refactor: InputItem typing

This commit is contained in:
axolotle 2024-07-05 17:17:12 +02:00
parent 15b512fa1e
commit 9a48aa1a45
3 changed files with 82 additions and 39 deletions

View file

@ -1,63 +1,70 @@
<script setup lang="ts">
import { inject } from 'vue'
import type { BaseValidation } from '@vuelidate/core'
import { computed, inject } from 'vue'
import { ValidationTouchSymbol } from '@/composables/form'
import type { BaseItemComputedProps, InputItemProps } from '@/types/form'
import { objectGet } from '@/helpers/commons'
const props = withDefaults(
defineProps<{
modelValue?: string | number | null
id?: string
placeholder?: string
type?: string
required?: boolean
state?: false | null
min?: number
max?: number
step?: number
trim?: boolean
autocomplete?: string
// FIXME pattern?
pattern?: object
name?: string
}>(),
defineProps<InputItemProps & BaseItemComputedProps<string | number | null>>(),
{
modelValue: null,
id: undefined,
name: undefined,
placeholder: undefined,
type: 'text',
required: false,
state: undefined,
min: undefined,
max: undefined,
touchKey: undefined,
autocomplete: undefined,
// pattern: undefined,
step: undefined,
trim: true,
autocomplete: undefined,
pattern: undefined,
name: undefined,
type: 'text',
ariaDescribedby: undefined,
modelValue: undefined,
state: undefined,
validation: undefined,
},
)
const emit = defineEmits<{
defineEmits<{
'update:modelValue': [value: string | number | null]
}>()
const touch = inject('touch')
const touch = inject(ValidationTouchSymbol)
const autocomplete =
props.autocomplete || props.type === 'password' ? 'new-password' : null
const model = defineModel<string | number | null>()
const autocomplete = computed(() => {
const typeToAutocomplete = {
password: 'new-password',
email: 'email',
url: 'url',
} as const
return props.autocomplete || objectGet(typeToAutocomplete, props.type)
})
const fromValidation = computed(() => {
const validation = props?.validation ?? ({} as BaseValidation)
return {
required: 'required' in validation,
min: 'min' in validation ? validation.min.$params.min : undefined,
max: 'max' in validation ? validation.max.$params.max : undefined,
}
})
</script>
<template>
<BFormInput
:modelValue="modelValue"
@update:modelValue="emit('update:modelValue', $event)"
:id="id"
v-bind="fromValidation"
v-model="model"
:name="name"
:placeholder="placeholder"
:type="type"
:state="state"
:required="required"
:min="min"
:max="max"
:autocomplete="autocomplete"
:step="step"
:trim="trim"
:autocomplete="autocomplete"
@blur="touch(name)"
:type="type"
:aria-describedby="ariaDescribedby"
:state="state"
@blur="touch?.(touchKey)"
/>
</template>

View file

@ -29,6 +29,14 @@ export function isObjectLiteral(value) {
)
}
export function objectGet<
T extends Obj,
K extends keyof T | string,
F extends any = undefined,
>(obj: T, key: K, fallback?: F) {
return (key in obj ? obj[key] : fallback) as K extends keyof T ? T[K] : F
}
/**
* Check if value is "empty" (`null`, `undefined`, `''`, `[]`, '{}').
* Note: `0` is not considered "empty" in that helper.

View file

@ -44,3 +44,31 @@ export type FileModelValue = {
current?: boolean
removed?: boolean
}
export type InputItemProps = BaseWritableItemProps & {
autocomplete?:
| 'off'
| 'on'
| 'name'
| 'email'
| 'username'
| 'new-password'
| 'current-password'
| 'url'
// pattern?: object
// choices?: string[] FIXME rm ?
step?: number
trim?: boolean
type?:
| 'color'
| 'date'
// | 'datetime-local'
| 'email'
| 'number'
| 'password'
| 'range'
// | 'search'
| 'text'
| 'time'
| 'url'
}