attaform 0.21.0 → 0.21.2
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/chunks/dev-key-collision-warnings.cjs +1 -1
- package/dist/chunks/dev-key-collision-warnings.mjs +1 -1
- package/dist/chunks/devtools.cjs +1 -1
- package/dist/chunks/devtools.mjs +1 -1
- package/dist/chunks/fingerprint2.cjs +1 -1
- package/dist/chunks/fingerprint2.mjs +1 -1
- package/dist/chunks/indexeddb.cjs +1 -1
- package/dist/chunks/indexeddb.mjs +1 -1
- package/dist/chunks/local-storage.cjs +1 -1
- package/dist/chunks/local-storage.mjs +1 -1
- package/dist/chunks/multi-tab-sync.cjs +2 -2
- package/dist/chunks/multi-tab-sync.mjs +2 -2
- package/dist/chunks/session-storage.cjs +1 -1
- package/dist/chunks/session-storage.mjs +1 -1
- package/dist/chunks/wire-persistence.cjs +2 -2
- package/dist/chunks/wire-persistence.mjs +2 -2
- package/dist/index.cjs +37 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -28
- package/dist/index.d.mts +31 -28
- package/dist/index.d.ts +31 -28
- package/dist/index.mjs +38 -25
- package/dist/index.mjs.map +1 -1
- package/dist/nuxt.d.cts +1 -1
- package/dist/nuxt.d.mts +1 -1
- package/dist/nuxt.d.ts +1 -1
- package/dist/runtime/components/AttaformDevtoolsPanel.vue +396 -216
- package/dist/runtime/components/DevtoolsValueTree.vue +176 -114
- package/dist/runtime/plugins/attaform.cjs +2 -2
- package/dist/runtime/plugins/attaform.mjs +2 -2
- package/dist/shared/{attaform.BA3vRDos.cjs → attaform.B5LNzqQh.cjs} +349 -277
- package/dist/shared/attaform.B5LNzqQh.cjs.map +1 -0
- package/dist/shared/{attaform.PnqML3xW.cjs → attaform.BBDIKtKY.cjs} +13 -16
- package/dist/shared/attaform.BBDIKtKY.cjs.map +1 -0
- package/dist/shared/{attaform.CRsXyy-Y.d.ts → attaform.BCcrLApm.d.mts} +131 -64
- package/dist/shared/{attaform.BupwXkj_.mjs → attaform.BFWb6hDk.mjs} +29 -23
- package/dist/shared/attaform.BFWb6hDk.mjs.map +1 -0
- package/dist/shared/{attaform.7lzO9pdM.d.mts → attaform.BGf_J22U.d.ts} +131 -64
- package/dist/shared/{attaform.BnK_bfcb.mjs → attaform.BVeLgfEh.mjs} +14 -17
- package/dist/shared/attaform.BVeLgfEh.mjs.map +1 -0
- package/dist/shared/{attaform.BK1RE2ha.d.ts → attaform.BYgioWLF.d.ts} +2 -2
- package/dist/shared/{attaform.F8LMHHWV.d.cts → attaform.BkjJfMvJ.d.cts} +131 -64
- package/dist/shared/{attaform.BDIEq9qP.d.cts → attaform.BoY6RZUl.d.cts} +2 -2
- package/dist/shared/{attaform.CEf6wYfD.cjs → attaform.BwLp9KM7.cjs} +2 -2
- package/dist/shared/{attaform.CEf6wYfD.cjs.map → attaform.BwLp9KM7.cjs.map} +1 -1
- package/dist/shared/{attaform._rsCZy2j.cjs → attaform.BwrowMp2.cjs} +25 -45
- package/dist/shared/attaform.BwrowMp2.cjs.map +1 -0
- package/dist/shared/{attaform.ezb5Nh2t.mjs → attaform.C41gjp-a.mjs} +2 -2
- package/dist/shared/{attaform.ezb5Nh2t.mjs.map → attaform.C41gjp-a.mjs.map} +1 -1
- package/dist/shared/{attaform.BM6YD9kZ.cjs → attaform.CR6wGvNu.cjs} +29 -23
- package/dist/shared/attaform.CR6wGvNu.cjs.map +1 -0
- package/dist/shared/{attaform.DSqO6Db7.mjs → attaform.CTheKoTc.mjs} +705 -282
- package/dist/shared/attaform.CTheKoTc.mjs.map +1 -0
- package/dist/shared/{attaform.BzvOdiSI.cjs → attaform.CcnF1AKJ.cjs} +4 -4
- package/dist/shared/attaform.CcnF1AKJ.cjs.map +1 -0
- package/dist/shared/{attaform.BQ6drorq.d.mts → attaform.CnEl--PF.d.mts} +2 -2
- package/dist/shared/{attaform.CkjTapyq.mjs → attaform.CrD73S4m.mjs} +4 -4
- package/dist/shared/attaform.CrD73S4m.mjs.map +1 -0
- package/dist/shared/{attaform.BUszFoKq.cjs → attaform.D2ZuIOCf.cjs} +711 -287
- package/dist/shared/attaform.D2ZuIOCf.cjs.map +1 -0
- package/dist/shared/{attaform.r3PePkDR.mjs → attaform.D6GYGshL.mjs} +25 -45
- package/dist/shared/attaform.D6GYGshL.mjs.map +1 -0
- package/dist/shared/{attaform.Y_Mgg0Yp.mjs → attaform.DP-u7_tk.mjs} +348 -277
- package/dist/shared/attaform.DP-u7_tk.mjs.map +1 -0
- package/dist/shared/{attaform.B1nyO4ec.d.cts → attaform.ory-3WhV.d.cts} +395 -176
- package/dist/shared/{attaform.B1nyO4ec.d.mts → attaform.ory-3WhV.d.mts} +395 -176
- package/dist/shared/{attaform.B1nyO4ec.d.ts → attaform.ory-3WhV.d.ts} +395 -176
- package/dist/transforms.cjs +1 -1
- package/dist/transforms.mjs +1 -1
- package/dist/vite.cjs +1 -1
- package/dist/vite.mjs +1 -1
- package/dist/zod-v3.cjs +3 -4
- package/dist/zod-v3.cjs.map +1 -1
- package/dist/zod-v3.d.cts +4 -4
- package/dist/zod-v3.d.mts +4 -4
- package/dist/zod-v3.d.ts +4 -4
- package/dist/zod-v3.mjs +2 -3
- package/dist/zod-v3.mjs.map +1 -1
- package/dist/zod-v4.cjs +3 -4
- package/dist/zod-v4.cjs.map +1 -1
- package/dist/zod-v4.d.cts +4 -4
- package/dist/zod-v4.d.mts +4 -4
- package/dist/zod-v4.d.ts +4 -4
- package/dist/zod-v4.mjs +2 -3
- package/dist/zod-v4.mjs.map +1 -1
- package/dist/zod.cjs +6 -6
- package/dist/zod.cjs.map +1 -1
- package/dist/zod.d.cts +77 -26
- package/dist/zod.d.mts +77 -26
- package/dist/zod.d.ts +77 -26
- package/dist/zod.mjs +5 -6
- package/dist/zod.mjs.map +1 -1
- package/package.json +3 -11
- package/dist/shared/attaform.BA3vRDos.cjs.map +0 -1
- package/dist/shared/attaform.BM6YD9kZ.cjs.map +0 -1
- package/dist/shared/attaform.BUszFoKq.cjs.map +0 -1
- package/dist/shared/attaform.BnK_bfcb.mjs.map +0 -1
- package/dist/shared/attaform.BupwXkj_.mjs.map +0 -1
- package/dist/shared/attaform.BzvOdiSI.cjs.map +0 -1
- package/dist/shared/attaform.CkjTapyq.mjs.map +0 -1
- package/dist/shared/attaform.DSqO6Db7.mjs.map +0 -1
- package/dist/shared/attaform.PnqML3xW.cjs.map +0 -1
- package/dist/shared/attaform.Y_Mgg0Yp.mjs.map +0 -1
- package/dist/shared/attaform._rsCZy2j.cjs.map +0 -1
- package/dist/shared/attaform.r3PePkDR.mjs.map +0 -1
- package/dist/shared/{attaform.DSD85fHb.d.cts → attaform.nf83TIR5.d.cts} +10 -10
- package/dist/shared/{attaform.DSD85fHb.d.mts → attaform.nf83TIR5.d.mts} +10 -10
- package/dist/shared/{attaform.DSD85fHb.d.ts → attaform.nf83TIR5.d.ts} +10 -10
|
@@ -73,6 +73,123 @@ type ResolvedFieldMeta = {
|
|
|
73
73
|
readonly meta: Readonly<FieldMetaPayload>;
|
|
74
74
|
};
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Path primitives for advanced integrations. The form library accepts
|
|
78
|
+
* paths in dotted-string form (`'user.email'`) at every public API.
|
|
79
|
+
* These primitives are exposed for adapter authors who need to
|
|
80
|
+
* canonicalise user-provided paths.
|
|
81
|
+
*/
|
|
82
|
+
declare const pathKeyBrand: unique symbol;
|
|
83
|
+
/**
|
|
84
|
+
* Branded string identifier for a canonicalised path. Useful as a
|
|
85
|
+
* `Map` key — two paths that resolve to the same canonical form
|
|
86
|
+
* produce the same `PathKey`. Treat as opaque; don't try to parse.
|
|
87
|
+
*/
|
|
88
|
+
type PathKey = string & {
|
|
89
|
+
readonly [pathKeyBrand]: 'PathKey';
|
|
90
|
+
};
|
|
91
|
+
/** A single path segment — a property name or array index. */
|
|
92
|
+
type Segment = string | number;
|
|
93
|
+
/** A structured path as a read-only sequence of segments. */
|
|
94
|
+
type Path = readonly Segment[];
|
|
95
|
+
/**
|
|
96
|
+
* Parse a dotted-string path into structured segments.
|
|
97
|
+
*
|
|
98
|
+
* ```ts
|
|
99
|
+
* parseDottedPath('user.address.line1') // ['user', 'address', 'line1']
|
|
100
|
+
* parseDottedPath('items.0.name') // ['items', 0, 'name']
|
|
101
|
+
* parseDottedPath('') // [''] (the empty-string key)
|
|
102
|
+
* ```
|
|
103
|
+
*
|
|
104
|
+
* The empty-string input `''` is the **literal empty-key path**, not
|
|
105
|
+
* the root. Use the array form `[]` for root. Form-level errors
|
|
106
|
+
* (root `.refine()`) live at the empty-string path bucket so
|
|
107
|
+
* `errors('')` returns them without sweeping every field error too.
|
|
108
|
+
*
|
|
109
|
+
* Throws `InvalidPathError` for paths with empty INTERNAL segments
|
|
110
|
+
* (`'a..b'`, leading or trailing dots). For keys containing literal
|
|
111
|
+
* dots, pass an array form (`['user.name']`) instead.
|
|
112
|
+
*/
|
|
113
|
+
declare function parseDottedPath(path: string): Segment[];
|
|
114
|
+
/**
|
|
115
|
+
* Canonicalise a path into structured segments plus a stable string
|
|
116
|
+
* key. Accepts either dotted-string or array form; integer-looking
|
|
117
|
+
* segments normalise to numbers.
|
|
118
|
+
*
|
|
119
|
+
* ```ts
|
|
120
|
+
* canonicalizePath('items.0.name')
|
|
121
|
+
* // { segments: ['items', 0, 'name'], key: '["items",0,"name"]' as PathKey }
|
|
122
|
+
*
|
|
123
|
+
* canonicalizePath(['items', 0, 'name'])
|
|
124
|
+
* // → same result
|
|
125
|
+
* ```
|
|
126
|
+
*
|
|
127
|
+
* The returned `key` is suitable as a `Map`/`Set` key — equal paths
|
|
128
|
+
* produce equal keys regardless of input form.
|
|
129
|
+
*/
|
|
130
|
+
declare function canonicalizePath(input: string | Path): {
|
|
131
|
+
segments: readonly Segment[];
|
|
132
|
+
key: PathKey;
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* The root path — an empty segment tuple. Pass to APIs that accept
|
|
136
|
+
* a `Path` to address the form value as a whole.
|
|
137
|
+
*/
|
|
138
|
+
declare const ROOT_PATH: Path;
|
|
139
|
+
/** Stable string key for the root path. */
|
|
140
|
+
declare const ROOT_PATH_KEY: PathKey;
|
|
141
|
+
/**
|
|
142
|
+
* `true` when `path` starts with every segment of `prefix` (in order).
|
|
143
|
+
* The empty `prefix` matches every path — ROOT prefix is universal.
|
|
144
|
+
*
|
|
145
|
+
* Walks segments rather than `PathKey` strings because the data this
|
|
146
|
+
* helper operates on (e.g. `meta.errors[].path`) carries segment
|
|
147
|
+
* arrays directly.
|
|
148
|
+
*
|
|
149
|
+
* ```ts
|
|
150
|
+
* isPathPrefix(['cargo'], ['cargo', 'items', 0, 'sku']) // true
|
|
151
|
+
* isPathPrefix(['cargo', 'items'], ['cargo']) // false (path shorter)
|
|
152
|
+
* isPathPrefix([], ['anything']) // true (root prefix)
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
declare function isPathPrefix(prefix: readonly Segment[], path: readonly Segment[]): boolean;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Per-FormStore registry tracking which DOM elements have opted into
|
|
159
|
+
* persistence for which paths. Lives on the FormStore so that two SFCs
|
|
160
|
+
* sharing a key share the registry — opt-ins are per-element, not
|
|
161
|
+
* per-component.
|
|
162
|
+
*
|
|
163
|
+
* The directive's input handler computes `meta.persist` for each write
|
|
164
|
+
* by calling `hasOptIn(elementId, path)` — only THIS element's writes
|
|
165
|
+
* persist if THIS element opted in. Other call sites that aren't tied
|
|
166
|
+
* to a single element (history undo/redo, field-array helpers, devtools
|
|
167
|
+
* edits) use `hasAnyOptInForPath(path)` — persist if any element has
|
|
168
|
+
* opted into that path.
|
|
169
|
+
*
|
|
170
|
+
* Internal data structure: `Map<PathKey, Set<elementId>>`. Small forms
|
|
171
|
+
* have ~10-50 paths; iteration is cheap. All operations are O(1) given
|
|
172
|
+
* (id, path).
|
|
173
|
+
*/
|
|
174
|
+
type PersistOptInRegistry = {
|
|
175
|
+
/** Add an opt-in entry; idempotent. */
|
|
176
|
+
add(elementId: string, path: PathKey): void;
|
|
177
|
+
/** Remove a single (element, path) entry. */
|
|
178
|
+
remove(elementId: string, path: PathKey): void;
|
|
179
|
+
/** Remove every opt-in for `elementId`. Called from directive's beforeUnmount. */
|
|
180
|
+
removeAllFor(elementId: string): void;
|
|
181
|
+
/** Check whether THIS element has opted into THIS path. */
|
|
182
|
+
hasOptIn(elementId: string, path: PathKey): boolean;
|
|
183
|
+
/** Check whether ANY element has opted into this path. */
|
|
184
|
+
hasAnyOptInForPath(path: PathKey): boolean;
|
|
185
|
+
/** Iterate every path that currently has at least one opt-in. */
|
|
186
|
+
optedInPaths(): IterableIterator<PathKey>;
|
|
187
|
+
/** True iff no element has opted into any path. */
|
|
188
|
+
isEmpty(): boolean;
|
|
189
|
+
/** Drop every entry. Called from FormStore.dispose. */
|
|
190
|
+
clear(): void;
|
|
191
|
+
};
|
|
192
|
+
|
|
76
193
|
/** Internal brand for the `Unset` type. Never exposed at runtime. */
|
|
77
194
|
declare const _unsetBrand: unique symbol;
|
|
78
195
|
/**
|
|
@@ -230,6 +347,21 @@ type KeyofUnion<T> = T extends unknown ? keyof T : never;
|
|
|
230
347
|
* variants and the runtime returns a stable stub there.
|
|
231
348
|
*/
|
|
232
349
|
type ValueOfUnion<T, K extends PropertyKey> = T extends unknown ? K extends keyof T ? T[K] : undefined : never;
|
|
350
|
+
/**
|
|
351
|
+
* Value at key `K` across union members of `T`, dropping members that
|
|
352
|
+
* LACK `K` entirely (they contribute `never`, not `undefined`). The
|
|
353
|
+
* counterpart to `ValueOfUnion`: where that injects a SYNTHETIC
|
|
354
|
+
* `undefined` for absent-variant keys (so chained reads stay safe),
|
|
355
|
+
* this yields only the PRESENT value type.
|
|
356
|
+
*
|
|
357
|
+
* `form.fields` uses it at discriminated-union keys so a variant-only
|
|
358
|
+
* field types as node-optional `FieldState<X> | undefined` (the node is
|
|
359
|
+
* absent when its variant isn't active) rather than value-optional
|
|
360
|
+
* `FieldState<X | undefined>` (which would falsely promise a readable
|
|
361
|
+
* node). A genuine `undefined` from an OPTIONAL declaration survives —
|
|
362
|
+
* only the synthetic absent-variant `undefined` is stripped.
|
|
363
|
+
*/
|
|
364
|
+
type PresentValueOfUnion<T, K extends PropertyKey> = T extends unknown ? K extends keyof T ? T[K] : never : never;
|
|
233
365
|
/**
|
|
234
366
|
* Apply the discriminated-union "lift" to a value shape (i.e., a
|
|
235
367
|
* shape carrying actual values, not metadata leaves like
|
|
@@ -530,6 +662,15 @@ type DefaultValuesInput<T> = T extends string ? string | Unset : T extends numbe
|
|
|
530
662
|
[K in keyof T]?: DefaultValuesInput<T[K]>;
|
|
531
663
|
} | Unset : T;
|
|
532
664
|
|
|
665
|
+
/**
|
|
666
|
+
* Identifier for a form. A `FormKey` is the string passed via
|
|
667
|
+
* `useForm({ key })`, used to look up a form by name from a distant
|
|
668
|
+
* component, namespace persisted drafts, and label errors and
|
|
669
|
+
* DevTools entries. Anonymous `useForm` calls allocate one
|
|
670
|
+
* automatically; you only need to pick one when the form needs
|
|
671
|
+
* stable identity.
|
|
672
|
+
*/
|
|
673
|
+
type FormKey = string;
|
|
533
674
|
/**
|
|
534
675
|
* Per-form options threaded from `useForm` into the adapter factory.
|
|
535
676
|
* Today carries the resolved `maxRecursionDepth` so adapter walks can
|
|
@@ -540,133 +681,6 @@ interface SchemaFactoryOptions {
|
|
|
540
681
|
/** Resolved recursion ceiling (per-form > app-default > library default). */
|
|
541
682
|
maxRecursionDepth: number;
|
|
542
683
|
}
|
|
543
|
-
|
|
544
|
-
/**
|
|
545
|
-
* Path primitives for advanced integrations. The form library accepts
|
|
546
|
-
* paths in dotted-string form (`'user.email'`) at every public API.
|
|
547
|
-
* These primitives are exposed for adapter authors who need to
|
|
548
|
-
* canonicalise user-provided paths.
|
|
549
|
-
*/
|
|
550
|
-
declare const pathKeyBrand: unique symbol;
|
|
551
|
-
/**
|
|
552
|
-
* Branded string identifier for a canonicalised path. Useful as a
|
|
553
|
-
* `Map` key — two paths that resolve to the same canonical form
|
|
554
|
-
* produce the same `PathKey`. Treat as opaque; don't try to parse.
|
|
555
|
-
*/
|
|
556
|
-
type PathKey = string & {
|
|
557
|
-
readonly [pathKeyBrand]: 'PathKey';
|
|
558
|
-
};
|
|
559
|
-
/** A single path segment — a property name or array index. */
|
|
560
|
-
type Segment = string | number;
|
|
561
|
-
/** A structured path as a read-only sequence of segments. */
|
|
562
|
-
type Path = readonly Segment[];
|
|
563
|
-
/**
|
|
564
|
-
* Parse a dotted-string path into structured segments.
|
|
565
|
-
*
|
|
566
|
-
* ```ts
|
|
567
|
-
* parseDottedPath('user.address.line1') // ['user', 'address', 'line1']
|
|
568
|
-
* parseDottedPath('items.0.name') // ['items', 0, 'name']
|
|
569
|
-
* parseDottedPath('') // [''] (the empty-string key)
|
|
570
|
-
* ```
|
|
571
|
-
*
|
|
572
|
-
* The empty-string input `''` is the **literal empty-key path**, not
|
|
573
|
-
* the root. Use the array form `[]` for root. Form-level errors
|
|
574
|
-
* (root `.refine()`) live at the empty-string path bucket so
|
|
575
|
-
* `errors('')` returns them without sweeping every field error too.
|
|
576
|
-
*
|
|
577
|
-
* Throws `InvalidPathError` for paths with empty INTERNAL segments
|
|
578
|
-
* (`'a..b'`, leading or trailing dots). For keys containing literal
|
|
579
|
-
* dots, pass an array form (`['user.name']`) instead.
|
|
580
|
-
*/
|
|
581
|
-
declare function parseDottedPath(path: string): Segment[];
|
|
582
|
-
/**
|
|
583
|
-
* Canonicalise a path into structured segments plus a stable string
|
|
584
|
-
* key. Accepts either dotted-string or array form; integer-looking
|
|
585
|
-
* segments normalise to numbers.
|
|
586
|
-
*
|
|
587
|
-
* ```ts
|
|
588
|
-
* canonicalizePath('items.0.name')
|
|
589
|
-
* // { segments: ['items', 0, 'name'], key: '["items",0,"name"]' as PathKey }
|
|
590
|
-
*
|
|
591
|
-
* canonicalizePath(['items', 0, 'name'])
|
|
592
|
-
* // → same result
|
|
593
|
-
* ```
|
|
594
|
-
*
|
|
595
|
-
* The returned `key` is suitable as a `Map`/`Set` key — equal paths
|
|
596
|
-
* produce equal keys regardless of input form.
|
|
597
|
-
*/
|
|
598
|
-
declare function canonicalizePath(input: string | Path): {
|
|
599
|
-
segments: readonly Segment[];
|
|
600
|
-
key: PathKey;
|
|
601
|
-
};
|
|
602
|
-
/**
|
|
603
|
-
* The root path — an empty segment tuple. Pass to APIs that accept
|
|
604
|
-
* a `Path` to address the form value as a whole.
|
|
605
|
-
*/
|
|
606
|
-
declare const ROOT_PATH: Path;
|
|
607
|
-
/** Stable string key for the root path. */
|
|
608
|
-
declare const ROOT_PATH_KEY: PathKey;
|
|
609
|
-
/**
|
|
610
|
-
* `true` when `path` starts with every segment of `prefix` (in order).
|
|
611
|
-
* The empty `prefix` matches every path — ROOT prefix is universal.
|
|
612
|
-
*
|
|
613
|
-
* Walks segments rather than `PathKey` strings because the data this
|
|
614
|
-
* helper operates on (e.g. `meta.errors[].path`) carries segment
|
|
615
|
-
* arrays directly.
|
|
616
|
-
*
|
|
617
|
-
* ```ts
|
|
618
|
-
* isPathPrefix(['cargo'], ['cargo', 'items', 0, 'sku']) // true
|
|
619
|
-
* isPathPrefix(['cargo', 'items'], ['cargo']) // false (path shorter)
|
|
620
|
-
* isPathPrefix([], ['anything']) // true (root prefix)
|
|
621
|
-
* ```
|
|
622
|
-
*/
|
|
623
|
-
declare function isPathPrefix(prefix: readonly Segment[], path: readonly Segment[]): boolean;
|
|
624
|
-
|
|
625
|
-
/**
|
|
626
|
-
* Per-FormStore registry tracking which DOM elements have opted into
|
|
627
|
-
* persistence for which paths. Lives on the FormStore so that two SFCs
|
|
628
|
-
* sharing a key share the registry — opt-ins are per-element, not
|
|
629
|
-
* per-component.
|
|
630
|
-
*
|
|
631
|
-
* The directive's input handler computes `meta.persist` for each write
|
|
632
|
-
* by calling `hasOptIn(elementId, path)` — only THIS element's writes
|
|
633
|
-
* persist if THIS element opted in. Other call sites that aren't tied
|
|
634
|
-
* to a single element (history undo/redo, field-array helpers, devtools
|
|
635
|
-
* edits) use `hasAnyOptInForPath(path)` — persist if any element has
|
|
636
|
-
* opted into that path.
|
|
637
|
-
*
|
|
638
|
-
* Internal data structure: `Map<PathKey, Set<elementId>>`. Small forms
|
|
639
|
-
* have ~10-50 paths; iteration is cheap. All operations are O(1) given
|
|
640
|
-
* (id, path).
|
|
641
|
-
*/
|
|
642
|
-
type PersistOptInRegistry = {
|
|
643
|
-
/** Add an opt-in entry; idempotent. */
|
|
644
|
-
add(elementId: string, path: PathKey): void;
|
|
645
|
-
/** Remove a single (element, path) entry. */
|
|
646
|
-
remove(elementId: string, path: PathKey): void;
|
|
647
|
-
/** Remove every opt-in for `elementId`. Called from directive's beforeUnmount. */
|
|
648
|
-
removeAllFor(elementId: string): void;
|
|
649
|
-
/** Check whether THIS element has opted into THIS path. */
|
|
650
|
-
hasOptIn(elementId: string, path: PathKey): boolean;
|
|
651
|
-
/** Check whether ANY element has opted into this path. */
|
|
652
|
-
hasAnyOptInForPath(path: PathKey): boolean;
|
|
653
|
-
/** Iterate every path that currently has at least one opt-in. */
|
|
654
|
-
optedInPaths(): IterableIterator<PathKey>;
|
|
655
|
-
/** True iff no element has opted into any path. */
|
|
656
|
-
isEmpty(): boolean;
|
|
657
|
-
/** Drop every entry. Called from FormStore.dispose. */
|
|
658
|
-
clear(): void;
|
|
659
|
-
};
|
|
660
|
-
|
|
661
|
-
/**
|
|
662
|
-
* Identifier for a form. A `FormKey` is the string passed via
|
|
663
|
-
* `useForm({ key })`, used to look up a form by name from a distant
|
|
664
|
-
* component, namespace persisted drafts, and label errors and
|
|
665
|
-
* DevTools entries. Anonymous `useForm` calls allocate one
|
|
666
|
-
* automatically; you only need to pick one when the form needs
|
|
667
|
-
* stable identity.
|
|
668
|
-
*/
|
|
669
|
-
type FormKey = string;
|
|
670
684
|
/**
|
|
671
685
|
* One validation failure. `path` points at the offending field as a
|
|
672
686
|
* structured array — `['user', 'address', 0, 'line1']` for a nested
|
|
@@ -944,6 +958,29 @@ type AbstractSchema<Form, GetValueFormType> = {
|
|
|
944
958
|
* `optional(z.tuple([...]))` reports its tuple length.
|
|
945
959
|
*/
|
|
946
960
|
arrayShapeAtPath(path: Path): number | null | undefined;
|
|
961
|
+
/**
|
|
962
|
+
* Whether the schema at `path` is a FIXED object: a closed set of
|
|
963
|
+
* declared keys (`z.object`), as opposed to an open or union container
|
|
964
|
+
* (array / record / map / set / union / discriminated union) whose
|
|
965
|
+
* element schema matches any segment.
|
|
966
|
+
*
|
|
967
|
+
* The surface proxies (`form.fields` / `form.errors`) use this to
|
|
968
|
+
* resolve a collision: a fixed object's declared keys are known ahead
|
|
969
|
+
* of any data, so a key the schema owns descends to a real terminal
|
|
970
|
+
* even when the live value hasn't been populated yet (a declared-but-
|
|
971
|
+
* absent `optional` field stays registrable). An open container can't
|
|
972
|
+
* make that promise — its element schema accepts ANY segment, so the
|
|
973
|
+
* proxy must fall back to the keys the data currently holds and read
|
|
974
|
+
* a genuinely-absent key (out-of-bounds index, missing record key,
|
|
975
|
+
* inactive variant key) as `undefined` rather than a phantom node.
|
|
976
|
+
*
|
|
977
|
+
* The empty path (the root form) is always a fixed object. Wrappers
|
|
978
|
+
* (optional / nullable / default / readonly / catch / pipe / lazy)
|
|
979
|
+
* are peeled before the kind check, so `z.object({...}).optional()`
|
|
980
|
+
* still reports `true`. A path the schema doesn't declare reports
|
|
981
|
+
* `false`.
|
|
982
|
+
*/
|
|
983
|
+
isFixedObjectAtPath(path: Path): boolean;
|
|
947
984
|
/**
|
|
948
985
|
* Return every sub-schema that could resolve at the given structured
|
|
949
986
|
* path. Multiple results are only expected for discriminated / union
|
|
@@ -2270,6 +2307,11 @@ type DisplayMachine = {
|
|
|
2270
2307
|
* not `field.validating`, is the timing anchor: the elapsed wait is
|
|
2271
2308
|
* `now - validatingSince`. Pinned to the start of the streak, so
|
|
2272
2309
|
* overlapping sub-runs do not reset it.
|
|
2310
|
+
* - `transformingSince` — the same anchor for an in-flight async
|
|
2311
|
+
* `register` transform, or `null` when none is running. Folds into the
|
|
2312
|
+
* one in-flight clock the reducer already runs for validation, so a
|
|
2313
|
+
* deferred transform rides the anti-flash spinner timing identically.
|
|
2314
|
+
* `null` for a sync-only chain, which never defers.
|
|
2273
2315
|
* - `now` — the engine's clock, injected so the reducer stays pure and
|
|
2274
2316
|
* deterministic (and frozen to `0` under SSR, where there is no clock).
|
|
2275
2317
|
*/
|
|
@@ -2277,6 +2319,7 @@ type DisplayCtx = {
|
|
|
2277
2319
|
readonly field: Omit<FieldState, FieldStateDerivedKey>;
|
|
2278
2320
|
readonly formMeta: Omit<FormMeta, FieldStateDerivedKey>;
|
|
2279
2321
|
readonly validatingSince: number | null;
|
|
2322
|
+
readonly transformingSince: number | null;
|
|
2280
2323
|
readonly now: number;
|
|
2281
2324
|
};
|
|
2282
2325
|
/**
|
|
@@ -2392,7 +2435,7 @@ type MetaTrackerValue = {
|
|
|
2392
2435
|
};
|
|
2393
2436
|
type RegisterFlatPath<Form, Key extends keyof Form = keyof Form> = FlatPathBuilder<Form, 'register', Key>;
|
|
2394
2437
|
/**
|
|
2395
|
-
*
|
|
2438
|
+
* A transformation applied to a field's value as user input flows
|
|
2396
2439
|
* from DOM through the directive's assigner. Composes left-to-right
|
|
2397
2440
|
* via the `transforms: [...]` array on `register()`.
|
|
2398
2441
|
*
|
|
@@ -2412,19 +2455,33 @@ type RegisterFlatPath<Form, Key extends keyof Form = keyof Form> = FlatPathBuild
|
|
|
2412
2455
|
* doesn't accept gets rejected at write time with a standard
|
|
2413
2456
|
* diagnostic.
|
|
2414
2457
|
*
|
|
2415
|
-
* Transforms
|
|
2416
|
-
*
|
|
2417
|
-
*
|
|
2418
|
-
*
|
|
2419
|
-
*
|
|
2420
|
-
*
|
|
2421
|
-
*
|
|
2422
|
-
*
|
|
2423
|
-
*
|
|
2424
|
-
*
|
|
2425
|
-
*
|
|
2458
|
+
* Transforms may be sync or async. The chain stays fully synchronous —
|
|
2459
|
+
* the value reaches form state in the same tick — until a transform
|
|
2460
|
+
* returns a thenable; from there the write defers, the field reads
|
|
2461
|
+
* `busy` / `transforming` while the chain settles, and the resolved
|
|
2462
|
+
* value commits to canonical state once it lands. Rapid edits discard
|
|
2463
|
+
* all but the latest (latest-request-wins), and a rejection surfaces on
|
|
2464
|
+
* `field.transformError` rather than throwing or logging:
|
|
2465
|
+
*
|
|
2466
|
+
* ```ts
|
|
2467
|
+
* export const normalize: RegisterTransform = async (v, ctx) => {
|
|
2468
|
+
* const res = await fetch(`/normalize?q=${v}`, { signal: ctx?.signal })
|
|
2469
|
+
* return res.text()
|
|
2470
|
+
* }
|
|
2471
|
+
* ```
|
|
2472
|
+
*
|
|
2473
|
+
* `ctx.signal` is an `AbortSignal` aborted when the run is superseded by
|
|
2474
|
+
* a newer edit, or torn down by `reset()` / unmount — thread it into
|
|
2475
|
+
* cancellable I/O so a stale request is dropped. A sync chain never
|
|
2476
|
+
* touches it and allocates no controller.
|
|
2477
|
+
*
|
|
2478
|
+
* A synchronous throw is caught and aborts the pipeline: subsequent
|
|
2479
|
+
* transforms don't run, nothing is written to form state, and the
|
|
2480
|
+
* assigner returns `false` — so a buggy or defensive-throw transform
|
|
2481
|
+
* never crashes the host app. (An async rejection is the
|
|
2482
|
+
* `transformError` channel above, not a throw into the host app.)
|
|
2426
2483
|
*/
|
|
2427
|
-
type RegisterTransform = (value: unknown) => unknown;
|
|
2484
|
+
type RegisterTransform = (value: unknown, ctx?: TransformContext) => unknown;
|
|
2428
2485
|
/**
|
|
2429
2486
|
* Runtime type for a slim primitive kind. Used to narrow the
|
|
2430
2487
|
* `transform` parameter and return value on a `CoercionEntry` so
|
|
@@ -2549,9 +2606,11 @@ type RegisterOptions = {
|
|
|
2549
2606
|
* form.setValue('email', slugify(lowercase(rawValue)))
|
|
2550
2607
|
* ```
|
|
2551
2608
|
*
|
|
2552
|
-
* Transforms
|
|
2553
|
-
*
|
|
2554
|
-
* the
|
|
2609
|
+
* Transforms may be sync or async: the chain stays synchronous until
|
|
2610
|
+
* one returns a thenable, then the write defers and commits the
|
|
2611
|
+
* resolved value (the field reads `busy` meanwhile). A sync throw
|
|
2612
|
+
* aborts the write; an async rejection lands on `field.transformError`
|
|
2613
|
+
* (see `RegisterTransform` for the full contract).
|
|
2555
2614
|
*
|
|
2556
2615
|
* For patterns that need to inspect the `RegisterValue` itself
|
|
2557
2616
|
* (rejection-with-side-effect, redirection to other fields, custom
|
|
@@ -2869,6 +2928,64 @@ type RegisterValue<Value = unknown> = Readonly<{
|
|
|
2869
2928
|
*/
|
|
2870
2929
|
ariaDisplayState?: Readonly<Ref<DisplayState>>;
|
|
2871
2930
|
}>;
|
|
2931
|
+
/**
|
|
2932
|
+
* Internal extension of `RegisterValue` that includes directive-private
|
|
2933
|
+
* coordination state. Imported by the directive runtime; not part of
|
|
2934
|
+
* the public surface.
|
|
2935
|
+
*
|
|
2936
|
+
* `lastTypedForm` is the user's most recently typed string form for a
|
|
2937
|
+
* numeric field while mid-typing, or `null` once the field has been
|
|
2938
|
+
* blurred / cleared. The directive populates it on every committable
|
|
2939
|
+
* input event and clears it on the change (blur) event so:
|
|
2940
|
+
*
|
|
2941
|
+
* - Mid-typing: `displayValue` returns the typed form (e.g.
|
|
2942
|
+
* `'1e2'`) when it parses back to current storage. Vue's
|
|
2943
|
+
* `:value` patch then targets the typed form, which already
|
|
2944
|
+
* equals the DOM — idempotent, no cursor reset.
|
|
2945
|
+
* - On blur: `displayValue` falls back to `String(storage)`
|
|
2946
|
+
* (`'100'`), Vue patches the DOM to match. The user sees
|
|
2947
|
+
* exactly what's stored.
|
|
2948
|
+
*
|
|
2949
|
+
* Why a separate field: JavaScript's Number carries no representation
|
|
2950
|
+
* info — `1e2 === 100`, so `String(parseFloat('1e2'))` yields `'100'`.
|
|
2951
|
+
* Tracking the typed form lets us avoid Vue's mid-typing DOM yank
|
|
2952
|
+
* without lying about storage. Only meaningful for `.number` text
|
|
2953
|
+
* inputs and `<input type="number">`; other bindings ignore it.
|
|
2954
|
+
*
|
|
2955
|
+
* @internal
|
|
2956
|
+
*/
|
|
2957
|
+
/**
|
|
2958
|
+
* Mutable holder for an async-transform run's `AbortController`, shared
|
|
2959
|
+
* between the directive — which lazily creates the controller the first
|
|
2960
|
+
* time a transform reaches for `ctx.signal` — and the store, which
|
|
2961
|
+
* aborts it when the run is superseded, cancelled, or reset.
|
|
2962
|
+
* `controller` stays `null` until `ctx.signal` is actually touched, so a
|
|
2963
|
+
* purely-sync chain never allocates one. `aborted` latches `true` the
|
|
2964
|
+
* moment the store tears the run down, so a signal accessed AFTER
|
|
2965
|
+
* teardown still resolves to an already-aborted signal rather than a
|
|
2966
|
+
* live one.
|
|
2967
|
+
*/
|
|
2968
|
+
type TransformAbortHolder = {
|
|
2969
|
+
controller: AbortController | null;
|
|
2970
|
+
aborted: boolean;
|
|
2971
|
+
};
|
|
2972
|
+
/**
|
|
2973
|
+
* The second argument handed to every transform in a `transforms: [...]`
|
|
2974
|
+
* chain. `signal` is an `AbortSignal` that aborts when the run is
|
|
2975
|
+
* superseded by a newer input, or torn down by a reset / cancel — so a
|
|
2976
|
+
* transform doing cancellable I/O (a `fetch`, a worker round-trip) can
|
|
2977
|
+
* pass `ctx.signal` through and bail the moment its result is no longer
|
|
2978
|
+
* wanted.
|
|
2979
|
+
*
|
|
2980
|
+
* The signal is lazy: the backing `AbortController` is allocated only on
|
|
2981
|
+
* first access, so a purely-synchronous chain that never reaches for
|
|
2982
|
+
* `ctx.signal` allocates nothing. It is meaningful for async transforms;
|
|
2983
|
+
* a sync chain has no in-flight I/O to cancel, so its `signal` simply
|
|
2984
|
+
* never aborts.
|
|
2985
|
+
*/
|
|
2986
|
+
type TransformContext = {
|
|
2987
|
+
readonly signal: AbortSignal;
|
|
2988
|
+
};
|
|
2872
2989
|
/**
|
|
2873
2990
|
* Custom assigner installed on an element via the directive's
|
|
2874
2991
|
* `[assignKey]` slot OR an `@update:registerValue` listener. Called
|
|
@@ -2928,6 +3045,15 @@ type CustomRegisterDirective<T, Modifiers extends string = string> = ObjectDirec
|
|
|
2928
3045
|
* from the user's input.
|
|
2929
3046
|
*/
|
|
2930
3047
|
_lastAppliedModel?: unknown;
|
|
3048
|
+
/**
|
|
3049
|
+
* Variant-specific "repaint the DOM from current storage" closure,
|
|
3050
|
+
* stashed by each input directive's `created` hook (it mirrors that
|
|
3051
|
+
* variant's post-write force-sync block). The deferred async-transform
|
|
3052
|
+
* orchestrator calls it once the resolved value has committed, so a
|
|
3053
|
+
* bare `<input v-register>` with no other reactive reader still paints
|
|
3054
|
+
* the normalized result without depending on a parent re-render.
|
|
3055
|
+
*/
|
|
3056
|
+
_syncFromStorage?: () => void;
|
|
2931
3057
|
[S: symbol]: CustomDirectiveRegisterAssignerFn;
|
|
2932
3058
|
}, RegisterValue | undefined, Modifiers, string>;
|
|
2933
3059
|
/**
|
|
@@ -3263,8 +3389,38 @@ type FieldState<Value = unknown> = {
|
|
|
3263
3389
|
* is in flight (`errors.length === 0 && !validating`). Confidence
|
|
3264
3390
|
* that "we've checked, and we have no problems right now." Use for
|
|
3265
3391
|
* green-checkmark / `aria-invalid` UX.
|
|
3392
|
+
*
|
|
3393
|
+
* Validation-only: an in-flight async transform does NOT clamp
|
|
3394
|
+
* `valid` to `false`. `valid` is the verdict on the last committed
|
|
3395
|
+
* value; `busy` is the union "work in flight" signal.
|
|
3266
3396
|
*/
|
|
3267
3397
|
readonly valid: boolean;
|
|
3398
|
+
/**
|
|
3399
|
+
* `true` while an async `register` transform is in flight at this
|
|
3400
|
+
* path: a transform returned a thenable and the resolved value has
|
|
3401
|
+
* not yet committed to form state. Always `false` for a sync-only
|
|
3402
|
+
* chain, which reaches form state in the same tick with no deferral.
|
|
3403
|
+
* Containers roll it up as a disjunction (any descendant transforming).
|
|
3404
|
+
*/
|
|
3405
|
+
readonly transforming: boolean;
|
|
3406
|
+
/**
|
|
3407
|
+
* `transforming || validating` — the union "work is in flight at this
|
|
3408
|
+
* path" signal. Drives `aria-busy` through `displayState` on a
|
|
3409
|
+
* revealed field, and is the surface to bind for a busy indicator on a
|
|
3410
|
+
* field not yet revealed (where `displayState` stays idle by the
|
|
3411
|
+
* reveal gate). Containers roll it up as a disjunction.
|
|
3412
|
+
*/
|
|
3413
|
+
readonly busy: boolean;
|
|
3414
|
+
/**
|
|
3415
|
+
* The `Error` from the most recent async transform that rejected at
|
|
3416
|
+
* this path, else `null`. A per-field normalization-failure channel
|
|
3417
|
+
* separate from validation `errors`: a transform that rejects (a
|
|
3418
|
+
* failed fetch, a parse error) surfaces here instead of crashing the
|
|
3419
|
+
* host app or logging. Cleared when a fresh transform starts or a
|
|
3420
|
+
* write supersedes it. Leaf-only — containers do not roll it up (it is
|
|
3421
|
+
* always `null` at a container path).
|
|
3422
|
+
*/
|
|
3423
|
+
readonly transformError: Error | null;
|
|
3268
3424
|
/**
|
|
3269
3425
|
* The single display-state verdict at this path: `'idle'`,
|
|
3270
3426
|
* `'pending'`, `'error'`, or `'success'`. The source of truth the
|
|
@@ -3533,15 +3689,33 @@ interface LeafSchemeFor<T> {
|
|
|
3533
3689
|
*/
|
|
3534
3690
|
type LeafWalker<T, Kind extends keyof LeafSchemeFor<unknown>, StripOptional extends boolean = true> = [T] extends [string | number | boolean | bigint | symbol | null | undefined | Date | File] ? LeafSchemeFor<T>[Kind] : [T] extends [ReadonlyArray<infer U>] ? {
|
|
3535
3691
|
readonly [K: number]: LeafWalker<U, Kind, StripOptional>;
|
|
3536
|
-
} & ContainerSelfErrorsSlot<T, Kind> : [T] extends [object] ?
|
|
3537
|
-
readonly [K in
|
|
3692
|
+
} & ContainerSelfErrorsSlot<T, Kind> : [T] extends [object] ? string extends keyof T ? {
|
|
3693
|
+
readonly [K in keyof T]: LeafWalker<T[K], Kind, StripOptional>;
|
|
3694
|
+
} & ContainerSelfErrorsSlot<T, Kind> : [IsUnion<T>] extends [true] ? StripOptional extends true ? {
|
|
3695
|
+
readonly [K in KeyofUnion<T>]-?: DiscriminatedLeaf<T, K, Kind, StripOptional>;
|
|
3538
3696
|
} & ContainerSelfErrorsSlot<T, Kind> : {
|
|
3539
|
-
readonly [K in KeyofUnion<T>]:
|
|
3697
|
+
readonly [K in KeyofUnion<T>]: DiscriminatedLeaf<T, K, Kind, StripOptional>;
|
|
3540
3698
|
} & ContainerSelfErrorsSlot<T, Kind> : StripOptional extends true ? {
|
|
3541
3699
|
readonly [K in keyof T]-?: LeafWalker<T[K], Kind, StripOptional>;
|
|
3542
3700
|
} & ContainerSelfErrorsSlot<T, Kind> : {
|
|
3543
3701
|
readonly [K in keyof T]: LeafWalker<T[K], Kind, StripOptional>;
|
|
3544
3702
|
} & ContainerSelfErrorsSlot<T, Kind> : LeafSchemeFor<T>[Kind];
|
|
3703
|
+
/**
|
|
3704
|
+
* One key of a discriminated-union container in `LeafWalker`. A key
|
|
3705
|
+
* present (and required) in EVERY variant is universal — its node is
|
|
3706
|
+
* always reachable. A variant-only or optional-in-some key is a dynamic
|
|
3707
|
+
* hop: its node is `undefined` when its variant isn't active, so it
|
|
3708
|
+
* carries node-optionality (`LeafWalker<…> | undefined`), NOT value-
|
|
3709
|
+
* optionality (`LeafWalker<… | undefined>`). `PresentValueOfUnion`
|
|
3710
|
+
* strips the synthetic absent-variant `undefined` so the present node
|
|
3711
|
+
* resolves to the precise value type; a genuine `undefined` from an
|
|
3712
|
+
* `optional` declaration survives.
|
|
3713
|
+
*
|
|
3714
|
+
* Universality is `[T] extends [Record<K, unknown>]` — true iff `T`
|
|
3715
|
+
* (the whole union) satisfies "has K, required", which holds only when
|
|
3716
|
+
* every variant declares K as a required property.
|
|
3717
|
+
*/
|
|
3718
|
+
type DiscriminatedLeaf<T, K extends PropertyKey, Kind extends keyof LeafSchemeFor<unknown>, StripOptional extends boolean> = [T] extends [Record<K, unknown>] ? LeafWalker<PresentValueOfUnion<T, K>, Kind, StripOptional> : LeafWalker<PresentValueOfUnion<T, K>, Kind, StripOptional> | undefined;
|
|
3545
3719
|
/**
|
|
3546
3720
|
* Intersection augmenting every container in the `form.errors` walker
|
|
3547
3721
|
* with a `''` sentinel slot — the per-container home for cross-field
|
|
@@ -3556,6 +3730,22 @@ type ContainerSelfErrorsSlot<T, Kind> = Kind extends 'errors' ? '' extends keyof
|
|
|
3556
3730
|
readonly ['']: readonly ValidationError[];
|
|
3557
3731
|
} : unknown;
|
|
3558
3732
|
type FieldStateMapEntry<T> = LeafWalker<T, 'field'>;
|
|
3733
|
+
/**
|
|
3734
|
+
* Result of the `form.fields(path)` string call-form. A path the schema
|
|
3735
|
+
* declares resolves to its `FieldState` — a leaf's value type, or a
|
|
3736
|
+
* container's rolled-up aggregate (every FieldState property exists
|
|
3737
|
+
* regardless of the value type). A path the schema lacks resolves to
|
|
3738
|
+
* `undefined`, because a typo is not a field and the runtime hands back
|
|
3739
|
+
* `undefined` rather than a phantom stub. A non-literal `string` could
|
|
3740
|
+
* be either, so it widens to `FieldState<unknown> | undefined`.
|
|
3741
|
+
*
|
|
3742
|
+
* Named (rather than inlined into the `FieldStateMap` call signature) so
|
|
3743
|
+
* the conditional is one cached type — keeps two structurally-identical
|
|
3744
|
+
* `FieldStateMap` instantiations (e.g. the unified `attaform/zod` return
|
|
3745
|
+
* and `UseFormReturnV4`) relatable instead of collapsing to a nominal
|
|
3746
|
+
* "two different types with this name" mismatch.
|
|
3747
|
+
*/
|
|
3748
|
+
type FieldCallResult<Form, P extends string> = [P] extends [FlatPath<Form>] ? FieldState<NestedType<Form, P>> : string extends P ? FieldState<unknown> | undefined : undefined;
|
|
3559
3749
|
/**
|
|
3560
3750
|
* Type of `form.fields` — leaf-aware drillable callable Proxy. At
|
|
3561
3751
|
* a leaf path the proxy resolves to a `FieldState<Value>`; at
|
|
@@ -3576,18 +3766,14 @@ type FieldStateMapEntry<T> = LeafWalker<T, 'field'>;
|
|
|
3576
3766
|
* string as a single key. Use chained dot/bracket or the callable
|
|
3577
3767
|
* form.
|
|
3578
3768
|
*/
|
|
3579
|
-
type FieldStateMap<Form extends GenericForm> =
|
|
3580
|
-
readonly [K in KeyofUnion<Form>]-?: FieldStateMapEntry<ValueOfUnion<Form, K>>;
|
|
3581
|
-
} : {
|
|
3582
|
-
readonly [K in keyof Form]-?: FieldStateMapEntry<Form[K]>;
|
|
3583
|
-
}) & {
|
|
3769
|
+
type FieldStateMap<Form extends GenericForm> = LeafWalker<Form, 'field'> & {
|
|
3584
3770
|
/**
|
|
3585
|
-
*
|
|
3586
|
-
*
|
|
3587
|
-
*
|
|
3588
|
-
* `FieldState<
|
|
3771
|
+
* String-path form (dynamic / programmatic). See {@link FieldCallResult}:
|
|
3772
|
+
* a path the schema declares resolves to its precise `FieldState`, a
|
|
3773
|
+
* path it lacks to `undefined`, and a non-literal `string` to
|
|
3774
|
+
* `FieldState<unknown> | undefined`.
|
|
3589
3775
|
*/
|
|
3590
|
-
(path:
|
|
3776
|
+
<P extends string>(path: P): FieldCallResult<Form, P>;
|
|
3591
3777
|
/**
|
|
3592
3778
|
* Tuple-segment form. Returns the typed `FieldStateMapEntry` for
|
|
3593
3779
|
* the resolved path when the tuple resolves to a known path.
|
|
@@ -3598,10 +3784,10 @@ type FieldStateMap<Form extends GenericForm> = ([IsUnion<Form>] extends [true] ?
|
|
|
3598
3784
|
/**
|
|
3599
3785
|
* Dynamic-array fallback for callers passing `Path`-typed (runtime)
|
|
3600
3786
|
* segment arrays — e.g. forwarding `RegisterValue.segments` to
|
|
3601
|
-
* resolve a field view.
|
|
3602
|
-
* the value type is known.
|
|
3787
|
+
* resolve a field view. The path may not resolve, so the result
|
|
3788
|
+
* widens with `| undefined`; cast when the value type is known.
|
|
3603
3789
|
*/
|
|
3604
|
-
(segments: ReadonlyArray<string | number>): FieldState<unknown
|
|
3790
|
+
(segments: ReadonlyArray<string | number>): FieldState<unknown> | undefined;
|
|
3605
3791
|
/**
|
|
3606
3792
|
* No-arg call returns the root FieldState — same as
|
|
3607
3793
|
* `form.fields([])`. Aggregates over the whole form (one
|
|
@@ -3848,15 +4034,23 @@ type FormMeta<F = unknown> = FieldState<F> & {
|
|
|
3848
4034
|
*/
|
|
3849
4035
|
readonly departAttempts: number;
|
|
3850
4036
|
/**
|
|
3851
|
-
* The error thrown or rejected by the most recent submit callback
|
|
3852
|
-
*
|
|
3853
|
-
*
|
|
4037
|
+
* The error thrown or rejected by the most recent submit callback (or
|
|
4038
|
+
* its `onError` handler), coerced to a real `Error` (a non-`Error`
|
|
4039
|
+
* throw keeps its origin on `.cause`). Cleared to `null` at the start
|
|
4040
|
+
* of each new submission attempt; stays `null` on success.
|
|
3854
4041
|
*
|
|
3855
|
-
* The submit handler
|
|
3856
|
-
*
|
|
3857
|
-
* `
|
|
4042
|
+
* The submit handler does NOT re-throw — its returned promise always
|
|
4043
|
+
* resolves, so binding it to `@submit.prevent` never manufactures a
|
|
4044
|
+
* `window` unhandledrejection. This is the single channel for "the
|
|
4045
|
+
* submit failed", read the same way in templates and after an
|
|
4046
|
+
* imperative `await submit()`. Like `hydrateError`, it stays distinct
|
|
4047
|
+
* from the curated user-error store: render it where you choose:
|
|
4048
|
+
*
|
|
4049
|
+
* ```vue
|
|
4050
|
+
* <p v-if="form.meta.submitError">{{ form.meta.submitError.message }}</p>
|
|
4051
|
+
* ```
|
|
3858
4052
|
*/
|
|
3859
|
-
readonly submitError:
|
|
4053
|
+
readonly submitError: Error | null;
|
|
3860
4054
|
/**
|
|
3861
4055
|
* Scalar mirror of `meta.errors.length`. Read it from templates and
|
|
3862
4056
|
* `watch()` without indexing the underlying array.
|
|
@@ -3926,7 +4120,7 @@ type FormMeta<F = unknown> = FieldState<F> & {
|
|
|
3926
4120
|
*
|
|
3927
4121
|
* - `GetValueFormType` — the **output / parsed shape**
|
|
3928
4122
|
* (`z.output<Schema>`). Used by `handleSubmit`'s `onSubmit`
|
|
3929
|
-
* callback and by `form.
|
|
4123
|
+
* callback and by `form.parse()`'s success payload. This is the
|
|
3930
4124
|
* shape after refinements have fired and transforms have run.
|
|
3931
4125
|
*
|
|
3932
4126
|
* - `ReadForm` — the **read / storage shape**. Used by `values`,
|
|
@@ -4023,7 +4217,7 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4023
4217
|
* `z.input<Schema>` shape — `.transform()`s have NOT run, so for
|
|
4024
4218
|
* a schema like `z.string().transform(v => v.length > 10)` the
|
|
4025
4219
|
* value reads as `string`, not `boolean`. Use `handleSubmit` or
|
|
4026
|
-
* `form.
|
|
4220
|
+
* `form.parse()` when you need the post-transform output shape.
|
|
4027
4221
|
*/
|
|
4028
4222
|
values: ValuesSurface<WriteShape<ReadForm>>;
|
|
4029
4223
|
/**
|
|
@@ -4150,6 +4344,26 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4150
4344
|
* `true` while the promise is in flight.
|
|
4151
4345
|
*/
|
|
4152
4346
|
validateAsync: (path?: FlatPath<Form>) => Promise<ValidationResponseWithoutValue<Form>>;
|
|
4347
|
+
/**
|
|
4348
|
+
* Resolve once every in-flight async `register({ transforms })` run
|
|
4349
|
+
* has settled — globally, or (with `path`) only at-or-under that path.
|
|
4350
|
+
* Resolve-never-reject: a transform that throws still settles the
|
|
4351
|
+
* field (its failure lands on `field.transformError`), so the returned
|
|
4352
|
+
* promise always resolves.
|
|
4353
|
+
*
|
|
4354
|
+
* `handleSubmit` awaits this internally before parsing, so a submit
|
|
4355
|
+
* fired the instant after an async transform still validates the
|
|
4356
|
+
* resolved value. Reach for it directly when you need the same
|
|
4357
|
+
* guarantee outside submit — e.g. before reading `form.values` in an
|
|
4358
|
+
* imperative flow or a test:
|
|
4359
|
+
*
|
|
4360
|
+
* ```ts
|
|
4361
|
+
* input.value = ' a@b.com '
|
|
4362
|
+
* await form.settleTransforms('email')
|
|
4363
|
+
* // form.values.email is now the normalized value
|
|
4364
|
+
* ```
|
|
4365
|
+
*/
|
|
4366
|
+
settleTransforms: (path?: FlatPath<Form>) => Promise<void>;
|
|
4153
4367
|
/**
|
|
4154
4368
|
* Imperative one-shot parse. Same pipeline as `validateAsync` —
|
|
4155
4369
|
* runs refinements, applies `.transform()`s, composes blank-required
|
|
@@ -4159,11 +4373,11 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4159
4373
|
* preprocess normalization applied but `.transform()` deferred. For
|
|
4160
4374
|
* schemas where the input type differs from the output type (e.g.,
|
|
4161
4375
|
* `z.string().transform(v => v.length > 10)`), `form.values.X` is
|
|
4162
|
-
* the input shape and `(await form.
|
|
4376
|
+
* the input shape and `(await form.parse()).data?.X` is the
|
|
4163
4377
|
* output shape.
|
|
4164
4378
|
*
|
|
4165
4379
|
* ```ts
|
|
4166
|
-
* const result = await form.
|
|
4380
|
+
* const result = await form.parse()
|
|
4167
4381
|
* if (result.success) {
|
|
4168
4382
|
* // result.data matches z.output<typeof schema>
|
|
4169
4383
|
* } else {
|
|
@@ -4171,11 +4385,16 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4171
4385
|
* }
|
|
4172
4386
|
* ```
|
|
4173
4387
|
*
|
|
4174
|
-
*
|
|
4175
|
-
*
|
|
4176
|
-
*
|
|
4388
|
+
* Always async, and there is no synchronous variant by design: a
|
|
4389
|
+
* schema can carry async refinements or transforms, so a sync parse
|
|
4390
|
+
* would silently miss them the moment one is added. One always-
|
|
4391
|
+
* awaited `parse` closes that category of bug entirely. The returned
|
|
4392
|
+
* promise never rejects (a thrown adapter lands as a `success: false`
|
|
4393
|
+
* response). Pass a path to parse a subtree only. `meta.validating`
|
|
4394
|
+
* flips `true` while the promise is in flight (shared with
|
|
4395
|
+
* validateAsync).
|
|
4177
4396
|
*/
|
|
4178
|
-
|
|
4397
|
+
parse: (path?: FlatPath<Form>) => Promise<ValidationResponse<GetValueFormType>>;
|
|
4179
4398
|
/**
|
|
4180
4399
|
* Bind a path to a native input via `v-register`. Returns a
|
|
4181
4400
|
* `RegisterValue` carrying the live ref and event handlers the
|
|
@@ -4696,5 +4915,5 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4696
4915
|
blankPaths: ComputedRef<BlankPathsView>;
|
|
4697
4916
|
};
|
|
4698
4917
|
|
|
4699
|
-
export { ROOT_PATH as
|
|
4700
|
-
export type {
|
|
4918
|
+
export { ROOT_PATH as a4, ROOT_PATH_KEY as a5, canonicalizePath as as, isPathPrefix as at, isUnset as au, parseDottedPath as av, unset as aw };
|
|
4919
|
+
export type { PendingValidationStatus as $, AttaformDefaults as A, FormStorage as B, CoercionEntry as C, DefaultValuesInput as D, ErrorsProxyShape as E, FormKey as F, GenericForm as G, FormStorageKind as H, HandleSubmit as I, HistoryConfig as J, IsTuple as K, IsUnion as L, JoinSegments as M, KeyofUnion as N, LiftedValueShape as O, MetaTrackerValue as P, NestedReadType as Q, RegisterModelDynamicCustomDirective as R, NestedType as S, OnError as T, UseFormConfiguration as U, ValidationError as V, OnInvalidSubmitPolicy as W, OnSubmit as X, PartialFlatPath as Y, Path as Z, PathKey as _, AbstractSchema as a, PersistConfig as a0, PersistConfigOptions as a1, PersistIncludeMode as a2, Primitive as a3, ReactiveValidationStatus as a6, RegisterDirective as a7, RegisterFlatPath as a8, RegisterOptions as a9, RegisterSelectModifier as aa, RegisterTextModifier as ab, RegisterTransform as ac, Segment as ad, SetValueCallback as ae, SetValuePayload as af, SettledValidationStatus as ag, SlimPrimitiveKind as ah, SlimRuntimeOf as ai, SubmitHandler as aj, Unset as ak, ValidateOn as al, ValidateOnConfig as am, ValidationResponse as an, ValidationResponseWithoutValue as ao, ValueOfUnion as ap, WriteMeta as aq, WriteShape as ar, SchemaFactoryOptions as ax, TransformAbortHolder as ay, PersistOptInRegistry as az, UseFormReturnType as b, RegisterValue as c, GetDisplayState as d, ApiErrorEnvelope as e, ApiErrorDetails as f, ApiErrorEntry as g, ArrayItem as h, ArrayPath as i, CoercionRegistry as j, CoercionResult as k, CustomDirectiveRegisterAssignerFn as l, DeepPartial as m, DefaultValuesResponse as n, DefaultValuesShape as o, DisplayCtx as p, DisplayMachine as q, DisplayState as r, FieldMetaPayload as s, FieldState as t, FieldStateMap as u, FieldStateMapEntry as v, FlatPath as w, FormErrorRecord as x, FormErrorsSurface as y, FormMeta as z };
|