@rific/auto-paper 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,10 +1,12 @@
1
1
  # @rific/auto-paper
2
2
 
3
- Adaptive theming for [`react-native-paper`](https://callstack.github.io/react-native-paper/). Give it one color and an appearance setting — it generates an MD3 palette and handles light/dark/system mode automatically.
3
+ Adaptive theming for [`react-native-paper`](https://callstack.github.io/react-native-paper/). Give it one color and an appearance setting, and it generates an MD3 palette and handles light/dark/system mode automatically.
4
4
 
5
5
  ## Features
6
6
 
7
- - Color harmony palette from a single seed color (primary → secondary → tertiary) — 6 harmony modes available, defaulting to `split-complementary`
7
+ - Color harmony palette from a single seed color (primary → secondary → tertiary), with 6 harmony modes available, defaulting to `split-complementary`
8
+ - Or supply an explicit `{ primary, secondary, tertiary }` triad directly, bypassing harmony math entirely
9
+ - `getThirdColor(colorA, colorB)` derives a third color maximally distinct in hue from two arbitrary inputs, handy for pairing with the explicit triad above when you have two colors and need a third that won't clash with either
8
10
  - System/light/dark appearance with live updates via `Appearance` API
9
11
  - Tinted surface, surfaceVariant, outline, and elevation levels derived from the seed
10
12
  - Fixed `success`/`warning`/`danger` semantic color roles (each with `on*`/`*Container` variants) alongside MD3's built-in `error`
@@ -27,11 +29,13 @@ npm install react-native-paper
27
29
  Optional peer dependencies:
28
30
 
29
31
  ```bash
30
- npm install expo-blur # frosted-glass BlurView; without it BlurView renders its solid (non-blur) fallback
32
+ npm install expo-blur # frosted-glass BlurView
31
33
  npm install expo-navigation-bar # (>= 56.0.0, SDK 54+) auto-syncs Android nav bar icon style to the theme when BottomNavigation is mounted
32
34
  ```
33
35
 
34
- The exported Redux slice has no dependency on `@reduxjs/toolkit` — it works with RTK stores, vanilla Redux, or no Redux at all.
36
+ Neither is auto-detected: pass them to `Provider` (`expoBlur`, `navigationBar`, see the prop table below) and `BlurView`/`BottomNavigation` pick them up automatically. Omit either and you get a working fallback instead: `BlurView` renders its solid (non-blur) look, and the Android nav bar simply isn't synced.
37
+
38
+ The exported Redux slice has no dependency on `@reduxjs/toolkit`: it works with RTK stores, vanilla Redux, or no Redux at all.
35
39
 
36
40
  ## Usage
37
41
 
@@ -49,7 +53,7 @@ export default function App() {
49
53
  }
50
54
  ```
51
55
 
52
- `Provider` renders `null` on the first render while the theme computes, then wraps your app in `PaperProvider` with the computed theme, a matching `StatusBar`, and a background `View`. Use `onReady` to hook into that moment — e.g. to dismiss a splash screen:
56
+ `Provider` renders `null` on the first render while the theme computes, then wraps your app in `PaperProvider` with the computed theme, a matching `StatusBar`, and a background `View`. Use `onReady` to hook into that moment, e.g. to dismiss a splash screen:
53
57
 
54
58
  ```tsx
55
59
  <AutoPaperProvider initialValue={{ appearance: 'system', color: '#6750a4' }} onReady={SplashScreen.hideAsync}>
@@ -75,7 +79,7 @@ function SettingsScreen() {
75
79
 
76
80
  ### Choosing a color harmony
77
81
 
78
- The `harmony` prop controls how secondary and tertiary colors are derived from your seed. The default is `split-complementary`, which works well for most apps — it keeps secondary and tertiary close together in hue so they feel like a family of accents rather than three competing dominant colors.
82
+ The `harmony` prop controls how secondary and tertiary colors are derived from your seed. The default is `split-complementary`, which works well for most apps: it keeps secondary and tertiary close together in hue so they feel like a family of accents rather than three competing dominant colors.
79
83
 
80
84
  ```tsx
81
85
  <AutoPaperProvider initialValue={{ appearance: 'system', color: '#6750a4', harmony: 'split-complementary' }}>
@@ -83,12 +87,44 @@ The `harmony` prop controls how secondary and tertiary colors are derived from y
83
87
 
84
88
  | Harmony | Offsets | Character |
85
89
  |---|---|---|
86
- | `split-complementary` *(default)* | 0°, +150°, +210° | Harmonious contrast — flanks the complement by ±30° |
87
- | `triadic` | 0°, +120°, +240° | Equilateral — maximum variety, three equal-weight colors |
88
- | `analogous` | 0°, +30°, +60° | Cohesive, natural — neighboring hues |
89
- | `square` | 0°, +90°, +270° | Balanced, structured — right-angle symmetry |
90
- | `complementary` | 0°, +90°, +180° | Bold — accent at 90° plus true opposite |
91
- | `double-split` | 0°, +30°, +330° | Tight — flanks the primary by ±30° |
90
+ | `split-complementary` *(default)* | 0°, +150°, +210° | Harmonious contrast: flanks the complement by ±30° |
91
+ | `triadic` | 0°, +120°, +240° | Equilateral: maximum variety, three equal-weight colors |
92
+ | `analogous` | 0°, +30°, +60° | Cohesive, natural: neighboring hues |
93
+ | `square` | 0°, +90°, +270° | Balanced, structured: right-angle symmetry |
94
+ | `complementary` | 0°, +90°, +180° | Bold: accent at 90° plus true opposite |
95
+ | `double-split` | 0°, +30°, +330° | Tight: flanks the primary by ±30° |
96
+
97
+ ### Explicit triad (bypassing harmony)
98
+
99
+ Instead of a single seed color, `color` also accepts a `{ primary, secondary, tertiary }` object (`TriadicPalette`). Each field is assigned directly, through `getColorRoles`, with no hue math, and `harmony` is ignored entirely. Useful whenever you already have three colors that matter individually, rather than one seed to expand.
100
+
101
+ ```tsx
102
+ <AutoPaperProvider
103
+ initialValue={{
104
+ appearance: 'system',
105
+ color: { primary: '#e53935', secondary: '#1e88e5', tertiary: '#43a047' }
106
+ }}
107
+ >
108
+ ```
109
+
110
+ A common case is deriving the third color from two you already have: any two arbitrary colors, from user picks to brand colors to data-driven values.
111
+
112
+ ```tsx
113
+ import { getThirdColor, Provider as AutoPaperProvider } from '@rific/auto-paper'
114
+
115
+ const colorA = '#e53935'
116
+ const colorB = '#1e88e5'
117
+
118
+ <AutoPaperProvider
119
+ initialValue={{
120
+ color: {
121
+ primary: colorA,
122
+ secondary: colorB,
123
+ tertiary: getThirdColor(colorA, colorB) // → '#59e52a'
124
+ }
125
+ }}
126
+ >
127
+ ```
92
128
 
93
129
  ### With component defaults
94
130
 
@@ -158,7 +194,7 @@ dispatch(themeActions.setAppearance('dark'))
158
194
 
159
195
  ### With `useComputedTheme`
160
196
 
161
- Use the hook directly when you need to extend the theme before passing it to `PaperProvider` — for example, to merge in a navigation theme or add custom color keys:
197
+ Use the hook directly when you need to extend the theme before passing it to `PaperProvider`, for example to merge in a navigation theme or add custom color keys:
162
198
 
163
199
  ```tsx
164
200
  import { useComputedTheme } from '@rific/auto-paper'
@@ -194,11 +230,13 @@ export default function App() {
194
230
 
195
231
  | Prop | Type | Description |
196
232
  |---|---|---|
197
- | `initialValue` | `Partial<ThemeSettings>` | Initial theme settings — `appearance`, `color`, `harmony`, `blur`, `blurTint`. Defaults from `defaultThemeSettings` fill any omitted fields. |
233
+ | `initialValue` | `Partial<ThemeSettings>` | Initial theme settings: `appearance`, `color`, `harmony`, `blur`, `blurTint`. Defaults from `defaultThemeSettings` fill any omitted fields. |
198
234
  | `onChange` | `(settings: ThemeSettings) => void` | Called whenever settings change via `useThemeSettings().set()` |
199
235
  | `children` | `ReactNode` | |
200
236
  | `defaults` | `PaperDefaults` | Prop defaults for wrapper components (see below) |
201
- | `onNavBarChange` | `(color: string, dark: boolean) => void` | Overrides the built-in nav bar sync: called on Android when the theme changes while a `BottomNavigation` is mounted, instead of the automatic `expo-navigation-bar` icon-style sync |
237
+ | `expoBlur` | `ExpoBlurModule` | Injects `expo-blur` (`import * as ExpoBlur from 'expo-blur'`) so `<BlurView>` renders the real frosted-glass effect. Omit to always render its solid fallback. |
238
+ | `navigationBar` | `ExpoNavigationBarModule` | Injects `expo-navigation-bar` (`import * as ExpoNavigationBar from 'expo-navigation-bar'`) so the Android nav bar icon style auto-syncs with the theme while a `BottomNavigation` is mounted. Omit (and don't pass `onNavBarChange`) to skip nav bar syncing entirely. |
239
+ | `onNavBarChange` | `(color: string, dark: boolean) => void` | Overrides the built-in nav bar sync: called on Android when the theme changes while a `BottomNavigation` is mounted, instead of the automatic `navigationBar`-driven icon-style sync |
202
240
  | `onReady` | `() => void` | Called once when the theme first resolves |
203
241
  | `statusBarProps` | `StatusBarProps` | Spread over the auto-derived `StatusBar` defaults |
204
242
  | `style` | `StyleProp<ViewStyle>` | Applied to the wrapper `View` |
@@ -208,8 +246,8 @@ export default function App() {
208
246
  | Field | Type | Default |
209
247
  |---|---|---|
210
248
  | `appearance` | `'system' \| 'light' \| 'dark'` | `'system'` |
211
- | `color` | `string` | `'#6750a4'` |
212
- | `harmony` | `ColorHarmony` | `'split-complementary'` |
249
+ | `color` | `string \| TriadicPalette` | `'#6750a4'` |
250
+ | `harmony` | `ColorHarmony` | `'split-complementary'` (ignored when `color` is a `TriadicPalette`) |
213
251
  | `blur` | `boolean` | `true` |
214
252
  | `blurTint` | `number` | `0.2` |
215
253
 
@@ -229,11 +267,14 @@ set({ harmony: 'triadic' })
229
267
 
230
268
  ### `useComputedTheme(appearance, color, harmony?)`
231
269
 
232
- Returns `AutoPaperTheme | null` — `MD3Theme` plus `success`/`warning`/`danger` color roles (see below). `null` on the first render while the theme computes.
270
+ Returns `AutoPaperTheme | null`: `MD3Theme` plus `success`/`warning`/`danger` color roles (see below). `null` on the first render while the theme computes.
271
+
272
+ `color` accepts either a single seed string (expanded into `primary`/`secondary`/`tertiary` via `harmony`) or an explicit `{ primary, secondary, tertiary }` triad (`TriadicPalette`), which assigns each field directly and ignores `harmony`. Either way, the resulting `primary` also drives `outline`/`surfaceVariant`/elevation tinting.
233
273
 
234
274
  ```ts
235
275
  const theme = useComputedTheme('system', '#6750a4')
236
276
  const theme = useComputedTheme('system', '#6750a4', 'triadic')
277
+ const theme = useComputedTheme('system', { primary: '#e53935', secondary: '#1e88e5', tertiary: '#43a047' }) // harmony ignored
237
278
  ```
238
279
 
239
280
  Alongside the standard MD3 `primary`/`secondary`/`tertiary` roles derived from the seed color, `theme.colors` also carries three fixed semantic roles, each with the usual `color`/`onColor`/`Container`/`onContainer` quadruple (`success`, `onSuccess`, `successContainer`, `onSuccessContainer`, and likewise for `warning` and `danger`):
@@ -244,7 +285,7 @@ Alongside the standard MD3 `primary`/`secondary`/`tertiary` roles derived from t
244
285
  | `warning` | `SEMANTIC_BASE_COLORS.warning` (`#A15C00`) |
245
286
  | `danger` | `SEMANTIC_BASE_COLORS.danger` (`#B00020`) |
246
287
 
247
- These are fixed brand colors — like MD3's own `error`, which is left untouched — not derived from the seed; only their container blending adapts to light/dark mode. `danger` is deliberately separate from `error`: `react-native-paper` components (`TextInput`'s error state, `HelperText`, `Badge`) read `colors.error`/`colors.onError` directly, so redefining `error` itself would change form-validation colors app-wide.
288
+ These are fixed brand colors (like MD3's own `error`, which is left untouched), not derived from the seed; only their container blending adapts to light/dark mode. `danger` is deliberately separate from `error`: `react-native-paper` components (`TextInput`'s error state, `HelperText`, `Badge`) read `colors.error`/`colors.onError` directly, so redefining `error` itself would change form-validation colors app-wide.
248
289
 
249
290
  ```ts
250
291
  import { SEMANTIC_BASE_COLORS } from '@rific/auto-paper'
@@ -253,7 +294,7 @@ import type { AutoPaperTheme, SemanticColorRoles } from '@rific/auto-paper'
253
294
 
254
295
  ### `useAutoPaperTheme()`
255
296
 
256
- A typed alternative to `react-native-paper`'s own `useTheme()` that returns `AutoPaperTheme` — the same theme, with `colors.success`/`warning`/`danger` (and their `on*`/`*Container` variants) typed in, so you get autocomplete without redeclaring the generic yourself at every call site.
297
+ A typed alternative to `react-native-paper`'s own `useTheme()` that returns `AutoPaperTheme`: the same theme, with `colors.success`/`warning`/`danger` (and their `on*`/`*Container` variants) typed in, so you get autocomplete without redeclaring the generic yourself at every call site.
257
298
 
258
299
  ```tsx
259
300
  import { useAutoPaperTheme } from '@rific/auto-paper'
@@ -280,8 +321,8 @@ function SettingsScreen() {
280
321
  |---|---|---|
281
322
  | `value` | `ThemeAppearance` | Currently selected appearance |
282
323
  | `onChange` | `(appearance: ThemeAppearance) => void` | Called when a segment is tapped |
283
- | `showLabels` | `boolean` | Set `false` for icon-only segments — useful in tight layouts where "System" would truncate. `accessibilityLabel` is always set regardless, so screen readers still announce the full word. Defaults to `true` |
284
- | `icons` | `AppearanceIcons` | Per-value icon overrides — pass just the ones you want to change (e.g. `{ system: 'theme-light-dark' }`), merged over the defaults (`monitor` / `white-balance-sunny` / `weather-night`) |
324
+ | `showLabels` | `boolean` | Set `false` for icon-only segments, useful in tight layouts where "System" would truncate. `accessibilityLabel` is always set regardless, so screen readers still announce the full word. Defaults to `true` |
325
+ | `icons` | `AppearanceIcons` | Per-value icon overrides: pass just the ones you want to change (e.g. `{ system: 'theme-light-dark' }`), merged over the defaults (`monitor` / `white-balance-sunny` / `weather-night`) |
285
326
 
286
327
  ### `Appbar`
287
328
 
@@ -297,11 +338,11 @@ import { Appbar } from '@rific/auto-paper'
297
338
  </Appbar.Header>
298
339
  ```
299
340
 
300
- `Appbar.Content`, `Appbar.Action`, and `Appbar.BackAction` are re-exported directly from `react-native-paper`. Only `Appbar.Header` is wrapped — it applies `AppbarHeader` defaults from context and renders the synced `StatusBar`.
341
+ `Appbar.Content`, `Appbar.Action`, and `Appbar.BackAction` are re-exported directly from `react-native-paper`. Only `Appbar.Header` is wrapped: it applies `AppbarHeader` defaults from context and renders the synced `StatusBar`.
301
342
 
302
343
  ### `BottomNavigation`
303
344
 
304
- A thin wrapper around `react-native-paper`'s `BottomNavigation` that keeps the Android system navigation bar icons readable: when the optional `expo-navigation-bar` peer is installed, the icon style automatically follows the theme's darkness (edge-to-edge safe — no background color calls). Pass `onNavBarChange` to the `Provider` to take full control instead; with neither, it silently no-ops.
345
+ A thin wrapper around `react-native-paper`'s `BottomNavigation` that keeps the Android system navigation bar icons readable: when `navigationBar` is injected into `Provider`, the icon style automatically follows the theme's darkness (edge-to-edge safe, no background color calls). Pass `onNavBarChange` to the `Provider` to take full control instead; with neither, it silently no-ops.
305
346
 
306
347
  ```tsx
307
348
  import { BottomNavigation } from '@rific/auto-paper'
@@ -353,13 +394,13 @@ import { IconButton } from '@rific/auto-paper'
353
394
  | Prop | Type | Description |
354
395
  |---|---|---|
355
396
  | `variant` | `'primary' \| 'secondary' \| 'tertiary' \| 'surface'` | Sets `containerColor` and `iconColor` from the matching theme color pair |
356
- | ...all `IconButtonProps` | | All props from `react-native-paper`'s `IconButton` are supported — explicit `containerColor` or `iconColor` override the variant |
397
+ | ...all `IconButtonProps` | | All props from `react-native-paper`'s `IconButton` are supported; explicit `containerColor` or `iconColor` override the variant |
357
398
 
358
399
  `IconButtonProps` is exported from `@rific/auto-paper` and extends `react-native-paper`'s `IconButtonProps` with the `variant` field. Use `PaperIconButtonProps` if you need the base paper type.
359
400
 
360
401
  ### `PalettePicker`
361
402
 
362
- Like `ColorPicker`, but each swatch — and the trigger itself — renders the seed's full triadic palette as a 3-wedge pie instead of a flat color, so you see the whole result before picking.
403
+ Like `ColorPicker`, but each swatch (and the trigger itself) renders the seed's full triadic palette as a 3-wedge pie instead of a flat color, so you see the whole result before picking.
363
404
 
364
405
  ```tsx
365
406
  import { PalettePicker, useThemeSettings } from '@rific/auto-paper'
@@ -375,7 +416,7 @@ function SettingsScreen() {
375
416
  | `value` | `string` | Currently selected seed color |
376
417
  | `onChange` | `(color: string) => void` | Called with the seed color when a swatch is tapped |
377
418
  | `harmony` | `ColorHarmony` | Harmony used to compute each swatch's preview palette. Defaults to `'split-complementary'` |
378
- | `weights` | `PaletteWeights` | Relative size of each wedge — `{ primary, secondary, tertiary }`. Defaults to `{ primary: 2, secondary: 1, tertiary: 1 }` (primary half the pie, secondary/tertiary a quarter each). Values are normalized, so any positive ratio works; keep each share at or under half the total so its wedge stays a single slice |
419
+ | `weights` | `PaletteWeights` | Relative size of each wedge: `{ primary, secondary, tertiary }`. Defaults to `{ primary: 2, secondary: 1, tertiary: 1 }` (primary half the pie, secondary/tertiary a quarter each). Values are normalized, so any positive ratio works; keep each share at or under half the total so its wedge stays a single slice |
379
420
  | `colors` | `SeedColor[]` | Seed color swatches to offer. Defaults to the same set as `ColorPicker` |
380
421
  | `blur` | `boolean` | Overrides the ambient blur setting for this component's dialog |
381
422
 
@@ -423,10 +464,10 @@ import type { ThemeState, ThemeAppearance } from '@rific/auto-paper'
423
464
  | `initialize` | `Partial<ThemeState>` |
424
465
  | `setAppearance` | `ThemeAppearance` |
425
466
  | `setBlur` | `boolean` |
426
- | `setColor` | `string` |
467
+ | `setColor` | `string \| TriadicPalette` |
427
468
  | `setHarmony` | `ColorHarmony` |
428
469
 
429
- Selectors accept `ThemeState` directly — compose them with your root state selector:
470
+ Selectors accept `ThemeState` directly; compose them with your root state selector:
430
471
 
431
472
  ```ts
432
473
  const appearance = useSelector((state: RootState) => selectThemeAppearance(state.theme))
@@ -435,8 +476,8 @@ const appearance = useSelector((state: RootState) => selectThemeAppearance(state
435
476
  ### Color utilities
436
477
 
437
478
  ```ts
438
- import { getTriadicPalette, getBlendedColor, getColorRoles, getContrastColor, isDarkColor, getRgb, getHex, getTonalColor, getTintTextColor } from '@rific/auto-paper'
439
- import type { ColorHarmony } from '@rific/auto-paper'
479
+ import { getTriadicPalette, getThirdColor, getBlendedColor, getColorRoles, getContrastColor, isDarkColor, getRgb, getHex, getTonalColor, getTintTextColor } from '@rific/auto-paper'
480
+ import type { ColorHarmony, TriadicPalette } from '@rific/auto-paper'
440
481
 
441
482
  getTriadicPalette('#6750a4') // split-complementary (default)
442
483
  getTriadicPalette('#6750a4', 'triadic') // → { primary, secondary, tertiary }
@@ -445,9 +486,11 @@ getTriadicPalette('#6750a4', 'square')
445
486
  getTriadicPalette('#6750a4', 'complementary')
446
487
  getTriadicPalette('#6750a4', 'double-split')
447
488
 
489
+ getThirdColor('#e53935', '#1e88e5') // → '#59e52a' (hue maximally distant from both inputs; s/l averaged from both)
490
+
448
491
  getBlendedColor('#ff0000', '#0000ff', 0.5) // → '#800080'
449
- getColorRoles('#6750a4', '#fffbfe') // → { color, onColor, container, onContainer } — the MD3 color/onColor/container/onContainer math, generalized (this is what useComputedTheme uses internally for every role)
450
- getContrastColor('#6750a4') // → '#ffffff' — black/white pick for content sitting on a fully saturated fill
492
+ getColorRoles('#6750a4', '#fffbfe') // → { color, onColor, container, onContainer }: the MD3 color/onColor/container/onContainer math, generalized (this is what useComputedTheme uses internally for every role)
493
+ getContrastColor('#6750a4') // → '#ffffff' (black/white pick for content sitting on a fully saturated fill)
451
494
  isDarkColor('#6750a4') // → true
452
495
  getRgb('coral') // → { r: 255, g: 127, b: 80 }
453
496
  getHex('rgb(255, 0, 0)') // → '#ff0000'
package/dist/index.d.mts CHANGED
@@ -5,7 +5,7 @@ import * as react_native_paper from 'react-native-paper';
5
5
  import { AppbarHeaderProps, MD3Theme, BottomNavigationRoute, BottomNavigationProps, BottomNavigation as BottomNavigation$1, ButtonProps, ChipProps as ChipProps$1, DialogProps as DialogProps$1, DialogTitleProps, DialogContentProps, DialogActionsProps, DialogScrollAreaProps, FABProps, IconButtonProps as IconButtonProps$1, MenuProps as MenuProps$1, MenuItemProps, TextInputProps } from 'react-native-paper';
6
6
  export { AppbarHeaderProps, BottomNavigationProps, BottomNavigationRoute, ButtonProps, FABProps, ChipProps as PaperChipProps, DialogProps as PaperDialogProps, IconButtonProps as PaperIconButtonProps, MenuProps as PaperMenuProps, TextInputProps } from 'react-native-paper';
7
7
  import * as react from 'react';
8
- import react__default, { RefObject, ReactNode } from 'react';
8
+ import react__default, { RefObject, ReactNode, ComponentType } from 'react';
9
9
 
10
10
  declare function useBlur(override?: boolean): boolean;
11
11
 
@@ -51,7 +51,7 @@ type SemanticColorRoles = {
51
51
  type AutoPaperTheme = Omit<MD3Theme, 'colors'> & {
52
52
  colors: MD3Theme['colors'] & SemanticColorRoles;
53
53
  };
54
- declare function useComputedTheme(appearance: ThemeAppearance, color: string, harmony?: ColorHarmony): AutoPaperTheme | null;
54
+ declare function useComputedTheme(appearance: ThemeAppearance, color: string | TriadicPalette, harmony?: ColorHarmony): AutoPaperTheme | null;
55
55
 
56
56
  type AppearanceIcons = Partial<Record<ThemeAppearance, string>>;
57
57
  type Props$3 = {
@@ -62,6 +62,14 @@ type Props$3 = {
62
62
  };
63
63
  declare const AppearancePicker: ({ value, onChange, showLabels, icons }: Props$3) => react.JSX.Element;
64
64
 
65
+ interface ExpoBlurModule {
66
+ BlurView: ComponentType<{
67
+ children?: ReactNode;
68
+ style?: StyleProp<ViewStyle>;
69
+ tint?: any;
70
+ [key: string]: unknown;
71
+ }>;
72
+ }
65
73
  type ExpoBlurTint = 'light' | 'dark' | 'default' | 'extraLight' | 'regular' | 'prominent' | 'systemUltraThinMaterial' | 'systemThinMaterial' | 'systemMaterial' | 'systemThickMaterial' | 'systemChromeMaterial' | 'systemUltraThinMaterialLight' | 'systemThinMaterialLight' | 'systemMaterialLight' | 'systemThickMaterialLight' | 'systemChromeMaterialLight' | 'systemUltraThinMaterialDark' | 'systemThinMaterialDark' | 'systemMaterialDark' | 'systemThickMaterialDark' | 'systemChromeMaterialDark';
66
74
  type ExpoBlurMethod = 'none' | 'dimezisBlurView' | 'dimezisBlurViewSdk31Plus';
67
75
  type ExpoBlurViewProps = {
@@ -170,6 +178,12 @@ declare const PalettePicker: ({ value, onChange, harmony, weights, colors, blur:
170
178
 
171
179
  declare const TextInput: react.ForwardRefExoticComponent<Omit<TextInputProps, "ref"> & react.RefAttributes<TextInput$1>>;
172
180
 
181
+ interface ExpoNavigationBarModule {
182
+ NavigationBar: {
183
+ setStyle: (style: 'light' | 'dark') => void;
184
+ };
185
+ }
186
+
173
187
  type PaperDefaults = {
174
188
  AppbarHeader?: Partial<AppbarHeaderProps>;
175
189
  BottomNavigation?: Partial<BottomNavigationProps<BottomNavigationRoute>>;
@@ -184,7 +198,7 @@ declare function usePaperDefaults(): PaperDefaults;
184
198
  type ThemeState = {
185
199
  appearance: ThemeAppearance;
186
200
  blur: boolean;
187
- color: string;
201
+ color: string | TriadicPalette;
188
202
  harmony: ColorHarmony;
189
203
  };
190
204
  type PayloadAction<P> = {
@@ -214,11 +228,11 @@ declare const themeActions: {
214
228
  }): action is PayloadAction<boolean>;
215
229
  };
216
230
  setColor: {
217
- (payload: string): PayloadAction<string>;
231
+ (payload: string | TriadicPalette): PayloadAction<string | TriadicPalette>;
218
232
  type: string;
219
233
  match(action: {
220
234
  type: string;
221
- }): action is PayloadAction<string>;
235
+ }): action is PayloadAction<string | TriadicPalette>;
222
236
  };
223
237
  setHarmony: {
224
238
  (payload: ColorHarmony): PayloadAction<ColorHarmony>;
@@ -236,14 +250,14 @@ declare const themeReducer: (state: ThemeState | undefined, action: {
236
250
  }) => ThemeState;
237
251
  declare const selectThemeAppearance: (state: ThemeState) => ThemeAppearance;
238
252
  declare const selectThemeBlur: (state: ThemeState) => boolean;
239
- declare const selectThemeColor: (state: ThemeState) => string;
253
+ declare const selectThemeColor: (state: ThemeState) => string | TriadicPalette;
240
254
  declare const selectThemeHarmony: (state: ThemeState) => ColorHarmony;
241
255
 
242
256
  type ThemeSettings = {
243
257
  appearance: ThemeAppearance;
244
258
  blur: boolean;
245
259
  blurTint: number;
246
- color: string;
260
+ color: string | TriadicPalette;
247
261
  harmony: ColorHarmony;
248
262
  };
249
263
  declare const defaultThemeSettings: ThemeSettings;
@@ -253,17 +267,27 @@ type ThemeSettingsContextType = {
253
267
  };
254
268
  declare const ThemeSettingsContext: react.Context<ThemeSettingsContextType>;
255
269
 
270
+ type NavBarContextType = {
271
+ navigationBar?: ExpoNavigationBarModule;
272
+ onNavBarChange?: (color: string, dark: boolean) => void;
273
+ };
274
+ declare const useNavBarContext: () => NavBarContextType;
275
+ declare const useBlurModule: () => ExpoBlurModule | undefined;
256
276
  type ProviderProps = {
257
- initialValue?: Partial<ThemeSettings>;
258
- onChange?: (settings: ThemeSettings) => void;
259
277
  children: ReactNode;
260
278
  defaults?: PaperDefaults;
279
+ /** Injects expo-blur for `<BlurView>`. Pass `import * as ExpoBlur from 'expo-blur'`; omit to always render BlurView's solid fallback. */
280
+ expoBlur?: ExpoBlurModule;
281
+ initialValue?: Partial<ThemeSettings>;
282
+ /** Injects expo-navigation-bar so the Android nav bar icon style auto-syncs with the theme. Pass `import * as ExpoNavigationBar from 'expo-navigation-bar'`; omit (and don't pass onNavBarChange) to skip nav bar syncing entirely. */
283
+ navigationBar?: ExpoNavigationBarModule;
284
+ onChange?: (settings: ThemeSettings) => void;
261
285
  onNavBarChange?: (color: string, dark: boolean) => void;
262
286
  onReady?: () => void;
263
287
  statusBarProps?: StatusBarProps;
264
288
  style?: StyleProp<ViewStyle>;
265
289
  };
266
- declare function Provider({ initialValue, onChange, children, defaults, onNavBarChange, onReady, statusBarProps, style }: ProviderProps): react.JSX.Element | null;
290
+ declare function Provider({ children, defaults, expoBlur, initialValue, navigationBar, onChange, onNavBarChange, onReady, statusBarProps, style }: ProviderProps): react.JSX.Element | null;
267
291
 
268
292
  declare const useAutoPaperTheme: () => AutoPaperTheme;
269
293
 
@@ -291,10 +315,12 @@ declare const getRgb: (value: string) => RGB | null;
291
315
 
292
316
  declare const getContrastColor: (color: string) => string;
293
317
 
318
+ declare function getThirdColor(colorA: string, colorB: string): string;
319
+
294
320
  declare const getTintTextColor: (tintColor: string, backdropColor: string, tintOpacity: number) => string;
295
321
 
296
322
  declare const getTonalColor: (color: string, lightness: number) => string;
297
323
 
298
324
  declare const isDarkColor: (value: string) => boolean;
299
325
 
300
- export { Appbar, type AppearanceIcons, AppearancePicker, type AutoPaperTheme, BlurView, type BlurViewProps, BottomNavigation, Button, Chip, type ChipProps, type ColorHarmony, ColorPicker, type ColorRoles, Dialog, type DialogProps, FAB, HarmonyPicker, IconButton, type IconButtonProps, Menu, type MenuProps, PalettePicker, type PaletteWeights, type PaperDefaults, Provider, type ProviderProps, type RGB, SEMANTIC_BASE_COLORS, type SeedColor, type SemanticColorRoles, TextInput, type ThemeAppearance, type ThemeSettings, ThemeSettingsContext, type ThemeSettingsContextType, type ThemeState, type TriadicPalette, createThemeReducer, defaultColors, defaultThemeSettings, getBlendedColor, getColorRoles, getContrastColor, getHex, getRgb, getTintTextColor, getTonalColor, getTriadicPalette, isDarkColor, selectThemeAppearance, selectThemeBlur, selectThemeColor, selectThemeHarmony, themeActions, themeReducer, useAutoPaperTheme, useBlur, useComputedTheme, usePaperDefaults, useThemeSettings };
326
+ export { Appbar, type AppearanceIcons, AppearancePicker, type AutoPaperTheme, BlurView, type BlurViewProps, BottomNavigation, Button, Chip, type ChipProps, type ColorHarmony, ColorPicker, type ColorRoles, Dialog, type DialogProps, type ExpoBlurModule, type ExpoNavigationBarModule, FAB, HarmonyPicker, IconButton, type IconButtonProps, Menu, type MenuProps, PalettePicker, type PaletteWeights, type PaperDefaults, Provider, type ProviderProps, type RGB, SEMANTIC_BASE_COLORS, type SeedColor, type SemanticColorRoles, TextInput, type ThemeAppearance, type ThemeSettings, ThemeSettingsContext, type ThemeSettingsContextType, type ThemeState, type TriadicPalette, createThemeReducer, defaultColors, defaultThemeSettings, getBlendedColor, getColorRoles, getContrastColor, getHex, getRgb, getThirdColor, getTintTextColor, getTonalColor, getTriadicPalette, isDarkColor, selectThemeAppearance, selectThemeBlur, selectThemeColor, selectThemeHarmony, themeActions, themeReducer, useAutoPaperTheme, useBlur, useBlurModule, useComputedTheme, useNavBarContext, usePaperDefaults, useThemeSettings };
package/dist/index.d.ts CHANGED
@@ -5,7 +5,7 @@ import * as react_native_paper from 'react-native-paper';
5
5
  import { AppbarHeaderProps, MD3Theme, BottomNavigationRoute, BottomNavigationProps, BottomNavigation as BottomNavigation$1, ButtonProps, ChipProps as ChipProps$1, DialogProps as DialogProps$1, DialogTitleProps, DialogContentProps, DialogActionsProps, DialogScrollAreaProps, FABProps, IconButtonProps as IconButtonProps$1, MenuProps as MenuProps$1, MenuItemProps, TextInputProps } from 'react-native-paper';
6
6
  export { AppbarHeaderProps, BottomNavigationProps, BottomNavigationRoute, ButtonProps, FABProps, ChipProps as PaperChipProps, DialogProps as PaperDialogProps, IconButtonProps as PaperIconButtonProps, MenuProps as PaperMenuProps, TextInputProps } from 'react-native-paper';
7
7
  import * as react from 'react';
8
- import react__default, { RefObject, ReactNode } from 'react';
8
+ import react__default, { RefObject, ReactNode, ComponentType } from 'react';
9
9
 
10
10
  declare function useBlur(override?: boolean): boolean;
11
11
 
@@ -51,7 +51,7 @@ type SemanticColorRoles = {
51
51
  type AutoPaperTheme = Omit<MD3Theme, 'colors'> & {
52
52
  colors: MD3Theme['colors'] & SemanticColorRoles;
53
53
  };
54
- declare function useComputedTheme(appearance: ThemeAppearance, color: string, harmony?: ColorHarmony): AutoPaperTheme | null;
54
+ declare function useComputedTheme(appearance: ThemeAppearance, color: string | TriadicPalette, harmony?: ColorHarmony): AutoPaperTheme | null;
55
55
 
56
56
  type AppearanceIcons = Partial<Record<ThemeAppearance, string>>;
57
57
  type Props$3 = {
@@ -62,6 +62,14 @@ type Props$3 = {
62
62
  };
63
63
  declare const AppearancePicker: ({ value, onChange, showLabels, icons }: Props$3) => react.JSX.Element;
64
64
 
65
+ interface ExpoBlurModule {
66
+ BlurView: ComponentType<{
67
+ children?: ReactNode;
68
+ style?: StyleProp<ViewStyle>;
69
+ tint?: any;
70
+ [key: string]: unknown;
71
+ }>;
72
+ }
65
73
  type ExpoBlurTint = 'light' | 'dark' | 'default' | 'extraLight' | 'regular' | 'prominent' | 'systemUltraThinMaterial' | 'systemThinMaterial' | 'systemMaterial' | 'systemThickMaterial' | 'systemChromeMaterial' | 'systemUltraThinMaterialLight' | 'systemThinMaterialLight' | 'systemMaterialLight' | 'systemThickMaterialLight' | 'systemChromeMaterialLight' | 'systemUltraThinMaterialDark' | 'systemThinMaterialDark' | 'systemMaterialDark' | 'systemThickMaterialDark' | 'systemChromeMaterialDark';
66
74
  type ExpoBlurMethod = 'none' | 'dimezisBlurView' | 'dimezisBlurViewSdk31Plus';
67
75
  type ExpoBlurViewProps = {
@@ -170,6 +178,12 @@ declare const PalettePicker: ({ value, onChange, harmony, weights, colors, blur:
170
178
 
171
179
  declare const TextInput: react.ForwardRefExoticComponent<Omit<TextInputProps, "ref"> & react.RefAttributes<TextInput$1>>;
172
180
 
181
+ interface ExpoNavigationBarModule {
182
+ NavigationBar: {
183
+ setStyle: (style: 'light' | 'dark') => void;
184
+ };
185
+ }
186
+
173
187
  type PaperDefaults = {
174
188
  AppbarHeader?: Partial<AppbarHeaderProps>;
175
189
  BottomNavigation?: Partial<BottomNavigationProps<BottomNavigationRoute>>;
@@ -184,7 +198,7 @@ declare function usePaperDefaults(): PaperDefaults;
184
198
  type ThemeState = {
185
199
  appearance: ThemeAppearance;
186
200
  blur: boolean;
187
- color: string;
201
+ color: string | TriadicPalette;
188
202
  harmony: ColorHarmony;
189
203
  };
190
204
  type PayloadAction<P> = {
@@ -214,11 +228,11 @@ declare const themeActions: {
214
228
  }): action is PayloadAction<boolean>;
215
229
  };
216
230
  setColor: {
217
- (payload: string): PayloadAction<string>;
231
+ (payload: string | TriadicPalette): PayloadAction<string | TriadicPalette>;
218
232
  type: string;
219
233
  match(action: {
220
234
  type: string;
221
- }): action is PayloadAction<string>;
235
+ }): action is PayloadAction<string | TriadicPalette>;
222
236
  };
223
237
  setHarmony: {
224
238
  (payload: ColorHarmony): PayloadAction<ColorHarmony>;
@@ -236,14 +250,14 @@ declare const themeReducer: (state: ThemeState | undefined, action: {
236
250
  }) => ThemeState;
237
251
  declare const selectThemeAppearance: (state: ThemeState) => ThemeAppearance;
238
252
  declare const selectThemeBlur: (state: ThemeState) => boolean;
239
- declare const selectThemeColor: (state: ThemeState) => string;
253
+ declare const selectThemeColor: (state: ThemeState) => string | TriadicPalette;
240
254
  declare const selectThemeHarmony: (state: ThemeState) => ColorHarmony;
241
255
 
242
256
  type ThemeSettings = {
243
257
  appearance: ThemeAppearance;
244
258
  blur: boolean;
245
259
  blurTint: number;
246
- color: string;
260
+ color: string | TriadicPalette;
247
261
  harmony: ColorHarmony;
248
262
  };
249
263
  declare const defaultThemeSettings: ThemeSettings;
@@ -253,17 +267,27 @@ type ThemeSettingsContextType = {
253
267
  };
254
268
  declare const ThemeSettingsContext: react.Context<ThemeSettingsContextType>;
255
269
 
270
+ type NavBarContextType = {
271
+ navigationBar?: ExpoNavigationBarModule;
272
+ onNavBarChange?: (color: string, dark: boolean) => void;
273
+ };
274
+ declare const useNavBarContext: () => NavBarContextType;
275
+ declare const useBlurModule: () => ExpoBlurModule | undefined;
256
276
  type ProviderProps = {
257
- initialValue?: Partial<ThemeSettings>;
258
- onChange?: (settings: ThemeSettings) => void;
259
277
  children: ReactNode;
260
278
  defaults?: PaperDefaults;
279
+ /** Injects expo-blur for `<BlurView>`. Pass `import * as ExpoBlur from 'expo-blur'`; omit to always render BlurView's solid fallback. */
280
+ expoBlur?: ExpoBlurModule;
281
+ initialValue?: Partial<ThemeSettings>;
282
+ /** Injects expo-navigation-bar so the Android nav bar icon style auto-syncs with the theme. Pass `import * as ExpoNavigationBar from 'expo-navigation-bar'`; omit (and don't pass onNavBarChange) to skip nav bar syncing entirely. */
283
+ navigationBar?: ExpoNavigationBarModule;
284
+ onChange?: (settings: ThemeSettings) => void;
261
285
  onNavBarChange?: (color: string, dark: boolean) => void;
262
286
  onReady?: () => void;
263
287
  statusBarProps?: StatusBarProps;
264
288
  style?: StyleProp<ViewStyle>;
265
289
  };
266
- declare function Provider({ initialValue, onChange, children, defaults, onNavBarChange, onReady, statusBarProps, style }: ProviderProps): react.JSX.Element | null;
290
+ declare function Provider({ children, defaults, expoBlur, initialValue, navigationBar, onChange, onNavBarChange, onReady, statusBarProps, style }: ProviderProps): react.JSX.Element | null;
267
291
 
268
292
  declare const useAutoPaperTheme: () => AutoPaperTheme;
269
293
 
@@ -291,10 +315,12 @@ declare const getRgb: (value: string) => RGB | null;
291
315
 
292
316
  declare const getContrastColor: (color: string) => string;
293
317
 
318
+ declare function getThirdColor(colorA: string, colorB: string): string;
319
+
294
320
  declare const getTintTextColor: (tintColor: string, backdropColor: string, tintOpacity: number) => string;
295
321
 
296
322
  declare const getTonalColor: (color: string, lightness: number) => string;
297
323
 
298
324
  declare const isDarkColor: (value: string) => boolean;
299
325
 
300
- export { Appbar, type AppearanceIcons, AppearancePicker, type AutoPaperTheme, BlurView, type BlurViewProps, BottomNavigation, Button, Chip, type ChipProps, type ColorHarmony, ColorPicker, type ColorRoles, Dialog, type DialogProps, FAB, HarmonyPicker, IconButton, type IconButtonProps, Menu, type MenuProps, PalettePicker, type PaletteWeights, type PaperDefaults, Provider, type ProviderProps, type RGB, SEMANTIC_BASE_COLORS, type SeedColor, type SemanticColorRoles, TextInput, type ThemeAppearance, type ThemeSettings, ThemeSettingsContext, type ThemeSettingsContextType, type ThemeState, type TriadicPalette, createThemeReducer, defaultColors, defaultThemeSettings, getBlendedColor, getColorRoles, getContrastColor, getHex, getRgb, getTintTextColor, getTonalColor, getTriadicPalette, isDarkColor, selectThemeAppearance, selectThemeBlur, selectThemeColor, selectThemeHarmony, themeActions, themeReducer, useAutoPaperTheme, useBlur, useComputedTheme, usePaperDefaults, useThemeSettings };
326
+ export { Appbar, type AppearanceIcons, AppearancePicker, type AutoPaperTheme, BlurView, type BlurViewProps, BottomNavigation, Button, Chip, type ChipProps, type ColorHarmony, ColorPicker, type ColorRoles, Dialog, type DialogProps, type ExpoBlurModule, type ExpoNavigationBarModule, FAB, HarmonyPicker, IconButton, type IconButtonProps, Menu, type MenuProps, PalettePicker, type PaletteWeights, type PaperDefaults, Provider, type ProviderProps, type RGB, SEMANTIC_BASE_COLORS, type SeedColor, type SemanticColorRoles, TextInput, type ThemeAppearance, type ThemeSettings, ThemeSettingsContext, type ThemeSettingsContextType, type ThemeState, type TriadicPalette, createThemeReducer, defaultColors, defaultThemeSettings, getBlendedColor, getColorRoles, getContrastColor, getHex, getRgb, getThirdColor, getTintTextColor, getTonalColor, getTriadicPalette, isDarkColor, selectThemeAppearance, selectThemeBlur, selectThemeColor, selectThemeHarmony, themeActions, themeReducer, useAutoPaperTheme, useBlur, useBlurModule, useComputedTheme, useNavBarContext, usePaperDefaults, useThemeSettings };