react-native-bottom-sheet-stack 1.5.2 → 1.6.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 (45) hide show
  1. package/lib/commonjs/BottomSheetBackdrop.js.map +1 -1
  2. package/lib/commonjs/BottomSheetHost.js +103 -140
  3. package/lib/commonjs/BottomSheetHost.js.map +1 -1
  4. package/lib/commonjs/BottomSheetManaged.js +8 -9
  5. package/lib/commonjs/BottomSheetManaged.js.map +1 -1
  6. package/lib/commonjs/BottomSheetPortal.js +2 -10
  7. package/lib/commonjs/BottomSheetPortal.js.map +1 -1
  8. package/lib/commonjs/BottomSheetScaleView.js +13 -28
  9. package/lib/commonjs/BottomSheetScaleView.js.map +1 -1
  10. package/lib/commonjs/useBottomSheetContext.js +18 -11
  11. package/lib/commonjs/useBottomSheetContext.js.map +1 -1
  12. package/lib/commonjs/useBottomSheetControl.js.map +1 -1
  13. package/lib/commonjs/useScaleAnimation.js +25 -12
  14. package/lib/commonjs/useScaleAnimation.js.map +1 -1
  15. package/lib/typescript/example/src/components/Badge.d.ts +1 -1
  16. package/lib/typescript/example/src/components/Badge.d.ts.map +1 -1
  17. package/lib/typescript/example/src/components/Button.d.ts.map +1 -1
  18. package/lib/typescript/example/src/components/DemoCard.d.ts.map +1 -1
  19. package/lib/typescript/example/src/components/Sheet.d.ts.map +1 -1
  20. package/lib/typescript/example/src/screens/HomeScreen.d.ts.map +1 -1
  21. package/lib/typescript/example/src/sheets/ContextSheets.d.ts.map +1 -1
  22. package/lib/typescript/example/src/sheets/DynamicContentSheet.d.ts.map +1 -1
  23. package/lib/typescript/example/src/sheets/NavigationSheets.d.ts.map +1 -1
  24. package/lib/typescript/example/src/sheets/NestedScaleSheets.d.ts.map +1 -1
  25. package/lib/typescript/example/src/styles/theme.d.ts +71 -35
  26. package/lib/typescript/example/src/styles/theme.d.ts.map +1 -1
  27. package/lib/typescript/src/BottomSheetBackdrop.d.ts.map +1 -1
  28. package/lib/typescript/src/BottomSheetHost.d.ts.map +1 -1
  29. package/lib/typescript/src/BottomSheetManaged.d.ts.map +1 -1
  30. package/lib/typescript/src/BottomSheetPortal.d.ts.map +1 -1
  31. package/lib/typescript/src/BottomSheetScaleView.d.ts.map +1 -1
  32. package/lib/typescript/src/useBottomSheetContext.d.ts +1 -2
  33. package/lib/typescript/src/useBottomSheetContext.d.ts.map +1 -1
  34. package/lib/typescript/src/useBottomSheetControl.d.ts.map +1 -1
  35. package/lib/typescript/src/useScaleAnimation.d.ts +2 -3
  36. package/lib/typescript/src/useScaleAnimation.d.ts.map +1 -1
  37. package/package.json +1 -1
  38. package/src/BottomSheetBackdrop.tsx +0 -3
  39. package/src/BottomSheetHost.tsx +17 -31
  40. package/src/BottomSheetManaged.tsx +3 -9
  41. package/src/BottomSheetPortal.tsx +4 -6
  42. package/src/BottomSheetScaleView.tsx +2 -7
  43. package/src/useBottomSheetContext.ts +13 -11
  44. package/src/useBottomSheetControl.ts +0 -1
  45. package/src/useScaleAnimation.ts +4 -10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-bottom-sheet-stack",
3
- "version": "1.5.2",
3
+ "version": "1.6.0",
4
4
  "description": "Bottom Sheet Stack Manager",
5
5
  "source": "./src/index.tsx",
6
6
  "main": "lib/commonjs/index.js",
@@ -28,12 +28,9 @@ export function BottomSheetBackdrop({
28
28
  );
29
29
 
30
30
  const animatedIndex = getAnimatedIndex(sheetId);
31
-
32
31
  const isVisible = status === 'opening' || status === 'open';
33
32
 
34
33
  const animatedStyle = useAnimatedStyle(() => {
35
- // Interpolate opacity based on animatedIndex
36
- // -1 = closed, 0+ = open at snap point
37
34
  const opacity = interpolate(
38
35
  animatedIndex.value,
39
36
  [-1, 0],
@@ -6,13 +6,13 @@ import { PortalHost } from 'react-native-teleport';
6
6
 
7
7
  import { shallow } from 'zustand/shallow';
8
8
  import { cleanupAnimatedIndex } from './animatedRegistry';
9
- import { cleanupSheetRef } from './refsMap';
10
9
  import { BottomSheetContext } from './BottomSheet.context';
11
10
  import { useBottomSheetStore } from './bottomSheet.store';
12
11
  import { BottomSheetBackdrop } from './BottomSheetBackdrop';
13
12
  import { initBottomSheetCoordinator } from './bottomSheetCoordinator';
14
13
  import { useBottomSheetManagerContext } from './BottomSheetManager.provider';
15
- import { useScaleAnimatedStyle, type ScaleConfig } from './useScaleAnimation';
14
+ import { cleanupSheetRef } from './refsMap';
15
+ import { useScaleAnimatedStyle } from './useScaleAnimation';
16
16
 
17
17
  function PortalHostWrapper({
18
18
  id,
@@ -23,18 +23,14 @@ function PortalHostWrapper({
23
23
  width: number;
24
24
  height: number;
25
25
  }) {
26
- return (
27
- <View style={{ flex: 1, width, height }} pointerEvents="box-none">
28
- <PortalHost name={`bottomsheet-${id}`} style={{ width, height }} />
29
- </View>
30
- );
26
+ return <PortalHost name={`bottomsheet-${id}`} style={{ width, height }} />;
31
27
  }
32
28
 
33
29
  function BottomSheetHostComp() {
34
30
  const queueIds = useQueueIds();
35
31
  const clearGroup = useBottomSheetStore((store) => store.clearGroup);
36
32
 
37
- const { groupId, scaleConfig } = useBottomSheetManagerContext();
33
+ const { groupId } = useBottomSheetManagerContext();
38
34
 
39
35
  useEffect(() => {
40
36
  const unsubscribe = initBottomSheetCoordinator(groupId);
@@ -52,36 +48,26 @@ function BottomSheetHostComp() {
52
48
  return (
53
49
  <>
54
50
  {queueIds.map((id, index) => (
55
- <QueueItem
56
- key={id}
57
- id={id}
58
- groupId={groupId}
59
- scaleConfig={scaleConfig}
60
- stackIndex={index}
61
- />
51
+ <QueueItem key={id} id={id} stackIndex={index} />
62
52
  ))}
63
53
  </>
64
54
  );
65
55
  }
66
56
 
67
- function QueueItem({
68
- id,
69
- groupId,
70
- scaleConfig,
71
- stackIndex,
72
- }: {
73
- id: string;
74
- groupId: string;
75
- scaleConfig?: ScaleConfig;
76
- stackIndex: number;
77
- }) {
78
- const sheet = useBottomSheetStore((state) => state.sheetsById[id]);
79
- const startClosing = useBottomSheetStore((state) => state.startClosing);
57
+ function QueueItem({ id, stackIndex }: { id: string; stackIndex: number }) {
58
+ const { content, usePortal, startClosing } = useBottomSheetStore(
59
+ (state) => ({
60
+ content: state.sheetsById[id]?.content,
61
+ usePortal: state.sheetsById[id]?.usePortal,
62
+ startClosing: state.startClosing,
63
+ }),
64
+ shallow
65
+ );
80
66
 
81
67
  const { width, height } = useSafeAreaFrame();
82
68
  const value = { id };
83
69
 
84
- const scaleStyle = useScaleAnimatedStyle({ groupId, id }, scaleConfig);
70
+ const scaleStyle = useScaleAnimatedStyle({ id });
85
71
 
86
72
  useEffect(() => {
87
73
  return () => {
@@ -108,10 +94,10 @@ function QueueItem({
108
94
  scaleStyle,
109
95
  ]}
110
96
  >
111
- {sheet?.usePortal ? (
97
+ {usePortal ? (
112
98
  <PortalHostWrapper id={id} width={width} height={height} />
113
99
  ) : (
114
- sheet?.content
100
+ content
115
101
  )}
116
102
  </Animated.View>
117
103
  </BottomSheetContext.Provider>
@@ -13,7 +13,6 @@ export interface BottomSheetRef extends BottomSheetMethods {}
13
13
 
14
14
  interface BottomSheetManagedProps extends BottomSheetProps {}
15
15
 
16
- // Null backdrop - we render our own backdrop separately in BottomSheetHost
17
16
  const nullBackdrop = () => null;
18
17
 
19
18
  export const BottomSheetManaged = React.forwardRef<
@@ -32,15 +31,10 @@ export const BottomSheetManaged = React.forwardRef<
32
31
  },
33
32
  ref
34
33
  ) => {
35
- const { bottomSheetState } = useBottomSheetContext();
34
+ const { id } = useBottomSheetContext();
36
35
 
37
- // Get or create shared animated index for this sheet
38
- const animatedIndex =
39
- externalAnimatedIndex ?? getAnimatedIndex(bottomSheetState.id);
40
-
41
- const { handleAnimate, handleClose } = createSheetEventHandlers(
42
- bottomSheetState.id
43
- );
36
+ const animatedIndex = externalAnimatedIndex ?? getAnimatedIndex(id);
37
+ const { handleAnimate, handleClose } = createSheetEventHandlers(id);
44
38
 
45
39
  const wrappedOnAnimate: BottomSheetProps['onAnimate'] = (
46
40
  fromIndex: number,
@@ -14,22 +14,20 @@ interface BottomSheetPortalProps {
14
14
  }
15
15
 
16
16
  export function BottomSheetPortal({ id, children }: BottomSheetPortalProps) {
17
- const sheetState = useBottomSheetStore((state) => state.sheetsById[id]);
17
+ const usePortal = useBottomSheetStore(
18
+ (state) => state.sheetsById[id]?.usePortal
19
+ );
18
20
 
19
- // Only render when the sheet is active and using portal
20
- if (!sheetState?.usePortal) {
21
+ if (!usePortal) {
21
22
  return null;
22
23
  }
23
24
 
24
- // Get the ref that was created in useBottomSheetControl.open()
25
25
  const ref = getSheetRef(id);
26
26
 
27
- // Clone the child element to add the ref
28
27
  const childWithRef = React.cloneElement(children, {
29
28
  ref,
30
29
  } as { ref: typeof ref });
31
30
 
32
- // Wrap with BottomSheetContext so useBottomSheetContext() works inside portal content
33
31
  return (
34
32
  <Portal hostName={`bottomsheet-${id}`}>
35
33
  <BottomSheetContext.Provider value={{ id }}>
@@ -1,7 +1,6 @@
1
- import { useContext, type PropsWithChildren } from 'react';
1
+ import { type PropsWithChildren } from 'react';
2
2
  import { StyleSheet } from 'react-native';
3
3
  import Animated from 'react-native-reanimated';
4
- import { BottomSheetManagerContext } from './BottomSheetManager.context';
5
4
  import { useScaleAnimatedStyle } from './useScaleAnimation';
6
5
 
7
6
  /**
@@ -20,11 +19,7 @@ import { useScaleAnimatedStyle } from './useScaleAnimation';
20
19
  * ```
21
20
  */
22
21
  export function BottomSheetScaleView({ children }: PropsWithChildren) {
23
- const context = useContext(BottomSheetManagerContext);
24
- const groupId = context?.groupId ?? 'default';
25
- const scaleConfig = context?.scaleConfig;
26
-
27
- const animatedStyle = useScaleAnimatedStyle({ groupId }, scaleConfig);
22
+ const animatedStyle = useScaleAnimatedStyle();
28
23
 
29
24
  return (
30
25
  <Animated.View style={[styles.container, animatedStyle]}>
@@ -1,15 +1,13 @@
1
+ import { shallow } from 'zustand/shallow';
1
2
  import { useMaybeBottomSheetContext } from './BottomSheet.context';
2
- import {
3
- useBottomSheetStore,
4
- type BottomSheetState,
5
- } from './bottomSheet.store';
3
+ import { useBottomSheetStore } from './bottomSheet.store';
6
4
  import type {
7
5
  BottomSheetPortalId,
8
6
  BottomSheetPortalParams,
9
7
  } from './portal.types';
10
8
 
11
9
  export interface UseBottomSheetContextReturn<TParams> {
12
- bottomSheetState: BottomSheetState;
10
+ id: string;
13
11
  params: TParams;
14
12
  close: () => void;
15
13
  /** @deprecated Use `close` instead */
@@ -27,23 +25,27 @@ export function useBottomSheetContext<
27
25
  >(): UseBottomSheetContextReturn<BottomSheetPortalParams<T> | unknown> {
28
26
  const context = useMaybeBottomSheetContext();
29
27
 
30
- const bottomSheetState = useBottomSheetStore(
31
- (state) => state.sheetsById[context?.id!]
28
+ const { id, params } = useBottomSheetStore(
29
+ (state) => ({
30
+ id: state.sheetsById[context?.id!]?.id,
31
+ params: state.sheetsById[context?.id!]?.params,
32
+ }),
33
+ shallow
32
34
  );
33
35
 
34
36
  const startClosing = useBottomSheetStore((state) => state.startClosing);
35
37
 
36
- if (!bottomSheetState) {
38
+ if (!id) {
37
39
  throw new Error(
38
40
  'useBottomSheetContext must be used within a BottomSheet component'
39
41
  );
40
42
  }
41
43
 
42
- const close = () => startClosing(bottomSheetState.id);
44
+ const close = () => startClosing(id);
43
45
 
44
46
  return {
45
- bottomSheetState,
46
- params: bottomSheetState.params as BottomSheetPortalParams<T>,
47
+ id,
48
+ params: params as BottomSheetPortalParams<T>,
47
49
  close,
48
50
  closeBottomSheet: close,
49
51
  };
@@ -48,7 +48,6 @@ export function useBottomSheetControl<T extends BottomSheetPortalId>(
48
48
  const open = (options?: OpenOptions<T>) => {
49
49
  const groupId = bottomSheetManagerContext?.groupId || 'default';
50
50
 
51
- // Create ref when opening (same pattern as useBottomSheetManager)
52
51
  const ref = React.createRef<BottomSheetMethods>();
53
52
  setSheetRef(id, ref);
54
53
 
@@ -8,6 +8,7 @@ import {
8
8
  useBottomSheetStore,
9
9
  type BottomSheetStore,
10
10
  } from './bottomSheet.store';
11
+ import { useBottomSheetManagerContext } from './BottomSheetManager.provider';
11
12
 
12
13
  export interface ScaleConfig {
13
14
  /** Scale factor when sheet is open (default: 0.92) */
@@ -39,12 +40,9 @@ export function useScaleDepth(groupId: string, sheetId?: string): number {
39
40
  const scaleDepthSelector = (state: BottomSheetStore) => {
40
41
  const { stackOrder, sheetsById } = state;
41
42
 
42
- // For background: check if ANY scaleBackground sheet is active (binary 0/1)
43
- // For a sheet: count scaleBackground sheets above it in the stack
44
43
  const startIndex = sheetId ? stackOrder.indexOf(sheetId) + 1 : 0;
45
44
 
46
45
  if (sheetId && startIndex === 0) {
47
- // Sheet not found in stack, return previous value to avoid flicker
48
46
  return prevDepthRef.current;
49
47
  }
50
48
 
@@ -59,8 +57,6 @@ export function useScaleDepth(groupId: string, sheetId?: string): number {
59
57
  sheet.status !== 'closing'
60
58
  ) {
61
59
  depth++;
62
- // For background wrapper (no sheetId), we only need to know if there's at least one
63
- // Don't accumulate - background scales once, sheets below scale cumulatively
64
60
  if (!sheetId) {
65
61
  break;
66
62
  }
@@ -78,10 +74,8 @@ export function useScaleDepth(groupId: string, sheetId?: string): number {
78
74
  * Returns animated style for scale effect based on depth.
79
75
  * Uses power scaling: scale^depth for cascading effect.
80
76
  */
81
- export function useScaleAnimatedStyle(
82
- { groupId, id }: { groupId: string; id?: string },
83
- config?: ScaleConfig
84
- ) {
77
+ export function useScaleAnimatedStyle({ id }: { id?: string } = {}) {
78
+ const { groupId, scaleConfig } = useBottomSheetManagerContext();
85
79
  const scaleDepth = useScaleDepth(groupId, id);
86
80
 
87
81
  const {
@@ -89,7 +83,7 @@ export function useScaleAnimatedStyle(
89
83
  translateY = DEFAULT_CONFIG.translateY,
90
84
  borderRadius = DEFAULT_CONFIG.borderRadius,
91
85
  duration = DEFAULT_CONFIG.duration,
92
- } = config ?? {};
86
+ } = scaleConfig ?? {};
93
87
 
94
88
  const progress = useDerivedValue(() => {
95
89
  return withTiming(scaleDepth, { duration });