@reliverse/relinka 1.1.7 → 1.1.8
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.
- package/dist-npm/components/anykey/index.js +57 -77
- package/dist-npm/components/block/block.js +48 -61
- package/dist-npm/components/checkbox/index.js +178 -211
- package/dist-npm/components/confirm/confirm-main.js +85 -122
- package/dist-npm/components/confirm/confirm-three.js +24 -27
- package/dist-npm/components/confirm/index.js +36 -45
- package/dist-npm/components/core/Separator.js +15 -17
- package/dist-npm/components/core/create-prompt.js +101 -124
- package/dist-npm/components/core/errors.js +19 -15
- package/dist-npm/components/core/hook-engine.js +91 -120
- package/dist-npm/components/core/index.js +12 -12
- package/dist-npm/components/core/key.js +16 -6
- package/dist-npm/components/core/lines.js +45 -54
- package/dist-npm/components/core/make-theme.js +21 -30
- package/dist-npm/components/core/position.js +27 -23
- package/dist-npm/components/core/promise-polyfill.js +11 -14
- package/dist-npm/components/core/screen-manager.js +59 -74
- package/dist-npm/components/core/theme.js +22 -32
- package/dist-npm/components/core/use-effect.js +9 -15
- package/dist-npm/components/core/use-keypress.js +19 -23
- package/dist-npm/components/core/use-memo.js +10 -16
- package/dist-npm/components/core/use-pagination.js +33 -32
- package/dist-npm/components/core/use-prefix.js +40 -38
- package/dist-npm/components/core/use-ref.js +2 -5
- package/dist-npm/components/core/use-state.js +15 -23
- package/dist-npm/components/core/useKeyPress.js +14 -17
- package/dist-npm/components/core/usePromptState.js +8 -14
- package/dist-npm/components/core/utils.js +7 -16
- package/dist-npm/components/date/date.js +173 -204
- package/dist-npm/components/editor/index.js +71 -92
- package/dist-npm/components/expand/index.js +96 -124
- package/dist-npm/components/figures/index.js +283 -294
- package/dist-npm/components/input/index.js +61 -87
- package/dist-npm/components/input/text-main.js +97 -124
- package/dist-npm/components/input/text.js +24 -28
- package/dist-npm/components/instance/basic.js +17 -25
- package/dist-npm/components/instance/browser.js +14 -18
- package/dist-npm/components/instance/reporter/basic.js +46 -65
- package/dist-npm/components/instance/reporter/browser.js +44 -47
- package/dist-npm/components/instance/reporter/fancy.js +83 -96
- package/dist-npm/components/instance/shared.js +2 -2
- package/dist-npm/components/mono/mono.js +52 -62
- package/dist-npm/components/mono/monoTwo.js +35 -49
- package/dist-npm/components/multiselect/group-multiselect.js +55 -71
- package/dist-npm/components/multiselect/multi-select-two.js +97 -130
- package/dist-npm/components/multiselect/multi-select.js +43 -49
- package/dist-npm/components/multiselect/multiselect-main.d.ts +1 -0
- package/dist-npm/components/multiselect/multiselect-main.js +158 -145
- package/dist-npm/components/multiselect/num-multi-select.js +97 -130
- package/dist-npm/components/multiselect/num-multiselect-main.js +24 -35
- package/dist-npm/components/next-steps/next-steps.js +23 -25
- package/dist-npm/components/number/index.js +78 -112
- package/dist-npm/components/number/number-main.js +95 -2
- package/dist-npm/components/password/index.js +54 -73
- package/dist-npm/components/password/password-main.js +119 -2
- package/dist-npm/components/password/password-three.js +26 -30
- package/dist-npm/components/progressbar/ProgressBar.js +45 -64
- package/dist-npm/components/progressbar/helper.js +33 -40
- package/dist-npm/components/progressbar/index.js +1 -1
- package/dist-npm/components/prompts/create.js +29 -44
- package/dist-npm/components/prompts/index.d.ts +1 -0
- package/dist-npm/components/prompts/index.js +46 -45
- package/dist-npm/components/prompts/prompt.js +211 -260
- package/dist-npm/components/prompts/promptTwo.js +561 -605
- package/dist-npm/components/prompts/relinka.js +237 -295
- package/dist-npm/components/range/range.js +247 -294
- package/dist-npm/components/rawlist/index.js +87 -107
- package/dist-npm/components/results/results.js +31 -37
- package/dist-npm/components/search/index.js +148 -193
- package/dist-npm/components/select/index.js +148 -186
- package/dist-npm/components/select/num-select-main.js +27 -27
- package/dist-npm/components/select/num-select.js +124 -5
- package/dist-npm/components/select/select-key.js +24 -25
- package/dist-npm/components/select/select-main.d.ts +1 -0
- package/dist-npm/components/select/select-main.js +143 -133
- package/dist-npm/components/select/select-three.js +32 -36
- package/dist-npm/components/select/select-two.js +94 -87
- package/dist-npm/components/spinner/index.js +107 -136
- package/dist-npm/components/st-end/end.js +34 -26
- package/dist-npm/components/st-end/start.js +29 -15
- package/dist-npm/components/toggle/index.js +113 -137
- package/dist-npm/components/visual/animate/animate.js +53 -10
- package/dist-npm/components/visual/ascii-art/ascii-art.js +12 -1
- package/dist-npm/main.js +1 -0
- package/dist-npm/testing/index.js +58 -83
- package/dist-npm/types/general.d.ts +1 -1
- package/dist-npm/types/general.js +0 -1
- package/dist-npm/types/index.js +2 -3
- package/dist-npm/types/keypress.js +35 -36
- package/dist-npm/types/readline.js +0 -1
- package/dist-npm/types/relinka.js +0 -1
- package/dist-npm/types/utils.js +0 -1
- package/dist-npm/utils/box.js +135 -137
- package/dist-npm/utils/color.js +65 -74
- package/dist-npm/utils/colorize.js +124 -156
- package/dist-npm/utils/component.js +532 -657
- package/dist-npm/utils/constants.js +64 -63
- package/dist-npm/utils/core.js +2 -3
- package/dist-npm/utils/decoder.js +244 -223
- package/dist-npm/utils/error.js +4 -9
- package/dist-npm/utils/errors.js +14 -4
- package/dist-npm/utils/format.js +19 -24
- package/dist-npm/utils/keypress.js +316 -414
- package/dist-npm/utils/log.js +11 -15
- package/dist-npm/utils/mapping.js +45 -52
- package/dist-npm/utils/messages.js +196 -183
- package/dist-npm/utils/platforms.js +16 -20
- package/dist-npm/utils/prompt-tmp.js +235 -286
- package/dist-npm/utils/prompt-two.js +235 -286
- package/dist-npm/utils/readline.js +5 -7
- package/dist-npm/utils/skeleton.js +130 -170
- package/dist-npm/utils/stream.js +2 -2
- package/dist-npm/utils/string.js +44 -58
- package/dist-npm/utils/terminal.js +23 -34
- package/dist-npm/utils/tree.js +30 -41
- package/dist-npm/utils/types.js +0 -1
- package/dist-npm/utils/utils.js +8 -8
- package/dist-npm/utils/variants.js +36 -44
- package/package.json +14 -14
- package/dist-npm/mod.js +0 -2
- /package/dist-npm/{mod.d.ts → main.d.ts} +0 -0
|
@@ -1,214 +1,176 @@
|
|
|
1
|
-
import ansiEscapes from
|
|
2
|
-
import colors from
|
|
1
|
+
import ansiEscapes from "ansi-escapes";
|
|
2
|
+
import colors from "picocolors";
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
} from
|
|
21
|
-
import figures from
|
|
22
|
-
|
|
23
|
-
const isString = (a) => typeof a === 'string';
|
|
24
|
-
|
|
4
|
+
createPrompt,
|
|
5
|
+
useState,
|
|
6
|
+
useKeypress,
|
|
7
|
+
usePrefix,
|
|
8
|
+
usePagination,
|
|
9
|
+
useRef,
|
|
10
|
+
useMemo,
|
|
11
|
+
useEffect,
|
|
12
|
+
isBackspaceKey,
|
|
13
|
+
isEnterKey,
|
|
14
|
+
isUpKey,
|
|
15
|
+
isDownKey,
|
|
16
|
+
isNumberKey,
|
|
17
|
+
Separator,
|
|
18
|
+
ValidationError,
|
|
19
|
+
makeTheme
|
|
20
|
+
} from "../../components/core/index.js";
|
|
21
|
+
import figures from "../../components/figures/index.js";
|
|
25
22
|
const selectTheme = {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
},
|
|
33
|
-
helpMode: 'auto',
|
|
23
|
+
icon: { cursor: figures.pointer },
|
|
24
|
+
style: {
|
|
25
|
+
disabled: (text) => colors.dim(`- ${text}`),
|
|
26
|
+
description: (text) => colors.cyan(text)
|
|
27
|
+
},
|
|
28
|
+
helpMode: "auto"
|
|
34
29
|
};
|
|
35
|
-
|
|
36
30
|
function isSelectable(item) {
|
|
37
|
-
|
|
31
|
+
return !Separator.isSeparator(item) && !item.disabled;
|
|
38
32
|
}
|
|
39
|
-
|
|
40
33
|
function normalizeChoices(choices) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
disabled: choice.disabled ?? false,
|
|
63
|
-
};
|
|
64
|
-
});
|
|
34
|
+
return choices.map((choice) => {
|
|
35
|
+
if (Separator.isSeparator(choice)) {
|
|
36
|
+
return choice;
|
|
37
|
+
}
|
|
38
|
+
if (typeof choice === "string") {
|
|
39
|
+
return {
|
|
40
|
+
value: choice,
|
|
41
|
+
name: choice,
|
|
42
|
+
short: choice,
|
|
43
|
+
disabled: false
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const name = choice.name ?? String(choice.value);
|
|
47
|
+
return {
|
|
48
|
+
value: choice.value,
|
|
49
|
+
name,
|
|
50
|
+
description: choice.description,
|
|
51
|
+
short: choice.short ?? name,
|
|
52
|
+
disabled: choice.disabled ?? false
|
|
53
|
+
};
|
|
54
|
+
});
|
|
65
55
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const {loop = true, pageSize = 7} = config;
|
|
56
|
+
const select = createPrompt(
|
|
57
|
+
(config, done) => {
|
|
58
|
+
const { loop = true, pageSize = 7 } = config;
|
|
69
59
|
const firstRender = useRef(true);
|
|
70
60
|
const theme = makeTheme(selectTheme, config.theme);
|
|
71
|
-
const [status, setStatus] = useState(
|
|
72
|
-
const prefix = usePrefix({
|
|
73
|
-
status,
|
|
74
|
-
theme,
|
|
75
|
-
});
|
|
61
|
+
const [status, setStatus] = useState("idle");
|
|
62
|
+
const prefix = usePrefix({ status, theme });
|
|
76
63
|
const searchTimeoutRef = useRef();
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
64
|
+
const items = useMemo(
|
|
65
|
+
() => normalizeChoices(config.choices),
|
|
66
|
+
[config.choices]
|
|
67
|
+
);
|
|
80
68
|
const bounds = useMemo(() => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
first,
|
|
90
|
-
last,
|
|
91
|
-
};
|
|
69
|
+
const first = items.findIndex(isSelectable);
|
|
70
|
+
const last = items.findLastIndex(isSelectable);
|
|
71
|
+
if (first === -1) {
|
|
72
|
+
throw new ValidationError(
|
|
73
|
+
"[select prompt] No selectable choices. All choices are disabled."
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return { first, last };
|
|
92
77
|
}, [items]);
|
|
93
|
-
|
|
94
78
|
const defaultItemIndex = useMemo(() => {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
79
|
+
if (!("default" in config)) {
|
|
80
|
+
return -1;
|
|
81
|
+
}
|
|
82
|
+
return items.findIndex(
|
|
83
|
+
(item) => isSelectable(item) && item.value === config.default
|
|
84
|
+
);
|
|
100
85
|
}, [config.default, items]);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
86
|
+
const [active, setActive] = useState(
|
|
87
|
+
defaultItemIndex === -1 ? bounds.first : defaultItemIndex
|
|
88
|
+
);
|
|
104
89
|
const selectedChoice = items[active];
|
|
105
|
-
|
|
106
90
|
useKeypress((key, rl) => {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
.name
|
|
141
|
-
.toLowerCase()
|
|
142
|
-
.startsWith(searchTerm);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
if (matchIndex !== -1) {
|
|
146
|
-
setActive(matchIndex);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
searchTimeoutRef.current = setTimeout(() => {
|
|
150
|
-
rl.clearLine(0);
|
|
151
|
-
}, 700);
|
|
91
|
+
clearTimeout(searchTimeoutRef.current);
|
|
92
|
+
if (isEnterKey(key)) {
|
|
93
|
+
setStatus("done");
|
|
94
|
+
done(selectedChoice.value);
|
|
95
|
+
} else if (isUpKey(key) || isDownKey(key)) {
|
|
96
|
+
rl.clearLine(0);
|
|
97
|
+
if (loop || isUpKey(key) && active !== bounds.first || isDownKey(key) && active !== bounds.last) {
|
|
98
|
+
const offset = isUpKey(key) ? -1 : 1;
|
|
99
|
+
let next = active;
|
|
100
|
+
do {
|
|
101
|
+
next = (next + offset + items.length) % items.length;
|
|
102
|
+
} while (!isSelectable(items[next]));
|
|
103
|
+
setActive(next);
|
|
104
|
+
}
|
|
105
|
+
} else if (isNumberKey(key)) {
|
|
106
|
+
rl.clearLine(0);
|
|
107
|
+
const position = Number(key.name) - 1;
|
|
108
|
+
const item = items[position];
|
|
109
|
+
if (item != null && isSelectable(item)) {
|
|
110
|
+
setActive(position);
|
|
111
|
+
}
|
|
112
|
+
} else if (isBackspaceKey(key)) {
|
|
113
|
+
rl.clearLine(0);
|
|
114
|
+
} else {
|
|
115
|
+
const searchTerm = rl.line.toLowerCase();
|
|
116
|
+
const matchIndex = items.findIndex((item) => {
|
|
117
|
+
if (Separator.isSeparator(item) || !isSelectable(item)) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
return item.name.toLowerCase().startsWith(searchTerm);
|
|
121
|
+
});
|
|
122
|
+
if (matchIndex !== -1) {
|
|
123
|
+
setActive(matchIndex);
|
|
152
124
|
}
|
|
153
|
-
|
|
154
|
-
|
|
125
|
+
searchTimeoutRef.current = setTimeout(() => {
|
|
126
|
+
rl.clearLine(0);
|
|
127
|
+
}, 700);
|
|
128
|
+
}
|
|
155
129
|
});
|
|
156
|
-
useEffect(
|
|
130
|
+
useEffect(
|
|
131
|
+
() => () => {
|
|
157
132
|
clearTimeout(searchTimeoutRef.current);
|
|
158
|
-
|
|
133
|
+
},
|
|
134
|
+
[]
|
|
135
|
+
);
|
|
159
136
|
const message = theme.style.message(config.message, status);
|
|
160
|
-
let helpTipTop =
|
|
161
|
-
let helpTipBottom =
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
}
|
|
137
|
+
let helpTipTop = "";
|
|
138
|
+
let helpTipBottom = "";
|
|
139
|
+
if (theme.helpMode === "always" || theme.helpMode === "auto" && firstRender.current) {
|
|
140
|
+
firstRender.current = false;
|
|
141
|
+
if (items.length > pageSize) {
|
|
142
|
+
helpTipBottom = `
|
|
143
|
+
${theme.style.help("(Use arrow keys to reveal more choices)")}`;
|
|
144
|
+
} else {
|
|
145
|
+
helpTipTop = theme.style.help("(Use arrow keys)");
|
|
146
|
+
}
|
|
171
147
|
}
|
|
172
|
-
|
|
173
148
|
const page = usePagination({
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
},
|
|
191
|
-
pageSize,
|
|
192
|
-
loop,
|
|
149
|
+
items,
|
|
150
|
+
active,
|
|
151
|
+
renderItem({ item, isActive }) {
|
|
152
|
+
if (Separator.isSeparator(item)) {
|
|
153
|
+
return ` ${item.separator}`;
|
|
154
|
+
}
|
|
155
|
+
if (item.disabled) {
|
|
156
|
+
const disabledLabel = typeof item.disabled === "string" ? item.disabled : "(disabled)";
|
|
157
|
+
return theme.style.disabled(`${item.name} ${disabledLabel}`);
|
|
158
|
+
}
|
|
159
|
+
const color = isActive ? theme.style.highlight : (x) => x;
|
|
160
|
+
const cursor = isActive ? theme.icon.cursor : ` `;
|
|
161
|
+
return color(`${cursor} ${item.name}`);
|
|
162
|
+
},
|
|
163
|
+
pageSize,
|
|
164
|
+
loop
|
|
193
165
|
});
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
return `${prefix} ${message} ${theme.style.answer(selectedChoice.short)}`;
|
|
166
|
+
if (status === "done") {
|
|
167
|
+
return `${prefix} ${message} ${theme.style.answer(selectedChoice.short)}`;
|
|
197
168
|
}
|
|
198
|
-
|
|
199
169
|
const choiceDescription = selectedChoice.description ? `
|
|
200
170
|
${theme.style.description(selectedChoice.description)}` : ``;
|
|
201
|
-
|
|
202
|
-
return `${[
|
|
203
|
-
prefix,
|
|
204
|
-
message,
|
|
205
|
-
helpTipTop,
|
|
206
|
-
]
|
|
207
|
-
.filter(Boolean)
|
|
208
|
-
.join(' ')}
|
|
171
|
+
return `${[prefix, message, helpTipTop].filter(Boolean).join(" ")}
|
|
209
172
|
${page}${helpTipBottom}${choiceDescription}${ansiEscapes.cursorHide}`;
|
|
210
|
-
}
|
|
211
|
-
|
|
173
|
+
}
|
|
174
|
+
);
|
|
212
175
|
export default select;
|
|
213
|
-
|
|
214
|
-
export {Separator} from '../../components/core/index.js';
|
|
176
|
+
export { Separator } from "../../components/core/index.js";
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import { stdin as input, stdout as output } from "process";
|
|
2
|
+
import readline from "readline/promises";
|
|
3
|
+
export async function selectPrompt(params) {
|
|
4
|
+
const { message, options, initial } = params;
|
|
5
|
+
const selectedIndex = initial ? options.findIndex((option) => option.value === initial) : 0;
|
|
6
|
+
const rl = readline.createInterface({ input, output });
|
|
7
|
+
while (true) {
|
|
8
|
+
console.log(`
|
|
9
|
+
${message}`);
|
|
10
|
+
options.forEach((option, index2) => {
|
|
11
|
+
const prefix = index2 === selectedIndex ? "->" : " ";
|
|
12
|
+
const isDefault = option.value === initial ? "(default)" : "";
|
|
13
|
+
console.log(`${prefix} [${index2 + 1}] ${option.label} ${isDefault}`);
|
|
12
14
|
});
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
index = selectedIndex;
|
|
21
|
-
} else {
|
|
22
|
-
index = parseInt(response.trim(), 10) - 1;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (index >= 0 && index < options.length) {
|
|
26
|
-
rl.close();
|
|
27
|
-
return options[index].value;
|
|
28
|
-
}
|
|
15
|
+
const promptMessage = initial !== void 0 ? `Please select an option by number (default ${selectedIndex + 1}): ` : "Please select an option by number: ";
|
|
16
|
+
const response = await rl.question(promptMessage);
|
|
17
|
+
let index;
|
|
18
|
+
if (response.trim() === "" && initial !== void 0) {
|
|
19
|
+
index = selectedIndex;
|
|
20
|
+
} else {
|
|
21
|
+
index = parseInt(response.trim(), 10) - 1;
|
|
29
22
|
}
|
|
23
|
+
if (index >= 0 && index < options.length) {
|
|
24
|
+
rl.close();
|
|
25
|
+
return options[index].value;
|
|
26
|
+
} else {
|
|
27
|
+
console.log("Invalid selection. Please try again.");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
30
|
}
|
|
@@ -1,6 +1,125 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { Value } from "@sinclair/typebox/value";
|
|
2
|
+
import { stdin as input, stdout as output } from "node:process";
|
|
3
|
+
import readline from "node:readline/promises";
|
|
4
|
+
import { colorize } from "../../utils/colorize.js";
|
|
5
|
+
import { fmt, msg, bar } from "../../utils/messages.js";
|
|
6
|
+
import {
|
|
7
|
+
countLines,
|
|
8
|
+
deleteLastLine,
|
|
9
|
+
deleteLastLines
|
|
10
|
+
} from "../../utils/terminal.js";
|
|
11
|
+
export async function numSelectPrompt(options) {
|
|
12
|
+
const {
|
|
13
|
+
title,
|
|
14
|
+
hint,
|
|
15
|
+
validate,
|
|
16
|
+
defaultValue,
|
|
17
|
+
schema,
|
|
18
|
+
titleColor = "cyanBright",
|
|
19
|
+
titleTypography = "bold",
|
|
20
|
+
titleVariant,
|
|
21
|
+
content,
|
|
22
|
+
contentColor,
|
|
23
|
+
contentTypography,
|
|
24
|
+
contentVariant,
|
|
25
|
+
borderColor = "viceGradient",
|
|
26
|
+
variantOptions,
|
|
27
|
+
inline = true,
|
|
28
|
+
choices
|
|
29
|
+
} = options;
|
|
30
|
+
if (!choices || choices.length === 0) {
|
|
31
|
+
throw new Error("Choices are required for select prompt.");
|
|
32
|
+
}
|
|
33
|
+
const rl = readline.createInterface({ input, output });
|
|
34
|
+
const formattedBar = bar({ borderColor });
|
|
35
|
+
let linesToDelete = 0;
|
|
36
|
+
let errorMessage = "";
|
|
37
|
+
while (true) {
|
|
38
|
+
if (linesToDelete > 0) {
|
|
39
|
+
deleteLastLines(linesToDelete);
|
|
4
40
|
}
|
|
5
|
-
|
|
6
|
-
|
|
41
|
+
const question = fmt({
|
|
42
|
+
type: errorMessage !== "" ? "M_ERROR" : "M_GENERAL",
|
|
43
|
+
title,
|
|
44
|
+
titleColor,
|
|
45
|
+
titleTypography,
|
|
46
|
+
titleVariant,
|
|
47
|
+
content,
|
|
48
|
+
contentColor,
|
|
49
|
+
contentTypography,
|
|
50
|
+
contentVariant,
|
|
51
|
+
borderColor,
|
|
52
|
+
hint,
|
|
53
|
+
variantOptions,
|
|
54
|
+
errorMessage
|
|
55
|
+
});
|
|
56
|
+
let choicesText = "";
|
|
57
|
+
if (inline) {
|
|
58
|
+
choicesText = choices.map(
|
|
59
|
+
(choice, index) => `${index + 1}) ${choice.title}${choice.description ? ` (${choice.description})` : ""}`
|
|
60
|
+
).join(" / ");
|
|
61
|
+
} else {
|
|
62
|
+
choicesText = choices.map(
|
|
63
|
+
(choice, index) => `${index + 1}) ${choice.title}${choice.description ? ` - ${choice.description}` : ""}`
|
|
64
|
+
).join(`
|
|
65
|
+
${formattedBar} `);
|
|
66
|
+
}
|
|
67
|
+
const formattedPrompt = fmt({
|
|
68
|
+
type: "M_NULL",
|
|
69
|
+
title: `${question}${choicesText}
|
|
70
|
+
${formattedBar} ${colorize(
|
|
71
|
+
`Enter your choice:`,
|
|
72
|
+
contentColor
|
|
73
|
+
)}
|
|
74
|
+
${formattedBar} `
|
|
75
|
+
});
|
|
76
|
+
const questionLines = countLines(formattedPrompt);
|
|
77
|
+
linesToDelete = questionLines + 1;
|
|
78
|
+
const prompt = await rl.question(formattedPrompt);
|
|
79
|
+
const answer = prompt.trim() || defaultValue;
|
|
80
|
+
if (!prompt.trim() && defaultValue !== void 0) {
|
|
81
|
+
deleteLastLine();
|
|
82
|
+
msg({
|
|
83
|
+
type: "M_MIDDLE",
|
|
84
|
+
title: ` ${defaultValue}`,
|
|
85
|
+
titleColor: "none"
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
const num = Number(answer);
|
|
89
|
+
if (isNaN(num) || num < 1 || num > choices.length) {
|
|
90
|
+
errorMessage = `Please enter a number between 1 and ${choices.length}.`;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const selectedChoice = choices[num - 1];
|
|
94
|
+
const selectedValue = selectedChoice?.id ?? num;
|
|
95
|
+
let isValid = true;
|
|
96
|
+
errorMessage = "";
|
|
97
|
+
if (schema) {
|
|
98
|
+
isValid = Value.Check(schema, selectedValue);
|
|
99
|
+
if (!isValid) {
|
|
100
|
+
const errors = [...Value.Errors(schema, selectedValue)];
|
|
101
|
+
if (errors.length > 0) {
|
|
102
|
+
errorMessage = errors[0]?.message ?? "Invalid input.";
|
|
103
|
+
} else {
|
|
104
|
+
errorMessage = "Invalid input.";
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (validate && isValid) {
|
|
109
|
+
const validation = await validate(selectedValue);
|
|
110
|
+
if (validation !== true) {
|
|
111
|
+
isValid = false;
|
|
112
|
+
errorMessage = typeof validation === "string" ? validation : "Invalid input.";
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (isValid) {
|
|
116
|
+
msg({ type: "M_NEWLINE" });
|
|
117
|
+
rl.close();
|
|
118
|
+
if (selectedChoice?.action) {
|
|
119
|
+
await selectedChoice.action();
|
|
120
|
+
}
|
|
121
|
+
return selectedValue;
|
|
122
|
+
} else {
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -1,27 +1,26 @@
|
|
|
1
|
-
import Prompt from
|
|
2
|
-
|
|
1
|
+
import Prompt from "../prompts/prompt.js";
|
|
3
2
|
export default class SelectKeyPrompt extends Prompt {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
3
|
+
options;
|
|
4
|
+
cursor = 0;
|
|
5
|
+
constructor(opts) {
|
|
6
|
+
super(opts, false);
|
|
7
|
+
this.options = opts.options;
|
|
8
|
+
const keys = this.options.map(
|
|
9
|
+
({ value: [initial] }) => initial?.toLowerCase()
|
|
10
|
+
);
|
|
11
|
+
this.cursor = Math.max(keys.indexOf(opts.initialValue), 0);
|
|
12
|
+
this.on("key", (key) => {
|
|
13
|
+
if (!keys.includes(key)) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const value = this.options.find(
|
|
17
|
+
({ value: [initial] }) => initial?.toLowerCase() === key
|
|
18
|
+
);
|
|
19
|
+
if (value) {
|
|
20
|
+
this.value = value.value;
|
|
21
|
+
this.state = "submit";
|
|
22
|
+
this.emit("submit");
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
27
26
|
}
|