diff --git a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/common/text_field.dart b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/common/text_field.dart index 50d264512d..895b3a8ee1 100644 --- a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/common/text_field.dart +++ b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/common/text_field.dart @@ -13,6 +13,7 @@ class InputTextField extends StatefulWidget { final bool autoClearWhenDone; final String text; final int? maxLength; + final FocusNode? focusNode; const InputTextField({ required this.text, @@ -21,6 +22,7 @@ class InputTextField extends StatefulWidget { this.onChanged, this.autoClearWhenDone = false, this.maxLength, + this.focusNode, Key? key, }) : super(key: key); @@ -35,7 +37,7 @@ class _InputTextFieldState extends State { @override void initState() { - _focusNode = FocusNode(); + _focusNode = widget.focusNode ?? FocusNode(); _controller = TextEditingController(text: widget.text); SchedulerBinding.instance.addPostFrameCallback((Duration _) { _focusNode.requestFocus(); @@ -81,7 +83,10 @@ class _InputTextFieldState extends State { @override void dispose() { _focusNode.removeListener(notifyDidEndEditing); - _focusNode.dispose(); + // only dispose the focusNode if it was created in this widget's initState + if (widget.focusNode == null) { + _focusNode.dispose(); + } super.dispose(); } diff --git a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/select_option.dart b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/select_option.dart index ee35d208f9..7463509e02 100644 --- a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/select_option.dart +++ b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/select_option.dart @@ -45,9 +45,11 @@ class SelectOptionTypeOptionWidget extends StatelessWidget { const TypeOptionSeparator(), const OptionTitle(), if (state.isEditingOption) - const Padding( - padding: EdgeInsets.only(bottom: 10), - child: _CreateOptionTextField(), + Padding( + padding: const EdgeInsets.only(bottom: 10), + child: _CreateOptionTextField( + popoverMutex: popoverMutex, + ), ), if (state.options.isEmpty && !state.isEditingOption) const _AddOptionButton(), @@ -251,8 +253,35 @@ class _AddOptionButton extends StatelessWidget { } } -class _CreateOptionTextField extends StatelessWidget { - const _CreateOptionTextField({Key? key}) : super(key: key); +class _CreateOptionTextField extends StatefulWidget { + final PopoverMutex? popoverMutex; + const _CreateOptionTextField({ + Key? key, + this.popoverMutex, + }) : super(key: key); + + @override + State<_CreateOptionTextField> createState() => _CreateOptionTextFieldState(); +} + +class _CreateOptionTextFieldState extends State<_CreateOptionTextField> { + late final FocusNode _focusNode; + + @override + void initState() { + _focusNode = FocusNode(); + _focusNode.addListener(() { + if (_focusNode.hasFocus) { + widget.popoverMutex?.close(); + } + }); + widget.popoverMutex?.listenOnPopoverChanged(() { + if (_focusNode.hasFocus) { + _focusNode.unfocus(); + } + }); + super.initState(); + } @override Widget build(BuildContext context) { @@ -263,6 +292,7 @@ class _CreateOptionTextField extends StatelessWidget { autoClearWhenDone: true, maxLength: 30, text: text, + focusNode: _focusNode, onCanceled: () { context .read()