// @flow
import React, { type Element } from 'react';
import type { AnimationType, AnimationStateType } from './animate';
import calculateTotalDuration from './utils/calculateTotalDuration';

type Sequence = AnimationType & {
  sequenceId?: string | number,
  sequenceIndex?: number,
};

type Sequences = Array<Sequence>;

type Props = {
  play: boolean,
  sequences?: Sequences,
  reverseSequences?: Sequences,
  children: Element<*>,
};

type State = {
  animationStates?: AnimationStateType,
};

// $FlowIgnoreLine
export const AnimateContext = React.createContext({
  animationStates: {},
  register: () => {},
});

export default class AnimateGroup extends React.PureComponent<Props, State> {
  static displayName = 'AnimateGroup';

  static defaultProps = {
    sequences: [],
    reverseSequences: [],
  };

  state = {
    animationStates: {},
  };

  timers: { [string | number]: TimeoutID } = {};

  animations: { [string | number]: AnimationType } = {};

  componentDidMount() {
    this.props.play && this.calculateSequences();
  }

  componentDidUpdate(prevProps: Props) {
    if (this.props.play !== prevProps.play) this.calculateSequences();
  }

  componentWillUnmount() {
    Object.values(this.timers).forEach((timer: any) => clearTimeout(timer));
  }

  setupAnimationTimers = ({
    totalDuration,
    id,
    restAttributes,
    play,
  }: {
    totalDuration: number,
    id: number | string,
    restAttributes: AnimationType,
    play: boolean,
  }) => {
    const duration = totalDuration - (restAttributes.overlaySeconds || 0) * 1000;

    this.timers[id] = setTimeout(() => {
      this.setState(previousState => {
        const stateCopy = { ...previousState.animationStates };

        if (!stateCopy[id]) stateCopy[id] = {};
        Object.entries(restAttributes).forEach(([key, value]) => {
          stateCopy[id][key] = value;
        });
        stateCopy[id].play = play;

        return {
          animationStates: stateCopy,
        };
      });
    }, duration < 0 ? 0 : duration);
  };

  calculateSequences = () => {
    const { sequences, reverseSequences, play } = this.props;
    const sequencesToAnimate: any =
      Array.isArray(sequences) && sequences.length ? sequences : Object.values(this.animations);
    const reverseSequencesToAnimate: any =
      Array.isArray(reverseSequences) && reverseSequences.length ? reverseSequences : [...sequencesToAnimate].reverse();

    return (play ? sequencesToAnimate : reverseSequencesToAnimate).reduce((previous, current, currentIndex) => {
      const { sequenceId, sequenceIndex, ...restAttributes } = current;
      const id = sequenceId === undefined && sequenceIndex === undefined ? currentIndex : sequenceId || sequenceIndex;
      const totalDuration =
        previous +
        calculateTotalDuration({
          ...this.animations[id],
          play,
          restAttributes,
        });

      this.setupAnimationTimers({
        id,
        totalDuration: currentIndex === 0 ? 0 : previous,
        restAttributes,
        play,
      });
      return totalDuration;
    }, 0);
  };

  register = (props: Sequence) => {
    const { sequenceIndex, sequenceId } = props;
    const id = sequenceId || sequenceIndex;
    if (id === undefined || (sequenceIndex && sequenceIndex < 0) || (sequenceId && sequenceId === '')) return;

    this.animations[id] = {
      ...props,
    };
  };

  render() {
    return (
      <AnimateContext.Provider value={{ animationStates: this.state.animationStates, register: this.register }}>
        {this.props.children}
      </AnimateContext.Provider>
    );
  }
}

@@ -1122,16 +1122,50 @@
 ps.play)
+ %7B%0A      this.clearTimers();%0A     
  this.ca
@@ -1176,32 +1176,38 @@
 ateSequences();%0A
+    %7D%0A
   %7D%0A%0A  component
@@ -1225,16 +1225,63 @@
 () %7B%0A   
+ this.clearTimers();%0A  %7D%0A%0A  clearTimers = () =%3E
  Object.
@@ -1345,20 +1345,16 @@
 timer));
-%0A  %7D
 %0A%0A  setu

fix an issue with animate group with animation sequence cancelling