cli-menu-kit 0.1.26 → 0.2.1

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 (78) hide show
  1. package/dist/api.d.ts +23 -5
  2. package/dist/api.js +16 -4
  3. package/dist/component-factories.d.ts +59 -0
  4. package/dist/component-factories.js +141 -0
  5. package/dist/components/display/header-v2.d.ts +13 -0
  6. package/dist/components/display/header-v2.js +43 -0
  7. package/dist/components/display/header.d.ts +40 -0
  8. package/dist/components/display/header.js +331 -18
  9. package/dist/components/display/headers.d.ts +1 -0
  10. package/dist/components/display/headers.js +15 -5
  11. package/dist/components/display/hints-v2.d.ts +10 -0
  12. package/dist/components/display/hints-v2.js +34 -0
  13. package/dist/components/display/hints.d.ts +56 -0
  14. package/dist/components/display/hints.js +81 -0
  15. package/dist/components/display/index.d.ts +4 -1
  16. package/dist/components/display/index.js +17 -1
  17. package/dist/components/display/input-prompt.d.ts +35 -0
  18. package/dist/components/display/input-prompt.js +36 -0
  19. package/dist/components/display/list.d.ts +49 -0
  20. package/dist/components/display/list.js +86 -0
  21. package/dist/components/display/messages.js +5 -5
  22. package/dist/components/display/progress.d.ts +17 -0
  23. package/dist/components/display/progress.js +18 -0
  24. package/dist/components/display/summary.js +72 -10
  25. package/dist/components/display/table.d.ts +44 -0
  26. package/dist/components/display/table.js +108 -0
  27. package/dist/components/inputs/language-input.js +8 -5
  28. package/dist/components/inputs/number-input.js +19 -14
  29. package/dist/components/inputs/text-input.js +50 -13
  30. package/dist/components/menus/boolean-menu.js +34 -20
  31. package/dist/components/menus/checkbox-menu.d.ts +2 -1
  32. package/dist/components/menus/checkbox-menu.js +35 -61
  33. package/dist/components/menus/checkbox-table-menu.d.ts +12 -0
  34. package/dist/components/menus/checkbox-table-menu.js +398 -0
  35. package/dist/components/menus/index.d.ts +1 -0
  36. package/dist/components/menus/index.js +3 -1
  37. package/dist/components/menus/radio-menu-split.d.ts +34 -0
  38. package/dist/components/menus/radio-menu-split.js +258 -0
  39. package/dist/components/menus/radio-menu-v2.d.ts +11 -0
  40. package/dist/components/menus/radio-menu-v2.js +150 -0
  41. package/dist/components/menus/radio-menu.d.ts +2 -1
  42. package/dist/components/menus/radio-menu.js +100 -134
  43. package/dist/components.js +3 -3
  44. package/dist/config/index.d.ts +5 -0
  45. package/dist/config/index.js +21 -0
  46. package/dist/config/language-config.d.ts +73 -0
  47. package/dist/config/language-config.js +157 -0
  48. package/dist/config/user-config.d.ts +83 -0
  49. package/dist/config/user-config.js +185 -0
  50. package/dist/core/colors.d.ts +24 -18
  51. package/dist/core/colors.js +74 -7
  52. package/dist/core/hint-manager.d.ts +29 -0
  53. package/dist/core/hint-manager.js +65 -0
  54. package/dist/core/renderer.d.ts +2 -1
  55. package/dist/core/renderer.js +46 -22
  56. package/dist/core/screen-manager.d.ts +54 -0
  57. package/dist/core/screen-manager.js +119 -0
  58. package/dist/core/state-manager.d.ts +27 -0
  59. package/dist/core/state-manager.js +56 -0
  60. package/dist/core/terminal.d.ts +17 -1
  61. package/dist/core/terminal.js +124 -4
  62. package/dist/core/virtual-scroll.d.ts +65 -0
  63. package/dist/core/virtual-scroll.js +120 -0
  64. package/dist/features/commands.js +23 -22
  65. package/dist/i18n/languages/en.js +4 -1
  66. package/dist/i18n/languages/zh.js +4 -1
  67. package/dist/i18n/registry.d.ts +4 -3
  68. package/dist/i18n/registry.js +12 -4
  69. package/dist/i18n/types.d.ts +3 -0
  70. package/dist/index.d.ts +7 -4
  71. package/dist/index.js +49 -4
  72. package/dist/layout.d.ts +67 -0
  73. package/dist/layout.js +86 -0
  74. package/dist/page-layout.d.ts +123 -0
  75. package/dist/page-layout.js +195 -0
  76. package/dist/types/input.types.d.ts +8 -0
  77. package/dist/types/menu.types.d.ts +61 -5
  78. package/package.json +4 -1
@@ -0,0 +1,195 @@
1
+ "use strict";
2
+ /**
3
+ * Page Layout System - Simple Configuration API
4
+ * Architecture: Header + Main Area + Footer
5
+ *
6
+ * This is the simple, configuration-based API that users want.
7
+ * Just pass config objects, no need to create components manually.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.renderPage = renderPage;
11
+ const api_js_1 = require("./api.js");
12
+ const header_js_1 = require("./components/display/header.js");
13
+ const headers_js_1 = require("./components/display/headers.js");
14
+ /**
15
+ * Render Header
16
+ */
17
+ function renderHeaderSection(config) {
18
+ if (!config || config.type === 'none') {
19
+ return;
20
+ }
21
+ const topBlankLines = Math.max(0, config.topBlankLines ?? 0);
22
+ for (let i = 0; i < topBlankLines; i += 1) {
23
+ console.log('');
24
+ }
25
+ if (config.type === 'simple' && config.text) {
26
+ (0, headers_js_1.renderSimpleHeader)(config.text);
27
+ }
28
+ else if (config.type === 'section' && config.text) {
29
+ // Add extra blank line before section header for spacing between menus
30
+ console.log('');
31
+ (0, headers_js_1.renderSectionHeader)(config.text, config.width || 50);
32
+ }
33
+ else if (config.type === 'full') {
34
+ // Render full header WITHOUT menuTitle
35
+ (0, header_js_1.renderHeader)({
36
+ asciiArt: config.asciiArt || [],
37
+ figletText: config.figletText,
38
+ figletFont: config.figletFont,
39
+ figletSize: config.figletSize,
40
+ figletScale: config.figletScale,
41
+ title: config.title || '',
42
+ titleColor: config.titleColor,
43
+ titleGradientStart: config.titleGradientStart,
44
+ titleGradientEnd: config.titleGradientEnd,
45
+ description: config.description,
46
+ descriptionColor: config.descriptionColor,
47
+ descriptionGradientStart: config.descriptionGradientStart,
48
+ descriptionGradientEnd: config.descriptionGradientEnd,
49
+ version: config.version,
50
+ url: config.url,
51
+ menuTitle: undefined, // Don't render menuTitle in header
52
+ boxWidth: config.boxWidth,
53
+ showBoxBorder: config.showBoxBorder,
54
+ fillBox: config.fillBox,
55
+ fillBoxColor: config.fillBoxColor,
56
+ fillBoxGradientStart: config.fillBoxGradientStart,
57
+ fillBoxGradientEnd: config.fillBoxGradientEnd,
58
+ asciiArtGradientStart: config.asciiArtGradientStart,
59
+ asciiArtGradientEnd: config.asciiArtGradientEnd,
60
+ asciiArtColor: config.asciiArtColor
61
+ });
62
+ }
63
+ }
64
+ /**
65
+ * Render Menu Title (separate from header)
66
+ */
67
+ function renderMenuTitle(title) {
68
+ if (title) {
69
+ console.log('');
70
+ console.log(` ${title}`);
71
+ }
72
+ }
73
+ /**
74
+ * Render Main Area
75
+ */
76
+ async function renderMainArea(config, hints) {
77
+ if (config.type === 'menu' && config.menu) {
78
+ // Menu in main area - pass hints from footer
79
+ const result = await api_js_1.menuAPI.radio({
80
+ options: config.menu.options,
81
+ allowLetterKeys: config.menu.allowLetterKeys ?? true,
82
+ allowNumberKeys: config.menu.allowNumberKeys ?? true,
83
+ preserveOnSelect: config.menu.preserveOnSelect ?? true,
84
+ preserveOnExit: config.menu.preserveOnExit ?? config.menu.preserveOnSelect ?? false,
85
+ onExit: config.menu.onExit
86
+ }, hints); // Pass hints as second parameter
87
+ return result;
88
+ }
89
+ else if (config.render) {
90
+ // Custom render function
91
+ await config.render();
92
+ return null;
93
+ }
94
+ return null;
95
+ }
96
+ /**
97
+ * Render Footer
98
+ */
99
+ async function renderFooterSection(config, hints) {
100
+ if (!config) {
101
+ return null;
102
+ }
103
+ let result = null;
104
+ // 1. Menu (if present)
105
+ if (config.menu) {
106
+ result = await api_js_1.menuAPI.radio({
107
+ options: config.menu.options,
108
+ allowLetterKeys: config.menu.allowLetterKeys ?? true,
109
+ allowNumberKeys: config.menu.allowNumberKeys ?? true,
110
+ preserveOnSelect: config.menu.preserveOnSelect ?? true,
111
+ preserveOnExit: config.menu.preserveOnExit ?? config.menu.preserveOnSelect ?? false,
112
+ onExit: config.menu.onExit
113
+ }, hints || config.hints);
114
+ }
115
+ // 2. Input (if present)
116
+ else if (config.input) {
117
+ result = await api_js_1.inputAPI.text({
118
+ prompt: config.input.prompt,
119
+ defaultValue: config.input.defaultValue,
120
+ allowEmpty: config.input.allowEmpty ?? false,
121
+ lang: config.input.lang,
122
+ preserveOnExit: config.input.preserveOnExit,
123
+ onExit: config.input.onExit
124
+ });
125
+ }
126
+ // 3. Ask (if present)
127
+ else if (config.ask) {
128
+ const askResult = await api_js_1.menuAPI.boolean({
129
+ question: config.ask.question,
130
+ helperText: config.ask.helperText,
131
+ defaultValue: config.ask.defaultValue ?? false,
132
+ orientation: config.ask.horizontal ? 'horizontal' : 'vertical',
133
+ preserveOnSelect: config.ask.preserveOnSelect ?? false,
134
+ preserveOnExit: config.ask.preserveOnExit ?? config.ask.preserveOnSelect ?? false,
135
+ onExit: config.ask.onExit
136
+ });
137
+ result = askResult;
138
+ }
139
+ return result;
140
+ }
141
+ /**
142
+ * Render complete page with simple configuration API
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * const result = await renderPage({
147
+ * header: {
148
+ * type: 'full',
149
+ * asciiArt: ['...'],
150
+ * title: 'My App',
151
+ * description: 'Description',
152
+ * version: '1.0.0'
153
+ * },
154
+ * mainArea: {
155
+ * type: 'menu',
156
+ * menu: {
157
+ * options: ['Option 1', 'Option 2'],
158
+ * allowLetterKeys: true,
159
+ * allowNumberKeys: true
160
+ * }
161
+ * },
162
+ * footer: {
163
+ * hints: ['↑↓ Navigate', 'Enter Confirm']
164
+ * }
165
+ * });
166
+ * ```
167
+ */
168
+ async function renderPage(config) {
169
+ // 1. Render Header (without menuTitle)
170
+ renderHeaderSection(config.header);
171
+ // 2. Render Menu Title (if provided)
172
+ renderMenuTitle(config.header?.menuTitle);
173
+ // 3. Determine where to render hints
174
+ let mainResult = null;
175
+ if (config.footer?.menu || config.footer?.ask || config.footer?.input) {
176
+ // Footer has interactive element - render main area first, then footer with hints
177
+ if (config.mainArea.type === 'menu' && config.mainArea.menu) {
178
+ mainResult = await renderMainArea(config.mainArea, undefined);
179
+ }
180
+ else if (config.mainArea.render) {
181
+ await config.mainArea.render();
182
+ // Add newline after custom render to separate from footer menu
183
+ // This ensures the escape codes from initTerminal don't interfere
184
+ console.log('');
185
+ }
186
+ // Render footer with hints
187
+ const footerResult = await renderFooterSection(config.footer, config.footer.hints);
188
+ return footerResult || mainResult;
189
+ }
190
+ else {
191
+ // Footer has no interactive element - render main area with hints from footer
192
+ mainResult = await renderMainArea(config.mainArea, config.footer?.hints);
193
+ return mainResult;
194
+ }
195
+ }
@@ -5,6 +5,8 @@
5
5
  * Base input configuration
6
6
  */
7
7
  export interface BaseInputConfig {
8
+ /** UI language (default: current i18n language) */
9
+ lang?: 'zh' | 'en';
8
10
  /** Input prompt text */
9
11
  prompt: string;
10
12
  /** Default value */
@@ -15,6 +17,8 @@ export interface BaseInputConfig {
15
17
  errorMessage?: string;
16
18
  /** Goodbye message function */
17
19
  onExit?: () => void;
20
+ /** Keep current input rendered on Ctrl+C exit instead of clearing (default: false) */
21
+ preserveOnExit?: boolean;
18
22
  }
19
23
  /**
20
24
  * Text input configuration
@@ -58,6 +62,8 @@ export interface LanguageSelectorConfig {
58
62
  prompt?: string;
59
63
  /** Goodbye message function */
60
64
  onExit?: () => void;
65
+ /** Keep current selector rendered on Ctrl+C exit instead of clearing (default: false) */
66
+ preserveOnExit?: boolean;
61
67
  }
62
68
  /**
63
69
  * Modify field configuration
@@ -75,6 +81,8 @@ export interface ModifyFieldConfig {
75
81
  validate?: (value: string) => boolean | string;
76
82
  /** Goodbye message function */
77
83
  onExit?: () => void;
84
+ /** Keep current prompt rendered on Ctrl+C exit instead of clearing (default: false) */
85
+ preserveOnExit?: boolean;
78
86
  }
79
87
  /**
80
88
  * Input result types
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * Menu component types for CLI Menu Kit
3
3
  */
4
- import { MenuLayout } from './layout.types.js';
5
4
  /**
6
5
  * Menu option (can be string, object with label, or section header)
7
6
  */
@@ -20,10 +19,6 @@ export interface BaseMenuConfig {
20
19
  title?: string;
21
20
  /** Input prompt text */
22
21
  prompt?: string;
23
- /** Hint texts to display */
24
- hints?: string[];
25
- /** Layout configuration */
26
- layout?: MenuLayout;
27
22
  /** Color for highlighted items */
28
23
  highlightColor?: string;
29
24
  /** Goodbye message function */
@@ -32,6 +27,8 @@ export interface BaseMenuConfig {
32
27
  separatorWidth?: number;
33
28
  /** Keep menu rendered after selection instead of clearing (default: false) */
34
29
  preserveOnSelect?: boolean;
30
+ /** Keep current menu rendered on Ctrl+C exit instead of clearing (default: false) */
31
+ preserveOnExit?: boolean;
35
32
  }
36
33
  /**
37
34
  * Radio menu (single-select) configuration
@@ -69,6 +66,8 @@ export interface CheckboxMenuConfig extends BaseMenuConfig {
69
66
  export interface BooleanMenuConfig extends BaseMenuConfig {
70
67
  /** Question text */
71
68
  question: string;
69
+ /** Optional helper text rendered on the next line */
70
+ helperText?: string;
72
71
  /** Default value */
73
72
  defaultValue?: boolean;
74
73
  /** Yes text */
@@ -90,3 +89,60 @@ export interface CheckboxMenuResult {
90
89
  values: string[];
91
90
  }
92
91
  export type BooleanMenuResult = boolean;
92
+ /**
93
+ * Checkbox table menu configuration
94
+ * Combines checkbox selection with table display
95
+ */
96
+ export interface CheckboxTableMenuConfig extends BaseMenuConfig {
97
+ /** Table columns definition */
98
+ columns: Array<{
99
+ header: string;
100
+ key: string;
101
+ width?: number;
102
+ align?: 'left' | 'center' | 'right';
103
+ }>;
104
+ /** Data rows (each row is an object with column keys) */
105
+ data: Record<string, any>[];
106
+ /** Optional: Key to use as unique identifier (default: index) */
107
+ idKey?: string;
108
+ /** Default selected row indices or IDs */
109
+ defaultSelected?: (number | string)[];
110
+ /** Minimum selections required */
111
+ minSelections?: number;
112
+ /** Maximum selections allowed */
113
+ maxSelections?: number;
114
+ /** Allow select all */
115
+ allowSelectAll?: boolean;
116
+ /** Allow invert selection */
117
+ allowInvert?: boolean;
118
+ /** Show table borders (default: false for checkbox menu style) */
119
+ showBorders?: boolean;
120
+ /** Show header separator (default: true) */
121
+ showHeaderSeparator?: boolean;
122
+ /** Phase/group separators (for grouping rows) */
123
+ separators?: Array<{
124
+ /** Insert before this row index */
125
+ beforeIndex: number;
126
+ /** Separator label */
127
+ label: string;
128
+ /** Optional description shown below the separator */
129
+ description?: string;
130
+ }>;
131
+ /** Separator label and description alignment (default: 'center') */
132
+ separatorAlign?: 'left' | 'center' | 'right';
133
+ /** Column width calculation mode */
134
+ widthMode?: 'auto' | 'fixed';
135
+ /** Checkbox column width (default: 4) */
136
+ checkboxWidth?: number;
137
+ }
138
+ /**
139
+ * Checkbox table menu result
140
+ */
141
+ export interface CheckboxTableMenuResult {
142
+ /** Selected row indices */
143
+ indices: number[];
144
+ /** Selected row data objects */
145
+ rows: Record<string, any>[];
146
+ /** Selected IDs (if idKey is provided) */
147
+ ids?: (string | number)[];
148
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cli-menu-kit",
3
- "version": "0.1.26",
3
+ "version": "0.2.1",
4
4
  "description": "A lightweight, customizable CLI menu system with keyboard shortcuts and real-time rendering",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -31,5 +31,8 @@
31
31
  },
32
32
  "engines": {
33
33
  "node": ">=14.0.0"
34
+ },
35
+ "dependencies": {
36
+ "figlet": "^1.10.0"
34
37
  }
35
38
  }