Skip to content

Commit

Permalink
Add Suspense in Background Video and suppressHydrationWarning
Browse files Browse the repository at this point in the history
  • Loading branch information
ronalduQualabs committed Jan 29, 2025
1 parent 36b6602 commit 0e53492
Showing 1 changed file with 97 additions and 103 deletions.
200 changes: 97 additions & 103 deletions src/components/players/background-player.tsx
Original file line number Diff line number Diff line change
@@ -1,87 +1,78 @@
'use client';

import { forwardRef, Children, isValidElement, useState } from 'react';
import { forwardRef, Children, isValidElement, useState, Suspense } from 'react';
import Media from './media/index.js';
import { getPlaybackId, getPosterURLFromPlaybackId } from '../../providers/mux/transformer.js';
import { svgBlurImage } from '../utils.js';

import type { PlayerProps } from '../types.js';
import type { MediaProps } from './media/index.js';

const BackgroundPlayer = forwardRef<HTMLVideoElement, Omit<MediaProps, 'ref'> & PlayerProps>((allProps, forwardedRef) => {
let {
style,
className,
children,
asset,
poster,
blurDataURL,
onPlaying,
onLoadStart,
...rest
} = allProps;

const slottedPoster = Children.toArray(children).find((child) => {
return typeof child === 'object' && 'type' in child && (child.props as any).slot === 'poster';
});

// If there's a slotted poster image (e.g. next/image) remove the default player poster and blurDataURL.
if (isValidElement(slottedPoster)) {
poster = '';
blurDataURL = undefined;
}
const BackgroundPlayer = forwardRef<HTMLVideoElement, Omit<MediaProps, 'ref'> & PlayerProps>(
(allProps, forwardedRef) => {
let { style, className, children, asset, poster, blurDataURL, onPlaying, onLoadStart, ...rest } = allProps;

const props = rest as MediaProps & { thumbnailTime?: number };
const imgStyleProps: React.CSSProperties = {};
const playbackId = asset ? getPlaybackId(asset) : undefined;

let isCustomPoster = true;
let srcSet: string | undefined;

if (playbackId && asset?.status === 'ready') {
props.src = undefined;
props.playbackId = playbackId;

if (poster) {
isCustomPoster = poster !== getPosterURLFromPlaybackId(playbackId, props);

if (!isCustomPoster) {
// If it's not a custom poster URL, optimize with a srcset.
srcSet =
`${getPosterURLFromPlaybackId(playbackId, { ...props, width: 480 })} 480w,` +
`${getPosterURLFromPlaybackId(playbackId, { ...props, width: 640 })} 640w,` +
`${getPosterURLFromPlaybackId(playbackId, { ...props, width: 960 })} 960w,` +
`${getPosterURLFromPlaybackId(playbackId, { ...props, width: 1280 })} 1280w,` +
`${getPosterURLFromPlaybackId(playbackId, { ...props, width: 1600 })} 1600w,` +
`${getPosterURLFromPlaybackId(playbackId, { ...props })} 1920w`;
}
const slottedPoster = Children.toArray(children).find((child) => {
return typeof child === 'object' && 'type' in child && (child.props as any).slot === 'poster';
});

// If there's a slotted poster image (e.g. next/image) remove the default player poster and blurDataURL.
if (isValidElement(slottedPoster)) {
poster = '';
blurDataURL = undefined;
}
}

if (blurDataURL) {
const showGeneratedBlur = !isCustomPoster && blurDataURL === asset?.blurDataURL;
const showCustomBlur = isCustomPoster && blurDataURL !== asset?.blurDataURL;

if (showGeneratedBlur || showCustomBlur) {
imgStyleProps.width = '100%';
imgStyleProps.height = '100%';
imgStyleProps.color = 'transparent';
imgStyleProps.backgroundSize = 'cover';
imgStyleProps.backgroundPosition = 'center';
imgStyleProps.backgroundRepeat = 'no-repeat';
imgStyleProps.backgroundImage = `url('data:image/svg+xml;charset=utf-8,${svgBlurImage(blurDataURL)}')`;
const props = rest as MediaProps & { thumbnailTime?: number };
const imgStyleProps: React.CSSProperties = {};
const playbackId = asset ? getPlaybackId(asset) : undefined;

let isCustomPoster = true;
let srcSet: string | undefined;

if (playbackId && asset?.status === 'ready') {
props.src = undefined;
props.playbackId = playbackId;

if (poster) {
isCustomPoster = poster !== getPosterURLFromPlaybackId(playbackId, props);

if (!isCustomPoster) {
// If it's not a custom poster URL, optimize with a srcset.
srcSet =
`${getPosterURLFromPlaybackId(playbackId, { ...props, width: 480 })} 480w,` +
`${getPosterURLFromPlaybackId(playbackId, { ...props, width: 640 })} 640w,` +
`${getPosterURLFromPlaybackId(playbackId, { ...props, width: 960 })} 960w,` +
`${getPosterURLFromPlaybackId(playbackId, { ...props, width: 1280 })} 1280w,` +
`${getPosterURLFromPlaybackId(playbackId, { ...props, width: 1600 })} 1600w,` +
`${getPosterURLFromPlaybackId(playbackId, { ...props })} 1920w`;
}
}
}
}

// Remove props that are not supported by MuxVideo.
delete props.thumbnailTime;
if (blurDataURL) {
const showGeneratedBlur = !isCustomPoster && blurDataURL === asset?.blurDataURL;
const showCustomBlur = isCustomPoster && blurDataURL !== asset?.blurDataURL;

if (showGeneratedBlur || showCustomBlur) {
imgStyleProps.width = '100%';
imgStyleProps.height = '100%';
imgStyleProps.color = 'transparent';
imgStyleProps.backgroundSize = 'cover';
imgStyleProps.backgroundPosition = 'center';
imgStyleProps.backgroundRepeat = 'no-repeat';
imgStyleProps.backgroundImage = `url('data:image/svg+xml;charset=utf-8,${svgBlurImage(blurDataURL)}')`;
}
}

const [posterHidden, setPosterHidden] = useState(false);
// Remove props that are not supported by MuxVideo.
delete props.thumbnailTime;
const [posterHidden, setPosterHidden] = useState(false);

return (
<>
<style>{
/* css */`
return (
<Suspense fallback={null}>
<>
<style>{
/* css */ `
.next-video-bg {
width: 100%;
height: 100%;
Expand Down Expand Up @@ -117,40 +108,43 @@ const BackgroundPlayer = forwardRef<HTMLVideoElement, Omit<MediaProps, 'ref'> &
padding: 5% 5% 10%;
}
`
}</style>
<div className={`${className ? `${className} ` : ''}next-video-bg`} style={{ ...style }}>
<Media
ref={forwardedRef}
className="next-video-bg-video"
onPlaying={(event) => {
onPlaying?.(event as any);
setPosterHidden(true);
}}
onLoadStart={(event) => {
onLoadStart?.(event as any);
setPosterHidden(false);
}}
muted={true}
autoPlay={true}
loop={true}
playsInline={true}
{...props}
/>
{poster && (
<img
className="next-video-bg-poster"
src={isCustomPoster ? poster : undefined}
srcSet={srcSet}
style={imgStyleProps}
hidden={posterHidden}
decoding="async"
aria-hidden="true"
/>
)}
<div className="next-video-bg-text">{children}</div>
</div>
</>
);
});
}</style>
<div className={`${className ? `${className} ` : ''}next-video-bg`} style={{ ...style }}>
<Media
suppressHydrationWarning
ref={forwardedRef}
className="next-video-bg-video"
onPlaying={(event) => {
onPlaying?.(event as any);
setPosterHidden(true);
}}
onLoadStart={(event) => {
onLoadStart?.(event as any);
setPosterHidden(false);
}}
muted={true}
autoPlay={true}
loop={true}
playsInline={true}
{...props}
/>
{poster && (
<img
className="next-video-bg-poster"
src={isCustomPoster ? poster : undefined}
srcSet={srcSet}
style={imgStyleProps}
hidden={posterHidden}
decoding="async"
aria-hidden="true"
/>
)}
<div className="next-video-bg-text">{children}</div>
</div>
</>
</Suspense>
);
}
);

export default BackgroundPlayer;

0 comments on commit 0e53492

Please sign in to comment.