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,
+})