vuetify
Version:
Vue Material Component Framework
278 lines • 9.34 kB
JavaScript
import { createVNode as _createVNode, createElementVNode as _createElementVNode, Fragment as _Fragment, mergeProps as _mergeProps } from "vue";
// Components
import { VFileUploadItem } from "./VFileUploadItem.js";
import { VBtn } from "../../components/VBtn/VBtn.js";
import { VDefaultsProvider } from "../../components/VDefaultsProvider/VDefaultsProvider.js";
import { makeVDividerProps, VDivider } from "../../components/VDivider/VDivider.js";
import { VIcon } from "../../components/VIcon/VIcon.js";
import { VOverlay } from "../../components/VOverlay/VOverlay.js";
import { makeVSheetProps, VSheet } from "../../components/VSheet/VSheet.js"; // Composables
import { makeDelayProps } from "../../composables/delay.js";
import { makeDensityProps, useDensity } from "../../composables/density.js";
import { useFileDrop } from "../../composables/fileDrop.js";
import { forwardRefs } from "../../composables/forwardRefs.js";
import { IconValue } from "../../composables/icons.js";
import { useLocale } from "../../composables/locale.js"; // Utilities
import { inject, ref, shallowRef } from 'vue';
import { genericComponent, pick, propsFactory, useRender } from "../../util/index.js"; // Types
export const VFileUploadKey = Symbol.for('vuetify:file-upload');
export const makeVFileUploadDropzoneProps = 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'
},
clearable: Boolean,
disabled: Boolean,
error: Boolean,
hideBrowse: Boolean,
insetFileList: Boolean,
multiple: Boolean,
scrim: {
type: [Boolean, String],
default: true
},
showSize: Boolean,
...makeDelayProps(),
...makeDensityProps(),
...pick(makeVDividerProps({
length: 150
}), ['length', 'thickness', 'opacity']),
...makeVSheetProps(),
modelValue: {
type: Array,
default: () => []
}
}, 'VFileUploadDropzone');
export const VFileUploadDropzone = genericComponent()({
name: 'VFileUploadDropzone',
props: makeVFileUploadDropzoneProps(),
emits: {
'click:browse': () => true,
'click:remove': index => true,
drop: files => true
},
setup(props, {
emit,
slots
}) {
const {
t
} = useLocale();
const {
densityClasses
} = useDensity(props);
const {
handleDrop
} = useFileDrop();
const context = inject(VFileUploadKey, null);
const vSheetRef = ref();
const isDragging = shallowRef(false);
function onDragover(e) {
e.preventDefault();
e.stopImmediatePropagation();
isDragging.value = true;
}
function onDragleave(e) {
e.preventDefault();
const container = e.currentTarget;
if (!container.contains(e.relatedTarget)) {
isDragging.value = false;
}
}
async function onDrop(e) {
e.preventDefault();
e.stopImmediatePropagation();
isDragging.value = false;
const files = await handleDrop(e);
if (context) {
context.onDrop(files);
} else {
emit('drop', files);
}
}
function onClickBrowse() {
if (context) {
context.onClickBrowse();
} else {
emit('click:browse');
}
}
function onClickRemove(index) {
if (context) {
context.onClickRemove(index);
} else {
emit('click:remove', index);
}
}
useRender(() => {
const modelValue = context?.files.value ?? props.modelValue;
const disabled = context?.disabled.value ?? props.disabled;
const error = context?.error.value || props.error;
const hasTitle = !!(slots.title || props.title);
const hasIcon = !!(slots.icon || props.icon);
const hasBrowse = !!(!props.hideBrowse && (slots.browse || props.density === 'default'));
const hasFiles = modelValue.length > 0;
const isInset = props.insetFileList && hasFiles;
const sheetProps = VSheet.filterProps(props);
const dividerProps = VDivider.filterProps(props);
return _createVNode(VSheet, _mergeProps({
"ref": vSheetRef
}, sheetProps, {
"class": ['v-file-upload-dropzone', {
'v-file-upload-dropzone--clickable': !hasBrowse,
'v-file-upload-dropzone--disabled': disabled,
'v-file-upload-dropzone--dragging': isDragging.value,
'v-file-upload-dropzone--has-files': hasFiles,
'v-file-upload-dropzone--inset': isInset,
'v-file-upload-dropzone--error': error
}, densityClasses.value, props.class],
"style": props.style,
"onDragleave": onDragleave,
"onDragover": onDragover,
"onDrop": onDrop,
"onClick": !hasBrowse && !(isInset && hasFiles) ? onClickBrowse : undefined
}), {
default: () => [slots.default?.({
isDragging: isDragging.value,
hasFiles,
files: modelValue,
props: {
onClick: onClickBrowse
}
}) ?? (isInset ? _createElementVNode("div", {
"key": "inset",
"class": "v-file-upload-inset"
}, [modelValue.length === 1 && !props.multiple ? slots.single?.({
file: modelValue[0],
props: {
'onClick:remove': () => onClickRemove(0)
}
}) ?? _createVNode(VDefaultsProvider, {
"defaults": {
VFileUploadItem: {
file: modelValue[0],
clearable: props.clearable,
disabled,
showSize: props.showSize,
border: false
}
}
}, {
default: () => [_createVNode(VFileUploadItem, {
"onClick:remove": () => onClickRemove(0)
}, null)]
}) : modelValue.map((file, i) => {
const slotProps = {
file,
props: {
'onClick:remove': () => onClickRemove(i)
}
};
return _createVNode(VDefaultsProvider, {
"key": i,
"defaults": {
VFileUploadItem: {
file,
clearable: props.clearable,
disabled,
showSize: props.showSize,
border: false
}
}
}, {
default: () => [slots.item?.(slotProps) ?? _createVNode(VFileUploadItem, {
"key": i,
"onClick:remove": () => onClickRemove(i)
}, null)]
});
}), _createVNode(VDivider, null, null), _createElementVNode("div", {
"class": "v-file-upload-inset__action"
}, [!slots.browse ? _createVNode(VBtn, {
"readonly": disabled,
"text": t(props.browseText),
"variant": "text",
"onClick": onClickBrowse
}, null) : _createVNode(VDefaultsProvider, {
"defaults": {
VBtn: {
readonly: disabled,
text: t(props.browseText),
variant: 'text'
}
}
}, {
default: () => [slots.browse({
props: {
onClick: onClickBrowse
}
})]
})])]) : _createElementVNode(_Fragment, null, [hasIcon && _createElementVNode("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 && _createElementVNode("div", {
"key": "title",
"class": "v-file-upload-title"
}, [slots.title?.() ?? t(props.title)]), props.density === 'default' && _createElementVNode(_Fragment, null, [hasBrowse && _createElementVNode(_Fragment, null, [_createElementVNode("div", {
"key": "upload-divider",
"class": "v-file-upload-divider"
}, [slots.divider?.() ?? _createVNode(VDivider, dividerProps, {
default: () => [t(props.dividerText)]
})]), !slots.browse ? _createVNode(VBtn, {
"readonly": disabled,
"size": "large",
"text": t(props.browseText),
"variant": "tonal",
"onClick": onClickBrowse
}, null) : _createVNode(VDefaultsProvider, {
"defaults": {
VBtn: {
readonly: disabled,
size: 'large',
text: t(props.browseText),
variant: 'tonal'
}
}
}, {
default: () => [slots.browse({
props: {
onClick: onClickBrowse
}
})]
})]), props.subtitle && _createElementVNode("div", {
"class": "v-file-upload-subtitle"
}, [props.subtitle])])])), _createVNode(VOverlay, {
"modelValue": isDragging.value,
"contained": true,
"scrim": props.scrim
}, null), slots.input?.()]
});
});
return forwardRefs({}, vSheetRef);
}
});
//# sourceMappingURL=VFileUploadDropzone.js.map