@vuehookform/core 0.4.1 → 0.4.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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 vuehookform
3
+ Copyright (c) 2026 vuehookform
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -121,12 +121,52 @@ const { value, ...bindings } = register('field', { controlled: true })
121
121
 
122
122
  ### Common Mistakes
123
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 |
124
+ | Wrong | Right | Why |
125
+ | ------------------------------------ | ----------------------------------------- | -------------------------------------------- |
126
+ | `items[0].name` | `items.0.name` | Always use dot notation for paths |
127
+ | `:key="index"` | `:key="field.key"` | Index can change during reordering |
128
+ | `formState.errors` | `formState.value.errors` | formState is a Ref, must access `.value` |
129
+ | `v-model` + `register()` | Either one, not both | Causes double binding conflict |
130
+ | `const state = getFieldState('x')` | `formState.value.errors.x` | getFieldState returns snapshot, not reactive |
131
+ | `<CustomInput v-bind="register()"/>` | Use `controlled: true` or `useController` | Custom components need controlled mode |
132
+
133
+ #### ⚠️ Critical: `getFieldState()` is NOT Reactive
134
+
135
+ **Problem:** Calling `getFieldState()` once returns a snapshot that never updates.
136
+
137
+ ```vue
138
+ <!-- ❌ WRONG - Error will persist even after fixing the input -->
139
+ <script setup>
140
+ const emailState = getFieldState('email')
141
+ </script>
142
+ <template>
143
+ <span v-if="emailState.error">{{ emailState.error }}</span>
144
+ </template>
145
+ ```
146
+
147
+ **Solutions:**
148
+
149
+ ```vue
150
+ <!-- ✅ Option 1: Use formState (always reactive) -->
151
+ <span v-if="formState.value.errors.email">{{ formState.value.errors.email }}</span>
152
+
153
+ <!-- ✅ Option 2: Use computed for specific field -->
154
+ <script setup>
155
+ const emailError = computed(() => formState.value.errors.email)
156
+ </script>
157
+ <template>
158
+ <span v-if="emailError">{{ emailError }}</span>
159
+ </template>
160
+
161
+ <!-- ✅ Option 3: Use useController for reusable components -->
162
+ <script setup>
163
+ const { fieldState } = useController({ name: 'email', control })
164
+ // fieldState is a ComputedRef that updates automatically
165
+ </script>
166
+ <template>
167
+ <span v-if="fieldState.error">{{ fieldState.error }}</span>
168
+ </template>
169
+ ```
130
170
 
131
171
  ## Contributing
132
172
 
@@ -1,22 +1,48 @@
1
1
  import { Ref } from 'vue';
2
2
  import { RegisterOptions } from '../types';
3
+ /**
4
+ * Extract the actual HTMLInputElement from a ref value.
5
+ * Handles both native elements and Vue component instances (PrimeVue, Vuetify, etc.)
6
+ *
7
+ * Vue component libraries typically expose:
8
+ * - $el: The root DOM element of the component
9
+ * - Some components wrap inputs in divs, so we may need to query for the input
10
+ *
11
+ * @param refValue - The value from fieldRef.value (HTMLInputElement, Component, or null)
12
+ * @returns The underlying HTMLInputElement, or null if not found
13
+ */
14
+ export declare function getInputElement(refValue: unknown): HTMLInputElement | null;
15
+ /**
16
+ * Get a focusable element from a ref value.
17
+ * Works with both native elements and Vue component instances.
18
+ *
19
+ * @param refValue - The value from fieldRef.value
20
+ * @returns The focusable HTMLElement, or null if not found
21
+ */
22
+ export declare function getFocusableElement(refValue: unknown): HTMLElement | null;
3
23
  /**
4
24
  * Sync values from uncontrolled DOM inputs to form data
5
25
  *
6
26
  * This reads the current DOM state from uncontrolled inputs and updates
7
27
  * the formData object. Used before form submission and when getting values.
8
28
  *
29
+ * Handles type coercion for:
30
+ * - checkbox: returns boolean (el.checked)
31
+ * - number/range: returns number (el.valueAsNumber)
32
+ * - all other types: returns string (el.value)
33
+ *
9
34
  * @param fieldRefs - Map of field names to their DOM element refs
10
35
  * @param fieldOptions - Map of field names to their registration options
11
36
  * @param formData - The reactive form data object to update
12
37
  */
13
- export declare function syncUncontrolledInputs(fieldRefs: Map<string, Ref<HTMLInputElement | null>>, fieldOptions: Map<string, RegisterOptions>, formData: Record<string, unknown>): void;
38
+ export declare function syncUncontrolledInputs(fieldRefs: Map<string, Ref<unknown>>, fieldOptions: Map<string, RegisterOptions>, formData: Record<string, unknown>): void;
14
39
  /**
15
40
  * Update a single DOM element with a new value
16
41
  *
17
42
  * Handles both checkbox and text inputs appropriately.
43
+ * Supports both native elements and Vue component instances.
18
44
  *
19
- * @param el - The DOM input element to update
45
+ * @param refValue - The ref value (HTMLInputElement, Vue component, or null)
20
46
  * @param value - The value to set
21
47
  */
22
- export declare function updateDomElement(el: HTMLInputElement, value: unknown): void;
48
+ export declare function updateDomElement(refValue: unknown, value: unknown): void;
@@ -1,42 +1,34 @@
1
- import { Ref, ShallowRef } from 'vue';
1
+ import { ShallowRef } from 'vue';
2
2
  /**
3
3
  * Mark a field as dirty (value has changed from default).
4
4
  * Optimized to skip clone if already dirty.
5
- * Maintains O(1) dirty field count for performance.
6
5
  *
7
6
  * @param dirtyFields - The reactive dirty fields record
8
- * @param dirtyFieldCount - Counter for O(1) isDirty checks
9
7
  * @param fieldName - Name of the field to mark as dirty
10
8
  */
11
- export declare function markFieldDirty(dirtyFields: ShallowRef<Record<string, boolean>>, dirtyFieldCount: Ref<number>, fieldName: string): void;
9
+ export declare function markFieldDirty(dirtyFields: ShallowRef<Record<string, boolean>>, fieldName: string): void;
12
10
  /**
13
11
  * Mark a field as touched (user has interacted with it).
14
12
  * Optimized to skip clone if already touched.
15
- * Maintains O(1) touched field count for performance.
16
13
  *
17
14
  * @param touchedFields - The reactive touched fields record
18
- * @param touchedFieldCount - Counter for O(1) touched checks
19
15
  * @param fieldName - Name of the field to mark as touched
20
16
  */
21
- export declare function markFieldTouched(touchedFields: ShallowRef<Record<string, boolean>>, touchedFieldCount: Ref<number>, fieldName: string): void;
17
+ export declare function markFieldTouched(touchedFields: ShallowRef<Record<string, boolean>>, fieldName: string): void;
22
18
  /**
23
19
  * Clear dirty state for a field.
24
- * Maintains O(1) dirty field count for performance.
25
20
  *
26
21
  * @param dirtyFields - The reactive dirty fields record
27
- * @param dirtyFieldCount - Counter for O(1) isDirty checks
28
22
  * @param fieldName - Name of the field to clear
29
23
  */
30
- export declare function clearFieldDirty(dirtyFields: ShallowRef<Record<string, boolean>>, dirtyFieldCount: Ref<number>, fieldName: string): void;
24
+ export declare function clearFieldDirty(dirtyFields: ShallowRef<Record<string, boolean>>, fieldName: string): void;
31
25
  /**
32
26
  * Clear touched state for a field.
33
- * Maintains O(1) touched field count for performance.
34
27
  *
35
28
  * @param touchedFields - The reactive touched fields record
36
- * @param touchedFieldCount - Counter for O(1) touched checks
37
29
  * @param fieldName - Name of the field to clear
38
30
  */
39
- export declare function clearFieldTouched(touchedFields: ShallowRef<Record<string, boolean>>, touchedFieldCount: Ref<number>, fieldName: string): void;
31
+ export declare function clearFieldTouched(touchedFields: ShallowRef<Record<string, boolean>>, fieldName: string): void;
40
32
  /**
41
33
  * Clear errors for a field and its nested paths.
42
34
  * Optimized with early exit if nothing to delete.
@@ -45,3 +37,17 @@ export declare function clearFieldTouched(touchedFields: ShallowRef<Record<strin
45
37
  * @param fieldName - Name of the field (clears exact match and all nested paths)
46
38
  */
47
39
  export declare function clearFieldErrors<T>(errors: ShallowRef<Record<string, T>>, fieldName: string): void;
40
+ /**
41
+ * Update field dirty state based on value comparison with default.
42
+ * Field is dirty only if current value differs from default value.
43
+ *
44
+ * Uses lazy hash computation - default hashes are computed on first access
45
+ * and cached for subsequent comparisons.
46
+ *
47
+ * @param dirtyFields - The reactive dirty fields record
48
+ * @param defaultValues - The original default values
49
+ * @param defaultValueHashes - Cache of hashed default values
50
+ * @param fieldName - Name of the field to check
51
+ * @param currentValue - The current value to compare against default
52
+ */
53
+ export declare function updateFieldDirtyState(dirtyFields: ShallowRef<Record<string, boolean>>, defaultValues: Record<string, unknown>, defaultValueHashes: Map<string, string>, fieldName: string, currentValue: unknown): void;
@@ -2,57 +2,114 @@ import { Ref, ShallowRef } from 'vue';
2
2
  import { ZodType } from 'zod';
3
3
  import { UseFormOptions, FieldErrors, FieldErrorValue, InferSchema, RegisterOptions, FieldArrayItem, FieldArrayRules } from '../types';
4
4
  /**
5
- * Internal state for field array management
5
+ * Internal state for field array management.
6
+ * Tracks items, their indices, and array-level validation rules.
7
+ *
8
+ * @internal This interface is used internally by useFieldArray and should not be
9
+ * directly instantiated by consumers.
6
10
  */
7
11
  export interface FieldArrayState {
12
+ /** Reactive list of field array items with stable keys for Vue reconciliation */
8
13
  items: Ref<FieldArrayItem[]>;
14
+ /** Raw array values (kept in sync with formData) */
9
15
  values: unknown[];
16
+ /** O(1) lookup cache mapping item keys to their current indices */
10
17
  indexCache: Map<string, number>;
18
+ /** Optional validation rules for the array itself (minLength, maxLength, custom) */
11
19
  rules?: FieldArrayRules;
12
20
  }
13
21
  /**
14
- * Cached event handlers for a field to prevent recreation on every render
22
+ * Cached event handlers for a field.
23
+ * These are created once per field registration and reused to prevent
24
+ * unnecessary re-renders and closure recreation.
25
+ *
26
+ * @internal This interface is used internally by useFieldRegistration and should not be
27
+ * directly instantiated by consumers.
15
28
  */
16
29
  export interface FieldHandlers {
30
+ /** Handler for input events, triggers validation based on mode */
17
31
  onInput: (e: Event) => Promise<void>;
18
- onBlur: (e: Event) => Promise<void>;
32
+ /** Handler for blur events, marks field as touched and may trigger validation */
33
+ onBlur: () => Promise<void>;
34
+ /** Ref callback to capture the DOM element reference */
19
35
  refCallback: (el: unknown) => void;
20
36
  }
21
37
  /**
22
- * Shared form context containing all reactive state
23
- * This is passed to sub-modules via dependency injection
38
+ * Shared form context containing all reactive state.
39
+ * This is the central state container passed to sub-modules via dependency injection.
40
+ *
41
+ * The context is organized into several categories:
42
+ * - **Form Data**: Raw form values and their defaults
43
+ * - **Form State**: Validation errors, touched/dirty tracking, submission state
44
+ * - **Field Tracking**: DOM refs, registration options, field arrays
45
+ * - **Validation**: Caching, debouncing, and async validation coordination
46
+ * - **Configuration**: Form options and disabled state
47
+ *
48
+ * @typeParam FormValues - The inferred type from the Zod schema
49
+ *
50
+ * @internal This interface is used internally by useForm and its sub-modules.
51
+ * Consumers should use the public API returned by useForm() instead.
24
52
  */
25
53
  export interface FormContext<FormValues> {
54
+ /** Reactive form data object containing current field values */
26
55
  formData: Record<string, unknown>;
56
+ /** Original default values used for reset() and dirty detection */
27
57
  defaultValues: Record<string, unknown>;
58
+ /** Current validation errors keyed by field path */
28
59
  errors: ShallowRef<FieldErrors<FormValues>>;
60
+ /** Record of field paths that have been touched (blurred) */
29
61
  touchedFields: ShallowRef<Record<string, boolean>>;
62
+ /** Record of field paths that differ from default values */
30
63
  dirtyFields: ShallowRef<Record<string, boolean>>;
64
+ /** Whether the form is currently being submitted */
31
65
  isSubmitting: Ref<boolean>;
66
+ /** Whether async default values are being loaded */
32
67
  isLoading: Ref<boolean>;
68
+ /** Number of times the form has been submitted */
33
69
  submitCount: Ref<number>;
70
+ /** Error that occurred while loading async default values */
34
71
  defaultValuesError: Ref<unknown>;
72
+ /** Whether the last submission completed successfully */
35
73
  isSubmitSuccessful: Ref<boolean>;
74
+ /** Set of field paths currently being validated (for isValidating state) */
36
75
  validatingFields: ShallowRef<Set<string>>;
76
+ /** External errors (e.g., from server) merged with validation errors */
37
77
  externalErrors: ShallowRef<FieldErrors<FormValues>>;
78
+ /** Timers for delayed error display per field */
38
79
  errorDelayTimers: Map<string, ReturnType<typeof setTimeout>>;
80
+ /** Pending errors waiting for delay timer to complete */
39
81
  pendingErrors: Map<string, FieldErrorValue>;
82
+ /** DOM element refs for registered uncontrolled fields */
40
83
  fieldRefs: Map<string, Ref<HTMLInputElement | null>>;
84
+ /** Registration options per field path */
41
85
  fieldOptions: Map<string, RegisterOptions>;
86
+ /** Field array state for array fields managed by fields() */
42
87
  fieldArrays: Map<string, FieldArrayState>;
88
+ /** Cached event handlers to prevent recreation on re-render */
43
89
  fieldHandlers: Map<string, FieldHandlers>;
90
+ /** Debounce timers for custom async validation per field */
44
91
  debounceTimers: Map<string, ReturnType<typeof setTimeout>>;
92
+ /** Request IDs for canceling stale async validation results */
45
93
  validationRequestIds: Map<string, number>;
94
+ /** Generation counter incremented on reset to cancel in-flight validations */
46
95
  resetGeneration: Ref<number>;
47
- isDisabled: Ref<boolean>;
48
- dirtyFieldCount: Ref<number>;
49
- touchedFieldCount: Ref<number>;
96
+ /** Cache of validation results keyed by field path and value hash */
50
97
  validationCache: Map<string, {
51
98
  hash: string;
52
99
  isValid: boolean;
53
100
  }>;
101
+ /** Debounce timers for schema validation per field */
54
102
  schemaValidationTimers: Map<string, ReturnType<typeof setTimeout>>;
103
+ /** Set of field paths with persistent errors (survive validation cycles) */
104
+ persistentErrorFields: Set<string>;
105
+ /** Hashed default values for value-comparison dirty detection */
106
+ defaultValueHashes: Map<string, string>;
107
+ /** Whether the entire form is disabled */
108
+ isDisabled: Ref<boolean>;
109
+ /** Original options passed to useForm() */
55
110
  options: UseFormOptions<ZodType>;
111
+ /** Cleanup function to stop all watchers and prevent memory leaks */
112
+ cleanup: () => void;
56
113
  }
57
114
  /**
58
115
  * Create a new form context with all reactive state initialized
package/dist/index.d.ts CHANGED
@@ -20,4 +20,5 @@ 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, SetErrorsOptions, FieldArray, FieldArrayItem, InferSchema, FormValues, FormPath, Path, PathValue, ArrayElement, ArrayPath, FieldPath, ValidationMode, SetFocusOptions, ResetOptions, ResetFieldOptions, AsyncDefaultValues, } from './types';
23
+ export type { UseFormOptions, UseFormReturn, RegisterOptions, RegisterReturn, FormState, FieldState, FieldErrors, FieldError, FieldErrorValue, ErrorOption, SetErrorsOptions, FieldArray, FieldArrayItem, FieldArrayOptions, FieldArrayRules, FieldArrayFocusOptions, InferSchema, FormValues, FormPath, Path, PathValue, ArrayElement, ArrayPath, FieldPath, ValidationMode, SetFocusOptions, ResetOptions, ResetFieldOptions, AsyncDefaultValues, TriggerOptions, SetValueOptions, UnregisterOptions, CriteriaMode, } from './types';
24
+ export { get, set, unset, generateId, clearPathCache } from './utils/paths';
package/dist/types.d.ts CHANGED
@@ -7,7 +7,7 @@ export type ValidationMode = 'onSubmit' | 'onBlur' | 'onChange' | 'onTouched';
7
7
  /**
8
8
  * Extract the inferred type from a Zod schema
9
9
  */
10
- export type InferSchema<T extends ZodType> = z.infer<T>;
10
+ export type InferSchema<TSchema extends ZodType> = z.infer<TSchema>;
11
11
  /**
12
12
  * Alias for InferSchema - extracts form value type from schema.
13
13
  * Use this when you need the actual form data type.
@@ -198,7 +198,7 @@ export interface FieldState {
198
198
  /** Whether field has a validation error */
199
199
  invalid: boolean;
200
200
  /** The error (string for backward compatibility, or FieldError for structured errors) */
201
- error?: string | FieldError;
201
+ error?: FieldErrorValue;
202
202
  }
203
203
  /**
204
204
  * Error option for setError()
@@ -208,6 +208,11 @@ export interface ErrorOption {
208
208
  type?: string;
209
209
  /** Error message to display */
210
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;
211
216
  }
212
217
  /**
213
218
  * Options for setFocus()
@@ -241,6 +246,16 @@ export interface ResetFieldOptions<TValue = unknown> {
241
246
  /** New default value (updates stored default) - typed to match field */
242
247
  defaultValue?: TValue;
243
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
+ }
244
259
  /**
245
260
  * Options for unregister()
246
261
  */
@@ -341,7 +356,7 @@ export interface RegisterReturn<TValue = unknown> {
341
356
  /** Input handler (fires on every keystroke) */
342
357
  onInput: (e: Event) => void;
343
358
  /** Blur handler */
344
- onBlur: (e: Event) => void;
359
+ onBlur: () => void;
345
360
  /** Current value (for controlled mode) - only present when controlled: true */
346
361
  value?: Ref<TValue>;
347
362
  /** Disabled state from form-level disabled option */
@@ -403,6 +418,10 @@ export interface FieldArrayOptions<T = unknown> {
403
418
  * - minLength rule would be violated (remove, removeAll, removeMany)
404
419
  * - Index is out of bounds (remove, update, swap, move)
405
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
+ *
406
425
  * @template TItem - The type of items in the array (inferred from field path)
407
426
  *
408
427
  * @example
@@ -418,7 +437,7 @@ export interface FieldArrayOptions<T = unknown> {
418
437
  * }
419
438
  */
420
439
  export interface FieldArray<TItem = unknown> {
421
- /** Current field items with metadata */
440
+ /** Current field items with metadata. Reactive - updates when array methods are called. */
422
441
  value: FieldArrayItem[];
423
442
  /** Append item(s) to end of array. Returns false if maxLength exceeded. */
424
443
  append: (value: TItem | TItem[], options?: FieldArrayFocusOptions) => boolean;
@@ -839,14 +858,20 @@ export interface UseFormReturn<TSchema extends ZodType> {
839
858
  /**
840
859
  * Manually trigger validation for specific fields or entire form
841
860
  * @param name - Optional field path or array of paths
861
+ * @param options - Optional trigger options (e.g., markAsSubmitted)
842
862
  */
843
- trigger: <TPath extends Path<InferSchema<TSchema>>>(name?: TPath | TPath[]) => Promise<boolean>;
863
+ trigger: <TPath extends Path<InferSchema<TSchema>>>(name?: TPath | TPath[], options?: TriggerOptions) => Promise<boolean>;
844
864
  /**
845
865
  * Programmatically focus a field
846
866
  * @param name - Field path
847
867
  * @param options - Focus options
848
868
  */
849
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'>;
850
875
  }
851
876
  /**
852
877
  * Type guard to check if an error value is a structured FieldError object.
package/dist/useForm.d.ts CHANGED
@@ -1,5 +1,11 @@
1
1
  import { ZodType } from 'zod';
2
2
  import { UseFormOptions, UseFormReturn } from './types';
3
+ /**
4
+ * Set the internal flag to suppress getFieldState warnings.
5
+ * Used by useController before calling getFieldState inside computed().
6
+ * @internal
7
+ */
8
+ export declare function setCalledFromController(value: boolean): void;
3
9
  /**
4
10
  * Main form management composable
5
11
  *
@@ -8,12 +8,12 @@
8
8
  * - Arrays (recursive clone)
9
9
  * - Date objects (new Date instance)
10
10
  * - null/undefined (pass-through)
11
+ * - Circular references (recreates the circular structure in the clone)
11
12
  *
12
13
  * Does NOT handle (by design, not needed for form data):
13
- * - Circular references
14
14
  * - Map/Set/WeakMap/WeakSet
15
15
  * - Functions
16
16
  * - Symbols
17
17
  * - Class instances (cloned as plain objects)
18
18
  */
19
- export declare function deepClone<T>(obj: T): T;
19
+ export declare function deepClone<T>(obj: T, seen?: Map<object, unknown>): T;
@@ -2,5 +2,8 @@
2
2
  * Fast value hashing for validation cache.
3
3
  * Uses JSON.stringify for objects/arrays, direct conversion for primitives.
4
4
  * Returns a string that can be compared for equality.
5
+ *
6
+ * Handles circular references by assigning stable IDs via WeakMap,
7
+ * ensuring the same object always produces the same hash.
5
8
  */
6
9
  export declare function hashValue(value: unknown): string;
@@ -0,0 +1,22 @@
1
+ import { ValidationMode } from '../types';
2
+ /**
3
+ * Determines if validation should occur on change event.
4
+ * Used by useController and register for consistent mode handling.
5
+ *
6
+ * @param mode - The form's validation mode
7
+ * @param isTouched - Whether the field has been touched
8
+ * @param reValidateMode - The form's reValidateMode (used after first submit)
9
+ * @param hasSubmitted - Whether the form has been submitted at least once (optional, for reValidateMode)
10
+ * @returns true if validation should be triggered
11
+ */
12
+ export declare function shouldValidateOnChange(mode: ValidationMode, isTouched: boolean, reValidateMode?: ValidationMode, hasSubmitted?: boolean): boolean;
13
+ /**
14
+ * Determines if validation should occur on blur event.
15
+ * Used by useController and register for consistent mode handling.
16
+ *
17
+ * @param mode - The form's validation mode
18
+ * @param hasSubmitted - Whether the form has been submitted at least once
19
+ * @param reValidateMode - The form's reValidateMode (used after first submit)
20
+ * @returns true if validation should be triggered
21
+ */
22
+ export declare function shouldValidateOnBlur(mode: ValidationMode, hasSubmitted: boolean, reValidateMode?: ValidationMode): boolean;
@@ -1,6 +1,10 @@
1
1
  /**
2
- * Clear the path cache. Useful for testing or when paths change significantly.
3
- * @internal
2
+ * Clear the path segment cache.
3
+ * Call this between SSR requests to prevent memory accumulation,
4
+ * or in tests to reset state.
5
+ *
6
+ * The cache is bounded to 256 entries, so clearing is optional
7
+ * for client-side only applications.
4
8
  */
5
9
  export declare function clearPathCache(): void;
6
10
  /**
@@ -19,7 +23,15 @@ export declare function set(obj: Record<string, unknown>, path: string, value: u
19
23
  */
20
24
  export declare function unset(obj: Record<string, unknown>, path: string): void;
21
25
  /**
22
- * Check if path exists in object
26
+ * Check if path exists in object.
27
+ * Unlike `get(obj, path) !== undefined`, this properly distinguishes between
28
+ * a missing path and a path that exists with an `undefined` value.
29
+ *
30
+ * @example
31
+ * has({ name: undefined }, 'name') // true - path exists
32
+ * has({ }, 'name') // false - path doesn't exist
33
+ * has({ user: { name: 'John' } }, 'user.name') // true
34
+ * has({ user: { name: 'John' } }, 'user.age') // false
23
35
  */
24
36
  export declare function has(obj: Record<string, unknown>, path: string): boolean;
25
37
  export declare function generateId(): string;