Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions plugins/continuous-toolbox/src/ContinuousFlyout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,26 @@ export class ContinuousFlyout extends Blockly.VerticalFlyout {
this.scrollTo(position);
}

/**
* Returns the header item in the flyout corresponding to the given
* toolbox category, if any.
*
* @param category The toolbox category to retrieve header item for.
* @returns The given category's header item, or undefined if not found.
*/
headerForCategory(
category: Blockly.ISelectableToolboxItem,
): Blockly.IFocusableNode | undefined {
return this.getContents()
.find((item) => {
return (
this.toolboxItemIsLabel(item) &&
item.getElement().getButtonText() === category.getName()
);
})
?.getElement();
}

/**
* Step the scrolling animation by scrolling a fraction of the way to
* a scroll target, and request the next frame if necessary.
Expand Down
15 changes: 15 additions & 0 deletions plugins/continuous-toolbox/src/ContinuousToolbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import * as Blockly from 'blockly/core';
import {ContinuousFlyout} from './ContinuousFlyout';
import {ContinuousToolboxNavigator} from './ContinuousToolboxNavigator';

/**
* Class for continuous toolbox.
Expand All @@ -21,6 +22,12 @@ export class ContinuousToolbox extends Blockly.Toolbox {
*/
private refreshDebouncer?: ReturnType<typeof setTimeout>;

/**
* Navigator object responsible for handling keyboard navigation within this
* toolbox.
*/
private continuousToolboxNavigator = new ContinuousToolboxNavigator(this);

/**
* Initializes the continuous toolbox.
*/
Expand Down Expand Up @@ -192,4 +199,12 @@ export class ContinuousToolbox extends Blockly.Toolbox {
}
return super.getClientRect();
}

/**
* Returns the Navigator object responsible for handling keyboard navigation
* inside this toolbox.
*/
override getNavigator(): Blockly.ToolboxNavigator {
return this.continuousToolboxNavigator;
}
}
32 changes: 32 additions & 0 deletions plugins/continuous-toolbox/src/ContinuousToolboxNavigator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* @license
* Copyright 2026 Raspberry Pi Foundation
* SPDX-License-Identifier: Apache-2.0
*/

import * as Blockly from 'blockly/core';
import {ContinuousToolbox} from './ContinuousToolbox';
import {ContinuousCategory} from './ContinuousCategory';

/**
* A Navigator that handles keyboard navigation within a continuous toolbox.
*/
export class ContinuousToolboxNavigator extends Blockly.ToolboxNavigator {
constructor(protected toolbox: ContinuousToolbox) {
super(toolbox);
}

/**
* Returns the next node when navigating "in", in this case the first flyout
* item in the toolbox's currently selected category.
*
* @param node The node to navigate relative to.
* @returns The node "in" relative to the given node.
*/
override getInNode(
node = Blockly.getFocusManager().getFocusedNode(),
): Blockly.IFocusableNode | null {
if (!(node instanceof ContinuousCategory)) return null;
return this.toolbox.getFlyout().headerForCategory(node) ?? null;
}
}
Loading