@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/slim.cjs CHANGED
@@ -307,6 +307,7 @@ var lowPriorityQueue = [];
307
307
  var enqueueMicrotask = typeof queueMicrotask === "function" ? queueMicrotask : (fn) => {
308
308
  Promise.resolve().then(fn);
309
309
  };
310
+ var inCleanup = false;
310
311
  function link(dep, sub, version) {
311
312
  const prevDep = sub.depsTail;
312
313
  if (prevDep !== void 0 && prevDep.dep === dep) return;
@@ -552,7 +553,15 @@ function updateComputed(c) {
552
553
  }
553
554
  function runEffect(e) {
554
555
  const flags = e.flags;
555
- if (flags & Dirty || flags & Pending && e.deps && checkDirty(e.deps, e)) {
556
+ if (flags & Dirty) {
557
+ if (e.runCleanup) {
558
+ inCleanup = true;
559
+ try {
560
+ e.runCleanup();
561
+ } finally {
562
+ inCleanup = false;
563
+ }
564
+ }
556
565
  ++cycle;
557
566
  effectRunDevtools(e);
558
567
  e.depsTail = void 0;
@@ -569,6 +578,35 @@ function runEffect(e) {
569
578
  e.flags = Watching;
570
579
  throw err;
571
580
  }
581
+ } else if (flags & Pending && e.deps) {
582
+ if (e.runCleanup) {
583
+ inCleanup = true;
584
+ try {
585
+ e.runCleanup();
586
+ } finally {
587
+ inCleanup = false;
588
+ }
589
+ }
590
+ if (checkDirty(e.deps, e)) {
591
+ ++cycle;
592
+ effectRunDevtools(e);
593
+ e.depsTail = void 0;
594
+ e.flags = WatchingRunning;
595
+ const prevSub = activeSub;
596
+ activeSub = e;
597
+ try {
598
+ e.fn();
599
+ activeSub = prevSub;
600
+ e.flags = Watching;
601
+ purgeDeps(e);
602
+ } catch (err) {
603
+ activeSub = prevSub;
604
+ e.flags = Watching;
605
+ throw err;
606
+ }
607
+ } else {
608
+ e.flags = Watching;
609
+ }
572
610
  } else {
573
611
  e.flags = Watching;
574
612
  }
@@ -664,7 +702,7 @@ function signalOper(value) {
664
702
  return;
665
703
  }
666
704
  const flags = this.flags;
667
- if (flags & Dirty) {
705
+ if (flags & Dirty && !inCleanup) {
668
706
  if (updateSignal(this)) {
669
707
  const subs = this.subs;
670
708
  if (subs !== void 0) shallowPropagate(subs);
@@ -746,6 +784,30 @@ function effect(fn) {
746
784
  }
747
785
  return effectOper.bind(e);
748
786
  }
787
+ function effectWithCleanup(fn, cleanupRunner) {
788
+ const e = {
789
+ fn,
790
+ subs: void 0,
791
+ subsTail: void 0,
792
+ deps: void 0,
793
+ depsTail: void 0,
794
+ flags: WatchingRunning,
795
+ runCleanup: cleanupRunner,
796
+ __id: void 0
797
+ };
798
+ registerEffectDevtools(e);
799
+ const prevSub = activeSub;
800
+ if (prevSub !== void 0) link(e, prevSub, 0);
801
+ activeSub = e;
802
+ try {
803
+ effectRunDevtools(e);
804
+ fn();
805
+ } finally {
806
+ activeSub = prevSub;
807
+ e.flags &= ~Running;
808
+ }
809
+ return effectOper.bind(e);
810
+ }
749
811
  function effectOper() {
750
812
  disposeNode(this);
751
813
  }
@@ -766,10 +828,17 @@ function effectScopeOper() {
766
828
  }
767
829
  function batch(fn) {
768
830
  ++batchDepth;
831
+ let hasError = false;
769
832
  try {
770
833
  return fn();
834
+ } catch (e) {
835
+ hasError = true;
836
+ throw e;
771
837
  } finally {
772
- if (--batchDepth === 0) flush();
838
+ --batchDepth;
839
+ if (!hasError && batchDepth === 0) {
840
+ flush();
841
+ }
773
842
  }
774
843
  }
775
844
  function setActiveSub(sub) {
@@ -820,7 +889,7 @@ function effectRunDevtools(node) {
820
889
  function createSelector(source, equalityFn = (a, b) => a === b) {
821
890
  let current = source();
822
891
  const observers = /* @__PURE__ */ new Map();
823
- effect(() => {
892
+ const dispose = effect(() => {
824
893
  const next = source();
825
894
  if (equalityFn(current, next)) return;
826
895
  const prevSig = observers.get(current);
@@ -829,6 +898,10 @@ function createSelector(source, equalityFn = (a, b) => a === b) {
829
898
  if (nextSig) nextSig(true);
830
899
  current = next;
831
900
  });
901
+ registerRootCleanup(() => {
902
+ dispose();
903
+ observers.clear();
904
+ });
832
905
  return (key) => {
833
906
  let sig = observers.get(key);
834
907
  if (!sig) {
@@ -849,8 +922,11 @@ function createMemo(fn) {
849
922
  function createEffect(fn) {
850
923
  let cleanups = [];
851
924
  const rootForError = getCurrentRoot();
852
- const run = () => {
925
+ const doCleanup = () => {
853
926
  runCleanupList(cleanups);
927
+ cleanups = [];
928
+ };
929
+ const run = () => {
854
930
  const bucket = [];
855
931
  withEffectCleanups(bucket, () => {
856
932
  try {
@@ -867,7 +943,7 @@ function createEffect(fn) {
867
943
  });
868
944
  cleanups = bucket;
869
945
  };
870
- const disposeEffect = effect(run);
946
+ const disposeEffect = effectWithCleanup(run, doCleanup);
871
947
  const teardown = () => {
872
948
  runCleanupList(cleanups);
873
949
  disposeEffect();
@@ -878,24 +954,27 @@ function createEffect(fn) {
878
954
  function createRenderEffect(fn) {
879
955
  let cleanup;
880
956
  const rootForError = getCurrentRoot();
881
- const run = () => {
957
+ const doCleanup = () => {
882
958
  if (cleanup) {
883
959
  cleanup();
884
960
  cleanup = void 0;
885
961
  }
962
+ };
963
+ const run = () => {
886
964
  try {
887
965
  const maybeCleanup = fn();
888
966
  if (typeof maybeCleanup === "function") {
889
967
  cleanup = maybeCleanup;
890
968
  }
891
969
  } catch (err) {
892
- if (handleError(err, { source: "effect" }, rootForError)) {
970
+ const handled = handleError(err, { source: "effect" }, rootForError);
971
+ if (handled) {
893
972
  return;
894
973
  }
895
974
  throw err;
896
975
  }
897
976
  };
898
- const disposeEffect = effect(run);
977
+ const disposeEffect = effectWithCleanup(run, doCleanup);
899
978
  const teardown = () => {
900
979
  if (cleanup) {
901
980
  cleanup();
@@ -1281,159 +1360,22 @@ var UnitlessStyles = /* @__PURE__ */ new Set([
1281
1360
  // src/jsx.ts
1282
1361
  var Fragment = Symbol("Fragment");
1283
1362
 
1284
- // src/node-ops.ts
1285
- function toNodeArray(node) {
1286
- try {
1287
- if (Array.isArray(node)) {
1288
- let allNodes = true;
1289
- for (const item of node) {
1290
- let isItemNode = false;
1291
- try {
1292
- isItemNode = item instanceof Node;
1293
- } catch {
1294
- isItemNode = false;
1295
- }
1296
- if (!isItemNode) {
1297
- allNodes = false;
1298
- break;
1299
- }
1300
- }
1301
- if (allNodes) {
1302
- return node;
1303
- }
1304
- const result = [];
1305
- for (const item of node) {
1306
- result.push(...toNodeArray(item));
1307
- }
1308
- return result;
1309
- }
1310
- if (node === null || node === void 0 || node === false) {
1311
- return [];
1312
- }
1313
- } catch {
1314
- return [];
1315
- }
1316
- let isNode = false;
1317
- try {
1318
- isNode = node instanceof Node;
1319
- } catch {
1320
- isNode = false;
1321
- }
1322
- if (isNode) {
1323
- try {
1324
- if (node instanceof DocumentFragment) {
1325
- return Array.from(node.childNodes);
1326
- }
1327
- } catch {
1328
- }
1329
- return [node];
1330
- }
1331
- try {
1332
- if (typeof node === "object" && node !== null && "marker" in node) {
1333
- return toNodeArray(node.marker);
1334
- }
1335
- } catch {
1336
- }
1337
- try {
1338
- return [document.createTextNode(String(node))];
1339
- } catch {
1340
- return [document.createTextNode("")];
1341
- }
1342
- }
1343
- function insertNodesBefore(parent, nodes, anchor) {
1344
- if (nodes.length === 0) return;
1345
- if (nodes.length === 1) {
1346
- const node = nodes[0];
1347
- if (node === void 0 || node === null) return;
1348
- if (node.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {
1349
- parent.ownerDocument.adoptNode(node);
1350
- }
1351
- try {
1352
- parent.insertBefore(node, anchor);
1353
- } catch (e) {
1354
- if (parent.ownerDocument) {
1355
- try {
1356
- const clone = parent.ownerDocument.importNode(node, true);
1357
- parent.insertBefore(clone, anchor);
1358
- return;
1359
- } catch {
1360
- }
1361
- }
1362
- throw e;
1363
- }
1364
- return;
1365
- }
1366
- const doc = parent.ownerDocument;
1367
- if (doc) {
1368
- const frag = doc.createDocumentFragment();
1369
- for (let i = 0; i < nodes.length; i++) {
1370
- const node = nodes[i];
1371
- if (node === void 0 || node === null) continue;
1372
- if (node.nodeType === 11) {
1373
- const childrenArr = Array.from(node.childNodes);
1374
- for (let j = 0; j < childrenArr.length; j++) {
1375
- frag.appendChild(childrenArr[j]);
1376
- }
1377
- } else {
1378
- if (node.ownerDocument !== doc) {
1379
- doc.adoptNode(node);
1380
- }
1381
- frag.appendChild(node);
1382
- }
1383
- }
1384
- parent.insertBefore(frag, anchor);
1385
- return;
1386
- }
1387
- const insertSingle = (nodeToInsert, anchorNode) => {
1388
- if (nodeToInsert.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {
1389
- parent.ownerDocument.adoptNode(nodeToInsert);
1390
- }
1391
- try {
1392
- parent.insertBefore(nodeToInsert, anchorNode);
1393
- return nodeToInsert;
1394
- } catch (e) {
1395
- if (parent.ownerDocument) {
1396
- try {
1397
- const clone = parent.ownerDocument.importNode(nodeToInsert, true);
1398
- parent.insertBefore(clone, anchorNode);
1399
- return clone;
1400
- } catch {
1401
- }
1402
- }
1403
- throw e;
1404
- }
1405
- };
1406
- for (let i = nodes.length - 1; i >= 0; i--) {
1407
- const node = nodes[i];
1408
- if (node === void 0 || node === null) continue;
1409
- const isFrag = node.nodeType === 11;
1410
- if (isFrag) {
1411
- const childrenArr = Array.from(node.childNodes);
1412
- for (let j = childrenArr.length - 1; j >= 0; j--) {
1413
- const child = childrenArr[j];
1414
- anchor = insertSingle(child, anchor);
1415
- }
1416
- } else {
1417
- anchor = insertSingle(node, anchor);
1418
- }
1419
- }
1420
- }
1421
- function removeNodes(nodes) {
1422
- for (const node of nodes) {
1423
- node.parentNode?.removeChild(node);
1424
- }
1425
- }
1426
-
1427
1363
  // src/hooks.ts
1428
1364
  var ctxStack = [];
1365
+ function assertRenderContext(ctx, hookName) {
1366
+ if (!ctx.rendering) {
1367
+ throw new Error(`${hookName} can only be used during render execution`);
1368
+ }
1369
+ }
1429
1370
  function __fictUseContext() {
1430
1371
  if (ctxStack.length === 0) {
1431
- const ctx2 = { slots: [], cursor: 0 };
1372
+ const ctx2 = { slots: [], cursor: 0, rendering: true };
1432
1373
  ctxStack.push(ctx2);
1433
1374
  return ctx2;
1434
1375
  }
1435
1376
  const ctx = ctxStack[ctxStack.length - 1];
1436
1377
  ctx.cursor = 0;
1378
+ ctx.rendering = true;
1437
1379
  return ctx;
1438
1380
  }
1439
1381
  function __fictPushContext() {
@@ -1448,6 +1390,7 @@ function __fictResetContext() {
1448
1390
  ctxStack.length = 0;
1449
1391
  }
1450
1392
  function __fictUseSignal(ctx, initial, slot) {
1393
+ assertRenderContext(ctx, "__fictUseSignal");
1451
1394
  const index = slot ?? ctx.cursor++;
1452
1395
  if (!ctx.slots[index]) {
1453
1396
  ctx.slots[index] = signal(initial);
@@ -1455,6 +1398,7 @@ function __fictUseSignal(ctx, initial, slot) {
1455
1398
  return ctx.slots[index];
1456
1399
  }
1457
1400
  function __fictUseMemo(ctx, fn, slot) {
1401
+ assertRenderContext(ctx, "__fictUseMemo");
1458
1402
  const index = slot ?? ctx.cursor++;
1459
1403
  if (!ctx.slots[index]) {
1460
1404
  ctx.slots[index] = createMemo(fn);
@@ -1462,6 +1406,7 @@ function __fictUseMemo(ctx, fn, slot) {
1462
1406
  return ctx.slots[index];
1463
1407
  }
1464
1408
  function __fictUseEffect(ctx, fn, slot) {
1409
+ assertRenderContext(ctx, "__fictUseEffect");
1465
1410
  const index = slot ?? ctx.cursor++;
1466
1411
  if (!ctx.slots[index]) {
1467
1412
  ctx.slots[index] = createEffect(fn);
@@ -1470,9 +1415,11 @@ function __fictUseEffect(ctx, fn, slot) {
1470
1415
  function __fictRender(ctx, fn) {
1471
1416
  ctxStack.push(ctx);
1472
1417
  ctx.cursor = 0;
1418
+ ctx.rendering = true;
1473
1419
  try {
1474
1420
  return fn();
1475
1421
  } finally {
1422
+ ctx.rendering = false;
1476
1423
  ctxStack.pop();
1477
1424
  }
1478
1425
  }
@@ -1675,6 +1622,14 @@ function createElementWithContext(node, namespace) {
1675
1622
  if (typeof handle.dispose === "function") {
1676
1623
  registerRootCleanup(handle.dispose);
1677
1624
  }
1625
+ if (typeof handle.flush === "function") {
1626
+ const runFlush = () => handle.flush && handle.flush();
1627
+ if (typeof queueMicrotask === "function") {
1628
+ queueMicrotask(runFlush);
1629
+ } else {
1630
+ Promise.resolve().then(runFlush).catch(() => void 0);
1631
+ }
1632
+ }
1678
1633
  return createElement(handle.marker);
1679
1634
  }
1680
1635
  const nodeRecord = node;
@@ -1722,18 +1677,18 @@ function createElementWithContext(node, namespace) {
1722
1677
  }
1723
1678
  });
1724
1679
  const props = createPropsProxy(baseProps);
1680
+ __fictPushContext();
1725
1681
  try {
1726
- __fictPushContext();
1727
1682
  const rendered = vnode.type(props);
1728
- __fictPopContext();
1729
1683
  return createElementWithContext(rendered, namespace);
1730
1684
  } catch (err) {
1731
- __fictPopContext();
1732
1685
  if (handleSuspend(err)) {
1733
1686
  return document.createComment("fict:suspend");
1734
1687
  }
1735
1688
  handleError(err, { source: "render", componentName: vnode.type.name });
1736
1689
  throw err;
1690
+ } finally {
1691
+ __fictPopContext();
1737
1692
  }
1738
1693
  }
1739
1694
  if (vnode.type === Fragment) {
@@ -2025,6 +1980,149 @@ function eventNameFromProp(key) {
2025
1980
  return key.slice(2).toLowerCase();
2026
1981
  }
2027
1982
 
1983
+ // src/node-ops.ts
1984
+ function toNodeArray(node) {
1985
+ try {
1986
+ if (Array.isArray(node)) {
1987
+ let allNodes = true;
1988
+ for (const item of node) {
1989
+ let isItemNode = false;
1990
+ try {
1991
+ isItemNode = item instanceof Node;
1992
+ } catch {
1993
+ isItemNode = false;
1994
+ }
1995
+ if (!isItemNode) {
1996
+ allNodes = false;
1997
+ break;
1998
+ }
1999
+ }
2000
+ if (allNodes) {
2001
+ return node;
2002
+ }
2003
+ const result = [];
2004
+ for (const item of node) {
2005
+ result.push(...toNodeArray(item));
2006
+ }
2007
+ return result;
2008
+ }
2009
+ if (node === null || node === void 0 || node === false) {
2010
+ return [];
2011
+ }
2012
+ } catch {
2013
+ return [];
2014
+ }
2015
+ let isNode = false;
2016
+ try {
2017
+ isNode = node instanceof Node;
2018
+ } catch {
2019
+ isNode = false;
2020
+ }
2021
+ if (isNode) {
2022
+ try {
2023
+ if (node instanceof DocumentFragment) {
2024
+ return Array.from(node.childNodes);
2025
+ }
2026
+ } catch {
2027
+ }
2028
+ return [node];
2029
+ }
2030
+ try {
2031
+ if (typeof node === "object" && node !== null && "marker" in node) {
2032
+ return toNodeArray(node.marker);
2033
+ }
2034
+ } catch {
2035
+ }
2036
+ try {
2037
+ return [document.createTextNode(String(node))];
2038
+ } catch {
2039
+ return [document.createTextNode("")];
2040
+ }
2041
+ }
2042
+ function insertNodesBefore(parent, nodes, anchor) {
2043
+ if (nodes.length === 0) return;
2044
+ if (nodes.length === 1) {
2045
+ const node = nodes[0];
2046
+ if (node === void 0 || node === null) return;
2047
+ if (node.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {
2048
+ parent.ownerDocument.adoptNode(node);
2049
+ }
2050
+ try {
2051
+ parent.insertBefore(node, anchor);
2052
+ } catch (e) {
2053
+ if (parent.ownerDocument) {
2054
+ try {
2055
+ const clone = parent.ownerDocument.importNode(node, true);
2056
+ parent.insertBefore(clone, anchor);
2057
+ return;
2058
+ } catch {
2059
+ }
2060
+ }
2061
+ throw e;
2062
+ }
2063
+ return;
2064
+ }
2065
+ const doc = parent.ownerDocument;
2066
+ if (doc) {
2067
+ const frag = doc.createDocumentFragment();
2068
+ for (let i = 0; i < nodes.length; i++) {
2069
+ const node = nodes[i];
2070
+ if (node === void 0 || node === null) continue;
2071
+ if (node.nodeType === 11) {
2072
+ const childrenArr = Array.from(node.childNodes);
2073
+ for (let j = 0; j < childrenArr.length; j++) {
2074
+ frag.appendChild(childrenArr[j]);
2075
+ }
2076
+ } else {
2077
+ if (node.ownerDocument !== doc) {
2078
+ doc.adoptNode(node);
2079
+ }
2080
+ frag.appendChild(node);
2081
+ }
2082
+ }
2083
+ parent.insertBefore(frag, anchor);
2084
+ return;
2085
+ }
2086
+ const insertSingle = (nodeToInsert, anchorNode) => {
2087
+ if (nodeToInsert.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {
2088
+ parent.ownerDocument.adoptNode(nodeToInsert);
2089
+ }
2090
+ try {
2091
+ parent.insertBefore(nodeToInsert, anchorNode);
2092
+ return nodeToInsert;
2093
+ } catch (e) {
2094
+ if (parent.ownerDocument) {
2095
+ try {
2096
+ const clone = parent.ownerDocument.importNode(nodeToInsert, true);
2097
+ parent.insertBefore(clone, anchorNode);
2098
+ return clone;
2099
+ } catch {
2100
+ }
2101
+ }
2102
+ throw e;
2103
+ }
2104
+ };
2105
+ for (let i = nodes.length - 1; i >= 0; i--) {
2106
+ const node = nodes[i];
2107
+ if (node === void 0 || node === null) continue;
2108
+ const isFrag = node.nodeType === 11;
2109
+ if (isFrag) {
2110
+ const childrenArr = Array.from(node.childNodes);
2111
+ for (let j = childrenArr.length - 1; j >= 0; j--) {
2112
+ const child = childrenArr[j];
2113
+ anchor = insertSingle(child, anchor);
2114
+ }
2115
+ } else {
2116
+ anchor = insertSingle(node, anchor);
2117
+ }
2118
+ }
2119
+ }
2120
+ function removeNodes(nodes) {
2121
+ for (const node of nodes) {
2122
+ node.parentNode?.removeChild(node);
2123
+ }
2124
+ }
2125
+
2028
2126
  // src/reconcile.ts
2029
2127
  function reconcileArrays(parentNode, a, b) {
2030
2128
  const bLength = b.length;
@@ -2252,7 +2350,6 @@ function createKeyedBlock(key, item, index, render2, needsIndex = true, hostRoot
2252
2350
  } finally {
2253
2351
  setActiveSub(prevSub);
2254
2352
  popRoot(prevRoot);
2255
- flushOnMount(root);
2256
2353
  }
2257
2354
  return {
2258
2355
  key,
@@ -2276,13 +2373,24 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2276
2373
  const hostRoot = getCurrentRoot();
2277
2374
  const fragment = document.createDocumentFragment();
2278
2375
  fragment.append(container.startMarker, container.endMarker);
2279
- let pendingItems = null;
2280
2376
  let disposed = false;
2377
+ let effectDispose;
2378
+ let connectObserver = null;
2379
+ let effectStarted = false;
2380
+ let startScheduled = false;
2381
+ const getConnectedParent = () => {
2382
+ const endParent = container.endMarker.parentNode;
2383
+ const startParent = container.startMarker.parentNode;
2384
+ if (endParent && startParent && endParent === startParent && endParent.nodeType !== 11) {
2385
+ return endParent;
2386
+ }
2387
+ return null;
2388
+ };
2281
2389
  const performDiff = () => {
2282
2390
  if (disposed) return;
2391
+ const parent = getConnectedParent();
2392
+ if (!parent) return;
2283
2393
  batch2(() => {
2284
- const newItems = pendingItems || getItems();
2285
- pendingItems = null;
2286
2394
  const oldBlocks = container.blocks;
2287
2395
  const newBlocks = container.nextBlocks;
2288
2396
  const prevOrderedBlocks = container.orderedBlocks;
@@ -2291,20 +2399,17 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2291
2399
  newBlocks.clear();
2292
2400
  nextOrderedBlocks.length = 0;
2293
2401
  orderedIndexByKey.clear();
2294
- const endParent = container.endMarker.parentNode;
2295
- const startParent = container.startMarker.parentNode;
2296
- const parent = endParent && startParent && endParent === startParent && endParent.isConnected ? endParent : null;
2297
- if (!parent) {
2298
- pendingItems = newItems;
2299
- queueMicrotask(performDiff);
2300
- return;
2301
- }
2402
+ const createdBlocks = [];
2403
+ const newItems = getItems();
2302
2404
  if (newItems.length === 0) {
2303
2405
  if (oldBlocks.size > 0) {
2304
2406
  for (const block of oldBlocks.values()) {
2305
2407
  destroyRoot(block.root);
2306
- removeNodes(block.nodes);
2307
2408
  }
2409
+ const range = document.createRange();
2410
+ range.setStartAfter(container.startMarker);
2411
+ range.setEndBefore(container.endMarker);
2412
+ range.deleteContents();
2308
2413
  }
2309
2414
  oldBlocks.clear();
2310
2415
  newBlocks.clear();
@@ -2321,8 +2426,8 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2321
2426
  const appendedBlocks = [];
2322
2427
  newItems.forEach((item, index) => {
2323
2428
  const key = keyFn(item, index);
2324
- const existed = oldBlocks.has(key);
2325
2429
  let block = oldBlocks.get(key);
2430
+ const existed = block !== void 0;
2326
2431
  if (block) {
2327
2432
  if (block.rawItem !== item) {
2328
2433
  block.rawItem = item;
@@ -2333,38 +2438,23 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2333
2438
  block.index(index);
2334
2439
  }
2335
2440
  }
2336
- const existingBlock = newBlocks.get(key);
2337
- if (existingBlock && existingBlock !== block) {
2338
- destroyRoot(existingBlock.root);
2339
- removeNodes(existingBlock.nodes);
2340
- }
2341
2441
  if (block) {
2342
2442
  newBlocks.set(key, block);
2343
2443
  oldBlocks.delete(key);
2344
2444
  } else {
2345
- const existingBlock2 = newBlocks.get(key);
2346
- if (existingBlock2) {
2347
- destroyRoot(existingBlock2.root);
2348
- removeNodes(existingBlock2.nodes);
2445
+ const existingBlock = newBlocks.get(key);
2446
+ if (existingBlock) {
2447
+ destroyRoot(existingBlock.root);
2448
+ removeNodes(existingBlock.nodes);
2349
2449
  }
2350
2450
  block = createKeyedBlock(key, item, index, renderItem, needsIndex, hostRoot);
2451
+ createdBlocks.push(block);
2351
2452
  }
2352
2453
  const resolvedBlock = block;
2353
2454
  newBlocks.set(key, resolvedBlock);
2354
2455
  const position = orderedIndexByKey.get(key);
2355
2456
  if (position !== void 0) {
2356
2457
  appendCandidate = false;
2357
- }
2358
- if (appendCandidate) {
2359
- if (index < prevCount) {
2360
- if (!prevOrderedBlocks[index] || prevOrderedBlocks[index].key !== key) {
2361
- appendCandidate = false;
2362
- }
2363
- } else if (existed) {
2364
- appendCandidate = false;
2365
- }
2366
- }
2367
- if (position !== void 0) {
2368
2458
  const prior = nextOrderedBlocks[position];
2369
2459
  if (prior && prior !== resolvedBlock) {
2370
2460
  destroyRoot(prior.root);
@@ -2372,6 +2462,15 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2372
2462
  }
2373
2463
  nextOrderedBlocks[position] = resolvedBlock;
2374
2464
  } else {
2465
+ if (appendCandidate) {
2466
+ if (index < prevCount) {
2467
+ if (!prevOrderedBlocks[index] || prevOrderedBlocks[index].key !== key) {
2468
+ appendCandidate = false;
2469
+ }
2470
+ } else if (existed) {
2471
+ appendCandidate = false;
2472
+ }
2473
+ }
2375
2474
  orderedIndexByKey.set(key, nextOrderedBlocks.length);
2376
2475
  nextOrderedBlocks.push(resolvedBlock);
2377
2476
  }
@@ -2400,6 +2499,11 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2400
2499
  container.nextBlocks = oldBlocks;
2401
2500
  container.orderedBlocks = nextOrderedBlocks;
2402
2501
  container.nextOrderedBlocks = prevOrderedBlocks;
2502
+ for (const block of createdBlocks) {
2503
+ if (newBlocks.get(block.key) === block) {
2504
+ flushOnMount(block.root);
2505
+ }
2506
+ }
2403
2507
  return;
2404
2508
  }
2405
2509
  if (oldBlocks.size > 0) {
@@ -2429,22 +2533,87 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2429
2533
  container.nextBlocks = oldBlocks;
2430
2534
  container.orderedBlocks = nextOrderedBlocks;
2431
2535
  container.nextOrderedBlocks = prevOrderedBlocks;
2536
+ for (const block of createdBlocks) {
2537
+ if (newBlocks.get(block.key) === block) {
2538
+ flushOnMount(block.root);
2539
+ }
2540
+ }
2541
+ });
2542
+ };
2543
+ const disconnectObserver = () => {
2544
+ connectObserver?.disconnect();
2545
+ connectObserver = null;
2546
+ };
2547
+ const ensureEffectStarted = () => {
2548
+ if (disposed || effectStarted) return effectStarted;
2549
+ const parent = getConnectedParent();
2550
+ if (!parent) return false;
2551
+ const start = () => {
2552
+ effectDispose = createRenderEffect(performDiff);
2553
+ effectStarted = true;
2554
+ };
2555
+ if (hostRoot) {
2556
+ const prev = pushRoot(hostRoot);
2557
+ try {
2558
+ start();
2559
+ } finally {
2560
+ popRoot(prev);
2561
+ }
2562
+ } else {
2563
+ start();
2564
+ }
2565
+ return true;
2566
+ };
2567
+ const waitForConnection = () => {
2568
+ if (connectObserver || typeof MutationObserver === "undefined") return;
2569
+ connectObserver = new MutationObserver(() => {
2570
+ if (disposed) return;
2571
+ if (getConnectedParent()) {
2572
+ disconnectObserver();
2573
+ if (ensureEffectStarted()) {
2574
+ flush();
2575
+ }
2576
+ }
2432
2577
  });
2578
+ connectObserver.observe(document, { childList: true, subtree: true });
2579
+ };
2580
+ const scheduleStart = () => {
2581
+ if (startScheduled || disposed || effectStarted) return;
2582
+ startScheduled = true;
2583
+ const run = () => {
2584
+ startScheduled = false;
2585
+ if (!ensureEffectStarted()) {
2586
+ waitForConnection();
2587
+ }
2588
+ };
2589
+ if (typeof queueMicrotask === "function") {
2590
+ queueMicrotask(run);
2591
+ } else {
2592
+ Promise.resolve().then(run).catch(() => void 0);
2593
+ }
2433
2594
  };
2434
- const effectDispose = createRenderEffect(performDiff);
2595
+ scheduleStart();
2435
2596
  return {
2436
- marker: fragment,
2597
+ get marker() {
2598
+ scheduleStart();
2599
+ return fragment;
2600
+ },
2437
2601
  startMarker: container.startMarker,
2438
2602
  endMarker: container.endMarker,
2439
2603
  // Flush pending items - call after markers are inserted into DOM
2440
2604
  flush: () => {
2441
- if (pendingItems !== null) {
2442
- performDiff();
2605
+ if (disposed) return;
2606
+ scheduleStart();
2607
+ if (ensureEffectStarted()) {
2608
+ flush();
2609
+ } else {
2610
+ waitForConnection();
2443
2611
  }
2444
2612
  },
2445
2613
  dispose: () => {
2446
2614
  disposed = true;
2447
2615
  effectDispose?.();
2616
+ disconnectObserver();
2448
2617
  container.dispose();
2449
2618
  }
2450
2619
  };
@@ -2616,8 +2785,17 @@ function createClassBinding(el, value) {
2616
2785
  }
2617
2786
  function bindClass(el, getValue) {
2618
2787
  let prev = {};
2788
+ let prevString;
2619
2789
  return createRenderEffect(() => {
2620
2790
  const next = getValue();
2791
+ if (typeof next === "string") {
2792
+ if (next === prevString) return;
2793
+ prevString = next;
2794
+ el.className = next;
2795
+ prev = {};
2796
+ return;
2797
+ }
2798
+ prevString = void 0;
2621
2799
  prev = applyClass(el, next, prev);
2622
2800
  });
2623
2801
  }
@@ -2843,11 +3021,19 @@ function clearDelegatedEvents(doc = window.document) {
2843
3021
  }
2844
3022
  }
2845
3023
  function globalEventHandler(e) {
2846
- let node = e.target;
3024
+ const asNode = (value) => value && typeof value.nodeType === "number" ? value : null;
3025
+ const asElement = (value) => {
3026
+ const n = asNode(value);
3027
+ if (!n) return null;
3028
+ if (n.nodeType === 1) return n;
3029
+ return n.parentElement;
3030
+ };
3031
+ let node = asElement(e.target);
2847
3032
  const key = `$$${e.type}`;
2848
3033
  const dataKey = `${key}Data`;
2849
3034
  const oriTarget = e.target;
2850
3035
  const oriCurrentTarget = e.currentTarget;
3036
+ let lastHandled = null;
2851
3037
  const retarget = (value) => Object.defineProperty(e, "target", {
2852
3038
  configurable: true,
2853
3039
  value
@@ -2870,23 +3056,28 @@ function globalEventHandler(e) {
2870
3056
  const rawData = node[dataKey];
2871
3057
  const hasData = rawData !== void 0;
2872
3058
  const resolvedNodeData = hasData ? resolveData(rawData) : void 0;
2873
- if (typeof handler === "function") {
2874
- callEventHandler(handler, e, node, hasData ? resolvedNodeData : void 0);
2875
- } else if (Array.isArray(handler)) {
2876
- const tupleData = resolveData(handler[1]);
2877
- callEventHandler(handler[0], e, node, tupleData);
2878
- }
3059
+ batch2(() => {
3060
+ if (typeof handler === "function") {
3061
+ callEventHandler(handler, e, node, hasData ? resolvedNodeData : void 0);
3062
+ } else if (Array.isArray(handler)) {
3063
+ const tupleData = resolveData(handler[1]);
3064
+ callEventHandler(handler[0], e, node, tupleData);
3065
+ }
3066
+ });
2879
3067
  if (e.cancelBubble) return false;
2880
3068
  }
2881
3069
  const shadowHost = node.host;
2882
- if (shadowHost && typeof shadowHost !== "string" && !shadowHost._$host && node.contains(e.target)) {
3070
+ if (shadowHost && typeof shadowHost !== "string" && !shadowHost._$host && (() => {
3071
+ const targetNode = asNode(e.target);
3072
+ return targetNode ? node.contains(targetNode) : false;
3073
+ })()) {
2883
3074
  retarget(shadowHost);
2884
3075
  }
2885
3076
  return true;
2886
3077
  };
2887
3078
  const walkUpTree = () => {
2888
3079
  while (handleNode() && node) {
2889
- node = node._$host || node.parentNode || node.host;
3080
+ node = asElement(node._$host || node.parentNode || node.host);
2890
3081
  }
2891
3082
  };
2892
3083
  Object.defineProperty(e, "currentTarget", {
@@ -2899,8 +3090,11 @@ function globalEventHandler(e) {
2899
3090
  const path = e.composedPath();
2900
3091
  retarget(path[0]);
2901
3092
  for (let i = 0; i < path.length - 2; i++) {
2902
- node = path[i];
3093
+ const nextNode = asElement(path[i]);
3094
+ if (!nextNode || nextNode === lastHandled) continue;
3095
+ node = nextNode;
2903
3096
  if (!handleNode()) break;
3097
+ lastHandled = node;
2904
3098
  if (node._$host) {
2905
3099
  node = node._$host;
2906
3100
  walkUpTree();