From c6b0ada2c3d42e5e0adec9abfc864a0a71b6e78a Mon Sep 17 00:00:00 2001 From: "b.kotov" Date: Wed, 11 Mar 2026 13:02:35 +0300 Subject: [PATCH 1/4] feat: Add support for going to the beginning of a block --- packages/blockly/core/workspace_svg.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/blockly/core/workspace_svg.ts b/packages/blockly/core/workspace_svg.ts index c693225970f..59a1402b932 100644 --- a/packages/blockly/core/workspace_svg.ts +++ b/packages/blockly/core/workspace_svg.ts @@ -1987,8 +1987,9 @@ export class WorkspaceSvg * * @param id ID of block center on. * @param blockOnly True to center only on the block itself, not its stack. + * @param centerOnBlockStart It is correct to center only on the block itself at its beginning. */ - centerOnBlock(id: string | null, blockOnly?: boolean) { + centerOnBlock(id: string | null, blockOnly?: boolean, centerOnBlockStart?: boolean) { if (!this.isMovable()) { console.warn( 'Tried to move a non-movable workspace. This could result' + @@ -2010,7 +2011,9 @@ export class WorkspaceSvg : block.getHeightWidth(); // Find the enter of the block in workspace units. - const blockCenterY = xy.y + heightWidth.height / 2; + const blockCenterY = centerOnBlockStart + ? xy.y + : xy.y + heightWidth.height / 2; // In RTL the block's position is the top right of the block, not top left. const multiplier = this.RTL ? -1 : 1; From 283f505e31c865ce4fb82edc0e80b43ebc7876a1 Mon Sep 17 00:00:00 2001 From: "b.kotov" Date: Thu, 19 Mar 2026 12:29:09 +0300 Subject: [PATCH 2/4] feat: Add check is block fully in bounds (#9628) --- packages/blockly/core/block_svg.ts | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/packages/blockly/core/block_svg.ts b/packages/blockly/core/block_svg.ts index b5935297b8b..d1e75fa5f33 100644 --- a/packages/blockly/core/block_svg.ts +++ b/packages/blockly/core/block_svg.ts @@ -1819,6 +1819,36 @@ export class BlockSvg return this.dragStrategy.isMovable(); } + /** Returns whether the block fully fits within the boundaries of the workspace */ + isBlockFullyInBounds(): boolean { + let blockLeft; + let blockRight; + const {left, top, width, height} = this.workspace + .getMetricsManager() + .getViewMetrics(true); + + const xy = this.getRelativeToSurfaceXY(); + const {width: blockWidth, height: blockHeight} = this.getHeightWidth(); + + if (this.RTL) { + blockLeft = xy.x - blockWidth; + blockRight = xy.x; + } else { + blockLeft = xy.x; + blockRight = xy.x + blockWidth; + } + + const blockTop = xy.y; + const blockBottom = xy.y + blockHeight; + + return ( + blockLeft >= left && + blockRight <= left + width && + blockTop >= top && + blockBottom <= top + height + ); + } + /** Starts a drag on the block. */ startDrag(e?: PointerEvent): void { this.dragStrategy.startDrag(e); From 28c9d369e85cad435323cfdce3d74155a35817d0 Mon Sep 17 00:00:00 2001 From: "b.kotov" Date: Thu, 19 Mar 2026 12:30:24 +0300 Subject: [PATCH 3/4] chore: Update the centering on the block by checking the block position (#9628) --- packages/blockly/core/workspace_svg.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/blockly/core/workspace_svg.ts b/packages/blockly/core/workspace_svg.ts index 59a1402b932..b7a422ddb3b 100644 --- a/packages/blockly/core/workspace_svg.ts +++ b/packages/blockly/core/workspace_svg.ts @@ -1987,9 +1987,8 @@ export class WorkspaceSvg * * @param id ID of block center on. * @param blockOnly True to center only on the block itself, not its stack. - * @param centerOnBlockStart It is correct to center only on the block itself at its beginning. */ - centerOnBlock(id: string | null, blockOnly?: boolean, centerOnBlockStart?: boolean) { + centerOnBlock(id: string | null, blockOnly?: boolean) { if (!this.isMovable()) { console.warn( 'Tried to move a non-movable workspace. This could result' + @@ -2011,9 +2010,9 @@ export class WorkspaceSvg : block.getHeightWidth(); // Find the enter of the block in workspace units. - const blockCenterY = centerOnBlockStart - ? xy.y - : xy.y + heightWidth.height / 2; + const blockCenterY = block.isBlockFullyInBounds() + ? xy.y + heightWidth.height / 2 + : xy.y; // In RTL the block's position is the top right of the block, not top left. const multiplier = this.RTL ? -1 : 1; From afb67abdc825400637960c1643305c194415f811 Mon Sep 17 00:00:00 2001 From: "b.kotov" Date: Thu, 19 Mar 2026 12:31:19 +0300 Subject: [PATCH 4/4] chore: Add test centerOnBlock when block partially out of bounds (#9628) --- .../blockly/tests/mocha/workspace_svg_test.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/blockly/tests/mocha/workspace_svg_test.js b/packages/blockly/tests/mocha/workspace_svg_test.js index b40a46941bd..9ea0564e3fc 100644 --- a/packages/blockly/tests/mocha/workspace_svg_test.js +++ b/packages/blockly/tests/mocha/workspace_svg_test.js @@ -314,6 +314,21 @@ suite('WorkspaceSvg', function () { this.clock, ); }); + test('centerOnBlock when block partially out of bounds', function () { + const block = this.workspace.newBlock('stack_block'); + block.initSvg(); + block.render(); + + sinon.stub(block, 'getRelativeToSurfaceXY').returns({x: 10, y: 80}); + sinon.stub(block, 'getHeightWidth').returns({width: 40, height: 40}); + + runViewportEventTest( + () => this.workspace.centerOnBlock(block.id), + this.changeListenerSpy, + this.workspace, + this.clock, + ); + }); }); suite('Blocks triggering viewport changes', function () { test('block move that triggers scroll', function () {