import { useNavigation } from "@react-navigation/native"; import { NativeStackNavigationOptions } from "@react-navigation/native-stack"; import { useGetBottomTabBarHeight, useGetHeaderHeight } from "design-system/hooks/useGetNavigationHeights"; import { useInternalTheme } from "design-system/hooks/useInternalTheme"; import { AnimatedFlatListBox, AnimatedFlatListBoxProps, } from "design-system/primitives/Box/AnimatedFlatListBox"; import { AnimatedScrollViewBox, AnimatedScrollViewBoxProps, } from "design-system/primitives/Box/AnimatedScrollViewBox"; import { Box, BoxProps } from "design-system/primitives/Box/Box"; import { FlatListBox, FlatListBoxProps } from "design-system/primitives/Box/FlatListBox"; import { SafeAreaBox } from "design-system/primitives/Box/SafeAreaBox"; import { ScrollViewBox, ScrollViewBoxProps } from "design-system/primitives/Box/ScrollViewBox"; import { SectionListBox, SectionListBoxProps } from "design-system/primitives/Box/SectionListBox"; import { navigationRef } from "navigation/Navigation"; import React, { ForwardedRef, forwardRef, ReactNode, RefObject } from "react"; import { ReactElement, useLayoutEffect } from "react"; import { FlatList, ScrollView, SectionList, StyleSheet, View } from "react-native"; import Animated from "react-native-reanimated"; import { Edge, SafeAreaViewProps } from "react-native-safe-area-context"; export type ScreenBaseProps = { options?: NativeStackNavigationOptions; mode?: SafeAreaViewProps["mode"]; edges?: ReadonlyArray<"top" | "bottom">; backgroundComponent?: ReactElement | null; absolutePositionedTabBar?: boolean; }; type ScreenProps = ScreenBaseProps & ( | ({ as?: "View"; ref?: RefObject } & BoxProps) | ({ as: "ScrollView"; ref?: RefObject } & ScrollViewBoxProps) | ({ as: "AnimatedScrollView"; ref?: RefObject } & AnimatedScrollViewBoxProps) | ({ as: "FlatList"; ref?: RefObject } & FlatListBoxProps) | ({ as: "AnimatedFlatList"; ref?: RefObject> } & AnimatedFlatListBoxProps) | ({ as: "SectionList"; ref?: RefObject> } & SectionListBoxProps) ); interface ScreenComponentType { (props: ScreenProps, ref: ForwardedRef): JSX.Element; } const getNavigationOptions = () => { if (navigationRef.isReady()) { return navigationRef.getCurrentOptions() as Partial | undefined; } return {} as Partial; }; export const Screen = forwardRef(function Screen(p: ScreenProps, ref: ForwardedRef) { const { defaults } = useInternalTheme(); const navigation = useNavigation(); const combinedProps = { ...defaults.Screen, ...p }; const { options, mode, edges, backgroundComponent, backgroundColor, absolutePositionedTabBar, ...props } = combinedProps; useLayoutEffect(() => { if (options) { navigation.setOptions(options); } }, [navigation, options]); let headerHeight = useGetHeaderHeight(); let bottomTabHeight = useGetBottomTabBarHeight(); let customEdges = ["left", "right"] as Edge[]; if (headerHeight === 0) { customEdges.push("top"); } if (bottomTabHeight === 0) { customEdges.push("bottom"); } if (getNavigationOptions()?.headerTransparent !== true && options?.headerTransparent !== true) { headerHeight = 0; } if (!absolutePositionedTabBar) { bottomTabHeight = 0; } const edgeArray = edges ?? customEdges; const containerprops = { backgroundColor, backgroundComponent }; if (props.as === "ScrollView") { const { children, ...rest } = props; return ( {children} ); } if (props.as === "AnimatedScrollView") { const { children, ...rest } = props; return ( {children as ReactNode} ); } if (props.as === "FlatList") { let { children, ListHeaderComponent, ListFooterComponent, ...rest } = props; return ( <>{ListHeaderComponent} } ListFooterComponent={ <>{ListFooterComponent} } {...rest} /> ); } if (props.as === "AnimatedFlatList") { let { children, ListHeaderComponent, ListFooterComponent, ...rest } = props; return ( <>{ListHeaderComponent} } ListFooterComponent={ <>{ListFooterComponent} } {...rest} /> ); } if (props.as === "SectionList") { const { children, ListHeaderComponent, ListFooterComponent, ...rest } = props; return ( ref={ref} flex={1} ListHeaderComponent={ <>{ListHeaderComponent} } ListFooterComponent={ <>{ListFooterComponent} } {...rest} /> ); } if (!edgeArray?.length) { const { children, ...rest } = props; return ( {children} ); } const { children, ...rest } = props; return ( {children} ); }) as ScreenComponentType; function ScreenContainer({ backgroundColor, backgroundComponent, children, ...rest }: { backgroundComponent?: ReactElement | null; } & BoxProps) { return ( {!!backgroundComponent && {backgroundComponent}} {children} ); }