import React , { FunctionComponent , useCallback , useEffect , useMemo , useRef , useState } from 'react' ; import { Animated , Easing , EasingFunction , Platform , StyleSheet } from 'react-native' ; const IOS_OPACITY = 0.25 ; export type BackdropContextValue = { show : ( ) => void ; hide : ( ) => void ; toggle : ( ) => void ; } ; export const BackdropContext = React . createContext < BackdropContextValue > ( null ) ; export type BackdropProviderProps = { backgroundColor ? : string ; duration ? : number ; easing ? : EasingFunction ; opacity ? : number ; useNativeDriver ? : boolean ; zIndex ? : number ; } ; export const defaultProps = { backgroundColor : 'black' , duration : 300 , easing : Easing . inOut ( Easing . ease ) , opacity : IOS_OPACITY , useNativeDriver : true , zIndex : 99 } ; export const BackdropProvider = ( { backgroundColor = 'black' , children , duration = defaultProps . duration , easing = defaultProps . easing , opacity = defaultProps . opacity , useNativeDriver = defaultProps . useNativeDriver , zIndex = defaultProps . zIndex } ) => { const [ isVisible , setIsVisible ] = useState < boolean > ( false ) ; const [ displayStyle , setDisplayStyle ] = useState < 'flex' | 'none' > ( 'flex' ) ; const latestIsVisible = useRef < boolean > ( isVisible ) ; const show = useCallback ( ( ) => { setIsVisible ( true ) ; setDisplayStyle ( 'flex' ) ; } , [ ] ) ; const hide = useCallback ( ( ) => { setIsVisible ( false ) ; latestIsVisible . current = false ; } , [ ] ) ; useEffect ( ( ) => { latestIsVisible . current = isVisible ; } , [ isVisible ] ) ; const toggle = useCallback ( ( ) => { ! latestIsVisible . current ? show ( ) : hide ( ) ; } , [ latestIsVisible , show , hide ] ) ; const contextValue = useMemo < BackdropContextValue > ( ( ) => { return { show , hide , toggle } ; } , [ show , hide , toggle ] ) ; const { current : animatedOpacity } = useRef ( new Animated . Value ( 0 ) ) ; useEffect ( ( ) => { const animation = Animated . timing ( animatedOpacity , { duration : isVisible ? duration : 200 , easing , toValue : isVisible ? opacity : 0 , useNativeDriver } ) ; animation . start ( ( ) => { setDisplayStyle ( isVisible ? 'flex' : 'none' ) ; } ) ; return ( ) => animation . stop ( ) ; } , [ isVisible , duration , easing , opacity , animatedOpacity , useNativeDriver ] ) ; return ( < BackdropContext . Provider value = { contextValue } > { children } < Animated . View style = { [ StyleSheet . absoluteFill , Platform . select ( { android : { position : displayStyle === 'none' ? 'relative' : 'absolute' } } ) , { display : displayStyle , zIndex , backgroundColor , opacity : animatedOpacity } ] } / > < /BackdropContext.Provider>); } ; export default BackdropProvider ;