react-native-bottom-sheet-stack 1.0.1 → 1.0.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 (70) hide show
  1. package/lib/commonjs/BottomSheet.context.js.map +1 -1
  2. package/lib/commonjs/BottomSheetBackdrop.js +76 -0
  3. package/lib/commonjs/BottomSheetBackdrop.js.map +1 -0
  4. package/lib/commonjs/BottomSheetHost.js +215 -51
  5. package/lib/commonjs/BottomSheetHost.js.map +1 -1
  6. package/lib/commonjs/BottomSheetManaged.js +128 -38
  7. package/lib/commonjs/BottomSheetManaged.js.map +1 -1
  8. package/lib/commonjs/BottomSheetManager.context.js.map +1 -1
  9. package/lib/commonjs/BottomSheetManager.provider.js +38 -13
  10. package/lib/commonjs/BottomSheetManager.provider.js.map +1 -1
  11. package/lib/commonjs/BottomSheetScaleView.js +67 -0
  12. package/lib/commonjs/BottomSheetScaleView.js.map +1 -0
  13. package/lib/commonjs/animatedRegistry.js +25 -0
  14. package/lib/commonjs/animatedRegistry.js.map +1 -0
  15. package/lib/commonjs/bottomSheet.store.js +86 -73
  16. package/lib/commonjs/bottomSheet.store.js.map +1 -1
  17. package/lib/commonjs/bottomSheetCoordinator.js +12 -14
  18. package/lib/commonjs/bottomSheetCoordinator.js.map +1 -1
  19. package/lib/commonjs/index.js +3 -3
  20. package/lib/commonjs/index.js.map +1 -1
  21. package/lib/commonjs/useBottomSheetManager.js +88 -44
  22. package/lib/commonjs/useBottomSheetManager.js.map +1 -1
  23. package/lib/commonjs/useBottomSheetState.js +40 -17
  24. package/lib/commonjs/useBottomSheetState.js.map +1 -1
  25. package/lib/commonjs/useScaleAnimation.js +108 -0
  26. package/lib/commonjs/useScaleAnimation.js.map +1 -0
  27. package/lib/typescript/example/src/App.d.ts +0 -2
  28. package/lib/typescript/example/src/App.d.ts.map +1 -1
  29. package/lib/typescript/src/BottomSheetBackdrop.d.ts +12 -0
  30. package/lib/typescript/src/BottomSheetBackdrop.d.ts.map +1 -0
  31. package/lib/typescript/src/BottomSheetHost.d.ts +2 -6
  32. package/lib/typescript/src/BottomSheetHost.d.ts.map +1 -1
  33. package/lib/typescript/src/BottomSheetManaged.d.ts.map +1 -1
  34. package/lib/typescript/src/BottomSheetManager.context.d.ts +2 -0
  35. package/lib/typescript/src/BottomSheetManager.context.d.ts.map +1 -1
  36. package/lib/typescript/src/BottomSheetManager.provider.d.ts +4 -3
  37. package/lib/typescript/src/BottomSheetManager.provider.d.ts.map +1 -1
  38. package/lib/typescript/src/BottomSheetScaleView.d.ts +18 -0
  39. package/lib/typescript/src/BottomSheetScaleView.d.ts.map +1 -0
  40. package/lib/typescript/src/animatedRegistry.d.ts +4 -0
  41. package/lib/typescript/src/animatedRegistry.d.ts.map +1 -0
  42. package/lib/typescript/src/bottomSheet.store.d.ts +6 -4
  43. package/lib/typescript/src/bottomSheet.store.d.ts.map +1 -1
  44. package/lib/typescript/src/bottomSheetCoordinator.d.ts +1 -1
  45. package/lib/typescript/src/bottomSheetCoordinator.d.ts.map +1 -1
  46. package/lib/typescript/src/index.d.ts +2 -1
  47. package/lib/typescript/src/index.d.ts.map +1 -1
  48. package/lib/typescript/src/useBottomSheetManager.d.ts.map +1 -1
  49. package/lib/typescript/src/useBottomSheetState.d.ts.map +1 -1
  50. package/lib/typescript/src/useScaleAnimation.d.ts +43 -0
  51. package/lib/typescript/src/useScaleAnimation.d.ts.map +1 -0
  52. package/package.json +9 -2
  53. package/src/BottomSheetBackdrop.tsx +61 -0
  54. package/src/BottomSheetHost.tsx +89 -51
  55. package/src/BottomSheetManaged.tsx +26 -33
  56. package/src/BottomSheetManager.context.tsx +2 -0
  57. package/src/BottomSheetManager.provider.tsx +10 -6
  58. package/src/BottomSheetScaleView.tsx +41 -0
  59. package/src/animatedRegistry.ts +22 -0
  60. package/src/bottomSheet.store.ts +132 -97
  61. package/src/bottomSheetCoordinator.ts +15 -15
  62. package/src/index.tsx +2 -4
  63. package/src/useBottomSheetManager.tsx +37 -48
  64. package/src/useBottomSheetState.ts +5 -17
  65. package/src/useScaleAnimation.ts +114 -0
  66. package/lib/commonjs/ScaleBackgroundWrapper.js +0 -69
  67. package/lib/commonjs/ScaleBackgroundWrapper.js.map +0 -1
  68. package/lib/typescript/src/ScaleBackgroundWrapper.d.ts +0 -32
  69. package/lib/typescript/src/ScaleBackgroundWrapper.d.ts.map +0 -1
  70. package/src/ScaleBackgroundWrapper.tsx +0 -98
@@ -0,0 +1,43 @@
1
+ export interface ScaleConfig {
2
+ /** Scale factor when sheet is open (default: 0.92) */
3
+ scale?: number;
4
+ /** Vertical translation when sheet is open (default: 10) */
5
+ translateY?: number;
6
+ /** Border radius when sheet is open (default: 12) */
7
+ borderRadius?: number;
8
+ /** Animation duration in ms (default: 300) */
9
+ duration?: number;
10
+ }
11
+ /**
12
+ * Returns the number of sheets with scaleBackground above a given element.
13
+ * For background wrapper, pass undefined as sheetId - returns 0 or 1 (binary).
14
+ * For sheets, returns the count of scaleBackground sheets above it.
15
+ * Uses shallow comparison internally for optimal re-renders.
16
+ */
17
+ export declare function useScaleDepth(groupId: string, sheetId?: string): number;
18
+ /**
19
+ * Returns animated style for scale effect based on depth.
20
+ * Uses power scaling: scale^depth for cascading effect.
21
+ */
22
+ export declare function useScaleAnimatedStyle(depth: number, config?: ScaleConfig): {
23
+ transform: ({
24
+ scale: number;
25
+ translateY?: undefined;
26
+ } | {
27
+ translateY: number;
28
+ scale?: undefined;
29
+ })[];
30
+ borderRadius: number;
31
+ overflow: "visible";
32
+ } | {
33
+ transform: ({
34
+ scale: number;
35
+ translateY?: undefined;
36
+ } | {
37
+ translateY: number;
38
+ scale?: undefined;
39
+ })[];
40
+ borderRadius: number;
41
+ overflow: "hidden";
42
+ };
43
+ //# sourceMappingURL=useScaleAnimation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useScaleAnimation.d.ts","sourceRoot":"","sources":["../../../src/useScaleAnimation.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,WAAW;IAC1B,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AASD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAuCvE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW;;;;;;;;;;;;;;;;;;;;EAiCxE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-bottom-sheet-stack",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Bottom Sheet Stack Manager",
5
5
  "source": "./src/index.tsx",
6
6
  "main": "lib/commonjs/index.js",
@@ -38,6 +38,7 @@
38
38
  "registry": "https://registry.npmjs.org/"
39
39
  },
40
40
  "devDependencies": {
41
+ "@babel/cli": "^7.28.6",
41
42
  "@commitlint/config-conventional": "^19.6.0",
42
43
  "@eslint/compat": "^1.2.7",
43
44
  "@eslint/eslintrc": "^3.3.0",
@@ -48,6 +49,7 @@
48
49
  "@release-it/conventional-changelog": "^9.0.2",
49
50
  "@types/jest": "^29.5.5",
50
51
  "@types/react": "^19.0.12",
52
+ "babel-plugin-react-compiler": "^1.0.0",
51
53
  "commitlint": "^19.6.1",
52
54
  "del-cli": "^5.1.0",
53
55
  "eslint": "^9.22.0",
@@ -121,7 +123,12 @@
121
123
  "source": "src",
122
124
  "output": "lib",
123
125
  "targets": [
124
- "commonjs",
126
+ [
127
+ "commonjs",
128
+ {
129
+ "configFile": true
130
+ }
131
+ ],
125
132
  "typescript"
126
133
  ]
127
134
  },
@@ -0,0 +1,61 @@
1
+ import { Pressable, StyleSheet } from 'react-native';
2
+ import Animated, {
3
+ Extrapolation,
4
+ interpolate,
5
+ useAnimatedStyle,
6
+ } from 'react-native-reanimated';
7
+ import { getAnimatedIndex } from './animatedRegistry';
8
+ import { useBottomSheetStore } from './bottomSheet.store';
9
+
10
+ interface BottomSheetBackdropProps {
11
+ sheetId: string;
12
+ onPress?: () => void;
13
+ }
14
+
15
+ const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
16
+
17
+ /**
18
+ * Custom backdrop component rendered separately from the scaled sheet content.
19
+ * This ensures the backdrop doesn't scale with the sheet.
20
+ * Opacity is interpolated from the bottom sheet's animatedIndex for smooth animation.
21
+ */
22
+ export function BottomSheetBackdrop({
23
+ sheetId,
24
+ onPress,
25
+ }: BottomSheetBackdropProps) {
26
+ const status = useBottomSheetStore(
27
+ (state) => state.sheetsById[sheetId]?.status
28
+ );
29
+
30
+ const animatedIndex = getAnimatedIndex(sheetId);
31
+
32
+ const isVisible = status === 'opening' || status === 'open';
33
+
34
+ const animatedStyle = useAnimatedStyle(() => {
35
+ // Interpolate opacity based on animatedIndex
36
+ // -1 = closed, 0+ = open at snap point
37
+ const opacity = interpolate(
38
+ animatedIndex.value,
39
+ [-1, 0],
40
+ [0, 1],
41
+ Extrapolation.CLAMP
42
+ );
43
+
44
+ return { opacity };
45
+ });
46
+
47
+ return (
48
+ <AnimatedPressable
49
+ style={[styles.backdrop, animatedStyle]}
50
+ onPress={onPress}
51
+ pointerEvents={isVisible ? 'auto' : 'none'}
52
+ />
53
+ );
54
+ }
55
+
56
+ const styles = StyleSheet.create({
57
+ backdrop: {
58
+ ...StyleSheet.absoluteFillObject,
59
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
60
+ },
61
+ });
@@ -1,39 +1,33 @@
1
- import React, {
2
- Fragment,
3
- useEffect,
4
- useMemo,
5
- type PropsWithChildren,
6
- } from 'react';
1
+ import { useEffect } from 'react';
7
2
  import { StyleSheet, View } from 'react-native';
3
+ import Animated from 'react-native-reanimated';
8
4
  import { useSafeAreaFrame } from 'react-native-safe-area-context';
9
5
 
6
+ import { shallow } from 'zustand/shallow';
7
+ import { cleanupAnimatedIndex } from './animatedRegistry';
8
+ import { BottomSheetBackdrop } from './BottomSheetBackdrop';
10
9
  import { BottomSheetContext } from './BottomSheet.context';
11
10
  import { useBottomSheetStore } from './bottomSheet.store';
12
- import { initBottomSheetCoordinator } from './bottomSheetCoordinator';
13
11
  import { useBottomSheetManagerContext } from './BottomSheetManager.provider';
12
+ import { initBottomSheetCoordinator } from './bottomSheetCoordinator';
13
+ import {
14
+ useScaleAnimatedStyle,
15
+ useScaleDepth,
16
+ type ScaleConfig,
17
+ } from './useScaleAnimation';
14
18
 
15
- initBottomSheetCoordinator();
16
-
17
- interface BottomSheetHostProps {
18
- Container?: React.ComponentType<any>;
19
- }
20
-
21
- function BottomSheetHostComp({ Container = Fragment }: BottomSheetHostProps) {
22
- const { bottomSheetsStack, clearAll } = useBottomSheetStore((store) => ({
23
- bottomSheetsStack: store.stack,
24
- clearAll: store.clearAll,
25
- }));
19
+ function BottomSheetHostComp() {
20
+ const queueIds = useQueueIds();
21
+ const clearAll = useBottomSheetStore((store) => store.clearAll);
26
22
 
27
- const { width, height } = useSafeAreaFrame();
28
- const { groupId } = useBottomSheetManagerContext();
23
+ const { groupId, scaleConfig } = useBottomSheetManagerContext();
29
24
 
30
- const filteredQueue = useMemo(
31
- () =>
32
- bottomSheetsStack.filter(
33
- (bottomSheet) => bottomSheet.groupId === groupId
34
- ),
35
- [bottomSheetsStack, groupId]
36
- );
25
+ useEffect(() => {
26
+ const unsubscribe = initBottomSheetCoordinator(groupId);
27
+ return () => {
28
+ unsubscribe();
29
+ };
30
+ }, [groupId]);
37
31
 
38
32
  useEffect(() => {
39
33
  return () => {
@@ -43,38 +37,82 @@ function BottomSheetHostComp({ Container = Fragment }: BottomSheetHostProps) {
43
37
 
44
38
  return (
45
39
  <>
46
- {filteredQueue.map(({ id, content }) => (
47
- <BottomSheetContext.Provider key={id} value={{ id }}>
48
- <Container>
49
- <View
50
- style={[
51
- StyleSheet.absoluteFillObject,
52
- styles.container,
53
- {
54
- width,
55
- height,
56
- },
57
- ]}
58
- >
59
- <MemoizedContent id={id}>{content}</MemoizedContent>
60
- </View>
61
- </Container>
62
- </BottomSheetContext.Provider>
40
+ {queueIds.map((id) => (
41
+ <QueueItem
42
+ key={id}
43
+ id={id}
44
+ groupId={groupId}
45
+ scaleConfig={scaleConfig}
46
+ />
63
47
  ))}
64
48
  </>
65
49
  );
66
50
  }
67
51
 
68
- const MemoizedContent = React.memo(
69
- ({ children }: PropsWithChildren<{ id: string }>) => <>{children}</>,
70
- (prevProps, nextProps) => {
71
- return prevProps.id === nextProps.id;
72
- }
73
- );
52
+ function QueueItem({
53
+ id,
54
+ groupId,
55
+ scaleConfig,
56
+ }: {
57
+ id: string;
58
+ groupId: string;
59
+ scaleConfig?: ScaleConfig;
60
+ }) {
61
+ const content = useBottomSheetStore((state) => state.sheetsById[id]?.content);
62
+
63
+ const { width, height } = useSafeAreaFrame();
64
+ const value = { id };
65
+
66
+ const scaleDepth = useScaleDepth(groupId, id);
67
+ const scaleStyle = useScaleAnimatedStyle(scaleDepth, scaleConfig);
68
+
69
+ // Cleanup animated index when sheet is unmounted
70
+ useEffect(() => {
71
+ return () => {
72
+ cleanupAnimatedIndex(id);
73
+ };
74
+ }, [id]);
75
+
76
+ return (
77
+ <BottomSheetContext.Provider value={value}>
78
+ {/* Backdrop - rendered without scaling */}
79
+ <View style={[StyleSheet.absoluteFillObject, styles.backdropContainer]}>
80
+ <BottomSheetBackdrop sheetId={id} />
81
+ </View>
82
+
83
+ {/* Sheet content - rendered with scaling */}
84
+ <Animated.View
85
+ style={[
86
+ StyleSheet.absoluteFillObject,
87
+ styles.container,
88
+ { width, height },
89
+ scaleStyle,
90
+ ]}
91
+ >
92
+ {content}
93
+ </Animated.View>
94
+ </BottomSheetContext.Provider>
95
+ );
96
+ }
97
+
98
+ const useQueueIds = () => {
99
+ const { groupId } = useBottomSheetManagerContext();
74
100
 
75
- export const BottomSheetHost = React.memo(BottomSheetHostComp);
101
+ return useBottomSheetStore(
102
+ (state) =>
103
+ state.stackOrder.filter(
104
+ (sheetId) => state.sheetsById[sheetId]?.groupId === groupId
105
+ ),
106
+ shallow
107
+ );
108
+ };
109
+
110
+ export const BottomSheetHost = BottomSheetHostComp;
76
111
 
77
112
  const styles = StyleSheet.create({
113
+ backdropContainer: {
114
+ zIndex: 99_999_999,
115
+ },
78
116
  container: {
79
117
  zIndex: 100_000_000,
80
118
  pointerEvents: 'box-none',
@@ -1,12 +1,11 @@
1
1
  import BottomSheetOriginal, {
2
- BottomSheetBackdrop,
3
2
  useBottomSheetSpringConfigs,
4
- type BottomSheetBackdropProps,
5
3
  type BottomSheetProps,
6
4
  } from '@gorhom/bottom-sheet';
7
5
  import { type BottomSheetMethods } from '@gorhom/bottom-sheet/lib/typescript/types';
8
- import React, { useCallback, useMemo } from 'react';
6
+ import React from 'react';
9
7
 
8
+ import { getAnimatedIndex } from './animatedRegistry';
10
9
  import { createSheetEventHandlers } from './bottomSheetCoordinator';
11
10
  import { useBottomSheetState } from './useBottomSheetState';
12
11
 
@@ -14,6 +13,9 @@ export interface BottomSheetRef extends BottomSheetMethods {}
14
13
 
15
14
  interface BottomSheetManagedProps extends BottomSheetProps {}
16
15
 
16
+ // Null backdrop - we render our own backdrop separately in BottomSheetHost
17
+ const nullBackdrop = () => null;
18
+
17
19
  export const BottomSheetManaged = React.forwardRef<
18
20
  BottomSheetRef,
19
21
  BottomSheetManagedProps
@@ -24,35 +26,36 @@ export const BottomSheetManaged = React.forwardRef<
24
26
  onAnimate,
25
27
  onClose,
26
28
  enablePanDownToClose = true,
27
- backdropComponent,
29
+ backdropComponent = nullBackdrop,
30
+ animatedIndex: externalAnimatedIndex,
28
31
  ...props
29
32
  },
30
33
  ref
31
34
  ) => {
32
35
  const { bottomSheetState } = useBottomSheetState();
33
36
 
34
- const { handleAnimate, handleClose } = useMemo(
35
- () => createSheetEventHandlers(bottomSheetState.id),
36
- [bottomSheetState.id]
37
- );
37
+ // Get or create shared animated index for this sheet
38
+ const animatedIndex =
39
+ externalAnimatedIndex ?? getAnimatedIndex(bottomSheetState.id);
38
40
 
39
- const wrappedOnAnimate: BottomSheetProps['onAnimate'] = useCallback(
40
- (
41
- fromIndex: number,
42
- toIndex: number,
43
- fromPosition: number,
44
- toPosition: number
45
- ) => {
46
- handleAnimate(fromIndex, toIndex);
47
- onAnimate?.(fromIndex, toIndex, fromPosition, toPosition);
48
- },
49
- [handleAnimate, onAnimate]
41
+ const { handleAnimate, handleClose } = createSheetEventHandlers(
42
+ bottomSheetState.id
50
43
  );
51
44
 
52
- const wrappedOnClose = useCallback(() => {
45
+ const wrappedOnAnimate: BottomSheetProps['onAnimate'] = (
46
+ fromIndex: number,
47
+ toIndex: number,
48
+ fromPosition: number,
49
+ toPosition: number
50
+ ) => {
51
+ handleAnimate(fromIndex, toIndex);
52
+ onAnimate?.(fromIndex, toIndex, fromPosition, toPosition);
53
+ };
54
+
55
+ const wrappedOnClose = () => {
53
56
  onClose?.();
54
57
  handleClose();
55
- }, [handleClose, onClose]);
58
+ };
56
59
 
57
60
  const config = useBottomSheetSpringConfigs({
58
61
  stiffness: 400,
@@ -60,25 +63,15 @@ export const BottomSheetManaged = React.forwardRef<
60
63
  mass: 0.7,
61
64
  });
62
65
 
63
- const renderBackdropComponent = useCallback(
64
- (backdropProps: BottomSheetBackdropProps) => (
65
- <BottomSheetBackdrop
66
- {...backdropProps}
67
- disappearsOnIndex={-1}
68
- appearsOnIndex={0}
69
- />
70
- ),
71
- []
72
- );
73
-
74
66
  return (
75
67
  <BottomSheetOriginal
76
68
  animationConfigs={config}
77
69
  ref={ref}
78
70
  {...props}
71
+ animatedIndex={animatedIndex}
79
72
  onClose={wrappedOnClose}
80
73
  onAnimate={wrappedOnAnimate}
81
- backdropComponent={backdropComponent || renderBackdropComponent}
74
+ backdropComponent={backdropComponent}
82
75
  enablePanDownToClose={enablePanDownToClose}
83
76
  >
84
77
  {children}
@@ -1,7 +1,9 @@
1
1
  import React from 'react';
2
+ import type { ScaleConfig } from './useScaleAnimation';
2
3
 
3
4
  export interface BottomSheetManagerContextValue {
4
5
  groupId: string;
6
+ scaleConfig?: ScaleConfig;
5
7
  }
6
8
 
7
9
  export const BottomSheetManagerContext =
@@ -4,23 +4,27 @@ import {
4
4
  BottomSheetManagerContext,
5
5
  type BottomSheetManagerContextValue,
6
6
  } from './BottomSheetManager.context';
7
+ import type { ScaleConfig } from './useScaleAnimation';
7
8
 
8
9
  interface ProviderProps extends PropsWithChildren {
9
10
  id: string;
11
+ scaleConfig?: ScaleConfig;
10
12
  }
11
13
 
12
- function BottomSheetManagerProviderComp({ id, children }: ProviderProps) {
14
+ export function BottomSheetManagerProvider({
15
+ id,
16
+ scaleConfig,
17
+ children,
18
+ }: ProviderProps) {
19
+ const value = { groupId: id, scaleConfig };
20
+
13
21
  return (
14
- <BottomSheetManagerContext.Provider key={id} value={{ groupId: id }}>
22
+ <BottomSheetManagerContext.Provider key={id} value={value}>
15
23
  {children}
16
24
  </BottomSheetManagerContext.Provider>
17
25
  );
18
26
  }
19
27
 
20
- export const BottomSheetManagerProvider = React.memo(
21
- BottomSheetManagerProviderComp
22
- );
23
-
24
28
  export const useBottomSheetManagerContext =
25
29
  (): BottomSheetManagerContextValue => {
26
30
  const context = React.useContext(BottomSheetManagerContext);
@@ -0,0 +1,41 @@
1
+ import { useContext, type PropsWithChildren } from 'react';
2
+ import { StyleSheet } from 'react-native';
3
+ import Animated from 'react-native-reanimated';
4
+ import { BottomSheetManagerContext } from './BottomSheetManager.context';
5
+ import { useScaleAnimatedStyle, useScaleDepth } from './useScaleAnimation';
6
+
7
+ /**
8
+ * Wraps your app content with iOS-style scale animation when a bottom sheet
9
+ * with scaleBackground: true is open. Place your main content inside this
10
+ * component, but keep BottomSheetHost outside of it.
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * <BottomSheetManagerProvider id="default" scaleConfig={{ scale: 0.92 }}>
15
+ * <BottomSheetScaleView>
16
+ * <MainContent />
17
+ * </BottomSheetScaleView>
18
+ * <BottomSheetHost />
19
+ * </BottomSheetManagerProvider>
20
+ * ```
21
+ */
22
+ export function BottomSheetScaleView({ children }: PropsWithChildren) {
23
+ const context = useContext(BottomSheetManagerContext);
24
+ const groupId = context?.groupId ?? 'default';
25
+ const scaleConfig = context?.scaleConfig;
26
+
27
+ const scaleDepth = useScaleDepth(groupId);
28
+ const animatedStyle = useScaleAnimatedStyle(scaleDepth, scaleConfig);
29
+
30
+ return (
31
+ <Animated.View style={[styles.container, animatedStyle]}>
32
+ {children}
33
+ </Animated.View>
34
+ );
35
+ }
36
+
37
+ const styles = StyleSheet.create({
38
+ container: {
39
+ flex: 1,
40
+ },
41
+ });
@@ -0,0 +1,22 @@
1
+ import { makeMutable, type SharedValue } from 'react-native-reanimated';
2
+
3
+ /**
4
+ * Registry for shared animated values per sheet.
5
+ * This allows backdrop to access the animatedIndex from the bottom sheet.
6
+ */
7
+ const animatedIndexRegistry = new Map<string, SharedValue<number>>();
8
+
9
+ export function getAnimatedIndex(sheetId: string): SharedValue<number> {
10
+ let animatedIndex = animatedIndexRegistry.get(sheetId);
11
+
12
+ if (!animatedIndex) {
13
+ animatedIndex = makeMutable(-1);
14
+ animatedIndexRegistry.set(sheetId, animatedIndex);
15
+ }
16
+
17
+ return animatedIndex;
18
+ }
19
+
20
+ export function cleanupAnimatedIndex(sheetId: string): void {
21
+ animatedIndexRegistry.delete(sheetId);
22
+ }