lucid-ui
Version:
A UI component library from Xandr.
223 lines • 8.45 kB
JavaScript
import _, { omit } from 'lodash';
import React from 'react';
import PropTypes from 'prop-types';
import { lucidClassNames } from '../../util/style-helpers';
import { filterTypes, findTypes, } from '../../util/component-types';
import { buildModernHybridComponent } from '../../util/state-management';
import * as reducers from './Sidebar.reducers';
import SplitVertical from '../SplitVertical/SplitVertical';
import Button from '../Button/Button';
import ChevronIcon from '../Icon/ChevronIcon/ChevronIcon';
import GripperVerticalIcon from '../Icon/GripperVerticalIcon/GripperVerticalIcon';
const cx = lucidClassNames.bind('&-Sidebar');
const { any, bool, func, node, number, string, object, oneOf, oneOfType } = PropTypes;
const defaultProps = {
isExpanded: true,
isAnimated: true,
width: 250,
position: 'left',
isResizeDisabled: false,
onResizing: _.noop,
onResize: _.noop,
onToggle: _.noop,
};
const Primary = (_props) => null;
Primary.peek = {
description: `Main pane content that will have a paired \`Bar\`.`,
};
Primary.displayName = 'SplitHorizontal.Primary';
Primary.propName = 'Primary';
const Title = (_props) => null;
Title.peek = {
description: `Sidebar title.`,
};
Title.propTypes = {
/**
Content that will be displayed as the title of the Bar. It's only
shown when the user has the Bar expanded.
*/
children: node,
};
Title.propTypes = {
/**
Sidebar title.
*/
children: node,
};
Title.displayName = 'Sidebar.Title';
Title.propName = ['Title', 'title'];
const Bar = (_props) => null;
Bar.peek = {
description: `Content to be placed alongside the \`Primary\` pane.`,
};
Bar.displayName = 'Sidebar.Bar';
Bar.propName = 'Bar';
Bar.propTypes = {
/**
Set the title of the Sidebar. (alias for \`title\` and \`Sidebar.Title\`)
*/
Title: any,
/**
Adds default padding to the sidebar content.
*/
hasGutters: bool,
};
Bar.defaultProps = {
hasGutters: true,
};
class Sidebar extends React.Component {
constructor() {
super(...arguments);
this.handleExpanderClick = (event) => {
const { onToggle } = this.props;
onToggle && onToggle({ props: this.props, event });
};
this.handleResizing = (width, { event }) => {
const { onResizing } = this.props;
onResizing && onResizing(width, { props: this.props, event });
};
this.handleResize = (width, { event }) => {
const { onResize } = this.props;
onResize && onResize(width, { props: this.props, event });
};
}
render() {
const { children, style, className, isExpanded, isAnimated, position, isResizeDisabled, width, ...passThroughs } = this.props;
const primaryProps = _.get(_.first(filterTypes(children, Sidebar.Primary)), 'props', {}); // props from first Primary
const barProps = _.get(_.first(filterTypes(children, Sidebar.Bar)), 'props', {}); // props from first Bar
const titleProps = _.get(findTypes(barProps, Sidebar.Title).concat(findTypes(this.props, Sidebar.Title)), // get titles from Bar and parent Sidebar
'[0].props', // select props from the first title element
{ children: 'Title' } // default props
);
let PrimaryPane, BarPane; // using Left/Right Pane as primary depends on position
if (position !== 'right') {
PrimaryPane = SplitVertical.RightPane;
BarPane = SplitVertical.LeftPane;
}
else {
PrimaryPane = SplitVertical.LeftPane;
BarPane = SplitVertical.RightPane;
}
return (React.createElement(SplitVertical, { ...omit(passThroughs, [
'width',
'isExpanded',
'isAnimated',
'position',
'isResizeDisabled',
'title',
'Title',
'onResizing',
'onResize',
'onToggle',
].concat('initialState')), style: {
minWidth: isExpanded
? _.isNumber(width)
? width + 6
: `calc(${width} + 6px)`
: undefined,
...style,
}, className: cx('&', {
'&-is-resize-disabled': isResizeDisabled,
'&-is-position-right': position === 'right',
'&-is-position-left': position !== 'right',
}, className), isAnimated: isAnimated, isExpanded: isExpanded, collapseShift: 33, onResizing: this.handleResizing, onResize: this.handleResize },
React.createElement(BarPane, { ...omit(barProps, ['hasGutters', 'Title'].concat('initialState')), className: cx('&-Bar', barProps.className), width: width, style: {
overflow: isExpanded ? 'auto' : 'hidden',
} },
React.createElement("div", { className: cx('&-Bar-overlay') }),
React.createElement("div", { className: cx('&-Bar-header') },
React.createElement("div", { ...titleProps, className: cx('&-Bar-Title', titleProps.className) }),
React.createElement(Button, { className: cx('&-expander'), kind: 'invisible', onMouseDown: this.handleExpanderClick, hasOnlyIcon: true },
React.createElement(ChevronIcon, { direction: (isExpanded && position === 'right') ||
(!isExpanded && position !== 'right')
? 'right'
: 'left' }))),
React.createElement("div", { className: cx('&-Bar-content', {
'&-Bar-content-has-gutters': barProps.hasGutters,
}) }, barProps.children)),
React.createElement(SplitVertical.Divider, { className: cx('&-Divider') },
React.createElement(GripperVerticalIcon, { className: cx('&-Divider-gripper') })),
React.createElement(PrimaryPane, { ...primaryProps, className: cx('&-Primary', primaryProps.className), isPrimary: true })));
}
}
Sidebar.displayName = 'Sidebar';
Sidebar.Bar = Bar;
Sidebar.Primary = Primary;
Sidebar.Title = Title;
Sidebar.peek = {
description: `\`Sidebar\` renders a collapsible, resizeable side bar panel next to primary content.`,
categories: ['layout'],
};
Sidebar.reducers = reducers;
Sidebar.propTypes = {
/**
Style object that gets applied to the outer element.
*/
style: object,
/**
Appended to the component-specific class names set on the root element.
Value is run through the \`classnames\` library.
*/
className: string,
/**
Direct children must be types {Sidebar.Primary, Sidebar.Bar,
Sidebar.Title}. All content is composed as children of these respective
elements.
*/
children: node,
/**
Sets the starting width of the Bar.
*/
width: oneOfType([number, string]),
/**
Force the Sidebar to be expanded or collapsed.
*/
isExpanded: bool,
/**
Allows animated expand and collapse behavior.
*/
isAnimated: bool,
/**
Render the Sidebar to the left or right of primary content.
*/
position: oneOf(['left', 'right']),
/**
Disable user resizing of the Sidebar.
*/
isResizeDisabled: bool,
/**
Set the title of the Sidebar. (alias for \`Title\` and \`Sidebar.Title\`)
*/
title: any,
/**
Set the title of the Sidebar. (alias for \`title\` and \`Sidebar.Title\`)
*/
Title: any,
/**
Content to be placed alongside the Primary pane.
*/
Bar: any,
/**
Main pane content that will have a paired \`Bar\`.
*/
Primary: any,
/**
Called when the user is currently resizing the Sidebar. Signature:
\`(width, { event, props }) => {}\`
*/
onResizing: func,
/**
Called when the user resizes the Sidebar. Signature: \`(width, { event,
props }) => {}\`
*/
onResize: func,
/**
Called when the user expands or collapses the Sidebar. Signature: \`({
event, props }) => {}\`
*/
onToggle: func,
};
Sidebar.defaultProps = defaultProps;
export default buildModernHybridComponent(Sidebar, { reducers });
export { Sidebar as SidebarDumb };
//# sourceMappingURL=Sidebar.js.map