@gravity-ui/uikit
Version:
Gravity UI base styling and components
97 lines (96 loc) • 3.6 kB
JavaScript
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