attaform 0.22.0 → 0.23.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/README.md +7 -10
- package/dist/chunks/dev-key-collision-warnings.cjs +0 -33
- package/dist/chunks/dev-key-collision-warnings.cjs.map +1 -1
- package/dist/chunks/dev-key-collision-warnings.mjs +1 -33
- package/dist/chunks/dev-key-collision-warnings.mjs.map +1 -1
- package/dist/chunks/devtools.cjs +3 -5
- package/dist/chunks/devtools.cjs.map +1 -1
- package/dist/chunks/devtools.mjs +3 -5
- package/dist/chunks/devtools.mjs.map +1 -1
- package/dist/chunks/fingerprint2.cjs +1 -1
- package/dist/chunks/fingerprint2.mjs +1 -1
- package/dist/index.cjs +3 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -41
- package/dist/index.d.mts +6 -41
- package/dist/index.d.ts +6 -41
- package/dist/index.mjs +5 -5
- 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 +3 -11
- package/dist/runtime/plugins/attaform.cjs +2 -2
- package/dist/runtime/plugins/attaform.mjs +2 -2
- package/dist/shared/{attaform.BGwNZ9GV.d.cts → attaform.BGMRvckW.d.ts} +10 -77
- package/dist/shared/{attaform.DvUH4a3o.d.ts → attaform.BJnNK75Y.d.cts} +45 -670
- package/dist/shared/{attaform.DvUH4a3o.d.mts → attaform.BJnNK75Y.d.mts} +45 -670
- package/dist/shared/{attaform.DvUH4a3o.d.cts → attaform.BJnNK75Y.d.ts} +45 -670
- package/dist/shared/{attaform.BKFwekY2.mjs → attaform.BhI9Icek.mjs} +3 -287
- package/dist/shared/attaform.BhI9Icek.mjs.map +1 -0
- package/dist/shared/{attaform.CRzpFCjV.cjs → attaform.BibT5AS_.cjs} +2 -2
- package/dist/shared/{attaform.CRzpFCjV.cjs.map → attaform.BibT5AS_.cjs.map} +1 -1
- package/dist/shared/{attaform.DkA5J8NW.d.cts → attaform.CO0e7YVY.d.cts} +1 -46
- package/dist/shared/{attaform.DkA5J8NW.d.ts → attaform.CO0e7YVY.d.mts} +1 -46
- package/dist/shared/{attaform.DkA5J8NW.d.mts → attaform.CO0e7YVY.d.ts} +1 -46
- package/dist/shared/{attaform.Q3eAD2wD.cjs → attaform.CaYj3ZfY.cjs} +3 -3
- package/dist/shared/{attaform.Q3eAD2wD.cjs.map → attaform.CaYj3ZfY.cjs.map} +1 -1
- package/dist/shared/{attaform.AyujQoHp.cjs → attaform.Cmb_LCie.cjs} +4 -4
- package/dist/shared/{attaform.DNuiFCXG.mjs.map → attaform.Cmb_LCie.cjs.map} +1 -1
- package/dist/shared/{attaform.CsB-iKbU.mjs → attaform.CtJOd7ox.mjs} +81 -591
- package/dist/shared/attaform.CtJOd7ox.mjs.map +1 -0
- package/dist/shared/{attaform.DgCfLqay.mjs → attaform.CzVta5o2.mjs} +4 -4
- package/dist/shared/attaform.CzVta5o2.mjs.map +1 -0
- package/dist/shared/{attaform.FN0vaQAg.d.mts → attaform.D52oJiYC.d.cts} +1 -1
- package/dist/shared/{attaform.aekT7mMx.d.cts → attaform.DCkSNnPr.d.mts} +1 -1
- package/dist/shared/{attaform.01iKS_lz.cjs → attaform.Db4E4IW6.cjs} +2 -294
- package/dist/shared/attaform.Db4E4IW6.cjs.map +1 -0
- package/dist/shared/{attaform.C-RtnCJM.cjs → attaform.DbyTD8N2.cjs} +4 -4
- package/dist/shared/attaform.DbyTD8N2.cjs.map +1 -0
- package/dist/shared/{attaform.DCjgGir_.mjs → attaform.Dd1Kmmaj.mjs} +3 -3
- package/dist/shared/{attaform.DCjgGir_.mjs.map → attaform.Dd1Kmmaj.mjs.map} +1 -1
- package/dist/shared/{attaform.D4XYaasQ.d.ts → attaform.DrY8srOp.d.mts} +10 -77
- package/dist/shared/{attaform.CjMcwV7W.cjs → attaform.DsQkXE3o.cjs} +79 -599
- package/dist/shared/attaform.DsQkXE3o.cjs.map +1 -0
- package/dist/shared/{attaform.CCCeEPwa.d.mts → attaform.DuPneYR0.d.cts} +10 -77
- package/dist/shared/{attaform.6xE0Lcfd.mjs → attaform.Dx9-QQE2.mjs} +2 -2
- package/dist/shared/{attaform.6xE0Lcfd.mjs.map → attaform.Dx9-QQE2.mjs.map} +1 -1
- package/dist/shared/{attaform.DUMWQefY.d.ts → attaform.WEwfXcHq.d.ts} +1 -1
- package/dist/shared/{attaform.DNuiFCXG.mjs → attaform.alpG7rT7.mjs} +4 -4
- package/dist/shared/{attaform.AyujQoHp.cjs.map → attaform.alpG7rT7.mjs.map} +1 -1
- package/dist/zod-v3.cjs +2 -2
- package/dist/zod-v3.d.cts +3 -3
- package/dist/zod-v3.d.mts +3 -3
- package/dist/zod-v3.d.ts +3 -3
- package/dist/zod-v3.mjs +2 -2
- package/dist/zod-v4.cjs +2 -2
- package/dist/zod-v4.d.cts +5 -5
- package/dist/zod-v4.d.mts +5 -5
- package/dist/zod-v4.d.ts +5 -5
- package/dist/zod-v4.mjs +2 -2
- package/dist/zod.cjs +5 -5
- package/dist/zod.d.cts +5 -5
- package/dist/zod.d.mts +5 -5
- package/dist/zod.d.ts +5 -5
- package/dist/zod.mjs +5 -5
- package/package.json +1 -1
- package/dist/chunks/indexeddb.cjs +0 -119
- package/dist/chunks/indexeddb.cjs.map +0 -1
- package/dist/chunks/indexeddb.mjs +0 -117
- package/dist/chunks/indexeddb.mjs.map +0 -1
- package/dist/chunks/local-storage.cjs +0 -58
- package/dist/chunks/local-storage.cjs.map +0 -1
- package/dist/chunks/local-storage.mjs +0 -56
- package/dist/chunks/local-storage.mjs.map +0 -1
- package/dist/chunks/multi-tab-sync.cjs +0 -367
- package/dist/chunks/multi-tab-sync.cjs.map +0 -1
- package/dist/chunks/multi-tab-sync.mjs +0 -364
- package/dist/chunks/multi-tab-sync.mjs.map +0 -1
- package/dist/chunks/session-storage.cjs +0 -58
- package/dist/chunks/session-storage.cjs.map +0 -1
- package/dist/chunks/session-storage.mjs +0 -56
- package/dist/chunks/session-storage.mjs.map +0 -1
- package/dist/chunks/wire-persistence.cjs +0 -396
- package/dist/chunks/wire-persistence.cjs.map +0 -1
- package/dist/chunks/wire-persistence.mjs +0 -394
- package/dist/chunks/wire-persistence.mjs.map +0 -1
- package/dist/shared/attaform.01iKS_lz.cjs.map +0 -1
- package/dist/shared/attaform.BKFwekY2.mjs.map +0 -1
- package/dist/shared/attaform.C-RtnCJM.cjs.map +0 -1
- package/dist/shared/attaform.CjMcwV7W.cjs.map +0 -1
- package/dist/shared/attaform.CsB-iKbU.mjs.map +0 -1
- package/dist/shared/attaform.DgCfLqay.mjs.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ObjectDirective, Ref,
|
|
1
|
+
import { ObjectDirective, Ref, ComputedRef } from 'vue';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Schema-attached field metadata — the shared types used by both Zod
|
|
@@ -154,42 +154,6 @@ declare const ROOT_PATH_KEY: PathKey;
|
|
|
154
154
|
*/
|
|
155
155
|
declare function isPathPrefix(prefix: readonly Segment[], path: readonly Segment[]): boolean;
|
|
156
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
|
-
|
|
193
157
|
/** Internal brand for the `Unset` type. Never exposed at runtime. */
|
|
194
158
|
declare const _unsetBrand: unique symbol;
|
|
195
159
|
/**
|
|
@@ -665,8 +629,8 @@ type DefaultValuesInput<T> = T extends string ? string | Unset : T extends numbe
|
|
|
665
629
|
/**
|
|
666
630
|
* Identifier for a form. A `FormKey` is the string passed via
|
|
667
631
|
* `useForm({ key })`, used to look up a form by name from a distant
|
|
668
|
-
* component
|
|
669
|
-
*
|
|
632
|
+
* component and to label errors and DevTools entries. Anonymous
|
|
633
|
+
* `useForm` calls allocate one
|
|
670
634
|
* automatically; you only need to pick one when the form needs
|
|
671
635
|
* stable identity.
|
|
672
636
|
*/
|
|
@@ -830,9 +794,9 @@ type AbstractSchema<Form, GetValueFormType> = {
|
|
|
830
794
|
*
|
|
831
795
|
* Resolves a `Promise` so adapters can defer the structural walk (and
|
|
832
796
|
* its `canonicalStringify` helper) onto a dynamic import. The framework
|
|
833
|
-
* only ever needs the fingerprint
|
|
834
|
-
*
|
|
835
|
-
*
|
|
797
|
+
* only ever needs the fingerprint for the dev-only shared-key schema
|
|
798
|
+
* mismatch warning, so none of those bytes belong on the eager
|
|
799
|
+
* `useForm` path.
|
|
836
800
|
*
|
|
837
801
|
* The library uses this to detect schema mismatches at a shared
|
|
838
802
|
* form key: two `useForm({ key: 'x', schema })` calls are allowed
|
|
@@ -1394,64 +1358,11 @@ type ValidateOnConfig = {
|
|
|
1394
1358
|
debounceMs?: never;
|
|
1395
1359
|
};
|
|
1396
1360
|
/**
|
|
1397
|
-
*
|
|
1398
|
-
*
|
|
1399
|
-
*
|
|
1400
|
-
* - `'session'` — browser `sessionStorage` (cleared when the tab closes).
|
|
1401
|
-
* - `'indexeddb'` — IndexedDB via a zero-dependency wrapper (handles
|
|
1402
|
-
* structured-cloneable data; suitable for larger drafts).
|
|
1403
|
-
*
|
|
1404
|
-
* For anything else (encrypted storage, a native bridge, a cookie
|
|
1405
|
-
* store) pass a custom `FormStorage` object instead.
|
|
1406
|
-
*/
|
|
1407
|
-
type FormStorageKind = 'local' | 'session' | 'indexeddb';
|
|
1408
|
-
/**
|
|
1409
|
-
* Custom persistence backend. Implement this when none of the built-in
|
|
1410
|
-
* `'local'` / `'session'` / `'indexeddb'` backends fit (e.g. encrypted
|
|
1411
|
-
* storage, a cross-window broadcast layer, or a native mobile bridge).
|
|
1412
|
-
*
|
|
1413
|
-
* All methods are async. Pass values through unchanged — `getItem`
|
|
1414
|
-
* should return whatever `setItem` was given, including non-string
|
|
1415
|
-
* values. The library handles serialization for the built-in
|
|
1416
|
-
* `'local'` / `'session'` backends; custom adapters can store the
|
|
1417
|
-
* value directly if their backing store accepts structured data.
|
|
1418
|
-
*
|
|
1419
|
-
* `listKeys(prefix)` returns every key starting with `prefix`. The
|
|
1420
|
-
* library uses it on mount to clean up entries left over from older
|
|
1421
|
-
* schema versions (each persisted entry carries a schema fingerprint
|
|
1422
|
-
* suffix; mismatched entries are dropped automatically).
|
|
1423
|
-
*/
|
|
1424
|
-
type FormStorage = {
|
|
1425
|
-
/** Fetch the value previously stored under `key`. Resolve to `null`/`undefined` for misses. */
|
|
1426
|
-
getItem(key: string): Promise<unknown>;
|
|
1427
|
-
/** Persist `value` under `key`. */
|
|
1428
|
-
setItem(key: string, value: unknown): Promise<void>;
|
|
1429
|
-
/** Remove the entry at `key`. No-op if not present. */
|
|
1430
|
-
removeItem(key: string): Promise<void>;
|
|
1431
|
-
/** Return every key in this backend whose name starts with `prefix`. */
|
|
1432
|
-
listKeys(prefix: string): Promise<string[]>;
|
|
1433
|
-
};
|
|
1434
|
-
/**
|
|
1435
|
-
* What to include when persisting:
|
|
1436
|
-
*
|
|
1437
|
-
* - `'form'` (default) — only the form value. Errors get repopulated
|
|
1438
|
-
* by validation on reload anyway.
|
|
1439
|
-
* - `'form+errors'` — also persist the current error list. Useful when
|
|
1440
|
-
* the error context is expensive to recompute (e.g. cross-field
|
|
1441
|
-
* refinements that depend on server data).
|
|
1442
|
-
*/
|
|
1443
|
-
type PersistIncludeMode = 'form' | 'form+errors';
|
|
1444
|
-
/**
|
|
1445
|
-
* Per-write metadata. Used internally to flag which writes should
|
|
1446
|
-
* reach the persistence layer (e.g. only writes from elements opted
|
|
1447
|
-
* into persistence via `register(path, { persist: true })`).
|
|
1448
|
-
*
|
|
1449
|
-
* Custom directive integrations may set `persist: true` to forward
|
|
1450
|
-
* a write to the configured storage adapter; otherwise leave unset.
|
|
1361
|
+
* Per-write metadata. Used internally to tag writes so listeners and
|
|
1362
|
+
* the write funnel can treat a write specially (a blank mark, an array
|
|
1363
|
+
* structural op, a hydration replay, a per-instance config override).
|
|
1451
1364
|
*/
|
|
1452
1365
|
type WriteMeta = {
|
|
1453
|
-
/** When `true`, this write is forwarded to the configured persistence backend. */
|
|
1454
|
-
readonly persist?: boolean;
|
|
1455
1366
|
/**
|
|
1456
1367
|
* When `true`, the path being written is added to the FormStore's
|
|
1457
1368
|
* `blankPaths` set — meaning storage holds a real, schema-
|
|
@@ -1513,159 +1424,16 @@ type WriteMeta = {
|
|
|
1513
1424
|
readonly rememberVariants?: boolean;
|
|
1514
1425
|
};
|
|
1515
1426
|
/**
|
|
1516
|
-
* When `true`, marks this `applyFormReplacement` call as
|
|
1517
|
-
*
|
|
1518
|
-
*
|
|
1519
|
-
*
|
|
1520
|
-
* subsequent `undo()` can't
|
|
1521
|
-
* default. Internal — set by
|
|
1522
|
-
*
|
|
1427
|
+
* When `true`, marks this `applyFormReplacement` call as a hydration
|
|
1428
|
+
* step (the async-`defaultValues` / `activate()` / `rehydrate()`
|
|
1429
|
+
* path). Modules that snapshot the form state (notably the history
|
|
1430
|
+
* module) treat hydration as the baseline: stacks reset to a single
|
|
1431
|
+
* seed of the post-hydration value, so a subsequent `undo()` can't
|
|
1432
|
+
* recover the transient pre-hydration default. Internal — set by the
|
|
1433
|
+
* activate path in `create-form-store.ts`. Don't set from consumer
|
|
1434
|
+
* code.
|
|
1523
1435
|
*/
|
|
1524
1436
|
readonly hydration?: boolean;
|
|
1525
|
-
/**
|
|
1526
|
-
* When `true`, this write originated from a sibling tab's
|
|
1527
|
-
* BroadcastChannel broadcast (the multi-tab sync module's inbound
|
|
1528
|
-
* apply). Listeners that initiate side effects check this flag to
|
|
1529
|
-
* avoid amplification loops and spurious side effects:
|
|
1530
|
-
*
|
|
1531
|
-
* - The multi-tab sync OUTBOUND broadcaster skips so a remote-driven
|
|
1532
|
-
* write doesn't echo back across the channel.
|
|
1533
|
-
* - The history module updates its diff anchor but does NOT push a
|
|
1534
|
-
* delta — remote writes aren't part of the local user's undo
|
|
1535
|
-
* timeline.
|
|
1536
|
-
* - The persistence writer skips so the receiving tab doesn't
|
|
1537
|
-
* double-persist a value the originating tab already wrote.
|
|
1538
|
-
*
|
|
1539
|
-
* Internal — set by `createMultiTabSyncModule`. Don't set from
|
|
1540
|
-
* consumer code.
|
|
1541
|
-
*/
|
|
1542
|
-
readonly crossTab?: boolean;
|
|
1543
|
-
/**
|
|
1544
|
-
* When `true`, this write lands normally (storage, validation,
|
|
1545
|
-
* persistence, history) but does NOT notify `form.onChange` handlers.
|
|
1546
|
-
* The side-channel reacts to user edits, not programmatic rebaselines:
|
|
1547
|
-
* `reset()` tags its replacement with this flag, and the public
|
|
1548
|
-
* `setValue(path, value, { silent: true })` option forwards it so a
|
|
1549
|
-
* consumer hydrating the form (loading a saved record into the fields)
|
|
1550
|
-
* can land values without echoing each one back through an autosave
|
|
1551
|
-
* loop. The store's internal taggers and that single consumer-facing
|
|
1552
|
-
* option are the only writers.
|
|
1553
|
-
*/
|
|
1554
|
-
readonly silent?: boolean;
|
|
1555
|
-
};
|
|
1556
|
-
/** Options for a `setValue` write. */
|
|
1557
|
-
type SetValueOptions = {
|
|
1558
|
-
/**
|
|
1559
|
-
* When `true`, the write lands normally (storage, validation, persistence,
|
|
1560
|
-
* history) but does NOT notify `form.onChange` handlers. Use it to hydrate
|
|
1561
|
-
* the form (load a saved record into the fields) without echoing every
|
|
1562
|
-
* field back through an autosave loop.
|
|
1563
|
-
*/
|
|
1564
|
-
readonly silent?: boolean;
|
|
1565
|
-
};
|
|
1566
|
-
/**
|
|
1567
|
-
* A source address for `form.onChange` — the subtree(s) a handler reacts to.
|
|
1568
|
-
*
|
|
1569
|
-
* - a dotted path string (`'user.email'`) — one leaf or subtree;
|
|
1570
|
-
* - a list of path strings (`['shipping', 'billing']`) — react to any of
|
|
1571
|
-
* several paths; the handler fires once per matched path, `ctx.path`
|
|
1572
|
-
* distinguishing which;
|
|
1573
|
-
* - a getter or ref / computed resolving to either — re-read on each write,
|
|
1574
|
-
* so the aim can follow a moving target (the active list row). Re-aiming
|
|
1575
|
-
* is never itself a trigger; only a real write dispatches.
|
|
1576
|
-
*
|
|
1577
|
-
* Omit the source entirely (`form.onChange(handler)`) to react to the whole
|
|
1578
|
-
* form. An empty list (`form.onChange([], handler)`) lists zero paths, so it
|
|
1579
|
-
* never fires — that is a deliberate no-op, NOT a shorthand for the root.
|
|
1580
|
-
*/
|
|
1581
|
-
type OnChangeSource = MaybeRefOrGetter<string | readonly string[]>;
|
|
1582
|
-
/**
|
|
1583
|
-
* Context handed to an `onChange` handler alongside the changed value.
|
|
1584
|
-
*
|
|
1585
|
-
* `onChange` is a pure side-channel: it reacts to value changes and runs
|
|
1586
|
-
* side effects, but never touches the form's own lifecycle. Nothing a
|
|
1587
|
-
* handler does here marks the form dirty, pending, or validating — autosave
|
|
1588
|
-
* status lives in the consumer's own state, validation in `.refine` and
|
|
1589
|
-
* `field.show*`.
|
|
1590
|
-
*/
|
|
1591
|
-
type OnChangeContext<FormApi = unknown> = {
|
|
1592
|
-
/**
|
|
1593
|
-
* The source path this fire is for, in dotted form (`'user.email'`).
|
|
1594
|
-
* The empty string `''` is the whole form (a root handler). For a
|
|
1595
|
-
* multi-path source, the handler fires once per matched path and `path`
|
|
1596
|
-
* names which one.
|
|
1597
|
-
*/
|
|
1598
|
-
readonly path: string;
|
|
1599
|
-
/**
|
|
1600
|
-
* The value at the source path BEFORE this change, seeded at registration.
|
|
1601
|
-
* Accurate for leaf sources. For a container or the whole form, an
|
|
1602
|
-
* in-place leaf edit preserves the container's reference, so `previous`
|
|
1603
|
-
* can be reference-equal to the current value (Vue's deep-watch gotcha) —
|
|
1604
|
-
* snapshot inside the handler if a true container diff is needed.
|
|
1605
|
-
*/
|
|
1606
|
-
readonly previous: unknown;
|
|
1607
|
-
/**
|
|
1608
|
-
* Aborted when a newer write to the same source supersedes this run. A
|
|
1609
|
-
* debounced or awaiting handler should bail on `signal.aborted` (or pass
|
|
1610
|
-
* `signal` straight to `fetch`) so superseded work cancels itself.
|
|
1611
|
-
*/
|
|
1612
|
-
readonly signal: AbortSignal;
|
|
1613
|
-
/** Retry counter — `0` on the first run, incremented by `onError`'s `retry()`. */
|
|
1614
|
-
readonly attempt: number;
|
|
1615
|
-
/**
|
|
1616
|
-
* The form handle, so a portable `useForm({ onChange })` handler can reach
|
|
1617
|
-
* back into the form (e.g. `ctx.form.validateAsync(ctx.path)` to gate an
|
|
1618
|
-
* autosave on validity). Typed precisely by the `form.onChange` overload.
|
|
1619
|
-
*/
|
|
1620
|
-
readonly form: FormApi;
|
|
1621
|
-
/**
|
|
1622
|
-
* The leaf path(s), in dotted form, that actually changed in this
|
|
1623
|
-
* dispatch. For a leaf source this is just `[path]`; for a container or
|
|
1624
|
-
* the whole form it is every changed descendant.
|
|
1625
|
-
*/
|
|
1626
|
-
readonly changed: readonly string[];
|
|
1627
|
-
};
|
|
1628
|
-
/**
|
|
1629
|
-
* Context handed to an `onChange` handler's `onError` callback when the
|
|
1630
|
-
* handler throws or rejects.
|
|
1631
|
-
*/
|
|
1632
|
-
type OnChangeErrorContext<FormApi = unknown> = {
|
|
1633
|
-
/** The source path this run was for, in dotted form (`''` for the whole form). */
|
|
1634
|
-
readonly path: string;
|
|
1635
|
-
/** The value passed to the handler that failed. */
|
|
1636
|
-
readonly value: unknown;
|
|
1637
|
-
/** The attempt number that failed (`0` on the first run). */
|
|
1638
|
-
readonly attempt: number;
|
|
1639
|
-
/**
|
|
1640
|
-
* Re-run the handler with the same value and `attempt + 1`. A no-op once a
|
|
1641
|
-
* newer write has superseded this run — stale work is never resurrected.
|
|
1642
|
-
* Backoff and a retry cap are the consumer's to impose.
|
|
1643
|
-
*/
|
|
1644
|
-
readonly retry: () => void;
|
|
1645
|
-
/** The form handle. Typed precisely by the `form.onChange` overload. */
|
|
1646
|
-
readonly form: FormApi;
|
|
1647
|
-
};
|
|
1648
|
-
/** A reaction to form value changes. Its return is ignored; throws route to `onError`. */
|
|
1649
|
-
type OnChangeHandler<Value = unknown, FormApi = unknown> = (value: Value, ctx: OnChangeContext<FormApi>) => void | Promise<void>;
|
|
1650
|
-
/** Handles a throw / rejection from an `onChange` handler. Must not throw. */
|
|
1651
|
-
type OnChangeErrorHandler<FormApi = unknown> = (error: unknown, ctx: OnChangeErrorContext<FormApi>) => void;
|
|
1652
|
-
/** Options for `form.onChange`. */
|
|
1653
|
-
type OnChangeOptions<FormApi = unknown> = {
|
|
1654
|
-
/**
|
|
1655
|
-
* Called when the handler throws or its promise rejects. Without it, a
|
|
1656
|
-
* failure is swallowed (logged in dev). `onChange` never throws into the
|
|
1657
|
-
* write that triggered it.
|
|
1658
|
-
*/
|
|
1659
|
-
readonly onError?: OnChangeErrorHandler<FormApi>;
|
|
1660
|
-
};
|
|
1661
|
-
/**
|
|
1662
|
-
* The `useForm({ onChange })` option — a whole-form handler registered at
|
|
1663
|
-
* construction, bound to the form's lifetime. Either a bare handler or a
|
|
1664
|
-
* `{ handler, onError }` pair.
|
|
1665
|
-
*/
|
|
1666
|
-
type OnChangeConfig<Value = unknown, FormApi = unknown> = OnChangeHandler<Value, FormApi> | {
|
|
1667
|
-
readonly handler: OnChangeHandler<Value, FormApi>;
|
|
1668
|
-
readonly onError?: OnChangeErrorHandler<FormApi>;
|
|
1669
1437
|
};
|
|
1670
1438
|
/**
|
|
1671
1439
|
* Undo/redo configuration passed via `useForm({ history })`.
|
|
@@ -1731,81 +1499,6 @@ type FormHistoryNamespace = {
|
|
|
1731
1499
|
*/
|
|
1732
1500
|
readonly size: number;
|
|
1733
1501
|
};
|
|
1734
|
-
/**
|
|
1735
|
-
* Full options bag for `useForm({ persist })`. Use this when you need
|
|
1736
|
-
* to override defaults beyond picking the backend.
|
|
1737
|
-
*
|
|
1738
|
-
* For backend-only setup, the shorthand forms are equivalent:
|
|
1739
|
-
*
|
|
1740
|
-
* ```ts
|
|
1741
|
-
* useForm({ persist: 'local' })
|
|
1742
|
-
* // same as
|
|
1743
|
-
* useForm({ persist: { storage: 'local' } })
|
|
1744
|
-
* ```
|
|
1745
|
-
*/
|
|
1746
|
-
type PersistConfigOptions = {
|
|
1747
|
-
/**
|
|
1748
|
-
* Where to persist. Pass `'local'` / `'session'` / `'indexeddb'` to
|
|
1749
|
-
* use a built-in backend, or a custom `FormStorage` object for
|
|
1750
|
-
* anything else. The built-in backends are loaded on demand, so
|
|
1751
|
-
* picking `'local'` doesn't pull in IndexedDB code.
|
|
1752
|
-
*/
|
|
1753
|
-
storage: FormStorageKind | FormStorage;
|
|
1754
|
-
/**
|
|
1755
|
-
* Storage key namespace. Defaults to `attaform:${formKey}`.
|
|
1756
|
-
* Override when you need a custom prefix (e.g. multi-tenant apps
|
|
1757
|
-
* where the same form key may exist per-tenant).
|
|
1758
|
-
*/
|
|
1759
|
-
key?: string;
|
|
1760
|
-
/**
|
|
1761
|
-
* How long to wait after the last mutation before writing. Default
|
|
1762
|
-
* `300` ms.
|
|
1763
|
-
*
|
|
1764
|
-
* Pass `0` to disable debouncing — every form change writes to the
|
|
1765
|
-
* storage adapter immediately, no `setTimeout` indirection. Almost
|
|
1766
|
-
* never the right choice for production (the storage adapter sees
|
|
1767
|
-
* every keystroke), but useful for tests or for diagnosing perceived
|
|
1768
|
-
* lag.
|
|
1769
|
-
*/
|
|
1770
|
-
debounceMs?: number;
|
|
1771
|
-
/**
|
|
1772
|
-
* What to persist. `'form'` (default) is sufficient for most cases —
|
|
1773
|
-
* fresh validation on reload repopulates errors. Pick `'form+errors'`
|
|
1774
|
-
* when the error state is expensive to recompute (e.g. server-side
|
|
1775
|
-
* cross-field validation).
|
|
1776
|
-
*/
|
|
1777
|
-
include?: PersistIncludeMode;
|
|
1778
|
-
/**
|
|
1779
|
-
* When `true` (default), the persisted entry is wiped after
|
|
1780
|
-
* `handleSubmit`'s submit callback resolves successfully. Set to
|
|
1781
|
-
* `false` if you need the draft to survive across submissions.
|
|
1782
|
-
*/
|
|
1783
|
-
clearOnSubmitSuccess?: boolean;
|
|
1784
|
-
};
|
|
1785
|
-
/**
|
|
1786
|
-
* Persistence configuration for `useForm({ persist })`. Off by default —
|
|
1787
|
-
* with no config, the form does no reads, no writes, and pulls in no
|
|
1788
|
-
* storage code.
|
|
1789
|
-
*
|
|
1790
|
-
* Three input forms; pick the one that reads best at the call site:
|
|
1791
|
-
*
|
|
1792
|
-
* ```ts
|
|
1793
|
-
* // shorthand: built-in backend
|
|
1794
|
-
* useForm({ persist: 'local' })
|
|
1795
|
-
*
|
|
1796
|
-
* // shorthand: custom adapter
|
|
1797
|
-
* useForm({ persist: encryptedStorage })
|
|
1798
|
-
*
|
|
1799
|
-
* // full options bag
|
|
1800
|
-
* useForm({ persist: { storage: 'local', debounceMs: 500 } })
|
|
1801
|
-
* ```
|
|
1802
|
-
*
|
|
1803
|
-
* Per-field opt-in: setting `persist` is necessary but not sufficient.
|
|
1804
|
-
* Each field that should actually persist also needs
|
|
1805
|
-
* `register('foo', { persist: true })` — sensitive fields must opt in
|
|
1806
|
-
* explicitly so they don't accidentally land in client-side storage.
|
|
1807
|
-
*/
|
|
1808
|
-
type PersistConfig = FormStorageKind | FormStorage | PersistConfigOptions;
|
|
1809
1502
|
/**
|
|
1810
1503
|
* Configuration object passed to `useForm`. All fields except `schema`
|
|
1811
1504
|
* are optional.
|
|
@@ -1816,7 +1509,6 @@ type PersistConfig = FormStorageKind | FormStorage | PersistConfigOptions;
|
|
|
1816
1509
|
* defaultValues: { email: '' },
|
|
1817
1510
|
* validateOn: 'change',
|
|
1818
1511
|
* debounceMs: 200,
|
|
1819
|
-
* persist: 'local',
|
|
1820
1512
|
* })
|
|
1821
1513
|
* ```
|
|
1822
1514
|
*/
|
|
@@ -1846,8 +1538,7 @@ type UseFormConfiguration<Form extends GenericForm, GetValueFormType, Schema ext
|
|
|
1846
1538
|
* - to look it up from a distant component via `injectForm(key)`;
|
|
1847
1539
|
* - to share state across components (multiple `useForm({ key })`
|
|
1848
1540
|
* calls with the same key resolve to the same form);
|
|
1849
|
-
* - to give DevTools and validation errors a recognisable label
|
|
1850
|
-
* - to namespace persisted drafts.
|
|
1541
|
+
* - to give DevTools and validation errors a recognisable label.
|
|
1851
1542
|
*
|
|
1852
1543
|
* Keys starting with `__atta:` are reserved for internal use and
|
|
1853
1544
|
* throw `ReservedFormKeyError` if passed.
|
|
@@ -1951,41 +1642,6 @@ type UseFormConfiguration<Form extends GenericForm, GetValueFormType, Schema ext
|
|
|
1951
1642
|
* per blur for `<input v-register.lazy>`).
|
|
1952
1643
|
*/
|
|
1953
1644
|
debounceMs?: number;
|
|
1954
|
-
/**
|
|
1955
|
-
* A whole-form `onChange` handler, registered at construction and bound to
|
|
1956
|
-
* the form's lifetime. The same side-channel as `form.onChange(handler)`,
|
|
1957
|
-
* but declared in the options bag so it travels with the form (handy for a
|
|
1958
|
-
* `useAutosave`-style composable). Pass a handler, or `{ handler, onError }`.
|
|
1959
|
-
*
|
|
1960
|
-
* For path-scoped reactions, call `form.onChange('path', handler)` on the
|
|
1961
|
-
* returned form instead. `onChange` never touches the form's own
|
|
1962
|
-
* lifecycle — keep validation in `.refine` and `field.show*`.
|
|
1963
|
-
*/
|
|
1964
|
-
onChange?: OnChangeConfig<Form, UseFormReturnType<Form>>;
|
|
1965
|
-
/**
|
|
1966
|
-
* Opt-in persistence of the form's draft state. Off by default —
|
|
1967
|
-
* with no config, no reads, no writes, no storage code is loaded.
|
|
1968
|
-
*
|
|
1969
|
-
* Three input forms; pick the one that reads best:
|
|
1970
|
-
*
|
|
1971
|
-
* ```ts
|
|
1972
|
-
* useForm({ persist: 'local' }) // built-in backend
|
|
1973
|
-
* useForm({ persist: encryptedStorage }) // custom backend
|
|
1974
|
-
* useForm({ persist: { storage: 'local', debounceMs: 500 } })
|
|
1975
|
-
* ```
|
|
1976
|
-
*
|
|
1977
|
-
* Per-field opt-in is required: every field that should actually
|
|
1978
|
-
* persist needs `register(path, { persist: true })`. Without any
|
|
1979
|
-
* opt-ins, the form mounts but never writes to storage — and a
|
|
1980
|
-
* dev-mode warning surfaces the misconfiguration. This guard
|
|
1981
|
-
* prevents sensitive fields from accidentally leaking to
|
|
1982
|
-
* client-side storage.
|
|
1983
|
-
*
|
|
1984
|
-
* Switching backends across reloads (e.g. `'local'` → `'session'`)
|
|
1985
|
-
* automatically clears the previous backend's entry so old drafts
|
|
1986
|
-
* don't orphan.
|
|
1987
|
-
*/
|
|
1988
|
-
persist?: PersistConfig;
|
|
1989
1645
|
/**
|
|
1990
1646
|
* Opt-in undo/redo. Off by default. `true` enables with a 128-position
|
|
1991
1647
|
* cap; `{ max: N }` tunes the cap.
|
|
@@ -2013,12 +1669,8 @@ type UseFormConfiguration<Form extends GenericForm, GetValueFormType, Schema ext
|
|
|
2013
1669
|
* every switch (the data is gone). The new variant initializes
|
|
2014
1670
|
* from its slim default.
|
|
2015
1671
|
*
|
|
2016
|
-
* Memory is in-memory only and does not survive
|
|
2017
|
-
*
|
|
2018
|
-
* variant memory starts empty — the first discriminator switch
|
|
2019
|
-
* after reload loses any persisted typing in the outgoing variant.
|
|
2020
|
-
* Consumers needing cross-session continuity must persist beyond
|
|
2021
|
-
* the variant boundary themselves.
|
|
1672
|
+
* Memory is in-memory only and does not survive a fresh mount: a
|
|
1673
|
+
* page reload starts every discriminator's variant memory empty.
|
|
2022
1674
|
*
|
|
2023
1675
|
* `reset()` clears variant memory. `resetField(path)` clears any
|
|
2024
1676
|
* memory entry whose union path equals or sits under `path`.
|
|
@@ -2074,54 +1726,6 @@ type UseFormConfiguration<Form extends GenericForm, GetValueFormType, Schema ext
|
|
|
2074
1726
|
* and the broader description of where the cap is read.
|
|
2075
1727
|
*/
|
|
2076
1728
|
maxRecursionDepth?: number;
|
|
2077
|
-
/**
|
|
2078
|
-
* Override the path-segment name stems treated as sensitive for this
|
|
2079
|
-
* form. Sensitive paths are excluded from persistence writes and
|
|
2080
|
-
* multi-tab sync broadcasts. (DevTools renders raw values by design;
|
|
2081
|
-
* it does not redact.)
|
|
2082
|
-
*
|
|
2083
|
-
* Resolution: per-form value (this field) > global default
|
|
2084
|
-
* (`createAttaform({ defaults: { sensitiveNames } })`) > library
|
|
2085
|
-
* default (`DEFAULT_SENSITIVE_NAMES`).
|
|
2086
|
-
*
|
|
2087
|
-
* Pass an empty array `[]` as the explicit opt-out — "nothing is
|
|
2088
|
-
* sensitive on this form" — for fully-trusted internal tooling.
|
|
2089
|
-
* See `AttaformDefaults.sensitiveNames` for composition examples.
|
|
2090
|
-
*/
|
|
2091
|
-
sensitiveNames?: readonly string[];
|
|
2092
|
-
/**
|
|
2093
|
-
* Cross-tab synchronisation via BroadcastChannel. **Defaults to
|
|
2094
|
-
* `false` (opt-in).** Setting `true` on a keyed `useForm` callsite
|
|
2095
|
-
* auto-pairs the form with same-keyed siblings in other same-origin
|
|
2096
|
-
* tabs and mirrors their mutations in near real-time.
|
|
2097
|
-
*
|
|
2098
|
-
* **Resolution order (per-register override > per-form > global > library):**
|
|
2099
|
-
*
|
|
2100
|
-
* register(path, { multiTab }) > useForm({ multiTab }) > AttaformDefaults.multiTab > library default (`false`)
|
|
2101
|
-
*
|
|
2102
|
-
* **Why opt-in.** Same-keyed forms broadcasting by default leaks
|
|
2103
|
-
* surprise: a user editing in one tab sees their values appear in a
|
|
2104
|
-
* sibling tab they forgot was open, including PII / PHI for forms
|
|
2105
|
-
* that don't explicitly use `sensitiveNames`. Mirrors the `persist`
|
|
2106
|
-
* default (also opt-in): both opt-in surfaces compose into one
|
|
2107
|
-
* consistent "richer state needs explicit consent" rule.
|
|
2108
|
-
*
|
|
2109
|
-
* **What's stripped even when opt-in.** `File` and `Blob` values
|
|
2110
|
-
* never traverse the channel regardless of this flag (security +
|
|
2111
|
-
* `structuredClone` cost). Sensitive-named paths (via
|
|
2112
|
-
* `sensitiveNames`) are stripped both directions. See the
|
|
2113
|
-
* multi-tab sync page for the full security model.
|
|
2114
|
-
*
|
|
2115
|
-
* **Secure-context requirement.** Even with `multiTab: true`, sync
|
|
2116
|
-
* is silently disabled outside `window.isSecureContext === true`
|
|
2117
|
-
* (HTTPS or localhost). On plain HTTP a one-shot dev warning fires
|
|
2118
|
-
* and the module noops.
|
|
2119
|
-
*
|
|
2120
|
-
* **Anonymous (auto-keyed) forms skip sync entirely** — without a
|
|
2121
|
-
* consumer-supplied `key`, cross-tab identity is undefined and the
|
|
2122
|
-
* channel would be solo by construction.
|
|
2123
|
-
*/
|
|
2124
|
-
multiTab?: boolean;
|
|
2125
1729
|
/**
|
|
2126
1730
|
* Whether `v-register` automatically manages aria attributes
|
|
2127
1731
|
* (`aria-invalid`, `aria-busy`, `aria-required`, `aria-describedby`)
|
|
@@ -2178,8 +1782,8 @@ type UseFormConfiguration<Form extends GenericForm, GetValueFormType, Schema ext
|
|
|
2178
1782
|
* app-level default is fine — forms that switch to `'blur'` /
|
|
2179
1783
|
* `'submit'` simply ignore the inherited `debounceMs`.
|
|
2180
1784
|
*
|
|
2181
|
-
* `schema`, `key`,
|
|
2182
|
-
*
|
|
1785
|
+
* `schema`, `key`, and `defaultValues` are not configurable here —
|
|
1786
|
+
* they belong on the per-form call.
|
|
2183
1787
|
*/
|
|
2184
1788
|
type AttaformDefaults = {
|
|
2185
1789
|
/** Default for `useForm({ strict })`. Default `true`. */
|
|
@@ -2304,56 +1908,6 @@ type AttaformDefaults = {
|
|
|
2304
1908
|
* confident the recursion is bounded by the actual data shape.
|
|
2305
1909
|
*/
|
|
2306
1910
|
maxRecursionDepth?: number;
|
|
2307
|
-
/**
|
|
2308
|
-
* Override the path-segment name stems treated as sensitive.
|
|
2309
|
-
* Sensitive paths are excluded from persistence writes and multi-tab
|
|
2310
|
-
* sync broadcasts — one configurable source of truth across those
|
|
2311
|
-
* surfaces. (DevTools renders raw values by design; it does not
|
|
2312
|
-
* redact.)
|
|
2313
|
-
*
|
|
2314
|
-
* Library default is `DEFAULT_SENSITIVE_NAMES` (exported from
|
|
2315
|
-
* `attaform`); compose to extend:
|
|
2316
|
-
*
|
|
2317
|
-
* ```ts
|
|
2318
|
-
* import { DEFAULT_SENSITIVE_NAMES, createAttaform } from 'attaform'
|
|
2319
|
-
*
|
|
2320
|
-
* createAttaform({
|
|
2321
|
-
* defaults: { sensitiveNames: [...DEFAULT_SENSITIVE_NAMES, 'mrn', 'tax_id'] }
|
|
2322
|
-
* })
|
|
2323
|
-
* ```
|
|
2324
|
-
*
|
|
2325
|
-
* Pass an empty array `[]` as the explicit opt-out — "nothing is
|
|
2326
|
-
* sensitive" — for fully-trusted internal tooling. When present at
|
|
2327
|
-
* the per-form level via `useForm({ sensitiveNames })`, the per-form
|
|
2328
|
-
* list REPLACES the global one (consumers compose their own
|
|
2329
|
-
* additive lists via the exported default).
|
|
2330
|
-
*/
|
|
2331
|
-
sensitiveNames?: readonly string[];
|
|
2332
|
-
/**
|
|
2333
|
-
* App-wide default for `useForm({ multiTab })`. Library default is
|
|
2334
|
-
* `false` (opt-in) — same posture as `persist`. Set to `true` once
|
|
2335
|
-
* at the plugin level to enable cross-tab sync for every form in
|
|
2336
|
-
* the app by default; individual forms can still opt out via
|
|
2337
|
-
* `useForm({ multiTab: false })`.
|
|
2338
|
-
*
|
|
2339
|
-
* **Resolution order (per-form wins):**
|
|
2340
|
-
*
|
|
2341
|
-
* useForm({ multiTab }) > AttaformDefaults.multiTab > library default (`false`)
|
|
2342
|
-
*
|
|
2343
|
-
* **Why opt-in.** Auto-broadcasting same-keyed forms surprises users
|
|
2344
|
-
* (a value typed in one tab appearing in another they forgot was
|
|
2345
|
-
* open) and leaks state for forms that don't explicitly use
|
|
2346
|
-
* `sensitiveNames`. Paired with `persist` (also opt-in), the two
|
|
2347
|
-
* "richer state" surfaces follow one consistent rule: explicit
|
|
2348
|
-
* consent.
|
|
2349
|
-
*
|
|
2350
|
-
* **Secure-context gate.** Even with `multiTab: true`, sync only
|
|
2351
|
-
* activates over HTTPS or localhost. On plain HTTP, the module
|
|
2352
|
-
* silently noops with a one-shot dev-mode warning — production
|
|
2353
|
-
* deployments MUST be served over HTTPS for sync to function. See
|
|
2354
|
-
* the multi-tab-sync recipe's Security section for the threat model.
|
|
2355
|
-
*/
|
|
2356
|
-
multiTab?: boolean;
|
|
2357
1911
|
/**
|
|
2358
1912
|
* App-wide default for `useForm({ autoAria })`. Library default is
|
|
2359
1913
|
* `true`: `v-register` keeps `aria-invalid` / `aria-busy` /
|
|
@@ -2674,55 +2228,10 @@ type CoercionEntry<I extends SlimPrimitiveKind = SlimPrimitiveKind, O extends Sl
|
|
|
2674
2228
|
*/
|
|
2675
2229
|
type CoercionRegistry = readonly CoercionEntry[];
|
|
2676
2230
|
/**
|
|
2677
|
-
* Options for `register(path, options)`. Per-field
|
|
2678
|
-
*
|
|
2679
|
-
* adding a new field can't accidentally leak into the persistence
|
|
2680
|
-
* pipeline unless the field's `register` call says so explicitly.
|
|
2231
|
+
* Options for `register(path, options)`. Per-field configuration
|
|
2232
|
+
* applied at the binding's own call site.
|
|
2681
2233
|
*/
|
|
2682
2234
|
type RegisterOptions = {
|
|
2683
|
-
/**
|
|
2684
|
-
* Opt this field into the form's persistence pipeline. The form
|
|
2685
|
-
* also needs `useForm({ persist })` configured for any storage
|
|
2686
|
-
* activity to happen.
|
|
2687
|
-
*
|
|
2688
|
-
* Persistence follows the field's lifecycle: writes flow on
|
|
2689
|
-
* mount, the field is dropped from the persisted draft on unmount.
|
|
2690
|
-
* If multiple inputs bind to the same path, the path keeps
|
|
2691
|
-
* persisting as long as any opted-in input is mounted.
|
|
2692
|
-
*
|
|
2693
|
-
* When the path looks sensitive (password / cvv / ssn / token /
|
|
2694
|
-
* etc.) the opt-in is skipped with a one-shot dev warning unless
|
|
2695
|
-
* `acknowledgeSensitive: true` is also set — the field simply isn't
|
|
2696
|
-
* persisted (the secure default). It never throws.
|
|
2697
|
-
*/
|
|
2698
|
-
persist?: boolean;
|
|
2699
|
-
/**
|
|
2700
|
-
* Suppress the sensitive-name guard. Required to persist any path
|
|
2701
|
-
* whose name matches the heuristic (password, cvv, ssn, etc.).
|
|
2702
|
-
* Treat this as a code-review checkpoint: setting it should be a
|
|
2703
|
-
* deliberate decision that the path's data is safe to land in
|
|
2704
|
-
* client-side storage for this user's session.
|
|
2705
|
-
*/
|
|
2706
|
-
acknowledgeSensitive?: boolean;
|
|
2707
|
-
/**
|
|
2708
|
-
* Opt this field OUT of multi-tab sync. The form-level cascade
|
|
2709
|
-
* activates sync by default; passing `multiTab: false` on a single
|
|
2710
|
-
* register call keeps that path tab-local — outbound patches at
|
|
2711
|
-
* the path are stripped, and inbound patches at the path are
|
|
2712
|
-
* rejected (symmetric tab-local behaviour).
|
|
2713
|
-
*
|
|
2714
|
-
* The opt-out is downgrade-only — you cannot pass `multiTab: true`
|
|
2715
|
-
* to bring sync back on a form whose form-level `multiTab` is
|
|
2716
|
-
* `false` (in that case the sync module never instantiated; there's
|
|
2717
|
-
* no broadcaster to opt back into).
|
|
2718
|
-
*
|
|
2719
|
-
* Use for fields that hold transient per-tab UI state inside an
|
|
2720
|
-
* otherwise-synced form (e.g. an editor's cursor position field
|
|
2721
|
-
* mirrored into the form for save-on-blur), or for individual
|
|
2722
|
-
* paths the consumer wants to scope to the originating tab without
|
|
2723
|
-
* disabling sync globally.
|
|
2724
|
-
*/
|
|
2725
|
-
multiTab?: boolean;
|
|
2726
2235
|
/**
|
|
2727
2236
|
* Sync transformation pipeline applied to user-typed values before
|
|
2728
2237
|
* they reach form state. Composes left-to-right: each transform
|
|
@@ -2783,7 +2292,7 @@ type RegisterOptions = {
|
|
|
2783
2292
|
* Or read `innerRef` directly when integrating with custom components.
|
|
2784
2293
|
*
|
|
2785
2294
|
* The returned value is a `shallowReadonly` reactive proxy: top-level
|
|
2786
|
-
* reads (`rv.path`, `rv.formKey`, `rv.
|
|
2295
|
+
* reads (`rv.path`, `rv.formKey`, `rv.segments`, …) track in reactive
|
|
2787
2296
|
* scopes, mutations are blocked, and inner refs (`innerRef`,
|
|
2788
2297
|
* `displayValue`) keep their `Ref` shape.
|
|
2789
2298
|
*
|
|
@@ -2803,16 +2312,14 @@ type RegisterValue<Value = unknown> = Readonly<{
|
|
|
2803
2312
|
* automatically; expose it to custom integrations that need to
|
|
2804
2313
|
* register an element manually.
|
|
2805
2314
|
*
|
|
2806
|
-
* Recording the element
|
|
2807
|
-
*
|
|
2808
|
-
* their own.
|
|
2315
|
+
* Recording the element drives the form's element map (used for
|
|
2316
|
+
* `field.meta.connected`, `focusFirstError`, and `scrollToFirstError`).
|
|
2809
2317
|
*/
|
|
2810
2318
|
registerElement: (el: HTMLElement) => void;
|
|
2811
2319
|
/**
|
|
2812
2320
|
* Detach an HTML element from this binding. Pair with
|
|
2813
|
-
* `registerElement` for custom integrations.
|
|
2814
|
-
*
|
|
2815
|
-
* "no auto-persist".
|
|
2321
|
+
* `registerElement` for custom integrations. Drops the element from
|
|
2322
|
+
* the form's element map.
|
|
2816
2323
|
*/
|
|
2817
2324
|
deregisterElement: (el: HTMLElement) => void;
|
|
2818
2325
|
/**
|
|
@@ -2820,16 +2327,10 @@ type RegisterValue<Value = unknown> = Readonly<{
|
|
|
2820
2327
|
* write was accepted, `false` when it was rejected (e.g. wrong
|
|
2821
2328
|
* primitive type for the path).
|
|
2822
2329
|
*
|
|
2823
|
-
*
|
|
2824
|
-
* the
|
|
2825
|
-
*
|
|
2826
|
-
*
|
|
2827
|
-
* and consumer assigners can omit `meta` to participate in the same
|
|
2828
|
-
* persistence channel the default assigner uses.
|
|
2829
|
-
*
|
|
2830
|
-
* Pass an explicit `meta` to override the auto-derivation, e.g.
|
|
2831
|
-
* `{ persist: false }` to skip persistence for a transient write
|
|
2832
|
-
* even when the element is opted in.
|
|
2330
|
+
* The write path for custom directives and consumer assigners: it
|
|
2331
|
+
* routes through the same funnel (and per-instance meta) as the
|
|
2332
|
+
* directive's default assigner. Caller-supplied `meta` passes through
|
|
2333
|
+
* unchanged.
|
|
2833
2334
|
*/
|
|
2834
2335
|
setValueWithInternalPath: (value: unknown, meta?: WriteMeta) => boolean;
|
|
2835
2336
|
/**
|
|
@@ -2878,55 +2379,6 @@ type RegisterValue<Value = unknown> = Readonly<{
|
|
|
2878
2379
|
* `key`.
|
|
2879
2380
|
*/
|
|
2880
2381
|
formInstanceId: string;
|
|
2881
|
-
/**
|
|
2882
|
-
* Whether this binding opted into persistence via `register(path, { persist: true })`.
|
|
2883
|
-
* @internal
|
|
2884
|
-
*/
|
|
2885
|
-
persist: boolean;
|
|
2886
|
-
/**
|
|
2887
|
-
* Whether this binding acknowledged a sensitive-name override.
|
|
2888
|
-
* @internal
|
|
2889
|
-
*/
|
|
2890
|
-
acknowledgeSensitive: boolean;
|
|
2891
|
-
/**
|
|
2892
|
-
* Per-element persistence opt-in registry. Used by directive integrations.
|
|
2893
|
-
* @internal
|
|
2894
|
-
*/
|
|
2895
|
-
persistOptIns: PersistOptInRegistry;
|
|
2896
|
-
/**
|
|
2897
|
-
* Resolved sensitive-path predicate honoring this form's
|
|
2898
|
-
* `sensitiveNames` cascade. The directive calls this through
|
|
2899
|
-
* `allowSensitivePersist` when a `register('path', { persist: true })`
|
|
2900
|
-
* binding mounts so a per-form custom list (e.g. extending with
|
|
2901
|
-
* `'mrn'`) gates persistence enrolment correctly.
|
|
2902
|
-
* @internal
|
|
2903
|
-
*/
|
|
2904
|
-
isSensitivePath: (path: Path | PathKey | string) => boolean;
|
|
2905
|
-
/**
|
|
2906
|
-
* Whether this binding declared `register('path', { multiTab: false })`.
|
|
2907
|
-
* Drives the directive's mount/unmount lifecycle: when `false`, the
|
|
2908
|
-
* directive's `created` hook bumps `state.noSyncPaths` for this
|
|
2909
|
-
* path, and `beforeUnmount` decrements. When `true` (the default),
|
|
2910
|
-
* the binding rides the form-level cascade.
|
|
2911
|
-
* @internal
|
|
2912
|
-
*/
|
|
2913
|
-
multiTab: boolean;
|
|
2914
|
-
/**
|
|
2915
|
-
* Pre-bound mount hook for `multiTab: false` bindings — calls
|
|
2916
|
-
* `state.incrementNoSyncOptOut(path)` with this binding's path.
|
|
2917
|
-
* `undefined` when `multiTab !== false`. The directive invokes
|
|
2918
|
-
* during the mount lifecycle.
|
|
2919
|
-
* @internal
|
|
2920
|
-
*/
|
|
2921
|
-
markNoSync?: () => void;
|
|
2922
|
-
/**
|
|
2923
|
-
* Pre-bound unmount hook for `multiTab: false` bindings — calls
|
|
2924
|
-
* `state.decrementNoSyncOptOut(path)`. Paired with `markNoSync`;
|
|
2925
|
-
* the directive invokes on `beforeUnmount` (and on `beforeUpdate`
|
|
2926
|
-
* when the binding transitions out of opt-out).
|
|
2927
|
-
* @internal
|
|
2928
|
-
*/
|
|
2929
|
-
unmarkNoSync?: () => void;
|
|
2930
2382
|
/**
|
|
2931
2383
|
* Sync transform pipeline applied by the directive's assigner to
|
|
2932
2384
|
* user-typed values before they reach form state. See
|
|
@@ -2978,8 +2430,7 @@ type RegisterValue<Value = unknown> = Readonly<{
|
|
|
2978
2430
|
* Add this field's path to the form's `blankPaths` set,
|
|
2979
2431
|
* writing the slim default to storage. Returns the `setValueAtPath`
|
|
2980
2432
|
* boolean (`true` accepted, `false` rejected by the slim-primitive
|
|
2981
|
-
* gate).
|
|
2982
|
-
* the same persistence channel as user-typed writes.
|
|
2433
|
+
* gate).
|
|
2983
2434
|
*
|
|
2984
2435
|
* Called by the directive's input listener on numeric clear (commit
|
|
2985
2436
|
* 5) and by the imperative `setValue(path, unset)` translation
|
|
@@ -4422,11 +3873,8 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4422
3873
|
* type at a leaf). Refinement-level mismatches (out-of-enum
|
|
4423
3874
|
* values, failing format checks, etc.) succeed and surface as
|
|
4424
3875
|
* field errors instead.
|
|
4425
|
-
*
|
|
4426
|
-
* Pass `{ silent: true }` to land the write without notifying
|
|
4427
|
-
* `form.onChange` handlers (e.g. hydrating a saved record).
|
|
4428
3876
|
*/
|
|
4429
|
-
<Value extends SetValuePayload<DefaultValuesShape<Form>, WriteShape<Form>>>(value: Value
|
|
3877
|
+
<Value extends SetValuePayload<DefaultValuesShape<Form>, WriteShape<Form>>>(value: Value): boolean;
|
|
4430
3878
|
/**
|
|
4431
3879
|
* Write at a specific path. Pass a value or a callback receiving
|
|
4432
3880
|
* the previous value at that path.
|
|
@@ -4444,49 +3892,14 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4444
3892
|
* it blank (storage holds the slim default; UI displays
|
|
4445
3893
|
* empty; submit raises "No value supplied" for required schemas).
|
|
4446
3894
|
*/
|
|
4447
|
-
<Path extends FlatPath<Form>, Value extends PathSetValuePayload<NestedType<Form, Path>>>(path: Path, value: Value
|
|
3895
|
+
<Path extends FlatPath<Form>, Value extends PathSetValuePayload<NestedType<Form, Path>>>(path: Path, value: Value): boolean;
|
|
4448
3896
|
/**
|
|
4449
3897
|
* Tuple-segment form. Equivalent to the dotted-string overload —
|
|
4450
3898
|
* useful when paths are built from variables or arrays:
|
|
4451
3899
|
* `form.setValue([prefix, 'line1'], 'value')`. The resolved leaf
|
|
4452
3900
|
* type is exact, matching the dotted-string form.
|
|
4453
3901
|
*/
|
|
4454
|
-
<const S extends ReadonlyArray<string | number>, Value extends PathSetValuePayload<NestedType<Form, JoinSegments<S>>>>(segments: S & ([JoinSegments<S>] extends [FlatPath<Form>] ? unknown : never), value: Value
|
|
4455
|
-
};
|
|
4456
|
-
/**
|
|
4457
|
-
* Subscribe to form value changes — the side-channel autosave is built on.
|
|
4458
|
-
* Three call forms:
|
|
4459
|
-
*
|
|
4460
|
-
* - `form.onChange(handler, options?)` — react to the whole form.
|
|
4461
|
-
* - `form.onChange('user.email', handler, options?)` — react to one path;
|
|
4462
|
-
* `value` is that path's value.
|
|
4463
|
-
* - `form.onChange(source, handler, options?)` — react to a list of paths,
|
|
4464
|
-
* or a getter / ref resolving to a path or list (re-read on each write,
|
|
4465
|
-
* so the aim can follow a moving target like the active list row).
|
|
4466
|
-
*
|
|
4467
|
-
* The handler runs AFTER the value lands. Its return is ignored, and a
|
|
4468
|
-
* throw or rejection routes to `options.onError`, never into the write that
|
|
4469
|
-
* triggered it. Returns an idempotent `stop()`; called inside a component's
|
|
4470
|
-
* setup it also stops automatically on unmount.
|
|
4471
|
-
*
|
|
4472
|
-
* `onChange` is a pure side-channel: nothing it does marks the form dirty,
|
|
4473
|
-
* pending, or validating. Keep validation feedback in `.refine` and
|
|
4474
|
-
* `field.show*`, and track autosave status in your own state.
|
|
4475
|
-
*
|
|
4476
|
-
* ```ts
|
|
4477
|
-
* form.onChange('user.email', async (email, ctx) => {
|
|
4478
|
-
* const verdict = await ctx.form.validateAsync(ctx.path)
|
|
4479
|
-
* if (verdict.success) await api.save({ email }, { signal: ctx.signal })
|
|
4480
|
-
* }, { onError: (error, ctx) => ctx.retry() })
|
|
4481
|
-
* ```
|
|
4482
|
-
*/
|
|
4483
|
-
onChange: {
|
|
4484
|
-
/** React to the whole form. `value` is the current form. */
|
|
4485
|
-
(handler: OnChangeHandler<ReadForm, UseFormReturnType<Form, GetValueFormType, ReadForm, K>>, options?: OnChangeOptions<UseFormReturnType<Form, GetValueFormType, ReadForm, K>>): () => void;
|
|
4486
|
-
/** React to one path. `value` is that path's value. */
|
|
4487
|
-
<P extends FlatPath<Form>>(source: P, handler: OnChangeHandler<NestedType<Form, P>, UseFormReturnType<Form, GetValueFormType, ReadForm, K>>, options?: OnChangeOptions<UseFormReturnType<Form, GetValueFormType, ReadForm, K>>): () => void;
|
|
4488
|
-
/** React to a list of paths, or a getter / ref / computed. `value` is unknown. */
|
|
4489
|
-
(source: OnChangeSource, handler: OnChangeHandler<unknown, UseFormReturnType<Form, GetValueFormType, ReadForm, K>>, options?: OnChangeOptions<UseFormReturnType<Form, GetValueFormType, ReadForm, K>>): () => void;
|
|
3902
|
+
<const S extends ReadonlyArray<string | number>, Value extends PathSetValuePayload<NestedType<Form, JoinSegments<S>>>>(segments: S & ([JoinSegments<S>] extends [FlatPath<Form>] ? unknown : never), value: Value): boolean;
|
|
4490
3903
|
};
|
|
4491
3904
|
/**
|
|
4492
3905
|
* Reactive validation status. Re-runs whenever the form (or the
|
|
@@ -4577,10 +3990,7 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4577
3990
|
*
|
|
4578
3991
|
* ```vue
|
|
4579
3992
|
* <input v-register="form.register('email')" />
|
|
4580
|
-
* <input
|
|
4581
|
-
* type="password"
|
|
4582
|
-
* v-register="form.register('password', { persist: true, acknowledgeSensitive: true })"
|
|
4583
|
-
* />
|
|
3993
|
+
* <input v-register="form.register('username', { transforms: [trim] })" />
|
|
4584
3994
|
* ```
|
|
4585
3995
|
*
|
|
4586
3996
|
* Also accepts a segment-array form for callers building paths
|
|
@@ -4594,9 +4004,8 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4594
4004
|
* </fieldset>
|
|
4595
4005
|
* ```
|
|
4596
4006
|
*
|
|
4597
|
-
* Pass `options.
|
|
4598
|
-
*
|
|
4599
|
-
* for storage activity to actually happen.
|
|
4007
|
+
* Pass `options.transforms` to run a sync normalisation pipeline over
|
|
4008
|
+
* user-typed values before they reach form state.
|
|
4600
4009
|
*/
|
|
4601
4010
|
register: {
|
|
4602
4011
|
<Path extends RegisterFlatPath<Form, keyof Form>>(path: Path, options?: RegisterOptions): RegisterValue<NestedReadType<WriteShape<ReadForm>, Path>>;
|
|
@@ -4840,11 +4249,7 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4840
4249
|
* - field errors;
|
|
4841
4250
|
* - touched / focused / blurred per-field flags;
|
|
4842
4251
|
* - submission state (`submitting` / `submissionAttempts` /
|
|
4843
|
-
* `submitted` / `submitError`)
|
|
4844
|
-
* - the persisted draft, if persistence is configured.
|
|
4845
|
-
*
|
|
4846
|
-
* The next edit on a still-mounted opted-in input will start
|
|
4847
|
-
* persisting again automatically.
|
|
4252
|
+
* `submitted` / `submitError`).
|
|
4848
4253
|
*/
|
|
4849
4254
|
reset: (nextDefaultValues?: DefaultValuesInput<Form>) => void;
|
|
4850
4255
|
/**
|
|
@@ -4854,9 +4259,6 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4854
4259
|
*
|
|
4855
4260
|
* No-op when the path doesn't exist on the form (e.g. a typo'd
|
|
4856
4261
|
* dynamic key).
|
|
4857
|
-
*
|
|
4858
|
-
* If persistence is configured, the matching subpath is removed
|
|
4859
|
-
* from the persisted draft too.
|
|
4860
4262
|
*/
|
|
4861
4263
|
resetField: (path: FlatPath<Form>) => void;
|
|
4862
4264
|
/**
|
|
@@ -4892,8 +4294,8 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4892
4294
|
* on a `false` return.
|
|
4893
4295
|
*
|
|
4894
4296
|
* Sugar over `setValue(path, schema.getEmptyValueAtPath(path))` —
|
|
4895
|
-
* no separate bookkeeping. Variant memory, history,
|
|
4896
|
-
*
|
|
4297
|
+
* no separate bookkeeping. Variant memory, history, and listeners
|
|
4298
|
+
* all see this as a regular write at the path.
|
|
4897
4299
|
*
|
|
4898
4300
|
* `clear()` (no arg) targets the whole form. `clear('')` targets
|
|
4899
4301
|
* the empty-string path slot SPECIFICALLY — the two are NOT
|
|
@@ -4904,33 +4306,6 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4904
4306
|
<Path extends FlatPath<Form> | ''>(path: Path): boolean;
|
|
4905
4307
|
<const S extends ReadonlyArray<string | number>>(segments: S & ([JoinSegments<S>] extends [FlatPath<Form> | ''] ? unknown : never)): boolean;
|
|
4906
4308
|
};
|
|
4907
|
-
/**
|
|
4908
|
-
* Write the current value at `path` to storage immediately. Useful
|
|
4909
|
-
* for explicit "Save draft" buttons, `beforeunload` handlers, or
|
|
4910
|
-
* multi-step checkpoints where the user shouldn't wait for the
|
|
4911
|
-
* debounce window.
|
|
4912
|
-
*
|
|
4913
|
-
* Bypasses both the per-field opt-in and the debouncer. Existing
|
|
4914
|
-
* paths in the persisted draft are preserved (this is a merge,
|
|
4915
|
-
* not a replace).
|
|
4916
|
-
*
|
|
4917
|
-
* For sensitive-looking paths, warns once and no-ops unless you pass
|
|
4918
|
-
* `{ acknowledgeSensitive: true }` — it never throws. Also a no-op
|
|
4919
|
-
* when `useForm({ persist })` wasn't configured.
|
|
4920
|
-
*/
|
|
4921
|
-
persist: (path: FlatPath<Form>, options?: {
|
|
4922
|
-
acknowledgeSensitive?: boolean;
|
|
4923
|
-
}) => Promise<void>;
|
|
4924
|
-
/**
|
|
4925
|
-
* Remove data from the persisted draft. Without arguments, wipes
|
|
4926
|
-
* the entire entry. With a path, removes just that subpath.
|
|
4927
|
-
*
|
|
4928
|
-
* Does not change the in-memory form state — pair with `reset()`
|
|
4929
|
-
* / `resetField()` if you need both. Future edits to still-mounted
|
|
4930
|
-
* opted-in fields will re-populate the entry. No-op when
|
|
4931
|
-
* persistence isn't configured.
|
|
4932
|
-
*/
|
|
4933
|
-
clearPersistedDraft: (path?: FlatPath<Form>) => Promise<void>;
|
|
4934
4309
|
/**
|
|
4935
4310
|
* Consolidated undo/redo namespace — `form.history.{undo, redo,
|
|
4936
4311
|
* clear, canUndo, canRedo, size}`. Always present; inert when
|
|
@@ -5090,5 +4465,5 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
5090
4465
|
blankPaths: ComputedRef<BlankPathsView>;
|
|
5091
4466
|
};
|
|
5092
4467
|
|
|
5093
|
-
export {
|
|
5094
|
-
export type {
|
|
4468
|
+
export { ROOT_PATH as $, ROOT_PATH_KEY as a0, canonicalizePath as an, isPathPrefix as ao, isUnset as ap, parseDottedPath as aq, unset as ar };
|
|
4469
|
+
export type { AttaformDefaults as A, HistoryConfig as B, CoercionEntry as C, DefaultValuesInput as D, ErrorsProxyShape as E, FormKey as F, GenericForm as G, HandleSubmit as H, IsTuple as I, IsUnion as J, JoinSegments as K, KeyofUnion as L, LiftedValueShape as M, MetaTrackerValue as N, NestedReadType as O, NestedType as P, OnError as Q, RegisterModelDynamicCustomDirective as R, OnInvalidSubmitPolicy as S, OnSubmit as T, UseFormConfiguration as U, ValidationError as V, PartialFlatPath as W, Path as X, PathKey as Y, PendingValidationStatus as Z, Primitive as _, AbstractSchema as a, ReactiveValidationStatus as a1, RegisterDirective as a2, RegisterFlatPath as a3, RegisterOptions as a4, RegisterSelectModifier as a5, RegisterTextModifier as a6, RegisterTransform as a7, Segment as a8, SetValueCallback as a9, SetValuePayload as aa, SettledValidationStatus as ab, SlimPrimitiveKind as ac, SlimRuntimeOf as ad, SubmitHandler as ae, Unset as af, ValidateOn as ag, ValidateOnConfig as ah, ValidationResponse as ai, ValidationResponseWithoutValue as aj, ValueOfUnion as ak, WriteMeta as al, WriteShape as am, SchemaFactoryOptions as as, TransformAbortHolder as at, 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 };
|