Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/pchmn/expo-material3-theme
Manage Material 3 theme in your React Native App
https://github.com/pchmn/expo-material3-theme
android expo ios react-native
Last synced: about 2 hours ago
JSON representation
Manage Material 3 theme in your React Native App
- Host: GitHub
- URL: https://github.com/pchmn/expo-material3-theme
- Owner: pchmn
- License: mit
- Created: 2023-03-09T17:32:01.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-01-15T18:03:13.000Z (10 months ago)
- Last Synced: 2024-11-05T08:38:40.327Z (12 days ago)
- Topics: android, expo, ios, react-native
- Language: TypeScript
- Homepage:
- Size: 63.3 MB
- Stars: 79
- Watchers: 1
- Forks: 3
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
![image](https://user-images.githubusercontent.com/12658241/225726041-d086724a-9bef-49e1-a21b-2a91d5a3b5e9.png)
[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/pchmn/expo-material3-theme/blob/main/LICENSE)
[![npm latest package](https://img.shields.io/npm/v/@pchmn/expo-material3-theme/latest.svg)](https://www.npmjs.com/package/@pchmn/expo-material3-theme)
[![platform - android](https://img.shields.io/badge/platform-Android-3ddc84.svg?logo=android)](https://www.android.com)
[![platform - ios](https://img.shields.io/badge/platform-iOS-000.svg?logo=apple)](https://developer.apple.com/ios)Expo Material 3 Theme
This [expo module](https://docs.expo.dev/modules/overview/) allows you retrieve the [Material 3 dynamic theme](https://developer.android.com/develop/ui/views/theming/dynamic-colors) from Android 12+ devices, so that you can use it in your expo (or bare react-native) app.
For devices not compatible (iOS or older Android versions) a fallback theme is returned.
## ✨ Features
- Retrieve Material 3 dynamic theme from Android 12+ devices (or a fallback theme if device is not compatible)
- Generate Material 3 theme based on a source color (using [`@material/material-color-utilities`](https://github.com/material-foundation/material-color-utilities/tree/main/typescript))
- Material 3 theme compatible with [`react-native-paper`](https://callstack.github.io/react-native-paper/)
![example-android](docs/example-android.gif)
## Installation
### Installation in managed Expo projects
> This library works with Expo Go, but you won't be able to retrieve the system theme (you'll get a fallback theme) because it requires custom native code and Expo Go [doesn't support it](https://docs.expo.dev/workflow/customizing/)
```
npx expo install @pchmn/expo-material3-theme
```If you use development build, you'll have to rebuild development client (only android) after adding the library because it contains native code (https://docs.expo.dev/develop/development-builds/use-development-builds/#rebuild-a-development-build) :
```
npx expo prebuild --platform android
npx expo run:android
```### Installation in bare React Native projects
For bare React Native projects, you must ensure that you have [installed and configured the `expo` package](https://docs.expo.dev/bare/installing-expo-modules/) before continuing.
```sh
npx expo install @pchmn/expo-material3-theme
npx pod-install
```## Usage
### Retrieve system theme
A basic usage would be to retrieve the Material 3 theme from user device (or a fallback theme if not supported) by using `useMaterial3Theme` hook:
```tsx
import { useMaterial3Theme } from '@pchmn/expo-material3-theme';
import { useColorScheme, View, Button } from 'react-native';function App() {
const colorScheme = useColorScheme();
// If the device is not compatible, it will return a theme based on the fallback source color (optional, default to #6750A4)
const { theme } = useMaterial3Theme({ fallbackSourceColor: '#3E8260' });return (
Themed button
);
}
```### Use a custom theme
If you want to use a theme based on a specific color instead of the system theme, just pass the `sourceColor` param to `useMaterial3Theme` hook:
```tsx
import { useMaterial3Theme } from '@pchmn/expo-material3-theme';
import { useColorScheme, View, Button } from 'react-native';function App() {
const colorScheme = useColorScheme();
// Theme returned will be based on #3E8260 color
const { theme } = useMaterial3Theme({ sourceColor: '#3E8260' });return (
Themed button
);
}
```### Change theme
You may also want to update the theme by generating a new one, or go back to the default theme (to let users personalize your app for example). You can do it with `useMaterial3Theme` hook:
```tsx
import { useMaterial3Theme } from '@pchmn/expo-material3-theme';
import { useColorScheme, View, Button } from 'react-native';function App() {
const colorScheme = useColorScheme();
const { theme, updateTheme, resetTheme } = useMaterial3Theme();return (
{/* Update theme by generating a new one based on #3E8260 color */}
updateTheme('#3E8260')}>Update theme
{/* Reset theme to default (system or fallback) */}
resetTheme()}>Reset theme
);
}
```> ℹ️ `updateTheme()` and `resetTheme()` will change the theme returned by `useMaterial3Theme()`, it will not change theme at system level
### Usage with `react-native-paper`
#### Basic example
`@pchmn/expo-material3-theme` provides a theme compatible with `react-native-paper`, so you can combine both libraries easily:```tsx
import { useMaterial3Theme } from '@pchmn/expo-material3-theme';
import { useMemo } from 'react';
import { useColorScheme } from 'react-native';
import { Button, MD3DarkTheme, MD3LightTheme, Provider as PaperProvider } from 'react-native-paper';function App() {
const colorScheme = useColorScheme();
const { theme } = useMaterial3Theme();const paperTheme = useMemo(
() =>
colorScheme === 'dark' ? { ...MD3DarkTheme, colors: theme.dark } : { ...MD3LightTheme, colors: theme.light },
[colorScheme, theme]
);return (
Themed react native paper button
);
}
```#### Advanced usage
Override
react-native-paper
theme (Typescript)
Some [colors](https://github.com/pchmn/expo-material3-theme/blob/main/src/ExpoMaterial3Theme.types.ts#L54-L61) present in `Material3Theme` from this library are not present in `MD3Theme` of `react-native-paper`. You can create a typed `useAppTheme()` hook and use it instead of `useTheme()` hook to fix this :
```ts
import { Material3Scheme } from '@pchmn/expo-material3-theme';
import { MD3Theme, useTheme } from 'react-native-paper';export const useAppTheme = useTheme;
// Now use useAppTheme() instead of useTheme()
```Create a
Material3ThemeProvider
that includesPaperProvider
```tsx
// Material3ThemeProvider.tsx
import { Material3Scheme, Material3Theme, useMaterial3Theme } from '@pchmn/expo-material3-theme';
import { createContext, useContext } from 'react';
import { useColorScheme } from 'react-native';
import {
MD3DarkTheme,
MD3LightTheme,
MD3Theme,
Provider as PaperProvider,
ProviderProps,
useTheme,
} from 'react-native-paper';type Material3ThemeProviderProps = {
theme: Material3Theme;
updateTheme: (sourceColor: string) => void;
resetTheme: () => void;
};const Material3ThemeProviderContext = createContext({} as Material3ThemeProviderProps);
export function Material3ThemeProvider({
children,
sourceColor,
fallbackSourceColor,
...otherProps
}: ProviderProps & { sourceColor?: string; fallbackSourceColor?: string }) {
const colorScheme = useColorScheme();const { theme, updateTheme, resetTheme } = useMaterial3Theme({
sourceColor,
fallbackSourceColor,
});const paperTheme =
colorScheme === 'dark' ? { ...MD3DarkTheme, colors: theme.dark } : { ...MD3LightTheme, colors: theme.light };return (
{children}
);
}export function useMaterial3ThemeContext() {
const ctx = useContext(Material3ThemeProviderContext);
if (!ctx) {
throw new Error('useMaterial3ThemeContext must be used inside Material3ThemeProvider');
}
return ctx;
}export const useAppTheme = useTheme;
// App.tsx
import { Material3ThemeProvider, useAppTheme, useMaterial3ThemeContext } from '../Material3ThemeProvider';
import { View, Button } from 'react-native';function App() {
return (
)
}function AppContent() {
const { updateTheme, resetTheme } = useMaterial3ThemeContext();
// react-native-paper theme is always in sync
const theme = useAppTheme();return (
{/* Update theme by generating a new one based on #3E8260 color */}
updateTheme('#3E8260')}>Update theme
{/* Reset theme to default (system or fallback) */}
resetTheme()}>Reset theme
);
}
```## Example
You can see an example app in the [`/example`](./example/) folder.
### Android example
Extract [zip file](docs/example-apps.zip), and install `expo-material3-theme-example-android.apk` on your device.
### iOS example
This is a file for iOS simulator. Extract [zip file](docs/example-apps.zip), and drag and drop `expo-material3-theme-example-ios` into your emulator.
## [API Reference](docs/API.md)
- [`useMaterial3Theme`](docs/API.md#usematerial3theme)
- [`getMaterial3Theme`](docs/API.md#getmaterial3theme)
- [`createMaterial3Theme`](docs/API.md#creatematerial3theme)
- [`isDynamicThemeSupported`](docs/API.md#isdynamicthemesupported-boolean)## ⚠️ Activity recreation
When Material 3 dynamic theme is changed on Android 12+ devices, it is a configuration change and the system will recreate an Activity.
This configuration change can't be disable: "Some configuration changes always cause the activity to restart. You can't disable them. For example, you can't disable the dynamic colors change introduced in API 32" (cf official [doc](https://developer.android.com/guide/topics/resources/runtime-changes#restrict-activity)).
So be aware that when users change their theme then go back to your app, all local state may be lost (and may cause some flickering) if your don't handle it.
## License
This project is released under the [MIT License](https://github.com/pchmn/firebase-cli-github-action/blob/main/license).