mirror of
https://github.com/KuekHaoYang/KVideo.git
synced 2026-08-15 16:53:42 +08:00
70 lines
1.9 KiB
TypeScript
70 lines
1.9 KiB
TypeScript
/**
|
|
* Focus Trap Utility
|
|
* Traps keyboard focus within a specified container for accessibility
|
|
*/
|
|
|
|
const FOCUSABLE_ELEMENTS = [
|
|
'a[href]',
|
|
'button:not([disabled])',
|
|
'textarea:not([disabled])',
|
|
'input:not([disabled])',
|
|
'select:not([disabled])',
|
|
'[tabindex]:not([tabindex="-1"])',
|
|
].join(',');
|
|
|
|
export function getFocusableElements(container: HTMLElement): HTMLElement[] {
|
|
return Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE_ELEMENTS)).filter(
|
|
(el) => !el.hasAttribute('disabled') && el.offsetParent !== null
|
|
);
|
|
}
|
|
|
|
export function trapFocus(container: HTMLElement): () => void {
|
|
const focusableElements = getFocusableElements(container);
|
|
|
|
if (focusableElements.length === 0) return () => {};
|
|
|
|
const firstElement = focusableElements[0];
|
|
const lastElement = focusableElements[focusableElements.length - 1];
|
|
|
|
// Store the element that had focus before the trap
|
|
const previouslyFocusedElement = document.activeElement as HTMLElement;
|
|
|
|
// Focus the first element
|
|
firstElement.focus();
|
|
|
|
const handleKeyDown = (e: KeyboardEvent) => {
|
|
if (e.key !== 'Tab') return;
|
|
|
|
if (e.shiftKey) {
|
|
// Shift + Tab
|
|
if (document.activeElement === firstElement) {
|
|
e.preventDefault();
|
|
lastElement.focus();
|
|
}
|
|
} else {
|
|
// Tab
|
|
if (document.activeElement === lastElement) {
|
|
e.preventDefault();
|
|
firstElement.focus();
|
|
}
|
|
}
|
|
};
|
|
|
|
container.addEventListener('keydown', handleKeyDown);
|
|
|
|
// Return cleanup function
|
|
return () => {
|
|
container.removeEventListener('keydown', handleKeyDown);
|
|
// Restore focus to the previously focused element
|
|
if (previouslyFocusedElement && typeof previouslyFocusedElement.focus === 'function') {
|
|
previouslyFocusedElement.focus();
|
|
}
|
|
};
|
|
}
|
|
|
|
export function restoreFocus(element: HTMLElement | null) {
|
|
if (element && typeof element.focus === 'function') {
|
|
element.focus();
|
|
}
|
|
}
|