import React, { Children, Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import { styled } from '@storybook/theming'; import { Placeholder } from '../placeholder/placeholder'; import { FlexBar } from '../bar/bar'; import { TabButton } from '../bar/button'; const Wrapper = styled.div( ({ theme, bordered }) => bordered ? { backgroundClip: 'padding-box', borderRadius: 4, border: `1px solid ${theme.mainBorderColor}`, } : {}, ({ absolute }) => absolute ? { width: '100%', height: '100%', boxSizing: 'border-box', display: 'flex', flexDirection: 'column', } : { display: 'block', } ); export const TabBar = styled.div( { whiteSpace: 'nowrap', height: '100%', '&:first-child': { marginLeft: 0, }, }, ({ scroll }) => ({ // super lame, hiding of scrollbar paddingBottom: 50, overflowX: scroll ? 'auto' : 'visisble', overflowY: scroll ? 'hidden' : 'visisble', }), ({ flex }) => flex ? { flex: typeof flex === 'number' ? flex : 1, } : {} ); const Content = styled.div( { display: 'block', position: 'relative', }, ({ theme }) => ({ fontSize: `${theme.typography.size.s2}px`, }), ({ absolute }) => absolute ? { position: 'relative', overflow: 'auto', flex: 1, width: '100%', } : {} ); const VisuallyHidden = styled.div(({ active }) => active ? { display: 'block' } : { display: 'none' } ); export const TabWrapper = ({ active, render, children }) => ( {render ? render() : children} ); TabWrapper.propTypes = { active: PropTypes.bool.isRequired, render: PropTypes.func, children: PropTypes.node, }; TabWrapper.defaultProps = { render: undefined, children: undefined, }; export const panelProps = { active: PropTypes.bool, }; const childrenToList = (children, selected) => Children.toArray(children).map(({ props: { title, id, children: childrenOfChild } }, index) => { const content = Array.isArray(childrenOfChild) ? childrenOfChild[0] : childrenOfChild; return { active: selected ? id === selected : index === 0, title, id, render: typeof content === 'function' ? content : // eslint-disable-next-line react/prop-types ({ active, key }) => ( {content} ), }; }); export const Tabs = React.memo( ({ children, selected, actions, absolute, bordered, scroll, tools, id: htmlId }) => { const list = childrenToList(children, selected); return list.length ? ( {list.map(({ title, id, active }) => ( e.preventDefault() || actions.onSelect(id)} role="tab" > {typeof title === 'function' ? title() : title} ))} {tools ? {tools} : null} {list.map(({ id, active, render }) => render({ key: id, active }))} ) : ( Nothing found ); } ); Tabs.displayName = 'Tabs'; Tabs.propTypes = { id: PropTypes.string, children: PropTypes.node, tools: PropTypes.node, selected: PropTypes.string, actions: PropTypes.shape({ onSelect: PropTypes.func.isRequired, }).isRequired, absolute: PropTypes.bool, bordered: PropTypes.bool, scroll: PropTypes.bool, }; Tabs.defaultProps = { id: null, children: null, tools: null, selected: null, absolute: false, bordered: false, scroll: true, }; // eslint-disable-next-line react/no-multi-comp export class TabsState extends Component { static propTypes = { children: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.node, PropTypes.func])), initial: PropTypes.string, absolute: PropTypes.bool, bordered: PropTypes.bool, scroll: PropTypes.bool, }; static defaultProps = { children: [], initial: null, absolute: false, bordered: false, scroll: true, }; constructor(props) { super(props); this.state = { selected: props.initial, }; } render() { const { bordered = false, absolute = false, children, scroll = true } = this.props; const { selected } = this.state; return ( this.setState({ selected: id }), }} > {children} ); } }