UNPKG

@6thquake/react-material

Version:

React components that implement Google's Material Design.

292 lines (263 loc) 7.28 kB
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/objectWithoutPropertiesLoose"; import React from 'react'; import PropTypes from 'prop-types'; import warning from 'warning'; import classNames from 'classnames'; import { createChainedFunction, find } from '../utils/helpers'; import withStyles from '../styles/withStyles'; import Check from '@material-ui/icons/Check'; const styles = theme => ({ root: { display: 'flex', alignItems: 'center', justifyContent: 'flex-start' }, wrapper: { position: 'relative', overflow: 'visible', cursor: 'pointer' }, disabled: { cursor: 'default' }, foldUp: {}, checked: {}, smallAvatar: { width: 24, height: 24, fontSize: theme.typography.pxToRem(12) }, mediumAvatar: { width: 40, height: 40, fontSize: theme.typography.pxToRem(20) }, largeAvatar: { width: 56, height: 56, fontSize: theme.typography.pxToRem(28) }, check: { position: 'absolute', zIndex: 1, borderRadius: '50%', border: '2px solid #fff', color: '#fff', background: 'green' }, small: { fontSize: theme.typography.pxToRem(12), bottom: -2, right: -2 }, medium: { fontSize: theme.typography.pxToRem(16), bottom: -4, right: -4 }, large: { fontSize: theme.typography.pxToRem(24), bottom: -8, right: -8 }, rowContent: { display: 'flex', flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-start' }, columnContent: { display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center' }, rowReverse: { flexDirection: 'row-reverse' }, columnReverse: { flexDirection: 'column-reverse' } }); class AvatarGroup extends React.Component { constructor(props) { super(props); this.avatars = []; this.handleClick = (val, event) => { const { value: valueProp, multiple, disabled } = this.props; if (disabled) { return; } let value = this.isControlled ? valueProp : this.state.value; value = multiple ? value.slice() : []; const index = value.indexOf(val); if (index === -1) { value.push(val); } else { value.splice(index, 1); } if (!this.isControlled) { this.setState({ value }); } if (this.props.onChange) { this.props.onChange(event, value); } }; this.isControlled = props.value != null; if (!this.isControlled) { this.state = { value: props.defaultValue }; } } render() { const _this$props = this.props, { classes, component: Component, children, value: valueProp, size, foldUp, spacing, placeholder, max, disabled } = _this$props, other = _objectWithoutPropertiesLoose(_this$props, ["classes", "className", "component", "children", "name", "value", "onChange", "size", "foldUp", "spacing", "direction", "placeholder", "max", "disabled"]); const value = this.isControlled ? valueProp : this.state.value; this.avatars = []; return React.createElement(Component, { role: "radiogroup", className: classes.root }, React.Children.map(children, (child, index) => { if (index >= max) { return null; } if (!React.isValidElement(child)) { return null; } process.env.NODE_ENV !== "production" ? warning(child.type !== React.Fragment, ["React-Material: the AvatarGroup component doesn't accept a Fragment as a child.", 'Consider providing an array instead.'].join('\n')) : void 0; const { direction } = child.props; const val = typeof child.props.value !== 'undefined' ? child.props.value : index; const checked = value && value.indexOf(val) !== -1; return React.createElement("div", { className: classNames({ [classes.wrapper]: true, [classes.foldUp]: foldUp, [classes.rowContent]: direction === 'left' || direction === 'right', [classes.columnContent]: direction === 'top' || direction === 'bottom', [classes.rowReverse]: direction === 'left', [classes.columnReverse]: direction === 'top', [classes.disabled]: disabled, [classes.checked]: checked }), style: foldUp ? { transform: `translateX(-${index * 20}%)` } : { margin: `0px ${spacing}px` }, onClick: createChainedFunction(child.props.onClick, this.handleClick.bind(this, val)) }, React.cloneElement(child, { className: classNames({ [classes[`${size}Avatar`]]: true }), inputRef: node => { if (node) { this.avatars.push(node); } } }), child.props.content, checked && React.createElement(Check, { className: classNames({ [classes.check]: true, [classes[`${size}`]]: true }) })); }), React.Children.count(children) > max && '...', React.Children.count(children) <= 0 && placeholder); } } process.env.NODE_ENV !== "production" ? AvatarGroup.propTypes = { /** * Used to render icon or text elements inside the AvatarGroup. * This can be an element, or just a string. */ children: PropTypes.node, /** * Override or extend the styles applied to the component. * See [CSS API](#css-api) below for more details. */ classes: PropTypes.object.isRequired, /** * 'div' The component used for the root node. Either a string to use a DOM element or a component. */ component: PropTypes.element, /** * The default selected avatar, useful when not controlling the component. */ defaultValue: PropTypes.arrayOf([PropTypes.string, PropTypes.number, PropTypes.bool]), /** * If true, do not fire click event. */ disabled: PropTypes.bool, /** * If true, the avatars will be fold up. */ foldUp: PropTypes.bool, /** * max item length. */ max: PropTypes.number, /** * a multiple select filter or single select filter. */ multiple: PropTypes.bool, /** * The name used to reference the value of the control. */ name: PropTypes.string, /** * Callback fired when a avatar is selected. * * @param {object} event The event source of the callback. * You can pull out the new value by accessing `event.target.value`. * @param {string} value The `value` of the selected avatar */ onChange: PropTypes.func, /** * The short hint displayed without any avatars. */ placeholder: PropTypes.string, /** * the size of each item. */ size: PropTypes.oneOf(['small', 'medium', 'large']), /** * spacing between items. */ spacing: PropTypes.number, /** * Value of the selected avatar. */ value: PropTypes.arrayOf([PropTypes.string, PropTypes.number, PropTypes.bool]) } : void 0; AvatarGroup.defaultProps = { component: 'div', size: 'medium', foldUp: false, spacing: 8, multiple: false, max: 20, placeholder: '暂无', disabled: false }; export default withStyles(styles, { name: 'RMAvatarGroup' })(AvatarGroup);