attaform 0.0.1 → 0.14.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 (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +142 -2
  3. package/dist/chunks/devtools.cjs +179 -0
  4. package/dist/chunks/devtools.cjs.map +1 -0
  5. package/dist/chunks/devtools.mjs +177 -0
  6. package/dist/chunks/devtools.mjs.map +1 -0
  7. package/dist/chunks/indexeddb.cjs +119 -0
  8. package/dist/chunks/indexeddb.cjs.map +1 -0
  9. package/dist/chunks/indexeddb.mjs +117 -0
  10. package/dist/chunks/indexeddb.mjs.map +1 -0
  11. package/dist/chunks/local-storage.cjs +58 -0
  12. package/dist/chunks/local-storage.cjs.map +1 -0
  13. package/dist/chunks/local-storage.mjs +56 -0
  14. package/dist/chunks/local-storage.mjs.map +1 -0
  15. package/dist/chunks/session-storage.cjs +58 -0
  16. package/dist/chunks/session-storage.cjs.map +1 -0
  17. package/dist/chunks/session-storage.mjs +56 -0
  18. package/dist/chunks/session-storage.mjs.map +1 -0
  19. package/dist/index.cjs +173 -0
  20. package/dist/index.cjs.map +1 -0
  21. package/dist/index.d.cts +493 -0
  22. package/dist/index.d.mts +493 -0
  23. package/dist/index.d.ts +493 -0
  24. package/dist/index.mjs +141 -0
  25. package/dist/index.mjs.map +1 -0
  26. package/dist/nuxt.cjs +97 -0
  27. package/dist/nuxt.cjs.map +1 -0
  28. package/dist/nuxt.d.cts +38 -0
  29. package/dist/nuxt.d.mts +38 -0
  30. package/dist/nuxt.d.ts +38 -0
  31. package/dist/nuxt.mjs +94 -0
  32. package/dist/nuxt.mjs.map +1 -0
  33. package/dist/runtime/plugins/attaform.cjs +32 -0
  34. package/dist/runtime/plugins/attaform.cjs.map +1 -0
  35. package/dist/runtime/plugins/attaform.d.cts +5 -0
  36. package/dist/runtime/plugins/attaform.d.mts +5 -0
  37. package/dist/runtime/plugins/attaform.d.ts +5 -0
  38. package/dist/runtime/plugins/attaform.mjs +30 -0
  39. package/dist/runtime/plugins/attaform.mjs.map +1 -0
  40. package/dist/shared/attaform.B5GWYl76.cjs +386 -0
  41. package/dist/shared/attaform.B5GWYl76.cjs.map +1 -0
  42. package/dist/shared/attaform.BRTxpA3q.mjs +3283 -0
  43. package/dist/shared/attaform.BRTxpA3q.mjs.map +1 -0
  44. package/dist/shared/attaform.BYc9kugA.d.ts +124 -0
  45. package/dist/shared/attaform.Bubm_slq.cjs +622 -0
  46. package/dist/shared/attaform.Bubm_slq.cjs.map +1 -0
  47. package/dist/shared/attaform.BwaYWtMs.d.cts +126 -0
  48. package/dist/shared/attaform.BwaYWtMs.d.mts +126 -0
  49. package/dist/shared/attaform.BwaYWtMs.d.ts +126 -0
  50. package/dist/shared/attaform.CNJO3mME.cjs +3295 -0
  51. package/dist/shared/attaform.CNJO3mME.cjs.map +1 -0
  52. package/dist/shared/attaform.CRgix6_n.cjs +796 -0
  53. package/dist/shared/attaform.CRgix6_n.cjs.map +1 -0
  54. package/dist/shared/attaform.CXZgUECn.d.cts +124 -0
  55. package/dist/shared/attaform.CXpzmj38.mjs +617 -0
  56. package/dist/shared/attaform.CXpzmj38.mjs.map +1 -0
  57. package/dist/shared/attaform.Cc93zNzD.mjs +83 -0
  58. package/dist/shared/attaform.Cc93zNzD.mjs.map +1 -0
  59. package/dist/shared/attaform.DDXrY-1Q.d.cts +2568 -0
  60. package/dist/shared/attaform.DDXrY-1Q.d.mts +2568 -0
  61. package/dist/shared/attaform.DDXrY-1Q.d.ts +2568 -0
  62. package/dist/shared/attaform.DOKOyb3Y.d.mts +124 -0
  63. package/dist/shared/attaform.DlgKK10S.mjs +789 -0
  64. package/dist/shared/attaform.DlgKK10S.mjs.map +1 -0
  65. package/dist/shared/attaform.al_rpt7_.mjs +361 -0
  66. package/dist/shared/attaform.al_rpt7_.mjs.map +1 -0
  67. package/dist/shared/attaform.xKWYHMdq.cjs +89 -0
  68. package/dist/shared/attaform.xKWYHMdq.cjs.map +1 -0
  69. package/dist/transforms.cjs +11 -0
  70. package/dist/transforms.cjs.map +1 -0
  71. package/dist/transforms.d.cts +49 -0
  72. package/dist/transforms.d.mts +49 -0
  73. package/dist/transforms.d.ts +49 -0
  74. package/dist/transforms.mjs +2 -0
  75. package/dist/transforms.mjs.map +1 -0
  76. package/dist/vite.cjs +39 -0
  77. package/dist/vite.cjs.map +1 -0
  78. package/dist/vite.d.cts +53 -0
  79. package/dist/vite.d.mts +53 -0
  80. package/dist/vite.d.ts +53 -0
  81. package/dist/vite.mjs +37 -0
  82. package/dist/vite.mjs.map +1 -0
  83. package/dist/zod-v3.cjs +1511 -0
  84. package/dist/zod-v3.cjs.map +1 -0
  85. package/dist/zod-v3.d.cts +164 -0
  86. package/dist/zod-v3.d.mts +164 -0
  87. package/dist/zod-v3.d.ts +164 -0
  88. package/dist/zod-v3.mjs +1504 -0
  89. package/dist/zod-v3.mjs.map +1 -0
  90. package/dist/zod.cjs +1548 -0
  91. package/dist/zod.cjs.map +1 -0
  92. package/dist/zod.d.cts +67 -0
  93. package/dist/zod.d.mts +67 -0
  94. package/dist/zod.d.ts +67 -0
  95. package/dist/zod.mjs +1541 -0
  96. package/dist/zod.mjs.map +1 -0
  97. package/package.json +182 -6
@@ -0,0 +1,796 @@
1
+ 'use strict';
2
+
3
+ const sensitiveNames = require('./attaform.B5GWYl76.cjs');
4
+ const vue = require('vue');
5
+
6
+ const isArray = Array.isArray;
7
+ function isFunction(value) {
8
+ return typeof value === "function";
9
+ }
10
+ function toTypeString(value) {
11
+ return Object.prototype.toString.call(value);
12
+ }
13
+ function isSet(value) {
14
+ return toTypeString(value) === "[object Set]";
15
+ }
16
+ function isDate(value) {
17
+ return toTypeString(value) === "[object Date]";
18
+ }
19
+ function isSymbol(value) {
20
+ return typeof value === "symbol";
21
+ }
22
+ function isObject(value) {
23
+ return value !== null && typeof value === "object";
24
+ }
25
+ function looseToNumber(val) {
26
+ const n = parseFloat(val);
27
+ return isNaN(n) ? val : n;
28
+ }
29
+ function looseCompareArrays(a, b) {
30
+ if (a.length !== b.length) return false;
31
+ let equal = true;
32
+ for (let i = 0; equal && i < a.length; i++) {
33
+ equal = looseEqual(a[i], b[i]);
34
+ }
35
+ return equal;
36
+ }
37
+ function looseEqual(a, b) {
38
+ if (a === b) return true;
39
+ const aValidType = isDate(a);
40
+ const bValidType = isDate(b);
41
+ if (aValidType || bValidType) {
42
+ return aValidType && bValidType ? a.getTime() === b.getTime() : false;
43
+ }
44
+ const aSymbol = isSymbol(a);
45
+ const bSymbol = isSymbol(b);
46
+ if (aSymbol || bSymbol) return a === b;
47
+ const aIsArray = isArray(a);
48
+ const bIsArray = isArray(b);
49
+ if (aIsArray || bIsArray) {
50
+ return aIsArray && bIsArray ? looseCompareArrays(a, b) : false;
51
+ }
52
+ const aIsObject = isObject(a);
53
+ const bIsObject = isObject(b);
54
+ if (aIsObject !== bIsObject) return false;
55
+ if (aIsObject && bIsObject) {
56
+ const keysA = Object.keys(a);
57
+ if (keysA.length !== Object.keys(b).length) return false;
58
+ for (const key of keysA) {
59
+ const hasA = Object.prototype.hasOwnProperty.call(a, key);
60
+ const hasB = Object.prototype.hasOwnProperty.call(b, key);
61
+ if (!hasA || !hasB || !looseEqual(a[key], b[key])) return false;
62
+ }
63
+ return true;
64
+ }
65
+ return String(a) === String(b);
66
+ }
67
+ function looseIndexOf(arr, val) {
68
+ return arr.findIndex((item) => looseEqual(item, val));
69
+ }
70
+ function invokeArrayFns(fns, ...args) {
71
+ for (let i = 0; i < fns.length; i++) {
72
+ const fn = fns[i];
73
+ if (fn) fn(...args);
74
+ }
75
+ }
76
+
77
+ const assignKey = Symbol.for("attaform:assign-key");
78
+ const listenersKey = Symbol.for("attaform:directive-listeners");
79
+ function isRegisterValue(val) {
80
+ if (typeof val !== "object" || val === null) return false;
81
+ if (!("innerRef" in val)) return false;
82
+ if (!vue.isRef(val.innerRef)) return false;
83
+ if (!("registerElement" in val)) return false;
84
+ if (typeof val.registerElement !== "function") return false;
85
+ if (!("setValueWithInternalPath" in val)) return false;
86
+ if (typeof val.setValueWithInternalPath !== "function") return false;
87
+ return true;
88
+ }
89
+ function addEventListener(el, event, handler, options) {
90
+ el.addEventListener(event, handler, options);
91
+ const carrier = el;
92
+ const bag = carrier[listenersKey] ?? [];
93
+ bag.push({ event, handler, options });
94
+ carrier[listenersKey] = bag;
95
+ }
96
+ function removeTrackedListeners(el) {
97
+ const carrier = el;
98
+ const bag = carrier[listenersKey];
99
+ if (bag === void 0) return;
100
+ for (const { event, handler, options } of bag) {
101
+ el.removeEventListener(event, handler, options);
102
+ }
103
+ delete carrier[listenersKey];
104
+ }
105
+ function computePersistMeta(el, registerValue) {
106
+ const elementId = sensitiveNames.getOrAssignElementId(el);
107
+ return { persist: registerValue.persistOptIns.hasOptIn(elementId, registerValue.path) };
108
+ }
109
+ const DEFAULT_ASSIGNER_TAG = Symbol.for("attaform:default-assigner-tag");
110
+ function isDefaultAssigner(fn) {
111
+ return typeof fn === "function" && fn[DEFAULT_ASSIGNER_TAG] === true;
112
+ }
113
+ function shouldBailListener(el) {
114
+ if (SUPPORTED_TAGS.has(el.tagName)) return false;
115
+ return isDefaultAssigner(el[assignKey]);
116
+ }
117
+ function runTransforms(initial, registerValue) {
118
+ const transforms = registerValue.transforms;
119
+ if (transforms === void 0 || transforms.length === 0) {
120
+ return { ok: true, value: initial };
121
+ }
122
+ let v = initial;
123
+ for (let i = 0; i < transforms.length; i++) {
124
+ const fn = transforms[i];
125
+ try {
126
+ v = fn(v);
127
+ } catch (err) {
128
+ logTransformFailure(registerValue.path, i, fn, err);
129
+ return { ok: false };
130
+ }
131
+ }
132
+ if (v instanceof Promise) {
133
+ logTransformAsync(registerValue.path);
134
+ return { ok: false };
135
+ }
136
+ return { ok: true, value: v };
137
+ }
138
+ function logTransformFailure(path, index, fn, err) {
139
+ if (sensitiveNames.__DEV__) {
140
+ const namePart = fn.name !== "" ? `, '${fn.name}'` : "";
141
+ console.error(
142
+ `[attaform] transform threw for path '${path}' (index ${index}${namePart}) \u2014 write aborted. Transforms must not throw; wrap your own try/catch if the throw is recoverable. Original error:`,
143
+ err
144
+ );
145
+ } else {
146
+ console.error(
147
+ `[attaform] transform error \u2014 write aborted (set NODE_ENV=development for details).`
148
+ );
149
+ }
150
+ }
151
+ function applyCoerce(value, registerValue) {
152
+ return registerValue.coerce !== void 0 ? registerValue.coerce(value) : value;
153
+ }
154
+ function applyElementCoerce(value, registerValue) {
155
+ return registerValue.coerceElement !== void 0 ? registerValue.coerceElement(value) : value;
156
+ }
157
+ function logTransformAsync(path) {
158
+ if (sensitiveNames.__DEV__) {
159
+ console.error(
160
+ `[attaform] transform pipeline for path '${path}' returned a Promise \u2014 transforms must be sync. Use async field validation for canonicalize-before-write patterns. Write aborted.`
161
+ );
162
+ } else {
163
+ console.error(
164
+ `[attaform] transform error \u2014 write aborted (set NODE_ENV=development for details).`
165
+ );
166
+ }
167
+ }
168
+ const getModelAssigner = (el, vnode, registerValue) => {
169
+ const fn = vnode.props?.["onUpdate:registerValue"] ?? vnode.props?.["on:update:registerValue"];
170
+ if (isArray(fn)) {
171
+ const fnArr = fn.filter((x) => isFunction(x));
172
+ return (value) => {
173
+ const r = runTransforms(value, registerValue);
174
+ if (!r.ok) return false;
175
+ const coerced = applyCoerce(r.value, registerValue);
176
+ invokeArrayFns(fnArr, coerced, registerValue);
177
+ return void 0;
178
+ };
179
+ }
180
+ if (isFunction(fn)) {
181
+ const handler = fn;
182
+ return (value) => {
183
+ const r = runTransforms(value, registerValue);
184
+ if (!r.ok) return false;
185
+ const coerced = applyCoerce(r.value, registerValue);
186
+ return handler(coerced, registerValue);
187
+ };
188
+ }
189
+ const defaultAssigner = (value) => {
190
+ const r = runTransforms(value, registerValue);
191
+ if (!r.ok) return false;
192
+ const coerced = applyCoerce(r.value, registerValue);
193
+ return registerValue.setValueWithInternalPath(coerced, computePersistMeta(el, registerValue));
194
+ };
195
+ defaultAssigner[DEFAULT_ASSIGNER_TAG] = true;
196
+ return defaultAssigner;
197
+ };
198
+ function syncPersistOptIn(el, value, oldValue) {
199
+ const wasOptedIn = isRegisterValue(oldValue) && oldValue.persist === true;
200
+ const wantsOptIn = isRegisterValue(value) && value.persist === true;
201
+ if (!wasOptedIn && !wantsOptIn) return;
202
+ const elementId = sensitiveNames.getOrAssignElementId(el);
203
+ if (wasOptedIn) {
204
+ const old = oldValue;
205
+ const samePathAndRegistry = wantsOptIn && value.path === old.path && value.persistOptIns === old.persistOptIns;
206
+ if (!samePathAndRegistry) {
207
+ old.persistOptIns.remove(elementId, old.path);
208
+ }
209
+ }
210
+ if (wantsOptIn) {
211
+ const v = value;
212
+ sensitiveNames.enforceSensitiveCheck(v.path, v.acknowledgeSensitive);
213
+ v.persistOptIns.add(elementId, v.path);
214
+ }
215
+ }
216
+ function syncElementRegistration(el, value, oldValue) {
217
+ const wasRegistered = isRegisterValue(oldValue);
218
+ const isRegistered = isRegisterValue(value);
219
+ if (!wasRegistered && !isRegistered) return;
220
+ if (wasRegistered && isRegistered) {
221
+ const old = oldValue;
222
+ const next = value;
223
+ if (old.path === next.path && old.persistOptIns === next.persistOptIns) return;
224
+ }
225
+ if (wasRegistered) {
226
+ oldValue.deregisterElement(el);
227
+ }
228
+ if (isRegistered) {
229
+ value.registerElement(el);
230
+ }
231
+ }
232
+ function onCompositionStart(e) {
233
+ const target = e.target;
234
+ if (!target) return;
235
+ target.composing = true;
236
+ }
237
+ function onCompositionEnd(e) {
238
+ const target = e.target;
239
+ if (target?.composing === true) {
240
+ target.composing = false;
241
+ target.dispatchEvent(new Event("input"));
242
+ }
243
+ }
244
+ function makeNoopAssigner() {
245
+ const noop = (_) => void 0;
246
+ noop[DEFAULT_ASSIGNER_TAG] = true;
247
+ return noop;
248
+ }
249
+ function setAssignFunction(el, vnode, value) {
250
+ if (el[assignKey] !== void 0 && !isDefaultAssigner(el[assignKey])) {
251
+ return;
252
+ }
253
+ if (value === void 0) {
254
+ el[assignKey] = makeNoopAssigner();
255
+ return;
256
+ }
257
+ if (!isRegisterValue(value)) {
258
+ vue.warn(
259
+ `v-register expected a RegisterValue, got '${typeof value}'. Bind to form.register('field') \u2014 not the field's ref, value, or path string.`
260
+ );
261
+ el[assignKey] = makeNoopAssigner();
262
+ return;
263
+ }
264
+ el[assignKey] = getModelAssigner(el, vnode, value);
265
+ }
266
+ const vRegisterText = {
267
+ created(el, { value, modifiers: { lazy, trim, number } }, vnode) {
268
+ const castToNumber = number === true || vnode.props?.["type"] === "number";
269
+ if (isRegisterValue(value)) {
270
+ value.registerElement(el);
271
+ setAssignFunction(el, vnode, value);
272
+ }
273
+ addEventListener(el, lazy === true ? "change" : "input", (e) => {
274
+ if (shouldBailListener(el)) return;
275
+ const target = e.target;
276
+ if (target === null || target.composing) return;
277
+ let domValue = el.value;
278
+ if (trim === true && lazy === true) {
279
+ domValue = domValue.trim();
280
+ }
281
+ if (castToNumber) {
282
+ if (domValue === "") {
283
+ const validity = el.validity;
284
+ if (validity?.badInput === true) {
285
+ return;
286
+ }
287
+ if (isRegisterValue(value)) {
288
+ value.lastTypedForm.value = null;
289
+ value.markBlank();
290
+ }
291
+ return;
292
+ }
293
+ const typedString = domValue;
294
+ domValue = looseToNumber(domValue);
295
+ if (typeof domValue !== "number") {
296
+ if (isRegisterValue(value)) {
297
+ value.lastTypedForm.value = null;
298
+ value.markBlank();
299
+ }
300
+ return;
301
+ }
302
+ if (!Number.isFinite(domValue)) {
303
+ if (isRegisterValue(value)) {
304
+ const target2 = value.displayValue.value;
305
+ if (el.value !== target2) el.value = target2;
306
+ }
307
+ return;
308
+ }
309
+ if (isRegisterValue(value)) value.lastTypedForm.value = typedString;
310
+ }
311
+ el[assignKey]?.(domValue);
312
+ if (isRegisterValue(value) && isDefaultAssigner(el[assignKey])) {
313
+ const storage = value.innerRef.value;
314
+ if (storage !== domValue) {
315
+ const display = storage == null ? "" : String(storage);
316
+ if (el.value !== display) el.value = display;
317
+ if (castToNumber) value.lastTypedForm.value = null;
318
+ }
319
+ }
320
+ });
321
+ if (trim === true || castToNumber) {
322
+ addEventListener(el, "change", () => {
323
+ if (shouldBailListener(el)) return;
324
+ let normalized = el.value;
325
+ if (trim === true) normalized = normalized.trim();
326
+ if (castToNumber) {
327
+ const cast = looseToNumber(normalized);
328
+ if (typeof cast === "number" && Number.isFinite(cast)) {
329
+ if (isRegisterValue(value)) value.lastTypedForm.value = null;
330
+ el.value = String(cast);
331
+ if (lazy !== true) el[assignKey]?.(cast);
332
+ } else {
333
+ if (isRegisterValue(value)) {
334
+ value.lastTypedForm.value = null;
335
+ value.markBlank();
336
+ }
337
+ el.value = "";
338
+ }
339
+ return;
340
+ }
341
+ el.value = typeof normalized === "number" ? String(normalized) : normalized;
342
+ if (trim === true && lazy !== true) {
343
+ el[assignKey]?.(normalized);
344
+ }
345
+ });
346
+ }
347
+ if (lazy !== true) {
348
+ addEventListener(el, "compositionstart", onCompositionStart);
349
+ addEventListener(el, "compositionend", onCompositionEnd);
350
+ addEventListener(el, "change", onCompositionEnd);
351
+ }
352
+ if (number === true && vnode.props?.["type"] !== "number") {
353
+ addEventListener(el, "beforeinput", (e) => {
354
+ const ev = e;
355
+ if (ev.inputType !== "insertText" && ev.inputType !== "insertFromPaste" && ev.inputType !== "insertFromDrop") {
356
+ return;
357
+ }
358
+ const data = ev.data;
359
+ if (data === null) return;
360
+ const start = el.selectionStart ?? 0;
361
+ const end = el.selectionEnd ?? 0;
362
+ const next = el.value.slice(0, start) + data + el.value.slice(end);
363
+ if (!/^-?\d*\.?\d*([eE][+-]?\d*)?$/.test(next)) ev.preventDefault();
364
+ });
365
+ }
366
+ },
367
+ // set value on mounted so it's after min/max for type="range"
368
+ mounted(el, { value }) {
369
+ if (!isRegisterValue(value)) return;
370
+ const _val = value.innerRef.value;
371
+ el.value = typeof _val === "string" || typeof _val === "number" ? `${_val}` : "";
372
+ },
373
+ beforeUpdate(el, { value, oldValue, modifiers: { lazy, trim, number } }, vnode) {
374
+ setAssignFunction(el, vnode, value);
375
+ if (el.composing === true) return;
376
+ if (!isRegisterValue(value)) return;
377
+ const elValue = (number === true || el.type === "number") && !/^0\d/.test(el.value) ? looseToNumber(el.value) : el.value;
378
+ const newValue = value.innerRef.value === null ? "" : value.innerRef.value;
379
+ if (elValue === newValue) {
380
+ return;
381
+ }
382
+ const rootNode = el.getRootNode();
383
+ const activeElement = rootNode instanceof Document || rootNode instanceof ShadowRoot ? rootNode.activeElement : null;
384
+ if (activeElement === el && el.type !== "range") {
385
+ if (lazy === true && value.innerRef.value === oldValue) {
386
+ return;
387
+ }
388
+ if (trim === true && el.value.trim() === newValue) {
389
+ return;
390
+ }
391
+ }
392
+ el.value = newValue == null ? "" : String(newValue);
393
+ }
394
+ };
395
+ const vRegisterCheckbox = {
396
+ // #4096 array checkboxes need to be deep traversed
397
+ deep: true,
398
+ created(el, { value }, vnode) {
399
+ if (!isRegisterValue(value)) return;
400
+ value.registerElement(el);
401
+ setAssignFunction(el, vnode, value);
402
+ addEventListener(el, "change", () => {
403
+ if (shouldBailListener(el)) return;
404
+ const modelValue = value.innerRef.value ?? [];
405
+ const explicitValueRequired = true;
406
+ const rawElementValue = getValue(el, explicitValueRequired);
407
+ const checked = el.checked;
408
+ const assign = el[assignKey];
409
+ if (isArray(modelValue)) {
410
+ if (rawElementValue === void 0) {
411
+ vue.warn(
412
+ 'Checkbox bound to an array model is missing a `value` attribute \u2014 cannot determine which item to add or remove. Add value="..." to each <input type="checkbox">.'
413
+ );
414
+ return;
415
+ }
416
+ const elementValue = applyElementCoerce(rawElementValue, value);
417
+ const index = looseIndexOf(modelValue, elementValue);
418
+ const found = index !== -1;
419
+ if (checked && !found) {
420
+ assign?.(modelValue.concat(elementValue));
421
+ } else if (!checked && found) {
422
+ const filtered = [...modelValue];
423
+ filtered.splice(index, 1);
424
+ assign?.(filtered);
425
+ }
426
+ } else if (isSet(modelValue)) {
427
+ if (rawElementValue === void 0) {
428
+ vue.warn(
429
+ 'Checkbox bound to a Set model is missing a `value` attribute \u2014 cannot determine which item to add or remove. Add value="..." to each <input type="checkbox">.'
430
+ );
431
+ return;
432
+ }
433
+ const elementValue = applyElementCoerce(rawElementValue, value);
434
+ const cloned = new Set(modelValue);
435
+ if (checked) {
436
+ cloned.add(elementValue);
437
+ } else {
438
+ cloned.delete(elementValue);
439
+ }
440
+ assign?.(cloned);
441
+ } else {
442
+ assign?.(getCheckboxValue(el, checked));
443
+ }
444
+ if (isRegisterValue(value) && isDefaultAssigner(el[assignKey])) {
445
+ setChecked(el, value);
446
+ el._lastAppliedModel = value.innerRef.value;
447
+ }
448
+ });
449
+ },
450
+ // set initial checked on mount to wait for true-value/false-value
451
+ mounted(el, { value }) {
452
+ setChecked(el, value);
453
+ if (isRegisterValue(value)) el._lastAppliedModel = value.innerRef.value;
454
+ },
455
+ // Skip the DOM sync when the model is identity-unchanged from the
456
+ // last application. Pre-fix the scalar branch in `setChecked`
457
+ // gated on `originalValue === oldValue`, comparing a primitive
458
+ // scalar against the wrapper RegisterValue object — always !==,
459
+ // so the guard was a silent no-op. Array / Set branches lacked
460
+ // any guard. The per-render re-apply mirrors the just-fixed
461
+ // `vRegisterSelect` shape: a sibling's reactive write triggers
462
+ // `beforeUpdate` mid-click, `setChecked` re-applies the prior
463
+ // model state, and the in-flight user toggle is clobbered before
464
+ // the browser fires `change`. Identity comparison on
465
+ // `innerRef.value` is sound for the same reason as multi-select —
466
+ // every form write produces a fresh value at the path (new
467
+ // primitives; new array/Set references along the spine), so
468
+ // reference equality tracks "did the model move" exactly.
469
+ beforeUpdate(el, binding, vnode) {
470
+ setAssignFunction(el, vnode, binding.value);
471
+ if (!isRegisterValue(binding.value)) return;
472
+ const currentModel = binding.value.innerRef.value;
473
+ if (el._lastAppliedModel === currentModel) return;
474
+ setChecked(el, binding.value);
475
+ el._lastAppliedModel = currentModel;
476
+ }
477
+ };
478
+ function setChecked(el, value) {
479
+ if (!isRegisterValue(value)) return;
480
+ const originalValue = value.innerRef.value;
481
+ let checked;
482
+ if (isArray(originalValue)) {
483
+ checked = looseIndexOf(originalValue, applyElementCoerce(getValue(el), value)) > -1;
484
+ } else if (isSet(originalValue)) {
485
+ checked = originalValue.has(applyElementCoerce(getValue(el), value));
486
+ } else {
487
+ const trueValueCoerced = applyCoerce(getCheckboxValue(el, true), value);
488
+ checked = looseEqual(originalValue, trueValueCoerced);
489
+ }
490
+ if (el.checked !== checked) {
491
+ el.checked = checked;
492
+ }
493
+ }
494
+ const vRegisterRadio = {
495
+ created(el, { value }, vnode) {
496
+ if (!isRegisterValue(value)) return;
497
+ value.registerElement(el);
498
+ setAssignFunction(el, vnode, value);
499
+ addEventListener(el, "change", () => {
500
+ if (shouldBailListener(el)) return;
501
+ el[assignKey]?.(getValue(el));
502
+ if (isRegisterValue(value) && isDefaultAssigner(el[assignKey])) {
503
+ const currentModel = value.innerRef.value;
504
+ const target = looseEqual(currentModel, applyCoerce(getValue(el), value));
505
+ if (el.checked !== target) el.checked = target;
506
+ el._lastAppliedModel = currentModel;
507
+ }
508
+ });
509
+ },
510
+ // Initial checked-state sync runs in `mounted`, NOT `created` —
511
+ // Vue's directive lifecycle fires `created` BEFORE the element's
512
+ // attributes are patched (`type`, `value`, `_value` etc. aren't on
513
+ // the element yet), so `getValue(el)` would return `undefined` and
514
+ // every radio in a group would mount unchecked regardless of the
515
+ // model. Checkbox already uses `mounted: setChecked` for the same
516
+ // reason.
517
+ mounted(el, { value }) {
518
+ if (!isRegisterValue(value)) return;
519
+ el.checked = looseEqual(value.innerRef.value, applyCoerce(getValue(el), value));
520
+ el._lastAppliedModel = value.innerRef.value;
521
+ },
522
+ // Skip the DOM sync when the model is identity-unchanged from the
523
+ // last application. Pre-fix the guard read `value.innerRef.value
524
+ // !== oldValue`, comparing a primitive scalar against the previous
525
+ // binding's wrapper RegisterValue object — always !==, so the
526
+ // guard was a silent no-op and `el.checked = …` re-applied on
527
+ // every parent re-render. Same shape as the just-fixed
528
+ // `vRegisterSelect` and `setChecked` bugs: a sibling's reactive
529
+ // write triggers `beforeUpdate` mid-click and writes back the
530
+ // prior model state, clobbering the in-flight selection.
531
+ beforeUpdate(el, { value }, vnode) {
532
+ if (!isRegisterValue(value)) return;
533
+ setAssignFunction(el, vnode, value);
534
+ const currentModel = value.innerRef.value;
535
+ if (el._lastAppliedModel === currentModel) return;
536
+ el.checked = looseEqual(currentModel, applyCoerce(getValue(el), value));
537
+ el._lastAppliedModel = currentModel;
538
+ }
539
+ };
540
+ const vRegisterSelect = {
541
+ // <select multiple> value need to be deep traversed
542
+ deep: true,
543
+ created(el, { value, modifiers: { number } }, vnode) {
544
+ if (!isRegisterValue(value)) return;
545
+ value.registerElement(el);
546
+ const isSetModel = isSet(value.innerRef.value);
547
+ addEventListener(el, "change", () => {
548
+ if (shouldBailListener(el)) return;
549
+ const selectedVal = Array.prototype.filter.call(el.options, (o) => o.selected).map((o) => number === true ? looseToNumber(getValue(o)) : getValue(o));
550
+ const wrote = el[assignKey]?.(
551
+ el.multiple ? isSetModel ? new Set(selectedVal) : selectedVal : selectedVal[0]
552
+ );
553
+ if (wrote !== false) {
554
+ el._assigning = true;
555
+ void vue.nextTick(() => {
556
+ el._assigning = false;
557
+ });
558
+ }
559
+ if (isRegisterValue(value) && isDefaultAssigner(el[assignKey])) {
560
+ setSelected(el, value);
561
+ el._lastAppliedModel = value.innerRef.value;
562
+ }
563
+ });
564
+ setAssignFunction(el, vnode, value);
565
+ },
566
+ // set value in mounted & updated because <select> relies on its children
567
+ // <option>s.
568
+ mounted(el, { value }) {
569
+ setSelected(el, value);
570
+ if (isRegisterValue(value)) el._lastAppliedModel = value.innerRef.value;
571
+ },
572
+ beforeUpdate(el, binding, vnode) {
573
+ setAssignFunction(el, vnode, binding.value);
574
+ },
575
+ // Skip the DOM sync when the model is identity-unchanged from the
576
+ // last application. Parent re-renders fire `updated` whether or not
577
+ // the bound model actually moved (a typed character in a sibling,
578
+ // an async-validation tick, any reactive read elsewhere on the
579
+ // page). Without this guard, every such render unconditionally re-
580
+ // applies `setSelected` against the prior model, which on a
581
+ // `<select multiple>` clobbers any in-progress user selection
582
+ // between mousedown and the browser's change-event decision — the
583
+ // browser then sees no net change, never fires `change`, and the
584
+ // model never updates. Identity comparison is sound: every form
585
+ // write produces a new array/Set reference at the path (the diff-
586
+ // apply replacement of `form.value` rolls forward fresh structures
587
+ // along the spine), so reference equality on `innerRef.value`
588
+ // tracks "did the model move" exactly. The `_assigning` gate stays
589
+ // — it short-circuits the immediate post-write render where the
590
+ // DOM is already in sync from the user's click.
591
+ updated(el, { value }) {
592
+ if (el._assigning === true) return;
593
+ if (!isRegisterValue(value)) return;
594
+ const currentModel = value.innerRef.value;
595
+ if (el._lastAppliedModel === currentModel) return;
596
+ setSelected(el, value);
597
+ el._lastAppliedModel = currentModel;
598
+ }
599
+ };
600
+ function setSelected(el, value) {
601
+ if (!isRegisterValue(value)) return;
602
+ const externalValue = value.innerRef.value;
603
+ const isMultiple = el.multiple;
604
+ const isArrayValue = isArray(externalValue);
605
+ if (isMultiple && !isArrayValue && !isSet(externalValue)) {
606
+ if (sensitiveNames.__DEV__) {
607
+ vue.warn(
608
+ `<select multiple v-register> expected an Array or Set, got ${Object.prototype.toString.call(externalValue).slice(8, -1)}. Bind to a list-typed schema (e.g. z.array(z.string()) or z.set(z.string())).`
609
+ );
610
+ }
611
+ return;
612
+ }
613
+ if (!isMultiple && (isArrayValue || isSet(externalValue))) {
614
+ if (sensitiveNames.__DEV__) {
615
+ vue.warn(
616
+ `<select v-register> (no \`multiple\` attribute) expected a scalar value for its binding, but got ${Object.prototype.toString.call(externalValue).slice(8, -1)}. Add the \`multiple\` attribute to bind to a list, or use a scalar schema (e.g. \`z.string()\`) for a single-select binding.`
617
+ );
618
+ }
619
+ return;
620
+ }
621
+ if (isMultiple) {
622
+ const stringifiedMembers = /* @__PURE__ */ new Set();
623
+ const iter = isArrayValue ? externalValue : externalValue;
624
+ for (const v of iter) stringifiedMembers.add(String(v));
625
+ for (let i = 0, l = el.options.length; i < l; i++) {
626
+ const option = el.options[i];
627
+ if (!option) continue;
628
+ const optionValue = applyElementCoerce(getValue(option), value);
629
+ const optionType = typeof optionValue;
630
+ if (optionType === "string" || optionType === "number") {
631
+ option.selected = stringifiedMembers.has(String(optionValue));
632
+ } else if (optionType === "boolean") {
633
+ option.selected = stringifiedMembers.has(String(optionValue));
634
+ } else if (isArrayValue) {
635
+ option.selected = looseIndexOf(externalValue, optionValue) > -1;
636
+ } else {
637
+ option.selected = externalValue.has(optionValue);
638
+ }
639
+ }
640
+ return;
641
+ }
642
+ for (let i = 0, l = el.options.length; i < l; i++) {
643
+ const option = el.options[i];
644
+ if (!option) continue;
645
+ if (looseEqual(applyCoerce(getValue(option), value), externalValue)) {
646
+ if (el.selectedIndex !== i) el.selectedIndex = i;
647
+ return;
648
+ }
649
+ }
650
+ if (el.selectedIndex !== -1) el.selectedIndex = -1;
651
+ }
652
+ function getValue(el, explicitRequired = false) {
653
+ if ("_value" in el) return el._value;
654
+ if (explicitRequired && !el.hasAttribute("value")) return void 0;
655
+ return el.value;
656
+ }
657
+ function getCheckboxValue(el, checked) {
658
+ const key = checked ? "_trueValue" : "_falseValue";
659
+ return key in el ? el[key] : checked;
660
+ }
661
+ const SUPPORTED_TAGS = /* @__PURE__ */ new Set(["INPUT", "TEXTAREA", "SELECT"]);
662
+ const warnedUnsupportedElements = sensitiveNames.__DEV__ ? /* @__PURE__ */ new WeakSet() : null;
663
+ const vRegisterDynamic = {
664
+ created(el, binding, vnode) {
665
+ syncPersistOptIn(el, binding.value, void 0);
666
+ callModelHook(el, binding, vnode, null, "created");
667
+ if (sensitiveNames.__DEV__ && warnedUnsupportedElements !== null && !SUPPORTED_TAGS.has(el.tagName) && !warnedUnsupportedElements.has(el)) {
668
+ void vue.nextTick(() => {
669
+ if (warnedUnsupportedElements.has(el)) return;
670
+ const hasMarker = el[sensitiveNames.REGISTER_OWNER_MARKER] === true;
671
+ const hasUserAssigner = !isDefaultAssigner(
672
+ el[assignKey]
673
+ );
674
+ if (hasMarker || hasUserAssigner) return;
675
+ warnedUnsupportedElements.add(el);
676
+ vue.warn(
677
+ `[attaform] v-register on <${el.tagName.toLowerCase()}> is a no-op \u2014 non-input roots aren't bound to text-input semantics. For custom components: call \`useRegister()\` in the child's setup and re-bind v-register to an inner native element. Lower-level: install a custom assigner via the \`assignKey\` symbol on the element.`
678
+ );
679
+ });
680
+ }
681
+ },
682
+ mounted(el, binding, vnode) {
683
+ callModelHook(el, binding, vnode, null, "mounted");
684
+ },
685
+ beforeUpdate(el, binding, vnode, prevVNode) {
686
+ syncPersistOptIn(el, binding.value, binding.oldValue);
687
+ syncElementRegistration(el, binding.value, binding.oldValue);
688
+ callModelHook(el, binding, vnode, prevVNode, "beforeUpdate");
689
+ },
690
+ updated(el, binding, vnode, prevVNode) {
691
+ callModelHook(el, binding, vnode, prevVNode, "updated");
692
+ },
693
+ beforeUnmount(el, { value }) {
694
+ removeTrackedListeners(el);
695
+ if (isRegisterValue(value)) {
696
+ value.persistOptIns.removeAllFor(sensitiveNames.getOrAssignElementId(el));
697
+ }
698
+ if (!isRegisterValue(value)) return;
699
+ value.deregisterElement(el);
700
+ delete el.composing;
701
+ delete el._assigning;
702
+ delete el[assignKey];
703
+ }
704
+ };
705
+ const vRegisterFileNoop = {
706
+ created(el, { value }) {
707
+ if (!isRegisterValue(value)) return;
708
+ value.registerElement(el);
709
+ if (sensitiveNames.__DEV__) {
710
+ vue.warn(
711
+ '[attaform] v-register on <input type="file"> is not supported. Handle uploads with a manual @change listener.'
712
+ );
713
+ }
714
+ },
715
+ beforeUnmount(el, { value }) {
716
+ removeTrackedListeners(el);
717
+ if (!isRegisterValue(value)) return;
718
+ value.deregisterElement(el);
719
+ }
720
+ };
721
+ function resolveDynamicModel(tagName, type) {
722
+ if (tagName === "SELECT") return vRegisterSelect;
723
+ if (tagName === "TEXTAREA") return vRegisterText;
724
+ if (typeof type !== "string") return vRegisterText;
725
+ if (type === "file") return vRegisterFileNoop;
726
+ if (type === "checkbox") return vRegisterCheckbox;
727
+ if (type === "radio") return vRegisterRadio;
728
+ return vRegisterText;
729
+ }
730
+ function callModelHook(el, binding, vnode, prevVNode, hook) {
731
+ const modelToUse = resolveDynamicModel(el.tagName, vnode.props?.["type"]);
732
+ const fn = modelToUse[hook];
733
+ fn?.(el, binding, vnode, prevVNode);
734
+ }
735
+ const vRegister = vRegisterDynamic;
736
+
737
+ function createAttaform(options = {}) {
738
+ const plugin = {
739
+ install(app) {
740
+ if (app._attaform !== void 0) {
741
+ if (sensitiveNames.__DEV__) {
742
+ console.warn(
743
+ "[attaform] createAttaform() install was called twice on the same app; the second call is a no-op. Likely cause: registering the plugin via both the Nuxt module AND a manual `app.use(...)`."
744
+ );
745
+ }
746
+ return;
747
+ }
748
+ const registry = sensitiveNames.createRegistry(options);
749
+ sensitiveNames.attachRegistryToApp(app, registry);
750
+ app.directive("register", vRegister);
751
+ if (options.devtools !== false && !registry.isSSR) {
752
+ void (async () => {
753
+ try {
754
+ const { setupAttaformDevtools } = await import('../chunks/devtools.cjs');
755
+ await setupAttaformDevtools(app, registry);
756
+ } catch {
757
+ }
758
+ })();
759
+ }
760
+ }
761
+ };
762
+ return plugin;
763
+ }
764
+
765
+ function renderAttaformState(app) {
766
+ const registry = sensitiveNames.getRegistryFromApp(app);
767
+ const forms = [];
768
+ for (const [key, state] of registry.forms) {
769
+ const transientList = Array.from(state.blankPaths);
770
+ forms.push([
771
+ key,
772
+ {
773
+ form: state.form.value,
774
+ schemaErrors: Array.from(state.schemaErrors.entries()),
775
+ userErrors: Array.from(state.userErrors.entries()),
776
+ fields: Array.from(state.fields.entries()),
777
+ ...transientList.length > 0 ? { blankPaths: transientList } : {}
778
+ }
779
+ ]);
780
+ }
781
+ return { forms };
782
+ }
783
+ function hydrateAttaformState(app, payload) {
784
+ const registry = sensitiveNames.getRegistryFromApp(app);
785
+ for (const [key, data] of payload.forms) {
786
+ registry.pendingHydration.set(key, data);
787
+ }
788
+ }
789
+
790
+ exports.assignKey = assignKey;
791
+ exports.createAttaform = createAttaform;
792
+ exports.hydrateAttaformState = hydrateAttaformState;
793
+ exports.isRegisterValue = isRegisterValue;
794
+ exports.renderAttaformState = renderAttaformState;
795
+ exports.vRegister = vRegister;
796
+ //# sourceMappingURL=attaform.CRgix6_n.cjs.map