15
common/resources/client/utils/keybinds/is-ctrl-key-pressed.ts
Executable file
15
common/resources/client/utils/keybinds/is-ctrl-key-pressed.ts
Executable file
@@ -0,0 +1,15 @@
|
||||
import {isMac} from '@react-aria/utils';
|
||||
|
||||
interface Event {
|
||||
altKey: boolean;
|
||||
ctrlKey: boolean;
|
||||
metaKey: boolean;
|
||||
}
|
||||
|
||||
export function isCtrlKeyPressed(e: Event) {
|
||||
if (isMac()) {
|
||||
return e.metaKey;
|
||||
}
|
||||
|
||||
return e.ctrlKey;
|
||||
}
|
||||
12
common/resources/client/utils/keybinds/is-ctrl-or-shift-pressed.ts
Executable file
12
common/resources/client/utils/keybinds/is-ctrl-or-shift-pressed.ts
Executable file
@@ -0,0 +1,12 @@
|
||||
import {isCtrlKeyPressed} from './is-ctrl-key-pressed';
|
||||
|
||||
interface Event {
|
||||
altKey: boolean;
|
||||
ctrlKey: boolean;
|
||||
metaKey: boolean;
|
||||
shiftKey: boolean;
|
||||
}
|
||||
|
||||
export function isCtrlOrShiftPressed(e: Event) {
|
||||
return e.shiftKey || isCtrlKeyPressed(e);
|
||||
}
|
||||
55
common/resources/client/utils/keybinds/use-keybind.ts
Executable file
55
common/resources/client/utils/keybinds/use-keybind.ts
Executable file
@@ -0,0 +1,55 @@
|
||||
import {useGlobalListeners} from '@react-aria/utils';
|
||||
import {useCallbackRef} from '@common/utils/hooks/use-callback-ref';
|
||||
import {useEffect} from 'react';
|
||||
import {isCtrlKeyPressed} from '@common/utils/keybinds/is-ctrl-key-pressed';
|
||||
import {isAnyInputFocused} from '@common/utils/dom/is-any-input-focused';
|
||||
|
||||
interface Options {
|
||||
allowedInputSelector?: string;
|
||||
}
|
||||
|
||||
export function useKeybind(
|
||||
el: HTMLElement | 'window',
|
||||
shortcut: string,
|
||||
userCallback: (e: KeyboardEvent) => void,
|
||||
{allowedInputSelector}: Options = {},
|
||||
) {
|
||||
const {addGlobalListener, removeAllGlobalListeners} = useGlobalListeners();
|
||||
const callback = useCallbackRef(userCallback);
|
||||
|
||||
useEffect(() => {
|
||||
const target = el === 'window' ? window : el;
|
||||
addGlobalListener(target, 'keydown', (e: KeyboardEvent) => {
|
||||
if (!shouldIgnoreActiveEl(allowedInputSelector) && isAnyInputFocused()) {
|
||||
return;
|
||||
}
|
||||
const matches = shortcut.split('+').every(key => {
|
||||
if (key === 'ctrl') {
|
||||
return isCtrlKeyPressed(e);
|
||||
} else {
|
||||
return e.key === key;
|
||||
}
|
||||
});
|
||||
if (matches) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
callback(e);
|
||||
}
|
||||
});
|
||||
return removeAllGlobalListeners;
|
||||
}, [
|
||||
addGlobalListener,
|
||||
shortcut,
|
||||
removeAllGlobalListeners,
|
||||
callback,
|
||||
el,
|
||||
allowedInputSelector,
|
||||
]);
|
||||
}
|
||||
|
||||
function shouldIgnoreActiveEl(selector?: string) {
|
||||
if (!selector || !document.activeElement) {
|
||||
return false;
|
||||
}
|
||||
return (document.activeElement as HTMLElement).closest(selector);
|
||||
}
|
||||
Reference in New Issue
Block a user