From 4f2764eef4aa904e2cf166c9d77d8026d3e34e65 Mon Sep 17 00:00:00 2001 From: Cyril Date: Thu, 11 Dec 2025 12:21:36 +0100 Subject: [PATCH] =?UTF-8?q?=E2=99=BF=EF=B8=8F(frontend)=20add=20tooltip=20?= =?UTF-8?q?and=20sr=20hint=20for=20f2=20shortcut=20to=20bottom=20toolbar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit helps keyboard and sr users discover the f2 shortcut for toolbar access Signed-off-by: Cyril --- .../livekit/components/ParticipantTile.tsx | 26 ++++++++++++++----- .../prefabs/ControlBar/DesktopControlBar.tsx | 13 ++++++++++ src/frontend/src/locales/de/rooms.json | 4 ++- src/frontend/src/locales/en/rooms.json | 3 ++- src/frontend/src/locales/fr/rooms.json | 3 ++- src/frontend/src/locales/nl/rooms.json | 3 ++- 6 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/frontend/src/features/rooms/livekit/components/ParticipantTile.tsx b/src/frontend/src/features/rooms/livekit/components/ParticipantTile.tsx index b19c6f33..b02d954a 100644 --- a/src/frontend/src/features/rooms/livekit/components/ParticipantTile.tsx +++ b/src/frontend/src/features/rooms/livekit/components/ParticipantTile.tsx @@ -31,6 +31,7 @@ import { FullScreenShareWarning } from './FullScreenShareWarning' import { ParticipantName } from './ParticipantName' import { getParticipantName } from '@/features/rooms/utils/getParticipantName' import { useTranslation } from 'react-i18next' +import { css } from '@/styled-system/css' export function TrackRefContextIfNeeded( props: React.PropsWithChildren<{ @@ -109,14 +110,8 @@ export const ParticipantTile: ( const participantName = getParticipantName(trackReference.participant) const { t } = useTranslation('rooms', { keyPrefix: 'participantTileFocus' }) - // Avoid double announcements: LiveKit's useParticipantTile may set its own - // aria-label / aria-labelledby / aria-describedby. We strip them here - // and provide a single, explicit label for the focusable tile container. - const { 'aria-label': _ignoredAriaLabel, ...safeElementProps } = elementProps - void _ignoredAriaLabel - const interactiveProps = { - ...safeElementProps, + ...elementProps, // Ensure the tile is focusable to expose contextual controls to keyboard users. tabIndex: 0, 'aria-label': t('containerLabel', { name: participantName }), @@ -232,6 +227,23 @@ export const ParticipantTile: ( )} + {hasKeyboardFocus && ( +
+ {t('toolbarHint')} +
+ )} ) }) diff --git a/src/frontend/src/features/rooms/livekit/prefabs/ControlBar/DesktopControlBar.tsx b/src/frontend/src/features/rooms/livekit/prefabs/ControlBar/DesktopControlBar.tsx index c7b050e2..dce26463 100644 --- a/src/frontend/src/features/rooms/livekit/prefabs/ControlBar/DesktopControlBar.tsx +++ b/src/frontend/src/features/rooms/livekit/prefabs/ControlBar/DesktopControlBar.tsx @@ -11,6 +11,7 @@ import { OptionsButton } from '../../components/controls/Options/OptionsButton' import { StartMediaButton } from '../../components/controls/StartMediaButton' import { MoreOptions } from './MoreOptions' import { useRef } from 'react' +import { useRegisterKeyboardShortcut } from '@/features/shortcuts/useRegisterKeyboardShortcut' import { VideoDeviceControl } from '../../components/controls/Device/VideoDeviceControl' import { AudioDevicesControl } from '../../components/controls/Device/AudioDevicesControl' @@ -19,6 +20,18 @@ export function DesktopControlBar({ }: Readonly) { const browserSupportsScreenSharing = supportsScreenSharing() const desktopControlBarEl = useRef(null) + + useRegisterKeyboardShortcut({ + shortcut: { key: 'F2' }, + handler: () => { + const root = desktopControlBarEl.current + if (!root) return + const firstButton = root.querySelector( + 'button, [role="button"], [tabindex="0"]' + ) + firstButton?.focus() + }, + }) return (