index.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import React, { PureComponent } from 'react';
  2. import classNames from 'classnames';
  3. import PropTypes from 'prop-types';
  4. import { cssClasses, strings } from '@douyinfe/semi-foundation/button/constants';
  5. import { strings as iconStrings } from '@douyinfe/semi-foundation/icons/constants';
  6. import Button, { Theme, ButtonProps } from '../button/Button';
  7. import SpinIcon from '../spin/icon';
  8. import { IconSize } from '@douyinfe/semi-icons';
  9. import { noop } from 'lodash';
  10. import '@douyinfe/semi-foundation/button/iconButton.scss';
  11. const iconSizes = iconStrings.SIZE;
  12. export type HorizontalPaddingType = 'left' | 'right';
  13. export interface IconButtonProps extends ButtonProps {
  14. icon?: React.ReactNode;
  15. iconPosition?: 'left' | 'right';
  16. iconSize?: IconSize;
  17. iconStyle?: React.CSSProperties;
  18. loading?: boolean;
  19. theme?: Theme;
  20. style?: React.CSSProperties;
  21. className?: string;
  22. disabled?: boolean;
  23. noHorizontalPadding?: boolean | HorizontalPaddingType | HorizontalPaddingType[];
  24. prefixCls?: string;
  25. contentClassName?: string;
  26. }
  27. // TODO: add a buttonGroup component
  28. // TODO: icon configuration
  29. class IconButton extends PureComponent<IconButtonProps> {
  30. static defaultProps = {
  31. iconPosition: strings.DEFAULT_ICON_POSITION,
  32. prefixCls: cssClasses.PREFIX,
  33. loading: false,
  34. noHorizontalPadding: false, // true same as ['left', 'right']
  35. onMouseEnter: noop,
  36. onMouseLeave: noop,
  37. };
  38. static elementType = "IconButton";
  39. static propTypes = {
  40. iconStyle: PropTypes.object,
  41. style: PropTypes.object,
  42. loading: PropTypes.bool,
  43. prefixCls: PropTypes.string,
  44. icon: PropTypes.oneOfType([PropTypes.object, PropTypes.string, PropTypes.node]),
  45. iconSize: PropTypes.oneOf(iconSizes),
  46. noHorizontalPadding: PropTypes.oneOfType([PropTypes.bool, PropTypes.string, PropTypes.array]),
  47. children: PropTypes.node,
  48. theme: PropTypes.string,
  49. iconPosition: PropTypes.oneOf(strings.iconPositions),
  50. className: PropTypes.string,
  51. onMouseEnter: PropTypes.func,
  52. onMouseLeave: PropTypes.func,
  53. };
  54. render() {
  55. const {
  56. children: originChildren,
  57. iconPosition,
  58. iconSize,
  59. iconStyle,
  60. style: originStyle,
  61. icon,
  62. noHorizontalPadding,
  63. theme,
  64. className,
  65. prefixCls,
  66. loading,
  67. ...otherProps
  68. } = this.props;
  69. const style = { ...originStyle };
  70. // TODO: review check
  71. if (Array.isArray(noHorizontalPadding)) {
  72. noHorizontalPadding.includes('left') && (style.paddingLeft = 0);
  73. noHorizontalPadding.includes('right') && (style.paddingRight = 0);
  74. } else if (noHorizontalPadding === true) {
  75. style.paddingLeft = 0;
  76. style.paddingRight = 0;
  77. } else if (typeof noHorizontalPadding === 'string') {
  78. noHorizontalPadding === 'left' && (style.paddingLeft = 0);
  79. noHorizontalPadding === 'right' && (style.paddingRight = 0);
  80. }
  81. let finalChildren = null;
  82. let IconElem = null;
  83. if (loading && !otherProps.disabled) {
  84. IconElem = <SpinIcon />;
  85. } else if (React.isValidElement(icon)) {
  86. IconElem = icon;
  87. }
  88. const btnTextCls = classNames({
  89. [`${prefixCls}-content-left`]: iconPosition === 'right',
  90. [`${prefixCls}-content-right`]: iconPosition === 'left',
  91. });
  92. const xSemiProp = this.props['x-semi-children-alias'] || 'children';
  93. const children = originChildren != null ? <span className={btnTextCls} x-semi-prop={xSemiProp}>{originChildren}</span> : null;
  94. if (iconPosition === 'left') {
  95. finalChildren = (
  96. <>
  97. {IconElem}
  98. {children}
  99. </>
  100. );
  101. } else {
  102. finalChildren = (
  103. <>
  104. {children}
  105. {IconElem}
  106. </>
  107. );
  108. }
  109. const iconBtnCls = classNames(className, `${prefixCls}-with-icon`, {
  110. [`${prefixCls}-with-icon-only`]: children == null || (children as any) === '',
  111. [`${prefixCls}-loading`]: loading,
  112. });
  113. return (
  114. <Button {...otherProps} className={iconBtnCls} theme={theme} style={style}>
  115. {finalChildren}
  116. </Button>
  117. );
  118. }
  119. }
  120. export default IconButton;