feat!: synchronous per-detent container layout#735
Merged
Conversation
Size the container to the sheet's visible height per detent instead of screen height / largest detent. Requires RN 0.82+. - iOS: report all size changes; immediate state updates relayout Yoga within the same UIKit layout pass - Android: per-detent state sizing (grow before animation, shrink on settle); remove scroll expansion padding workaround - JS: container always fills the sheet so flex layouts track detents - Web: sized flex wrapper for non-scrollable sheets (auto/form keep content-fit flow)
Container and footer frames now come purely from Yoga (synchronous state updates land them in the same UIKit layout pass). Footer is pinned via bottom:0 style; keyboard avoidance uses a transform. Removes LayoutUtil.
ScrollViews/FlatLists now plug in directly like a regular view: - Content fills the sheet by default (except with auto detents, which derive height from natural content) - Native scroll wiring (insets, keyboard, nested scrolling, edge effects) always applies to the detected ScrollView - iOS: removed scrollview frame-forcing; Yoga owns the frame - scrollable prop is deprecated and a no-op on native
Track the sheet's visible height per-frame during drag (and post-release settle) so the container resizes with the finger like iOS, killing the settle flicker. Skip detent reconfigure mid-drag — the size change is driven by the drag itself and resetting behavior state kills the gesture.
Kotlin's StateWrapper.updateState is hardcoded async, so the container's Yoga layout lagged the sheet by a frame or two during drags (footer jumping). Bridge to ConcreteState::updateState with unstable_Immediate — commits and mounts within the same UI-thread frame, like iOS. Falls back to the async path when the codegen lib isn't loadable (merged-so builds).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
# Conflicts: # CHANGELOG.md
Scrollables are auto-detected — the prop was already a no-op on native. Web now always uses the sized content-fill layout for plugged scrollables. Docs updated for auto-detection.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The sheet container is now sized to the sheet's visible height per detent — previously the screen height / largest detent — driven by synchronous Fabric state updates so Yoga layout lands in the same frame as the sheet on both platforms. Requires React Native 0.82+.
containerWidth/containerHeightoverride Yoga dimensions in the shared shadow node). Flex layouts (flex: 1,justifyContent, etc.) now track the sheet size and relayout on resize.unstable_Immediate, so the container relayouts within the same UIKit layout pass and animates with detent transitions. AutoLayout constraints are gone — container and footer are laid out purely by Yoga (footer keyboard avoidance uses a transform).StateWrapper.updateStateis hardcoded async, so a small JNI bridge (TrueSheetStateUpdater) commits withunstable_Immediatefor same-frame mount — replacing the scroll-range padding workaround. Falls back to the async path when the native lib isn't available.ScrollView/FlatListwork plugged in directly; insets, keyboard handling, and nested scrolling are wired automatically. Thescrollableprop is deprecated and a no-op on native.autodetents and form sheets keep content-fit sizing).Type of Change
Test Plan
Example app on both platforms:
FlatListSheet— container/scrollview resizes with the finger during drags, no flicker at settle; floating footer stays pinned through drags and detent transitionsresize(), grabber tap) — content relayouts with the transition, shrinks deferred to settle on Androidautodetents keep content-derived sizingChecklist
🤖 Generated with Claude Code