fix: Make non-autoclosing flyouts stay open. (#9245)

* chore: Add tests for toolbox/flyout/focus autoclose behavior.

* fix: Don't force-close non-autoclosing flyouts.
This commit is contained in:
Aaron Dodson
2025-07-18 14:27:49 -07:00
committed by GitHub
parent 908712e19d
commit 3c7add57ee
3 changed files with 54 additions and 11 deletions

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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();