lucid-ui
Version:
A UI component library from AppNexus.
180 lines (179 loc) • 7.55 kB
JavaScript
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 };