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
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User Configuration System for CLI Menu Kit
|
|
3
|
+
* Provides persistent user preferences
|
|
4
|
+
*/
|
|
5
|
+
export interface UserConfig {
|
|
6
|
+
language?: string;
|
|
7
|
+
theme?: string;
|
|
8
|
+
[key: string]: any;
|
|
9
|
+
}
|
|
10
|
+
export interface ConfigOptions {
|
|
11
|
+
appName: string;
|
|
12
|
+
configFileName?: string;
|
|
13
|
+
defaults?: UserConfig;
|
|
14
|
+
}
|
|
15
|
+
declare class ConfigManager {
|
|
16
|
+
private appName;
|
|
17
|
+
private configFileName;
|
|
18
|
+
private defaults;
|
|
19
|
+
private configDir;
|
|
20
|
+
private configPath;
|
|
21
|
+
constructor(options: ConfigOptions);
|
|
22
|
+
/**
|
|
23
|
+
* Ensure config directory exists
|
|
24
|
+
*/
|
|
25
|
+
private ensureConfigDir;
|
|
26
|
+
/**
|
|
27
|
+
* Load configuration
|
|
28
|
+
*/
|
|
29
|
+
load(): UserConfig;
|
|
30
|
+
/**
|
|
31
|
+
* Save configuration
|
|
32
|
+
*/
|
|
33
|
+
save(config: Partial<UserConfig>): void;
|
|
34
|
+
/**
|
|
35
|
+
* Get a specific config value
|
|
36
|
+
*/
|
|
37
|
+
get<K extends keyof UserConfig>(key: K): UserConfig[K];
|
|
38
|
+
/**
|
|
39
|
+
* Set a specific config value
|
|
40
|
+
*/
|
|
41
|
+
set<K extends keyof UserConfig>(key: K, value: UserConfig[K]): void;
|
|
42
|
+
/**
|
|
43
|
+
* Reset configuration to defaults
|
|
44
|
+
*/
|
|
45
|
+
reset(): void;
|
|
46
|
+
/**
|
|
47
|
+
* Get config file path
|
|
48
|
+
*/
|
|
49
|
+
getConfigPath(): string;
|
|
50
|
+
/**
|
|
51
|
+
* Get config directory path
|
|
52
|
+
*/
|
|
53
|
+
getConfigDir(): string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Initialize config manager
|
|
57
|
+
*/
|
|
58
|
+
export declare function initConfig(options: ConfigOptions): ConfigManager;
|
|
59
|
+
/**
|
|
60
|
+
* Get global config manager
|
|
61
|
+
*/
|
|
62
|
+
export declare function getConfigManager(): ConfigManager;
|
|
63
|
+
/**
|
|
64
|
+
* Load configuration
|
|
65
|
+
*/
|
|
66
|
+
export declare function loadConfig(): UserConfig;
|
|
67
|
+
/**
|
|
68
|
+
* Save configuration
|
|
69
|
+
*/
|
|
70
|
+
export declare function saveConfig(config: Partial<UserConfig>): void;
|
|
71
|
+
/**
|
|
72
|
+
* Get config value
|
|
73
|
+
*/
|
|
74
|
+
export declare function getConfig<K extends keyof UserConfig>(key: K): UserConfig[K];
|
|
75
|
+
/**
|
|
76
|
+
* Set config value
|
|
77
|
+
*/
|
|
78
|
+
export declare function setConfig<K extends keyof UserConfig>(key: K, value: UserConfig[K]): void;
|
|
79
|
+
/**
|
|
80
|
+
* Reset configuration
|
|
81
|
+
*/
|
|
82
|
+
export declare function resetConfig(): void;
|
|
83
|
+
export {};
|
|
@@ -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
|
}
|
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
|
}
|
|
@@ -160,8 +169,7 @@ function renderSectionLabel(label, width = 30, align = 'center') {
|
|
|
160
169
|
dashesRight = dashesTotal - dashesLeft;
|
|
161
170
|
break;
|
|
162
171
|
}
|
|
163
|
-
|
|
164
|
-
const line = ` ${colors_js_1.colors.cyan}${colors_js_1.colors.bold}${'─'.repeat(dashesLeft)}${labelWithPadding}${'─'.repeat(dashesRight)}${colors_js_1.colors.reset}`;
|
|
172
|
+
const line = ` ${colors_js_1.uiColors.primary}${colors_js_1.colors.bold}${'─'.repeat(dashesLeft)}${labelWithPadding}${'─'.repeat(dashesRight)}${colors_js_1.colors.reset}`;
|
|
165
173
|
(0, terminal_js_1.writeLine)(line);
|
|
166
174
|
}
|
|
167
175
|
else {
|
|
@@ -179,23 +187,23 @@ function renderMessage(type, message) {
|
|
|
179
187
|
switch (type) {
|
|
180
188
|
case 'success':
|
|
181
189
|
icon = '✓';
|
|
182
|
-
color = colors_js_1.
|
|
190
|
+
color = colors_js_1.uiColors.success;
|
|
183
191
|
break;
|
|
184
192
|
case 'error':
|
|
185
193
|
icon = '✗';
|
|
186
|
-
color = colors_js_1.
|
|
194
|
+
color = colors_js_1.uiColors.error;
|
|
187
195
|
break;
|
|
188
196
|
case 'warning':
|
|
189
197
|
icon = '⚠';
|
|
190
|
-
color = colors_js_1.
|
|
198
|
+
color = colors_js_1.uiColors.warning;
|
|
191
199
|
break;
|
|
192
200
|
case 'info':
|
|
193
201
|
icon = 'ℹ';
|
|
194
|
-
color = colors_js_1.
|
|
202
|
+
color = colors_js_1.uiColors.info;
|
|
195
203
|
break;
|
|
196
204
|
case 'question':
|
|
197
205
|
icon = '?';
|
|
198
|
-
color = colors_js_1.
|
|
206
|
+
color = colors_js_1.uiColors.warning;
|
|
199
207
|
break;
|
|
200
208
|
}
|
|
201
209
|
(0, terminal_js_1.writeLine)(`${color}${icon}${colors_js_1.colors.reset} ${message}`);
|
|
@@ -209,16 +217,16 @@ function renderProgress(steps, currentStep) {
|
|
|
209
217
|
const parts = [];
|
|
210
218
|
steps.forEach((step, index) => {
|
|
211
219
|
if (index === currentStep) {
|
|
212
|
-
parts.push(`${colors_js_1.
|
|
220
|
+
parts.push(`${colors_js_1.uiColors.primary}${step}${colors_js_1.colors.reset}`);
|
|
213
221
|
}
|
|
214
222
|
else if (index < currentStep) {
|
|
215
|
-
parts.push(step);
|
|
223
|
+
parts.push(`${colors_js_1.uiColors.textPrimary}${step}${colors_js_1.colors.reset}`);
|
|
216
224
|
}
|
|
217
225
|
else {
|
|
218
|
-
parts.push(`${colors_js_1.
|
|
226
|
+
parts.push(`${colors_js_1.uiColors.textSecondary}${step}${colors_js_1.colors.reset}`);
|
|
219
227
|
}
|
|
220
228
|
});
|
|
221
|
-
(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} `)}`);
|
|
222
230
|
}
|
|
223
231
|
/**
|
|
224
232
|
* Render a box with content
|
package/dist/core/terminal.d.ts
CHANGED
|
@@ -11,6 +11,19 @@ export interface TerminalState {
|
|
|
11
11
|
isRawMode: boolean;
|
|
12
12
|
useAltScreen: boolean;
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Remove ANSI escape sequences from a string.
|
|
16
|
+
* This is required when calculating the visible width in terminal cells.
|
|
17
|
+
*/
|
|
18
|
+
export declare function stripAnsi(text: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Calculate the visible width of a string in terminal cells.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getDisplayWidth(text: string): number;
|
|
23
|
+
/**
|
|
24
|
+
* Count how many visual rows the text occupies after terminal wrapping.
|
|
25
|
+
*/
|
|
26
|
+
export declare function countVisualLines(text: string, terminalWidth?: number): number;
|
|
14
27
|
/**
|
|
15
28
|
* Initialize terminal for interactive mode
|
|
16
29
|
* @param useAltScreen - Whether to use alternate screen buffer (prevents scroll issues)
|