react-native-bottom-sheet-stack 1.0.3 → 1.3.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 (38) hide show
  1. package/README.md +263 -49
  2. package/lib/commonjs/BottomSheetHost.js +146 -56
  3. package/lib/commonjs/BottomSheetHost.js.map +1 -1
  4. package/lib/commonjs/BottomSheetManager.provider.js +7 -4
  5. package/lib/commonjs/BottomSheetManager.provider.js.map +1 -1
  6. package/lib/commonjs/BottomSheetPortal.js +46 -0
  7. package/lib/commonjs/BottomSheetPortal.js.map +1 -0
  8. package/lib/commonjs/bottomSheet.store.js +19 -0
  9. package/lib/commonjs/bottomSheet.store.js.map +1 -1
  10. package/lib/commonjs/index.js +14 -0
  11. package/lib/commonjs/index.js.map +1 -1
  12. package/lib/commonjs/portal.types.js +2 -0
  13. package/lib/commonjs/portal.types.js.map +1 -0
  14. package/lib/commonjs/useBottomSheetControl.js +81 -0
  15. package/lib/commonjs/useBottomSheetControl.js.map +1 -0
  16. package/lib/typescript/example/src/App.d.ts.map +1 -1
  17. package/lib/typescript/src/BottomSheetHost.d.ts.map +1 -1
  18. package/lib/typescript/src/BottomSheetManager.provider.d.ts.map +1 -1
  19. package/lib/typescript/src/BottomSheetPortal.d.ts +9 -0
  20. package/lib/typescript/src/BottomSheetPortal.d.ts.map +1 -0
  21. package/lib/typescript/src/bottomSheet.store.d.ts +5 -0
  22. package/lib/typescript/src/bottomSheet.store.d.ts.map +1 -1
  23. package/lib/typescript/src/index.d.ts +3 -0
  24. package/lib/typescript/src/index.d.ts.map +1 -1
  25. package/lib/typescript/src/portal.types.d.ts +24 -0
  26. package/lib/typescript/src/portal.types.d.ts.map +1 -0
  27. package/lib/typescript/src/useBottomSheetControl.d.ts +10 -0
  28. package/lib/typescript/src/useBottomSheetControl.d.ts.map +1 -0
  29. package/lib/typescript/src/useBottomSheetManager.d.ts +2 -0
  30. package/lib/typescript/src/useBottomSheetManager.d.ts.map +1 -1
  31. package/package.json +3 -1
  32. package/src/BottomSheetHost.tsx +32 -11
  33. package/src/BottomSheetManager.provider.tsx +6 -3
  34. package/src/BottomSheetPortal.tsx +39 -0
  35. package/src/bottomSheet.store.ts +27 -0
  36. package/src/index.tsx +6 -0
  37. package/src/portal.types.ts +25 -0
  38. package/src/useBottomSheetControl.ts +52 -0
@@ -1,4 +1,5 @@
1
1
  import React, { type PropsWithChildren } from 'react';
2
+ import { PortalProvider } from 'react-native-teleport';
2
3
 
3
4
  import {
4
5
  BottomSheetManagerContext,
@@ -19,9 +20,11 @@ export function BottomSheetManagerProvider({
19
20
  const value = { groupId: id, scaleConfig };
20
21
 
21
22
  return (
22
- <BottomSheetManagerContext.Provider key={id} value={value}>
23
- {children}
24
- </BottomSheetManagerContext.Provider>
23
+ <PortalProvider>
24
+ <BottomSheetManagerContext.Provider key={id} value={value}>
25
+ {children}
26
+ </BottomSheetManagerContext.Provider>
27
+ </PortalProvider>
25
28
  );
26
29
  }
27
30
 
@@ -0,0 +1,39 @@
1
+ 'use no memo';
2
+
3
+ import React from 'react';
4
+ import { Portal } from 'react-native-teleport';
5
+
6
+ import { BottomSheetContext } from './BottomSheet.context';
7
+ import { useBottomSheetStore } from './bottomSheet.store';
8
+ import type { BottomSheetPortalId } from './portal.types';
9
+ import { sheetRefs } from './refsMap';
10
+
11
+ interface BottomSheetPortalProps {
12
+ id: BottomSheetPortalId;
13
+ children: React.ReactElement;
14
+ }
15
+
16
+ export function BottomSheetPortal({ id, children }: BottomSheetPortalProps) {
17
+ const sheetState = useBottomSheetStore((state) => state.sheetsById[id]);
18
+
19
+ // Only render when the sheet is active and using portal
20
+ if (!sheetState?.usePortal) {
21
+ return null;
22
+ }
23
+
24
+ // Get the ref that was created in useBottomSheetControl.open()
25
+ const ref = sheetRefs[id];
26
+
27
+ // Clone the child element to add the ref
28
+ // @ts-ignore - same pattern as useBottomSheetManager
29
+ const childWithRef = React.cloneElement(children, { ref });
30
+
31
+ // Wrap with BottomSheetContext so useBottomSheetState() works inside portal content
32
+ return (
33
+ <Portal hostName={`bottomsheet-${id}`}>
34
+ <BottomSheetContext.Provider value={{ id }}>
35
+ {childWithRef}
36
+ </BottomSheetContext.Provider>
37
+ </Portal>
38
+ );
39
+ }
@@ -11,6 +11,7 @@ export interface BottomSheetState {
11
11
  content: ReactNode;
12
12
  status: BottomSheetStatus;
13
13
  scaleBackground?: boolean;
14
+ usePortal?: boolean;
14
15
  }
15
16
 
16
17
  type TriggerState = Omit<BottomSheetState, 'status'>;
@@ -20,10 +21,15 @@ interface BottomSheetStoreState {
20
21
  stackOrder: string[];
21
22
  }
22
23
 
24
+ export interface PortalOpenOptions {
25
+ scaleBackground?: boolean;
26
+ }
27
+
23
28
  interface BottomSheetStoreActions {
24
29
  push(sheet: TriggerState): void;
25
30
  switch(sheet: TriggerState): void;
26
31
  replace(sheet: TriggerState): void;
32
+ openPortal(id: string, groupId: string, options?: PortalOpenOptions): void;
27
33
  markOpen(id: string): void;
28
34
  startClosing(id: string): void;
29
35
  finishClosing(id: string): void;
@@ -99,6 +105,27 @@ export const useBottomSheetStore = create(
99
105
  };
100
106
  }),
101
107
 
108
+ openPortal: (id, groupId, options) =>
109
+ set((state) => {
110
+ if (state.sheetsById[id]) {
111
+ return state;
112
+ }
113
+ return {
114
+ sheetsById: {
115
+ ...state.sheetsById,
116
+ [id]: {
117
+ id,
118
+ groupId,
119
+ content: null,
120
+ status: 'opening',
121
+ usePortal: true,
122
+ scaleBackground: options?.scaleBackground,
123
+ },
124
+ },
125
+ stackOrder: [...state.stackOrder, id],
126
+ };
127
+ }),
128
+
102
129
  markOpen: (id) =>
103
130
  set((state) => {
104
131
  const sheet = state.sheetsById[id];
package/src/index.tsx CHANGED
@@ -5,3 +5,9 @@ export { useBottomSheetState } from './useBottomSheetState';
5
5
  export { BottomSheetManaged } from './BottomSheetManaged';
6
6
  export { BottomSheetScaleView } from './BottomSheetScaleView';
7
7
  export { type ScaleConfig } from './useScaleAnimation';
8
+ export { BottomSheetPortal } from './BottomSheetPortal';
9
+ export { useBottomSheetControl } from './useBottomSheetControl';
10
+ export type {
11
+ BottomSheetPortalRegistry,
12
+ BottomSheetPortalId,
13
+ } from './portal.types';
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Registry for portal-based bottom sheets.
3
+ * Augment this interface in your app to get type-safe sheet IDs:
4
+ *
5
+ * @example
6
+ * ```tsx
7
+ * declare module 'react-native-bottom-sheet-stack' {
8
+ * interface BottomSheetPortalRegistry {
9
+ * 'my-sheet': true;
10
+ * 'settings-sheet': true;
11
+ * 'profile-sheet': true;
12
+ * }
13
+ * }
14
+ * ```
15
+ */
16
+ export interface BottomSheetPortalRegistry {}
17
+
18
+ /**
19
+ * Type-safe portal sheet ID.
20
+ * If BottomSheetPortalRegistry is augmented, this will be a union of the registered keys.
21
+ * Otherwise, it falls back to `string` for flexibility.
22
+ */
23
+ export type BottomSheetPortalId = keyof BottomSheetPortalRegistry extends never
24
+ ? string
25
+ : Extract<keyof BottomSheetPortalRegistry, string>;
@@ -0,0 +1,52 @@
1
+ import React from 'react';
2
+ import type { BottomSheetMethods } from '@gorhom/bottom-sheet/lib/typescript/types';
3
+
4
+ import {
5
+ useBottomSheetStore,
6
+ type BottomSheetStatus,
7
+ type PortalOpenOptions,
8
+ } from './bottomSheet.store';
9
+ import { useMaybeBottomSheetManagerContext } from './BottomSheetManager.provider';
10
+ import type { BottomSheetPortalId } from './portal.types';
11
+ import { sheetRefs } from './refsMap';
12
+
13
+ export interface UseBottomSheetControlReturn {
14
+ open: (options?: PortalOpenOptions) => void;
15
+ close: () => void;
16
+ isOpen: boolean;
17
+ status: BottomSheetStatus | null;
18
+ }
19
+
20
+ export function useBottomSheetControl(
21
+ id: BottomSheetPortalId
22
+ ): UseBottomSheetControlReturn {
23
+ const bottomSheetManagerContext = useMaybeBottomSheetManagerContext();
24
+
25
+ const openPortal = useBottomSheetStore((state) => state.openPortal);
26
+ const startClosing = useBottomSheetStore((state) => state.startClosing);
27
+ const sheetState = useBottomSheetStore((state) => state.sheetsById[id]);
28
+
29
+ const open = (options?: PortalOpenOptions) => {
30
+ const groupId = bottomSheetManagerContext?.groupId || 'default';
31
+
32
+ // Create ref when opening (same pattern as useBottomSheetManager)
33
+ const ref = React.createRef<BottomSheetMethods>();
34
+ sheetRefs[id] = ref;
35
+
36
+ openPortal(id, groupId, options);
37
+ };
38
+
39
+ const close = () => {
40
+ startClosing(id);
41
+ };
42
+
43
+ const status = sheetState?.status ?? null;
44
+ const isOpen = status === 'open' || status === 'opening';
45
+
46
+ return {
47
+ open,
48
+ close,
49
+ isOpen,
50
+ status,
51
+ };
52
+ }