import { VCounter, VField, makeVFieldProps } from "./chunk-ITO3JWXJ.js"; import { VChip } from "./chunk-PLNIG6WP.js"; import { VInput, makeVInputProps, useFocus } from "./chunk-IK67YVHF.js"; import { forwardRefs } from "./chunk-GUNW7S2L.js"; import { useLocale } from "./chunk-ENTLCOCZ.js"; import { useProxiedModel } from "./chunk-KA77II4V.js"; import { callEvent, filterInputAttrs, genericComponent, humanReadableFileSize, propsFactory, useRender, wrapInArray } from "./chunk-LZ5T2ERG.js"; import { Fragment, computed, createBaseVNode, createVNode, mergeProps, nextTick, normalizeClass, ref, shallowRef, toRef, watch } from "./chunk-2MKFL3BX.js"; // node_modules/vuetify/lib/components/VFileInput/VFileInput.js import "/home/david/gitea_repo/personal_development/ServerManagerWebApp/frontend/node_modules/vuetify/lib/components/VFileInput/VFileInput.css"; // node_modules/vuetify/lib/composables/fileDrop.js function useFileDrop() { function hasFilesOrFolders(e) { const entries = [...e.dataTransfer?.items ?? []].filter((x) => x.kind === "file").map((x) => x.webkitGetAsEntry()).filter(Boolean); return entries.length > 0 || [...e.dataTransfer?.files ?? []].length > 0; } async function handleDrop(e) { const result = []; const entries = [...e.dataTransfer?.items ?? []].filter((x) => x.kind === "file").map((x) => x.webkitGetAsEntry()).filter(Boolean); if (entries.length) { for (const entry of entries) { const files = await traverseFileTree(entry, appendIfDirectory(".", entry)); result.push(...files.map((x) => x.file)); } } else { result.push(...[...e.dataTransfer?.files ?? []]); } return result; } return { handleDrop, hasFilesOrFolders }; } function traverseFileTree(item) { let path = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : ""; return new Promise((resolve, reject) => { if (item.isFile) { const fileEntry = item; fileEntry.file((file) => resolve([{ file, path }]), reject); } else if (item.isDirectory) { const directoryReader = item.createReader(); directoryReader.readEntries(async (entries) => { const files = []; for (const entry of entries) { files.push(...await traverseFileTree(entry, appendIfDirectory(path, entry))); } resolve(files); }); } }); } function appendIfDirectory(path, item) { return item.isDirectory ? `${path}/${item.name}` : path; } // node_modules/vuetify/lib/composables/fileFilter.js var makeFileFilterProps = propsFactory({ filterByType: String }, "file-accept"); function useFileFilter(props) { const fileFilter = computed(() => props.filterByType ? createFilter(props.filterByType) : null); function filterAccepted(files) { if (fileFilter.value) { const accepted = files.filter(fileFilter.value); return { accepted, rejected: files.filter((f) => !accepted.includes(f)) }; } return { accepted: files, rejected: [] }; } return { filterAccepted }; } function createFilter(v) { const types = v.split(",").map((x) => x.trim().toLowerCase()); const extensionsToMatch = types.filter((x) => x.startsWith(".")); const wildcards = types.filter((x) => x.endsWith("/*")); const typesToMatch = types.filter((x) => !extensionsToMatch.includes(x) && !wildcards.includes(x)); return (file) => { const extension = file.name.split(".").at(-1)?.toLowerCase() ?? ""; const typeGroup = file.type.split("/").at(0)?.toLowerCase() ?? ""; return typesToMatch.includes(file.type) || extensionsToMatch.includes(`.${extension}`) || wildcards.includes(`${typeGroup}/*`); }; } // node_modules/vuetify/lib/components/VFileInput/VFileInput.js var makeVFileInputProps = propsFactory({ chips: Boolean, counter: Boolean, counterSizeString: { type: String, default: "$vuetify.fileInput.counterSize" }, counterString: { type: String, default: "$vuetify.fileInput.counter" }, hideInput: Boolean, multiple: Boolean, showSize: { type: [Boolean, Number, String], default: false, validator: (v) => { return typeof v === "boolean" || [1e3, 1024].includes(Number(v)); } }, truncateLength: { type: [Number, String], default: 22 }, ...makeVInputProps({ prependIcon: "$file" }), modelValue: { type: [Array, Object], default: (props) => props.multiple ? [] : null, validator: (val) => { return wrapInArray(val).every((v) => v != null && typeof v === "object"); } }, ...makeFileFilterProps(), ...makeVFieldProps({ clearable: true }) }, "VFileInput"); var VFileInput = genericComponent()({ name: "VFileInput", inheritAttrs: false, props: makeVFileInputProps(), emits: { "click:control": (e) => true, "mousedown:control": (e) => true, "update:focused": (focused) => true, "update:modelValue": (files) => true, rejected: (files) => true }, setup(props, _ref) { let { attrs, emit, slots } = _ref; const { t } = useLocale(); const { filterAccepted } = useFileFilter(props); const model = useProxiedModel(props, "modelValue", props.modelValue, (val) => wrapInArray(val), (val) => !props.multiple && Array.isArray(val) ? val[0] : val); const { isFocused, focus, blur } = useFocus(props); const base = computed(() => typeof props.showSize !== "boolean" ? props.showSize : void 0); const totalBytes = computed(() => (model.value ?? []).reduce((bytes, _ref2) => { let { size = 0 } = _ref2; return bytes + size; }, 0)); const totalBytesReadable = computed(() => humanReadableFileSize(totalBytes.value, base.value)); const fileNames = computed(() => (model.value ?? []).map((file) => { const { name = "", size = 0 } = file; const truncatedText = truncateText(name); return !props.showSize ? truncatedText : `${truncatedText} (${humanReadableFileSize(size, base.value)})`; })); const counterValue = computed(() => { const fileCount = model.value?.length ?? 0; if (props.showSize) return t(props.counterSizeString, fileCount, totalBytesReadable.value); else return t(props.counterString, fileCount); }); const vInputRef = ref(); const vFieldRef = ref(); const inputRef = ref(); const isActive = toRef(() => isFocused.value || props.active); const isPlainOrUnderlined = computed(() => ["plain", "underlined"].includes(props.variant)); const isDragging = shallowRef(false); const { handleDrop, hasFilesOrFolders } = useFileDrop(); function onFocus() { if (inputRef.value !== document.activeElement) { inputRef.value?.focus(); } if (!isFocused.value) focus(); } function onClickPrepend(e) { inputRef.value?.click(); } function onControlMousedown(e) { emit("mousedown:control", e); } function onControlClick(e) { inputRef.value?.click(); emit("click:control", e); } function onClear(e) { e.stopPropagation(); onFocus(); nextTick(() => { model.value = []; callEvent(props["onClick:clear"], e); }); } function truncateText(str) { if (str.length < Number(props.truncateLength)) return str; const charsKeepOneSide = Math.floor((Number(props.truncateLength) - 1) / 2); return `${str.slice(0, charsKeepOneSide)}…${str.slice(str.length - charsKeepOneSide)}`; } function onDragover(e) { e.preventDefault(); e.stopImmediatePropagation(); isDragging.value = true; } function onDragleave(e) { e.preventDefault(); isDragging.value = false; } async function onDrop(e) { e.preventDefault(); e.stopImmediatePropagation(); isDragging.value = false; if (!inputRef.value || !hasFilesOrFolders(e)) return; const allDroppedFiles = await handleDrop(e); selectAccepted(allDroppedFiles); } function onFileSelection(e) { if (!e.target || e.repack) return; if (!props.filterByType) { const target = e.target; model.value = [...target.files ?? []]; } else { selectAccepted([...e.target.files]); } } function selectAccepted(files) { const dataTransfer = new DataTransfer(); const { accepted, rejected } = filterAccepted(files); if (rejected.length) { emit("rejected", rejected); } for (const file of accepted) { dataTransfer.items.add(file); } inputRef.value.files = dataTransfer.files; model.value = [...dataTransfer.files]; const event = new Event("change", { bubbles: true }); event.repack = true; inputRef.value.dispatchEvent(event); } watch(model, (newValue) => { const hasModelReset = !Array.isArray(newValue) || !newValue.length; if (hasModelReset && inputRef.value) { inputRef.value.value = ""; } }); useRender(() => { const hasCounter = !!(slots.counter || props.counter); const hasDetails = !!(hasCounter || slots.details); const [rootAttrs, inputAttrs] = filterInputAttrs(attrs); const { modelValue: _, ...inputProps } = VInput.filterProps(props); const fieldProps = { ...VField.filterProps(props), "onClick:clear": onClear }; const expectsDirectory = attrs.webkitdirectory !== void 0 && attrs.webkitdirectory !== false; const acceptFallback = attrs.accept ? String(attrs.accept) : void 0; const inputAccept = expectsDirectory ? void 0 : props.filterByType ?? acceptFallback; return createVNode(VInput, mergeProps({ "ref": vInputRef, "modelValue": props.multiple ? model.value : model.value[0], "class": ["v-file-input", { "v-file-input--chips": !!props.chips, "v-file-input--dragging": isDragging.value, "v-file-input--hide": props.hideInput, "v-input--plain-underlined": isPlainOrUnderlined.value }, props.class], "style": props.style, "onClick:prepend": onClickPrepend }, rootAttrs, inputProps, { "centerAffix": !isPlainOrUnderlined.value, "focused": isFocused.value }), { ...slots, default: (_ref3) => { let { id, isDisabled, isDirty, isReadonly, isValid, hasDetails: hasDetails2 } = _ref3; return createVNode(VField, mergeProps({ "ref": vFieldRef, "prependIcon": props.prependIcon, "onMousedown": onControlMousedown, "onClick": onControlClick, "onClick:prependInner": props["onClick:prependInner"], "onClick:appendInner": props["onClick:appendInner"] }, fieldProps, { "id": id.value, "active": isActive.value || isDirty.value, "dirty": isDirty.value || props.dirty, "disabled": isDisabled.value, "focused": isFocused.value, "details": hasDetails2.value, "error": isValid.value === false, "onDragover": onDragover, "onDrop": onDrop }), { ...slots, default: (_ref4) => { let { props: { class: fieldClass, ...slotProps }, controlRef } = _ref4; return createBaseVNode(Fragment, null, [createBaseVNode("input", mergeProps({ "ref": (val) => inputRef.value = controlRef.value = val, "type": "file", "accept": inputAccept, "readonly": isReadonly.value, "disabled": isDisabled.value, "multiple": props.multiple, "name": props.name, "onClick": (e) => { e.stopPropagation(); if (isReadonly.value) e.preventDefault(); onFocus(); }, "onChange": onFileSelection, "onDragleave": onDragleave, "onFocus": onFocus, "onBlur": blur }, slotProps, inputAttrs), null), createBaseVNode("div", { "class": normalizeClass(fieldClass) }, [!!model.value?.length && !props.hideInput && (slots.selection ? slots.selection({ fileNames: fileNames.value, totalBytes: totalBytes.value, totalBytesReadable: totalBytesReadable.value }) : props.chips ? fileNames.value.map((text) => createVNode(VChip, { "key": text, "size": "small", "text": text }, null)) : fileNames.value.join(", "))])]); } }); }, details: hasDetails ? (slotProps) => createBaseVNode(Fragment, null, [slots.details?.(slotProps), hasCounter && createBaseVNode(Fragment, null, [createBaseVNode("span", null, null), createVNode(VCounter, { "active": !!model.value?.length, "value": counterValue.value, "disabled": props.disabled }, slots.counter)])]) : void 0 }); }); return forwardRefs({}, vInputRef, vFieldRef, inputRef); } }); export { VFileInput }; //# sourceMappingURL=chunk-EKMPZMZF.js.map