|
16 | 16 | #import "RCTBridge.h" |
17 | 17 | #import "RCTConstants.h" |
18 | 18 | #import "RCTDevSettings.h" // [macOS] |
| 19 | +#import "RCTFocusChangeEvent.h" // [macOS] |
19 | 20 | // [macOS] remove #import "RCTKeyCommands.h" |
20 | 21 | #import "RCTLog.h" |
21 | 22 | #import "RCTPerformanceLogger.h" |
@@ -438,6 +439,63 @@ - (void)viewDidChangeEffectiveAppearance |
438 | 439 | #endif // macOS] |
439 | 440 |
|
440 | 441 |
|
| 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 | + |
441 | 499 | #if TARGET_OS_OSX // [macOS |
442 | 500 | - (NSMenu *)menuForEvent:(NSEvent *)event |
443 | 501 | { |
|
0 commit comments