Skip to content

Commit d0bd5ec

Browse files
amgleitmanAdam Gleitman
andauthored
[0.74-stable] Send JS blur/focus events when switching to another NSWindow (#2362)
* Send JS blur/focus events when switching to another NSWindow * Enable searching through a view's parents for a React tag to call blur/focus on --------- Co-authored-by: Adam Gleitman <adgleitm@microsoft.com>
1 parent 713e4d2 commit d0bd5ec

File tree

1 file changed

+58
-0
lines changed

1 file changed

+58
-0
lines changed

packages/react-native/React/Base/RCTRootView.m

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#import "RCTBridge.h"
1717
#import "RCTConstants.h"
1818
#import "RCTDevSettings.h" // [macOS]
19+
#import "RCTFocusChangeEvent.h" // [macOS]
1920
// [macOS] remove #import "RCTKeyCommands.h"
2021
#import "RCTLog.h"
2122
#import "RCTPerformanceLogger.h"
@@ -438,6 +439,63 @@ - (void)viewDidChangeEffectiveAppearance
438439
#endif // macOS]
439440

440441

442+
#pragma mark - Key window blur/focus
443+
444+
#if TARGET_OS_OSX // [macOS
445+
- (void)viewDidMoveToWindow {
446+
[super viewDidMoveToWindow];
447+
448+
NSWindow *window = [self window];
449+
if (window == nil) {
450+
return;
451+
}
452+
453+
[[NSNotificationCenter defaultCenter] addObserver:self
454+
selector:@selector(containingWindowDidBecomeKey)
455+
name:NSWindowDidBecomeKeyNotification
456+
object:window];
457+
458+
[[NSNotificationCenter defaultCenter] addObserver:self
459+
selector:@selector(containingWindowDidResignKey)
460+
name:NSWindowDidResignKeyNotification
461+
object:window];
462+
}
463+
464+
+ (NSNumber *)reactTagClosestToView:(RCTPlatformView *)view {
465+
// The first responder may not necessarily have a React tag. For example, if we're focused on
466+
// a multiline <TextInput>, the RN component whose blur/focus events we need to touch is an
467+
// RCTMultilineTextInputView, but the first responder will be the underlying RCTUITextView.
468+
for (RCTPlatformView *testView = view; testView != nil; testView = [testView superview]) {
469+
NSNumber *reactTag = [testView reactTag];
470+
if (reactTag != nil) {
471+
return reactTag;
472+
}
473+
}
474+
return nil;
475+
}
476+
477+
- (void)containingWindowDidBecomeKey {
478+
NSResponder *firstResponder = [[self window] firstResponder];
479+
if ([firstResponder isKindOfClass:[RCTPlatformView class]]) {
480+
NSNumber *reactTag = [RCTRootView reactTagClosestToView:(RCTPlatformView *)firstResponder];
481+
if (reactTag != nil) {
482+
[[[self bridge] eventDispatcher] sendEvent:[RCTFocusChangeEvent focusEventWithReactTag:reactTag]];
483+
}
484+
}
485+
}
486+
487+
- (void)containingWindowDidResignKey {
488+
NSResponder *firstResponder = [[self window] firstResponder];
489+
if ([firstResponder isKindOfClass:[RCTPlatformView class]]) {
490+
NSNumber *reactTag = [RCTRootView reactTagClosestToView:(RCTPlatformView *)firstResponder];
491+
if (reactTag != nil) {
492+
[[[self bridge] eventDispatcher] sendEvent:[RCTFocusChangeEvent blurEventWithReactTag:reactTag]];
493+
}
494+
}
495+
}
496+
#endif // macOS]
497+
498+
441499
#if TARGET_OS_OSX // [macOS
442500
- (NSMenu *)menuForEvent:(NSEvent *)event
443501
{

0 commit comments

Comments
 (0)