cli-menu-kit 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.
Files changed (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +716 -0
  3. package/dist/api.d.ts +158 -0
  4. package/dist/api.js +128 -0
  5. package/dist/components/display/headers.d.ts +32 -0
  6. package/dist/components/display/headers.js +84 -0
  7. package/dist/components/display/index.d.ts +8 -0
  8. package/dist/components/display/index.js +31 -0
  9. package/dist/components/display/messages.d.ts +41 -0
  10. package/dist/components/display/messages.js +90 -0
  11. package/dist/components/display/progress.d.ts +41 -0
  12. package/dist/components/display/progress.js +82 -0
  13. package/dist/components/display/summary.d.ts +33 -0
  14. package/dist/components/display/summary.js +82 -0
  15. package/dist/components/inputs/index.d.ts +8 -0
  16. package/dist/components/inputs/index.js +15 -0
  17. package/dist/components/inputs/language-input.d.ts +11 -0
  18. package/dist/components/inputs/language-input.js +104 -0
  19. package/dist/components/inputs/modify-field.d.ts +11 -0
  20. package/dist/components/inputs/modify-field.js +42 -0
  21. package/dist/components/inputs/number-input.d.ts +11 -0
  22. package/dist/components/inputs/number-input.js +143 -0
  23. package/dist/components/inputs/text-input.d.ts +11 -0
  24. package/dist/components/inputs/text-input.js +114 -0
  25. package/dist/components/menus/boolean-menu.d.ts +11 -0
  26. package/dist/components/menus/boolean-menu.js +169 -0
  27. package/dist/components/menus/checkbox-menu.d.ts +11 -0
  28. package/dist/components/menus/checkbox-menu.js +161 -0
  29. package/dist/components/menus/index.d.ts +7 -0
  30. package/dist/components/menus/index.js +13 -0
  31. package/dist/components/menus/radio-menu.d.ts +11 -0
  32. package/dist/components/menus/radio-menu.js +158 -0
  33. package/dist/components.d.ts +55 -0
  34. package/dist/components.js +166 -0
  35. package/dist/core/colors.d.ts +64 -0
  36. package/dist/core/colors.js +139 -0
  37. package/dist/core/keyboard.d.ts +124 -0
  38. package/dist/core/keyboard.js +185 -0
  39. package/dist/core/renderer.d.ts +74 -0
  40. package/dist/core/renderer.js +217 -0
  41. package/dist/core/terminal.d.ts +89 -0
  42. package/dist/core/terminal.js +170 -0
  43. package/dist/features/commands.d.ts +57 -0
  44. package/dist/features/commands.js +161 -0
  45. package/dist/features/wizard.d.ts +62 -0
  46. package/dist/features/wizard.js +112 -0
  47. package/dist/i18n/languages/en.d.ts +5 -0
  48. package/dist/i18n/languages/en.js +54 -0
  49. package/dist/i18n/languages/zh.d.ts +5 -0
  50. package/dist/i18n/languages/zh.js +54 -0
  51. package/dist/i18n/registry.d.ts +36 -0
  52. package/dist/i18n/registry.js +82 -0
  53. package/dist/i18n/types.d.ts +65 -0
  54. package/dist/i18n/types.js +5 -0
  55. package/dist/index.d.ts +27 -0
  56. package/dist/index.js +104 -0
  57. package/dist/input.d.ts +40 -0
  58. package/dist/input.js +211 -0
  59. package/dist/menu-core.d.ts +52 -0
  60. package/dist/menu-core.js +201 -0
  61. package/dist/menu-multi.d.ts +21 -0
  62. package/dist/menu-multi.js +119 -0
  63. package/dist/menu-single.d.ts +18 -0
  64. package/dist/menu-single.js +138 -0
  65. package/dist/menu.d.ts +66 -0
  66. package/dist/menu.js +78 -0
  67. package/dist/types/display.types.d.ts +57 -0
  68. package/dist/types/display.types.js +5 -0
  69. package/dist/types/input.types.d.ts +88 -0
  70. package/dist/types/input.types.js +5 -0
  71. package/dist/types/layout.types.d.ts +56 -0
  72. package/dist/types/layout.types.js +36 -0
  73. package/dist/types/menu.types.d.ts +85 -0
  74. package/dist/types/menu.types.js +5 -0
  75. package/dist/types.d.ts +49 -0
  76. package/dist/types.js +5 -0
  77. package/package.json +35 -0
package/README.md ADDED
@@ -0,0 +1,716 @@
1
+ # CLI Menu Kit
2
+
3
+ A comprehensive, modular CLI menu system for Node.js with full TypeScript support. Zero dependencies, pure Node.js implementation with advanced features including i18n, wizards, and command handling.
4
+
5
+ ## Features
6
+
7
+ ### Menu Components
8
+ - ✅ **RadioMenu** - Single-select vertical menu with arrow/number/letter navigation
9
+ - ✅ **CheckboxMenu** - Multi-select with checkboxes, select all, and invert
10
+ - ✅ **BooleanMenu** - Yes/No selection (horizontal and vertical)
11
+
12
+ ### Input Components
13
+ - ✅ **TextInput** - Single-line text with validation and constraints
14
+ - ✅ **NumberInput** - Numeric input with min/max validation
15
+ - ✅ **LanguageSelector** - Specialized language picker
16
+ - ✅ **ModifyField** - Composite field modification prompt
17
+
18
+ ### Display Components
19
+ - ✅ **Headers** - Simple and ASCII art headers with borders
20
+ - ✅ **Progress** - Step indicators, stage headers, separators
21
+ - ✅ **Messages** - Success/Error/Warning/Info/Question with icons
22
+ - ✅ **Summary** - Bordered tables with sections and key-value pairs
23
+
24
+ ### Advanced Features
25
+ - ✅ **Wizard System** - Multi-step configuration flows with progress tracking
26
+ - ✅ **i18n Support** - Chinese and English translations (extensible)
27
+ - ✅ **Command Handling** - Built-in commands (/quit, /help, /clear, /back)
28
+ - ✅ **Layout System** - Flexible component composition
29
+ - ✅ **Color System** - Single colors and two-color gradients
30
+ - ✅ **Unified API** - Simple, consistent interface for all components
31
+
32
+ ### Core Principles
33
+ - ✅ **Zero dependencies** - Pure Node.js
34
+ - ✅ **Fully typed** - Complete TypeScript support
35
+ - ✅ **Modular architecture** - All files under 300 lines
36
+ - ✅ **Component-based** - Reusable, composable components
37
+ - ✅ **Type-safe** - Strict TypeScript with full type definitions
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ npm install cli-menu-kit
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ### Unified API (Recommended)
48
+
49
+ ```javascript
50
+ import { menu, input, wizard } from 'cli-menu-kit';
51
+
52
+ // Radio menu (single-select)
53
+ const result = await menu.radio({
54
+ title: 'Select Framework',
55
+ options: ['React', 'Vue', 'Angular', 'Svelte']
56
+ });
57
+ console.log(`Selected: ${result.value}`);
58
+
59
+ // Checkbox menu (multi-select)
60
+ const features = await menu.checkbox({
61
+ options: ['TypeScript', 'ESLint', 'Prettier', 'Testing'],
62
+ minSelections: 1
63
+ });
64
+ console.log(`Selected: ${features.values.join(', ')}`);
65
+
66
+ // Boolean menu (yes/no)
67
+ const confirmed = await menu.booleanH('Continue?', true);
68
+ console.log(`Confirmed: ${confirmed}`);
69
+
70
+ // Text input
71
+ const name = await input.text({
72
+ prompt: 'Enter your name',
73
+ defaultValue: 'User',
74
+ minLength: 2
75
+ });
76
+
77
+ // Number input
78
+ const age = await input.number({
79
+ prompt: 'Enter your age',
80
+ min: 1,
81
+ max: 120
82
+ });
83
+
84
+ // Language selector
85
+ const lang = await input.language({
86
+ languages: [
87
+ { code: 'zh', name: 'Chinese', nativeName: '简体中文' },
88
+ { code: 'en', name: 'English' }
89
+ ]
90
+ });
91
+
92
+ // Wizard (multi-step flow)
93
+ const result = await wizard.run({
94
+ steps: [
95
+ {
96
+ name: 'language',
97
+ title: 'Select Language',
98
+ component: 'language-selector',
99
+ config: { /* ... */ }
100
+ },
101
+ {
102
+ name: 'projectName',
103
+ title: 'Project Name',
104
+ component: 'text-input',
105
+ config: { prompt: 'Enter project name' }
106
+ }
107
+ ]
108
+ });
109
+ ```
110
+
111
+ ### Display Components
112
+
113
+ ```javascript
114
+ import {
115
+ createSimpleHeader,
116
+ createAsciiHeader,
117
+ createProgressIndicator,
118
+ showSuccess,
119
+ showError,
120
+ showWarning,
121
+ showInfo,
122
+ createSummaryTable
123
+ } from 'cli-menu-kit';
124
+
125
+ // Simple header
126
+ createSimpleHeader('My Application', '\x1b[36m');
127
+
128
+ // ASCII header
129
+ createAsciiHeader(asciiArt, {
130
+ subtitle: 'Version 1.0.0',
131
+ url: 'https://github.com/user/repo'
132
+ });
133
+
134
+ // Progress indicator
135
+ createProgressIndicator(['Step 1', 'Step 2', 'Step 3'], 1);
136
+
137
+ // Messages
138
+ showSuccess('Operation completed!');
139
+ showError('Something went wrong');
140
+ showWarning('Please check your input');
141
+ showInfo('Press Ctrl+C to exit');
142
+
143
+ // Summary table
144
+ createSummaryTable('Session Summary', [
145
+ {
146
+ header: 'Statistics',
147
+ items: [
148
+ { key: 'Total', value: '100' },
149
+ { key: 'Success', value: '95' }
150
+ ]
151
+ }
152
+ ]);
153
+ ```
154
+
155
+ ### i18n Support
156
+
157
+ ```javascript
158
+ import { setLanguage, t } from 'cli-menu-kit';
159
+
160
+ // Set language
161
+ setLanguage('en'); // or 'zh'
162
+
163
+ // Get translations
164
+ const prompt = t('menus.selectPrompt');
165
+ const goodbye = t('messages.goodbye');
166
+ ```
167
+
168
+ ### Command Handling
169
+
170
+ ```javascript
171
+ import { registerCommand, handleCommand } from 'cli-menu-kit';
172
+
173
+ // Register custom command
174
+ registerCommand('test', () => {
175
+ console.log('Test command executed!');
176
+ return false; // Continue (don't exit)
177
+ }, 'Run test command');
178
+
179
+ // Handle command input
180
+ const result = handleCommand('/test');
181
+ // Built-in commands: /quit, /help, /clear, /back
182
+ ```
183
+
184
+ ## API Reference
185
+
186
+ ### Menu API
187
+
188
+ #### menu.radio(config)
189
+ Single-select vertical menu.
190
+
191
+ ```typescript
192
+ interface RadioMenuConfig {
193
+ title?: string;
194
+ options: MenuOption[];
195
+ prompt?: string;
196
+ hints?: string[];
197
+ layout?: MenuLayout;
198
+ defaultIndex?: number;
199
+ allowNumberKeys?: boolean;
200
+ allowLetterKeys?: boolean;
201
+ onExit?: () => void;
202
+ }
203
+
204
+ // Returns: { index: number, value: string }
205
+ ```
206
+
207
+ #### menu.checkbox(config)
208
+ Multi-select vertical menu.
209
+
210
+ ```typescript
211
+ interface CheckboxMenuConfig {
212
+ title?: string;
213
+ options: MenuOption[];
214
+ prompt?: string;
215
+ hints?: string[];
216
+ layout?: MenuLayout;
217
+ defaultSelected?: number[];
218
+ minSelections?: number;
219
+ maxSelections?: number;
220
+ allowSelectAll?: boolean;
221
+ allowInvert?: boolean;
222
+ onExit?: () => void;
223
+ }
224
+
225
+ // Returns: { indices: number[], values: string[] }
226
+ ```
227
+
228
+ #### menu.boolean(config)
229
+ Yes/No selection menu.
230
+
231
+ ```typescript
232
+ interface BooleanMenuConfig {
233
+ question: string;
234
+ defaultValue?: boolean;
235
+ yesText?: string;
236
+ noText?: string;
237
+ orientation?: 'horizontal' | 'vertical';
238
+ onExit?: () => void;
239
+ }
240
+
241
+ // Returns: boolean
242
+ ```
243
+
244
+ ### Input API
245
+
246
+ #### input.text(config)
247
+ Text input with validation.
248
+
249
+ ```typescript
250
+ interface TextInputConfig {
251
+ prompt: string;
252
+ defaultValue?: string;
253
+ placeholder?: string;
254
+ maxLength?: number;
255
+ minLength?: number;
256
+ allowEmpty?: boolean;
257
+ validate?: (value: string) => boolean | string;
258
+ errorMessage?: string;
259
+ onExit?: () => void;
260
+ }
261
+
262
+ // Returns: string
263
+ ```
264
+
265
+ #### input.number(config)
266
+ Number input with constraints.
267
+
268
+ ```typescript
269
+ interface NumberInputConfig {
270
+ prompt: string;
271
+ defaultValue?: number;
272
+ min?: number;
273
+ max?: number;
274
+ allowDecimals?: boolean;
275
+ allowNegative?: boolean;
276
+ validate?: (value: string) => boolean | string;
277
+ errorMessage?: string;
278
+ onExit?: () => void;
279
+ }
280
+
281
+ // Returns: number
282
+ ```
283
+
284
+ #### input.language(config)
285
+ Language selector.
286
+
287
+ ```typescript
288
+ interface LanguageSelectorConfig {
289
+ languages: Array<{
290
+ code: string;
291
+ name: string;
292
+ nativeName?: string;
293
+ }>;
294
+ defaultLanguage?: string;
295
+ prompt?: string;
296
+ onExit?: () => void;
297
+ }
298
+
299
+ // Returns: string (language code)
300
+ ```
301
+
302
+ ### Wizard API
303
+
304
+ #### wizard.run(config)
305
+ Run a multi-step wizard.
306
+
307
+ ```typescript
308
+ interface WizardConfig {
309
+ title?: string;
310
+ steps: WizardStep[];
311
+ showProgress?: boolean;
312
+ onComplete?: (results: Record<string, any>) => void;
313
+ onCancel?: () => void;
314
+ }
315
+
316
+ interface WizardStep {
317
+ name: string;
318
+ title: string;
319
+ component: 'radio-menu' | 'checkbox-menu' | 'boolean-menu' |
320
+ 'text-input' | 'number-input' | 'language-selector';
321
+ config: any;
322
+ required?: boolean;
323
+ validate?: (value: any) => boolean | string;
324
+ skip?: (results: Record<string, any>) => boolean;
325
+ }
326
+
327
+ // Returns: { completed: boolean, results: Record<string, any> }
328
+ ```
329
+
330
+ ## Architecture
331
+
332
+ The library is organized into a modular architecture:
333
+
334
+ ```
335
+ src/
336
+ ├── types/ # Type definitions
337
+ │ ├── layout.types.ts
338
+ │ ├── menu.types.ts
339
+ │ ├── input.types.ts
340
+ │ └── display.types.ts
341
+ ├── core/ # Core utilities
342
+ │ ├── terminal.ts
343
+ │ ├── keyboard.ts
344
+ │ ├── renderer.ts
345
+ │ └── colors.ts
346
+ ├── components/ # UI components
347
+ │ ├── menus/
348
+ │ ├── inputs/
349
+ │ └── display/
350
+ ├── features/ # Advanced features
351
+ │ ├── wizard.ts
352
+ │ └── commands.ts
353
+ ├── i18n/ # Internationalization
354
+ │ ├── types.ts
355
+ │ ├── registry.ts
356
+ │ └── languages/
357
+ ├── api.ts # Unified API
358
+ └── index.ts # Main entry point
359
+ ```
360
+
361
+ See [ARCHITECTURE.md](./ARCHITECTURE.md) for detailed documentation.
362
+
363
+ ## Development
364
+
365
+ ```bash
366
+ # Install dependencies
367
+ npm install
368
+
369
+ # Build TypeScript
370
+ npm run build
371
+
372
+ # Run tests
373
+ node test/phase2-test.js # Menu components
374
+ node test/phase3-test.js # Input components
375
+ node test/phase4-test.js # Display components
376
+ node test/phase5-test.js # Advanced features
377
+ ```
378
+
379
+ ## Design Principles
380
+
381
+ 1. **Component-Based**: Each UI element is a separate, reusable component
382
+ 2. **Layout System**: Components can be composed in different orders
383
+ 3. **Type Safety**: Full TypeScript support with strict typing
384
+ 4. **Zero Dependencies**: Pure Node.js implementation
385
+ 5. **i18n Support**: Multi-language support with mapping system
386
+ 6. **Maintainability**: All files kept under 300 lines
387
+
388
+ ## License
389
+
390
+ MIT
391
+
392
+ ## Contributing
393
+
394
+ Contributions are welcome! Please ensure:
395
+ - Files stay under 300 lines
396
+ - TypeScript types are properly defined
397
+ - Code follows existing patterns
398
+ - Tests are included for new features
399
+ - All comments in English
400
+
401
+ ## Installation
402
+
403
+ ```bash
404
+ npm install cli-menu-kit
405
+ ```
406
+
407
+ ## Quick Start
408
+
409
+ ### Unified API (Recommended)
410
+
411
+ ```javascript
412
+ const { menu } = require('cli-menu-kit');
413
+
414
+ // Single select
415
+ const choice = await menu.select(
416
+ ['Option 1', 'Option 2', 'Option 3'],
417
+ { title: 'Choose one', lang: 'en' }
418
+ );
419
+
420
+ // Multi select
421
+ const choices = await menu.multiSelect(
422
+ ['Feature A', 'Feature B', 'Feature C'],
423
+ { lang: 'en' }
424
+ );
425
+
426
+ // Yes/No confirmation
427
+ const confirmed = await menu.confirm('Continue?', { lang: 'en' });
428
+
429
+ // Text input
430
+ const name = await menu.input('Enter your name', {
431
+ defaultValue: 'User',
432
+ validator: (input) => input.length > 0 || 'Name cannot be empty'
433
+ });
434
+
435
+ // Number input
436
+ const age = await menu.number('Enter your age', {
437
+ min: 1,
438
+ max: 120
439
+ });
440
+ ```
441
+
442
+ ### Direct Function Calls
443
+
444
+ ```javascript
445
+ const {
446
+ selectMenu,
447
+ selectMultiMenu,
448
+ askYesNo,
449
+ askInput,
450
+ askNumber
451
+ } = require('cli-menu-kit');
452
+
453
+ const choice = await selectMenu(['A', 'B', 'C'], { lang: 'zh' });
454
+ const choices = await selectMultiMenu(['1', '2', '3'], { lang: 'zh' });
455
+ const confirmed = await askYesNo('确认吗?', { lang: 'zh' });
456
+ ```
457
+
458
+ ## API Reference
459
+
460
+ ### menu.select(options, config)
461
+
462
+ Single-select menu with vertical navigation.
463
+
464
+ **Parameters:**
465
+ - `options`: Array of strings or `MenuOption` objects
466
+ - `config`: Configuration object
467
+ - `lang`: 'zh' | 'en' (default: 'zh')
468
+ - `type`: 'main' | 'sub' | 'firstRun' (default: 'main')
469
+ - `title`: Optional header title
470
+ - `showPrompt`: Show input prompt (default: true for main)
471
+ - `showHints`: Show operation hints (default: true)
472
+
473
+ **Returns:** Selected index (0-based)
474
+
475
+ **Keyboard shortcuts:**
476
+ - ↑/↓: Navigate
477
+ - 1-9: Quick select by number
478
+ - A-Z: Quick select by letter (for labeled options)
479
+ - Enter: Confirm
480
+ - Ctrl+C: Exit
481
+
482
+ ### menu.multiSelect(options, config)
483
+
484
+ Multi-select menu with checkboxes.
485
+
486
+ **Parameters:**
487
+ - `options`: Array of strings
488
+ - `config`: Configuration object
489
+ - `lang`: 'zh' | 'en' (default: 'zh')
490
+ - `defaultSelected`: Array of pre-selected indices
491
+
492
+ **Returns:** Array of selected indices
493
+
494
+ **Keyboard shortcuts:**
495
+ - ↑/↓: Navigate
496
+ - Space: Toggle selection
497
+ - A: Select all
498
+ - I: Invert selection
499
+ - Enter: Confirm
500
+ - Ctrl+C: Exit
501
+
502
+ ### menu.confirm(prompt, options)
503
+
504
+ Yes/No confirmation with horizontal selection.
505
+
506
+ **Parameters:**
507
+ - `prompt`: Question to ask
508
+ - `options`: Configuration object
509
+ - `lang`: 'zh' | 'en' (default: 'zh')
510
+ - `defaultYes`: Default to Yes (default: true)
511
+
512
+ **Returns:** Boolean (true for Yes, false for No)
513
+
514
+ **Keyboard shortcuts:**
515
+ - ←/→: Navigate
516
+ - Y/N: Quick select
517
+ - Enter: Confirm
518
+ - Ctrl+C: Exit
519
+
520
+ ### menu.input(prompt, options)
521
+
522
+ Text input with validation.
523
+
524
+ **Parameters:**
525
+ - `prompt`: Input prompt text
526
+ - `options`: Configuration object
527
+ - `lang`: 'zh' | 'en' (default: 'zh')
528
+ - `defaultValue`: Default value
529
+ - `validator`: Validation function `(input: string) => boolean | string`
530
+
531
+ **Returns:** User input string
532
+
533
+ ### menu.number(prompt, options)
534
+
535
+ Number input with constraints.
536
+
537
+ **Parameters:**
538
+ - `prompt`: Input prompt text
539
+ - `options`: Configuration object
540
+ - `lang`: 'zh' | 'en' (default: 'zh')
541
+ - `min`: Minimum value
542
+ - `max`: Maximum value
543
+ - `defaultValue`: Default value
544
+
545
+ **Returns:** User input number
546
+
547
+ ### selectWithChildren(parentOptions, getChildOptions, config)
548
+
549
+ Parent-child menu relationship.
550
+
551
+ **Parameters:**
552
+ - `parentOptions`: Parent menu options
553
+ - `getChildOptions`: Function `(parentIndex: number) => string[]`
554
+ - `config`: Configuration object
555
+ - `parentConfig`: Parent menu configuration
556
+ - `childConfig`: Child menu configuration
557
+
558
+ **Returns:** `{ parentIndex: number, childIndices: number[] }`
559
+
560
+ ## Examples
561
+
562
+ ### Basic Single Select
563
+
564
+ ```javascript
565
+ const { menu } = require('cli-menu-kit');
566
+
567
+ const options = [
568
+ '1. Create new project - Start a new project',
569
+ '2. Open existing - Open an existing project',
570
+ '3. Settings - Configure settings',
571
+ '4. Exit - Exit the application'
572
+ ];
573
+
574
+ const choice = await menu.select(options, {
575
+ title: 'Main Menu',
576
+ lang: 'en'
577
+ });
578
+
579
+ console.log(`You selected: ${choice}`);
580
+ ```
581
+
582
+ ### Multi-Select with Default Selection
583
+
584
+ ```javascript
585
+ const { menu } = require('cli-menu-kit');
586
+
587
+ const features = ['Dark Mode', 'Auto Save', 'Notifications', 'Analytics'];
588
+
589
+ const selected = await menu.multiSelect(features, {
590
+ lang: 'en',
591
+ defaultSelected: [0, 1] // Pre-select first two options
592
+ });
593
+
594
+ console.log(`Selected features: ${selected.map(i => features[i]).join(', ')}`);
595
+ ```
596
+
597
+ ### Input with Validation
598
+
599
+ ```javascript
600
+ const { menu } = require('cli-menu-kit');
601
+
602
+ const email = await menu.input('Enter your email', {
603
+ lang: 'en',
604
+ validator: (input) => {
605
+ if (!input.includes('@')) {
606
+ return 'Invalid email format';
607
+ }
608
+ return true;
609
+ }
610
+ });
611
+
612
+ console.log(`Email: ${email}`);
613
+ ```
614
+
615
+ ### Parent-Child Menu
616
+
617
+ ```javascript
618
+ const { selectWithChildren } = require('cli-menu-kit');
619
+
620
+ const categories = ['Electronics', 'Clothing', 'Books'];
621
+
622
+ const result = await selectWithChildren(
623
+ categories,
624
+ (parentIndex) => {
625
+ if (parentIndex === 0) return ['Phones', 'Laptops', 'Tablets'];
626
+ if (parentIndex === 1) return ['Shirts', 'Pants', 'Shoes'];
627
+ return ['Fiction', 'Non-Fiction', 'Comics'];
628
+ },
629
+ {
630
+ parentConfig: { title: 'Select Category', lang: 'en' },
631
+ childConfig: { lang: 'en' }
632
+ }
633
+ );
634
+
635
+ console.log(`Category: ${categories[result.parentIndex]}`);
636
+ console.log(`Items: ${result.childIndices.join(', ')}`);
637
+ ```
638
+
639
+ ### Display Components
640
+
641
+ ```javascript
642
+ const {
643
+ showInfo,
644
+ showSuccess,
645
+ showError,
646
+ showWarning,
647
+ printHeader
648
+ } = require('cli-menu-kit');
649
+
650
+ showInfo('Processing...', 'zh');
651
+ showSuccess('Operation completed!', 'en');
652
+ showError('Something went wrong', 'en');
653
+ showWarning('Please check your input', 'zh');
654
+
655
+ printHeader({
656
+ asciiArt: [' ███╗ ███╗', ' ████╗ ████║', ' ██╔████╔██║'],
657
+ title: 'My App',
658
+ subtitle: 'v1.0.0'
659
+ });
660
+ ```
661
+
662
+ ## Architecture
663
+
664
+ See [ARCHITECTURE.md](./ARCHITECTURE.md) for detailed architecture documentation.
665
+
666
+ ## File Structure
667
+
668
+ ```
669
+ src/
670
+ ├── types.ts # Type definitions (58 lines)
671
+ ├── components.ts # Colors, themes, symbols (187 lines)
672
+ ├── menu-core.ts # Shared utilities (213 lines)
673
+ ├── menu-single.ts # Single-select menu (163 lines)
674
+ ├── menu-multi.ts # Multi-select menu (151 lines)
675
+ ├── input.ts # Input components (246 lines)
676
+ ├── menu.ts # Unified API wrapper (90 lines)
677
+ └── index.ts # Main entry point (12 lines)
678
+ ```
679
+
680
+ All files are kept under 300 lines for maintainability.
681
+
682
+ ## Development
683
+
684
+ ```bash
685
+ # Install dependencies
686
+ npm install
687
+
688
+ # Build TypeScript
689
+ npm run build
690
+
691
+ # Run tests
692
+ node test/simple-test.js
693
+ node test/input-test.js
694
+ node test/unified-api-test.js
695
+ ```
696
+
697
+ ## Design Principles
698
+
699
+ 1. **Modularity**: Each menu type is in its own file
700
+ 2. **Decoupling**: Common utilities extracted to menu-core.ts
701
+ 3. **File Size**: Each file kept under 200-300 lines
702
+ 4. **Zero Dependencies**: Pure Node.js implementation
703
+ 5. **Type Safety**: Full TypeScript support
704
+ 6. **Flexibility**: Configurable layouts, prompts, hints
705
+
706
+ ## License
707
+
708
+ MIT
709
+
710
+ ## Contributing
711
+
712
+ Contributions are welcome! Please ensure:
713
+ - Files stay under 300 lines
714
+ - TypeScript types are properly defined
715
+ - Code follows existing patterns
716
+ - Tests are included for new features