import React from 'react' import { View, StyleSheet } from 'react-native' import Animated, { Easing, useAnimatedStyle, useSharedValue, withTiming, runOnJS } from 'react-native-reanimated' import { Gesture, GestureDetector } from 'react-native-gesture-handler' import type { QuickPreviewOptions } from '../../types' import { resolveSizeStyle } from '../resolveSize' export function SheetContainer({ children, options, insets, onRequestClose, }: { children: React.ReactNode options?: QuickPreviewOptions insets: { top: number; bottom: number } onRequestClose: () => void }) { const translateY = useSharedValue(1000) const dismissOnPanDown = options?.dismissOnPanDown ?? true React.useEffect(() => { // Smooth slide up, no spring bounce. translateY.value = withTiming(0, { duration: 300, easing: Easing.out(Easing.cubic) }) }, [translateY]) const pan = Gesture.Pan() .onUpdate((e) => { if (!dismissOnPanDown) return translateY.value = Math.max(0, e.translationY) }) .onEnd((e) => { const shouldClose = e.velocityY > 1000 || translateY.value > 140 if (shouldClose) { translateY.value = withTiming(800, { duration: 200 }, (finished) => { if (finished) runOnJS(onRequestClose)() }) } else { translateY.value = withTiming(0, { duration: 240, easing: Easing.out(Easing.cubic) }) } }) const style = useAnimatedStyle(() => ({ transform: [{ translateY: translateY.value }], })) const sizeStyle = resolveSizeStyle(options?.size) return ( {children} ) } const styles = StyleSheet.create({ sheet: { position: 'absolute', left: 0, right: 0, bottom: 0, borderTopLeftRadius: 16, borderTopRightRadius: 16, paddingTop: 8, backgroundColor: 'white', overflow: 'hidden', elevation: 3, }, grabber: { alignSelf: 'center', width: 40, height: 4, borderRadius: 2, backgroundColor: 'rgba(0,0,0,0.2)', marginBottom: 8, }, })