UNPKG

@gravity-ui/uikit

Version:

Gravity UI base styling and components

97 lines (96 loc) 3.6 kB
import * as React from 'react'; import { KeyCode } from "../../../constants.js"; import { useDirection } from "../../theme/index.js"; import { TAB_DATA_ATTRIBUTE, bTabList } from "../constants.js"; import { TabContext } from "../contexts/TabContext.js"; const getAllTabElements = (tabElement) => { return [ ...(tabElement .closest('[role="tablist"]') ?.querySelectorAll(`[${TAB_DATA_ATTRIBUTE}]`) ?? []), ]; }; const isTabDisabled = (tabElement) => { return Boolean(tabElement.getAttribute('aria-disabled')); }; const getTabValue = (tabElement) => { return tabElement.getAttribute(TAB_DATA_ATTRIBUTE); }; const focusNearestTab = (event, isInverse, isRTL) => { const tabElement = event.target; const allTabElements = getAllTabElements(tabElement); const index = allTabElements.indexOf(tabElement); let distance = 1; while (distance < allTabElements.length) { const nextIndex = index + distance * (isRTL ? -1 : 1) * (isInverse ? -1 : 1); const nextTabElement = allTabElements.at(nextIndex % allTabElements.length); if (nextTabElement && !isTabDisabled(nextTabElement)) { nextTabElement.focus(); return nextTabElement; } distance++; } return tabElement; }; const focusFurthestTab = (event, isInverse) => { const tabElement = event.target; const allTabElements = getAllTabElements(tabElement); const stopIndex = isInverse ? 0 : allTabElements.length - 1; let index = allTabElements.indexOf(tabElement); let lastFocusableTabElement = tabElement; while (index !== stopIndex) { index += isInverse ? -1 : 1; const nextTabElement = allTabElements.at(index); if (nextTabElement && !isTabDisabled(nextTabElement)) { lastFocusableTabElement = nextTabElement; } } lastFocusableTabElement.focus(); return lastFocusableTabElement; }; export function useTabList(tabListProps) { const tabContext = React.useContext(TabContext); const isRTL = useDirection() === 'rtl'; const activateOnFocus = (tabElement) => { const value = getTabValue(tabElement); if (tabListProps.activateOnFocus && value) { tabListProps.onUpdate?.(value); tabContext?.onUpdate?.(value); } }; const onKeyDown = (event) => { switch (event.code) { case KeyCode.ARROW_LEFT: { event.preventDefault(); activateOnFocus(focusNearestTab(event, true, isRTL)); break; } case KeyCode.ARROW_RIGHT: { event.preventDefault(); activateOnFocus(focusNearestTab(event, false, isRTL)); break; } case KeyCode.HOME: { event.preventDefault(); activateOnFocus(focusFurthestTab(event, true)); break; } case KeyCode.END: { event.preventDefault(); activateOnFocus(focusFurthestTab(event, false)); break; } } tabListProps.onKeyDown?.(event); }; const { value: _value, onUpdate: _onUpdate, size: _size, activateOnFocus: _activateOnFocus, qa: _qa, ...htmlProps } = tabListProps; return { ...htmlProps, role: 'tablist', 'aria-orientation': 'horizontal', onKeyDown, className: bTabList({ size: tabListProps.size ?? 'm' }, tabListProps.className), 'data-qa': tabListProps.qa, }; } //# sourceMappingURL=useTabList.js.map