refactor: use defineModel

This commit is contained in:
axolotle 2024-08-22 00:45:07 +02:00
parent 2ba27d6c33
commit d2cf9522b1
13 changed files with 43 additions and 57 deletions

View file

@ -19,7 +19,6 @@ import { isDisplayComponent, isWritableComponent } from '@/types/form'
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
id?: string id?: string
modelValue?: MV
fields?: FFD fields?: FFD
validations?: FormValidation<MV> validations?: FormValidation<MV>
submitText?: string submitText?: string
@ -31,7 +30,6 @@ const props = withDefaults(
}>(), }>(),
{ {
id: 'ynh-form', id: 'ynh-form',
modelValue: undefined,
fields: undefined, fields: undefined,
validations: undefined, validations: undefined,
submitText: undefined, submitText: undefined,
@ -71,6 +69,8 @@ const slots = defineSlots<
} }
>() >()
const modelValue = defineModel<MV>()
const { t } = useI18n() const { t } = useI18n()
const globalErrorFeedback = computed(() => { const globalErrorFeedback = computed(() => {
@ -94,7 +94,7 @@ const sections = computed(() => {
function onModelUpdate(key: keyof MV, value: MV[keyof MV]) { function onModelUpdate(key: keyof MV, value: MV[keyof MV]) {
emit('update:modelValue', { emit('update:modelValue', {
...props.modelValue!, ...modelValue.value!,
[key]: value, [key]: value,
}) })
} }
@ -119,7 +119,7 @@ const Fields = createReusableTemplate<{
<FormField <FormField
v-if="!field.readonly" v-if="!field.readonly"
v-bind="field" v-bind="field"
:model-value="props.modelValue![k]" :model-value="modelValue![k]"
:validation="props.validations?.form[k]" :validation="props.validations?.form[k]"
@update:model-value="onModelUpdate(k, $event)" @update:model-value="onModelUpdate(k, $event)"
> >
@ -130,7 +130,7 @@ const Fields = createReusableTemplate<{
<FormFieldReadonly <FormFieldReadonly
v-else v-else
v-bind="field" v-bind="field"
:model-value="props.modelValue![k]" :model-value="modelValue![k]"
/> />
</slot> </slot>
<slot <slot

View file

@ -36,7 +36,6 @@ const props = withDefaults(defineProps<FormFieldProps<C, MV>>(), {
prepend: undefined, prepend: undefined,
rules: undefined, rules: undefined,
modelValue: undefined,
validation: undefined, validation: undefined,
}) })
@ -51,7 +50,7 @@ const slots = defineSlots<{
description?: any description?: any
}>() }>()
const model = defineModel<MV>() const modelValue = defineModel<MV>()
const attrs = useAttrs() const attrs = useAttrs()
const { t } = useI18n() const { t } = useI18n()
@ -137,7 +136,6 @@ const [DefineTemplate, ReuseTemplate] = createReusableTemplate<{
v-bind="{ v-bind="{
...(props.cProps ?? ({} as ItemComponentToItemProps[C])), ...(props.cProps ?? ({} as ItemComponentToItemProps[C])),
ariaDescribedby, ariaDescribedby,
modelValue: props.modelValue,
state, state,
validation: validation, validation: validation,
}" }"
@ -146,7 +144,7 @@ const [DefineTemplate, ReuseTemplate] = createReusableTemplate<{
<Component <Component
v-bind="props.cProps" v-bind="props.cProps"
:is="component" :is="component"
v-model="model" v-model="modelValue"
:aria-describedby="ariaDescribedby" :aria-describedby="ariaDescribedby"
:state="state" :state="state"
:validation="validation" :validation="validation"

View file

@ -44,13 +44,12 @@ const props = withDefaults(
defaultValue: undefined, defaultValue: undefined,
addBtnText: undefined, addBtnText: undefined,
modelValue: undefined,
validation: undefined, validation: undefined,
}, },
) )
const emit = defineEmits<{ const emit = defineEmits<{
'update:modelValue': [value: MV] 'update:modelValue': [modelValue: MV]
}>() }>()
const slots = defineSlots<{ const slots = defineSlots<{
@ -62,6 +61,8 @@ const slots = defineSlots<{
description?: () => any description?: () => any
}>() }>()
const modelValue = defineModel<MV>()
const { t } = useI18n() const { t } = useI18n()
const attrs = useAttrs() const attrs = useAttrs()
@ -104,7 +105,7 @@ const error = computed(() => {
const subProps = computed<FormFieldProps<C, ArrInnerType<MV>>[]>(() => { const subProps = computed<FormFieldProps<C, ArrInnerType<MV>>[]>(() => {
return ( return (
props.modelValue?.map((modelValue: ArrInnerType<MV>, i) => { modelValue.value?.map((modelValue: ArrInnerType<MV>, i) => {
return { return {
cProps: { cProps: {
...(props.cProps ?? ({} as ItemComponentToItemProps[C])), ...(props.cProps ?? ({} as ItemComponentToItemProps[C])),
@ -143,22 +144,22 @@ const errorMessage = computed(() => {
}) })
function addElement() { function addElement() {
const value = [...(props?.modelValue || []), props.defaultValue!()] as MV const value = [...(modelValue.value || []), props.defaultValue!()] as MV
emit('update:modelValue', value) emit('update:modelValue', value)
// FIXME: Focus newly inserted form item // FIXME: Focus newly inserted form item
} }
function removeElement(index: number) { function removeElement(index: number) {
if (!props.modelValue) return if (!modelValue.value) return
const value = [...props.modelValue] as MV const value = [...modelValue.value] as MV
value.splice(index, 1) value.splice(index, 1)
emit('update:modelValue', value) emit('update:modelValue', value)
} }
function updateElement(index: number, newValue: ArrInnerType<MV>) { function updateElement(index: number, newValue: ArrInnerType<MV>) {
if (!props.modelValue) return if (!modelValue.value) return
const value = [...props.modelValue] as MV const value = [...modelValue.value] as MV
value.splice(index, 1, newValue) value.splice(index, 1, newValue)
emit('update:modelValue', value) emit('update:modelValue', value)
} }

View file

@ -19,10 +19,11 @@ defineOptions({
const props = withDefaults(defineProps<FormFieldReadonlyProps<C, MV>>(), { const props = withDefaults(defineProps<FormFieldReadonlyProps<C, MV>>(), {
id: undefined, id: undefined,
modelValue: undefined,
cols: () => ({ md: 4, lg: 3 }), cols: () => ({ md: 4, lg: 3 }),
}) })
const modelValue = defineModel<MV>()
const { t } = useI18n() const { t } = useI18n()
const cols = computed<Cols>(() => ({ const cols = computed<Cols>(() => ({
@ -32,7 +33,7 @@ const cols = computed<Cols>(() => ({
})) }))
const text = computed(() => { const text = computed(() => {
return parseValue(props.modelValue) return parseValue(modelValue.value)
}) })
function parseValue(value: any) { function parseValue(value: any) {

View file

@ -9,11 +9,9 @@ const props = withDefaults(
defineProps<{ defineProps<{
items?: T[] | null items?: T[] | null
itemsName: string | null itemsName: string | null
modelValue?: string
}>(), }>(),
{ {
items: undefined, items: undefined,
modelValue: undefined,
}, },
) )

View file

@ -14,7 +14,6 @@ withDefaults(
touchKey: undefined, touchKey: undefined,
type: 'email', type: 'email',
modelValue: undefined,
state: undefined, state: undefined,
validation: undefined, validation: undefined,
ariaDescribedby: undefined, ariaDescribedby: undefined,

View file

@ -12,23 +12,18 @@ withDefaults(
labels: () => ({ true: 'yes', false: 'no' }), labels: () => ({ true: 'yes', false: 'no' }),
ariaDescribedby: undefined, ariaDescribedby: undefined,
modelValue: undefined,
state: undefined, state: undefined,
validation: undefined, validation: undefined,
}, },
) )
defineEmits<{ const modelValue = defineModel<boolean>()
'update:modelValue': [value: boolean]
}>()
const model = defineModel<boolean>()
</script> </script>
<template> <template>
<BFormCheckbox <BFormCheckbox
:id="id" :id="id"
v-model="model" v-model="modelValue"
:name="name" :name="name"
:aria-describedby="ariaDescribedby" :aria-describedby="ariaDescribedby"
:state="state" :state="state"

View file

@ -21,7 +21,6 @@ const props = withDefaults(
dropPlaceholder: undefined, dropPlaceholder: undefined,
ariaDescribedby: undefined, ariaDescribedby: undefined,
modelValue: () => ({ file: null }),
state: undefined, state: undefined,
validation: undefined, validation: undefined,
}, },
@ -31,13 +30,17 @@ const emit = defineEmits<{
'update:modelValue': [value: FileModelValue] 'update:modelValue': [value: FileModelValue]
}>() }>()
const modelValue = defineModel<FileModelValue>({
default: () => ({ file: null }),
})
const touch = inject(ValidationTouchSymbol) 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 modelValue.value.file === null
? props.placeholder ? props.placeholder
: props.modelValue.file.name : modelValue.value.file.name
}) })
function onInput(file: File | File[] | null) { function onInput(file: File | File[] | null) {

View file

@ -20,18 +20,12 @@ const props = withDefaults(
type: 'text', type: 'text',
ariaDescribedby: undefined, ariaDescribedby: undefined,
modelValue: undefined,
state: undefined, state: undefined,
validation: undefined, validation: undefined,
}, },
) )
defineEmits<{
'update:modelValue': [value: string | number | null]
}>()
const touch = inject(ValidationTouchSymbol) const modelValue = defineModel<string | number | null>({
const model = defineModel<string | number | null>({
set(value) { set(value) {
if (props.type === 'number' && typeof value === 'string') { if (props.type === 'number' && typeof value === 'string') {
if (value === '') return '' if (value === '') return ''
@ -41,6 +35,8 @@ const model = defineModel<string | number | null>({
}, },
}) })
const touch = inject(ValidationTouchSymbol)
const autocomplete = computed(() => { const autocomplete = computed(() => {
const typeToAutocomplete = { const typeToAutocomplete = {
password: 'new-password', password: 'new-password',
@ -64,7 +60,7 @@ const fromValidation = computed(() => {
<BFormInput <BFormInput
:id="id" :id="id"
v-bind="fromValidation" v-bind="fromValidation"
v-model="model" v-model="modelValue"
:name="name" :name="name"
:placeholder="placeholder" :placeholder="placeholder"
:autocomplete="autocomplete" :autocomplete="autocomplete"

View file

@ -15,7 +15,6 @@ const props = withDefaults(
// options: undefined, // options: undefined,
ariaDescribedby: undefined, ariaDescribedby: undefined,
modelValue: undefined,
state: undefined, state: undefined,
validation: undefined, validation: undefined,
}, },
@ -23,7 +22,7 @@ const props = withDefaults(
const touch = inject(ValidationTouchSymbol) const touch = inject(ValidationTouchSymbol)
const model = defineModel<string[]>() const modelValue = defineModel<string[]>()
const required = computed(() => 'required' in (props?.validation ?? {})) const required = computed(() => 'required' in (props?.validation ?? {}))
@ -34,7 +33,7 @@ const required = computed(() => 'required' in (props?.validation ?? {}))
<template> <template>
<BFormTags <BFormTags
:id="id" :id="id"
v-model="model" v-model="modelValue"
:name="name" :name="name"
:placeholder="placeholder" :placeholder="placeholder"
:limit="limit" :limit="limit"

View file

@ -30,18 +30,17 @@ const props = withDefaults(
tagIcon: undefined, tagIcon: undefined,
ariaDescribedby: undefined, ariaDescribedby: undefined,
modelValue: undefined,
state: undefined, state: undefined,
validation: undefined, validation: undefined,
}, },
) )
const emit = defineEmits<{ const emit = defineEmits<{
'update:modelValue': [value: string[]]
'tag-update': [value: TagUpdateArgs] 'tag-update': [value: TagUpdateArgs]
}>() }>()
const model = defineModel<string[]>() const modelValue = defineModel<string[]>()
const searchElem = ref<InstanceType<typeof BDropdown> | null>(null) const searchElem = ref<InstanceType<typeof BDropdown> | null>(null)
const dropdownElem = ref<InstanceType<typeof BFormInput> | null>(null) const dropdownElem = ref<InstanceType<typeof BFormInput> | null>(null)
@ -55,7 +54,7 @@ const availableOptions = computed(() => {
return props.options.filter((opt) => { return props.options.filter((opt) => {
const tag = typeof opt === 'string' ? opt : opt.value const tag = typeof opt === 'string' ? opt : opt.value
let filterIn = let filterIn =
model.value?.indexOf(tag) === -1 && modelValue.value?.indexOf(tag) === -1 &&
!(props.disabledItems?.includes(tag) ?? false) !(props.disabledItems?.includes(tag) ?? false)
if (filterIn && criteria.value) { if (filterIn && criteria.value) {
filterIn = tag.toLowerCase().indexOf(criteria.value) > -1 filterIn = tag.toLowerCase().indexOf(criteria.value) > -1
@ -120,7 +119,7 @@ function onDropdownKeydown(e: KeyboardEvent) {
<BFormTags <BFormTags
v-bind="$attrs" v-bind="$attrs"
:id="id" :id="id"
v-model="model" v-model="modelValue"
:name="name" :name="name"
:aria-describedby="ariaDescribedby" :aria-describedby="ariaDescribedby"
:state="state" :state="state"

View file

@ -24,7 +24,7 @@ defineEmits<{
'update:modelValue': [value: string | null] 'update:modelValue': [value: string | null]
}>() }>()
const model = defineModel<string>() const modelValue = defineModel<string>()
const touch = inject(ValidationTouchSymbol) const touch = inject(ValidationTouchSymbol)
@ -34,7 +34,7 @@ const required = computed(() => 'required' in (props?.validation ?? {}))
<template> <template>
<BFormTextarea <BFormTextarea
:id="id" :id="id"
v-model="model" v-model="modelValue"
:name="name" :name="name"
:placeholder="placeholder" :placeholder="placeholder"
:aria-describedby="ariaDescribedby" :aria-describedby="ariaDescribedby"

View file

@ -55,7 +55,6 @@ type BaseWritableItemProps = {
export type BaseItemComputedProps<MV extends any = any> = { export type BaseItemComputedProps<MV extends any = any> = {
ariaDescribedby?: string | string[] ariaDescribedby?: string | string[]
modelValue?: MV
state?: StateValidation state?: StateValidation
validation?: BaseValidation validation?: BaseValidation
} }
@ -238,8 +237,7 @@ type FormFieldRules<MV extends any> = MV extends object
: ValidationArgs<MV | Partial<MV>> : ValidationArgs<MV | Partial<MV>>
: ValidationRuleCollection<MV> : ValidationRuleCollection<MV>
type BaseFormFieldComputedProps<MV extends any = any> = { type BaseFormFieldComputedProps = {
modelValue?: MV
validation?: BaseValidation validation?: BaseValidation
} }
@ -295,14 +293,13 @@ export type FormFieldProps<
C extends AnyWritableComponents, C extends AnyWritableComponents,
MV extends any, MV extends any,
> = Omit<FormField<C, MV>, 'hr' | 'visible' | 'readonly'> & > = Omit<FormField<C, MV>, 'hr' | 'visible' | 'readonly'> &
BaseFormFieldComputedProps<MV> BaseFormFieldComputedProps
// BaseFormFieldComputedProps<MV>
export type FormFieldReadonlyProps< export type FormFieldReadonlyProps<
C extends AnyWritableComponents, C extends AnyWritableComponents,
MV extends any, MV extends any,
> = Omit<FormFieldReadonly<C>, 'hr' | 'visible' | 'readonly' | 'rules'> & { > = Omit<FormFieldReadonly<C>, 'hr' | 'visible' | 'readonly' | 'rules'>
modelValue?: MV
}
export type FormFieldDict<T extends Obj = Obj> = { export type FormFieldDict<T extends Obj = Obj> = {
[k in keyof T | string]: k extends keyof T [k in keyof T | string]: k extends keyof T