Skip to content

fix: bounds transitions are mirrored in RTL#134

Closed
AlshehriAli0 wants to merge 1 commit into
eds2002:mainfrom
AlshehriAli0:fix/rtl-physical-left-anchors
Closed

fix: bounds transitions are mirrored in RTL#134
AlshehriAli0 wants to merge 1 commit into
eds2002:mainfrom
AlshehriAli0:fix/rtl-physical-left-anchors

Conversation

@AlshehriAli0

@AlshehriAli0 AlshehriAli0 commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Problem

On apps running in native RTL (I18nManager.isRTL), every bounds/zoom transition is horizontally mirrored. An element sitting on the left side of the screen opens from the right, dismisses to the right, then snaps to its real position when the transition pair tears down. Drag gestures track the finger correctly the whole time.

Cause

The translate math works in physical page coordinates measured from the left edge of the screen, but three fixed width boxes assume a physical top-left anchor, and RTL layout moves that anchor to the right edge:

  • portal-boundary-host.tsx: the teleported clone is absolutely positioned with left: 0 plus an explicit source width. With RN's default doLeftAndRightSwapInRTL, left: 0 becomes a right edge anchor in RTL, so the clone's base is screenWidth - width instead of 0.
  • maybe-masked-navigation-container.tsx: the navigation mask element is a fixed width flex child, and cross axis flex-start is the right edge in RTL.
  • masked-view.tsx (deprecated): same pattern as the mask above.

Fix

Pin these boxes to the physical left edge when RTL is active. In RTL, end: 0 always means the physical left edge, regardless of the swap setting. The LTR code path is byte identical to before. I18nManager.isRTL is fixed at app launch, so reading it at module scope is safe with worklets.

With this change the package works perfectly in RTL apps, which opens it up to a whole set of locales it did not support well before.

Why not fix the transform math instead

  • Drag gestures are already correct in RTL, which means Reanimated applies translateX physically, not mirrored. Negating the transforms fixes the flight but breaks the gestures (tried it).
  • Mirroring the measured pageX sends the flight off screen, so Fabric measurements are physical too (also tried).
  • Only anchoring the base to the physical left fixes open, dismiss, and gestures at once.

Found in a production RTL app, where we have been running this fix as a local patch and it works perfectly. Verified on an Android device with an Arabic locale: grid to detail zoom with escapeClipping and navigationMaskEnabled, open, dismiss, and all drag gestures correct, LTR unchanged. bun run lint and bun run typecheck pass.

@netlify

netlify Bot commented Jul 22, 2026

Copy link
Copy Markdown

Deploy Preview for rnst-docs canceled.

Name Link
🔨 Latest commit 6c45132
🔍 Latest deploy log https://app.netlify.com/projects/rnst-docs/deploys/6a611991b51cba00082b214c

@AlshehriAli0

Copy link
Copy Markdown
Contributor Author

@eds2002

@eds2002

eds2002 commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Cherry picked and released in v3.10 thank you!

@eds2002 eds2002 closed this Jul 24, 2026
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