@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/slim.js CHANGED
@@ -764,10 +764,17 @@ function effectScopeOper() {
764
764
  }
765
765
  function batch(fn) {
766
766
  ++batchDepth;
767
+ let hasError = false;
767
768
  try {
768
769
  return fn();
770
+ } catch (e) {
771
+ hasError = true;
772
+ throw e;
769
773
  } finally {
770
- if (--batchDepth === 0) flush();
774
+ --batchDepth;
775
+ if (!hasError && batchDepth === 0) {
776
+ flush();
777
+ }
771
778
  }
772
779
  }
773
780
  function setActiveSub(sub) {
@@ -818,7 +825,7 @@ function effectRunDevtools(node) {
818
825
  function createSelector(source, equalityFn = (a, b) => a === b) {
819
826
  let current = source();
820
827
  const observers = /* @__PURE__ */ new Map();
821
- effect(() => {
828
+ const dispose = effect(() => {
822
829
  const next = source();
823
830
  if (equalityFn(current, next)) return;
824
831
  const prevSig = observers.get(current);
@@ -827,6 +834,10 @@ function createSelector(source, equalityFn = (a, b) => a === b) {
827
834
  if (nextSig) nextSig(true);
828
835
  current = next;
829
836
  });
837
+ registerRootCleanup(() => {
838
+ dispose();
839
+ observers.clear();
840
+ });
830
841
  return (key) => {
831
842
  let sig = observers.get(key);
832
843
  if (!sig) {
@@ -887,7 +898,8 @@ function createRenderEffect(fn) {
887
898
  cleanup = maybeCleanup;
888
899
  }
889
900
  } catch (err) {
890
- if (handleError(err, { source: "effect" }, rootForError)) {
901
+ const handled = handleError(err, { source: "effect" }, rootForError);
902
+ if (handled) {
891
903
  return;
892
904
  }
893
905
  throw err;
@@ -1279,159 +1291,22 @@ var UnitlessStyles = /* @__PURE__ */ new Set([
1279
1291
  // src/jsx.ts
1280
1292
  var Fragment = Symbol("Fragment");
1281
1293
 
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
1294
  // src/hooks.ts
1426
1295
  var ctxStack = [];
1296
+ function assertRenderContext(ctx, hookName) {
1297
+ if (!ctx.rendering) {
1298
+ throw new Error(`${hookName} can only be used during render execution`);
1299
+ }
1300
+ }
1427
1301
  function __fictUseContext() {
1428
1302
  if (ctxStack.length === 0) {
1429
- const ctx2 = { slots: [], cursor: 0 };
1303
+ const ctx2 = { slots: [], cursor: 0, rendering: true };
1430
1304
  ctxStack.push(ctx2);
1431
1305
  return ctx2;
1432
1306
  }
1433
1307
  const ctx = ctxStack[ctxStack.length - 1];
1434
1308
  ctx.cursor = 0;
1309
+ ctx.rendering = true;
1435
1310
  return ctx;
1436
1311
  }
1437
1312
  function __fictPushContext() {
@@ -1446,6 +1321,7 @@ function __fictResetContext() {
1446
1321
  ctxStack.length = 0;
1447
1322
  }
1448
1323
  function __fictUseSignal(ctx, initial, slot) {
1324
+ assertRenderContext(ctx, "__fictUseSignal");
1449
1325
  const index = slot ?? ctx.cursor++;
1450
1326
  if (!ctx.slots[index]) {
1451
1327
  ctx.slots[index] = signal(initial);
@@ -1453,6 +1329,7 @@ function __fictUseSignal(ctx, initial, slot) {
1453
1329
  return ctx.slots[index];
1454
1330
  }
1455
1331
  function __fictUseMemo(ctx, fn, slot) {
1332
+ assertRenderContext(ctx, "__fictUseMemo");
1456
1333
  const index = slot ?? ctx.cursor++;
1457
1334
  if (!ctx.slots[index]) {
1458
1335
  ctx.slots[index] = createMemo(fn);
@@ -1460,6 +1337,7 @@ function __fictUseMemo(ctx, fn, slot) {
1460
1337
  return ctx.slots[index];
1461
1338
  }
1462
1339
  function __fictUseEffect(ctx, fn, slot) {
1340
+ assertRenderContext(ctx, "__fictUseEffect");
1463
1341
  const index = slot ?? ctx.cursor++;
1464
1342
  if (!ctx.slots[index]) {
1465
1343
  ctx.slots[index] = createEffect(fn);
@@ -1468,9 +1346,11 @@ function __fictUseEffect(ctx, fn, slot) {
1468
1346
  function __fictRender(ctx, fn) {
1469
1347
  ctxStack.push(ctx);
1470
1348
  ctx.cursor = 0;
1349
+ ctx.rendering = true;
1471
1350
  try {
1472
1351
  return fn();
1473
1352
  } finally {
1353
+ ctx.rendering = false;
1474
1354
  ctxStack.pop();
1475
1355
  }
1476
1356
  }
@@ -1673,6 +1553,14 @@ function createElementWithContext(node, namespace) {
1673
1553
  if (typeof handle.dispose === "function") {
1674
1554
  registerRootCleanup(handle.dispose);
1675
1555
  }
1556
+ if (typeof handle.flush === "function") {
1557
+ const runFlush = () => handle.flush && handle.flush();
1558
+ if (typeof queueMicrotask === "function") {
1559
+ queueMicrotask(runFlush);
1560
+ } else {
1561
+ Promise.resolve().then(runFlush).catch(() => void 0);
1562
+ }
1563
+ }
1676
1564
  return createElement(handle.marker);
1677
1565
  }
1678
1566
  const nodeRecord = node;
@@ -1720,18 +1608,18 @@ function createElementWithContext(node, namespace) {
1720
1608
  }
1721
1609
  });
1722
1610
  const props = createPropsProxy(baseProps);
1611
+ __fictPushContext();
1723
1612
  try {
1724
- __fictPushContext();
1725
1613
  const rendered = vnode.type(props);
1726
- __fictPopContext();
1727
1614
  return createElementWithContext(rendered, namespace);
1728
1615
  } catch (err) {
1729
- __fictPopContext();
1730
1616
  if (handleSuspend(err)) {
1731
1617
  return document.createComment("fict:suspend");
1732
1618
  }
1733
1619
  handleError(err, { source: "render", componentName: vnode.type.name });
1734
1620
  throw err;
1621
+ } finally {
1622
+ __fictPopContext();
1735
1623
  }
1736
1624
  }
1737
1625
  if (vnode.type === Fragment) {
@@ -2023,6 +1911,149 @@ function eventNameFromProp(key) {
2023
1911
  return key.slice(2).toLowerCase();
2024
1912
  }
2025
1913
 
1914
+ // src/node-ops.ts
1915
+ function toNodeArray(node) {
1916
+ try {
1917
+ if (Array.isArray(node)) {
1918
+ let allNodes = true;
1919
+ for (const item of node) {
1920
+ let isItemNode = false;
1921
+ try {
1922
+ isItemNode = item instanceof Node;
1923
+ } catch {
1924
+ isItemNode = false;
1925
+ }
1926
+ if (!isItemNode) {
1927
+ allNodes = false;
1928
+ break;
1929
+ }
1930
+ }
1931
+ if (allNodes) {
1932
+ return node;
1933
+ }
1934
+ const result = [];
1935
+ for (const item of node) {
1936
+ result.push(...toNodeArray(item));
1937
+ }
1938
+ return result;
1939
+ }
1940
+ if (node === null || node === void 0 || node === false) {
1941
+ return [];
1942
+ }
1943
+ } catch {
1944
+ return [];
1945
+ }
1946
+ let isNode = false;
1947
+ try {
1948
+ isNode = node instanceof Node;
1949
+ } catch {
1950
+ isNode = false;
1951
+ }
1952
+ if (isNode) {
1953
+ try {
1954
+ if (node instanceof DocumentFragment) {
1955
+ return Array.from(node.childNodes);
1956
+ }
1957
+ } catch {
1958
+ }
1959
+ return [node];
1960
+ }
1961
+ try {
1962
+ if (typeof node === "object" && node !== null && "marker" in node) {
1963
+ return toNodeArray(node.marker);
1964
+ }
1965
+ } catch {
1966
+ }
1967
+ try {
1968
+ return [document.createTextNode(String(node))];
1969
+ } catch {
1970
+ return [document.createTextNode("")];
1971
+ }
1972
+ }
1973
+ function insertNodesBefore(parent, nodes, anchor) {
1974
+ if (nodes.length === 0) return;
1975
+ if (nodes.length === 1) {
1976
+ const node = nodes[0];
1977
+ if (node === void 0 || node === null) return;
1978
+ if (node.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {
1979
+ parent.ownerDocument.adoptNode(node);
1980
+ }
1981
+ try {
1982
+ parent.insertBefore(node, anchor);
1983
+ } catch (e) {
1984
+ if (parent.ownerDocument) {
1985
+ try {
1986
+ const clone = parent.ownerDocument.importNode(node, true);
1987
+ parent.insertBefore(clone, anchor);
1988
+ return;
1989
+ } catch {
1990
+ }
1991
+ }
1992
+ throw e;
1993
+ }
1994
+ return;
1995
+ }
1996
+ const doc = parent.ownerDocument;
1997
+ if (doc) {
1998
+ const frag = doc.createDocumentFragment();
1999
+ for (let i = 0; i < nodes.length; i++) {
2000
+ const node = nodes[i];
2001
+ if (node === void 0 || node === null) continue;
2002
+ if (node.nodeType === 11) {
2003
+ const childrenArr = Array.from(node.childNodes);
2004
+ for (let j = 0; j < childrenArr.length; j++) {
2005
+ frag.appendChild(childrenArr[j]);
2006
+ }
2007
+ } else {
2008
+ if (node.ownerDocument !== doc) {
2009
+ doc.adoptNode(node);
2010
+ }
2011
+ frag.appendChild(node);
2012
+ }
2013
+ }
2014
+ parent.insertBefore(frag, anchor);
2015
+ return;
2016
+ }
2017
+ const insertSingle = (nodeToInsert, anchorNode) => {
2018
+ if (nodeToInsert.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {
2019
+ parent.ownerDocument.adoptNode(nodeToInsert);
2020
+ }
2021
+ try {
2022
+ parent.insertBefore(nodeToInsert, anchorNode);
2023
+ return nodeToInsert;
2024
+ } catch (e) {
2025
+ if (parent.ownerDocument) {
2026
+ try {
2027
+ const clone = parent.ownerDocument.importNode(nodeToInsert, true);
2028
+ parent.insertBefore(clone, anchorNode);
2029
+ return clone;
2030
+ } catch {
2031
+ }
2032
+ }
2033
+ throw e;
2034
+ }
2035
+ };
2036
+ for (let i = nodes.length - 1; i >= 0; i--) {
2037
+ const node = nodes[i];
2038
+ if (node === void 0 || node === null) continue;
2039
+ const isFrag = node.nodeType === 11;
2040
+ if (isFrag) {
2041
+ const childrenArr = Array.from(node.childNodes);
2042
+ for (let j = childrenArr.length - 1; j >= 0; j--) {
2043
+ const child = childrenArr[j];
2044
+ anchor = insertSingle(child, anchor);
2045
+ }
2046
+ } else {
2047
+ anchor = insertSingle(node, anchor);
2048
+ }
2049
+ }
2050
+ }
2051
+ function removeNodes(nodes) {
2052
+ for (const node of nodes) {
2053
+ node.parentNode?.removeChild(node);
2054
+ }
2055
+ }
2056
+
2026
2057
  // src/reconcile.ts
2027
2058
  function reconcileArrays(parentNode, a, b) {
2028
2059
  const bLength = b.length;
@@ -2250,7 +2281,6 @@ function createKeyedBlock(key, item, index, render2, needsIndex = true, hostRoot
2250
2281
  } finally {
2251
2282
  setActiveSub(prevSub);
2252
2283
  popRoot(prevRoot);
2253
- flushOnMount(root);
2254
2284
  }
2255
2285
  return {
2256
2286
  key,
@@ -2274,13 +2304,24 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2274
2304
  const hostRoot = getCurrentRoot();
2275
2305
  const fragment = document.createDocumentFragment();
2276
2306
  fragment.append(container.startMarker, container.endMarker);
2277
- let pendingItems = null;
2278
2307
  let disposed = false;
2308
+ let effectDispose;
2309
+ let connectObserver = null;
2310
+ let effectStarted = false;
2311
+ let startScheduled = false;
2312
+ const getConnectedParent = () => {
2313
+ const endParent = container.endMarker.parentNode;
2314
+ const startParent = container.startMarker.parentNode;
2315
+ if (endParent && startParent && endParent === startParent && endParent.nodeType !== 11) {
2316
+ return endParent;
2317
+ }
2318
+ return null;
2319
+ };
2279
2320
  const performDiff = () => {
2280
2321
  if (disposed) return;
2322
+ const parent = getConnectedParent();
2323
+ if (!parent) return;
2281
2324
  batch2(() => {
2282
- const newItems = pendingItems || getItems();
2283
- pendingItems = null;
2284
2325
  const oldBlocks = container.blocks;
2285
2326
  const newBlocks = container.nextBlocks;
2286
2327
  const prevOrderedBlocks = container.orderedBlocks;
@@ -2289,20 +2330,17 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2289
2330
  newBlocks.clear();
2290
2331
  nextOrderedBlocks.length = 0;
2291
2332
  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
- }
2333
+ const createdBlocks = [];
2334
+ const newItems = getItems();
2300
2335
  if (newItems.length === 0) {
2301
2336
  if (oldBlocks.size > 0) {
2302
2337
  for (const block of oldBlocks.values()) {
2303
2338
  destroyRoot(block.root);
2304
- removeNodes(block.nodes);
2305
2339
  }
2340
+ const range = document.createRange();
2341
+ range.setStartAfter(container.startMarker);
2342
+ range.setEndBefore(container.endMarker);
2343
+ range.deleteContents();
2306
2344
  }
2307
2345
  oldBlocks.clear();
2308
2346
  newBlocks.clear();
@@ -2319,8 +2357,8 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2319
2357
  const appendedBlocks = [];
2320
2358
  newItems.forEach((item, index) => {
2321
2359
  const key = keyFn(item, index);
2322
- const existed = oldBlocks.has(key);
2323
2360
  let block = oldBlocks.get(key);
2361
+ const existed = block !== void 0;
2324
2362
  if (block) {
2325
2363
  if (block.rawItem !== item) {
2326
2364
  block.rawItem = item;
@@ -2331,38 +2369,23 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2331
2369
  block.index(index);
2332
2370
  }
2333
2371
  }
2334
- const existingBlock = newBlocks.get(key);
2335
- if (existingBlock && existingBlock !== block) {
2336
- destroyRoot(existingBlock.root);
2337
- removeNodes(existingBlock.nodes);
2338
- }
2339
2372
  if (block) {
2340
2373
  newBlocks.set(key, block);
2341
2374
  oldBlocks.delete(key);
2342
2375
  } else {
2343
- const existingBlock2 = newBlocks.get(key);
2344
- if (existingBlock2) {
2345
- destroyRoot(existingBlock2.root);
2346
- removeNodes(existingBlock2.nodes);
2376
+ const existingBlock = newBlocks.get(key);
2377
+ if (existingBlock) {
2378
+ destroyRoot(existingBlock.root);
2379
+ removeNodes(existingBlock.nodes);
2347
2380
  }
2348
2381
  block = createKeyedBlock(key, item, index, renderItem, needsIndex, hostRoot);
2382
+ createdBlocks.push(block);
2349
2383
  }
2350
2384
  const resolvedBlock = block;
2351
2385
  newBlocks.set(key, resolvedBlock);
2352
2386
  const position = orderedIndexByKey.get(key);
2353
2387
  if (position !== void 0) {
2354
2388
  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
2389
  const prior = nextOrderedBlocks[position];
2367
2390
  if (prior && prior !== resolvedBlock) {
2368
2391
  destroyRoot(prior.root);
@@ -2370,6 +2393,15 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2370
2393
  }
2371
2394
  nextOrderedBlocks[position] = resolvedBlock;
2372
2395
  } else {
2396
+ if (appendCandidate) {
2397
+ if (index < prevCount) {
2398
+ if (!prevOrderedBlocks[index] || prevOrderedBlocks[index].key !== key) {
2399
+ appendCandidate = false;
2400
+ }
2401
+ } else if (existed) {
2402
+ appendCandidate = false;
2403
+ }
2404
+ }
2373
2405
  orderedIndexByKey.set(key, nextOrderedBlocks.length);
2374
2406
  nextOrderedBlocks.push(resolvedBlock);
2375
2407
  }
@@ -2398,6 +2430,11 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2398
2430
  container.nextBlocks = oldBlocks;
2399
2431
  container.orderedBlocks = nextOrderedBlocks;
2400
2432
  container.nextOrderedBlocks = prevOrderedBlocks;
2433
+ for (const block of createdBlocks) {
2434
+ if (newBlocks.get(block.key) === block) {
2435
+ flushOnMount(block.root);
2436
+ }
2437
+ }
2401
2438
  return;
2402
2439
  }
2403
2440
  if (oldBlocks.size > 0) {
@@ -2427,22 +2464,87 @@ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2427
2464
  container.nextBlocks = oldBlocks;
2428
2465
  container.orderedBlocks = nextOrderedBlocks;
2429
2466
  container.nextOrderedBlocks = prevOrderedBlocks;
2467
+ for (const block of createdBlocks) {
2468
+ if (newBlocks.get(block.key) === block) {
2469
+ flushOnMount(block.root);
2470
+ }
2471
+ }
2430
2472
  });
2431
2473
  };
2432
- const effectDispose = createRenderEffect(performDiff);
2474
+ const disconnectObserver = () => {
2475
+ connectObserver?.disconnect();
2476
+ connectObserver = null;
2477
+ };
2478
+ const ensureEffectStarted = () => {
2479
+ if (disposed || effectStarted) return effectStarted;
2480
+ const parent = getConnectedParent();
2481
+ if (!parent) return false;
2482
+ const start = () => {
2483
+ effectDispose = createRenderEffect(performDiff);
2484
+ effectStarted = true;
2485
+ };
2486
+ if (hostRoot) {
2487
+ const prev = pushRoot(hostRoot);
2488
+ try {
2489
+ start();
2490
+ } finally {
2491
+ popRoot(prev);
2492
+ }
2493
+ } else {
2494
+ start();
2495
+ }
2496
+ return true;
2497
+ };
2498
+ const waitForConnection = () => {
2499
+ if (connectObserver || typeof MutationObserver === "undefined") return;
2500
+ connectObserver = new MutationObserver(() => {
2501
+ if (disposed) return;
2502
+ if (getConnectedParent()) {
2503
+ disconnectObserver();
2504
+ if (ensureEffectStarted()) {
2505
+ flush();
2506
+ }
2507
+ }
2508
+ });
2509
+ connectObserver.observe(document, { childList: true, subtree: true });
2510
+ };
2511
+ const scheduleStart = () => {
2512
+ if (startScheduled || disposed || effectStarted) return;
2513
+ startScheduled = true;
2514
+ const run = () => {
2515
+ startScheduled = false;
2516
+ if (!ensureEffectStarted()) {
2517
+ waitForConnection();
2518
+ }
2519
+ };
2520
+ if (typeof queueMicrotask === "function") {
2521
+ queueMicrotask(run);
2522
+ } else {
2523
+ Promise.resolve().then(run).catch(() => void 0);
2524
+ }
2525
+ };
2526
+ scheduleStart();
2433
2527
  return {
2434
- marker: fragment,
2528
+ get marker() {
2529
+ scheduleStart();
2530
+ return fragment;
2531
+ },
2435
2532
  startMarker: container.startMarker,
2436
2533
  endMarker: container.endMarker,
2437
2534
  // Flush pending items - call after markers are inserted into DOM
2438
2535
  flush: () => {
2439
- if (pendingItems !== null) {
2440
- performDiff();
2536
+ if (disposed) return;
2537
+ scheduleStart();
2538
+ if (ensureEffectStarted()) {
2539
+ flush();
2540
+ } else {
2541
+ waitForConnection();
2441
2542
  }
2442
2543
  },
2443
2544
  dispose: () => {
2444
2545
  disposed = true;
2445
2546
  effectDispose?.();
2547
+ disconnectObserver();
2446
2548
  container.dispose();
2447
2549
  }
2448
2550
  };
@@ -2614,8 +2716,17 @@ function createClassBinding(el, value) {
2614
2716
  }
2615
2717
  function bindClass(el, getValue) {
2616
2718
  let prev = {};
2719
+ let prevString;
2617
2720
  return createRenderEffect(() => {
2618
2721
  const next = getValue();
2722
+ if (typeof next === "string") {
2723
+ if (next === prevString) return;
2724
+ prevString = next;
2725
+ el.className = next;
2726
+ prev = {};
2727
+ return;
2728
+ }
2729
+ prevString = void 0;
2619
2730
  prev = applyClass(el, next, prev);
2620
2731
  });
2621
2732
  }
@@ -2841,11 +2952,19 @@ function clearDelegatedEvents(doc = window.document) {
2841
2952
  }
2842
2953
  }
2843
2954
  function globalEventHandler(e) {
2844
- let node = e.target;
2955
+ const asNode = (value) => value && typeof value.nodeType === "number" ? value : null;
2956
+ const asElement = (value) => {
2957
+ const n = asNode(value);
2958
+ if (!n) return null;
2959
+ if (n.nodeType === 1) return n;
2960
+ return n.parentElement;
2961
+ };
2962
+ let node = asElement(e.target);
2845
2963
  const key = `$$${e.type}`;
2846
2964
  const dataKey = `${key}Data`;
2847
2965
  const oriTarget = e.target;
2848
2966
  const oriCurrentTarget = e.currentTarget;
2967
+ let lastHandled = null;
2849
2968
  const retarget = (value) => Object.defineProperty(e, "target", {
2850
2969
  configurable: true,
2851
2970
  value
@@ -2868,23 +2987,28 @@ function globalEventHandler(e) {
2868
2987
  const rawData = node[dataKey];
2869
2988
  const hasData = rawData !== void 0;
2870
2989
  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
- }
2990
+ batch2(() => {
2991
+ if (typeof handler === "function") {
2992
+ callEventHandler(handler, e, node, hasData ? resolvedNodeData : void 0);
2993
+ } else if (Array.isArray(handler)) {
2994
+ const tupleData = resolveData(handler[1]);
2995
+ callEventHandler(handler[0], e, node, tupleData);
2996
+ }
2997
+ });
2877
2998
  if (e.cancelBubble) return false;
2878
2999
  }
2879
3000
  const shadowHost = node.host;
2880
- if (shadowHost && typeof shadowHost !== "string" && !shadowHost._$host && node.contains(e.target)) {
3001
+ if (shadowHost && typeof shadowHost !== "string" && !shadowHost._$host && (() => {
3002
+ const targetNode = asNode(e.target);
3003
+ return targetNode ? node.contains(targetNode) : false;
3004
+ })()) {
2881
3005
  retarget(shadowHost);
2882
3006
  }
2883
3007
  return true;
2884
3008
  };
2885
3009
  const walkUpTree = () => {
2886
3010
  while (handleNode() && node) {
2887
- node = node._$host || node.parentNode || node.host;
3011
+ node = asElement(node._$host || node.parentNode || node.host);
2888
3012
  }
2889
3013
  };
2890
3014
  Object.defineProperty(e, "currentTarget", {
@@ -2897,8 +3021,11 @@ function globalEventHandler(e) {
2897
3021
  const path = e.composedPath();
2898
3022
  retarget(path[0]);
2899
3023
  for (let i = 0; i < path.length - 2; i++) {
2900
- node = path[i];
3024
+ const nextNode = asElement(path[i]);
3025
+ if (!nextNode || nextNode === lastHandled) continue;
3026
+ node = nextNode;
2901
3027
  if (!handleNode()) break;
3028
+ lastHandled = node;
2902
3029
  if (node._$host) {
2903
3030
  node = node._$host;
2904
3031
  walkUpTree();