Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions __tests__/config/navigationTheme.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { DefaultTheme } from "@react-navigation/native";
import { NAVIGATION_THEME } from "config/navigationTheme";
import { THEME } from "config/theme";

describe("NAVIGATION_THEME", () => {
it("uses the app's dark surface as the scene background", () => {
// React Navigation's Native Stack paints each screen's contentStyle with
// the theme's `colors.background` by default. If we don't override it, the
// light DefaultTheme background flashes through during transitions (most
// visibly as a white flicker at the iOS modal's rounded corners). The
// navigation theme must therefore match the app's dark surface.
expect(NAVIGATION_THEME.colors.background).toBe(
THEME.colors.background.default,
);
expect(NAVIGATION_THEME.colors.card).toBe(THEME.colors.background.default);
});

it("does not fall back to the light DefaultTheme background", () => {
expect(NAVIGATION_THEME.colors.background).not.toBe(
DefaultTheme.colors.background,
);
expect(NAVIGATION_THEME.dark).toBe(true);
});
});
2 changes: 2 additions & 0 deletions src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
import * as Sentry from "@sentry/react-native";
import { AuthErrorToastListener } from "components/AuthErrorToastListener";
import { initializeSentryLogger } from "config/logger";
import { NAVIGATION_THEME } from "config/navigationTheme";
import { RootStackParamList } from "config/routes";
import { initializeSentry } from "config/sentryConfig";
import { THEME } from "config/theme";
Expand Down Expand Up @@ -70,6 +71,7 @@ export const App = (): React.JSX.Element => {
<AuthErrorToastListener />
<NavigationContainer
ref={navigationRef}
theme={NAVIGATION_THEME}
onStateChange={onStateChange}
>
<AuthCheckProvider>
Expand Down
30 changes: 30 additions & 0 deletions src/config/navigationTheme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { DarkTheme, Theme } from "@react-navigation/native";
import { THEME } from "config/theme";

/**
* React Navigation theme for the app's top-level `<NavigationContainer>`.
*
* Without an explicit theme, React Navigation falls back to its light
* `DefaultTheme` (background `rgb(242, 242, 242)`). Native Stack uses the
* theme's `colors.background` as each screen's default `contentStyle`
* background, so that light native container shows through during transitions
* — most visibly as a white flicker at the iOS modal's rounded corners while a
* screen slides in horizontally. Painting the native scene background with the
* app's dark surface removes that flash for every navigator and every screen.
*
* The app forces dark mode (see `App.tsx`), so this extends `DarkTheme` and
* overrides the surface colors with the app's own background token.
*
* Kept in its own module (rather than `config/theme.ts`) so the design-token
* file stays free of the React Navigation dependency — `config/theme` is
* imported by nearly every component, and several component tests replace
* `@react-navigation/native` with an inline mock that omits `DarkTheme`.
*/
export const NAVIGATION_THEME: Theme = {
...DarkTheme,
colors: {
...DarkTheme.colors,
background: THEME.colors.background.default,
card: THEME.colors.background.default,
},
};
Loading