Describe the bug
TextBlockTapGestureRecognizer reconfigures touch delivery on the UITextView for every touch, which desyncs React Native's RCTSurfaceTouchHandler touch registry and aborts the app when dragging a text selection.
In its initialiser (ios/utils/TextBlockTapGestureRecognizer.mm):
self.cancelsTouchesInView = YES;
self.delaysTouchesBegan = YES;
self.delaysTouchesEnded = YES;
for (UIGestureRecognizer *gr in _input->textView.gestureRecognizers) {
[gr requireGestureRecognizerToFail:self];
}
delaysTouchesBegan = YES withholds touchesBegan: from the view hierarchy until this recognizer resolves. RCTSurfaceTouchHandler (a recognizer on the RN root view) then receives touchesMoved: for a touch it never registered in touchesBegan:, and trips its assert:
auto iterator = _activeTouches.find(touch);
RCTAssert(iterator != _activeTouches.end(), @"Inconsistency between local and UIKit touch registries");
Crash is SIGABRT, no JS error:
0 CoreFoundation __exceptionPreprocess + 164
1 libobjc.A.dylib objc_exception_throw + 88
3 <app>.debug.dylib -[RCTSurfaceTouchHandler _updateTouches:] + 528
4 <app>.debug.dylib -[RCTSurfaceTouchHandler touchesMoved:withEvent:] + 124
5 UIKitCore -[UIGestureRecognizer _componentsChanged:withEve
6 UIKitCore -[UITouchesEvent _sendEventToGestureRecognizer:] + 488
12 UIKitCore -[UIWindow sendEvent:] + 3540
13 UIKitCore -[UIApplication sendEvent:] + 408
The abort itself is debug-only (RCTAssert compiles out in release), but the touch registry is equally wrong in release. RN just silently skips the touch update instead of reporting it. This leads to crashes in downstream code.
Separately, the requireGestureRecognizerToFail: loop gates UITextView's own selection recognizers behind this one on every touch, which makes selection dragging occasionally buggy.
To Reproduce
- Run a debug build of an app rendering
<EnrichedTextInput> with defaultValue containing some styled content, e.g. <html><p>some <s>struck</s>text</p><blockquote>quoted text</blockquote></html>.
- Long-press in the text to start a selection.
- Drag the selection handle across a styled region, e.g. so its end extends across the strikethrough.
- You might have to repeat step 3 a few times, or even restart the app to get it to trigger.
- App aborts with
Inconsistency between local and UIKit touch registries.
We first found this reliably reproducible by dragging a selection that ends inside a blockquote, but have since hit it with strikethroughs too, so it is not specific to any one style. Plain-text drags did not reproduce the issue.
Expected behavior
Dragging a text selection should never crash, and the recognizer should not alter touch delivery.
Screenshots
N/A. The app aborts with no UI.
Device (please complete the following information):
- Device: IPhone 16 Plus
- OS: iOS 26.5.2 (23F84)
- Version:
react-native-enriched-html 1.0.0, react-native 0.85.3, Expo SDK 56, New Architecture
Additional context
We patched it locally by restoring stock UIKit touch delivery and dropping the loop:
self.cancelsTouchesInView = NO;
self.delaysTouchesBegan = NO;
self.delaysTouchesEnded = NO;
Describe the bug
TextBlockTapGestureRecognizerreconfigures touch delivery on theUITextViewfor every touch, which desyncs React Native'sRCTSurfaceTouchHandlertouch registry and aborts the app when dragging a text selection.In its initialiser (
ios/utils/TextBlockTapGestureRecognizer.mm):delaysTouchesBegan = YESwithholdstouchesBegan:from the view hierarchy until this recognizer resolves.RCTSurfaceTouchHandler(a recognizer on the RN root view) then receivestouchesMoved:for a touch it never registered intouchesBegan:, and trips its assert:Crash is
SIGABRT, no JS error:The abort itself is debug-only (
RCTAssertcompiles out in release), but the touch registry is equally wrong in release. RN just silently skips the touch update instead of reporting it. This leads to crashes in downstream code.Separately, the
requireGestureRecognizerToFail:loop gates UITextView's own selection recognizers behind this one on every touch, which makes selection dragging occasionally buggy.To Reproduce
<EnrichedTextInput>withdefaultValuecontaining some styled content, e.g.<html><p>some <s>struck</s>text</p><blockquote>quoted text</blockquote></html>.Inconsistency between local and UIKit touch registries.We first found this reliably reproducible by dragging a selection that ends inside a blockquote, but have since hit it with strikethroughs too, so it is not specific to any one style. Plain-text drags did not reproduce the issue.
Expected behavior
Dragging a text selection should never crash, and the recognizer should not alter touch delivery.
Screenshots
N/A. The app aborts with no UI.
Device (please complete the following information):
react-native-enriched-html1.0.0,react-native0.85.3, Expo SDK 56, New ArchitectureAdditional context
We patched it locally by restoring stock UIKit touch delivery and dropping the loop: