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