Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
113 lines
4.4 KiB
Plaintext
113 lines
4.4 KiB
Plaintext
import { NativeAnimationControls, isGenerator, createGeneratorEasing, supportsLinearEasing } from 'motion-dom';
|
|
import { invariant, secondsToMilliseconds } from 'motion-utils';
|
|
import { startWaapiAnimation } from './index.mjs';
|
|
import { browserNumberValueTypes } from '../../../render/dom/value-types/number-browser.mjs';
|
|
import { getFinalKeyframe } from './utils/get-final-keyframe.mjs';
|
|
import { setCSSVar, setStyle } from './utils/style.mjs';
|
|
import { supportsPartialKeyframes } from './utils/supports-partial-keyframes.mjs';
|
|
import { supportsWaapi } from './utils/supports-waapi.mjs';
|
|
|
|
const state = new WeakMap();
|
|
function hydrateKeyframes(valueName, keyframes, read) {
|
|
for (let i = 0; i < keyframes.length; i++) {
|
|
if (keyframes[i] === null) {
|
|
keyframes[i] = i === 0 ? read() : keyframes[i - 1];
|
|
}
|
|
if (typeof keyframes[i] === "number" &&
|
|
browserNumberValueTypes[valueName]) {
|
|
keyframes[i] = browserNumberValueTypes[valueName].transform(keyframes[i]);
|
|
}
|
|
}
|
|
if (!supportsPartialKeyframes() && keyframes.length < 2) {
|
|
keyframes.unshift(read());
|
|
}
|
|
}
|
|
const defaultEasing = "easeOut";
|
|
function getElementAnimationState(element) {
|
|
const animationState = state.get(element) || new Map();
|
|
state.set(element, animationState);
|
|
return state.get(element);
|
|
}
|
|
class NativeAnimation extends NativeAnimationControls {
|
|
constructor(element, valueName, valueKeyframes, options) {
|
|
const isCSSVar = valueName.startsWith("--");
|
|
invariant(typeof options.type !== "string", `animateMini doesn't support "type" as a string. Did you mean to import { spring } from "framer-motion"?`);
|
|
const existingAnimation = getElementAnimationState(element).get(valueName);
|
|
existingAnimation && existingAnimation.stop();
|
|
const readInitialKeyframe = () => {
|
|
return valueName.startsWith("--")
|
|
? element.style.getPropertyValue(valueName)
|
|
: window.getComputedStyle(element)[valueName];
|
|
};
|
|
if (!Array.isArray(valueKeyframes)) {
|
|
valueKeyframes = [valueKeyframes];
|
|
}
|
|
hydrateKeyframes(valueName, valueKeyframes, readInitialKeyframe);
|
|
// TODO: Replace this with toString()?
|
|
if (isGenerator(options.type)) {
|
|
const generatorOptions = createGeneratorEasing(options, 100, options.type);
|
|
options.ease = supportsLinearEasing()
|
|
? generatorOptions.ease
|
|
: defaultEasing;
|
|
options.duration = secondsToMilliseconds(generatorOptions.duration);
|
|
options.type = "keyframes";
|
|
}
|
|
else {
|
|
options.ease = options.ease || defaultEasing;
|
|
}
|
|
const onFinish = () => {
|
|
this.setValue(element, valueName, getFinalKeyframe(valueKeyframes, options));
|
|
this.cancel();
|
|
this.resolveFinishedPromise();
|
|
};
|
|
const init = () => {
|
|
this.setValue = isCSSVar ? setCSSVar : setStyle;
|
|
this.options = options;
|
|
this.updateFinishedPromise();
|
|
this.removeAnimation = () => {
|
|
const elementState = state.get(element);
|
|
elementState && elementState.delete(valueName);
|
|
};
|
|
};
|
|
if (!supportsWaapi()) {
|
|
super();
|
|
init();
|
|
onFinish();
|
|
}
|
|
else {
|
|
super(startWaapiAnimation(element, valueName, valueKeyframes, options));
|
|
init();
|
|
if (options.autoplay === false) {
|
|
this.animation.pause();
|
|
}
|
|
this.animation.onfinish = onFinish;
|
|
getElementAnimationState(element).set(valueName, this);
|
|
}
|
|
}
|
|
/**
|
|
* Allows the returned animation to be awaited or promise-chained. Currently
|
|
* resolves when the animation finishes at all but in a future update could/should
|
|
* reject if its cancels.
|
|
*/
|
|
then(resolve, reject) {
|
|
return this.currentFinishedPromise.then(resolve, reject);
|
|
}
|
|
updateFinishedPromise() {
|
|
this.currentFinishedPromise = new Promise((resolve) => {
|
|
this.resolveFinishedPromise = resolve;
|
|
});
|
|
}
|
|
play() {
|
|
if (this.state === "finished") {
|
|
this.updateFinishedPromise();
|
|
}
|
|
super.play();
|
|
}
|
|
cancel() {
|
|
this.removeAnimation();
|
|
super.cancel();
|
|
}
|
|
}
|
|
|
|
export { NativeAnimation };
|