123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- import { resolveDirective as _resolveDirective, Fragment as _Fragment, createVNode as _createVNode, mergeProps as _mergeProps } from "vue";
- // Styles
- import "./VFileUpload.css";
- // Components
- import { VFileUploadItem } from "./VFileUploadItem.mjs";
- import { VBtn } from "../../components/VBtn/VBtn.mjs";
- import { VDefaultsProvider } from "../../components/VDefaultsProvider/VDefaultsProvider.mjs";
- import { makeVDividerProps, VDivider } from "../../components/VDivider/VDivider.mjs";
- import { VIcon } from "../../components/VIcon/VIcon.mjs";
- import { VOverlay } from "../../components/VOverlay/VOverlay.mjs";
- import { makeVSheetProps, VSheet } from "../../components/VSheet/VSheet.mjs"; // Composables
- import { makeDelayProps } from "../../composables/delay.mjs";
- import { makeDensityProps, useDensity } from "../../composables/density.mjs";
- import { IconValue } from "../../composables/icons.mjs";
- import { useLocale } from "../../composables/locale.mjs";
- import { useProxiedModel } from "../../composables/proxiedModel.mjs"; // Utilities
- import { onMounted, onUnmounted, ref, shallowRef } from 'vue';
- import { filterInputAttrs, genericComponent, only, propsFactory, useRender, wrapInArray } from "../../util/index.mjs"; // Types
- 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],
- default: null,
- validator: val => {
- 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 => true
- },
- setup(props, _ref) {
- let {
- attrs,
- slots
- } = _ref;
- 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);
- 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) {
- e.preventDefault();
- e.stopImmediatePropagation();
- dragOver.value = true;
- }
- function onDragLeave(e) {
- e.preventDefault();
- dragOver.value = false;
- }
- function onDrop(e) {
- 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) {
- 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 = _createVNode("input", _mergeProps({
- "ref": inputRef,
- "type": "file",
- "disabled": props.disabled,
- "multiple": props.multiple,
- "name": props.name,
- "onChange": e => {
- if (!e.target) return;
- const target = e.target;
- model.value = [...(target.files ?? [])];
- }
- }, inputAttrs), null);
- return _createVNode(_Fragment, null, [_createVNode(VSheet, _mergeProps({
- "ref": vSheetRef
- }, cardProps, {
- "class": ['v-file-upload', {
- 'v-file-upload--clickable': !hasBrowse,
- 'v-file-upload--disabled': props.disabled,
- 'v-file-upload--dragging': dragOver.value
- }, densityClasses.value],
- "onDragleave": onDragLeave,
- "onDragover": onDragOver,
- "onDrop": onDrop,
- "onClick": !hasBrowse ? onClick : undefined
- }, rootAttrs), {
- default: () => [hasIcon && _createVNode("div", {
- "key": "icon",
- "class": "v-file-upload-icon"
- }, [!slots.icon ? _createVNode(VIcon, {
- "key": "icon-icon",
- "icon": props.icon
- }, null) : _createVNode(VDefaultsProvider, {
- "key": "icon-defaults",
- "defaults": {
- VIcon: {
- icon: props.icon
- }
- }
- }, {
- default: () => [slots.icon()]
- })]), hasTitle && _createVNode("div", {
- "key": "title",
- "class": "v-file-upload-title"
- }, [slots.title?.() ?? t(props.title)]), props.density === 'default' && _createVNode(_Fragment, null, [_createVNode("div", {
- "key": "upload-divider",
- "class": "v-file-upload-divider"
- }, [slots.divider?.() ?? _createVNode(VDivider, dividerProps, {
- default: () => [t(props.dividerText)]
- })]), hasBrowse && _createVNode(_Fragment, null, [!slots.browse ? _createVNode(VBtn, {
- "readonly": props.disabled,
- "size": "large",
- "text": t(props.browseText),
- "variant": "tonal",
- "onClick": onClick
- }, null) : _createVNode(VDefaultsProvider, {
- "defaults": {
- VBtn: {
- readonly: props.disabled,
- size: 'large',
- text: t(props.browseText),
- variant: 'tonal'
- }
- }
- }, {
- default: () => [slots.browse({
- props: {
- onClick
- }
- })]
- })]), props.subtitle && _createVNode("div", {
- "class": "v-file-upload-subtitle"
- }, [props.subtitle])]), _createVNode(VOverlay, {
- "model-value": dragOver.value,
- "contained": true,
- "scrim": props.scrim
- }, null), slots.input?.({
- inputNode
- }) ?? inputNode]
- }), model.value.length > 0 && _createVNode("div", {
- "class": "v-file-upload-items"
- }, [model.value.map((file, i) => {
- const slotProps = {
- file,
- props: {
- 'onClick:remove': () => onClickRemove(i)
- }
- };
- return _createVNode(VDefaultsProvider, {
- "key": i,
- "defaults": {
- VFileUploadItem: {
- file,
- clearable: props.clearable,
- disabled: props.disabled,
- showSize: props.showSize
- }
- }
- }, {
- default: () => [slots.item?.(slotProps) ?? _createVNode(VFileUploadItem, {
- "key": i,
- "onClick:remove": () => onClickRemove(i)
- }, slots)]
- });
- })])]);
- });
- }
- });
- //# sourceMappingURL=VFileUpload.mjs.map
|