1
0

Button.tsx 4.4 KB

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