@inquirer/select 4.3.4 → 4.4.1
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 -24
- package/dist/commonjs/index.d.ts +4 -1
- package/dist/commonjs/index.js +41 -21
- package/dist/esm/index.d.ts +4 -1
- package/dist/esm/index.js +41 -21
- package/package.json +10 -9
package/README.md
CHANGED
|
@@ -4,16 +4,6 @@ Simple interactive command line prompt to display a list of choices (single sele
|
|
|
4
4
|
|
|
5
5
|

|
|
6
6
|
|
|
7
|
-
# Special Thanks
|
|
8
|
-
|
|
9
|
-
<div align="center" markdown="1">
|
|
10
|
-
|
|
11
|
-
[](https://graphite.dev/?utm_source=npmjs&utm_medium=repo&utm_campaign=inquirerjs)<br>
|
|
12
|
-
|
|
13
|
-
### [Graphite is the AI developer productivity platform helping teams on GitHub ship higher quality software, faster](https://graphite.dev/?utm_source=npmjs&utm_medium=repo&utm_campaign=inquirerjs)
|
|
14
|
-
|
|
15
|
-
</div>
|
|
16
|
-
|
|
17
7
|
# Installation
|
|
18
8
|
|
|
19
9
|
<table>
|
|
@@ -95,15 +85,14 @@ const answer = await select({
|
|
|
95
85
|
|
|
96
86
|
## Options
|
|
97
87
|
|
|
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. |
|
|
88
|
+
| Property | Type | Required | Description |
|
|
89
|
+
| -------- | ----------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
90
|
+
| message | `string` | yes | The question to ask |
|
|
91
|
+
| choices | `Choice[]` | yes | List of the available choices. |
|
|
92
|
+
| 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. |
|
|
93
|
+
| 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. |
|
|
94
|
+
| 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. |
|
|
95
|
+
| theme | [See Theming](#Theming) | no | Customize look of the prompt. |
|
|
107
96
|
|
|
108
97
|
`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
98
|
|
|
@@ -150,20 +139,34 @@ type Theme = {
|
|
|
150
139
|
highlight: (text: string) => string;
|
|
151
140
|
description: (text: string) => string;
|
|
152
141
|
disabled: (text: string) => string;
|
|
142
|
+
keysHelpTip: (keys: [key: string, action: string][]) => string | undefined;
|
|
153
143
|
};
|
|
154
144
|
icon: {
|
|
155
145
|
cursor: string;
|
|
156
146
|
};
|
|
157
|
-
helpMode: 'always' | 'never' | 'auto';
|
|
158
147
|
indexMode: 'hidden' | 'number';
|
|
159
148
|
};
|
|
160
149
|
```
|
|
161
150
|
|
|
162
|
-
### `theme.
|
|
151
|
+
### `theme.style.keysHelpTip`
|
|
163
152
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
153
|
+
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.
|
|
154
|
+
|
|
155
|
+
It can also returns `undefined` to hide the help tip entirely. This is the replacement for the deprecated theme option `helpMode: 'never'`.
|
|
156
|
+
|
|
157
|
+
```js
|
|
158
|
+
theme: {
|
|
159
|
+
style: {
|
|
160
|
+
keysHelpTip: (keys) => {
|
|
161
|
+
// Return undefined to hide the help tip completely.
|
|
162
|
+
return undefined;
|
|
163
|
+
|
|
164
|
+
// Or customize the formatting. Or localize the labels.
|
|
165
|
+
return keys.map(([key, action]) => `${key}: ${action}`).join(' | ');
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
167
170
|
|
|
168
171
|
### `theme.indexMode`
|
|
169
172
|
|
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
|
@@ -13,9 +13,13 @@ const selectTheme = {
|
|
|
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
|
@@ -7,9 +7,13 @@ const selectTheme = {
|
|
|
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.1",
|
|
4
4
|
"description": "Inquirer select/list prompt",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"answer",
|
|
@@ -74,16 +74,17 @@
|
|
|
74
74
|
"tsc": "tshy"
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
|
-
"@inquirer/ansi": "^1.0.
|
|
78
|
-
"@inquirer/core": "^10.
|
|
79
|
-
"@inquirer/figures": "^1.0.
|
|
80
|
-
"@inquirer/type": "^3.0.
|
|
81
|
-
"yoctocolors-cjs": "^2.1.
|
|
77
|
+
"@inquirer/ansi": "^1.0.2",
|
|
78
|
+
"@inquirer/core": "^10.3.1",
|
|
79
|
+
"@inquirer/figures": "^1.0.15",
|
|
80
|
+
"@inquirer/type": "^3.0.10",
|
|
81
|
+
"yoctocolors-cjs": "^2.1.3"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"@arethetypeswrong/cli": "^0.18.2",
|
|
85
|
-
"@inquirer/testing": "^2.1.
|
|
86
|
-
"
|
|
85
|
+
"@inquirer/testing": "^2.1.52",
|
|
86
|
+
"@repo/tsconfig": "0.0.0",
|
|
87
|
+
"tshy": "^3.0.3"
|
|
87
88
|
},
|
|
88
89
|
"engines": {
|
|
89
90
|
"node": ">=18"
|
|
@@ -108,5 +109,5 @@
|
|
|
108
109
|
"optional": true
|
|
109
110
|
}
|
|
110
111
|
},
|
|
111
|
-
"gitHead": "
|
|
112
|
+
"gitHead": "6881993e517e76fa891b72e1f5086fd11f7676ac"
|
|
112
113
|
}
|