diff --git a/example/src/App.tsx b/example/src/App.tsx
index 925aae4..f0b5996 100644
--- a/example/src/App.tsx
+++ b/example/src/App.tsx
@@ -9,7 +9,7 @@ import { SafeAreaProvider } from 'react-native-safe-area-context';
import { UserProvider } from './context/UserContext';
import { HomeScreen } from './screens';
-import { ScannerSheet } from './sheets';
+import { PersistentWithPortalSheet, ScannerSheet } from './sheets';
import { sharedStyles } from './styles/theme';
export default function App() {
@@ -30,6 +30,10 @@ export default function App() {
+ {/* Persistent sheet with nested portal sheet inside */}
+
+
+
diff --git a/example/src/bottom-sheet.d.ts b/example/src/bottom-sheet.d.ts
index ef2dc84..2bcd64e 100644
--- a/example/src/bottom-sheet.d.ts
+++ b/example/src/bottom-sheet.d.ts
@@ -11,5 +11,9 @@ declare module 'react-native-bottom-sheet-stack' {
source: 'home' | 'navigation';
title?: string;
};
+ 'persistent-with-portal': true;
+ 'nested-portal-in-persistent': {
+ message: string;
+ };
}
}
diff --git a/example/src/screens/HomeScreen.tsx b/example/src/screens/HomeScreen.tsx
index 5f84839..6826e94 100644
--- a/example/src/screens/HomeScreen.tsx
+++ b/example/src/screens/HomeScreen.tsx
@@ -24,6 +24,9 @@ export function HomeScreen() {
const portalSheetControl = useBottomSheetControl('context-portal-sheet');
const portalModeSheetA = useBottomSheetControl('portal-mode-sheet-a');
const scannerControl = useBottomSheetControl('scanner-sheet');
+ const persistentWithPortalControl = useBottomSheetControl(
+ 'persistent-with-portal'
+ );
return (
@@ -125,6 +128,15 @@ export function HomeScreen() {
})
}
/>
+
+
+ persistentWithPortalControl.open({ scaleBackground: true })
+ }
+ />
{/* Features */}
diff --git a/example/src/sheets/PersistentWithNestedPortal.tsx b/example/src/sheets/PersistentWithNestedPortal.tsx
new file mode 100644
index 0000000..0db4f47
--- /dev/null
+++ b/example/src/sheets/PersistentWithNestedPortal.tsx
@@ -0,0 +1,212 @@
+import type { BottomSheetMethods } from '@gorhom/bottom-sheet/lib/typescript/types';
+import { forwardRef, useState } from 'react';
+import { StyleSheet, Text, View } from 'react-native';
+import {
+ BottomSheetPortal,
+ useBottomSheetContext,
+ useBottomSheetControl,
+} from 'react-native-bottom-sheet-stack';
+
+import { Badge, Button, SecondaryButton, Sheet } from '../components';
+import { colors, sharedStyles } from '../styles/theme';
+
+/**
+ * Nested portal sheet content - defined inside the persistent sheet
+ * to demonstrate portal sheets can be declared within other sheets
+ */
+const NestedPortalSheetContent = forwardRef((_, ref) => {
+ const { close, params } =
+ useBottomSheetContext<'nested-portal-in-persistent'>();
+ const [counter, setCounter] = useState(0);
+
+ return (
+
+
+
+
+
+ Nested Portal Sheet
+
+ This portal-based sheet is defined inside the persistent sheet. It has
+ access to the same React context as its parent.
+
+
+ {params?.message && (
+
+ Message from parent:
+ {params.message}
+
+ )}
+
+
+ Local counter:
+ {counter}
+
+
+
+
+
+
+
+ Note: This sheet's state resets on close because it's a portal sheet
+ (not persistent). The parent persistent sheet keeps its state.
+
+
+
+ );
+});
+
+NestedPortalSheetContent.displayName = 'NestedPortalSheetContent';
+
+/**
+ * Persistent sheet that contains a portal-based sheet definition inside
+ */
+export const PersistentWithPortalSheet = forwardRef(
+ (_, ref) => {
+ const { close } = useBottomSheetContext<'persistent-with-portal'>();
+ const nestedPortalControl = useBottomSheetControl(
+ 'nested-portal-in-persistent'
+ );
+ const [openCount, setOpenCount] = useState(0);
+
+ const handleOpenNestedPortal = () => {
+ setOpenCount((c) => c + 1);
+ nestedPortalControl.open({
+ scaleBackground: true,
+ mode: 'push',
+ params: {
+ message: `Opened ${openCount + 1} time(s) from persistent sheet`,
+ },
+ });
+ };
+
+ return (
+ <>
+ {/* Portal sheet defined inside the persistent sheet */}
+
+
+
+
+
+
+
+
+
+ Persistent + Portal Demo
+
+ This persistent sheet contains a portal-based sheet definition
+ inside. The persistent sheet keeps its state across open/close
+ cycles, while the nested portal sheet resets.
+
+
+
+ Nested portal opened:
+ {openCount} time(s)
+
+
+
+
+
+
+
+
+
+ Close this sheet and reopen it - the "opened count" persists
+ because this is a persistent sheet. The nested portal sheet's
+ counter will reset each time it opens.
+
+
+
+ >
+ );
+ }
+);
+
+PersistentWithPortalSheet.displayName = 'PersistentWithPortalSheet';
+
+const styles = StyleSheet.create({
+ badgeRow: {
+ flexDirection: 'row',
+ gap: 8,
+ },
+ actions: {
+ gap: 12,
+ marginTop: 16,
+ },
+ paramBox: {
+ backgroundColor: colors.primaryDark,
+ borderRadius: 12,
+ padding: 14,
+ marginTop: 16,
+ },
+ paramLabel: {
+ color: colors.textSecondary,
+ fontSize: 12,
+ marginBottom: 4,
+ },
+ paramValue: {
+ color: colors.primary,
+ fontSize: 16,
+ fontWeight: '600',
+ },
+ counterBox: {
+ backgroundColor: colors.background,
+ borderRadius: 12,
+ padding: 14,
+ marginTop: 12,
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ },
+ counterLabel: {
+ color: colors.textSecondary,
+ fontSize: 14,
+ },
+ counterValue: {
+ color: colors.warning,
+ fontSize: 24,
+ fontWeight: '700',
+ },
+ stateBox: {
+ backgroundColor: colors.background,
+ borderRadius: 12,
+ padding: 14,
+ marginTop: 16,
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ alignItems: 'center',
+ borderWidth: 1,
+ borderColor: colors.border,
+ },
+ stateLabel: {
+ color: colors.textSecondary,
+ fontSize: 14,
+ },
+ stateValue: {
+ color: colors.cyan,
+ fontSize: 20,
+ fontWeight: '700',
+ },
+ infoBox: {
+ backgroundColor: colors.background,
+ borderRadius: 12,
+ padding: 14,
+ marginTop: 16,
+ borderWidth: 1,
+ borderColor: colors.border,
+ },
+ infoText: {
+ color: colors.textSecondary,
+ fontSize: 13,
+ lineHeight: 18,
+ textAlign: 'center',
+ },
+});
diff --git a/example/src/sheets/index.ts b/example/src/sheets/index.ts
index 1ef9cd0..af88f3c 100644
--- a/example/src/sheets/index.ts
+++ b/example/src/sheets/index.ts
@@ -7,5 +7,6 @@ export {
export { HeavySheet } from './DynamicContentSheet';
export { SheetA, SheetB, SheetC, SheetD } from './NavigationSheets';
export { NestedSheet1, NestedSheet2, NestedSheet3 } from './NestedScaleSheets';
+export { PersistentWithPortalSheet } from './PersistentWithNestedPortal';
export { PortalModeSheetA, PortalModeSheetB } from './PortalModeSheets';
export { ScannerSheet } from './ScannerSheet';
diff --git a/src/BottomSheetPersistent.tsx b/src/BottomSheetPersistent.tsx
index 39d257b..36b93b5 100644
--- a/src/BottomSheetPersistent.tsx
+++ b/src/BottomSheetPersistent.tsx
@@ -1,14 +1,20 @@
import type { BottomSheetMethods } from '@gorhom/bottom-sheet/lib/typescript/types';
import React, { useEffect, useRef } from 'react';
-import { useMount, useSheetExists, useUnmount } from './bottomSheet.store';
+import {
+ useMount,
+ useSheetExists,
+ useSheetPortalSession,
+ useUnmount,
+} from './bottomSheet.store';
import { BottomSheetDefaultIndexContext } from './BottomSheetDefaultIndex.context';
import { useMaybeBottomSheetManagerContext } from './BottomSheetManager.provider';
-import { BottomSheetPortal } from './BottomSheetPortal';
import { BottomSheetRefContext } from './BottomSheetRef.context';
import type { BottomSheetPortalId } from './portal.types';
import { setSheetRef } from './refsMap';
import { useEvent } from './useEvent';
+import { Portal } from 'react-native-teleport';
+import { BottomSheetContext } from './BottomSheet.context';
interface BottomSheetPersistentProps {
id: BottomSheetPortalId;
@@ -23,7 +29,7 @@ export function BottomSheetPersistent({
const mount = useMount();
const unmount = useUnmount();
const sheetExists = useSheetExists(id);
-
+ const portalSession = useSheetPortalSession(id);
const sheetRef = useRef(null);
const groupId = bottomSheetManagerContext?.groupId || 'default';
@@ -49,12 +55,14 @@ export function BottomSheetPersistent({
}
return (
-
-
-
- {children}
-
-
-
+
+
+
+
+ {children}
+
+
+
+
);
}
diff --git a/src/BottomSheetPortal.tsx b/src/BottomSheetPortal.tsx
index f768397..abc7998 100644
--- a/src/BottomSheetPortal.tsx
+++ b/src/BottomSheetPortal.tsx
@@ -4,7 +4,9 @@ import React from 'react';
import { Portal } from 'react-native-teleport';
import { BottomSheetContext } from './BottomSheet.context';
-import { useSheetUsePortal, useSheetPortalSession } from './bottomSheet.store';
+import { BottomSheetDefaultIndexContext } from './BottomSheetDefaultIndex.context';
+import { BottomSheetRefContext } from './BottomSheetRef.context';
+import { useSheetPortalSession } from './bottomSheet.store';
import type { BottomSheetPortalId } from './portal.types';
import { getSheetRef } from './refsMap';
@@ -14,22 +16,21 @@ interface BottomSheetPortalProps {
}
export function BottomSheetPortal({ id, children }: BottomSheetPortalProps) {
- const usePortal = useSheetUsePortal(id);
const portalSession = useSheetPortalSession(id);
+ const ref = getSheetRef(id);
- if (!usePortal || portalSession === undefined) {
+ if (!portalSession || !ref) {
return null;
}
- const ref = getSheetRef(id);
- const childWithRef = React.cloneElement(children, {
- ref,
- } as { ref: typeof ref });
-
return (
- {childWithRef}
+
+
+ {children}
+
+
);