This commit is contained in:
Benjamin Canac
2025-07-18 15:11:22 +02:00
parent bfa6460613
commit 8dca270965

View File

@@ -2,7 +2,6 @@
import type { AppConfig } from '@nuxt/schema' import type { AppConfig } from '@nuxt/schema'
import type { UseFileDialogReturn } from '@vueuse/core' import type { UseFileDialogReturn } from '@vueuse/core'
import theme from '#build/ui/file-upload' import theme from '#build/ui/file-upload'
import type { UseComponentIconsProps } from '../composables/useComponentIcons'
import type { ButtonProps } from '../types' import type { ButtonProps } from '../types'
import type { ComponentConfig } from '../types/utils' import type { ComponentConfig } from '../types/utils'
@@ -58,16 +57,12 @@ export interface FileUploadEmits<M extends boolean = false> {
} }
export interface FileUploadSlots { export interface FileUploadSlots {
default(props: { default(props: { open: UseFileDialogReturn['open'], reset: UseFileDialogReturn['reset'] }): any
open: UseFileDialogReturn['open']
reset: UseFileDialogReturn['reset']
previewUrls: string[]
}): any
leading(props?: {}): any leading(props?: {}): any
label(props?: {}): any label(props?: {}): any
description(props?: {}): any description(props?: {}): any
actions(props?: {}): any actions(props?: {}): any
preview(props?: {}): any files(props: { files: FileList }): any
} }
</script> </script>
@@ -96,7 +91,7 @@ const appConfig = useAppConfig() as FileUpload['AppConfig']
const inputRef = ref<HTMLInputElement>() const inputRef = ref<HTMLInputElement>()
const dropZoneRef = ref<HTMLDivElement>() const dropZoneRef = ref<HTMLDivElement>()
const { files, open, reset, onCancel, onChange } = useFileDialog({ const { files, open, reset, onChange } = useFileDialog({
multiple: props.multiple, multiple: props.multiple,
accept: props.accept, accept: props.accept,
reset: props.reset, reset: props.reset,
@@ -105,10 +100,10 @@ const { files, open, reset, onCancel, onChange } = useFileDialog({
}) })
const { isOverDropZone } = useDropZone(dropZoneRef, { const { isOverDropZone } = useDropZone(dropZoneRef, {
onDrop, onDrop,
dataTypes: props.accept.split(','), // dataTypes: props.accept.split(','),
multiple: props.multiple multiple: props.multiple
}) })
const { emitFormInput, emitFormChange, id, name, disabled, ariaAttrs } = useFormField<FileUploadProps>(props, { deferInputValidation: true }) const { emitFormInput, id, name, disabled, ariaAttrs } = useFormField<FileUploadProps>(props, { deferInputValidation: true })
const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.fileUpload || {}) })({ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.fileUpload || {}) })({
dropzone: props.dropzone, dropzone: props.dropzone,
@@ -116,24 +111,24 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.fileUpload |
size: props.size size: props.size
})) }))
const previewUrls = computed(() => Array.from(files.value || []).map(file => URL.createObjectURL(file)))
onChange((files) => { onChange((files) => {
modelValue.value = (props.multiple ? files : files?.[0]) as (M extends true ? File[] : File) | null modelValue.value = (props.multiple ? files : files?.[0]) as (M extends true ? File[] : File) | null
})
onCancel(() => { emitFormInput()
/** do something on cancel */
}) })
function onDrop(files: File[] | null) { function onDrop(files: File[] | null) {
modelValue.value = (props.multiple ? files : files?.[0]) as (M extends true ? File[] : File) | null modelValue.value = (props.multiple ? files : files?.[0]) as (M extends true ? File[] : File) | null
} }
defineExpose({
inputRef
})
</script> </script>
<template> <template>
<Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })"> <Primitive :as="as" :class="ui.root({ class: [props.ui?.root, props.class] })">
<slot :open="open" :reset="reset" :preview-urls="previewUrls"> <slot :open="open" :reset="reset">
<div <div
ref="dropZoneRef" ref="dropZoneRef"
role="button" role="button"
@@ -166,6 +161,12 @@ function onDrop(files: File[] | null) {
</div> </div>
</div> </div>
</div> </div>
<div v-if="files && files.length > 0" :class="ui.files({ class: props.ui?.files })">
<slot name="files" :files="files">
{{ files }}
</slot>
</div>
</slot> </slot>
<input <input