123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124 |
- import * as React from 'react';
- import { StyleSheet, Dimensions } from 'react-native';
- import NativeSafeAreaView from './NativeSafeAreaView';
- import { EdgeInsets, InsetChangedEvent, Metrics, Rect } from './SafeArea.types';
-
- export const SafeAreaInsetsContext = React.createContext<EdgeInsets | null>(
- null,
- );
-
- export const SafeAreaFrameContext = React.createContext<Rect | null>(null);
-
- export interface SafeAreaViewProps {
- children?: React.ReactNode;
- initialMetrics?: Metrics | null;
- /**
- * @deprecated
- */
- initialSafeAreaInsets?: EdgeInsets | null;
- }
-
- export function SafeAreaProvider({
- children,
- initialMetrics,
- initialSafeAreaInsets,
- }: SafeAreaViewProps) {
- const parentInsets = useParentSafeAreaInsets();
- const parentFrame = useParentSafeAreaFrame();
- const [insets, setInsets] = React.useState<EdgeInsets | null>(
- initialMetrics?.insets ?? initialSafeAreaInsets ?? parentInsets ?? null,
- );
- const [frame, setFrame] = React.useState<Rect>(
- initialMetrics?.frame ??
- parentFrame ?? {
- // Backwards compat so we render anyway if we don't have frame.
- x: 0,
- y: 0,
- width: Dimensions.get('window').width,
- height: Dimensions.get('window').height,
- },
- );
- const onInsetsChange = React.useCallback((event: InsetChangedEvent) => {
- // Backwards compat with old native code that won't send frame.
- if (event.nativeEvent.frame != null) {
- setFrame(event.nativeEvent.frame);
- }
- setInsets(event.nativeEvent.insets);
- }, []);
-
- return (
- <NativeSafeAreaView style={styles.fill} onInsetsChange={onInsetsChange}>
- {insets != null ? (
- <SafeAreaFrameContext.Provider value={frame}>
- <SafeAreaInsetsContext.Provider value={insets}>
- {children}
- </SafeAreaInsetsContext.Provider>
- </SafeAreaFrameContext.Provider>
- ) : null}
- </NativeSafeAreaView>
- );
- }
-
- const styles = StyleSheet.create({
- fill: { flex: 1 },
- });
-
- function useParentSafeAreaInsets(): EdgeInsets | null {
- return React.useContext(SafeAreaInsetsContext);
- }
-
- function useParentSafeAreaFrame(): Rect | null {
- return React.useContext(SafeAreaFrameContext);
- }
-
- export function useSafeAreaInsets(): EdgeInsets {
- const safeArea = React.useContext(SafeAreaInsetsContext);
- if (safeArea == null) {
- throw new Error(
- 'No safe area insets value available. Make sure you are rendering `<SafeAreaProvider>` at the top of your app.',
- );
- }
- return safeArea;
- }
-
- export function useSafeAreaFrame(): Rect {
- const frame = React.useContext(SafeAreaFrameContext);
- if (frame == null) {
- throw new Error(
- 'No safe area frame value available. Make sure you are rendering `<SafeAreaProvider>` at the top of your app.',
- );
- }
- return frame;
- }
-
- export function withSafeAreaInsets<T>(
- WrappedComponent: React.ComponentType<T>,
- ) {
- return (props: T) => (
- <SafeAreaConsumer>
- {(insets) => <WrappedComponent {...props} insets={insets} />}
- </SafeAreaConsumer>
- );
- }
-
- /**
- * @deprecated
- */
- export function useSafeArea(): EdgeInsets {
- return useSafeAreaInsets();
- }
-
- /**
- * @deprecated
- */
- export function SafeAreaConsumer(
- props: React.ComponentProps<typeof SafeAreaInsetsContext.Consumer>,
- ) {
- return <SafeAreaInsetsContext.Consumer {...props} />;
- }
-
- /**
- * @deprecated
- */
- export const SafeAreaContext = SafeAreaInsetsContext;
|