Skip to content

fix: guard against bogus measureInWindow values#3739

Merged
isekovanic merged 2 commits into
developfrom
fix/rn-sys-nav-bar-portal-content
Jul 22, 2026
Merged

fix: guard against bogus measureInWindow values#3739
isekovanic merged 2 commits into
developfrom
fix/rn-sys-nav-bar-portal-content

Conversation

@isekovanic

Copy link
Copy Markdown
Contributor

🎯 Goal

Fixes an issue where in certain scenarios on Android, measureInWindow would produce extremely out of bouds values for its x and y coordinates, causing the contextual menu to not display any content as it's about 30 screens offset.

Should also close this Zendesk issue.

This reproduces whenever the app is made edge-to-edge by a library (i.e react-native-system-navigation-bar's setNavigationColor('transparent'), which sets FLAG_LAYOUT_NO_LIMITS) while React Native's own edge-to-edge is explicitly not enabled (edgeToEdgeEnabled=false). In that state Android's measureInWindow returns wildly out of bounds coordinates, so the overlay which positions its teleported hosts at the absolute measured rect lands ~tens of screens offscreen. Only the position independent absoluteFill backdrop stays visible.

🛠 Implementation details

  • measureInWindow now sanity checks the measured rect. If it's non finite, zero sized or lands more than the screen bounds away (the failure mode is off by ~33×, valid on screen targets are always < 1× so this was an acceptable buffer zone to me), it falls back to measure() and uses the root relative pageX/pageY.
    • Root relative is the coordinate space the overlay is actually positioned in (the host layer is absoluteFill inside OverlayProvider) and it stays correct because the React root's layout is RN owned, unlike the OS window, whose frame the library mutates behind RN's back
    • The healthy path is untouched, so the primary measureInWindow + Android insets.top compensation is unchanged, and measure().pageY equals it exactly in every healthy config, so a (rare) false positive is a noop
  • Additionally, PortalWhileClosingView now shares the same util, so the close animation teleport (composer/header staying above the closing message) gets the identical protection instead of its previous duplicated inline measurement

For integrators, the first class fix remains enabling RN's edgeToEdgeEnabled=true as this change is only a workaround that makes the SDK resilient even when they haven't.

🎨 UI Changes

iOS
Before After
Android
Before After

🧪 Testing

☑️ Checklist

  • I have signed the Stream CLA (required)
  • PR targets the develop branch
  • Documentation is updated
  • New code is tested in main example apps, including all possible scenarios
    • SampleApp iOS and Android
    • Expo iOS and Android

@isekovanic
isekovanic requested review from oliverlaz and szuperaz July 22, 2026 20:13
@Stream-SDK-Bot

Stream-SDK-Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

SDK Size

title develop branch diff status
js_bundle_size 1989 KB 1989 KB +531 B 🔴

@isekovanic
isekovanic merged commit edad79f into develop Jul 22, 2026
9 of 10 checks passed
@isekovanic
isekovanic deleted the fix/rn-sys-nav-bar-portal-content branch July 22, 2026 20:36
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.

3 participants