index.tsx 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. import React, { PureComponent } from 'react';
  2. import cls from 'classnames';
  3. import PropTypes from 'prop-types';
  4. import { isNumber, isString } from 'lodash';
  5. import ConfigContext, { ContextValue } from '../configProvider/context';
  6. import { cssClasses, strings } from '@douyinfe/semi-foundation/badge/constants';
  7. import '@douyinfe/semi-foundation/badge/badge.scss';
  8. const prefixCls = cssClasses.PREFIX;
  9. export type BadgeType = 'primary' | 'secondary' | 'tertiary' | 'danger' | 'warning';
  10. export type BadgeTheme = 'solid' | 'light' | 'inverted';
  11. export type BadgePosition = 'leftTop' | 'leftBottom' | 'rightTop' | 'rightBottom';
  12. export interface BadgeProps {
  13. count?: React.ReactNode;
  14. dot?: boolean;
  15. type?: BadgeType;
  16. theme?: BadgeTheme;
  17. position?: BadgePosition;
  18. overflowCount?: number;
  19. style?: React.CSSProperties;
  20. className?: string;
  21. children?: React.ReactNode | undefined;
  22. }
  23. export default class Badge extends PureComponent<BadgeProps> {
  24. static contextType = ConfigContext;
  25. static propTypes = {
  26. count: PropTypes.node,
  27. dot: PropTypes.bool,
  28. type: PropTypes.oneOf(strings.TYPE_SET),
  29. theme: PropTypes.oneOf(strings.THEME_SET),
  30. position: PropTypes.oneOf(strings.POS_SET),
  31. overflowCount: PropTypes.number,
  32. style: PropTypes.object,
  33. className: PropTypes.string,
  34. children: PropTypes.node,
  35. };
  36. static defaultProps = {
  37. dot: false,
  38. type: 'primary',
  39. theme: 'solid',
  40. className: '',
  41. };
  42. context: ContextValue;
  43. render() {
  44. const { direction } = this.context;
  45. // DefaultPosition here, static can't get this
  46. const defaultPosition = direction === 'rtl' ? 'leftTop' : 'rightTop';
  47. // eslint-disable-next-line max-len
  48. const { count, dot, type, theme, position = defaultPosition, overflowCount, style, children, className } = this.props;
  49. const custom = count && !(isNumber(count) || isString(count));
  50. const showBadge = count !== null && typeof count !== 'undefined';
  51. const wrapper = cls(className, {
  52. [`${prefixCls}-${type}`]: !custom,
  53. [`${prefixCls}-${theme}`]: !custom,
  54. [`${prefixCls}-${position}`]: Boolean(position) && Boolean(children),
  55. [`${prefixCls}-block`]: !children,
  56. [`${prefixCls}-dot`]: dot,
  57. [`${prefixCls}-count`]: !dot && !custom && showBadge,
  58. [`${prefixCls}-custom`]: custom,
  59. });
  60. let content;
  61. if (isNumber(count)) {
  62. content = overflowCount && overflowCount < count ? `${overflowCount}+` : `${count}`;
  63. } else {
  64. content = count;
  65. }
  66. return (
  67. <span className={prefixCls}>
  68. {children}
  69. <span className={wrapper} style={style}>
  70. {dot ? null : content}
  71. </span>
  72. </span>
  73. );
  74. }
  75. }