import {memo, useContext, useMemo} from 'react' import { type StyleProp, View, type ViewProps, type ViewStyle, } from 'react-native' import Animated, { type AnimatedRef, type AnimatedScrollViewProps, useAnimatedStyle, } from 'react-native-reanimated' import {useSafeAreaInsets} from 'react-native-safe-area-context' import {userStyle} from '#/lib/userstyles' import {useEnableMinimalShellModeForScreen} from '#/state/shell' import {useShellLayout} from '#/state/shell/shell-layout' import {useIsWithinSplitView} from '#/screens/Messages/components/splitView/context' import { atoms as a, useBreakpoints, useLayoutBreakpoints, useTheme, web, } from '#/alf' import {useDialogContext} from '#/components/Dialog' import { CENTER_COLUMN_OFFSET, CENTER_COLUMN_WIDTH, SCROLLBAR_OFFSET, } from '#/components/Layout/const' import {ScrollbarOffsetContext} from '#/components/Layout/context' import {IS_WEB} from '#/env' export * from '#/components/Layout/const' export * as Header from '#/components/Layout/Header' export type ScreenProps = React.ComponentProps & { style?: StyleProp noInsetTop?: boolean minimalShell?: boolean } /** * Outermost component of every screen */ export const Screen = memo(function Screen({ style, noInsetTop, minimalShell = false, ...props }: ScreenProps) { const {top} = useSafeAreaInsets() const {isWithinSplitView} = useIsWithinSplitView() useEnableMinimalShellModeForScreen({enabled: minimalShell}) return ( <> {IS_WEB && !isWithinSplitView && } ) }) export type ContentProps = AnimatedScrollViewProps & { style?: StyleProp contentContainerStyle?: StyleProp ignoreTabletLayoutOffset?: boolean ref?: AnimatedRef } /** * Default scroll view for simple pages */ export const Content = memo(function Content({ children, style, contentContainerStyle, ignoreTabletLayoutOffset, ref, ...props }: ContentProps) { const t = useTheme() const {footerHeight} = useShellLayout() const {isWithinSplitView} = useIsWithinSplitView() // note - if we ever make the footer transparent in any way, // we'll need to change this to use contentInsets/scrollIndicatorInsets // on iOS and contentContainerStyle padding on Android -sfn const animatedStyle = useAnimatedStyle(() => { return { marginBottom: footerHeight.get(), } }) return ( {IS_WEB ? (
{/* @ts-expect-error web only -esb */} {children}
) : ( children )}
) }) /** * Utility component to center content within the screen */ export const Center = memo(function LayoutCenter({ children, style, ignoreTabletLayoutOffset, ...props }: ViewProps & {ignoreTabletLayoutOffset?: boolean}) { const {isWithinOffsetView} = useContext(ScrollbarOffsetContext) const {gtMobile} = useBreakpoints() const {centerColumnOffset} = useLayoutBreakpoints() const {isWithinDialog} = useDialogContext() const {isWithinSplitView} = useIsWithinSplitView() const ctx = useMemo(() => ({isWithinOffsetView: true}), []) return ( {children} ) }) /** * Only used within `Layout.Screen`, not for reuse */ const WebCenterBorders = memo(function LayoutWebCenterBorders() { const t = useTheme() const {gtMobile} = useBreakpoints() const {centerColumnOffset} = useLayoutBreakpoints() return gtMobile ? ( ) : null })