cli-menu-kit 0.1.26 → 0.2.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/api.d.ts +23 -5
- package/dist/api.js +16 -4
- package/dist/component-factories.d.ts +59 -0
- package/dist/component-factories.js +141 -0
- package/dist/components/display/header-v2.d.ts +13 -0
- package/dist/components/display/header-v2.js +43 -0
- package/dist/components/display/hints-v2.d.ts +10 -0
- package/dist/components/display/hints-v2.js +34 -0
- package/dist/components/display/hints.d.ts +56 -0
- package/dist/components/display/hints.js +81 -0
- package/dist/components/display/index.d.ts +3 -0
- package/dist/components/display/index.js +15 -1
- package/dist/components/display/input-prompt.d.ts +35 -0
- package/dist/components/display/input-prompt.js +36 -0
- package/dist/components/display/list.d.ts +49 -0
- package/dist/components/display/list.js +86 -0
- package/dist/components/display/table.d.ts +42 -0
- package/dist/components/display/table.js +107 -0
- package/dist/components/menus/boolean-menu.js +2 -1
- package/dist/components/menus/checkbox-menu.d.ts +2 -1
- package/dist/components/menus/checkbox-menu.js +30 -59
- package/dist/components/menus/checkbox-table-menu.d.ts +12 -0
- package/dist/components/menus/checkbox-table-menu.js +395 -0
- package/dist/components/menus/index.d.ts +1 -0
- package/dist/components/menus/index.js +3 -1
- package/dist/components/menus/radio-menu-split.d.ts +33 -0
- package/dist/components/menus/radio-menu-split.js +248 -0
- package/dist/components/menus/radio-menu-v2.d.ts +11 -0
- package/dist/components/menus/radio-menu-v2.js +150 -0
- package/dist/components/menus/radio-menu.d.ts +2 -1
- package/dist/components/menus/radio-menu.js +60 -123
- package/dist/core/hint-manager.d.ts +29 -0
- package/dist/core/hint-manager.js +65 -0
- package/dist/core/renderer.d.ts +2 -1
- package/dist/core/renderer.js +22 -6
- package/dist/core/screen-manager.d.ts +54 -0
- package/dist/core/screen-manager.js +119 -0
- package/dist/core/state-manager.d.ts +27 -0
- package/dist/core/state-manager.js +56 -0
- package/dist/core/terminal.d.ts +4 -1
- package/dist/core/terminal.js +37 -4
- package/dist/core/virtual-scroll.d.ts +65 -0
- package/dist/core/virtual-scroll.js +120 -0
- package/dist/i18n/languages/en.js +4 -1
- package/dist/i18n/languages/zh.js +4 -1
- package/dist/i18n/registry.d.ts +4 -3
- package/dist/i18n/registry.js +12 -4
- package/dist/i18n/types.d.ts +3 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.js +30 -4
- package/dist/layout.d.ts +68 -0
- package/dist/layout.js +134 -0
- package/dist/page-layout.d.ts +92 -0
- package/dist/page-layout.js +156 -0
- package/dist/types/menu.types.d.ts +57 -5
- package/package.json +1 -1
- package/dist/types/layout.types.d.ts +0 -56
- package/dist/types/layout.types.js +0 -36
|
@@ -0,0 +1,156 @@
|
|
|
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
|
+
if (config.type === 'simple' && config.text) {
|
|
22
|
+
(0, headers_js_1.renderSimpleHeader)(config.text);
|
|
23
|
+
}
|
|
24
|
+
else if (config.type === 'section' && config.text) {
|
|
25
|
+
// Add extra blank line before section header for spacing between menus
|
|
26
|
+
console.log('');
|
|
27
|
+
(0, headers_js_1.renderSectionHeader)(config.text, config.width || 50);
|
|
28
|
+
}
|
|
29
|
+
else if (config.type === 'full') {
|
|
30
|
+
// Render full header WITHOUT menuTitle
|
|
31
|
+
(0, header_js_1.renderHeader)({
|
|
32
|
+
asciiArt: config.asciiArt || [],
|
|
33
|
+
title: config.title || '',
|
|
34
|
+
description: config.description,
|
|
35
|
+
version: config.version,
|
|
36
|
+
url: config.url,
|
|
37
|
+
menuTitle: undefined // Don't render menuTitle in header
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Render Menu Title (separate from header)
|
|
43
|
+
*/
|
|
44
|
+
function renderMenuTitle(title) {
|
|
45
|
+
if (title) {
|
|
46
|
+
console.log('');
|
|
47
|
+
console.log(` ${title}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Render Main Area
|
|
52
|
+
*/
|
|
53
|
+
async function renderMainArea(config, hints) {
|
|
54
|
+
if (config.type === 'menu' && config.menu) {
|
|
55
|
+
// Menu in main area - pass hints from footer
|
|
56
|
+
const result = await api_js_1.menuAPI.radio({
|
|
57
|
+
options: config.menu.options,
|
|
58
|
+
allowLetterKeys: config.menu.allowLetterKeys ?? true,
|
|
59
|
+
allowNumberKeys: config.menu.allowNumberKeys ?? true,
|
|
60
|
+
preserveOnSelect: config.menu.preserveOnSelect ?? true
|
|
61
|
+
}, hints); // Pass hints as second parameter
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
else if (config.render) {
|
|
65
|
+
// Custom render function
|
|
66
|
+
await config.render();
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Render Footer
|
|
73
|
+
*/
|
|
74
|
+
async function renderFooterSection(config, hints) {
|
|
75
|
+
if (!config) {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
let result = null;
|
|
79
|
+
// 1. Menu (if present)
|
|
80
|
+
if (config.menu) {
|
|
81
|
+
result = await api_js_1.menuAPI.radio({
|
|
82
|
+
options: config.menu.options,
|
|
83
|
+
allowLetterKeys: config.menu.allowLetterKeys ?? true,
|
|
84
|
+
allowNumberKeys: config.menu.allowNumberKeys ?? true,
|
|
85
|
+
preserveOnSelect: config.menu.preserveOnSelect ?? true
|
|
86
|
+
}, hints || config.hints);
|
|
87
|
+
}
|
|
88
|
+
// 2. Input (if present)
|
|
89
|
+
else if (config.input) {
|
|
90
|
+
result = await api_js_1.inputAPI.text({
|
|
91
|
+
prompt: config.input.prompt,
|
|
92
|
+
defaultValue: config.input.defaultValue,
|
|
93
|
+
allowEmpty: config.input.allowEmpty ?? false
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
// 3. Ask (if present)
|
|
97
|
+
else if (config.ask) {
|
|
98
|
+
const askResult = config.ask.horizontal
|
|
99
|
+
? await api_js_1.menuAPI.booleanH(config.ask.question, config.ask.defaultValue ?? false)
|
|
100
|
+
: await api_js_1.menuAPI.booleanV(config.ask.question, config.ask.defaultValue ?? false);
|
|
101
|
+
result = askResult;
|
|
102
|
+
}
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Render complete page with simple configuration API
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* const result = await renderPage({
|
|
111
|
+
* header: {
|
|
112
|
+
* type: 'full',
|
|
113
|
+
* asciiArt: ['...'],
|
|
114
|
+
* title: 'My App',
|
|
115
|
+
* description: 'Description',
|
|
116
|
+
* version: '1.0.0'
|
|
117
|
+
* },
|
|
118
|
+
* mainArea: {
|
|
119
|
+
* type: 'menu',
|
|
120
|
+
* menu: {
|
|
121
|
+
* options: ['Option 1', 'Option 2'],
|
|
122
|
+
* allowLetterKeys: true,
|
|
123
|
+
* allowNumberKeys: true
|
|
124
|
+
* }
|
|
125
|
+
* },
|
|
126
|
+
* footer: {
|
|
127
|
+
* hints: ['↑↓ Navigate', 'Enter Confirm']
|
|
128
|
+
* }
|
|
129
|
+
* });
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
async function renderPage(config) {
|
|
133
|
+
// 1. Render Header (without menuTitle)
|
|
134
|
+
renderHeaderSection(config.header);
|
|
135
|
+
// 2. Render Menu Title (if provided)
|
|
136
|
+
renderMenuTitle(config.header?.menuTitle);
|
|
137
|
+
// 3. Determine where to render hints
|
|
138
|
+
let mainResult = null;
|
|
139
|
+
if (config.footer?.menu || config.footer?.ask || config.footer?.input) {
|
|
140
|
+
// Footer has interactive element - render main area first, then footer with hints
|
|
141
|
+
if (config.mainArea.type === 'menu' && config.mainArea.menu) {
|
|
142
|
+
mainResult = await renderMainArea(config.mainArea, undefined);
|
|
143
|
+
}
|
|
144
|
+
else if (config.mainArea.render) {
|
|
145
|
+
await config.mainArea.render();
|
|
146
|
+
}
|
|
147
|
+
// Render footer with hints
|
|
148
|
+
const footerResult = await renderFooterSection(config.footer, config.footer.hints);
|
|
149
|
+
return footerResult || mainResult;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// Footer has no interactive element - render main area with hints from footer
|
|
153
|
+
mainResult = await renderMainArea(config.mainArea, config.footer?.hints);
|
|
154
|
+
return mainResult;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -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 */
|
|
@@ -90,3 +85,60 @@ export interface CheckboxMenuResult {
|
|
|
90
85
|
values: string[];
|
|
91
86
|
}
|
|
92
87
|
export type BooleanMenuResult = boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Checkbox table menu configuration
|
|
90
|
+
* Combines checkbox selection with table display
|
|
91
|
+
*/
|
|
92
|
+
export interface CheckboxTableMenuConfig extends BaseMenuConfig {
|
|
93
|
+
/** Table columns definition */
|
|
94
|
+
columns: Array<{
|
|
95
|
+
header: string;
|
|
96
|
+
key: string;
|
|
97
|
+
width?: number;
|
|
98
|
+
align?: 'left' | 'center' | 'right';
|
|
99
|
+
}>;
|
|
100
|
+
/** Data rows (each row is an object with column keys) */
|
|
101
|
+
data: Record<string, any>[];
|
|
102
|
+
/** Optional: Key to use as unique identifier (default: index) */
|
|
103
|
+
idKey?: string;
|
|
104
|
+
/** Default selected row indices or IDs */
|
|
105
|
+
defaultSelected?: (number | string)[];
|
|
106
|
+
/** Minimum selections required */
|
|
107
|
+
minSelections?: number;
|
|
108
|
+
/** Maximum selections allowed */
|
|
109
|
+
maxSelections?: number;
|
|
110
|
+
/** Allow select all */
|
|
111
|
+
allowSelectAll?: boolean;
|
|
112
|
+
/** Allow invert selection */
|
|
113
|
+
allowInvert?: boolean;
|
|
114
|
+
/** Show table borders (default: false for checkbox menu style) */
|
|
115
|
+
showBorders?: boolean;
|
|
116
|
+
/** Show header separator (default: true) */
|
|
117
|
+
showHeaderSeparator?: boolean;
|
|
118
|
+
/** Phase/group separators (for grouping rows) */
|
|
119
|
+
separators?: Array<{
|
|
120
|
+
/** Insert before this row index */
|
|
121
|
+
beforeIndex: number;
|
|
122
|
+
/** Separator label */
|
|
123
|
+
label: string;
|
|
124
|
+
/** Optional description shown below the separator */
|
|
125
|
+
description?: string;
|
|
126
|
+
}>;
|
|
127
|
+
/** Separator label and description alignment (default: 'center') */
|
|
128
|
+
separatorAlign?: 'left' | 'center' | 'right';
|
|
129
|
+
/** Column width calculation mode */
|
|
130
|
+
widthMode?: 'auto' | 'fixed';
|
|
131
|
+
/** Checkbox column width (default: 4) */
|
|
132
|
+
checkboxWidth?: number;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Checkbox table menu result
|
|
136
|
+
*/
|
|
137
|
+
export interface CheckboxTableMenuResult {
|
|
138
|
+
/** Selected row indices */
|
|
139
|
+
indices: number[];
|
|
140
|
+
/** Selected row data objects */
|
|
141
|
+
rows: Record<string, any>[];
|
|
142
|
+
/** Selected IDs (if idKey is provided) */
|
|
143
|
+
ids?: (string | number)[];
|
|
144
|
+
}
|
package/package.json
CHANGED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Layout system types for CLI Menu Kit
|
|
3
|
-
* Defines how components are composed and rendered
|
|
4
|
-
*/
|
|
5
|
-
/**
|
|
6
|
-
* Layout element types that can be arranged
|
|
7
|
-
*/
|
|
8
|
-
export type LayoutElement = 'header' | 'options' | 'input' | 'hints' | 'progress';
|
|
9
|
-
/**
|
|
10
|
-
* Visibility configuration for layout elements
|
|
11
|
-
*/
|
|
12
|
-
export interface LayoutVisibility {
|
|
13
|
-
header?: boolean;
|
|
14
|
-
input?: boolean;
|
|
15
|
-
hints?: boolean;
|
|
16
|
-
progress?: boolean;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Spacing configuration for layout elements
|
|
20
|
-
* Values represent number of blank lines
|
|
21
|
-
*/
|
|
22
|
-
export interface LayoutSpacing {
|
|
23
|
-
beforeHeader?: number;
|
|
24
|
-
afterHeader?: number;
|
|
25
|
-
beforeOptions?: number;
|
|
26
|
-
afterOptions?: number;
|
|
27
|
-
beforeInput?: number;
|
|
28
|
-
afterInput?: number;
|
|
29
|
-
beforeHints?: number;
|
|
30
|
-
beforeProgress?: number;
|
|
31
|
-
afterProgress?: number;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Complete menu layout configuration
|
|
35
|
-
*/
|
|
36
|
-
export interface MenuLayout {
|
|
37
|
-
/** Order in which elements are rendered */
|
|
38
|
-
order: LayoutElement[];
|
|
39
|
-
/** Which elements are visible */
|
|
40
|
-
visible: LayoutVisibility;
|
|
41
|
-
/** Spacing between elements */
|
|
42
|
-
spacing?: LayoutSpacing;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Preset layout configurations
|
|
46
|
-
*/
|
|
47
|
-
export declare const LAYOUT_PRESETS: {
|
|
48
|
-
/** Main menu with header */
|
|
49
|
-
MAIN_MENU: MenuLayout;
|
|
50
|
-
/** Sub menu without header */
|
|
51
|
-
SUB_MENU: MenuLayout;
|
|
52
|
-
/** Wizard step with progress indicator */
|
|
53
|
-
WIZARD_STEP: MenuLayout;
|
|
54
|
-
/** Minimal layout (options only) */
|
|
55
|
-
MINIMAL: MenuLayout;
|
|
56
|
-
};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Layout system types for CLI Menu Kit
|
|
4
|
-
* Defines how components are composed and rendered
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.LAYOUT_PRESETS = void 0;
|
|
8
|
-
/**
|
|
9
|
-
* Preset layout configurations
|
|
10
|
-
*/
|
|
11
|
-
exports.LAYOUT_PRESETS = {
|
|
12
|
-
/** Main menu with header */
|
|
13
|
-
MAIN_MENU: {
|
|
14
|
-
order: ['header', 'options', 'input', 'hints'],
|
|
15
|
-
visible: { header: true, input: true, hints: true },
|
|
16
|
-
spacing: { afterHeader: 1, afterOptions: 1, beforeHints: 1 }
|
|
17
|
-
},
|
|
18
|
-
/** Sub menu without header */
|
|
19
|
-
SUB_MENU: {
|
|
20
|
-
order: ['options', 'input', 'hints'],
|
|
21
|
-
visible: { header: false, input: true, hints: true },
|
|
22
|
-
spacing: { afterOptions: 1, beforeHints: 1 }
|
|
23
|
-
},
|
|
24
|
-
/** Wizard step with progress indicator */
|
|
25
|
-
WIZARD_STEP: {
|
|
26
|
-
order: ['header', 'progress', 'options', 'input', 'hints'],
|
|
27
|
-
visible: { header: true, progress: true, input: true, hints: true },
|
|
28
|
-
spacing: { afterHeader: 1, afterProgress: 1, afterOptions: 1, beforeHints: 1 }
|
|
29
|
-
},
|
|
30
|
-
/** Minimal layout (options only) */
|
|
31
|
-
MINIMAL: {
|
|
32
|
-
order: ['options'],
|
|
33
|
-
visible: { header: false, input: false, hints: false },
|
|
34
|
-
spacing: {}
|
|
35
|
-
}
|
|
36
|
-
};
|