cli-menu-kit 0.1.23 → 0.2.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.
Files changed (60) 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/hints-v2.d.ts +10 -0
  8. package/dist/components/display/hints-v2.js +34 -0
  9. package/dist/components/display/hints.d.ts +56 -0
  10. package/dist/components/display/hints.js +81 -0
  11. package/dist/components/display/index.d.ts +3 -0
  12. package/dist/components/display/index.js +15 -1
  13. package/dist/components/display/input-prompt.d.ts +35 -0
  14. package/dist/components/display/input-prompt.js +36 -0
  15. package/dist/components/display/list.d.ts +49 -0
  16. package/dist/components/display/list.js +86 -0
  17. package/dist/components/display/summary.js +119 -15
  18. package/dist/components/display/table.d.ts +42 -0
  19. package/dist/components/display/table.js +107 -0
  20. package/dist/components/menus/boolean-menu.js +2 -1
  21. package/dist/components/menus/checkbox-menu.d.ts +2 -1
  22. package/dist/components/menus/checkbox-menu.js +30 -59
  23. package/dist/components/menus/checkbox-table-menu.d.ts +12 -0
  24. package/dist/components/menus/checkbox-table-menu.js +395 -0
  25. package/dist/components/menus/index.d.ts +1 -0
  26. package/dist/components/menus/index.js +3 -1
  27. package/dist/components/menus/radio-menu-split.d.ts +33 -0
  28. package/dist/components/menus/radio-menu-split.js +248 -0
  29. package/dist/components/menus/radio-menu-v2.d.ts +11 -0
  30. package/dist/components/menus/radio-menu-v2.js +150 -0
  31. package/dist/components/menus/radio-menu.d.ts +2 -1
  32. package/dist/components/menus/radio-menu.js +60 -123
  33. package/dist/core/hint-manager.d.ts +29 -0
  34. package/dist/core/hint-manager.js +65 -0
  35. package/dist/core/renderer.d.ts +2 -1
  36. package/dist/core/renderer.js +22 -6
  37. package/dist/core/screen-manager.d.ts +54 -0
  38. package/dist/core/screen-manager.js +119 -0
  39. package/dist/core/state-manager.d.ts +27 -0
  40. package/dist/core/state-manager.js +56 -0
  41. package/dist/core/terminal.d.ts +4 -1
  42. package/dist/core/terminal.js +37 -4
  43. package/dist/core/virtual-scroll.d.ts +65 -0
  44. package/dist/core/virtual-scroll.js +120 -0
  45. package/dist/i18n/languages/en.js +4 -1
  46. package/dist/i18n/languages/zh.js +4 -1
  47. package/dist/i18n/registry.d.ts +4 -3
  48. package/dist/i18n/registry.js +12 -4
  49. package/dist/i18n/types.d.ts +3 -0
  50. package/dist/index.d.ts +5 -4
  51. package/dist/index.js +30 -4
  52. package/dist/layout.d.ts +68 -0
  53. package/dist/layout.js +134 -0
  54. package/dist/page-layout.d.ts +92 -0
  55. package/dist/page-layout.js +156 -0
  56. package/dist/types/display.types.d.ts +6 -0
  57. package/dist/types/menu.types.d.ts +57 -5
  58. package/package.json +1 -1
  59. package/dist/types/layout.types.d.ts +0 -56
  60. package/dist/types/layout.types.js +0 -36
@@ -0,0 +1,49 @@
1
+ /**
2
+ * List Component
3
+ * Displays items in a list format with optional bullets/numbers
4
+ */
5
+ /**
6
+ * List item configuration
7
+ */
8
+ export interface ListItem {
9
+ /** Item text */
10
+ text: string;
11
+ /** Item indent level (0 = no indent) */
12
+ indent?: number;
13
+ /** Custom bullet/prefix */
14
+ bullet?: string;
15
+ }
16
+ /**
17
+ * List configuration
18
+ */
19
+ export interface ListConfig {
20
+ /** List items */
21
+ items: (string | ListItem)[];
22
+ /** List style */
23
+ style?: 'bullet' | 'number' | 'none';
24
+ /** Custom bullet character (for bullet style) */
25
+ bulletChar?: string;
26
+ /** Indent size in spaces */
27
+ indentSize?: number;
28
+ }
29
+ /**
30
+ * Render list component
31
+ * @param config - List configuration
32
+ */
33
+ export declare function renderList(config: ListConfig): void;
34
+ /**
35
+ * Create list configuration (factory function)
36
+ */
37
+ export declare function createList(items: (string | ListItem)[], options?: {
38
+ style?: 'bullet' | 'number' | 'none';
39
+ bulletChar?: string;
40
+ indentSize?: number;
41
+ }): ListConfig;
42
+ /**
43
+ * Create a simple bullet list
44
+ */
45
+ export declare function createBulletList(items: string[]): ListConfig;
46
+ /**
47
+ * Create a numbered list
48
+ */
49
+ export declare function createNumberedList(items: string[]): ListConfig;
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ /**
3
+ * List Component
4
+ * Displays items in a list format with optional bullets/numbers
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.renderList = renderList;
8
+ exports.createList = createList;
9
+ exports.createBulletList = createBulletList;
10
+ exports.createNumberedList = createNumberedList;
11
+ const terminal_js_1 = require("../../core/terminal.js");
12
+ /**
13
+ * Render list component
14
+ * @param config - List configuration
15
+ */
16
+ function renderList(config) {
17
+ const { items, style = 'bullet', bulletChar = '•', indentSize = 2 } = config;
18
+ if (items.length === 0) {
19
+ return;
20
+ }
21
+ items.forEach((item, index) => {
22
+ let text;
23
+ let indent;
24
+ let bullet;
25
+ // Parse item
26
+ if (typeof item === 'string') {
27
+ text = item;
28
+ indent = 0;
29
+ bullet = undefined;
30
+ }
31
+ else {
32
+ text = item.text;
33
+ indent = item.indent || 0;
34
+ bullet = item.bullet;
35
+ }
36
+ // Generate prefix based on style
37
+ let prefix;
38
+ if (bullet) {
39
+ // Custom bullet
40
+ prefix = bullet;
41
+ }
42
+ else {
43
+ switch (style) {
44
+ case 'number':
45
+ prefix = `${index + 1}.`;
46
+ break;
47
+ case 'bullet':
48
+ prefix = bulletChar;
49
+ break;
50
+ case 'none':
51
+ default:
52
+ prefix = '';
53
+ break;
54
+ }
55
+ }
56
+ // Build line with indent and prefix
57
+ const indentStr = ' '.repeat(indent * indentSize);
58
+ const line = prefix
59
+ ? `${indentStr}${prefix} ${text}`
60
+ : `${indentStr}${text}`;
61
+ (0, terminal_js_1.writeLine)(line);
62
+ });
63
+ }
64
+ /**
65
+ * Create list configuration (factory function)
66
+ */
67
+ function createList(items, options) {
68
+ return {
69
+ items,
70
+ style: options?.style ?? 'bullet',
71
+ bulletChar: options?.bulletChar ?? '•',
72
+ indentSize: options?.indentSize ?? 2
73
+ };
74
+ }
75
+ /**
76
+ * Create a simple bullet list
77
+ */
78
+ function createBulletList(items) {
79
+ return createList(items, { style: 'bullet' });
80
+ }
81
+ /**
82
+ * Create a numbered list
83
+ */
84
+ function createNumberedList(items) {
85
+ return createList(items, { style: 'number' });
86
+ }
@@ -11,7 +11,83 @@ const terminal_js_1 = require("../../core/terminal.js");
11
11
  const colors_js_1 = require("../../core/colors.js");
12
12
  const terminal_js_2 = require("../../core/terminal.js");
13
13
  /**
14
- * Wrap text to fit within a specific width
14
+ * Wrap text to fit within a specific width, preserving ANSI color codes
15
+ */
16
+ function wrapTextWithColors(text, maxWidth) {
17
+ // Extract ANSI codes and plain text
18
+ const ansiRegex = /\x1b\[[0-9;]*m/g;
19
+ const plainText = text.replace(ansiRegex, '');
20
+ // If plain text fits, return as-is
21
+ if (plainText.length <= maxWidth) {
22
+ return [text];
23
+ }
24
+ // Find all ANSI codes and their positions in the original text
25
+ const codes = [];
26
+ let match;
27
+ let offset = 0;
28
+ const textCopy = text;
29
+ while ((match = ansiRegex.exec(textCopy)) !== null) {
30
+ // Calculate position in plain text
31
+ const plainPos = match.index - offset;
32
+ codes.push({ pos: plainPos, code: match[0] });
33
+ offset += match[0].length;
34
+ }
35
+ // Wrap plain text by words
36
+ const words = plainText.split(' ');
37
+ const lines = [];
38
+ let currentLine = '';
39
+ let currentPos = 0;
40
+ for (const word of words) {
41
+ const testLine = currentLine ? `${currentLine} ${word}` : word;
42
+ if (testLine.length <= maxWidth) {
43
+ currentLine = testLine;
44
+ }
45
+ else {
46
+ if (currentLine) {
47
+ lines.push(currentLine);
48
+ currentPos += currentLine.length + 1; // +1 for space
49
+ }
50
+ currentLine = word;
51
+ }
52
+ }
53
+ if (currentLine) {
54
+ lines.push(currentLine);
55
+ }
56
+ // Re-insert ANSI codes into wrapped lines
57
+ const result = [];
58
+ let lineStart = 0;
59
+ let activeColor = '';
60
+ for (const line of lines) {
61
+ const lineEnd = lineStart + line.length;
62
+ let coloredLine = activeColor; // Start with active color from previous line
63
+ // Find codes that apply to this line
64
+ let lastPos = 0;
65
+ for (const { pos, code } of codes) {
66
+ if (pos >= lineStart && pos < lineEnd) {
67
+ const relPos = pos - lineStart;
68
+ coloredLine += line.substring(lastPos, relPos) + code;
69
+ lastPos = relPos;
70
+ // Track active color (reset or new color)
71
+ if (code === '\x1b[0m') {
72
+ activeColor = '';
73
+ }
74
+ else {
75
+ activeColor = code;
76
+ }
77
+ }
78
+ }
79
+ coloredLine += line.substring(lastPos);
80
+ // Add reset at end if there's an active color
81
+ if (activeColor && activeColor !== '\x1b[0m') {
82
+ coloredLine += '\x1b[0m';
83
+ }
84
+ result.push(coloredLine);
85
+ lineStart = lineEnd + 1; // +1 for space between words
86
+ }
87
+ return result;
88
+ }
89
+ /**
90
+ * Wrap text to fit within a specific width (plain text only)
15
91
  */
16
92
  function wrapText(text, maxWidth) {
17
93
  const words = text.split(' ');
@@ -39,7 +115,16 @@ function wrapText(text, maxWidth) {
39
115
  * @param config - Summary table configuration
40
116
  */
41
117
  function renderSummaryTable(config) {
42
- const { title, titleAlign = 'center', sections, width } = config;
118
+ const { title, titleAlign = 'center', sections, width, colors: colorConfig } = config;
119
+ // Default colors
120
+ const defaultColors = {
121
+ title: 'cyan+bold',
122
+ sectionHeader: '', // No color (default/black)
123
+ key: 'cyan',
124
+ value: '' // No color (default/black)
125
+ };
126
+ // Merge with provided colors
127
+ const finalColors = { ...defaultColors, ...colorConfig };
43
128
  const termWidth = (0, terminal_js_2.getTerminalWidth)();
44
129
  // Use full terminal width minus padding, or specified width
45
130
  const boxWidth = width || Math.max(60, termWidth - 4);
@@ -51,55 +136,68 @@ function renderSummaryTable(config) {
51
136
  (0, terminal_js_1.writeLine)(`│${' '.repeat(boxWidth - 2)}│`);
52
137
  // Title if provided
53
138
  if (title) {
139
+ // Parse color configuration (supports "color" or "color+style" format)
140
+ let titleColor = '';
141
+ if (finalColors.title) {
142
+ const parts = finalColors.title.split('+');
143
+ titleColor = parts.map(part => colors_js_1.colors[part.trim()] || '').join('');
144
+ }
145
+ const resetColor = titleColor ? colors_js_1.colors.reset : '';
54
146
  let titleLine;
55
147
  let remainingSpace;
56
148
  if (titleAlign === 'left') {
57
- titleLine = ` ${colors_js_1.colors.cyan}${title}${colors_js_1.colors.reset}`;
149
+ titleLine = ` ${titleColor}${title}${resetColor}`;
58
150
  const plainTitle = title;
59
151
  remainingSpace = boxWidth - plainTitle.length - 4;
60
152
  }
61
153
  else if (titleAlign === 'right') {
62
154
  const plainTitle = title;
63
155
  const rightPadding = contentWidth - plainTitle.length;
64
- titleLine = ' '.repeat(rightPadding + 2) + colors_js_1.colors.cyan + title + colors_js_1.colors.reset;
156
+ titleLine = ' '.repeat(rightPadding + 2) + titleColor + title + resetColor;
65
157
  remainingSpace = 2;
66
158
  }
67
159
  else {
68
160
  // center (default)
69
161
  const titlePadding = Math.floor((contentWidth - title.length) / 2);
70
- titleLine = ' '.repeat(titlePadding + 2) + colors_js_1.colors.cyan + title + colors_js_1.colors.reset;
162
+ titleLine = ' '.repeat(titlePadding + 2) + titleColor + title + resetColor;
71
163
  remainingSpace = boxWidth - titlePadding - title.length - 4;
72
164
  }
73
165
  (0, terminal_js_1.writeLine)(`│${titleLine}${' '.repeat(remainingSpace)}│`);
74
166
  (0, terminal_js_1.writeLine)(`│${' '.repeat(boxWidth - 2)}│`);
75
167
  }
168
+ // Calculate global keyPadding based on longest key across ALL sections
169
+ const allKeys = sections.flatMap(section => section.items.map(item => item.key));
170
+ const maxKeyLength = Math.max(...allKeys.map(key => key.length));
171
+ const keyPadding = maxKeyLength + 3; // +3 for colon and spacing
76
172
  // Sections
77
173
  sections.forEach((section, sectionIndex) => {
78
174
  // Section header if provided
79
175
  if (section.header) {
80
- const headerLine = ` ${section.header}`;
176
+ const headerColor = finalColors.sectionHeader ? colors_js_1.colors[finalColors.sectionHeader] || '' : '';
177
+ const resetColor = headerColor ? colors_js_1.colors.reset : '';
178
+ const headerLine = ` ${headerColor}${section.header}${resetColor}`;
81
179
  const remainingSpace = boxWidth - section.header.length - 4;
82
180
  (0, terminal_js_1.writeLine)(`│${headerLine}${' '.repeat(remainingSpace)}│`);
83
181
  }
84
- // Calculate keyPadding based on longest key in this section
85
- const maxKeyLength = Math.max(...section.items.map(item => item.key.length));
86
- const keyPadding = maxKeyLength + 3; // +3 for colon and spacing
87
- // Section items
182
+ // Section items (using global keyPadding)
88
183
  section.items.forEach(item => {
89
184
  const valueMaxWidth = contentWidth - keyPadding - 2; // 2 for leading spaces
90
185
  // Check if value needs wrapping
91
186
  const plainValue = item.value.replace(/\x1b\[[0-9;]*m/g, '');
92
187
  if (plainValue.length > valueMaxWidth) {
93
- // Wrap the value
94
- const wrappedLines = wrapText(plainValue, valueMaxWidth);
188
+ // Wrap the value (preserving colors if present)
189
+ const wrappedLines = wrapTextWithColors(item.value, valueMaxWidth);
95
190
  // First line with key
96
- const firstLine = ` ${colors_js_1.colors.cyan}${item.key}:${colors_js_1.colors.reset}${' '.repeat(Math.max(1, keyPadding - item.key.length))}${wrappedLines[0]}`;
191
+ const keyColor = finalColors.key ? colors_js_1.colors[finalColors.key] || '' : '';
192
+ const keyResetColor = keyColor ? colors_js_1.colors.reset : '';
193
+ // wrappedLines already contain colors, don't add valueColor
194
+ const firstLine = ` ${keyColor}${item.key}:${keyResetColor}${' '.repeat(Math.max(1, keyPadding - item.key.length))}${wrappedLines[0]}`;
97
195
  const plainFirstLine = firstLine.replace(/\x1b\[[0-9;]*m/g, '');
98
196
  const remainingSpace = boxWidth - plainFirstLine.length - 2;
99
197
  (0, terminal_js_1.writeLine)(`│${firstLine}${' '.repeat(Math.max(0, remainingSpace))}│`);
100
198
  // Subsequent lines with indentation
101
199
  for (let i = 1; i < wrappedLines.length; i++) {
102
- const continuationLine = ` ${' '.repeat(keyPadding)}${wrappedLines[i]}`;
200
+ const continuationLine = ` ${' '.repeat(keyPadding + 1)}${wrappedLines[i]}`;
103
201
  const plainContinuationLine = continuationLine.replace(/\x1b\[[0-9;]*m/g, '');
104
202
  const contRemainingSpace = boxWidth - plainContinuationLine.length - 2;
105
203
  (0, terminal_js_1.writeLine)(`│${continuationLine}${' '.repeat(Math.max(0, contRemainingSpace))}│`);
@@ -107,7 +205,13 @@ function renderSummaryTable(config) {
107
205
  }
108
206
  else {
109
207
  // No wrapping needed
110
- const itemLine = ` ${item.key}:${' '.repeat(Math.max(1, keyPadding - item.key.length))}${item.value}`;
208
+ const keyColor = finalColors.key ? colors_js_1.colors[finalColors.key] || '' : '';
209
+ const keyResetColor = keyColor ? colors_js_1.colors.reset : '';
210
+ const valueColor = finalColors.value ? colors_js_1.colors[finalColors.value] || '' : '';
211
+ const valueResetColor = valueColor ? colors_js_1.colors.reset : '';
212
+ // Only wrap value with color if valueColor is set, otherwise preserve original colors in item.value
213
+ const coloredValue = valueColor ? `${valueColor}${item.value}${valueResetColor}` : item.value;
214
+ const itemLine = ` ${keyColor}${item.key}:${keyResetColor}${' '.repeat(Math.max(1, keyPadding - item.key.length))}${coloredValue}`;
111
215
  const plainItemLine = itemLine.replace(/\x1b\[[0-9;]*m/g, '');
112
216
  const remainingSpace = boxWidth - plainItemLine.length - 2;
113
217
  (0, terminal_js_1.writeLine)(`│${itemLine}${' '.repeat(Math.max(0, remainingSpace))}│`);
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Table Component
3
+ * Displays data in a table format with headers and rows
4
+ */
5
+ /**
6
+ * Table column configuration
7
+ */
8
+ export interface TableColumn {
9
+ /** Column header */
10
+ header: string;
11
+ /** Column key in data object */
12
+ key: string;
13
+ /** Column width (optional, auto-calculated if not provided) */
14
+ width?: number;
15
+ /** Text alignment */
16
+ align?: 'left' | 'center' | 'right';
17
+ }
18
+ /**
19
+ * Table configuration
20
+ */
21
+ export interface TableConfig {
22
+ /** Table columns */
23
+ columns: TableColumn[];
24
+ /** Table data rows */
25
+ data: Record<string, any>[];
26
+ /** Show table borders */
27
+ showBorders?: boolean;
28
+ /** Show header separator */
29
+ showHeaderSeparator?: boolean;
30
+ }
31
+ /**
32
+ * Render table component
33
+ * @param config - Table configuration
34
+ */
35
+ export declare function renderTable(config: TableConfig): void;
36
+ /**
37
+ * Create table configuration (factory function)
38
+ */
39
+ export declare function createTable(columns: TableColumn[], data: Record<string, any>[], options?: {
40
+ showBorders?: boolean;
41
+ showHeaderSeparator?: boolean;
42
+ }): TableConfig;
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ /**
3
+ * Table Component
4
+ * Displays data in a table format with headers and rows
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.renderTable = renderTable;
8
+ exports.createTable = createTable;
9
+ const terminal_js_1 = require("../../core/terminal.js");
10
+ /**
11
+ * Render table component
12
+ * @param config - Table configuration
13
+ */
14
+ function renderTable(config) {
15
+ const { columns, data, showBorders = true, showHeaderSeparator = true } = config;
16
+ if (columns.length === 0 || data.length === 0) {
17
+ return;
18
+ }
19
+ // Calculate column widths
20
+ const columnWidths = columns.map((col, index) => {
21
+ if (col.width)
22
+ return col.width;
23
+ // Auto-calculate width based on header and data
24
+ const headerWidth = col.header.length;
25
+ const dataWidth = Math.max(...data.map(row => String(row[col.key] || '').length));
26
+ return Math.max(headerWidth, dataWidth) + 2; // +2 for padding
27
+ });
28
+ // Render top border
29
+ if (showBorders) {
30
+ const border = columnWidths.map(w => '─'.repeat(w)).join('┬');
31
+ (0, terminal_js_1.writeLine)(`┌${border}┐`);
32
+ }
33
+ // Render header
34
+ const headerCells = columns.map((col, index) => {
35
+ const width = columnWidths[index];
36
+ const align = col.align || 'left';
37
+ return alignText(col.header, width, align);
38
+ });
39
+ if (showBorders) {
40
+ (0, terminal_js_1.writeLine)(`│${headerCells.join('│')}│`);
41
+ }
42
+ else {
43
+ (0, terminal_js_1.writeLine)(headerCells.join(' '));
44
+ }
45
+ // Render header separator
46
+ if (showHeaderSeparator) {
47
+ if (showBorders) {
48
+ const separator = columnWidths.map(w => '─'.repeat(w)).join('┼');
49
+ (0, terminal_js_1.writeLine)(`├${separator}┤`);
50
+ }
51
+ else {
52
+ const separator = columnWidths.map(w => '─'.repeat(w)).join(' ');
53
+ (0, terminal_js_1.writeLine)(separator);
54
+ }
55
+ }
56
+ // Render data rows
57
+ data.forEach((row, rowIndex) => {
58
+ const cells = columns.map((col, colIndex) => {
59
+ const width = columnWidths[colIndex];
60
+ const align = col.align || 'left';
61
+ const value = String(row[col.key] || '');
62
+ return alignText(value, width, align);
63
+ });
64
+ if (showBorders) {
65
+ (0, terminal_js_1.writeLine)(`│${cells.join('│')}│`);
66
+ }
67
+ else {
68
+ (0, terminal_js_1.writeLine)(cells.join(' '));
69
+ }
70
+ });
71
+ // Render bottom border
72
+ if (showBorders) {
73
+ const border = columnWidths.map(w => '─'.repeat(w)).join('┴');
74
+ (0, terminal_js_1.writeLine)(`└${border}┘`);
75
+ }
76
+ }
77
+ /**
78
+ * Align text within a given width
79
+ */
80
+ function alignText(text, width, align) {
81
+ const padding = width - text.length;
82
+ if (padding <= 0) {
83
+ return text.substring(0, width);
84
+ }
85
+ switch (align) {
86
+ case 'center':
87
+ const leftPad = Math.floor(padding / 2);
88
+ const rightPad = padding - leftPad;
89
+ return ' '.repeat(leftPad) + text + ' '.repeat(rightPad);
90
+ case 'right':
91
+ return ' '.repeat(padding) + text;
92
+ case 'left':
93
+ default:
94
+ return text + ' '.repeat(padding);
95
+ }
96
+ }
97
+ /**
98
+ * Create table configuration (factory function)
99
+ */
100
+ function createTable(columns, data, options) {
101
+ return {
102
+ columns,
103
+ data,
104
+ showBorders: options?.showBorders ?? true,
105
+ showHeaderSeparator: options?.showHeaderSeparator ?? true
106
+ };
107
+ }
@@ -8,13 +8,14 @@ exports.showBooleanMenu = showBooleanMenu;
8
8
  const terminal_js_1 = require("../../core/terminal.js");
9
9
  const keyboard_js_1 = require("../../core/keyboard.js");
10
10
  const colors_js_1 = require("../../core/colors.js");
11
+ const registry_js_1 = require("../../i18n/registry.js");
11
12
  /**
12
13
  * Show a boolean menu (yes/no selection)
13
14
  * @param config - Menu configuration
14
15
  * @returns Promise resolving to boolean result
15
16
  */
16
17
  async function showBooleanMenu(config) {
17
- const { question, defaultValue = true, yesText = '', noText = '', orientation = 'horizontal', onExit, preserveOnSelect = false } = config;
18
+ const { question, defaultValue = true, yesText = (0, registry_js_1.t)('menus.yes'), noText = (0, registry_js_1.t)('menus.no'), orientation = 'horizontal', onExit, preserveOnSelect = false } = config;
18
19
  if (orientation === 'horizontal') {
19
20
  return showBooleanMenuHorizontal(question, defaultValue, yesText, noText, onExit, preserveOnSelect);
20
21
  }
@@ -6,6 +6,7 @@ import { CheckboxMenuConfig, CheckboxMenuResult } from '../../types/menu.types.j
6
6
  /**
7
7
  * Show a checkbox menu (multi-select)
8
8
  * @param config - Menu configuration
9
+ * @param hints - Optional hints to display at the bottom (for Page Layout use)
9
10
  * @returns Promise resolving to selected options
10
11
  */
11
- export declare function showCheckboxMenu(config: CheckboxMenuConfig): Promise<CheckboxMenuResult>;
12
+ export declare function showCheckboxMenu(config: CheckboxMenuConfig, hints?: string[]): Promise<CheckboxMenuResult>;
@@ -5,36 +5,20 @@
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
7
  exports.showCheckboxMenu = showCheckboxMenu;
8
- const layout_types_js_1 = require("../../types/layout.types.js");
9
8
  const terminal_js_1 = require("../../core/terminal.js");
10
9
  const keyboard_js_1 = require("../../core/keyboard.js");
11
10
  const renderer_js_1 = require("../../core/renderer.js");
12
11
  const registry_js_1 = require("../../i18n/registry.js");
13
- /**
14
- * Generate hints based on menu configuration
15
- */
16
- function generateHints(allowSelectAll, allowInvert) {
17
- const hints = [(0, registry_js_1.t)('hints.arrows'), (0, registry_js_1.t)('hints.space')];
18
- if (allowSelectAll) {
19
- hints.push((0, registry_js_1.t)('hints.selectAll'));
20
- }
21
- if (allowInvert) {
22
- hints.push((0, registry_js_1.t)('hints.invert'));
23
- }
24
- hints.push((0, registry_js_1.t)('hints.enter'));
25
- return hints;
26
- }
27
12
  /**
28
13
  * Show a checkbox menu (multi-select)
29
14
  * @param config - Menu configuration
15
+ * @param hints - Optional hints to display at the bottom (for Page Layout use)
30
16
  * @returns Promise resolving to selected options
31
17
  */
32
- async function showCheckboxMenu(config) {
33
- const { options, title, prompt, hints, layout = { ...layout_types_js_1.LAYOUT_PRESETS.SUB_MENU, order: ['input', 'options', 'hints'] }, defaultSelected = [], minSelections = 0, maxSelections, allowSelectAll = true, allowInvert = true, separatorWidth = 30, onExit, preserveOnSelect = false } = config;
18
+ async function showCheckboxMenu(config, hints) {
19
+ const { options, title, prompt, defaultSelected = [], minSelections = 0, maxSelections, allowSelectAll = true, allowInvert = true, separatorWidth = 30, onExit, preserveOnSelect = false } = config;
34
20
  // Use i18n for default prompt if not provided
35
21
  const displayPrompt = prompt || (0, registry_js_1.t)('menus.multiSelectPrompt');
36
- // Generate hints dynamically if not provided
37
- const displayHints = hints || generateHints(allowSelectAll, allowInvert);
38
22
  // Validate options
39
23
  if (!options || options.length === 0) {
40
24
  throw new Error('CheckboxMenu requires at least one option');
@@ -89,49 +73,36 @@ async function showCheckboxMenu(config) {
89
73
  const render = () => {
90
74
  (0, terminal_js_1.clearMenu)(state);
91
75
  let lineCount = 0;
92
- // Render based on layout order
93
- layout.order.forEach(element => {
94
- // Add spacing before element
95
- const spacingKey = `before${element.charAt(0).toUpperCase() + element.slice(1)}`;
96
- if (layout.spacing?.[spacingKey]) {
97
- (0, renderer_js_1.renderBlankLines)(layout.spacing[spacingKey]);
98
- lineCount += layout.spacing[spacingKey];
99
- }
100
- switch (element) {
101
- case 'input':
102
- if (layout.visible.input) {
103
- const selectedCount = selected.size;
104
- const displayValue = `${selectedCount} ${(0, registry_js_1.t)('menus.selectedCount')}`;
105
- (0, renderer_js_1.renderInputPrompt)(displayPrompt, displayValue);
106
- lineCount++;
107
- }
108
- break;
109
- case 'options':
110
- optionData.forEach((item, index) => {
111
- if (item.isSeparator) {
112
- // Render section label
113
- (0, renderer_js_1.renderSectionLabel)(item.label, separatorWidth);
114
- }
115
- else {
116
- (0, renderer_js_1.renderOption)(item.value, selected.has(index), index === cursorIndex);
117
- }
118
- lineCount++;
119
- });
120
- break;
121
- case 'hints':
122
- if (layout.visible.hints && displayHints.length > 0) {
123
- (0, renderer_js_1.renderHints)(displayHints);
124
- lineCount++;
125
- }
126
- break;
76
+ // Render title if provided
77
+ if (title) {
78
+ (0, renderer_js_1.renderBlankLines)(1);
79
+ lineCount++;
80
+ }
81
+ // Render input prompt (show selected count)
82
+ const selectedCount = selected.size;
83
+ const displayValue = `${selectedCount} ${(0, registry_js_1.t)('menus.selectedCount')}`;
84
+ (0, renderer_js_1.renderInputPrompt)(displayPrompt, displayValue);
85
+ lineCount++;
86
+ (0, renderer_js_1.renderBlankLines)(1);
87
+ lineCount++;
88
+ // Render options
89
+ optionData.forEach((item, index) => {
90
+ if (item.isSeparator) {
91
+ // Render section label
92
+ (0, renderer_js_1.renderSectionLabel)(item.label, separatorWidth);
127
93
  }
128
- // Add spacing after element
129
- const afterSpacingKey = `after${element.charAt(0).toUpperCase() + element.slice(1)}`;
130
- if (layout.spacing?.[afterSpacingKey]) {
131
- (0, renderer_js_1.renderBlankLines)(layout.spacing[afterSpacingKey]);
132
- lineCount += layout.spacing[afterSpacingKey];
94
+ else {
95
+ (0, renderer_js_1.renderOption)(item.value, selected.has(index), index === cursorIndex);
133
96
  }
97
+ lineCount++;
134
98
  });
99
+ // Render hints if provided
100
+ if (hints && hints.length > 0) {
101
+ (0, renderer_js_1.renderBlankLines)(1);
102
+ lineCount++;
103
+ (0, renderer_js_1.renderHints)(hints);
104
+ lineCount += 1;
105
+ }
135
106
  state.renderedLines = lineCount;
136
107
  };
137
108
  // Initial render
@@ -0,0 +1,12 @@
1
+ /**
2
+ * CheckboxTableMenu - Multi-select menu with table display
3
+ * Combines checkbox selection with formatted table layout
4
+ */
5
+ import { CheckboxTableMenuConfig, CheckboxTableMenuResult } from '../../types/menu.types.js';
6
+ /**
7
+ * Show a checkbox table menu (multi-select with table display)
8
+ * @param config - Menu configuration
9
+ * @param hints - Optional hints to display at the bottom (for Page Layout use)
10
+ * @returns Promise resolving to selected rows
11
+ */
12
+ export declare function showCheckboxTableMenu(config: CheckboxTableMenuConfig, hints?: string[]): Promise<CheckboxTableMenuResult>;