UNPKG

lucid-ui

Version:

A UI component library from Xandr.

138 lines 5.85 kB
import _, { omit } from 'lodash'; import React from 'react'; import PropTypes from 'prop-types'; import { lucidClassNames } from '../../util/style-helpers'; import { filterTypes, getFirst, } from '../../util/component-types'; import { buildModernHybridComponent } from '../../util/state-management'; import { Button } from '../Button/Button'; import { ButtonGroupDumb as ButtonGroup } from '../ButtonGroup/ButtonGroup'; import ChevronIcon from '../Icon/ChevronIcon/ChevronIcon'; import { DropMenuDumb as DropMenu, } from '../DropMenu/DropMenu'; import * as reducers from './SplitButton.reducers'; const cx = lucidClassNames.bind('&-SplitButton'); const { bool, func, node, oneOf, shape, string } = PropTypes; const ButtonChild = (_props) => null; ButtonChild.displayName = 'SplitButton.ButtonChild'; ButtonChild.peek = { description: ` One of many potential \`Button\`s to render in this \`SplitButton\`. The first \`Button\` will be used as the Primary button, while all others will be rendered within the \`DropMenu\` below. `, }; ButtonChild.propTypes = { /** The children to render within the \`Button\`. */ children: node, /** Disables selection of the \`Button\`. */ isDisabled: bool, /** Called when the user clicks the \`Button\`. Signature: \`({ props, event }) => {}\` */ onClick: func, }; class SplitButton extends React.Component { constructor() { super(...arguments); // Handles select events in the DropMenu this.handleSelect = (optionIndex, { event, }) => { const buttonChildProps = _.map(filterTypes(this.props.children, SplitButton.Button), 'props'); if (optionIndex !== null) { this.handleButtonClick(buttonChildProps[optionIndex + 1], event); } }; // Handles clicks on the Primary Button this.handleClick = ({ event, }) => { const clickedButtonProps = _.get(getFirst(this.props, SplitButton.Button), 'props'); // Stop propagation to prevent this `Click` from expanding the `DropMenu` event.stopPropagation(); this.handleButtonClick(clickedButtonProps, event); }; // Handles clicks within handleClick and handleSelect this.handleButtonClick = (buttonProps, event) => { const { DropMenu: { onCollapse }, } = this.props; onCollapse && onCollapse({ props: this.props.DropMenu, event }); if (_.has(buttonProps, 'onClick')) { buttonProps.onClick({ event, props: buttonProps }); } }; } render() { const { className, kind, direction, type, size, DropMenu: dropMenuProps, ...passThroughs } = this.props; const { isExpanded } = dropMenuProps; const [primaryButtonProps, ...buttonChildProps] = _.map(filterTypes(this.props.children, SplitButton.Button), 'props'); return (React.createElement(DropMenu, { ...dropMenuProps, ...omit(passThroughs, [ 'DropMenu', 'children', 'className', 'direction', 'kind', 'size', 'type', 'initialState', 'callbackId', ]), direction: direction, className: cx('&', className), onSelect: this.handleSelect }, React.createElement(DropMenu.Control, null, React.createElement(ButtonGroup, null, React.createElement(Button, { ...primaryButtonProps, className: cx('&-Button-primary', _.get(primaryButtonProps, 'className')), kind: kind, type: type, size: size, onClick: this.handleClick }), React.createElement(Button, { className: cx('&-Button-drop'), size: size, hasOnlyIcon: true, isActive: isExpanded, kind: kind, isDisabled: _.every([primaryButtonProps, ...buttonChildProps], 'isDisabled') }, React.createElement(ChevronIcon, { className: cx('&-ChevronIcon'), direction: direction, size: 10 })))), _.map(buttonChildProps, (buttonChildProp, index) => (React.createElement(DropMenu.Option, { ...buttonChildProp, key: index }))))); } } SplitButton.displayName = 'SplitButton'; SplitButton.Button = ButtonChild; SplitButton.peek = { description: `\`SplitButton\` allows you to combine a single main \`Button\` together with a list of additional \`Buttons\` with actions which will be rendered within a \`DropMenu\`.`, categories: ['controls', 'buttons'], madeFrom: ['Button', 'DropMenu'], }; SplitButton.reducers = reducers; SplitButton.propTypes = { /** Object of DropMenu props which are passed through to the underlying DropMenu component. */ DropMenu: shape(DropMenu.propTypes), /** All children should be \`ButtonGroup.Button\`s and they support the same props as \`Button\`s. */ children: node, /** Appended to the component-specific class names set on the root element. Value is run through the \`classnames\` library. */ className: string, /** Sets the direction the flyout menu will render relative to the SplitButton. */ direction: oneOf(['up', 'down']), /** Style variations of the SplitButton. */ kind: oneOf(['primary', 'danger']), /** Size variations of the SplitButton. */ size: oneOf(['short', 'small', 'large']), /** Form element type variations of SplitButton. Passed through to DOM Button. */ type: string, }; SplitButton.defaultProps = { direction: 'down', type: 'button', DropMenu: DropMenu.defaultProps, }; export default buildModernHybridComponent(SplitButton, { reducers }); export { SplitButton as SplitButtonDumb }; //# sourceMappingURL=SplitButton.js.map