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.
- package/README.md +263 -49
- package/lib/commonjs/BottomSheetHost.js +146 -56
- package/lib/commonjs/BottomSheetHost.js.map +1 -1
- package/lib/commonjs/BottomSheetManager.provider.js +7 -4
- package/lib/commonjs/BottomSheetManager.provider.js.map +1 -1
- package/lib/commonjs/BottomSheetPortal.js +46 -0
- package/lib/commonjs/BottomSheetPortal.js.map +1 -0
- package/lib/commonjs/bottomSheet.store.js +19 -0
- package/lib/commonjs/bottomSheet.store.js.map +1 -1
- package/lib/commonjs/index.js +14 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/portal.types.js +2 -0
- package/lib/commonjs/portal.types.js.map +1 -0
- package/lib/commonjs/useBottomSheetControl.js +81 -0
- package/lib/commonjs/useBottomSheetControl.js.map +1 -0
- package/lib/typescript/example/src/App.d.ts.map +1 -1
- package/lib/typescript/src/BottomSheetHost.d.ts.map +1 -1
- package/lib/typescript/src/BottomSheetManager.provider.d.ts.map +1 -1
- package/lib/typescript/src/BottomSheetPortal.d.ts +9 -0
- package/lib/typescript/src/BottomSheetPortal.d.ts.map +1 -0
- package/lib/typescript/src/bottomSheet.store.d.ts +5 -0
- package/lib/typescript/src/bottomSheet.store.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +3 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/portal.types.d.ts +24 -0
- package/lib/typescript/src/portal.types.d.ts.map +1 -0
- package/lib/typescript/src/useBottomSheetControl.d.ts +10 -0
- package/lib/typescript/src/useBottomSheetControl.d.ts.map +1 -0
- package/lib/typescript/src/useBottomSheetManager.d.ts +2 -0
- package/lib/typescript/src/useBottomSheetManager.d.ts.map +1 -1
- package/package.json +3 -1
- package/src/BottomSheetHost.tsx +32 -11
- package/src/BottomSheetManager.provider.tsx +6 -3
- package/src/BottomSheetPortal.tsx +39 -0
- package/src/bottomSheet.store.ts +27 -0
- package/src/index.tsx +6 -0
- package/src/portal.types.ts +25 -0
- 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
|
-
<
|
|
23
|
-
{
|
|
24
|
-
|
|
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
|
+
}
|
package/src/bottomSheet.store.ts
CHANGED
|
@@ -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
|
+
}
|