|
import { getConfig } from "./config"; |
|
|
|
export function easeInOutQuad(elapsed: number, initialValue: number, amountOfChange: number, duration: number): number { |
|
if ((elapsed /= duration / 2) < 1) { |
|
return (amountOfChange / 2) * elapsed * elapsed + initialValue; |
|
} |
|
return (-amountOfChange / 2) * (--elapsed * (elapsed - 2) - 1) + initialValue; |
|
} |
|
|
|
export function getFocusableElements(parentEls: Element[] | HTMLElement[]) { |
|
const focusableQuery = |
|
'a[href]:not([disabled]), button:not([disabled]), textarea:not([disabled]), input[type="text"]:not([disabled]), input[type="radio"]:not([disabled]), input[type="checkbox"]:not([disabled]), select:not([disabled])'; |
|
|
|
return parentEls |
|
.flatMap(parentEl => { |
|
const isParentFocusable = parentEl.matches(focusableQuery); |
|
const focusableEls: HTMLElement[] = Array.from(parentEl.querySelectorAll(focusableQuery)); |
|
|
|
return [...(isParentFocusable ? [parentEl as HTMLElement] : []), ...focusableEls]; |
|
}) |
|
.filter(el => { |
|
return getComputedStyle(el).pointerEvents !== "none" && isElementVisible(el); |
|
}); |
|
} |
|
|
|
export function bringInView(element: Element) { |
|
if (!element || isElementInView(element)) { |
|
return; |
|
} |
|
|
|
const shouldSmoothScroll = getConfig("smoothScroll"); |
|
|
|
const isTallerThanViewport = (element as HTMLElement).offsetHeight > window.innerHeight; |
|
|
|
element.scrollIntoView({ |
|
|
|
|
|
behavior: !shouldSmoothScroll || hasScrollableParent(element) ? "auto" : "smooth", |
|
inline: "center", |
|
block: isTallerThanViewport ? "start" : "center", |
|
}); |
|
} |
|
|
|
function hasScrollableParent(e: Element) { |
|
if (!e || !e.parentElement) { |
|
return; |
|
} |
|
|
|
const parent = e.parentElement as HTMLElement & { scrollTopMax?: number }; |
|
|
|
return parent.scrollHeight > parent.clientHeight; |
|
} |
|
|
|
function isElementInView(element: Element) { |
|
const rect = element.getBoundingClientRect(); |
|
|
|
return ( |
|
rect.top >= 0 && |
|
rect.left >= 0 && |
|
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && |
|
rect.right <= (window.innerWidth || document.documentElement.clientWidth) |
|
); |
|
} |
|
|
|
export function isElementVisible(el: HTMLElement) { |
|
return !!(el.offsetWidth || el.offsetHeight || el.getClientRects().length); |
|
} |
|
|