diff --git a/docs/content/3.components/form.md b/docs/content/3.components/form.md index 0ee769b7fd..885a86f1c6 100644 --- a/docs/content/3.components/form.md +++ b/docs/content/3.components/form.md @@ -98,6 +98,7 @@ The Form component automatically triggers validation when an input emits an `inp - Validation on `input` occurs **as you type**. - Validation on `change` occurs when you **commit to a value**. - Validation on `blur` happens when an input **loses focus**. +- Validation on `error-input` happens when as you type on an input with an error. You can control when validation happens this using the `validate-on` prop. diff --git a/playground/app/pages/components/form.vue b/playground/app/pages/components/form.vue index 9641ce79d0..3f399175a0 100644 --- a/playground/app/pages/components/form.vue +++ b/playground/app/pages/components/form.vue @@ -57,7 +57,7 @@ const disabled = ref(false)
{ name?: P message: string diff --git a/test/components/Checkbox.spec.ts b/test/components/Checkbox.spec.ts index 4ac957b80c..99d11cc46e 100644 --- a/test/components/Checkbox.spec.ts +++ b/test/components/Checkbox.spec.ts @@ -4,7 +4,7 @@ import ComponentRender from '../component-render' import theme from '#build/ui/checkbox' import { renderForm } from '../utils/form' import { mount, flushPromises } from '@vue/test-utils' -import type { FormInputEvents } from '~/src/module' +import type { FormValidateOn } from '~/src/module' describe('Checkbox', () => { const sizes = Object.keys(theme.variants.size) as any @@ -58,7 +58,7 @@ describe('Checkbox', () => { }) describe('form integration', async () => { - async function createForm(validateOn?: FormInputEvents[]) { + async function createForm(validateOn?: FormValidateOn[]) { const wrapper = await renderForm({ props: { validateOn, diff --git a/test/components/CheckboxGroup.spec.ts b/test/components/CheckboxGroup.spec.ts index 01cac48f06..dabc125b76 100644 --- a/test/components/CheckboxGroup.spec.ts +++ b/test/components/CheckboxGroup.spec.ts @@ -5,7 +5,7 @@ import theme from '#build/ui/checkbox-group' import themeCheckbox from '#build/ui/checkbox' import { flushPromises, mount } from '@vue/test-utils' import { renderForm } from '../utils/form' -import type { FormInputEvents } from '~/src/module' +import type { FormValidateOn } from '~/src/module' describe('CheckboxGroup', () => { const sizes = Object.keys(theme.variants.size) as any @@ -65,7 +65,7 @@ describe('CheckboxGroup', () => { }) describe('form integration', async () => { - async function createForm(validateOn?: FormInputEvents[]) { + async function createForm(validateOn?: FormValidateOn[]) { const wrapper = await renderForm({ props: { validateOn, diff --git a/test/components/Input.spec.ts b/test/components/Input.spec.ts index f655cdd56b..e07d5f46af 100644 --- a/test/components/Input.spec.ts +++ b/test/components/Input.spec.ts @@ -4,8 +4,8 @@ import Input, { type InputProps, type InputSlots } from '../../src/runtime/compo import ComponentRender from '../component-render' import theme from '#build/ui/input' +import type { FormValidateOn } from '~/src/module' import { renderForm } from '../utils/form' -import type { FormInputEvents } from '~/src/module' describe('Input', () => { const sizes = Object.keys(theme.variants.size) as any @@ -104,7 +104,7 @@ describe('Input', () => { }) describe('form integration', async () => { - async function createForm(validateOn?: FormInputEvents[], eagerValidation?: boolean) { + async function createForm(validateOn?: FormValidateOn[], eagerValidation?: boolean) { const wrapper = await renderForm({ props: { validateOn, @@ -160,6 +160,18 @@ describe('Input', () => { expect(wrapper.text()).not.toContain('Error message') }) + test('validate on error-input works', async () => { + const { input, wrapper } = await createForm(['error-input', 'blur'], true) + await input.setValue('value') + expect(wrapper.text()).not.toContain('Error message') + + await input.trigger('blur') + 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']) diff --git a/test/components/InputMenu.spec.ts b/test/components/InputMenu.spec.ts index dd2f1d5c7c..c1bf223a64 100644 --- a/test/components/InputMenu.spec.ts +++ b/test/components/InputMenu.spec.ts @@ -4,7 +4,7 @@ import ComponentRender from '../component-render' import theme from '#build/ui/input' import { renderForm } from '../utils/form' import { flushPromises, mount } from '@vue/test-utils' -import type { FormInputEvents } from '~/src/module' +import type { FormValidateOn } from '~/src/module' import { expectEmitPayloadType } from '../utils/types' describe('InputMenu', () => { @@ -110,7 +110,7 @@ describe('InputMenu', () => { }) describe('form integration', async () => { - async function createForm(validateOn?: FormInputEvents[]) { + async function createForm(validateOn?: FormValidateOn[]) { const wrapper = await renderForm({ props: { validateOn, diff --git a/test/components/InputNumber.spec.ts b/test/components/InputNumber.spec.ts index 9f2d6754a2..b98258481c 100644 --- a/test/components/InputNumber.spec.ts +++ b/test/components/InputNumber.spec.ts @@ -5,7 +5,7 @@ import { reactive } from 'vue' import InputNumber, { type InputNumberProps, type InputNumberSlots } from '../../src/runtime/components/InputNumber.vue' import ComponentRender from '../component-render' import theme from '#build/ui/input-number' -import type { FormInputEvents } from '~/src/module' +import type { FormValidateOn } from '~/src/module' import { renderForm } from '../utils/form' describe('InputNumber', () => { @@ -61,7 +61,7 @@ describe('InputNumber', () => { }) describe('form integration', async () => { - async function createForm(validateOn?: FormInputEvents[]) { + async function createForm(validateOn?: FormValidateOn[]) { const wrapper = await renderForm({ state: reactive({ value: 0 }), props: { diff --git a/test/components/PinInput.spec.ts b/test/components/PinInput.spec.ts index 771bbb8ce9..7799f89fe0 100644 --- a/test/components/PinInput.spec.ts +++ b/test/components/PinInput.spec.ts @@ -5,7 +5,7 @@ import ComponentRender from '../component-render' import theme from '#build/ui/pin-input' import { renderForm } from '../utils/form' -import type { FormInputEvents } from '~/src/module' +import type { FormValidateOn } from '~/src/module' describe('PinInput', () => { const sizes = Object.keys(theme.variants.size) as any @@ -65,7 +65,7 @@ describe('PinInput', () => { }) describe('form integration', async () => { - async function createForm(validateOn?: FormInputEvents[]) { + async function createForm(validateOn?: FormValidateOn[]) { const wrapper = await renderForm({ props: { validateOn, diff --git a/test/components/RadioGroup.spec.ts b/test/components/RadioGroup.spec.ts index d0be84a9d0..fbe6876f62 100644 --- a/test/components/RadioGroup.spec.ts +++ b/test/components/RadioGroup.spec.ts @@ -4,7 +4,7 @@ import ComponentRender from '../component-render' import theme from '#build/ui/radio-group' import { flushPromises, mount } from '@vue/test-utils' import { renderForm } from '../utils/form' -import type { FormInputEvents } from '~/src/module' +import type { FormValidateOn } from '~/src/module' describe('RadioGroup', () => { const sizes = Object.keys(theme.variants.size) as any @@ -67,7 +67,7 @@ describe('RadioGroup', () => { }) describe('form integration', async () => { - async function createForm(validateOn?: FormInputEvents[]) { + async function createForm(validateOn?: FormValidateOn[]) { const wrapper = await renderForm({ props: { validateOn, diff --git a/test/components/Select.spec.ts b/test/components/Select.spec.ts index 9231cd6e1b..12b0a06279 100644 --- a/test/components/Select.spec.ts +++ b/test/components/Select.spec.ts @@ -4,7 +4,7 @@ import Select, { type SelectProps, type SelectSlots } from '../../src/runtime/co import ComponentRender from '../component-render' import theme from '#build/ui/input' import { renderForm } from '../utils/form' -import type { FormInputEvents } from '~/src/module' +import type { FormValidateOn } from '~/src/module' import { expectEmitPayloadType } from '../utils/types' describe('Select', () => { @@ -107,7 +107,7 @@ describe('Select', () => { }) describe('form integration', async () => { - async function createForm(validateOn?: FormInputEvents[]) { + async function createForm(validateOn?: FormValidateOn[]) { const wrapper = await renderForm({ props: { validateOn, diff --git a/test/components/SelectMenu.spec.ts b/test/components/SelectMenu.spec.ts index e843735ef7..4a039819f3 100644 --- a/test/components/SelectMenu.spec.ts +++ b/test/components/SelectMenu.spec.ts @@ -4,7 +4,7 @@ import ComponentRender from '../component-render' import theme from '#build/ui/input' import { renderForm } from '../utils/form' import { flushPromises, mount } from '@vue/test-utils' -import type { FormInputEvents } from '~/src/module' +import type { FormValidateOn } from '~/src/module' import { expectEmitPayloadType } from '../utils/types' describe('SelectMenu', () => { @@ -113,7 +113,7 @@ describe('SelectMenu', () => { }) describe('form integration', async () => { - async function createForm(validateOn?: FormInputEvents[]) { + async function createForm(validateOn?: FormValidateOn[]) { const wrapper = await renderForm({ props: { validateOn, diff --git a/test/components/Slider.spec.ts b/test/components/Slider.spec.ts index 435edfe808..80a7d31636 100644 --- a/test/components/Slider.spec.ts +++ b/test/components/Slider.spec.ts @@ -4,7 +4,7 @@ import ComponentRender from '../component-render' import theme from '#build/ui/slider' import { flushPromises, mount } from '@vue/test-utils' import { renderForm } from '../utils/form' -import type { FormInputEvents } from '~/src/module' +import type { FormValidateOn } from '~/src/module' describe('Slider', () => { const sizes = Object.keys(theme.variants.size) as any @@ -52,7 +52,7 @@ describe('Slider', () => { }) describe('form integration', async () => { - async function createForm(validateOn?: FormInputEvents[]) { + async function createForm(validateOn?: FormValidateOn[]) { const wrapper = await renderForm({ props: { validateOn, diff --git a/test/components/Switch.spec.ts b/test/components/Switch.spec.ts index 59cb75a419..0cb240cb5d 100644 --- a/test/components/Switch.spec.ts +++ b/test/components/Switch.spec.ts @@ -4,7 +4,7 @@ import ComponentRender from '../component-render' import theme from '#build/ui/switch' import { flushPromises, mount } from '@vue/test-utils' import { renderForm } from '../utils/form' -import type { FormInputEvents } from '~/src/module' +import type { FormValidateOn } from '~/src/module' describe('Switch', () => { const sizes = Object.keys(theme.variants.size) as any @@ -55,7 +55,7 @@ describe('Switch', () => { }) describe('form integration', async () => { - async function createForm(validateOn?: FormInputEvents[]) { + async function createForm(validateOn?: FormValidateOn[]) { const wrapper = await renderForm({ props: { validateOn, diff --git a/test/components/Textarea.spec.ts b/test/components/Textarea.spec.ts index 90280b2103..58dcffca54 100644 --- a/test/components/Textarea.spec.ts +++ b/test/components/Textarea.spec.ts @@ -4,7 +4,7 @@ import Textarea, { type TextareaProps, type TextareaSlots } from '../../src/runt import ComponentRender from '../component-render' import theme from '#build/ui/textarea' import { renderForm } from '../utils/form' -import type { FormInputEvents } from '~/src/module' +import type { FormValidateOn } from '~/src/module' describe('Textarea', () => { const sizes = Object.keys(theme.variants.size) as any @@ -107,7 +107,7 @@ describe('Textarea', () => { }) describe('form integration', async () => { - async function createForm(validateOn?: FormInputEvents[], eagerValidation?: boolean) { + async function createForm(validateOn?: FormValidateOn[], eagerValidation?: boolean) { const wrapper = await renderForm({ props: { validateOn,