@equinor/eds-core-react
Version:
The React implementation of the Equinor Design System
95 lines (92 loc) • 3.3 kB
JavaScript
import { forwardRef, useContext, useRef, useState, useCallback, Children, cloneElement } from 'react';
import styled from 'styled-components';
import { mergeRefs } from '@equinor/eds-utils';
import { TabsContext } from './Tabs.context.js';
import { jsx } from 'react/jsx-runtime';
const variants = {
fullWidth: 'minmax(1%, 360px)',
minWidth: 'max-content'
};
const StyledTabList = styled.div.attrs(() => ({
role: 'tablist'
})).withConfig({
displayName: "TabList__StyledTabList",
componentId: "sc-1g1p5i1-0"
})(["display:grid;grid-auto-flow:column;grid-auto-columns:", ";overflow-x:", ";scroll-snap-type:x mandatory;overscroll-behavior-x:contain;@media (prefers-reduced-motion:no-preference){scroll-behavior:smooth;}@media (hover:none){overflow-x:scroll;-webkit-overflow-scrolling:touch;scrollbar-width:none;& ::-webkit-scrollbar{width:0;height:0;}}"], ({
$variant
}) => variants[$variant], ({
$scrollable
}) => $scrollable ? 'auto' : 'hidden');
const TabList = /*#__PURE__*/forwardRef(function TabsList({
children = [],
...props
}, ref) {
const {
activeTab,
handleChange,
tabsId,
variant = 'minWidth',
scrollable = false,
tabsFocused
} = useContext(TabsContext);
const currentTab = useRef();
const [arrowNavigating, setArrowNavigating] = useState(false);
const selectedTabRef = useCallback(node => {
if (node !== null && tabsFocused || node !== null && arrowNavigating) {
setArrowNavigating(false);
node.focus();
}
}, [arrowNavigating, tabsFocused]);
const Tabs = Children.map(children, (child, $index) => {
const childProps = child.props;
const controlledActive = childProps.value;
const isActive = controlledActive ? controlledActive === activeTab : $index === activeTab;
const tabRef = isActive ? mergeRefs(child.ref, selectedTabRef) : child.ref;
if (isActive) currentTab.current = $index;
return /*#__PURE__*/cloneElement(child, {
id: `${tabsId}-tab-${$index + 1}`,
'aria-controls': `${tabsId}-panel-${$index + 1}`,
active: isActive,
$index,
onClick: () => handleChange($index),
ref: tabRef
});
});
const focusableChildren = Tabs.filter(child => {
const childProps = child.props;
return !childProps.disabled;
}).map(child => {
const childProps = child.props;
return childProps.$index;
});
const firstFocusableChild = focusableChildren[0];
const lastFocusableChild = focusableChildren[focusableChildren.length - 1];
const handleTabsChange = (direction, fallbackTab) => {
const i = direction === 'left' ? 1 : -1;
const nextTab = focusableChildren[focusableChildren.indexOf(currentTab.current) - i];
setArrowNavigating(true);
handleChange(nextTab === undefined ? fallbackTab : nextTab);
};
const handleKeyPress = event => {
const {
key
} = event;
if (key === 'ArrowLeft') {
event.preventDefault();
handleTabsChange('left', lastFocusableChild);
}
if (key === 'ArrowRight') {
event.preventDefault();
handleTabsChange('right', firstFocusableChild);
}
};
return /*#__PURE__*/jsx(StyledTabList, {
onKeyDown: handleKeyPress,
ref: ref,
...props,
$variant: variant,
$scrollable: scrollable,
children: Tabs
});
});
export { TabList };