@vuehookform/core 0.4.2 → 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,889 +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: (e: Event) => 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
- * @template TItem - The type of items in the array (inferred from field path)
422
- *
423
- * @example
424
- * interface Address { street: string; city: string }
425
- * const addresses = fields('addresses') // FieldArray<Address>
426
- * addresses.append({ street: '123 Main', city: 'NYC' }) // Typed!
427
- *
428
- * @example Check if operation succeeded
429
- * const success = addresses.append({ street: '', city: '' })
430
- * if (!success) {
431
- * // Operation was rejected (e.g., maxLength exceeded)
432
- * showNotification('Cannot add more addresses')
433
- * }
434
- */
435
- export interface FieldArray<TItem = unknown> {
436
- /** Current field items with metadata */
437
- value: FieldArrayItem[];
438
- /** Append item(s) to end of array. Returns false if maxLength exceeded. */
439
- append: (value: TItem | TItem[], options?: FieldArrayFocusOptions) => boolean;
440
- /** Prepend item(s) to beginning of array. Returns false if maxLength exceeded. */
441
- prepend: (value: TItem | TItem[], options?: FieldArrayFocusOptions) => boolean;
442
- /** Remove item at index. Returns false if minLength violated or index out of bounds. */
443
- remove: (index: number) => boolean;
444
- /**
445
- * Remove all items from the array.
446
- * Returns false if minLength > 0.
447
- */
448
- removeAll: () => boolean;
449
- /**
450
- * Remove multiple items by indices (handles any order, removes from highest to lowest).
451
- * Returns false if minLength would be violated.
452
- * @param indices - Array of indices to remove
453
- */
454
- removeMany: (indices: number[]) => boolean;
455
- /** Insert item(s) at index. Returns false if maxLength exceeded. */
456
- insert: (index: number, value: TItem | TItem[], options?: FieldArrayFocusOptions) => boolean;
457
- /** Swap two items. Returns false if either index is out of bounds. */
458
- swap: (indexA: number, indexB: number) => boolean;
459
- /** Move item from one index to another. Returns false if from index is out of bounds. */
460
- move: (from: number, to: number) => boolean;
461
- /** Update item at index (preserves key/identity). Returns false if index out of bounds. */
462
- update: (index: number, value: TItem) => boolean;
463
- /** Replace all items with new values. Always succeeds (returns true). */
464
- replace: (values: TItem[]) => boolean;
465
- }
466
- /**
467
- * Async default values function type
468
- */
469
- export type AsyncDefaultValues<T> = () => Promise<Partial<T>>;
470
- /**
471
- * Criteria mode for error collection
472
- */
473
- export type CriteriaMode = 'firstError' | 'all';
474
- /**
475
- * Options for useForm composable
476
- */
477
- export interface UseFormOptions<TSchema extends ZodType> {
478
- /** Zod schema for validation */
479
- schema: TSchema;
480
- /**
481
- * Default form values. Can be a sync object or async function.
482
- * Async function is useful for fetching initial values from an API.
483
- *
484
- * @example Sync default values
485
- * ```ts
486
- * useForm({
487
- * schema,
488
- * defaultValues: { email: '', name: '' }
489
- * })
490
- * ```
491
- *
492
- * @example Async default values (API fetch)
493
- * ```ts
494
- * useForm({
495
- * schema,
496
- * defaultValues: async () => {
497
- * const user = await api.getCurrentUser()
498
- * return { email: user.email, name: user.name }
499
- * },
500
- * onDefaultValuesError: (err) => console.error('Failed to load user:', err)
501
- * })
502
- * // Check formState.isLoading to show loading indicator
503
- * ```
504
- */
505
- defaultValues?: Partial<InferSchema<TSchema>> | AsyncDefaultValues<InferSchema<TSchema>>;
506
- /**
507
- * When to run validation.
508
- * - 'onSubmit' (default): Only validate on form submission
509
- * - 'onBlur': Validate when field loses focus
510
- * - 'onChange': Validate on every input change
511
- * - 'onTouched': Validate after field touched, then on every change
512
- *
513
- * @example Different validation modes
514
- * ```ts
515
- * // Most performant - only show errors after submit attempt
516
- * useForm({ schema, mode: 'onSubmit' })
517
- *
518
- * // Real-time feedback - validate as user types
519
- * useForm({ schema, mode: 'onChange' })
520
- *
521
- * // Balanced - validate after first interaction
522
- * useForm({ schema, mode: 'onTouched' })
523
- * ```
524
- */
525
- mode?: ValidationMode;
526
- /**
527
- * Validation mode after first submission.
528
- * Useful for "validate on submit, then real-time revalidation" pattern.
529
- *
530
- * @example Submit first, then real-time
531
- * ```ts
532
- * useForm({
533
- * schema,
534
- * mode: 'onSubmit', // First submit validates all
535
- * reValidateMode: 'onChange' // After submit, revalidate on change
536
- * })
537
- * ```
538
- */
539
- reValidateMode?: ValidationMode;
540
- /** Remove field data when unmounted (default: false) */
541
- shouldUnregister?: boolean;
542
- /** Callback when async default values fail to load */
543
- onDefaultValuesError?: (error: unknown) => void;
544
- /** Focus first field with error on submit (default: true) */
545
- shouldFocusError?: boolean;
546
- /**
547
- * How to collect validation errors.
548
- * - 'firstError' (default): Stop at first error per field
549
- * - 'all': Collect all errors for each field (populates FieldError.types)
550
- *
551
- * @example Show all validation errors (password requirements)
552
- * ```ts
553
- * const schema = z.object({
554
- * password: z.string()
555
- * .min(8, 'At least 8 characters')
556
- * .regex(/[A-Z]/, 'Needs uppercase letter')
557
- * .regex(/[0-9]/, 'Needs a number')
558
- * })
559
- *
560
- * useForm({ schema, criteriaMode: 'all' })
561
- *
562
- * // In template - display all password requirements:
563
- * // <ul v-if="formState.errors.password?.types">
564
- * // <li v-for="(msg, type) in formState.errors.password.types" :key="type">
565
- * // {{ msg }}
566
- * // </li>
567
- * // </ul>
568
- * ```
569
- *
570
- * @see isFieldError - Type guard for structured errors
571
- * @see FieldError.types - Contains all error types when criteriaMode is 'all'
572
- */
573
- criteriaMode?: CriteriaMode;
574
- /**
575
- * Delay in milliseconds before displaying validation errors.
576
- * Prevents error flash during fast typing.
577
- *
578
- * @example Delay error display by 500ms
579
- * ```ts
580
- * useForm({
581
- * schema,
582
- * mode: 'onChange',
583
- * delayError: 500 // Wait 500ms before showing error
584
- * })
585
- * // If user fixes error within 500ms, error never appears
586
- * ```
587
- */
588
- delayError?: number;
589
- /**
590
- * Debounce time in milliseconds for schema validation in onChange mode.
591
- * Prevents excessive validation calls during rapid typing.
592
- * Unlike delayError which delays showing errors, this delays the validation itself.
593
- *
594
- * @example Debounce validation by 150ms
595
- * ```ts
596
- * useForm({
597
- * schema,
598
- * mode: 'onChange',
599
- * validationDebounce: 150 // Wait 150ms of idle time before validating
600
- * })
601
- * // Reduces validation calls during rapid typing
602
- * ```
603
- */
604
- validationDebounce?: number;
605
- /**
606
- * External values to sync to form. Changes update formData without marking dirty.
607
- * Useful for server-fetched data or parent component state.
608
- *
609
- * @example Sync with parent component state
610
- * ```ts
611
- * const props = defineProps<{ userData: UserData }>()
612
- *
613
- * useForm({
614
- * schema,
615
- * values: computed(() => props.userData) // Reactive sync
616
- * })
617
- * // When props.userData changes, form updates without becoming dirty
618
- * ```
619
- *
620
- * @example Sync with API polling
621
- * ```ts
622
- * const { data: serverData } = useQuery('user', fetchUser)
623
- *
624
- * useForm({
625
- * schema,
626
- * values: serverData // Ref from useQuery
627
- * })
628
- * ```
629
- */
630
- values?: MaybeRef<Partial<InferSchema<TSchema>>>;
631
- /**
632
- * External/server errors to merge with validation errors.
633
- * These take precedence over client-side validation errors.
634
- *
635
- * @example Display server validation errors
636
- * ```ts
637
- * const serverErrors = ref({})
638
- *
639
- * const { handleSubmit } = useForm({
640
- * schema,
641
- * errors: serverErrors
642
- * })
643
- *
644
- * const onSubmit = async (data) => {
645
- * try {
646
- * await api.submit(data)
647
- * } catch (err) {
648
- * if (err.validationErrors) {
649
- * serverErrors.value = err.validationErrors
650
- * // e.g., { email: 'Email already registered' }
651
- * }
652
- * }
653
- * }
654
- * ```
655
- */
656
- errors?: MaybeRef<Partial<FieldErrors<InferSchema<TSchema>>>>;
657
- /**
658
- * Disable the entire form. When true:
659
- * - All registered fields receive `disabled` attribute
660
- * - Form submission is prevented
661
- * - Can be reactive (MaybeRef) to toggle dynamically
662
- *
663
- * @example Disable form during submission
664
- * ```ts
665
- * const isSubmitting = ref(false)
666
- *
667
- * useForm({
668
- * schema,
669
- * disabled: isSubmitting
670
- * })
671
- * ```
672
- */
673
- disabled?: MaybeRef<boolean>;
674
- /**
675
- * Enable browser's native validation API.
676
- * When true:
677
- * - Calls setCustomValidity() on inputs with error messages
678
- * - Enables :valid/:invalid CSS pseudo-selectors
679
- * - Shows native browser validation tooltips
680
- *
681
- * @example
682
- * ```ts
683
- * useForm({ schema, shouldUseNativeValidation: true })
684
- *
685
- * // CSS styling:
686
- * // input:invalid { border-color: red; }
687
- * // input:valid { border-color: green; }
688
- * ```
689
- */
690
- shouldUseNativeValidation?: boolean;
691
- }
692
- /**
693
- * Return value from useForm composable.
694
- * Provides full type safety with autocomplete for field paths and typed values.
695
- *
696
- * @template TSchema - The Zod schema type for form validation
697
- */
698
- export interface UseFormReturn<TSchema extends ZodType> {
699
- /**
700
- * Register an input field for form management.
701
- * Returns props to spread onto your input element.
702
- *
703
- * @param name - Field path (e.g., 'email' or 'user.address.street')
704
- * @param options - Registration options (validation, controlled mode, etc.)
705
- * @returns Props to bind to the input element
706
- *
707
- * @example
708
- * <input v-bind="register('email')" />
709
- * <input v-bind="register('age', { validate: (v) => v >= 0 || 'Must be positive' })" />
710
- */
711
- register: <TPath extends Path<InferSchema<TSchema>>>(name: TPath, options?: RegisterOptions<PathValue<InferSchema<TSchema>, TPath>>) => RegisterReturn<PathValue<InferSchema<TSchema>, TPath>>;
712
- /**
713
- * Unregister a field to clean up refs and options
714
- * Call this when a field is unmounted to prevent memory leaks
715
- * @param name - Field path to unregister
716
- * @param options - Options for what state to preserve
717
- */
718
- unregister: <TPath extends Path<InferSchema<TSchema>>>(name: TPath, options?: UnregisterOptions) => void;
719
- /**
720
- * Handle form submission
721
- * @param onValid - Callback called with valid data
722
- * @param onInvalid - Optional callback called with errors
723
- */
724
- handleSubmit: (onValid: (data: InferSchema<TSchema>) => void | Promise<void>, onInvalid?: (errors: FieldErrors<InferSchema<TSchema>>) => void) => (e: Event) => Promise<void>;
725
- /** Reactive form state */
726
- formState: ComputedRef<FormState<InferSchema<TSchema>>>;
727
- /**
728
- * Manage dynamic field arrays.
729
- * Returns a typed API for adding, removing, and reordering array items.
730
- *
731
- * @param name - Array field path (must be an array field in the schema)
732
- * @param options - Optional configuration including validation rules
733
- * @returns Typed FieldArray API
734
- *
735
- * @example
736
- * const addresses = fields('addresses')
737
- * addresses.append({ street: '', city: '' }) // Typed to Address
738
- */
739
- fields: <TPath extends ArrayPath<InferSchema<TSchema>>>(name: TPath, options?: FieldArrayOptions<ArrayElement<PathValue<InferSchema<TSchema>, TPath>>>) => FieldArray<ArrayElement<PathValue<InferSchema<TSchema>, TPath>>>;
740
- /**
741
- * Set field value programmatically
742
- * @param name - Field path
743
- * @param value - New value (typed to match field)
744
- * @param options - Options for validation/dirty/touched behavior
745
- */
746
- setValue: <TPath extends Path<InferSchema<TSchema>>>(name: TPath, value: PathValue<InferSchema<TSchema>, TPath>, options?: SetValueOptions) => void;
747
- /**
748
- * Reset form to default values
749
- * @param values - Optional new default values
750
- * @param options - Optional reset options
751
- */
752
- reset: (values?: Partial<InferSchema<TSchema>>, options?: ResetOptions) => void;
753
- /**
754
- * Reset an individual field to its default value
755
- * @param name - Field path
756
- * @param options - Options for what state to preserve (with typed defaultValue)
757
- */
758
- resetField: <TPath extends Path<InferSchema<TSchema>>>(name: TPath, options?: ResetFieldOptions<PathValue<InferSchema<TSchema>, TPath>>) => void;
759
- /**
760
- * Watch field value(s) reactively
761
- * @overload Watch all form values
762
- * @overload Watch single field value by path
763
- * @overload Watch multiple field values by paths array
764
- */
765
- watch: {
766
- (): ComputedRef<InferSchema<TSchema>>;
767
- <TPath extends Path<InferSchema<TSchema>>>(name: TPath): ComputedRef<PathValue<InferSchema<TSchema>, TPath>>;
768
- <TPath extends Path<InferSchema<TSchema>>>(names: TPath[]): ComputedRef<Partial<InferSchema<TSchema>>>;
769
- };
770
- /**
771
- * Manually trigger validation
772
- * @param name - Optional field path (validates all if not provided)
773
- */
774
- validate: <TPath extends Path<InferSchema<TSchema>>>(name?: TPath) => Promise<boolean>;
775
- /**
776
- * Clear errors for specified fields or all errors
777
- * @param name - Optional field path or array of paths
778
- */
779
- clearErrors: <TPath extends Path<InferSchema<TSchema>>>(name?: TPath | TPath[] | 'root' | `root.${string}`) => void;
780
- /**
781
- * Set an error for a specific field
782
- * @param name - Field path or root error
783
- * @param error - Error option with message
784
- */
785
- setError: <TPath extends Path<InferSchema<TSchema>>>(name: TPath | 'root' | `root.${string}`, error: ErrorOption) => void;
786
- /**
787
- * Set multiple errors at once. Useful for server-side validation errors
788
- * or bulk error handling scenarios.
789
- *
790
- * @param errors - Record of field paths to error messages or ErrorOption objects
791
- * @param options - Optional configuration for merge behavior
792
- *
793
- * @example
794
- * // Simple string errors
795
- * setErrors({
796
- * email: 'Email already exists',
797
- * 'user.name': 'Name is too short'
798
- * })
799
- *
800
- * @example
801
- * // Replace all errors
802
- * setErrors({ email: 'New error' }, { shouldReplace: true })
803
- */
804
- setErrors: <TPath extends Path<InferSchema<TSchema>>>(errors: Partial<Record<TPath | 'root' | `root.${string}`, string | ErrorOption>>, options?: SetErrorsOptions) => void;
805
- /**
806
- * Check if the form or a specific field has validation errors
807
- *
808
- * @param fieldPath - Optional field path to check. If omitted, checks entire form.
809
- * @returns true if errors exist, false otherwise
810
- *
811
- * @example
812
- * if (hasErrors()) {
813
- * console.log('Form has validation errors')
814
- * }
815
- *
816
- * @example
817
- * if (hasErrors('email')) {
818
- * focusField('email')
819
- * }
820
- */
821
- hasErrors: <TPath extends Path<InferSchema<TSchema>>>(fieldPath?: TPath | 'root' | `root.${string}`) => boolean;
822
- /**
823
- * Get validation errors for the form or a specific field
824
- *
825
- * @overload Get all form errors
826
- * @overload Get error for a specific field
827
- *
828
- * @example
829
- * const allErrors = getErrors()
830
- *
831
- * @example
832
- * const emailError = getErrors('email')
833
- */
834
- getErrors: {
835
- (): FieldErrors<InferSchema<TSchema>>;
836
- <TPath extends Path<InferSchema<TSchema>>>(fieldPath: TPath | 'root' | `root.${string}`): FieldErrorValue | undefined;
837
- };
838
- /**
839
- * Get all form values, a single value, or multiple values
840
- * @overload Get all form values
841
- * @overload Get single field value by path
842
- * @overload Get multiple field values by paths array
843
- */
844
- getValues: {
845
- (): InferSchema<TSchema>;
846
- <TPath extends Path<InferSchema<TSchema>>>(name: TPath): PathValue<InferSchema<TSchema>, TPath>;
847
- <TPath extends Path<InferSchema<TSchema>>>(names: TPath[]): Partial<InferSchema<TSchema>>;
848
- };
849
- /**
850
- * Get the state of an individual field
851
- * @param name - Field path
852
- */
853
- getFieldState: <TPath extends Path<InferSchema<TSchema>>>(name: TPath) => FieldState;
854
- /**
855
- * Manually trigger validation for specific fields or entire form
856
- * @param name - Optional field path or array of paths
857
- * @param options - Optional trigger options (e.g., markAsSubmitted)
858
- */
859
- trigger: <TPath extends Path<InferSchema<TSchema>>>(name?: TPath | TPath[], options?: TriggerOptions) => Promise<boolean>;
860
- /**
861
- * Programmatically focus a field
862
- * @param name - Field path
863
- * @param options - Focus options
864
- */
865
- setFocus: <TPath extends Path<InferSchema<TSchema>>>(name: TPath, options?: SetFocusOptions) => void;
866
- /**
867
- * Form configuration options (mode, reValidateMode).
868
- * Useful for composables like useController that need to respect validation modes.
869
- */
870
- options: Pick<UseFormOptions<TSchema>, 'mode' | 'reValidateMode'>;
871
- }
872
- /**
873
- * Type guard to check if an error value is a structured FieldError object.
874
- * Use this to safely narrow FieldErrorValue when handling errors.
875
- *
876
- * @param error - The error value to check (can be string, FieldError, or undefined)
877
- * @returns True if the error is a FieldError object with type and message
878
- *
879
- * @example
880
- * const error = formState.value.errors.email
881
- * if (isFieldError(error)) {
882
- * // error is FieldError - has .type, .message, and optional .types
883
- * console.log(`${error.type}: ${error.message}`)
884
- * } else if (typeof error === 'string') {
885
- * // error is a simple string message
886
- * console.log(error)
887
- * }
888
- */
889
- export declare function isFieldError(error: FieldErrorValue | undefined | null): error is FieldError;