Skip to content

fix: clear the scrim pin when a sheet view is torn down - #112

Merged
Skalakid merged 4 commits into
mainfrom
claude/agent-finding-investigation-d0e5fb
Nov 6, 2026
Merged

Skalakid merged 4 commits into
mainfrom
claude/agent-finding-investigation-d0e5fb

Conversation

@Skalakid

@Skalakid Skalakid commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

scrimPinnedFull holds the scrim at the fully open opacity while an open sheet re-anchors to new detents. Neither teardown path cleared it, so a view torn down during a re-anchor kept the pin. If that view is used again at a lower detent, the scrim shows the tallest detent's opacity until something clears the pin.

Platform Reuses views in production? Change
iOS Yes, Fabric recycles them resetSheetState() clears the pin
Android No, BottomSheetViewManager doesn't call setupViewRecycling() destroy() clears the pin and other leftover state
Web No, each sheet creates its own controller None. detach() keeps the pin on purpose, so a Strict Mode reattach can resume the settle

On Android, destroy() now also resets hasCardGaps and the card clipping, widestCardInsets and scrimOpacities. Only the scrim pin has a demonstrated bug and a test; the others are tidying. This doesn't make Android reuse fully supported, because values set from props and the listeners still aren't restored.

Testing

  • Android: testDebugUnitTest passes (155 tests). a scrim pinned at destroy does not carry over to a reused sheet fails without the fix because the scrim tap wrongly dismisses the sheet. a re-anchor pins the scrim at the fully open opacity is a control: it fails if the setup stops pinning, so the first test can't pass without exercising the reset.
  • iOS: the Swift sources type-check, and this branch builds and runs on a simulator. The fix itself is untested on iOS: no test recycles a view mid-animation, there's no regression test, and the bug comes from reading the code rather than reproducing it.

Not in this PR

On Android, tapping above the card on an open modal sheet with an invisible scrim fires onIndexChange and onSettle for the current detent. It reproduces on main at 289be4f, so this PR doesn't cause it, and it will be fixed separately. That's why the new test only checks that the sheet doesn't dismiss.

🤖 Generated with Claude Code

Skalakid and others added 4 commits November 5, 2026 17:08
Android does not recycle these views today, so this only affects a host
used again after destroy(). Such a host kept `scrimPinnedFull` if it was
destroyed during a re-anchor, holding the scrim at the fully open opacity.

Also clear the detent-derived fields and animation bookkeeping destroy()
missed. Values set from props and the listeners are still not restored, so
this does not make reuse fully supported.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Recycling drops the active spring without running its completion, so
`scrimPinnedFull` can outlive the sheet. From reading the code, a reused
sheet with `animateIn` off would show the tallest detent's scrim opacity at
a lower detent until the pin clears. This was not reproduced on a device,
and the change has only been type-checked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…investigation-d0e5fb

# Conflicts:
#	android/src/main/java/com/swmansion/reactnativebottomsheet/BottomSheetHostView.kt
#	ios/BottomSheetHostingView.swift
Add a control test showing the re-anchor really pins the scrim, using a
detent whose scrim is invisible unless pinned. Note why the reuse test
only checks for dismissal, and drop two resets that had no effect.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@patrickmichalik patrickmichalik left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@Skalakid
Skalakid merged commit 6439fc6 into main Nov 6, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants