@fictjs/runtime 0.0.7 → 0.0.9

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
@@ -889,6 +889,7 @@ function createSelector(source, equalityFn = (a, b) => a === b) {
889
889
  // src/store.ts
890
890
  var PROXY = Symbol("fict:store-proxy");
891
891
  var TARGET = Symbol("fict:store-target");
892
+ var ITERATE_KEY = Symbol("fict:iterate");
892
893
  function createStore(initialValue) {
893
894
  const unwrapped = unwrap(initialValue);
894
895
  const wrapped = wrap(unwrapped);
@@ -916,20 +917,41 @@ function wrap(value) {
916
917
  track(target, prop);
917
918
  return wrap(value2);
918
919
  },
920
+ has(target, prop) {
921
+ const result = Reflect.has(target, prop);
922
+ track(target, prop);
923
+ return result;
924
+ },
925
+ ownKeys(target) {
926
+ track(target, ITERATE_KEY);
927
+ return Reflect.ownKeys(target);
928
+ },
929
+ getOwnPropertyDescriptor(target, prop) {
930
+ track(target, prop);
931
+ return Reflect.getOwnPropertyDescriptor(target, prop);
932
+ },
919
933
  set(target, prop, value2, receiver) {
920
934
  if (prop === PROXY || prop === TARGET) return false;
935
+ const hadKey = Object.prototype.hasOwnProperty.call(target, prop);
921
936
  const oldValue = Reflect.get(target, prop, receiver);
922
937
  if (oldValue === value2) return true;
923
938
  const result = Reflect.set(target, prop, value2, receiver);
924
939
  if (result) {
925
940
  trigger(target, prop);
941
+ if (!hadKey) {
942
+ trigger(target, ITERATE_KEY);
943
+ }
926
944
  }
927
945
  return result;
928
946
  },
929
947
  deleteProperty(target, prop) {
948
+ const hadKey = Object.prototype.hasOwnProperty.call(target, prop);
930
949
  const result = Reflect.deleteProperty(target, prop);
931
950
  if (result) {
932
951
  trigger(target, prop);
952
+ if (hadKey) {
953
+ trigger(target, ITERATE_KEY);
954
+ }
933
955
  }
934
956
  return result;
935
957
  }
@@ -952,7 +974,8 @@ function track(target, prop) {
952
974
  }
953
975
  let s = signals.get(prop);
954
976
  if (!s) {
955
- s = signal(getLastValue(target, prop));
977
+ const initial = prop === ITERATE_KEY ? Reflect.ownKeys(target).length : getLastValue(target, prop);
978
+ s = signal(initial);
956
979
  signals.set(prop, s);
957
980
  }
958
981
  s();
@@ -962,7 +985,11 @@ function trigger(target, prop) {
962
985
  if (signals) {
963
986
  const s = signals.get(prop);
964
987
  if (s) {
965
- s(getLastValue(target, prop));
988
+ if (prop === ITERATE_KEY) {
989
+ s(Reflect.ownKeys(target).length);
990
+ } else {
991
+ s(getLastValue(target, prop));
992
+ }
966
993
  }
967
994
  }
968
995
  }
@@ -1570,2631 +1597,2563 @@ function removeNodes(nodes) {
1570
1597
  }
1571
1598
  }
1572
1599
 
1573
- // src/binding.ts
1574
- function isReactive(value) {
1575
- return typeof value === "function" && value.length === 0;
1600
+ // src/hooks.ts
1601
+ var ctxStack = [];
1602
+ function __fictUseContext() {
1603
+ if (ctxStack.length === 0) {
1604
+ const ctx2 = { slots: [], cursor: 0 };
1605
+ ctxStack.push(ctx2);
1606
+ return ctx2;
1607
+ }
1608
+ const ctx = ctxStack[ctxStack.length - 1];
1609
+ ctx.cursor = 0;
1610
+ return ctx;
1576
1611
  }
1577
- function unwrap2(value) {
1578
- return isReactive(value) ? value() : value;
1612
+ function __fictPushContext() {
1613
+ const ctx = { slots: [], cursor: 0 };
1614
+ ctxStack.push(ctx);
1615
+ return ctx;
1579
1616
  }
1580
- function callEventHandler(handler, event, node, data) {
1581
- if (!handler) return;
1582
- const context = node ?? event.currentTarget ?? void 0;
1583
- const invoke = (fn) => {
1584
- if (typeof fn === "function") {
1585
- const result = data === void 0 ? fn.call(context, event) : fn.call(context, data, event);
1586
- if (typeof result === "function" && result !== fn) {
1587
- if (data === void 0) {
1588
- ;
1589
- result.call(context, event);
1590
- } else {
1591
- ;
1592
- result.call(context, data, event);
1593
- }
1594
- } else if (result && typeof result.handleEvent === "function") {
1595
- ;
1596
- result.handleEvent.call(result, event);
1617
+ function __fictPopContext() {
1618
+ ctxStack.pop();
1619
+ }
1620
+ function __fictResetContext() {
1621
+ ctxStack.length = 0;
1622
+ }
1623
+ function __fictUseSignal(ctx, initial, slot) {
1624
+ const index = slot ?? ctx.cursor++;
1625
+ if (!ctx.slots[index]) {
1626
+ ctx.slots[index] = signal(initial);
1627
+ }
1628
+ return ctx.slots[index];
1629
+ }
1630
+ function __fictUseMemo(ctx, fn, slot) {
1631
+ const index = slot ?? ctx.cursor++;
1632
+ if (!ctx.slots[index]) {
1633
+ ctx.slots[index] = createMemo(fn);
1634
+ }
1635
+ return ctx.slots[index];
1636
+ }
1637
+ function __fictUseEffect(ctx, fn, slot) {
1638
+ const index = slot ?? ctx.cursor++;
1639
+ if (!ctx.slots[index]) {
1640
+ ctx.slots[index] = createEffect(fn);
1641
+ }
1642
+ }
1643
+ function __fictRender(ctx, fn) {
1644
+ ctxStack.push(ctx);
1645
+ ctx.cursor = 0;
1646
+ try {
1647
+ return fn();
1648
+ } finally {
1649
+ ctxStack.pop();
1650
+ }
1651
+ }
1652
+
1653
+ // src/props.ts
1654
+ var propGetters = /* @__PURE__ */ new WeakSet();
1655
+ var rawToProxy = /* @__PURE__ */ new WeakMap();
1656
+ var proxyToRaw = /* @__PURE__ */ new WeakMap();
1657
+ function __fictProp(getter) {
1658
+ if (typeof getter === "function" && getter.length === 0) {
1659
+ propGetters.add(getter);
1660
+ }
1661
+ return getter;
1662
+ }
1663
+ function isPropGetter(value) {
1664
+ return typeof value === "function" && propGetters.has(value);
1665
+ }
1666
+ function createPropsProxy(props) {
1667
+ if (!props || typeof props !== "object") {
1668
+ return props;
1669
+ }
1670
+ if (proxyToRaw.has(props)) {
1671
+ return props;
1672
+ }
1673
+ const cached = rawToProxy.get(props);
1674
+ if (cached) {
1675
+ return cached;
1676
+ }
1677
+ const proxy = new Proxy(props, {
1678
+ get(target, prop, receiver) {
1679
+ const value = Reflect.get(target, prop, receiver);
1680
+ if (isPropGetter(value)) {
1681
+ return value();
1597
1682
  }
1598
- } else if (fn && typeof fn.handleEvent === "function") {
1599
- fn.handleEvent.call(fn, event);
1683
+ return value;
1684
+ },
1685
+ set(target, prop, value, receiver) {
1686
+ return Reflect.set(target, prop, value, receiver);
1687
+ },
1688
+ has(target, prop) {
1689
+ return prop in target;
1690
+ },
1691
+ ownKeys(target) {
1692
+ return Reflect.ownKeys(target);
1693
+ },
1694
+ getOwnPropertyDescriptor(target, prop) {
1695
+ return Object.getOwnPropertyDescriptor(target, prop);
1600
1696
  }
1601
- };
1602
- invoke(handler);
1697
+ });
1698
+ rawToProxy.set(props, proxy);
1699
+ proxyToRaw.set(proxy, props);
1700
+ return proxy;
1603
1701
  }
1604
- var PRIMITIVE_PROXY = Symbol("fict:primitive-proxy");
1605
- var PRIMITIVE_PROXY_RAW_VALUE = Symbol("fict:primitive-proxy:raw-value");
1606
- function unwrapPrimitive(value) {
1607
- if (value && typeof value === "object" && PRIMITIVE_PROXY in value) {
1608
- const getRawValue = value[PRIMITIVE_PROXY_RAW_VALUE];
1609
- if (typeof getRawValue === "function") {
1610
- return getRawValue();
1611
- }
1702
+ function unwrapProps(props) {
1703
+ if (!props || typeof props !== "object") {
1704
+ return props;
1612
1705
  }
1613
- return value;
1706
+ return proxyToRaw.get(props) ?? props;
1614
1707
  }
1615
- function createValueProxy(read) {
1616
- const getPrimitivePrototype = (value) => {
1617
- switch (typeof value) {
1618
- case "string":
1619
- return String.prototype;
1620
- case "number":
1621
- return Number.prototype;
1622
- case "boolean":
1623
- return Boolean.prototype;
1624
- case "bigint":
1625
- return BigInt.prototype;
1626
- case "symbol":
1627
- return Symbol.prototype;
1628
- default:
1629
- return void 0;
1630
- }
1708
+ function __fictPropsRest(props, exclude) {
1709
+ const raw = unwrapProps(props);
1710
+ const out = {};
1711
+ const excludeSet = new Set(exclude);
1712
+ for (const key of Reflect.ownKeys(raw)) {
1713
+ if (excludeSet.has(key)) continue;
1714
+ out[key] = raw[key];
1715
+ }
1716
+ return createPropsProxy(out);
1717
+ }
1718
+ function mergeProps(...sources) {
1719
+ const validSources = sources.filter(
1720
+ (s) => s != null && (typeof s === "object" || typeof s === "function")
1721
+ );
1722
+ if (validSources.length === 0) {
1723
+ return {};
1724
+ }
1725
+ if (validSources.length === 1 && typeof validSources[0] === "object") {
1726
+ return validSources[0];
1727
+ }
1728
+ const resolveSource = (src) => {
1729
+ const value = typeof src === "function" ? src() : src;
1730
+ if (!value || typeof value !== "object") return void 0;
1731
+ return unwrapProps(value);
1631
1732
  };
1632
- const target = {};
1633
- const handler = {
1634
- get(_target, prop, receiver) {
1635
- if (prop === PRIMITIVE_PROXY) {
1636
- return true;
1637
- }
1638
- if (prop === PRIMITIVE_PROXY_RAW_VALUE) {
1639
- return () => read();
1640
- }
1641
- if (prop === Symbol.toPrimitive) {
1642
- return (hint) => {
1643
- const value2 = read();
1644
- if (value2 != null && (typeof value2 === "object" || typeof value2 === "function")) {
1645
- const toPrimitive = value2[Symbol.toPrimitive];
1646
- if (typeof toPrimitive === "function") {
1647
- return toPrimitive.call(value2, hint);
1648
- }
1649
- if (hint === "string") return value2.toString?.() ?? "[object Object]";
1650
- if (hint === "number") return value2.valueOf?.() ?? value2;
1651
- return value2.valueOf?.() ?? value2;
1652
- }
1653
- return value2;
1654
- };
1655
- }
1656
- if (prop === "valueOf") {
1657
- return () => {
1658
- const value2 = read();
1659
- if (value2 != null && (typeof value2 === "object" || typeof value2 === "function")) {
1660
- return typeof value2.valueOf === "function" ? value2.valueOf() : value2;
1661
- }
1662
- return value2;
1663
- };
1664
- }
1665
- if (prop === "toString") {
1666
- return () => String(read());
1667
- }
1668
- const value = read();
1669
- if (value != null && (typeof value === "object" || typeof value === "function")) {
1670
- return Reflect.get(value, prop, receiver === _target ? value : receiver);
1733
+ return new Proxy({}, {
1734
+ get(_, prop) {
1735
+ if (typeof prop === "symbol") {
1736
+ return void 0;
1671
1737
  }
1672
- const proto = getPrimitivePrototype(value);
1673
- if (proto && prop in proto) {
1674
- const descriptor = Reflect.get(proto, prop, value);
1675
- return typeof descriptor === "function" ? descriptor.bind(value) : descriptor;
1738
+ for (let i = validSources.length - 1; i >= 0; i--) {
1739
+ const src = validSources[i];
1740
+ const raw = resolveSource(src);
1741
+ if (!raw || !(prop in raw)) continue;
1742
+ const value = raw[prop];
1743
+ if (typeof src === "function" && !isPropGetter(value)) {
1744
+ return __fictProp(() => {
1745
+ const latest = resolveSource(src);
1746
+ if (!latest || !(prop in latest)) return void 0;
1747
+ return latest[prop];
1748
+ });
1749
+ }
1750
+ return value;
1676
1751
  }
1677
1752
  return void 0;
1678
1753
  },
1679
- set(_target, prop, newValue, receiver) {
1680
- const value = read();
1681
- if (value != null && (typeof value === "object" || typeof value === "function")) {
1682
- return Reflect.set(value, prop, newValue, receiver === _target ? value : receiver);
1754
+ has(_, prop) {
1755
+ for (const src of validSources) {
1756
+ const raw = resolveSource(src);
1757
+ if (raw && prop in raw) {
1758
+ return true;
1759
+ }
1683
1760
  }
1684
1761
  return false;
1685
1762
  },
1686
- has(_target, prop) {
1687
- if (prop === PRIMITIVE_PROXY || prop === PRIMITIVE_PROXY_RAW_VALUE) {
1688
- return true;
1689
- }
1690
- const value = read();
1691
- if (value != null && (typeof value === "object" || typeof value === "function")) {
1692
- return prop in value;
1693
- }
1694
- const proto = getPrimitivePrototype(value);
1695
- return proto ? prop in proto : false;
1696
- },
1697
1763
  ownKeys() {
1698
- const value = read();
1699
- if (value != null && (typeof value === "object" || typeof value === "function")) {
1700
- return Reflect.ownKeys(value);
1764
+ const keys = /* @__PURE__ */ new Set();
1765
+ for (const src of validSources) {
1766
+ const raw = resolveSource(src);
1767
+ if (raw) {
1768
+ for (const key of Reflect.ownKeys(raw)) {
1769
+ keys.add(key);
1770
+ }
1771
+ }
1701
1772
  }
1702
- const proto = getPrimitivePrototype(value);
1703
- return proto ? Reflect.ownKeys(proto) : [];
1773
+ return Array.from(keys);
1704
1774
  },
1705
- getOwnPropertyDescriptor(_target, prop) {
1706
- const value = read();
1707
- if (value != null && (typeof value === "object" || typeof value === "function")) {
1708
- return Object.getOwnPropertyDescriptor(value, prop);
1775
+ getOwnPropertyDescriptor(_, prop) {
1776
+ for (let i = validSources.length - 1; i >= 0; i--) {
1777
+ const raw = resolveSource(validSources[i]);
1778
+ if (raw && prop in raw) {
1779
+ return {
1780
+ enumerable: true,
1781
+ configurable: true,
1782
+ get: () => {
1783
+ const value = raw[prop];
1784
+ return value;
1785
+ }
1786
+ };
1787
+ }
1709
1788
  }
1710
- const proto = getPrimitivePrototype(value);
1711
- return proto ? Object.getOwnPropertyDescriptor(proto, prop) || void 0 : void 0;
1789
+ return void 0;
1712
1790
  }
1713
- };
1714
- return new Proxy(target, handler);
1791
+ });
1715
1792
  }
1716
- function createTextBinding(value) {
1717
- const text = document.createTextNode("");
1718
- if (isReactive(value)) {
1719
- createRenderEffect(() => {
1720
- const v = value();
1721
- const fmt = formatTextValue(v);
1722
- if (text.data !== fmt) {
1723
- text.data = fmt;
1724
- }
1725
- });
1726
- } else {
1727
- text.data = formatTextValue(value);
1728
- }
1729
- return text;
1793
+ function useProp(getter) {
1794
+ return __fictProp(createMemo(getter));
1730
1795
  }
1731
- function bindText(textNode, getValue) {
1732
- return createRenderEffect(() => {
1733
- const value = formatTextValue(getValue());
1734
- if (textNode.data !== value) {
1735
- textNode.data = value;
1736
- }
1737
- });
1738
- }
1739
- function formatTextValue(value) {
1740
- if (value == null || value === false) {
1741
- return "";
1796
+
1797
+ // src/transition.ts
1798
+ function startTransition(fn) {
1799
+ const prev = setTransitionContext(true);
1800
+ try {
1801
+ fn();
1802
+ } finally {
1803
+ setTransitionContext(prev);
1804
+ scheduleFlush();
1742
1805
  }
1743
- return String(value);
1744
1806
  }
1745
- function createAttributeBinding(el, key, value, setter) {
1746
- if (isReactive(value)) {
1747
- createRenderEffect(() => {
1748
- setter(el, key, value());
1807
+ function useTransition() {
1808
+ const pending = signal(false);
1809
+ const start = (fn) => {
1810
+ pending(true);
1811
+ startTransition(() => {
1812
+ try {
1813
+ fn();
1814
+ } finally {
1815
+ pending(false);
1816
+ }
1749
1817
  });
1750
- } else {
1751
- setter(el, key, value);
1752
- }
1753
- }
1754
- function bindAttribute(el, key, getValue) {
1755
- let prevValue = void 0;
1756
- return createRenderEffect(() => {
1757
- const value = getValue();
1758
- if (value === prevValue) return;
1759
- prevValue = value;
1760
- if (value === void 0 || value === null || value === false) {
1761
- el.removeAttribute(key);
1762
- } else if (value === true) {
1763
- el.setAttribute(key, "");
1764
- } else {
1765
- el.setAttribute(key, String(value));
1766
- }
1767
- });
1818
+ };
1819
+ return [() => pending(), start];
1768
1820
  }
1769
- function bindProperty(el, key, getValue) {
1770
- const PROPERTY_BINDING_KEYS = /* @__PURE__ */ new Set([
1771
- "value",
1772
- "checked",
1773
- "selected",
1774
- "disabled",
1775
- "readOnly",
1776
- "multiple",
1777
- "muted"
1778
- ]);
1779
- let prevValue = void 0;
1780
- return createRenderEffect(() => {
1781
- const next = getValue();
1782
- if (next === prevValue) return;
1783
- prevValue = next;
1784
- if (PROPERTY_BINDING_KEYS.has(key) && (next === void 0 || next === null)) {
1785
- const fallback = key === "checked" || key === "selected" ? false : "";
1786
- el[key] = fallback;
1787
- return;
1821
+ function useDeferredValue(getValue) {
1822
+ const deferredValue = signal(getValue());
1823
+ createEffect(() => {
1824
+ const newValue = getValue();
1825
+ const currentDeferred = untrack(() => deferredValue());
1826
+ if (currentDeferred !== newValue) {
1827
+ startTransition(() => {
1828
+ deferredValue(newValue);
1829
+ });
1788
1830
  }
1789
- ;
1790
- el[key] = next;
1791
1831
  });
1832
+ return () => deferredValue();
1792
1833
  }
1793
- function createStyleBinding(el, value) {
1794
- if (isReactive(value)) {
1795
- let prev;
1796
- createRenderEffect(() => {
1797
- const next = value();
1798
- applyStyle(el, next, prev);
1799
- prev = next;
1800
- });
1801
- } else {
1802
- applyStyle(el, value, void 0);
1803
- }
1834
+
1835
+ // src/scheduler.ts
1836
+ function batch2(fn) {
1837
+ return batch(fn);
1804
1838
  }
1805
- function bindStyle(el, getValue) {
1806
- let prev;
1807
- return createRenderEffect(() => {
1808
- const next = getValue();
1809
- applyStyle(el, next, prev);
1810
- prev = next;
1811
- });
1839
+ function untrack2(fn) {
1840
+ return untrack(fn);
1812
1841
  }
1813
- function applyStyle(el, value, prev) {
1814
- if (typeof value === "string") {
1815
- el.style.cssText = value;
1816
- } else if (value && typeof value === "object") {
1817
- const styles = value;
1818
- if (typeof prev === "string") {
1819
- el.style.cssText = "";
1820
- }
1821
- if (prev && typeof prev === "object") {
1822
- const prevStyles = prev;
1823
- for (const key of Object.keys(prevStyles)) {
1824
- if (!(key in styles)) {
1825
- const cssProperty = key.replace(/([A-Z])/g, "-$1").toLowerCase();
1826
- el.style.removeProperty(cssProperty);
1827
- }
1828
- }
1829
- }
1830
- for (const [prop, v] of Object.entries(styles)) {
1831
- if (v != null) {
1832
- const cssProperty = prop.replace(/([A-Z])/g, "-$1").toLowerCase();
1833
- const unitless = isUnitlessStyleProperty(prop) || isUnitlessStyleProperty(cssProperty);
1834
- const valueStr = typeof v === "number" && !unitless ? `${v}px` : String(v);
1835
- el.style.setProperty(cssProperty, valueStr);
1836
- } else {
1837
- const cssProperty = prop.replace(/([A-Z])/g, "-$1").toLowerCase();
1838
- el.style.removeProperty(cssProperty);
1839
- }
1840
- }
1841
- } else {
1842
- if (prev && typeof prev === "object") {
1843
- const prevStyles = prev;
1844
- for (const key of Object.keys(prevStyles)) {
1845
- const cssProperty = key.replace(/([A-Z])/g, "-$1").toLowerCase();
1846
- el.style.removeProperty(cssProperty);
1847
- }
1848
- } else if (typeof prev === "string") {
1849
- el.style.cssText = "";
1850
- }
1842
+
1843
+ // src/dom.ts
1844
+ var SVG_NS = "http://www.w3.org/2000/svg";
1845
+ var MATHML_NS = "http://www.w3.org/1998/Math/MathML";
1846
+ function render(view, container) {
1847
+ const root = createRootContext();
1848
+ const prev = pushRoot(root);
1849
+ let dom;
1850
+ try {
1851
+ const output = view();
1852
+ dom = createElement(output);
1853
+ } finally {
1854
+ popRoot(prev);
1851
1855
  }
1856
+ container.replaceChildren(dom);
1857
+ container.setAttribute("data-fict-fine-grained", "1");
1858
+ flushOnMount(root);
1859
+ const teardown = () => {
1860
+ destroyRoot(root);
1861
+ container.innerHTML = "";
1862
+ };
1863
+ return teardown;
1852
1864
  }
1853
- function isUnitlessStyleProperty(prop) {
1854
- return UnitlessStyles.has(prop);
1855
- }
1856
- function createClassBinding(el, value) {
1857
- if (isReactive(value)) {
1858
- let prev = {};
1859
- createRenderEffect(() => {
1860
- const next = value();
1861
- prev = applyClass(el, next, prev);
1862
- });
1863
- } else {
1864
- applyClass(el, value, {});
1865
- }
1865
+ function createElement(node) {
1866
+ return createElementWithContext(node, null);
1866
1867
  }
1867
- function bindClass(el, getValue) {
1868
- let prev = {};
1869
- return createRenderEffect(() => {
1870
- const next = getValue();
1871
- prev = applyClass(el, next, prev);
1872
- });
1868
+ function resolveNamespace(tagName, namespace) {
1869
+ if (tagName === "svg") return "svg";
1870
+ if (tagName === "math") return "mathml";
1871
+ if (namespace === "mathml") return "mathml";
1872
+ if (namespace === "svg") return "svg";
1873
+ if (SVGElements.has(tagName)) return "svg";
1874
+ return null;
1873
1875
  }
1874
- function toggleClassKey(node, key, value) {
1875
- const classNames = key.trim().split(/\s+/);
1876
- for (let i = 0, len = classNames.length; i < len; i++) {
1877
- node.classList.toggle(classNames[i], value);
1876
+ function createElementWithContext(node, namespace) {
1877
+ if (node instanceof Node) {
1878
+ return node;
1878
1879
  }
1879
- }
1880
- function applyClass(el, value, prev) {
1881
- const prevState = prev && typeof prev === "object" ? prev : {};
1882
- if (typeof value === "string") {
1883
- el.className = value;
1884
- return {};
1880
+ if (node === null || node === void 0 || node === false) {
1881
+ return document.createTextNode("");
1885
1882
  }
1886
- if (value && typeof value === "object") {
1887
- const classes = value;
1888
- const classKeys = Object.keys(classes);
1889
- const prevKeys = Object.keys(prevState);
1890
- for (let i = 0, len = prevKeys.length; i < len; i++) {
1891
- const key = prevKeys[i];
1892
- if (!key || key === "undefined" || classes[key]) continue;
1893
- toggleClassKey(el, key, false);
1894
- delete prevState[key];
1883
+ if (typeof node === "object" && node !== null && !(node instanceof Node)) {
1884
+ if ("marker" in node) {
1885
+ const handle = node;
1886
+ if (typeof handle.dispose === "function") {
1887
+ registerRootCleanup(handle.dispose);
1888
+ }
1889
+ return createElement(handle.marker);
1895
1890
  }
1896
- for (let i = 0, len = classKeys.length; i < len; i++) {
1897
- const key = classKeys[i];
1898
- const classValue = !!classes[key];
1899
- if (!key || key === "undefined" || prevState[key] === classValue || !classValue) continue;
1900
- toggleClassKey(el, key, true);
1901
- prevState[key] = classValue;
1891
+ const nodeRecord = node;
1892
+ if (nodeRecord[PRIMITIVE_PROXY]) {
1893
+ const primitiveGetter = nodeRecord[Symbol.toPrimitive];
1894
+ const value = typeof primitiveGetter === "function" ? primitiveGetter.call(node, "default") : node;
1895
+ return document.createTextNode(value == null || value === false ? "" : String(value));
1902
1896
  }
1903
- return prevState;
1904
1897
  }
1905
- if (!value) {
1906
- for (const key of Object.keys(prevState)) {
1907
- if (key && key !== "undefined") {
1908
- toggleClassKey(el, key, false);
1909
- }
1898
+ if (Array.isArray(node)) {
1899
+ const frag = document.createDocumentFragment();
1900
+ for (const child of node) {
1901
+ appendChildNode(frag, child, namespace);
1910
1902
  }
1911
- return {};
1903
+ return frag;
1912
1904
  }
1913
- return prevState;
1914
- }
1915
- function classList(node, value, prev = {}) {
1916
- return applyClass(node, value, prev);
1917
- }
1918
- function insert(parent, getValue, markerOrCreateElement, createElementFn) {
1919
- let marker;
1920
- let ownsMarker = false;
1921
- let createFn = createElementFn;
1922
- if (markerOrCreateElement instanceof Node) {
1923
- marker = markerOrCreateElement;
1924
- createFn = createElementFn;
1925
- } else {
1926
- marker = document.createComment("fict:insert");
1927
- parent.appendChild(marker);
1928
- createFn = markerOrCreateElement;
1929
- ownsMarker = true;
1905
+ if (typeof node === "string" || typeof node === "number") {
1906
+ return document.createTextNode(String(node));
1930
1907
  }
1931
- let currentNodes = [];
1932
- let currentText = null;
1933
- let currentRoot2 = null;
1934
- const clearCurrentNodes = () => {
1935
- if (currentNodes.length > 0) {
1936
- removeNodes(currentNodes);
1937
- currentNodes = [];
1938
- }
1939
- };
1940
- const setTextNode = (textValue, shouldInsert, parentNode) => {
1941
- if (!currentText) {
1942
- currentText = document.createTextNode(textValue);
1943
- } else if (currentText.data !== textValue) {
1944
- currentText.data = textValue;
1945
- }
1946
- if (!shouldInsert) {
1947
- clearCurrentNodes();
1948
- return;
1949
- }
1950
- if (currentNodes.length === 1 && currentNodes[0] === currentText) {
1951
- return;
1952
- }
1953
- clearCurrentNodes();
1954
- insertNodesBefore(parentNode, [currentText], marker);
1955
- currentNodes = [currentText];
1956
- };
1957
- const dispose = createRenderEffect(() => {
1958
- const value = getValue();
1959
- const parentNode = marker.parentNode;
1960
- const isPrimitive = value == null || value === false || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
1961
- if (isPrimitive) {
1962
- if (currentRoot2) {
1963
- destroyRoot(currentRoot2);
1964
- currentRoot2 = null;
1965
- }
1966
- if (!parentNode) {
1967
- clearCurrentNodes();
1968
- return;
1969
- }
1970
- const textValue = value == null || value === false ? "" : String(value);
1971
- const shouldInsert = value != null && value !== false;
1972
- setTextNode(textValue, shouldInsert, parentNode);
1973
- return;
1974
- }
1975
- if (currentRoot2) {
1976
- destroyRoot(currentRoot2);
1977
- currentRoot2 = null;
1978
- }
1979
- clearCurrentNodes();
1980
- const root = createRootContext();
1981
- const prev = pushRoot(root);
1982
- let nodes = [];
1983
- try {
1984
- let newNode;
1985
- if (value instanceof Node) {
1986
- newNode = value;
1987
- } else if (Array.isArray(value)) {
1988
- if (value.every((v) => v instanceof Node)) {
1989
- newNode = value;
1990
- } else {
1991
- newNode = createFn ? createFn(value) : document.createTextNode(String(value));
1908
+ if (typeof node === "boolean") {
1909
+ return document.createTextNode("");
1910
+ }
1911
+ const vnode = node;
1912
+ if (typeof vnode.type === "function") {
1913
+ const rawProps = unwrapProps(vnode.props ?? {});
1914
+ const baseProps = vnode.key === void 0 ? rawProps : new Proxy(rawProps, {
1915
+ get(target, prop, receiver) {
1916
+ if (prop === "key") return vnode.key;
1917
+ return Reflect.get(target, prop, receiver);
1918
+ },
1919
+ has(target, prop) {
1920
+ if (prop === "key") return true;
1921
+ return prop in target;
1922
+ },
1923
+ ownKeys(target) {
1924
+ const keys = new Set(Reflect.ownKeys(target));
1925
+ keys.add("key");
1926
+ return Array.from(keys);
1927
+ },
1928
+ getOwnPropertyDescriptor(target, prop) {
1929
+ if (prop === "key") {
1930
+ return { enumerable: true, configurable: true, value: vnode.key };
1992
1931
  }
1993
- } else {
1994
- newNode = createFn ? createFn(value) : document.createTextNode(String(value));
1932
+ return Object.getOwnPropertyDescriptor(target, prop);
1995
1933
  }
1996
- nodes = toNodeArray(newNode);
1997
- if (parentNode) {
1998
- insertNodesBefore(parentNode, nodes, marker);
1934
+ });
1935
+ const props = createPropsProxy(baseProps);
1936
+ try {
1937
+ __fictPushContext();
1938
+ const rendered = vnode.type(props);
1939
+ __fictPopContext();
1940
+ return createElementWithContext(rendered, namespace);
1941
+ } catch (err) {
1942
+ __fictPopContext();
1943
+ if (handleSuspend(err)) {
1944
+ return document.createComment("fict:suspend");
1999
1945
  }
2000
- } finally {
2001
- popRoot(prev);
2002
- flushOnMount(root);
1946
+ handleError(err, { source: "render", componentName: vnode.type.name });
1947
+ throw err;
2003
1948
  }
2004
- currentRoot2 = root;
2005
- currentNodes = nodes;
2006
- });
2007
- return () => {
2008
- dispose();
2009
- if (currentRoot2) {
2010
- destroyRoot(currentRoot2);
2011
- currentRoot2 = null;
1949
+ }
1950
+ if (vnode.type === Fragment) {
1951
+ const frag = document.createDocumentFragment();
1952
+ const children = vnode.props?.children;
1953
+ appendChildren(frag, children, namespace);
1954
+ return frag;
1955
+ }
1956
+ const tagName = typeof vnode.type === "string" ? vnode.type : "div";
1957
+ const resolvedNamespace = resolveNamespace(tagName, namespace);
1958
+ const el = resolvedNamespace === "svg" ? document.createElementNS(SVG_NS, tagName) : resolvedNamespace === "mathml" ? document.createElementNS(MATHML_NS, tagName) : document.createElement(tagName);
1959
+ applyProps(el, vnode.props ?? {}, resolvedNamespace === "svg");
1960
+ appendChildren(
1961
+ el,
1962
+ vnode.props?.children,
1963
+ tagName === "foreignObject" ? null : resolvedNamespace
1964
+ );
1965
+ return el;
1966
+ }
1967
+ function template(html, isImportNode, isSVG, isMathML) {
1968
+ let node = null;
1969
+ const create = () => {
1970
+ const t = isMathML ? document.createElementNS(MATHML_NS, "template") : document.createElement("template");
1971
+ t.innerHTML = html;
1972
+ if (isSVG) {
1973
+ return t.content.firstChild.firstChild;
2012
1974
  }
2013
- clearCurrentNodes();
2014
- if (ownsMarker) {
2015
- marker.parentNode?.removeChild(marker);
1975
+ if (isMathML) {
1976
+ return t.firstChild;
2016
1977
  }
1978
+ return t.content.firstChild;
2017
1979
  };
1980
+ const fn = isImportNode ? () => untrack2(() => document.importNode(node || (node = create()), true)) : () => (node || (node = create())).cloneNode(true);
1981
+ fn.cloneNode = fn;
1982
+ return fn;
2018
1983
  }
2019
- function createChildBinding(parent, getValue, createElementFn) {
2020
- const marker = document.createComment("fict:child");
2021
- parent.appendChild(marker);
2022
- const dispose = createRenderEffect(() => {
2023
- const root = createRootContext();
2024
- const prev = pushRoot(root);
2025
- let nodes = [];
2026
- let handledError = false;
2027
- try {
2028
- const value = getValue();
2029
- if (value == null || value === false) {
2030
- return;
2031
- }
2032
- const output = createElementFn(value);
2033
- nodes = toNodeArray(output);
2034
- const parentNode = marker.parentNode;
2035
- if (parentNode) {
2036
- insertNodesBefore(parentNode, nodes, marker);
2037
- }
2038
- return () => {
2039
- destroyRoot(root);
2040
- removeNodes(nodes);
2041
- };
2042
- } catch (err) {
2043
- if (handleSuspend(err, root)) {
2044
- handledError = true;
2045
- destroyRoot(root);
2046
- return;
2047
- }
2048
- if (handleError(err, { source: "renderChild" }, root)) {
2049
- handledError = true;
2050
- destroyRoot(root);
2051
- return;
2052
- }
2053
- throw err;
2054
- } finally {
2055
- popRoot(prev);
2056
- if (!handledError) {
2057
- flushOnMount(root);
2058
- }
1984
+ function isBindingHandle(node) {
1985
+ return node !== null && typeof node === "object" && "marker" in node && "dispose" in node && typeof node.dispose === "function";
1986
+ }
1987
+ function appendChildNode(parent, child, namespace) {
1988
+ if (child === null || child === void 0 || child === false) {
1989
+ return;
1990
+ }
1991
+ if (isBindingHandle(child)) {
1992
+ appendChildNode(parent, child.marker, namespace);
1993
+ child.flush?.();
1994
+ return;
1995
+ }
1996
+ if (typeof child === "function" && child.length === 0) {
1997
+ const childGetter = child;
1998
+ createChildBinding(parent, childGetter, (node) => createElementWithContext(node, namespace));
1999
+ return;
2000
+ }
2001
+ if (Array.isArray(child)) {
2002
+ for (const item of child) {
2003
+ appendChildNode(parent, item, namespace);
2059
2004
  }
2060
- });
2061
- return {
2062
- marker,
2063
- dispose: () => {
2064
- dispose();
2065
- marker.parentNode?.removeChild(marker);
2005
+ return;
2006
+ }
2007
+ let domNode;
2008
+ if (typeof child !== "object" || child === null) {
2009
+ domNode = document.createTextNode(String(child ?? ""));
2010
+ } else {
2011
+ domNode = createElementWithContext(child, namespace);
2012
+ }
2013
+ if (domNode.nodeType === 11) {
2014
+ const children = Array.from(domNode.childNodes);
2015
+ for (const node of children) {
2016
+ appendChildNode(parent, node, namespace);
2066
2017
  }
2067
- };
2018
+ return;
2019
+ }
2020
+ if (domNode.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {
2021
+ parent.ownerDocument.adoptNode(domNode);
2022
+ }
2023
+ try {
2024
+ parent.appendChild(domNode);
2025
+ } catch (e) {
2026
+ if (parent.ownerDocument) {
2027
+ const clone = parent.ownerDocument.importNode(domNode, true);
2028
+ parent.appendChild(clone);
2029
+ return;
2030
+ }
2031
+ throw e;
2032
+ }
2068
2033
  }
2069
- function delegateEvents(eventNames, doc = window.document) {
2070
- const e = doc[$$EVENTS] || (doc[$$EVENTS] = /* @__PURE__ */ new Set());
2071
- for (let i = 0, l = eventNames.length; i < l; i++) {
2072
- const name = eventNames[i];
2073
- if (!e.has(name)) {
2074
- e.add(name);
2075
- doc.addEventListener(name, globalEventHandler);
2034
+ function appendChildren(parent, children, namespace) {
2035
+ if (children === void 0) return;
2036
+ if (Array.isArray(children)) {
2037
+ for (const child of children) {
2038
+ appendChildren(parent, child, namespace);
2076
2039
  }
2040
+ return;
2077
2041
  }
2042
+ appendChildNode(parent, children, namespace);
2078
2043
  }
2079
- function clearDelegatedEvents(doc = window.document) {
2080
- const e = doc[$$EVENTS];
2081
- if (e) {
2082
- for (const name of e.keys()) {
2083
- doc.removeEventListener(name, globalEventHandler);
2044
+ function applyRef(el, value) {
2045
+ if (typeof value === "function") {
2046
+ const refFn = value;
2047
+ refFn(el);
2048
+ if (getCurrentRoot()) {
2049
+ registerRootCleanup(() => {
2050
+ refFn(null);
2051
+ });
2052
+ }
2053
+ } else if (value && typeof value === "object" && "current" in value) {
2054
+ const refObj = value;
2055
+ refObj.current = el;
2056
+ if (getCurrentRoot()) {
2057
+ registerRootCleanup(() => {
2058
+ refObj.current = null;
2059
+ });
2084
2060
  }
2085
- delete doc[$$EVENTS];
2086
2061
  }
2087
2062
  }
2088
- function globalEventHandler(e) {
2089
- let node = e.target;
2090
- const key = `$$${e.type}`;
2091
- const dataKey = `${key}Data`;
2092
- const oriTarget = e.target;
2093
- const oriCurrentTarget = e.currentTarget;
2094
- const retarget = (value) => Object.defineProperty(e, "target", {
2095
- configurable: true,
2096
- value
2097
- });
2098
- const handleNode = () => {
2099
- if (!node) return false;
2100
- const handler = node[key];
2101
- if (handler && !node.disabled) {
2102
- const resolveData = (value) => {
2103
- if (typeof value === "function") {
2104
- try {
2105
- const fn = value;
2106
- return fn.length > 0 ? fn(e) : fn();
2107
- } catch {
2108
- return value();
2109
- }
2063
+ function applyProps(el, props, isSVG = false) {
2064
+ props = unwrapProps(props);
2065
+ const tagName = el.tagName;
2066
+ const isCE = tagName.includes("-") || "is" in props;
2067
+ for (const [key, value] of Object.entries(props)) {
2068
+ if (key === "children") continue;
2069
+ if (key === "ref") {
2070
+ applyRef(el, value);
2071
+ continue;
2072
+ }
2073
+ if (isEventKey(key)) {
2074
+ bindEvent(
2075
+ el,
2076
+ eventNameFromProp(key),
2077
+ value
2078
+ );
2079
+ continue;
2080
+ }
2081
+ if (key.slice(0, 3) === "on:") {
2082
+ bindEvent(
2083
+ el,
2084
+ key.slice(3),
2085
+ value,
2086
+ false
2087
+ // Non-delegated
2088
+ );
2089
+ continue;
2090
+ }
2091
+ if (key.slice(0, 10) === "oncapture:") {
2092
+ bindEvent(
2093
+ el,
2094
+ key.slice(10),
2095
+ value,
2096
+ true
2097
+ // Capture
2098
+ );
2099
+ continue;
2100
+ }
2101
+ if (key === "class" || key === "className") {
2102
+ createClassBinding(el, value);
2103
+ continue;
2104
+ }
2105
+ if (key === "classList") {
2106
+ createClassBinding(el, value);
2107
+ continue;
2108
+ }
2109
+ if (key === "style") {
2110
+ createStyleBinding(
2111
+ el,
2112
+ value
2113
+ );
2114
+ continue;
2115
+ }
2116
+ if (key === "dangerouslySetInnerHTML" && value && typeof value === "object") {
2117
+ const htmlValue = value.__html;
2118
+ if (htmlValue !== void 0) {
2119
+ if (isReactive(htmlValue)) {
2120
+ createAttributeBinding(el, "innerHTML", htmlValue, setInnerHTML);
2121
+ } else {
2122
+ el.innerHTML = htmlValue;
2110
2123
  }
2111
- return value;
2112
- };
2113
- const rawData = node[dataKey];
2114
- const hasData = rawData !== void 0;
2115
- const resolvedNodeData = hasData ? resolveData(rawData) : void 0;
2116
- if (typeof handler === "function") {
2117
- callEventHandler(handler, e, node, hasData ? resolvedNodeData : void 0);
2118
- } else if (Array.isArray(handler)) {
2119
- const tupleData = resolveData(handler[1]);
2120
- callEventHandler(handler[0], e, node, tupleData);
2121
2124
  }
2122
- if (e.cancelBubble) return false;
2125
+ continue;
2123
2126
  }
2124
- const shadowHost = node.host;
2125
- if (shadowHost && typeof shadowHost !== "string" && !shadowHost._$host && node.contains(e.target)) {
2126
- retarget(shadowHost);
2127
+ if (ChildProperties.has(key)) {
2128
+ createAttributeBinding(el, key, value, setProperty);
2129
+ continue;
2127
2130
  }
2128
- return true;
2129
- };
2130
- const walkUpTree = () => {
2131
- while (handleNode() && node) {
2132
- node = node._$host || node.parentNode || node.host;
2131
+ if (key.slice(0, 5) === "attr:") {
2132
+ createAttributeBinding(el, key.slice(5), value, setAttribute);
2133
+ continue;
2133
2134
  }
2134
- };
2135
- Object.defineProperty(e, "currentTarget", {
2136
- configurable: true,
2137
- get() {
2138
- return node || document;
2135
+ if (key.slice(0, 5) === "bool:") {
2136
+ createAttributeBinding(el, key.slice(5), value, setBoolAttribute);
2137
+ continue;
2139
2138
  }
2140
- });
2141
- if (e.composedPath) {
2142
- const path = e.composedPath();
2143
- retarget(path[0]);
2144
- for (let i = 0; i < path.length - 2; i++) {
2145
- node = path[i];
2146
- if (!handleNode()) break;
2147
- if (node._$host) {
2148
- node = node._$host;
2149
- walkUpTree();
2150
- break;
2139
+ if (key.slice(0, 5) === "prop:") {
2140
+ createAttributeBinding(el, key.slice(5), value, setProperty);
2141
+ continue;
2142
+ }
2143
+ const propAlias = !isSVG ? getPropAlias(key, tagName) : void 0;
2144
+ if (propAlias || !isSVG && Properties.has(key) || isCE && !isSVG) {
2145
+ const propName = propAlias || key;
2146
+ if (isCE && !Properties.has(key)) {
2147
+ createAttributeBinding(
2148
+ el,
2149
+ toPropertyName(propName),
2150
+ value,
2151
+ setProperty
2152
+ );
2153
+ } else {
2154
+ createAttributeBinding(el, propName, value, setProperty);
2151
2155
  }
2152
- if (node.parentNode === oriCurrentTarget) {
2153
- break;
2156
+ continue;
2157
+ }
2158
+ if (isSVG && key.indexOf(":") > -1) {
2159
+ const [prefix, name] = key.split(":");
2160
+ const ns = SVGNamespace[prefix];
2161
+ if (ns) {
2162
+ createAttributeBinding(
2163
+ el,
2164
+ key,
2165
+ value,
2166
+ (el2, _key, val) => setAttributeNS(el2, ns, name, val)
2167
+ );
2168
+ continue;
2154
2169
  }
2155
2170
  }
2156
- } else {
2157
- walkUpTree();
2171
+ const attrName = Aliases[key] || key;
2172
+ createAttributeBinding(el, attrName, value, setAttribute);
2158
2173
  }
2159
- retarget(oriTarget);
2160
2174
  }
2161
- function addEventListener(node, name, handler, delegate) {
2162
- if (handler == null) return;
2163
- if (delegate) {
2164
- if (Array.isArray(handler)) {
2165
- ;
2166
- node[`$$${name}`] = handler[0];
2167
- node[`$$${name}Data`] = handler[1];
2168
- } else {
2169
- ;
2170
- node[`$$${name}`] = handler;
2171
- }
2172
- } else if (Array.isArray(handler)) {
2173
- const handlerFn = handler[0];
2174
- node.addEventListener(name, (e) => handlerFn.call(node, handler[1], e));
2175
- } else {
2176
- node.addEventListener(name, handler);
2177
- }
2175
+ function toPropertyName(name) {
2176
+ return name.toLowerCase().replace(/-([a-z])/g, (_, w) => w.toUpperCase());
2178
2177
  }
2179
- function bindEvent(el, eventName, handler, options2) {
2180
- if (handler == null) return () => {
2181
- };
2182
- const rootRef = getCurrentRoot();
2183
- if (DelegatedEvents.has(eventName) && !options2) {
2184
- const key = `$$${eventName}`;
2185
- delegateEvents([eventName]);
2186
- const resolveHandler = isReactive(handler) ? handler : () => handler;
2187
- el[key] = function(...args) {
2188
- try {
2189
- const fn = resolveHandler();
2190
- callEventHandler(fn, args[0], el);
2191
- } catch (err) {
2192
- handleError(err, { source: "event", eventName }, rootRef);
2193
- }
2194
- };
2195
- return () => {
2196
- el[key] = void 0;
2197
- };
2178
+ var setAttribute = (el, key, value) => {
2179
+ if (value === void 0 || value === null || value === false) {
2180
+ el.removeAttribute(key);
2181
+ return;
2198
2182
  }
2199
- const getHandler = isReactive(handler) ? handler : () => handler;
2200
- const wrapped = (event) => {
2201
- try {
2202
- const resolved = getHandler();
2203
- callEventHandler(resolved, event, el);
2204
- } catch (err) {
2205
- if (handleError(err, { source: "event", eventName }, rootRef)) {
2206
- return;
2183
+ if (value === true) {
2184
+ el.setAttribute(key, "");
2185
+ return;
2186
+ }
2187
+ const valueType = typeof value;
2188
+ if (valueType === "string" || valueType === "number") {
2189
+ el.setAttribute(key, String(value));
2190
+ return;
2191
+ }
2192
+ if (key in el) {
2193
+ ;
2194
+ el[key] = value;
2195
+ return;
2196
+ }
2197
+ el.setAttribute(key, String(value));
2198
+ };
2199
+ var setProperty = (el, key, value) => {
2200
+ if (value === void 0 || value === null) {
2201
+ const fallback = key === "checked" || key === "selected" ? false : "";
2202
+ el[key] = fallback;
2203
+ return;
2204
+ }
2205
+ if (key === "style" && typeof value === "object" && value !== null) {
2206
+ for (const k in value) {
2207
+ const v = value[k];
2208
+ if (v !== void 0) {
2209
+ ;
2210
+ el.style[k] = String(v);
2207
2211
  }
2208
- throw err;
2209
- }
2210
- };
2211
- el.addEventListener(eventName, wrapped, options2);
2212
- const cleanup = () => el.removeEventListener(eventName, wrapped, options2);
2213
- registerRootCleanup(cleanup);
2214
- return cleanup;
2215
- }
2216
- function bindRef(el, ref) {
2217
- if (ref == null) return () => {
2218
- };
2219
- const getRef = isReactive(ref) ? ref : () => ref;
2220
- const applyRef2 = (refValue) => {
2221
- if (refValue == null) return;
2222
- if (typeof refValue === "function") {
2223
- ;
2224
- refValue(el);
2225
- } else if (typeof refValue === "object" && "current" in refValue) {
2226
- ;
2227
- refValue.current = el;
2228
2212
  }
2229
- };
2230
- const initialRef = getRef();
2231
- applyRef2(initialRef);
2232
- if (isReactive(ref)) {
2233
- const cleanup2 = createRenderEffect(() => {
2234
- const currentRef = getRef();
2235
- applyRef2(currentRef);
2236
- });
2237
- registerRootCleanup(cleanup2);
2238
- const nullifyCleanup = () => {
2239
- const currentRef = getRef();
2240
- if (currentRef && typeof currentRef === "object" && "current" in currentRef) {
2241
- ;
2242
- currentRef.current = null;
2243
- }
2244
- };
2245
- registerRootCleanup(nullifyCleanup);
2246
- return () => {
2247
- cleanup2();
2248
- nullifyCleanup();
2249
- };
2213
+ return;
2250
2214
  }
2251
- const cleanup = () => {
2252
- const refValue = getRef();
2253
- if (refValue && typeof refValue === "object" && "current" in refValue) {
2254
- ;
2255
- refValue.current = null;
2256
- }
2257
- };
2258
- registerRootCleanup(cleanup);
2259
- return cleanup;
2260
- }
2261
- function spread(node, props = {}, isSVG = false, skipChildren = false) {
2262
- const prevProps = {};
2263
- if (!skipChildren && "children" in props) {
2264
- createRenderEffect(() => {
2265
- prevProps.children = props.children;
2266
- });
2215
+ ;
2216
+ el[key] = value;
2217
+ };
2218
+ var setInnerHTML = (el, _key, value) => {
2219
+ ;
2220
+ el.innerHTML = value == null ? "" : String(value);
2221
+ };
2222
+ var setBoolAttribute = (el, key, value) => {
2223
+ if (value) {
2224
+ el.setAttribute(key, "");
2225
+ } else {
2226
+ el.removeAttribute(key);
2227
+ }
2228
+ };
2229
+ function setAttributeNS(el, namespace, name, value) {
2230
+ if (value == null) {
2231
+ el.removeAttributeNS(namespace, name);
2232
+ } else {
2233
+ el.setAttributeNS(namespace, name, String(value));
2267
2234
  }
2268
- createRenderEffect(() => {
2269
- if (typeof props.ref === "function") {
2270
- ;
2271
- props.ref(node);
2272
- }
2273
- });
2274
- createRenderEffect(() => {
2275
- assign(node, props, isSVG, true, prevProps, true);
2276
- });
2277
- return prevProps;
2278
2235
  }
2279
- function assign(node, props, isSVG = false, skipChildren = false, prevProps = {}, skipRef = false) {
2280
- props = props || {};
2281
- for (const prop in prevProps) {
2282
- if (!(prop in props)) {
2283
- if (prop === "children") continue;
2284
- prevProps[prop] = assignProp(node, prop, null, prevProps[prop], isSVG, skipRef, props);
2236
+ function isEventKey(key) {
2237
+ return key.startsWith("on") && key.length > 2 && key[2].toUpperCase() === key[2];
2238
+ }
2239
+ function eventNameFromProp(key) {
2240
+ return key.slice(2).toLowerCase();
2241
+ }
2242
+
2243
+ // src/reconcile.ts
2244
+ function reconcileArrays(parentNode, a, b) {
2245
+ const bLength = b.length;
2246
+ let aEnd = a.length;
2247
+ let bEnd = bLength;
2248
+ let aStart = 0;
2249
+ let bStart = 0;
2250
+ const after = aEnd > 0 ? a[aEnd - 1].nextSibling : null;
2251
+ let map = null;
2252
+ while (aStart < aEnd || bStart < bEnd) {
2253
+ if (a[aStart] === b[bStart]) {
2254
+ aStart++;
2255
+ bStart++;
2256
+ continue;
2285
2257
  }
2286
- }
2287
- for (const prop in props) {
2288
- if (prop === "children") {
2289
- if (!skipChildren) {
2290
- prevProps.children = props.children;
2258
+ while (a[aEnd - 1] === b[bEnd - 1]) {
2259
+ aEnd--;
2260
+ bEnd--;
2261
+ }
2262
+ if (aEnd === aStart) {
2263
+ const node = bEnd < bLength ? bStart ? b[bStart - 1].nextSibling : b[bEnd - bStart] ?? null : after;
2264
+ const count = bEnd - bStart;
2265
+ const doc = parentNode.ownerDocument;
2266
+ if (count > 1 && doc) {
2267
+ const frag = doc.createDocumentFragment();
2268
+ for (let i = bStart; i < bEnd; i++) {
2269
+ frag.appendChild(b[i]);
2270
+ }
2271
+ parentNode.insertBefore(frag, node);
2272
+ bStart = bEnd;
2273
+ } else {
2274
+ while (bStart < bEnd) {
2275
+ parentNode.insertBefore(b[bStart++], node);
2276
+ }
2277
+ }
2278
+ } else if (bEnd === bStart) {
2279
+ while (aStart < aEnd) {
2280
+ const nodeToRemove = a[aStart];
2281
+ if (!map || !map.has(nodeToRemove)) {
2282
+ nodeToRemove.parentNode?.removeChild(nodeToRemove);
2283
+ }
2284
+ aStart++;
2285
+ }
2286
+ } else if (a[aStart] === b[bEnd - 1] && b[bStart] === a[aEnd - 1]) {
2287
+ const node = a[--aEnd].nextSibling;
2288
+ parentNode.insertBefore(b[bStart++], a[aStart++].nextSibling);
2289
+ parentNode.insertBefore(b[--bEnd], node);
2290
+ a[aEnd] = b[bEnd];
2291
+ } else {
2292
+ if (!map) {
2293
+ map = /* @__PURE__ */ new Map();
2294
+ let i = bStart;
2295
+ while (i < bEnd) {
2296
+ map.set(b[i], i++);
2297
+ }
2298
+ }
2299
+ const index = map.get(a[aStart]);
2300
+ if (index != null) {
2301
+ if (bStart < index && index < bEnd) {
2302
+ let i = aStart;
2303
+ let sequence = 1;
2304
+ let t;
2305
+ while (++i < aEnd && i < bEnd) {
2306
+ t = map.get(a[i]);
2307
+ if (t == null || t !== index + sequence) break;
2308
+ sequence++;
2309
+ }
2310
+ if (sequence > index - bStart) {
2311
+ const node = a[aStart];
2312
+ while (bStart < index) {
2313
+ parentNode.insertBefore(b[bStart++], node);
2314
+ }
2315
+ } else {
2316
+ parentNode.replaceChild(b[bStart++], a[aStart++]);
2317
+ }
2318
+ } else {
2319
+ aStart++;
2320
+ }
2321
+ } else {
2322
+ const nodeToRemove = a[aStart++];
2323
+ nodeToRemove.parentNode?.removeChild(nodeToRemove);
2291
2324
  }
2292
- continue;
2293
2325
  }
2294
- const value = props[prop];
2295
- prevProps[prop] = assignProp(node, prop, value, prevProps[prop], isSVG, skipRef, props);
2296
2326
  }
2297
2327
  }
2298
- function assignProp(node, prop, value, prev, isSVG, skipRef, props) {
2299
- if (prop === "style") {
2300
- applyStyle(node, value, prev);
2301
- return value;
2302
- }
2303
- if (prop === "classList") {
2304
- return applyClass(node, value, prev);
2305
- }
2306
- if (value === prev) return prev;
2307
- if (prop === "ref") {
2308
- if (!skipRef && typeof value === "function") {
2309
- ;
2310
- value(node);
2328
+
2329
+ // src/list-helpers.ts
2330
+ function moveNodesBefore(parent, nodes, anchor) {
2331
+ for (let i = nodes.length - 1; i >= 0; i--) {
2332
+ const node = nodes[i];
2333
+ if (!node || !(node instanceof Node)) {
2334
+ throw new Error("Invalid node in moveNodesBefore");
2311
2335
  }
2312
- return value;
2313
- }
2314
- if (prop.slice(0, 3) === "on:") {
2315
- const eventName = prop.slice(3);
2316
- if (prev) node.removeEventListener(eventName, prev);
2317
- if (value) node.addEventListener(eventName, value);
2318
- return value;
2336
+ if (node.nextSibling !== anchor) {
2337
+ if (node.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {
2338
+ parent.ownerDocument.adoptNode(node);
2339
+ }
2340
+ try {
2341
+ parent.insertBefore(node, anchor);
2342
+ } catch (e) {
2343
+ if (parent.ownerDocument) {
2344
+ try {
2345
+ const clone = parent.ownerDocument.importNode(node, true);
2346
+ parent.insertBefore(clone, anchor);
2347
+ continue;
2348
+ } catch {
2349
+ }
2350
+ }
2351
+ throw e;
2352
+ }
2353
+ }
2354
+ anchor = node;
2319
2355
  }
2320
- if (prop.slice(0, 10) === "oncapture:") {
2321
- const eventName = prop.slice(10);
2322
- if (prev) node.removeEventListener(eventName, prev, true);
2323
- if (value) node.addEventListener(eventName, value, true);
2324
- return value;
2356
+ }
2357
+ function moveMarkerBlock(parent, block, anchor) {
2358
+ const nodes = collectBlockNodes(block);
2359
+ if (nodes.length === 0) return;
2360
+ moveNodesBefore(parent, nodes, anchor);
2361
+ }
2362
+ function destroyMarkerBlock(block) {
2363
+ if (block.root) {
2364
+ destroyRoot(block.root);
2325
2365
  }
2326
- if (prop.slice(0, 2) === "on") {
2327
- const eventName = prop.slice(2).toLowerCase();
2328
- const shouldDelegate = DelegatedEvents.has(eventName);
2329
- if (!shouldDelegate && prev) {
2330
- const handler = Array.isArray(prev) ? prev[0] : prev;
2331
- node.removeEventListener(eventName, handler);
2366
+ removeBlockRange(block);
2367
+ }
2368
+ function collectBlockNodes(block) {
2369
+ const nodes = [];
2370
+ let cursor = block.start;
2371
+ while (cursor) {
2372
+ nodes.push(cursor);
2373
+ if (cursor === block.end) {
2374
+ break;
2332
2375
  }
2333
- if (shouldDelegate || value) {
2334
- addEventListener(node, eventName, value, shouldDelegate);
2335
- if (shouldDelegate) delegateEvents([eventName]);
2376
+ cursor = cursor.nextSibling;
2377
+ }
2378
+ return nodes;
2379
+ }
2380
+ function removeBlockRange(block) {
2381
+ let cursor = block.start;
2382
+ while (cursor) {
2383
+ const next = cursor.nextSibling;
2384
+ cursor.parentNode?.removeChild(cursor);
2385
+ if (cursor === block.end) {
2386
+ break;
2336
2387
  }
2337
- return value;
2388
+ cursor = next;
2338
2389
  }
2339
- if (prop.slice(0, 5) === "attr:") {
2340
- if (value == null) node.removeAttribute(prop.slice(5));
2341
- else node.setAttribute(prop.slice(5), String(value));
2342
- return value;
2343
- }
2344
- if (prop.slice(0, 5) === "bool:") {
2345
- if (value) node.setAttribute(prop.slice(5), "");
2346
- else node.removeAttribute(prop.slice(5));
2347
- return value;
2348
- }
2349
- if (prop.slice(0, 5) === "prop:") {
2350
- ;
2351
- node[prop.slice(5)] = value;
2352
- return value;
2353
- }
2354
- if (prop === "class" || prop === "className") {
2355
- if (value == null) node.removeAttribute("class");
2356
- else node.className = String(value);
2357
- return value;
2358
- }
2359
- const isCE = node.nodeName.includes("-") || "is" in props;
2360
- if (!isSVG) {
2361
- const propAlias = getPropAlias(prop, node.tagName);
2362
- const isProperty = Properties.has(prop);
2363
- const isChildProp = ChildProperties.has(prop);
2364
- if (propAlias || isProperty || isChildProp || isCE) {
2365
- const propName = propAlias || prop;
2366
- if (isCE && !isProperty && !isChildProp) {
2367
- ;
2368
- node[toPropertyName(propName)] = value;
2369
- } else {
2370
- ;
2371
- node[propName] = value;
2372
- }
2373
- return value;
2374
- }
2375
- }
2376
- if (isSVG && prop.indexOf(":") > -1) {
2377
- const [prefix, name] = prop.split(":");
2378
- const ns = SVGNamespace[prefix];
2379
- if (ns) {
2380
- if (value == null) node.removeAttributeNS(ns, name);
2381
- else node.setAttributeNS(ns, name, String(value));
2382
- return value;
2390
+ }
2391
+ function createVersionedSignalAccessor(initialValue) {
2392
+ let current = initialValue;
2393
+ let version = 0;
2394
+ const track2 = signal(version);
2395
+ function accessor(value) {
2396
+ if (arguments.length === 0) {
2397
+ track2();
2398
+ return current;
2383
2399
  }
2400
+ current = value;
2401
+ version++;
2402
+ track2(version);
2384
2403
  }
2385
- const attrName = Aliases[prop] || prop;
2386
- if (value == null) node.removeAttribute(attrName);
2387
- else node.setAttribute(attrName, String(value));
2388
- return value;
2389
- }
2390
- function toPropertyName(name) {
2391
- return name.toLowerCase().replace(/-([a-z])/g, (_, w) => w.toUpperCase());
2404
+ return accessor;
2392
2405
  }
2393
- function createConditional(condition, renderTrue, createElementFn, renderFalse) {
2394
- const startMarker = document.createComment("fict:cond:start");
2395
- const endMarker = document.createComment("fict:cond:end");
2396
- const fragment = document.createDocumentFragment();
2397
- fragment.append(startMarker, endMarker);
2398
- let currentNodes = [];
2399
- let currentRoot2 = null;
2400
- let lastCondition = void 0;
2401
- let pendingRender = false;
2402
- const conditionMemo = computed(condition);
2403
- const runConditional = () => {
2404
- const cond = conditionMemo();
2405
- const parent = startMarker.parentNode;
2406
- if (!parent) {
2407
- pendingRender = true;
2408
- return;
2409
- }
2410
- pendingRender = false;
2411
- if (lastCondition === cond && currentNodes.length > 0) {
2412
- return;
2413
- }
2414
- if (lastCondition === cond && lastCondition === false && renderFalse === void 0) {
2415
- return;
2416
- }
2417
- lastCondition = cond;
2418
- if (currentRoot2) {
2419
- destroyRoot(currentRoot2);
2420
- currentRoot2 = null;
2406
+ function createKeyedListContainer() {
2407
+ const startMarker = document.createComment("fict:list:start");
2408
+ const endMarker = document.createComment("fict:list:end");
2409
+ const dispose = () => {
2410
+ for (const block of container.blocks.values()) {
2411
+ destroyRoot(block.root);
2421
2412
  }
2422
- removeNodes(currentNodes);
2423
- currentNodes = [];
2424
- const render2 = cond ? renderTrue : renderFalse;
2425
- if (!render2) {
2413
+ container.blocks.clear();
2414
+ container.nextBlocks.clear();
2415
+ if (!startMarker.parentNode || !endMarker.parentNode) {
2416
+ container.currentNodes = [];
2417
+ container.nextNodes = [];
2418
+ container.orderedBlocks.length = 0;
2419
+ container.nextOrderedBlocks.length = 0;
2420
+ container.orderedIndexByKey.clear();
2426
2421
  return;
2427
2422
  }
2428
- const root = createRootContext();
2429
- const prev = pushRoot(root);
2430
- let handledError = false;
2431
- try {
2432
- const output = untrack(render2);
2433
- if (output == null || output === false) {
2434
- return;
2435
- }
2436
- const el = createElementFn(output);
2437
- const nodes = toNodeArray(el);
2438
- insertNodesBefore(parent, nodes, endMarker);
2439
- currentNodes = nodes;
2440
- } catch (err) {
2441
- if (handleSuspend(err, root)) {
2442
- handledError = true;
2443
- destroyRoot(root);
2444
- return;
2445
- }
2446
- if (handleError(err, { source: "renderChild" }, root)) {
2447
- handledError = true;
2448
- destroyRoot(root);
2449
- return;
2450
- }
2451
- throw err;
2452
- } finally {
2453
- popRoot(prev);
2454
- if (!handledError) {
2455
- flushOnMount(root);
2456
- currentRoot2 = root;
2457
- } else {
2458
- currentRoot2 = null;
2459
- }
2460
- }
2423
+ const range = document.createRange();
2424
+ range.setStartBefore(startMarker);
2425
+ range.setEndAfter(endMarker);
2426
+ range.deleteContents();
2427
+ container.currentNodes = [];
2428
+ container.nextNodes = [];
2429
+ container.nextBlocks.clear();
2430
+ container.orderedBlocks.length = 0;
2431
+ container.nextOrderedBlocks.length = 0;
2432
+ container.orderedIndexByKey.clear();
2461
2433
  };
2462
- const dispose = createRenderEffect(runConditional);
2463
- return {
2464
- marker: fragment,
2465
- flush: () => {
2466
- if (pendingRender) {
2467
- runConditional();
2468
- }
2469
- },
2470
- dispose: () => {
2471
- dispose();
2472
- if (currentRoot2) {
2473
- destroyRoot(currentRoot2);
2474
- }
2475
- removeNodes(currentNodes);
2476
- currentNodes = [];
2477
- startMarker.parentNode?.removeChild(startMarker);
2478
- endMarker.parentNode?.removeChild(endMarker);
2434
+ const container = {
2435
+ startMarker,
2436
+ endMarker,
2437
+ blocks: /* @__PURE__ */ new Map(),
2438
+ nextBlocks: /* @__PURE__ */ new Map(),
2439
+ currentNodes: [startMarker, endMarker],
2440
+ nextNodes: [],
2441
+ orderedBlocks: [],
2442
+ nextOrderedBlocks: [],
2443
+ orderedIndexByKey: /* @__PURE__ */ new Map(),
2444
+ dispose
2445
+ };
2446
+ return container;
2447
+ }
2448
+ function createKeyedBlock(key, item, index, render2, needsIndex = true, hostRoot) {
2449
+ const itemSig = createVersionedSignalAccessor(item);
2450
+ const indexSig = needsIndex ? signal(index) : ((next) => {
2451
+ if (arguments.length === 0) return index;
2452
+ index = next;
2453
+ return index;
2454
+ });
2455
+ const root = createRootContext(hostRoot);
2456
+ const prevRoot = pushRoot(root);
2457
+ const prevSub = setActiveSub(void 0);
2458
+ let nodes = [];
2459
+ try {
2460
+ const rendered = render2(itemSig, indexSig, key);
2461
+ if (rendered instanceof Node || Array.isArray(rendered) && rendered.every((n) => n instanceof Node)) {
2462
+ nodes = toNodeArray(rendered);
2463
+ } else {
2464
+ const element = createElement(rendered);
2465
+ nodes = toNodeArray(element);
2479
2466
  }
2467
+ } finally {
2468
+ setActiveSub(prevSub);
2469
+ popRoot(prevRoot);
2470
+ flushOnMount(root);
2471
+ }
2472
+ return {
2473
+ key,
2474
+ nodes,
2475
+ root,
2476
+ item: itemSig,
2477
+ index: indexSig,
2478
+ rawItem: item,
2479
+ rawIndex: index
2480
2480
  };
2481
2481
  }
2482
- function createList(items, renderItem, createElementFn, getKey) {
2483
- const startMarker = document.createComment("fict:list:start");
2484
- const endMarker = document.createComment("fict:list:end");
2482
+ function getFirstNodeAfter(marker) {
2483
+ return marker.nextSibling;
2484
+ }
2485
+ function isNodeBetweenMarkers(node, startMarker, endMarker) {
2486
+ let current = startMarker.nextSibling;
2487
+ while (current && current !== endMarker) {
2488
+ if (current === node) return true;
2489
+ current = current.nextSibling;
2490
+ }
2491
+ return false;
2492
+ }
2493
+ function createKeyedList(getItems, keyFn, renderItem, needsIndex) {
2494
+ const resolvedNeedsIndex = arguments.length >= 4 ? !!needsIndex : renderItem.length > 1;
2495
+ return createFineGrainedKeyedList(getItems, keyFn, renderItem, resolvedNeedsIndex);
2496
+ }
2497
+ function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
2498
+ const container = createKeyedListContainer();
2499
+ const hostRoot = getCurrentRoot();
2485
2500
  const fragment = document.createDocumentFragment();
2486
- fragment.append(startMarker, endMarker);
2487
- const nodeMap = /* @__PURE__ */ new Map();
2501
+ fragment.append(container.startMarker, container.endMarker);
2488
2502
  let pendingItems = null;
2489
- const runListUpdate = () => {
2490
- const arr = items();
2491
- const parent = startMarker.parentNode;
2492
- if (!parent) {
2493
- pendingItems = arr;
2494
- return;
2495
- }
2496
- pendingItems = null;
2497
- const newNodeMap = /* @__PURE__ */ new Map();
2498
- const blocks = [];
2499
- for (let i = 0; i < arr.length; i++) {
2500
- const item = arr[i];
2501
- const key = getKey ? getKey(item, i) : i;
2502
- const existing = nodeMap.get(key);
2503
- let block;
2504
- if (existing) {
2505
- const previousValue = existing.value();
2506
- if (!getKey && previousValue !== item) {
2507
- destroyRoot(existing.root);
2508
- removeBlockNodes(existing);
2509
- block = mountBlock(item, i, renderItem, parent, endMarker, createElementFn);
2510
- } else {
2511
- const previousIndex = existing.index();
2512
- existing.value(item);
2513
- existing.index(i);
2514
- if (previousValue === item) {
2515
- bumpBlockVersion(existing);
2516
- }
2517
- const needsRerender = getKey ? true : previousValue !== item || previousIndex !== i;
2518
- block = needsRerender ? rerenderBlock(existing, createElementFn) : existing;
2503
+ let disposed = false;
2504
+ const performDiff = () => {
2505
+ if (disposed) return;
2506
+ batch2(() => {
2507
+ const newItems = pendingItems || getItems();
2508
+ pendingItems = null;
2509
+ const oldBlocks = container.blocks;
2510
+ const newBlocks = container.nextBlocks;
2511
+ const prevOrderedBlocks = container.orderedBlocks;
2512
+ const nextOrderedBlocks = container.nextOrderedBlocks;
2513
+ const orderedIndexByKey = container.orderedIndexByKey;
2514
+ newBlocks.clear();
2515
+ nextOrderedBlocks.length = 0;
2516
+ 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
+ }
2525
+ if (newItems.length === 0) {
2526
+ if (oldBlocks.size > 0) {
2527
+ for (const block of oldBlocks.values()) {
2528
+ destroyRoot(block.root);
2529
+ removeNodes(block.nodes);
2530
+ }
2519
2531
  }
2520
- } else {
2521
- block = mountBlock(item, i, renderItem, parent, endMarker, createElementFn);
2532
+ oldBlocks.clear();
2533
+ newBlocks.clear();
2534
+ prevOrderedBlocks.length = 0;
2535
+ nextOrderedBlocks.length = 0;
2536
+ orderedIndexByKey.clear();
2537
+ container.currentNodes.length = 0;
2538
+ container.currentNodes.push(container.startMarker, container.endMarker);
2539
+ container.nextNodes.length = 0;
2540
+ return;
2522
2541
  }
2523
- newNodeMap.set(key, block);
2524
- blocks.push(block);
2525
- }
2526
- for (const [key, managed] of nodeMap) {
2527
- if (!newNodeMap.has(key)) {
2528
- destroyRoot(managed.root);
2529
- removeBlockNodes(managed);
2542
+ const prevCount = prevOrderedBlocks.length;
2543
+ let appendCandidate = prevCount > 0 && newItems.length >= prevCount;
2544
+ const appendedBlocks = [];
2545
+ newItems.forEach((item, index) => {
2546
+ const key = keyFn(item, index);
2547
+ const existed = oldBlocks.has(key);
2548
+ let block = oldBlocks.get(key);
2549
+ if (block) {
2550
+ if (block.rawItem !== item) {
2551
+ block.rawItem = item;
2552
+ block.item(item);
2553
+ }
2554
+ if (needsIndex && block.rawIndex !== index) {
2555
+ block.rawIndex = index;
2556
+ block.index(index);
2557
+ }
2558
+ }
2559
+ const existingBlock = newBlocks.get(key);
2560
+ if (existingBlock && existingBlock !== block) {
2561
+ destroyRoot(existingBlock.root);
2562
+ removeNodes(existingBlock.nodes);
2563
+ }
2564
+ if (block) {
2565
+ newBlocks.set(key, block);
2566
+ oldBlocks.delete(key);
2567
+ } else {
2568
+ const existingBlock2 = newBlocks.get(key);
2569
+ if (existingBlock2) {
2570
+ destroyRoot(existingBlock2.root);
2571
+ removeNodes(existingBlock2.nodes);
2572
+ }
2573
+ block = createKeyedBlock(key, item, index, renderItem, needsIndex, hostRoot);
2574
+ }
2575
+ const resolvedBlock = block;
2576
+ newBlocks.set(key, resolvedBlock);
2577
+ const position = orderedIndexByKey.get(key);
2578
+ if (position !== void 0) {
2579
+ 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
+ const prior = nextOrderedBlocks[position];
2592
+ if (prior && prior !== resolvedBlock) {
2593
+ destroyRoot(prior.root);
2594
+ removeNodes(prior.nodes);
2595
+ }
2596
+ nextOrderedBlocks[position] = resolvedBlock;
2597
+ } else {
2598
+ orderedIndexByKey.set(key, nextOrderedBlocks.length);
2599
+ nextOrderedBlocks.push(resolvedBlock);
2600
+ }
2601
+ if (appendCandidate && index >= prevCount) {
2602
+ appendedBlocks.push(resolvedBlock);
2603
+ }
2604
+ });
2605
+ const canAppend = appendCandidate && prevCount > 0 && newItems.length > prevCount && oldBlocks.size === 0 && appendedBlocks.length > 0;
2606
+ if (canAppend) {
2607
+ const appendedNodes = [];
2608
+ for (const block of appendedBlocks) {
2609
+ for (let i = 0; i < block.nodes.length; i++) {
2610
+ appendedNodes.push(block.nodes[i]);
2611
+ }
2612
+ }
2613
+ if (appendedNodes.length > 0) {
2614
+ insertNodesBefore(parent, appendedNodes, container.endMarker);
2615
+ const currentNodes = container.currentNodes;
2616
+ currentNodes.pop();
2617
+ for (let i = 0; i < appendedNodes.length; i++) {
2618
+ currentNodes.push(appendedNodes[i]);
2619
+ }
2620
+ currentNodes.push(container.endMarker);
2621
+ }
2622
+ container.blocks = newBlocks;
2623
+ container.nextBlocks = oldBlocks;
2624
+ container.orderedBlocks = nextOrderedBlocks;
2625
+ container.nextOrderedBlocks = prevOrderedBlocks;
2626
+ return;
2530
2627
  }
2531
- }
2532
- let anchor = endMarker;
2533
- for (let i = blocks.length - 1; i >= 0; i--) {
2534
- const block = blocks[i];
2535
- insertNodesBefore(parent, block.nodes, anchor);
2536
- if (block.nodes.length > 0) {
2537
- anchor = block.nodes[0];
2628
+ if (oldBlocks.size > 0) {
2629
+ for (const block of oldBlocks.values()) {
2630
+ destroyRoot(block.root);
2631
+ removeNodes(block.nodes);
2632
+ }
2633
+ oldBlocks.clear();
2538
2634
  }
2539
- }
2540
- nodeMap.clear();
2541
- for (const [k, v] of newNodeMap) {
2542
- nodeMap.set(k, v);
2543
- }
2635
+ if (newBlocks.size > 0 || container.currentNodes.length > 0) {
2636
+ const prevNodes = container.currentNodes;
2637
+ const nextNodes = container.nextNodes;
2638
+ nextNodes.length = 0;
2639
+ nextNodes.push(container.startMarker);
2640
+ for (let i = 0; i < nextOrderedBlocks.length; i++) {
2641
+ const nodes = nextOrderedBlocks[i].nodes;
2642
+ for (let j = 0; j < nodes.length; j++) {
2643
+ nextNodes.push(nodes[j]);
2644
+ }
2645
+ }
2646
+ nextNodes.push(container.endMarker);
2647
+ reconcileArrays(parent, prevNodes, nextNodes);
2648
+ container.currentNodes = nextNodes;
2649
+ container.nextNodes = prevNodes;
2650
+ }
2651
+ container.blocks = newBlocks;
2652
+ container.nextBlocks = oldBlocks;
2653
+ container.orderedBlocks = nextOrderedBlocks;
2654
+ container.nextOrderedBlocks = prevOrderedBlocks;
2655
+ });
2544
2656
  };
2545
- const dispose = createRenderEffect(runListUpdate);
2657
+ const effectDispose = createRenderEffect(performDiff);
2546
2658
  return {
2547
2659
  marker: fragment,
2660
+ startMarker: container.startMarker,
2661
+ endMarker: container.endMarker,
2662
+ // Flush pending items - call after markers are inserted into DOM
2548
2663
  flush: () => {
2549
2664
  if (pendingItems !== null) {
2550
- runListUpdate();
2665
+ performDiff();
2551
2666
  }
2552
2667
  },
2553
2668
  dispose: () => {
2554
- dispose();
2555
- for (const [, managed] of nodeMap) {
2556
- destroyRoot(managed.root);
2557
- removeBlockNodes(managed);
2558
- }
2559
- nodeMap.clear();
2560
- startMarker.parentNode?.removeChild(startMarker);
2561
- endMarker.parentNode?.removeChild(endMarker);
2669
+ disposed = true;
2670
+ effectDispose?.();
2671
+ container.dispose();
2562
2672
  }
2563
2673
  };
2564
2674
  }
2565
- function createShow(el, condition, displayValue) {
2566
- const originalDisplay = displayValue ?? el.style.display;
2567
- createRenderEffect(() => {
2568
- el.style.display = condition() ? originalDisplay : "none";
2569
- });
2675
+
2676
+ // src/binding.ts
2677
+ function isReactive(value) {
2678
+ return typeof value === "function" && value.length === 0;
2570
2679
  }
2571
- function createPortal(container, render2, createElementFn) {
2572
- const parentRoot = getCurrentRoot();
2573
- const marker = document.createComment("fict:portal");
2574
- container.appendChild(marker);
2575
- let currentNodes = [];
2576
- let currentRoot2 = null;
2577
- const dispose = createRenderEffect(() => {
2578
- if (currentRoot2) {
2579
- destroyRoot(currentRoot2);
2580
- currentRoot2 = null;
2581
- }
2582
- if (currentNodes.length > 0) {
2583
- removeNodes(currentNodes);
2584
- currentNodes = [];
2585
- }
2586
- const root = createRootContext();
2587
- const prev = pushRoot(root);
2588
- let handledError = false;
2589
- try {
2590
- const output = render2();
2591
- if (output != null && output !== false) {
2592
- const el = createElementFn(output);
2593
- const nodes = toNodeArray(el);
2594
- if (marker.parentNode) {
2595
- insertNodesBefore(marker.parentNode, nodes, marker);
2680
+ function unwrap2(value) {
2681
+ return isReactive(value) ? value() : value;
2682
+ }
2683
+ function callEventHandler(handler, event, node, data) {
2684
+ if (!handler) return;
2685
+ const context = node ?? event.currentTarget ?? void 0;
2686
+ const invoke = (fn) => {
2687
+ if (typeof fn === "function") {
2688
+ const result = data === void 0 ? fn.call(context, event) : fn.call(context, data, event);
2689
+ if (typeof result === "function" && result !== fn) {
2690
+ if (data === void 0) {
2691
+ ;
2692
+ result.call(context, event);
2693
+ } else {
2694
+ ;
2695
+ result.call(context, data, event);
2596
2696
  }
2597
- currentNodes = nodes;
2598
- }
2599
- } catch (err) {
2600
- if (handleSuspend(err, root)) {
2601
- handledError = true;
2602
- destroyRoot(root);
2603
- currentNodes = [];
2604
- return;
2605
- }
2606
- if (handleError(err, { source: "renderChild" }, root)) {
2607
- handledError = true;
2608
- destroyRoot(root);
2609
- currentNodes = [];
2610
- return;
2697
+ } else if (result && typeof result.handleEvent === "function") {
2698
+ ;
2699
+ result.handleEvent.call(result, event);
2611
2700
  }
2612
- throw err;
2613
- } finally {
2614
- popRoot(prev);
2615
- if (!handledError) {
2616
- flushOnMount(root);
2617
- currentRoot2 = root;
2618
- } else {
2619
- currentRoot2 = null;
2620
- }
2621
- }
2622
- });
2623
- const portalDispose = () => {
2624
- dispose();
2625
- if (currentRoot2) {
2626
- destroyRoot(currentRoot2);
2627
- }
2628
- if (currentNodes.length > 0) {
2629
- removeNodes(currentNodes);
2701
+ } else if (fn && typeof fn.handleEvent === "function") {
2702
+ fn.handleEvent.call(fn, event);
2630
2703
  }
2631
- marker.parentNode?.removeChild(marker);
2632
2704
  };
2633
- if (parentRoot) {
2634
- parentRoot.destroyCallbacks.push(portalDispose);
2705
+ invoke(handler);
2706
+ }
2707
+ var PRIMITIVE_PROXY = Symbol("fict:primitive-proxy");
2708
+ var PRIMITIVE_PROXY_RAW_VALUE = Symbol("fict:primitive-proxy:raw-value");
2709
+ function unwrapPrimitive(value) {
2710
+ if (value && typeof value === "object" && PRIMITIVE_PROXY in value) {
2711
+ const getRawValue = value[PRIMITIVE_PROXY_RAW_VALUE];
2712
+ if (typeof getRawValue === "function") {
2713
+ return getRawValue();
2714
+ }
2635
2715
  }
2636
- return {
2637
- marker,
2638
- dispose: portalDispose
2639
- };
2716
+ return value;
2640
2717
  }
2641
- function mountBlock(initialValue, initialIndex, renderItem, parent, anchor, createElementFn) {
2642
- const start = document.createComment("fict:block:start");
2643
- const end = document.createComment("fict:block:end");
2644
- const valueSig = signal(initialValue);
2645
- const indexSig = signal(initialIndex);
2646
- const versionSig = signal(0);
2647
- const valueProxy = createValueProxy(() => {
2648
- versionSig();
2649
- return valueSig();
2650
- });
2651
- const renderCurrent = () => renderItem(valueProxy, indexSig());
2652
- const root = createRootContext();
2653
- const prev = pushRoot(root);
2654
- const nodes = [start];
2655
- let handledError = false;
2656
- try {
2657
- const output = renderCurrent();
2658
- if (output != null && output !== false) {
2659
- const el = createElementFn(output);
2660
- const rendered = toNodeArray(el);
2661
- nodes.push(...rendered);
2718
+ function createTextBinding(value) {
2719
+ const text = document.createTextNode("");
2720
+ if (isReactive(value)) {
2721
+ createRenderEffect(() => {
2722
+ const v = value();
2723
+ const fmt = formatTextValue(v);
2724
+ if (text.data !== fmt) {
2725
+ text.data = fmt;
2726
+ }
2727
+ });
2728
+ } else {
2729
+ text.data = formatTextValue(value);
2730
+ }
2731
+ return text;
2732
+ }
2733
+ function bindText(textNode, getValue) {
2734
+ return createRenderEffect(() => {
2735
+ const value = formatTextValue(getValue());
2736
+ if (textNode.data !== value) {
2737
+ textNode.data = value;
2662
2738
  }
2663
- nodes.push(end);
2664
- insertNodesBefore(parent, nodes, anchor);
2665
- } catch (err) {
2666
- if (handleSuspend(err, root)) {
2667
- handledError = true;
2668
- nodes.push(end);
2669
- insertNodesBefore(parent, nodes, anchor);
2670
- } else if (handleError(err, { source: "renderChild" }, root)) {
2671
- handledError = true;
2672
- nodes.push(end);
2673
- insertNodesBefore(parent, nodes, anchor);
2739
+ });
2740
+ }
2741
+ function formatTextValue(value) {
2742
+ if (value == null || value === false) {
2743
+ return "";
2744
+ }
2745
+ return String(value);
2746
+ }
2747
+ function createAttributeBinding(el, key, value, setter) {
2748
+ if (isReactive(value)) {
2749
+ createRenderEffect(() => {
2750
+ setter(el, key, value());
2751
+ });
2752
+ } else {
2753
+ setter(el, key, value);
2754
+ }
2755
+ }
2756
+ function bindAttribute(el, key, getValue) {
2757
+ let prevValue = void 0;
2758
+ return createRenderEffect(() => {
2759
+ const value = getValue();
2760
+ if (value === prevValue) return;
2761
+ prevValue = value;
2762
+ if (value === void 0 || value === null || value === false) {
2763
+ el.removeAttribute(key);
2764
+ } else if (value === true) {
2765
+ el.setAttribute(key, "");
2674
2766
  } else {
2675
- throw err;
2767
+ el.setAttribute(key, String(value));
2676
2768
  }
2677
- } finally {
2678
- popRoot(prev);
2679
- if (!handledError) {
2680
- flushOnMount(root);
2681
- } else {
2682
- destroyRoot(root);
2769
+ });
2770
+ }
2771
+ function bindProperty(el, key, getValue) {
2772
+ const PROPERTY_BINDING_KEYS = /* @__PURE__ */ new Set([
2773
+ "value",
2774
+ "checked",
2775
+ "selected",
2776
+ "disabled",
2777
+ "readOnly",
2778
+ "multiple",
2779
+ "muted"
2780
+ ]);
2781
+ let prevValue = void 0;
2782
+ return createRenderEffect(() => {
2783
+ const next = getValue();
2784
+ if (next === prevValue) return;
2785
+ prevValue = next;
2786
+ if (PROPERTY_BINDING_KEYS.has(key) && (next === void 0 || next === null)) {
2787
+ const fallback = key === "checked" || key === "selected" ? false : "";
2788
+ el[key] = fallback;
2789
+ return;
2683
2790
  }
2791
+ ;
2792
+ el[key] = next;
2793
+ });
2794
+ }
2795
+ function createStyleBinding(el, value) {
2796
+ const target = el;
2797
+ if (isReactive(value)) {
2798
+ let prev;
2799
+ createRenderEffect(() => {
2800
+ const next = value();
2801
+ applyStyle(target, next, prev);
2802
+ prev = next;
2803
+ });
2804
+ } else {
2805
+ applyStyle(target, value, void 0);
2684
2806
  }
2685
- return {
2686
- nodes,
2687
- root,
2688
- value: valueSig,
2689
- index: indexSig,
2690
- version: versionSig,
2691
- start,
2692
- end,
2693
- valueProxy,
2694
- renderCurrent
2695
- };
2696
2807
  }
2697
- function rerenderBlock(block, createElementFn) {
2698
- const currentContent = block.nodes.slice(1, Math.max(1, block.nodes.length - 1));
2699
- const currentNode = currentContent.length === 1 ? currentContent[0] : null;
2700
- clearRoot(block.root);
2701
- const prev = pushRoot(block.root);
2702
- let nextOutput;
2703
- let handledError = false;
2704
- try {
2705
- nextOutput = block.renderCurrent();
2706
- } catch (err) {
2707
- if (handleSuspend(err, block.root)) {
2708
- handledError = true;
2709
- popRoot(prev);
2710
- destroyRoot(block.root);
2711
- block.nodes = [block.start, block.end];
2712
- return block;
2808
+ function bindStyle(el, getValue) {
2809
+ const target = el;
2810
+ let prev;
2811
+ return createRenderEffect(() => {
2812
+ const next = getValue();
2813
+ applyStyle(target, next, prev);
2814
+ prev = next;
2815
+ });
2816
+ }
2817
+ function applyStyle(el, value, prev) {
2818
+ if (typeof value === "string") {
2819
+ el.style.cssText = value;
2820
+ } else if (value && typeof value === "object") {
2821
+ const styles = value;
2822
+ if (typeof prev === "string") {
2823
+ el.style.cssText = "";
2713
2824
  }
2714
- if (handleError(err, { source: "renderChild" }, block.root)) {
2715
- handledError = true;
2716
- popRoot(prev);
2717
- destroyRoot(block.root);
2718
- block.nodes = [block.start, block.end];
2719
- return block;
2825
+ if (prev && typeof prev === "object") {
2826
+ const prevStyles = prev;
2827
+ for (const key of Object.keys(prevStyles)) {
2828
+ if (!(key in styles)) {
2829
+ const cssProperty = key.replace(/([A-Z])/g, "-$1").toLowerCase();
2830
+ el.style.removeProperty(cssProperty);
2831
+ }
2832
+ }
2720
2833
  }
2721
- throw err;
2722
- } finally {
2723
- if (!handledError) {
2724
- popRoot(prev);
2834
+ for (const [prop, v] of Object.entries(styles)) {
2835
+ if (v != null) {
2836
+ const cssProperty = prop.replace(/([A-Z])/g, "-$1").toLowerCase();
2837
+ const unitless = isUnitlessStyleProperty(prop) || isUnitlessStyleProperty(cssProperty);
2838
+ const valueStr = typeof v === "number" && !unitless ? `${v}px` : String(v);
2839
+ el.style.setProperty(cssProperty, valueStr);
2840
+ } else {
2841
+ const cssProperty = prop.replace(/([A-Z])/g, "-$1").toLowerCase();
2842
+ el.style.removeProperty(cssProperty);
2843
+ }
2725
2844
  }
2726
- }
2727
- if (isFragmentVNode(nextOutput) && currentContent.length > 0) {
2728
- const patched = patchFragmentChildren(currentContent, nextOutput.props?.children);
2729
- if (patched) {
2730
- block.nodes = [block.start, ...currentContent, block.end];
2731
- return block;
2845
+ } else {
2846
+ if (prev && typeof prev === "object") {
2847
+ const prevStyles = prev;
2848
+ for (const key of Object.keys(prevStyles)) {
2849
+ const cssProperty = key.replace(/([A-Z])/g, "-$1").toLowerCase();
2850
+ el.style.removeProperty(cssProperty);
2851
+ }
2852
+ } else if (typeof prev === "string") {
2853
+ el.style.cssText = "";
2732
2854
  }
2733
2855
  }
2734
- if (currentNode && patchNode(currentNode, nextOutput)) {
2735
- block.nodes = [block.start, currentNode, block.end];
2736
- return block;
2737
- }
2738
- clearContent(block);
2739
- if (nextOutput != null && nextOutput !== false) {
2740
- const newNodes = toNodeArray(
2741
- nextOutput instanceof Node ? nextOutput : createElementFn(nextOutput)
2742
- );
2743
- insertNodesBefore(block.start.parentNode, newNodes, block.end);
2744
- block.nodes = [block.start, ...newNodes, block.end];
2856
+ }
2857
+ function isUnitlessStyleProperty(prop) {
2858
+ return UnitlessStyles.has(prop);
2859
+ }
2860
+ function createClassBinding(el, value) {
2861
+ if (isReactive(value)) {
2862
+ let prev = {};
2863
+ createRenderEffect(() => {
2864
+ const next = value();
2865
+ prev = applyClass(el, next, prev);
2866
+ });
2745
2867
  } else {
2746
- block.nodes = [block.start, block.end];
2868
+ applyClass(el, value, {});
2747
2869
  }
2748
- return block;
2749
2870
  }
2750
- function patchElement(el, output) {
2751
- if (output === null || output === void 0 || output === false || typeof output === "string" || typeof output === "number") {
2752
- el.textContent = output === null || output === void 0 || output === false ? "" : String(output);
2753
- return true;
2754
- }
2755
- if (output instanceof Text) {
2756
- el.textContent = output.data;
2757
- return true;
2758
- }
2759
- if (output && typeof output === "object" && !(output instanceof Node)) {
2760
- const vnode = output;
2761
- if (typeof vnode.type === "string" && vnode.type.toLowerCase() === el.tagName.toLowerCase()) {
2762
- const children = vnode.props?.children;
2763
- const props = vnode.props ?? {};
2764
- for (const [key, value] of Object.entries(props)) {
2765
- if (key === "children" || key === "key") continue;
2766
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null || value === void 0) {
2767
- if (key === "class" || key === "className") {
2768
- el.setAttribute("class", value === false || value === null ? "" : String(value));
2769
- } else if (key === "style" && typeof value === "string") {
2770
- ;
2771
- el.style.cssText = value;
2772
- } else if (value === false || value === null || value === void 0) {
2773
- el.removeAttribute(key);
2774
- } else if (value === true) {
2775
- el.setAttribute(key, "");
2776
- } else {
2777
- el.setAttribute(key, String(value));
2778
- }
2779
- }
2780
- }
2781
- if (typeof children === "string" || typeof children === "number" || children === null || children === void 0 || children === false) {
2782
- el.textContent = children === null || children === void 0 || children === false ? "" : String(children);
2783
- return true;
2784
- }
2785
- if (children && typeof children === "object" && !Array.isArray(children) && !(children instanceof Node)) {
2786
- const childVNode = children;
2787
- if (typeof childVNode.type === "string") {
2788
- const childEl = el.querySelector(childVNode.type);
2789
- if (childEl && patchElement(childEl, children)) {
2790
- return true;
2791
- }
2792
- }
2793
- }
2794
- return false;
2795
- }
2796
- }
2797
- if (output instanceof Node) {
2798
- if (output.nodeType === Node.ELEMENT_NODE) {
2799
- const nextEl = output;
2800
- if (nextEl.tagName.toLowerCase() === el.tagName.toLowerCase()) {
2801
- el.textContent = nextEl.textContent;
2802
- return true;
2803
- }
2804
- } else if (output.nodeType === Node.TEXT_NODE) {
2805
- el.textContent = output.data;
2806
- return true;
2807
- }
2808
- }
2809
- return false;
2871
+ function bindClass(el, getValue) {
2872
+ let prev = {};
2873
+ return createRenderEffect(() => {
2874
+ const next = getValue();
2875
+ prev = applyClass(el, next, prev);
2876
+ });
2810
2877
  }
2811
- function patchNode(currentNode, nextOutput) {
2812
- if (!currentNode) return false;
2813
- if (currentNode instanceof Text && (nextOutput === null || nextOutput === void 0 || nextOutput === false || typeof nextOutput === "string" || typeof nextOutput === "number" || nextOutput instanceof Text)) {
2814
- const nextText = nextOutput instanceof Text ? nextOutput.data : nextOutput === null || nextOutput === void 0 || nextOutput === false ? "" : String(nextOutput);
2815
- currentNode.data = nextText;
2816
- return true;
2817
- }
2818
- if (currentNode instanceof Element && patchElement(currentNode, nextOutput)) {
2819
- return true;
2820
- }
2821
- if (nextOutput instanceof Node && currentNode === nextOutput) {
2822
- return true;
2878
+ function toggleClassKey(node, key, value) {
2879
+ const classNames = key.trim().split(/\s+/);
2880
+ for (let i = 0, len = classNames.length; i < len; i++) {
2881
+ node.classList.toggle(classNames[i], value);
2823
2882
  }
2824
- return false;
2825
- }
2826
- function isFragmentVNode(value) {
2827
- return value != null && typeof value === "object" && !(value instanceof Node) && value.type === Fragment;
2828
2883
  }
2829
- function normalizeChildren(children, result = []) {
2830
- if (children === void 0) {
2831
- return result;
2884
+ function applyClass(el, value, prev) {
2885
+ const prevState = prev && typeof prev === "object" ? prev : {};
2886
+ if (typeof value === "string") {
2887
+ el.className = value;
2888
+ return {};
2832
2889
  }
2833
- if (Array.isArray(children)) {
2834
- for (const child of children) {
2835
- normalizeChildren(child, result);
2890
+ if (value && typeof value === "object") {
2891
+ const classes = value;
2892
+ const classKeys = Object.keys(classes);
2893
+ const prevKeys = Object.keys(prevState);
2894
+ for (let i = 0, len = prevKeys.length; i < len; i++) {
2895
+ const key = prevKeys[i];
2896
+ if (!key || key === "undefined" || classes[key]) continue;
2897
+ toggleClassKey(el, key, false);
2898
+ delete prevState[key];
2836
2899
  }
2837
- return result;
2838
- }
2839
- if (children === null || children === false) {
2840
- return result;
2841
- }
2842
- result.push(children);
2843
- return result;
2844
- }
2845
- function patchFragmentChildren(nodes, children) {
2846
- const normalized = normalizeChildren(children);
2847
- if (normalized.length !== nodes.length) {
2848
- return false;
2900
+ for (let i = 0, len = classKeys.length; i < len; i++) {
2901
+ const key = classKeys[i];
2902
+ const classValue = !!classes[key];
2903
+ if (!key || key === "undefined" || prevState[key] === classValue || !classValue) continue;
2904
+ toggleClassKey(el, key, true);
2905
+ prevState[key] = classValue;
2906
+ }
2907
+ return prevState;
2849
2908
  }
2850
- for (let i = 0; i < normalized.length; i++) {
2851
- if (!patchNode(nodes[i], normalized[i])) {
2852
- return false;
2909
+ if (!value) {
2910
+ for (const key of Object.keys(prevState)) {
2911
+ if (key && key !== "undefined") {
2912
+ toggleClassKey(el, key, false);
2913
+ }
2853
2914
  }
2915
+ return {};
2854
2916
  }
2855
- return true;
2917
+ return prevState;
2856
2918
  }
2857
- function clearContent(block) {
2858
- const nodes = block.nodes.slice(1, Math.max(1, block.nodes.length - 1));
2859
- removeNodes(nodes);
2919
+ function classList(node, value, prev = {}) {
2920
+ return applyClass(node, value, prev);
2860
2921
  }
2861
- function removeBlockNodes(block) {
2862
- let cursor = block.start;
2863
- const end = block.end;
2864
- while (cursor) {
2865
- const next = cursor.nextSibling;
2866
- cursor.parentNode?.removeChild(cursor);
2867
- if (cursor === end) break;
2868
- cursor = next;
2922
+ function insert(parent, getValue, markerOrCreateElement, createElementFn) {
2923
+ const hostRoot = getCurrentRoot();
2924
+ let marker;
2925
+ let ownsMarker = false;
2926
+ let createFn = createElementFn;
2927
+ if (markerOrCreateElement instanceof Node) {
2928
+ marker = markerOrCreateElement;
2929
+ createFn = createElementFn;
2930
+ } else {
2931
+ marker = document.createComment("fict:insert");
2932
+ parent.appendChild(marker);
2933
+ createFn = markerOrCreateElement;
2934
+ ownsMarker = true;
2869
2935
  }
2870
- }
2871
- function bumpBlockVersion(block) {
2872
- block.version(block.version() + 1);
2873
- }
2874
-
2875
- // src/scope.ts
2876
- function createScope() {
2877
- let dispose = null;
2878
- const stop = () => {
2879
- if (dispose) {
2880
- dispose();
2881
- dispose = null;
2936
+ let currentNodes = [];
2937
+ let currentText = null;
2938
+ let currentRoot2 = null;
2939
+ const clearCurrentNodes = () => {
2940
+ if (currentNodes.length > 0) {
2941
+ removeNodes(currentNodes);
2942
+ currentNodes = [];
2882
2943
  }
2883
2944
  };
2884
- const run = (fn) => {
2885
- stop();
2886
- const { dispose: rootDispose, value } = createRoot(fn);
2887
- dispose = rootDispose;
2888
- return value;
2945
+ const setTextNode = (textValue, shouldInsert, parentNode) => {
2946
+ if (!currentText) {
2947
+ currentText = document.createTextNode(textValue);
2948
+ } else if (currentText.data !== textValue) {
2949
+ currentText.data = textValue;
2950
+ }
2951
+ if (!shouldInsert) {
2952
+ clearCurrentNodes();
2953
+ return;
2954
+ }
2955
+ if (currentNodes.length === 1 && currentNodes[0] === currentText) {
2956
+ return;
2957
+ }
2958
+ clearCurrentNodes();
2959
+ insertNodesBefore(parentNode, [currentText], marker);
2960
+ currentNodes = [currentText];
2889
2961
  };
2890
- registerRootCleanup(stop);
2891
- return { run, stop };
2892
- }
2893
- function runInScope(flag, fn) {
2894
- const scope = createScope();
2895
- const evaluate = () => isReactive(flag) ? flag() : !!flag;
2896
- createEffect(() => {
2897
- const enabled = evaluate();
2898
- if (enabled) {
2899
- scope.run(fn);
2900
- } else {
2901
- scope.stop();
2962
+ const dispose = createRenderEffect(() => {
2963
+ const value = getValue();
2964
+ const parentNode = marker.parentNode;
2965
+ const isPrimitive = value == null || value === false || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
2966
+ if (isPrimitive) {
2967
+ if (currentRoot2) {
2968
+ destroyRoot(currentRoot2);
2969
+ currentRoot2 = null;
2970
+ }
2971
+ if (!parentNode) {
2972
+ clearCurrentNodes();
2973
+ return;
2974
+ }
2975
+ const textValue = value == null || value === false ? "" : String(value);
2976
+ const shouldInsert = value != null && value !== false;
2977
+ setTextNode(textValue, shouldInsert, parentNode);
2978
+ return;
2902
2979
  }
2903
- });
2904
- onCleanup(scope.stop);
2905
- }
2906
-
2907
- // src/hooks.ts
2908
- var ctxStack = [];
2909
- function __fictUseContext() {
2910
- if (ctxStack.length === 0) {
2911
- const ctx2 = { slots: [], cursor: 0 };
2912
- ctxStack.push(ctx2);
2913
- return ctx2;
2914
- }
2915
- const ctx = ctxStack[ctxStack.length - 1];
2916
- ctx.cursor = 0;
2917
- return ctx;
2918
- }
2919
- function __fictPushContext() {
2920
- const ctx = { slots: [], cursor: 0 };
2921
- ctxStack.push(ctx);
2922
- return ctx;
2923
- }
2924
- function __fictPopContext() {
2925
- ctxStack.pop();
2926
- }
2927
- function __fictResetContext() {
2928
- ctxStack.length = 0;
2929
- }
2930
- function __fictUseSignal(ctx, initial, slot) {
2931
- const index = slot ?? ctx.cursor++;
2932
- if (!ctx.slots[index]) {
2933
- ctx.slots[index] = signal(initial);
2934
- }
2935
- return ctx.slots[index];
2936
- }
2937
- function __fictUseMemo(ctx, fn, slot) {
2938
- const index = slot ?? ctx.cursor++;
2939
- if (!ctx.slots[index]) {
2940
- ctx.slots[index] = createMemo(fn);
2941
- }
2942
- return ctx.slots[index];
2943
- }
2944
- function __fictUseEffect(ctx, fn, slot) {
2945
- const index = slot ?? ctx.cursor++;
2946
- if (!ctx.slots[index]) {
2947
- ctx.slots[index] = createEffect(fn);
2948
- }
2949
- }
2950
- function __fictRender(ctx, fn) {
2951
- ctxStack.push(ctx);
2952
- ctx.cursor = 0;
2953
- try {
2954
- return fn();
2955
- } finally {
2956
- ctxStack.pop();
2957
- }
2958
- }
2959
-
2960
- // src/versioned-signal.ts
2961
- function createVersionedSignal(initialValue, options2) {
2962
- const equals = options2?.equals ?? Object.is;
2963
- const value = signal(initialValue);
2964
- const version = signal(0);
2965
- const bumpVersion = () => {
2966
- const next = version() + 1;
2967
- version(next);
2968
- };
2969
- return {
2970
- read: () => {
2971
- version();
2972
- return value();
2973
- },
2974
- write: (next) => {
2975
- const prev = value();
2976
- if (!equals(prev, next)) {
2977
- value(next);
2978
- return;
2980
+ if (currentRoot2) {
2981
+ destroyRoot(currentRoot2);
2982
+ currentRoot2 = null;
2983
+ }
2984
+ clearCurrentNodes();
2985
+ const root = createRootContext(hostRoot);
2986
+ const prev = pushRoot(root);
2987
+ let nodes = [];
2988
+ try {
2989
+ let newNode;
2990
+ if (value instanceof Node) {
2991
+ newNode = value;
2992
+ } else if (Array.isArray(value)) {
2993
+ if (value.every((v) => v instanceof Node)) {
2994
+ newNode = value;
2995
+ } else {
2996
+ if (createFn) {
2997
+ const mapped = [];
2998
+ for (const item of value) {
2999
+ mapped.push(...toNodeArray(createFn(item)));
3000
+ }
3001
+ newNode = mapped;
3002
+ } else {
3003
+ newNode = document.createTextNode(String(value));
3004
+ }
3005
+ }
3006
+ } else {
3007
+ newNode = createFn ? createFn(value) : document.createTextNode(String(value));
2979
3008
  }
2980
- bumpVersion();
2981
- },
2982
- force: () => {
2983
- bumpVersion();
2984
- },
2985
- peekVersion: () => version(),
2986
- peekValue: () => value()
3009
+ nodes = toNodeArray(newNode);
3010
+ if (parentNode) {
3011
+ insertNodesBefore(parentNode, nodes, marker);
3012
+ }
3013
+ } finally {
3014
+ popRoot(prev);
3015
+ flushOnMount(root);
3016
+ }
3017
+ currentRoot2 = root;
3018
+ currentNodes = nodes;
3019
+ });
3020
+ return () => {
3021
+ dispose();
3022
+ if (currentRoot2) {
3023
+ destroyRoot(currentRoot2);
3024
+ currentRoot2 = null;
3025
+ }
3026
+ clearCurrentNodes();
3027
+ if (ownsMarker) {
3028
+ marker.parentNode?.removeChild(marker);
3029
+ }
2987
3030
  };
2988
3031
  }
2989
-
2990
- // src/props.ts
2991
- var propGetters = /* @__PURE__ */ new WeakSet();
2992
- var rawToProxy = /* @__PURE__ */ new WeakMap();
2993
- var proxyToRaw = /* @__PURE__ */ new WeakMap();
2994
- function __fictProp(getter) {
2995
- if (typeof getter === "function" && getter.length === 0) {
2996
- propGetters.add(getter);
2997
- }
2998
- return getter;
2999
- }
3000
- function isPropGetter(value) {
3001
- return typeof value === "function" && propGetters.has(value);
3002
- }
3003
- function createPropsProxy(props) {
3004
- if (!props || typeof props !== "object") {
3005
- return props;
3006
- }
3007
- if (proxyToRaw.has(props)) {
3008
- return props;
3009
- }
3010
- const cached = rawToProxy.get(props);
3011
- if (cached) {
3012
- return cached;
3013
- }
3014
- const proxy = new Proxy(props, {
3015
- get(target, prop, receiver) {
3016
- const value = Reflect.get(target, prop, receiver);
3017
- if (isPropGetter(value)) {
3018
- return value();
3032
+ function createChildBinding(parent, getValue, createElementFn) {
3033
+ const marker = document.createComment("fict:child");
3034
+ parent.appendChild(marker);
3035
+ const hostRoot = getCurrentRoot();
3036
+ const dispose = createRenderEffect(() => {
3037
+ const root = createRootContext(hostRoot);
3038
+ const prev = pushRoot(root);
3039
+ let nodes = [];
3040
+ let handledError = false;
3041
+ try {
3042
+ const value = getValue();
3043
+ if (value == null || value === false) {
3044
+ return;
3045
+ }
3046
+ const output = createElementFn(value);
3047
+ nodes = toNodeArray(output);
3048
+ const parentNode = marker.parentNode;
3049
+ if (parentNode) {
3050
+ insertNodesBefore(parentNode, nodes, marker);
3051
+ }
3052
+ return () => {
3053
+ destroyRoot(root);
3054
+ removeNodes(nodes);
3055
+ };
3056
+ } catch (err) {
3057
+ if (handleSuspend(err, root)) {
3058
+ handledError = true;
3059
+ destroyRoot(root);
3060
+ return;
3061
+ }
3062
+ if (handleError(err, { source: "renderChild" }, root)) {
3063
+ handledError = true;
3064
+ destroyRoot(root);
3065
+ return;
3066
+ }
3067
+ throw err;
3068
+ } finally {
3069
+ popRoot(prev);
3070
+ if (!handledError) {
3071
+ flushOnMount(root);
3019
3072
  }
3020
- return value;
3021
- },
3022
- set(target, prop, value, receiver) {
3023
- return Reflect.set(target, prop, value, receiver);
3024
- },
3025
- has(target, prop) {
3026
- return prop in target;
3027
- },
3028
- ownKeys(target) {
3029
- return Reflect.ownKeys(target);
3030
- },
3031
- getOwnPropertyDescriptor(target, prop) {
3032
- return Object.getOwnPropertyDescriptor(target, prop);
3033
3073
  }
3034
3074
  });
3035
- rawToProxy.set(props, proxy);
3036
- proxyToRaw.set(proxy, props);
3037
- return proxy;
3075
+ return {
3076
+ marker,
3077
+ dispose: () => {
3078
+ dispose();
3079
+ marker.parentNode?.removeChild(marker);
3080
+ }
3081
+ };
3038
3082
  }
3039
- function unwrapProps(props) {
3040
- if (!props || typeof props !== "object") {
3041
- return props;
3083
+ function delegateEvents(eventNames, doc = window.document) {
3084
+ const e = doc[$$EVENTS] || (doc[$$EVENTS] = /* @__PURE__ */ new Set());
3085
+ for (let i = 0, l = eventNames.length; i < l; i++) {
3086
+ const name = eventNames[i];
3087
+ if (!e.has(name)) {
3088
+ e.add(name);
3089
+ doc.addEventListener(name, globalEventHandler);
3090
+ }
3042
3091
  }
3043
- return proxyToRaw.get(props) ?? props;
3044
3092
  }
3045
- function __fictPropsRest(props, exclude) {
3046
- const raw = unwrapProps(props);
3047
- const out = {};
3048
- const excludeSet = new Set(exclude);
3049
- for (const key of Reflect.ownKeys(raw)) {
3050
- if (excludeSet.has(key)) continue;
3051
- out[key] = raw[key];
3093
+ function clearDelegatedEvents(doc = window.document) {
3094
+ const e = doc[$$EVENTS];
3095
+ if (e) {
3096
+ for (const name of e.keys()) {
3097
+ doc.removeEventListener(name, globalEventHandler);
3098
+ }
3099
+ delete doc[$$EVENTS];
3052
3100
  }
3053
- return createPropsProxy(out);
3054
3101
  }
3055
- function mergeProps(...sources) {
3056
- const validSources = sources.filter(
3057
- (s) => s != null && (typeof s === "object" || typeof s === "function")
3058
- );
3059
- if (validSources.length === 0) {
3060
- return {};
3061
- }
3062
- if (validSources.length === 1 && typeof validSources[0] === "object") {
3063
- return validSources[0];
3064
- }
3065
- const resolveSource = (src) => {
3066
- const value = typeof src === "function" ? src() : src;
3067
- if (!value || typeof value !== "object") return void 0;
3068
- return unwrapProps(value);
3069
- };
3070
- return new Proxy({}, {
3071
- get(_, prop) {
3072
- if (typeof prop === "symbol") {
3073
- return void 0;
3074
- }
3075
- for (let i = validSources.length - 1; i >= 0; i--) {
3076
- const src = validSources[i];
3077
- const raw = resolveSource(src);
3078
- if (!raw || !(prop in raw)) continue;
3079
- const value = raw[prop];
3080
- if (typeof src === "function" && !isPropGetter(value)) {
3081
- return __fictProp(() => {
3082
- const latest = resolveSource(src);
3083
- if (!latest || !(prop in latest)) return void 0;
3084
- return latest[prop];
3085
- });
3086
- }
3087
- return value;
3088
- }
3089
- return void 0;
3090
- },
3091
- has(_, prop) {
3092
- for (const src of validSources) {
3093
- const raw = resolveSource(src);
3094
- if (raw && prop in raw) {
3095
- return true;
3096
- }
3097
- }
3098
- return false;
3099
- },
3100
- ownKeys() {
3101
- const keys = /* @__PURE__ */ new Set();
3102
- for (const src of validSources) {
3103
- const raw = resolveSource(src);
3104
- if (raw) {
3105
- for (const key of Reflect.ownKeys(raw)) {
3106
- keys.add(key);
3102
+ function globalEventHandler(e) {
3103
+ let node = e.target;
3104
+ const key = `$$${e.type}`;
3105
+ const dataKey = `${key}Data`;
3106
+ const oriTarget = e.target;
3107
+ const oriCurrentTarget = e.currentTarget;
3108
+ const retarget = (value) => Object.defineProperty(e, "target", {
3109
+ configurable: true,
3110
+ value
3111
+ });
3112
+ const handleNode = () => {
3113
+ if (!node) return false;
3114
+ const handler = node[key];
3115
+ if (handler && !node.disabled) {
3116
+ const resolveData = (value) => {
3117
+ if (typeof value === "function") {
3118
+ try {
3119
+ const fn = value;
3120
+ return fn.length > 0 ? fn(e) : fn();
3121
+ } catch {
3122
+ return value();
3107
3123
  }
3108
3124
  }
3125
+ return value;
3126
+ };
3127
+ const rawData = node[dataKey];
3128
+ const hasData = rawData !== void 0;
3129
+ 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);
3109
3135
  }
3110
- return Array.from(keys);
3111
- },
3112
- getOwnPropertyDescriptor(_, prop) {
3113
- for (let i = validSources.length - 1; i >= 0; i--) {
3114
- const raw = resolveSource(validSources[i]);
3115
- if (raw && prop in raw) {
3116
- return {
3117
- enumerable: true,
3118
- configurable: true,
3119
- get: () => {
3120
- const value = raw[prop];
3121
- return value;
3122
- }
3123
- };
3124
- }
3125
- }
3126
- return void 0;
3136
+ if (e.cancelBubble) return false;
3137
+ }
3138
+ const shadowHost = node.host;
3139
+ if (shadowHost && typeof shadowHost !== "string" && !shadowHost._$host && node.contains(e.target)) {
3140
+ retarget(shadowHost);
3141
+ }
3142
+ return true;
3143
+ };
3144
+ const walkUpTree = () => {
3145
+ while (handleNode() && node) {
3146
+ node = node._$host || node.parentNode || node.host;
3147
+ }
3148
+ };
3149
+ Object.defineProperty(e, "currentTarget", {
3150
+ configurable: true,
3151
+ get() {
3152
+ return node || document;
3127
3153
  }
3128
3154
  });
3155
+ if (e.composedPath) {
3156
+ const path = e.composedPath();
3157
+ retarget(path[0]);
3158
+ for (let i = 0; i < path.length - 2; i++) {
3159
+ node = path[i];
3160
+ if (!handleNode()) break;
3161
+ if (node._$host) {
3162
+ node = node._$host;
3163
+ walkUpTree();
3164
+ break;
3165
+ }
3166
+ if (node.parentNode === oriCurrentTarget) {
3167
+ break;
3168
+ }
3169
+ }
3170
+ } else {
3171
+ walkUpTree();
3172
+ }
3173
+ retarget(oriTarget);
3129
3174
  }
3130
- function useProp(getter) {
3131
- return __fictProp(createMemo(getter));
3132
- }
3133
-
3134
- // src/ref.ts
3135
- function createRef() {
3136
- return { current: null };
3137
- }
3138
-
3139
- // src/transition.ts
3140
- function startTransition(fn) {
3141
- const prev = setTransitionContext(true);
3142
- try {
3143
- fn();
3144
- } finally {
3145
- setTransitionContext(prev);
3146
- scheduleFlush();
3175
+ function addEventListener(node, name, handler, delegate) {
3176
+ if (handler == null) return;
3177
+ if (delegate) {
3178
+ if (Array.isArray(handler)) {
3179
+ ;
3180
+ node[`$$${name}`] = handler[0];
3181
+ node[`$$${name}Data`] = handler[1];
3182
+ } else {
3183
+ ;
3184
+ node[`$$${name}`] = handler;
3185
+ }
3186
+ } else if (Array.isArray(handler)) {
3187
+ const handlerFn = handler[0];
3188
+ node.addEventListener(name, (e) => handlerFn.call(node, handler[1], e));
3189
+ } else {
3190
+ node.addEventListener(name, handler);
3147
3191
  }
3148
3192
  }
3149
- function useTransition() {
3150
- const pending = signal(false);
3151
- const start = (fn) => {
3152
- pending(true);
3153
- startTransition(() => {
3193
+ function bindEvent(el, eventName, handler, options2) {
3194
+ if (handler == null) return () => {
3195
+ };
3196
+ const rootRef = getCurrentRoot();
3197
+ if (DelegatedEvents.has(eventName) && !options2) {
3198
+ const key = `$$${eventName}`;
3199
+ delegateEvents([eventName]);
3200
+ const resolveHandler = isReactive(handler) ? handler : () => handler;
3201
+ el[key] = function(...args) {
3154
3202
  try {
3155
- fn();
3156
- } finally {
3157
- pending(false);
3203
+ const fn = resolveHandler();
3204
+ callEventHandler(fn, args[0], el);
3205
+ } catch (err) {
3206
+ handleError(err, { source: "event", eventName }, rootRef);
3158
3207
  }
3159
- });
3208
+ };
3209
+ return () => {
3210
+ el[key] = void 0;
3211
+ };
3212
+ }
3213
+ const getHandler = isReactive(handler) ? handler : () => handler;
3214
+ const wrapped = (event) => {
3215
+ try {
3216
+ const resolved = getHandler();
3217
+ callEventHandler(resolved, event, el);
3218
+ } catch (err) {
3219
+ if (handleError(err, { source: "event", eventName }, rootRef)) {
3220
+ return;
3221
+ }
3222
+ throw err;
3223
+ }
3160
3224
  };
3161
- return [() => pending(), start];
3225
+ el.addEventListener(eventName, wrapped, options2);
3226
+ const cleanup = () => el.removeEventListener(eventName, wrapped, options2);
3227
+ registerRootCleanup(cleanup);
3228
+ return cleanup;
3162
3229
  }
3163
- function useDeferredValue(getValue) {
3164
- const deferredValue = signal(getValue());
3165
- createEffect(() => {
3166
- const newValue = getValue();
3167
- const currentDeferred = untrack(() => deferredValue());
3168
- if (currentDeferred !== newValue) {
3169
- startTransition(() => {
3170
- deferredValue(newValue);
3171
- });
3230
+ function bindRef(el, ref) {
3231
+ if (ref == null) return () => {
3232
+ };
3233
+ const getRef = isReactive(ref) ? ref : () => ref;
3234
+ const applyRef2 = (refValue) => {
3235
+ if (refValue == null) return;
3236
+ if (typeof refValue === "function") {
3237
+ ;
3238
+ refValue(el);
3239
+ } else if (typeof refValue === "object" && "current" in refValue) {
3240
+ ;
3241
+ refValue.current = el;
3172
3242
  }
3173
- });
3174
- return () => deferredValue();
3175
- }
3176
-
3177
- // src/scheduler.ts
3178
- function batch2(fn) {
3179
- return batch(fn);
3180
- }
3181
- function untrack2(fn) {
3182
- return untrack(fn);
3183
- }
3184
-
3185
- // src/dom.ts
3186
- function render(view, container) {
3187
- const root = createRootContext();
3188
- const prev = pushRoot(root);
3189
- let dom;
3190
- try {
3191
- const output = view();
3192
- dom = createElement(output);
3193
- } finally {
3194
- popRoot(prev);
3243
+ };
3244
+ const initialRef = getRef();
3245
+ applyRef2(initialRef);
3246
+ if (isReactive(ref)) {
3247
+ const cleanup2 = createRenderEffect(() => {
3248
+ const currentRef = getRef();
3249
+ applyRef2(currentRef);
3250
+ });
3251
+ registerRootCleanup(cleanup2);
3252
+ const nullifyCleanup = () => {
3253
+ const currentRef = getRef();
3254
+ if (currentRef && typeof currentRef === "object" && "current" in currentRef) {
3255
+ ;
3256
+ currentRef.current = null;
3257
+ }
3258
+ };
3259
+ registerRootCleanup(nullifyCleanup);
3260
+ return () => {
3261
+ cleanup2();
3262
+ nullifyCleanup();
3263
+ };
3195
3264
  }
3196
- container.replaceChildren(dom);
3197
- container.setAttribute("data-fict-fine-grained", "1");
3198
- flushOnMount(root);
3199
- const teardown = () => {
3200
- destroyRoot(root);
3201
- container.innerHTML = "";
3265
+ const cleanup = () => {
3266
+ const refValue = getRef();
3267
+ if (refValue && typeof refValue === "object" && "current" in refValue) {
3268
+ ;
3269
+ refValue.current = null;
3270
+ }
3202
3271
  };
3203
- return teardown;
3272
+ registerRootCleanup(cleanup);
3273
+ return cleanup;
3204
3274
  }
3205
- function createElement(node) {
3206
- if (node instanceof Node) {
3207
- return node;
3208
- }
3209
- if (node === null || node === void 0 || node === false) {
3210
- return document.createTextNode("");
3275
+ function spread(node, props = {}, isSVG = false, skipChildren = false) {
3276
+ const prevProps = {};
3277
+ if (!skipChildren && "children" in props) {
3278
+ createRenderEffect(() => {
3279
+ prevProps.children = props.children;
3280
+ });
3211
3281
  }
3212
- if (typeof node === "object" && node !== null && !(node instanceof Node)) {
3213
- if ("marker" in node) {
3214
- return createElement(node.marker);
3282
+ createRenderEffect(() => {
3283
+ if (typeof props.ref === "function") {
3284
+ ;
3285
+ props.ref(node);
3215
3286
  }
3216
- const nodeRecord = node;
3217
- if (nodeRecord[PRIMITIVE_PROXY]) {
3218
- const primitiveGetter = nodeRecord[Symbol.toPrimitive];
3219
- const value = typeof primitiveGetter === "function" ? primitiveGetter.call(node, "default") : node;
3220
- return document.createTextNode(value == null || value === false ? "" : String(value));
3287
+ });
3288
+ createRenderEffect(() => {
3289
+ assign(node, props, isSVG, true, prevProps, true);
3290
+ });
3291
+ return prevProps;
3292
+ }
3293
+ function assign(node, props, isSVG = false, skipChildren = false, prevProps = {}, skipRef = false) {
3294
+ props = props || {};
3295
+ for (const prop in prevProps) {
3296
+ if (!(prop in props)) {
3297
+ if (prop === "children") continue;
3298
+ prevProps[prop] = assignProp(node, prop, null, prevProps[prop], isSVG, skipRef, props);
3221
3299
  }
3222
3300
  }
3223
- if (Array.isArray(node)) {
3224
- const frag = document.createDocumentFragment();
3225
- for (const child of node) {
3226
- appendChildNode(frag, child);
3301
+ for (const prop in props) {
3302
+ if (prop === "children") {
3303
+ if (!skipChildren) {
3304
+ prevProps.children = props.children;
3305
+ }
3306
+ continue;
3227
3307
  }
3228
- return frag;
3308
+ const value = props[prop];
3309
+ prevProps[prop] = assignProp(node, prop, value, prevProps[prop], isSVG, skipRef, props);
3229
3310
  }
3230
- if (typeof node === "string" || typeof node === "number") {
3231
- return document.createTextNode(String(node));
3311
+ }
3312
+ function assignProp(node, prop, value, prev, isSVG, skipRef, props) {
3313
+ if (prop === "style") {
3314
+ applyStyle(node, value, prev);
3315
+ return value;
3232
3316
  }
3233
- if (typeof node === "boolean") {
3234
- return document.createTextNode("");
3317
+ if (prop === "classList") {
3318
+ return applyClass(node, value, prev);
3235
3319
  }
3236
- const vnode = node;
3237
- if (typeof vnode.type === "function") {
3238
- const rawProps = unwrapProps(vnode.props ?? {});
3239
- const baseProps = vnode.key === void 0 ? rawProps : new Proxy(rawProps, {
3240
- get(target, prop, receiver) {
3241
- if (prop === "key") return vnode.key;
3242
- return Reflect.get(target, prop, receiver);
3243
- },
3244
- has(target, prop) {
3245
- if (prop === "key") return true;
3246
- return prop in target;
3247
- },
3248
- ownKeys(target) {
3249
- const keys = new Set(Reflect.ownKeys(target));
3250
- keys.add("key");
3251
- return Array.from(keys);
3252
- },
3253
- getOwnPropertyDescriptor(target, prop) {
3254
- if (prop === "key") {
3255
- return { enumerable: true, configurable: true, value: vnode.key };
3256
- }
3257
- return Object.getOwnPropertyDescriptor(target, prop);
3258
- }
3259
- });
3260
- const props = createPropsProxy(baseProps);
3261
- try {
3262
- __fictPushContext();
3263
- const rendered = vnode.type(props);
3264
- __fictPopContext();
3265
- return createElement(rendered);
3266
- } catch (err) {
3267
- __fictPopContext();
3268
- if (handleSuspend(err)) {
3269
- return document.createComment("fict:suspend");
3270
- }
3271
- handleError(err, { source: "render", componentName: vnode.type.name });
3272
- throw err;
3320
+ if (value === prev) return prev;
3321
+ if (prop === "ref") {
3322
+ if (!skipRef && typeof value === "function") {
3323
+ ;
3324
+ value(node);
3273
3325
  }
3326
+ return value;
3274
3327
  }
3275
- if (vnode.type === Fragment) {
3276
- const frag = document.createDocumentFragment();
3277
- const children = vnode.props?.children;
3278
- appendChildren(frag, children);
3279
- return frag;
3328
+ if (prop.slice(0, 3) === "on:") {
3329
+ const eventName = prop.slice(3);
3330
+ if (prev) node.removeEventListener(eventName, prev);
3331
+ if (value) node.addEventListener(eventName, value);
3332
+ return value;
3280
3333
  }
3281
- const tagName = typeof vnode.type === "string" ? vnode.type : "div";
3282
- const el = document.createElement(tagName);
3283
- applyProps(el, vnode.props ?? {});
3284
- return el;
3285
- }
3286
- function template(html, isImportNode, isSVG, isMathML) {
3287
- let node = null;
3288
- const create = () => {
3289
- const t = isMathML ? document.createElementNS("http://www.w3.org/1998/Math/MathML", "template") : document.createElement("template");
3290
- t.innerHTML = html;
3291
- if (isSVG) {
3292
- return t.content.firstChild.firstChild;
3334
+ if (prop.slice(0, 10) === "oncapture:") {
3335
+ const eventName = prop.slice(10);
3336
+ if (prev) node.removeEventListener(eventName, prev, true);
3337
+ if (value) node.addEventListener(eventName, value, true);
3338
+ return value;
3339
+ }
3340
+ if (prop.slice(0, 2) === "on") {
3341
+ const eventName = prop.slice(2).toLowerCase();
3342
+ const shouldDelegate = DelegatedEvents.has(eventName);
3343
+ if (!shouldDelegate && prev) {
3344
+ const handler = Array.isArray(prev) ? prev[0] : prev;
3345
+ node.removeEventListener(eventName, handler);
3293
3346
  }
3294
- if (isMathML) {
3295
- return t.firstChild;
3347
+ if (shouldDelegate || value) {
3348
+ addEventListener(node, eventName, value, shouldDelegate);
3349
+ if (shouldDelegate) delegateEvents([eventName]);
3296
3350
  }
3297
- return t.content.firstChild;
3298
- };
3299
- const fn = isImportNode ? () => untrack2(() => document.importNode(node || (node = create()), true)) : () => (node || (node = create())).cloneNode(true);
3300
- fn.cloneNode = fn;
3301
- return fn;
3302
- }
3303
- function isBindingHandle(node) {
3304
- return node !== null && typeof node === "object" && "marker" in node && "dispose" in node && typeof node.dispose === "function";
3305
- }
3306
- function appendChildNode(parent, child) {
3307
- if (child === null || child === void 0 || child === false) {
3308
- return;
3351
+ return value;
3309
3352
  }
3310
- if (isBindingHandle(child)) {
3311
- appendChildNode(parent, child.marker);
3312
- child.flush?.();
3313
- return;
3353
+ if (prop.slice(0, 5) === "attr:") {
3354
+ if (value == null) node.removeAttribute(prop.slice(5));
3355
+ else node.setAttribute(prop.slice(5), String(value));
3356
+ return value;
3314
3357
  }
3315
- if (typeof child === "function" && child.length === 0) {
3316
- const childGetter = child;
3317
- createChildBinding(parent, childGetter, createElement);
3318
- return;
3358
+ if (prop.slice(0, 5) === "bool:") {
3359
+ if (value) node.setAttribute(prop.slice(5), "");
3360
+ else node.removeAttribute(prop.slice(5));
3361
+ return value;
3319
3362
  }
3320
- if (Array.isArray(child)) {
3321
- for (const item of child) {
3322
- appendChildNode(parent, item);
3323
- }
3324
- return;
3363
+ if (prop.slice(0, 5) === "prop:") {
3364
+ ;
3365
+ node[prop.slice(5)] = value;
3366
+ return value;
3325
3367
  }
3326
- let domNode;
3327
- if (typeof child !== "object" || child === null) {
3328
- domNode = document.createTextNode(String(child ?? ""));
3329
- } else {
3330
- domNode = createElement(child);
3368
+ if (prop === "class" || prop === "className") {
3369
+ if (value == null) node.removeAttribute("class");
3370
+ else node.className = String(value);
3371
+ return value;
3331
3372
  }
3332
- if (domNode.nodeType === 11) {
3333
- const children = Array.from(domNode.childNodes);
3334
- for (const node of children) {
3335
- appendChildNode(parent, node);
3373
+ const isCE = node.nodeName.includes("-") || "is" in props;
3374
+ if (!isSVG) {
3375
+ const propAlias = getPropAlias(prop, node.tagName);
3376
+ const isProperty = Properties.has(prop);
3377
+ const isChildProp = ChildProperties.has(prop);
3378
+ if (propAlias || isProperty || isChildProp || isCE) {
3379
+ const propName = propAlias || prop;
3380
+ if (isCE && !isProperty && !isChildProp) {
3381
+ ;
3382
+ node[toPropertyName2(propName)] = value;
3383
+ } else {
3384
+ ;
3385
+ node[propName] = value;
3386
+ }
3387
+ return value;
3336
3388
  }
3337
- return;
3338
3389
  }
3339
- if (domNode.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {
3340
- parent.ownerDocument.adoptNode(domNode);
3341
- }
3342
- try {
3343
- parent.appendChild(domNode);
3344
- } catch (e) {
3345
- if (parent.ownerDocument) {
3346
- const clone = parent.ownerDocument.importNode(domNode, true);
3347
- parent.appendChild(clone);
3348
- return;
3390
+ if (isSVG && prop.indexOf(":") > -1) {
3391
+ const [prefix, name] = prop.split(":");
3392
+ const ns = SVGNamespace[prefix];
3393
+ if (ns) {
3394
+ if (value == null) node.removeAttributeNS(ns, name);
3395
+ else node.setAttributeNS(ns, name, String(value));
3396
+ return value;
3349
3397
  }
3350
- throw e;
3351
3398
  }
3399
+ const attrName = Aliases[prop] || prop;
3400
+ if (value == null) node.removeAttribute(attrName);
3401
+ else node.setAttribute(attrName, String(value));
3402
+ return value;
3352
3403
  }
3353
- function appendChildren(parent, children) {
3354
- if (children === void 0) return;
3355
- if (Array.isArray(children)) {
3356
- for (const child of children) {
3357
- appendChildren(parent, child);
3358
- }
3359
- return;
3360
- }
3361
- appendChildNode(parent, children);
3404
+ function toPropertyName2(name) {
3405
+ return name.toLowerCase().replace(/-([a-z])/g, (_, w) => w.toUpperCase());
3362
3406
  }
3363
- function applyRef(el, value) {
3364
- if (typeof value === "function") {
3365
- const refFn = value;
3366
- refFn(el);
3367
- if (getCurrentRoot()) {
3368
- registerRootCleanup(() => {
3369
- refFn(null);
3370
- });
3371
- }
3372
- } else if (value && typeof value === "object" && "current" in value) {
3373
- const refObj = value;
3374
- refObj.current = el;
3375
- if (getCurrentRoot()) {
3376
- registerRootCleanup(() => {
3377
- refObj.current = null;
3378
- });
3407
+ function createConditional(condition, renderTrue, createElementFn, renderFalse) {
3408
+ const startMarker = document.createComment("fict:cond:start");
3409
+ const endMarker = document.createComment("fict:cond:end");
3410
+ const fragment = document.createDocumentFragment();
3411
+ fragment.append(startMarker, endMarker);
3412
+ const hostRoot = getCurrentRoot();
3413
+ let currentNodes = [];
3414
+ let currentRoot2 = null;
3415
+ let lastCondition = void 0;
3416
+ let pendingRender = false;
3417
+ const conditionMemo = computed(condition);
3418
+ const runConditional = () => {
3419
+ const cond = conditionMemo();
3420
+ const parent = startMarker.parentNode;
3421
+ if (!parent) {
3422
+ pendingRender = true;
3423
+ return;
3379
3424
  }
3380
- }
3381
- }
3382
- function applyProps(el, props, isSVG = false) {
3383
- props = unwrapProps(props);
3384
- const tagName = el.tagName;
3385
- const isCE = tagName.includes("-") || "is" in props;
3386
- for (const [key, value] of Object.entries(props)) {
3387
- if (key === "children") continue;
3388
- if (key === "ref") {
3389
- applyRef(el, value);
3390
- continue;
3425
+ pendingRender = false;
3426
+ if (lastCondition === cond && currentNodes.length > 0) {
3427
+ return;
3391
3428
  }
3392
- if (isEventKey(key)) {
3393
- bindEvent(
3394
- el,
3395
- eventNameFromProp(key),
3396
- value
3397
- );
3398
- continue;
3429
+ if (lastCondition === cond && lastCondition === false && renderFalse === void 0) {
3430
+ return;
3399
3431
  }
3400
- if (key.slice(0, 3) === "on:") {
3401
- bindEvent(
3402
- el,
3403
- key.slice(3),
3404
- value,
3405
- false
3406
- // Non-delegated
3407
- );
3408
- continue;
3432
+ lastCondition = cond;
3433
+ if (currentRoot2) {
3434
+ destroyRoot(currentRoot2);
3435
+ currentRoot2 = null;
3409
3436
  }
3410
- if (key.slice(0, 10) === "oncapture:") {
3411
- bindEvent(
3412
- el,
3413
- key.slice(10),
3414
- value,
3415
- true
3416
- // Capture
3417
- );
3418
- continue;
3437
+ removeNodes(currentNodes);
3438
+ currentNodes = [];
3439
+ const render2 = cond ? renderTrue : renderFalse;
3440
+ if (!render2) {
3441
+ return;
3419
3442
  }
3420
- if (key === "class" || key === "className") {
3421
- createClassBinding(el, value);
3422
- continue;
3443
+ const root = createRootContext(hostRoot);
3444
+ const prev = pushRoot(root);
3445
+ let handledError = false;
3446
+ try {
3447
+ const output = untrack(render2);
3448
+ if (output == null || output === false) {
3449
+ return;
3450
+ }
3451
+ const el = createElementFn(output);
3452
+ const nodes = toNodeArray(el);
3453
+ insertNodesBefore(parent, nodes, endMarker);
3454
+ currentNodes = nodes;
3455
+ } catch (err) {
3456
+ if (handleSuspend(err, root)) {
3457
+ handledError = true;
3458
+ destroyRoot(root);
3459
+ return;
3460
+ }
3461
+ if (handleError(err, { source: "renderChild" }, root)) {
3462
+ handledError = true;
3463
+ destroyRoot(root);
3464
+ return;
3465
+ }
3466
+ throw err;
3467
+ } finally {
3468
+ popRoot(prev);
3469
+ if (!handledError) {
3470
+ flushOnMount(root);
3471
+ currentRoot2 = root;
3472
+ } else {
3473
+ currentRoot2 = null;
3474
+ }
3423
3475
  }
3424
- if (key === "classList") {
3425
- createClassBinding(el, value);
3426
- continue;
3476
+ };
3477
+ const dispose = createRenderEffect(runConditional);
3478
+ return {
3479
+ marker: fragment,
3480
+ flush: () => {
3481
+ if (pendingRender) {
3482
+ runConditional();
3483
+ }
3484
+ },
3485
+ dispose: () => {
3486
+ dispose();
3487
+ if (currentRoot2) {
3488
+ destroyRoot(currentRoot2);
3489
+ }
3490
+ removeNodes(currentNodes);
3491
+ currentNodes = [];
3492
+ startMarker.parentNode?.removeChild(startMarker);
3493
+ endMarker.parentNode?.removeChild(endMarker);
3427
3494
  }
3428
- if (key === "style") {
3429
- createStyleBinding(
3430
- el,
3431
- value
3432
- );
3433
- continue;
3495
+ };
3496
+ }
3497
+ function createList(items, renderItem, createElementFn, getKey) {
3498
+ const startMarker = document.createComment("fict:list:start");
3499
+ const endMarker = document.createComment("fict:list:end");
3500
+ const fragment = document.createDocumentFragment();
3501
+ fragment.append(startMarker, endMarker);
3502
+ const hostRoot = getCurrentRoot();
3503
+ const nodeMap = /* @__PURE__ */ new Map();
3504
+ let pendingItems = null;
3505
+ const runListUpdate = () => {
3506
+ const arr = items();
3507
+ const parent = startMarker.parentNode;
3508
+ if (!parent) {
3509
+ pendingItems = arr;
3510
+ return;
3434
3511
  }
3435
- if (key === "dangerouslySetInnerHTML" && value && typeof value === "object") {
3436
- const htmlValue = value.__html;
3437
- if (htmlValue !== void 0) {
3438
- if (isReactive(htmlValue)) {
3439
- createAttributeBinding(el, "innerHTML", htmlValue, setInnerHTML);
3512
+ pendingItems = null;
3513
+ const newNodeMap = /* @__PURE__ */ new Map();
3514
+ const blocks = [];
3515
+ for (let i = 0; i < arr.length; i++) {
3516
+ const item = arr[i];
3517
+ const key = getKey ? getKey(item, i) : i;
3518
+ const existing = nodeMap.get(key);
3519
+ let block;
3520
+ if (existing) {
3521
+ const previousValue = existing.value();
3522
+ if (!getKey && previousValue !== item) {
3523
+ destroyRoot(existing.root);
3524
+ removeBlockNodes(existing);
3525
+ block = mountBlock(item, i, renderItem, parent, endMarker, createElementFn, hostRoot);
3440
3526
  } else {
3441
- el.innerHTML = htmlValue;
3527
+ const previousIndex = existing.index();
3528
+ existing.value(item);
3529
+ existing.index(i);
3530
+ const needsRerender = getKey ? true : previousValue !== item || previousIndex !== i;
3531
+ block = needsRerender ? rerenderBlock(existing, createElementFn) : existing;
3442
3532
  }
3533
+ } else {
3534
+ block = mountBlock(item, i, renderItem, parent, endMarker, createElementFn, hostRoot);
3443
3535
  }
3444
- continue;
3445
- }
3446
- if (ChildProperties.has(key)) {
3447
- createAttributeBinding(el, key, value, setProperty);
3448
- continue;
3536
+ newNodeMap.set(key, block);
3537
+ blocks.push(block);
3449
3538
  }
3450
- if (key.slice(0, 5) === "attr:") {
3451
- createAttributeBinding(el, key.slice(5), value, setAttribute);
3452
- continue;
3539
+ for (const [key, managed] of nodeMap) {
3540
+ if (!newNodeMap.has(key)) {
3541
+ destroyRoot(managed.root);
3542
+ removeBlockNodes(managed);
3543
+ }
3453
3544
  }
3454
- if (key.slice(0, 5) === "bool:") {
3455
- createAttributeBinding(el, key.slice(5), value, setBoolAttribute);
3456
- continue;
3545
+ let anchor = endMarker;
3546
+ for (let i = blocks.length - 1; i >= 0; i--) {
3547
+ const block = blocks[i];
3548
+ insertNodesBefore(parent, block.nodes, anchor);
3549
+ if (block.nodes.length > 0) {
3550
+ anchor = block.nodes[0];
3551
+ }
3457
3552
  }
3458
- if (key.slice(0, 5) === "prop:") {
3459
- createAttributeBinding(el, key.slice(5), value, setProperty);
3460
- continue;
3553
+ nodeMap.clear();
3554
+ for (const [k, v] of newNodeMap) {
3555
+ nodeMap.set(k, v);
3461
3556
  }
3462
- const propAlias = !isSVG ? getPropAlias(key, tagName) : void 0;
3463
- if (propAlias || !isSVG && Properties.has(key) || isCE && !isSVG) {
3464
- const propName = propAlias || key;
3465
- if (isCE && !Properties.has(key)) {
3466
- createAttributeBinding(
3467
- el,
3468
- toPropertyName2(propName),
3469
- value,
3470
- setProperty
3471
- );
3472
- } else {
3473
- createAttributeBinding(el, propName, value, setProperty);
3557
+ };
3558
+ const dispose = createRenderEffect(runListUpdate);
3559
+ return {
3560
+ marker: fragment,
3561
+ flush: () => {
3562
+ if (pendingItems !== null) {
3563
+ runListUpdate();
3474
3564
  }
3475
- continue;
3476
- }
3477
- if (isSVG && key.indexOf(":") > -1) {
3478
- const [prefix, name] = key.split(":");
3479
- const ns = SVGNamespace[prefix];
3480
- if (ns) {
3481
- createAttributeBinding(
3482
- el,
3483
- key,
3484
- value,
3485
- (el2, _key, val) => setAttributeNS(el2, ns, name, val)
3486
- );
3487
- continue;
3565
+ },
3566
+ dispose: () => {
3567
+ dispose();
3568
+ for (const [, managed] of nodeMap) {
3569
+ destroyRoot(managed.root);
3570
+ removeBlockNodes(managed);
3488
3571
  }
3572
+ nodeMap.clear();
3573
+ startMarker.parentNode?.removeChild(startMarker);
3574
+ endMarker.parentNode?.removeChild(endMarker);
3489
3575
  }
3490
- const attrName = Aliases[key] || key;
3491
- createAttributeBinding(el, attrName, value, setAttribute);
3492
- }
3493
- const children = props.children;
3494
- appendChildren(el, children);
3576
+ };
3495
3577
  }
3496
- function toPropertyName2(name) {
3497
- return name.toLowerCase().replace(/-([a-z])/g, (_, w) => w.toUpperCase());
3578
+ function createShow(el, condition, displayValue) {
3579
+ const originalDisplay = displayValue ?? el.style.display;
3580
+ createRenderEffect(() => {
3581
+ el.style.display = condition() ? originalDisplay : "none";
3582
+ });
3498
3583
  }
3499
- var setAttribute = (el, key, value) => {
3500
- if (value === void 0 || value === null || value === false) {
3501
- el.removeAttribute(key);
3502
- return;
3503
- }
3504
- if (value === true) {
3505
- el.setAttribute(key, "");
3506
- return;
3507
- }
3508
- const valueType = typeof value;
3509
- if (valueType === "string" || valueType === "number") {
3510
- el.setAttribute(key, String(value));
3511
- return;
3512
- }
3513
- if (key in el) {
3514
- ;
3515
- el[key] = value;
3516
- return;
3517
- }
3518
- el.setAttribute(key, String(value));
3519
- };
3520
- var setProperty = (el, key, value) => {
3521
- if (value === void 0 || value === null) {
3522
- const fallback = key === "checked" || key === "selected" ? false : "";
3523
- el[key] = fallback;
3524
- return;
3525
- }
3526
- if (key === "style" && typeof value === "object" && value !== null) {
3527
- for (const k in value) {
3528
- const v = value[k];
3529
- if (v !== void 0) {
3530
- ;
3531
- el.style[k] = String(v);
3532
- }
3533
- }
3534
- return;
3535
- }
3536
- ;
3537
- el[key] = value;
3538
- };
3539
- var setInnerHTML = (el, _key, value) => {
3540
- el.innerHTML = value == null ? "" : String(value);
3541
- };
3542
- var setBoolAttribute = (el, key, value) => {
3543
- if (value) {
3544
- el.setAttribute(key, "");
3545
- } else {
3546
- el.removeAttribute(key);
3547
- }
3548
- };
3549
- function setAttributeNS(el, namespace, name, value) {
3550
- if (value == null) {
3551
- el.removeAttributeNS(namespace, name);
3552
- } else {
3553
- el.setAttributeNS(namespace, name, String(value));
3554
- }
3555
- }
3556
- function isEventKey(key) {
3557
- return key.startsWith("on") && key.length > 2 && key[2].toUpperCase() === key[2];
3558
- }
3559
- function eventNameFromProp(key) {
3560
- return key.slice(2).toLowerCase();
3561
- }
3562
-
3563
- // src/error-boundary.ts
3564
- function ErrorBoundary(props) {
3565
- const fragment = document.createDocumentFragment();
3566
- const marker = document.createComment("fict:error-boundary");
3567
- fragment.appendChild(marker);
3568
- const currentView = signal(props.children ?? null);
3569
- let cleanup;
3570
- let activeNodes = [];
3571
- let renderingFallback = false;
3572
- const toView = (err) => {
3573
- if (err != null) {
3574
- return typeof props.fallback === "function" ? props.fallback(err) : props.fallback;
3575
- }
3576
- return props.children ?? null;
3577
- };
3578
- const renderValue = (value) => {
3579
- if (cleanup) {
3580
- cleanup();
3581
- cleanup = void 0;
3582
- }
3583
- if (activeNodes.length) {
3584
- removeNodes(activeNodes);
3585
- activeNodes = [];
3584
+ function createPortal(container, render2, createElementFn) {
3585
+ const parentRoot = getCurrentRoot();
3586
+ const marker = document.createComment("fict:portal");
3587
+ container.appendChild(marker);
3588
+ let currentNodes = [];
3589
+ let currentRoot2 = null;
3590
+ const dispose = createRenderEffect(() => {
3591
+ if (currentRoot2) {
3592
+ destroyRoot(currentRoot2);
3593
+ currentRoot2 = null;
3586
3594
  }
3587
- if (value == null || value === false) {
3588
- return;
3595
+ if (currentNodes.length > 0) {
3596
+ removeNodes(currentNodes);
3597
+ currentNodes = [];
3589
3598
  }
3590
- const root = createRootContext();
3599
+ const root = createRootContext(parentRoot);
3591
3600
  const prev = pushRoot(root);
3592
- let nodes = [];
3601
+ let handledError = false;
3593
3602
  try {
3594
- const output = createElement(value);
3595
- nodes = toNodeArray(output);
3596
- const parentNode = marker.parentNode;
3597
- if (parentNode) {
3598
- insertNodesBefore(parentNode, nodes, marker);
3603
+ const output = render2();
3604
+ if (output != null && output !== false) {
3605
+ const el = createElementFn(output);
3606
+ const nodes = toNodeArray(el);
3607
+ if (marker.parentNode) {
3608
+ insertNodesBefore(marker.parentNode, nodes, marker);
3609
+ }
3610
+ currentNodes = nodes;
3599
3611
  }
3600
3612
  } catch (err) {
3601
- popRoot(prev);
3602
- flushOnMount(root);
3603
- destroyRoot(root);
3604
- if (renderingFallback) {
3605
- throw err;
3613
+ if (handleSuspend(err, root)) {
3614
+ handledError = true;
3615
+ destroyRoot(root);
3616
+ currentNodes = [];
3617
+ return;
3606
3618
  }
3607
- renderingFallback = true;
3608
- try {
3609
- renderValue(toView(err));
3610
- } finally {
3611
- renderingFallback = false;
3619
+ if (handleError(err, { source: "renderChild" }, root)) {
3620
+ handledError = true;
3621
+ destroyRoot(root);
3622
+ currentNodes = [];
3623
+ return;
3624
+ }
3625
+ throw err;
3626
+ } finally {
3627
+ popRoot(prev);
3628
+ if (!handledError) {
3629
+ flushOnMount(root);
3630
+ currentRoot2 = root;
3631
+ } else {
3632
+ currentRoot2 = null;
3612
3633
  }
3613
- props.onError?.(err);
3614
- return;
3615
3634
  }
3616
- popRoot(prev);
3617
- flushOnMount(root);
3618
- cleanup = () => {
3619
- destroyRoot(root);
3620
- removeNodes(nodes);
3621
- };
3622
- activeNodes = nodes;
3623
- };
3624
- createEffect(() => {
3625
- const value = currentView();
3626
- renderValue(value);
3627
- });
3628
- registerErrorHandler((err) => {
3629
- renderValue(toView(err));
3630
- props.onError?.(err);
3631
- return true;
3632
3635
  });
3633
- if (props.resetKeys !== void 0) {
3634
- const isGetter = typeof props.resetKeys === "function" && props.resetKeys.length === 0;
3635
- const getter = isGetter ? props.resetKeys : void 0;
3636
- let prev = isGetter ? getter() : props.resetKeys;
3637
- createEffect(() => {
3638
- const next = getter ? getter() : props.resetKeys;
3639
- if (prev !== next) {
3640
- prev = next;
3641
- renderValue(toView(null));
3642
- }
3643
- });
3636
+ const portalDispose = () => {
3637
+ dispose();
3638
+ if (currentRoot2) {
3639
+ destroyRoot(currentRoot2);
3640
+ }
3641
+ if (currentNodes.length > 0) {
3642
+ removeNodes(currentNodes);
3643
+ }
3644
+ marker.parentNode?.removeChild(marker);
3645
+ };
3646
+ if (parentRoot) {
3647
+ parentRoot.destroyCallbacks.push(portalDispose);
3644
3648
  }
3645
- return fragment;
3646
- }
3647
-
3648
- // src/suspense.ts
3649
- function createSuspenseToken() {
3650
- let resolve;
3651
- let reject;
3652
- const promise = new Promise((res, rej) => {
3653
- resolve = res;
3654
- reject = rej;
3655
- });
3656
3649
  return {
3657
- token: {
3658
- then: promise.then.bind(promise)
3659
- },
3660
- resolve,
3661
- reject
3650
+ marker,
3651
+ dispose: portalDispose
3662
3652
  };
3663
3653
  }
3664
- var isThenable = (value) => typeof value === "object" && value !== null && typeof value.then === "function";
3665
- function Suspense(props) {
3666
- const currentView = signal(props.children ?? null);
3667
- const pending = signal(0);
3668
- let resolvedOnce = false;
3669
- let epoch = 0;
3670
- const hostRoot = getCurrentRoot();
3671
- const toFallback = (err) => typeof props.fallback === "function" ? props.fallback(err) : props.fallback;
3672
- const switchView = (view) => {
3673
- currentView(view);
3674
- renderView(view);
3675
- };
3676
- const renderView = (view) => {
3677
- if (cleanup) {
3678
- cleanup();
3679
- cleanup = void 0;
3680
- }
3681
- if (activeNodes.length) {
3682
- removeNodes(activeNodes);
3683
- activeNodes = [];
3654
+ function mountBlock(initialValue, initialIndex, renderItem, parent, anchor, createElementFn, hostRoot) {
3655
+ const start = document.createComment("fict:block:start");
3656
+ const end = document.createComment("fict:block:end");
3657
+ const valueSig = createVersionedSignalAccessor(initialValue);
3658
+ const indexSig = signal(initialIndex);
3659
+ const renderCurrent = () => renderItem(valueSig, indexSig);
3660
+ const root = createRootContext(hostRoot);
3661
+ const prev = pushRoot(root);
3662
+ const nodes = [start];
3663
+ let handledError = false;
3664
+ try {
3665
+ const output = renderCurrent();
3666
+ if (output != null && output !== false) {
3667
+ const el = createElementFn(output);
3668
+ const rendered = toNodeArray(el);
3669
+ nodes.push(...rendered);
3684
3670
  }
3685
- if (view == null || view === false) {
3686
- return;
3671
+ nodes.push(end);
3672
+ insertNodesBefore(parent, nodes, anchor);
3673
+ } catch (err) {
3674
+ if (handleSuspend(err, root)) {
3675
+ handledError = true;
3676
+ nodes.push(end);
3677
+ insertNodesBefore(parent, nodes, anchor);
3678
+ } else if (handleError(err, { source: "renderChild" }, root)) {
3679
+ handledError = true;
3680
+ nodes.push(end);
3681
+ insertNodesBefore(parent, nodes, anchor);
3682
+ } else {
3683
+ throw err;
3687
3684
  }
3688
- const root = createRootContext(hostRoot);
3689
- const prev = pushRoot(root);
3690
- let nodes = [];
3691
- try {
3692
- const output = createElement(view);
3693
- nodes = toNodeArray(output);
3694
- const suspendedAttempt = nodes.length > 0 && nodes.every((node) => node instanceof Comment && node.data === "fict:suspend");
3695
- if (suspendedAttempt) {
3696
- popRoot(prev);
3697
- destroyRoot(root);
3698
- return;
3699
- }
3700
- const parentNode = marker.parentNode;
3701
- if (parentNode) {
3702
- insertNodesBefore(parentNode, nodes, marker);
3703
- }
3704
- } catch (err) {
3705
- popRoot(prev);
3685
+ } finally {
3686
+ popRoot(prev);
3687
+ if (!handledError) {
3706
3688
  flushOnMount(root);
3689
+ } else {
3707
3690
  destroyRoot(root);
3708
- handleError(err, { source: "render" });
3709
- return;
3710
3691
  }
3711
- popRoot(prev);
3712
- flushOnMount(root);
3713
- cleanup = () => {
3714
- destroyRoot(root);
3715
- removeNodes(nodes);
3716
- };
3717
- activeNodes = nodes;
3692
+ }
3693
+ return {
3694
+ nodes,
3695
+ root,
3696
+ value: valueSig,
3697
+ index: indexSig,
3698
+ start,
3699
+ end,
3700
+ renderCurrent
3718
3701
  };
3719
- const fragment = document.createDocumentFragment();
3720
- const marker = document.createComment("fict:suspense");
3721
- fragment.appendChild(marker);
3722
- let cleanup;
3723
- let activeNodes = [];
3724
- const onResolveMaybe = () => {
3725
- if (!resolvedOnce) {
3726
- resolvedOnce = true;
3727
- props.onResolve?.();
3702
+ }
3703
+ function rerenderBlock(block, createElementFn) {
3704
+ const currentContent = block.nodes.slice(1, Math.max(1, block.nodes.length - 1));
3705
+ const currentNode = currentContent.length === 1 ? currentContent[0] : null;
3706
+ clearRoot(block.root);
3707
+ const prev = pushRoot(block.root);
3708
+ let nextOutput;
3709
+ let handledError = false;
3710
+ try {
3711
+ nextOutput = block.renderCurrent();
3712
+ } catch (err) {
3713
+ if (handleSuspend(err, block.root)) {
3714
+ handledError = true;
3715
+ popRoot(prev);
3716
+ destroyRoot(block.root);
3717
+ block.nodes = [block.start, block.end];
3718
+ return block;
3728
3719
  }
3729
- };
3730
- registerSuspenseHandler((token) => {
3731
- const tokenEpoch = epoch;
3732
- pending(pending() + 1);
3733
- switchView(toFallback());
3734
- const thenable = token.then ? token : isThenable(token) ? token : null;
3735
- if (thenable) {
3736
- thenable.then(
3737
- () => {
3738
- if (epoch !== tokenEpoch) return;
3739
- pending(Math.max(0, pending() - 1));
3740
- if (pending() === 0) {
3741
- switchView(props.children ?? null);
3742
- onResolveMaybe();
3743
- }
3744
- },
3745
- (err) => {
3746
- if (epoch !== tokenEpoch) return;
3747
- pending(Math.max(0, pending() - 1));
3748
- props.onReject?.(err);
3749
- handleError(err, { source: "render" }, hostRoot);
3750
- }
3751
- );
3752
- return true;
3720
+ if (handleError(err, { source: "renderChild" }, block.root)) {
3721
+ handledError = true;
3722
+ popRoot(prev);
3723
+ destroyRoot(block.root);
3724
+ block.nodes = [block.start, block.end];
3725
+ return block;
3753
3726
  }
3754
- return false;
3755
- });
3756
- createEffect(() => {
3757
- renderView(currentView());
3758
- });
3759
- if (props.resetKeys !== void 0) {
3760
- const isGetter = typeof props.resetKeys === "function" && props.resetKeys.length === 0;
3761
- const getter = isGetter ? props.resetKeys : void 0;
3762
- let prev = isGetter ? getter() : props.resetKeys;
3763
- createEffect(() => {
3764
- const next = getter ? getter() : props.resetKeys;
3765
- if (prev !== next) {
3766
- prev = next;
3767
- epoch++;
3768
- pending(0);
3769
- switchView(props.children ?? null);
3770
- }
3771
- });
3772
- }
3773
- return fragment;
3774
- }
3775
-
3776
- // src/reconcile.ts
3777
- function reconcileArrays(parentNode, a, b) {
3778
- const bLength = b.length;
3779
- let aEnd = a.length;
3780
- let bEnd = bLength;
3781
- let aStart = 0;
3782
- let bStart = 0;
3783
- const after = aEnd > 0 ? a[aEnd - 1].nextSibling : null;
3784
- let map = null;
3785
- while (aStart < aEnd || bStart < bEnd) {
3786
- if (a[aStart] === b[bStart]) {
3787
- aStart++;
3788
- bStart++;
3789
- continue;
3727
+ throw err;
3728
+ } finally {
3729
+ if (!handledError) {
3730
+ popRoot(prev);
3790
3731
  }
3791
- while (a[aEnd - 1] === b[bEnd - 1]) {
3792
- aEnd--;
3793
- bEnd--;
3732
+ }
3733
+ if (isFragmentVNode(nextOutput) && currentContent.length > 0) {
3734
+ const patched = patchFragmentChildren(currentContent, nextOutput.props?.children);
3735
+ if (patched) {
3736
+ block.nodes = [block.start, ...currentContent, block.end];
3737
+ return block;
3794
3738
  }
3795
- if (aEnd === aStart) {
3796
- const node = bEnd < bLength ? bStart ? b[bStart - 1].nextSibling : b[bEnd - bStart] ?? null : after;
3797
- const count = bEnd - bStart;
3798
- const doc = parentNode.ownerDocument;
3799
- if (count > 1 && doc) {
3800
- const frag = doc.createDocumentFragment();
3801
- for (let i = bStart; i < bEnd; i++) {
3802
- frag.appendChild(b[i]);
3803
- }
3804
- parentNode.insertBefore(frag, node);
3805
- bStart = bEnd;
3806
- } else {
3807
- while (bStart < bEnd) {
3808
- parentNode.insertBefore(b[bStart++], node);
3809
- }
3810
- }
3811
- } else if (bEnd === bStart) {
3812
- while (aStart < aEnd) {
3813
- const nodeToRemove = a[aStart];
3814
- if (!map || !map.has(nodeToRemove)) {
3815
- nodeToRemove.parentNode?.removeChild(nodeToRemove);
3816
- }
3817
- aStart++;
3818
- }
3819
- } else if (a[aStart] === b[bEnd - 1] && b[bStart] === a[aEnd - 1]) {
3820
- const node = a[--aEnd].nextSibling;
3821
- parentNode.insertBefore(b[bStart++], a[aStart++].nextSibling);
3822
- parentNode.insertBefore(b[--bEnd], node);
3823
- a[aEnd] = b[bEnd];
3824
- } else {
3825
- if (!map) {
3826
- map = /* @__PURE__ */ new Map();
3827
- let i = bStart;
3828
- while (i < bEnd) {
3829
- map.set(b[i], i++);
3830
- }
3831
- }
3832
- const index = map.get(a[aStart]);
3833
- if (index != null) {
3834
- if (bStart < index && index < bEnd) {
3835
- let i = aStart;
3836
- let sequence = 1;
3837
- let t;
3838
- while (++i < aEnd && i < bEnd) {
3839
- t = map.get(a[i]);
3840
- if (t == null || t !== index + sequence) break;
3841
- sequence++;
3842
- }
3843
- if (sequence > index - bStart) {
3844
- const node = a[aStart];
3845
- while (bStart < index) {
3846
- parentNode.insertBefore(b[bStart++], node);
3847
- }
3739
+ }
3740
+ if (currentNode && patchNode(currentNode, nextOutput)) {
3741
+ block.nodes = [block.start, currentNode, block.end];
3742
+ return block;
3743
+ }
3744
+ clearContent(block);
3745
+ if (nextOutput != null && nextOutput !== false) {
3746
+ const newNodes = toNodeArray(
3747
+ nextOutput instanceof Node ? nextOutput : createElementFn(nextOutput)
3748
+ );
3749
+ insertNodesBefore(block.start.parentNode, newNodes, block.end);
3750
+ block.nodes = [block.start, ...newNodes, block.end];
3751
+ } else {
3752
+ block.nodes = [block.start, block.end];
3753
+ }
3754
+ return block;
3755
+ }
3756
+ function patchElement(el, output) {
3757
+ if (output === null || output === void 0 || output === false || typeof output === "string" || typeof output === "number") {
3758
+ el.textContent = output === null || output === void 0 || output === false ? "" : String(output);
3759
+ return true;
3760
+ }
3761
+ if (output instanceof Text) {
3762
+ el.textContent = output.data;
3763
+ return true;
3764
+ }
3765
+ if (output && typeof output === "object" && !(output instanceof Node)) {
3766
+ const vnode = output;
3767
+ if (typeof vnode.type === "string" && vnode.type.toLowerCase() === el.tagName.toLowerCase()) {
3768
+ const children = vnode.props?.children;
3769
+ const props = vnode.props ?? {};
3770
+ for (const [key, value] of Object.entries(props)) {
3771
+ if (key === "children" || key === "key") continue;
3772
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean" || value === null || value === void 0) {
3773
+ if (key === "class" || key === "className") {
3774
+ el.setAttribute("class", value === false || value === null ? "" : String(value));
3775
+ } else if (key === "style" && typeof value === "string") {
3776
+ ;
3777
+ el.style.cssText = value;
3778
+ } else if (value === false || value === null || value === void 0) {
3779
+ el.removeAttribute(key);
3780
+ } else if (value === true) {
3781
+ el.setAttribute(key, "");
3848
3782
  } else {
3849
- parentNode.replaceChild(b[bStart++], a[aStart++]);
3783
+ el.setAttribute(key, String(value));
3850
3784
  }
3851
- } else {
3852
- aStart++;
3853
3785
  }
3854
- } else {
3855
- const nodeToRemove = a[aStart++];
3856
- nodeToRemove.parentNode?.removeChild(nodeToRemove);
3857
3786
  }
3858
- }
3859
- }
3860
- }
3861
-
3862
- // src/list-helpers.ts
3863
- function moveNodesBefore(parent, nodes, anchor) {
3864
- for (let i = nodes.length - 1; i >= 0; i--) {
3865
- const node = nodes[i];
3866
- if (!node || !(node instanceof Node)) {
3867
- throw new Error("Invalid node in moveNodesBefore");
3868
- }
3869
- if (node.nextSibling !== anchor) {
3870
- if (node.ownerDocument !== parent.ownerDocument && parent.ownerDocument) {
3871
- parent.ownerDocument.adoptNode(node);
3787
+ if (typeof children === "string" || typeof children === "number" || children === null || children === void 0 || children === false) {
3788
+ el.textContent = children === null || children === void 0 || children === false ? "" : String(children);
3789
+ return true;
3872
3790
  }
3873
- try {
3874
- parent.insertBefore(node, anchor);
3875
- } catch (e) {
3876
- if (parent.ownerDocument) {
3877
- try {
3878
- const clone = parent.ownerDocument.importNode(node, true);
3879
- parent.insertBefore(clone, anchor);
3880
- continue;
3881
- } catch {
3791
+ if (children && typeof children === "object" && !Array.isArray(children) && !(children instanceof Node)) {
3792
+ const childVNode = children;
3793
+ if (typeof childVNode.type === "string") {
3794
+ const childEl = el.querySelector(childVNode.type);
3795
+ if (childEl && patchElement(childEl, children)) {
3796
+ return true;
3882
3797
  }
3883
3798
  }
3884
- throw e;
3885
3799
  }
3800
+ return false;
3801
+ }
3802
+ }
3803
+ if (output instanceof Node) {
3804
+ if (output.nodeType === Node.ELEMENT_NODE) {
3805
+ const nextEl = output;
3806
+ if (nextEl.tagName.toLowerCase() === el.tagName.toLowerCase()) {
3807
+ el.textContent = nextEl.textContent;
3808
+ return true;
3809
+ }
3810
+ } else if (output.nodeType === Node.TEXT_NODE) {
3811
+ el.textContent = output.data;
3812
+ return true;
3886
3813
  }
3887
- anchor = node;
3888
3814
  }
3815
+ return false;
3889
3816
  }
3890
- function moveMarkerBlock(parent, block, anchor) {
3891
- const nodes = collectBlockNodes(block);
3892
- if (nodes.length === 0) return;
3893
- moveNodesBefore(parent, nodes, anchor);
3817
+ function patchNode(currentNode, nextOutput) {
3818
+ if (!currentNode) return false;
3819
+ if (currentNode instanceof Text && (nextOutput === null || nextOutput === void 0 || nextOutput === false || typeof nextOutput === "string" || typeof nextOutput === "number" || nextOutput instanceof Text)) {
3820
+ const nextText = nextOutput instanceof Text ? nextOutput.data : nextOutput === null || nextOutput === void 0 || nextOutput === false ? "" : String(nextOutput);
3821
+ currentNode.data = nextText;
3822
+ return true;
3823
+ }
3824
+ if (currentNode instanceof Element && patchElement(currentNode, nextOutput)) {
3825
+ return true;
3826
+ }
3827
+ if (nextOutput instanceof Node && currentNode === nextOutput) {
3828
+ return true;
3829
+ }
3830
+ return false;
3894
3831
  }
3895
- function destroyMarkerBlock(block) {
3896
- if (block.root) {
3897
- destroyRoot(block.root);
3832
+ function isFragmentVNode(value) {
3833
+ return value != null && typeof value === "object" && !(value instanceof Node) && value.type === Fragment;
3834
+ }
3835
+ function normalizeChildren(children, result = []) {
3836
+ if (children === void 0) {
3837
+ return result;
3898
3838
  }
3899
- removeBlockRange(block);
3839
+ if (Array.isArray(children)) {
3840
+ for (const child of children) {
3841
+ normalizeChildren(child, result);
3842
+ }
3843
+ return result;
3844
+ }
3845
+ if (children === null || children === false) {
3846
+ return result;
3847
+ }
3848
+ result.push(children);
3849
+ return result;
3900
3850
  }
3901
- function collectBlockNodes(block) {
3902
- const nodes = [];
3903
- let cursor = block.start;
3904
- while (cursor) {
3905
- nodes.push(cursor);
3906
- if (cursor === block.end) {
3907
- break;
3851
+ function patchFragmentChildren(nodes, children) {
3852
+ const normalized = normalizeChildren(children);
3853
+ if (normalized.length !== nodes.length) {
3854
+ return false;
3855
+ }
3856
+ for (let i = 0; i < normalized.length; i++) {
3857
+ if (!patchNode(nodes[i], normalized[i])) {
3858
+ return false;
3908
3859
  }
3909
- cursor = cursor.nextSibling;
3910
3860
  }
3911
- return nodes;
3861
+ return true;
3912
3862
  }
3913
- function removeBlockRange(block) {
3863
+ function clearContent(block) {
3864
+ const nodes = block.nodes.slice(1, Math.max(1, block.nodes.length - 1));
3865
+ removeNodes(nodes);
3866
+ }
3867
+ function removeBlockNodes(block) {
3914
3868
  let cursor = block.start;
3869
+ const end = block.end;
3915
3870
  while (cursor) {
3916
3871
  const next = cursor.nextSibling;
3917
3872
  cursor.parentNode?.removeChild(cursor);
3918
- if (cursor === block.end) {
3919
- break;
3920
- }
3873
+ if (cursor === end) break;
3921
3874
  cursor = next;
3922
3875
  }
3923
3876
  }
3924
- function createVersionedSignalAccessor(initialValue) {
3925
- let current = initialValue;
3926
- let version = 0;
3927
- const track2 = signal(version);
3928
- function accessor(value) {
3929
- if (arguments.length === 0) {
3930
- track2();
3931
- return current;
3932
- }
3933
- current = value;
3934
- version++;
3935
- track2(version);
3936
- }
3937
- return accessor;
3938
- }
3939
- function createKeyedListContainer() {
3940
- const startMarker = document.createComment("fict:list:start");
3941
- const endMarker = document.createComment("fict:list:end");
3942
- const dispose = () => {
3943
- for (const block of container.blocks.values()) {
3944
- destroyRoot(block.root);
3877
+
3878
+ // src/scope.ts
3879
+ function createScope() {
3880
+ let dispose = null;
3881
+ const stop = () => {
3882
+ if (dispose) {
3883
+ dispose();
3884
+ dispose = null;
3945
3885
  }
3946
- container.blocks.clear();
3947
- container.nextBlocks.clear();
3948
- const range = document.createRange();
3949
- range.setStartBefore(startMarker);
3950
- range.setEndAfter(endMarker);
3951
- range.deleteContents();
3952
- container.currentNodes = [];
3953
- container.nextNodes = [];
3954
- container.nextBlocks.clear();
3955
- container.orderedBlocks.length = 0;
3956
- container.nextOrderedBlocks.length = 0;
3957
- container.orderedIndexByKey.clear();
3958
3886
  };
3959
- const container = {
3960
- startMarker,
3961
- endMarker,
3962
- blocks: /* @__PURE__ */ new Map(),
3963
- nextBlocks: /* @__PURE__ */ new Map(),
3964
- currentNodes: [startMarker, endMarker],
3965
- nextNodes: [],
3966
- orderedBlocks: [],
3967
- nextOrderedBlocks: [],
3968
- orderedIndexByKey: /* @__PURE__ */ new Map(),
3969
- dispose
3887
+ const run = (fn) => {
3888
+ stop();
3889
+ const { dispose: rootDispose, value } = createRoot(fn);
3890
+ dispose = rootDispose;
3891
+ return value;
3970
3892
  };
3971
- return container;
3893
+ registerRootCleanup(stop);
3894
+ return { run, stop };
3972
3895
  }
3973
- function createKeyedBlock(key, item, index, render2, needsIndex = true) {
3974
- const itemSig = createVersionedSignalAccessor(item);
3975
- const indexSig = needsIndex ? signal(index) : ((next) => {
3976
- if (arguments.length === 0) return index;
3977
- index = next;
3978
- return index;
3979
- });
3980
- const root = createRootContext();
3981
- const prevRoot = pushRoot(root);
3982
- const prevSub = setActiveSub(void 0);
3983
- let nodes = [];
3984
- try {
3985
- const rendered = render2(itemSig, indexSig, key);
3986
- if (rendered instanceof Node || Array.isArray(rendered) && rendered.every((n) => n instanceof Node)) {
3987
- nodes = toNodeArray(rendered);
3896
+ function runInScope(flag, fn) {
3897
+ const scope = createScope();
3898
+ const evaluate = () => isReactive(flag) ? flag() : !!flag;
3899
+ createEffect(() => {
3900
+ const enabled = evaluate();
3901
+ if (enabled) {
3902
+ scope.run(fn);
3988
3903
  } else {
3989
- const element = createElement(rendered);
3990
- nodes = toNodeArray(element);
3904
+ scope.stop();
3991
3905
  }
3992
- } finally {
3993
- setActiveSub(prevSub);
3994
- popRoot(prevRoot);
3995
- flushOnMount(root);
3996
- }
3906
+ });
3907
+ onCleanup(scope.stop);
3908
+ }
3909
+
3910
+ // src/versioned-signal.ts
3911
+ function createVersionedSignal(initialValue, options2) {
3912
+ const equals = options2?.equals ?? Object.is;
3913
+ const value = signal(initialValue);
3914
+ const version = signal(0);
3915
+ const bumpVersion = () => {
3916
+ const next = version() + 1;
3917
+ version(next);
3918
+ };
3997
3919
  return {
3998
- key,
3999
- nodes,
4000
- root,
4001
- item: itemSig,
4002
- index: indexSig,
4003
- rawItem: item,
4004
- rawIndex: index
3920
+ read: () => {
3921
+ version();
3922
+ return value();
3923
+ },
3924
+ write: (next) => {
3925
+ const prev = value();
3926
+ if (!equals(prev, next)) {
3927
+ value(next);
3928
+ return;
3929
+ }
3930
+ bumpVersion();
3931
+ },
3932
+ force: () => {
3933
+ bumpVersion();
3934
+ },
3935
+ peekVersion: () => version(),
3936
+ peekValue: () => value()
4005
3937
  };
4006
3938
  }
4007
- function getFirstNodeAfter(marker) {
4008
- return marker.nextSibling;
4009
- }
4010
- function isNodeBetweenMarkers(node, startMarker, endMarker) {
4011
- let current = startMarker.nextSibling;
4012
- while (current && current !== endMarker) {
4013
- if (current === node) return true;
4014
- current = current.nextSibling;
4015
- }
4016
- return false;
4017
- }
4018
- function createKeyedList(getItems, keyFn, renderItem, needsIndex) {
4019
- const resolvedNeedsIndex = arguments.length >= 4 ? !!needsIndex : renderItem.length > 1;
4020
- return createFineGrainedKeyedList(getItems, keyFn, renderItem, resolvedNeedsIndex);
3939
+
3940
+ // src/ref.ts
3941
+ function createRef() {
3942
+ return { current: null };
4021
3943
  }
4022
- function createFineGrainedKeyedList(getItems, keyFn, renderItem, needsIndex) {
4023
- const container = createKeyedListContainer();
3944
+
3945
+ // src/error-boundary.ts
3946
+ function ErrorBoundary(props) {
4024
3947
  const fragment = document.createDocumentFragment();
4025
- fragment.append(container.startMarker, container.endMarker);
4026
- let pendingItems = null;
4027
- let disposed = false;
4028
- const performDiff = () => {
4029
- if (disposed) return;
4030
- batch2(() => {
4031
- const newItems = pendingItems || getItems();
4032
- pendingItems = null;
4033
- const oldBlocks = container.blocks;
4034
- const newBlocks = container.nextBlocks;
4035
- const prevOrderedBlocks = container.orderedBlocks;
4036
- const nextOrderedBlocks = container.nextOrderedBlocks;
4037
- const orderedIndexByKey = container.orderedIndexByKey;
4038
- newBlocks.clear();
4039
- nextOrderedBlocks.length = 0;
4040
- orderedIndexByKey.clear();
4041
- const endParent = container.endMarker.parentNode;
4042
- const startParent = container.startMarker.parentNode;
4043
- const parent = endParent && startParent && endParent === startParent && endParent.isConnected ? endParent : null;
4044
- if (!parent) {
4045
- pendingItems = newItems;
4046
- queueMicrotask(performDiff);
4047
- return;
4048
- }
4049
- if (newItems.length === 0) {
4050
- if (oldBlocks.size > 0) {
4051
- for (const block of oldBlocks.values()) {
4052
- destroyRoot(block.root);
4053
- removeNodes(block.nodes);
4054
- }
4055
- }
4056
- oldBlocks.clear();
4057
- newBlocks.clear();
4058
- prevOrderedBlocks.length = 0;
4059
- nextOrderedBlocks.length = 0;
4060
- orderedIndexByKey.clear();
4061
- container.currentNodes.length = 0;
4062
- container.currentNodes.push(container.startMarker, container.endMarker);
4063
- container.nextNodes.length = 0;
4064
- return;
3948
+ const marker = document.createComment("fict:error-boundary");
3949
+ fragment.appendChild(marker);
3950
+ const currentView = signal(props.children ?? null);
3951
+ const hostRoot = getCurrentRoot();
3952
+ let cleanup;
3953
+ let activeNodes = [];
3954
+ let renderingFallback = false;
3955
+ const toView = (err) => {
3956
+ if (err != null) {
3957
+ return typeof props.fallback === "function" ? props.fallback(err) : props.fallback;
3958
+ }
3959
+ return props.children ?? null;
3960
+ };
3961
+ const renderValue = (value) => {
3962
+ if (cleanup) {
3963
+ cleanup();
3964
+ cleanup = void 0;
3965
+ }
3966
+ if (activeNodes.length) {
3967
+ removeNodes(activeNodes);
3968
+ activeNodes = [];
3969
+ }
3970
+ if (value == null || value === false) {
3971
+ return;
3972
+ }
3973
+ const root = createRootContext(hostRoot);
3974
+ const prev = pushRoot(root);
3975
+ let nodes = [];
3976
+ try {
3977
+ const output = createElement(value);
3978
+ nodes = toNodeArray(output);
3979
+ const parentNode = marker.parentNode;
3980
+ if (parentNode) {
3981
+ insertNodesBefore(parentNode, nodes, marker);
4065
3982
  }
4066
- const prevCount = prevOrderedBlocks.length;
4067
- let appendCandidate = prevCount > 0 && newItems.length >= prevCount;
4068
- const appendedBlocks = [];
4069
- newItems.forEach((item, index) => {
4070
- const key = keyFn(item, index);
4071
- const existed = oldBlocks.has(key);
4072
- let block = oldBlocks.get(key);
4073
- if (block) {
4074
- if (block.rawItem !== item) {
4075
- block.rawItem = item;
4076
- block.item(item);
4077
- }
4078
- if (needsIndex && block.rawIndex !== index) {
4079
- block.rawIndex = index;
4080
- block.index(index);
4081
- }
4082
- }
4083
- const existingBlock = newBlocks.get(key);
4084
- if (existingBlock && existingBlock !== block) {
4085
- destroyRoot(existingBlock.root);
4086
- removeNodes(existingBlock.nodes);
4087
- }
4088
- if (block) {
4089
- newBlocks.set(key, block);
4090
- oldBlocks.delete(key);
4091
- } else {
4092
- const existingBlock2 = newBlocks.get(key);
4093
- if (existingBlock2) {
4094
- destroyRoot(existingBlock2.root);
4095
- removeNodes(existingBlock2.nodes);
4096
- }
4097
- block = createKeyedBlock(key, item, index, renderItem, needsIndex);
4098
- }
4099
- const resolvedBlock = block;
4100
- newBlocks.set(key, resolvedBlock);
4101
- const position = orderedIndexByKey.get(key);
4102
- if (position !== void 0) {
4103
- appendCandidate = false;
4104
- }
4105
- if (appendCandidate) {
4106
- if (index < prevCount) {
4107
- if (!prevOrderedBlocks[index] || prevOrderedBlocks[index].key !== key) {
4108
- appendCandidate = false;
4109
- }
4110
- } else if (existed) {
4111
- appendCandidate = false;
4112
- }
4113
- }
4114
- if (position !== void 0) {
4115
- const prior = nextOrderedBlocks[position];
4116
- if (prior && prior !== resolvedBlock) {
4117
- destroyRoot(prior.root);
4118
- removeNodes(prior.nodes);
4119
- }
4120
- nextOrderedBlocks[position] = resolvedBlock;
4121
- } else {
4122
- orderedIndexByKey.set(key, nextOrderedBlocks.length);
4123
- nextOrderedBlocks.push(resolvedBlock);
4124
- }
4125
- if (appendCandidate && index >= prevCount) {
4126
- appendedBlocks.push(resolvedBlock);
4127
- }
4128
- });
4129
- const canAppend = appendCandidate && prevCount > 0 && newItems.length > prevCount && oldBlocks.size === 0 && appendedBlocks.length > 0;
4130
- if (canAppend) {
4131
- const appendedNodes = [];
4132
- for (const block of appendedBlocks) {
4133
- for (let i = 0; i < block.nodes.length; i++) {
4134
- appendedNodes.push(block.nodes[i]);
4135
- }
4136
- }
4137
- if (appendedNodes.length > 0) {
4138
- insertNodesBefore(parent, appendedNodes, container.endMarker);
4139
- const currentNodes = container.currentNodes;
4140
- currentNodes.pop();
4141
- for (let i = 0; i < appendedNodes.length; i++) {
4142
- currentNodes.push(appendedNodes[i]);
4143
- }
4144
- currentNodes.push(container.endMarker);
4145
- }
4146
- container.blocks = newBlocks;
4147
- container.nextBlocks = oldBlocks;
4148
- container.orderedBlocks = nextOrderedBlocks;
4149
- container.nextOrderedBlocks = prevOrderedBlocks;
4150
- return;
3983
+ } catch (err) {
3984
+ popRoot(prev);
3985
+ flushOnMount(root);
3986
+ destroyRoot(root);
3987
+ if (renderingFallback) {
3988
+ throw err;
4151
3989
  }
4152
- if (oldBlocks.size > 0) {
4153
- for (const block of oldBlocks.values()) {
4154
- destroyRoot(block.root);
4155
- removeNodes(block.nodes);
4156
- }
4157
- oldBlocks.clear();
3990
+ renderingFallback = true;
3991
+ try {
3992
+ renderValue(toView(err));
3993
+ } finally {
3994
+ renderingFallback = false;
4158
3995
  }
4159
- if (newBlocks.size > 0 || container.currentNodes.length > 0) {
4160
- const prevNodes = container.currentNodes;
4161
- const nextNodes = container.nextNodes;
4162
- nextNodes.length = 0;
4163
- nextNodes.push(container.startMarker);
4164
- for (let i = 0; i < nextOrderedBlocks.length; i++) {
4165
- const nodes = nextOrderedBlocks[i].nodes;
4166
- for (let j = 0; j < nodes.length; j++) {
4167
- nextNodes.push(nodes[j]);
4168
- }
4169
- }
4170
- nextNodes.push(container.endMarker);
4171
- reconcileArrays(parent, prevNodes, nextNodes);
4172
- container.currentNodes = nextNodes;
4173
- container.nextNodes = prevNodes;
3996
+ props.onError?.(err);
3997
+ return;
3998
+ }
3999
+ popRoot(prev);
4000
+ flushOnMount(root);
4001
+ cleanup = () => {
4002
+ destroyRoot(root);
4003
+ removeNodes(nodes);
4004
+ };
4005
+ activeNodes = nodes;
4006
+ };
4007
+ createEffect(() => {
4008
+ const value = currentView();
4009
+ renderValue(value);
4010
+ });
4011
+ registerErrorHandler((err) => {
4012
+ renderValue(toView(err));
4013
+ props.onError?.(err);
4014
+ return true;
4015
+ });
4016
+ if (props.resetKeys !== void 0) {
4017
+ const isGetter = typeof props.resetKeys === "function" && props.resetKeys.length === 0;
4018
+ const getter = isGetter ? props.resetKeys : void 0;
4019
+ let prev = isGetter ? getter() : props.resetKeys;
4020
+ createEffect(() => {
4021
+ const next = getter ? getter() : props.resetKeys;
4022
+ if (prev !== next) {
4023
+ prev = next;
4024
+ renderValue(toView(null));
4174
4025
  }
4175
- container.blocks = newBlocks;
4176
- container.nextBlocks = oldBlocks;
4177
- container.orderedBlocks = nextOrderedBlocks;
4178
- container.nextOrderedBlocks = prevOrderedBlocks;
4179
4026
  });
4180
- };
4181
- const effectDispose = createRenderEffect(performDiff);
4027
+ }
4028
+ return fragment;
4029
+ }
4030
+
4031
+ // src/suspense.ts
4032
+ function createSuspenseToken() {
4033
+ let resolve;
4034
+ let reject;
4035
+ const promise = new Promise((res, rej) => {
4036
+ resolve = res;
4037
+ reject = rej;
4038
+ });
4182
4039
  return {
4183
- marker: fragment,
4184
- startMarker: container.startMarker,
4185
- endMarker: container.endMarker,
4186
- // Flush pending items - call after markers are inserted into DOM
4187
- flush: () => {
4188
- if (pendingItems !== null) {
4189
- performDiff();
4190
- }
4040
+ token: {
4041
+ then: promise.then.bind(promise)
4191
4042
  },
4192
- dispose: () => {
4193
- disposed = true;
4194
- effectDispose?.();
4195
- container.dispose();
4043
+ resolve,
4044
+ reject
4045
+ };
4046
+ }
4047
+ var isThenable = (value) => typeof value === "object" && value !== null && typeof value.then === "function";
4048
+ function Suspense(props) {
4049
+ const currentView = signal(props.children ?? null);
4050
+ const pending = signal(0);
4051
+ let resolvedOnce = false;
4052
+ let epoch = 0;
4053
+ const hostRoot = getCurrentRoot();
4054
+ const toFallback = (err) => typeof props.fallback === "function" ? props.fallback(err) : props.fallback;
4055
+ const switchView = (view) => {
4056
+ currentView(view);
4057
+ renderView(view);
4058
+ };
4059
+ const renderView = (view) => {
4060
+ if (cleanup) {
4061
+ cleanup();
4062
+ cleanup = void 0;
4063
+ }
4064
+ if (activeNodes.length) {
4065
+ removeNodes(activeNodes);
4066
+ activeNodes = [];
4196
4067
  }
4068
+ if (view == null || view === false) {
4069
+ return;
4070
+ }
4071
+ const root = createRootContext(hostRoot);
4072
+ const prev = pushRoot(root);
4073
+ let nodes = [];
4074
+ try {
4075
+ const output = createElement(view);
4076
+ nodes = toNodeArray(output);
4077
+ const suspendedAttempt = nodes.length > 0 && nodes.every((node) => node instanceof Comment && node.data === "fict:suspend");
4078
+ if (suspendedAttempt) {
4079
+ popRoot(prev);
4080
+ destroyRoot(root);
4081
+ return;
4082
+ }
4083
+ const parentNode = marker.parentNode;
4084
+ if (parentNode) {
4085
+ insertNodesBefore(parentNode, nodes, marker);
4086
+ }
4087
+ } catch (err) {
4088
+ popRoot(prev);
4089
+ flushOnMount(root);
4090
+ destroyRoot(root);
4091
+ handleError(err, { source: "render" });
4092
+ return;
4093
+ }
4094
+ popRoot(prev);
4095
+ flushOnMount(root);
4096
+ cleanup = () => {
4097
+ destroyRoot(root);
4098
+ removeNodes(nodes);
4099
+ };
4100
+ activeNodes = nodes;
4197
4101
  };
4102
+ const fragment = document.createDocumentFragment();
4103
+ const marker = document.createComment("fict:suspense");
4104
+ fragment.appendChild(marker);
4105
+ let cleanup;
4106
+ let activeNodes = [];
4107
+ const onResolveMaybe = () => {
4108
+ if (!resolvedOnce) {
4109
+ resolvedOnce = true;
4110
+ props.onResolve?.();
4111
+ }
4112
+ };
4113
+ registerSuspenseHandler((token) => {
4114
+ const tokenEpoch = epoch;
4115
+ pending(pending() + 1);
4116
+ switchView(toFallback());
4117
+ const thenable = token.then ? token : isThenable(token) ? token : null;
4118
+ if (thenable) {
4119
+ thenable.then(
4120
+ () => {
4121
+ if (epoch !== tokenEpoch) return;
4122
+ pending(Math.max(0, pending() - 1));
4123
+ if (pending() === 0) {
4124
+ switchView(props.children ?? null);
4125
+ onResolveMaybe();
4126
+ }
4127
+ },
4128
+ (err) => {
4129
+ if (epoch !== tokenEpoch) return;
4130
+ pending(Math.max(0, pending() - 1));
4131
+ props.onReject?.(err);
4132
+ handleError(err, { source: "render" }, hostRoot);
4133
+ }
4134
+ );
4135
+ return true;
4136
+ }
4137
+ return false;
4138
+ });
4139
+ createEffect(() => {
4140
+ renderView(currentView());
4141
+ });
4142
+ if (props.resetKeys !== void 0) {
4143
+ const isGetter = typeof props.resetKeys === "function" && props.resetKeys.length === 0;
4144
+ const getter = isGetter ? props.resetKeys : void 0;
4145
+ let prev = isGetter ? getter() : props.resetKeys;
4146
+ createEffect(() => {
4147
+ const next = getter ? getter() : props.resetKeys;
4148
+ if (prev !== next) {
4149
+ prev = next;
4150
+ epoch++;
4151
+ pending(0);
4152
+ switchView(props.children ?? null);
4153
+ }
4154
+ });
4155
+ }
4156
+ return fragment;
4198
4157
  }
4199
4158
  export {
4200
4159
  $effect,