UNPKG

react-lottie-hook

Version:
472 lines (460 loc) 19.1 kB
import { __assign, __spreadArray } from 'tslib'; import React, { useCallback, useMemo, useState, useEffect } from 'react'; import lottie from 'lottie-web'; import ReactDOM from 'react-dom'; var Lottie = function (props) { if (!props.lottieRef) { throw new Error("Lottie component requires a valid ref but got: " + props.lottieRef); } var getSize = useCallback(function (initial) { if (initial === void 0) { initial = 200; } return (typeof initial === "number" ? initial + "px" : initial); }, []); var styles = useMemo(function () { return (__assign({ width: getSize(props.width), height: getSize(props.height), overflow: "hidden", margin: "0 auto", outline: "none" }, props.style)); }, [props.style, props.width, props.height, getSize]); return (React.createElement("div", { ref: function (r) { props.lottieRef.current = r; }, className: props.className, style: styles, onKeyDown: props.onKeyDown, onClick: props.onClick, title: props.title, role: props.ariaRole, "aria-label": props.ariaLabel, "tab-index": "0" })); }; var AnimType; (function (AnimType) { AnimType[AnimType["svg"] = 0] = "svg"; AnimType[AnimType["canvas"] = 1] = "canvas"; AnimType[AnimType["html"] = 2] = "html"; })(AnimType || (AnimType = {})); var Renderer; (function (Renderer) { Renderer["html"] = "html"; Renderer["svg"] = "svg"; Renderer["canvas"] = "canvas"; })(Renderer || (Renderer = {})); var array = { isPopulated: function (item) { return Array.isArray(item) && item.length > 0; } }; var object = { isPopulated: function (obj) { return !!obj && typeof obj === "object" && Object.keys(obj).length > 0; } }; var string = { isEmpty: function (str) { return typeof str === "string" && str.length === 0; }, isPopulated: function (str) { return typeof str === "string" && str.length > 0; } }; var number = { is: function (number) { return typeof number === "number"; } }; var boolean = { is: function (boolean) { return typeof boolean === "boolean" || (typeof boolean === "number" && Boolean(boolean)); } }; var removeProps = function (obj) { var props = []; for (var _i = 1; _i < arguments.length; _i++) { props[_i - 1] = arguments[_i]; } if (!object.isPopulated(obj)) return; var list = __spreadArray([], props, true); return Object.entries(obj).reduce(function (acc, _a) { var _b; var key = _a[0], value = _a[1]; if (list.includes(key)) return acc; return __assign(__assign({}, acc), (_b = {}, _b[key] = value, _b)); }, {}); }; var useLottie = function (_a) { var _b = _a.renderer, renderer = _b === void 0 ? Renderer.svg : _b, _c = _a.loop, loop = _c === void 0 ? true : _c, _d = _a.autoplay, autoplay = _d === void 0 ? true : _d, _e = _a.rendererSettings, rendererSettings = _e === void 0 ? {} : _e, _f = _a.segments, segments = _f === void 0 ? [] : _f, _g = _a.animationData, animationData = _g === void 0 ? {} : _g, _h = _a.eventListeners, eventListeners = _h === void 0 ? {} : _h; var _j = useState(undefined), animation = _j[0], setAnimation = _j[1]; var lottieRef = React.useRef(null); var _k = useState(animationData), internalAnimationData = _k[0], setInternalAnimationData = _k[1]; var _l = useState({ animType: undefined, animationID: undefined, assets: [], assetsPath: undefined, autoloadSegments: false, autoplay: false, currentFrame: 0, currentRawFrame: 0, firstFrame: 0, frameModifier: 0, frameMult: 0, frameRate: 0, initialSegment: undefined, isPaused: false, isLoaded: false, isSubframeEnabled: false, loop: undefined, name: undefined, path: undefined, playCount: 0, playDirection: 1, playSpeed: 0, segmentPos: 0, segments: [], timeCompleted: 0, totalFrames: 0, isStopped: false, animationData: animationData }), state = _l[0], dispatch = _l[1]; var hasOwnProperty = useCallback(function (anim, prop) { return object.isPopulated(anim) && !!anim[prop]; }, []); var registerEvents = useCallback(function (anim, eventListeners) { if (!object.isPopulated(eventListeners)) return; Object.entries(eventListeners).forEach(function (_a) { var eventName = _a[0], callback = _a[1]; if (hasOwnProperty(anim, "addEventListener") && callback !== undefined) { anim === null || anim === void 0 ? void 0 : anim.addEventListener(eventName, callback); } }); }, [hasOwnProperty]); var deRegisterEvents = useCallback(function (anim, eventListeners) { if (!object.isPopulated(eventListeners)) return; Object.entries(eventListeners).forEach(function (_a) { var eventName = _a[0], callback = _a[1]; if (hasOwnProperty(anim, "removeEventListener")) { anim === null || anim === void 0 ? void 0 : anim.removeEventListener(eventName, callback); } }); }, [hasOwnProperty]); var animationConfig = useCallback(function (container) { return ({ container: container, renderer: renderer, loop: loop, autoplay: autoplay, rendererSettings: rendererSettings, animationData: internalAnimationData }); }, [renderer, loop, autoplay, rendererSettings, internalAnimationData]); var update = function (update) { dispatch(function (state) { return (__assign(__assign({}, state), update)); }); }; var play = useCallback(function () { if (hasOwnProperty(animation, "play")) { animation === null || animation === void 0 ? void 0 : animation.play(); update({ isPaused: false, isStopped: false }); } }, [animation, hasOwnProperty]); var playSegments = useCallback(function (newSegments, forceFlag) { if (forceFlag === void 0) { forceFlag = true; } if (hasOwnProperty(animation, "playSegments")) { animation === null || animation === void 0 ? void 0 : animation.playSegments(newSegments || segments, forceFlag); } }, [animation, segments, hasOwnProperty]); var stop = useCallback(function () { if (hasOwnProperty(animation, "stop")) { animation === null || animation === void 0 ? void 0 : animation.stop(); update({ isStopped: true, isPaused: true }); } }, [animation, hasOwnProperty]); var pause = useCallback(function () { if (hasOwnProperty(animation, "pause")) { animation === null || animation === void 0 ? void 0 : animation.pause(); update({ isPaused: true }); } }, [animation, hasOwnProperty]); var destroy = useCallback(function () { if (hasOwnProperty(animation, "destroy")) { animation === null || animation === void 0 ? void 0 : animation.destroy(); } }, [animation, hasOwnProperty]); var setDirection = useCallback(function (direction) { if (direction === void 0) { direction = 1; } if (hasOwnProperty(animation, "setDirection")) { animation === null || animation === void 0 ? void 0 : animation.setDirection(direction); update({ playDirection: direction }); } }, [animation, hasOwnProperty]); var selectAnimation = useCallback(function (newAnimation) { if (object.isPopulated(animation) && object.isPopulated(newAnimation)) { update({ isStopped: false, isPaused: false, animationData: newAnimation }); } }, [animation]); var setSpeed = useCallback(function (speed) { if (hasOwnProperty(animation, "setSpeed")) { animation === null || animation === void 0 ? void 0 : animation.setSpeed(speed); update({ playSpeed: speed }); } }, [animation, hasOwnProperty]); var resize = useCallback(function () { if (hasOwnProperty(animation, "resize")) { animation === null || animation === void 0 ? void 0 : animation.resize(); } }, [animation, hasOwnProperty]); var goToAndPlay = useCallback(function (value, isFrame) { if (hasOwnProperty(animation, "goToAndPlay")) { if (state.totalFrames && value > state.totalFrames) { console.error("[goToAndPlay]: provided value " + value + " exceeds animation total frames which is " + state.totalFrames); } animation === null || animation === void 0 ? void 0 : animation.goToAndPlay(value, isFrame); } }, [animation, hasOwnProperty, state.totalFrames]); var goToAndStop = useCallback(function (value, isFrame) { if (hasOwnProperty(animation, "goToAndStop")) { if (state.totalFrames && value > state.totalFrames) { console.error("[goToAndStop]: provided value " + value + " exceeds animation total frames which is " + state.totalFrames); } animation === null || animation === void 0 ? void 0 : animation.goToAndStop(value, isFrame); } }, [animation, hasOwnProperty, state.totalFrames]); var setSubframe = useCallback(function (useSubFrames) { if (hasOwnProperty(animation, "setSubframe")) { animation === null || animation === void 0 ? void 0 : animation.setSubframe(useSubFrames); } }, [animation, hasOwnProperty]); var getDuration = useCallback(function (inFrames) { if (hasOwnProperty(animation, "getDuration")) { return animation === null || animation === void 0 ? void 0 : animation.getDuration(inFrames); } return 0; }, [animation, hasOwnProperty]); var controls = useMemo(function () { return ({ play: play, stop: stop, pause: pause, resize: resize, destroy: destroy, setSpeed: setSpeed, getDuration: getDuration, setSubframe: setSubframe, goToAndPlay: goToAndPlay, goToAndStop: goToAndStop, playSegments: playSegments, setDirection: setDirection, selectAnimation: selectAnimation }); }, [ play, stop, pause, resize, destroy, setSpeed, getDuration, setSubframe, goToAndPlay, goToAndStop, setDirection, playSegments, selectAnimation, ]); var filterLottieState = useCallback(function (anim) { var props = []; if (!string.isPopulated(anim.name)) props.push("name"); if (!string.isPopulated(anim.path)) props.push("path"); if (!string.isPopulated(anim.animType)) props.push("animType"); if (!string.isPopulated(anim.assetsPath)) props.push("assetsPath"); if (!string.isPopulated(anim.animationID)) props.push("animationID"); if (!number.is(anim.frameMult)) props.push("frameMult"); if (!number.is(anim.frameRate)) props.push("frameRate"); if (!number.is(anim.playCount)) props.push("playCount"); if (!number.is(anim.playSpeed)) props.push("playSpeed"); if (!number.is(anim.firstFrame)) props.push("firstFrame"); if (!number.is(anim.segmentPos)) props.push("segmentPos"); if (!number.is(anim.totalFrames)) props.push("totalFrames"); if (!number.is(anim.currentFrame)) props.push("currentFrame"); if (!number.is(anim.timeCompleted)) props.push("timeCompleted"); if (!number.is(anim.frameModifier)) props.push("frameModifier"); if (!number.is(anim.playDirection)) props.push("playDirection"); if (!number.is(anim.initialSegment)) props.push("initialSegment"); if (!number.is(anim.currentRawFrame)) props.push("currentRawFrame"); if (!boolean.is(anim.autoloadSegments)) props.push("autoloadSegments"); if (!boolean.is(anim.isSubframeEnabled)) props.push("isSubframeEnabled"); if (!boolean.is(anim.isLoaded)) props.push("isLoaded"); if (!boolean.is(anim.isPaused)) props.push("isPaused"); if (!boolean.is(anim.autoplay)) props.push("autoplay"); if (!boolean.is(anim.loop)) props.push("loop"); if (!array.isPopulated(anim.segments)) props.push("segments"); if (!array.isPopulated(anim.assets)) props.push("assets"); var updates = removeProps.apply(void 0, __spreadArray([anim], props, false)); updates.isStopped = state.isStopped; return updates; }, [state.isStopped]); useEffect(function () { var anim = lottie.loadAnimation(animationConfig(lottieRef.current)); registerEvents(anim, eventListeners); var updates = filterLottieState(anim); update(updates); setAnimation(anim); return function () { if (hasOwnProperty(animation, "destroy")) animation === null || animation === void 0 ? void 0 : animation.destroy(); deRegisterEvents(animation, eventListeners); controls.destroy(); setAnimation(undefined); update({ animationData: {} }); }; }, []); useEffect(function () { if (internalAnimationData !== state.animationData) { deRegisterEvents(animation, eventListeners); controls.destroy(); var newOptions = __assign(__assign({}, animationConfig(lottieRef.current)), { renderer: renderer, loop: loop, autoplay: autoplay, rendererSettings: rendererSettings, animationData: state.animationData }); var anim = lottie.loadAnimation(newOptions); registerEvents(anim, eventListeners); setInternalAnimationData(state.animationData); setAnimation(anim); var updates = filterLottieState(anim); update(updates); } }, [ animation, internalAnimationData, state.animationData, eventListeners, rendererSettings, deRegisterEvents, animationConfig, registerEvents, filterLottieState, autoplay, renderer, controls, state, loop, ]); var lottieState = filterLottieState(state); return [lottieRef, lottieState, controls]; }; function ownerDocument(node) { return (node && node.ownerDocument) || document; } var setRef = function (ref, value) { if (typeof ref === "function") { ref(value); } else if (ref) { ref.current = value; } }; var useForkRef = function (refA, refB) { return React.useMemo(function () { if (refA == null && refB == null) { return null; } return function (refValue) { setRef(refA, refValue); setRef(refB, refValue); }; }, [refA, refB]); }; var useEnhancedEffect = typeof window !== "undefined" ? React.useLayoutEffect : React.useEffect; function useEventCallback(fn) { var ref = React.useRef(fn); useEnhancedEffect(function () { ref.current = fn; }); return React.useCallback(function (event) { return (0, ref.current)(event); }, []); } function mapEventPropToEvent(eventProp) { return eventProp.substring(2).toLowerCase(); } var ClickAway = React.forwardRef(function (props, ref) { var style = props.style, className = props.className, onClickAway = props.onClickAway, _a = props.mouseEvent, mouseEvent = _a === void 0 ? "onClick" : _a, _b = props.touchEvent, touchEvent = _b === void 0 ? "onTouchEnd" : _b, _c = props.onClickIn, onClickIn = _c === void 0 ? function () { return void 0; } : _c, children = props.children; var _d = React.useState(false), clicked = _d[0], setClicked = _d[1]; var movedRef = React.useRef(false); var nodeRef = React.useRef(null); var mountedRef = React.useRef(false); React.useEffect(function () { mountedRef.current = true; return function () { mountedRef.current = false; }; }, []); var handleNodeRef = useForkRef(nodeRef, ref); var handleOwnRef = React.useCallback(function (instance) { setRef(handleNodeRef, ReactDOM.findDOMNode(instance)); }, [handleNodeRef]); var handleRef = useForkRef(children.ref, handleOwnRef); var handleClickIn = React.useCallback(function () { setClicked(function (state) { return !state; }); onClickIn(); }, [onClickIn]); var handleClickAway = useEventCallback(function (event) { if (!mountedRef.current) { return; } if (movedRef.current) { movedRef.current = false; return; } if (!nodeRef.current) return; var doc = ownerDocument(nodeRef.current); if (doc.documentElement && doc.documentElement.contains(event.target) && !nodeRef.current.contains(event.target)) { if (clicked) { setClicked(false); onClickAway(event); } } }); var handleTouchMove = React.useCallback(function () { movedRef.current = true; }, []); React.useEffect(function () { if (touchEvent !== false) { var mappedTouchEvent_1 = mapEventPropToEvent(touchEvent); var doc_1 = ownerDocument(nodeRef.current); doc_1.addEventListener(mappedTouchEvent_1, handleClickAway); doc_1.addEventListener("touchmove", handleTouchMove); return function () { doc_1.removeEventListener(mappedTouchEvent_1, handleClickAway); doc_1.removeEventListener("touchmove", handleTouchMove); }; } return undefined; }, [handleClickAway, handleTouchMove, touchEvent]); React.useEffect(function () { if (mouseEvent !== false) { var mappedMouseEvent_1 = mapEventPropToEvent(mouseEvent); var doc_2 = ownerDocument(nodeRef.current); doc_2.addEventListener(mappedMouseEvent_1, handleClickAway); return function () { doc_2.removeEventListener(mappedMouseEvent_1, handleClickAway); }; } return undefined; }, [handleClickAway, mouseEvent]); var Wrapper = (React.createElement("div", { role: "presentation", onClick: handleClickIn, style: style, className: className }, children)); return React.createElement(React.Fragment, null, React.cloneElement(Wrapper, { ref: handleRef })); }); export { ClickAway, Lottie, Renderer, useLottie }; //# sourceMappingURL=index.esm.js.map