import {useSafeArea} from '../../hooks/util/useSafeArea' /** @publicDocs */ export type Edge = 'top' | 'right' | 'bottom' | 'left' /** * A container that applies safe area insets as padding or margin, ensuring content is not hidden behind system UI such as the home indicator on iOS or the navigation bar on Android. * * You can pass in custom classes and styles just like a regular `div`, so we recommend using it in place of your usual top-level wrapper. * * When no `edges` prop is specified, all four edges are applied. If you only need a specific edge, for example a sticky footer, use `edges={["bottom"]}`. * @publicDocs */ export interface SafeAreaDocProps { /** Which edges to apply safe area insets to. Defaults to all edges. */ edges?: Edge[] /** Whether to apply insets as padding or margin. Defaults to 'padding'. */ mode?: 'padding' | 'margin' /** Additional CSS classes */ className?: string /** Additional inline styles */ style?: React.CSSProperties /** Content to render inside the safe area */ children?: React.ReactNode } const ALL_EDGES: Edge[] = ['top', 'right', 'bottom', 'left'] const CSS_VAR_MAP: {[key in Edge]: string} = { top: 'var(--safe-area-inset-top, 0px)', right: 'var(--safe-area-inset-right, 0px)', bottom: 'var(--safe-area-inset-bottom, 0px)', left: 'var(--safe-area-inset-left, 0px)', } const STYLE_KEY_MAP: {[key in 'padding' | 'margin']: {[edge in Edge]: string}} = { padding: { top: 'paddingTop', right: 'paddingRight', bottom: 'paddingBottom', left: 'paddingLeft', }, margin: { top: 'marginTop', right: 'marginRight', bottom: 'marginBottom', left: 'marginLeft', }, } /** * A container that applies safe area insets as padding or margin. * * Ensures content isn't hidden behind system UI (home indicator, * navigation bar, etc). * * Uses CSS custom properties (`--safe-area-inset-*`) injected by the * Shop app, which work reliably on both iOS and Android. * * Only applies inline padding/margin for edges where the safe area * inset is non-zero, so your Tailwind classes and styles are preserved * on edges that don't need safe area handling. * * @example * ```tsx * * * * ``` * * @example * ```tsx * *
Custom top/side padding, safe area bottom
*
* ``` */ export function SafeArea({ edges = ALL_EDGES, mode = 'padding', className, style: styleProp, children, }: SafeAreaDocProps) { const style: React.CSSProperties = {...styleProp} const keys = STYLE_KEY_MAP[mode] const insets = useSafeArea() for (const edge of edges) { if (insets?.[edge] > 0) { ;(style as any)[keys[edge]] = CSS_VAR_MAP[edge] } } return (
{children}
) }