|
import { refreshActiveHighlight } from "./highlight"; |
|
import { emit } from "./emitter"; |
|
import { getState, setState } from "./state"; |
|
import { getConfig } from "./config"; |
|
import { getFocusableElements } from "./utils"; |
|
|
|
export function requireRefresh() { |
|
const resizeTimeout = getState("__resizeTimeout"); |
|
if (resizeTimeout) { |
|
window.cancelAnimationFrame(resizeTimeout); |
|
} |
|
|
|
setState("__resizeTimeout", window.requestAnimationFrame(refreshActiveHighlight)); |
|
} |
|
|
|
function trapFocus(e: KeyboardEvent) { |
|
const isActivated = getState("isInitialized"); |
|
if (!isActivated) { |
|
return; |
|
} |
|
|
|
const isTabKey = e.key === "Tab" || e.keyCode === 9; |
|
if (!isTabKey) { |
|
return; |
|
} |
|
|
|
const activeElement = getState("__activeElement"); |
|
const popoverEl = getState("popover")?.wrapper; |
|
|
|
const focusableEls = getFocusableElements([ |
|
...(popoverEl ? [popoverEl] : []), |
|
...(activeElement ? [activeElement] : []), |
|
]); |
|
|
|
const firstFocusableEl = focusableEls[0]; |
|
const lastFocusableEl = focusableEls[focusableEls.length - 1]; |
|
|
|
e.preventDefault(); |
|
|
|
if (e.shiftKey) { |
|
const previousFocusableEl = |
|
focusableEls[focusableEls.indexOf(document.activeElement as HTMLElement) - 1] || lastFocusableEl; |
|
previousFocusableEl?.focus(); |
|
} else { |
|
const nextFocusableEl = |
|
focusableEls[focusableEls.indexOf(document.activeElement as HTMLElement) + 1] || firstFocusableEl; |
|
nextFocusableEl?.focus(); |
|
} |
|
} |
|
|
|
function onKeyup(e: KeyboardEvent) { |
|
const allowKeyboardControl = getConfig("allowKeyboardControl") ?? true; |
|
|
|
if (!allowKeyboardControl) { |
|
return; |
|
} |
|
|
|
if (e.key === "Escape") { |
|
emit("escapePress"); |
|
} else if (e.key === "ArrowRight") { |
|
emit("arrowRightPress"); |
|
} else if (e.key === "ArrowLeft") { |
|
emit("arrowLeftPress"); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function onDriverClick( |
|
element: Element, |
|
listener: (pointer: MouseEvent | PointerEvent) => void, |
|
shouldPreventDefault?: (target: HTMLElement) => boolean |
|
) { |
|
const listenerWrapper = (e: MouseEvent | PointerEvent, listener?: (pointer: MouseEvent | PointerEvent) => void) => { |
|
const target = e.target as HTMLElement; |
|
if (!element.contains(target)) { |
|
return; |
|
} |
|
|
|
if (!shouldPreventDefault || shouldPreventDefault(target)) { |
|
e.preventDefault(); |
|
e.stopPropagation(); |
|
e.stopImmediatePropagation(); |
|
} |
|
|
|
listener?.(e); |
|
}; |
|
|
|
|
|
const useCapture = true; |
|
|
|
|
|
document.addEventListener("pointerdown", listenerWrapper, useCapture); |
|
document.addEventListener("mousedown", listenerWrapper, useCapture); |
|
document.addEventListener("pointerup", listenerWrapper, useCapture); |
|
document.addEventListener("mouseup", listenerWrapper, useCapture); |
|
|
|
|
|
document.addEventListener( |
|
"click", |
|
e => { |
|
listenerWrapper(e, listener); |
|
}, |
|
useCapture |
|
); |
|
} |
|
|
|
export function initEvents() { |
|
window.addEventListener("keyup", onKeyup, false); |
|
window.addEventListener("keydown", trapFocus, false); |
|
window.addEventListener("resize", requireRefresh); |
|
window.addEventListener("scroll", requireRefresh); |
|
} |
|
|
|
export function destroyEvents() { |
|
window.removeEventListener("keyup", onKeyup); |
|
window.removeEventListener("resize", requireRefresh); |
|
window.removeEventListener("scroll", requireRefresh); |
|
} |
|
|