From 7d7f76f9be77fdbe2108c15974afd5ccadd8f9dd Mon Sep 17 00:00:00 2001 From: Ross Johnson Date: Thu, 13 Jul 2023 16:54:11 +0100 Subject: [PATCH 1/5] Remove DefaultProps, use default params instead --- src/makeLottiePlayer.js | 393 ++++++++++++++++++--------------- src/{props.js => propTypes.js} | 32 +-- 2 files changed, 216 insertions(+), 209 deletions(-) rename src/{props.js => propTypes.js} (56%) diff --git a/src/makeLottiePlayer.js b/src/makeLottiePlayer.js index 542fe37..b3d47fb 100644 --- a/src/makeLottiePlayer.js +++ b/src/makeLottiePlayer.js @@ -1,213 +1,242 @@ // eslint-disable-next-line no-unused-vars import React, { - memo, useRef, useEffect, useState, forwardRef, useCallback, + memo, + useRef, + useEffect, + useState, + forwardRef, + useCallback, } from 'react'; import equal from 'fast-deep-equal/es6/react'; import clone from 'rfdc/default'; -import { propTypes, defaultProps } from './props'; +import propTypes from './propTypes'; const makeLottiePlayer = ({ loadAnimation }) => { - const Lottie = memo(forwardRef(({ - animationData, - path, - - play, - speed, - direction, - segments: segmentsIn, - goTo, - useSubframes, - - renderer, - loop, - rendererSettings: rendererSettingsIn, - - audioFactory, - - onLoad, - onComplete, - onLoopComplete, - onEnterFrame, - onSegmentStart, - - ...props - }, forwardedRef) => { - const animElementRef = useRef(); - const animRef = useRef(); - - const [ready, setReady] = useState(false); - - const [segments, setSegments] = useState(segmentsIn); - - // Prevent re-init - useEffect(() => { - if (!equal(segments, segmentsIn)) setSegments(segmentsIn); - }, [segmentsIn, segments]); - - const [rendererSettings, setRendererSettings] = useState(rendererSettingsIn); - - // Prevent re-init - useEffect(() => { - if (!equal(rendererSettings, rendererSettingsIn)) setRendererSettings(rendererSettingsIn); - }, [rendererSettingsIn, rendererSettings]); - - // In order to remove listeners before animRef gets destroyed: - useEffect(() => () => animRef.current.removeEventListener('complete', onComplete), [onComplete]); - useEffect(() => () => animRef.current.removeEventListener('loopComplete', onLoopComplete), [onLoopComplete]); - useEffect(() => () => animRef.current.removeEventListener('enterFrame', onEnterFrame), [onEnterFrame]); - useEffect(() => () => animRef.current.removeEventListener('segmentStart', onSegmentStart), [onSegmentStart]); - useEffect(() => () => animRef.current.removeEventListener('DOMLoaded', onLoad), [onLoad]); - - const setLottieRefs = useCallback((newRef) => { - animRef.current = newRef; - // eslint-disable-next-line no-param-reassign - if (forwardedRef) forwardedRef.current = newRef; - }, []); // eslint-disable-line react-hooks/exhaustive-deps - - useEffect(() => { - function parseAnimationData() { - if (animationData == null || typeof animationData !== 'object') return animationData; - - // https://github.com/mifi/react-lottie-player/issues/11#issuecomment-879310039 - // https://github.com/chenqingspring/vue-lottie/issues/20 - if (typeof animationData.default === 'object') { - return clone(animationData.default); + const Lottie = memo( + forwardRef((params, forwardedRef) => { + const { + animationData = null, + path = null, + + play = null, + speed = 1, + direction = 1, + segments: segmentsIn = null, + goTo = null, + useSubframes = true, + + renderer = 'svg', + loop = true, + rendererSettings: rendererSettingsIn = {}, + + audioFactory = null, + + onLoad = () => {}, + onComplete = () => {}, + onLoopComplete = () => {}, + onEnterFrame = () => {}, + onSegmentStart = () => {}, + ...props + } = params; + const animElementRef = useRef(); + const animRef = useRef(); + + const [ready, setReady] = useState(false); + + const [segments, setSegments] = useState(segmentsIn); + + // Prevent re-init + useEffect(() => { + if (!equal(segments, segmentsIn)) setSegments(segmentsIn); + }, [segmentsIn, segments]); + + const [rendererSettings, setRendererSettings] = useState(rendererSettingsIn); + + // Prevent re-init + useEffect(() => { + if (!equal(rendererSettings, rendererSettingsIn)) setRendererSettings(rendererSettingsIn); + }, [rendererSettingsIn, rendererSettings]); + + // In order to remove listeners before animRef gets destroyed: + useEffect( + () => () => animRef.current.removeEventListener('complete', onComplete), + [onComplete], + ); + useEffect( + () => () => animRef.current.removeEventListener('loopComplete', onLoopComplete), + [onLoopComplete], + ); + useEffect( + () => () => animRef.current.removeEventListener('enterFrame', onEnterFrame), + [onEnterFrame], + ); + useEffect( + () => () => animRef.current.removeEventListener('segmentStart', onSegmentStart), + [onSegmentStart], + ); + useEffect( + () => () => animRef.current.removeEventListener('DOMLoaded', onLoad), + [onLoad], + ); + + const setLottieRefs = useCallback((newRef) => { + animRef.current = newRef; + // eslint-disable-next-line no-param-reassign + if (forwardedRef) forwardedRef.current = newRef; + }, []); // eslint-disable-line react-hooks/exhaustive-deps + + useEffect(() => { + function parseAnimationData() { + if (animationData == null || typeof animationData !== 'object') return animationData; + + // https://github.com/mifi/react-lottie-player/issues/11#issuecomment-879310039 + // https://github.com/chenqingspring/vue-lottie/issues/20 + if (typeof animationData.default === 'object') { + return clone(animationData.default); + } + // cloneDeep to prevent memory leak. See #35 + return clone(animationData); } - // cloneDeep to prevent memory leak. See #35 - return clone(animationData); - } - // console.log('init') - const lottie = loadAnimation({ - animationData: parseAnimationData(), - path, - container: animElementRef.current, + // console.log('init') + const lottie = loadAnimation({ + animationData: parseAnimationData(), + path, + container: animElementRef.current, + renderer, + loop: false, + autoplay: false, // We want to explicitly control playback + rendererSettings, + audioFactory, + }); + setLottieRefs(lottie); + + const onDomLoaded = () => setReady(true); + + animRef.current.addEventListener('DOMLoaded', onDomLoaded); + + return () => { + animRef.current.removeEventListener('DOMLoaded', onDomLoaded); + setReady(false); + animRef.current.destroy(); + setLottieRefs(undefined); + }; + }, [ + loop, renderer, - loop: false, - autoplay: false, // We want to explicitly control playback rendererSettings, + animationData, + path, audioFactory, - }); - setLottieRefs(lottie); + setLottieRefs, + ]); - const onDomLoaded = () => setReady(true); + useEffect(() => { + animRef.current.addEventListener('DOMLoaded', onLoad); + }, [onLoad]); - animRef.current.addEventListener('DOMLoaded', onDomLoaded); + useEffect(() => { + animRef.current.addEventListener('complete', onComplete); + }, [onComplete]); - return () => { - animRef.current.removeEventListener('DOMLoaded', onDomLoaded); - setReady(false); - animRef.current.destroy(); - setLottieRefs(undefined); - }; - }, [loop, renderer, rendererSettings, animationData, path, audioFactory, setLottieRefs]); + useEffect(() => { + animRef.current.addEventListener('loopComplete', onLoopComplete); + }, [onLoopComplete]); - useEffect(() => { - animRef.current.addEventListener('DOMLoaded', onLoad); - }, [onLoad]); + useEffect(() => { + animRef.current.addEventListener('enterFrame', onEnterFrame); + }, [onEnterFrame]); - useEffect(() => { - animRef.current.addEventListener('complete', onComplete); - }, [onComplete]); + useEffect(() => { + animRef.current.addEventListener('segmentStart', onSegmentStart); + }, [onSegmentStart]); - useEffect(() => { - animRef.current.addEventListener('loopComplete', onLoopComplete); - }, [onLoopComplete]); + useEffect(() => { + if (!ready) return; + animRef.current.loop = loop; + }, [ready, loop]); - useEffect(() => { - animRef.current.addEventListener('enterFrame', onEnterFrame); - }, [onEnterFrame]); + const wasPlayingSegmentsRef = useRef(false); - useEffect(() => { - animRef.current.addEventListener('segmentStart', onSegmentStart); - }, [onSegmentStart]); + useEffect(() => { + if (!ready) return; - useEffect(() => { - if (!ready) return; - animRef.current.loop = loop; - }, [ready, loop]); - - const wasPlayingSegmentsRef = useRef(false); - - useEffect(() => { - if (!ready) return; + // Without this code, when playback restarts, it will not play in reverse: + // https://github.com/mifi/react-lottie-player/issues/19 + function playReverse(lastFrame) { + animRef.current.goToAndPlay(lastFrame, true); + animRef.current.setDirection(direction); + } - // Without this code, when playback restarts, it will not play in reverse: - // https://github.com/mifi/react-lottie-player/issues/19 - function playReverse(lastFrame) { - animRef.current.goToAndPlay(lastFrame, true); - animRef.current.setDirection(direction); - } - - if (play === true) { - const force = true; - if (segments) { - animRef.current.playSegments(segments, force); - wasPlayingSegmentsRef.current = true; - - // This needs to be called after playSegments or it will not play backwards - if (direction === -1) { - // TODO What if more than one segment - const lastFrame = segments[1]; - playReverse(lastFrame); - } - } else { - // If we called playSegments last time, the segments are stored as a state in the lottie object - // Need to reset segments or else it will still play the old segments also when calling play() - // wasPlayingSegmentsRef: Only reset segments if playSegments last time, because resetSegments will also reset playback position - // https://github.com/airbnb/lottie-web/blob/master/index.d.ts - if (wasPlayingSegmentsRef.current) animRef.current.resetSegments(force); - wasPlayingSegmentsRef.current = false; - - if (direction === -1) { - const lastFrame = animRef.current.getDuration(true); - playReverse(lastFrame); + if (play === true) { + const force = true; + if (segments) { + animRef.current.playSegments(segments, force); + wasPlayingSegmentsRef.current = true; + + // This needs to be called after playSegments or it will not play backwards + if (direction === -1) { + // TODO What if more than one segment + const lastFrame = segments[1]; + playReverse(lastFrame); + } } else { - animRef.current.play(); + // If we called playSegments last time, the segments are stored as a state in the lottie object + // Need to reset segments or else it will still play the old segments also when calling play() + // wasPlayingSegmentsRef: Only reset segments if playSegments last time, because resetSegments will also reset playback position + // https://github.com/airbnb/lottie-web/blob/master/index.d.ts + if (wasPlayingSegmentsRef.current) animRef.current.resetSegments(force); + wasPlayingSegmentsRef.current = false; + + if (direction === -1) { + const lastFrame = animRef.current.getDuration(true); + playReverse(lastFrame); + } else { + animRef.current.play(); + } } + } else if (play === false) { + animRef.current.pause(); } - } else if (play === false) { - animRef.current.pause(); - } - }, [play, segments, ready, direction]); - - useEffect(() => { - if (!ready) return; - if (Number.isNaN(speed)) return; - animRef.current.setSpeed(speed); - }, [speed, ready]); - - // This handles the case where only direction has changed (direction is not a dependency of the other effect that calls setDirection) - useEffect(() => { - if (!ready) return; - animRef.current.setDirection(direction); - }, [direction, ready]); - - useEffect(() => { - if (!ready) return; - if (goTo == null) return; - const isFrame = true; // TODO - if (play) animRef.current.goToAndPlay(goTo, isFrame); - else animRef.current.goToAndStop(goTo, isFrame); - }, [goTo, play, ready]); - - useEffect(() => { - if (animRef.current.setSubframe) animRef.current.setSubframe(useSubframes); - // console.log(animRef.current.isSubframeEnabled) - }, [useSubframes]); - - return ( -
- ); - })); + }, [play, segments, ready, direction]); + + useEffect(() => { + if (!ready) return; + if (Number.isNaN(speed)) return; + animRef.current.setSpeed(speed); + }, [speed, ready]); + + // This handles the case where only direction has changed (direction is not a dependency of the other effect that calls setDirection) + useEffect(() => { + if (!ready) return; + animRef.current.setDirection(direction); + }, [direction, ready]); + + useEffect(() => { + if (!ready) return; + if (goTo == null) return; + const isFrame = true; // TODO + if (play) animRef.current.goToAndPlay(goTo, isFrame); + else animRef.current.goToAndStop(goTo, isFrame); + }, [goTo, play, ready]); + + useEffect(() => { + if (animRef.current.setSubframe) animRef.current.setSubframe(useSubframes); + // console.log(animRef.current.isSubframeEnabled) + }, [useSubframes]); + + return ( +
+ ); + }), + ); Lottie.propTypes = propTypes; - Lottie.defaultProps = defaultProps; return Lottie; }; diff --git a/src/props.js b/src/propTypes.js similarity index 56% rename from src/props.js rename to src/propTypes.js index f009552..0b0f0d7 100644 --- a/src/props.js +++ b/src/propTypes.js @@ -1,7 +1,7 @@ // eslint-disable-next-line import/no-extraneous-dependencies import PropTypes from 'prop-types'; -export const propTypes = { +export default { // You can use either animationData OR path animationData: PropTypes.object, path: PropTypes.string, @@ -13,7 +13,10 @@ export const propTypes = { loop: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]), useSubframes: PropTypes.bool, - segments: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), PropTypes.bool]), + segments: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.number), + PropTypes.bool, + ]), rendererSettings: PropTypes.object, @@ -26,28 +29,3 @@ export const propTypes = { onEnterFrame: PropTypes.func, onSegmentStart: PropTypes.func, }; - -export const defaultProps = { - animationData: null, - path: null, - - play: null, - segments: null, - goTo: null, - useSubframes: true, - - speed: 1, - direction: 1, - loop: true, - - rendererSettings: {}, - renderer: 'svg', - - audioFactory: null, - - onLoad: () => {}, - onComplete: () => {}, - onLoopComplete: () => {}, - onEnterFrame: () => {}, - onSegmentStart: () => {}, -}; From 0cdd0ef27c2529a173dd88e0eb00e816cb2881e2 Mon Sep 17 00:00:00 2001 From: Ross Johnson Date: Thu, 13 Jul 2023 17:10:13 +0100 Subject: [PATCH 2/5] fixed linting rules --- src/makeLottiePlayer.js | 391 +++++++++++++++++++--------------------- 1 file changed, 181 insertions(+), 210 deletions(-) diff --git a/src/makeLottiePlayer.js b/src/makeLottiePlayer.js index b3d47fb..1710db8 100644 --- a/src/makeLottiePlayer.js +++ b/src/makeLottiePlayer.js @@ -1,11 +1,6 @@ // eslint-disable-next-line no-unused-vars import React, { - memo, - useRef, - useEffect, - useState, - forwardRef, - useCallback, + memo, useRef, useEffect, useState, forwardRef, useCallback, } from 'react'; import equal from 'fast-deep-equal/es6/react'; import clone from 'rfdc/default'; @@ -13,228 +8,204 @@ import clone from 'rfdc/default'; import propTypes from './propTypes'; const makeLottiePlayer = ({ loadAnimation }) => { - const Lottie = memo( - forwardRef((params, forwardedRef) => { - const { - animationData = null, - path = null, - - play = null, - speed = 1, - direction = 1, - segments: segmentsIn = null, - goTo = null, - useSubframes = true, - - renderer = 'svg', - loop = true, - rendererSettings: rendererSettingsIn = {}, - - audioFactory = null, - - onLoad = () => {}, - onComplete = () => {}, - onLoopComplete = () => {}, - onEnterFrame = () => {}, - onSegmentStart = () => {}, - ...props - } = params; - const animElementRef = useRef(); - const animRef = useRef(); - - const [ready, setReady] = useState(false); - - const [segments, setSegments] = useState(segmentsIn); - - // Prevent re-init - useEffect(() => { - if (!equal(segments, segmentsIn)) setSegments(segmentsIn); - }, [segmentsIn, segments]); - - const [rendererSettings, setRendererSettings] = useState(rendererSettingsIn); - - // Prevent re-init - useEffect(() => { - if (!equal(rendererSettings, rendererSettingsIn)) setRendererSettings(rendererSettingsIn); - }, [rendererSettingsIn, rendererSettings]); - - // In order to remove listeners before animRef gets destroyed: - useEffect( - () => () => animRef.current.removeEventListener('complete', onComplete), - [onComplete], - ); - useEffect( - () => () => animRef.current.removeEventListener('loopComplete', onLoopComplete), - [onLoopComplete], - ); - useEffect( - () => () => animRef.current.removeEventListener('enterFrame', onEnterFrame), - [onEnterFrame], - ); - useEffect( - () => () => animRef.current.removeEventListener('segmentStart', onSegmentStart), - [onSegmentStart], - ); - useEffect( - () => () => animRef.current.removeEventListener('DOMLoaded', onLoad), - [onLoad], - ); - - const setLottieRefs = useCallback((newRef) => { - animRef.current = newRef; - // eslint-disable-next-line no-param-reassign - if (forwardedRef) forwardedRef.current = newRef; - }, []); // eslint-disable-line react-hooks/exhaustive-deps - - useEffect(() => { - function parseAnimationData() { - if (animationData == null || typeof animationData !== 'object') return animationData; - - // https://github.com/mifi/react-lottie-player/issues/11#issuecomment-879310039 - // https://github.com/chenqingspring/vue-lottie/issues/20 - if (typeof animationData.default === 'object') { - return clone(animationData.default); - } - // cloneDeep to prevent memory leak. See #35 - return clone(animationData); + const Lottie = memo(forwardRef((params, forwardedRef) => { + const { + animationData = null, + path = null, + + play = null, + speed = 1, + direction = 1, + segments: segmentsIn = null, + goTo = null, + useSubframes = true, + + renderer = 'svg', + loop = true, + rendererSettings: rendererSettingsIn = {}, + + audioFactory = null, + + onLoad = () => {}, + onComplete = () => {}, + onLoopComplete = () => {}, + onEnterFrame = () => {}, + onSegmentStart = () => {}, + ...props + } = params; + + const animElementRef = useRef(); + const animRef = useRef(); + + const [ready, setReady] = useState(false); + + const [segments, setSegments] = useState(segmentsIn); + + // Prevent re-init + useEffect(() => { + if (!equal(segments, segmentsIn)) setSegments(segmentsIn); + }, [segmentsIn, segments]); + + const [rendererSettings, setRendererSettings] = useState(rendererSettingsIn); + + // Prevent re-init + useEffect(() => { + if (!equal(rendererSettings, rendererSettingsIn)) setRendererSettings(rendererSettingsIn); + }, [rendererSettingsIn, rendererSettings]); + + // In order to remove listeners before animRef gets destroyed: + useEffect(() => () => animRef.current.removeEventListener('complete', onComplete), [onComplete]); + useEffect(() => () => animRef.current.removeEventListener('loopComplete', onLoopComplete), [onLoopComplete]); + useEffect(() => () => animRef.current.removeEventListener('enterFrame', onEnterFrame), [onEnterFrame]); + useEffect(() => () => animRef.current.removeEventListener('segmentStart', onSegmentStart), [onSegmentStart]); + useEffect(() => () => animRef.current.removeEventListener('DOMLoaded', onLoad), [onLoad]); + + const setLottieRefs = useCallback((newRef) => { + animRef.current = newRef; + // eslint-disable-next-line no-param-reassign + if (forwardedRef) forwardedRef.current = newRef; + }, []); // eslint-disable-line react-hooks/exhaustive-deps + + useEffect(() => { + function parseAnimationData() { + if (animationData == null || typeof animationData !== 'object') return animationData; + + // https://github.com/mifi/react-lottie-player/issues/11#issuecomment-879310039 + // https://github.com/chenqingspring/vue-lottie/issues/20 + if (typeof animationData.default === 'object') { + return clone(animationData.default); } + // cloneDeep to prevent memory leak. See #35 + return clone(animationData); + } - // console.log('init') - const lottie = loadAnimation({ - animationData: parseAnimationData(), - path, - container: animElementRef.current, - renderer, - loop: false, - autoplay: false, // We want to explicitly control playback - rendererSettings, - audioFactory, - }); - setLottieRefs(lottie); - - const onDomLoaded = () => setReady(true); - - animRef.current.addEventListener('DOMLoaded', onDomLoaded); - - return () => { - animRef.current.removeEventListener('DOMLoaded', onDomLoaded); - setReady(false); - animRef.current.destroy(); - setLottieRefs(undefined); - }; - }, [ - loop, + // console.log('init') + const lottie = loadAnimation({ + animationData: parseAnimationData(), + path, + container: animElementRef.current, renderer, + loop: false, + autoplay: false, // We want to explicitly control playback rendererSettings, - animationData, - path, audioFactory, - setLottieRefs, - ]); + }); + setLottieRefs(lottie); - useEffect(() => { - animRef.current.addEventListener('DOMLoaded', onLoad); - }, [onLoad]); + const onDomLoaded = () => setReady(true); - useEffect(() => { - animRef.current.addEventListener('complete', onComplete); - }, [onComplete]); + animRef.current.addEventListener('DOMLoaded', onDomLoaded); - useEffect(() => { - animRef.current.addEventListener('loopComplete', onLoopComplete); - }, [onLoopComplete]); + return () => { + animRef.current.removeEventListener('DOMLoaded', onDomLoaded); + setReady(false); + animRef.current.destroy(); + setLottieRefs(undefined); + }; + }, [loop, renderer, rendererSettings, animationData, path, audioFactory, setLottieRefs]); - useEffect(() => { - animRef.current.addEventListener('enterFrame', onEnterFrame); - }, [onEnterFrame]); + useEffect(() => { + animRef.current.addEventListener('DOMLoaded', onLoad); + }, [onLoad]); - useEffect(() => { - animRef.current.addEventListener('segmentStart', onSegmentStart); - }, [onSegmentStart]); + useEffect(() => { + animRef.current.addEventListener('complete', onComplete); + }, [onComplete]); - useEffect(() => { - if (!ready) return; - animRef.current.loop = loop; - }, [ready, loop]); + useEffect(() => { + animRef.current.addEventListener('loopComplete', onLoopComplete); + }, [onLoopComplete]); - const wasPlayingSegmentsRef = useRef(false); + useEffect(() => { + animRef.current.addEventListener('enterFrame', onEnterFrame); + }, [onEnterFrame]); - useEffect(() => { - if (!ready) return; + useEffect(() => { + animRef.current.addEventListener('segmentStart', onSegmentStart); + }, [onSegmentStart]); - // Without this code, when playback restarts, it will not play in reverse: - // https://github.com/mifi/react-lottie-player/issues/19 - function playReverse(lastFrame) { - animRef.current.goToAndPlay(lastFrame, true); - animRef.current.setDirection(direction); - } + useEffect(() => { + if (!ready) return; + animRef.current.loop = loop; + }, [ready, loop]); - if (play === true) { - const force = true; - if (segments) { - animRef.current.playSegments(segments, force); - wasPlayingSegmentsRef.current = true; - - // This needs to be called after playSegments or it will not play backwards - if (direction === -1) { - // TODO What if more than one segment - const lastFrame = segments[1]; - playReverse(lastFrame); - } - } else { - // If we called playSegments last time, the segments are stored as a state in the lottie object - // Need to reset segments or else it will still play the old segments also when calling play() - // wasPlayingSegmentsRef: Only reset segments if playSegments last time, because resetSegments will also reset playback position - // https://github.com/airbnb/lottie-web/blob/master/index.d.ts - if (wasPlayingSegmentsRef.current) animRef.current.resetSegments(force); - wasPlayingSegmentsRef.current = false; - - if (direction === -1) { - const lastFrame = animRef.current.getDuration(true); - playReverse(lastFrame); - } else { - animRef.current.play(); - } - } - } else if (play === false) { - animRef.current.pause(); - } - }, [play, segments, ready, direction]); + const wasPlayingSegmentsRef = useRef(false); - useEffect(() => { - if (!ready) return; - if (Number.isNaN(speed)) return; - animRef.current.setSpeed(speed); - }, [speed, ready]); + useEffect(() => { + if (!ready) return; - // This handles the case where only direction has changed (direction is not a dependency of the other effect that calls setDirection) - useEffect(() => { - if (!ready) return; + // Without this code, when playback restarts, it will not play in reverse: + // https://github.com/mifi/react-lottie-player/issues/19 + function playReverse(lastFrame) { + animRef.current.goToAndPlay(lastFrame, true); animRef.current.setDirection(direction); - }, [direction, ready]); - - useEffect(() => { - if (!ready) return; - if (goTo == null) return; - const isFrame = true; // TODO - if (play) animRef.current.goToAndPlay(goTo, isFrame); - else animRef.current.goToAndStop(goTo, isFrame); - }, [goTo, play, ready]); - - useEffect(() => { - if (animRef.current.setSubframe) animRef.current.setSubframe(useSubframes); - // console.log(animRef.current.isSubframeEnabled) - }, [useSubframes]); - - return ( -
- ); - }), - ); + } + + if (play === true) { + const force = true; + if (segments) { + animRef.current.playSegments(segments, force); + wasPlayingSegmentsRef.current = true; + + // This needs to be called after playSegments or it will not play backwards + if (direction === -1) { + // TODO What if more than one segment + const lastFrame = segments[1]; + playReverse(lastFrame); + } + } else { + // If we called playSegments last time, the segments are stored as a state in the lottie object + // Need to reset segments or else it will still play the old segments also when calling play() + // wasPlayingSegmentsRef: Only reset segments if playSegments last time, because resetSegments will also reset playback position + // https://github.com/airbnb/lottie-web/blob/master/index.d.ts + if (wasPlayingSegmentsRef.current) animRef.current.resetSegments(force); + wasPlayingSegmentsRef.current = false; + + if (direction === -1) { + const lastFrame = animRef.current.getDuration(true); + playReverse(lastFrame); + } else { + animRef.current.play(); + } + } + } else if (play === false) { + animRef.current.pause(); + } + }, [play, segments, ready, direction]); + + useEffect(() => { + if (!ready) return; + if (Number.isNaN(speed)) return; + animRef.current.setSpeed(speed); + }, [speed, ready]); + + // This handles the case where only direction has changed (direction is not a dependency of the other effect that calls setDirection) + useEffect(() => { + if (!ready) return; + animRef.current.setDirection(direction); + }, [direction, ready]); + + useEffect(() => { + if (!ready) return; + if (goTo == null) return; + const isFrame = true; // TODO + if (play) animRef.current.goToAndPlay(goTo, isFrame); + else animRef.current.goToAndStop(goTo, isFrame); + }, [goTo, play, ready]); + + useEffect(() => { + if (animRef.current.setSubframe) animRef.current.setSubframe(useSubframes); + // console.log(animRef.current.isSubframeEnabled) + }, [useSubframes]); + + return ( +
+ ); + })); Lottie.propTypes = propTypes; From 90914be4322772db9a056922028eca5f6ef2a017 Mon Sep 17 00:00:00 2001 From: Ross Johnson Date: Thu, 13 Jul 2023 17:11:57 +0100 Subject: [PATCH 3/5] revert linting change --- src/propTypes.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/propTypes.js b/src/propTypes.js index 0b0f0d7..48b4404 100644 --- a/src/propTypes.js +++ b/src/propTypes.js @@ -13,10 +13,7 @@ export default { loop: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]), useSubframes: PropTypes.bool, - segments: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.number), - PropTypes.bool, - ]), + segments: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), PropTypes.bool]), rendererSettings: PropTypes.object, From df0326dcd9441e7a458eee5525d0a13f0f7266cb Mon Sep 17 00:00:00 2001 From: Kai Dederichs Date: Wed, 23 Aug 2023 16:36:48 +0200 Subject: [PATCH 4/5] fix: introduce emptyObject and noOp --- src/makeLottiePlayer.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/makeLottiePlayer.js b/src/makeLottiePlayer.js index 1710db8..ec6f6c2 100644 --- a/src/makeLottiePlayer.js +++ b/src/makeLottiePlayer.js @@ -7,6 +7,9 @@ import clone from 'rfdc/default'; import propTypes from './propTypes'; +const emptyObject = {} +const noOp = () => {} + const makeLottiePlayer = ({ loadAnimation }) => { const Lottie = memo(forwardRef((params, forwardedRef) => { const { @@ -22,15 +25,15 @@ const makeLottiePlayer = ({ loadAnimation }) => { renderer = 'svg', loop = true, - rendererSettings: rendererSettingsIn = {}, + rendererSettings: rendererSettingsIn = emptyObject, audioFactory = null, - onLoad = () => {}, - onComplete = () => {}, - onLoopComplete = () => {}, - onEnterFrame = () => {}, - onSegmentStart = () => {}, + onLoad = noOp, + onComplete = noOp, + onLoopComplete = noOp, + onEnterFrame = noOp, + onSegmentStart = noOp, ...props } = params; From 3bee1afd90bb8417b1f91566c17a2db34ff348a6 Mon Sep 17 00:00:00 2001 From: Kai Dederichs Date: Wed, 23 Aug 2023 16:38:37 +0200 Subject: [PATCH 5/5] chore: CS add ; --- src/makeLottiePlayer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/makeLottiePlayer.js b/src/makeLottiePlayer.js index ec6f6c2..ee35a19 100644 --- a/src/makeLottiePlayer.js +++ b/src/makeLottiePlayer.js @@ -7,8 +7,8 @@ import clone from 'rfdc/default'; import propTypes from './propTypes'; -const emptyObject = {} -const noOp = () => {} +const emptyObject = {}; +const noOp = () => {}; const makeLottiePlayer = ({ loadAnimation }) => { const Lottie = memo(forwardRef((params, forwardedRef) => {