diff --git a/src/__tests__/native/safe-area-view.test.tsx b/src/__tests__/native/safe-area-view.test.tsx new file mode 100644 index 00000000..565d1a12 --- /dev/null +++ b/src/__tests__/native/safe-area-view.test.tsx @@ -0,0 +1,62 @@ +import { StyleSheet } from "react-native"; + +import { render, screen } from "@testing-library/react-native"; +import { SafeAreaView } from "react-native-css/components/react-native-safe-area-context"; +import { registerCSS } from "react-native-css/jest"; +import { SafeAreaView as OriginalSafeAreaView } from "react-native-safe-area-context"; + +// https://github.com/nativewind/react-native-css/issues/386 +describe("SafeAreaView from the safe-area-context shim", () => { + test("applies className as style", () => { + registerCSS(`.screen { flex: 1; background-color: red; }`); + + render(); + + const subject = screen.getByTestId("subject"); + expect(StyleSheet.flatten(subject.props.style)).toStrictEqual({ + flexBasis: "0%", + flexGrow: 1, + flexShrink: 1, + backgroundColor: "#f00", + }); + }); + + test("keeps its own props and an inline style next to className", () => { + registerCSS(`.screen { flex: 1; }`); + + render( + <> + + + , + ); + + const shim = screen.getByTestId("shim"); + const original = screen.getByTestId("original"); + + expect(StyleSheet.flatten(shim.props.style)).toStrictEqual({ + flexBasis: "0%", + flexGrow: 1, + flexShrink: 1, + opacity: 0.5, + }); + // Its own props reach the native component exactly as they do without the shim + expect(shim.props.edges).toBeDefined(); + expect(shim.props.edges).toStrictEqual(original.props.edges); + }); + + test("renders without a className", () => { + render(); + + expect(screen.getByTestId("subject")).toBeTruthy(); + }); +}); diff --git a/src/components/react-native-safe-area-context.native.tsx b/src/components/react-native-safe-area-context.native.tsx index 5370e809..e4857d19 100644 --- a/src/components/react-native-safe-area-context.native.tsx +++ b/src/components/react-native-safe-area-context.native.tsx @@ -1,17 +1,37 @@ import { useContext, useMemo, type PropsWithChildren } from "react"; +import { + useCssElement, + type StyledConfiguration, + type StyledProps, +} from "react-native-css"; import { VariableContext, VariableContextProvider, } from "react-native-css/native-internal"; import { SafeAreaProvider as OriginalSafeAreaProvider, + SafeAreaView as OriginalSafeAreaView, useSafeAreaInsets, type SafeAreaProviderProps, + type SafeAreaViewProps, } from "react-native-safe-area-context"; +import { copyComponentProperties } from "./copyComponentProperties"; + export * from "react-native-safe-area-context"; +const safeAreaViewMapping = { + className: "style", +} satisfies StyledConfiguration; + +export const SafeAreaView = copyComponentProperties( + OriginalSafeAreaView, + (props: StyledProps) => { + return useCssElement(OriginalSafeAreaView, props, safeAreaViewMapping); + }, +); + export function SafeAreaProvider({ children, ...props