@opentui/core 0.1.23 → 0.1.25

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.
@@ -1,3 +1,4 @@
1
+ // @bun
1
2
  var __create = Object.create;
2
3
  var __getProtoOf = Object.getPrototypeOf;
3
4
  var __defProp = Object.defineProperty;
@@ -26,102 +27,29 @@ var __export = (target, all) => {
26
27
  };
27
28
  var __require = import.meta.require;
28
29
 
29
- // src/lib/border.ts
30
- var BorderChars = {
31
- single: {
32
- topLeft: "\u250C",
33
- topRight: "\u2510",
34
- bottomLeft: "\u2514",
35
- bottomRight: "\u2518",
36
- horizontal: "\u2500",
37
- vertical: "\u2502",
38
- topT: "\u252C",
39
- bottomT: "\u2534",
40
- leftT: "\u251C",
41
- rightT: "\u2524",
42
- cross: "\u253C"
43
- },
44
- double: {
45
- topLeft: "\u2554",
46
- topRight: "\u2557",
47
- bottomLeft: "\u255A",
48
- bottomRight: "\u255D",
49
- horizontal: "\u2550",
50
- vertical: "\u2551",
51
- topT: "\u2566",
52
- bottomT: "\u2569",
53
- leftT: "\u2560",
54
- rightT: "\u2563",
55
- cross: "\u256C"
56
- },
57
- rounded: {
58
- topLeft: "\u256D",
59
- topRight: "\u256E",
60
- bottomLeft: "\u2570",
61
- bottomRight: "\u256F",
62
- horizontal: "\u2500",
63
- vertical: "\u2502",
64
- topT: "\u252C",
65
- bottomT: "\u2534",
66
- leftT: "\u251C",
67
- rightT: "\u2524",
68
- cross: "\u253C"
69
- },
70
- heavy: {
71
- topLeft: "\u250F",
72
- topRight: "\u2513",
73
- bottomLeft: "\u2517",
74
- bottomRight: "\u251B",
75
- horizontal: "\u2501",
76
- vertical: "\u2503",
77
- topT: "\u2533",
78
- bottomT: "\u253B",
79
- leftT: "\u2523",
80
- rightT: "\u252B",
81
- cross: "\u254B"
82
- }
83
- };
84
- function getBorderFromSides(sides) {
85
- const result = [];
86
- if (sides.top)
87
- result.push("top");
88
- if (sides.right)
89
- result.push("right");
90
- if (sides.bottom)
91
- result.push("bottom");
92
- if (sides.left)
93
- result.push("left");
94
- return result.length > 0 ? result : false;
95
- }
96
- function getBorderSides(border) {
97
- return border === true ? { top: true, right: true, bottom: true, left: true } : Array.isArray(border) ? {
98
- top: border.includes("top"),
99
- right: border.includes("right"),
100
- bottom: border.includes("bottom"),
101
- left: border.includes("left")
102
- } : { top: false, right: false, bottom: false, left: false };
103
- }
104
- function borderCharsToArray(chars) {
105
- const array = new Uint32Array(11);
106
- array[0] = chars.topLeft.codePointAt(0);
107
- array[1] = chars.topRight.codePointAt(0);
108
- array[2] = chars.bottomLeft.codePointAt(0);
109
- array[3] = chars.bottomRight.codePointAt(0);
110
- array[4] = chars.horizontal.codePointAt(0);
111
- array[5] = chars.vertical.codePointAt(0);
112
- array[6] = chars.topT.codePointAt(0);
113
- array[7] = chars.bottomT.codePointAt(0);
114
- array[8] = chars.leftT.codePointAt(0);
115
- array[9] = chars.rightT.codePointAt(0);
116
- array[10] = chars.cross.codePointAt(0);
117
- return array;
118
- }
119
- var BorderCharArrays = {
120
- single: borderCharsToArray(BorderChars.single),
121
- double: borderCharsToArray(BorderChars.double),
122
- rounded: borderCharsToArray(BorderChars.rounded),
123
- heavy: borderCharsToArray(BorderChars.heavy)
124
- };
30
+ // ../../node_modules/yoga-layout/dist/src/index.js
31
+ var exports_src = {};
32
+ __export(exports_src, {
33
+ default: () => src_default,
34
+ Wrap: () => Wrap,
35
+ Unit: () => Unit,
36
+ PositionType: () => PositionType,
37
+ Overflow: () => Overflow,
38
+ NodeType: () => NodeType,
39
+ MeasureMode: () => MeasureMode,
40
+ LogLevel: () => LogLevel,
41
+ Justify: () => Justify,
42
+ Gutter: () => Gutter,
43
+ FlexDirection: () => FlexDirection,
44
+ ExperimentalFeature: () => ExperimentalFeature,
45
+ Errata: () => Errata,
46
+ Edge: () => Edge,
47
+ Display: () => Display,
48
+ Direction: () => Direction,
49
+ Dimension: () => Dimension,
50
+ BoxSizing: () => BoxSizing,
51
+ Align: () => Align
52
+ });
125
53
 
126
54
  // ../../node_modules/yoga-layout/dist/binaries/yoga-wasm-base64-esm.js
127
55
  var loadYoga = (() => {
@@ -1737,186 +1665,336 @@ function wrapAssembly(lib) {
1737
1665
  var Yoga = wrapAssembly(await yoga_wasm_base64_esm_default());
1738
1666
  var src_default = Yoga;
1739
1667
 
1740
- // src/lib/TrackedNode.ts
1741
- import { EventEmitter } from "events";
1742
-
1743
- class TrackedNode extends EventEmitter {
1744
- static idCounter = 0;
1745
- id;
1746
- yogaNode;
1747
- metadata;
1748
- parent;
1749
- children;
1750
- _destroyed = false;
1751
- _width = "auto";
1752
- _height = "auto";
1753
- constructor(yogaNode, metadata = {}) {
1754
- super();
1755
- this.id = TrackedNode.idCounter++;
1756
- this.yogaNode = yogaNode;
1757
- this.metadata = metadata;
1758
- this.parent = null;
1759
- this.children = [];
1760
- }
1761
- parseWidth(width) {
1762
- if (this._destroyed) {
1763
- throw new Error("Node is destroyed");
1764
- }
1765
- if (typeof width === "number" || width === "auto") {
1766
- return width;
1767
- }
1768
- if (!this.parent) {
1769
- return this.yogaNode.getComputedWidth();
1770
- }
1771
- if (this.parent._destroyed) {
1772
- throw new Error("Parent node is destroyed");
1773
- }
1774
- return Math.floor(this.parent.yogaNode.getComputedWidth() * parseInt(width) / 100);
1668
+ // src/lib/border.ts
1669
+ var BorderChars = {
1670
+ single: {
1671
+ topLeft: "\u250C",
1672
+ topRight: "\u2510",
1673
+ bottomLeft: "\u2514",
1674
+ bottomRight: "\u2518",
1675
+ horizontal: "\u2500",
1676
+ vertical: "\u2502",
1677
+ topT: "\u252C",
1678
+ bottomT: "\u2534",
1679
+ leftT: "\u251C",
1680
+ rightT: "\u2524",
1681
+ cross: "\u253C"
1682
+ },
1683
+ double: {
1684
+ topLeft: "\u2554",
1685
+ topRight: "\u2557",
1686
+ bottomLeft: "\u255A",
1687
+ bottomRight: "\u255D",
1688
+ horizontal: "\u2550",
1689
+ vertical: "\u2551",
1690
+ topT: "\u2566",
1691
+ bottomT: "\u2569",
1692
+ leftT: "\u2560",
1693
+ rightT: "\u2563",
1694
+ cross: "\u256C"
1695
+ },
1696
+ rounded: {
1697
+ topLeft: "\u256D",
1698
+ topRight: "\u256E",
1699
+ bottomLeft: "\u2570",
1700
+ bottomRight: "\u256F",
1701
+ horizontal: "\u2500",
1702
+ vertical: "\u2502",
1703
+ topT: "\u252C",
1704
+ bottomT: "\u2534",
1705
+ leftT: "\u251C",
1706
+ rightT: "\u2524",
1707
+ cross: "\u253C"
1708
+ },
1709
+ heavy: {
1710
+ topLeft: "\u250F",
1711
+ topRight: "\u2513",
1712
+ bottomLeft: "\u2517",
1713
+ bottomRight: "\u251B",
1714
+ horizontal: "\u2501",
1715
+ vertical: "\u2503",
1716
+ topT: "\u2533",
1717
+ bottomT: "\u253B",
1718
+ leftT: "\u2523",
1719
+ rightT: "\u252B",
1720
+ cross: "\u254B"
1775
1721
  }
1776
- parseHeight(height) {
1777
- if (this._destroyed) {
1778
- throw new Error("Node is destroyed");
1779
- }
1780
- if (typeof height === "number" || height === "auto") {
1781
- return height;
1782
- }
1783
- if (!this.parent) {
1784
- return this.yogaNode.getComputedHeight();
1785
- }
1786
- if (this.parent._destroyed) {
1787
- throw new Error("Parent node is destroyed");
1722
+ };
1723
+ function getBorderFromSides(sides) {
1724
+ const result = [];
1725
+ if (sides.top)
1726
+ result.push("top");
1727
+ if (sides.right)
1728
+ result.push("right");
1729
+ if (sides.bottom)
1730
+ result.push("bottom");
1731
+ if (sides.left)
1732
+ result.push("left");
1733
+ return result.length > 0 ? result : false;
1734
+ }
1735
+ function getBorderSides(border) {
1736
+ return border === true ? { top: true, right: true, bottom: true, left: true } : Array.isArray(border) ? {
1737
+ top: border.includes("top"),
1738
+ right: border.includes("right"),
1739
+ bottom: border.includes("bottom"),
1740
+ left: border.includes("left")
1741
+ } : { top: false, right: false, bottom: false, left: false };
1742
+ }
1743
+ function borderCharsToArray(chars) {
1744
+ const array = new Uint32Array(11);
1745
+ array[0] = chars.topLeft.codePointAt(0);
1746
+ array[1] = chars.topRight.codePointAt(0);
1747
+ array[2] = chars.bottomLeft.codePointAt(0);
1748
+ array[3] = chars.bottomRight.codePointAt(0);
1749
+ array[4] = chars.horizontal.codePointAt(0);
1750
+ array[5] = chars.vertical.codePointAt(0);
1751
+ array[6] = chars.topT.codePointAt(0);
1752
+ array[7] = chars.bottomT.codePointAt(0);
1753
+ array[8] = chars.leftT.codePointAt(0);
1754
+ array[9] = chars.rightT.codePointAt(0);
1755
+ array[10] = chars.cross.codePointAt(0);
1756
+ return array;
1757
+ }
1758
+ var BorderCharArrays = {
1759
+ single: borderCharsToArray(BorderChars.single),
1760
+ double: borderCharsToArray(BorderChars.double),
1761
+ rounded: borderCharsToArray(BorderChars.rounded),
1762
+ heavy: borderCharsToArray(BorderChars.heavy)
1763
+ };
1764
+
1765
+ // src/lib/parse.keypress.ts
1766
+ import { Buffer } from "buffer";
1767
+
1768
+ // src/lib/parse.keypress-kitty.ts
1769
+ var kittyKeyMap = {
1770
+ 27: "escape",
1771
+ 9: "tab",
1772
+ 13: "enter",
1773
+ 127: "backspace",
1774
+ 57344: "escape",
1775
+ 57345: "enter",
1776
+ 57346: "tab",
1777
+ 57347: "backspace",
1778
+ 57348: "insert",
1779
+ 57349: "delete",
1780
+ 57350: "left",
1781
+ 57351: "right",
1782
+ 57352: "up",
1783
+ 57353: "down",
1784
+ 57354: "pageup",
1785
+ 57355: "pagedown",
1786
+ 57356: "home",
1787
+ 57357: "end",
1788
+ 57364: "f1",
1789
+ 57365: "f2",
1790
+ 57366: "f3",
1791
+ 57367: "f4",
1792
+ 57368: "f5",
1793
+ 57369: "f6",
1794
+ 57370: "f7",
1795
+ 57371: "f8",
1796
+ 57372: "f9",
1797
+ 57373: "f10",
1798
+ 57374: "f11",
1799
+ 57375: "f12",
1800
+ 57376: "f13",
1801
+ 57377: "f14",
1802
+ 57378: "f15",
1803
+ 57379: "f16",
1804
+ 57380: "f17",
1805
+ 57381: "f18",
1806
+ 57382: "f19",
1807
+ 57383: "f20",
1808
+ 57384: "f21",
1809
+ 57385: "f22",
1810
+ 57386: "f23",
1811
+ 57387: "f24",
1812
+ 57388: "f25",
1813
+ 57389: "f26",
1814
+ 57390: "f27",
1815
+ 57391: "f28",
1816
+ 57392: "f29",
1817
+ 57393: "f30",
1818
+ 57394: "f31",
1819
+ 57395: "f32",
1820
+ 57396: "f33",
1821
+ 57397: "f34",
1822
+ 57398: "f35",
1823
+ 57400: "kp0",
1824
+ 57401: "kp1",
1825
+ 57402: "kp2",
1826
+ 57403: "kp3",
1827
+ 57404: "kp4",
1828
+ 57405: "kp5",
1829
+ 57406: "kp6",
1830
+ 57407: "kp7",
1831
+ 57408: "kp8",
1832
+ 57409: "kp9",
1833
+ 57410: "kpdecimal",
1834
+ 57411: "kpdivide",
1835
+ 57412: "kpmultiply",
1836
+ 57413: "kpminus",
1837
+ 57414: "kpplus",
1838
+ 57415: "kpenter",
1839
+ 57416: "kpequal",
1840
+ 57428: "mediaplay",
1841
+ 57429: "mediapause",
1842
+ 57430: "mediaplaypause",
1843
+ 57431: "mediareverse",
1844
+ 57432: "mediastop",
1845
+ 57433: "mediafastforward",
1846
+ 57434: "mediarewind",
1847
+ 57435: "medianext",
1848
+ 57436: "mediaprev",
1849
+ 57437: "mediarecord",
1850
+ 57438: "volumedown",
1851
+ 57439: "volumeup",
1852
+ 57440: "mute",
1853
+ 57441: "leftshift",
1854
+ 57442: "leftctrl",
1855
+ 57443: "leftalt",
1856
+ 57444: "leftsuper",
1857
+ 57445: "lefthyper",
1858
+ 57446: "leftmeta",
1859
+ 57447: "rightshift",
1860
+ 57448: "rightctrl",
1861
+ 57449: "rightalt",
1862
+ 57450: "rightsuper",
1863
+ 57451: "righthyper",
1864
+ 57452: "rightmeta",
1865
+ 57453: "iso_level3_shift",
1866
+ 57454: "iso_level5_shift"
1867
+ };
1868
+ function fromKittyMods(mod) {
1869
+ return {
1870
+ shift: !!(mod & 1),
1871
+ alt: !!(mod & 2),
1872
+ ctrl: !!(mod & 4),
1873
+ super: !!(mod & 8),
1874
+ hyper: !!(mod & 16),
1875
+ meta: !!(mod & 32),
1876
+ capsLock: !!(mod & 64),
1877
+ numLock: !!(mod & 128)
1878
+ };
1879
+ }
1880
+ function parseKittyKeyboard(sequence) {
1881
+ const kittyRe = /^\x1b\[([^\x1b]+)u$/;
1882
+ const match = kittyRe.exec(sequence);
1883
+ if (!match)
1884
+ return null;
1885
+ const params = match[1];
1886
+ const fields = params.split(";");
1887
+ if (fields.length < 1)
1888
+ return null;
1889
+ const key = {
1890
+ name: "",
1891
+ ctrl: false,
1892
+ meta: false,
1893
+ shift: false,
1894
+ option: false,
1895
+ number: false,
1896
+ sequence,
1897
+ raw: sequence,
1898
+ eventType: "press",
1899
+ super: false,
1900
+ hyper: false,
1901
+ capsLock: false,
1902
+ numLock: false
1903
+ };
1904
+ let text = "";
1905
+ const field1 = fields[0]?.split(":") || [];
1906
+ const codepointStr = field1[0];
1907
+ if (!codepointStr)
1908
+ return null;
1909
+ const codepoint = parseInt(codepointStr, 10);
1910
+ if (isNaN(codepoint))
1911
+ return null;
1912
+ let shiftedCodepoint;
1913
+ let baseCodepoint;
1914
+ if (field1[1]) {
1915
+ const shifted = parseInt(field1[1], 10);
1916
+ if (!isNaN(shifted) && shifted > 0 && shifted <= 1114111) {
1917
+ shiftedCodepoint = shifted;
1788
1918
  }
1789
- return Math.floor(this.parent.yogaNode.getComputedHeight() * parseInt(height) / 100);
1790
1919
  }
1791
- setWidth(width) {
1792
- this._width = width;
1793
- const parsedWidth = this.parseWidth(width);
1794
- if (parsedWidth === "auto") {
1795
- this.yogaNode.setWidthAuto();
1796
- } else {
1797
- this.yogaNode.setWidth(parsedWidth);
1920
+ if (field1[2]) {
1921
+ const base = parseInt(field1[2], 10);
1922
+ if (!isNaN(base) && base > 0 && base <= 1114111) {
1923
+ baseCodepoint = base;
1798
1924
  }
1799
1925
  }
1800
- setHeight(height) {
1801
- this._height = height;
1802
- const parsedHeight = this.parseHeight(height);
1803
- if (parsedHeight === "auto") {
1804
- this.yogaNode.setHeightAuto();
1926
+ const knownKey = kittyKeyMap[codepoint];
1927
+ if (knownKey) {
1928
+ key.name = knownKey;
1929
+ key.code = `[${codepoint}u`;
1930
+ } else {
1931
+ if (codepoint > 0 && codepoint <= 1114111) {
1932
+ const char = String.fromCodePoint(codepoint);
1933
+ key.name = char;
1934
+ if (baseCodepoint) {
1935
+ key.baseCode = baseCodepoint;
1936
+ }
1805
1937
  } else {
1806
- this.yogaNode.setHeight(parsedHeight);
1938
+ return null;
1807
1939
  }
1808
1940
  }
1809
- addChild(childNode) {
1810
- if (childNode.parent) {
1811
- childNode.parent.removeChild(childNode);
1941
+ if (fields[1]) {
1942
+ const field2 = fields[1].split(":");
1943
+ const modifierStr = field2[0];
1944
+ const eventTypeStr = field2[1];
1945
+ if (modifierStr) {
1946
+ const modifierMask = parseInt(modifierStr, 10);
1947
+ if (!isNaN(modifierMask) && modifierMask > 1) {
1948
+ const mods = fromKittyMods(modifierMask - 1);
1949
+ key.shift = mods.shift;
1950
+ key.ctrl = mods.ctrl;
1951
+ key.meta = mods.alt || mods.meta;
1952
+ key.option = mods.alt;
1953
+ key.super = mods.super;
1954
+ key.hyper = mods.hyper;
1955
+ key.capsLock = mods.capsLock;
1956
+ key.numLock = mods.numLock;
1957
+ }
1812
1958
  }
1813
- childNode.parent = this;
1814
- const index = this.children.length;
1815
- this.children.push(childNode);
1816
- this.yogaNode.insertChild(childNode.yogaNode, index);
1817
- try {
1818
- childNode.yogaNode.setWidth(childNode.parseWidth(childNode._width));
1819
- childNode.yogaNode.setHeight(childNode.parseHeight(childNode._height));
1820
- } catch (e) {
1821
- console.error("Error setting width and height", e);
1959
+ if (eventTypeStr === "1" || !eventTypeStr) {
1960
+ key.eventType = "press";
1961
+ } else if (eventTypeStr === "2") {
1962
+ key.eventType = "repeat";
1963
+ } else if (eventTypeStr === "3") {
1964
+ key.eventType = "release";
1965
+ } else {
1966
+ key.eventType = "press";
1822
1967
  }
1823
- return index;
1824
- }
1825
- getChildIndex(childNode) {
1826
- return this.children.indexOf(childNode);
1827
1968
  }
1828
- removeChild(childNode) {
1829
- const index = this.children.indexOf(childNode);
1830
- if (index === -1) {
1831
- return false;
1832
- }
1833
- this.children.splice(index, 1);
1834
- this.yogaNode.removeChild(childNode.yogaNode);
1835
- childNode.parent = null;
1836
- return true;
1837
- }
1838
- removeChildAtIndex(index) {
1839
- if (index < 0 || index >= this.children.length) {
1840
- return null;
1841
- }
1842
- const childNode = this.children[index];
1843
- this.children.splice(index, 1);
1844
- this.yogaNode.removeChild(childNode.yogaNode);
1845
- childNode.parent = null;
1846
- return childNode;
1847
- }
1848
- moveChild(childNode, newIndex) {
1849
- const currentIndex = this.children.indexOf(childNode);
1850
- if (currentIndex === -1) {
1851
- throw new Error("Node is not a child of this parent");
1852
- }
1853
- const boundedNewIndex = Math.max(0, Math.min(newIndex, this.children.length - 1));
1854
- if (currentIndex === boundedNewIndex) {
1855
- return currentIndex;
1856
- }
1857
- this.children.splice(currentIndex, 1);
1858
- this.children.splice(boundedNewIndex, 0, childNode);
1859
- this.yogaNode.removeChild(childNode.yogaNode);
1860
- this.yogaNode.insertChild(childNode.yogaNode, boundedNewIndex);
1861
- return boundedNewIndex;
1862
- }
1863
- insertChild(childNode, index) {
1864
- if (childNode.parent) {
1865
- childNode.parent.removeChild(childNode);
1866
- }
1867
- childNode.parent = this;
1868
- const boundedIndex = Math.max(0, Math.min(index, this.children.length));
1869
- this.children.splice(boundedIndex, 0, childNode);
1870
- this.yogaNode.insertChild(childNode.yogaNode, boundedIndex);
1871
- try {
1872
- childNode.yogaNode.setWidth(childNode.parseWidth(childNode._width));
1873
- childNode.yogaNode.setHeight(childNode.parseHeight(childNode._height));
1874
- } catch (e) {
1875
- console.error("Error setting width and height", e);
1969
+ if (fields[2]) {
1970
+ const codepoints = fields[2].split(":");
1971
+ for (const cpStr of codepoints) {
1972
+ const cp = parseInt(cpStr, 10);
1973
+ if (!isNaN(cp) && cp > 0 && cp <= 1114111) {
1974
+ text += String.fromCodePoint(cp);
1975
+ }
1876
1976
  }
1877
- return boundedIndex;
1878
- }
1879
- getChildCount() {
1880
- return this.children.length;
1881
1977
  }
1882
- getChildAtIndex(index) {
1883
- if (index < 0 || index >= this.children.length) {
1884
- return null;
1978
+ if (text === "") {
1979
+ const isPrintable = key.name.length > 0 && !kittyKeyMap[codepoint];
1980
+ if (isPrintable) {
1981
+ if (key.shift && shiftedCodepoint) {
1982
+ text = String.fromCodePoint(shiftedCodepoint);
1983
+ } else {
1984
+ text = key.name;
1985
+ }
1885
1986
  }
1886
- return this.children[index];
1887
1987
  }
1888
- setMetadata(key, value) {
1889
- this.metadata[key] = value;
1988
+ if (key.name === " " && key.shift && !key.ctrl && !key.meta) {
1989
+ text = " ";
1890
1990
  }
1891
- getMetadata(key) {
1892
- return this.metadata[key];
1991
+ if (text) {
1992
+ key.sequence = text;
1893
1993
  }
1894
- removeMetadata(key) {
1895
- delete this.metadata[key];
1896
- }
1897
- hasChild(childNode) {
1898
- return this.children.includes(childNode);
1899
- }
1900
- destroy() {
1901
- if (this._destroyed) {
1902
- return;
1903
- }
1904
- if (this.parent) {
1905
- this.parent.removeChild(this);
1906
- }
1907
- try {
1908
- this.yogaNode.free();
1909
- } catch (e) {}
1910
- this._destroyed = true;
1911
- }
1912
- }
1913
- function createTrackedNode(metadata = {}, yogaConfig) {
1914
- const yogaNode = src_default.Node.create(yogaConfig);
1915
- return new TrackedNode(yogaNode, metadata);
1994
+ return key;
1916
1995
  }
1917
1996
 
1918
1997
  // src/lib/parse.keypress.ts
1919
- import { Buffer } from "buffer";
1920
1998
  var metaKeyCodeRe = /^(?:\x1b)([a-zA-Z0-9])$/;
1921
1999
  var fnKeyRe = /^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/;
1922
2000
  var keyName = {
@@ -2000,7 +2078,7 @@ var isShiftKey = (code) => {
2000
2078
  var isCtrlKey = (code) => {
2001
2079
  return ["Oa", "Ob", "Oc", "Od", "Oe", "[2^", "[3^", "[5^", "[6^", "[7^", "[8^"].includes(code);
2002
2080
  };
2003
- var parseKeypress = (s = "") => {
2081
+ var parseKeypress = (s = "", options = {}) => {
2004
2082
  let parts;
2005
2083
  if (Buffer.isBuffer(s)) {
2006
2084
  if (s[0] > 127 && s[1] === undefined) {
@@ -2022,9 +2100,16 @@ var parseKeypress = (s = "") => {
2022
2100
  option: false,
2023
2101
  number: false,
2024
2102
  sequence: s,
2025
- raw: s
2103
+ raw: s,
2104
+ eventType: "press"
2026
2105
  };
2027
2106
  key.sequence = key.sequence || s || key.name;
2107
+ if (options.useKittyKeyboard && /^\x1b\[.*u$/.test(s)) {
2108
+ const kittyResult = parseKittyKeyboard(s);
2109
+ if (kittyResult) {
2110
+ return kittyResult;
2111
+ }
2112
+ }
2028
2113
  if (s === "\r") {
2029
2114
  key.name = "return";
2030
2115
  } else if (s === `
@@ -2064,15 +2149,21 @@ var parseKeypress = (s = "") => {
2064
2149
  key.option = true;
2065
2150
  }
2066
2151
  const code = [parts[1], parts[2], parts[4], parts[6]].filter(Boolean).join("");
2067
- const modifier = (parts[3] || parts[5] || 1) - 1;
2152
+ const modifier = parseInt(parts[3] || parts[5] || "1", 10) - 1;
2068
2153
  key.ctrl = !!(modifier & 4);
2069
2154
  key.meta = !!(modifier & 10);
2070
2155
  key.shift = !!(modifier & 1);
2071
2156
  key.option = !!(modifier & 2);
2072
2157
  key.code = code;
2073
- key.name = keyName[code];
2074
- key.shift = isShiftKey(code) || key.shift;
2075
- key.ctrl = isCtrlKey(code) || key.ctrl;
2158
+ const keyNameResult = keyName[code];
2159
+ if (keyNameResult) {
2160
+ key.name = keyNameResult;
2161
+ key.shift = isShiftKey(code) || key.shift;
2162
+ key.ctrl = isCtrlKey(code) || key.ctrl;
2163
+ } else {
2164
+ key.name = "";
2165
+ key.code = undefined;
2166
+ }
2076
2167
  } else if (s === "\x1B[3~") {
2077
2168
  key.name = "delete";
2078
2169
  key.meta = false;
@@ -2082,42 +2173,69 @@ var parseKeypress = (s = "") => {
2082
2173
  };
2083
2174
 
2084
2175
  // src/lib/KeyHandler.ts
2085
- import { EventEmitter as EventEmitter2 } from "events";
2176
+ import { EventEmitter } from "events";
2086
2177
 
2087
- // src/singleton.ts
2088
- var singletonCacheSymbol = Symbol.for("@opentui/core/singleton");
2089
- function singleton(key, factory) {
2090
- const bag = globalThis[singletonCacheSymbol] ??= {};
2091
- if (!(key in bag)) {
2092
- bag[key] = factory();
2093
- }
2094
- return bag[key];
2095
- }
2178
+ // src/ansi.ts
2179
+ var ANSI = {
2180
+ switchToAlternateScreen: "\x1B[?1049h",
2181
+ switchToMainScreen: "\x1B[?1049l",
2182
+ reset: "\x1B[0m",
2183
+ scrollDown: (lines) => `\x1B[${lines}T`,
2184
+ scrollUp: (lines) => `\x1B[${lines}S`,
2185
+ moveCursor: (row, col) => `\x1B[${row};${col}H`,
2186
+ moveCursorAndClear: (row, col) => `\x1B[${row};${col}H\x1B[J`,
2187
+ setRgbBackground: (r, g, b) => `\x1B[48;2;${r};${g};${b}m`,
2188
+ resetBackground: "\x1B[49m",
2189
+ bracketedPasteStart: "\x1B[200~",
2190
+ bracketedPasteEnd: "\x1B[201~"
2191
+ };
2096
2192
 
2097
2193
  // src/lib/KeyHandler.ts
2098
- class KeyHandler extends EventEmitter2 {
2099
- constructor() {
2194
+ class KeyHandler extends EventEmitter {
2195
+ stdin;
2196
+ useKittyKeyboard;
2197
+ listener;
2198
+ pasteMode = false;
2199
+ pasteBuffer = [];
2200
+ constructor(stdin, useKittyKeyboard = false) {
2100
2201
  super();
2101
- if (process.stdin.setRawMode) {
2102
- process.stdin.setRawMode(true);
2103
- }
2104
- process.stdin.resume();
2105
- process.stdin.setEncoding("utf8");
2106
- process.stdin.on("data", (key) => {
2107
- const parsedKey = parseKeypress(key);
2108
- this.emit("keypress", parsedKey);
2109
- });
2202
+ this.stdin = stdin || process.stdin;
2203
+ this.useKittyKeyboard = useKittyKeyboard;
2204
+ this.listener = (key) => {
2205
+ let data = key.toString();
2206
+ if (data.startsWith(ANSI.bracketedPasteStart)) {
2207
+ this.pasteMode = true;
2208
+ }
2209
+ if (this.pasteMode) {
2210
+ this.pasteBuffer.push(Bun.stripANSI(data));
2211
+ if (data.endsWith(ANSI.bracketedPasteEnd)) {
2212
+ this.pasteMode = false;
2213
+ this.emit("paste", this.pasteBuffer.join(""));
2214
+ this.pasteBuffer = [];
2215
+ }
2216
+ return;
2217
+ }
2218
+ const parsedKey = parseKeypress(key, { useKittyKeyboard: this.useKittyKeyboard });
2219
+ switch (parsedKey.eventType) {
2220
+ case "press":
2221
+ this.emit("keypress", parsedKey);
2222
+ break;
2223
+ case "repeat":
2224
+ this.emit("keyrepeat", parsedKey);
2225
+ break;
2226
+ case "release":
2227
+ this.emit("keyrelease", parsedKey);
2228
+ break;
2229
+ default:
2230
+ this.emit("keypress", parsedKey);
2231
+ break;
2232
+ }
2233
+ };
2234
+ this.stdin.on("data", this.listener);
2110
2235
  }
2111
2236
  destroy() {
2112
- process.stdin.removeAllListeners("data");
2113
- }
2114
- }
2115
- var keyHandler = null;
2116
- function getKeyHandler() {
2117
- if (!keyHandler) {
2118
- keyHandler = singleton("KeyHandler", () => new KeyHandler);
2237
+ this.stdin.removeListener("data", this.listener);
2119
2238
  }
2120
- return keyHandler;
2121
2239
  }
2122
2240
 
2123
2241
  // src/lib/RGBA.ts
@@ -3936,6 +4054,31 @@ function createTextAttributes({
3936
4054
  attributes |= TextAttributes.STRIKETHROUGH;
3937
4055
  return attributes;
3938
4056
  }
4057
+ function visualizeRenderableTree(renderable, maxDepth = 10) {
4058
+ function buildTreeLines(node, prefix = "", parentPrefix = "", isLastChild = true, depth = 0) {
4059
+ if (depth >= maxDepth) {
4060
+ return [`${prefix}${node.id} ... (max depth reached)`];
4061
+ }
4062
+ const lines = [];
4063
+ const children = node.getChildren();
4064
+ lines.push(`${prefix}${node.id}`);
4065
+ if (children.length > 0) {
4066
+ const lastChildIndex = children.length - 1;
4067
+ children.forEach((child, index) => {
4068
+ const childIsLast = index === lastChildIndex;
4069
+ const connector = childIsLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
4070
+ const childPrefix = parentPrefix + (isLastChild ? " " : "\u2502 ");
4071
+ const childLines = buildTreeLines(child, childPrefix + connector, childPrefix, childIsLast, depth + 1);
4072
+ lines.push(...childLines);
4073
+ });
4074
+ }
4075
+ return lines;
4076
+ }
4077
+ const treeLines = buildTreeLines(renderable);
4078
+ console.log(`Renderable Tree:
4079
+ ` + treeLines.join(`
4080
+ `));
4081
+ }
3939
4082
 
3940
4083
  // src/lib/styled-text.ts
3941
4084
  var BrandedStyledText = Symbol.for("@opentui/core/StyledText");
@@ -4671,6 +4814,166 @@ class ASCIIFontSelectionHelper {
4671
4814
  return previousSelection?.start !== this.localSelection?.start || previousSelection?.end !== this.localSelection?.end;
4672
4815
  }
4673
4816
  }
4817
+
4818
+ // src/lib/singleton.ts
4819
+ var singletonCacheSymbol = Symbol.for("@opentui/core/singleton");
4820
+ function singleton(key, factory) {
4821
+ const bag = globalThis[singletonCacheSymbol] ??= {};
4822
+ if (!(key in bag)) {
4823
+ bag[key] = factory();
4824
+ }
4825
+ return bag[key];
4826
+ }
4827
+
4828
+ // src/lib/env.ts
4829
+ var envRegistry = {};
4830
+ function registerEnvVar(config) {
4831
+ const existing = envRegistry[config.name];
4832
+ if (existing) {
4833
+ if (existing.description !== config.description || existing.type !== config.type || existing.default !== config.default) {
4834
+ throw new Error(`Environment variable "${config.name}" is already registered with different configuration. ` + `Existing: ${JSON.stringify(existing)}, New: ${JSON.stringify(config)}`);
4835
+ }
4836
+ return;
4837
+ }
4838
+ envRegistry[config.name] = config;
4839
+ }
4840
+ function normalizeBoolean(value) {
4841
+ const lowerValue = value.toLowerCase();
4842
+ return ["true", "1", "on", "yes"].includes(lowerValue);
4843
+ }
4844
+ function parseEnvValue(config) {
4845
+ const envValue = process.env[config.name];
4846
+ if (envValue === undefined && config.default !== undefined) {
4847
+ return config.default;
4848
+ }
4849
+ if (envValue === undefined) {
4850
+ throw new Error(`Required environment variable ${config.name} is not set. ${config.description}`);
4851
+ }
4852
+ switch (config.type) {
4853
+ case "boolean":
4854
+ return typeof envValue === "boolean" ? envValue : normalizeBoolean(envValue);
4855
+ case "number":
4856
+ const numValue = Number(envValue);
4857
+ if (isNaN(numValue)) {
4858
+ throw new Error(`Environment variable ${config.name} must be a valid number, got: ${envValue}`);
4859
+ }
4860
+ return numValue;
4861
+ case "string":
4862
+ default:
4863
+ return envValue;
4864
+ }
4865
+ }
4866
+
4867
+ class EnvStore {
4868
+ parsedValues = new Map;
4869
+ get(key) {
4870
+ if (this.parsedValues.has(key)) {
4871
+ return this.parsedValues.get(key);
4872
+ }
4873
+ if (!(key in envRegistry)) {
4874
+ throw new Error(`Environment variable ${key} is not registered.`);
4875
+ }
4876
+ try {
4877
+ const value = parseEnvValue(envRegistry[key]);
4878
+ this.parsedValues.set(key, value);
4879
+ return value;
4880
+ } catch (error) {
4881
+ throw new Error(`Failed to parse env var ${key}: ${error instanceof Error ? error.message : String(error)}`);
4882
+ }
4883
+ }
4884
+ has(key) {
4885
+ return key in envRegistry;
4886
+ }
4887
+ }
4888
+ var envStore = singleton("env-store", () => new EnvStore);
4889
+ function generateEnvMarkdown() {
4890
+ const configs = Object.values(envRegistry);
4891
+ if (configs.length === 0) {
4892
+ return `# Environment Variables
4893
+
4894
+ No environment variables registered.
4895
+ `;
4896
+ }
4897
+ let markdown = `# Environment Variables
4898
+
4899
+ `;
4900
+ for (const config of configs) {
4901
+ markdown += `## ${config.name}
4902
+
4903
+ `;
4904
+ markdown += `${config.description}
4905
+
4906
+ `;
4907
+ markdown += `**Type:** \`${config.type || "string"}\`
4908
+ `;
4909
+ if (config.default !== undefined) {
4910
+ const defaultValue = typeof config.default === "string" ? `"${config.default}"` : String(config.default);
4911
+ markdown += `**Default:** \`${defaultValue}\`
4912
+ `;
4913
+ } else {
4914
+ markdown += `**Default:** *Required*
4915
+ `;
4916
+ }
4917
+ markdown += `
4918
+ `;
4919
+ }
4920
+ return markdown;
4921
+ }
4922
+ function generateEnvColored() {
4923
+ const configs = Object.values(envRegistry);
4924
+ if (configs.length === 0) {
4925
+ return `\x1B[1;36mEnvironment Variables\x1B[0m
4926
+
4927
+ No environment variables registered.
4928
+ `;
4929
+ }
4930
+ let output = `\x1B[1;36mEnvironment Variables\x1B[0m
4931
+
4932
+ `;
4933
+ for (const config of configs) {
4934
+ output += `\x1B[1;33m${config.name}\x1B[0m
4935
+ `;
4936
+ output += `${config.description}
4937
+ `;
4938
+ output += `\x1B[32mType:\x1B[0m \x1B[36m${config.type || "string"}\x1B[0m
4939
+ `;
4940
+ if (config.default !== undefined) {
4941
+ const defaultValue = typeof config.default === "string" ? `"${config.default}"` : String(config.default);
4942
+ output += `\x1B[32mDefault:\x1B[0m \x1B[35m${defaultValue}\x1B[0m
4943
+ `;
4944
+ } else {
4945
+ output += `\x1B[32mDefault:\x1B[0m \x1B[31mRequired\x1B[0m
4946
+ `;
4947
+ }
4948
+ output += `
4949
+ `;
4950
+ }
4951
+ return output;
4952
+ }
4953
+ var env = new Proxy({}, {
4954
+ get(target, prop) {
4955
+ if (typeof prop !== "string") {
4956
+ return;
4957
+ }
4958
+ return envStore.get(prop);
4959
+ },
4960
+ has(target, prop) {
4961
+ return envStore.has(prop);
4962
+ },
4963
+ ownKeys() {
4964
+ return Object.keys(envRegistry);
4965
+ },
4966
+ getOwnPropertyDescriptor(target, prop) {
4967
+ if (envStore.has(prop)) {
4968
+ return {
4969
+ enumerable: true,
4970
+ configurable: true,
4971
+ get: () => envStore.get(prop)
4972
+ };
4973
+ }
4974
+ return;
4975
+ }
4976
+ });
4674
4977
  // src/zig.ts
4675
4978
  import { dlopen, toArrayBuffer as toArrayBuffer2, JSCallback, ptr } from "bun:ffi";
4676
4979
  import { existsSync } from "fs";
@@ -4713,10 +5016,16 @@ class OptimizedBuffer {
4713
5016
  _height;
4714
5017
  respectAlpha = false;
4715
5018
  _rawBuffers = null;
5019
+ _destroyed = false;
4716
5020
  get ptr() {
4717
5021
  return this.bufferPtr;
4718
5022
  }
5023
+ guard() {
5024
+ if (this._destroyed)
5025
+ throw new Error(`Buffer ${this.id} is destroyed`);
5026
+ }
4719
5027
  get buffers() {
5028
+ this.guard();
4720
5029
  if (this._rawBuffers === null) {
4721
5030
  const size = this._width * this._height;
4722
5031
  const charPtr = this.lib.bufferGetCharPtr(this.bufferPtr);
@@ -4746,9 +5055,6 @@ class OptimizedBuffer {
4746
5055
  const id = options.id && options.id.trim() !== "" ? options.id : "unnamed buffer";
4747
5056
  return lib.createOptimizedBuffer(width, height, widthMethod, respectAlpha, id);
4748
5057
  }
4749
- coordsToIndex(x, y) {
4750
- return y * this._width + x;
4751
- }
4752
5058
  get width() {
4753
5059
  return this._width;
4754
5060
  }
@@ -4756,22 +5062,35 @@ class OptimizedBuffer {
4756
5062
  return this._height;
4757
5063
  }
4758
5064
  setRespectAlpha(respectAlpha) {
5065
+ this.guard();
4759
5066
  this.lib.bufferSetRespectAlpha(this.bufferPtr, respectAlpha);
4760
5067
  this.respectAlpha = respectAlpha;
4761
5068
  }
4762
5069
  getNativeId() {
5070
+ this.guard();
4763
5071
  return this.lib.bufferGetId(this.bufferPtr);
4764
5072
  }
5073
+ getRealCharBytes(addLineBreaks = false) {
5074
+ this.guard();
5075
+ const realSize = this.lib.bufferGetRealCharSize(this.bufferPtr);
5076
+ const outputBuffer = new Uint8Array(realSize);
5077
+ const bytesWritten = this.lib.bufferWriteResolvedChars(this.bufferPtr, outputBuffer, addLineBreaks);
5078
+ return outputBuffer.slice(0, bytesWritten);
5079
+ }
4765
5080
  clear(bg2 = RGBA.fromValues(0, 0, 0, 1)) {
5081
+ this.guard();
4766
5082
  this.lib.bufferClear(this.bufferPtr, bg2);
4767
5083
  }
4768
5084
  setCell(x, y, char, fg2, bg2, attributes = 0) {
5085
+ this.guard();
4769
5086
  this.lib.bufferSetCell(this.bufferPtr, x, y, char, fg2, bg2, attributes);
4770
5087
  }
4771
5088
  setCellWithAlphaBlending(x, y, char, fg2, bg2, attributes = 0) {
5089
+ this.guard();
4772
5090
  this.lib.bufferSetCellWithAlphaBlending(this.bufferPtr, x, y, char, fg2, bg2, attributes);
4773
5091
  }
4774
5092
  drawText(text, x, y, fg2, bg2, attributes = 0, selection2) {
5093
+ this.guard();
4775
5094
  if (!selection2) {
4776
5095
  this.lib.bufferDrawText(this.bufferPtr, text, x, y, fg2, bg2, attributes);
4777
5096
  return;
@@ -4804,21 +5123,29 @@ class OptimizedBuffer {
4804
5123
  this.lib.bufferFillRect(this.bufferPtr, x, y, width, height, bg2);
4805
5124
  }
4806
5125
  drawFrameBuffer(destX, destY, frameBuffer, sourceX, sourceY, sourceWidth, sourceHeight) {
5126
+ this.guard();
4807
5127
  this.lib.drawFrameBuffer(this.bufferPtr, destX, destY, frameBuffer.ptr, sourceX, sourceY, sourceWidth, sourceHeight);
4808
5128
  }
4809
5129
  destroy() {
5130
+ if (this._destroyed)
5131
+ return;
5132
+ this._destroyed = true;
4810
5133
  this.lib.destroyOptimizedBuffer(this.bufferPtr);
4811
5134
  }
4812
5135
  drawTextBuffer(textBuffer, x, y, clipRect) {
5136
+ this.guard();
4813
5137
  this.lib.bufferDrawTextBuffer(this.bufferPtr, textBuffer.ptr, x, y, clipRect);
4814
5138
  }
4815
5139
  drawSuperSampleBuffer(x, y, pixelDataPtr, pixelDataLength, format, alignedBytesPerRow) {
5140
+ this.guard();
4816
5141
  this.lib.bufferDrawSuperSampleBuffer(this.bufferPtr, x, y, pixelDataPtr, pixelDataLength, format, alignedBytesPerRow);
4817
5142
  }
4818
5143
  drawPackedBuffer(dataPtr, dataLen, posX, posY, terminalWidthCells, terminalHeightCells) {
5144
+ this.guard();
4819
5145
  this.lib.bufferDrawPackedBuffer(this.bufferPtr, dataPtr, dataLen, posX, posY, terminalWidthCells, terminalHeightCells);
4820
5146
  }
4821
5147
  resize(width, height) {
5148
+ this.guard();
4822
5149
  if (this._width === width && this._height === height)
4823
5150
  return;
4824
5151
  this._width = width;
@@ -4827,18 +5154,22 @@ class OptimizedBuffer {
4827
5154
  this.lib.bufferResize(this.bufferPtr, width, height);
4828
5155
  }
4829
5156
  drawBox(options) {
5157
+ this.guard();
4830
5158
  const style = options.borderStyle || "single";
4831
5159
  const borderChars = options.customBorderChars ?? BorderCharArrays[style];
4832
5160
  const packedOptions = packDrawOptions(options.border, options.shouldFill ?? false, options.titleAlignment || "left");
4833
5161
  this.lib.bufferDrawBox(this.bufferPtr, options.x, options.y, options.width, options.height, borderChars, packedOptions, options.borderColor, options.backgroundColor, options.title ?? null);
4834
5162
  }
4835
5163
  pushScissorRect(x, y, width, height) {
5164
+ this.guard();
4836
5165
  this.lib.bufferPushScissorRect(this.bufferPtr, x, y, width, height);
4837
5166
  }
4838
5167
  popScissorRect() {
5168
+ this.guard();
4839
5169
  this.lib.bufferPopScissorRect(this.bufferPtr);
4840
5170
  }
4841
5171
  clearScissorRects() {
5172
+ this.guard();
4842
5173
  this.lib.bufferClearScissorRects(this.bufferPtr);
4843
5174
  }
4844
5175
  }
@@ -4849,19 +5180,31 @@ var targetLibPath = module.default;
4849
5180
  if (!existsSync(targetLibPath)) {
4850
5181
  throw new Error(`opentui is not supported on the current platform: ${process.platform}-${process.arch}`);
4851
5182
  }
5183
+ registerEnvVar({
5184
+ name: "OTUI_DEBUG_FFI",
5185
+ description: "Enable debug logging for the FFI bindings.",
5186
+ type: "boolean",
5187
+ default: false
5188
+ });
5189
+ registerEnvVar({
5190
+ name: "OTUI_TRACE_FFI",
5191
+ description: "Enable tracing for the FFI bindings.",
5192
+ type: "boolean",
5193
+ default: false
5194
+ });
4852
5195
  function getOpenTUILib(libPath) {
4853
5196
  const resolvedLibPath = libPath || targetLibPath;
4854
- return dlopen(resolvedLibPath, {
5197
+ const rawSymbols = dlopen(resolvedLibPath, {
4855
5198
  setLogCallback: {
4856
5199
  args: ["ptr"],
4857
5200
  returns: "void"
4858
5201
  },
4859
5202
  createRenderer: {
4860
- args: ["u32", "u32"],
5203
+ args: ["u32", "u32", "bool"],
4861
5204
  returns: "ptr"
4862
5205
  },
4863
5206
  destroyRenderer: {
4864
- args: ["ptr", "bool", "u32"],
5207
+ args: ["ptr"],
4865
5208
  returns: "void"
4866
5209
  },
4867
5210
  setUseThread: {
@@ -4896,6 +5239,10 @@ function getOpenTUILib(libPath) {
4896
5239
  args: ["ptr"],
4897
5240
  returns: "ptr"
4898
5241
  },
5242
+ queryPixelResolution: {
5243
+ args: ["ptr"],
5244
+ returns: "void"
5245
+ },
4899
5246
  createOptimizedBuffer: {
4900
5247
  args: ["u32", "u32", "bool", "u8", "ptr", "usize"],
4901
5248
  returns: "ptr"
@@ -4948,6 +5295,14 @@ function getOpenTUILib(libPath) {
4948
5295
  args: ["ptr", "ptr", "usize"],
4949
5296
  returns: "usize"
4950
5297
  },
5298
+ bufferGetRealCharSize: {
5299
+ args: ["ptr"],
5300
+ returns: "u32"
5301
+ },
5302
+ bufferWriteResolvedChars: {
5303
+ args: ["ptr", "ptr", "usize", "bool"],
5304
+ returns: "u32"
5305
+ },
4951
5306
  bufferDrawText: {
4952
5307
  args: ["ptr", "ptr", "u32", "u32", "u32", "ptr", "ptr", "u8"],
4953
5308
  returns: "void"
@@ -5061,25 +5416,17 @@ function getOpenTUILib(libPath) {
5061
5416
  returns: "void"
5062
5417
  },
5063
5418
  createTextBuffer: {
5064
- args: ["u32", "u8"],
5419
+ args: ["u8"],
5065
5420
  returns: "ptr"
5066
5421
  },
5067
5422
  destroyTextBuffer: {
5068
5423
  args: ["ptr"],
5069
5424
  returns: "void"
5070
5425
  },
5071
- textBufferGetCharPtr: {
5072
- args: ["ptr"],
5073
- returns: "ptr"
5074
- },
5075
5426
  textBufferGetLength: {
5076
5427
  args: ["ptr"],
5077
5428
  returns: "u32"
5078
5429
  },
5079
- textBufferResize: {
5080
- args: ["ptr", "u32"],
5081
- returns: "void"
5082
- },
5083
5430
  textBufferReset: {
5084
5431
  args: ["ptr"],
5085
5432
  returns: "void"
@@ -5112,10 +5459,6 @@ function getOpenTUILib(libPath) {
5112
5459
  args: ["ptr", "ptr", "u32", "ptr", "ptr", "ptr"],
5113
5460
  returns: "u32"
5114
5461
  },
5115
- textBufferGetCapacity: {
5116
- args: ["ptr"],
5117
- returns: "u32"
5118
- },
5119
5462
  textBufferFinalizeLineInfo: {
5120
5463
  args: ["ptr"],
5121
5464
  returns: "void"
@@ -5126,7 +5469,7 @@ function getOpenTUILib(libPath) {
5126
5469
  },
5127
5470
  textBufferGetLineInfoDirect: {
5128
5471
  args: ["ptr", "ptr", "ptr"],
5129
- returns: "void"
5472
+ returns: "u32"
5130
5473
  },
5131
5474
  textBufferGetSelectionInfo: {
5132
5475
  args: ["ptr"],
@@ -5164,6 +5507,14 @@ function getOpenTUILib(libPath) {
5164
5507
  args: ["ptr"],
5165
5508
  returns: "usize"
5166
5509
  },
5510
+ textBufferSetWrapWidth: {
5511
+ args: ["ptr", "u32"],
5512
+ returns: "void"
5513
+ },
5514
+ textBufferSetWrapMode: {
5515
+ args: ["ptr", "u8"],
5516
+ returns: "void"
5517
+ },
5167
5518
  getArenaAllocatedBytes: {
5168
5519
  args: [],
5169
5520
  returns: "usize"
@@ -5181,6 +5532,115 @@ function getOpenTUILib(libPath) {
5181
5532
  returns: "void"
5182
5533
  }
5183
5534
  });
5535
+ if (env.OTUI_DEBUG_FFI || env.OTUI_TRACE_FFI) {
5536
+ return {
5537
+ symbols: convertToDebugSymbols(rawSymbols.symbols)
5538
+ };
5539
+ }
5540
+ return rawSymbols;
5541
+ }
5542
+ function convertToDebugSymbols(symbols) {
5543
+ const debugSymbols = {};
5544
+ const traceSymbols = {};
5545
+ let hasTracing = false;
5546
+ Object.entries(symbols).forEach(([key, value]) => {
5547
+ debugSymbols[key] = value;
5548
+ });
5549
+ if (env.OTUI_DEBUG_FFI) {
5550
+ Object.entries(symbols).forEach(([key, value]) => {
5551
+ if (typeof value === "function") {
5552
+ debugSymbols[key] = (...args) => {
5553
+ console.log(`${key}(${args.map((arg) => String(arg)).join(", ")})`);
5554
+ const result = value(...args);
5555
+ console.log(`${key} returned:`, String(result));
5556
+ return result;
5557
+ };
5558
+ }
5559
+ });
5560
+ }
5561
+ if (env.OTUI_TRACE_FFI) {
5562
+ hasTracing = true;
5563
+ Object.entries(symbols).forEach(([key, value]) => {
5564
+ if (typeof value === "function") {
5565
+ traceSymbols[key] = [];
5566
+ const originalFunc = debugSymbols[key];
5567
+ debugSymbols[key] = (...args) => {
5568
+ const start = performance.now();
5569
+ const result = originalFunc(...args);
5570
+ const end = performance.now();
5571
+ traceSymbols[key].push(end - start);
5572
+ return result;
5573
+ };
5574
+ }
5575
+ });
5576
+ }
5577
+ if (hasTracing) {
5578
+ process.on("exit", () => {
5579
+ const allStats = [];
5580
+ for (const [key, timings] of Object.entries(traceSymbols)) {
5581
+ if (!Array.isArray(timings) || timings.length === 0) {
5582
+ continue;
5583
+ }
5584
+ const sortedTimings = [...timings].sort((a, b) => a - b);
5585
+ const count = sortedTimings.length;
5586
+ const total = sortedTimings.reduce((acc, t2) => acc + t2, 0);
5587
+ const average = total / count;
5588
+ const min = sortedTimings[0];
5589
+ const max = sortedTimings[count - 1];
5590
+ const medianIndex = Math.floor(count / 2);
5591
+ const p90Index = Math.floor(count * 0.9);
5592
+ const p99Index = Math.floor(count * 0.99);
5593
+ const median = sortedTimings[medianIndex];
5594
+ const p90 = sortedTimings[Math.min(p90Index, count - 1)];
5595
+ const p99 = sortedTimings[Math.min(p99Index, count - 1)];
5596
+ allStats.push({
5597
+ name: key,
5598
+ count,
5599
+ total,
5600
+ average,
5601
+ min,
5602
+ max,
5603
+ median,
5604
+ p90,
5605
+ p99
5606
+ });
5607
+ }
5608
+ allStats.sort((a, b) => b.total - a.total);
5609
+ console.log(`
5610
+ --- OpenTUI FFI Call Performance ---`);
5611
+ console.log("Sorted by total time spent (descending)");
5612
+ console.log("-------------------------------------------------------------------------------------------------------------------------");
5613
+ if (allStats.length === 0) {
5614
+ console.log("No trace data collected or all symbols had zero calls.");
5615
+ } else {
5616
+ const nameHeader = "Symbol";
5617
+ const callsHeader = "Calls";
5618
+ const totalHeader = "Total (ms)";
5619
+ const avgHeader = "Avg (ms)";
5620
+ const minHeader = "Min (ms)";
5621
+ const maxHeader = "Max (ms)";
5622
+ const medHeader = "Med (ms)";
5623
+ const p90Header = "P90 (ms)";
5624
+ const p99Header = "P99 (ms)";
5625
+ const nameWidth = Math.max(nameHeader.length, ...allStats.map((s) => s.name.length));
5626
+ const countWidth = Math.max(callsHeader.length, ...allStats.map((s) => String(s.count).length));
5627
+ const totalWidth = Math.max(totalHeader.length, ...allStats.map((s) => s.total.toFixed(2).length));
5628
+ const avgWidth = Math.max(avgHeader.length, ...allStats.map((s) => s.average.toFixed(2).length));
5629
+ const minWidth = Math.max(minHeader.length, ...allStats.map((s) => s.min.toFixed(2).length));
5630
+ const maxWidth = Math.max(maxHeader.length, ...allStats.map((s) => s.max.toFixed(2).length));
5631
+ const medianWidth = Math.max(medHeader.length, ...allStats.map((s) => s.median.toFixed(2).length));
5632
+ const p90Width = Math.max(p90Header.length, ...allStats.map((s) => s.p90.toFixed(2).length));
5633
+ const p99Width = Math.max(p99Header.length, ...allStats.map((s) => s.p99.toFixed(2).length));
5634
+ console.log(`${nameHeader.padEnd(nameWidth)} | ${callsHeader.padStart(countWidth)} | ${totalHeader.padStart(totalWidth)} | ${avgHeader.padStart(avgWidth)} | ${minHeader.padStart(minWidth)} | ${maxHeader.padStart(maxWidth)} | ${medHeader.padStart(medianWidth)} | ${p90Header.padStart(p90Width)} | ${p99Header.padStart(p99Width)}`);
5635
+ console.log(`${"-".repeat(nameWidth)}-+-${"-".repeat(countWidth)}-+-${"-".repeat(totalWidth)}-+-${"-".repeat(avgWidth)}-+-${"-".repeat(minWidth)}-+-${"-".repeat(maxWidth)}-+-${"-".repeat(medianWidth)}-+-${"-".repeat(p90Width)}-+-${"-".repeat(p99Width)}`);
5636
+ allStats.forEach((stat) => {
5637
+ console.log(`${stat.name.padEnd(nameWidth)} | ${String(stat.count).padStart(countWidth)} | ${stat.total.toFixed(2).padStart(totalWidth)} | ${stat.average.toFixed(2).padStart(avgWidth)} | ${stat.min.toFixed(2).padStart(minWidth)} | ${stat.max.toFixed(2).padStart(maxWidth)} | ${stat.median.toFixed(2).padStart(medianWidth)} | ${stat.p90.toFixed(2).padStart(p90Width)} | ${stat.p99.toFixed(2).padStart(p99Width)}`);
5638
+ });
5639
+ }
5640
+ console.log("-------------------------------------------------------------------------------------------------------------------------");
5641
+ });
5642
+ }
5643
+ return debugSymbols;
5184
5644
  }
5185
5645
  var LogLevel2;
5186
5646
  ((LogLevel3) => {
@@ -5244,11 +5704,11 @@ class FFIRenderLib {
5244
5704
  setLogCallback(callbackPtr) {
5245
5705
  this.opentui.symbols.setLogCallback(callbackPtr);
5246
5706
  }
5247
- createRenderer(width, height) {
5248
- return this.opentui.symbols.createRenderer(width, height);
5707
+ createRenderer(width, height, options = { testing: false }) {
5708
+ return this.opentui.symbols.createRenderer(width, height, options.testing);
5249
5709
  }
5250
- destroyRenderer(renderer, useAlternateScreen, splitHeight) {
5251
- this.opentui.symbols.destroyRenderer(renderer, useAlternateScreen, splitHeight);
5710
+ destroyRenderer(renderer) {
5711
+ this.opentui.symbols.destroyRenderer(renderer);
5252
5712
  }
5253
5713
  setUseThread(renderer, useThread) {
5254
5714
  this.opentui.symbols.setUseThread(renderer, useThread);
@@ -5324,6 +5784,13 @@ class FFIRenderLib {
5324
5784
  const len = typeof actualLen === "bigint" ? Number(actualLen) : actualLen;
5325
5785
  return this.decoder.decode(outBuffer.slice(0, len));
5326
5786
  }
5787
+ bufferGetRealCharSize(buffer) {
5788
+ return this.opentui.symbols.bufferGetRealCharSize(buffer);
5789
+ }
5790
+ bufferWriteResolvedChars(buffer, outputBuffer, addLineBreaks) {
5791
+ const bytesWritten = this.opentui.symbols.bufferWriteResolvedChars(buffer, outputBuffer, outputBuffer.length, addLineBreaks);
5792
+ return typeof bytesWritten === "bigint" ? Number(bytesWritten) : bytesWritten;
5793
+ }
5327
5794
  getBufferWidth(buffer) {
5328
5795
  return this.opentui.symbols.getBufferWidth(buffer);
5329
5796
  }
@@ -5453,30 +5920,23 @@ class FFIRenderLib {
5453
5920
  setupTerminal(renderer, useAlternateScreen) {
5454
5921
  this.opentui.symbols.setupTerminal(renderer, useAlternateScreen);
5455
5922
  }
5456
- createTextBuffer(capacity, widthMethod) {
5923
+ queryPixelResolution(renderer) {
5924
+ this.opentui.symbols.queryPixelResolution(renderer);
5925
+ }
5926
+ createTextBuffer(widthMethod) {
5457
5927
  const widthMethodCode = widthMethod === "wcwidth" ? 0 : 1;
5458
- const bufferPtr = this.opentui.symbols.createTextBuffer(capacity, widthMethodCode);
5928
+ const bufferPtr = this.opentui.symbols.createTextBuffer(widthMethodCode);
5459
5929
  if (!bufferPtr) {
5460
- throw new Error(`Failed to create TextBuffer with capacity ${capacity}`);
5930
+ throw new Error(`Failed to create TextBuffer`);
5461
5931
  }
5462
- return new TextBuffer(this, bufferPtr, capacity);
5932
+ return new TextBuffer(this, bufferPtr);
5463
5933
  }
5464
5934
  destroyTextBuffer(buffer) {
5465
5935
  this.opentui.symbols.destroyTextBuffer(buffer);
5466
5936
  }
5467
- textBufferGetCharPtr(buffer) {
5468
- const ptr2 = this.opentui.symbols.textBufferGetCharPtr(buffer);
5469
- if (!ptr2) {
5470
- throw new Error("Failed to get TextBuffer char pointer");
5471
- }
5472
- return ptr2;
5473
- }
5474
5937
  textBufferGetLength(buffer) {
5475
5938
  return this.opentui.symbols.textBufferGetLength(buffer);
5476
5939
  }
5477
- textBufferResize(buffer, newLength) {
5478
- this.opentui.symbols.textBufferResize(buffer, newLength);
5479
- }
5480
5940
  textBufferReset(buffer) {
5481
5941
  this.opentui.symbols.textBufferReset(buffer);
5482
5942
  }
@@ -5507,9 +5967,6 @@ class FFIRenderLib {
5507
5967
  const attrValue = attributes === null ? null : new Uint8Array([attributes]);
5508
5968
  return this.opentui.symbols.textBufferWriteChunk(buffer, textBytes, textBytes.length, fg2 ? fg2.buffer : null, bg2 ? bg2.buffer : null, attrValue);
5509
5969
  }
5510
- textBufferGetCapacity(buffer) {
5511
- return this.opentui.symbols.textBufferGetCapacity(buffer);
5512
- }
5513
5970
  textBufferFinalizeLineInfo(buffer) {
5514
5971
  this.opentui.symbols.textBufferFinalizeLineInfo(buffer);
5515
5972
  }
@@ -5517,7 +5974,7 @@ class FFIRenderLib {
5517
5974
  return this.opentui.symbols.textBufferGetLineCount(buffer);
5518
5975
  }
5519
5976
  textBufferGetLineInfoDirect(buffer, lineStartsPtr, lineWidthsPtr) {
5520
- this.opentui.symbols.textBufferGetLineInfoDirect(buffer, lineStartsPtr, lineWidthsPtr);
5977
+ return this.opentui.symbols.textBufferGetLineInfoDirect(buffer, lineStartsPtr, lineWidthsPtr);
5521
5978
  }
5522
5979
  textBufferGetSelection(buffer) {
5523
5980
  const packedInfo = this.textBufferGetSelectionInfo(buffer);
@@ -5582,6 +6039,13 @@ class FFIRenderLib {
5582
6039
  const result = this.opentui.symbols.textBufferGetChunkGroupCount(buffer);
5583
6040
  return typeof result === "bigint" ? Number(result) : result;
5584
6041
  }
6042
+ textBufferSetWrapWidth(buffer, width) {
6043
+ this.opentui.symbols.textBufferSetWrapWidth(buffer, width);
6044
+ }
6045
+ textBufferSetWrapMode(buffer, mode) {
6046
+ const modeValue = mode === "char" ? 0 : 1;
6047
+ this.opentui.symbols.textBufferSetWrapMode(buffer, modeValue);
6048
+ }
5585
6049
  getArenaAllocatedBytes() {
5586
6050
  const result = this.opentui.symbols.getArenaAllocatedBytes();
5587
6051
  return typeof result === "bigint" ? Number(result) : result;
@@ -5589,12 +6053,13 @@ class FFIRenderLib {
5589
6053
  textBufferGetLineInfo(buffer) {
5590
6054
  const lineCount = this.textBufferGetLineCount(buffer);
5591
6055
  if (lineCount === 0) {
5592
- return { lineStarts: [], lineWidths: [] };
6056
+ return { lineStarts: [], lineWidths: [], maxLineWidth: 0 };
5593
6057
  }
5594
6058
  const lineStarts = new Uint32Array(lineCount);
5595
6059
  const lineWidths = new Uint32Array(lineCount);
5596
- this.textBufferGetLineInfoDirect(buffer, ptr(lineStarts), ptr(lineWidths));
6060
+ const maxLineWidth = this.textBufferGetLineInfoDirect(buffer, ptr(lineStarts), ptr(lineWidths));
5597
6061
  return {
6062
+ maxLineWidth,
5598
6063
  lineStarts: Array.from(lineStarts),
5599
6064
  lineWidths: Array.from(lineWidths)
5600
6065
  };
@@ -5669,53 +6134,58 @@ class TextBuffer {
5669
6134
  lib;
5670
6135
  bufferPtr;
5671
6136
  _length = 0;
5672
- _capacity;
5673
6137
  _lineInfo;
5674
- constructor(lib, ptr2, capacity) {
6138
+ _destroyed = false;
6139
+ constructor(lib, ptr2) {
5675
6140
  this.lib = lib;
5676
6141
  this.bufferPtr = ptr2;
5677
- this._capacity = capacity;
5678
6142
  }
5679
- static create(capacity = 256, widthMethod) {
6143
+ static create(widthMethod) {
5680
6144
  const lib = resolveRenderLib();
5681
- return lib.createTextBuffer(capacity, widthMethod);
6145
+ return lib.createTextBuffer(widthMethod);
6146
+ }
6147
+ guard() {
6148
+ if (this._destroyed)
6149
+ throw new Error("TextBuffer is destroyed");
5682
6150
  }
5683
6151
  setStyledText(text) {
6152
+ this.guard();
5684
6153
  this.lib.textBufferReset(this.bufferPtr);
5685
6154
  this._length = 0;
5686
6155
  this._lineInfo = undefined;
5687
6156
  for (const chunk of text.chunks) {
5688
6157
  const textBytes = this.lib.encoder.encode(chunk.text);
5689
- const result = this.lib.textBufferWriteChunk(this.bufferPtr, textBytes, chunk.fg || null, chunk.bg || null, chunk.attributes ?? null);
5690
- if (result & 1) {
5691
- this._capacity = this.lib.textBufferGetCapacity(this.bufferPtr);
5692
- }
6158
+ this.lib.textBufferWriteChunk(this.bufferPtr, textBytes, chunk.fg || null, chunk.bg || null, chunk.attributes ?? null);
5693
6159
  }
5694
6160
  this.lib.textBufferFinalizeLineInfo(this.bufferPtr);
5695
6161
  this._length = this.lib.textBufferGetLength(this.bufferPtr);
5696
6162
  }
5697
6163
  setDefaultFg(fg2) {
6164
+ this.guard();
5698
6165
  this.lib.textBufferSetDefaultFg(this.bufferPtr, fg2);
5699
6166
  }
5700
6167
  setDefaultBg(bg2) {
6168
+ this.guard();
5701
6169
  this.lib.textBufferSetDefaultBg(this.bufferPtr, bg2);
5702
6170
  }
5703
6171
  setDefaultAttributes(attributes) {
6172
+ this.guard();
5704
6173
  this.lib.textBufferSetDefaultAttributes(this.bufferPtr, attributes);
5705
6174
  }
5706
6175
  resetDefaults() {
6176
+ this.guard();
5707
6177
  this.lib.textBufferResetDefaults(this.bufferPtr);
5708
6178
  }
5709
6179
  get length() {
6180
+ this.guard();
5710
6181
  return this._length;
5711
6182
  }
5712
- get capacity() {
5713
- return this._capacity;
5714
- }
5715
6183
  get ptr() {
6184
+ this.guard();
5716
6185
  return this.bufferPtr;
5717
6186
  }
5718
6187
  getSelectedText() {
6188
+ this.guard();
5719
6189
  if (this._length === 0)
5720
6190
  return "";
5721
6191
  const selectedBytes = this.lib.getSelectedTextBytes(this.bufferPtr, this.length * 4);
@@ -5724,6 +6194,7 @@ class TextBuffer {
5724
6194
  return this.lib.decoder.decode(selectedBytes);
5725
6195
  }
5726
6196
  getPlainText() {
6197
+ this.guard();
5727
6198
  if (this._length === 0)
5728
6199
  return "";
5729
6200
  const plainBytes = this.lib.getPlainTextBytes(this.bufferPtr, this.length * 4);
@@ -5732,72 +6203,87 @@ class TextBuffer {
5732
6203
  return this.lib.decoder.decode(plainBytes);
5733
6204
  }
5734
6205
  get lineInfo() {
6206
+ this.guard();
5735
6207
  if (!this._lineInfo) {
5736
6208
  this._lineInfo = this.lib.textBufferGetLineInfo(this.bufferPtr);
5737
6209
  }
5738
6210
  return this._lineInfo;
5739
6211
  }
5740
6212
  setSelection(start, end, bgColor, fgColor) {
6213
+ this.guard();
5741
6214
  this.lib.textBufferSetSelection(this.bufferPtr, start, end, bgColor || null, fgColor || null);
5742
6215
  }
5743
6216
  resetSelection() {
6217
+ this.guard();
5744
6218
  this.lib.textBufferResetSelection(this.bufferPtr);
5745
6219
  }
5746
6220
  setLocalSelection(anchorX, anchorY, focusX, focusY, bgColor, fgColor) {
6221
+ this.guard();
5747
6222
  return this.lib.textBufferSetLocalSelection(this.bufferPtr, anchorX, anchorY, focusX, focusY, bgColor || null, fgColor || null);
5748
6223
  }
5749
6224
  resetLocalSelection() {
6225
+ this.guard();
5750
6226
  this.lib.textBufferResetLocalSelection(this.bufferPtr);
5751
6227
  }
5752
6228
  getSelection() {
6229
+ this.guard();
5753
6230
  return this.lib.textBufferGetSelection(this.bufferPtr);
5754
6231
  }
5755
6232
  hasSelection() {
6233
+ this.guard();
5756
6234
  return this.getSelection() !== null;
5757
6235
  }
5758
6236
  insertChunkGroup(index, text, fg2, bg2, attributes) {
6237
+ this.guard();
5759
6238
  const textBytes = this.lib.encoder.encode(text);
5760
6239
  this.insertEncodedChunkGroup(index, textBytes, fg2, bg2, attributes);
5761
6240
  }
5762
6241
  insertEncodedChunkGroup(index, textBytes, fg2, bg2, attributes) {
6242
+ this.guard();
5763
6243
  this._length = this.lib.textBufferInsertChunkGroup(this.bufferPtr, index, textBytes, fg2 || null, bg2 || null, attributes ?? null);
5764
6244
  this._lineInfo = undefined;
5765
6245
  }
5766
6246
  removeChunkGroup(index) {
6247
+ this.guard();
5767
6248
  this._length = this.lib.textBufferRemoveChunkGroup(this.bufferPtr, index);
5768
6249
  this._lineInfo = undefined;
5769
6250
  }
5770
6251
  replaceChunkGroup(index, text, fg2, bg2, attributes) {
6252
+ this.guard();
5771
6253
  const textBytes = this.lib.encoder.encode(text);
5772
6254
  this.replaceEncodedChunkGroup(index, textBytes, fg2, bg2, attributes);
5773
6255
  }
5774
6256
  replaceEncodedChunkGroup(index, textBytes, fg2, bg2, attributes) {
6257
+ this.guard();
5775
6258
  this._length = this.lib.textBufferReplaceChunkGroup(this.bufferPtr, index, textBytes, fg2 || null, bg2 || null, attributes ?? null);
5776
6259
  this._lineInfo = undefined;
5777
6260
  }
5778
6261
  get chunkGroupCount() {
6262
+ this.guard();
5779
6263
  return this.lib.textBufferGetChunkGroupCount(this.bufferPtr);
5780
6264
  }
6265
+ setWrapWidth(width) {
6266
+ this.guard();
6267
+ this.lib.textBufferSetWrapWidth(this.bufferPtr, width ?? 0);
6268
+ this._lineInfo = undefined;
6269
+ }
6270
+ setWrapMode(mode) {
6271
+ this.guard();
6272
+ this.lib.textBufferSetWrapMode(this.bufferPtr, mode);
6273
+ this._lineInfo = undefined;
6274
+ }
5781
6275
  destroy() {
6276
+ if (this._destroyed)
6277
+ return;
6278
+ this._destroyed = true;
5782
6279
  this.lib.destroyTextBuffer(this.bufferPtr);
5783
6280
  }
5784
6281
  }
5785
6282
 
5786
6283
  // src/Renderable.ts
5787
- import { EventEmitter as EventEmitter3 } from "events";
5788
- var BrandedRenderable = Symbol.for("@opentui/core/Renderable");
5789
- var LayoutEvents;
5790
- ((LayoutEvents2) => {
5791
- LayoutEvents2["LAYOUT_CHANGED"] = "layout-changed";
5792
- LayoutEvents2["ADDED"] = "added";
5793
- LayoutEvents2["REMOVED"] = "removed";
5794
- LayoutEvents2["RESIZED"] = "resized";
5795
- })(LayoutEvents ||= {});
5796
- var RenderableEvents;
5797
- ((RenderableEvents2) => {
5798
- RenderableEvents2["FOCUSED"] = "focused";
5799
- RenderableEvents2["BLURRED"] = "blurred";
5800
- })(RenderableEvents ||= {});
6284
+ import { EventEmitter as EventEmitter2 } from "events";
6285
+
6286
+ // src/lib/renderable.validations.ts
5801
6287
  function validateOptions(id, options) {
5802
6288
  if (typeof options.width === "number") {
5803
6289
  if (options.width < 0) {
@@ -5869,20 +6355,43 @@ function isSizeType(value) {
5869
6355
  }
5870
6356
  return isValidPercentage(value);
5871
6357
  }
6358
+
6359
+ // src/Renderable.ts
6360
+ var BrandedRenderable = Symbol.for("@opentui/core/Renderable");
6361
+ var LayoutEvents;
6362
+ ((LayoutEvents2) => {
6363
+ LayoutEvents2["LAYOUT_CHANGED"] = "layout-changed";
6364
+ LayoutEvents2["ADDED"] = "added";
6365
+ LayoutEvents2["REMOVED"] = "removed";
6366
+ LayoutEvents2["RESIZED"] = "resized";
6367
+ })(LayoutEvents ||= {});
6368
+ var RenderableEvents;
6369
+ ((RenderableEvents2) => {
6370
+ RenderableEvents2["FOCUSED"] = "focused";
6371
+ RenderableEvents2["BLURRED"] = "blurred";
6372
+ })(RenderableEvents ||= {});
5872
6373
  function isRenderable(obj) {
5873
6374
  return !!obj?.[BrandedRenderable];
5874
6375
  }
5875
6376
 
5876
- class BaseRenderable extends EventEmitter3 {
6377
+ class BaseRenderable extends EventEmitter2 {
5877
6378
  [BrandedRenderable] = true;
5878
6379
  static renderableNumber = 1;
5879
- id;
6380
+ _id;
5880
6381
  num;
5881
6382
  _dirty = false;
6383
+ parent = null;
6384
+ _visible = true;
5882
6385
  constructor(options) {
5883
6386
  super();
5884
6387
  this.num = BaseRenderable.renderableNumber++;
5885
- this.id = options.id ?? `renderable-${this.num}`;
6388
+ this._id = options.id ?? `renderable-${this.num}`;
6389
+ }
6390
+ get id() {
6391
+ return this._id;
6392
+ }
6393
+ set id(value) {
6394
+ this._id = value;
5886
6395
  }
5887
6396
  get isDirty() {
5888
6397
  return this._dirty;
@@ -5893,7 +6402,18 @@ class BaseRenderable extends EventEmitter3 {
5893
6402
  markDirty() {
5894
6403
  this._dirty = true;
5895
6404
  }
6405
+ destroy() {}
6406
+ destroyRecursively() {}
6407
+ get visible() {
6408
+ return this._visible;
6409
+ }
6410
+ set visible(value) {
6411
+ this._visible = value;
6412
+ }
5896
6413
  }
6414
+ var yogaConfig = src_default.Config.create();
6415
+ yogaConfig.setUseWebDefaults(false);
6416
+ yogaConfig.setPointScaleFactor(1);
5897
6417
 
5898
6418
  class Renderable extends BaseRenderable {
5899
6419
  static renderablesByNumber = new Map;
@@ -5908,31 +6428,33 @@ class Renderable extends BaseRenderable {
5908
6428
  _widthValue = 0;
5909
6429
  _heightValue = 0;
5910
6430
  _zIndex;
5911
- _visible;
5912
6431
  selectable = false;
5913
6432
  buffered;
5914
6433
  frameBuffer = null;
5915
6434
  _focusable = false;
5916
6435
  _focused = false;
5917
- keyHandler = getKeyHandler();
5918
6436
  keypressHandler = null;
6437
+ pasteHandler = null;
5919
6438
  _live = false;
5920
6439
  _liveCount = 0;
5921
6440
  _sizeChangeListener = undefined;
5922
6441
  _mouseListener = null;
5923
6442
  _mouseListeners = {};
6443
+ _pasteListener = undefined;
5924
6444
  _keyListeners = {};
5925
- layoutNode;
6445
+ yogaNode;
5926
6446
  _positionType = "relative";
5927
6447
  _overflow = "visible";
5928
6448
  _position = {};
5929
- renderableMap = new Map;
5930
- renderableArray = [];
6449
+ renderableMapById = new Map;
6450
+ _childrenInLayoutOrder = [];
6451
+ _childrenInZIndexOrder = [];
5931
6452
  needsZIndexSort = false;
5932
6453
  parent = null;
5933
6454
  childrenPrimarySortDirty = true;
5934
6455
  childrenSortedByPrimaryAxis = [];
5935
6456
  _newChildren = [];
6457
+ onLifecyclePass = null;
5936
6458
  renderBefore;
5937
6459
  renderAfter;
5938
6460
  constructor(ctx, options) {
@@ -5955,14 +6477,24 @@ class Renderable extends BaseRenderable {
5955
6477
  this.buffered = options.buffered ?? false;
5956
6478
  this._live = options.live ?? false;
5957
6479
  this._liveCount = this._live && this._visible ? 1 : 0;
5958
- this.layoutNode = createTrackedNode({ renderable: this });
5959
- this.layoutNode.yogaNode.setDisplay(this._visible ? Display.Flex : Display.None);
6480
+ this.yogaNode = src_default.Node.create(yogaConfig);
6481
+ this.yogaNode.setDisplay(this._visible ? Display.Flex : Display.None);
5960
6482
  this.setupYogaProperties(options);
5961
6483
  this.applyEventOptions(options);
5962
6484
  if (this.buffered) {
5963
6485
  this.createFrameBuffer();
5964
6486
  }
5965
6487
  }
6488
+ get id() {
6489
+ return this._id;
6490
+ }
6491
+ set id(value) {
6492
+ if (this.parent) {
6493
+ this.parent.renderableMapById.delete(this.id);
6494
+ this.parent.renderableMapById.set(value, this);
6495
+ }
6496
+ super.id = value;
6497
+ }
5966
6498
  get focusable() {
5967
6499
  return this._focusable;
5968
6500
  }
@@ -5973,7 +6505,7 @@ class Renderable extends BaseRenderable {
5973
6505
  return this._visible;
5974
6506
  }
5975
6507
  get primaryAxis() {
5976
- const dir = this.layoutNode.yogaNode.getFlexDirection();
6508
+ const dir = this.yogaNode.getFlexDirection();
5977
6509
  return dir === 2 || dir === 3 ? "row" : "column";
5978
6510
  }
5979
6511
  set visible(value) {
@@ -5981,7 +6513,7 @@ class Renderable extends BaseRenderable {
5981
6513
  return;
5982
6514
  const wasVisible = this._visible;
5983
6515
  this._visible = value;
5984
- this.layoutNode.yogaNode.setDisplay(value ? Display.Flex : Display.None);
6516
+ this.yogaNode.setDisplay(value ? Display.Flex : Display.None);
5985
6517
  if (this._live) {
5986
6518
  if (!wasVisible && value) {
5987
6519
  this.propagateLiveCount(1);
@@ -6018,7 +6550,14 @@ class Renderable extends BaseRenderable {
6018
6550
  this.handleKeyPress(key);
6019
6551
  }
6020
6552
  };
6021
- this.keyHandler.on("keypress", this.keypressHandler);
6553
+ this.pasteHandler = (text) => {
6554
+ this._pasteListener?.call(this, text);
6555
+ if (this.handlePaste) {
6556
+ this.handlePaste(text);
6557
+ }
6558
+ };
6559
+ this.ctx.keyInput.on("keypress", this.keypressHandler);
6560
+ this.ctx.keyInput.on("paste", this.pasteHandler);
6022
6561
  this.emit("focused" /* FOCUSED */);
6023
6562
  }
6024
6563
  blur() {
@@ -6027,9 +6566,13 @@ class Renderable extends BaseRenderable {
6027
6566
  this._focused = false;
6028
6567
  this.requestRender();
6029
6568
  if (this.keypressHandler) {
6030
- this.keyHandler.off("keypress", this.keypressHandler);
6569
+ this.ctx.keyInput.off("keypress", this.keypressHandler);
6031
6570
  this.keypressHandler = null;
6032
6571
  }
6572
+ if (this.pasteHandler) {
6573
+ this.ctx.keyInput.off("paste", this.pasteHandler);
6574
+ this.pasteHandler = null;
6575
+ }
6033
6576
  this.emit("blurred" /* BLURRED */);
6034
6577
  }
6035
6578
  get focused() {
@@ -6055,12 +6598,14 @@ class Renderable extends BaseRenderable {
6055
6598
  this.parent?.propagateLiveCount(delta);
6056
6599
  }
6057
6600
  findDescendantById(id) {
6058
- for (const child of this.renderableArray) {
6601
+ for (const child of this._childrenInLayoutOrder) {
6059
6602
  if (child.id === id)
6060
6603
  return child;
6061
- const found = child.findDescendantById(id);
6062
- if (found)
6063
- return found;
6604
+ if (isRenderable(child)) {
6605
+ const found = child.findDescendantById(id);
6606
+ if (found)
6607
+ return found;
6608
+ }
6064
6609
  }
6065
6610
  return;
6066
6611
  }
@@ -6146,7 +6691,7 @@ class Renderable extends BaseRenderable {
6146
6691
  set width(value) {
6147
6692
  if (isDimensionType(value)) {
6148
6693
  this._width = value;
6149
- this.layoutNode.setWidth(value);
6694
+ this.yogaNode.setWidth(value);
6150
6695
  this.requestRender();
6151
6696
  }
6152
6697
  }
@@ -6156,7 +6701,7 @@ class Renderable extends BaseRenderable {
6156
6701
  set height(value) {
6157
6702
  if (isDimensionType(value)) {
6158
6703
  this._height = value;
6159
- this.layoutNode.setHeight(value);
6704
+ this.yogaNode.setHeight(value);
6160
6705
  this.requestRender();
6161
6706
  }
6162
6707
  }
@@ -6174,17 +6719,17 @@ class Renderable extends BaseRenderable {
6174
6719
  }
6175
6720
  ensureZIndexSorted() {
6176
6721
  if (this.needsZIndexSort) {
6177
- this.renderableArray.sort((a, b) => a.zIndex > b.zIndex ? 1 : a.zIndex < b.zIndex ? -1 : 0);
6722
+ this._childrenInZIndexOrder.sort((a, b) => a.zIndex > b.zIndex ? 1 : a.zIndex < b.zIndex ? -1 : 0);
6178
6723
  this.needsZIndexSort = false;
6179
6724
  }
6180
6725
  }
6181
6726
  getChildrenSortedByPrimaryAxis() {
6182
- if (!this.childrenPrimarySortDirty && this.childrenSortedByPrimaryAxis.length === this.renderableArray.length) {
6727
+ if (!this.childrenPrimarySortDirty && this.childrenSortedByPrimaryAxis.length === this._childrenInLayoutOrder.length) {
6183
6728
  return this.childrenSortedByPrimaryAxis;
6184
6729
  }
6185
- const dir = this.layoutNode.yogaNode.getFlexDirection();
6730
+ const dir = this.yogaNode.getFlexDirection();
6186
6731
  const axis = dir === 2 || dir === 3 ? "x" : "y";
6187
- const sorted = [...this.renderableArray];
6732
+ const sorted = [...this._childrenInLayoutOrder];
6188
6733
  sorted.sort((a, b) => {
6189
6734
  const va = axis === "y" ? a.y : a.x;
6190
6735
  const vb = axis === "y" ? b.y : b.x;
@@ -6195,7 +6740,7 @@ class Renderable extends BaseRenderable {
6195
6740
  return this.childrenSortedByPrimaryAxis;
6196
6741
  }
6197
6742
  setupYogaProperties(options) {
6198
- const node = this.layoutNode.yogaNode;
6743
+ const node = this.yogaNode;
6199
6744
  if (isFlexBasisType(options.flexBasis)) {
6200
6745
  node.setFlexBasis(options.flexBasis);
6201
6746
  }
@@ -6213,8 +6758,7 @@ class Renderable extends BaseRenderable {
6213
6758
  if (options.flexShrink !== undefined) {
6214
6759
  node.setFlexShrink(options.flexShrink);
6215
6760
  } else {
6216
- const shrinkValue = options.flexGrow && options.flexGrow > 0 ? 1 : 0;
6217
- node.setFlexShrink(shrinkValue);
6761
+ node.setFlexShrink(1);
6218
6762
  }
6219
6763
  if (options.flexDirection !== undefined) {
6220
6764
  node.setFlexDirection(parseFlexDirection(options.flexDirection));
@@ -6233,11 +6777,11 @@ class Renderable extends BaseRenderable {
6233
6777
  }
6234
6778
  if (isDimensionType(options.width)) {
6235
6779
  this._width = options.width;
6236
- this.layoutNode.setWidth(options.width);
6780
+ this.yogaNode.setWidth(options.width);
6237
6781
  }
6238
6782
  if (isDimensionType(options.height)) {
6239
6783
  this._height = options.height;
6240
- this.layoutNode.setHeight(options.height);
6784
+ this.yogaNode.setHeight(options.height);
6241
6785
  }
6242
6786
  this._positionType = options.position === "absolute" ? "absolute" : "relative";
6243
6787
  if (this._positionType !== "relative") {
@@ -6266,7 +6810,7 @@ class Renderable extends BaseRenderable {
6266
6810
  this.setupMarginAndPadding(options);
6267
6811
  }
6268
6812
  setupMarginAndPadding(options) {
6269
- const node = this.layoutNode.yogaNode;
6813
+ const node = this.yogaNode;
6270
6814
  if (isMarginType(options.margin)) {
6271
6815
  node.setMargin(Edge.Top, options.margin);
6272
6816
  node.setMargin(Edge.Right, options.margin);
@@ -6308,7 +6852,7 @@ class Renderable extends BaseRenderable {
6308
6852
  if (!isPositionTypeType(positionType) || this._positionType === positionType)
6309
6853
  return;
6310
6854
  this._positionType = positionType;
6311
- this.layoutNode.yogaNode.setPositionType(parsePositionType(positionType));
6855
+ this.yogaNode.setPositionType(parsePositionType(positionType));
6312
6856
  this.requestRender();
6313
6857
  }
6314
6858
  get overflow() {
@@ -6318,7 +6862,7 @@ class Renderable extends BaseRenderable {
6318
6862
  if (!isOverflowType(overflow) || this._overflow === overflow)
6319
6863
  return;
6320
6864
  this._overflow = overflow;
6321
- this.layoutNode.yogaNode.setOverflow(parseOverflow(overflow));
6865
+ this.yogaNode.setOverflow(parseOverflow(overflow));
6322
6866
  this.requestRender();
6323
6867
  }
6324
6868
  setPosition(position) {
@@ -6326,7 +6870,7 @@ class Renderable extends BaseRenderable {
6326
6870
  this.updateYogaPosition(position);
6327
6871
  }
6328
6872
  updateYogaPosition(position) {
6329
- const node = this.layoutNode.yogaNode;
6873
+ const node = this.yogaNode;
6330
6874
  const { top, right, bottom, left } = position;
6331
6875
  if (isPositionType(top)) {
6332
6876
  if (top === "auto") {
@@ -6359,66 +6903,66 @@ class Renderable extends BaseRenderable {
6359
6903
  this.requestRender();
6360
6904
  }
6361
6905
  set flexGrow(grow) {
6362
- this.layoutNode.yogaNode.setFlexGrow(grow);
6906
+ this.yogaNode.setFlexGrow(grow);
6363
6907
  this.requestRender();
6364
6908
  }
6365
6909
  set flexShrink(shrink) {
6366
- this.layoutNode.yogaNode.setFlexShrink(shrink);
6910
+ this.yogaNode.setFlexShrink(shrink);
6367
6911
  this.requestRender();
6368
6912
  }
6369
6913
  set flexDirection(direction) {
6370
- this.layoutNode.yogaNode.setFlexDirection(parseFlexDirection(direction));
6914
+ this.yogaNode.setFlexDirection(parseFlexDirection(direction));
6371
6915
  this.requestRender();
6372
6916
  }
6373
6917
  set flexWrap(wrap) {
6374
- this.layoutNode.yogaNode.setFlexWrap(parseWrap(wrap));
6918
+ this.yogaNode.setFlexWrap(parseWrap(wrap));
6375
6919
  this.requestRender();
6376
6920
  }
6377
6921
  set alignItems(alignItems) {
6378
- this.layoutNode.yogaNode.setAlignItems(parseAlign(alignItems));
6922
+ this.yogaNode.setAlignItems(parseAlign(alignItems));
6379
6923
  this.requestRender();
6380
6924
  }
6381
6925
  set justifyContent(justifyContent) {
6382
- this.layoutNode.yogaNode.setJustifyContent(parseJustify(justifyContent));
6926
+ this.yogaNode.setJustifyContent(parseJustify(justifyContent));
6383
6927
  this.requestRender();
6384
6928
  }
6385
6929
  set alignSelf(alignSelf) {
6386
- this.layoutNode.yogaNode.setAlignSelf(parseAlign(alignSelf));
6930
+ this.yogaNode.setAlignSelf(parseAlign(alignSelf));
6387
6931
  this.requestRender();
6388
6932
  }
6389
6933
  set flexBasis(basis) {
6390
6934
  if (isFlexBasisType(basis)) {
6391
- this.layoutNode.yogaNode.setFlexBasis(basis);
6935
+ this.yogaNode.setFlexBasis(basis);
6392
6936
  this.requestRender();
6393
6937
  }
6394
6938
  }
6395
6939
  set minWidth(minWidth) {
6396
6940
  if (isSizeType(minWidth)) {
6397
- this.layoutNode.yogaNode.setMinWidth(minWidth);
6941
+ this.yogaNode.setMinWidth(minWidth);
6398
6942
  this.requestRender();
6399
6943
  }
6400
6944
  }
6401
6945
  set maxWidth(maxWidth) {
6402
6946
  if (isSizeType(maxWidth)) {
6403
- this.layoutNode.yogaNode.setMaxWidth(maxWidth);
6947
+ this.yogaNode.setMaxWidth(maxWidth);
6404
6948
  this.requestRender();
6405
6949
  }
6406
6950
  }
6407
6951
  set minHeight(minHeight) {
6408
6952
  if (isSizeType(minHeight)) {
6409
- this.layoutNode.yogaNode.setMinHeight(minHeight);
6953
+ this.yogaNode.setMinHeight(minHeight);
6410
6954
  this.requestRender();
6411
6955
  }
6412
6956
  }
6413
6957
  set maxHeight(maxHeight) {
6414
6958
  if (isSizeType(maxHeight)) {
6415
- this.layoutNode.yogaNode.setMaxHeight(maxHeight);
6959
+ this.yogaNode.setMaxHeight(maxHeight);
6416
6960
  this.requestRender();
6417
6961
  }
6418
6962
  }
6419
6963
  set margin(margin) {
6420
6964
  if (isMarginType(margin)) {
6421
- const node = this.layoutNode.yogaNode;
6965
+ const node = this.yogaNode;
6422
6966
  node.setMargin(Edge.Top, margin);
6423
6967
  node.setMargin(Edge.Right, margin);
6424
6968
  node.setMargin(Edge.Bottom, margin);
@@ -6428,31 +6972,31 @@ class Renderable extends BaseRenderable {
6428
6972
  }
6429
6973
  set marginTop(margin) {
6430
6974
  if (isMarginType(margin)) {
6431
- this.layoutNode.yogaNode.setMargin(Edge.Top, margin);
6975
+ this.yogaNode.setMargin(Edge.Top, margin);
6432
6976
  this.requestRender();
6433
6977
  }
6434
6978
  }
6435
6979
  set marginRight(margin) {
6436
6980
  if (isMarginType(margin)) {
6437
- this.layoutNode.yogaNode.setMargin(Edge.Right, margin);
6981
+ this.yogaNode.setMargin(Edge.Right, margin);
6438
6982
  this.requestRender();
6439
6983
  }
6440
6984
  }
6441
6985
  set marginBottom(margin) {
6442
6986
  if (isMarginType(margin)) {
6443
- this.layoutNode.yogaNode.setMargin(Edge.Bottom, margin);
6987
+ this.yogaNode.setMargin(Edge.Bottom, margin);
6444
6988
  this.requestRender();
6445
6989
  }
6446
6990
  }
6447
6991
  set marginLeft(margin) {
6448
6992
  if (isMarginType(margin)) {
6449
- this.layoutNode.yogaNode.setMargin(Edge.Left, margin);
6993
+ this.yogaNode.setMargin(Edge.Left, margin);
6450
6994
  this.requestRender();
6451
6995
  }
6452
6996
  }
6453
6997
  set padding(padding) {
6454
6998
  if (isPaddingType(padding)) {
6455
- const node = this.layoutNode.yogaNode;
6999
+ const node = this.yogaNode;
6456
7000
  node.setPadding(Edge.Top, padding);
6457
7001
  node.setPadding(Edge.Right, padding);
6458
7002
  node.setPadding(Edge.Bottom, padding);
@@ -6462,33 +7006,33 @@ class Renderable extends BaseRenderable {
6462
7006
  }
6463
7007
  set paddingTop(padding) {
6464
7008
  if (isPaddingType(padding)) {
6465
- this.layoutNode.yogaNode.setPadding(Edge.Top, padding);
7009
+ this.yogaNode.setPadding(Edge.Top, padding);
6466
7010
  this.requestRender();
6467
7011
  }
6468
7012
  }
6469
7013
  set paddingRight(padding) {
6470
7014
  if (isPaddingType(padding)) {
6471
- this.layoutNode.yogaNode.setPadding(Edge.Right, padding);
7015
+ this.yogaNode.setPadding(Edge.Right, padding);
6472
7016
  this.requestRender();
6473
7017
  }
6474
7018
  }
6475
7019
  set paddingBottom(padding) {
6476
7020
  if (isPaddingType(padding)) {
6477
- this.layoutNode.yogaNode.setPadding(Edge.Bottom, padding);
7021
+ this.yogaNode.setPadding(Edge.Bottom, padding);
6478
7022
  this.requestRender();
6479
7023
  }
6480
7024
  }
6481
7025
  set paddingLeft(padding) {
6482
7026
  if (isPaddingType(padding)) {
6483
- this.layoutNode.yogaNode.setPadding(Edge.Left, padding);
7027
+ this.yogaNode.setPadding(Edge.Left, padding);
6484
7028
  this.requestRender();
6485
7029
  }
6486
7030
  }
6487
7031
  getLayoutNode() {
6488
- return this.layoutNode;
7032
+ return this.yogaNode;
6489
7033
  }
6490
7034
  updateFromLayout() {
6491
- const layout = this.layoutNode.yogaNode.getComputedLayout();
7035
+ const layout = this.yogaNode.getComputedLayout();
6492
7036
  const oldX = this._x;
6493
7037
  const oldY = this._y;
6494
7038
  this._x = layout.left;
@@ -6564,7 +7108,7 @@ class Renderable extends BaseRenderable {
6564
7108
  }
6565
7109
  return -1;
6566
7110
  }
6567
- if (this.renderableMap.has(renderable.id)) {
7111
+ if (this.renderableMapById.has(renderable.id)) {
6568
7112
  console.warn(`A renderable with id ${renderable.id} already exists in ${this.id}, removing it`);
6569
7113
  this.remove(renderable.id);
6570
7114
  }
@@ -6572,16 +7116,22 @@ class Renderable extends BaseRenderable {
6572
7116
  const childLayoutNode = renderable.getLayoutNode();
6573
7117
  let insertedIndex;
6574
7118
  if (index !== undefined) {
6575
- this.renderableArray.splice(index, 0, renderable);
6576
- this._forceLayoutUpdateFor = this.renderableArray.slice(index);
6577
- insertedIndex = this.layoutNode.insertChild(childLayoutNode, index);
7119
+ insertedIndex = Math.max(0, Math.min(index, this._childrenInLayoutOrder.length));
7120
+ this._childrenInLayoutOrder.splice(index, 0, renderable);
7121
+ this._forceLayoutUpdateFor = this._childrenInLayoutOrder.slice(index);
7122
+ this.yogaNode.insertChild(childLayoutNode, insertedIndex);
6578
7123
  } else {
6579
- this.renderableArray.push(renderable);
6580
- insertedIndex = this.layoutNode.addChild(childLayoutNode);
7124
+ insertedIndex = this._childrenInLayoutOrder.length;
7125
+ this._childrenInLayoutOrder.push(renderable);
7126
+ this.yogaNode.insertChild(childLayoutNode, insertedIndex);
6581
7127
  }
6582
7128
  this.needsZIndexSort = true;
6583
7129
  this.childrenPrimarySortDirty = true;
6584
- this.renderableMap.set(renderable.id, renderable);
7130
+ this.renderableMapById.set(renderable.id, renderable);
7131
+ this._childrenInZIndexOrder.push(renderable);
7132
+ if (typeof renderable.onLifecyclePass === "function") {
7133
+ this._ctx.registerLifecyclePass(renderable);
7134
+ }
6585
7135
  this._newChildren.push(renderable);
6586
7136
  if (renderable._liveCount > 0) {
6587
7137
  this.propagateLiveCount(renderable._liveCount);
@@ -6590,6 +7140,9 @@ class Renderable extends BaseRenderable {
6590
7140
  return insertedIndex;
6591
7141
  }
6592
7142
  insertBefore(obj, anchor) {
7143
+ if (!anchor) {
7144
+ return this.add(obj);
7145
+ }
6593
7146
  if (!obj) {
6594
7147
  return -1;
6595
7148
  }
@@ -6597,60 +7150,91 @@ class Renderable extends BaseRenderable {
6597
7150
  if (!renderable) {
6598
7151
  return -1;
6599
7152
  }
6600
- if (!anchor) {
6601
- return this.add(renderable);
7153
+ if (renderable.isDestroyed) {
7154
+ if (true) {
7155
+ console.warn(`Renderable with id ${renderable.id} was already destroyed, skipping insertBefore`);
7156
+ }
7157
+ return -1;
6602
7158
  }
6603
7159
  if (!isRenderable(anchor)) {
6604
7160
  throw new Error("Anchor must be a Renderable");
6605
7161
  }
6606
- if (!this.renderableMap.has(anchor.id)) {
6607
- throw new Error("Anchor does not exist");
7162
+ if (anchor.isDestroyed) {
7163
+ if (true) {
7164
+ console.warn(`Anchor with id ${anchor.id} was already destroyed, skipping insertBefore`);
7165
+ }
7166
+ return -1;
6608
7167
  }
6609
- const anchorIndex = this.renderableArray.indexOf(anchor);
6610
- if (anchorIndex === -1) {
7168
+ if (!this.renderableMapById.has(anchor.id)) {
6611
7169
  throw new Error("Anchor does not exist");
6612
7170
  }
6613
- return this.add(renderable, anchorIndex);
7171
+ if (renderable.parent === this) {
7172
+ this.yogaNode.removeChild(renderable.getLayoutNode());
7173
+ this._childrenInLayoutOrder.splice(this._childrenInLayoutOrder.indexOf(renderable), 1);
7174
+ } else if (renderable.parent) {
7175
+ this.replaceParent(renderable);
7176
+ this.needsZIndexSort = true;
7177
+ this.renderableMapById.set(renderable.id, renderable);
7178
+ if (typeof renderable.onLifecyclePass === "function") {
7179
+ this._ctx.registerLifecyclePass(renderable);
7180
+ }
7181
+ if (renderable._liveCount > 0) {
7182
+ this.propagateLiveCount(renderable._liveCount);
7183
+ }
7184
+ }
7185
+ this._newChildren.push(renderable);
7186
+ this.childrenPrimarySortDirty = true;
7187
+ const anchorIndex = this._childrenInLayoutOrder.indexOf(anchor);
7188
+ const insertedIndex = Math.max(0, Math.min(anchorIndex, this._childrenInLayoutOrder.length));
7189
+ this._forceLayoutUpdateFor = this._childrenInLayoutOrder.slice(insertedIndex);
7190
+ this._childrenInLayoutOrder.splice(insertedIndex, 0, renderable);
7191
+ this.yogaNode.insertChild(renderable.getLayoutNode(), insertedIndex);
7192
+ return insertedIndex;
6614
7193
  }
6615
7194
  getRenderable(id) {
6616
- return this.renderableMap.get(id);
7195
+ return this.renderableMapById.get(id);
6617
7196
  }
6618
7197
  remove(id) {
6619
7198
  if (!id) {
6620
7199
  return;
6621
7200
  }
6622
- if (this.renderableMap.has(id)) {
6623
- const obj = this.renderableMap.get(id);
7201
+ if (this.renderableMapById.has(id)) {
7202
+ const obj = this.renderableMapById.get(id);
6624
7203
  if (obj) {
6625
7204
  if (obj._liveCount > 0) {
6626
7205
  this.propagateLiveCount(-obj._liveCount);
6627
7206
  }
6628
7207
  const childLayoutNode = obj.getLayoutNode();
6629
- this.layoutNode.removeChild(childLayoutNode);
7208
+ this.yogaNode.removeChild(childLayoutNode);
6630
7209
  this.requestRender();
6631
7210
  obj.onRemove();
6632
7211
  obj.parent = null;
7212
+ this._ctx.unregisterLifecyclePass(obj);
7213
+ this.renderableMapById.delete(id);
7214
+ const index = this._childrenInLayoutOrder.findIndex((obj2) => obj2.id === id);
7215
+ if (index !== -1) {
7216
+ this._childrenInLayoutOrder.splice(index, 1);
7217
+ }
7218
+ const zIndexIndex = this._childrenInZIndexOrder.findIndex((obj2) => obj2.id === id);
7219
+ if (zIndexIndex !== -1) {
7220
+ this._childrenInZIndexOrder.splice(zIndexIndex, 1);
7221
+ }
7222
+ this.childrenPrimarySortDirty = true;
6633
7223
  }
6634
- this.renderableMap.delete(id);
6635
- const index = this.renderableArray.findIndex((obj2) => obj2.id === id);
6636
- if (index !== -1) {
6637
- this.renderableArray.splice(index, 1);
6638
- }
6639
- this.childrenPrimarySortDirty = true;
6640
7224
  }
6641
7225
  }
6642
7226
  onRemove() {}
6643
7227
  getChildren() {
6644
- return [...this.renderableArray];
7228
+ return [...this._childrenInLayoutOrder];
6645
7229
  }
6646
7230
  getChildrenCount() {
6647
- return this.renderableArray.length;
7231
+ return this._childrenInLayoutOrder.length;
6648
7232
  }
6649
7233
  updateLayout(deltaTime, renderList = []) {
6650
7234
  if (!this.visible)
6651
7235
  return;
6652
- this.updateFromLayout();
6653
7236
  this.onUpdate(deltaTime);
7237
+ this.updateFromLayout();
6654
7238
  renderList.push({ action: "render", renderable: this });
6655
7239
  if (this._newChildren.length > 0) {
6656
7240
  for (const child of this._newChildren) {
@@ -6702,7 +7286,7 @@ class Renderable extends BaseRenderable {
6702
7286
  }
6703
7287
  }
6704
7288
  _getChildren() {
6705
- return this.renderableArray;
7289
+ return this._childrenInZIndexOrder;
6706
7290
  }
6707
7291
  onUpdate(deltaTime) {}
6708
7292
  getScissorRect() {
@@ -6729,19 +7313,21 @@ class Renderable extends BaseRenderable {
6729
7313
  this.frameBuffer.destroy();
6730
7314
  this.frameBuffer = null;
6731
7315
  }
6732
- for (const child of this.renderableArray) {
7316
+ for (const child of this._childrenInLayoutOrder) {
6733
7317
  this.remove(child.id);
6734
7318
  }
6735
- this.renderableArray = [];
6736
- this.renderableMap.clear();
7319
+ this._childrenInLayoutOrder = [];
7320
+ this.renderableMapById.clear();
6737
7321
  Renderable.renderablesByNumber.delete(this.num);
6738
7322
  this.blur();
6739
7323
  this.removeAllListeners();
6740
7324
  this.destroySelf();
6741
- this.layoutNode.destroy();
7325
+ try {
7326
+ this.yogaNode.free();
7327
+ } catch (e) {}
6742
7328
  }
6743
7329
  destroyRecursively() {
6744
- for (const child of this.renderableArray) {
7330
+ for (const child of this._childrenInLayoutOrder) {
6745
7331
  child.destroyRecursively();
6746
7332
  }
6747
7333
  this.destroy();
@@ -6816,6 +7402,12 @@ class Renderable extends BaseRenderable {
6816
7402
  else
6817
7403
  delete this._mouseListeners["scroll"];
6818
7404
  }
7405
+ set onPaste(handler) {
7406
+ this._pasteListener = handler;
7407
+ }
7408
+ get onPaste() {
7409
+ return this._pasteListener;
7410
+ }
6819
7411
  set onKeyDown(handler) {
6820
7412
  if (handler)
6821
7413
  this._keyListeners["down"] = handler;
@@ -6842,32 +7434,32 @@ class Renderable extends BaseRenderable {
6842
7434
  this.onMouseOver = options.onMouseOver;
6843
7435
  this.onMouseOut = options.onMouseOut;
6844
7436
  this.onMouseScroll = options.onMouseScroll;
7437
+ this.onPaste = options.onPaste;
6845
7438
  this.onKeyDown = options.onKeyDown;
6846
7439
  this.onSizeChange = options.onSizeChange;
6847
7440
  }
6848
7441
  }
6849
7442
 
6850
7443
  class RootRenderable extends Renderable {
6851
- yogaConfig;
6852
7444
  renderList = [];
6853
7445
  constructor(ctx) {
6854
7446
  super(ctx, { id: "__root__", zIndex: 0, visible: true, width: ctx.width, height: ctx.height, enableLayout: true });
6855
- this.yogaConfig = src_default.Config.create();
6856
- this.yogaConfig.setUseWebDefaults(false);
6857
- this.yogaConfig.setPointScaleFactor(1);
6858
- if (this.layoutNode) {
6859
- this.layoutNode.destroy();
6860
- }
6861
- this.layoutNode = createTrackedNode({}, this.yogaConfig);
6862
- this.layoutNode.setWidth(ctx.width);
6863
- this.layoutNode.setHeight(ctx.height);
6864
- this.layoutNode.yogaNode.setFlexDirection(FlexDirection.Column);
7447
+ if (this.yogaNode) {
7448
+ this.yogaNode.free();
7449
+ }
7450
+ this.yogaNode = src_default.Node.create(yogaConfig);
7451
+ this.yogaNode.setWidth(ctx.width);
7452
+ this.yogaNode.setHeight(ctx.height);
7453
+ this.yogaNode.setFlexDirection(FlexDirection.Column);
6865
7454
  this.calculateLayout();
6866
7455
  }
6867
7456
  render(buffer, deltaTime) {
6868
7457
  if (!this.visible)
6869
7458
  return;
6870
- if (this.layoutNode.yogaNode.isDirty()) {
7459
+ for (const renderable of this._ctx.getLifecyclePasses()) {
7460
+ renderable.onLifecyclePass?.call(renderable);
7461
+ }
7462
+ if (this.yogaNode.isDirty()) {
6871
7463
  this.calculateLayout();
6872
7464
  }
6873
7465
  this.renderList.length = 0;
@@ -6897,7 +7489,7 @@ class RootRenderable extends Renderable {
6897
7489
  }
6898
7490
  }
6899
7491
  calculateLayout() {
6900
- this.layoutNode.yogaNode.calculateLayout(this.width, this.height, Direction.LTR);
7492
+ this.yogaNode.calculateLayout(this.width, this.height, Direction.LTR);
6901
7493
  this.emit("layout-changed" /* LAYOUT_CHANGED */);
6902
7494
  }
6903
7495
  resize(width, height) {
@@ -6905,15 +7497,6 @@ class RootRenderable extends Renderable {
6905
7497
  this.height = height;
6906
7498
  this.emit("resized" /* RESIZED */, { width, height });
6907
7499
  }
6908
- onUpdate(deltaTime) {}
6909
- destroySelf() {
6910
- if (this.layoutNode) {
6911
- this.layoutNode.destroy();
6912
- }
6913
- try {
6914
- this.yogaConfig.free();
6915
- } catch (error) {}
6916
- }
6917
7500
  }
6918
7501
 
6919
7502
  // src/renderables/composition/vnode.ts
@@ -7083,7 +7666,7 @@ function delegate(mapping, vnode) {
7083
7666
  }
7084
7667
 
7085
7668
  // src/console.ts
7086
- import { EventEmitter as EventEmitter5 } from "events";
7669
+ import { EventEmitter as EventEmitter4 } from "events";
7087
7670
  import { Console } from "console";
7088
7671
  import fs from "fs";
7089
7672
  import path from "path";
@@ -7091,9 +7674,9 @@ import util2 from "util";
7091
7674
 
7092
7675
  // src/lib/output.capture.ts
7093
7676
  import { Writable } from "stream";
7094
- import { EventEmitter as EventEmitter4 } from "events";
7677
+ import { EventEmitter as EventEmitter3 } from "events";
7095
7678
 
7096
- class Capture extends EventEmitter4 {
7679
+ class Capture extends EventEmitter3 {
7097
7680
  output = [];
7098
7681
  constructor() {
7099
7682
  super();
@@ -7156,8 +7739,20 @@ function getCallerInfo() {
7156
7739
  return { functionName, fullPath, fileName, lineNumber, columnNumber };
7157
7740
  }
7158
7741
  var capture = singleton("ConsoleCapture", () => new Capture);
7742
+ registerEnvVar({
7743
+ name: "OTUI_USE_CONSOLE",
7744
+ description: "Whether to use the console. Will not capture console output if set to false.",
7745
+ type: "boolean",
7746
+ default: true
7747
+ });
7748
+ registerEnvVar({
7749
+ name: "SHOW_CONSOLE",
7750
+ description: "Show the console at startup if set to true.",
7751
+ type: "boolean",
7752
+ default: false
7753
+ });
7159
7754
 
7160
- class TerminalConsoleCache extends EventEmitter5 {
7755
+ class TerminalConsoleCache extends EventEmitter4 {
7161
7756
  _cachedLogs = [];
7162
7757
  MAX_CACHE_SIZE = 1000;
7163
7758
  _collectCallerInfo = false;
@@ -7173,7 +7768,7 @@ class TerminalConsoleCache extends EventEmitter5 {
7173
7768
  this.overrideConsoleMethods();
7174
7769
  }
7175
7770
  setupConsoleCapture() {
7176
- if (process.env.OTUI_USE_CONSOLE === "false")
7771
+ if (!env.OTUI_USE_CONSOLE)
7177
7772
  return;
7178
7773
  const mockStdout = new CapturedWritableStream("stdout", capture);
7179
7774
  const mockStderr = new CapturedWritableStream("stderr", capture);
@@ -7278,7 +7873,7 @@ var DEFAULT_CONSOLE_OPTIONS = {
7278
7873
  };
7279
7874
  var INDENT_WIDTH = 2;
7280
7875
 
7281
- class TerminalConsole extends EventEmitter5 {
7876
+ class TerminalConsole extends EventEmitter4 {
7282
7877
  isVisible = false;
7283
7878
  isFocused = false;
7284
7879
  renderer;
@@ -7338,7 +7933,7 @@ class TerminalConsole extends EventEmitter5 {
7338
7933
  terminalConsoleCache.on("entry", (logEntry) => {
7339
7934
  this._handleNewLog(logEntry);
7340
7935
  });
7341
- if (process.env.SHOW_CONSOLE === "true") {
7936
+ if (env.SHOW_CONSOLE) {
7342
7937
  this.show();
7343
7938
  }
7344
7939
  }
@@ -7737,39 +8332,8 @@ class TerminalConsole extends EventEmitter5 {
7737
8332
  }
7738
8333
  }
7739
8334
 
7740
- // src/ansi.ts
7741
- var ANSI = {
7742
- switchToAlternateScreen: "\x1B[?1049h",
7743
- switchToMainScreen: "\x1B[?1049l",
7744
- reset: "\x1B[0m",
7745
- hideCursor: "\x1B[?25l",
7746
- showCursor: "\x1B[?25h",
7747
- resetCursorColor: "\x1B]12;default\x07",
7748
- saveCursorState: "\x1B[s",
7749
- restoreCursorState: "\x1B[u",
7750
- queryPixelSize: "\x1B[14t",
7751
- scrollDown: (lines) => `\x1B[${lines}T`,
7752
- scrollUp: (lines) => `\x1B[${lines}S`,
7753
- moveCursor: (row, col) => `\x1B[${row};${col}H`,
7754
- moveCursorAndClear: (row, col) => `\x1B[${row};${col}H\x1B[J`,
7755
- clearFromCursor: "\x1B[J",
7756
- setRgbBackground: (r, g, b) => `\x1B[48;2;${r};${g};${b}m`,
7757
- resetBackground: "\x1B[49m",
7758
- enableMouseTracking: "\x1B[?1000h",
7759
- disableMouseTracking: "\x1B[?1000l",
7760
- enableButtonEventTracking: "\x1B[?1002h",
7761
- disableButtonEventTracking: "\x1B[?1002l",
7762
- enableAnyEventTracking: "\x1B[?1003h",
7763
- disableAnyEventTracking: "\x1B[?1003l",
7764
- enableSGRMouseMode: "\x1B[?1006h",
7765
- disableSGRMouseMode: "\x1B[?1006l",
7766
- makeRoomForRenderer: (height) => `
7767
- `.repeat(height) + `\x1B[${height}A`,
7768
- clearRendererSpace: (height) => `\x1B[${height}A\x1B[1G\x1B[J`
7769
- };
7770
-
7771
8335
  // src/renderer.ts
7772
- import { EventEmitter as EventEmitter6 } from "events";
8336
+ import { EventEmitter as EventEmitter5 } from "events";
7773
8337
 
7774
8338
  // src/lib/objects-in-viewport.ts
7775
8339
  function getObjectsInViewport(viewport, objects, direction = "column", padding = 10, minTriggerSize = 16) {
@@ -7847,6 +8411,19 @@ function getObjectsInViewport(viewport, objects, direction = "column", padding =
7847
8411
  }
7848
8412
 
7849
8413
  // src/renderer.ts
8414
+ registerEnvVar({
8415
+ name: "OTUI_DUMP_CAPTURES",
8416
+ description: "Dump captured output when the renderer exits.",
8417
+ type: "boolean",
8418
+ default: false
8419
+ });
8420
+ registerEnvVar({
8421
+ name: "OTUI_NO_NATIVE_RENDER",
8422
+ description: "Disable native rendering. This will not actually output ansi and is useful for debugging.",
8423
+ type: "boolean",
8424
+ default: false
8425
+ });
8426
+
7850
8427
  class MouseEvent {
7851
8428
  type;
7852
8429
  button;
@@ -7898,6 +8475,20 @@ singleton("ProcessExitSignals", () => {
7898
8475
  });
7899
8476
  });
7900
8477
  });
8478
+ var rendererTracker = singleton("RendererTracker", () => {
8479
+ const renderers = new Set;
8480
+ return {
8481
+ addRenderer: (renderer) => {
8482
+ renderers.add(renderer);
8483
+ },
8484
+ removeRenderer: (renderer) => {
8485
+ renderers.delete(renderer);
8486
+ if (renderers.size === 0) {
8487
+ process.stdin.pause();
8488
+ }
8489
+ }
8490
+ };
8491
+ });
7901
8492
  async function createCliRenderer(config = {}) {
7902
8493
  if (process.argv.includes("--delay-start")) {
7903
8494
  await new Promise((resolve) => setTimeout(resolve, 5000));
@@ -7927,7 +8518,7 @@ var CliRenderEvents;
7927
8518
  ((CliRenderEvents2) => {
7928
8519
  CliRenderEvents2["DEBUG_OVERLAY_TOGGLE"] = "debugOverlay:toggle";
7929
8520
  })(CliRenderEvents ||= {});
7930
- class CliRenderer extends EventEmitter6 {
8521
+ class CliRenderer extends EventEmitter5 {
7931
8522
  static animationFrameId = 0;
7932
8523
  lib;
7933
8524
  rendererPtr;
@@ -7939,6 +8530,7 @@ class CliRenderer extends EventEmitter6 {
7939
8530
  currentRenderBuffer;
7940
8531
  _isRunning = false;
7941
8532
  targetFps = 30;
8533
+ automaticMemorySnapshot = false;
7942
8534
  memorySnapshotInterval;
7943
8535
  memorySnapshotTimer = null;
7944
8536
  lastMemorySnapshot = {
@@ -7981,6 +8573,7 @@ class CliRenderer extends EventEmitter6 {
7981
8573
  };
7982
8574
  _console;
7983
8575
  _resolution = null;
8576
+ _keyHandler;
7984
8577
  animationRequest = new Map;
7985
8578
  resizeTimeoutId = null;
7986
8579
  resizeDebounceDelay = 100;
@@ -8005,12 +8598,74 @@ class CliRenderer extends EventEmitter6 {
8005
8598
  };
8006
8599
  _useConsole = true;
8007
8600
  mouseParser = new MouseParser;
8008
- sigwinchHandler = null;
8601
+ sigwinchHandler = (() => {
8602
+ const width = this.stdout.columns || 80;
8603
+ const height = this.stdout.rows || 24;
8604
+ this.handleResize(width, height);
8605
+ }).bind(this);
8009
8606
  _capabilities = null;
8010
8607
  _latestPointer = { x: 0, y: 0 };
8011
8608
  _currentFocusedRenderable = null;
8609
+ lifecyclePasses = new Set;
8610
+ handleError = ((error) => {
8611
+ this.stop();
8612
+ this.destroy();
8613
+ new Promise((resolve) => {
8614
+ setTimeout(() => {
8615
+ resolve(true);
8616
+ }, 100);
8617
+ }).then(() => {
8618
+ this.realStdoutWrite.call(this.stdout, `
8619
+ `.repeat(this._terminalHeight));
8620
+ this.realStdoutWrite.call(this.stdout, `
8621
+ === FATAL ERROR OCCURRED ===
8622
+ `);
8623
+ this.dumpOutputCache();
8624
+ this.realStdoutWrite.call(this.stdout, `
8625
+ Error details:
8626
+ `);
8627
+ this.realStdoutWrite.call(this.stdout, error.message || "unknown error");
8628
+ this.realStdoutWrite.call(this.stdout, `
8629
+ `);
8630
+ this.realStdoutWrite.call(this.stdout, error.stack || error.toString());
8631
+ this.realStdoutWrite.call(this.stdout, `
8632
+ `);
8633
+ process.exit(1);
8634
+ });
8635
+ }).bind(this);
8636
+ dumpOutputCache(optionalMessage = "") {
8637
+ const cachedLogs = this.console.getCachedLogs();
8638
+ const capturedOutput = capture.claimOutput();
8639
+ if (capturedOutput.length > 0 || cachedLogs.length > 0) {
8640
+ this.realStdoutWrite.call(this.stdout, optionalMessage);
8641
+ }
8642
+ if (cachedLogs.length > 0) {
8643
+ this.realStdoutWrite.call(this.stdout, `Console cache:
8644
+ `);
8645
+ this.realStdoutWrite.call(this.stdout, cachedLogs);
8646
+ }
8647
+ if (capturedOutput.length > 0) {
8648
+ this.realStdoutWrite.call(this.stdout, `
8649
+ Captured output:
8650
+ `);
8651
+ this.realStdoutWrite.call(this.stdout, capturedOutput + `
8652
+ `);
8653
+ }
8654
+ this.realStdoutWrite.call(this.stdout, ANSI.reset);
8655
+ }
8656
+ exitHandler = (() => {
8657
+ this.destroy();
8658
+ if (env.OTUI_DUMP_CAPTURES) {
8659
+ this.dumpOutputCache(`=== CAPTURED OUTPUT ===
8660
+ `);
8661
+ }
8662
+ }).bind(this);
8663
+ warningHandler = ((warning) => {
8664
+ console.warn(JSON.stringify(warning.message, null, 2));
8665
+ }).bind(this);
8012
8666
  constructor(lib, rendererPtr, stdin, stdout, width, height, config = {}) {
8013
8667
  super();
8668
+ rendererTracker.addRenderer(this);
8014
8669
  this.stdin = stdin;
8015
8670
  this.stdout = stdout;
8016
8671
  this.realStdoutWrite = stdout.write;
@@ -8031,7 +8686,7 @@ class CliRenderer extends EventEmitter6 {
8031
8686
  this.exitOnCtrlC = config.exitOnCtrlC === undefined ? true : config.exitOnCtrlC;
8032
8687
  this.resizeDebounceDelay = config.debounceDelay || 100;
8033
8688
  this.targetFps = config.targetFps || 30;
8034
- this.memorySnapshotInterval = config.memorySnapshotInterval || 5000;
8689
+ this.memorySnapshotInterval = config.memorySnapshotInterval ?? 0;
8035
8690
  this.gatherStats = config.gatherStats || false;
8036
8691
  this.maxStatSamples = config.maxStatSamples || 300;
8037
8692
  this.enableMouseMovement = config.enableMouseMovement || true;
@@ -8041,63 +8696,18 @@ class CliRenderer extends EventEmitter6 {
8041
8696
  this.currentRenderBuffer = this.lib.getCurrentBuffer(this.rendererPtr);
8042
8697
  this.postProcessFns = config.postProcessFns || [];
8043
8698
  this.root = new RootRenderable(this);
8044
- this.takeMemorySnapshot();
8045
8699
  if (this.memorySnapshotInterval > 0) {
8046
8700
  this.startMemorySnapshotTimer();
8047
8701
  }
8048
8702
  this.stdout.write = this.interceptStdoutWrite.bind(this);
8049
- this.sigwinchHandler = () => {
8050
- const width2 = this.stdout.columns || 80;
8051
- const height2 = this.stdout.rows || 24;
8052
- this.handleResize(width2, height2);
8053
- };
8054
8703
  process.on("SIGWINCH", this.sigwinchHandler);
8055
- const handleError = (error) => {
8056
- this.stop();
8057
- this.destroy();
8058
- new Promise((resolve) => {
8059
- setTimeout(() => {
8060
- resolve(true);
8061
- }, 100);
8062
- }).then(() => {
8063
- this.realStdoutWrite.call(this.stdout, `
8064
- `.repeat(this._terminalHeight));
8065
- this.realStdoutWrite.call(this.stdout, `
8066
- === FATAL ERROR OCCURRED ===
8067
- `);
8068
- this.realStdoutWrite.call(this.stdout, `Console cache:
8069
- `);
8070
- this.realStdoutWrite.call(this.stdout, this.console.getCachedLogs());
8071
- this.realStdoutWrite.call(this.stdout, `
8072
- Captured output:
8073
- `);
8074
- const capturedOutput = capture.claimOutput();
8075
- if (capturedOutput) {
8076
- this.realStdoutWrite.call(this.stdout, capturedOutput + `
8077
- `);
8078
- }
8079
- this.realStdoutWrite.call(this.stdout, `
8080
- Error details:
8081
- `);
8082
- this.realStdoutWrite.call(this.stdout, error.message || "unknown error");
8083
- this.realStdoutWrite.call(this.stdout, `
8084
- `);
8085
- this.realStdoutWrite.call(this.stdout, error.stack || error.toString());
8086
- this.realStdoutWrite.call(this.stdout, `
8087
- `);
8088
- process.exit(1);
8089
- });
8090
- };
8091
- process.on("warning", (warning) => {
8092
- console.warn(JSON.stringify(warning.message, null, 2));
8093
- });
8094
- process.on("uncaughtException", handleError);
8095
- process.on("unhandledRejection", handleError);
8096
- process.on("exit", () => {
8097
- this.destroy();
8098
- });
8704
+ process.on("warning", this.warningHandler);
8705
+ process.on("uncaughtException", this.handleError);
8706
+ process.on("unhandledRejection", this.handleError);
8707
+ process.on("exit", this.exitHandler);
8099
8708
  this._console = new TerminalConsole(this, config.consoleOptions);
8100
8709
  this.useConsole = config.useConsole ?? true;
8710
+ this._keyHandler = new KeyHandler(this.stdin, config.useKittyKeyboard ?? false);
8101
8711
  global.requestAnimationFrame = (callback) => {
8102
8712
  const id = CliRenderer.animationFrameId++;
8103
8713
  this.animationRequest.set(id, callback);
@@ -8112,13 +8722,23 @@ Error details:
8112
8722
  global.window = {};
8113
8723
  }
8114
8724
  global.window.requestAnimationFrame = requestAnimationFrame;
8115
- if (process.env.OTUI_NO_NATIVE_RENDER === "true") {
8725
+ if (env.OTUI_NO_NATIVE_RENDER) {
8116
8726
  this.renderNative = () => {
8117
8727
  if (this._splitHeight > 0) {
8118
8728
  this.flushStdoutCache(this._splitHeight);
8119
8729
  }
8120
8730
  };
8121
8731
  }
8732
+ this.setupInput();
8733
+ }
8734
+ registerLifecyclePass(renderable) {
8735
+ this.lifecyclePasses.add(renderable);
8736
+ }
8737
+ unregisterLifecyclePass(renderable) {
8738
+ this.lifecyclePasses.delete(renderable);
8739
+ }
8740
+ getLifecyclePasses() {
8741
+ return this.lifecyclePasses;
8122
8742
  }
8123
8743
  get currentFocusedRenderable() {
8124
8744
  return this._currentFocusedRenderable;
@@ -8172,6 +8792,9 @@ Error details:
8172
8792
  get console() {
8173
8793
  return this._console;
8174
8794
  }
8795
+ get keyInput() {
8796
+ return this._keyHandler;
8797
+ }
8175
8798
  get terminalWidth() {
8176
8799
  return this._terminalWidth;
8177
8800
  }
@@ -8260,7 +8883,6 @@ Error details:
8260
8883
  return true;
8261
8884
  };
8262
8885
  disableStdoutInterception() {
8263
- this.flushStdoutCache(this._splitHeight);
8264
8886
  this.stdout.write = this.realStdoutWrite;
8265
8887
  }
8266
8888
  flushStdoutCache(space, force = false) {
@@ -8271,10 +8893,13 @@ Error details:
8271
8893
  const flush = ANSI.moveCursorAndClear(rendererStartLine, 1);
8272
8894
  const outputLine = this._terminalHeight - this._splitHeight;
8273
8895
  const move = ANSI.moveCursor(outputLine, 1);
8274
- const backgroundColor = this.backgroundColor.toInts();
8275
- const newlines = " ".repeat(this.width) + `
8896
+ let clear = "";
8897
+ if (space > 0) {
8898
+ const backgroundColor = this.backgroundColor.toInts();
8899
+ const newlines = " ".repeat(this.width) + `
8276
8900
  `.repeat(space);
8277
- const clear = ANSI.setRgbBackground(backgroundColor[0], backgroundColor[1], backgroundColor[2]) + newlines + ANSI.resetBackground;
8901
+ clear = ANSI.setRgbBackground(backgroundColor[0], backgroundColor[1], backgroundColor[2]) + newlines + ANSI.resetBackground;
8902
+ }
8278
8903
  this.writeOut(flush + move + output + clear);
8279
8904
  return true;
8280
8905
  }
@@ -8300,11 +8925,6 @@ Error details:
8300
8925
  if (this._terminalIsSetup)
8301
8926
  return;
8302
8927
  this._terminalIsSetup = true;
8303
- if (this.stdin.setRawMode) {
8304
- this.stdin.setRawMode(true);
8305
- }
8306
- this.stdin.resume();
8307
- this.stdin.setEncoding("utf8");
8308
8928
  await new Promise((resolve) => {
8309
8929
  const timeout = setTimeout(() => {
8310
8930
  this.stdin.off("data", capListener);
@@ -8323,32 +8943,40 @@ Error details:
8323
8943
  if (this._useMouse) {
8324
8944
  this.enableMouse();
8325
8945
  }
8326
- this.stdin.on("data", (data) => {
8327
- const str = data.toString();
8328
- if (this.waitingForPixelResolution && /\x1b\[4;\d+;\d+t/.test(str)) {
8329
- const match = str.match(/\x1b\[4;(\d+);(\d+)t/);
8330
- if (match) {
8331
- const resolution = {
8332
- width: parseInt(match[2]),
8333
- height: parseInt(match[1])
8334
- };
8335
- this._resolution = resolution;
8336
- this.waitingForPixelResolution = false;
8337
- return;
8338
- }
8339
- }
8340
- if (this.exitOnCtrlC && str === "\x03") {
8341
- process.nextTick(() => {
8342
- process.exit();
8343
- });
8344
- return;
8345
- }
8346
- if (this._useMouse && this.handleMouseData(data)) {
8946
+ this.queryPixelResolution();
8947
+ }
8948
+ stdinListener = ((data) => {
8949
+ const str = data.toString();
8950
+ if (this.waitingForPixelResolution && /\x1b\[4;\d+;\d+t/.test(str)) {
8951
+ const match = str.match(/\x1b\[4;(\d+);(\d+)t/);
8952
+ if (match) {
8953
+ const resolution = {
8954
+ width: parseInt(match[2]),
8955
+ height: parseInt(match[1])
8956
+ };
8957
+ this._resolution = resolution;
8958
+ this.waitingForPixelResolution = false;
8347
8959
  return;
8348
8960
  }
8349
- this.emit("key", data);
8350
- });
8351
- this.queryPixelResolution();
8961
+ }
8962
+ if (this.exitOnCtrlC && str === "\x03") {
8963
+ process.nextTick(() => {
8964
+ this.destroy();
8965
+ });
8966
+ return;
8967
+ }
8968
+ if (this._useMouse && this.handleMouseData(data)) {
8969
+ return;
8970
+ }
8971
+ this.emit("key", data);
8972
+ }).bind(this);
8973
+ setupInput() {
8974
+ if (this.stdin.setRawMode) {
8975
+ this.stdin.setRawMode(true);
8976
+ }
8977
+ this.stdin.resume();
8978
+ this.stdin.setEncoding("utf8");
8979
+ this.stdin.on("data", this.stdinListener);
8352
8980
  }
8353
8981
  handleMouseData(data) {
8354
8982
  const mouseEvent = this.mouseParser.parseMouseEvent(data);
@@ -8375,7 +9003,7 @@ Error details:
8375
9003
  this.lastOverRenderableNum = maybeRenderableId;
8376
9004
  const maybeRenderable = Renderable.renderablesByNumber.get(maybeRenderableId);
8377
9005
  if (mouseEvent.type === "down" && mouseEvent.button === 0 /* LEFT */ && !this.currentSelection?.isSelecting && !mouseEvent.modifiers.ctrl) {
8378
- if (maybeRenderable && maybeRenderable.selectable && maybeRenderable.shouldStartSelection(mouseEvent.x, mouseEvent.y)) {
9006
+ if (maybeRenderable && maybeRenderable.selectable && !maybeRenderable.isDestroyed && maybeRenderable.shouldStartSelection(mouseEvent.x, mouseEvent.y)) {
8379
9007
  this.startSelection(maybeRenderable, mouseEvent.x, mouseEvent.y);
8380
9008
  const event2 = new MouseEvent(maybeRenderable, mouseEvent);
8381
9009
  maybeRenderable.processMouseEvent(event2);
@@ -8463,6 +9091,8 @@ Error details:
8463
9091
  return false;
8464
9092
  }
8465
9093
  takeMemorySnapshot() {
9094
+ if (this.isDestroyed)
9095
+ return;
8466
9096
  const memoryUsage = process.memoryUsage();
8467
9097
  this.lastMemorySnapshot = {
8468
9098
  heapUsed: memoryUsage.heapUsed,
@@ -8473,13 +9103,17 @@ Error details:
8473
9103
  this.emit("memory:snapshot", this.lastMemorySnapshot);
8474
9104
  }
8475
9105
  startMemorySnapshotTimer() {
8476
- if (this.memorySnapshotTimer) {
8477
- clearInterval(this.memorySnapshotTimer);
8478
- }
9106
+ this.stopMemorySnapshotTimer();
8479
9107
  this.memorySnapshotTimer = setInterval(() => {
8480
9108
  this.takeMemorySnapshot();
8481
9109
  }, this.memorySnapshotInterval);
8482
9110
  }
9111
+ stopMemorySnapshotTimer() {
9112
+ if (this.memorySnapshotTimer) {
9113
+ clearInterval(this.memorySnapshotTimer);
9114
+ this.memorySnapshotTimer = null;
9115
+ }
9116
+ }
8483
9117
  setMemorySnapshotInterval(interval) {
8484
9118
  this.memorySnapshotInterval = interval;
8485
9119
  if (this._isRunning && interval > 0) {
@@ -8507,7 +9141,7 @@ Error details:
8507
9141
  }
8508
9142
  queryPixelResolution() {
8509
9143
  this.waitingForPixelResolution = true;
8510
- this.writeOut(ANSI.queryPixelSize);
9144
+ this.lib.queryPixelResolution(this.rendererPtr);
8511
9145
  }
8512
9146
  processResize(width, height) {
8513
9147
  if (width === this._terminalWidth && height === this._terminalHeight)
@@ -8549,6 +9183,16 @@ Error details:
8549
9183
  this.requestRender();
8550
9184
  }
8551
9185
  toggleDebugOverlay() {
9186
+ const willBeEnabled = !this.debugOverlay.enabled;
9187
+ if (willBeEnabled && !this.memorySnapshotInterval) {
9188
+ this.memorySnapshotInterval = 3000;
9189
+ this.startMemorySnapshotTimer();
9190
+ this.automaticMemorySnapshot = true;
9191
+ } else if (!willBeEnabled && this.automaticMemorySnapshot) {
9192
+ this.stopMemorySnapshotTimer();
9193
+ this.memorySnapshotInterval = 0;
9194
+ this.automaticMemorySnapshot = false;
9195
+ }
8552
9196
  this.debugOverlay.enabled = !this.debugOverlay.enabled;
8553
9197
  this.lib.setDebugOverlay(this.rendererPtr, this.debugOverlay.enabled, this.debugOverlay.corner);
8554
9198
  this.emit("debugOverlay:toggle" /* DEBUG_OVERLAY_TOGGLE */, this.debugOverlay.enabled);
@@ -8560,9 +9204,6 @@ Error details:
8560
9204
  this.lib.setDebugOverlay(this.rendererPtr, this.debugOverlay.enabled, this.debugOverlay.corner);
8561
9205
  this.requestRender();
8562
9206
  }
8563
- clearTerminal() {
8564
- this.lib.clearTerminal(this.rendererPtr);
8565
- }
8566
9207
  setTerminalTitle(title) {
8567
9208
  this.lib.setTerminalTitle(this.rendererPtr, title);
8568
9209
  }
@@ -8675,19 +9316,37 @@ Error details:
8675
9316
  }
8676
9317
  }
8677
9318
  destroy() {
8678
- this.stdin.setRawMode(false);
9319
+ process.removeListener("SIGWINCH", this.sigwinchHandler);
9320
+ process.removeListener("uncaughtException", this.handleError);
9321
+ process.removeListener("unhandledRejection", this.handleError);
9322
+ process.removeListener("warning", this.warningHandler);
9323
+ capture.removeListener("write", this.captureCallback);
9324
+ if (this.memorySnapshotTimer) {
9325
+ clearInterval(this.memorySnapshotTimer);
9326
+ }
8679
9327
  if (this.isDestroyed)
8680
9328
  return;
8681
9329
  this.isDestroyed = true;
9330
+ if (this.renderTimeout) {
9331
+ clearTimeout(this.renderTimeout);
9332
+ this.renderTimeout = null;
9333
+ }
9334
+ this._isRunning = false;
8682
9335
  this.waitingForPixelResolution = false;
8683
9336
  this.capturedRenderable = undefined;
8684
- if (this.sigwinchHandler) {
8685
- process.removeListener("SIGWINCH", this.sigwinchHandler);
8686
- this.sigwinchHandler = null;
8687
- }
9337
+ this.root.destroyRecursively();
9338
+ this._keyHandler.destroy();
8688
9339
  this._console.deactivate();
8689
9340
  this.disableStdoutInterception();
8690
- this.lib.destroyRenderer(this.rendererPtr, this._useAlternateScreen, this._splitHeight);
9341
+ if (this._splitHeight > 0) {
9342
+ this.flushStdoutCache(this._splitHeight, true);
9343
+ }
9344
+ if (this.stdin.setRawMode) {
9345
+ this.stdin.setRawMode(false);
9346
+ }
9347
+ this.stdin.removeListener("data", this.stdinListener);
9348
+ this.lib.destroyRenderer(this.rendererPtr);
9349
+ rendererTracker.removeRenderer(this);
8691
9350
  }
8692
9351
  startRenderLoop() {
8693
9352
  if (!this._isRunning)
@@ -8744,7 +9403,9 @@ Error details:
8744
9403
  postProcessFn(this.nextRenderBuffer, deltaTime);
8745
9404
  }
8746
9405
  this._console.renderToBuffer(this.nextRenderBuffer);
8747
- this.renderNative();
9406
+ if (!this.isDestroyed) {
9407
+ this.renderNative();
9408
+ }
8748
9409
  const overallFrameTime = performance.now() - overallStart;
8749
9410
  this.lib.updateStats(this.rendererPtr, overallFrameTime, this.renderStats.fps, this.renderStats.frameCallbackTime);
8750
9411
  if (this.gatherStats) {
@@ -8820,7 +9481,7 @@ Error details:
8820
9481
  clearSelection() {
8821
9482
  if (this.currentSelection) {
8822
9483
  for (const renderable of this.currentSelection.touchedRenderables) {
8823
- if (renderable.selectable) {
9484
+ if (renderable.selectable && !renderable.isDestroyed) {
8824
9485
  renderable.onSelectionChanged(null);
8825
9486
  }
8826
9487
  }
@@ -8911,7 +9572,7 @@ Error details:
8911
9572
  }
8912
9573
  }
8913
9574
 
8914
- export { __toESM, __commonJS, __export, __require, Edge, Gutter, MeasureMode, BorderChars, getBorderFromSides, getBorderSides, borderCharsToArray, BorderCharArrays, TrackedNode, createTrackedNode, nonAlphanumericKeys, parseKeypress, KeyHandler, getKeyHandler, RGBA, hexToRgb, rgbToHex, hsvToRgb, parseColor, fonts, measureText, getCharacterPositions, coordinateToCharacterIndex, renderFontToFrameBuffer, TextAttributes, DebugOverlayCorner, createTextAttributes, isStyledText, StyledText, stringToStyledText, black, red, green, yellow, blue, magenta, cyan, white, brightBlack, brightRed, brightGreen, brightYellow, brightBlue, brightMagenta, brightCyan, brightWhite, bgBlack, bgRed, bgGreen, bgYellow, bgBlue, bgMagenta, bgCyan, bgWhite, bold, italic, underline, strikethrough, dim, reverse, blink, fg, bg, t, SyntaxStyle, hastToStyledText, parseAlign, parseBoxSizing, parseDimension, parseDirection, parseDisplay, parseEdge, parseFlexDirection, parseGutter, parseJustify, parseLogLevel, parseMeasureMode, parseOverflow, parsePositionType, parseUnit, parseWrap, MouseParser, Selection, convertGlobalToLocalSelection, ASCIIFontSelectionHelper, TextBuffer, LogLevel2 as LogLevel, setRenderLibPath, resolveRenderLib, OptimizedBuffer, h, isVNode, maybeMakeRenderable, wrapWithDelegates, instantiate, delegate, LayoutEvents, RenderableEvents, isValidPercentage, isMarginType, isPaddingType, isPositionType, isPositionTypeType, isOverflowType, isDimensionType, isFlexBasisType, isSizeType, isRenderable, BaseRenderable, Renderable, RootRenderable, capture, ConsolePosition, TerminalConsole, getObjectsInViewport, MouseEvent, MouseButton, createCliRenderer, CliRenderEvents, CliRenderer };
9575
+ export { __toESM, __commonJS, __export, __require, Edge, Gutter, exports_src, BorderChars, getBorderFromSides, getBorderSides, borderCharsToArray, BorderCharArrays, nonAlphanumericKeys, parseKeypress, ANSI, KeyHandler, RGBA, hexToRgb, rgbToHex, hsvToRgb, parseColor, fonts, measureText, getCharacterPositions, coordinateToCharacterIndex, renderFontToFrameBuffer, TextAttributes, DebugOverlayCorner, createTextAttributes, visualizeRenderableTree, isStyledText, StyledText, stringToStyledText, black, red, green, yellow, blue, magenta, cyan, white, brightBlack, brightRed, brightGreen, brightYellow, brightBlue, brightMagenta, brightCyan, brightWhite, bgBlack, bgRed, bgGreen, bgYellow, bgBlue, bgMagenta, bgCyan, bgWhite, bold, italic, underline, strikethrough, dim, reverse, blink, fg, bg, t, SyntaxStyle, hastToStyledText, parseAlign, parseBoxSizing, parseDimension, parseDirection, parseDisplay, parseEdge, parseFlexDirection, parseGutter, parseJustify, parseLogLevel, parseMeasureMode, parseOverflow, parsePositionType, parseUnit, parseWrap, MouseParser, Selection, convertGlobalToLocalSelection, ASCIIFontSelectionHelper, envRegistry, registerEnvVar, generateEnvMarkdown, generateEnvColored, env, TextBuffer, LogLevel2 as LogLevel, setRenderLibPath, resolveRenderLib, OptimizedBuffer, h, isVNode, maybeMakeRenderable, wrapWithDelegates, instantiate, delegate, isValidPercentage, LayoutEvents, RenderableEvents, isRenderable, BaseRenderable, Renderable, RootRenderable, capture, ConsolePosition, TerminalConsole, getObjectsInViewport, MouseEvent, MouseButton, createCliRenderer, CliRenderEvents, CliRenderer };
8915
9576
 
8916
- //# debugId=22DC4532C30EE05864756E2164756E21
8917
- //# sourceMappingURL=index-a6ydv6yb.js.map
9577
+ //# debugId=FA47EE78BCA83E8664756E2164756E21
9578
+ //# sourceMappingURL=index-6kvgbzah.js.map