diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 5b89e2c3d5..ebc671d550 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -3436,6 +3436,10 @@ "messageformat": "Open sticker chooser", "description": "Shown in the shortcuts guide" }, + "icu:Keyboard--open-gif-chooser": { + "messageformat": "Open GIF chooser", + "description": "Shown in the shortcuts guide" + }, "icu:Keyboard--begin-recording-voice-note": { "messageformat": "Begin recording voice note", "description": "Shown in the shortcuts guide" diff --git a/ts/components/ShortcutGuide.tsx b/ts/components/ShortcutGuide.tsx index c5dd528112..03090e2ea4 100644 --- a/ts/components/ShortcutGuide.tsx +++ b/ts/components/ShortcutGuide.tsx @@ -41,12 +41,15 @@ type KeyType = | 'L' | 'M' | 'N' + | 'O' | 'P' + | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' + | 'W' | 'X' | 'Y' | '1 to 9'; @@ -154,6 +157,11 @@ function getNavigationShortcuts(i18n: LocalizerType): Array { { id: 'Keyboard--open-sticker-chooser', description: i18n('icu:Keyboard--open-sticker-chooser'), + keys: [['commandOrCtrl', 'shift', 'O']], + }, + { + id: 'Keyboard--open-gif-chooser', + description: i18n('icu:Keyboard--open-gif-chooser'), keys: [['commandOrCtrl', 'shift', 'G']], }, { diff --git a/ts/components/fun/FunPicker.tsx b/ts/components/fun/FunPicker.tsx index 542babb0cc..a3eb805e04 100644 --- a/ts/components/fun/FunPicker.tsx +++ b/ts/components/fun/FunPicker.tsx @@ -1,9 +1,10 @@ // Copyright 2025 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import type { ReactNode } from 'react'; -import React, { memo, useCallback } from 'react'; +import React, { memo, useCallback, useEffect } from 'react'; import type { Placement } from 'react-aria'; import { DialogTrigger } from 'react-aria-components'; +import { createKeybindingsHandler } from 'tinykeys'; import { FunPickerTabKey } from './constants'; import { FunPopover } from './base/FunPopover'; import { FunPickerTab, FunTabList, FunTabPanel, FunTabs } from './base/FunTabs'; @@ -38,7 +39,7 @@ export const FunPicker = memo(function FunPicker( ): JSX.Element { const { onOpenChange } = props; const fun = useFunContext(); - const { i18n, onOpenChange: onFunOpenChange } = fun; + const { i18n, onOpenChange: onFunOpenChange, onChangeTab } = fun; const handleOpenChange = useCallback( (open: boolean) => { @@ -52,6 +53,27 @@ export const FunPicker = memo(function FunPicker( handleOpenChange(false); }, [handleOpenChange]); + useEffect(() => { + const onKeyDown = createKeybindingsHandler({ + '$mod+Shift+J': () => { + onChangeTab(FunPickerTabKey.Emoji); + handleOpenChange(true); + }, + '$mod+Shift+O': () => { + onChangeTab(FunPickerTabKey.Stickers); + handleOpenChange(true); + }, + '$mod+Shift+G': () => { + onChangeTab(FunPickerTabKey.Gifs); + handleOpenChange(true); + }, + }); + window.addEventListener('keydown', onKeyDown); + return () => { + window.removeEventListener('keydown', onKeyDown); + }; + }, [handleOpenChange, onChangeTab]); + return ( {props.children}