♿️(frontend) add tooltip and sr hint for f2 shortcut to bottom toolbar
helps keyboard and sr users discover the f2 shortcut for toolbar access Signed-off-by: Cyril <c.gromoff@gmail.com>
This commit is contained in:
@@ -31,6 +31,7 @@ import { FullScreenShareWarning } from './FullScreenShareWarning'
|
|||||||
import { ParticipantName } from './ParticipantName'
|
import { ParticipantName } from './ParticipantName'
|
||||||
import { getParticipantName } from '@/features/rooms/utils/getParticipantName'
|
import { getParticipantName } from '@/features/rooms/utils/getParticipantName'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { css } from '@/styled-system/css'
|
||||||
|
|
||||||
export function TrackRefContextIfNeeded(
|
export function TrackRefContextIfNeeded(
|
||||||
props: React.PropsWithChildren<{
|
props: React.PropsWithChildren<{
|
||||||
@@ -109,14 +110,8 @@ export const ParticipantTile: (
|
|||||||
const participantName = getParticipantName(trackReference.participant)
|
const participantName = getParticipantName(trackReference.participant)
|
||||||
const { t } = useTranslation('rooms', { keyPrefix: 'participantTileFocus' })
|
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 = {
|
const interactiveProps = {
|
||||||
...safeElementProps,
|
...elementProps,
|
||||||
// Ensure the tile is focusable to expose contextual controls to keyboard users.
|
// Ensure the tile is focusable to expose contextual controls to keyboard users.
|
||||||
tabIndex: 0,
|
tabIndex: 0,
|
||||||
'aria-label': t('containerLabel', { name: participantName }),
|
'aria-label': t('containerLabel', { name: participantName }),
|
||||||
@@ -232,6 +227,23 @@ export const ParticipantTile: (
|
|||||||
)}
|
)}
|
||||||
</ParticipantContextIfNeeded>
|
</ParticipantContextIfNeeded>
|
||||||
</TrackRefContextIfNeeded>
|
</TrackRefContextIfNeeded>
|
||||||
|
{hasKeyboardFocus && (
|
||||||
|
<div
|
||||||
|
className={css({
|
||||||
|
position: 'absolute',
|
||||||
|
top: '0.75rem',
|
||||||
|
left: '0.75rem',
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.6)',
|
||||||
|
color: 'white',
|
||||||
|
borderRadius: '999px',
|
||||||
|
paddingInline: '0.5rem',
|
||||||
|
paddingBlock: '0.1rem',
|
||||||
|
fontSize: '0.75rem',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{t('toolbarHint')}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { OptionsButton } from '../../components/controls/Options/OptionsButton'
|
|||||||
import { StartMediaButton } from '../../components/controls/StartMediaButton'
|
import { StartMediaButton } from '../../components/controls/StartMediaButton'
|
||||||
import { MoreOptions } from './MoreOptions'
|
import { MoreOptions } from './MoreOptions'
|
||||||
import { useRef } from 'react'
|
import { useRef } from 'react'
|
||||||
|
import { useRegisterKeyboardShortcut } from '@/features/shortcuts/useRegisterKeyboardShortcut'
|
||||||
import { VideoDeviceControl } from '../../components/controls/Device/VideoDeviceControl'
|
import { VideoDeviceControl } from '../../components/controls/Device/VideoDeviceControl'
|
||||||
import { AudioDevicesControl } from '../../components/controls/Device/AudioDevicesControl'
|
import { AudioDevicesControl } from '../../components/controls/Device/AudioDevicesControl'
|
||||||
|
|
||||||
@@ -19,6 +20,18 @@ export function DesktopControlBar({
|
|||||||
}: Readonly<ControlBarAuxProps>) {
|
}: Readonly<ControlBarAuxProps>) {
|
||||||
const browserSupportsScreenSharing = supportsScreenSharing()
|
const browserSupportsScreenSharing = supportsScreenSharing()
|
||||||
const desktopControlBarEl = useRef<HTMLDivElement>(null)
|
const desktopControlBarEl = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
|
useRegisterKeyboardShortcut({
|
||||||
|
shortcut: { key: 'F2' },
|
||||||
|
handler: () => {
|
||||||
|
const root = desktopControlBarEl.current
|
||||||
|
if (!root) return
|
||||||
|
const firstButton = root.querySelector<HTMLButtonElement>(
|
||||||
|
'button, [role="button"], [tabindex="0"]'
|
||||||
|
)
|
||||||
|
firstButton?.focus()
|
||||||
|
},
|
||||||
|
})
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={desktopControlBarEl}
|
ref={desktopControlBarEl}
|
||||||
|
|||||||
@@ -512,7 +512,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"participantTileFocus": {
|
"participantTileFocus": {
|
||||||
"containerLabel": "Optionen für {{name}}",
|
"containerLabel": "Optionen für {{name}}, F2: zur Symbolleiste unten.",
|
||||||
|
"toolbarHint": "F2: zur Symbolleiste unten.",
|
||||||
|
|
||||||
"pin": {
|
"pin": {
|
||||||
"enable": "Anheften",
|
"enable": "Anheften",
|
||||||
"disable": "Lösen"
|
"disable": "Lösen"
|
||||||
|
|||||||
@@ -512,7 +512,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"participantTileFocus": {
|
"participantTileFocus": {
|
||||||
"containerLabel": "Options for {{name}}",
|
"containerLabel": "Options for {{name}}, F2: go to the bottom toolbar.",
|
||||||
|
"toolbarHint": "F2: go to the bottom toolbar.",
|
||||||
"pin": {
|
"pin": {
|
||||||
"enable": "Pin",
|
"enable": "Pin",
|
||||||
"disable": "Unpin"
|
"disable": "Unpin"
|
||||||
|
|||||||
@@ -512,7 +512,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"participantTileFocus": {
|
"participantTileFocus": {
|
||||||
"containerLabel": "Options pour {{name}}",
|
"containerLabel": "Options pour {{name}}, raccourci F2 pour aller à la barre d'outils en bas.",
|
||||||
|
"toolbarHint": "F2: raccourci barre d'outils en bas.",
|
||||||
"pin": {
|
"pin": {
|
||||||
"enable": "Épingler",
|
"enable": "Épingler",
|
||||||
"disable": "Annuler l'épinglage"
|
"disable": "Annuler l'épinglage"
|
||||||
|
|||||||
@@ -512,7 +512,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"participantTileFocus": {
|
"participantTileFocus": {
|
||||||
"containerLabel": "Opties voor {{name}}",
|
"containerLabel": "Opties voor {{name}}, F2: naar de werkbalk onderaan.",
|
||||||
|
"toolbarHint": "F2: naar de werkbalk onderaan.",
|
||||||
"pin": {
|
"pin": {
|
||||||
"enable": "Pinnen",
|
"enable": "Pinnen",
|
||||||
"disable": "Losmaken"
|
"disable": "Losmaken"
|
||||||
|
|||||||
Reference in New Issue
Block a user