diff --git a/pkgs/dartpad_ui/lib/blur.dart b/pkgs/dartpad_ui/lib/blur.dart new file mode 100644 index 000000000..f819401a4 --- /dev/null +++ b/pkgs/dartpad_ui/lib/blur.dart @@ -0,0 +1,30 @@ +// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import 'dart:js_interop'; + +import 'package:web/web.dart'; + +const _flutterViewSelector = 'flutter-view'; + +void addBlurListener() { + window.addEventListener('blur', _onBlur.toJS); +} + +void removeBlurListener() { + window.removeEventListener('blur', _onBlur.toJS); +} + +void _onBlur(Event _) { + print('onBlur'); + final activeElement = document.activeElement as HTMLElement?; + if (activeElement == null) return; + // Only call blur on elements that are within a Flutter view. + final inFlutterView = activeElement.closest(_flutterViewSelector) != null; + print('inFlutterView = $inFlutterView'); + if (inFlutterView) { + print('activeElement = $activeElement'); + activeElement.blur(); + } +} \ No newline at end of file diff --git a/pkgs/dartpad_ui/lib/main.dart b/pkgs/dartpad_ui/lib/main.dart index 807b46079..a13ddbabd 100644 --- a/pkgs/dartpad_ui/lib/main.dart +++ b/pkgs/dartpad_ui/lib/main.dart @@ -16,6 +16,7 @@ import 'package:split_view/split_view.dart'; import 'package:url_launcher/url_launcher.dart' as url_launcher; import 'package:vtable/vtable.dart'; +import 'blur.dart'; import 'console.dart'; import 'embed/embed.dart'; import 'enable_gen_ai.dart'; @@ -326,7 +327,9 @@ class DartPadMainPageState extends State if (widget.runOnLoad) { appServices.performCompileAndRun(); } - }), + }).then((_) { + addBlurListener(); + }), ]); initialized.complete(); diff --git a/pkgs/dartpad_ui/web/frame.js b/pkgs/dartpad_ui/web/frame.js index fc0fab9f3..597234301 100644 --- a/pkgs/dartpad_ui/web/frame.js +++ b/pkgs/dartpad_ui/web/frame.js @@ -65,3 +65,34 @@ window.addEventListener('load', function () { window.addEventListener('message', messageHandler, false); parent.postMessage({ 'sender': 'frame', 'type': 'ready' }, '*'); }); + +window.addEventListener('blur', onBlurHandler); + +// Blur listener +const flutterViewSelector = 'flutter-view'; +function onBlurHandler(event) { + console.log('onBlur'); + const activeElement = document.activeElement; + if (!activeElement) { + return; + } + if (!(activeElement instanceof HTMLElement) || typeof activeElement.closest !== 'function') { + return; + } + const inFlutterView = activeElement.closest(flutterViewSelector) !== null; + console.log(`JS inFlutterView = ${inFlutterView}`); + + if (inFlutterView) { + console.log('JS activeElement = ', activeElement); + activeElement.blur(); + } +} + +function addBlurListener() { + window.addEventListener('blur', onBlurHandler); + console.log('JS Blur listener added.'); +} +function removeBlurListener() { + window.removeEventListener('blur', onBlurHandler); + console.log('JS Blur listener removed.'); +} \ No newline at end of file