@oxyhq/bloom 0.59.2 → 0.59.3

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.
Files changed (45) hide show
  1. package/README.md +1 -1
  2. package/lib/commonjs/bottom-sheet/BottomSheetBase.js +25 -9
  3. package/lib/commonjs/bottom-sheet/BottomSheetBase.js.map +1 -1
  4. package/lib/commonjs/dialog/Dialog.js +2 -1
  5. package/lib/commonjs/dialog/Dialog.js.map +1 -1
  6. package/lib/commonjs/dialog/SheetShell.js +2 -1
  7. package/lib/commonjs/dialog/SheetShell.js.map +1 -1
  8. package/lib/commonjs/overlay/index.js +9 -1
  9. package/lib/commonjs/overlay/index.js.map +1 -1
  10. package/lib/commonjs/styles/radii.js +9 -0
  11. package/lib/commonjs/styles/radii.js.map +1 -0
  12. package/lib/module/bottom-sheet/BottomSheetBase.js +26 -10
  13. package/lib/module/bottom-sheet/BottomSheetBase.js.map +1 -1
  14. package/lib/module/dialog/Dialog.js +2 -1
  15. package/lib/module/dialog/Dialog.js.map +1 -1
  16. package/lib/module/dialog/SheetShell.js +2 -1
  17. package/lib/module/dialog/SheetShell.js.map +1 -1
  18. package/lib/module/overlay/index.js +8 -1
  19. package/lib/module/overlay/index.js.map +1 -1
  20. package/lib/module/styles/radii.js +5 -0
  21. package/lib/module/styles/radii.js.map +1 -0
  22. package/lib/typescript/commonjs/bottom-sheet/BottomSheetBase.d.ts +4 -5
  23. package/lib/typescript/commonjs/bottom-sheet/BottomSheetBase.d.ts.map +1 -1
  24. package/lib/typescript/commonjs/dialog/Dialog.d.ts.map +1 -1
  25. package/lib/typescript/commonjs/dialog/SheetShell.d.ts.map +1 -1
  26. package/lib/typescript/commonjs/overlay/index.d.ts +3 -0
  27. package/lib/typescript/commonjs/overlay/index.d.ts.map +1 -1
  28. package/lib/typescript/commonjs/styles/radii.d.ts +3 -0
  29. package/lib/typescript/commonjs/styles/radii.d.ts.map +1 -0
  30. package/lib/typescript/module/bottom-sheet/BottomSheetBase.d.ts +4 -5
  31. package/lib/typescript/module/bottom-sheet/BottomSheetBase.d.ts.map +1 -1
  32. package/lib/typescript/module/dialog/Dialog.d.ts.map +1 -1
  33. package/lib/typescript/module/dialog/SheetShell.d.ts.map +1 -1
  34. package/lib/typescript/module/overlay/index.d.ts +3 -0
  35. package/lib/typescript/module/overlay/index.d.ts.map +1 -1
  36. package/lib/typescript/module/styles/radii.d.ts +3 -0
  37. package/lib/typescript/module/styles/radii.d.ts.map +1 -0
  38. package/package.json +1 -1
  39. package/src/__tests__/BottomSheet.test.tsx +1 -1
  40. package/src/__tests__/BottomSheetGesture.test.tsx +21 -3
  41. package/src/bottom-sheet/BottomSheetBase.tsx +33 -15
  42. package/src/dialog/Dialog.tsx +2 -1
  43. package/src/dialog/SheetShell.tsx +2 -1
  44. package/src/overlay/index.tsx +12 -1
  45. package/src/styles/radii.ts +2 -0
@@ -20,6 +20,7 @@ import Animated, {
20
20
  type SharedValue,
21
21
  useAnimatedScrollHandler,
22
22
  useAnimatedStyle,
23
+ useDerivedValue,
23
24
  useSharedValue,
24
25
  withSpring,
25
26
  withTiming,
@@ -27,6 +28,7 @@ import Animated, {
27
28
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
28
29
  import { Backdrop, BACKDROP_DIM_OPACITY } from '../overlay';
29
30
  import { useBloomBlurTarget } from '../overlay/blur-target';
31
+ import { DETACHED_SHEET_RADIUS } from '../styles/radii';
30
32
  import { useTheme } from '../theme/use-theme';
31
33
 
32
34
  /** Hook that returns current screen dimensions and updates on rotation/resize. */
@@ -126,12 +128,11 @@ export interface BottomSheetProps {
126
128
  */
127
129
  manualActivation?: boolean;
128
130
  /**
129
- * When `true`, the backdrop dims proportionally with drag distance — the
130
- * overlay fades from full opacity (sheet at rest) to 30% as the sheet is
131
- * pulled down 40% of the screen height. iOS Photos style. The base
132
- * `backdropOpacity` still controls the resting dim level.
131
+ * When `true`, the backdrop and native blur fade proportionally with drag
132
+ * distance fully visible at rest and fully gone once the sheet leaves the
133
+ * viewport. The base `backdropOpacity` still controls the resting dim level.
133
134
  *
134
- * Defaults to `false` (constant opacity during drag).
135
+ * Defaults to `true`. Set to `false` only for a deliberately fixed backdrop.
135
136
  */
136
137
  dynamicBackdrop?: boolean;
137
138
  /**
@@ -219,7 +220,7 @@ export const BottomSheetBase = forwardRef((props: BottomSheetBaseProps, ref: Rea
219
220
  backdropOpacity = BACKDROP_DIM_OPACITY,
220
221
  scrollable = true,
221
222
  manualActivation = false,
222
- dynamicBackdrop = false,
223
+ dynamicBackdrop = true,
223
224
  handleComponent,
224
225
  scrollY: externalScrollY,
225
226
  headerOverlay,
@@ -257,6 +258,10 @@ export const BottomSheetBase = forwardRef((props: BottomSheetBaseProps, ref: Rea
257
258
  }, [screenHeight, screenHeightSV]);
258
259
 
259
260
  const translateY = useSharedValue(screenHeight);
261
+ // The blur must reach zero when the CARD itself has moved fully below the
262
+ // viewport. A short detached dialog can be far smaller than the screen, so
263
+ // screen height is not a valid denominator for this interaction.
264
+ const sheetHeight = useSharedValue(screenHeight);
260
265
  const opacity = useSharedValue(0);
261
266
  const scrollOffsetY = useSharedValue(0);
262
267
  const isScrollAtTop = useSharedValue(true);
@@ -644,19 +649,25 @@ export const BottomSheetBase = forwardRef((props: BottomSheetBaseProps, ref: Rea
644
649
  // is multiplied into this group opacity instead, the opaque black child
645
650
  // hides the BlurView and Android looks like a plain dark scrim.
646
651
  // `dynamicBackdrop` fades the composed blur+dim proportionally with drag.
647
- const backdropStyle = useAnimatedStyle(() => {
652
+ // The SAME progress drives BlurView's native `intensity` prop below:
653
+ // Android's RenderEffect can remain visibly blurred when only an ancestor's
654
+ // alpha changes, so reducing the radius itself is required for the content
655
+ // behind the sheet to become genuinely sharp during the gesture.
656
+ const backdropProgress = useDerivedValue(() => {
648
657
  const dragFactor = dynamicBackdrop
649
658
  ? interpolate(
650
659
  translateY.value,
651
- [0, screenHeightSV.value * 0.4],
652
- [1, 0.3],
660
+ [0, sheetHeight.value],
661
+ [1, 0],
653
662
  'clamp',
654
663
  )
655
664
  : 1;
656
- return {
657
- opacity: opacity.value * dragFactor,
658
- };
659
- }, [dynamicBackdrop, opacity, translateY, screenHeightSV]);
665
+ return opacity.value * dragFactor;
666
+ }, [dynamicBackdrop, opacity, translateY, sheetHeight]);
667
+
668
+ const backdropStyle = useAnimatedStyle(() => ({
669
+ opacity: backdropProgress.value,
670
+ }), [backdropProgress]);
660
671
 
661
672
  const sheetStyle = useAnimatedStyle(() => {
662
673
  const scale = interpolate(translateY.value, [0, screenHeightSV.value], [1, 0.95]);
@@ -692,6 +703,12 @@ export const BottomSheetBase = forwardRef((props: BottomSheetBaseProps, ref: Rea
692
703
  dismiss();
693
704
  }, [onDismissAttempt, dismiss]);
694
705
 
706
+ const handleSheetLayout = useCallback((event: LayoutChangeEvent) => {
707
+ const measuredHeight = event.nativeEvent.layout.height;
708
+ if (measuredHeight > 0) sheetHeight.value = measuredHeight;
709
+ onLayout?.(event);
710
+ }, [onLayout, sheetHeight]);
711
+
695
712
  const scrollHandler = useAnimatedScrollHandler({
696
713
  onScroll: (event) => {
697
714
  scrollOffsetY.value = event.contentOffset.y;
@@ -800,13 +817,14 @@ export const BottomSheetBase = forwardRef((props: BottomSheetBaseProps, ref: Rea
800
817
  onPress={handleBackdropPress}
801
818
  dimOpacity={backdropOpacity}
802
819
  blurTarget={blurTarget ?? undefined}
820
+ blurProgress={backdropProgress}
803
821
  style={[styles.backdrop, backdropStyle]}
804
822
  />
805
823
  )}
806
824
 
807
825
  <GestureDetector gesture={panGesture}>
808
826
  <Animated.View
809
- onLayout={onLayout}
827
+ onLayout={handleSheetLayout}
810
828
  style={[dynamicStyles.sheet, sheetMarginStyle, sheetStyle, sheetHeightStyle, style]}
811
829
  >
812
830
  {backgroundComponent?.({ style: styles.background })}
@@ -845,7 +863,7 @@ const styles = StyleSheet.create({
845
863
  sheetDetached: {
846
864
  left: 16,
847
865
  right: 16,
848
- borderRadius: 28,
866
+ borderRadius: DETACHED_SHEET_RADIUS,
849
867
  },
850
868
  sheetNormal: {
851
869
  left: 0,
@@ -26,6 +26,7 @@ import Animated, {
26
26
  } from 'react-native-reanimated';
27
27
 
28
28
  import { BottomSheet, type BottomSheetRef } from '../bottom-sheet';
29
+ import { DETACHED_SHEET_RADIUS } from '../styles/radii';
29
30
  import { Z_INDEX, Z_INDEX_LAYER_STEP } from '../styles/z-index';
30
31
  import { useTheme } from '../theme/use-theme';
31
32
  import { Context, useDialogControl } from './context';
@@ -251,7 +252,7 @@ function CenteredOrSideDialog({
251
252
  // All four corners rounded — bloom's BottomSheet defaults to top-only
252
253
  // radius in flush mode, but we use `detached` so the whole card is
253
254
  // floating and rounded uniformly.
254
- borderRadius: 28,
255
+ borderRadius: DETACHED_SHEET_RADIUS,
255
256
  },
256
257
  // Drives the card's `height` only while a morph is in flight; at rest it
257
258
  // resolves to `height: 'auto'` — the card's normal content sizing.
@@ -14,6 +14,7 @@ import React, { useCallback, useImperativeHandle, useMemo, useRef } from 'react'
14
14
  import { Pressable, StyleSheet, View, type StyleProp, type ViewStyle } from 'react-native';
15
15
 
16
16
  import { BottomSheet, type BottomSheetRef } from '../bottom-sheet';
17
+ import { DETACHED_SHEET_RADIUS } from '../styles/radii';
17
18
  import { Z_INDEX } from '../styles/z-index';
18
19
  import { useTheme } from '../theme/use-theme';
19
20
  import { Context } from './context';
@@ -87,7 +88,7 @@ export function SheetShell({
87
88
  () => ({
88
89
  maxWidth: 500,
89
90
  backgroundColor: theme.colors.background,
90
- borderRadius: 28,
91
+ borderRadius: DETACHED_SHEET_RADIUS,
91
92
  }),
92
93
  [theme.colors.background],
93
94
  );
@@ -41,6 +41,7 @@
41
41
  */
42
42
  import { forwardRef, memo, type ReactNode, type RefObject } from 'react';
43
43
  import { BlurView } from 'expo-blur';
44
+ import Animated, { type SharedValue, useAnimatedProps } from 'react-native-reanimated';
44
45
  import {
45
46
  Platform,
46
47
  Pressable,
@@ -61,6 +62,8 @@ export const BACKDROP_BLUR_INTENSITY = 40;
61
62
  /** Dim laid over the blur — the blur alone does not give enough contrast. */
62
63
  export const BACKDROP_DIM_OPACITY = 0.45;
63
64
 
65
+ const AnimatedBlurView = Animated.createAnimatedComponent(BlurView);
66
+
64
67
  export interface OverlayRootProps {
65
68
  children?: ReactNode;
66
69
  style?: StyleProp<ViewStyle>;
@@ -98,6 +101,8 @@ export interface BackdropProps {
98
101
  dimOpacity?: number;
99
102
  /** Android view sampled by the native blur. Modal surfaces receive this from BloomProvider. */
100
103
  blurTarget?: RefObject<NativeView | null>;
104
+ /** Live visibility progress used to reduce native blur while a surface leaves. */
105
+ blurProgress?: SharedValue<number>;
101
106
  /** Extra style on the press target — animated opacity, insets, z-index. */
102
107
  style?: StyleProp<ViewStyle>;
103
108
  /** Rendered ON TOP of the dim, inside the press target (Dialog's panel does this). */
@@ -120,6 +125,7 @@ export const Backdrop = memo(forwardRef<View, BackdropProps>(function Backdrop(
120
125
  dimColor = '#000',
121
126
  dimOpacity = BACKDROP_DIM_OPACITY,
122
127
  blurTarget,
128
+ blurProgress,
123
129
  style,
124
130
  children,
125
131
  accessibilityLabel = 'Dismiss',
@@ -128,6 +134,10 @@ export const Backdrop = memo(forwardRef<View, BackdropProps>(function Backdrop(
128
134
  ref,
129
135
  ) {
130
136
  const inert = disabled || !onPress;
137
+ const animatedBlurProps = useAnimatedProps(() => ({
138
+ intensity: Math.max(0, Math.min(100, blurIntensity * (blurProgress?.value ?? 1))),
139
+ }), [blurIntensity, blurProgress]);
140
+
131
141
  return (
132
142
  <Pressable
133
143
  // MUST forward the ref: surfaces animate the backdrop through
@@ -150,8 +160,9 @@ export const Backdrop = memo(forwardRef<View, BackdropProps>(function Backdrop(
150
160
  style={[StyleSheet.absoluteFill, style]}
151
161
  >
152
162
  {blurIntensity > 0 ? (
153
- <BlurView
163
+ <AnimatedBlurView
154
164
  intensity={blurIntensity}
165
+ animatedProps={animatedBlurProps}
155
166
  tint={blurTint}
156
167
  blurTarget={blurTarget}
157
168
  // Expo disables Android blur without an explicit target. Sheets get
@@ -0,0 +1,2 @@
1
+ /** Radius for floating bottom sheets and native detached dialog cards. */
2
+ export const DETACHED_SHEET_RADIUS = 32;