@redocly/theme
Version:
Shared UI components lib
46 lines (38 loc) • 1.5 kB
text/typescript
import { useEffect, useRef } from 'react';
import type { RefObject } from 'react';
export function useDialogHotKeys(ref: RefObject<HTMLElement | null>, onClose: () => void): void {
const firstFocusableRef = useRef<HTMLElement>(null);
const lastFocusableRef = useRef<HTMLElement>(null);
const onKeyDownHandler = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
onClose();
} else if (event.key === 'Tab') {
if (!event.shiftKey && document.activeElement === lastFocusableRef.current) {
event.preventDefault();
firstFocusableRef.current?.focus();
} else if (event.shiftKey && document.activeElement === firstFocusableRef.current) {
event.preventDefault();
lastFocusableRef.current?.focus();
}
}
};
const onFocusableElementsHandler = () => {
const focusableElements = ref.current?.querySelectorAll(
'input, [href], [tabindex]:not([tabindex="-1"])',
);
if (focusableElements && focusableElements.length > 0) {
firstFocusableRef.current = focusableElements[0] as HTMLElement;
lastFocusableRef.current = focusableElements[focusableElements.length - 1] as HTMLElement;
}
};
useEffect(() => {
document.addEventListener('keydown', onKeyDownHandler);
return () => {
document.removeEventListener('keydown', onKeyDownHandler);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
onFocusableElementsHandler();
});
}