lottie-react-component
Version:
Render your lottie animations in React, with full typescript support
103 lines (102 loc) • 3.78 kB
JavaScript
import React, { useEffect, useRef, useState } from "react";
import lottie from "lottie-web";
import lottieApi from "lottie-api";
const getSize = (initial) => {
if (typeof initial === "number") {
return `${initial}px`;
}
return initial || "100%";
};
export const Lottie = ({ eventListeners, isStopped = false, isPaused = false, speed = 1, ariaRole = "button", ariaLabel = "animation", title = "", tabIndex = 0, width, height, style, loop = true, autoplay = true, animationControl, direction, assetsPath, animationData, rendererSettings, renderer, }) => {
const ref = useRef(null);
const [animation, setAnimation] = useState(null);
const [animationApi, setAnimationApi] = useState(null);
const lottieStyles = {
width: getSize(width),
height: getSize(height),
overflow: "hidden",
margin: "0 auto",
outline: "none",
...style,
};
useEffect(() => {
if (animation) {
eventListeners?.forEach((eventListener) => {
animation.addEventListener(eventListener.eventName, eventListener.callback);
});
}
return () => {
if (animation) {
eventListeners?.forEach((eventListener) => {
animation.removeEventListener(eventListener.eventName, eventListener.callback);
});
}
};
}, [animation, eventListeners]);
useEffect(() => {
if (animation && loop !== undefined) {
animation.loop = loop;
}
}, [animation, loop]);
useEffect(() => {
if (ref.current) {
const aggregatedOptions = {
container: ref.current,
renderer,
loop: loop !== false,
autoplay: autoplay !== false,
animationData,
rendererSettings,
assetsPath,
};
const newAnimation = lottie.loadAnimation(aggregatedOptions);
newAnimation.setSpeed(speed);
newAnimation.setDirection(direction || 1);
if (isStopped) {
newAnimation.stop();
}
else {
newAnimation.play();
}
const newApi = lottieApi.createAnimationApi(newAnimation);
setAnimation(newAnimation);
setAnimationApi(newApi);
return () => {
newAnimation.destroy();
};
}
// Yes we're lying to the dependency array - oh well
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [animationData]);
useEffect(() => {
if (isStopped) {
animation?.stop();
}
else {
animation?.play();
}
}, [animation, isStopped]);
useEffect(() => {
if (animationControl && animationApi) {
const properties = Object.keys(animationControl);
properties.forEach((property) => {
const propertyPath = animationApi.getKeyPath(property);
const value = animationControl[property];
animationApi.addValueCallback(propertyPath, () => value);
});
}
}, [animationApi, animationControl]);
useEffect(() => {
animation?.setDirection(direction || 1);
}, [animation, direction]);
useEffect(() => {
animation?.setSpeed(speed);
}, [animation, speed]);
useEffect(() => {
if (Boolean(isPaused) !== Boolean(animation?.isPaused)) {
animation?.pause();
}
}, [animation, isPaused]);
return (React.createElement("div", { ref: ref, style: lottieStyles, title: title, role: ariaRole, "aria-label": ariaLabel, tabIndex: tabIndex }));
};
export default Lottie;