mirror of
https://github.com/suitenumerique/meet.git
synced 2026-08-29 19:57:14 +00:00
fixup! ✨(feat) connect PiP to room and options menu
This commit is contained in:
@@ -36,25 +36,63 @@ const syncThemeAttribute = (source: Document, target: Document) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cssVarNameCacheByElement = new WeakMap<HTMLElement, string[]>()
|
||||||
|
const cssVarNameCacheByUri = new Map<string, string[]>()
|
||||||
|
|
||||||
const syncCssVariables = (source: Document, target: Document) => {
|
const syncCssVariables = (source: Document, target: Document) => {
|
||||||
const sourceView = source.defaultView
|
const sourceView = source.defaultView
|
||||||
if (!sourceView) return
|
if (!sourceView) return
|
||||||
|
|
||||||
const applyVarsFrom = (element: HTMLElement | null) => {
|
const getCachedVarNames = () => {
|
||||||
if (!element) return
|
const docEl = source.documentElement
|
||||||
const styles = sourceView.getComputedStyle(element)
|
if (!docEl) return []
|
||||||
for (let i = 0; i < styles.length; i += 1) {
|
|
||||||
const property = styles[i]
|
const cachedByElement = cssVarNameCacheByElement.get(docEl)
|
||||||
if (!property.startsWith('--')) continue
|
if (cachedByElement) return cachedByElement
|
||||||
const value = styles.getPropertyValue(property)
|
|
||||||
if (value) {
|
const cachedByUri = source.baseURI
|
||||||
target.documentElement.style.setProperty(property, value)
|
? cssVarNameCacheByUri.get(source.baseURI)
|
||||||
|
: undefined
|
||||||
|
if (cachedByUri) return cachedByUri
|
||||||
|
|
||||||
|
const varNames = new Set<string>()
|
||||||
|
const collectVarsFrom = (element: HTMLElement | null) => {
|
||||||
|
if (!element) return
|
||||||
|
const styles = sourceView.getComputedStyle(element)
|
||||||
|
for (let i = 0; i < styles.length; i += 1) {
|
||||||
|
const property = styles[i]
|
||||||
|
if (property.startsWith('--')) {
|
||||||
|
varNames.add(property)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
collectVarsFrom(source.documentElement)
|
||||||
|
collectVarsFrom(source.body)
|
||||||
|
|
||||||
|
const result = Array.from(varNames)
|
||||||
|
cssVarNameCacheByElement.set(docEl, result)
|
||||||
|
if (source.baseURI) {
|
||||||
|
cssVarNameCacheByUri.set(source.baseURI, result)
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
applyVarsFrom(source.documentElement)
|
const varNames = getCachedVarNames()
|
||||||
applyVarsFrom(source.body)
|
if (!varNames.length) return
|
||||||
|
|
||||||
|
const rootStyles = sourceView.getComputedStyle(source.documentElement)
|
||||||
|
const bodyStyles = source.body
|
||||||
|
? sourceView.getComputedStyle(source.body)
|
||||||
|
: null
|
||||||
|
|
||||||
|
varNames.forEach((property) => {
|
||||||
|
const bodyValue = bodyStyles?.getPropertyValue(property)
|
||||||
|
const value = bodyValue || rootStyles.getPropertyValue(property)
|
||||||
|
if (value) {
|
||||||
|
target.documentElement.style.setProperty(property, value)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
|
|
||||||
type DocumentPictureInPicture = {
|
type DocumentPictureInPicture = {
|
||||||
requestWindow: (options?: {
|
requestWindow: (options?: {
|
||||||
@@ -19,24 +19,44 @@ export const useDocumentPiP = ({
|
|||||||
height?: number
|
height?: number
|
||||||
} = {}) => {
|
} = {}) => {
|
||||||
const [pipWindow, setPipWindow] = useState<Window | null>(null)
|
const [pipWindow, setPipWindow] = useState<Window | null>(null)
|
||||||
|
const pipWindowRef = useRef<Window | null>(null)
|
||||||
|
const pendingPiPRef = useRef<Promise<Window | null> | null>(null)
|
||||||
|
|
||||||
const isSupported = useMemo(() => {
|
const [isSupported] = useState(() => {
|
||||||
if (typeof window === 'undefined') return false
|
if (typeof window === 'undefined') return false
|
||||||
return 'documentPictureInPicture' in window
|
return 'documentPictureInPicture' in window
|
||||||
}, [])
|
})
|
||||||
|
|
||||||
const openPiP = useCallback(async () => {
|
const openPiP = useCallback(async () => {
|
||||||
if (!isSupported) return null
|
if (!isSupported) return null
|
||||||
if (pipWindow && !pipWindow.closed) return pipWindow
|
const existingWindow = pipWindowRef.current
|
||||||
|
if (existingWindow && !existingWindow.closed) return existingWindow
|
||||||
|
|
||||||
|
if (pendingPiPRef.current) return pendingPiPRef.current
|
||||||
|
|
||||||
// Request a new PiP window from the browser API.
|
// Request a new PiP window from the browser API.
|
||||||
const pip = (window as WindowWithDocumentPiP).documentPictureInPicture
|
const pip = (window as WindowWithDocumentPiP).documentPictureInPicture
|
||||||
if (!pip) return null
|
if (!pip) return null
|
||||||
|
|
||||||
const win = await pip.requestWindow({ width, height })
|
const requestPromise = (async () => {
|
||||||
setPipWindow(win)
|
try {
|
||||||
return win
|
const win = await pip.requestWindow({ width, height })
|
||||||
}, [height, isSupported, pipWindow, width])
|
const currentWindow = pipWindowRef.current
|
||||||
|
if (currentWindow && !currentWindow.closed) return currentWindow
|
||||||
|
setPipWindow(win)
|
||||||
|
return win
|
||||||
|
} catch (error) {
|
||||||
|
// Avoid unhandled rejections if the user blocks or closes the request.
|
||||||
|
console.error('Failed to open Picture-in-Picture window', error)
|
||||||
|
return null
|
||||||
|
} finally {
|
||||||
|
pendingPiPRef.current = null
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
|
||||||
|
pendingPiPRef.current = requestPromise
|
||||||
|
return requestPromise
|
||||||
|
}, [height, isSupported, width])
|
||||||
|
|
||||||
const closePiP = useCallback(() => {
|
const closePiP = useCallback(() => {
|
||||||
if (!pipWindow) return
|
if (!pipWindow) return
|
||||||
@@ -46,6 +66,10 @@ export const useDocumentPiP = ({
|
|||||||
setPipWindow(null)
|
setPipWindow(null)
|
||||||
}, [pipWindow])
|
}, [pipWindow])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
pipWindowRef.current = pipWindow
|
||||||
|
}, [pipWindow])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!pipWindow) return
|
if (!pipWindow) return
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,5 @@ export const useOverlayPortalContainer = () => {
|
|||||||
*/
|
*/
|
||||||
export const useOverlayBoundaryElement = () => {
|
export const useOverlayBoundaryElement = () => {
|
||||||
const portalContainer = useOverlayPortalContainer()
|
const portalContainer = useOverlayPortalContainer()
|
||||||
return useMemo(() => {
|
return portalContainer
|
||||||
if (portalContainer) return portalContainer
|
|
||||||
return undefined
|
|
||||||
}, [portalContainer])
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user