Refactoring and optimizations for useHotkeys
This commit is contained in:
parent
f91960b90c
commit
84ea8e480e
@ -282,10 +282,10 @@ const LeftColumn: FC<StateProps> = ({
|
||||
openChat({ id: currentUserId });
|
||||
}, [currentUserId, openChat]);
|
||||
|
||||
useHotkeys([
|
||||
['mod+shift+F', handleHotkeySearch],
|
||||
['mod+shift+S', handleHotkeySavedMessages],
|
||||
]);
|
||||
useHotkeys({
|
||||
'mod+shift+F': handleHotkeySearch,
|
||||
'mod+shift+S': handleHotkeySavedMessages,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
clearTwoFaError();
|
||||
|
||||
@ -163,7 +163,7 @@ const ChatFolders: FC<OwnProps & StateProps> = ({
|
||||
return () => {
|
||||
document.removeEventListener('keydown', handleKeyDown, true);
|
||||
};
|
||||
});
|
||||
}, [currentUserId, folderTabs, openChat, setActiveChatFolder]);
|
||||
|
||||
const {
|
||||
shouldRender: shouldRenderPlaceholder, transitionClassNames,
|
||||
|
||||
@ -19,7 +19,7 @@ import usePrevious from '../../../hooks/usePrevious';
|
||||
import useInfiniteScroll from '../../../hooks/useInfiniteScroll';
|
||||
import { useFolderManagerForOrderedIds } from '../../../hooks/useFolderManager';
|
||||
import { useChatAnimationType } from './hooks';
|
||||
import { HotkeyItem, useHotkeys } from '../../../hooks/useHotkeys';
|
||||
import { useHotkeys } from '../../../hooks/useHotkeys';
|
||||
|
||||
import InfiniteScroll from '../../ui/InfiniteScroll';
|
||||
import Loading from '../../ui/Loading';
|
||||
@ -76,19 +76,16 @@ const ChatList: FC<OwnProps> = ({
|
||||
const [viewportIds, getMore] = useInfiniteScroll(undefined, orderedIds, undefined, CHAT_LIST_SLICE);
|
||||
|
||||
// Support <Alt>+<Up/Down> to navigate between chats
|
||||
const hotkeys: HotkeyItem[] = [];
|
||||
if (isActive && orderedIds?.length) {
|
||||
hotkeys.push(['alt+ArrowUp', (e: KeyboardEvent) => {
|
||||
useHotkeys(isActive && orderedIds?.length ? {
|
||||
'alt+ArrowUp': (e: KeyboardEvent) => {
|
||||
e.preventDefault();
|
||||
openNextChat({ targetIndexDelta: -1, orderedIds });
|
||||
}]);
|
||||
hotkeys.push(['alt+ArrowDown', (e: KeyboardEvent) => {
|
||||
},
|
||||
'alt+ArrowDown': (e: KeyboardEvent) => {
|
||||
e.preventDefault();
|
||||
openNextChat({ targetIndexDelta: 1, orderedIds });
|
||||
}]);
|
||||
}
|
||||
|
||||
useHotkeys(hotkeys);
|
||||
},
|
||||
} : undefined);
|
||||
|
||||
// Support <Cmd>+<Digit> to navigate between chats
|
||||
useEffect(() => {
|
||||
|
||||
@ -151,9 +151,9 @@ const HeaderActions: FC<OwnProps & StateProps> = ({
|
||||
handleSearchClick();
|
||||
}, [canSearch, handleSearchClick]);
|
||||
|
||||
useHotkeys([
|
||||
['meta+F', handleHotkeySearchClick],
|
||||
]);
|
||||
useHotkeys({
|
||||
'meta+F': handleHotkeySearchClick,
|
||||
});
|
||||
|
||||
const lang = useLang();
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ const useCopySelectedMessages = (isActive: boolean, copySelectedMessages: NoneTo
|
||||
copySelectedMessages();
|
||||
}
|
||||
|
||||
useHotkeys([['meta+C', handleCopy]]);
|
||||
useHotkeys({ 'meta+C': handleCopy });
|
||||
};
|
||||
|
||||
export default useCopySelectedMessages;
|
||||
|
||||
@ -1,31 +1,40 @@
|
||||
// Original source from Mantine
|
||||
// https://github.com/mantinedev/mantine/blob/master/src/mantine-hooks/src/use-hotkeys/
|
||||
|
||||
import { useEffect } from '../lib/teact/teact';
|
||||
import { getHotkeyHandler, getHotkeyMatcher } from '../util/parseHotkey';
|
||||
import { getHotkeyMatcher } from '../util/parseHotkey';
|
||||
import { createCallbackManager } from '../util/callbacks';
|
||||
|
||||
export { getHotkeyHandler };
|
||||
const IGNORE_TAGS = new Set(['INPUT', 'TEXTAREA', 'SELECT']);
|
||||
|
||||
export type HotkeyItem = [string, (event: KeyboardEvent) => void];
|
||||
const handlers = createCallbackManager();
|
||||
document.documentElement.addEventListener('keydown', handlers.runCallbacks);
|
||||
|
||||
function shouldFireEvent(event: KeyboardEvent) {
|
||||
if (event.target instanceof HTMLElement) {
|
||||
return !['INPUT', 'TEXTAREA', 'SELECT'].includes(event.target.tagName);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export function useHotkeys(hotkeys: HotkeyItem[]) {
|
||||
export function useHotkeys(hotkeys?: Record<string, (e: KeyboardEvent) => void>) {
|
||||
useEffect(() => {
|
||||
const keydownListener = (event: KeyboardEvent) => {
|
||||
hotkeys.forEach(([hotkey, handler]) => {
|
||||
if (getHotkeyMatcher(hotkey)(event) && shouldFireEvent(event)) {
|
||||
handler(event);
|
||||
if (!hotkeys) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const entries = Object.entries(hotkeys);
|
||||
|
||||
function handleKeyDown(e: KeyboardEvent) {
|
||||
if (!shouldFireEvent(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
entries.forEach(([hotkey, handler]) => {
|
||||
if (getHotkeyMatcher(hotkey)(e)) {
|
||||
handler(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
document.documentElement.addEventListener('keydown', keydownListener);
|
||||
return () => document.documentElement.removeEventListener('keydown', keydownListener);
|
||||
return handlers.addCallback(handleKeyDown);
|
||||
}, [hotkeys]);
|
||||
}
|
||||
|
||||
function shouldFireEvent(e: KeyboardEvent) {
|
||||
if (e.target instanceof HTMLElement) {
|
||||
return !IGNORE_TAGS.has(e.target.tagName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ const useNativeCopySelectedMessages = (copyMessagesByIds: ({ messageIds }: { mes
|
||||
}
|
||||
}
|
||||
|
||||
useHotkeys([['meta+C', handleCopy]]);
|
||||
useHotkeys({ 'meta+C': handleCopy });
|
||||
};
|
||||
|
||||
export default useNativeCopySelectedMessages;
|
||||
|
||||
@ -13,8 +13,6 @@ export type Hotkey = KeyboardModifiers & {
|
||||
key?: string;
|
||||
};
|
||||
|
||||
type HotkeyItem = [string, (event: React.KeyboardEvent<HTMLElement>) => void];
|
||||
|
||||
type CheckHotkeyMatch = (event: KeyboardEvent) => boolean;
|
||||
|
||||
export function parseHotkey(hotkey: string): Hotkey {
|
||||
@ -77,14 +75,3 @@ function isExactHotkey(hotkey: Hotkey, event: KeyboardEvent): boolean {
|
||||
export function getHotkeyMatcher(hotkey: string): CheckHotkeyMatch {
|
||||
return (event) => isExactHotkey(parseHotkey(hotkey), event);
|
||||
}
|
||||
|
||||
export function getHotkeyHandler(hotkeys: HotkeyItem[]) {
|
||||
return (event: React.KeyboardEvent<HTMLElement>) => {
|
||||
hotkeys.forEach(([hotkey, handler]) => {
|
||||
if (getHotkeyMatcher(hotkey)(event.nativeEvent)) {
|
||||
event.preventDefault();
|
||||
handler(event);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user