1import { css } from '@emotion/react'; 2import { borderRadius, shadows, spacing, theme } from '@expo/styleguide'; 3import { TabList, TabPanels, Tabs as ReachTabs, TabsProps } from '@reach/tabs'; 4import * as React from 'react'; 5 6import { TabButton } from './TabButton'; 7 8type Props = React.PropsWithChildren<TabsProps> & { 9 tabs: string[]; 10}; 11 12const generateTabLabels = (children: React.ReactNode) => { 13 return React.Children.map(children, child => 14 React.isValidElement(child) ? child?.props?.label : child || '[untitled]' 15 ); 16}; 17 18export const Tabs = ({ children, tabs }: Props) => { 19 const tabTitles = tabs || generateTabLabels(children); 20 const [tabIndex, setTabIndex] = React.useState(0); 21 22 return ( 23 <ReachTabs index={tabIndex} onChange={setTabIndex} css={tabsWrapperStyle}> 24 <TabList css={tabsListStyle}> 25 {tabTitles.map((title, index) => ( 26 <TabButton key={index} selected={index === tabIndex}> 27 {title} 28 </TabButton> 29 ))} 30 </TabList> 31 <TabPanels css={tabsPanelStyle}>{children}</TabPanels> 32 </ReachTabs> 33 ); 34}; 35 36const tabsWrapperStyle = css({ 37 border: `1px solid ${theme.border.default}`, 38 borderRadius: borderRadius.small, 39 boxShadow: shadows.micro, 40 margin: `${spacing[4]}px 0`, 41}); 42 43const tabsPanelStyle = css({ 44 padding: `${spacing[4]}px ${spacing[5]}px ${spacing[1]}px`, 45 46 'pre:first-child': { 47 marginTop: spacing[1], 48 }, 49 50 ul: { 51 marginBottom: spacing[3], 52 }, 53}); 54 55const tabsListStyle = css({ 56 borderBottom: `1px solid ${theme.border.default}`, 57}); 58