formstand 0.16.0 → 0.18.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,178 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.18.0 — 2026-09-17
4
+
5
+ ### Changed
6
+
7
+ - **`PersistHandle.restore()` is now `load()`** (breaking). The method's
8
+ DEFAULT application is `adoptValues` — a rebase that reads clean — and
9
+ the old name promised the setValues semantics it only has under
10
+ `apply: "restore"`. The name now describes what it does; the `apply`
11
+ mode names are unchanged. `usePersistForm`'s handle follows.
12
+ - **Cleared inputs write `emptyValue` whenever the schema accepts it.**
13
+ `textInputProps`/`selectProps` (and the bound `TextField`/`SelectField`)
14
+ used to write the empty value only for nullable fields, so clearing
15
+ `z.string().optional()` left `""` behind — a documented asymmetry that
16
+ kept the field dirty against an `undefined` initial and made an optional
17
+ enum select unclearable. Clearing now writes `undefined` for optional
18
+ and defaulted fields and `null` for nullable ones; a REQUIRED string
19
+ cleared to `""` still stays `""`, so the schema judges a visible value
20
+ instead of a hole it rejects. `SelectField`'s empty option is
21
+ accordingly selectable for every clearable field, not just nullable
22
+ ones.
23
+
24
+ ### Added
25
+
26
+ - **`field.clearable`** on `UseFieldReturn`: whether the schema accepts
27
+ the field's `emptyValue` (optional, nullable, or defaulted),
28
+ introspected from the zod schema with the same shallow walk as
29
+ `emptyValue` so the pair can never disagree. Schema-less forms fall
30
+ back to the null-initial heuristic. **`isClearableSchema(schema)`** is
31
+ the exported rule behind it, next to `emptyValueForSchema`.
32
+
33
+ ## formstand-cli 0.18.0 — 2026-09-17
34
+
35
+ ### Changed
36
+
37
+ - **Generated kit adapters clear through `field.clearable`.** The
38
+ emitted text and select bindings wrote the empty value only for
39
+ nullable fields, mirroring the library's old rule; they now write
40
+ `field.emptyValue` whenever `field.clearable` says the schema accepts
41
+ it, so generated optional fields clear to `undefined` instead of
42
+ holding `""`. Kit output therefore needs formstand 0.18; regenerate
43
+ to pick the rule up, or keep the old adapter — both compile.
44
+
45
+ ## formstand-cli 0.17.0 — 2026-09-17
46
+
47
+ ### Added
48
+
49
+ - **Containers inside array rows generate.** The remaining row-shape
50
+ TODO matrix is gone (formstand 0.17 types the paths): a tuple as the
51
+ row item or as a row-object field binds its positions inline at static
52
+ sub-indices (`points.${index}.0`, `segments.${index}.span.1`); a
53
+ discriminated union as a row-object FIELD binds on the holed template
54
+ (`invoices.${p0}.pay`), optional/nullable ones keeping the clearable
55
+ select; an array-of-arrays item extracts an inner Rows component; and
56
+ the same shapes under nested arrays work at any depth, union items
57
+ included (`teams.${p0}.methods.${index}`). Single-file extracts a
58
+ child component per site that needs hooks (rows render inside
59
+ rows.map); the module layout binds in the Row component, which already
60
+ is one. The one shape that still degrades to a TODO is a container
61
+ inside a union variant — binding it needs variant sub-paths the
62
+ library does not type.
63
+
64
+ ## 0.17.0 — 2026-09-17
65
+
66
+ ### Added
67
+
68
+ - **`form.addErrors(errors)`.** The merge-many sibling of `setError`:
69
+ takes a server response's own runtime-keyed error map as-is and merges
70
+ it into the server channel — no per-key `FieldPath` cast, no
71
+ `setErrors` wholesale replacement. An empty array removes its key,
72
+ like `setError`. The docs' own examples now use it.
73
+ - **`SubmitOptions.onError` and a dev-mode swallowed-failure warning.**
74
+ A throwing submit handler resolves `{kind: "error"}` writing no state
75
+ anywhere, so the fire-and-forget `handleSubmit` form could swallow a
76
+ save failure completely — button re-enables, zero feedback. `onError`
77
+ is the save-failure hook mirroring `onInvalid`, and dev builds warn
78
+ when an unobserved handler failure resolves without one.
79
+ - **`useFieldArray` parity with its siblings.** The return gains `path`,
80
+ `firstError`, and the array-level server channel (`setError` /
81
+ `clearError`) — a "too many rows" verdict from the API is set and
82
+ cleared from the hook that owns the array. Custom `FieldArrayFormApi`
83
+ implementations opt in via the optional `setError`/`clearErrors`
84
+ members (same contract as the optional `validateField`).
85
+ - **`useIsValidating(form, path?)`.** The boolean-only in-flight flag,
86
+ form-level (whole-form pass or any field) or scoped to a subtree —
87
+ previously reachable only through a selector, asymmetric with
88
+ `useIsSubmitting`.
89
+ - **`usePersistForm(form, options)`.** The React lifecycle wrapper
90
+ `persistForm` was missing: owns the mount/dispose effect (StrictMode
91
+ safe), returns a reference-stable handle safe to close over in submit
92
+ handlers, and reads options when the subscription starts (the
93
+ `useForm` locked-options rule).
94
+ - **`createFormHooks` binds the newer hooks.** `use{Name}Values`,
95
+ `use{Name}Fields` (position-typed like the plain `useFields`), and
96
+ `use{Name}IsValidating` join the factory.
97
+
98
+ ### Fixed
99
+
100
+ - **`numberInputProps` keeps the value on a partial entry.** The
101
+ `type="number"` builder wrote `emptyValue` for BOTH empty and invalid
102
+ text, so a transient "-" or "1e" nulled the field mid-keystroke
103
+ (error flash, dirty flip) — diverging from `useNumberInput`'s
104
+ deliberate keep-the-value semantics. Invalid now keeps the stored
105
+ value; empty still clears. (Browsers report `""` for badInput on
106
+ number inputs, so `useNumberInput` remains the binding that preserves
107
+ every keystroke.)
108
+ - **Tuples resolve positionally in the typed paths.** Tuples fell into
109
+ the generic-array arms of `FieldPath` and `UnionValueAt`, which union
110
+ every element — so nested paths under heterogeneous tuples were
111
+ rejected (`"hetero.0.a"` unbindable), out-of-range indices
112
+ (`"coord.5"`) accepted with a lying element type, and a discriminated
113
+ union below a tuple position unbindable through `useVariantField`.
114
+ Both types gained a tuple arm keyed on the literal indices; `"coord.0"`
115
+ spellings the CLI generates are unchanged.
116
+ - **Platform containers are path leaves.** `File`/`Blob` (matched
117
+ structurally, so no DOM lib requirement), `Map`, `Set`, `WeakMap`,
118
+ `WeakSet`, `Promise`, and functions no longer descend as records:
119
+ bogus sub-paths like `"file.name"` or `"meta.size"` used to
120
+ type-check, and a `setValue` through one would have spread the
121
+ instance into a plain object.
122
+ - **Literal dotted keys are no longer offered as paths.** A key named
123
+ `"a.b"` appeared in `FieldPath` but resolved to `never` (the runtime
124
+ walk splits on `"."`), so the offer was the lie; it is now excluded
125
+ where it is offered rather than where it resolves.
126
+ - **`validateField` no longer crashes on prototype-key paths.** The
127
+ schema walk read the ZodObject shape with a bare index, so a
128
+ runtime-built path like `"user.constructor.x"` (server error fields
129
+ mapped onto `validateField`) resolved Object's constructor as a
130
+ "schema" and threw — and the subschema cache kept the poisoned entry.
131
+ Both walks now do own-key reads, like every other walk in the library.
132
+ - **Persist discards version-downgrade drafts instead of adopting the
133
+ wrapper.** A draft written with `version: n` is a `{__v, values}`
134
+ wrapper; if the app later shipped without the `version` option, the
135
+ wrapper's keys evaded the shape guard and the wrapper OBJECT became
136
+ the form's values, then re-persisted. A versioned draft under a
137
+ version-less config is now discarded like any other draft the config
138
+ cannot vouch for.
139
+ - **Debounced validation no longer survives `reset()`.** A pending
140
+ debounce timer fired after `reset()`/`adoptValues()` and re-committed
141
+ errors onto the pristine form. The fire now bails when the form is
142
+ pristine (values is the initialValues reference) or when the path's
143
+ value changed since scheduling; an unrelated field's edit inside the
144
+ window still lets the pending validation run.
145
+ - **Array ops accept a null-valued nullable array.** `arrayPush` on a
146
+ `.nullable()` array field holding `null` warned and silently no-op'd,
147
+ while `undefined` created the array — even though the op item types
148
+ are built on `NonNullable<...>` precisely so nullable arrays accept
149
+ ops. Both empties now start the op from `[]`.
150
+
151
+ ### Changed
152
+
153
+ - **Awaited async validation is typed settled.** `validateAsync` and
154
+ `validateFieldAsync` (and `useField`'s `validateAsync`) resolved a
155
+ union carrying a `"pending"` arm that can never occur — the promise IS
156
+ the pending state — forcing every exhaustive `switch` to carry a dead
157
+ case. All three now resolve the `Settled*` result types
158
+ `validateFieldsAsync` always had. A `switch` that handled `"pending"`
159
+ on an awaited result will now fail to compile; delete the dead arm.
160
+
161
+ ## formstand-cli 0.16.0 — 2026-09-16
162
+
163
+ ### Added
164
+
165
+ - **Union array rows generate.** A discriminated union that is an
166
+ array's row item — the shape the airfield-maps trial hand-wrote — now
167
+ compiles to a `{Stem}Row` component per row instead of a TODO, in
168
+ both layouts: the discriminant and common fields bind with the field
169
+ hook, variant-only fields with the variant hook, all on the
170
+ row-indexed path (`methods.${index}`), with the same conditional
171
+ variant blocks, fragment elision, and hoisted number-props hooks a
172
+ static union gets. Needs formstand 0.16 for the row-indexed variant
173
+ path types. A union or tuple nested as a FIELD inside a row object,
174
+ and a tuple row item, keep their TODOs.
175
+
3
176
  ## 0.16.0 — 2026-09-16
4
177
 
5
178
  ### Added
@@ -1,9 +1,15 @@
1
1
  import { z } from 'zod';
2
2
  import { StoreApi } from 'zustand/vanilla';
3
3
 
4
- type LeafType = string | number | boolean | bigint | symbol | null | undefined | Date | RegExp;
4
+ type BlobLike = Readonly<{
5
+ size: number;
6
+ type: string;
7
+ arrayBuffer: () => Promise<unknown>;
8
+ }>;
9
+ type LeafType = string | number | boolean | bigint | symbol | null | undefined | Date | RegExp | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown> | WeakMap<object, unknown> | WeakSet<object> | Promise<unknown> | ((...args: never[]) => unknown) | BlobLike;
5
10
  type IsRecord<T> = T extends LeafType ? false : T extends readonly unknown[] ? false : T extends object ? true : false;
6
11
  type IsArray<T> = T extends readonly unknown[] ? true : false;
12
+ type IsTuple<T> = T extends readonly unknown[] ? number extends T["length"] ? false : true : false;
7
13
  type Prev = [
8
14
  never,
9
15
  0,
@@ -37,8 +43,10 @@ type PathDepth = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14
37
43
  type IsUnion<T, U = T> = [T] extends [never] ? false : T extends unknown ? [U] extends [T] ? false : true : never;
38
44
  type NormalizeDepth<D extends number> = number extends D ? DefaultPathDepth : [D] extends [PathDepth] ? IsUnion<D> extends true ? DefaultPathDepth : D : DefaultPathDepth;
39
45
  type FieldPath<T, D extends number = DefaultPathDepth> = FieldPathRec<T, NormalizeDepth<D>>;
40
- type FieldPathRec<T, D extends number> = [D] extends [0] ? never : IsArray<T> extends true ? T extends readonly (infer U)[] ? `${number}` | (IsRecord<NonNullable<U>> extends true ? `${number}.${FieldPathRec<NonNullable<U>, Prev[D]>}` : IsArray<NonNullable<U>> extends true ? `${number}.${FieldPathRec<NonNullable<U>, Prev[D]>}` : never) : never : IsRecord<T> extends true ? {
41
- [K in keyof T & string]: K | (IsRecord<NonNullable<T[K]>> extends true ? `${K}.${FieldPathRec<NonNullable<T[K]>, Prev[D]>}` : IsArray<NonNullable<T[K]>> extends true ? `${K}.${FieldPathRec<NonNullable<T[K]>, Prev[D]>}` : never);
46
+ type FieldPathRec<T, D extends number> = [D] extends [0] ? never : IsTuple<T> extends true ? {
47
+ [K in keyof T & `${number}`]: K | (IsRecord<NonNullable<T[K]>> extends true ? `${K}.${FieldPathRec<NonNullable<T[K]>, Prev[D]>}` : IsArray<NonNullable<T[K]>> extends true ? `${K}.${FieldPathRec<NonNullable<T[K]>, Prev[D]>}` : never);
48
+ }[keyof T & `${number}`] : IsArray<T> extends true ? T extends readonly (infer U)[] ? `${number}` | (IsRecord<NonNullable<U>> extends true ? `${number}.${FieldPathRec<NonNullable<U>, Prev[D]>}` : IsArray<NonNullable<U>> extends true ? `${number}.${FieldPathRec<NonNullable<U>, Prev[D]>}` : never) : never : IsRecord<T> extends true ? {
49
+ [K in keyof T & string]: K extends `${string}.${string}` ? never : K | (IsRecord<NonNullable<T[K]>> extends true ? `${K}.${FieldPathRec<NonNullable<T[K]>, Prev[D]>}` : IsArray<NonNullable<T[K]>> extends true ? `${K}.${FieldPathRec<NonNullable<T[K]>, Prev[D]>}` : never);
42
50
  }[keyof T & string] : never;
43
51
  type StepValue<T, K extends string> = T extends readonly (infer U)[] ? K extends keyof T ? T[K] : K extends `${number}` ? U : never : T extends object ? K extends keyof T ? T[K] : never : never;
44
52
  type FieldValue<T, P extends string> = [T] extends [NonNullable<T>] ? P extends `${infer Head}.${infer Tail}` ? FieldValue<StepValue<T, Head>, Tail> : StepValue<T, P> : FieldValue<NonNullable<T>, P> | undefined;
@@ -100,6 +108,7 @@ declare const validateSync: <TSchema extends z.ZodType>(schema: TSchema, values:
100
108
  declare const validateAsync: <TSchema extends z.ZodType>(schema: TSchema, values: z.input<TSchema>) => Promise<SettledValidationResult<z.output<TSchema>>>;
101
109
  declare const isAsyncRequiredError: (e: unknown) => boolean;
102
110
  declare const emptyValueForSchema: (schema: z.ZodType) => null | undefined;
111
+ declare const isClearableSchema: (schema: z.ZodType) => boolean;
103
112
 
104
113
  type ReadonlyStoreApi<T> = Pick<StoreApi<T>, "getState" | "getInitialState" | "subscribe">;
105
114
  type CreateFormOptions<TSchema extends z.ZodType, D extends PathDepth = DefaultPathDepth> = Readonly<{
@@ -114,6 +123,7 @@ type SubmitHandler<TSchema extends z.ZodType> = (data: z.output<TSchema>) => voi
114
123
  type InvalidSubmitHandler = (errors: ErrorMap) => void;
115
124
  type SubmitOptions = Readonly<{
116
125
  force?: boolean;
126
+ onError?: (error: unknown) => void;
117
127
  }>;
118
128
  type SubmitResult<TOutput> = Readonly<{
119
129
  kind: "valid";
@@ -159,6 +169,7 @@ type Form<TSchema extends z.ZodType, D extends PathDepth = DefaultPathDepth> = R
159
169
  setReValidateMode: (mode: ValidationMode) => void;
160
170
  setError: (path: ErrorPath<z.input<TSchema>, D>, errors: string | readonly string[]) => void;
161
171
  setErrors: (errors: ErrorMap) => void;
172
+ addErrors: (errors: ErrorMap) => void;
162
173
  clearErrors: (path?: ErrorPath<z.input<TSchema>, D>) => void;
163
174
  updateState: (updater: (state: FormState<z.input<TSchema>>) => Partial<Omit<FormState<z.input<TSchema>>, "errors">>) => void;
164
175
  reset: (nextInitial?: Partial<z.input<TSchema>>, options?: ResetOptions) => void;
@@ -168,8 +179,8 @@ type Form<TSchema extends z.ZodType, D extends PathDepth = DefaultPathDepth> = R
168
179
  validate: () => ValidationResult<z.output<TSchema>>;
169
180
  validateField: (path: ErrorPath<z.input<TSchema>, D>) => FieldValidationResult;
170
181
  validateFields: (paths: readonly FieldPath<z.input<TSchema>, D>[]) => FieldsValidationResult;
171
- validateAsync: () => Promise<ValidationResult<z.output<TSchema>>>;
172
- validateFieldAsync: (path: ErrorPath<z.input<TSchema>, D>) => Promise<FieldValidationResult>;
182
+ validateAsync: () => Promise<SettledValidationResult<z.output<TSchema>>>;
183
+ validateFieldAsync: (path: ErrorPath<z.input<TSchema>, D>) => Promise<SettledFieldValidationResult>;
173
184
  validateFieldsAsync: (paths: readonly FieldPath<z.input<TSchema>, D>[]) => Promise<SettledFieldsValidationResult>;
174
185
  submit: (onValid: SubmitHandler<TSchema>, onInvalid?: InvalidSubmitHandler, options?: SubmitOptions) => Promise<SubmitResult<z.output<TSchema>>>;
175
186
  arrayPush: <P extends FieldPath<z.input<TSchema>, D>>(path: P, item: ArrayItemOf<NonNullable<FieldValue<z.input<TSchema>, P>>>) => void;
@@ -187,4 +198,4 @@ type Form<TSchema extends z.ZodType, D extends PathDepth = DefaultPathDepth> = R
187
198
  }>;
188
199
  declare const createForm: <TSchema extends z.ZodType, D extends PathDepth = DefaultPathDepth>(schema: TSchema, options: CreateFormOptions<TSchema, D>) => Form<TSchema, D>;
189
200
 
190
- export { type BoolMap as B, type CreateFormOptions as C, type DefaultPathDepth as D, type ErrorMap as E, type Form as F, type InvalidSubmitHandler as I, type PathDepth as P, type ReadonlyStoreApi as R, type SettledFieldValidationResult as S, type ValidationMode as V, type FieldValidationResult as a, type FormState as b, type FieldPath as c, type FieldValue as d, type FieldSnapshot as e, type FieldsValidationResult as f, type ResetOptions as g, type SettledFieldsValidationResult as h, type SettledValidationResult as i, type SubmitHandler as j, type SubmitOptions as k, type SubmitResult as l, type ValidationResult as m, type ValidationTrigger as n, createForm as o, emptyValueForSchema as p, flattenIssues as q, isAsyncRequiredError as r, shouldValidateOn as s, validateSync as t, validateAsync as v };
201
+ export { type BoolMap as B, type CreateFormOptions as C, type DefaultPathDepth as D, type ErrorMap as E, type Form as F, type InvalidSubmitHandler as I, type PathDepth as P, type ReadonlyStoreApi as R, type SettledFieldValidationResult as S, type ValidationMode as V, type FieldValidationResult as a, type FormState as b, type FieldPath as c, type FieldValue as d, type FieldSnapshot as e, type FieldsValidationResult as f, type ResetOptions as g, type SettledFieldsValidationResult as h, type SettledValidationResult as i, type SubmitHandler as j, type SubmitOptions as k, type SubmitResult as l, type ValidationResult as m, type ValidationTrigger as n, createForm as o, emptyValueForSchema as p, flattenIssues as q, isAsyncRequiredError as r, isClearableSchema as s, shouldValidateOn as t, validateSync as u, validateAsync as v };
@@ -1,9 +1,15 @@
1
1
  import { z } from 'zod';
2
2
  import { StoreApi } from 'zustand/vanilla';
3
3
 
4
- type LeafType = string | number | boolean | bigint | symbol | null | undefined | Date | RegExp;
4
+ type BlobLike = Readonly<{
5
+ size: number;
6
+ type: string;
7
+ arrayBuffer: () => Promise<unknown>;
8
+ }>;
9
+ type LeafType = string | number | boolean | bigint | symbol | null | undefined | Date | RegExp | ReadonlyMap<unknown, unknown> | ReadonlySet<unknown> | WeakMap<object, unknown> | WeakSet<object> | Promise<unknown> | ((...args: never[]) => unknown) | BlobLike;
5
10
  type IsRecord<T> = T extends LeafType ? false : T extends readonly unknown[] ? false : T extends object ? true : false;
6
11
  type IsArray<T> = T extends readonly unknown[] ? true : false;
12
+ type IsTuple<T> = T extends readonly unknown[] ? number extends T["length"] ? false : true : false;
7
13
  type Prev = [
8
14
  never,
9
15
  0,
@@ -37,8 +43,10 @@ type PathDepth = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14
37
43
  type IsUnion<T, U = T> = [T] extends [never] ? false : T extends unknown ? [U] extends [T] ? false : true : never;
38
44
  type NormalizeDepth<D extends number> = number extends D ? DefaultPathDepth : [D] extends [PathDepth] ? IsUnion<D> extends true ? DefaultPathDepth : D : DefaultPathDepth;
39
45
  type FieldPath<T, D extends number = DefaultPathDepth> = FieldPathRec<T, NormalizeDepth<D>>;
40
- type FieldPathRec<T, D extends number> = [D] extends [0] ? never : IsArray<T> extends true ? T extends readonly (infer U)[] ? `${number}` | (IsRecord<NonNullable<U>> extends true ? `${number}.${FieldPathRec<NonNullable<U>, Prev[D]>}` : IsArray<NonNullable<U>> extends true ? `${number}.${FieldPathRec<NonNullable<U>, Prev[D]>}` : never) : never : IsRecord<T> extends true ? {
41
- [K in keyof T & string]: K | (IsRecord<NonNullable<T[K]>> extends true ? `${K}.${FieldPathRec<NonNullable<T[K]>, Prev[D]>}` : IsArray<NonNullable<T[K]>> extends true ? `${K}.${FieldPathRec<NonNullable<T[K]>, Prev[D]>}` : never);
46
+ type FieldPathRec<T, D extends number> = [D] extends [0] ? never : IsTuple<T> extends true ? {
47
+ [K in keyof T & `${number}`]: K | (IsRecord<NonNullable<T[K]>> extends true ? `${K}.${FieldPathRec<NonNullable<T[K]>, Prev[D]>}` : IsArray<NonNullable<T[K]>> extends true ? `${K}.${FieldPathRec<NonNullable<T[K]>, Prev[D]>}` : never);
48
+ }[keyof T & `${number}`] : IsArray<T> extends true ? T extends readonly (infer U)[] ? `${number}` | (IsRecord<NonNullable<U>> extends true ? `${number}.${FieldPathRec<NonNullable<U>, Prev[D]>}` : IsArray<NonNullable<U>> extends true ? `${number}.${FieldPathRec<NonNullable<U>, Prev[D]>}` : never) : never : IsRecord<T> extends true ? {
49
+ [K in keyof T & string]: K extends `${string}.${string}` ? never : K | (IsRecord<NonNullable<T[K]>> extends true ? `${K}.${FieldPathRec<NonNullable<T[K]>, Prev[D]>}` : IsArray<NonNullable<T[K]>> extends true ? `${K}.${FieldPathRec<NonNullable<T[K]>, Prev[D]>}` : never);
42
50
  }[keyof T & string] : never;
43
51
  type StepValue<T, K extends string> = T extends readonly (infer U)[] ? K extends keyof T ? T[K] : K extends `${number}` ? U : never : T extends object ? K extends keyof T ? T[K] : never : never;
44
52
  type FieldValue<T, P extends string> = [T] extends [NonNullable<T>] ? P extends `${infer Head}.${infer Tail}` ? FieldValue<StepValue<T, Head>, Tail> : StepValue<T, P> : FieldValue<NonNullable<T>, P> | undefined;
@@ -100,6 +108,7 @@ declare const validateSync: <TSchema extends z.ZodType>(schema: TSchema, values:
100
108
  declare const validateAsync: <TSchema extends z.ZodType>(schema: TSchema, values: z.input<TSchema>) => Promise<SettledValidationResult<z.output<TSchema>>>;
101
109
  declare const isAsyncRequiredError: (e: unknown) => boolean;
102
110
  declare const emptyValueForSchema: (schema: z.ZodType) => null | undefined;
111
+ declare const isClearableSchema: (schema: z.ZodType) => boolean;
103
112
 
104
113
  type ReadonlyStoreApi<T> = Pick<StoreApi<T>, "getState" | "getInitialState" | "subscribe">;
105
114
  type CreateFormOptions<TSchema extends z.ZodType, D extends PathDepth = DefaultPathDepth> = Readonly<{
@@ -114,6 +123,7 @@ type SubmitHandler<TSchema extends z.ZodType> = (data: z.output<TSchema>) => voi
114
123
  type InvalidSubmitHandler = (errors: ErrorMap) => void;
115
124
  type SubmitOptions = Readonly<{
116
125
  force?: boolean;
126
+ onError?: (error: unknown) => void;
117
127
  }>;
118
128
  type SubmitResult<TOutput> = Readonly<{
119
129
  kind: "valid";
@@ -159,6 +169,7 @@ type Form<TSchema extends z.ZodType, D extends PathDepth = DefaultPathDepth> = R
159
169
  setReValidateMode: (mode: ValidationMode) => void;
160
170
  setError: (path: ErrorPath<z.input<TSchema>, D>, errors: string | readonly string[]) => void;
161
171
  setErrors: (errors: ErrorMap) => void;
172
+ addErrors: (errors: ErrorMap) => void;
162
173
  clearErrors: (path?: ErrorPath<z.input<TSchema>, D>) => void;
163
174
  updateState: (updater: (state: FormState<z.input<TSchema>>) => Partial<Omit<FormState<z.input<TSchema>>, "errors">>) => void;
164
175
  reset: (nextInitial?: Partial<z.input<TSchema>>, options?: ResetOptions) => void;
@@ -168,8 +179,8 @@ type Form<TSchema extends z.ZodType, D extends PathDepth = DefaultPathDepth> = R
168
179
  validate: () => ValidationResult<z.output<TSchema>>;
169
180
  validateField: (path: ErrorPath<z.input<TSchema>, D>) => FieldValidationResult;
170
181
  validateFields: (paths: readonly FieldPath<z.input<TSchema>, D>[]) => FieldsValidationResult;
171
- validateAsync: () => Promise<ValidationResult<z.output<TSchema>>>;
172
- validateFieldAsync: (path: ErrorPath<z.input<TSchema>, D>) => Promise<FieldValidationResult>;
182
+ validateAsync: () => Promise<SettledValidationResult<z.output<TSchema>>>;
183
+ validateFieldAsync: (path: ErrorPath<z.input<TSchema>, D>) => Promise<SettledFieldValidationResult>;
173
184
  validateFieldsAsync: (paths: readonly FieldPath<z.input<TSchema>, D>[]) => Promise<SettledFieldsValidationResult>;
174
185
  submit: (onValid: SubmitHandler<TSchema>, onInvalid?: InvalidSubmitHandler, options?: SubmitOptions) => Promise<SubmitResult<z.output<TSchema>>>;
175
186
  arrayPush: <P extends FieldPath<z.input<TSchema>, D>>(path: P, item: ArrayItemOf<NonNullable<FieldValue<z.input<TSchema>, P>>>) => void;
@@ -187,4 +198,4 @@ type Form<TSchema extends z.ZodType, D extends PathDepth = DefaultPathDepth> = R
187
198
  }>;
188
199
  declare const createForm: <TSchema extends z.ZodType, D extends PathDepth = DefaultPathDepth>(schema: TSchema, options: CreateFormOptions<TSchema, D>) => Form<TSchema, D>;
189
200
 
190
- export { type BoolMap as B, type CreateFormOptions as C, type DefaultPathDepth as D, type ErrorMap as E, type Form as F, type InvalidSubmitHandler as I, type PathDepth as P, type ReadonlyStoreApi as R, type SettledFieldValidationResult as S, type ValidationMode as V, type FieldValidationResult as a, type FormState as b, type FieldPath as c, type FieldValue as d, type FieldSnapshot as e, type FieldsValidationResult as f, type ResetOptions as g, type SettledFieldsValidationResult as h, type SettledValidationResult as i, type SubmitHandler as j, type SubmitOptions as k, type SubmitResult as l, type ValidationResult as m, type ValidationTrigger as n, createForm as o, emptyValueForSchema as p, flattenIssues as q, isAsyncRequiredError as r, shouldValidateOn as s, validateSync as t, validateAsync as v };
201
+ export { type BoolMap as B, type CreateFormOptions as C, type DefaultPathDepth as D, type ErrorMap as E, type Form as F, type InvalidSubmitHandler as I, type PathDepth as P, type ReadonlyStoreApi as R, type SettledFieldValidationResult as S, type ValidationMode as V, type FieldValidationResult as a, type FormState as b, type FieldPath as c, type FieldValue as d, type FieldSnapshot as e, type FieldsValidationResult as f, type ResetOptions as g, type SettledFieldsValidationResult as h, type SettledValidationResult as i, type SubmitHandler as j, type SubmitOptions as k, type SubmitResult as l, type ValidationResult as m, type ValidationTrigger as n, createForm as o, emptyValueForSchema as p, flattenIssues as q, isAsyncRequiredError as r, isClearableSchema as s, shouldValidateOn as t, validateSync as u, validateAsync as v };
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { z } from 'zod';
3
- import { F as Form } from '../createForm-jlzK2lCG.cjs';
3
+ import { F as Form } from '../createForm-B73p1TgL.cjs';
4
4
  import 'zustand/vanilla';
5
5
 
6
6
  type DevtoolsPosition = "bottom-right" | "bottom-left" | "top-right" | "top-left";
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { z } from 'zod';
3
- import { F as Form } from '../createForm-jlzK2lCG.js';
3
+ import { F as Form } from '../createForm-B73p1TgL.js';
4
4
  import 'zustand/vanilla';
5
5
 
6
6
  type DevtoolsPosition = "bottom-right" | "bottom-left" | "top-right" | "top-left";