From 89c58dd3b40169920d7530f6b4d2da350ac785c3 Mon Sep 17 00:00:00 2001 From: John Leider <9064066+johnleider@users.noreply.github.com> Date: Wed, 11 Dec 2024 13:59:16 -0600 Subject: [PATCH] feat(VFileUpload): add new component (#19667) Co-authored-by: MajesticPotatoe --- packages/docs/src/data/nav.json | 4 + .../examples/v-file-upload/prop-content.vue | 8 + .../examples/v-file-upload/prop-density.vue | 19 + .../examples/v-file-upload/prop-disabled.vue | 3 + .../src/examples/v-file-upload/prop-scrim.vue | 3 + .../src/examples/v-file-upload/slot-item.vue | 26 ++ .../docs/src/examples/v-file-upload/usage.vue | 48 +++ .../src/pages/en/components/file-upload.md | 99 +++++ packages/vuetify/src/iconsets/mdi.ts | 1 + .../src/labs/VFileUpload/VFileUpload.sass | 75 ++++ .../src/labs/VFileUpload/VFileUpload.tsx | 340 ++++++++++++++++++ .../src/labs/VFileUpload/VFileUploadItem.tsx | 140 ++++++++ .../src/labs/VFileUpload/_variables.scss | 12 + .../vuetify/src/labs/VFileUpload/index.ts | 2 + packages/vuetify/src/labs/components.ts | 1 + packages/vuetify/src/locale/af.ts | 5 + packages/vuetify/src/locale/ar.ts | 5 + packages/vuetify/src/locale/az.ts | 5 + packages/vuetify/src/locale/bg.ts | 5 + packages/vuetify/src/locale/ca.ts | 5 + packages/vuetify/src/locale/ckb.ts | 5 + packages/vuetify/src/locale/cs.ts | 5 + packages/vuetify/src/locale/da.ts | 5 + packages/vuetify/src/locale/de.ts | 5 + packages/vuetify/src/locale/el.ts | 5 + packages/vuetify/src/locale/en.ts | 5 + packages/vuetify/src/locale/es.ts | 5 + packages/vuetify/src/locale/et.ts | 5 + packages/vuetify/src/locale/fa.ts | 5 + packages/vuetify/src/locale/fi.ts | 5 + packages/vuetify/src/locale/fr.ts | 5 + packages/vuetify/src/locale/he.ts | 5 + packages/vuetify/src/locale/hr.ts | 5 + packages/vuetify/src/locale/hu.ts | 5 + packages/vuetify/src/locale/id.ts | 5 + packages/vuetify/src/locale/it.ts | 5 + packages/vuetify/src/locale/ja.ts | 5 + packages/vuetify/src/locale/km.ts | 5 + packages/vuetify/src/locale/ko.ts | 5 + packages/vuetify/src/locale/lt.ts | 5 + packages/vuetify/src/locale/lv.ts | 5 + packages/vuetify/src/locale/nl.ts | 5 + packages/vuetify/src/locale/no.ts | 5 + packages/vuetify/src/locale/pl.ts | 5 + packages/vuetify/src/locale/pt.ts | 5 + packages/vuetify/src/locale/ro.ts | 5 + packages/vuetify/src/locale/ru.ts | 5 + packages/vuetify/src/locale/sk.ts | 5 + packages/vuetify/src/locale/sl.ts | 5 + packages/vuetify/src/locale/sr-Cyrl.ts | 5 + packages/vuetify/src/locale/sr-Latn.ts | 5 + packages/vuetify/src/locale/sv.ts | 5 + packages/vuetify/src/locale/th.ts | 5 + packages/vuetify/src/locale/tr.ts | 5 + packages/vuetify/src/locale/uk.ts | 5 + packages/vuetify/src/locale/vi.ts | 5 + packages/vuetify/src/locale/zh-Hans.ts | 5 + packages/vuetify/src/locale/zh-Hant.ts | 5 + 58 files changed, 996 insertions(+) create mode 100644 packages/docs/src/examples/v-file-upload/prop-content.vue create mode 100644 packages/docs/src/examples/v-file-upload/prop-density.vue create mode 100644 packages/docs/src/examples/v-file-upload/prop-disabled.vue create mode 100644 packages/docs/src/examples/v-file-upload/prop-scrim.vue create mode 100644 packages/docs/src/examples/v-file-upload/slot-item.vue create mode 100644 packages/docs/src/examples/v-file-upload/usage.vue create mode 100644 packages/docs/src/pages/en/components/file-upload.md create mode 100644 packages/vuetify/src/labs/VFileUpload/VFileUpload.sass create mode 100644 packages/vuetify/src/labs/VFileUpload/VFileUpload.tsx create mode 100644 packages/vuetify/src/labs/VFileUpload/VFileUploadItem.tsx create mode 100644 packages/vuetify/src/labs/VFileUpload/_variables.scss create mode 100644 packages/vuetify/src/labs/VFileUpload/index.ts diff --git a/packages/docs/src/data/nav.json b/packages/docs/src/data/nav.json index 9d0a526bde2..d0f83422675 100644 --- a/packages/docs/src/data/nav.json +++ b/packages/docs/src/data/nav.json @@ -237,6 +237,10 @@ "title": "date-inputs", "subfolder": "components" }, + { + "title": "file-upload", + "subfolder": "components" + }, { "title": "number-inputs", "subfolder": "components" diff --git a/packages/docs/src/examples/v-file-upload/prop-content.vue b/packages/docs/src/examples/v-file-upload/prop-content.vue new file mode 100644 index 00000000000..8d9a6070318 --- /dev/null +++ b/packages/docs/src/examples/v-file-upload/prop-content.vue @@ -0,0 +1,8 @@ + diff --git a/packages/docs/src/examples/v-file-upload/prop-density.vue b/packages/docs/src/examples/v-file-upload/prop-density.vue new file mode 100644 index 00000000000..12e8556663f --- /dev/null +++ b/packages/docs/src/examples/v-file-upload/prop-density.vue @@ -0,0 +1,19 @@ + + + diff --git a/packages/docs/src/examples/v-file-upload/prop-disabled.vue b/packages/docs/src/examples/v-file-upload/prop-disabled.vue new file mode 100644 index 00000000000..af636f7f41d --- /dev/null +++ b/packages/docs/src/examples/v-file-upload/prop-disabled.vue @@ -0,0 +1,3 @@ + diff --git a/packages/docs/src/examples/v-file-upload/prop-scrim.vue b/packages/docs/src/examples/v-file-upload/prop-scrim.vue new file mode 100644 index 00000000000..56d88c513ad --- /dev/null +++ b/packages/docs/src/examples/v-file-upload/prop-scrim.vue @@ -0,0 +1,3 @@ + diff --git a/packages/docs/src/examples/v-file-upload/slot-item.vue b/packages/docs/src/examples/v-file-upload/slot-item.vue new file mode 100644 index 00000000000..65f4772a483 --- /dev/null +++ b/packages/docs/src/examples/v-file-upload/slot-item.vue @@ -0,0 +1,26 @@ + + + diff --git a/packages/docs/src/examples/v-file-upload/usage.vue b/packages/docs/src/examples/v-file-upload/usage.vue new file mode 100644 index 00000000000..417a9201e72 --- /dev/null +++ b/packages/docs/src/examples/v-file-upload/usage.vue @@ -0,0 +1,48 @@ + + + diff --git a/packages/docs/src/pages/en/components/file-upload.md b/packages/docs/src/pages/en/components/file-upload.md new file mode 100644 index 00000000000..13506c501af --- /dev/null +++ b/packages/docs/src/pages/en/components/file-upload.md @@ -0,0 +1,99 @@ +--- +emphasized: true +meta: + title: File upload + description: The file upload component is a drag and drop area for uploading files. + keywords: file uploading, file upload, file drag and drop, file drop area, file dropzone, file upload component +related: + - /components/buttons/ + - /components/file-inputs/ + - /components/sheets/ +features: + report: true + label: 'C: VFileUpload' + github: '/labs/VFileUpload/' +--- + +# File upload + + + +::: warning + +This feature requires [v3.7.3](/getting-started/release-notes/?version=v3.7.3) + +::: + +## Installation + +Labs components require a manual import and installation of the component. + +```js { resource="src/plugins/vuetify.js" } +import { VFileUpload } from 'vuetify/labs/VFileUpload' + +export default createVuetify({ + components: { + VFileUpload, + }, +}) +``` + +## Usage + +The `v-file-upload` component is a drag and drop area for uploading files. It can be customized with slots and has support for density and multiple styles. + + + + + +## API + +| Component | Description | +| - | - | +| [v-file-upload](/api/v-file-upload/) | Primary Component | +| [v-file-upload-item](/api/v-file-upload-item/) | Item Component | +| [v-file-input](/api/v-file-input/) | File input component | + + + +## Guide + +The v-file-upload component is a more visual counterpart to the [v-file-input](/components/file-inputs/) component. It provides a drag and drop area for files, and can be customized with slots. + +### Props + +Utilize various properties to customize the look and feel of the `v-file-upload` component. + +#### Density + +The **density** prop is used to control the vertical space the upload takes up. + + + +#### Content + +Use the **browse-text**, **divider-text**, **icon**, **title**, or **subtitle** props to customize the text displayed in the component. + + + +#### Disabled + +The **disabled** property reduces the opacity of the component and prevents interaction. + + + +#### Scrim + +The **scrim** property allows you to set a colored scrim when hovering over the component with files. + + + +### Slots + +The `v-file-upload` component has several slots that can be used to customize the component. + +#### Item + +The **item** slot is used to customize the appearance of the file item. + + diff --git a/packages/vuetify/src/iconsets/mdi.ts b/packages/vuetify/src/iconsets/mdi.ts index d1a9e788062..059e3cf9f67 100644 --- a/packages/vuetify/src/iconsets/mdi.ts +++ b/packages/vuetify/src/iconsets/mdi.ts @@ -47,6 +47,7 @@ const aliases: IconAliases = { treeviewCollapse: 'mdi-menu-down', treeviewExpand: 'mdi-menu-right', eyeDropper: 'mdi-eyedropper', + upload: 'mdi-cloud-upload', } const mdi: IconSet = { diff --git a/packages/vuetify/src/labs/VFileUpload/VFileUpload.sass b/packages/vuetify/src/labs/VFileUpload/VFileUpload.sass new file mode 100644 index 00000000000..eafca31e8e9 --- /dev/null +++ b/packages/vuetify/src/labs/VFileUpload/VFileUpload.sass @@ -0,0 +1,75 @@ +@use '../../styles/tools' +@use '../../styles/settings' +@use './variables' as * + +@include tools.layer('components') + .v-file-upload + padding: $file-upload-padding + flex-direction: column + justify-content: center + align-items: center + position: relative + + &.v-sheet + display: flex + border-radius: 4px + border-style: dashed + border-width: 2px + + &.v-file-upload--density-compact + padding: 32px 0 + flex-direction: row + gap: 1rem + + .v-overlay__scrim + pointer-events: none + + &--disabled + pointer-events: none + opacity: var(--v-disabled-opacity) + + &--dragging + > * + pointer-events: none + + &--clickable + cursor: pointer + + input[type="file"] + left: 0 + opacity: 0 + position: absolute + cursor: pointer + top: 0 + z-index: -1 + + .v-file-upload-title + font-size: $file-upload-title-font-size + font-weight: 600 + + .v-file-upload-icon + opacity: var(--v-medium-emphasis-opacity) + font-size: $file-upload-icon-font-size + margin-bottom: $file-upload-icon-margin-bottom + + .v-file-upload--density-comfortable & + font-size: $file-upload-icon-font-size - .5rem + margin-bottom: $file-upload-icon-margin-bottom - .5rem + + .v-file-upload--density-compact & + font-size: $file-upload-icon-font-size - 1rem + margin-bottom: $file-upload-icon-margin-bottom - 1rem + + .v-file-upload-divider + align-items: center + display: flex + margin: $file-upload-divider-margin + justify-content: center + width: 100% + + .v-file-upload-items + margin: $file-upload-items-margin + + .v-file-upload-item + &:not(:first-child) + margin-top: 8px diff --git a/packages/vuetify/src/labs/VFileUpload/VFileUpload.tsx b/packages/vuetify/src/labs/VFileUpload/VFileUpload.tsx new file mode 100644 index 00000000000..a48a79b21cc --- /dev/null +++ b/packages/vuetify/src/labs/VFileUpload/VFileUpload.tsx @@ -0,0 +1,340 @@ +// Styles +import './VFileUpload.sass' + +// Components +import { VFileUploadItem } from './VFileUploadItem' +import { VBtn } from '@/components/VBtn/VBtn' +import { VDefaultsProvider } from '@/components/VDefaultsProvider/VDefaultsProvider' +import { makeVDividerProps, VDivider } from '@/components/VDivider/VDivider' +import { VIcon } from '@/components/VIcon/VIcon' +import { VOverlay } from '@/components/VOverlay/VOverlay' +import { makeVSheetProps, VSheet } from '@/components/VSheet/VSheet' + +// Composables +import { makeDelayProps } from '@/composables/delay' +import { makeDensityProps, useDensity } from '@/composables/density' +import { IconValue } from '@/composables/icons' +import { useLocale } from '@/composables/locale' +import { useProxiedModel } from '@/composables/proxiedModel' + +// Utilities +import { onMounted, onUnmounted, ref, shallowRef } from 'vue' +import { filterInputAttrs, genericComponent, only, propsFactory, useRender, wrapInArray } from '@/util' + +// Types +import type { PropType, VNode } from 'vue' + +export type VFileUploadSlots = { + browse: { + props: { onClick: (e: MouseEvent) => void } + } + default: never + icon: never + input: { + inputNode: VNode + } + item: { + file: File + props: { 'onClick:remove': () => void } + } + title: never + divider: never +} + +export const makeVFileUploadProps = propsFactory({ + browseText: { + type: String, + default: '$vuetify.fileUpload.browse', + }, + dividerText: { + type: String, + default: '$vuetify.fileUpload.divider', + }, + title: { + type: String, + default: '$vuetify.fileUpload.title', + }, + subtitle: String, + icon: { + type: IconValue, + default: '$upload', + }, + modelValue: { + type: [Array, Object] as PropType, + default: null, + validator: (val: any) => { + return wrapInArray(val).every(v => v != null && typeof v === 'object') + }, + }, + clearable: Boolean, + disabled: Boolean, + hideBrowse: Boolean, + multiple: Boolean, + scrim: { + type: [Boolean, String], + default: true, + }, + showSize: Boolean, + name: String, + + ...makeDelayProps(), + ...makeDensityProps(), + ...only(makeVDividerProps({ + length: 150, + }), ['length', 'thickness', 'opacity']), + ...makeVSheetProps(), +}, 'VFileUpload') + +export const VFileUpload = genericComponent()({ + name: 'VFileUpload', + + inheritAttrs: false, + + props: makeVFileUploadProps(), + + emits: { + 'update:modelValue': (files: File[]) => true, + }, + + setup (props, { attrs, slots }) { + const { t } = useLocale() + const { densityClasses } = useDensity(props) + const model = useProxiedModel( + props, + 'modelValue', + props.modelValue, + val => wrapInArray(val), + val => (props.multiple || Array.isArray(props.modelValue)) ? val : val[0], + ) + + const dragOver = shallowRef(false) + const vSheetRef = ref | null>(null) + const inputRef = ref(null) + + onMounted(() => { + vSheetRef.value?.$el.addEventListener('dragover', onDragOver) + vSheetRef.value?.$el.addEventListener('drop', onDrop) + }) + + onUnmounted(() => { + vSheetRef.value?.$el.removeEventListener('dragover', onDragOver) + vSheetRef.value?.$el.removeEventListener('drop', onDrop) + }) + + function onDragOver (e: DragEvent) { + e.preventDefault() + e.stopImmediatePropagation() + dragOver.value = true + } + + function onDragLeave (e: DragEvent) { + e.preventDefault() + dragOver.value = false + } + + function onDrop (e: DragEvent) { + e.preventDefault() + e.stopImmediatePropagation() + dragOver.value = false + + const files = Array.from(e.dataTransfer?.files ?? []) + + if (!files.length) return + + if (!props.multiple) { + model.value = [files[0]] + + return + } + + const array = model.value.slice() + + for (const file of files) { + if (!array.some(f => f.name === file.name)) { + array.push(file) + } + } + + model.value = array + } + + function onClick () { + inputRef.value?.click() + } + + function onClickRemove (index: number) { + model.value = model.value.filter((_, i) => i !== index) + + if (model.value.length > 0 || !inputRef.value) return + + inputRef.value.value = '' + } + + useRender(() => { + const hasTitle = !!(slots.title || props.title) + const hasIcon = !!(slots.icon || props.icon) + const hasBrowse = !!(!props.hideBrowse && (slots.browse || props.density === 'default')) + const cardProps = VSheet.filterProps(props) + const dividerProps = VDivider.filterProps(props) + const [rootAttrs, inputAttrs] = filterInputAttrs(attrs) + + const inputNode = ( + { + if (!e.target) return + + const target = e.target as HTMLInputElement + model.value = [...target.files ?? []] + }} + { ...inputAttrs } + /> + ) + + return ( + <> + + { hasIcon && ( +
+ { !slots.icon ? ( + + ) : ( + + { slots.icon() } + + )} +
+ )} + + { hasTitle && ( +
+ { slots.title?.() ?? t(props.title) } +
+ )} + + { props.density === 'default' && ( + <> +
+ { slots.divider?.() ?? ( + + { t(props.dividerText) } + + )} +
+ + { hasBrowse && ( + <> + { !slots.browse ? ( + + ) : ( + + { slots.browse({ props: { onClick } }) } + + )} + + )} + + { props.subtitle && ( +
+ { props.subtitle } +
+ )} + + )} + + + + { slots.input?.({ inputNode }) ?? inputNode } +
+ + { model.value.length > 0 && ( +
+ { model.value.map((file, i) => { + const slotProps = { + file, + props: { + 'onClick:remove': () => onClickRemove(i), + }, + } + + return ( + + { slots.item?.(slotProps) ?? ( + onClickRemove(i) } + v-slots={ slots } + /> + )} + + ) + })} +
+ )} + + ) + }) + }, +}) + +export type VFileUpload = InstanceType diff --git a/packages/vuetify/src/labs/VFileUpload/VFileUploadItem.tsx b/packages/vuetify/src/labs/VFileUpload/VFileUploadItem.tsx new file mode 100644 index 00000000000..24e5ea5ca30 --- /dev/null +++ b/packages/vuetify/src/labs/VFileUpload/VFileUploadItem.tsx @@ -0,0 +1,140 @@ +// Components +import { VAvatar } from '@/components/VAvatar/VAvatar' +import { VBtn } from '@/components/VBtn/VBtn' +import { VDefaultsProvider } from '@/components/VDefaultsProvider/VDefaultsProvider' +import { makeVListItemProps, VListItem } from '@/components/VList/VListItem' + +// Utilities +import { computed, ref, watchEffect } from 'vue' +import { genericComponent, humanReadableFileSize, propsFactory, useRender } from '@/util' + +// Types +import type { PropType } from 'vue' +import type { VListItemSlots } from '@/components/VList/VListItem' + +export type VFileUploadItemSlots = { + clear: { + props: { onClick: () => void } + } +} & VListItemSlots + +export const makeVFileUploadItemProps = propsFactory({ + clearable: Boolean, + file: { + type: Object as PropType, + default: null, + }, + fileIcon: { + type: String, + // TODO: setup up a proper aliased icon + default: 'mdi-file-document', + }, + showSize: Boolean, + + ...makeVListItemProps({ + border: true, + rounded: true, + lines: 'two' as const, + }), +}, 'VFileUploadItem') + +export const VFileUploadItem = genericComponent()({ + name: 'VFileUploadItem', + + props: makeVFileUploadItemProps(), + + emits: { + 'click:remove': () => true, + click: (e: MouseEvent | KeyboardEvent) => true, + }, + + setup (props, { emit, slots }) { + const preview = ref() + const base = computed(() => typeof props.showSize !== 'boolean' ? props.showSize : undefined) + + function onClickRemove () { + emit('click:remove') + } + + watchEffect(() => { + preview.value = props.file?.type.startsWith('image') ? URL.createObjectURL(props.file) : undefined + }) + + useRender(() => { + const listItemProps = VListItem.filterProps(props) + + return ( + + {{ + ...slots, + prepend: slotProps => ( + <> + { !slots.prepend ? ( + + ) : ( + + { slots.prepend?.(slotProps) ?? ( + + )} + + )} + + ), + append: slotProps => ( + <> + { props.clearable && ( + <> + { !slots.clear ? ( + + ) : ( + + { slots.clear?.({ + ...slotProps, + props: { onClick: onClickRemove }, + }) ?? ()} + + )} + + )} + + { slots.append?.(slotProps) } + + ), + }} + + ) + }) + }, +}) + +export type VFileUploadItem = InstanceType diff --git a/packages/vuetify/src/labs/VFileUpload/_variables.scss b/packages/vuetify/src/labs/VFileUpload/_variables.scss new file mode 100644 index 00000000000..38c3ba95aad --- /dev/null +++ b/packages/vuetify/src/labs/VFileUpload/_variables.scss @@ -0,0 +1,12 @@ +@use '../../styles/tools'; +@use '../../styles/settings'; + +$file-upload-title-font-size: 1.5rem !default; +$file-upload-padding: 64px 0 !default; +$file-upload-border-radius: 4px !default; +$file-upload-border-width: 2px !default; +$file-upload-title-font-weight: 600 !default; +$file-upload-icon-font-size: 3rem !default; +$file-upload-icon-margin-bottom: 1rem !default; +$file-upload-divider-margin: 32px 0 !default; +$file-upload-items-margin: 16px 0 !default; diff --git a/packages/vuetify/src/labs/VFileUpload/index.ts b/packages/vuetify/src/labs/VFileUpload/index.ts new file mode 100644 index 00000000000..3f85597a4d3 --- /dev/null +++ b/packages/vuetify/src/labs/VFileUpload/index.ts @@ -0,0 +1,2 @@ +export { VFileUpload } from './VFileUpload' +export { VFileUploadItem } from './VFileUploadItem' diff --git a/packages/vuetify/src/labs/components.ts b/packages/vuetify/src/labs/components.ts index 6b753ff8790..341d9536360 100644 --- a/packages/vuetify/src/labs/components.ts +++ b/packages/vuetify/src/labs/components.ts @@ -1,5 +1,6 @@ export * from './VCalendar' export * from './VDateInput' +export * from './VFileUpload' export * from './VNumberInput' export * from './VPicker' export * from './VStepperVertical' diff --git a/packages/vuetify/src/locale/af.ts b/packages/vuetify/src/locale/af.ts index 34fc7bd4c76..d7fd337c043 100644 --- a/packages/vuetify/src/locale/af.ts +++ b/packages/vuetify/src/locale/af.ts @@ -69,6 +69,11 @@ export default { counter: '{0} files', counterSize: '{0} files ({1} in total)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/ar.ts b/packages/vuetify/src/locale/ar.ts index b5ec2b2ea6f..e28cb07f5de 100644 --- a/packages/vuetify/src/locale/ar.ts +++ b/packages/vuetify/src/locale/ar.ts @@ -69,6 +69,11 @@ export default { counter: '{0} ملفات', counterSize: '{0} ملفات ({1} في المجموع)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'صباحاً', pm: 'مساءً', diff --git a/packages/vuetify/src/locale/az.ts b/packages/vuetify/src/locale/az.ts index b452d1ccd95..40477c14b8e 100644 --- a/packages/vuetify/src/locale/az.ts +++ b/packages/vuetify/src/locale/az.ts @@ -69,6 +69,11 @@ export default { counter: '{0} fayl', counterSize: '{0} fayl (cəmi {1})', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/bg.ts b/packages/vuetify/src/locale/bg.ts index f795df46016..f2a7c345147 100644 --- a/packages/vuetify/src/locale/bg.ts +++ b/packages/vuetify/src/locale/bg.ts @@ -69,6 +69,11 @@ export default { counter: '{0} файла', counterSize: '{0} файла ({1} общо)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'пр. обяд', pm: 'сл. обяд', diff --git a/packages/vuetify/src/locale/ca.ts b/packages/vuetify/src/locale/ca.ts index 09b06b0b9e9..93c064b55a4 100644 --- a/packages/vuetify/src/locale/ca.ts +++ b/packages/vuetify/src/locale/ca.ts @@ -69,6 +69,11 @@ export default { counter: '{0} fitxers', counterSize: '{0} fitxers ({1} en total)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/ckb.ts b/packages/vuetify/src/locale/ckb.ts index 64ffde6ea1a..ceef0ea6149 100644 --- a/packages/vuetify/src/locale/ckb.ts +++ b/packages/vuetify/src/locale/ckb.ts @@ -69,6 +69,11 @@ export default { counter: '{0} فایل', counterSize: '{0} فایل ({1} لە کۆی گشتی)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'پێش نیوەڕۆژ', pm: 'دوای نیوەڕۆژ', diff --git a/packages/vuetify/src/locale/cs.ts b/packages/vuetify/src/locale/cs.ts index 85a8b6b613a..261fc5a4099 100644 --- a/packages/vuetify/src/locale/cs.ts +++ b/packages/vuetify/src/locale/cs.ts @@ -69,6 +69,11 @@ export default { counter: '{0} souborů', counterSize: '{0} souborů ({1} celkem)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/da.ts b/packages/vuetify/src/locale/da.ts index 8a80af26500..4668d8e9fde 100644 --- a/packages/vuetify/src/locale/da.ts +++ b/packages/vuetify/src/locale/da.ts @@ -69,6 +69,11 @@ export default { counter: '{0} filer', counterSize: '{0} filer ({1} total)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/de.ts b/packages/vuetify/src/locale/de.ts index 9b350fc1222..253f9c3b7b4 100644 --- a/packages/vuetify/src/locale/de.ts +++ b/packages/vuetify/src/locale/de.ts @@ -69,6 +69,11 @@ export default { counter: '{0} Dateien', counterSize: '{0} Dateien ({1} gesamt)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/el.ts b/packages/vuetify/src/locale/el.ts index be1701683f9..fba9a4b9fb1 100755 --- a/packages/vuetify/src/locale/el.ts +++ b/packages/vuetify/src/locale/el.ts @@ -69,6 +69,11 @@ export default { counter: '{0} files', counterSize: '{0} files ({1} in total)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/en.ts b/packages/vuetify/src/locale/en.ts index cf94f5e9786..0c59dac42d9 100644 --- a/packages/vuetify/src/locale/en.ts +++ b/packages/vuetify/src/locale/en.ts @@ -69,6 +69,11 @@ export default { counter: '{0} files', counterSize: '{0} files ({1} in total)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/es.ts b/packages/vuetify/src/locale/es.ts index 849ddececaa..86142336aed 100644 --- a/packages/vuetify/src/locale/es.ts +++ b/packages/vuetify/src/locale/es.ts @@ -69,6 +69,11 @@ export default { counter: '{0} archivos', counterSize: '{0} archivos ({1} en total)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/et.ts b/packages/vuetify/src/locale/et.ts index b420079173d..1ff3d0c9875 100644 --- a/packages/vuetify/src/locale/et.ts +++ b/packages/vuetify/src/locale/et.ts @@ -69,6 +69,11 @@ export default { counter: '{0} faili', counterSize: '{0} faili (kokku {1})', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/fa.ts b/packages/vuetify/src/locale/fa.ts index d80255e4351..559789c561e 100644 --- a/packages/vuetify/src/locale/fa.ts +++ b/packages/vuetify/src/locale/fa.ts @@ -69,6 +69,11 @@ export default { counter: '{0} پرونده', counterSize: '{0} پرونده ({1} در کل)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'قبل از ظهر', pm: 'بعد از ظهر', diff --git a/packages/vuetify/src/locale/fi.ts b/packages/vuetify/src/locale/fi.ts index d03c0703928..5d9b54d6581 100644 --- a/packages/vuetify/src/locale/fi.ts +++ b/packages/vuetify/src/locale/fi.ts @@ -69,6 +69,11 @@ export default { counter: '{0} tiedostoa', counterSize: '{0} tiedostoa ({1} yhteensä)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'ap.', pm: 'ip.', diff --git a/packages/vuetify/src/locale/fr.ts b/packages/vuetify/src/locale/fr.ts index 0bf6954ac79..371798e0434 100644 --- a/packages/vuetify/src/locale/fr.ts +++ b/packages/vuetify/src/locale/fr.ts @@ -69,6 +69,11 @@ export default { counter: '{0} fichier(s)', counterSize: '{0} fichier(s) ({1} au total)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/he.ts b/packages/vuetify/src/locale/he.ts index ebc04e428e6..463ac6ddb7c 100644 --- a/packages/vuetify/src/locale/he.ts +++ b/packages/vuetify/src/locale/he.ts @@ -69,6 +69,11 @@ export default { counter: '{0} קבצים', counterSize: '{0} קבצים ({1} בסך הכל)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/hr.ts b/packages/vuetify/src/locale/hr.ts index d24be21324b..d064708a31c 100644 --- a/packages/vuetify/src/locale/hr.ts +++ b/packages/vuetify/src/locale/hr.ts @@ -69,6 +69,11 @@ export default { counter: 'Odabranih datoteka: {0}', counterSize: 'Odabranih datoteka: {0} ({1} ukupno)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/hu.ts b/packages/vuetify/src/locale/hu.ts index d23db5b5e15..ce7a5fac4c4 100644 --- a/packages/vuetify/src/locale/hu.ts +++ b/packages/vuetify/src/locale/hu.ts @@ -69,6 +69,11 @@ export default { counter: '{0} fájl', counterSize: '{0} fájl ({1} összesen)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'de', pm: 'du', diff --git a/packages/vuetify/src/locale/id.ts b/packages/vuetify/src/locale/id.ts index ad689c5f478..9ddda9a693d 100644 --- a/packages/vuetify/src/locale/id.ts +++ b/packages/vuetify/src/locale/id.ts @@ -69,6 +69,11 @@ export default { counter: '{0} berkas', counterSize: '{0} berkas (dari total {1})', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/it.ts b/packages/vuetify/src/locale/it.ts index cc2d11e9f53..206aeeaad90 100644 --- a/packages/vuetify/src/locale/it.ts +++ b/packages/vuetify/src/locale/it.ts @@ -69,6 +69,11 @@ export default { counter: '{0} file', counterSize: '{0} file ({1} in totale)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/ja.ts b/packages/vuetify/src/locale/ja.ts index 1156492f552..034842f41c7 100644 --- a/packages/vuetify/src/locale/ja.ts +++ b/packages/vuetify/src/locale/ja.ts @@ -69,6 +69,11 @@ export default { counter: '{0} ファイル', counterSize: '{0} ファイル (合計 {1})', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/km.ts b/packages/vuetify/src/locale/km.ts index 10c1cd735ac..5de87fc9454 100644 --- a/packages/vuetify/src/locale/km.ts +++ b/packages/vuetify/src/locale/km.ts @@ -69,6 +69,11 @@ export default { counter: '{0} ឯកសារ', counterSize: '{0} ឯកសារ ({1} សរុប)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'ព្រឹក', pm: 'ល្ងាច', diff --git a/packages/vuetify/src/locale/ko.ts b/packages/vuetify/src/locale/ko.ts index 1a0782eec8a..72b07e732bc 100644 --- a/packages/vuetify/src/locale/ko.ts +++ b/packages/vuetify/src/locale/ko.ts @@ -69,6 +69,11 @@ export default { counter: '{0} files', counterSize: '{0} files ({1} in total)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: '오전', pm: '오후', diff --git a/packages/vuetify/src/locale/lt.ts b/packages/vuetify/src/locale/lt.ts index 307340e31a3..2b2f492c4d2 100644 --- a/packages/vuetify/src/locale/lt.ts +++ b/packages/vuetify/src/locale/lt.ts @@ -69,6 +69,11 @@ export default { counter: '{0} failų', counterSize: '{0} failų ({1} iš viso)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/lv.ts b/packages/vuetify/src/locale/lv.ts index eb493589646..bb4b563e6be 100644 --- a/packages/vuetify/src/locale/lv.ts +++ b/packages/vuetify/src/locale/lv.ts @@ -69,6 +69,11 @@ export default { counter: '{0} files', counterSize: '{0} files ({1} in total)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/nl.ts b/packages/vuetify/src/locale/nl.ts index b8c6032fe32..266996e1918 100644 --- a/packages/vuetify/src/locale/nl.ts +++ b/packages/vuetify/src/locale/nl.ts @@ -69,6 +69,11 @@ export default { counter: '{0} bestanden', counterSize: '{0} bestanden ({1} in totaal)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/no.ts b/packages/vuetify/src/locale/no.ts index c9fc72ddfc6..0796d33e009 100644 --- a/packages/vuetify/src/locale/no.ts +++ b/packages/vuetify/src/locale/no.ts @@ -69,6 +69,11 @@ export default { counter: '{0} filer', counterSize: '{0} filer ({1} totalt)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/pl.ts b/packages/vuetify/src/locale/pl.ts index 0e45ad375df..ccc577f6ed0 100644 --- a/packages/vuetify/src/locale/pl.ts +++ b/packages/vuetify/src/locale/pl.ts @@ -69,6 +69,11 @@ export default { counter: 'Liczba plików: {0}', counterSize: 'Liczba plików: {0} (łącznie {1})', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/pt.ts b/packages/vuetify/src/locale/pt.ts index d6094cb7edd..65a63d04bbe 100644 --- a/packages/vuetify/src/locale/pt.ts +++ b/packages/vuetify/src/locale/pt.ts @@ -69,6 +69,11 @@ export default { counter: '{0} arquivo(s)', counterSize: '{0} arquivo(s) ({1} no total)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/ro.ts b/packages/vuetify/src/locale/ro.ts index 615b2861637..8f898a72fb9 100644 --- a/packages/vuetify/src/locale/ro.ts +++ b/packages/vuetify/src/locale/ro.ts @@ -69,6 +69,11 @@ export default { counter: '{0} fișiere', counterSize: '{0} fișiere ({1} în total)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/ru.ts b/packages/vuetify/src/locale/ru.ts index 3c6eb2cde0e..3082bab7450 100644 --- a/packages/vuetify/src/locale/ru.ts +++ b/packages/vuetify/src/locale/ru.ts @@ -69,6 +69,11 @@ export default { counter: 'Файлов: {0}', counterSize: 'Файлов: {0} (всего {1})', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/sk.ts b/packages/vuetify/src/locale/sk.ts index 9b1ffe2481e..f2c8e51b043 100644 --- a/packages/vuetify/src/locale/sk.ts +++ b/packages/vuetify/src/locale/sk.ts @@ -69,6 +69,11 @@ export default { counter: '{0} súborov', counterSize: '{0} súborov ({1} celkom)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/sl.ts b/packages/vuetify/src/locale/sl.ts index c36e668c611..2d39a6c857f 100644 --- a/packages/vuetify/src/locale/sl.ts +++ b/packages/vuetify/src/locale/sl.ts @@ -69,6 +69,11 @@ export default { counter: '{0} datotek', counterSize: '{0} datotek (skupno {1})', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/sr-Cyrl.ts b/packages/vuetify/src/locale/sr-Cyrl.ts index 6e9c1f9cc16..3230a8f1e4b 100644 --- a/packages/vuetify/src/locale/sr-Cyrl.ts +++ b/packages/vuetify/src/locale/sr-Cyrl.ts @@ -69,6 +69,11 @@ export default { counter: '{0} фајлова', counterSize: '{0} фајлова ({1} укупно)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/sr-Latn.ts b/packages/vuetify/src/locale/sr-Latn.ts index 485d81bd2d0..7b7c1e92857 100644 --- a/packages/vuetify/src/locale/sr-Latn.ts +++ b/packages/vuetify/src/locale/sr-Latn.ts @@ -69,6 +69,11 @@ export default { counter: '{0} fajlova', counterSize: '{0} fajlova ({1} ukupno)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/sv.ts b/packages/vuetify/src/locale/sv.ts index 2a0b576b7aa..63508c57130 100644 --- a/packages/vuetify/src/locale/sv.ts +++ b/packages/vuetify/src/locale/sv.ts @@ -69,6 +69,11 @@ export default { counter: '{0} filer', counterSize: '{0} filer ({1})', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/th.ts b/packages/vuetify/src/locale/th.ts index 672643cd6c0..2d2dce683eb 100644 --- a/packages/vuetify/src/locale/th.ts +++ b/packages/vuetify/src/locale/th.ts @@ -69,6 +69,11 @@ export default { counter: '{0} ไฟล์', counterSize: '{0} ไฟล์ (รวม {1})', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/tr.ts b/packages/vuetify/src/locale/tr.ts index 2463d23ba1e..0bd7eaaddae 100644 --- a/packages/vuetify/src/locale/tr.ts +++ b/packages/vuetify/src/locale/tr.ts @@ -69,6 +69,11 @@ export default { counter: '{0} dosya', counterSize: '{0} dosya (toplamda {1})', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/uk.ts b/packages/vuetify/src/locale/uk.ts index 4d1d28540ac..e1e6fc13dca 100644 --- a/packages/vuetify/src/locale/uk.ts +++ b/packages/vuetify/src/locale/uk.ts @@ -69,6 +69,11 @@ export default { counter: '{0} файлів', counterSize: '{0} файлів ({1} загалом)', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/vi.ts b/packages/vuetify/src/locale/vi.ts index 67915a2dc1e..1d6c493ad68 100644 --- a/packages/vuetify/src/locale/vi.ts +++ b/packages/vuetify/src/locale/vi.ts @@ -69,6 +69,11 @@ export default { counter: '{0} tệp', counterSize: '{0} tệp (tổng cộng {1})', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'SA', pm: 'CH', diff --git a/packages/vuetify/src/locale/zh-Hans.ts b/packages/vuetify/src/locale/zh-Hans.ts index dec1c61f811..eed400c16c3 100644 --- a/packages/vuetify/src/locale/zh-Hans.ts +++ b/packages/vuetify/src/locale/zh-Hans.ts @@ -69,6 +69,11 @@ export default { counter: '{0} 个文件', counterSize: '{0} 个文件(共 {1})', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM', diff --git a/packages/vuetify/src/locale/zh-Hant.ts b/packages/vuetify/src/locale/zh-Hant.ts index dbae45b6526..7bebfcd5b49 100644 --- a/packages/vuetify/src/locale/zh-Hant.ts +++ b/packages/vuetify/src/locale/zh-Hant.ts @@ -69,6 +69,11 @@ export default { counter: '{0} 個檔案', counterSize: '{0} 個檔案(共 {1})', }, + fileUpload: { + title: 'Drag and drop files here', + divider: 'or', + browse: 'Browse Files', + }, timePicker: { am: 'AM', pm: 'PM',