diff --git a/packages/blockly/core/css.ts b/packages/blockly/core/css.ts index 65158557b02..95200b7203b 100644 --- a/packages/blockly/core/css.ts +++ b/packages/blockly/core/css.ts @@ -596,6 +596,15 @@ input[type=number] { ) .blocklyPassiveFocus.blocklyField > .blocklyFieldRect, +/* Full-block fields use the block path for their passive focus indicator. */ +.blocklyKeyboardNavigation:not( + :has( + .blocklyDropDownDiv:focus-within, + .blocklyWidgetDiv:focus-within + ) + ) + .blocklyBlock:has(> .blocklyFullBlockField.blocklyPassiveFocus) + > .blocklyPath:not(.blocklyFlyout .blocklyPath), /* Icons with passive focus except when widget/dropdown div in use. */ .blocklyKeyboardNavigation:not( :has( diff --git a/packages/blockly/core/field.ts b/packages/blockly/core/field.ts index 2acd110c5fe..b88dad42f16 100644 --- a/packages/blockly/core/field.ts +++ b/packages/blockly/core/field.ts @@ -429,6 +429,7 @@ export abstract class Field // Since full-block fields can be focused from the workspace's tree, // they need IDs in the format that the workspace is expecting. if (this.isFullBlockField()) { + dom.addClass(this.fieldGroup_, 'blocklyFullBlockField'); this.id_ = idGenerator.getNextUniqueId(); } else { this.id_ = `${sourceBlockSvg.id}_field_${idGenerator.getNextUniqueId()}`; diff --git a/packages/blockly/tests/mocha/keyboard_navigation_test.ts b/packages/blockly/tests/mocha/keyboard_navigation_test.ts index 43ab200e993..86bfb0a0b4f 100644 --- a/packages/blockly/tests/mocha/keyboard_navigation_test.ts +++ b/packages/blockly/tests/mocha/keyboard_navigation_test.ts @@ -515,6 +515,60 @@ suite('Keyboard navigation on Fields', function () { }); }); +suite('Field focus indicators', function () { + let workspace: Blockly.WorkspaceSvg; + + setup(function (this: Mocha.Context) { + sharedTestSetup.call(this); + Blockly.defineBlocksWithJsonArray([ + { + type: 'focus_reporter', + message0: '%1', + args0: [{type: 'field_input', name: 'TEXT', text: 'value'}], + output: null, + }, + ]); + workspace = Blockly.inject('blocklyDiv', { + ...DEFAULT_INJECT_OPTIONS, + renderer: 'zelos', + toolbox: { + kind: 'categoryToolbox', + contents: [ + { + kind: 'category', + name: 'Fields', + contents: [{kind: 'block', type: 'focus_reporter'}], + }, + ], + }, + }); + Blockly.keyboardNavigationController.setIsActive(true); + }); + + teardown(function (this: Mocha.Context) { + Blockly.keyboardNavigationController.setIsActive(false); + sharedTestTeardown.call(this, workspace); + delete Blockly.Blocks['focus_reporter']; + }); + + test('full-block fields show a passive outline when focus moves to the toolbox', function () { + const block = workspace.newBlock('focus_reporter'); + block.initSvg(); + block.render(); + Blockly.getFocusManager().focusNode(block); + + workspace + .getInjectionDiv() + .dispatchEvent(createKeyDownEvent(Blockly.utils.KeyCodes.T)); + + const dashArray = getComputedStyle( + block.pathObject.svgPath, + ).strokeDasharray; + assert.isNotEmpty(dashArray); + assert.notEqual(dashArray, 'none'); + }); +}); + suite('Workspace comment navigation', function () { let workspace: Blockly.WorkspaceSvg; let commentId1: string;