UNPKG

lottie-react-component

Version:

Render your lottie animations in React, with full typescript support

103 lines (102 loc) 3.78 kB
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;