@vuehookform/core 0.2.11 → 0.3.3

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/README.md CHANGED
@@ -7,10 +7,10 @@ A TypeScript-first form library for Vue 3, inspired by React Hook Form.
7
7
  ## Features
8
8
 
9
9
  - **TypeScript First** - Perfect type inference with zero manual typing
10
- - **Zero Config** - Works out of the box with sensible defaults
10
+ - **Field Arrays** - Dynamic lists with stable keys built-in
11
11
  - **Performant** - Minimal re-renders using uncontrolled inputs
12
12
  - **Zod Native** - First-class Zod integration for validation
13
- - **Tiny Bundle** - < 5kb gzipped, tree-shakable
13
+ - **Tiny Bundle** - ~10kb gzipped, tree-shakable
14
14
  - **UI Agnostic** - Works with any UI library or custom components
15
15
 
16
16
  ## Quick Start
@@ -73,6 +73,13 @@ type UserForm = z.infer<typeof userSchema>
73
73
  <script setup>
74
74
  const { register, fields } = useForm({ schema })
75
75
  const addresses = fields('addresses')
76
+
77
+ // Available methods:
78
+ // addresses.append(value) - Add to end
79
+ // addresses.remove(index) - Remove at index
80
+ // addresses.insert(index, value)
81
+ // addresses.swap(i, j)
82
+ // addresses.move(from, to)
76
83
  </script>
77
84
 
78
85
  <template>
@@ -96,40 +103,31 @@ useForm({
96
103
  })
97
104
  ```
98
105
 
99
- ## API Reference
100
-
101
- ### `useForm(options)`
106
+ - `disabled: ref(true)` - Disable entire form (reactive, blocks submission)
107
+ - `shouldUseNativeValidation: true` - Enable CSS `:valid`/`:invalid` selectors
102
108
 
103
- ```typescript
104
- const {
105
- register, // Register input field
106
- handleSubmit, // Create submit handler with validation
107
- formState, // Reactive form state (errors, isSubmitting, etc.)
108
- fields, // Manage dynamic field arrays
109
- setValue, // Programmatically set field value
110
- getValue, // Get current field value
111
- reset, // Reset form to default values
112
- watch, // Watch field value changes
113
- validate, // Manually trigger validation
114
- } = useForm({
115
- schema, // Zod schema for validation
116
- defaultValues: {}, // Initial form values
117
- mode: 'onSubmit', // When to validate
118
- })
119
- ```
109
+ ## Tips
120
110
 
121
- ### `fields(name)`
111
+ ### Controlled vs Uncontrolled
122
112
 
123
113
  ```typescript
124
- const addresses = fields('addresses')
114
+ // Default (uncontrolled) - for native inputs
115
+ <input v-bind="register('email')" />
125
116
 
126
- addresses.append({ street: '', city: '' })
127
- addresses.remove(0)
128
- addresses.insert(1, value)
129
- addresses.swap(0, 1)
130
- addresses.move(0, 2)
117
+ // Controlled - for v-model / custom components
118
+ const { value, ...bindings } = register('field', { controlled: true })
119
+ <CustomInput v-model="value" v-bind="bindings" />
131
120
  ```
132
121
 
122
+ ### Common Mistakes
123
+
124
+ | Wrong | Right |
125
+ | ------------------------ | ------------------------ |
126
+ | `items[0].name` | `items.0.name` |
127
+ | `:key="index"` | `:key="field.key"` |
128
+ | `formState.errors` | `formState.value.errors` |
129
+ | `v-model` + `register()` | Either one, not both |
130
+
133
131
  ## Contributing
134
132
 
135
133
  Contributions welcome! Feel free to report bugs, suggest features, or submit PRs.
@@ -20,10 +20,3 @@ export declare function syncUncontrolledInputs(fieldRefs: Map<string, Ref<HTMLIn
20
20
  * @param value - The value to set
21
21
  */
22
22
  export declare function updateDomElement(el: HTMLInputElement, value: unknown): void;
23
- /**
24
- * Get value from a DOM element based on its type
25
- *
26
- * @param el - The DOM input element
27
- * @returns The current value (checked state for checkboxes, value for others)
28
- */
29
- export declare function getDomElementValue(el: HTMLInputElement): unknown;
@@ -44,6 +44,7 @@ export interface FormContext<FormValues> {
44
44
  debounceTimers: Map<string, ReturnType<typeof setTimeout>>;
45
45
  validationRequestIds: Map<string, number>;
46
46
  resetGeneration: Ref<number>;
47
+ isDisabled: Ref<boolean>;
47
48
  options: UseFormOptions<ZodType>;
48
49
  }
49
50
  /**
package/dist/index.d.ts CHANGED
@@ -20,4 +20,4 @@ export { useWatch, type UseWatchOptions } from './useWatch';
20
20
  export { useController, type UseControllerOptions, type UseControllerReturn, type ControllerFieldProps, } from './useController';
21
21
  export { useFormState, type UseFormStateOptions, type FormStateKey } from './useFormState';
22
22
  export { isFieldError } from './types';
23
- export type { UseFormOptions, UseFormReturn, RegisterOptions, RegisterReturn, FormState, FieldState, FieldErrors, FieldError, FieldErrorValue, ErrorOption, FieldArray, FieldArrayItem, InferSchema, FormValues, FormPath, Path, PathValue, ArrayElement, ArrayPath, ValidationMode, SetFocusOptions, ResetOptions, ResetFieldOptions, AsyncDefaultValues, } from './types';
23
+ export type { UseFormOptions, UseFormReturn, RegisterOptions, RegisterReturn, FormState, FieldState, FieldErrors, FieldError, FieldErrorValue, ErrorOption, SetErrorsOptions, FieldArray, FieldArrayItem, InferSchema, FormValues, FormPath, Path, PathValue, ArrayElement, ArrayPath, FieldPath, ValidationMode, SetFocusOptions, ResetOptions, ResetFieldOptions, AsyncDefaultValues, } from './types';
package/dist/types.d.ts CHANGED
@@ -63,9 +63,20 @@ export type FormPath<TSchema extends ZodType> = Path<FormValues<TSchema>>;
63
63
  export type ArrayPath<T> = {
64
64
  [K in Path<T>]: PathValue<T, K> extends Array<unknown> ? K : never;
65
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>];
66
77
  /**
67
78
  * Extract the value type at a given dot-notation path.
68
- * Used internally to ensure setValue/getValue have correct types.
79
+ * Used internally to ensure setValue/getValues have correct types.
69
80
  * Supports numeric string indices for array access (e.g., 'items.0.name').
70
81
  *
71
82
  * @example
@@ -76,14 +87,42 @@ export type ArrayPath<T> = {
76
87
  */
77
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;
78
89
  /**
79
- * Single field error with type and message
90
+ * Single field error with type and message.
91
+ * When criteriaMode is 'all', the `types` property contains all validation errors.
80
92
  */
81
93
  export interface FieldError {
82
- /** Error type identifier (e.g., 'required', 'minLength', 'custom') */
94
+ /** Error type identifier (e.g., 'required', 'too_small', 'invalid_string', 'custom') */
83
95
  type: string;
84
- /** Error message to display */
96
+ /** Primary error message to display */
85
97
  message: string;
86
- /** Additional error types when multiple validations fail */
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
+ */
87
126
  types?: Record<string, string | string[]>;
88
127
  }
89
128
  /**
@@ -145,6 +184,8 @@ export interface FormState<T> {
145
184
  isSubmitted: boolean;
146
185
  /** Whether the last submission was successful */
147
186
  isSubmitSuccessful: boolean;
187
+ /** Whether the form is disabled */
188
+ disabled: boolean;
148
189
  }
149
190
  /**
150
191
  * State of an individual field
@@ -236,6 +277,13 @@ export interface ResetOptions {
236
277
  /** Keep isSubmitSuccessful state after reset */
237
278
  keepIsSubmitSuccessful?: boolean;
238
279
  }
280
+ /**
281
+ * Options for setErrors() bulk operation
282
+ */
283
+ export interface SetErrorsOptions {
284
+ /** Replace all existing errors instead of merging (default: false) */
285
+ shouldReplace?: boolean;
286
+ }
239
287
  /**
240
288
  * Options for registering a field
241
289
  * @template TValue - The type of the field value (inferred from field path)
@@ -296,6 +344,8 @@ export interface RegisterReturn<TValue = unknown> {
296
344
  onBlur: (e: Event) => void;
297
345
  /** Current value (for controlled mode) - only present when controlled: true */
298
346
  value?: Ref<TValue>;
347
+ /** Disabled state from form-level disabled option */
348
+ disabled?: boolean;
299
349
  }
300
350
  /**
301
351
  * Field metadata for dynamic arrays
@@ -347,32 +397,56 @@ export interface FieldArrayOptions<T = unknown> {
347
397
  * API for managing dynamic field arrays.
348
398
  * All methods that accept values are typed to match the array item type.
349
399
  *
400
+ * Most operations return a boolean indicating success or failure.
401
+ * Operations fail (return false) when:
402
+ * - maxLength rule would be exceeded (append, prepend, insert)
403
+ * - minLength rule would be violated (remove, removeAll, removeMany)
404
+ * - Index is out of bounds (remove, update, swap, move)
405
+ *
350
406
  * @template TItem - The type of items in the array (inferred from field path)
351
407
  *
352
408
  * @example
353
409
  * interface Address { street: string; city: string }
354
410
  * const addresses = fields('addresses') // FieldArray<Address>
355
411
  * addresses.append({ street: '123 Main', city: 'NYC' }) // Typed!
412
+ *
413
+ * @example Check if operation succeeded
414
+ * const success = addresses.append({ street: '', city: '' })
415
+ * if (!success) {
416
+ * // Operation was rejected (e.g., maxLength exceeded)
417
+ * showNotification('Cannot add more addresses')
418
+ * }
356
419
  */
357
420
  export interface FieldArray<TItem = unknown> {
358
421
  /** Current field items with metadata */
359
422
  value: FieldArrayItem[];
360
- /** Append item(s) to end of array */
361
- append: (value: TItem | TItem[], options?: FieldArrayFocusOptions) => void;
362
- /** Prepend item(s) to beginning of array */
363
- prepend: (value: TItem | TItem[], options?: FieldArrayFocusOptions) => void;
364
- /** Remove item at index */
365
- remove: (index: number) => void;
366
- /** Insert item(s) at index */
367
- insert: (index: number, value: TItem | TItem[], options?: FieldArrayFocusOptions) => void;
368
- /** Swap two items */
369
- swap: (indexA: number, indexB: number) => void;
370
- /** Move item from one index to another */
371
- move: (from: number, to: number) => void;
372
- /** Update item at index (preserves key/identity) */
373
- update: (index: number, value: TItem) => void;
374
- /** Replace all items with new values */
375
- replace: (values: TItem[]) => void;
423
+ /** Append item(s) to end of array. Returns false if maxLength exceeded. */
424
+ append: (value: TItem | TItem[], options?: FieldArrayFocusOptions) => boolean;
425
+ /** Prepend item(s) to beginning of array. Returns false if maxLength exceeded. */
426
+ prepend: (value: TItem | TItem[], options?: FieldArrayFocusOptions) => boolean;
427
+ /** Remove item at index. Returns false if minLength violated or index out of bounds. */
428
+ remove: (index: number) => boolean;
429
+ /**
430
+ * Remove all items from the array.
431
+ * Returns false if minLength > 0.
432
+ */
433
+ removeAll: () => boolean;
434
+ /**
435
+ * Remove multiple items by indices (handles any order, removes from highest to lowest).
436
+ * Returns false if minLength would be violated.
437
+ * @param indices - Array of indices to remove
438
+ */
439
+ removeMany: (indices: number[]) => boolean;
440
+ /** Insert item(s) at index. Returns false if maxLength exceeded. */
441
+ insert: (index: number, value: TItem | TItem[], options?: FieldArrayFocusOptions) => boolean;
442
+ /** Swap two items. Returns false if either index is out of bounds. */
443
+ swap: (indexA: number, indexB: number) => boolean;
444
+ /** Move item from one index to another. Returns false if from index is out of bounds. */
445
+ move: (from: number, to: number) => boolean;
446
+ /** Update item at index (preserves key/identity). Returns false if index out of bounds. */
447
+ update: (index: number, value: TItem) => boolean;
448
+ /** Replace all items with new values. Always succeeds (returns true). */
449
+ replace: (values: TItem[]) => boolean;
376
450
  }
377
451
  /**
378
452
  * Async default values function type
@@ -388,11 +462,65 @@ export type CriteriaMode = 'firstError' | 'all';
388
462
  export interface UseFormOptions<TSchema extends ZodType> {
389
463
  /** Zod schema for validation */
390
464
  schema: TSchema;
391
- /** Default form values (can be a sync object or async function) */
465
+ /**
466
+ * Default form values. Can be a sync object or async function.
467
+ * Async function is useful for fetching initial values from an API.
468
+ *
469
+ * @example Sync default values
470
+ * ```ts
471
+ * useForm({
472
+ * schema,
473
+ * defaultValues: { email: '', name: '' }
474
+ * })
475
+ * ```
476
+ *
477
+ * @example Async default values (API fetch)
478
+ * ```ts
479
+ * useForm({
480
+ * schema,
481
+ * defaultValues: async () => {
482
+ * const user = await api.getCurrentUser()
483
+ * return { email: user.email, name: user.name }
484
+ * },
485
+ * onDefaultValuesError: (err) => console.error('Failed to load user:', err)
486
+ * })
487
+ * // Check formState.isLoading to show loading indicator
488
+ * ```
489
+ */
392
490
  defaultValues?: Partial<InferSchema<TSchema>> | AsyncDefaultValues<InferSchema<TSchema>>;
393
- /** When to run validation */
491
+ /**
492
+ * When to run validation.
493
+ * - 'onSubmit' (default): Only validate on form submission
494
+ * - 'onBlur': Validate when field loses focus
495
+ * - 'onChange': Validate on every input change
496
+ * - 'onTouched': Validate after field touched, then on every change
497
+ *
498
+ * @example Different validation modes
499
+ * ```ts
500
+ * // Most performant - only show errors after submit attempt
501
+ * useForm({ schema, mode: 'onSubmit' })
502
+ *
503
+ * // Real-time feedback - validate as user types
504
+ * useForm({ schema, mode: 'onChange' })
505
+ *
506
+ * // Balanced - validate after first interaction
507
+ * useForm({ schema, mode: 'onTouched' })
508
+ * ```
509
+ */
394
510
  mode?: ValidationMode;
395
- /** Revalidate on change after first submit */
511
+ /**
512
+ * Validation mode after first submission.
513
+ * Useful for "validate on submit, then real-time revalidation" pattern.
514
+ *
515
+ * @example Submit first, then real-time
516
+ * ```ts
517
+ * useForm({
518
+ * schema,
519
+ * mode: 'onSubmit', // First submit validates all
520
+ * reValidateMode: 'onChange' // After submit, revalidate on change
521
+ * })
522
+ * ```
523
+ */
396
524
  reValidateMode?: ValidationMode;
397
525
  /** Remove field data when unmounted (default: false) */
398
526
  shouldUnregister?: boolean;
@@ -400,20 +528,135 @@ export interface UseFormOptions<TSchema extends ZodType> {
400
528
  onDefaultValuesError?: (error: unknown) => void;
401
529
  /** Focus first field with error on submit (default: true) */
402
530
  shouldFocusError?: boolean;
403
- /** How to collect validation errors: 'firstError' or 'all' (default: 'firstError') */
531
+ /**
532
+ * How to collect validation errors.
533
+ * - 'firstError' (default): Stop at first error per field
534
+ * - 'all': Collect all errors for each field (populates FieldError.types)
535
+ *
536
+ * @example Show all validation errors (password requirements)
537
+ * ```ts
538
+ * const schema = z.object({
539
+ * password: z.string()
540
+ * .min(8, 'At least 8 characters')
541
+ * .regex(/[A-Z]/, 'Needs uppercase letter')
542
+ * .regex(/[0-9]/, 'Needs a number')
543
+ * })
544
+ *
545
+ * useForm({ schema, criteriaMode: 'all' })
546
+ *
547
+ * // In template - display all password requirements:
548
+ * // <ul v-if="formState.errors.password?.types">
549
+ * // <li v-for="(msg, type) in formState.errors.password.types" :key="type">
550
+ * // {{ msg }}
551
+ * // </li>
552
+ * // </ul>
553
+ * ```
554
+ *
555
+ * @see isFieldError - Type guard for structured errors
556
+ * @see FieldError.types - Contains all error types when criteriaMode is 'all'
557
+ */
404
558
  criteriaMode?: CriteriaMode;
405
- /** Delay before displaying validation errors in milliseconds (default: 0 = no delay) */
559
+ /**
560
+ * Delay in milliseconds before displaying validation errors.
561
+ * Prevents error flash during fast typing.
562
+ *
563
+ * @example Delay error display by 500ms
564
+ * ```ts
565
+ * useForm({
566
+ * schema,
567
+ * mode: 'onChange',
568
+ * delayError: 500 // Wait 500ms before showing error
569
+ * })
570
+ * // If user fixes error within 500ms, error never appears
571
+ * ```
572
+ */
406
573
  delayError?: number;
407
574
  /**
408
575
  * External values to sync to form. Changes update formData without marking dirty.
409
576
  * Useful for server-fetched data or parent component state.
577
+ *
578
+ * @example Sync with parent component state
579
+ * ```ts
580
+ * const props = defineProps<{ userData: UserData }>()
581
+ *
582
+ * useForm({
583
+ * schema,
584
+ * values: computed(() => props.userData) // Reactive sync
585
+ * })
586
+ * // When props.userData changes, form updates without becoming dirty
587
+ * ```
588
+ *
589
+ * @example Sync with API polling
590
+ * ```ts
591
+ * const { data: serverData } = useQuery('user', fetchUser)
592
+ *
593
+ * useForm({
594
+ * schema,
595
+ * values: serverData // Ref from useQuery
596
+ * })
597
+ * ```
410
598
  */
411
599
  values?: MaybeRef<Partial<InferSchema<TSchema>>>;
412
600
  /**
413
601
  * External/server errors to merge with validation errors.
414
- * Useful for server-side validation errors.
602
+ * These take precedence over client-side validation errors.
603
+ *
604
+ * @example Display server validation errors
605
+ * ```ts
606
+ * const serverErrors = ref({})
607
+ *
608
+ * const { handleSubmit } = useForm({
609
+ * schema,
610
+ * errors: serverErrors
611
+ * })
612
+ *
613
+ * const onSubmit = async (data) => {
614
+ * try {
615
+ * await api.submit(data)
616
+ * } catch (err) {
617
+ * if (err.validationErrors) {
618
+ * serverErrors.value = err.validationErrors
619
+ * // e.g., { email: 'Email already registered' }
620
+ * }
621
+ * }
622
+ * }
623
+ * ```
415
624
  */
416
625
  errors?: MaybeRef<Partial<FieldErrors<InferSchema<TSchema>>>>;
626
+ /**
627
+ * Disable the entire form. When true:
628
+ * - All registered fields receive `disabled` attribute
629
+ * - Form submission is prevented
630
+ * - Can be reactive (MaybeRef) to toggle dynamically
631
+ *
632
+ * @example Disable form during submission
633
+ * ```ts
634
+ * const isSubmitting = ref(false)
635
+ *
636
+ * useForm({
637
+ * schema,
638
+ * disabled: isSubmitting
639
+ * })
640
+ * ```
641
+ */
642
+ disabled?: MaybeRef<boolean>;
643
+ /**
644
+ * Enable browser's native validation API.
645
+ * When true:
646
+ * - Calls setCustomValidity() on inputs with error messages
647
+ * - Enables :valid/:invalid CSS pseudo-selectors
648
+ * - Shows native browser validation tooltips
649
+ *
650
+ * @example
651
+ * ```ts
652
+ * useForm({ schema, shouldUseNativeValidation: true })
653
+ *
654
+ * // CSS styling:
655
+ * // input:invalid { border-color: red; }
656
+ * // input:valid { border-color: green; }
657
+ * ```
658
+ */
659
+ shouldUseNativeValidation?: boolean;
417
660
  }
418
661
  /**
419
662
  * Return value from useForm composable.
@@ -454,7 +697,7 @@ export interface UseFormReturn<TSchema extends ZodType> {
454
697
  * Manage dynamic field arrays.
455
698
  * Returns a typed API for adding, removing, and reordering array items.
456
699
  *
457
- * @param name - Array field path
700
+ * @param name - Array field path (must be an array field in the schema)
458
701
  * @param options - Optional configuration including validation rules
459
702
  * @returns Typed FieldArray API
460
703
  *
@@ -462,7 +705,7 @@ export interface UseFormReturn<TSchema extends ZodType> {
462
705
  * const addresses = fields('addresses')
463
706
  * addresses.append({ street: '', city: '' }) // Typed to Address
464
707
  */
465
- fields: <TPath extends Path<InferSchema<TSchema>>>(name: TPath, options?: FieldArrayOptions<ArrayElement<PathValue<InferSchema<TSchema>, TPath>>>) => FieldArray<ArrayElement<PathValue<InferSchema<TSchema>, TPath>>>;
708
+ fields: <TPath extends ArrayPath<InferSchema<TSchema>>>(name: TPath, options?: FieldArrayOptions<ArrayElement<PathValue<InferSchema<TSchema>, TPath>>>) => FieldArray<ArrayElement<PathValue<InferSchema<TSchema>, TPath>>>;
466
709
  /**
467
710
  * Set field value programmatically
468
711
  * @param name - Field path
@@ -470,12 +713,6 @@ export interface UseFormReturn<TSchema extends ZodType> {
470
713
  * @param options - Options for validation/dirty/touched behavior
471
714
  */
472
715
  setValue: <TPath extends Path<InferSchema<TSchema>>>(name: TPath, value: PathValue<InferSchema<TSchema>, TPath>, options?: SetValueOptions) => void;
473
- /**
474
- * Get field value
475
- * @param name - Field path
476
- * @returns The field value (typed) or undefined if not set
477
- */
478
- getValue: <TPath extends Path<InferSchema<TSchema>>>(name: TPath) => PathValue<InferSchema<TSchema>, TPath> | undefined;
479
716
  /**
480
717
  * Reset form to default values
481
718
  * @param values - Optional new default values
@@ -515,6 +752,58 @@ export interface UseFormReturn<TSchema extends ZodType> {
515
752
  * @param error - Error option with message
516
753
  */
517
754
  setError: <TPath extends Path<InferSchema<TSchema>>>(name: TPath | 'root' | `root.${string}`, error: ErrorOption) => void;
755
+ /**
756
+ * Set multiple errors at once. Useful for server-side validation errors
757
+ * or bulk error handling scenarios.
758
+ *
759
+ * @param errors - Record of field paths to error messages or ErrorOption objects
760
+ * @param options - Optional configuration for merge behavior
761
+ *
762
+ * @example
763
+ * // Simple string errors
764
+ * setErrors({
765
+ * email: 'Email already exists',
766
+ * 'user.name': 'Name is too short'
767
+ * })
768
+ *
769
+ * @example
770
+ * // Replace all errors
771
+ * setErrors({ email: 'New error' }, { shouldReplace: true })
772
+ */
773
+ setErrors: <TPath extends Path<InferSchema<TSchema>>>(errors: Partial<Record<TPath | 'root' | `root.${string}`, string | ErrorOption>>, options?: SetErrorsOptions) => void;
774
+ /**
775
+ * Check if the form or a specific field has validation errors
776
+ *
777
+ * @param fieldPath - Optional field path to check. If omitted, checks entire form.
778
+ * @returns true if errors exist, false otherwise
779
+ *
780
+ * @example
781
+ * if (hasErrors()) {
782
+ * console.log('Form has validation errors')
783
+ * }
784
+ *
785
+ * @example
786
+ * if (hasErrors('email')) {
787
+ * focusField('email')
788
+ * }
789
+ */
790
+ hasErrors: <TPath extends Path<InferSchema<TSchema>>>(fieldPath?: TPath | 'root' | `root.${string}`) => boolean;
791
+ /**
792
+ * Get validation errors for the form or a specific field
793
+ *
794
+ * @overload Get all form errors
795
+ * @overload Get error for a specific field
796
+ *
797
+ * @example
798
+ * const allErrors = getErrors()
799
+ *
800
+ * @example
801
+ * const emailError = getErrors('email')
802
+ */
803
+ getErrors: {
804
+ (): FieldErrors<InferSchema<TSchema>>;
805
+ <TPath extends Path<InferSchema<TSchema>>>(fieldPath: TPath | 'root' | `root.${string}`): FieldErrorValue | undefined;
806
+ };
518
807
  /**
519
808
  * Get all form values, a single value, or multiple values
520
809
  * @overload Get all form values
@@ -0,0 +1,55 @@
1
+ import { ZodType } from 'zod';
2
+ export declare const __DEV__: boolean;
3
+ /**
4
+ * Warn once per unique message (prevents spam on re-renders)
5
+ */
6
+ export declare function warnOnce(message: string, key?: string): void;
7
+ /**
8
+ * Warn every time (for errors that should always be shown)
9
+ */
10
+ export declare function warn(message: string): void;
11
+ /**
12
+ * Clear warning cache (useful for testing)
13
+ */
14
+ export declare function clearWarningCache(): void;
15
+ /**
16
+ * Validate a dot-notation path string for common syntax errors
17
+ * @returns Error message or null if valid
18
+ */
19
+ export declare function validatePathSyntax(path: string): string | null;
20
+ /**
21
+ * Check if a path exists in a Zod schema
22
+ * This is a runtime check to validate paths against the schema structure
23
+ */
24
+ export declare function validatePathAgainstSchema(schema: ZodType, path: string): {
25
+ valid: boolean;
26
+ reason?: string;
27
+ availableFields?: string[];
28
+ };
29
+ /**
30
+ * Check if a path points to an array field in the schema
31
+ */
32
+ export declare function isArrayFieldInSchema(schema: ZodType, path: string): boolean | null;
33
+ /**
34
+ * Warn about registering an invalid path with fix suggestion
35
+ */
36
+ export declare function warnInvalidPath(fnName: string, path: string, reason: string): void;
37
+ /**
38
+ * Warn about path not in schema with suggestions
39
+ */
40
+ export declare function warnPathNotInSchema(fnName: string, path: string, availableFields?: string[]): void;
41
+ /**
42
+ * Warn about calling fields() on non-array path
43
+ */
44
+ export declare function warnFieldsOnNonArray(path: string): void;
45
+ /**
46
+ * Warn about silent field array operation failures
47
+ */
48
+ export declare function warnArrayOperationRejected(operation: string, path: string, reason: 'maxLength' | 'minLength', details?: {
49
+ current: number;
50
+ limit: number;
51
+ }): void;
52
+ /**
53
+ * Warn about array operation with out of bounds index
54
+ */
55
+ export declare function warnArrayIndexOutOfBounds(operation: string, path: string, index: number, length: number): void;