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.
Files changed (55) hide show
  1. package/dist/abstract.d.mts +5 -5
  2. package/dist/abstract.mjs +4 -4
  3. package/dist/dev/abstract.mjs +4 -4
  4. package/dist/dev/chunks/devtools.mjs +3 -3
  5. package/dist/dev/directive.mjs +1 -1
  6. package/dist/dev/history.mjs +15 -2
  7. package/dist/dev/index.mjs +5 -5
  8. package/dist/dev/runtime/plugins/attaform.mjs +1 -1
  9. package/dist/dev/shared/{attaform-dev.zlvDr0WB.mjs → attaform-dev.04aupFBW.mjs} +3 -2
  10. package/dist/dev/shared/{attaform-dev.DxHdkkPG.mjs → attaform-dev.3uTCYwy8.mjs} +770 -254
  11. package/dist/dev/shared/{attaform-dev.BJK1kqHY.mjs → attaform-dev.BpVGFSFa.mjs} +88 -115
  12. package/dist/dev/shared/{attaform-dev.Chm4D6SJ.mjs → attaform-dev.Bu6wgrA5.mjs} +3 -3
  13. package/dist/dev/shared/{attaform-dev.BMQ3GcgD.mjs → attaform-dev.Cbx0AiQF.mjs} +476 -337
  14. package/dist/dev/shared/attaform-dev.CwYTWyPX.mjs +120 -0
  15. package/dist/dev/shared/{attaform-dev.DuEE4GU1.mjs → attaform-dev.D7lKyM_7.mjs} +4 -4
  16. package/dist/dev/shared/{attaform-dev.CT7MDjPy.mjs → attaform-dev.OceE0X3v.mjs} +154 -229
  17. package/dist/{shared/attaform.DRsANMok.mjs → dev/shared/attaform-dev.PTGM9KE1.mjs} +16 -15
  18. package/dist/{shared/attaform.8mfKZCwH.mjs → dev/shared/attaform-dev.n6n00owJ.mjs} +49 -128
  19. package/dist/dev/zod-v3.mjs +6 -6
  20. package/dist/dev/zod-v4.mjs +6 -6
  21. package/dist/dev/zod.mjs +5 -5
  22. package/dist/directive.d.mts +2 -2
  23. package/dist/directive.mjs +1 -1
  24. package/dist/history.d.mts +1 -1
  25. package/dist/history.mjs +15 -2
  26. package/dist/index.d.mts +16 -55
  27. package/dist/index.mjs +5 -5
  28. package/dist/runtime/components/AttaformDevtoolsPanel.vue +3 -3
  29. package/dist/runtime/plugins/attaform.mjs +1 -1
  30. package/dist/shared/{attaform.CO918TdU.mjs → attaform.B5b-HmhH.mjs} +88 -115
  31. package/dist/shared/{attaform.2FslhB9R.d.mts → attaform.B9PYKlhB.d.mts} +43 -19
  32. package/dist/shared/{attaform.D_f1WgYf.mjs → attaform.BPMOl562.mjs} +458 -319
  33. package/dist/{dev/shared/attaform-dev.CZz4GYZ6.mjs → shared/attaform.BPSqtU7a.mjs} +44 -156
  34. package/dist/shared/{attaform.CdZIEf7_.mjs → attaform.BhtAZysa.mjs} +3 -2
  35. package/dist/shared/{attaform.BcQwgWaq.d.mts → attaform.CYlF4P6X.d.mts} +58 -17
  36. package/dist/shared/{attaform.WiGdIqgx.mjs → attaform.CdA9bfRv.mjs} +3 -3
  37. package/dist/shared/{attaform.BIWicztt.mjs → attaform.DAf4ehIe.mjs} +765 -251
  38. package/dist/shared/{attaform.ZYn2ahzJ.mjs → attaform.DBCbxlyk.mjs} +59 -1
  39. package/dist/shared/{attaform.L0kUn3vL.d.mts → attaform.DZOynI6c.d.mts} +1 -1
  40. package/dist/shared/{attaform.B2iebkPA.mjs → attaform.KEfNRDot.mjs} +4 -4
  41. package/dist/shared/attaform._1Zp3mDG.mjs +96 -0
  42. package/dist/shared/{attaform.Br8EBn5B.d.mts → attaform.i13OEHJF.d.mts} +195 -38
  43. package/dist/{dev/shared/attaform-dev.BUIFcTYf.mjs → shared/attaform.j9xI_ObC.mjs} +16 -15
  44. package/dist/shared/{attaform.D_pt1gOj.mjs → attaform.u6jfHoed.mjs} +154 -229
  45. package/dist/transforms.mjs +1 -1
  46. package/dist/vite.mjs +1 -1
  47. package/dist/zod-v3.d.mts +4 -4
  48. package/dist/zod-v3.mjs +6 -6
  49. package/dist/zod-v4.d.mts +22 -16
  50. package/dist/zod-v4.mjs +6 -6
  51. package/dist/zod.d.mts +4 -4
  52. package/dist/zod.mjs +5 -5
  53. package/package.json +2 -1
  54. package/skills/attaform/SKILL.md +2 -1
  55. package/skills/attaform/references/custom-components.md +4 -0
@@ -1,8 +1,374 @@
1
- import { reactive, markRaw, isRef, effectScope, watch, warn, nextTick } from 'vue';
2
- import { e as canonicalizePath } from './attaform-dev.zlvDr0WB.mjs';
1
+ import { isRef, warn, toRaw, reactive, markRaw, effectScope, watch, nextTick } from 'vue';
2
+ import { e as canonicalizePath } from './attaform-dev.04aupFBW.mjs';
3
+ import { e as safeOwnHas } from './attaform-dev.CwYTWyPX.mjs';
4
+
5
+ function activeElementOf(node) {
6
+ const rootNode = node.getRootNode();
7
+ return rootNode instanceof Document || rootNode instanceof ShadowRoot ? rootNode.activeElement : null;
8
+ }
3
9
 
4
10
  const INTERACTIVE_TAG_NAMES = /* @__PURE__ */ new Set(["INPUT", "SELECT", "TEXTAREA"]);
5
11
 
12
+ const isArray = Array.isArray;
13
+ function isFunction(value) {
14
+ return typeof value === "function";
15
+ }
16
+ function toTypeString(value) {
17
+ return Object.prototype.toString.call(value);
18
+ }
19
+ function isSet(value) {
20
+ return toTypeString(value) === "[object Set]";
21
+ }
22
+ function isDate(value) {
23
+ return toTypeString(value) === "[object Date]";
24
+ }
25
+ function isSymbol(value) {
26
+ return typeof value === "symbol";
27
+ }
28
+ function isObject(value) {
29
+ return value !== null && typeof value === "object";
30
+ }
31
+ function looseToNumber(val) {
32
+ const n = parseFloat(val);
33
+ return isNaN(n) ? val : n;
34
+ }
35
+ function looseCompareArrays(a, b) {
36
+ if (a.length !== b.length) return false;
37
+ let equal = true;
38
+ for (let i = 0; equal && i < a.length; i++) {
39
+ equal = looseEqual(a[i], b[i]);
40
+ }
41
+ return equal;
42
+ }
43
+ function looseEqual(a, b) {
44
+ if (a === b) return true;
45
+ const aValidType = isDate(a);
46
+ const bValidType = isDate(b);
47
+ if (aValidType || bValidType) {
48
+ return aValidType && bValidType ? a.getTime() === b.getTime() : false;
49
+ }
50
+ const aSymbol = isSymbol(a);
51
+ const bSymbol = isSymbol(b);
52
+ if (aSymbol || bSymbol) return a === b;
53
+ const aIsArray = isArray(a);
54
+ const bIsArray = isArray(b);
55
+ if (aIsArray || bIsArray) {
56
+ return aIsArray && bIsArray ? looseCompareArrays(a, b) : false;
57
+ }
58
+ const aIsObject = isObject(a);
59
+ const bIsObject = isObject(b);
60
+ if (aIsObject !== bIsObject) return false;
61
+ if (aIsObject && bIsObject) {
62
+ const keysA = Object.keys(a);
63
+ if (keysA.length !== Object.keys(b).length) return false;
64
+ for (const key of keysA) {
65
+ const hasA = Object.prototype.hasOwnProperty.call(a, key);
66
+ const hasB = Object.prototype.hasOwnProperty.call(b, key);
67
+ if (!hasA || !hasB || !looseEqual(a[key], b[key])) return false;
68
+ }
69
+ return true;
70
+ }
71
+ return String(a) === String(b);
72
+ }
73
+ function looseIndexOf(arr, val) {
74
+ return arr.findIndex((item) => looseEqual(item, val));
75
+ }
76
+ function invokeArrayFns(fns, ...args) {
77
+ for (let i = 0; i < fns.length; i++) {
78
+ const fn = fns[i];
79
+ if (fn) fn(...args);
80
+ }
81
+ }
82
+
83
+ const V_REGISTER_MARKER = /* @__PURE__ */ Symbol.for("attaform:v-register-directive");
84
+ const REGISTER_OWNER_MARKER = /* @__PURE__ */ Symbol.for("attaform:register-owner-marker");
85
+ const SSR_COMPONENT_HOST_MODIFIER = "attaformComponentHost";
86
+ const V_REGISTER_COMPILED_MODIFIER = "attaformCompiled";
87
+ function isRegisterValue(val) {
88
+ if (typeof val !== "object" || val === null) return false;
89
+ if (!("innerRef" in val)) return false;
90
+ if (!isRef(val.innerRef)) return false;
91
+ if (!("registerElement" in val)) return false;
92
+ if (typeof val.registerElement !== "function") return false;
93
+ if (!("setValueWithInternalPath" in val)) return false;
94
+ if (typeof val.setValueWithInternalPath !== "function") return false;
95
+ return true;
96
+ }
97
+ function isTransforming(value) {
98
+ return isRegisterValue(value) && value.transforming;
99
+ }
100
+
101
+ const assignKey = /* @__PURE__ */ Symbol.for("attaform:assign-key");
102
+ const DEFAULT_ASSIGNER_TAG = /* @__PURE__ */ Symbol.for("attaform:default-assigner-tag");
103
+ function isDefaultAssigner(fn) {
104
+ return typeof fn === "function" && fn[DEFAULT_ASSIGNER_TAG] === true;
105
+ }
106
+ const CONSUMER_WRAPPED_TAG = /* @__PURE__ */ Symbol.for("attaform:consumer-wrapped-assigner");
107
+ function isConsumerWrapped(fn) {
108
+ return typeof fn === "function" && fn[CONSUMER_WRAPPED_TAG] === true;
109
+ }
110
+ function fireAssigner(el, registerValue, value) {
111
+ const fn = el[assignKey];
112
+ if (fn === void 0) return void 0;
113
+ if (isDefaultAssigner(fn) || isConsumerWrapped(fn)) {
114
+ return fn(value);
115
+ }
116
+ if (!isRegisterValue(registerValue)) {
117
+ return fn(value, void 0);
118
+ }
119
+ return wrapWithTransforms(
120
+ value,
121
+ registerValue,
122
+ (coerced) => fn(coerced, registerValue),
123
+ void 0
124
+ );
125
+ }
126
+ function isThenable(x) {
127
+ return x !== null && (typeof x === "object" || typeof x === "function") && typeof x.then === "function";
128
+ }
129
+ function makeTransformContext() {
130
+ const holder = { controller: null, aborted: false };
131
+ const ctx = {
132
+ get signal() {
133
+ if (holder.controller === null) {
134
+ holder.controller = new AbortController();
135
+ if (holder.aborted) holder.controller.abort();
136
+ }
137
+ return holder.controller.signal;
138
+ }
139
+ };
140
+ return { ctx, holder };
141
+ }
142
+ function runTransforms(initial, registerValue) {
143
+ const transforms = registerValue.transforms;
144
+ if (transforms === void 0 || transforms.length === 0) {
145
+ return { kind: "sync", ok: true, value: initial };
146
+ }
147
+ const { ctx, holder } = makeTransformContext();
148
+ let v = initial;
149
+ for (let i = 0; i < transforms.length; i++) {
150
+ const fn = transforms[i];
151
+ let out;
152
+ try {
153
+ out = fn(v, ctx);
154
+ } catch (err) {
155
+ logTransformFailure(registerValue.path, i, fn, err);
156
+ return { kind: "sync", ok: false };
157
+ }
158
+ if (isThenable(out)) {
159
+ const rest = transforms.slice(i + 1);
160
+ const seed = out;
161
+ const run = () => rest.reduce(
162
+ (acc, next) => acc.then((value) => next(value, ctx)),
163
+ Promise.resolve(seed)
164
+ );
165
+ return { kind: "async", run, holder };
166
+ }
167
+ v = out;
168
+ }
169
+ return { kind: "sync", ok: true, value: v };
170
+ }
171
+ function kickoffAsyncTransform(rv, holder, run, commit, syncDom) {
172
+ const token = rv.beginTransform(holder);
173
+ void run().then(
174
+ (value) => {
175
+ const live = rv.isCurrentTransform(token);
176
+ rv.endTransform(token);
177
+ if (!live) return;
178
+ const coerced = applyCoerce(value, rv);
179
+ const wrote = commit(coerced);
180
+ if (wrote === false) rv.setTransformError(transformGateRejectedError(rv.path));
181
+ else syncDom?.();
182
+ },
183
+ (err) => {
184
+ if (rv.isCurrentTransform(token)) rv.setTransformError(toTransformError(err));
185
+ rv.endTransform(token);
186
+ }
187
+ );
188
+ }
189
+ function logTransformFailure(path, index, fn, err) {
190
+ {
191
+ const namePart = fn.name !== "" ? `, '${fn.name}'` : "";
192
+ console.error(
193
+ `[attaform] transform threw for path '${path}' (index ${index}${namePart}). Write aborted. Transforms must not throw; wrap your own try/catch if the throw is recoverable. Original error:`,
194
+ err
195
+ );
196
+ }
197
+ }
198
+ function applyCoerce(value, registerValue) {
199
+ return registerValue.coerce !== void 0 ? registerValue.coerce(value) : value;
200
+ }
201
+ function wrapWithTransforms(value, registerValue, commit, syncDom) {
202
+ const r = runTransforms(value, registerValue);
203
+ if (r.kind === "async") {
204
+ kickoffAsyncTransform(registerValue, r.holder, r.run, commit, syncDom);
205
+ return true;
206
+ }
207
+ if (!r.ok) return false;
208
+ const coerced = applyCoerce(r.value, registerValue);
209
+ return commit(coerced);
210
+ }
211
+ function toTransformError(value) {
212
+ if (value instanceof Error) return value;
213
+ const message = typeof value === "string" && value.length > 0 ? value : `Transform rejected with a non-Error value (${typeof value})`;
214
+ return new Error(message, { cause: value });
215
+ }
216
+ function transformGateRejectedError(path) {
217
+ return new Error(
218
+ `[attaform] transform result for path '${path}' was rejected by the field's type gate (the resolved value did not fit the schema slot).`
219
+ );
220
+ }
221
+ const getModelAssigner = (el, vnode, registerValue) => {
222
+ const fn = vnode.props?.["onUpdate:registerValue"] ?? vnode.props?.["on:update:registerValue"];
223
+ if (isArray(fn)) {
224
+ const fnArr = fn.filter((x) => isFunction(x));
225
+ const wrapped = (value) => {
226
+ return wrapWithTransforms(
227
+ value,
228
+ registerValue,
229
+ (coerced) => {
230
+ invokeArrayFns(fnArr, coerced, registerValue);
231
+ return void 0;
232
+ },
233
+ void 0
234
+ );
235
+ };
236
+ wrapped[CONSUMER_WRAPPED_TAG] = true;
237
+ return wrapped;
238
+ }
239
+ if (isFunction(fn)) {
240
+ const handler = fn;
241
+ const wrapped = (value) => {
242
+ return wrapWithTransforms(
243
+ value,
244
+ registerValue,
245
+ (coerced) => handler(coerced, registerValue),
246
+ void 0
247
+ );
248
+ };
249
+ wrapped[CONSUMER_WRAPPED_TAG] = true;
250
+ return wrapped;
251
+ }
252
+ const defaultAssigner = (value) => {
253
+ if (value === void 0 && registerValue.acceptsUndefined) {
254
+ return registerValue.setValueWithInternalPath(void 0);
255
+ }
256
+ return wrapWithTransforms(
257
+ value,
258
+ registerValue,
259
+ (coerced) => registerValue.setValueWithInternalPath(coerced),
260
+ el._syncFromStorage
261
+ );
262
+ };
263
+ defaultAssigner[DEFAULT_ASSIGNER_TAG] = true;
264
+ return defaultAssigner;
265
+ };
266
+ function makeNoopAssigner() {
267
+ const noop = (_) => void 0;
268
+ noop[DEFAULT_ASSIGNER_TAG] = true;
269
+ return noop;
270
+ }
271
+ function setAssignFunction(el, vnode, value) {
272
+ const current = el[assignKey];
273
+ if (current !== void 0 && !isDefaultAssigner(current) && !isConsumerWrapped(current)) {
274
+ return;
275
+ }
276
+ if (value === void 0) {
277
+ el[assignKey] = makeNoopAssigner();
278
+ return;
279
+ }
280
+ if (!isRegisterValue(value)) {
281
+ {
282
+ warn(
283
+ `v-register expected a RegisterValue, got '${typeof value}'. Bind to form.register('field'), not the field's ref, value, or path string.`
284
+ );
285
+ }
286
+ el[assignKey] = makeNoopAssigner();
287
+ return;
288
+ }
289
+ el[assignKey] = getModelAssigner(el, vnode, value);
290
+ }
291
+
292
+ const inherited = /* @__PURE__ */ new WeakMap();
293
+ function recordInheritedModifiers(rv, modifiers) {
294
+ const lazy = modifiers.lazy === true;
295
+ const trim = modifiers.trim === true;
296
+ const number = modifiers.number === true;
297
+ if ((lazy || trim || number) && typeof rv === "object" && rv !== null) {
298
+ inherited.set(toRaw(rv), { lazy, trim, number });
299
+ }
300
+ }
301
+ function withInheritedModifiers(rv, own) {
302
+ const found = typeof rv === "object" && rv !== null ? inherited.get(toRaw(rv)) : void 0;
303
+ return found === void 0 ? own : { ...found, ...own };
304
+ }
305
+
306
+ function commit(rv, raw, modifiers) {
307
+ let value = raw;
308
+ if (modifiers.number === true && typeof value === "string") {
309
+ const cast = looseToNumber(value);
310
+ if (typeof cast !== "number") return rv.markBlank();
311
+ if (!Number.isFinite(cast)) return false;
312
+ value = cast;
313
+ }
314
+ if (value == null || value === "" && !rv.acceptsString) return rv.commitFromHost(value);
315
+ return wrapWithTransforms(value, rv, (coerced) => rv.commitFromHost(coerced), void 0) !== false;
316
+ }
317
+ function createHostChannel() {
318
+ const editing = /* @__PURE__ */ new Set();
319
+ const pending = /* @__PURE__ */ new Map();
320
+ const heldDraft = (rv) => {
321
+ const draft = pending.get(rv.path);
322
+ return draft?.basis === rv.innerRef.value ? draft : void 0;
323
+ };
324
+ return {
325
+ write(rv, value, ownModifiers) {
326
+ const modifiers = withInheritedModifiers(rv, ownModifiers);
327
+ if (modifiers.lazy === true && editing.has(rv.path)) {
328
+ pending.set(rv.path, { value, basis: rv.innerRef.value });
329
+ return true;
330
+ }
331
+ return commit(rv, value, modifiers);
332
+ },
333
+ writeInput(rv, payload, modifiers) {
334
+ if (typeof payload !== "object" || payload === null || payload instanceof Event || !("value" in payload) || !safeOwnHas(payload, "value")) {
335
+ return false;
336
+ }
337
+ return rv.setValueFromHost(payload.value, modifiers);
338
+ },
339
+ markEditing(rv, isEditing, modifiers) {
340
+ if (isEditing) {
341
+ editing.add(rv.path);
342
+ return;
343
+ }
344
+ editing.delete(rv.path);
345
+ const draft = heldDraft(rv);
346
+ if (pending.delete(rv.path)) {
347
+ if (draft !== void 0) {
348
+ const buffered = draft.value;
349
+ commit(
350
+ rv,
351
+ modifiers.trim === true && typeof buffered === "string" ? buffered.trim() : buffered,
352
+ modifiers
353
+ );
354
+ }
355
+ return;
356
+ }
357
+ if (modifiers.trim === true) {
358
+ const current = rv.innerRef.value;
359
+ if (typeof current === "string" && current !== current.trim()) {
360
+ commit(rv, current.trim(), modifiers);
361
+ }
362
+ }
363
+ },
364
+ holdsDraft: (rv) => heldDraft(rv) !== void 0,
365
+ release(rv) {
366
+ editing.delete(rv.path);
367
+ pending.delete(rv.path);
368
+ }
369
+ };
370
+ }
371
+
6
372
  const attaformListenersSymbol = /* @__PURE__ */ Symbol.for("attaform:focus-listeners");
7
373
  const HOST_FOCUS_TARGET_SELECTOR = [
8
374
  'input:not([type="hidden"])',
@@ -32,9 +398,7 @@ function attachFocusListeners(kernel, segments, element, instanceMeta) {
32
398
  element.addEventListener("focus", handleFocus);
33
399
  element.addEventListener("blur", handleBlur);
34
400
  target[attaformListenersSymbol] = { handleFocus, handleBlur };
35
- const rootNode = element.getRootNode();
36
- const activeElement = rootNode instanceof Document || rootNode instanceof ShadowRoot ? rootNode.activeElement : null;
37
- if (activeElement === element) {
401
+ if (activeElementOf(element) === element) {
38
402
  kernel.markFocused(segments, true, focusMeta);
39
403
  }
40
404
  }
@@ -109,133 +473,45 @@ function createDomBinding(kernel) {
109
473
  host: false,
110
474
  formInstanceId: elementToFormInstance.get(el) ?? ""
111
475
  });
112
- }
113
- }
114
- for (const [key, target] of hostTargets) {
115
- if (elements.has(key)) continue;
116
- flat.push({
117
- path: target.path,
118
- element: target.hostRoot,
119
- host: true,
120
- formInstanceId: target.formInstanceId
121
- });
122
- }
123
- flat.sort(
124
- (a, b) => a.element.compareDocumentPosition(b.element) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1
125
- );
126
- return flat;
127
- }
128
- function getFirstErrorElement(formInstanceId) {
129
- sortedRegistrationsCache ?? (sortedRegistrationsCache = rebuildSortedRegistrations());
130
- for (const entry of sortedRegistrationsCache) {
131
- if (entry.formInstanceId !== formInstanceId) continue;
132
- if (!entry.element.isConnected) continue;
133
- if (entry.element.offsetParent === null) continue;
134
- if (kernel.getErrorsForPath(entry.path).length === 0) continue;
135
- const element = entry.host ? resolveHostFocusTarget(entry.element) : entry.element;
136
- return { path: entry.path, element };
137
- }
138
- return null;
139
- }
140
- return {
141
- elements,
142
- attach,
143
- detach,
144
- markHostConnected,
145
- getFirstErrorElement
146
- };
147
- }
148
- function armDomBinding(value) {
149
- value.ensureDomBinding?.(createDomBinding);
150
- }
151
-
152
- const V_REGISTER_MARKER = /* @__PURE__ */ Symbol.for("attaform:v-register-directive");
153
- const REGISTER_OWNER_MARKER = /* @__PURE__ */ Symbol.for("attaform:register-owner-marker");
154
- const SSR_COMPONENT_HOST_MODIFIER = "attaformComponentHost";
155
- const V_REGISTER_COMPILED_MODIFIER = "attaformCompiled";
156
- function isRegisterValue(val) {
157
- if (typeof val !== "object" || val === null) return false;
158
- if (!("innerRef" in val)) return false;
159
- if (!isRef(val.innerRef)) return false;
160
- if (!("registerElement" in val)) return false;
161
- if (typeof val.registerElement !== "function") return false;
162
- if (!("setValueWithInternalPath" in val)) return false;
163
- if (typeof val.setValueWithInternalPath !== "function") return false;
164
- return true;
165
- }
166
- function isTransforming(value) {
167
- return isRegisterValue(value) && value.transforming;
168
- }
169
-
170
- const isArray = Array.isArray;
171
- function isFunction(value) {
172
- return typeof value === "function";
173
- }
174
- function toTypeString(value) {
175
- return Object.prototype.toString.call(value);
176
- }
177
- function isSet(value) {
178
- return toTypeString(value) === "[object Set]";
179
- }
180
- function isDate(value) {
181
- return toTypeString(value) === "[object Date]";
182
- }
183
- function isSymbol(value) {
184
- return typeof value === "symbol";
185
- }
186
- function isObject(value) {
187
- return value !== null && typeof value === "object";
188
- }
189
- function looseToNumber(val) {
190
- const n = parseFloat(val);
191
- return isNaN(n) ? val : n;
192
- }
193
- function looseCompareArrays(a, b) {
194
- if (a.length !== b.length) return false;
195
- let equal = true;
196
- for (let i = 0; equal && i < a.length; i++) {
197
- equal = looseEqual(a[i], b[i]);
198
- }
199
- return equal;
200
- }
201
- function looseEqual(a, b) {
202
- if (a === b) return true;
203
- const aValidType = isDate(a);
204
- const bValidType = isDate(b);
205
- if (aValidType || bValidType) {
206
- return aValidType && bValidType ? a.getTime() === b.getTime() : false;
207
- }
208
- const aSymbol = isSymbol(a);
209
- const bSymbol = isSymbol(b);
210
- if (aSymbol || bSymbol) return a === b;
211
- const aIsArray = isArray(a);
212
- const bIsArray = isArray(b);
213
- if (aIsArray || bIsArray) {
214
- return aIsArray && bIsArray ? looseCompareArrays(a, b) : false;
476
+ }
477
+ }
478
+ for (const [key, target] of hostTargets) {
479
+ if (elements.has(key)) continue;
480
+ flat.push({
481
+ path: target.path,
482
+ element: target.hostRoot,
483
+ host: true,
484
+ formInstanceId: target.formInstanceId
485
+ });
486
+ }
487
+ flat.sort(
488
+ (a, b) => a.element.compareDocumentPosition(b.element) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1
489
+ );
490
+ return flat;
215
491
  }
216
- const aIsObject = isObject(a);
217
- const bIsObject = isObject(b);
218
- if (aIsObject !== bIsObject) return false;
219
- if (aIsObject && bIsObject) {
220
- const keysA = Object.keys(a);
221
- if (keysA.length !== Object.keys(b).length) return false;
222
- for (const key of keysA) {
223
- const hasA = Object.prototype.hasOwnProperty.call(a, key);
224
- const hasB = Object.prototype.hasOwnProperty.call(b, key);
225
- if (!hasA || !hasB || !looseEqual(a[key], b[key])) return false;
492
+ function getFirstErrorElement(formInstanceId) {
493
+ sortedRegistrationsCache ?? (sortedRegistrationsCache = rebuildSortedRegistrations());
494
+ for (const entry of sortedRegistrationsCache) {
495
+ if (entry.formInstanceId !== formInstanceId) continue;
496
+ if (!entry.element.isConnected) continue;
497
+ if (entry.element.offsetParent === null) continue;
498
+ if (kernel.getErrorsForPath(entry.path).length === 0) continue;
499
+ const element = entry.host ? resolveHostFocusTarget(entry.element) : entry.element;
500
+ return { path: entry.path, element };
226
501
  }
227
- return true;
502
+ return null;
228
503
  }
229
- return String(a) === String(b);
230
- }
231
- function looseIndexOf(arr, val) {
232
- return arr.findIndex((item) => looseEqual(item, val));
504
+ return {
505
+ elements,
506
+ attach,
507
+ detach,
508
+ markHostConnected,
509
+ getFirstErrorElement,
510
+ hostChannel: createHostChannel()
511
+ };
233
512
  }
234
- function invokeArrayFns(fns, ...args) {
235
- for (let i = 0; i < fns.length; i++) {
236
- const fn = fns[i];
237
- if (fn) fn(...args);
238
- }
513
+ function armDomBinding(value) {
514
+ return value.ensureDomBinding?.(createDomBinding);
239
515
  }
240
516
 
241
517
  const MANAGED_ARIA_ATTRS = [
@@ -386,197 +662,6 @@ function isRegisterValueLike(val) {
386
662
  return typeof val === "object" && val !== null && "markInteracted" in val && typeof val.markInteracted === "function";
387
663
  }
388
664
 
389
- const assignKey = /* @__PURE__ */ Symbol.for("attaform:assign-key");
390
- const DEFAULT_ASSIGNER_TAG = /* @__PURE__ */ Symbol.for("attaform:default-assigner-tag");
391
- function isDefaultAssigner(fn) {
392
- return typeof fn === "function" && fn[DEFAULT_ASSIGNER_TAG] === true;
393
- }
394
- const CONSUMER_WRAPPED_TAG = /* @__PURE__ */ Symbol.for("attaform:consumer-wrapped-assigner");
395
- function isConsumerWrapped(fn) {
396
- return typeof fn === "function" && fn[CONSUMER_WRAPPED_TAG] === true;
397
- }
398
- function fireAssigner(el, registerValue, value) {
399
- const fn = el[assignKey];
400
- if (fn === void 0) return void 0;
401
- if (isDefaultAssigner(fn) || isConsumerWrapped(fn)) {
402
- return fn(value);
403
- }
404
- if (!isRegisterValue(registerValue)) {
405
- return fn(value, void 0);
406
- }
407
- return wrapWithTransforms(
408
- value,
409
- registerValue,
410
- (coerced) => fn(coerced, registerValue),
411
- void 0
412
- );
413
- }
414
- function isThenable(x) {
415
- return x !== null && (typeof x === "object" || typeof x === "function") && typeof x.then === "function";
416
- }
417
- function makeTransformContext() {
418
- const holder = { controller: null, aborted: false };
419
- const ctx = {
420
- get signal() {
421
- if (holder.controller === null) {
422
- holder.controller = new AbortController();
423
- if (holder.aborted) holder.controller.abort();
424
- }
425
- return holder.controller.signal;
426
- }
427
- };
428
- return { ctx, holder };
429
- }
430
- function runTransforms(initial, registerValue) {
431
- const transforms = registerValue.transforms;
432
- if (transforms === void 0 || transforms.length === 0) {
433
- return { kind: "sync", ok: true, value: initial };
434
- }
435
- const { ctx, holder } = makeTransformContext();
436
- let v = initial;
437
- for (let i = 0; i < transforms.length; i++) {
438
- const fn = transforms[i];
439
- let out;
440
- try {
441
- out = fn(v, ctx);
442
- } catch (err) {
443
- logTransformFailure(registerValue.path, i, fn, err);
444
- return { kind: "sync", ok: false };
445
- }
446
- if (isThenable(out)) {
447
- const rest = transforms.slice(i + 1);
448
- const seed = out;
449
- const run = () => rest.reduce(
450
- (acc, next) => acc.then((value) => next(value, ctx)),
451
- Promise.resolve(seed)
452
- );
453
- return { kind: "async", run, holder };
454
- }
455
- v = out;
456
- }
457
- return { kind: "sync", ok: true, value: v };
458
- }
459
- function kickoffAsyncTransform(rv, holder, run, commit, syncDom) {
460
- const token = rv.beginTransform(holder);
461
- void run().then(
462
- (value) => {
463
- const live = rv.isCurrentTransform(token);
464
- rv.endTransform(token);
465
- if (!live) return;
466
- const coerced = applyCoerce(value, rv);
467
- const wrote = commit(coerced);
468
- if (wrote === false) rv.setTransformError(transformGateRejectedError(rv.path));
469
- else syncDom?.();
470
- },
471
- (err) => {
472
- if (rv.isCurrentTransform(token)) rv.setTransformError(toTransformError(err));
473
- rv.endTransform(token);
474
- }
475
- );
476
- }
477
- function logTransformFailure(path, index, fn, err) {
478
- {
479
- const namePart = fn.name !== "" ? `, '${fn.name}'` : "";
480
- console.error(
481
- `[attaform] transform threw for path '${path}' (index ${index}${namePart}). Write aborted. Transforms must not throw; wrap your own try/catch if the throw is recoverable. Original error:`,
482
- err
483
- );
484
- }
485
- }
486
- function applyCoerce(value, registerValue) {
487
- return registerValue.coerce !== void 0 ? registerValue.coerce(value) : value;
488
- }
489
- function wrapWithTransforms(value, registerValue, commit, syncDom) {
490
- const r = runTransforms(value, registerValue);
491
- if (r.kind === "async") {
492
- kickoffAsyncTransform(registerValue, r.holder, r.run, commit, syncDom);
493
- return true;
494
- }
495
- if (!r.ok) return false;
496
- const coerced = applyCoerce(r.value, registerValue);
497
- return commit(coerced);
498
- }
499
- function toTransformError(value) {
500
- if (value instanceof Error) return value;
501
- const message = typeof value === "string" && value.length > 0 ? value : `Transform rejected with a non-Error value (${typeof value})`;
502
- return new Error(message, { cause: value });
503
- }
504
- function transformGateRejectedError(path) {
505
- return new Error(
506
- `[attaform] transform result for path '${path}' was rejected by the field's type gate (the resolved value did not fit the schema slot).`
507
- );
508
- }
509
- const getModelAssigner = (el, vnode, registerValue) => {
510
- const fn = vnode.props?.["onUpdate:registerValue"] ?? vnode.props?.["on:update:registerValue"];
511
- if (isArray(fn)) {
512
- const fnArr = fn.filter((x) => isFunction(x));
513
- const wrapped = (value) => {
514
- return wrapWithTransforms(
515
- value,
516
- registerValue,
517
- (coerced) => {
518
- invokeArrayFns(fnArr, coerced, registerValue);
519
- return void 0;
520
- },
521
- void 0
522
- );
523
- };
524
- wrapped[CONSUMER_WRAPPED_TAG] = true;
525
- return wrapped;
526
- }
527
- if (isFunction(fn)) {
528
- const handler = fn;
529
- const wrapped = (value) => {
530
- return wrapWithTransforms(
531
- value,
532
- registerValue,
533
- (coerced) => handler(coerced, registerValue),
534
- void 0
535
- );
536
- };
537
- wrapped[CONSUMER_WRAPPED_TAG] = true;
538
- return wrapped;
539
- }
540
- const defaultAssigner = (value) => {
541
- if (value === void 0 && registerValue.acceptsUndefined) {
542
- return registerValue.setValueWithInternalPath(void 0);
543
- }
544
- return wrapWithTransforms(
545
- value,
546
- registerValue,
547
- (coerced) => registerValue.setValueWithInternalPath(coerced),
548
- el._syncFromStorage
549
- );
550
- };
551
- defaultAssigner[DEFAULT_ASSIGNER_TAG] = true;
552
- return defaultAssigner;
553
- };
554
- function makeNoopAssigner() {
555
- const noop = (_) => void 0;
556
- noop[DEFAULT_ASSIGNER_TAG] = true;
557
- return noop;
558
- }
559
- function setAssignFunction(el, vnode, value) {
560
- const current = el[assignKey];
561
- if (current !== void 0 && !isDefaultAssigner(current) && !isConsumerWrapped(current)) {
562
- return;
563
- }
564
- if (value === void 0) {
565
- el[assignKey] = makeNoopAssigner();
566
- return;
567
- }
568
- if (!isRegisterValue(value)) {
569
- {
570
- warn(
571
- `v-register expected a RegisterValue, got '${typeof value}'. Bind to form.register('field'), not the field's ref, value, or path string.`
572
- );
573
- }
574
- el[assignKey] = makeNoopAssigner();
575
- return;
576
- }
577
- el[assignKey] = getModelAssigner(el, vnode, value);
578
- }
579
-
580
665
  function isBlankFileValue(value) {
581
666
  if (value === null || value === void 0) return true;
582
667
  if (Array.isArray(value) && value.length === 0) return true;
@@ -668,11 +753,6 @@ function syncElementRegistration(el, value, oldValue) {
668
753
  }
669
754
 
670
755
  const valueSyncScopeKey = /* @__PURE__ */ Symbol.for("attaform:value-sync-scope");
671
- function isElementFocused(el) {
672
- const rootNode = el.getRootNode();
673
- const activeElement = rootNode instanceof Document || rootNode instanceof ShadowRoot ? rootNode.activeElement : null;
674
- return activeElement === el;
675
- }
676
756
  function setupValueSync(el, source, apply, options = {}) {
677
757
  const skipWhileFocused = options.skipWhileFocused === true;
678
758
  const scope = effectScope(true);
@@ -681,7 +761,7 @@ function setupValueSync(el, source, apply, options = {}) {
681
761
  source,
682
762
  () => {
683
763
  if (el.composing === true) return;
684
- if (skipWhileFocused && isElementFocused(el)) return;
764
+ if (skipWhileFocused && activeElementOf(el) === el) return;
685
765
  apply();
686
766
  },
687
767
  { flush: "post" }
@@ -740,6 +820,28 @@ function onCompositionEnd(e) {
740
820
  target.dispatchEvent(new Event("input"));
741
821
  }
742
822
  }
823
+ const heldDrafts = /* @__PURE__ */ new WeakMap();
824
+ function holdDraft(owner, control, stale) {
825
+ heldDrafts.set(owner, {
826
+ control,
827
+ text: control.value,
828
+ stale,
829
+ start: control.selectionStart,
830
+ end: control.selectionEnd
831
+ });
832
+ }
833
+ function restoreDraft(owner) {
834
+ const held = heldDrafts.get(owner);
835
+ if (held === void 0) return;
836
+ heldDrafts.delete(owner);
837
+ const { control, text, stale, start, end } = held;
838
+ if (control.value !== stale || stale === text) return;
839
+ control.value = text;
840
+ if (start !== null && end !== null) control.setSelectionRange(start, end);
841
+ }
842
+ function textControl(node) {
843
+ return node instanceof HTMLInputElement || node instanceof HTMLTextAreaElement ? node : null;
844
+ }
743
845
  const vRegisterText = {
744
846
  created(el, { value, modifiers: { lazy, trim, number } }, vnode) {
745
847
  const castToNumberAtCreated = number === true || vnode.props?.["type"] === "number";
@@ -862,12 +964,14 @@ const vRegisterText = {
862
964
  mounted(el, { value }) {
863
965
  if (!isRegisterValue(value)) return;
864
966
  el.value = value.displayValue.value;
967
+ el._lastAppliedModel = value.innerRef.value;
865
968
  setupValueSync(
866
969
  el,
867
970
  value.displayValue,
868
971
  () => {
869
972
  const next = value.displayValue.value;
870
973
  if (el.value !== next) el.value = next;
974
+ el._lastAppliedModel = value.innerRef.value;
871
975
  },
872
976
  { skipWhileFocused: true }
873
977
  );
@@ -876,17 +980,16 @@ const vRegisterText = {
876
980
  setAssignFunction(el, vnode, value);
877
981
  if (el.composing === true) return;
878
982
  if (!isRegisterValue(value)) return;
983
+ const model = value.innerRef.value;
984
+ const modelMoved = model !== el._lastAppliedModel || !isRegisterValue(oldValue) || oldValue.path !== value.path;
985
+ el._lastAppliedModel = model;
879
986
  const target = value.displayValue.value;
880
987
  if (el.value === target) {
881
988
  return;
882
989
  }
883
- const rootNode = el.getRootNode();
884
- const activeElement = rootNode instanceof Document || rootNode instanceof ShadowRoot ? rootNode.activeElement : null;
885
- if (activeElement === el && el.type !== "range") {
886
- if (lazy === true && value.innerRef.value === oldValue) {
887
- return;
888
- }
889
- if (trim === true && el.value.trim() === target) {
990
+ if (activeElementOf(el) === el && el.type !== "range") {
991
+ if (lazy === true && !modelMoved || trim === true && el.value.trim() === target) {
992
+ holdDraft(el, el, target);
890
993
  return;
891
994
  }
892
995
  }
@@ -1265,6 +1368,29 @@ function observeForLateHostControl(el, rv) {
1265
1368
  observer.observe(el, { childList: true, subtree: true });
1266
1369
  hostHealObservers.set(el, observer);
1267
1370
  }
1371
+ const hostEdits = /* @__PURE__ */ new WeakMap();
1372
+ function trackHostEdits(el, rv, modifiers) {
1373
+ if (modifiers.lazy !== true && modifiers.trim !== true) return;
1374
+ if (!INTERACTIVE_TAG_NAMES.has(el.tagName) && rv.hasRegisteredDescendant(el)) return;
1375
+ const channel = armDomBinding(rv)?.hostChannel;
1376
+ if (channel === void 0) return;
1377
+ const edits = { channel, rv, base: void 0 };
1378
+ const edge = (editing) => (event) => {
1379
+ if (editing && !channel.holdsDraft(rv)) edits.base = textControl(event.target)?.value;
1380
+ const other = event.relatedTarget;
1381
+ if (other instanceof Node && el.contains(other)) return;
1382
+ channel.markEditing(rv, editing, modifiers);
1383
+ };
1384
+ addTrackedListener(el, "focus", edge(true), { capture: true });
1385
+ addTrackedListener(el, "blur", edge(false), { capture: true });
1386
+ hostEdits.set(el, edits);
1387
+ }
1388
+ function holdHostDraft(el) {
1389
+ const edits = hostEdits.get(el);
1390
+ if (edits?.base === void 0 || !edits.channel.holdsDraft(edits.rv)) return;
1391
+ const control = textControl(activeElementOf(el));
1392
+ if (control !== null && el.contains(control)) holdDraft(el, control, edits.base);
1393
+ }
1268
1394
  function activateComponentHost(el, rv) {
1269
1395
  if (rv.hasRegisteredDescendant(el)) return;
1270
1396
  el[REGISTER_OWNER_MARKER] = true;
@@ -1279,19 +1405,26 @@ function activateComponentHost(el, rv) {
1279
1405
  setupNoLatchHost(el, rv);
1280
1406
  scheduleHostSelfHeal(el, rv);
1281
1407
  }
1408
+ function inheritModifiers(binding) {
1409
+ const modifiers = withInheritedModifiers(binding.value, binding.modifiers);
1410
+ return modifiers === binding.modifiers ? binding : { ...binding, modifiers };
1411
+ }
1282
1412
  const vRegisterDynamic = {
1283
- created(el, binding, vnode) {
1413
+ created(el, ownBinding, vnode) {
1414
+ const binding = inheritModifiers(ownBinding);
1284
1415
  if (isRegisterValue(binding.value)) armDomBinding(binding.value);
1285
1416
  callModelHook(el, binding, vnode, null, "created");
1286
1417
  if (isRegisterValue(binding.value)) setupAria(el, binding.value, vnode);
1287
1418
  warnRedundantStateBinding(el, binding, vnode);
1288
1419
  },
1289
- mounted(el, binding, vnode) {
1420
+ mounted(el, ownBinding, vnode) {
1421
+ const binding = inheritModifiers(ownBinding);
1290
1422
  callModelHook(el, binding, vnode, null, "mounted");
1291
1423
  if (isRegisterValue(binding.value) && INTERACTIVE_TAG_NAMES.has(el.tagName) && binding.modifiers[SSR_COMPONENT_HOST_MODIFIER] !== true && vnode.props?.["disabled"] === void 0) {
1292
1424
  setupDisabledSync(el, binding.value.disabled);
1293
1425
  }
1294
1426
  if (binding.modifiers[SSR_COMPONENT_HOST_MODIFIER] === true && isRegisterValue(binding.value)) {
1427
+ trackHostEdits(el, binding.value, binding.modifiers);
1295
1428
  activateComponentHost(el, binding.value);
1296
1429
  }
1297
1430
  if (warnedUnsupportedElements !== null && !INTERACTIVE_TAG_NAMES.has(el.tagName) && !warnedUnsupportedElements.has(el)) {
@@ -1309,10 +1442,12 @@ const vRegisterDynamic = {
1309
1442
  });
1310
1443
  }
1311
1444
  },
1312
- beforeUpdate(el, binding, vnode, prevVNode) {
1445
+ beforeUpdate(el, ownBinding, vnode, prevVNode) {
1446
+ const binding = inheritModifiers(ownBinding);
1313
1447
  if (isRegisterValue(binding.value)) armDomBinding(binding.value);
1314
1448
  syncElementRegistration(el, binding.value, binding.oldValue);
1315
1449
  callModelHook(el, binding, vnode, prevVNode, "beforeUpdate");
1450
+ holdHostDraft(el);
1316
1451
  const ariaEl = el;
1317
1452
  const value = binding.value;
1318
1453
  if (!isRegisterValue(value) || value.ariaDisplayState === void 0) {
@@ -1330,13 +1465,17 @@ const vRegisterDynamic = {
1330
1465
  }
1331
1466
  },
1332
1467
  updated(el, binding, vnode, prevVNode) {
1333
- callModelHook(el, binding, vnode, prevVNode, "updated");
1468
+ callModelHook(el, inheritModifiers(binding), vnode, prevVNode, "updated");
1469
+ restoreDraft(el);
1334
1470
  },
1335
1471
  beforeUnmount(el, { value }) {
1336
1472
  removeTrackedListeners(el);
1337
1473
  teardownAria(el);
1338
1474
  teardownValueSync(el);
1339
1475
  teardownDisabledSync(el);
1476
+ const edits = hostEdits.get(el);
1477
+ edits?.channel.release(edits.rv);
1478
+ hostEdits.delete(el);
1340
1479
  if (!isRegisterValue(value)) return;
1341
1480
  value.deregisterElement(el);
1342
1481
  if (componentHostLatch.has(el)) {
@@ -1449,4 +1588,4 @@ function installVRegister(app) {
1449
1588
  }
1450
1589
  }
1451
1590
 
1452
- export { REGISTER_OWNER_MARKER as R, V_REGISTER_MARKER as V, assignKey as a, installVRegister as b, vRegisterFile as c, armDomBinding as d, isRegisterValue as i, vRegister as v };
1591
+ export { REGISTER_OWNER_MARKER as R, V_REGISTER_MARKER as V, assignKey as a, installVRegister as b, vRegisterFile as c, armDomBinding as d, isRegisterValue as i, recordInheritedModifiers as r, vRegister as v, withInheritedModifiers as w };