@termuijs/core 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -22,17 +22,26 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  App: () => App,
24
24
  BORDER_CHARS: () => BORDER_CHARS,
25
+ BRAILLE_DOTS: () => BRAILLE_DOTS,
26
+ BRAILLE_OFFSET: () => BRAILLE_OFFSET,
27
+ BarSets: () => BarSets,
28
+ BorderSets: () => BorderSets,
25
29
  CTRL_KEYS: () => CTRL_KEYS,
26
30
  ColorDepth: () => ColorDepth,
27
31
  ESCAPE_SEQUENCES: () => ESCAPE_SEQUENCES,
28
32
  EventEmitter: () => EventEmitter,
29
33
  FocusManager: () => FocusManager,
34
+ HORIZONTAL_BAR_SYMBOLS: () => HORIZONTAL_BAR_SYMBOLS,
30
35
  InputParser: () => InputParser,
31
36
  LayerManager: () => LayerManager,
37
+ LineSets: () => LineSets,
32
38
  Renderer: () => Renderer,
33
39
  SPECIAL_KEYS: () => SPECIAL_KEYS,
34
40
  Screen: () => Screen,
41
+ ScrollbarSets: () => ScrollbarSets,
42
+ Shade: () => Shade,
35
43
  Terminal: () => Terminal,
44
+ VERTICAL_BAR_SYMBOLS: () => VERTICAL_BAR_SYMBOLS,
36
45
  ansi: () => ansi_exports,
37
46
  borderSize: () => borderSize,
38
47
  cellsEqual: () => cellsEqual,
@@ -43,23 +52,36 @@ __export(index_exports, {
43
52
  containsPoint: () => containsPoint,
44
53
  createKeyEvent: () => createKeyEvent,
45
54
  createLayoutNode: () => createLayoutNode,
55
+ createTestScreen: () => createTestScreen,
46
56
  defaultStyle: () => defaultStyle,
47
57
  detectColorDepth: () => detectColorDepth,
48
58
  emptyCell: () => emptyCell,
49
59
  emptyRect: () => emptyRect,
60
+ fill: () => fill,
50
61
  getBorderChars: () => getBorderChars,
51
62
  intersectRect: () => intersectRect,
52
63
  isMouseSequence: () => isMouseSequence,
64
+ length: () => length,
65
+ max: () => max,
53
66
  mergeStyles: () => mergeStyles,
67
+ min: () => min,
54
68
  normalizeEdges: () => normalizeEdges,
55
69
  parseColor: () => parseColor,
56
70
  parseMouseEvent: () => parseMouseEvent,
71
+ percentage: () => percentage,
72
+ ratio: () => ratio,
57
73
  renderFallback: () => renderFallback,
58
74
  shouldUseFallback: () => shouldUseFallback,
59
75
  shrinkRect: () => shrinkRect,
76
+ splitRect: () => splitRect,
60
77
  stringWidth: () => stringWidth,
61
78
  stripAnsi: () => stripAnsi,
62
79
  styleToCellAttrs: () => styleToCellAttrs,
80
+ testScreenClear: () => testScreenClear,
81
+ testScreenGetCell: () => testScreenGetCell,
82
+ testScreenSetCell: () => testScreenSetCell,
83
+ testScreenSetString: () => testScreenSetString,
84
+ testScreenToString: () => testScreenToString,
63
85
  truncate: () => truncate,
64
86
  unionRect: () => unionRect,
65
87
  wordWrap: () => wordWrap
@@ -125,7 +147,7 @@ function parseColor(input) {
125
147
  if (hex.length === 6 && /^[0-9a-fA-F]{6}$/.test(hex)) {
126
148
  return { type: "hex", hex: "#" + hex.toLowerCase() };
127
149
  }
128
- throw new Error(`Invalid hex color: ${input}`);
150
+ return { type: "none" };
129
151
  }
130
152
  const rgbMatch = input.match(/^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/);
131
153
  if (rgbMatch) {
@@ -139,7 +161,7 @@ function parseColor(input) {
139
161
  const code = Math.min(255, parseInt(ansi256Match[1], 10));
140
162
  return { type: "ansi256", code };
141
163
  }
142
- throw new Error(`Unknown color format: ${input}`);
164
+ return { type: "none" };
143
165
  }
144
166
  function colorToRgb(color) {
145
167
  switch (color.type) {
@@ -382,19 +404,26 @@ var Terminal = class {
382
404
  _resizeHandlers = [];
383
405
  _cleanupHandlers = [];
384
406
  _originalRawMode;
407
+ // Stored handler references for proper cleanup
408
+ _resizeHandler = null;
409
+ _exitHandler = null;
410
+ _sigintHandler = null;
411
+ _sigtermHandler = null;
412
+ _restored = false;
385
413
  constructor(options = {}) {
386
414
  this.stdout = options.stdout ?? process.stdout;
387
415
  this.stdin = options.stdin ?? process.stdin;
388
416
  this.colorDepth = options.colorDepth ?? detectColorDepth();
389
417
  this._cols = this.stdout.columns ?? 80;
390
418
  this._rows = this.stdout.rows ?? 24;
391
- this.stdout.on("resize", () => {
419
+ this._resizeHandler = () => {
392
420
  this._cols = this.stdout.columns ?? 80;
393
421
  this._rows = this.stdout.rows ?? 24;
394
422
  for (const handler of this._resizeHandlers) {
395
423
  handler(this._cols, this._rows);
396
424
  }
397
- });
425
+ };
426
+ this.stdout.on("resize", this._resizeHandler);
398
427
  this._setupCleanup();
399
428
  }
400
429
  /** Current terminal width in columns */
@@ -471,9 +500,18 @@ var Terminal = class {
471
500
  // ── Cleanup ─────────────────────────────────────────
472
501
  /**
473
502
  * Restore terminal to its original state.
503
+ * Removes all process signal handlers to prevent leaks.
474
504
  * Called automatically on SIGINT, SIGTERM, process exit.
475
505
  */
476
506
  restore() {
507
+ if (this._restored) return;
508
+ this._restored = true;
509
+ if (this._exitHandler) process.off("exit", this._exitHandler);
510
+ if (this._sigintHandler) process.off("SIGINT", this._sigintHandler);
511
+ if (this._sigtermHandler) process.off("SIGTERM", this._sigtermHandler);
512
+ if (this._resizeHandler) {
513
+ this.stdout.off("resize", this._resizeHandler);
514
+ }
477
515
  this.disableMouse();
478
516
  this.exitAltScreen();
479
517
  this.exitRawMode();
@@ -487,7 +525,7 @@ var Terminal = class {
487
525
  this._cleanupHandlers.push(handler);
488
526
  }
489
527
  _setupCleanup() {
490
- const cleanup = () => {
528
+ const runCleanupHandlers = () => {
491
529
  for (const handler of this._cleanupHandlers) {
492
530
  try {
493
531
  handler();
@@ -496,20 +534,18 @@ var Terminal = class {
496
534
  }
497
535
  this.restore();
498
536
  };
499
- process.on("exit", cleanup);
500
- process.on("SIGINT", () => {
501
- cleanup();
537
+ this._exitHandler = runCleanupHandlers;
538
+ this._sigintHandler = () => {
539
+ runCleanupHandlers();
502
540
  process.exit(130);
503
- });
504
- process.on("SIGTERM", () => {
505
- cleanup();
541
+ };
542
+ this._sigtermHandler = () => {
543
+ runCleanupHandlers();
506
544
  process.exit(143);
507
- });
508
- process.on("uncaughtException", (err) => {
509
- cleanup();
510
- console.error(err);
511
- process.exit(1);
512
- });
545
+ };
546
+ process.on("exit", this._exitHandler);
547
+ process.on("SIGINT", this._sigintHandler);
548
+ process.on("SIGTERM", this._sigtermHandler);
513
549
  }
514
550
  };
515
551
 
@@ -528,6 +564,18 @@ function emptyCell() {
528
564
  width: 1
529
565
  };
530
566
  }
567
+ function resetCell(cell) {
568
+ cell.char = " ";
569
+ cell.fg = { type: "none" };
570
+ cell.bg = { type: "none" };
571
+ cell.bold = false;
572
+ cell.italic = false;
573
+ cell.underline = false;
574
+ cell.dim = false;
575
+ cell.strikethrough = false;
576
+ cell.inverse = false;
577
+ cell.width = 1;
578
+ }
531
579
  function cellsEqual(a, b) {
532
580
  return a.char === b.char && a.bold === b.bold && a.italic === b.italic && a.underline === b.underline && a.dim === b.dim && a.strikethrough === b.strikethrough && a.inverse === b.inverse && a.width === b.width && colorsEqual(a.fg, b.fg) && colorsEqual(a.bg, b.bg);
533
581
  }
@@ -659,7 +707,7 @@ var Screen = class {
659
707
  clear() {
660
708
  for (let r = 0; r < this._rows; r++) {
661
709
  for (let c = 0; c < this._cols; c++) {
662
- this.back[r][c] = emptyCell();
710
+ resetCell(this.back[r][c]);
663
711
  }
664
712
  }
665
713
  }
@@ -1194,13 +1242,19 @@ var EventEmitter = class {
1194
1242
  const handlers = this._handlers.get(event);
1195
1243
  if (handlers) {
1196
1244
  for (const handler of handlers) {
1197
- handler(data);
1245
+ try {
1246
+ handler(data);
1247
+ } catch {
1248
+ }
1198
1249
  }
1199
1250
  }
1200
1251
  const onceHandlers = this._onceHandlers.get(event);
1201
1252
  if (onceHandlers) {
1202
1253
  for (const handler of onceHandlers) {
1203
- handler(data);
1254
+ try {
1255
+ handler(data);
1256
+ } catch {
1257
+ }
1204
1258
  }
1205
1259
  onceHandlers.clear();
1206
1260
  }
@@ -1641,17 +1695,17 @@ function layoutNode(node, availWidth, availHeight, precomputed = false) {
1641
1695
  }
1642
1696
  if (isRow) {
1643
1697
  info.node.computed = {
1644
- x: node.computed.x + innerX + mainOffset + info.margin.left,
1645
- y: node.computed.y + innerY + crossOffset + info.margin.top,
1646
- width: Math.max(0, info.mainSize - info.margin.left - info.margin.right),
1647
- height: Math.max(0, finalCrossSize - info.margin.top - info.margin.bottom)
1698
+ x: Math.floor(node.computed.x + innerX + mainOffset + info.margin.left),
1699
+ y: Math.floor(node.computed.y + innerY + crossOffset + info.margin.top),
1700
+ width: Math.round(Math.max(0, info.mainSize - info.margin.left - info.margin.right)),
1701
+ height: Math.round(Math.max(0, finalCrossSize - info.margin.top - info.margin.bottom))
1648
1702
  };
1649
1703
  } else {
1650
1704
  info.node.computed = {
1651
- x: node.computed.x + innerX + crossOffset + info.margin.left,
1652
- y: node.computed.y + innerY + mainOffset + info.margin.top,
1653
- width: Math.max(0, finalCrossSize - info.margin.left - info.margin.right),
1654
- height: Math.max(0, info.mainSize - info.margin.top - info.margin.bottom)
1705
+ x: Math.floor(node.computed.x + innerX + crossOffset + info.margin.left),
1706
+ y: Math.floor(node.computed.y + innerY + mainOffset + info.margin.top),
1707
+ width: Math.round(Math.max(0, finalCrossSize - info.margin.left - info.margin.right)),
1708
+ height: Math.round(Math.max(0, info.mainSize - info.margin.top - info.margin.bottom))
1655
1709
  };
1656
1710
  }
1657
1711
  mainOffset += info.mainSize + gap + spaceBetween;
@@ -1667,10 +1721,10 @@ function resolveSize(value, available) {
1667
1721
  }
1668
1722
  return void 0;
1669
1723
  }
1670
- function clampSize(value, min, max) {
1724
+ function clampSize(value, min2, max2) {
1671
1725
  let result = value;
1672
- if (min !== void 0) result = Math.max(result, min);
1673
- if (max !== void 0) result = Math.min(result, max);
1726
+ if (min2 !== void 0) result = Math.max(result, min2);
1727
+ if (max2 !== void 0) result = Math.min(result, max2);
1674
1728
  return result;
1675
1729
  }
1676
1730
 
@@ -1705,6 +1759,94 @@ function unionRect(a, b) {
1705
1759
  return { x, y, width: r - x, height: bot - y };
1706
1760
  }
1707
1761
 
1762
+ // src/layout/ConstraintLayout.ts
1763
+ var length = (n) => ({ type: "length", value: n });
1764
+ var percentage = (n) => ({ type: "percentage", value: n });
1765
+ var ratio = (num, den) => ({ type: "ratio", num, den });
1766
+ var min = (n) => ({ type: "min", value: n });
1767
+ var max = (n) => ({ type: "max", value: n });
1768
+ var fill = (weight = 1) => ({ type: "fill", weight });
1769
+ function resolveSize2(constraint, available) {
1770
+ switch (constraint.type) {
1771
+ case "length":
1772
+ return Math.min(constraint.value, available);
1773
+ case "percentage":
1774
+ return Math.min(Math.floor(available * constraint.value / 100), available);
1775
+ case "ratio":
1776
+ return constraint.den === 0 ? 0 : Math.min(
1777
+ Math.floor(available * constraint.num / constraint.den),
1778
+ available
1779
+ );
1780
+ case "min":
1781
+ return constraint.value;
1782
+ case "max":
1783
+ return Math.min(constraint.value, available);
1784
+ case "fill":
1785
+ return 0;
1786
+ }
1787
+ }
1788
+ function splitRect(rect, constraints, direction = "vertical", gap = 0) {
1789
+ if (constraints.length === 0) return [];
1790
+ const totalAvailable = direction === "horizontal" ? rect.width : rect.height;
1791
+ const count = constraints.length;
1792
+ const totalGaps = count > 1 ? gap * (count - 1) : 0;
1793
+ const availableForConstraints = Math.max(0, totalAvailable - totalGaps);
1794
+ const sizes = [];
1795
+ let usedSpace = 0;
1796
+ let fillWeightSum = 0;
1797
+ for (const constraint of constraints) {
1798
+ if (constraint.type === "fill") {
1799
+ sizes.push(0);
1800
+ fillWeightSum += Math.max(1, constraint.weight);
1801
+ } else {
1802
+ const size = resolveSize2(constraint, availableForConstraints);
1803
+ sizes.push(size);
1804
+ usedSpace += size;
1805
+ }
1806
+ }
1807
+ if (fillWeightSum > 0) {
1808
+ const remaining = Math.max(0, availableForConstraints - usedSpace);
1809
+ let distributed = 0;
1810
+ for (let i = 0; i < count; i++) {
1811
+ const constraint = constraints[i];
1812
+ if (!constraint || constraint.type !== "fill") continue;
1813
+ const weight = Math.max(1, constraint.weight);
1814
+ const share = Math.floor(remaining * weight / fillWeightSum);
1815
+ sizes[i] = share;
1816
+ distributed += share;
1817
+ }
1818
+ const leftover = remaining - distributed;
1819
+ if (leftover > 0) {
1820
+ for (let i = count - 1; i >= 0; i--) {
1821
+ const constraint = constraints[i];
1822
+ if (constraint && constraint.type === "fill") {
1823
+ sizes[i] = (sizes[i] ?? 0) + leftover;
1824
+ break;
1825
+ }
1826
+ }
1827
+ }
1828
+ }
1829
+ let totalUsed = 0;
1830
+ for (let i = 0; i < count; i++) {
1831
+ const size = sizes[i] ?? 0;
1832
+ const clamped = Math.max(0, Math.min(size, availableForConstraints - totalUsed));
1833
+ sizes[i] = clamped;
1834
+ totalUsed += clamped;
1835
+ }
1836
+ const results = [];
1837
+ let offset = 0;
1838
+ for (let i = 0; i < count; i++) {
1839
+ const size = sizes[i] ?? 0;
1840
+ if (direction === "horizontal") {
1841
+ results.push({ x: rect.x + offset, y: rect.y, width: size, height: rect.height });
1842
+ } else {
1843
+ results.push({ x: rect.x, y: rect.y + offset, width: rect.width, height: size });
1844
+ }
1845
+ offset += size + gap;
1846
+ }
1847
+ return results;
1848
+ }
1849
+
1708
1850
  // src/events/FocusManager.ts
1709
1851
  var FocusManager = class {
1710
1852
  _focusables = [];
@@ -1936,6 +2078,212 @@ var FocusManager = class {
1936
2078
  }
1937
2079
  };
1938
2080
 
2081
+ // src/style/symbols.ts
2082
+ var BorderSets = {
2083
+ PLAIN: {
2084
+ topLeft: "\u250C",
2085
+ topRight: "\u2510",
2086
+ bottomLeft: "\u2514",
2087
+ bottomRight: "\u2518",
2088
+ horizontal: "\u2500",
2089
+ vertical: "\u2502",
2090
+ cross: "\u253C"
2091
+ },
2092
+ ROUNDED: {
2093
+ topLeft: "\u256D",
2094
+ topRight: "\u256E",
2095
+ bottomLeft: "\u2570",
2096
+ bottomRight: "\u256F",
2097
+ horizontal: "\u2500",
2098
+ vertical: "\u2502",
2099
+ cross: "\u253C"
2100
+ },
2101
+ DOUBLE: {
2102
+ topLeft: "\u2554",
2103
+ topRight: "\u2557",
2104
+ bottomLeft: "\u255A",
2105
+ bottomRight: "\u255D",
2106
+ horizontal: "\u2550",
2107
+ vertical: "\u2551",
2108
+ cross: "\u256C"
2109
+ },
2110
+ THICK: {
2111
+ topLeft: "\u250F",
2112
+ topRight: "\u2513",
2113
+ bottomLeft: "\u2517",
2114
+ bottomRight: "\u251B",
2115
+ horizontal: "\u2501",
2116
+ vertical: "\u2503",
2117
+ cross: "\u254B"
2118
+ },
2119
+ QUADRANT_INSIDE: {
2120
+ topLeft: "\u2597",
2121
+ topRight: "\u2596",
2122
+ bottomLeft: "\u259D",
2123
+ bottomRight: "\u2598",
2124
+ horizontal: "\u2580",
2125
+ vertical: "\u2590",
2126
+ cross: "\u2588"
2127
+ },
2128
+ QUADRANT_OUTSIDE: {
2129
+ topLeft: "\u259B",
2130
+ topRight: "\u259C",
2131
+ bottomLeft: "\u2599",
2132
+ bottomRight: "\u259F",
2133
+ horizontal: "\u2580",
2134
+ vertical: "\u258C",
2135
+ cross: "\u2588"
2136
+ },
2137
+ EMPTY: {
2138
+ topLeft: " ",
2139
+ topRight: " ",
2140
+ bottomLeft: " ",
2141
+ bottomRight: " ",
2142
+ horizontal: " ",
2143
+ vertical: " ",
2144
+ cross: " "
2145
+ }
2146
+ };
2147
+ var BarSets = {
2148
+ NINE_LEVELS: {
2149
+ full: "\u2588",
2150
+ sevenEighths: "\u2587",
2151
+ threeQuarters: "\u2586",
2152
+ fiveEighths: "\u2585",
2153
+ half: "\u2584",
2154
+ threeEighths: "\u2583",
2155
+ oneQuarter: "\u2582",
2156
+ oneEighth: "\u2581",
2157
+ empty: " "
2158
+ },
2159
+ THREE_LEVELS: {
2160
+ full: "\u2588",
2161
+ sevenEighths: "\u2591",
2162
+ threeQuarters: "\u2591",
2163
+ fiveEighths: "\u2591",
2164
+ half: "\u2584",
2165
+ threeEighths: "\u2591",
2166
+ oneQuarter: "\u2591",
2167
+ oneEighth: "\u2591",
2168
+ empty: " "
2169
+ },
2170
+ ASCII: {
2171
+ full: "#",
2172
+ sevenEighths: "#",
2173
+ threeQuarters: "#",
2174
+ fiveEighths: "#",
2175
+ half: "#",
2176
+ threeEighths: "-",
2177
+ oneQuarter: "-",
2178
+ oneEighth: "-",
2179
+ empty: " "
2180
+ }
2181
+ };
2182
+ var VERTICAL_BAR_SYMBOLS = [
2183
+ " ",
2184
+ "\u2581",
2185
+ "\u2582",
2186
+ "\u2583",
2187
+ "\u2584",
2188
+ "\u2585",
2189
+ "\u2586",
2190
+ "\u2587",
2191
+ "\u2588"
2192
+ ];
2193
+ var HORIZONTAL_BAR_SYMBOLS = [
2194
+ " ",
2195
+ "\u258F",
2196
+ "\u258E",
2197
+ "\u258D",
2198
+ "\u258C",
2199
+ "\u258B",
2200
+ "\u258A",
2201
+ "\u2589",
2202
+ "\u2588"
2203
+ ];
2204
+ var ScrollbarSets = {
2205
+ VERTICAL: { track: "\u2502", thumb: "\u2588", begin: "\u2191", end: "\u2193" },
2206
+ HORIZONTAL: { track: "\u2500", thumb: "\u2588", begin: "\u2190", end: "\u2192" },
2207
+ DOUBLE_VERTICAL: { track: "\u2551", thumb: "\u2590", begin: "\u25B2", end: "\u25BC" },
2208
+ DOUBLE_HORIZONTAL: { track: "\u2550", thumb: "\u258C", begin: "\u25C4", end: "\u25BA" }
2209
+ };
2210
+ var LineSets = {
2211
+ NORMAL: { horizontal: "\u2500", vertical: "\u2502", cross: "\u253C" },
2212
+ THICK: { horizontal: "\u2501", vertical: "\u2503", cross: "\u254B" },
2213
+ DOUBLE: { horizontal: "\u2550", vertical: "\u2551", cross: "\u256C" }
2214
+ };
2215
+ var Shade = {
2216
+ FULL: "\u2588",
2217
+ DARK: "\u2593",
2218
+ MEDIUM: "\u2592",
2219
+ LIGHT: "\u2591",
2220
+ EMPTY: " "
2221
+ };
2222
+ var BRAILLE_OFFSET = 10240;
2223
+ var BRAILLE_DOTS = [
2224
+ [1, 8],
2225
+ [2, 16],
2226
+ [4, 32],
2227
+ [64, 128]
2228
+ ];
2229
+
2230
+ // src/terminal/TestBackend.ts
2231
+ function createTestScreen(width, height) {
2232
+ const cells = [];
2233
+ for (let row = 0; row < height; row++) {
2234
+ const rowCells = [];
2235
+ for (let col = 0; col < width; col++) {
2236
+ rowCells.push(emptyCell());
2237
+ }
2238
+ cells.push(rowCells);
2239
+ }
2240
+ return { width, height, cells };
2241
+ }
2242
+ function testScreenSetCell(screen, x, y, cell) {
2243
+ if (x < 0 || x >= screen.width || y < 0 || y >= screen.height) {
2244
+ return;
2245
+ }
2246
+ const row = screen.cells[y];
2247
+ if (row) {
2248
+ row[x] = cell;
2249
+ }
2250
+ }
2251
+ function testScreenGetCell(screen, x, y) {
2252
+ if (x < 0 || x >= screen.width || y < 0 || y >= screen.height) {
2253
+ return void 0;
2254
+ }
2255
+ const row = screen.cells[y];
2256
+ return row ? row[x] : void 0;
2257
+ }
2258
+ function testScreenToString(screen) {
2259
+ return screen.cells.map((row) => row.map((cell) => cell.char).join("")).join("\n");
2260
+ }
2261
+ function testScreenClear(screen) {
2262
+ for (let y = 0; y < screen.height; y++) {
2263
+ const row = screen.cells[y];
2264
+ if (row) {
2265
+ for (let x = 0; x < screen.width; x++) {
2266
+ row[x] = emptyCell();
2267
+ }
2268
+ }
2269
+ }
2270
+ }
2271
+ function testScreenSetString(screen, x, y, str) {
2272
+ let cx = x;
2273
+ for (const ch of str) {
2274
+ if (cx >= screen.width) break;
2275
+ if (cx >= 0 && y >= 0 && y < screen.height) {
2276
+ const row = screen.cells[y];
2277
+ if (row) {
2278
+ const cell = emptyCell();
2279
+ cell.char = ch;
2280
+ row[cx] = cell;
2281
+ }
2282
+ }
2283
+ cx++;
2284
+ }
2285
+ }
2286
+
1939
2287
  // src/app/Fallback.ts
1940
2288
  function shouldUseFallback() {
1941
2289
  if (!process.stdout.isTTY) return true;
@@ -1996,7 +2344,7 @@ var App = class {
1996
2344
  */
1997
2345
  async mount() {
1998
2346
  if (this._mounted) return 0;
1999
- if (this._options.forceFallback || shouldUseFallback()) {
2347
+ if (this._options.forceFallback || !this._options.skipFallback && shouldUseFallback()) {
2000
2348
  this._renderFallback();
2001
2349
  return 0;
2002
2350
  }
@@ -2106,8 +2454,6 @@ var App = class {
2106
2454
  if (this._exitResolve) {
2107
2455
  this._exitResolve(code);
2108
2456
  this._exitResolve = null;
2109
- } else {
2110
- process.exit(code);
2111
2457
  }
2112
2458
  }
2113
2459
  /**
@@ -2320,17 +2666,26 @@ function wordWrap(str, width) {
2320
2666
  0 && (module.exports = {
2321
2667
  App,
2322
2668
  BORDER_CHARS,
2669
+ BRAILLE_DOTS,
2670
+ BRAILLE_OFFSET,
2671
+ BarSets,
2672
+ BorderSets,
2323
2673
  CTRL_KEYS,
2324
2674
  ColorDepth,
2325
2675
  ESCAPE_SEQUENCES,
2326
2676
  EventEmitter,
2327
2677
  FocusManager,
2678
+ HORIZONTAL_BAR_SYMBOLS,
2328
2679
  InputParser,
2329
2680
  LayerManager,
2681
+ LineSets,
2330
2682
  Renderer,
2331
2683
  SPECIAL_KEYS,
2332
2684
  Screen,
2685
+ ScrollbarSets,
2686
+ Shade,
2333
2687
  Terminal,
2688
+ VERTICAL_BAR_SYMBOLS,
2334
2689
  ansi,
2335
2690
  borderSize,
2336
2691
  cellsEqual,
@@ -2341,23 +2696,36 @@ function wordWrap(str, width) {
2341
2696
  containsPoint,
2342
2697
  createKeyEvent,
2343
2698
  createLayoutNode,
2699
+ createTestScreen,
2344
2700
  defaultStyle,
2345
2701
  detectColorDepth,
2346
2702
  emptyCell,
2347
2703
  emptyRect,
2704
+ fill,
2348
2705
  getBorderChars,
2349
2706
  intersectRect,
2350
2707
  isMouseSequence,
2708
+ length,
2709
+ max,
2351
2710
  mergeStyles,
2711
+ min,
2352
2712
  normalizeEdges,
2353
2713
  parseColor,
2354
2714
  parseMouseEvent,
2715
+ percentage,
2716
+ ratio,
2355
2717
  renderFallback,
2356
2718
  shouldUseFallback,
2357
2719
  shrinkRect,
2720
+ splitRect,
2358
2721
  stringWidth,
2359
2722
  stripAnsi,
2360
2723
  styleToCellAttrs,
2724
+ testScreenClear,
2725
+ testScreenGetCell,
2726
+ testScreenSetCell,
2727
+ testScreenSetString,
2728
+ testScreenToString,
2361
2729
  truncate,
2362
2730
  unionRect,
2363
2731
  wordWrap