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.
Files changed (78) hide show
  1. package/dist/api.d.ts +23 -5
  2. package/dist/api.js +16 -4
  3. package/dist/component-factories.d.ts +59 -0
  4. package/dist/component-factories.js +141 -0
  5. package/dist/components/display/header-v2.d.ts +13 -0
  6. package/dist/components/display/header-v2.js +43 -0
  7. package/dist/components/display/header.d.ts +40 -0
  8. package/dist/components/display/header.js +331 -18
  9. package/dist/components/display/headers.d.ts +1 -0
  10. package/dist/components/display/headers.js +15 -5
  11. package/dist/components/display/hints-v2.d.ts +10 -0
  12. package/dist/components/display/hints-v2.js +34 -0
  13. package/dist/components/display/hints.d.ts +56 -0
  14. package/dist/components/display/hints.js +81 -0
  15. package/dist/components/display/index.d.ts +4 -1
  16. package/dist/components/display/index.js +17 -1
  17. package/dist/components/display/input-prompt.d.ts +35 -0
  18. package/dist/components/display/input-prompt.js +36 -0
  19. package/dist/components/display/list.d.ts +49 -0
  20. package/dist/components/display/list.js +86 -0
  21. package/dist/components/display/messages.js +5 -5
  22. package/dist/components/display/progress.d.ts +17 -0
  23. package/dist/components/display/progress.js +18 -0
  24. package/dist/components/display/summary.js +72 -10
  25. package/dist/components/display/table.d.ts +44 -0
  26. package/dist/components/display/table.js +108 -0
  27. package/dist/components/inputs/language-input.js +8 -5
  28. package/dist/components/inputs/number-input.js +19 -14
  29. package/dist/components/inputs/text-input.js +50 -13
  30. package/dist/components/menus/boolean-menu.js +34 -20
  31. package/dist/components/menus/checkbox-menu.d.ts +2 -1
  32. package/dist/components/menus/checkbox-menu.js +35 -61
  33. package/dist/components/menus/checkbox-table-menu.d.ts +12 -0
  34. package/dist/components/menus/checkbox-table-menu.js +398 -0
  35. package/dist/components/menus/index.d.ts +1 -0
  36. package/dist/components/menus/index.js +3 -1
  37. package/dist/components/menus/radio-menu-split.d.ts +34 -0
  38. package/dist/components/menus/radio-menu-split.js +258 -0
  39. package/dist/components/menus/radio-menu-v2.d.ts +11 -0
  40. package/dist/components/menus/radio-menu-v2.js +150 -0
  41. package/dist/components/menus/radio-menu.d.ts +2 -1
  42. package/dist/components/menus/radio-menu.js +100 -134
  43. package/dist/components.js +3 -3
  44. package/dist/config/index.d.ts +5 -0
  45. package/dist/config/index.js +21 -0
  46. package/dist/config/language-config.d.ts +73 -0
  47. package/dist/config/language-config.js +157 -0
  48. package/dist/config/user-config.d.ts +83 -0
  49. package/dist/config/user-config.js +185 -0
  50. package/dist/core/colors.d.ts +24 -18
  51. package/dist/core/colors.js +74 -7
  52. package/dist/core/hint-manager.d.ts +29 -0
  53. package/dist/core/hint-manager.js +65 -0
  54. package/dist/core/renderer.d.ts +2 -1
  55. package/dist/core/renderer.js +46 -22
  56. package/dist/core/screen-manager.d.ts +54 -0
  57. package/dist/core/screen-manager.js +119 -0
  58. package/dist/core/state-manager.d.ts +27 -0
  59. package/dist/core/state-manager.js +56 -0
  60. package/dist/core/terminal.d.ts +17 -1
  61. package/dist/core/terminal.js +124 -4
  62. package/dist/core/virtual-scroll.d.ts +65 -0
  63. package/dist/core/virtual-scroll.js +120 -0
  64. package/dist/features/commands.js +23 -22
  65. package/dist/i18n/languages/en.js +4 -1
  66. package/dist/i18n/languages/zh.js +4 -1
  67. package/dist/i18n/registry.d.ts +4 -3
  68. package/dist/i18n/registry.js +12 -4
  69. package/dist/i18n/types.d.ts +3 -0
  70. package/dist/index.d.ts +7 -4
  71. package/dist/index.js +49 -4
  72. package/dist/layout.d.ts +67 -0
  73. package/dist/layout.js +86 -0
  74. package/dist/page-layout.d.ts +123 -0
  75. package/dist/page-layout.js +195 -0
  76. package/dist/types/input.types.d.ts +8 -0
  77. package/dist/types/menu.types.d.ts +61 -5
  78. package/package.json +4 -1
@@ -3,45 +3,358 @@
3
3
  * Header component for CLI applications
4
4
  * Displays ASCII art, title, description, version and URL
5
5
  */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
6
9
  Object.defineProperty(exports, "__esModule", { value: true });
7
10
  exports.renderHeader = renderHeader;
8
11
  const colors_js_1 = require("../../core/colors.js");
9
12
  const terminal_js_1 = require("../../core/terminal.js");
13
+ const figlet_1 = __importDefault(require("figlet"));
14
+ function visibleLength(value) {
15
+ return value.replace(/\x1b\[[0-9;]*m/g, '').length;
16
+ }
17
+ function padToVisibleWidth(value, width) {
18
+ const current = visibleLength(value);
19
+ if (current >= width) {
20
+ return value;
21
+ }
22
+ return value + ' '.repeat(width - current);
23
+ }
24
+ function parseBackgroundAnsiToRgb(value) {
25
+ const trueColor = /^\x1b\[48;2;(\d{1,3});(\d{1,3});(\d{1,3})m$/.exec(value);
26
+ if (trueColor) {
27
+ return {
28
+ r: Math.max(0, Math.min(255, Number.parseInt(trueColor[1], 10))),
29
+ g: Math.max(0, Math.min(255, Number.parseInt(trueColor[2], 10))),
30
+ b: Math.max(0, Math.min(255, Number.parseInt(trueColor[3], 10)))
31
+ };
32
+ }
33
+ const ansi256 = /^\x1b\[48;5;(\d{1,3})m$/.exec(value);
34
+ if (ansi256) {
35
+ const code = Math.max(0, Math.min(255, Number.parseInt(ansi256[1], 10)));
36
+ if (code >= 16 && code <= 231) {
37
+ const n = code - 16;
38
+ const r = Math.floor(n / 36);
39
+ const g = Math.floor((n % 36) / 6);
40
+ const b = n % 6;
41
+ const steps = [0, 95, 135, 175, 215, 255];
42
+ return { r: steps[r], g: steps[g], b: steps[b] };
43
+ }
44
+ if (code >= 232) {
45
+ const gray = 8 + (code - 232) * 10;
46
+ return { r: gray, g: gray, b: gray };
47
+ }
48
+ const basicMap = [
49
+ { r: 0, g: 0, b: 0 },
50
+ { r: 170, g: 0, b: 0 },
51
+ { r: 0, g: 170, b: 0 },
52
+ { r: 170, g: 85, b: 0 },
53
+ { r: 0, g: 0, b: 170 },
54
+ { r: 170, g: 0, b: 170 },
55
+ { r: 0, g: 170, b: 170 },
56
+ { r: 170, g: 170, b: 170 },
57
+ { r: 85, g: 85, b: 85 },
58
+ { r: 255, g: 85, b: 85 },
59
+ { r: 85, g: 255, b: 85 },
60
+ { r: 255, g: 255, b: 85 },
61
+ { r: 85, g: 85, b: 255 },
62
+ { r: 255, g: 85, b: 255 },
63
+ { r: 85, g: 255, b: 255 },
64
+ { r: 255, g: 255, b: 255 }
65
+ ];
66
+ return basicMap[code] ?? null;
67
+ }
68
+ return null;
69
+ }
70
+ function isTrueColorBackground(value) {
71
+ return /^\x1b\[48;2;\d{1,3};\d{1,3};\d{1,3}m$/.test(value);
72
+ }
73
+ function supportsTrueColorTerminal() {
74
+ const colorterm = (process.env.COLORTERM ?? '').toLowerCase();
75
+ if (colorterm.includes('truecolor') || colorterm.includes('24bit')) {
76
+ return true;
77
+ }
78
+ const term = (process.env.TERM ?? '').toLowerCase();
79
+ if (term.includes('direct')) {
80
+ return true;
81
+ }
82
+ const program = (process.env.TERM_PROGRAM ?? '').toLowerCase();
83
+ if (program.includes('ghostty') || program.includes('wezterm') || program.includes('iterm') || program.includes('vscode')) {
84
+ return true;
85
+ }
86
+ return false;
87
+ }
88
+ function applyBackgroundGradient(content, startColor, endColor) {
89
+ // Compatibility fallback:
90
+ // only use per-character background gradients on truecolor terminals.
91
+ if (!isTrueColorBackground(startColor) || !isTrueColorBackground(endColor) || !supportsTrueColorTerminal()) {
92
+ return `${startColor}${content}${colors_js_1.colors.reset}`;
93
+ }
94
+ const start = parseBackgroundAnsiToRgb(startColor);
95
+ const end = parseBackgroundAnsiToRgb(endColor);
96
+ if (!start || !end) {
97
+ return `${startColor}${content}${colors_js_1.colors.reset}`;
98
+ }
99
+ const total = Math.max(1, visibleLength(content));
100
+ let out = '';
101
+ let visibleIndex = 0;
102
+ for (let i = 0; i < content.length; i += 1) {
103
+ const ch = content[i] ?? '';
104
+ if (ch === '\x1b') {
105
+ const endIdx = content.indexOf('m', i);
106
+ if (endIdx >= 0) {
107
+ out += content.slice(i, endIdx + 1);
108
+ i = endIdx;
109
+ continue;
110
+ }
111
+ }
112
+ const t = total <= 1 ? 0 : visibleIndex / (total - 1);
113
+ const r = Math.round(start.r + (end.r - start.r) * t);
114
+ const g = Math.round(start.g + (end.g - start.g) * t);
115
+ const b = Math.round(start.b + (end.b - start.b) * t);
116
+ out += `\x1b[48;2;${String(r)};${String(g)};${String(b)}m${ch}`;
117
+ visibleIndex += 1;
118
+ }
119
+ return `${out}${colors_js_1.colors.reset}`;
120
+ }
121
+ const figletCache = new Map();
122
+ function inkCount(line) {
123
+ let count = 0;
124
+ for (const ch of line) {
125
+ if (ch !== ' ' && ch !== '\t') {
126
+ count += 1;
127
+ }
128
+ }
129
+ return count;
130
+ }
131
+ function trimFigletTailNoise(lines) {
132
+ const out = [...lines];
133
+ while (out.length > 1) {
134
+ const last = out[out.length - 1] ?? '';
135
+ const prev = out[out.length - 2] ?? '';
136
+ const lastInk = inkCount(last);
137
+ const prevInk = inkCount(prev);
138
+ // Remove very small dangling tail rows (common in Bloody-like fonts).
139
+ if (lastInk <= 1 && prevInk >= 4) {
140
+ out.pop();
141
+ continue;
142
+ }
143
+ break;
144
+ }
145
+ return out;
146
+ }
147
+ function resolveFigletFont(font, size = 'medium') {
148
+ if (font && font.trim().length > 0) {
149
+ return font;
150
+ }
151
+ if (size === 'small') {
152
+ return 'Small';
153
+ }
154
+ if (size === 'large') {
155
+ return 'Big';
156
+ }
157
+ return 'Standard';
158
+ }
159
+ function resolveFigletLines(text, font) {
160
+ const cacheKey = `${font}\u0000${text}`;
161
+ const cached = figletCache.get(cacheKey);
162
+ if (cached) {
163
+ return cached;
164
+ }
165
+ try {
166
+ const rendered = figlet_1.default.textSync(text, { font });
167
+ const lines = rendered.split('\n');
168
+ while (lines.length > 0 && lines[lines.length - 1].trim().length === 0) {
169
+ lines.pop();
170
+ }
171
+ const cleaned = trimFigletTailNoise(lines);
172
+ figletCache.set(cacheKey, cleaned);
173
+ return cleaned;
174
+ }
175
+ catch {
176
+ const fallback = figlet_1.default.textSync(text, { font: 'Standard' }).split('\n');
177
+ while (fallback.length > 0 && fallback[fallback.length - 1].trim().length === 0) {
178
+ fallback.pop();
179
+ }
180
+ const cleanedFallback = trimFigletTailNoise(fallback);
181
+ figletCache.set(cacheKey, cleanedFallback);
182
+ return cleanedFallback;
183
+ }
184
+ }
185
+ function scaleLineX(line, outCols) {
186
+ const srcCols = line.length;
187
+ if (srcCols === 0 || outCols <= 0) {
188
+ return '';
189
+ }
190
+ if (outCols === srcCols) {
191
+ return line;
192
+ }
193
+ let scaled = '';
194
+ for (let c = 0; c < outCols; c += 1) {
195
+ if (outCols === 1 || srcCols === 1) {
196
+ scaled += line[0] ?? ' ';
197
+ continue;
198
+ }
199
+ const pos = (c * (srcCols - 1)) / (outCols - 1);
200
+ const srcCol = Math.max(0, Math.min(srcCols - 1, Math.round(pos)));
201
+ scaled += line[srcCol] ?? ' ';
202
+ }
203
+ return scaled;
204
+ }
205
+ function scaleAsciiLines(lines, scaleX, scaleY) {
206
+ const sx = Number.isFinite(scaleX) ? Math.max(0.4, Math.min(4, scaleX)) : 1;
207
+ const sy = Number.isFinite(scaleY) ? Math.max(0.4, Math.min(4, scaleY)) : sx;
208
+ if (Math.abs(sx - 1) < 0.001 && Math.abs(sy - 1) < 0.001) {
209
+ return lines;
210
+ }
211
+ const srcRows = lines.length;
212
+ if (srcRows === 0) {
213
+ return lines;
214
+ }
215
+ const outRows = Math.max(1, Math.round(srcRows * sy));
216
+ const out = [];
217
+ const sampleIndex = (outIndex, outCount, srcCount) => {
218
+ if (srcCount <= 1 || outCount <= 1) {
219
+ return 0;
220
+ }
221
+ const ratio = outIndex / (outCount - 1);
222
+ return Math.max(0, Math.min(srcCount - 1, Math.round(ratio * (srcCount - 1))));
223
+ };
224
+ for (let r = 0; r < outRows; r += 1) {
225
+ const srcRow = sampleIndex(r, outRows, srcRows);
226
+ const srcLine = lines[srcRow] ?? '';
227
+ const outCols = Math.max(1, Math.round(srcLine.length * sx));
228
+ out.push(scaleLineX(srcLine, outCols).replace(/\s+$/g, ''));
229
+ }
230
+ return out;
231
+ }
232
+ function resolveFigletScale(scale, _explicitFont, _size) {
233
+ if (typeof scale === 'number' && Number.isFinite(scale)) {
234
+ return Math.max(0.4, Math.min(4, scale));
235
+ }
236
+ return 1;
237
+ }
238
+ function resolveFigletScaleY(scaleY, scaleX, explicitFont) {
239
+ if (typeof scaleY === 'number' && Number.isFinite(scaleY)) {
240
+ return Math.max(0.4, Math.min(4, scaleY));
241
+ }
242
+ const normalizedFont = (explicitFont || '').trim().toLowerCase();
243
+ // Keep Pagga crisp: no default Y stretch (its native height is 3 rows).
244
+ if (normalizedFont === 'pagga' && scaleX > 1) {
245
+ return 1;
246
+ }
247
+ return scaleX;
248
+ }
10
249
  /**
11
250
  * Render a boxed header with ASCII art, title, and description
12
251
  * @param config - Header configuration
13
252
  */
14
253
  function renderHeader(config) {
15
- const { asciiArt = [], title = '', description = '', version, url, menuTitle, boxWidth = 60, color = colors_js_1.uiColors.border } = config;
254
+ const { asciiArt = [], figletText, figletFont, figletSize = 'medium', figletScale, figletScaleY, title = '', titleColor, titleGradientStart, titleGradientEnd, description = '', descriptionColor, descriptionGradientStart, descriptionGradientEnd, version, url, menuTitle, boxWidth = 60, showBoxBorder = true, fillBox = false, fillBoxColor = colors_js_1.colors.bgBlack, fillBoxGradientStart, fillBoxGradientEnd, color = colors_js_1.uiColors.border, asciiArtColor, asciiArtGradientStart, asciiArtGradientEnd } = config;
255
+ const resolvedFigletFont = resolveFigletFont(figletFont, figletSize);
256
+ const effectiveFigletScale = resolveFigletScale(figletScale, figletFont, figletSize);
257
+ const effectiveScaleY = resolveFigletScaleY(figletScaleY, effectiveFigletScale, resolvedFigletFont);
258
+ const resolvedAsciiArt = figletText
259
+ ? scaleAsciiLines(resolveFigletLines(figletText, resolvedFigletFont), effectiveFigletScale, effectiveScaleY)
260
+ : asciiArt;
261
+ const requestedInnerWidth = Math.max(10, boxWidth - 2);
262
+ const contentLengths = [];
263
+ for (const line of resolvedAsciiArt) {
264
+ contentLengths.push(visibleLength(` ${line}`));
265
+ }
266
+ if (title) {
267
+ contentLengths.push(visibleLength(` ${title}`));
268
+ }
269
+ if (description) {
270
+ contentLengths.push(visibleLength(` ${description}`));
271
+ }
272
+ const innerWidth = Math.max(requestedInnerWidth, ...contentLengths, 10);
16
273
  const boldColor = `${color}${colors_js_1.colors.bold}`;
274
+ const applyBoxFill = (content) => {
275
+ if (!fillBox) {
276
+ return content;
277
+ }
278
+ if (fillBoxGradientStart && fillBoxGradientEnd) {
279
+ return applyBackgroundGradient(content, fillBoxGradientStart, fillBoxGradientEnd);
280
+ }
281
+ const replayed = content.replace(/\x1b\[0m/g, `${colors_js_1.colors.reset}${fillBoxColor}`);
282
+ return `${fillBoxColor}${replayed}${colors_js_1.colors.reset}`;
283
+ };
284
+ const writeSpacer = () => {
285
+ if (showBoxBorder) {
286
+ const spacerContent = fillBox ? applyBoxFill(' '.repeat(innerWidth)) : ' '.repeat(innerWidth);
287
+ (0, terminal_js_1.writeLine)(`${boldColor}║${spacerContent}${boldColor}║${colors_js_1.colors.reset}`);
288
+ }
289
+ else if (fillBox) {
290
+ (0, terminal_js_1.writeLine)(` ${applyBoxFill(' '.repeat(innerWidth))}`);
291
+ }
292
+ else {
293
+ (0, terminal_js_1.writeLine)('');
294
+ }
295
+ };
296
+ const writeContentLine = (content, tint) => {
297
+ const normalized = showBoxBorder || fillBox ? padToVisibleWidth(content, innerWidth) : content;
298
+ if (showBoxBorder) {
299
+ const inner = tint ? `${tint}${normalized}${colors_js_1.colors.reset}` : `${colors_js_1.colors.reset}${normalized}`;
300
+ const body = fillBox ? applyBoxFill(inner) : inner;
301
+ if (tint) {
302
+ (0, terminal_js_1.writeLine)(`${boldColor}║${body}${boldColor}║${colors_js_1.colors.reset}`);
303
+ }
304
+ else {
305
+ (0, terminal_js_1.writeLine)(`${boldColor}║${body}${boldColor}║${colors_js_1.colors.reset}`);
306
+ }
307
+ return;
308
+ }
309
+ const plainLine = tint ? `${tint}${normalized}${colors_js_1.colors.reset}` : normalized;
310
+ if (fillBox) {
311
+ (0, terminal_js_1.writeLine)(` ${applyBoxFill(plainLine)}`);
312
+ return;
313
+ }
314
+ (0, terminal_js_1.writeLine)(plainLine);
315
+ };
17
316
  // Top border
18
317
  (0, terminal_js_1.writeLine)('');
19
- (0, terminal_js_1.writeLine)(`${boldColor}╔${'═'.repeat(boxWidth - 2)}╗${colors_js_1.colors.reset}`);
20
- // Empty line
21
- (0, terminal_js_1.writeLine)(`${boldColor}║${' '.repeat(boxWidth - 2)}║${colors_js_1.colors.reset}`);
318
+ if (showBoxBorder) {
319
+ (0, terminal_js_1.writeLine)(`${boldColor}╔${'═'.repeat(innerWidth)}╗${colors_js_1.colors.reset}`);
320
+ }
321
+ writeSpacer();
22
322
  // ASCII art (left-aligned with 2 spaces padding)
23
- if (asciiArt.length > 0) {
24
- asciiArt.forEach(line => {
25
- const paddedLine = ` ${line}`.padEnd(boxWidth - 2, ' ');
26
- (0, terminal_js_1.writeLine)(`${boldColor}║${paddedLine}║${colors_js_1.colors.reset}`);
323
+ if (resolvedAsciiArt.length > 0) {
324
+ resolvedAsciiArt.forEach(line => {
325
+ const paddedLine = showBoxBorder ? ` ${line}`.padEnd(innerWidth, ' ') : ` ${line}`;
326
+ const artLine = asciiArtGradientStart && asciiArtGradientEnd
327
+ ? `${(0, colors_js_1.applyGradient)(paddedLine, asciiArtGradientStart, asciiArtGradientEnd)}`
328
+ : `${(asciiArtColor || color)}${paddedLine}${colors_js_1.colors.reset}`;
329
+ writeContentLine(artLine);
27
330
  });
28
- (0, terminal_js_1.writeLine)(`${boldColor}║${' '.repeat(boxWidth - 2)}║${colors_js_1.colors.reset}`);
331
+ writeSpacer();
29
332
  }
30
- // Title (left-aligned with 2 spaces padding, black text)
333
+ // Title (left-aligned with 2 spaces padding)
31
334
  if (title) {
32
- const paddedTitle = ` ${title}`.padEnd(boxWidth - 2, ' ');
33
- (0, terminal_js_1.writeLine)(`${boldColor}║${colors_js_1.colors.reset}${paddedTitle}${boldColor}║${colors_js_1.colors.reset}`);
34
- (0, terminal_js_1.writeLine)(`${boldColor}║${' '.repeat(boxWidth - 2)}║${colors_js_1.colors.reset}`);
335
+ const paddedTitle = showBoxBorder ? ` ${title}`.padEnd(innerWidth, ' ') : ` ${title}`;
336
+ const titleLine = titleGradientStart && titleGradientEnd
337
+ ? (0, colors_js_1.applyGradient)(paddedTitle, titleGradientStart, titleGradientEnd)
338
+ : paddedTitle;
339
+ writeContentLine(titleLine, titleGradientStart && titleGradientEnd ? undefined : titleColor);
340
+ writeSpacer();
35
341
  }
36
- // Description (left-aligned with 2 spaces padding, gray text)
342
+ // Description (left-aligned with 2 spaces padding)
37
343
  if (description) {
38
344
  const textContent = ` ${description}`;
39
- const paddedText = textContent.padEnd(boxWidth - 2, ' ');
40
- (0, terminal_js_1.writeLine)(`${boldColor}║${colors_js_1.uiColors.textSecondary}${paddedText}${colors_js_1.colors.reset}${boldColor}║${colors_js_1.colors.reset}`);
41
- (0, terminal_js_1.writeLine)(`${boldColor}║${' '.repeat(boxWidth - 2)}║${colors_js_1.colors.reset}`);
345
+ const paddedText = showBoxBorder ? textContent.padEnd(innerWidth, ' ') : textContent;
346
+ const descLine = descriptionGradientStart && descriptionGradientEnd
347
+ ? (0, colors_js_1.applyGradient)(paddedText, descriptionGradientStart, descriptionGradientEnd)
348
+ : paddedText;
349
+ writeContentLine(descLine, descriptionGradientStart && descriptionGradientEnd
350
+ ? undefined
351
+ : (descriptionColor || colors_js_1.uiColors.textSecondary));
352
+ writeSpacer();
42
353
  }
43
354
  // Bottom border
44
- (0, terminal_js_1.writeLine)(`${boldColor}╚${'═'.repeat(boxWidth - 2)}╝${colors_js_1.colors.reset}`);
355
+ if (showBoxBorder) {
356
+ (0, terminal_js_1.writeLine)(`${boldColor}╚${'═'.repeat(innerWidth)}╝${colors_js_1.colors.reset}`);
357
+ }
45
358
  // Blank line after box
46
359
  (0, terminal_js_1.writeLine)('');
47
360
  // Version and URL (outside the box, with colors)
@@ -10,6 +10,7 @@ import { AsciiHeaderConfig } from '../../types/display.types.js';
10
10
  * @param color - Optional color (default: cyan)
11
11
  */
12
12
  export declare function renderSimpleHeader(text: string, color?: string): void;
13
+ export declare function renderSimpleHeaderWithSpacing(text: string, color?: string, spacingAfter?: number): void;
13
14
  /**
14
15
  * Render a section header with double-line borders
15
16
  * Format:
@@ -5,6 +5,7 @@
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.renderSimpleHeader = renderSimpleHeader;
8
+ exports.renderSimpleHeaderWithSpacing = renderSimpleHeaderWithSpacing;
8
9
  exports.renderSectionHeader = renderSectionHeader;
9
10
  exports.renderAsciiHeader = renderAsciiHeader;
10
11
  exports.createSimpleHeader = createSimpleHeader;
@@ -21,10 +22,19 @@ const terminal_js_2 = require("../../core/terminal.js");
21
22
  */
22
23
  function renderSimpleHeader(text, color) {
23
24
  const headerColor = color || colors_js_1.uiColors.primary;
24
- const line = `=== ${text} ===`;
25
+ const line = ` === ${text} ===`;
25
26
  (0, terminal_js_1.writeLine)(`${headerColor}${line}${colors_js_1.colors.reset}`);
26
27
  (0, terminal_js_1.writeLine)('');
27
28
  }
29
+ function renderSimpleHeaderWithSpacing(text, color, spacingAfter = 1) {
30
+ const headerColor = color || colors_js_1.uiColors.primary;
31
+ const line = ` === ${text} ===`;
32
+ (0, terminal_js_1.writeLine)(`${headerColor}${line}${colors_js_1.colors.reset}`);
33
+ const spacerLines = Math.max(0, Math.floor(spacingAfter));
34
+ for (let i = 0; i < spacerLines; i += 1) {
35
+ (0, terminal_js_1.writeLine)('');
36
+ }
37
+ }
28
38
  /**
29
39
  * Render a section header with double-line borders
30
40
  * Format:
@@ -53,22 +63,22 @@ function renderAsciiHeader(config) {
53
63
  const termWidth = (0, terminal_js_2.getTerminalWidth)();
54
64
  const border = borderChar.repeat(termWidth);
55
65
  // Top border
56
- (0, terminal_js_1.writeLine)(colors_js_1.colors.cyan + border + colors_js_1.colors.reset);
66
+ (0, terminal_js_1.writeLine)(colors_js_1.uiColors.border + border + colors_js_1.colors.reset);
57
67
  (0, terminal_js_1.writeLine)('');
58
68
  // ASCII art (centered)
59
69
  const artLines = asciiArt.split('\n');
60
70
  artLines.forEach(line => {
61
- (0, terminal_js_1.writeLine)(colors_js_1.colors.cyan + line + colors_js_1.colors.reset);
71
+ (0, terminal_js_1.writeLine)(colors_js_1.uiColors.primary + line + colors_js_1.colors.reset);
62
72
  });
63
73
  // Subtitle if provided
64
74
  if (subtitle) {
65
75
  (0, terminal_js_1.writeLine)('');
66
76
  const padding = Math.floor((termWidth - subtitle.length) / 2);
67
- (0, terminal_js_1.writeLine)(' '.repeat(padding) + colors_js_1.colors.brightCyan + subtitle + colors_js_1.colors.reset);
77
+ (0, terminal_js_1.writeLine)(' '.repeat(padding) + colors_js_1.uiColors.accent + subtitle + colors_js_1.colors.reset);
68
78
  }
69
79
  (0, terminal_js_1.writeLine)('');
70
80
  // Bottom border
71
- (0, terminal_js_1.writeLine)(colors_js_1.colors.cyan + border + colors_js_1.colors.reset);
81
+ (0, terminal_js_1.writeLine)(colors_js_1.uiColors.border + border + colors_js_1.colors.reset);
72
82
  // Footer info (version and URL)
73
83
  if (version || url) {
74
84
  const footerParts = [];
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Hints Component - New Architecture Version
3
+ * Returns string arrays and listens to HintManager
4
+ */
5
+ import { Component } from '../../layout.js';
6
+ export declare function createHintsComponentV2(hints: string[]): Component;
7
+ /**
8
+ * Create a dynamic hints component that listens to HintManager
9
+ */
10
+ export declare function createDynamicHintsComponent(): Component;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ /**
3
+ * Hints Component - New Architecture Version
4
+ * Returns string arrays and listens to HintManager
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.createHintsComponentV2 = createHintsComponentV2;
8
+ exports.createDynamicHintsComponent = createDynamicHintsComponent;
9
+ const layout_js_1 = require("../../layout.js");
10
+ const colors_js_1 = require("../../core/colors.js");
11
+ function createHintsComponentV2(hints) {
12
+ return {
13
+ type: 'hints',
14
+ regionId: 'footerHints',
15
+ render: (rect) => {
16
+ // Join hints with separator
17
+ const hintsText = hints.join(' • ');
18
+ return [`${colors_js_1.colors.dim}${hintsText}${colors_js_1.colors.reset}`];
19
+ }
20
+ };
21
+ }
22
+ /**
23
+ * Create a dynamic hints component that listens to HintManager
24
+ */
25
+ function createDynamicHintsComponent() {
26
+ return {
27
+ type: 'hints',
28
+ regionId: 'footerHints',
29
+ render: (rect) => {
30
+ const currentHint = layout_js_1.hintManager.current();
31
+ return [currentHint ? `${colors_js_1.colors.dim}${currentHint}${colors_js_1.colors.reset}` : ''];
32
+ }
33
+ };
34
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Hints Component
3
+ * Displays operation hints at the bottom of the page
4
+ */
5
+ /**
6
+ * Hints configuration
7
+ */
8
+ export interface HintsConfig {
9
+ hints: string[];
10
+ }
11
+ /**
12
+ * Standard hint types
13
+ */
14
+ export declare const HintTypes: {
15
+ /** Arrow keys navigation */
16
+ readonly ARROWS: () => string;
17
+ /** Number keys selection */
18
+ readonly NUMBERS: () => string;
19
+ /** Letter keys selection */
20
+ readonly LETTERS: () => string;
21
+ /** Space key toggle */
22
+ readonly SPACE: () => string;
23
+ /** Enter key confirm */
24
+ readonly ENTER: () => string;
25
+ /** Escape key cancel */
26
+ readonly ESC: () => string;
27
+ /** Select all */
28
+ readonly SELECT_ALL: () => string;
29
+ /** Invert selection */
30
+ readonly INVERT: () => string;
31
+ };
32
+ /**
33
+ * Generate hints for menu interactions
34
+ */
35
+ export declare function generateMenuHints(options: {
36
+ hasMultipleOptions?: boolean;
37
+ allowNumberKeys?: boolean;
38
+ allowLetterKeys?: boolean;
39
+ allowSelectAll?: boolean;
40
+ allowInvert?: boolean;
41
+ }): string[];
42
+ /**
43
+ * Generate hints for input interactions
44
+ */
45
+ export declare function generateInputHints(): string[];
46
+ /**
47
+ * Render hints component
48
+ * @param config - Hints configuration
49
+ */
50
+ export declare function renderHintsComponent(config: HintsConfig): void;
51
+ /**
52
+ * Create hints component (factory function)
53
+ * @param hints - Array of hint strings
54
+ * @returns Hints configuration
55
+ */
56
+ export declare function createHints(hints: string[]): HintsConfig;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ /**
3
+ * Hints Component
4
+ * Displays operation hints at the bottom of the page
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.HintTypes = void 0;
8
+ exports.generateMenuHints = generateMenuHints;
9
+ exports.generateInputHints = generateInputHints;
10
+ exports.renderHintsComponent = renderHintsComponent;
11
+ exports.createHints = createHints;
12
+ const renderer_js_1 = require("../../core/renderer.js");
13
+ const registry_js_1 = require("../../i18n/registry.js");
14
+ /**
15
+ * Standard hint types
16
+ */
17
+ exports.HintTypes = {
18
+ /** Arrow keys navigation */
19
+ ARROWS: () => (0, registry_js_1.t)('hints.arrows'),
20
+ /** Number keys selection */
21
+ NUMBERS: () => (0, registry_js_1.t)('hints.numbers'),
22
+ /** Letter keys selection */
23
+ LETTERS: () => (0, registry_js_1.t)('hints.letters'),
24
+ /** Space key toggle */
25
+ SPACE: () => (0, registry_js_1.t)('hints.space'),
26
+ /** Enter key confirm */
27
+ ENTER: () => (0, registry_js_1.t)('hints.enter'),
28
+ /** Escape key cancel */
29
+ ESC: () => 'Esc Cancel',
30
+ /** Select all */
31
+ SELECT_ALL: () => (0, registry_js_1.t)('hints.selectAll'),
32
+ /** Invert selection */
33
+ INVERT: () => (0, registry_js_1.t)('hints.invert')
34
+ };
35
+ /**
36
+ * Generate hints for menu interactions
37
+ */
38
+ function generateMenuHints(options) {
39
+ const hints = [];
40
+ if (options.hasMultipleOptions) {
41
+ hints.push(exports.HintTypes.ARROWS());
42
+ }
43
+ if (options.allowNumberKeys) {
44
+ hints.push(exports.HintTypes.NUMBERS());
45
+ }
46
+ if (options.allowLetterKeys) {
47
+ hints.push(exports.HintTypes.LETTERS());
48
+ }
49
+ if (options.allowSelectAll) {
50
+ hints.push(exports.HintTypes.SELECT_ALL());
51
+ }
52
+ if (options.allowInvert) {
53
+ hints.push(exports.HintTypes.INVERT());
54
+ }
55
+ hints.push(exports.HintTypes.ENTER());
56
+ return hints;
57
+ }
58
+ /**
59
+ * Generate hints for input interactions
60
+ */
61
+ function generateInputHints() {
62
+ return [exports.HintTypes.ENTER(), exports.HintTypes.ESC()];
63
+ }
64
+ /**
65
+ * Render hints component
66
+ * @param config - Hints configuration
67
+ */
68
+ function renderHintsComponent(config) {
69
+ if (!config.hints || config.hints.length === 0) {
70
+ return;
71
+ }
72
+ (0, renderer_js_1.renderHints)(config.hints);
73
+ }
74
+ /**
75
+ * Create hints component (factory function)
76
+ * @param hints - Array of hint strings
77
+ * @returns Hints configuration
78
+ */
79
+ function createHints(hints) {
80
+ return { hints };
81
+ }
@@ -3,7 +3,10 @@
3
3
  * Exports all display component functions
4
4
  */
5
5
  export { renderSimpleHeader, renderSectionHeader, renderAsciiHeader, createSimpleHeader, createSectionHeader, createAsciiHeader } from './headers.js';
6
- export { renderProgressIndicator, renderStageHeader, renderStageSeparator, createProgressIndicator, createStageHeader, createStageSeparator } from './progress.js';
6
+ export { renderProgressIndicator, renderStageHeader, renderStageSeparator, createProgressIndicator, createStageHeader, createStageSeparator, renderProgressCheckmark, createProgressCheckmark } from './progress.js';
7
7
  export { renderMessage, showSuccess, showError, showWarning, showInfo, showQuestion, createMessage } from './messages.js';
8
8
  export { renderSummaryTable, createSummaryTable, createSimpleSummary } from './summary.js';
9
9
  export { renderHeader, type HeaderConfig } from './header.js';
10
+ export { renderHintsComponent, createHints, generateMenuHints, generateInputHints, HintTypes, type HintsConfig } from './hints.js';
11
+ export { renderTable, createTable, type TableConfig, type TableColumn } from './table.js';
12
+ export { renderList, createList, createBulletList, createNumberedList, type ListConfig, type ListItem } from './list.js';