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 +173 -0
- package/dist/{createForm-jlzK2lCG.d.cts → createForm-B73p1TgL.d.cts} +17 -6
- package/dist/{createForm-jlzK2lCG.d.ts → createForm-B73p1TgL.d.ts} +17 -6
- package/dist/devtools/index.d.cts +1 -1
- package/dist/devtools/index.d.ts +1 -1
- package/dist/index.cjs +142 -48
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -23
- package/dist/index.d.ts +45 -23
- package/dist/index.js +141 -50
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
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 :
|
|
41
|
-
[K in keyof T &
|
|
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<
|
|
172
|
-
validateFieldAsync: (path: ErrorPath<z.input<TSchema>, D>) => Promise<
|
|
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,
|
|
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
|
|
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 :
|
|
41
|
-
[K in keyof T &
|
|
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<
|
|
172
|
-
validateFieldAsync: (path: ErrorPath<z.input<TSchema>, D>) => Promise<
|
|
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,
|
|
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-
|
|
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";
|
package/dist/devtools/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { F as Form } from '../createForm-
|
|
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";
|