motion
Version:
The Motion library for the web
153 lines (148 loc) • 6.54 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
var data = require('./data.cjs.js');
var cssVar = require('./utils/css-var.cjs.js');
var noop = require('../../utils/noop.cjs.js');
var time = require('./utils/time.cjs.js');
var transforms = require('./utils/transforms.cjs.js');
var stopAnimation = require('./utils/stop-animation.cjs.js');
var easing = require('./utils/easing.cjs.js');
var featureDetection = require('./utils/feature-detection.cjs.js');
var apply = require('./utils/apply.cjs.js');
var animateNumber = require('../js/animate-number.cjs.js');
var keyframes = require('./utils/keyframes.cjs.js');
var style = require('./style.cjs.js');
var defaults = require('./utils/defaults.cjs.js');
function animateStyle(element, name, keyframesDefinition, options = {}) {
let { duration = defaults.defaults.duration, delay = defaults.defaults.delay, endDelay = defaults.defaults.endDelay, repeat = defaults.defaults.repeat, easing: easing$1 = defaults.defaults.easing, direction, offset, allowWebkitAcceleration = false, } = options;
const data$1 = data.getAnimationData(element);
let canAnimateNatively = featureDetection.supports.waapi();
let render = noop.noop;
const valueIsTransform = transforms.isTransform(name);
/**
* If this is an individual transform, we need to map its
* key to a CSS variable and update the element's transform style
*/
if (valueIsTransform) {
if (transforms.transformAlias[name])
name = transforms.transformAlias[name];
transforms.addTransformToElement(element, name);
name = transforms.asTransformCssVar(name);
}
/**
* Get definition of value, this will be used to convert numerical
* keyframes into the default value type.
*/
const definition = transforms.transformPropertyDefinitions.get(name);
/**
* Replace null values with the previous keyframe value, or read
* it from the DOM if it's the first keyframe.
*
* TODO: This needs to come after the valueIsTransform
* check so it can correctly read the underlying value.
* Should make a test for this.
*/
let keyframes$1 = keyframes.hydrateKeyframes(keyframes.keyframesList(keyframesDefinition), element, name);
stopCurrentAnimation(data$1, name);
/**
* If this is a CSS variable we need to register it with the browser
* before it can be animated natively. We also set it with setProperty
* rather than directly onto the element.style object.
*/
if (cssVar.isCssVar(name)) {
render = apply.createCssVariableRenderer(element, name);
if (featureDetection.supports.cssRegisterProperty()) {
cssVar.registerCssVariable(name);
}
else {
canAnimateNatively = false;
}
}
else {
render = apply.createStyleRenderer(element, name);
}
let animation;
/**
* If we can animate this value with WAAPI, do so. Currently this only
* feature detects CSS.registerProperty but could check WAAPI too.
*/
if (canAnimateNatively) {
/**
* Convert numbers to default value types. Currently this only supports
* transforms but it could also support other value types.
*/
if (definition) {
keyframes$1 = keyframes$1.map((value) => typeof value === "number" ? definition.toDefaultUnit(value) : value);
}
if (!featureDetection.supports.partialKeyframes() && keyframes$1.length === 1) {
keyframes$1.unshift(style.style.get(element, name));
}
const animationOptions = {
delay: time.ms(delay),
duration: time.ms(duration),
endDelay: time.ms(endDelay),
easing: !easing.isEasingList(easing$1) ? easing.convertEasing(easing$1) : undefined,
direction,
iterations: repeat + 1,
};
animation = element.animate({
[name]: keyframes$1,
offset,
easing: easing.isEasingList(easing$1) ? easing$1.map(easing.convertEasing) : undefined,
}, animationOptions);
/**
* Polyfill finished Promise in browsers that don't support it
*/
if (!animation.finished) {
animation.finished = new Promise((resolve, reject) => {
animation.onfinish = resolve;
animation.oncancel = reject;
});
}
const target = keyframes$1[keyframes$1.length - 1];
animation.finished.then(() => render(target)).catch(noop.noop);
/**
* This forces Webkit to run animations on the main thread by exploiting
* this condition:
* https://trac.webkit.org/browser/webkit/trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp?rev=281238#L1099
*
* This fixes Webkit's timing bugs, like accelerated animations falling
* out of sync with main thread animations and massive delays in starting
* accelerated animations in WKWebView.
*/
if (!allowWebkitAcceleration)
animation.playbackRate = 1.000001;
}
else if (valueIsTransform && keyframes$1.every(isNumber)) {
if (keyframes$1.length === 1) {
keyframes$1.unshift(style.style.get(element, name) || (definition === null || definition === void 0 ? void 0 : definition.initialValue) || 0);
}
/**
* Transform styles are currently only accepted as numbers of
* their default value type, so here we loop through and map
* them to numbers.
*/
keyframes$1 = keyframes$1.map((value) => typeof value === "string" ? parseFloat(value) : value);
if (definition) {
const applyStyle = render;
render = (v) => applyStyle(definition.toDefaultUnit(v));
}
animation = animateNumber.animateNumber(render, keyframes$1, options);
}
else {
const target = keyframes$1[keyframes$1.length - 1];
render(definition && typeof target === "number"
? definition.toDefaultUnit(target)
: target);
}
data$1.activeAnimations[name] = animation;
return animation;
}
function stopCurrentAnimation(data, name) {
if (data.activeAnimations[name]) {
stopAnimation.stopAnimation(data.activeAnimations[name]);
data.activeAnimations[name] = undefined;
}
}
const isNumber = (value) => typeof value === "number";
exports.animateStyle = animateStyle;