-
Notifications
You must be signed in to change notification settings - Fork 285
Description
SuperEditor internally contains a widget called SuperEditorImeInteractor. This interactor holds the current IME connection in a State property:
final _imeConnection = ValueNotifier<TextInputConnection?>(null);As a result, if this part of the widget tree is recreated, we lose the existing text input connection and then create a new one.
Why would this widget be recreated?
Any ancestor widget that's added or removed in the tree will result in a full subtree recreation, including this widget.
Can we avoid subtree recreation?
Carefully placed GlobalKeys can prevent subtree recreation, however, it's not clear where exactly those GlobalKeys need to be placed. It will be easy to get that wrong and end up with unexpected keyboard behaviors. It would be better to interact with the IME in a way that's not susceptible to widget recreation.
Why does recreation matter?
There might be any number of unexpected behaviors, but here's one that's happening for sure:
- Deploy a bottom mounted chat experience
- Tap the editor to give focus and open the keyboard
- Open a panel that replaces the keyboard
- In the IDE, add or remove any ancestor widget above the editor and run hot reload
- The panel stays open, but the keyboard pops back up, seemingly for no reason, on top of the panel.
The cause of this issue is that the interactor widget with the original IME connection is disposed, at which point it not only loses the IME connection property, but even tells the IME connection to close. The new IME interactor widget that's replacing the old one has an addPostFrameCallback in its initState, which then opens a new IME connection because the SoftwareKeyboardController still exists and it says we want an open IME connection.
How do we solve this?
If we're not going to rely on GlobalKeys to keep the interactor widget around across rebuilds then I see two options:
- Require a
ValueNotifier<IMEConnection>or a similar controller to be passed into everySuperEditorwidget. We can't allow it to be created insideSuperEditorbecause then we suffer the same fate whenSuperEditoris recreated. - Create a global shared IME connection that's never created or destroyed via widget rebuilds.
SuperEditorand its internal widgets would need to know when and how to take ownership of this shared connection, including when oneSuperEditoris being initialized, to replaced anotherSuperEditorthat's being disposed.