@@ -22,11 +22,14 @@ import {DeleteArea} from '../delete_area.js';
2222import '../events/events_toolbox_item_select.js' ;
2323import { EventType } from '../events/type.js' ;
2424import * as eventUtils from '../events/utils.js' ;
25+ import { getFocusManager } from '../focus_manager.js' ;
2526import type { IAutoHideable } from '../interfaces/i_autohideable.js' ;
2627import type { ICollapsibleToolboxItem } from '../interfaces/i_collapsible_toolbox_item.js' ;
2728import { isDeletable } from '../interfaces/i_deletable.js' ;
2829import type { IDraggable } from '../interfaces/i_draggable.js' ;
2930import type { IFlyout } from '../interfaces/i_flyout.js' ;
31+ import type { IFocusableNode } from '../interfaces/i_focusable_node.js' ;
32+ import type { IFocusableTree } from '../interfaces/i_focusable_tree.js' ;
3033import type { IKeyboardAccessible } from '../interfaces/i_keyboard_accessible.js' ;
3134import type { ISelectableToolboxItem } from '../interfaces/i_selectable_toolbox_item.js' ;
3235import { isSelectableToolboxItem } from '../interfaces/i_selectable_toolbox_item.js' ;
@@ -51,7 +54,12 @@ import {CollapsibleToolboxCategory} from './collapsible_category.js';
5154 */
5255export class Toolbox
5356 extends DeleteArea
54- implements IAutoHideable , IKeyboardAccessible , IStyleable , IToolbox
57+ implements
58+ IAutoHideable ,
59+ IKeyboardAccessible ,
60+ IStyleable ,
61+ IToolbox ,
62+ IFocusableNode
5563{
5664 /**
5765 * The unique ID for this component that is used to register with the
@@ -163,6 +171,7 @@ export class Toolbox
163171 ComponentManager . Capability . DRAG_TARGET ,
164172 ] ,
165173 } ) ;
174+ getFocusManager ( ) . registerTree ( this ) ;
166175 }
167176
168177 /**
@@ -177,7 +186,6 @@ export class Toolbox
177186 const container = this . createContainer_ ( ) ;
178187
179188 this . contentsDiv_ = this . createContentsContainer_ ( ) ;
180- this . contentsDiv_ . tabIndex = 0 ;
181189 aria . setRole ( this . contentsDiv_ , aria . Role . TREE ) ;
182190 container . appendChild ( this . contentsDiv_ ) ;
183191
@@ -194,6 +202,7 @@ export class Toolbox
194202 */
195203 protected createContainer_ ( ) : HTMLDivElement {
196204 const toolboxContainer = document . createElement ( 'div' ) ;
205+ toolboxContainer . tabIndex = 0 ;
197206 toolboxContainer . setAttribute ( 'layout' , this . isHorizontal ( ) ? 'h' : 'v' ) ;
198207 dom . addClass ( toolboxContainer , 'blocklyToolbox' ) ;
199208 toolboxContainer . setAttribute ( 'dir' , this . RTL ? 'RTL' : 'LTR' ) ;
@@ -1077,7 +1086,71 @@ export class Toolbox
10771086 this . workspace_ . getThemeManager ( ) . unsubscribe ( this . HtmlDiv ) ;
10781087 dom . removeNode ( this . HtmlDiv ) ;
10791088 }
1089+
1090+ getFocusManager ( ) . unregisterTree ( this ) ;
1091+ }
1092+
1093+ /** See IFocusableNode.getFocusableElement. */
1094+ getFocusableElement ( ) : HTMLElement | SVGElement {
1095+ if ( ! this . HtmlDiv ) throw Error ( 'Toolbox DOM has not yet been created.' ) ;
1096+ return this . HtmlDiv ;
1097+ }
1098+
1099+ /** See IFocusableNode.getFocusableTree. */
1100+ getFocusableTree ( ) : IFocusableTree {
1101+ return this ;
1102+ }
1103+
1104+ /** See IFocusableNode.onNodeFocus. */
1105+ onNodeFocus ( ) : void { }
1106+
1107+ /** See IFocusableNode.onNodeBlur. */
1108+ onNodeBlur ( ) : void { }
1109+
1110+ /** See IFocusableTree.getRootFocusableNode. */
1111+ getRootFocusableNode ( ) : IFocusableNode {
1112+ return this ;
1113+ }
1114+
1115+ /** See IFocusableTree.getRestoredFocusableNode. */
1116+ getRestoredFocusableNode (
1117+ previousNode : IFocusableNode | null ,
1118+ ) : IFocusableNode | null {
1119+ // Always try to select the first selectable toolbox item rather than the
1120+ // root of the toolbox.
1121+ if ( ! previousNode || previousNode === this ) {
1122+ return this . getToolboxItems ( ) . find ( ( item ) => item . isSelectable ( ) ) ?? null ;
1123+ }
1124+ return null ;
10801125 }
1126+
1127+ /** See IFocusableTree.getNestedTrees. */
1128+ getNestedTrees ( ) : Array < IFocusableTree > {
1129+ return [ ] ;
1130+ }
1131+
1132+ /** See IFocusableTree.lookUpFocusableNode. */
1133+ lookUpFocusableNode ( id : string ) : IFocusableNode | null {
1134+ return this . getToolboxItemById ( id ) as IFocusableNode ;
1135+ }
1136+
1137+ /** See IFocusableTree.onTreeFocus. */
1138+ onTreeFocus (
1139+ node : IFocusableNode ,
1140+ _previousTree : IFocusableTree | null ,
1141+ ) : void {
1142+ if ( node !== this ) {
1143+ // Only select the item if it isn't already selected so as to not toggle.
1144+ if ( this . getSelectedItem ( ) !== node ) {
1145+ this . setSelectedItem ( node as IToolboxItem ) ;
1146+ }
1147+ } else {
1148+ this . clearSelection ( ) ;
1149+ }
1150+ }
1151+
1152+ /** See IFocusableTree.onTreeBlur. */
1153+ onTreeBlur ( _nextTree : IFocusableTree | null ) : void { }
10811154}
10821155
10831156/** CSS for Toolbox. See css.js for use. */
0 commit comments