Skip to content

Commit 83bd3c1

Browse files
authored
fix: missing unfocus event on iOS Fabric (#799)
## 📜 Description Fixed a problem when input looses a focus, but `FocusedInputObserver` doesn't send `noFocusedInputEvent` to JS. ## 💡 Motivation and Context The problem was introduced in this PR #760 before we were relying on keyboard evens, but in #760 I re-worked the approach and started to use blur/focus events. However I couldn't use only input events, because on iOS 15 keyboard event (`keyboardWillShow`) was arriving earlier than focus event, and for us it's crucial to know the layout of focused input inside `onStart` (i. e. before keyboard movement starts). I decided to keep backward compatibility and keep keyboard events in place. However it comes with own set of challenges. For example: <img width="829" alt="image" src="https://github.com/user-attachments/assets/0b718794-39a7-4f45-a089-04d92d9a7688" /> This check works well for Paper, but doesn't work for Fabric. And for focus events we can keep two event sources, because logic for focus is simple -> "we got a focus -> save the state and push event to JS". For blur it's different: - keyboard can be closed but focus still can be present; - when we switch between inputs we also receive `blur` event but we should ignore it; - we may have a random order of events including some missing events. Initially I don't know how to fix it. But then I realized, that on Android we already have a similar situation. We can looses a focus and keyboard will be focus, we can have a focus and close a keyboard, so overall it's a very similar to what we can have on iOS right now. But why I don't experience any problems on Android? Because I just rely on "focus"/"blur" events there (and actually relying on `keyboardWillShow` on iOS is needed to have a stable order of events in JS). So at this point of time I thought "what if I remove `keyboardWillHide` handler?". Yes, it will not work as before (some events may be delayed), but for dismissing keyboard it's not so important at the moment (because on Android we can also have any order of those events). So after thinking a lot I decided that it can be safe to remove that handler completely and reduce logic complexity presented in this class. Closes #798 ## 📢 Changelog <!-- High level overview of important changes --> <!-- For example: fixed status bar manipulation; added new types declarations; --> <!-- If your changes don't affect one of platform/language below - then remove this platform/language --> ### iOS - rely on `blur` event only for sending `noFocusedInputEvent` (remove `keyboardWillHide` event); - check in `blur` event `UIResponder.current` presence instead of `self.currentResponder`. ## 🤔 How Has This Been Tested? Tested manually on iPhone 15 Pro iOS 17.5 ## 📸 Screenshots (if appropriate): https://github.com/user-attachments/assets/471afd00-9fdb-4fca-b159-985203baab1d ## 📝 Checklist - [x] CI successfully passed - [x] I added new mocks and corresponding unit-tests if library API was changed
1 parent 76ab331 commit 83bd3c1

File tree

1 file changed

+1
-24
lines changed

1 file changed

+1
-24
lines changed

ios/observers/FocusedInputObserver.swift

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,6 @@ public class FocusedInputObserver: NSObject {
8080
name: UIResponder.keyboardWillShowNotification,
8181
object: nil
8282
)
83-
NotificationCenter.default.addObserver(
84-
self,
85-
selector: #selector(keyboardWillHide),
86-
name: UIResponder.keyboardWillHideNotification,
87-
object: nil
88-
)
8983
NotificationCenter.default.addObserver(
9084
self,
9185
selector: #selector(didReceiveFocus),
@@ -118,10 +112,6 @@ public class FocusedInputObserver: NSObject {
118112
NotificationCenter.default.removeObserver(self)
119113
}
120114

121-
@objc func keyboardWillHide(_: Notification) {
122-
onBlur()
123-
}
124-
125115
@objc func didReceiveFocus(_: Notification) {
126116
if UIResponder.current == currentResponder {
127117
// focus was already handled by keyboard event
@@ -131,22 +121,13 @@ public class FocusedInputObserver: NSObject {
131121
onFocus()
132122
}
133123

134-
/**
135-
* We handle blur events in `keyboardWillHide` handler
136-
* And this additional handler is needed only to have
137-
* a consistent state when keyboard is not shown
138-
*/
139124
@objc func didReceiveBlur(_: Notification) {
140-
if currentResponder == nil {
141-
// blur was already handled by keyboard event
142-
return
143-
}
144125
// blur gets triggered on endEditing, so we check if no upcoming
145126
// didReceiveFocus events are coming to exclude `noFocusedInput`
146127
// event when user switches between inputs
147128
DispatchQueue.main.async {
148129
// check that it wasn't a switch between inputs
149-
if self.currentResponder == nil {
130+
if !(UIResponder.current is TextInput) {
150131
self.onBlur()
151132
}
152133
}
@@ -173,10 +154,6 @@ public class FocusedInputObserver: NSObject {
173154
}
174155

175156
func onBlur() {
176-
// when we switch to next input, but `showSoftInput={false}`
177-
if UIResponder.current is TextInput {
178-
return
179-
}
180157
removeObservers(newResponder: nil)
181158
currentInput = nil
182159
currentResponder = nil

0 commit comments

Comments
 (0)