Skip to content

Comments

fix: Focus nearest neighbor when deleting a focused block#9599

Open
gonfunko wants to merge 2 commits intomainfrom
delete-focus
Open

fix: Focus nearest neighbor when deleting a focused block#9599
gonfunko wants to merge 2 commits intomainfrom
delete-focus

Conversation

@gonfunko
Copy link
Contributor

The basics

The details

Resolves

Fixes #9585

Proposed Changes

This PR adjusts the focus behavior when a focused block is deleted. Previously, deleting a focused block would focus the workspace, which would in turn focus the first (left/topmost) block on the workspace. This could cause large jumps in scroll position. Now, when a focused block is deleted, it moves focus to the closest remaining block, resulting in a smaller (or no) workspace movement.

The tests were partially LLM-generated in response to a list of testcases I specified. I reviewed, modified them, and manually added an additional testcase.

@gonfunko gonfunko requested a review from a team as a code owner February 24, 2026 22:28
@gonfunko gonfunko requested a review from BenHenning February 24, 2026 22:28
@github-actions github-actions bot added the PR: fix Fixes a bug label Feb 24, 2026
Copy link
Collaborator

@BenHenning BenHenning left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @gonfunko! Largely LGTM but had a few thoughts--PTAL.

setTimeout(() => focusManager.focusTree(this.workspace), 0);
const nearestNeighbour = this.getNearestNeighbour();
if (nearestNeighbour) {
setTimeout(() => focusManager.focusNode(nearestNeighbour), 0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any case where there may be a sequence of deletions such that this triggers an attempt to focus the next closest node before it's deleted? Might be worth adding a test case to see if that's actually possible and, if so, make this a bit more robust against that.

const block = this.workspace.getTopBlocks(false)[0];
Blockly.getFocusManager().focusNode(block);
block.dispose();
this.clock.runAll();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually needed here & below?

}

Blockly.getFocusManager().focusNode(
this.workspace.getTopBlocks(false)[0],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This relates to my other comment: perhaps double check that the nearest neighbor is still actually doing what it seems like and selecting and trying to focus a block before it's disposed. It may be the case that something else (maybe the focus system or another part of disposal) is robust against this failure case.

});

test('Bulk deleting blocks does not focus another dying block', function () {
for (let i = 0; i < 50; i++) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idea can probably be tested with fewer blocks (for perforamnce). Maybe just have something like 5?

b.dispose();
this.clock.runAll();

assert.equal(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here & elsewhere: I suggest using strictEqual instead since there can be problems with the deep equal for connected blocks (circular references are possible), and it shouldn't actually be necessary for verifying focus.

@BenHenning BenHenning assigned gonfunko and unassigned BenHenning Feb 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

PR: fix Fixes a bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Deleting a top-level selected block scrolls the workspace to the top left

2 participants