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 });
|
openChat({ id: currentUserId });
|
||||||
}, [currentUserId, openChat]);
|
}, [currentUserId, openChat]);
|
||||||
|
|
||||||
useHotkeys([
|
useHotkeys({
|
||||||
['mod+shift+F', handleHotkeySearch],
|
'mod+shift+F': handleHotkeySearch,
|
||||||
['mod+shift+S', handleHotkeySavedMessages],
|
'mod+shift+S': handleHotkeySavedMessages,
|
||||||
]);
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
clearTwoFaError();
|
clearTwoFaError();
|
||||||
|
|||||||
@ -163,7 +163,7 @@ const ChatFolders: FC<OwnProps & StateProps> = ({
|
|||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener('keydown', handleKeyDown, true);
|
document.removeEventListener('keydown', handleKeyDown, true);
|
||||||
};
|
};
|
||||||
});
|
}, [currentUserId, folderTabs, openChat, setActiveChatFolder]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
shouldRender: shouldRenderPlaceholder, transitionClassNames,
|
shouldRender: shouldRenderPlaceholder, transitionClassNames,
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import usePrevious from '../../../hooks/usePrevious';
|
|||||||
import useInfiniteScroll from '../../../hooks/useInfiniteScroll';
|
import useInfiniteScroll from '../../../hooks/useInfiniteScroll';
|
||||||
import { useFolderManagerForOrderedIds } from '../../../hooks/useFolderManager';
|
import { useFolderManagerForOrderedIds } from '../../../hooks/useFolderManager';
|
||||||
import { useChatAnimationType } from './hooks';
|
import { useChatAnimationType } from './hooks';
|
||||||
import { HotkeyItem, useHotkeys } from '../../../hooks/useHotkeys';
|
import { useHotkeys } from '../../../hooks/useHotkeys';
|
||||||
|
|
||||||
import InfiniteScroll from '../../ui/InfiniteScroll';
|
import InfiniteScroll from '../../ui/InfiniteScroll';
|
||||||
import Loading from '../../ui/Loading';
|
import Loading from '../../ui/Loading';
|
||||||
@ -76,19 +76,16 @@ const ChatList: FC<OwnProps> = ({
|
|||||||
const [viewportIds, getMore] = useInfiniteScroll(undefined, orderedIds, undefined, CHAT_LIST_SLICE);
|
const [viewportIds, getMore] = useInfiniteScroll(undefined, orderedIds, undefined, CHAT_LIST_SLICE);
|
||||||
|
|
||||||
// Support <Alt>+<Up/Down> to navigate between chats
|
// Support <Alt>+<Up/Down> to navigate between chats
|
||||||
const hotkeys: HotkeyItem[] = [];
|
useHotkeys(isActive && orderedIds?.length ? {
|
||||||
if (isActive && orderedIds?.length) {
|
'alt+ArrowUp': (e: KeyboardEvent) => {
|
||||||
hotkeys.push(['alt+ArrowUp', (e: KeyboardEvent) => {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
openNextChat({ targetIndexDelta: -1, orderedIds });
|
openNextChat({ targetIndexDelta: -1, orderedIds });
|
||||||
}]);
|
},
|
||||||
hotkeys.push(['alt+ArrowDown', (e: KeyboardEvent) => {
|
'alt+ArrowDown': (e: KeyboardEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
openNextChat({ targetIndexDelta: 1, orderedIds });
|
openNextChat({ targetIndexDelta: 1, orderedIds });
|
||||||
}]);
|
},
|
||||||
}
|
} : undefined);
|
||||||
|
|
||||||
useHotkeys(hotkeys);
|
|
||||||
|
|
||||||
// Support <Cmd>+<Digit> to navigate between chats
|
// Support <Cmd>+<Digit> to navigate between chats
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -151,9 +151,9 @@ const HeaderActions: FC<OwnProps & StateProps> = ({
|
|||||||
handleSearchClick();
|
handleSearchClick();
|
||||||
}, [canSearch, handleSearchClick]);
|
}, [canSearch, handleSearchClick]);
|
||||||
|
|
||||||
useHotkeys([
|
useHotkeys({
|
||||||
['meta+F', handleHotkeySearchClick],
|
'meta+F': handleHotkeySearchClick,
|
||||||
]);
|
});
|
||||||
|
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ const useCopySelectedMessages = (isActive: boolean, copySelectedMessages: NoneTo
|
|||||||
copySelectedMessages();
|
copySelectedMessages();
|
||||||
}
|
}
|
||||||
|
|
||||||
useHotkeys([['meta+C', handleCopy]]);
|
useHotkeys({ 'meta+C': handleCopy });
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useCopySelectedMessages;
|
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 { 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) {
|
export function useHotkeys(hotkeys?: Record<string, (e: KeyboardEvent) => void>) {
|
||||||
if (event.target instanceof HTMLElement) {
|
|
||||||
return !['INPUT', 'TEXTAREA', 'SELECT'].includes(event.target.tagName);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useHotkeys(hotkeys: HotkeyItem[]) {
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const keydownListener = (event: KeyboardEvent) => {
|
if (!hotkeys) {
|
||||||
hotkeys.forEach(([hotkey, handler]) => {
|
return undefined;
|
||||||
if (getHotkeyMatcher(hotkey)(event) && shouldFireEvent(event)) {
|
}
|
||||||
handler(event);
|
|
||||||
|
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 handlers.addCallback(handleKeyDown);
|
||||||
return () => document.documentElement.removeEventListener('keydown', keydownListener);
|
|
||||||
}, [hotkeys]);
|
}, [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;
|
export default useNativeCopySelectedMessages;
|
||||||
|
|||||||
@ -13,8 +13,6 @@ export type Hotkey = KeyboardModifiers & {
|
|||||||
key?: string;
|
key?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type HotkeyItem = [string, (event: React.KeyboardEvent<HTMLElement>) => void];
|
|
||||||
|
|
||||||
type CheckHotkeyMatch = (event: KeyboardEvent) => boolean;
|
type CheckHotkeyMatch = (event: KeyboardEvent) => boolean;
|
||||||
|
|
||||||
export function parseHotkey(hotkey: string): Hotkey {
|
export function parseHotkey(hotkey: string): Hotkey {
|
||||||
@ -77,14 +75,3 @@ function isExactHotkey(hotkey: Hotkey, event: KeyboardEvent): boolean {
|
|||||||
export function getHotkeyMatcher(hotkey: string): CheckHotkeyMatch {
|
export function getHotkeyMatcher(hotkey: string): CheckHotkeyMatch {
|
||||||
return (event) => isExactHotkey(parseHotkey(hotkey), event);
|
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