device-navigation
Version:
Navigate HTML elements in two dimensions with non-pointer devices.
64 lines (63 loc) • 2.07 kB
JavaScript
/**
* Walk each node in the tree with a depth-first traversal. Walking stops if the callback returns
* true.
*
* @category Internal
* @returns The nav tree node that the callback returned `true` on, if any. Otherwise, `undefined`.
*/
export function walkNavTree(
/** The tree to walk. */
tree,
/** The callback to call on each node. If this returns `true`, the walking stops. */
callback) {
return walkRecursively([
{
ancestorChain: [],
node: tree,
nodeCoords: {
x: 0,
y: 0,
},
},
], tree.children, callback);
}
function walkRecursively(ancestorChain, children, callback) {
// eslint-disable-next-line unicorn/no-for-loop
for (let y = 0; y < children.length; y++) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const row = children[y];
// eslint-disable-next-line unicorn/no-for-loop
for (let x = 0; x < row.length; x++) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const node = row[x];
const walkResult = {
ancestorChain,
nodeCoords: { x, y },
node,
};
if (callback(walkResult)) {
return walkResult;
}
const result = walkRecursively(ancestorChain.concat(walkResult), node.children, callback);
if (result) {
return result;
}
}
}
return undefined;
}
/**
* Finds the given {@link NavEntry} in the given {@link NavTree}. If it does not exist, error out.
*
* @category Internal
* @throws Error if the {@link NavEntry} is not found in the {@link NavTree}.
*/
export function findNavTreeNodeByNavEntry(navTree, navEntry) {
const walkResult = walkNavTree(navTree, ({ node }) => {
return !node.root && node.navEntry === navEntry;
});
if (!walkResult) {
throw new Error(`Failed to find NavEntry in NavTree.`);
}
return walkResult;
}