attaform 0.30.1 → 0.31.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/abstract.d.mts +5 -5
- package/dist/abstract.mjs +4 -4
- package/dist/dev/abstract.mjs +4 -4
- package/dist/dev/chunks/devtools.mjs +3 -3
- package/dist/dev/directive.mjs +1 -1
- package/dist/dev/history.mjs +15 -2
- package/dist/dev/index.mjs +5 -5
- package/dist/dev/runtime/plugins/attaform.mjs +1 -1
- package/dist/dev/shared/{attaform-dev.zlvDr0WB.mjs → attaform-dev.04aupFBW.mjs} +3 -2
- package/dist/dev/shared/{attaform-dev.DxHdkkPG.mjs → attaform-dev.3uTCYwy8.mjs} +770 -254
- package/dist/dev/shared/{attaform-dev.BJK1kqHY.mjs → attaform-dev.BpVGFSFa.mjs} +88 -115
- package/dist/dev/shared/{attaform-dev.Chm4D6SJ.mjs → attaform-dev.Bu6wgrA5.mjs} +3 -3
- package/dist/dev/shared/{attaform-dev.BMQ3GcgD.mjs → attaform-dev.Cbx0AiQF.mjs} +476 -337
- package/dist/dev/shared/attaform-dev.CwYTWyPX.mjs +120 -0
- package/dist/dev/shared/{attaform-dev.DuEE4GU1.mjs → attaform-dev.D7lKyM_7.mjs} +4 -4
- package/dist/dev/shared/{attaform-dev.CT7MDjPy.mjs → attaform-dev.OceE0X3v.mjs} +154 -229
- package/dist/{shared/attaform.DRsANMok.mjs → dev/shared/attaform-dev.PTGM9KE1.mjs} +16 -15
- package/dist/{shared/attaform.8mfKZCwH.mjs → dev/shared/attaform-dev.n6n00owJ.mjs} +49 -128
- package/dist/dev/zod-v3.mjs +6 -6
- package/dist/dev/zod-v4.mjs +6 -6
- package/dist/dev/zod.mjs +5 -5
- package/dist/directive.d.mts +2 -2
- package/dist/directive.mjs +1 -1
- package/dist/history.d.mts +1 -1
- package/dist/history.mjs +15 -2
- package/dist/index.d.mts +16 -55
- package/dist/index.mjs +5 -5
- package/dist/runtime/components/AttaformDevtoolsPanel.vue +3 -3
- package/dist/runtime/plugins/attaform.mjs +1 -1
- package/dist/shared/{attaform.CO918TdU.mjs → attaform.B5b-HmhH.mjs} +88 -115
- package/dist/shared/{attaform.2FslhB9R.d.mts → attaform.B9PYKlhB.d.mts} +43 -19
- package/dist/shared/{attaform.D_f1WgYf.mjs → attaform.BPMOl562.mjs} +458 -319
- package/dist/{dev/shared/attaform-dev.CZz4GYZ6.mjs → shared/attaform.BPSqtU7a.mjs} +44 -156
- package/dist/shared/{attaform.CdZIEf7_.mjs → attaform.BhtAZysa.mjs} +3 -2
- package/dist/shared/{attaform.BcQwgWaq.d.mts → attaform.CYlF4P6X.d.mts} +58 -17
- package/dist/shared/{attaform.WiGdIqgx.mjs → attaform.CdA9bfRv.mjs} +3 -3
- package/dist/shared/{attaform.BIWicztt.mjs → attaform.DAf4ehIe.mjs} +765 -251
- package/dist/shared/{attaform.ZYn2ahzJ.mjs → attaform.DBCbxlyk.mjs} +59 -1
- package/dist/shared/{attaform.L0kUn3vL.d.mts → attaform.DZOynI6c.d.mts} +1 -1
- package/dist/shared/{attaform.B2iebkPA.mjs → attaform.KEfNRDot.mjs} +4 -4
- package/dist/shared/attaform._1Zp3mDG.mjs +96 -0
- package/dist/shared/{attaform.Br8EBn5B.d.mts → attaform.i13OEHJF.d.mts} +195 -38
- package/dist/{dev/shared/attaform-dev.BUIFcTYf.mjs → shared/attaform.j9xI_ObC.mjs} +16 -15
- package/dist/shared/{attaform.D_pt1gOj.mjs → attaform.u6jfHoed.mjs} +154 -229
- package/dist/transforms.mjs +1 -1
- package/dist/vite.mjs +1 -1
- package/dist/zod-v3.d.mts +4 -4
- package/dist/zod-v3.mjs +6 -6
- package/dist/zod-v4.d.mts +22 -16
- package/dist/zod-v4.mjs +6 -6
- package/dist/zod.d.mts +4 -4
- package/dist/zod.mjs +5 -5
- package/package.json +2 -1
- package/skills/attaform/SKILL.md +2 -1
- package/skills/attaform/references/custom-components.md +4 -0
|
@@ -119,6 +119,20 @@ const NATIVE_FORM_TAGS = /* @__PURE__ */ new Set([
|
|
|
119
119
|
"label",
|
|
120
120
|
"button"
|
|
121
121
|
]);
|
|
122
|
+
const HOST_MODIFIERS = ["lazy", "trim", "number"];
|
|
123
|
+
function hostModifiersLiteral(registerDirective) {
|
|
124
|
+
const present = HOST_MODIFIERS.filter(
|
|
125
|
+
(name) => registerDirective?.modifiers.some((m) => m.content === name) === true
|
|
126
|
+
);
|
|
127
|
+
return present.length === 0 ? "{}" : `{ ${present.map((name) => `${name}: true`).join(", ")} }`;
|
|
128
|
+
}
|
|
129
|
+
function isInputListenerSlot(prop) {
|
|
130
|
+
if (prop.type !== NodeTypes.DIRECTIVE || prop.name !== "on" && prop.name !== "bind") {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
if (prop.arg === void 0) return true;
|
|
134
|
+
return prop.arg.type === NodeTypes.SIMPLE_EXPRESSION && prop.arg.content === (prop.name === "on" ? "input" : "onInput");
|
|
135
|
+
}
|
|
122
136
|
function inferOptionValueFromChildren(node) {
|
|
123
137
|
if (!("children" in node)) return null;
|
|
124
138
|
const children = node.children;
|
|
@@ -275,6 +289,11 @@ const componentBridgeTransform = (node, context) => {
|
|
|
275
289
|
node.props.push(valueProp);
|
|
276
290
|
}
|
|
277
291
|
if (isPlainComponentHost) {
|
|
292
|
+
const hostModifiers = hostModifiersLiteral(
|
|
293
|
+
node.props.find(
|
|
294
|
+
(p) => p.type === NodeTypes.DIRECTIVE && p.name === "register"
|
|
295
|
+
)
|
|
296
|
+
);
|
|
278
297
|
removePropsByName(node.props, [
|
|
279
298
|
"model",
|
|
280
299
|
"modelValue",
|
|
@@ -317,7 +336,7 @@ const componentBridgeTransform = (node, context) => {
|
|
|
317
336
|
const updateInitExpression = createCompoundExpression([
|
|
318
337
|
"$event => (",
|
|
319
338
|
...modelValuePropExpArray,
|
|
320
|
-
|
|
339
|
+
`)?.setValueFromHost?.($event, ${hostModifiers})`
|
|
321
340
|
]);
|
|
322
341
|
const updateSimpleExpression = createSimpleExpression(
|
|
323
342
|
flattenExpression(updateInitExpression),
|
|
@@ -346,6 +365,45 @@ const componentBridgeTransform = (node, context) => {
|
|
|
346
365
|
loc: selectLoc
|
|
347
366
|
};
|
|
348
367
|
node.props.push(updateModelValueProp);
|
|
368
|
+
const inputAlreadyInjected = node.props.some(
|
|
369
|
+
(p) => p.type === NodeTypes.DIRECTIVE && p.name === "bind" && p.arg?.type === NodeTypes.SIMPLE_EXPRESSION && p.arg.content === "onInput" && p.exp !== void 0 && flattenExpression(p.exp).includes("setValueFromHostInput")
|
|
370
|
+
);
|
|
371
|
+
if (!inputAlreadyInjected) {
|
|
372
|
+
const inputInitExpression = createCompoundExpression([
|
|
373
|
+
"$event => (",
|
|
374
|
+
...modelValuePropExpArray,
|
|
375
|
+
`)?.setValueFromHostInput?.($event, ${hostModifiers})`
|
|
376
|
+
]);
|
|
377
|
+
const inputSimpleExpression = createSimpleExpression(
|
|
378
|
+
flattenExpression(inputInitExpression),
|
|
379
|
+
false
|
|
380
|
+
);
|
|
381
|
+
let inputOutputExp;
|
|
382
|
+
try {
|
|
383
|
+
inputOutputExp = processExpression(inputSimpleExpression, {
|
|
384
|
+
...context,
|
|
385
|
+
prefixIdentifiers: false
|
|
386
|
+
});
|
|
387
|
+
} catch (err) {
|
|
388
|
+
console.error(
|
|
389
|
+
"[attaform] component-bridge transform: processExpression failed for onInput; falling back to the unprocessed expression.",
|
|
390
|
+
err
|
|
391
|
+
);
|
|
392
|
+
inputOutputExp = inputSimpleExpression;
|
|
393
|
+
}
|
|
394
|
+
const inputProp = {
|
|
395
|
+
rawName: "@input",
|
|
396
|
+
arg: createSimpleExpression("onInput", true),
|
|
397
|
+
exp: inputOutputExp,
|
|
398
|
+
name: "bind",
|
|
399
|
+
modifiers: [],
|
|
400
|
+
type: NodeTypes.DIRECTIVE,
|
|
401
|
+
loc: selectLoc
|
|
402
|
+
};
|
|
403
|
+
const authorListenerIndex = node.props.findIndex(isInputListenerSlot);
|
|
404
|
+
if (authorListenerIndex === -1) node.props.push(inputProp);
|
|
405
|
+
else node.props.splice(authorListenerIndex, 0, inputProp);
|
|
406
|
+
}
|
|
349
407
|
}
|
|
350
408
|
const registerExprArray = Array.isArray(registerSummarizedProp?.value) ? registerSummarizedProp.value : [registerSummarizedProp?.value ?? "undefined"];
|
|
351
409
|
const hasAuthorDisabled = selectSummarizedProps.findIndex((p) => isExactKey(p.key, "disabled")) !== -1;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { App } from 'vue';
|
|
2
|
-
import {
|
|
2
|
+
import { an as RegisterModelDynamicCustomDirective } from './attaform.i13OEHJF.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The `v-register` directive. Bind a form field to a native input, select,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { a as InvalidUseFormConfigError } from './attaform.
|
|
2
|
-
import { u as useForm$2 } from './attaform.
|
|
3
|
-
import { u as useForm$1 } from './attaform.
|
|
4
|
-
import { i as installingFieldMetaStore, g as getFieldMetaForSchema } from './attaform.
|
|
1
|
+
import { a as InvalidUseFormConfigError } from './attaform.BhtAZysa.mjs';
|
|
2
|
+
import { u as useForm$2 } from './attaform.u6jfHoed.mjs';
|
|
3
|
+
import { u as useForm$1 } from './attaform.B5b-HmhH.mjs';
|
|
4
|
+
import { i as installingFieldMetaStore, g as getFieldMetaForSchema } from './attaform.j9xI_ObC.mjs';
|
|
5
5
|
|
|
6
6
|
function isZodV4SchemaShape(value) {
|
|
7
7
|
if (typeof value !== "object" || value === null) return false;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
function callConsumerFn(fn, fallback, site, detail) {
|
|
2
|
+
try {
|
|
3
|
+
return fn();
|
|
4
|
+
} catch (err) {
|
|
5
|
+
return fallback;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
function readConsumerProp(obj, key) {
|
|
9
|
+
try {
|
|
10
|
+
return obj[key];
|
|
11
|
+
} catch {
|
|
12
|
+
return void 0;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function consumerKeys(obj) {
|
|
16
|
+
try {
|
|
17
|
+
return Object.keys(obj);
|
|
18
|
+
} catch {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function readConsumerIndex(arr, i) {
|
|
23
|
+
try {
|
|
24
|
+
return arr[i];
|
|
25
|
+
} catch {
|
|
26
|
+
return void 0;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function consumerSymbolKeys(obj) {
|
|
30
|
+
try {
|
|
31
|
+
return Object.getOwnPropertySymbols(obj);
|
|
32
|
+
} catch {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function consumerHas(obj, key) {
|
|
37
|
+
try {
|
|
38
|
+
return key in obj;
|
|
39
|
+
} catch {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function safeAssign(target, key, value) {
|
|
45
|
+
if (key === "__proto__") {
|
|
46
|
+
Object.defineProperty(target, key, {
|
|
47
|
+
value,
|
|
48
|
+
writable: true,
|
|
49
|
+
enumerable: true,
|
|
50
|
+
configurable: true
|
|
51
|
+
});
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
target[key] = value;
|
|
55
|
+
}
|
|
56
|
+
const SHADOWED_KEYS = new Set(Object.getOwnPropertyNames(Object.prototype));
|
|
57
|
+
function isShadowedKey(key) {
|
|
58
|
+
return SHADOWED_KEYS.has(key);
|
|
59
|
+
}
|
|
60
|
+
function safeOwnRead(target, key) {
|
|
61
|
+
if (isShadowedKey(key)) {
|
|
62
|
+
const desc = Object.getOwnPropertyDescriptor(target, key);
|
|
63
|
+
if (desc === void 0) return void 0;
|
|
64
|
+
return "value" in desc ? desc.value : readConsumerProp(target, key);
|
|
65
|
+
}
|
|
66
|
+
return readConsumerProp(target, key);
|
|
67
|
+
}
|
|
68
|
+
function safeOwnHas(target, key) {
|
|
69
|
+
try {
|
|
70
|
+
return Object.prototype.hasOwnProperty.call(target, key);
|
|
71
|
+
} catch {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function spreadConsumerRecord(src) {
|
|
76
|
+
try {
|
|
77
|
+
return { ...src };
|
|
78
|
+
} catch {
|
|
79
|
+
const out = {};
|
|
80
|
+
for (const key of Object.keys(src)) {
|
|
81
|
+
safeAssign(out, key, readConsumerProp(src, key));
|
|
82
|
+
}
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function copyConsumerArray(src) {
|
|
87
|
+
try {
|
|
88
|
+
return src.slice();
|
|
89
|
+
} catch {
|
|
90
|
+
const out = new Array(src.length);
|
|
91
|
+
for (let i = 0; i < src.length; i++) out[i] = readConsumerIndex(src, i);
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export { safeOwnRead as a, readConsumerProp as b, consumerKeys as c, callConsumerFn as d, safeOwnHas as e, consumerHas as f, spreadConsumerRecord as g, copyConsumerArray as h, isShadowedKey as i, consumerSymbolKeys as j, readConsumerIndex as r, safeAssign as s };
|
|
@@ -215,6 +215,25 @@ type OriginalsRecord = {
|
|
|
215
215
|
readonly segments: Path;
|
|
216
216
|
readonly value: unknown;
|
|
217
217
|
};
|
|
218
|
+
/** Every tracked array's identity tokens and baseline order, by array key. */
|
|
219
|
+
type IdentityOrders = {
|
|
220
|
+
readonly tokens: ReadonlyMap<PathKey, readonly string[]>;
|
|
221
|
+
readonly baselines: ReadonlyMap<PathKey, readonly string[]>;
|
|
222
|
+
};
|
|
223
|
+
/**
|
|
224
|
+
* The per-element bookkeeping a history position puts back with its value.
|
|
225
|
+
* A typed array op moves each element's baseline with its identity and drops
|
|
226
|
+
* a removed element's, as it does the element's blank membership, so a value
|
|
227
|
+
* alone, restored by position, would compare each row against the baseline of
|
|
228
|
+
* whichever row sits there now. With them come the identity orders and the
|
|
229
|
+
* removed-baseline set those baselines are read against. Opaque to the history module, which keeps it and hands it back.
|
|
230
|
+
*/
|
|
231
|
+
type StructureSnapshot = {
|
|
232
|
+
readonly identity: IdentityOrders;
|
|
233
|
+
readonly originals: ReadonlyArray<readonly [PathKey, OriginalsRecord]>;
|
|
234
|
+
readonly originalBlank: ReadonlyArray<PathKey>;
|
|
235
|
+
readonly removed: ReadonlyArray<readonly [PathKey, Path]>;
|
|
236
|
+
};
|
|
218
237
|
|
|
219
238
|
/** Internal brand for the `Unset` type. Never exposed at runtime. */
|
|
220
239
|
declare const _unsetBrand: unique symbol;
|
|
@@ -888,8 +907,6 @@ type SchemaParseErrorWithData<TData> = {
|
|
|
888
907
|
};
|
|
889
908
|
/** Settled schema-level verdict. Discriminate on `success`. */
|
|
890
909
|
type SchemaParseResult<TData> = SchemaParseSuccess<TData> | SchemaParseErrorWithData<TData> | SchemaParseErrorWithoutData;
|
|
891
|
-
/** Schema-level `getDefaultValues` verdict: defaults always come back. */
|
|
892
|
-
type SchemaDefaultsResult<TData> = SchemaParseSuccess<TData> | SchemaParseErrorWithData<TData>;
|
|
893
910
|
/** Settled validation result when the form or subtree parsed successfully. */
|
|
894
911
|
type ValidationResponseSuccess<TData> = SchemaParseSuccess<TData> & {
|
|
895
912
|
/** The form this verdict belongs to. Stamped by the store, not the schema. */
|
|
@@ -977,7 +994,31 @@ type GetDefaultValuesConfig<Form> = {
|
|
|
977
994
|
* library.
|
|
978
995
|
*/
|
|
979
996
|
type AbstractSchema<Form, GetValueFormType> = {
|
|
980
|
-
|
|
997
|
+
/**
|
|
998
|
+
* The form's starting value: the schema's defaults, with
|
|
999
|
+
* `config.constraints` merged over them and any shape the merge broke
|
|
1000
|
+
* repaired. Derivation only. Nothing is validated here, so no
|
|
1001
|
+
* refinement, check or transform runs; `validateSync` is the verdict.
|
|
1002
|
+
*/
|
|
1003
|
+
getDefaultValues(config: GetDefaultValuesConfig<Form>): Form;
|
|
1004
|
+
/**
|
|
1005
|
+
* The schema's synchronous verdict on `data` as a whole form, as a
|
|
1006
|
+
* list of failures: empty when the data passes.
|
|
1007
|
+
*
|
|
1008
|
+
* The runtime seeds the schema error channel with it whenever it
|
|
1009
|
+
* establishes a baseline: on the starting value, the first time
|
|
1010
|
+
* anything reads or writes the form's errors, and on `reset()`. A form
|
|
1011
|
+
* starting from invalid defaults therefore reads invalid from its
|
|
1012
|
+
* first render.
|
|
1013
|
+
* A hydrating client never calls it, since the server's verdict
|
|
1014
|
+
* arrives with the payload.
|
|
1015
|
+
*
|
|
1016
|
+
* Adapters MUST NOT throw: a refinement that throws, or a schema whose
|
|
1017
|
+
* verdict resolves only through a Promise, returns `[]` and leaves the
|
|
1018
|
+
* verdict to the async pass that `needsAsyncValidation` queues. An
|
|
1019
|
+
* adapter with no synchronous parse returns `[]` unconditionally.
|
|
1020
|
+
*/
|
|
1021
|
+
validateSync(data: unknown): ValidationError[];
|
|
981
1022
|
/**
|
|
982
1023
|
* The schema-prescribed default at `path`. The runtime uses it to
|
|
983
1024
|
* fill structural gaps, so every `setValue` write leaves the form
|
|
@@ -1325,8 +1366,8 @@ type AbstractSchema<Form, GetValueFormType> = {
|
|
|
1325
1366
|
/**
|
|
1326
1367
|
* Whether `validateAtPath` MAY have to run asynchronously to surface
|
|
1327
1368
|
* every error this schema can produce. The runtime asks at
|
|
1328
|
-
* construction: `false` means the
|
|
1329
|
-
* authoritative and no extra microtask is spent, `true` queues a
|
|
1369
|
+
* construction: `false` means the synchronous verdict on the starting
|
|
1370
|
+
* value is authoritative and no extra microtask is spent, `true` queues a
|
|
1330
1371
|
* one-shot full-form async pass so async-only verdicts (refinements,
|
|
1331
1372
|
* transforms or pipes that resolve only through a Promise) surface
|
|
1332
1373
|
* without waiting for a user mutation.
|
|
@@ -1338,7 +1379,10 @@ type AbstractSchema<Form, GetValueFormType> = {
|
|
|
1338
1379
|
* For a per-path query, compose with `getSchemasAtPath(path)`: each
|
|
1339
1380
|
* candidate sub-schema exposes its own `needsAsyncValidation`, so
|
|
1340
1381
|
* "does the cargo subtree contain async work?" is the union of the
|
|
1341
|
-
* per-candidate answers, with no separate top-level overload.
|
|
1382
|
+
* per-candidate answers, with no separate top-level overload. A root
|
|
1383
|
+
* that answers `false` answers for every path, and the runtime then
|
|
1384
|
+
* asks no sub-schema, so never answer `false` at the root of a tree
|
|
1385
|
+
* where a sub-schema would answer `true`.
|
|
1342
1386
|
*/
|
|
1343
1387
|
needsAsyncValidation?(): boolean;
|
|
1344
1388
|
/**
|
|
@@ -1378,6 +1422,20 @@ type AbstractSchema<Form, GetValueFormType> = {
|
|
|
1378
1422
|
* that disables variant reshape and stub correction for the form.
|
|
1379
1423
|
*/
|
|
1380
1424
|
hasDiscriminatedUnions?(): boolean;
|
|
1425
|
+
/**
|
|
1426
|
+
* Whether `isPreprocessOrCoerceLeaf` can answer `true` at any path:
|
|
1427
|
+
* the schema holds a preprocess-style normalizer or a coerce
|
|
1428
|
+
* primitive somewhere. The store reads it once at construction.
|
|
1429
|
+
* `false` lets it skip recording which paths the consumer authored,
|
|
1430
|
+
* a set that is only read at such leaves.
|
|
1431
|
+
*
|
|
1432
|
+
* Optional, and an adapter that omits it is treated as holding one,
|
|
1433
|
+
* which keeps that bookkeeping on. Never return `false` for a schema
|
|
1434
|
+
* where `isPreprocessOrCoerceLeaf` answers `true` anywhere: verdicts
|
|
1435
|
+
* at a path the consumer authored with `undefined` would then stay
|
|
1436
|
+
* hidden.
|
|
1437
|
+
*/
|
|
1438
|
+
hasPreprocessOrCoerce?(): boolean;
|
|
1381
1439
|
};
|
|
1382
1440
|
/**
|
|
1383
1441
|
* A discriminated union as the adapter reports it: the discriminator
|
|
@@ -1583,10 +1641,13 @@ type WriteMeta = {
|
|
|
1583
1641
|
type HistoryKernel = {
|
|
1584
1642
|
readonly form: Ref<unknown>;
|
|
1585
1643
|
readonly blankPaths: Set<PathKey>;
|
|
1586
|
-
readonly errorCells: Map<PathKey, ErrorCell>;
|
|
1644
|
+
readonly errorCells: () => Map<PathKey, ErrorCell>;
|
|
1587
1645
|
onFormChange(listener: (next: unknown, meta?: WriteMeta) => void): () => void;
|
|
1646
|
+
onReset(listener: () => void): () => void;
|
|
1588
1647
|
applyFormReplacement(next: unknown): void;
|
|
1589
1648
|
restoreErrorCells(entries: ReadonlyArray<readonly [PathKey, ErrorCell]>): void;
|
|
1649
|
+
captureStructure(): StructureSnapshot;
|
|
1650
|
+
restoreStructure(snapshot: StructureSnapshot): void;
|
|
1590
1651
|
};
|
|
1591
1652
|
/**
|
|
1592
1653
|
* The live undo/redo runtime a {@link HistoryPlugin} attaches to one
|
|
@@ -2033,7 +2094,13 @@ type HandleSubmit<Form extends GenericForm> = (onSubmit: OnSubmit<Form>, onError
|
|
|
2033
2094
|
* fields appear in friendlier shape on `FieldState`.
|
|
2034
2095
|
*/
|
|
2035
2096
|
type MetaTrackerValue = {
|
|
2036
|
-
/**
|
|
2097
|
+
/**
|
|
2098
|
+
* ISO timestamp of the most recent write at this path or under it,
|
|
2099
|
+
* counting the form's creation. A removal is a write too, so the stamp
|
|
2100
|
+
* never moves backwards, and every write reads later than the one before
|
|
2101
|
+
* it, whatever the device's clock says. `null` only for a path never
|
|
2102
|
+
* written or no longer present.
|
|
2103
|
+
*/
|
|
2037
2104
|
updatedAt: string | null;
|
|
2038
2105
|
/** Value as it arrived, before any transforms. Distinguishes a parse-coerced read from raw user input. */
|
|
2039
2106
|
rawValue: unknown;
|
|
@@ -2184,6 +2251,32 @@ type AttaformDomBinding = {
|
|
|
2184
2251
|
path: Path;
|
|
2185
2252
|
element: HTMLElement;
|
|
2186
2253
|
} | null;
|
|
2254
|
+
readonly hostChannel: HostChannel;
|
|
2255
|
+
};
|
|
2256
|
+
/**
|
|
2257
|
+
* The write policy for a `v-register` component host, held on the DOM
|
|
2258
|
+
* binding so it stays in the directive cluster's lazy graph. Applies the
|
|
2259
|
+
* binding site's modifiers, runs register `transforms` and schema
|
|
2260
|
+
* coercion, and buffers `.lazy` writes while focus is inside the host.
|
|
2261
|
+
*
|
|
2262
|
+
* - `write` commits a value the host emitted through
|
|
2263
|
+
* `update:modelValue`.
|
|
2264
|
+
* - `writeInput` takes an `input` emit and commits it only when the
|
|
2265
|
+
* payload carries the live value as an own `value` property.
|
|
2266
|
+
* - `markEditing` records focus entering or leaving the host. Leaving
|
|
2267
|
+
* commits a buffered `.lazy` value, or the trimmed form under `.trim`.
|
|
2268
|
+
* - `holdsDraft` reports a buffered `.lazy` value that storage has not
|
|
2269
|
+
* moved past, the edit a re-render must leave on screen.
|
|
2270
|
+
* - `release` drops any buffered value when the host unmounts.
|
|
2271
|
+
*
|
|
2272
|
+
* @internal
|
|
2273
|
+
*/
|
|
2274
|
+
type HostChannel = {
|
|
2275
|
+
readonly write: (rv: RegisterValue, value: unknown, modifiers: HostModifiers) => boolean;
|
|
2276
|
+
readonly writeInput: (rv: RegisterValue, payload: unknown, modifiers: HostModifiers) => boolean;
|
|
2277
|
+
readonly markEditing: (rv: RegisterValue, editing: boolean, modifiers: HostModifiers) => void;
|
|
2278
|
+
readonly holdsDraft: (rv: RegisterValue) => boolean;
|
|
2279
|
+
readonly release: (rv: RegisterValue) => void;
|
|
2187
2280
|
};
|
|
2188
2281
|
/**
|
|
2189
2282
|
* Factory the directive and `useRegister` inject through
|
|
@@ -2244,16 +2337,39 @@ type RegisterValue<Value = unknown> = Readonly<{
|
|
|
2244
2337
|
setValueWithInternalPath: (value: unknown, meta?: WriteMeta) => boolean;
|
|
2245
2338
|
/**
|
|
2246
2339
|
* Commit a value emitted by a third-party component bound through
|
|
2247
|
-
* `v-register`'s compile-time v-model desugar
|
|
2248
|
-
*
|
|
2249
|
-
* the
|
|
2250
|
-
*
|
|
2251
|
-
*
|
|
2252
|
-
*
|
|
2340
|
+
* `v-register`'s compile-time v-model desugar, and mark the field
|
|
2341
|
+
* interacted, since a v-model host has no DOM input listener to flip
|
|
2342
|
+
* the sticky `interacted` bit. The write takes the same path a native
|
|
2343
|
+
* input's does: the binding site's `.number` / `.trim` / `.lazy`
|
|
2344
|
+
* modifiers, then register `transforms`, then schema coercion. The
|
|
2345
|
+
* injected `onUpdate:modelValue` handler is the caller, passing the
|
|
2346
|
+
* modifiers as a static literal. `true` when the write was accepted
|
|
2347
|
+
* or buffered.
|
|
2348
|
+
*
|
|
2349
|
+
* @internal
|
|
2350
|
+
*/
|
|
2351
|
+
setValueFromHost: (value: unknown, modifiers: HostModifiers) => boolean;
|
|
2352
|
+
/**
|
|
2353
|
+
* Commit the live value from a component host's `input` emit. A
|
|
2354
|
+
* payload that is a non-Event object owning a `value` property (the
|
|
2355
|
+
* shape PrimeVue's InputNumber reports per keystroke) writes that
|
|
2356
|
+
* value through `setValueFromHost`; anything else, a native `Event`
|
|
2357
|
+
* reaching a fallthrough listener included, is ignored and returns
|
|
2358
|
+
* `false`. The injected `onInput` handler is the only caller.
|
|
2359
|
+
*
|
|
2360
|
+
* @internal
|
|
2361
|
+
*/
|
|
2362
|
+
setValueFromHostInput: (payload: unknown, modifiers: HostModifiers) => boolean;
|
|
2363
|
+
/**
|
|
2364
|
+
* The final step of a component-host write, after modifiers,
|
|
2365
|
+
* transforms and coercion: an empty signal (`''`, `null` or
|
|
2366
|
+
* `undefined`) the field's schema does not admit marks the field
|
|
2367
|
+
* blank, and anything else writes through. Called by the host write
|
|
2368
|
+
* channel.
|
|
2253
2369
|
*
|
|
2254
2370
|
* @internal
|
|
2255
2371
|
*/
|
|
2256
|
-
|
|
2372
|
+
commitFromHost: (value: unknown) => boolean;
|
|
2257
2373
|
/**
|
|
2258
2374
|
* Mark this field DOM-connected during SSR, so a server-rendered
|
|
2259
2375
|
* template reading `form.fields.<path>.connected` does not flicker on
|
|
@@ -2312,11 +2428,12 @@ type RegisterValue<Value = unknown> = Readonly<{
|
|
|
2312
2428
|
* every later registration.
|
|
2313
2429
|
*
|
|
2314
2430
|
* Optional, so a hand-rolled RegisterValue owning its own element
|
|
2315
|
-
* handling need not declare it.
|
|
2431
|
+
* handling need not declare it. Returns the armed binding, which is how
|
|
2432
|
+
* the directive reaches the host write channel.
|
|
2316
2433
|
*
|
|
2317
2434
|
* @internal
|
|
2318
2435
|
*/
|
|
2319
|
-
ensureDomBinding?: (factory: DomBindingFactory) =>
|
|
2436
|
+
ensureDomBinding?: (factory: DomBindingFactory) => AttaformDomBinding;
|
|
2320
2437
|
/**
|
|
2321
2438
|
* Canonical JSON-encoded path key for this binding, such as
|
|
2322
2439
|
* `'["items",0,"name"]'`. Useful for stable Map and Set keys, log
|
|
@@ -2576,9 +2693,10 @@ type CustomRegisterDirective<T, Modifiers extends string = string> = ObjectDirec
|
|
|
2576
2693
|
/**
|
|
2577
2694
|
* Snapshot of the last `value.innerRef.value` reference the
|
|
2578
2695
|
* directive's DOM-sync (setSelected / setChecked / radio
|
|
2579
|
-
* `el.checked = …`) was applied for. Used by
|
|
2580
|
-
* directive's `updated` / `beforeUpdate` to skip the
|
|
2581
|
-
* DOM sync when the model is identity-unchanged
|
|
2696
|
+
* `el.checked = …` / text `el.value = …`) was applied for. Used by
|
|
2697
|
+
* every input directive's `updated` / `beforeUpdate` to skip the
|
|
2698
|
+
* per-render DOM sync when the model is identity-unchanged (for
|
|
2699
|
+
* text, a focused `.lazy` edit is held through it), so a parent
|
|
2582
2700
|
* re-render (a typed character in a sibling, an async-validation
|
|
2583
2701
|
* tick, any reactive read) cannot clobber an in-progress user
|
|
2584
2702
|
* interaction. Identity comparison is sound because every form
|
|
@@ -2604,16 +2722,18 @@ type CustomRegisterDirective<T, Modifiers extends string = string> = ObjectDirec
|
|
|
2604
2722
|
}, RegisterValue | undefined, Modifiers, string>;
|
|
2605
2723
|
/**
|
|
2606
2724
|
* Modifier names supported by `v-register` on `<input type="text">`,
|
|
2607
|
-
* `<input type="number">`,
|
|
2608
|
-
* `v-model` modifier semantics on the same elements; combine
|
|
2609
|
-
* (`<input v-register.lazy.trim.number="..." />`).
|
|
2725
|
+
* `<input type="number">`, `<textarea>`, and component hosts. Mirrors
|
|
2726
|
+
* Vue's `v-model` modifier semantics on the same elements; combine
|
|
2727
|
+
* freely (`<input v-register.lazy.trim.number="..." />`).
|
|
2610
2728
|
*/
|
|
2611
2729
|
type RegisterTextModifier =
|
|
2612
2730
|
/**
|
|
2613
2731
|
* Write on `change` (blur) instead of `input`. The reactive
|
|
2614
2732
|
* model only updates after the user tabs/clicks out of the
|
|
2615
2733
|
* field. IME composition handlers are skipped under `.lazy`, since
|
|
2616
|
-
* composition events do not gate writes.
|
|
2734
|
+
* composition events do not gate writes. On a component host the
|
|
2735
|
+
* last value emitted while focus is inside the host commits when
|
|
2736
|
+
* focus leaves it.
|
|
2617
2737
|
*/
|
|
2618
2738
|
'lazy'
|
|
2619
2739
|
/**
|
|
@@ -2621,18 +2741,30 @@ type RegisterTextModifier =
|
|
|
2621
2741
|
* the user's raw input (whitespace included) while they're
|
|
2622
2742
|
* typing; on `change` (blur / commit) the value is trimmed
|
|
2623
2743
|
* once and written back to both the model and the visible DOM.
|
|
2624
|
-
* Combine with `.lazy` to skip the mid-typing writes entirely.
|
|
2744
|
+
* Combine with `.lazy` to skip the mid-typing writes entirely. On a
|
|
2745
|
+
* component host the trimmed value commits when focus leaves the
|
|
2746
|
+
* host.
|
|
2625
2747
|
*/
|
|
2626
2748
|
| 'trim'
|
|
2627
2749
|
/**
|
|
2628
|
-
* Cast the value with `parseFloat` before writing.
|
|
2629
|
-
* does not parse as a number (`'abc'`)
|
|
2630
|
-
*
|
|
2631
|
-
*
|
|
2632
|
-
* `<input type="number">`, where an
|
|
2633
|
-
* redundant.
|
|
2750
|
+
* Cast the value with `parseFloat` before writing. An empty field,
|
|
2751
|
+
* or text that does not parse as a number (`'abc'`), marks the field
|
|
2752
|
+
* blank instead of writing a string. On a component host the cast
|
|
2753
|
+
* applies to string emits, and a value the component already typed
|
|
2754
|
+
* passes through. Auto-applied for `<input type="number">`, where an
|
|
2755
|
+
* explicit `.number` is redundant.
|
|
2634
2756
|
*/
|
|
2635
2757
|
| 'number';
|
|
2758
|
+
/**
|
|
2759
|
+
* The `v-register` modifiers a component host honours, carried from the
|
|
2760
|
+
* binding site to the host write channel as a static literal that the
|
|
2761
|
+
* compile-time bridge transform emits. Shaped like Vue's directive
|
|
2762
|
+
* modifiers, so the directive passes a binding's modifiers to the channel
|
|
2763
|
+
* unchanged.
|
|
2764
|
+
*
|
|
2765
|
+
* @internal
|
|
2766
|
+
*/
|
|
2767
|
+
type HostModifiers = Readonly<Partial<Record<RegisterTextModifier, boolean>>>;
|
|
2636
2768
|
/**
|
|
2637
2769
|
* v-register directive variant for `<input type="text">`,
|
|
2638
2770
|
* `<input type="number">` and `<textarea>`. Supports the `.lazy`,
|
|
@@ -2855,6 +2987,13 @@ type FieldState<Value = unknown> = {
|
|
|
2855
2987
|
readonly dirty: boolean;
|
|
2856
2988
|
readonly focused: boolean | null;
|
|
2857
2989
|
readonly blurred: boolean | null;
|
|
2990
|
+
/**
|
|
2991
|
+
* `true` once this field has been blurred, with or without an edit.
|
|
2992
|
+
* Sticky thereafter, including through a value round trip; cleared by
|
|
2993
|
+
* `form.reset()` / `form.resetField(path)`. Containers roll it up as
|
|
2994
|
+
* a disjunction, and keep it after the descendant that set it is
|
|
2995
|
+
* removed.
|
|
2996
|
+
*/
|
|
2858
2997
|
readonly touched: boolean;
|
|
2859
2998
|
/**
|
|
2860
2999
|
* `true` once the user has issued at least one value edit on this
|
|
@@ -2866,7 +3005,8 @@ type FieldState<Value = unknown> = {
|
|
|
2866
3005
|
* flips `touched` but never `interacted`. Set only by user input,
|
|
2867
3006
|
* never by hydration or programmatic `setValue`; cleared by
|
|
2868
3007
|
* `form.reset()` / `form.resetField(path)`. Containers roll it up as
|
|
2869
|
-
* a disjunction (any descendant interacted)
|
|
3008
|
+
* a disjunction (any descendant interacted), and keep it after the
|
|
3009
|
+
* descendant that set it is removed.
|
|
2870
3010
|
*/
|
|
2871
3011
|
readonly interacted: boolean;
|
|
2872
3012
|
/**
|
|
@@ -2879,7 +3019,8 @@ type FieldState<Value = unknown> = {
|
|
|
2879
3019
|
* visible through a re-focus to be fixed live. Set only by user
|
|
2880
3020
|
* input/blur, never by hydration or programmatic writes; cleared by
|
|
2881
3021
|
* `form.reset()` / `form.resetField(path)`. Containers roll it up as a
|
|
2882
|
-
* disjunction
|
|
3022
|
+
* disjunction, and keep it after the descendant that set it is
|
|
3023
|
+
* removed.
|
|
2883
3024
|
*/
|
|
2884
3025
|
readonly blurredAfterInteraction: boolean;
|
|
2885
3026
|
readonly connected: boolean;
|
|
@@ -2915,6 +3056,18 @@ type FieldState<Value = unknown> = {
|
|
|
2915
3056
|
* `elements[0] ?? null`.
|
|
2916
3057
|
*/
|
|
2917
3058
|
readonly elements: readonly HTMLElement[];
|
|
3059
|
+
/**
|
|
3060
|
+
* ISO timestamp of the most recent write at this path or anywhere
|
|
3061
|
+
* under it, counting the form's creation. A removal is a write too, so
|
|
3062
|
+
* a container's stamp moves forward when a row leaves and never moves
|
|
3063
|
+
* backwards. A survivor keeps its own stamp when a removal or a reorder
|
|
3064
|
+
* moves it to a new index, and a write that changes nothing stamps
|
|
3065
|
+
* nothing. Every write that changes a value reads later than the one
|
|
3066
|
+
* before it: two writes in one millisecond, or a write on a device whose
|
|
3067
|
+
* clock runs behind the server that rendered the page, take one
|
|
3068
|
+
* millisecond past the latest stamp the form holds. `null` only for a
|
|
3069
|
+
* path never written or no longer present.
|
|
3070
|
+
*/
|
|
2918
3071
|
readonly updatedAt: string | null;
|
|
2919
3072
|
/**
|
|
2920
3073
|
* Every `ValidationError` in this path's SUBTREE: the node's own
|
|
@@ -4252,7 +4405,9 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4252
4405
|
* - the form value back to defaults;
|
|
4253
4406
|
* - the dirty baseline (so the next edit flips `dirty` correctly);
|
|
4254
4407
|
* - field errors;
|
|
4255
|
-
* - touched /
|
|
4408
|
+
* - the interaction history (`touched` / `interacted` /
|
|
4409
|
+
* `blurredAfterInteraction`) at every path, containers included;
|
|
4410
|
+
* `focused`, `blurred` and `connected` follow the DOM and stay;
|
|
4256
4411
|
* - submission state (`submitting` / `submissionAttempts` /
|
|
4257
4412
|
* `submitted` / `submitError`).
|
|
4258
4413
|
*
|
|
@@ -4279,8 +4434,10 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4279
4434
|
reset: (nextDefaultValues?: DefaultValuesInput<Form>) => void;
|
|
4280
4435
|
/**
|
|
4281
4436
|
* Restore a single field (or a sub-tree like `'user'`) to its
|
|
4282
|
-
* initial value. Clears errors and
|
|
4283
|
-
*
|
|
4437
|
+
* initial value. Clears errors and the interaction history
|
|
4438
|
+
* (`touched` / `interacted` / `blurredAfterInteraction`) for the
|
|
4439
|
+
* field and its descendants; leaves siblings, ancestors and
|
|
4440
|
+
* submission state alone.
|
|
4284
4441
|
*
|
|
4285
4442
|
* No-op when the path doesn't exist on the form (e.g. a typo'd
|
|
4286
4443
|
* dynamic key).
|
|
@@ -4549,5 +4706,5 @@ type UseFormReturnType<Form extends GenericForm, GetValueFormType extends Generi
|
|
|
4549
4706
|
blankPaths: ComputedRef<BlankPathsView>;
|
|
4550
4707
|
};
|
|
4551
4708
|
|
|
4552
|
-
export { ROOT_PATH as R, canonicalizePath as
|
|
4553
|
-
export type {
|
|
4709
|
+
export { ROOT_PATH as R, canonicalizePath as ai, isPathPrefix as aj, isUnset as ak, parseDottedPath as al, unset as am, ROOT_PATH_KEY as z };
|
|
4710
|
+
export type { SchemaParseErrorWithData as $, AbstractSchema as A, ReactiveValidationStatus as B, CustomDirectiveRegisterAssignerFn as C, DefaultValuesInput as D, ErrorInput as E, FormKey as F, GenericForm as G, HandleSubmit as H, IsTuple as I, JoinSegments as J, KeyofUnion as K, LiftedValueShape as L, MetaTrackerValue as M, NestedReadType as N, OnError as O, ParseOptions as P, RecordPath as Q, RecordValue as S, RegisterDirective as T, UseFormConfiguration as U, RegisterFlatPath as V, RegisterOptions as W, RegisterSelectModifier as X, RegisterTextModifier as Y, RegisterTransform as Z, RegisterValue as _, UseFormReturnType as a, SchemaParseErrorWithoutData as a0, SchemaParseResult as a1, SchemaParseSuccess as a2, Segment as a3, SetValueCallback as a4, SetValuePayload as a5, SettledValidationStatus as a6, SlimPrimitiveKind as a7, SubmitHandler as a8, Unset as a9, ValidateOn as aa, ValidateOnConfig as ab, ValidationError as ac, ValidationResponse as ad, ValidationResponseWithoutValue as ae, ValueOfUnion as af, WriteMeta as ag, WriteShape as ah, RegisterModelDynamicCustomDirective as an, SchemaFactoryOptions as ao, AcceptableDefaults as ap, DisplayCtx as aq, GetDisplayState as ar, DisplayMachine as as, FieldRecord as at, ErrorCell as au, OriginalsRecord as av, StructureSnapshot as aw, AttaformDomBinding as ax, TransformAbortHolder as ay, ArrayItem as b, ArrayPath as c, DeepPartial as d, DefaultValuesShape as e, DisplayState as f, ErrorsProxyShape as g, FieldMetaPayload as h, FieldState as i, FieldStateMap as j, FieldStateMapEntry as k, FlatPath as l, FormErrorRecord as m, FormErrorsSurface as n, FormMeta as o, HistoryPlugin as p, IsUnion as q, Json as r, NestedType as s, OnSubmit as t, PartialFlatPath as u, Path as v, PathKey as w, PendingValidationStatus as x, Primitive as y };
|