@fictjs/runtime 0.0.9 → 0.0.10

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
@@ -807,10 +807,17 @@ function effectScopeOper() {
807
807
  }
808
808
  function batch(fn) {
809
809
  ++batchDepth;
810
+ let hasError = false;
810
811
  try {
811
812
  return fn();
813
+ } catch (e) {
814
+ hasError = true;
815
+ throw e;
812
816
  } finally {
813
- if (--batchDepth === 0) flush();
817
+ --batchDepth;
818
+ if (!hasError && batchDepth === 0) {
819
+ flush();
820
+ }
814
821
  }
815
822
  }
816
823
  function setActiveSub(sub) {
@@ -866,7 +873,7 @@ function effectRunDevtools(node) {
866
873
  function createSelector(source, equalityFn = (a, b) => a === b) {
867
874
  let current = source();
868
875
  const observers = /* @__PURE__ */ new Map();
869
- effect(() => {
876
+ const dispose = effect(() => {
870
877
  const next = source();
871
878
  if (equalityFn(current, next)) return;
872
879
  const prevSig = observers.get(current);
@@ -875,6 +882,10 @@ function createSelector(source, equalityFn = (a, b) => a === b) {
875
882
  if (nextSig) nextSig(true);
876
883
  current = next;
877
884
  });
885
+ registerRootCleanup(() => {
886
+ dispose();
887
+ observers.clear();
888
+ });
878
889
  return (key) => {
879
890
  let sig = observers.get(key);
880
891
  if (!sig) {
@@ -1062,7 +1073,8 @@ function createRenderEffect(fn) {
1062
1073
  cleanup = maybeCleanup;
1063
1074
  }
1064
1075
  } catch (err) {
1065
- if (handleError(err, { source: "effect" }, rootForError)) {
1076
+ const handled = handleError(err, { source: "effect" }, rootForError);
1077
+ if (handled) {
1066
1078
  return;
1067
1079
  }
1068
1080
  throw err;
@@ -1454,159 +1466,22 @@ var UnitlessStyles = /* @__PURE__ */ new Set([
1454
1466
  // src/jsx.ts
1455
1467
  var Fragment = Symbol("Fragment");
1456
1468
 
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
1469
  // src/hooks.ts
1601
1470
  var ctxStack = [];
1471
+ function assertRenderContext(ctx, hookName) {
1472
+ if (!ctx.rendering) {
1473
+ throw new Error(`${hookName} can only be used during render execution`);
1474
+ }
1475
+ }
1602
1476
  function __fictUseContext() {
1603
1477
  if (ctxStack.length === 0) {
1604
- const ctx2 = { slots: [], cursor: 0 };
1478
+ const ctx2 = { slots: [], cursor: 0, rendering: true };
1605
1479
  ctxStack.push(ctx2);
1606
1480
  return ctx2;
1607
1481
  }
1608
1482
  const ctx = ctxStack[ctxStack.length - 1];
1609
1483
  ctx.cursor = 0;
1484
+ ctx.rendering = true;
1610
1485
  return ctx;
1611
1486
  }
1612
1487
  function __fictPushContext() {
@@ -1621,6 +1496,7 @@ function __fictResetContext() {
1621
1496
  ctxStack.length = 0;
1622
1497
  }
1623
1498
  function __fictUseSignal(ctx, initial, slot) {
1499
+ assertRenderContext(ctx, "__fictUseSignal");
1624
1500
  const index = slot ?? ctx.cursor++;
1625
1501
  if (!ctx.slots[index]) {
1626
1502
  ctx.slots[index] = signal(initial);
@@ -1628,6 +1504,7 @@ function __fictUseSignal(ctx, initial, slot) {
1628
1504
  return ctx.slots[index];
1629
1505
  }
1630
1506
  function __fictUseMemo(ctx, fn, slot) {
1507
+ assertRenderContext(ctx, "__fictUseMemo");
1631
1508
  const index = slot ?? ctx.cursor++;
1632
1509
  if (!ctx.slots[index]) {
1633
1510
  ctx.slots[index] = createMemo(fn);
@@ -1635,6 +1512,7 @@ function __fictUseMemo(ctx, fn, slot) {
1635
1512
  return ctx.slots[index];
1636
1513
  }
1637
1514
  function __fictUseEffect(ctx, fn, slot) {
1515
+ assertRenderContext(ctx, "__fictUseEffect");
1638
1516
  const index = slot ?? ctx.cursor++;
1639
1517
  if (!ctx.slots[index]) {
1640
1518
  ctx.slots[index] = createEffect(fn);
@@ -1643,9 +1521,11 @@ function __fictUseEffect(ctx, fn, slot) {
1643
1521
  function __fictRender(ctx, fn) {
1644
1522
  ctxStack.push(ctx);
1645
1523
  ctx.cursor = 0;
1524
+ ctx.rendering = true;
1646
1525
  try {
1647
1526
  return fn();
1648
1527
  } finally {
1528
+ ctx.rendering = false;
1649
1529
  ctxStack.pop();
1650
1530
  }
1651
1531
  }
@@ -1886,6 +1766,14 @@ function createElementWithContext(node, namespace) {
1886
1766
  if (typeof handle.dispose === "function") {
1887
1767
  registerRootCleanup(handle.dispose);
1888
1768
  }
1769
+ if (typeof handle.flush === "function") {
1770
+ const runFlush = () => handle.flush && handle.flush();
1771
+ if (typeof queueMicrotask === "function") {
1772
+ queueMicrotask(runFlush);
1773
+ } else {
1774
+ Promise.resolve().then(runFlush).catch(() => void 0);
1775
+ }
1776
+ }
1889
1777
  return createElement(handle.marker);
1890
1778
  }
1891
1779
  const nodeRecord = node;
@@ -1933,18 +1821,18 @@ function createElementWithContext(node, namespace) {
1933
1821
  }
1934
1822
  });
1935
1823
  const props = createPropsProxy(baseProps);
1824
+ __fictPushContext();
1936
1825
  try {
1937
- __fictPushContext();
1938
1826
  const rendered = vnode.type(props);
1939
- __fictPopContext();
1940
1827
  return createElementWithContext(rendered, namespace);
1941
1828
  } catch (err) {
1942
- __fictPopContext();
1943
1829
  if (handleSuspend(err)) {
1944
1830
  return document.createComment("fict:suspend");
1945
1831
  }
1946
1832
  handleError(err, { source: "render", componentName: vnode.type.name });
1947
1833
  throw err;
1834
+ } finally {
1835
+ __fictPopContext();
1948
1836
  }
1949
1837
  }
1950
1838
  if (vnode.type === Fragment) {
@@ -2236,6 +2124,149 @@ function eventNameFromProp(key) {
2236
2124
  return key.slice(2).toLowerCase();
2237
2125
  }
2238
2126
 
2127
+ // src/node-ops.ts
2128
+ function toNodeArray(node) {
2129
+ try {
2130
+ if (Array.isArray(node)) {
2131
+ let allNodes = true;
2132
+ for (const item of node) {
2133
+ let isItemNode = false;
2134
+ try {
2135
+ isItemNode = item instanceof Node;
2136
+ } catch {
2137
+ isItemNode = false;
2138
+ }
2139
+ if (!isItemNode) {
2140
+ allNodes = false;
2141
+ break;
2142
+ }
2143
+ }
2144
+ if (allNodes) {
2145
+ return node;
2146
+ }
2147
+ const result = [];
2148
+ for (const item of node) {
2149
+ result.push(...toNodeArray(item));
2150
+ }
2151
+ return result;
2152
+ }
2153
+ if (node === null || node === void 0 || node === false) {
2154
+ return [];
2155
+ }
2156
+ } catch {
2157
+ return [];
2158
+ }
2159
+ let isNode = false;
2160
+ try {
2161
+ isNode = node instanceof Node;
2162
+ } catch {
2163
+ isNode = false;
2164
+ }
2165
+ if (isNode) {
2166
+ try {
2167
+ if (node instanceof DocumentFragment) {
2168
+ return Array.from(node.childNodes);
2169
+ }
2170
+ } catch {
2171
+ }
2172
+ return [node];
2173
+ }
2174
+ try {
2175
+ if (typeof node === "object" && node !== null && "marker" in node) {
2176
+ return toNodeArray(node.marker);
2177
+ }
2178
+ } catch {
2179
+ }
2180
+ try {
2181
+ return [document.createTextNode(String(node))];
2182
+ } catch {
2183
+ return [document.createTextNode("")];
2184
+ }
2185
+ }
2186
+ function insertNodesBefore(parent, nodes, anchor) {
2187
+ if (nodes.length === 0) return;
2188
+ if (nodes.length === 1) {
2189
+ const node = nodes[0];
2190
+ if (node === void 0 || node === null) return;
2191
+ if (node.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {
2192
+ parent.ownerDocument.adoptNode(node);
2193
+ }
2194
+ try {
2195
+ parent.insertBefore(node, anchor);
2196
+ } catch (e) {
2197
+ if (parent.ownerDocument) {
2198
+ try {
2199
+ const clone = parent.ownerDocument.importNode(node, true);
2200
+ parent.insertBefore(clone, anchor);
2201
+ return;
2202
+ } catch {
2203
+ }
2204
+ }
2205
+ throw e;
2206
+ }
2207
+ return;
2208
+ }
2209
+ const doc = parent.ownerDocument;
2210
+ if (doc) {
2211
+ const frag = doc.createDocumentFragment();
2212
+ for (let i = 0; i < nodes.length; i++) {
2213
+ const node = nodes[i];
2214
+ if (node === void 0 || node === null) continue;
2215
+ if (node.nodeType === 11) {
2216
+ const childrenArr = Array.from(node.childNodes);
2217
+ for (let j = 0; j < childrenArr.length; j++) {
2218
+ frag.appendChild(childrenArr[j]);
2219
+ }
2220
+ } else {
2221
+ if (node.ownerDocument !== doc) {
2222
+ doc.adoptNode(node);
2223
+ }
2224
+ frag.appendChild(node);
2225
+ }
2226
+ }
2227
+ parent.insertBefore(frag, anchor);
2228
+ return;
2229
+ }
2230
+ const insertSingle = (nodeToInsert, anchorNode) => {
2231
+ if (nodeToInsert.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {
2232
+ parent.ownerDocument.adoptNode(nodeToInsert);
2233
+ }
2234
+ try {
2235
+ parent.insertBefore(nodeToInsert, anchorNode);
2236
+ return nodeToInsert;
2237
+ } catch (e) {
2238
+ if (parent.ownerDocument) {
2239
+ try {
2240
+ const clone = parent.ownerDocument.importNode(nodeToInsert, true);
2241
+ parent.insertBefore(clone, anchorNode);
2242
+ return clone;
2243
+ } catch {
2244
+ }
2245
+ }
2246
+ throw e;
2247
+ }
2248
+ };
2249
+ for (let i = nodes.length - 1; i >= 0; i--) {
2250
+ const node = nodes[i];
2251
+ if (node === void 0 || node === null) continue;
2252
+ const isFrag = node.nodeType === 11;
2253
+ if (isFrag) {
2254
+ const childrenArr = Array.from(node.childNodes);
2255
+ for (let j = childrenArr.length - 1; j >= 0; j--) {
2256
+ const child = childrenArr[j];
2257
+ anchor = insertSingle(child, anchor);
2258
+ }
2259
+ } else {
2260
+ anchor = insertSingle(node, anchor);
2261
+ }
2262
+ }
2263
+ }
2264
+ function removeNodes(nodes) {
2265
+ for (const node of nodes) {
2266
+ node.parentNode?.removeChild(node);
2267
+ }
2268
+ }
2269
+
2239
2270
  // src/reconcile.ts
2240
2271
  function reconcileArrays(parentNode, a, b) {
2241
2272
  const bLength = b.length;
@@ -2463,7 +2494,6 @@ function createKeyedBlock(key, item, index, render2, needsIndex = true, hostRoot
2463
2494
  } finally {
2464
2495
  setActiveSub(prevSub);
2465
2496
  popRoot(prevRoot);
2466
- flushOnMount(root);
2467
2497
  }
2468
2498
  return {
2469
2499
  key,
@@ -2495,13 +2525,24 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2495
2525
  const hostRoot = getCurrentRoot();
2496
2526
  const fragment = document.createDocumentFragment();
2497
2527
  fragment.append(container.startMarker, container.endMarker);
2498
- let pendingItems = null;
2499
2528
  let disposed = false;
2529
+ let effectDispose;
2530
+ let connectObserver = null;
2531
+ let effectStarted = false;
2532
+ let startScheduled = false;
2533
+ const getConnectedParent = () => {
2534
+ const endParent = container.endMarker.parentNode;
2535
+ const startParent = container.startMarker.parentNode;
2536
+ if (endParent && startParent && endParent === startParent && endParent.nodeType !== 11) {
2537
+ return endParent;
2538
+ }
2539
+ return null;
2540
+ };
2500
2541
  const performDiff = () => {
2501
2542
  if (disposed) return;
2543
+ const parent = getConnectedParent();
2544
+ if (!parent) return;
2502
2545
  batch2(() => {
2503
- const newItems = pendingItems || getItems();
2504
- pendingItems = null;
2505
2546
  const oldBlocks = container.blocks;
2506
2547
  const newBlocks = container.nextBlocks;
2507
2548
  const prevOrderedBlocks = container.orderedBlocks;
@@ -2510,20 +2551,17 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2510
2551
  newBlocks.clear();
2511
2552
  nextOrderedBlocks.length = 0;
2512
2553
  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
- }
2554
+ const createdBlocks = [];
2555
+ const newItems = getItems();
2521
2556
  if (newItems.length === 0) {
2522
2557
  if (oldBlocks.size > 0) {
2523
2558
  for (const block of oldBlocks.values()) {
2524
2559
  destroyRoot(block.root);
2525
- removeNodes(block.nodes);
2526
2560
  }
2561
+ const range = document.createRange();
2562
+ range.setStartAfter(container.startMarker);
2563
+ range.setEndBefore(container.endMarker);
2564
+ range.deleteContents();
2527
2565
  }
2528
2566
  oldBlocks.clear();
2529
2567
  newBlocks.clear();
@@ -2540,8 +2578,8 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2540
2578
  const appendedBlocks = [];
2541
2579
  newItems.forEach((item, index) => {
2542
2580
  const key = keyFn(item, index);
2543
- const existed = oldBlocks.has(key);
2544
2581
  let block = oldBlocks.get(key);
2582
+ const existed = block !== void 0;
2545
2583
  if (block) {
2546
2584
  if (block.rawItem !== item) {
2547
2585
  block.rawItem = item;
@@ -2552,38 +2590,23 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2552
2590
  block.index(index);
2553
2591
  }
2554
2592
  }
2555
- const existingBlock = newBlocks.get(key);
2556
- if (existingBlock && existingBlock !== block) {
2557
- destroyRoot(existingBlock.root);
2558
- removeNodes(existingBlock.nodes);
2559
- }
2560
2593
  if (block) {
2561
2594
  newBlocks.set(key, block);
2562
2595
  oldBlocks.delete(key);
2563
2596
  } else {
2564
- const existingBlock2 = newBlocks.get(key);
2565
- if (existingBlock2) {
2566
- destroyRoot(existingBlock2.root);
2567
- removeNodes(existingBlock2.nodes);
2597
+ const existingBlock = newBlocks.get(key);
2598
+ if (existingBlock) {
2599
+ destroyRoot(existingBlock.root);
2600
+ removeNodes(existingBlock.nodes);
2568
2601
  }
2569
2602
  block = createKeyedBlock(key, item, index, renderItem, needsIndex, hostRoot);
2603
+ createdBlocks.push(block);
2570
2604
  }
2571
2605
  const resolvedBlock = block;
2572
2606
  newBlocks.set(key, resolvedBlock);
2573
2607
  const position = orderedIndexByKey.get(key);
2574
2608
  if (position !== void 0) {
2575
2609
  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
2610
  const prior = nextOrderedBlocks[position];
2588
2611
  if (prior && prior !== resolvedBlock) {
2589
2612
  destroyRoot(prior.root);
@@ -2591,6 +2614,15 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2591
2614
  }
2592
2615
  nextOrderedBlocks[position] = resolvedBlock;
2593
2616
  } else {
2617
+ if (appendCandidate) {
2618
+ if (index < prevCount) {
2619
+ if (!prevOrderedBlocks[index] || prevOrderedBlocks[index].key !== key) {
2620
+ appendCandidate = false;
2621
+ }
2622
+ } else if (existed) {
2623
+ appendCandidate = false;
2624
+ }
2625
+ }
2594
2626
  orderedIndexByKey.set(key, nextOrderedBlocks.length);
2595
2627
  nextOrderedBlocks.push(resolvedBlock);
2596
2628
  }
@@ -2619,6 +2651,11 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2619
2651
  container.nextBlocks = oldBlocks;
2620
2652
  container.orderedBlocks = nextOrderedBlocks;
2621
2653
  container.nextOrderedBlocks = prevOrderedBlocks;
2654
+ for (const block of createdBlocks) {
2655
+ if (newBlocks.get(block.key) === block) {
2656
+ flushOnMount(block.root);
2657
+ }
2658
+ }
2622
2659
  return;
2623
2660
  }
2624
2661
  if (oldBlocks.size > 0) {
@@ -2648,22 +2685,87 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2648
2685
  container.nextBlocks = oldBlocks;
2649
2686
  container.orderedBlocks = nextOrderedBlocks;
2650
2687
  container.nextOrderedBlocks = prevOrderedBlocks;
2688
+ for (const block of createdBlocks) {
2689
+ if (newBlocks.get(block.key) === block) {
2690
+ flushOnMount(block.root);
2691
+ }
2692
+ }
2651
2693
  });
2652
2694
  };
2653
- const effectDispose = createRenderEffect(performDiff);
2695
+ const disconnectObserver = () => {
2696
+ connectObserver?.disconnect();
2697
+ connectObserver = null;
2698
+ };
2699
+ const ensureEffectStarted = () => {
2700
+ if (disposed || effectStarted) return effectStarted;
2701
+ const parent = getConnectedParent();
2702
+ if (!parent) return false;
2703
+ const start = () => {
2704
+ effectDispose = createRenderEffect(performDiff);
2705
+ effectStarted = true;
2706
+ };
2707
+ if (hostRoot) {
2708
+ const prev = pushRoot(hostRoot);
2709
+ try {
2710
+ start();
2711
+ } finally {
2712
+ popRoot(prev);
2713
+ }
2714
+ } else {
2715
+ start();
2716
+ }
2717
+ return true;
2718
+ };
2719
+ const waitForConnection = () => {
2720
+ if (connectObserver || typeof MutationObserver === "undefined") return;
2721
+ connectObserver = new MutationObserver(() => {
2722
+ if (disposed) return;
2723
+ if (getConnectedParent()) {
2724
+ disconnectObserver();
2725
+ if (ensureEffectStarted()) {
2726
+ flush();
2727
+ }
2728
+ }
2729
+ });
2730
+ connectObserver.observe(document, { childList: true, subtree: true });
2731
+ };
2732
+ const scheduleStart = () => {
2733
+ if (startScheduled || disposed || effectStarted) return;
2734
+ startScheduled = true;
2735
+ const run = () => {
2736
+ startScheduled = false;
2737
+ if (!ensureEffectStarted()) {
2738
+ waitForConnection();
2739
+ }
2740
+ };
2741
+ if (typeof queueMicrotask === "function") {
2742
+ queueMicrotask(run);
2743
+ } else {
2744
+ Promise.resolve().then(run).catch(() => void 0);
2745
+ }
2746
+ };
2747
+ scheduleStart();
2654
2748
  return {
2655
- marker: fragment,
2749
+ get marker() {
2750
+ scheduleStart();
2751
+ return fragment;
2752
+ },
2656
2753
  startMarker: container.startMarker,
2657
2754
  endMarker: container.endMarker,
2658
2755
  // Flush pending items - call after markers are inserted into DOM
2659
2756
  flush: () => {
2660
- if (pendingItems !== null) {
2661
- performDiff();
2757
+ if (disposed) return;
2758
+ scheduleStart();
2759
+ if (ensureEffectStarted()) {
2760
+ flush();
2761
+ } else {
2762
+ waitForConnection();
2662
2763
  }
2663
2764
  },
2664
2765
  dispose: () => {
2665
2766
  disposed = true;
2666
2767
  effectDispose?.();
2768
+ disconnectObserver();
2667
2769
  container.dispose();
2668
2770
  }
2669
2771
  };
@@ -2863,8 +2965,17 @@ function createClassBinding(el, value) {
2863
2965
  }
2864
2966
  function bindClass(el, getValue) {
2865
2967
  let prev = {};
2968
+ let prevString;
2866
2969
  return createRenderEffect(() => {
2867
2970
  const next = getValue();
2971
+ if (typeof next === "string") {
2972
+ if (next === prevString) return;
2973
+ prevString = next;
2974
+ el.className = next;
2975
+ prev = {};
2976
+ return;
2977
+ }
2978
+ prevString = void 0;
2868
2979
  prev = applyClass(el, next, prev);
2869
2980
  });
2870
2981
  }
@@ -3093,11 +3204,19 @@ function clearDelegatedEvents(doc = window.document) {
3093
3204
  }
3094
3205
  }
3095
3206
  function globalEventHandler(e) {
3096
- let node = e.target;
3207
+ const asNode = (value) => value && typeof value.nodeType === "number" ? value : null;
3208
+ const asElement = (value) => {
3209
+ const n = asNode(value);
3210
+ if (!n) return null;
3211
+ if (n.nodeType === 1) return n;
3212
+ return n.parentElement;
3213
+ };
3214
+ let node = asElement(e.target);
3097
3215
  const key = `$$${e.type}`;
3098
3216
  const dataKey = `${key}Data`;
3099
3217
  const oriTarget = e.target;
3100
3218
  const oriCurrentTarget = e.currentTarget;
3219
+ let lastHandled = null;
3101
3220
  const retarget = (value) => Object.defineProperty(e, "target", {
3102
3221
  configurable: true,
3103
3222
  value
@@ -3120,23 +3239,28 @@ function globalEventHandler(e) {
3120
3239
  const rawData = node[dataKey];
3121
3240
  const hasData = rawData !== void 0;
3122
3241
  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
- }
3242
+ batch2(() => {
3243
+ if (typeof handler === "function") {
3244
+ callEventHandler(handler, e, node, hasData ? resolvedNodeData : void 0);
3245
+ } else if (Array.isArray(handler)) {
3246
+ const tupleData = resolveData(handler[1]);
3247
+ callEventHandler(handler[0], e, node, tupleData);
3248
+ }
3249
+ });
3129
3250
  if (e.cancelBubble) return false;
3130
3251
  }
3131
3252
  const shadowHost = node.host;
3132
- if (shadowHost && typeof shadowHost !== "string" && !shadowHost._$host && node.contains(e.target)) {
3253
+ if (shadowHost && typeof shadowHost !== "string" && !shadowHost._$host && (() => {
3254
+ const targetNode = asNode(e.target);
3255
+ return targetNode ? node.contains(targetNode) : false;
3256
+ })()) {
3133
3257
  retarget(shadowHost);
3134
3258
  }
3135
3259
  return true;
3136
3260
  };
3137
3261
  const walkUpTree = () => {
3138
3262
  while (handleNode() && node) {
3139
- node = node._$host || node.parentNode || node.host;
3263
+ node = asElement(node._$host || node.parentNode || node.host);
3140
3264
  }
3141
3265
  };
3142
3266
  Object.defineProperty(e, "currentTarget", {
@@ -3149,8 +3273,11 @@ function globalEventHandler(e) {
3149
3273
  const path = e.composedPath();
3150
3274
  retarget(path[0]);
3151
3275
  for (let i = 0; i < path.length - 2; i++) {
3152
- node = path[i];
3276
+ const nextNode = asElement(path[i]);
3277
+ if (!nextNode || nextNode === lastHandled) continue;
3278
+ node = nextNode;
3153
3279
  if (!handleNode()) break;
3280
+ lastHandled = node;
3154
3281
  if (node._$host) {
3155
3282
  node = node._$host;
3156
3283
  walkUpTree();