group.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. import React, { PureComponent } from 'react';
  2. import classNames from 'classnames';
  3. import PropTypes from 'prop-types';
  4. import { cssClasses, strings } from '@douyinfe/semi-foundation/tag/constants';
  5. import Tag from './index';
  6. import Popover, { PopoverProps } from '../popover/index';
  7. import { AvatarShape, TagProps } from './interface';
  8. const prefixCls = cssClasses.PREFIX;
  9. const tagSize = strings.TAG_SIZE;
  10. const avatarShapeSet = strings.AVATAR_SHAPE;
  11. export interface TagGroupProps<T> {
  12. style?: React.CSSProperties;
  13. className?: string;
  14. maxTagCount?: number;
  15. restCount?: number;
  16. tagList?: (T extends 'custom' ? React.ReactNode : TagProps)[];
  17. size?: 'small' | 'large';
  18. showPopover?: boolean;
  19. popoverProps?: PopoverProps;
  20. avatarShape?: AvatarShape;
  21. mode?: string;
  22. }
  23. export default class TagGroup<T> extends PureComponent<TagGroupProps<T>> {
  24. static defaultProps = {
  25. style: {},
  26. className: '',
  27. size: tagSize[0],
  28. avatarShape: 'square',
  29. };
  30. static propTypes = {
  31. children: PropTypes.node,
  32. style: PropTypes.object,
  33. className: PropTypes.string,
  34. maxTagCount: PropTypes.number,
  35. restCount: PropTypes.number,
  36. tagList: PropTypes.array,
  37. size: PropTypes.oneOf(tagSize),
  38. mode: PropTypes.string,
  39. showPopover: PropTypes.bool,
  40. popoverProps: PropTypes.object,
  41. avatarShape: PropTypes.oneOf(avatarShapeSet),
  42. };
  43. renderNTag(n: number, restTags: React.ReactNode) {
  44. const { size, showPopover, popoverProps } = this.props;
  45. let nTag = (
  46. <Tag
  47. closable={false}
  48. size={size}
  49. color="grey"
  50. style={{ backgroundColor: 'transparent' }}
  51. key="_+n"
  52. >
  53. +{n}
  54. </Tag>
  55. );
  56. if (showPopover) {
  57. nTag = (
  58. <Popover
  59. showArrow
  60. content={restTags}
  61. trigger="hover"
  62. position="top"
  63. autoAdjustOverflow
  64. className={`${prefixCls}-rest-group-popover`}
  65. {...popoverProps}
  66. key="_+n_Popover"
  67. >
  68. {nTag}
  69. </Popover>
  70. );
  71. }
  72. return nTag;
  73. }
  74. renderMergeTags(tags: (Tag | React.ReactNode)[]) {
  75. const { maxTagCount, tagList, restCount } = this.props;
  76. const n = restCount ? restCount : tagList.length - maxTagCount;
  77. let renderTags: (Tag | React.ReactNode)[] = tags;
  78. const normalTags: (Tag | React.ReactNode)[] = tags.slice(0, maxTagCount);
  79. const restTags = tags.slice(maxTagCount) as React.ReactNode;
  80. let nTag = null;
  81. if (n > 0) {
  82. nTag = this.renderNTag(n, restTags);
  83. normalTags.push(nTag);
  84. renderTags = normalTags;
  85. }
  86. return renderTags;
  87. }
  88. renderAllTags() {
  89. const { tagList, size, mode, avatarShape } = this.props;
  90. const renderTags = tagList.map((tag, index): (Tag | React.ReactNode) => {
  91. if (mode === 'custom') {
  92. return tag as React.ReactNode;
  93. }
  94. if (!(tag as TagProps).size) {
  95. (tag as TagProps).size = size;
  96. }
  97. if (!(tag as TagProps).avatarShape) {
  98. (tag as TagProps).avatarShape = avatarShape;
  99. }
  100. return <Tag key={`${index}-tag`} {...(tag as TagProps)} />;
  101. });
  102. return renderTags;
  103. }
  104. render() {
  105. const { style, className, maxTagCount, size } = this.props;
  106. const groupCls = classNames({
  107. [`${prefixCls}-group`]: true,
  108. [`${prefixCls}-group-max`]: maxTagCount,
  109. [`${prefixCls}-group-small`]: size === 'small',
  110. [`${prefixCls}-group-large`]: size === 'large',
  111. }, className);
  112. const tags = this.renderAllTags();
  113. const tagContents = (typeof maxTagCount === 'undefined' ? tags : this.renderMergeTags(tags)) as React.ReactNode;
  114. return (
  115. <div style={style} className={groupCls}>
  116. {tagContents}
  117. </div>
  118. );
  119. }
  120. }