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