@termuijs/core 0.1.0
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 +2365 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1081 -0
- package/dist/index.d.ts +1081 -0
- package/dist/index.js +2302 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,1081 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supported color depth levels, ordered from least to most capable.
|
|
3
|
+
*/
|
|
4
|
+
declare enum ColorDepth {
|
|
5
|
+
/** No color support (e.g. NO_COLOR env var set) */
|
|
6
|
+
None = 0,
|
|
7
|
+
/** 4-bit, 16 colors (standard ANSI) */
|
|
8
|
+
Basic = 4,
|
|
9
|
+
/** 8-bit, 256 colors */
|
|
10
|
+
Ansi256 = 8,
|
|
11
|
+
/** 24-bit, 16.7 million colors (true color) */
|
|
12
|
+
TrueColor = 24
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Represents a color value in the terminal.
|
|
16
|
+
* Supports named ANSI colors, 256-color palette, and RGB true color.
|
|
17
|
+
*/
|
|
18
|
+
type Color = {
|
|
19
|
+
type: 'named';
|
|
20
|
+
name: NamedColor;
|
|
21
|
+
} | {
|
|
22
|
+
type: 'ansi256';
|
|
23
|
+
code: number;
|
|
24
|
+
} | {
|
|
25
|
+
type: 'rgb';
|
|
26
|
+
r: number;
|
|
27
|
+
g: number;
|
|
28
|
+
b: number;
|
|
29
|
+
} | {
|
|
30
|
+
type: 'hex';
|
|
31
|
+
hex: string;
|
|
32
|
+
} | {
|
|
33
|
+
type: 'none';
|
|
34
|
+
};
|
|
35
|
+
type NamedColor = 'black' | 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan' | 'white' | 'brightBlack' | 'brightRed' | 'brightGreen' | 'brightYellow' | 'brightBlue' | 'brightMagenta' | 'brightCyan' | 'brightWhite';
|
|
36
|
+
/**
|
|
37
|
+
* Parse a color string into a Color object.
|
|
38
|
+
*
|
|
39
|
+
* Accepts:
|
|
40
|
+
* - Named colors: 'red', 'brightBlue', etc.
|
|
41
|
+
* - Hex: '#ff0000', '#f00'
|
|
42
|
+
* - RGB: 'rgb(255, 0, 0)'
|
|
43
|
+
* - ANSI 256: 'ansi256(196)'
|
|
44
|
+
*/
|
|
45
|
+
declare function parseColor(input: string): Color;
|
|
46
|
+
/**
|
|
47
|
+
* Convert any Color to its RGB representation.
|
|
48
|
+
*/
|
|
49
|
+
declare function colorToRgb(color: Color): [number, number, number];
|
|
50
|
+
/**
|
|
51
|
+
* Detect the terminal's color depth from environment variables.
|
|
52
|
+
*/
|
|
53
|
+
declare function detectColorDepth(): ColorDepth;
|
|
54
|
+
/**
|
|
55
|
+
* Generate the ANSI escape codes for a foreground color at the given depth.
|
|
56
|
+
*/
|
|
57
|
+
declare function colorToAnsiFg(color: Color, depth: ColorDepth): string;
|
|
58
|
+
/**
|
|
59
|
+
* Generate the ANSI escape codes for a background color at the given depth.
|
|
60
|
+
*/
|
|
61
|
+
declare function colorToAnsiBg(color: Color, depth: ColorDepth): string;
|
|
62
|
+
|
|
63
|
+
interface TerminalOptions {
|
|
64
|
+
/** Override stdout stream (useful for testing) */
|
|
65
|
+
stdout?: NodeJS.WriteStream;
|
|
66
|
+
/** Override stdin stream (useful for testing) */
|
|
67
|
+
stdin?: NodeJS.ReadStream;
|
|
68
|
+
/** Force a specific color depth */
|
|
69
|
+
colorDepth?: ColorDepth;
|
|
70
|
+
/** Enable mouse tracking */
|
|
71
|
+
mouse?: boolean;
|
|
72
|
+
/** Use alternate screen buffer for full-screen apps */
|
|
73
|
+
altScreen?: boolean;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Terminal adapter — wraps process.stdout/stdin and manages
|
|
77
|
+
* terminal state (raw mode, cursor, mouse, alternate screen).
|
|
78
|
+
*/
|
|
79
|
+
declare class Terminal {
|
|
80
|
+
readonly stdout: NodeJS.WriteStream;
|
|
81
|
+
readonly stdin: NodeJS.ReadStream;
|
|
82
|
+
readonly colorDepth: ColorDepth;
|
|
83
|
+
private _cols;
|
|
84
|
+
private _rows;
|
|
85
|
+
private _isRawMode;
|
|
86
|
+
private _isAltScreen;
|
|
87
|
+
private _isMouseEnabled;
|
|
88
|
+
private _resizeHandlers;
|
|
89
|
+
private _cleanupHandlers;
|
|
90
|
+
private _originalRawMode;
|
|
91
|
+
constructor(options?: TerminalOptions);
|
|
92
|
+
/** Current terminal width in columns */
|
|
93
|
+
get cols(): number;
|
|
94
|
+
/** Current terminal height in rows */
|
|
95
|
+
get rows(): number;
|
|
96
|
+
/** Whether stdin is a TTY (interactive) */
|
|
97
|
+
isInteractive(): boolean;
|
|
98
|
+
/** Whether the terminal supports raw mode */
|
|
99
|
+
supportsRawMode(): boolean;
|
|
100
|
+
enterRawMode(): void;
|
|
101
|
+
exitRawMode(): void;
|
|
102
|
+
enterAltScreen(): void;
|
|
103
|
+
exitAltScreen(): void;
|
|
104
|
+
enableMouse(): void;
|
|
105
|
+
disableMouse(): void;
|
|
106
|
+
hideCursor(): void;
|
|
107
|
+
showCursor(): void;
|
|
108
|
+
write(data: string): void;
|
|
109
|
+
onResize(handler: (cols: number, rows: number) => void): () => void;
|
|
110
|
+
/**
|
|
111
|
+
* Restore terminal to its original state.
|
|
112
|
+
* Called automatically on SIGINT, SIGTERM, process exit.
|
|
113
|
+
*/
|
|
114
|
+
restore(): void;
|
|
115
|
+
/**
|
|
116
|
+
* Register a custom cleanup handler that runs on terminal restore.
|
|
117
|
+
*/
|
|
118
|
+
onCleanup(handler: () => void): void;
|
|
119
|
+
private _setupCleanup;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* A single cell in the terminal grid.
|
|
124
|
+
*/
|
|
125
|
+
interface Cell {
|
|
126
|
+
/** The character displayed (single grapheme cluster) */
|
|
127
|
+
char: string;
|
|
128
|
+
/** Foreground color */
|
|
129
|
+
fg: Color;
|
|
130
|
+
/** Background color */
|
|
131
|
+
bg: Color;
|
|
132
|
+
/** Bold text */
|
|
133
|
+
bold: boolean;
|
|
134
|
+
/** Italic text */
|
|
135
|
+
italic: boolean;
|
|
136
|
+
/** Underline text */
|
|
137
|
+
underline: boolean;
|
|
138
|
+
/** Dim text */
|
|
139
|
+
dim: boolean;
|
|
140
|
+
/** Strikethrough text */
|
|
141
|
+
strikethrough: boolean;
|
|
142
|
+
/** Inverse colors */
|
|
143
|
+
inverse: boolean;
|
|
144
|
+
/**
|
|
145
|
+
* Visual width of this cell.
|
|
146
|
+
* - 1 for normal characters
|
|
147
|
+
* - 2 for wide chars (CJK/emoji) — the next cell is a "continuation" cell
|
|
148
|
+
* - 0 for continuation cells (second half of a wide char)
|
|
149
|
+
*/
|
|
150
|
+
width: number;
|
|
151
|
+
}
|
|
152
|
+
/** Create a blank cell with default attributes */
|
|
153
|
+
declare function emptyCell(): Cell;
|
|
154
|
+
/** Check if two cells are visually identical */
|
|
155
|
+
declare function cellsEqual(a: Cell, b: Cell): boolean;
|
|
156
|
+
/**
|
|
157
|
+
* Double-buffered 2D cell grid for the terminal.
|
|
158
|
+
*
|
|
159
|
+
* - `front` = what's currently displayed on screen
|
|
160
|
+
* - `back` = what we're building for the next frame
|
|
161
|
+
*
|
|
162
|
+
* After rendering, the renderer diffs `front` vs `back` and only emits
|
|
163
|
+
* changes, then swaps the buffers.
|
|
164
|
+
*/
|
|
165
|
+
declare class Screen {
|
|
166
|
+
private _cols;
|
|
167
|
+
private _rows;
|
|
168
|
+
front: Cell[][];
|
|
169
|
+
back: Cell[][];
|
|
170
|
+
/**
|
|
171
|
+
* Stack of clipping regions. When non-empty, setCell/writeString
|
|
172
|
+
* only write to cells within the topmost clip rectangle.
|
|
173
|
+
*/
|
|
174
|
+
private _clipStack;
|
|
175
|
+
constructor(cols: number, rows: number);
|
|
176
|
+
get cols(): number;
|
|
177
|
+
get rows(): number;
|
|
178
|
+
/**
|
|
179
|
+
* Push a clipping region onto the stack.
|
|
180
|
+
* All subsequent setCell/writeString calls will be constrained
|
|
181
|
+
* to cells within this rectangle. Clips are intersected with
|
|
182
|
+
* any parent clip already on the stack (nested clipping).
|
|
183
|
+
*/
|
|
184
|
+
pushClip(region: {
|
|
185
|
+
x: number;
|
|
186
|
+
y: number;
|
|
187
|
+
width: number;
|
|
188
|
+
height: number;
|
|
189
|
+
}): void;
|
|
190
|
+
/**
|
|
191
|
+
* Pop the most recent clipping region from the stack.
|
|
192
|
+
*/
|
|
193
|
+
popClip(): void;
|
|
194
|
+
/**
|
|
195
|
+
* Get the current active clip region, or null if no clip is active.
|
|
196
|
+
*/
|
|
197
|
+
get activeClip(): {
|
|
198
|
+
x: number;
|
|
199
|
+
y: number;
|
|
200
|
+
width: number;
|
|
201
|
+
height: number;
|
|
202
|
+
} | null;
|
|
203
|
+
/**
|
|
204
|
+
* Write a cell to the back buffer at position (col, row).
|
|
205
|
+
*/
|
|
206
|
+
setCell(col: number, row: number, cell: Partial<Cell>): void;
|
|
207
|
+
/**
|
|
208
|
+
* Write a string to the back buffer starting at (col, row).
|
|
209
|
+
* Applies the provided style attributes to each character.
|
|
210
|
+
*/
|
|
211
|
+
writeString(col: number, row: number, str: string, style?: Partial<Omit<Cell, 'char' | 'width'>>): void;
|
|
212
|
+
/**
|
|
213
|
+
* Clear the back buffer to all empty cells.
|
|
214
|
+
*/
|
|
215
|
+
clear(): void;
|
|
216
|
+
/**
|
|
217
|
+
* Swap front and back buffers. Called after rendering diffs.
|
|
218
|
+
*/
|
|
219
|
+
swap(): void;
|
|
220
|
+
/**
|
|
221
|
+
* Resize the screen. Clears both buffers.
|
|
222
|
+
*/
|
|
223
|
+
resize(cols: number, rows: number): void;
|
|
224
|
+
/**
|
|
225
|
+
* Clear the front buffer (marks everything as "needs redraw").
|
|
226
|
+
*/
|
|
227
|
+
invalidate(): void;
|
|
228
|
+
private _createGrid;
|
|
229
|
+
private _isWideCodePoint;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Differential renderer — compares front/back screen buffers and
|
|
234
|
+
* outputs only the changed cells. Uses synchronized output (CSI 2026)
|
|
235
|
+
* for atomic, flicker-free updates.
|
|
236
|
+
*/
|
|
237
|
+
declare class Renderer {
|
|
238
|
+
private _terminal;
|
|
239
|
+
private _screen;
|
|
240
|
+
private _fps;
|
|
241
|
+
private _frameTimer;
|
|
242
|
+
private _renderRequested;
|
|
243
|
+
private _colorDepth;
|
|
244
|
+
constructor(terminal: Terminal, screen: Screen, fps?: number);
|
|
245
|
+
/** Change the rendering frame rate cap */
|
|
246
|
+
setFPS(fps: number): void;
|
|
247
|
+
/** Start the render loop */
|
|
248
|
+
start(): void;
|
|
249
|
+
/** Stop the render loop */
|
|
250
|
+
stop(): void;
|
|
251
|
+
/** Request a render on the next frame */
|
|
252
|
+
requestFrame(): void;
|
|
253
|
+
/** Force an immediate render (bypass frame rate) */
|
|
254
|
+
renderNow(): void;
|
|
255
|
+
/**
|
|
256
|
+
* Full-screen clear and redraw (first render or after resize).
|
|
257
|
+
*/
|
|
258
|
+
fullRender(): void;
|
|
259
|
+
/**
|
|
260
|
+
* Core diff and flush: compare front vs back buffer,
|
|
261
|
+
* emit only changed cells.
|
|
262
|
+
*/
|
|
263
|
+
private _flush;
|
|
264
|
+
/**
|
|
265
|
+
* Generate the ANSI escape sequence to render a single cell.
|
|
266
|
+
*/
|
|
267
|
+
private _renderCell;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* A computed rectangle with position and size.
|
|
272
|
+
*/
|
|
273
|
+
interface Rect {
|
|
274
|
+
x: number;
|
|
275
|
+
y: number;
|
|
276
|
+
width: number;
|
|
277
|
+
height: number;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* A 2D size.
|
|
281
|
+
*/
|
|
282
|
+
interface Size {
|
|
283
|
+
width: number;
|
|
284
|
+
height: number;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Create an empty rect at origin.
|
|
288
|
+
*/
|
|
289
|
+
declare function emptyRect(): Rect;
|
|
290
|
+
/**
|
|
291
|
+
* Check if a point is inside a rect.
|
|
292
|
+
*/
|
|
293
|
+
declare function containsPoint(rect: Rect, x: number, y: number): boolean;
|
|
294
|
+
/**
|
|
295
|
+
* Shrink a rect by the given edges (inset).
|
|
296
|
+
*/
|
|
297
|
+
declare function shrinkRect(rect: Rect, top: number, right: number, bottom: number, left: number): Rect;
|
|
298
|
+
/**
|
|
299
|
+
* Intersect two rects. Returns the overlapping region, or null if disjoint.
|
|
300
|
+
*/
|
|
301
|
+
declare function intersectRect(a: Rect, b: Rect): Rect | null;
|
|
302
|
+
/**
|
|
303
|
+
* Union two rects into the smallest bounding rect that contains both.
|
|
304
|
+
*/
|
|
305
|
+
declare function unionRect(a: Rect, b: Rect): Rect;
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* A rendering layer. Each layer has its own cell grid and z-index.
|
|
309
|
+
* Higher z-index layers render on top of lower ones during compositing.
|
|
310
|
+
*/
|
|
311
|
+
interface Layer {
|
|
312
|
+
/** Unique identifier for this layer */
|
|
313
|
+
id: string;
|
|
314
|
+
/** Stacking order — higher renders on top */
|
|
315
|
+
zIndex: number;
|
|
316
|
+
/** Cell grid (same dimensions as Screen) */
|
|
317
|
+
cells: Cell[][];
|
|
318
|
+
/** Whether this layer is visible */
|
|
319
|
+
visible: boolean;
|
|
320
|
+
/** Bounding box of cells written since last clear (null = nothing dirty) */
|
|
321
|
+
dirtyRegion: Rect | null;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Manages multiple rendering layers for overlay support.
|
|
325
|
+
*
|
|
326
|
+
* The base layer (z=0) is the primary widget layer — always opaque.
|
|
327
|
+
* Overlay layers (z>0) support transparency: only cells explicitly
|
|
328
|
+
* written to them overwrite the base layer during compositing.
|
|
329
|
+
*
|
|
330
|
+
* Typical z-index values:
|
|
331
|
+
* - 0: Base widget layer
|
|
332
|
+
* - 10: Dropdown menus
|
|
333
|
+
* - 100: Modal dialogs
|
|
334
|
+
* - 1000: Toasts / notifications
|
|
335
|
+
*/
|
|
336
|
+
declare class LayerManager {
|
|
337
|
+
private _layers;
|
|
338
|
+
private _cols;
|
|
339
|
+
private _rows;
|
|
340
|
+
constructor(cols: number, rows: number);
|
|
341
|
+
get cols(): number;
|
|
342
|
+
get rows(): number;
|
|
343
|
+
/**
|
|
344
|
+
* Create a new overlay layer.
|
|
345
|
+
* @param id Unique identifier (e.g. 'modal', 'select-dropdown', 'toast')
|
|
346
|
+
* @param zIndex Stacking order (higher = rendered on top)
|
|
347
|
+
*/
|
|
348
|
+
createLayer(id: string, zIndex: number): Layer;
|
|
349
|
+
/**
|
|
350
|
+
* Remove an overlay layer and clean up its resources.
|
|
351
|
+
*/
|
|
352
|
+
removeLayer(id: string): void;
|
|
353
|
+
/**
|
|
354
|
+
* Get a layer by ID.
|
|
355
|
+
*/
|
|
356
|
+
getLayer(id: string): Layer | undefined;
|
|
357
|
+
/**
|
|
358
|
+
* Check if a layer exists.
|
|
359
|
+
*/
|
|
360
|
+
hasLayer(id: string): boolean;
|
|
361
|
+
/**
|
|
362
|
+
* Get all layers sorted by z-index (ascending).
|
|
363
|
+
*/
|
|
364
|
+
getSortedLayers(): Layer[];
|
|
365
|
+
/**
|
|
366
|
+
* Write a cell to a specific layer.
|
|
367
|
+
*/
|
|
368
|
+
setCell(layerId: string, col: number, row: number, cell: Partial<Cell>): void;
|
|
369
|
+
/**
|
|
370
|
+
* Write a string to a specific layer at position (col, row).
|
|
371
|
+
*/
|
|
372
|
+
writeString(layerId: string, col: number, row: number, str: string, style?: Partial<Omit<Cell, 'char' | 'width'>>): void;
|
|
373
|
+
/**
|
|
374
|
+
* Clear all cells in a specific layer.
|
|
375
|
+
*/
|
|
376
|
+
clearLayer(id: string): void;
|
|
377
|
+
/**
|
|
378
|
+
* Clear all overlay layers.
|
|
379
|
+
*/
|
|
380
|
+
clearAll(): void;
|
|
381
|
+
/**
|
|
382
|
+
* Composite all overlay layers onto the Screen's back buffer.
|
|
383
|
+
* Layers are applied in z-index order (lowest first).
|
|
384
|
+
* Transparent cells (empty with no colors) are skipped.
|
|
385
|
+
*/
|
|
386
|
+
composite(screen: Screen): void;
|
|
387
|
+
/**
|
|
388
|
+
* Resize all layers when the terminal is resized.
|
|
389
|
+
*/
|
|
390
|
+
resize(cols: number, rows: number): void;
|
|
391
|
+
/**
|
|
392
|
+
* Create an empty cell grid.
|
|
393
|
+
*/
|
|
394
|
+
private _createGrid;
|
|
395
|
+
/**
|
|
396
|
+
* Expand the dirty region of a layer to include the given cell.
|
|
397
|
+
*/
|
|
398
|
+
private _expandDirty;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Keyboard event emitted when a key is pressed.
|
|
403
|
+
*/
|
|
404
|
+
interface KeyEvent {
|
|
405
|
+
/** Human-readable key name: 'a', 'enter', 'up', 'f1', 'tab', etc. */
|
|
406
|
+
key: string;
|
|
407
|
+
/** Raw byte sequence from stdin */
|
|
408
|
+
raw: Buffer;
|
|
409
|
+
/** Ctrl modifier held */
|
|
410
|
+
ctrl: boolean;
|
|
411
|
+
/** Alt/Meta modifier held */
|
|
412
|
+
alt: boolean;
|
|
413
|
+
/** Shift modifier held */
|
|
414
|
+
shift: boolean;
|
|
415
|
+
/** The widget ID that currently has focus (target of the event) */
|
|
416
|
+
targetId?: string;
|
|
417
|
+
/** Whether propagation has been stopped */
|
|
418
|
+
_propagationStopped?: boolean;
|
|
419
|
+
/** Whether the default action has been prevented */
|
|
420
|
+
_defaultPrevented?: boolean;
|
|
421
|
+
/** Stop this event from bubbling to parent widgets */
|
|
422
|
+
stopPropagation(): void;
|
|
423
|
+
/** Prevent the default action for this event */
|
|
424
|
+
preventDefault(): void;
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Create a KeyEvent with propagation control methods attached.
|
|
428
|
+
*/
|
|
429
|
+
declare function createKeyEvent(base: {
|
|
430
|
+
key: string;
|
|
431
|
+
raw: Buffer;
|
|
432
|
+
ctrl: boolean;
|
|
433
|
+
alt: boolean;
|
|
434
|
+
shift: boolean;
|
|
435
|
+
targetId?: string;
|
|
436
|
+
}): KeyEvent;
|
|
437
|
+
/**
|
|
438
|
+
* Mouse event types.
|
|
439
|
+
*/
|
|
440
|
+
type MouseEventType = 'mousedown' | 'mouseup' | 'mousemove' | 'scroll';
|
|
441
|
+
type MouseButton = 'left' | 'middle' | 'right' | 'none';
|
|
442
|
+
/**
|
|
443
|
+
* Mouse event emitted when mouse activity is detected.
|
|
444
|
+
*/
|
|
445
|
+
interface MouseEvent {
|
|
446
|
+
/** x (column) position, 0-indexed */
|
|
447
|
+
x: number;
|
|
448
|
+
/** y (row) position, 0-indexed */
|
|
449
|
+
y: number;
|
|
450
|
+
/** Which mouse button */
|
|
451
|
+
button: MouseButton;
|
|
452
|
+
/** Type of mouse event */
|
|
453
|
+
type: MouseEventType;
|
|
454
|
+
/** Scroll direction (-1 = up, 1 = down) */
|
|
455
|
+
scrollDelta?: number;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Resize event emitted when the terminal is resized.
|
|
459
|
+
*/
|
|
460
|
+
interface ResizeEvent {
|
|
461
|
+
cols: number;
|
|
462
|
+
rows: number;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Focus event emitted when a widget gains or loses focus.
|
|
466
|
+
*/
|
|
467
|
+
interface FocusEvent {
|
|
468
|
+
/** Widget ID that is gaining or losing focus */
|
|
469
|
+
targetId: string;
|
|
470
|
+
/** Type of focus event */
|
|
471
|
+
type: 'focus' | 'blur';
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Map of all event types to their data shapes.
|
|
475
|
+
*/
|
|
476
|
+
interface EventMap {
|
|
477
|
+
'key': KeyEvent;
|
|
478
|
+
'mouse': MouseEvent;
|
|
479
|
+
'resize': ResizeEvent;
|
|
480
|
+
'focus': FocusEvent;
|
|
481
|
+
'blur': FocusEvent;
|
|
482
|
+
'render': void;
|
|
483
|
+
'mount': void;
|
|
484
|
+
'unmount': void;
|
|
485
|
+
'tick': number;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Reads raw stdin bytes and parses them into typed KeyEvent / MouseEvent objects.
|
|
490
|
+
* Handles escape sequences, multi-byte keys, ctrl+key, and SGR mouse events.
|
|
491
|
+
*/
|
|
492
|
+
declare class InputParser {
|
|
493
|
+
private _events;
|
|
494
|
+
private _stdin;
|
|
495
|
+
private _handler;
|
|
496
|
+
private _escapeTimeout;
|
|
497
|
+
private _escapeBuffer;
|
|
498
|
+
constructor(stdin: NodeJS.ReadStream);
|
|
499
|
+
/** Subscribe to key events */
|
|
500
|
+
onKey(handler: (event: KeyEvent) => void): () => void;
|
|
501
|
+
/** Subscribe to mouse events */
|
|
502
|
+
onMouse(handler: (event: MouseEvent) => void): () => void;
|
|
503
|
+
/** Start listening for input */
|
|
504
|
+
start(): void;
|
|
505
|
+
/** Stop listening for input */
|
|
506
|
+
stop(): void;
|
|
507
|
+
/**
|
|
508
|
+
* Process a chunk of raw input bytes.
|
|
509
|
+
*/
|
|
510
|
+
private _processInput;
|
|
511
|
+
/**
|
|
512
|
+
* Try to parse buffered escape sequence.
|
|
513
|
+
*/
|
|
514
|
+
private _tryParseEscape;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Maps raw byte sequences to human-readable key names.
|
|
519
|
+
* These are standard VT100/xterm escape sequences.
|
|
520
|
+
*/
|
|
521
|
+
declare const ESCAPE_SEQUENCES: Record<string, string>;
|
|
522
|
+
/**
|
|
523
|
+
* Maps control character codes (0x01-0x1A) to key names.
|
|
524
|
+
* Ctrl+A = 0x01, Ctrl+B = 0x02, ... Ctrl+Z = 0x1A
|
|
525
|
+
*/
|
|
526
|
+
declare const CTRL_KEYS: Record<number, string>;
|
|
527
|
+
/**
|
|
528
|
+
* Special single-byte key codes.
|
|
529
|
+
*/
|
|
530
|
+
declare const SPECIAL_KEYS: Record<number, string>;
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Parse an SGR mouse event escape sequence.
|
|
534
|
+
*
|
|
535
|
+
* SGR format: ESC [ < Cb ; Cx ; Cy M (button press)
|
|
536
|
+
* ESC [ < Cb ; Cx ; Cy m (button release)
|
|
537
|
+
*
|
|
538
|
+
* Where Cb encodes the button and modifiers, Cx/Cy are 1-based coordinates.
|
|
539
|
+
*
|
|
540
|
+
* @returns Parsed MouseEvent or null if not a mouse sequence.
|
|
541
|
+
*/
|
|
542
|
+
declare function parseMouseEvent(data: string): MouseEvent | null;
|
|
543
|
+
/**
|
|
544
|
+
* Check if a string looks like it could be a mouse sequence.
|
|
545
|
+
*/
|
|
546
|
+
declare function isMouseSequence(data: string): boolean;
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Supported border styles.
|
|
550
|
+
*/
|
|
551
|
+
type BorderStyle = 'none' | 'single' | 'double' | 'round' | 'heavy' | 'dashed' | 'custom';
|
|
552
|
+
/**
|
|
553
|
+
* The characters used to draw a border.
|
|
554
|
+
* Layout:
|
|
555
|
+
* ```
|
|
556
|
+
* topLeft ─── top ─── topRight
|
|
557
|
+
* │ │
|
|
558
|
+
* left content right
|
|
559
|
+
* │ │
|
|
560
|
+
* bottomLeft ─ bottom ─ bottomRight
|
|
561
|
+
* ```
|
|
562
|
+
*/
|
|
563
|
+
interface BorderChars {
|
|
564
|
+
topLeft: string;
|
|
565
|
+
top: string;
|
|
566
|
+
topRight: string;
|
|
567
|
+
right: string;
|
|
568
|
+
bottomRight: string;
|
|
569
|
+
bottom: string;
|
|
570
|
+
bottomLeft: string;
|
|
571
|
+
left: string;
|
|
572
|
+
}
|
|
573
|
+
/** Character maps for each border style */
|
|
574
|
+
declare const BORDER_CHARS: Record<Exclude<BorderStyle, 'none' | 'custom'>, BorderChars>;
|
|
575
|
+
/**
|
|
576
|
+
* Get the border characters for a given style.
|
|
577
|
+
*/
|
|
578
|
+
declare function getBorderChars(style: BorderStyle, customChars?: Partial<BorderChars>): BorderChars | null;
|
|
579
|
+
/**
|
|
580
|
+
* Calculate the total space a border takes up.
|
|
581
|
+
* Returns { horizontal, vertical } representing how many columns/rows
|
|
582
|
+
* the border consumes (0 for none, 2 for any visible border — 1 on each side).
|
|
583
|
+
*/
|
|
584
|
+
declare function borderSize(style: BorderStyle): {
|
|
585
|
+
horizontal: number;
|
|
586
|
+
vertical: number;
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Edge values (padding, margin) — top, right, bottom, left.
|
|
591
|
+
*/
|
|
592
|
+
interface Edges {
|
|
593
|
+
top: number;
|
|
594
|
+
right: number;
|
|
595
|
+
bottom: number;
|
|
596
|
+
left: number;
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Complete style definition for a widget.
|
|
600
|
+
*/
|
|
601
|
+
interface Style {
|
|
602
|
+
fg?: Color;
|
|
603
|
+
bg?: Color;
|
|
604
|
+
bold?: boolean;
|
|
605
|
+
italic?: boolean;
|
|
606
|
+
underline?: boolean;
|
|
607
|
+
dim?: boolean;
|
|
608
|
+
strikethrough?: boolean;
|
|
609
|
+
inverse?: boolean;
|
|
610
|
+
padding?: Partial<Edges> | number;
|
|
611
|
+
margin?: Partial<Edges> | number;
|
|
612
|
+
border?: BorderStyle;
|
|
613
|
+
borderColor?: Color;
|
|
614
|
+
width?: number | string;
|
|
615
|
+
height?: number | string;
|
|
616
|
+
minWidth?: number;
|
|
617
|
+
minHeight?: number;
|
|
618
|
+
maxWidth?: number;
|
|
619
|
+
maxHeight?: number;
|
|
620
|
+
flexDirection?: 'row' | 'column';
|
|
621
|
+
justifyContent?: 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around';
|
|
622
|
+
alignItems?: 'flex-start' | 'flex-end' | 'center' | 'stretch';
|
|
623
|
+
flexGrow?: number;
|
|
624
|
+
flexShrink?: number;
|
|
625
|
+
flexWrap?: 'nowrap' | 'wrap';
|
|
626
|
+
gap?: number;
|
|
627
|
+
overflow?: 'visible' | 'hidden' | 'scroll';
|
|
628
|
+
/** Z-index for layer ordering. Higher values render on top. */
|
|
629
|
+
zIndex?: number;
|
|
630
|
+
/** Color of the focus ring when this widget has focus */
|
|
631
|
+
focusRingColor?: Color;
|
|
632
|
+
/** Style of the focus ring indicator */
|
|
633
|
+
focusRingStyle?: 'border' | 'corners' | 'glow' | 'none';
|
|
634
|
+
visible?: boolean;
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Normalize a shorthand edge value (number) into the full Edges object.
|
|
638
|
+
*/
|
|
639
|
+
declare function normalizeEdges(value: Partial<Edges> | number | undefined): Edges;
|
|
640
|
+
/**
|
|
641
|
+
* Merge two styles. `override` values take precedence.
|
|
642
|
+
* Undefined values in override do not overwrite base values.
|
|
643
|
+
*/
|
|
644
|
+
declare function mergeStyles(base: Style, override: Style): Style;
|
|
645
|
+
/**
|
|
646
|
+
* Create a default (empty) style.
|
|
647
|
+
*/
|
|
648
|
+
declare function defaultStyle(): Style;
|
|
649
|
+
/**
|
|
650
|
+
* Extract the cell-level style attributes from a Style object.
|
|
651
|
+
* Used when rendering text into the screen buffer.
|
|
652
|
+
*/
|
|
653
|
+
declare function styleToCellAttrs(style: Style): {
|
|
654
|
+
fg: Color;
|
|
655
|
+
bg: Color;
|
|
656
|
+
bold: boolean;
|
|
657
|
+
italic: boolean;
|
|
658
|
+
underline: boolean;
|
|
659
|
+
dim: boolean;
|
|
660
|
+
strikethrough: boolean;
|
|
661
|
+
inverse: boolean;
|
|
662
|
+
};
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* A node in the layout tree. Each widget produces one LayoutNode.
|
|
666
|
+
*/
|
|
667
|
+
interface LayoutNode {
|
|
668
|
+
/** Reference back to the widget/element that created this node */
|
|
669
|
+
id: string;
|
|
670
|
+
/** Style properties that affect layout */
|
|
671
|
+
style: Style;
|
|
672
|
+
/** Child nodes */
|
|
673
|
+
children: LayoutNode[];
|
|
674
|
+
/** Computed position and size — filled in by computeLayout() */
|
|
675
|
+
computed: Rect;
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Create a LayoutNode with default values.
|
|
679
|
+
*/
|
|
680
|
+
declare function createLayoutNode(id: string, style: Style, children?: LayoutNode[]): LayoutNode;
|
|
681
|
+
/**
|
|
682
|
+
* Compute the layout of a tree of LayoutNodes.
|
|
683
|
+
*
|
|
684
|
+
* This is a simplified Flexbox implementation that handles:
|
|
685
|
+
* - flexDirection: row | column
|
|
686
|
+
* - justifyContent: flex-start | flex-end | center | space-between | space-around
|
|
687
|
+
* - alignItems: flex-start | flex-end | center | stretch
|
|
688
|
+
* - flexGrow / flexShrink
|
|
689
|
+
* - padding, margin, border
|
|
690
|
+
* - fixed width/height, percentage width/height
|
|
691
|
+
* - minWidth, maxWidth, minHeight, maxHeight
|
|
692
|
+
* - gap between children
|
|
693
|
+
*/
|
|
694
|
+
declare function computeLayout(root: LayoutNode, containerWidth: number, containerHeight: number): void;
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Strongly-typed event emitter using TypeScript generics.
|
|
698
|
+
* Supports `on`, `off`, `once`, `emit` with type-safe event maps.
|
|
699
|
+
*/
|
|
700
|
+
declare class EventEmitter<TEventMap extends Record<string, any>> {
|
|
701
|
+
private _handlers;
|
|
702
|
+
private _onceHandlers;
|
|
703
|
+
/**
|
|
704
|
+
* Subscribe to an event.
|
|
705
|
+
* @returns Unsubscribe function.
|
|
706
|
+
*/
|
|
707
|
+
on<K extends keyof TEventMap>(event: K, handler: (data: TEventMap[K]) => void): () => void;
|
|
708
|
+
/**
|
|
709
|
+
* Subscribe to an event, but only fire once.
|
|
710
|
+
*/
|
|
711
|
+
once<K extends keyof TEventMap>(event: K, handler: (data: TEventMap[K]) => void): () => void;
|
|
712
|
+
/**
|
|
713
|
+
* Unsubscribe from an event.
|
|
714
|
+
*/
|
|
715
|
+
off<K extends keyof TEventMap>(event: K, handler: (data: TEventMap[K]) => void): void;
|
|
716
|
+
/**
|
|
717
|
+
* Emit an event to all subscribed handlers.
|
|
718
|
+
*/
|
|
719
|
+
emit<K extends keyof TEventMap>(event: K, data: TEventMap[K]): void;
|
|
720
|
+
/**
|
|
721
|
+
* Remove all handlers for a specific event, or all events if no event specified.
|
|
722
|
+
*/
|
|
723
|
+
removeAll(event?: keyof TEventMap): void;
|
|
724
|
+
/**
|
|
725
|
+
* Check if there are any handlers for an event.
|
|
726
|
+
*/
|
|
727
|
+
hasListeners(event: keyof TEventMap): boolean;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
interface Focusable {
|
|
731
|
+
id: string;
|
|
732
|
+
tabIndex: number;
|
|
733
|
+
focusable: boolean;
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Manages tab-order focus cycling between focusable widgets.
|
|
737
|
+
* Dispatches focus/blur events when focus changes.
|
|
738
|
+
*
|
|
739
|
+
* Supports:
|
|
740
|
+
* - Tab-order cycling (focusNext/focusPrev)
|
|
741
|
+
* - Focus trapping (for modals — limits Tab to a container)
|
|
742
|
+
* - Focus groups (for arrow-key navigation within a group)
|
|
743
|
+
*/
|
|
744
|
+
declare class FocusManager {
|
|
745
|
+
private _focusables;
|
|
746
|
+
private _currentIndex;
|
|
747
|
+
private _events;
|
|
748
|
+
/**
|
|
749
|
+
* Stack of trap container IDs. When non-empty, only focusables
|
|
750
|
+
* that belong to the topmost trap container are reachable via Tab.
|
|
751
|
+
*/
|
|
752
|
+
private _trapStack;
|
|
753
|
+
/**
|
|
754
|
+
* Map of container ID → child widget IDs that belong to it.
|
|
755
|
+
* Used for trap membership lookup.
|
|
756
|
+
*/
|
|
757
|
+
private _containerMembers;
|
|
758
|
+
/**
|
|
759
|
+
* Named focus groups. Arrow keys move within a group, Tab moves between groups.
|
|
760
|
+
* Maps groupId → ordered list of widget IDs.
|
|
761
|
+
*/
|
|
762
|
+
private _groups;
|
|
763
|
+
/** Currently focused widget ID, or null if none */
|
|
764
|
+
get currentId(): string | null;
|
|
765
|
+
/** Subscribe to focus/blur events */
|
|
766
|
+
on<K extends 'focus' | 'blur'>(event: K, handler: (data: FocusEvent) => void): () => void;
|
|
767
|
+
/**
|
|
768
|
+
* Register a focusable widget.
|
|
769
|
+
* Widgets are ordered by tabIndex (ascending), then insertion order.
|
|
770
|
+
*/
|
|
771
|
+
register(focusable: Focusable): void;
|
|
772
|
+
/**
|
|
773
|
+
* Unregister a focusable widget.
|
|
774
|
+
*/
|
|
775
|
+
unregister(id: string): void;
|
|
776
|
+
/**
|
|
777
|
+
* Move focus to the next focusable widget (wraps around).
|
|
778
|
+
* Respects focus traps — if a trap is active, only cycles within it.
|
|
779
|
+
*/
|
|
780
|
+
focusNext(): void;
|
|
781
|
+
/**
|
|
782
|
+
* Move focus to the previous focusable widget (wraps around).
|
|
783
|
+
* Respects focus traps.
|
|
784
|
+
*/
|
|
785
|
+
focusPrev(): void;
|
|
786
|
+
/**
|
|
787
|
+
* Focus a specific widget by ID.
|
|
788
|
+
*/
|
|
789
|
+
focusWidget(id: string): void;
|
|
790
|
+
/**
|
|
791
|
+
* Check if a specific widget currently has focus.
|
|
792
|
+
*/
|
|
793
|
+
isFocused(id: string): boolean;
|
|
794
|
+
/**
|
|
795
|
+
* Register widget IDs as members of a container (for trap lookup).
|
|
796
|
+
*/
|
|
797
|
+
registerContainerMembers(containerId: string, memberIds: string[]): void;
|
|
798
|
+
/**
|
|
799
|
+
* Unregister a container's member list.
|
|
800
|
+
*/
|
|
801
|
+
unregisterContainerMembers(containerId: string): void;
|
|
802
|
+
/**
|
|
803
|
+
* Trap focus within a container. Only focusables inside the
|
|
804
|
+
* container are reachable via Tab. Traps are stacked —
|
|
805
|
+
* nested modals create nested traps.
|
|
806
|
+
*/
|
|
807
|
+
trap(containerId: string): void;
|
|
808
|
+
/**
|
|
809
|
+
* Release the current focus trap. Restores previous trap or free navigation.
|
|
810
|
+
*/
|
|
811
|
+
release(): void;
|
|
812
|
+
/** Whether a focus trap is currently active */
|
|
813
|
+
get isTrapped(): boolean;
|
|
814
|
+
/** ID of the current trap container, or null */
|
|
815
|
+
get currentTrapId(): string | null;
|
|
816
|
+
/**
|
|
817
|
+
* Register a focus group. Arrow keys move within the group.
|
|
818
|
+
* @param groupId Unique group identifier
|
|
819
|
+
* @param widgetIds Ordered list of widget IDs in the group
|
|
820
|
+
*/
|
|
821
|
+
registerGroup(groupId: string, widgetIds: string[]): void;
|
|
822
|
+
/**
|
|
823
|
+
* Unregister a focus group.
|
|
824
|
+
*/
|
|
825
|
+
unregisterGroup(groupId: string): void;
|
|
826
|
+
/**
|
|
827
|
+
* Move focus to the next widget within the same group.
|
|
828
|
+
* Returns true if focus was moved, false if the widget isn't in a group.
|
|
829
|
+
*/
|
|
830
|
+
focusNextInGroup(): boolean;
|
|
831
|
+
/**
|
|
832
|
+
* Move focus to the previous widget within the same group.
|
|
833
|
+
*/
|
|
834
|
+
focusPrevInGroup(): boolean;
|
|
835
|
+
/**
|
|
836
|
+
* Get the active focusables, filtered by the current trap if any.
|
|
837
|
+
*/
|
|
838
|
+
private _getActiveFocusables;
|
|
839
|
+
private _changeFocus;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
interface AppOptions extends TerminalOptions {
|
|
843
|
+
/** Frames per second for the render loop */
|
|
844
|
+
fps?: number;
|
|
845
|
+
/** Use alternate screen (full-screen mode). Default: true */
|
|
846
|
+
fullscreen?: boolean;
|
|
847
|
+
/** Enable mouse support. Default: false */
|
|
848
|
+
mouse?: boolean;
|
|
849
|
+
/** Force fallback (static) rendering */
|
|
850
|
+
forceFallback?: boolean;
|
|
851
|
+
/** Title to set on the terminal window */
|
|
852
|
+
title?: string;
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* Widget interface that App expects for the root widget.
|
|
856
|
+
* This is the minimum contract — the full Widget class in @termuijs/widgets extends this.
|
|
857
|
+
*/
|
|
858
|
+
interface RootWidget {
|
|
859
|
+
id: string;
|
|
860
|
+
getLayoutNode(): LayoutNode;
|
|
861
|
+
syncLayout?(): void;
|
|
862
|
+
render(screen: Screen): void;
|
|
863
|
+
mount?(): void;
|
|
864
|
+
unmount?(): void;
|
|
865
|
+
/** Check if this widget needs re-rendering (dirty flag) */
|
|
866
|
+
isDirty?: boolean;
|
|
867
|
+
/** Clear the dirty flag after rendering */
|
|
868
|
+
clearDirty?(): void;
|
|
869
|
+
}
|
|
870
|
+
/**
|
|
871
|
+
* Application lifecycle manager.
|
|
872
|
+
*
|
|
873
|
+
* Manages:
|
|
874
|
+
* - Terminal setup/teardown (alt screen, raw mode, cursor, mouse)
|
|
875
|
+
* - Screen buffer and renderer initialization
|
|
876
|
+
* - Input parsing and event dispatch
|
|
877
|
+
* - Layout computation and rect sync
|
|
878
|
+
* - Render loop
|
|
879
|
+
* - Graceful shutdown
|
|
880
|
+
*/
|
|
881
|
+
declare class App {
|
|
882
|
+
readonly terminal: Terminal;
|
|
883
|
+
readonly screen: Screen;
|
|
884
|
+
readonly renderer: Renderer;
|
|
885
|
+
readonly input: InputParser;
|
|
886
|
+
readonly focus: FocusManager;
|
|
887
|
+
readonly events: EventEmitter<EventMap>;
|
|
888
|
+
readonly layers: LayerManager;
|
|
889
|
+
private _rootWidget;
|
|
890
|
+
private _options;
|
|
891
|
+
private _mounted;
|
|
892
|
+
private _exitResolve;
|
|
893
|
+
constructor(rootWidget: RootWidget, options?: AppOptions);
|
|
894
|
+
/**
|
|
895
|
+
* Start the application.
|
|
896
|
+
* Sets up the terminal, starts the render loop, and mounts the root widget.
|
|
897
|
+
* Returns a promise that resolves when exit() is called.
|
|
898
|
+
*/
|
|
899
|
+
mount(): Promise<number>;
|
|
900
|
+
/**
|
|
901
|
+
* Stop the application and restore terminal state.
|
|
902
|
+
*/
|
|
903
|
+
unmount(): void;
|
|
904
|
+
/**
|
|
905
|
+
* Create an overlay layer for rendering above normal widgets.
|
|
906
|
+
* @param id Unique layer identifier (e.g. 'modal', 'select-dropdown', 'toast')
|
|
907
|
+
* @param zIndex Stacking order (higher = rendered on top). Default: 100
|
|
908
|
+
*/
|
|
909
|
+
addOverlay(id: string, zIndex?: number): void;
|
|
910
|
+
/**
|
|
911
|
+
* Remove an overlay layer.
|
|
912
|
+
*/
|
|
913
|
+
removeOverlay(id: string): void;
|
|
914
|
+
/**
|
|
915
|
+
* Request a re-render on the next frame.
|
|
916
|
+
*/
|
|
917
|
+
requestRender(): void;
|
|
918
|
+
/**
|
|
919
|
+
* Exit the app (convenience method).
|
|
920
|
+
*/
|
|
921
|
+
exit(code?: number): void;
|
|
922
|
+
/**
|
|
923
|
+
* Render in fallback (static) mode for non-interactive environments.
|
|
924
|
+
*/
|
|
925
|
+
private _renderFallback;
|
|
926
|
+
/**
|
|
927
|
+
* Build the bubble chain for keyboard events.
|
|
928
|
+
* Returns an array: [focused widget, parent, grandparent, ..., root]
|
|
929
|
+
*/
|
|
930
|
+
private _buildBubbleChain;
|
|
931
|
+
/**
|
|
932
|
+
* Find a widget by ID in the widget tree (DFS).
|
|
933
|
+
* Uses duck-typing to work with any object that has id/children.
|
|
934
|
+
*/
|
|
935
|
+
private _findWidgetById;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
/**
|
|
939
|
+
* Detect if the terminal should use fallback (non-interactive) rendering.
|
|
940
|
+
*
|
|
941
|
+
* Returns true when:
|
|
942
|
+
* - stdout is not a TTY (piped)
|
|
943
|
+
* - CI environment variable is set
|
|
944
|
+
* - TERM is 'dumb'
|
|
945
|
+
* - NO_COLOR is set
|
|
946
|
+
*/
|
|
947
|
+
declare function shouldUseFallback(): boolean;
|
|
948
|
+
/**
|
|
949
|
+
* Render a Screen buffer as plain text (no ANSI, no interactivity).
|
|
950
|
+
*
|
|
951
|
+
* Reads all cells from the screen and produces a simple text representation.
|
|
952
|
+
* Strips trailing whitespace from each line and removes empty trailing lines.
|
|
953
|
+
*/
|
|
954
|
+
declare function renderFallback(screen: Screen): string;
|
|
955
|
+
|
|
956
|
+
/**
|
|
957
|
+
* Calculate the visual width of a string in terminal columns.
|
|
958
|
+
*
|
|
959
|
+
* - CJK characters count as 2 columns
|
|
960
|
+
* - Emoji count as 2 columns
|
|
961
|
+
* - Combining/zero-width characters count as 0
|
|
962
|
+
* - ANSI escape sequences count as 0
|
|
963
|
+
* - Regular characters count as 1
|
|
964
|
+
*/
|
|
965
|
+
declare function stringWidth(str: string): number;
|
|
966
|
+
/**
|
|
967
|
+
* Truncate a string to the given visual width, preserving ANSI codes.
|
|
968
|
+
* Appends an ellipsis character if truncated.
|
|
969
|
+
*/
|
|
970
|
+
declare function truncate(str: string, maxWidth: number, ellipsis?: string): string;
|
|
971
|
+
/**
|
|
972
|
+
* Strip all ANSI escape sequences from a string.
|
|
973
|
+
*/
|
|
974
|
+
declare function stripAnsi(str: string): string;
|
|
975
|
+
/**
|
|
976
|
+
* Word-wrap text to a given width, respecting existing newlines.
|
|
977
|
+
* Does not handle ANSI codes within words (wraps at the character level).
|
|
978
|
+
*/
|
|
979
|
+
declare function wordWrap(str: string, width: number): string;
|
|
980
|
+
|
|
981
|
+
/** CSI (Control Sequence Introducer) prefix */
|
|
982
|
+
declare const CSI = "\u001B[";
|
|
983
|
+
/** OSC (Operating System Command) prefix */
|
|
984
|
+
declare const OSC = "\u001B]";
|
|
985
|
+
/** ESC character */
|
|
986
|
+
declare const ESC = "\u001B";
|
|
987
|
+
declare const hideCursor = "\u001B[?25l";
|
|
988
|
+
declare const showCursor = "\u001B[?25h";
|
|
989
|
+
declare const saveCursorPosition = "\u001B[s";
|
|
990
|
+
declare const restoreCursorPosition = "\u001B[u";
|
|
991
|
+
declare function moveTo(col: number, row: number): string;
|
|
992
|
+
declare function moveUp(n?: number): string;
|
|
993
|
+
declare function moveDown(n?: number): string;
|
|
994
|
+
declare function moveRight(n?: number): string;
|
|
995
|
+
declare function moveLeft(n?: number): string;
|
|
996
|
+
declare const clearScreen = "\u001B[2J";
|
|
997
|
+
declare const clearLine = "\u001B[2K";
|
|
998
|
+
declare const clearLineToEnd = "\u001B[0K";
|
|
999
|
+
declare const clearLineToStart = "\u001B[1K";
|
|
1000
|
+
declare const clearDown = "\u001B[J";
|
|
1001
|
+
declare const clearUp = "\u001B[1J";
|
|
1002
|
+
declare const enterAltScreen = "\u001B[?1049h";
|
|
1003
|
+
declare const exitAltScreen = "\u001B[?1049l";
|
|
1004
|
+
/** Begin synchronized update — terminal holds display until end marker */
|
|
1005
|
+
declare const beginSyncUpdate = "\u001B[?2026h";
|
|
1006
|
+
/** End synchronized update — terminal flushes all pending changes atomically */
|
|
1007
|
+
declare const endSyncUpdate = "\u001B[?2026l";
|
|
1008
|
+
/** Enable SGR mouse tracking (most compatible modern mode) */
|
|
1009
|
+
declare const enableMouse = "\u001B[?1000h\u001B[?1002h\u001B[?1006h";
|
|
1010
|
+
/** Disable mouse tracking */
|
|
1011
|
+
declare const disableMouse = "\u001B[?1000l\u001B[?1002l\u001B[?1006l";
|
|
1012
|
+
declare const enableBracketedPaste = "\u001B[?2004h";
|
|
1013
|
+
declare const disableBracketedPaste = "\u001B[?2004l";
|
|
1014
|
+
declare const reset = "\u001B[0m";
|
|
1015
|
+
declare const bold = "\u001B[1m";
|
|
1016
|
+
declare const dim = "\u001B[2m";
|
|
1017
|
+
declare const italic = "\u001B[3m";
|
|
1018
|
+
declare const underline = "\u001B[4m";
|
|
1019
|
+
declare const blink = "\u001B[5m";
|
|
1020
|
+
declare const inverse = "\u001B[7m";
|
|
1021
|
+
declare const strikethrough = "\u001B[9m";
|
|
1022
|
+
declare const resetBold = "\u001B[22m";
|
|
1023
|
+
declare const resetDim = "\u001B[22m";
|
|
1024
|
+
declare const resetItalic = "\u001B[23m";
|
|
1025
|
+
declare const resetUnderline = "\u001B[24m";
|
|
1026
|
+
declare const resetBlink = "\u001B[25m";
|
|
1027
|
+
declare const resetInverse = "\u001B[27m";
|
|
1028
|
+
declare const resetStrikethrough = "\u001B[29m";
|
|
1029
|
+
declare function setScrollRegion(top: number, bottom: number): string;
|
|
1030
|
+
declare const resetScrollRegion = "\u001B[r";
|
|
1031
|
+
declare function setTitle(title: string): string;
|
|
1032
|
+
|
|
1033
|
+
declare const ansi_CSI: typeof CSI;
|
|
1034
|
+
declare const ansi_ESC: typeof ESC;
|
|
1035
|
+
declare const ansi_OSC: typeof OSC;
|
|
1036
|
+
declare const ansi_beginSyncUpdate: typeof beginSyncUpdate;
|
|
1037
|
+
declare const ansi_blink: typeof blink;
|
|
1038
|
+
declare const ansi_bold: typeof bold;
|
|
1039
|
+
declare const ansi_clearDown: typeof clearDown;
|
|
1040
|
+
declare const ansi_clearLine: typeof clearLine;
|
|
1041
|
+
declare const ansi_clearLineToEnd: typeof clearLineToEnd;
|
|
1042
|
+
declare const ansi_clearLineToStart: typeof clearLineToStart;
|
|
1043
|
+
declare const ansi_clearScreen: typeof clearScreen;
|
|
1044
|
+
declare const ansi_clearUp: typeof clearUp;
|
|
1045
|
+
declare const ansi_dim: typeof dim;
|
|
1046
|
+
declare const ansi_disableBracketedPaste: typeof disableBracketedPaste;
|
|
1047
|
+
declare const ansi_disableMouse: typeof disableMouse;
|
|
1048
|
+
declare const ansi_enableBracketedPaste: typeof enableBracketedPaste;
|
|
1049
|
+
declare const ansi_enableMouse: typeof enableMouse;
|
|
1050
|
+
declare const ansi_endSyncUpdate: typeof endSyncUpdate;
|
|
1051
|
+
declare const ansi_enterAltScreen: typeof enterAltScreen;
|
|
1052
|
+
declare const ansi_exitAltScreen: typeof exitAltScreen;
|
|
1053
|
+
declare const ansi_hideCursor: typeof hideCursor;
|
|
1054
|
+
declare const ansi_inverse: typeof inverse;
|
|
1055
|
+
declare const ansi_italic: typeof italic;
|
|
1056
|
+
declare const ansi_moveDown: typeof moveDown;
|
|
1057
|
+
declare const ansi_moveLeft: typeof moveLeft;
|
|
1058
|
+
declare const ansi_moveRight: typeof moveRight;
|
|
1059
|
+
declare const ansi_moveTo: typeof moveTo;
|
|
1060
|
+
declare const ansi_moveUp: typeof moveUp;
|
|
1061
|
+
declare const ansi_reset: typeof reset;
|
|
1062
|
+
declare const ansi_resetBlink: typeof resetBlink;
|
|
1063
|
+
declare const ansi_resetBold: typeof resetBold;
|
|
1064
|
+
declare const ansi_resetDim: typeof resetDim;
|
|
1065
|
+
declare const ansi_resetInverse: typeof resetInverse;
|
|
1066
|
+
declare const ansi_resetItalic: typeof resetItalic;
|
|
1067
|
+
declare const ansi_resetScrollRegion: typeof resetScrollRegion;
|
|
1068
|
+
declare const ansi_resetStrikethrough: typeof resetStrikethrough;
|
|
1069
|
+
declare const ansi_resetUnderline: typeof resetUnderline;
|
|
1070
|
+
declare const ansi_restoreCursorPosition: typeof restoreCursorPosition;
|
|
1071
|
+
declare const ansi_saveCursorPosition: typeof saveCursorPosition;
|
|
1072
|
+
declare const ansi_setScrollRegion: typeof setScrollRegion;
|
|
1073
|
+
declare const ansi_setTitle: typeof setTitle;
|
|
1074
|
+
declare const ansi_showCursor: typeof showCursor;
|
|
1075
|
+
declare const ansi_strikethrough: typeof strikethrough;
|
|
1076
|
+
declare const ansi_underline: typeof underline;
|
|
1077
|
+
declare namespace ansi {
|
|
1078
|
+
export { ansi_CSI as CSI, ansi_ESC as ESC, ansi_OSC as OSC, ansi_beginSyncUpdate as beginSyncUpdate, ansi_blink as blink, ansi_bold as bold, ansi_clearDown as clearDown, ansi_clearLine as clearLine, ansi_clearLineToEnd as clearLineToEnd, ansi_clearLineToStart as clearLineToStart, ansi_clearScreen as clearScreen, ansi_clearUp as clearUp, ansi_dim as dim, ansi_disableBracketedPaste as disableBracketedPaste, ansi_disableMouse as disableMouse, ansi_enableBracketedPaste as enableBracketedPaste, ansi_enableMouse as enableMouse, ansi_endSyncUpdate as endSyncUpdate, ansi_enterAltScreen as enterAltScreen, ansi_exitAltScreen as exitAltScreen, ansi_hideCursor as hideCursor, ansi_inverse as inverse, ansi_italic as italic, ansi_moveDown as moveDown, ansi_moveLeft as moveLeft, ansi_moveRight as moveRight, ansi_moveTo as moveTo, ansi_moveUp as moveUp, ansi_reset as reset, ansi_resetBlink as resetBlink, ansi_resetBold as resetBold, ansi_resetDim as resetDim, ansi_resetInverse as resetInverse, ansi_resetItalic as resetItalic, ansi_resetScrollRegion as resetScrollRegion, ansi_resetStrikethrough as resetStrikethrough, ansi_resetUnderline as resetUnderline, ansi_restoreCursorPosition as restoreCursorPosition, ansi_saveCursorPosition as saveCursorPosition, ansi_setScrollRegion as setScrollRegion, ansi_setTitle as setTitle, ansi_showCursor as showCursor, ansi_strikethrough as strikethrough, ansi_underline as underline };
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
export { App, type AppOptions, BORDER_CHARS, type BorderChars, type BorderStyle, CTRL_KEYS, type Cell, type Color, ColorDepth, ESCAPE_SEQUENCES, type Edges, EventEmitter, type EventMap, type FocusEvent, FocusManager, type Focusable, InputParser, type KeyEvent, type Layer, LayerManager, type LayoutNode, type MouseEvent, type NamedColor, type Rect, Renderer, type ResizeEvent, type RootWidget, SPECIAL_KEYS, Screen, type Size, type Style, Terminal, type TerminalOptions, ansi, borderSize, cellsEqual, colorToAnsiBg, colorToAnsiFg, colorToRgb, computeLayout, containsPoint, createKeyEvent, createLayoutNode, defaultStyle, detectColorDepth, emptyCell, emptyRect, getBorderChars, intersectRect, isMouseSequence, mergeStyles, normalizeEdges, parseColor, parseMouseEvent, renderFallback, shouldUseFallback, shrinkRect, stringWidth, stripAnsi, styleToCellAttrs, truncate, unionRect, wordWrap };
|