module import { closest } from "./closest" ; import { getActiveElement } from "./getActiveElement" ; import { matches } from "./matches" ; const selector = "input:not([type='hidden']):not([disabled]), select:not([disabled]), " + "textarea:not([disabled]), a[href], button:not([disabled]), [tabindex], " + "iframe, object, embed, area[href], audio[controls], video[controls], " + "[contenteditable]:not([contenteditable='false'])" ; function isVisible ( element ) { const htmlElement = element as HTMLElement ; return ( htmlElement . offsetWidth > 0 || htmlElement . offsetHeight > 0 || element . getClientRects ( ) . length > 0 ) ; } function hasNegativeTabIndex ( element ) { const tabIndex = parseInt ( element . getAttribute ( "tabindex" ) || "0" , 10 ) ; return tabIndex < 0 ; } memberof example export function isFocusable ( element ) { return matches ( element , selector ) && isVisible ( element ) ; } memberof example export function isTabbable ( element ) { return isFocusable ( element ) && ! hasNegativeTabIndex ( element ) ; } memberof param { Element } container returns { Element [ ] } export function getAllFocusableIn < T extends Element > ( container ) { const allFocusable = Array . from ( container . querySelectorAll < T > ( selector ) ) ; allFocusable . unshift ( container ) ; return allFocusable . filter ( isFocusable ) ; } memberof param { Element } container returns { Element | null } export function getFirstFocusableIn < T extends Element > ( container ) { const [ first ] = getAllFocusableIn ( container ) ; return first || null ; } memberof param { Element } container param fallbackToFocusable returns { Element [ ] } export function getAllTabbableIn < T extends Element > ( container , fallbackToFocusable ? ) { const allFocusable = Array . from ( container . querySelectorAll < T > ( selector ) ) ; const allTabbable = allFocusable . filter ( isTabbable ) ; if ( isTabbable ( container ) ) { allTabbable . unshift ( container ) ; } if ( ! allTabbable . length && fallbackToFocusable ) { return allFocusable ; } return allTabbable ; } memberof param { Element } container param fallbackToFocusable returns { Element | null } export function getFirstTabbableIn < T extends Element > ( container , fallbackToFocusable ? ) { const [ first ] = getAllTabbableIn ( container , fallbackToFocusable ) ; return first || null ; } memberof param { Element } container param fallbackToFocusable returns { Element | null } export function getLastTabbableIn < T extends Element > ( container , fallbackToFocusable ? ) { const allTabbable = getAllTabbableIn ( container , fallbackToFocusable ) ; return allTabbable [ allTabbable . length - 1 ] || null ; } memberof param { Element } container param fallbackToFocusable returns { Element | null } export function getNextTabbableIn < T extends Element > ( container , fallbackToFocusable ? ) { const activeElement = getActiveElement ( container ) ; const allFocusable = getAllFocusableIn ( container ) ; const index = allFocusable . indexOf ( activeElement as T ) ; const slice = allFocusable . slice ( index + 1 ) ; return ( slice . find ( isTabbable ) || allFocusable . find ( isTabbable ) || ( fallbackToFocusable ? slice [ 0 ] : null ) ) ; } memberof param { Element } container param fallbackToFocusable returns { Element | null } export function getPreviousTabbableIn < T extends Element > ( container , fallbackToFocusable ? ) { const activeElement = getActiveElement ( container ) ; const allFocusable = getAllFocusableIn ( container ) . reverse ( ) ; const index = allFocusable . indexOf ( activeElement as T ) ; const slice = allFocusable . slice ( index + 1 ) ; return ( slice . find ( isTabbable ) || allFocusable . find ( isTabbable ) || ( fallbackToFocusable ? slice [ 0 ] : null ) ) ; } memberof param { Element } container returns { Element | null } export function getClosestFocusable < T extends Element > ( element ? ) { while ( element && ! isFocusable ( element ) ) { element = closest ( element , selector ) as T ; } return element ; }