import * as React from 'react'; import { Animated, View, StyleSheet, StyleProp, ViewStyle } from 'react-native'; import { Props as HeaderContainerProps } from '../Header/HeaderContainer'; import Card from './Card'; import HeaderHeightContext from '../../utils/HeaderHeightContext'; import useTheme from '../../../utils/useTheme'; import { Route, Scene, Layout, StackHeaderMode, StackCardMode, TransitionPreset, } from '../../types'; type Props = TransitionPreset & { index: number; active: boolean; focused: boolean; closing: boolean; layout: Layout; gesture: Animated.Value; previousScene?: Scene>; scene: Scene>; safeAreaInsetTop: number; safeAreaInsetRight: number; safeAreaInsetBottom: number; safeAreaInsetLeft: number; cardOverlay?: (props: { style: StyleProp }) => React.ReactNode; cardOverlayEnabled?: boolean; cardShadowEnabled?: boolean; cardStyle?: StyleProp; getPreviousRoute: (props: { route: Route; }) => Route | undefined; getFocusedRoute: () => Route; renderHeader: (props: HeaderContainerProps) => React.ReactNode; renderScene: (props: { route: Route }) => React.ReactNode; onOpenRoute: (props: { route: Route }) => void; onCloseRoute: (props: { route: Route }) => void; onTransitionStart?: ( props: { route: Route }, closing: boolean ) => void; onTransitionEnd?: (props: { route: Route }, closing: boolean) => void; onPageChangeStart?: () => void; onPageChangeConfirm?: () => void; onPageChangeCancel?: () => void; gestureEnabled?: boolean; gestureResponseDistance?: { vertical?: number; horizontal?: number; }; gestureVelocityImpact?: number; mode: StackCardMode; headerMode: StackHeaderMode; headerShown?: boolean; headerTransparent?: boolean; headerHeight: number; onHeaderHeightChange: (props: { route: Route; height: number; }) => void; }; const EPSILON = 0.1; function CardContainer({ active, cardOverlay, cardOverlayEnabled, cardShadowEnabled, cardStyle, cardStyleInterpolator, closing, gesture, focused, gestureDirection, gestureEnabled, gestureResponseDistance, gestureVelocityImpact, getPreviousRoute, getFocusedRoute, mode, headerMode, headerShown, headerStyleInterpolator, headerTransparent, headerHeight, onHeaderHeightChange, index, layout, onCloseRoute, onOpenRoute, onPageChangeCancel, onPageChangeConfirm, onPageChangeStart, onTransitionEnd, onTransitionStart, previousScene, renderHeader, renderScene, safeAreaInsetBottom, safeAreaInsetLeft, safeAreaInsetRight, safeAreaInsetTop, scene, transitionSpec, }: Props) { React.useEffect(() => { onPageChangeConfirm?.(); }, [active, onPageChangeConfirm]); const handleOpen = () => { onTransitionEnd?.({ route: scene.route }, false); onOpenRoute({ route: scene.route }); }; const handleClose = () => { onTransitionEnd?.({ route: scene.route }, true); onCloseRoute({ route: scene.route }); }; const handleTransitionStart = ({ closing }: { closing: boolean }) => { if (active && closing) { onPageChangeConfirm?.(); } else { onPageChangeCancel?.(); } onTransitionStart?.({ route: scene.route }, closing); }; const insets = { top: safeAreaInsetTop, right: safeAreaInsetRight, bottom: safeAreaInsetBottom, left: safeAreaInsetLeft, }; const { colors } = useTheme(); const [pointerEvents, setPointerEvents] = React.useState<'box-none' | 'none'>( 'box-none' ); React.useEffect(() => { // `addListener` may not exist on web and older versions of React Native // @ts-ignore const listener = scene.progress.next?.addListener?.( ({ value }: { value: number }) => { setPointerEvents(value <= EPSILON ? 'box-none' : 'none'); } ); return () => { if (listener) { // @ts-ignore scene.progress.next?.removeListener?.(listener); } }; }, [pointerEvents, scene.progress.next]); return ( {renderScene({ route: scene.route })} {headerMode === 'screen' ? renderHeader({ mode: 'screen', layout, insets, scenes: [previousScene, scene], getPreviousRoute, getFocusedRoute, gestureDirection, styleInterpolator: headerStyleInterpolator, onContentHeightChange: onHeaderHeightChange, }) : null} ); } export default React.memo(CardContainer); const styles = StyleSheet.create({ container: { flex: 1, flexDirection: 'column-reverse', }, scene: { flex: 1, }, });