@kahi-ui/framework
Version:
Straight-forward Svelte UI for the Web
53 lines (52 loc) • 2.19 kB
JavaScript
const FOCUSABLE_SELECTORS = [
"[tabindex]:not([aria-disabled])",
"a[href]",
"iframe",
"button:not(:disabled)",
"input:not(:disabled)",
"select:not(:disabled)",
"textarea:not(:disabled)",
];
const FOCUSABLE_SELECTOR = `:is(${FOCUSABLE_SELECTORS.join(", ")})`;
function get_scroll_top(container_element, target_element, position) {
// TODO: implement `nearest` position
let y = target_element.offsetTop;
switch (position) {
case "center":
y -= target_element.offsetHeight / 2 - container_element.offsetHeight / 2;
case "end":
y += target_element.offsetHeight - container_element.offsetHeight;
}
return y - container_element.offsetTop;
}
export function can_focus(element) {
return !is_hidden(element) && element.matches(FOCUSABLE_SELECTOR);
}
export function is_hidden(element) {
const style = window.getComputedStyle(element);
return style.display === "none";
}
export function query_focusable_element(element, options = {}) {
// NOTE: Would be a lot faster to run `querySelector` instead of `querySelectorAll` and manual
// filtering, but we need to run `is_hidden` and similar
const children = query_focusable_elements(element);
return children[options.last ? children.length - 1 : 0] ?? null;
}
export function query_focusable_elements(element) {
const children = element.querySelectorAll(FOCUSABLE_SELECTOR);
return Array.from(children).filter((child) => !is_hidden(child));
}
export function scroll_into_container(target, position = "start", behavior = "auto", parent) {
const target_element = typeof target === "string" ? document.querySelector(target) : target;
if (!target_element) {
throw ReferenceError(`bad argument #0 to 'scroll_into_container' (target '${target}' is invalid)`);
}
const container_element = parent ?? target_element.parentElement;
if (!container_element) {
throw ReferenceError("bad argument #0 to 'scroll_into_container' (target doesn't have parent element)");
}
container_element.scrollTo({
behavior,
top: get_scroll_top(container_element, target_element, position),
});
}