index.tsx 3.4 KB

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