Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions packages/app/ui/components/BottomSheetWrapper.native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,17 @@ export const BottomSheetWrapper = forwardRef<
[dismissOnSnapToBottom, onOpenChange]
);

// Gorhom skips onChange(-1) when the sheet is dismissed before its open
// animation finishes (e.g. a backdrop tap mid-animation), so
// handleSheetChanges alone can leave `open` stuck at true. onDismiss fires
// on every modal dismissal path; if the parent still thinks the sheet is
// open at that point, sync it so the next open isn't a no-op.
const handleModalDismiss = useCallback(() => {
if (open) {
onOpenChange(false);
}
}, [open, onOpenChange]);

const renderBackdrop = useCallback(
(props: any) =>
showOverlay ? (
Expand Down Expand Up @@ -467,6 +478,7 @@ export const BottomSheetWrapper = forwardRef<
ref={bottomSheetModalRef}
accessibilityViewIsModal={true}
stackBehavior={stackBehavior}
onDismiss={handleModalDismiss}
{...commonProps}
{...commonOverrides}
>
Expand Down
27 changes: 27 additions & 0 deletions patches/@gorhom__bottom-sheet@5.2.14.patch
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,30 @@ index 4a69a6892ff553836b72216b598451c56f6284cc..7cdacc259c532844f5ec378e111f2f16
return {
paddingBottom: animate({
point: paddingBottom,
diff --git a/src/components/bottomSheetModal/BottomSheetModal.tsx b/src/components/bottomSheetModal/BottomSheetModal.tsx
index 2954b3f4282e28c1973ab88f479eb2d7889913c5..ec2ea40cdb40688fffb297bad212097529bea7e5 100644
--- a/src/components/bottomSheetModal/BottomSheetModal.tsx
+++ b/src/components/bottomSheetModal/BottomSheetModal.tsx
@@ -275,11 +275,19 @@ function BottomSheetModalComponent<T = never>(
/**
* if the modal position is already in a closed position,
* then we unmount the node and early exit.
+ *
+ * INITIAL is included so that dismissing a modal that was never
+ * presented (or that already fully dismissed itself, e.g. via a
+ * backdrop press) stays idempotent. Without it, the status gets
+ * stuck at DISMISSING and every later present() silently no-ops.
+ * https://github.com/gorhom/react-native-bottom-sheet/issues/2669
*/
if (
- [MODAL_STATUS.CLOSED, MODAL_STATUS.MINIMIZED].includes(
- statusRef.current
- ) ||
+ [
+ MODAL_STATUS.INITIAL,
+ MODAL_STATUS.CLOSED,
+ MODAL_STATUS.MINIMIZED,
+ ].includes(statusRef.current) ||
(statusRef.current === MODAL_STATUS.DISMISSING &&
currentIndexRef.current === -1)
) {
41 changes: 37 additions & 4 deletions patches/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ When adding a patch, document:

## @gorhom/bottom-sheet@5.2.14

Local patch:
`patches/@gorhom__bottom-sheet@5.2.14.patch`

This patch carries two independent fixes.

### 1. First-open layout of flex:1 sheet content

Why:
On the first open of a bottom sheet whose content is a `flex:1` ScrollView/View
with content larger than the eventual viewport (a long scrollable list with a
Expand All @@ -33,9 +40,6 @@ fix (enabling Yoga's `WebFlexBasis` flag) requires building React Native
from source, which we currently don't do; the writeup is in the closed
draft PR linked below.

Local patch:
`patches/@gorhom__bottom-sheet@5.2.14.patch`

Background and reproduction details: PR #5790 (closed, kept for reference).

Validation:
Expand All @@ -44,11 +48,40 @@ than the viewport plus a footer (e.g. CreateChatSheet). The footer should be
visible at the bottom of the sheet on first open.

Removal:
Drop this patch once we either move to building React Native from source
Drop this hunk once we either move to building React Native from source
(so we can flip the Yoga `WebFlexBasis` flag and fix the bug at the
layout-engine level), or once `@gorhom/bottom-sheet` ships an equivalent
workaround upstream.

### 2. Modal dismiss() bricks the modal when already dismissed

Why:
`BottomSheetModal.dismiss()` called while the modal's status is `INITIAL`
(never presented, or already fully dismissed and reset) falls through the
already-closed early-exit, permanently sets the internal status to
`DISMISSING`, and every later `present()` silently no-ops. Our
`BottomSheetWrapper` calls `dismiss()` whenever `open` flips false — which
is always the case right after a user-initiated close (backdrop tap / swipe
down) has already dismissed the modal internally — so modal sheets (e.g. the
personal invite sheet) could only be opened once per mount.

What it does:
Adds `MODAL_STATUS.INITIAL` to the already-closed early-exit in
`handleDismiss` (`src/components/bottomSheetModal/BottomSheetModal.tsx`),
making `dismiss()` idempotent.

Upstream:
- issue: `gorhom/react-native-bottom-sheet#2669`
- fix submitted: `gorhom/react-native-bottom-sheet#2711`

Validation:
- Home header → AddPerson opens the invite sheet; close it via the backdrop;
tap AddPerson again — the sheet must open again (repeat a few times).

Removal:
Drop this hunk once `gorhom/react-native-bottom-sheet#2711` (or an
equivalent fix) ships in a release we use.

## react-native@0.85.3

Local patch:
Expand Down
6 changes: 3 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading