Button.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /* eslint-disable react/destructuring-assignment */
  2. import React, { PureComponent } from 'react';
  3. import classNames from 'classnames';
  4. import PropTypes from 'prop-types';
  5. import { cssClasses, strings } from '@douyinfe/semi-foundation/button/constants';
  6. import '@douyinfe/semi-foundation/button/button.scss';
  7. import { noop } from '@douyinfe/semi-foundation/utils/function';
  8. const btnSizes = strings.sizes;
  9. const { htmlTypes, btnTypes } = strings;
  10. export type HtmlType = 'button' | 'reset' | 'submit';
  11. export type Size = 'default' | 'small' | 'large';
  12. export type Theme = 'solid' | 'borderless' | 'light';
  13. export type Type = 'primary' | 'secondary' | 'tertiary' | 'warning' | 'danger';
  14. export interface ButtonProps {
  15. block?: boolean;
  16. circle?: boolean;
  17. disabled?: boolean;
  18. className?: string;
  19. icon?: React.ReactNode;
  20. iconPosition?: 'left' | 'right';
  21. loading?: boolean;
  22. htmlType?: HtmlType;
  23. size?: Size;
  24. style?: React.CSSProperties;
  25. theme?: Theme;
  26. type?: Type;
  27. prefixCls?: string;
  28. onClick?: React.MouseEventHandler<HTMLButtonElement>;
  29. onMouseDown?: React.MouseEventHandler<HTMLButtonElement>;
  30. onMouseEnter?: React.MouseEventHandler<HTMLButtonElement>;
  31. onMouseLeave?: React.MouseEventHandler<HTMLButtonElement>;
  32. }
  33. // TODO: icon configuration
  34. export default class Button extends PureComponent<ButtonProps> {
  35. static defaultProps = {
  36. disabled: false,
  37. size: 'default',
  38. type: 'primary',
  39. theme: 'light',
  40. block: false,
  41. htmlType: 'button',
  42. onMouseDown: noop,
  43. onClick: noop,
  44. onMouseEnter: noop,
  45. onMouseLeave: noop,
  46. prefixCls: cssClasses.PREFIX,
  47. };
  48. static propTypes = {
  49. children: PropTypes.node,
  50. disabled: PropTypes.bool,
  51. prefixCls: PropTypes.string,
  52. style: PropTypes.object,
  53. size: PropTypes.oneOf(btnSizes),
  54. type: PropTypes.oneOf(btnTypes),
  55. block: PropTypes.bool,
  56. onClick: PropTypes.func,
  57. onMouseDown: PropTypes.func,
  58. circle: PropTypes.bool,
  59. loading: PropTypes.bool,
  60. htmlType: PropTypes.oneOf(htmlTypes),
  61. theme: PropTypes.oneOf(strings.themes),
  62. className: PropTypes.string,
  63. onMouseEnter: PropTypes.func,
  64. onMouseLeave: PropTypes.func,
  65. };
  66. render() {
  67. const {
  68. children,
  69. block,
  70. htmlType,
  71. loading,
  72. circle,
  73. className,
  74. style,
  75. disabled,
  76. size,
  77. theme,
  78. type,
  79. prefixCls,
  80. iconPosition,
  81. ...attr
  82. } = this.props;
  83. const baseProps = {
  84. disabled,
  85. ...attr,
  86. className: classNames(
  87. prefixCls,
  88. {
  89. [`${prefixCls}-${type}`]: !disabled && type,
  90. [`${prefixCls}-disabled`]: disabled,
  91. [`${prefixCls}-size-large`]: size === 'large',
  92. [`${prefixCls}-size-small`]: size === 'small',
  93. // [`${prefixCls}-loading`]: loading,
  94. [`${prefixCls}-light`]: theme === 'light',
  95. [`${prefixCls}-block`]: block,
  96. [`${prefixCls}-circle`]: circle,
  97. [`${prefixCls}-borderless`]: theme === 'borderless',
  98. },
  99. className
  100. ),
  101. type: htmlType,
  102. };
  103. return (
  104. // eslint-disable-next-line react/button-has-type
  105. <button
  106. {...baseProps}
  107. onClick={this.props.onClick}
  108. onMouseDown={this.props.onMouseDown}
  109. style={style}
  110. >
  111. <span className={`${prefixCls}-content`} onClick={e => disabled && e.stopPropagation()}>
  112. {children}
  113. </span>
  114. </button>
  115. );
  116. }
  117. }