UNPKG

@primer/react

Version:

An implementation of GitHub's Primer Design System using React

143 lines (142 loc) 4.6 kB
import { useMenuInitialFocus } from "./useMenuInitialFocus.js"; import { useMnemonics } from "./useMnemonics.js"; import { c } from "react-compiler-runtime"; import React from "react"; import { iterateFocusableElements } from "@primer/behaviors/utils"; //#region src/hooks/useMenuKeyboardNavigation.ts /** * Keyboard navigation is a mix of 4 hooks * 1. useMenuInitialFocus * 2. useTypeaheadFocus * 3. useCloseMenuOnTab * 4. useMoveFocusToMenuItem */ const useMenuKeyboardNavigation = (open, onClose, containerRef, anchorRef, t0) => { const isSubmenu = t0 === void 0 ? false : t0; useMenuInitialFocus(open, containerRef, anchorRef); useMnemonics(open, containerRef); useCloseMenuOnTab(open, onClose, containerRef, anchorRef); useMoveFocusToMenuItem(open, containerRef, anchorRef); useCloseSubmenuOnArrow(open, isSubmenu, onClose, containerRef); }; /** * When Tab or Shift+Tab is pressed, the menu should close * and the focus should naturally move to the next item */ const useCloseMenuOnTab = (open, onClose, containerRef, anchorRef) => { const $ = c(6); let t0; let t1; if ($[0] !== anchorRef || $[1] !== containerRef || $[2] !== onClose || $[3] !== open) { t0 = () => { const container = containerRef === null || containerRef === void 0 ? void 0 : containerRef.current; const anchor = anchorRef === null || anchorRef === void 0 ? void 0 : anchorRef.current; const handler = (event) => { if (open && event.key === "Tab") onClose === null || onClose === void 0 || onClose("tab"); }; container === null || container === void 0 || container.addEventListener("keydown", handler); anchor === null || anchor === void 0 || anchor.addEventListener("keydown", handler); return () => { container === null || container === void 0 || container.removeEventListener("keydown", handler); anchor === null || anchor === void 0 || anchor.removeEventListener("keydown", handler); }; }; t1 = [ open, onClose, containerRef, anchorRef ]; $[0] = anchorRef; $[1] = containerRef; $[2] = onClose; $[3] = open; $[4] = t0; $[5] = t1; } else { t0 = $[4]; t1 = $[5]; } React.useEffect(t0, t1); }; /** * Close submenu when left arrow key is pressed */ const useCloseSubmenuOnArrow = (open, isSubmenu, onClose, containerRef) => { const $ = c(6); let t0; let t1; if ($[0] !== containerRef || $[1] !== isSubmenu || $[2] !== onClose || $[3] !== open) { t0 = () => { const container = containerRef === null || containerRef === void 0 ? void 0 : containerRef.current; const handler = (event) => { if (open && isSubmenu && event.key === "ArrowLeft") onClose === null || onClose === void 0 || onClose("arrow-left"); }; container === null || container === void 0 || container.addEventListener("keydown", handler); return () => { container === null || container === void 0 || container.removeEventListener("keydown", handler); }; }; t1 = [ open, onClose, containerRef, isSubmenu ]; $[0] = containerRef; $[1] = isSubmenu; $[2] = onClose; $[3] = open; $[4] = t0; $[5] = t1; } else { t0 = $[4]; t1 = $[5]; } React.useEffect(t0, t1); }; /** * When Arrow Keys are pressed and the focus is on the anchor, * focus should move to a menu item */ const useMoveFocusToMenuItem = (open, containerRef, anchorRef) => { const $ = c(5); let t0; let t1; if ($[0] !== anchorRef || $[1] !== containerRef || $[2] !== open) { t0 = () => { const container = containerRef === null || containerRef === void 0 ? void 0 : containerRef.current; const anchor = anchorRef === null || anchorRef === void 0 ? void 0 : anchorRef.current; const handler = (event) => { if (!open || !container) return; const iterable = iterateFocusableElements(container); if (event.key === "ArrowDown") { const firstElement = iterable.next().value; setTimeout(() => firstElement === null || firstElement === void 0 ? void 0 : firstElement.focus()); } else if (event.key === "ArrowUp") { const elements = [...iterable]; const lastElement = elements[elements.length - 1]; setTimeout(() => lastElement.focus()); } }; anchor === null || anchor === void 0 || anchor.addEventListener("keydown", handler); return () => anchor === null || anchor === void 0 ? void 0 : anchor.addEventListener("keydown", handler); }; t1 = [ open, containerRef, anchorRef ]; $[0] = anchorRef; $[1] = containerRef; $[2] = open; $[3] = t0; $[4] = t1; } else { t0 = $[3]; t1 = $[4]; } React.useEffect(t0, t1); }; //#endregion export { useMenuKeyboardNavigation };