1 import type { MutableRefObject } from 'react';
3 import { tabbable } from 'tabbable';
5 import type { HotkeyTuple } from './useHotkeys';
8 rootRef: MutableRefObject<HTMLDivElement | null>;
11 const useDropdownArrowNavigation = ({ rootRef }: Context) => {
12 const getDropdownMenuItems = () => {
13 if (!rootRef.current) {
17 return tabbable(rootRef.current, { includeContainer: false }).filter(
18 (elm) => !elm.dataset.preventArrowNavigation
22 const getFocusIndex = () => getDropdownMenuItems().findIndex((elm) => elm === document.activeElement);
24 const findElementAndFocus = (startingIndex: number) => {
25 const dropdownMenuItems = getDropdownMenuItems();
27 if (!dropdownMenuItems.length) {
31 const lastIndex = dropdownMenuItems.length - 1;
32 let index = startingIndex;
34 /* loop from last to first item */
35 if (index > lastIndex) {
38 /* reverse loop from first to last item */
43 const elem = dropdownMenuItems[index] as any;
48 const focusOnFirst = () => {
50 findElementAndFocus(index);
53 const focusOnLast = () => {
54 const dropdownMenuItems = getDropdownMenuItems();
55 const index = dropdownMenuItems.length - 1;
56 findElementAndFocus(index);
59 const focusOnPrevious = () => {
60 const focusIndex = getFocusIndex();
61 findElementAndFocus(focusIndex - 1);
64 const focusOnNext = () => {
65 const focusIndex = getFocusIndex();
66 findElementAndFocus(focusIndex + 1);
69 const shortcutHandlers: HotkeyTuple[] = [
92 ['Meta', 'ArrowDown'],
105 export default useDropdownArrowNavigation;