Skip to content

Commit 8c25c1f

Browse files
authored
Merge pull request #8774 from BenHenning/introduce-focus-system-interfaces
feat: Add interfaces for focus management
2 parents e6e57dd + de076a7 commit 8c25c1f

3 files changed

Lines changed: 93 additions & 0 deletions

File tree

core/blockly.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ import {
140140
} from './interfaces/i_draggable.js';
141141
import {IDragger} from './interfaces/i_dragger.js';
142142
import {IFlyout} from './interfaces/i_flyout.js';
143+
import {IFocusableNode} from './interfaces/i_focusable_node.js';
144+
import {IFocusableTree} from './interfaces/i_focusable_tree.js';
143145
import {IHasBubble, hasBubble} from './interfaces/i_has_bubble.js';
144146
import {IIcon, isIcon} from './interfaces/i_icon.js';
145147
import {IKeyboardAccessible} from './interfaces/i_keyboard_accessible.js';
@@ -544,6 +546,8 @@ export {
544546
IDragger,
545547
IFlyout,
546548
IFlyoutInflater,
549+
IFocusableNode,
550+
IFocusableTree,
547551
IHasBubble,
548552
IIcon,
549553
IKeyboardAccessible,
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import type {IFocusableTree} from './i_focusable_tree.js';
8+
9+
/** Represents anything that can have input focus. */
10+
export interface IFocusableNode {
11+
/**
12+
* Returns the DOM element that can be explicitly requested to receive focus.
13+
*
14+
* IMPORTANT: Please note that this element is expected to have a visual
15+
* presence on the page as it will both be explicitly focused and have its
16+
* style changed depending on its current focus state (i.e. blurred, actively
17+
* focused, and passively focused). The element will have one of two styles
18+
* attached (where no style indicates blurred/not focused):
19+
* - blocklyActiveFocus
20+
* - blocklyPassiveFocus
21+
*
22+
* The returned element must also have a valid ID specified, and unique to the
23+
* element relative to its nearest IFocusableTree parent.
24+
*
25+
* It's expected the return element will not change for the lifetime of the
26+
* node.
27+
*/
28+
getFocusableElement(): HTMLElement | SVGElement;
29+
30+
/**
31+
* Returns the closest parent tree of this node (in cases where a tree has
32+
* distinct trees underneath it), which represents the tree to which this node
33+
* belongs.
34+
*/
35+
getFocusableTree(): IFocusableTree;
36+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/**
2+
* @license
3+
* Copyright 2025 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import type {IFocusableNode} from './i_focusable_node.js';
8+
9+
/**
10+
* Represents a tree of focusable elements with its own active/passive focus
11+
* context.
12+
*
13+
* Note that focus is handled by FocusManager, and tree implementations can have
14+
* at most one IFocusableNode focused at one time. If the tree itself has focus,
15+
* then the tree's focused node is considered 'active' ('passive' if another
16+
* tree has focus).
17+
*
18+
* Focus is shared between one or more trees, where each tree can have exactly
19+
* one active or passive node (and only one active node can exist on the whole
20+
* page at any given time). The idea of passive focus is to provide context to
21+
* users on where their focus will be restored upon navigating back to a
22+
* previously focused tree.
23+
*/
24+
export interface IFocusableTree {
25+
/**
26+
* Returns the current node with focus in this tree, or null if none (or if
27+
* the root has focus).
28+
*
29+
* Note that this will never return a node from a nested sub-tree as that tree
30+
* should specifically be called in order to retrieve its focused node.
31+
*/
32+
getFocusedNode(): IFocusableNode | null;
33+
34+
/**
35+
* Returns the top-level focusable node of the tree.
36+
*
37+
* It's expected that the returned node will be focused in cases where
38+
* FocusManager wants to focus a tree in a situation where it does not
39+
* currently have a focused node.
40+
*/
41+
getRootFocusableNode(): IFocusableNode;
42+
43+
/**
44+
* Returns the IFocusableNode corresponding to the select element, or null if
45+
* the element does not have such a node.
46+
*
47+
* The provided element must have a non-null ID that conforms to the contract
48+
* mentioned in IFocusableNode.
49+
*/
50+
findFocusableNodeFor(
51+
element: HTMLElement | SVGElement,
52+
): IFocusableNode | null;
53+
}

0 commit comments

Comments
 (0)