Skip to content

Commit c8ae87b

Browse files
committed
♿(frontend) restore toolbar shortcuts inside PiP window
Forward PiP keydown events and register PiP-specific handlers.
1 parent 636d298 commit c8ae87b

4 files changed

Lines changed: 66 additions & 3 deletions

File tree

src/frontend/src/features/pip/components/PipControlBar.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { styled } from '@/styled-system/jsx'
2-
import { useRef, useMemo } from 'react'
2+
import { useRef, useMemo, useCallback } from 'react'
33
import { useTranslation } from 'react-i18next'
4+
import { useRegisterKeyboardShortcut } from '@/features/shortcuts/useRegisterKeyboardShortcut'
5+
import { findFirstFocusable } from '@/utils/dom'
46
import { AudioDevicesControl } from '@/features/rooms/livekit/components/controls/Device/AudioDevicesControl'
57
import { VideoDeviceControl } from '@/features/rooms/livekit/components/controls/Device/VideoDeviceControl'
68
import { ScreenShareToggle } from '@/features/rooms/livekit/components/controls/ScreenShareToggle'
@@ -64,6 +66,14 @@ export const PipControlBar = ({
6466
[width, showScreenShare]
6567
)
6668

69+
useRegisterKeyboardShortcut({
70+
id: 'focus-toolbar',
71+
handler: useCallback(() => {
72+
const doc = containerRef.current?.ownerDocument ?? document
73+
findFirstFocusable(doc.getElementById('pip-control-bar'))?.focus()
74+
}, []),
75+
})
76+
6777
return (
6878
<PipControls
6979
ref={containerRef}

src/frontend/src/features/pip/components/PipReactionsToggle.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1+
import { useCallback } from 'react'
12
import { useTranslation } from 'react-i18next'
23
import { RiEmotionLine } from '@remixicon/react'
34
import { ToggleButton } from '@/primitives'
45
import { useSnapshot } from 'valtio'
56
import { pipLayoutStore } from '../stores/pipLayoutStore'
7+
import { useRegisterKeyboardShortcut } from '@/features/shortcuts/useRegisterKeyboardShortcut'
68

79
export const PipReactionsToggle = () => {
810
const { t } = useTranslation('rooms', { keyPrefix: 'controls.reactions' })
911
const { showReactionsToolbar: isOpen } = useSnapshot(pipLayoutStore)
1012

11-
const toggle = () => {
13+
const toggle = useCallback(() => {
1214
pipLayoutStore.showReactionsToolbar = !pipLayoutStore.showReactionsToolbar
13-
}
15+
}, [])
16+
17+
useRegisterKeyboardShortcut({ id: 'reaction', handler: toggle })
1418

1519
return (
1620
<ToggleButton

src/frontend/src/features/pip/components/PipView.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { SidePanel } from '@/features/rooms/livekit/components/SidePanel'
66
import { useSidePanel } from '@/features/rooms/livekit/hooks/useSidePanel'
77
import { pipLayoutStore } from '../stores/pipLayoutStore'
88
import { useEscapeDismiss } from '../hooks/useEscapeDismiss'
9+
import { usePipKeyboardShortcuts } from '../hooks/usePipKeyboardShortcuts'
910
import { usePipRestoreFocus } from '../hooks/usePipRestoreFocus'
1011
import { PipControlBar } from './PipControlBar'
1112
import { PipReactionsToolbar } from './PipReactionsToolbar'
@@ -22,6 +23,9 @@ export const PipView = () => {
2223
// Escape closes the side panel instead of the whole PiP window.
2324
useEscapeDismiss(containerRef, isSidePanelOpen, closePanel)
2425

26+
// Forward keyboard shortcuts (Ctrl+D, Ctrl+E, etc.) to the main store.
27+
usePipKeyboardShortcuts(containerRef)
28+
2529
// Side panels open via a menu item that unmounts on click; fall back to the
2630
// options button so focus returns somewhere visible.
2731
const resolveTrigger = useCallback((activeEl: HTMLElement | null) => {
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { useEffect, type RefObject } from 'react'
2+
import { keyboardShortcutsStore } from '@/stores/keyboardShortcuts'
3+
import { formatShortcutKey } from '@/features/shortcuts/utils'
4+
import { isMacintosh } from '@/utils/livekit'
5+
6+
/**
7+
* Mirror the main-window keyboard shortcuts inside the PiP document.
8+
*
9+
* The central `useKeyboardShortcuts` hook listens on `window`, which is the
10+
* main document's window. Keydown events from the PiP document never reach
11+
* it. This hook attaches the same dispatch logic to the PiP document so that
12+
* Ctrl+D (mic), Ctrl+E (cam), etc. work identically in both contexts.
13+
*/
14+
export const usePipKeyboardShortcuts = (
15+
containerRef: RefObject<HTMLElement | null>
16+
) => {
17+
useEffect(() => {
18+
const doc = containerRef.current?.ownerDocument
19+
if (!doc || doc === document) return
20+
21+
const onKeyDown = (e: KeyboardEvent) => {
22+
const { key, metaKey, ctrlKey, shiftKey, altKey } = e
23+
if (!key) return
24+
25+
const shortcutKey = formatShortcutKey({
26+
key,
27+
ctrlKey: ctrlKey || (isMacintosh() && metaKey),
28+
shiftKey,
29+
altKey,
30+
})
31+
32+
let handler = keyboardShortcutsStore.shortcuts.get(shortcutKey)
33+
if (!handler && shortcutKey === 'ctrl+shift+?') {
34+
handler = keyboardShortcutsStore.shortcuts.get('ctrl+shift+/')
35+
}
36+
if (!handler) return
37+
38+
e.preventDefault()
39+
handler()
40+
}
41+
42+
doc.addEventListener('keydown', onKeyDown)
43+
return () => doc.removeEventListener('keydown', onKeyDown)
44+
}, [containerRef])
45+
}

0 commit comments

Comments
 (0)