UNPKG

@oxyhq/services

Version:

OxyHQ Expo/React Native SDK — UI components, screens, and native features

174 lines (167 loc) 4.91 kB
"use strict"; import React, { useRef, useEffect, useCallback, useMemo } from 'react'; import { BackHandler, View, StyleSheet } from 'react-native'; import { useStore } from 'zustand'; import { getScreenComponent, isValidRoute } from "../navigation/routes.js"; import { useColorScheme } from "../hooks/useColorScheme.js"; import { Colors } from "../constants/theme.js"; import BottomSheet from "./BottomSheet.js"; import { bottomSheetStore, getState, showBottomSheet, closeBottomSheet, goBack, updateState } from "../navigation/bottomSheetManager.js"; import { jsx as _jsx } from "react/jsx-runtime"; /** * BottomSheetRouter - Navigation container for bottom sheet screens */ const BottomSheetRouter = ({ onScreenChange, onDismiss }) => { const sheetRef = useRef(null); const colorScheme = useColorScheme(); const colors = Colors[colorScheme ?? 'light']; const prevScreenRef = useRef(null); const { currentScreen, screenProps, currentStep, isOpen } = useStore(bottomSheetStore); const ScreenComponent = useMemo(() => currentScreen ? getScreenComponent(currentScreen) : null, [currentScreen]); // Notify screen changes useEffect(() => { if (prevScreenRef.current !== currentScreen) { onScreenChange?.(currentScreen); prevScreenRef.current = currentScreen; } }, [currentScreen, onScreenChange]); // Control visibility useEffect(() => { if (!sheetRef.current) return; if (isOpen) { sheetRef.current.present(); } else { sheetRef.current.dismiss(); } }, [isOpen]); // Android back button useEffect(() => { if (!isOpen) return; const handler = BackHandler.addEventListener('hardwareBackPress', () => { handleGoBack(); return true; }); return () => handler.remove(); }, [isOpen]); const navigate = useCallback((screen, props) => { if (!isValidRoute(screen)) { if (__DEV__) console.warn(`[BottomSheetRouter] Invalid route: ${screen}`); return; } showBottomSheet({ screen, props }); }, []); const handleGoBack = useCallback(() => { const state = getState(); // Try history first if (state.history.length > 0) { goBack(); return true; } // Try step back const step = state.currentStep ?? 0; if (step > 0) { updateState({ currentStep: step - 1, screenProps: { ...state.screenProps, initialStep: step - 1 } }); return true; } // Close closeBottomSheet(); return true; }, []); const canDismiss = useCallback(() => { const state = getState(); if (state.history.length > 0) return false; const step = state.currentStep ?? 0; return step <= 0; }, []); const handleDismissAttempt = useCallback(() => { if (!canDismiss()) { handleGoBack(); return false; } return true; }, [canDismiss, handleGoBack]); const handleDismiss = useCallback(() => { closeBottomSheet(); onDismiss?.(); }, [onDismiss]); const handleStepChange = useCallback(step => { const state = getState(); updateState({ currentStep: step, screenProps: { ...state.screenProps, initialStep: step } }); }, []); const scrollTo = useCallback((y, animated) => { sheetRef.current?.scrollTo(y, animated); }, []); const renderBackground = useCallback(props => /*#__PURE__*/_jsx(View, { style: [styles.background, { backgroundColor: colors.background }, props.style] }), [colors.background]); const screenPropsValue = useMemo(() => { const { initialStep: _, ...rest } = screenProps; return { navigate, goBack: handleGoBack, onClose: closeBottomSheet, onAuthenticated: closeBottomSheet, theme: colorScheme ?? 'light', currentScreen: currentScreen ?? undefined, initialStep: currentStep ?? screenProps?.initialStep, onStepChange: handleStepChange, scrollTo, ...rest }; }, [navigate, handleGoBack, colorScheme, currentScreen, currentStep, screenProps, handleStepChange, scrollTo]); return /*#__PURE__*/_jsx(BottomSheet, { ref: sheetRef, enablePanDownToClose: true, enableHandlePanningGesture: true, backgroundComponent: renderBackground, style: styles.container, onDismiss: handleDismiss, onDismissAttempt: handleDismissAttempt, children: ScreenComponent && currentScreen && /*#__PURE__*/_jsx(ScreenComponent, { ...screenPropsValue }) }); }; const styles = StyleSheet.create({ container: { maxWidth: 800, width: '100%', alignSelf: 'center', marginHorizontal: 'auto' }, background: { borderTopLeftRadius: 20, borderTopRightRadius: 20, overflow: 'hidden' } }); export default /*#__PURE__*/React.memo(BottomSheetRouter); //# sourceMappingURL=BottomSheetRouter.js.map