1import BottomSheet, { 2 BottomSheetBackdrop, 3 BottomSheetView, 4 useBottomSheetDynamicSnapPoints, 5} from '@gorhom/bottom-sheet'; 6import React, { useCallback, useEffect, useMemo, useRef } from 'react'; 7import { StyleSheet, View } from 'react-native'; 8 9import DevMenuBottomSheetContext from './DevMenuBottomSheetContext'; 10import * as DevMenu from './DevMenuModule'; 11 12type Props = { 13 uuid: string; 14 children?: React.ReactNode; 15}; 16 17function DevMenuBottomSheet({ children, uuid }: Props) { 18 const bottomSheetRef = useRef<BottomSheet | null>(null); 19 20 const onCollapse = useCallback( 21 () => 22 new Promise<void>((resolve) => { 23 bottomSheetRef.current?.close(); 24 25 // still no way to wait for animation to end before the callback, so we wait for 300ms 26 setTimeout(() => { 27 resolve(); 28 DevMenu.closeAsync(); 29 }, 300); 30 }), 31 [] 32 ); 33 34 const onExpand = useCallback( 35 () => 36 new Promise<void>((resolve) => { 37 bottomSheetRef.current?.expand(); 38 setTimeout(() => { 39 resolve(); 40 }, 300); 41 }), 42 [] 43 ); 44 45 const onChange = useCallback((index: number) => { 46 if (index === -1) { 47 DevMenu.closeAsync(); 48 } 49 }, []); 50 51 const initialSnapPoints = useMemo(() => ['CONTENT_HEIGHT'], []); 52 53 useEffect(() => { 54 bottomSheetRef.current?.expand(); 55 }, [uuid]); 56 57 useEffect(() => { 58 const closeSubscription = DevMenu.listenForCloseRequests(() => { 59 bottomSheetRef.current?.collapse(); 60 return new Promise<void>((resolve) => { 61 resolve(); 62 }); 63 }); 64 return () => { 65 closeSubscription.remove(); 66 }; 67 }, []); 68 69 const { animatedHandleHeight, animatedSnapPoints, animatedContentHeight, handleContentLayout } = 70 useBottomSheetDynamicSnapPoints(initialSnapPoints); 71 72 return ( 73 <BottomSheet 74 key={uuid} 75 ref={bottomSheetRef} 76 backdropComponent={(props) => ( 77 <BottomSheetBackdrop {...props} opacity={0.5} appearsOnIndex={0} disappearsOnIndex={-1} /> 78 )} 79 handleComponent={null} 80 snapPoints={animatedSnapPoints} 81 handleHeight={animatedHandleHeight} 82 contentHeight={animatedContentHeight} 83 backgroundStyle={styles.bottomSheetBackground} 84 enablePanDownToClose 85 onChange={onChange}> 86 <DevMenuBottomSheetContext.Provider value={{ collapse: onCollapse, expand: onExpand }}> 87 <BottomSheetView style={styles.contentContainerStyle} onLayout={handleContentLayout}> 88 {children} 89 </BottomSheetView> 90 </DevMenuBottomSheetContext.Provider> 91 {/* Adds bottom offset so that no empty space is shown on overdrag */} 92 <View style={{ height: 100 }} /> 93 </BottomSheet> 94 ); 95} 96 97const styles = StyleSheet.create({ 98 bottomSheetContainer: { 99 flex: 1, 100 }, 101 contentContainerStyle: {}, 102 bottomSheetBackground: { 103 backgroundColor: '#f8f8fa', 104 }, 105}); 106 107export default DevMenuBottomSheet; 108