import {
DarkTheme,
DefaultTheme,
ThemeProvider as RNThemeProvider,
} from 'expo-router/react-navigation';
import { useMemo } from 'react';
import { useColorScheme } from '@/hooks/useColorScheme';
import { Colors } from '@/theme/colors';
import { Mode, ModeProvider, ModeStorage } from '@/providers/mode-provider';
type Props = {
children: React.ReactNode;
/** Supply to persist the theme choice across launches. Omit and it resets. */
storage?: ModeStorage;
storageKey?: string;
defaultMode?: Mode;
};
/**
* Mounts `ModeProvider` — the app-wide source of truth for light/dark/system —
* and maps the resolved scheme onto React Navigation's theme.
*
* The navigation half is a separate component because it calls
* `useColorScheme()`, which has to read that context from *inside* the provider.
*/
export const ThemeProvider = ({
children,
storage,
storageKey,
defaultMode,
}: Props) => (
{children}
);
const NavigationTheme = ({ children }: { children: React.ReactNode }) => {
const colorScheme = useColorScheme();
// Rebuilding this on every render invalidates every useTheme() consumer
// app-wide, since ThemeProvider is mounted at the root — memoize on the
// one thing it actually depends on, and only build the active theme.
const theme = useMemo(() => {
if (colorScheme === 'dark') {
return {
...DarkTheme,
colors: {
...DarkTheme.colors,
primary: Colors.dark.primary,
background: Colors.dark.background,
card: Colors.dark.card,
text: Colors.dark.text,
border: Colors.dark.border,
notification: Colors.dark.red,
},
};
}
return {
...DefaultTheme,
colors: {
...DefaultTheme.colors,
primary: Colors.light.primary,
background: Colors.light.background,
card: Colors.light.card,
text: Colors.light.text,
border: Colors.light.border,
notification: Colors.light.red,
},
};
}, [colorScheme]);
return {children};
};