import React , { CSSProperties , useEffect , useRef , ReactElement , useState , } from 'react' ; import lottie , { AnimationConfigWithData , AnimationItem , AnimationDirection , AnimationSegment , } from 'lottie-web' ; import { Listener , LottieOptions , LottieRefCurrentProps , PartialListener , } from './types' ; const useLottie = ( props , style ? ) : { View : ReactElement ; } & LottieRefCurrentProps => { const { animationData , loop , autoplay , initialSegment , onComplete , onLoopComplete , onEnterFrame , onSegmentStart , onConfigReady , onDataReady , onDataFailed , onLoadedImages , onDOMLoaded , onDestroy , lottieRef , renderer , name , assetsPath , rendererSettings , quality = 8 , ... rest } = props ; const [ animationLoaded , setAnimationLoaded ] = useState ( false ) ; const animationInstanceRef = useRef < AnimationItem > ( ) ; const animationContainer = useRef < HTMLDivElement > ( null ) ; const play = ( ) : void => { animationInstanceRef . current ?. play ( ) ; } ; const stop = ( ) : void => { animationInstanceRef . current ?. stop ( ) ; } ; const pause = ( ) : void => { animationInstanceRef . current ?. pause ( ) ; } ; const setSpeed = ( speed ) : void => { animationInstanceRef . current ?. setSpeed ( speed ) ; } ; const goToAndPlay = ( value , isFrame ? ) : void => { animationInstanceRef . current ?. goToAndPlay ( value , isFrame ) ; } ; const goToAndStop = ( value , isFrame ? ) : void => { animationInstanceRef . current ?. goToAndStop ( value , isFrame ) ; } ; const setDirection = ( direction ) : void => { animationInstanceRef . current ?. setDirection ( direction ) ; } ; const playSegments = ( segments , forceFlag ? ) : void => { animationInstanceRef . current ?. playSegments ( segments , forceFlag ) ; } ; const setSubframe = ( useSubFrames ) : void => { animationInstanceRef . current ?. setSubframe ( useSubFrames ) ; } ; /**
     * Get animation duration
     */ const getDuration = ( inFrames ? ) : number | undefined => { return animationInstanceRef . current ?. getDuration ( inFrames ) ; } ; /**
     * Destroy animation
     */ const destroy = ( ) : void => { animationInstanceRef . current ?. destroy ( ) ; } ; /**
     * Load a new animation, and if it's the case, destroy the previous one
     */ const loadAnimation = ( forcedConfigs = { } ) => { if ( ! animationContainer . current ) { return ; } animationInstanceRef . current ?. destroy ( ) ; const config = { ... props , ... forcedConfigs , container : animationContainer . current , } ; lottie . setQuality ( quality ) ; animationInstanceRef . current = lottie . loadAnimation ( config ) ; setAnimationLoaded ( ! ! animationInstanceRef . current ) ; } ; /**
     * Initialize and listen for changes that affect the animation state
     */ useEffect ( ( ) => { loadAnimation ( ) ; } , [ animationData ] ) ; useEffect ( ( ) => { if ( ! animationInstanceRef . current ) { return ; } animationInstanceRef . current . loop = ! ! loop ; if ( loop && animationInstanceRef . current . isPaused ) { animationInstanceRef . current . play ( ) ; } } , [ loop ] ) ; useEffect ( ( ) => { if ( ! animationInstanceRef . current ) { return ; } animationInstanceRef . current . autoplay = ! ! autoplay ; } , [ autoplay ] ) ; useEffect ( ( ) => { if ( ! animationInstanceRef . current ) { return ; } if ( ! initialSegment ) { animationInstanceRef . current . resetSegments ( false ) ; return ; } if ( ! Array . isArray ( initialSegment ) || ! initialSegment . length ) { return ; } if ( animationInstanceRef . current . currentRawFrame < initialSegment [ 0 ] || animationInstanceRef . current . currentRawFrame > initialSegment [ 1 ] ) { animationInstanceRef . current . currentRawFrame = initialSegment [ 0 ] ; } animationInstanceRef . current . setSegment ( initialSegment [ 0 ] , initialSegment [ 1 ] ) ; } , [ initialSegment ] ) ; /**
     * Reinitialize listener on change
     */ useEffect ( ( ) => { const partialListeners = [ { name : 'complete' , handler : onComplete } , { name : 'loopComplete' , handler : onLoopComplete } , { name : 'enterFrame' , handler : onEnterFrame } , { name : 'segmentStart' , handler : onSegmentStart } , { name : 'config_ready' , handler : onConfigReady } , { name : 'data_ready' , handler : onDataReady } , { name : 'data_failed' , handler : onDataFailed } , { name : 'loaded_images' , handler : onLoadedImages } , { name : 'DOMLoaded' , handler : onDOMLoaded } , { name : 'destroy' , handler : onDestroy } , ] ; const listeners = partialListeners . filter ( ( listener ) : listener is Listener => listener . handler != null ) ; if ( ! listeners . length ) { return ; } const deregisterList = listeners . map ( ( listener ) => { animationInstanceRef . current ?. addEventListener ( listener . name , listener . handler ) ; return ( ) => { animationInstanceRef . current ?. removeEventListener ( listener . name , listener . handler ) ; } ; } ) ; return ( ) => { deregisterList . forEach ( ( deregister ) => deregister ( ) ) ; } ; } , [ onComplete , onLoopComplete , onEnterFrame , onSegmentStart , onConfigReady , onDataReady , onDataFailed , onLoadedImages , onDOMLoaded , onDestroy , ] ) ; /**
     * Build the animation view
     */ const View = < div style = { style } ref = { animationContainer } { ... rest } />; return { View , play , stop , pause , setSpeed , goToAndStop , goToAndPlay , setDirection , playSegments , setSubframe , getDuration , destroy , animationLoaded , animationItem : animationInstanceRef . current , } ; } ; export default useLottie ;