framer-motion
Version:
A simple and powerful React animation library
80 lines (77 loc) • 2.95 kB
JavaScript
import { __spreadArray, __read } from 'tslib';
import { invariant } from 'hey-listen';
import { stopAnimation, animateVisualElement } from '../render/utils/animation.mjs';
import { setValues } from '../render/utils/setters.mjs';
/**
* @public
*/
function animationControls() {
/**
* Track whether the host component has mounted.
*/
var hasMounted = false;
/**
* Pending animations that are started before a component is mounted.
* TODO: Remove this as animations should only run in effects
*/
var pendingAnimations = [];
/**
* A collection of linked component animation controls.
*/
var subscribers = new Set();
var controls = {
subscribe: function (visualElement) {
subscribers.add(visualElement);
return function () { return void subscribers.delete(visualElement); };
},
start: function (definition, transitionOverride) {
/**
* TODO: We only perform this hasMounted check because in Framer we used to
* encourage the ability to start an animation within the render phase. This
* isn't behaviour concurrent-safe so when we make Framer concurrent-safe
* we can ditch this.
*/
if (hasMounted) {
var animations_1 = [];
subscribers.forEach(function (visualElement) {
animations_1.push(animateVisualElement(visualElement, definition, {
transitionOverride: transitionOverride,
}));
});
return Promise.all(animations_1);
}
else {
return new Promise(function (resolve) {
pendingAnimations.push({
animation: [definition, transitionOverride],
resolve: resolve,
});
});
}
},
set: function (definition) {
invariant(hasMounted, "controls.set() should only be called after a component has mounted. Consider calling within a useEffect hook.");
return subscribers.forEach(function (visualElement) {
setValues(visualElement, definition);
});
},
stop: function () {
subscribers.forEach(function (visualElement) {
stopAnimation(visualElement);
});
},
mount: function () {
hasMounted = true;
pendingAnimations.forEach(function (_a) {
var animation = _a.animation, resolve = _a.resolve;
controls.start.apply(controls, __spreadArray([], __read(animation), false)).then(resolve);
});
return function () {
hasMounted = false;
controls.stop();
};
},
};
return controls;
}
export { animationControls };