112 行
3.0 KiB
TypeScript
112 行
3.0 KiB
TypeScript
import { useRef, useLayoutEffect, useEffect, useState } from 'react'
|
|
type Props = { id: string,
|
|
width: number,
|
|
height: number,
|
|
style?: CSSProperties }
|
|
|
|
import type { CSSProperties, FC } from 'react'
|
|
|
|
|
|
export default ((props: Props) => {
|
|
const { id, width, height, style = { } } = props
|
|
|
|
const iframeRef = useRef<HTMLIFrameElement> (null)
|
|
|
|
const [screenWidth, setScreenWidth] = useState<CSSProperties['width']> ()
|
|
const [screenHeight, setScreenHeight] = useState<CSSProperties['height']> ()
|
|
const [landscape, setLandscape] = useState<boolean> (false)
|
|
const [fullScreen, setFullScreen] = useState<boolean> (false)
|
|
|
|
const src = `https://embed.nicovideo.jp/watch/${id}?persistence=1&oldScript=1&referer=&from=0&allowProgrammaticFullScreen=1`;
|
|
|
|
const styleFullScreen: CSSProperties = fullScreen ? {
|
|
top: 0,
|
|
left: landscape ? 0 : '100%',
|
|
position: 'fixed',
|
|
width: screenWidth,
|
|
height: screenHeight,
|
|
zIndex: 2147483647,
|
|
maxWidth: 'none',
|
|
transformOrigin: '0% 0%',
|
|
transform: landscape ? 'none' : 'rotate(90deg)',
|
|
WebkitTransformOrigin: '0% 0%',
|
|
WebkitTransform: landscape ? 'none' : 'rotate(90deg)' } : {};
|
|
|
|
const margedStyle = {
|
|
border: 'none',
|
|
maxWidth: '100%',
|
|
...style,
|
|
...styleFullScreen }
|
|
|
|
useEffect (() => {
|
|
const onMessage = (event: MessageEvent<any>) => {
|
|
if (!(iframeRef.current)
|
|
|| (event.source !== iframeRef.current.contentWindow))
|
|
return
|
|
|
|
if (event.data.eventName === 'enterProgrammaticFullScreen')
|
|
setFullScreen (true)
|
|
else if (event.data.eventName === 'exitProgrammaticFullScreen')
|
|
setFullScreen (false)
|
|
}
|
|
|
|
addEventListener ('message', onMessage)
|
|
|
|
return () => removeEventListener ('message', onMessage)
|
|
}, [])
|
|
|
|
useLayoutEffect(() => {
|
|
if (!(fullScreen))
|
|
return
|
|
|
|
const initialScrollX = scrollX
|
|
const initialScrollY = scrollY
|
|
let timer: NodeJS.Timeout
|
|
let ended = false
|
|
|
|
const pollingResize = () => {
|
|
if (ended)
|
|
return
|
|
|
|
const landscape = innerWidth >= innerHeight
|
|
const windowWidth = `${landscape ? innerWidth : innerHeight}px`
|
|
const windowHeight = `${landscape ? innerHeight : innerWidth}px`
|
|
|
|
setLandscape (landscape)
|
|
setScreenWidth (windowWidth)
|
|
setScreenHeight (windowHeight)
|
|
timer = setTimeout (startPollingResize, 200)
|
|
}
|
|
|
|
const startPollingResize = () => {
|
|
if (requestAnimationFrame)
|
|
requestAnimationFrame (pollingResize)
|
|
else
|
|
pollingResize ()
|
|
}
|
|
|
|
startPollingResize ()
|
|
|
|
return () => {
|
|
clearTimeout (timer)
|
|
ended = true
|
|
scrollTo (initialScrollX, initialScrollY)
|
|
}
|
|
}, [fullScreen])
|
|
|
|
useEffect (() => {
|
|
if (!(fullScreen))
|
|
return
|
|
scrollTo (0, 0)
|
|
}, [screenWidth, screenHeight, fullScreen])
|
|
|
|
return (
|
|
<iframe ref={iframeRef}
|
|
src={src}
|
|
width={width}
|
|
height={height}
|
|
style={margedStyle}
|
|
allowFullScreen
|
|
allow="autoplay"/>)
|
|
}) satisfies FC<Props>
|