Create global keyboard shortcut handler (#10145)

This commit is contained in:
DS Boyce
2026-04-03 10:06:51 -07:00
committed by GitHub
parent e0ea778e58
commit cca3326b21
16 changed files with 257 additions and 182 deletions
@@ -1,77 +0,0 @@
import {useEffect} from 'react'
import {useOpenComposer} from '#/lib/hooks/useOpenComposer'
import {useDialogStateContext} from '#/state/dialogs'
import {useLightbox} from '#/state/lightbox'
import {useModals} from '#/state/modals'
import {useSession} from '#/state/session'
import {useIsDrawerOpen} from '#/state/shell/drawer-open'
/**
* Based on {@link https://github.com/jaywcjlove/hotkeys-js/blob/b0038773f3b902574f22af747f3bb003a850f1da/src/index.js#L51C1-L64C2}
*/
function shouldIgnore(event: KeyboardEvent) {
const target: any = event.target || event.srcElement
if (!target) return false
const {tagName} = target
if (!tagName) return false
const isInput =
tagName === 'INPUT' &&
![
'checkbox',
'radio',
'range',
'button',
'file',
'reset',
'submit',
'color',
].includes(target.type)
// ignore: isContentEditable === 'true', <input> and <textarea> when readOnly state is false, <select>
if (
target.isContentEditable ||
((isInput || tagName === 'TEXTAREA' || tagName === 'SELECT') &&
!target.readOnly)
) {
return true
}
return false
}
export function useComposerKeyboardShortcut() {
const {openComposer} = useOpenComposer()
const {openDialogs} = useDialogStateContext()
const {isModalActive} = useModals()
const {activeLightbox} = useLightbox()
const isDrawerOpen = useIsDrawerOpen()
const {hasSession} = useSession()
useEffect(() => {
if (!hasSession) {
return
}
function handler(event: KeyboardEvent) {
if (shouldIgnore(event)) return
if (
openDialogs?.current.size > 0 ||
isModalActive ||
activeLightbox ||
isDrawerOpen
)
return
if (event.key === 'n' || event.key === 'N') {
openComposer({logContext: 'Other'})
}
}
document.addEventListener('keydown', handler)
return () => document.removeEventListener('keydown', handler)
}, [
openComposer,
isModalActive,
openDialogs,
activeLightbox,
isDrawerOpen,
hasSession,
])
}
+15 -1
View File
@@ -1,5 +1,7 @@
import {createContext, useContext, useState} from 'react'
import {useHotkeysContext} from '#/lib/hotkeys'
type StateContext = boolean
type SetContext = (v: boolean) => void
@@ -10,10 +12,22 @@ setContext.displayName = 'DrawerOpenSetContext'
export function Provider({children}: React.PropsWithChildren<{}>) {
const [state, setState] = useState(false)
const {disableScope, enableScope} = useHotkeysContext()
const setDrawerOpen = (open: boolean) => {
if (open) {
disableScope('global')
} else {
enableScope('global')
}
setState(open)
}
return (
<stateContext.Provider value={state}>
<setContext.Provider value={setState}>{children}</setContext.Provider>
<setContext.Provider value={setDrawerOpen}>
{children}
</setContext.Provider>
</stateContext.Provider>
)
}