import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Count from 'countup.js';

class CountUp extends Component {
  static defaultProps = {
    decimal: '.',
    decimals: 0,
    duration: null,
    easingFn: null,
    formattingFn: null,
    onEnd: null,
    onPauseResume: null,
    onReset: null,
    onStart: null,
    onUpdate: null,
    prefix: '',
    separator: '',
    start: 0,
    suffix: '',
    redraw: true,
    style: undefined,
    useEasing: true,
  };

  static propTypes = {
    decimal: PropTypes.string,
    decimals: PropTypes.number,
    easingFn: PropTypes.func,
    end: PropTypes.number.isRequired,
    formattingFn: PropTypes.func,
    onEnd: PropTypes.func,
    onStart: PropTypes.func,
    prefix: PropTypes.string,
    redraw: PropTypes.bool,
    separator: PropTypes.string,
    start: PropTypes.number,
    suffix: PropTypes.string,
    style: PropTypes.object,
    useEasing: PropTypes.bool,
  };

  componentDidMount() {
    this.instance = this.createInstance();

    if (this.props.autostart) {
      this.start();
    }
  }

  shouldComponentUpdate(nextProps) {
    const hasCertainPropsChanged =
      this.props.duration !== nextProps.duration ||
      this.props.end !== nextProps.end ||
      this.props.start !== nextProps.start;

    return this.props.redraw || hasCertainPropsChanged;
  }

  componentDidUpdate(prevProps) {
    // If duration or start has changed, there's no way to update the duration
    // or start value. So we need to re-create the CountUp instance in order to
    // restart it.
    if (
      this.props.duration !== prevProps.duration ||
      this.props.start !== prevProps.start
    ) {
      this.instance = this.createInstance();
      this.start();
    }

    // Only end value has changed, so reset and and re-animate with the updated
    // end value.
    if (this.props.end !== prevProps.end) {
      this.instance.reset();
      this.instance.update(this.props.end);
    }
  }

  createInstance = () => {
    const {
      decimal,
      decimals,
      duration,
      easingFn,
      end,
      formattingFn,
      prefix,
      separator,
      start,
      suffix,
      useEasing,
    } = this.props;

    return new Count(this.spanRef.current, start, end, decimals, duration, {
      decimal,
      easingFn,
      formattingFn,
      separator,
      prefix,
      suffix,
      useEasing,
      useGrouping: !!separator,
    });
  };

  pauseResume = (...args) => {
    const { onPauseResume } = this.props;

    if (typeof onPauseResume === 'function') onPauseResume(this);

    this.instance.pauseResume(...args);
  };

  reset = (...args) => {
    const { onReset } = this.props;

    if (typeof onReset === 'function') onReset(this);

    this.instance.reset(...args);
  };

  start = () => {
    const { onEnd, onStart } = this.props;

    this.instance.start(
      typeof onEnd === 'function' ? () => onEnd(this) : undefined,
    );
    if (typeof onStart === 'function') onStart(this);
  };

  update = (...args) => {
    const { onUpdate } = this.props;

    this.instance.reset(...args);
    if (typeof onUpdate === 'function') onUpdate(this);
  };

  spanRef = React.createRef();

  render() {
    const { className, style } = this.props;

    return <span className={className} ref={this.spanRef} style={style} />;
  }
}

export default CountUp;

@@ -2230,25 +2230,37 @@
 w Count(
-this.span
+%0A      this.container
 Ref.curr
@@ -2267,20 +2267,38 @@
 ent,
+%0A     
  start,
- end,
+%0A      end,%0A     
  dec
@@ -2303,16 +2303,22 @@
 ecimals,
+%0A     
  duratio
@@ -2319,19 +2319,27 @@
 uration,
+%0A     
  %7B%0A
+  
       de
@@ -2343,32 +2343,34 @@
  decimal,%0A      
+ 
+ 
 easingFn,%0A      
@@ -2359,24 +2359,26 @@
   easingFn,%0A
+  
       format
@@ -2383,32 +2383,34 @@
 attingFn,%0A      
+ 
+ 
 separator,%0A     
@@ -2406,32 +2406,34 @@
 ator,%0A      
+  
 prefix,%0A
       suffix
@@ -2416,24 +2416,26 @@
     prefix,%0A
+  
       suffix
@@ -2434,32 +2434,34 @@
   suffix,%0A      
+  
 useEasing,%0A     
@@ -2451,24 +2451,26 @@
  useEasing,%0A
+  
       useGro
@@ -2493,17 +2493,25 @@
 or,%0A    
-%7D
+  %7D,%0A    
 );%0A  %7D;%0A
@@ -3238,20 +3238,25 @@
   %7D;%0A%0A  
-span
+container
 Ref = Re
@@ -3297,16 +3297,26 @@
  const %7B
+ children,
  classNa
@@ -3332,32 +3332,227 @@
  %7D = this.props;
+%0A    const %7B containerRef, pauseResume, reset, start, update %7D = this;%0A%0A    if (typeof children === 'function') %7B%0A      return children(%7B containerRef, pauseResume, reset, start, update %7D);%0A    %7D
 %0A%0A    return %3Csp
@@ -3585,17 +3585,17 @@
 ef=%7B
-this.span
+container
 Ref%7D

Support render prop usage