cli-menu-kit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +716 -0
- package/dist/api.d.ts +158 -0
- package/dist/api.js +128 -0
- package/dist/components/display/headers.d.ts +32 -0
- package/dist/components/display/headers.js +84 -0
- package/dist/components/display/index.d.ts +8 -0
- package/dist/components/display/index.js +31 -0
- package/dist/components/display/messages.d.ts +41 -0
- package/dist/components/display/messages.js +90 -0
- package/dist/components/display/progress.d.ts +41 -0
- package/dist/components/display/progress.js +82 -0
- package/dist/components/display/summary.d.ts +33 -0
- package/dist/components/display/summary.js +82 -0
- package/dist/components/inputs/index.d.ts +8 -0
- package/dist/components/inputs/index.js +15 -0
- package/dist/components/inputs/language-input.d.ts +11 -0
- package/dist/components/inputs/language-input.js +104 -0
- package/dist/components/inputs/modify-field.d.ts +11 -0
- package/dist/components/inputs/modify-field.js +42 -0
- package/dist/components/inputs/number-input.d.ts +11 -0
- package/dist/components/inputs/number-input.js +143 -0
- package/dist/components/inputs/text-input.d.ts +11 -0
- package/dist/components/inputs/text-input.js +114 -0
- package/dist/components/menus/boolean-menu.d.ts +11 -0
- package/dist/components/menus/boolean-menu.js +169 -0
- package/dist/components/menus/checkbox-menu.d.ts +11 -0
- package/dist/components/menus/checkbox-menu.js +161 -0
- package/dist/components/menus/index.d.ts +7 -0
- package/dist/components/menus/index.js +13 -0
- package/dist/components/menus/radio-menu.d.ts +11 -0
- package/dist/components/menus/radio-menu.js +158 -0
- package/dist/components.d.ts +55 -0
- package/dist/components.js +166 -0
- package/dist/core/colors.d.ts +64 -0
- package/dist/core/colors.js +139 -0
- package/dist/core/keyboard.d.ts +124 -0
- package/dist/core/keyboard.js +185 -0
- package/dist/core/renderer.d.ts +74 -0
- package/dist/core/renderer.js +217 -0
- package/dist/core/terminal.d.ts +89 -0
- package/dist/core/terminal.js +170 -0
- package/dist/features/commands.d.ts +57 -0
- package/dist/features/commands.js +161 -0
- package/dist/features/wizard.d.ts +62 -0
- package/dist/features/wizard.js +112 -0
- package/dist/i18n/languages/en.d.ts +5 -0
- package/dist/i18n/languages/en.js +54 -0
- package/dist/i18n/languages/zh.d.ts +5 -0
- package/dist/i18n/languages/zh.js +54 -0
- package/dist/i18n/registry.d.ts +36 -0
- package/dist/i18n/registry.js +82 -0
- package/dist/i18n/types.d.ts +65 -0
- package/dist/i18n/types.js +5 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +104 -0
- package/dist/input.d.ts +40 -0
- package/dist/input.js +211 -0
- package/dist/menu-core.d.ts +52 -0
- package/dist/menu-core.js +201 -0
- package/dist/menu-multi.d.ts +21 -0
- package/dist/menu-multi.js +119 -0
- package/dist/menu-single.d.ts +18 -0
- package/dist/menu-single.js +138 -0
- package/dist/menu.d.ts +66 -0
- package/dist/menu.js +78 -0
- package/dist/types/display.types.d.ts +57 -0
- package/dist/types/display.types.js +5 -0
- package/dist/types/input.types.d.ts +88 -0
- package/dist/types/input.types.js +5 -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 +85 -0
- package/dist/types/menu.types.js +5 -0
- package/dist/types.d.ts +49 -0
- package/dist/types.js +5 -0
- package/package.json +35 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CLI Menu Kit - UI Components
|
|
4
|
+
* Handles all display-related UI components
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.symbols = exports.theme = exports.colors = void 0;
|
|
8
|
+
exports.formatSection = formatSection;
|
|
9
|
+
exports.buildHint = buildHint;
|
|
10
|
+
exports.showSubMenuTitle = showSubMenuTitle;
|
|
11
|
+
exports.showProgress = showProgress;
|
|
12
|
+
exports.showInfo = showInfo;
|
|
13
|
+
exports.showSuccess = showSuccess;
|
|
14
|
+
exports.showError = showError;
|
|
15
|
+
exports.showWarning = showWarning;
|
|
16
|
+
exports.showGoodbye = showGoodbye;
|
|
17
|
+
exports.printHeader = printHeader;
|
|
18
|
+
// ANSI Colors
|
|
19
|
+
exports.colors = {
|
|
20
|
+
reset: '\x1b[0m',
|
|
21
|
+
red: '\x1b[31m',
|
|
22
|
+
green: '\x1b[32m',
|
|
23
|
+
yellow: '\x1b[33m',
|
|
24
|
+
blue: '\x1b[34m',
|
|
25
|
+
cyan: '\x1b[36m',
|
|
26
|
+
gray: '\x1b[90m',
|
|
27
|
+
};
|
|
28
|
+
// Additional color codes
|
|
29
|
+
const colorCodes = {
|
|
30
|
+
bright: '\x1b[1m',
|
|
31
|
+
dim: '\x1b[2m',
|
|
32
|
+
magenta: '\x1b[35m',
|
|
33
|
+
};
|
|
34
|
+
// Theme colors
|
|
35
|
+
exports.theme = {
|
|
36
|
+
active: `${colorCodes.bright}${exports.colors.cyan}`, // Selected item - bright cyan
|
|
37
|
+
primary: exports.colors.cyan, // Standard - cyan (numbers, separators)
|
|
38
|
+
title: exports.colors.reset, // Title - white (menu titles)
|
|
39
|
+
muted: exports.colors.gray, // Auxiliary - gray (descriptions, hints)
|
|
40
|
+
success: exports.colors.green, // Success - green
|
|
41
|
+
warning: exports.colors.yellow, // Warning - yellow
|
|
42
|
+
error: exports.colors.red, // Error - red
|
|
43
|
+
};
|
|
44
|
+
// Message symbols with colors
|
|
45
|
+
exports.symbols = {
|
|
46
|
+
success: { icon: '✓', color: exports.colors.green },
|
|
47
|
+
error: { icon: 'x', color: exports.colors.red },
|
|
48
|
+
warning: { icon: '!', color: exports.colors.yellow },
|
|
49
|
+
info: { icon: 'ℹ', color: exports.colors.blue },
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Format section title with separator
|
|
53
|
+
*/
|
|
54
|
+
function formatSection(text) {
|
|
55
|
+
const separator = '─'.repeat(10);
|
|
56
|
+
return `${separator} ${text} ${separator}`;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Build hint text for interactive menus
|
|
60
|
+
*/
|
|
61
|
+
function buildHint(keys, lang = 'zh') {
|
|
62
|
+
const hints = {
|
|
63
|
+
zh: {
|
|
64
|
+
arrows: `${exports.colors.reset}↑↓${exports.theme.muted} 方向键`,
|
|
65
|
+
space: `${exports.colors.reset}空格${exports.theme.muted} 选中/取消`,
|
|
66
|
+
number: `${exports.colors.reset}0-9${exports.theme.muted} 输入序号`,
|
|
67
|
+
letter: `${exports.colors.reset}字母${exports.theme.muted} 快捷键`,
|
|
68
|
+
all: `${exports.colors.reset}A${exports.theme.muted} 全选`,
|
|
69
|
+
invert: `${exports.colors.reset}I${exports.theme.muted} 反选`,
|
|
70
|
+
enter: `${exports.colors.reset}⏎${exports.theme.muted} 确认`,
|
|
71
|
+
esc: `${exports.colors.reset}Esc${exports.theme.muted} 退出`,
|
|
72
|
+
},
|
|
73
|
+
en: {
|
|
74
|
+
arrows: `${exports.colors.reset}↑↓${exports.theme.muted} Navigate`,
|
|
75
|
+
space: `${exports.colors.reset}Space${exports.theme.muted} Select`,
|
|
76
|
+
number: `${exports.colors.reset}0-9${exports.theme.muted} Type number`,
|
|
77
|
+
letter: `${exports.colors.reset}Letter${exports.theme.muted} Shortcut`,
|
|
78
|
+
all: `${exports.colors.reset}A${exports.theme.muted} All`,
|
|
79
|
+
invert: `${exports.colors.reset}I${exports.theme.muted} Invert`,
|
|
80
|
+
enter: `${exports.colors.reset}⏎${exports.theme.muted} Submit`,
|
|
81
|
+
esc: `${exports.colors.reset}Esc${exports.theme.muted} Exit`,
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const langHints = hints[lang] || hints.zh;
|
|
85
|
+
const parts = keys.map(key => langHints[key]).filter(Boolean);
|
|
86
|
+
return parts.join(` ${exports.theme.muted}•${exports.colors.reset} `) + exports.colors.reset;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Show submenu title with section format
|
|
90
|
+
*/
|
|
91
|
+
function showSubMenuTitle(title, lang, indent = ' ') {
|
|
92
|
+
console.log();
|
|
93
|
+
console.log(`${indent}${exports.theme.primary}${formatSection(title)}${exports.colors.reset}`);
|
|
94
|
+
console.log();
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Show progress indicator
|
|
98
|
+
*/
|
|
99
|
+
function showProgress(steps, currentStep, lang, indent = ' ') {
|
|
100
|
+
const progress = steps.map((step, index) => {
|
|
101
|
+
if (index <= currentStep) {
|
|
102
|
+
return `${exports.colors.reset}${step}${exports.colors.reset}`;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
return `${exports.theme.muted}${step}${exports.colors.reset}`;
|
|
106
|
+
}
|
|
107
|
+
}).join(` ${exports.theme.muted}→${exports.colors.reset} `);
|
|
108
|
+
console.log(`${indent}${progress}`);
|
|
109
|
+
console.log();
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Show info message
|
|
113
|
+
*/
|
|
114
|
+
function showInfo(message, indent = '') {
|
|
115
|
+
console.log(`${indent}${exports.symbols.info.color}${exports.symbols.info.icon} ${message}${exports.colors.reset}`);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Show success message
|
|
119
|
+
*/
|
|
120
|
+
function showSuccess(message, indent = '') {
|
|
121
|
+
console.log(`${indent}${exports.symbols.success.color}${exports.symbols.success.icon} ${message}${exports.colors.reset}`);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Show error message
|
|
125
|
+
*/
|
|
126
|
+
function showError(message, indent = '') {
|
|
127
|
+
console.log(`${indent}${exports.symbols.error.color}${exports.symbols.error.icon} ${message}${exports.colors.reset}`);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Show warning message
|
|
131
|
+
*/
|
|
132
|
+
function showWarning(message, indent = '') {
|
|
133
|
+
console.log(`${indent}${exports.symbols.warning.color}${exports.symbols.warning.icon} ${message}${exports.colors.reset}`);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Show goodbye message
|
|
137
|
+
*/
|
|
138
|
+
function showGoodbye(lang = 'zh') {
|
|
139
|
+
console.log('\n');
|
|
140
|
+
const message = lang === 'zh'
|
|
141
|
+
? '👋 感谢使用,再见!'
|
|
142
|
+
: '👋 Thank you for using CLI Menu Kit. Goodbye!';
|
|
143
|
+
console.log(`${exports.theme.active}${message}${exports.colors.reset}`);
|
|
144
|
+
console.log();
|
|
145
|
+
}
|
|
146
|
+
function printHeader(options) {
|
|
147
|
+
const { asciiArt, title, subtitle, version, github } = options;
|
|
148
|
+
const indent = ' ';
|
|
149
|
+
console.log(`${exports.theme.primary}${'═'.repeat(71)}${exports.colors.reset}`);
|
|
150
|
+
console.log();
|
|
151
|
+
asciiArt.forEach(line => {
|
|
152
|
+
console.log(`${indent}${exports.theme.active}${line}${exports.colors.reset}`);
|
|
153
|
+
});
|
|
154
|
+
console.log();
|
|
155
|
+
console.log(`${indent}${colorCodes.bright}${title}${exports.colors.reset}${subtitle ? ` ${exports.theme.muted}${subtitle}${exports.colors.reset}` : ''}`);
|
|
156
|
+
console.log();
|
|
157
|
+
console.log(`${exports.theme.primary}${'═'.repeat(71)}${exports.colors.reset}`);
|
|
158
|
+
console.log();
|
|
159
|
+
if (version || github) {
|
|
160
|
+
const versionText = version ? `${exports.theme.muted}Version: ${exports.colors.reset}${exports.theme.primary}${version}${exports.colors.reset}` : '';
|
|
161
|
+
const githubText = github ? `${exports.theme.primary}${github}${exports.colors.reset}` : '';
|
|
162
|
+
const separator = version && github ? ` ${exports.theme.muted}|${exports.colors.reset} ` : '';
|
|
163
|
+
console.log(`${indent}${versionText}${separator}${githubText}`);
|
|
164
|
+
console.log();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Color system for CLI Menu Kit
|
|
3
|
+
* Supports single colors and two-color gradients
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* ANSI color codes
|
|
7
|
+
*/
|
|
8
|
+
export declare const colors: {
|
|
9
|
+
readonly reset: "\u001B[0m";
|
|
10
|
+
readonly black: "\u001B[30m";
|
|
11
|
+
readonly red: "\u001B[31m";
|
|
12
|
+
readonly green: "\u001B[32m";
|
|
13
|
+
readonly yellow: "\u001B[33m";
|
|
14
|
+
readonly blue: "\u001B[34m";
|
|
15
|
+
readonly magenta: "\u001B[35m";
|
|
16
|
+
readonly cyan: "\u001B[36m";
|
|
17
|
+
readonly white: "\u001B[37m";
|
|
18
|
+
readonly brightBlack: "\u001B[90m";
|
|
19
|
+
readonly brightRed: "\u001B[91m";
|
|
20
|
+
readonly brightGreen: "\u001B[92m";
|
|
21
|
+
readonly brightYellow: "\u001B[93m";
|
|
22
|
+
readonly brightBlue: "\u001B[94m";
|
|
23
|
+
readonly brightMagenta: "\u001B[95m";
|
|
24
|
+
readonly brightCyan: "\u001B[96m";
|
|
25
|
+
readonly brightWhite: "\u001B[97m";
|
|
26
|
+
readonly bgBlack: "\u001B[40m";
|
|
27
|
+
readonly bgRed: "\u001B[41m";
|
|
28
|
+
readonly bgGreen: "\u001B[42m";
|
|
29
|
+
readonly bgYellow: "\u001B[43m";
|
|
30
|
+
readonly bgBlue: "\u001B[44m";
|
|
31
|
+
readonly bgMagenta: "\u001B[45m";
|
|
32
|
+
readonly bgCyan: "\u001B[46m";
|
|
33
|
+
readonly bgWhite: "\u001B[47m";
|
|
34
|
+
readonly bold: "\u001B[1m";
|
|
35
|
+
readonly dim: "\u001B[2m";
|
|
36
|
+
readonly italic: "\u001B[3m";
|
|
37
|
+
readonly underline: "\u001B[4m";
|
|
38
|
+
readonly inverse: "\u001B[7m";
|
|
39
|
+
readonly hidden: "\u001B[8m";
|
|
40
|
+
readonly strikethrough: "\u001B[9m";
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Create a gradient between two colors
|
|
44
|
+
* @param startColor - Starting ANSI color code
|
|
45
|
+
* @param endColor - Ending ANSI color code
|
|
46
|
+
* @param steps - Number of steps in the gradient
|
|
47
|
+
* @returns Array of ANSI color codes for each step
|
|
48
|
+
*/
|
|
49
|
+
export declare function createGradient(startColor: string, endColor: string, steps: number): string[];
|
|
50
|
+
/**
|
|
51
|
+
* Apply gradient to text
|
|
52
|
+
* @param text - Text to colorize
|
|
53
|
+
* @param startColor - Starting color
|
|
54
|
+
* @param endColor - Ending color
|
|
55
|
+
* @returns Colorized text with gradient
|
|
56
|
+
*/
|
|
57
|
+
export declare function applyGradient(text: string, startColor: string, endColor: string): string;
|
|
58
|
+
/**
|
|
59
|
+
* Apply single color to text
|
|
60
|
+
* @param text - Text to colorize
|
|
61
|
+
* @param color - ANSI color code
|
|
62
|
+
* @returns Colorized text
|
|
63
|
+
*/
|
|
64
|
+
export declare function colorize(text: string, color: string): string;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Color system for CLI Menu Kit
|
|
4
|
+
* Supports single colors and two-color gradients
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.colors = void 0;
|
|
8
|
+
exports.createGradient = createGradient;
|
|
9
|
+
exports.applyGradient = applyGradient;
|
|
10
|
+
exports.colorize = colorize;
|
|
11
|
+
/**
|
|
12
|
+
* ANSI color codes
|
|
13
|
+
*/
|
|
14
|
+
exports.colors = {
|
|
15
|
+
// Reset
|
|
16
|
+
reset: '\x1b[0m',
|
|
17
|
+
// Basic colors
|
|
18
|
+
black: '\x1b[30m',
|
|
19
|
+
red: '\x1b[31m',
|
|
20
|
+
green: '\x1b[32m',
|
|
21
|
+
yellow: '\x1b[33m',
|
|
22
|
+
blue: '\x1b[34m',
|
|
23
|
+
magenta: '\x1b[35m',
|
|
24
|
+
cyan: '\x1b[36m',
|
|
25
|
+
white: '\x1b[37m',
|
|
26
|
+
// Bright colors
|
|
27
|
+
brightBlack: '\x1b[90m',
|
|
28
|
+
brightRed: '\x1b[91m',
|
|
29
|
+
brightGreen: '\x1b[92m',
|
|
30
|
+
brightYellow: '\x1b[93m',
|
|
31
|
+
brightBlue: '\x1b[94m',
|
|
32
|
+
brightMagenta: '\x1b[95m',
|
|
33
|
+
brightCyan: '\x1b[96m',
|
|
34
|
+
brightWhite: '\x1b[97m',
|
|
35
|
+
// Background colors
|
|
36
|
+
bgBlack: '\x1b[40m',
|
|
37
|
+
bgRed: '\x1b[41m',
|
|
38
|
+
bgGreen: '\x1b[42m',
|
|
39
|
+
bgYellow: '\x1b[43m',
|
|
40
|
+
bgBlue: '\x1b[44m',
|
|
41
|
+
bgMagenta: '\x1b[45m',
|
|
42
|
+
bgCyan: '\x1b[46m',
|
|
43
|
+
bgWhite: '\x1b[47m',
|
|
44
|
+
// Styles
|
|
45
|
+
bold: '\x1b[1m',
|
|
46
|
+
dim: '\x1b[2m',
|
|
47
|
+
italic: '\x1b[3m',
|
|
48
|
+
underline: '\x1b[4m',
|
|
49
|
+
inverse: '\x1b[7m',
|
|
50
|
+
hidden: '\x1b[8m',
|
|
51
|
+
strikethrough: '\x1b[9m'
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Parse ANSI color code to RGB values
|
|
55
|
+
* Supports basic 8 colors and bright variants
|
|
56
|
+
*/
|
|
57
|
+
function parseColorToRGB(colorCode) {
|
|
58
|
+
// Map of ANSI codes to approximate RGB values
|
|
59
|
+
const colorMap = {
|
|
60
|
+
'\x1b[30m': { r: 0, g: 0, b: 0 }, // black
|
|
61
|
+
'\x1b[31m': { r: 170, g: 0, b: 0 }, // red
|
|
62
|
+
'\x1b[32m': { r: 0, g: 170, b: 0 }, // green
|
|
63
|
+
'\x1b[33m': { r: 170, g: 85, b: 0 }, // yellow
|
|
64
|
+
'\x1b[34m': { r: 0, g: 0, b: 170 }, // blue
|
|
65
|
+
'\x1b[35m': { r: 170, g: 0, b: 170 }, // magenta
|
|
66
|
+
'\x1b[36m': { r: 0, g: 170, b: 170 }, // cyan
|
|
67
|
+
'\x1b[37m': { r: 170, g: 170, b: 170 }, // white
|
|
68
|
+
'\x1b[90m': { r: 85, g: 85, b: 85 }, // bright black
|
|
69
|
+
'\x1b[91m': { r: 255, g: 85, b: 85 }, // bright red
|
|
70
|
+
'\x1b[92m': { r: 85, g: 255, b: 85 }, // bright green
|
|
71
|
+
'\x1b[93m': { r: 255, g: 255, b: 85 }, // bright yellow
|
|
72
|
+
'\x1b[94m': { r: 85, g: 85, b: 255 }, // bright blue
|
|
73
|
+
'\x1b[95m': { r: 255, g: 85, b: 255 }, // bright magenta
|
|
74
|
+
'\x1b[96m': { r: 85, g: 255, b: 255 }, // bright cyan
|
|
75
|
+
'\x1b[97m': { r: 255, g: 255, b: 255 } // bright white
|
|
76
|
+
};
|
|
77
|
+
return colorMap[colorCode] || { r: 170, g: 170, b: 170 };
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Convert RGB to ANSI 256-color code
|
|
81
|
+
*/
|
|
82
|
+
function rgbToAnsi256(r, g, b) {
|
|
83
|
+
// Use 256-color mode for better gradient quality
|
|
84
|
+
const code = 16 + 36 * Math.round(r / 255 * 5) + 6 * Math.round(g / 255 * 5) + Math.round(b / 255 * 5);
|
|
85
|
+
return `\x1b[38;5;${code}m`;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Interpolate between two RGB colors
|
|
89
|
+
*/
|
|
90
|
+
function interpolateRGB(color1, color2, factor) {
|
|
91
|
+
return {
|
|
92
|
+
r: Math.round(color1.r + (color2.r - color1.r) * factor),
|
|
93
|
+
g: Math.round(color1.g + (color2.g - color1.g) * factor),
|
|
94
|
+
b: Math.round(color1.b + (color2.b - color1.b) * factor)
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Create a gradient between two colors
|
|
99
|
+
* @param startColor - Starting ANSI color code
|
|
100
|
+
* @param endColor - Ending ANSI color code
|
|
101
|
+
* @param steps - Number of steps in the gradient
|
|
102
|
+
* @returns Array of ANSI color codes for each step
|
|
103
|
+
*/
|
|
104
|
+
function createGradient(startColor, endColor, steps) {
|
|
105
|
+
if (steps <= 0)
|
|
106
|
+
return [];
|
|
107
|
+
if (steps === 1)
|
|
108
|
+
return [startColor];
|
|
109
|
+
const start = parseColorToRGB(startColor);
|
|
110
|
+
const end = parseColorToRGB(endColor);
|
|
111
|
+
const gradient = [];
|
|
112
|
+
for (let i = 0; i < steps; i++) {
|
|
113
|
+
const factor = i / (steps - 1);
|
|
114
|
+
const rgb = interpolateRGB(start, end, factor);
|
|
115
|
+
gradient.push(rgbToAnsi256(rgb.r, rgb.g, rgb.b));
|
|
116
|
+
}
|
|
117
|
+
return gradient;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Apply gradient to text
|
|
121
|
+
* @param text - Text to colorize
|
|
122
|
+
* @param startColor - Starting color
|
|
123
|
+
* @param endColor - Ending color
|
|
124
|
+
* @returns Colorized text with gradient
|
|
125
|
+
*/
|
|
126
|
+
function applyGradient(text, startColor, endColor) {
|
|
127
|
+
const chars = text.split('');
|
|
128
|
+
const gradient = createGradient(startColor, endColor, chars.length);
|
|
129
|
+
return chars.map((char, i) => `${gradient[i]}${char}`).join('') + exports.colors.reset;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Apply single color to text
|
|
133
|
+
* @param text - Text to colorize
|
|
134
|
+
* @param color - ANSI color code
|
|
135
|
+
* @returns Colorized text
|
|
136
|
+
*/
|
|
137
|
+
function colorize(text, color) {
|
|
138
|
+
return `${color}${text}${exports.colors.reset}`;
|
|
139
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyboard handling utilities for CLI Menu Kit
|
|
3
|
+
* Handles key detection and special key combinations
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Key codes for special keys
|
|
7
|
+
*/
|
|
8
|
+
export declare const KEY_CODES: {
|
|
9
|
+
readonly UP: "\u001B[A";
|
|
10
|
+
readonly DOWN: "\u001B[B";
|
|
11
|
+
readonly RIGHT: "\u001B[C";
|
|
12
|
+
readonly LEFT: "\u001B[D";
|
|
13
|
+
readonly ENTER: "\r";
|
|
14
|
+
readonly SPACE: " ";
|
|
15
|
+
readonly BACKSPACE: "";
|
|
16
|
+
readonly DELETE: "\u001B[3~";
|
|
17
|
+
readonly ESCAPE: "\u001B";
|
|
18
|
+
readonly TAB: "\t";
|
|
19
|
+
readonly CTRL_C: "\u0003";
|
|
20
|
+
readonly CTRL_D: "\u0004";
|
|
21
|
+
readonly CTRL_Z: "\u001A";
|
|
22
|
+
readonly CTRL_A: "\u0001";
|
|
23
|
+
readonly CTRL_E: "\u0005";
|
|
24
|
+
readonly CTRL_U: "\u0015";
|
|
25
|
+
readonly CTRL_K: "\v";
|
|
26
|
+
readonly CTRL_L: "\f";
|
|
27
|
+
readonly HOME: "\u001B[H";
|
|
28
|
+
readonly END: "\u001B[F";
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Check if key is an arrow key
|
|
32
|
+
* @param key - Key input
|
|
33
|
+
* @returns True if arrow key
|
|
34
|
+
*/
|
|
35
|
+
export declare function isArrowKey(key: string): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Check if key is a number key (0-9)
|
|
38
|
+
* @param key - Key input
|
|
39
|
+
* @returns True if number key
|
|
40
|
+
*/
|
|
41
|
+
export declare function isNumberKey(key: string): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Check if key is a letter key (a-z, A-Z)
|
|
44
|
+
* @param key - Key input
|
|
45
|
+
* @returns True if letter key
|
|
46
|
+
*/
|
|
47
|
+
export declare function isLetterKey(key: string): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Check if key is alphanumeric (0-9, a-z, A-Z)
|
|
50
|
+
* @param key - Key input
|
|
51
|
+
* @returns True if alphanumeric
|
|
52
|
+
*/
|
|
53
|
+
export declare function isAlphanumeric(key: string): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Check if key is printable character
|
|
56
|
+
* @param key - Key input
|
|
57
|
+
* @returns True if printable
|
|
58
|
+
*/
|
|
59
|
+
export declare function isPrintable(key: string): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Check if key is Ctrl+C
|
|
62
|
+
* @param key - Key input
|
|
63
|
+
* @returns True if Ctrl+C
|
|
64
|
+
*/
|
|
65
|
+
export declare function isCtrlC(key: string): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Check if key is Enter
|
|
68
|
+
* @param key - Key input
|
|
69
|
+
* @returns True if Enter
|
|
70
|
+
*/
|
|
71
|
+
export declare function isEnter(key: string): boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Check if key is Space
|
|
74
|
+
* @param key - Key input
|
|
75
|
+
* @returns True if Space
|
|
76
|
+
*/
|
|
77
|
+
export declare function isSpace(key: string): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Check if key is Backspace
|
|
80
|
+
* @param key - Key input
|
|
81
|
+
* @returns True if Backspace
|
|
82
|
+
*/
|
|
83
|
+
export declare function isBackspace(key: string): boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Check if key is Escape
|
|
86
|
+
* @param key - Key input
|
|
87
|
+
* @returns True if Escape
|
|
88
|
+
*/
|
|
89
|
+
export declare function isEscape(key: string): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Parse number from key input
|
|
92
|
+
* @param key - Key input
|
|
93
|
+
* @returns Number or null if not a number
|
|
94
|
+
*/
|
|
95
|
+
export declare function parseNumber(key: string): number | null;
|
|
96
|
+
/**
|
|
97
|
+
* Normalize letter key to lowercase
|
|
98
|
+
* @param key - Key input
|
|
99
|
+
* @returns Lowercase letter or original key
|
|
100
|
+
*/
|
|
101
|
+
export declare function normalizeLetter(key: string): string;
|
|
102
|
+
/**
|
|
103
|
+
* Check if input is a command (starts with /)
|
|
104
|
+
* @param input - Input string
|
|
105
|
+
* @returns True if command
|
|
106
|
+
*/
|
|
107
|
+
export declare function isCommand(input: string): boolean;
|
|
108
|
+
/**
|
|
109
|
+
* Parse command from input
|
|
110
|
+
* @param input - Input string
|
|
111
|
+
* @returns Command name (without /) or null
|
|
112
|
+
*/
|
|
113
|
+
export declare function parseCommand(input: string): string | null;
|
|
114
|
+
/**
|
|
115
|
+
* Key event handler type
|
|
116
|
+
*/
|
|
117
|
+
export type KeyHandler = (key: string) => void;
|
|
118
|
+
/**
|
|
119
|
+
* Create a keyboard listener
|
|
120
|
+
* @param stdin - Input stream
|
|
121
|
+
* @param handler - Key handler function
|
|
122
|
+
* @returns Cleanup function
|
|
123
|
+
*/
|
|
124
|
+
export declare function createKeyboardListener(stdin: NodeJS.ReadStream, handler: KeyHandler): () => void;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Keyboard handling utilities for CLI Menu Kit
|
|
4
|
+
* Handles key detection and special key combinations
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.KEY_CODES = void 0;
|
|
8
|
+
exports.isArrowKey = isArrowKey;
|
|
9
|
+
exports.isNumberKey = isNumberKey;
|
|
10
|
+
exports.isLetterKey = isLetterKey;
|
|
11
|
+
exports.isAlphanumeric = isAlphanumeric;
|
|
12
|
+
exports.isPrintable = isPrintable;
|
|
13
|
+
exports.isCtrlC = isCtrlC;
|
|
14
|
+
exports.isEnter = isEnter;
|
|
15
|
+
exports.isSpace = isSpace;
|
|
16
|
+
exports.isBackspace = isBackspace;
|
|
17
|
+
exports.isEscape = isEscape;
|
|
18
|
+
exports.parseNumber = parseNumber;
|
|
19
|
+
exports.normalizeLetter = normalizeLetter;
|
|
20
|
+
exports.isCommand = isCommand;
|
|
21
|
+
exports.parseCommand = parseCommand;
|
|
22
|
+
exports.createKeyboardListener = createKeyboardListener;
|
|
23
|
+
/**
|
|
24
|
+
* Key codes for special keys
|
|
25
|
+
*/
|
|
26
|
+
exports.KEY_CODES = {
|
|
27
|
+
// Arrow keys
|
|
28
|
+
UP: '\x1b[A',
|
|
29
|
+
DOWN: '\x1b[B',
|
|
30
|
+
RIGHT: '\x1b[C',
|
|
31
|
+
LEFT: '\x1b[D',
|
|
32
|
+
// Control keys
|
|
33
|
+
ENTER: '\r',
|
|
34
|
+
SPACE: ' ',
|
|
35
|
+
BACKSPACE: '\x7f',
|
|
36
|
+
DELETE: '\x1b[3~',
|
|
37
|
+
ESCAPE: '\x1b',
|
|
38
|
+
TAB: '\t',
|
|
39
|
+
// Ctrl combinations
|
|
40
|
+
CTRL_C: '\x03',
|
|
41
|
+
CTRL_D: '\x04',
|
|
42
|
+
CTRL_Z: '\x1a',
|
|
43
|
+
CTRL_A: '\x01',
|
|
44
|
+
CTRL_E: '\x05',
|
|
45
|
+
CTRL_U: '\x15',
|
|
46
|
+
CTRL_K: '\x0b',
|
|
47
|
+
CTRL_L: '\x0c',
|
|
48
|
+
// Home/End
|
|
49
|
+
HOME: '\x1b[H',
|
|
50
|
+
END: '\x1b[F'
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Check if key is an arrow key
|
|
54
|
+
* @param key - Key input
|
|
55
|
+
* @returns True if arrow key
|
|
56
|
+
*/
|
|
57
|
+
function isArrowKey(key) {
|
|
58
|
+
return key === exports.KEY_CODES.UP || key === exports.KEY_CODES.DOWN ||
|
|
59
|
+
key === exports.KEY_CODES.LEFT || key === exports.KEY_CODES.RIGHT;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Check if key is a number key (0-9)
|
|
63
|
+
* @param key - Key input
|
|
64
|
+
* @returns True if number key
|
|
65
|
+
*/
|
|
66
|
+
function isNumberKey(key) {
|
|
67
|
+
return /^[0-9]$/.test(key);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Check if key is a letter key (a-z, A-Z)
|
|
71
|
+
* @param key - Key input
|
|
72
|
+
* @returns True if letter key
|
|
73
|
+
*/
|
|
74
|
+
function isLetterKey(key) {
|
|
75
|
+
return /^[a-zA-Z]$/.test(key);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Check if key is alphanumeric (0-9, a-z, A-Z)
|
|
79
|
+
* @param key - Key input
|
|
80
|
+
* @returns True if alphanumeric
|
|
81
|
+
*/
|
|
82
|
+
function isAlphanumeric(key) {
|
|
83
|
+
return /^[0-9a-zA-Z]$/.test(key);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Check if key is printable character
|
|
87
|
+
* @param key - Key input
|
|
88
|
+
* @returns True if printable
|
|
89
|
+
*/
|
|
90
|
+
function isPrintable(key) {
|
|
91
|
+
return key.length === 1 && key >= ' ' && key <= '~';
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Check if key is Ctrl+C
|
|
95
|
+
* @param key - Key input
|
|
96
|
+
* @returns True if Ctrl+C
|
|
97
|
+
*/
|
|
98
|
+
function isCtrlC(key) {
|
|
99
|
+
return key === exports.KEY_CODES.CTRL_C;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Check if key is Enter
|
|
103
|
+
* @param key - Key input
|
|
104
|
+
* @returns True if Enter
|
|
105
|
+
*/
|
|
106
|
+
function isEnter(key) {
|
|
107
|
+
return key === exports.KEY_CODES.ENTER || key === '\n';
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Check if key is Space
|
|
111
|
+
* @param key - Key input
|
|
112
|
+
* @returns True if Space
|
|
113
|
+
*/
|
|
114
|
+
function isSpace(key) {
|
|
115
|
+
return key === exports.KEY_CODES.SPACE;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Check if key is Backspace
|
|
119
|
+
* @param key - Key input
|
|
120
|
+
* @returns True if Backspace
|
|
121
|
+
*/
|
|
122
|
+
function isBackspace(key) {
|
|
123
|
+
return key === exports.KEY_CODES.BACKSPACE || key === '\b';
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Check if key is Escape
|
|
127
|
+
* @param key - Key input
|
|
128
|
+
* @returns True if Escape
|
|
129
|
+
*/
|
|
130
|
+
function isEscape(key) {
|
|
131
|
+
return key === exports.KEY_CODES.ESCAPE;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Parse number from key input
|
|
135
|
+
* @param key - Key input
|
|
136
|
+
* @returns Number or null if not a number
|
|
137
|
+
*/
|
|
138
|
+
function parseNumber(key) {
|
|
139
|
+
if (isNumberKey(key)) {
|
|
140
|
+
return parseInt(key, 10);
|
|
141
|
+
}
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Normalize letter key to lowercase
|
|
146
|
+
* @param key - Key input
|
|
147
|
+
* @returns Lowercase letter or original key
|
|
148
|
+
*/
|
|
149
|
+
function normalizeLetter(key) {
|
|
150
|
+
if (isLetterKey(key)) {
|
|
151
|
+
return key.toLowerCase();
|
|
152
|
+
}
|
|
153
|
+
return key;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Check if input is a command (starts with /)
|
|
157
|
+
* @param input - Input string
|
|
158
|
+
* @returns True if command
|
|
159
|
+
*/
|
|
160
|
+
function isCommand(input) {
|
|
161
|
+
return input.startsWith('/');
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Parse command from input
|
|
165
|
+
* @param input - Input string
|
|
166
|
+
* @returns Command name (without /) or null
|
|
167
|
+
*/
|
|
168
|
+
function parseCommand(input) {
|
|
169
|
+
if (isCommand(input)) {
|
|
170
|
+
return input.slice(1).toLowerCase();
|
|
171
|
+
}
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Create a keyboard listener
|
|
176
|
+
* @param stdin - Input stream
|
|
177
|
+
* @param handler - Key handler function
|
|
178
|
+
* @returns Cleanup function
|
|
179
|
+
*/
|
|
180
|
+
function createKeyboardListener(stdin, handler) {
|
|
181
|
+
stdin.on('data', handler);
|
|
182
|
+
return () => {
|
|
183
|
+
stdin.removeListener('data', handler);
|
|
184
|
+
};
|
|
185
|
+
}
|