mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-31 12:17:54 +01:00
fix(FormField): restore eager-validation prop behavior (#3031)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
committed by
Benjamin Canac
parent
00b3c86584
commit
41dc11ceef
@@ -74,7 +74,7 @@ const slots = defineSlots<InputSlots>()
|
|||||||
|
|
||||||
const [modelValue, modelModifiers] = defineModel<string | number>()
|
const [modelValue, modelModifiers] = defineModel<string | number>()
|
||||||
|
|
||||||
const { emitFormBlur, emitFormInput, emitFormChange, size: formGroupSize, color, id, name, highlight, disabled } = useFormField<InputProps>(props)
|
const { emitFormBlur, emitFormInput, emitFormChange, size: formGroupSize, color, id, name, highlight, disabled } = useFormField<InputProps>(props, { deferInputValidation: true })
|
||||||
const { orientation, size: buttonGroupSize } = useButtonGroup<InputProps>(props)
|
const { orientation, size: buttonGroupSize } = useButtonGroup<InputProps>(props)
|
||||||
const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(props)
|
const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(props)
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ const emits = defineEmits<TextareaEmits>()
|
|||||||
|
|
||||||
const [modelValue, modelModifiers] = defineModel<string | number>()
|
const [modelValue, modelModifiers] = defineModel<string | number>()
|
||||||
|
|
||||||
const { emitFormBlur, emitFormInput, emitFormChange, size, color, id, name, highlight, disabled } = useFormField<TextareaProps>(props)
|
const { emitFormBlur, emitFormInput, emitFormChange, size, color, id, name, highlight, disabled } = useFormField<TextareaProps>(props, { deferInputValidation: true })
|
||||||
|
|
||||||
const ui = computed(() => textarea({
|
const ui = computed(() => textarea({
|
||||||
color: color.value,
|
color: color.value,
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ type Props<T> = {
|
|||||||
name?: string
|
name?: string
|
||||||
size?: GetObjectField<T, 'size'>
|
size?: GetObjectField<T, 'size'>
|
||||||
color?: GetObjectField<T, 'color'>
|
color?: GetObjectField<T, 'color'>
|
||||||
eagerValidation?: boolean
|
|
||||||
legend?: string
|
legend?: string
|
||||||
highlight?: boolean
|
highlight?: boolean
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
@@ -22,7 +21,7 @@ export const inputIdInjectionKey: InjectionKey<Ref<string | undefined>> = Symbol
|
|||||||
export const formInputsInjectionKey: InjectionKey<Ref<Record<string, { id?: string, pattern?: RegExp }>>> = Symbol('nuxt-ui.form-inputs')
|
export const formInputsInjectionKey: InjectionKey<Ref<Record<string, { id?: string, pattern?: RegExp }>>> = Symbol('nuxt-ui.form-inputs')
|
||||||
export const formLoadingInjectionKey: InjectionKey<Readonly<Ref<boolean>>> = Symbol('nuxt-ui.form-loading')
|
export const formLoadingInjectionKey: InjectionKey<Readonly<Ref<boolean>>> = Symbol('nuxt-ui.form-loading')
|
||||||
|
|
||||||
export function useFormField<T>(props?: Props<T>, opts?: { bind?: boolean }) {
|
export function useFormField<T>(props?: Props<T>, opts?: { bind?: boolean, deferInputValidation?: boolean }) {
|
||||||
const formOptions = inject(formOptionsInjectionKey, undefined)
|
const formOptions = inject(formOptionsInjectionKey, undefined)
|
||||||
const formBus = inject(formBusInjectionKey, undefined)
|
const formBus = inject(formBusInjectionKey, undefined)
|
||||||
const formField = inject(formFieldInjectionKey, undefined)
|
const formField = inject(formFieldInjectionKey, undefined)
|
||||||
@@ -42,7 +41,7 @@ export function useFormField<T>(props?: Props<T>, opts?: { bind?: boolean }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const blurred = ref(false)
|
const touched = ref(false)
|
||||||
|
|
||||||
function emitFormEvent(type: FormInputEvents, name?: string) {
|
function emitFormEvent(type: FormInputEvents, name?: string) {
|
||||||
if (formBus && formField && name) {
|
if (formBus && formField && name) {
|
||||||
@@ -51,17 +50,20 @@ export function useFormField<T>(props?: Props<T>, opts?: { bind?: boolean }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function emitFormBlur() {
|
function emitFormBlur() {
|
||||||
|
touched.value = true
|
||||||
emitFormEvent('blur', formField?.value.name)
|
emitFormEvent('blur', formField?.value.name)
|
||||||
blurred.value = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitFormChange() {
|
function emitFormChange() {
|
||||||
|
touched.value = true
|
||||||
emitFormEvent('change', formField?.value.name)
|
emitFormEvent('change', formField?.value.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
const emitFormInput = useDebounceFn(
|
const emitFormInput = useDebounceFn(
|
||||||
() => {
|
() => {
|
||||||
emitFormEvent('input', formField?.value.name)
|
if (!opts?.deferInputValidation || touched.value || formField?.value.eagerValidation) {
|
||||||
|
emitFormEvent('input', formField?.value.name)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
formField?.value.validateOnInputDelay ?? formOptions?.value.validateOnInputDelay ?? 0
|
formField?.value.validateOnInputDelay ?? formOptions?.value.validateOnInputDelay ?? 0
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ describe('Input', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('form integration', async () => {
|
describe('form integration', async () => {
|
||||||
async function createForm(validateOn?: FormInputEvents[]) {
|
async function createForm(validateOn?: FormInputEvents[], eagerValidation?: boolean) {
|
||||||
const wrapper = await renderForm({
|
const wrapper = await renderForm({
|
||||||
props: {
|
props: {
|
||||||
validateOn,
|
validateOn,
|
||||||
@@ -114,10 +114,13 @@ describe('Input', () => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
slotTemplate: `
|
slotTemplate: `
|
||||||
<UFormField name="value">
|
<UFormField name="value" :eager-validation="eagerValidation">
|
||||||
<UInput id="input" v-model="state.value" />
|
<UInput id="input" v-model="state.value" />
|
||||||
</UFormField>
|
</UFormField>
|
||||||
`
|
`,
|
||||||
|
slotVars: {
|
||||||
|
eagerValidation
|
||||||
|
}
|
||||||
})
|
})
|
||||||
const input = wrapper.find('#input')
|
const input = wrapper.find('#input')
|
||||||
return {
|
return {
|
||||||
@@ -147,7 +150,22 @@ describe('Input', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('validate on input works', async () => {
|
test('validate on input works', async () => {
|
||||||
|
const { input, wrapper } = await createForm(['input'], true)
|
||||||
|
await input.setValue('value')
|
||||||
|
expect(wrapper.text()).toContain('Error message')
|
||||||
|
|
||||||
|
await input.setValue('valid')
|
||||||
|
expect(wrapper.text()).not.toContain('Error message')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('validate on input without eager validation works', async () => {
|
||||||
const { input, wrapper } = await createForm(['input'])
|
const { input, wrapper } = await createForm(['input'])
|
||||||
|
|
||||||
|
await input.setValue('value')
|
||||||
|
expect(wrapper.text()).not.toContain('Error message')
|
||||||
|
|
||||||
|
await input.trigger('blur')
|
||||||
|
|
||||||
await input.setValue('value')
|
await input.setValue('value')
|
||||||
expect(wrapper.text()).toContain('Error message')
|
expect(wrapper.text()).toContain('Error message')
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ describe('Textarea', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('form integration', async () => {
|
describe('form integration', async () => {
|
||||||
async function createForm(validateOn?: FormInputEvents[]) {
|
async function createForm(validateOn?: FormInputEvents[], eagerValidation?: boolean) {
|
||||||
const wrapper = await renderForm({
|
const wrapper = await renderForm({
|
||||||
props: {
|
props: {
|
||||||
validateOn,
|
validateOn,
|
||||||
@@ -101,10 +101,13 @@ describe('Textarea', () => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
slotTemplate: `
|
slotTemplate: `
|
||||||
<UFormField name="value">
|
<UFormField name="value" :eager-validation="eagerValidation">
|
||||||
<UTextarea id="input" v-model="state.value" />
|
<UTextarea id="input" v-model="state.value" />
|
||||||
</UFormField>
|
</UFormField>
|
||||||
`
|
`,
|
||||||
|
slotVars: {
|
||||||
|
eagerValidation
|
||||||
|
}
|
||||||
})
|
})
|
||||||
const input = wrapper.find('#input')
|
const input = wrapper.find('#input')
|
||||||
return {
|
return {
|
||||||
@@ -134,7 +137,22 @@ describe('Textarea', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('validate on input works', async () => {
|
test('validate on input works', async () => {
|
||||||
|
const { input, wrapper } = await createForm(['input'], true)
|
||||||
|
await input.setValue('value')
|
||||||
|
expect(wrapper.text()).toContain('Error message')
|
||||||
|
|
||||||
|
await input.setValue('valid')
|
||||||
|
expect(wrapper.text()).not.toContain('Error message')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('validate on input without eager validation works', async () => {
|
||||||
const { input, wrapper } = await createForm(['input'])
|
const { input, wrapper } = await createForm(['input'])
|
||||||
|
|
||||||
|
await input.setValue('value')
|
||||||
|
expect(wrapper.text()).not.toContain('Error message')
|
||||||
|
|
||||||
|
await input.trigger('blur')
|
||||||
|
|
||||||
await input.setValue('value')
|
await input.setValue('value')
|
||||||
expect(wrapper.text()).toContain('Error message')
|
expect(wrapper.text()).toContain('Error message')
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user