cli-menu-kit 0.1.17 → 0.1.19

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.
@@ -14,18 +14,18 @@ const colors_js_1 = require("../../core/colors.js");
14
14
  * @returns Promise resolving to boolean result
15
15
  */
16
16
  async function showBooleanMenu(config) {
17
- const { question, defaultValue = true, yesText = '是', noText = '否', orientation = 'horizontal', onExit } = config;
17
+ const { question, defaultValue = true, yesText = '是', noText = '否', orientation = 'horizontal', onExit, preserveOnSelect = false } = config;
18
18
  if (orientation === 'horizontal') {
19
- return showBooleanMenuHorizontal(question, defaultValue, yesText, noText, onExit);
19
+ return showBooleanMenuHorizontal(question, defaultValue, yesText, noText, onExit, preserveOnSelect);
20
20
  }
21
21
  else {
22
- return showBooleanMenuVertical(question, defaultValue, yesText, noText, onExit);
22
+ return showBooleanMenuVertical(question, defaultValue, yesText, noText, onExit, preserveOnSelect);
23
23
  }
24
24
  }
25
25
  /**
26
26
  * Show horizontal boolean menu (side by side)
27
27
  */
28
- async function showBooleanMenuHorizontal(question, defaultValue, yesText, noText, onExit) {
28
+ async function showBooleanMenuHorizontal(question, defaultValue, yesText, noText, onExit, preserveOnSelect = false) {
29
29
  const state = (0, terminal_js_1.initTerminal)();
30
30
  let selected = defaultValue;
31
31
  const render = () => {
@@ -61,7 +61,9 @@ async function showBooleanMenuHorizontal(question, defaultValue, yesText, noText
61
61
  // Handle Enter
62
62
  if ((0, keyboard_js_1.isEnter)(key)) {
63
63
  state.stdin.removeListener('data', onData);
64
- (0, terminal_js_1.clearMenu)(state);
64
+ if (!preserveOnSelect) {
65
+ (0, terminal_js_1.clearMenu)(state);
66
+ }
65
67
  (0, terminal_js_1.restoreTerminal)(state);
66
68
  resolve(selected);
67
69
  return;
@@ -96,7 +98,7 @@ async function showBooleanMenuHorizontal(question, defaultValue, yesText, noText
96
98
  /**
97
99
  * Show vertical boolean menu (stacked)
98
100
  */
99
- async function showBooleanMenuVertical(question, defaultValue, yesText, noText, onExit) {
101
+ async function showBooleanMenuVertical(question, defaultValue, yesText, noText, onExit, preserveOnSelect = false) {
100
102
  const state = (0, terminal_js_1.initTerminal)();
101
103
  let selected = defaultValue;
102
104
  const render = () => {
@@ -135,7 +137,9 @@ async function showBooleanMenuVertical(question, defaultValue, yesText, noText,
135
137
  // Handle Enter
136
138
  if ((0, keyboard_js_1.isEnter)(key)) {
137
139
  state.stdin.removeListener('data', onData);
138
- (0, terminal_js_1.clearMenu)(state);
140
+ if (!preserveOnSelect) {
141
+ (0, terminal_js_1.clearMenu)(state);
142
+ }
139
143
  (0, terminal_js_1.restoreTerminal)(state);
140
144
  resolve(selected);
141
145
  return;
@@ -30,7 +30,7 @@ function generateHints(allowSelectAll, allowInvert) {
30
30
  * @returns Promise resolving to selected options
31
31
  */
32
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 } = 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;
34
34
  // Use i18n for default prompt if not provided
35
35
  const displayPrompt = prompt || (0, registry_js_1.t)('menus.multiSelectPrompt');
36
36
  // Generate hints dynamically if not provided
@@ -160,7 +160,9 @@ async function showCheckboxMenu(config) {
160
160
  return;
161
161
  }
162
162
  state.stdin.removeListener('data', onData);
163
- (0, terminal_js_1.clearMenu)(state);
163
+ if (!preserveOnSelect) {
164
+ (0, terminal_js_1.clearMenu)(state);
165
+ }
164
166
  (0, terminal_js_1.restoreTerminal)(state);
165
167
  const indices = Array.from(selected).sort((a, b) => a - b);
166
168
  const values = indices.map(i => {
@@ -12,15 +12,39 @@ const renderer_js_1 = require("../../core/renderer.js");
12
12
  const colors_js_1 = require("../../core/colors.js");
13
13
  const registry_js_1 = require("../../i18n/registry.js");
14
14
  /**
15
- * Generate hints based on menu configuration
15
+ * Generate hints based on menu configuration and actual options
16
16
  */
17
- function generateHints(allowNumberKeys, allowLetterKeys) {
18
- const hints = [(0, registry_js_1.t)('hints.arrows')];
17
+ function generateHints(options, allowNumberKeys, allowLetterKeys) {
18
+ const hints = [];
19
+ // Count selectable options
20
+ const selectableCount = options.filter(opt => !(typeof opt === 'object' && 'type' in opt && opt.type === 'separator')).length;
21
+ // Only show arrow hints if there are multiple options
22
+ if (selectableCount > 1) {
23
+ hints.push((0, registry_js_1.t)('hints.arrows'));
24
+ }
25
+ // Check if there are actually number-prefixed options
19
26
  if (allowNumberKeys) {
20
- hints.push((0, registry_js_1.t)('hints.numbers'));
27
+ const hasNumberOptions = options.some(opt => {
28
+ if (typeof opt === 'string') {
29
+ return /^\d+\./.test(opt);
30
+ }
31
+ return false;
32
+ });
33
+ if (hasNumberOptions) {
34
+ hints.push((0, registry_js_1.t)('hints.numbers'));
35
+ }
21
36
  }
37
+ // Check if there are actually letter-prefixed options
22
38
  if (allowLetterKeys) {
23
- hints.push((0, registry_js_1.t)('hints.letters'));
39
+ const hasLetterOptions = options.some(opt => {
40
+ if (typeof opt === 'string') {
41
+ return /^[a-zA-Z]\./.test(opt);
42
+ }
43
+ return false;
44
+ });
45
+ if (hasLetterOptions) {
46
+ hints.push((0, registry_js_1.t)('hints.letters'));
47
+ }
24
48
  }
25
49
  hints.push((0, registry_js_1.t)('hints.enter'));
26
50
  return hints;
@@ -31,11 +55,11 @@ function generateHints(allowNumberKeys, allowLetterKeys) {
31
55
  * @returns Promise resolving to selected option
32
56
  */
33
57
  async function showRadioMenu(config) {
34
- const { options, title, prompt, hints, layout = layout_types_js_1.LAYOUT_PRESETS.MAIN_MENU, defaultIndex = 0, allowNumberKeys = true, allowLetterKeys = false, separatorWidth = 30, onExit } = config;
58
+ const { options, title, prompt, hints, layout = layout_types_js_1.LAYOUT_PRESETS.MAIN_MENU, defaultIndex = 0, allowNumberKeys = true, allowLetterKeys = false, separatorWidth = 30, onExit, preserveOnSelect = false } = config;
35
59
  // Use i18n for default prompt if not provided
36
60
  const displayPrompt = prompt || (0, registry_js_1.t)('menus.selectPrompt');
37
61
  // Generate hints dynamically if not provided
38
- const displayHints = hints || generateHints(allowNumberKeys, allowLetterKeys);
62
+ const displayHints = hints || generateHints(options, allowNumberKeys, allowLetterKeys);
39
63
  // Validate options
40
64
  if (!options || options.length === 0) {
41
65
  throw new Error('RadioMenu requires at least one option');
@@ -186,7 +210,12 @@ async function showRadioMenu(config) {
186
210
  // Handle Enter
187
211
  if ((0, keyboard_js_1.isEnter)(key)) {
188
212
  state.stdin.removeListener('data', onData);
189
- (0, terminal_js_1.clearMenu)(state);
213
+ if (!preserveOnSelect) {
214
+ (0, terminal_js_1.clearMenu)(state);
215
+ }
216
+ else {
217
+ (0, terminal_js_1.writeLine)('');
218
+ }
190
219
  (0, terminal_js_1.restoreTerminal)(state);
191
220
  const selectedOption = options[selectedIndex];
192
221
  let value;
@@ -30,6 +30,8 @@ export interface BaseMenuConfig {
30
30
  onExit?: () => void;
31
31
  /** Separator width for section labels (default: 30) */
32
32
  separatorWidth?: number;
33
+ /** Keep menu rendered after selection instead of clearing (default: false) */
34
+ preserveOnSelect?: boolean;
33
35
  }
34
36
  /**
35
37
  * Radio menu (single-select) configuration
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cli-menu-kit",
3
- "version": "0.1.17",
3
+ "version": "0.1.19",
4
4
  "description": "A lightweight, customizable CLI menu system with keyboard shortcuts and real-time rendering",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",