refactor: FileItem typing

This commit is contained in:
axolotle 2024-07-05 17:14:43 +02:00
parent 5cd0ed23a5
commit 15b512fa1e
3 changed files with 50 additions and 45 deletions

View file

@ -2,46 +2,39 @@
import type { BFormFile } from 'bootstrap-vue-next' import type { BFormFile } from 'bootstrap-vue-next'
import { computed, inject, ref } from 'vue' import { computed, inject, ref } from 'vue'
import { ValidationTouchSymbol } from '@/composables/form'
import { getFileContent } from '@/helpers/commons' import { getFileContent } from '@/helpers/commons'
import type {
type CustomFile = { BaseItemComputedProps,
file: File | null FileItemProps,
content?: string | null FileModelValue,
current?: boolean } from '@/types/form'
removed?: boolean
}
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<FileItemProps & BaseItemComputedProps<FileModelValue>>(),
id?: string
modelValue?: CustomFile
placeholder?: string
dropPlaceholder?: string
accept?: string
state?: string
required?: boolean
name?: string
}>(),
{ {
id: undefined, id: undefined,
modelValue: () => ({ file: null }),
placeholder: 'Choose a file or drop it here...',
dropPlaceholder: undefined,
accept: '',
state: undefined,
required: false,
name: undefined, name: undefined,
placeholder: 'Choose a file or drop it here...',
touchKey: undefined,
accept: '',
dropPlaceholder: undefined,
ariaDescribedby: undefined,
modelValue: () => ({ file: null }),
state: undefined,
validation: undefined,
}, },
) )
const emit = defineEmits<{ const emit = defineEmits<{
'update:modelValue': [value: CustomFile] 'update:modelValue': [value: FileModelValue]
}>() }>()
const touch = inject('touch') const touch = inject(ValidationTouchSymbol)
const inputElem = ref<InstanceType<typeof BFormFile> | null>(null) const inputElem = ref<InstanceType<typeof BFormFile> | null>(null)
const _placeholder = computed(() => { const placeholder = computed(() => {
return props.modelValue.file === null return props.modelValue.file === null
? props.placeholder ? props.placeholder
: props.modelValue.file.name : props.modelValue.file.name
@ -72,34 +65,34 @@ function clearFiles() {
removed: true, removed: true,
}) })
} }
const required = computed(() => 'required' in (props.validation ?? {}))
</script> </script>
<template> <template>
<BInputGroup class="w-100"> <BInputGroup class="w-100">
<template #append> <template v-if="!required && modelValue.file !== null" #append>
<BButton <BButton variant="danger" @click="clearFiles">
v-if="!required && modelValue.file !== null"
@click="clearFiles"
variant="danger"
>
<span class="visually-hidden">{{ $t('delete') }}</span> <span class="visually-hidden">{{ $t('delete') }}</span>
<YIcon iname="trash" /> <YIcon iname="trash" />
</BButton> </BButton>
</template> </template>
<BFormFile <BFormFile
:modelValue="modelValue.file"
ref="inputElem"
:id="id" :id="id"
:required="required" ref="inputElem"
:placeholder="_placeholder" :name="name"
:placeholder="placeholder"
:accept="accept" :accept="accept"
:drop-placeholder="dropPlaceholder" :drop-placeholder="dropPlaceholder"
:aria-describedby="ariaDescribedby"
:model-value="modelValue.file"
:state="state" :state="state"
:browse-text="$t('words.browse')" :browse-text="$t('words.browse')"
@update:modelValue="onInput" :required="required"
@blur="touch(name)" @blur="touch?.(touchKey)"
@focusout="touch(name)" @focusout="touch?.(touchKey)"
@update:model-value="onInput"
/> />
</BInputGroup> </BInputGroup>
</template> </template>

View file

@ -117,16 +117,17 @@ export function randint(min, max) {
/** /**
* Returns a File content. * Returns a File content.
* *
* @param {File} file * @param file -
* @param {Object} [extraParams] - Optionnal params * @param base64 - returns a base64 representation of the file.
* @param {Boolean} [extraParams.base64] - returns a base64 representation of the file.
* @return {Promise<String>}
*/ */
export function getFileContent(file, { base64 = false } = {}) { export function getFileContent(
file: File,
{ base64 = false } = {},
): Promise<string> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const reader = new FileReader() const reader = new FileReader()
reader.onerror = reject reader.onerror = reject
reader.onload = () => resolve(reader.result) reader.onload = () => resolve(reader.result as string)
if (base64) { if (base64) {
reader.readAsDataURL(file) reader.readAsDataURL(file)

View file

@ -33,3 +33,14 @@ export type CheckboxItemProps = BaseWritableItemProps & {
// FIXME unused? // FIXME unused?
// choices: string[] // choices: string[]
} }
export type FileItemProps = BaseWritableItemProps & {
accept?: string | string[]
dropPlaceholder?: string
}
export type FileModelValue = {
file: File | null
content?: string | null
current?: boolean
removed?: boolean
}