@oxyhq/bloom 0.61.0 → 0.62.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/lib/commonjs/bottom-sheet/BottomSheetBase.js +24 -9
- package/lib/commonjs/bottom-sheet/BottomSheetBase.js.map +1 -1
- package/lib/commonjs/dialog/Dialog.web.js +14 -8
- package/lib/commonjs/dialog/Dialog.web.js.map +1 -1
- package/lib/commonjs/overlay/index.js +33 -19
- package/lib/commonjs/overlay/index.js.map +1 -1
- package/lib/commonjs/zoomable-image-gallery/ZoomableImageGallery.js +2 -4
- package/lib/commonjs/zoomable-image-gallery/ZoomableImageGallery.js.map +1 -1
- package/lib/module/bottom-sheet/BottomSheetBase.js +25 -10
- package/lib/module/bottom-sheet/BottomSheetBase.js.map +1 -1
- package/lib/module/dialog/Dialog.web.js +14 -8
- package/lib/module/dialog/Dialog.web.js.map +1 -1
- package/lib/module/overlay/index.js +33 -21
- package/lib/module/overlay/index.js.map +1 -1
- package/lib/module/zoomable-image-gallery/ZoomableImageGallery.js +2 -4
- package/lib/module/zoomable-image-gallery/ZoomableImageGallery.js.map +1 -1
- package/lib/typescript/commonjs/bottom-sheet/BottomSheetBase.d.ts.map +1 -1
- package/lib/typescript/commonjs/dialog/Dialog.web.d.ts.map +1 -1
- package/lib/typescript/commonjs/overlay/index.d.ts +21 -3
- package/lib/typescript/commonjs/overlay/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/zoomable-image-gallery/ZoomableImageGallery.d.ts.map +1 -1
- package/lib/typescript/module/bottom-sheet/BottomSheetBase.d.ts.map +1 -1
- package/lib/typescript/module/dialog/Dialog.web.d.ts.map +1 -1
- package/lib/typescript/module/overlay/index.d.ts +21 -3
- package/lib/typescript/module/overlay/index.d.ts.map +1 -1
- package/lib/typescript/module/zoomable-image-gallery/ZoomableImageGallery.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/overlay-pointer-events.test.tsx +17 -16
- package/src/bottom-sheet/BottomSheetBase.tsx +24 -9
- package/src/dialog/Dialog.web.tsx +16 -18
- package/src/overlay/index.tsx +59 -30
- package/src/zoomable-image-gallery/ZoomableImageGallery.tsx +6 -4
|
@@ -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,
|
|
@@ -199,8 +200,6 @@ export interface BottomSheetBaseProps extends BottomSheetProps {
|
|
|
199
200
|
Shell: React.ComponentType<BottomSheetShellProps>;
|
|
200
201
|
}
|
|
201
202
|
|
|
202
|
-
const AnimatedBackdrop = Animated.createAnimatedComponent(Backdrop);
|
|
203
|
-
|
|
204
203
|
export const BottomSheetBase = forwardRef((props: BottomSheetBaseProps, ref: React.ForwardedRef<BottomSheetRef>) => {
|
|
205
204
|
const {
|
|
206
205
|
Shell,
|
|
@@ -642,7 +641,11 @@ export const BottomSheetBase = forwardRef((props: BottomSheetBaseProps, ref: Rea
|
|
|
642
641
|
// dim opacity applies smoothly across the animation. When
|
|
643
642
|
// `dynamicBackdrop` is enabled, the dim also fades proportionally with
|
|
644
643
|
// drag distance (iOS Photos style).
|
|
645
|
-
|
|
644
|
+
// A VALUE, not a style: `Backdrop` applies it to its blur and dim layers
|
|
645
|
+
// itself. Handing it over as an animated style would put the opacity on the
|
|
646
|
+
// layers' shared ancestor, which composites the group in isolation and
|
|
647
|
+
// leaves `backdrop-filter` with nothing behind it to blur.
|
|
648
|
+
const backdropProgress = useDerivedValue(() => {
|
|
646
649
|
const dragFactor = dynamicBackdrop
|
|
647
650
|
? interpolate(
|
|
648
651
|
translateY.value,
|
|
@@ -651,11 +654,17 @@ export const BottomSheetBase = forwardRef((props: BottomSheetBaseProps, ref: Rea
|
|
|
651
654
|
'clamp',
|
|
652
655
|
)
|
|
653
656
|
: 1;
|
|
654
|
-
return
|
|
655
|
-
opacity: opacity.value * backdropOpacity * dragFactor,
|
|
656
|
-
};
|
|
657
|
+
return opacity.value * backdropOpacity * dragFactor;
|
|
657
658
|
}, [backdropOpacity, dynamicBackdrop, opacity, translateY, screenHeightSV]);
|
|
658
659
|
|
|
660
|
+
// Only the consumer-supplied `backdropComponent` needs the progress as a
|
|
661
|
+
// style — it owns its own visuals, blur included, so the ancestor-opacity
|
|
662
|
+
// hazard is its call to make.
|
|
663
|
+
const customBackdropStyle = useAnimatedStyle(
|
|
664
|
+
() => ({ opacity: backdropProgress.value }),
|
|
665
|
+
[backdropProgress],
|
|
666
|
+
);
|
|
667
|
+
|
|
659
668
|
const sheetStyle = useAnimatedStyle(() => {
|
|
660
669
|
const scale = interpolate(translateY.value, [0, screenHeightSV.value], [1, 0.95]);
|
|
661
670
|
return {
|
|
@@ -787,7 +796,7 @@ export const BottomSheetBase = forwardRef((props: BottomSheetBaseProps, ref: Rea
|
|
|
787
796
|
<Shell visible={rendered} onRequestClose={dismiss} keyboardHeight={keyboardHeight}>
|
|
788
797
|
<View style={StyleSheet.absoluteFill}>
|
|
789
798
|
{backdropComponent ? (
|
|
790
|
-
<Animated.View style={[StyleSheet.absoluteFill,
|
|
799
|
+
<Animated.View style={[StyleSheet.absoluteFill, customBackdropStyle]}>
|
|
791
800
|
{backdropComponent({ onPress: handleBackdropPress })}
|
|
792
801
|
</Animated.View>
|
|
793
802
|
) : (
|
|
@@ -795,10 +804,16 @@ export const BottomSheetBase = forwardRef((props: BottomSheetBaseProps, ref: Rea
|
|
|
795
804
|
// `backdropStyle` drives the fade; the dim level rides on
|
|
796
805
|
// `backdropOpacity`, so the shared component's own dim is
|
|
797
806
|
// switched off here to keep a single source of dimming.
|
|
798
|
-
<
|
|
807
|
+
<Backdrop
|
|
799
808
|
onPress={handleBackdropPress}
|
|
809
|
+
// `backdropProgress` already folds in `backdropOpacity`
|
|
810
|
+
// and the drag factor, so the dim rides at full weight.
|
|
811
|
+
// It goes through `progress` rather than an animated
|
|
812
|
+
// style because an opacity on the root would sit above
|
|
813
|
+
// the blur layer and neutralise it.
|
|
800
814
|
dimOpacity={1}
|
|
801
|
-
|
|
815
|
+
progress={backdropProgress}
|
|
816
|
+
style={styles.backdrop}
|
|
802
817
|
/>
|
|
803
818
|
)}
|
|
804
819
|
|
|
@@ -332,16 +332,17 @@ function CenterOrSideDialog({
|
|
|
332
332
|
disabled={!dismissOnBackdrop}
|
|
333
333
|
accessibilityLabel={label ? `Dismiss ${label}` : 'Dismiss dialog'}
|
|
334
334
|
dimOpacity={DIALOG_BACKDROP_DIM_OPACITY}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
335
|
+
// The fade rides on the LAYERS, never on the press target: an
|
|
336
|
+
// opacity animation on the blur's ancestor composites the group in
|
|
337
|
+
// isolation and leaves `backdrop-filter` nothing to sample.
|
|
338
|
+
layerStyle={isClosing ? BACKDROP_FADE_OUT : BACKDROP_FADE_IN}
|
|
339
|
+
style={{
|
|
340
|
+
position: WEB_POSITION_FIXED,
|
|
341
|
+
zIndex: dialogZIndex.backdrop,
|
|
342
|
+
alignItems: 'center',
|
|
343
|
+
justifyContent: 'center',
|
|
344
|
+
paddingHorizontal: 20,
|
|
345
|
+
}}
|
|
345
346
|
>
|
|
346
347
|
<DialogPanel
|
|
347
348
|
testID={testID}
|
|
@@ -702,14 +703,11 @@ function SheetSurface({
|
|
|
702
703
|
accessibilityLabel={label ? `Dismiss ${label}` : 'Dismiss dialog'}
|
|
703
704
|
onPress={handleBackdropPress}
|
|
704
705
|
disabled={!dismissOnBackdrop}
|
|
705
|
-
//
|
|
706
|
-
//
|
|
707
|
-
dimOpacity={
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
backdropTransition,
|
|
711
|
-
{ opacity: visible ? SHEET_BACKDROP_OPACITY : 0 },
|
|
712
|
-
]}
|
|
706
|
+
// Same reason as the centred dialog: the transition and the opacity it
|
|
707
|
+
// animates belong to the layers, not to the press target above them.
|
|
708
|
+
dimOpacity={SHEET_BACKDROP_OPACITY}
|
|
709
|
+
layerStyle={backdropTransition}
|
|
710
|
+
style={[sheetStyles.backdrop, { opacity: visible ? 1 : 0 }]}
|
|
713
711
|
/>
|
|
714
712
|
|
|
715
713
|
<View
|
package/src/overlay/index.tsx
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
* Use `<OverlayRoot>` for the surface's outermost node and `<Backdrop>` for its
|
|
40
40
|
* dimming layer; do not re-implement either with raw `View`s.
|
|
41
41
|
*/
|
|
42
|
-
import {
|
|
42
|
+
import { memo, type ReactNode } from 'react';
|
|
43
43
|
import { BlurView } from 'expo-blur';
|
|
44
44
|
import {
|
|
45
45
|
Platform,
|
|
@@ -49,9 +49,12 @@ import {
|
|
|
49
49
|
type StyleProp,
|
|
50
50
|
type ViewStyle,
|
|
51
51
|
} from 'react-native';
|
|
52
|
+
import Animated, { useAnimatedStyle, type SharedValue } from 'react-native-reanimated';
|
|
52
53
|
|
|
53
54
|
import { WEB_POSITION_FIXED } from '../styles/web-view-style';
|
|
54
55
|
|
|
56
|
+
const AnimatedBlurView = Animated.createAnimatedComponent(BlurView);
|
|
57
|
+
|
|
55
58
|
/**
|
|
56
59
|
* One blur radius for every Bloom overlay. Surfaces differ in what they show,
|
|
57
60
|
* not in how the app behind them recedes.
|
|
@@ -85,6 +88,12 @@ OverlayRoot.displayName = 'OverlayRoot';
|
|
|
85
88
|
export interface BackdropProps {
|
|
86
89
|
/** Dismiss handler. Omit (or pass `disabled`) for a backdrop that only dims. */
|
|
87
90
|
onPress?: () => void;
|
|
91
|
+
/**
|
|
92
|
+
* Fade driver, 0 (hidden) → 1 (fully shown). The backdrop applies it to its
|
|
93
|
+
* OWN layers — see the note on `style` for why the caller must not animate
|
|
94
|
+
* opacity from the outside.
|
|
95
|
+
*/
|
|
96
|
+
progress?: SharedValue<number>;
|
|
88
97
|
/** `true` keeps the dim but makes it inert — a blocking dialog, a busy state. */
|
|
89
98
|
disabled?: boolean;
|
|
90
99
|
/** Blur radius behind the dim. `0` renders the dim alone. */
|
|
@@ -95,8 +104,19 @@ export interface BackdropProps {
|
|
|
95
104
|
dimColor?: string;
|
|
96
105
|
/** Dim opacity, 0–1. */
|
|
97
106
|
dimOpacity?: number;
|
|
98
|
-
/**
|
|
107
|
+
/**
|
|
108
|
+
* Geometry for the press target: insets, z-index, layout. NOT opacity —
|
|
109
|
+
* `backdrop-filter` samples nothing under an ancestor with `opacity < 1`
|
|
110
|
+
* (the group composites in isolation), so a fade applied here silently kills
|
|
111
|
+
* the blur. An `opacity` found in this style is redirected onto the layers;
|
|
112
|
+
* animate the fade through `progress` instead.
|
|
113
|
+
*/
|
|
99
114
|
style?: StyleProp<ViewStyle>;
|
|
115
|
+
/**
|
|
116
|
+
* Extra style for the blur + dim LAYERS, for fades a shared value can't
|
|
117
|
+
* express — the web dialog's CSS keyframes, for instance.
|
|
118
|
+
*/
|
|
119
|
+
layerStyle?: StyleProp<ViewStyle>;
|
|
100
120
|
/** Rendered ON TOP of the dim, inside the press target (Dialog's panel does this). */
|
|
101
121
|
children?: ReactNode;
|
|
102
122
|
accessibilityLabel?: string;
|
|
@@ -108,31 +128,40 @@ export interface BackdropProps {
|
|
|
108
128
|
* pointer events (that is its whole job), so anything that must stay pressable
|
|
109
129
|
* goes INSIDE it as `children`, never as a sibling rendered over it.
|
|
110
130
|
*/
|
|
111
|
-
export const Backdrop = memo(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
) {
|
|
131
|
+
export const Backdrop = memo(function Backdrop({
|
|
132
|
+
onPress,
|
|
133
|
+
progress,
|
|
134
|
+
disabled = false,
|
|
135
|
+
blurIntensity = BACKDROP_BLUR_INTENSITY,
|
|
136
|
+
blurTint = 'dark',
|
|
137
|
+
dimColor = '#000',
|
|
138
|
+
dimOpacity = BACKDROP_DIM_OPACITY,
|
|
139
|
+
style,
|
|
140
|
+
layerStyle,
|
|
141
|
+
children,
|
|
142
|
+
accessibilityLabel = 'Dismiss',
|
|
143
|
+
testID,
|
|
144
|
+
}: BackdropProps) {
|
|
126
145
|
const inert = disabled || !onPress;
|
|
146
|
+
|
|
147
|
+
// An `opacity` handed in through `style` would sit on the ancestor of the
|
|
148
|
+
// blur and kill it; hoist it onto the layers instead of honouring it there.
|
|
149
|
+
const flat: ViewStyle = StyleSheet.flatten(style) ?? {};
|
|
150
|
+
const { opacity: styleOpacity, ...rootStyle } = flat;
|
|
151
|
+
const staticOpacity = typeof styleOpacity === 'number' ? styleOpacity : 1;
|
|
152
|
+
|
|
153
|
+
// The fade lives on each LAYER, never on their shared ancestor.
|
|
154
|
+
const blurFade = useAnimatedStyle(
|
|
155
|
+
() => ({ opacity: (progress ? progress.value : 1) * staticOpacity }),
|
|
156
|
+
[progress, staticOpacity],
|
|
157
|
+
);
|
|
158
|
+
const dimFade = useAnimatedStyle(
|
|
159
|
+
() => ({ opacity: (progress ? progress.value : 1) * staticOpacity * dimOpacity }),
|
|
160
|
+
[progress, staticOpacity, dimOpacity],
|
|
161
|
+
);
|
|
162
|
+
|
|
127
163
|
return (
|
|
128
164
|
<Pressable
|
|
129
|
-
// MUST forward the ref: surfaces animate the backdrop through
|
|
130
|
-
// `Animated.createAnimatedComponent(Backdrop)`, and reanimated applies
|
|
131
|
-
// those updates by reaching the underlying host view. With the ref
|
|
132
|
-
// swallowed the animated style never lands, so a backdrop whose opacity
|
|
133
|
-
// is animated from 0 stays at 0 — fully transparent, with the surface
|
|
134
|
-
// floating over an undimmed app.
|
|
135
|
-
ref={ref}
|
|
136
165
|
pointerEvents="auto"
|
|
137
166
|
onPress={inert ? undefined : onPress}
|
|
138
167
|
disabled={inert}
|
|
@@ -143,27 +172,27 @@ export const Backdrop = memo(forwardRef<View, BackdropProps>(function Backdrop(
|
|
|
143
172
|
accessibilityRole={inert ? undefined : 'button'}
|
|
144
173
|
accessibilityLabel={inert ? undefined : accessibilityLabel}
|
|
145
174
|
testID={testID}
|
|
146
|
-
style={[StyleSheet.absoluteFill,
|
|
175
|
+
style={[StyleSheet.absoluteFill, rootStyle]}
|
|
147
176
|
>
|
|
148
177
|
{blurIntensity > 0 ? (
|
|
149
|
-
<
|
|
178
|
+
<AnimatedBlurView
|
|
150
179
|
intensity={blurIntensity}
|
|
151
180
|
tint={blurTint}
|
|
152
181
|
// Android's default blur is a no-op on many devices; this is the
|
|
153
182
|
// implementation that actually renders there.
|
|
154
183
|
experimentalBlurMethod="dimezisBlurView"
|
|
155
184
|
pointerEvents="none"
|
|
156
|
-
style={StyleSheet.absoluteFill}
|
|
185
|
+
style={[StyleSheet.absoluteFill, layerStyle, blurFade]}
|
|
157
186
|
/>
|
|
158
187
|
) : null}
|
|
159
|
-
<View
|
|
188
|
+
<Animated.View
|
|
160
189
|
pointerEvents="none"
|
|
161
|
-
style={[StyleSheet.absoluteFill, { backgroundColor: dimColor,
|
|
190
|
+
style={[StyleSheet.absoluteFill, { backgroundColor: dimColor }, layerStyle, dimFade]}
|
|
162
191
|
/>
|
|
163
192
|
{children}
|
|
164
193
|
</Pressable>
|
|
165
194
|
);
|
|
166
|
-
})
|
|
195
|
+
});
|
|
167
196
|
|
|
168
197
|
Backdrop.displayName = 'Backdrop';
|
|
169
198
|
|
|
@@ -74,8 +74,6 @@ import type {
|
|
|
74
74
|
} from './types';
|
|
75
75
|
|
|
76
76
|
const AnimatedImage = Animated.createAnimatedComponent(Image);
|
|
77
|
-
// The shared overlay backdrop, driven by the viewer's open/drag progress.
|
|
78
|
-
const AnimatedBackdrop = Animated.createAnimatedComponent(Backdrop);
|
|
79
77
|
|
|
80
78
|
// Web-only interaction hints (no-ops on native): the zoom surfaces are
|
|
81
79
|
// tap-to-dismiss (`cursor: pointer`) and must not select text or drag the
|
|
@@ -791,11 +789,15 @@ const ZoomableImageGalleryInner = React.forwardRef<ZoomableImageGalleryHandle, Z
|
|
|
791
789
|
did nothing on web while Escape still closed. `Backdrop` opts back
|
|
792
790
|
in via the `pointerEvents` PROP, the only form that reaches the DOM
|
|
793
791
|
(see `src/overlay`). */}
|
|
794
|
-
|
|
792
|
+
{/* `progress` rather than an animated style: an opacity on the
|
|
793
|
+
backdrop's root would sit ABOVE the blur layer and neutralise it —
|
|
794
|
+
`backdrop-filter` samples nothing under an ancestor that composites
|
|
795
|
+
in isolation. */}
|
|
796
|
+
<Backdrop
|
|
795
797
|
onPress={handleDismiss}
|
|
796
798
|
accessibilityLabel="Close image viewer"
|
|
797
799
|
dimColor={theme.colors.overlay}
|
|
798
|
-
|
|
800
|
+
progress={opacity}
|
|
799
801
|
/>
|
|
800
802
|
|
|
801
803
|
<GestureDetector gesture={panGesture}>
|