@inquirer/select 4.3.3 → 4.4.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.
- package/README.md +27 -14
- package/dist/commonjs/index.d.ts +4 -1
- package/dist/commonjs/index.js +42 -22
- package/dist/esm/index.d.ts +4 -1
- package/dist/esm/index.js +42 -22
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -95,15 +95,14 @@ const answer = await select({
|
|
|
95
95
|
|
|
96
96
|
## Options
|
|
97
97
|
|
|
98
|
-
| Property
|
|
99
|
-
|
|
|
100
|
-
| message
|
|
101
|
-
| choices
|
|
102
|
-
| default
|
|
103
|
-
| pageSize
|
|
104
|
-
| loop
|
|
105
|
-
|
|
|
106
|
-
| theme | [See Theming](#Theming) | no | Customize look of the prompt. |
|
|
98
|
+
| Property | Type | Required | Description |
|
|
99
|
+
| -------- | ----------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
100
|
+
| message | `string` | yes | The question to ask |
|
|
101
|
+
| choices | `Choice[]` | yes | List of the available choices. |
|
|
102
|
+
| default | `string` | no | Defines in front of which item the cursor will initially appear. When omitted, the cursor will appear on the first selectable item. |
|
|
103
|
+
| pageSize | `number` | no | By default, lists of choice longer than 7 will be paginated. Use this option to control how many choices will appear on the screen at once. |
|
|
104
|
+
| loop | `boolean` | no | Defaults to `true`. When set to `false`, the cursor will be constrained to the top and bottom of the choice list without looping. |
|
|
105
|
+
| theme | [See Theming](#Theming) | no | Customize look of the prompt. |
|
|
107
106
|
|
|
108
107
|
`Separator` objects can be used in the `choices` array to render non-selectable lines in the choice list. By default it'll render a line, but you can provide the text as argument (`new Separator('-- Dependencies --')`). This option is often used to add labels to groups within long list of options.
|
|
109
108
|
|
|
@@ -150,20 +149,34 @@ type Theme = {
|
|
|
150
149
|
highlight: (text: string) => string;
|
|
151
150
|
description: (text: string) => string;
|
|
152
151
|
disabled: (text: string) => string;
|
|
152
|
+
keysHelpTip: (keys: [key: string, action: string][]) => string | undefined;
|
|
153
153
|
};
|
|
154
154
|
icon: {
|
|
155
155
|
cursor: string;
|
|
156
156
|
};
|
|
157
|
-
helpMode: 'always' | 'never' | 'auto';
|
|
158
157
|
indexMode: 'hidden' | 'number';
|
|
159
158
|
};
|
|
160
159
|
```
|
|
161
160
|
|
|
162
|
-
### `theme.
|
|
161
|
+
### `theme.style.keysHelpTip`
|
|
163
162
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
163
|
+
This function allows you to customize the keyboard shortcuts help tip displayed below the prompt. It receives an array of key-action pairs and should return a formatted string. You can also hook here to localize the labels to different languages.
|
|
164
|
+
|
|
165
|
+
It can also returns `undefined` to hide the help tip entirely. This is the replacement for the deprecated theme option `helpMode: 'never'`.
|
|
166
|
+
|
|
167
|
+
```js
|
|
168
|
+
theme: {
|
|
169
|
+
style: {
|
|
170
|
+
keysHelpTip: (keys) => {
|
|
171
|
+
// Return undefined to hide the help tip completely.
|
|
172
|
+
return undefined;
|
|
173
|
+
|
|
174
|
+
// Or customize the formatting. Or localize the labels.
|
|
175
|
+
return keys.map(([key, action]) => `${key}: ${action}`).join(' | ');
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
167
180
|
|
|
168
181
|
### `theme.indexMode`
|
|
169
182
|
|
package/dist/commonjs/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Separator, type Theme } from '@inquirer/core';
|
|
1
|
+
import { Separator, type Theme, type Keybinding } from '@inquirer/core';
|
|
2
2
|
import type { PartialDeep } from '@inquirer/type';
|
|
3
3
|
type SelectTheme = {
|
|
4
4
|
icon: {
|
|
@@ -7,9 +7,12 @@ type SelectTheme = {
|
|
|
7
7
|
style: {
|
|
8
8
|
disabled: (text: string) => string;
|
|
9
9
|
description: (text: string) => string;
|
|
10
|
+
keysHelpTip: (keys: [key: string, action: string][]) => string | undefined;
|
|
10
11
|
};
|
|
12
|
+
/** @deprecated Use theme.style.keysHelpTip instead */
|
|
11
13
|
helpMode: 'always' | 'never' | 'auto';
|
|
12
14
|
indexMode: 'hidden' | 'number';
|
|
15
|
+
keybindings: ReadonlyArray<Keybinding>;
|
|
13
16
|
};
|
|
14
17
|
type Choice<Value> = {
|
|
15
18
|
value: Value;
|
package/dist/commonjs/index.js
CHANGED
|
@@ -5,17 +5,21 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.Separator = void 0;
|
|
7
7
|
const core_1 = require("@inquirer/core");
|
|
8
|
+
const ansi_1 = require("@inquirer/ansi");
|
|
8
9
|
const yoctocolors_cjs_1 = __importDefault(require("yoctocolors-cjs"));
|
|
9
10
|
const figures_1 = __importDefault(require("@inquirer/figures"));
|
|
10
|
-
const ansi_escapes_1 = __importDefault(require("ansi-escapes"));
|
|
11
11
|
const selectTheme = {
|
|
12
12
|
icon: { cursor: figures_1.default.pointer },
|
|
13
13
|
style: {
|
|
14
14
|
disabled: (text) => yoctocolors_cjs_1.default.dim(`- ${text}`),
|
|
15
15
|
description: (text) => yoctocolors_cjs_1.default.cyan(text),
|
|
16
|
+
keysHelpTip: (keys) => keys
|
|
17
|
+
.map(([key, action]) => `${yoctocolors_cjs_1.default.bold(key)} ${yoctocolors_cjs_1.default.dim(action)}`)
|
|
18
|
+
.join(yoctocolors_cjs_1.default.dim(' • ')),
|
|
16
19
|
},
|
|
17
|
-
helpMode: '
|
|
20
|
+
helpMode: 'always',
|
|
18
21
|
indexMode: 'hidden',
|
|
22
|
+
keybindings: [],
|
|
19
23
|
};
|
|
20
24
|
function isSelectable(item) {
|
|
21
25
|
return !core_1.Separator.isSeparator(item) && !item.disabled;
|
|
@@ -47,11 +51,14 @@ function normalizeChoices(choices) {
|
|
|
47
51
|
}
|
|
48
52
|
exports.default = (0, core_1.createPrompt)((config, done) => {
|
|
49
53
|
const { loop = true, pageSize = 7 } = config;
|
|
50
|
-
const firstRender = (0, core_1.useRef)(true);
|
|
51
54
|
const theme = (0, core_1.makeTheme)(selectTheme, config.theme);
|
|
55
|
+
const { keybindings } = theme;
|
|
52
56
|
const [status, setStatus] = (0, core_1.useState)('idle');
|
|
53
57
|
const prefix = (0, core_1.usePrefix)({ status, theme });
|
|
54
58
|
const searchTimeoutRef = (0, core_1.useRef)();
|
|
59
|
+
// Vim keybindings (j/k) conflict with typing those letters in search,
|
|
60
|
+
// so search must be disabled when vim bindings are enabled
|
|
61
|
+
const searchEnabled = !keybindings.includes('vim');
|
|
55
62
|
const items = (0, core_1.useMemo)(() => normalizeChoices(config.choices), [config.choices]);
|
|
56
63
|
const bounds = (0, core_1.useMemo)(() => {
|
|
57
64
|
const first = items.findIndex(isSelectable);
|
|
@@ -75,12 +82,12 @@ exports.default = (0, core_1.createPrompt)((config, done) => {
|
|
|
75
82
|
setStatus('done');
|
|
76
83
|
done(selectedChoice.value);
|
|
77
84
|
}
|
|
78
|
-
else if ((0, core_1.isUpKey)(key) || (0, core_1.isDownKey)(key)) {
|
|
85
|
+
else if ((0, core_1.isUpKey)(key, keybindings) || (0, core_1.isDownKey)(key, keybindings)) {
|
|
79
86
|
rl.clearLine(0);
|
|
80
87
|
if (loop ||
|
|
81
|
-
((0, core_1.isUpKey)(key) && active !== bounds.first) ||
|
|
82
|
-
((0, core_1.isDownKey)(key) && active !== bounds.last)) {
|
|
83
|
-
const offset = (0, core_1.isUpKey)(key) ? -1 : 1;
|
|
88
|
+
((0, core_1.isUpKey)(key, keybindings) && active !== bounds.first) ||
|
|
89
|
+
((0, core_1.isDownKey)(key, keybindings) && active !== bounds.last)) {
|
|
90
|
+
const offset = (0, core_1.isUpKey)(key, keybindings) ? -1 : 1;
|
|
84
91
|
let next = active;
|
|
85
92
|
do {
|
|
86
93
|
next = (next + offset + items.length) % items.length;
|
|
@@ -109,8 +116,7 @@ exports.default = (0, core_1.createPrompt)((config, done) => {
|
|
|
109
116
|
else if ((0, core_1.isBackspaceKey)(key)) {
|
|
110
117
|
rl.clearLine(0);
|
|
111
118
|
}
|
|
112
|
-
else {
|
|
113
|
-
// Default to search
|
|
119
|
+
else if (searchEnabled) {
|
|
114
120
|
const searchTerm = rl.line.toLowerCase();
|
|
115
121
|
const matchIndex = items.findIndex((item) => {
|
|
116
122
|
if (core_1.Separator.isSeparator(item) || !isSelectable(item))
|
|
@@ -129,16 +135,20 @@ exports.default = (0, core_1.createPrompt)((config, done) => {
|
|
|
129
135
|
clearTimeout(searchTimeoutRef.current);
|
|
130
136
|
}, []);
|
|
131
137
|
const message = theme.style.message(config.message, status);
|
|
132
|
-
let
|
|
133
|
-
|
|
134
|
-
if (theme.helpMode
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
138
|
+
let helpLine;
|
|
139
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
140
|
+
if (theme.helpMode !== 'never') {
|
|
141
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
142
|
+
if (config.instructions) {
|
|
143
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
144
|
+
const { pager, navigation } = config.instructions;
|
|
145
|
+
helpLine = theme.style.help(items.length > pageSize ? pager : navigation);
|
|
139
146
|
}
|
|
140
147
|
else {
|
|
141
|
-
|
|
148
|
+
helpLine = theme.style.keysHelpTip([
|
|
149
|
+
['↑↓', 'navigate'],
|
|
150
|
+
['⏎', 'select'],
|
|
151
|
+
]);
|
|
142
152
|
}
|
|
143
153
|
}
|
|
144
154
|
let separatorCount = 0;
|
|
@@ -163,12 +173,22 @@ exports.default = (0, core_1.createPrompt)((config, done) => {
|
|
|
163
173
|
loop,
|
|
164
174
|
});
|
|
165
175
|
if (status === 'done') {
|
|
166
|
-
return
|
|
176
|
+
return [prefix, message, theme.style.answer(selectedChoice.short)]
|
|
177
|
+
.filter(Boolean)
|
|
178
|
+
.join(' ');
|
|
167
179
|
}
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
180
|
+
const { description } = selectedChoice;
|
|
181
|
+
const lines = [
|
|
182
|
+
[prefix, message].filter(Boolean).join(' '),
|
|
183
|
+
page,
|
|
184
|
+
' ',
|
|
185
|
+
description ? theme.style.description(description) : '',
|
|
186
|
+
helpLine,
|
|
187
|
+
]
|
|
188
|
+
.filter(Boolean)
|
|
189
|
+
.join('\n')
|
|
190
|
+
.trimEnd();
|
|
191
|
+
return `${lines}${ansi_1.cursorHide}`;
|
|
172
192
|
});
|
|
173
193
|
var core_2 = require("@inquirer/core");
|
|
174
194
|
Object.defineProperty(exports, "Separator", { enumerable: true, get: function () { return core_2.Separator; } });
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Separator, type Theme } from '@inquirer/core';
|
|
1
|
+
import { Separator, type Theme, type Keybinding } from '@inquirer/core';
|
|
2
2
|
import type { PartialDeep } from '@inquirer/type';
|
|
3
3
|
type SelectTheme = {
|
|
4
4
|
icon: {
|
|
@@ -7,9 +7,12 @@ type SelectTheme = {
|
|
|
7
7
|
style: {
|
|
8
8
|
disabled: (text: string) => string;
|
|
9
9
|
description: (text: string) => string;
|
|
10
|
+
keysHelpTip: (keys: [key: string, action: string][]) => string | undefined;
|
|
10
11
|
};
|
|
12
|
+
/** @deprecated Use theme.style.keysHelpTip instead */
|
|
11
13
|
helpMode: 'always' | 'never' | 'auto';
|
|
12
14
|
indexMode: 'hidden' | 'number';
|
|
15
|
+
keybindings: ReadonlyArray<Keybinding>;
|
|
13
16
|
};
|
|
14
17
|
type Choice<Value> = {
|
|
15
18
|
value: Value;
|
package/dist/esm/index.js
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { createPrompt, useState, useKeypress, usePrefix, usePagination, useRef, useMemo, useEffect, isBackspaceKey, isEnterKey, isUpKey, isDownKey, isNumberKey, Separator, ValidationError, makeTheme, } from '@inquirer/core';
|
|
2
|
+
import { cursorHide } from '@inquirer/ansi';
|
|
2
3
|
import colors from 'yoctocolors-cjs';
|
|
3
4
|
import figures from '@inquirer/figures';
|
|
4
|
-
import ansiEscapes from 'ansi-escapes';
|
|
5
5
|
const selectTheme = {
|
|
6
6
|
icon: { cursor: figures.pointer },
|
|
7
7
|
style: {
|
|
8
8
|
disabled: (text) => colors.dim(`- ${text}`),
|
|
9
9
|
description: (text) => colors.cyan(text),
|
|
10
|
+
keysHelpTip: (keys) => keys
|
|
11
|
+
.map(([key, action]) => `${colors.bold(key)} ${colors.dim(action)}`)
|
|
12
|
+
.join(colors.dim(' • ')),
|
|
10
13
|
},
|
|
11
|
-
helpMode: '
|
|
14
|
+
helpMode: 'always',
|
|
12
15
|
indexMode: 'hidden',
|
|
16
|
+
keybindings: [],
|
|
13
17
|
};
|
|
14
18
|
function isSelectable(item) {
|
|
15
19
|
return !Separator.isSeparator(item) && !item.disabled;
|
|
@@ -41,11 +45,14 @@ function normalizeChoices(choices) {
|
|
|
41
45
|
}
|
|
42
46
|
export default createPrompt((config, done) => {
|
|
43
47
|
const { loop = true, pageSize = 7 } = config;
|
|
44
|
-
const firstRender = useRef(true);
|
|
45
48
|
const theme = makeTheme(selectTheme, config.theme);
|
|
49
|
+
const { keybindings } = theme;
|
|
46
50
|
const [status, setStatus] = useState('idle');
|
|
47
51
|
const prefix = usePrefix({ status, theme });
|
|
48
52
|
const searchTimeoutRef = useRef();
|
|
53
|
+
// Vim keybindings (j/k) conflict with typing those letters in search,
|
|
54
|
+
// so search must be disabled when vim bindings are enabled
|
|
55
|
+
const searchEnabled = !keybindings.includes('vim');
|
|
49
56
|
const items = useMemo(() => normalizeChoices(config.choices), [config.choices]);
|
|
50
57
|
const bounds = useMemo(() => {
|
|
51
58
|
const first = items.findIndex(isSelectable);
|
|
@@ -69,12 +76,12 @@ export default createPrompt((config, done) => {
|
|
|
69
76
|
setStatus('done');
|
|
70
77
|
done(selectedChoice.value);
|
|
71
78
|
}
|
|
72
|
-
else if (isUpKey(key) || isDownKey(key)) {
|
|
79
|
+
else if (isUpKey(key, keybindings) || isDownKey(key, keybindings)) {
|
|
73
80
|
rl.clearLine(0);
|
|
74
81
|
if (loop ||
|
|
75
|
-
(isUpKey(key) && active !== bounds.first) ||
|
|
76
|
-
(isDownKey(key) && active !== bounds.last)) {
|
|
77
|
-
const offset = isUpKey(key) ? -1 : 1;
|
|
82
|
+
(isUpKey(key, keybindings) && active !== bounds.first) ||
|
|
83
|
+
(isDownKey(key, keybindings) && active !== bounds.last)) {
|
|
84
|
+
const offset = isUpKey(key, keybindings) ? -1 : 1;
|
|
78
85
|
let next = active;
|
|
79
86
|
do {
|
|
80
87
|
next = (next + offset + items.length) % items.length;
|
|
@@ -103,8 +110,7 @@ export default createPrompt((config, done) => {
|
|
|
103
110
|
else if (isBackspaceKey(key)) {
|
|
104
111
|
rl.clearLine(0);
|
|
105
112
|
}
|
|
106
|
-
else {
|
|
107
|
-
// Default to search
|
|
113
|
+
else if (searchEnabled) {
|
|
108
114
|
const searchTerm = rl.line.toLowerCase();
|
|
109
115
|
const matchIndex = items.findIndex((item) => {
|
|
110
116
|
if (Separator.isSeparator(item) || !isSelectable(item))
|
|
@@ -123,16 +129,20 @@ export default createPrompt((config, done) => {
|
|
|
123
129
|
clearTimeout(searchTimeoutRef.current);
|
|
124
130
|
}, []);
|
|
125
131
|
const message = theme.style.message(config.message, status);
|
|
126
|
-
let
|
|
127
|
-
|
|
128
|
-
if (theme.helpMode
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
132
|
+
let helpLine;
|
|
133
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
134
|
+
if (theme.helpMode !== 'never') {
|
|
135
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
136
|
+
if (config.instructions) {
|
|
137
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
138
|
+
const { pager, navigation } = config.instructions;
|
|
139
|
+
helpLine = theme.style.help(items.length > pageSize ? pager : navigation);
|
|
133
140
|
}
|
|
134
141
|
else {
|
|
135
|
-
|
|
142
|
+
helpLine = theme.style.keysHelpTip([
|
|
143
|
+
['↑↓', 'navigate'],
|
|
144
|
+
['⏎', 'select'],
|
|
145
|
+
]);
|
|
136
146
|
}
|
|
137
147
|
}
|
|
138
148
|
let separatorCount = 0;
|
|
@@ -157,11 +167,21 @@ export default createPrompt((config, done) => {
|
|
|
157
167
|
loop,
|
|
158
168
|
});
|
|
159
169
|
if (status === 'done') {
|
|
160
|
-
return
|
|
170
|
+
return [prefix, message, theme.style.answer(selectedChoice.short)]
|
|
171
|
+
.filter(Boolean)
|
|
172
|
+
.join(' ');
|
|
161
173
|
}
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
174
|
+
const { description } = selectedChoice;
|
|
175
|
+
const lines = [
|
|
176
|
+
[prefix, message].filter(Boolean).join(' '),
|
|
177
|
+
page,
|
|
178
|
+
' ',
|
|
179
|
+
description ? theme.style.description(description) : '',
|
|
180
|
+
helpLine,
|
|
181
|
+
]
|
|
182
|
+
.filter(Boolean)
|
|
183
|
+
.join('\n')
|
|
184
|
+
.trimEnd();
|
|
185
|
+
return `${lines}${cursorHide}`;
|
|
166
186
|
});
|
|
167
187
|
export { Separator } from '@inquirer/core';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inquirer/select",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.0",
|
|
4
4
|
"description": "Inquirer select/list prompt",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"answer",
|
|
@@ -74,15 +74,15 @@
|
|
|
74
74
|
"tsc": "tshy"
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
|
-
"@inquirer/
|
|
78
|
-
"@inquirer/
|
|
79
|
-
"@inquirer/
|
|
80
|
-
"
|
|
77
|
+
"@inquirer/ansi": "^1.0.1",
|
|
78
|
+
"@inquirer/core": "^10.3.0",
|
|
79
|
+
"@inquirer/figures": "^1.0.14",
|
|
80
|
+
"@inquirer/type": "^3.0.9",
|
|
81
81
|
"yoctocolors-cjs": "^2.1.2"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
85
|
-
"@inquirer/testing": "^2.1.
|
|
85
|
+
"@inquirer/testing": "^2.1.51",
|
|
86
86
|
"tshy": "^3.0.2"
|
|
87
87
|
},
|
|
88
88
|
"engines": {
|
|
@@ -108,5 +108,5 @@
|
|
|
108
108
|
"optional": true
|
|
109
109
|
}
|
|
110
110
|
},
|
|
111
|
-
"gitHead": "
|
|
111
|
+
"gitHead": "87cb01e67a25983bdaf0d74a7685915c0afb5f23"
|
|
112
112
|
}
|