@rific/auto-paper 0.12.3 → 0.13.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
@@ -34,7 +34,7 @@ npm install expo-blur # frosted-glass BlurView
34
34
  npm install expo-navigation-bar # (>= 56.0.0, SDK 54+) auto-syncs Android nav bar icon style to the theme when BottomNavigation is mounted
35
35
  ```
36
36
 
37
- These integrations are opt-in: pass them to `Provider` (`expoBlur`, `navigationBar`, and `reanimated` — see the prop table below), and the relevant wrappers pick them up automatically. Omit them and you still get working fallbacks: `BlurView` renders its solid (non-blur) look, `BottomNavigation` simply skips nav-bar syncing, and `Dialog` treats `animatedStyle` as a no-op unless a reanimated module is injected.
37
+ These integrations are opt-in: pass them to `Provider` (`expoBlur`, `maskedView`, `navigationBar`, and `reanimated` - see the prop table below), and the relevant wrappers pick them up automatically. Omit them and you still get working fallbacks: `BlurView` renders its solid (non-blur) look, `FadingScrollView` scrolls without its fade on iOS and Android, `BottomNavigation` simply skips nav-bar syncing, and `Dialog` treats `animatedStyle` as a no-op unless a reanimated module is injected.
38
38
 
39
39
  The exported Redux slice has no dependency on `@reduxjs/toolkit`: it works with RTK stores, vanilla Redux, or no Redux at all.
40
40
 
@@ -221,7 +221,7 @@ export function Theme({ children }: { children: React.ReactNode }) {
221
221
  }
222
222
  ```
223
223
 
224
- Keep the scope honest: this only replaces the final `<Provider initialValue={...} onChange={...} onReady={...}>` prop list with `<Provider {...bridgeProps}>`. It doesn't do the `useSelector`/`useDispatch` wiring above it — that's still yours to write, since `RootState`'s shape is app-local and this package has no opinion on it (or on state management being Redux at all; `useThemeBridgeProps` takes plain values and callbacks, not a `dispatch` function).
224
+ Keep the scope honest: this only replaces the final `<Provider initialValue={...} onChange={...} onReady={...}>` prop list with `<Provider {...bridgeProps}>`. It doesn't do the `useSelector`/`useDispatch` wiring above it - that's still yours to write, since `RootState`'s shape is app-local and this package has no opinion on it (or on state management being Redux at all; `useThemeBridgeProps` takes plain values and callbacks, not a `dispatch` function).
225
225
 
226
226
  ### With `useComputedTheme`
227
227
 
@@ -266,7 +266,8 @@ export default function App() {
266
266
  | `children` | `ReactNode` | |
267
267
  | `defaults` | `PaperDefaults` | Prop defaults for wrapper components (see below) |
268
268
  | `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. On Android, expo-blur only blurs when given a `blurTarget` and a `blurMethod` (`'dimezisBlurView'`, or `'dimezisBlurViewSdk31Plus'` on API 31+); without both, `<BlurView>` renders the solid fallback there too, rather than expo-blur's unblurred translucent tint. |
269
- | `fontFamily` | `string` | Applied to every Paper typography variant (`bodyLarge`, `headlineMedium`, `labelSmall`, ...) via `configureFonts`'s flat-config mode — each variant keeps its own MD3 fontSize/lineHeight/weight, only fontFamily changes. Omit to keep each platform's system font. |
269
+ | `maskedView` | `MaskedViewModule` | Injects `@react-native-masked-view/masked-view` (`import MaskedView from '@react-native-masked-view/masked-view'`) so `<FadingScrollView>` fades its content out above a pinned footer on iOS and Android. Omit to have it scroll without the fade there; web needs nothing. |
270
+ | `fontFamily` | `string` | Applied to every Paper typography variant (`bodyLarge`, `headlineMedium`, `labelSmall`, ...) via `configureFonts`'s flat-config mode - each variant keeps its own MD3 fontSize/lineHeight/weight, only fontFamily changes. Omit to keep each platform's system font. |
270
271
  | `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. |
271
272
  | `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 |
272
273
  | `onReady` | `() => void` | Called once when the theme first resolves |
@@ -288,7 +289,7 @@ export default function App() {
288
289
 
289
290
  ### `useThemeBridgeProps({ initialValue, onChange, onReady })`
290
291
 
291
- Reshapes already-resolved values into the exact `Pick<ProviderProps, 'initialValue' | 'onChange' | 'onReady'>` shape `Provider` expects, memoized on those three fields so the returned object is referentially stable across re-renders until an input actually changes. Meant for a consuming app's own Redux-backed "Theme" component — see "With Redux" above — but takes plain values and callbacks rather than a `dispatch` function or anything Redux-specific, so it works with any state management, or none.
292
+ Reshapes already-resolved values into the exact `Pick<ProviderProps, 'initialValue' | 'onChange' | 'onReady'>` shape `Provider` expects, memoized on those three fields so the returned object is referentially stable across re-renders until an input actually changes. Meant for a consuming app's own Redux-backed "Theme" component - see "With Redux" above - but takes plain values and callbacks rather than a `dispatch` function or anything Redux-specific, so it works with any state management, or none.
292
293
 
293
294
  It only replaces the final prop list handed to `Provider`; it does not do any `useSelector`/`dispatch` wiring itself, and `onReady` is threaded through unchanged.
294
295
 
@@ -378,7 +379,7 @@ function SettingsScreen() {
378
379
 
379
380
  ### `AutoAppearancePicker`
380
381
 
381
- `AppearancePicker` wired straight to the `Provider`'s own `ThemeSettings` — for the common case where the appearance being edited IS the whole app's own theme. Reads/writes `useThemeSettings()` internally, so it takes neither `value` nor `onChange`; every other `AppearancePicker` prop still passes through. Reach for the plain `AppearancePicker` instead when it needs to be controlled by something other than the global theme (a local preview before committing, one-off UI unrelated to `Provider`).
382
+ `AppearancePicker` wired straight to the `Provider`'s own `ThemeSettings` - for the common case where the appearance being edited IS the whole app's own theme. Reads/writes `useThemeSettings()` internally, so it takes neither `value` nor `onChange`; every other `AppearancePicker` prop still passes through. Reach for the plain `AppearancePicker` instead when it needs to be controlled by something other than the global theme (a local preview before committing, one-off UI unrelated to `Provider`).
382
383
 
383
384
  ```tsx
384
385
  import { AutoAppearancePicker } from '@rific/auto-paper'
@@ -390,7 +391,7 @@ function SettingsScreen() {
390
391
 
391
392
  ### `HarmonyPicker`
392
393
 
393
- Switches between the 6 `ColorHarmony` modes (`triadic`, `split-complementary`, `analogous`, `square`, `complementary`, `double-split`) via `react-native-paper`'s `SegmentedButtons`. `PalettePicker` can embed this same picker in its own dialog instead of standing alone — see `onHarmonyChange` below.
394
+ Switches between the 6 `ColorHarmony` modes (`triadic`, `split-complementary`, `analogous`, `square`, `complementary`, `double-split`) via `react-native-paper`'s `SegmentedButtons`. `PalettePicker` can embed this same picker in its own dialog instead of standing alone - see `onHarmonyChange` below.
394
395
 
395
396
  ```tsx
396
397
  import { HarmonyPicker, useThemeSettings } from '@rific/auto-paper'
@@ -405,7 +406,7 @@ function SettingsScreen() {
405
406
  |---|---|---|
406
407
  | `value` | `ColorHarmony` | Currently selected harmony |
407
408
  | `onChange` | `(harmony: ColorHarmony) => void` | Called when a segment is tapped |
408
- | `showLabels` | `boolean` | Set `false` for icon-only segments. Also lowers Paper's default 76px-per-segment minimum width down to 0, so all 6 segments can always shrink to fit — however narrow the container, they resize down together instead of overflowing it. `accessibilityLabel` is always set regardless, so screen readers still announce the full harmony name either way. Defaults to `true` |
409
+ | `showLabels` | `boolean` | Set `false` for icon-only segments. Also lowers Paper's default 76px-per-segment minimum width down to 0, so all 6 segments can always shrink to fit - however narrow the container, they resize down together instead of overflowing it. `accessibilityLabel` is always set regardless, so screen readers still announce the full harmony name either way. Defaults to `true` |
409
410
  | `checkedColor` / `uncheckedColor` | `string` | Icon color for the checked and unchecked segments, matching Paper's own segmented-button vocabulary |
410
411
  | `checkedContainerColor` / `uncheckedContainerColor` | `string` | Fill color for the checked and unchecked segments. Omit any of these four color props to fall back to Paper's default segmented-button styling |
411
412
 
@@ -425,6 +426,29 @@ import { Appbar } from '@rific/auto-paper'
425
426
 
426
427
  `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`.
427
428
 
429
+ ### `BlurView`
430
+
431
+ A frosted-glass surface that follows the theme. It blurs when `blur` is true (the default) and `expoBlur` is injected into `Provider` (on Android, only with a `blurTarget` and a `blurMethod`, see the `Provider` table); otherwise it renders a solid `surface` (or `surfaceVariant`) background. `Dialog` and `Menu` use it for their surfaces, passing the ambient `settings.blur`.
432
+
433
+ ```tsx
434
+ import { BlurView, useBlur } from '@rific/auto-paper'
435
+
436
+ <BlurView blur={useBlur()} elevation={2} style={{ borderRadius: 16, overflow: 'hidden' }}>
437
+ <Text>Frosted</Text>
438
+ </BlurView>
439
+ ```
440
+
441
+ | Prop | Type | Description |
442
+ |---|---|---|
443
+ | `blur` | `boolean` | Whether to blur at all (default `true`). Flipping it while mounted never remounts the children: their state, scroll position and focus survive |
444
+ | `elevation` | `0`-`5` | Tints the surface with `colors.primary` at the MD3 elevation opacity |
445
+ | `variant` | `'primary' \| 'secondary' \| 'tertiary' \| 'error' \| 'surface' \| 'surfaceVariant'` | Theme-derived tint (or, for `surfaceVariant`, the base surface color) |
446
+ | `tintColor` / `tintOpacity` | `string` / `number` | An explicit tint overlay, overriding `variant` and `elevation` |
447
+ | `intensity`, `blurMethod`, `blurTarget`, `blurReductionFactor` | | Passed to expo-blur's `BlurView`, as in expo-blur |
448
+ | ...all `ViewProps` | | Applied to the outer `View` |
449
+
450
+ Whether or not it blurs, `BlurView` is always the same outer `View`, holding the blurTint surface layer (at `settings.blurTint`), the tint, and the children. On iOS and Android the blur is an absolutely filled expo-blur layer behind them, the same structure as expo-blur's own native `BlurView`, so (as with expo-blur) rounded corners only clip the blur when the style also sets `overflow: 'hidden'`. On web the outer `View` is itself the CSS `backdrop-filter` element, styled the way expo-blur's web `BlurView` styles its own, so an opacity animated on `BlurView` (as `Dialog` and `Menu` do on web) fades the blur correctly instead of cutting it off.
451
+
428
452
  ### `BottomNavigation`
429
453
 
430
454
  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.
@@ -491,6 +515,26 @@ function SettingsDialog({ visible }: { visible: boolean }) {
491
515
 
492
516
  `DialogProps` is exported from `@rific/auto-paper` and extends `react-native-paper`'s `DialogProps` with the `blur` and `animatedStyle` fields. Use `PaperDialogProps` if you need the base paper type.
493
517
 
518
+ ### `FadingScrollView`
519
+
520
+ A vertical `ScrollView` whose content fades to transparent over `fadeHeight` (default `SCROLL_FADE_HEIGHT`, 24) at each edge while there is more to scroll past it: at the bottom until the end is reached (the cue that rows continue below a pinned footer, such as a dialog's Done button), and at the top once scrolled down (never at rest, so a header at the top is never dimmed). It masks the content instead of painting over it, so whatever is behind it (a blurred `Dialog`/`BlurView` surface or a solid one, light or dark) stays one continuous surface. A second `BlurView` as a frosted footer leaves a seam instead: a blur nested inside a blurred card can't frost the card's own content.
521
+
522
+ ```tsx
523
+ import MaskedView from '@react-native-masked-view/masked-view'
524
+ import { Dialog, FadingScrollView, Provider } from '@rific/auto-paper'
525
+
526
+ <Provider maskedView={MaskedView}>
527
+ <Dialog visible onDismiss={close}>
528
+ <Dialog.ScrollArea>
529
+ <FadingScrollView>{rows}</FadingScrollView>
530
+ </Dialog.ScrollArea>
531
+ <Dialog.Actions>{done}</Dialog.Actions>
532
+ </Dialog>
533
+ </Provider>
534
+ ```
535
+
536
+ On iOS and Android it needs `maskedView` injected into `Provider` (and React Native 0.77+, for the native gradient it masks with); without it, it scrolls with no fade. On web it uses a CSS `mask-image` and needs nothing (react-native-masked-view's web build doesn't mask). `style` goes on the outer box, so `flexGrow`/`flexShrink`/`alignSelf` work as on a plain `ScrollView`; every other prop, `onScroll`/`onLayout`/`onContentSizeChange` included, reaches the `ScrollView`.
537
+
494
538
  ### `IconButton`
495
539
 
496
540
  A thin wrapper around `react-native-paper`'s `IconButton` that adds a `variant` prop for applying theme-derived container and icon colors.
@@ -514,7 +558,7 @@ import { IconButton } from '@rific/auto-paper'
514
558
 
515
559
  ### `PalettePicker`
516
560
 
517
- 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. Pass `onHarmonyChange` to fold a compact, icon-only `HarmonyPicker` row into the same dialog, above the swatch grid — every swatch's own pie reshapes live as harmony changes, so there's one place to tune both instead of two separate controls. Omit it and this renders exactly as a plain color-only picker always has.
561
+ 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. Pass `onHarmonyChange` to fold a compact, icon-only `HarmonyPicker` row into the same dialog, above the swatch grid - every swatch's own pie reshapes live as harmony changes, so there's one place to tune both instead of two separate controls. Omit it and this renders exactly as a plain color-only picker always has.
518
562
 
519
563
  ```tsx
520
564
  import { PalettePicker, useThemeSettings } from '@rific/auto-paper'
@@ -537,7 +581,7 @@ function SettingsScreen() {
537
581
 
538
582
  ### `AutoPalettePicker`
539
583
 
540
- `PalettePicker` wired straight to the `Provider`'s own `ThemeSettings` — both color AND harmony — for the common case where the palette being edited IS the whole app's own theme. Reads/writes `useThemeSettings()` internally (narrowing `ThemeSettings.color`'s `string | TriadicPalette` down to a plain string via `resolveSeedColor`), so it takes none of `value`/`onChange`/`harmony`/`onHarmonyChange`; `weights`/`colors`/`blur` still pass through. Reach for the plain `PalettePicker` instead when it needs to be controlled by something other than the global theme.
584
+ `PalettePicker` wired straight to the `Provider`'s own `ThemeSettings` - both color AND harmony - for the common case where the palette being edited IS the whole app's own theme. Reads/writes `useThemeSettings()` internally (narrowing `ThemeSettings.color`'s `string | TriadicPalette` down to a plain string via `resolveSeedColor`), so it takes none of `value`/`onChange`/`harmony`/`onHarmonyChange`; `weights`/`colors`/`blur` still pass through. Reach for the plain `PalettePicker` instead when it needs to be controlled by something other than the global theme.
541
585
 
542
586
  ```tsx
543
587
  import { AutoPalettePicker } from '@rific/auto-paper'
package/dist/index.d.mts CHANGED
@@ -1,11 +1,11 @@
1
1
  import * as react_native_paper_lib_typescript_utils_forwardRef from 'react-native-paper/lib/typescript/utils/forwardRef';
2
2
  import * as react_native from 'react-native';
3
- import { View, ViewProps, StyleProp, ViewStyle, TextInput as TextInput$1, StatusBarProps } from 'react-native';
3
+ import { View, ViewProps, StyleProp, ViewStyle, ScrollViewProps, TextInput as TextInput$1, StatusBarProps } from 'react-native';
4
4
  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, ComponentType } from 'react';
8
+ import react__default, { RefObject, ReactNode, ComponentType, ReactElement } from 'react';
9
9
  import * as _rific_core from '@rific/core';
10
10
  import { SettingsContextValue } from '@rific/core';
11
11
 
@@ -133,7 +133,7 @@ type BlurViewProps = ExpoBlurViewProps & {
133
133
  tintOpacity?: number;
134
134
  variant?: 'primary' | 'secondary' | 'tertiary' | 'error' | 'surface' | 'surfaceVariant';
135
135
  };
136
- declare const BlurView: ({ blur, children, elevation, style, tintColor, tintOpacity, variant, ...props }: BlurViewProps) => react.JSX.Element;
136
+ declare const BlurView: ({ blur, blurMethod, blurReductionFactor, blurTarget, children, elevation, experimentalBlurMethod, intensity, style, tint: _tint, tintColor, tintOpacity, variant, ...props }: BlurViewProps) => react.JSX.Element;
137
137
 
138
138
  declare function BottomNavigationComponent<Route extends BottomNavigationRoute>(props: BottomNavigationProps<Route>): react__default.JSX.Element;
139
139
  declare namespace BottomNavigationComponent {
@@ -181,6 +181,18 @@ declare const Dialog: typeof DialogComponent;
181
181
 
182
182
  declare function FAB(props: FABProps): react.JSX.Element;
183
183
 
184
+ type MaskedViewModule = ComponentType<{
185
+ children?: ReactNode;
186
+ maskElement: ReactElement;
187
+ style?: StyleProp<ViewStyle>;
188
+ }>;
189
+ declare const SCROLL_FADE_HEIGHT = 24;
190
+ type FadingScrollViewProps = Omit<ScrollViewProps, 'style'> & {
191
+ style?: StyleProp<ViewStyle>;
192
+ fadeHeight?: number;
193
+ };
194
+ declare function FadingScrollView({ style, fadeHeight, onScroll, onLayout, onContentSizeChange, scrollEventThrottle, children, ...rest }: FadingScrollViewProps): react.JSX.Element;
195
+
184
196
  type Props = {
185
197
  value: ColorHarmony;
186
198
  onChange: (harmony: ColorHarmony) => void;
@@ -292,18 +304,21 @@ type NavBarContextType = {
292
304
  declare const useNavBarContext: () => NavBarContextType;
293
305
  declare const useBlurModule: () => ExpoBlurModule | undefined;
294
306
  declare const useReanimatedModule: () => ReanimatedModule | undefined;
307
+ declare const useMaskedViewModule: () => MaskedViewModule | undefined;
295
308
  type ProviderProps = {
296
309
  children: ReactNode;
297
310
  defaults?: PaperDefaults;
298
311
  /** Injects expo-blur for `<BlurView>`. Pass `import * as ExpoBlur from 'expo-blur'`; omit to always render BlurView's solid fallback. */
299
312
  expoBlur?: ExpoBlurModule;
300
313
  /** Applied to every Paper typography variant (bodyLarge, headlineMedium, labelSmall, ...) via
301
- * `configureFonts`'s flat-config mode — each variant keeps its own MD3 fontSize/lineHeight/weight,
314
+ * `configureFonts`'s flat-config mode - each variant keeps its own MD3 fontSize/lineHeight/weight,
302
315
  * only fontFamily changes. The one-line way to reskin an app's whole text to a custom typeface,
303
316
  * instead of passing `fontFamily` to every individual Text/TextInput/Button across the app. Omit
304
317
  * to keep each platform's system font (MD3's own default). */
305
318
  fontFamily?: string;
306
319
  initialValue?: Partial<ThemeSettings>;
320
+ /** Injects @react-native-masked-view/masked-view so `<FadingScrollView>` can fade its content out above a pinned footer on iOS and Android. Pass `import MaskedView from '@react-native-masked-view/masked-view'`; omit to have it scroll without the fade there (web never needs it). */
321
+ maskedView?: MaskedViewModule;
307
322
  /** 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. */
308
323
  navigationBar?: ExpoNavigationBarModule;
309
324
  onChange?: (settings: ThemeSettings) => void;
@@ -314,7 +329,7 @@ type ProviderProps = {
314
329
  statusBarProps?: StatusBarProps;
315
330
  style?: StyleProp<ViewStyle>;
316
331
  };
317
- declare function Provider({ children, defaults, expoBlur, fontFamily, initialValue, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBarProps, style }: ProviderProps): react.JSX.Element;
332
+ declare function Provider({ children, defaults, expoBlur, fontFamily, initialValue, maskedView, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBarProps, style }: ProviderProps): react.JSX.Element;
318
333
 
319
334
  declare const useAutoPaperTheme: () => AutoPaperTheme;
320
335
 
@@ -393,4 +408,4 @@ declare const isDarkColor: (value: string) => boolean;
393
408
 
394
409
  declare const resolveSeedColor: (color: string | TriadicPalette) => string;
395
410
 
396
- export { Appbar, type AppearanceIcons, AppearancePicker, AutoAppearancePicker, AutoPalettePicker, 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, type ReanimatedModule, SEMANTIC_BASE_COLORS, type SeedColor, type SemanticColorRoles, TextInput, type ThemeAppearance, type ThemeBridgeProps, type ThemeSettings, ThemeSettingsContext, type ThemeSettingsContextType, type ThemeState, type TriadicPalette, createThemeReducer, defaultColors, defaultThemeSettings, getBlendedColor, getColorRoles, getContrastColor, getHex, getRgb, getThirdColor, getTintTextColor, getTonalColor, getTriadicPalette, isDarkColor, resolveSeedColor, selectThemeAppearance, selectThemeBlur, selectThemeColor, selectThemeHarmony, themeActions, themeReducer, useAutoPaperTheme, useBlur, useBlurModule, useComputedTheme, useNavBarContext, usePaperDefaults, useReanimatedModule, useThemeBridgeProps, useThemeSettings };
411
+ export { Appbar, type AppearanceIcons, AppearancePicker, AutoAppearancePicker, AutoPalettePicker, type AutoPaperTheme, BlurView, type BlurViewProps, BottomNavigation, Button, Chip, type ChipProps, type ColorHarmony, ColorPicker, type ColorRoles, Dialog, type DialogProps, type ExpoBlurModule, type ExpoNavigationBarModule, FAB, FadingScrollView, type FadingScrollViewProps, HarmonyPicker, IconButton, type IconButtonProps, type MaskedViewModule, Menu, type MenuProps, PalettePicker, type PaletteWeights, type PaperDefaults, Provider, type ProviderProps, type RGB, type ReanimatedModule, SCROLL_FADE_HEIGHT, SEMANTIC_BASE_COLORS, type SeedColor, type SemanticColorRoles, TextInput, type ThemeAppearance, type ThemeBridgeProps, type ThemeSettings, ThemeSettingsContext, type ThemeSettingsContextType, type ThemeState, type TriadicPalette, createThemeReducer, defaultColors, defaultThemeSettings, getBlendedColor, getColorRoles, getContrastColor, getHex, getRgb, getThirdColor, getTintTextColor, getTonalColor, getTriadicPalette, isDarkColor, resolveSeedColor, selectThemeAppearance, selectThemeBlur, selectThemeColor, selectThemeHarmony, themeActions, themeReducer, useAutoPaperTheme, useBlur, useBlurModule, useComputedTheme, useMaskedViewModule, useNavBarContext, usePaperDefaults, useReanimatedModule, useThemeBridgeProps, useThemeSettings };
package/dist/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import * as react_native_paper_lib_typescript_utils_forwardRef from 'react-native-paper/lib/typescript/utils/forwardRef';
2
2
  import * as react_native from 'react-native';
3
- import { View, ViewProps, StyleProp, ViewStyle, TextInput as TextInput$1, StatusBarProps } from 'react-native';
3
+ import { View, ViewProps, StyleProp, ViewStyle, ScrollViewProps, TextInput as TextInput$1, StatusBarProps } from 'react-native';
4
4
  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, ComponentType } from 'react';
8
+ import react__default, { RefObject, ReactNode, ComponentType, ReactElement } from 'react';
9
9
  import * as _rific_core from '@rific/core';
10
10
  import { SettingsContextValue } from '@rific/core';
11
11
 
@@ -133,7 +133,7 @@ type BlurViewProps = ExpoBlurViewProps & {
133
133
  tintOpacity?: number;
134
134
  variant?: 'primary' | 'secondary' | 'tertiary' | 'error' | 'surface' | 'surfaceVariant';
135
135
  };
136
- declare const BlurView: ({ blur, children, elevation, style, tintColor, tintOpacity, variant, ...props }: BlurViewProps) => react.JSX.Element;
136
+ declare const BlurView: ({ blur, blurMethod, blurReductionFactor, blurTarget, children, elevation, experimentalBlurMethod, intensity, style, tint: _tint, tintColor, tintOpacity, variant, ...props }: BlurViewProps) => react.JSX.Element;
137
137
 
138
138
  declare function BottomNavigationComponent<Route extends BottomNavigationRoute>(props: BottomNavigationProps<Route>): react__default.JSX.Element;
139
139
  declare namespace BottomNavigationComponent {
@@ -181,6 +181,18 @@ declare const Dialog: typeof DialogComponent;
181
181
 
182
182
  declare function FAB(props: FABProps): react.JSX.Element;
183
183
 
184
+ type MaskedViewModule = ComponentType<{
185
+ children?: ReactNode;
186
+ maskElement: ReactElement;
187
+ style?: StyleProp<ViewStyle>;
188
+ }>;
189
+ declare const SCROLL_FADE_HEIGHT = 24;
190
+ type FadingScrollViewProps = Omit<ScrollViewProps, 'style'> & {
191
+ style?: StyleProp<ViewStyle>;
192
+ fadeHeight?: number;
193
+ };
194
+ declare function FadingScrollView({ style, fadeHeight, onScroll, onLayout, onContentSizeChange, scrollEventThrottle, children, ...rest }: FadingScrollViewProps): react.JSX.Element;
195
+
184
196
  type Props = {
185
197
  value: ColorHarmony;
186
198
  onChange: (harmony: ColorHarmony) => void;
@@ -292,18 +304,21 @@ type NavBarContextType = {
292
304
  declare const useNavBarContext: () => NavBarContextType;
293
305
  declare const useBlurModule: () => ExpoBlurModule | undefined;
294
306
  declare const useReanimatedModule: () => ReanimatedModule | undefined;
307
+ declare const useMaskedViewModule: () => MaskedViewModule | undefined;
295
308
  type ProviderProps = {
296
309
  children: ReactNode;
297
310
  defaults?: PaperDefaults;
298
311
  /** Injects expo-blur for `<BlurView>`. Pass `import * as ExpoBlur from 'expo-blur'`; omit to always render BlurView's solid fallback. */
299
312
  expoBlur?: ExpoBlurModule;
300
313
  /** Applied to every Paper typography variant (bodyLarge, headlineMedium, labelSmall, ...) via
301
- * `configureFonts`'s flat-config mode — each variant keeps its own MD3 fontSize/lineHeight/weight,
314
+ * `configureFonts`'s flat-config mode - each variant keeps its own MD3 fontSize/lineHeight/weight,
302
315
  * only fontFamily changes. The one-line way to reskin an app's whole text to a custom typeface,
303
316
  * instead of passing `fontFamily` to every individual Text/TextInput/Button across the app. Omit
304
317
  * to keep each platform's system font (MD3's own default). */
305
318
  fontFamily?: string;
306
319
  initialValue?: Partial<ThemeSettings>;
320
+ /** Injects @react-native-masked-view/masked-view so `<FadingScrollView>` can fade its content out above a pinned footer on iOS and Android. Pass `import MaskedView from '@react-native-masked-view/masked-view'`; omit to have it scroll without the fade there (web never needs it). */
321
+ maskedView?: MaskedViewModule;
307
322
  /** 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. */
308
323
  navigationBar?: ExpoNavigationBarModule;
309
324
  onChange?: (settings: ThemeSettings) => void;
@@ -314,7 +329,7 @@ type ProviderProps = {
314
329
  statusBarProps?: StatusBarProps;
315
330
  style?: StyleProp<ViewStyle>;
316
331
  };
317
- declare function Provider({ children, defaults, expoBlur, fontFamily, initialValue, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBarProps, style }: ProviderProps): react.JSX.Element;
332
+ declare function Provider({ children, defaults, expoBlur, fontFamily, initialValue, maskedView, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBarProps, style }: ProviderProps): react.JSX.Element;
318
333
 
319
334
  declare const useAutoPaperTheme: () => AutoPaperTheme;
320
335
 
@@ -393,4 +408,4 @@ declare const isDarkColor: (value: string) => boolean;
393
408
 
394
409
  declare const resolveSeedColor: (color: string | TriadicPalette) => string;
395
410
 
396
- export { Appbar, type AppearanceIcons, AppearancePicker, AutoAppearancePicker, AutoPalettePicker, 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, type ReanimatedModule, SEMANTIC_BASE_COLORS, type SeedColor, type SemanticColorRoles, TextInput, type ThemeAppearance, type ThemeBridgeProps, type ThemeSettings, ThemeSettingsContext, type ThemeSettingsContextType, type ThemeState, type TriadicPalette, createThemeReducer, defaultColors, defaultThemeSettings, getBlendedColor, getColorRoles, getContrastColor, getHex, getRgb, getThirdColor, getTintTextColor, getTonalColor, getTriadicPalette, isDarkColor, resolveSeedColor, selectThemeAppearance, selectThemeBlur, selectThemeColor, selectThemeHarmony, themeActions, themeReducer, useAutoPaperTheme, useBlur, useBlurModule, useComputedTheme, useNavBarContext, usePaperDefaults, useReanimatedModule, useThemeBridgeProps, useThemeSettings };
411
+ export { Appbar, type AppearanceIcons, AppearancePicker, AutoAppearancePicker, AutoPalettePicker, type AutoPaperTheme, BlurView, type BlurViewProps, BottomNavigation, Button, Chip, type ChipProps, type ColorHarmony, ColorPicker, type ColorRoles, Dialog, type DialogProps, type ExpoBlurModule, type ExpoNavigationBarModule, FAB, FadingScrollView, type FadingScrollViewProps, HarmonyPicker, IconButton, type IconButtonProps, type MaskedViewModule, Menu, type MenuProps, PalettePicker, type PaletteWeights, type PaperDefaults, Provider, type ProviderProps, type RGB, type ReanimatedModule, SCROLL_FADE_HEIGHT, SEMANTIC_BASE_COLORS, type SeedColor, type SemanticColorRoles, TextInput, type ThemeAppearance, type ThemeBridgeProps, type ThemeSettings, ThemeSettingsContext, type ThemeSettingsContextType, type ThemeState, type TriadicPalette, createThemeReducer, defaultColors, defaultThemeSettings, getBlendedColor, getColorRoles, getContrastColor, getHex, getRgb, getThirdColor, getTintTextColor, getTonalColor, getTriadicPalette, isDarkColor, resolveSeedColor, selectThemeAppearance, selectThemeBlur, selectThemeColor, selectThemeHarmony, themeActions, themeReducer, useAutoPaperTheme, useBlur, useBlurModule, useComputedTheme, useMaskedViewModule, useNavBarContext, usePaperDefaults, useReanimatedModule, useThemeBridgeProps, useThemeSettings };
package/dist/index.js CHANGED
@@ -41,11 +41,13 @@ __export(index_exports, {
41
41
  ColorPicker: () => ColorPicker,
42
42
  Dialog: () => Dialog,
43
43
  FAB: () => FAB,
44
+ FadingScrollView: () => FadingScrollView,
44
45
  HarmonyPicker: () => HarmonyPicker,
45
46
  IconButton: () => IconButton,
46
47
  Menu: () => Menu,
47
48
  PalettePicker: () => PalettePicker,
48
49
  Provider: () => Provider,
50
+ SCROLL_FADE_HEIGHT: () => SCROLL_FADE_HEIGHT,
49
51
  SEMANTIC_BASE_COLORS: () => SEMANTIC_BASE_COLORS,
50
52
  TextInput: () => TextInput,
51
53
  ThemeSettingsContext: () => ThemeSettingsContext,
@@ -73,6 +75,7 @@ __export(index_exports, {
73
75
  useBlur: () => useBlur,
74
76
  useBlurModule: () => useBlurModule,
75
77
  useComputedTheme: () => useComputedTheme,
78
+ useMaskedViewModule: () => useMaskedViewModule,
76
79
  useNavBarContext: () => useNavBarContext,
77
80
  usePaperDefaults: () => usePaperDefaults,
78
81
  useReanimatedModule: () => useReanimatedModule,
@@ -684,11 +687,13 @@ var BlurModuleContext = (0, import_react5.createContext)(void 0);
684
687
  var useBlurModule = () => (0, import_react5.useContext)(BlurModuleContext);
685
688
  var ReanimatedModuleContext = (0, import_react5.createContext)(void 0);
686
689
  var useReanimatedModule = () => (0, import_react5.useContext)(ReanimatedModuleContext);
687
- function Provider({ children, defaults, expoBlur, fontFamily, initialValue, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBarProps, style }) {
688
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ThemeSettingsProvider, { initialValue, onChange, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ThemeProviderBody, { defaults, expoBlur, fontFamily, navigationBar, onNavBarChange, onReady, reanimated, statusBarProps, style, children }) });
690
+ var MaskedViewModuleContext = (0, import_react5.createContext)(void 0);
691
+ var useMaskedViewModule = () => (0, import_react5.useContext)(MaskedViewModuleContext);
692
+ function Provider({ children, defaults, expoBlur, fontFamily, initialValue, maskedView, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBarProps, style }) {
693
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ThemeSettingsProvider, { initialValue, onChange, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ThemeProviderBody, { defaults, expoBlur, fontFamily, maskedView, navigationBar, onNavBarChange, onReady, reanimated, statusBarProps, style, children }) });
689
694
  }
690
695
  var ThemeSettingsProvider = themeSettingsProvider;
691
- function ThemeProviderBody({ children, defaults, expoBlur, fontFamily, navigationBar, onNavBarChange, onReady, reanimated, statusBarProps, style }) {
696
+ function ThemeProviderBody({ children, defaults, expoBlur, fontFamily, maskedView, navigationBar, onNavBarChange, onReady, reanimated, statusBarProps, style }) {
692
697
  const { settings } = useThemeSettingsInternal();
693
698
  const computedTheme = useComputedTheme(settings.appearance, settings.color, settings.harmony);
694
699
  const theme = (0, import_react5.useMemo)(() => {
@@ -706,7 +711,7 @@ function ThemeProviderBody({ children, defaults, expoBlur, fontFamily, navigatio
706
711
  if (!theme) return null;
707
712
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_react_native_paper4.Provider, { theme, children: [
708
713
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native3.StatusBar, { backgroundColor: theme.colors.background, barStyle: theme.dark ? "light-content" : "dark-content", ...statusBarProps }),
709
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PaperDefaultsContext.Provider, { value: defaults ?? {}, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavBarContext.Provider, { value: { navigationBar, onNavBarChange }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(BlurModuleContext.Provider, { value: expoBlur, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ReanimatedModuleContext.Provider, { value: reanimated, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper4.Portal.Host, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native3.View, { style: [styles.flex, { backgroundColor: theme.colors.background }, style], children }) }) }) }) }) })
714
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PaperDefaultsContext.Provider, { value: defaults ?? {}, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(NavBarContext.Provider, { value: { navigationBar, onNavBarChange }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(BlurModuleContext.Provider, { value: expoBlur, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ReanimatedModuleContext.Provider, { value: reanimated, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MaskedViewModuleContext.Provider, { value: maskedView, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native_paper4.Portal.Host, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native3.View, { style: [styles.flex, { backgroundColor: theme.colors.background }, style], children }) }) }) }) }) }) })
710
715
  ] });
711
716
  }
712
717
  var styles = import_react_native3.StyleSheet.create({
@@ -725,7 +730,12 @@ var blursOnAndroid = ({ blurMethod, blurTarget, experimentalBlurMethod }) => {
725
730
  };
726
731
  var ELEVATION_OPACITY = { 0: 0, 1: 0.05, 2: 0.08, 3: 0.11, 4: 0.12, 5: 0.14 };
727
732
  var VARIANT_TINT_OPACITY = { light: 0.12, dark: 0.18 };
728
- var BlurView = ({ blur = true, children, elevation, style, tintColor, tintOpacity, variant = "surface", ...props }) => {
733
+ var getWebBlurStyle = (intensity, dark) => {
734
+ const amount = Math.min(intensity, 100);
735
+ const filter = `saturate(180%) blur(${amount * 0.2}px)`;
736
+ return { backdropFilter: filter, backgroundColor: `rgba(${dark ? "25,25,25" : "249,249,249"},${amount / 100 * 0.78})`, WebkitBackdropFilter: filter };
737
+ };
738
+ var BlurView = ({ blur = true, blurMethod, blurReductionFactor, blurTarget, children, elevation, experimentalBlurMethod, intensity, style, tint: _tint, tintColor, tintOpacity, variant = "surface", ...props }) => {
729
739
  const { dark, colors } = (0, import_react_native_paper5.useTheme)();
730
740
  const { settings } = (0, import_react6.useContext)(ThemeSettingsContext);
731
741
  const expoBlur = useBlurModule();
@@ -734,13 +744,13 @@ var BlurView = ({ blur = true, children, elevation, style, tintColor, tintOpacit
734
744
  const resolvedTintColor = tintColor ?? variantColor ?? (elevation !== void 0 ? colors.primary : void 0);
735
745
  const resolvedTintOpacity = tintOpacity ?? (tintColor ? dark ? 0.24 : 0.16 : variantColor ? dark ? VARIANT_TINT_OPACITY.dark : VARIANT_TINT_OPACITY.light : elevation !== void 0 ? ELEVATION_OPACITY[elevation] : 0);
736
746
  const tint = resolvedTintColor && resolvedTintOpacity > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.View, { style: [import_react_native4.StyleSheet.absoluteFill, { backgroundColor: resolvedTintColor, opacity: resolvedTintOpacity }] }) : null;
737
- if (blur && expoBlur && (import_react_native4.Platform.OS !== "android" || blursOnAndroid(props)))
738
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(expoBlur.BlurView, { ...props, tint: dark ? "dark" : "light", style, children: [
739
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.View, { style: [import_react_native4.StyleSheet.absoluteFill, { backgroundColor: surfaceColor, opacity: settings.blurTint }] }),
740
- tint,
741
- children
742
- ] });
743
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native4.View, { ...props, style: [{ backgroundColor: surfaceColor }, style], children: [
747
+ const blurProps = { blurMethod, blurReductionFactor, blurTarget, experimentalBlurMethod, intensity };
748
+ const blurs = blur && expoBlur !== void 0 && (import_react_native4.Platform.OS !== "android" || blursOnAndroid(blurProps));
749
+ const web = import_react_native4.Platform.OS === "web";
750
+ const containerStyle = !blurs ? [{ backgroundColor: surfaceColor }, style] : web ? [style, getWebBlurStyle(intensity ?? 50, dark)] : style;
751
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_react_native4.View, { ...props, style: containerStyle, children: [
752
+ blurs && !web ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(expoBlur.BlurView, { ...blurProps, style: import_react_native4.StyleSheet.absoluteFill, tint: dark ? "dark" : "light" }) : null,
753
+ blurs ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react_native4.View, { style: [import_react_native4.StyleSheet.absoluteFill, { backgroundColor: surfaceColor, opacity: settings.blurTint }] }) : null,
744
754
  tint,
745
755
  children
746
756
  ] });
@@ -1033,59 +1043,141 @@ function FAB(props) {
1033
1043
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper13.FAB, { ...defaults.FAB, ...props });
1034
1044
  }
1035
1045
 
1046
+ // src/components/FadingScrollView.tsx
1047
+ var import_react11 = require("react");
1048
+ var import_react_native9 = require("react-native");
1049
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1050
+ var SCROLL_FADE_HEIGHT = 24;
1051
+ function FadingScrollView({ style, fadeHeight = SCROLL_FADE_HEIGHT, onScroll, onLayout, onContentSizeChange, scrollEventThrottle = 16, children, ...rest }) {
1052
+ const MaskedView = useMaskedViewModule();
1053
+ const sizes = (0, import_react11.useRef)({ viewport: 0, content: 0, offset: 0 });
1054
+ const [edges, setEdges] = (0, import_react11.useState)(NO_EDGES);
1055
+ const update = (0, import_react11.useCallback)(() => {
1056
+ const { viewport, content, offset } = sizes.current;
1057
+ const above = offset > 1;
1058
+ const below = content - viewport - offset > 1;
1059
+ setEdges((prev) => prev.above === above && prev.below === below ? prev : { above, below });
1060
+ }, []);
1061
+ const scroll = /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1062
+ import_react_native9.ScrollView,
1063
+ {
1064
+ ...rest,
1065
+ style: styles5.fill,
1066
+ scrollEventThrottle,
1067
+ onScroll: (e) => {
1068
+ sizes.current.offset = e.nativeEvent.contentOffset.y;
1069
+ update();
1070
+ onScroll?.(e);
1071
+ },
1072
+ onLayout: (e) => {
1073
+ sizes.current.viewport = e.nativeEvent.layout.height;
1074
+ update();
1075
+ onLayout?.(e);
1076
+ },
1077
+ onContentSizeChange: (width, height) => {
1078
+ sizes.current.content = height;
1079
+ update();
1080
+ onContentSizeChange?.(width, height);
1081
+ },
1082
+ children
1083
+ }
1084
+ );
1085
+ if (import_react_native9.Platform.OS === "web") return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native9.View, { style: [styles5.box, style, (edges.above || edges.below) && webFadeStyle(fadeHeight, edges)], children: scroll });
1086
+ if (!MaskedView) return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native9.View, { style: [styles5.box, style], children: scroll });
1087
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1088
+ MaskedView,
1089
+ {
1090
+ style: [styles5.box, style],
1091
+ maskElement: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react_native9.View, { style: styles5.fill, children: [
1092
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native9.View, { style: [{ height: fadeHeight }, edges.above ? FADE_IN_BAND : styles5.opaque] }),
1093
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native9.View, { style: styles5.fillOpaque }),
1094
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native9.View, { style: [{ height: fadeHeight }, edges.below ? FADE_OUT_BAND : styles5.opaque] })
1095
+ ] }),
1096
+ children: scroll
1097
+ }
1098
+ );
1099
+ }
1100
+ var FADE_IN_BAND = { experimental_backgroundImage: "linear-gradient(transparent, #000)" };
1101
+ var FADE_OUT_BAND = { experimental_backgroundImage: "linear-gradient(#000, transparent)" };
1102
+ var NO_EDGES = { above: false, below: false };
1103
+ function webFadeStyle(fadeHeight, edges) {
1104
+ const top = edges.above ? `transparent 0, #000 ${fadeHeight}px` : "#000 0";
1105
+ const bottom = edges.below ? `#000 calc(100% - ${fadeHeight}px), transparent 100%` : "#000 100%";
1106
+ const mask = `linear-gradient(to bottom, ${top}, ${bottom})`;
1107
+ return { maskImage: mask, WebkitMaskImage: mask };
1108
+ }
1109
+ var styles5 = import_react_native9.StyleSheet.create({
1110
+ // A plain ScrollView's own flex defaults, so it sizes the same in its parent.
1111
+ box: {
1112
+ flexGrow: 1,
1113
+ flexShrink: 1
1114
+ },
1115
+ fill: {
1116
+ flexGrow: 1,
1117
+ flexShrink: 1
1118
+ },
1119
+ fillOpaque: {
1120
+ backgroundColor: "#000",
1121
+ flexGrow: 1
1122
+ },
1123
+ opaque: {
1124
+ backgroundColor: "#000"
1125
+ }
1126
+ });
1127
+
1036
1128
  // src/components/IconButton.tsx
1037
1129
  var import_react_native_paper14 = require("react-native-paper");
1038
- var import_jsx_runtime15 = require("react/jsx-runtime");
1130
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1039
1131
  function IconButton({ variant, iconColor, containerColor, ...props }) {
1040
1132
  const defaults = usePaperDefaults();
1041
1133
  const { colors } = (0, import_react_native_paper14.useTheme)();
1042
1134
  const variantContainerColor = variant === "primary" ? colors.primaryContainer : variant === "secondary" ? colors.secondaryContainer : variant === "tertiary" ? colors.tertiaryContainer : variant === "surface" ? colors.surface : void 0;
1043
1135
  const variantIconColor = variant === "primary" ? colors.onPrimaryContainer : variant === "secondary" ? colors.onSecondaryContainer : variant === "tertiary" ? colors.onTertiaryContainer : variant === "surface" ? colors.onSurface : void 0;
1044
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react_native_paper14.IconButton, { ...defaults.IconButton, containerColor: containerColor ?? variantContainerColor, iconColor: iconColor ?? variantIconColor, ...props });
1136
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper14.IconButton, { ...defaults.IconButton, containerColor: containerColor ?? variantContainerColor, iconColor: iconColor ?? variantIconColor, ...props });
1045
1137
  }
1046
1138
 
1047
1139
  // src/components/Menu.tsx
1048
- var import_react11 = require("react");
1049
- var import_react_native9 = require("react-native");
1140
+ var import_react12 = require("react");
1141
+ var import_react_native10 = require("react-native");
1050
1142
  var import_react_native_paper15 = require("react-native-paper");
1051
- var import_jsx_runtime16 = require("react/jsx-runtime");
1143
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1052
1144
  var ANIMATION_DURATION2 = 250;
1053
- var EASING = import_react_native9.Easing.bezier(0.4, 0, 0.2, 1);
1145
+ var EASING = import_react_native10.Easing.bezier(0.4, 0, 0.2, 1);
1054
1146
  var DEFAULT_ELEVATION = 2;
1055
1147
  var SHADOW_HEIGHT = [0, 1, 2, 4, 6, 8];
1056
1148
  var SHADOW_RADIUS = [0, 3, 6, 8, 10, 12];
1057
- var AnimatedBlurView2 = import_react_native9.Animated.createAnimatedComponent(BlurView);
1149
+ var AnimatedBlurView2 = import_react_native10.Animated.createAnimatedComponent(BlurView);
1058
1150
  var FadingBlurView = ({ blur, children, elevation, theme: themeOverrides, visible }) => {
1059
1151
  const { animation, roundness } = (0, import_react_native_paper15.useTheme)(themeOverrides);
1060
- const [opacity] = (0, import_react11.useState)(() => new import_react_native9.Animated.Value(0));
1061
- const [closing, setClosing] = (0, import_react11.useState)(false);
1152
+ const [opacity] = (0, import_react12.useState)(() => new import_react_native10.Animated.Value(0));
1153
+ const [closing, setClosing] = (0, import_react12.useState)(false);
1062
1154
  if (!visible && !closing) setClosing(true);
1063
- (0, import_react11.useEffect)(() => {
1064
- import_react_native9.Animated.timing(opacity, { duration: animation.scale * ANIMATION_DURATION2, easing: EASING, toValue: closing ? 0 : 1, useNativeDriver: false }).start();
1155
+ (0, import_react12.useEffect)(() => {
1156
+ import_react_native10.Animated.timing(opacity, { duration: animation.scale * ANIMATION_DURATION2, easing: EASING, toValue: closing ? 0 : 1, useNativeDriver: false }).start();
1065
1157
  }, [animation.scale, closing, opacity]);
1066
1158
  const shadow = elevation > 0 ? { shadowColor: "#000000", shadowOffset: { height: SHADOW_HEIGHT[elevation], width: 0 }, shadowOpacity: 0.3, shadowRadius: SHADOW_RADIUS[elevation] } : null;
1067
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(AnimatedBlurView2, { blur, style: [{ borderRadius: roundness, opacity }, shadow], children });
1159
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(AnimatedBlurView2, { blur, style: [{ borderRadius: roundness, opacity }, shadow], children });
1068
1160
  };
1069
1161
  var MenuComponent = ({ blur: blurProp, children, ...props }) => {
1070
1162
  const blur = useBlur(blurProp);
1071
- const web = import_react_native9.Platform.OS === "web";
1072
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper15.Menu, { ...props, contentStyle: [styles5.content, web && styles5.webSurface, props.contentStyle], children: web ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(FadingBlurView, { blur, elevation: props.mode === "flat" ? 0 : props.elevation ?? DEFAULT_ELEVATION, theme: props.theme, visible: props.visible, children }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(BlurView, { blur, children }) });
1163
+ const web = import_react_native10.Platform.OS === "web";
1164
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native_paper15.Menu, { ...props, contentStyle: [styles6.content, web && styles6.webSurface, props.contentStyle], children: web ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FadingBlurView, { blur, elevation: props.mode === "flat" ? 0 : props.elevation ?? DEFAULT_ELEVATION, theme: props.theme, visible: props.visible, children }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(BlurView, { blur, children }) });
1073
1165
  };
1074
1166
  var Menu = Object.assign(MenuComponent, {
1075
1167
  Item: import_react_native_paper15.Menu.Item
1076
1168
  });
1077
- var styles5 = import_react_native9.StyleSheet.create({
1169
+ var styles6 = import_react_native10.StyleSheet.create({
1078
1170
  content: { backgroundColor: "transparent", paddingVertical: 0 },
1079
1171
  webSurface: { opacity: 1, shadowOpacity: 0 }
1080
1172
  });
1081
1173
 
1082
1174
  // src/components/TextInput.tsx
1083
- var import_react12 = require("react");
1175
+ var import_react13 = require("react");
1084
1176
  var import_react_native_paper16 = require("react-native-paper");
1085
- var import_jsx_runtime17 = require("react/jsx-runtime");
1086
- var TextInput = (0, import_react12.forwardRef)(function TextInput2(props, ref) {
1177
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1178
+ var TextInput = (0, import_react13.forwardRef)(function TextInput2(props, ref) {
1087
1179
  const defaults = usePaperDefaults();
1088
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native_paper16.TextInput, { ref, ...defaults.TextInput, ...props });
1180
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_paper16.TextInput, { ref, ...defaults.TextInput, ...props });
1089
1181
  });
1090
1182
 
1091
1183
  // src/redux/themeSlice.ts
@@ -1114,10 +1206,10 @@ var import_react_native_paper17 = require("react-native-paper");
1114
1206
  var useAutoPaperTheme = () => (0, import_react_native_paper17.useTheme)();
1115
1207
 
1116
1208
  // src/useThemeBridgeProps.ts
1117
- var import_react13 = require("react");
1209
+ var import_react14 = require("react");
1118
1210
  function useThemeBridgeProps(props) {
1119
1211
  const { initialValue, onChange, onReady } = props;
1120
- return (0, import_react13.useMemo)(() => ({ initialValue, onChange, onReady }), [initialValue, onChange, onReady]);
1212
+ return (0, import_react14.useMemo)(() => ({ initialValue, onChange, onReady }), [initialValue, onChange, onReady]);
1121
1213
  }
1122
1214
 
1123
1215
  // src/utils/getThirdColor.ts
@@ -1214,11 +1306,13 @@ var getTintTextColor = (tintColor, backdropColor, tintOpacity) => {
1214
1306
  ColorPicker,
1215
1307
  Dialog,
1216
1308
  FAB,
1309
+ FadingScrollView,
1217
1310
  HarmonyPicker,
1218
1311
  IconButton,
1219
1312
  Menu,
1220
1313
  PalettePicker,
1221
1314
  Provider,
1315
+ SCROLL_FADE_HEIGHT,
1222
1316
  SEMANTIC_BASE_COLORS,
1223
1317
  TextInput,
1224
1318
  ThemeSettingsContext,
@@ -1246,6 +1340,7 @@ var getTintTextColor = (tintColor, backdropColor, tintOpacity) => {
1246
1340
  useBlur,
1247
1341
  useBlurModule,
1248
1342
  useComputedTheme,
1343
+ useMaskedViewModule,
1249
1344
  useNavBarContext,
1250
1345
  usePaperDefaults,
1251
1346
  useReanimatedModule,