Skip to content

Commit 8a52f03

Browse files
authored
feat: Add a new FOCUSABLE capability to IComponent (#10038)
1 parent f6fcc64 commit 8a52f03

4 files changed

Lines changed: 31 additions & 40 deletions

File tree

packages/blockly/core/component_manager.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import type {IAutoHideable} from './interfaces/i_autohideable.js';
1515
import type {IComponent} from './interfaces/i_component.js';
1616
import type {IDeleteArea} from './interfaces/i_delete_area.js';
1717
import type {IDragTarget} from './interfaces/i_drag_target.js';
18+
import type {IFocusableNode} from './interfaces/i_focusable_node.js';
1819
import type {IPositionable} from './interfaces/i_positionable.js';
1920
import * as arrayUtils from './utils/array.js';
2021

@@ -23,6 +24,7 @@ class Capability<_T> {
2324
static DRAG_TARGET = new Capability<IDragTarget>('drag_target');
2425
static DELETE_AREA = new Capability<IDeleteArea>('delete_area');
2526
static AUTOHIDEABLE = new Capability<IAutoHideable>('autohideable');
27+
static FOCUSABLE = new Capability<IFocusableNode>('focusable');
2628
private readonly name: string;
2729
/** @param name The name of the component capability. */
2830
constructor(name: string) {

packages/blockly/core/trashcan.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {EventType} from './events/type.js';
2222
import * as eventUtils from './events/utils.js';
2323
import {getFocusManager} from './focus_manager.js';
2424
import type {IAutoHideable} from './interfaces/i_autohideable.js';
25+
import type {IComponent} from './interfaces/i_component';
2526
import type {IDraggable} from './interfaces/i_draggable.js';
2627
import type {IFlyout} from './interfaces/i_flyout.js';
2728
import type {IFocusableNode} from './interfaces/i_focusable_node.js';
@@ -49,7 +50,7 @@ import type {WorkspaceSvg} from './workspace_svg.js';
4950
*/
5051
export class Trashcan
5152
extends DeleteArea
52-
implements IAutoHideable, IPositionable, IFocusableNode
53+
implements IAutoHideable, IPositionable, IFocusableNode, IComponent
5354
{
5455
/**
5556
* The id for this component that is used to register with the
@@ -269,6 +270,7 @@ export class Trashcan
269270
ComponentManager.Capability.DELETE_AREA,
270271
ComponentManager.Capability.DRAG_TARGET,
271272
ComponentManager.Capability.POSITIONABLE,
273+
ComponentManager.Capability.FOCUSABLE,
272274
],
273275
});
274276
this.initialized = true;
@@ -659,16 +661,6 @@ export class Trashcan
659661
performAction() {
660662
this.click();
661663
}
662-
663-
/**
664-
* Retrieves the globally unique ID of this Trashcan instance. Used for focus
665-
* management.
666-
*
667-
* @internal
668-
*/
669-
getGloballyUniqueId() {
670-
return this.uniqueId;
671-
}
672664
}
673665

674666
/** Width of both the trash can and lid images. */

packages/blockly/core/workspace_svg.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import * as hints from './hints.js';
4949
import {MutatorIcon} from './icons/mutator_icon.js';
5050
import {isAutoHideable} from './interfaces/i_autohideable.js';
5151
import type {IBoundedElement} from './interfaces/i_bounded_element.js';
52+
import type {IComponent} from './interfaces/i_component.js';
5253
import {IContextMenu} from './interfaces/i_contextmenu.js';
5354
import type {IDragTarget} from './interfaces/i_drag_target.js';
5455
import type {IFlyout} from './interfaces/i_flyout.js';
@@ -2961,13 +2962,15 @@ export class WorkspaceSvg
29612962
}
29622963
}
29632964

2964-
if (this.trashcan?.getGloballyUniqueId() === id) {
2965-
return this.trashcan;
2965+
const focusableComponents = this.getComponentManager().getComponents<
2966+
IFocusableNode & IComponent
2967+
>(ComponentManager.Capability.FOCUSABLE, false);
2968+
for (const component of focusableComponents) {
2969+
if (component.getFocusableElement().getAttribute('id') === id) {
2970+
return component;
2971+
}
29662972
}
29672973

2968-
const zoomControl = this.zoomControls_?.getControlWithId(id);
2969-
if (zoomControl) return zoomControl;
2970-
29712974
return null;
29722975
}
29732976

packages/blockly/core/zoom_controls.ts

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {ComponentManager} from './component_manager.js';
1919
import * as Css from './css.js';
2020
import {EventType} from './events/type.js';
2121
import * as eventUtils from './events/utils.js';
22+
import type {IComponent} from './interfaces/i_component.js';
2223
import {IFocusableNode} from './interfaces/i_focusable_node.js';
2324
import type {IPositionable} from './interfaces/i_positionable.js';
2425
import type {UiMetrics} from './metrics_manager.js';
@@ -39,9 +40,9 @@ import type {WorkspaceSvg} from './workspace_svg.js';
3940
*
4041
* @internal
4142
*/
42-
abstract class ZoomControl implements IFocusableNode {
43+
abstract class ZoomControl implements IFocusableNode, IComponent {
4344
private pointerDownHandler: browserEvents.Data;
44-
private id: string;
45+
id: string;
4546

4647
constructor(
4748
protected workspace: WorkspaceSvg,
@@ -60,10 +61,6 @@ abstract class ZoomControl implements IFocusableNode {
6061
this.group.id = this.id;
6162
}
6263

63-
getId() {
64-
return this.id;
65-
}
66-
6764
/**
6865
* Handles a mouse down event on the zoom in or zoom out buttons on the
6966
* workspace.
@@ -385,6 +382,21 @@ export class ZoomControls implements IPositionable {
385382
this.svgGroup,
386383
);
387384
}
385+
386+
for (const control of [
387+
this.zoomOutControl,
388+
this.zoomInControl,
389+
this.zoomResetControl,
390+
]) {
391+
if (!control) continue;
392+
393+
this.workspace.getComponentManager().addComponent({
394+
component: control,
395+
weight: ComponentManager.ComponentWeight.ZOOM_CONTROLS_WEIGHT,
396+
capabilities: [ComponentManager.Capability.FOCUSABLE],
397+
});
398+
}
399+
388400
return this.svgGroup;
389401
}
390402

@@ -508,24 +520,6 @@ export class ZoomControls implements IPositionable {
508520
'translate(' + this.left + ',' + this.top + ')',
509521
);
510522
}
511-
512-
/**
513-
* Returns the individual zoom control, if any, with the given ID. Used for
514-
* focus management.
515-
*
516-
* @internal
517-
*/
518-
getControlWithId(id: string) {
519-
for (const control of [
520-
this.zoomInControl,
521-
this.zoomOutControl,
522-
this.zoomResetControl,
523-
]) {
524-
if (control?.getId() === id) {
525-
return control;
526-
}
527-
}
528-
}
529523
}
530524

531525
/** CSS for zoom controls. See css.js for use. */

0 commit comments

Comments
 (0)