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.
- 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/header.d.ts +40 -0
- package/dist/components/display/header.js +331 -18
- package/dist/components/display/headers.d.ts +1 -0
- package/dist/components/display/headers.js +15 -5
- 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 +4 -1
- package/dist/components/display/index.js +17 -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/messages.js +5 -5
- package/dist/components/display/progress.d.ts +17 -0
- package/dist/components/display/progress.js +18 -0
- package/dist/components/display/summary.js +72 -10
- package/dist/components/display/table.d.ts +44 -0
- package/dist/components/display/table.js +108 -0
- package/dist/components/inputs/language-input.js +8 -5
- package/dist/components/inputs/number-input.js +19 -14
- package/dist/components/inputs/text-input.js +50 -13
- package/dist/components/menus/boolean-menu.js +34 -20
- package/dist/components/menus/checkbox-menu.d.ts +2 -1
- package/dist/components/menus/checkbox-menu.js +35 -61
- package/dist/components/menus/checkbox-table-menu.d.ts +12 -0
- package/dist/components/menus/checkbox-table-menu.js +398 -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 +34 -0
- package/dist/components/menus/radio-menu-split.js +258 -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 +100 -134
- package/dist/components.js +3 -3
- package/dist/config/index.d.ts +5 -0
- package/dist/config/index.js +21 -0
- package/dist/config/language-config.d.ts +73 -0
- package/dist/config/language-config.js +157 -0
- package/dist/config/user-config.d.ts +83 -0
- package/dist/config/user-config.js +185 -0
- package/dist/core/colors.d.ts +24 -18
- package/dist/core/colors.js +74 -7
- 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 +46 -22
- 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 +17 -1
- package/dist/core/terminal.js +124 -4
- package/dist/core/virtual-scroll.d.ts +65 -0
- package/dist/core/virtual-scroll.js +120 -0
- package/dist/features/commands.js +23 -22
- 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 +7 -4
- package/dist/index.js +49 -4
- package/dist/layout.d.ts +67 -0
- package/dist/layout.js +86 -0
- package/dist/page-layout.d.ts +123 -0
- package/dist/page-layout.js +195 -0
- package/dist/types/input.types.d.ts +8 -0
- package/dist/types/menu.types.d.ts +61 -5
- package/package.json +4 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Exports all display component functions
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.renderHeader = exports.createSimpleSummary = exports.createSummaryTable = exports.renderSummaryTable = exports.createMessage = exports.showQuestion = exports.showInfo = exports.showWarning = exports.showError = exports.showSuccess = exports.renderMessage = exports.createStageSeparator = exports.createStageHeader = exports.createProgressIndicator = exports.renderStageSeparator = exports.renderStageHeader = exports.renderProgressIndicator = exports.createAsciiHeader = exports.createSectionHeader = exports.createSimpleHeader = exports.renderAsciiHeader = exports.renderSectionHeader = exports.renderSimpleHeader = void 0;
|
|
7
|
+
exports.createNumberedList = exports.createBulletList = exports.createList = exports.renderList = exports.createTable = exports.renderTable = exports.HintTypes = exports.generateInputHints = exports.generateMenuHints = exports.createHints = exports.renderHintsComponent = exports.renderHeader = exports.createSimpleSummary = exports.createSummaryTable = exports.renderSummaryTable = exports.createMessage = exports.showQuestion = exports.showInfo = exports.showWarning = exports.showError = exports.showSuccess = exports.renderMessage = exports.createProgressCheckmark = exports.renderProgressCheckmark = exports.createStageSeparator = exports.createStageHeader = exports.createProgressIndicator = exports.renderStageSeparator = exports.renderStageHeader = exports.renderProgressIndicator = exports.createAsciiHeader = exports.createSectionHeader = exports.createSimpleHeader = exports.renderAsciiHeader = exports.renderSectionHeader = exports.renderSimpleHeader = void 0;
|
|
8
8
|
var headers_js_1 = require("./headers.js");
|
|
9
9
|
Object.defineProperty(exports, "renderSimpleHeader", { enumerable: true, get: function () { return headers_js_1.renderSimpleHeader; } });
|
|
10
10
|
Object.defineProperty(exports, "renderSectionHeader", { enumerable: true, get: function () { return headers_js_1.renderSectionHeader; } });
|
|
@@ -19,6 +19,8 @@ Object.defineProperty(exports, "renderStageSeparator", { enumerable: true, get:
|
|
|
19
19
|
Object.defineProperty(exports, "createProgressIndicator", { enumerable: true, get: function () { return progress_js_1.createProgressIndicator; } });
|
|
20
20
|
Object.defineProperty(exports, "createStageHeader", { enumerable: true, get: function () { return progress_js_1.createStageHeader; } });
|
|
21
21
|
Object.defineProperty(exports, "createStageSeparator", { enumerable: true, get: function () { return progress_js_1.createStageSeparator; } });
|
|
22
|
+
Object.defineProperty(exports, "renderProgressCheckmark", { enumerable: true, get: function () { return progress_js_1.renderProgressCheckmark; } });
|
|
23
|
+
Object.defineProperty(exports, "createProgressCheckmark", { enumerable: true, get: function () { return progress_js_1.createProgressCheckmark; } });
|
|
22
24
|
var messages_js_1 = require("./messages.js");
|
|
23
25
|
Object.defineProperty(exports, "renderMessage", { enumerable: true, get: function () { return messages_js_1.renderMessage; } });
|
|
24
26
|
Object.defineProperty(exports, "showSuccess", { enumerable: true, get: function () { return messages_js_1.showSuccess; } });
|
|
@@ -33,3 +35,17 @@ Object.defineProperty(exports, "createSummaryTable", { enumerable: true, get: fu
|
|
|
33
35
|
Object.defineProperty(exports, "createSimpleSummary", { enumerable: true, get: function () { return summary_js_1.createSimpleSummary; } });
|
|
34
36
|
var header_js_1 = require("./header.js");
|
|
35
37
|
Object.defineProperty(exports, "renderHeader", { enumerable: true, get: function () { return header_js_1.renderHeader; } });
|
|
38
|
+
var hints_js_1 = require("./hints.js");
|
|
39
|
+
Object.defineProperty(exports, "renderHintsComponent", { enumerable: true, get: function () { return hints_js_1.renderHintsComponent; } });
|
|
40
|
+
Object.defineProperty(exports, "createHints", { enumerable: true, get: function () { return hints_js_1.createHints; } });
|
|
41
|
+
Object.defineProperty(exports, "generateMenuHints", { enumerable: true, get: function () { return hints_js_1.generateMenuHints; } });
|
|
42
|
+
Object.defineProperty(exports, "generateInputHints", { enumerable: true, get: function () { return hints_js_1.generateInputHints; } });
|
|
43
|
+
Object.defineProperty(exports, "HintTypes", { enumerable: true, get: function () { return hints_js_1.HintTypes; } });
|
|
44
|
+
var table_js_1 = require("./table.js");
|
|
45
|
+
Object.defineProperty(exports, "renderTable", { enumerable: true, get: function () { return table_js_1.renderTable; } });
|
|
46
|
+
Object.defineProperty(exports, "createTable", { enumerable: true, get: function () { return table_js_1.createTable; } });
|
|
47
|
+
var list_js_1 = require("./list.js");
|
|
48
|
+
Object.defineProperty(exports, "renderList", { enumerable: true, get: function () { return list_js_1.renderList; } });
|
|
49
|
+
Object.defineProperty(exports, "createList", { enumerable: true, get: function () { return list_js_1.createList; } });
|
|
50
|
+
Object.defineProperty(exports, "createBulletList", { enumerable: true, get: function () { return list_js_1.createBulletList; } });
|
|
51
|
+
Object.defineProperty(exports, "createNumberedList", { enumerable: true, get: function () { return list_js_1.createNumberedList; } });
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input Prompt Component
|
|
3
|
+
* Factory function to create input prompt configuration
|
|
4
|
+
*/
|
|
5
|
+
export interface InputPromptConfig {
|
|
6
|
+
/** Prompt text to display */
|
|
7
|
+
prompt: string;
|
|
8
|
+
/** Default value */
|
|
9
|
+
defaultValue?: string;
|
|
10
|
+
/** Allow empty input */
|
|
11
|
+
allowEmpty?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Create an input prompt component configuration
|
|
15
|
+
* Returns a configuration object that can be used in footer.input
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const inputConfig = createInputPromptComponent({
|
|
20
|
+
* prompt: '请输入名称',
|
|
21
|
+
* defaultValue: '',
|
|
22
|
+
* allowEmpty: false
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* await renderPage({
|
|
26
|
+
* header: {...},
|
|
27
|
+
* mainArea: {...},
|
|
28
|
+
* footer: {
|
|
29
|
+
* input: inputConfig,
|
|
30
|
+
* hints: ['Enter 确认', 'Esc 取消']
|
|
31
|
+
* }
|
|
32
|
+
* });
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function createInputPromptComponent(config: InputPromptConfig): InputPromptConfig;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Input Prompt Component
|
|
4
|
+
* Factory function to create input prompt configuration
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.createInputPromptComponent = createInputPromptComponent;
|
|
8
|
+
/**
|
|
9
|
+
* Create an input prompt component configuration
|
|
10
|
+
* Returns a configuration object that can be used in footer.input
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const inputConfig = createInputPromptComponent({
|
|
15
|
+
* prompt: '请输入名称',
|
|
16
|
+
* defaultValue: '',
|
|
17
|
+
* allowEmpty: false
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* await renderPage({
|
|
21
|
+
* header: {...},
|
|
22
|
+
* mainArea: {...},
|
|
23
|
+
* footer: {
|
|
24
|
+
* input: inputConfig,
|
|
25
|
+
* hints: ['Enter 确认', 'Esc 取消']
|
|
26
|
+
* }
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
function createInputPromptComponent(config) {
|
|
31
|
+
return {
|
|
32
|
+
prompt: config.prompt,
|
|
33
|
+
defaultValue: config.defaultValue,
|
|
34
|
+
allowEmpty: config.allowEmpty ?? false
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List Component
|
|
3
|
+
* Displays items in a list format with optional bullets/numbers
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* List item configuration
|
|
7
|
+
*/
|
|
8
|
+
export interface ListItem {
|
|
9
|
+
/** Item text */
|
|
10
|
+
text: string;
|
|
11
|
+
/** Item indent level (0 = no indent) */
|
|
12
|
+
indent?: number;
|
|
13
|
+
/** Custom bullet/prefix */
|
|
14
|
+
bullet?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* List configuration
|
|
18
|
+
*/
|
|
19
|
+
export interface ListConfig {
|
|
20
|
+
/** List items */
|
|
21
|
+
items: (string | ListItem)[];
|
|
22
|
+
/** List style */
|
|
23
|
+
style?: 'bullet' | 'number' | 'none';
|
|
24
|
+
/** Custom bullet character (for bullet style) */
|
|
25
|
+
bulletChar?: string;
|
|
26
|
+
/** Indent size in spaces */
|
|
27
|
+
indentSize?: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Render list component
|
|
31
|
+
* @param config - List configuration
|
|
32
|
+
*/
|
|
33
|
+
export declare function renderList(config: ListConfig): void;
|
|
34
|
+
/**
|
|
35
|
+
* Create list configuration (factory function)
|
|
36
|
+
*/
|
|
37
|
+
export declare function createList(items: (string | ListItem)[], options?: {
|
|
38
|
+
style?: 'bullet' | 'number' | 'none';
|
|
39
|
+
bulletChar?: string;
|
|
40
|
+
indentSize?: number;
|
|
41
|
+
}): ListConfig;
|
|
42
|
+
/**
|
|
43
|
+
* Create a simple bullet list
|
|
44
|
+
*/
|
|
45
|
+
export declare function createBulletList(items: string[]): ListConfig;
|
|
46
|
+
/**
|
|
47
|
+
* Create a numbered list
|
|
48
|
+
*/
|
|
49
|
+
export declare function createNumberedList(items: string[]): ListConfig;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* List Component
|
|
4
|
+
* Displays items in a list format with optional bullets/numbers
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.renderList = renderList;
|
|
8
|
+
exports.createList = createList;
|
|
9
|
+
exports.createBulletList = createBulletList;
|
|
10
|
+
exports.createNumberedList = createNumberedList;
|
|
11
|
+
const terminal_js_1 = require("../../core/terminal.js");
|
|
12
|
+
/**
|
|
13
|
+
* Render list component
|
|
14
|
+
* @param config - List configuration
|
|
15
|
+
*/
|
|
16
|
+
function renderList(config) {
|
|
17
|
+
const { items, style = 'bullet', bulletChar = '•', indentSize = 2 } = config;
|
|
18
|
+
if (items.length === 0) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
items.forEach((item, index) => {
|
|
22
|
+
let text;
|
|
23
|
+
let indent;
|
|
24
|
+
let bullet;
|
|
25
|
+
// Parse item
|
|
26
|
+
if (typeof item === 'string') {
|
|
27
|
+
text = item;
|
|
28
|
+
indent = 0;
|
|
29
|
+
bullet = undefined;
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
text = item.text;
|
|
33
|
+
indent = item.indent || 0;
|
|
34
|
+
bullet = item.bullet;
|
|
35
|
+
}
|
|
36
|
+
// Generate prefix based on style
|
|
37
|
+
let prefix;
|
|
38
|
+
if (bullet) {
|
|
39
|
+
// Custom bullet
|
|
40
|
+
prefix = bullet;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
switch (style) {
|
|
44
|
+
case 'number':
|
|
45
|
+
prefix = `${index + 1}.`;
|
|
46
|
+
break;
|
|
47
|
+
case 'bullet':
|
|
48
|
+
prefix = bulletChar;
|
|
49
|
+
break;
|
|
50
|
+
case 'none':
|
|
51
|
+
default:
|
|
52
|
+
prefix = '';
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// Build line with indent and prefix
|
|
57
|
+
const indentStr = ' '.repeat(indent * indentSize);
|
|
58
|
+
const line = prefix
|
|
59
|
+
? `${indentStr}${prefix} ${text}`
|
|
60
|
+
: `${indentStr}${text}`;
|
|
61
|
+
(0, terminal_js_1.writeLine)(line);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Create list configuration (factory function)
|
|
66
|
+
*/
|
|
67
|
+
function createList(items, options) {
|
|
68
|
+
return {
|
|
69
|
+
items,
|
|
70
|
+
style: options?.style ?? 'bullet',
|
|
71
|
+
bulletChar: options?.bulletChar ?? '•',
|
|
72
|
+
indentSize: options?.indentSize ?? 2
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Create a simple bullet list
|
|
77
|
+
*/
|
|
78
|
+
function createBulletList(items) {
|
|
79
|
+
return createList(items, { style: 'bullet' });
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Create a numbered list
|
|
83
|
+
*/
|
|
84
|
+
function createNumberedList(items) {
|
|
85
|
+
return createList(items, { style: 'number' });
|
|
86
|
+
}
|
|
@@ -24,23 +24,23 @@ function renderMessage(config) {
|
|
|
24
24
|
switch (type) {
|
|
25
25
|
case 'success':
|
|
26
26
|
icon = '✓';
|
|
27
|
-
color = colors_js_1.
|
|
27
|
+
color = colors_js_1.uiColors.success;
|
|
28
28
|
break;
|
|
29
29
|
case 'error':
|
|
30
30
|
icon = '✗';
|
|
31
|
-
color = colors_js_1.
|
|
31
|
+
color = colors_js_1.uiColors.error;
|
|
32
32
|
break;
|
|
33
33
|
case 'warning':
|
|
34
34
|
icon = '⚠';
|
|
35
|
-
color = colors_js_1.
|
|
35
|
+
color = colors_js_1.uiColors.warning;
|
|
36
36
|
break;
|
|
37
37
|
case 'info':
|
|
38
38
|
icon = 'ℹ';
|
|
39
|
-
color = colors_js_1.
|
|
39
|
+
color = colors_js_1.uiColors.info;
|
|
40
40
|
break;
|
|
41
41
|
case 'question':
|
|
42
42
|
icon = '?';
|
|
43
|
-
color = colors_js_1.
|
|
43
|
+
color = colors_js_1.uiColors.warning;
|
|
44
44
|
break;
|
|
45
45
|
}
|
|
46
46
|
(0, terminal_js_1.writeLine)(`${color}${icon}${colors_js_1.colors.reset} ${message}`);
|
|
@@ -39,3 +39,20 @@ export declare function createStageHeader(stageName: string, stepNumber: number)
|
|
|
39
39
|
* @param width - Optional width
|
|
40
40
|
*/
|
|
41
41
|
export declare function createStageSeparator(char?: string, width?: number): void;
|
|
42
|
+
/**
|
|
43
|
+
* Single-line completed progress marker.
|
|
44
|
+
* Use this for execution flows that print one completed step at a time.
|
|
45
|
+
*/
|
|
46
|
+
export declare function renderProgressCheckmark(step: string, options?: {
|
|
47
|
+
icon?: string;
|
|
48
|
+
indent?: string;
|
|
49
|
+
color?: string;
|
|
50
|
+
}): void;
|
|
51
|
+
/**
|
|
52
|
+
* Alias factory for renderProgressCheckmark
|
|
53
|
+
*/
|
|
54
|
+
export declare function createProgressCheckmark(step: string, options?: {
|
|
55
|
+
icon?: string;
|
|
56
|
+
indent?: string;
|
|
57
|
+
color?: string;
|
|
58
|
+
}): void;
|
|
@@ -10,6 +10,8 @@ exports.renderStageSeparator = renderStageSeparator;
|
|
|
10
10
|
exports.createProgressIndicator = createProgressIndicator;
|
|
11
11
|
exports.createStageHeader = createStageHeader;
|
|
12
12
|
exports.createStageSeparator = createStageSeparator;
|
|
13
|
+
exports.renderProgressCheckmark = renderProgressCheckmark;
|
|
14
|
+
exports.createProgressCheckmark = createProgressCheckmark;
|
|
13
15
|
const terminal_js_1 = require("../../core/terminal.js");
|
|
14
16
|
const colors_js_1 = require("../../core/colors.js");
|
|
15
17
|
const terminal_js_2 = require("../../core/terminal.js");
|
|
@@ -80,3 +82,19 @@ function createStageHeader(stageName, stepNumber) {
|
|
|
80
82
|
function createStageSeparator(char, width) {
|
|
81
83
|
renderStageSeparator(char, width);
|
|
82
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Single-line completed progress marker.
|
|
87
|
+
* Use this for execution flows that print one completed step at a time.
|
|
88
|
+
*/
|
|
89
|
+
function renderProgressCheckmark(step, options) {
|
|
90
|
+
const icon = options?.icon ?? '✓';
|
|
91
|
+
const indent = options?.indent ?? ' ';
|
|
92
|
+
const color = options?.color ?? colors_js_1.uiColors.primary;
|
|
93
|
+
(0, terminal_js_1.writeLine)(`${indent}${color}${icon}${colors_js_1.colors.reset} ${step}`);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Alias factory for renderProgressCheckmark
|
|
97
|
+
*/
|
|
98
|
+
function createProgressCheckmark(step, options) {
|
|
99
|
+
renderProgressCheckmark(step, options);
|
|
100
|
+
}
|
|
@@ -10,6 +10,58 @@ exports.createSimpleSummary = createSimpleSummary;
|
|
|
10
10
|
const terminal_js_1 = require("../../core/terminal.js");
|
|
11
11
|
const colors_js_1 = require("../../core/colors.js");
|
|
12
12
|
const terminal_js_2 = require("../../core/terminal.js");
|
|
13
|
+
function resolveColorSpec(spec) {
|
|
14
|
+
if (!spec) {
|
|
15
|
+
return '';
|
|
16
|
+
}
|
|
17
|
+
return spec
|
|
18
|
+
.split('+')
|
|
19
|
+
.map(part => {
|
|
20
|
+
const token = part.trim();
|
|
21
|
+
if (!token) {
|
|
22
|
+
return '';
|
|
23
|
+
}
|
|
24
|
+
const named = colors_js_1.colors[token];
|
|
25
|
+
if (named) {
|
|
26
|
+
return named;
|
|
27
|
+
}
|
|
28
|
+
// Accept raw ANSI sequences (e.g. values from getUIColors()).
|
|
29
|
+
if (/^\x1b\[[0-9;]*m$/.test(token)) {
|
|
30
|
+
return token;
|
|
31
|
+
}
|
|
32
|
+
return '';
|
|
33
|
+
})
|
|
34
|
+
.join('');
|
|
35
|
+
}
|
|
36
|
+
function splitLongToken(token, maxWidth) {
|
|
37
|
+
if (token.length <= maxWidth) {
|
|
38
|
+
return [token];
|
|
39
|
+
}
|
|
40
|
+
const chunks = [];
|
|
41
|
+
let rest = token;
|
|
42
|
+
const breakChars = ['/', '\\', '-', '_', '.'];
|
|
43
|
+
while (rest.length > maxWidth) {
|
|
44
|
+
let breakPos = -1;
|
|
45
|
+
for (const ch of breakChars) {
|
|
46
|
+
const idx = rest.lastIndexOf(ch, maxWidth - 1);
|
|
47
|
+
if (idx > breakPos) {
|
|
48
|
+
breakPos = idx;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (breakPos <= 0) {
|
|
52
|
+
breakPos = maxWidth;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
breakPos += 1;
|
|
56
|
+
}
|
|
57
|
+
chunks.push(rest.slice(0, breakPos));
|
|
58
|
+
rest = rest.slice(breakPos);
|
|
59
|
+
}
|
|
60
|
+
if (rest.length > 0) {
|
|
61
|
+
chunks.push(rest);
|
|
62
|
+
}
|
|
63
|
+
return chunks;
|
|
64
|
+
}
|
|
13
65
|
/**
|
|
14
66
|
* Wrap text to fit within a specific width, preserving ANSI color codes
|
|
15
67
|
*/
|
|
@@ -17,10 +69,15 @@ function wrapTextWithColors(text, maxWidth) {
|
|
|
17
69
|
// Extract ANSI codes and plain text
|
|
18
70
|
const ansiRegex = /\x1b\[[0-9;]*m/g;
|
|
19
71
|
const plainText = text.replace(ansiRegex, '');
|
|
72
|
+
const hasAnsi = /\x1b\[[0-9;]*m/.test(text);
|
|
20
73
|
// If plain text fits, return as-is
|
|
21
74
|
if (plainText.length <= maxWidth) {
|
|
22
75
|
return [text];
|
|
23
76
|
}
|
|
77
|
+
// Fast path for plain text (no ANSI): support long token wrapping (e.g. file paths).
|
|
78
|
+
if (!hasAnsi) {
|
|
79
|
+
return wrapText(text, maxWidth);
|
|
80
|
+
}
|
|
24
81
|
// Find all ANSI codes and their positions in the original text
|
|
25
82
|
const codes = [];
|
|
26
83
|
let match;
|
|
@@ -94,6 +151,16 @@ function wrapText(text, maxWidth) {
|
|
|
94
151
|
const lines = [];
|
|
95
152
|
let currentLine = '';
|
|
96
153
|
for (const word of words) {
|
|
154
|
+
if (word.length > maxWidth) {
|
|
155
|
+
if (currentLine) {
|
|
156
|
+
lines.push(currentLine);
|
|
157
|
+
currentLine = '';
|
|
158
|
+
}
|
|
159
|
+
const chunks = splitLongToken(word, maxWidth);
|
|
160
|
+
lines.push(...chunks.slice(0, -1));
|
|
161
|
+
currentLine = chunks[chunks.length - 1] || '';
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
97
164
|
const testLine = currentLine ? `${currentLine} ${word}` : word;
|
|
98
165
|
if (testLine.length <= maxWidth) {
|
|
99
166
|
currentLine = testLine;
|
|
@@ -136,12 +203,7 @@ function renderSummaryTable(config) {
|
|
|
136
203
|
(0, terminal_js_1.writeLine)(`│${' '.repeat(boxWidth - 2)}│`);
|
|
137
204
|
// Title if provided
|
|
138
205
|
if (title) {
|
|
139
|
-
|
|
140
|
-
let titleColor = '';
|
|
141
|
-
if (finalColors.title) {
|
|
142
|
-
const parts = finalColors.title.split('+');
|
|
143
|
-
titleColor = parts.map(part => colors_js_1.colors[part.trim()] || '').join('');
|
|
144
|
-
}
|
|
206
|
+
const titleColor = resolveColorSpec(finalColors.title);
|
|
145
207
|
const resetColor = titleColor ? colors_js_1.colors.reset : '';
|
|
146
208
|
let titleLine;
|
|
147
209
|
let remainingSpace;
|
|
@@ -173,7 +235,7 @@ function renderSummaryTable(config) {
|
|
|
173
235
|
sections.forEach((section, sectionIndex) => {
|
|
174
236
|
// Section header if provided
|
|
175
237
|
if (section.header) {
|
|
176
|
-
const headerColor = finalColors.sectionHeader
|
|
238
|
+
const headerColor = resolveColorSpec(finalColors.sectionHeader);
|
|
177
239
|
const resetColor = headerColor ? colors_js_1.colors.reset : '';
|
|
178
240
|
const headerLine = ` ${headerColor}${section.header}${resetColor}`;
|
|
179
241
|
const remainingSpace = boxWidth - section.header.length - 4;
|
|
@@ -188,7 +250,7 @@ function renderSummaryTable(config) {
|
|
|
188
250
|
// Wrap the value (preserving colors if present)
|
|
189
251
|
const wrappedLines = wrapTextWithColors(item.value, valueMaxWidth);
|
|
190
252
|
// First line with key
|
|
191
|
-
const keyColor = finalColors.key
|
|
253
|
+
const keyColor = resolveColorSpec(finalColors.key);
|
|
192
254
|
const keyResetColor = keyColor ? colors_js_1.colors.reset : '';
|
|
193
255
|
// wrappedLines already contain colors, don't add valueColor
|
|
194
256
|
const firstLine = ` ${keyColor}${item.key}:${keyResetColor}${' '.repeat(Math.max(1, keyPadding - item.key.length))}${wrappedLines[0]}`;
|
|
@@ -205,9 +267,9 @@ function renderSummaryTable(config) {
|
|
|
205
267
|
}
|
|
206
268
|
else {
|
|
207
269
|
// No wrapping needed
|
|
208
|
-
const keyColor = finalColors.key
|
|
270
|
+
const keyColor = resolveColorSpec(finalColors.key);
|
|
209
271
|
const keyResetColor = keyColor ? colors_js_1.colors.reset : '';
|
|
210
|
-
const valueColor = finalColors.value
|
|
272
|
+
const valueColor = resolveColorSpec(finalColors.value);
|
|
211
273
|
const valueResetColor = valueColor ? colors_js_1.colors.reset : '';
|
|
212
274
|
// Only wrap value with color if valueColor is set, otherwise preserve original colors in item.value
|
|
213
275
|
const coloredValue = valueColor ? `${valueColor}${item.value}${valueResetColor}` : item.value;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Table Component
|
|
3
|
+
* Displays data in a table format with headers and rows
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Table column configuration
|
|
7
|
+
*/
|
|
8
|
+
export interface TableColumn {
|
|
9
|
+
/** Column header */
|
|
10
|
+
header: string;
|
|
11
|
+
/** Column key in data object */
|
|
12
|
+
key: string;
|
|
13
|
+
/** Column width (optional, auto-calculated if not provided) */
|
|
14
|
+
width?: number;
|
|
15
|
+
/** Text alignment */
|
|
16
|
+
align?: 'left' | 'center' | 'right';
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Table configuration
|
|
20
|
+
*/
|
|
21
|
+
export interface TableConfig {
|
|
22
|
+
/** Table columns */
|
|
23
|
+
columns: TableColumn[];
|
|
24
|
+
/** Table data rows */
|
|
25
|
+
data: Record<string, any>[];
|
|
26
|
+
/** Show table borders */
|
|
27
|
+
showBorders?: boolean;
|
|
28
|
+
/** Show header separator */
|
|
29
|
+
showHeaderSeparator?: boolean;
|
|
30
|
+
/** Border color (ANSI escape code, e.g., '\x1b[2m' for dim/gray) */
|
|
31
|
+
borderColor?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Render table component
|
|
35
|
+
* @param config - Table configuration
|
|
36
|
+
*/
|
|
37
|
+
export declare function renderTable(config: TableConfig): void;
|
|
38
|
+
/**
|
|
39
|
+
* Create table configuration (factory function)
|
|
40
|
+
*/
|
|
41
|
+
export declare function createTable(columns: TableColumn[], data: Record<string, any>[], options?: {
|
|
42
|
+
showBorders?: boolean;
|
|
43
|
+
showHeaderSeparator?: boolean;
|
|
44
|
+
}): TableConfig;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Table Component
|
|
4
|
+
* Displays data in a table format with headers and rows
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.renderTable = renderTable;
|
|
8
|
+
exports.createTable = createTable;
|
|
9
|
+
const terminal_js_1 = require("../../core/terminal.js");
|
|
10
|
+
/**
|
|
11
|
+
* Render table component
|
|
12
|
+
* @param config - Table configuration
|
|
13
|
+
*/
|
|
14
|
+
function renderTable(config) {
|
|
15
|
+
const { columns, data, showBorders = true, showHeaderSeparator = true, borderColor = '' } = config;
|
|
16
|
+
if (columns.length === 0 || data.length === 0) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const resetColor = borderColor ? '\x1b[0m' : '';
|
|
20
|
+
// Calculate column widths
|
|
21
|
+
const columnWidths = columns.map((col, index) => {
|
|
22
|
+
if (col.width)
|
|
23
|
+
return col.width;
|
|
24
|
+
// Auto-calculate width based on header and data
|
|
25
|
+
const headerWidth = col.header.length;
|
|
26
|
+
const dataWidth = Math.max(...data.map(row => String(row[col.key] || '').length));
|
|
27
|
+
return Math.max(headerWidth, dataWidth) + 2; // +2 for padding
|
|
28
|
+
});
|
|
29
|
+
// Render top border
|
|
30
|
+
if (showBorders) {
|
|
31
|
+
const border = columnWidths.map(w => '─'.repeat(w)).join('┬');
|
|
32
|
+
(0, terminal_js_1.writeLine)(`${borderColor}┌${border}┐${resetColor}`);
|
|
33
|
+
}
|
|
34
|
+
// Render header
|
|
35
|
+
const headerCells = columns.map((col, index) => {
|
|
36
|
+
const width = columnWidths[index];
|
|
37
|
+
const align = col.align || 'left';
|
|
38
|
+
return alignText(col.header, width, align);
|
|
39
|
+
});
|
|
40
|
+
if (showBorders) {
|
|
41
|
+
(0, terminal_js_1.writeLine)(`${borderColor}│${resetColor}${headerCells.join(`${borderColor}│${resetColor}`)}${borderColor}│${resetColor}`);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
(0, terminal_js_1.writeLine)(headerCells.join(' '));
|
|
45
|
+
}
|
|
46
|
+
// Render header separator
|
|
47
|
+
if (showHeaderSeparator) {
|
|
48
|
+
if (showBorders) {
|
|
49
|
+
const separator = columnWidths.map(w => '─'.repeat(w)).join('┼');
|
|
50
|
+
(0, terminal_js_1.writeLine)(`${borderColor}├${separator}┤${resetColor}`);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
const separator = columnWidths.map(w => '─'.repeat(w)).join(' ');
|
|
54
|
+
(0, terminal_js_1.writeLine)(separator);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Render data rows
|
|
58
|
+
data.forEach((row, rowIndex) => {
|
|
59
|
+
const cells = columns.map((col, colIndex) => {
|
|
60
|
+
const width = columnWidths[colIndex];
|
|
61
|
+
const align = col.align || 'left';
|
|
62
|
+
const value = String(row[col.key] || '');
|
|
63
|
+
return alignText(value, width, align);
|
|
64
|
+
});
|
|
65
|
+
if (showBorders) {
|
|
66
|
+
(0, terminal_js_1.writeLine)(`${borderColor}│${resetColor}${cells.join(`${borderColor}│${resetColor}`)}${borderColor}│${resetColor}`);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
(0, terminal_js_1.writeLine)(cells.join(' '));
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
// Render bottom border
|
|
73
|
+
if (showBorders) {
|
|
74
|
+
const border = columnWidths.map(w => '─'.repeat(w)).join('┴');
|
|
75
|
+
(0, terminal_js_1.writeLine)(`${borderColor}└${border}┘${resetColor}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Align text within a given width
|
|
80
|
+
*/
|
|
81
|
+
function alignText(text, width, align) {
|
|
82
|
+
const padding = width - text.length;
|
|
83
|
+
if (padding <= 0) {
|
|
84
|
+
return text.substring(0, width);
|
|
85
|
+
}
|
|
86
|
+
switch (align) {
|
|
87
|
+
case 'center':
|
|
88
|
+
const leftPad = Math.floor(padding / 2);
|
|
89
|
+
const rightPad = padding - leftPad;
|
|
90
|
+
return ' '.repeat(leftPad) + text + ' '.repeat(rightPad);
|
|
91
|
+
case 'right':
|
|
92
|
+
return ' '.repeat(padding) + text;
|
|
93
|
+
case 'left':
|
|
94
|
+
default:
|
|
95
|
+
return text + ' '.repeat(padding);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Create table configuration (factory function)
|
|
100
|
+
*/
|
|
101
|
+
function createTable(columns, data, options) {
|
|
102
|
+
return {
|
|
103
|
+
columns,
|
|
104
|
+
data,
|
|
105
|
+
showBorders: options?.showBorders ?? true,
|
|
106
|
+
showHeaderSeparator: options?.showHeaderSeparator ?? true
|
|
107
|
+
};
|
|
108
|
+
}
|
|
@@ -9,13 +9,14 @@ const terminal_js_1 = require("../../core/terminal.js");
|
|
|
9
9
|
const keyboard_js_1 = require("../../core/keyboard.js");
|
|
10
10
|
const renderer_js_1 = require("../../core/renderer.js");
|
|
11
11
|
const colors_js_1 = require("../../core/colors.js");
|
|
12
|
+
const registry_js_1 = require("../../i18n/registry.js");
|
|
12
13
|
/**
|
|
13
14
|
* Show a language selector
|
|
14
15
|
* @param config - Selector configuration
|
|
15
16
|
* @returns Promise resolving to selected language code
|
|
16
17
|
*/
|
|
17
18
|
async function showLanguageSelector(config) {
|
|
18
|
-
const { languages, defaultLanguage, prompt = '
|
|
19
|
+
const { languages, defaultLanguage, prompt = 'Select Language', onExit, preserveOnExit = false } = config;
|
|
19
20
|
// Validate languages
|
|
20
21
|
if (!languages || languages.length === 0) {
|
|
21
22
|
throw new Error('LanguageSelector requires at least one language');
|
|
@@ -33,7 +34,7 @@ async function showLanguageSelector(config) {
|
|
|
33
34
|
(0, terminal_js_1.clearMenu)(state);
|
|
34
35
|
let lineCount = 0;
|
|
35
36
|
// Render header
|
|
36
|
-
(0, renderer_js_1.renderHeader)(` ${prompt}`, colors_js_1.
|
|
37
|
+
(0, renderer_js_1.renderHeader)(` ${prompt}`, colors_js_1.uiColors.primary);
|
|
37
38
|
lineCount++;
|
|
38
39
|
(0, renderer_js_1.renderBlankLines)(1);
|
|
39
40
|
lineCount++;
|
|
@@ -48,7 +49,7 @@ async function showLanguageSelector(config) {
|
|
|
48
49
|
// Render hints
|
|
49
50
|
(0, renderer_js_1.renderBlankLines)(1);
|
|
50
51
|
lineCount++;
|
|
51
|
-
(0, renderer_js_1.renderHints)([
|
|
52
|
+
(0, renderer_js_1.renderHints)([(0, registry_js_1.t)('hints.arrows'), (0, registry_js_1.t)('hints.numbers'), (0, registry_js_1.t)('hints.enter')]);
|
|
52
53
|
lineCount++;
|
|
53
54
|
state.renderedLines = lineCount;
|
|
54
55
|
};
|
|
@@ -60,13 +61,15 @@ async function showLanguageSelector(config) {
|
|
|
60
61
|
// Handle Ctrl+C
|
|
61
62
|
if ((0, keyboard_js_1.isCtrlC)(key)) {
|
|
62
63
|
state.stdin.removeListener('data', onData);
|
|
63
|
-
|
|
64
|
+
if (!preserveOnExit) {
|
|
65
|
+
(0, terminal_js_1.clearMenu)(state);
|
|
66
|
+
}
|
|
64
67
|
(0, terminal_js_1.restoreTerminal)(state);
|
|
65
68
|
if (onExit) {
|
|
66
69
|
onExit();
|
|
67
70
|
}
|
|
68
71
|
else {
|
|
69
|
-
console.log(
|
|
72
|
+
console.log(`\n${(0, registry_js_1.t)('messages.goodbye')}`);
|
|
70
73
|
}
|
|
71
74
|
process.exit(0);
|
|
72
75
|
}
|