1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-15 09:04:04 +02:00
joplin/packages/app-desktop/gui/DialogButtonRow/useKeyboardHandler.ts

63 lines
1.9 KiB
TypeScript

import { useEffect, useState, useRef, useCallback } from 'react';
import { isInsideContainer } from '@joplin/lib/dom';
interface Props {
onOkButtonClick: Function;
onCancelButtonClick: Function;
}
const globalKeydownHandlers: string[] = [];
export default (props: Props) => {
const [elementId] = useState(`${Math.round(Math.random() * 10000000)}`);
const globalKeydownHandlersRef = useRef(globalKeydownHandlers);
useEffect(() => {
globalKeydownHandlersRef.current.push(elementId);
return () => {
const idx = globalKeydownHandlersRef.current.findIndex(e => e === elementId);
globalKeydownHandlersRef.current.splice(idx, 1);
};
}, []);
const isTopDialog = () => {
const ln = globalKeydownHandlersRef.current.length;
return ln && globalKeydownHandlersRef.current[ln - 1] === elementId;
};
const isInSubModal = (targetElement: any) => {
// If we are inside a sub-modal within the dialog, we shouldn't handle
// global key events. It can be for example the emoji picker. In general
// it's difficult to know whether an element is a modal or not, so we'll
// have to add special cases here. Normally there shouldn't be many of
// these.
if (isInsideContainer(targetElement, 'emoji-picker')) return true;
return false;
};
const onKeyDown = useCallback((event: any) => {
// Early exit if it's neither ENTER nor ESCAPE, because isInSubModal
// function can be costly.
if (event.keyCode !== 13 && event.keyCode !== 27) return;
if (!isTopDialog() || isInSubModal(event.target)) return;
if (event.keyCode === 13) {
if (event.target.nodeName !== 'TEXTAREA') {
props.onOkButtonClick();
}
} else if (event.keyCode === 27) {
props.onCancelButtonClick();
}
}, [props.onOkButtonClick, props.onCancelButtonClick]);
useEffect(() => {
document.addEventListener('keydown', onKeyDown);
return () => {
document.removeEventListener('keydown', onKeyDown);
};
}, [onKeyDown]);
return onKeyDown;
};