avatarGroup.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import React, { PureComponent, Fragment } from 'react';
  2. import cls from 'classnames';
  3. import PropTypes from 'prop-types';
  4. import { get as lodashGet, isFunction, isNumber } from 'lodash';
  5. import Avatar from './index';
  6. import { AvatarGroupProps } from './interface';
  7. import { cssClasses, strings } from '@douyinfe/semi-foundation/avatar/constants';
  8. const sizeSet = strings.SIZE;
  9. const shapeSet = strings.SHAPE;
  10. const overlapFromSet = strings.OVERLAP_FROM;
  11. const prefixCls = cssClasses.PREFIX;
  12. export default class AvatarGroup extends PureComponent<AvatarGroupProps> {
  13. static defaultProps = {
  14. size: 'medium',
  15. shape: 'circle',
  16. overlapFrom: 'start',
  17. };
  18. static propTypes = {
  19. children: PropTypes.node,
  20. shape: PropTypes.oneOf(shapeSet),
  21. size: PropTypes.oneOf(sizeSet),
  22. maxCount: PropTypes.number,
  23. renderMore: PropTypes.func,
  24. overlapFrom: PropTypes.oneOf(overlapFromSet),
  25. };
  26. getAllAvatars() {
  27. const { children } = this.props;
  28. return Array.isArray(children) ? children : [children];
  29. }
  30. getMergeAvatars(avatars: React.ReactNode[]) {
  31. const { maxCount } = this.props;
  32. let renderAvatars = avatars;
  33. const restNumber = avatars.length - maxCount;
  34. const normalAvatars = avatars.slice(0, maxCount);
  35. const restAvatars = avatars.slice(maxCount);
  36. if (restNumber > 0) {
  37. const more = this.renderMoreAvatar(restNumber, restAvatars);
  38. normalAvatars.push(more);
  39. renderAvatars = normalAvatars;
  40. }
  41. return renderAvatars;
  42. }
  43. renderMoreAvatar(restNumber: number, restAvatars: React.ReactNode[]) {
  44. const { renderMore } = this.props;
  45. const moreCls = cls(`${prefixCls}-item-more`);
  46. let moreAvatar = <Avatar className={moreCls} key="_+n">{`+${restNumber}`}</Avatar>;
  47. if (isFunction(renderMore)) {
  48. moreAvatar = <Fragment key="_+n">{renderMore(restNumber, restAvatars)}</Fragment>;
  49. }
  50. return moreAvatar;
  51. }
  52. render() {
  53. // eslint-disable-next-line no-unused-vars
  54. const { children, maxCount, overlapFrom, size, shape, renderMore, ...rest } = this.props;
  55. let inner;
  56. const groupCls = cls({
  57. [`${prefixCls}-group`]: true,
  58. });
  59. if (children) {
  60. const avatars = this.getAllAvatars();
  61. inner = (isNumber(maxCount) ? this.getMergeAvatars(avatars) : avatars).map((itm, index) => {
  62. const className = cls(lodashGet((itm as any).props, 'className'), {
  63. [`${prefixCls}-item-start-${index}`]: overlapFrom === 'start',
  64. [`${prefixCls}-item-end-${index}`]: overlapFrom === 'end',
  65. });
  66. return React.cloneElement((itm as any), { ...rest, className, size, shape, key: index });
  67. });
  68. }
  69. return <div className={groupCls}>{inner}</div>;
  70. }
  71. }