import React, { useEffect } from 'react'; import { Animated, StyleSheet, TouchableWithoutFeedback, View, Platform, } from 'react-native'; import { useFadeTransition } from '../../components/composites/Transitions/useFadeTransition'; import isEqual from 'lodash/isEqual'; import type { IOverlayConfig } from './types'; type OverlayWrapperType = { overlayItem: any; overlayConfig: IOverlayConfig; setOverlayItem: any; }; function areEqual( prevProps: OverlayWrapperType, nextProps: OverlayWrapperType ) { if ( isEqual(prevProps.overlayItem, nextProps.overlayItem) && isEqual(prevProps.overlayConfig, nextProps.overlayConfig) ) return true; return false; } function Wrapper({ overlayItem, overlayConfig, setOverlayItem, }: OverlayWrapperType) { const { fadeValue, fadeIn, fadeOut } = useFadeTransition( overlayConfig.animationDuration ); const backgroundColor = overlayConfig.disableOverlay ? 'transparent' : overlayConfig.backgroundColor ?? '#161616cc'; const isSlideAnimation = overlayConfig.motionPreset === 'slide'; const overlayStyle = StyleSheet.create({ wrapper: { position: 'absolute', top: 0, bottom: 0, right: 0, left: 0, zIndex: 999, }, background: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, zIndex: 999, opacity: 0.5, backgroundColor, }, itemBackground: { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, alignItems: 'center', justifyContent: overlayConfig.position === 'top' ? 'flex-start' : overlayConfig.position === 'bottom' ? 'flex-end' : 'center', zIndex: 9999, }, }); const [overlayItemHeight, setOverlayItemHeight] = React.useState(0); const [overlayItemPosition, setOverlayItemposition] = React.useState(0); const [windowSize, setWindowSize] = React.useState(0); const [readyToAnimate, setReadyToAnimate] = React.useState(false); const provideSize = (layoutSize: any) => { setOverlayItemHeight(layoutSize.height); }; const provideWindowSize = (layoutSize: any) => { setWindowSize(layoutSize.height); }; const handleClose = React.useCallback(() => { setOverlayItem(null); overlayConfig.onClose ? overlayConfig.onClose(false) : null; }, [overlayConfig, setOverlayItem]); useEffect(() => { if (isSlideAnimation) { if (overlayItem && overlayItemHeight) { setTimeout(() => { setReadyToAnimate(true); }, 100); } else if (!overlayItem) { setReadyToAnimate(false); } } }, [isSlideAnimation, overlayItem, overlayItemHeight, setReadyToAnimate]); useEffect(() => { if (isSlideAnimation) { switch (overlayConfig.position) { case 'top': setOverlayItemposition(windowSize); break; case 'bottom': setOverlayItemposition(overlayItemHeight); break; default: // as center is default position setOverlayItemposition(windowSize / 2 - overlayItemHeight / 2); break; } } }, [ isSlideAnimation, overlayConfig.position, windowSize, overlayItemHeight, setOverlayItemposition, ]); useEffect( function closeOverlayOnEscapeEffectCallback() { let escapeKeyListener: any = null; if (Platform.OS === 'web') { escapeKeyListener = (e: KeyboardEvent) => { if ( e.key === 'Escape' && overlayConfig.isKeyboardDismissable && overlayItem ) { handleClose(); } }; document.addEventListener('keydown', escapeKeyListener); } return () => { if (Platform.OS === 'web') { document.removeEventListener('keydown', escapeKeyListener); } }; }, [overlayConfig, overlayItem, handleClose] ); const placeOverlayItem = () => { if (readyToAnimate && overlayItem) { const webStyle = { transition: `top ${overlayConfig.animationDuration}ms`, top: 0, }; return ( {overlayItem} ); } else { return ( provideSize(e.nativeEvent.layout)} > {overlayItem} ); } }; overlayItem ? fadeIn() : fadeOut(); const isOverlayOpen = !!overlayItem; const isModal = isOverlayOpen && overlayConfig.accessibilityViewIsModal; return ( { if (overlayConfig.closeOnPress) { handleClose(); } }} > {/* Added box-none instead of none to fix Web modal not able to get clicked inside Modal.Body */} provideWindowSize(e.nativeEvent.layout)} > {isSlideAnimation ? placeOverlayItem() : overlayItem} ); } export default React.memo(Wrapper, areEqual);