Files
meet/src/frontend/src/features/rooms/livekit/prefabs/ControlBar/DesktopControlBar.tsx
T
lebaudantoine 15ca2b41b4 🐛(frontend) use state instead of a ref for MoreControls container
After the recent refactoring, `MoreControls` only renders once. On
that first render, the container ref is `null`, and when it later
gets a reference to the div, the ref update does not trigger a
re-render.

As a result, the additional controls were never showing up.

Switch from a ref to a state to track the container element. State
updates do trigger a re-render, so the controls now show as
expected once the container is available.
2026-08-21 22:55:28 +02:00

101 lines
3.3 KiB
TypeScript

import { supportsScreenSharing } from '@livekit/components-core'
import type { ControlBarAuxProps } from './ControlBar'
import { css } from '@/styled-system/css'
import { LeaveButton } from '../../components/controls/LeaveButton'
import { Track } from 'livekit-client'
import { HandToggle } from '../../components/controls/HandToggle'
import { ScreenShareToggle } from '../../components/controls/ScreenShareToggle'
import { SubtitlesToggle } from '../../components/controls/SubtitlesToggle'
import { OptionsButton } from '../../components/controls/Options/OptionsButton'
import { StartMediaButton } from '../../components/controls/StartMediaButton'
import { MoreOptions } from './MoreOptions'
import { RefObject, useMemo, useState } from 'react'
import { useRegisterKeyboardShortcut } from '@/features/shortcuts/useRegisterKeyboardShortcut'
import { useFullScreen } from '../../hooks/useFullScreen'
import { VideoDeviceControl } from '../../components/controls/Device/VideoDeviceControl'
import { AudioDevicesControl } from '../../components/controls/Device/AudioDevicesControl'
import { ReactionsToggle } from '@/features/reactions/components/ReactionsToggle'
import { ControlBarRegion } from '@/features/layout/components/ControlBarRegion'
export function DesktopControlBar({
onDeviceError,
}: Readonly<ControlBarAuxProps>) {
const browserSupportsScreenSharing = supportsScreenSharing()
const [controlBarElement, setControlBarElement] =
useState<HTMLDivElement | null>(null)
const desktopControlBarEl = useMemo<RefObject<HTMLDivElement>>(
() => ({ current: controlBarElement }),
[controlBarElement]
)
const { toggleFullScreen, isFullscreenAvailable } = useFullScreen({})
useRegisterKeyboardShortcut({
id: 'focus-toolbar',
handler: () => {
const root = desktopControlBarEl.current
if (!root) return
const firstButton = root.querySelector<HTMLButtonElement>(
'button, [role="button"], [tabindex="0"]'
)
firstButton?.focus()
},
})
useRegisterKeyboardShortcut({
id: 'fullscreen',
handler: toggleFullScreen,
isDisabled: !isFullscreenAvailable,
})
return (
<div
ref={setControlBarElement}
className={css({
width: '100vw',
display: 'flex',
padding: '1.125rem',
})}
>
<div
className={css({
display: 'flex',
justifyContent: 'flex-start',
flex: '1 1 33%',
alignItems: 'center',
gap: '0.5rem',
marginLeft: '0.5rem',
})}
/>
<ControlBarRegion>
<AudioDevicesControl
onDeviceError={(error) =>
onDeviceError?.({ source: Track.Source.Microphone, error })
}
/>
<VideoDeviceControl
onDeviceError={(error) =>
onDeviceError?.({ source: Track.Source.Camera, error })
}
/>
<ReactionsToggle />
{browserSupportsScreenSharing && (
<ScreenShareToggle
onDeviceError={(error) =>
onDeviceError?.({ source: Track.Source.ScreenShare, error })
}
/>
)}
<SubtitlesToggle />
<HandToggle />
<OptionsButton />
<LeaveButton />
<StartMediaButton />
</ControlBarRegion>
<MoreOptions parentElement={desktopControlBarEl} />
</div>
)
}