UNPKG

@primer/components

Version:
101 lines (84 loc) 2.77 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = require("react"); // adapted from details-menu web component https://github.com/github/details-menu-element function useKeyboardNav(details, open, setOpen) { const handleKeyDown = (0, _react.useCallback)(event => { const closeDetails = () => { setOpen(false); const summary = details.current.querySelector('summary'); if (summary) summary.focus(); }; const openDetails = () => { setOpen(true); }; const focusItem = next => { const options = Array.from(details.current.querySelectorAll('[role^="menuitem"]:not([hidden]):not([disabled]):not([aria-disabled="true"])')); const selected = document.activeElement; const index = options.indexOf(selected); const found = next ? options[index + 1] : options[index - 1]; const def = next ? options[0] : options[options.length - 1]; return found || def; }; const isMenuItem = el => { const role = el.getAttribute('role'); return role === 'menuitem' || role === 'menuitemcheckbox' || role === 'menuitemradio'; }; if (!(event instanceof KeyboardEvent)) return; const isSummaryFocused = event.target instanceof Element && event.target.tagName === 'SUMMARY'; switch (event.key) { case 'Escape': if (open) { closeDetails(details); event.preventDefault(); event.stopPropagation(); } break; case 'ArrowDown': { if (isSummaryFocused && !open) { openDetails(details); } const target = focusItem(true); if (target) target.focus(); event.preventDefault(); } break; case 'ArrowUp': { if (isSummaryFocused && !open) { openDetails(); } const target = focusItem(false); if (target) target.focus(); event.preventDefault(); } break; case ' ': case 'Enter': { const selected = document.activeElement; if (selected && isMenuItem(selected) && selected.closest('details') === details) { event.preventDefault(); event.stopPropagation(); selected.click(); } } break; default: } }, [details, open, setOpen]); (0, _react.useEffect)(() => { const current = details.current; if (!current) return; current.addEventListener('keydown', handleKeyDown); return () => { current.removeEventListener('keydown', handleKeyDown); }; }, [details, handleKeyDown]); } var _default = useKeyboardNav; exports.default = _default;