UNPKG

lucid-ui

Version:

A UI component library from AppNexus.

180 lines (179 loc) 7.55 kB
import _ from 'lodash'; import React from 'react'; import PropTypes from 'react-peek/prop-types'; import { lucidClassNames } from '../../util/style-helpers'; import { filterTypes, findTypes, omitProps, } from '../../util/component-types'; import { buildModernHybridComponent } from '../../util/state-management'; import * as reducers from './Submarine.reducers'; import SplitHorizontal from '../SplitHorizontal/SplitHorizontal'; import ChevronIcon from '../Icon/ChevronIcon/ChevronIcon'; import GripperHorizontalIcon from '../Icon/GripperHorizontalIcon/GripperHorizontalIcon'; import Button from '../Button/Button'; const cx = lucidClassNames.bind('&-Submarine'); const { any, bool, func, node, number, string, oneOf, oneOfType } = PropTypes; const Primary = (_props) => null; Primary.peek = { description: ` Primary content rendered beside the Submarine. `, }; Primary.displayName = 'SplitHorizontal.Primary'; Primary.propName = 'Primary'; const Title = (_props) => null; Title.peek = { description: ` Submarine title; `, }; Title.displayName = 'Submarine.Title'; Title.propName = 'Title'; const Bar = (_props) => null; Bar.peek = { description: ` Submarine bar; `, }; Bar.displayName = 'Submarine.Bar'; Bar.propName = 'Bar'; Bar.propTypes = { Title: any ` Set the title of the Submarine. (alias for \`Submarine.Title\`) `, }; const defaultProps = { isExpanded: true, isAnimated: true, height: 250, position: 'bottom', isResizeDisabled: false, isHidden: false, isTitleShownCollapsed: false, onResizing: _.noop, onResize: _.noop, onToggle: _.noop, }; class Submarine extends React.Component { constructor() { super(...arguments); this.handleExpanderClick = ({ event, }) => { const { onToggle } = this.props; onToggle({ props: this.props, event }); }; this.handleResizing = (height, { event }) => { const { onResizing } = this.props; onResizing(height, { props: this.props, event }); }; this.handleResize = (height, { event }) => { const { onResize } = this.props; onResize(height, { props: this.props, event }); }; } render() { const { children, className, isExpanded, isAnimated, position, isResizeDisabled, height, isHidden, isTitleShownCollapsed, ...passThroughs } = this.props; const primaryProps = _.get(_.first(filterTypes(children, Submarine.Primary)), 'props', {}); // props from first Primary const barProps = _.get(_.first(filterTypes(children, Submarine.Bar)), 'props', {}); // props from first Bar const titleProps = _.get(findTypes(barProps, Submarine.Title).concat(findTypes(this.props, Submarine.Title)), // get titles from Bar and parent Submarine '[0].props', // select props from the first title element React.createElement(Submarine.Title).props // default props ); let PrimaryPane, BarPane; // using Left/Right Pane as primary depends on position if (position !== 'bottom') { PrimaryPane = SplitHorizontal.BottomPane; BarPane = SplitHorizontal.TopPane; } else { PrimaryPane = SplitHorizontal.TopPane; BarPane = SplitHorizontal.BottomPane; } // leave 33px of sidebar to stick out when collapsed, or 0px if hidden const collapseShift = isHidden ? 0 : 33; return (React.createElement(SplitHorizontal, Object.assign({}, omitProps(passThroughs, undefined, _.keys(Submarine.propTypes), false), { className: cx('&', { '&-is-resize-disabled': isResizeDisabled, '&-is-position-bottom': position === 'bottom', '&-is-position-top': position !== 'bottom', }, className), isAnimated: isAnimated, isExpanded: isExpanded && !isHidden, collapseShift: collapseShift, onResizing: this.handleResizing, onResize: this.handleResize }), React.createElement(BarPane, Object.assign({}, omitProps(barProps, undefined, _.keys(Submarine.Bar.propTypes), false), { className: cx('&-Bar', barProps.className), height: height }), React.createElement("div", { className: cx('&-Bar-overlay') }), React.createElement("div", { className: cx('&-Bar-header') }, React.createElement("div", Object.assign({}, titleProps, { className: cx('&-Bar-Title', { '&-Bar-Title-is-shown-collapsed': isTitleShownCollapsed }, titleProps.className) })), React.createElement(Button, { className: cx('&-expander'), kind: 'invisible', onClick: this.handleExpanderClick, hasOnlyIcon: true }, React.createElement(ChevronIcon, { direction: (isExpanded && position === 'bottom') || (!isExpanded && position !== 'bottom') ? 'down' : 'up' }))), React.createElement("div", { className: cx('&-Bar-content') }, barProps.children)), React.createElement(SplitHorizontal.Divider, { className: cx('&-Divider') }, React.createElement(GripperHorizontalIcon, { className: cx('&-Divider-gripper') })), React.createElement(PrimaryPane, Object.assign({}, primaryProps, { className: cx('&-Primary', primaryProps.className), isPrimary: true })))); } } Submarine.displayName = 'Submarine'; Submarine.Bar = Bar; Submarine.Title = Title; Submarine.Primary = Primary; Submarine.peek = { description: ` \`Submarine\` renders a collapsible, resizeable side bar panel next to primary content. `, categories: ['layout'], madeFrom: ['SplitHorizontal', 'ChevronIcon', 'GripperHorizontalIcon'], }; Submarine.reducers = reducers; Submarine.propTypes = { className: string ` Appended to the component-specific class names set on the root element. Value is run through the \`classnames\` library. `, children: node ` Direct children must be types {Submarine.Primary, Submarine.Bar, Submarine.Title}. All content is composed as children of these respective elements. `, height: oneOfType([number, string]) ` Sets the starting height of the Bar. `, isExpanded: bool ` Force the Submarine to be expanded or collapsed. `, isHidden: bool ` Indicates if the Submarine should be shown or not. This will override the value of isExpanded. `, isTitleShownCollapsed: bool ` Indicates if the Title should be shown when the Submarine is collapsed `, isAnimated: bool ` Allows animated expand and collapse behavior. `, position: oneOf(['top', 'bottom']) ` Render the Submarine to the top or bottom of primary content. `, isResizeDisabled: bool ` Disable user resizing of the Submarine. `, Title: any ` Set the title of the Submarine. `, Bar: any ` Set the submarine bar content. `, Primary: any ` Set the primary content of the Submarine. `, onResizing: func ` Called when the user is currently resizing the Submarine. Signature: \`(height, { event, props }) => {}\` `, onResize: func ` Called when the user resizes the Submarine. Signature: \`(height, { event, props }) => {}\` `, onToggle: func ` Called when the user expands or collapses the Submarine. Signature: \`({ event, props }) => {}\` `, }; Submarine.defaultProps = defaultProps; export default buildModernHybridComponent(Submarine, { reducers }); export { Submarine as SubmarineDumb };