cli-menu-kit 0.1.26 → 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 (58) 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/table.d.ts +42 -0
  18. package/dist/components/display/table.js +107 -0
  19. package/dist/components/menus/boolean-menu.js +2 -1
  20. package/dist/components/menus/checkbox-menu.d.ts +2 -1
  21. package/dist/components/menus/checkbox-menu.js +30 -59
  22. package/dist/components/menus/checkbox-table-menu.d.ts +12 -0
  23. package/dist/components/menus/checkbox-table-menu.js +395 -0
  24. package/dist/components/menus/index.d.ts +1 -0
  25. package/dist/components/menus/index.js +3 -1
  26. package/dist/components/menus/radio-menu-split.d.ts +33 -0
  27. package/dist/components/menus/radio-menu-split.js +248 -0
  28. package/dist/components/menus/radio-menu-v2.d.ts +11 -0
  29. package/dist/components/menus/radio-menu-v2.js +150 -0
  30. package/dist/components/menus/radio-menu.d.ts +2 -1
  31. package/dist/components/menus/radio-menu.js +60 -123
  32. package/dist/core/hint-manager.d.ts +29 -0
  33. package/dist/core/hint-manager.js +65 -0
  34. package/dist/core/renderer.d.ts +2 -1
  35. package/dist/core/renderer.js +22 -6
  36. package/dist/core/screen-manager.d.ts +54 -0
  37. package/dist/core/screen-manager.js +119 -0
  38. package/dist/core/state-manager.d.ts +27 -0
  39. package/dist/core/state-manager.js +56 -0
  40. package/dist/core/terminal.d.ts +4 -1
  41. package/dist/core/terminal.js +37 -4
  42. package/dist/core/virtual-scroll.d.ts +65 -0
  43. package/dist/core/virtual-scroll.js +120 -0
  44. package/dist/i18n/languages/en.js +4 -1
  45. package/dist/i18n/languages/zh.js +4 -1
  46. package/dist/i18n/registry.d.ts +4 -3
  47. package/dist/i18n/registry.js +12 -4
  48. package/dist/i18n/types.d.ts +3 -0
  49. package/dist/index.d.ts +5 -4
  50. package/dist/index.js +30 -4
  51. package/dist/layout.d.ts +68 -0
  52. package/dist/layout.js +134 -0
  53. package/dist/page-layout.d.ts +92 -0
  54. package/dist/page-layout.js +156 -0
  55. package/dist/types/menu.types.d.ts +57 -5
  56. package/package.json +1 -1
  57. package/dist/types/layout.types.d.ts +0 -56
  58. 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
+ }
@@ -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>;