import BottomSheet, { BottomSheetBackdrop, BottomSheetBackdropProps, } from "@gorhom/bottom-sheet"; import React, { ReactNode, useCallback, useEffect, useMemo, useRef, useState, } from "react"; import { BackHandler, StyleSheet } from "react-native"; import Animated, { FadeIn, FadeOut } from "react-native-reanimated"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { BottomSheetStackContext, BottomSheetStackItem, } from "./BottomSheetStackContext"; export const BottomSheetStackProvider: React.FC<{ children: ReactNode }> = ({ children, }) => { const [stack, setStack] = useState([]); const sheetRef = useRef(null); const { top } = useSafeAreaInsets(); const push = useCallback((item: BottomSheetStackItem) => { setStack((prev) => [...prev, item]); }, []); const clear = useCallback(() => { setStack([]); }, []); const pop = useCallback(() => { setStack((prev) => prev.slice(0, -1)); }, []); const replace = useCallback((item: BottomSheetStackItem) => { setStack([item]); }, []); const currentItem = useMemo(() => stack[stack.length - 1], [stack]); const canGoBack = stack.length > 1; const isOpen = stack.length > 0; useEffect(() => { if (stack === undefined || stack.length === 0) { sheetRef.current?.close(); } if (isOpen && currentItem) { sheetRef.current?.snapToIndex(currentItem.initialSnapIndex ?? 0); } const backHandlerSubscription = BackHandler.addEventListener( "hardwareBackPress", () => { if (canGoBack) { pop(); return true; } if (!canGoBack && stack.length === 1) { sheetRef.current?.close(); return true; } return false; } ); return () => backHandlerSubscription.remove(); }, [isOpen, canGoBack, currentItem, pop, stack]); const AnimatedView = Animated.View; const enteringAnimation = FadeIn.duration(200); const exitingAnimation = FadeOut.duration(200); const renderBackdrop = useCallback( (props: BottomSheetBackdropProps) => ( ), [] ); const contextValue = useMemo( () => ({ push, pop, replace, clear, }), [push, pop, replace, clear] ); return ( {children} {currentItem && ( {currentItem.component} )} ); }; const styles = StyleSheet.create({ animatedView: { flex: 1, }, });