mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat: add background video components (#567)
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
import { BackgroundVideo } from '../../media/background-video';
|
||||
|
||||
export class BackgroundVideoElement extends BackgroundVideo {
|
||||
static readonly tagName = 'background-video';
|
||||
}
|
||||
|
||||
customElements.define(BackgroundVideoElement.tagName, BackgroundVideoElement);
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
[BackgroundVideoElement.tagName]: BackgroundVideoElement;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { HlsVideo } from '../../ui/hls-video/hls-video-element';
|
||||
import { HlsVideo } from '../../media/hls-video';
|
||||
|
||||
export class HlsVideoElement extends HlsVideo {
|
||||
static readonly tagName = 'hls-video';
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import { CustomMediaMixin } from '../custom-media-element';
|
||||
|
||||
function getTemplateHTML(attrs: Record<string, string>) {
|
||||
return /*html*/ `
|
||||
<style>
|
||||
:host {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
video {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: inherit;
|
||||
}
|
||||
</style>
|
||||
<slot></slot>
|
||||
<video ${serializeAttributes(attrs)}></video>
|
||||
`;
|
||||
}
|
||||
|
||||
export class BackgroundVideo extends CustomMediaMixin(HTMLElement, { tag: 'video' }) {
|
||||
static shadowRootOptions = { mode: 'open' as ShadowRootMode };
|
||||
static getTemplateHTML = getTemplateHTML;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
if (!this.shadowRoot) {
|
||||
this.attachShadow((this.constructor as typeof BackgroundVideo).shadowRootOptions);
|
||||
|
||||
const attrs = {
|
||||
...namedNodeMapToObject(this.attributes),
|
||||
...(!this.hasAttribute('nomuted') && { muted: '' }),
|
||||
...(!this.hasAttribute('noloop') && { loop: '' }),
|
||||
...(!this.hasAttribute('noautoplay') && { autoplay: '' }),
|
||||
playsinline: '',
|
||||
disableremoteplayback: '',
|
||||
disablepictureinpicture: '',
|
||||
};
|
||||
|
||||
this.shadowRoot!.innerHTML = getTemplateHTML(attrs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function namedNodeMapToObject(namedNodeMap: NamedNodeMap) {
|
||||
const obj: Record<string, string> = {};
|
||||
for (const attr of namedNodeMap) {
|
||||
obj[attr.name] = attr.value;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
const VideoAttributes = [
|
||||
'autoplay',
|
||||
'controls',
|
||||
'controlslist',
|
||||
'crossorigin',
|
||||
'disablepictureinpicture',
|
||||
'disableremoteplayback',
|
||||
'loop',
|
||||
'muted',
|
||||
'playsinline',
|
||||
'preload',
|
||||
] as const;
|
||||
|
||||
function serializeAttributes(attrs: Record<string, string>): string {
|
||||
let html = '';
|
||||
for (const key in attrs) {
|
||||
// Skip forwarding non native video attributes.
|
||||
if (!VideoAttributes.includes(key as any)) continue;
|
||||
|
||||
const value = attrs[key];
|
||||
if (value === '') html += ` ${key}`;
|
||||
else html += ` ${key}="${value}"`;
|
||||
}
|
||||
return html;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
'use client';
|
||||
|
||||
import type { VideoHTMLAttributes } from 'react';
|
||||
import { forwardRef, useCallback } from 'react';
|
||||
|
||||
import { useMediaRegistration } from '../../player/context';
|
||||
import { useComposedRefs } from '../../utils/use-composed-refs';
|
||||
|
||||
export interface BackgroundVideoProps extends VideoHTMLAttributes<HTMLVideoElement> {}
|
||||
|
||||
export const BackgroundVideo = forwardRef<HTMLVideoElement, BackgroundVideoProps>(function BackgroundVideo(
|
||||
{ children, ...props },
|
||||
ref
|
||||
) {
|
||||
const setMedia = useMediaRegistration();
|
||||
|
||||
const mediaRef = useCallback(
|
||||
(el: HTMLVideoElement | null) => {
|
||||
setMedia?.(el);
|
||||
},
|
||||
[setMedia]
|
||||
);
|
||||
|
||||
const composedRef = useComposedRefs(ref, mediaRef);
|
||||
|
||||
return (
|
||||
<video ref={composedRef} muted autoPlay loop playsInline disableRemotePlayback disablePictureInPicture {...props}>
|
||||
{children}
|
||||
</video>
|
||||
);
|
||||
});
|
||||
|
||||
export namespace BackgroundVideo {
|
||||
export type Props = BackgroundVideoProps;
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
export { BackgroundVideo, type BackgroundVideoProps } from '@/media/background-video';
|
||||
export * from './skin';
|
||||
|
||||
Reference in New Issue
Block a user