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