cli-menu-kit 0.2.0 → 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/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/index.d.ts +1 -1
- package/dist/components/display/index.js +3 -1
- 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 +2 -0
- package/dist/components/display/table.js +7 -6
- 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 +33 -20
- package/dist/components/menus/checkbox-menu.js +5 -2
- package/dist/components/menus/checkbox-table-menu.js +12 -9
- package/dist/components/menus/radio-menu-split.d.ts +1 -0
- package/dist/components/menus/radio-menu-split.js +26 -16
- package/dist/components/menus/radio-menu.js +67 -38
- 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/renderer.js +26 -18
- package/dist/core/terminal.d.ts +13 -0
- package/dist/core/terminal.js +87 -0
- package/dist/features/commands.js +23 -22
- package/dist/index.d.ts +3 -1
- package/dist/index.js +21 -2
- package/dist/layout.d.ts +50 -51
- package/dist/layout.js +69 -117
- package/dist/page-layout.d.ts +31 -0
- package/dist/page-layout.js +46 -7
- package/dist/types/input.types.d.ts +8 -0
- package/dist/types/layout.types.d.ts +56 -0
- package/dist/types/layout.types.js +36 -0
- package/dist/types/menu.types.d.ts +4 -0
- package/package.json +4 -1
package/dist/core/terminal.js
CHANGED
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
* Handles cursor movement, screen clearing, and terminal state
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.stripAnsi = stripAnsi;
|
|
8
|
+
exports.getDisplayWidth = getDisplayWidth;
|
|
9
|
+
exports.countVisualLines = countVisualLines;
|
|
7
10
|
exports.initTerminal = initTerminal;
|
|
8
11
|
exports.restoreTerminal = restoreTerminal;
|
|
9
12
|
exports.clearMenu = clearMenu;
|
|
@@ -20,6 +23,90 @@ exports.getTerminalWidth = getTerminalWidth;
|
|
|
20
23
|
exports.getTerminalHeight = getTerminalHeight;
|
|
21
24
|
exports.clearScreen = clearScreen;
|
|
22
25
|
exports.exitWithGoodbye = exitWithGoodbye;
|
|
26
|
+
const ANSI_ESCAPE_PATTERN = /[\u001B\u009B][[\]()#;?]*(?:(?:[a-zA-Z\d]*(?:;[a-zA-Z\d]*)*)?\u0007|(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PR-TZcf-nq-uy=><~])/g;
|
|
27
|
+
const TAB_WIDTH = 4;
|
|
28
|
+
/**
|
|
29
|
+
* Remove ANSI escape sequences from a string.
|
|
30
|
+
* This is required when calculating the visible width in terminal cells.
|
|
31
|
+
*/
|
|
32
|
+
function stripAnsi(text) {
|
|
33
|
+
return text.replace(ANSI_ESCAPE_PATTERN, '');
|
|
34
|
+
}
|
|
35
|
+
function isCombiningCodePoint(codePoint) {
|
|
36
|
+
return ((codePoint >= 0x0300 && codePoint <= 0x036F) || // Combining Diacritical Marks
|
|
37
|
+
(codePoint >= 0x1AB0 && codePoint <= 0x1AFF) || // Combining Diacritical Marks Extended
|
|
38
|
+
(codePoint >= 0x1DC0 && codePoint <= 0x1DFF) || // Combining Diacritical Marks Supplement
|
|
39
|
+
(codePoint >= 0x20D0 && codePoint <= 0x20FF) || // Combining Diacritical Marks for Symbols
|
|
40
|
+
(codePoint >= 0xFE20 && codePoint <= 0xFE2F) // Combining Half Marks
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
function isFullWidthCodePoint(codePoint) {
|
|
44
|
+
if (codePoint < 0x1100) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
return (codePoint <= 0x115F ||
|
|
48
|
+
codePoint === 0x2329 ||
|
|
49
|
+
codePoint === 0x232A ||
|
|
50
|
+
((codePoint >= 0x2E80 && codePoint <= 0x3247) && codePoint !== 0x303F) ||
|
|
51
|
+
(codePoint >= 0x3250 && codePoint <= 0x4DBF) ||
|
|
52
|
+
(codePoint >= 0x4E00 && codePoint <= 0xA4C6) ||
|
|
53
|
+
(codePoint >= 0xA960 && codePoint <= 0xA97C) ||
|
|
54
|
+
(codePoint >= 0xAC00 && codePoint <= 0xD7A3) ||
|
|
55
|
+
(codePoint >= 0xF900 && codePoint <= 0xFAFF) ||
|
|
56
|
+
(codePoint >= 0xFE10 && codePoint <= 0xFE19) ||
|
|
57
|
+
(codePoint >= 0xFE30 && codePoint <= 0xFE6B) ||
|
|
58
|
+
(codePoint >= 0xFF01 && codePoint <= 0xFF60) ||
|
|
59
|
+
(codePoint >= 0xFFE0 && codePoint <= 0xFFE6) ||
|
|
60
|
+
(codePoint >= 0x1B000 && codePoint <= 0x1B001) ||
|
|
61
|
+
(codePoint >= 0x1F200 && codePoint <= 0x1F251) ||
|
|
62
|
+
(codePoint >= 0x20000 && codePoint <= 0x3FFFD));
|
|
63
|
+
}
|
|
64
|
+
function getCharacterWidth(char, currentLineWidth) {
|
|
65
|
+
if (char === '\t') {
|
|
66
|
+
const remainder = currentLineWidth % TAB_WIDTH;
|
|
67
|
+
return remainder === 0 ? TAB_WIDTH : TAB_WIDTH - remainder;
|
|
68
|
+
}
|
|
69
|
+
const codePoint = char.codePointAt(0);
|
|
70
|
+
if (codePoint === undefined) {
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
// Control characters and zero-width joiners/modifiers.
|
|
74
|
+
if (codePoint <= 0x001F ||
|
|
75
|
+
(codePoint >= 0x007F && codePoint <= 0x009F) ||
|
|
76
|
+
codePoint === 0x200D ||
|
|
77
|
+
(codePoint >= 0xFE00 && codePoint <= 0xFE0F) ||
|
|
78
|
+
isCombiningCodePoint(codePoint)) {
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
if (isFullWidthCodePoint(codePoint) || (codePoint >= 0x1F300 && codePoint <= 0x1FAFF)) {
|
|
82
|
+
return 2;
|
|
83
|
+
}
|
|
84
|
+
return 1;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Calculate the visible width of a string in terminal cells.
|
|
88
|
+
*/
|
|
89
|
+
function getDisplayWidth(text) {
|
|
90
|
+
const plain = stripAnsi(text);
|
|
91
|
+
let width = 0;
|
|
92
|
+
for (const char of plain) {
|
|
93
|
+
width += getCharacterWidth(char, width);
|
|
94
|
+
}
|
|
95
|
+
return width;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Count how many visual rows the text occupies after terminal wrapping.
|
|
99
|
+
*/
|
|
100
|
+
function countVisualLines(text, terminalWidth = getTerminalWidth()) {
|
|
101
|
+
const width = Math.max(1, terminalWidth);
|
|
102
|
+
const lines = text.split(/\r\n|\r|\n/);
|
|
103
|
+
let lineCount = 0;
|
|
104
|
+
for (const line of lines) {
|
|
105
|
+
const visualWidth = getDisplayWidth(line);
|
|
106
|
+
lineCount += Math.max(1, Math.ceil(visualWidth / width));
|
|
107
|
+
}
|
|
108
|
+
return lineCount;
|
|
109
|
+
}
|
|
23
110
|
/**
|
|
24
111
|
* Initialize terminal for interactive mode
|
|
25
112
|
* @param useAltScreen - Whether to use alternate screen buffer (prevents scroll issues)
|
|
@@ -14,40 +14,41 @@ exports.getAvailableCommands = getAvailableCommands;
|
|
|
14
14
|
exports.showCommandHelp = showCommandHelp;
|
|
15
15
|
const terminal_js_1 = require("../core/terminal.js");
|
|
16
16
|
const colors_js_1 = require("../core/colors.js");
|
|
17
|
+
const registry_js_1 = require("../i18n/registry.js");
|
|
17
18
|
/**
|
|
18
19
|
* Default command registry
|
|
19
20
|
*/
|
|
20
21
|
const defaultCommands = {
|
|
21
22
|
quit: {
|
|
22
23
|
handler: () => {
|
|
23
|
-
(0, terminal_js_1.writeLine)(
|
|
24
|
+
(0, terminal_js_1.writeLine)(`\n${(0, registry_js_1.t)('messages.goodbye')}`);
|
|
24
25
|
process.exit(0);
|
|
25
26
|
},
|
|
26
|
-
|
|
27
|
+
descriptionKey: 'commands.quit'
|
|
27
28
|
},
|
|
28
29
|
help: {
|
|
29
30
|
handler: () => {
|
|
30
|
-
(0, terminal_js_1.writeLine)(
|
|
31
|
-
Object.entries(defaultCommands).forEach(([cmd, {
|
|
32
|
-
(0, terminal_js_1.writeLine)(` ${colors_js_1.
|
|
31
|
+
(0, terminal_js_1.writeLine)(`\n${(0, registry_js_1.t)('commands.availableCommands')}:`);
|
|
32
|
+
Object.entries(defaultCommands).forEach(([cmd, { descriptionKey }]) => {
|
|
33
|
+
(0, terminal_js_1.writeLine)(` ${colors_js_1.uiColors.primary}/${cmd}${colors_js_1.colors.reset} - ${(0, registry_js_1.t)(descriptionKey)}`);
|
|
33
34
|
});
|
|
34
35
|
(0, terminal_js_1.writeLine)('');
|
|
35
36
|
return false; // Don't exit, continue
|
|
36
37
|
},
|
|
37
|
-
|
|
38
|
+
descriptionKey: 'commands.help'
|
|
38
39
|
},
|
|
39
40
|
clear: {
|
|
40
41
|
handler: () => {
|
|
41
42
|
(0, terminal_js_1.clearScreen)();
|
|
42
43
|
return false; // Don't exit, continue
|
|
43
44
|
},
|
|
44
|
-
|
|
45
|
+
descriptionKey: 'commands.clear'
|
|
45
46
|
},
|
|
46
47
|
back: {
|
|
47
48
|
handler: () => {
|
|
48
49
|
return true; // Signal to go back
|
|
49
50
|
},
|
|
50
|
-
|
|
51
|
+
descriptionKey: 'commands.back'
|
|
51
52
|
}
|
|
52
53
|
};
|
|
53
54
|
/**
|
|
@@ -61,7 +62,7 @@ let customCommands = {};
|
|
|
61
62
|
* @param description - Command description
|
|
62
63
|
*/
|
|
63
64
|
function registerCommand(command, handler, description) {
|
|
64
|
-
customCommands[command.toLowerCase()] = { handler, description };
|
|
65
|
+
customCommands[command.toLowerCase()] = { handler, descriptionKey: description };
|
|
65
66
|
}
|
|
66
67
|
/**
|
|
67
68
|
* Unregister a custom command
|
|
@@ -120,8 +121,8 @@ function handleCommand(input) {
|
|
|
120
121
|
return result === undefined ? false : result;
|
|
121
122
|
}
|
|
122
123
|
// Unknown command
|
|
123
|
-
(0, terminal_js_1.writeLine)(`${colors_js_1.
|
|
124
|
-
(0, terminal_js_1.writeLine)(`${colors_js_1.
|
|
124
|
+
(0, terminal_js_1.writeLine)(`${colors_js_1.uiColors.error}✗ ${(0, registry_js_1.t)('messages.unknownCommand')}: /${command}${colors_js_1.colors.reset}`);
|
|
125
|
+
(0, terminal_js_1.writeLine)(`${colors_js_1.uiColors.textSecondary}${(0, registry_js_1.t)('messages.helpPrompt')}${colors_js_1.colors.reset}\n`);
|
|
125
126
|
return false;
|
|
126
127
|
}
|
|
127
128
|
/**
|
|
@@ -131,12 +132,12 @@ function handleCommand(input) {
|
|
|
131
132
|
function getAvailableCommands() {
|
|
132
133
|
const commands = [];
|
|
133
134
|
// Add default commands
|
|
134
|
-
Object.entries(defaultCommands).forEach(([cmd, {
|
|
135
|
-
commands.push({ command: cmd, description });
|
|
135
|
+
Object.entries(defaultCommands).forEach(([cmd, { descriptionKey }]) => {
|
|
136
|
+
commands.push({ command: cmd, description: (0, registry_js_1.t)(descriptionKey) });
|
|
136
137
|
});
|
|
137
138
|
// Add custom commands
|
|
138
|
-
Object.entries(customCommands).forEach(([cmd, {
|
|
139
|
-
commands.push({ command: cmd, description });
|
|
139
|
+
Object.entries(customCommands).forEach(([cmd, { descriptionKey }]) => {
|
|
140
|
+
commands.push({ command: cmd, description: descriptionKey });
|
|
140
141
|
});
|
|
141
142
|
return commands;
|
|
142
143
|
}
|
|
@@ -144,17 +145,17 @@ function getAvailableCommands() {
|
|
|
144
145
|
* Show help for all commands
|
|
145
146
|
*/
|
|
146
147
|
function showCommandHelp() {
|
|
147
|
-
(0, terminal_js_1.writeLine)(
|
|
148
|
+
(0, terminal_js_1.writeLine)(`\n${(0, registry_js_1.t)('commands.availableCommands')}:`);
|
|
148
149
|
// Show default commands
|
|
149
|
-
(0, terminal_js_1.writeLine)(`\n${colors_js_1.
|
|
150
|
-
Object.entries(defaultCommands).forEach(([cmd, {
|
|
151
|
-
(0, terminal_js_1.writeLine)(` ${colors_js_1.
|
|
150
|
+
(0, terminal_js_1.writeLine)(`\n${colors_js_1.uiColors.primary}${(0, registry_js_1.t)('commands.defaultCommands')}:${colors_js_1.colors.reset}`);
|
|
151
|
+
Object.entries(defaultCommands).forEach(([cmd, { descriptionKey }]) => {
|
|
152
|
+
(0, terminal_js_1.writeLine)(` ${colors_js_1.uiColors.primary}/${cmd}${colors_js_1.colors.reset} - ${(0, registry_js_1.t)(descriptionKey)}`);
|
|
152
153
|
});
|
|
153
154
|
// Show custom commands if any
|
|
154
155
|
if (Object.keys(customCommands).length > 0) {
|
|
155
|
-
(0, terminal_js_1.writeLine)(`\n${colors_js_1.
|
|
156
|
-
Object.entries(customCommands).forEach(([cmd, {
|
|
157
|
-
(0, terminal_js_1.writeLine)(` ${colors_js_1.
|
|
156
|
+
(0, terminal_js_1.writeLine)(`\n${colors_js_1.uiColors.primary}${(0, registry_js_1.t)('commands.customCommands')}:${colors_js_1.colors.reset}`);
|
|
157
|
+
Object.entries(customCommands).forEach(([cmd, { descriptionKey }]) => {
|
|
158
|
+
(0, terminal_js_1.writeLine)(` ${colors_js_1.uiColors.primary}/${cmd}${colors_js_1.colors.reset} - ${descriptionKey}`);
|
|
158
159
|
});
|
|
159
160
|
}
|
|
160
161
|
(0, terminal_js_1.writeLine)('');
|
package/dist/index.d.ts
CHANGED
|
@@ -8,10 +8,12 @@ export { renderPage, type PageLayoutConfig, type HeaderConfig as PageHeaderConfi
|
|
|
8
8
|
export { createFullHeaderComponent, createSimpleHeaderComponent, createSectionHeaderComponent, createHintsComponent, createTableComponent, createListComponent, createSummaryTableComponent, createRadioMenuComponent, createInputPromptComponent } from './component-factories.js';
|
|
9
9
|
export { showRadioMenu, showCheckboxMenu, showCheckboxTableMenu, showBooleanMenu } from './components/menus/index.js';
|
|
10
10
|
export { showTextInput, showNumberInput, showLanguageSelector, showModifyField } from './components/inputs/index.js';
|
|
11
|
-
export { renderSimpleHeader, renderSectionHeader, renderAsciiHeader, createSimpleHeader, createSectionHeader, createAsciiHeader, renderProgressIndicator, renderStageHeader, renderStageSeparator, createProgressIndicator, createStageHeader, createStageSeparator, renderMessage, showSuccess, showError, showWarning, showInfo, showQuestion, createMessage, renderSummaryTable, createSummaryTable, createSimpleSummary, renderHeader, type HeaderConfig, renderHintsComponent, createHints, generateMenuHints, generateInputHints, HintTypes, type HintsConfig, renderTable, createTable, type TableConfig, type TableColumn, renderList, createList, createBulletList, createNumberedList, type ListConfig, type ListItem } from './components/display/index.js';
|
|
11
|
+
export { renderSimpleHeader, renderSectionHeader, renderAsciiHeader, createSimpleHeader, createSectionHeader, createAsciiHeader, renderProgressIndicator, renderStageHeader, renderStageSeparator, createProgressIndicator, createStageHeader, createStageSeparator, renderProgressCheckmark, createProgressCheckmark, renderMessage, showSuccess, showError, showWarning, showInfo, showQuestion, createMessage, renderSummaryTable, createSummaryTable, createSimpleSummary, renderHeader, type HeaderConfig, renderHintsComponent, createHints, generateMenuHints, generateInputHints, HintTypes, type HintsConfig, renderTable, createTable, type TableConfig, type TableColumn, renderList, createList, createBulletList, createNumberedList, type ListConfig, type ListItem } from './components/display/index.js';
|
|
12
12
|
export { runWizard, createWizard, WizardConfig, WizardStep, WizardResult } from './features/wizard.js';
|
|
13
13
|
export { registerCommand, unregisterCommand, clearCustomCommands, isCommand, parseCommand, handleCommand, getAvailableCommands, showCommandHelp } from './features/commands.js';
|
|
14
14
|
export { getCurrentLanguage, setLanguage, t, registerLanguage, getAvailableLanguages, getCurrentLanguageMap } from './i18n/registry.js';
|
|
15
|
+
export { initConfig, getConfigManager, loadConfig, saveConfig, getConfig, setConfig, resetConfig, type UserConfig, type ConfigOptions } from './config/user-config.js';
|
|
16
|
+
export { initLanguages, loadLanguagesFromFile, getLanguageManager, getSupportedLanguages, getLanguageConfig, getDefaultLanguage, getCLILanguageCode, type LanguageConfig, type LanguagesConfig } from './config/language-config.js';
|
|
15
17
|
export { colors, uiColors, defaultUIColors, getUIColors, setUIColors, resetUIColors, createGradient, applyGradient, colorize } from './core/colors.js';
|
|
16
18
|
export type { MenuOption, BaseMenuConfig, RadioMenuConfig, CheckboxMenuConfig, BooleanMenuConfig, RadioMenuResult, CheckboxMenuResult, BooleanMenuResult } from './types/menu.types.js';
|
|
17
19
|
export type { BaseInputConfig, TextInputConfig, NumberInputConfig, LanguageSelectorConfig, ModifyFieldConfig, TextInputResult, NumberInputResult, LanguageSelectorResult, ModifyFieldResult } from './types/input.types.js';
|
package/dist/index.js
CHANGED
|
@@ -21,8 +21,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
21
21
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
22
22
|
};
|
|
23
23
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
-
exports.
|
|
25
|
-
exports.calculateVirtualScroll = exports.KEY_CODES = exports.colorize = exports.applyGradient = exports.createGradient = exports.resetUIColors = exports.setUIColors = exports.getUIColors = exports.defaultUIColors = exports.uiColors = exports.colors = exports.getCurrentLanguageMap = exports.getAvailableLanguages = exports.registerLanguage = exports.t = exports.setLanguage = exports.getCurrentLanguage = exports.showCommandHelp = exports.getAvailableCommands = exports.handleCommand = exports.parseCommand = exports.isCommand = exports.clearCustomCommands = exports.unregisterCommand = exports.registerCommand = exports.createWizard = exports.runWizard = exports.createNumberedList = exports.createBulletList = exports.createList = exports.renderList = exports.createTable = exports.renderTable = void 0;
|
|
24
|
+
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 = exports.showModifyField = exports.showLanguageSelector = exports.showNumberInput = exports.showTextInput = exports.showBooleanMenu = exports.showCheckboxTableMenu = exports.showCheckboxMenu = exports.showRadioMenu = exports.createInputPromptComponent = exports.createRadioMenuComponent = exports.createSummaryTableComponent = exports.createListComponent = exports.createTableComponent = exports.createHintsComponent = exports.createSectionHeaderComponent = exports.createSimpleHeaderComponent = exports.createFullHeaderComponent = exports.renderPage = exports.default = exports.wizard = exports.input = exports.menu = void 0;
|
|
25
|
+
exports.calculateVirtualScroll = exports.KEY_CODES = exports.colorize = exports.applyGradient = exports.createGradient = exports.resetUIColors = exports.setUIColors = exports.getUIColors = exports.defaultUIColors = exports.uiColors = exports.colors = exports.getCLILanguageCode = exports.getDefaultLanguage = exports.getLanguageConfig = exports.getSupportedLanguages = exports.getLanguageManager = exports.loadLanguagesFromFile = exports.initLanguages = exports.resetConfig = exports.setConfig = exports.getConfig = exports.saveConfig = exports.loadConfig = exports.getConfigManager = exports.initConfig = exports.getCurrentLanguageMap = exports.getAvailableLanguages = exports.registerLanguage = exports.t = exports.setLanguage = exports.getCurrentLanguage = exports.showCommandHelp = exports.getAvailableCommands = exports.handleCommand = exports.parseCommand = exports.isCommand = exports.clearCustomCommands = exports.unregisterCommand = exports.registerCommand = exports.createWizard = exports.runWizard = exports.createNumberedList = exports.createBulletList = exports.createList = exports.renderList = exports.createTable = exports.renderTable = exports.HintTypes = exports.generateInputHints = void 0;
|
|
26
26
|
// Export unified API
|
|
27
27
|
var api_js_1 = require("./api.js");
|
|
28
28
|
Object.defineProperty(exports, "menu", { enumerable: true, get: function () { return api_js_1.menuAPI; } });
|
|
@@ -70,6 +70,8 @@ Object.defineProperty(exports, "renderStageSeparator", { enumerable: true, get:
|
|
|
70
70
|
Object.defineProperty(exports, "createProgressIndicator", { enumerable: true, get: function () { return index_js_3.createProgressIndicator; } });
|
|
71
71
|
Object.defineProperty(exports, "createStageHeader", { enumerable: true, get: function () { return index_js_3.createStageHeader; } });
|
|
72
72
|
Object.defineProperty(exports, "createStageSeparator", { enumerable: true, get: function () { return index_js_3.createStageSeparator; } });
|
|
73
|
+
Object.defineProperty(exports, "renderProgressCheckmark", { enumerable: true, get: function () { return index_js_3.renderProgressCheckmark; } });
|
|
74
|
+
Object.defineProperty(exports, "createProgressCheckmark", { enumerable: true, get: function () { return index_js_3.createProgressCheckmark; } });
|
|
73
75
|
Object.defineProperty(exports, "renderMessage", { enumerable: true, get: function () { return index_js_3.renderMessage; } });
|
|
74
76
|
Object.defineProperty(exports, "showSuccess", { enumerable: true, get: function () { return index_js_3.showSuccess; } });
|
|
75
77
|
Object.defineProperty(exports, "showError", { enumerable: true, get: function () { return index_js_3.showError; } });
|
|
@@ -113,6 +115,23 @@ Object.defineProperty(exports, "t", { enumerable: true, get: function () { retur
|
|
|
113
115
|
Object.defineProperty(exports, "registerLanguage", { enumerable: true, get: function () { return registry_js_1.registerLanguage; } });
|
|
114
116
|
Object.defineProperty(exports, "getAvailableLanguages", { enumerable: true, get: function () { return registry_js_1.getAvailableLanguages; } });
|
|
115
117
|
Object.defineProperty(exports, "getCurrentLanguageMap", { enumerable: true, get: function () { return registry_js_1.getCurrentLanguageMap; } });
|
|
118
|
+
// Export configuration system
|
|
119
|
+
var user_config_js_1 = require("./config/user-config.js");
|
|
120
|
+
Object.defineProperty(exports, "initConfig", { enumerable: true, get: function () { return user_config_js_1.initConfig; } });
|
|
121
|
+
Object.defineProperty(exports, "getConfigManager", { enumerable: true, get: function () { return user_config_js_1.getConfigManager; } });
|
|
122
|
+
Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return user_config_js_1.loadConfig; } });
|
|
123
|
+
Object.defineProperty(exports, "saveConfig", { enumerable: true, get: function () { return user_config_js_1.saveConfig; } });
|
|
124
|
+
Object.defineProperty(exports, "getConfig", { enumerable: true, get: function () { return user_config_js_1.getConfig; } });
|
|
125
|
+
Object.defineProperty(exports, "setConfig", { enumerable: true, get: function () { return user_config_js_1.setConfig; } });
|
|
126
|
+
Object.defineProperty(exports, "resetConfig", { enumerable: true, get: function () { return user_config_js_1.resetConfig; } });
|
|
127
|
+
var language_config_js_1 = require("./config/language-config.js");
|
|
128
|
+
Object.defineProperty(exports, "initLanguages", { enumerable: true, get: function () { return language_config_js_1.initLanguages; } });
|
|
129
|
+
Object.defineProperty(exports, "loadLanguagesFromFile", { enumerable: true, get: function () { return language_config_js_1.loadLanguagesFromFile; } });
|
|
130
|
+
Object.defineProperty(exports, "getLanguageManager", { enumerable: true, get: function () { return language_config_js_1.getLanguageManager; } });
|
|
131
|
+
Object.defineProperty(exports, "getSupportedLanguages", { enumerable: true, get: function () { return language_config_js_1.getSupportedLanguages; } });
|
|
132
|
+
Object.defineProperty(exports, "getLanguageConfig", { enumerable: true, get: function () { return language_config_js_1.getLanguageConfig; } });
|
|
133
|
+
Object.defineProperty(exports, "getDefaultLanguage", { enumerable: true, get: function () { return language_config_js_1.getDefaultLanguage; } });
|
|
134
|
+
Object.defineProperty(exports, "getCLILanguageCode", { enumerable: true, get: function () { return language_config_js_1.getCLILanguageCode; } });
|
|
116
135
|
// Export color configuration
|
|
117
136
|
var colors_js_1 = require("./core/colors.js");
|
|
118
137
|
Object.defineProperty(exports, "colors", { enumerable: true, get: function () { return colors_js_1.colors; } });
|
package/dist/layout.d.ts
CHANGED
|
@@ -1,68 +1,67 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Page Layout
|
|
3
|
-
*
|
|
4
|
-
* Core Principles:
|
|
5
|
-
* 1. Complete component decoupling
|
|
6
|
-
* 2. Fixed-height regions (Header/Footer fixed, Main fills rest)
|
|
7
|
-
* 3. Components return string arrays (lines)
|
|
8
|
-
* 4. Diff-based rendering - only update changed regions
|
|
9
|
-
* 5. Two-phase execution: render (non-blocking) + interact (blocking)
|
|
2
|
+
* Page Layout System
|
|
3
|
+
* 通用页面布局:Header + Main Area + Footer
|
|
10
4
|
*/
|
|
11
|
-
import { ScreenManager, Rect } from './core/screen-manager.js';
|
|
12
|
-
import { HintManager } from './core/hint-manager.js';
|
|
13
|
-
export declare const screenManager: ScreenManager;
|
|
14
|
-
export declare const hintManager: HintManager;
|
|
15
|
-
export { ScreenManager, HintManager, Rect };
|
|
16
5
|
/**
|
|
17
|
-
*
|
|
6
|
+
* Header 配置
|
|
18
7
|
*/
|
|
19
|
-
export interface
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
regionId: string;
|
|
24
|
-
/** Render function - returns lines to display */
|
|
25
|
-
render: (rect: Rect) => string[] | Promise<string[]>;
|
|
26
|
-
/** Optional interact function - handles user input (blocking) */
|
|
27
|
-
interact?: () => void | Promise<void>;
|
|
28
|
-
/** Optional component-specific configuration */
|
|
29
|
-
config?: any;
|
|
8
|
+
export interface HeaderConfig {
|
|
9
|
+
type: 'simple' | 'section' | 'none';
|
|
10
|
+
text?: string;
|
|
11
|
+
width?: number;
|
|
30
12
|
}
|
|
31
13
|
/**
|
|
32
|
-
*
|
|
14
|
+
* Main Area 配置
|
|
33
15
|
*/
|
|
34
|
-
export interface
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
footerHints: Rect;
|
|
38
|
-
footerPrompt: Rect;
|
|
16
|
+
export interface MainAreaConfig {
|
|
17
|
+
type: 'menu' | 'display' | 'interactive';
|
|
18
|
+
render: () => void | Promise<void>;
|
|
39
19
|
}
|
|
40
20
|
/**
|
|
41
|
-
*
|
|
42
|
-
*/
|
|
43
|
-
export declare function computeLayout(rows?: number, cols?: number): Layout;
|
|
44
|
-
/**
|
|
45
|
-
* Area configuration
|
|
21
|
+
* Footer 配置
|
|
46
22
|
*/
|
|
47
|
-
export interface
|
|
48
|
-
|
|
23
|
+
export interface FooterConfig {
|
|
24
|
+
menu?: {
|
|
25
|
+
options: string[];
|
|
26
|
+
allowLetterKeys?: boolean;
|
|
27
|
+
allowNumberKeys?: boolean;
|
|
28
|
+
};
|
|
29
|
+
input?: {
|
|
30
|
+
prompt: string;
|
|
31
|
+
defaultValue?: string;
|
|
32
|
+
allowEmpty?: boolean;
|
|
33
|
+
};
|
|
34
|
+
ask?: {
|
|
35
|
+
question: string;
|
|
36
|
+
defaultValue?: boolean;
|
|
37
|
+
horizontal?: boolean;
|
|
38
|
+
};
|
|
39
|
+
hints?: string[];
|
|
49
40
|
}
|
|
50
41
|
/**
|
|
51
|
-
*
|
|
42
|
+
* 完整页面布局配置
|
|
52
43
|
*/
|
|
53
|
-
export interface
|
|
54
|
-
header?:
|
|
55
|
-
mainArea
|
|
56
|
-
footer?:
|
|
44
|
+
export interface PageLayoutConfig {
|
|
45
|
+
header?: HeaderConfig;
|
|
46
|
+
mainArea: MainAreaConfig;
|
|
47
|
+
footer?: FooterConfig;
|
|
57
48
|
}
|
|
58
49
|
/**
|
|
59
|
-
*
|
|
50
|
+
* 渲染完整页面
|
|
60
51
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* const result = await renderPage({
|
|
55
|
+
* header: { type: 'simple', text: 'My Page' },
|
|
56
|
+
* mainArea: {
|
|
57
|
+
* type: 'display',
|
|
58
|
+
* render: () => console.log('Content')
|
|
59
|
+
* },
|
|
60
|
+
* footer: {
|
|
61
|
+
* menu: { options: ['1. Save', 'b. Back'] },
|
|
62
|
+
* hints: ['↑↓ Navigate Enter Confirm']
|
|
63
|
+
* }
|
|
64
|
+
* });
|
|
65
|
+
* ```
|
|
67
66
|
*/
|
|
68
|
-
export declare function
|
|
67
|
+
export declare function renderPage(config: PageLayoutConfig): Promise<any>;
|
package/dist/layout.js
CHANGED
|
@@ -1,134 +1,86 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* Page Layout
|
|
4
|
-
*
|
|
5
|
-
* Core Principles:
|
|
6
|
-
* 1. Complete component decoupling
|
|
7
|
-
* 2. Fixed-height regions (Header/Footer fixed, Main fills rest)
|
|
8
|
-
* 3. Components return string arrays (lines)
|
|
9
|
-
* 4. Diff-based rendering - only update changed regions
|
|
10
|
-
* 5. Two-phase execution: render (non-blocking) + interact (blocking)
|
|
3
|
+
* Page Layout System
|
|
4
|
+
* 通用页面布局:Header + Main Area + Footer
|
|
11
5
|
*/
|
|
12
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
exports.createCustomComponent = createCustomComponent;
|
|
17
|
-
const screen_manager_js_1 = require("./core/screen-manager.js");
|
|
18
|
-
Object.defineProperty(exports, "ScreenManager", { enumerable: true, get: function () { return screen_manager_js_1.ScreenManager; } });
|
|
19
|
-
const hint_manager_js_1 = require("./core/hint-manager.js");
|
|
20
|
-
Object.defineProperty(exports, "HintManager", { enumerable: true, get: function () { return hint_manager_js_1.HintManager; } });
|
|
21
|
-
// Global instances
|
|
22
|
-
exports.screenManager = new screen_manager_js_1.ScreenManager();
|
|
23
|
-
exports.hintManager = new hint_manager_js_1.HintManager();
|
|
24
|
-
/**
|
|
25
|
-
* Compute layout based on terminal size
|
|
26
|
-
*/
|
|
27
|
-
function computeLayout(rows, cols) {
|
|
28
|
-
const termRows = rows || process.stdout.rows || 24;
|
|
29
|
-
const termCols = cols || process.stdout.columns || 80;
|
|
30
|
-
const headerHeight = 13; // Fixed header height (6 ASCII art + title + desc + separator)
|
|
31
|
-
const footerHintsHeight = 1; // Fixed hints height
|
|
32
|
-
const footerPromptHeight = 1; // Fixed prompt height
|
|
33
|
-
const mainHeight = Math.max(1, termRows - headerHeight - footerHintsHeight - footerPromptHeight);
|
|
34
|
-
return {
|
|
35
|
-
header: { top: 1, left: 1, width: termCols, height: headerHeight },
|
|
36
|
-
main: { top: 1 + headerHeight, left: 1, width: termCols, height: mainHeight },
|
|
37
|
-
footerHints: { top: 1 + headerHeight + mainHeight, left: 1, width: termCols, height: footerHintsHeight },
|
|
38
|
-
footerPrompt: { top: 1 + headerHeight + mainHeight + footerHintsHeight, left: 1, width: termCols, height: footerPromptHeight }
|
|
39
|
-
};
|
|
40
|
-
}
|
|
7
|
+
exports.renderPage = renderPage;
|
|
8
|
+
const api_js_1 = require("./api.js");
|
|
9
|
+
const headers_js_1 = require("./components/display/headers.js");
|
|
41
10
|
/**
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* Phase 1: Render all components (non-blocking)
|
|
45
|
-
* Phase 2: Handle interactions (blocking)
|
|
11
|
+
* 渲染 Header
|
|
46
12
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
// Compute layout
|
|
51
|
-
const layout = computeLayout();
|
|
52
|
-
// Register regions
|
|
53
|
-
if (config.header?.components) {
|
|
54
|
-
for (const component of config.header.components) {
|
|
55
|
-
exports.screenManager.registerRegion(component.regionId, layout.header);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
if (config.mainArea?.components) {
|
|
59
|
-
for (const component of config.mainArea.components) {
|
|
60
|
-
exports.screenManager.registerRegion(component.regionId, layout.main);
|
|
61
|
-
}
|
|
13
|
+
function renderHeader(config) {
|
|
14
|
+
if (!config || config.type === 'none') {
|
|
15
|
+
return;
|
|
62
16
|
}
|
|
63
|
-
if (config.
|
|
64
|
-
|
|
65
|
-
// Map components to their specific footer regions
|
|
66
|
-
if (component.type === 'hints') {
|
|
67
|
-
exports.screenManager.registerRegion(component.regionId, layout.footerHints);
|
|
68
|
-
}
|
|
69
|
-
else if (component.type === 'prompt') {
|
|
70
|
-
exports.screenManager.registerRegion(component.regionId, layout.footerPrompt);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
17
|
+
if (config.type === 'simple' && config.text) {
|
|
18
|
+
(0, headers_js_1.renderSimpleHeader)(config.text);
|
|
73
19
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const lines = await component.render(rect);
|
|
77
|
-
exports.screenManager.renderRegion(component.regionId, lines);
|
|
78
|
-
};
|
|
79
|
-
if (config.header?.components) {
|
|
80
|
-
for (const component of config.header.components) {
|
|
81
|
-
await renderComponent(component, layout.header);
|
|
82
|
-
}
|
|
20
|
+
else if (config.type === 'section' && config.text) {
|
|
21
|
+
(0, headers_js_1.renderSectionHeader)(config.text, config.width || 50);
|
|
83
22
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
await renderComponent(component, rect);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
// Setup hint manager listener
|
|
96
|
-
exports.hintManager.on('change', (text) => {
|
|
97
|
-
const hintsComponent = config.footer?.components.find(c => c.type === 'hints');
|
|
98
|
-
if (hintsComponent) {
|
|
99
|
-
exports.screenManager.renderRegion(hintsComponent.regionId, [text]);
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
// Handle terminal resize
|
|
103
|
-
process.stdout.on('resize', () => {
|
|
104
|
-
const newLayout = computeLayout();
|
|
105
|
-
exports.screenManager.invalidateAll();
|
|
106
|
-
// Re-register and re-render all regions
|
|
107
|
-
// (Implementation can be enhanced to avoid code duplication)
|
|
108
|
-
});
|
|
109
|
-
// Phase 2: Handle interactions
|
|
110
|
-
const interactiveComponents = [];
|
|
111
|
-
if (config.header?.components) {
|
|
112
|
-
interactiveComponents.push(...config.header.components.filter(c => c.interact));
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 渲染 Footer
|
|
26
|
+
* 返回用户的选择/输入结果
|
|
27
|
+
*/
|
|
28
|
+
async function renderFooter(config) {
|
|
29
|
+
if (!config) {
|
|
30
|
+
return null;
|
|
113
31
|
}
|
|
114
|
-
|
|
115
|
-
|
|
32
|
+
let result = null;
|
|
33
|
+
// 1. Menu (如果有)
|
|
34
|
+
if (config.menu) {
|
|
35
|
+
result = await api_js_1.menuAPI.radio({
|
|
36
|
+
options: config.menu.options,
|
|
37
|
+
allowLetterKeys: config.menu.allowLetterKeys ?? true,
|
|
38
|
+
allowNumberKeys: config.menu.allowNumberKeys ?? true,
|
|
39
|
+
hints: config.hints,
|
|
40
|
+
preserveOnSelect: true
|
|
41
|
+
});
|
|
116
42
|
}
|
|
117
|
-
|
|
118
|
-
|
|
43
|
+
// 2. Input (如果有)
|
|
44
|
+
else if (config.input) {
|
|
45
|
+
result = await api_js_1.inputAPI.text({
|
|
46
|
+
prompt: config.input.prompt,
|
|
47
|
+
defaultValue: config.input.defaultValue,
|
|
48
|
+
allowEmpty: config.input.allowEmpty ?? false
|
|
49
|
+
});
|
|
119
50
|
}
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
await
|
|
124
|
-
|
|
51
|
+
// 3. Ask (如果有 - 通常在 Menu 或 Input 之后)
|
|
52
|
+
if (config.ask) {
|
|
53
|
+
const askResult = config.ask.horizontal
|
|
54
|
+
? await api_js_1.menuAPI.booleanH(config.ask.question, config.ask.defaultValue ?? false)
|
|
55
|
+
: await api_js_1.menuAPI.booleanV(config.ask.question, config.ask.defaultValue ?? false);
|
|
56
|
+
return { ...result, confirmed: askResult };
|
|
125
57
|
}
|
|
126
|
-
|
|
127
|
-
exports.screenManager.exit();
|
|
58
|
+
return result;
|
|
128
59
|
}
|
|
129
60
|
/**
|
|
130
|
-
*
|
|
61
|
+
* 渲染完整页面
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* const result = await renderPage({
|
|
66
|
+
* header: { type: 'simple', text: 'My Page' },
|
|
67
|
+
* mainArea: {
|
|
68
|
+
* type: 'display',
|
|
69
|
+
* render: () => console.log('Content')
|
|
70
|
+
* },
|
|
71
|
+
* footer: {
|
|
72
|
+
* menu: { options: ['1. Save', 'b. Back'] },
|
|
73
|
+
* hints: ['↑↓ Navigate Enter Confirm']
|
|
74
|
+
* }
|
|
75
|
+
* });
|
|
76
|
+
* ```
|
|
131
77
|
*/
|
|
132
|
-
function
|
|
133
|
-
|
|
78
|
+
async function renderPage(config) {
|
|
79
|
+
// 1. Render Header
|
|
80
|
+
renderHeader(config.header);
|
|
81
|
+
// 2. Render Main Area
|
|
82
|
+
await config.mainArea.render();
|
|
83
|
+
// 3. Render Footer
|
|
84
|
+
const footerResult = await renderFooter(config.footer);
|
|
85
|
+
return footerResult;
|
|
134
86
|
}
|