mepcli 0.3.0 → 0.5.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 (44) hide show
  1. package/README.md +59 -4
  2. package/dist/ansi.d.ts +3 -0
  3. package/dist/ansi.js +4 -0
  4. package/dist/base.d.ts +6 -0
  5. package/dist/base.js +18 -0
  6. package/dist/core.d.ts +8 -3
  7. package/dist/core.js +20 -24
  8. package/dist/input.d.ts +1 -0
  9. package/dist/input.js +62 -8
  10. package/dist/prompts/autocomplete.d.ts +22 -0
  11. package/dist/prompts/autocomplete.js +175 -0
  12. package/dist/prompts/checkbox.d.ts +2 -1
  13. package/dist/prompts/checkbox.js +14 -4
  14. package/dist/prompts/confirm.d.ts +2 -1
  15. package/dist/prompts/confirm.js +6 -0
  16. package/dist/prompts/date.d.ts +3 -1
  17. package/dist/prompts/date.js +62 -31
  18. package/dist/prompts/file.js +0 -6
  19. package/dist/prompts/multi-select.d.ts +2 -1
  20. package/dist/prompts/multi-select.js +15 -0
  21. package/dist/prompts/number.d.ts +2 -1
  22. package/dist/prompts/number.js +22 -0
  23. package/dist/prompts/rating.d.ts +8 -0
  24. package/dist/prompts/rating.js +78 -0
  25. package/dist/prompts/select.d.ts +2 -1
  26. package/dist/prompts/select.js +15 -0
  27. package/dist/prompts/slider.d.ts +2 -1
  28. package/dist/prompts/slider.js +14 -0
  29. package/dist/prompts/sort.d.ts +14 -0
  30. package/dist/prompts/sort.js +160 -0
  31. package/dist/prompts/table.d.ts +14 -0
  32. package/dist/prompts/table.js +106 -0
  33. package/dist/prompts/text.js +0 -50
  34. package/dist/prompts/toggle.d.ts +2 -1
  35. package/dist/prompts/toggle.js +6 -0
  36. package/dist/spinner.d.ts +33 -0
  37. package/dist/spinner.js +89 -0
  38. package/dist/symbols.d.ts +4 -0
  39. package/dist/symbols.js +6 -2
  40. package/dist/types.d.ts +32 -0
  41. package/dist/utils.d.ts +1 -0
  42. package/dist/utils.js +4 -1
  43. package/example.ts +60 -11
  44. package/package.json +1 -1
@@ -37,6 +37,18 @@ class DatePrompt extends base_1.Prompt {
37
37
  }
38
38
  handleInput(char) {
39
39
  if (char === '\r' || char === '\n') {
40
+ // Min constraint check
41
+ if (this.options.min && this.value < this.options.min) {
42
+ this.errorMsg = 'Date cannot be before minimum allowed.';
43
+ this.render(false);
44
+ return;
45
+ }
46
+ // Max constraint check
47
+ if (this.options.max && this.value > this.options.max) {
48
+ this.errorMsg = 'Date cannot be after maximum allowed.';
49
+ this.render(false);
50
+ return;
51
+ }
40
52
  this.submit(this.value);
41
53
  return;
42
54
  }
@@ -89,7 +101,16 @@ class DatePrompt extends base_1.Prompt {
89
101
  else if (this.selectedField === 4)
90
102
  d.setMinutes(Math.max(0, Math.min(59, finalVal)));
91
103
  this.value = d;
92
- this.errorMsg = '';
104
+ // Check immediately after updating the value to display an error message (but still allow further input)
105
+ if (this.options.min && this.value < this.options.min) {
106
+ this.errorMsg = 'Warning: Date is before minimum.';
107
+ }
108
+ else if (this.options.max && this.value > this.options.max) {
109
+ this.errorMsg = 'Warning: Date is after maximum.';
110
+ }
111
+ else {
112
+ this.errorMsg = '';
113
+ }
93
114
  this.render(false);
94
115
  return;
95
116
  }
@@ -99,39 +120,49 @@ class DatePrompt extends base_1.Prompt {
99
120
  if (isUp || isDown) {
100
121
  this.inputBuffer = ''; // Reset buffer on arrow move
101
122
  const dir = isUp ? 1 : -1;
102
- const d = new Date(this.value);
103
- switch (this.selectedField) {
104
- case 0:
105
- d.setFullYear(d.getFullYear() + dir);
106
- break;
107
- case 1:
108
- d.setMonth(d.getMonth() + dir);
109
- break;
110
- case 2:
111
- d.setDate(d.getDate() + dir);
112
- break;
113
- case 3:
114
- d.setHours(d.getHours() + dir);
115
- break;
116
- case 4:
117
- d.setMinutes(d.getMinutes() + dir);
118
- break;
119
- }
120
- let valid = true;
121
- if (this.options.min && d < this.options.min) {
122
- this.errorMsg = 'Date cannot be before minimum allowed.';
123
- valid = false;
124
- }
125
- if (this.options.max && d > this.options.max) {
126
- this.errorMsg = 'Date cannot be after maximum allowed.';
127
- valid = false;
123
+ this.adjustDate(dir);
124
+ }
125
+ }
126
+ handleMouse(event) {
127
+ if (event.action === 'scroll') {
128
+ if (event.scroll === 'up') {
129
+ this.adjustDate(1);
128
130
  }
129
- if (valid) {
130
- this.value = d;
131
- this.errorMsg = '';
131
+ else if (event.scroll === 'down') {
132
+ this.adjustDate(-1);
132
133
  }
133
- this.render(false);
134
134
  }
135
135
  }
136
+ adjustDate(dir) {
137
+ const d = new Date(this.value);
138
+ switch (this.selectedField) {
139
+ case 0:
140
+ d.setFullYear(d.getFullYear() + dir);
141
+ break;
142
+ case 1:
143
+ d.setMonth(d.getMonth() + dir);
144
+ break;
145
+ case 2:
146
+ d.setDate(d.getDate() + dir);
147
+ break;
148
+ case 3:
149
+ d.setHours(d.getHours() + dir);
150
+ break;
151
+ case 4:
152
+ d.setMinutes(d.getMinutes() + dir);
153
+ break;
154
+ }
155
+ this.value = d;
156
+ if (this.options.min && this.value < this.options.min) {
157
+ this.errorMsg = 'Date cannot be before minimum allowed.';
158
+ }
159
+ else if (this.options.max && this.value > this.options.max) {
160
+ this.errorMsg = 'Date cannot be after maximum allowed.';
161
+ }
162
+ else {
163
+ this.errorMsg = '';
164
+ }
165
+ this.render(false);
166
+ }
136
167
  }
137
168
  exports.DatePrompt = DatePrompt;
@@ -131,12 +131,6 @@ class FilePrompt extends base_1.Prompt {
131
131
  // Move right
132
132
  const prefix = `${icon} ${theme_1.theme.title}${this.options.message} `;
133
133
  const prefixLen = this.stripAnsi(prefix).length;
134
- // Cursor is usually at the end of input unless we add backspace support etc.
135
- // The cursor property tracks it, but my handleInput simplified it.
136
- // Let's rely on this.input.length for now since handleInput appends.
137
- // Ah, handleInput logic below supports cursor pos theoretically but I only see appending?
138
- // Actually handleInput doesn't support left/right in the original code, it supports down/up for suggestions.
139
- // So cursor is always at end.
140
134
  const targetCol = prefixLen + this.input.length;
141
135
  this.print(ansi_1.ANSI.CURSOR_LEFT);
142
136
  if (targetCol > 0)
@@ -1,5 +1,5 @@
1
1
  import { Prompt } from '../base';
2
- import { MultiSelectOptions } from '../types';
2
+ import { MultiSelectOptions, MouseEvent } from '../types';
3
3
  export declare class MultiSelectPrompt<V> extends Prompt<any[], MultiSelectOptions<V>> {
4
4
  private selectedIndex;
5
5
  private checkedState;
@@ -11,4 +11,5 @@ export declare class MultiSelectPrompt<V> extends Prompt<any[], MultiSelectOptio
11
11
  private getFilteredChoices;
12
12
  protected render(firstRender: boolean): void;
13
13
  protected handleInput(char: string): void;
14
+ protected handleMouse(event: MouseEvent): void;
14
15
  }
@@ -120,5 +120,20 @@ class MultiSelectPrompt extends base_1.Prompt {
120
120
  this.render(false);
121
121
  }
122
122
  }
123
+ handleMouse(event) {
124
+ const choices = this.getFilteredChoices();
125
+ if (choices.length === 0)
126
+ return;
127
+ if (event.action === 'scroll') {
128
+ if (event.scroll === 'up') {
129
+ this.selectedIndex = (this.selectedIndex - 1 + choices.length) % choices.length;
130
+ this.render(false);
131
+ }
132
+ else if (event.scroll === 'down') {
133
+ this.selectedIndex = (this.selectedIndex + 1) % choices.length;
134
+ this.render(false);
135
+ }
136
+ }
137
+ }
123
138
  }
124
139
  exports.MultiSelectPrompt = MultiSelectPrompt;
@@ -1,5 +1,5 @@
1
1
  import { Prompt } from '../base';
2
- import { NumberOptions } from '../types';
2
+ import { NumberOptions, MouseEvent } from '../types';
3
3
  export declare class NumberPrompt extends Prompt<number, NumberOptions> {
4
4
  private stringValue;
5
5
  private cursor;
@@ -7,4 +7,5 @@ export declare class NumberPrompt extends Prompt<number, NumberOptions> {
7
7
  constructor(options: NumberOptions);
8
8
  protected render(firstRender: boolean): void;
9
9
  protected handleInput(char: string): void;
10
+ protected handleMouse(event: MouseEvent): void;
10
11
  }
@@ -130,5 +130,27 @@ class NumberPrompt extends base_1.Prompt {
130
130
  this.render(false);
131
131
  }
132
132
  }
133
+ handleMouse(event) {
134
+ if (event.action === 'scroll') {
135
+ let num = parseFloat(this.stringValue) || 0;
136
+ const step = this.options.step ?? 1;
137
+ if (event.scroll === 'up') {
138
+ num += step;
139
+ if (this.options.max !== undefined && num > this.options.max)
140
+ num = this.options.max;
141
+ }
142
+ else if (event.scroll === 'down') {
143
+ num -= step;
144
+ if (this.options.min !== undefined && num < this.options.min)
145
+ num = this.options.min;
146
+ }
147
+ // Round to avoid float errors
148
+ num = Math.round(num * 10000) / 10000;
149
+ this.stringValue = num.toString();
150
+ this.cursor = this.stringValue.length;
151
+ this.errorMsg = '';
152
+ this.render(false);
153
+ }
154
+ }
133
155
  }
134
156
  exports.NumberPrompt = NumberPrompt;
@@ -0,0 +1,8 @@
1
+ import { Prompt } from '../base';
2
+ import { RatingOptions, MouseEvent } from '../types';
3
+ export declare class RatingPrompt extends Prompt<number, RatingOptions> {
4
+ constructor(options: RatingOptions);
5
+ protected render(firstRender: boolean): void;
6
+ protected handleInput(char: string): void;
7
+ protected handleMouse(event: MouseEvent): void;
8
+ }
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RatingPrompt = 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 RatingPrompt extends base_1.Prompt {
9
+ constructor(options) {
10
+ super(options);
11
+ // Default to min if initial is not provided
12
+ this.value = options.initial ?? (options.min || 1);
13
+ }
14
+ render(firstRender) {
15
+ const min = this.options.min || 1;
16
+ const max = this.options.max || 5;
17
+ // Render stars
18
+ let stars = '';
19
+ for (let i = min; i <= max; i++) {
20
+ if (i <= this.value) {
21
+ stars += `${theme_1.theme.success}${symbols_1.symbols.star}${ansi_1.ANSI.RESET} `;
22
+ }
23
+ else {
24
+ stars += `${theme_1.theme.muted}${symbols_1.symbols.starEmpty}${ansi_1.ANSI.RESET} `;
25
+ }
26
+ }
27
+ 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} ${stars}`;
28
+ this.renderFrame(output);
29
+ }
30
+ handleInput(char) {
31
+ const min = this.options.min || 1;
32
+ const max = this.options.max || 5;
33
+ if (char === '\r' || char === '\n') {
34
+ this.submit(this.value);
35
+ return;
36
+ }
37
+ // Arrow keys
38
+ if (this.isLeft(char) || this.isDown(char)) { // Left/Down decreases
39
+ if (this.value > min) {
40
+ this.value--;
41
+ this.render(false);
42
+ }
43
+ }
44
+ else if (this.isRight(char) || this.isUp(char)) { // Right/Up increases
45
+ if (this.value < max) {
46
+ this.value++;
47
+ this.render(false);
48
+ }
49
+ }
50
+ // Number keys (1-9)
51
+ const num = parseInt(char);
52
+ if (!isNaN(num)) {
53
+ if (num >= min && num <= max) {
54
+ this.value = num;
55
+ this.render(false);
56
+ }
57
+ }
58
+ }
59
+ handleMouse(event) {
60
+ const min = this.options.min || 1;
61
+ const max = this.options.max || 5;
62
+ if (event.action === 'scroll') {
63
+ if (event.scroll === 'up') {
64
+ if (this.value < max) {
65
+ this.value++;
66
+ this.render(false);
67
+ }
68
+ }
69
+ else if (event.scroll === 'down') {
70
+ if (this.value > min) {
71
+ this.value--;
72
+ this.render(false);
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ exports.RatingPrompt = RatingPrompt;
@@ -1,5 +1,5 @@
1
1
  import { Prompt } from '../base';
2
- import { SelectOptions } from '../types';
2
+ import { SelectOptions, MouseEvent } from '../types';
3
3
  export declare class SelectPrompt<V> extends Prompt<any, SelectOptions<V>> {
4
4
  private selectedIndex;
5
5
  private searchBuffer;
@@ -11,4 +11,5 @@ export declare class SelectPrompt<V> extends Prompt<any, SelectOptions<V>> {
11
11
  private getFilteredChoices;
12
12
  protected render(firstRender: boolean): void;
13
13
  protected handleInput(char: string): void;
14
+ protected handleMouse(event: MouseEvent): void;
14
15
  }
@@ -145,5 +145,20 @@ class SelectPrompt extends base_1.Prompt {
145
145
  this.render(false);
146
146
  }
147
147
  }
148
+ handleMouse(event) {
149
+ const choices = this.getFilteredChoices();
150
+ if (choices.length === 0)
151
+ return;
152
+ if (event.action === 'scroll') {
153
+ if (event.scroll === 'up') {
154
+ this.selectedIndex = this.findNextSelectableIndex(this.selectedIndex, -1);
155
+ this.render(false);
156
+ }
157
+ else if (event.scroll === 'down') {
158
+ this.selectedIndex = this.findNextSelectableIndex(this.selectedIndex, 1);
159
+ this.render(false);
160
+ }
161
+ }
162
+ }
148
163
  }
149
164
  exports.SelectPrompt = SelectPrompt;
@@ -1,7 +1,8 @@
1
1
  import { Prompt } from '../base';
2
- import { SliderOptions } from '../types';
2
+ import { SliderOptions, MouseEvent } from '../types';
3
3
  export declare class SliderPrompt extends Prompt<number, SliderOptions> {
4
4
  constructor(options: SliderOptions);
5
5
  protected render(firstRender: boolean): void;
6
6
  protected handleInput(char: string): void;
7
+ protected handleMouse(event: MouseEvent): void;
7
8
  }
@@ -46,5 +46,19 @@ class SliderPrompt extends base_1.Prompt {
46
46
  this.render(false);
47
47
  }
48
48
  }
49
+ handleMouse(event) {
50
+ if (event.action === 'scroll') {
51
+ const step = this.options.step || 1;
52
+ if (event.scroll === 'up') { // Scroll Up -> Increase
53
+ this.value = Math.min(this.options.max, this.value + step);
54
+ }
55
+ if (event.scroll === 'down') { // Scroll Down -> Decrease
56
+ this.value = Math.max(this.options.min, this.value - step);
57
+ }
58
+ // Round to avoid float errors
59
+ this.value = Math.round(this.value * 10000) / 10000;
60
+ this.render(false);
61
+ }
62
+ }
49
63
  }
50
64
  exports.SliderPrompt = SliderPrompt;
@@ -0,0 +1,14 @@
1
+ import { Prompt } from '../base';
2
+ import { SortOptions, MouseEvent } from '../types';
3
+ export declare class SortPrompt extends Prompt<string[], SortOptions> {
4
+ private items;
5
+ private selectedIndex;
6
+ private grabbedIndex;
7
+ private scrollTop;
8
+ private readonly pageSize;
9
+ constructor(options: SortOptions);
10
+ protected render(firstRender: boolean): void;
11
+ protected handleInput(char: string): void;
12
+ private swap;
13
+ protected handleMouse(event: MouseEvent): void;
14
+ }
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SortPrompt = 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 SortPrompt extends base_1.Prompt {
9
+ constructor(options) {
10
+ super(options);
11
+ this.selectedIndex = 0;
12
+ this.grabbedIndex = null;
13
+ this.scrollTop = 0;
14
+ this.pageSize = 10;
15
+ this.items = [...options.items];
16
+ }
17
+ render(firstRender) {
18
+ // Adjust Scroll Top
19
+ if (this.selectedIndex < this.scrollTop) {
20
+ this.scrollTop = this.selectedIndex;
21
+ }
22
+ else if (this.selectedIndex >= this.scrollTop + this.pageSize) {
23
+ this.scrollTop = this.selectedIndex - this.pageSize + 1;
24
+ }
25
+ // Ensure valid scroll (handle list shrinking?) - list doesn't shrink here but good practice
26
+ this.scrollTop = Math.max(0, Math.min(this.scrollTop, this.items.length - this.pageSize));
27
+ if (this.scrollTop < 0)
28
+ this.scrollTop = 0;
29
+ let output = '';
30
+ // Header
31
+ output += `${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}(Press <space> to grab, arrows to move, <enter> to confirm)${ansi_1.ANSI.RESET}\n`;
32
+ const visibleItems = this.items.slice(this.scrollTop, this.scrollTop + this.pageSize);
33
+ visibleItems.forEach((item, index) => {
34
+ const actualIndex = this.scrollTop + index;
35
+ if (index > 0)
36
+ output += '\n';
37
+ const isSelected = actualIndex === this.selectedIndex;
38
+ const isGrabbed = actualIndex === this.grabbedIndex;
39
+ // Pointer
40
+ let prefix = ' ';
41
+ if (isSelected) {
42
+ if (isGrabbed) {
43
+ prefix = `${theme_1.theme.main}${symbols_1.symbols.pointer}${symbols_1.symbols.pointer} `; // Double pointer for grabbed?
44
+ }
45
+ else {
46
+ prefix = `${theme_1.theme.main}${symbols_1.symbols.pointer} `;
47
+ }
48
+ }
49
+ else if (isGrabbed) {
50
+ // Should not happen if we move grabbed item with cursor
51
+ // But if logic differs, maybe.
52
+ }
53
+ // Item Content
54
+ let content = item;
55
+ if (isGrabbed) {
56
+ content = `${ansi_1.ANSI.BOLD}${theme_1.theme.main}${content}${ansi_1.ANSI.RESET}`;
57
+ }
58
+ else if (isSelected) {
59
+ content = `${theme_1.theme.main}${content}${ansi_1.ANSI.RESET}`;
60
+ }
61
+ // Index indicator? Maybe not needed, minimalist.
62
+ output += `${prefix}${content}`;
63
+ });
64
+ this.renderFrame(output);
65
+ }
66
+ handleInput(char) {
67
+ // Enter
68
+ if (char === '\r' || char === '\n') {
69
+ this.submit(this.items);
70
+ return;
71
+ }
72
+ // Space (Grab/Drop)
73
+ if (char === ' ') {
74
+ if (this.grabbedIndex === null) {
75
+ this.grabbedIndex = this.selectedIndex;
76
+ }
77
+ else {
78
+ this.grabbedIndex = null;
79
+ }
80
+ this.render(false);
81
+ return;
82
+ }
83
+ // Up
84
+ if (this.isUp(char)) {
85
+ if (this.grabbedIndex !== null) {
86
+ // Move item up
87
+ if (this.selectedIndex > 0) {
88
+ const newIndex = this.selectedIndex - 1;
89
+ this.swap(this.selectedIndex, newIndex);
90
+ this.selectedIndex = newIndex;
91
+ this.grabbedIndex = newIndex;
92
+ }
93
+ }
94
+ else {
95
+ // Move cursor up
96
+ this.selectedIndex = this.selectedIndex > 0 ? this.selectedIndex - 1 : this.items.length - 1;
97
+ }
98
+ this.render(false);
99
+ return;
100
+ }
101
+ // Down
102
+ if (this.isDown(char)) {
103
+ if (this.grabbedIndex !== null) {
104
+ // Move item down
105
+ if (this.selectedIndex < this.items.length - 1) {
106
+ const newIndex = this.selectedIndex + 1;
107
+ this.swap(this.selectedIndex, newIndex);
108
+ this.selectedIndex = newIndex;
109
+ this.grabbedIndex = newIndex;
110
+ }
111
+ }
112
+ else {
113
+ // Move cursor down
114
+ this.selectedIndex = this.selectedIndex < this.items.length - 1 ? this.selectedIndex + 1 : 0;
115
+ }
116
+ this.render(false);
117
+ return;
118
+ }
119
+ }
120
+ swap(i, j) {
121
+ [this.items[i], this.items[j]] = [this.items[j], this.items[i]];
122
+ }
123
+ // Mouse support?
124
+ // Drag and drop is hard with just clicks/scroll.
125
+ // Maybe click to grab, scroll to move?
126
+ handleMouse(event) {
127
+ // Simple scroll support for navigation
128
+ if (event.action === 'scroll') {
129
+ if (event.scroll === 'up') {
130
+ if (this.grabbedIndex !== null) {
131
+ if (this.selectedIndex > 0) {
132
+ const newIndex = this.selectedIndex - 1;
133
+ this.swap(this.selectedIndex, newIndex);
134
+ this.selectedIndex = newIndex;
135
+ this.grabbedIndex = newIndex;
136
+ }
137
+ }
138
+ else {
139
+ this.selectedIndex = this.selectedIndex > 0 ? this.selectedIndex - 1 : this.items.length - 1;
140
+ }
141
+ this.render(false);
142
+ }
143
+ else if (event.scroll === 'down') {
144
+ if (this.grabbedIndex !== null) {
145
+ if (this.selectedIndex < this.items.length - 1) {
146
+ const newIndex = this.selectedIndex + 1;
147
+ this.swap(this.selectedIndex, newIndex);
148
+ this.selectedIndex = newIndex;
149
+ this.grabbedIndex = newIndex;
150
+ }
151
+ }
152
+ else {
153
+ this.selectedIndex = this.selectedIndex < this.items.length - 1 ? this.selectedIndex + 1 : 0;
154
+ }
155
+ this.render(false);
156
+ }
157
+ }
158
+ }
159
+ }
160
+ exports.SortPrompt = SortPrompt;
@@ -0,0 +1,14 @@
1
+ import { Prompt } from '../base';
2
+ import { TableOptions, MouseEvent } from '../types';
3
+ export declare class TablePrompt<V> extends Prompt<V, TableOptions<V>> {
4
+ private selectedIndex;
5
+ private scrollTop;
6
+ private readonly pageSize;
7
+ private colWidths;
8
+ constructor(options: TableOptions<V>);
9
+ private calculateColWidths;
10
+ protected render(firstRender: boolean): void;
11
+ private pad;
12
+ protected handleInput(char: string): void;
13
+ protected handleMouse(event: MouseEvent): void;
14
+ }
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TablePrompt = 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 TablePrompt extends base_1.Prompt {
10
+ constructor(options) {
11
+ super(options);
12
+ this.selectedIndex = 0;
13
+ this.scrollTop = 0;
14
+ this.colWidths = [];
15
+ this.pageSize = options.rows || 7;
16
+ this.calculateColWidths();
17
+ }
18
+ calculateColWidths() {
19
+ const { columns, data } = this.options;
20
+ this.colWidths = columns.map(c => (0, utils_1.stringWidth)(c));
21
+ data.forEach(row => {
22
+ row.row.forEach((cell, idx) => {
23
+ if (idx < this.colWidths.length) {
24
+ this.colWidths[idx] = Math.max(this.colWidths[idx], (0, utils_1.stringWidth)(cell));
25
+ }
26
+ });
27
+ });
28
+ // Add padding
29
+ this.colWidths = this.colWidths.map(w => w + 2);
30
+ }
31
+ render(firstRender) {
32
+ // Scroll Logic
33
+ if (this.selectedIndex < this.scrollTop) {
34
+ this.scrollTop = this.selectedIndex;
35
+ }
36
+ else if (this.selectedIndex >= this.scrollTop + this.pageSize) {
37
+ this.scrollTop = this.selectedIndex - this.pageSize + 1;
38
+ }
39
+ const maxScroll = Math.max(0, this.options.data.length - this.pageSize);
40
+ this.scrollTop = Math.min(this.scrollTop, maxScroll);
41
+ let output = '';
42
+ // Title
43
+ 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`;
44
+ // Table Header
45
+ let headerStr = ' '; // Indent for pointer space
46
+ this.options.columns.forEach((col, i) => {
47
+ headerStr += this.pad(col, this.colWidths[i]);
48
+ });
49
+ output += `${ansi_1.ANSI.BOLD}${headerStr}${ansi_1.ANSI.RESET}\n`;
50
+ // Table Body
51
+ const visibleRows = this.options.data.slice(this.scrollTop, this.scrollTop + this.pageSize);
52
+ visibleRows.forEach((item, index) => {
53
+ const actualIndex = this.scrollTop + index;
54
+ if (index > 0)
55
+ output += '\n';
56
+ const isSelected = actualIndex === this.selectedIndex;
57
+ const pointer = isSelected ? `${theme_1.theme.main}${symbols_1.symbols.pointer}${ansi_1.ANSI.RESET} ` : ' ';
58
+ let rowStr = '';
59
+ item.row.forEach((cell, colIdx) => {
60
+ const width = this.colWidths[colIdx];
61
+ let cellStr = this.pad(cell, width);
62
+ if (isSelected) {
63
+ cellStr = `${theme_1.theme.main}${cellStr}${ansi_1.ANSI.RESET}`;
64
+ }
65
+ rowStr += cellStr;
66
+ });
67
+ output += `${pointer}${rowStr}`;
68
+ });
69
+ this.renderFrame(output);
70
+ }
71
+ pad(str, width) {
72
+ const len = (0, utils_1.stringWidth)(str);
73
+ if (len >= width)
74
+ return str;
75
+ return str + ' '.repeat(width - len);
76
+ }
77
+ handleInput(char) {
78
+ if (char === '\r' || char === '\n') {
79
+ this.submit(this.options.data[this.selectedIndex].value);
80
+ return;
81
+ }
82
+ if (this.isUp(char)) {
83
+ this.selectedIndex = this.selectedIndex > 0 ? this.selectedIndex - 1 : this.options.data.length - 1;
84
+ this.render(false);
85
+ return;
86
+ }
87
+ if (this.isDown(char)) {
88
+ this.selectedIndex = this.selectedIndex < this.options.data.length - 1 ? this.selectedIndex + 1 : 0;
89
+ this.render(false);
90
+ return;
91
+ }
92
+ }
93
+ handleMouse(event) {
94
+ if (event.action === 'scroll') {
95
+ if (event.scroll === 'up') {
96
+ this.selectedIndex = this.selectedIndex > 0 ? this.selectedIndex - 1 : this.options.data.length - 1;
97
+ this.render(false);
98
+ }
99
+ else if (event.scroll === 'down') {
100
+ this.selectedIndex = this.selectedIndex < this.options.data.length - 1 ? this.selectedIndex + 1 : 0;
101
+ this.render(false);
102
+ }
103
+ }
104
+ }
105
+ }
106
+ exports.TablePrompt = TablePrompt;