packages/victory-core/src/victory-util/transitions.js
function getTransitionPropsFactory(props, state, setState) {
  const nodesWillExit = state && state.nodesWillExit;
  const nodesWillEnter = state && state.nodesWillEnter;
  const nodesShouldEnter = state && state.nodesShouldEnter;
  const nodesShouldLoad = state && state.nodesShouldLoad;
  const nodesDoneLoad = state && state.nodesDoneLoad;
  const childrenTransitions = (state && state.childrenTransitions) || [];
  const transitionDurations = {
    enter: props.animate && props.animate.onEnter && props.animate.onEnter.duration,
    exit: props.animate && props.animate.onExit && props.animate.onExit.duration,
    load: props.animate && props.animate.onLoad && props.animate.onLoad.duration,
    move: props.animate && props.animate.duration
  };

  const onLoad = (child, data, animate) => {
    if (nodesShouldLoad) {
      return getChildOnLoad(animate, data, () => {
        setState({ nodesShouldLoad: false, nodesDoneLoad: true });
      });
    }

    return getChildBeforeLoad(animate, child, data, () => {
      setState({ nodesDoneLoad: true });
    });
  };

  // eslint-disable-next-line max-params
  const onExit = (nodes, child, data, animate) => {
    return getChildPropsOnExit(animate, child, data, nodes, () => {
      setState({ nodesWillExit: false });
    });
  };

  // eslint-disable-next-line max-params
  const onEnter = (nodes, child, data, animate) => {
    if (nodesShouldEnter) {
      return getChildPropsOnEnter(animate, data, nodes, () => {
        setState({ nodesWillEnter: false });
      });
    }

    return getChildPropsBeforeEnter(animate, child, data, nodes, () => {
      setState({ nodesShouldEnter: true });
    });
  };

  const getChildTransitionDuration = function(child, type) {
    const animate = child.props.animate;
    if (!child.type) {
      return {};
    }
    const defaultTransitions =
      child.props && child.props.polar
        ? child.type.defaultPolarTransitions || child.type.defaultTransitions
        : child.type.defaultTransitions;
    if (defaultTransitions) {
      const animationDuration = animate[type] && animate[type].duration;
      return animationDuration !== undefined
        ? animationDuration
        : defaultTransitions[type] && defaultTransitions[type].duration;
    } else {
      return {};
    }
  };

  // eslint-disable-next-line max-statements, complexity, max-len
  return function getTransitionProps(child, index) {
    const data = getChildData(child) || [];
    const animate = defaults({}, props.animate, child.props.animate);
    const defaultTransitions = child.props.polar
      ? child.type.defaultPolarTransitions || child.type.defaultTransitions
      : child.type.defaultTransitions;

    animate.onExit = defaults({}, animate.onExit, defaultTransitions && defaultTransitions.onExit);
    animate.onEnter = defaults(
      {},
      animate.onEnter,
      defaultTransitions && defaultTransitions.onEnter
    );
    animate.onLoad = defaults({}, animate.onLoad, defaultTransitions && defaultTransitions.onLoad);

    const childTransitions = childrenTransitions[index] || childrenTransitions[0];
    if (!nodesDoneLoad) {
      // should do onLoad animation
      const load =
        transitionDurations.load !== undefined
          ? transitionDurations.load
          : getChildTransitionDuration(child, "onLoad");
      const animation = { duration: load };
      return onLoad(child, data, assign({}, animate, animation));
    } else if (nodesWillExit) {
      const exitingNodes = childTransitions && childTransitions.exiting;
      const exit =
        transitionDurations.exit !== undefined
          ? transitionDurations.exit
          : getChildTransitionDuration(child, "onExit");
      // if nodesWillExit, but this child has no exiting nodes, set a delay instead of a duration
      const animation = exitingNodes ? { duration: exit } : { delay: exit };
      return onExit(exitingNodes, child, data, assign({}, animate, animation));
    } else if (nodesWillEnter) {
      const enteringNodes = childTransitions && childTransitions.entering;
      const enter =
        transitionDurations.enter !== undefined
          ? transitionDurations.enter
          : getChildTransitionDuration(child, "onEnter");
      const move =
        transitionDurations.move !== undefined
          ? transitionDurations.move
          : child.props.animate && child.props.animate.duration;
      const animation = {
        duration: nodesShouldEnter && enteringNodes ? enter : move
      };
      return onEnter(enteringNodes, child, data, assign({}, animate, animation));
    } else if (!state && animate && animate.onExit) {
      // This is the initial render, and nodes may enter when props change. Because
      // animation interpolation is determined by old- and next- props, data may need
      // to be augmented with certain properties.
      //
      // For example, it may be desired that exiting nodes go from `opacity: 1` to
      // `opacity: 0`. Without setting this on a per-datum basis, the interpolation
      // might go from `opacity: undefined` to `opacity: 0`, which would result in
      // interpolated `opacity: NaN` values.
      //
      return getInitialChildProps(animate, data);
    }
    return { animate, data };
  };
}
function getTransitionPropsFactory(props, state, setState) {
  const nodesWillExit = state && state.nodesWillExit;
  const nodesWillEnter = state && state.nodesWillEnter;
  const nodesShouldEnter = state && state.nodesShouldEnter;
  const nodesShouldLoad = state && state.nodesShouldLoad;
  const nodesDoneLoad = state && state.nodesDoneLoad;
  const childrenTransitions = (state && state.childrenTransitions) || [];
  const transitionDurations = {
    enter: props.animate && props.animate.onEnter && props.animate.onEnter.duration,
    exit: props.animate && props.animate.onExit && props.animate.onExit.duration,
    load: props.animate && props.animate.onLoad && props.animate.onLoad.duration,
    move: props.animate && props.animate.duration
  };

  const onLoad = (child, data, animate) => {
    if (nodesShouldLoad) {
      return getChildOnLoad(animate, data, () => {
        setState({ nodesShouldLoad: false, nodesDoneLoad: true });
      });
    }

    return getChildBeforeLoad(animate, child, data, () => {
      setState({ nodesDoneLoad: true });
    });
  };

  // eslint-disable-next-line max-params
  const onExit = (nodes, child, data, animate) => {
    return getChildPropsOnExit(animate, child, data, nodes, () => {
      setState({ nodesWillExit: false });
    });
  };

  // eslint-disable-next-line max-params
  const onEnter = (nodes, child, data, animate) => {
    if (nodesShouldEnter) {
      return getChildPropsOnEnter(animate, data, nodes, () => {
        setState({ nodesWillEnter: false });
      });
    }

    return getChildPropsBeforeEnter(animate, child, data, nodes, () => {
      setState({ nodesShouldEnter: true });
    });
  };

  const getChildTransitionDuration = function(child, type) {
    const animate = child.props.animate;
    if (!child.type) {
      return {};
    }
    const defaultTransitions =
      child.props && child.props.polar
        ? child.type.defaultPolarTransitions || child.type.defaultTransitions
        : child.type.defaultTransitions;
    if (defaultTransitions) {
      const animationDuration = animate[type] && animate[type].duration;
      return animationDuration !== undefined
        ? animationDuration
        : defaultTransitions[type] && defaultTransitions[type].duration;
    } else {
      return {};
    }
  };

  // eslint-disable-next-line max-statements, complexity, max-len
  return function getTransitionProps(child, index) {
    const data = getChildData(child) || [];
    const animate = defaults({}, props.animate, child.props.animate);
    const defaultTransitions = child.props.polar
      ? child.type.defaultPolarTransitions || child.type.defaultTransitions
      : child.type.defaultTransitions;

    animate.onExit = defaults({}, animate.onExit, defaultTransitions && defaultTransitions.onExit);
    animate.onEnter = defaults(
      {},
      animate.onEnter,
      defaultTransitions && defaultTransitions.onEnter
    );
    animate.onLoad = defaults({}, animate.onLoad, defaultTransitions && defaultTransitions.onLoad);

    const childTransitions = childrenTransitions[index] || childrenTransitions[0];
    if (!nodesDoneLoad) {
      // should do onLoad animation
      const load =
        transitionDurations.load !== undefined
          ? transitionDurations.load
          : getChildTransitionDuration(child, "onLoad");
      const animation = { duration: load };
      return onLoad(child, data, assign({}, animate, animation));
    } else if (nodesWillExit) {
      const exitingNodes = childTransitions && childTransitions.exiting;
      const exit =
        transitionDurations.exit !== undefined
          ? transitionDurations.exit
          : getChildTransitionDuration(child, "onExit");
      // if nodesWillExit, but this child has no exiting nodes, set a delay instead of a duration
      const animation = exitingNodes ? { duration: exit } : { delay: exit };
      return onExit(exitingNodes, child, data, assign({}, animate, animation));
    } else if (nodesWillEnter) {
      const enteringNodes = childTransitions && childTransitions.entering;
      const enter =
        transitionDurations.enter !== undefined
          ? transitionDurations.enter
          : getChildTransitionDuration(child, "onEnter");
      const move =
        transitionDurations.move !== undefined
          ? transitionDurations.move
          : child.props.animate && child.props.animate.duration;
      const animation = {
        duration: nodesShouldEnter && enteringNodes ? enter : move
      };
      return onEnter(enteringNodes, child, data, assign({}, animate, animation));
    } else if (!state && animate && animate.onExit) {
      // This is the initial render, and nodes may enter when props change. Because
      // animation interpolation is determined by old- and next- props, data may need
      // to be augmented with certain properties.
      //
      // For example, it may be desired that exiting nodes go from `opacity: 1` to
      // `opacity: 0`. Without setting this on a per-datum basis, the interpolation
      // might go from `opacity: undefined` to `opacity: 0`, which would result in
      // interpolated `opacity: NaN` values.
      //
      return getInitialChildProps(animate, data);
    }
    return { animate, data };
  };
}
function getTransitionPropsFactory ( props , state , setState ) { const nodesWillExit = state && state . nodesWillExit ; const nodesWillEnter = state && state . nodesWillEnter ; const nodesShouldEnter = state && state . nodesShouldEnter ; const nodesShouldLoad = state && state . nodesShouldLoad ; const nodesDoneLoad = state && state . nodesDoneLoad ; const childrenTransitions = ( state && state . childrenTransitions ) || [ ] ; const transitionDurations = { enter : props . animate && props . animate . onEnter && props . animate . onEnter . duration , exit : props . animate && props . animate . onExit && props . animate . onExit . duration , load : props . animate && props . animate . onLoad && props . animate . onLoad . duration , move : props . animate && props . animate . duration } ; const onLoad = ( child , data , animate ) => { if ( nodesShouldLoad ) { return getChildOnLoad ( animate , data , ( ) => { setState ( { nodesShouldLoad : false , nodesDoneLoad : true } ) ; } ) ; } return getChildBeforeLoad ( animate , child , data , ( ) => { setState ( { nodesDoneLoad : true } ) ; } ) ; } ; // eslint-disable-next-line max-params const onExit = ( nodes , child , data , animate ) => { return getChildPropsOnExit ( animate , child , data , nodes , ( ) => { setState ( { nodesWillExit : false } ) ; } ) ; } ; // eslint-disable-next-line max-params const onEnter = ( nodes , child , data , animate ) => { if ( nodesShouldEnter ) { return getChildPropsOnEnter ( animate , data , nodes , ( ) => { setState ( { nodesWillEnter : false } ) ; } ) ; } return getChildPropsBeforeEnter ( animate , child , data , nodes , ( ) => { setState ( { nodesShouldEnter : true } ) ; } ) ; } ; const getChildTransitionDuration = function ( child , type ) { const animate = child . props . animate ; if ( ! child . type ) { return { } ; } const defaultTransitions = child . props && child . props . polar ? child . type . defaultPolarTransitions || child . type . defaultTransitions : child . type . defaultTransitions ; if ( defaultTransitions ) { const animationDuration = animate [ type ] && animate [ type ] . duration ; return animationDuration !== undefined ? animationDuration : defaultTransitions [ type ] && defaultTransitions [ type ] . duration ; } else { return { } ; } } ; // eslint-disable-next-line max-statements, complexity, max-len return function getTransitionProps ( child , index ) { const data = getChildData ( child ) || [ ] ; const animate = defaults ( { } , props . animate , child . props . animate ) ; const defaultTransitions = child . props . polar ? child . type . defaultPolarTransitions || child . type . defaultTransitions : child . type . defaultTransitions ; animate . onExit = defaults ( { } , animate . onExit , defaultTransitions && defaultTransitions . onExit ) ; animate . onEnter = defaults ( { } , animate . onEnter , defaultTransitions && defaultTransitions . onEnter ) ; animate . onLoad = defaults ( { } , animate . onLoad , defaultTransitions && defaultTransitions . onLoad ) ; const childTransitions = childrenTransitions [ index ] || childrenTransitions [ 0 ] ; if ( ! nodesDoneLoad ) { // should do onLoad animation const load = transitionDurations . load !== undefined ? transitionDurations . load : getChildTransitionDuration ( child , "onLoad" ) ; const animation = { duration : load } ; return onLoad ( child , data , assign ( { } , animate , animation ) ) ; } else if ( nodesWillExit ) { const exitingNodes = childTransitions && childTransitions . exiting ; const exit = transitionDurations . exit !== undefined ? transitionDurations . exit : getChildTransitionDuration ( child , "onExit" ) ; // if nodesWillExit, but this child has no exiting nodes, set a delay instead of a duration const animation = exitingNodes ? { duration : exit } : { delay : exit } ; return onExit ( exitingNodes , child , data , assign ( { } , animate , animation ) ) ; } else if ( nodesWillEnter ) { const enteringNodes = childTransitions && childTransitions . entering ; const enter = transitionDurations . enter !== undefined ? transitionDurations . enter : getChildTransitionDuration ( child , "onEnter" ) ; const move = transitionDurations . move !== undefined ? transitionDurations . move : child . props . animate && child . props . animate . duration ; const animation = { duration : nodesShouldEnter && enteringNodes ? enter : move } ; return onEnter ( enteringNodes , child , data , assign ( { } , animate , animation ) ) ; } else if ( ! state && animate && animate . onExit ) { // This is the initial render, and nodes may enter when props change. Because // animation interpolation is determined by old- and next- props, data may need // to be augmented with certain properties. // // For example, it may be desired that exiting nodes go from `opacity: 1` to // `opacity: 0`. Without setting this on a per-datum basis, the interpolation // might go from `opacity: undefined` to `opacity: 0`, which would result in // interpolated `opacity: NaN` values. // return getInitialChildProps ( animate , data ) ; } return { animate , data } ; } ; }
getTransitionPropsFactory - putting the Java in JavaScript.  This will return a
function that returns prop transformations for a child, given that child's props
and its index in the parent's children array.

In particular, this will include an `animate` object that is set appropriately
so that each child will be synchoronized for each stage of a transition
animation.  It will also include a transformed `data` object, where each datum
is transformed by `animate.onExit` and `animate.onEnter` `before` and `after`
functions.

@param  {Object}  props       `this.props` for the parent component.
@param  {Object} state        `this.state` for the parent component.
@param  {Function} setState    Function that, when called, will `this.setState` on
the parent component with the provided object.

@return {Function}              Child-prop transformation function.
getTransitionPropsFactory - putting the Java in JavaScript . This will return a function that returns prop transformations for a child given that child s props and its index in the parent s children array .