闭社主体 forked from https://github.com/tootsuite/mastodon
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
3.6 KiB

  1. import React from 'react';
  2. import Motion from '../features/ui/util/optional_motion';
  3. import spring from 'react-motion/lib/spring';
  4. import PropTypes from 'prop-types';
  5. import classNames from 'classnames';
  6. import Icon from 'mastodon/components/icon';
  7. export default class IconButton extends React.PureComponent {
  8. static propTypes = {
  9. className: PropTypes.string,
  10. title: PropTypes.string.isRequired,
  11. icon: PropTypes.string.isRequired,
  12. onClick: PropTypes.func,
  13. onMouseDown: PropTypes.func,
  14. onKeyDown: PropTypes.func,
  15. onKeyPress: PropTypes.func,
  16. size: PropTypes.number,
  17. active: PropTypes.bool,
  18. pressed: PropTypes.bool,
  19. expanded: PropTypes.bool,
  20. style: PropTypes.object,
  21. activeStyle: PropTypes.object,
  22. disabled: PropTypes.bool,
  23. inverted: PropTypes.bool,
  24. animate: PropTypes.bool,
  25. overlay: PropTypes.bool,
  26. tabIndex: PropTypes.string,
  27. };
  28. static defaultProps = {
  29. size: 18,
  30. active: false,
  31. disabled: false,
  32. animate: false,
  33. overlay: false,
  34. tabIndex: '0',
  35. };
  36. handleClick = (e) => {
  37. e.preventDefault();
  38. if (!this.props.disabled) {
  39. this.props.onClick(e);
  40. }
  41. }
  42. handleKeyPress = (e) => {
  43. if (this.props.onKeyPress && !this.props.disabled) {
  44. this.props.onKeyPress(e);
  45. }
  46. }
  47. handleMouseDown = (e) => {
  48. if (!this.props.disabled && this.props.onMouseDown) {
  49. this.props.onMouseDown(e);
  50. }
  51. }
  52. handleKeyDown = (e) => {
  53. if (!this.props.disabled && this.props.onKeyDown) {
  54. this.props.onKeyDown(e);
  55. }
  56. }
  57. render () {
  58. const style = {
  59. fontSize: `${this.props.size}px`,
  60. width: `${this.props.size * 1.28571429}px`,
  61. height: `${this.props.size * 1.28571429}px`,
  62. lineHeight: `${this.props.size}px`,
  63. ...this.props.style,
  64. ...(this.props.active ? this.props.activeStyle : {}),
  65. };
  66. const {
  67. active,
  68. animate,
  69. className,
  70. disabled,
  71. expanded,
  72. icon,
  73. inverted,
  74. overlay,
  75. pressed,
  76. tabIndex,
  77. title,
  78. } = this.props;
  79. const classes = classNames(className, 'icon-button', {
  80. active,
  81. disabled,
  82. inverted,
  83. overlayed: overlay,
  84. });
  85. if (!animate) {
  86. // Perf optimization: avoid unnecessary <Motion> components unless
  87. // we actually need to animate.
  88. return (
  89. <button
  90. aria-label={title}
  91. aria-pressed={pressed}
  92. aria-expanded={expanded}
  93. title={title}
  94. className={classes}
  95. onClick={this.handleClick}
  96. onMouseDown={this.handleMouseDown}
  97. onKeyDown={this.handleKeyDown}
  98. onKeyPress={this.handleKeyPress}
  99. style={style}
  100. tabIndex={tabIndex}
  101. disabled={disabled}
  102. >
  103. <Icon id={icon} fixedWidth aria-hidden='true' />
  104. </button>
  105. );
  106. }
  107. return (
  108. <Motion defaultStyle={{ rotate: active ? -360 : 0 }} style={{ rotate: animate ? spring(active ? -360 : 0, { stiffness: 120, damping: 7 }) : 0 }}>
  109. {({ rotate }) => (
  110. <button
  111. aria-label={title}
  112. aria-pressed={pressed}
  113. aria-expanded={expanded}
  114. title={title}
  115. className={classes}
  116. onClick={this.handleClick}
  117. onMouseDown={this.handleMouseDown}
  118. onKeyDown={this.handleKeyDown}
  119. onKeyPress={this.handleKeyPress}
  120. style={style}
  121. tabIndex={tabIndex}
  122. disabled={disabled}
  123. >
  124. <Icon id={icon} style={{ transform: `rotate(${rotate}deg)` }} fixedWidth aria-hidden='true' />
  125. </button>
  126. )}
  127. </Motion>
  128. );
  129. }
  130. }