Animation Primitives

The library exports these animation primitives:

animate($elt, props, opts, label)
This operates on the given jQuery-wrapped $elt, and always returns a promise (even if the $elt is undefined). props and opts are passed directly through to Velocity's animate function. label is an optional string that you can use to refer to this animation while it's running.
stop($elt)
This stops any currently running animations on the given element.
isAnimating($elt, label)
Tests whether an animation with the given label is currently running on this element.
timeSpent($elt, label)
Returns the number of milliseconds already spent running the labeled animation. Useful when adaptively interrupting in-progress animations.
timeRemaining($elt, label)
Returns the number of milliseconds remaining for the labeled animation. Useful when adaptively interrupting in-progress animations.
finish($elt, label)
Returns a promise that resolves when the running animation with the given label on the given element completes.

Demo

This shows a slow fade effect so you can experiment with interrupting the transition. Notice that it has two different behaviors depending on whether you interrupt the fade-out or fade-in.

import { isAnimating, finish, timeSpent, animate, stop } from '../index';

export default function fade(opts = {}) {
  let firstStep;
  let outOpts = opts;
  const fadingElement = findFadingElement(this);

  if (fadingElement) {
    // We still have some older version that is in the process of
    // fading out, so out first step is waiting for it to finish.
    firstStep = finish(fadingElement, 'fade-out');
  } else {
    if (isAnimating(this.oldElement, 'fade-in')) {
      // if the previous view is partially faded in, scale its
      // fade-out duration appropriately.
      outOpts = { duration: timeSpent(this.oldElement, 'fade-in') };
    }
    stop(this.oldElement);
    firstStep = animate(this.oldElement, { opacity: 0 }, outOpts, 'fade-out');
  }
  return firstStep.then(() => {
    return animate(
      this.newElement,
      { opacity: [opts.maxOpacity || 1, 0] },
      opts,
      'fade-in',
    );
  });
}

function findFadingElement(context) {
  for (let i = 0; i < context.older.length; i++) {
    const entry = context.older[i];
    if (isAnimating(entry.element, 'fade-out')) {
      return entry.element;
    }
  }
  if (isAnimating(context.oldElement, 'fade-out')) {
    return context.oldElement;
  }
}