UNPKG

lucid-ui

Version:

A UI component library from Xandr.

92 lines 4.05 kB
import _ from 'lodash'; import React from 'react'; import PropTypes from 'prop-types'; import Button from '../Button/Button'; import { lucidClassNames } from '../../util/style-helpers'; import { findTypes } from '../../util/component-types'; import reducers from './ButtonGroup.reducers'; import { buildModernHybridComponent } from '../../util/state-management'; const cx = lucidClassNames.bind('&-ButtonGroup'); const { any, func, arrayOf, number } = PropTypes; const ButtonGroupButton = (_props) => null; ButtonGroupButton.displayName = 'ButtonGroup.Button'; ButtonGroupButton.peek = { description: `Renders a \`<Button\`> inside the \`ButtonGroup\`.`, }; const defaultProps = { onSelect: _.noop, selectedIndices: [], }; const nonPassThroughs = [ 'onSelect', 'className', 'children', 'selectedIndices', ]; class ButtonGroup extends React.Component { constructor() { super(...arguments); this.handleSelect = (event, childProps, index) => { const clickedButtonProps = _.get(findTypes(this.props, ButtonGroup.Button)[index], 'props', {}); // If the consumer passed in an `onClick` to the child `ButtonGroup.Button` // component, we should make sure to call that in addition to the // `ButtonGroup`'s `onSelect`. if (_.isFunction(clickedButtonProps.onClick)) { clickedButtonProps.onClick({ event, props: childProps }); } this.props.onSelect(index, { event, props: childProps }); }; } render() { const { selectedIndices, className, children, ...passThroughs } = this.props; const buttonChildProps = _.map(findTypes(this.props, ButtonGroup.Button), 'props'); return (React.createElement("span", { ..._.omit(passThroughs, nonPassThroughs), className: cx('&', className) }, _.map(buttonChildProps, (buttonChildProp, index) => { return ( // The order of the spread operator below is important. If the // consumer puts `isActive` directly on a `ButtonGroup.Button`, we // want that to take precedence over the `selectedIndices` prop on // the parent `ButtonGroup`. However, we want our `onClick` at the // bottom because we manually handle passing the event to the // `ButtonGroup.Button`'s `onClick` if it exists. React.createElement(Button, { isActive: _.includes(selectedIndices, index), ...buttonChildProp, key: index, onClick: ({ event, props }) => this.handleSelect(event, props, index) })); }), children)); } } ButtonGroup.displayName = 'ButtonGroup'; ButtonGroup.peek = { description: `\`Button Group\` allows you to pair \`Buttons\` together to form a seamless cluster. Any props not explicitly called out are spread on to the root component.`, categories: ['controls', 'buttons'], madeFrom: ['Button'], }; ButtonGroup.Button = ButtonGroupButton; ButtonGroup.reducers = reducers; ButtonGroup.defaultProps = defaultProps; ButtonGroup.propTypes = { /** A function that is called with the index of the child button clicked. \`props\` refers to the child button props. Signature: \`(selectedIndex, { event, props }) => {}\` */ onSelect: func, /** Appended to the component-specific class names set on the root element. Value is run through the \`classnames\` library. */ className: any, /** All children should be \`ButtonGroup.Button\`s and they support the same props as \`Button\`s. */ children: any, /** An array of currently selected \`ButtonGroup.Button\`s indices. You can also pass the prop \`isActive\` to individual \`ButtonGroup.Button\` components. */ selectedIndices: arrayOf(number), }; export default buildModernHybridComponent(ButtonGroup, { reducers }); export { ButtonGroup as ButtonGroupDumb }; //# sourceMappingURL=ButtonGroup.js.map