From 81527c131a382bf0407a9746d019d9842150a8ef Mon Sep 17 00:00:00 2001 From: Nick Lefever Date: Fri, 25 Aug 2023 21:50:46 +0200 Subject: [PATCH 1/3] [fabric] Make text input first responder through the window instance Summary: Fix AppKit exception throws when focusing text inputs by calling becomeFirstResponder directly on the backing text input view. Making a view first responder has to happen through the window using makeFirstResponder. Test Plan: - Run Zeratul with Fabric - Focus the search text input above the message threads - Click inside the active message thread to trigger the auto-focus of the composer - The composer gets focus without AppKit throwing an exception. https://pxl.cl/3dVMx Reviewers: shawndempsey, #rn-desktop Reviewed By: shawndempsey Differential Revision: https://phabricator.intern.facebook.com/D48696690 --- .../ComponentViews/TextInput/RCTTextInputComponentView.mm | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index 876344c26054bd..f1930cfb0ed7eb 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -528,7 +528,14 @@ - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args - (void)focus { +#if !TARGET_OS_OSX // [macOS] [_backedTextInputView becomeFirstResponder]; +#else // [macOS + NSWindow *window = _backedTextInputView.window; + if (window) { + [window makeFirstResponder:_backedTextInputView]; + } +#endif // macOS] const auto &props = static_cast(*_props); From edbec15c0f9f3f6de44383e129a52ac9f62319cd Mon Sep 17 00:00:00 2001 From: Nick Lefever Date: Thu, 26 Oct 2023 19:25:27 +0200 Subject: [PATCH 2/3] [fabric] Make text input resign first responder through the window instance Summary: Fix AppKit exception throws when blurring text inputs by calling `resignFirstResponder` directly on the backing text input view. Resigning the first responder state has to happen through the window by calling `[window makeFirstResponder:nil]` which will: - call `resignFirstResponder` on the current first responder - if successful, the window will become the first responder Test Plan: - Run Zeratul with Fabric - Focus the search text input above the message threads - Click inside the active message thread to trigger the auto-focus of the composer and the blur on the search field - The focused field resigns the first responder status without throwing an exception https://pxl.cl/3GvZD Reviewers: shawndempsey, #rn-desktop Reviewed By: shawndempsey Differential Revision: https://phabricator.intern.facebook.com/D50700782 --- .../ComponentViews/TextInput/RCTTextInputComponentView.mm | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index f1930cfb0ed7eb..4aafb8c88cb954 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -552,7 +552,15 @@ - (void)focus - (void)blur { +#if !TARGET_OS_OSX // [macOS] [_backedTextInputView resignFirstResponder]; +#else // [macOS + NSWindow *window = _backedTextInputView.window; + if (window && window.firstResponder == _backedTextInputView) { + // Calling makeFirstResponder with nil will call resignFirstResponder and make the window the first responder + [window makeFirstResponder:nil]; + } +#endif // macOS]; } - (void)setTextAndSelection:(NSInteger)eventCount From 78467d279c018973ab9b130bfe8f7e44120bf815 Mon Sep 17 00:00:00 2001 From: Saad Najmi Date: Wed, 20 Nov 2024 10:06:55 -0800 Subject: [PATCH 3/3] style(fabric, textinput): don't nil check the window before calling focus / blur --- .../TextInput/RCTTextInputComponentView.mm | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index 4aafb8c88cb954..83cfeb779dfc8e 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -531,10 +531,8 @@ - (void)focus #if !TARGET_OS_OSX // [macOS] [_backedTextInputView becomeFirstResponder]; #else // [macOS - NSWindow *window = _backedTextInputView.window; - if (window) { - [window makeFirstResponder:_backedTextInputView]; - } + NSWindow *window = [_backedTextInputView window]; + [window makeFirstResponder:_backedTextInputView]; #endif // macOS] const auto &props = static_cast(*_props); @@ -555,12 +553,11 @@ - (void)blur #if !TARGET_OS_OSX // [macOS] [_backedTextInputView resignFirstResponder]; #else // [macOS - NSWindow *window = _backedTextInputView.window; - if (window && window.firstResponder == _backedTextInputView) { - // Calling makeFirstResponder with nil will call resignFirstResponder and make the window the first responder + NSWindow *window = [_backedTextInputView window]; + if ([window firstResponder] == _backedTextInputView) { [window makeFirstResponder:nil]; } -#endif // macOS]; +#endif // macOS] } - (void)setTextAndSelection:(NSInteger)eventCount