| /** |
| * @license |
| * Copyright 2022 Google LLC |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| const FOCUSABLE_QUERY = |
| 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'; |
| |
| /** |
| * Gets an ordered list of focusable elements nested within a containing |
| * element that may contain shadow DOMs. |
| * |
| * This goes depth-first, so that the order of elements follows the a11y tree. |
| */ |
| export function* getFocusableElements( |
| el: HTMLElement | SVGElement |
| ): Generator<HTMLElement | SVGElement> { |
| const style = window.getComputedStyle(el); |
| if (style.display === 'none' || style.visibility === 'hidden') return; |
| if (el.matches(FOCUSABLE_QUERY)) { |
| yield el; |
| } |
| |
| let children = []; |
| if (el.localName === 'slot') { |
| children = (el as HTMLSlotElement).assignedNodes({flatten: true}); |
| } else { |
| children = [...(el.shadowRoot || el).children]; |
| } |
| |
| for (const node of children.filter( |
| node => node instanceof HTMLElement || node instanceof SVGElement |
| )) { |
| yield* getFocusableElements(node as HTMLElement | SVGElement); |
| } |
| } |
| |
| /** |
| * Gets an ordered list of focusable elements nested within a containing |
| * element that may contain shadow DOMs. |
| * |
| * This returns in reverse a11 order. |
| */ |
| export function* getFocusableElementsReverse( |
| el: HTMLElement | SVGElement |
| ): Generator<HTMLElement | SVGElement> { |
| const style = window.getComputedStyle(el); |
| if (style.display === 'none' || style.visibility === 'hidden') return; |
| |
| let children = []; |
| if (el.localName === 'slot') { |
| children = (el as HTMLSlotElement).assignedNodes({flatten: true}); |
| } else { |
| children = [...(el.shadowRoot || el).children]; |
| } |
| |
| for (const node of children |
| .filter(node => node instanceof HTMLElement || node instanceof SVGElement) |
| .reverse()) { |
| yield* getFocusableElementsReverse(node as HTMLElement | SVGElement); |
| } |
| |
| if (el.matches(FOCUSABLE_QUERY)) { |
| yield el; |
| } |
| } |