From e1c5d52dbed9847fd5da892f951cc0023a68d1cb Mon Sep 17 00:00:00 2001 From: Aman Harwara Date: Mon, 14 Aug 2023 13:49:32 +0530 Subject: [PATCH] refactor: menu keyboard navigation --- .../Hooks/useListKeyboardNavigation.ts | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/web/src/javascripts/Hooks/useListKeyboardNavigation.ts b/packages/web/src/javascripts/Hooks/useListKeyboardNavigation.ts index ed81c0147..a29965b84 100644 --- a/packages/web/src/javascripts/Hooks/useListKeyboardNavigation.ts +++ b/packages/web/src/javascripts/Hooks/useListKeyboardNavigation.ts @@ -69,8 +69,6 @@ export const useListKeyboardNavigation = ( return } - listItems.current = Array.from(container.current?.querySelectorAll('button') as NodeListOf) - if (e.key === KeyboardKey.Up) { const previousIndex = getPreviousFocusableIndex(focusedItemIndex.current, listItems.current) focusItemWithIndex(previousIndex) @@ -81,14 +79,13 @@ export const useListKeyboardNavigation = ( focusItemWithIndex(nextIndex) } }, - [container, focusItemWithIndex, getNextFocusableIndex, getPreviousFocusableIndex], + [focusItemWithIndex, getNextFocusableIndex, getPreviousFocusableIndex], ) const FIRST_ITEM_FOCUS_TIMEOUT = 20 const setInitialFocus = useCallback(() => { - const items = Array.from(container.current?.querySelectorAll('button') as NodeListOf) - listItems.current = items + const items = listItems.current if (items.length < 1) { return @@ -99,7 +96,7 @@ export const useListKeyboardNavigation = ( indexToFocus = getNextFocusableIndex(indexToFocus - 1, items) focusItemWithIndex(indexToFocus, items) - }, [container, focusItemWithIndex, getNextFocusableIndex, initialFocus]) + }, [focusItemWithIndex, getNextFocusableIndex, initialFocus]) useEffect(() => { if (shouldAutoFocus) { @@ -117,10 +114,25 @@ export const useListKeyboardNavigation = ( useEffect(() => { const containerElement = container.current - containerElement?.addEventListener('keydown', keyDownHandler) + + if (!containerElement) { + return + } + + containerElement.addEventListener('keydown', keyDownHandler) + + const containerMutationObserver = new MutationObserver(() => { + listItems.current = Array.from(containerElement.querySelectorAll('button')) + }) + + containerMutationObserver.observe(containerElement, { + childList: true, + subtree: true, + }) return () => { containerElement?.removeEventListener('keydown', keyDownHandler) + containerMutationObserver.disconnect() } }, [container, setInitialFocus, keyDownHandler])