Skip to content

Commit 09c4072

Browse files
authored
Textfield focus issue workaround (#9091)
1 parent baeb606 commit 09c4072

File tree

9 files changed

+71
-63
lines changed

9 files changed

+71
-63
lines changed

packages/devtools_app/lib/src/app.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import 'shared/primitives/query_parameters.dart';
5858
import 'shared/primitives/utils.dart';
5959
import 'shared/ui/common_widgets.dart';
6060
import 'shared/ui/hover.dart';
61+
import 'shared/utils/focus_utils.dart';
6162
import 'shared/utils/utils.dart';
6263
import 'standalone_ui/standalone_screen.dart';
6364

@@ -188,11 +189,16 @@ class DevToolsAppState extends State<DevToolsApp> with AutoDisposeMixin {
188189
addAutoDisposeListener(preferences.darkModeEnabled);
189190

190191
releaseNotesController = ReleaseNotesController();
192+
193+
// Workaround for https://github.com/flutter/flutter/issues/155265.
194+
setUpTextFieldFocusFixHandler();
191195
}
192196

193197
@override
194198
void dispose() {
195199
FrameworkCore.dispose();
200+
// Workaround for https://github.com/flutter/flutter/issues/155265.
201+
removeTextFieldFocusFixHandler();
196202
super.dispose();
197203
}
198204

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright 2025 The Flutter Authors
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
4+
5+
void addBlurListener() {
6+
// No-op for desktop platforms.
7+
}
8+
9+
void removeBlurListener() {
10+
// No-op for desktop platforms.
11+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2025 The Flutter Authors
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
4+
5+
import 'dart:js_interop';
6+
7+
import 'package:web/web.dart';
8+
9+
const _flutterViewSelector = 'flutter-view';
10+
11+
void addBlurListener() {
12+
window.addEventListener('blur', _onBlur.toJS);
13+
}
14+
15+
void removeBlurListener() {
16+
window.removeEventListener('blur', _onBlur.toJS);
17+
}
18+
19+
void _onBlur(Event _) {
20+
final activeElement = document.activeElement as HTMLElement?;
21+
if (activeElement == null) return;
22+
// Only call blur on elements that are within a Flutter view.
23+
final inFlutterView = activeElement.closest(_flutterViewSelector) != null;
24+
if (inFlutterView) {
25+
activeElement.blur();
26+
}
27+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2025 The Flutter Authors
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
4+
5+
import '_focus_utils_desktop.dart'
6+
if (dart.library.js_interop) '_focus_utils_web.dart';
7+
8+
/// Workaround to prevent TextFields from holding onto focus when IFRAME-ed.
9+
///
10+
/// See https://github.com/flutter/flutter/issues/155265 for details.
11+
void setUpTextFieldFocusFixHandler() {
12+
addBlurListener();
13+
}
14+
15+
/// Workaround to prevent TextFields from holding onto focus when IFRAME-ed.
16+
///
17+
/// See https://github.com/flutter/flutter/issues/155265 for details.
18+
void removeTextFieldFocusFixHandler() {
19+
removeBlurListener();
20+
}

packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/property_editor_view.dart

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -85,47 +85,25 @@ class PropertyEditorView extends StatelessWidget {
8585
}
8686
}
8787

88-
class _PropertiesList extends StatefulWidget {
88+
class _PropertiesList extends StatelessWidget {
8989
const _PropertiesList({required this.controller});
9090

9191
final PropertyEditorController controller;
9292

9393
static const defaultItemPadding = borderPadding;
9494
static const denseItemPadding = defaultItemPadding / 2;
9595

96-
@override
97-
State<_PropertiesList> createState() => _PropertiesListState();
98-
}
99-
100-
class _PropertiesListState extends State<_PropertiesList> {
101-
@override
102-
void initState() {
103-
super.initState();
104-
// Workaround for https://github.com/flutter/devtools/issues/8929.
105-
setUpTextFieldFocusFixHandler();
106-
}
107-
108-
@override
109-
void dispose() {
110-
super.dispose();
111-
// Workaround for https://github.com/flutter/devtools/issues/8929.
112-
removeTextFieldFocusFixHandler();
113-
}
114-
11596
@override
11697
Widget build(BuildContext context) {
11798
return ValueListenableBuilder(
118-
valueListenable: widget.controller.filteredData,
99+
valueListenable: controller.filteredData,
119100
builder: (context, properties, _) {
120101
return Column(
121102
children: <Widget>[
122-
_FilterControls(controller: widget.controller),
103+
_FilterControls(controller: controller),
123104
if (properties.isEmpty) const NoMatchingPropertiesMessage(),
124105
for (final property in properties)
125-
_EditablePropertyItem(
126-
property: property,
127-
controller: widget.controller,
128-
),
106+
_EditablePropertyItem(property: property, controller: controller),
129107
].joinWith(const PaddedDivider.noPadding()),
130108
);
131109
},

packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/utils/_utils_desktop.dart

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,3 @@
55
void reloadIframe() {
66
// No-op for desktop platforms.
77
}
8-
9-
void addBlurListener() {
10-
// No-op for desktop platforms.
11-
}
12-
13-
void removeBlurListener() {
14-
// No-op for desktop platforms.
15-
}

packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/utils/_utils_web.dart

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,8 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
44

5-
import 'dart:js_interop';
6-
75
import 'package:web/web.dart';
86

97
void reloadIframe() {
108
window.location.reload();
119
}
12-
13-
void addBlurListener() {
14-
window.addEventListener('blur', _onBlur.toJS);
15-
}
16-
17-
void removeBlurListener() {
18-
window.removeEventListener('blur', _onBlur.toJS);
19-
}
20-
21-
void _onBlur(Event _) {
22-
final inputElement = document.activeElement as HTMLElement?;
23-
inputElement?.blur();
24-
}

packages/devtools_app/lib/src/standalone_ui/ide_shared/property_editor/utils/utils.dart

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -141,17 +141,3 @@ class DartDocConverter {
141141
void forceReload() {
142142
reloadIframe();
143143
}
144-
145-
/// Workaround to prevent TextFields from holding onto focus when IFRAME-ed.
146-
///
147-
/// See https://github.com/flutter/devtools/issues/8929 for details.
148-
void setUpTextFieldFocusFixHandler() {
149-
addBlurListener();
150-
}
151-
152-
/// Workaround to prevent TextFields from holding onto focus when IFRAME-ed.
153-
///
154-
/// See https://github.com/flutter/devtools/issues/8929 for details.
155-
void removeTextFieldFocusFixHandler() {
156-
removeBlurListener();
157-
}

packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ DevTools in order to avoid an OOM crash. -
4343
pausing on breakpoint on connection. -
4444
[#8991](https://github.com/flutter/devtools/pull/8991)
4545

46+
* Prevented text inputs from stealing focus from the IDE. -
47+
[#9091](https://github.com/flutter/devtools/pull/9091)
48+
4649
## Inspector updates
4750

4851
* Fixed bug where errors in the inspector tree (e.g. RenderFlex overflow

0 commit comments

Comments
 (0)