WadhahEssam / react-native-theme-switch-animation

A Plug & Play Animations for Switching (Dark/Light) Themes. 🌖
MIT License
327 stars 21 forks source link

Modal appears not to be in the 'screen shot' when switching theme #14

Closed mvolonnino closed 4 weeks ago

mvolonnino commented 1 month ago

https://github.com/user-attachments/assets/01dfa852-2838-4bab-9f5d-619dd684644e

https://github.com/user-attachments/assets/ef7f36a1-1197-4aba-90ef-838eb0a24302

Code sample:

import { useEffect } from 'react';
import { Appearance, useColorScheme } from 'react-native';
import { useTheme as useTamaguiTheme, type ThemeName } from 'tamagui';
import switchTheme from 'react-native-theme-switch-animation';
import AsyncStorage from '@react-native-async-storage/async-storage';

import { createWithEqualityFn, shallow, persist, createJSONStorage } from '@/lib/zustand';
import track from '@/constants/track';
import { injectTamaguiTheme } from './navigation/theme';
import { DarkTheme, LightTheme } from './navigation/Colors';

export type ColorMode = 'light' | 'dark' | 'system';

interface ThemeStore {
  themeName: ThemeName;
  colorMode: ColorMode;
  /* ---------------- actions ---------------- */
  setThemeName: (themeName: ThemeName) => void;
  setColorMode: (colorMode: ColorMode) => void;
}

const useThemeStore = createWithEqualityFn<ThemeStore>()(
  persist(
    set => ({
      themeName: track.variant === 'nightly' ? 'purple' : 'blue',
      colorMode: 'system',
      setThemeName: themeName => set({ themeName }),
      setColorMode: colorMode => {
        switchTheme({
          switchThemeFunction: () => {
            set({ colorMode });
            Appearance.setColorScheme(colorMode === 'system' ? null : colorMode);
          },
          animationConfig: {
            type: 'fade',
            duration: 400,
          },
        });
      },
    }),
    {
      name: 'theme-store',
      storage: createJSONStorage(() => AsyncStorage),
      version: 4,
    }
  ),
  shallow
);

export default useThemeStore;

/**
 * Hook that utilizes the `useColorScheme` & `useThemeStore` to return the correct app color mode & current theme name
 */
export const useTheming = () => {
  const appearance = useColorScheme();
  const { colorMode, themeName } = useThemeStore(s => ({
    colorMode: s.colorMode,
    themeName: s.themeName,
  }));

  return {
    colorMode: colorMode === 'system' ? appearance! : colorMode,
    themeName,
  };
};

/** Hook to get the Native Theme injected with selected Tamagui Theme */
export const useNavigationTheming = () => {
  const { colorMode } = useTheming();
  const tamaguiTheme = useTamaguiTheme();

  const navigationTheme = colorMode === 'dark' ? DarkTheme : LightTheme;
  const nativeTheme = injectTamaguiTheme(tamaguiTheme, navigationTheme);

  return nativeTheme;
};

/**
 * Need to sync the appearance with the color mode on first launch as Tamagui components seem to hook into the appearance no matter what...
 */
export const useSyncAppearance = () => {
  useEffect(function syncAppearance() {
    const { colorMode } = useThemeStore.getState();
    if (colorMode === 'system') return;

    // sync appearance with the color mode
    Appearance.setColorScheme(colorMode);
  }, []);
};

If i remove the modal and make it an inline component (modal meaning that it appears above the bottom tabs as you can see) then it works as expected and the modal doesnt disappear.

Im thinking it has something to do with how Tamagui (react native) renders a modal/hierarchy

Let me know if you have any ideas.

Here are deps:

"dependencies": {
    "@dotlottie/react-player": "^1.6.19",
    "@expo/vector-icons": "^14.0.0",
    "@gorhom/bottom-sheet": "^4",
    "@react-native-async-storage/async-storage": "1.23.1",
    "@react-navigation/native": "^6.0.2",
    "@supabase/supabase-js": "^2.44.3",
    "@tamagui/animations-moti": "1.108.1",
    "@tamagui/animations-react-native": "1.108.1",
    "@tamagui/babel-plugin": "1.108.1",
    "@tamagui/config": "1.108.1",
    "@tamagui/lucide-icons": "1.108.1",
    "@tamagui/metro-plugin": "1.108.1",
    "@tamagui/theme-builder": "1.108.1",
    "@tamagui/toast": "1.108.1",
    "burnt": "^0.12.2",
    "dayjs": "^1.11.12",
    "dotenv": "^16.4.5",
    "expo": "~51.0.26",
    "expo-build-properties": "~0.12.5",
    "expo-dev-client": "~4.0.22",
    "expo-font": "~12.0.9",
    "expo-haptics": "~13.0.1",
    "expo-image": "~1.12.13",
    "expo-linear-gradient": "~13.0.2",
    "expo-linking": "~6.3.1",
    "expo-router": "~3.5.21",
    "expo-splash-screen": "~0.27.5",
    "expo-status-bar": "~1.12.1",
    "expo-system-ui": "~3.0.7",
    "expo-updates": "~0.25.22",
    "expo-web-browser": "~13.0.3",
    "inquirer": "^10.1.7",
    "lottie-react-native": "6.7.2",
    "moti": "^0.29.0",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-native": "0.74.5",
    "react-native-gesture-handler": "~2.16.1",
    "react-native-reanimated": "~3.10.1",
    "react-native-safe-area-context": "4.10.5",
    "react-native-screens": "3.31.1",
    "react-native-svg": "15.2.0",
    "react-native-theme-switch-animation": "^0.6.0",
    "react-native-url-polyfill": "^2.0.0",
    "react-native-web": "~0.19.10",
    "sonner": "^1.5.0",
    "tamagui": "1.108.1",
    "tinycolor2": "^1.6.0",
    "zod": "^3.23.8",
    "zustand": "^4.5.2"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0",
    "@eslint/eslintrc": "^3.1.0",
    "@eslint/js": "^9.8.0",
    "@types/react": "~18.2.45",
    "@types/tinycolor2": "^1.4.6",
    "eslint": "^8.57.0",
    "eslint-config-expo": "^7.1.2",
    "eslint-plugin-import": "^2.29.1",
    "jest": "^29.2.1",
    "jest-expo": "~51.0.3",
    "react-test-renderer": "18.2.0",
    "typescript": "~5.3.3"
  }
WadhahEssam commented 4 weeks ago

Thank you for the detailed issue, will be checking if I can expand the capture tree

WadhahEssam commented 4 weeks ago

can you try 0.8.0 release

and then do this

 switchTheme({
    switchThemeFunction: () => {
      set({ colorMode });
      Appearance.setColorScheme(colorMode === 'system' ? null : colorMode);
    },
    animationConfig: {
      type: 'fade',
      duration: 400,
    captureType: 'hierarchy' -> add this
    },
  });