Discard measured responder region that excludes the grant touch#57503
Discard measured responder region that excludes the grant touch#57503joeltjames wants to merge 1 commit into
Conversation
The responder is granted by a native hit test, so the touch that granted it necessarily lies inside the view's true on-screen region. When a view has been repositioned by native code after layout (e.g. a native sheet footer pinned with AutoLayout), measure() still reports the stale layout frame; Pressability then cancels the press on the first touchMove because the touch is outside the measured rect — press feedback fires, onPress never does. Stationary simulator taps emit no move events, so the bug only reproduces on physical devices. Validate the measured region against the grant touch position: if the region excludes the point where the press was granted, the measurement is provably stale, so discard it. A null region already means "skip press-rect checks", and correct measurements are unaffected since they contain the grant point by construction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Hi @joeltjames! Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks! |
|
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks! |
Summary:
Fixes #57502.
Pressabilitymeasures the responder view on grant and, on everytouchMove, cancels the press if the touch is outside the measured rect. On Fabric,measure()answers from the shadow tree — so when a view has been repositioned by native code after layout (e.g.@lodev09/react-native-true-sheetpins its footer slot to the sheet bottom with AutoLayout — lodev09/react-native-true-sheet#726), the measured rect can be hundreds of points away from where the view actually is. A button that natively hit-tested and granted the responder then shows press feedback (onPressIn) but never firesonPress: the first move event deactivates the press viaLEAVE_PRESS_RECT.The failure is invisible in development: stationary simulator taps emit zero move events (the check never runs), and newer device/OS combos coalesce micro-jitter moves away. On older physical hardware (tested iPhone XS-class, iOS 16/18), every real-finger tap emits at least one move event — even zero-delta — and the press silently dies.
This PR validates the measurement against the press itself: the responder was granted by a native hit test, so the grant touch necessarily lies inside the view's true on-screen region. If the async-measured region excludes the grant point, the measurement is provably stale — discard it. A
nullregion already means "skip press-rect checks" (that state exists today whenevermeasurehasn't completed), and correct measurements are unaffected since they contain the grant point by construction. Precedent:_measureCallbackalready discards all-zero measurements.Found while working on the Planning Center mobile app; diagnosed and fixed with the help of Claude (Fable). The identical patch is running in production and verified on the previously-failing devices.
Changelog:
[GENERAL] [FIXED] - Pressability no longer cancels presses using a stale measured region that does not contain the touch that granted the responder
Test Plan:
Pressability-test.js:onPressfires when the measured region excludes the grant touch (press granted at page (276, 467) with the mock region at (0, 0, 50, 50) — models a natively repositioned view; previously the first move deactivated the press).onPressstill does not fire when a valid measurement contains the grant touch and the finger then leaves the region — confirming slide-off-to-cancel is unchanged.