Modify navigation and completion keyboard shortcuts to not use scroll. (#12502)

This commit is contained in:
Jacob Richman
2025-11-03 16:22:04 -08:00
committed by GitHub
parent f3759381b1
commit ad33c22374
7 changed files with 131 additions and 29 deletions
@@ -48,15 +48,19 @@ describe('useSelectionList', () => {
mockOnHighlight.mockClear();
});
const pressKey = (name: string, sequence: string = name) => {
const pressKey = (
name: string,
sequence: string = name,
options: { shift?: boolean; ctrl?: boolean } = {},
) => {
act(() => {
if (activeKeypressHandler) {
const key: Key = {
name,
sequence,
ctrl: false,
ctrl: options.ctrl ?? false,
meta: false,
shift: false,
shift: options.shift ?? false,
paste: false,
};
activeKeypressHandler(key);
@@ -202,6 +206,31 @@ describe('useSelectionList', () => {
expect(result.current.activeIndex).toBe(0);
});
it('should ignore navigation keys when shift is pressed', async () => {
const { result } = await renderSelectionListHook({
items,
initialIndex: 2, // Start at middle item 'C'
onSelect: mockOnSelect,
});
expect(result.current.activeIndex).toBe(2);
// Shift+Down / Shift+J should not move down
pressKey('down', undefined, { shift: true });
expect(result.current.activeIndex).toBe(2);
pressKey('j', undefined, { shift: true });
expect(result.current.activeIndex).toBe(2);
// Shift+Up / Shift+K should not move up
pressKey('up', undefined, { shift: true });
expect(result.current.activeIndex).toBe(2);
pressKey('k', undefined, { shift: true });
expect(result.current.activeIndex).toBe(2);
// Verify normal navigation still works
pressKey('down');
expect(result.current.activeIndex).toBe(3);
});
it('should wrap navigation correctly', async () => {
const { result } = await renderSelectionListHook({
items,
@@ -6,6 +6,7 @@
import { useReducer, useRef, useEffect, useCallback } from 'react';
import { useKeypress, type Key } from './useKeypress.js';
import { keyMatchers, Command } from '../keyMatchers.js';
export interface SelectionListItem<T> {
key: string;
@@ -318,7 +319,7 @@ export function useSelectionList<T>({
const itemsLength = items.length;
const handleKeypress = useCallback(
(key: Key) => {
const { sequence, name } = key;
const { sequence } = key;
const isNumeric = showNumbers && /^[0-9]$/.test(sequence);
// Clear number input buffer on non-numeric key press
@@ -327,17 +328,17 @@ export function useSelectionList<T>({
numberInputRef.current = '';
}
if (name === 'k' || name === 'up') {
if (keyMatchers[Command.DIALOG_NAVIGATION_UP](key)) {
dispatch({ type: 'MOVE_UP' });
return;
}
if (name === 'j' || name === 'down') {
if (keyMatchers[Command.DIALOG_NAVIGATION_DOWN](key)) {
dispatch({ type: 'MOVE_DOWN' });
return;
}
if (name === 'return') {
if (keyMatchers[Command.RETURN](key)) {
dispatch({ type: 'SELECT_CURRENT' });
return;
}