Fix onFocus/onBlur event bubbling (#506)

* Update scripts to publish react-native-macos-init

* Clean up merge markers

* Restored ios:macos RNTester parity except for InputAccessoryView.

* Revert "Restored ios:macos RNTester parity except for InputAccessoryView."

This reverts commit 5a67ae06b0.

* Remove unnecessary android builds and tar file upload.

* Fix onFocus/onBlur View events to properly bubble.

* The Text component can also be selectable={true} and needs the same focus/blur event triggering as View.

Co-authored-by: React-Native Bot <53619745+rnbot@users.noreply.github.com>
This commit is contained in:
Tom Underhill 2020-07-20 16:16:10 -07:00 коммит произвёл GitHub
Родитель 317a3aec19
Коммит 4ee9c185d1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
17 изменённых файлов: 260 добавлений и 55 удалений

0
.ado/setup_droid_deps.sh Normal file → Executable file
Просмотреть файл

Просмотреть файл

@ -21,6 +21,7 @@ const View = require('./View/View');
const invariant = require('invariant'); const invariant = require('invariant');
import type {PressEvent} from '../Types/CoreEventTypes'; import type {PressEvent} from '../Types/CoreEventTypes';
import type {FocusEvent, BlurEvent} from './TextInput/TextInput'; // TODO(OSS Candidate ISS#2710739)
type ButtonProps = $ReadOnly<{| type ButtonProps = $ReadOnly<{|
/** /**
@ -100,6 +101,18 @@ type ButtonProps = $ReadOnly<{|
* Used to locate this view in end-to-end tests. * Used to locate this view in end-to-end tests.
*/ */
testID?: ?string, testID?: ?string,
// [TODO(OSS Candidate ISS#2710739)
/**
* Handler to be called when the button receives key focus
*/
onBlur?: ?(e: BlurEvent) => void,
/**
* Handler to be called when the button loses key focus
*/
onFocus?: ?(e: FocusEvent) => void,
// ]TODO(OSS Candidate ISS#2710739)
|}>; |}>;
/** /**
@ -147,6 +160,8 @@ class Button extends React.Component<ButtonProps> {
nextFocusUp, nextFocusUp,
disabled, disabled,
testID, testID,
onFocus, // TODO(OSS Candidate ISS#2710739)
onBlur, // TODO(OSS Candidate ISS#2710739)
} = this.props; } = this.props;
const buttonStyles = [styles.button]; const buttonStyles = [styles.button];
const textStyles = [styles.text]; const textStyles = [styles.text];
@ -189,6 +204,8 @@ class Button extends React.Component<ButtonProps> {
testID={testID} testID={testID}
disabled={disabled} disabled={disabled}
onPress={onPress} onPress={onPress}
onFocus={onFocus} // TODO(OSS Candidate ISS#2710739)
onBlur={onBlur} // TODO(OSS Candidate ISS#2710739)
touchSoundDisabled={touchSoundDisabled}> touchSoundDisabled={touchSoundDisabled}>
<View style={buttonStyles}> <View style={buttonStyles}>
<Text style={textStyles} disabled={disabled}> <Text style={textStyles} disabled={disabled}>

Просмотреть файл

@ -1025,6 +1025,8 @@ const TextInput = createReactClass({
<TouchableWithoutFeedback <TouchableWithoutFeedback
onLayout={props.onLayout} onLayout={props.onLayout}
onPress={this._onPress} onPress={this._onPress}
onFocus={this._onFocus} // TODO(macOS ISS#2323203)
onBlur={this._onBlur} // TODO(macOS ISS#2323203)
rejectResponderTermination={true} rejectResponderTermination={true}
accessible={props.accessible} accessible={props.accessible}
accessibilityLabel={props.accessibilityLabel} accessibilityLabel={props.accessibilityLabel}
@ -1079,6 +1081,8 @@ const TextInput = createReactClass({
<TouchableWithoutFeedback <TouchableWithoutFeedback
onLayout={props.onLayout} onLayout={props.onLayout}
onPress={this._onPress} onPress={this._onPress}
onFocus={this._onFocus} // TODO(macOS ISS#2323203)
onBlur={this._onBlur} // TODO(macOS ISS#2323203)
rejectResponderTermination={props.rejectResponderTermination} rejectResponderTermination={props.rejectResponderTermination}
accessible={props.accessible} accessible={props.accessible}
accessibilityLabel={props.accessibilityLabel} accessibilityLabel={props.accessibilityLabel}
@ -1136,6 +1140,8 @@ const TextInput = createReactClass({
<TouchableWithoutFeedback <TouchableWithoutFeedback
onLayout={props.onLayout} onLayout={props.onLayout}
onPress={this._onPress} onPress={this._onPress}
onFocus={this._onFocus} // TODO(macOS ISS#2323203)
onBlur={this._onBlur} // TODO(macOS ISS#2323203)
accessible={this.props.accessible} accessible={this.props.accessible}
accessibilityLabel={this.props.accessibilityLabel} accessibilityLabel={this.props.accessibilityLabel}
accessibilityRole={this.props.accessibilityRole} accessibilityRole={this.props.accessibilityRole}

Просмотреть файл

@ -218,6 +218,8 @@ const TouchableBounce = ((createReactClass({
onDragEnter={this.props.onDragEnter} onDragEnter={this.props.onDragEnter}
onDragLeave={this.props.onDragLeave} onDragLeave={this.props.onDragLeave}
onDrop={this.props.onDrop} onDrop={this.props.onDrop}
onFocus={this.props.onFocus}
onBlur={this.props.onBlur}
draggedTypes={this.props.draggedTypes} // ]TODO(macOS ISS#2323203) draggedTypes={this.props.draggedTypes} // ]TODO(macOS ISS#2323203)
> >
{this.props.children} {this.props.children}

Просмотреть файл

@ -454,6 +454,8 @@ const TouchableHighlight = ((createReactClass({
onDragEnter={this.props.onDragEnter} onDragEnter={this.props.onDragEnter}
onDragLeave={this.props.onDragLeave} onDragLeave={this.props.onDragLeave}
onDrop={this.props.onDrop} onDrop={this.props.onDrop}
onFocus={this.props.onFocus}
onBlur={this.props.onBlur}
draggedTypes={this.props.draggedTypes} // ]TODO(macOS/win ISS#2323203) draggedTypes={this.props.draggedTypes} // ]TODO(macOS/win ISS#2323203)
nativeID={this.props.nativeID} nativeID={this.props.nativeID}
testID={this.props.testID}> testID={this.props.testID}>

Просмотреть файл

@ -355,6 +355,8 @@ const TouchableOpacity = ((createReactClass({
onDragEnter={this.props.onDragEnter} onDragEnter={this.props.onDragEnter}
onDragLeave={this.props.onDragLeave} onDragLeave={this.props.onDragLeave}
onDrop={this.props.onDrop} onDrop={this.props.onDrop}
onFocus={this.props.onFocus}
onBlur={this.props.onBlur}
draggedTypes={this.props.draggedTypes} // ]TODO(macOS ISS#2323203) draggedTypes={this.props.draggedTypes} // ]TODO(macOS ISS#2323203)
onResponderTerminate={this.touchableHandleResponderTerminate}> onResponderTerminate={this.touchableHandleResponderTerminate}>
{this.props.children} {this.props.children}

Просмотреть файл

@ -351,6 +351,8 @@ const TouchableWithoutFeedback = ((createReactClass({
onDragEnter: this.props.onDragEnter, onDragEnter: this.props.onDragEnter,
onDragLeave: this.props.onDragLeave, onDragLeave: this.props.onDragLeave,
onDrop: this.props.onDrop, onDrop: this.props.onDrop,
onFocus: this.props.onFocus,
onBlur: this.props.onBlur,
draggedTypes: this.props.draggedTypes, // ]TODO(macOS ISS#2323203) draggedTypes: this.props.draggedTypes, // ]TODO(macOS ISS#2323203)
children, children,
}); });

Просмотреть файл

@ -6,6 +6,7 @@
*/ */
#import <React/RCTComponent.h> #import <React/RCTComponent.h>
#import <React/RCTEventDispatcher.h> // TODO(OSS Candidate ISS#2710739)
#import <React/RCTUIKit.h> // TODO(macOS ISS#2323203) #import <React/RCTUIKit.h> // TODO(macOS ISS#2323203)
@ -13,6 +14,8 @@ NS_ASSUME_NONNULL_BEGIN
@interface RCTTextView : RCTUIView // TODO(macOS ISS#3536887) @interface RCTTextView : RCTUIView // TODO(macOS ISS#3536887)
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher; // TODO(OSS Candidate ISS#2710739)
@property (nonatomic, assign) BOOL selectable; @property (nonatomic, assign) BOOL selectable;
- (void)setTextStorage:(NSTextStorage *)textStorage - (void)setTextStorage:(NSTextStorage *)textStorage

Просмотреть файл

@ -16,6 +16,7 @@
#import <React/RCTAssert.h> // TODO(macOS ISS#2323203) #import <React/RCTAssert.h> // TODO(macOS ISS#2323203)
#import <React/RCTUtils.h> #import <React/RCTUtils.h>
#import <React/UIView+React.h> #import <React/UIView+React.h>
#import <React/RCTFocusChangeEvent.h> // TODO(OSS Candidate ISS#2710739)
#import <React/RCTTextShadowView.h> #import <React/RCTTextShadowView.h>
@ -30,11 +31,22 @@
NSString * _accessibilityLabel; NSString * _accessibilityLabel;
#endif // ]TODO(macOS ISS#2323203) #endif // ]TODO(macOS ISS#2323203)
RCTEventDispatcher *_eventDispatcher; // TODO(OSS Candidate ISS#2710739)
NSArray<RCTUIView *> *_Nullable _descendantViews; // TODO(macOS ISS#3536887) NSArray<RCTUIView *> *_Nullable _descendantViews; // TODO(macOS ISS#3536887)
NSTextStorage *_Nullable _textStorage; NSTextStorage *_Nullable _textStorage;
CGRect _contentFrame; CGRect _contentFrame;
} }
// [TODO(OSS Candidate ISS#2710739)
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
{
if ((self = [self initWithFrame:CGRectZero])) {
_eventDispatcher = eventDispatcher;
}
return self;
}
// ]TODO(OSS Candidate ISS#2710739)
- (instancetype)initWithFrame:(CGRect)frame - (instancetype)initWithFrame:(CGRect)frame
{ {
if (self = [super initWithFrame:frame]) { if (self = [super initWithFrame:frame]) {
@ -374,6 +386,31 @@
} }
} }
} }
- (BOOL)becomeFirstResponder
{
if (![super becomeFirstResponder]) {
return NO;
}
// If we've gained focus, notify listeners
[_eventDispatcher sendEvent:[RCTFocusChangeEvent focusEventWithReactTag:self.reactTag]];
return YES;
}
- (BOOL)resignFirstResponder
{
if (![super resignFirstResponder]) {
return NO;
}
// If we've lost focus, notify listeners
[_eventDispatcher sendEvent:[RCTFocusChangeEvent blurEventWithReactTag:self.reactTag]];
return YES;
}
#endif // ]TODO(macOS ISS#2323203) #endif // ]TODO(macOS ISS#2323203)
- (BOOL)canBecomeFirstResponder - (BOOL)canBecomeFirstResponder

Просмотреть файл

@ -59,7 +59,7 @@ RCT_EXPORT_VIEW_PROPERTY(selectable, BOOL)
- (RCTUIView *)view // TODO(macOS ISS#3536887) - (RCTUIView *)view // TODO(macOS ISS#3536887)
{ {
return [RCTTextView new]; return [[RCTTextView alloc] initWithEventDispatcher:self.bridge.eventDispatcher]; // TODO(OSS Candidate ISS#2710739)
} }
- (RCTShadowView *)shadowView - (RCTShadowView *)shadowView

Просмотреть файл

@ -348,34 +348,34 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
boost-for-react-native: a110407d9db2642fd2e1bcd7c5a51c81f2521dc9 boost-for-react-native: a110407d9db2642fd2e1bcd7c5a51c81f2521dc9
DoubleConversion: a1bc12a74baa397a2609e0f10e19b8062d864053 DoubleConversion: a1bc12a74baa397a2609e0f10e19b8062d864053
FBLazyVector: f5bad3ee19c3b19198bc28f46d6659e25572ac47 FBLazyVector: dd4758081b0f021c1143d98bfb9b9c417c4b9759
FBReactNativeSpec: 7732ed43803015907c93dfe88fdf2be2e24d0d70 FBReactNativeSpec: c6032881e58249a39922c173508a450a8c0fa84a
Folly: feff29ba9d0b7c2e4f793a94942831d6cc5bbad7 Folly: feff29ba9d0b7c2e4f793a94942831d6cc5bbad7
glog: b3f6d74f3e2d33396addc0ee724d2b2b79fc3e00 glog: b3f6d74f3e2d33396addc0ee724d2b2b79fc3e00
RCTRequired: 812bd7bbc1be8b3256048f9b5f34535639b29732 RCTRequired: 733f6fc9179aa8fcc87fb63f3f3aad9929241fc3
RCTTypeSafety: 193e6faaa597b67aff42fddb7c2fd541ef623f1b RCTTypeSafety: c52f0b46836e84cb951d9c40c8209d10775b6bbc
React: fe6fcc68ad4f08c1fe87a4f2fa15b017f239bc0f React: b94e937a7271f35ee705c21d0c54990192cc1634
React-ART: bc65ee94c935651318476044693d899f8aa8efd5 React-ART: c55a2a4bc6f9bec3bb604606175f05ee081a7455
React-Core: a35413a7c9a7bea6971d7c0f97f760cc5e08fbaa React-Core: 5fc0c8ad37c5f0f6a40433be0524cee6058edd17
React-CoreModules: c94d232fd1a586cb39ba012e619a153197c87789 React-CoreModules: 015ba93e2945bf810a6ef67f5b4086c87ae63009
React-cxxreact: f80f29082cdceb455e30db3970a01cba7e3e04e6 React-cxxreact: 07fae12835719892e7fe92dfc46103f69a1a8e39
React-jsi: 140a17602e41ecfdd12d05ecc6d4da581d9a8106 React-jsi: 20175357a063599ea4c8f969c4b325e76eae5aaa
React-jsiexecutor: 557554207726e37d82725e5e90536f528d97578c React-jsiexecutor: 308871755c64cb5eacd94cd01ee34ba02a50f5da
React-jsinspector: cc8beb2af2ace265bf9d32535611caa06b39c9c1 React-jsinspector: 03688e20257352e97f0e69016743b90561a3b23f
React-RCTActionSheet: b7034fd12b78151e1ca8c58c860a965b925df4ea React-RCTActionSheet: 3a6b052391c5fff7e1b27539ef9d7834f7cefed5
React-RCTAnimation: a3ad6ef884a511336589ee9c8f7ee3f377d5466c React-RCTAnimation: 15e4bf4f576bb5f610dbaa016c2e555ea4a7c228
React-RCTBlob: fbb81655e4d135a57e29954f2c2d67d1aafdfff6 React-RCTBlob: 4b22ab790b485e2d1b5bc0183ccc02dc15ae866d
React-RCTImage: 85746d1b88dd0f6ab0d9c3783b0b034838e4daad React-RCTImage: 71640ec76e906b84d86af56f98421aeb4f82466b
React-RCTLinking: 57aa7ef8760443195c2cfd704ca64c85436bcde4 React-RCTLinking: af1912929e4da9443ac128f6ded8eecca7fcde90
React-RCTNetwork: 08ef45f90629939182c1a33d70892ed66b8f5cc2 React-RCTNetwork: fc021eb11dabf0100f570f89588df3e27b0499b1
React-RCTPushNotification: df58486300dfbf81dee444b725d1208cd79b808d React-RCTPushNotification: 15e4ffb1d0db67e906afdecc8cacfab348f451e5
React-RCTSettings: 3eb68e04de7e8b99e38eb299fb7d2161ae14743c React-RCTSettings: d5486cbc262bf0b1b76ab7a0c60e78e8973f5563
React-RCTTest: 262ad0c0820cbbcbb609386c9dde07083b3d62db React-RCTTest: 1ade3c47acd1eef8ed042be56d6d2ba153fca552
React-RCTText: 5b457f78863067483d3f74ed43b8740a57d94fb0 React-RCTText: 89c4bc63088b38b68b9008c525b507edaa9277e8
React-RCTVibration: 4616073e79bd812b402aabe21aa9f663bccaf1b0 React-RCTVibration: 13734e1938ee92a3363e7d437602e3e0cbe0b1f9
ReactCommon: 8d2b53e8598fa17b6fb8ef814b726a3f17cce4f9 ReactCommon: cdaca147e8b50f4c424044db5055e602f9addf07
Yoga: 9cc54b8ca13d6fa87f8214c6eac97745e1df8092 Yoga: 39d21425da1d0e0463995aaa8f5af56db0b39ed3
PODFILE CHECKSUM: 2bf56de39dc7e153b4f1637e0f4874f2591fc55a PODFILE CHECKSUM: 1a5700c13b2bc8ffc5ed4282d795e8909c883f63
COCOAPODS: 1.9.1 COCOAPODS: 1.9.3

Просмотреть файл

@ -13,7 +13,7 @@
var React = require('react'); var React = require('react');
var ReactNative = require('react-native'); var ReactNative = require('react-native');
import {Platform} from 'react-native'; import {Platform} from 'react-native';
var {StyleSheet, Text, View, TextInput} = ReactNative; var {Button, StyleSheet, Text, View, TextInput} = ReactNative;
type State = { type State = {
eventStream: string, eventStream: string,
@ -110,33 +110,103 @@ class FocusEventExample extends React.Component<{}, State> {
{// Only test View on MacOS, since canBecomeFirstResponder is false on all iOS, therefore we can't focus {// Only test View on MacOS, since canBecomeFirstResponder is false on all iOS, therefore we can't focus
Platform.OS === 'macos' ? ( Platform.OS === 'macos' ? (
<View <View>
onFocus={() => {
this.setState(prevState => ({
eventStream:
prevState.eventStream + '\nNested View Parent Focus',
}));
}}
onBlur={() => {
this.setState(prevState => ({
eventStream:
prevState.eventStream + '\nNested View Parent Blur',
}));
}}>
<View <View
acceptsKeyboardFocus={true}
enableFocusRing={true}
onFocus={() => { onFocus={() => {
this.setState(prevState => ({ this.setState(prevState => ({
eventStream: prevState.eventStream + '\nNested View Focus', eventStream:
prevState.eventStream + '\nDescendent Button Focus',
})); }));
}} }}
onBlur={() => { onBlur={() => {
this.setState(prevState => ({ this.setState(prevState => ({
eventStream: prevState.eventStream + '\nNested View Blur', eventStream:
prevState.eventStream + '\nDescendent Button Blur',
})); }));
}}> }}>
<Text>Nested Focusable View</Text> <View>
<Button
title="Button whose ancestor has onFocus/onBlur"
onPress={() => {}}
/>
</View>
</View>
<View
onFocus={() => {
this.setState(prevState => ({
eventStream:
prevState.eventStream + '\nDescendent Button Focus',
}));
}}
onBlur={() => {
this.setState(prevState => ({
eventStream:
prevState.eventStream + '\nDescendent Button Blur',
}));
}}>
<View>
<Button
title="Button with onFocus/onBlur and ancestor has onFocus/onBlur"
onPress={() => {}}
onFocus={() => {
this.setState(prevState => ({
eventStream: prevState.eventStream + '\nButton Focus',
}));
}}
onBlur={() => {
this.setState(prevState => ({
eventStream: prevState.eventStream + '\nButton Blur',
}));
}}
/>
</View>
</View>
<View
onFocus={() => {
this.setState(prevState => ({
eventStream:
prevState.eventStream + '\nDescendent Text Focus',
}));
}}
onBlur={() => {
this.setState(prevState => ({
eventStream:
prevState.eventStream + '\nDescendent Text Blur',
}));
}}>
<View>
<Text selectable={true}>Selectable text</Text>
</View>
</View>
<View
onFocus={() => {
this.setState(prevState => ({
eventStream:
prevState.eventStream + '\nNested View Parent Focus',
}));
}}
onBlur={() => {
this.setState(prevState => ({
eventStream:
prevState.eventStream + '\nNested View Parent Blur',
}));
}}>
<View
acceptsKeyboardFocus={true}
enableFocusRing={true}
onFocus={() => {
this.setState(prevState => ({
eventStream:
prevState.eventStream + '\nNested View Focus',
}));
}}
onBlur={() => {
this.setState(prevState => ({
eventStream: prevState.eventStream + '\nNested View Blur',
}));
}}>
<Text>Nested Focusable View</Text>
</View>
</View> </View>
</View> </View>
) : null} ) : null}

Просмотреть файл

@ -0,0 +1,20 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import <Foundation/Foundation.h>
#import <React/RCTComponentEvent.h>
/**
* Represents a focus change event meaning that a view that can become first responder has become or resigned being first responder.
*/
@interface RCTFocusChangeEvent : RCTComponentEvent
+ (instancetype)focusEventWithReactTag:(NSNumber *)reactTag;
+ (instancetype)blurEventWithReactTag:(NSNumber *)reactTag;
@end

Просмотреть файл

@ -0,0 +1,30 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#import "RCTFocusChangeEvent.h"
#import "RCTAssert.h"
@implementation RCTFocusChangeEvent
+ (instancetype)focusEventWithReactTag:(NSNumber *)reactTag
{
RCTFocusChangeEvent *event = [[self alloc] initWithName:@"focus"
viewTag:reactTag
body:@{}];
return event;
}
+ (instancetype)blurEventWithReactTag:(NSNumber *)reactTag
{
RCTFocusChangeEvent *event = [[self alloc] initWithName:@"blur"
viewTag:reactTag
body:@{}];
return event;
}
@end

Просмотреть файл

@ -9,6 +9,7 @@
#import <React/RCTBorderStyle.h> #import <React/RCTBorderStyle.h>
#import <React/RCTComponent.h> #import <React/RCTComponent.h>
#import <React/RCTEventDispatcher.h> // TODO(OSS Candidate ISS#2710739)
#import <React/RCTPointerEvents.h> #import <React/RCTPointerEvents.h>
#if !TARGET_OS_OSX // TODO(macOS ISS#2323203) #if !TARGET_OS_OSX // TODO(macOS ISS#2323203)
@ -22,6 +23,8 @@ extern const UIAccessibilityTraits SwitchAccessibilityTrait;
@interface RCTView : RCTUIView // TODO(macOS ISS#3536887) @interface RCTView : RCTUIView // TODO(macOS ISS#3536887)
// [TODO(OSS Candidate ISS#2710739) // [TODO(OSS Candidate ISS#2710739)
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher;
- (BOOL)becomeFirstResponder; - (BOOL)becomeFirstResponder;
- (BOOL)resignFirstResponder; - (BOOL)resignFirstResponder;
// ]TODO(OSS Candidate ISS#2710739) // ]TODO(OSS Candidate ISS#2710739)

Просмотреть файл

@ -9,6 +9,7 @@
#import "RCTAutoInsetsProtocol.h" #import "RCTAutoInsetsProtocol.h"
#import "RCTBorderDrawing.h" #import "RCTBorderDrawing.h"
#import "RCTFocusChangeEvent.h" // TODO(OSS Candidate ISS#2710739)
#import "RCTConvert.h" #import "RCTConvert.h"
#import "RCTLog.h" #import "RCTLog.h"
#import "RCTRootContentView.h" // TODO(macOS ISS#2323203) #import "RCTRootContentView.h" // TODO(macOS ISS#2323203)
@ -108,6 +109,7 @@ static NSString *RCTRecursiveAccessibilityLabel(RCTUIView *view) // TODO(macOS I
@implementation RCTView @implementation RCTView
{ {
RCTUIColor *_backgroundColor; // TODO(OSS Candidate ISS#2710739) RCTUIColor *_backgroundColor; // TODO(OSS Candidate ISS#2710739)
RCTEventDispatcher *_eventDispatcher; // TODO(OSS Candidate ISS#2710739)
#if TARGET_OS_OSX // [TODO(macOS ISS#2323203) #if TARGET_OS_OSX // [TODO(macOS ISS#2323203)
NSTrackingArea *_trackingArea; NSTrackingArea *_trackingArea;
BOOL _hasMouseOver; BOOL _hasMouseOver;
@ -116,6 +118,16 @@ static NSString *RCTRecursiveAccessibilityLabel(RCTUIView *view) // TODO(macOS I
NSMutableDictionary<NSString *, NSDictionary *> *accessibilityActionsLabelMap; NSMutableDictionary<NSString *, NSDictionary *> *accessibilityActionsLabelMap;
} }
// [TODO(OSS Candidate ISS#2710739)
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
{
if ((self = [self initWithFrame:CGRectZero])) {
_eventDispatcher = eventDispatcher;
}
return self;
}
// ]TODO(OSS Candidate ISS#2710739)
- (instancetype)initWithFrame:(CGRect)frame - (instancetype)initWithFrame:(CGRect)frame
{ {
if ((self = [super initWithFrame:frame])) { if ((self = [super initWithFrame:frame])) {
@ -710,21 +722,20 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:unused)
} }
// If we've gained focus, notify listeners // If we've gained focus, notify listeners
if (self.onFocus != nil ) { [_eventDispatcher sendEvent:[RCTFocusChangeEvent focusEventWithReactTag:self.reactTag]];
self.onFocus(nil);
}
return YES; return YES;
} }
- (BOOL)resignFirstResponder - (BOOL)resignFirstResponder
{ {
if (![super resignFirstResponder]) { if (![super resignFirstResponder]) {
return NO; return NO;
} }
// If we've gained focus, notify listeners // If we've lost focus, notify listeners
if (self.onBlur != nil ) { [_eventDispatcher sendEvent:[RCTFocusChangeEvent blurEventWithReactTag:self.reactTag]];
self.onBlur(nil);
}
return YES; return YES;
} }

Просмотреть файл

@ -89,7 +89,7 @@ RCT_EXPORT_MODULE()
#if TARGET_OS_TV #if TARGET_OS_TV
return [RCTTVView new]; return [RCTTVView new];
#else #else
return [RCTView new]; return [[RCTView alloc] initWithEventDispatcher:self.bridge.eventDispatcher]; // TODO(OSS Candidate ISS#2710739)
#endif #endif
} }