-
-
Notifications
You must be signed in to change notification settings - Fork 238
Open
Labels
enhancementNew feature or requestNew feature or request
Description
Web color scheme is broken.
To make a working color scheme for web version of app without breaking native version, it requires to write an ugly work around like this:
// app/providers/ThemeProvider.tsx
import { DarkTheme, DefaultTheme, Theme, ThemeProvider as NavigationThemeProvider } from '@react-navigation/native';
import { StatusBar } from 'expo-status-bar';
import { Appearance, ColorSchemeName, Platform } from 'react-native';
import { NAV_THEME } from '~/lib/constants';
import { useColorScheme } from '~/lib/useColorScheme';
import { setAndroidNavigationBar } from '~/lib/android-navigation-bar';
import { isWeb } from '~/lib/utils';
import { ReactNode, useEffect, useLayoutEffect, useRef, useState } from 'react';
import { useThemeStore, Theme as StoreTheme } from '~/stores/theme-store';
import { SplashScreen } from 'expo-router';
import * as React from 'react';
SplashScreen.preventAutoHideAsync();
export function ThemeProvider({ children }: { children: ReactNode }) {
const { theme } = useThemeStore();
const hasMounted = React.useRef(false);
const { colorScheme, isDarkColorScheme, setColorScheme } = useColorScheme();
const [isColorSchemeLoaded, setIsColorSchemeLoaded] = React.useState(false);
useIsomorphicLayoutEffect(() => {
if (hasMounted.current) {
return;
}
if (isWeb) {
// Adds the background color to the html element to prevent white background on overscroll.
document.documentElement.classList.add('bg-background');
}
//This a hack to set color scheme from theme store, without setTimout it doesn't work
// TODO: Need to find a better way to handle this.
setTimeout(() => {
setColorScheme(theme);
setIsColorSchemeLoaded(true);
hasMounted.current = true;
if (!isWeb || theme !== 'system')
return;
handleColorSchemeChange(colorScheme, theme);
}, 10);
}, []);
useEffect(() => {
handleColorSchemeChange(colorScheme, theme);
}, [colorScheme]);
useEffect(() => {
if (!isColorSchemeLoaded || !hasMounted.current)
return;
// This is a hack to prevent the splash screen from auto-hiding before asset loading is complete.
// TODO: Need to find a better way to handle this.
const timeout = setTimeout(() => SplashScreen.hideAsync(), 10);
return () => clearTimeout(timeout);
}, [isColorSchemeLoaded]);
if (!isColorSchemeLoaded)
return null;
return (
<NavigationThemeProvider value={isDarkColorScheme ? DARK_THEME : LIGHT_THEME}>
<StatusBar style={isDarkColorScheme ? 'light' : 'dark'}/>
{children}
</NavigationThemeProvider>
);
}
const LIGHT_THEME: Theme = { ...DefaultTheme, colors: NAV_THEME.light };
const DARK_THEME: Theme = { ...DarkTheme, colors: NAV_THEME.dark };
const handleColorSchemeChange = (colorScheme: 'light' | 'dark', theme: StoreTheme) => {
setAndroidNavigationBar(colorScheme).then();
if (!isWeb || theme !== 'system')
return;
if (colorScheme === 'dark')
document.documentElement.classList.add('dark');
else if (colorScheme === 'light')
document.documentElement.classList.remove('dark');
};
const useIsomorphicLayoutEffect =
Platform.OS === 'web' && typeof window === 'undefined' ? useEffect : useLayoutEffect;
If anyone have any better idea, I would be glad to see it, because I can't find a better implementation but in the same time I don't like my variant
ivryb and luca1s
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request