mepcli 0.2.0 → 0.2.5

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.
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CheckboxPrompt = void 0;
4
+ const ansi_1 = require("../ansi");
5
+ const base_1 = require("../base");
6
+ const theme_1 = require("../theme");
7
+ // --- Implementation: Checkbox Prompt ---
8
+ class CheckboxPrompt extends base_1.Prompt {
9
+ constructor(options) {
10
+ super(options);
11
+ this.selectedIndex = 0;
12
+ this.errorMsg = '';
13
+ this.checkedState = options.choices.map(c => !!c.selected);
14
+ }
15
+ render(firstRender) {
16
+ // Ensure cursor is HIDDEN for menus
17
+ this.print(ansi_1.ANSI.HIDE_CURSOR);
18
+ if (!firstRender) {
19
+ const extraLines = this.errorMsg ? 1 : 0;
20
+ this.print(`\x1b[${this.options.choices.length + 1 + extraLines}A`);
21
+ }
22
+ this.print(`${ansi_1.ANSI.ERASE_LINE}${ansi_1.ANSI.CURSOR_LEFT}`);
23
+ const icon = this.errorMsg ? `${theme_1.theme.error}✖` : `${theme_1.theme.success}?`;
24
+ this.print(`${icon} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET} ${theme_1.theme.muted}(Press <space> to select, <enter> to confirm)${ansi_1.ANSI.RESET}\n`);
25
+ this.options.choices.forEach((choice, index) => {
26
+ this.print(`${ansi_1.ANSI.ERASE_LINE}${ansi_1.ANSI.CURSOR_LEFT}`);
27
+ const cursor = index === this.selectedIndex ? `${theme_1.theme.main}❯${ansi_1.ANSI.RESET}` : ' ';
28
+ const isChecked = this.checkedState[index];
29
+ const checkbox = isChecked
30
+ ? `${theme_1.theme.success}◉${ansi_1.ANSI.RESET}`
31
+ : `${theme_1.theme.muted}◯${ansi_1.ANSI.RESET}`;
32
+ const title = index === this.selectedIndex
33
+ ? `${theme_1.theme.main}${choice.title}${ansi_1.ANSI.RESET}`
34
+ : choice.title;
35
+ this.print(`${cursor} ${checkbox} ${title}\n`);
36
+ });
37
+ if (this.errorMsg) {
38
+ this.print(`${ansi_1.ANSI.ERASE_LINE}${theme_1.theme.error}>> ${this.errorMsg}${ansi_1.ANSI.RESET}`);
39
+ }
40
+ else if (!firstRender) {
41
+ this.print(`${ansi_1.ANSI.ERASE_LINE}`);
42
+ }
43
+ }
44
+ handleInput(char) {
45
+ if (char === '\r' || char === '\n') {
46
+ const selectedCount = this.checkedState.filter(Boolean).length;
47
+ const { min = 0, max } = this.options;
48
+ if (selectedCount < min) {
49
+ this.errorMsg = `You must select at least ${min} options.`;
50
+ this.render(false);
51
+ return;
52
+ }
53
+ if (max && selectedCount > max) {
54
+ this.errorMsg = `You can only select up to ${max} options.`;
55
+ this.render(false);
56
+ return;
57
+ }
58
+ this.cleanup();
59
+ this.print(ansi_1.ANSI.SHOW_CURSOR + '\n');
60
+ const results = this.options.choices
61
+ .filter((_, i) => this.checkedState[i])
62
+ .map(c => c.value);
63
+ if (this._resolve)
64
+ this._resolve(results);
65
+ return;
66
+ }
67
+ if (char === ' ') {
68
+ const currentChecked = this.checkedState[this.selectedIndex];
69
+ const selectedCount = this.checkedState.filter(Boolean).length;
70
+ const { max } = this.options;
71
+ if (!currentChecked && max && selectedCount >= max) {
72
+ this.errorMsg = `Max ${max} selections allowed.`;
73
+ }
74
+ else {
75
+ this.checkedState[this.selectedIndex] = !currentChecked;
76
+ this.errorMsg = '';
77
+ }
78
+ this.render(false);
79
+ }
80
+ if (this.isUp(char)) { // Up
81
+ this.selectedIndex = this.selectedIndex > 0 ? this.selectedIndex - 1 : this.options.choices.length - 1;
82
+ this.errorMsg = '';
83
+ this.render(false);
84
+ }
85
+ if (this.isDown(char)) { // Down
86
+ this.selectedIndex = this.selectedIndex < this.options.choices.length - 1 ? this.selectedIndex + 1 : 0;
87
+ this.errorMsg = '';
88
+ this.render(false);
89
+ }
90
+ }
91
+ }
92
+ exports.CheckboxPrompt = CheckboxPrompt;
@@ -0,0 +1,7 @@
1
+ import { Prompt } from '../base';
2
+ import { ConfirmOptions } from '../types';
3
+ export declare class ConfirmPrompt extends Prompt<boolean, ConfirmOptions> {
4
+ constructor(options: ConfirmOptions);
5
+ protected render(firstRender: boolean): void;
6
+ protected handleInput(char: string): void;
7
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConfirmPrompt = void 0;
4
+ const ansi_1 = require("../ansi");
5
+ const base_1 = require("../base");
6
+ const theme_1 = require("../theme");
7
+ // --- Implementation: Confirm Prompt ---
8
+ class ConfirmPrompt extends base_1.Prompt {
9
+ constructor(options) {
10
+ super(options);
11
+ this.value = options.initial ?? true;
12
+ }
13
+ render(firstRender) {
14
+ // Hide cursor for confirm, user just hits Y/N or Enter
15
+ this.print(ansi_1.ANSI.HIDE_CURSOR);
16
+ if (!firstRender) {
17
+ this.print(`${ansi_1.ANSI.ERASE_LINE}${ansi_1.ANSI.CURSOR_LEFT}`);
18
+ }
19
+ const hint = this.value ? `${ansi_1.ANSI.BOLD}Yes${ansi_1.ANSI.RESET}/no` : `yes/${ansi_1.ANSI.BOLD}No${ansi_1.ANSI.RESET}`;
20
+ this.print(`${theme_1.theme.success}?${ansi_1.ANSI.RESET} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET} ${theme_1.theme.muted}(${hint})${ansi_1.ANSI.RESET} `);
21
+ const text = this.value ? 'Yes' : 'No';
22
+ this.print(`${theme_1.theme.main}${text}${ansi_1.ANSI.RESET}\x1b[${text.length}D`);
23
+ }
24
+ handleInput(char) {
25
+ const c = char.toLowerCase();
26
+ if (c === '\r' || c === '\n') {
27
+ this.submit(this.value);
28
+ return;
29
+ }
30
+ if (c === 'y') {
31
+ this.value = true;
32
+ this.render(false);
33
+ }
34
+ if (c === 'n') {
35
+ this.value = false;
36
+ this.render(false);
37
+ }
38
+ }
39
+ }
40
+ exports.ConfirmPrompt = ConfirmPrompt;
@@ -0,0 +1,10 @@
1
+ import { Prompt } from '../base';
2
+ import { DateOptions } from '../types';
3
+ export declare class DatePrompt extends Prompt<Date, DateOptions> {
4
+ private selectedField;
5
+ private errorMsg;
6
+ private inputBuffer;
7
+ constructor(options: DateOptions);
8
+ protected render(firstRender: boolean): void;
9
+ protected handleInput(char: string): void;
10
+ }
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DatePrompt = void 0;
4
+ const ansi_1 = require("../ansi");
5
+ const base_1 = require("../base");
6
+ const theme_1 = require("../theme");
7
+ // --- Implementation: Date Prompt ---
8
+ class DatePrompt extends base_1.Prompt {
9
+ constructor(options) {
10
+ super(options);
11
+ this.selectedField = 0; // 0: Year, 1: Month, 2: Day, 3: Hour, 4: Minute
12
+ this.errorMsg = '';
13
+ this.inputBuffer = '';
14
+ this.value = options.initial || new Date();
15
+ }
16
+ render(firstRender) {
17
+ this.print(ansi_1.ANSI.HIDE_CURSOR);
18
+ if (!firstRender) {
19
+ this.print(ansi_1.ANSI.ERASE_LINE + ansi_1.ANSI.CURSOR_LEFT);
20
+ if (this.errorMsg) {
21
+ this.print(ansi_1.ANSI.UP + ansi_1.ANSI.ERASE_LINE + ansi_1.ANSI.CURSOR_LEFT);
22
+ }
23
+ }
24
+ const y = this.value.getFullYear();
25
+ const m = (this.value.getMonth() + 1).toString().padStart(2, '0');
26
+ const d = this.value.getDate().toString().padStart(2, '0');
27
+ const h = this.value.getHours().toString().padStart(2, '0');
28
+ const min = this.value.getMinutes().toString().padStart(2, '0');
29
+ const fields = [y, m, d, h, min];
30
+ const display = fields.map((val, i) => {
31
+ if (i === this.selectedField)
32
+ return `${theme_1.theme.main}${ansi_1.ANSI.UNDERLINE}${val}${ansi_1.ANSI.RESET}`;
33
+ return val;
34
+ });
35
+ const icon = this.errorMsg ? `${theme_1.theme.error}✖` : `${theme_1.theme.success}?`;
36
+ const dateStr = `${display[0]}-${display[1]}-${display[2]} ${display[3]}:${display[4]}`;
37
+ this.print(`${icon} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET} ${dateStr} ${theme_1.theme.muted}(Use arrows or type)${ansi_1.ANSI.RESET}`);
38
+ if (this.errorMsg) {
39
+ this.print(`\n${ansi_1.ANSI.ERASE_LINE}${theme_1.theme.error}>> ${this.errorMsg}${ansi_1.ANSI.RESET}`);
40
+ this.print(ansi_1.ANSI.UP);
41
+ // restore cursor pos logic isn't needed as we are on one line mostly, but for consistency:
42
+ const promptLen = this.options.message.length + 3; // roughly
43
+ this.print(`\x1b[1000D\x1b[${promptLen + 15}C`); // approx move back
44
+ }
45
+ }
46
+ handleInput(char) {
47
+ if (char === '\r' || char === '\n') {
48
+ this.submit(this.value);
49
+ return;
50
+ }
51
+ if (this.isLeft(char)) { // Left
52
+ this.selectedField = Math.max(0, this.selectedField - 1);
53
+ this.inputBuffer = ''; // Reset buffer on move
54
+ this.errorMsg = '';
55
+ this.render(false);
56
+ return;
57
+ }
58
+ if (this.isRight(char)) { // Right
59
+ this.selectedField = Math.min(4, this.selectedField + 1);
60
+ this.inputBuffer = ''; // Reset buffer on move
61
+ this.errorMsg = '';
62
+ this.render(false);
63
+ return;
64
+ }
65
+ // Support numeric input
66
+ if (/^\d$/.test(char)) {
67
+ const maxLen = this.selectedField === 0 ? 4 : 2;
68
+ let nextBuffer = this.inputBuffer + char;
69
+ // If we exceed max length, reset to just the new char (assuming user is starting a new number)
70
+ // Or better: try to parse.
71
+ // Logic:
72
+ // 1. Try appending.
73
+ // 2. Validate.
74
+ // 3. If valid, keep.
75
+ // 4. If invalid (e.g. Month 13), assume new start -> set buffer to just char.
76
+ // However, we must respect field limits first.
77
+ if (nextBuffer.length > maxLen) {
78
+ nextBuffer = char;
79
+ }
80
+ const val = parseInt(nextBuffer, 10);
81
+ let valid = true;
82
+ // Pre-validation to decide if we should append or reset
83
+ if (this.selectedField === 1 && (val < 1 || val > 12))
84
+ valid = false; // Month
85
+ if (this.selectedField === 2 && (val < 1 || val > 31))
86
+ valid = false; // Day (rough check)
87
+ if (this.selectedField === 3 && (val > 23))
88
+ valid = false; // Hour
89
+ if (this.selectedField === 4 && (val > 59))
90
+ valid = false; // Minute
91
+ if (!valid) {
92
+ // If appending made it invalid (e.g. was '1', typed '3' -> '13' invalid month),
93
+ // treat '3' as the start of a new number.
94
+ nextBuffer = char;
95
+ }
96
+ this.inputBuffer = nextBuffer;
97
+ const finalVal = parseInt(this.inputBuffer, 10);
98
+ const d = new Date(this.value);
99
+ if (this.selectedField === 0) {
100
+ // Year is special, we just set it.
101
+ d.setFullYear(finalVal);
102
+ }
103
+ else if (this.selectedField === 1)
104
+ d.setMonth(Math.max(0, Math.min(11, finalVal - 1)));
105
+ else if (this.selectedField === 2)
106
+ d.setDate(Math.max(1, Math.min(31, finalVal)));
107
+ else if (this.selectedField === 3)
108
+ d.setHours(Math.max(0, Math.min(23, finalVal)));
109
+ else if (this.selectedField === 4)
110
+ d.setMinutes(Math.max(0, Math.min(59, finalVal)));
111
+ this.value = d;
112
+ this.errorMsg = '';
113
+ this.render(false);
114
+ return;
115
+ }
116
+ // Support standard and application cursor keys
117
+ const isUp = this.isUp(char);
118
+ const isDown = this.isDown(char);
119
+ if (isUp || isDown) {
120
+ this.inputBuffer = ''; // Reset buffer on arrow move
121
+ const dir = isUp ? 1 : -1;
122
+ const d = new Date(this.value);
123
+ switch (this.selectedField) {
124
+ case 0:
125
+ d.setFullYear(d.getFullYear() + dir);
126
+ break;
127
+ case 1:
128
+ d.setMonth(d.getMonth() + dir);
129
+ break;
130
+ case 2:
131
+ d.setDate(d.getDate() + dir);
132
+ break;
133
+ case 3:
134
+ d.setHours(d.getHours() + dir);
135
+ break;
136
+ case 4:
137
+ d.setMinutes(d.getMinutes() + dir);
138
+ break;
139
+ }
140
+ let valid = true;
141
+ if (this.options.min && d < this.options.min) {
142
+ this.errorMsg = 'Date cannot be before minimum allowed.';
143
+ valid = false;
144
+ }
145
+ if (this.options.max && d > this.options.max) {
146
+ this.errorMsg = 'Date cannot be after maximum allowed.';
147
+ valid = false;
148
+ }
149
+ if (valid) {
150
+ this.value = d;
151
+ this.errorMsg = '';
152
+ }
153
+ this.render(false);
154
+ }
155
+ }
156
+ }
157
+ exports.DatePrompt = DatePrompt;
@@ -0,0 +1,13 @@
1
+ import { Prompt } from '../base';
2
+ import { FileOptions } from '../types';
3
+ export declare class FilePrompt extends Prompt<string, FileOptions> {
4
+ private input;
5
+ private cursor;
6
+ private suggestions;
7
+ private selectedSuggestion;
8
+ private errorMsg;
9
+ constructor(options: FileOptions);
10
+ private updateSuggestions;
11
+ protected render(firstRender: boolean): void;
12
+ protected handleInput(char: string): void;
13
+ }
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.FilePrompt = void 0;
37
+ const ansi_1 = require("../ansi");
38
+ const base_1 = require("../base");
39
+ const theme_1 = require("../theme");
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ // --- Implementation: File Prompt ---
43
+ class FilePrompt extends base_1.Prompt {
44
+ constructor(options) {
45
+ super(options);
46
+ this.input = '';
47
+ this.cursor = 0;
48
+ this.suggestions = [];
49
+ this.selectedSuggestion = -1;
50
+ this.errorMsg = '';
51
+ this.input = options.basePath || '';
52
+ this.cursor = this.input.length;
53
+ }
54
+ updateSuggestions() {
55
+ try {
56
+ const dir = path.dirname(this.input) || '.';
57
+ const partial = path.basename(this.input);
58
+ if (fs.existsSync(dir) && fs.statSync(dir).isDirectory()) {
59
+ const files = fs.readdirSync(dir);
60
+ this.suggestions = files
61
+ .filter(f => f.startsWith(partial))
62
+ .filter(f => {
63
+ const fullPath = path.join(dir, f);
64
+ const isDir = fs.statSync(fullPath).isDirectory();
65
+ if (this.options.onlyDirectories && !isDir)
66
+ return false;
67
+ if (this.options.extensions && !isDir) {
68
+ return this.options.extensions.some(ext => f.endsWith(ext));
69
+ }
70
+ return true;
71
+ })
72
+ .map(f => {
73
+ const fullPath = path.join(dir, f);
74
+ if (fs.statSync(fullPath).isDirectory())
75
+ return f + '/';
76
+ return f;
77
+ });
78
+ }
79
+ else {
80
+ this.suggestions = [];
81
+ }
82
+ }
83
+ catch (e) {
84
+ this.suggestions = [];
85
+ }
86
+ this.selectedSuggestion = -1;
87
+ }
88
+ render(firstRender) {
89
+ this.print(ansi_1.ANSI.SHOW_CURSOR);
90
+ if (!firstRender) {
91
+ // Clear input line + suggestions
92
+ this.print(ansi_1.ANSI.ERASE_LINE + ansi_1.ANSI.CURSOR_LEFT); // Input line
93
+ // We need to track how many lines suggestions took
94
+ // For now assume simple clear, or use ANSI.ERASE_DOWN if at bottom?
95
+ // Safer to move up and clear
96
+ this.print(ansi_1.ANSI.ERASE_DOWN);
97
+ }
98
+ const icon = this.errorMsg ? `${theme_1.theme.error}✖` : `${theme_1.theme.success}?`;
99
+ this.print(`${icon} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET} ${this.input}`);
100
+ if (this.suggestions.length > 0) {
101
+ this.print('\n');
102
+ const maxShow = 5;
103
+ this.suggestions.slice(0, maxShow).forEach((s, i) => {
104
+ if (i === this.selectedSuggestion) {
105
+ this.print(`${theme_1.theme.main}❯ ${s}${ansi_1.ANSI.RESET}\n`);
106
+ }
107
+ else {
108
+ this.print(` ${s}\n`);
109
+ }
110
+ });
111
+ if (this.suggestions.length > maxShow) {
112
+ this.print(` ...and ${this.suggestions.length - maxShow} more\n`);
113
+ }
114
+ // Move cursor back to input line
115
+ const lines = Math.min(this.suggestions.length, maxShow) + (this.suggestions.length > maxShow ? 2 : 1);
116
+ this.print(`\x1b[${lines}A`);
117
+ const inputLen = this.options.message.length + 3 + this.input.length;
118
+ this.print(`\x1b[${inputLen}C`);
119
+ }
120
+ }
121
+ handleInput(char) {
122
+ if (char === '\t') { // Tab
123
+ if (this.suggestions.length === 1) {
124
+ const dir = path.dirname(this.input);
125
+ this.input = path.join(dir === '.' ? '' : dir, this.suggestions[0]);
126
+ this.cursor = this.input.length;
127
+ this.suggestions = [];
128
+ this.render(false);
129
+ }
130
+ else if (this.suggestions.length > 1) {
131
+ // Cycle or show? For now cycle if selected
132
+ if (this.selectedSuggestion !== -1) {
133
+ const dir = path.dirname(this.input);
134
+ this.input = path.join(dir === '.' ? '' : dir, this.suggestions[this.selectedSuggestion]);
135
+ this.cursor = this.input.length;
136
+ this.suggestions = [];
137
+ this.render(false);
138
+ }
139
+ else {
140
+ // Just show suggestions (already done in render loop usually, but update logic ensures it)
141
+ this.updateSuggestions();
142
+ this.render(false);
143
+ }
144
+ }
145
+ else {
146
+ this.updateSuggestions();
147
+ this.render(false);
148
+ }
149
+ return;
150
+ }
151
+ if (char === '\r' || char === '\n') {
152
+ if (this.selectedSuggestion !== -1) {
153
+ const dir = path.dirname(this.input);
154
+ this.input = path.join(dir === '.' ? '' : dir, this.suggestions[this.selectedSuggestion]);
155
+ this.cursor = this.input.length;
156
+ this.suggestions = [];
157
+ this.selectedSuggestion = -1;
158
+ this.render(false);
159
+ }
160
+ else {
161
+ this.submit(this.input);
162
+ }
163
+ return;
164
+ }
165
+ if (this.isDown(char)) { // Down
166
+ if (this.suggestions.length > 0) {
167
+ this.selectedSuggestion = (this.selectedSuggestion + 1) % Math.min(this.suggestions.length, 5);
168
+ this.render(false);
169
+ }
170
+ return;
171
+ }
172
+ if (this.isUp(char)) { // Up
173
+ if (this.suggestions.length > 0) {
174
+ this.selectedSuggestion = (this.selectedSuggestion - 1 + Math.min(this.suggestions.length, 5)) % Math.min(this.suggestions.length, 5);
175
+ this.render(false);
176
+ }
177
+ return;
178
+ }
179
+ if (char === '\u0008' || char === '\x7f') { // Backspace
180
+ if (this.input.length > 0) {
181
+ this.input = this.input.slice(0, -1);
182
+ this.updateSuggestions();
183
+ this.render(false);
184
+ }
185
+ return;
186
+ }
187
+ if (!/^[\x00-\x1F]/.test(char) && !char.startsWith('\x1b')) {
188
+ this.input += char;
189
+ this.updateSuggestions();
190
+ this.render(false);
191
+ }
192
+ }
193
+ }
194
+ exports.FilePrompt = FilePrompt;
@@ -0,0 +1,9 @@
1
+ import { Prompt } from '../base';
2
+ import { ListOptions } from '../types';
3
+ export declare class ListPrompt extends Prompt<string[], ListOptions> {
4
+ private currentInput;
5
+ private errorMsg;
6
+ constructor(options: ListOptions);
7
+ protected render(firstRender: boolean): void;
8
+ protected handleInput(char: string): void;
9
+ }
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ListPrompt = void 0;
4
+ const ansi_1 = require("../ansi");
5
+ const base_1 = require("../base");
6
+ const theme_1 = require("../theme");
7
+ // --- Implementation: List Prompt ---
8
+ class ListPrompt extends base_1.Prompt {
9
+ constructor(options) {
10
+ super(options);
11
+ this.currentInput = '';
12
+ this.errorMsg = '';
13
+ this.value = options.initial || [];
14
+ }
15
+ render(firstRender) {
16
+ this.print(ansi_1.ANSI.SHOW_CURSOR);
17
+ if (!firstRender) {
18
+ this.print(ansi_1.ANSI.ERASE_LINE + ansi_1.ANSI.CURSOR_LEFT);
19
+ if (this.errorMsg) {
20
+ this.print(ansi_1.ANSI.UP + ansi_1.ANSI.ERASE_LINE + ansi_1.ANSI.CURSOR_LEFT);
21
+ }
22
+ }
23
+ const icon = this.errorMsg ? `${theme_1.theme.error}✖` : `${theme_1.theme.success}?`;
24
+ this.print(`${icon} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET} `);
25
+ // Render Tags
26
+ if (this.value.length > 0) {
27
+ this.value.forEach((tag) => {
28
+ this.print(`${theme_1.theme.main}[${tag}]${ansi_1.ANSI.RESET} `);
29
+ });
30
+ }
31
+ // Render Current Input
32
+ this.print(`${this.currentInput}`);
33
+ if (this.errorMsg) {
34
+ this.print(`\n${ansi_1.ANSI.ERASE_LINE}${theme_1.theme.error}>> ${this.errorMsg}${ansi_1.ANSI.RESET}`);
35
+ this.print(ansi_1.ANSI.UP);
36
+ // Return cursor
37
+ const promptLen = this.options.message.length + 3;
38
+ let tagsLen = 0;
39
+ this.value.forEach((tag) => tagsLen += tag.length + 3); // [tag] + space
40
+ const inputLen = this.currentInput.length;
41
+ this.print(`\x1b[1000D\x1b[${promptLen + tagsLen + inputLen}C`);
42
+ }
43
+ }
44
+ handleInput(char) {
45
+ if (char === '\r' || char === '\n') {
46
+ if (this.currentInput.trim()) {
47
+ this.value.push(this.currentInput.trim());
48
+ this.currentInput = '';
49
+ this.errorMsg = '';
50
+ this.render(false);
51
+ }
52
+ else {
53
+ // Done if input is empty
54
+ if (this.options.validate) {
55
+ const result = this.options.validate(this.value);
56
+ if (result !== true) {
57
+ this.errorMsg = typeof result === 'string' ? result : 'Invalid input';
58
+ this.render(false);
59
+ return;
60
+ }
61
+ }
62
+ this.submit(this.value);
63
+ }
64
+ return;
65
+ }
66
+ if (char === '\u0008' || char === '\x7f') { // Backspace
67
+ if (this.currentInput.length > 0) {
68
+ this.currentInput = this.currentInput.slice(0, -1);
69
+ this.render(false);
70
+ }
71
+ else if (this.value.length > 0) {
72
+ this.value.pop();
73
+ this.render(false);
74
+ }
75
+ return;
76
+ }
77
+ if (!/^[\x00-\x1F]/.test(char) && !char.startsWith('\x1b')) {
78
+ this.currentInput += char;
79
+ this.render(false);
80
+ }
81
+ }
82
+ }
83
+ exports.ListPrompt = ListPrompt;
@@ -0,0 +1,14 @@
1
+ import { Prompt } from '../base';
2
+ import { MultiSelectOptions } from '../types';
3
+ export declare class MultiSelectPrompt extends Prompt<any[], MultiSelectOptions> {
4
+ private selectedIndex;
5
+ private checkedState;
6
+ private searchBuffer;
7
+ private scrollTop;
8
+ private readonly pageSize;
9
+ private errorMsg;
10
+ constructor(options: MultiSelectOptions);
11
+ private getFilteredChoices;
12
+ protected render(firstRender: boolean): void;
13
+ protected handleInput(char: string): void;
14
+ }