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