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