@cli-use/tui 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/LICENSE +21 -0
- package/README.md +125 -0
- package/dist/cli/index.cjs +549 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +526 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/hooks/index.cjs +309 -0
- package/dist/hooks/index.cjs.map +1 -0
- package/dist/hooks/index.d.cts +4 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.js +280 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index-DAO84gkm.d.cts +272 -0
- package/dist/index-DAO84gkm.d.ts +272 -0
- package/dist/index.cjs +970 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +181 -0
- package/dist/index.d.ts +181 -0
- package/dist/index.js +917 -0
- package/dist/index.js.map +1 -0
- package/package.json +99 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,970 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license MIT
|
|
3
|
+
* cli-use - React-based Terminal UI Framework
|
|
4
|
+
* Inspired by Ratatui (https://ratatui.rs)
|
|
5
|
+
*/
|
|
6
|
+
"use strict";
|
|
7
|
+
var __create = Object.create;
|
|
8
|
+
var __defProp = Object.defineProperty;
|
|
9
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
10
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
11
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
12
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
13
|
+
var __export = (target, all) => {
|
|
14
|
+
for (var name in all)
|
|
15
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
16
|
+
};
|
|
17
|
+
var __copyProps = (to, from, except, desc) => {
|
|
18
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
19
|
+
for (let key of __getOwnPropNames(from))
|
|
20
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
21
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
22
|
+
}
|
|
23
|
+
return to;
|
|
24
|
+
};
|
|
25
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
26
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
27
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
28
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
29
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
30
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
31
|
+
mod
|
|
32
|
+
));
|
|
33
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
34
|
+
|
|
35
|
+
// src/index.ts
|
|
36
|
+
var index_exports = {};
|
|
37
|
+
__export(index_exports, {
|
|
38
|
+
ANSI: () => ANSI,
|
|
39
|
+
Box: () => Box,
|
|
40
|
+
Buffer: () => Buffer2,
|
|
41
|
+
Button: () => Button,
|
|
42
|
+
Flex: () => Flex,
|
|
43
|
+
Grid: () => Grid,
|
|
44
|
+
Input: () => Input,
|
|
45
|
+
Progress: () => Progress,
|
|
46
|
+
React: () => import_react15.default,
|
|
47
|
+
Renderer: () => Renderer,
|
|
48
|
+
Terminal: () => Terminal,
|
|
49
|
+
Text: () => Text,
|
|
50
|
+
createRoot: () => createRoot,
|
|
51
|
+
render: () => render,
|
|
52
|
+
useApp: () => useApp,
|
|
53
|
+
useAppState: () => useAppState,
|
|
54
|
+
useFocus: () => useFocus,
|
|
55
|
+
useInput: () => useInput,
|
|
56
|
+
useInterval: () => useInterval,
|
|
57
|
+
useKey: () => useKey,
|
|
58
|
+
useList: () => useList,
|
|
59
|
+
useStdout: () => useStdout,
|
|
60
|
+
useStdoutDimensions: () => useStdoutDimensions,
|
|
61
|
+
useTimeout: () => useTimeout
|
|
62
|
+
});
|
|
63
|
+
module.exports = __toCommonJS(index_exports);
|
|
64
|
+
|
|
65
|
+
// src/renderer/types.ts
|
|
66
|
+
var Buffer2 = class _Buffer {
|
|
67
|
+
constructor(width, height, cells = []) {
|
|
68
|
+
this.width = width;
|
|
69
|
+
this.height = height;
|
|
70
|
+
this.cells = cells;
|
|
71
|
+
this.cells = Array.from(
|
|
72
|
+
{ length: height },
|
|
73
|
+
() => Array.from({ length: width }, () => ({ char: " " }))
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
setCell(x, y, cell) {
|
|
77
|
+
if (y >= 0 && y < this.height && x >= 0 && x < this.width) {
|
|
78
|
+
this.cells[y][x] = cell;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
getCell(x, y) {
|
|
82
|
+
if (y >= 0 && y < this.height && x >= 0 && x < this.width) {
|
|
83
|
+
return this.cells[y][x];
|
|
84
|
+
}
|
|
85
|
+
return void 0;
|
|
86
|
+
}
|
|
87
|
+
clear() {
|
|
88
|
+
this.cells = Array.from(
|
|
89
|
+
{ length: this.height },
|
|
90
|
+
() => Array.from({ length: this.width }, () => ({ char: " " }))
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
resize(width, height) {
|
|
94
|
+
const newCells = Array.from(
|
|
95
|
+
{ length: height },
|
|
96
|
+
() => Array.from({ length: width }, () => ({ char: " " }))
|
|
97
|
+
);
|
|
98
|
+
for (let y = 0; y < Math.min(this.height, height); y++) {
|
|
99
|
+
for (let x = 0; x < Math.min(this.width, width); x++) {
|
|
100
|
+
newCells[y][x] = this.cells[y][x];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
this.cells = newCells;
|
|
104
|
+
this.width = width;
|
|
105
|
+
this.height = height;
|
|
106
|
+
}
|
|
107
|
+
clone() {
|
|
108
|
+
const newBuffer = new _Buffer(this.width, this.height);
|
|
109
|
+
newBuffer.cells = this.cells.map((row) => row.map((cell) => ({ ...cell })));
|
|
110
|
+
return newBuffer;
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// src/renderer/terminal.ts
|
|
115
|
+
var readline = __toESM(require("readline"), 1);
|
|
116
|
+
var ANSI = {
|
|
117
|
+
// Screen control
|
|
118
|
+
CLEAR_SCREEN: "\x1B[2J",
|
|
119
|
+
RESET_CURSOR: "\x1B[H",
|
|
120
|
+
ALTERNATE_SCREEN_ENABLE: "\x1B[?1049h",
|
|
121
|
+
ALTERNATE_SCREEN_DISABLE: "\x1B[?1049l",
|
|
122
|
+
// Cursor control
|
|
123
|
+
HIDE_CURSOR: "\x1B[?25l",
|
|
124
|
+
SHOW_CURSOR: "\x1B[?25h",
|
|
125
|
+
MOVE_CURSOR: (x, y) => `\x1B[${y + 1};${x + 1}H`,
|
|
126
|
+
// Colors
|
|
127
|
+
RESET_STYLE: "\x1B[0m",
|
|
128
|
+
FG_COLOR_256: (color) => `\x1B[38;5;${color}m`,
|
|
129
|
+
BG_COLOR_256: (color) => `\x1B[48;5;${color}m`,
|
|
130
|
+
FG_COLOR_RGB: (r, g, b) => `\x1B[38;2;${r};${g};${b}m`,
|
|
131
|
+
BG_COLOR_RGB: (r, g, b) => `\x1B[48;2;${r};${g};${b}m`,
|
|
132
|
+
// Text styles
|
|
133
|
+
BOLD: "\x1B[1m",
|
|
134
|
+
DIM: "\x1B[2m",
|
|
135
|
+
ITALIC: "\x1B[3m",
|
|
136
|
+
UNDERLINE: "\x1B[4m",
|
|
137
|
+
STRIKETHROUGH: "\x1B[9m",
|
|
138
|
+
// Reset individual styles
|
|
139
|
+
BOLD_OFF: "\x1B[22m",
|
|
140
|
+
DIM_OFF: "\x1B[22m",
|
|
141
|
+
ITALIC_OFF: "\x1B[23m",
|
|
142
|
+
UNDERLINE_OFF: "\x1B[24m",
|
|
143
|
+
STRIKETHROUGH_OFF: "\x1B[29m"
|
|
144
|
+
};
|
|
145
|
+
var Terminal = class {
|
|
146
|
+
stdin;
|
|
147
|
+
stdout;
|
|
148
|
+
_size;
|
|
149
|
+
rawMode = false;
|
|
150
|
+
alternateScreen = false;
|
|
151
|
+
constructor(stdin = process.stdin, stdout = process.stdout) {
|
|
152
|
+
this.stdin = stdin;
|
|
153
|
+
this.stdout = stdout;
|
|
154
|
+
this._size = { cols: stdout.columns || 80, rows: stdout.rows || 24 };
|
|
155
|
+
}
|
|
156
|
+
get size() {
|
|
157
|
+
return this._size;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Enable raw mode for character-by-character input
|
|
161
|
+
*/
|
|
162
|
+
enableRawMode() {
|
|
163
|
+
if (this.rawMode) return;
|
|
164
|
+
this.rawMode = true;
|
|
165
|
+
readline.emitKeypressEvents(this.stdin);
|
|
166
|
+
this.stdin.setRawMode(true);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Disable raw mode
|
|
170
|
+
*/
|
|
171
|
+
disableRawMode() {
|
|
172
|
+
if (!this.rawMode) return;
|
|
173
|
+
this.rawMode = false;
|
|
174
|
+
this.stdin.setRawMode(false);
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Enable alternate screen buffer
|
|
178
|
+
*/
|
|
179
|
+
enableAlternateScreen() {
|
|
180
|
+
if (this.alternateScreen) return;
|
|
181
|
+
this.alternateScreen = true;
|
|
182
|
+
this.stdout.write(ANSI.ALTERNATE_SCREEN_ENABLE);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Disable alternate screen buffer
|
|
186
|
+
*/
|
|
187
|
+
disableAlternateScreen() {
|
|
188
|
+
if (!this.alternateScreen) return;
|
|
189
|
+
this.alternateScreen = false;
|
|
190
|
+
this.stdout.write(ANSI.ALTERNATE_SCREEN_DISABLE);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Hide cursor
|
|
194
|
+
*/
|
|
195
|
+
hideCursor() {
|
|
196
|
+
this.stdout.write(ANSI.HIDE_CURSOR);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Show cursor
|
|
200
|
+
*/
|
|
201
|
+
showCursor() {
|
|
202
|
+
this.stdout.write(ANSI.SHOW_CURSOR);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Clear the entire screen
|
|
206
|
+
*/
|
|
207
|
+
clear() {
|
|
208
|
+
this.stdout.write(ANSI.CLEAR_SCREEN + ANSI.RESET_CURSOR);
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Write buffer to terminal
|
|
212
|
+
*/
|
|
213
|
+
write(buffer) {
|
|
214
|
+
let output = ANSI.RESET_STYLE;
|
|
215
|
+
let lastStyle = null;
|
|
216
|
+
for (let y = 0; y < buffer.height; y++) {
|
|
217
|
+
for (let x = 0; x < buffer.width; x++) {
|
|
218
|
+
const cell = buffer.getCell(x, y);
|
|
219
|
+
if (!cell) continue;
|
|
220
|
+
const style = this.buildStyleString(cell);
|
|
221
|
+
if (style !== lastStyle) {
|
|
222
|
+
output += style;
|
|
223
|
+
lastStyle = style;
|
|
224
|
+
}
|
|
225
|
+
output += cell.char;
|
|
226
|
+
}
|
|
227
|
+
output += "\r\n";
|
|
228
|
+
}
|
|
229
|
+
this.stdout.write(output);
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Build ANSI style string from cell
|
|
233
|
+
*/
|
|
234
|
+
buildStyleString(cell) {
|
|
235
|
+
let style = "";
|
|
236
|
+
if (cell.fg !== void 0) {
|
|
237
|
+
style += ANSI.FG_COLOR_256(cell.fg);
|
|
238
|
+
}
|
|
239
|
+
if (cell.bg !== void 0) {
|
|
240
|
+
style += ANSI.BG_COLOR_256(cell.bg);
|
|
241
|
+
}
|
|
242
|
+
if (cell.bold) {
|
|
243
|
+
style += ANSI.BOLD;
|
|
244
|
+
}
|
|
245
|
+
if (cell.dim) {
|
|
246
|
+
style += ANSI.DIM;
|
|
247
|
+
}
|
|
248
|
+
return style;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Set up SIGWINCH handler for terminal resize
|
|
252
|
+
*/
|
|
253
|
+
onResize(callback) {
|
|
254
|
+
const handler = () => {
|
|
255
|
+
this._size = { cols: this.stdout.columns || 80, rows: this.stdout.rows || 24 };
|
|
256
|
+
callback(this._size);
|
|
257
|
+
};
|
|
258
|
+
process.on("SIGWINCH", handler);
|
|
259
|
+
return () => {
|
|
260
|
+
process.off("SIGWINCH", handler);
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Set up input handler
|
|
265
|
+
*/
|
|
266
|
+
onInput(callback) {
|
|
267
|
+
const handler = (chunk, key) => {
|
|
268
|
+
callback(chunk, key);
|
|
269
|
+
};
|
|
270
|
+
this.stdin.on("keypress", handler);
|
|
271
|
+
return () => {
|
|
272
|
+
this.stdin.off("keypress", handler);
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Clean up terminal state
|
|
277
|
+
*/
|
|
278
|
+
restore() {
|
|
279
|
+
this.showCursor();
|
|
280
|
+
this.disableAlternateScreen();
|
|
281
|
+
this.disableRawMode();
|
|
282
|
+
this.stdout.write(ANSI.RESET_STYLE);
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
// src/renderer/renderer.ts
|
|
287
|
+
var Renderer = class {
|
|
288
|
+
terminal;
|
|
289
|
+
buffer;
|
|
290
|
+
previousBuffer;
|
|
291
|
+
currentSize;
|
|
292
|
+
running = false;
|
|
293
|
+
constructor(terminal = new Terminal()) {
|
|
294
|
+
this.terminal = terminal;
|
|
295
|
+
this.currentSize = terminal.size;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Start the renderer
|
|
299
|
+
*/
|
|
300
|
+
start() {
|
|
301
|
+
if (this.running) return;
|
|
302
|
+
this.running = true;
|
|
303
|
+
this.terminal.enableRawMode();
|
|
304
|
+
this.terminal.enableAlternateScreen();
|
|
305
|
+
this.terminal.hideCursor();
|
|
306
|
+
this.terminal.clear();
|
|
307
|
+
this.buffer = new Buffer2(this.currentSize.cols, this.currentSize.rows);
|
|
308
|
+
this.terminal.onResize((size) => {
|
|
309
|
+
this.currentSize = size;
|
|
310
|
+
this.buffer?.resize(size.cols, size.rows);
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Stop the renderer
|
|
315
|
+
*/
|
|
316
|
+
stop() {
|
|
317
|
+
if (!this.running) return;
|
|
318
|
+
this.running = false;
|
|
319
|
+
this.terminal.restore();
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Get a writable buffer for the current frame
|
|
323
|
+
*/
|
|
324
|
+
getBuffer() {
|
|
325
|
+
if (!this.buffer) {
|
|
326
|
+
throw new Error("Renderer not started");
|
|
327
|
+
}
|
|
328
|
+
return this.buffer;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Present the current buffer to the terminal
|
|
332
|
+
*/
|
|
333
|
+
present() {
|
|
334
|
+
if (!this.buffer) return;
|
|
335
|
+
this.terminal.write(this.buffer);
|
|
336
|
+
this.previousBuffer = this.buffer.clone();
|
|
337
|
+
this.buffer.clear();
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Get the current terminal size
|
|
341
|
+
*/
|
|
342
|
+
getSize() {
|
|
343
|
+
return this.currentSize;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Get the terminal instance for direct access
|
|
347
|
+
*/
|
|
348
|
+
getTerminal() {
|
|
349
|
+
return this.terminal;
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
// src/reconciler/index.ts
|
|
354
|
+
var import_react_reconciler = __toESM(require("react-reconciler"), 1);
|
|
355
|
+
|
|
356
|
+
// src/reconciler/host-config.ts
|
|
357
|
+
var hostConfig = {
|
|
358
|
+
supportsPersistence: false,
|
|
359
|
+
supportsMutation: true,
|
|
360
|
+
createInstance(type, props) {
|
|
361
|
+
return { type, props: { ...props }, children: [], parent: null, node: { type, props: { ...props }, children: [] } };
|
|
362
|
+
},
|
|
363
|
+
appendInitialChild(parentInstance, child) {
|
|
364
|
+
parentInstance.children.push(child);
|
|
365
|
+
child.parent = parentInstance;
|
|
366
|
+
},
|
|
367
|
+
finalizeInitialChildren() {
|
|
368
|
+
return false;
|
|
369
|
+
},
|
|
370
|
+
prepareUpdate() {
|
|
371
|
+
return {};
|
|
372
|
+
},
|
|
373
|
+
shouldSetTextContent(type) {
|
|
374
|
+
return type === "TEXT";
|
|
375
|
+
},
|
|
376
|
+
createTextInstance(text) {
|
|
377
|
+
return { type: "TEXT", props: { children: text }, children: [], parent: null, node: { type: "TEXT", props: { children: text }, children: [] } };
|
|
378
|
+
},
|
|
379
|
+
appendChildToContainer(container, child) {
|
|
380
|
+
container.root = child;
|
|
381
|
+
child.parent = null;
|
|
382
|
+
},
|
|
383
|
+
appendChild(parentInstance, child) {
|
|
384
|
+
parentInstance.children.push(child);
|
|
385
|
+
child.parent = parentInstance;
|
|
386
|
+
},
|
|
387
|
+
removeChild(parentInstance, child) {
|
|
388
|
+
const index = parentInstance.children.indexOf(child);
|
|
389
|
+
if (index !== -1) {
|
|
390
|
+
parentInstance.children.splice(index, 1);
|
|
391
|
+
child.parent = null;
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
removeChildFromContainer(_container, child) {
|
|
395
|
+
child.parent = null;
|
|
396
|
+
},
|
|
397
|
+
insertBefore(parentInstance, child, beforeChild) {
|
|
398
|
+
const index = parentInstance.children.indexOf(beforeChild);
|
|
399
|
+
if (index !== -1) {
|
|
400
|
+
parentInstance.children.splice(index, 0, child);
|
|
401
|
+
} else {
|
|
402
|
+
parentInstance.children.push(child);
|
|
403
|
+
}
|
|
404
|
+
child.parent = parentInstance;
|
|
405
|
+
},
|
|
406
|
+
insertInContainerBefore() {
|
|
407
|
+
},
|
|
408
|
+
commitUpdate(instance, _updatePayload, _type, _oldProps, newProps) {
|
|
409
|
+
instance.props = { ...newProps };
|
|
410
|
+
instance.node.props = { ...newProps };
|
|
411
|
+
},
|
|
412
|
+
commitTextUpdate(textInstance, _oldText, newText) {
|
|
413
|
+
textInstance.props.children = newText;
|
|
414
|
+
textInstance.node.props.children = newText;
|
|
415
|
+
},
|
|
416
|
+
resetTextContent(instance) {
|
|
417
|
+
if (instance.type === "TEXT") {
|
|
418
|
+
instance.props.children = "";
|
|
419
|
+
instance.node.props.children = "";
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
getPublicInstance(instance) {
|
|
423
|
+
return instance;
|
|
424
|
+
},
|
|
425
|
+
getRootHostContext(rootContainer) {
|
|
426
|
+
return rootContainer;
|
|
427
|
+
},
|
|
428
|
+
getChildHostContext(parentHostContext) {
|
|
429
|
+
return parentHostContext;
|
|
430
|
+
},
|
|
431
|
+
prepareForCommit() {
|
|
432
|
+
return null;
|
|
433
|
+
},
|
|
434
|
+
resetAfterCommit(container) {
|
|
435
|
+
if (container.root) {
|
|
436
|
+
renderToBuffer(container.root, container.buffer);
|
|
437
|
+
}
|
|
438
|
+
},
|
|
439
|
+
shouldAttemptEagerTransition() {
|
|
440
|
+
return false;
|
|
441
|
+
},
|
|
442
|
+
scheduleTimeout: setTimeout,
|
|
443
|
+
cancelTimeout: clearTimeout,
|
|
444
|
+
noTimeout: -1,
|
|
445
|
+
getCurrentEventPriority() {
|
|
446
|
+
return 0;
|
|
447
|
+
},
|
|
448
|
+
getInstanceFromNode(node) {
|
|
449
|
+
return node;
|
|
450
|
+
},
|
|
451
|
+
beforeActiveInstanceBlur() {
|
|
452
|
+
},
|
|
453
|
+
afterActiveInstanceBlur() {
|
|
454
|
+
},
|
|
455
|
+
preparePortalMount() {
|
|
456
|
+
},
|
|
457
|
+
prepareScopeUpdate() {
|
|
458
|
+
},
|
|
459
|
+
getInstanceFromScope() {
|
|
460
|
+
return null;
|
|
461
|
+
},
|
|
462
|
+
detachDeletedInstance() {
|
|
463
|
+
},
|
|
464
|
+
isPrimaryRenderer: true,
|
|
465
|
+
supportsHydration: false
|
|
466
|
+
};
|
|
467
|
+
function renderToBuffer(instance, buffer, x = 0, y = 0) {
|
|
468
|
+
if (!instance) return;
|
|
469
|
+
const { type, props, children } = instance;
|
|
470
|
+
const currentX = props.x ?? x;
|
|
471
|
+
const currentY = props.y ?? y;
|
|
472
|
+
if (type === "TEXT" || typeof props.children === "string") {
|
|
473
|
+
const text = String(props.children || "");
|
|
474
|
+
const style = props.style || {};
|
|
475
|
+
for (let i = 0; i < text.length; i++) {
|
|
476
|
+
const char = text[i];
|
|
477
|
+
if (char === "\n") continue;
|
|
478
|
+
buffer.setCell(currentX + i, currentY, { char, ...style });
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
if (Array.isArray(children)) {
|
|
482
|
+
for (const child of children) {
|
|
483
|
+
renderToBuffer(child, buffer, currentX, currentY);
|
|
484
|
+
}
|
|
485
|
+
} else if (children) {
|
|
486
|
+
renderToBuffer(children, buffer, currentX, currentY);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// src/reconciler/index.ts
|
|
491
|
+
var createReconciler = () => (0, import_react_reconciler.default)(hostConfig);
|
|
492
|
+
var createRoot = (renderer) => {
|
|
493
|
+
const buffer = renderer.getBuffer();
|
|
494
|
+
return {
|
|
495
|
+
buffer,
|
|
496
|
+
root: null,
|
|
497
|
+
listeners: {}
|
|
498
|
+
};
|
|
499
|
+
};
|
|
500
|
+
var render = (element, container, renderer) => {
|
|
501
|
+
const reconciler = createReconciler();
|
|
502
|
+
reconciler.updateContainer(element, container, null, () => {
|
|
503
|
+
renderer.present();
|
|
504
|
+
});
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
// src/components/Box.tsx
|
|
508
|
+
var import_react = __toESM(require("react"), 1);
|
|
509
|
+
var Box = ({
|
|
510
|
+
children,
|
|
511
|
+
style,
|
|
512
|
+
x = 0,
|
|
513
|
+
y = 0,
|
|
514
|
+
width,
|
|
515
|
+
height,
|
|
516
|
+
border = false,
|
|
517
|
+
flexDirection = "column",
|
|
518
|
+
justifyContent = "flex-start",
|
|
519
|
+
alignItems = "flex-start",
|
|
520
|
+
padding = 0
|
|
521
|
+
}) => {
|
|
522
|
+
const props = {
|
|
523
|
+
children,
|
|
524
|
+
style,
|
|
525
|
+
x,
|
|
526
|
+
y,
|
|
527
|
+
width,
|
|
528
|
+
height,
|
|
529
|
+
border,
|
|
530
|
+
flexDirection,
|
|
531
|
+
justifyContent,
|
|
532
|
+
alignItems,
|
|
533
|
+
padding
|
|
534
|
+
};
|
|
535
|
+
return import_react.default.createElement("BOX", props, children);
|
|
536
|
+
};
|
|
537
|
+
Box.displayName = "Box";
|
|
538
|
+
|
|
539
|
+
// src/components/Text.tsx
|
|
540
|
+
var import_react2 = __toESM(require("react"), 1);
|
|
541
|
+
var Text = ({ children, style, x = 0, y = 0 }) => {
|
|
542
|
+
const props = {
|
|
543
|
+
children: String(children),
|
|
544
|
+
style,
|
|
545
|
+
x,
|
|
546
|
+
y
|
|
547
|
+
};
|
|
548
|
+
return import_react2.default.createElement("TEXT", props);
|
|
549
|
+
};
|
|
550
|
+
Text.displayName = "Text";
|
|
551
|
+
|
|
552
|
+
// src/components/Flex.tsx
|
|
553
|
+
var import_react3 = __toESM(require("react"), 1);
|
|
554
|
+
var Flex = ({
|
|
555
|
+
children,
|
|
556
|
+
grow = 0,
|
|
557
|
+
shrink = 1,
|
|
558
|
+
basis = "auto",
|
|
559
|
+
...boxProps
|
|
560
|
+
}) => {
|
|
561
|
+
const props = {
|
|
562
|
+
...boxProps,
|
|
563
|
+
children
|
|
564
|
+
};
|
|
565
|
+
return import_react3.default.createElement("FLEX", props);
|
|
566
|
+
};
|
|
567
|
+
Flex.displayName = "Flex";
|
|
568
|
+
|
|
569
|
+
// src/components/Grid.tsx
|
|
570
|
+
var import_react4 = __toESM(require("react"), 1);
|
|
571
|
+
var Grid = ({
|
|
572
|
+
children,
|
|
573
|
+
columns = 2,
|
|
574
|
+
rows,
|
|
575
|
+
gap = 1,
|
|
576
|
+
style,
|
|
577
|
+
x = 0,
|
|
578
|
+
y = 0,
|
|
579
|
+
width,
|
|
580
|
+
height
|
|
581
|
+
}) => {
|
|
582
|
+
const props = {
|
|
583
|
+
children,
|
|
584
|
+
columns,
|
|
585
|
+
rows,
|
|
586
|
+
gap,
|
|
587
|
+
style,
|
|
588
|
+
x,
|
|
589
|
+
y,
|
|
590
|
+
width,
|
|
591
|
+
height
|
|
592
|
+
};
|
|
593
|
+
return import_react4.default.createElement("GRID", props, children);
|
|
594
|
+
};
|
|
595
|
+
Grid.displayName = "Grid";
|
|
596
|
+
|
|
597
|
+
// src/components/Button.tsx
|
|
598
|
+
var import_react5 = __toESM(require("react"), 1);
|
|
599
|
+
var Button = ({
|
|
600
|
+
children,
|
|
601
|
+
onClick,
|
|
602
|
+
focused = false,
|
|
603
|
+
style,
|
|
604
|
+
x = 0,
|
|
605
|
+
y = 0
|
|
606
|
+
}) => {
|
|
607
|
+
const activeStyle = focused ? {
|
|
608
|
+
...style,
|
|
609
|
+
fg: style?.focusedFg || style?.fg || 0,
|
|
610
|
+
bg: style?.focusedBg || style?.bg || 7
|
|
611
|
+
} : style;
|
|
612
|
+
const props = {
|
|
613
|
+
children: `[ ${children} ]`,
|
|
614
|
+
onClick,
|
|
615
|
+
focused,
|
|
616
|
+
style: activeStyle,
|
|
617
|
+
x,
|
|
618
|
+
y
|
|
619
|
+
};
|
|
620
|
+
return import_react5.default.createElement("BUTTON", props);
|
|
621
|
+
};
|
|
622
|
+
Button.displayName = "Button";
|
|
623
|
+
|
|
624
|
+
// src/components/Input.tsx
|
|
625
|
+
var import_react6 = __toESM(require("react"), 1);
|
|
626
|
+
var Input = ({
|
|
627
|
+
value,
|
|
628
|
+
onChange,
|
|
629
|
+
placeholder = "",
|
|
630
|
+
focused = false,
|
|
631
|
+
mask = false,
|
|
632
|
+
style,
|
|
633
|
+
x = 0,
|
|
634
|
+
y = 0,
|
|
635
|
+
width = 20,
|
|
636
|
+
maxLength
|
|
637
|
+
}) => {
|
|
638
|
+
const displayValue = mask ? "*".repeat(value.length) : value;
|
|
639
|
+
const displayText = value.length > 0 ? displayValue : focused ? placeholder : "";
|
|
640
|
+
const props = {
|
|
641
|
+
value: displayText,
|
|
642
|
+
onChange,
|
|
643
|
+
placeholder,
|
|
644
|
+
focused,
|
|
645
|
+
mask,
|
|
646
|
+
style: focused ? style : {
|
|
647
|
+
...style,
|
|
648
|
+
fg: style?.placeholderFg || 8
|
|
649
|
+
},
|
|
650
|
+
x,
|
|
651
|
+
y,
|
|
652
|
+
width,
|
|
653
|
+
maxLength
|
|
654
|
+
};
|
|
655
|
+
return import_react6.default.createElement("INPUT", props);
|
|
656
|
+
};
|
|
657
|
+
Input.displayName = "Input";
|
|
658
|
+
|
|
659
|
+
// src/components/Progress.tsx
|
|
660
|
+
var import_react7 = __toESM(require("react"), 1);
|
|
661
|
+
var Progress = ({
|
|
662
|
+
value,
|
|
663
|
+
max = 100,
|
|
664
|
+
style,
|
|
665
|
+
x = 0,
|
|
666
|
+
y = 0,
|
|
667
|
+
width = 20,
|
|
668
|
+
label
|
|
669
|
+
}) => {
|
|
670
|
+
const percentage = Math.min(Math.max(value / max, 0), 1);
|
|
671
|
+
const filledWidth = Math.floor(percentage * width);
|
|
672
|
+
const props = {
|
|
673
|
+
value,
|
|
674
|
+
max,
|
|
675
|
+
style,
|
|
676
|
+
x,
|
|
677
|
+
y,
|
|
678
|
+
width,
|
|
679
|
+
label
|
|
680
|
+
};
|
|
681
|
+
return import_react7.default.createElement("PROGRESS", props);
|
|
682
|
+
};
|
|
683
|
+
Progress.displayName = "Progress";
|
|
684
|
+
|
|
685
|
+
// src/hooks/useApp.ts
|
|
686
|
+
var import_react8 = require("react");
|
|
687
|
+
var useApp = (options = {}) => {
|
|
688
|
+
const rendererRef = (0, import_react8.useRef)(null);
|
|
689
|
+
const [size, setSize] = (0, import_react8.useState)({ cols: 80, rows: 24 });
|
|
690
|
+
const [running, setRunning] = (0, import_react8.useState)(false);
|
|
691
|
+
(0, import_react8.useEffect)(() => {
|
|
692
|
+
const cleanupResize = () => {
|
|
693
|
+
};
|
|
694
|
+
setRunning(true);
|
|
695
|
+
return () => {
|
|
696
|
+
setRunning(false);
|
|
697
|
+
cleanupResize();
|
|
698
|
+
};
|
|
699
|
+
}, []);
|
|
700
|
+
const exit = () => {
|
|
701
|
+
if (rendererRef.current) {
|
|
702
|
+
setRunning(false);
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
return {
|
|
706
|
+
renderer: rendererRef.current,
|
|
707
|
+
size,
|
|
708
|
+
running,
|
|
709
|
+
exit
|
|
710
|
+
};
|
|
711
|
+
};
|
|
712
|
+
|
|
713
|
+
// src/hooks/useInput.ts
|
|
714
|
+
var import_react9 = require("react");
|
|
715
|
+
var useInput = (callback, deps = []) => {
|
|
716
|
+
(0, import_react9.useEffect)(() => {
|
|
717
|
+
const readline2 = require("readline");
|
|
718
|
+
const handler = (chunk, key) => {
|
|
719
|
+
if (!key) return;
|
|
720
|
+
callback({
|
|
721
|
+
key: key.name || "",
|
|
722
|
+
name: key.name || "",
|
|
723
|
+
ctrl: key.ctrl || false,
|
|
724
|
+
meta: key.meta || false,
|
|
725
|
+
shift: key.shift || false,
|
|
726
|
+
sequence: key.sequence || ""
|
|
727
|
+
});
|
|
728
|
+
};
|
|
729
|
+
process.stdin.setRawMode(true);
|
|
730
|
+
readline2.emitKeypressEvents(process.stdin);
|
|
731
|
+
process.stdin.on("keypress", handler);
|
|
732
|
+
return () => {
|
|
733
|
+
process.stdin.off("keypress", handler);
|
|
734
|
+
};
|
|
735
|
+
}, [callback, ...deps]);
|
|
736
|
+
};
|
|
737
|
+
var useKey = (keyName, callback, deps = []) => {
|
|
738
|
+
const keys = Array.isArray(keyName) ? keyName : [keyName];
|
|
739
|
+
useInput(
|
|
740
|
+
(0, import_react9.useCallback)(
|
|
741
|
+
({ key, ctrl, meta }) => {
|
|
742
|
+
if (ctrl || meta) return;
|
|
743
|
+
if (keys.includes(key)) {
|
|
744
|
+
callback();
|
|
745
|
+
}
|
|
746
|
+
},
|
|
747
|
+
[callback, keys]
|
|
748
|
+
),
|
|
749
|
+
deps
|
|
750
|
+
);
|
|
751
|
+
};
|
|
752
|
+
|
|
753
|
+
// src/hooks/useFocus.ts
|
|
754
|
+
var import_react10 = require("react");
|
|
755
|
+
var useFocus = (initialFocus = 0, itemCount) => {
|
|
756
|
+
const [focusedIndex, setFocusedIndex] = (0, import_react10.useState)(initialFocus);
|
|
757
|
+
const focusableRefs = (0, import_react10.useRef)(/* @__PURE__ */ new Map());
|
|
758
|
+
const focusNext = (0, import_react10.useCallback)(() => {
|
|
759
|
+
setFocusedIndex((current) => (current + 1) % itemCount);
|
|
760
|
+
}, [itemCount]);
|
|
761
|
+
const focusPrevious = (0, import_react10.useCallback)(() => {
|
|
762
|
+
setFocusedIndex((current) => (current - 1 + itemCount) % itemCount);
|
|
763
|
+
}, [itemCount]);
|
|
764
|
+
const setFocus = (0, import_react10.useCallback)((index) => {
|
|
765
|
+
if (index >= 0 && index < itemCount) {
|
|
766
|
+
setFocusedIndex(index);
|
|
767
|
+
}
|
|
768
|
+
}, [itemCount]);
|
|
769
|
+
const isFocused = (0, import_react10.useCallback)(
|
|
770
|
+
(index) => index === focusedIndex,
|
|
771
|
+
[focusedIndex]
|
|
772
|
+
);
|
|
773
|
+
(0, import_react10.useEffect)(() => {
|
|
774
|
+
const readline2 = require("readline");
|
|
775
|
+
readline2.emitKeypressEvents(process.stdin);
|
|
776
|
+
process.stdin.setRawMode(true);
|
|
777
|
+
const handleKeyPress = (_chunk, key) => {
|
|
778
|
+
if (key.name === "tab" || key.name === "right") {
|
|
779
|
+
focusNext();
|
|
780
|
+
} else if (key.name === "left") {
|
|
781
|
+
focusPrevious();
|
|
782
|
+
}
|
|
783
|
+
};
|
|
784
|
+
process.stdin.on("keypress", handleKeyPress);
|
|
785
|
+
return () => {
|
|
786
|
+
process.stdin.off("keypress", handleKeyPress);
|
|
787
|
+
};
|
|
788
|
+
}, [focusNext, focusPrevious]);
|
|
789
|
+
return {
|
|
790
|
+
focusedIndex,
|
|
791
|
+
focusNext,
|
|
792
|
+
focusPrevious,
|
|
793
|
+
setFocus,
|
|
794
|
+
isFocused
|
|
795
|
+
};
|
|
796
|
+
};
|
|
797
|
+
|
|
798
|
+
// src/hooks/useStdout.ts
|
|
799
|
+
var import_react11 = require("react");
|
|
800
|
+
var useStdoutDimensions = () => {
|
|
801
|
+
const [dimensions, setDimensions] = (0, import_react11.useState)(() => ({
|
|
802
|
+
columns: process.stdout.columns || 80,
|
|
803
|
+
rows: process.stdout.rows || 24
|
|
804
|
+
}));
|
|
805
|
+
(0, import_react11.useEffect)(() => {
|
|
806
|
+
const handleResize = () => {
|
|
807
|
+
setDimensions({
|
|
808
|
+
columns: process.stdout.columns || 80,
|
|
809
|
+
rows: process.stdout.rows || 24
|
|
810
|
+
});
|
|
811
|
+
};
|
|
812
|
+
process.stdout.on("resize", handleResize);
|
|
813
|
+
return () => {
|
|
814
|
+
process.stdout.off("resize", handleResize);
|
|
815
|
+
};
|
|
816
|
+
}, []);
|
|
817
|
+
return dimensions;
|
|
818
|
+
};
|
|
819
|
+
var useStdout = () => {
|
|
820
|
+
const write = (0, import_react11.useCallback)((data) => {
|
|
821
|
+
process.stdout.write(data);
|
|
822
|
+
}, []);
|
|
823
|
+
return { write };
|
|
824
|
+
};
|
|
825
|
+
|
|
826
|
+
// src/hooks/useInterval.ts
|
|
827
|
+
var import_react12 = require("react");
|
|
828
|
+
var useInterval = (callback, delay) => {
|
|
829
|
+
const savedCallback = (0, import_react12.useRef)(callback);
|
|
830
|
+
(0, import_react12.useEffect)(() => {
|
|
831
|
+
savedCallback.current = callback;
|
|
832
|
+
}, [callback]);
|
|
833
|
+
(0, import_react12.useEffect)(() => {
|
|
834
|
+
if (delay === null) return;
|
|
835
|
+
const tick = () => savedCallback.current();
|
|
836
|
+
const id = setInterval(tick, delay);
|
|
837
|
+
return () => clearInterval(id);
|
|
838
|
+
}, [delay]);
|
|
839
|
+
};
|
|
840
|
+
var useTimeout = (callback, delay) => {
|
|
841
|
+
const savedCallback = (0, import_react12.useRef)(callback);
|
|
842
|
+
(0, import_react12.useEffect)(() => {
|
|
843
|
+
savedCallback.current = callback;
|
|
844
|
+
}, [callback]);
|
|
845
|
+
(0, import_react12.useEffect)(() => {
|
|
846
|
+
if (delay === null) return;
|
|
847
|
+
const tick = () => savedCallback.current();
|
|
848
|
+
const id = setTimeout(tick, delay);
|
|
849
|
+
return () => clearTimeout(id);
|
|
850
|
+
}, [delay]);
|
|
851
|
+
};
|
|
852
|
+
|
|
853
|
+
// src/hooks/useAppState.ts
|
|
854
|
+
var import_react13 = require("react");
|
|
855
|
+
var useAppState = (initialState = "idle") => {
|
|
856
|
+
const [state, setState] = (0, import_react13.useState)(initialState);
|
|
857
|
+
const [error, setError] = (0, import_react13.useState)(null);
|
|
858
|
+
const setLoading = (0, import_react13.useCallback)(() => {
|
|
859
|
+
setState("loading");
|
|
860
|
+
setError(null);
|
|
861
|
+
}, []);
|
|
862
|
+
const setSuccess = (0, import_react13.useCallback)(() => {
|
|
863
|
+
setState("success");
|
|
864
|
+
setError(null);
|
|
865
|
+
}, []);
|
|
866
|
+
const setErrorState = (0, import_react13.useCallback)((err) => {
|
|
867
|
+
setState("error");
|
|
868
|
+
setError(err);
|
|
869
|
+
}, []);
|
|
870
|
+
const setIdle = (0, import_react13.useCallback)(() => {
|
|
871
|
+
setState("idle");
|
|
872
|
+
setError(null);
|
|
873
|
+
}, []);
|
|
874
|
+
const isLoading = state === "loading";
|
|
875
|
+
const isSuccess = state === "success";
|
|
876
|
+
const isError = state === "error";
|
|
877
|
+
const isIdle = state === "idle";
|
|
878
|
+
return {
|
|
879
|
+
state,
|
|
880
|
+
error,
|
|
881
|
+
isLoading,
|
|
882
|
+
isSuccess,
|
|
883
|
+
isError,
|
|
884
|
+
isIdle,
|
|
885
|
+
setLoading,
|
|
886
|
+
setSuccess,
|
|
887
|
+
setError: setErrorState,
|
|
888
|
+
setIdle
|
|
889
|
+
};
|
|
890
|
+
};
|
|
891
|
+
|
|
892
|
+
// src/hooks/useList.ts
|
|
893
|
+
var import_react14 = require("react");
|
|
894
|
+
var useList = ({
|
|
895
|
+
initialItems = [],
|
|
896
|
+
initialIndex = 0,
|
|
897
|
+
loop = true
|
|
898
|
+
} = {}) => {
|
|
899
|
+
const [items, setItems] = (0, import_react14.useState)(initialItems);
|
|
900
|
+
const [index, setIndex] = (0, import_react14.useState)(initialIndex);
|
|
901
|
+
const next = (0, import_react14.useCallback)(() => {
|
|
902
|
+
setIndex((current) => {
|
|
903
|
+
if (items.length === 0) return 0;
|
|
904
|
+
const nextIndex = current + 1;
|
|
905
|
+
if (nextIndex >= items.length) {
|
|
906
|
+
return loop ? 0 : items.length - 1;
|
|
907
|
+
}
|
|
908
|
+
return nextIndex;
|
|
909
|
+
});
|
|
910
|
+
}, [items.length, loop]);
|
|
911
|
+
const previous = (0, import_react14.useCallback)(() => {
|
|
912
|
+
setIndex((current) => {
|
|
913
|
+
if (items.length === 0) return 0;
|
|
914
|
+
const prevIndex = current - 1;
|
|
915
|
+
if (prevIndex < 0) {
|
|
916
|
+
return loop ? items.length - 1 : 0;
|
|
917
|
+
}
|
|
918
|
+
return prevIndex;
|
|
919
|
+
});
|
|
920
|
+
}, [items.length, loop]);
|
|
921
|
+
const select = (0, import_react14.useCallback)((item) => {
|
|
922
|
+
const newIndex = items.indexOf(item);
|
|
923
|
+
if (newIndex !== -1) {
|
|
924
|
+
setIndex(newIndex);
|
|
925
|
+
}
|
|
926
|
+
}, [items]);
|
|
927
|
+
const selectedIndex = index;
|
|
928
|
+
const selectedItem = items[index] ?? null;
|
|
929
|
+
return {
|
|
930
|
+
items,
|
|
931
|
+
setItems,
|
|
932
|
+
index: selectedIndex,
|
|
933
|
+
setIndex,
|
|
934
|
+
selectedItem,
|
|
935
|
+
next,
|
|
936
|
+
previous,
|
|
937
|
+
select
|
|
938
|
+
};
|
|
939
|
+
};
|
|
940
|
+
|
|
941
|
+
// src/index.ts
|
|
942
|
+
var import_react15 = __toESM(require("react"), 1);
|
|
943
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
944
|
+
0 && (module.exports = {
|
|
945
|
+
ANSI,
|
|
946
|
+
Box,
|
|
947
|
+
Buffer,
|
|
948
|
+
Button,
|
|
949
|
+
Flex,
|
|
950
|
+
Grid,
|
|
951
|
+
Input,
|
|
952
|
+
Progress,
|
|
953
|
+
React,
|
|
954
|
+
Renderer,
|
|
955
|
+
Terminal,
|
|
956
|
+
Text,
|
|
957
|
+
createRoot,
|
|
958
|
+
render,
|
|
959
|
+
useApp,
|
|
960
|
+
useAppState,
|
|
961
|
+
useFocus,
|
|
962
|
+
useInput,
|
|
963
|
+
useInterval,
|
|
964
|
+
useKey,
|
|
965
|
+
useList,
|
|
966
|
+
useStdout,
|
|
967
|
+
useStdoutDimensions,
|
|
968
|
+
useTimeout
|
|
969
|
+
});
|
|
970
|
+
//# sourceMappingURL=index.cjs.map
|