The code powering m.abunchtell.com https://m.abunchtell.com
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.
 
 
 
 

118 lines
2.9 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. size: PropTypes.number,
  14. active: PropTypes.bool,
  15. pressed: PropTypes.bool,
  16. expanded: PropTypes.bool,
  17. style: PropTypes.object,
  18. activeStyle: PropTypes.object,
  19. disabled: PropTypes.bool,
  20. inverted: PropTypes.bool,
  21. animate: PropTypes.bool,
  22. overlay: PropTypes.bool,
  23. tabIndex: PropTypes.string,
  24. };
  25. static defaultProps = {
  26. size: 18,
  27. active: false,
  28. disabled: false,
  29. animate: false,
  30. overlay: false,
  31. tabIndex: '0',
  32. };
  33. handleClick = (e) => {
  34. e.preventDefault();
  35. if (!this.props.disabled) {
  36. this.props.onClick(e);
  37. }
  38. }
  39. render () {
  40. const style = {
  41. fontSize: `${this.props.size}px`,
  42. width: `${this.props.size * 1.28571429}px`,
  43. height: `${this.props.size * 1.28571429}px`,
  44. lineHeight: `${this.props.size}px`,
  45. ...this.props.style,
  46. ...(this.props.active ? this.props.activeStyle : {}),
  47. };
  48. const {
  49. active,
  50. animate,
  51. className,
  52. disabled,
  53. expanded,
  54. icon,
  55. inverted,
  56. overlay,
  57. pressed,
  58. tabIndex,
  59. title,
  60. } = this.props;
  61. const classes = classNames(className, 'icon-button', {
  62. active,
  63. disabled,
  64. inverted,
  65. overlayed: overlay,
  66. });
  67. if (!animate) {
  68. // Perf optimization: avoid unnecessary <Motion> components unless
  69. // we actually need to animate.
  70. return (
  71. <button
  72. aria-label={title}
  73. aria-pressed={pressed}
  74. aria-expanded={expanded}
  75. title={title}
  76. className={classes}
  77. onClick={this.handleClick}
  78. style={style}
  79. tabIndex={tabIndex}
  80. disabled={disabled}
  81. >
  82. <Icon id={icon} fixedWidth aria-hidden='true' />
  83. </button>
  84. );
  85. }
  86. return (
  87. <Motion defaultStyle={{ rotate: active ? -360 : 0 }} style={{ rotate: animate ? spring(active ? -360 : 0, { stiffness: 120, damping: 7 }) : 0 }}>
  88. {({ rotate }) => (
  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. style={style}
  97. tabIndex={tabIndex}
  98. disabled={disabled}
  99. >
  100. <Icon id={icon} style={{ transform: `rotate(${rotate}deg)` }} fixedWidth aria-hidden='true' />
  101. </button>
  102. )}
  103. </Motion>
  104. );
  105. }
  106. }