UNPKG

@appearhere/bloom

Version:

Appear Here's pattern library and styleguide

78 lines (69 loc) 2.15 kB
import PropTypes from 'prop-types'; import React, { Children } from 'react'; import cx from 'classnames'; import warning from 'warning'; import { Motion, spring } from 'react-motion'; import { SIBLING_TRANSITION as SPRING_CONFIG } from '../../../constants/springs'; import css from './TabBar.css'; const TabBar = ({ children, variant, activeMarkerOffset, scrollable, className }) => { const tabWidth = scrollable ? (100 / children.length) * 2 : 100 / children.length; const activeTabs = children .map((child, i) => { if (child.props.active === true) return i; return false; }) .filter(originalIndex => originalIndex !== false); const activeTabIndex = activeTabs[0]; warning(activeTabs.length < 2, '`<TabBar />`: has multiple active tabs'); return ( <div className={cx(css.root, css[variant], scrollable ? css.scrollable : null)}> <div className={cx(css.bar, className)}> { Children.map(children, (child, i) => ( <div className={cx( css.link, activeTabIndex === i ? css.active : null, (scrollable && i === 0) ? css.scrollableLink : null, )} style={{ width: `${tabWidth}%`, }} > { child } </div> )) } </div> <Motion defaultStyle={{ x: 0, }} style={{ x: spring(activeTabIndex * 100, SPRING_CONFIG), }} > { ({ x }) => ( <div className={cx(css.underline, scrollable ? css.scrollableUnderline : null)} style={{ width: `${tabWidth}%`, transform: `translate3d(${x}%, ${activeMarkerOffset}px, 0)`, }} /> ) } </Motion> </div> ); }; TabBar.propTypes = { children: PropTypes.array.isRequired, variant: PropTypes.oneOf(['light', 'dark']), className: PropTypes.string, activeMarkerOffset: PropTypes.number, scrollable: PropTypes.bool, }; TabBar.defaultProps = { variant: 'light', activeMarkerOffset: -1, scrollable: false, }; export default TabBar;