diff --git a/docs/pages/2.theming.md b/docs/pages/2.theming.md index ffa81a3e3c..b8ebdbc20e 100644 --- a/docs/pages/2.theming.md +++ b/docs/pages/2.theming.md @@ -22,36 +22,36 @@ export default function Main() { } ``` -By default React Native Paper will apply the [Material Design 3 default theme](https://github.com/callstack/react-native-paper/blob/main/src/styles/themes/v3/LightTheme.tsx) if no `theme` or `version` prop is passed to to the `Provider`. +By default React Native Paper will apply the [Material You theme (MD3)](https://github.com/callstack/react-native-paper/blob/main/src/styles/themes/v3/LightTheme.tsx) if no `theme` or `version` prop is passed to to the `Provider`. -You can also provide a `theme` prop with a theme object with same properties as the default theme: +## Accessing theme properties + +Use the built-in `useTheme()` hook to get access to the theme's variables: ```js import * as React from 'react'; -import { MD3LightTheme as DefaultTheme, Provider as PaperProvider } from 'react-native-paper'; -import App from './src/App'; +import { useTheme } from 'react-native-paper'; -const theme = { - ...DefaultTheme, - roundness: 2, - version: 3, - colors: { - ...DefaultTheme.colors, - primary: '#3498db', - secondary: '#f1c40f', - tertiary: '#a1b2c3' - }, -}; +export default function PaymentScreen() { + const theme = useTheme(); -export default function Main() { - return ( - - - - ); + return ; } ``` +You can also use the `withTheme()` HOC exported from the library. If you wrap your component with the HOC, you'll receive the theme as a prop: + +```js +import * as React from 'react'; +import { withTheme } from 'react-native-paper'; + +function PaymentScreen({ theme }) { + return ; +} + +export default withTheme(PaymentScreen); +``` + ## Theme properties You can change the theme prop dynamically and all the components will automatically update to reflect the new theme. @@ -68,69 +68,69 @@ A theme usually contains the following properties: > The primary key color is used to derive roles for key components across the UI, such as the FAB, prominent buttons, active states, as well as the tint of elevated surfaces. - - `primary` - - `onPrimary` - - `primaryContainer` - - `onPrimaryContainer` + - `primary` + - `onPrimary` + - `primaryContainer` + - `onPrimaryContainer` > The secondary key color is used for less prominent components in the UI such as filter chips, while expanding the opportunity for color expression. - - `secondary` - - `onSecondary` - - `secondaryContainer` - - `onSecondaryContainer` + - `secondary` + - `onSecondary` + - `secondaryContainer` + - `onSecondaryContainer` - > The tertiary key color is used to derive the roles of contrasting accents that can be used to balance primary and secondary colors or bring heightened attention to an element. + > The tertiary key color is used to derive the roles of contrasting accents that can be used to balance primary and secondary colors or bring heightened attention to an element. > The tertiary color role is left for teams to use at their discretion and is intended to support broader color expression in products. - - `tertiary` - - `onTertiary` - - `tertiaryContainer` - - `onTertiaryContainer` + - `tertiary` + - `onTertiary` + - `tertiaryContainer` + - `onTertiaryContainer` > The neutral key color is used to derive the roles of surface and background, as well as high emphasis text and icons. - - `background` - - `onBackground` - - `surface` - - `onSurface` + - `background` + - `onBackground` + - `surface` + - `onSurface` > The neutral variant key color is used to derive medium emphasis text and icons, surface variants, and component outlines. - - `surfaceVariant` - - `onSurfaceVariant` - - `outline` + - `surfaceVariant` + - `onSurfaceVariant` + - `outline` > In addition to the accent and neutral key color, the color system includes a semantic color role for error - - `error` - - `onError` - - `errorContainer` - - `onErrorContainer` + - `error` + - `onError` + - `errorContainer` + - `onErrorContainer` > Surfaces at elevation levels 0-5 are tinted via color overlays based on the primary color, such as app bars or menus. The addition of a grade from 0-5 introduces tonal variation to the surface baseline. - - `elevation` (`object`) - - `level0` - transparent - - `level1` - 5% opacity - - `level2` - 8% opacity - - `level3` - 11% opacity - - `level4` - 12% opacity - - `level5` - 14% opacity + - `elevation` (`object`) + - `level0` - transparent + - `level1` - 5% opacity + - `level2` - 8% opacity + - `level3` - 11% opacity + - `level4` - 12% opacity + - `level5` - 14% opacity > Colors for disabled state - - `surfaceDisabled` - - `onSurfaceDisabled` - + - `surfaceDisabled` + - `onSurfaceDisabled` + > These additional role mappings exist in a scheme and are mapped to components where needed. - - `shadow` - - `inverseOnSurface` - - `inverseSurface` - - `inversePrimary` - - `backdrop` + - `shadow` + - `inverseOnSurface` + - `inverseSurface` + - `inversePrimary` + - `backdrop` - `fonts` (`object`): various fonts styling properties under the text variant key used in component. - [`variant` e.g. `labelMedium`] (`object`): @@ -154,7 +154,10 @@ Keeping your own properties in the theme is fully supported by our library: ```js import * as React from 'react'; -import { MD3LightTheme as DefaultTheme, Provider as PaperProvider } from 'react-native-paper'; +import { + MD3LightTheme as DefaultTheme, + Provider as PaperProvider, +} from 'react-native-paper'; import App from './src/App'; const theme = { @@ -164,7 +167,7 @@ const theme = { // Specify custom property in nested object colors: { myOwnColor: '#BADA55', - } + }, }; export default function Main() { @@ -268,28 +271,106 @@ export default function App() { ## TypeScript -By default extending the theme won't work well with TypeScript, but we can take advantage of `global augmentations` and specify the new properties that we added to the theme: +By default, TypeScript works well whenever you change the value of the built-in theme's properties. It gets more complicated when you want to extend the theme's properties or change their types. In order to fully support TypeScript, you will need to follow the guide that fits your use-case most accurately: + +There are two supported ways of overriding the theme: + +1. **Simple built-in theme overrides** - when you only customize the values and the whole theme schema remains the same +2. **Advanced theme overrides** - when you _add new properties_ or _change the built-in schema shape_ + +**Warning**: TypeScript support for withTheme is currently limited to Material You theme only. We are planning to provide a better support of handling custom theme overrides in future releases. + +### Simple built-in theme overrides + +You can provide a `theme` prop with a theme object with the same properties as the default theme: + +```js +import * as React from 'react'; +import { MD3LightTheme, Provider as PaperProvider } from 'react-native-paper'; +import App from './src/App'; + +const theme = { + ...MD3LightTheme, // or MD3DarkTheme + roundness: 2, + colors: { + ...MD3LightTheme.colors, + primary: '#3498db', + secondary: '#f1c40f', + tertiary: '#a1b2c3', + }, +}; + +export default function Main() { + return ( + + + + ); +} +``` + +### Advanced theme overrides + +If you need to modify the built-in theme schema by adding a new property or changing its type, you need to follow these steps: + +1. Pass your theme overrides to the Provider component + +```ts +import * as React from 'react'; +import { MD3LightTheme, Provider as PaperProvider } from 'react-native-paper'; +import App from './src/App'; + +const theme = { + ...MD3LightTheme, + + // Specify a custom property + custom: 'property', + + // Specify a custom property in nested object + colors: { + ...MD3LightTheme.colors, + brandPrimary: '#fefefe', + brandSecondary: 'red', + }, +}; + +export default function Main() { + return ( + + + + ); +} +``` + +2. Create a typed `useAppTheme()` hook in your project ```ts -// App.tsx import * as React from 'react'; import { - MD3LightTheme as DefaultTheme, + MD3LightTheme, Provider as PaperProvider, + useTheme, } from 'react-native-paper'; import App from './src/App'; const theme = { - ...DefaultTheme, - // Specify custom property - myOwnProperty: true, - // Specify custom property in nested object + ...MD3LightTheme, + + // Specify a custom property + custom: 'property', + + // Specify a custom property in nested object colors: { - myOwnColor: '#BADA55', + ...MD3LightTheme.colors, + brandPrimary: '#fefefe', + brandSecondary: 'red', }, }; -export type ThemeOverride = typeof theme; +export type AppTheme = typeof theme; + +export const useAppTheme = () => useTheme(); export default function Main() { return ( @@ -300,23 +381,28 @@ export default function Main() { } ``` +3. Start using the `useAppTheme()` hook across your components in the whole app + ```ts -// index.d.ts +import * as React from 'react'; +import { useAppTheme } from './App'; -import { ThemeOverride } from './src/App.tsx' +export default function HomeScreen() { + const { + colors: { brandPrimary }, + } = useAppTheme(); -declare global { - namespace ReactNativePaper { - interface Theme extends ThemeOverride - } + return ...; } ``` ## Material Design 2 -If you want to use previous versions of Material Design **we provide backwards support for older versions**. +Using Material Design 2 is **fully supported in React Native Paper v5+**. + +### Simple setup -In order to change the theme version, you can pass it as a prop to the `Provider` like so: +In order to use the Material Design 2 theme you can just pass `{ version: 2 }` to the PaperProvider theme prop: ```js import * as React from 'react'; @@ -334,72 +420,106 @@ export default function Main() { Specifying `{ version: 2 }` tells React Native Paper to use the built in Material Design 2 theme, so you don't have to fully extend it on your own. -### Typescript +### Advanced setup -You need to apply a global type change in a similar way how you would do that when [extending the theme](#typescript) +As with any theme, you can also specify your custom properties within the Material Design 2 theme: + +```js +import * as React from 'react'; +import { MD2LightTheme, Provider as PaperProvider } from 'react-native-paper'; +import App from './src/App'; -Instead of extending it, you can import the built in types for Material Design 2 like so: +export default function Main() { + const theme = { + ...MD2LightTheme, -```ts -// index.d.ts + // Specify a custom property + custom: 'property', -import { MD2Theme } from 'react-native-paper' + // Specify a custom nested property + colors: { + ...MD2LightTheme.colors, + primary: '#fefefe', + }, + }; -declare global { - namespace ReactNativePaper { - interface Theme extends MD2Theme - } + return ( + + + + ); } ``` -If you are migrating from Material Design 2 (4.x and lower) to Material You (5.x), please refer to our [Migration Guide](https://callstack.github.io/react-native-paper/introducing-v5-with-material-you.html) +### Typescript -## Applying a theme to a paper component +Due to the amount of changes in the theme's schema shape it falls into the [Advanced theme overrides](#advanced-theme-overrides) category. The steps are identical as with any advanced theme, just make sure to extend the built-in `MD2LightTheme` or `MD2DarkTheme` instead of `MD3LightTheme` or `MD3DarkTheme`. -If you want to change the theme for a certain component from the library, you can directly pass the `theme` prop to the component. The theme passed as the prop is merged with the theme from the `Provider`: +The final example for Material Design 2 would look like this: -```js +```ts import * as React from 'react'; -import { Button } from 'react-native-paper'; +import { + MD2LightTheme, + Provider as PaperProvider, + useTheme, +} from 'react-native-paper'; +import App from './src/App'; -export default function ButtonExample() { - return ( - - ); -} -``` +const theme = { + // Extend Material Design 2 theme -## Using the theme in your own components + ...MD2LightTheme, // or MD2DarkTheme -To access the theme in your own components, you can use the `withTheme` HOC exported from the library. If you wrap your component with the HOC, you'll receive the theme as a prop: + // Specify a custom property + myOwnProperty: true, -```js -import * as React from 'react'; -import { withTheme } from 'react-native-paper'; + // Specify a custom nested property + colors: { + ...MD2LightTheme.colors, + myOwnColor: '#BADA55', + }, +}; + +export type AppTheme = typeof theme; -function MyComponent(props) { - const { colors } = props.theme; +export const useAppTheme = () => useTheme(); - return Yo!; +export default function Main() { + return ( + + + + ); } -export default withTheme(MyComponent); +// App.tsx + +export default function App() { + const { theme } = useAppTheme(); + + return ; +} ``` -Components wrapped with `withTheme` support the theme from the `Provider` as well as from the `theme` prop. +### Migrating to Material You + +If you are migrating from Material Design 2 (4.x and lower) to Material You (5.x), please refer to our [Migration Guide](https://callstack.github.io/react-native-paper/introducing-v5-with-material-you.html) -You can also use the `useTheme` hook: +## Applying a theme to a paper component + +If you want to change the theme for a certain component from the library, you can directly pass the `theme` prop to the component. The theme passed as the prop is merged with the theme from the `Provider`: ```js import * as React from 'react'; -import { useTheme } from 'react-native-paper'; - -function MyComponent(props) { - const { colors } = useTheme(); +import { Button } from 'react-native-paper'; - return Yo!; +export default function ButtonExample() { + return ( + + ); } ``` @@ -414,7 +534,12 @@ import * as React from 'react'; import { Button } from 'react-native-paper'; export default function FancyButton(props) { - return