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
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* User Configuration System for CLI Menu Kit
|
|
4
|
+
* Provides persistent user preferences
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.initConfig = initConfig;
|
|
41
|
+
exports.getConfigManager = getConfigManager;
|
|
42
|
+
exports.loadConfig = loadConfig;
|
|
43
|
+
exports.saveConfig = saveConfig;
|
|
44
|
+
exports.getConfig = getConfig;
|
|
45
|
+
exports.setConfig = setConfig;
|
|
46
|
+
exports.resetConfig = resetConfig;
|
|
47
|
+
const fs = __importStar(require("fs"));
|
|
48
|
+
const path = __importStar(require("path"));
|
|
49
|
+
const os = __importStar(require("os"));
|
|
50
|
+
class ConfigManager {
|
|
51
|
+
constructor(options) {
|
|
52
|
+
this.appName = options.appName;
|
|
53
|
+
this.configFileName = options.configFileName || 'config.json';
|
|
54
|
+
this.defaults = options.defaults || {};
|
|
55
|
+
// Set config directory
|
|
56
|
+
this.configDir = path.join(os.homedir(), `.${this.appName}`);
|
|
57
|
+
this.configPath = path.join(this.configDir, this.configFileName);
|
|
58
|
+
// Ensure config directory exists
|
|
59
|
+
this.ensureConfigDir();
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Ensure config directory exists
|
|
63
|
+
*/
|
|
64
|
+
ensureConfigDir() {
|
|
65
|
+
if (!fs.existsSync(this.configDir)) {
|
|
66
|
+
fs.mkdirSync(this.configDir, { recursive: true });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Load configuration
|
|
71
|
+
*/
|
|
72
|
+
load() {
|
|
73
|
+
if (!fs.existsSync(this.configPath)) {
|
|
74
|
+
return { ...this.defaults };
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const content = fs.readFileSync(this.configPath, 'utf8');
|
|
78
|
+
const config = JSON.parse(content);
|
|
79
|
+
return { ...this.defaults, ...config };
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
console.error('Failed to load config:', error);
|
|
83
|
+
return { ...this.defaults };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Save configuration
|
|
88
|
+
*/
|
|
89
|
+
save(config) {
|
|
90
|
+
const currentConfig = this.load();
|
|
91
|
+
const newConfig = {
|
|
92
|
+
...currentConfig,
|
|
93
|
+
...config,
|
|
94
|
+
updated_at: new Date().toISOString()
|
|
95
|
+
};
|
|
96
|
+
try {
|
|
97
|
+
fs.writeFileSync(this.configPath, JSON.stringify(newConfig, null, 2), 'utf8');
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
console.error('Failed to save config:', error);
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get a specific config value
|
|
106
|
+
*/
|
|
107
|
+
get(key) {
|
|
108
|
+
const config = this.load();
|
|
109
|
+
return config[key];
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Set a specific config value
|
|
113
|
+
*/
|
|
114
|
+
set(key, value) {
|
|
115
|
+
this.save({ [key]: value });
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Reset configuration to defaults
|
|
119
|
+
*/
|
|
120
|
+
reset() {
|
|
121
|
+
if (fs.existsSync(this.configPath)) {
|
|
122
|
+
fs.unlinkSync(this.configPath);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Get config file path
|
|
127
|
+
*/
|
|
128
|
+
getConfigPath() {
|
|
129
|
+
return this.configPath;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Get config directory path
|
|
133
|
+
*/
|
|
134
|
+
getConfigDir() {
|
|
135
|
+
return this.configDir;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Global config manager instance
|
|
139
|
+
let globalConfigManager = null;
|
|
140
|
+
/**
|
|
141
|
+
* Initialize config manager
|
|
142
|
+
*/
|
|
143
|
+
function initConfig(options) {
|
|
144
|
+
globalConfigManager = new ConfigManager(options);
|
|
145
|
+
return globalConfigManager;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Get global config manager
|
|
149
|
+
*/
|
|
150
|
+
function getConfigManager() {
|
|
151
|
+
if (!globalConfigManager) {
|
|
152
|
+
throw new Error('Config manager not initialized. Call initConfig() first.');
|
|
153
|
+
}
|
|
154
|
+
return globalConfigManager;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Load configuration
|
|
158
|
+
*/
|
|
159
|
+
function loadConfig() {
|
|
160
|
+
return getConfigManager().load();
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Save configuration
|
|
164
|
+
*/
|
|
165
|
+
function saveConfig(config) {
|
|
166
|
+
getConfigManager().save(config);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Get config value
|
|
170
|
+
*/
|
|
171
|
+
function getConfig(key) {
|
|
172
|
+
return getConfigManager().get(key);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Set config value
|
|
176
|
+
*/
|
|
177
|
+
function setConfig(key, value) {
|
|
178
|
+
getConfigManager().set(key, value);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Reset configuration
|
|
182
|
+
*/
|
|
183
|
+
function resetConfig() {
|
|
184
|
+
getConfigManager().reset();
|
|
185
|
+
}
|
package/dist/core/colors.d.ts
CHANGED
|
@@ -44,19 +44,21 @@ export declare const colors: {
|
|
|
44
44
|
* Defines consistent colors for different levels of information
|
|
45
45
|
*/
|
|
46
46
|
export declare const defaultUIColors: {
|
|
47
|
-
readonly primary: "\u001B[
|
|
48
|
-
readonly accent: "\u001B[
|
|
47
|
+
readonly primary: "\u001B[0m";
|
|
48
|
+
readonly accent: "\u001B[0m";
|
|
49
49
|
readonly textPrimary: "\u001B[0m";
|
|
50
50
|
readonly textSecondary: "\u001B[2m";
|
|
51
51
|
readonly textMuted: "\u001B[90m";
|
|
52
52
|
readonly success: "\u001B[32m";
|
|
53
53
|
readonly error: "\u001B[31m";
|
|
54
54
|
readonly warning: "\u001B[33m";
|
|
55
|
-
readonly info: "\u001B[
|
|
56
|
-
readonly cursor: "\u001B[
|
|
57
|
-
readonly selected: "\u001B[
|
|
55
|
+
readonly info: "\u001B[0m";
|
|
56
|
+
readonly cursor: "\u001B[0m";
|
|
57
|
+
readonly selected: "\u001B[0m";
|
|
58
|
+
readonly highlightBg: "";
|
|
59
|
+
readonly highlightText: "\u001B[0m";
|
|
58
60
|
readonly disabled: "\u001B[2m";
|
|
59
|
-
readonly border: "\u001B[
|
|
61
|
+
readonly border: "\u001B[90m";
|
|
60
62
|
readonly separator: "\u001B[2m";
|
|
61
63
|
readonly prefix: "\u001B[2m";
|
|
62
64
|
};
|
|
@@ -64,19 +66,21 @@ export declare const defaultUIColors: {
|
|
|
64
66
|
* Get current UI colors
|
|
65
67
|
*/
|
|
66
68
|
export declare function getUIColors(): {
|
|
67
|
-
primary: "\u001B[
|
|
68
|
-
accent: "\u001B[
|
|
69
|
+
primary: "\u001B[0m";
|
|
70
|
+
accent: "\u001B[0m";
|
|
69
71
|
textPrimary: "\u001B[0m";
|
|
70
72
|
textSecondary: "\u001B[2m";
|
|
71
73
|
textMuted: "\u001B[90m";
|
|
72
74
|
success: "\u001B[32m";
|
|
73
75
|
error: "\u001B[31m";
|
|
74
76
|
warning: "\u001B[33m";
|
|
75
|
-
info: "\u001B[
|
|
76
|
-
cursor: "\u001B[
|
|
77
|
-
selected: "\u001B[
|
|
77
|
+
info: "\u001B[0m";
|
|
78
|
+
cursor: "\u001B[0m";
|
|
79
|
+
selected: "\u001B[0m";
|
|
80
|
+
highlightBg: "";
|
|
81
|
+
highlightText: "\u001B[0m";
|
|
78
82
|
disabled: "\u001B[2m";
|
|
79
|
-
border: "\u001B[
|
|
83
|
+
border: "\u001B[90m";
|
|
80
84
|
separator: "\u001B[2m";
|
|
81
85
|
prefix: "\u001B[2m";
|
|
82
86
|
};
|
|
@@ -93,19 +97,21 @@ export declare function resetUIColors(): void;
|
|
|
93
97
|
* UI colors accessor (always returns current colors)
|
|
94
98
|
*/
|
|
95
99
|
export declare const uiColors: {
|
|
96
|
-
readonly primary: "\u001B[
|
|
97
|
-
readonly accent: "\u001B[
|
|
100
|
+
readonly primary: "\u001B[0m";
|
|
101
|
+
readonly accent: "\u001B[0m";
|
|
98
102
|
readonly textPrimary: "\u001B[0m";
|
|
99
103
|
readonly textSecondary: "\u001B[2m";
|
|
100
104
|
readonly textMuted: "\u001B[90m";
|
|
101
105
|
readonly success: "\u001B[32m";
|
|
102
106
|
readonly error: "\u001B[31m";
|
|
103
107
|
readonly warning: "\u001B[33m";
|
|
104
|
-
readonly info: "\u001B[
|
|
105
|
-
readonly cursor: "\u001B[
|
|
106
|
-
readonly selected: "\u001B[
|
|
108
|
+
readonly info: "\u001B[0m";
|
|
109
|
+
readonly cursor: "\u001B[0m";
|
|
110
|
+
readonly selected: "\u001B[0m";
|
|
111
|
+
readonly highlightBg: "";
|
|
112
|
+
readonly highlightText: "\u001B[0m";
|
|
107
113
|
readonly disabled: "\u001B[2m";
|
|
108
|
-
readonly border: "\u001B[
|
|
114
|
+
readonly border: "\u001B[90m";
|
|
109
115
|
readonly separator: "\u001B[2m";
|
|
110
116
|
readonly prefix: "\u001B[2m";
|
|
111
117
|
};
|
package/dist/core/colors.js
CHANGED
|
@@ -59,8 +59,8 @@ exports.colors = {
|
|
|
59
59
|
*/
|
|
60
60
|
exports.defaultUIColors = {
|
|
61
61
|
// Primary elements
|
|
62
|
-
primary: exports.colors.
|
|
63
|
-
accent: exports.colors.
|
|
62
|
+
primary: exports.colors.reset, // Main interactive elements, follows terminal foreground
|
|
63
|
+
accent: exports.colors.reset, // Secondary highlights, follows terminal foreground
|
|
64
64
|
// Text hierarchy
|
|
65
65
|
textPrimary: exports.colors.reset, // Main text (black/default)
|
|
66
66
|
textSecondary: exports.colors.dim, // Descriptions, hints, less important text
|
|
@@ -69,13 +69,15 @@ exports.defaultUIColors = {
|
|
|
69
69
|
success: exports.colors.green, // Success states, confirmations
|
|
70
70
|
error: exports.colors.red, // Errors, warnings, exit
|
|
71
71
|
warning: exports.colors.yellow, // Warnings, cautions
|
|
72
|
-
info: exports.colors.
|
|
72
|
+
info: exports.colors.reset, // Informational messages
|
|
73
73
|
// Interactive elements
|
|
74
|
-
cursor: exports.colors.
|
|
75
|
-
selected: exports.colors.
|
|
74
|
+
cursor: exports.colors.reset, // Cursor indicator
|
|
75
|
+
selected: exports.colors.reset, // Selected items
|
|
76
|
+
highlightBg: '', // Optional background block for highlighted option
|
|
77
|
+
highlightText: exports.colors.reset, // Text color when highlightBg is used
|
|
76
78
|
disabled: exports.colors.dim, // Disabled/inactive items
|
|
77
79
|
// Structural elements
|
|
78
|
-
border: exports.colors.
|
|
80
|
+
border: exports.colors.brightBlack, // Borders, frames
|
|
79
81
|
separator: exports.colors.dim, // Separators, dividers
|
|
80
82
|
prefix: exports.colors.dim // Number/letter prefixes
|
|
81
83
|
};
|
|
@@ -118,6 +120,18 @@ exports.uiColors = new Proxy({}, {
|
|
|
118
120
|
* Supports basic 8 colors and bright variants
|
|
119
121
|
*/
|
|
120
122
|
function parseColorToRGB(colorCode) {
|
|
123
|
+
const trueColorMatch = /^\x1b\[38;2;(\d{1,3});(\d{1,3});(\d{1,3})m$/.exec(colorCode);
|
|
124
|
+
if (trueColorMatch) {
|
|
125
|
+
return {
|
|
126
|
+
r: Math.max(0, Math.min(255, Number.parseInt(trueColorMatch[1], 10))),
|
|
127
|
+
g: Math.max(0, Math.min(255, Number.parseInt(trueColorMatch[2], 10))),
|
|
128
|
+
b: Math.max(0, Math.min(255, Number.parseInt(trueColorMatch[3], 10)))
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
const ansi256Match = /^\x1b\[38;5;(\d{1,3})m$/.exec(colorCode);
|
|
132
|
+
if (ansi256Match) {
|
|
133
|
+
return ansi256ToRgb(Math.max(0, Math.min(255, Number.parseInt(ansi256Match[1], 10))));
|
|
134
|
+
}
|
|
121
135
|
// Map of ANSI codes to approximate RGB values
|
|
122
136
|
const colorMap = {
|
|
123
137
|
'\x1b[30m': { r: 0, g: 0, b: 0 }, // black
|
|
@@ -139,6 +153,48 @@ function parseColorToRGB(colorCode) {
|
|
|
139
153
|
};
|
|
140
154
|
return colorMap[colorCode] || { r: 170, g: 170, b: 170 };
|
|
141
155
|
}
|
|
156
|
+
function detectColorMode(colorCode) {
|
|
157
|
+
if (/^\x1b\[38;2;\d{1,3};\d{1,3};\d{1,3}m$/.test(colorCode)) {
|
|
158
|
+
return 'truecolor';
|
|
159
|
+
}
|
|
160
|
+
if (/^\x1b\[38;5;\d{1,3}m$/.test(colorCode)) {
|
|
161
|
+
return 'ansi256';
|
|
162
|
+
}
|
|
163
|
+
return 'ansi16';
|
|
164
|
+
}
|
|
165
|
+
function ansi256ToRgb(code) {
|
|
166
|
+
if (code < 16) {
|
|
167
|
+
const ansi16Map = [
|
|
168
|
+
{ r: 0, g: 0, b: 0 }, // 0 black
|
|
169
|
+
{ r: 170, g: 0, b: 0 }, // 1 red
|
|
170
|
+
{ r: 0, g: 170, b: 0 }, // 2 green
|
|
171
|
+
{ r: 170, g: 85, b: 0 }, // 3 yellow
|
|
172
|
+
{ r: 0, g: 0, b: 170 }, // 4 blue
|
|
173
|
+
{ r: 170, g: 0, b: 170 }, // 5 magenta
|
|
174
|
+
{ r: 0, g: 170, b: 170 }, // 6 cyan
|
|
175
|
+
{ r: 170, g: 170, b: 170 }, // 7 white
|
|
176
|
+
{ r: 85, g: 85, b: 85 }, // 8 bright black
|
|
177
|
+
{ r: 255, g: 85, b: 85 }, // 9 bright red
|
|
178
|
+
{ r: 85, g: 255, b: 85 }, // 10 bright green
|
|
179
|
+
{ r: 255, g: 255, b: 85 }, // 11 bright yellow
|
|
180
|
+
{ r: 85, g: 85, b: 255 }, // 12 bright blue
|
|
181
|
+
{ r: 255, g: 85, b: 255 }, // 13 bright magenta
|
|
182
|
+
{ r: 85, g: 255, b: 255 }, // 14 bright cyan
|
|
183
|
+
{ r: 255, g: 255, b: 255 } // 15 bright white
|
|
184
|
+
];
|
|
185
|
+
return ansi16Map[code];
|
|
186
|
+
}
|
|
187
|
+
if (code >= 16 && code <= 231) {
|
|
188
|
+
const n = code - 16;
|
|
189
|
+
const r = Math.floor(n / 36);
|
|
190
|
+
const g = Math.floor((n % 36) / 6);
|
|
191
|
+
const b = n % 6;
|
|
192
|
+
const steps = [0, 95, 135, 175, 215, 255];
|
|
193
|
+
return { r: steps[r], g: steps[g], b: steps[b] };
|
|
194
|
+
}
|
|
195
|
+
const gray = 8 + (code - 232) * 10;
|
|
196
|
+
return { r: gray, g: gray, b: gray };
|
|
197
|
+
}
|
|
142
198
|
/**
|
|
143
199
|
* Convert RGB to ANSI 256-color code
|
|
144
200
|
*/
|
|
@@ -147,6 +203,12 @@ function rgbToAnsi256(r, g, b) {
|
|
|
147
203
|
const code = 16 + 36 * Math.round(r / 255 * 5) + 6 * Math.round(g / 255 * 5) + Math.round(b / 255 * 5);
|
|
148
204
|
return `\x1b[38;5;${code}m`;
|
|
149
205
|
}
|
|
206
|
+
function rgbToAnsiTrueColor(r, g, b) {
|
|
207
|
+
const rr = Math.max(0, Math.min(255, Math.round(r)));
|
|
208
|
+
const gg = Math.max(0, Math.min(255, Math.round(g)));
|
|
209
|
+
const bb = Math.max(0, Math.min(255, Math.round(b)));
|
|
210
|
+
return `\x1b[38;2;${rr};${gg};${bb}m`;
|
|
211
|
+
}
|
|
150
212
|
/**
|
|
151
213
|
* Interpolate between two RGB colors
|
|
152
214
|
*/
|
|
@@ -171,11 +233,16 @@ function createGradient(startColor, endColor, steps) {
|
|
|
171
233
|
return [startColor];
|
|
172
234
|
const start = parseColorToRGB(startColor);
|
|
173
235
|
const end = parseColorToRGB(endColor);
|
|
236
|
+
const startMode = detectColorMode(startColor);
|
|
237
|
+
const endMode = detectColorMode(endColor);
|
|
238
|
+
const outputMode = startMode === 'truecolor' && endMode === 'truecolor' ? 'truecolor' : 'ansi256';
|
|
174
239
|
const gradient = [];
|
|
175
240
|
for (let i = 0; i < steps; i++) {
|
|
176
241
|
const factor = i / (steps - 1);
|
|
177
242
|
const rgb = interpolateRGB(start, end, factor);
|
|
178
|
-
gradient.push(
|
|
243
|
+
gradient.push(outputMode === 'truecolor'
|
|
244
|
+
? rgbToAnsiTrueColor(rgb.r, rgb.g, rgb.b)
|
|
245
|
+
: rgbToAnsi256(rgb.r, rgb.g, rgb.b));
|
|
179
246
|
}
|
|
180
247
|
return gradient;
|
|
181
248
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hint Manager - Manages hints from multiple components with priority
|
|
3
|
+
*
|
|
4
|
+
* Allows multiple components to set hints with different priorities.
|
|
5
|
+
* The highest priority hint is displayed.
|
|
6
|
+
*/
|
|
7
|
+
import { EventEmitter } from 'events';
|
|
8
|
+
export declare class HintManager extends EventEmitter {
|
|
9
|
+
private entries;
|
|
10
|
+
/**
|
|
11
|
+
* Set a hint with a token and priority
|
|
12
|
+
* @param token - Unique identifier for this hint source
|
|
13
|
+
* @param text - Hint text to display
|
|
14
|
+
* @param priority - Higher priority hints are displayed first (default: 0)
|
|
15
|
+
*/
|
|
16
|
+
set(token: string, text: string, priority?: number): void;
|
|
17
|
+
/**
|
|
18
|
+
* Clear a hint by token
|
|
19
|
+
*/
|
|
20
|
+
clear(token: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Get the current highest priority hint
|
|
23
|
+
*/
|
|
24
|
+
current(): string;
|
|
25
|
+
/**
|
|
26
|
+
* Clear all hints
|
|
27
|
+
*/
|
|
28
|
+
clearAll(): void;
|
|
29
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Hint Manager - Manages hints from multiple components with priority
|
|
4
|
+
*
|
|
5
|
+
* Allows multiple components to set hints with different priorities.
|
|
6
|
+
* The highest priority hint is displayed.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.HintManager = void 0;
|
|
10
|
+
const events_1 = require("events");
|
|
11
|
+
class HintManager extends events_1.EventEmitter {
|
|
12
|
+
constructor() {
|
|
13
|
+
super(...arguments);
|
|
14
|
+
this.entries = new Map();
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Set a hint with a token and priority
|
|
18
|
+
* @param token - Unique identifier for this hint source
|
|
19
|
+
* @param text - Hint text to display
|
|
20
|
+
* @param priority - Higher priority hints are displayed first (default: 0)
|
|
21
|
+
*/
|
|
22
|
+
set(token, text, priority = 0) {
|
|
23
|
+
this.entries.set(token, {
|
|
24
|
+
text,
|
|
25
|
+
priority,
|
|
26
|
+
timestamp: Date.now()
|
|
27
|
+
});
|
|
28
|
+
this.emit('change', this.current());
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Clear a hint by token
|
|
32
|
+
*/
|
|
33
|
+
clear(token) {
|
|
34
|
+
if (this.entries.delete(token)) {
|
|
35
|
+
this.emit('change', this.current());
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get the current highest priority hint
|
|
40
|
+
*/
|
|
41
|
+
current() {
|
|
42
|
+
const list = Array.from(this.entries.values());
|
|
43
|
+
if (list.length === 0) {
|
|
44
|
+
return '';
|
|
45
|
+
}
|
|
46
|
+
// Sort by priority (descending), then by timestamp (most recent first)
|
|
47
|
+
list.sort((a, b) => {
|
|
48
|
+
if (b.priority !== a.priority) {
|
|
49
|
+
return b.priority - a.priority;
|
|
50
|
+
}
|
|
51
|
+
return b.timestamp - a.timestamp;
|
|
52
|
+
});
|
|
53
|
+
return list[0].text;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Clear all hints
|
|
57
|
+
*/
|
|
58
|
+
clearAll() {
|
|
59
|
+
if (this.entries.size > 0) {
|
|
60
|
+
this.entries.clear();
|
|
61
|
+
this.emit('change', '');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.HintManager = HintManager;
|
package/dist/core/renderer.d.ts
CHANGED
|
@@ -43,8 +43,9 @@ export declare function renderSeparator(char?: string, width?: number): void;
|
|
|
43
43
|
* Render a section label (menu grouping)
|
|
44
44
|
* @param label - Label text (optional)
|
|
45
45
|
* @param width - Total width of the separator (default: 30)
|
|
46
|
+
* @param align - Alignment of the label (default: 'center')
|
|
46
47
|
*/
|
|
47
|
-
export declare function renderSectionLabel(label?: string, width?: number): void;
|
|
48
|
+
export declare function renderSectionLabel(label?: string, width?: number, align?: 'left' | 'center' | 'right'): void;
|
|
48
49
|
/**
|
|
49
50
|
* Render a message with icon
|
|
50
51
|
* @param type - Message type (success, error, warning, info, question)
|
package/dist/core/renderer.js
CHANGED
|
@@ -69,14 +69,23 @@ function renderOption(text, isSelected, isHighlighted, prefix) {
|
|
|
69
69
|
const parts = text.split(' - ');
|
|
70
70
|
const mainText = parts[0];
|
|
71
71
|
const description = parts.length > 1 ? parts.slice(1).join(' - ') : '';
|
|
72
|
+
const hasHighlightBlock = Boolean(colors_js_1.uiColors.highlightBg);
|
|
73
|
+
const blockLead = hasHighlightBlock ? ' ' : '';
|
|
72
74
|
if (isHighlighted) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
if (hasHighlightBlock) {
|
|
76
|
+
const highlightText = colors_js_1.uiColors.highlightText || colors_js_1.uiColors.textPrimary;
|
|
77
|
+
const mergedText = description ? `${mainText} - ${description}` : mainText;
|
|
78
|
+
line += `${colors_js_1.uiColors.highlightBg}${highlightText}${colors_js_1.colors.bold}${blockLead}${mergedText} ${colors_js_1.colors.reset}`;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
line += `${colors_js_1.uiColors.primary}${colors_js_1.colors.bold}${mainText}${colors_js_1.colors.reset}`;
|
|
82
|
+
if (description) {
|
|
83
|
+
line += ` ${colors_js_1.uiColors.textSecondary}- ${description}${colors_js_1.colors.reset}`;
|
|
84
|
+
}
|
|
76
85
|
}
|
|
77
86
|
}
|
|
78
87
|
else {
|
|
79
|
-
line += `${colors_js_1.colors.bold}${mainText}${colors_js_1.colors.reset}`;
|
|
88
|
+
line += `${colors_js_1.uiColors.textPrimary}${colors_js_1.colors.bold}${blockLead}${mainText}${colors_js_1.colors.reset}`;
|
|
80
89
|
if (description) {
|
|
81
90
|
line += ` ${colors_js_1.uiColors.textSecondary}- ${description}${colors_js_1.colors.reset}`;
|
|
82
91
|
}
|
|
@@ -90,12 +99,12 @@ function renderOption(text, isSelected, isHighlighted, prefix) {
|
|
|
90
99
|
* @param showCursor - Whether to show cursor
|
|
91
100
|
*/
|
|
92
101
|
function renderInputPrompt(prompt, value, showCursor = false) {
|
|
93
|
-
let line = ` ${prompt} `;
|
|
102
|
+
let line = ` ${colors_js_1.uiColors.textPrimary}${prompt}${colors_js_1.colors.reset} `;
|
|
94
103
|
if (value) {
|
|
95
|
-
line += `${colors_js_1.
|
|
104
|
+
line += `${colors_js_1.uiColors.primary}${value}${colors_js_1.colors.reset}`;
|
|
96
105
|
}
|
|
97
106
|
if (showCursor) {
|
|
98
|
-
line += `${colors_js_1.
|
|
107
|
+
line += `${colors_js_1.uiColors.primary}_${colors_js_1.colors.reset}`;
|
|
99
108
|
}
|
|
100
109
|
(0, terminal_js_1.writeLine)(line);
|
|
101
110
|
}
|
|
@@ -135,17 +144,32 @@ function renderSeparator(char = '─', width) {
|
|
|
135
144
|
* Render a section label (menu grouping)
|
|
136
145
|
* @param label - Label text (optional)
|
|
137
146
|
* @param width - Total width of the separator (default: 30)
|
|
147
|
+
* @param align - Alignment of the label (default: 'center')
|
|
138
148
|
*/
|
|
139
|
-
function renderSectionLabel(label, width = 30) {
|
|
149
|
+
function renderSectionLabel(label, width = 30, align = 'center') {
|
|
140
150
|
if (label) {
|
|
141
|
-
const totalWidth = width;
|
|
142
|
-
const padding = 2; // Spaces around label
|
|
151
|
+
const totalWidth = width;
|
|
143
152
|
const labelWithPadding = ` ${label} `;
|
|
144
153
|
const labelLength = labelWithPadding.length;
|
|
145
154
|
const dashesTotal = totalWidth - labelLength;
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
155
|
+
let dashesLeft;
|
|
156
|
+
let dashesRight;
|
|
157
|
+
switch (align) {
|
|
158
|
+
case 'left':
|
|
159
|
+
dashesLeft = 0;
|
|
160
|
+
dashesRight = dashesTotal;
|
|
161
|
+
break;
|
|
162
|
+
case 'right':
|
|
163
|
+
dashesLeft = dashesTotal;
|
|
164
|
+
dashesRight = 0;
|
|
165
|
+
break;
|
|
166
|
+
case 'center':
|
|
167
|
+
default:
|
|
168
|
+
dashesLeft = Math.floor(dashesTotal / 2);
|
|
169
|
+
dashesRight = dashesTotal - dashesLeft;
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
const line = ` ${colors_js_1.uiColors.primary}${colors_js_1.colors.bold}${'─'.repeat(dashesLeft)}${labelWithPadding}${'─'.repeat(dashesRight)}${colors_js_1.colors.reset}`;
|
|
149
173
|
(0, terminal_js_1.writeLine)(line);
|
|
150
174
|
}
|
|
151
175
|
else {
|
|
@@ -163,23 +187,23 @@ function renderMessage(type, message) {
|
|
|
163
187
|
switch (type) {
|
|
164
188
|
case 'success':
|
|
165
189
|
icon = '✓';
|
|
166
|
-
color = colors_js_1.
|
|
190
|
+
color = colors_js_1.uiColors.success;
|
|
167
191
|
break;
|
|
168
192
|
case 'error':
|
|
169
193
|
icon = '✗';
|
|
170
|
-
color = colors_js_1.
|
|
194
|
+
color = colors_js_1.uiColors.error;
|
|
171
195
|
break;
|
|
172
196
|
case 'warning':
|
|
173
197
|
icon = '⚠';
|
|
174
|
-
color = colors_js_1.
|
|
198
|
+
color = colors_js_1.uiColors.warning;
|
|
175
199
|
break;
|
|
176
200
|
case 'info':
|
|
177
201
|
icon = 'ℹ';
|
|
178
|
-
color = colors_js_1.
|
|
202
|
+
color = colors_js_1.uiColors.info;
|
|
179
203
|
break;
|
|
180
204
|
case 'question':
|
|
181
205
|
icon = '?';
|
|
182
|
-
color = colors_js_1.
|
|
206
|
+
color = colors_js_1.uiColors.warning;
|
|
183
207
|
break;
|
|
184
208
|
}
|
|
185
209
|
(0, terminal_js_1.writeLine)(`${color}${icon}${colors_js_1.colors.reset} ${message}`);
|
|
@@ -193,16 +217,16 @@ function renderProgress(steps, currentStep) {
|
|
|
193
217
|
const parts = [];
|
|
194
218
|
steps.forEach((step, index) => {
|
|
195
219
|
if (index === currentStep) {
|
|
196
|
-
parts.push(`${colors_js_1.
|
|
220
|
+
parts.push(`${colors_js_1.uiColors.primary}${step}${colors_js_1.colors.reset}`);
|
|
197
221
|
}
|
|
198
222
|
else if (index < currentStep) {
|
|
199
|
-
parts.push(step);
|
|
223
|
+
parts.push(`${colors_js_1.uiColors.textPrimary}${step}${colors_js_1.colors.reset}`);
|
|
200
224
|
}
|
|
201
225
|
else {
|
|
202
|
-
parts.push(`${colors_js_1.
|
|
226
|
+
parts.push(`${colors_js_1.uiColors.textSecondary}${step}${colors_js_1.colors.reset}`);
|
|
203
227
|
}
|
|
204
228
|
});
|
|
205
|
-
(0, terminal_js_1.writeLine)(` ${parts.join(` ${colors_js_1.
|
|
229
|
+
(0, terminal_js_1.writeLine)(` ${parts.join(` ${colors_js_1.uiColors.textSecondary}→${colors_js_1.colors.reset} `)}`);
|
|
206
230
|
}
|
|
207
231
|
/**
|
|
208
232
|
* Render a box with content
|