Skip to content

Commit 2497482

Browse files
committed
Start arrow key focus sequence with last focused element
1 parent d8064ec commit 2497482

File tree

2 files changed

+25
-7
lines changed

2 files changed

+25
-7
lines changed

src/hooks/test/use-arrow-key-navigation-test.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,13 @@ function ToolbarWithToggle({ navigationOptions = {} }) {
4848

4949
describe('useArrowKeyNavigation', () => {
5050
let container;
51-
let toolbar;
5251

5352
beforeEach(() => {
5453
container = document.createElement('div');
5554
const button = document.createElement('button');
5655
button.setAttribute('data-testid', 'outside-button');
5756
container.append(button);
5857
document.body.append(container);
59-
toolbar = renderToolbar();
6058
});
6159

6260
afterEach(() => {
@@ -98,6 +96,7 @@ describe('useArrowKeyNavigation', () => {
9896
{ forwardKey: 'ArrowDown', backKey: 'ArrowUp' },
9997
].forEach(({ forwardKey, backKey }) => {
10098
it('should move focus and tab stop between elements when arrow keys are pressed', () => {
99+
const toolbar = renderToolbar();
101100
const steps = [
102101
// Test navigating forwards.
103102
[forwardKey, 'Italic'],
@@ -381,12 +380,23 @@ describe('useArrowKeyNavigation', () => {
381380
container,
382381
),
383382
);
383+
const toggleToolbar = () => findElementByTestId('toggle').click();
384384

385385
// No button should be initially focused
386386
assert.equal(document.activeElement, document.body);
387387

388-
// Once we toggle the list open, the first item will be focused
389-
findElementByTestId('toggle').click();
388+
// Once we open the toolbar, the first item will be focused
389+
toggleToolbar();
390390
await waitFor(() => document.activeElement === findElementByTestId('bold'));
391+
392+
// If we then focus another toolbar item, then close the toolbar and open it
393+
// again, that same element should be focused again
394+
pressKey('ArrowDown'); // "italic" is focused
395+
pressKey('ArrowDown'); // "underline" is focused
396+
toggleToolbar(); // Close toolbar
397+
toggleToolbar(); // Open toolbar again
398+
await waitFor(
399+
() => document.activeElement === findElementByTestId('underline'),
400+
);
391401
});
392402
});

src/hooks/use-arrow-key-navigation.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ export type UseArrowKeyNavigationOptions = {
7777
* [2] https://www.w3.org/TR/wai-aria-practices/#keyboard
7878
*
7979
*/
80-
8180
export function useArrowKeyNavigation(
8281
containerRef: RefObject<HTMLElement | undefined>,
8382
{
@@ -92,7 +91,7 @@ export function useArrowKeyNavigation(
9291
// Keep track of the element that was last focused by this hook such that
9392
// navigation can be restored if focus moves outside the container and then
9493
// back to/into it.
95-
const lastFocusedItem = useRef<HTMLOrSVGElement | null>(null);
94+
const lastFocusedItem = useRef<HTMLElement | null>(null);
9695

9796
useEffect(() => {
9897
if (!containerRef.current) {
@@ -192,7 +191,16 @@ export function useArrowKeyNavigation(
192191
event.stopPropagation();
193192
};
194193

195-
updateTabIndexes(getNavigableElements(), 0, containerVisible && autofocus);
194+
const navigableElements = getNavigableElements();
195+
// Start focus sequence with previously focused element, if any
196+
const initialIndex = lastFocusedItem.current
197+
? navigableElements.indexOf(lastFocusedItem.current)
198+
: 0;
199+
updateTabIndexes(
200+
navigableElements,
201+
initialIndex,
202+
containerVisible && autofocus,
203+
);
196204

197205
const listeners = new ListenerCollection();
198206

0 commit comments

Comments
 (0)