import { useRef, useEffect, ReactNode, useCallback, useMemo, memo, forwardRef } from 'react'; import { Animated, Pressable, // Easing, StyleProp, StyleSheet, useWindowDimensions, View, ViewProps, ViewStyle, } from 'react-native'; import type { MD3Elevation } from '../../types/theme'; import { useBackHandler } from '../../hooks'; import { Surface } from '../Surface'; import { modalStyles } from './utils'; export type Props = ViewProps & { /** * Determines whether clicking outside the modal dismiss it. */ dismissible?: boolean; /** * Accessibility label for the overlay. This is read by the screen reader when the user taps outside the modal. */ overlayAccessibilityLabel?: string; /** * content elevation */ elevation?: MD3Elevation; /** * to determine whether the modal is visible or not */ isOpen: boolean | undefined; /** * onClose function will be trigger when the modal is dismissed */ onClose?: () => void; /** * Content of the `Modal`. */ children: ReactNode; /** * Style for the content of the modal */ contentContainerStyle?: StyleProp; /** * Size of the modal * md - width and height - auto * lg - maxWidth:600, maxHeight:800 */ size?: 'md' | 'lg'; /** * Style for the wrapper of the modal. * Use this prop to change the default wrapper style or to override safe area insets with marginTop and marginBottom. */ style?: StyleProp; backdropStyle?: StyleProp; containerStyle?: StyleProp; // /** // * Duration of the animations in the modal // * @default 220 // * */ // animationDuration?: number; /** * testID to be used on tests. */ testID?: string; }; // const DEFAULT_DURATION = 220; function Modal( { dismissible = true, isOpen = false, overlayAccessibilityLabel = 'Close modal', onClose, children, contentContainerStyle: contentContainerStyleProp, elevation, size = 'md', style, containerStyle, // animationDuration = DEFAULT_DURATION, testID = 'modal', backdropStyle: backdropStyleProp, ...rest }: Props, ref: any, ) { modalStyles.useVariants({ size: size as any, }); const visibleRef = useRef(isOpen); // const prevVisible = useRef(null); // const opacityRef = useRef(new Animated.Value(isOpen ? 1 : 0)); const hideModalRef = useRef<() => void>(() => {}); const dimensions = useWindowDimensions(); const { backdropStyle, contentContainerStyle, contentStyle } = useMemo(() => { return { animationScale: 1, backdropStyle: [ modalStyles.backdrop, { // @ts-ignore to resolve maximum callstack exceeded issue // TODO - find out why this is happening(it isn't happening on contentStyle) opacity: 1, }, backdropStyleProp, ], contentContainerStyle: [ StyleSheet.absoluteFill, modalStyles.contentContainer, contentContainerStyleProp, ], contentStyle: [ modalStyles.modalContent, { width: dimensions.width, opacity: 1 }, style, ], }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [backdropStyleProp, contentContainerStyleProp, dimensions.width, style, size]); const handleBack = useCallback(() => { if (dismissible) { hideModalRef.current(); } return true; }, [dismissible]); useBackHandler({ enabled: isOpen, callback: handleBack, }); // const showModal = useCallback(() => { // Animated.timing(opacityRef.current, { // toValue: 1, // duration: animationScale * animationDuration, // easing: Easing.out(Easing.cubic), // useNativeDriver: true, // }).start(); // }, [animationDuration, animationScale, opacityRef]); const hideModal = useCallback(() => { // Animated.timing(opacityRef.current, { // toValue: 0, // duration: animationScale * animationDuration, // easing: Easing.out(Easing.cubic), // useNativeDriver: true, // }).start(({ finished }) => { // if (!finished) { // return; // } // if (isOpen && onClose) { // onClose(); // } // }); if (isOpen && onClose) { onClose(); } }, [isOpen, onClose]); useEffect(() => { hideModalRef.current = hideModal; }, [hideModal]); useEffect(() => { visibleRef.current = isOpen; }); // useEffect(() => { // if (prevVisible.current !== isOpen) { // if (isOpen) { // showModal(); // } else { // hideModal(); // } // } // prevVisible.current = isOpen; // }, [hideModal, showModal, isOpen]); if (!isOpen) return null; return ( {children} ); } export default memo(forwardRef(Modal));