{"id":20774155,"url":"https://github.com/pchmn/expo-material3-theme","last_synced_at":"2025-04-04T11:07:27.773Z","repository":{"id":143164114,"uuid":"611859405","full_name":"pchmn/expo-material3-theme","owner":"pchmn","description":"Manage Material 3 theme in your React Native App","archived":false,"fork":false,"pushed_at":"2024-12-06T09:35:24.000Z","size":66440,"stargazers_count":96,"open_issues_count":5,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-28T10:02:55.297Z","etag":null,"topics":["android","expo","ios","react-native"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pchmn.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-03-09T17:32:01.000Z","updated_at":"2025-03-28T00:30:08.000Z","dependencies_parsed_at":"2024-12-27T10:06:18.697Z","dependency_job_id":null,"html_url":"https://github.com/pchmn/expo-material3-theme","commit_stats":{"total_commits":93,"total_committers":2,"mean_commits":46.5,"dds":0.08602150537634412,"last_synced_commit":"a32494e4a40b69cecd288f6dd0b87239f1fa2fbe"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pchmn%2Fexpo-material3-theme","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pchmn%2Fexpo-material3-theme/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pchmn%2Fexpo-material3-theme/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pchmn%2Fexpo-material3-theme/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pchmn","download_url":"https://codeload.github.com/pchmn/expo-material3-theme/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247166157,"owners_count":20894652,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","expo","ios","react-native"],"created_at":"2024-11-17T12:28:33.240Z","updated_at":"2025-04-04T11:07:27.753Z","avatar_url":"https://github.com/pchmn.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n![image](https://user-images.githubusercontent.com/12658241/225726041-d086724a-9bef-49e1-a21b-2a91d5a3b5e9.png)\n\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/pchmn/expo-material3-theme/blob/main/LICENSE)\n[![npm latest package](https://img.shields.io/npm/v/@pchmn/expo-material3-theme/latest.svg)](https://www.npmjs.com/package/@pchmn/expo-material3-theme)\n[![platform - android](https://img.shields.io/badge/platform-Android-3ddc84.svg?logo=android)](https://www.android.com)\n[![platform - ios](https://img.shields.io/badge/platform-iOS-000.svg?logo=apple)](https://developer.apple.com/ios)\n\n\u003c/div\u003e\n\n\u003ch1 align=\"center\"\u003eExpo Material 3 Theme\u003c/h1\u003e\n\n\u003cdiv align=\"center\"\u003e\n\nThis [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.\n\nFor devices not compatible (iOS or older Android versions) a fallback theme is returned.\n\n\u003c/div\u003e\n\n\u003cbr\u003e\n\n## ✨ Features\n\n- Retrieve Material 3 dynamic theme from Android 12+ devices (or a fallback theme if device is not compatible)\n- 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))\n- Material 3 theme compatible with [`react-native-paper`](https://callstack.github.io/react-native-paper/)\n\n\u003cbr\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n![example-android](docs/example-android.gif)\n\n\u003c/div\u003e\n\u003cbr\u003e\n\n## Installation\n\n### Installation in managed Expo projects\n\n\u003e 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/)\n\n\n```\nnpx expo install @pchmn/expo-material3-theme\n```\n\nIf 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) :\n\n```\nnpx expo prebuild --platform android\nnpx expo run:android\n```\n\n### Installation in bare React Native projects\n\nFor 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.\n\n```sh\nnpx expo install @pchmn/expo-material3-theme\nnpx pod-install\n```\n\n## Usage\n\n### Retrieve system theme\n\nA basic usage would be to retrieve the Material 3 theme from user device (or a fallback theme if not supported) by using `useMaterial3Theme` hook:\n\n```tsx\nimport { useMaterial3Theme } from '@pchmn/expo-material3-theme';\nimport { useColorScheme, View, Button } from 'react-native';\n\nfunction App() {\n  const colorScheme = useColorScheme();\n  // If the device is not compatible, it will return a theme based on the fallback source color (optional, default to #6750A4)\n  const { theme } = useMaterial3Theme({ fallbackSourceColor: '#3E8260' });\n\n  return (\n    \u003cView style={{ backgroundColor: theme[colorScheme].background }}\u003e\n      \u003cButton color={theme[colorScheme].primary}\u003eThemed button\u003c/Button\u003e\n    \u003c/View\u003e\n  );\n}\n```\n\n### Use a custom theme\n\nIf you want to use a theme based on a specific color instead of the system theme, just pass the `sourceColor` param to `useMaterial3Theme` hook:\n\n```tsx\nimport { useMaterial3Theme } from '@pchmn/expo-material3-theme';\nimport { useColorScheme, View, Button } from 'react-native';\n\nfunction App() {\n  const colorScheme = useColorScheme();\n  // Theme returned will be based on #3E8260 color\n  const { theme } = useMaterial3Theme({ sourceColor: '#3E8260' });\n\n  return (\n    \u003cView style={{ backgroundColor: theme[colorScheme].background }}\u003e\n      \u003cButton color={theme[colorScheme].primary}\u003eThemed button\u003c/Button\u003e\n    \u003c/View\u003e\n  );\n}\n```\n\n### Change theme\n\nYou 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:\n\n```tsx\nimport { useMaterial3Theme } from '@pchmn/expo-material3-theme';\nimport { useColorScheme, View, Button } from 'react-native';\n\nfunction App() {\n  const colorScheme = useColorScheme();\n  const { theme, updateTheme, resetTheme } = useMaterial3Theme();\n\n  return (\n    \u003cView style={{ backgroundColor: theme[colorScheme].background }}\u003e\n      {/* Update theme by generating a new one based on #3E8260 color */}\n      \u003cButton onPress={() =\u003e updateTheme('#3E8260')}\u003eUpdate theme\u003c/Button\u003e\n      {/* Reset theme to default (system or fallback) */}\n      \u003cButton onPress={() =\u003e resetTheme()}\u003eReset theme\u003c/Button\u003e\n    \u003c/View\u003e\n  );\n}\n```\n\n\u003e ℹ️ `updateTheme()` and `resetTheme()` will change the theme returned by `useMaterial3Theme()`, it will not change theme at system level\n\n### Usage with `react-native-paper`\n\n#### Basic example\n`@pchmn/expo-material3-theme` provides a theme compatible with `react-native-paper`, so you can combine both libraries easily:\n\n```tsx\nimport { useMaterial3Theme } from '@pchmn/expo-material3-theme';\nimport { useMemo } from 'react';\nimport { useColorScheme } from 'react-native';\nimport { Button, MD3DarkTheme, MD3LightTheme, Provider as PaperProvider } from 'react-native-paper';\n\nfunction App() {\n  const colorScheme = useColorScheme();\n  const { theme } = useMaterial3Theme();\n\n  const paperTheme = useMemo(\n    () =\u003e\n      colorScheme === 'dark' ? { ...MD3DarkTheme, colors: theme.dark } : { ...MD3LightTheme, colors: theme.light },\n    [colorScheme, theme]\n  );\n\n  return (\n    \u003cPaperProvider theme={paperTheme}\u003e\n      \u003cButton\u003eThemed react native paper button\u003c/Button\u003e\n    \u003c/PaperProvider\u003e\n  );\n}\n```\n\n#### Advanced usage\n\n\u003cdetails\u003e\n  \u003csummary\u003eOverride \u003ccode\u003ereact-native-paper\u003c/code\u003e theme (Typescript)\u003c/summary\u003e\n  \u003cbr\u003e\n\n  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 :\n\n  ```ts\n  import { Material3Scheme } from '@pchmn/expo-material3-theme';\n  import { MD3Theme, useTheme } from 'react-native-paper';\n\n  export const useAppTheme = useTheme\u003cMD3Theme \u0026 { colors: Material3Scheme }\u003e;\n\n  // Now use useAppTheme() instead of useTheme()\n  ```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003eCreate a \u003ccode\u003eMaterial3ThemeProvider\u003c/code\u003e that includes \u003ccode\u003ePaperProvider\u003c/code\u003e\u003c/summary\u003e\n\n  ```tsx\n  // Material3ThemeProvider.tsx\n  import { Material3Scheme, Material3Theme, useMaterial3Theme } from '@pchmn/expo-material3-theme';\n  import { createContext, useContext } from 'react';\n  import { useColorScheme } from 'react-native';\n  import {\n    MD3DarkTheme,\n    MD3LightTheme,\n    MD3Theme,\n    Provider as PaperProvider,\n    ProviderProps,\n    useTheme,\n  } from 'react-native-paper';\n\n  type Material3ThemeProviderProps = {\n    theme: Material3Theme;\n    updateTheme: (sourceColor: string) =\u003e void;\n    resetTheme: () =\u003e void;\n  };\n\n  const Material3ThemeProviderContext = createContext\u003cMaterial3ThemeProviderProps\u003e({} as Material3ThemeProviderProps);\n\n  export function Material3ThemeProvider({\n    children,\n    sourceColor,\n    fallbackSourceColor,\n    ...otherProps\n  }: ProviderProps \u0026 { sourceColor?: string; fallbackSourceColor?: string }) {\n    const colorScheme = useColorScheme();\n\n    const { theme, updateTheme, resetTheme } = useMaterial3Theme({\n      sourceColor,\n      fallbackSourceColor,\n    });\n\n    const paperTheme =\n      colorScheme === 'dark' ? { ...MD3DarkTheme, colors: theme.dark } : { ...MD3LightTheme, colors: theme.light };\n\n    return (\n      \u003cMaterial3ThemeProviderContext.Provider value={{ theme, updateTheme, resetTheme }}\u003e\n        \u003cPaperProvider theme={paperTheme} {...otherProps}\u003e\n          {children}\n        \u003c/PaperProvider\u003e\n      \u003c/Material3ThemeProviderContext.Provider\u003e\n    );\n  }\n\n  export function useMaterial3ThemeContext() {\n    const ctx = useContext(Material3ThemeProviderContext);\n    if (!ctx) {\n      throw new Error('useMaterial3ThemeContext must be used inside Material3ThemeProvider');\n    }\n    return ctx;\n  }\n\n  export const useAppTheme = useTheme\u003cMD3Theme \u0026 { colors: Material3Scheme }\u003e;\n\n\n  // App.tsx\n  import { Material3ThemeProvider, useAppTheme, useMaterial3ThemeContext } from '../Material3ThemeProvider';\n  import { View, Button } from 'react-native';\n\n  function App() {\n    return (\n      \u003cMaterial3ThemeProvider\u003e\n        \u003cAppContent /\u003e\n      \u003c/Material3ThemeProvider\u003e\n    )\n  }\n\n  function AppContent() {\n    const { updateTheme, resetTheme } = useMaterial3ThemeContext();\n    // react-native-paper theme is always in sync\n    const theme = useAppTheme();\n\n    return (\n      \u003cView style={{ backgroundColor: theme.colors.background }}\u003e\n        {/* Update theme by generating a new one based on #3E8260 color */}\n        \u003cButton onPress={() =\u003e updateTheme('#3E8260')}\u003eUpdate theme\u003c/Button\u003e\n        {/* Reset theme to default (system or fallback) */}\n        \u003cButton onPress={() =\u003e resetTheme()}\u003eReset theme\u003c/Button\u003e\n      \u003c/View\u003e\n    );\n  }\n  ```\n\u003c/details\u003e\n\n## Example\n\nYou can see an example app in the [`/example`](./example/) folder.\n\n### Android example\n\nExtract [zip file](docs/example-apps.zip), and install `expo-material3-theme-example-android.apk` on your device.\n\n### iOS example\n\nThis 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.\n\n## [API Reference](docs/API.md)\n\n- [`useMaterial3Theme`](docs/API.md#usematerial3theme)\n- [`getMaterial3Theme`](docs/API.md#getmaterial3theme)\n- [`createMaterial3Theme`](docs/API.md#creatematerial3theme)\n- [`isDynamicThemeSupported`](docs/API.md#isdynamicthemesupported-boolean)\n\n## ⚠️ Activity recreation\n\nWhen Material 3 dynamic theme is changed on Android 12+ devices, it is a configuration change and the system will recreate an Activity.\n\nThis 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)).\n\nSo 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.\n\n## License\n\nThis project is released under the [MIT License](https://github.com/pchmn/firebase-cli-github-action/blob/main/license).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpchmn%2Fexpo-material3-theme","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpchmn%2Fexpo-material3-theme","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpchmn%2Fexpo-material3-theme/lists"}