UNPKG

@primer/react

Version:

An implementation of GitHub's Primer Design System using React

171 lines (170 loc) • 8.05 kB
import { FocusKeys, useFocusZone } from "../hooks/useFocusZone.js"; import { getScrollContainer } from "../utils/scroll.js"; import { c } from "react-compiler-runtime"; //#region src/TreeView/useRovingTabIndex.ts function useRovingTabIndex(t0, t1) { const $ = c(12); const { containerRef, mouseDownRef, preventScroll: t2 } = t0; const preventScroll = t2 === void 0 ? true : t2; let t3; if ($[0] !== t1) { t3 = t1 === void 0 ? [] : t1; $[0] = t1; $[1] = t3; } else t3 = $[1]; const dependencies = t3; let t4; if ($[2] !== containerRef || $[3] !== mouseDownRef) { t4 = () => { var _containerRef$current, _containerRef$current2, _containerRef$current3; if (mouseDownRef !== null && mouseDownRef !== void 0 && mouseDownRef.current) return; const currentItem = (_containerRef$current = containerRef.current) === null || _containerRef$current === void 0 ? void 0 : _containerRef$current.querySelector("[aria-current]"); const firstItem = (_containerRef$current2 = containerRef.current) === null || _containerRef$current2 === void 0 ? void 0 : _containerRef$current2.querySelector("[role=\"treeitem\"]"); if (currentItem instanceof HTMLElement) return currentItem; if (document.activeElement instanceof HTMLElement && (_containerRef$current3 = containerRef.current) !== null && _containerRef$current3 !== void 0 && _containerRef$current3.contains(document.activeElement) && document.activeElement.getAttribute("role") === "treeitem") return document.activeElement; return firstItem instanceof HTMLElement ? firstItem : void 0; }; $[2] = containerRef; $[3] = mouseDownRef; $[4] = t4; } else t4 = $[4]; let t5; if ($[5] !== containerRef || $[6] !== preventScroll || $[7] !== t4) { t5 = { containerRef, bindKeys: FocusKeys.ArrowVertical | FocusKeys.ArrowHorizontal | FocusKeys.HomeAndEnd | FocusKeys.Backspace | FocusKeys.PageUpDown, preventScroll, getNextFocusable: _temp, focusInStrategy: t4 }; $[5] = containerRef; $[6] = preventScroll; $[7] = t4; $[8] = t5; } else t5 = $[8]; let t6; if ($[9] !== dependencies || $[10] !== preventScroll) { t6 = [preventScroll, ...dependencies]; $[9] = dependencies; $[10] = preventScroll; $[11] = t6; } else t6 = $[11]; useFocusZone(t5, t6); } function _temp(direction, from, event) { var _getNextFocusableElem; if (!(from instanceof HTMLElement)) return; try { if (from.closest("dialog:modal")) return; } catch {} return (_getNextFocusableElem = getNextFocusableElement(from, event)) !== null && _getNextFocusableElem !== void 0 ? _getNextFocusableElem : from; } function getNextFocusableElement(activeElement, event) { switch (`${getElementState(activeElement)} ${event.key}`) { case "open ArrowRight": return getFirstChildElement(activeElement); case "open ArrowLeft": return; case "closed ArrowRight": return; case "closed ArrowLeft": return getParentElement(activeElement); case "end ArrowRight": return; case "end ArrowLeft": return getParentElement(activeElement); } switch (event.key) { case "ArrowUp": return getVisibleElement(activeElement, "previous"); case "ArrowDown": return getVisibleElement(activeElement, "next"); case "Backspace": return getParentElement(activeElement); case "Home": return getFirstElement(activeElement); case "End": return getLastElement(activeElement); case "PageUp": return getPreviousPageElement(activeElement); case "PageDown": return getNextPageElement(activeElement); } } function getElementState(element) { if (element.getAttribute("role") !== "treeitem") throw new Error("Element is not a treeitem"); switch (element.getAttribute("aria-expanded")) { case "true": return "open"; case "false": return "closed"; default: return "end"; } } function getVisibleElement(element, direction) { const root = element.closest("[role=tree]"); if (!root) return; const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, (node) => { if (!(node instanceof HTMLElement)) return NodeFilter.FILTER_SKIP; return node.getAttribute("role") === "treeitem" ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP; }); let current = walker.firstChild(); while (current !== element) current = walker.nextNode(); let next = direction === "next" ? walker.nextNode() : walker.previousNode(); while (next instanceof HTMLElement && (_next$parentElement = next.parentElement) !== null && _next$parentElement !== void 0 && _next$parentElement.closest("[role=treeitem][aria-expanded=false]")) { var _next$parentElement; next = direction === "next" ? walker.nextNode() : walker.previousNode(); } return next instanceof HTMLElement ? next : void 0; } function getFirstChildElement(element) { const firstChild = element.querySelector("[role=treeitem]"); return firstChild instanceof HTMLElement ? firstChild : void 0; } function getParentElement(element) { const group = element.closest("[role=group]"); const parent = group === null || group === void 0 ? void 0 : group.closest("[role=treeitem]"); return parent instanceof HTMLElement ? parent : void 0; } function getFirstElement(element) { const root = element.closest("[role=tree]"); const first = root === null || root === void 0 ? void 0 : root.querySelector("[role=treeitem]"); return first instanceof HTMLElement ? first : void 0; } function getLastElement(element) { const root = element.closest("[role=tree]"); if (!root) return; const items = Array.from(root.querySelectorAll("[role=treeitem]")); if (items.length === 0) return; let index = items.length - 1; let last = items[index]; while (index > 0 && last instanceof HTMLElement && (_last$parentElement = last.parentElement) !== null && _last$parentElement !== void 0 && _last$parentElement.closest("[role=treeitem][aria-expanded=false]")) { var _last$parentElement; index -= 1; last = items[index]; } return last instanceof HTMLElement ? last : void 0; } const defaultSize = { height: 32 }; /** * Determine the page size for the given tree based on an item in the tree. We * estimate this size by trying to see how many items will fit in the given * tree. If the tree is within a scroll container, we will use the height of * that container. Otherwise, we'll use the current window height */ function getPageSize(root, item) { var _item$getBoundingClie, _scrollContainer$clie; const scrollContainer = getScrollContainer(root); const { height: itemHeight } = (_item$getBoundingClie = item === null || item === void 0 ? void 0 : item.getBoundingClientRect()) !== null && _item$getBoundingClie !== void 0 ? _item$getBoundingClie : defaultSize; const availableHeight = (_scrollContainer$clie = scrollContainer === null || scrollContainer === void 0 ? void 0 : scrollContainer.clientHeight) !== null && _scrollContainer$clie !== void 0 ? _scrollContainer$clie : window.innerHeight; return Math.floor(availableHeight / itemHeight); } function getNextPageElement(element) { const root = element.closest("[role=\"tree\"]"); if (!root) return; const items = Array.from(root.querySelectorAll("[role=\"treeitem\"]")); if (items.length === 0) return; const itemLabel = items[0].firstElementChild; const pageSize = getPageSize(root, itemLabel); const page = Math.floor(items.indexOf(element) / pageSize); const offset = items.indexOf(element) - pageSize * page; return items[Math.min(items.length - 1, (page + 1) * pageSize + offset)]; } function getPreviousPageElement(element) { const root = element.closest("[role=\"tree\"]"); if (!root) return; const items = Array.from(root.querySelectorAll("[role=\"treeitem\"]")); if (items.length === 0) return; const itemLabel = items[0].firstElementChild; const pageSize = getPageSize(root, itemLabel); const page = Math.floor(items.indexOf(element) / pageSize); const offset = items.indexOf(element) - pageSize * page; return items[Math.max(0, (page - 1) * pageSize + offset)]; } //#endregion export { getElementState, getFirstChildElement, getFirstElement, getLastElement, getNextFocusableElement, getParentElement, getVisibleElement, useRovingTabIndex };