react-f0rm 1.1.1 → 1.3.0

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.
Files changed (61) hide show
  1. package/README.md +242 -39
  2. package/dist/devtools/index.cjs.js +1 -1
  3. package/dist/devtools/index.cjs.js.map +1 -1
  4. package/dist/devtools/index.d.ts +2 -2
  5. package/dist/devtools/index.mjs +1 -1
  6. package/dist/devtools/index.mjs.map +1 -1
  7. package/dist/errors-BKrUdpfI.cjs.js +2 -0
  8. package/dist/errors-BKrUdpfI.cjs.js.map +1 -0
  9. package/dist/errors-CrQBddrJ.mjs +2 -0
  10. package/dist/errors-CrQBddrJ.mjs.map +1 -0
  11. package/dist/form-CeKSBs31.d.ts +486 -0
  12. package/dist/index.cjs.js +1 -1
  13. package/dist/index.cjs.js.map +1 -1
  14. package/dist/index.d.ts +1097 -118
  15. package/dist/index.mjs +1 -1
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/index.umd.js +1082 -544
  18. package/dist/index.umd.js.map +1 -1
  19. package/dist/index.umd.min.js +2 -2
  20. package/dist/index.umd.min.js.map +1 -1
  21. package/dist/persist.cjs.js +2 -0
  22. package/dist/persist.cjs.js.map +1 -0
  23. package/dist/persist.d.ts +49 -0
  24. package/dist/persist.mjs +2 -0
  25. package/dist/persist.mjs.map +1 -0
  26. package/dist/resolvers/standard-schema.cjs.js +1 -1
  27. package/dist/resolvers/standard-schema.cjs.js.map +1 -1
  28. package/dist/resolvers/standard-schema.d.ts +7 -5
  29. package/dist/resolvers/standard-schema.mjs +1 -1
  30. package/dist/resolvers/standard-schema.mjs.map +1 -1
  31. package/dist/resolvers/yup.cjs.js +1 -1
  32. package/dist/resolvers/yup.cjs.js.map +1 -1
  33. package/dist/resolvers/yup.d.ts +1 -1
  34. package/dist/resolvers/yup.mjs +1 -1
  35. package/dist/resolvers/yup.mjs.map +1 -1
  36. package/dist/resolvers/zod.cjs.js +1 -1
  37. package/dist/resolvers/zod.cjs.js.map +1 -1
  38. package/dist/resolvers/zod.d.ts +1 -1
  39. package/dist/resolvers/zod.mjs +1 -1
  40. package/dist/resolvers/zod.mjs.map +1 -1
  41. package/dist/server/index.cjs.js +2 -0
  42. package/dist/server/index.cjs.js.map +1 -0
  43. package/dist/server/index.d.ts +77 -0
  44. package/dist/server/index.mjs +2 -0
  45. package/dist/server/index.mjs.map +1 -0
  46. package/dist/validate-CNtuUhmk.mjs +2 -0
  47. package/dist/validate-CNtuUhmk.mjs.map +1 -0
  48. package/dist/validate-Cl4ksNFu.cjs.js +2 -0
  49. package/dist/validate-Cl4ksNFu.cjs.js.map +1 -0
  50. package/dist/validate-nksgv1pR.d.ts +272 -0
  51. package/dist/values-Cu6awQOJ.cjs.js +2 -0
  52. package/dist/values-Cu6awQOJ.cjs.js.map +1 -0
  53. package/dist/values-DRY-a32G.mjs +2 -0
  54. package/dist/values-DRY-a32G.mjs.map +1 -0
  55. package/package.json +87 -29
  56. package/dist/form-2_tBkEXU.mjs +0 -2
  57. package/dist/form-2_tBkEXU.mjs.map +0 -1
  58. package/dist/form-BiDaJLjD.d.ts +0 -826
  59. package/dist/form-BwLNQ6WB.cjs.js +0 -2
  60. package/dist/form-BwLNQ6WB.cjs.js.map +0 -1
  61. package/dist/validate-2XUilILy.d.ts +0 -22
package/dist/index.d.ts CHANGED
@@ -1,9 +1,502 @@
1
- import { a as FieldPath, N as Name, F as Form$1, V as ValidationMode, P as PathValueOf, b as FieldError, c as Path, O as Options } from './form-BiDaJLjD.js';
2
- export { d as FieldErrorEntry, e as FieldState, f as FormValidateFn, g as FormValidateMeta, h as FormValidationError, H as HandleSubmitOptions, i as PathValue, R as ReValidateMode, j as ResetFieldOptions, k as ResetOptions, S as SetFieldOptions, l as SetFocusOptions, m as SetServerErrorsOptions, n as VALIDATION_OUTCOME, o as ValidateResult, p as ValidationOutcome, q as changeValue, r as changeValueByPath, s as clearErrors, t as createForm, u as emitChangeByPath, v as ensureValidate, w as getDirtyFields, x as getError, y as getErrorByPath, z as getErrors, A as getFieldErrors, B as getFieldErrorsByPath, C as getFieldState, D as getFirstError, E as getTouchedFields, G as getValue, I as getValueByPath, J as getValues, K as handleSubmit, L as hasErrors, M as hasTouched, Q as hasTouchedByPath, T as incrementSubmitCount, U as isDirty, W as isTouched, X as registerFieldValidateDeps, Y as removeField, Z as removeFieldByPath, _ as reset, $ as resetField, a0 as revalidateDependentsOnChange, a1 as revalidateFormOnChange, a2 as seedValueByPath, a3 as setDisabled, a4 as setError, a5 as setErrorByPath, a6 as setFocus, a7 as setInitialValues, a8 as setIsSubmitting, a9 as setServerErrors, aa as setSubmitSuccessful, ab as setTouched, ac as setTouchedByPath, ad as setValidatingByPath, ae as setValue, af as setValueByPath, ag as trigger, ah as unregisterFieldValidateDeps, ai as unsetValidatingByPath, aj as validate } from './form-BiDaJLjD.js';
3
- import { V as Validator } from './validate-2XUilILy.js';
1
+ import { a as FieldError, F as Form$1, P as Path, b as FieldPath, c as PathSegments, d as PathValueOf, N as Name, V as ValidationMode, e as FieldErrorEntry, O as Options, f as FormEvents } from './form-CeKSBs31.js';
2
+ export { g as FORM_ERROR, h as FormValidateFn, i as FormValidateMeta, j as PathValue, R as ReValidateMode, S as SetErrorOptions, k as SetFocusOptions, l as SetServerErrorsOptions, m as VALIDATION_OUTCOME, n as ValidateResult, o as ValidationOutcome, p as clearErrors, q as createForm, r as getError, s as getErrorByPath, t as getErrors, u as getFieldErrors, v as getFieldErrorsByPath, w as getFirstError, x as hasErrors, y as setError, z as setErrorByPath, A as setFocus, B as setServerErrors } from './form-CeKSBs31.js';
3
+ import { EventEmitter } from '@for-fun/event-emitter';
4
+ export { EventEmitter } from '@for-fun/event-emitter';
4
5
  import * as React from 'react';
5
6
  import { ReactNode } from 'react';
6
- import { EventEmitter } from '@for-fun/event-emitter';
7
+ import { S as SyncValidator, V as Validator } from './validate-nksgv1pR.js';
8
+ export { F as FormValidationError, T as TriggerOptions, a as ValidatorRegistration, e as ensureValidate, r as registerFieldValidateDeps, b as registerValidatorByPath, c as revalidateDependentsOnChange, d as revalidateFormOnChange, f as runFormValidate, s as setValidatingByPath, t as trigger, u as unregisterFieldValidateDeps, g as unsetValidatingByPath, v as validate } from './validate-nksgv1pR.js';
9
+
10
+ /**
11
+ * Get form values: the values Map layered over parsedValues (when a schema
12
+ * validation produced them) layered over initialValues.
13
+ *
14
+ * Merged with copy-on-write ownership tracking ({@link setOwned}): every
15
+ * distinct container on a written path is allocated once and shared by all
16
+ * paths through it, instead of re-copying the whole branch for every key.
17
+ * One owned set spans the whole merge, so containers borrowed from the
18
+ * parsedValues tree are copied before mutation exactly like initialValues
19
+ * ones. The result is a freshly merged tree per mutation, with untouched
20
+ * branches sharing references with the baseline exactly like chained
21
+ * `set` did.
22
+ *
23
+ * Memoized per form like {@link getDirtyFields}: every value write bumps a
24
+ * `version` counter ({@link bumpValuesVersion}) while reads reset it, so
25
+ * consecutive reads hand back the same reference (submit, changeValue and
26
+ * form-level validate all read the whole tree, often several times per
27
+ * interaction). Treat the result as read-only — the next read after a
28
+ * write returns a fresh tree, but between writes the cached one is shared
29
+ * with every other reader.
30
+ *
31
+ * parsedValues is the schema's complete output tree: once validation
32
+ * succeeds it replaces the initialValues baseline (fields the schema
33
+ * dropped disappear), while live edits in the values Map still win over
34
+ * both. It never affects dirty state — {@link isDirty} and
35
+ * {@link getDirtyFields} compare live edits against initialValues only,
36
+ * because parsing is not a user edit.
37
+ *
38
+ * @param form
39
+ */
40
+ declare function getValues<T extends Record<string, any> = any>(form: Form$1<T>): T;
41
+ /**
42
+ * Get field value
43
+ * @param form
44
+ * @param name
45
+ */
46
+ declare function getValue<T extends Record<string, any> = any, P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments>(form: Form$1<T>, name: P): PathValueOf<T, P>;
47
+ /**
48
+ * Get field value by path
49
+ * @param form
50
+ * @param path
51
+ */
52
+ declare function getValueByPath({ initialValues, parsedValues, values, deleted }: Form$1, path: Path): any;
53
+ /** Options accepted by {@link setValue} / {@link setValueByPath} / {@link
54
+ * changeValue} / {@link changeValueByPath}. `shouldValidate`/`shouldTouch`
55
+ * default to `false`; omitting the options object entirely keeps the plain
56
+ * set-value behavior (no validation, no touched marking, dirty stays
57
+ * derived). */
58
+ type SetFieldOptions = {
59
+ /** Run the field's registered validator (if any) after the value lands,
60
+ * same as triggering that single field. Defaults to `false`. */
61
+ shouldValidate?: boolean;
62
+ /** Mark the field as touched. Defaults to `false`. */
63
+ shouldTouch?: boolean;
64
+ /** Land the value as a commit instead of an edit: the value becomes the
65
+ * field's dirty-comparison baseline, so `getDirtyFields`/`isDirty`/
66
+ * `getFieldState().isDirty` read the field as clean, and a later write
67
+ * dirties it only by differing from the new baseline. `true` (or
68
+ * omitting the flag) keeps the default derived behavior — dirty while
69
+ * the live value differs from initialValues. */
70
+ shouldDirty?: boolean;
71
+ };
72
+ /**
73
+ * Set field value. The value may also be an updater function receiving
74
+ * the field's current value and returning the next one (TanStack Form's
75
+ * `setFieldValue` contract) — handy for increments and array transforms:
76
+ * `setValue(form, 'count', c => c + 1)`. The tradeoff: a function can
77
+ * never itself be stored as a field value through this function.
78
+ * @param form
79
+ * @param name
80
+ * @param value
81
+ * @param options
82
+ */
83
+ declare function setValue<T extends Record<string, any> = any, P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments>(form: Form$1<T>, name: P, value: PathValueOf<T, P> | ((prev: PathValueOf<T, P>) => PathValueOf<T, P>), options?: SetFieldOptions): void;
84
+ /**
85
+ * Set field value. The value may also be an updater function receiving
86
+ * the field's current value and returning the next one (TanStack Form's
87
+ * `setFieldValue` contract) — note that a function can therefore never
88
+ * itself be stored as a field value through this function.
89
+ * @param form
90
+ * @param path
91
+ * @param value
92
+ * @param options
93
+ */
94
+ declare function setValueByPath(form: Form$1, path: Path, value: any | ((prev: any) => any), options?: SetFieldOptions): void;
95
+ /**
96
+ * The write of {@link setValueByPath} minus the `'change'` emit: the
97
+ * render-time {@link useField} `initialValue` seed. The field's first
98
+ * paint (SSR included — effects never run on the server) must already
99
+ * carry the value, so the write happens during render where emitting is
100
+ * illegal; the seeding field announces it from its post-commit effect
101
+ * through {@link emitChangeByPath} instead.
102
+ *
103
+ * Everything else matches a plain write: descendant keys of the seeded
104
+ * path are pruned, the branch's tombstones and committed baselines are
105
+ * revived/dropped, and both memo caches are invalidated. Like the effect
106
+ * seed it replaces, the caller guards it to paths with no value yet.
107
+ */
108
+ declare function seedValueByPath(form: Form$1, path: Path, value: any): void;
109
+ /** Announce a {@link seedValueByPath} that happened during render: the
110
+ * payload-carrying `'change'` emit {@link setValueByPath} would have
111
+ * fired, split out so it can run post-commit where emitting is safe.
112
+ * Subscribers that rendered after the seed re-read an unchanged snapshot
113
+ * and bail; subscribers from earlier commits resync. */
114
+ declare function emitChangeByPath({ emitter }: Form$1, path: Path): void;
115
+ /** Per-form registry of mounted fields' validation-mode overrides: path
116
+ * key -> the field's `mode` option (undefined = follow {@link Form.mode})
117
+ * plus an owner token so competing mounts at one path clean up safely.
118
+ * Presence of an entry is the "a field is mounted at this path" signal
119
+ * that routes {@link changeValueByPath} into the gated user-change
120
+ * pipeline ({@link userChangeByPath}). Held in a WeakMap so the Form
121
+ * shape carries only plain state fields. */
122
+ /** Snapshot of one field's aggregated state, as {@link getFieldState}
123
+ * returns it. `errors` is the stored array shared with the form — treat it
124
+ * as read-only, like every {@link getFieldErrors} result. */
125
+ type FieldState<T = any> = {
126
+ value: T;
127
+ error: FieldError | undefined;
128
+ errors: FieldError[];
129
+ isDirty: boolean;
130
+ isTouched: boolean;
131
+ isValidating: boolean;
132
+ };
133
+ /**
134
+ * Get one field's aggregated state: the layered value ({@link getValue}),
135
+ * the first error ({@link getError}) and every error ({@link
136
+ * getFieldErrors}), dirtiness, the touched flag, and whether a validator
137
+ * is in flight. `isDirty` applies the same per-field rule as {@link
138
+ * getDirtyFields}: a live value exists and differs from initialValues at
139
+ * that path (parsedValues never counts — parsing is not an edit).
140
+ *
141
+ * @param form
142
+ * @param name
143
+ */
144
+ declare function getFieldState<T extends Record<string, any> = any, P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments>(form: Form$1<T>, name: P): FieldState<PathValueOf<T, P>>;
145
+ /**
146
+ * Remove a field: by default its live value drops out of reads and
147
+ * `getValues()` (the path is tombstoned, so it never falls back to
148
+ * initialValues), its dirty baseline, touched flag and errors are cleared.
149
+ * The keep-flags preserve slices of that state instead.
150
+ *
151
+ * @param form
152
+ * @param name
153
+ */
154
+ /**
155
+ * Options accepted by {@link removeField}. All flags default to `false` —
156
+ * the historical remove semantics (value dropped, path tombstoned, dirty
157
+ * baseline/touched/errors cleared). Names mirror react-hook-form's
158
+ * `unregister` options to ease migration; RHF's `shouldValidate` and
159
+ * `keepDefaultValue` have no counterparts (removal never validates, and
160
+ * the tombstone is exactly the "do not revive from initialValues" choice).
161
+ */
162
+ type RemoveFieldOptions = {
163
+ /** Keep the field's live value and dirty baseline instead of
164
+ * tombstoning: reads and `getValues()` keep returning the value, submit
165
+ * includes it, and dirtiness against initialValues is preserved. */
166
+ keepValue?: boolean;
167
+ /** Keep the field's dirty baseline. Implies `keepValue` — a removed
168
+ * value has nothing to be dirty about. */
169
+ keepDirty?: boolean;
170
+ /** Keep the field's touched flag instead of clearing it. */
171
+ keepTouched?: boolean;
172
+ /** Keep the field's errors instead of clearing them. */
173
+ keepError?: boolean;
174
+ };
175
+ declare function removeField(form: Form$1, name: Name, options?: RemoveFieldOptions): void;
176
+ /**
177
+ * Remove field
178
+ * @param form
179
+ * @param path
180
+ * @param options keep-flags to preserve slices of state through the removal
181
+ */
182
+ declare function removeFieldByPath(form: Form$1, path: Path, options?: RemoveFieldOptions): void;
183
+ /**
184
+ * Set form initialValues
185
+ *
186
+ * Content-based early return: a new reference with equal content (the
187
+ * re-rendered inline literal) is a no-op, so committed edits survive, while
188
+ * genuinely changed content swaps the baseline and re-seeds — live values
189
+ * and tombstones are cleared, touched flags and errors survive.
190
+ * @param form
191
+ * @param initialValues
192
+ */
193
+ declare function setInitialValues(form: Form$1, initialValues: any): void;
194
+ /** Options accepted by {@link reset}. Every flag defaults to `false` —
195
+ * omitting the object (or any flag) keeps the plain full-reset behavior.
196
+ * Names mirror react-hook-form's reset options to ease migration. */
197
+ type ResetOptions = {
198
+ /** Keep the current values of fields that are dirty — differ from the
199
+ * pre-reset initialValues (the same rule {@link getDirtyFields} applies).
200
+ * Clean fields fall back to the new initialValues as usual. */
201
+ keepDirtyValues?: boolean;
202
+ /** Keep every field's current live value instead of returning to the
203
+ * baseline (react-hook-form's `keepValues` — a strict superset of
204
+ * `keepDirtyValues`, which only preserves dirty fields' values).
205
+ * Dirtiness is recomputed against the post-reset baseline, so kept
206
+ * values that differ from a newly provided baseline count as dirty. */
207
+ keepValues?: boolean;
208
+ /** Ignore a newly provided `initialValues` argument and keep the current
209
+ * baseline — fields still return to it (react-hook-form's
210
+ * `keepDefaultValues`). */
211
+ keepDefaultValues?: boolean;
212
+ /** Keep the touched set instead of clearing it. */
213
+ keepTouched?: boolean;
214
+ /** Keep field errors instead of clearing them. */
215
+ keepErrors?: boolean;
216
+ /** Keep the submitted flag (`isSubmitted`) instead of clearing it —
217
+ * react-hook-form's `keepIsSubmitted`. */
218
+ keepIsSubmitted?: boolean;
219
+ /** Keep the last submit's success flag (`isSubmitSuccessful`) instead of
220
+ * clearing it. */
221
+ keepIsSubmitSuccessful?: boolean;
222
+ /** Keep `submitCount` instead of resetting it to 0. */
223
+ keepSubmitCount?: boolean;
224
+ /** Keep `isSubmitting` instead of resetting it to false. */
225
+ keepIsSubmitting?: boolean;
226
+ };
227
+ /**
228
+ * Reset form
229
+ * @param form
230
+ * @param initialValues new baseline — omitted (or undefined), the form
231
+ * keeps its current initialValues and fields simply return to them
232
+ * (react-hook-form's reset-without-values semantics)
233
+ * @param options keep-flags to preserve slices of state through the reset
234
+ */
235
+ declare function reset(form: Form$1, initialValues?: any, options?: ResetOptions): void;
236
+ /** Options accepted by {@link resetField}. The flags default to `false`;
237
+ * `value` has no default — omitted, the field falls back to initialValues;
238
+ * provided, the explicit value becomes the live value with no fallback at
239
+ * all. Mirrors react-hook-form's resetField options (`value` plays their
240
+ * `defaultValue`'s role) to ease migration. */
241
+ type ResetFieldOptions = {
242
+ /** Keep the field's touched flag instead of clearing it. */
243
+ keepTouched?: boolean;
244
+ /** Keep the field's errors instead of clearing them. */
245
+ keepErrors?: boolean;
246
+ /** Explicit post-reset value for the field — never falls back to
247
+ * initialValues. */
248
+ value?: any;
249
+ };
250
+ /**
251
+ * Reset a single field: drop its live value (reads fall back to the
252
+ * baseline — initialValues, or the schema's parsed output when one
253
+ * exists, in which case the path is removed from parsedValues and the
254
+ * initial value pinned back so the field reads initialValues again),
255
+ * clear its touched flag and errors, and revive the path's removal
256
+ * tombstones — the inverse of {@link removeFieldByPath}. Other fields
257
+ * and the submission flags are untouched; see {@link reset} for the
258
+ * form-wide counterpart.
259
+ *
260
+ * @param form
261
+ * @param name
262
+ * @param options
263
+ */
264
+ declare function resetField<T extends Record<string, any> = any, P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments>(form: Form$1<T>, name: P, options?: ResetFieldOptions): void;
265
+
266
+ /**
267
+ * Set field touched state
268
+ * @param form
269
+ * @param name
270
+ */
271
+ declare function setTouched(form: Form$1, name: Name): void;
272
+ /**
273
+ * Set field touched state
274
+ * @param form
275
+ * @param path
276
+ */
277
+ declare function setTouchedByPath({ emitter, touched }: Form$1, path: Path): void;
278
+ /**
279
+ * Check if field has been touched
280
+ * @param form
281
+ * @param name
282
+ */
283
+ declare function hasTouched<T extends Record<string, any> = any, P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments>(form: Form$1<T>, name: P): boolean;
284
+ /**
285
+ * Check if field has been touched
286
+ * @param form
287
+ * @param path
288
+ */
289
+ declare function hasTouchedByPath({ touched }: Form$1, path: Path): boolean;
290
+ /**
291
+ * Is dirty -- any value differs from initialValues
292
+ * @param form
293
+ */
294
+ /**
295
+ * Get touched fields as user-facing dotted paths ('a.b', 'a.0.c'), unlike
296
+ * the JSON array keys stored in the touched Set.
297
+ * @param form
298
+ * @return array of touched fields' dotted paths
299
+ */
300
+ declare function getTouchedFields({ touched }: Form$1): string[];
301
+ /**
302
+ * Is touched -- any field has been touched
303
+ * @param form
304
+ */
305
+ declare function isTouched({ touched }: Form$1): boolean;
306
+
307
+ /**
308
+ * Is one field dirty — the per-field rule behind `getFieldState`'s
309
+ * `isDirty` and {@link useIsFieldDirty}: a live value exists at the path
310
+ * and differs from the field's effective baseline (committed
311
+ * `shouldDirty: false` baselines included). A leaf under a wholesale
312
+ * ancestor write reports clean — dirtiness belongs to the branch that
313
+ * actually diverged, the same attribution {@link getDirtyFields} applies.
314
+ */
315
+ declare function isFieldDirtyByPath(form: Form$1, path: Path): boolean;
316
+ /**
317
+ * Is dirty -- any value differs from initialValues
318
+ * @param form
319
+ */
320
+ declare function isDirty(form: Form$1): boolean;
321
+ /**
322
+ * Get dirty fields -- fields whose current value differs from initialValues.
323
+ * Keys are user-facing dotted paths ('a.b', 'a.0.c'), unlike the JSON array
324
+ * keys stored in the values Map.
325
+ * @param form
326
+ * @return object mapping each dirty field's dotted path to true; the same
327
+ * reference is returned until the dirty set actually changes
328
+ */
329
+ declare function getDirtyFields(form: Form$1): Record<string, boolean>;
330
+
331
+ /**
332
+ * Set a field value as a user change.
333
+ *
334
+ * The write rides the same gated user-change pipeline a user typing into
335
+ * the field would fire when a field is mounted on the path (registered
336
+ * through {@link registerFieldMode} — `useField` registers on mount): the
337
+ * field's effective `mode` (per-field override included) and the form's
338
+ * `reValidateMode` drive validation exactly as in {@link
339
+ * userChangeByPath}. With no mounted field on the path it degrades to a
340
+ * plain value set ({@link setValue}).
341
+ *
342
+ * This is the channel for component-library bridges that hand a control a
343
+ * plain setter bound to a field — they cannot rebuild the gating from
344
+ * public form state, because the per-field mode override and the
345
+ * live-error view that gates `reValidateMode` live in the field
346
+ * registration, not in public state.
347
+ *
348
+ * Contrast {@link setValue}: that is the imperative channel — its
349
+ * `shouldValidate` option kicks the field's validator unconditionally,
350
+ * ignoring any mode. Functional updaters are the caller's to evaluate
351
+ * ({@link getValue}).
352
+ *
353
+ * `options` carries the same {@link SetFieldOptions}: on the fallback path
354
+ * (no mounted field) they forward to {@link setValueByPath} wholesale,
355
+ * while on the mounted-field path only `shouldDirty: false` applies — the
356
+ * write lands as a commit while the field's own mode gating keeps driving
357
+ * validation, which is the point of this channel.
358
+ *
359
+ * @param form
360
+ * @param name
361
+ * @param value
362
+ * @param options
363
+ */
364
+ declare function changeValue<T extends Record<string, any> = any, P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments>(form: Form$1<T>, name: P, value: PathValueOf<T, P>, options?: SetFieldOptions): void;
365
+ /**
366
+ * Set a field value as a user change, by parsed path
367
+ * @param form
368
+ * @param path
369
+ * @param value
370
+ * @param options
371
+ */
372
+ declare function changeValueByPath(form: Form$1, path: Path, value: any, options?: SetFieldOptions): void;
373
+ /**
374
+ * Register a mounted field's `mode` override at `path` for user-change
375
+ * gating ({@link userChangeByPath} / {@link userBlur}). Returns the
376
+ * registration token for {@link unregisterFieldMode} plus whether the
377
+ * slot was already occupied — two fields mounted at one path is almost
378
+ * always a bug: the latest mount's mode governs every user-change write
379
+ * there, which the React layer warns about in DEV.
380
+ *
381
+ * @param form
382
+ * @param path
383
+ * @param mode the field's `mode` option, or undefined to follow
384
+ * {@link Form.mode}
385
+ * @return `token` to hand to {@link unregisterFieldMode}; `displaced`
386
+ * true when a previous registration at the same path still owned
387
+ * the slot
388
+ */
389
+ declare function registerFieldMode(form: Form$1, path: Path, mode: ValidationMode | undefined): {
390
+ token: object;
391
+ displaced: boolean;
392
+ };
393
+ /** Drop a {@link registerFieldMode} registration. A later mount at the
394
+ * same path keeps its slot: only the entry owned by `token` is removed. */
395
+ declare function unregisterFieldMode(form: Form$1, path: Path, token: object): void;
396
+ /**
397
+ * Write a bound field's user change by path: the write plus the
398
+ * mode/reValidateMode-gated validation pipeline — what a bound field's
399
+ * onChange does when the user types. Reads the effective mode from the
400
+ * field-mode registry (the latest mount's override governs), so a plain
401
+ * write happens when no field is registered at `path`. Framework
402
+ * adapters (React's `useField`, a Solid binding) forward their field
403
+ * change events here.
404
+ *
405
+ * @param form
406
+ * @param path
407
+ * @param value
408
+ */
409
+ declare function userChangeByPath(form: Form$1, path: Path, value: any): void;
410
+ /**
411
+ * A bound field's blur: mark the path touched, then kick its validator
412
+ * under the blur-side gate (`mode` `'onBlur'`/`'onTouched'`/`'all'`, or
413
+ * `reValidateMode: 'onBlur'` while the field carries a live error). The
414
+ * touched marking is unconditional — a field counts as touched on blur
415
+ * regardless of mode. Framework adapters forward field blur events here.
416
+ *
417
+ * @param form
418
+ * @param path
419
+ */
420
+ declare function userBlur(form: Form$1, path: Path): void;
421
+
422
+ declare function setIsSubmitting(form: Form$1, value: boolean): void;
423
+ declare function incrementSubmitCount(form: Form$1): void;
424
+ declare function setSubmitSuccessful(form: Form$1, value: boolean): void;
425
+ /**
426
+ * Set the form-level disabled flag and emit a payload-less 'disabled'
427
+ * event — subscribed fields (useField and the components built on it)
428
+ * re-render with the merged disabled state: form flag || their own
429
+ * `disabled` option.
430
+ * @param form
431
+ * @param value
432
+ */
433
+ declare function setDisabled(form: Form$1, value: boolean): void;
434
+ /**
435
+ * Set the form's user-owned metadata slot (Formik's `status` role): the
436
+ * payload-less 'status' event wakes {@link useStatus} and any imperative
437
+ * `subscribe(form, {event: 'status'})` listeners. Nothing else reads or
438
+ * interprets the value — server session flags, step state, non-field
439
+ * errors of any shape are all fair game. Starts `undefined`.
440
+ * @param form
441
+ * @param value
442
+ */
443
+ declare function setStatus(form: Form$1, value: any): void;
444
+ /** Submit callbacks for {@link handleSubmit}. All optional — a missing
445
+ * callback is simply skipped, matching the <Form> component semantics. */
446
+ type HandleSubmitOptions<T extends Record<string, any> = any> = {
447
+ /** Called after validation passes, before onValidSubmit. */
448
+ onSubmit?: (values: T, e?: any) => void | Promise<void>;
449
+ /** Called after validation passes, following a successful onSubmit. */
450
+ onValidSubmit?: (values: T, e?: any) => void | Promise<void>;
451
+ /**
452
+ * Called when validation fails.
453
+ * @param errors array of {path, type, message} entries in insertion
454
+ * order; path is the dotted field path ('a.b', 'list.0'), type is
455
+ * the error kind ('custom' for plain string errors, 'native' for
456
+ * failed DOM constraint validation), message is the display text
457
+ * @param values current form values
458
+ */
459
+ onInvalidSubmit?: (errors: FieldErrorEntry[], values: T) => void;
460
+ /**
461
+ * Called after validation passes and the submit callbacks ran, with the
462
+ * final (schema-coerced) values — the slot <Form>'s `action` prop uses
463
+ * to dispatch React 19 server actions with FormData. Runs inside the
464
+ * same isSubmitting window and is awaited like onSubmit/onValidSubmit.
465
+ */
466
+ onAction?: (values: T, e?: any) => void | Promise<void>;
467
+ /**
468
+ * Focus the first error field after a failed submit. Defaults to true —
469
+ * only an explicit `false` disables it. When custom validation fails,
470
+ * a 'focusError' event carrying the first error's path key is emitted
471
+ * on the form (bound fields such as <Field> subscribe and focus their
472
+ * input); when native constraint validation fails, the submitted
473
+ * form's first ':invalid' control is focused directly.
474
+ */
475
+ shouldFocusError?: boolean;
476
+ };
477
+ /**
478
+ * Create an async submit handler for `form` — the headless counterpart of
479
+ * the <Form> component's onSubmit wiring.
480
+ *
481
+ * Behavior mirrors <Form> exactly: preventDefault when present, then the
482
+ * submit state machine (isSubmitting/submitCount/isSubmitSuccessful) runs
483
+ * around native constraint validation (via `e.currentTarget.checkValidity`,
484
+ * skipped when the target has no checkValidity — e.g. React Native or
485
+ * toolbar-button submits) and custom validators. Failed validation fires
486
+ * onInvalidSubmit with the flattened error entries; a passing submit runs
487
+ * onSubmit then onValidSubmit. Errors thrown by either are swallowed into
488
+ * isSubmitSuccessful=false rather than rejecting the returned promise.
489
+ * Failed validation also focuses the offending field (see
490
+ * {@link HandleSubmitOptions.shouldFocusError}).
491
+ *
492
+ * @param form form instance
493
+ * @param options submit callbacks
494
+ * @return async event handler, callable without an event object
495
+ */
496
+ declare function handleSubmit<T extends Record<string, any> = any>(form: Form$1<T>, options?: HandleSubmitOptions<T>): (e?: {
497
+ preventDefault?: () => void;
498
+ currentTarget?: any;
499
+ }) => Promise<void>;
7
500
 
8
501
  /** Type tag of a failed rule, as stored on the resulting FieldError. */
9
502
  type RuleType = 'required' | 'min' | 'max' | 'minLength' | 'maxLength' | 'pattern';
@@ -14,55 +507,102 @@ type RuleType = 'required' | 'min' | 'max' | 'minLength' | 'maxLength' | 'patter
14
507
  * rule name) instead of only surfacing through the browser's validity
15
508
  * bubble, so any design system can render the messages uniformly.
16
509
  */
17
- interface FieldRules {
510
+ type FieldRules = {
18
511
  /**
19
- * Fails on empty values: `''`, `undefined` or `null` (`0` and `false`
20
- * count as filled). A string is the error message; `true` uses the
21
- * default. When it fails, the remaining rules are skipped an empty
22
- * value reports only its required error.
512
+ * Fails on empty values: `''`, `undefined`, `null` or an empty array
513
+ * (`0` and `false` count as filled) react-hook-form's `required`
514
+ * semantics. A string is the error message; `true` uses the default.
515
+ * When it fails, the remaining rules are skipped — an empty value
516
+ * reports only its required error.
23
517
  */
24
518
  required?: string | true;
25
519
  /** Fails when `Number(value)` is below this bound; `NaN` values skip. */
26
520
  min?: number;
27
521
  /** Fails when `Number(value)` is above this bound; `NaN` values skip. */
28
522
  max?: number;
29
- /** Fails when a string value is shorter than this; non-strings skip. */
523
+ /** Fails when a string value is shorter than this, or an array has
524
+ * fewer entries; other values skip. */
30
525
  minLength?: number;
31
- /** Fails when a string value is longer than this; non-strings skip. */
526
+ /** Fails when a string value is longer than this, or an array has more
527
+ * entries; other values skip. */
32
528
  maxLength?: number;
33
529
  /** Fails when the value does not match `pattern.value`. */
34
530
  pattern?: {
35
531
  value: RegExp;
36
532
  message: string;
37
533
  };
534
+ /**
535
+ * Custom rule callbacks — react-hook-form's `register({validate})`
536
+ * shape: one function, or a record of named functions. Each runs after
537
+ * the declarative checks, and only when they passed (`required` failing
538
+ * short-circuits the rest, RHF's first-error semantics). A returned
539
+ * error keeps its message; its `type` becomes the record key
540
+ * (`'validate'` for the single-function form) so consumers can switch
541
+ * on `error.type`. Sync-only — async checks belong in the field's
542
+ * `validate` option.
543
+ */
544
+ validate?: SyncValidator | Record<string, SyncValidator>;
38
545
  /**
39
546
  * Overrides the message per rule type — `min`, `max`, `minLength`,
40
547
  * `maxLength` defaults and pattern's inline `message` alike — e.g. for
41
548
  * centralizing or localizing messages.
42
549
  */
43
550
  messages?: Partial<Record<Exclude<RuleType, 'required'>, string>>;
44
- }
551
+ };
45
552
 
46
- interface UseFieldOptions$1<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | Name = Name> {
553
+ type UseFieldOptions$1<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments> = {
47
554
  form?: Form$1<TValues>;
48
555
  name: TPath;
49
556
  initialValue?: any;
50
557
  shouldUnregister?: boolean;
51
- validate?: Validator;
558
+ /**
559
+ * Field-level validator. The value argument follows the path: with a
560
+ * typed form the callback receives `PathValueOf<TValues, TPath>` (the
561
+ * TanStack-parity inference — `name: 'age'` on a `{age: number}` shape
562
+ * types `value` as `number`), and falls back to `any` for untyped call
563
+ * sites (segment arrays, dynamic names). The return shape mirrors
564
+ * {@link Validator} — an error (string / FieldError / mixed array) or
565
+ * undefined when valid, possibly a Promise for async validation. The
566
+ * second argument carries the validation context (`meta.signal` aborts
567
+ * when the round is superseded).
568
+ */
569
+ validate?: (value: PathValueOf<TValues, TPath>, meta: {
570
+ form: Form$1<TValues>;
571
+ path: Path;
572
+ signal: AbortSignal;
573
+ }) => ReturnType<Validator>;
52
574
  /**
53
575
  * Declarative rules (required/min/max/minLength/maxLength/pattern),
54
- * compiled into a validator that runs before `validate` both sources'
55
- * errors merge into one FieldError[], rules errors ahead. Failures land
56
- * in the form's error state with the given or default messages.
576
+ * compiled into a synchronous validator. `required` is special: it runs
577
+ * immediately on every kick never debounced and while it fails,
578
+ * `validate` is skipped (the expensive check never sees an empty value).
579
+ * The other rules compose with `validate` — rules run first, then
580
+ * `validate` (awaited when async), merging both sources' errors with
581
+ * rules errors ahead. Failures land in the form's error state with the
582
+ * given or default messages.
57
583
  */
58
584
  rules?: FieldRules;
59
585
  /**
60
586
  * Milliseconds to debounce this field's validation kicks. Defaults to 0
61
587
  * (validate immediately); while the timer is pending the field counts as
62
588
  * validating, so `trigger`/`ensureValidate` wait out the window. Only the
63
- * last kick inside the window runs the validator.
589
+ * last kick inside the window runs the validator. The `required` rule is
590
+ * exempt: it runs synchronously on every kick, so a required failure
591
+ * shows immediately instead of waiting out the window.
64
592
  */
65
593
  validateDebounce?: number;
594
+ /**
595
+ * Run this field's debounced validator even when its `required` gate
596
+ * failed — TanStack Form's `asyncAlways`. The gate's errors land
597
+ * immediately (never debounced) and the validator's own result lands
598
+ * alongside them, per-source: a passing async round clears only its
599
+ * own errors while the gate's verdict stays. Falls back to the
600
+ * form-level `createForm({asyncAlways})` flag when omitted, so a field
601
+ * opts out with `asyncAlways: false`. The use case: the cheap format
602
+ * check fails (gate) but the expensive backend check should still run
603
+ * ("not in the right shape — and the backend says taken, too").
604
+ */
605
+ asyncAlways?: boolean;
66
606
  /**
67
607
  * Milliseconds to delay showing a newly appearing error in the render
68
608
  * layer (`error`/`errorObject`/`errors` stay undefined/empty until the
@@ -78,6 +618,22 @@ interface UseFieldOptions$1<TValues extends Record<string, any> = any, TPath ext
78
618
  * `disabled`. A field cannot opt out of a disabled form.
79
619
  */
80
620
  disabled?: boolean;
621
+ /**
622
+ * Uncontrolled mode: the field never subscribes to its own value, so
623
+ * typing re-renders nothing — the store still carries every write
624
+ * (getValues/submit/validation read it), and errors/touched/disabled/
625
+ * validating still re-render the field like react-hook-form's
626
+ * `register`. The result's `value` is the mount-time snapshot (initial
627
+ * value seed or baseline); it never refreshes, and bulk operations
628
+ * (reset/setInitialValues) sync the DOM element directly through the
629
+ * `focusRef`-held element instead of a render — the register-style
630
+ * contract, RHF's reset clears the input the same way. Attach the
631
+ * result with `<input defaultValue={field.value} ref={field.focusRef}>`
632
+ * -style binding (no `value` prop), exactly like <Field uncontrolled />
633
+ * does. The DOM sync writes the raw stored value (file inputs are
634
+ * skipped); read live values with useValue/getValues.
635
+ */
636
+ uncontrolled?: boolean;
81
637
  /**
82
638
  * Field-level validation mode override: when given, this field validates
83
639
  * on its own schedule instead of `form.mode` — every other field keeps
@@ -111,13 +667,22 @@ interface UseFieldOptions$1<TValues extends Record<string, any> = any, TPath ext
111
667
  * the field's own path is a no-op (its own change already validates it).
112
668
  */
113
669
  validateDeps?: FieldPath<TValues>[];
114
- }
670
+ /**
671
+ * Validate this field once on mount instead of waiting for the first
672
+ * submit/change — errors show immediately for an untouched field.
673
+ * Overrides the form-level `createForm({validateOnMount})` flag in
674
+ * either direction (`false` opts a field out of a validating form).
675
+ * While an async `initialValues` source is still pending the kick waits
676
+ * for the resolved baseline; a field unmounted in between never kicks.
677
+ */
678
+ validateOnMount?: boolean;
679
+ };
115
680
  /**
116
681
  * The result of {@link useField}. Deliberately a closed shape: no index
117
682
  * signature, so a typo'd property access (`field.vlaue`) is a type error
118
683
  * instead of silently reading `undefined`.
119
684
  */
120
- interface UseFieldResult<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | Name = Name> {
685
+ type UseFieldResult<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments> = {
121
686
  /** The form instance this field is bound to (explicit prop or context) —
122
687
  * handy for consumers that need direct access to the headless API. */
123
688
  form: Form$1<TValues>;
@@ -130,6 +695,22 @@ interface UseFieldResult<TValues extends Record<string, any> = any, TPath extend
130
695
  * and `errorObject` are its first entry. Empty (and reference-stable)
131
696
  * when the field has no errors. */
132
697
  errors: FieldError[];
698
+ /**
699
+ * Whether the field is dirty: its live value exists and differs from
700
+ * the field's effective baseline (the same per-field rule
701
+ * `getFieldState(form, name).isDirty` applies — committed
702
+ * `shouldDirty: false` baselines included). Live in controlled mode;
703
+ * pinned at mount in uncontrolled mode (like `value`) so typing never
704
+ * re-renders the field — {@link useIsFieldDirty} is the live scoped
705
+ * channel for either mode.
706
+ */
707
+ isDirty: boolean;
708
+ /**
709
+ * Whether a validator round for this field is currently in flight —
710
+ * a pending debounce window or an unresolved async validator (the
711
+ * `getFieldState(form, name).isValidating` reading, made reactive).
712
+ */
713
+ validating: boolean;
133
714
  onChange: (v: any) => void;
134
715
  onBlur: () => void;
135
716
  name: string;
@@ -137,15 +718,51 @@ interface UseFieldResult<TValues extends Record<string, any> = any, TPath extend
137
718
  * toggled by `setDisabled`) OR-ed with this field's own `disabled`
138
719
  * option, updated live through the form's event core. */
139
720
  disabled: boolean;
140
- }
141
- declare function useField<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | Name = Name>(options: UseFieldOptions$1<TValues, TPath>): UseFieldResult<TValues, TPath>;
721
+ /**
722
+ * Callback ref carrying the focus channel: attach it to your input
723
+ * element (`<input ref={field.focusRef} />`) so `setFocus` and a failed
724
+ * submit's first-error auto-focus (`shouldFocusError`) can focus this
725
+ * headless field — the same 'focusError' wiring `<Field>` performs for
726
+ * its own input. Without it, focus requests aimed at this field are
727
+ * silent no-ops, matching `setFocus`'s contract: focusing a field
728
+ * whose element is not bound neither throws nor focuses anything.
729
+ */
730
+ focusRef: (el: any) => void;
731
+ };
732
+ declare function useField<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments>(options: UseFieldOptions$1<TValues, TPath>): UseFieldResult<TValues, TPath>;
142
733
 
143
- interface FieldArrayItem {
734
+ type FieldArrayItem<K extends string> = {
144
735
  id: string;
145
736
  index: number;
146
- }
147
- interface UseFieldArrayResult {
148
- fields: FieldArrayItem[];
737
+ } & Record<K, string>;
738
+ /** Options accepted by {@link useFieldArray} and the per-instance hook
739
+ * returned by `createFormContext()`. */
740
+ type UseFieldArrayOptions<K extends string = 'id'> = {
741
+ name: Name;
742
+ form?: Form$1;
743
+ /**
744
+ * Property name the stable row key is exposed under on each `fields`
745
+ * entry (react-hook-form's `keyName`): defaults to `'id'`, a custom
746
+ * name (e.g. `'key'`) avoids clashing with a row data field of the
747
+ * same name. The underlying id is unchanged.
748
+ */
749
+ keyName?: K;
750
+ /**
751
+ * Declarative rules validated against the whole array value
752
+ * (react-hook-form's `useFieldArray` `rules`): `required` fails on an
753
+ * empty array, `minLength`/`maxLength` read the array's length. Checked
754
+ * on submit and `trigger`, like every registered validator.
755
+ */
756
+ rules?: FieldRules;
757
+ /**
758
+ * Whether unmounting this array removes its branch. Defaults to the
759
+ * form-level `shouldUnregister` — tombstone (drop values) like a bound
760
+ * field's unmount; pass `false` to keep the values.
761
+ */
762
+ shouldUnregister?: boolean;
763
+ };
764
+ type UseFieldArrayResult<K extends string = 'id'> = {
765
+ fields: FieldArrayItem<K>[];
149
766
  append: (value: any) => void;
150
767
  prepend: (value: any) => void;
151
768
  insert: (index: number, value: any) => void;
@@ -154,18 +771,15 @@ interface UseFieldArrayResult {
154
771
  move: (from: number, to: number) => void;
155
772
  replace: (values: any[]) => void;
156
773
  update: (index: number, value: any) => void;
157
- }
158
- declare function useFieldArray(options: {
159
- name: Name;
160
- form?: Form$1;
161
- }): UseFieldArrayResult;
774
+ };
775
+ declare function useFieldArray<K extends string = 'id'>(options: UseFieldArrayOptions<K>): UseFieldArrayResult<K>;
162
776
  /**
163
777
  * The result of {@link useFieldArrayItem}. Mirrors the {@link useField}
164
778
  * return shape (`value`/`errors`/`error`) plus the row's `index` and
165
779
  * `name` (path key) so nested fields can build on it —
166
780
  * `useField({name: ['tags', item.index, 'label']})`.
167
781
  */
168
- interface UseFieldArrayItemResult<TValue = any> {
782
+ type UseFieldArrayItemResult<TValue = any> = {
169
783
  value: TValue;
170
784
  /** Overwrite this row's value in place (same array-layer write as
171
785
  * `update(index, value)`: the row's id and position are kept). */
@@ -183,7 +797,7 @@ interface UseFieldArrayItemResult<TValue = any> {
183
797
  * undefined and nothing writes the dangling path. */
184
798
  index: number;
185
799
  form: Form$1;
186
- }
800
+ };
187
801
  /**
188
802
  * Subscribe to a single row of a {@link useFieldArray} field — the
189
803
  * per-item counterpart `useFieldArray` alone cannot offer. `useFieldArray`
@@ -215,8 +829,8 @@ declare function useFieldArrayItem<TValue = any>(options: {
215
829
  form?: Form$1;
216
830
  }): UseFieldArrayItemResult<TValue>;
217
831
 
218
- declare const FormContext: React.Context<any>;
219
- declare const FormProvider: React.Provider<any>;
832
+ declare const FormContext: React.Context<Form$1<any> | null>;
833
+ declare const FormProvider: React.Provider<Form$1<any> | null>;
220
834
  /**
221
835
  * Read the form from the module-level {@link FormContext}. Pass the values
222
836
  * shape — `useFormContext<Values>()` — to get a fully typed `Form<Values>`
@@ -249,12 +863,15 @@ declare function createFormContext<TValues extends Record<string, any> = any>():
249
863
  children: ReactNode;
250
864
  }) => ReactNode;
251
865
  useFormContext: () => Form$1<TValues>;
252
- useField: <TPath extends FieldPath<TValues> | Name = Name>(options: {
866
+ useField: <TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments>(options: {
253
867
  name: TPath;
254
868
  } & Omit<UseFieldOptions$1<TValues, TPath>, "form">) => UseFieldResult<TValues, TPath>;
255
- useFieldArray: (options: {
869
+ useFieldArray: <K extends string = "id">(options: {
256
870
  name: FieldPath<TValues> | Name;
257
- }) => UseFieldArrayResult;
871
+ keyName?: K;
872
+ rules?: FieldRules;
873
+ shouldUnregister?: boolean;
874
+ }) => UseFieldArrayResult<K>;
258
875
  useFieldArrayItem: <TValue = any>(options: {
259
876
  name: FieldPath<TValues> | Name;
260
877
  id: string;
@@ -264,6 +881,70 @@ declare const CheckboxGroupContext: React.Context<any>;
264
881
  declare const CheckboxGroupProvider: React.Provider<any>;
265
882
  declare function useCheckboxGroupContext(): any;
266
883
 
884
+ /** Subscription granularity for {@link onPathEvent}.
885
+ * - `'leaf'`: the subscriber reads exactly one key ({@link
886
+ * useValueByPath}); only writes at that key or above it can change what
887
+ * it reads.
888
+ * - `'branch'`: the subscriber aggregates a whole subtree below a key
889
+ * ({@link useFieldArray}); descendant writes matter too. */
890
+ type WatchScope = 'leaf' | 'branch';
891
+ /** Events {@link subscribe} can watch. `'errors'` and `'touched'` are
892
+ * stored per exact key, so they match exact keys ({@link onKeyEvent});
893
+ * `'change'`, `'validating'`, `'submitting'`, `'submitCount'`,
894
+ * `'disabled'`, `'status'` and `'submitSuccessful'` go through
895
+ * {@link onPathEvent}. `'validating'` carries paths (one per async
896
+ * validator round) and matches by path exactly like `'change'`;
897
+ * `'submitting'`, `'submitCount'`, `'disabled'`, `'status'` and
898
+ * `'submitSuccessful'` are payload-less broadcasts, so `name` never
899
+ * narrows them — every subscriber hears every emission. */
900
+ type SubscribeEvent = 'change' | 'errors' | 'touched' | 'validating' | 'submitting' | 'submitCount' | 'submitSuccessful' | 'disabled' | 'status' | 'loading';
901
+ /** Options accepted by {@link subscribe}. */
902
+ type SubscribeOptions = {
903
+ /** Path (or list of paths) to watch. Omit to receive every emission of
904
+ * `event`, payload-less broadcasts included. A single segments path
905
+ * (`['tags', 0]`) and a list of names (`['tags', 'user.name']`) are told
906
+ * apart by the same rule `trigger` uses: only a segments path can hold
907
+ * a number. */
908
+ name?: Name | Name[];
909
+ /** Event to watch. Defaults to `'change'`. */
910
+ event?: SubscribeEvent;
911
+ /** Which writes around `name` are relevant — `'leaf'` or `'branch'`.
912
+ * Only meaningful for the path-carrying events `'change'` and
913
+ * `'validating'`: `'errors'`/`'touched'` match exact keys and
914
+ * `'submitting'`/`'submitCount'`/`'disabled'`/`'status'`/
915
+ * `'submitSuccessful'` are payload-less. Defaults to `'branch'` — the
916
+ * intuitive linkage semantics, where subscribing to `'tags'` means the
917
+ * whole branch. */
918
+ scope?: WatchScope;
919
+ /** Invoked with no arguments after each matching emission. Read fresh
920
+ * state through the `get*` readers inside it. */
921
+ callback: () => void;
922
+ };
923
+ /**
924
+ * Subscribe to form events imperatively — the non-render counterpart of
925
+ * the `use*` hooks: linkages and side effects (province changed → clear
926
+ * city, autosave, analytics) run without mounting a watching component.
927
+ *
928
+ * Without `name`, `callback` fires on every `event` emission, payload-less
929
+ * broadcasts (reset, setInitialValues) included. With `name`, matching
930
+ * follows the event's shape: `'errors'`/`'touched'` match the exact key
931
+ * ({@link onKeyEvent}) — another field's error never wakes this
932
+ * subscriber — while `'change'`/`'validating'`/`'submitting'`/
933
+ * `'submitCount'`/`'disabled'`/`'submitSuccessful'` go through
934
+ * {@link onPathEvent}, so the default `'branch'` scope wakes a `'tags'`
935
+ * subscriber when any `tags.*` descendant is written. `'validating'`
936
+ * carries a path per validator round and narrows by path like
937
+ * `'change'`; `'disabled'`/`'submitSuccessful'` (like `'submitting'`)
938
+ * are payload-less broadcasts that every named subscriber receives. A
939
+ * `name` array builds one subscription per path and the returned
940
+ * function unsubscribes them all.
941
+ *
942
+ * @param form the form to watch
943
+ * @param options event, name(s), scope and callback
944
+ * @return unsubscribe function
945
+ */
946
+ declare function subscribe(form: Form$1, options: SubscribeOptions): () => void;
947
+
267
948
  /**
268
949
  * Create a form instance bound to this component.
269
950
  *
@@ -279,6 +960,23 @@ declare function useCheckboxGroupContext(): any;
279
960
  declare function useForm<T extends Record<string, any> = any>(options?: Options<T> & {
280
961
  values?: T;
281
962
  }): Form$1<T>;
963
+ /**
964
+ * Shared core of {@link useWatch} and the path-scoped hooks: a
965
+ * useSyncExternalStore binding over a custom event subscription.
966
+ * `subscribeFactory` receives the invalidate callback (drop the snapshot
967
+ * cache, then notify React) and returns its unsubscribe function, so the
968
+ * core stays identical whether the subscription is global or scoped to
969
+ * one path.
970
+ *
971
+ * The optional `isEqual` comparator redirects `invalidate`: instead of
972
+ * dropping the cache and waking React unconditionally, an event first
973
+ * recomputes the getter and asks `isEqual` whether anything observable
974
+ * changed — an equal verdict keeps the cached snapshot and skips the
975
+ * notify entirely (no render at all), an unequal one stores the fresh
976
+ * snapshot and notifies. Omitted, the historical drop-and-notify pipeline
977
+ * runs byte-for-byte unchanged.
978
+ */
979
+ declare function useWatchCore<T>(subscribeFactory: (invalidate: () => void) => () => void, getter: () => T, isEqual?: (prev: T, next: T) => boolean): T;
282
980
  /**
283
981
  * Subscribe to a form event and keep the component's snapshot of `getter()`
284
982
  * in sync with the form state.
@@ -286,20 +984,53 @@ declare function useForm<T extends Record<string, any> = any>(options?: Options<
286
984
  * Built on useSyncExternalStore, so snapshots taken while React renders are
287
985
  * guaranteed consistent (no tearing under concurrent rendering) and changes
288
986
  * emitted before the subscription effect runs are still picked up.
987
+ *
988
+ * The first argument is the form for the unified `fn(form, ...)` context
989
+ * shape every hook shares; the raw emitter form remains accepted for
990
+ * back-compat and for subscription sources that are not a full form.
991
+ *
992
+ * By default the re-render surface is the event's own scope: every emit
993
+ * the subscription hears drops the snapshot cache and wakes React, which
994
+ * then bails out when the recomputed snapshot is reference-identical
995
+ * (Object.is) — the path/leaf scoping every built-in reader relies on.
996
+ * The optional `isEqual` comparator exists for wide-scope getters that
997
+ * return a fresh reference per call (a whole-values selector, say): each
998
+ * event recomputes the getter and asks `isEqual` whether the result is
999
+ * observably the same, and an equal verdict skips notifying React
1000
+ * altogether — no render, not even a bailed-out one. An unequal verdict
1001
+ * stores the new snapshot and re-renders. Same contract as TanStack's
1002
+ * `useSelector` compare. Omitted, behavior is unchanged.
289
1003
  */
290
- declare function useWatch<T>(emitter: EventEmitter, event: string, getter: () => T): T;
1004
+ declare function useWatch<T>(formOrEmitter: Form$1 | EventEmitter<FormEvents>, event: SubscribeEvent, getter: () => T, isEqual?: (prev: T, next: T) => boolean): T;
1005
+ /** Options for {@link useValue} and {@link useValueByPath}. */
1006
+ type UseValueOptions<T extends Record<string, any> = any, P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments> = {
1007
+ /** Value to return while the field reads undefined — react-hook-form's
1008
+ * `useWatch` `defaultValue`: an untouched, never-seeded field reads
1009
+ * this instead of `undefined`. */
1010
+ defaultValue?: PathValueOf<T, P>;
1011
+ /** Watch descendants too (react-hook-form's `exact: false`): a write
1012
+ * to `a.b` invalidates a `useValue(form, 'a')` read, and the read
1013
+ * resolves the merged subtree (the copy-on-write `getValues` tree) so
1014
+ * descendant edits show up in the result. Defaults to true — the leaf
1015
+ * scope, where only the exact key and its ancestors invalidate (the
1016
+ * long-standing behavior). */
1017
+ exact?: boolean;
1018
+ };
291
1019
  /**
292
1020
  * Get field value state
293
1021
  */
294
- declare function useValue<T extends Record<string, any> = any, P extends FieldPath<T> | Name = Name>(form: Form$1<T>, name: P): PathValueOf<T, P>;
1022
+ declare function useValue<T extends Record<string, any> = any, P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments>(form: Form$1<T>, name: P, options?: UseValueOptions<T, P>): PathValueOf<T, P>;
295
1023
  /**
296
1024
  * Get field value state by path
297
1025
  */
298
- declare function useValueByPath(form: Form$1, path: Path): any;
1026
+ declare function useValueByPath(form: Form$1, path: Path, options?: {
1027
+ defaultValue?: any;
1028
+ exact?: boolean;
1029
+ }): any;
299
1030
  /**
300
1031
  * Get field touched state
301
1032
  */
302
- declare function useTouched<T extends Record<string, any> = any, P extends FieldPath<T> | Name = Name>(form: Form$1<T>, name: P): boolean;
1033
+ declare function useTouched<T extends Record<string, any> = any, P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments>(form: Form$1<T>, name: P): boolean;
303
1034
  /**
304
1035
  * Get field touched state by path
305
1036
  */
@@ -308,7 +1039,7 @@ declare function useTouchedByPath(form: Form$1, path: Path): boolean;
308
1039
  * Get field error message state
309
1040
  * @return current error's message string (display text), or undefined
310
1041
  */
311
- declare function useError<T extends Record<string, any> = any, P extends FieldPath<T> | Name = Name>(form: Form$1<T>, name: P): string | undefined;
1042
+ declare function useError<T extends Record<string, any> = any, P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments>(form: Form$1<T>, name: P): string | undefined;
312
1043
  /**
313
1044
  * Get field error state by path
314
1045
  * @return current FieldError object ({type, message}), or undefined
@@ -319,7 +1050,7 @@ declare function useErrorByPath(form: Form$1, path: Path): FieldError | undefine
319
1050
  * @return every error registered for the field (insertion order); an empty
320
1051
  * array when the field has none
321
1052
  */
322
- declare function useFieldErrors<T extends Record<string, any> = any, P extends FieldPath<T> | Name = Name>(form: Form$1<T>, name: P): FieldError[];
1053
+ declare function useFieldErrors<T extends Record<string, any> = any, P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments>(form: Form$1<T>, name: P): FieldError[];
323
1054
  /**
324
1055
  * Get all field errors by path
325
1056
  * @return every error registered for the field (insertion order); an empty
@@ -327,6 +1058,21 @@ declare function useFieldErrors<T extends Record<string, any> = any, P extends F
327
1058
  */
328
1059
  declare function useFieldErrorsByPath(form: Form$1, path: Path): FieldError[];
329
1060
  declare function useIsDirty(form: Form$1): boolean;
1061
+ /**
1062
+ * Get whether one field is dirty: its live value exists and differs from
1063
+ * the field's effective baseline — the same per-field rule
1064
+ * `getFieldState(form, name).isDirty` applies (committed
1065
+ * `shouldDirty: false` baselines included). Subscribes to 'change' at
1066
+ * leaf scope like {@link useValue}: own-key and ancestor writes re-check
1067
+ * the flag, payload-less broadcasts (reset, setInitialValues) always
1068
+ * sync, and writes elsewhere never re-render it.
1069
+ */
1070
+ declare function useIsFieldDirty<T extends Record<string, any> = any, P extends FieldPath<T> | PathSegments = FieldPath<T> | PathSegments>(form: Form$1<T>, name: P): boolean;
1071
+ /**
1072
+ * Get whether one field is dirty, by parsed path. See {@link
1073
+ * useIsFieldDirty}.
1074
+ */
1075
+ declare function useIsFieldDirtyByPath(form: Form$1, path: Path): boolean;
330
1076
  /**
331
1077
  * Get dirty fields state -- object mapping each dirty field's user-facing
332
1078
  * dotted path ('a.b', 'a.0.c') to true; recalculated after 'change' events
@@ -337,8 +1083,76 @@ declare function useDirtyFields(form: Form$1): Record<string, boolean>;
337
1083
  * paths ('a.b', 'a.0.c'); recalculated after 'touched' events
338
1084
  */
339
1085
  declare function useTouchedFields(form: Form$1): string[];
1086
+ /**
1087
+ * Aggregate snapshot of the whole form's state flags — the one-subscription
1088
+ * counterpart of react-hook-form's `formState` object (no errors object;
1089
+ * per-field error state stays with `useError`/`useFieldErrors`, and
1090
+ * `hasErrors`/`isValid` cover the whole-form questions).
1091
+ *
1092
+ * Recomputed on every state-bearing event; the field-wise comparator keeps
1093
+ * the returned reference stable while nothing observably changed, so
1094
+ * `useFormState(form).isDirty` re-renders no more often than the dedicated
1095
+ * {@link useIsDirty}. Cheaper than calling the granular hooks one by one
1096
+ * (one subscription and one snapshot instead of one per flag).
1097
+ */
1098
+ type FormState = {
1099
+ /** Any live value differs from its baseline (see {@link isDirty}). */
1100
+ isDirty: boolean;
1101
+ /** Dirty fields keyed by user-facing dotted path ('a.b', 'a.0.c'). */
1102
+ dirtyFields: Record<string, boolean>;
1103
+ /** At least one field is touched. */
1104
+ isTouched: boolean;
1105
+ /** Touched fields' user-facing dotted paths. */
1106
+ touchedFields: string[];
1107
+ /** Any error registered (field or form level). */
1108
+ hasErrors: boolean;
1109
+ /** No errors are registered — react-hook-form's `isValid` semantics.
1110
+ * In-flight validation is NOT factored in ({@link isValidating} is the
1111
+ * separate signal; async rounds temporarily pass this flag like RHF's). */
1112
+ isValid: boolean;
1113
+ isSubmitting: boolean;
1114
+ /**
1115
+ * Whether a submit has been attempted on this form — set on the first
1116
+ * `handleSubmit` call (validation outcome aside) and cleared by
1117
+ * `reset`, react-hook-form's `formState.isSubmitted` semantics. Read
1118
+ * after a failed submit to render a "fix the errors below" panel.
1119
+ */
1120
+ isSubmitted: boolean;
1121
+ /** Any validation round is running (field, form-level, or a pending
1122
+ * debounce window). */
1123
+ isValidating: boolean;
1124
+ isSubmitSuccessful: boolean | undefined;
1125
+ submitCount: number;
1126
+ /** Async initialValues still pending ({@link Form.isLoading}). */
1127
+ isLoading: boolean;
1128
+ /** The form-level disabled flag (fields OR their own `disabled`). */
1129
+ disabled: boolean;
1130
+ };
1131
+ declare function useFormState(form: Form$1): FormState;
340
1132
  declare function useHasErrors(form: Form$1): boolean;
1133
+ /**
1134
+ * Get whether the form currently has no errors — react-hook-form's
1135
+ * `formState.isValid` counterpart. Subscribes to the `'errors'` event only;
1136
+ * in-flight validation does not flip it (see {@link useIsValidating}).
1137
+ */
1138
+ declare function useIsValid(form: Form$1): boolean;
341
1139
  declare function useIsSubmitting(form: Form$1): boolean;
1140
+ /**
1141
+ * Get whether an async {@link Options.initialValues} source is still
1142
+ * pending — the flag a loading skeleton or a disabled submit button gates
1143
+ * on until the resolved baseline lands. Subscribes to the 'loading' event
1144
+ * the core emits around the resolution cycle.
1145
+ */
1146
+ declare function useIsLoading(form: Form$1): boolean;
1147
+ /**
1148
+ * Get the form's user-owned metadata slot reactively (Formik's `status`
1149
+ * counterpart): any value the app stores through {@link setStatus} —
1150
+ * server session flags, wizard step state, non-field errors. Subscribes
1151
+ * to the payload-less 'status' event, so unrelated events never re-render
1152
+ * the caller, and the returned reference is stable between writes that
1153
+ * store an equal value (useSyncExternalStore's Object.is bailout).
1154
+ */
1155
+ declare function useStatus<T = any>(form: Form$1): T;
342
1156
  /**
343
1157
  * Get whether the form accepts a submit right now:
344
1158
  * `!isSubmitting && !hasErrors`. This is the single flag a submit
@@ -351,59 +1165,112 @@ declare function useIsSubmitting(form: Form$1): boolean;
351
1165
  */
352
1166
  declare function useCanSubmit(form: Form$1): boolean;
353
1167
  declare function useSubmitCount(form: Form$1): number;
1168
+ /**
1169
+ * Get whether any validation round is currently running: a field
1170
+ * validator's pending `validateDebounce` window, an async field validator
1171
+ * still in flight, or the form-level validate's debounce window / in-flight
1172
+ * round — every one of them holds a key in `form.validating`, and the
1173
+ * 'validating' events they emit (field rounds with a path payload, the
1174
+ * form-level round as a payload-less broadcast) are what this subscribes
1175
+ * to. The boolean snapshot is Object.is-stable, so churn among the marks
1176
+ * (a second field opening while the first settles) costs no render while
1177
+ * the flag holds. This is the flag a submit button disables itself on, or
1178
+ * spins a spinner with, through the pre-submit validation pass — it flips
1179
+ * true the moment the first round opens and back false when the last one
1180
+ * settles.
1181
+ */
1182
+ declare function useIsValidating(form: Form$1): boolean;
1183
+ /**
1184
+ * Get whether the last submit succeeded: `true` once a submit's validation
1185
+ * and `onSubmit` completed without throwing, `false` after a failed submit
1186
+ * (validation rejection or a thrown callback) and before any submit ran —
1187
+ * the falsy reading of the undefined initial/reset state. Subscribes to
1188
+ * the 'submitSuccessful' event the core's setSubmitSuccessful emits, so
1189
+ * the flag flips in the same tick the outcome lands: the usual consumers
1190
+ * are a success banner and a redirect-on-success effect.
1191
+ */
1192
+ declare function useIsSubmitSuccessful(form: Form$1): boolean;
1193
+ /**
1194
+ * Get the form-level error message: the first error stored under the
1195
+ * reserved {@link FORM_ERROR} key, as display text — or undefined while
1196
+ * the slot is clean. That key is where a form-level `validate` record's
1197
+ * `_form` entry lands and where the Standard Schema adapter drops
1198
+ * path-less issues, so errors that belong to no single field still have a
1199
+ * reader. The classic usage renders it once above the submit button —
1200
+ * `useFormError(form) || null` — and the imperative twin is
1201
+ * `getError(form, FORM_ERROR)`.
1202
+ */
1203
+ declare function useFormError(form: Form$1): string | undefined;
1204
+ /**
1205
+ * Get every form-level error: all errors stored under the reserved
1206
+ * {@link FORM_ERROR} key (insertion order), an empty array when the slot
1207
+ * is clean. The plural twin of {@link useFormError} for forms that stack
1208
+ * several form-level issues — each path-less Standard Schema issue lands
1209
+ * in this slot. The array reference is stable between unrelated events
1210
+ * (the stored array or a shared empty constant), so consumers can memo on
1211
+ * it; the imperative counterpart is `getFieldErrors(form, FORM_ERROR)`.
1212
+ */
1213
+ declare function useFormErrors(form: Form$1): FieldError[];
354
1214
 
355
- /** Subscription granularity for {@link onPathEvent}.
356
- * - `'leaf'`: the subscriber reads exactly one key ({@link
357
- * useValueByPath}); only writes at that key or above it can change what
358
- * it reads.
359
- * - `'branch'`: the subscriber aggregates a whole subtree below a key
360
- * ({@link useFieldArray}); descendant writes matter too. */
361
- type WatchScope = 'leaf' | 'branch';
362
- /** Events {@link subscribe} can watch. `'errors'` and `'touched'` are
363
- * stored per exact key, so they match exact keys ({@link onKeyEvent});
364
- * `'change'`, `'submitting'` and `'submitCount'` carry paths and go
365
- * through {@link onPathEvent}. */
366
- type SubscribeEvent = 'change' | 'errors' | 'touched' | 'submitting' | 'submitCount';
367
- /** Options accepted by {@link subscribe}. */
368
- type SubscribeOptions = {
369
- /** Path (or list of paths) to watch. Omit to receive every emission of
370
- * `event`, payload-less broadcasts included. A single segments path
371
- * (`['tags', 0]`) and a list of names (`['tags', 'user.name']`) are told
372
- * apart by the same rule `trigger` uses: only a segments path can hold
373
- * a number. */
374
- name?: Name | Name[];
375
- /** Event to watch. Defaults to `'change'`. */
376
- event?: SubscribeEvent;
377
- /** Which writes around `name` are relevant — `'leaf'` or `'branch'`.
378
- * Only meaningful for `'change'`: `'errors'`/`'touched'` match exact
379
- * keys and `'submitting'`/`'submitCount'` are payload-less. Defaults to
380
- * `'branch'` — the intuitive linkage semantics, where subscribing to
381
- * `'tags'` means the whole branch. */
382
- scope?: WatchScope;
383
- /** Invoked with no arguments after each matching emission. Read fresh
384
- * state through the `get*` readers inside it. */
385
- callback: () => void;
1215
+ /**
1216
+ * Options accepted by {@link useTransform}.
1217
+ */
1218
+ type UseTransformOptions<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments, TDisplay = PathValueOf<TValues, TPath>> = {
1219
+ /**
1220
+ * Map the form's stored (raw) value to the display value the control
1221
+ * renders the read direction. Omitted: the raw value is displayed
1222
+ * as-is (identity).
1223
+ */
1224
+ toDisplay?: (raw: PathValueOf<TValues, TPath>) => TDisplay;
1225
+ /**
1226
+ * Map a display value back to the raw value written into the form —
1227
+ * the write direction. Omitted: the display value is written as-is
1228
+ * (identity). The round trip should be an identity
1229
+ * (`toDisplay(fromDisplay(x)) === x`); a store value the transform
1230
+ * cannot invert (e.g. `undefined` for a not-yet-edited field) must be
1231
+ * handled by `toDisplay`, since it runs first.
1232
+ */
1233
+ fromDisplay?: (display: TDisplay) => PathValueOf<TValues, TPath>;
386
1234
  };
387
1235
  /**
388
- * Subscribe to form events imperatively the non-render counterpart of
389
- * the `use*` hooks: linkages and side effects (province changed → clear
390
- * city, autosave, analytics) run without mounting a watching component.
1236
+ * Bind a control to a field whose stored value and display value differ
1237
+ * TanStack Form's `useTransform` counterpart, with the round trip made
1238
+ * explicit: `toDisplay` maps the store value to what the control shows,
1239
+ * `fromDisplay` maps the control's display value back to what the store
1240
+ * holds. The store always carries the raw typed value, so
1241
+ * `getValues`/submit/validation never see display representations.
391
1242
  *
392
- * Without `name`, `callback` fires on every `event` emission, payload-less
393
- * broadcasts (reset, setInitialValues) included. With `name`, matching
394
- * follows the event's shape: `'errors'`/`'touched'` match the exact key
395
- * ({@link onKeyEvent}) another field's error never wakes this
396
- * subscriber — while `'change'`/`'submitting'`/`'submitCount'` go through
397
- * {@link onPathEvent}, so the default `'branch'` scope wakes a `'tags'`
398
- * subscriber when any `tags.*` descendant is written. A `name` array
399
- * builds one subscription per path and the returned function unsubscribes
400
- * them all.
1243
+ * ```jsx
1244
+ * const age = useTransform(form, 'age', {
1245
+ * toDisplay: (raw: number) => String(raw),
1246
+ * fromDisplay: (display: string) => Number(display)
1247
+ * });
1248
+ * <input value={age.value} onChange={e => age.onChange(e.target.value)} />
1249
+ * ```
401
1250
  *
402
- * @param form the form to watch
403
- * @param options event, name(s), scope and callback
404
- * @return unsubscribe function
1251
+ * `value` subscribes to 'change' at leaf scope exactly like a controlled
1252
+ * `useField` value typing, programmatic `setValue` and ancestor writes
1253
+ * all re-derive it, writes elsewhere never re-render it. `onChange`
1254
+ * writes through `userChangeByPath` (the user-change channel): with a
1255
+ * field mounted at the same path the mode/reValidateMode-gated
1256
+ * validation fires exactly as if the user typed into a bound field; with
1257
+ * no mounted field it degrades to a plain value write. Touched marking
1258
+ * stays a blur concern — pair this with `useField` at the same path, or
1259
+ * call `setTouched`, when blur semantics matter.
1260
+ *
1261
+ * The transform functions are read fresh on every render (inline
1262
+ * closures work), and `value` is recomputed per render — keep display
1263
+ * values primitive (string/number) so React's equal-state bailout holds.
1264
+ *
1265
+ * @param form the form instance (explicit; the hook is headless — no
1266
+ * context read, no provider required)
1267
+ * @param name the field's path (dotted string or segments)
1268
+ * @param options the two mapping directions; both optional (identity)
405
1269
  */
406
- declare function subscribe(form: Form$1, options: SubscribeOptions): () => void;
1270
+ declare function useTransform<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments, TDisplay = PathValueOf<TValues, TPath>>(form: Form$1<TValues>, name: TPath, options?: UseTransformOptions<TValues, TPath, TDisplay>): {
1271
+ value: TDisplay;
1272
+ onChange: (display: TDisplay) => void;
1273
+ };
407
1274
 
408
1275
  /**
409
1276
  * Props for <Form>.
@@ -419,7 +1286,7 @@ declare function subscribe(form: Form$1, options: SubscribeOptions): () => void;
419
1286
  * The submit flow itself lives in the headless `handleSubmit` (see form.ts);
420
1287
  * this component is a thin wrapper that binds it to the rendered <form>.
421
1288
  */
422
- interface FormProps<T extends Record<string, any> = any> extends Omit<React.FormHTMLAttributes<HTMLFormElement>, 'onSubmit'> {
1289
+ type FormProps<T extends Record<string, any> = any> = Omit<React.FormHTMLAttributes<HTMLFormElement>, 'onSubmit'> & {
423
1290
  form?: Form$1<T>;
424
1291
  /**
425
1292
  * Provide into an isolated context from `createFormContext()` instead of
@@ -431,7 +1298,39 @@ interface FormProps<T extends Record<string, any> = any> extends Omit<React.Form
431
1298
  * the form lands in the module-level FormContext as before.
432
1299
  */
433
1300
  context?: React.Context<Form$1<any> | null>;
434
- initialValues?: T;
1301
+ /**
1302
+ * The values baseline — a sync object, a Promise, or a thunk returning
1303
+ * either ({@link Options.initialValues}). Async sources render the form
1304
+ * empty and gate on `form.isLoading` until they resolve.
1305
+ */
1306
+ initialValues?: T | Promise<T> | (() => T | Promise<T>);
1307
+ /**
1308
+ * Form-level default for a bound field's unmount behavior
1309
+ * ({@link Options.shouldUnregister}): `true` (the default) tombstones
1310
+ * unmounted fields, `false` keeps their values.
1311
+ */
1312
+ shouldUnregister?: boolean;
1313
+ /**
1314
+ * Validate on mount (see {@link Options.validateOnMount}): every
1315
+ * mounted field with a validator kicks once after mount and the
1316
+ * form-level `validate` (if any) runs once. A field's own
1317
+ * `validateOnMount` prop overrides this flag.
1318
+ */
1319
+ validateOnMount?: boolean;
1320
+ /**
1321
+ * Disable every bound field: the form-level flag fields OR with their
1322
+ * own `disabled` option (a field cannot opt out). Seeded at create and
1323
+ * kept in sync while this prop changes (undefined leaves the current
1324
+ * flag untouched — toggle at runtime with `setDisabled`).
1325
+ */
1326
+ disabled?: boolean;
1327
+ /**
1328
+ * Form-level default for field validation's `asyncAlways`: a field
1329
+ * whose `required` gate failed still runs its debounced validator, its
1330
+ * result landing per-source alongside the gate's errors. A field's own
1331
+ * `asyncAlways` prop overrides this flag.
1332
+ */
1333
+ asyncAlways?: boolean;
435
1334
  /**
436
1335
  * Controlled external values. When the `values` reference changes, the
437
1336
  * new object is synced into the form (via setInitialValues semantics):
@@ -446,6 +1345,16 @@ interface FormProps<T extends Record<string, any> = any> extends Omit<React.Form
446
1345
  onSubmit?: (values: T, e: React.FormEvent) => void | Promise<void>;
447
1346
  /** May be async, same as onSubmit. */
448
1347
  onValidSubmit?: (values: T, e: React.FormEvent) => void | Promise<void>;
1348
+ /**
1349
+ * React 19 Server Action target: after validation passes (and after
1350
+ * onSubmit/onValidSubmit), the validated, schema-coerced values are
1351
+ * converted to FormData ({@link formDataFromValues} — files, arrays and
1352
+ * nested objects included) and dispatched to this callback, e.g.
1353
+ * `action={createUser}` for a server action or
1354
+ * `action={formData => startTransition(() => dispatch(formData))}` in a
1355
+ * useActionState bridge. `isSubmitting` covers the whole flight.
1356
+ */
1357
+ action?: (formData: FormData) => void | Promise<void>;
449
1358
  /**
450
1359
  * Called when validation fails.
451
1360
  * @param errors array of {path, type, message} entries in insertion
@@ -466,8 +1375,31 @@ interface FormProps<T extends Record<string, any> = any> extends Omit<React.Form
466
1375
  * false to disable.
467
1376
  */
468
1377
  shouldFocusError?: boolean;
469
- }
470
- declare function Form<T extends Record<string, any> = any>({ form: f1, context, initialValues, values, onSubmit, onValidSubmit, onInvalidSubmit, shouldFocusError, ...props }: FormProps<T>): React.JSX.Element;
1378
+ };
1379
+ declare function Form<T extends Record<string, any> = any>({ form: f1, context, initialValues, values, shouldUnregister, validateOnMount, disabled, asyncAlways, onSubmit, onValidSubmit, onInvalidSubmit, action, shouldFocusError, ...props }: FormProps<T>): React.JSX.Element;
1380
+
1381
+ /**
1382
+ * Props for {@link FormField}: every {@link UseFieldOptions} option plus a
1383
+ * render-prop `children` receiving the bound field result.
1384
+ */
1385
+ type FormFieldProps<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments> = UseFieldOptions$1<TValues, TPath> & {
1386
+ children: (field: UseFieldResult<TValues, TPath>) => React.ReactNode;
1387
+ };
1388
+ /**
1389
+ * Headless field bound through a render prop — the non-hook counterpart of
1390
+ * {@link useField} for class components, callback-style consumers and
1391
+ * library bridges where a hook cannot be called (Formik `<Field>` /
1392
+ * TanStack `form.Field` shape).
1393
+ *
1394
+ * The child function receives the full {@link UseFieldResult} — value,
1395
+ * error(s), onChange/onBlur, `disabled`, `focusRef`, the bound `form` —
1396
+ * and renders whatever UI it wants; nothing is rendered when it returns
1397
+ * null/undefined, so it can also gate conditional layout. Resolves its
1398
+ * form from the module-level `FormContext` or the explicit `form` option
1399
+ * (per-instance contexts from `createFormContext()` keep using their own
1400
+ * `useField` hook).
1401
+ */
1402
+ declare function FormField<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments>({ children, ...options }: FormFieldProps<TValues, TPath>): React.ReactNode;
471
1403
 
472
1404
  /**
473
1405
  * Props shared by Field/Checkbox/Select. Generic so a typed form flows into
@@ -477,7 +1409,7 @@ declare function Form<T extends Record<string, any> = any>({ form: f1, context,
477
1409
  * bare `<Field name="x" />` (context-resolved, untyped) call sites exactly
478
1410
  * as permissive as before.
479
1411
  */
480
- interface UseFieldOptions<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | Name = Name> {
1412
+ type UseFieldOptions<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments> = {
481
1413
  form?: Form$1<TValues>;
482
1414
  name?: TPath;
483
1415
  initialValue?: any;
@@ -496,10 +1428,17 @@ interface UseFieldOptions<TValues extends Record<string, any> = any, TPath exten
496
1428
  signal: AbortSignal;
497
1429
  }) => ReturnType<Validator>;
498
1430
  /**
499
- * Declarative rules (required/min/max/minLength/maxLength/pattern),
500
- * compiled into a validator that runs before `validate`; failures land
501
- * in the form's error state. Passed through to useField — like
502
- * validateDebounce it is never spread onto the DOM element.
1431
+ * Declarative rules (required/min/max/minLength/maxLength/pattern,
1432
+ * plus custom `validate` callbacks), compiled into a validator that
1433
+ * runs before `validate`; failures land in the form's error state.
1434
+ * The declarative subset is also rendered as native constraint
1435
+ * attributes (`required`, `minLength`, `pattern`, …) onto the element
1436
+ * for browser/AT hints — `:invalid` styling, screen-reader
1437
+ * announcements — while the store pipeline stays the source of truth
1438
+ * for messages (`renderError`/`aria-invalid` keep working; a user-passed
1439
+ * `required`/`pattern`/… prop overrides the derived attribute). Passed
1440
+ * through to useField — like validateDebounce it is never spread onto
1441
+ * the DOM element.
503
1442
  */
504
1443
  rules?: FieldRules;
505
1444
  /**
@@ -509,6 +1448,21 @@ interface UseFieldOptions<TValues extends Record<string, any> = any, TPath exten
509
1448
  * useField/useValidate.
510
1449
  */
511
1450
  validateDebounce?: number;
1451
+ /**
1452
+ * Run this field's debounced validator even when its `required` gate
1453
+ * failed (TanStack Form's `asyncAlways`): the gate's errors land
1454
+ * immediately, the validator's own result lands alongside them
1455
+ * per-source. Falls back to the form-level `createForm({asyncAlways})`.
1456
+ * Passed through to useField.
1457
+ */
1458
+ asyncAlways?: boolean;
1459
+ /**
1460
+ * Validate this field once on mount (see {@link
1461
+ * UseFieldOptions}' `validateOnMount`): overrides the form-level
1462
+ * `createForm({validateOnMount})` / `<Form validateOnMount>` flag in
1463
+ * either direction. Passed through to useField.
1464
+ */
1465
+ validateOnMount?: boolean;
512
1466
  /**
513
1467
  * Disable this field's control: OR-ed with the form-level flag
514
1468
  * (`createForm({disabled})` / `setDisabled`) — a field cannot opt out
@@ -532,9 +1486,19 @@ interface UseFieldOptions<TValues extends Record<string, any> = any, TPath exten
532
1486
  * the DOM element.
533
1487
  */
534
1488
  mode?: ValidationMode;
1489
+ /**
1490
+ * Uncontrolled mode: render the element with `defaultValue` instead of
1491
+ * `value` — typing re-renders nothing (the store still carries every
1492
+ * write; errors/touched/disabled still re-render the field). The
1493
+ * snapshot is pinned at mount; bulk operations (reset/setInitialValues)
1494
+ * sync the DOM element directly without a render — RHF-register
1495
+ * behavior (read live values with useValue/getValues). Passed through
1496
+ * to useField, never spread onto the DOM element.
1497
+ */
1498
+ uncontrolled?: boolean;
535
1499
  [key: string]: any;
536
- }
537
- interface FieldProps<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | Name = Name> extends UseFieldOptions<TValues, TPath> {
1500
+ };
1501
+ type FieldProps<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments> = UseFieldOptions<TValues, TPath> & {
538
1502
  as?: React.ComponentType<any>;
539
1503
  asProps?: Record<string, any>;
540
1504
  eventToValue?: (e: any) => any;
@@ -549,7 +1513,23 @@ interface FieldProps<TValues extends Record<string, any> = any, TPath extends Fi
549
1513
  * wiring for free.
550
1514
  */
551
1515
  renderError?: (error: string, id: string) => React.ReactNode;
552
- }
1516
+ /**
1517
+ * Store `e.target.valueAsNumber` instead of the string value —
1518
+ * react-hook-form's `register({valueAsNumber})` counterpart for number
1519
+ * inputs (`<input type="number">`). `NaN` passes through as-is when the
1520
+ * input cannot be parsed, matching RHF. An explicit `eventToValue`
1521
+ * takes precedence.
1522
+ */
1523
+ valueAsNumber?: boolean;
1524
+ /**
1525
+ * Store `e.target.valueAsDate` instead of the string value — RHF's
1526
+ * `register({valueAsDate})` counterpart for date/time inputs. `null`
1527
+ * passes through when the input cannot be parsed. An explicit
1528
+ * `eventToValue` takes precedence; combining with `valueAsNumber` is a
1529
+ * TypeError.
1530
+ */
1531
+ valueAsDate?: boolean;
1532
+ };
553
1533
  /**
554
1534
  * The error-message element id a field's `aria-describedby` points at —
555
1535
  * `fieldErrorId('a[0].b')` is `'a-0-b'`, the same id `Field`'s built-in
@@ -568,32 +1548,31 @@ declare function fieldErrorId(name: Name): string;
568
1548
  * same types, and the inline form trips no-use-before-define on the type
569
1549
  * parameters.
570
1550
  */
571
- interface FieldComponent {
572
- <TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | Name = Name>(props: FieldProps<TValues, TPath> & React.RefAttributes<HTMLInputElement>): React.ReactElement | null;
573
- }
1551
+ type FieldComponent = {
1552
+ <TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments>(props: FieldProps<TValues, TPath> & React.RefAttributes<HTMLInputElement>): React.ReactElement | null;
1553
+ };
574
1554
  declare const Field: FieldComponent;
575
- interface CheckboxProps<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | Name = Name> extends UseFieldOptions<TValues, TPath> {
576
- }
1555
+ type CheckboxProps<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments> = UseFieldOptions<TValues, TPath>;
577
1556
  /**
578
1557
  * Callable shape of {@link Checkbox}: the same form-typed `validate`
579
1558
  * inference contract as {@link FieldComponent}.
580
1559
  */
581
- interface CheckboxComponent {
582
- <TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | Name = Name>(props: CheckboxProps<TValues, TPath> & React.RefAttributes<HTMLInputElement>): React.ReactElement | null;
583
- }
1560
+ type CheckboxComponent = {
1561
+ <TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments>(props: CheckboxProps<TValues, TPath> & React.RefAttributes<HTMLInputElement>): React.ReactElement | null;
1562
+ };
584
1563
  declare const Checkbox: CheckboxComponent;
585
- interface SelectProps<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | Name = Name> extends UseFieldOptions<TValues, TPath> {
1564
+ type SelectProps<TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments> = UseFieldOptions<TValues, TPath> & {
586
1565
  multiple?: boolean;
587
1566
  children?: React.ReactNode;
588
- }
1567
+ };
589
1568
  /**
590
1569
  * Callable shape of {@link Select}: the same form-typed `validate`
591
1570
  * inference contract as {@link FieldComponent}.
592
1571
  */
593
- interface SelectComponent {
594
- <TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | Name = Name>(props: SelectProps<TValues, TPath> & React.RefAttributes<HTMLSelectElement>): React.ReactElement | null;
595
- }
1572
+ type SelectComponent = {
1573
+ <TValues extends Record<string, any> = any, TPath extends FieldPath<TValues> | PathSegments = FieldPath<TValues> | PathSegments>(props: SelectProps<TValues, TPath> & React.RefAttributes<HTMLSelectElement>): React.ReactElement | null;
1574
+ };
596
1575
  declare const Select: SelectComponent;
597
1576
 
598
- export { Checkbox, CheckboxGroupContext, CheckboxGroupProvider, Field, FieldError, FieldPath, Form, FormContext, Form$1 as FormInstance, FormProvider, Name, Options, Path, PathValueOf, Select, ValidationMode, Validator, createFormContext, fieldErrorId, subscribe, useCanSubmit, useCheckboxGroupContext, useDirtyFields, useError, useErrorByPath, useField, useFieldArray, useFieldArrayItem, useFieldErrors, useFieldErrorsByPath, useForm, useFormContext, useHasErrors, useIsDirty, useIsSubmitting, useSubmitCount, useTouched, useTouchedByPath, useTouchedFields, useValue, useValueByPath, useWatch };
599
- export type { FieldRules, SubscribeEvent, SubscribeOptions, WatchScope };
1577
+ export { Checkbox, CheckboxGroupContext, CheckboxGroupProvider, Field, FieldError, FieldErrorEntry, FieldPath, Form, FormContext, FormEvents, FormField, Form$1 as FormInstance, FormProvider, Name, Options, Path, PathSegments, PathValueOf, Select, SyncValidator, ValidationMode, Validator, changeValue, changeValueByPath, createFormContext, emitChangeByPath, fieldErrorId, getDirtyFields, getFieldState, getTouchedFields, getValue, getValueByPath, getValues, handleSubmit, hasTouched, hasTouchedByPath, incrementSubmitCount, isDirty, isFieldDirtyByPath, isTouched, registerFieldMode, removeField, removeFieldByPath, reset, resetField, seedValueByPath, setDisabled, setInitialValues, setIsSubmitting, setStatus, setSubmitSuccessful, setTouched, setTouchedByPath, setValue, setValueByPath, subscribe, unregisterFieldMode, useCanSubmit, useCheckboxGroupContext, useDirtyFields, useError, useErrorByPath, useField, useFieldArray, useFieldArrayItem, useFieldErrors, useFieldErrorsByPath, useForm, useFormContext, useFormError, useFormErrors, useFormState, useHasErrors, useIsDirty, useIsFieldDirty, useIsFieldDirtyByPath, useIsLoading, useIsSubmitSuccessful, useIsSubmitting, useIsValid, useIsValidating, useStatus, useSubmitCount, useTouched, useTouchedByPath, useTouchedFields, useTransform, useValue, useValueByPath, useWatch, useWatchCore, userBlur, userChangeByPath };
1578
+ export type { FieldRules, FieldState, FormState, HandleSubmitOptions, RemoveFieldOptions, ResetFieldOptions, ResetOptions, SetFieldOptions, SubscribeEvent, SubscribeOptions, UseTransformOptions, UseValueOptions, WatchScope };