You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

65 lines
2.0 KiB

import { focusable, isFocusable, isTabbable, tabbable } from 'tabbable'
import { getDocument, isHTMLElement } from './core'
import { findVisible } from './focus'
function getTabbableOptions() {
return {
getShadowRoot: true,
displayCheck:
typeof ResizeObserver === 'function' && ResizeObserver.toString().includes('[native code]')
? 'full'
: 'none'
} as const
}
function toHtmlElements(nodes: ReadonlyArray<HTMLElement | SVGElement>): HTMLElement[] {
return nodes.filter(isHTMLElement)
}
export function getTabbableCandidates(container: HTMLElement): HTMLElement[] {
return toHtmlElements(tabbable(container, getTabbableOptions()))
}
export function getTabbableEdges(
container: HTMLElement
): readonly [HTMLElement | undefined, HTMLElement | undefined] {
const candidates = getTabbableCandidates(container)
const first = findVisible(candidates, container)
const last = findVisible([...candidates].reverse(), container)
return [first, last] as const
}
export function getTabbableFrom(currentNode: HTMLElement, direction: 'next' | 'prev'): HTMLElement {
if (!isTabbable(currentNode, getTabbableOptions())) {
return getTabbableFromFocusable(currentNode, direction)
}
const doc = getDocument(currentNode)
const allTabbable = toHtmlElements(tabbable(doc.body, getTabbableOptions()))
if (direction === 'prev') allTabbable.reverse()
const activeIndex = allTabbable.indexOf(currentNode)
if (activeIndex === -1) return doc.body
return allTabbable.slice(activeIndex + 1)[0] ?? doc.body
}
export function getTabbableFromFocusable(
currentNode: HTMLElement,
direction: 'next' | 'prev'
): HTMLElement {
const doc = getDocument(currentNode)
if (!isFocusable(currentNode, getTabbableOptions())) return doc.body
const allFocusable = toHtmlElements(focusable(doc.body, getTabbableOptions()))
if (direction === 'prev') allFocusable.reverse()
const activeIndex = allFocusable.indexOf(currentNode)
if (activeIndex === -1) return doc.body
return (
allFocusable.slice(activeIndex + 1).find((node) => isTabbable(node, getTabbableOptions())) ??
doc.body
)
}

Powered by TurnKey Linux.