react-native-bottom-sheet-stack 1.7.6 → 1.9.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.
Files changed (112) hide show
  1. package/lib/commonjs/BottomSheetManaged.js +5 -172
  2. package/lib/commonjs/BottomSheetManaged.js.map +1 -1
  3. package/lib/commonjs/BottomSheetPersistent.js.map +1 -1
  4. package/lib/commonjs/BottomSheetRef.context.js.map +1 -1
  5. package/lib/commonjs/adapter.types.js +6 -0
  6. package/lib/commonjs/adapter.types.js.map +1 -0
  7. package/lib/commonjs/adapters/actions-sheet/ActionsSheetAdapter.js +137 -0
  8. package/lib/commonjs/adapters/actions-sheet/ActionsSheetAdapter.js.map +1 -0
  9. package/lib/commonjs/adapters/actions-sheet/index.js +13 -0
  10. package/lib/commonjs/adapters/actions-sheet/index.js.map +1 -0
  11. package/lib/commonjs/adapters/custom-modal/CustomModalAdapter.js +136 -0
  12. package/lib/commonjs/adapters/custom-modal/CustomModalAdapter.js.map +1 -0
  13. package/lib/commonjs/adapters/custom-modal/index.js +19 -0
  14. package/lib/commonjs/adapters/custom-modal/index.js.map +1 -0
  15. package/lib/commonjs/adapters/gorhom-sheet/GorhomSheetAdapter.js +189 -0
  16. package/lib/commonjs/adapters/gorhom-sheet/GorhomSheetAdapter.js.map +1 -0
  17. package/lib/commonjs/adapters/gorhom-sheet/index.js +13 -0
  18. package/lib/commonjs/adapters/gorhom-sheet/index.js.map +1 -0
  19. package/lib/commonjs/adapters/index.js +40 -0
  20. package/lib/commonjs/adapters/index.js.map +1 -0
  21. package/lib/commonjs/adapters/react-native-modal/ReactNativeModalAdapter.js +119 -0
  22. package/lib/commonjs/adapters/react-native-modal/ReactNativeModalAdapter.js.map +1 -0
  23. package/lib/commonjs/adapters/react-native-modal/index.js +13 -0
  24. package/lib/commonjs/adapters/react-native-modal/index.js.map +1 -0
  25. package/lib/commonjs/animatedRegistry.js +11 -1
  26. package/lib/commonjs/animatedRegistry.js.map +1 -1
  27. package/lib/commonjs/bottomSheetCoordinator.js +29 -22
  28. package/lib/commonjs/bottomSheetCoordinator.js.map +1 -1
  29. package/lib/commonjs/index.js +75 -1
  30. package/lib/commonjs/index.js.map +1 -1
  31. package/lib/commonjs/refsMap.js.map +1 -1
  32. package/lib/commonjs/useAdapterRef.js +29 -0
  33. package/lib/commonjs/useAdapterRef.js.map +1 -0
  34. package/lib/commonjs/useAnimatedIndex.js +47 -0
  35. package/lib/commonjs/useAnimatedIndex.js.map +1 -0
  36. package/lib/commonjs/useBackHandler.js +59 -0
  37. package/lib/commonjs/useBackHandler.js.map +1 -0
  38. package/lib/commonjs/useBottomSheetControl.js.map +1 -1
  39. package/lib/commonjs/useBottomSheetManager.js.map +1 -1
  40. package/lib/typescript/example/src/App.d.ts.map +1 -1
  41. package/lib/typescript/example/src/screens/HomeScreen.d.ts.map +1 -1
  42. package/lib/typescript/example/src/sheets/ContextSheets.d.ts.map +1 -1
  43. package/lib/typescript/example/src/sheets/ModalSheets.d.ts +8 -0
  44. package/lib/typescript/example/src/sheets/ModalSheets.d.ts.map +1 -0
  45. package/lib/typescript/example/src/sheets/PersistentMixedAdapters.d.ts +2 -0
  46. package/lib/typescript/example/src/sheets/PersistentMixedAdapters.d.ts.map +1 -0
  47. package/lib/typescript/example/src/sheets/ThirdPartyAdapterSheets.d.ts +17 -0
  48. package/lib/typescript/example/src/sheets/ThirdPartyAdapterSheets.d.ts.map +1 -0
  49. package/lib/typescript/example/src/sheets/index.d.ts +3 -0
  50. package/lib/typescript/example/src/sheets/index.d.ts.map +1 -1
  51. package/lib/typescript/src/BottomSheetManaged.d.ts +10 -9
  52. package/lib/typescript/src/BottomSheetManaged.d.ts.map +1 -1
  53. package/lib/typescript/src/BottomSheetPersistent.d.ts.map +1 -1
  54. package/lib/typescript/src/BottomSheetRef.context.d.ts +1 -4
  55. package/lib/typescript/src/BottomSheetRef.context.d.ts.map +1 -1
  56. package/lib/typescript/src/adapter.types.d.ts +33 -0
  57. package/lib/typescript/src/adapter.types.d.ts.map +1 -0
  58. package/lib/typescript/src/adapters/actions-sheet/ActionsSheetAdapter.d.ts +23 -0
  59. package/lib/typescript/src/adapters/actions-sheet/ActionsSheetAdapter.d.ts.map +1 -0
  60. package/lib/typescript/src/adapters/actions-sheet/index.d.ts +2 -0
  61. package/lib/typescript/src/adapters/actions-sheet/index.d.ts.map +1 -0
  62. package/lib/typescript/src/adapters/custom-modal/CustomModalAdapter.d.ts +9 -0
  63. package/lib/typescript/src/adapters/custom-modal/CustomModalAdapter.d.ts.map +1 -0
  64. package/lib/typescript/src/adapters/custom-modal/index.d.ts +4 -0
  65. package/lib/typescript/src/adapters/custom-modal/index.d.ts.map +1 -0
  66. package/lib/typescript/src/adapters/gorhom-sheet/GorhomSheetAdapter.d.ts +7 -0
  67. package/lib/typescript/src/adapters/gorhom-sheet/GorhomSheetAdapter.d.ts.map +1 -0
  68. package/lib/typescript/src/adapters/gorhom-sheet/index.d.ts +2 -0
  69. package/lib/typescript/src/adapters/gorhom-sheet/index.d.ts.map +1 -0
  70. package/lib/typescript/src/adapters/index.d.ts +5 -0
  71. package/lib/typescript/src/adapters/index.d.ts.map +1 -0
  72. package/lib/typescript/src/adapters/react-native-modal/ReactNativeModalAdapter.d.ts +22 -0
  73. package/lib/typescript/src/adapters/react-native-modal/ReactNativeModalAdapter.d.ts.map +1 -0
  74. package/lib/typescript/src/adapters/react-native-modal/index.d.ts +2 -0
  75. package/lib/typescript/src/adapters/react-native-modal/index.d.ts.map +1 -0
  76. package/lib/typescript/src/animatedRegistry.d.ts +4 -0
  77. package/lib/typescript/src/animatedRegistry.d.ts.map +1 -1
  78. package/lib/typescript/src/bottomSheetCoordinator.d.ts +13 -7
  79. package/lib/typescript/src/bottomSheetCoordinator.d.ts.map +1 -1
  80. package/lib/typescript/src/index.d.ts +12 -0
  81. package/lib/typescript/src/index.d.ts.map +1 -1
  82. package/lib/typescript/src/refsMap.d.ts +1 -4
  83. package/lib/typescript/src/refsMap.d.ts.map +1 -1
  84. package/lib/typescript/src/useAdapterRef.d.ts +21 -0
  85. package/lib/typescript/src/useAdapterRef.d.ts.map +1 -0
  86. package/lib/typescript/src/useAnimatedIndex.d.ts +25 -0
  87. package/lib/typescript/src/useAnimatedIndex.d.ts.map +1 -0
  88. package/lib/typescript/src/useBackHandler.d.ts +8 -0
  89. package/lib/typescript/src/useBackHandler.d.ts.map +1 -0
  90. package/package.json +33 -2
  91. package/src/BottomSheetManaged.tsx +14 -106
  92. package/src/BottomSheetPersistent.tsx +2 -2
  93. package/src/BottomSheetRef.context.ts +2 -4
  94. package/src/adapter.types.ts +35 -0
  95. package/src/adapters/actions-sheet/ActionsSheetAdapter.tsx +83 -0
  96. package/src/adapters/actions-sheet/index.ts +4 -0
  97. package/src/adapters/custom-modal/CustomModalAdapter.tsx +117 -0
  98. package/src/adapters/custom-modal/index.ts +7 -0
  99. package/src/adapters/gorhom-sheet/GorhomSheetAdapter.tsx +121 -0
  100. package/src/adapters/gorhom-sheet/index.ts +4 -0
  101. package/src/adapters/index.ts +17 -0
  102. package/src/adapters/react-native-modal/ReactNativeModalAdapter.tsx +81 -0
  103. package/src/adapters/react-native-modal/index.ts +4 -0
  104. package/src/animatedRegistry.ts +10 -1
  105. package/src/bottomSheetCoordinator.ts +32 -24
  106. package/src/index.tsx +34 -0
  107. package/src/refsMap.ts +1 -4
  108. package/src/useAdapterRef.ts +28 -0
  109. package/src/useAnimatedIndex.ts +31 -0
  110. package/src/useBackHandler.ts +32 -0
  111. package/src/useBottomSheetControl.ts +2 -2
  112. package/src/useBottomSheetManager.tsx +2 -2
@@ -0,0 +1,121 @@
1
+ import BottomSheetOriginal, {
2
+ useBottomSheetSpringConfigs,
3
+ type BottomSheetProps,
4
+ } from '@gorhom/bottom-sheet';
5
+ import React, { useImperativeHandle, useRef } from 'react';
6
+ import { useAnimatedReaction } from 'react-native-reanimated';
7
+
8
+ import type { SheetAdapterRef } from '../../adapter.types';
9
+ import { createSheetEventHandlers } from '../../bottomSheetCoordinator';
10
+ import { useBottomSheetDefaultIndex } from '../../BottomSheetDefaultIndex.context';
11
+ import { useAdapterRef } from '../../useAdapterRef';
12
+ import { useAnimatedIndex } from '../../useAnimatedIndex';
13
+ import { useBackHandler } from '../../useBackHandler';
14
+ import { useBottomSheetContext } from '../../useBottomSheetContext';
15
+ import type { BottomSheetMethods } from '@gorhom/bottom-sheet/lib/typescript/types';
16
+
17
+ export interface GorhomSheetAdapterProps extends BottomSheetProps {}
18
+
19
+ const nullBackdrop = () => null;
20
+
21
+ export const GorhomSheetAdapter = React.forwardRef<
22
+ SheetAdapterRef,
23
+ GorhomSheetAdapterProps
24
+ >(
25
+ (
26
+ {
27
+ children,
28
+ onAnimate,
29
+ onChange,
30
+ onClose,
31
+ enablePanDownToClose = true,
32
+ backdropComponent = nullBackdrop,
33
+ animatedIndex: externalAnimatedIndex,
34
+ ...props
35
+ },
36
+ forwardedRef
37
+ ) => {
38
+ const { id } = useBottomSheetContext();
39
+ const ref = useAdapterRef(forwardedRef);
40
+ const contextAnimatedIndex = useAnimatedIndex();
41
+ const defaultIndex = useBottomSheetDefaultIndex();
42
+
43
+ const gorhomRef = useRef<BottomSheetMethods | null>(null);
44
+
45
+ useImperativeHandle(
46
+ ref,
47
+ () => ({
48
+ expand: () => gorhomRef.current?.expand(),
49
+ close: () => gorhomRef.current?.close(),
50
+ }),
51
+ []
52
+ );
53
+
54
+ useAnimatedReaction(
55
+ () => contextAnimatedIndex.value,
56
+ (value) => {
57
+ externalAnimatedIndex?.set(value);
58
+ }
59
+ );
60
+
61
+ const { handleDismiss, handleOpened, handleClosed } =
62
+ createSheetEventHandlers(id);
63
+
64
+ useBackHandler(id, handleDismiss);
65
+
66
+ const wrappedOnAnimate: BottomSheetProps['onAnimate'] = (
67
+ fromIndex,
68
+ toIndex,
69
+ fromPosition,
70
+ toPosition
71
+ ) => {
72
+ // toIndex === -1 means gorhom is animating toward closed state
73
+ if (toIndex === -1) {
74
+ handleDismiss();
75
+ }
76
+ onAnimate?.(fromIndex, toIndex, fromPosition, toPosition);
77
+ };
78
+
79
+ const wrappedOnChange: BottomSheetProps['onChange'] = (
80
+ index,
81
+ position,
82
+ type
83
+ ) => {
84
+ // index >= 0 means sheet reached a valid snap point (opened)
85
+ if (index >= 0) {
86
+ handleOpened();
87
+ }
88
+ onChange?.(index, position, type);
89
+ };
90
+
91
+ const wrappedOnClose = () => {
92
+ onClose?.();
93
+ handleClosed();
94
+ };
95
+
96
+ const config = useBottomSheetSpringConfigs({
97
+ stiffness: 400,
98
+ damping: 80,
99
+ mass: 0.7,
100
+ });
101
+
102
+ return (
103
+ <BottomSheetOriginal
104
+ animationConfigs={config}
105
+ ref={gorhomRef}
106
+ {...props}
107
+ index={defaultIndex}
108
+ animatedIndex={contextAnimatedIndex}
109
+ onChange={wrappedOnChange}
110
+ onClose={wrappedOnClose}
111
+ onAnimate={wrappedOnAnimate}
112
+ backdropComponent={backdropComponent}
113
+ enablePanDownToClose={enablePanDownToClose}
114
+ >
115
+ {children}
116
+ </BottomSheetOriginal>
117
+ );
118
+ }
119
+ );
120
+
121
+ GorhomSheetAdapter.displayName = 'GorhomSheetAdapter';
@@ -0,0 +1,4 @@
1
+ export {
2
+ GorhomSheetAdapter,
3
+ type GorhomSheetAdapterProps,
4
+ } from './GorhomSheetAdapter';
@@ -0,0 +1,17 @@
1
+ export {
2
+ GorhomSheetAdapter,
3
+ type GorhomSheetAdapterProps,
4
+ } from './gorhom-sheet';
5
+ export {
6
+ CustomModalAdapter,
7
+ ModalAdapter,
8
+ type ModalAdapterProps,
9
+ } from './custom-modal';
10
+ export {
11
+ ReactNativeModalAdapter,
12
+ type ReactNativeModalAdapterProps,
13
+ } from './react-native-modal';
14
+ export {
15
+ ActionsSheetAdapter,
16
+ type ActionsSheetAdapterProps,
17
+ } from './actions-sheet';
@@ -0,0 +1,81 @@
1
+ import React, { useImperativeHandle, useState } from 'react';
2
+
3
+ import type { SheetAdapterRef } from '../../adapter.types';
4
+ import { createSheetEventHandlers } from '../../bottomSheetCoordinator';
5
+ import { useAdapterRef } from '../../useAdapterRef';
6
+ import { useAnimatedIndex } from '../../useAnimatedIndex';
7
+ import { useBottomSheetContext } from '../../useBottomSheetContext';
8
+
9
+ const RNModal = require('react-native-modal').default;
10
+
11
+ /**
12
+ * Adapter for `react-native-modal`.
13
+ *
14
+ * All react-native-modal props are accepted via spread and forwarded
15
+ * to the underlying component. The adapter sets opinionated defaults
16
+ * (swipe-to-dismiss, native driver) that can be overridden.
17
+ *
18
+ * Requires `react-native-modal` as a peer dependency:
19
+ * ```
20
+ * npm install react-native-modal
21
+ * ```
22
+ *
23
+ * @see https://github.com/react-native-modal/react-native-modal
24
+ */
25
+ export interface ReactNativeModalAdapterProps {
26
+ children: React.ReactNode;
27
+ [key: string]: unknown;
28
+ }
29
+
30
+ export const ReactNativeModalAdapter = React.forwardRef<
31
+ SheetAdapterRef,
32
+ ReactNativeModalAdapterProps
33
+ >(({ children, ...modalProps }, forwardedRef) => {
34
+ const { id } = useBottomSheetContext();
35
+ const ref = useAdapterRef(forwardedRef);
36
+ const animatedIndex = useAnimatedIndex();
37
+ const [isVisible, setIsVisible] = useState(false);
38
+
39
+ const { handleDismiss, handleOpened, handleClosed } =
40
+ createSheetEventHandlers(id);
41
+
42
+ useImperativeHandle(
43
+ ref,
44
+ () => ({
45
+ expand: () => {
46
+ setIsVisible(true);
47
+ animatedIndex.set(0);
48
+ },
49
+ close: () => {
50
+ setIsVisible(false);
51
+ animatedIndex.set(-1);
52
+ },
53
+ }),
54
+ [animatedIndex]
55
+ );
56
+
57
+ return (
58
+ <RNModal
59
+ // Adapter defaults (overridable via spread)
60
+ swipeDirection="down"
61
+ useNativeDriver
62
+ hideModalContentWhileAnimating
63
+ {...modalProps}
64
+ // Managed by adapter (not overridable)
65
+ // coverScreen={false}: renders as View instead of native Modal,
66
+ // so QueueItem z-index controls stacking order for push mode.
67
+ // hasBackdrop={false}: manager's BottomSheetBackdrop handles the overlay.
68
+ isVisible={isVisible}
69
+ coverScreen={false}
70
+ hasBackdrop={false}
71
+ onModalShow={handleOpened}
72
+ onModalHide={handleClosed}
73
+ onBackButtonPress={handleDismiss}
74
+ onSwipeComplete={handleDismiss}
75
+ >
76
+ {children}
77
+ </RNModal>
78
+ );
79
+ });
80
+
81
+ ReactNativeModalAdapter.displayName = 'ReactNativeModalAdapter';
@@ -0,0 +1,4 @@
1
+ export {
2
+ ReactNativeModalAdapter,
3
+ type ReactNativeModalAdapterProps,
4
+ } from './ReactNativeModalAdapter';
@@ -21,8 +21,17 @@ export function ensureAnimatedIndex(sheetId: string): SharedValue<number> {
21
21
  export function getAnimatedIndex(
22
22
  sheetId: string
23
23
  ): SharedValue<number> | undefined {
24
+ return animatedIndexRegistry.get(sheetId);
25
+ }
26
+
27
+ /**
28
+ * Set the animated index value for a sheet.
29
+ */
30
+ export function setAnimatedIndexValue(sheetId: string, value: number): void {
24
31
  const animatedIndex = animatedIndexRegistry.get(sheetId);
25
- return animatedIndex;
32
+ if (animatedIndex) {
33
+ animatedIndex.value = value;
34
+ }
26
35
  }
27
36
 
28
37
  export function cleanupAnimatedIndex(sheetId: string): void {
@@ -1,6 +1,11 @@
1
+ import type { SheetAdapterEvents } from './adapter.types';
1
2
  import { useBottomSheetStore } from './bottomSheet.store';
2
3
  import { getSheetRef } from './refsMap';
3
4
 
5
+ /**
6
+ * Subscribes to store changes and calls adapter ref methods.
7
+ * Direction: Store → Adapter (via SheetAdapterRef)
8
+ */
4
9
  export function initBottomSheetCoordinator(groupId: string) {
5
10
  return useBottomSheetStore.subscribe(
6
11
  (s) =>
@@ -19,13 +24,17 @@ export function initBottomSheetCoordinator(groupId: string) {
19
24
 
20
25
  switch (status) {
21
26
  case 'opening':
22
- getSheetRef(id)?.current?.expand();
27
+ requestAnimationFrame(() => {
28
+ const currentStatus =
29
+ useBottomSheetStore.getState().sheetsById[id]?.status;
30
+ if (currentStatus === 'opening') {
31
+ getSheetRef(id)?.current?.expand();
32
+ }
33
+ });
23
34
  break;
24
35
  case 'hidden':
25
- if (ref) ref.close();
26
- break;
27
36
  case 'closing':
28
- if (ref) ref.close();
37
+ ref?.close();
29
38
  break;
30
39
  }
31
40
  });
@@ -34,46 +43,45 @@ export function initBottomSheetCoordinator(groupId: string) {
34
43
  }
35
44
 
36
45
  /**
37
- * Creates event handlers for a bottom sheet that sync gorhom events back to the store.
38
- * Direction: Gorhom Events → Store
46
+ * Creates event handlers that adapters call to sync UI state back to the store.
47
+ * Direction: Adapter Events → Store
48
+ *
49
+ * Adapters must call:
50
+ * - `handleDismiss()` when the user initiates dismissal (swipe, backdrop tap, back button)
51
+ * - `handleOpened()` when the show animation completes
52
+ * - `handleClosed()` when the hide animation completes
39
53
  */
40
- export function createSheetEventHandlers(sheetId: string) {
41
- const { startClosing, finishClosing, markOpen } =
42
- useBottomSheetStore.getState();
43
-
44
- const handleAnimate = (_fromIndex: number, toIndex: number) => {
54
+ export function createSheetEventHandlers(sheetId: string): SheetAdapterEvents {
55
+ const handleDismiss = () => {
45
56
  const state = useBottomSheetStore.getState();
46
57
  const currentStatus = state.sheetsById[sheetId]?.status;
47
58
 
48
- if (
49
- toIndex === -1 &&
50
- (currentStatus === 'open' || currentStatus === 'opening')
51
- ) {
52
- startClosing(sheetId);
59
+ if (currentStatus === 'open' || currentStatus === 'opening') {
60
+ state.startClosing(sheetId);
53
61
  }
54
62
  };
55
63
 
56
- const handleChange = (index: number) => {
64
+ const handleOpened = () => {
57
65
  const state = useBottomSheetStore.getState();
58
66
  const currentStatus = state.sheetsById[sheetId]?.status;
59
67
 
60
- if (index >= 0 && currentStatus === 'opening') {
61
- markOpen(sheetId);
68
+ if (currentStatus === 'opening') {
69
+ state.markOpen(sheetId);
62
70
  }
63
71
  };
64
72
 
65
- const handleClose = () => {
73
+ const handleClosed = () => {
66
74
  const state = useBottomSheetStore.getState();
67
75
  const currentStatus = state.sheetsById[sheetId]?.status;
68
76
 
69
77
  if (currentStatus !== 'hidden') {
70
- finishClosing(sheetId);
78
+ state.finishClosing(sheetId);
71
79
  }
72
80
  };
73
81
 
74
82
  return {
75
- handleAnimate,
76
- handleChange,
77
- handleClose,
83
+ handleDismiss,
84
+ handleOpened,
85
+ handleClosed,
78
86
  };
79
87
  }
package/src/index.tsx CHANGED
@@ -6,6 +6,40 @@ export { BottomSheetManaged, type BottomSheetRef } from './BottomSheetManaged';
6
6
  export { BottomSheetPortal } from './BottomSheetPortal';
7
7
  export { BottomSheetPersistent } from './BottomSheetPersistent';
8
8
 
9
+ // Adapters
10
+ export {
11
+ GorhomSheetAdapter,
12
+ type GorhomSheetAdapterProps,
13
+ } from './adapters/gorhom-sheet';
14
+ export {
15
+ CustomModalAdapter,
16
+ type ModalAdapterProps,
17
+ } from './adapters/custom-modal';
18
+ /** @deprecated Use `CustomModalAdapter` instead. */
19
+ export { ModalAdapter } from './adapters/custom-modal';
20
+ export {
21
+ ReactNativeModalAdapter,
22
+ type ReactNativeModalAdapterProps,
23
+ } from './adapters/react-native-modal';
24
+ export {
25
+ ActionsSheetAdapter,
26
+ type ActionsSheetAdapterProps,
27
+ } from './adapters/actions-sheet';
28
+
29
+ // Adapter types
30
+ export type {
31
+ SheetAdapterRef,
32
+ SheetAdapterEvents,
33
+ SheetRef,
34
+ } from './adapter.types';
35
+
36
+ // Adapter utilities (for custom adapter authors)
37
+ export { createSheetEventHandlers } from './bottomSheetCoordinator';
38
+ export { useAdapterRef } from './useAdapterRef';
39
+ export { useAnimatedIndex } from './useAnimatedIndex';
40
+ export { useBackHandler } from './useBackHandler';
41
+ export { getAnimatedIndex, setAnimatedIndexValue } from './animatedRegistry';
42
+
9
43
  // Hooks
10
44
  export { useBottomSheetManager } from './useBottomSheetManager';
11
45
  export {
package/src/refsMap.ts CHANGED
@@ -1,7 +1,4 @@
1
- import type { BottomSheetMethods } from '@gorhom/bottom-sheet/lib/typescript/types';
2
- import type { RefObject } from 'react';
3
-
4
- type SheetRef = RefObject<BottomSheetMethods | null>;
1
+ import type { SheetRef } from './adapter.types';
5
2
 
6
3
  const sheetRefsMap = new Map<string, SheetRef>();
7
4
 
@@ -0,0 +1,28 @@
1
+ import type { ForwardedRef } from 'react';
2
+
3
+ import type { SheetAdapterRef, SheetRef } from './adapter.types';
4
+ import { useBottomSheetRefContext } from './BottomSheetRef.context';
5
+
6
+ /**
7
+ * Returns the correct ref for a custom adapter.
8
+ *
9
+ * Handles the internal ref routing between portal/persistent mode
10
+ * (where the ref comes from context) and inline mode (where the ref
11
+ * is forwarded by `useBottomSheetManager`).
12
+ *
13
+ * Usage:
14
+ * ```tsx
15
+ * const MyAdapter = React.forwardRef<SheetAdapterRef, Props>(
16
+ * ({ children }, forwardedRef) => {
17
+ * const ref = useAdapterRef(forwardedRef);
18
+ * useImperativeHandle(ref, () => ({ expand: ..., close: ... }));
19
+ * }
20
+ * );
21
+ * ```
22
+ */
23
+ export function useAdapterRef(
24
+ forwardedRef: ForwardedRef<SheetAdapterRef>
25
+ ): SheetRef | ForwardedRef<SheetAdapterRef> {
26
+ const contextRef = useBottomSheetRefContext();
27
+ return contextRef ?? forwardedRef;
28
+ }
@@ -0,0 +1,31 @@
1
+ import type { SharedValue } from 'react-native-reanimated';
2
+
3
+ import { ensureAnimatedIndex } from './animatedRegistry';
4
+ import { useBottomSheetContext } from './useBottomSheetContext';
5
+
6
+ /**
7
+ * Returns the `animatedIndex` shared value for the current sheet.
8
+ *
9
+ * The value drives backdrop opacity and scale animations:
10
+ * - `-1` = hidden (backdrop transparent)
11
+ * - `0` = fully visible (backdrop opaque)
12
+ *
13
+ * **Binary strategy** — set to `0` on expand and `-1` on close:
14
+ * ```ts
15
+ * const animatedIndex = useAnimatedIndex();
16
+ * // in expand: animatedIndex.set(0);
17
+ * // in close: animatedIndex.set(-1);
18
+ * ```
19
+ *
20
+ * **Continuous strategy** — pass directly to a library that updates it during gestures:
21
+ * ```ts
22
+ * const animatedIndex = useAnimatedIndex();
23
+ * <SomeSheet animatedIndex={animatedIndex} />
24
+ * ```
25
+ *
26
+ * Must be called inside a sheet component (within `BottomSheetContext`).
27
+ */
28
+ export function useAnimatedIndex(): SharedValue<number> {
29
+ const { id } = useBottomSheetContext();
30
+ return ensureAnimatedIndex(id);
31
+ }
@@ -0,0 +1,32 @@
1
+ import { useEffect } from 'react';
2
+ import { BackHandler } from 'react-native';
3
+
4
+ import { useBottomSheetStore } from './bottomSheet.store';
5
+
6
+ /**
7
+ * Manages Android hardware back button for a sheet.
8
+ *
9
+ * The listener is only active when the sheet is fully open
10
+ * AND is the topmost sheet in the stack.
11
+ */
12
+ export function useBackHandler(id: string, onBackPress: () => void): void {
13
+ const isTopAndOpen = useBottomSheetStore((state) => {
14
+ const { stackOrder, sheetsById } = state;
15
+ const sheet = sheetsById[id];
16
+ return sheet?.status === 'open' && stackOrder[stackOrder.length - 1] === id;
17
+ });
18
+
19
+ useEffect(() => {
20
+ if (!isTopAndOpen) {
21
+ return;
22
+ }
23
+ const subscription = BackHandler.addEventListener(
24
+ 'hardwareBackPress',
25
+ () => {
26
+ onBackPress();
27
+ return true;
28
+ }
29
+ );
30
+ return () => subscription.remove();
31
+ }, [isTopAndOpen, onBackPress]);
32
+ }
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import type { BottomSheetMethods } from '@gorhom/bottom-sheet/lib/typescript/types';
2
+ import type { SheetAdapterRef } from './adapter.types';
3
3
 
4
4
  import {
5
5
  useOpen,
@@ -56,7 +56,7 @@ export function useBottomSheetControl<T extends BottomSheetPortalId>(
56
56
  // Only create ref if it doesn't exist (keepMounted sheets already have one)
57
57
  const existingRef = getSheetRef(id);
58
58
  if (!existingRef) {
59
- const ref = React.createRef<BottomSheetMethods>();
59
+ const ref = React.createRef<SheetAdapterRef>();
60
60
  setSheetRef(id, ref);
61
61
  }
62
62
 
@@ -7,8 +7,8 @@ import {
7
7
  type OpenMode,
8
8
  } from './bottomSheet.store';
9
9
  import { useMaybeBottomSheetManagerContext } from './BottomSheetManager.provider';
10
+ import type { SheetAdapterRef } from './adapter.types';
10
11
  import { setSheetRef } from './refsMap';
11
- import type { BottomSheetMethods } from '@gorhom/bottom-sheet/lib/typescript/types';
12
12
 
13
13
  export const useBottomSheetManager = () => {
14
14
  const bottomSheetManagerContext = useMaybeBottomSheetManagerContext();
@@ -30,7 +30,7 @@ export const useBottomSheetManager = () => {
30
30
  options.groupId || bottomSheetManagerContext?.groupId || 'default';
31
31
 
32
32
  const id = options.id || Math.random().toString(36);
33
- const ref = React.createRef<BottomSheetMethods>();
33
+ const ref = React.createRef<SheetAdapterRef>();
34
34
 
35
35
  setSheetRef(id, ref);
36
36