@getforma/core 1.0.7 → 1.0.9

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 (48) hide show
  1. package/README.md +4 -4
  2. package/dist/{chunk-OUVOAYIO.js → chunk-3G7ET4O5.js} +33 -9
  3. package/dist/chunk-3G7ET4O5.js.map +1 -0
  4. package/dist/{chunk-DCTOXHPF.cjs → chunk-6FW5E54W.cjs} +38 -12
  5. package/dist/chunk-6FW5E54W.cjs.map +1 -0
  6. package/dist/{chunk-FJGTMWKY.js → chunk-AFRFF7XL.js} +67 -23
  7. package/dist/chunk-AFRFF7XL.js.map +1 -0
  8. package/dist/{chunk-OZCHIVAZ.js → chunk-HLM5BZZQ.js} +2 -2
  9. package/dist/chunk-HLM5BZZQ.js.map +1 -0
  10. package/dist/{chunk-3U57L2TY.cjs → chunk-QLPCVK7C.cjs} +2 -2
  11. package/dist/chunk-QLPCVK7C.cjs.map +1 -0
  12. package/dist/{chunk-SZSKW57A.cjs → chunk-T33QUD2Y.cjs} +102 -58
  13. package/dist/chunk-T33QUD2Y.cjs.map +1 -0
  14. package/dist/formajs-runtime-hardened.global.js.map +1 -1
  15. package/dist/formajs-runtime.global.js.map +1 -1
  16. package/dist/formajs.global.js +102 -26
  17. package/dist/formajs.global.js.map +1 -1
  18. package/dist/http.cjs +11 -11
  19. package/dist/http.js +2 -2
  20. package/dist/index.cjs +72 -61
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +166 -11
  23. package/dist/index.d.ts +166 -11
  24. package/dist/index.js +16 -9
  25. package/dist/index.js.map +1 -1
  26. package/dist/{resource-Cd0cGOxS.d.ts → resource-BHsgURy0.d.ts} +3 -1
  27. package/dist/{resource-DK98lW5e.d.cts → resource-DeEzxUz6.d.cts} +3 -1
  28. package/dist/runtime-hardened.cjs.map +1 -1
  29. package/dist/runtime-hardened.js.map +1 -1
  30. package/dist/runtime.cjs +29 -29
  31. package/dist/runtime.js +3 -3
  32. package/dist/server.cjs +7 -7
  33. package/dist/server.d.cts +2 -2
  34. package/dist/server.d.ts +2 -2
  35. package/dist/server.js +2 -2
  36. package/dist/{signal-YlS1kgfh.d.cts → signal-C9v4akyJ.d.cts} +2 -0
  37. package/dist/{signal-YlS1kgfh.d.ts → signal-C9v4akyJ.d.ts} +2 -0
  38. package/dist/tc39-compat.cjs +3 -3
  39. package/dist/tc39-compat.d.cts +1 -1
  40. package/dist/tc39-compat.d.ts +1 -1
  41. package/dist/tc39-compat.js +1 -1
  42. package/package.json +1 -1
  43. package/dist/chunk-3U57L2TY.cjs.map +0 -1
  44. package/dist/chunk-DCTOXHPF.cjs.map +0 -1
  45. package/dist/chunk-FJGTMWKY.js.map +0 -1
  46. package/dist/chunk-OUVOAYIO.js.map +0 -1
  47. package/dist/chunk-OZCHIVAZ.js.map +0 -1
  48. package/dist/chunk-SZSKW57A.cjs.map +0 -1
@@ -49,6 +49,7 @@ var FormaJS = (() => {
49
49
  createSuspense: () => createSuspense,
50
50
  createSwitch: () => createSwitch,
51
51
  createText: () => createText,
52
+ createUnownedRoot: () => createUnownedRoot,
52
53
  deactivateAllIslands: () => deactivateAllIslands,
53
54
  deactivateIsland: () => deactivateIsland,
54
55
  defineComponent: () => defineComponent,
@@ -622,11 +623,15 @@ var FormaJS = (() => {
622
623
  // src/reactive/root.ts
623
624
  var currentRoot = null;
624
625
  var rootStack = [];
625
- function createRoot(fn) {
626
+ function createRootImpl(fn, owned) {
626
627
  const scope = { disposers: [], scopeDispose: null };
628
+ const parentRoot = owned ? currentRoot : null;
627
629
  rootStack.push(currentRoot);
628
630
  currentRoot = scope;
631
+ let disposed = false;
629
632
  const dispose = () => {
633
+ if (disposed) return;
634
+ disposed = true;
630
635
  if (scope.scopeDispose) {
631
636
  try {
632
637
  scope.scopeDispose();
@@ -642,16 +647,36 @@ var FormaJS = (() => {
642
647
  }
643
648
  scope.disposers.length = 0;
644
649
  };
650
+ if (parentRoot) {
651
+ parentRoot.disposers.push(dispose);
652
+ }
645
653
  let result;
646
654
  try {
647
- scope.scopeDispose = effectScope(() => {
648
- result = fn(dispose);
649
- });
655
+ if (owned) {
656
+ scope.scopeDispose = effectScope(() => {
657
+ result = fn(dispose);
658
+ });
659
+ } else {
660
+ const prevSub = setActiveSub(void 0);
661
+ try {
662
+ scope.scopeDispose = effectScope(() => {
663
+ result = fn(dispose);
664
+ });
665
+ } finally {
666
+ setActiveSub(prevSub);
667
+ }
668
+ }
650
669
  } finally {
651
670
  currentRoot = rootStack.pop() ?? null;
652
671
  }
653
672
  return result;
654
673
  }
674
+ function createRoot(fn) {
675
+ return createRootImpl(fn, true);
676
+ }
677
+ function createUnownedRoot(fn) {
678
+ return createRootImpl(fn, false);
679
+ }
655
680
  function registerDisposer(dispose) {
656
681
  if (currentRoot) {
657
682
  currentRoot.disposers.push(dispose);
@@ -1314,18 +1339,26 @@ var FormaJS = (() => {
1314
1339
  const cached = cache2.get(key);
1315
1340
  if (cached) cached.item = item;
1316
1341
  };
1342
+ const oldCache = cache2;
1317
1343
  const result = reconcileList(
1318
1344
  parent2,
1319
1345
  currentItems,
1320
1346
  cleanItems,
1321
1347
  currentNodes,
1322
1348
  keyFn,
1323
- // createFn: create element + cache entry
1349
+ // createFn: create element + cache entry.
1350
+ // Each item is rendered inside createRoot + untrack so that inner
1351
+ // effects are owned by the item's root (not the parent), and are
1352
+ // disposed when the item is removed from the list.
1324
1353
  (item) => {
1325
1354
  const key = keyFn(item);
1326
1355
  const [getIndex, setIndex] = createSignal(0);
1327
- const element = untrack(() => renderFn(item, getIndex));
1328
- cache2.set(key, { element, item, getIndex, setIndex });
1356
+ let itemDispose;
1357
+ const element = createRoot((dispose) => {
1358
+ itemDispose = dispose;
1359
+ return untrack(() => renderFn(item, getIndex));
1360
+ });
1361
+ cache2.set(key, { element, item, getIndex, setIndex, dispose: itemDispose });
1329
1362
  return element;
1330
1363
  },
1331
1364
  updateRow,
@@ -1335,23 +1368,36 @@ var FormaJS = (() => {
1335
1368
  const newCache = /* @__PURE__ */ new Map();
1336
1369
  for (let i = 0; i < cleanItems.length; i++) {
1337
1370
  const key = keyFn(cleanItems[i]);
1338
- const cached = cache2.get(key);
1371
+ const cached = oldCache.get(key);
1339
1372
  if (cached) {
1340
1373
  cached.setIndex(i);
1341
1374
  newCache.set(key, cached);
1342
1375
  }
1343
1376
  }
1377
+ for (const [key, cached] of oldCache) {
1378
+ if (!newCache.has(key)) {
1379
+ cached.dispose();
1380
+ }
1381
+ }
1344
1382
  cache2 = newCache;
1345
1383
  currentNodes = result.nodes;
1346
1384
  currentItems = result.items;
1347
1385
  });
1386
+ registerDisposer(() => {
1387
+ for (const cached of cache2.values()) {
1388
+ cached.dispose();
1389
+ }
1390
+ cache2 = /* @__PURE__ */ new Map();
1391
+ currentNodes = [];
1392
+ currentItems = [];
1393
+ });
1348
1394
  return fragment2;
1349
1395
  }
1350
1396
 
1351
1397
  // src/dom/show.ts
1352
- function createShow(when, thenFn, elseFn) {
1398
+ function createShow(when, thenFn, elseFn = () => null) {
1353
1399
  if (hydrating) {
1354
- const branch = when() ? thenFn() : elseFn?.() ?? null;
1400
+ const branch = when() ? thenFn() : elseFn();
1355
1401
  return {
1356
1402
  type: "show",
1357
1403
  condition: when,
@@ -1412,6 +1458,13 @@ var FormaJS = (() => {
1412
1458
  parent2.insertBefore(currentNode, endMarker);
1413
1459
  }
1414
1460
  });
1461
+ registerDisposer(() => {
1462
+ if (currentDispose) {
1463
+ currentDispose();
1464
+ currentDispose = null;
1465
+ }
1466
+ currentNode = null;
1467
+ });
1415
1468
  fragment2.__showDispose = () => {
1416
1469
  showDispose();
1417
1470
  if (currentDispose) {
@@ -2095,6 +2148,31 @@ var FormaJS = (() => {
2095
2148
  }
2096
2149
  }
2097
2150
  }
2151
+ function parseCssString(css) {
2152
+ const obj = {};
2153
+ for (const decl of css.split(";")) {
2154
+ const colon = decl.indexOf(":");
2155
+ if (colon < 0) continue;
2156
+ const prop = decl.slice(0, colon).trim();
2157
+ const val = decl.slice(colon + 1).trim();
2158
+ if (prop && val) {
2159
+ const camel = prop.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
2160
+ obj[camel] = val;
2161
+ }
2162
+ }
2163
+ return obj;
2164
+ }
2165
+ function applyStyleObj(el, obj, prevKeys) {
2166
+ const style = el.style;
2167
+ const nextKeys = Object.keys(obj);
2168
+ for (const k of prevKeys) {
2169
+ if (!(k in obj)) {
2170
+ style.removeProperty(k.replace(/[A-Z]/g, (c) => "-" + c.toLowerCase()));
2171
+ }
2172
+ }
2173
+ Object.assign(style, obj);
2174
+ return nextKeys;
2175
+ }
2098
2176
  function handleStyle(el, _key, value2) {
2099
2177
  if (typeof value2 === "function") {
2100
2178
  let prevKeys = [];
@@ -2104,25 +2182,16 @@ var FormaJS = (() => {
2104
2182
  const cache2 = getCache(el);
2105
2183
  if (cache2["style"] === v) return;
2106
2184
  cache2["style"] = v;
2107
- prevKeys = [];
2108
- el.style.cssText = v;
2185
+ prevKeys = applyStyleObj(el, parseCssString(v), prevKeys);
2109
2186
  } else if (v && typeof v === "object") {
2110
- const style = el.style;
2111
- const nextKeys = Object.keys(v);
2112
- for (const k of prevKeys) {
2113
- if (!(k in v)) {
2114
- style.removeProperty(k.replace(/[A-Z]/g, (c) => "-" + c.toLowerCase()));
2115
- }
2116
- }
2117
- Object.assign(style, v);
2118
- prevKeys = nextKeys;
2187
+ prevKeys = applyStyleObj(el, v, prevKeys);
2119
2188
  }
2120
2189
  });
2121
2190
  } else if (typeof value2 === "string") {
2122
2191
  const cache2 = getCache(el);
2123
2192
  if (cache2["style"] === value2) return;
2124
2193
  cache2["style"] = value2;
2125
- el.style.cssText = value2;
2194
+ applyStyleObj(el, parseCssString(value2), []);
2126
2195
  } else if (value2 && typeof value2 === "object") {
2127
2196
  Object.assign(el.style, value2);
2128
2197
  }
@@ -2295,7 +2364,7 @@ var FormaJS = (() => {
2295
2364
  }
2296
2365
  if (key === "style") {
2297
2366
  if (typeof value2 === "string") {
2298
- el.style.cssText = value2;
2367
+ applyStyleObj(el, parseCssString(value2), []);
2299
2368
  } else if (value2 && typeof value2 === "object") {
2300
2369
  Object.assign(el.style, value2);
2301
2370
  }
@@ -2516,12 +2585,12 @@ var FormaJS = (() => {
2516
2585
  }
2517
2586
  let disposeRoot;
2518
2587
  if (target.hasAttribute("data-forma-ssr")) {
2519
- createRoot((dispose) => {
2588
+ createUnownedRoot((dispose) => {
2520
2589
  disposeRoot = dispose;
2521
2590
  hydrateIsland(component, target);
2522
2591
  });
2523
2592
  } else {
2524
- const dom = createRoot((dispose) => {
2593
+ const dom = createUnownedRoot((dispose) => {
2525
2594
  disposeRoot = dispose;
2526
2595
  return component();
2527
2596
  });
@@ -2602,6 +2671,13 @@ var FormaJS = (() => {
2602
2671
  if (DEBUG) console.log("[forma:switch] inserted", currentNode.nodeName, "before end marker");
2603
2672
  }
2604
2673
  });
2674
+ registerDisposer(() => {
2675
+ for (const entry of cache2.values()) {
2676
+ entry.dispose();
2677
+ }
2678
+ cache2.clear();
2679
+ currentNode = null;
2680
+ });
2605
2681
  fragment2.__switchDispose = () => {
2606
2682
  switchDispose();
2607
2683
  for (const entry of cache2.values()) {
@@ -2817,7 +2893,7 @@ var FormaJS = (() => {
2817
2893
  const props = loadIslandProps(root, id, sharedProps);
2818
2894
  root.setAttribute("data-forma-status", "hydrating");
2819
2895
  let activeRoot = root;
2820
- createRoot((dispose) => {
2896
+ createUnownedRoot((dispose) => {
2821
2897
  activeRoot = hydrateIsland(() => hydrateFn(root, props), root);
2822
2898
  activeRoot.__formaDispose = dispose;
2823
2899
  });