Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a ThemeProvider component that allows overriding the theme behavior in shared components, enabling better testing support. The changes migrate theme-related code from the adapter/react-navigation directory to a new theme-provider directory, update component imports accordingly, and add a test component demonstrating the new functionality.
Changes:
- Introduce
ThemeProviderandThemeContextfor theme override functionality - Refactor
useThemeColorPallette()hook to support theme context override - Move theme definitions (
ScreensLightThemeandScreensDarkTheme) toColors.ts - Update all component imports to use the new theme provider hook location
- Add
TestThemeProvidertest component to demonstrate the feature
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| apps/src/shared/styling/theme-provider/ThemeContext.ts | New context definition for theme override |
| apps/src/shared/styling/theme-provider/ThemeProvider.tsx | New provider component for wrapping app sections with specific themes |
| apps/src/shared/styling/theme-provider/useColorPallette.ts | Refactored hook that checks context first before falling back to react-navigation theme |
| apps/src/shared/styling/Colors.ts | Updated to include theme definitions and new text property in ColorPallette type |
| apps/src/shared/ThemedText.tsx | Updated import and hook usage |
| apps/src/shared/ThemedTextInput.tsx | Updated hook usage and changed border color property from border to cardBorder |
| apps/src/shared/ThemedView.tsx | Updated import path |
| apps/src/shared/Alert.tsx | Updated import path |
| apps/src/tests/IssueTestsScreen.tsx | Updated import path for theme definitions |
| apps/src/tests/issue-tests/TestThemeProvider.tsx | New test component demonstrating ThemeProvider functionality |
| apps/src/tests/issue-tests/index.ts | Added export for new test component |
| apps/Example.tsx | Updated import path for theme definitions |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import { useTheme } from '@react-navigation/native'; | ||
|
|
||
| /** | ||
| * Requires `ThemeContext` (from react-navigation) presence. |
There was a problem hiding this comment.
The comment states that ThemeContext is from react-navigation, but it's actually a custom context defined in this codebase at ThemeContext.ts. This is misleading to developers reading this code.
There was a problem hiding this comment.
done, here's the latest version of that comment: 4ba07d9
| /** | ||
| * Requires `ThemeContext` (from react-navigation) presence. | ||
| * However, it is possible to override theme by wrapping part of the app in `ThemeProvider` and passing desired theme as a prop. | ||
| * Use this to get whole collor pallete current theme is based on. |
There was a problem hiding this comment.
Typo in documentation comment: "collor" should be "color".
kkafar
left a comment
There was a problem hiding this comment.
Hey, thanks!
I've left a couple of remarks. Let's resolve them before proceeding.
There was a problem hiding this comment.
The component we add with this PR isn't part of the library API, nor it relates to any particular reported bug. We usually don't add "test for testing code". If testing code does not work correctly -> tests for library API won't work as expected. This is sufficient for now. Also we shouldn't mix library API tests with other testing code.
tldr; let's remove this one
apps/src/shared/styling/Colors.ts
Outdated
| export const ScreensLightTheme = { | ||
| ...DefaultTheme, | ||
| colors: { | ||
| ...DefaultTheme.colors, | ||
| primary: LightColors.primary as string, | ||
| background: LightColors.background as string, | ||
| card: LightColors.cardBackground as string, | ||
| border: LightColors.cardBorder as string, | ||
| }, | ||
| }; | ||
|
|
||
| export const ScreensDarkTheme = { | ||
| ...DarkTheme, | ||
| colors: { | ||
| ...DarkTheme.colors, | ||
| primary: DarkColors.primary as string, | ||
| background: DarkColors.background as string, | ||
| card: DarkColors.cardBackground as string, | ||
| border: DarkColors.cardBorder as string, | ||
| }, | ||
| }; |
There was a problem hiding this comment.
These two shouldn't be moved here, right? They are indeed adapters for react-navigation & they should stay there. I'd be best to have react-navigation code separated as it were. Don't mix it here. Our goal is to decouple ourselves from react-navigation 😄
There was a problem hiding this comment.
Alright, I restored those changes via rebase
|
|
||
| export type ThemeName = 'light' | 'dark'; | ||
|
|
||
| export const ThemeContext = React.createContext<ThemeName | undefined>( |
There was a problem hiding this comment.
The theme values should be already in the payload. It's better than passing only a theme name.
There was a problem hiding this comment.
I want to also pay attention to naming of theme-provider module here. It's not limited to provider. It also exposes other utilities. Simple theme would be better and not misleading.
There was a problem hiding this comment.
done: 972d1fc
I was also wondering if placing Theme-related types and constants in Colors.ts is a good idea or we should keep that in another file in theme directory
| import { ThemeContext } from './ThemeContext'; | ||
| import type { ThemeName } from './ThemeContext'; | ||
| import { ColorPallette, DarkColors, LightColors } from '../Colors'; | ||
| import { useTheme } from '@react-navigation/native'; |
There was a problem hiding this comment.
We don't wanna import directly from react-navigation here. Go via adapter.
There was a problem hiding this comment.
now the only added react-navigation import in this commit is in adapter/react-navigation/useReactNavigationTheme.ts: 5b37ce9
| export default function useThemeColorPallette(): { | ||
| theme: ThemeName; | ||
| colors: ColorPallette; | ||
| } { | ||
| const navigationTheme = useTheme(); | ||
| let theme: ThemeName = navigationTheme.dark ? 'dark' : 'light'; | ||
|
|
||
| const providedTheme = React.useContext(ThemeContext); | ||
| if (providedTheme !== undefined) { | ||
| theme = providedTheme; | ||
| } | ||
| return { | ||
| theme: theme, | ||
| colors: theme === 'dark' ? DarkColors : LightColors, | ||
| }; | ||
| } |
There was a problem hiding this comment.
IIRC we described it a bit differently during the meeting.
- Our theme context should be prioritised.
- We should use
react-navigationtheme only if our context is not present. - As you can not call the hooks conditionally, then in adapter we should add our custom implementation of
react-navigation#useTheme, e.g.useReactNavigationThemeand use it here. The difference here would be that our implementation wouldn't crash, so it'd be safe to use unconditionally.
Replace direct useTheme (react-navigation) usage in themed components with useThemeColorPallette hook that supports local overrides via new ThemeProvider. Add text color to ColorPallette type and light/dark palettes. Remove old adapter/react-navigation/useColorPallette in favor of new theme-provider module.
it returns theme based on useTheme if useTheme throws an error, it is caught, a proper message is logged and DefaultTheme is returned
…, fix misspelling (pallette -> palette) also added LightTheme and DarkTheme and Theme type to Colors.ts, also moved ThemeName into this file useReactNavigation theme now returns undefined when useTheme throws an error if both useTheme and ThemeProvider don't provide us a theme, then useThemeColorPalette returns LightTheme as a default
useReactNavigationTheme works similar to useTheme though, but instead of throwing error when theme is null, it returns undefined
fdac2a1 to
5b37ce9
Compare
Description
Some of our shared components relied on
useTheme()from react-navigation. This PR introducesThemeProviderthat allows to override this behaviour inuseThemeColorPallette().Closes https://github.com/software-mansion/react-native-screens-labs/issues/1100
Changes
ThemeProvider.tsxandThemeContext.tsuseThemeColorPallette()accordingly to description aboveScreensLightThemeandScreensDarkThemetoColors.tsasadapter/react-navigationdirectory is deletedTestThemeProvider.tsxAfter - visual documentation
iOSThemeProvider.mov
AndroidThemeProvider.mov
Test plan
Run
TestThemeProviderand change system theme.Checklist