import React from 'react' import { StyleSheet, View } from 'react-native' import Animated, { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated' import { SafeAreaInsetsContext } from 'react-native-safe-area-context' import { QuickPreviewOptions } from '../types' import { Backdrop } from './components/Backdrop' import { SheetContainer } from './components/SheetContainer' import { PopoverContainer } from './components/PopoverContainer' export function QuickPreviewRoot({ options, onRequestClose, children, }: { options?: QuickPreviewOptions onRequestClose: () => void children: React.ReactNode }) { // Read insets from context directly so a missing degrades // to zero insets instead of throwing. useSafeAreaInsets() would crash the host // app when no provider is mounted; the peek only needs insets to clear the // notch / home indicator, so zero is a safe fallback (provider still recommended). const insets = React.useContext(SafeAreaInsetsContext) const top = insets?.top ?? 0 const bottom = insets?.bottom ?? 0 const variant = options?.variant ?? 'popover' const dismissOnBackdropPress = options?.dismissOnBackdropPress ?? true const opacity = useSharedValue(0) const cbs = React.useRef({ onOpenStart: options?.onOpenStart, onOpenEnd: options?.onOpenEnd, onCloseStart: options?.onCloseStart, onCloseEnd: options?.onCloseEnd, }) React.useEffect(() => { cbs.current = { onOpenStart: options?.onOpenStart, onOpenEnd: options?.onOpenEnd, onCloseStart: options?.onCloseStart, onCloseEnd: options?.onCloseEnd, } }, [options?.onOpenStart, options?.onOpenEnd, options?.onCloseStart, options?.onCloseEnd]) React.useEffect(() => { cbs.current.onOpenStart?.() opacity.value = withTiming(1, { duration: 180 }, finished => { if (finished) cbs.current.onOpenEnd?.() }) return () => { cbs.current.onCloseStart?.() cbs.current.onCloseEnd?.() } // run once (mount-only effect) }, []) const containerStyle = useAnimatedStyle(() => ({ opacity: opacity.value })) return ( {variant === 'sheet' ? ( {children} ) : ( {children} )} ) }