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