/** * @license * Copyright 2025 Google LLC * SPDX-License-Identifier: Apache-2.0 */ import type { IFocusableNode } from './i_focusable_node.js'; /** * Represents a tree of focusable elements with its own active/passive focus * context. * * Note that focus is handled by FocusManager, and tree implementations can have * at most one IFocusableNode focused at one time. If the tree itself has focus, * then the tree's focused node is considered 'active' ('passive' if another * tree has focus). * * Focus is shared between one or more trees, where each tree can have exactly * one active or passive node (and only one active node can exist on the whole * page at any given time). The idea of passive focus is to provide context to * users on where their focus will be restored upon navigating back to a * previously focused tree. * * Note that if the tree's current focused node (passive or active) is needed, * FocusableTreeTraverser.findFocusedNode can be used. * * Note that if specific nodes are needed to be retrieved for this tree, either * use lookUpFocusableNode or FocusableTreeTraverser.findFocusableNodeFor. */ export interface IFocusableTree { /** * Returns the top-level focusable node of the tree. * * It's expected that the returned node will be focused in cases where * FocusManager wants to focus a tree in a situation where it does not * currently have a focused node. */ getRootFocusableNode(): IFocusableNode; /** * Returns the IFocusableNode of this tree that should receive active focus * when the tree itself has focus returned to it. * * There are some very important notes to consider about a tree's focus * lifecycle when implementing a version of this method that doesn't return * null: * 1. A null previousNode does not guarantee first-time focus state as nodes * can be deleted. * 2. This method is only used when the tree itself is focused, either through * tab navigation or via FocusManager.focusTree(). In many cases, the * previously focused node will be directly focused instead which will * bypass this method. * 3. The default behavior (i.e. returning null here) involves either * restoring the previous node (previousNode) or focusing the tree's root. * 4. The provided node may sometimes no longer be valid, such as in the case * an attempt is made to focus a node that has been recently removed from * its parent tree. Implementations can check for the validity of the node * in order to specialize the node to which focus should fall back. * * This method is largely intended to provide tree implementations with the * means of specifying a better default node than their root. * * @param previousNode The node that previously held passive focus for this * tree, or null if the tree hasn't yet been focused. * @returns The IFocusableNode that should now receive focus, or null if * default behavior should be used, instead. */ getRestoredFocusableNode(previousNode: IFocusableNode | null): IFocusableNode | null; /** * Returns all directly nested trees under this tree. * * Note that the returned list of trees doesn't need to be stable, however all * returned trees *do* need to be registered with FocusManager. Additionally, * this must return actual nested trees as omitting a nested tree will affect * how focus changes map to a specific node and its tree, potentially leading * to user confusion. */ getNestedTrees(): Array; /** * Returns the IFocusableNode corresponding to the specified element ID, or * null if there's no exact node within this tree with that ID or if the ID * corresponds to the root of the tree. * * This will never match against nested trees. * * @param id The ID of the node's focusable HTMLElement or SVGElement. */ lookUpFocusableNode(id: string): IFocusableNode | null; /** * Called when a node of this tree has received active focus. * * Note that a null previousTree does not necessarily indicate that this is * the first time Blockly is receiving focus. In fact, few assumptions can be * made about previous focus state as a previous null tree simply indicates * that Blockly did not hold active focus prior to this tree becoming focused * (which can happen due to focus exiting the Blockly injection div, or for * other cases like ephemeral focus). * * See IFocusableNode.onNodeFocus() as implementations have the same * restrictions as with that method. * * @param node The node receiving active focus. * @param previousTree The previous tree that held active focus, or null if * none. */ onTreeFocus(node: IFocusableNode, previousTree: IFocusableTree | null): void; /** * Called when the previously actively focused node of this tree is now * passively focused and there is no other active node of this tree taking its * place. * * This has the same implementation restrictions and considerations as * onTreeFocus(). * * @param nextTree The next tree receiving active focus, or null if none (such * as in the case that Blockly is entirely losing DOM focus). */ onTreeBlur(nextTree: IFocusableTree | null): void; } /** * Determines whether the provided object fulfills the contract of * IFocusableTree. * * @param obj The object to test. * @returns Whether the provided object can be used as an IFocusableTree. */ export declare function isFocusableTree(obj: any): obj is IFocusableTree; //# sourceMappingURL=i_focusable_tree.d.ts.map