rework moveFocus

This commit is contained in:
Min Idzelis 2025-05-16 01:13:45 +00:00
parent b9ff2a2e2e
commit 7a2c035299

View File

@ -12,28 +12,43 @@ export const setDefaultTabbleOptions = (options: TabbableOpts) => {
export const getTabbable = (container: Element, includeContainer: boolean = false) =>
tabbable(container, { ...defaultOpts, includeContainer });
export const moveFocus = (selector: (element: HTMLElement | SVGElement) => boolean, direction: 'previous' | 'next') => {
const focusElements = focusable(document.body, { includeContainer: true });
const current = document.activeElement as HTMLElement;
const index = focusElements.indexOf(current);
if (index === -1) {
for (const element of focusElements) {
if (selector(element)) {
element.focus();
return;
}
}
focusElements[0].focus();
export const moveFocus = (
selector: (element: HTMLElement | SVGElement) => boolean,
direction: 'previous' | 'next',
): void => {
const focusableElements = focusable(document.body, { includeContainer: true });
if (focusableElements.length === 0) {
return;
}
const totalElements = focusElements.length;
let i = index;
const currentElement = document.activeElement as HTMLElement | null;
const currentIndex = currentElement ? focusableElements.indexOf(currentElement) : -1;
// If no element is focused, focus the first matching element or the first focusable element
if (currentIndex === -1) {
const firstMatchingElement = focusableElements.find(selector);
if (firstMatchingElement) {
firstMatchingElement.focus();
} else if (focusableElements[0]) {
focusableElements[0].focus();
}
return;
}
// Calculate the step direction
const step = direction === 'next' ? 1 : -1;
const totalElements = focusableElements.length;
// Search for the next focusable element that matches the selector
let nextIndex = currentIndex;
do {
i = (i + (direction === 'next' ? 1 : -1) + totalElements) % totalElements;
const next = focusElements[i];
if (isTabbable(next) && selector(next)) {
next.focus();
nextIndex = (nextIndex + step + totalElements) % totalElements;
const candidateElement = focusableElements[nextIndex];
if (isTabbable(candidateElement) && selector(candidateElement)) {
candidateElement.focus();
break;
}
} while (i !== index);
} while (nextIndex !== currentIndex);
};