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