react-native-reanimated
Version:
More powerful alternative to Animated library for React Native.
130 lines (126 loc) • 4.93 kB
JavaScript
'use strict';
import CSSKeyframesRuleImpl from "../models/CSSKeyframesRule.web.js";
import { configureWebCSSAnimations, insertCSSAnimation, maybeAddSuffixes, parseTimingFunction, processKeyframeDefinitions, removeCSSAnimation } from "../platform/web/index.js";
import { convertPropertiesToArrays, kebabizeCamelCase } from "../utils/index.js";
export const isCSSKeyframesRuleImpl = keyframes => typeof keyframes === 'object' && 'processedKeyframes' in keyframes;
export default class CSSAnimationsManager {
// Keys are processed keyframes
attachedAnimations = {};
constructor(element) {
configureWebCSSAnimations();
this.element = element;
}
update(animationProperties) {
if (!animationProperties) {
this.detach();
return;
}
const {
animationName: definitions,
...animationSettings
} = convertPropertiesToArrays(animationProperties);
if (definitions.length === 0) {
this.detach();
return;
}
const processedAnimations = definitions.map(definition => {
// If the CSSKeyframesRule instance was provided, we can just use it
if (isCSSKeyframesRuleImpl(definition)) {
return {
keyframesRule: definition,
removable: false
};
}
// If keyframes was defined as an object, the additional processing is needed
const keyframes = definition;
const processedKeyframes = processKeyframeDefinitions(keyframes);
// If the animation with the same keyframes was already attached, we can reuse it
if (this.attachedAnimations[processedKeyframes]) {
return {
keyframesRule: this.attachedAnimations[processedKeyframes].keyframesRule,
removable: true
};
}
// Otherwise, we need to create a new CSSKeyframesRule object
return {
keyframesRule: new CSSKeyframesRuleImpl(keyframes, processedKeyframes),
removable: true
};
});
const animationNames = processedAnimations.map(({
keyframesRule: {
name
}
}) => name);
this.updateAttachedAnimations(processedAnimations);
this.setElementAnimations(animationNames, animationSettings);
}
unmountCleanup() {
// noop
}
detach() {
const attachedAnimations = Object.values(this.attachedAnimations);
if (attachedAnimations.length === 0) {
return;
}
this.element.style.animationDuration = '';
this.element.style.animationDelay = '';
this.element.style.animationDirection = '';
this.element.style.animationFillMode = '';
this.element.style.animationPlayState = '';
this.element.style.animationTimingFunction = '';
attachedAnimations.forEach(({
keyframesRule: {
name,
processedKeyframes
},
removable
}) => {
if (removable && processedKeyframes) {
removeCSSAnimation(name);
}
});
this.attachedAnimations = {};
}
updateAttachedAnimations(processedAnimations) {
const newAttachedAnimations = {};
processedAnimations.forEach(processedAnimation => {
const rule = processedAnimation.keyframesRule;
if (rule.processedKeyframes) {
// We always call insert as it will insert animation only if it doesn't exist
insertCSSAnimation(rule.name, rule.processedKeyframes);
}
newAttachedAnimations[rule.processedKeyframes] = processedAnimation;
});
Object.values(this.attachedAnimations).forEach(({
keyframesRule: rule,
removable
}) => {
if (removable && rule.processedKeyframes && !newAttachedAnimations[rule.processedKeyframes]) {
removeCSSAnimation(rule.name);
}
});
this.attachedAnimations = newAttachedAnimations;
}
setElementAnimations(animationNames, animationSettings) {
this.element.style.animationName = animationNames.join(',');
this.element.style.animationDuration = maybeAddSuffixes(animationSettings, 'animationDuration', 'ms').join(',');
this.element.style.animationDelay = maybeAddSuffixes(animationSettings, 'animationDelay', 'ms').join(',');
if (animationSettings.animationIterationCount) {
this.element.style.animationIterationCount = animationSettings.animationIterationCount.join(',');
}
if (animationSettings.animationDirection) {
this.element.style.animationDirection = animationSettings.animationDirection.map(kebabizeCamelCase).join(',');
}
if (animationSettings.animationFillMode) {
this.element.style.animationFillMode = animationSettings.animationFillMode.join(',');
}
if (animationSettings.animationPlayState) {
this.element.style.animationPlayState = animationSettings.animationPlayState.join(',');
}
if (animationSettings.animationTimingFunction) {
this.element.style.animationTimingFunction = parseTimingFunction(animationSettings.animationTimingFunction);
}
}
}
//# sourceMappingURL=CSSAnimationsManager.web.js.map