{"version":3,"file":"BFormFile-DUd50zn5.mjs","names":[],"sources":["../src/components/BFormFile/BFormFile.vue","../src/components/BFormFile/BFormFile.vue"],"sourcesContent":["<template>\n  <div ref=\"rootRef\" v-bind=\"processedAttrs.rootAttrs\" class=\"b-form-file-root\">\n    <!-- Optional label -->\n    <label\n      v-if=\"hasLabelSlot || props.label\"\n      class=\"form-label\"\n      :class=\"props.labelClass\"\n      :for=\"computedId\"\n    >\n      <slot name=\"label\">\n        {{ props.label }}\n      </slot>\n    </label>\n\n    <!-- Drop zone wrapper -->\n    <div\n      v-if=\"!props.plain\"\n      ref=\"dropZoneRef\"\n      v-bind=\"processedAttrs.dropZoneAttrs\"\n      class=\"b-form-file-wrapper\"\n      :class=\"{\n        'b-form-file-dragging': isOverDropZone && !props.noDrop,\n        'b-form-file-has-files': hasFiles,\n      }\"\n    >\n      <!-- Custom file control (mimics Bootstrap native input) -->\n      <div\n        class=\"b-form-file-control\"\n        :class=\"computedClasses\"\n        :aria-disabled=\"props.disabled\"\n        @click=\"handleControlClick\"\n      >\n        <!-- Custom browse button (now on LEFT to match Bootstrap v5) -->\n        <button\n          v-if=\"!props.noButton\"\n          :id=\"computedId\"\n          ref=\"browseButtonRef\"\n          type=\"button\"\n          class=\"b-form-file-button\"\n          :disabled=\"props.disabled\"\n          :aria-label=\"props.ariaLabel\"\n          :aria-labelledby=\"props.ariaLabelledby\"\n          @click.stop=\"openFileDialog\"\n        >\n          {{ effectiveBrowseText }}\n        </button>\n\n        <!-- File name display -->\n        <div class=\"b-form-file-text\">\n          <slot name=\"file-name\" :files=\"selectedFiles\" :names=\"fileNames\">\n            <span v-if=\"hasFiles\">{{ formattedFileNames }}</span>\n            <span v-else-if=\"hasPlaceholderSlot || props.placeholder\" class=\"text-muted\">\n              <slot name=\"placeholder\">{{ props.placeholder }}</slot>\n            </span>\n          </slot>\n        </div>\n      </div>\n\n      <!-- Drag overlay (only shown when dragging) -->\n      <div v-if=\"isOverDropZone && !props.noDrop\" class=\"b-form-file-drag-overlay\">\n        <slot name=\"drop-placeholder\">\n          <div class=\"b-form-file-drag-text\">\n            {{ effectiveDropPlaceholder }}\n          </div>\n        </slot>\n      </div>\n\n      <!-- Hidden input for form submission (positioned behind UI with z-index) -->\n      <input\n        ref=\"customInputRef\"\n        v-bind=\"processedAttrs.inputAttrs\"\n        type=\"file\"\n        :name=\"props.name\"\n        :form=\"props.form\"\n        :multiple=\"props.multiple || props.directory\"\n        :disabled=\"props.disabled\"\n        :required=\"props.required\"\n        :accept=\"computedAccept || undefined\"\n        :capture=\"props.capture\"\n        :directory=\"props.directory || undefined\"\n        :webkitdirectory=\"props.directory || undefined\"\n        tabindex=\"-1\"\n        aria-hidden=\"true\"\n        style=\"\n          position: absolute;\n          z-index: -5;\n          width: 0;\n          height: 0;\n          opacity: 0;\n          overflow: hidden;\n          pointer-events: none;\n        \"\n      />\n    </div>\n\n    <!-- Plain mode - simple native input -->\n    <input\n      v-else\n      :id=\"computedId\"\n      ref=\"plainInputRef\"\n      v-bind=\"processedAttrs.inputAttrs\"\n      type=\"file\"\n      :class=\"computedPlainClasses\"\n      :form=\"props.form\"\n      :name=\"props.name\"\n      :multiple=\"props.multiple || props.directory\"\n      :disabled=\"props.disabled\"\n      :capture=\"props.capture\"\n      :accept=\"computedAccept || undefined\"\n      :required=\"props.required || undefined\"\n      :aria-label=\"props.ariaLabel\"\n      :aria-labelledby=\"props.ariaLabelledby\"\n      :aria-required=\"props.required || undefined\"\n      :directory=\"props.directory || undefined\"\n      :webkitdirectory=\"props.directory || undefined\"\n      @change=\"onPlainChange\"\n    />\n\n    <!-- External file display (when showFileNames is true and not plain) -->\n    <div v-if=\"showExternalDisplay\" class=\"b-form-file-display mt-2\">\n      <slot name=\"file-name\" :files=\"selectedFiles\" :names=\"fileNames\">\n        <div v-if=\"hasFiles\" class=\"small text-muted\">\n          {{ formattedFileNames }}\n        </div>\n        <div v-else-if=\"hasPlaceholderSlot || props.placeholder\" class=\"small text-muted\">\n          <slot name=\"placeholder\">\n            {{ props.placeholder }}\n          </slot>\n        </div>\n      </slot>\n    </div>\n\n    <!-- ARIA live region for screen reader announcements -->\n    <div v-if=\"!props.plain\" class=\"visually-hidden\" aria-live=\"polite\" aria-atomic=\"true\">\n      {{ ariaLiveMessage }}\n    </div>\n  </div>\n</template>\n\n<script setup lang=\"ts\">\nimport {useDropZone, useFileDialog} from '@vueuse/core'\nimport {computed, nextTick, onMounted, ref, type Ref, useAttrs, useTemplateRef, watch} from 'vue'\nimport {useDefaults} from '../../composables/useDefaults'\nimport {useId} from '../../composables/useId'\nimport {useStateClass} from '../../composables/useStateClass'\nimport {isEmptySlot} from '../../utils/dom'\nimport type {BFormFileSlots, BFormFileProps} from '../../types'\n\ndefineOptions({\n  inheritAttrs: false,\n})\n\nconst _props = withDefaults(defineProps<Omit<BFormFileProps, 'modelValue'>>(), {\n  ariaLabel: undefined,\n  ariaLabelledby: undefined,\n  accept: '',\n  autofocus: false,\n  browseText: undefined,\n  capture: undefined,\n  directory: false,\n  disabled: false,\n  dropPlaceholder: undefined,\n  fileNameFormatter: undefined,\n  form: undefined,\n  id: undefined,\n  label: '',\n  labelClass: undefined,\n  multiple: false,\n  name: undefined,\n  noButton: false,\n  noDrop: false,\n  plain: false,\n  placeholder: 'No file chosen',\n  required: false,\n  showFileNames: false,\n  size: undefined,\n  state: null,\n})\nconst props = useDefaults(_props, 'BFormFile')\nconst slots = defineSlots<BFormFileSlots>()\n\nconst emit = defineEmits<{\n  change: [value: Event]\n}>()\n\nconst modelValue = defineModel<Exclude<BFormFileProps['modelValue'], undefined>>({\n  default: null,\n})\n\nconst attrs = useAttrs()\n\nconst processedAttrs = computed(() => {\n  // In plain mode, pass all attributes to the input element\n  if (props.plain) {\n    return {\n      rootAttrs: {},\n      dropZoneAttrs: {},\n      inputAttrs: attrs,\n    }\n  }\n  // In custom mode, split attributes:\n  // - class/style go to root (for layout/positioning)\n  // - title goes to drop zone (for tooltip on interactive element)\n  // - everything else goes to hidden input (for form functionality)\n  const {class: rootClass, style: rootStyle, title: dropZoneTitle, ...inputAttrs} = attrs\n  const rootAttrs: Record<string, unknown> = {}\n  const dropZoneAttrs: Record<string, unknown> = {}\n  if (rootClass !== undefined) rootAttrs.class = rootClass\n  if (rootStyle !== undefined) rootAttrs.style = rootStyle\n  if (dropZoneTitle !== undefined) dropZoneAttrs.title = dropZoneTitle\n  return {\n    rootAttrs,\n    dropZoneAttrs,\n    inputAttrs,\n  }\n})\n\nconst computedId = useId(() => props.id)\nconst stateClass = useStateClass(() => props.state)\n\n// Refs\nconst rootRef = useTemplateRef('rootRef')\nconst dropZoneRef = useTemplateRef('dropZoneRef')\nconst browseButtonRef = useTemplateRef('browseButtonRef')\nconst plainInputRef = useTemplateRef<HTMLInputElement>('plainInputRef')\nconst customInputRef = useTemplateRef<HTMLInputElement>('customInputRef')\n\n// Computed accept for file type validation\nconst computedAccept = computed(() =>\n  typeof props.accept === 'string' ? props.accept : props.accept.join(',')\n)\n\n// VueUse file dialog (uses our hidden input element)\nconst {\n  open,\n  reset: resetDialog,\n  onChange: onDialogChange,\n} = useFileDialog({\n  accept: computedAccept.value,\n  multiple: props.multiple || props.directory,\n  directory: props.directory,\n  input: customInputRef as unknown as Ref<HTMLInputElement>,\n})\n\n// VueUse drop zone (replaces manual drag/drop)\n// Note: We don't pass dataTypes because the accept attribute handles validation\n// and there is no reliable way to get MIME types from in all browsers\n// https://github.com/vueuse/vueuse/issues/4523\nconst {isOverDropZone} = useDropZone(dropZoneRef, {\n  onDrop: (files) => {\n    if (files && !props.noDrop) {\n      handleFiles(files)\n    }\n  },\n  multiple: props.multiple || props.directory,\n})\n\n// Computed properties\nconst hasLabelSlot = computed(() => !isEmptySlot(slots.label))\nconst hasPlaceholderSlot = computed(() => !isEmptySlot(slots.placeholder))\n\nconst computedClasses = computed(() => [\n  stateClass.value,\n  {\n    [`form-control-${props.size}`]: props.size !== undefined,\n  },\n])\n\nconst computedPlainClasses = computed(() => [\n  'form-control',\n  stateClass.value,\n  {\n    [`form-control-${props.size}`]: props.size !== undefined,\n  },\n])\n\n// Selected files (from dialog or managed state)\nconst internalFiles = ref<readonly File[]>([])\n\nconst selectedFiles = computed<readonly File[]>(() => internalFiles.value)\n\nconst hasFiles = computed(() => selectedFiles.value.length > 0)\n\nconst fileNames = computed(() => selectedFiles.value.map((file) => file.name))\n\nconst formattedFileNames = computed(() => {\n  if (!hasFiles.value) return ''\n  if (props.fileNameFormatter) {\n    return props.fileNameFormatter(selectedFiles.value)\n  }\n  const names = fileNames.value\n  if (names.length === 1) return names[0]\n  return `${names.length} files selected`\n})\n\nconst showExternalDisplay = computed(\n  () => !props.plain && props.showFileNames && (hasFiles.value || props.placeholder)\n)\n\n// ARIA live region message for accessibility\nconst ariaLiveMessage = computed(() => {\n  if (!hasFiles.value) return ''\n  const count = selectedFiles.value.length\n  if (count === 1) {\n    return `File selected: ${selectedFiles.value[0]?.name}`\n  }\n  return `${count} files selected`\n})\n\nconst effectiveBrowseText = computed(() => props.browseText ?? 'Browse')\nconst effectiveDropPlaceholder = computed(() => props.dropPlaceholder ?? 'Drop files here...')\n\n// Validate file against accept criteria\nconst isFileAccepted = (file: File): boolean => {\n  if (!computedAccept.value) return true\n\n  const acceptTypes = computedAccept.value.split(',').map((type) => type.trim())\n\n  return acceptTypes.some((acceptType) => {\n    // Extension match (e.g., .pdf)\n    if (acceptType.startsWith('.')) {\n      return file.name.toLowerCase().endsWith(acceptType.toLowerCase())\n    }\n    // Exact MIME type match (e.g., image/png)\n    if (!acceptType.includes('*')) {\n      return file.type === acceptType\n    }\n    // Wildcard MIME type match (e.g., image/* or */*)\n    const slashIndex = acceptType.indexOf('/')\n    if (slashIndex === -1) {\n      // Malformed wildcard pattern (no '/'): do not match anything\n      return false\n    }\n    const category = acceptType.slice(0, slashIndex)\n    // */* should match any MIME type\n    if (category === '*') {\n      return true\n    }\n    return file.type.startsWith(`${category}/`)\n  })\n}\n\n// File handling\nconst handleFiles = (files: File[] | FileList, nativeEvent?: Event) => {\n  let fileArray: File[] = []\n\n  if (nativeEvent) {\n    // Plain mode: read from the event target (browser already filtered via accept)\n    const input = nativeEvent.target as HTMLInputElement\n    fileArray = input.files ? Array.from(input.files) : []\n  } else {\n    // Custom mode (drag & drop or file dialog): manually filter and set on hidden input\n    fileArray = Array.from(files).filter((file) => isFileAccepted(file))\n    if (customInputRef.value && typeof DataTransfer !== 'undefined') {\n      try {\n        const dataTransfer = new DataTransfer()\n        fileArray.forEach((file) => dataTransfer.items.add(file))\n        customInputRef.value.files = dataTransfer.files\n      } catch {\n        // In environments where DataTransfer is not fully supported, skip syncing files on the input\n      }\n    }\n  }\n\n  // Update internal state\n  internalFiles.value = fileArray\n\n  // Update model value\n  if (fileArray.length === 0) {\n    modelValue.value = null\n  } else if (props.directory || props.multiple) {\n    modelValue.value = fileArray\n  } else {\n    const [firstFile] = fileArray\n    if (firstFile) {\n      modelValue.value = firstFile\n    }\n  }\n\n  // Emit change event in nextTick to ensure DOM updates\n  // In plain mode: forward the native event (has target.files)\n  // In custom mode: create CustomEvent with files in detail\n  nextTick(() => {\n    if (nativeEvent) {\n      // Plain mode: forward native event\n      emit('change', nativeEvent)\n    } else {\n      // Custom mode: create CustomEvent with files\n      const changeEvent = new CustomEvent('change', {\n        bubbles: true,\n        cancelable: false,\n        detail: {\n          files: fileArray,\n          target: {files: fileArray},\n        },\n      })\n      // Also attach files directly for easier access\n      Object.defineProperty(changeEvent, 'files', {\n        value: fileArray,\n        enumerable: true,\n      })\n      emit('change', changeEvent)\n    }\n  })\n}\n\n// Open file dialog\nconst openFileDialog = () => {\n  if (!props.disabled) {\n    open({\n      accept: computedAccept.value,\n      multiple: props.multiple || props.directory,\n      directory: props.directory,\n    })\n  }\n}\n\n// Handle click on control wrapper (make entire control clickable like Bootstrap v5)\nconst handleControlClick = () => {\n  // Don't trigger if clicking the button itself (button has its own handler with .stop)\n  // Don't trigger if disabled\n  if (!props.disabled) {\n    openFileDialog()\n  }\n}\n\n// Plain mode change handler\nconst onPlainChange = (e: Event) => {\n  const input = e.target as HTMLInputElement\n  if (input.files) {\n    handleFiles(input.files, e) // Pass native event\n  }\n}\n\n// Watch dialog files from useFileDialog\nonDialogChange((files) => {\n  if (files) {\n    handleFiles(files)\n  }\n})\n\n// Reset method\nconst reset = () => {\n  internalFiles.value = []\n  modelValue.value = null\n  resetDialog() // This resets the hidden input in custom mode\n  if (plainInputRef.value) {\n    plainInputRef.value.value = ''\n  }\n}\n\n// Focus management\nconst focus = () => {\n  if (props.plain) {\n    plainInputRef.value?.focus()\n  } else {\n    browseButtonRef.value?.focus()\n  }\n}\n\nconst blur = () => {\n  if (props.plain) {\n    plainInputRef.value?.blur()\n  } else {\n    browseButtonRef.value?.blur()\n  }\n}\n\n// Autofocus support - initial focus on mount\nonMounted(() => {\n  if (props.autofocus) {\n    nextTick(() => {\n      focus()\n    })\n  }\n})\n\n// Autofocus support - runtime prop changes\nwatch(\n  () => props.autofocus,\n  (autofocus) => {\n    if (autofocus) {\n      focus()\n    }\n  }\n)\n\n// Watch modelValue changes from parent\nwatch(modelValue, (newValue) => {\n  if (newValue === null) {\n    internalFiles.value = []\n    if (plainInputRef.value) {\n      plainInputRef.value.value = ''\n    }\n  } else if (Array.isArray(newValue)) {\n    internalFiles.value = newValue as readonly File[]\n  } else {\n    internalFiles.value = [newValue] as readonly File[]\n  }\n})\n\ndefineExpose({\n  blur,\n  element: computed(() => (props.plain ? plainInputRef.value : browseButtonRef.value)),\n  focus,\n  reset,\n})\n</script>\n","<template>\n  <div ref=\"rootRef\" v-bind=\"processedAttrs.rootAttrs\" class=\"b-form-file-root\">\n    <!-- Optional label -->\n    <label\n      v-if=\"hasLabelSlot || props.label\"\n      class=\"form-label\"\n      :class=\"props.labelClass\"\n      :for=\"computedId\"\n    >\n      <slot name=\"label\">\n        {{ props.label }}\n      </slot>\n    </label>\n\n    <!-- Drop zone wrapper -->\n    <div\n      v-if=\"!props.plain\"\n      ref=\"dropZoneRef\"\n      v-bind=\"processedAttrs.dropZoneAttrs\"\n      class=\"b-form-file-wrapper\"\n      :class=\"{\n        'b-form-file-dragging': isOverDropZone && !props.noDrop,\n        'b-form-file-has-files': hasFiles,\n      }\"\n    >\n      <!-- Custom file control (mimics Bootstrap native input) -->\n      <div\n        class=\"b-form-file-control\"\n        :class=\"computedClasses\"\n        :aria-disabled=\"props.disabled\"\n        @click=\"handleControlClick\"\n      >\n        <!-- Custom browse button (now on LEFT to match Bootstrap v5) -->\n        <button\n          v-if=\"!props.noButton\"\n          :id=\"computedId\"\n          ref=\"browseButtonRef\"\n          type=\"button\"\n          class=\"b-form-file-button\"\n          :disabled=\"props.disabled\"\n          :aria-label=\"props.ariaLabel\"\n          :aria-labelledby=\"props.ariaLabelledby\"\n          @click.stop=\"openFileDialog\"\n        >\n          {{ effectiveBrowseText }}\n        </button>\n\n        <!-- File name display -->\n        <div class=\"b-form-file-text\">\n          <slot name=\"file-name\" :files=\"selectedFiles\" :names=\"fileNames\">\n            <span v-if=\"hasFiles\">{{ formattedFileNames }}</span>\n            <span v-else-if=\"hasPlaceholderSlot || props.placeholder\" class=\"text-muted\">\n              <slot name=\"placeholder\">{{ props.placeholder }}</slot>\n            </span>\n          </slot>\n        </div>\n      </div>\n\n      <!-- Drag overlay (only shown when dragging) -->\n      <div v-if=\"isOverDropZone && !props.noDrop\" class=\"b-form-file-drag-overlay\">\n        <slot name=\"drop-placeholder\">\n          <div class=\"b-form-file-drag-text\">\n            {{ effectiveDropPlaceholder }}\n          </div>\n        </slot>\n      </div>\n\n      <!-- Hidden input for form submission (positioned behind UI with z-index) -->\n      <input\n        ref=\"customInputRef\"\n        v-bind=\"processedAttrs.inputAttrs\"\n        type=\"file\"\n        :name=\"props.name\"\n        :form=\"props.form\"\n        :multiple=\"props.multiple || props.directory\"\n        :disabled=\"props.disabled\"\n        :required=\"props.required\"\n        :accept=\"computedAccept || undefined\"\n        :capture=\"props.capture\"\n        :directory=\"props.directory || undefined\"\n        :webkitdirectory=\"props.directory || undefined\"\n        tabindex=\"-1\"\n        aria-hidden=\"true\"\n        style=\"\n          position: absolute;\n          z-index: -5;\n          width: 0;\n          height: 0;\n          opacity: 0;\n          overflow: hidden;\n          pointer-events: none;\n        \"\n      />\n    </div>\n\n    <!-- Plain mode - simple native input -->\n    <input\n      v-else\n      :id=\"computedId\"\n      ref=\"plainInputRef\"\n      v-bind=\"processedAttrs.inputAttrs\"\n      type=\"file\"\n      :class=\"computedPlainClasses\"\n      :form=\"props.form\"\n      :name=\"props.name\"\n      :multiple=\"props.multiple || props.directory\"\n      :disabled=\"props.disabled\"\n      :capture=\"props.capture\"\n      :accept=\"computedAccept || undefined\"\n      :required=\"props.required || undefined\"\n      :aria-label=\"props.ariaLabel\"\n      :aria-labelledby=\"props.ariaLabelledby\"\n      :aria-required=\"props.required || undefined\"\n      :directory=\"props.directory || undefined\"\n      :webkitdirectory=\"props.directory || undefined\"\n      @change=\"onPlainChange\"\n    />\n\n    <!-- External file display (when showFileNames is true and not plain) -->\n    <div v-if=\"showExternalDisplay\" class=\"b-form-file-display mt-2\">\n      <slot name=\"file-name\" :files=\"selectedFiles\" :names=\"fileNames\">\n        <div v-if=\"hasFiles\" class=\"small text-muted\">\n          {{ formattedFileNames }}\n        </div>\n        <div v-else-if=\"hasPlaceholderSlot || props.placeholder\" class=\"small text-muted\">\n          <slot name=\"placeholder\">\n            {{ props.placeholder }}\n          </slot>\n        </div>\n      </slot>\n    </div>\n\n    <!-- ARIA live region for screen reader announcements -->\n    <div v-if=\"!props.plain\" class=\"visually-hidden\" aria-live=\"polite\" aria-atomic=\"true\">\n      {{ ariaLiveMessage }}\n    </div>\n  </div>\n</template>\n\n<script setup lang=\"ts\">\nimport {useDropZone, useFileDialog} from '@vueuse/core'\nimport {computed, nextTick, onMounted, ref, type Ref, useAttrs, useTemplateRef, watch} from 'vue'\nimport {useDefaults} from '../../composables/useDefaults'\nimport {useId} from '../../composables/useId'\nimport {useStateClass} from '../../composables/useStateClass'\nimport {isEmptySlot} from '../../utils/dom'\nimport type {BFormFileSlots, BFormFileProps} from '../../types'\n\ndefineOptions({\n  inheritAttrs: false,\n})\n\nconst _props = withDefaults(defineProps<Omit<BFormFileProps, 'modelValue'>>(), {\n  ariaLabel: undefined,\n  ariaLabelledby: undefined,\n  accept: '',\n  autofocus: false,\n  browseText: undefined,\n  capture: undefined,\n  directory: false,\n  disabled: false,\n  dropPlaceholder: undefined,\n  fileNameFormatter: undefined,\n  form: undefined,\n  id: undefined,\n  label: '',\n  labelClass: undefined,\n  multiple: false,\n  name: undefined,\n  noButton: false,\n  noDrop: false,\n  plain: false,\n  placeholder: 'No file chosen',\n  required: false,\n  showFileNames: false,\n  size: undefined,\n  state: null,\n})\nconst props = useDefaults(_props, 'BFormFile')\nconst slots = defineSlots<BFormFileSlots>()\n\nconst emit = defineEmits<{\n  change: [value: Event]\n}>()\n\nconst modelValue = defineModel<Exclude<BFormFileProps['modelValue'], undefined>>({\n  default: null,\n})\n\nconst attrs = useAttrs()\n\nconst processedAttrs = computed(() => {\n  // In plain mode, pass all attributes to the input element\n  if (props.plain) {\n    return {\n      rootAttrs: {},\n      dropZoneAttrs: {},\n      inputAttrs: attrs,\n    }\n  }\n  // In custom mode, split attributes:\n  // - class/style go to root (for layout/positioning)\n  // - title goes to drop zone (for tooltip on interactive element)\n  // - everything else goes to hidden input (for form functionality)\n  const {class: rootClass, style: rootStyle, title: dropZoneTitle, ...inputAttrs} = attrs\n  const rootAttrs: Record<string, unknown> = {}\n  const dropZoneAttrs: Record<string, unknown> = {}\n  if (rootClass !== undefined) rootAttrs.class = rootClass\n  if (rootStyle !== undefined) rootAttrs.style = rootStyle\n  if (dropZoneTitle !== undefined) dropZoneAttrs.title = dropZoneTitle\n  return {\n    rootAttrs,\n    dropZoneAttrs,\n    inputAttrs,\n  }\n})\n\nconst computedId = useId(() => props.id)\nconst stateClass = useStateClass(() => props.state)\n\n// Refs\nconst rootRef = useTemplateRef('rootRef')\nconst dropZoneRef = useTemplateRef('dropZoneRef')\nconst browseButtonRef = useTemplateRef('browseButtonRef')\nconst plainInputRef = useTemplateRef<HTMLInputElement>('plainInputRef')\nconst customInputRef = useTemplateRef<HTMLInputElement>('customInputRef')\n\n// Computed accept for file type validation\nconst computedAccept = computed(() =>\n  typeof props.accept === 'string' ? props.accept : props.accept.join(',')\n)\n\n// VueUse file dialog (uses our hidden input element)\nconst {\n  open,\n  reset: resetDialog,\n  onChange: onDialogChange,\n} = useFileDialog({\n  accept: computedAccept.value,\n  multiple: props.multiple || props.directory,\n  directory: props.directory,\n  input: customInputRef as unknown as Ref<HTMLInputElement>,\n})\n\n// VueUse drop zone (replaces manual drag/drop)\n// Note: We don't pass dataTypes because the accept attribute handles validation\n// and there is no reliable way to get MIME types from in all browsers\n// https://github.com/vueuse/vueuse/issues/4523\nconst {isOverDropZone} = useDropZone(dropZoneRef, {\n  onDrop: (files) => {\n    if (files && !props.noDrop) {\n      handleFiles(files)\n    }\n  },\n  multiple: props.multiple || props.directory,\n})\n\n// Computed properties\nconst hasLabelSlot = computed(() => !isEmptySlot(slots.label))\nconst hasPlaceholderSlot = computed(() => !isEmptySlot(slots.placeholder))\n\nconst computedClasses = computed(() => [\n  stateClass.value,\n  {\n    [`form-control-${props.size}`]: props.size !== undefined,\n  },\n])\n\nconst computedPlainClasses = computed(() => [\n  'form-control',\n  stateClass.value,\n  {\n    [`form-control-${props.size}`]: props.size !== undefined,\n  },\n])\n\n// Selected files (from dialog or managed state)\nconst internalFiles = ref<readonly File[]>([])\n\nconst selectedFiles = computed<readonly File[]>(() => internalFiles.value)\n\nconst hasFiles = computed(() => selectedFiles.value.length > 0)\n\nconst fileNames = computed(() => selectedFiles.value.map((file) => file.name))\n\nconst formattedFileNames = computed(() => {\n  if (!hasFiles.value) return ''\n  if (props.fileNameFormatter) {\n    return props.fileNameFormatter(selectedFiles.value)\n  }\n  const names = fileNames.value\n  if (names.length === 1) return names[0]\n  return `${names.length} files selected`\n})\n\nconst showExternalDisplay = computed(\n  () => !props.plain && props.showFileNames && (hasFiles.value || props.placeholder)\n)\n\n// ARIA live region message for accessibility\nconst ariaLiveMessage = computed(() => {\n  if (!hasFiles.value) return ''\n  const count = selectedFiles.value.length\n  if (count === 1) {\n    return `File selected: ${selectedFiles.value[0]?.name}`\n  }\n  return `${count} files selected`\n})\n\nconst effectiveBrowseText = computed(() => props.browseText ?? 'Browse')\nconst effectiveDropPlaceholder = computed(() => props.dropPlaceholder ?? 'Drop files here...')\n\n// Validate file against accept criteria\nconst isFileAccepted = (file: File): boolean => {\n  if (!computedAccept.value) return true\n\n  const acceptTypes = computedAccept.value.split(',').map((type) => type.trim())\n\n  return acceptTypes.some((acceptType) => {\n    // Extension match (e.g., .pdf)\n    if (acceptType.startsWith('.')) {\n      return file.name.toLowerCase().endsWith(acceptType.toLowerCase())\n    }\n    // Exact MIME type match (e.g., image/png)\n    if (!acceptType.includes('*')) {\n      return file.type === acceptType\n    }\n    // Wildcard MIME type match (e.g., image/* or */*)\n    const slashIndex = acceptType.indexOf('/')\n    if (slashIndex === -1) {\n      // Malformed wildcard pattern (no '/'): do not match anything\n      return false\n    }\n    const category = acceptType.slice(0, slashIndex)\n    // */* should match any MIME type\n    if (category === '*') {\n      return true\n    }\n    return file.type.startsWith(`${category}/`)\n  })\n}\n\n// File handling\nconst handleFiles = (files: File[] | FileList, nativeEvent?: Event) => {\n  let fileArray: File[] = []\n\n  if (nativeEvent) {\n    // Plain mode: read from the event target (browser already filtered via accept)\n    const input = nativeEvent.target as HTMLInputElement\n    fileArray = input.files ? Array.from(input.files) : []\n  } else {\n    // Custom mode (drag & drop or file dialog): manually filter and set on hidden input\n    fileArray = Array.from(files).filter((file) => isFileAccepted(file))\n    if (customInputRef.value && typeof DataTransfer !== 'undefined') {\n      try {\n        const dataTransfer = new DataTransfer()\n        fileArray.forEach((file) => dataTransfer.items.add(file))\n        customInputRef.value.files = dataTransfer.files\n      } catch {\n        // In environments where DataTransfer is not fully supported, skip syncing files on the input\n      }\n    }\n  }\n\n  // Update internal state\n  internalFiles.value = fileArray\n\n  // Update model value\n  if (fileArray.length === 0) {\n    modelValue.value = null\n  } else if (props.directory || props.multiple) {\n    modelValue.value = fileArray\n  } else {\n    const [firstFile] = fileArray\n    if (firstFile) {\n      modelValue.value = firstFile\n    }\n  }\n\n  // Emit change event in nextTick to ensure DOM updates\n  // In plain mode: forward the native event (has target.files)\n  // In custom mode: create CustomEvent with files in detail\n  nextTick(() => {\n    if (nativeEvent) {\n      // Plain mode: forward native event\n      emit('change', nativeEvent)\n    } else {\n      // Custom mode: create CustomEvent with files\n      const changeEvent = new CustomEvent('change', {\n        bubbles: true,\n        cancelable: false,\n        detail: {\n          files: fileArray,\n          target: {files: fileArray},\n        },\n      })\n      // Also attach files directly for easier access\n      Object.defineProperty(changeEvent, 'files', {\n        value: fileArray,\n        enumerable: true,\n      })\n      emit('change', changeEvent)\n    }\n  })\n}\n\n// Open file dialog\nconst openFileDialog = () => {\n  if (!props.disabled) {\n    open({\n      accept: computedAccept.value,\n      multiple: props.multiple || props.directory,\n      directory: props.directory,\n    })\n  }\n}\n\n// Handle click on control wrapper (make entire control clickable like Bootstrap v5)\nconst handleControlClick = () => {\n  // Don't trigger if clicking the button itself (button has its own handler with .stop)\n  // Don't trigger if disabled\n  if (!props.disabled) {\n    openFileDialog()\n  }\n}\n\n// Plain mode change handler\nconst onPlainChange = (e: Event) => {\n  const input = e.target as HTMLInputElement\n  if (input.files) {\n    handleFiles(input.files, e) // Pass native event\n  }\n}\n\n// Watch dialog files from useFileDialog\nonDialogChange((files) => {\n  if (files) {\n    handleFiles(files)\n  }\n})\n\n// Reset method\nconst reset = () => {\n  internalFiles.value = []\n  modelValue.value = null\n  resetDialog() // This resets the hidden input in custom mode\n  if (plainInputRef.value) {\n    plainInputRef.value.value = ''\n  }\n}\n\n// Focus management\nconst focus = () => {\n  if (props.plain) {\n    plainInputRef.value?.focus()\n  } else {\n    browseButtonRef.value?.focus()\n  }\n}\n\nconst blur = () => {\n  if (props.plain) {\n    plainInputRef.value?.blur()\n  } else {\n    browseButtonRef.value?.blur()\n  }\n}\n\n// Autofocus support - initial focus on mount\nonMounted(() => {\n  if (props.autofocus) {\n    nextTick(() => {\n      focus()\n    })\n  }\n})\n\n// Autofocus support - runtime prop changes\nwatch(\n  () => props.autofocus,\n  (autofocus) => {\n    if (autofocus) {\n      focus()\n    }\n  }\n)\n\n// Watch modelValue changes from parent\nwatch(modelValue, (newValue) => {\n  if (newValue === null) {\n    internalFiles.value = []\n    if (plainInputRef.value) {\n      plainInputRef.value.value = ''\n    }\n  } else if (Array.isArray(newValue)) {\n    internalFiles.value = newValue as readonly File[]\n  } else {\n    internalFiles.value = [newValue] as readonly File[]\n  }\n})\n\ndefineExpose({\n  blur,\n  element: computed(() => (props.plain ? plainInputRef.value : browseButtonRef.value)),\n  focus,\n  reset,\n})\n</script>\n"],"mappings":"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"}