UNPKG

@equinor/eds-core-react

Version:

The React implementation of the Equinor Design System

95 lines (92 loc) 3.3 kB
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 };