import { FC, useEffect, useId, useState } from 'react'; import JSXStyle from 'styled-jsx/style'; import { ItemProps } from '../Item'; import { LinkWrapper } from '../LinkWrapper'; import { getYoutubeId } from '../../../utils/getValidYoutubeUrl'; import { useEmbedVideoItem } from './useEmbedVideoItem'; import { useItemAngle } from '../useItemAngle'; import { getLayoutStyles, YoutubeEmbedItem as TYoutubeEmbedItem } from '@cntrl-site/sdk'; import { useCntrlContext } from '../../../provider/useCntrlContext'; import { useYouTubeIframeApi } from '../../../utils/Youtube/useYouTubeIframeApi'; import { YTPlayer } from '../../../utils/Youtube/YoutubeIframeApi'; import { useRegisterResize } from '../../../common/useRegisterResize'; import { getStyleFromItemStateAndParams } from '../../../utils/getStyleFromItemStateAndParams'; import { useLayoutContext } from '../../useLayoutContext'; import { useItemGeometry } from '../../../ItemGeometry/useItemGeometry'; export const YoutubeEmbedItem: FC> = ({ item, sectionId, onResize, interactionCtrl, onVisibilityChange }) => { const reactId = useId(); const id = `${reactId}-youtube-${item.id}`; const { layouts } = useCntrlContext(); const { url } = item.commonParams; const layoutId = useLayoutContext(); const layoutParams = layoutId ? item.layoutParams[layoutId] : null; const { radius: itemRadius, blur: itemBlur, opacity: itemOpacity } = useEmbedVideoItem(item, sectionId); const itemAngle = useItemAngle(item, sectionId); const YT = useYouTubeIframeApi(); const [div, setDiv] = useState(null); const [player, setPlayer] = useState(undefined); const [isCoverVisible, setIsCoverVisible] = useState(item.commonParams.coverUrl !== null); const [imgRef, setImgRef] = useState(null); const layoutValues: Record[] = [item.area, item.layoutParams]; const wrapperStateParams = interactionCtrl?.getState(['angle', 'blur', 'opacity']); const frameStateParams = interactionCtrl?.getState(['radius']); const angle = getStyleFromItemStateAndParams(wrapperStateParams?.styles?.angle, itemAngle); const blur = getStyleFromItemStateAndParams(wrapperStateParams?.styles?.blur, itemBlur); const opacity = getStyleFromItemStateAndParams(wrapperStateParams?.styles?.opacity, itemOpacity); const radius = getStyleFromItemStateAndParams(frameStateParams?.styles?.radius, itemRadius); const isInteractive = opacity !== 0; useEffect(() => { onVisibilityChange?.(isInteractive); }, [isInteractive, onVisibilityChange]); useRegisterResize(div, onResize); useItemGeometry(item.id, div); useEffect(() => { const newUrl = new URL(url); const videoId = getYoutubeId(newUrl); if (!YT || !videoId || !div || !layoutParams) return; const { play, controls } = layoutParams; const placeholder = document.createElement('div'); div.appendChild(placeholder); const player = new YT.Player(placeholder, { videoId, playerVars: { autoplay: play === 'auto' ? '1' : '0', controls: controls ? '1' : '0' }, events: { onStateChange: (event) => { if (play !== 'auto') return; if (event.data === 1) { setIsCoverVisible(false); } if (event.data === 2 || event.data === -1) { setIsCoverVisible(true); } }, onReady: (event) => { setPlayer(event.target); if (play !== 'on-click') { player.mute(); } } } }); return () => { setPlayer(undefined); player.destroy(); placeholder.parentElement?.removeChild(placeholder); }; }, [YT, div, layoutParams]); const onCoverClick = () => { if (!player || !imgRef) return; player.playVideo(); setIsCoverVisible(false); }; useEffect(() => { if (layoutParams && layoutParams.play === 'on-click' && !layoutParams.controls) { setIsCoverVisible(true); } }, [layoutParams]); useEffect(() => { onVisibilityChange?.(isInteractive); if (!isInteractive && player) { player.pauseVideo(); } }, [isInteractive, onVisibilityChange, player]); useEffect(() => { if (!player || !interactionCtrl) return; interactionCtrl.setActionReceiver((type) => { switch (type) { case 'play': player.playVideo(); break; case 'pause': player.pauseVideo(); break; } }); }, [interactionCtrl, player]); return (
{ if (!player || !layoutParams || layoutParams.play !== 'on-hover' || isCoverVisible) return; player.playVideo(); }} onMouseLeave={() => { if (!player || !layoutParams || layoutParams.play !== 'on-hover') return; player.pauseVideo(); }} style={{ ...(opacity !== undefined ? { opacity } : {}), ...(angle !== undefined ? { transform: `rotate(${angle}deg)` } : {}), ...(blur !== undefined ? { filter: `blur(${blur * 100}vw)` } : {}), willChange: blur !== 0 && blur !== undefined ? 'transform' : 'unset', transition: wrapperStateParams?.transition ?? 'none' }} > {item.commonParams.coverUrl && ( onCoverClick() } : {})} {...(layoutParams?.play === 'on-hover' ? { onMouseEnter: () => { if (!player || !layoutParams || layoutParams.play !== 'on-hover') return; setIsCoverVisible(false); player.playVideo(); } } : {})} src={item.commonParams.coverUrl ?? ''} style={{ display: isCoverVisible ? 'block' : 'none', cursor: 'pointer', position: 'absolute', objectFit: 'cover', height: '100%', width: '100%', top: '0', left: '0', zIndex: 1 }} alt="Cover img" /> )}
{` .embed-youtube-video-wrapper-${item.id}, .embed-${item.id} { position: absolute; width: 100%; height: 100%; } .embed-${item.id} { overflow: hidden; } .embed-youtube-video-wrapper-${item.id} iframe { width: 100%; height: 100%; z-index: 1; border: none; } ${getLayoutStyles(layouts, layoutValues, ([area, layoutParams]) => { return (` .embed-youtube-video-wrapper-${item.id} { opacity: ${layoutParams.opacity}; transform: rotate(${area.angle}deg); filter: ${layoutParams.blur !== 0 ? `blur(${layoutParams.blur * 100}vw)` : 'unset'}; ${layoutParams.blur !== 0 ? 'will-change: transform;' : ''} } .embed-youtube-video-wrapper-${item.id} .embed-${item.id} { border-radius: ${layoutParams.radius * 100}vw; } `); })} `} ); };