(feat) move pip state to valtio store

replace context provider with shared store for pip ui state
This commit is contained in:
Cyril
2026-02-10 14:13:00 +01:00
parent e38d0861b1
commit 1c5b6b1e1f
6 changed files with 40 additions and 64 deletions
@@ -4,7 +4,7 @@ import { useRoomPiP } from '../hooks/useRoomPiP'
/** /**
* Wrapper that mounts the PiP UI when room-level PiP state is enabled. * Wrapper that mounts the PiP UI when room-level PiP state is enabled.
* Bridges RoomPiPProvider state with DocumentPiPPortal and PipView rendering. * Bridges Valtio-backed PiP state with DocumentPiPPortal and PipView rendering.
*/ */
export const RoomPiP = () => { export const RoomPiP = () => {
const { isOpen, close } = useRoomPiP() const { isOpen, close } = useRoomPiP()
@@ -1,38 +0,0 @@
import { useCallback, useMemo, useState } from 'react'
import { RoomPiPContext } from './roomPiPContext'
/**
* Context Provider that manages Picture-in-Picture state at the room level.
* Handles open/closed state, browser support detection, and exposes open/close/toggle functions.
* Components access PiP state via the useRoomPiP hook.
*/
export const RoomPiPProvider = ({
children,
}: {
children: React.ReactNode
}) => {
const [isOpen, setIsOpen] = useState(false)
// Feature detection for Document Picture-in-Picture.
const isSupported =
typeof window !== 'undefined' && 'documentPictureInPicture' in window
const open = useCallback(() => setIsOpen(true), [])
const close = useCallback(() => setIsOpen(false), [])
const toggle = useCallback(() => setIsOpen((current) => !current), [])
const value = useMemo(
() => ({
isSupported,
isOpen,
open,
close,
toggle,
}),
[close, isOpen, isSupported, open, toggle]
)
return (
<RoomPiPContext.Provider value={value}>{children}</RoomPiPContext.Provider>
)
}
@@ -1,11 +0,0 @@
import { createContext } from 'react'
export type RoomPiPContextValue = {
isSupported: boolean
isOpen: boolean
open: () => void
close: () => void
toggle: () => void
}
export const RoomPiPContext = createContext<RoomPiPContextValue | null>(null)
@@ -1,10 +1,29 @@
import { useContext } from 'react' import { useCallback } from 'react'
import { RoomPiPContext } from './roomPiPContext' import { useSnapshot } from 'valtio'
import { roomPiPStore } from '@/stores/roomPiP'
export const useRoomPiP = () => { export const useRoomPiP = () => {
const context = useContext(RoomPiPContext) const { isOpen } = useSnapshot(roomPiPStore)
if (!context) { const isSupported =
throw new Error('useRoomPiP must be used within a RoomPiPProvider') typeof window !== 'undefined' && 'documentPictureInPicture' in window
const open = useCallback(() => {
roomPiPStore.isOpen = true
}, [])
const close = useCallback(() => {
roomPiPStore.isOpen = false
}, [])
const toggle = useCallback(() => {
roomPiPStore.isOpen = !roomPiPStore.isOpen
}, [])
return {
isSupported,
isOpen,
open,
close,
toggle,
} }
return context
} }
@@ -35,7 +35,6 @@ import { useVideoResolutionSubscription } from '../hooks/useVideoResolutionSubsc
import { SettingsDialogProvider } from '@/features/settings/components/SettingsDialogProvider' import { SettingsDialogProvider } from '@/features/settings/components/SettingsDialogProvider'
import { IsIdleDisconnectModal } from '../components/IsIdleDisconnectModal' import { IsIdleDisconnectModal } from '../components/IsIdleDisconnectModal'
import { RoomPiP } from '../components/RoomPiP' import { RoomPiP } from '../components/RoomPiP'
import { RoomPiPProvider } from '../hooks/RoomPiPProvider'
import { getParticipantName } from '@/features/rooms/utils/getParticipantName' import { getParticipantName } from '@/features/rooms/utils/getParticipantName'
import { useScreenReaderAnnounce } from '@/hooks/useScreenReaderAnnounce' import { useScreenReaderAnnounce } from '@/hooks/useScreenReaderAnnounce'
import { ReactionPortals } from '@/features/reactions/components/ReactionPortals' import { ReactionPortals } from '@/features/reactions/components/ReactionPortals'
@@ -240,11 +239,10 @@ export function VideoConference({ ...props }: VideoConferenceProps) {
}} }}
> >
{isWeb() && ( {isWeb() && (
<RoomPiPProvider> <LayoutContextProvider
<LayoutContextProvider value={layoutContext}
value={layoutContext} // onPinChange={handleFocusStateChange}
// onPinChange={handleFocusStateChange} >
>
<ScreenShareErrorModal <ScreenShareErrorModal
isOpen={isShareErrorVisible} isOpen={isShareErrorVisible}
onClose={() => setIsShareErrorVisible(false)} onClose={() => setIsShareErrorVisible(false)}
@@ -293,8 +291,7 @@ export function VideoConference({ ...props }: VideoConferenceProps) {
/> />
<SidePanel /> <SidePanel />
<RoomPiP /> <RoomPiP />
</LayoutContextProvider> </LayoutContextProvider>
</RoomPiPProvider>
)} )}
<RoomAudioRenderer /> <RoomAudioRenderer />
<ConnectionStateToast /> <ConnectionStateToast />
+9
View File
@@ -0,0 +1,9 @@
import { proxy } from 'valtio'
type State = {
isOpen: boolean
}
export const roomPiPStore = proxy<State>({
isOpen: false,
})