forked from facebook/react-native
-
Notifications
You must be signed in to change notification settings - Fork 162
Closed
Labels
Description
Environment
react-native -v: command not found (Metro says v0.73.2)
npm ls react-native-macos: react-native-macos@0.73.15
node -v: v18.19.0
npm -v: 10.3.0
yarn --version: 3.6.1
xcodebuild -version: Xcode 13.2.1 Build version 13C100Steps to reproduce the bug
- Create a custom native tabView component
// MyTabViewManager.m
#import <AppKit/AppKit.h>
#import <React/RCTViewManager.h>
@interface MyTabView : NSTabView
@end
@interface MyTabViewManager : RCTViewManager<NSTabViewDelegate>
@end
@implementation MyTabViewManager
RCT_EXPORT_MODULE(MyTabView)
- (MyTabView *)view {
MyTabView *tabView = [[MyTabView alloc] init];
tabView.delegate = self;
// Insert some tabs
NSTabViewItem *tabViewItem = [[NSTabViewItem alloc] init];
tabViewItem.label = @"Tab One";
// Add empty view
tabViewItem.view = [NSView new];
[tabView addTabViewItem:tabViewItem];
// Insert another tab
NSTabViewItem *tabViewItem2 = [[NSTabViewItem alloc] init];
tabViewItem2.label = @"Tab Two";
// Add empty view
tabViewItem2.view = [NSView new];
[tabView addTabViewItem:tabViewItem2];
return tabView;
}- Create a TabView React component
// MyTabView.tsx
import React from 'react';
import {requireNativeComponent} from 'react-native';
const TabView = () => {
return <MyTabView style={{ height: 300 }} />;
};
const MyTabView = requireNativeComponent('MyTabView');
module.exports = TabView;- Click on tab label buttons.
Expected Behavior
The tab buttons should activate on click.
Actual Behavior
The first click activates the button but the second click logs the error "Touch is already recorded. This is a critical bug." On the first click, the mouseDown event fires but mouseUp does not. On the second click the mouseDown does not fire but mouseUp does.
Reproducible Demo
No response
Additional context
The bug is located in RCTTouchHandler
// Pair the mouse down events with mouse up events so our _nativeTouches cache doesn't get stale
if ([targetView isKindOfClass:[NSControl class]]) {
_shouldSendMouseUpOnSystemBehalf = [(NSControl*)targetView isEnabled];
} else if ([targetView isKindOfClass:[NSText class]]) {
_shouldSendMouseUpOnSystemBehalf = [(NSText*)targetView isSelectable];
}
else if ([targetView.superview isKindOfClass:[RCTUITextField class]]) {
_shouldSendMouseUpOnSystemBehalf = [(RCTUITextField*)targetView.superview isSelectable];
} else {
_shouldSendMouseUpOnSystemBehalf = NO;
}NSTabView does not inherit from NSControl. According to the view hierarchy inspector this is the class inheritance hierarchy:
- NSTabView
- NSView
- NSResponder
- NSObject
This code change seems to work
} else if ([targetView isKindOfClass:[NSTabView class]]) {
_shouldSendMouseUpOnSystemBehalf = YES;
}However this by itself seems to still have click locations in the wrong place. If I combine this with a hitTest on the custom NSTabView then it works:
- (NSView *)hitTest:(NSPoint)aPoint {
if (!self.isHidden && [self mouse:aPoint inRect:self.bounds]) {
// Convert point to each subview and check
for (NSView *subview in [self.subviews reverseObjectEnumerator]) {
NSPoint convertedPoint = [self convertPoint:aPoint toView:subview];
NSView *hitTestView = [subview hitTest:convertedPoint];
if (hitTestView) {
return hitTestView;
}
}
// If no subview should handle this point, return self or nil based on whether this view should handle clicks
return self;
}
return nil;
}