mepcli 0.5.0 → 0.6.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 (76) hide show
  1. package/README.md +182 -6
  2. package/dist/ansi.d.ts +1 -0
  3. package/dist/ansi.js +1 -0
  4. package/dist/base.d.ts +1 -1
  5. package/dist/base.js +1 -10
  6. package/dist/core.d.ts +26 -1
  7. package/dist/core.js +72 -0
  8. package/dist/highlight.d.ts +1 -0
  9. package/dist/highlight.js +40 -0
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/input.js +26 -14
  13. package/dist/prompts/autocomplete.d.ts +1 -1
  14. package/dist/prompts/autocomplete.js +2 -7
  15. package/dist/prompts/calendar.d.ts +20 -0
  16. package/dist/prompts/calendar.js +329 -0
  17. package/dist/prompts/checkbox.d.ts +1 -1
  18. package/dist/prompts/checkbox.js +38 -8
  19. package/dist/prompts/code.d.ts +17 -0
  20. package/dist/prompts/code.js +210 -0
  21. package/dist/prompts/color.d.ts +14 -0
  22. package/dist/prompts/color.js +147 -0
  23. package/dist/prompts/confirm.d.ts +1 -1
  24. package/dist/prompts/confirm.js +1 -1
  25. package/dist/prompts/cron.d.ts +13 -0
  26. package/dist/prompts/cron.js +176 -0
  27. package/dist/prompts/date.d.ts +1 -1
  28. package/dist/prompts/date.js +15 -5
  29. package/dist/prompts/editor.d.ts +14 -0
  30. package/dist/prompts/editor.js +207 -0
  31. package/dist/prompts/file.d.ts +7 -0
  32. package/dist/prompts/file.js +56 -60
  33. package/dist/prompts/form.d.ts +17 -0
  34. package/dist/prompts/form.js +225 -0
  35. package/dist/prompts/grid.d.ts +14 -0
  36. package/dist/prompts/grid.js +178 -0
  37. package/dist/prompts/keypress.d.ts +7 -0
  38. package/dist/prompts/keypress.js +57 -0
  39. package/dist/prompts/list.d.ts +1 -1
  40. package/dist/prompts/list.js +42 -22
  41. package/dist/prompts/multi-select.d.ts +1 -1
  42. package/dist/prompts/multi-select.js +39 -4
  43. package/dist/prompts/number.d.ts +1 -1
  44. package/dist/prompts/number.js +2 -2
  45. package/dist/prompts/range.d.ts +9 -0
  46. package/dist/prompts/range.js +140 -0
  47. package/dist/prompts/rating.d.ts +1 -1
  48. package/dist/prompts/rating.js +1 -1
  49. package/dist/prompts/select.d.ts +1 -1
  50. package/dist/prompts/select.js +1 -1
  51. package/dist/prompts/slider.d.ts +1 -1
  52. package/dist/prompts/slider.js +1 -1
  53. package/dist/prompts/snippet.d.ts +18 -0
  54. package/dist/prompts/snippet.js +203 -0
  55. package/dist/prompts/sort.d.ts +1 -1
  56. package/dist/prompts/sort.js +1 -4
  57. package/dist/prompts/spam.d.ts +17 -0
  58. package/dist/prompts/spam.js +62 -0
  59. package/dist/prompts/table.d.ts +1 -1
  60. package/dist/prompts/table.js +1 -1
  61. package/dist/prompts/text.d.ts +1 -0
  62. package/dist/prompts/text.js +14 -32
  63. package/dist/prompts/toggle.d.ts +1 -1
  64. package/dist/prompts/toggle.js +1 -1
  65. package/dist/prompts/transfer.d.ts +18 -0
  66. package/dist/prompts/transfer.js +203 -0
  67. package/dist/prompts/tree-select.d.ts +32 -0
  68. package/dist/prompts/tree-select.js +277 -0
  69. package/dist/prompts/tree.d.ts +20 -0
  70. package/dist/prompts/tree.js +231 -0
  71. package/dist/prompts/wait.d.ts +18 -0
  72. package/dist/prompts/wait.js +62 -0
  73. package/dist/types.d.ts +105 -0
  74. package/dist/utils.js +6 -2
  75. package/example.ts +213 -27
  76. package/package.json +14 -4
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TransferPrompt = void 0;
4
+ const ansi_1 = require("../ansi");
5
+ const base_1 = require("../base");
6
+ const theme_1 = require("../theme");
7
+ const symbols_1 = require("../symbols");
8
+ const utils_1 = require("../utils");
9
+ class TransferPrompt extends base_1.Prompt {
10
+ constructor(options) {
11
+ super(options);
12
+ this.leftList = [];
13
+ this.rightList = [];
14
+ this.cursorLeft = 0;
15
+ this.cursorRight = 0;
16
+ this.scrollTopLeft = 0;
17
+ this.scrollTopRight = 0;
18
+ this.activeSide = 'left';
19
+ this.pageSize = 10;
20
+ this.leftList = this.normalize(options.source);
21
+ this.rightList = this.normalize(options.target || []);
22
+ }
23
+ normalize(items) {
24
+ return items.map(item => {
25
+ if (typeof item === 'string') {
26
+ return { title: item, value: item };
27
+ }
28
+ return item;
29
+ });
30
+ }
31
+ truncate(str, width) {
32
+ if ((0, utils_1.stringWidth)(str) <= width)
33
+ return str;
34
+ let res = str;
35
+ while ((0, utils_1.stringWidth)(res + '...') > width && res.length > 0) {
36
+ res = res.slice(0, -1);
37
+ }
38
+ return res + '...';
39
+ }
40
+ render(_firstRender) {
41
+ const termWidth = process.stdout.columns || 80;
42
+ const colWidth = Math.floor((termWidth - 6) / 2);
43
+ // Adjust Scroll Top
44
+ if (this.activeSide === 'left') {
45
+ if (this.cursorLeft < this.scrollTopLeft)
46
+ this.scrollTopLeft = this.cursorLeft;
47
+ if (this.cursorLeft >= this.scrollTopLeft + this.pageSize)
48
+ this.scrollTopLeft = this.cursorLeft - this.pageSize + 1;
49
+ }
50
+ else {
51
+ if (this.cursorRight < this.scrollTopRight)
52
+ this.scrollTopRight = this.cursorRight;
53
+ if (this.cursorRight >= this.scrollTopRight + this.pageSize)
54
+ this.scrollTopRight = this.cursorRight - this.pageSize + 1;
55
+ }
56
+ let output = `${theme_1.theme.success}?${ansi_1.ANSI.RESET} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET}\n`;
57
+ // Headers
58
+ const leftTitle = this.activeSide === 'left' ? `${theme_1.theme.main}Source${ansi_1.ANSI.RESET}` : 'Source';
59
+ const rightTitle = this.activeSide === 'right' ? `${theme_1.theme.main}Target${ansi_1.ANSI.RESET}` : 'Target';
60
+ output += ` ${leftTitle}`.padEnd(colWidth + 2) + ' ' + ` ${rightTitle}\n`;
61
+ output += ` ${ansi_1.ANSI.DIM}${symbols_1.symbols.line.repeat(colWidth)}${ansi_1.ANSI.RESET} ${ansi_1.ANSI.DIM}${symbols_1.symbols.line.repeat(colWidth)}${ansi_1.ANSI.RESET}\n`;
62
+ for (let i = 0; i < this.pageSize; i++) {
63
+ const idxLeft = this.scrollTopLeft + i;
64
+ const idxRight = this.scrollTopRight + i;
65
+ const itemLeft = this.leftList[idxLeft];
66
+ const itemRight = this.rightList[idxRight];
67
+ // Left Column
68
+ let leftStr = '';
69
+ if (itemLeft) {
70
+ const isSelected = this.activeSide === 'left' && idxLeft === this.cursorLeft;
71
+ const title = this.truncate(itemLeft.title, colWidth - 2);
72
+ if (isSelected) {
73
+ leftStr = `${theme_1.theme.main}${symbols_1.symbols.pointer} ${title}${ansi_1.ANSI.RESET}`;
74
+ }
75
+ else {
76
+ leftStr = ` ${title}`;
77
+ }
78
+ }
79
+ else {
80
+ leftStr = ''; // Empty
81
+ }
82
+ // Right Column
83
+ let rightStr = '';
84
+ if (itemRight) {
85
+ const isSelected = this.activeSide === 'right' && idxRight === this.cursorRight;
86
+ const title = this.truncate(itemRight.title, colWidth - 2);
87
+ if (isSelected) {
88
+ rightStr = `${theme_1.theme.main}${symbols_1.symbols.pointer} ${title}${ansi_1.ANSI.RESET}`;
89
+ }
90
+ else {
91
+ rightStr = ` ${title}`;
92
+ }
93
+ }
94
+ const leftVisualWidth = itemLeft ? ((0, utils_1.stringWidth)(this.truncate(itemLeft.title, colWidth - 2)) + 2) : 0;
95
+ // Pad visually
96
+ const padding = ' '.repeat(Math.max(0, colWidth - leftVisualWidth));
97
+ output += leftStr + padding + ' | ' + rightStr + '\n';
98
+ }
99
+ output += `\n${ansi_1.ANSI.DIM}(Tab: Switch | a: Move All Right | r: Reset/All Left)${ansi_1.ANSI.RESET}`;
100
+ this.renderFrame(output);
101
+ }
102
+ handleInput(char) {
103
+ if (char === '\r' || char === '\n') {
104
+ const leftValues = this.leftList.map(i => i.value);
105
+ const rightValues = this.rightList.map(i => i.value);
106
+ this.submit([leftValues, rightValues]);
107
+ return;
108
+ }
109
+ if (char === '\t' || this.isLeft(char) || this.isRight(char)) {
110
+ // Toggle side
111
+ this.activeSide = this.activeSide === 'left' ? 'right' : 'left';
112
+ this.render(false);
113
+ return;
114
+ }
115
+ // --- Batch Transfer Shortcuts ---
116
+ // Move All to Right ('a' or '>')
117
+ if (char === 'a' || char === '>') {
118
+ if (this.leftList.length > 0) {
119
+ this.rightList.push(...this.leftList);
120
+ this.leftList = [];
121
+ this.cursorLeft = 0;
122
+ this.activeSide = 'right';
123
+ this.render(false);
124
+ }
125
+ return;
126
+ }
127
+ // Move All to Left ('r' or '<')
128
+ if (char === 'r' || char === '<') {
129
+ if (this.rightList.length > 0) {
130
+ this.leftList.push(...this.rightList);
131
+ this.rightList = [];
132
+ this.cursorRight = 0;
133
+ this.activeSide = 'left';
134
+ this.render(false);
135
+ }
136
+ return;
137
+ }
138
+ if (this.isUp(char)) {
139
+ if (this.activeSide === 'left') {
140
+ this.cursorLeft = Math.max(0, this.cursorLeft - 1);
141
+ }
142
+ else {
143
+ this.cursorRight = Math.max(0, this.cursorRight - 1);
144
+ }
145
+ this.render(false);
146
+ return;
147
+ }
148
+ if (this.isDown(char)) {
149
+ if (this.activeSide === 'left') {
150
+ this.cursorLeft = Math.min(this.leftList.length - 1, this.cursorLeft + 1);
151
+ }
152
+ else {
153
+ this.cursorRight = Math.min(this.rightList.length - 1, this.cursorRight + 1);
154
+ }
155
+ this.render(false);
156
+ return;
157
+ }
158
+ if (char === ' ') {
159
+ // Move item
160
+ if (this.activeSide === 'left') {
161
+ if (this.leftList.length > 0) {
162
+ const [item] = this.leftList.splice(this.cursorLeft, 1);
163
+ this.rightList.push(item);
164
+ if (this.cursorLeft >= this.leftList.length) {
165
+ this.cursorLeft = Math.max(0, this.leftList.length - 1);
166
+ }
167
+ }
168
+ }
169
+ else {
170
+ if (this.rightList.length > 0) {
171
+ const [item] = this.rightList.splice(this.cursorRight, 1);
172
+ this.leftList.push(item);
173
+ if (this.cursorRight >= this.rightList.length) {
174
+ this.cursorRight = Math.max(0, this.rightList.length - 1);
175
+ }
176
+ }
177
+ }
178
+ this.render(false);
179
+ }
180
+ }
181
+ handleMouse(event) {
182
+ if (event.action === 'scroll') {
183
+ if (event.scroll === 'up') {
184
+ if (this.activeSide === 'left') {
185
+ this.cursorLeft = Math.max(0, this.cursorLeft - 1);
186
+ }
187
+ else {
188
+ this.cursorRight = Math.max(0, this.cursorRight - 1);
189
+ }
190
+ }
191
+ else {
192
+ if (this.activeSide === 'left') {
193
+ this.cursorLeft = Math.min(this.leftList.length - 1, this.cursorLeft + 1);
194
+ }
195
+ else {
196
+ this.cursorRight = Math.min(this.rightList.length - 1, this.cursorRight + 1);
197
+ }
198
+ }
199
+ this.render(false);
200
+ }
201
+ }
202
+ }
203
+ exports.TransferPrompt = TransferPrompt;
@@ -0,0 +1,32 @@
1
+ import { Prompt } from '../base';
2
+ import { TreeSelectOptions, MouseEvent } from '../types';
3
+ /**
4
+ * FIXED-ISH: This prompt may hang on Windows TTY after multiple prompt cycles.
5
+ * Current workaround: User must press 'Enter' to flush the stdin buffer.
6
+ * Potential root cause: Synchronous recursion during initialization blocking setRawMode.
7
+ */
8
+ export declare class TreeSelectPrompt<V> extends Prompt<V[], TreeSelectOptions<V>> {
9
+ private cursor;
10
+ private expandedNodes;
11
+ private flatList;
12
+ private scrollTop;
13
+ private readonly pageSize;
14
+ private parentMap;
15
+ private static hasWarnedWindows;
16
+ private readonly ICON_CLOSED;
17
+ private readonly ICON_OPEN;
18
+ constructor(options: TreeSelectOptions<V>);
19
+ private buildParentMap;
20
+ private initializeExpanded;
21
+ private initializeSelection;
22
+ private recalculateAllParents;
23
+ private updateNodeStateFromChildren;
24
+ private setNodeState;
25
+ private recalculateFlatList;
26
+ private traverse;
27
+ private toggleRecursive;
28
+ protected render(_firstRender: boolean): void;
29
+ protected handleInput(char: string, _key: Buffer): void;
30
+ private collectSelected;
31
+ protected handleMouse(event: MouseEvent): void;
32
+ }
@@ -0,0 +1,277 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TreeSelectPrompt = void 0;
4
+ const ansi_1 = require("../ansi");
5
+ const base_1 = require("../base");
6
+ const theme_1 = require("../theme");
7
+ const symbols_1 = require("../symbols");
8
+ /**
9
+ * FIXED-ISH: This prompt may hang on Windows TTY after multiple prompt cycles.
10
+ * Current workaround: User must press 'Enter' to flush the stdin buffer.
11
+ * Potential root cause: Synchronous recursion during initialization blocking setRawMode.
12
+ */
13
+ class TreeSelectPrompt extends base_1.Prompt {
14
+ constructor(options) {
15
+ super(options);
16
+ this.cursor = 0;
17
+ this.expandedNodes = new Set();
18
+ this.flatList = [];
19
+ this.scrollTop = 0;
20
+ this.pageSize = 15;
21
+ this.parentMap = new Map();
22
+ this.ICON_CLOSED = symbols_1.symbols.pointer === '>' ? '+' : '▸';
23
+ this.ICON_OPEN = symbols_1.symbols.pointer === '>' ? '-' : '▾';
24
+ this.buildParentMap(this.options.data, null);
25
+ this.initializeExpanded(this.options.data);
26
+ if (this.options.initial) {
27
+ const initialSet = new Set(this.options.initial);
28
+ this.initializeSelection(this.options.data, initialSet);
29
+ this.recalculateAllParents(this.options.data);
30
+ }
31
+ if (process.platform === 'win32' && !TreeSelectPrompt.hasWarnedWindows) {
32
+ console.warn(`${ansi_1.ANSI.FG_YELLOW}Warning:${ansi_1.ANSI.RESET} TreeSelectPrompt may hang on Windows TTY after multiple prompt cycles. Please press 'Enter' if the prompt becomes unresponsive.${ansi_1.ANSI.RESET}`);
33
+ TreeSelectPrompt.hasWarnedWindows = true;
34
+ }
35
+ this.recalculateFlatList();
36
+ }
37
+ buildParentMap(nodes, parent) {
38
+ for (const node of nodes) {
39
+ if (parent)
40
+ this.parentMap.set(node, parent);
41
+ if (node.children) {
42
+ this.buildParentMap(node.children, node);
43
+ }
44
+ }
45
+ }
46
+ initializeExpanded(nodes) {
47
+ for (const node of nodes) {
48
+ if (node.expanded) {
49
+ this.expandedNodes.add(node);
50
+ }
51
+ if (node.children) {
52
+ this.initializeExpanded(node.children);
53
+ }
54
+ }
55
+ }
56
+ initializeSelection(nodes, initialValues) {
57
+ for (const node of nodes) {
58
+ if (initialValues.has(node.value)) {
59
+ this.setNodeState(node, true, false);
60
+ }
61
+ if (node.children) {
62
+ this.initializeSelection(node.children, initialValues);
63
+ }
64
+ }
65
+ }
66
+ recalculateAllParents(nodes) {
67
+ for (const node of nodes) {
68
+ if (node.children) {
69
+ this.recalculateAllParents(node.children);
70
+ this.updateNodeStateFromChildren(node);
71
+ }
72
+ }
73
+ }
74
+ updateNodeStateFromChildren(node) {
75
+ if (!node.children || node.children.length === 0)
76
+ return;
77
+ const allChecked = node.children.every(c => c.selected === true);
78
+ const allUnchecked = node.children.every(c => !c.selected);
79
+ if (allChecked) {
80
+ node.selected = true;
81
+ }
82
+ else if (allUnchecked) {
83
+ node.selected = false;
84
+ }
85
+ else {
86
+ node.selected = 'indeterminate';
87
+ }
88
+ }
89
+ setNodeState(node, state, updateParents = true) {
90
+ node.selected = state;
91
+ if (node.children) {
92
+ node.children.forEach(c => this.setNodeState(c, state, false));
93
+ }
94
+ if (updateParents) {
95
+ let curr = node;
96
+ while (this.parentMap.has(curr)) {
97
+ const parent = this.parentMap.get(curr);
98
+ this.updateNodeStateFromChildren(parent);
99
+ curr = parent;
100
+ }
101
+ }
102
+ }
103
+ recalculateFlatList() {
104
+ this.flatList = [];
105
+ this.traverse(this.options.data, 0, null);
106
+ if (this.cursor >= this.flatList.length) {
107
+ this.cursor = Math.max(0, this.flatList.length - 1);
108
+ }
109
+ }
110
+ traverse(nodes, depth, parent) {
111
+ for (const node of nodes) {
112
+ this.flatList.push({ node, depth, parent });
113
+ if (node.children && node.children.length > 0 && this.expandedNodes.has(node)) {
114
+ this.traverse(node.children, depth + 1, node);
115
+ }
116
+ }
117
+ }
118
+ toggleRecursive(node, expand) {
119
+ if (expand)
120
+ this.expandedNodes.add(node);
121
+ else
122
+ this.expandedNodes.delete(node);
123
+ if (node.children) {
124
+ node.children.forEach(child => this.toggleRecursive(child, expand));
125
+ }
126
+ }
127
+ render(_firstRender) {
128
+ let output = `${theme_1.theme.success}?${ansi_1.ANSI.RESET} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET}\n`;
129
+ if (this.flatList.length === 0) {
130
+ output += ` ${theme_1.theme.muted}No data${ansi_1.ANSI.RESET}`;
131
+ this.renderFrame(output);
132
+ return;
133
+ }
134
+ if (this.cursor < this.scrollTop) {
135
+ this.scrollTop = this.cursor;
136
+ }
137
+ else if (this.cursor >= this.scrollTop + this.pageSize) {
138
+ this.scrollTop = this.cursor - this.pageSize + 1;
139
+ }
140
+ const visible = this.flatList.slice(this.scrollTop, this.scrollTop + this.pageSize);
141
+ visible.forEach((item, index) => {
142
+ const actualIndex = this.scrollTop + index;
143
+ const isSelected = actualIndex === this.cursor;
144
+ const indentSize = this.options.indent || 2;
145
+ const indentation = ' '.repeat(item.depth * indentSize);
146
+ const linePrefix = isSelected ? `${theme_1.theme.main}${symbols_1.symbols.pointer} ` : ' ';
147
+ let folderIcon = ' ';
148
+ const hasChildren = item.node.children && item.node.children.length > 0;
149
+ if (hasChildren) {
150
+ folderIcon = this.expandedNodes.has(item.node) ? `${this.ICON_OPEN} ` : `${this.ICON_CLOSED} `;
151
+ }
152
+ // Checkbox
153
+ let checkIcon = `[ ]`;
154
+ if (item.node.selected === true) {
155
+ checkIcon = `${theme_1.theme.success}[x]${ansi_1.ANSI.RESET}`;
156
+ }
157
+ else if (item.node.selected === 'indeterminate') {
158
+ checkIcon = `${ansi_1.ANSI.FG_YELLOW}[-]${ansi_1.ANSI.RESET}`;
159
+ }
160
+ else {
161
+ checkIcon = `${theme_1.theme.muted}[ ]${ansi_1.ANSI.RESET}`;
162
+ }
163
+ let title = item.node.title;
164
+ if (item.node.disabled) {
165
+ title = `${theme_1.theme.muted}${title} (disabled)${ansi_1.ANSI.RESET}`;
166
+ }
167
+ let line = `${indentation}${folderIcon}${checkIcon} ${title}`;
168
+ if (isSelected) {
169
+ line = `${theme_1.theme.main}${line}${ansi_1.ANSI.RESET}`;
170
+ }
171
+ output += linePrefix + line;
172
+ if (index < visible.length - 1)
173
+ output += '\n';
174
+ });
175
+ output += `\n${theme_1.theme.muted}(e: Expand All, c: Collapse All, Space: Toggle)${ansi_1.ANSI.RESET}`;
176
+ this.renderFrame(output);
177
+ }
178
+ handleInput(char, _key) {
179
+ if (this.flatList.length === 0)
180
+ return;
181
+ // 1. Priority: Navigation keys (ANSI sequences)
182
+ if (this.isUp(char)) {
183
+ this.cursor = (this.cursor - 1 + this.flatList.length) % this.flatList.length;
184
+ this.render(false);
185
+ return;
186
+ }
187
+ if (this.isDown(char)) {
188
+ this.cursor = (this.cursor + 1) % this.flatList.length;
189
+ this.render(false);
190
+ return;
191
+ }
192
+ const currentItem = this.flatList[this.cursor];
193
+ if (!currentItem)
194
+ return;
195
+ const node = currentItem.node;
196
+ const hasChildren = node.children && node.children.length > 0;
197
+ // 2. Right Arrow: Expand folder or move to first child
198
+ if (this.isRight(char)) {
199
+ if (hasChildren && !this.expandedNodes.has(node)) {
200
+ this.expandedNodes.add(node);
201
+ this.recalculateFlatList();
202
+ }
203
+ else if (this.cursor + 1 < this.flatList.length) {
204
+ this.cursor++;
205
+ }
206
+ this.render(false);
207
+ return;
208
+ }
209
+ // 3. Left Arrow: Collapse folder or move to parent
210
+ if (this.isLeft(char)) {
211
+ if (hasChildren && this.expandedNodes.has(node)) {
212
+ this.expandedNodes.delete(node);
213
+ this.recalculateFlatList();
214
+ }
215
+ else if (currentItem.parent) {
216
+ const parentIndex = this.flatList.findIndex(x => x.node === currentItem.parent);
217
+ if (parentIndex !== -1) {
218
+ this.cursor = parentIndex;
219
+ }
220
+ }
221
+ this.render(false);
222
+ return;
223
+ }
224
+ // 4. Space: Toggle selection
225
+ if (char === ' ') {
226
+ if (!node.disabled) {
227
+ const newState = node.selected === true ? false : true;
228
+ this.setNodeState(node, newState);
229
+ this.render(false);
230
+ }
231
+ return;
232
+ }
233
+ // 5. Functional keys (Keep it simple to avoid blocking)
234
+ if (char === 'e' && hasChildren) {
235
+ this.toggleRecursive(node, true);
236
+ this.recalculateFlatList();
237
+ this.render(false);
238
+ return;
239
+ }
240
+ if (char === 'c' && hasChildren) {
241
+ this.toggleRecursive(node, false);
242
+ this.recalculateFlatList();
243
+ this.render(false);
244
+ return;
245
+ }
246
+ // 6. Submit: Enter
247
+ if (char === '\r' || char === '\n') {
248
+ const selectedValues = [];
249
+ this.collectSelected(this.options.data, selectedValues);
250
+ this.submit(selectedValues);
251
+ }
252
+ }
253
+ collectSelected(nodes, result) {
254
+ for (const node of nodes) {
255
+ if (node.selected === true) {
256
+ result.push(node.value);
257
+ }
258
+ if (node.children) {
259
+ this.collectSelected(node.children, result);
260
+ }
261
+ }
262
+ }
263
+ handleMouse(event) {
264
+ if (event.action === 'scroll') {
265
+ if (event.scroll === 'up') {
266
+ this.cursor = (this.cursor - 1 + this.flatList.length) % this.flatList.length;
267
+ this.render(false);
268
+ }
269
+ else if (event.scroll === 'down') {
270
+ this.cursor = (this.cursor + 1) % this.flatList.length;
271
+ this.render(false);
272
+ }
273
+ }
274
+ }
275
+ }
276
+ exports.TreeSelectPrompt = TreeSelectPrompt;
277
+ TreeSelectPrompt.hasWarnedWindows = false; // Static flag to warn only once
@@ -0,0 +1,20 @@
1
+ import { Prompt } from '../base';
2
+ import { TreeOptions, MouseEvent } from '../types';
3
+ export declare class TreePrompt<V> extends Prompt<V, TreeOptions<V>> {
4
+ private cursor;
5
+ private expandedNodes;
6
+ private flatList;
7
+ private scrollTop;
8
+ private readonly pageSize;
9
+ private readonly ICON_CLOSED;
10
+ private readonly ICON_OPEN;
11
+ constructor(options: TreeOptions<V>);
12
+ private expandPathTo;
13
+ private initializeExpanded;
14
+ private recalculateFlatList;
15
+ private traverse;
16
+ private toggleRecursive;
17
+ protected render(_firstRender: boolean): void;
18
+ protected handleInput(char: string, _key: Buffer): void;
19
+ protected handleMouse(event: MouseEvent): void;
20
+ }