UNPKG

bootstrap-vue-next

Version:

Seamless integration of Vue 3, Bootstrap 5, and TypeScript for modern, type-safe UI development

418 lines (417 loc) 15.8 kB
require("./chunk-CoQrYLCe.js"); const require_dist = require("./dist-B_c893QG.js"); const require_dom = require("./dom-Bs6DzM72.js"); const require_useDefaults = require("./useDefaults-DsLf4iRY.js"); const require_useId = require("./useId-DHrBgM7P.js"); const require_useStateClass = require("./useStateClass-0b-hPufa.js"); let vue = require("vue"); //#region src/components/BFormFile/BFormFile.vue?vue&type=script&setup=true&lang.ts var _hoisted_1 = ["for"]; var _hoisted_2 = ["aria-disabled"]; var _hoisted_3 = [ "id", "disabled", "aria-label", "aria-labelledby" ]; var _hoisted_4 = { class: "b-form-file-text" }; var _hoisted_5 = { key: 0 }; var _hoisted_6 = { key: 1, class: "text-muted" }; var _hoisted_7 = { key: 0, class: "b-form-file-drag-overlay" }; var _hoisted_8 = { class: "b-form-file-drag-text" }; var _hoisted_9 = [ "name", "form", "multiple", "disabled", "required", "accept", "capture", "directory", "webkitdirectory" ]; var _hoisted_10 = [ "id", "form", "name", "multiple", "disabled", "capture", "accept", "required", "aria-label", "aria-labelledby", "aria-required", "directory", "webkitdirectory" ]; var _hoisted_11 = { key: 3, class: "b-form-file-display mt-2" }; var _hoisted_12 = { key: 0, class: "small text-muted" }; var _hoisted_13 = { key: 1, class: "small text-muted" }; var _hoisted_14 = { key: 4, class: "visually-hidden", "aria-live": "polite", "aria-atomic": "true" }; //#endregion //#region src/components/BFormFile/BFormFile.vue var BFormFile_default = /* @__PURE__ */ (0, vue.defineComponent)({ inheritAttrs: false, __name: "BFormFile", props: /* @__PURE__ */ (0, vue.mergeModels)({ ariaLabel: { default: void 0 }, ariaLabelledby: { default: void 0 }, accept: { default: "" }, autofocus: { type: Boolean, default: false }, browseText: { default: void 0 }, capture: { default: void 0 }, directory: { type: Boolean, default: false }, disabled: { type: Boolean, default: false }, dropPlaceholder: { default: void 0 }, fileNameFormatter: { type: Function, default: void 0 }, form: { default: void 0 }, id: { default: void 0 }, label: { default: "" }, labelClass: { default: void 0 }, multiple: { type: Boolean, default: false }, name: { default: void 0 }, noButton: { type: Boolean, default: false }, noDrop: { type: Boolean, default: false }, plain: { type: Boolean, default: false }, placeholder: { default: "No file chosen" }, required: { type: Boolean, default: false }, showFileNames: { type: Boolean, default: false }, size: { default: void 0 }, state: { type: [Boolean, null], default: null } }, { "modelValue": { default: null }, "modelModifiers": {} }), emits: /* @__PURE__ */ (0, vue.mergeModels)(["change"], ["update:modelValue"]), setup(__props, { expose: __expose, emit: __emit }) { const props = require_useDefaults.useDefaults(__props, "BFormFile"); const slots = (0, vue.useSlots)(); const emit = __emit; const modelValue = (0, vue.useModel)(__props, "modelValue"); const attrs = (0, vue.useAttrs)(); const processedAttrs = (0, vue.computed)(() => { if (props.plain) return { rootAttrs: {}, dropZoneAttrs: {}, inputAttrs: attrs }; const { class: rootClass, style: rootStyle, title: dropZoneTitle, ...inputAttrs } = attrs; const rootAttrs = {}; const dropZoneAttrs = {}; if (rootClass !== void 0) rootAttrs.class = rootClass; if (rootStyle !== void 0) rootAttrs.style = rootStyle; if (dropZoneTitle !== void 0) dropZoneAttrs.title = dropZoneTitle; return { rootAttrs, dropZoneAttrs, inputAttrs }; }); const computedId = require_useId.useId(() => props.id); const stateClass = require_useStateClass.useStateClass(() => props.state); const rootRef = (0, vue.useTemplateRef)("rootRef"); const dropZoneRef = (0, vue.useTemplateRef)("dropZoneRef"); const browseButtonRef = (0, vue.useTemplateRef)("browseButtonRef"); const plainInputRef = (0, vue.useTemplateRef)("plainInputRef"); const customInputRef = (0, vue.useTemplateRef)("customInputRef"); const computedAccept = (0, vue.computed)(() => typeof props.accept === "string" ? props.accept : props.accept.join(",")); const { open, reset: resetDialog, onChange: onDialogChange } = require_dist.useFileDialog({ accept: computedAccept.value, multiple: props.multiple || props.directory, directory: props.directory, input: customInputRef }); const { isOverDropZone } = require_dist.useDropZone(dropZoneRef, { onDrop: (files) => { if (files && !props.noDrop) handleFiles(files); }, multiple: props.multiple || props.directory }); const hasLabelSlot = (0, vue.computed)(() => !require_dom.isEmptySlot(slots.label)); const hasPlaceholderSlot = (0, vue.computed)(() => !require_dom.isEmptySlot(slots.placeholder)); const computedClasses = (0, vue.computed)(() => [stateClass.value, { [`form-control-${props.size}`]: props.size !== void 0 }]); const computedPlainClasses = (0, vue.computed)(() => [ "form-control", stateClass.value, { [`form-control-${props.size}`]: props.size !== void 0 } ]); const internalFiles = (0, vue.ref)([]); const selectedFiles = (0, vue.computed)(() => internalFiles.value); const hasFiles = (0, vue.computed)(() => selectedFiles.value.length > 0); const fileNames = (0, vue.computed)(() => selectedFiles.value.map((file) => file.name)); const formattedFileNames = (0, vue.computed)(() => { if (!hasFiles.value) return ""; if (props.fileNameFormatter) return props.fileNameFormatter(selectedFiles.value); const names = fileNames.value; if (names.length === 1) return names[0]; return `${names.length} files selected`; }); const showExternalDisplay = (0, vue.computed)(() => !props.plain && props.showFileNames && (hasFiles.value || props.placeholder)); const ariaLiveMessage = (0, vue.computed)(() => { if (!hasFiles.value) return ""; const count = selectedFiles.value.length; if (count === 1) return `File selected: ${selectedFiles.value[0]?.name}`; return `${count} files selected`; }); const effectiveBrowseText = (0, vue.computed)(() => props.browseText ?? "Browse"); const effectiveDropPlaceholder = (0, vue.computed)(() => props.dropPlaceholder ?? "Drop files here..."); const isFileAccepted = (file) => { if (!computedAccept.value) return true; return computedAccept.value.split(",").map((type) => type.trim()).some((acceptType) => { if (acceptType.startsWith(".")) return file.name.toLowerCase().endsWith(acceptType.toLowerCase()); if (!acceptType.includes("*")) return file.type === acceptType; const slashIndex = acceptType.indexOf("/"); if (slashIndex === -1) return false; const category = acceptType.slice(0, slashIndex); if (category === "*") return true; return file.type.startsWith(`${category}/`); }); }; const handleFiles = (files, nativeEvent) => { let fileArray = []; if (nativeEvent) { const input = nativeEvent.target; fileArray = input.files ? Array.from(input.files) : []; } else { fileArray = Array.from(files).filter((file) => isFileAccepted(file)); if (customInputRef.value && typeof DataTransfer !== "undefined") try { const dataTransfer = new DataTransfer(); fileArray.forEach((file) => dataTransfer.items.add(file)); customInputRef.value.files = dataTransfer.files; } catch {} } internalFiles.value = fileArray; if (fileArray.length === 0) modelValue.value = null; else if (props.directory || props.multiple) modelValue.value = fileArray; else { const [firstFile] = fileArray; if (firstFile) modelValue.value = firstFile; } (0, vue.nextTick)(() => { if (nativeEvent) emit("change", nativeEvent); else { const changeEvent = new CustomEvent("change", { bubbles: true, cancelable: false, detail: { files: fileArray, target: { files: fileArray } } }); Object.defineProperty(changeEvent, "files", { value: fileArray, enumerable: true }); emit("change", changeEvent); } }); }; const openFileDialog = () => { if (!props.disabled) open({ accept: computedAccept.value, multiple: props.multiple || props.directory, directory: props.directory }); }; const handleControlClick = () => { if (!props.disabled) openFileDialog(); }; const onPlainChange = (e) => { const input = e.target; if (input.files) handleFiles(input.files, e); }; onDialogChange((files) => { if (files) handleFiles(files); }); const reset = () => { internalFiles.value = []; modelValue.value = null; resetDialog(); if (plainInputRef.value) plainInputRef.value.value = ""; }; const focus = () => { if (props.plain) plainInputRef.value?.focus(); else browseButtonRef.value?.focus(); }; const blur = () => { if (props.plain) plainInputRef.value?.blur(); else browseButtonRef.value?.blur(); }; (0, vue.onMounted)(() => { if (props.autofocus) (0, vue.nextTick)(() => { focus(); }); }); (0, vue.watch)(() => props.autofocus, (autofocus) => { if (autofocus) focus(); }); (0, vue.watch)(modelValue, (newValue) => { if (newValue === null) { internalFiles.value = []; if (plainInputRef.value) plainInputRef.value.value = ""; } else if (Array.isArray(newValue)) internalFiles.value = newValue; else internalFiles.value = [newValue]; }); __expose({ blur, element: (0, vue.computed)(() => props.plain ? plainInputRef.value : browseButtonRef.value), focus, reset }); return (_ctx, _cache) => { return (0, vue.openBlock)(), (0, vue.createElementBlock)("div", (0, vue.mergeProps)({ ref_key: "rootRef", ref: rootRef }, processedAttrs.value.rootAttrs, { class: "b-form-file-root" }), [ hasLabelSlot.value || (0, vue.unref)(props).label ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("label", { key: 0, class: (0, vue.normalizeClass)(["form-label", (0, vue.unref)(props).labelClass]), for: (0, vue.unref)(computedId) }, [(0, vue.renderSlot)(_ctx.$slots, "label", {}, () => [(0, vue.createTextVNode)((0, vue.toDisplayString)((0, vue.unref)(props).label), 1)])], 10, _hoisted_1)) : (0, vue.createCommentVNode)("", true), !(0, vue.unref)(props).plain ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", (0, vue.mergeProps)({ key: 1, ref_key: "dropZoneRef", ref: dropZoneRef }, processedAttrs.value.dropZoneAttrs, { class: ["b-form-file-wrapper", { "b-form-file-dragging": (0, vue.unref)(isOverDropZone) && !(0, vue.unref)(props).noDrop, "b-form-file-has-files": hasFiles.value }] }), [ (0, vue.createElementVNode)("div", { class: (0, vue.normalizeClass)(["b-form-file-control", computedClasses.value]), "aria-disabled": (0, vue.unref)(props).disabled, onClick: handleControlClick }, [!(0, vue.unref)(props).noButton ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", { key: 0, id: (0, vue.unref)(computedId), ref_key: "browseButtonRef", ref: browseButtonRef, type: "button", class: "b-form-file-button", disabled: (0, vue.unref)(props).disabled, "aria-label": (0, vue.unref)(props).ariaLabel, "aria-labelledby": (0, vue.unref)(props).ariaLabelledby, onClick: (0, vue.withModifiers)(openFileDialog, ["stop"]) }, (0, vue.toDisplayString)(effectiveBrowseText.value), 9, _hoisted_3)) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("div", _hoisted_4, [(0, vue.renderSlot)(_ctx.$slots, "file-name", { files: selectedFiles.value, names: fileNames.value }, () => [hasFiles.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_5, (0, vue.toDisplayString)(formattedFileNames.value), 1)) : hasPlaceholderSlot.value || (0, vue.unref)(props).placeholder ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_6, [(0, vue.renderSlot)(_ctx.$slots, "placeholder", {}, () => [(0, vue.createTextVNode)((0, vue.toDisplayString)((0, vue.unref)(props).placeholder), 1)])])) : (0, vue.createCommentVNode)("", true)])])], 10, _hoisted_2), (0, vue.unref)(isOverDropZone) && !(0, vue.unref)(props).noDrop ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_7, [(0, vue.renderSlot)(_ctx.$slots, "drop-placeholder", {}, () => [(0, vue.createElementVNode)("div", _hoisted_8, (0, vue.toDisplayString)(effectiveDropPlaceholder.value), 1)])])) : (0, vue.createCommentVNode)("", true), (0, vue.createElementVNode)("input", (0, vue.mergeProps)({ ref_key: "customInputRef", ref: customInputRef }, processedAttrs.value.inputAttrs, { type: "file", name: (0, vue.unref)(props).name, form: (0, vue.unref)(props).form, multiple: (0, vue.unref)(props).multiple || (0, vue.unref)(props).directory, disabled: (0, vue.unref)(props).disabled, required: (0, vue.unref)(props).required, accept: computedAccept.value || void 0, capture: (0, vue.unref)(props).capture, directory: (0, vue.unref)(props).directory || void 0, webkitdirectory: (0, vue.unref)(props).directory || void 0, tabindex: "-1", "aria-hidden": "true", style: { "position": "absolute", "z-index": "-5", "width": "0", "height": "0", "opacity": "0", "overflow": "hidden", "pointer-events": "none" } }), null, 16, _hoisted_9) ], 16)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("input", (0, vue.mergeProps)({ key: 2, id: (0, vue.unref)(computedId), ref_key: "plainInputRef", ref: plainInputRef }, processedAttrs.value.inputAttrs, { type: "file", class: computedPlainClasses.value, form: (0, vue.unref)(props).form, name: (0, vue.unref)(props).name, multiple: (0, vue.unref)(props).multiple || (0, vue.unref)(props).directory, disabled: (0, vue.unref)(props).disabled, capture: (0, vue.unref)(props).capture, accept: computedAccept.value || void 0, required: (0, vue.unref)(props).required || void 0, "aria-label": (0, vue.unref)(props).ariaLabel, "aria-labelledby": (0, vue.unref)(props).ariaLabelledby, "aria-required": (0, vue.unref)(props).required || void 0, directory: (0, vue.unref)(props).directory || void 0, webkitdirectory: (0, vue.unref)(props).directory || void 0, onChange: onPlainChange }), null, 16, _hoisted_10)), showExternalDisplay.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_11, [(0, vue.renderSlot)(_ctx.$slots, "file-name", { files: selectedFiles.value, names: fileNames.value }, () => [hasFiles.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_12, (0, vue.toDisplayString)(formattedFileNames.value), 1)) : hasPlaceholderSlot.value || (0, vue.unref)(props).placeholder ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_13, [(0, vue.renderSlot)(_ctx.$slots, "placeholder", {}, () => [(0, vue.createTextVNode)((0, vue.toDisplayString)((0, vue.unref)(props).placeholder), 1)])])) : (0, vue.createCommentVNode)("", true)])])) : (0, vue.createCommentVNode)("", true), !(0, vue.unref)(props).plain ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_14, (0, vue.toDisplayString)(ariaLiveMessage.value), 1)) : (0, vue.createCommentVNode)("", true) ], 16); }; } }); //#endregion Object.defineProperty(exports, "BFormFile_default", { enumerable: true, get: function() { return BFormFile_default; } }); //# sourceMappingURL=BFormFile-N491i_FE.js.map