Skip to content

Commit d51258f

Browse files
committed
feat: add dynamicColor prop and DynamicTheme refactor
1 parent a9ec233 commit d51258f

10 files changed

Lines changed: 510 additions & 495 deletions

File tree

src/babel/__fixtures__/rewrite-imports/code.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,4 @@ import {
1010
NonExistentSecond as Stuff,
1111
ThemeProvider,
1212
withTheme,
13-
DefaultTheme,
1413
} from 'react-native-paper';

src/babel/__fixtures__/rewrite-imports/output.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,3 @@ import { MD3Colors } from "react-native-paper/lib/module/deprecated";
88
import { NonExistent, NonExistentSecond as Stuff } from "react-native-paper/lib/module/index.js";
99
import { ThemeProvider } from "react-native-paper/lib/module/core/theming";
1010
import { withTheme } from "react-native-paper/lib/module/core/theming";
11-
import { DefaultTheme } from "react-native-paper/lib/module/core/theming";

src/components/__tests__/TextInput.test.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import { I18nManager, Platform, StyleSheet, Text, View } from 'react-native';
44

55
import { fireEvent, render } from '@testing-library/react-native';
66

7-
import { DefaultTheme, getTheme, ThemeProvider } from '../../core/theming';
7+
import { getTheme, ThemeProvider } from '../../core/theming';
88
import { red500 } from '../../theme/colors';
9+
import { LightTheme } from '../../theme/schemes';
910
import { tokens } from '../../theme/tokens';
1011
import {
1112
getFlatInputColors,
@@ -368,9 +369,9 @@ it('calls onLayout on right-side affix adornment', () => {
368369
it("correctly applies theme background to label when input's background is transparent", () => {
369370
const backgroundColor = 'transparent';
370371
const theme = {
371-
...DefaultTheme,
372+
...LightTheme,
372373
colors: {
373-
...DefaultTheme.colors,
374+
...LightTheme.colors,
374375
background: 'pink',
375376
},
376377
};

src/core/PaperProvider.tsx

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,34 +11,45 @@ import { useSystemColorScheme } from './useSystemColorScheme';
1111
import MaterialCommunityIcon from '../components/MaterialCommunityIcon';
1212
import PortalHost from '../components/Portal/PortalHost';
1313
import { ReduceMotionContext } from '../theme/accessibility/ReduceMotionContext';
14+
import {
15+
isDynamicColorSupported,
16+
lightDynamicColors,
17+
darkDynamicColors,
18+
} from '../theme/schemes/DynamicTheme';
1419
import type { Theme, ThemeProp } from '../types';
1520

1621
export type Props = {
1722
children: React.ReactNode;
1823
theme?: ThemeProp;
1924
settings?: Settings;
2025
reduceMotion?: ReduceMotionPreference;
26+
dynamicColor?: boolean;
2127
};
2228

2329
const PaperProvider = (props: Props) => {
24-
const { reduceMotion = 'auto' } = props;
30+
const { reduceMotion = 'auto', dynamicColor = false } = props;
2531

2632
const colorScheme = useSystemColorScheme(!props.theme);
2733
const resolvedReduceMotion = useResolvedReduceMotion(reduceMotion);
2834

2935
const theme = React.useMemo<Theme>(() => {
30-
const scheme = colorScheme === 'dark' ? 'dark' : 'light';
31-
const base = defaultThemes[scheme];
32-
const userScale = props.theme?.animation?.scale ?? 1;
36+
const isDark = props.theme?.dark ?? colorScheme === 'dark';
37+
const base = defaultThemes[isDark ? 'dark' : 'light'];
38+
const dynamicColors =
39+
dynamicColor && isDynamicColorSupported
40+
? isDark
41+
? darkDynamicColors
42+
: lightDynamicColors
43+
: undefined;
44+
const scale = resolvedReduceMotion ? 0 : props.theme?.animation?.scale ?? 1;
45+
3346
return {
3447
...base,
3548
...props.theme,
36-
animation: {
37-
...props.theme?.animation,
38-
scale: resolvedReduceMotion ? 0 : userScale,
39-
},
49+
colors: { ...base.colors, ...props.theme?.colors, ...dynamicColors },
50+
animation: { ...props.theme?.animation, scale },
4051
} as Theme;
41-
}, [colorScheme, props.theme, resolvedReduceMotion]);
52+
}, [colorScheme, props.theme, resolvedReduceMotion, dynamicColor]);
4253

4354
const { children, settings } = props;
4455

src/core/__tests__/PaperProvider.test.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,19 @@ describe('PaperProvider', () => {
213213
).toStrictEqual(0);
214214
});
215215

216+
it('leaves theme.colors unchanged when dynamicColor is true on an unsupported platform', async () => {
217+
mockAppearance();
218+
const { getByTestId } = render(
219+
<PaperProvider dynamicColor>
220+
<FakeChild />
221+
</PaperProvider>
222+
);
223+
// `isDynamicColorSupported` is false on the test platform → no color override.
224+
expect(getByTestId('provider-child-view').props.theme.colors.primary).toBe(
225+
LightTheme.colors.primary
226+
);
227+
});
228+
216229
it('should set Appearance listeners, if there is no theme', async () => {
217230
mockAppearance();
218231
const { getByTestId } = render(createProvider());

src/index.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ export {
44
useTheme,
55
withTheme,
66
ThemeProvider,
7-
DefaultTheme,
87
adaptNavigationTheme,
98
} from './core/theming';
109

src/theme/provider.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ import type { ComponentType } from 'react';
33
import { $DeepPartial, createTheming } from '@callstack/react-theme-provider';
44

55
import { DarkTheme, LightTheme } from './schemes';
6-
import type { InternalTheme, Theme, NavigationTheme } from '../types';
7-
8-
export const DefaultTheme = LightTheme;
6+
import type { Theme, NavigationTheme } from '../types';
97

108
export const {
119
ThemeProvider,
@@ -18,11 +16,11 @@ export function useTheme<T = Theme>(overrides?: $DeepPartial<T>) {
1816
}
1917

2018
export const useInternalTheme = (
21-
themeOverrides: $DeepPartial<InternalTheme> | undefined
22-
) => useAppTheme<InternalTheme>(themeOverrides);
19+
themeOverrides: $DeepPartial<Theme> | undefined
20+
) => useAppTheme<Theme>(themeOverrides);
2321

24-
export const withInternalTheme = <Props extends { theme: InternalTheme }, C>(
25-
WrappedComponent: ComponentType<Props & { theme: InternalTheme }> & C
22+
export const withInternalTheme = <Props extends { theme: Theme }, C>(
23+
WrappedComponent: ComponentType<Props & { theme: Theme }> & C
2624
) => withTheme<Props, C>(WrappedComponent);
2725

2826
export const defaultThemes = {

0 commit comments

Comments
 (0)