@vuehookform/core 0.4.3 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/types.d.ts DELETED
@@ -1,893 +0,0 @@
1
- import { ComponentPublicInstance, ComputedRef, MaybeRef, Ref } from 'vue';
2
- import { ZodType, z } from 'zod';
3
- /**
4
- * Validation mode determines when validation occurs
5
- */
6
- export type ValidationMode = 'onSubmit' | 'onBlur' | 'onChange' | 'onTouched';
7
- /**
8
- * Extract the inferred type from a Zod schema
9
- */
10
- export type InferSchema<TSchema extends ZodType> = z.infer<TSchema>;
11
- /**
12
- * Alias for InferSchema - extracts form value type from schema.
13
- * Use this when you need the actual form data type.
14
- *
15
- * @example
16
- * const schema = z.object({ email: z.string(), age: z.number() })
17
- * type MyFormValues = FormValues<typeof schema>
18
- * // Result: { email: string; age: number }
19
- */
20
- export type FormValues<TSchema extends ZodType> = InferSchema<TSchema>;
21
- /**
22
- * Extract the element type from an array type.
23
- * Returns `never` if T is not an array.
24
- *
25
- * @example
26
- * type Item = ArrayElement<string[]> // string
27
- * type Never = ArrayElement<string> // never
28
- */
29
- export type ArrayElement<T> = T extends Array<infer U> ? U : never;
30
- /**
31
- * Generate all possible dot-notation paths for a nested object type.
32
- * Provides IDE autocomplete for valid field names.
33
- *
34
- * @example
35
- * type Form = { user: { name: string; age: number }; tags: string[] }
36
- * type FormPaths = Path<Form>
37
- * // Result: 'user' | 'user.name' | 'user.age' | 'tags'
38
- *
39
- * @example Using with register
40
- * register('user.name') // ✅ Valid - autocomplete suggests this
41
- * register('user.invalid') // ❌ TypeScript error
42
- */
43
- export type Path<T> = T extends object ? {
44
- [K in keyof T & (string | number)]: K extends string | number ? `${K}` | `${K}.${Path<T[K]>}` : never;
45
- }[keyof T & (string | number)] : never;
46
- /**
47
- * Type alias for valid field paths in a form.
48
- * Provides autocomplete for all dot-notation paths.
49
- *
50
- * @example
51
- * type MyPaths = FormPath<typeof schema>
52
- * // Use with functions that accept field paths
53
- */
54
- export type FormPath<TSchema extends ZodType> = Path<FormValues<TSchema>>;
55
- /**
56
- * Get array field paths (fields that are arrays).
57
- * Useful for the fields() method which only works with array fields.
58
- *
59
- * @example
60
- * type Form = { name: string; addresses: Address[] }
61
- * type ArrayFields = ArrayPath<Form> // 'addresses'
62
- */
63
- export type ArrayPath<T> = {
64
- [K in Path<T>]: PathValue<T, K> extends Array<unknown> ? K : never;
65
- }[Path<T>];
66
- /**
67
- * Get non-array field paths (primitive fields and nested objects, excluding arrays).
68
- * Useful for methods like register() that work with individual fields.
69
- *
70
- * @example
71
- * type Form = { name: string; addresses: Address[] }
72
- * type Fields = FieldPath<Form> // 'name' (excludes 'addresses')
73
- */
74
- export type FieldPath<T> = {
75
- [K in Path<T>]: PathValue<T, K> extends Array<unknown> ? never : K;
76
- }[Path<T>];
77
- /**
78
- * Extract the value type at a given dot-notation path.
79
- * Used internally to ensure setValue/getValues have correct types.
80
- * Supports numeric string indices for array access (e.g., 'items.0.name').
81
- *
82
- * @example
83
- * type Form = { user: { name: string }; items: { id: number }[] }
84
- * type NameType = PathValue<Form, 'user.name'> // string
85
- * type ItemType = PathValue<Form, 'items.0'> // { id: number }
86
- * type ItemId = PathValue<Form, 'items.0.id'> // number
87
- */
88
- export type PathValue<T, P extends string> = T extends unknown ? P extends `${infer K}.${infer Rest}` ? K extends keyof T ? PathValue<T[K], Rest> : T extends Array<infer U> ? K extends `${number}` ? PathValue<U, Rest> : never : never : P extends keyof T ? T[P] : T extends Array<infer U> ? P extends `${number}` ? U : never : never : never;
89
- /**
90
- * Single field error with type and message.
91
- * When criteriaMode is 'all', the `types` property contains all validation errors.
92
- */
93
- export interface FieldError {
94
- /** Error type identifier (e.g., 'required', 'too_small', 'invalid_string', 'custom') */
95
- type: string;
96
- /** Primary error message to display */
97
- message: string;
98
- /**
99
- * Additional error types when multiple validations fail.
100
- * Only populated when `criteriaMode: 'all'` is set in useForm options.
101
- *
102
- * @example Password with multiple requirements
103
- * ```ts
104
- * // Schema:
105
- * const schema = z.object({
106
- * password: z.string()
107
- * .min(8, 'At least 8 characters')
108
- * .regex(/[A-Z]/, 'Needs uppercase letter')
109
- * .regex(/[0-9]/, 'Needs a number')
110
- * })
111
- *
112
- * // With criteriaMode: 'all', error.types might be:
113
- * // {
114
- * // too_small: 'At least 8 characters',
115
- * // invalid_string: ['Needs uppercase letter', 'Needs a number']
116
- * // }
117
- *
118
- * // Template usage:
119
- * // <ul v-if="isFieldError(error) && error.types">
120
- * // <li v-for="(messages, type) in error.types" :key="type">
121
- * // {{ Array.isArray(messages) ? messages.join(', ') : messages }}
122
- * // </li>
123
- * // </ul>
124
- * ```
125
- */
126
- types?: Record<string, string | string[]>;
127
- }
128
- /**
129
- * Field error value - supports both simple strings and structured errors.
130
- *
131
- * - When `criteriaMode: 'firstError'` (default): Errors are typically strings
132
- * - When `criteriaMode: 'all'`: Errors are FieldError objects with `types` populated
133
- *
134
- * Use the `isFieldError()` type guard to safely handle both cases:
135
- * @example
136
- * const error = formState.value.errors.email
137
- * if (isFieldError(error)) {
138
- * // Structured error with type, message, and optional types
139
- * console.log(error.type, error.message)
140
- * } else if (typeof error === 'string') {
141
- * // Simple string error
142
- * console.log(error)
143
- * }
144
- */
145
- export type FieldErrorValue = string | FieldError;
146
- /**
147
- * Field error structure matching the form data structure
148
- */
149
- export type FieldErrors<T> = {
150
- [K in keyof T]?: T[K] extends Array<infer U> ? Array<FieldErrors<U>> | FieldErrorValue : T[K] extends object ? FieldErrors<T[K]> | FieldErrorValue : FieldErrorValue;
151
- } & {
152
- /** Root-level form errors */
153
- root?: FieldError;
154
- };
155
- /**
156
- * Form state tracking
157
- */
158
- export interface FormState<T> {
159
- /** Field validation errors */
160
- errors: FieldErrors<T>;
161
- /** Whether form has been modified from default values */
162
- isDirty: boolean;
163
- /** Whether form is currently valid (no errors) */
164
- isValid: boolean;
165
- /** Whether form is currently submitting */
166
- isSubmitting: boolean;
167
- /** Whether async default values are loading */
168
- isLoading: boolean;
169
- /** Whether form is ready (initialization complete, not loading) */
170
- isReady: boolean;
171
- /** Whether any field is currently being validated */
172
- isValidating: boolean;
173
- /** Set of field paths currently being validated */
174
- validatingFields: Set<string>;
175
- /** Record of touched field paths */
176
- touchedFields: Record<string, boolean>;
177
- /** Record of dirty field paths */
178
- dirtyFields: Record<string, boolean>;
179
- /** Number of times form has been submitted */
180
- submitCount: number;
181
- /** Error that occurred while loading async default values */
182
- defaultValuesError: unknown;
183
- /** Whether form has been submitted at least once */
184
- isSubmitted: boolean;
185
- /** Whether the last submission was successful */
186
- isSubmitSuccessful: boolean;
187
- /** Whether the form is disabled */
188
- disabled: boolean;
189
- }
190
- /**
191
- * State of an individual field
192
- */
193
- export interface FieldState {
194
- /** Whether field value differs from default */
195
- isDirty: boolean;
196
- /** Whether field has been blurred */
197
- isTouched: boolean;
198
- /** Whether field has a validation error */
199
- invalid: boolean;
200
- /** The error (string for backward compatibility, or FieldError for structured errors) */
201
- error?: FieldErrorValue;
202
- }
203
- /**
204
- * Error option for setError()
205
- */
206
- export interface ErrorOption {
207
- /** Error type identifier */
208
- type?: string;
209
- /** Error message to display */
210
- message: string;
211
- /**
212
- * If true, the error will not be cleared by subsequent validations.
213
- * Useful for server-side validation errors that should persist until explicitly cleared.
214
- */
215
- persistent?: boolean;
216
- }
217
- /**
218
- * Options for setFocus()
219
- */
220
- export interface SetFocusOptions {
221
- /** Whether to select the text in the input */
222
- shouldSelect?: boolean;
223
- }
224
- /**
225
- * Options for setValue()
226
- */
227
- export interface SetValueOptions {
228
- /** Trigger validation after setting value (default: false) */
229
- shouldValidate?: boolean;
230
- /** Mark field as dirty (default: true) */
231
- shouldDirty?: boolean;
232
- /** Mark field as touched (default: false) */
233
- shouldTouch?: boolean;
234
- }
235
- /**
236
- * Options for resetField()
237
- * @template TValue - The type of the field value (inferred from field path)
238
- */
239
- export interface ResetFieldOptions<TValue = unknown> {
240
- /** Keep validation errors after reset */
241
- keepError?: boolean;
242
- /** Keep dirty state after reset */
243
- keepDirty?: boolean;
244
- /** Keep touched state after reset */
245
- keepTouched?: boolean;
246
- /** New default value (updates stored default) - typed to match field */
247
- defaultValue?: TValue;
248
- }
249
- /**
250
- * Options for trigger()
251
- */
252
- export interface TriggerOptions {
253
- /**
254
- * If true, increments submitCount to activate reValidateMode behavior.
255
- * Useful when you want manual validation to trigger reValidation on subsequent changes.
256
- */
257
- markAsSubmitted?: boolean;
258
- }
259
- /**
260
- * Options for unregister()
261
- */
262
- export interface UnregisterOptions {
263
- /** Keep the field value in form data */
264
- keepValue?: boolean;
265
- /** Keep validation errors */
266
- keepError?: boolean;
267
- /** Keep dirty state */
268
- keepDirty?: boolean;
269
- /** Keep touched state */
270
- keepTouched?: boolean;
271
- /** Keep the default value */
272
- keepDefaultValue?: boolean;
273
- /** Don't re-evaluate isValid */
274
- keepIsValid?: boolean;
275
- }
276
- /**
277
- * Options for reset()
278
- */
279
- export interface ResetOptions {
280
- /** Keep validation errors after reset */
281
- keepErrors?: boolean;
282
- /** Keep dirty state after reset */
283
- keepDirty?: boolean;
284
- /** Keep touched state after reset */
285
- keepTouched?: boolean;
286
- /** Keep submit count after reset */
287
- keepSubmitCount?: boolean;
288
- /** Keep current default values (don't update with new values) */
289
- keepDefaultValues?: boolean;
290
- /** Keep isSubmitting state after reset */
291
- keepIsSubmitting?: boolean;
292
- /** Keep isSubmitSuccessful state after reset */
293
- keepIsSubmitSuccessful?: boolean;
294
- }
295
- /**
296
- * Options for setErrors() bulk operation
297
- */
298
- export interface SetErrorsOptions {
299
- /** Replace all existing errors instead of merging (default: false) */
300
- shouldReplace?: boolean;
301
- }
302
- /**
303
- * Options for registering a field
304
- * @template TValue - The type of the field value (inferred from field path)
305
- */
306
- export interface RegisterOptions<TValue = unknown> {
307
- /** Use controlled mode (v-model) instead of uncontrolled (ref) */
308
- controlled?: boolean;
309
- /** Disable validation for this field */
310
- disabled?: boolean;
311
- /**
312
- * Custom validation function - receives the typed field value.
313
- * Return an error message string to indicate validation failure,
314
- * or undefined to indicate success.
315
- *
316
- * @example
317
- * register('email', {
318
- * validate: (value) => {
319
- * // value is typed as string (inferred from schema)
320
- * if (!value.includes('@')) return 'Must be a valid email'
321
- * }
322
- * })
323
- */
324
- validate?: (value: TValue) => string | undefined | Promise<string | undefined>;
325
- /** Debounce time in ms for async validation (default: 0 = no debounce) */
326
- validateDebounce?: number;
327
- /** Remove field data when unmounted (overrides global shouldUnregister option) */
328
- shouldUnregister?: boolean;
329
- /** Dependent fields to re-validate when this field changes */
330
- deps?: string[];
331
- }
332
- /**
333
- * Return value from register() for binding to inputs.
334
- * Use object spread to bind all properties to your input element.
335
- *
336
- * @template TValue - The type of the field value (inferred from field path)
337
- *
338
- * @example
339
- * // Uncontrolled (default) - uses ref for DOM access
340
- * <input v-bind="register('email')" />
341
- *
342
- * @example
343
- * // Controlled - uses v-model via value ref
344
- * const { value, ...rest } = register('email', { controlled: true })
345
- * <input v-model="value" v-bind="rest" />
346
- */
347
- export interface RegisterReturn<TValue = unknown> {
348
- /** Field name for form data */
349
- name: string;
350
- /**
351
- * Ref callback for uncontrolled inputs.
352
- * Compatible with Vue's template ref system (v-bind spreads this onto elements).
353
- * Internally handles HTMLInputElement, HTMLSelectElement, and HTMLTextAreaElement.
354
- */
355
- ref: (el: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | Element | ComponentPublicInstance | null, refs?: Record<string, unknown>) => void;
356
- /** Input handler (fires on every keystroke) */
357
- onInput: (e: Event) => void;
358
- /** Blur handler */
359
- onBlur: () => void;
360
- /** Current value (for controlled mode) - only present when controlled: true */
361
- value?: Ref<TValue>;
362
- /** Disabled state from form-level disabled option */
363
- disabled?: boolean;
364
- }
365
- /**
366
- * Field metadata for dynamic arrays
367
- */
368
- export interface FieldArrayItem {
369
- /** Stable key for v-for */
370
- key: string;
371
- /** Current index in array */
372
- index: number;
373
- /** Remove this item */
374
- remove: () => void;
375
- }
376
- /**
377
- * Focus options for field array operations
378
- */
379
- export interface FieldArrayFocusOptions {
380
- /** Whether to focus after operation (default: true for append/prepend/insert) */
381
- shouldFocus?: boolean;
382
- /** Which item index to focus relative to added items (default: 0 = first added) */
383
- focusIndex?: number;
384
- /** Field name within the item to focus (e.g., 'name' for items.X.name) */
385
- focusName?: string;
386
- }
387
- /**
388
- * Rules for validating field arrays
389
- */
390
- export interface FieldArrayRules<T = unknown> {
391
- /** Minimum number of items required */
392
- minLength?: {
393
- value: number;
394
- message: string;
395
- };
396
- /** Maximum number of items allowed */
397
- maxLength?: {
398
- value: number;
399
- message: string;
400
- };
401
- /** Custom validation function - return error message or true if valid */
402
- validate?: (items: T[]) => string | true | Promise<string | true>;
403
- }
404
- /**
405
- * Options for configuring field arrays
406
- */
407
- export interface FieldArrayOptions<T = unknown> {
408
- /** Validation rules for the array itself */
409
- rules?: FieldArrayRules<T>;
410
- }
411
- /**
412
- * API for managing dynamic field arrays.
413
- * All methods that accept values are typed to match the array item type.
414
- *
415
- * Most operations return a boolean indicating success or failure.
416
- * Operations fail (return false) when:
417
- * - maxLength rule would be exceeded (append, prepend, insert)
418
- * - minLength rule would be violated (remove, removeAll, removeMany)
419
- * - Index is out of bounds (remove, update, swap, move)
420
- *
421
- * **Reactivity:** The `value` property is fully reactive - it automatically
422
- * updates when array methods (append, remove, swap, etc.) are called.
423
- * Your template will re-render when items change.
424
- *
425
- * @template TItem - The type of items in the array (inferred from field path)
426
- *
427
- * @example
428
- * interface Address { street: string; city: string }
429
- * const addresses = fields('addresses') // FieldArray<Address>
430
- * addresses.append({ street: '123 Main', city: 'NYC' }) // Typed!
431
- *
432
- * @example Check if operation succeeded
433
- * const success = addresses.append({ street: '', city: '' })
434
- * if (!success) {
435
- * // Operation was rejected (e.g., maxLength exceeded)
436
- * showNotification('Cannot add more addresses')
437
- * }
438
- */
439
- export interface FieldArray<TItem = unknown> {
440
- /** Current field items with metadata. Reactive - updates when array methods are called. */
441
- value: FieldArrayItem[];
442
- /** Append item(s) to end of array. Returns false if maxLength exceeded. */
443
- append: (value: TItem | TItem[], options?: FieldArrayFocusOptions) => boolean;
444
- /** Prepend item(s) to beginning of array. Returns false if maxLength exceeded. */
445
- prepend: (value: TItem | TItem[], options?: FieldArrayFocusOptions) => boolean;
446
- /** Remove item at index. Returns false if minLength violated or index out of bounds. */
447
- remove: (index: number) => boolean;
448
- /**
449
- * Remove all items from the array.
450
- * Returns false if minLength > 0.
451
- */
452
- removeAll: () => boolean;
453
- /**
454
- * Remove multiple items by indices (handles any order, removes from highest to lowest).
455
- * Returns false if minLength would be violated.
456
- * @param indices - Array of indices to remove
457
- */
458
- removeMany: (indices: number[]) => boolean;
459
- /** Insert item(s) at index. Returns false if maxLength exceeded. */
460
- insert: (index: number, value: TItem | TItem[], options?: FieldArrayFocusOptions) => boolean;
461
- /** Swap two items. Returns false if either index is out of bounds. */
462
- swap: (indexA: number, indexB: number) => boolean;
463
- /** Move item from one index to another. Returns false if from index is out of bounds. */
464
- move: (from: number, to: number) => boolean;
465
- /** Update item at index (preserves key/identity). Returns false if index out of bounds. */
466
- update: (index: number, value: TItem) => boolean;
467
- /** Replace all items with new values. Always succeeds (returns true). */
468
- replace: (values: TItem[]) => boolean;
469
- }
470
- /**
471
- * Async default values function type
472
- */
473
- export type AsyncDefaultValues<T> = () => Promise<Partial<T>>;
474
- /**
475
- * Criteria mode for error collection
476
- */
477
- export type CriteriaMode = 'firstError' | 'all';
478
- /**
479
- * Options for useForm composable
480
- */
481
- export interface UseFormOptions<TSchema extends ZodType> {
482
- /** Zod schema for validation */
483
- schema: TSchema;
484
- /**
485
- * Default form values. Can be a sync object or async function.
486
- * Async function is useful for fetching initial values from an API.
487
- *
488
- * @example Sync default values
489
- * ```ts
490
- * useForm({
491
- * schema,
492
- * defaultValues: { email: '', name: '' }
493
- * })
494
- * ```
495
- *
496
- * @example Async default values (API fetch)
497
- * ```ts
498
- * useForm({
499
- * schema,
500
- * defaultValues: async () => {
501
- * const user = await api.getCurrentUser()
502
- * return { email: user.email, name: user.name }
503
- * },
504
- * onDefaultValuesError: (err) => console.error('Failed to load user:', err)
505
- * })
506
- * // Check formState.isLoading to show loading indicator
507
- * ```
508
- */
509
- defaultValues?: Partial<InferSchema<TSchema>> | AsyncDefaultValues<InferSchema<TSchema>>;
510
- /**
511
- * When to run validation.
512
- * - 'onSubmit' (default): Only validate on form submission
513
- * - 'onBlur': Validate when field loses focus
514
- * - 'onChange': Validate on every input change
515
- * - 'onTouched': Validate after field touched, then on every change
516
- *
517
- * @example Different validation modes
518
- * ```ts
519
- * // Most performant - only show errors after submit attempt
520
- * useForm({ schema, mode: 'onSubmit' })
521
- *
522
- * // Real-time feedback - validate as user types
523
- * useForm({ schema, mode: 'onChange' })
524
- *
525
- * // Balanced - validate after first interaction
526
- * useForm({ schema, mode: 'onTouched' })
527
- * ```
528
- */
529
- mode?: ValidationMode;
530
- /**
531
- * Validation mode after first submission.
532
- * Useful for "validate on submit, then real-time revalidation" pattern.
533
- *
534
- * @example Submit first, then real-time
535
- * ```ts
536
- * useForm({
537
- * schema,
538
- * mode: 'onSubmit', // First submit validates all
539
- * reValidateMode: 'onChange' // After submit, revalidate on change
540
- * })
541
- * ```
542
- */
543
- reValidateMode?: ValidationMode;
544
- /** Remove field data when unmounted (default: false) */
545
- shouldUnregister?: boolean;
546
- /** Callback when async default values fail to load */
547
- onDefaultValuesError?: (error: unknown) => void;
548
- /** Focus first field with error on submit (default: true) */
549
- shouldFocusError?: boolean;
550
- /**
551
- * How to collect validation errors.
552
- * - 'firstError' (default): Stop at first error per field
553
- * - 'all': Collect all errors for each field (populates FieldError.types)
554
- *
555
- * @example Show all validation errors (password requirements)
556
- * ```ts
557
- * const schema = z.object({
558
- * password: z.string()
559
- * .min(8, 'At least 8 characters')
560
- * .regex(/[A-Z]/, 'Needs uppercase letter')
561
- * .regex(/[0-9]/, 'Needs a number')
562
- * })
563
- *
564
- * useForm({ schema, criteriaMode: 'all' })
565
- *
566
- * // In template - display all password requirements:
567
- * // <ul v-if="formState.errors.password?.types">
568
- * // <li v-for="(msg, type) in formState.errors.password.types" :key="type">
569
- * // {{ msg }}
570
- * // </li>
571
- * // </ul>
572
- * ```
573
- *
574
- * @see isFieldError - Type guard for structured errors
575
- * @see FieldError.types - Contains all error types when criteriaMode is 'all'
576
- */
577
- criteriaMode?: CriteriaMode;
578
- /**
579
- * Delay in milliseconds before displaying validation errors.
580
- * Prevents error flash during fast typing.
581
- *
582
- * @example Delay error display by 500ms
583
- * ```ts
584
- * useForm({
585
- * schema,
586
- * mode: 'onChange',
587
- * delayError: 500 // Wait 500ms before showing error
588
- * })
589
- * // If user fixes error within 500ms, error never appears
590
- * ```
591
- */
592
- delayError?: number;
593
- /**
594
- * Debounce time in milliseconds for schema validation in onChange mode.
595
- * Prevents excessive validation calls during rapid typing.
596
- * Unlike delayError which delays showing errors, this delays the validation itself.
597
- *
598
- * @example Debounce validation by 150ms
599
- * ```ts
600
- * useForm({
601
- * schema,
602
- * mode: 'onChange',
603
- * validationDebounce: 150 // Wait 150ms of idle time before validating
604
- * })
605
- * // Reduces validation calls during rapid typing
606
- * ```
607
- */
608
- validationDebounce?: number;
609
- /**
610
- * External values to sync to form. Changes update formData without marking dirty.
611
- * Useful for server-fetched data or parent component state.
612
- *
613
- * @example Sync with parent component state
614
- * ```ts
615
- * const props = defineProps<{ userData: UserData }>()
616
- *
617
- * useForm({
618
- * schema,
619
- * values: computed(() => props.userData) // Reactive sync
620
- * })
621
- * // When props.userData changes, form updates without becoming dirty
622
- * ```
623
- *
624
- * @example Sync with API polling
625
- * ```ts
626
- * const { data: serverData } = useQuery('user', fetchUser)
627
- *
628
- * useForm({
629
- * schema,
630
- * values: serverData // Ref from useQuery
631
- * })
632
- * ```
633
- */
634
- values?: MaybeRef<Partial<InferSchema<TSchema>>>;
635
- /**
636
- * External/server errors to merge with validation errors.
637
- * These take precedence over client-side validation errors.
638
- *
639
- * @example Display server validation errors
640
- * ```ts
641
- * const serverErrors = ref({})
642
- *
643
- * const { handleSubmit } = useForm({
644
- * schema,
645
- * errors: serverErrors
646
- * })
647
- *
648
- * const onSubmit = async (data) => {
649
- * try {
650
- * await api.submit(data)
651
- * } catch (err) {
652
- * if (err.validationErrors) {
653
- * serverErrors.value = err.validationErrors
654
- * // e.g., { email: 'Email already registered' }
655
- * }
656
- * }
657
- * }
658
- * ```
659
- */
660
- errors?: MaybeRef<Partial<FieldErrors<InferSchema<TSchema>>>>;
661
- /**
662
- * Disable the entire form. When true:
663
- * - All registered fields receive `disabled` attribute
664
- * - Form submission is prevented
665
- * - Can be reactive (MaybeRef) to toggle dynamically
666
- *
667
- * @example Disable form during submission
668
- * ```ts
669
- * const isSubmitting = ref(false)
670
- *
671
- * useForm({
672
- * schema,
673
- * disabled: isSubmitting
674
- * })
675
- * ```
676
- */
677
- disabled?: MaybeRef<boolean>;
678
- /**
679
- * Enable browser's native validation API.
680
- * When true:
681
- * - Calls setCustomValidity() on inputs with error messages
682
- * - Enables :valid/:invalid CSS pseudo-selectors
683
- * - Shows native browser validation tooltips
684
- *
685
- * @example
686
- * ```ts
687
- * useForm({ schema, shouldUseNativeValidation: true })
688
- *
689
- * // CSS styling:
690
- * // input:invalid { border-color: red; }
691
- * // input:valid { border-color: green; }
692
- * ```
693
- */
694
- shouldUseNativeValidation?: boolean;
695
- }
696
- /**
697
- * Return value from useForm composable.
698
- * Provides full type safety with autocomplete for field paths and typed values.
699
- *
700
- * @template TSchema - The Zod schema type for form validation
701
- */
702
- export interface UseFormReturn<TSchema extends ZodType> {
703
- /**
704
- * Register an input field for form management.
705
- * Returns props to spread onto your input element.
706
- *
707
- * @param name - Field path (e.g., 'email' or 'user.address.street')
708
- * @param options - Registration options (validation, controlled mode, etc.)
709
- * @returns Props to bind to the input element
710
- *
711
- * @example
712
- * <input v-bind="register('email')" />
713
- * <input v-bind="register('age', { validate: (v) => v >= 0 || 'Must be positive' })" />
714
- */
715
- register: <TPath extends Path<InferSchema<TSchema>>>(name: TPath, options?: RegisterOptions<PathValue<InferSchema<TSchema>, TPath>>) => RegisterReturn<PathValue<InferSchema<TSchema>, TPath>>;
716
- /**
717
- * Unregister a field to clean up refs and options
718
- * Call this when a field is unmounted to prevent memory leaks
719
- * @param name - Field path to unregister
720
- * @param options - Options for what state to preserve
721
- */
722
- unregister: <TPath extends Path<InferSchema<TSchema>>>(name: TPath, options?: UnregisterOptions) => void;
723
- /**
724
- * Handle form submission
725
- * @param onValid - Callback called with valid data
726
- * @param onInvalid - Optional callback called with errors
727
- */
728
- handleSubmit: (onValid: (data: InferSchema<TSchema>) => void | Promise<void>, onInvalid?: (errors: FieldErrors<InferSchema<TSchema>>) => void) => (e: Event) => Promise<void>;
729
- /** Reactive form state */
730
- formState: ComputedRef<FormState<InferSchema<TSchema>>>;
731
- /**
732
- * Manage dynamic field arrays.
733
- * Returns a typed API for adding, removing, and reordering array items.
734
- *
735
- * @param name - Array field path (must be an array field in the schema)
736
- * @param options - Optional configuration including validation rules
737
- * @returns Typed FieldArray API
738
- *
739
- * @example
740
- * const addresses = fields('addresses')
741
- * addresses.append({ street: '', city: '' }) // Typed to Address
742
- */
743
- fields: <TPath extends ArrayPath<InferSchema<TSchema>>>(name: TPath, options?: FieldArrayOptions<ArrayElement<PathValue<InferSchema<TSchema>, TPath>>>) => FieldArray<ArrayElement<PathValue<InferSchema<TSchema>, TPath>>>;
744
- /**
745
- * Set field value programmatically
746
- * @param name - Field path
747
- * @param value - New value (typed to match field)
748
- * @param options - Options for validation/dirty/touched behavior
749
- */
750
- setValue: <TPath extends Path<InferSchema<TSchema>>>(name: TPath, value: PathValue<InferSchema<TSchema>, TPath>, options?: SetValueOptions) => void;
751
- /**
752
- * Reset form to default values
753
- * @param values - Optional new default values
754
- * @param options - Optional reset options
755
- */
756
- reset: (values?: Partial<InferSchema<TSchema>>, options?: ResetOptions) => void;
757
- /**
758
- * Reset an individual field to its default value
759
- * @param name - Field path
760
- * @param options - Options for what state to preserve (with typed defaultValue)
761
- */
762
- resetField: <TPath extends Path<InferSchema<TSchema>>>(name: TPath, options?: ResetFieldOptions<PathValue<InferSchema<TSchema>, TPath>>) => void;
763
- /**
764
- * Watch field value(s) reactively
765
- * @overload Watch all form values
766
- * @overload Watch single field value by path
767
- * @overload Watch multiple field values by paths array
768
- */
769
- watch: {
770
- (): ComputedRef<InferSchema<TSchema>>;
771
- <TPath extends Path<InferSchema<TSchema>>>(name: TPath): ComputedRef<PathValue<InferSchema<TSchema>, TPath>>;
772
- <TPath extends Path<InferSchema<TSchema>>>(names: TPath[]): ComputedRef<Partial<InferSchema<TSchema>>>;
773
- };
774
- /**
775
- * Manually trigger validation
776
- * @param name - Optional field path (validates all if not provided)
777
- */
778
- validate: <TPath extends Path<InferSchema<TSchema>>>(name?: TPath) => Promise<boolean>;
779
- /**
780
- * Clear errors for specified fields or all errors
781
- * @param name - Optional field path or array of paths
782
- */
783
- clearErrors: <TPath extends Path<InferSchema<TSchema>>>(name?: TPath | TPath[] | 'root' | `root.${string}`) => void;
784
- /**
785
- * Set an error for a specific field
786
- * @param name - Field path or root error
787
- * @param error - Error option with message
788
- */
789
- setError: <TPath extends Path<InferSchema<TSchema>>>(name: TPath | 'root' | `root.${string}`, error: ErrorOption) => void;
790
- /**
791
- * Set multiple errors at once. Useful for server-side validation errors
792
- * or bulk error handling scenarios.
793
- *
794
- * @param errors - Record of field paths to error messages or ErrorOption objects
795
- * @param options - Optional configuration for merge behavior
796
- *
797
- * @example
798
- * // Simple string errors
799
- * setErrors({
800
- * email: 'Email already exists',
801
- * 'user.name': 'Name is too short'
802
- * })
803
- *
804
- * @example
805
- * // Replace all errors
806
- * setErrors({ email: 'New error' }, { shouldReplace: true })
807
- */
808
- setErrors: <TPath extends Path<InferSchema<TSchema>>>(errors: Partial<Record<TPath | 'root' | `root.${string}`, string | ErrorOption>>, options?: SetErrorsOptions) => void;
809
- /**
810
- * Check if the form or a specific field has validation errors
811
- *
812
- * @param fieldPath - Optional field path to check. If omitted, checks entire form.
813
- * @returns true if errors exist, false otherwise
814
- *
815
- * @example
816
- * if (hasErrors()) {
817
- * console.log('Form has validation errors')
818
- * }
819
- *
820
- * @example
821
- * if (hasErrors('email')) {
822
- * focusField('email')
823
- * }
824
- */
825
- hasErrors: <TPath extends Path<InferSchema<TSchema>>>(fieldPath?: TPath | 'root' | `root.${string}`) => boolean;
826
- /**
827
- * Get validation errors for the form or a specific field
828
- *
829
- * @overload Get all form errors
830
- * @overload Get error for a specific field
831
- *
832
- * @example
833
- * const allErrors = getErrors()
834
- *
835
- * @example
836
- * const emailError = getErrors('email')
837
- */
838
- getErrors: {
839
- (): FieldErrors<InferSchema<TSchema>>;
840
- <TPath extends Path<InferSchema<TSchema>>>(fieldPath: TPath | 'root' | `root.${string}`): FieldErrorValue | undefined;
841
- };
842
- /**
843
- * Get all form values, a single value, or multiple values
844
- * @overload Get all form values
845
- * @overload Get single field value by path
846
- * @overload Get multiple field values by paths array
847
- */
848
- getValues: {
849
- (): InferSchema<TSchema>;
850
- <TPath extends Path<InferSchema<TSchema>>>(name: TPath): PathValue<InferSchema<TSchema>, TPath>;
851
- <TPath extends Path<InferSchema<TSchema>>>(names: TPath[]): Partial<InferSchema<TSchema>>;
852
- };
853
- /**
854
- * Get the state of an individual field
855
- * @param name - Field path
856
- */
857
- getFieldState: <TPath extends Path<InferSchema<TSchema>>>(name: TPath) => FieldState;
858
- /**
859
- * Manually trigger validation for specific fields or entire form
860
- * @param name - Optional field path or array of paths
861
- * @param options - Optional trigger options (e.g., markAsSubmitted)
862
- */
863
- trigger: <TPath extends Path<InferSchema<TSchema>>>(name?: TPath | TPath[], options?: TriggerOptions) => Promise<boolean>;
864
- /**
865
- * Programmatically focus a field
866
- * @param name - Field path
867
- * @param options - Focus options
868
- */
869
- setFocus: <TPath extends Path<InferSchema<TSchema>>>(name: TPath, options?: SetFocusOptions) => void;
870
- /**
871
- * Form configuration options (mode, reValidateMode).
872
- * Useful for composables like useController that need to respect validation modes.
873
- */
874
- options: Pick<UseFormOptions<TSchema>, 'mode' | 'reValidateMode'>;
875
- }
876
- /**
877
- * Type guard to check if an error value is a structured FieldError object.
878
- * Use this to safely narrow FieldErrorValue when handling errors.
879
- *
880
- * @param error - The error value to check (can be string, FieldError, or undefined)
881
- * @returns True if the error is a FieldError object with type and message
882
- *
883
- * @example
884
- * const error = formState.value.errors.email
885
- * if (isFieldError(error)) {
886
- * // error is FieldError - has .type, .message, and optional .types
887
- * console.log(`${error.type}: ${error.message}`)
888
- * } else if (typeof error === 'string') {
889
- * // error is a simple string message
890
- * console.log(error)
891
- * }
892
- */
893
- export declare function isFieldError(error: FieldErrorValue | undefined | null): error is FieldError;