1
0

index.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import React, { PureComponent } from 'react';
  2. import cls from 'classnames';
  3. import PropTypes from 'prop-types';
  4. import { isNumber, isString, noop } 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' | 'success';
  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. onMouseEnter?: (e: React.MouseEvent) => any;
  22. onMouseLeave?: (e: React.MouseEvent) => any;
  23. onClick?: (e: React.MouseEvent) => any;
  24. children?: React.ReactNode
  25. }
  26. export default class Badge extends PureComponent<BadgeProps> {
  27. static contextType = ConfigContext;
  28. static propTypes = {
  29. count: PropTypes.node,
  30. dot: PropTypes.bool,
  31. type: PropTypes.oneOf(strings.TYPE_SET),
  32. theme: PropTypes.oneOf(strings.THEME_SET),
  33. position: PropTypes.oneOf(strings.POS_SET),
  34. overflowCount: PropTypes.number,
  35. style: PropTypes.object,
  36. className: PropTypes.string,
  37. children: PropTypes.node,
  38. onClick: PropTypes.func,
  39. onMouseEnter: PropTypes.func,
  40. onMouseLeave: PropTypes.func,
  41. };
  42. static defaultProps = {
  43. dot: false,
  44. type: 'primary',
  45. theme: 'solid',
  46. className: '',
  47. onClick: () => noop,
  48. onMouseEnter: () => noop,
  49. onMouseLeave: () => noop,
  50. };
  51. context: ContextValue;
  52. render() {
  53. const { direction } = this.context;
  54. // DefaultPosition here, static can't get this
  55. const defaultPosition = direction === 'rtl' ? 'leftTop' : 'rightTop';
  56. const { count, dot, type, theme, position = defaultPosition, overflowCount, style, children, className, ...rest } = this.props;
  57. const custom = count && !(isNumber(count) || isString(count));
  58. const showBadge = count !== null && typeof count !== 'undefined';
  59. const wrapper = cls(className, {
  60. [`${prefixCls}-${type}`]: !custom,
  61. [`${prefixCls}-${theme}`]: !custom,
  62. [`${prefixCls}-${position}`]: Boolean(position) && Boolean(children),
  63. [`${prefixCls}-block`]: !children,
  64. [`${prefixCls}-dot`]: dot,
  65. [`${prefixCls}-count`]: !dot && !custom && showBadge,
  66. [`${prefixCls}-custom`]: custom,
  67. });
  68. let content;
  69. if (isNumber(count)) {
  70. content = overflowCount && overflowCount < count ? `${overflowCount}+` : `${count}`;
  71. } else {
  72. content = count;
  73. }
  74. return (
  75. <span className={prefixCls} {...rest}>
  76. {children}
  77. <span className={wrapper} style={style} x-semi-prop="count">
  78. {dot ? null : content}
  79. </span>
  80. </span>
  81. );
  82. }
  83. }