mepcli 0.5.5 → 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 (75) hide show
  1. package/README.md +173 -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 +23 -1
  7. package/dist/core.js +60 -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.js +2 -2
  30. package/dist/prompts/file.d.ts +7 -0
  31. package/dist/prompts/file.js +56 -60
  32. package/dist/prompts/form.d.ts +17 -0
  33. package/dist/prompts/form.js +225 -0
  34. package/dist/prompts/grid.d.ts +14 -0
  35. package/dist/prompts/grid.js +178 -0
  36. package/dist/prompts/keypress.d.ts +2 -2
  37. package/dist/prompts/keypress.js +2 -2
  38. package/dist/prompts/list.d.ts +1 -1
  39. package/dist/prompts/list.js +42 -22
  40. package/dist/prompts/multi-select.d.ts +1 -1
  41. package/dist/prompts/multi-select.js +39 -4
  42. package/dist/prompts/number.d.ts +1 -1
  43. package/dist/prompts/number.js +2 -2
  44. package/dist/prompts/range.d.ts +9 -0
  45. package/dist/prompts/range.js +140 -0
  46. package/dist/prompts/rating.d.ts +1 -1
  47. package/dist/prompts/rating.js +1 -1
  48. package/dist/prompts/select.d.ts +1 -1
  49. package/dist/prompts/select.js +1 -1
  50. package/dist/prompts/slider.d.ts +1 -1
  51. package/dist/prompts/slider.js +1 -1
  52. package/dist/prompts/snippet.d.ts +18 -0
  53. package/dist/prompts/snippet.js +203 -0
  54. package/dist/prompts/sort.d.ts +1 -1
  55. package/dist/prompts/sort.js +1 -4
  56. package/dist/prompts/spam.d.ts +17 -0
  57. package/dist/prompts/spam.js +62 -0
  58. package/dist/prompts/table.d.ts +1 -1
  59. package/dist/prompts/table.js +1 -1
  60. package/dist/prompts/text.d.ts +1 -0
  61. package/dist/prompts/text.js +13 -31
  62. package/dist/prompts/toggle.d.ts +1 -1
  63. package/dist/prompts/toggle.js +1 -1
  64. package/dist/prompts/transfer.d.ts +18 -0
  65. package/dist/prompts/transfer.js +203 -0
  66. package/dist/prompts/tree-select.d.ts +32 -0
  67. package/dist/prompts/tree-select.js +277 -0
  68. package/dist/prompts/tree.d.ts +3 -3
  69. package/dist/prompts/tree.js +27 -19
  70. package/dist/prompts/wait.d.ts +18 -0
  71. package/dist/prompts/wait.js +62 -0
  72. package/dist/types.d.ts +84 -0
  73. package/dist/utils.js +1 -1
  74. package/example.ts +150 -15
  75. package/package.json +2 -2
@@ -17,7 +17,7 @@ class NumberPrompt extends base_1.Prompt {
17
17
  this.stringValue = options.initial !== undefined ? options.initial.toString() : '';
18
18
  this.cursor = this.stringValue.length;
19
19
  }
20
- render(firstRender) {
20
+ render(_firstRender) {
21
21
  // Prepare content
22
22
  const icon = this.errorMsg ? `${theme_1.theme.error}${symbols_1.symbols.cross}` : `${theme_1.theme.success}?`;
23
23
  // Prefix
@@ -122,7 +122,7 @@ class NumberPrompt extends base_1.Prompt {
122
122
  return;
123
123
  }
124
124
  // Numeric Input (and . and -)
125
- if (/^[0-9.\-]+$/.test(char)) {
125
+ if (/^[0-9.-]+$/.test(char)) {
126
126
  // Allow if it looks like a number part
127
127
  this.stringValue = this.stringValue.slice(0, this.cursor) + char + this.stringValue.slice(this.cursor);
128
128
  this.cursor += char.length;
@@ -0,0 +1,9 @@
1
+ import { Prompt } from '../base';
2
+ import { RangeOptions, MouseEvent } from '../types';
3
+ export declare class RangePrompt extends Prompt<[number, number], RangeOptions> {
4
+ private activeHandle;
5
+ constructor(options: RangeOptions);
6
+ protected render(_firstRender: boolean): void;
7
+ protected handleInput(char: string): void;
8
+ protected handleMouse(event: MouseEvent): void;
9
+ }
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RangePrompt = 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
+ class RangePrompt extends base_1.Prompt {
9
+ constructor(options) {
10
+ super(options);
11
+ this.activeHandle = 'low';
12
+ // Ensure initial is sorted and within bounds, default to [min, max] if not provided
13
+ const initial = options.initial || [options.min, options.max];
14
+ // Basic validation for initial
15
+ let [low, high] = initial;
16
+ low = Math.max(options.min, Math.min(low, options.max));
17
+ high = Math.max(options.min, Math.min(high, options.max));
18
+ if (low > high) {
19
+ [low, high] = [high, low];
20
+ }
21
+ this.value = [low, high];
22
+ }
23
+ render(_firstRender) {
24
+ const width = 20;
25
+ const range = this.options.max - this.options.min;
26
+ const [low, high] = this.value;
27
+ // Calculate positions (0 to width)
28
+ // Avoid division by zero if min == max
29
+ const ratioLow = range === 0 ? 0 : (low - this.options.min) / range;
30
+ const posLow = Math.round(ratioLow * width);
31
+ const ratioHigh = range === 0 ? 1 : (high - this.options.min) / range;
32
+ const posHigh = Math.round(ratioHigh * width);
33
+ let bar = '';
34
+ for (let i = 0; i <= width; i++) {
35
+ if (i === posLow && i === posHigh) {
36
+ // Collision
37
+ bar += `${theme_1.theme.main}|${ansi_1.ANSI.RESET}`;
38
+ }
39
+ else if (i === posLow) {
40
+ if (this.activeHandle === 'low') {
41
+ // Highlight active handle
42
+ bar += `${theme_1.theme.main}${ansi_1.ANSI.REVERSE}O${ansi_1.ANSI.RESET}`;
43
+ }
44
+ else {
45
+ bar += `${theme_1.theme.main}O${ansi_1.ANSI.RESET}`;
46
+ }
47
+ }
48
+ else if (i === posHigh) {
49
+ if (this.activeHandle === 'high') {
50
+ // Highlight active handle
51
+ bar += `${theme_1.theme.main}${ansi_1.ANSI.REVERSE}O${ansi_1.ANSI.RESET}`;
52
+ }
53
+ else {
54
+ bar += `${theme_1.theme.main}O${ansi_1.ANSI.RESET}`;
55
+ }
56
+ }
57
+ else if (i > posLow && i < posHigh) {
58
+ // Active range
59
+ bar += `${theme_1.theme.main}=${ansi_1.ANSI.RESET}`;
60
+ }
61
+ else {
62
+ // Dimmed
63
+ bar += symbols_1.symbols.line;
64
+ }
65
+ }
66
+ const unit = this.options.unit || '';
67
+ // Format the value display
68
+ let valueDisplay = '';
69
+ if (this.activeHandle === 'low') {
70
+ valueDisplay = `${ansi_1.ANSI.UNDERLINE}${low}${ansi_1.ANSI.RESET}-${high}`;
71
+ }
72
+ else {
73
+ valueDisplay = `${low}-${ansi_1.ANSI.UNDERLINE}${high}${ansi_1.ANSI.RESET}`;
74
+ }
75
+ const output = `${theme_1.theme.success}?${ansi_1.ANSI.RESET} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET} [${bar}] ${valueDisplay}${unit}`;
76
+ this.renderFrame(output);
77
+ }
78
+ handleInput(char) {
79
+ if (char === '\r' || char === '\n') {
80
+ this.submit(this.value);
81
+ return;
82
+ }
83
+ if (char === ' ' || char === '\t') {
84
+ this.activeHandle = this.activeHandle === 'low' ? 'high' : 'low';
85
+ this.render(false);
86
+ return;
87
+ }
88
+ const step = this.options.step || 1;
89
+ let [low, high] = this.value;
90
+ if (this.isLeft(char)) { // Left
91
+ if (this.activeHandle === 'low') {
92
+ low = Math.max(this.options.min, low - step);
93
+ }
94
+ else {
95
+ high = Math.max(low, high - step);
96
+ }
97
+ }
98
+ if (this.isRight(char)) { // Right
99
+ if (this.activeHandle === 'low') {
100
+ low = Math.min(high, low + step);
101
+ }
102
+ else {
103
+ high = Math.min(this.options.max, high + step);
104
+ }
105
+ }
106
+ // Rounding to avoid floating point errors
107
+ low = Math.round(low * 10000) / 10000;
108
+ high = Math.round(high * 10000) / 10000;
109
+ this.value = [low, high];
110
+ this.render(false);
111
+ }
112
+ handleMouse(event) {
113
+ if (event.action === 'scroll') {
114
+ const step = this.options.step || 1;
115
+ let [low, high] = this.value;
116
+ if (event.scroll === 'up') { // Increase
117
+ if (this.activeHandle === 'low') {
118
+ low = Math.min(high, low + step);
119
+ }
120
+ else {
121
+ high = Math.min(this.options.max, high + step);
122
+ }
123
+ }
124
+ if (event.scroll === 'down') { // Decrease
125
+ if (this.activeHandle === 'low') {
126
+ low = Math.max(this.options.min, low - step);
127
+ }
128
+ else {
129
+ high = Math.max(low, high - step);
130
+ }
131
+ }
132
+ // Rounding
133
+ low = Math.round(low * 10000) / 10000;
134
+ high = Math.round(high * 10000) / 10000;
135
+ this.value = [low, high];
136
+ this.render(false);
137
+ }
138
+ }
139
+ }
140
+ exports.RangePrompt = RangePrompt;
@@ -2,7 +2,7 @@ import { Prompt } from '../base';
2
2
  import { RatingOptions, MouseEvent } from '../types';
3
3
  export declare class RatingPrompt extends Prompt<number, RatingOptions> {
4
4
  constructor(options: RatingOptions);
5
- protected render(firstRender: boolean): void;
5
+ protected render(_firstRender: boolean): void;
6
6
  protected handleInput(char: string): void;
7
7
  protected handleMouse(event: MouseEvent): void;
8
8
  }
@@ -11,7 +11,7 @@ class RatingPrompt extends base_1.Prompt {
11
11
  // Default to min if initial is not provided
12
12
  this.value = options.initial ?? (options.min || 1);
13
13
  }
14
- render(firstRender) {
14
+ render(_firstRender) {
15
15
  const min = this.options.min || 1;
16
16
  const max = this.options.max || 5;
17
17
  // Render stars
@@ -9,7 +9,7 @@ export declare class SelectPrompt<V> extends Prompt<any, SelectOptions<V>> {
9
9
  private isSeparator;
10
10
  private findNextSelectableIndex;
11
11
  private getFilteredChoices;
12
- protected render(firstRender: boolean): void;
12
+ protected render(_firstRender: boolean): void;
13
13
  protected handleInput(char: string): void;
14
14
  protected handleMouse(event: MouseEvent): void;
15
15
  }
@@ -50,7 +50,7 @@ class SelectPrompt extends base_1.Prompt {
50
50
  return c.title.toLowerCase().includes(this.searchBuffer.toLowerCase());
51
51
  });
52
52
  }
53
- render(firstRender) {
53
+ render(_firstRender) {
54
54
  let output = '';
55
55
  const choices = this.getFilteredChoices();
56
56
  // Adjust Scroll Top
@@ -2,7 +2,7 @@ import { Prompt } from '../base';
2
2
  import { SliderOptions, MouseEvent } from '../types';
3
3
  export declare class SliderPrompt extends Prompt<number, SliderOptions> {
4
4
  constructor(options: SliderOptions);
5
- protected render(firstRender: boolean): void;
5
+ protected render(_firstRender: boolean): void;
6
6
  protected handleInput(char: string): void;
7
7
  protected handleMouse(event: MouseEvent): void;
8
8
  }
@@ -11,7 +11,7 @@ class SliderPrompt extends base_1.Prompt {
11
11
  super(options);
12
12
  this.value = options.initial ?? options.min;
13
13
  }
14
- render(firstRender) {
14
+ render(_firstRender) {
15
15
  const width = 20;
16
16
  const range = this.options.max - this.options.min;
17
17
  const ratio = (this.value - this.options.min) / range;
@@ -0,0 +1,18 @@
1
+ import { Prompt } from '../base';
2
+ import { SnippetOptions, MouseEvent } from '../types';
3
+ export declare class SnippetPrompt extends Prompt<string, SnippetOptions> {
4
+ private tokens;
5
+ private variableTokens;
6
+ private values;
7
+ private activeVarIndex;
8
+ private cursor;
9
+ private errorMsg;
10
+ private lastLinesUp;
11
+ constructor(options: SnippetOptions);
12
+ private parseTemplate;
13
+ protected render(firstRender: boolean): void;
14
+ protected handleInput(char: string, _key: Buffer): void;
15
+ protected handleMouse(event: MouseEvent): void;
16
+ private moveFocus;
17
+ private submitSnippet;
18
+ }
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SnippetPrompt = void 0;
4
+ const ansi_1 = require("../ansi");
5
+ const base_1 = require("../base");
6
+ const theme_1 = require("../theme");
7
+ class SnippetPrompt extends base_1.Prompt {
8
+ constructor(options) {
9
+ super(options);
10
+ this.tokens = [];
11
+ this.variableTokens = []; // Indices in this.tokens
12
+ this.values = {};
13
+ this.activeVarIndex = 0; // Index in variableTokens
14
+ this.cursor = 0; // Cursor in active variable value
15
+ this.errorMsg = '';
16
+ this.lastLinesUp = 0;
17
+ this.parseTemplate();
18
+ // Initialize values
19
+ if (options.values) {
20
+ this.values = { ...options.values };
21
+ }
22
+ // Ensure all vars have entries
23
+ this.variableTokens.forEach(idx => {
24
+ const varName = this.tokens[idx].value;
25
+ if (this.values[varName] === undefined) {
26
+ this.values[varName] = '';
27
+ }
28
+ });
29
+ if (this.variableTokens.length > 0) {
30
+ const firstVar = this.tokens[this.variableTokens[0]].value;
31
+ this.cursor = this.values[firstVar].length;
32
+ }
33
+ }
34
+ parseTemplate() {
35
+ const regex = /\$\{([a-zA-Z0-9_]+)\}/g;
36
+ let lastIndex = 0;
37
+ let match;
38
+ while ((match = regex.exec(this.options.template)) !== null) {
39
+ if (match.index > lastIndex) {
40
+ this.tokens.push({ type: 'static', value: this.options.template.substring(lastIndex, match.index) });
41
+ }
42
+ this.tokens.push({ type: 'variable', value: match[1] });
43
+ this.variableTokens.push(this.tokens.length - 1);
44
+ lastIndex = regex.lastIndex;
45
+ }
46
+ if (lastIndex < this.options.template.length) {
47
+ this.tokens.push({ type: 'static', value: this.options.template.substring(lastIndex) });
48
+ }
49
+ }
50
+ render(firstRender) {
51
+ if (!firstRender && this.lastLinesUp > 0) {
52
+ this.print(`\x1b[${this.lastLinesUp}B`);
53
+ }
54
+ this.lastLinesUp = 0;
55
+ // Build the string
56
+ let output = '';
57
+ let cursorVisualIndex = 0;
58
+ let currentVisualIndex = 0;
59
+ // Prefix/Message
60
+ const prefix = `${theme_1.theme.success}? ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message || 'Fill snippet'}${ansi_1.ANSI.RESET}\n`;
61
+ output += prefix;
62
+ // cursorVisualIndex should start after prefix?
63
+ // Actually renderFrame handles newlines.
64
+ // We will construct the snippet line.
65
+ let snippetLine = '';
66
+ this.tokens.forEach((token, index) => {
67
+ if (token.type === 'static') {
68
+ snippetLine += `${theme_1.theme.muted}${token.value}${ansi_1.ANSI.RESET}`;
69
+ currentVisualIndex += token.value.length; // assuming simple ascii/static length
70
+ }
71
+ else {
72
+ const isFocused = this.variableTokens[this.activeVarIndex] === index;
73
+ const val = this.values[token.value] || '';
74
+ // Placeholder if empty?
75
+ const displayVal = val.length === 0 && isFocused ? '' : val; // maybe show placeholder?
76
+ let styledVal = displayVal;
77
+ if (isFocused) {
78
+ styledVal = `${ansi_1.ANSI.UNDERLINE}${theme_1.theme.main}${displayVal}${ansi_1.ANSI.RESET}`;
79
+ // Calculate cursor position
80
+ cursorVisualIndex = currentVisualIndex + this.cursor;
81
+ }
82
+ else {
83
+ styledVal = `${theme_1.theme.main}${displayVal}${ansi_1.ANSI.RESET}`;
84
+ }
85
+ snippetLine += styledVal;
86
+ currentVisualIndex += displayVal.length;
87
+ }
88
+ });
89
+ output += snippetLine;
90
+ if (this.errorMsg) {
91
+ output += `\n${theme_1.theme.error}>> ${this.errorMsg}${ansi_1.ANSI.RESET}`;
92
+ }
93
+ output += `\n${theme_1.theme.muted}(Tab to next variable, Enter to submit)${ansi_1.ANSI.RESET}`;
94
+ this.renderFrame(output);
95
+ // Position Cursor
96
+ this.print(ansi_1.ANSI.SHOW_CURSOR);
97
+ // We need to move to correct line and column
98
+ // Lines:
99
+ // 1. Message
100
+ // 2. Snippet (cursor here)
101
+ // 3. Error (optional)
102
+ // 4. Hint
103
+ // snippetLine is at index 1 (0-based) if Message has no newlines.
104
+ // Prefix ends with \n. So snippetLine is on 2nd line.
105
+ // Calculate which row relative to bottom the snippet line is.
106
+ // If error: 4 lines total. Snippet is line 1 (2nd). Lines up = 2.
107
+ // If no error: 3 lines total. Snippet is line 1. Lines up = 1.
108
+ let linesUp = 1;
109
+ if (this.errorMsg)
110
+ linesUp++;
111
+ if (linesUp > 0) {
112
+ this.print(`\x1b[${linesUp}A`);
113
+ this.lastLinesUp = linesUp;
114
+ }
115
+ this.print(ansi_1.ANSI.CURSOR_LEFT);
116
+ if (cursorVisualIndex > 0) {
117
+ this.print(`\x1b[${cursorVisualIndex}C`);
118
+ }
119
+ }
120
+ handleInput(char, _key) {
121
+ // Navigation: Tab / Shift+Tab
122
+ if (char === '\u001b[Z') {
123
+ // Shift Tab -> Prev
124
+ this.moveFocus(-1);
125
+ return;
126
+ }
127
+ if (char === '\t') {
128
+ this.moveFocus(1);
129
+ return;
130
+ }
131
+ // Enter
132
+ if (char === '\r' || char === '\n') {
133
+ this.submitSnippet();
134
+ return;
135
+ }
136
+ // Editing
137
+ const activeTokenIdx = this.variableTokens[this.activeVarIndex];
138
+ const varName = this.tokens[activeTokenIdx].value;
139
+ const val = this.values[varName];
140
+ if (char === '\u0008' || char === '\x7f') { // Backspace
141
+ if (this.cursor > 0) {
142
+ const pre = val.slice(0, this.cursor - 1);
143
+ const post = val.slice(this.cursor);
144
+ this.values[varName] = pre + post;
145
+ this.cursor--;
146
+ this.render(false);
147
+ }
148
+ return;
149
+ }
150
+ if (this.isLeft(char)) {
151
+ if (this.cursor > 0)
152
+ this.cursor--;
153
+ this.render(false);
154
+ return;
155
+ }
156
+ if (this.isRight(char)) {
157
+ if (this.cursor < val.length)
158
+ this.cursor++;
159
+ this.render(false);
160
+ return;
161
+ }
162
+ if (!/^[\x00-\x1F]/.test(char) && !char.startsWith('\x1b')) {
163
+ const pre = val.slice(0, this.cursor);
164
+ const post = val.slice(this.cursor);
165
+ this.values[varName] = pre + char + post;
166
+ this.cursor += char.length;
167
+ this.render(false);
168
+ }
169
+ }
170
+ handleMouse(event) {
171
+ if (event.action === 'scroll') {
172
+ if (event.scroll === 'up') {
173
+ this.moveFocus(-1);
174
+ }
175
+ else if (event.scroll === 'down') {
176
+ this.moveFocus(1);
177
+ }
178
+ }
179
+ }
180
+ moveFocus(direction) {
181
+ const nextIndex = this.activeVarIndex + direction;
182
+ if (nextIndex >= 0 && nextIndex < this.variableTokens.length) {
183
+ this.activeVarIndex = nextIndex;
184
+ const varName = this.tokens[this.variableTokens[this.activeVarIndex]].value;
185
+ this.cursor = this.values[varName].length;
186
+ this.render(false);
187
+ }
188
+ }
189
+ submitSnippet() {
190
+ // Construct final string
191
+ let result = '';
192
+ this.tokens.forEach(token => {
193
+ if (token.type === 'static') {
194
+ result += token.value;
195
+ }
196
+ else {
197
+ result += this.values[token.value] || '';
198
+ }
199
+ });
200
+ this.submit(result);
201
+ }
202
+ }
203
+ exports.SnippetPrompt = SnippetPrompt;
@@ -7,7 +7,7 @@ export declare class SortPrompt extends Prompt<string[], SortOptions> {
7
7
  private scrollTop;
8
8
  private readonly pageSize;
9
9
  constructor(options: SortOptions);
10
- protected render(firstRender: boolean): void;
10
+ protected render(_firstRender: boolean): void;
11
11
  protected handleInput(char: string): void;
12
12
  private swap;
13
13
  protected handleMouse(event: MouseEvent): void;
@@ -14,7 +14,7 @@ class SortPrompt extends base_1.Prompt {
14
14
  this.pageSize = 10;
15
15
  this.items = [...options.items];
16
16
  }
17
- render(firstRender) {
17
+ render(_firstRender) {
18
18
  // Adjust Scroll Top
19
19
  if (this.selectedIndex < this.scrollTop) {
20
20
  this.scrollTop = this.selectedIndex;
@@ -120,9 +120,6 @@ class SortPrompt extends base_1.Prompt {
120
120
  swap(i, j) {
121
121
  [this.items[i], this.items[j]] = [this.items[j], this.items[i]];
122
122
  }
123
- // Mouse support?
124
- // Drag and drop is hard with just clicks/scroll.
125
- // Maybe click to grab, scroll to move?
126
123
  handleMouse(event) {
127
124
  // Simple scroll support for navigation
128
125
  if (event.action === 'scroll') {
@@ -0,0 +1,17 @@
1
+ import { Prompt } from '../base';
2
+ import { BaseOptions } from '../types';
3
+ interface SpamOptions extends BaseOptions {
4
+ threshold: number;
5
+ spamKey?: string;
6
+ decay?: boolean;
7
+ }
8
+ export declare class SpamPrompt extends Prompt<boolean, SpamOptions> {
9
+ private count;
10
+ private width;
11
+ private decayTimer?;
12
+ constructor(options: SpamOptions);
13
+ protected cleanup(): void;
14
+ protected render(_firstRender: boolean): void;
15
+ protected handleInput(char: string): void;
16
+ }
17
+ export {};
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SpamPrompt = 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
+ class SpamPrompt extends base_1.Prompt {
9
+ constructor(options) {
10
+ super(options);
11
+ this.count = 0;
12
+ this.width = 20; // Visual width of the bar
13
+ if (options.decay) {
14
+ this.decayTimer = setInterval(() => {
15
+ if (this.count > 0) {
16
+ this.count = Math.max(0, this.count - 1);
17
+ this.render(false);
18
+ }
19
+ }, 200); // Drop 5 presses per second
20
+ }
21
+ }
22
+ cleanup() {
23
+ if (this.decayTimer)
24
+ clearInterval(this.decayTimer);
25
+ super.cleanup();
26
+ }
27
+ render(_firstRender) {
28
+ const progress = Math.min(this.count / this.options.threshold, 1);
29
+ const filledLen = Math.round(progress * this.width);
30
+ const emptyLen = this.width - filledLen;
31
+ // Visual Bar: [#####-----]
32
+ const filled = symbols_1.symbols.line.repeat(filledLen).replace(/./g, '#'); // Or use block char
33
+ const empty = symbols_1.symbols.line.repeat(emptyLen);
34
+ const barColor = progress === 1 ? theme_1.theme.success : theme_1.theme.error;
35
+ const bar = `${theme_1.theme.muted}[${barColor}${filled}${theme_1.theme.muted}${empty}]${ansi_1.ANSI.RESET}`;
36
+ let output = `${theme_1.theme.error}${symbols_1.symbols.cross} ${ansi_1.ANSI.BOLD}${theme_1.theme.title}${this.options.message}${ansi_1.ANSI.RESET}\n`;
37
+ output += ` ${bar} ${Math.floor(progress * 100)}%`;
38
+ if (this.count >= this.options.threshold) {
39
+ output += ` ${theme_1.theme.success} READY! Press Enter${ansi_1.ANSI.RESET}`;
40
+ }
41
+ else {
42
+ output += ` ${theme_1.theme.muted}(Mash '${this.options.spamKey || 'Space'}' to fill)${ansi_1.ANSI.RESET}`;
43
+ }
44
+ this.renderFrame(output);
45
+ }
46
+ handleInput(char) {
47
+ // Confirm execution
48
+ if (this.count >= this.options.threshold && (char === '\r' || char === '\n')) {
49
+ this.submit(true);
50
+ return;
51
+ }
52
+ const trigger = this.options.spamKey || ' ';
53
+ // Check if key matches (or any key if not specified)
54
+ if (char === trigger) {
55
+ if (this.count < this.options.threshold) {
56
+ this.count++;
57
+ this.render(false);
58
+ }
59
+ }
60
+ }
61
+ }
62
+ exports.SpamPrompt = SpamPrompt;
@@ -7,7 +7,7 @@ export declare class TablePrompt<V> extends Prompt<V, TableOptions<V>> {
7
7
  private colWidths;
8
8
  constructor(options: TableOptions<V>);
9
9
  private calculateColWidths;
10
- protected render(firstRender: boolean): void;
10
+ protected render(_firstRender: boolean): void;
11
11
  private pad;
12
12
  protected handleInput(char: string): void;
13
13
  protected handleMouse(event: MouseEvent): void;
@@ -28,7 +28,7 @@ class TablePrompt extends base_1.Prompt {
28
28
  // Add padding
29
29
  this.colWidths = this.colWidths.map(w => w + 2);
30
30
  }
31
- render(firstRender) {
31
+ render(_firstRender) {
32
32
  // Scroll Logic
33
33
  if (this.selectedIndex < this.scrollTop) {
34
34
  this.scrollTop = this.selectedIndex;
@@ -5,6 +5,7 @@ export declare class TextPrompt extends Prompt<string, TextOptions> {
5
5
  private cursor;
6
6
  private hasTyped;
7
7
  private segments;
8
+ private lastLinesUp;
8
9
  constructor(options: TextOptions);
9
10
  protected render(firstRender: boolean): void;
10
11
  private getSegmentWidth;