attaform 0.27.6 → 0.29.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/dist/abstract.d.mts +5 -4
- package/dist/abstract.mjs +4 -3
- package/dist/chunks/fingerprint.mjs +1 -2
- package/dist/chunks/fingerprint2.mjs +2 -3
- package/dist/dev/abstract.mjs +4 -0
- package/dist/{chunks → dev/chunks}/dev-key-collision-warnings.mjs +0 -1
- package/dist/{chunks → dev/chunks}/devtools.mjs +5 -6
- package/dist/{chunks/fingerprint.cjs → dev/chunks/fingerprint.mjs} +7 -10
- package/dist/{chunks/fingerprint2.cjs → dev/chunks/fingerprint2.mjs} +32 -35
- package/dist/dev/directive.mjs +1 -0
- package/dist/dev/history.mjs +89 -0
- package/dist/dev/index.mjs +5 -0
- package/dist/dev/runtime/plugins/attaform.mjs +40 -0
- package/dist/dev/shared/attaform-dev.A-TpJW0B.mjs +207 -0
- package/dist/dev/shared/attaform-dev.BO-71R54.mjs +820 -0
- package/dist/{shared/attaform.D6tk90Rc.cjs → dev/shared/attaform-dev.BgM6FdtA.mjs} +324 -73
- package/dist/dev/shared/attaform-dev.ButTkwHd.mjs +375 -0
- package/dist/{shared/attaform.BJGA_UOS.mjs → dev/shared/attaform-dev.BxfsuwBR.mjs} +8 -1
- package/dist/{shared/attaform.nMaz2C5P.mjs → dev/shared/attaform-dev.D8aoKb89.mjs} +190 -400
- package/dist/dev/shared/attaform-dev.DD5m2W51.mjs +220 -0
- package/dist/{shared/attaform.CKH2lGdL.mjs → dev/shared/attaform-dev.DHuydLAC.mjs} +3867 -4731
- package/dist/{shared/attaform.DYEr28Pt.mjs → dev/shared/attaform-dev.DrzObAZo.mjs} +6 -7
- package/dist/{shared/attaform.B1ZYt2Li.mjs → dev/shared/attaform-dev.q6UutkCx.mjs} +274 -672
- package/dist/dev/zod-v3.mjs +17 -0
- package/dist/dev/zod-v4.mjs +16 -0
- package/dist/dev/zod.mjs +5 -0
- package/dist/directive.d.mts +20 -0
- package/dist/directive.mjs +1 -0
- package/dist/esbuild.mjs +0 -1
- package/dist/history.d.mts +59 -0
- package/dist/history.mjs +89 -0
- package/dist/index.d.mts +14 -6
- package/dist/index.mjs +5 -4
- package/dist/nuxt.d.mts +10 -10
- package/dist/nuxt.mjs +5 -2
- package/dist/rollup.mjs +0 -1
- package/dist/rspack.d.mts +6 -1
- package/dist/rspack.mjs +0 -1
- package/dist/runtime/components/AttaformDevtoolsPanel.vue +9 -8
- package/dist/runtime/plugins/attaform.mjs +1 -2
- package/dist/shared/{attaform.CoR4mWfv.mjs → attaform.B0dKL8ST.mjs} +309 -46
- package/dist/shared/{attaform.Cs2Rbdlo.mjs → attaform.BK0cgu2K.mjs} +123 -140
- package/dist/shared/{attaform.B9Wyhfro.cjs → attaform.BndjUUYX.mjs} +11 -16
- package/dist/shared/{attaform.CQN9R62B.cjs → attaform.BxfsuwBR.mjs} +9 -4
- package/dist/shared/attaform.C2MVyuxC.mjs +811 -0
- package/dist/shared/{attaform.Fp3sCrVs.d.ts → attaform.CIWLMY-R.d.mts} +2 -2
- package/dist/shared/attaform.CZMAYwSK.mjs +6383 -0
- package/dist/shared/attaform.CZYt_5N_.mjs +207 -0
- package/dist/shared/{attaform.DniawQLP.d.cts → attaform.CsoeRi3P.d.mts} +490 -98
- package/dist/shared/attaform.Cvao8bW5.mjs +358 -0
- package/dist/shared/attaform.D0x-qSXm.mjs +197 -0
- package/dist/shared/{attaform.D8kliaKw.cjs → attaform.D1fnTifF.mjs} +279 -692
- package/dist/shared/{attaform.CHlJLAiv.d.mts → attaform.DDtqHYv1.d.mts} +155 -184
- package/dist/shared/{attaform.Biytrv0-.cjs → attaform.DffRL5pP.mjs} +215 -547
- package/dist/shared/attaform.DhnPb6nK.mjs +0 -1
- package/dist/shared/attaform.KvlEedlF.mjs +0 -1
- package/dist/shared/attaform.axHXVQO7.d.mts +44 -0
- package/dist/shared/attaform.v0fQtWyA.mjs +0 -1
- package/dist/transforms.d.mts +0 -22
- package/dist/transforms.mjs +1 -2
- package/dist/vite.d.mts +30 -9
- package/dist/vite.mjs +27 -4
- package/dist/webpack.d.mts +6 -1
- package/dist/webpack.mjs +0 -1
- package/dist/zod-v3.d.mts +13 -6
- package/dist/zod-v3.mjs +17 -4
- package/dist/zod-v4.d.mts +19 -26
- package/dist/zod-v4.mjs +16 -4
- package/dist/zod.d.mts +4 -3
- package/dist/zod.mjs +5 -4
- package/package.json +38 -20
- package/skills/attaform/SKILL.md +6 -2
- package/skills/attaform/references/custom-components.md +7 -2
- package/skills/attaform/references/errors.md +8 -3
- package/skills/attaform/references/saving.md +77 -0
- package/skills/attaform/references/wizards.md +10 -8
- package/dist/abstract.cjs +0 -48
- package/dist/abstract.cjs.map +0 -1
- package/dist/abstract.d.cts +0 -42
- package/dist/abstract.d.ts +0 -42
- package/dist/abstract.mjs.map +0 -1
- package/dist/chunks/dev-key-collision-warnings.cjs +0 -25
- package/dist/chunks/dev-key-collision-warnings.cjs.map +0 -1
- package/dist/chunks/dev-key-collision-warnings.mjs.map +0 -1
- package/dist/chunks/devtools.cjs +0 -157
- package/dist/chunks/devtools.cjs.map +0 -1
- package/dist/chunks/devtools.mjs.map +0 -1
- package/dist/chunks/fingerprint.cjs.map +0 -1
- package/dist/chunks/fingerprint.mjs.map +0 -1
- package/dist/chunks/fingerprint2.cjs.map +0 -1
- package/dist/chunks/fingerprint2.mjs.map +0 -1
- package/dist/esbuild.cjs +0 -28
- package/dist/esbuild.cjs.map +0 -1
- package/dist/esbuild.d.cts +0 -56
- package/dist/esbuild.d.ts +0 -56
- package/dist/esbuild.mjs.map +0 -1
- package/dist/index.cjs +0 -51
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -249
- package/dist/index.d.ts +0 -249
- package/dist/index.mjs.map +0 -1
- package/dist/nuxt.cjs +0 -84
- package/dist/nuxt.cjs.map +0 -1
- package/dist/nuxt.d.cts +0 -66
- package/dist/nuxt.d.ts +0 -66
- package/dist/nuxt.mjs.map +0 -1
- package/dist/rollup.cjs +0 -24
- package/dist/rollup.cjs.map +0 -1
- package/dist/rollup.d.cts +0 -35
- package/dist/rollup.d.ts +0 -35
- package/dist/rollup.mjs.map +0 -1
- package/dist/rspack.cjs +0 -10
- package/dist/rspack.cjs.map +0 -1
- package/dist/rspack.d.cts +0 -40
- package/dist/rspack.d.ts +0 -40
- package/dist/rspack.mjs.map +0 -1
- package/dist/runtime/components/AttaformDevtoolsPanel.vue.d.ts +0 -7
- package/dist/runtime/components/DevtoolsValueTree.vue.d.ts +0 -35
- package/dist/runtime/plugins/attaform.cjs +0 -43
- package/dist/runtime/plugins/attaform.cjs.map +0 -1
- package/dist/runtime/plugins/attaform.d.cts +0 -5
- package/dist/runtime/plugins/attaform.d.ts +0 -5
- package/dist/runtime/plugins/attaform.mjs.map +0 -1
- package/dist/shared/attaform.B1ZYt2Li.mjs.map +0 -1
- package/dist/shared/attaform.B9Wyhfro.cjs.map +0 -1
- package/dist/shared/attaform.BGDV42hI.d.cts +0 -232
- package/dist/shared/attaform.BJGA_UOS.mjs.map +0 -1
- package/dist/shared/attaform.Biytrv0-.cjs.map +0 -1
- package/dist/shared/attaform.Bn0IzhD_.cjs +0 -800
- package/dist/shared/attaform.Bn0IzhD_.cjs.map +0 -1
- package/dist/shared/attaform.C9fPTxjB.d.cts +0 -41
- package/dist/shared/attaform.C9fPTxjB.d.ts +0 -41
- package/dist/shared/attaform.CKH2lGdL.mjs.map +0 -1
- package/dist/shared/attaform.CQN9R62B.cjs.map +0 -1
- package/dist/shared/attaform.CoR4mWfv.mjs.map +0 -1
- package/dist/shared/attaform.Cs2Rbdlo.mjs.map +0 -1
- package/dist/shared/attaform.D6tk90Rc.cjs.map +0 -1
- package/dist/shared/attaform.D8kliaKw.cjs.map +0 -1
- package/dist/shared/attaform.DLknk9nF.d.mts +0 -232
- package/dist/shared/attaform.DMxM2kol.mjs +0 -1275
- package/dist/shared/attaform.DMxM2kol.mjs.map +0 -1
- package/dist/shared/attaform.DRUT703x.d.cts +0 -56
- package/dist/shared/attaform.DRUT703x.d.ts +0 -56
- package/dist/shared/attaform.DYEr28Pt.mjs.map +0 -1
- package/dist/shared/attaform.DdQN7sgN.cjs +0 -1302
- package/dist/shared/attaform.DdQN7sgN.cjs.map +0 -1
- package/dist/shared/attaform.DhnPb6nK.mjs.map +0 -1
- package/dist/shared/attaform.DniawQLP.d.mts +0 -4763
- package/dist/shared/attaform.DniawQLP.d.ts +0 -4763
- package/dist/shared/attaform.DoQm_Vkd.cjs +0 -58
- package/dist/shared/attaform.DoQm_Vkd.cjs.map +0 -1
- package/dist/shared/attaform.DrvMscNX.cjs +0 -7697
- package/dist/shared/attaform.DrvMscNX.cjs.map +0 -1
- package/dist/shared/attaform.F2Q8iv38.d.ts +0 -2494
- package/dist/shared/attaform.FmqKO1Ex.d.cts +0 -2494
- package/dist/shared/attaform.KvlEedlF.mjs.map +0 -1
- package/dist/shared/attaform.RaTzp1WF.cjs +0 -26
- package/dist/shared/attaform.RaTzp1WF.cjs.map +0 -1
- package/dist/shared/attaform.nMaz2C5P.mjs.map +0 -1
- package/dist/shared/attaform.v0fQtWyA.mjs.map +0 -1
- package/dist/shared/attaform.yUrz7C2z.cjs +0 -29
- package/dist/shared/attaform.yUrz7C2z.cjs.map +0 -1
- package/dist/transforms.cjs +0 -12
- package/dist/transforms.cjs.map +0 -1
- package/dist/transforms.d.cts +0 -73
- package/dist/transforms.d.ts +0 -73
- package/dist/transforms.mjs.map +0 -1
- package/dist/vite.cjs +0 -363
- package/dist/vite.cjs.map +0 -1
- package/dist/vite.d.cts +0 -133
- package/dist/vite.d.ts +0 -133
- package/dist/vite.mjs.map +0 -1
- package/dist/webpack.cjs +0 -10
- package/dist/webpack.cjs.map +0 -1
- package/dist/webpack.d.cts +0 -37
- package/dist/webpack.d.ts +0 -37
- package/dist/webpack.mjs.map +0 -1
- package/dist/zod-v3.cjs +0 -53
- package/dist/zod-v3.cjs.map +0 -1
- package/dist/zod-v3.d.cts +0 -246
- package/dist/zod-v3.d.ts +0 -246
- package/dist/zod-v3.mjs.map +0 -1
- package/dist/zod-v4.cjs +0 -55
- package/dist/zod-v4.cjs.map +0 -1
- package/dist/zod-v4.d.cts +0 -172
- package/dist/zod-v4.d.ts +0 -172
- package/dist/zod-v4.mjs.map +0 -1
- package/dist/zod.cjs +0 -51
- package/dist/zod.cjs.map +0 -1
- package/dist/zod.d.cts +0 -7
- package/dist/zod.d.ts +0 -7
- package/dist/zod.mjs.map +0 -1
|
@@ -164,6 +164,65 @@ declare const ROOT_PATH_KEY: PathKey;
|
|
|
164
164
|
*/
|
|
165
165
|
declare function isPathPrefix(prefix: readonly Segment[], path: readonly Segment[]): boolean;
|
|
166
166
|
|
|
167
|
+
/**
|
|
168
|
+
* Per-path field status. Replaced wholesale (not mutated in place) on
|
|
169
|
+
* every change. Five semantic groups:
|
|
170
|
+
*
|
|
171
|
+
* - `connected` — is a DOM element registered for this path?
|
|
172
|
+
* - `focused` / `blurred` — DOM-state flags. `null` while no element
|
|
173
|
+
* is connected (no DOM means the concepts don't apply); plain
|
|
174
|
+
* booleans once connected, with the invariant `blurred === !focused`
|
|
175
|
+
* enforced by `markFocused`.
|
|
176
|
+
* - `touched` — focus/blur history, not DOM state. Always a plain
|
|
177
|
+
* boolean: `false` at registration, sticky `true` after first blur,
|
|
178
|
+
* cleared only by `form.reset()` / `form.resetField(path)`. Persists
|
|
179
|
+
* across disconnects so v-if'd-away fields don't lose their touched
|
|
180
|
+
* state on rehide (wizard "show review of touched fields" patterns
|
|
181
|
+
* rely on this).
|
|
182
|
+
* - `interacted` — value-mutation history, not DOM state. Plain
|
|
183
|
+
* boolean: `false` at registration, sticky `true` once the user
|
|
184
|
+
* issues a value edit through the directive's input listeners
|
|
185
|
+
* (never on hydration, default seeding, or programmatic setValue);
|
|
186
|
+
* cleared with `touched` by `form.reset()` / `form.resetField(path)`.
|
|
187
|
+
* - `blurredAfterInteraction` — the first blur that follows a value
|
|
188
|
+
* edit (the field has been edited and then left). Plain boolean,
|
|
189
|
+
* sticky `true`. A tab-through blur with no prior edit does NOT set
|
|
190
|
+
* it (`interacted` is still false at that blur). Composes
|
|
191
|
+
* `interacted` with the departure; drives the default display gate.
|
|
192
|
+
*/
|
|
193
|
+
type FieldRecord = {
|
|
194
|
+
readonly path: Path;
|
|
195
|
+
readonly updatedAt: string | null;
|
|
196
|
+
readonly connected: boolean;
|
|
197
|
+
readonly focused: boolean | null;
|
|
198
|
+
readonly blurred: boolean | null;
|
|
199
|
+
readonly touched: boolean;
|
|
200
|
+
readonly interacted: boolean;
|
|
201
|
+
readonly blurredAfterInteraction: boolean;
|
|
202
|
+
};
|
|
203
|
+
/** Per-path DOM element tracking. Client-only. */
|
|
204
|
+
type ElementRecord = {
|
|
205
|
+
/**
|
|
206
|
+
* Original Path captured at first registration. Stored alongside the
|
|
207
|
+
* elements Set so the DOM-order sort cache can recover the structured
|
|
208
|
+
* Path without round-tripping through `JSON.parse(pathKey)`.
|
|
209
|
+
*/
|
|
210
|
+
readonly path: Path;
|
|
211
|
+
readonly elements: Set<HTMLElement>;
|
|
212
|
+
};
|
|
213
|
+
/**
|
|
214
|
+
* Per-path record stored in `originals`. Pairing `segments` with the tracked
|
|
215
|
+
* value means `dirty` and `resetField`'s container loop don't have to
|
|
216
|
+
* `JSON.parse(pathKey)` on every iteration — the canonical Path is already
|
|
217
|
+
* sitting next to the value it belongs to. PathKey still keys the Map (the
|
|
218
|
+
* stable string is the only collision-free identifier), but downstream
|
|
219
|
+
* iteration reads `segments` directly.
|
|
220
|
+
*/
|
|
221
|
+
type OriginalsRecord = {
|
|
222
|
+
readonly segments: Path;
|
|
223
|
+
readonly value: unknown;
|
|
224
|
+
};
|
|
225
|
+
|
|
167
226
|
/** Internal brand for the `Unset` type. Never exposed at runtime. */
|
|
168
227
|
declare const _unsetBrand: unique symbol;
|
|
169
228
|
/**
|
|
@@ -300,6 +359,48 @@ type JoinSegments<S extends ReadonlyArray<string | number>, Acc extends string =
|
|
|
300
359
|
infer Head extends string | number,
|
|
301
360
|
...infer Rest extends ReadonlyArray<string | number>
|
|
302
361
|
] ? Acc extends '' ? JoinSegments<Rest, `${Head}`> : JoinSegments<Rest, `${Acc}.${Head}`> : Acc;
|
|
362
|
+
/**
|
|
363
|
+
* The advice half of a segment-array rejection, used when `S` never
|
|
364
|
+
* inferred a tuple at all.
|
|
365
|
+
*
|
|
366
|
+
* A caller who passes a plain `string` reaches this branch, because
|
|
367
|
+
* inference falls back to the constraint and `JoinSegments` of a
|
|
368
|
+
* non-tuple array is `''`. Naming a path would be a lie there, so the
|
|
369
|
+
* message names the remedies instead. This is the case behind #568: a
|
|
370
|
+
* row component received its path prefix as an untyped `string` prop,
|
|
371
|
+
* every concatenation widened to `string`, and the only signal was
|
|
372
|
+
* `segments: never`.
|
|
373
|
+
*/
|
|
374
|
+
type PlainStringAdvice = 'attaform: a plain string cannot be checked against the schema. Pass a literal path, type the dynamic prefix, or use the segment-array form.';
|
|
375
|
+
/**
|
|
376
|
+
* Why a segment array was rejected, as a type the compiler prints.
|
|
377
|
+
*
|
|
378
|
+
* Every segment-array overload brands its parameter
|
|
379
|
+
* `S & (<joined path is valid> ? unknown : <this>)`. The brand used to
|
|
380
|
+
* be `never`, and `S & never` is `never`, so TypeScript reported the
|
|
381
|
+
* parameter as `never` and said nothing about what was wrong. A string
|
|
382
|
+
* literal intersects without collapsing, so the sentence survives into
|
|
383
|
+
* the diagnostic and the argument keeps its inferred tuple type:
|
|
384
|
+
*
|
|
385
|
+
* ```
|
|
386
|
+
* Argument of type '["boxes", 3, "nope"]' is not assignable to parameter
|
|
387
|
+
* of type 'readonly ["boxes", 3, "nope"] &
|
|
388
|
+
* "attaform: 'boxes.3.nope' is not a path in this form's schema"'.
|
|
389
|
+
* ```
|
|
390
|
+
*
|
|
391
|
+
* Nothing can satisfy the brand, so a wrong path is still a compile
|
|
392
|
+
* error; only the message changes.
|
|
393
|
+
*/
|
|
394
|
+
type SegmentPathRejection<Joined extends string> = [Joined] extends [''] ? PlainStringAdvice : `attaform: '${Joined}' is not a path in this form's schema`;
|
|
395
|
+
/**
|
|
396
|
+
* `SegmentPathRejection` for `register`, whose accepted set is
|
|
397
|
+
* `RegisterFlatPath` rather than `FlatPath`.
|
|
398
|
+
*
|
|
399
|
+
* The distinction is worth its own sentence: a container path is in the
|
|
400
|
+
* schema and still not registrable, so "not a path in this form's
|
|
401
|
+
* schema" would be false where it is most likely to be read.
|
|
402
|
+
*/
|
|
403
|
+
type SegmentRegisterRejection<Joined extends string> = [Joined] extends [''] ? PlainStringAdvice : `attaform: '${Joined}' is not a registrable path. v-register binds a leaf input, so container paths are excluded.`;
|
|
303
404
|
/**
|
|
304
405
|
* `true` when `T` is a union (multiple members), `false` when it's a
|
|
305
406
|
* single type. Used to gate non-homomorphic mapped-type forms so
|
|
@@ -464,44 +565,89 @@ type IsTuple<T extends readonly unknown[]> = number extends T['length'] ? false
|
|
|
464
565
|
* runtime possibility of a missing array position.
|
|
465
566
|
*/
|
|
466
567
|
type NestedReadType<RootValue, FlattenedPath extends string> = NestedTypeBuilder<RootValue, FlattenedPath, true>;
|
|
568
|
+
/**
|
|
569
|
+
* The array a path actually addresses, nullish stripped, or `never`
|
|
570
|
+
* when the path does not address an array. Shared by `ArrayPath`
|
|
571
|
+
* (membership) and `ArrayItem` (element type) so the filter and the
|
|
572
|
+
* extractor cannot disagree about what counts as one.
|
|
573
|
+
*
|
|
574
|
+
* The strip is the load-bearing part. `Form` is the schema's INPUT
|
|
575
|
+
* shape, so `z.array(row).default([])` resolves to `row[] | undefined`,
|
|
576
|
+
* and `NestedType` tags a discriminated union's per-variant keys the
|
|
577
|
+
* same way on purpose: that tagging is what keeps `NestedType` in
|
|
578
|
+
* lockstep with `FlatPath`, so every path `FlatPath` offers resolves to
|
|
579
|
+
* a useful value type. A bare `extends readonly unknown[]` predicate
|
|
580
|
+
* read the tag as "not an array", which is how every optional,
|
|
581
|
+
* defaulted, nullable, and DU-variant array fell out of the field-array
|
|
582
|
+
* helpers while the runtime went on accepting all of them (#541).
|
|
583
|
+
*
|
|
584
|
+
* `extends infer Leaf` binds the stripped leaf once so the guards below
|
|
585
|
+
* do not re-instantiate `NestedType`, and the tuple wraps suppress
|
|
586
|
+
* distribution so a union leaf is judged whole: `A[] | B[]` is an
|
|
587
|
+
* array, `A[] | string` is not.
|
|
588
|
+
*
|
|
589
|
+
* Exported so `rollup-plugin-dts` keeps it as a named alias in the
|
|
590
|
+
* bundled `.d.ts` instead of inlining the body at every reference.
|
|
591
|
+
* Consumers reach for `ArrayPath` / `ArrayItem`; this alias is not part
|
|
592
|
+
* of the stable surface.
|
|
593
|
+
*/
|
|
594
|
+
type ArrayLeafOf<Form, P extends string> = Exclude<NestedType<Form, P>, undefined | null> extends infer Leaf ? [Leaf] extends [never] ? never : [Leaf] extends [readonly unknown[]] ? Leaf : never : never;
|
|
467
595
|
/**
|
|
468
596
|
* Filter FlatPath<Form> down to the subset of paths whose resolved leaf
|
|
469
597
|
* is an array. Used by the typed field-array helpers (append / remove /
|
|
470
598
|
* swap / ...) so those helpers only accept paths that actually address
|
|
471
599
|
* an array — calling `append('email', ...)` on a `{ email: string }`
|
|
472
|
-
* is a compile error.
|
|
600
|
+
* is a compile error. Optionality is not a disqualifier; see
|
|
601
|
+
* `ArrayLeafOf` for what "is an array" means here.
|
|
473
602
|
*
|
|
474
603
|
* `P extends string` re-triggers distribution over the `FlatPath<Form>`
|
|
475
604
|
* union so the conditional evaluates per member. Without it, the
|
|
476
605
|
* branch would reduce against the union as a whole and collapse to
|
|
477
606
|
* `never` whenever a single member failed the predicate.
|
|
478
607
|
*/
|
|
479
|
-
type ArrayPath<Form, P extends FlatPath<Form> = FlatPath<Form>> = P extends string ?
|
|
608
|
+
type ArrayPath<Form, P extends FlatPath<Form> = FlatPath<Form>> = P extends string ? [ArrayLeafOf<Form, P>] extends [never] ? never : P : never;
|
|
480
609
|
/**
|
|
481
610
|
* Extract the element type of the array addressed by `Path`. Callers
|
|
482
611
|
* constrain `Path extends ArrayPath<Form>` so this is always well-defined.
|
|
612
|
+
* Rides on `ArrayLeafOf`, the same alias `ArrayPath` admits the path
|
|
613
|
+
* with, so an accepted path never hands its helper a `never` value slot.
|
|
483
614
|
*/
|
|
484
|
-
type ArrayItem<Form, Path extends ArrayPath<Form>> =
|
|
615
|
+
type ArrayItem<Form, Path extends ArrayPath<Form>> = ArrayLeafOf<Form, Path> extends ReadonlyArray<infer Item> ? Item : never;
|
|
616
|
+
/**
|
|
617
|
+
* The record a path actually addresses, nullish stripped, or `never`
|
|
618
|
+
* when the path does not address one. Shared by `RecordPath`
|
|
619
|
+
* (membership) and `RecordValue` (value type).
|
|
620
|
+
*
|
|
621
|
+
* `string extends keyof Leaf` is the index-signature probe: it holds for
|
|
622
|
+
* `Record<string, V>` (`keyof` is `string`) and fails for a fixed object
|
|
623
|
+
* (`keyof` is the literal key union). The leading array guard keeps
|
|
624
|
+
* arrays (which also satisfy the object check) out of the record set.
|
|
625
|
+
*
|
|
626
|
+
* Nullish is stripped first for the reason `ArrayLeafOf` gives, with an
|
|
627
|
+
* extra bite here: `keyof (Record<string, V> | undefined)` is `never`,
|
|
628
|
+
* so on a `.default({})` or `.optional()` record the probe could not
|
|
629
|
+
* fire at all and `form.record(path)` rejected the path (#541).
|
|
630
|
+
*
|
|
631
|
+
* Exported for the same `.d.ts` reason as `ArrayLeafOf`, and equally
|
|
632
|
+
* not part of the stable surface.
|
|
633
|
+
*/
|
|
634
|
+
type RecordLeafOf<Form, P extends string> = Exclude<NestedType<Form, P>, undefined | null> extends infer Leaf ? [Leaf] extends [never] ? never : [Leaf] extends [readonly unknown[]] ? never : [Leaf] extends [Record<string, unknown>] ? string extends keyof Leaf ? Leaf : never : never : never;
|
|
485
635
|
/**
|
|
486
636
|
* Companion to `ArrayPath`: filter `FlatPath<Form>` down to the subset
|
|
487
637
|
* of paths whose resolved leaf is a record (an object with an open
|
|
488
638
|
* string-keyed index signature, e.g. `z.record(z.string(), V)`). A
|
|
489
639
|
* fixed-shape object (`z.object({ ... })`) is excluded — its keys are
|
|
490
640
|
* statically known, so it has no `string` index signature.
|
|
491
|
-
*
|
|
492
|
-
* `string extends keyof T` is the index-signature probe: it holds for
|
|
493
|
-
* `Record<string, V>` (`keyof` is `string`) and fails for a fixed object
|
|
494
|
-
* (`keyof` is the literal key union). The leading array guard keeps
|
|
495
|
-
* arrays (which also satisfy the object check) out of the record set.
|
|
496
641
|
*/
|
|
497
|
-
type RecordPath<Form, P extends FlatPath<Form> = FlatPath<Form>> = P extends string ?
|
|
642
|
+
type RecordPath<Form, P extends FlatPath<Form> = FlatPath<Form>> = P extends string ? [RecordLeafOf<Form, P>] extends [never] ? never : P : never;
|
|
498
643
|
/**
|
|
499
644
|
* Value type of the record addressed by `Path` — the `V` in a
|
|
500
645
|
* `Record<string, V>`. Callers constrain `Path extends RecordPath<Form>`,
|
|
501
646
|
* so the leaf is always an open string-keyed record and this is
|
|
502
|
-
* well-defined.
|
|
647
|
+
* well-defined. Rides on `RecordLeafOf`, the same alias `RecordPath`
|
|
648
|
+
* admits the path with, so the two cannot disagree.
|
|
503
649
|
*/
|
|
504
|
-
type RecordValue<Form, Path extends RecordPath<Form>> =
|
|
650
|
+
type RecordValue<Form, Path extends RecordPath<Form>> = RecordLeafOf<Form, Path> extends Record<string, infer Value> ? Value : never;
|
|
505
651
|
/**
|
|
506
652
|
* Widens primitive-literal leaves to their primitive supertype to
|
|
507
653
|
* match the runtime "slim-primitive write contract."
|
|
@@ -722,11 +868,13 @@ interface JsonObject {
|
|
|
722
868
|
* structured array — `['user', 'address', 0, 'line1']` for a nested
|
|
723
869
|
* field, `[]` (the root path) for a form-level error (root `.refine()`
|
|
724
870
|
* messages, `setErrors` entries with no path, hydration failures,
|
|
725
|
-
* server-emitted form banners).
|
|
726
|
-
*
|
|
727
|
-
*
|
|
871
|
+
* server-emitted form banners). Which form produced an error is
|
|
872
|
+
* envelope-level identity: the `ValidationResponse` / submit result
|
|
873
|
+
* that carries the list stamps `formKey` once, and aggregators that
|
|
874
|
+
* merge lists across forms (the wizard) stamp their own envelope. The
|
|
875
|
+
* optional `data` slot carries an arbitrary server payload.
|
|
728
876
|
*
|
|
729
|
-
* Returned by `validate()` / `
|
|
877
|
+
* Returned by `validate()` / `parse()` / `handleSubmit`'s
|
|
730
878
|
* `onError` callback, and accepted (leniently, as `ErrorInput`) by
|
|
731
879
|
* `form.setErrors`.
|
|
732
880
|
*/
|
|
@@ -741,8 +889,6 @@ type ValidationError = {
|
|
|
741
889
|
* literal empty-key field.
|
|
742
890
|
*/
|
|
743
891
|
path: (string | number)[];
|
|
744
|
-
/** Identifies which form produced this error. */
|
|
745
|
-
formKey: FormKey;
|
|
746
892
|
/**
|
|
747
893
|
* Stable machine identifier for the failure, scoped by prefix:
|
|
748
894
|
*
|
|
@@ -764,6 +910,23 @@ type ValidationError = {
|
|
|
764
910
|
*/
|
|
765
911
|
data?: Json | null;
|
|
766
912
|
};
|
|
913
|
+
/**
|
|
914
|
+
* One path's slot in the form's tagged error store. The two sources
|
|
915
|
+
* that can put an error at a path stay segregated inside the cell:
|
|
916
|
+
* `schema` holds the validation pipeline's verdicts, `user` holds
|
|
917
|
+
* `setErrors` entries (and their history / SSR replays). Reads merge
|
|
918
|
+
* schema -> derived-blank -> user; each writer replaces exactly its
|
|
919
|
+
* own side. Cells are immutable — every write replaces the whole cell
|
|
920
|
+
* (or deletes the key when both sides empty), so Vue's per-key Map
|
|
921
|
+
* tracking fires for any side's change. An empty side is the shared
|
|
922
|
+
* frozen `NO_ERRORS` array, never a fresh allocation.
|
|
923
|
+
*
|
|
924
|
+
* @internal
|
|
925
|
+
*/
|
|
926
|
+
type ErrorCell = {
|
|
927
|
+
readonly schema: readonly ValidationError[];
|
|
928
|
+
readonly user: readonly ValidationError[];
|
|
929
|
+
};
|
|
767
930
|
/**
|
|
768
931
|
* The lenient input shape `form.setErrors` accepts: a real `Error`, or
|
|
769
932
|
* a partial `ValidationError` where every field is optional.
|
|
@@ -773,20 +936,17 @@ type ValidationError = {
|
|
|
773
936
|
* the path-scoped `setErrors(path, …)` form, which stamps its own.
|
|
774
937
|
* - `code`: defaults to `atta:user-error`.
|
|
775
938
|
* - `data`: forwarded verbatim onto the produced `ValidationError`.
|
|
776
|
-
* - `formKey`: accepted but ignored — the form always stamps its own.
|
|
777
939
|
*
|
|
778
|
-
* Because every field is optional
|
|
779
|
-
* `
|
|
780
|
-
*
|
|
781
|
-
*
|
|
782
|
-
* friction.
|
|
940
|
+
* Because every field is optional, `ValidationError` is a subtype of
|
|
941
|
+
* `ErrorInput`: a `ValidationError[]` you read back, or a server
|
|
942
|
+
* response that already emits the shape, pipes straight into
|
|
943
|
+
* `form.setErrors` with no adapter.
|
|
783
944
|
*/
|
|
784
945
|
type ErrorInput = Error | {
|
|
785
946
|
message?: string;
|
|
786
947
|
path?: (string | number)[];
|
|
787
948
|
code?: string;
|
|
788
949
|
data?: Json | null;
|
|
789
|
-
formKey?: FormKey;
|
|
790
950
|
};
|
|
791
951
|
/** Settled validation result when the form (or subtree) parsed successfully. */
|
|
792
952
|
type ValidationResponseSuccess<TData> = {
|
|
@@ -831,10 +991,19 @@ type ValidationResponse<TData> = ValidationResponseSuccess<TData> | ValidationRe
|
|
|
831
991
|
type DefaultValuesResponse<TData> = ValidationResponseSuccess<TData> | ValidationResponseErrorWithData<TData>;
|
|
832
992
|
/**
|
|
833
993
|
* Trimmed `ValidationResponse` that omits the `data` payload. Used by
|
|
834
|
-
* `validate()`
|
|
835
|
-
*
|
|
994
|
+
* the reactive `validate()` status, whose consumers only need the
|
|
995
|
+
* success flag and error list.
|
|
836
996
|
*/
|
|
837
997
|
type ValidationResponseWithoutValue<Form> = Omit<ValidationResponse<Form>, 'data'>;
|
|
998
|
+
/**
|
|
999
|
+
* Options bag for `form.parse`. `commit: true` turns the pure read
|
|
1000
|
+
* into an authoritative run: the verdict is committed to the error
|
|
1001
|
+
* store at the parsed scope and in-flight per-field validation runs
|
|
1002
|
+
* are cancelled first. Default `false`.
|
|
1003
|
+
*/
|
|
1004
|
+
type ParseOptions = {
|
|
1005
|
+
readonly commit?: boolean;
|
|
1006
|
+
};
|
|
838
1007
|
/**
|
|
839
1008
|
* Sync-or-async return shape for `AbstractSchema.validateAtPath`. The
|
|
840
1009
|
* adapter returns the response inline when the schema and the
|
|
@@ -998,7 +1167,7 @@ type AbstractSchema<Form, GetValueFormType> = {
|
|
|
998
1167
|
* the gate accepts the consumer's raw value verbatim and stops
|
|
999
1168
|
* walking children — storage holds the user's input, and the
|
|
1000
1169
|
* normalizer fires during `safeParse` (handleSubmit / validate /
|
|
1001
|
-
*
|
|
1170
|
+
* parse), not at `setValue` time.
|
|
1002
1171
|
*
|
|
1003
1172
|
* Path-prefix semantic: returns true if ANY ancestor of `path`
|
|
1004
1173
|
* resolves to such a wrapper, so descendants under a preprocess-
|
|
@@ -1006,29 +1175,50 @@ type AbstractSchema<Form, GetValueFormType> = {
|
|
|
1006
1175
|
* the result by canonicalized path key.
|
|
1007
1176
|
*/
|
|
1008
1177
|
isPreprocessOrCoerceLeaf(path: Path): boolean;
|
|
1178
|
+
/**
|
|
1179
|
+
* Reports whether `path` resolves to an opaque leaf: a schema that
|
|
1180
|
+
* declares a value without describing its shape. In Zod v4 that's
|
|
1181
|
+
* `z.any()`, `z.unknown()`, and `z.custom(...)` (the kind both
|
|
1182
|
+
* `z.instanceof(X)` and `z.custom<T>()` compile to); in Zod v3 it's
|
|
1183
|
+
* `z.any()` / `z.unknown()`, with `z.instanceof(X)` peeling through
|
|
1184
|
+
* `ZodEffects` to `ZodAny`.
|
|
1185
|
+
*
|
|
1186
|
+
* Consulted by the slim-primitive write gate. An opaque leaf admits
|
|
1187
|
+
* every kind, INCLUDING containers, and it declares no sub-paths.
|
|
1188
|
+
* Without this the gate accepts an array at the leaf and then walks
|
|
1189
|
+
* into it, checking `files.0` against a schema that never declared
|
|
1190
|
+
* that path; the empty accept set there reads as "not in your
|
|
1191
|
+
* schema" and no-ops the whole write (#542).
|
|
1192
|
+
*
|
|
1193
|
+
* Exact-path semantic, unlike `isPreprocessOrCoerceLeaf`: it answers
|
|
1194
|
+
* for the node at `path` only. Descendants stay unwritable on their
|
|
1195
|
+
* own, because the schema genuinely does not declare them and
|
|
1196
|
+
* fabricating them would put phantom nodes on `form.fields`. Writing
|
|
1197
|
+
* the whole value at the opaque leaf is the supported move.
|
|
1198
|
+
*/
|
|
1199
|
+
isOpaqueLeafAtPath(path: Path): boolean;
|
|
1009
1200
|
/**
|
|
1010
1201
|
* Distinguish a tuple (fixed-length, position-typed) from an
|
|
1011
1202
|
* unbounded array at `path`. The runtime calls this on every
|
|
1012
1203
|
* `mergeStructural` / `setAtPathWithSchemaFill` write that descends
|
|
1013
|
-
* into an array branch
|
|
1014
|
-
*
|
|
1015
|
-
* (up to 1024 schema lookups) the runtime previously used.
|
|
1204
|
+
* into an array branch, and the answer is definitive — the runtime
|
|
1205
|
+
* never second-guesses it.
|
|
1016
1206
|
*
|
|
1017
1207
|
* Return values:
|
|
1018
1208
|
* - `number` → tuple of this structural length. The runtime pads
|
|
1019
1209
|
* the consumer to this length and recurses position-by-position.
|
|
1020
|
-
* - `null` →
|
|
1021
|
-
* length and reuses one element default for
|
|
1022
|
-
*
|
|
1023
|
-
*
|
|
1024
|
-
*
|
|
1025
|
-
*
|
|
1210
|
+
* - `null` → not a tuple. Covers the unbounded array (the runtime
|
|
1211
|
+
* uses the consumer's length and reuses one element default for
|
|
1212
|
+
* every position) and every path that doesn't resolve to an
|
|
1213
|
+
* array at all — there `getDefaultAtPath` yields no element
|
|
1214
|
+
* default either, so the consumer's array passes through
|
|
1215
|
+
* unchanged.
|
|
1026
1216
|
*
|
|
1027
1217
|
* Wrappers (optional / nullable / default / readonly / catch /
|
|
1028
1218
|
* pipe / lazy) are peeled transparently before the type check, so
|
|
1029
1219
|
* `optional(z.tuple([...]))` reports its tuple length.
|
|
1030
1220
|
*/
|
|
1031
|
-
arrayShapeAtPath(path: Path): number | null
|
|
1221
|
+
arrayShapeAtPath(path: Path): number | null;
|
|
1032
1222
|
/**
|
|
1033
1223
|
* Whether the schema at `path` is a FIXED object: a closed set of
|
|
1034
1224
|
* declared keys (`z.object`), as opposed to an open or union container
|
|
@@ -1052,6 +1242,29 @@ type AbstractSchema<Form, GetValueFormType> = {
|
|
|
1052
1242
|
* `false`.
|
|
1053
1243
|
*/
|
|
1054
1244
|
isFixedObjectAtPath(path: Path): boolean;
|
|
1245
|
+
/**
|
|
1246
|
+
* How the container at `path` spells the keys of its own entries:
|
|
1247
|
+
* `'number'` for an array or a tuple, `'string'` for an object or a
|
|
1248
|
+
* record, and for a `z.map` the kind its declared key type accepts.
|
|
1249
|
+
* `undefined` for anything else, a leaf and an undeclared path
|
|
1250
|
+
* included.
|
|
1251
|
+
*
|
|
1252
|
+
* The write walkers consult it at a `Map`, where a new entry has to
|
|
1253
|
+
* be filed under a key of the declared type and the path segment
|
|
1254
|
+
* alone cannot say which: an integer-looking segment canonicalises
|
|
1255
|
+
* to a number, so `scores.42` against a `z.map(z.string(), V)` would
|
|
1256
|
+
* otherwise take the number `42` as its key and fail the map's own
|
|
1257
|
+
* parse. An entry the map already holds needs no ruling — its
|
|
1258
|
+
* existing key wins.
|
|
1259
|
+
*
|
|
1260
|
+
* A map whose key type is neither string-ish nor number-ish, or
|
|
1261
|
+
* which admits both, reports `undefined`: no segment can spell such
|
|
1262
|
+
* a key, so the map stays a whole value with no addressable entries.
|
|
1263
|
+
*
|
|
1264
|
+
* Adapters MAY cache per path; the runtime calls this on the write
|
|
1265
|
+
* path.
|
|
1266
|
+
*/
|
|
1267
|
+
entryKeyKindAtPath(path: Path): 'string' | 'number' | undefined;
|
|
1055
1268
|
/**
|
|
1056
1269
|
* Return every sub-schema that could resolve at the given structured
|
|
1057
1270
|
* path. Multiple results are only expected for discriminated / union
|
|
@@ -1122,9 +1335,12 @@ type AbstractSchema<Form, GetValueFormType> = {
|
|
|
1122
1335
|
*/
|
|
1123
1336
|
getSlimPrimitiveTypesAtPath(path: Path): Set<SlimPrimitiveKind>;
|
|
1124
1337
|
/**
|
|
1125
|
-
* Return `true` iff `path` resolves to a **leaf** in the schema
|
|
1126
|
-
* path
|
|
1127
|
-
*
|
|
1338
|
+
* Return `true` iff `path` resolves to a **leaf** in the schema: a
|
|
1339
|
+
* path the schema declares no sub-paths under. That is every path
|
|
1340
|
+
* whose slim primitive set contains only primitive kinds (no
|
|
1341
|
+
* `object`, `array`, `map`, `set`), plus the opaque leaves, which
|
|
1342
|
+
* admit every kind and are classified by kind instead (below). The
|
|
1343
|
+
* runtime proxies (`form.values`,
|
|
1128
1344
|
* `form.errors`, `form.fields`) query this at every step to decide
|
|
1129
1345
|
* between **descend into a sub-proxy** (container) and **terminate
|
|
1130
1346
|
* with a leaf value** (leaf).
|
|
@@ -1142,6 +1358,14 @@ type AbstractSchema<Form, GetValueFormType> = {
|
|
|
1142
1358
|
* date/function) → `true`. `'date'` counts as a leaf (don't drill
|
|
1143
1359
|
* into `Date`). `'function'` is a leaf for the same reason — opaque
|
|
1144
1360
|
* value.
|
|
1361
|
+
* - **Opaque leaf** (`z.any()`, `z.unknown()`, `z.custom()`, and the
|
|
1362
|
+
* `z.instanceof(X)` that compiles to it) → `true`, and it answers
|
|
1363
|
+
* ahead of the kind test. An opaque leaf admits every kind
|
|
1364
|
+
* INCLUDING the container ones, so reading it off the slim
|
|
1365
|
+
* primitive set alone classifies it as a container and puts
|
|
1366
|
+
* phantom nodes under it on `form.fields` — see
|
|
1367
|
+
* `isOpaqueLeafAtPath`. What leafness asks is whether the schema
|
|
1368
|
+
* declares sub-paths here, and an opaque leaf declares none.
|
|
1145
1369
|
* - **Optional / Nullable / Default / Catch** wrappers transparent —
|
|
1146
1370
|
* adds `'null'` / `'undefined'` to the inner kind set without
|
|
1147
1371
|
* changing the leaf classification.
|
|
@@ -1307,6 +1531,19 @@ type AbstractSchema<Form, GetValueFormType> = {
|
|
|
1307
1531
|
* toward returning `true` when in doubt.
|
|
1308
1532
|
*/
|
|
1309
1533
|
hasContainerOrRootRefine?(): boolean;
|
|
1534
|
+
/**
|
|
1535
|
+
* `true` when the schema tree contains at least one discriminated
|
|
1536
|
+
* union at any depth (inside arrays, tuples, records, and lazy
|
|
1537
|
+
* schemas included). The store computes its per-form DU capability
|
|
1538
|
+
* flag from this once at construction: `false` lets every write skip
|
|
1539
|
+
* the cross-variant ancestor guard and the variant-reshape dispatch,
|
|
1540
|
+
* and DU stub correction never runs. Optional: an adapter that omits
|
|
1541
|
+
* it is treated as containing unions, keeping the conservative
|
|
1542
|
+
* per-write probes on. Never return `false` for a schema that DOES
|
|
1543
|
+
* hold a discriminated union — that disables variant reshape and
|
|
1544
|
+
* stub correction for the form.
|
|
1545
|
+
*/
|
|
1546
|
+
hasDiscriminatedUnions?(): boolean;
|
|
1310
1547
|
};
|
|
1311
1548
|
/**
|
|
1312
1549
|
* Adapter-returned info for a discriminated union — its discriminator
|
|
@@ -1422,7 +1659,7 @@ type OnInvalidSubmitPolicy = 'none' | 'focus-first-error' | 'scroll-to-first-err
|
|
|
1422
1659
|
* registered field. No debounce — `debounceMs` is rejected by the
|
|
1423
1660
|
* type.
|
|
1424
1661
|
* - `'submit'`: no live validation. `handleSubmit` and explicit
|
|
1425
|
-
* `validate()` / `
|
|
1662
|
+
* `validate()` / `parse()` calls are the only validation
|
|
1426
1663
|
* surfaces. `debounceMs` is rejected by the type.
|
|
1427
1664
|
*/
|
|
1428
1665
|
type ValidateOn = 'change' | 'blur' | 'submit';
|
|
@@ -1499,8 +1736,8 @@ type WriteMeta = {
|
|
|
1499
1736
|
readonly skipDiscriminatorReshape?: boolean;
|
|
1500
1737
|
/**
|
|
1501
1738
|
* Records an array structural mutation precisely enough to replay the
|
|
1502
|
-
* exact index permutation it produced, set by
|
|
1503
|
-
*
|
|
1739
|
+
* exact index permutation it produced, set by the typed array helpers
|
|
1740
|
+
* in `array-engine.ts`. `setValueAtPath` uses it to surgically clear variant memory
|
|
1504
1741
|
* for the indices the operation invalidated. Without this hint, a raw
|
|
1505
1742
|
* whole-array `setValue(arrayPath, [...])` clears all memory under the
|
|
1506
1743
|
* array (the runtime can't tell which indices stayed put). Internal —
|
|
@@ -1551,19 +1788,68 @@ type WriteMeta = {
|
|
|
1551
1788
|
readonly hydration?: boolean;
|
|
1552
1789
|
};
|
|
1553
1790
|
/**
|
|
1554
|
-
*
|
|
1791
|
+
* The store slice the history runtime binds to. Structural on purpose:
|
|
1792
|
+
* `historyPlugin()` ships from the separate `attaform/history` entry, so
|
|
1793
|
+
* the runtime receives the store through this seam instead of importing
|
|
1794
|
+
* the store module (which would pull the history internals onto every
|
|
1795
|
+
* form's eager path). A FormStore satisfies it as-is.
|
|
1796
|
+
*
|
|
1797
|
+
* @internal
|
|
1798
|
+
*/
|
|
1799
|
+
type HistoryKernel = {
|
|
1800
|
+
readonly form: Ref<unknown>;
|
|
1801
|
+
readonly blankPaths: Set<PathKey>;
|
|
1802
|
+
readonly errorCells: Map<PathKey, ErrorCell>;
|
|
1803
|
+
onFormChange(listener: (next: unknown, meta?: WriteMeta) => void): () => void;
|
|
1804
|
+
applyFormReplacement(next: unknown): void;
|
|
1805
|
+
restoreErrorCells(entries: ReadonlyArray<readonly [PathKey, ErrorCell]>): void;
|
|
1806
|
+
};
|
|
1807
|
+
/**
|
|
1808
|
+
* The live undo/redo runtime a {@link HistoryPlugin} attaches to one
|
|
1809
|
+
* form. Cached on the FormStore so every `useForm` / `injectForm`
|
|
1810
|
+
* consumer of the same key shares one chain; `buildFormApi` adapts it
|
|
1811
|
+
* into the public `form.history` namespace.
|
|
1555
1812
|
*
|
|
1556
|
-
*
|
|
1557
|
-
|
|
1813
|
+
* @internal
|
|
1814
|
+
*/
|
|
1815
|
+
type HistoryModule = {
|
|
1816
|
+
undo(): boolean;
|
|
1817
|
+
redo(): boolean;
|
|
1818
|
+
clear(): void;
|
|
1819
|
+
canUndo: Readonly<ComputedRef<boolean>>;
|
|
1820
|
+
canRedo: Readonly<ComputedRef<boolean>>;
|
|
1821
|
+
historySize: Readonly<ComputedRef<number>>;
|
|
1822
|
+
dispose(): void;
|
|
1823
|
+
};
|
|
1824
|
+
/**
|
|
1825
|
+
* Opt-in undo/redo, created by `historyPlugin()` from `attaform/history`
|
|
1826
|
+
* and passed via `useForm({ history })`:
|
|
1827
|
+
*
|
|
1828
|
+
* ```ts
|
|
1829
|
+
* import { historyPlugin } from 'attaform/history'
|
|
1830
|
+
*
|
|
1831
|
+
* const form = useForm({ schema, history: historyPlugin({ max: 200 }) })
|
|
1832
|
+
* ```
|
|
1558
1833
|
*
|
|
1559
|
-
* When enabled, every mutation records a
|
|
1834
|
+
* When enabled, every mutation records a position; `form.history.undo()`
|
|
1560
1835
|
* / `form.history.redo()` walk the chain. `reset()` is itself a mutation —
|
|
1561
1836
|
* the pre-reset state stays one undo away. Persistence hydration is the
|
|
1562
1837
|
* floor: after hydrate applies, the chain reseeds with the hydrated value
|
|
1563
1838
|
* and `undo()` cannot reach the transient pre-hydration default.
|
|
1839
|
+
*
|
|
1840
|
+
* One plugin instance is a reusable configuration, not per-form state:
|
|
1841
|
+
* passing the same instance to several forms (or setting it once via
|
|
1842
|
+
* `createAttaform({ defaults: { history } })`) gives each form its own
|
|
1843
|
+
* independent chain.
|
|
1564
1844
|
*/
|
|
1565
|
-
type
|
|
1566
|
-
|
|
1845
|
+
type HistoryPlugin = {
|
|
1846
|
+
/**
|
|
1847
|
+
* Bind a fresh history runtime to one form's store. Called by
|
|
1848
|
+
* `useForm` when the store is first created.
|
|
1849
|
+
*
|
|
1850
|
+
* @internal
|
|
1851
|
+
*/
|
|
1852
|
+
readonly attach: (kernel: HistoryKernel) => HistoryModule;
|
|
1567
1853
|
};
|
|
1568
1854
|
/**
|
|
1569
1855
|
* Consolidated undo/redo namespace at `form.history`. All history-related
|
|
@@ -1781,16 +2067,17 @@ type UseFormConfiguration<Form extends GenericForm, GetValueFormType, Schema ext
|
|
|
1781
2067
|
*/
|
|
1782
2068
|
debounceMs?: number;
|
|
1783
2069
|
/**
|
|
1784
|
-
* Opt-in undo/redo. Off by default. `
|
|
1785
|
-
*
|
|
2070
|
+
* Opt-in undo/redo. Off by default. Pass `historyPlugin()` from
|
|
2071
|
+
* `attaform/history` — a 128-position cap by default,
|
|
2072
|
+
* `historyPlugin({ max: N })` to tune it.
|
|
1786
2073
|
*
|
|
1787
|
-
* Every mutation records a
|
|
2074
|
+
* Every mutation records a position. `form.history.undo()` walks
|
|
1788
2075
|
* one step back; `form.history.redo()` walks one step forward.
|
|
1789
2076
|
* `reset()` is itself a mutation, so the pre-reset state stays one
|
|
1790
2077
|
* undo away. The consolidated `form.history` namespace also exposes
|
|
1791
2078
|
* `clear()`, `canUndo`, `canRedo`, and `size`.
|
|
1792
2079
|
*/
|
|
1793
|
-
history?:
|
|
2080
|
+
history?: HistoryPlugin;
|
|
1794
2081
|
/**
|
|
1795
2082
|
* Whether to remember the typed state of each discriminated-union
|
|
1796
2083
|
* variant across switches. Default `true`.
|
|
@@ -1936,8 +2223,8 @@ type AttaformDefaults = {
|
|
|
1936
2223
|
* `validateOn` resolves to `'change'`. Default `0` (synchronous).
|
|
1937
2224
|
*/
|
|
1938
2225
|
debounceMs?: number;
|
|
1939
|
-
/** Default for `useForm({ history })
|
|
1940
|
-
history?:
|
|
2226
|
+
/** Default for `useForm({ history })` — a `historyPlugin()` instance. */
|
|
2227
|
+
history?: HistoryPlugin;
|
|
1941
2228
|
/** Default for `useForm({ rememberVariants })`. */
|
|
1942
2229
|
rememberVariants?: boolean;
|
|
1943
2230
|
/** Default for `useForm({ disabled })` — freeze the form's data. */
|
|
@@ -2016,7 +2303,7 @@ type AttaformDefaults = {
|
|
|
2016
2303
|
*
|
|
2017
2304
|
* "Permissive fallback" means storage and reads keep working at any
|
|
2018
2305
|
* depth; only the per-write type gate stops checking past the cap.
|
|
2019
|
-
* Full schema validation (`
|
|
2306
|
+
* Full schema validation (`parse`, `handleSubmit`) still runs
|
|
2020
2307
|
* against the real schema, so refinement errors at any depth still
|
|
2021
2308
|
* surface — the cap only affects the *write-time gate*.
|
|
2022
2309
|
*
|
|
@@ -2425,6 +2712,49 @@ type RegisterOptions = {
|
|
|
2425
2712
|
*/
|
|
2426
2713
|
autoAria?: boolean;
|
|
2427
2714
|
};
|
|
2715
|
+
/**
|
|
2716
|
+
* The narrow kernel surface the DOM binding drives. Structurally a
|
|
2717
|
+
* subset of the form store: the field-record connect/disconnect
|
|
2718
|
+
* transitions, focus marking (which owns blur-validation), the record
|
|
2719
|
+
* and merged-error reads the focus walk needs, and the async-transform
|
|
2720
|
+
* abort for a fully-detached path.
|
|
2721
|
+
* @internal
|
|
2722
|
+
*/
|
|
2723
|
+
type DomBindingKernel = {
|
|
2724
|
+
readonly noteDomConnected: (path: Path) => void;
|
|
2725
|
+
readonly noteDomDisconnected: (path: Path) => void;
|
|
2726
|
+
readonly markFocused: (path: Path, focused: boolean, meta?: {
|
|
2727
|
+
readonly instance?: WriteMeta['instance'];
|
|
2728
|
+
}) => void;
|
|
2729
|
+
readonly getFieldRecord: (path: Path) => FieldRecord | undefined;
|
|
2730
|
+
readonly getErrorsForPath: (path: Path) => ValidationError[];
|
|
2731
|
+
readonly cancelTransformsUnder: (prefix: Path) => void;
|
|
2732
|
+
};
|
|
2733
|
+
/**
|
|
2734
|
+
* The form store's DOM slice: the element registry backing
|
|
2735
|
+
* `field.element` / `field.elements`, no-latch host focus anchors, and
|
|
2736
|
+
* first-error focus resolution. Implemented in the directive cluster's
|
|
2737
|
+
* lazy graph and armed into the store's `domBinding` slot on first use
|
|
2738
|
+
* (see `RegisterValue.ensureDomBinding`); a `null` slot means nothing
|
|
2739
|
+
* in the app ever registered an element.
|
|
2740
|
+
* @internal
|
|
2741
|
+
*/
|
|
2742
|
+
type AttaformDomBinding = {
|
|
2743
|
+
readonly elements: Map<PathKey, ElementRecord>;
|
|
2744
|
+
readonly attach: (segments: Path, element: HTMLElement, formInstanceId: string, instanceMeta: WriteMeta['instance'] | undefined) => void;
|
|
2745
|
+
readonly detach: (segments: Path, element: HTMLElement) => void;
|
|
2746
|
+
readonly markHostConnected: (segments: Path, connected: boolean, hostEl: HTMLElement, formInstanceId: string) => void;
|
|
2747
|
+
readonly getFirstErrorElement: (formInstanceId: string) => {
|
|
2748
|
+
path: Path;
|
|
2749
|
+
element: HTMLElement;
|
|
2750
|
+
} | null;
|
|
2751
|
+
};
|
|
2752
|
+
/**
|
|
2753
|
+
* Factory the directive / `useRegister` inject through
|
|
2754
|
+
* `RegisterValue.ensureDomBinding` to arm a store's `domBinding` slot.
|
|
2755
|
+
* @internal
|
|
2756
|
+
*/
|
|
2757
|
+
type DomBindingFactory = (kernel: DomBindingKernel) => AttaformDomBinding;
|
|
2428
2758
|
/**
|
|
2429
2759
|
* The object returned by `form.register(path)`. Pass it to a native
|
|
2430
2760
|
* input via `v-register`:
|
|
@@ -2530,6 +2860,17 @@ type RegisterValue<Value = unknown> = Readonly<{
|
|
|
2530
2860
|
* @internal
|
|
2531
2861
|
*/
|
|
2532
2862
|
hasRegisteredDescendant: (hostElement: HTMLElement) => boolean;
|
|
2863
|
+
/**
|
|
2864
|
+
* Arm this binding's form store with the DOM-binding implementation
|
|
2865
|
+
* (element registry, focus listeners, first-error focus resolution).
|
|
2866
|
+
* The implementation lives in the directive cluster's lazy graph, so
|
|
2867
|
+
* the directive and `useRegister` inject its factory here before any
|
|
2868
|
+
* element call; once armed, the store's `domBinding` slot serves every
|
|
2869
|
+
* later registration. Optional so hand-rolled RegisterValues, which
|
|
2870
|
+
* own their element handling, don't have to declare it.
|
|
2871
|
+
* @internal
|
|
2872
|
+
*/
|
|
2873
|
+
ensureDomBinding?: (factory: DomBindingFactory) => void;
|
|
2533
2874
|
/**
|
|
2534
2875
|
* Canonical, JSON-encoded path key for this binding (e.g.
|
|
2535
2876
|
* `'["items",0,"name"]'`). Useful for stable Map / Set keys, log
|
|
@@ -2958,10 +3299,10 @@ type RegisterModelDynamicCustomDirective = ObjectDirective<HTMLInputElement | HT
|
|
|
2958
3299
|
* See `RegisterTextModifier` / `RegisterSelectModifier` for
|
|
2959
3300
|
* per-modifier semantics.
|
|
2960
3301
|
*
|
|
2961
|
-
*
|
|
2962
|
-
* `attaform/
|
|
2963
|
-
* directive itself — it's exposed for
|
|
2964
|
-
* directives manually.
|
|
3302
|
+
* Delivered by the Vite / Nuxt plugin's compile-time binding, or by
|
|
3303
|
+
* `installVRegister(app)` from `attaform/directive` everywhere else.
|
|
3304
|
+
* Most consumers don't import the directive itself — it's exposed for
|
|
3305
|
+
* integrations that install directives manually.
|
|
2965
3306
|
*/
|
|
2966
3307
|
type RegisterDirective = RegisterTextCustomDirective | RegisterCheckboxCustomDirective | RegisterSelectCustomDirective | RegisterRadioCustomDirective | RegisterModelDynamicCustomDirective;
|
|
2967
3308
|
/**
|
|
@@ -3015,9 +3356,11 @@ declare module 'vue' {
|
|
|
3015
3356
|
* form.setValue((prev) => ({ ...prev, name: 'Ada' }))
|
|
3016
3357
|
* ```
|
|
3017
3358
|
*
|
|
3018
|
-
*
|
|
3019
|
-
*
|
|
3020
|
-
* so
|
|
3359
|
+
* A whole-form callback replaces the whole form. Any key the return
|
|
3360
|
+
* omits is refilled from the SCHEMA's declared defaults (the slim
|
|
3361
|
+
* value where none is declared), so an omitted key is not carried
|
|
3362
|
+
* over from the previous value or from `defaultValues` — spread
|
|
3363
|
+
* `prev` to keep the rest of the form.
|
|
3021
3364
|
*/
|
|
3022
3365
|
type SetValueCallback<Read, Write = Read> = (prev: Read) => Read | Write;
|
|
3023
3366
|
/**
|
|
@@ -3206,7 +3549,7 @@ type FieldState<Value = unknown> = {
|
|
|
3206
3549
|
* `true` while a per-field validation run is in flight at this path.
|
|
3207
3550
|
* Reflects field-level debounced runs (`validate-on-change`) and
|
|
3208
3551
|
* cross-field re-validations targeting this path. Whole-form
|
|
3209
|
-
* `validate()` / `
|
|
3552
|
+
* `validate()` / `parse()` calls drive `form.meta.validating`
|
|
3210
3553
|
* only — they don't flip per-field flags.
|
|
3211
3554
|
*
|
|
3212
3555
|
* Per-field analogue of `form.meta.validating`. Use for a tight
|
|
@@ -3650,7 +3993,7 @@ type FieldStateMap<Form extends GenericForm> = LeafWalker<Form, 'field'> & {
|
|
|
3650
3993
|
* dot/bracket access (`form.fields.users[i].email`), which is what
|
|
3651
3994
|
* descends.
|
|
3652
3995
|
*/
|
|
3653
|
-
<const S extends ReadonlyArray<string | number>>(segments: S & ([JoinSegments<S>] extends [FlatPath<Form>] ? unknown :
|
|
3996
|
+
<const S extends ReadonlyArray<string | number>>(segments: S & ([JoinSegments<S>] extends [FlatPath<Form>] ? unknown : SegmentPathRejection<JoinSegments<S>>)): FieldState<NestedType<Form, JoinSegments<S>>>;
|
|
3654
3997
|
/**
|
|
3655
3998
|
* Dynamic-array fallback for callers passing `Path`-typed (runtime)
|
|
3656
3999
|
* segment arrays — e.g. forwarding `RegisterValue.segments` to
|
|
@@ -3721,7 +4064,7 @@ type FormErrorsSurface<Form> = ErrorsProxyShape<Form> & {
|
|
|
3721
4064
|
* tuples that don't resolve to a known path fail at the call site.
|
|
3722
4065
|
* Dynamic `Path`-typed inputs hit the untyped fallback overload below.
|
|
3723
4066
|
*/
|
|
3724
|
-
<const S extends ReadonlyArray<string | number>>(segments: S & ([JoinSegments<S>] extends [FlatPath<Form>] ? unknown :
|
|
4067
|
+
<const S extends ReadonlyArray<string | number>>(segments: S & ([JoinSegments<S>] extends [FlatPath<Form>] ? unknown : SegmentPathRejection<JoinSegments<S>>)): readonly ValidationError[];
|
|
3725
4068
|
(segments: ReadonlyArray<string | number>): readonly ValidationError[];
|
|
3726
4069
|
/**
|
|
3727
4070
|
* No-arg call returns the whole-form error aggregate, the same as
|
|
@@ -3766,6 +4109,27 @@ type ErrorsProxyShape<T> = LeafWalker<T, 'errors', false>;
|
|
|
3766
4109
|
* form.values() // the whole form value (root)
|
|
3767
4110
|
* ```
|
|
3768
4111
|
*
|
|
4112
|
+
* The two shapes answer different questions. Dot access is the
|
|
4113
|
+
* REACTIVE view: per-key tracking, no copying, always the live value.
|
|
4114
|
+
* The call form returns a SNAPSHOT: a detached plain object that keeps
|
|
4115
|
+
* what it held at capture time, so it is the shape to hand an async
|
|
4116
|
+
* call, a serialiser, or a diff.
|
|
4117
|
+
*
|
|
4118
|
+
* ```ts
|
|
4119
|
+
* const before = form.values() // detached; survives later writes
|
|
4120
|
+
* await api.save(before) // cannot mutate underneath the call
|
|
4121
|
+
* form.values.email // reactive read; use this in computed
|
|
4122
|
+
* ```
|
|
4123
|
+
*
|
|
4124
|
+
* Prefer dot access inside a `computed`, `watchEffect`, or template:
|
|
4125
|
+
* it tracks the one key you read, where the call form depends on the
|
|
4126
|
+
* whole form and re-runs the consumer on any change.
|
|
4127
|
+
*
|
|
4128
|
+
* The copy is deep across plain objects and arrays. Non-plain
|
|
4129
|
+
* instances (Map, Set, File, Date) are shared by reference, matching
|
|
4130
|
+
* `JSON.stringify` behaviour; `structuredClone(form.values())` gives a
|
|
4131
|
+
* fully detached copy when one is needed.
|
|
4132
|
+
*
|
|
3769
4133
|
* Single-bracket dotted access (`form.values['address.city']`) is
|
|
3770
4134
|
* intentionally NOT supported — JS object semantics treat the dotted
|
|
3771
4135
|
* string as a single key. Use chained dot/bracket or the callable
|
|
@@ -3809,7 +4173,9 @@ type ValuesSurface<F> = Readonly<LiftedValueShape<F>> & {
|
|
|
3809
4173
|
* `form.fields.<path>`; this is the aggregate view across the
|
|
3810
4174
|
* whole form.
|
|
3811
4175
|
*
|
|
3812
|
-
* Read-only at runtime —
|
|
4176
|
+
* Read-only at runtime — an assignment is refused with a dev-console
|
|
4177
|
+
* warning and never lands (Attaform does not throw from a read
|
|
4178
|
+
* surface). Destructuring snapshots
|
|
3813
4179
|
* the current values; use `toRefs()` if you need reactive handles
|
|
3814
4180
|
* to individual fields.
|
|
3815
4181
|
*/
|
|
@@ -4153,7 +4519,7 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4153
4519
|
* `form.setValue([prefix, 'line1'], 'value')`. The resolved leaf
|
|
4154
4520
|
* type is exact, matching the dotted-string form.
|
|
4155
4521
|
*/
|
|
4156
|
-
<const S extends ReadonlyArray<string | number>, Value extends PathSetValuePayload<NestedType<Form, JoinSegments<S>>>>(segments: S & ([JoinSegments<S>] extends [FlatPath<Form>] ? unknown :
|
|
4522
|
+
<const S extends ReadonlyArray<string | number>, Value extends PathSetValuePayload<NestedType<Form, JoinSegments<S>>>>(segments: S & ([JoinSegments<S>] extends [FlatPath<Form>] ? unknown : SegmentPathRejection<JoinSegments<S>>), value: Value): boolean;
|
|
4157
4523
|
};
|
|
4158
4524
|
/**
|
|
4159
4525
|
* Reactive validation status. Re-runs whenever the form (or the
|
|
@@ -4173,19 +4539,6 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4173
4539
|
* settles to results from the most recent call.
|
|
4174
4540
|
*/
|
|
4175
4541
|
validate: (path?: FlatPath<Form>) => Readonly<Ref<ReactiveValidationStatus<Form>>>;
|
|
4176
|
-
/**
|
|
4177
|
-
* Run validation once and return the result. Unlike `validate()`,
|
|
4178
|
-
* this does not subscribe to form reactivity.
|
|
4179
|
-
*
|
|
4180
|
-
* ```ts
|
|
4181
|
-
* const result = await form.validateAsync()
|
|
4182
|
-
* if (!result.success) showErrors(result.errors)
|
|
4183
|
-
* ```
|
|
4184
|
-
*
|
|
4185
|
-
* Pass a path to validate a subtree. `state.validating` flips
|
|
4186
|
-
* `true` while the promise is in flight.
|
|
4187
|
-
*/
|
|
4188
|
-
validateAsync: (path?: FlatPath<Form>) => Promise<ValidationResponseWithoutValue<Form>>;
|
|
4189
4542
|
/**
|
|
4190
4543
|
* Resolve once every in-flight async `register({ transforms })` run
|
|
4191
4544
|
* has settled — globally, or (with `path`) only at-or-under that path.
|
|
@@ -4207,9 +4560,9 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4207
4560
|
*/
|
|
4208
4561
|
settleTransforms: (path?: FlatPath<Form>) => Promise<void>;
|
|
4209
4562
|
/**
|
|
4210
|
-
* Imperative one-shot parse.
|
|
4211
|
-
*
|
|
4212
|
-
*
|
|
4563
|
+
* Imperative one-shot parse. Runs the full pipeline — refinements,
|
|
4564
|
+
* `.transform()`s, blank-required composition — against the current
|
|
4565
|
+
* form snapshot and RETAINS the parsed data.
|
|
4213
4566
|
*
|
|
4214
4567
|
* Storage holds the "honest input view" — values you wrote, with
|
|
4215
4568
|
* preprocess normalization applied but `.transform()` deferred. For
|
|
@@ -4227,16 +4580,31 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4227
4580
|
* }
|
|
4228
4581
|
* ```
|
|
4229
4582
|
*
|
|
4583
|
+
* By default the call is a PURE read: nothing is written to
|
|
4584
|
+
* `form.errors`, and in-flight per-field validation runs are left
|
|
4585
|
+
* alone. Pass `{ commit: true }` to make the run authoritative —
|
|
4586
|
+
* the verdict is committed to the error store at the parsed scope
|
|
4587
|
+
* and any in-flight per-field runs are cancelled first (mirroring
|
|
4588
|
+
* `handleSubmit`), so `await form.parse('email', { commit: true })`
|
|
4589
|
+
* lands a deterministic view of `form.errors.email`:
|
|
4590
|
+
*
|
|
4591
|
+
* ```ts
|
|
4592
|
+
* const result = await form.parse({ commit: true })
|
|
4593
|
+
* if (!result.success) showErrors(result.errors)
|
|
4594
|
+
* ```
|
|
4595
|
+
*
|
|
4230
4596
|
* Always async, and there is no synchronous variant by design: a
|
|
4231
4597
|
* schema can carry async refinements or transforms, so a sync parse
|
|
4232
4598
|
* would silently miss them the moment one is added. One always-
|
|
4233
4599
|
* awaited `parse` closes that category of bug entirely. The returned
|
|
4234
4600
|
* promise never rejects (a thrown adapter lands as a `success: false`
|
|
4235
4601
|
* response). Pass a path to parse a subtree only. `meta.validating`
|
|
4236
|
-
* flips `true` while the promise is in flight
|
|
4237
|
-
* validateAsync).
|
|
4602
|
+
* flips `true` while the promise is in flight.
|
|
4238
4603
|
*/
|
|
4239
|
-
parse:
|
|
4604
|
+
parse: {
|
|
4605
|
+
(path?: FlatPath<Form>, options?: ParseOptions): Promise<ValidationResponse<GetValueFormType>>;
|
|
4606
|
+
(options: ParseOptions): Promise<ValidationResponse<GetValueFormType>>;
|
|
4607
|
+
};
|
|
4240
4608
|
/**
|
|
4241
4609
|
* Bind a path to a native input via `v-register`. Returns a
|
|
4242
4610
|
* `RegisterValue` carrying the live ref and event handlers the
|
|
@@ -4263,7 +4631,7 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4263
4631
|
*/
|
|
4264
4632
|
register: {
|
|
4265
4633
|
<Path extends RegisterFlatPath<Form>>(path: Path, options?: RegisterOptions): RegisterValue<NestedReadType<WriteShape<ReadForm>, Path>>;
|
|
4266
|
-
<const S extends ReadonlyArray<string | number>>(segments: S & ([JoinSegments<S>] extends [RegisterFlatPath<Form>] ? unknown :
|
|
4634
|
+
<const S extends ReadonlyArray<string | number>>(segments: S & ([JoinSegments<S>] extends [RegisterFlatPath<Form>] ? unknown : SegmentRegisterRejection<JoinSegments<S>>), options?: RegisterOptions): RegisterValue<NestedReadType<WriteShape<ReadForm>, JoinSegments<S>>>;
|
|
4267
4635
|
};
|
|
4268
4636
|
/**
|
|
4269
4637
|
* The form's identifier — either the explicit `key` passed to
|
|
@@ -4344,8 +4712,12 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4344
4712
|
*
|
|
4345
4713
|
* Resolves after `hydrating` flips back to `false`. Throws
|
|
4346
4714
|
* synchronously when the form was constructed with a plain-value
|
|
4347
|
-
* `defaultValues` (nothing to re-fire).
|
|
4348
|
-
*
|
|
4715
|
+
* `defaultValues` (nothing to re-fire).
|
|
4716
|
+
*
|
|
4717
|
+
* The payload becomes the form's defaults, the same way a
|
|
4718
|
+
* `reset(next)` argument does, so `form.reset()` afterwards lands on
|
|
4719
|
+
* the values just fetched. Does NOT clear touched / submit state;
|
|
4720
|
+
* chain `form.reset()` for that.
|
|
4349
4721
|
*/
|
|
4350
4722
|
rehydrate(): Promise<void>;
|
|
4351
4723
|
/**
|
|
@@ -4403,7 +4775,7 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4403
4775
|
*/
|
|
4404
4776
|
toRef: {
|
|
4405
4777
|
<Path extends FlatPath<Form>>(path: Path): Readonly<Ref<NestedReadType<WriteShape<ReadForm>, Path>>>;
|
|
4406
|
-
<const S extends ReadonlyArray<string | number>>(segments: S & ([JoinSegments<S>] extends [FlatPath<Form>] ? unknown :
|
|
4778
|
+
<const S extends ReadonlyArray<string | number>>(segments: S & ([JoinSegments<S>] extends [FlatPath<Form>] ? unknown : SegmentPathRejection<JoinSegments<S>>)): Readonly<Ref<NestedReadType<WriteShape<ReadForm>, JoinSegments<S>>>>;
|
|
4407
4779
|
};
|
|
4408
4780
|
/**
|
|
4409
4781
|
* Set the form's manual error layer. One surface for server-side
|
|
@@ -4473,10 +4845,10 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4473
4845
|
*/
|
|
4474
4846
|
meta: FormMeta<Form>;
|
|
4475
4847
|
/**
|
|
4476
|
-
* Restore the form to its
|
|
4477
|
-
*
|
|
4478
|
-
*
|
|
4479
|
-
*
|
|
4848
|
+
* Restore the form to its defaults. Without arguments, re-applies
|
|
4849
|
+
* whatever the defaults currently are: `useForm({ defaultValues })`
|
|
4850
|
+
* on a fresh form, or the last values a `reset(next)` or an async
|
|
4851
|
+
* `defaultValues` factory settled on.
|
|
4480
4852
|
*
|
|
4481
4853
|
* Resets:
|
|
4482
4854
|
* - the form value back to defaults;
|
|
@@ -4485,6 +4857,26 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4485
4857
|
* - touched / focused / blurred per-field flags;
|
|
4486
4858
|
* - submission state (`submitting` / `submissionAttempts` /
|
|
4487
4859
|
* `submitted` / `submitError`).
|
|
4860
|
+
*
|
|
4861
|
+
* `nextDefaultValues` RE-SEATS the defaults rather than applying for
|
|
4862
|
+
* one call, so the form has a single set of defaults that `reset()`,
|
|
4863
|
+
* `resetField(path)`, and `dirty` all read. That is what makes the
|
|
4864
|
+
* save-then-discard shape work: reset from the resource the server
|
|
4865
|
+
* returned, and a later Discard returns to the save instead of
|
|
4866
|
+
* rolling back across it.
|
|
4867
|
+
*
|
|
4868
|
+
* ```ts
|
|
4869
|
+
* const saved = await api.save(form.values())
|
|
4870
|
+
* form.reset(toValues(saved)) // the saved resource is now the baseline
|
|
4871
|
+
* // …later…
|
|
4872
|
+
* form.reset() // back to the saved resource
|
|
4873
|
+
* ```
|
|
4874
|
+
*
|
|
4875
|
+
* The argument is sparse: it folds over the defaults already in
|
|
4876
|
+
* force, so paths it does not name keep the value they had, and
|
|
4877
|
+
* `reset({})` changes nothing. Arrays are replaced wholesale rather
|
|
4878
|
+
* than merged element-wise. Pass `unset` at a path to withdraw its
|
|
4879
|
+
* value and mark it blank.
|
|
4488
4880
|
*/
|
|
4489
4881
|
reset: (nextDefaultValues?: DefaultValuesInput<Form>) => void;
|
|
4490
4882
|
/**
|
|
@@ -4539,7 +4931,7 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4539
4931
|
clear: {
|
|
4540
4932
|
(): boolean;
|
|
4541
4933
|
<Path extends FlatPath<Form> | ''>(path: Path): boolean;
|
|
4542
|
-
<const S extends ReadonlyArray<string | number>>(segments: S & ([JoinSegments<S>] extends [FlatPath<Form> | ''] ? unknown :
|
|
4934
|
+
<const S extends ReadonlyArray<string | number>>(segments: S & ([JoinSegments<S>] extends [FlatPath<Form> | ''] ? unknown : SegmentPathRejection<JoinSegments<S>>)): boolean;
|
|
4543
4935
|
};
|
|
4544
4936
|
/**
|
|
4545
4937
|
* Consolidated undo/redo namespace — `form.history.{undo, redo,
|
|
@@ -4759,5 +5151,5 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4759
5151
|
blankPaths: ComputedRef<BlankPathsView>;
|
|
4760
5152
|
};
|
|
4761
5153
|
|
|
4762
|
-
export { ROOT_PATH as
|
|
4763
|
-
export type {
|
|
5154
|
+
export { ROOT_PATH as Y, ROOT_PATH_KEY as Z, canonicalizePath as ao, isPathPrefix as ap, isUnset as aq, parseDottedPath as ar, unset as as };
|
|
5155
|
+
export type { RecordPath as $, AbstractSchema as A, NestedType as B, CoercionEntry as C, DefaultValuesInput as D, ErrorInput as E, FormKey as F, GenericForm as G, HandleSubmit as H, IsTuple as I, JoinSegments as J, KeyofUnion as K, LiftedValueShape as L, MetaTrackerValue as M, NestedReadType as N, OnError as O, OnInvalidSubmitPolicy as P, OnSubmit as Q, ParseOptions as R, PartialFlatPath as S, Path as T, UseFormConfiguration as U, PathKey as V, PendingValidationStatus as W, Primitive as X, ReactiveValidationStatus as _, UseFormReturnType as a, RecordValue as a0, RegisterDirective as a1, RegisterFlatPath as a2, RegisterOptions as a3, RegisterSelectModifier as a4, RegisterTextModifier as a5, RegisterTransform as a6, RegisterValue as a7, Segment as a8, SetValueCallback as a9, TransformAbortHolder as aA, SetValuePayload as aa, SettledValidationStatus as ab, SlimPrimitiveKind as ac, SlimRuntimeOf as ad, SubmitHandler as ae, Unset as af, ValidateOn as ag, ValidateOnConfig as ah, ValidationError as ai, ValidationResponse as aj, ValidationResponseWithoutValue as ak, ValueOfUnion as al, WriteMeta as am, WriteShape as an, RegisterModelDynamicCustomDirective as at, SchemaFactoryOptions as au, AcceptableDefaults as av, FieldRecord as aw, ErrorCell as ax, OriginalsRecord as ay, AttaformDomBinding as az, ArrayItem as b, ArrayPath as c, AttaformDefaults as d, CoercionRegistry as e, CoercionResult as f, CustomDirectiveRegisterAssignerFn as g, DeepPartial as h, DefaultValuesResponse as i, DefaultValuesShape as j, DisplayCtx as k, DisplayMachine as l, DisplayState as m, ErrorsProxyShape as n, FieldMetaPayload as o, FieldState as p, FieldStateMap as q, FieldStateMapEntry as r, FlatPath as s, FormErrorRecord as t, FormErrorsSurface as u, FormMeta as v, GetDisplayState as w, HistoryPlugin as x, IsUnion as y, Json as z };
|