Button.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. /* eslint-disable react/destructuring-assignment */
  2. import React, { PureComponent, ReactNode } 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. id?: string;
  16. block?: boolean;
  17. circle?: boolean;
  18. children?: ReactNode | undefined;
  19. disabled?: boolean;
  20. className?: string;
  21. icon?: React.ReactNode;
  22. iconPosition?: 'left' | 'right';
  23. loading?: boolean;
  24. htmlType?: HtmlType;
  25. size?: Size;
  26. style?: React.CSSProperties;
  27. theme?: Theme;
  28. type?: Type;
  29. prefixCls?: string;
  30. onClick?: React.MouseEventHandler<HTMLButtonElement>;
  31. onMouseDown?: React.MouseEventHandler<HTMLButtonElement>;
  32. onMouseEnter?: React.MouseEventHandler<HTMLButtonElement>;
  33. onMouseLeave?: React.MouseEventHandler<HTMLButtonElement>;
  34. 'aria-label'?: React.AriaAttributes['aria-label'];
  35. }
  36. // TODO: icon configuration
  37. export default class Button extends PureComponent<ButtonProps> {
  38. static defaultProps = {
  39. disabled: false,
  40. size: 'default',
  41. type: 'primary',
  42. theme: 'light',
  43. block: false,
  44. htmlType: 'button',
  45. onMouseDown: noop,
  46. onClick: noop,
  47. onMouseEnter: noop,
  48. onMouseLeave: noop,
  49. prefixCls: cssClasses.PREFIX,
  50. };
  51. static propTypes = {
  52. children: PropTypes.node,
  53. disabled: PropTypes.bool,
  54. prefixCls: PropTypes.string,
  55. style: PropTypes.object,
  56. size: PropTypes.oneOf(btnSizes),
  57. type: PropTypes.oneOf(btnTypes),
  58. block: PropTypes.bool,
  59. onClick: PropTypes.func,
  60. onMouseDown: PropTypes.func,
  61. circle: PropTypes.bool,
  62. loading: PropTypes.bool,
  63. htmlType: PropTypes.oneOf(htmlTypes),
  64. theme: PropTypes.oneOf(strings.themes),
  65. className: PropTypes.string,
  66. onMouseEnter: PropTypes.func,
  67. onMouseLeave: PropTypes.func,
  68. 'aria-label': PropTypes.string,
  69. };
  70. render() {
  71. const {
  72. children,
  73. block,
  74. htmlType,
  75. loading,
  76. circle,
  77. className,
  78. style,
  79. disabled,
  80. size,
  81. theme,
  82. type,
  83. prefixCls,
  84. iconPosition,
  85. ...attr
  86. } = this.props;
  87. const baseProps = {
  88. disabled,
  89. ...attr,
  90. className: classNames(
  91. prefixCls,
  92. {
  93. [`${prefixCls}-${type}`]: !disabled && type,
  94. [`${prefixCls}-disabled`]: disabled,
  95. [`${prefixCls}-size-large`]: size === 'large',
  96. [`${prefixCls}-size-small`]: size === 'small',
  97. // [`${prefixCls}-loading`]: loading,
  98. [`${prefixCls}-light`]: theme === 'light',
  99. [`${prefixCls}-block`]: block,
  100. [`${prefixCls}-circle`]: circle,
  101. [`${prefixCls}-borderless`]: theme === 'borderless',
  102. },
  103. className
  104. ),
  105. type: htmlType,
  106. 'aria-disabled': disabled,
  107. };
  108. return (
  109. // eslint-disable-next-line react/button-has-type
  110. <button
  111. {...baseProps}
  112. onClick={this.props.onClick}
  113. onMouseDown={this.props.onMouseDown}
  114. style={style}
  115. >
  116. {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,jsx-a11y/no-static-element-interactions */}
  117. <span className={`${prefixCls}-content`} onClick={e => disabled && e.stopPropagation()}>
  118. {children}
  119. </span>
  120. </button>
  121. );
  122. }
  123. }