@hitools/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/element.js +46 -0
- package/elements/confirm.js +56 -0
- package/elements/error.js +22 -0
- package/elements/index.js +19 -0
- package/elements/loader.js +47 -0
- package/elements/message.js +23 -0
- package/elements/multiselect.js +62 -0
- package/elements/question.js +52 -0
- package/elements/select.js +60 -0
- package/elements/task.js +25 -0
- package/examples/index.js +1 -0
- package/index.js +85 -0
- package/package.json +29 -0
- package/prompt.js +152 -0
- package/readme.md +555 -0
- package/theme.js +328 -0
package/readme.md
ADDED
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
|
|
2
|
+
# Node.js Terminal UI
|
|
3
|
+
|
|
4
|
+
Minimal and extensible toolkit for building interactive CLI flows in Node.js.
|
|
5
|
+
|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Overview
|
|
14
|
+
|
|
15
|
+
**Node.js Terminal UI (TUI)** is a minimal toolkit for building interactive command-line interfaces.
|
|
16
|
+
|
|
17
|
+
It allows you to define a **flow of elements** that run sequentially in the terminal.
|
|
18
|
+
Each element can display information, collect input, or execute logic.
|
|
19
|
+
|
|
20
|
+
Typical use cases include:
|
|
21
|
+
|
|
22
|
+
- CLI installers
|
|
23
|
+
- project generators
|
|
24
|
+
- deployment scripts
|
|
25
|
+
- interactive configuration tools
|
|
26
|
+
- surveys and questionnaires
|
|
27
|
+
|
|
28
|
+
The toolkit focuses on **simplicity, small footprint, and extensibility**.
|
|
29
|
+
|
|
30
|
+
Built-in elements include:
|
|
31
|
+
|
|
32
|
+
- Message
|
|
33
|
+
- Question
|
|
34
|
+
- Select
|
|
35
|
+
- Multi-select
|
|
36
|
+
- Wait / Loader
|
|
37
|
+
- Confirmation
|
|
38
|
+
- Function executor
|
|
39
|
+
|
|
40
|
+
TUI also supports:
|
|
41
|
+
|
|
42
|
+
- themes
|
|
43
|
+
- input validation
|
|
44
|
+
- custom elements
|
|
45
|
+
- event hooks
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
# Demo
|
|
50
|
+
|
|
51
|
+
Example CLI interaction:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
> Welcome to TUI
|
|
56
|
+
|
|
57
|
+
? What is your name?
|
|
58
|
+
|
|
59
|
+
> Igor
|
|
60
|
+
|
|
61
|
+
✔ Environment: Production
|
|
62
|
+
✔ Continue deployment? Yes
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Add a GIF demo in your repository:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
docs/demo.gif
|
|
71
|
+
|
|
72
|
+
````
|
|
73
|
+
|
|
74
|
+
Example embed:
|
|
75
|
+
|
|
76
|
+
```markdown
|
|
77
|
+

|
|
78
|
+
````
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
# Why choose TUI
|
|
83
|
+
|
|
84
|
+
* zero heavy dependencies
|
|
85
|
+
* minimal runtime
|
|
86
|
+
* extensible elements
|
|
87
|
+
* themeable
|
|
88
|
+
* designed for CLI tooling
|
|
89
|
+
* simple sequential flow architecture
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
# Installation
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npm install @minojs/tui
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
# Getting started
|
|
102
|
+
|
|
103
|
+
Create a simple CLI flow.
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
import TUI from '@minojs/tui'
|
|
107
|
+
|
|
108
|
+
// Define a flow
|
|
109
|
+
const tui = new TUI([
|
|
110
|
+
{ type: 'message', label: 'Welcome to TUI!' },
|
|
111
|
+
{
|
|
112
|
+
type: 'question',
|
|
113
|
+
label: 'What is your first name?',
|
|
114
|
+
placeholder: 'first name',
|
|
115
|
+
name: 'firstname'
|
|
116
|
+
}
|
|
117
|
+
])
|
|
118
|
+
|
|
119
|
+
// Ask a single question outside of flow
|
|
120
|
+
tui.question({
|
|
121
|
+
label: 'What is your last name?',
|
|
122
|
+
placeholder: 'last name',
|
|
123
|
+
name: 'lastname'
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
// Run the flow
|
|
127
|
+
const result = await tui.run()
|
|
128
|
+
|
|
129
|
+
console.log(result)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
`run()` executes the flow sequentially and returns collected values.
|
|
133
|
+
|
|
134
|
+
Example result:
|
|
135
|
+
|
|
136
|
+
```js
|
|
137
|
+
{
|
|
138
|
+
firstname: "Igor",
|
|
139
|
+
lastname: "Hodunay"
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
# Configuration
|
|
146
|
+
|
|
147
|
+
A `TUI` instance can be created using either:
|
|
148
|
+
|
|
149
|
+
* a **flow array**
|
|
150
|
+
* a **configuration object**
|
|
151
|
+
|
|
152
|
+
Configuration allows you to extend the core functionality.
|
|
153
|
+
|
|
154
|
+
```javascript
|
|
155
|
+
const config = {
|
|
156
|
+
flow: [],
|
|
157
|
+
theme: class {},
|
|
158
|
+
validator: class {},
|
|
159
|
+
elements: []
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const tui = new TUI(config)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Options
|
|
166
|
+
|
|
167
|
+
| Option | Description |
|
|
168
|
+
| --------- | ----------------------------------- |
|
|
169
|
+
| flow | Default sequence of elements |
|
|
170
|
+
| theme | Theme class controlling CLI styling |
|
|
171
|
+
| validator | Validation module |
|
|
172
|
+
| elements | Custom elements to extend TUI |
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
# Elements
|
|
177
|
+
|
|
178
|
+
TUI includes a small set of built-in elements for common CLI interactions.
|
|
179
|
+
|
|
180
|
+
Each element is internally registered using:
|
|
181
|
+
|
|
182
|
+
```
|
|
183
|
+
Element.registerType()
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Elements can be used inside a flow or called directly from the `tui` instance.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
# Message
|
|
191
|
+
|
|
192
|
+
Displays static text in the terminal.
|
|
193
|
+
|
|
194
|
+
Useful for:
|
|
195
|
+
|
|
196
|
+
* headers
|
|
197
|
+
* instructions
|
|
198
|
+
* progress messages
|
|
199
|
+
|
|
200
|
+
Within flow:
|
|
201
|
+
|
|
202
|
+
```js
|
|
203
|
+
{ type: 'message', label: 'Welcome to the CLI!' }
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Standalone usage:
|
|
207
|
+
|
|
208
|
+
```js
|
|
209
|
+
tui.message('Welcome to the CLI!')
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
or
|
|
213
|
+
|
|
214
|
+
```js
|
|
215
|
+
tui.message({ label: 'Welcome to the CLI!' })
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
# Question
|
|
221
|
+
|
|
222
|
+
Prompts the user for text input.
|
|
223
|
+
|
|
224
|
+
The value will be stored under the specified `name`.
|
|
225
|
+
|
|
226
|
+
```js
|
|
227
|
+
{
|
|
228
|
+
type: 'question',
|
|
229
|
+
label: 'What is your name?',
|
|
230
|
+
placeholder: 'John',
|
|
231
|
+
name: 'username'
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Alternative usage:
|
|
236
|
+
|
|
237
|
+
```js
|
|
238
|
+
tui.question({
|
|
239
|
+
label: 'What is your name?',
|
|
240
|
+
placeholder: 'John',
|
|
241
|
+
name: 'username'
|
|
242
|
+
})
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Aliases:
|
|
246
|
+
|
|
247
|
+
```js
|
|
248
|
+
tui.ask({...})
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
# Select
|
|
254
|
+
|
|
255
|
+
Allows the user to choose **one option** from a list.
|
|
256
|
+
|
|
257
|
+
```js
|
|
258
|
+
{
|
|
259
|
+
type: 'select',
|
|
260
|
+
label: 'Choose environment',
|
|
261
|
+
options: ['Development', 'Production'],
|
|
262
|
+
name: 'env'
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Standalone usage:
|
|
267
|
+
|
|
268
|
+
```js
|
|
269
|
+
tui.select({
|
|
270
|
+
label: 'Choose environment',
|
|
271
|
+
options: ['Development', 'Production'],
|
|
272
|
+
name: 'env'
|
|
273
|
+
})
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
Navigation is typically handled with arrow keys.
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
# Multi-Select
|
|
281
|
+
|
|
282
|
+
Allows selecting **multiple options**.
|
|
283
|
+
|
|
284
|
+
```js
|
|
285
|
+
{
|
|
286
|
+
type: 'multiselect',
|
|
287
|
+
label: 'Select features',
|
|
288
|
+
options: ['Auth', 'Payments', 'Analytics']
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Standalone usage:
|
|
293
|
+
|
|
294
|
+
```js
|
|
295
|
+
tui.multiselect({
|
|
296
|
+
label: 'Select features',
|
|
297
|
+
options: ['Auth', 'Payments', 'Analytics']
|
|
298
|
+
})
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
# Confirmation
|
|
304
|
+
|
|
305
|
+
Simple Yes / No confirmation prompt.
|
|
306
|
+
|
|
307
|
+
Returns `true` or `false`.
|
|
308
|
+
|
|
309
|
+
```js
|
|
310
|
+
{
|
|
311
|
+
type: 'confirm',
|
|
312
|
+
label: 'Continue deployment?'
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Standalone usage:
|
|
317
|
+
|
|
318
|
+
```js
|
|
319
|
+
tui.confirm({
|
|
320
|
+
label: 'Continue deployment?'
|
|
321
|
+
})
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
# Loader
|
|
327
|
+
|
|
328
|
+
Displays a waiting state during async tasks.
|
|
329
|
+
|
|
330
|
+
Typical usage:
|
|
331
|
+
|
|
332
|
+
```js
|
|
333
|
+
{
|
|
334
|
+
type: 'loader',
|
|
335
|
+
text: 'Processing...'
|
|
336
|
+
}
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
Often used together with tasks or async operations.
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
# Task / Function executor
|
|
344
|
+
|
|
345
|
+
Runs custom logic inside the flow.
|
|
346
|
+
|
|
347
|
+
```js
|
|
348
|
+
{
|
|
349
|
+
type: 'task',
|
|
350
|
+
run: async (context) => {
|
|
351
|
+
console.log('Processing...')
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
Useful for:
|
|
357
|
+
|
|
358
|
+
* API calls
|
|
359
|
+
* file operations
|
|
360
|
+
* build steps
|
|
361
|
+
* deployment logic
|
|
362
|
+
|
|
363
|
+
Standalone usage:
|
|
364
|
+
|
|
365
|
+
```js
|
|
366
|
+
tui.task({
|
|
367
|
+
run: async (context) => {
|
|
368
|
+
console.log('Processing...')
|
|
369
|
+
}
|
|
370
|
+
})
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
# Keyboard Controls
|
|
376
|
+
|
|
377
|
+
| Key | Action |
|
|
378
|
+
| ----- | ------------- |
|
|
379
|
+
| ↑ ↓ | navigate |
|
|
380
|
+
| ← → | change option |
|
|
381
|
+
| space | toggle |
|
|
382
|
+
| enter | confirm |
|
|
383
|
+
|
|
384
|
+
You can override key behavior using custom actions:
|
|
385
|
+
|
|
386
|
+
```js
|
|
387
|
+
actions: {
|
|
388
|
+
return: value => console.log(value)
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
# Events
|
|
395
|
+
|
|
396
|
+
Elements support lifecycle hooks.
|
|
397
|
+
|
|
398
|
+
```js
|
|
399
|
+
{
|
|
400
|
+
type: 'question',
|
|
401
|
+
label: 'Your name',
|
|
402
|
+
before: () => console.log('Starting question'),
|
|
403
|
+
after: () => console.log('Answer received')
|
|
404
|
+
}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
These hooks allow you to run custom logic before or after an element executes.
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
# Validation
|
|
412
|
+
|
|
413
|
+
Input values can be validated using a validation function or module.
|
|
414
|
+
|
|
415
|
+
Validator receives the current value and must return:
|
|
416
|
+
|
|
417
|
+
* `true` → valid
|
|
418
|
+
* `string` → error message
|
|
419
|
+
|
|
420
|
+
Example:
|
|
421
|
+
|
|
422
|
+
```js
|
|
423
|
+
{
|
|
424
|
+
type: 'question',
|
|
425
|
+
label: 'Email',
|
|
426
|
+
validate: value => value.includes('@') || 'Invalid email'
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
# Themes
|
|
433
|
+
|
|
434
|
+
Themes control the visual appearance of the CLI.
|
|
435
|
+
|
|
436
|
+
You can customize:
|
|
437
|
+
|
|
438
|
+
* colors
|
|
439
|
+
* markers
|
|
440
|
+
* borders
|
|
441
|
+
* templates
|
|
442
|
+
* layouts
|
|
443
|
+
|
|
444
|
+
Example theme:
|
|
445
|
+
|
|
446
|
+
```js
|
|
447
|
+
class MyTheme {
|
|
448
|
+
|
|
449
|
+
static marker = {
|
|
450
|
+
current: '>'
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
static border = '|'
|
|
454
|
+
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
Apply the theme:
|
|
459
|
+
|
|
460
|
+
```js
|
|
461
|
+
const tui = new TUI({
|
|
462
|
+
theme: MyTheme
|
|
463
|
+
})
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
## Options
|
|
467
|
+
|
|
468
|
+
| Key | Action |
|
|
469
|
+
| ----------- | ------------- |
|
|
470
|
+
| colors | |
|
|
471
|
+
| templates | |
|
|
472
|
+
| marker | |
|
|
473
|
+
| borders | |
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
# Custom Elements
|
|
478
|
+
|
|
479
|
+
You can extend TUI by creating your own elements.
|
|
480
|
+
|
|
481
|
+
Example:
|
|
482
|
+
|
|
483
|
+
```js
|
|
484
|
+
class Spinner extends Element {
|
|
485
|
+
static type = 'spinner'
|
|
486
|
+
}
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
Register it:
|
|
490
|
+
|
|
491
|
+
```js
|
|
492
|
+
const tui = new TUI({
|
|
493
|
+
elements: [Spinner]
|
|
494
|
+
})
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
# Examples
|
|
500
|
+
|
|
501
|
+
Run the example collection:
|
|
502
|
+
|
|
503
|
+
```bash
|
|
504
|
+
npx node-cli@latest --examples
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
Source:
|
|
508
|
+
|
|
509
|
+
```
|
|
510
|
+
https://github.com/hodunay/tui/blob/main/src/examples/index.js
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
Examples include:
|
|
514
|
+
|
|
515
|
+
* CLI questionnaire
|
|
516
|
+
* menu navigation
|
|
517
|
+
* confirmation flows
|
|
518
|
+
* custom elements
|
|
519
|
+
|
|
520
|
+
---
|
|
521
|
+
|
|
522
|
+
# Use Cases
|
|
523
|
+
|
|
524
|
+
TUI works well for:
|
|
525
|
+
|
|
526
|
+
* CLI installers
|
|
527
|
+
* developer tooling
|
|
528
|
+
* deployment scripts
|
|
529
|
+
* project scaffolding
|
|
530
|
+
* interactive configuration
|
|
531
|
+
* terminal surveys
|
|
532
|
+
|
|
533
|
+
---
|
|
534
|
+
|
|
535
|
+
# Contributing
|
|
536
|
+
|
|
537
|
+
Contributions are welcome.
|
|
538
|
+
|
|
539
|
+
Feel free to open issues or submit pull requests.
|
|
540
|
+
|
|
541
|
+
---
|
|
542
|
+
|
|
543
|
+
# Roadmap
|
|
544
|
+
|
|
545
|
+
- [ ] arguments support ?
|
|
546
|
+
- [ ] use Method for themes, custom elements, validator and commands/fs actions
|
|
547
|
+
- [ ] RGB colors theme support
|
|
548
|
+
- [ ] Accept validator
|
|
549
|
+
- [ ] Terminal Forms
|
|
550
|
+
|
|
551
|
+
---
|
|
552
|
+
|
|
553
|
+
# License
|
|
554
|
+
|
|
555
|
+
MIT
|