diff --git a/src/frontend/src/features/rooms/livekit/components/RoomPiP.tsx b/src/frontend/src/features/rooms/livekit/components/RoomPiP.tsx index 000faabc..9cbddfba 100644 --- a/src/frontend/src/features/rooms/livekit/components/RoomPiP.tsx +++ b/src/frontend/src/features/rooms/livekit/components/RoomPiP.tsx @@ -4,7 +4,7 @@ import { useRoomPiP } from '../hooks/useRoomPiP' /** * 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 = () => { const { isOpen, close } = useRoomPiP() diff --git a/src/frontend/src/features/rooms/livekit/hooks/RoomPiPProvider.tsx b/src/frontend/src/features/rooms/livekit/hooks/RoomPiPProvider.tsx deleted file mode 100644 index ed470520..00000000 --- a/src/frontend/src/features/rooms/livekit/hooks/RoomPiPProvider.tsx +++ /dev/null @@ -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 ( - {children} - ) -} diff --git a/src/frontend/src/features/rooms/livekit/hooks/roomPiPContext.ts b/src/frontend/src/features/rooms/livekit/hooks/roomPiPContext.ts deleted file mode 100644 index 3771d11d..00000000 --- a/src/frontend/src/features/rooms/livekit/hooks/roomPiPContext.ts +++ /dev/null @@ -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(null) diff --git a/src/frontend/src/features/rooms/livekit/hooks/useRoomPiP.tsx b/src/frontend/src/features/rooms/livekit/hooks/useRoomPiP.tsx index a0f41f50..75880a37 100644 --- a/src/frontend/src/features/rooms/livekit/hooks/useRoomPiP.tsx +++ b/src/frontend/src/features/rooms/livekit/hooks/useRoomPiP.tsx @@ -1,10 +1,29 @@ -import { useContext } from 'react' -import { RoomPiPContext } from './roomPiPContext' +import { useCallback } from 'react' +import { useSnapshot } from 'valtio' +import { roomPiPStore } from '@/stores/roomPiP' export const useRoomPiP = () => { - const context = useContext(RoomPiPContext) - if (!context) { - throw new Error('useRoomPiP must be used within a RoomPiPProvider') + const { isOpen } = useSnapshot(roomPiPStore) + const isSupported = + 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 } diff --git a/src/frontend/src/features/rooms/livekit/prefabs/VideoConference.tsx b/src/frontend/src/features/rooms/livekit/prefabs/VideoConference.tsx index 466d36e2..ac32e8fd 100644 --- a/src/frontend/src/features/rooms/livekit/prefabs/VideoConference.tsx +++ b/src/frontend/src/features/rooms/livekit/prefabs/VideoConference.tsx @@ -35,7 +35,6 @@ import { useVideoResolutionSubscription } from '../hooks/useVideoResolutionSubsc import { SettingsDialogProvider } from '@/features/settings/components/SettingsDialogProvider' import { IsIdleDisconnectModal } from '../components/IsIdleDisconnectModal' import { RoomPiP } from '../components/RoomPiP' -import { RoomPiPProvider } from '../hooks/RoomPiPProvider' import { getParticipantName } from '@/features/rooms/utils/getParticipantName' import { useScreenReaderAnnounce } from '@/hooks/useScreenReaderAnnounce' import { ReactionPortals } from '@/features/reactions/components/ReactionPortals' @@ -240,11 +239,10 @@ export function VideoConference({ ...props }: VideoConferenceProps) { }} > {isWeb() && ( - - + setIsShareErrorVisible(false)} @@ -293,8 +291,7 @@ export function VideoConference({ ...props }: VideoConferenceProps) { /> - - + )} diff --git a/src/frontend/src/stores/roomPiP.ts b/src/frontend/src/stores/roomPiP.ts new file mode 100644 index 00000000..9e1b8c04 --- /dev/null +++ b/src/frontend/src/stores/roomPiP.ts @@ -0,0 +1,9 @@ +import { proxy } from 'valtio' + +type State = { + isOpen: boolean +} + +export const roomPiPStore = proxy({ + isOpen: false, +})