From c862b5ef0e1fe221096a19c4e2e5b4fd24853a12 Mon Sep 17 00:00:00 2001 From: Aaron Dodson Date: Wed, 18 Mar 2026 12:45:01 -0700 Subject: [PATCH] feat: Beep when attempting constrained move on top-level block (#9635) * feat: Beep when attempting constrained move on top-level block * chore: Remove errant `only` * refactor: Add and use `playErrorBeep()` --- packages/blockly/core/dragging/block_drag_strategy.ts | 1 + packages/blockly/core/workspace_audio.ts | 7 +++++++ packages/blockly/tests/mocha/keyboard_movement_test.js | 3 +++ 3 files changed, 11 insertions(+) diff --git a/packages/blockly/core/dragging/block_drag_strategy.ts b/packages/blockly/core/dragging/block_drag_strategy.ts index 39dff646e..b017eaf56 100644 --- a/packages/blockly/core/dragging/block_drag_strategy.ts +++ b/packages/blockly/core/dragging/block_drag_strategy.ts @@ -380,6 +380,7 @@ export class BlockDragStrategy implements IDragStrategy { if (this.moveMode === MoveMode.CONSTRAINED) { showUnconstrainedMoveHint(this.workspace, true); + this.workspace.getAudioManager().playErrorBeep(); } } } diff --git a/packages/blockly/core/workspace_audio.ts b/packages/blockly/core/workspace_audio.ts index 7d27277a0..66d555cd4 100644 --- a/packages/blockly/core/workspace_audio.ts +++ b/packages/blockly/core/workspace_audio.ts @@ -138,6 +138,13 @@ export class WorkspaceAudio { oscillator.stop(this.context.currentTime + duration); } + /** + * Plays a standard error beep. + */ + async playErrorBeep() { + return this.beep(260); + } + /** * Returns whether or not playing sounds is currently allowed. * diff --git a/packages/blockly/tests/mocha/keyboard_movement_test.js b/packages/blockly/tests/mocha/keyboard_movement_test.js index 9d6ac0cdd..8374699ea 100644 --- a/packages/blockly/tests/mocha/keyboard_movement_test.js +++ b/packages/blockly/tests/mocha/keyboard_movement_test.js @@ -534,6 +534,7 @@ suite('Keyboard-driven movement', function () { suite('in constrained mode', function () { test('prompts to use unconstrained mode when no destinations are available', function () { const toastSpy = sinon.spy(Blockly.Toast, 'show'); + const beepSpy = sinon.spy(this.workspace.getAudioManager(), 'beep'); Blockly.getFocusManager().focusNode(this.element); const originalBounds = this.element.getBoundingRectangle(); startMove(this.workspace); @@ -547,6 +548,8 @@ suite('Keyboard-driven movement', function () { ? 'Hold ⌘ Command and use arrow keys to move freely, then Enter to accept the position' : 'Hold Ctrl and use arrow keys to move freely, then Enter to accept the position', ); + sinon.assert.calledOnce(beepSpy); + beepSpy.restore(); toastSpy.restore(); });