@getforma/core 1.0.10 → 1.2.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 (55) hide show
  1. package/dist/{chunk-T33QUD2Y.cjs → chunk-E3FV2VSU.cjs} +43 -43
  2. package/dist/{chunk-T33QUD2Y.cjs.map → chunk-E3FV2VSU.cjs.map} +1 -1
  3. package/dist/chunk-ETPJTPYD.js +103 -0
  4. package/dist/chunk-ETPJTPYD.js.map +1 -0
  5. package/dist/chunk-H7MDUHS5.cjs +110 -0
  6. package/dist/chunk-H7MDUHS5.cjs.map +1 -0
  7. package/dist/{chunk-6FW5E54W.cjs → chunk-KUXNZ5MG.cjs} +127 -103
  8. package/dist/chunk-KUXNZ5MG.cjs.map +1 -0
  9. package/dist/{chunk-3G7ET4O5.js → chunk-Y3A2EVVS.js} +121 -94
  10. package/dist/chunk-Y3A2EVVS.js.map +1 -0
  11. package/dist/{chunk-AFRFF7XL.js → chunk-YRNYOZF3.js} +4 -4
  12. package/dist/{chunk-AFRFF7XL.js.map → chunk-YRNYOZF3.js.map} +1 -1
  13. package/dist/forma-runtime-csp.js +52 -4
  14. package/dist/forma-runtime.js +98 -10
  15. package/dist/formajs-runtime-hardened.global.js +52 -4
  16. package/dist/formajs-runtime-hardened.global.js.map +1 -1
  17. package/dist/formajs-runtime.global.js +98 -10
  18. package/dist/formajs-runtime.global.js.map +1 -1
  19. package/dist/formajs.global.js +368 -147
  20. package/dist/formajs.global.js.map +1 -1
  21. package/dist/http.cjs +11 -11
  22. package/dist/http.js +2 -2
  23. package/dist/index.cjs +262 -141
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +32 -27
  26. package/dist/index.d.ts +32 -27
  27. package/dist/index.js +204 -83
  28. package/dist/index.js.map +1 -1
  29. package/dist/{resource-DeEzxUz6.d.cts → resource-D6HfVgiA.d.cts} +7 -2
  30. package/dist/{resource-BHsgURy0.d.ts → resource-ljs2X5NM.d.ts} +7 -2
  31. package/dist/runtime-hardened.cjs +53 -3
  32. package/dist/runtime-hardened.cjs.map +1 -1
  33. package/dist/runtime-hardened.js +53 -3
  34. package/dist/runtime-hardened.js.map +1 -1
  35. package/dist/runtime.cjs +29 -29
  36. package/dist/runtime.js +3 -3
  37. package/dist/server.cjs +7 -7
  38. package/dist/server.d.cts +2 -2
  39. package/dist/server.d.ts +2 -2
  40. package/dist/server.js +2 -2
  41. package/dist/{signal-C9v4akyJ.d.cts → signal-CRBJYQ6B.d.cts} +0 -8
  42. package/dist/{signal-C9v4akyJ.d.ts → signal-CRBJYQ6B.d.ts} +0 -8
  43. package/dist/tc39-compat.cjs +3 -6
  44. package/dist/tc39-compat.cjs.map +1 -1
  45. package/dist/tc39-compat.d.cts +1 -1
  46. package/dist/tc39-compat.d.ts +1 -1
  47. package/dist/tc39-compat.js +1 -4
  48. package/dist/tc39-compat.js.map +1 -1
  49. package/package.json +1 -1
  50. package/dist/chunk-3G7ET4O5.js.map +0 -1
  51. package/dist/chunk-6FW5E54W.cjs.map +0 -1
  52. package/dist/chunk-HLM5BZZQ.js +0 -35
  53. package/dist/chunk-HLM5BZZQ.js.map +0 -1
  54. package/dist/chunk-QLPCVK7C.cjs +0 -38
  55. package/dist/chunk-QLPCVK7C.cjs.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,19 +1,19 @@
1
1
  'use strict';
2
2
 
3
- var chunkT33QUD2Y_cjs = require('./chunk-T33QUD2Y.cjs');
4
- var chunk6FW5E54W_cjs = require('./chunk-6FW5E54W.cjs');
5
- var chunkQLPCVK7C_cjs = require('./chunk-QLPCVK7C.cjs');
3
+ var chunkE3FV2VSU_cjs = require('./chunk-E3FV2VSU.cjs');
4
+ var chunkKUXNZ5MG_cjs = require('./chunk-KUXNZ5MG.cjs');
5
+ var chunkH7MDUHS5_cjs = require('./chunk-H7MDUHS5.cjs');
6
6
 
7
7
  // src/dom/text.ts
8
- function createText(value) {
9
- if (typeof value === "function") {
8
+ function createText(value2) {
9
+ if (typeof value2 === "function") {
10
10
  const node = new Text("");
11
- chunk6FW5E54W_cjs.internalEffect(() => {
12
- node.data = value();
11
+ chunkKUXNZ5MG_cjs.internalEffect(() => {
12
+ node.data = value2();
13
13
  });
14
14
  return node;
15
15
  }
16
- return new Text(value);
16
+ return new Text(value2);
17
17
  }
18
18
 
19
19
  // src/dom/mount.ts
@@ -24,12 +24,12 @@ function mount(component, container) {
24
24
  }
25
25
  let disposeRoot;
26
26
  if (target.hasAttribute("data-forma-ssr")) {
27
- chunk6FW5E54W_cjs.createUnownedRoot((dispose) => {
27
+ chunkKUXNZ5MG_cjs.createUnownedRoot((dispose) => {
28
28
  disposeRoot = dispose;
29
- chunkT33QUD2Y_cjs.hydrateIsland(component, target);
29
+ chunkE3FV2VSU_cjs.hydrateIsland(component, target);
30
30
  });
31
31
  } else {
32
- const dom = chunk6FW5E54W_cjs.createUnownedRoot((dispose) => {
32
+ const dom = chunkKUXNZ5MG_cjs.createUnownedRoot((dispose) => {
33
33
  disposeRoot = dispose;
34
34
  return component();
35
35
  });
@@ -46,7 +46,7 @@ function mount(component, container) {
46
46
  }
47
47
 
48
48
  // src/dom/switch.ts
49
- function createSwitch(value, cases, fallback) {
49
+ function createSwitch(value2, cases, fallback) {
50
50
  const startMarker = document.createComment("forma-switch");
51
51
  const endMarker = document.createComment("/forma-switch");
52
52
  const fragment2 = document.createDocumentFragment();
@@ -55,8 +55,8 @@ function createSwitch(value, cases, fallback) {
55
55
  const cache2 = /* @__PURE__ */ new Map();
56
56
  let currentNode = null;
57
57
  let currentMatch = UNSET;
58
- const switchDispose = chunk6FW5E54W_cjs.internalEffect(() => {
59
- const val = value();
58
+ const switchDispose = chunkKUXNZ5MG_cjs.internalEffect(() => {
59
+ const val = value2();
60
60
  if (val === currentMatch) return;
61
61
  const DEBUG = typeof globalThis.__FORMA_DEBUG__ !== "undefined";
62
62
  if (DEBUG) console.log("[forma:switch] transition", String(currentMatch), "\u2192", String(val));
@@ -90,9 +90,9 @@ function createSwitch(value, cases, fallback) {
90
90
  let entry = cache2.get(val);
91
91
  if (!entry) {
92
92
  let branchDispose;
93
- const node = chunk6FW5E54W_cjs.createRoot((dispose) => {
93
+ const node = chunkKUXNZ5MG_cjs.createRoot((dispose) => {
94
94
  branchDispose = dispose;
95
- return chunk6FW5E54W_cjs.untrack(() => matchedCase.render());
95
+ return chunkKUXNZ5MG_cjs.untrack(() => matchedCase.render());
96
96
  });
97
97
  entry = { node, dispose: branchDispose };
98
98
  cache2.set(val, entry);
@@ -110,7 +110,7 @@ function createSwitch(value, cases, fallback) {
110
110
  if (DEBUG) console.log("[forma:switch] inserted", currentNode.nodeName, "before end marker");
111
111
  }
112
112
  });
113
- chunk6FW5E54W_cjs.registerDisposer(() => {
113
+ chunkKUXNZ5MG_cjs.registerDisposer(() => {
114
114
  for (const entry of cache2.values()) {
115
115
  entry.dispose();
116
116
  }
@@ -142,7 +142,7 @@ function createPortal(children2, target) {
142
142
  }
143
143
  mountedNode = null;
144
144
  };
145
- chunk6FW5E54W_cjs.createEffect(() => {
145
+ chunkKUXNZ5MG_cjs.createEffect(() => {
146
146
  const node = children2();
147
147
  removeMountedNode();
148
148
  mountedNode = node;
@@ -161,9 +161,9 @@ function createErrorBoundary(tryFn, catchFn) {
161
161
  const fragment2 = document.createDocumentFragment();
162
162
  fragment2.appendChild(startMarker);
163
163
  fragment2.appendChild(endMarker);
164
- const [retryCount, setRetryCount] = chunkQLPCVK7C_cjs.createSignal(0);
164
+ const [retryCount, setRetryCount] = chunkH7MDUHS5_cjs.createSignal(0);
165
165
  let currentNode = null;
166
- chunk6FW5E54W_cjs.internalEffect(() => {
166
+ chunkKUXNZ5MG_cjs.internalEffect(() => {
167
167
  retryCount();
168
168
  const parent2 = startMarker.parentNode;
169
169
  if (!parent2) return;
@@ -191,7 +191,7 @@ function createSuspense(fallback, children2) {
191
191
  const fragment2 = document.createDocumentFragment();
192
192
  fragment2.appendChild(startMarker);
193
193
  fragment2.appendChild(endMarker);
194
- const [pending, setPending] = chunkQLPCVK7C_cjs.createSignal(0);
194
+ const [pending, setPending] = chunkH7MDUHS5_cjs.createSignal(0);
195
195
  let currentNode = null;
196
196
  let resolvedNode = null;
197
197
  let fallbackNode = null;
@@ -203,13 +203,13 @@ function createSuspense(fallback, children2) {
203
203
  setPending((p) => Math.max(0, p - 1));
204
204
  }
205
205
  };
206
- chunk6FW5E54W_cjs.pushSuspenseContext(ctx);
206
+ chunkKUXNZ5MG_cjs.pushSuspenseContext(ctx);
207
207
  try {
208
208
  resolvedNode = children2();
209
209
  } finally {
210
- chunk6FW5E54W_cjs.popSuspenseContext();
210
+ chunkKUXNZ5MG_cjs.popSuspenseContext();
211
211
  }
212
- chunk6FW5E54W_cjs.internalEffect(() => {
212
+ chunkKUXNZ5MG_cjs.internalEffect(() => {
213
213
  const parent2 = startMarker.parentNode;
214
214
  if (!parent2) return;
215
215
  const isPending = pending() > 0;
@@ -276,7 +276,7 @@ function activateIslands(registry) {
276
276
  const componentName = root.getAttribute("data-forma-component");
277
277
  const hydrateFn = registry[componentName];
278
278
  if (!hydrateFn) {
279
- if (chunk6FW5E54W_cjs.__DEV__) console.warn(`[forma] No hydrate function for island "${componentName}" (id=${id})`);
279
+ if (chunkH7MDUHS5_cjs.__DEV__) console.warn(`[forma] No hydrate function for island "${componentName}" (id=${id})`);
280
280
  root.setAttribute("data-forma-status", "error");
281
281
  continue;
282
282
  }
@@ -332,13 +332,13 @@ function hydrateIslandRoot(root, id, componentName, hydrateFn, sharedProps) {
332
332
  const props = loadIslandProps(root, id, sharedProps);
333
333
  root.setAttribute("data-forma-status", "hydrating");
334
334
  let activeRoot = root;
335
- chunk6FW5E54W_cjs.createUnownedRoot((dispose) => {
336
- activeRoot = chunkT33QUD2Y_cjs.hydrateIsland(() => hydrateFn(root, props), root);
335
+ chunkKUXNZ5MG_cjs.createUnownedRoot((dispose) => {
336
+ activeRoot = chunkE3FV2VSU_cjs.hydrateIsland(() => hydrateFn(root, props), root);
337
337
  activeRoot.__formaDispose = dispose;
338
338
  });
339
339
  activeRoot.setAttribute("data-forma-status", "active");
340
340
  } catch (err) {
341
- if (chunk6FW5E54W_cjs.__DEV__) console.error(`[forma] Island "${componentName}" (id=${id}) failed:`, err);
341
+ if (chunkH7MDUHS5_cjs.__DEV__) console.error(`[forma] Island "${componentName}" (id=${id}) failed:`, err);
342
342
  root.setAttribute("data-forma-status", "error");
343
343
  }
344
344
  }
@@ -387,14 +387,14 @@ function defineComponent(setupOrDef) {
387
387
  try {
388
388
  cb();
389
389
  } catch (e) {
390
- chunk6FW5E54W_cjs.reportError(e, "onUnmount");
390
+ chunkH7MDUHS5_cjs.reportError(e, "onUnmount");
391
391
  }
392
392
  }
393
393
  for (const d of ctx.disposers) {
394
394
  try {
395
395
  d();
396
396
  } catch (e) {
397
- chunk6FW5E54W_cjs.reportError(e, "component disposer");
397
+ chunkH7MDUHS5_cjs.reportError(e, "component disposer");
398
398
  }
399
399
  }
400
400
  ctx.disposers.length = 0;
@@ -409,7 +409,7 @@ function defineComponent(setupOrDef) {
409
409
  ctx.unmountCallbacks.push(cleanup2);
410
410
  }
411
411
  } catch (e) {
412
- chunk6FW5E54W_cjs.reportError(e, "onMount");
412
+ chunkH7MDUHS5_cjs.reportError(e, "onMount");
413
413
  }
414
414
  }
415
415
  return dom;
@@ -436,13 +436,13 @@ function createContext(defaultValue) {
436
436
  defaultValue
437
437
  };
438
438
  }
439
- function provide(ctx, value) {
439
+ function provide(ctx, value2) {
440
440
  let stack = contextStacks.get(ctx.id);
441
441
  if (stack === void 0) {
442
442
  stack = [];
443
443
  contextStacks.set(ctx.id, stack);
444
444
  }
445
- stack.push(value);
445
+ stack.push(value2);
446
446
  }
447
447
  function inject(ctx) {
448
448
  const stack = contextStacks.get(ctx.id);
@@ -498,6 +498,19 @@ function deepClone(obj, seen) {
498
498
  function createStore(initial) {
499
499
  const signals = /* @__PURE__ */ new Map();
500
500
  const children2 = /* @__PURE__ */ new Map();
501
+ const arrayVersions = /* @__PURE__ */ new Map();
502
+ function getArrayVersion(path) {
503
+ let p = arrayVersions.get(path);
504
+ if (!p) {
505
+ p = chunkH7MDUHS5_cjs.createSignal(0);
506
+ arrayVersions.set(path, p);
507
+ }
508
+ return p;
509
+ }
510
+ function bumpArrayVersion(path) {
511
+ const p = arrayVersions.get(path);
512
+ if (p) p[1]((n) => n + 1);
513
+ }
501
514
  function registerChild(path) {
502
515
  const lastDot = path.lastIndexOf(".");
503
516
  if (lastDot === -1) return;
@@ -512,7 +525,7 @@ function createStore(initial) {
512
525
  function getSignal(path, initialValue) {
513
526
  let pair = signals.get(path);
514
527
  if (!pair) {
515
- pair = chunkQLPCVK7C_cjs.createSignal(initialValue);
528
+ pair = chunkH7MDUHS5_cjs.createSignal(initialValue);
516
529
  signals.set(path, pair);
517
530
  registerChild(path);
518
531
  }
@@ -529,14 +542,37 @@ function createStore(initial) {
529
542
  }
530
543
  childSet.clear();
531
544
  }
545
+ function lastSegment(path) {
546
+ const d = path.lastIndexOf(".");
547
+ return d === -1 ? path : path.substring(d + 1);
548
+ }
549
+ function setLiteral(pair, v) {
550
+ pair[1](typeof v === "function" ? chunkH7MDUHS5_cjs.value(v) : v);
551
+ }
552
+ function reconcileChildren(parentPath, rawParent) {
553
+ const set = children2.get(parentPath);
554
+ if (!set) return;
555
+ for (const childPath of set) {
556
+ const key = lastSegment(childPath);
557
+ const nv = rawParent[key];
558
+ const pair = signals.get(childPath);
559
+ if (pair) setLiteral(pair, nv);
560
+ if (nv != null && typeof nv === "object") {
561
+ reconcileChildren(childPath, nv);
562
+ } else {
563
+ invalidateChildren(childPath);
564
+ }
565
+ }
566
+ }
532
567
  function wrap(raw, basePath) {
533
568
  if (!shouldWrap(raw)) return raw;
534
- const cached = proxyCache.get(raw);
535
- if (cached) return cached;
569
+ let byPath = proxyCache.get(raw);
570
+ if (byPath) {
571
+ const hit = byPath.get(basePath);
572
+ if (hit) return hit;
573
+ }
536
574
  const isArr = Array.isArray(raw);
537
575
  const basePrefix = basePath ? basePath + "." : "";
538
- let lastKey = "";
539
- let lastSignal;
540
576
  const proxy = new Proxy(raw, {
541
577
  // -------------------------------------------------------------------
542
578
  // GET
@@ -552,17 +588,15 @@ function createStore(initial) {
552
588
  if (isArr && ARRAY_MUTATORS.has(key)) {
553
589
  return (...args) => {
554
590
  let result;
555
- chunk6FW5E54W_cjs.batch(() => {
591
+ chunkKUXNZ5MG_cjs.batch(() => {
556
592
  const rawArgs = args.map(
557
593
  (a) => a != null && typeof a === "object" && a[RAW] ? a[RAW] : a
558
594
  );
559
595
  result = target[key].apply(target, rawArgs);
560
- invalidateChildren(basePath);
561
- const [, setLen] = getSignal(
562
- basePrefix + "length",
563
- target.length
564
- );
565
- setLen(target.length);
596
+ reconcileChildren(basePath, target);
597
+ const lenPair = signals.get(basePrefix + "length");
598
+ if (lenPair) lenPair[1](target.length);
599
+ if (basePath) bumpArrayVersion(basePath);
566
600
  });
567
601
  return result;
568
602
  };
@@ -572,34 +606,32 @@ function createStore(initial) {
572
606
  getter();
573
607
  return target.length;
574
608
  }
575
- const value = Reflect.get(target, prop);
576
- let pair;
577
- if (key === lastKey && lastSignal) {
578
- pair = lastSignal;
579
- } else {
580
- pair = getSignal(childPath, value);
581
- lastKey = key;
582
- lastSignal = pair;
583
- }
609
+ const value2 = Reflect.get(target, prop);
610
+ const pair = getSignal(childPath, value2);
584
611
  pair[0]();
585
- if (shouldWrap(value)) {
586
- return wrap(value, childPath);
612
+ if (Array.isArray(value2)) {
613
+ getArrayVersion(childPath)[0]();
587
614
  }
588
- return value;
615
+ if (shouldWrap(value2)) {
616
+ return wrap(value2, childPath);
617
+ }
618
+ return value2;
589
619
  },
590
620
  // -------------------------------------------------------------------
591
621
  // SET
592
622
  // -------------------------------------------------------------------
593
- set(target, prop, value) {
623
+ set(target, prop, value2) {
594
624
  if (typeof prop === "symbol") {
595
- return Reflect.set(target, prop, value);
625
+ return Reflect.set(target, prop, value2);
596
626
  }
597
627
  const key = String(prop);
598
628
  const childPath = basePrefix + key;
599
- const rawValue = value != null && typeof value === "object" && value[RAW] ? value[RAW] : value;
629
+ const rawValue = value2 != null && typeof value2 === "object" && value2[RAW] ? value2[RAW] : value2;
630
+ const oldRaw = Reflect.get(target, prop);
600
631
  Reflect.set(target, prop, rawValue);
601
- if (rawValue != null && typeof rawValue === "object") {
632
+ if (rawValue != null && typeof rawValue === "object" && oldRaw !== rawValue) {
602
633
  invalidateChildren(childPath);
634
+ evictProxy(oldRaw, childPath);
603
635
  }
604
636
  if (isArr && key !== "length") {
605
637
  const lengthPath = basePrefix + "length";
@@ -608,6 +640,12 @@ function createStore(initial) {
608
640
  lenPair[1](target.length);
609
641
  }
610
642
  }
643
+ if (isArr && key === "length") {
644
+ chunkKUXNZ5MG_cjs.batch(() => {
645
+ reconcileChildren(basePath, target);
646
+ if (basePath) bumpArrayVersion(basePath);
647
+ });
648
+ }
611
649
  const [, setter2] = getSignal(childPath, rawValue);
612
650
  setter2(rawValue);
613
651
  return true;
@@ -646,31 +684,37 @@ function createStore(initial) {
646
684
  }
647
685
  const key = String(prop);
648
686
  const childPath = basePrefix + key;
687
+ const oldRaw = Reflect.get(target, prop);
649
688
  const result = Reflect.deleteProperty(target, prop);
689
+ const delPair = signals.get(childPath);
690
+ if (delPair) delPair[1](void 0);
691
+ evictProxy(oldRaw, childPath);
650
692
  invalidateChildren(childPath);
651
- signals.delete(childPath);
652
- const parentPath = basePath;
653
- if (parentPath !== void 0) {
654
- const parentSet = children2.get(parentPath);
655
- if (parentSet) {
656
- parentSet.delete(childPath);
657
- if (parentSet.size === 0) children2.delete(parentPath);
658
- }
659
- }
660
- children2.delete(childPath);
661
693
  return result;
662
694
  }
663
695
  });
664
- proxyCache.set(raw, proxy);
696
+ if (!byPath) {
697
+ byPath = /* @__PURE__ */ new Map();
698
+ proxyCache.set(raw, byPath);
699
+ }
700
+ byPath.set(basePath, proxy);
665
701
  return proxy;
666
702
  }
703
+ function evictProxy(oldRaw, path) {
704
+ if (oldRaw == null || typeof oldRaw !== "object") return;
705
+ const om = proxyCache.get(oldRaw);
706
+ if (om) {
707
+ om.delete(path);
708
+ if (om.size === 0) proxyCache.delete(oldRaw);
709
+ }
710
+ }
667
711
  const rootProxy = wrap(initial, "");
668
712
  function getCurrentSnapshot() {
669
- return chunk6FW5E54W_cjs.untrack(() => deepClone(initial));
713
+ return chunkKUXNZ5MG_cjs.untrack(() => deepClone(initial));
670
714
  }
671
715
  const setter = (partial) => {
672
716
  const updates = typeof partial === "function" ? partial(getCurrentSnapshot()) : partial;
673
- chunk6FW5E54W_cjs.batch(() => {
717
+ chunkKUXNZ5MG_cjs.batch(() => {
674
718
  for (const key of Object.keys(updates)) {
675
719
  rootProxy[key] = updates[key];
676
720
  }
@@ -680,60 +724,81 @@ function createStore(initial) {
680
724
  }
681
725
 
682
726
  // src/state/history.ts
727
+ function cloneEntry(v, seen) {
728
+ if (v === null || typeof v !== "object") return v;
729
+ const proto = Object.getPrototypeOf(v);
730
+ if (!Array.isArray(v) && proto !== Object.prototype && proto !== null) return v;
731
+ if (!seen) seen = /* @__PURE__ */ new WeakSet();
732
+ if (seen.has(v)) return v;
733
+ seen.add(v);
734
+ if (Array.isArray(v)) return v.map((i) => cloneEntry(i, seen));
735
+ const out = {};
736
+ for (const k of Object.keys(v)) {
737
+ out[k] = cloneEntry(v[k], seen);
738
+ }
739
+ return out;
740
+ }
683
741
  function createHistory(source, options) {
684
742
  const [sourceGet, sourceSet] = source;
685
- const maxLength = options?.maxLength ?? 100;
686
- let _stack = [sourceGet()];
743
+ const maxLength = Math.max(1, options?.maxLength ?? 100);
744
+ let _stack = [cloneEntry(sourceGet())];
687
745
  let _cursor = 0;
688
- const [stackSignal, setStackSignal] = chunkQLPCVK7C_cjs.createSignal([..._stack]);
689
- const [cursorSignal, setCursorSignal] = chunkQLPCVK7C_cjs.createSignal(_cursor);
690
- const [stackLenSignal, setStackLenSignal] = chunkQLPCVK7C_cjs.createSignal(_stack.length);
746
+ const [stackSignal, setStackSignal] = chunkH7MDUHS5_cjs.createSignal([..._stack]);
747
+ const [cursorSignal, setCursorSignal] = chunkH7MDUHS5_cjs.createSignal(_cursor);
748
+ const [stackLenSignal, setStackLenSignal] = chunkH7MDUHS5_cjs.createSignal(_stack.length);
691
749
  function syncSignals() {
692
- chunk6FW5E54W_cjs.batch(() => {
750
+ chunkKUXNZ5MG_cjs.batch(() => {
693
751
  setStackSignal([..._stack]);
694
752
  setCursorSignal(_cursor);
695
753
  setStackLenSignal(_stack.length);
696
754
  });
697
755
  }
698
- let ignoreNext = false;
756
+ const NONE = /* @__PURE__ */ Symbol("none");
757
+ let _expected = NONE;
699
758
  let isFirstRun = true;
700
- chunk6FW5E54W_cjs.internalEffect(() => {
701
- const value = sourceGet();
759
+ const disposeEffect = chunkKUXNZ5MG_cjs.internalEffect(() => {
760
+ const value2 = sourceGet();
702
761
  if (isFirstRun) {
703
762
  isFirstRun = false;
704
763
  return;
705
764
  }
706
- if (ignoreNext) {
707
- ignoreNext = false;
765
+ if (_expected !== NONE && Object.is(value2, _expected)) {
766
+ _expected = NONE;
708
767
  return;
709
768
  }
769
+ _expected = NONE;
710
770
  _stack = _stack.slice(0, _cursor + 1);
711
- _stack.push(value);
771
+ _stack.push(cloneEntry(value2));
712
772
  if (_stack.length > maxLength) {
713
773
  _stack.splice(0, _stack.length - maxLength);
714
774
  }
715
775
  _cursor = _stack.length - 1;
716
776
  syncSignals();
717
777
  });
778
+ const destroy = () => {
779
+ disposeEffect();
780
+ };
718
781
  const canUndo = () => cursorSignal() > 0;
719
782
  const canRedo = () => cursorSignal() < stackLenSignal() - 1;
720
783
  const undo = () => {
721
784
  if (_cursor <= 0) return;
722
785
  _cursor--;
723
- ignoreNext = true;
724
- sourceSet(_stack[_cursor]);
786
+ const restored = cloneEntry(_stack[_cursor]);
787
+ _expected = restored;
788
+ sourceSet(restored);
725
789
  syncSignals();
726
790
  };
727
791
  const redo = () => {
728
792
  if (_cursor >= _stack.length - 1) return;
729
793
  _cursor++;
730
- ignoreNext = true;
731
- sourceSet(_stack[_cursor]);
794
+ const restored = cloneEntry(_stack[_cursor]);
795
+ _expected = restored;
796
+ sourceSet(restored);
732
797
  syncSignals();
733
798
  };
734
799
  const clear = () => {
735
800
  const currentValue = sourceGet();
736
- _stack = [currentValue];
801
+ _stack = [cloneEntry(currentValue)];
737
802
  _cursor = 0;
738
803
  syncSignals();
739
804
  };
@@ -744,35 +809,91 @@ function createHistory(source, options) {
744
809
  canRedo,
745
810
  history: () => stackSignal(),
746
811
  cursor: () => cursorSignal(),
747
- clear
812
+ clear,
813
+ destroy
748
814
  };
749
815
  }
750
816
 
751
817
  // src/state/persist.ts
818
+ var ENVELOPE_TAG = "$forma:v";
752
819
  function persist(source, key, options) {
753
820
  const [sourceGet, sourceSet] = source;
754
821
  const storage = options?.storage ?? globalThis.localStorage;
755
822
  const serialize = options?.serialize ?? JSON.stringify;
756
823
  const deserialize = options?.deserialize ?? JSON.parse;
757
824
  const validate = options?.validate;
758
- try {
759
- const stored = storage.getItem(key);
760
- if (stored !== null) {
761
- const value = deserialize(stored);
762
- if (!validate || validate(value)) {
763
- sourceSet(value);
825
+ const version = options?.version;
826
+ const migrate = options?.migrate;
827
+ const onError2 = options?.onError;
828
+ let writing = false;
829
+ function unwrap(stored) {
830
+ const parsed = deserialize(stored);
831
+ if (parsed != null && typeof parsed === "object" && Object.prototype.hasOwnProperty.call(parsed, ENVELOPE_TAG)) {
832
+ const env = parsed;
833
+ return { value: env.value, version: Number(env[ENVELOPE_TAG]) };
834
+ }
835
+ return { value: parsed, version: 0 };
836
+ }
837
+ function hydrate() {
838
+ let stored;
839
+ try {
840
+ stored = storage.getItem(key);
841
+ } catch (err) {
842
+ onError2?.(err, "hydrate");
843
+ return;
844
+ }
845
+ if (stored === null) return;
846
+ try {
847
+ const { value: raw, version: storedVersion } = unwrap(stored);
848
+ let value2 = raw;
849
+ if (version !== void 0 && storedVersion < version) {
850
+ if (!migrate) return;
851
+ try {
852
+ value2 = migrate(raw, storedVersion);
853
+ } catch (err) {
854
+ onError2?.(err, "migrate");
855
+ return;
856
+ }
764
857
  }
858
+ if (!validate || validate(value2)) {
859
+ writing = true;
860
+ try {
861
+ sourceSet(value2);
862
+ } finally {
863
+ writing = false;
864
+ }
865
+ }
866
+ } catch (err) {
867
+ onError2?.(err, "hydrate");
765
868
  }
766
- } catch {
767
869
  }
768
- chunk6FW5E54W_cjs.internalEffect(() => {
769
- const value = sourceGet();
870
+ hydrate();
871
+ const stopEffect = chunkKUXNZ5MG_cjs.internalEffect(() => {
872
+ const value2 = sourceGet();
873
+ if (writing) return;
770
874
  try {
771
- const serialized = serialize(value);
875
+ const serialized = version !== void 0 ? serialize({ [ENVELOPE_TAG]: version, value: value2 }) : serialize(value2);
772
876
  storage.setItem(key, serialized);
773
- } catch {
877
+ } catch (err) {
878
+ onError2?.(err, err?.name === "QuotaExceededError" ? "write" : "serialize");
774
879
  }
775
880
  });
881
+ const enableSync = options?.syncTabs ?? (typeof window !== "undefined" && storage === globalThis.localStorage);
882
+ let onStorage;
883
+ if (enableSync && typeof window !== "undefined") {
884
+ onStorage = (e) => {
885
+ if (e.storageArea !== storage) return;
886
+ if (e.key !== null && e.key !== key) return;
887
+ hydrate();
888
+ };
889
+ window.addEventListener("storage", onStorage);
890
+ }
891
+ return () => {
892
+ stopEffect();
893
+ if (onStorage && typeof window !== "undefined") {
894
+ window.removeEventListener("storage", onStorage);
895
+ }
896
+ };
776
897
  }
777
898
 
778
899
  // src/events/bus.ts
@@ -919,20 +1040,20 @@ function toggleClass(el, className, force) {
919
1040
  return el.classList.toggle(className, force);
920
1041
  }
921
1042
  function setStyle(el, styles) {
922
- for (const [key, value] of Object.entries(styles)) {
923
- if (value !== void 0) {
924
- el.style[key] = value;
1043
+ for (const [key, value2] of Object.entries(styles)) {
1044
+ if (value2 !== void 0) {
1045
+ el.style[key] = value2;
925
1046
  }
926
1047
  }
927
1048
  }
928
1049
  function setAttr(el, attrs) {
929
- for (const [name, value] of Object.entries(attrs)) {
930
- if (value === false || value === null) {
1050
+ for (const [name, value2] of Object.entries(attrs)) {
1051
+ if (value2 === false || value2 === null) {
931
1052
  el.removeAttribute(name);
932
- } else if (value === true) {
1053
+ } else if (value2 === true) {
933
1054
  el.setAttribute(name, "");
934
1055
  } else {
935
- el.setAttribute(name, value);
1056
+ el.setAttribute(name, value2);
936
1057
  }
937
1058
  }
938
1059
  }
@@ -1023,115 +1144,115 @@ function onMutation(el, handler, options) {
1023
1144
 
1024
1145
  Object.defineProperty(exports, "Fragment", {
1025
1146
  enumerable: true,
1026
- get: function () { return chunkT33QUD2Y_cjs.Fragment; }
1147
+ get: function () { return chunkE3FV2VSU_cjs.Fragment; }
1027
1148
  });
1028
1149
  Object.defineProperty(exports, "cleanup", {
1029
1150
  enumerable: true,
1030
- get: function () { return chunkT33QUD2Y_cjs.cleanup; }
1151
+ get: function () { return chunkE3FV2VSU_cjs.cleanup; }
1031
1152
  });
1032
1153
  Object.defineProperty(exports, "createList", {
1033
1154
  enumerable: true,
1034
- get: function () { return chunkT33QUD2Y_cjs.createList; }
1155
+ get: function () { return chunkE3FV2VSU_cjs.createList; }
1035
1156
  });
1036
1157
  Object.defineProperty(exports, "createShow", {
1037
1158
  enumerable: true,
1038
- get: function () { return chunkT33QUD2Y_cjs.createShow; }
1159
+ get: function () { return chunkE3FV2VSU_cjs.createShow; }
1039
1160
  });
1040
1161
  Object.defineProperty(exports, "fragment", {
1041
1162
  enumerable: true,
1042
- get: function () { return chunkT33QUD2Y_cjs.fragment; }
1163
+ get: function () { return chunkE3FV2VSU_cjs.fragment; }
1043
1164
  });
1044
1165
  Object.defineProperty(exports, "h", {
1045
1166
  enumerable: true,
1046
- get: function () { return chunkT33QUD2Y_cjs.h; }
1167
+ get: function () { return chunkE3FV2VSU_cjs.h; }
1047
1168
  });
1048
1169
  Object.defineProperty(exports, "hydrateIsland", {
1049
1170
  enumerable: true,
1050
- get: function () { return chunkT33QUD2Y_cjs.hydrateIsland; }
1171
+ get: function () { return chunkE3FV2VSU_cjs.hydrateIsland; }
1051
1172
  });
1052
1173
  Object.defineProperty(exports, "reconcileList", {
1053
1174
  enumerable: true,
1054
- get: function () { return chunkT33QUD2Y_cjs.reconcileList; }
1175
+ get: function () { return chunkE3FV2VSU_cjs.reconcileList; }
1055
1176
  });
1056
1177
  Object.defineProperty(exports, "batch", {
1057
1178
  enumerable: true,
1058
- get: function () { return chunk6FW5E54W_cjs.batch; }
1179
+ get: function () { return chunkKUXNZ5MG_cjs.batch; }
1059
1180
  });
1060
1181
  Object.defineProperty(exports, "createEffect", {
1061
1182
  enumerable: true,
1062
- get: function () { return chunk6FW5E54W_cjs.createEffect; }
1183
+ get: function () { return chunkKUXNZ5MG_cjs.createEffect; }
1063
1184
  });
1064
1185
  Object.defineProperty(exports, "createMemo", {
1065
1186
  enumerable: true,
1066
- get: function () { return chunk6FW5E54W_cjs.createMemo; }
1187
+ get: function () { return chunkKUXNZ5MG_cjs.createMemo; }
1067
1188
  });
1068
1189
  Object.defineProperty(exports, "createReducer", {
1069
1190
  enumerable: true,
1070
- get: function () { return chunk6FW5E54W_cjs.createReducer; }
1191
+ get: function () { return chunkKUXNZ5MG_cjs.createReducer; }
1071
1192
  });
1072
1193
  Object.defineProperty(exports, "createRef", {
1073
1194
  enumerable: true,
1074
- get: function () { return chunk6FW5E54W_cjs.createRef; }
1195
+ get: function () { return chunkKUXNZ5MG_cjs.createRef; }
1075
1196
  });
1076
1197
  Object.defineProperty(exports, "createResource", {
1077
1198
  enumerable: true,
1078
- get: function () { return chunk6FW5E54W_cjs.createResource; }
1199
+ get: function () { return chunkKUXNZ5MG_cjs.createResource; }
1079
1200
  });
1080
1201
  Object.defineProperty(exports, "createRoot", {
1081
1202
  enumerable: true,
1082
- get: function () { return chunk6FW5E54W_cjs.createRoot; }
1203
+ get: function () { return chunkKUXNZ5MG_cjs.createRoot; }
1083
1204
  });
1084
1205
  Object.defineProperty(exports, "createUnownedRoot", {
1085
1206
  enumerable: true,
1086
- get: function () { return chunk6FW5E54W_cjs.createUnownedRoot; }
1207
+ get: function () { return chunkKUXNZ5MG_cjs.createUnownedRoot; }
1087
1208
  });
1088
1209
  Object.defineProperty(exports, "getBatchDepth", {
1089
1210
  enumerable: true,
1090
- get: function () { return chunk6FW5E54W_cjs.getBatchDepth; }
1211
+ get: function () { return chunkKUXNZ5MG_cjs.getBatchDepth; }
1091
1212
  });
1092
1213
  Object.defineProperty(exports, "isComputed", {
1093
1214
  enumerable: true,
1094
- get: function () { return chunk6FW5E54W_cjs.isComputed; }
1215
+ get: function () { return chunkKUXNZ5MG_cjs.isComputed; }
1095
1216
  });
1096
1217
  Object.defineProperty(exports, "isEffect", {
1097
1218
  enumerable: true,
1098
- get: function () { return chunk6FW5E54W_cjs.isEffect; }
1219
+ get: function () { return chunkKUXNZ5MG_cjs.isEffect; }
1099
1220
  });
1100
1221
  Object.defineProperty(exports, "isEffectScope", {
1101
1222
  enumerable: true,
1102
- get: function () { return chunk6FW5E54W_cjs.isEffectScope; }
1223
+ get: function () { return chunkKUXNZ5MG_cjs.isEffectScope; }
1103
1224
  });
1104
1225
  Object.defineProperty(exports, "isSignal", {
1105
1226
  enumerable: true,
1106
- get: function () { return chunk6FW5E54W_cjs.isSignal; }
1227
+ get: function () { return chunkKUXNZ5MG_cjs.isSignal; }
1107
1228
  });
1108
1229
  Object.defineProperty(exports, "on", {
1109
1230
  enumerable: true,
1110
- get: function () { return chunk6FW5E54W_cjs.on; }
1231
+ get: function () { return chunkKUXNZ5MG_cjs.on; }
1111
1232
  });
1112
1233
  Object.defineProperty(exports, "onCleanup", {
1113
1234
  enumerable: true,
1114
- get: function () { return chunk6FW5E54W_cjs.onCleanup; }
1115
- });
1116
- Object.defineProperty(exports, "onError", {
1117
- enumerable: true,
1118
- get: function () { return chunk6FW5E54W_cjs.onError; }
1235
+ get: function () { return chunkKUXNZ5MG_cjs.onCleanup; }
1119
1236
  });
1120
1237
  Object.defineProperty(exports, "trigger", {
1121
1238
  enumerable: true,
1122
- get: function () { return chunk6FW5E54W_cjs.trigger; }
1239
+ get: function () { return chunkKUXNZ5MG_cjs.trigger; }
1123
1240
  });
1124
1241
  Object.defineProperty(exports, "untrack", {
1125
1242
  enumerable: true,
1126
- get: function () { return chunk6FW5E54W_cjs.untrack; }
1243
+ get: function () { return chunkKUXNZ5MG_cjs.untrack; }
1127
1244
  });
1128
1245
  Object.defineProperty(exports, "createComputed", {
1129
1246
  enumerable: true,
1130
- get: function () { return chunkQLPCVK7C_cjs.createComputed; }
1247
+ get: function () { return chunkH7MDUHS5_cjs.createComputed; }
1131
1248
  });
1132
1249
  Object.defineProperty(exports, "createSignal", {
1133
1250
  enumerable: true,
1134
- get: function () { return chunkQLPCVK7C_cjs.createSignal; }
1251
+ get: function () { return chunkH7MDUHS5_cjs.createSignal; }
1252
+ });
1253
+ Object.defineProperty(exports, "onError", {
1254
+ enumerable: true,
1255
+ get: function () { return chunkH7MDUHS5_cjs.onError; }
1135
1256
  });
1136
1257
  exports.$ = $;
1137
1258
  exports.$$ = $$;