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.

76 lines
1.9 KiB

  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import { FormattedNumber } from 'react-intl';
  4. import TransitionMotion from 'react-motion/lib/TransitionMotion';
  5. import spring from 'react-motion/lib/spring';
  6. import { reduceMotion } from 'mastodon/initial_state';
  7. const obfuscatedCount = count => {
  8. if (count < 0) {
  9. return 0;
  10. } else if (count <= 1) {
  11. return count;
  12. } else {
  13. return '1+';
  14. }
  15. };
  16. export default class AnimatedNumber extends React.PureComponent {
  17. static propTypes = {
  18. value: PropTypes.number.isRequired,
  19. obfuscate: PropTypes.bool,
  20. };
  21. state = {
  22. direction: 1,
  23. };
  24. componentWillReceiveProps (nextProps) {
  25. if (nextProps.value > this.props.value) {
  26. this.setState({ direction: 1 });
  27. } else if (nextProps.value < this.props.value) {
  28. this.setState({ direction: -1 });
  29. }
  30. }
  31. willEnter = () => {
  32. const { direction } = this.state;
  33. return { y: -1 * direction };
  34. }
  35. willLeave = () => {
  36. const { direction } = this.state;
  37. return { y: spring(1 * direction, { damping: 35, stiffness: 400 }) };
  38. }
  39. render () {
  40. const { value, obfuscate } = this.props;
  41. const { direction } = this.state;
  42. if (reduceMotion) {
  43. return obfuscate ? obfuscatedCount(value) : <FormattedNumber value={value} />;
  44. }
  45. const styles = [{
  46. key: `${value}`,
  47. data: value,
  48. style: { y: spring(0, { damping: 35, stiffness: 400 }) },
  49. }];
  50. return (
  51. <TransitionMotion styles={styles} willEnter={this.willEnter} willLeave={this.willLeave}>
  52. {items => (
  53. <span className='animated-number'>
  54. {items.map(({ key, data, style }) => (
  55. <span key={key} style={{ position: (direction * style.y) > 0 ? 'absolute' : 'static', transform: `translateY(${style.y * 100}%)` }}>{obfuscate ? obfuscatedCount(data) : <FormattedNumber value={data} />}</span>
  56. ))}
  57. </span>
  58. )}
  59. </TransitionMotion>
  60. );
  61. }
  62. }