diff --git a/core/toolbox/toolbox.ts b/core/toolbox/toolbox.ts index 4979fdfa40f..f34034d3399 100644 --- a/core/toolbox/toolbox.ts +++ b/core/toolbox/toolbox.ts @@ -22,10 +22,7 @@ import '../events/events_toolbox_item_select.js'; import {EventType} from '../events/type.js'; import * as eventUtils from '../events/utils.js'; import {getFocusManager} from '../focus_manager.js'; -import { - isAutoHideable, - type IAutoHideable, -} from '../interfaces/i_autohideable.js'; +import {type IAutoHideable} from '../interfaces/i_autohideable.js'; import type {ICollapsibleToolboxItem} from '../interfaces/i_collapsible_toolbox_item.js'; import {isDeletable} from '../interfaces/i_deletable.js'; import type {IDraggable} from '../interfaces/i_draggable.js'; @@ -1150,10 +1147,7 @@ export class Toolbox // If navigating to anything other than the toolbox's flyout then clear the // selection so that the toolbox's flyout can automatically close. if (!nextTree || nextTree !== this.flyout?.getWorkspace()) { - this.clearSelection(); - if (this.flyout && isAutoHideable(this.flyout)) { - this.flyout.autoHide(false); - } + this.autoHide(false); } } } diff --git a/core/workspace_svg.ts b/core/workspace_svg.ts index b666dc97a5d..6c6b5930110 100644 --- a/core/workspace_svg.ts +++ b/core/workspace_svg.ts @@ -2908,11 +2908,9 @@ export class WorkspaceSvg // Only hide the flyout if the flyout's workspace is losing focus and that // focus isn't returning to the flyout itself, the toolbox, or ephemeral. if (getFocusManager().ephemeralFocusTaken()) return; - const flyout = this.targetWorkspace.getFlyout(); const toolbox = this.targetWorkspace.getToolbox(); if (toolbox && nextTree === toolbox) return; - if (toolbox) toolbox.clearSelection(); - if (flyout && isAutoHideable(flyout)) flyout.autoHide(false); + if (isAutoHideable(toolbox)) toolbox.autoHide(false); } } diff --git a/tests/mocha/toolbox_test.js b/tests/mocha/toolbox_test.js index f32319c6779..4e92cd28fd3 100644 --- a/tests/mocha/toolbox_test.js +++ b/tests/mocha/toolbox_test.js @@ -183,6 +183,57 @@ suite('Toolbox', function () { }); }); + suite('focus management', function () { + setup(function () { + this.toolbox = getInjectedToolbox(); + }); + teardown(function () { + this.toolbox.dispose(); + }); + + test('Losing focus hides autoclosing flyout', function () { + // Focus the toolbox and select a category to open the flyout. + const target = this.toolbox.HtmlDiv.querySelector( + '.blocklyToolboxCategory', + ); + Blockly.getFocusManager().focusNode(this.toolbox); + target.dispatchEvent( + new PointerEvent('pointerdown', { + target, + bubbles: true, + }), + ); + assert.isTrue(this.toolbox.getFlyout().isVisible()); + + // Focus the workspace to trigger the toolbox to close the flyout. + Blockly.getFocusManager().focusNode(this.toolbox.getWorkspace()); + assert.isFalse(this.toolbox.getFlyout().isVisible()); + }); + + test('Losing focus does not hide non-autoclosing flyout', function () { + // Make the toolbox's flyout non-autoclosing. + this.toolbox.getFlyout().setAutoClose(false); + + // Focus the toolbox and select a category to open the flyout. + const target = this.toolbox.HtmlDiv.querySelector( + '.blocklyToolboxCategory', + ); + Blockly.getFocusManager().focusNode(this.toolbox); + target.dispatchEvent( + new PointerEvent('pointerdown', { + target, + bubbles: true, + }), + ); + assert.isTrue(this.toolbox.getFlyout().isVisible()); + + // Focus the workspace; this should *not* trigger the toolbox to close the + // flyout, which should remain visible. + Blockly.getFocusManager().focusNode(this.toolbox.getWorkspace()); + assert.isTrue(this.toolbox.getFlyout().isVisible()); + }); + }); + suite('onClick_', function () { setup(function () { this.toolbox = getInjectedToolbox();