import { isNil } from "./assertions" ; function isStyleVisible ( element ) { if ( ! ( element instanceof HTMLElement ) && ! ( element instanceof SVGElement ) ) { return false ; } const { display , visibility } = element . style ; if ( display === "none" || visibility === "hidden" || visibility === "collapse" ) { return false ; } const { getComputedStyle } = element . ownerDocument . defaultView ; const { display : computedDisplay , visibility : computedVisibility } = getComputedStyle ( element ) ; if ( computedDisplay === "none" || computedVisibility === "hidden" || computedVisibility === "collapse" ) { return false ; } return true ; } function isAttributeVisible ( element ) { return ! element . hasAttribute ( "hidden" ) && element . getAttribute ( "aria-hidden" ) !== "true" ; } function isParentElementVisible ( element , rootElement ? ) { const parentElement = element . parentElement ; if ( ! isNil ( parentElement ) ) { if ( parentElement !== rootElement ) { return isElementVisible ( parentElement , rootElement ) ; } } return true ; } function isElementVisible ( element , rootElement ? ) { if ( isNil ( element ) ) { return false ; } return element . nodeName !== "#comment" && isStyleVisible ( element ) && isAttributeVisible ( element ) && isParentElementVisible ( element , rootElement ) ; } const FocusableElements = [ "input:not([disabled]):not([type=hidden])" , "select:not([disabled])" , "textarea:not([disabled])" , "button:not([disabled])" , "a[href]" , "area[href]" , "summary" , "iframe" , "object" , "embed" , "audio[controls]" , "video[controls]" , "[contenteditable]" , "[tabindex]:not([disabled])" ] ; const FocusableExclusions = ":not([hidden]):not([aria-hidden=\"true\"])" ; const FocusableSelector = FocusableElements . join ( `${ FocusableExclusions },` ) + FocusableExclusions ; export interface CreateFocusableTreeWalkerOptions { acceptElement ? : ( element : HTMLElement ) => boolean ; } export function createFocusableTreeWalker ( root , { acceptElement = ( ) => true } = { } ) { const walker = document . createTreeWalker ( root , NodeFilter . SHOW_ELEMENT , { acceptNode ( node ) { if ( isFocusableElement ( node as HTMLElement , { rootElement : root } ) ) { if ( acceptElement ( node as HTMLElement ) ) { return NodeFilter . FILTER_ACCEPT ; } } return NodeFilter . FILTER_SKIP ; } } ) ; return walker ; } export interface IsFocusableElementOptions { rootElement ? : HTMLElement ; } export function isFocusableElement ( element , { rootElement } = { } ) { return element . matches ( FocusableSelector ) && isElementVisible ( element , rootElement ) ; }