@rific/auto-paper 0.9.0 → 0.9.2

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
@@ -33,7 +33,7 @@ npm install expo-blur # frosted-glass BlurView
33
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
34
34
  ```
35
35
 
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.
36
+ 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
37
 
38
38
  The exported Redux slice has no dependency on `@reduxjs/toolkit`: it works with RTK stores, vanilla Redux, or no Redux at all.
39
39
 
@@ -238,6 +238,7 @@ export default function App() {
238
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
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 |
240
240
  | `onReady` | `() => void` | Called once when the theme first resolves |
241
+ | `reanimated` | `ReanimatedModule` | Injects `react-native-reanimated` (for example `import Reanimated from 'react-native-reanimated'`) so `<Dialog animatedStyle={...}>` can animate its card on the UI thread. Omit to keep `animatedStyle` as a no-op. |
241
242
  | `statusBarProps` | `StatusBarProps` | Spread over the auto-derived `StatusBar` defaults |
242
243
  | `style` | `StyleProp<ViewStyle>` | Applied to the wrapper `View` |
243
244
 
@@ -255,6 +256,8 @@ export default function App() {
255
256
 
256
257
  Returns `{ settings: ThemeSettings, set: (patch: Partial<ThemeSettings>) => void }`. Use this hook from any component inside `Provider` to read or update the current theme settings.
257
258
 
259
+ `useReanimatedModule()` is also available inside the provider tree when you need to read the injected reanimated module directly; it returns `undefined` unless `Provider` was given a `reanimated` prop.
260
+
258
261
  ```tsx
259
262
  import { useThemeSettings } from '@rific/auto-paper'
260
263
 
@@ -377,6 +380,35 @@ import { Chip } from '@rific/auto-paper'
377
380
 
378
381
  `ChipProps` is exported from `@rific/auto-paper` and extends `react-native-paper`'s `ChipProps` with the `variant` field. Use `PaperChipProps` if you need the base paper type.
379
382
 
383
+ ### `Dialog`
384
+
385
+ A thin wrapper around `react-native-paper`'s `Dialog` with built-in blur support and optional UI-thread animation hooks. `blur` overrides the ambient blur setting for that dialog, and `animatedStyle` can be used to animate the card wrapper when a reanimated module has been injected into `Provider`.
386
+
387
+ ```tsx
388
+ import { Dialog, Provider } from '@rific/auto-paper'
389
+ import Reanimated, { useAnimatedStyle } from 'react-native-reanimated'
390
+
391
+ function SettingsDialog({ visible }: { visible: boolean }) {
392
+ const animatedStyle = useAnimatedStyle(() => ({ opacity: 1 }))
393
+
394
+ return (
395
+ <Provider initialValue={{ appearance: 'system', color: '#6750a4' }} reanimated={Reanimated}>
396
+ <Dialog visible={visible} onDismiss={() => {}} animatedStyle={animatedStyle} blur>
397
+ {/* dialog contents */}
398
+ </Dialog>
399
+ </Provider>
400
+ )
401
+ }
402
+ ```
403
+
404
+ | Prop | Type | Description |
405
+ |---|---|---|
406
+ | `blur` | `boolean` | Overrides the ambient blur setting for this component's dialog |
407
+ | `animatedStyle` | `unknown` | Applied to the card's outer wrapper when a reanimated module has been injected; otherwise ignored |
408
+ | ...all `DialogProps` | | All props from `react-native-paper`'s `Dialog` are supported |
409
+
410
+ `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.
411
+
380
412
  ### `IconButton`
381
413
 
382
414
  A thin wrapper around `react-native-paper`'s `IconButton` that adds a `variant` prop for applying theme-derived container and icon colors.
package/dist/index.d.mts CHANGED
@@ -127,11 +127,19 @@ type Props$2 = {
127
127
  };
128
128
  declare const ColorPicker: ({ value, onChange, colors, blur: blurProp }: Props$2) => react.JSX.Element;
129
129
 
130
+ interface ReanimatedModule {
131
+ View: ComponentType<{
132
+ children?: ReactNode;
133
+ style?: any;
134
+ testID?: string;
135
+ }>;
136
+ }
130
137
  type DialogProps = Omit<DialogProps$1, 'style'> & {
131
138
  blur?: boolean;
132
139
  style?: StyleProp<ViewStyle>;
140
+ animatedStyle?: unknown;
133
141
  };
134
- declare function DialogComponent({ blur: blurProp, dismissable, dismissableBackButton, visible, onDismiss, children, style, testID }: DialogProps): react__default.JSX.Element | null;
142
+ declare function DialogComponent({ animatedStyle, blur: blurProp, dismissable, dismissableBackButton, visible, onDismiss, children, style, testID }: DialogProps): react__default.JSX.Element | null;
135
143
  declare namespace DialogComponent {
136
144
  var Title: react__default.FC<DialogTitleProps>;
137
145
  var Content: react__default.FC<DialogContentProps>;
@@ -273,6 +281,7 @@ type NavBarContextType = {
273
281
  };
274
282
  declare const useNavBarContext: () => NavBarContextType;
275
283
  declare const useBlurModule: () => ExpoBlurModule | undefined;
284
+ declare const useReanimatedModule: () => ReanimatedModule | undefined;
276
285
  type ProviderProps = {
277
286
  children: ReactNode;
278
287
  defaults?: PaperDefaults;
@@ -284,10 +293,12 @@ type ProviderProps = {
284
293
  onChange?: (settings: ThemeSettings) => void;
285
294
  onNavBarChange?: (color: string, dark: boolean) => void;
286
295
  onReady?: () => void;
296
+ /** Injects react-native-reanimated so `<Dialog animatedStyle={...}>` (e.g. from `useAnimatedStyle()`) can animate its card on the UI thread. Pass `import Reanimated from 'react-native-reanimated'`; omit to keep Dialog's `animatedStyle` prop a no-op. */
297
+ reanimated?: ReanimatedModule;
287
298
  statusBarProps?: StatusBarProps;
288
299
  style?: StyleProp<ViewStyle>;
289
300
  };
290
- declare function Provider({ children, defaults, expoBlur, initialValue, navigationBar, onChange, onNavBarChange, onReady, statusBarProps, style }: ProviderProps): react.JSX.Element | null;
301
+ declare function Provider({ children, defaults, expoBlur, initialValue, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBarProps, style }: ProviderProps): react.JSX.Element | null;
291
302
 
292
303
  declare const useAutoPaperTheme: () => AutoPaperTheme;
293
304
 
@@ -323,4 +334,4 @@ declare const getTonalColor: (color: string, lightness: number) => string;
323
334
 
324
335
  declare const isDarkColor: (value: string) => boolean;
325
336
 
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 };
337
+ 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, type ReanimatedModule, 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, useReanimatedModule, useThemeSettings };
package/dist/index.d.ts CHANGED
@@ -127,11 +127,19 @@ type Props$2 = {
127
127
  };
128
128
  declare const ColorPicker: ({ value, onChange, colors, blur: blurProp }: Props$2) => react.JSX.Element;
129
129
 
130
+ interface ReanimatedModule {
131
+ View: ComponentType<{
132
+ children?: ReactNode;
133
+ style?: any;
134
+ testID?: string;
135
+ }>;
136
+ }
130
137
  type DialogProps = Omit<DialogProps$1, 'style'> & {
131
138
  blur?: boolean;
132
139
  style?: StyleProp<ViewStyle>;
140
+ animatedStyle?: unknown;
133
141
  };
134
- declare function DialogComponent({ blur: blurProp, dismissable, dismissableBackButton, visible, onDismiss, children, style, testID }: DialogProps): react__default.JSX.Element | null;
142
+ declare function DialogComponent({ animatedStyle, blur: blurProp, dismissable, dismissableBackButton, visible, onDismiss, children, style, testID }: DialogProps): react__default.JSX.Element | null;
135
143
  declare namespace DialogComponent {
136
144
  var Title: react__default.FC<DialogTitleProps>;
137
145
  var Content: react__default.FC<DialogContentProps>;
@@ -273,6 +281,7 @@ type NavBarContextType = {
273
281
  };
274
282
  declare const useNavBarContext: () => NavBarContextType;
275
283
  declare const useBlurModule: () => ExpoBlurModule | undefined;
284
+ declare const useReanimatedModule: () => ReanimatedModule | undefined;
276
285
  type ProviderProps = {
277
286
  children: ReactNode;
278
287
  defaults?: PaperDefaults;
@@ -284,10 +293,12 @@ type ProviderProps = {
284
293
  onChange?: (settings: ThemeSettings) => void;
285
294
  onNavBarChange?: (color: string, dark: boolean) => void;
286
295
  onReady?: () => void;
296
+ /** Injects react-native-reanimated so `<Dialog animatedStyle={...}>` (e.g. from `useAnimatedStyle()`) can animate its card on the UI thread. Pass `import Reanimated from 'react-native-reanimated'`; omit to keep Dialog's `animatedStyle` prop a no-op. */
297
+ reanimated?: ReanimatedModule;
287
298
  statusBarProps?: StatusBarProps;
288
299
  style?: StyleProp<ViewStyle>;
289
300
  };
290
- declare function Provider({ children, defaults, expoBlur, initialValue, navigationBar, onChange, onNavBarChange, onReady, statusBarProps, style }: ProviderProps): react.JSX.Element | null;
301
+ declare function Provider({ children, defaults, expoBlur, initialValue, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBarProps, style }: ProviderProps): react.JSX.Element | null;
291
302
 
292
303
  declare const useAutoPaperTheme: () => AutoPaperTheme;
293
304
 
@@ -323,4 +334,4 @@ declare const getTonalColor: (color: string, lightness: number) => string;
323
334
 
324
335
  declare const isDarkColor: (value: string) => boolean;
325
336
 
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 };
337
+ 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, type ReanimatedModule, 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, useReanimatedModule, useThemeSettings };
package/dist/index.js CHANGED
@@ -72,6 +72,7 @@ __export(index_exports, {
72
72
  useComputedTheme: () => useComputedTheme,
73
73
  useNavBarContext: () => useNavBarContext,
74
74
  usePaperDefaults: () => usePaperDefaults,
75
+ useReanimatedModule: () => useReanimatedModule,
75
76
  useThemeSettings: () => useThemeSettings
76
77
  });
77
78
  module.exports = __toCommonJS(index_exports);
@@ -634,7 +635,9 @@ var NavBarContext = (0, import_react5.createContext)({});
634
635
  var useNavBarContext = () => (0, import_react5.useContext)(NavBarContext);
635
636
  var BlurModuleContext = (0, import_react5.createContext)(void 0);
636
637
  var useBlurModule = () => (0, import_react5.useContext)(BlurModuleContext);
637
- function Provider({ children, defaults, expoBlur, initialValue, navigationBar, onChange, onNavBarChange, onReady, statusBarProps, style }) {
638
+ var ReanimatedModuleContext = (0, import_react5.createContext)(void 0);
639
+ var useReanimatedModule = () => (0, import_react5.useContext)(ReanimatedModuleContext);
640
+ function Provider({ children, defaults, expoBlur, initialValue, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBarProps, style }) {
638
641
  const [settings, setSettings] = (0, import_react5.useState)(() => ({ ...defaultThemeSettings, ...initialValue }));
639
642
  const set = (0, import_react5.useCallback)((patch) => {
640
643
  setSettings((prev) => ({ ...prev, ...patch }));
@@ -659,7 +662,7 @@ function Provider({ children, defaults, expoBlur, initialValue, navigationBar, o
659
662
  if (!theme) return null;
660
663
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ThemeSettingsContext.Provider, { value: { settings, set }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react_native_paper4.Provider, { theme, children: [
661
664
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.StatusBar, { backgroundColor: theme.colors.background, barStyle: theme.dark ? "light-content" : "dark-content", ...statusBarProps }),
662
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PaperDefaultsContext.Provider, { value: defaults ?? {}, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(NavBarContext.Provider, { value: { navigationBar, onNavBarChange }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BlurModuleContext.Provider, { value: expoBlur, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: [styles.flex, { backgroundColor: theme.colors.background }, style], children }) }) }) })
665
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PaperDefaultsContext.Provider, { value: defaults ?? {}, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(NavBarContext.Provider, { value: { navigationBar, onNavBarChange }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(BlurModuleContext.Provider, { value: expoBlur, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ReanimatedModuleContext.Provider, { value: reanimated, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native3.View, { style: [styles.flex, { backgroundColor: theme.colors.background }, style], children }) }) }) }) })
663
666
  ] }) });
664
667
  }
665
668
  var styles = import_react_native3.StyleSheet.create({
@@ -778,8 +781,9 @@ var import_react_native_safe_area_context = require("react-native-safe-area-cont
778
781
  var import_jsx_runtime8 = require("react/jsx-runtime");
779
782
  var ANIMATION_DURATION = 220;
780
783
  var DIALOG_MARGIN = 32;
781
- function DialogComponent({ blur: blurProp, dismissable = true, dismissableBackButton = dismissable, visible, onDismiss, children, style, testID = "dialog" }) {
784
+ function DialogComponent({ animatedStyle, blur: blurProp, dismissable = true, dismissableBackButton = dismissable, visible, onDismiss, children, style, testID = "dialog" }) {
782
785
  const blur = useBlur(blurProp);
786
+ const reanimated = useReanimatedModule();
783
787
  const theme = (0, import_react_native_paper9.useTheme)();
784
788
  const { colors, isV3, roundness } = theme;
785
789
  const { scale } = theme.animation;
@@ -820,7 +824,7 @@ function DialogComponent({ blur: blurProp, dismissable = true, dismissableBackBu
820
824
  const borderRadius = (isV3 ? 7 : 1) * roundness;
821
825
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native_paper9.Portal, { children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_react_native6.Animated.View, { accessibilityLiveRegion: "polite", accessibilityViewIsModal: true, pointerEvents: visible ? "box-none" : "none", style: [import_react_native6.StyleSheet.absoluteFill, { opacity }], testID, children: [
822
826
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native6.Pressable, { accessibilityLabel: "Close modal", accessibilityRole: "button", disabled: !dismissable, onPress: dismissable ? onDismiss : void 0, style: [import_react_native6.StyleSheet.absoluteFill, { backgroundColor: colors.backdrop }], testID: `${testID}-backdrop` }),
823
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native6.View, { pointerEvents: "box-none", style: [styles2.wrapper, { marginBottom: bottom, marginTop: top, paddingHorizontal: Math.max(left, right, DIALOG_MARGIN) }], testID: `${testID}-wrapper`, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(BlurView, { blur, style: [styles2.card, { borderRadius }, style], testID: `${testID}-surface`, children: content }) })
827
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react_native6.View, { pointerEvents: "box-none", style: [styles2.wrapper, { marginBottom: bottom, marginTop: top, paddingHorizontal: Math.max(left, right, DIALOG_MARGIN) }], testID: `${testID}-wrapper`, children: reanimated && animatedStyle ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(reanimated.View, { style: animatedStyle, testID: `${testID}-animated-wrapper`, children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(BlurView, { blur, style: [styles2.card, { borderRadius }, style], testID: `${testID}-surface`, children: content }) }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(BlurView, { blur, style: [styles2.card, { borderRadius }, style], testID: `${testID}-surface`, children: content }) })
824
828
  ] }) });
825
829
  }
826
830
  DialogComponent.Title = import_react_native_paper9.Dialog.Title;
@@ -1200,5 +1204,6 @@ var getTintTextColor = (tintColor, backdropColor, tintOpacity) => {
1200
1204
  useComputedTheme,
1201
1205
  useNavBarContext,
1202
1206
  usePaperDefaults,
1207
+ useReanimatedModule,
1203
1208
  useThemeSettings
1204
1209
  });
package/dist/index.mjs CHANGED
@@ -556,7 +556,9 @@ var NavBarContext = createContext3({});
556
556
  var useNavBarContext = () => useContext3(NavBarContext);
557
557
  var BlurModuleContext = createContext3(void 0);
558
558
  var useBlurModule = () => useContext3(BlurModuleContext);
559
- function Provider({ children, defaults, expoBlur, initialValue, navigationBar, onChange, onNavBarChange, onReady, statusBarProps, style }) {
559
+ var ReanimatedModuleContext = createContext3(void 0);
560
+ var useReanimatedModule = () => useContext3(ReanimatedModuleContext);
561
+ function Provider({ children, defaults, expoBlur, initialValue, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBarProps, style }) {
560
562
  const [settings, setSettings] = useState2(() => ({ ...defaultThemeSettings, ...initialValue }));
561
563
  const set = useCallback2((patch) => {
562
564
  setSettings((prev) => ({ ...prev, ...patch }));
@@ -581,7 +583,7 @@ function Provider({ children, defaults, expoBlur, initialValue, navigationBar, o
581
583
  if (!theme) return null;
582
584
  return /* @__PURE__ */ jsx3(ThemeSettingsContext.Provider, { value: { settings, set }, children: /* @__PURE__ */ jsxs2(PaperProvider, { theme, children: [
583
585
  /* @__PURE__ */ jsx3(StatusBar2, { backgroundColor: theme.colors.background, barStyle: theme.dark ? "light-content" : "dark-content", ...statusBarProps }),
584
- /* @__PURE__ */ jsx3(PaperDefaultsContext.Provider, { value: defaults ?? {}, children: /* @__PURE__ */ jsx3(NavBarContext.Provider, { value: { navigationBar, onNavBarChange }, children: /* @__PURE__ */ jsx3(BlurModuleContext.Provider, { value: expoBlur, children: /* @__PURE__ */ jsx3(View, { style: [styles.flex, { backgroundColor: theme.colors.background }, style], children }) }) }) })
586
+ /* @__PURE__ */ jsx3(PaperDefaultsContext.Provider, { value: defaults ?? {}, children: /* @__PURE__ */ jsx3(NavBarContext.Provider, { value: { navigationBar, onNavBarChange }, children: /* @__PURE__ */ jsx3(BlurModuleContext.Provider, { value: expoBlur, children: /* @__PURE__ */ jsx3(ReanimatedModuleContext.Provider, { value: reanimated, children: /* @__PURE__ */ jsx3(View, { style: [styles.flex, { backgroundColor: theme.colors.background }, style], children }) }) }) }) })
585
587
  ] }) });
586
588
  }
587
589
  var styles = StyleSheet.create({
@@ -700,8 +702,9 @@ import { useSafeAreaInsets } from "react-native-safe-area-context";
700
702
  import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
701
703
  var ANIMATION_DURATION = 220;
702
704
  var DIALOG_MARGIN = 32;
703
- function DialogComponent({ blur: blurProp, dismissable = true, dismissableBackButton = dismissable, visible, onDismiss, children, style, testID = "dialog" }) {
705
+ function DialogComponent({ animatedStyle, blur: blurProp, dismissable = true, dismissableBackButton = dismissable, visible, onDismiss, children, style, testID = "dialog" }) {
704
706
  const blur = useBlur(blurProp);
707
+ const reanimated = useReanimatedModule();
705
708
  const theme = useTheme5();
706
709
  const { colors, isV3, roundness } = theme;
707
710
  const { scale } = theme.animation;
@@ -742,7 +745,7 @@ function DialogComponent({ blur: blurProp, dismissable = true, dismissableBackBu
742
745
  const borderRadius = (isV3 ? 7 : 1) * roundness;
743
746
  return /* @__PURE__ */ jsx8(Portal, { children: /* @__PURE__ */ jsxs4(Animated.View, { accessibilityLiveRegion: "polite", accessibilityViewIsModal: true, pointerEvents: visible ? "box-none" : "none", style: [StyleSheet3.absoluteFill, { opacity }], testID, children: [
744
747
  /* @__PURE__ */ jsx8(Pressable, { accessibilityLabel: "Close modal", accessibilityRole: "button", disabled: !dismissable, onPress: dismissable ? onDismiss : void 0, style: [StyleSheet3.absoluteFill, { backgroundColor: colors.backdrop }], testID: `${testID}-backdrop` }),
745
- /* @__PURE__ */ jsx8(View3, { pointerEvents: "box-none", style: [styles2.wrapper, { marginBottom: bottom, marginTop: top, paddingHorizontal: Math.max(left, right, DIALOG_MARGIN) }], testID: `${testID}-wrapper`, children: /* @__PURE__ */ jsx8(BlurView, { blur, style: [styles2.card, { borderRadius }, style], testID: `${testID}-surface`, children: content }) })
748
+ /* @__PURE__ */ jsx8(View3, { pointerEvents: "box-none", style: [styles2.wrapper, { marginBottom: bottom, marginTop: top, paddingHorizontal: Math.max(left, right, DIALOG_MARGIN) }], testID: `${testID}-wrapper`, children: reanimated && animatedStyle ? /* @__PURE__ */ jsx8(reanimated.View, { style: animatedStyle, testID: `${testID}-animated-wrapper`, children: /* @__PURE__ */ jsx8(BlurView, { blur, style: [styles2.card, { borderRadius }, style], testID: `${testID}-surface`, children: content }) }) : /* @__PURE__ */ jsx8(BlurView, { blur, style: [styles2.card, { borderRadius }, style], testID: `${testID}-surface`, children: content }) })
746
749
  ] }) });
747
750
  }
748
751
  DialogComponent.Title = PaperDialog.Title;
@@ -1121,5 +1124,6 @@ export {
1121
1124
  useComputedTheme,
1122
1125
  useNavBarContext,
1123
1126
  usePaperDefaults,
1127
+ useReanimatedModule,
1124
1128
  useThemeSettings
1125
1129
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rific/auto-paper",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "Adaptive react-native-paper theming: triadic palette from a seed color + system/light/dark appearance",
5
5
  "keywords": [
6
6
  "react-native",
@@ -31,7 +31,7 @@
31
31
  "type": "commonjs",
32
32
  "exports": {
33
33
  ".": {
34
- "react-native": "./dist/index.mjs",
34
+ "react-native": "./src/index.ts",
35
35
  "types": "./dist/index.d.ts",
36
36
  "import": "./dist/index.mjs",
37
37
  "require": "./dist/index.js"
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "main": "dist/index.js",
41
41
  "module": "dist/index.mjs",
42
- "react-native": "dist/index.mjs",
42
+ "react-native": "src/index.ts",
43
43
  "types": "dist/index.d.ts",
44
44
  "files": [
45
45
  "dist",
@@ -95,9 +95,9 @@
95
95
  "typescript-eslint": "^8.59.3"
96
96
  },
97
97
  "peerDependencies": {
98
- "expo-blur": ">=14.0.0",
98
+ "expo-blur": ">=56.0.0",
99
99
  "expo-navigation-bar": ">=56.0.0",
100
- "react": ">=18.0.0",
100
+ "react": ">=19.0.0",
101
101
  "react-native": ">=0.76.0",
102
102
  "react-native-paper": ">=5.0.0",
103
103
  "react-native-safe-area-context": "*"
@@ -3,6 +3,7 @@ import { StatusBar, type StatusBarProps, type StyleProp, StyleSheet, View, type
3
3
  import { Provider as PaperProvider } from 'react-native-paper'
4
4
 
5
5
  import type { ExpoBlurModule } from './components/BlurView'
6
+ import type { ReanimatedModule } from './components/Dialog'
6
7
  import type { ExpoNavigationBarModule } from './navigation-bar'
7
8
  import { type PaperDefaults, PaperDefaultsContext } from './PaperDefaultsContext'
8
9
  import { defaultThemeSettings, type ThemeSettings, ThemeSettingsContext } from './ThemeSettingsContext'
@@ -20,6 +21,9 @@ export const useNavBarContext = () => useContext(NavBarContext)
20
21
  const BlurModuleContext = createContext<ExpoBlurModule | undefined>(undefined)
21
22
  export const useBlurModule = () => useContext(BlurModuleContext)
22
23
 
24
+ const ReanimatedModuleContext = createContext<ReanimatedModule | undefined>(undefined)
25
+ export const useReanimatedModule = () => useContext(ReanimatedModuleContext)
26
+
23
27
  export type ProviderProps = {
24
28
  children: ReactNode
25
29
  defaults?: PaperDefaults
@@ -31,11 +35,13 @@ export type ProviderProps = {
31
35
  onChange?: (settings: ThemeSettings) => void
32
36
  onNavBarChange?: (color: string, dark: boolean) => void
33
37
  onReady?: () => void
38
+ /** Injects react-native-reanimated so `<Dialog animatedStyle={...}>` (e.g. from `useAnimatedStyle()`) can animate its card on the UI thread. Pass `import Reanimated from 'react-native-reanimated'`; omit to keep Dialog's `animatedStyle` prop a no-op. */
39
+ reanimated?: ReanimatedModule
34
40
  statusBarProps?: StatusBarProps
35
41
  style?: StyleProp<ViewStyle>
36
42
  }
37
43
 
38
- export function Provider({ children, defaults, expoBlur, initialValue, navigationBar, onChange, onNavBarChange, onReady, statusBarProps, style }: ProviderProps) {
44
+ export function Provider({ children, defaults, expoBlur, initialValue, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBarProps, style }: ProviderProps) {
39
45
  const [settings, setSettings] = useState<ThemeSettings>(() => ({ ...defaultThemeSettings, ...initialValue }))
40
46
 
41
47
  const set = useCallback((patch: Partial<ThemeSettings>) => {
@@ -71,7 +77,9 @@ export function Provider({ children, defaults, expoBlur, initialValue, navigatio
71
77
  <PaperDefaultsContext.Provider value={defaults ?? {}}>
72
78
  <NavBarContext.Provider value={{ navigationBar, onNavBarChange }}>
73
79
  <BlurModuleContext.Provider value={expoBlur}>
74
- <View style={[styles.flex, { backgroundColor: theme.colors.background }, style]}>{children}</View>
80
+ <ReanimatedModuleContext.Provider value={reanimated}>
81
+ <View style={[styles.flex, { backgroundColor: theme.colors.background }, style]}>{children}</View>
82
+ </ReanimatedModuleContext.Provider>
75
83
  </BlurModuleContext.Provider>
76
84
  </NavBarContext.Provider>
77
85
  </PaperDefaultsContext.Provider>
@@ -1,16 +1,35 @@
1
- import React, { useEffect, useRef, useState } from 'react'
1
+ import React, { type ComponentType, type ReactNode, useEffect, useRef, useState } from 'react'
2
2
  import { Animated, BackHandler, Easing, Pressable, type StyleProp, StyleSheet, View, type ViewStyle } from 'react-native'
3
3
  import { Dialog as PaperDialog, type DialogActionsProps, type DialogContentProps, type DialogProps as PaperDialogProps, type DialogScrollAreaProps, type DialogTitleProps, Portal, useTheme } from 'react-native-paper'
4
4
  import { useSafeAreaInsets } from 'react-native-safe-area-context'
5
5
 
6
6
  import { useBlur } from '../BlurContext'
7
+ import { useReanimatedModule } from '../ThemeProvider'
7
8
  import { BlurView } from './BlurView'
8
9
 
9
- // `style` is narrowed to a plain ViewStyle: unlike react-native-paper's Dialog, the surface here is
10
- // never wrapped in Animated.View, so it can't drive an Animated-value style the way upstream's can.
10
+ // Minimal local mirror of react-native-reanimated's Animated.View — same reasoning as BlurView's
11
+ // ExpoBlurModule: Metro doesn't rewrite a require()-in-try/catch call into its module graph inside
12
+ // an ESM build, so the already-imported peer module is injected via <Provider reanimated={...}>
13
+ // (see ThemeProvider.tsx) instead of required directly. Only `View` is needed here. `style: any`,
14
+ // not a real style type — reanimated's actual AnimatedView only accepts its own branded
15
+ // AnimatedStyle shape, which this package never imports (no reanimated dependency at all), so `any`
16
+ // is the only type that both sides (this interface and the real component passed in) can agree on.
17
+ export interface ReanimatedModule {
18
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
+ View: ComponentType<{ children?: ReactNode; style?: any; testID?: string }>
20
+ }
21
+
11
22
  export type DialogProps = Omit<PaperDialogProps, 'style'> & {
12
23
  blur?: boolean
13
24
  style?: StyleProp<ViewStyle>
25
+ // Applied to the card's outer wrapper instead of the card itself, and only takes effect once a
26
+ // reanimated module has been injected via <Provider reanimated={...}> — otherwise ignored. `style`
27
+ // above is a plain object read once per render, so a fast-changing value (e.g. tracking the
28
+ // keyboard height every frame) driven through it needs a full JS re-render per update to paint at
29
+ // all; wiring the same value through `animatedStyle` (e.g. the result of Reanimated's
30
+ // useAnimatedStyle()) instead paints on the UI thread with no JS round-trip, which is the whole
31
+ // difference between a smooth follow and a laggy snap.
32
+ animatedStyle?: unknown
14
33
  }
15
34
 
16
35
  // Matches react-native-paper's Modal: DEFAULT_DURATION * theme.animation.scale, eased the same way,
@@ -20,8 +39,9 @@ const ANIMATION_DURATION = 220
20
39
  // Minimum breathing room between the card and the screen edge, clamped up from safe-area insets.
21
40
  const DIALOG_MARGIN = 32
22
41
 
23
- function DialogComponent({ blur: blurProp, dismissable = true, dismissableBackButton = dismissable, visible, onDismiss, children, style, testID = 'dialog' }: DialogProps) {
42
+ function DialogComponent({ animatedStyle, blur: blurProp, dismissable = true, dismissableBackButton = dismissable, visible, onDismiss, children, style, testID = 'dialog' }: DialogProps) {
24
43
  const blur = useBlur(blurProp)
44
+ const reanimated = useReanimatedModule()
25
45
  const theme = useTheme()
26
46
  const { colors, isV3, roundness } = theme
27
47
  const { scale } = theme.animation
@@ -75,9 +95,17 @@ function DialogComponent({ blur: blurProp, dismissable = true, dismissableBackBu
75
95
  <Animated.View accessibilityLiveRegion='polite' accessibilityViewIsModal pointerEvents={visible ? 'box-none' : 'none'} style={[StyleSheet.absoluteFill, { opacity }]} testID={testID}>
76
96
  <Pressable accessibilityLabel='Close modal' accessibilityRole='button' disabled={!dismissable} onPress={dismissable ? onDismiss : undefined} style={[StyleSheet.absoluteFill, { backgroundColor: colors.backdrop }]} testID={`${testID}-backdrop`} />
77
97
  <View pointerEvents='box-none' style={[styles.wrapper, { marginBottom: bottom, marginTop: top, paddingHorizontal: Math.max(left, right, DIALOG_MARGIN) }]} testID={`${testID}-wrapper`}>
78
- <BlurView blur={blur} style={[styles.card, { borderRadius }, style]} testID={`${testID}-surface`}>
79
- {content}
80
- </BlurView>
98
+ {reanimated && animatedStyle ? (
99
+ <reanimated.View style={animatedStyle} testID={`${testID}-animated-wrapper`}>
100
+ <BlurView blur={blur} style={[styles.card, { borderRadius }, style]} testID={`${testID}-surface`}>
101
+ {content}
102
+ </BlurView>
103
+ </reanimated.View>
104
+ ) : (
105
+ <BlurView blur={blur} style={[styles.card, { borderRadius }, style]} testID={`${testID}-surface`}>
106
+ {content}
107
+ </BlurView>
108
+ )}
81
109
  </View>
82
110
  </Animated.View>
83
111
  </Portal>
package/src/index.ts CHANGED
@@ -10,7 +10,7 @@ export type { ChipProps } from './components/Chip'
10
10
  export { Chip } from './components/Chip'
11
11
  export type { SeedColor } from './components/ColorPicker'
12
12
  export { ColorPicker, defaultColors } from './components/ColorPicker'
13
- export type { DialogProps } from './components/Dialog'
13
+ export type { DialogProps, ReanimatedModule } from './components/Dialog'
14
14
  export { Dialog } from './components/Dialog'
15
15
  export { FAB } from './components/FAB'
16
16
  export { HarmonyPicker } from './components/HarmonyPicker'
@@ -27,7 +27,7 @@ export { usePaperDefaults } from './PaperDefaultsContext'
27
27
  export type { ThemeState } from './redux/themeSlice'
28
28
  export { createThemeReducer, selectThemeAppearance, selectThemeBlur, selectThemeColor, selectThemeHarmony, themeActions, themeReducer } from './redux/themeSlice'
29
29
  export type { ProviderProps } from './ThemeProvider'
30
- export { Provider, useBlurModule, useNavBarContext } from './ThemeProvider'
30
+ export { Provider, useBlurModule, useNavBarContext, useReanimatedModule } from './ThemeProvider'
31
31
  export type { ThemeSettings, ThemeSettingsContextType } from './ThemeSettingsContext'
32
32
  export { defaultThemeSettings, ThemeSettingsContext } from './ThemeSettingsContext'
33
33
  export type { AutoPaperTheme, SemanticColorRoles, ThemeAppearance } from './useComputedTheme'