@fictjs/runtime 0.0.9 → 0.0.11

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.
package/dist/index.js CHANGED
@@ -346,6 +346,7 @@ var isInTransition = false;
346
346
  var enqueueMicrotask = typeof queueMicrotask === "function" ? queueMicrotask : (fn) => {
347
347
  Promise.resolve().then(fn);
348
348
  };
349
+ var inCleanup = false;
349
350
  function link(dep, sub, version) {
350
351
  const prevDep = sub.depsTail;
351
352
  if (prevDep !== void 0 && prevDep.dep === dep) return;
@@ -591,7 +592,15 @@ function updateComputed(c) {
591
592
  }
592
593
  function runEffect(e) {
593
594
  const flags = e.flags;
594
- if (flags & Dirty || flags & Pending && e.deps && checkDirty(e.deps, e)) {
595
+ if (flags & Dirty) {
596
+ if (e.runCleanup) {
597
+ inCleanup = true;
598
+ try {
599
+ e.runCleanup();
600
+ } finally {
601
+ inCleanup = false;
602
+ }
603
+ }
595
604
  ++cycle;
596
605
  effectRunDevtools(e);
597
606
  e.depsTail = void 0;
@@ -608,6 +617,35 @@ function runEffect(e) {
608
617
  e.flags = Watching;
609
618
  throw err;
610
619
  }
620
+ } else if (flags & Pending && e.deps) {
621
+ if (e.runCleanup) {
622
+ inCleanup = true;
623
+ try {
624
+ e.runCleanup();
625
+ } finally {
626
+ inCleanup = false;
627
+ }
628
+ }
629
+ if (checkDirty(e.deps, e)) {
630
+ ++cycle;
631
+ effectRunDevtools(e);
632
+ e.depsTail = void 0;
633
+ e.flags = WatchingRunning;
634
+ const prevSub = activeSub;
635
+ activeSub = e;
636
+ try {
637
+ e.fn();
638
+ activeSub = prevSub;
639
+ e.flags = Watching;
640
+ purgeDeps(e);
641
+ } catch (err) {
642
+ activeSub = prevSub;
643
+ e.flags = Watching;
644
+ throw err;
645
+ }
646
+ } else {
647
+ e.flags = Watching;
648
+ }
611
649
  } else {
612
650
  e.flags = Watching;
613
651
  }
@@ -703,7 +741,7 @@ function signalOper(value) {
703
741
  return;
704
742
  }
705
743
  const flags = this.flags;
706
- if (flags & Dirty) {
744
+ if (flags & Dirty && !inCleanup) {
707
745
  if (updateSignal(this)) {
708
746
  const subs = this.subs;
709
747
  if (subs !== void 0) shallowPropagate(subs);
@@ -785,6 +823,30 @@ function effect(fn) {
785
823
  }
786
824
  return effectOper.bind(e);
787
825
  }
826
+ function effectWithCleanup(fn, cleanupRunner) {
827
+ const e = {
828
+ fn,
829
+ subs: void 0,
830
+ subsTail: void 0,
831
+ deps: void 0,
832
+ depsTail: void 0,
833
+ flags: WatchingRunning,
834
+ runCleanup: cleanupRunner,
835
+ __id: void 0
836
+ };
837
+ registerEffectDevtools(e);
838
+ const prevSub = activeSub;
839
+ if (prevSub !== void 0) link(e, prevSub, 0);
840
+ activeSub = e;
841
+ try {
842
+ effectRunDevtools(e);
843
+ fn();
844
+ } finally {
845
+ activeSub = prevSub;
846
+ e.flags &= ~Running;
847
+ }
848
+ return effectOper.bind(e);
849
+ }
788
850
  function effectOper() {
789
851
  disposeNode(this);
790
852
  }
@@ -805,10 +867,17 @@ function effectScopeOper() {
805
867
  }
806
868
  function batch(fn) {
807
869
  ++batchDepth;
870
+ let hasError = false;
808
871
  try {
809
872
  return fn();
873
+ } catch (e) {
874
+ hasError = true;
875
+ throw e;
810
876
  } finally {
811
- if (--batchDepth === 0) flush();
877
+ --batchDepth;
878
+ if (!hasError && batchDepth === 0) {
879
+ flush();
880
+ }
812
881
  }
813
882
  }
814
883
  function setActiveSub(sub) {
@@ -864,7 +933,7 @@ function effectRunDevtools(node) {
864
933
  function createSelector(source, equalityFn = (a, b) => a === b) {
865
934
  let current = source();
866
935
  const observers = /* @__PURE__ */ new Map();
867
- effect(() => {
936
+ const dispose = effect(() => {
868
937
  const next = source();
869
938
  if (equalityFn(current, next)) return;
870
939
  const prevSig = observers.get(current);
@@ -873,6 +942,10 @@ function createSelector(source, equalityFn = (a, b) => a === b) {
873
942
  if (nextSig) nextSig(true);
874
943
  current = next;
875
944
  });
945
+ registerRootCleanup(() => {
946
+ dispose();
947
+ observers.clear();
948
+ });
876
949
  return (key) => {
877
950
  let sig = observers.get(key);
878
951
  if (!sig) {
@@ -1019,8 +1092,11 @@ var $memo = createMemo;
1019
1092
  function createEffect(fn) {
1020
1093
  let cleanups = [];
1021
1094
  const rootForError = getCurrentRoot();
1022
- const run = () => {
1095
+ const doCleanup = () => {
1023
1096
  runCleanupList(cleanups);
1097
+ cleanups = [];
1098
+ };
1099
+ const run = () => {
1024
1100
  const bucket = [];
1025
1101
  withEffectCleanups(bucket, () => {
1026
1102
  try {
@@ -1037,7 +1113,7 @@ function createEffect(fn) {
1037
1113
  });
1038
1114
  cleanups = bucket;
1039
1115
  };
1040
- const disposeEffect = effect(run);
1116
+ const disposeEffect = effectWithCleanup(run, doCleanup);
1041
1117
  const teardown = () => {
1042
1118
  runCleanupList(cleanups);
1043
1119
  disposeEffect();
@@ -1049,24 +1125,27 @@ var $effect = createEffect;
1049
1125
  function createRenderEffect(fn) {
1050
1126
  let cleanup;
1051
1127
  const rootForError = getCurrentRoot();
1052
- const run = () => {
1128
+ const doCleanup = () => {
1053
1129
  if (cleanup) {
1054
1130
  cleanup();
1055
1131
  cleanup = void 0;
1056
1132
  }
1133
+ };
1134
+ const run = () => {
1057
1135
  try {
1058
1136
  const maybeCleanup = fn();
1059
1137
  if (typeof maybeCleanup === "function") {
1060
1138
  cleanup = maybeCleanup;
1061
1139
  }
1062
1140
  } catch (err) {
1063
- if (handleError(err, { source: "effect" }, rootForError)) {
1141
+ const handled = handleError(err, { source: "effect" }, rootForError);
1142
+ if (handled) {
1064
1143
  return;
1065
1144
  }
1066
1145
  throw err;
1067
1146
  }
1068
1147
  };
1069
- const disposeEffect = effect(run);
1148
+ const disposeEffect = effectWithCleanup(run, doCleanup);
1070
1149
  const teardown = () => {
1071
1150
  if (cleanup) {
1072
1151
  cleanup();
@@ -1452,159 +1531,22 @@ var UnitlessStyles = /* @__PURE__ */ new Set([
1452
1531
  // src/jsx.ts
1453
1532
  var Fragment = Symbol("Fragment");
1454
1533
 
1455
- // src/node-ops.ts
1456
- function toNodeArray(node) {
1457
- try {
1458
- if (Array.isArray(node)) {
1459
- let allNodes = true;
1460
- for (const item of node) {
1461
- let isItemNode = false;
1462
- try {
1463
- isItemNode = item instanceof Node;
1464
- } catch {
1465
- isItemNode = false;
1466
- }
1467
- if (!isItemNode) {
1468
- allNodes = false;
1469
- break;
1470
- }
1471
- }
1472
- if (allNodes) {
1473
- return node;
1474
- }
1475
- const result = [];
1476
- for (const item of node) {
1477
- result.push(...toNodeArray(item));
1478
- }
1479
- return result;
1480
- }
1481
- if (node === null || node === void 0 || node === false) {
1482
- return [];
1483
- }
1484
- } catch {
1485
- return [];
1486
- }
1487
- let isNode = false;
1488
- try {
1489
- isNode = node instanceof Node;
1490
- } catch {
1491
- isNode = false;
1492
- }
1493
- if (isNode) {
1494
- try {
1495
- if (node instanceof DocumentFragment) {
1496
- return Array.from(node.childNodes);
1497
- }
1498
- } catch {
1499
- }
1500
- return [node];
1501
- }
1502
- try {
1503
- if (typeof node === "object" && node !== null && "marker" in node) {
1504
- return toNodeArray(node.marker);
1505
- }
1506
- } catch {
1507
- }
1508
- try {
1509
- return [document.createTextNode(String(node))];
1510
- } catch {
1511
- return [document.createTextNode("")];
1512
- }
1513
- }
1514
- function insertNodesBefore(parent, nodes, anchor) {
1515
- if (nodes.length === 0) return;
1516
- if (nodes.length === 1) {
1517
- const node = nodes[0];
1518
- if (node === void 0 || node === null) return;
1519
- if (node.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {
1520
- parent.ownerDocument.adoptNode(node);
1521
- }
1522
- try {
1523
- parent.insertBefore(node, anchor);
1524
- } catch (e) {
1525
- if (parent.ownerDocument) {
1526
- try {
1527
- const clone = parent.ownerDocument.importNode(node, true);
1528
- parent.insertBefore(clone, anchor);
1529
- return;
1530
- } catch {
1531
- }
1532
- }
1533
- throw e;
1534
- }
1535
- return;
1536
- }
1537
- const doc = parent.ownerDocument;
1538
- if (doc) {
1539
- const frag = doc.createDocumentFragment();
1540
- for (let i = 0; i < nodes.length; i++) {
1541
- const node = nodes[i];
1542
- if (node === void 0 || node === null) continue;
1543
- if (node.nodeType === 11) {
1544
- const childrenArr = Array.from(node.childNodes);
1545
- for (let j = 0; j < childrenArr.length; j++) {
1546
- frag.appendChild(childrenArr[j]);
1547
- }
1548
- } else {
1549
- if (node.ownerDocument !== doc) {
1550
- doc.adoptNode(node);
1551
- }
1552
- frag.appendChild(node);
1553
- }
1554
- }
1555
- parent.insertBefore(frag, anchor);
1556
- return;
1557
- }
1558
- const insertSingle = (nodeToInsert, anchorNode) => {
1559
- if (nodeToInsert.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {
1560
- parent.ownerDocument.adoptNode(nodeToInsert);
1561
- }
1562
- try {
1563
- parent.insertBefore(nodeToInsert, anchorNode);
1564
- return nodeToInsert;
1565
- } catch (e) {
1566
- if (parent.ownerDocument) {
1567
- try {
1568
- const clone = parent.ownerDocument.importNode(nodeToInsert, true);
1569
- parent.insertBefore(clone, anchorNode);
1570
- return clone;
1571
- } catch {
1572
- }
1573
- }
1574
- throw e;
1575
- }
1576
- };
1577
- for (let i = nodes.length - 1; i >= 0; i--) {
1578
- const node = nodes[i];
1579
- if (node === void 0 || node === null) continue;
1580
- const isFrag = node.nodeType === 11;
1581
- if (isFrag) {
1582
- const childrenArr = Array.from(node.childNodes);
1583
- for (let j = childrenArr.length - 1; j >= 0; j--) {
1584
- const child = childrenArr[j];
1585
- anchor = insertSingle(child, anchor);
1586
- }
1587
- } else {
1588
- anchor = insertSingle(node, anchor);
1589
- }
1590
- }
1591
- }
1592
- function removeNodes(nodes) {
1593
- for (const node of nodes) {
1594
- node.parentNode?.removeChild(node);
1595
- }
1596
- }
1597
-
1598
1534
  // src/hooks.ts
1599
1535
  var ctxStack = [];
1536
+ function assertRenderContext(ctx, hookName) {
1537
+ if (!ctx.rendering) {
1538
+ throw new Error(`${hookName} can only be used during render execution`);
1539
+ }
1540
+ }
1600
1541
  function __fictUseContext() {
1601
1542
  if (ctxStack.length === 0) {
1602
- const ctx2 = { slots: [], cursor: 0 };
1543
+ const ctx2 = { slots: [], cursor: 0, rendering: true };
1603
1544
  ctxStack.push(ctx2);
1604
1545
  return ctx2;
1605
1546
  }
1606
1547
  const ctx = ctxStack[ctxStack.length - 1];
1607
1548
  ctx.cursor = 0;
1549
+ ctx.rendering = true;
1608
1550
  return ctx;
1609
1551
  }
1610
1552
  function __fictPushContext() {
@@ -1619,6 +1561,7 @@ function __fictResetContext() {
1619
1561
  ctxStack.length = 0;
1620
1562
  }
1621
1563
  function __fictUseSignal(ctx, initial, slot) {
1564
+ assertRenderContext(ctx, "__fictUseSignal");
1622
1565
  const index = slot ?? ctx.cursor++;
1623
1566
  if (!ctx.slots[index]) {
1624
1567
  ctx.slots[index] = signal(initial);
@@ -1626,6 +1569,7 @@ function __fictUseSignal(ctx, initial, slot) {
1626
1569
  return ctx.slots[index];
1627
1570
  }
1628
1571
  function __fictUseMemo(ctx, fn, slot) {
1572
+ assertRenderContext(ctx, "__fictUseMemo");
1629
1573
  const index = slot ?? ctx.cursor++;
1630
1574
  if (!ctx.slots[index]) {
1631
1575
  ctx.slots[index] = createMemo(fn);
@@ -1633,6 +1577,7 @@ function __fictUseMemo(ctx, fn, slot) {
1633
1577
  return ctx.slots[index];
1634
1578
  }
1635
1579
  function __fictUseEffect(ctx, fn, slot) {
1580
+ assertRenderContext(ctx, "__fictUseEffect");
1636
1581
  const index = slot ?? ctx.cursor++;
1637
1582
  if (!ctx.slots[index]) {
1638
1583
  ctx.slots[index] = createEffect(fn);
@@ -1641,9 +1586,11 @@ function __fictUseEffect(ctx, fn, slot) {
1641
1586
  function __fictRender(ctx, fn) {
1642
1587
  ctxStack.push(ctx);
1643
1588
  ctx.cursor = 0;
1589
+ ctx.rendering = true;
1644
1590
  try {
1645
1591
  return fn();
1646
1592
  } finally {
1593
+ ctx.rendering = false;
1647
1594
  ctxStack.pop();
1648
1595
  }
1649
1596
  }
@@ -1884,6 +1831,14 @@ function createElementWithContext(node, namespace) {
1884
1831
  if (typeof handle.dispose === "function") {
1885
1832
  registerRootCleanup(handle.dispose);
1886
1833
  }
1834
+ if (typeof handle.flush === "function") {
1835
+ const runFlush = () => handle.flush && handle.flush();
1836
+ if (typeof queueMicrotask === "function") {
1837
+ queueMicrotask(runFlush);
1838
+ } else {
1839
+ Promise.resolve().then(runFlush).catch(() => void 0);
1840
+ }
1841
+ }
1887
1842
  return createElement(handle.marker);
1888
1843
  }
1889
1844
  const nodeRecord = node;
@@ -1931,18 +1886,18 @@ function createElementWithContext(node, namespace) {
1931
1886
  }
1932
1887
  });
1933
1888
  const props = createPropsProxy(baseProps);
1889
+ __fictPushContext();
1934
1890
  try {
1935
- __fictPushContext();
1936
1891
  const rendered = vnode.type(props);
1937
- __fictPopContext();
1938
1892
  return createElementWithContext(rendered, namespace);
1939
1893
  } catch (err) {
1940
- __fictPopContext();
1941
1894
  if (handleSuspend(err)) {
1942
1895
  return document.createComment("fict:suspend");
1943
1896
  }
1944
1897
  handleError(err, { source: "render", componentName: vnode.type.name });
1945
1898
  throw err;
1899
+ } finally {
1900
+ __fictPopContext();
1946
1901
  }
1947
1902
  }
1948
1903
  if (vnode.type === Fragment) {
@@ -2234,6 +2189,149 @@ function eventNameFromProp(key) {
2234
2189
  return key.slice(2).toLowerCase();
2235
2190
  }
2236
2191
 
2192
+ // src/node-ops.ts
2193
+ function toNodeArray(node) {
2194
+ try {
2195
+ if (Array.isArray(node)) {
2196
+ let allNodes = true;
2197
+ for (const item of node) {
2198
+ let isItemNode = false;
2199
+ try {
2200
+ isItemNode = item instanceof Node;
2201
+ } catch {
2202
+ isItemNode = false;
2203
+ }
2204
+ if (!isItemNode) {
2205
+ allNodes = false;
2206
+ break;
2207
+ }
2208
+ }
2209
+ if (allNodes) {
2210
+ return node;
2211
+ }
2212
+ const result = [];
2213
+ for (const item of node) {
2214
+ result.push(...toNodeArray(item));
2215
+ }
2216
+ return result;
2217
+ }
2218
+ if (node === null || node === void 0 || node === false) {
2219
+ return [];
2220
+ }
2221
+ } catch {
2222
+ return [];
2223
+ }
2224
+ let isNode = false;
2225
+ try {
2226
+ isNode = node instanceof Node;
2227
+ } catch {
2228
+ isNode = false;
2229
+ }
2230
+ if (isNode) {
2231
+ try {
2232
+ if (node instanceof DocumentFragment) {
2233
+ return Array.from(node.childNodes);
2234
+ }
2235
+ } catch {
2236
+ }
2237
+ return [node];
2238
+ }
2239
+ try {
2240
+ if (typeof node === "object" && node !== null && "marker" in node) {
2241
+ return toNodeArray(node.marker);
2242
+ }
2243
+ } catch {
2244
+ }
2245
+ try {
2246
+ return [document.createTextNode(String(node))];
2247
+ } catch {
2248
+ return [document.createTextNode("")];
2249
+ }
2250
+ }
2251
+ function insertNodesBefore(parent, nodes, anchor) {
2252
+ if (nodes.length === 0) return;
2253
+ if (nodes.length === 1) {
2254
+ const node = nodes[0];
2255
+ if (node === void 0 || node === null) return;
2256
+ if (node.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {
2257
+ parent.ownerDocument.adoptNode(node);
2258
+ }
2259
+ try {
2260
+ parent.insertBefore(node, anchor);
2261
+ } catch (e) {
2262
+ if (parent.ownerDocument) {
2263
+ try {
2264
+ const clone = parent.ownerDocument.importNode(node, true);
2265
+ parent.insertBefore(clone, anchor);
2266
+ return;
2267
+ } catch {
2268
+ }
2269
+ }
2270
+ throw e;
2271
+ }
2272
+ return;
2273
+ }
2274
+ const doc = parent.ownerDocument;
2275
+ if (doc) {
2276
+ const frag = doc.createDocumentFragment();
2277
+ for (let i = 0; i < nodes.length; i++) {
2278
+ const node = nodes[i];
2279
+ if (node === void 0 || node === null) continue;
2280
+ if (node.nodeType === 11) {
2281
+ const childrenArr = Array.from(node.childNodes);
2282
+ for (let j = 0; j < childrenArr.length; j++) {
2283
+ frag.appendChild(childrenArr[j]);
2284
+ }
2285
+ } else {
2286
+ if (node.ownerDocument !== doc) {
2287
+ doc.adoptNode(node);
2288
+ }
2289
+ frag.appendChild(node);
2290
+ }
2291
+ }
2292
+ parent.insertBefore(frag, anchor);
2293
+ return;
2294
+ }
2295
+ const insertSingle = (nodeToInsert, anchorNode) => {
2296
+ if (nodeToInsert.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {
2297
+ parent.ownerDocument.adoptNode(nodeToInsert);
2298
+ }
2299
+ try {
2300
+ parent.insertBefore(nodeToInsert, anchorNode);
2301
+ return nodeToInsert;
2302
+ } catch (e) {
2303
+ if (parent.ownerDocument) {
2304
+ try {
2305
+ const clone = parent.ownerDocument.importNode(nodeToInsert, true);
2306
+ parent.insertBefore(clone, anchorNode);
2307
+ return clone;
2308
+ } catch {
2309
+ }
2310
+ }
2311
+ throw e;
2312
+ }
2313
+ };
2314
+ for (let i = nodes.length - 1; i >= 0; i--) {
2315
+ const node = nodes[i];
2316
+ if (node === void 0 || node === null) continue;
2317
+ const isFrag = node.nodeType === 11;
2318
+ if (isFrag) {
2319
+ const childrenArr = Array.from(node.childNodes);
2320
+ for (let j = childrenArr.length - 1; j >= 0; j--) {
2321
+ const child = childrenArr[j];
2322
+ anchor = insertSingle(child, anchor);
2323
+ }
2324
+ } else {
2325
+ anchor = insertSingle(node, anchor);
2326
+ }
2327
+ }
2328
+ }
2329
+ function removeNodes(nodes) {
2330
+ for (const node of nodes) {
2331
+ node.parentNode?.removeChild(node);
2332
+ }
2333
+ }
2334
+
2237
2335
  // src/reconcile.ts
2238
2336
  function reconcileArrays(parentNode, a, b) {
2239
2337
  const bLength = b.length;
@@ -2461,7 +2559,6 @@ function createKeyedBlock(key, item, index, render2, needsIndex = true, hostRoot
2461
2559
  } finally {
2462
2560
  setActiveSub(prevSub);
2463
2561
  popRoot(prevRoot);
2464
- flushOnMount(root);
2465
2562
  }
2466
2563
  return {
2467
2564
  key,
@@ -2493,13 +2590,24 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2493
2590
  const hostRoot = getCurrentRoot();
2494
2591
  const fragment = document.createDocumentFragment();
2495
2592
  fragment.append(container.startMarker, container.endMarker);
2496
- let pendingItems = null;
2497
2593
  let disposed = false;
2594
+ let effectDispose;
2595
+ let connectObserver = null;
2596
+ let effectStarted = false;
2597
+ let startScheduled = false;
2598
+ const getConnectedParent = () => {
2599
+ const endParent = container.endMarker.parentNode;
2600
+ const startParent = container.startMarker.parentNode;
2601
+ if (endParent && startParent && endParent === startParent && endParent.nodeType !== 11) {
2602
+ return endParent;
2603
+ }
2604
+ return null;
2605
+ };
2498
2606
  const performDiff = () => {
2499
2607
  if (disposed) return;
2608
+ const parent = getConnectedParent();
2609
+ if (!parent) return;
2500
2610
  batch2(() => {
2501
- const newItems = pendingItems || getItems();
2502
- pendingItems = null;
2503
2611
  const oldBlocks = container.blocks;
2504
2612
  const newBlocks = container.nextBlocks;
2505
2613
  const prevOrderedBlocks = container.orderedBlocks;
@@ -2508,20 +2616,17 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2508
2616
  newBlocks.clear();
2509
2617
  nextOrderedBlocks.length = 0;
2510
2618
  orderedIndexByKey.clear();
2511
- const endParent = container.endMarker.parentNode;
2512
- const startParent = container.startMarker.parentNode;
2513
- const parent = endParent && startParent && endParent === startParent && endParent.isConnected ? endParent : null;
2514
- if (!parent) {
2515
- pendingItems = newItems;
2516
- queueMicrotask(performDiff);
2517
- return;
2518
- }
2619
+ const createdBlocks = [];
2620
+ const newItems = getItems();
2519
2621
  if (newItems.length === 0) {
2520
2622
  if (oldBlocks.size > 0) {
2521
2623
  for (const block of oldBlocks.values()) {
2522
2624
  destroyRoot(block.root);
2523
- removeNodes(block.nodes);
2524
2625
  }
2626
+ const range = document.createRange();
2627
+ range.setStartAfter(container.startMarker);
2628
+ range.setEndBefore(container.endMarker);
2629
+ range.deleteContents();
2525
2630
  }
2526
2631
  oldBlocks.clear();
2527
2632
  newBlocks.clear();
@@ -2538,8 +2643,8 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2538
2643
  const appendedBlocks = [];
2539
2644
  newItems.forEach((item, index) => {
2540
2645
  const key = keyFn(item, index);
2541
- const existed = oldBlocks.has(key);
2542
2646
  let block = oldBlocks.get(key);
2647
+ const existed = block !== void 0;
2543
2648
  if (block) {
2544
2649
  if (block.rawItem !== item) {
2545
2650
  block.rawItem = item;
@@ -2550,38 +2655,23 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2550
2655
  block.index(index);
2551
2656
  }
2552
2657
  }
2553
- const existingBlock = newBlocks.get(key);
2554
- if (existingBlock && existingBlock !== block) {
2555
- destroyRoot(existingBlock.root);
2556
- removeNodes(existingBlock.nodes);
2557
- }
2558
2658
  if (block) {
2559
2659
  newBlocks.set(key, block);
2560
2660
  oldBlocks.delete(key);
2561
2661
  } else {
2562
- const existingBlock2 = newBlocks.get(key);
2563
- if (existingBlock2) {
2564
- destroyRoot(existingBlock2.root);
2565
- removeNodes(existingBlock2.nodes);
2662
+ const existingBlock = newBlocks.get(key);
2663
+ if (existingBlock) {
2664
+ destroyRoot(existingBlock.root);
2665
+ removeNodes(existingBlock.nodes);
2566
2666
  }
2567
2667
  block = createKeyedBlock(key, item, index, renderItem, needsIndex, hostRoot);
2668
+ createdBlocks.push(block);
2568
2669
  }
2569
2670
  const resolvedBlock = block;
2570
2671
  newBlocks.set(key, resolvedBlock);
2571
2672
  const position = orderedIndexByKey.get(key);
2572
2673
  if (position !== void 0) {
2573
2674
  appendCandidate = false;
2574
- }
2575
- if (appendCandidate) {
2576
- if (index < prevCount) {
2577
- if (!prevOrderedBlocks[index] || prevOrderedBlocks[index].key !== key) {
2578
- appendCandidate = false;
2579
- }
2580
- } else if (existed) {
2581
- appendCandidate = false;
2582
- }
2583
- }
2584
- if (position !== void 0) {
2585
2675
  const prior = nextOrderedBlocks[position];
2586
2676
  if (prior && prior !== resolvedBlock) {
2587
2677
  destroyRoot(prior.root);
@@ -2589,6 +2679,15 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2589
2679
  }
2590
2680
  nextOrderedBlocks[position] = resolvedBlock;
2591
2681
  } else {
2682
+ if (appendCandidate) {
2683
+ if (index < prevCount) {
2684
+ if (!prevOrderedBlocks[index] || prevOrderedBlocks[index].key !== key) {
2685
+ appendCandidate = false;
2686
+ }
2687
+ } else if (existed) {
2688
+ appendCandidate = false;
2689
+ }
2690
+ }
2592
2691
  orderedIndexByKey.set(key, nextOrderedBlocks.length);
2593
2692
  nextOrderedBlocks.push(resolvedBlock);
2594
2693
  }
@@ -2617,6 +2716,11 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2617
2716
  container.nextBlocks = oldBlocks;
2618
2717
  container.orderedBlocks = nextOrderedBlocks;
2619
2718
  container.nextOrderedBlocks = prevOrderedBlocks;
2719
+ for (const block of createdBlocks) {
2720
+ if (newBlocks.get(block.key) === block) {
2721
+ flushOnMount(block.root);
2722
+ }
2723
+ }
2620
2724
  return;
2621
2725
  }
2622
2726
  if (oldBlocks.size > 0) {
@@ -2646,22 +2750,87 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2646
2750
  container.nextBlocks = oldBlocks;
2647
2751
  container.orderedBlocks = nextOrderedBlocks;
2648
2752
  container.nextOrderedBlocks = prevOrderedBlocks;
2753
+ for (const block of createdBlocks) {
2754
+ if (newBlocks.get(block.key) === block) {
2755
+ flushOnMount(block.root);
2756
+ }
2757
+ }
2649
2758
  });
2650
2759
  };
2651
- const effectDispose = createRenderEffect(performDiff);
2760
+ const disconnectObserver = () => {
2761
+ connectObserver?.disconnect();
2762
+ connectObserver = null;
2763
+ };
2764
+ const ensureEffectStarted = () => {
2765
+ if (disposed || effectStarted) return effectStarted;
2766
+ const parent = getConnectedParent();
2767
+ if (!parent) return false;
2768
+ const start = () => {
2769
+ effectDispose = createRenderEffect(performDiff);
2770
+ effectStarted = true;
2771
+ };
2772
+ if (hostRoot) {
2773
+ const prev = pushRoot(hostRoot);
2774
+ try {
2775
+ start();
2776
+ } finally {
2777
+ popRoot(prev);
2778
+ }
2779
+ } else {
2780
+ start();
2781
+ }
2782
+ return true;
2783
+ };
2784
+ const waitForConnection = () => {
2785
+ if (connectObserver || typeof MutationObserver === "undefined") return;
2786
+ connectObserver = new MutationObserver(() => {
2787
+ if (disposed) return;
2788
+ if (getConnectedParent()) {
2789
+ disconnectObserver();
2790
+ if (ensureEffectStarted()) {
2791
+ flush();
2792
+ }
2793
+ }
2794
+ });
2795
+ connectObserver.observe(document, { childList: true, subtree: true });
2796
+ };
2797
+ const scheduleStart = () => {
2798
+ if (startScheduled || disposed || effectStarted) return;
2799
+ startScheduled = true;
2800
+ const run = () => {
2801
+ startScheduled = false;
2802
+ if (!ensureEffectStarted()) {
2803
+ waitForConnection();
2804
+ }
2805
+ };
2806
+ if (typeof queueMicrotask === "function") {
2807
+ queueMicrotask(run);
2808
+ } else {
2809
+ Promise.resolve().then(run).catch(() => void 0);
2810
+ }
2811
+ };
2812
+ scheduleStart();
2652
2813
  return {
2653
- marker: fragment,
2814
+ get marker() {
2815
+ scheduleStart();
2816
+ return fragment;
2817
+ },
2654
2818
  startMarker: container.startMarker,
2655
2819
  endMarker: container.endMarker,
2656
2820
  // Flush pending items - call after markers are inserted into DOM
2657
2821
  flush: () => {
2658
- if (pendingItems !== null) {
2659
- performDiff();
2822
+ if (disposed) return;
2823
+ scheduleStart();
2824
+ if (ensureEffectStarted()) {
2825
+ flush();
2826
+ } else {
2827
+ waitForConnection();
2660
2828
  }
2661
2829
  },
2662
2830
  dispose: () => {
2663
2831
  disposed = true;
2664
2832
  effectDispose?.();
2833
+ disconnectObserver();
2665
2834
  container.dispose();
2666
2835
  }
2667
2836
  };
@@ -2861,8 +3030,17 @@ function createClassBinding(el, value) {
2861
3030
  }
2862
3031
  function bindClass(el, getValue) {
2863
3032
  let prev = {};
3033
+ let prevString;
2864
3034
  return createRenderEffect(() => {
2865
3035
  const next = getValue();
3036
+ if (typeof next === "string") {
3037
+ if (next === prevString) return;
3038
+ prevString = next;
3039
+ el.className = next;
3040
+ prev = {};
3041
+ return;
3042
+ }
3043
+ prevString = void 0;
2866
3044
  prev = applyClass(el, next, prev);
2867
3045
  });
2868
3046
  }
@@ -3091,11 +3269,19 @@ function clearDelegatedEvents(doc = window.document) {
3091
3269
  }
3092
3270
  }
3093
3271
  function globalEventHandler(e) {
3094
- let node = e.target;
3272
+ const asNode = (value) => value && typeof value.nodeType === "number" ? value : null;
3273
+ const asElement = (value) => {
3274
+ const n = asNode(value);
3275
+ if (!n) return null;
3276
+ if (n.nodeType === 1) return n;
3277
+ return n.parentElement;
3278
+ };
3279
+ let node = asElement(e.target);
3095
3280
  const key = `$$${e.type}`;
3096
3281
  const dataKey = `${key}Data`;
3097
3282
  const oriTarget = e.target;
3098
3283
  const oriCurrentTarget = e.currentTarget;
3284
+ let lastHandled = null;
3099
3285
  const retarget = (value) => Object.defineProperty(e, "target", {
3100
3286
  configurable: true,
3101
3287
  value
@@ -3118,23 +3304,28 @@ function globalEventHandler(e) {
3118
3304
  const rawData = node[dataKey];
3119
3305
  const hasData = rawData !== void 0;
3120
3306
  const resolvedNodeData = hasData ? resolveData(rawData) : void 0;
3121
- if (typeof handler === "function") {
3122
- callEventHandler(handler, e, node, hasData ? resolvedNodeData : void 0);
3123
- } else if (Array.isArray(handler)) {
3124
- const tupleData = resolveData(handler[1]);
3125
- callEventHandler(handler[0], e, node, tupleData);
3126
- }
3307
+ batch2(() => {
3308
+ if (typeof handler === "function") {
3309
+ callEventHandler(handler, e, node, hasData ? resolvedNodeData : void 0);
3310
+ } else if (Array.isArray(handler)) {
3311
+ const tupleData = resolveData(handler[1]);
3312
+ callEventHandler(handler[0], e, node, tupleData);
3313
+ }
3314
+ });
3127
3315
  if (e.cancelBubble) return false;
3128
3316
  }
3129
3317
  const shadowHost = node.host;
3130
- if (shadowHost && typeof shadowHost !== "string" && !shadowHost._$host && node.contains(e.target)) {
3318
+ if (shadowHost && typeof shadowHost !== "string" && !shadowHost._$host && (() => {
3319
+ const targetNode = asNode(e.target);
3320
+ return targetNode ? node.contains(targetNode) : false;
3321
+ })()) {
3131
3322
  retarget(shadowHost);
3132
3323
  }
3133
3324
  return true;
3134
3325
  };
3135
3326
  const walkUpTree = () => {
3136
3327
  while (handleNode() && node) {
3137
- node = node._$host || node.parentNode || node.host;
3328
+ node = asElement(node._$host || node.parentNode || node.host);
3138
3329
  }
3139
3330
  };
3140
3331
  Object.defineProperty(e, "currentTarget", {
@@ -3147,8 +3338,11 @@ function globalEventHandler(e) {
3147
3338
  const path = e.composedPath();
3148
3339
  retarget(path[0]);
3149
3340
  for (let i = 0; i < path.length - 2; i++) {
3150
- node = path[i];
3341
+ const nextNode = asElement(path[i]);
3342
+ if (!nextNode || nextNode === lastHandled) continue;
3343
+ node = nextNode;
3151
3344
  if (!handleNode()) break;
3345
+ lastHandled = node;
3152
3346
  if (node._$host) {
3153
3347
  node = node._$host;
3154
3348
  walkUpTree();