attaform 0.19.0 → 0.20.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 (110) hide show
  1. package/dist/chunks/devtools.cjs +1 -1
  2. package/dist/chunks/devtools.mjs +1 -1
  3. package/dist/chunks/indexeddb.cjs +1 -1
  4. package/dist/chunks/indexeddb.mjs +1 -1
  5. package/dist/chunks/local-storage.cjs +1 -1
  6. package/dist/chunks/local-storage.mjs +1 -1
  7. package/dist/chunks/session-storage.cjs +1 -1
  8. package/dist/chunks/session-storage.mjs +1 -1
  9. package/dist/index.cjs +3 -6
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +14 -40
  12. package/dist/index.d.mts +14 -40
  13. package/dist/index.d.ts +14 -40
  14. package/dist/index.mjs +5 -5
  15. package/dist/nuxt.d.cts +1 -1
  16. package/dist/nuxt.d.mts +1 -1
  17. package/dist/nuxt.d.ts +1 -1
  18. package/dist/runtime/components/AttaformDevtoolsPanel.vue +2 -2
  19. package/dist/runtime/components/DevtoolsValueTree.d.vue.ts +1 -3
  20. package/dist/runtime/components/DevtoolsValueTree.vue.d.ts +1 -3
  21. package/dist/runtime/plugins/attaform.cjs +2 -2
  22. package/dist/runtime/plugins/attaform.mjs +2 -2
  23. package/dist/shared/{attaform.CrpjyXdO.mjs → attaform.BKozEdTr.mjs} +275 -266
  24. package/dist/shared/attaform.BKozEdTr.mjs.map +1 -0
  25. package/dist/shared/{attaform.Bubm_slq.cjs → attaform.BM6YD9kZ.cjs} +212 -269
  26. package/dist/shared/attaform.BM6YD9kZ.cjs.map +1 -0
  27. package/dist/shared/{attaform.CoxJ8Qm8.cjs → attaform.BPxsYtTe.cjs} +2 -26
  28. package/dist/shared/attaform.BPxsYtTe.cjs.map +1 -0
  29. package/dist/shared/{attaform.BqEfHpVB.cjs → attaform.BPy-4qRx.cjs} +275 -268
  30. package/dist/shared/attaform.BPy-4qRx.cjs.map +1 -0
  31. package/dist/shared/attaform.BWgAFnsj.mjs +770 -0
  32. package/dist/shared/attaform.BWgAFnsj.mjs.map +1 -0
  33. package/dist/shared/{attaform.BTpuvGec.d.ts → attaform.Bh3ACtts.d.ts} +109 -101
  34. package/dist/shared/{attaform.CXpzmj38.mjs → attaform.BupwXkj_.mjs} +213 -270
  35. package/dist/shared/attaform.BupwXkj_.mjs.map +1 -0
  36. package/dist/shared/{attaform.JBx8cfMA.cjs → attaform.CIn4bMsD.cjs} +263 -799
  37. package/dist/shared/attaform.CIn4bMsD.cjs.map +1 -0
  38. package/dist/shared/{attaform.BTi-PsHr.mjs → attaform.CKFbKFb6.mjs} +1818 -1472
  39. package/dist/shared/attaform.CKFbKFb6.mjs.map +1 -0
  40. package/dist/shared/{attaform.ePUcKxId.d.cts → attaform.D5-1XGQU.d.cts} +109 -101
  41. package/dist/shared/{attaform.a3uBo-gw.mjs → attaform.DEBvCjeH.mjs} +257 -793
  42. package/dist/shared/attaform.DEBvCjeH.mjs.map +1 -0
  43. package/dist/shared/{attaform.C1msmO2v.cjs → attaform.DL4CQ-oW.cjs} +1823 -1477
  44. package/dist/shared/attaform.DL4CQ-oW.cjs.map +1 -0
  45. package/dist/shared/{attaform.D4I63aBV.d.ts → attaform.DSD85fHb.d.cts} +1 -19
  46. package/dist/shared/{attaform.CBjmobqk.d.cts → attaform.DSD85fHb.d.mts} +1 -19
  47. package/dist/shared/{attaform.DXYHL99q.d.mts → attaform.DSD85fHb.d.ts} +1 -19
  48. package/dist/shared/{attaform.B7rzpK1U.d.cts → attaform.DkA5J8NW.d.cts} +1 -17
  49. package/dist/shared/{attaform.B7rzpK1U.d.mts → attaform.DkA5J8NW.d.mts} +1 -17
  50. package/dist/shared/{attaform.B7rzpK1U.d.ts → attaform.DkA5J8NW.d.ts} +1 -17
  51. package/dist/shared/{attaform.CJ-e9gYI.d.ts → attaform.Dl5kDY-A.d.ts} +1 -1
  52. package/dist/shared/attaform.Dmb6itxC.cjs +781 -0
  53. package/dist/shared/attaform.Dmb6itxC.cjs.map +1 -0
  54. package/dist/shared/{attaform.CRNA0vrd.d.mts → attaform.DoKXru-a.d.mts} +1 -1
  55. package/dist/shared/attaform.DvA-CJJW.mjs +1876 -0
  56. package/dist/shared/attaform.DvA-CJJW.mjs.map +1 -0
  57. package/dist/shared/{attaform.BtBmfLQN.d.mts → attaform.EMzJcQci.d.mts} +109 -101
  58. package/dist/shared/attaform.EZG6fOFb.mjs +35 -0
  59. package/dist/shared/attaform.EZG6fOFb.mjs.map +1 -0
  60. package/dist/shared/{attaform.QvygsFGh.d.cts → attaform.GbDo_lJi.d.cts} +1 -1
  61. package/dist/shared/{attaform.C0uGZQ4M.d.ts → attaform.SfhU0OEY.d.cts} +134 -30
  62. package/dist/shared/{attaform.C0uGZQ4M.d.cts → attaform.SfhU0OEY.d.mts} +134 -30
  63. package/dist/shared/{attaform.C0uGZQ4M.d.mts → attaform.SfhU0OEY.d.ts} +134 -30
  64. package/dist/shared/attaform.jgzuNZVC.cjs +1882 -0
  65. package/dist/shared/attaform.jgzuNZVC.cjs.map +1 -0
  66. package/dist/transforms.cjs +2 -2
  67. package/dist/transforms.d.cts +22 -13
  68. package/dist/transforms.d.mts +22 -13
  69. package/dist/transforms.d.ts +22 -13
  70. package/dist/transforms.mjs +1 -1
  71. package/dist/vite.cjs +8 -7
  72. package/dist/vite.cjs.map +1 -1
  73. package/dist/vite.mjs +8 -7
  74. package/dist/vite.mjs.map +1 -1
  75. package/dist/zod-v3.cjs +3 -3
  76. package/dist/zod-v3.d.cts +32 -6
  77. package/dist/zod-v3.d.mts +32 -6
  78. package/dist/zod-v3.d.ts +32 -6
  79. package/dist/zod-v3.mjs +3 -3
  80. package/dist/zod-v4.cjs +3 -3
  81. package/dist/zod-v4.d.cts +12 -8
  82. package/dist/zod-v4.d.mts +12 -8
  83. package/dist/zod-v4.d.ts +12 -8
  84. package/dist/zod-v4.mjs +3 -3
  85. package/dist/zod.cjs +8 -8
  86. package/dist/zod.cjs.map +1 -1
  87. package/dist/zod.d.cts +6 -6
  88. package/dist/zod.d.mts +6 -6
  89. package/dist/zod.d.ts +6 -6
  90. package/dist/zod.mjs +6 -6
  91. package/package.json +1 -1
  92. package/dist/shared/attaform.BTi-PsHr.mjs.map +0 -1
  93. package/dist/shared/attaform.BqEfHpVB.cjs.map +0 -1
  94. package/dist/shared/attaform.Bubm_slq.cjs.map +0 -1
  95. package/dist/shared/attaform.C1msmO2v.cjs.map +0 -1
  96. package/dist/shared/attaform.C8CyvYa_.cjs +0 -36
  97. package/dist/shared/attaform.C8CyvYa_.cjs.map +0 -1
  98. package/dist/shared/attaform.CXpzmj38.mjs.map +0 -1
  99. package/dist/shared/attaform.Cghpuav8.mjs +0 -57
  100. package/dist/shared/attaform.Cghpuav8.mjs.map +0 -1
  101. package/dist/shared/attaform.CiMqJHDm.mjs +0 -1594
  102. package/dist/shared/attaform.CiMqJHDm.mjs.map +0 -1
  103. package/dist/shared/attaform.CoxJ8Qm8.cjs.map +0 -1
  104. package/dist/shared/attaform.CrpjyXdO.mjs.map +0 -1
  105. package/dist/shared/attaform.D13GMFgK.mjs +0 -32
  106. package/dist/shared/attaform.D13GMFgK.mjs.map +0 -1
  107. package/dist/shared/attaform.JBx8cfMA.cjs.map +0 -1
  108. package/dist/shared/attaform.OznWyOPy.cjs +0 -1600
  109. package/dist/shared/attaform.OznWyOPy.cjs.map +0 -1
  110. package/dist/shared/attaform.a3uBo-gw.mjs.map +0 -1
@@ -1,4 +1,4 @@
1
- import { shallowReactive, getCurrentInstance, inject, shallowRef, onBeforeMount, onBeforeUpdate, onMounted, nextTick, warn, isRef, effectScope, watch } from 'vue';
1
+ import { shallowReactive, getCurrentInstance, inject, shallowRef, onBeforeMount, onBeforeUpdate, onMounted, effectScope, watch, warn, nextTick, isRef } from 'vue';
2
2
 
3
3
  const __DEV__ = typeof process !== "undefined" && process.env["NODE_ENV"] !== "production";
4
4
 
@@ -43,14 +43,6 @@ class ReservedFormKeyError extends AttaformError {
43
43
  );
44
44
  }
45
45
  }
46
- class SensitivePersistFieldError extends AttaformError {
47
- constructor(path) {
48
- const display = Array.isArray(path) ? path.join(".") : String(path);
49
- super(
50
- `[attaform] Refusing to persist "${display}" \u2014 this path matches a sensitive-name pattern (password / cvv / ssn / token / etc.). Storing sensitive data in client-side storage is a compliance risk (HIPAA / PII / PCI-DSS / SOC2). Fix: persist this server-side, OR pass \`acknowledgeSensitive: true\` to register() (or form.persist()) if the client-side persistence is intentional.`
51
- );
52
- }
53
- }
54
46
  class AnonPersistError extends AttaformError {
55
47
  constructor(opts) {
56
48
  super(formatAnonPersistMessage(opts));
@@ -404,6 +396,197 @@ function warnNoParentRV(instance) {
404
396
  );
405
397
  }
406
398
 
399
+ const MANAGED_ARIA_ATTRS = [
400
+ "aria-invalid",
401
+ "aria-busy",
402
+ "aria-required",
403
+ "aria-describedby"
404
+ ];
405
+ const ariaLockKey = Symbol.for("attaform:aria-locks");
406
+ const ariaScopeKey = Symbol.for("attaform:aria-scope");
407
+ const EMPTY_ARIA_LOCKS = /* @__PURE__ */ new Set();
408
+ function mergeAriaLocks(el, vnode) {
409
+ let locks = el[ariaLockKey];
410
+ if (locks === void 0) {
411
+ locks = /* @__PURE__ */ new Set();
412
+ el[ariaLockKey] = locks;
413
+ }
414
+ const props = vnode.props;
415
+ if (props !== null) {
416
+ for (const attr of MANAGED_ARIA_ATTRS) {
417
+ if (attr in props) locks.add(attr);
418
+ }
419
+ }
420
+ return locks;
421
+ }
422
+ function setAriaAttr(el, attr, value) {
423
+ if (value === null) el.removeAttribute(attr);
424
+ else el.setAttribute(attr, value);
425
+ }
426
+ function resolveAriaValue(attr, rv, ds) {
427
+ switch (attr) {
428
+ case "aria-invalid":
429
+ return ds === "error" ? "true" : null;
430
+ case "aria-busy":
431
+ return ds === "pending" ? "true" : null;
432
+ case "aria-required":
433
+ return rv.isRequired === true ? "true" : null;
434
+ case "aria-describedby":
435
+ return ds === "error" && rv.aria?.errorId !== void 0 ? rv.aria.errorId : null;
436
+ default:
437
+ return null;
438
+ }
439
+ }
440
+ function applyAria(el, rv) {
441
+ if (rv.ariaEnabled !== true || rv.ariaDisplayState === void 0) return;
442
+ const locks = el[ariaLockKey] ?? EMPTY_ARIA_LOCKS;
443
+ const ds = rv.ariaDisplayState.value;
444
+ for (const attr of MANAGED_ARIA_ATTRS) {
445
+ if (!locks.has(attr)) setAriaAttr(el, attr, resolveAriaValue(attr, rv, ds));
446
+ }
447
+ }
448
+ function setupAria(el, rv, vnode) {
449
+ if (rv.ariaEnabled !== true || rv.ariaDisplayState === void 0) return;
450
+ mergeAriaLocks(el, vnode);
451
+ applyAria(el, rv);
452
+ const displayState = rv.ariaDisplayState;
453
+ const scope = effectScope(true);
454
+ scope.run(() => {
455
+ watch(displayState, () => applyAria(el, rv), { flush: "post" });
456
+ });
457
+ el[ariaScopeKey] = () => scope.stop();
458
+ }
459
+ function getSSRAriaProps(rv, vnode) {
460
+ if (rv.ariaEnabled !== true || rv.ariaDisplayState === void 0) return void 0;
461
+ const props = vnode?.props ?? null;
462
+ const ds = rv.ariaDisplayState.value;
463
+ const out = {};
464
+ for (const attr of MANAGED_ARIA_ATTRS) {
465
+ if (props !== null && attr in props) continue;
466
+ const value = resolveAriaValue(attr, rv, ds);
467
+ if (value !== null) out[attr] = value;
468
+ }
469
+ return out;
470
+ }
471
+ function teardownAria(el) {
472
+ const stop = el[ariaScopeKey];
473
+ if (stop === void 0) return;
474
+ stop();
475
+ delete el[ariaScopeKey];
476
+ const locks = el[ariaLockKey] ?? EMPTY_ARIA_LOCKS;
477
+ for (const attr of MANAGED_ARIA_ATTRS) {
478
+ if (!locks.has(attr)) el.removeAttribute(attr);
479
+ }
480
+ delete el[ariaLockKey];
481
+ }
482
+
483
+ const listenersKey = Symbol.for("attaform:directive-listeners");
484
+ function addTrackedListener(el, event, handler, options) {
485
+ el.addEventListener(event, handler, options);
486
+ const carrier = el;
487
+ const bag = carrier[listenersKey] ?? [];
488
+ bag.push({ event, handler, options });
489
+ carrier[listenersKey] = bag;
490
+ }
491
+ function removeTrackedListeners(el) {
492
+ const carrier = el;
493
+ const bag = carrier[listenersKey];
494
+ if (bag === void 0) return;
495
+ for (const { event, handler, options } of bag) {
496
+ el.removeEventListener(event, handler, options);
497
+ }
498
+ delete carrier[listenersKey];
499
+ }
500
+ function noteInteraction(value) {
501
+ if (isRegisterValueLike(value)) value.markInteracted();
502
+ }
503
+ function isRegisterValueLike(val) {
504
+ return typeof val === "object" && val !== null && "markInteracted" in val && typeof val.markInteracted === "function";
505
+ }
506
+
507
+ function isBlankFileValue(value) {
508
+ if (value === null || value === void 0) return true;
509
+ if (Array.isArray(value) && value.length === 0) return true;
510
+ if (typeof FileList !== "undefined" && value instanceof FileList && value.length === 0)
511
+ return true;
512
+ return false;
513
+ }
514
+ function readFilesFromInput(el) {
515
+ const files = el.files;
516
+ if (el.multiple) {
517
+ return files === null ? [] : Array.from(files);
518
+ }
519
+ if (files === null || files.length === 0) return null;
520
+ return files.item(0);
521
+ }
522
+ const warnedPersistedFileForms = __DEV__ ? /* @__PURE__ */ new WeakMap() : null;
523
+ function maybeWarnPersistedFile(value) {
524
+ if (!__DEV__ || warnedPersistedFileForms === null) return;
525
+ if (value.persist !== true) return;
526
+ let warnedPaths = warnedPersistedFileForms.get(value.persistOptIns);
527
+ if (warnedPaths === void 0) {
528
+ warnedPaths = /* @__PURE__ */ new Set();
529
+ warnedPersistedFileForms.set(value.persistOptIns, warnedPaths);
530
+ }
531
+ if (warnedPaths.has(value.path)) return;
532
+ warnedPaths.add(value.path);
533
+ warn(
534
+ `[attaform] register('${value.path}', { persist: true }) on <input type="file"> \u2014 files can't ride a refresh (browsers block programmatic writes to <input type="file">), so this path won't be saved. For long-lived flows, upload on selection and persist the resulting URL or ID in a sibling string field.`
535
+ );
536
+ }
537
+ const fileScopeKey = Symbol.for("attaform:file-scope");
538
+ const vRegisterFile = {
539
+ created(el, { value }) {
540
+ if (!isRegisterValue(value)) return;
541
+ const input = el;
542
+ value.registerElement(input);
543
+ maybeWarnPersistedFile(value);
544
+ const currentRaw = value.innerRef.value;
545
+ if (isBlankFileValue(currentRaw)) {
546
+ const blankShape = input.multiple ? [] : null;
547
+ value.setValueWithInternalPath(blankShape, { blank: true });
548
+ }
549
+ addTrackedListener(input, "change", () => {
550
+ noteInteraction(value);
551
+ const next = readFilesFromInput(input);
552
+ const blank = isBlankFileValue(next);
553
+ value.setValueWithInternalPath(next, blank ? { blank: true } : void 0);
554
+ });
555
+ const scope = effectScope(true);
556
+ scope.run(() => {
557
+ watch(
558
+ value.innerRef,
559
+ (next) => {
560
+ if (!isBlankFileValue(next)) return;
561
+ value.setValueWithInternalPath(next, { blank: true });
562
+ if (input.value !== "") input.value = "";
563
+ },
564
+ { flush: "post" }
565
+ );
566
+ });
567
+ input[fileScopeKey] = () => scope.stop();
568
+ },
569
+ beforeUpdate(el, { value }) {
570
+ if (!isRegisterValue(value)) return;
571
+ const input = el;
572
+ const currentRaw = value.innerRef.value;
573
+ if (isBlankFileValue(currentRaw)) {
574
+ value.setValueWithInternalPath(currentRaw, { blank: true });
575
+ if (input.value !== "") input.value = "";
576
+ }
577
+ },
578
+ beforeUnmount(el, { value }) {
579
+ removeTrackedListeners(el);
580
+ const stop = el[fileScopeKey];
581
+ if (stop !== void 0) {
582
+ stop();
583
+ delete el[fileScopeKey];
584
+ }
585
+ if (!isRegisterValue(value)) return;
586
+ value.deregisterElement(el);
587
+ }
588
+ };
589
+
407
590
  const idGenerator = /* @__PURE__ */ (() => {
408
591
  let counter = 0;
409
592
  return () => `el-${++counter}`;
@@ -588,22 +771,81 @@ function createIsSensitivePath(names = DEFAULT_SENSITIVE_NAMES) {
588
771
  return false;
589
772
  };
590
773
  }
591
- const defaultSegmentMatches = createSegmentMatchesSensitive();
592
774
  const defaultIsSensitivePath = createIsSensitivePath();
593
- function segmentMatchesSensitive(segment) {
594
- return defaultSegmentMatches(segment);
595
- }
596
775
  function isSensitivePath(path) {
597
776
  return defaultIsSensitivePath(path);
598
777
  }
599
- function enforceSensitiveCheck(path, acknowledged, isSensitive = defaultIsSensitivePath) {
600
- if (acknowledged) return;
601
- if (!isSensitive(path)) return;
602
- throw new SensitivePersistFieldError(path);
778
+ const warnedSensitivePersist = __DEV__ ? /* @__PURE__ */ new Set() : null;
779
+ function allowSensitivePersist(path, acknowledged, isSensitive = defaultIsSensitivePath) {
780
+ if (acknowledged) return true;
781
+ if (!isSensitive(path)) return true;
782
+ if (warnedSensitivePersist !== null) {
783
+ const display = Array.isArray(path) ? path.join(".") : String(path);
784
+ if (!warnedSensitivePersist.has(display)) {
785
+ warnedSensitivePersist.add(display);
786
+ console.warn(
787
+ `[attaform] Not persisting "${display}" \u2014 it matches a sensitive-name pattern (password / cvv / ssn / token / etc.) and was opted into persistence without \`acknowledgeSensitive: true\`. Storing sensitive data in client-side storage is a compliance risk (PII / PCI-DSS / HIPAA / SOC2). Persist it server-side, or pass \`acknowledgeSensitive: true\` to register() / form.persist() if this is intentional.`
788
+ );
789
+ }
790
+ }
791
+ return false;
603
792
  }
604
793
 
794
+ function syncPersistOptIn(el, value, oldValue, vnodeType) {
795
+ const wasOptedIn = isRegisterValue(oldValue) && oldValue.persist === true;
796
+ const isFileInput = el.tagName === "INPUT" && (vnodeType === "file" || el.type === "file");
797
+ const wantsOptIn = !isFileInput && isRegisterValue(value) && value.persist === true;
798
+ if (!wasOptedIn && !wantsOptIn) return;
799
+ const elementId = getOrAssignElementId(el);
800
+ if (wasOptedIn) {
801
+ const old = oldValue;
802
+ const samePathAndRegistry = wantsOptIn && value.path === old.path && value.persistOptIns === old.persistOptIns;
803
+ if (!samePathAndRegistry) {
804
+ old.persistOptIns.remove(elementId, old.path);
805
+ }
806
+ }
807
+ if (wantsOptIn) {
808
+ const v = value;
809
+ if (allowSensitivePersist(v.path, v.acknowledgeSensitive, v.isSensitivePath)) {
810
+ v.persistOptIns.add(elementId, v.path);
811
+ }
812
+ }
813
+ }
814
+ function syncMultiTabOptOut(value, oldValue) {
815
+ const wasOptedOut = isRegisterValue(oldValue) && oldValue.unmarkNoSync !== void 0;
816
+ const wantsOptOut = isRegisterValue(value) && value.markNoSync !== void 0;
817
+ if (!wasOptedOut && !wantsOptOut) return;
818
+ if (wasOptedOut) {
819
+ const old = oldValue;
820
+ const samePath = wantsOptOut && value.path === old.path;
821
+ if (!samePath) old.unmarkNoSync?.();
822
+ }
823
+ if (wantsOptOut) {
824
+ const v = value;
825
+ const samePathOld = wasOptedOut && oldValue.path === v.path;
826
+ if (!samePathOld) v.markNoSync?.();
827
+ }
828
+ }
829
+ function syncElementRegistration(el, value, oldValue) {
830
+ const wasRegistered = isRegisterValue(oldValue);
831
+ const isRegistered = isRegisterValue(value);
832
+ if (!wasRegistered && !isRegistered) return;
833
+ if (wasRegistered && isRegistered) {
834
+ const old = oldValue;
835
+ const next = value;
836
+ if (old.path === next.path && old.persistOptIns === next.persistOptIns) return;
837
+ }
838
+ if (wasRegistered) {
839
+ oldValue.deregisterElement(el);
840
+ }
841
+ if (isRegistered) {
842
+ value.registerElement(el);
843
+ }
844
+ }
845
+
846
+ const INTERACTIVE_TAG_NAMES = /* @__PURE__ */ new Set(["INPUT", "SELECT", "TEXTAREA"]);
847
+
605
848
  const assignKey = Symbol.for("attaform:assign-key");
606
- const listenersKey = Symbol.for("attaform:directive-listeners");
607
849
  function isRegisterValue(val) {
608
850
  if (typeof val !== "object" || val === null) return false;
609
851
  if (!("innerRef" in val)) return false;
@@ -614,22 +856,6 @@ function isRegisterValue(val) {
614
856
  if (typeof val.setValueWithInternalPath !== "function") return false;
615
857
  return true;
616
858
  }
617
- function addEventListener(el, event, handler, options) {
618
- el.addEventListener(event, handler, options);
619
- const carrier = el;
620
- const bag = carrier[listenersKey] ?? [];
621
- bag.push({ event, handler, options });
622
- carrier[listenersKey] = bag;
623
- }
624
- function removeTrackedListeners(el) {
625
- const carrier = el;
626
- const bag = carrier[listenersKey];
627
- if (bag === void 0) return;
628
- for (const { event, handler, options } of bag) {
629
- el.removeEventListener(event, handler, options);
630
- }
631
- delete carrier[listenersKey];
632
- }
633
859
  function writeLastTypedForm(rv, next) {
634
860
  rv.lastTypedForm.value = next;
635
861
  }
@@ -642,7 +868,7 @@ function isDefaultAssigner(fn) {
642
868
  return typeof fn === "function" && fn[DEFAULT_ASSIGNER_TAG] === true;
643
869
  }
644
870
  function shouldBailListener(el) {
645
- if (SUPPORTED_TAGS.has(el.tagName)) return false;
871
+ if (INTERACTIVE_TAG_NAMES.has(el.tagName)) return false;
646
872
  return isDefaultAssigner(el[assignKey]);
647
873
  }
648
874
  function runTransforms(initial, registerValue) {
@@ -732,56 +958,6 @@ const getModelAssigner = (el, vnode, registerValue) => {
732
958
  defaultAssigner[DEFAULT_ASSIGNER_TAG] = true;
733
959
  return defaultAssigner;
734
960
  };
735
- function syncPersistOptIn(el, value, oldValue, vnodeType) {
736
- const wasOptedIn = isRegisterValue(oldValue) && oldValue.persist === true;
737
- const isFileInput = el.tagName === "INPUT" && (vnodeType === "file" || el.type === "file");
738
- const wantsOptIn = !isFileInput && isRegisterValue(value) && value.persist === true;
739
- if (!wasOptedIn && !wantsOptIn) return;
740
- const elementId = getOrAssignElementId(el);
741
- if (wasOptedIn) {
742
- const old = oldValue;
743
- const samePathAndRegistry = wantsOptIn && value.path === old.path && value.persistOptIns === old.persistOptIns;
744
- if (!samePathAndRegistry) {
745
- old.persistOptIns.remove(elementId, old.path);
746
- }
747
- }
748
- if (wantsOptIn) {
749
- const v = value;
750
- enforceSensitiveCheck(v.path, v.acknowledgeSensitive, v.isSensitivePath);
751
- v.persistOptIns.add(elementId, v.path);
752
- }
753
- }
754
- function syncMultiTabOptOut(value, oldValue) {
755
- const wasOptedOut = isRegisterValue(oldValue) && oldValue.unmarkNoSync !== void 0;
756
- const wantsOptOut = isRegisterValue(value) && value.markNoSync !== void 0;
757
- if (!wasOptedOut && !wantsOptOut) return;
758
- if (wasOptedOut) {
759
- const old = oldValue;
760
- const samePath = wantsOptOut && value.path === old.path;
761
- if (!samePath) old.unmarkNoSync?.();
762
- }
763
- if (wantsOptOut) {
764
- const v = value;
765
- const samePathOld = wasOptedOut && oldValue.path === v.path;
766
- if (!samePathOld) v.markNoSync?.();
767
- }
768
- }
769
- function syncElementRegistration(el, value, oldValue) {
770
- const wasRegistered = isRegisterValue(oldValue);
771
- const isRegistered = isRegisterValue(value);
772
- if (!wasRegistered && !isRegistered) return;
773
- if (wasRegistered && isRegistered) {
774
- const old = oldValue;
775
- const next = value;
776
- if (old.path === next.path && old.persistOptIns === next.persistOptIns) return;
777
- }
778
- if (wasRegistered) {
779
- oldValue.deregisterElement(el);
780
- }
781
- if (isRegistered) {
782
- value.registerElement(el);
783
- }
784
- }
785
961
  function onCompositionStart(e) {
786
962
  const target = e.target;
787
963
  if (!target) return;
@@ -816,9 +992,6 @@ function setAssignFunction(el, vnode, value) {
816
992
  }
817
993
  el[assignKey] = getModelAssigner(el, vnode, value);
818
994
  }
819
- function noteInteraction(value) {
820
- if (isRegisterValue(value)) value.markInteracted();
821
- }
822
995
  const vRegisterText = {
823
996
  created(el, { value, modifiers: { lazy, trim, number } }, vnode) {
824
997
  const castToNumber = number === true || vnode.props?.["type"] === "number";
@@ -826,7 +999,7 @@ const vRegisterText = {
826
999
  value.registerElement(el);
827
1000
  setAssignFunction(el, vnode, value);
828
1001
  }
829
- addEventListener(el, lazy === true ? "change" : "input", (e) => {
1002
+ addTrackedListener(el, lazy === true ? "change" : "input", (e) => {
830
1003
  if (shouldBailListener(el)) return;
831
1004
  const target = e.target;
832
1005
  if (target === null || target.composing) return;
@@ -882,7 +1055,7 @@ const vRegisterText = {
882
1055
  }
883
1056
  });
884
1057
  if (trim === true || castToNumber) {
885
- addEventListener(el, "change", () => {
1058
+ addTrackedListener(el, "change", () => {
886
1059
  if (shouldBailListener(el)) return;
887
1060
  let normalized = el.value;
888
1061
  if (trim === true) normalized = normalized.trim();
@@ -908,12 +1081,12 @@ const vRegisterText = {
908
1081
  });
909
1082
  }
910
1083
  if (lazy !== true) {
911
- addEventListener(el, "compositionstart", onCompositionStart);
912
- addEventListener(el, "compositionend", onCompositionEnd);
913
- addEventListener(el, "change", onCompositionEnd);
1084
+ addTrackedListener(el, "compositionstart", onCompositionStart);
1085
+ addTrackedListener(el, "compositionend", onCompositionEnd);
1086
+ addTrackedListener(el, "change", onCompositionEnd);
914
1087
  }
915
1088
  if (number === true && vnode.props?.["type"] !== "number") {
916
- addEventListener(el, "beforeinput", (e) => {
1089
+ addTrackedListener(el, "beforeinput", (e) => {
917
1090
  const ev = e;
918
1091
  if (ev.inputType !== "insertText" && ev.inputType !== "insertFromPaste" && ev.inputType !== "insertFromDrop") {
919
1092
  return;
@@ -960,7 +1133,7 @@ const vRegisterCheckbox = {
960
1133
  if (!isRegisterValue(value)) return;
961
1134
  value.registerElement(el);
962
1135
  setAssignFunction(el, vnode, value);
963
- addEventListener(el, "change", () => {
1136
+ addTrackedListener(el, "change", () => {
964
1137
  if (shouldBailListener(el)) return;
965
1138
  noteInteraction(value);
966
1139
  const modelValue = value.innerRef.value ?? [];
@@ -1058,7 +1231,7 @@ const vRegisterRadio = {
1058
1231
  if (!isRegisterValue(value)) return;
1059
1232
  value.registerElement(el);
1060
1233
  setAssignFunction(el, vnode, value);
1061
- addEventListener(el, "change", () => {
1234
+ addTrackedListener(el, "change", () => {
1062
1235
  if (shouldBailListener(el)) return;
1063
1236
  noteInteraction(value);
1064
1237
  el[assignKey]?.(getValue(el));
@@ -1107,7 +1280,7 @@ const vRegisterSelect = {
1107
1280
  if (!isRegisterValue(value)) return;
1108
1281
  value.registerElement(el);
1109
1282
  const isSetModel = isSet(value.innerRef.value);
1110
- addEventListener(el, "change", () => {
1283
+ addTrackedListener(el, "change", () => {
1111
1284
  if (shouldBailListener(el)) return;
1112
1285
  noteInteraction(value);
1113
1286
  const selectedVal = Array.prototype.filter.call(el.options, (o) => o.selected).map((o) => number === true ? looseToNumber(getValue(o)) : getValue(o));
@@ -1222,86 +1395,14 @@ function getCheckboxValue(el, checked) {
1222
1395
  const key = checked ? "_trueValue" : "_falseValue";
1223
1396
  return key in el ? el[key] : checked;
1224
1397
  }
1225
- const SUPPORTED_TAGS = /* @__PURE__ */ new Set(["INPUT", "TEXTAREA", "SELECT"]);
1226
1398
  const warnedUnsupportedElements = __DEV__ ? /* @__PURE__ */ new WeakSet() : null;
1227
- const MANAGED_ARIA_ATTRS = [
1228
- "aria-invalid",
1229
- "aria-busy",
1230
- "aria-required",
1231
- "aria-describedby"
1232
- ];
1233
- const ariaLockKey = Symbol.for("attaform:aria-locks");
1234
- const ariaScopeKey = Symbol.for("attaform:aria-scope");
1235
- const EMPTY_ARIA_LOCKS = /* @__PURE__ */ new Set();
1236
- function mergeAriaLocks(el, vnode) {
1237
- let locks = el[ariaLockKey];
1238
- if (locks === void 0) {
1239
- locks = /* @__PURE__ */ new Set();
1240
- el[ariaLockKey] = locks;
1241
- }
1242
- const props = vnode.props;
1243
- if (props !== null) {
1244
- for (const attr of MANAGED_ARIA_ATTRS) {
1245
- if (attr in props) locks.add(attr);
1246
- }
1247
- }
1248
- return locks;
1249
- }
1250
- function setAriaAttr(el, attr, value) {
1251
- if (value === null) el.removeAttribute(attr);
1252
- else el.setAttribute(attr, value);
1253
- }
1254
- function resolveAriaValue(attr, rv, ds) {
1255
- switch (attr) {
1256
- case "aria-invalid":
1257
- return ds === "error" ? "true" : null;
1258
- case "aria-busy":
1259
- return ds === "pending" ? "true" : null;
1260
- case "aria-required":
1261
- return rv.isRequired === true ? "true" : null;
1262
- case "aria-describedby":
1263
- return ds === "error" && rv.aria?.errorId !== void 0 ? rv.aria.errorId : null;
1264
- default:
1265
- return null;
1266
- }
1267
- }
1268
- function applyAria(el, rv) {
1269
- if (rv.ariaEnabled !== true || rv.ariaDisplayState === void 0) return;
1270
- const locks = el[ariaLockKey] ?? EMPTY_ARIA_LOCKS;
1271
- const ds = rv.ariaDisplayState.value;
1272
- for (const attr of MANAGED_ARIA_ATTRS) {
1273
- if (!locks.has(attr)) setAriaAttr(el, attr, resolveAriaValue(attr, rv, ds));
1274
- }
1275
- }
1276
- function setupAria(el, rv, vnode) {
1277
- if (rv.ariaEnabled !== true || rv.ariaDisplayState === void 0) return;
1278
- mergeAriaLocks(el, vnode);
1279
- applyAria(el, rv);
1280
- const displayState = rv.ariaDisplayState;
1281
- const scope = effectScope(true);
1282
- scope.run(() => {
1283
- watch(displayState, () => applyAria(el, rv), { flush: "post" });
1284
- });
1285
- el[ariaScopeKey] = () => scope.stop();
1286
- }
1287
- function teardownAria(el) {
1288
- const stop = el[ariaScopeKey];
1289
- if (stop === void 0) return;
1290
- stop();
1291
- delete el[ariaScopeKey];
1292
- const locks = el[ariaLockKey] ?? EMPTY_ARIA_LOCKS;
1293
- for (const attr of MANAGED_ARIA_ATTRS) {
1294
- if (!locks.has(attr)) el.removeAttribute(attr);
1295
- }
1296
- delete el[ariaLockKey];
1297
- }
1298
1399
  const vRegisterDynamic = {
1299
1400
  created(el, binding, vnode) {
1300
1401
  syncPersistOptIn(el, binding.value, void 0, vnode.props?.["type"]);
1301
1402
  syncMultiTabOptOut(binding.value, void 0);
1302
1403
  callModelHook(el, binding, vnode, null, "created");
1303
1404
  if (isRegisterValue(binding.value)) setupAria(el, binding.value, vnode);
1304
- if (__DEV__ && warnedUnsupportedElements !== null && !SUPPORTED_TAGS.has(el.tagName) && !warnedUnsupportedElements.has(el)) {
1405
+ if (__DEV__ && warnedUnsupportedElements !== null && !INTERACTIVE_TAG_NAMES.has(el.tagName) && !warnedUnsupportedElements.has(el)) {
1305
1406
  void nextTick(() => {
1306
1407
  if (warnedUnsupportedElements.has(el)) return;
1307
1408
  const hasMarker = el[REGISTER_OWNER_MARKER] === true;
@@ -1365,100 +1466,8 @@ const vRegisterDynamic = {
1365
1466
  // describedby matches the client after hydration.
1366
1467
  getSSRProps(binding, vnode) {
1367
1468
  const rv = binding.value;
1368
- if (!isRegisterValue(rv) || rv.ariaEnabled !== true || rv.ariaDisplayState === void 0) {
1369
- return void 0;
1370
- }
1371
- const props = vnode?.props ?? null;
1372
- const ds = rv.ariaDisplayState.value;
1373
- const out = {};
1374
- for (const attr of MANAGED_ARIA_ATTRS) {
1375
- if (props !== null && attr in props) continue;
1376
- const value = resolveAriaValue(attr, rv, ds);
1377
- if (value !== null) out[attr] = value;
1378
- }
1379
- return out;
1380
- }
1381
- };
1382
- function isBlankFileValue(value) {
1383
- if (value === null || value === void 0) return true;
1384
- if (Array.isArray(value) && value.length === 0) return true;
1385
- if (typeof FileList !== "undefined" && value instanceof FileList && value.length === 0)
1386
- return true;
1387
- return false;
1388
- }
1389
- function readFilesFromInput(el) {
1390
- const files = el.files;
1391
- if (el.multiple) {
1392
- return files === null ? [] : Array.from(files);
1393
- }
1394
- if (files === null || files.length === 0) return null;
1395
- return files.item(0);
1396
- }
1397
- const warnedPersistedFileForms = __DEV__ ? /* @__PURE__ */ new WeakMap() : null;
1398
- function maybeWarnPersistedFile(value) {
1399
- if (!__DEV__ || warnedPersistedFileForms === null) return;
1400
- if (value.persist !== true) return;
1401
- let warnedPaths = warnedPersistedFileForms.get(value.persistOptIns);
1402
- if (warnedPaths === void 0) {
1403
- warnedPaths = /* @__PURE__ */ new Set();
1404
- warnedPersistedFileForms.set(value.persistOptIns, warnedPaths);
1405
- }
1406
- if (warnedPaths.has(value.path)) return;
1407
- warnedPaths.add(value.path);
1408
- warn(
1409
- `[attaform] register('${value.path}', { persist: true }) on <input type="file"> \u2014 files can't ride a refresh (browsers block programmatic writes to <input type="file">), so this path won't be saved. For long-lived flows, upload on selection and persist the resulting URL or ID in a sibling string field.`
1410
- );
1411
- }
1412
- const fileScopeKey = Symbol.for("attaform:file-scope");
1413
- const vRegisterFile = {
1414
- created(el, { value }) {
1415
- if (!isRegisterValue(value)) return;
1416
- const input = el;
1417
- value.registerElement(input);
1418
- maybeWarnPersistedFile(value);
1419
- const currentRaw = value.innerRef.value;
1420
- if (isBlankFileValue(currentRaw)) {
1421
- const blankShape = input.multiple ? [] : null;
1422
- value.setValueWithInternalPath(blankShape, { blank: true });
1423
- }
1424
- addEventListener(input, "change", () => {
1425
- noteInteraction(value);
1426
- const next = readFilesFromInput(input);
1427
- const blank = isBlankFileValue(next);
1428
- value.setValueWithInternalPath(next, blank ? { blank: true } : void 0);
1429
- });
1430
- const scope = effectScope(true);
1431
- scope.run(() => {
1432
- watch(
1433
- value.innerRef,
1434
- (next) => {
1435
- if (!isBlankFileValue(next)) return;
1436
- value.setValueWithInternalPath(next, { blank: true });
1437
- if (input.value !== "") input.value = "";
1438
- },
1439
- { flush: "post" }
1440
- );
1441
- });
1442
- input[fileScopeKey] = () => scope.stop();
1443
- },
1444
- beforeUpdate(el, { value }) {
1445
- if (!isRegisterValue(value)) return;
1446
- const input = el;
1447
- const currentRaw = value.innerRef.value;
1448
- if (isBlankFileValue(currentRaw)) {
1449
- value.setValueWithInternalPath(currentRaw, { blank: true });
1450
- if (input.value !== "") input.value = "";
1451
- }
1452
- },
1453
- beforeUnmount(el, { value }) {
1454
- removeTrackedListeners(el);
1455
- const stop = el[fileScopeKey];
1456
- if (stop !== void 0) {
1457
- stop();
1458
- delete el[fileScopeKey];
1459
- }
1460
- if (!isRegisterValue(value)) return;
1461
- value.deregisterElement(el);
1469
+ if (!isRegisterValue(rv)) return void 0;
1470
+ return getSSRAriaProps(rv, vnode ?? null);
1462
1471
  }
1463
1472
  };
1464
1473
  function resolveDynamicModel(tagName, type) {
@@ -1622,5 +1631,5 @@ function isPathPrefix(prefix, path) {
1622
1631
  return true;
1623
1632
  }
1624
1633
 
1625
- export { AnonPersistError as A, kFormInstanceId as B, parseDottedPath as C, DEFAULT_SENSITIVE_NAMES as D, pathKeyToDotted as E, FORM_ERRORS_PATH as F, segmentMatchesSensitive as G, segmentsForPathKey as H, InvalidPathError as I, useRegister as J, useRegistry as K, vRegister as L, OutsideSetupError as O, ROOT_PATH as R, SensitivePersistFieldError as S, __DEV__ as _, AttaformError as a, FORM_ERRORS_PATH_KEY as b, InvalidUseFormConfigError as c, ROOT_PATH_KEY as d, RegistryNotInstalledError as e, ReservedFormKeyError as f, SubmitErrorHandlerError as g, assignKey as h, canonicalizePath as i, captureUserCallSite as j, coerceToPathKey as k, createAttaform as l, createIsSensitivePath as m, createPersistOptInRegistry as n, createRegistry as o, createSegmentMatchesSensitive as p, enforceSensitiveCheck as q, ensureAttaformInstalled as r, getRegistryFromApp as s, isPathPrefix as t, isRegisterValue as u, isSensitivePath as v, kAttaformAncestorWizard as w, kAttaformRegistry as x, kAttaformWizardActiveStepResolver as y, kFormContext as z };
1626
- //# sourceMappingURL=attaform.CrpjyXdO.mjs.map
1634
+ export { AnonPersistError as A, parseDottedPath as B, pathKeyToDotted as C, DEFAULT_SENSITIVE_NAMES as D, segmentsForPathKey as E, FORM_ERRORS_PATH as F, useRegister as G, useRegistry as H, INTERACTIVE_TAG_NAMES as I, vRegister as J, OutsideSetupError as O, ROOT_PATH as R, SubmitErrorHandlerError as S, __DEV__ as _, AttaformError as a, FORM_ERRORS_PATH_KEY as b, InvalidPathError as c, InvalidUseFormConfigError as d, ROOT_PATH_KEY as e, RegistryNotInstalledError as f, ReservedFormKeyError as g, allowSensitivePersist as h, assignKey as i, canonicalizePath as j, captureUserCallSite as k, coerceToPathKey as l, createAttaform as m, createIsSensitivePath as n, createPersistOptInRegistry as o, createRegistry as p, ensureAttaformInstalled as q, getRegistryFromApp as r, isPathPrefix as s, isRegisterValue as t, isSensitivePath as u, kAttaformAncestorWizard as v, kAttaformRegistry as w, kAttaformWizardActiveStepResolver as x, kFormContext as y, kFormInstanceId as z };
1635
+ //# sourceMappingURL=attaform.BKozEdTr.mjs.map