@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.dev.js 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,19 @@ function effectScopeOper() {
807
869
  }
808
870
  function batch(fn) {
809
871
  ++batchDepth;
872
+ let _error;
873
+ let hasError = false;
810
874
  try {
811
875
  return fn();
876
+ } catch (e) {
877
+ _error = e;
878
+ hasError = true;
879
+ throw e;
812
880
  } finally {
813
- if (--batchDepth === 0) flush();
881
+ --batchDepth;
882
+ if (!hasError && batchDepth === 0) {
883
+ flush();
884
+ }
814
885
  }
815
886
  }
816
887
  function setActiveSub(sub) {
@@ -866,7 +937,7 @@ function effectRunDevtools(node) {
866
937
  function createSelector(source, equalityFn = (a, b) => a === b) {
867
938
  let current = source();
868
939
  const observers = /* @__PURE__ */ new Map();
869
- effect(() => {
940
+ const dispose = effect(() => {
870
941
  const next = source();
871
942
  if (equalityFn(current, next)) return;
872
943
  const prevSig = observers.get(current);
@@ -875,6 +946,10 @@ function createSelector(source, equalityFn = (a, b) => a === b) {
875
946
  if (nextSig) nextSig(true);
876
947
  current = next;
877
948
  });
949
+ registerRootCleanup(() => {
950
+ dispose();
951
+ observers.clear();
952
+ });
878
953
  return (key) => {
879
954
  let sig = observers.get(key);
880
955
  if (!sig) {
@@ -1021,8 +1096,11 @@ var $memo = createMemo;
1021
1096
  function createEffect(fn) {
1022
1097
  let cleanups = [];
1023
1098
  const rootForError = getCurrentRoot();
1024
- const run = () => {
1099
+ const doCleanup = () => {
1025
1100
  runCleanupList(cleanups);
1101
+ cleanups = [];
1102
+ };
1103
+ const run = () => {
1026
1104
  const bucket = [];
1027
1105
  withEffectCleanups(bucket, () => {
1028
1106
  try {
@@ -1039,7 +1117,7 @@ function createEffect(fn) {
1039
1117
  });
1040
1118
  cleanups = bucket;
1041
1119
  };
1042
- const disposeEffect = effect(run);
1120
+ const disposeEffect = effectWithCleanup(run, doCleanup);
1043
1121
  const teardown = () => {
1044
1122
  runCleanupList(cleanups);
1045
1123
  disposeEffect();
@@ -1051,24 +1129,27 @@ var $effect = createEffect;
1051
1129
  function createRenderEffect(fn) {
1052
1130
  let cleanup;
1053
1131
  const rootForError = getCurrentRoot();
1054
- const run = () => {
1132
+ const doCleanup = () => {
1055
1133
  if (cleanup) {
1056
1134
  cleanup();
1057
1135
  cleanup = void 0;
1058
1136
  }
1137
+ };
1138
+ const run = () => {
1059
1139
  try {
1060
1140
  const maybeCleanup = fn();
1061
1141
  if (typeof maybeCleanup === "function") {
1062
1142
  cleanup = maybeCleanup;
1063
1143
  }
1064
1144
  } catch (err) {
1065
- if (handleError(err, { source: "effect" }, rootForError)) {
1145
+ const handled = handleError(err, { source: "effect" }, rootForError);
1146
+ if (handled) {
1066
1147
  return;
1067
1148
  }
1068
1149
  throw err;
1069
1150
  }
1070
1151
  };
1071
- const disposeEffect = effect(run);
1152
+ const disposeEffect = effectWithCleanup(run, doCleanup);
1072
1153
  const teardown = () => {
1073
1154
  if (cleanup) {
1074
1155
  cleanup();
@@ -1454,159 +1535,22 @@ var UnitlessStyles = /* @__PURE__ */ new Set([
1454
1535
  // src/jsx.ts
1455
1536
  var Fragment = Symbol("Fragment");
1456
1537
 
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
1538
  // src/hooks.ts
1601
1539
  var ctxStack = [];
1540
+ function assertRenderContext(ctx, hookName) {
1541
+ if (!ctx.rendering) {
1542
+ throw new Error(`${hookName} can only be used during render execution`);
1543
+ }
1544
+ }
1602
1545
  function __fictUseContext() {
1603
1546
  if (ctxStack.length === 0) {
1604
- const ctx2 = { slots: [], cursor: 0 };
1547
+ const ctx2 = { slots: [], cursor: 0, rendering: true };
1605
1548
  ctxStack.push(ctx2);
1606
1549
  return ctx2;
1607
1550
  }
1608
1551
  const ctx = ctxStack[ctxStack.length - 1];
1609
1552
  ctx.cursor = 0;
1553
+ ctx.rendering = true;
1610
1554
  return ctx;
1611
1555
  }
1612
1556
  function __fictPushContext() {
@@ -1621,6 +1565,7 @@ function __fictResetContext() {
1621
1565
  ctxStack.length = 0;
1622
1566
  }
1623
1567
  function __fictUseSignal(ctx, initial, slot) {
1568
+ assertRenderContext(ctx, "__fictUseSignal");
1624
1569
  const index = slot ?? ctx.cursor++;
1625
1570
  if (!ctx.slots[index]) {
1626
1571
  ctx.slots[index] = signal(initial);
@@ -1628,6 +1573,7 @@ function __fictUseSignal(ctx, initial, slot) {
1628
1573
  return ctx.slots[index];
1629
1574
  }
1630
1575
  function __fictUseMemo(ctx, fn, slot) {
1576
+ assertRenderContext(ctx, "__fictUseMemo");
1631
1577
  const index = slot ?? ctx.cursor++;
1632
1578
  if (!ctx.slots[index]) {
1633
1579
  ctx.slots[index] = createMemo(fn);
@@ -1635,6 +1581,7 @@ function __fictUseMemo(ctx, fn, slot) {
1635
1581
  return ctx.slots[index];
1636
1582
  }
1637
1583
  function __fictUseEffect(ctx, fn, slot) {
1584
+ assertRenderContext(ctx, "__fictUseEffect");
1638
1585
  const index = slot ?? ctx.cursor++;
1639
1586
  if (!ctx.slots[index]) {
1640
1587
  ctx.slots[index] = createEffect(fn);
@@ -1643,9 +1590,11 @@ function __fictUseEffect(ctx, fn, slot) {
1643
1590
  function __fictRender(ctx, fn) {
1644
1591
  ctxStack.push(ctx);
1645
1592
  ctx.cursor = 0;
1593
+ ctx.rendering = true;
1646
1594
  try {
1647
1595
  return fn();
1648
1596
  } finally {
1597
+ ctx.rendering = false;
1649
1598
  ctxStack.pop();
1650
1599
  }
1651
1600
  }
@@ -1886,6 +1835,14 @@ function createElementWithContext(node, namespace) {
1886
1835
  if (typeof handle.dispose === "function") {
1887
1836
  registerRootCleanup(handle.dispose);
1888
1837
  }
1838
+ if (typeof handle.flush === "function") {
1839
+ const runFlush = () => handle.flush && handle.flush();
1840
+ if (typeof queueMicrotask === "function") {
1841
+ queueMicrotask(runFlush);
1842
+ } else {
1843
+ Promise.resolve().then(runFlush).catch(() => void 0);
1844
+ }
1845
+ }
1889
1846
  return createElement(handle.marker);
1890
1847
  }
1891
1848
  const nodeRecord = node;
@@ -1933,18 +1890,18 @@ function createElementWithContext(node, namespace) {
1933
1890
  }
1934
1891
  });
1935
1892
  const props = createPropsProxy(baseProps);
1893
+ __fictPushContext();
1936
1894
  try {
1937
- __fictPushContext();
1938
1895
  const rendered = vnode.type(props);
1939
- __fictPopContext();
1940
1896
  return createElementWithContext(rendered, namespace);
1941
1897
  } catch (err) {
1942
- __fictPopContext();
1943
1898
  if (handleSuspend(err)) {
1944
1899
  return document.createComment("fict:suspend");
1945
1900
  }
1946
1901
  handleError(err, { source: "render", componentName: vnode.type.name });
1947
1902
  throw err;
1903
+ } finally {
1904
+ __fictPopContext();
1948
1905
  }
1949
1906
  }
1950
1907
  if (vnode.type === Fragment) {
@@ -2240,6 +2197,149 @@ function eventNameFromProp(key) {
2240
2197
  return key.slice(2).toLowerCase();
2241
2198
  }
2242
2199
 
2200
+ // src/node-ops.ts
2201
+ function toNodeArray(node) {
2202
+ try {
2203
+ if (Array.isArray(node)) {
2204
+ let allNodes = true;
2205
+ for (const item of node) {
2206
+ let isItemNode = false;
2207
+ try {
2208
+ isItemNode = item instanceof Node;
2209
+ } catch {
2210
+ isItemNode = false;
2211
+ }
2212
+ if (!isItemNode) {
2213
+ allNodes = false;
2214
+ break;
2215
+ }
2216
+ }
2217
+ if (allNodes) {
2218
+ return node;
2219
+ }
2220
+ const result = [];
2221
+ for (const item of node) {
2222
+ result.push(...toNodeArray(item));
2223
+ }
2224
+ return result;
2225
+ }
2226
+ if (node === null || node === void 0 || node === false) {
2227
+ return [];
2228
+ }
2229
+ } catch {
2230
+ return [];
2231
+ }
2232
+ let isNode = false;
2233
+ try {
2234
+ isNode = node instanceof Node;
2235
+ } catch {
2236
+ isNode = false;
2237
+ }
2238
+ if (isNode) {
2239
+ try {
2240
+ if (node instanceof DocumentFragment) {
2241
+ return Array.from(node.childNodes);
2242
+ }
2243
+ } catch {
2244
+ }
2245
+ return [node];
2246
+ }
2247
+ try {
2248
+ if (typeof node === "object" && node !== null && "marker" in node) {
2249
+ return toNodeArray(node.marker);
2250
+ }
2251
+ } catch {
2252
+ }
2253
+ try {
2254
+ return [document.createTextNode(String(node))];
2255
+ } catch {
2256
+ return [document.createTextNode("")];
2257
+ }
2258
+ }
2259
+ function insertNodesBefore(parent, nodes, anchor) {
2260
+ if (nodes.length === 0) return;
2261
+ if (nodes.length === 1) {
2262
+ const node = nodes[0];
2263
+ if (node === void 0 || node === null) return;
2264
+ if (node.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {
2265
+ parent.ownerDocument.adoptNode(node);
2266
+ }
2267
+ try {
2268
+ parent.insertBefore(node, anchor);
2269
+ } catch (e) {
2270
+ if (parent.ownerDocument) {
2271
+ try {
2272
+ const clone = parent.ownerDocument.importNode(node, true);
2273
+ parent.insertBefore(clone, anchor);
2274
+ return;
2275
+ } catch {
2276
+ }
2277
+ }
2278
+ throw e;
2279
+ }
2280
+ return;
2281
+ }
2282
+ const doc = parent.ownerDocument;
2283
+ if (doc) {
2284
+ const frag = doc.createDocumentFragment();
2285
+ for (let i = 0; i < nodes.length; i++) {
2286
+ const node = nodes[i];
2287
+ if (node === void 0 || node === null) continue;
2288
+ if (node.nodeType === 11) {
2289
+ const childrenArr = Array.from(node.childNodes);
2290
+ for (let j = 0; j < childrenArr.length; j++) {
2291
+ frag.appendChild(childrenArr[j]);
2292
+ }
2293
+ } else {
2294
+ if (node.ownerDocument !== doc) {
2295
+ doc.adoptNode(node);
2296
+ }
2297
+ frag.appendChild(node);
2298
+ }
2299
+ }
2300
+ parent.insertBefore(frag, anchor);
2301
+ return;
2302
+ }
2303
+ const insertSingle = (nodeToInsert, anchorNode) => {
2304
+ if (nodeToInsert.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {
2305
+ parent.ownerDocument.adoptNode(nodeToInsert);
2306
+ }
2307
+ try {
2308
+ parent.insertBefore(nodeToInsert, anchorNode);
2309
+ return nodeToInsert;
2310
+ } catch (e) {
2311
+ if (parent.ownerDocument) {
2312
+ try {
2313
+ const clone = parent.ownerDocument.importNode(nodeToInsert, true);
2314
+ parent.insertBefore(clone, anchorNode);
2315
+ return clone;
2316
+ } catch {
2317
+ }
2318
+ }
2319
+ throw e;
2320
+ }
2321
+ };
2322
+ for (let i = nodes.length - 1; i >= 0; i--) {
2323
+ const node = nodes[i];
2324
+ if (node === void 0 || node === null) continue;
2325
+ const isFrag = node.nodeType === 11;
2326
+ if (isFrag) {
2327
+ const childrenArr = Array.from(node.childNodes);
2328
+ for (let j = childrenArr.length - 1; j >= 0; j--) {
2329
+ const child = childrenArr[j];
2330
+ anchor = insertSingle(child, anchor);
2331
+ }
2332
+ } else {
2333
+ anchor = insertSingle(node, anchor);
2334
+ }
2335
+ }
2336
+ }
2337
+ function removeNodes(nodes) {
2338
+ for (const node of nodes) {
2339
+ node.parentNode?.removeChild(node);
2340
+ }
2341
+ }
2342
+
2243
2343
  // src/reconcile.ts
2244
2344
  function reconcileArrays(parentNode, a, b) {
2245
2345
  const bLength = b.length;
@@ -2467,7 +2567,6 @@ function createKeyedBlock(key, item, index, render2, needsIndex = true, hostRoot
2467
2567
  } finally {
2468
2568
  setActiveSub(prevSub);
2469
2569
  popRoot(prevRoot);
2470
- flushOnMount(root);
2471
2570
  }
2472
2571
  return {
2473
2572
  key,
@@ -2499,13 +2598,24 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2499
2598
  const hostRoot = getCurrentRoot();
2500
2599
  const fragment = document.createDocumentFragment();
2501
2600
  fragment.append(container.startMarker, container.endMarker);
2502
- let pendingItems = null;
2503
2601
  let disposed = false;
2602
+ let effectDispose;
2603
+ let connectObserver = null;
2604
+ let effectStarted = false;
2605
+ let startScheduled = false;
2606
+ const getConnectedParent = () => {
2607
+ const endParent = container.endMarker.parentNode;
2608
+ const startParent = container.startMarker.parentNode;
2609
+ if (endParent && startParent && endParent === startParent && endParent.nodeType !== 11) {
2610
+ return endParent;
2611
+ }
2612
+ return null;
2613
+ };
2504
2614
  const performDiff = () => {
2505
2615
  if (disposed) return;
2616
+ const parent = getConnectedParent();
2617
+ if (!parent) return;
2506
2618
  batch2(() => {
2507
- const newItems = pendingItems || getItems();
2508
- pendingItems = null;
2509
2619
  const oldBlocks = container.blocks;
2510
2620
  const newBlocks = container.nextBlocks;
2511
2621
  const prevOrderedBlocks = container.orderedBlocks;
@@ -2514,20 +2624,17 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2514
2624
  newBlocks.clear();
2515
2625
  nextOrderedBlocks.length = 0;
2516
2626
  orderedIndexByKey.clear();
2517
- const endParent = container.endMarker.parentNode;
2518
- const startParent = container.startMarker.parentNode;
2519
- const parent = endParent && startParent && endParent === startParent && endParent.isConnected ? endParent : null;
2520
- if (!parent) {
2521
- pendingItems = newItems;
2522
- queueMicrotask(performDiff);
2523
- return;
2524
- }
2627
+ const createdBlocks = [];
2628
+ const newItems = getItems();
2525
2629
  if (newItems.length === 0) {
2526
2630
  if (oldBlocks.size > 0) {
2527
2631
  for (const block of oldBlocks.values()) {
2528
2632
  destroyRoot(block.root);
2529
- removeNodes(block.nodes);
2530
2633
  }
2634
+ const range = document.createRange();
2635
+ range.setStartAfter(container.startMarker);
2636
+ range.setEndBefore(container.endMarker);
2637
+ range.deleteContents();
2531
2638
  }
2532
2639
  oldBlocks.clear();
2533
2640
  newBlocks.clear();
@@ -2544,8 +2651,8 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2544
2651
  const appendedBlocks = [];
2545
2652
  newItems.forEach((item, index) => {
2546
2653
  const key = keyFn(item, index);
2547
- const existed = oldBlocks.has(key);
2548
2654
  let block = oldBlocks.get(key);
2655
+ const existed = block !== void 0;
2549
2656
  if (block) {
2550
2657
  if (block.rawItem !== item) {
2551
2658
  block.rawItem = item;
@@ -2556,38 +2663,23 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2556
2663
  block.index(index);
2557
2664
  }
2558
2665
  }
2559
- const existingBlock = newBlocks.get(key);
2560
- if (existingBlock && existingBlock !== block) {
2561
- destroyRoot(existingBlock.root);
2562
- removeNodes(existingBlock.nodes);
2563
- }
2564
2666
  if (block) {
2565
2667
  newBlocks.set(key, block);
2566
2668
  oldBlocks.delete(key);
2567
2669
  } else {
2568
- const existingBlock2 = newBlocks.get(key);
2569
- if (existingBlock2) {
2570
- destroyRoot(existingBlock2.root);
2571
- removeNodes(existingBlock2.nodes);
2670
+ const existingBlock = newBlocks.get(key);
2671
+ if (existingBlock) {
2672
+ destroyRoot(existingBlock.root);
2673
+ removeNodes(existingBlock.nodes);
2572
2674
  }
2573
2675
  block = createKeyedBlock(key, item, index, renderItem, needsIndex, hostRoot);
2676
+ createdBlocks.push(block);
2574
2677
  }
2575
2678
  const resolvedBlock = block;
2576
2679
  newBlocks.set(key, resolvedBlock);
2577
2680
  const position = orderedIndexByKey.get(key);
2578
2681
  if (position !== void 0) {
2579
2682
  appendCandidate = false;
2580
- }
2581
- if (appendCandidate) {
2582
- if (index < prevCount) {
2583
- if (!prevOrderedBlocks[index] || prevOrderedBlocks[index].key !== key) {
2584
- appendCandidate = false;
2585
- }
2586
- } else if (existed) {
2587
- appendCandidate = false;
2588
- }
2589
- }
2590
- if (position !== void 0) {
2591
2683
  const prior = nextOrderedBlocks[position];
2592
2684
  if (prior && prior !== resolvedBlock) {
2593
2685
  destroyRoot(prior.root);
@@ -2595,6 +2687,15 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2595
2687
  }
2596
2688
  nextOrderedBlocks[position] = resolvedBlock;
2597
2689
  } else {
2690
+ if (appendCandidate) {
2691
+ if (index < prevCount) {
2692
+ if (!prevOrderedBlocks[index] || prevOrderedBlocks[index].key !== key) {
2693
+ appendCandidate = false;
2694
+ }
2695
+ } else if (existed) {
2696
+ appendCandidate = false;
2697
+ }
2698
+ }
2598
2699
  orderedIndexByKey.set(key, nextOrderedBlocks.length);
2599
2700
  nextOrderedBlocks.push(resolvedBlock);
2600
2701
  }
@@ -2623,6 +2724,11 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2623
2724
  container.nextBlocks = oldBlocks;
2624
2725
  container.orderedBlocks = nextOrderedBlocks;
2625
2726
  container.nextOrderedBlocks = prevOrderedBlocks;
2727
+ for (const block of createdBlocks) {
2728
+ if (newBlocks.get(block.key) === block) {
2729
+ flushOnMount(block.root);
2730
+ }
2731
+ }
2626
2732
  return;
2627
2733
  }
2628
2734
  if (oldBlocks.size > 0) {
@@ -2652,22 +2758,87 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2652
2758
  container.nextBlocks = oldBlocks;
2653
2759
  container.orderedBlocks = nextOrderedBlocks;
2654
2760
  container.nextOrderedBlocks = prevOrderedBlocks;
2761
+ for (const block of createdBlocks) {
2762
+ if (newBlocks.get(block.key) === block) {
2763
+ flushOnMount(block.root);
2764
+ }
2765
+ }
2655
2766
  });
2656
2767
  };
2657
- const effectDispose = createRenderEffect(performDiff);
2768
+ const disconnectObserver = () => {
2769
+ connectObserver?.disconnect();
2770
+ connectObserver = null;
2771
+ };
2772
+ const ensureEffectStarted = () => {
2773
+ if (disposed || effectStarted) return effectStarted;
2774
+ const parent = getConnectedParent();
2775
+ if (!parent) return false;
2776
+ const start = () => {
2777
+ effectDispose = createRenderEffect(performDiff);
2778
+ effectStarted = true;
2779
+ };
2780
+ if (hostRoot) {
2781
+ const prev = pushRoot(hostRoot);
2782
+ try {
2783
+ start();
2784
+ } finally {
2785
+ popRoot(prev);
2786
+ }
2787
+ } else {
2788
+ start();
2789
+ }
2790
+ return true;
2791
+ };
2792
+ const waitForConnection = () => {
2793
+ if (connectObserver || typeof MutationObserver === "undefined") return;
2794
+ connectObserver = new MutationObserver(() => {
2795
+ if (disposed) return;
2796
+ if (getConnectedParent()) {
2797
+ disconnectObserver();
2798
+ if (ensureEffectStarted()) {
2799
+ flush();
2800
+ }
2801
+ }
2802
+ });
2803
+ connectObserver.observe(document, { childList: true, subtree: true });
2804
+ };
2805
+ const scheduleStart = () => {
2806
+ if (startScheduled || disposed || effectStarted) return;
2807
+ startScheduled = true;
2808
+ const run = () => {
2809
+ startScheduled = false;
2810
+ if (!ensureEffectStarted()) {
2811
+ waitForConnection();
2812
+ }
2813
+ };
2814
+ if (typeof queueMicrotask === "function") {
2815
+ queueMicrotask(run);
2816
+ } else {
2817
+ Promise.resolve().then(run).catch(() => void 0);
2818
+ }
2819
+ };
2820
+ scheduleStart();
2658
2821
  return {
2659
- marker: fragment,
2822
+ get marker() {
2823
+ scheduleStart();
2824
+ return fragment;
2825
+ },
2660
2826
  startMarker: container.startMarker,
2661
2827
  endMarker: container.endMarker,
2662
2828
  // Flush pending items - call after markers are inserted into DOM
2663
2829
  flush: () => {
2664
- if (pendingItems !== null) {
2665
- performDiff();
2830
+ if (disposed) return;
2831
+ scheduleStart();
2832
+ if (ensureEffectStarted()) {
2833
+ flush();
2834
+ } else {
2835
+ waitForConnection();
2666
2836
  }
2667
2837
  },
2668
2838
  dispose: () => {
2669
2839
  disposed = true;
2670
2840
  effectDispose?.();
2841
+ disconnectObserver();
2671
2842
  container.dispose();
2672
2843
  }
2673
2844
  };
@@ -2870,8 +3041,17 @@ function createClassBinding(el, value) {
2870
3041
  }
2871
3042
  function bindClass(el, getValue) {
2872
3043
  let prev = {};
3044
+ let prevString;
2873
3045
  return createRenderEffect(() => {
2874
3046
  const next = getValue();
3047
+ if (typeof next === "string") {
3048
+ if (next === prevString) return;
3049
+ prevString = next;
3050
+ el.className = next;
3051
+ prev = {};
3052
+ return;
3053
+ }
3054
+ prevString = void 0;
2875
3055
  prev = applyClass(el, next, prev);
2876
3056
  });
2877
3057
  }
@@ -3100,11 +3280,19 @@ function clearDelegatedEvents(doc = window.document) {
3100
3280
  }
3101
3281
  }
3102
3282
  function globalEventHandler(e) {
3103
- let node = e.target;
3283
+ const asNode = (value) => value && typeof value.nodeType === "number" ? value : null;
3284
+ const asElement = (value) => {
3285
+ const n = asNode(value);
3286
+ if (!n) return null;
3287
+ if (n.nodeType === 1) return n;
3288
+ return n.parentElement;
3289
+ };
3290
+ let node = asElement(e.target);
3104
3291
  const key = `$$${e.type}`;
3105
3292
  const dataKey = `${key}Data`;
3106
3293
  const oriTarget = e.target;
3107
3294
  const oriCurrentTarget = e.currentTarget;
3295
+ let lastHandled = null;
3108
3296
  const retarget = (value) => Object.defineProperty(e, "target", {
3109
3297
  configurable: true,
3110
3298
  value
@@ -3127,23 +3315,28 @@ function globalEventHandler(e) {
3127
3315
  const rawData = node[dataKey];
3128
3316
  const hasData = rawData !== void 0;
3129
3317
  const resolvedNodeData = hasData ? resolveData(rawData) : void 0;
3130
- if (typeof handler === "function") {
3131
- callEventHandler(handler, e, node, hasData ? resolvedNodeData : void 0);
3132
- } else if (Array.isArray(handler)) {
3133
- const tupleData = resolveData(handler[1]);
3134
- callEventHandler(handler[0], e, node, tupleData);
3135
- }
3318
+ batch2(() => {
3319
+ if (typeof handler === "function") {
3320
+ callEventHandler(handler, e, node, hasData ? resolvedNodeData : void 0);
3321
+ } else if (Array.isArray(handler)) {
3322
+ const tupleData = resolveData(handler[1]);
3323
+ callEventHandler(handler[0], e, node, tupleData);
3324
+ }
3325
+ });
3136
3326
  if (e.cancelBubble) return false;
3137
3327
  }
3138
3328
  const shadowHost = node.host;
3139
- if (shadowHost && typeof shadowHost !== "string" && !shadowHost._$host && node.contains(e.target)) {
3329
+ if (shadowHost && typeof shadowHost !== "string" && !shadowHost._$host && (() => {
3330
+ const targetNode = asNode(e.target);
3331
+ return targetNode ? node.contains(targetNode) : false;
3332
+ })()) {
3140
3333
  retarget(shadowHost);
3141
3334
  }
3142
3335
  return true;
3143
3336
  };
3144
3337
  const walkUpTree = () => {
3145
3338
  while (handleNode() && node) {
3146
- node = node._$host || node.parentNode || node.host;
3339
+ node = asElement(node._$host || node.parentNode || node.host);
3147
3340
  }
3148
3341
  };
3149
3342
  Object.defineProperty(e, "currentTarget", {
@@ -3156,8 +3349,11 @@ function globalEventHandler(e) {
3156
3349
  const path = e.composedPath();
3157
3350
  retarget(path[0]);
3158
3351
  for (let i = 0; i < path.length - 2; i++) {
3159
- node = path[i];
3352
+ const nextNode = asElement(path[i]);
3353
+ if (!nextNode || nextNode === lastHandled) continue;
3354
+ node = nextNode;
3160
3355
  if (!handleNode()) break;
3356
+ lastHandled = node;
3161
3357
  if (node._$host) {
3162
3358
  node = node._$host;
3163
3359
  walkUpTree();