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