diff --git a/.changeset/clever-tigers-jump.md b/.changeset/clever-tigers-jump.md new file mode 100644 index 00000000..e3f1430b --- /dev/null +++ b/.changeset/clever-tigers-jump.md @@ -0,0 +1,5 @@ +--- +"@clack/core": minor +--- + +Press number keys 1–9 in the select prompt to jump to the corresponding option. diff --git a/packages/core/src/prompts/select.ts b/packages/core/src/prompts/select.ts index 99ed5df9..a9c7cf96 100644 --- a/packages/core/src/prompts/select.ts +++ b/packages/core/src/prompts/select.ts @@ -43,5 +43,15 @@ export default class SelectPrompt } this.changeValue(); }); + + this.on('key', (char, key) => { + if (key.ctrl || key.meta) return; + if (!char || char.length !== 1) return; + if (char < '1' || char > '9') return; + const target = Number(char) - 1; + if (target >= this.options.length) return; + this.cursor = this.options[target].disabled ? findCursor(target, 1, this.options) : target; + this.changeValue(); + }); } } diff --git a/packages/core/test/prompts/select.test.ts b/packages/core/test/prompts/select.test.ts index a3583061..355f7f60 100644 --- a/packages/core/test/prompts/select.test.ts +++ b/packages/core/test/prompts/select.test.ts @@ -138,5 +138,41 @@ describe('SelectPrompt', () => { instance.prompt(); expect(instance.cursor).to.equal(1); }); + + test('number key jumps to option', () => { + const instance = new SelectPrompt({ + input, + output, + render: () => 'foo', + options: [{ value: 'foo' }, { value: 'bar' }, { value: 'baz' }], + }); + instance.prompt(); + input.emit('keypress', '3', { name: '3' }); + expect(instance.cursor).to.equal(2); + }); + + test('number key skips disabled option', () => { + const instance = new SelectPrompt({ + input, + output, + render: () => 'foo', + options: [{ value: 'foo' }, { value: 'bar', disabled: true }, { value: 'baz' }], + }); + instance.prompt(); + input.emit('keypress', '2', { name: '2' }); + expect(instance.cursor).to.equal(2); + }); + + test('out-of-range number key is ignored', () => { + const instance = new SelectPrompt({ + input, + output, + render: () => 'foo', + options: [{ value: 'foo' }, { value: 'bar' }], + }); + instance.prompt(); + input.emit('keypress', '9', { name: '9' }); + expect(instance.cursor).to.equal(0); + }); }); });