mirror of
https://github.com/suitenumerique/meet.git
synced 2026-08-25 17:57:09 +00:00
♿(frontend) restore toolbar shortcuts inside PiP window
Forward PiP keydown events and register PiP-specific handlers.
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
import { styled } from '@/styled-system/jsx'
|
import { styled } from '@/styled-system/jsx'
|
||||||
import { useRef, useMemo } from 'react'
|
import { useRef, useMemo, useCallback } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { useRegisterKeyboardShortcut } from '@/features/shortcuts/useRegisterKeyboardShortcut'
|
||||||
|
import { findFirstFocusable } from '@/utils/dom'
|
||||||
import { AudioDevicesControl } from '@/features/rooms/livekit/components/controls/Device/AudioDevicesControl'
|
import { AudioDevicesControl } from '@/features/rooms/livekit/components/controls/Device/AudioDevicesControl'
|
||||||
import { VideoDeviceControl } from '@/features/rooms/livekit/components/controls/Device/VideoDeviceControl'
|
import { VideoDeviceControl } from '@/features/rooms/livekit/components/controls/Device/VideoDeviceControl'
|
||||||
import { ScreenShareToggle } from '@/features/rooms/livekit/components/controls/ScreenShareToggle'
|
import { ScreenShareToggle } from '@/features/rooms/livekit/components/controls/ScreenShareToggle'
|
||||||
@@ -64,6 +66,14 @@ export const PipControlBar = ({
|
|||||||
[width, showScreenShare]
|
[width, showScreenShare]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
useRegisterKeyboardShortcut({
|
||||||
|
id: 'focus-toolbar',
|
||||||
|
handler: useCallback(() => {
|
||||||
|
const doc = containerRef.current?.ownerDocument ?? document
|
||||||
|
findFirstFocusable(doc.getElementById('pip-control-bar'))?.focus()
|
||||||
|
}, []),
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PipControls
|
<PipControls
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
|
import { useCallback } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { RiEmotionLine } from '@remixicon/react'
|
import { RiEmotionLine } from '@remixicon/react'
|
||||||
import { ToggleButton } from '@/primitives'
|
import { ToggleButton } from '@/primitives'
|
||||||
import { useSnapshot } from 'valtio'
|
import { useSnapshot } from 'valtio'
|
||||||
import { pipLayoutStore } from '../stores/pipLayoutStore'
|
import { pipLayoutStore } from '../stores/pipLayoutStore'
|
||||||
|
import { useRegisterKeyboardShortcut } from '@/features/shortcuts/useRegisterKeyboardShortcut'
|
||||||
|
|
||||||
export const PipReactionsToggle = () => {
|
export const PipReactionsToggle = () => {
|
||||||
const { t } = useTranslation('rooms', { keyPrefix: 'controls.reactions' })
|
const { t } = useTranslation('rooms', { keyPrefix: 'controls.reactions' })
|
||||||
const { showReactionsToolbar: isOpen } = useSnapshot(pipLayoutStore)
|
const { showReactionsToolbar: isOpen } = useSnapshot(pipLayoutStore)
|
||||||
|
|
||||||
const toggle = () => {
|
const toggle = useCallback(() => {
|
||||||
pipLayoutStore.showReactionsToolbar = !pipLayoutStore.showReactionsToolbar
|
pipLayoutStore.showReactionsToolbar = !pipLayoutStore.showReactionsToolbar
|
||||||
}
|
}, [])
|
||||||
|
|
||||||
|
useRegisterKeyboardShortcut({ id: 'reaction', handler: toggle })
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ToggleButton
|
<ToggleButton
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { SidePanel } from '@/features/rooms/livekit/components/SidePanel'
|
|||||||
import { useSidePanel } from '@/features/rooms/livekit/hooks/useSidePanel'
|
import { useSidePanel } from '@/features/rooms/livekit/hooks/useSidePanel'
|
||||||
import { pipLayoutStore } from '../stores/pipLayoutStore'
|
import { pipLayoutStore } from '../stores/pipLayoutStore'
|
||||||
import { useEscapeDismiss } from '../hooks/useEscapeDismiss'
|
import { useEscapeDismiss } from '../hooks/useEscapeDismiss'
|
||||||
|
import { usePipKeyboardShortcuts } from '../hooks/usePipKeyboardShortcuts'
|
||||||
import { usePipRestoreFocus } from '../hooks/usePipRestoreFocus'
|
import { usePipRestoreFocus } from '../hooks/usePipRestoreFocus'
|
||||||
import { PipControlBar } from './PipControlBar'
|
import { PipControlBar } from './PipControlBar'
|
||||||
import { PipReactionsToolbar } from './PipReactionsToolbar'
|
import { PipReactionsToolbar } from './PipReactionsToolbar'
|
||||||
@@ -22,6 +23,9 @@ export const PipView = () => {
|
|||||||
// Escape closes the side panel instead of the whole PiP window.
|
// Escape closes the side panel instead of the whole PiP window.
|
||||||
useEscapeDismiss(containerRef, isSidePanelOpen, closePanel)
|
useEscapeDismiss(containerRef, isSidePanelOpen, closePanel)
|
||||||
|
|
||||||
|
// Forward keyboard shortcuts (Ctrl+D, Ctrl+E, etc.) to the main store.
|
||||||
|
usePipKeyboardShortcuts(containerRef)
|
||||||
|
|
||||||
// Side panels open via a menu item that unmounts on click; fall back to the
|
// Side panels open via a menu item that unmounts on click; fall back to the
|
||||||
// options button so focus returns somewhere visible.
|
// options button so focus returns somewhere visible.
|
||||||
const resolveTrigger = useCallback((activeEl: HTMLElement | null) => {
|
const resolveTrigger = useCallback((activeEl: HTMLElement | null) => {
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { useEffect, type RefObject } from 'react'
|
||||||
|
import { keyboardShortcutsStore } from '@/stores/keyboardShortcuts'
|
||||||
|
import { formatShortcutKey } from '@/features/shortcuts/utils'
|
||||||
|
import { isMacintosh } from '@/utils/livekit'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mirror the main-window keyboard shortcuts inside the PiP document.
|
||||||
|
*
|
||||||
|
* The central `useKeyboardShortcuts` hook listens on `window`, which is the
|
||||||
|
* main document's window. Keydown events from the PiP document never reach
|
||||||
|
* it. This hook attaches the same dispatch logic to the PiP document so that
|
||||||
|
* Ctrl+D (mic), Ctrl+E (cam), etc. work identically in both contexts.
|
||||||
|
*/
|
||||||
|
export const usePipKeyboardShortcuts = (
|
||||||
|
containerRef: RefObject<HTMLElement | null>
|
||||||
|
) => {
|
||||||
|
useEffect(() => {
|
||||||
|
const doc = containerRef.current?.ownerDocument
|
||||||
|
if (!doc || doc === document) return
|
||||||
|
|
||||||
|
const onKeyDown = (e: KeyboardEvent) => {
|
||||||
|
const { key, metaKey, ctrlKey, shiftKey, altKey } = e
|
||||||
|
if (!key) return
|
||||||
|
|
||||||
|
const shortcutKey = formatShortcutKey({
|
||||||
|
key,
|
||||||
|
ctrlKey: ctrlKey || (isMacintosh() && metaKey),
|
||||||
|
shiftKey,
|
||||||
|
altKey,
|
||||||
|
})
|
||||||
|
|
||||||
|
let handler = keyboardShortcutsStore.shortcuts.get(shortcutKey)
|
||||||
|
if (!handler && shortcutKey === 'ctrl+shift+?') {
|
||||||
|
handler = keyboardShortcutsStore.shortcuts.get('ctrl+shift+/')
|
||||||
|
}
|
||||||
|
if (!handler) return
|
||||||
|
|
||||||
|
e.preventDefault()
|
||||||
|
handler()
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.addEventListener('keydown', onKeyDown)
|
||||||
|
return () => doc.removeEventListener('keydown', onKeyDown)
|
||||||
|
}, [containerRef])
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user