Fix: Can only call Element.querySelectorAll on instances of Element * Fix: Can only call Element.querySelectorAll on instances of Element errors Approved-by: Erik Tiekstra
68 lines
1.9 KiB
TypeScript
68 lines
1.9 KiB
TypeScript
/*!
|
|
* Adapted from jQuery UI core
|
|
*
|
|
* http://jqueryui.com
|
|
*
|
|
* Copyright 2014 jQuery Foundation and other contributors
|
|
* Released under the MIT license.
|
|
* http://jquery.org/license
|
|
*
|
|
* http://api.jqueryui.com/category/ui-core/
|
|
*/
|
|
|
|
const tabbableNode = /input|select|textarea|button|object/
|
|
|
|
function hidesContents(element: HTMLElement) {
|
|
const zeroSize = element.offsetWidth <= 0 && element.offsetHeight <= 0
|
|
|
|
// If the node is empty, this is good enough
|
|
if (zeroSize && !element.innerHTML) return true
|
|
|
|
// Otherwise we need to check some styles
|
|
const style = window.getComputedStyle(element)
|
|
return (
|
|
style.getPropertyValue("display") === "none" ||
|
|
(zeroSize && style.getPropertyValue("overflow") !== "visible")
|
|
)
|
|
}
|
|
|
|
function visible(element: any) {
|
|
let parentElement = element
|
|
while (parentElement) {
|
|
if (parentElement === document.body) break
|
|
if (hidesContents(parentElement)) return false
|
|
parentElement = parentElement.parentNode
|
|
}
|
|
return true
|
|
}
|
|
|
|
export function focusable(element: HTMLElement, isTabIndexNotNaN: boolean) {
|
|
const nodeName = element.nodeName.toLowerCase()
|
|
const res =
|
|
//@ts-ignore
|
|
(tabbableNode.test(nodeName) && !element.disabled) ||
|
|
//@ts-ignore
|
|
(nodeName === "a" ? element.href || isTabIndexNotNaN : isTabIndexNotNaN)
|
|
return res && visible(element)
|
|
}
|
|
|
|
export function tabbable(element: HTMLElement) {
|
|
const tabIndexAttr = element.getAttribute("tabindex")
|
|
const tabIndex = tabIndexAttr !== null ? Number(tabIndexAttr) : undefined
|
|
const isTabIndexNaN = tabIndex === undefined || isNaN(tabIndex)
|
|
|
|
return (isTabIndexNaN || tabIndex >= 0) && focusable(element, !isTabIndexNaN)
|
|
}
|
|
|
|
export default function findTabbableDescendants(
|
|
element: HTMLElement | null | undefined
|
|
): HTMLElement[] {
|
|
if (!(element instanceof HTMLElement)) {
|
|
return []
|
|
}
|
|
|
|
return Array.from(element.querySelectorAll("*"))
|
|
.filter((el): el is HTMLElement => el instanceof HTMLElement)
|
|
.filter(tabbable)
|
|
}
|