lucid-ui
Version:
A UI component library from Xandr.
92 lines • 4.05 kB
JavaScript
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