diff --git a/core/flyout_base.ts b/core/flyout_base.ts index 492d3341762..edfea767204 100644 --- a/core/flyout_base.ts +++ b/core/flyout_base.ts @@ -22,6 +22,7 @@ import {FlyoutItem} from './flyout_item.js'; import {FlyoutMetricsManager} from './flyout_metrics_manager.js'; import {FlyoutNavigator} from './flyout_navigator.js'; import {FlyoutSeparator, SeparatorAxis} from './flyout_separator.js'; +import { getFocusManager } from './focus_manager.js'; import {IAutoHideable} from './interfaces/i_autohideable.js'; import type {IFlyout} from './interfaces/i_flyout.js'; import type {IFlyoutInflater} from './interfaces/i_flyout_inflater.js'; @@ -615,6 +616,10 @@ export abstract class Flyout * toolbox definition, or a string with the name of the dynamic category. */ show(flyoutDef: toolbox.FlyoutDefinition | string) { + const previouslyFocusedNode = getFocusManager().getFocusedNode(); + const hadFocusedItem = + this.getContents().some( + (item) => item.getElement() === previouslyFocusedNode); this.workspace_.setResizesEnabled(false); this.hide(); this.clearOldBlocks(); @@ -655,6 +660,14 @@ export abstract class Flyout } }; this.workspace_.addChangeListener(this.reflowWrapper); + + // It's difficult to restore the actual element that was focused since + // everything gets recreated (and it may no longer exist). Instead, if the + // flyout previously held focus then force it to focus the first element. + const contents = this.getContents(); + if (hadFocusedItem && contents.length > 0) { + getFocusManager().focusNode(contents[0].getElement()); + } } /** diff --git a/core/variables.ts b/core/variables.ts index f75d673903b..5cc15adb1d9 100644 --- a/core/variables.ts +++ b/core/variables.ts @@ -9,6 +9,7 @@ import type {Block} from './block.js'; import {Blocks} from './blocks.js'; import * as dialog from './dialog.js'; +import { getFocusManager } from './focus_manager.js'; import {isLegacyProcedureDefBlock} from './interfaces/i_legacy_procedure_blocks.js'; import {isVariableBackedParameterModel} from './interfaces/i_variable_backed_parameter_model.js'; import {IVariableModel, IVariableState} from './interfaces/i_variable_model.js'; @@ -519,6 +520,8 @@ export function promptName( defaultText: string, callback: (p1: string | null) => void, ) { + const returnEphemeralFocus = + getFocusManager().takeEphemeralFocus(document.body); dialog.prompt(promptText, defaultText, function (newVar) { // Merge runs of whitespace. Strip leading and trailing whitespace. // Beyond this, all names are legal. @@ -529,6 +532,7 @@ export function promptName( newVar = null; } } + returnEphemeralFocus(); callback(newVar); }); } diff --git a/core/workspace_svg.ts b/core/workspace_svg.ts index 3033eacd74f..df8c41928b6 100644 --- a/core/workspace_svg.ts +++ b/core/workspace_svg.ts @@ -2859,8 +2859,9 @@ export class WorkspaceSvg 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); + // TODO: Figure out how to fix this. + // if (toolbox) toolbox.clearSelection(); + // if (flyout && isAutoHideable(flyout)) flyout.autoHide(false); } }