64 lines
2 KiB
TypeScript
64 lines
2 KiB
TypeScript
import React from 'react';
|
|
|
|
export interface UseDocSearchKeyboardEventsProps {
|
|
isOpen: boolean;
|
|
onOpen: () => void;
|
|
onClose: () => void;
|
|
onInput?: (event: KeyboardEvent) => void;
|
|
searchButtonRef?: React.RefObject<HTMLButtonElement>;
|
|
}
|
|
|
|
function isEditingContent(event: KeyboardEvent): boolean {
|
|
const element = event.target as HTMLElement;
|
|
const tagName = element.tagName;
|
|
|
|
return element.isContentEditable || tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA';
|
|
}
|
|
|
|
export function useDocSearchKeyboardEvents({
|
|
isOpen,
|
|
onOpen,
|
|
onClose,
|
|
onInput,
|
|
searchButtonRef,
|
|
}: UseDocSearchKeyboardEventsProps): void {
|
|
React.useEffect(() => {
|
|
function onKeyDown(event: KeyboardEvent): void {
|
|
if (
|
|
(event.code === 'Escape' && isOpen) ||
|
|
// The `Cmd+K` shortcut both opens and closes the modal.
|
|
// We need to check for `event.key` because it can be `undefined` with
|
|
// Chrome's autofill feature.
|
|
// See https://github.com/paperjs/paper.js/issues/1398
|
|
(event.key?.toLowerCase() === 'k' && (event.metaKey || event.ctrlKey)) ||
|
|
// The `/` shortcut opens but doesn't close the modal because it's
|
|
// a character.
|
|
(!isEditingContent(event) && event.key === '/' && !isOpen)
|
|
) {
|
|
event.preventDefault();
|
|
|
|
if (isOpen) {
|
|
onClose();
|
|
} else if (!document.body.classList.contains('DocSearch--active')) {
|
|
// We check that no other DocSearch modal is showing before opening
|
|
// another one.
|
|
onOpen();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (searchButtonRef && searchButtonRef.current === document.activeElement && onInput) {
|
|
if (/[a-zA-Z0-9]/.test(String.fromCharCode(event.keyCode))) {
|
|
onInput(event);
|
|
}
|
|
}
|
|
}
|
|
|
|
window.addEventListener('keydown', onKeyDown);
|
|
|
|
return (): void => {
|
|
window.removeEventListener('keydown', onKeyDown);
|
|
};
|
|
}, [isOpen, onOpen, onClose, onInput, searchButtonRef]);
|
|
}
|