fix: handle broken measureInWindow#1355
Conversation
On Fabric, measureInWindow returns modal-surface-relative coordinates instead of screen-absolute coordinates for views inside a Modal (RN bug #52450). This causes automaticOffset to compute incorrect shift values, leaving content hidden behind the keyboard. Detect the bug by comparing measureInWindow results with onLayout coordinates. When they match, estimate absolute Y by assuming the view extends to the bottom of the screen. Also preserve the pre-keyboard frame dimensions when automaticOffset is enabled to prevent iOS modal keyboard adjustment from shrinking the frame mid-animation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
📊 Package size report
|
|
Sorry I know you've been working on this. Let me review this PR to see what's up. It's my agent creating this automatically @kirillzyusko. |
…InWindow Replace the heuristic detection of broken measureInWindow with a native windowPosition method that uses UIKit/Android view APIs to get true screen-absolute coordinates. This correctly handles Fabric + Modal where measureInWindow returns surface-relative coordinates (RN bug #52450). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Pass both x and y from windowPosition (matching original measureInWindow behavior) - Add .catch() to handle view-not-found rejection gracefully Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On Paper architecture, viewWithTag may not find the view, causing windowPosition to reject. Fall back to measureInWindow which returns correct absolute coordinates on Paper. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fall back to onLayout values when findNodeHandle returns null instead of silently dropping the layout event - Replace deprecated keyWindow with UIWindowScene API for iOS 13+ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Import findNodeHandle from library's utils wrapper (consistent with KeyboardAwareScrollView usage) instead of directly from react-native - Add view.superview nil check in iOS windowPosition to avoid silently resolving with CGRectZero when superview is nil Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@kirillzyusko I took a look at this and it seems like an interesting direction. I know you're working on your own solution and submitted a PR for the RN team, but do you think this approach here would be something to consider? |
kirillzyusko
left a comment
There was a problem hiding this comment.
Overall I like the idea. I left few comments what can be improved in current implementation - in a meantime I'll test Android/iOS both architectures to check whether it works or not!
|
Paper/Android:
This is because: Error: Could not find view for tag
at promiseMethodWrapper (10.0.2.2:8081/index.bundle//&platform=android&dev=true&lazy=true&minify=false&app=com.example.reactnativekeyboardcontroller&modulesOnly=false&runModule=true&excludeSource=true&sourcePaths=url-server:2445:45)
at anonymous (10.0.2.2:8081/index.bundle//&platform=android&dev=true&lazy=true&minify=false&app=com.example.reactnativekeyboardcontroller&modulesOnly=false&runModule=true&excludeSource=true&sourcePaths=url-server:137449:100)
at executeDispatch (10.0.2.2:8081/index.bundle//&platform=android&dev=true&lazy=true&minify=false&app=com.example.reactnativekeyboardcontroller&modulesOnly=false&runModule=true&excludeSource=true&sourcePaths=url-server:77718:17)
at runWithFiberInDEV (10.0.2.2:8081/index.bundle//&platform=android&dev=true&lazy=true&minify=false&app=com.example.reactnativekeyboardcontroller&modulesOnly=false&runModule=true&excludeSource=true&sourcePaths=url-server:77696:135)
at executeDispatchesAndReleaseTopLevel (10.0.2.2:8081/index.bundle//&platform=android&dev=true&lazy=true&minify=false&app=com.example.reactnativekeyboardcontroller&modulesOnly=false&runModule=true&excludeSource=true&sourcePaths=url-server:77992:84)
at call (native)
at forEachAccumulated (10.0.2.2:8081/index.bundle//&platform=android&dev=true&lazy=true&minify=false&app=com.example.reactnativekeyboardcontroller&modulesOnly=false&runModule=true&excludeSource=true&sourcePaths=url-server:77861:67)
at anonymous (10.0.2.2:8081/index.bundle//&platform=android&dev=true&lazy=true&minify=false&app=com.example.reactnativekeyboardcontroller&modulesOnly=false&runModule=true&excludeSource=true&sourcePaths=url-server:78014:29)
at batchedUpdatesImpl (10.0.2.2:8081/index.bundle//&platform=android&dev=true&lazy=true&minify=false&app=com.example.reactnativekeyboardcontroller&modulesOnly=false&runModule=true&excludeSource=true&sourcePaths=url-server:86481:18)
at batchedUpdates$1 (10.0.2.2:8081/index.bundle//&platform=android&dev=true&lazy=true&minify=false&app=com.example.reactnativekeyboardcontroller&modulesOnly=false&runModule=true&excludeSource=true&sourcePaths=url-server:77978:34)
at _receiveRootNodeIDEvent (10.0.2.2:8081/index.bundle//&platform=android&dev=true&lazy=true&minify=false&app=com.example.reactnativekeyboardcontroller&modulesOnly=false&runModule=true&excludeSource=true&sourcePaths=url-server:78003:23)
at receiveEvent (10.0.2.2:8081/index.bundle//&platform=android&dev=true&lazy=true&minify=false&app=com.example.reactnativekeyboardcontroller&modulesOnly=false&runModule=true&excludeSource=true&sourcePaths=url-server:84702:32)
at apply (native)
at __callFunction (10.0.2.2:8081/index.bundle//&platform=android&dev=true&lazy=true&minify=false&app=com.example.reactnativekeyboardcontroller&modulesOnly=false&runModule=true&excludeSource=true&sourcePaths=url-server:2877:38)
at anonymous (10.0.2.2:8081/index.bundle//&platform=android&dev=true&lazy=true&minify=false&app=com.example.reactnativekeyboardcontroller&modulesOnly=false&runModule=true&excludeSource=true&sourcePaths=url-server:2633:31)
at __guard (10.0.2.2:8081/index.bundle//&platform=android&dev=true&lazy=true&minify=false&app=com.example.reactnativekeyboardcontroller&modulesOnly=false&runModule=true&excludeSource=true&sourcePaths=url-server:2823:15)
at callFunctionReturnFlushedQueue (10.0.2.2:8081/index.bundle//&platform=android&dev=true&lazy=true&minify=false&app=com.example.reactnativekeyboardcontroller&modulesOnly=false&runModule=true&excludeSource=true&sourcePaths=url-server:2632:21)I think you wrote: val view = mReactContext.currentActivity?.findViewById<View>(viewTag.toInt())Which may be not correct, because Modal will live in separate P. S. fixed in 404e936 |
|
I changed code a little bit, but thank you again for the contribution! ❤️ |
Thanks for taking it to the finish line! @kirillzyusko |
|
My pleasure 😊 |
) ## 📜 Description Automatically detect top border of `KeyboardAwareScrollView`. ## 💡 Motivation and Context Continue the epic with better discovery of component location on the screen and logical continuation of #1346 In this PR I started to detect relative position of `ScrollView`, so that I better understand if caret is not visible because it obscured by other elements (header etc.) It's still not perfectly implemented and there is still a "blind"/"dead" zone where text is already hidden but scroll doesn't happen. I'll fix it in following PRs but for now I just want to bring these changes to upcoming `1.21.0` release 🤞 We also can't use `measureInWindow` because it produces incorrect measurements, so we need to use our custom implementation that has been added in #1355 Significantly improves UI for behavior described in #1341 ## 📢 Changelog <!-- High level overview of important changes --> <!-- For example: fixed status bar manipulation; added new types declarations; --> <!-- If your changes don't affect one of platform/language below - then remove this platform/language --> ### JS - auto detect position of `KeyboardAwareScrollView` on the screen to better understand top border of the component relative to screen; ## 🤔 How Has This Been Tested? Tested manually on iPhone 17 Pro (iOS 26.2, simulator). ## 📸 Screenshots (if appropriate): https://github.com/user-attachments/assets/43fe233f-9c83-40c9-9642-a68e2d8e8e7c ## 📝 Checklist - [x] CI successfully passed - [x] I added new mocks and corresponding unit-tests if library API was changed
## 📜 Description Fixed `IllegalViewOperationException` crash on Android. ## 💡 Motivation and Context Original code has been introduced in #1355 and further started to be used in #1352 Now if view is not found it throws an unhandled exception and crashes the app. In reality we already handle "view not found" exception, so we should just add a proper try/catch block to handle this error correctly in Kotlin code 🤞 Closes #1443 ## 📢 Changelog <!-- High level overview of important changes --> <!-- For example: fixed status bar manipulation; added new types declarations; --> <!-- If your changes don't affect one of platform/language below - then remove this platform/language --> ### Android - wrap `resolveView` with `catch (e: IllegalViewOperationException)`; ## 🤔 How Has This Been Tested? Tested via e2e pipeline. ## 📝 Checklist - [x] CI successfully passed - [x] I added new mocks and corresponding unit-tests if library API was changed

📜 Description
Fixed broken
measureInWindowmeasurements in react-native.💡 Motivation and Context
The
measureInWindowworks unreliably in Fabric + formSheet Modal (facebook/react-native#56062) or on Android with edge-to-edge enabled (facebook/react-native#56056)Upstream fixes are available, but the problem is that it will require at least RN 0.85+ to work properly. So in this PR we add internal function that is capable of measuring given view. In future this functionality can be removed, but for now this is critical to have it bundled within a package.
Fixes #1356
📢 Changelog
JS
viewPositionInWindowtotypes;viewPositionInWindowto codegen;viewPositionInWindowto bindings/module;viewPositionInWindowinstead ofmeasureInWindow;viewPositionInWindowto mocks;iOS
viewPositionInWindow;activeWindowobjc available;Android
viewPositionInWindow;uiManagerandeventDispatchertoReactContextextensions;🤔 How Has This Been Tested?
Tested manually on iPhone 17 Pro (iOS 26.2, simulator) and Pixel 9 Pro (API 35, emulator).
📸 Screenshots (if appropriate):
Android
Fabric
Screen.Recording.2026-03-12.at.16.34.28.mov
Screen.Recording.2026-03-12.at.16.27.10.mov
Paper
Screen.Recording.2026-03-12.at.16.30.43.mov
Screen.Recording.2026-03-12.at.16.21.48.mov
iOS
Fabric
Simulator.Screen.Recording.-.iPhone.17.Pro.-.2026-03-12.at.16.38.23.mov
Simulator.Screen.Recording.-.iPhone.17.Pro.-.2026-03-12.at.16.25.29.mov
Paper
Simulator.Screen.Recording.-.iPhone.17.Pro.-.2026-03-12.at.16.29.28.mov
Simulator.Screen.Recording.-.iPhone.17.Pro.-.2026-03-12.at.16.18.25.mov
📝 Checklist