@oxyhq/services
Version:
174 lines (167 loc) • 4.91 kB
JavaScript
"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