♻️(frontend) share a PiP-aware element size hook

Reuse a single ResizeObserver hook in the PiP control bar.
This commit is contained in:
Cyril
2026-04-22 18:00:37 +02:00
parent a6d20e2f58
commit 61877d23bc
2 changed files with 45 additions and 32 deletions
@@ -1,5 +1,5 @@
import { styled } from '@/styled-system/jsx'
import { useRef, useMemo, useState, useEffect, useCallback } from 'react'
import { useRef, useMemo } from 'react'
import { AudioDevicesControl } from '@/features/rooms/livekit/components/controls/Device/AudioDevicesControl'
import { VideoDeviceControl } from '@/features/rooms/livekit/components/controls/Device/VideoDeviceControl'
import { ScreenShareToggle } from '@/features/rooms/livekit/components/controls/ScreenShareToggle'
@@ -7,6 +7,7 @@ import { LeaveButton } from '@/features/rooms/livekit/components/controls/LeaveB
import { SubtitlesToggle } from '@/features/rooms/livekit/components/controls/SubtitlesToggle'
import { HandToggle } from '@/features/rooms/livekit/components/controls/HandToggle'
import { StartMediaButton } from '@/features/rooms/livekit/components/controls/StartMediaButton'
import { usePipElementSize } from '../hooks/usePipElementSize'
import { PipOptionsMenu } from './controls/PipOptionsMenu'
import { PipReactionsToggle } from './PipReactionsToggle'
@@ -46,43 +47,13 @@ function getHiddenControls(
return hidden
}
/**
* ResizeObserver that works inside the PiP document context
* (the global singleton from the main window cannot observe PiP elements).
*/
function usePipSize(ref: React.RefObject<HTMLElement | null>) {
const [width, setWidth] = useState(0)
const measure = useCallback(() => {
if (ref.current) setWidth(ref.current.getBoundingClientRect().width)
}, [ref])
useEffect(() => {
const el = ref.current
if (!el) return
measure()
const RO =
el.ownerDocument.defaultView?.ResizeObserver ?? window.ResizeObserver
const observer = new RO((entries) => {
const entry = entries[0]
if (entry) setWidth(entry.contentRect.width)
})
observer.observe(el)
return () => observer.disconnect()
}, [ref, measure])
return width
}
export const PipControlBar = ({
showScreenShare,
}: {
showScreenShare: boolean
}) => {
const containerRef = useRef<HTMLDivElement>(null)
const width = usePipSize(containerRef)
const { width } = usePipElementSize(containerRef)
const hidden = useMemo(
() => getHiddenControls(width, showScreenShare),
@@ -0,0 +1,42 @@
import { useCallback, useEffect, useState, type RefObject } from 'react'
type Size = { width: number; height: number }
/**
* Observes an element's size, even when mounted in the PiP document.
* Resolves `ResizeObserver` from the element's own window.
*/
export const usePipElementSize = <T extends HTMLElement>(
ref: RefObject<T | null>
): Size => {
const [size, setSize] = useState<Size>({ width: 0, height: 0 })
const measure = useCallback(() => {
const el = ref.current
if (!el) return
const rect = el.getBoundingClientRect()
setSize({ width: rect.width, height: rect.height })
}, [ref])
useEffect(() => {
const el = ref.current
if (!el) return
measure()
const RO =
el.ownerDocument.defaultView?.ResizeObserver ?? window.ResizeObserver
if (!RO) return
const observer = new RO((entries) => {
const entry = entries[0]
if (!entry) return
const { width, height } = entry.contentRect
setSize({ width, height })
})
observer.observe(el)
return () => observer.disconnect()
}, [ref, measure])
return size
}