diff --git a/packages/web/src/javascripts/Components/LinkedItems/ItemLinkAutocompleteInput.tsx b/packages/web/src/javascripts/Components/LinkedItems/ItemLinkAutocompleteInput.tsx index ff7e3ac52..c582cf665 100644 --- a/packages/web/src/javascripts/Components/LinkedItems/ItemLinkAutocompleteInput.tsx +++ b/packages/web/src/javascripts/Components/LinkedItems/ItemLinkAutocompleteInput.tsx @@ -92,6 +92,7 @@ const ItemLinkAutocompleteInput = ({ linkingController, focusPreviousItem, focus break case KeyboardKey.Down: if (searchQuery.length > 0) { + event.preventDefault() searchResultsMenuRef.current?.focus() } break diff --git a/packages/web/src/javascripts/Hooks/useListKeyboardNavigation.ts b/packages/web/src/javascripts/Hooks/useListKeyboardNavigation.ts index ccf40f5f8..c112e7830 100644 --- a/packages/web/src/javascripts/Hooks/useListKeyboardNavigation.ts +++ b/packages/web/src/javascripts/Hooks/useListKeyboardNavigation.ts @@ -1,27 +1,24 @@ import { KeyboardKey } from '@standardnotes/ui-services' import { FOCUSABLE_BUT_NOT_TABBABLE } from '@/Constants/Constants' -import { useCallback, useState, useEffect, RefObject } from 'react' +import { useCallback, useEffect, RefObject, useRef } from 'react' export const useListKeyboardNavigation = (container: RefObject, initialFocus = 0) => { - const [listItems, setListItems] = useState() - const [focusedItemIndex, setFocusedItemIndex] = useState(initialFocus) + const listItems = useRef([]) + const focusedItemIndex = useRef(initialFocus) - const focusItemWithIndex = useCallback( - (index: number, items?: HTMLButtonElement[]) => { - setFocusedItemIndex(index) - if (items && items.length > 0) { - items[index]?.focus() - } else { - listItems?.[index]?.focus() - } - }, - [listItems], - ) + const focusItemWithIndex = useCallback((index: number, items?: HTMLButtonElement[]) => { + focusedItemIndex.current = index + if (items && items.length > 0) { + items[index]?.focus() + } else { + listItems.current[index]?.focus() + } + }, []) useEffect(() => { if (container.current) { container.current.tabIndex = FOCUSABLE_BUT_NOT_TABBABLE - setListItems(Array.from(container.current.querySelectorAll('button'))) + listItems.current = Array.from(container.current.querySelectorAll('button')) } }, [container]) @@ -33,47 +30,44 @@ export const useListKeyboardNavigation = (container: RefObject)) + listItems.current = Array.from(container.current?.querySelectorAll('button') as NodeListOf) + + if (e.key === KeyboardKey.Up) { + let previousIndex = focusedItemIndex.current - 1 + if (previousIndex < 0) { + previousIndex = listItems.current.length - 1 + } + focusItemWithIndex(previousIndex) } - if (listItems) { - if (e.key === KeyboardKey.Up) { - let previousIndex = focusedItemIndex - 1 - if (previousIndex < 0) { - previousIndex = listItems.length - 1 - } - focusItemWithIndex(previousIndex) - } - - if (e.key === KeyboardKey.Down) { - let nextIndex = focusedItemIndex + 1 - if (nextIndex > listItems.length - 1) { - nextIndex = 0 - } - focusItemWithIndex(nextIndex) + if (e.key === KeyboardKey.Down) { + let nextIndex = focusedItemIndex.current + 1 + if (nextIndex > listItems.current.length - 1) { + nextIndex = 0 } + focusItemWithIndex(nextIndex) } }, - [container, focusItemWithIndex, focusedItemIndex, listItems], + [container, focusItemWithIndex], ) const FIRST_ITEM_FOCUS_TIMEOUT = 20 const containerFocusHandler = useCallback(() => { - let temporaryItems = listItems && listItems?.length > 0 ? listItems : [] - if (!temporaryItems.length) { - temporaryItems = Array.from(container.current?.querySelectorAll('button') as NodeListOf) - setListItems(temporaryItems) + const items = Array.from(container.current?.querySelectorAll('button') as NodeListOf) + listItems.current = items + + if (items.length < 1) { + return } - if (temporaryItems.length > 0) { - const selectedItemIndex = Array.from(temporaryItems).findIndex((item) => item.dataset.selected) - const indexToFocus = selectedItemIndex > -1 ? selectedItemIndex : initialFocus - setTimeout(() => { - focusItemWithIndex(indexToFocus, temporaryItems) - }, FIRST_ITEM_FOCUS_TIMEOUT) - } - }, [container, focusItemWithIndex, initialFocus, listItems]) + + const selectedItemIndex = Array.from(items).findIndex((item) => item.dataset.selected) + const indexToFocus = selectedItemIndex > -1 ? selectedItemIndex : initialFocus + + setTimeout(() => { + focusItemWithIndex(indexToFocus, items) + }, FIRST_ITEM_FOCUS_TIMEOUT) + }, [container, focusItemWithIndex, initialFocus]) useEffect(() => { const containerElement = container.current