Adds keyboard shortcut to open context menu on messages
This commit is contained in:
parent
498205b964
commit
7247c2d674
5 changed files with 114 additions and 14 deletions
|
@ -2934,6 +2934,10 @@
|
|||
"messageformat": "Mark selected text as a spoiler",
|
||||
"description": "Description of command to bold text in composer"
|
||||
},
|
||||
"icu:Keyboard--open-context-menu": {
|
||||
"messageformat": "Open context menu for selected message",
|
||||
"description": "Shown in shortcuts guide"
|
||||
},
|
||||
"icu:FormatMenu--guide--bold": {
|
||||
"messageformat": "Bold",
|
||||
"description": "Shown when you hover over the bold button in the popup formatting menu"
|
||||
|
|
|
@ -24,6 +24,8 @@ type KeyType =
|
|||
| 'tab'
|
||||
| 'ctrl'
|
||||
| 'F6'
|
||||
| 'F10'
|
||||
| 'F12'
|
||||
| '↑'
|
||||
| '↓'
|
||||
| ','
|
||||
|
@ -53,8 +55,17 @@ type KeyType =
|
|||
type ShortcutType = {
|
||||
id: string;
|
||||
description: string;
|
||||
keys: Array<Array<KeyType>>;
|
||||
};
|
||||
} & (
|
||||
| {
|
||||
keys: Array<Array<KeyType>>;
|
||||
}
|
||||
| {
|
||||
keysByPlatform: {
|
||||
macOS: Array<Array<KeyType>>;
|
||||
other: Array<Array<KeyType>>;
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
function getNavigationShortcuts(i18n: LocalizerType): Array<ShortcutType> {
|
||||
return [
|
||||
|
@ -217,6 +228,14 @@ function getMessageShortcuts(i18n: LocalizerType): Array<ShortcutType> {
|
|||
description: i18n('icu:Keyboard--forward-messages'),
|
||||
keys: [['commandOrCtrl', 'shift', 'S']],
|
||||
},
|
||||
{
|
||||
id: 'Keyboard--open-context-menu',
|
||||
description: i18n('icu:Keyboard--open-context-menu'),
|
||||
keysByPlatform: {
|
||||
macOS: [['commandOrCtrl', 'F12']],
|
||||
other: [['shift', 'F10']],
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -439,13 +458,23 @@ function renderShortcut(
|
|||
isMacOS: boolean,
|
||||
i18n: LocalizerType
|
||||
) {
|
||||
let keysToRender: Array<Array<KeyType>> = [];
|
||||
|
||||
if ('keys' in shortcut) {
|
||||
keysToRender = shortcut.keys;
|
||||
} else if ('keysByPlatform' in shortcut) {
|
||||
keysToRender = isMacOS
|
||||
? shortcut.keysByPlatform.macOS
|
||||
: shortcut.keysByPlatform.other;
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={index} className="module-shortcut-guide__shortcut">
|
||||
<div className="module-shortcut-guide__shortcut__description">
|
||||
{shortcut.description}
|
||||
</div>
|
||||
<div className="module-shortcut-guide__shortcut__key-container">
|
||||
{shortcut.keys.map(keys => (
|
||||
{keysToRender.map(keys => (
|
||||
<div
|
||||
key={`${shortcut.description}--${keys.map(k => k).join('-')}`}
|
||||
className="module-shortcut-guide__shortcut__key-inner-container"
|
||||
|
|
|
@ -26,7 +26,11 @@ import type {
|
|||
import type { PushPanelForConversationActionType } from '../../state/ducks/conversations';
|
||||
import { doesMessageBodyOverflow } from './MessageBodyReadMore';
|
||||
import type { Props as ReactionPickerProps } from './ReactionPicker';
|
||||
import { useToggleReactionPicker } from '../../hooks/useKeyboardShortcuts';
|
||||
import {
|
||||
useKeyboardShortcutsConditionally,
|
||||
useOpenContextMenu,
|
||||
useToggleReactionPicker,
|
||||
} from '../../hooks/useKeyboardShortcuts';
|
||||
import { PanelType } from '../../types/Panels';
|
||||
import type { DeleteMessagesPropsType } from '../../state/ducks/globalModals';
|
||||
|
||||
|
@ -73,7 +77,9 @@ export type Props = PropsData &
|
|||
};
|
||||
|
||||
type Trigger = {
|
||||
handleContextClick: (event: React.MouseEvent<HTMLDivElement>) => void;
|
||||
handleContextClick: (
|
||||
event: React.MouseEvent<HTMLDivElement> | MouseEvent
|
||||
) => void;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -265,15 +271,21 @@ export function TimelineMessage(props: Props): JSX.Element {
|
|||
handleReact || noop
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isTargeted) {
|
||||
document.addEventListener('keydown', toggleReactionPickerKeyboard);
|
||||
const handleOpenContextMenu = useCallback(() => {
|
||||
if (!menuTriggerRef.current) {
|
||||
return;
|
||||
}
|
||||
const event = new MouseEvent('click');
|
||||
menuTriggerRef.current.handleContextClick(event);
|
||||
}, []);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('keydown', toggleReactionPickerKeyboard);
|
||||
};
|
||||
}, [isTargeted, toggleReactionPickerKeyboard]);
|
||||
const openContextMenuKeyboard = useOpenContextMenu(handleOpenContextMenu);
|
||||
|
||||
useKeyboardShortcutsConditionally(
|
||||
Boolean(isTargeted),
|
||||
openContextMenuKeyboard,
|
||||
toggleReactionPickerKeyboard
|
||||
);
|
||||
|
||||
const renderMenu = useCallback(() => {
|
||||
return (
|
||||
|
|
|
@ -234,6 +234,39 @@ export function useToggleReactionPicker(
|
|||
);
|
||||
}
|
||||
|
||||
export function useOpenContextMenu(
|
||||
openContextMenu: () => unknown
|
||||
): KeyboardShortcutHandlerType {
|
||||
const hasOverlay = useHasAnyOverlay();
|
||||
|
||||
return useCallback(
|
||||
ev => {
|
||||
if (hasOverlay) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { shiftKey } = ev;
|
||||
const key = KeyboardLayout.lookup(ev);
|
||||
|
||||
const isMacOS = get(window, 'platform') === 'darwin';
|
||||
|
||||
if (
|
||||
(!isMacOS && shiftKey && key === 'F10') ||
|
||||
(isMacOS && isCmdOrCtrl(ev) && key === 'F12')
|
||||
) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
openContextMenu();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
[hasOverlay, openContextMenu]
|
||||
);
|
||||
}
|
||||
|
||||
export function useEditLastMessageSent(
|
||||
maybeEditMessage: () => boolean
|
||||
): KeyboardShortcutHandlerType {
|
||||
|
@ -277,3 +310,23 @@ export function useKeyboardShortcuts(
|
|||
};
|
||||
}, [eventHandlers]);
|
||||
}
|
||||
|
||||
export function useKeyboardShortcutsConditionally(
|
||||
condition: boolean,
|
||||
...eventHandlers: Array<KeyboardShortcutHandlerType>
|
||||
): void {
|
||||
useEffect(() => {
|
||||
if (!condition) {
|
||||
return;
|
||||
}
|
||||
|
||||
function handleKeydown(ev: KeyboardEvent): void {
|
||||
eventHandlers.some(eventHandler => eventHandler(ev));
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', handleKeydown);
|
||||
return () => {
|
||||
document.removeEventListener('keydown', handleKeydown);
|
||||
};
|
||||
}, [condition, eventHandlers]);
|
||||
}
|
||||
|
|
|
@ -11,11 +11,13 @@ import { getQuotedMessageSelector } from '../state/selectors/composer';
|
|||
import { removeLinkPreview } from './LinkPreview';
|
||||
|
||||
export function addGlobalKeyboardShortcuts(): void {
|
||||
const isMacOS = window.platform === 'darwin';
|
||||
|
||||
document.addEventListener('keydown', event => {
|
||||
const { ctrlKey, metaKey, shiftKey, altKey } = event;
|
||||
|
||||
const commandKey = window.platform === 'darwin' && metaKey;
|
||||
const controlKey = window.platform !== 'darwin' && ctrlKey;
|
||||
const commandKey = isMacOS && metaKey;
|
||||
const controlKey = !isMacOS && ctrlKey;
|
||||
const commandOrCtrl = commandKey || controlKey;
|
||||
|
||||
const state = window.reduxStore.getState();
|
||||
|
|
Loading…
Reference in a new issue