diff --git a/packages/react/react/src/components/Video.tsx b/packages/react/react/src/components/Video.tsx new file mode 100644 index 00000000..da6d2992 --- /dev/null +++ b/packages/react/react/src/components/Video.tsx @@ -0,0 +1,125 @@ +'use client'; +import * as React from 'react'; +import { useMediaRef } from '@vjs-10/react-media-store'; +import { createMediaStateOwner } from '@vjs-10/media'; +import { + ElementType, + VideoHTMLAttributes, + DetailedHTMLProps, + PropsWithChildren, + CSSProperties, + Ref, + useImperativeHandle, + useRef, +} from 'react'; + +export type MuxVideoProps = { + 'playback-id'?: string; +}; + +type MediaStateOwner = NonNullable>[0]>; + +/** @TODO Improve type inference and narrowing/widening for different use cases (CJP) */ +type ComponentType = ElementType< + Omit< + DetailedHTMLProps, HTMLVideoElement>, + 'ref' + > & { ref: Ref } +>; + +// These are the first steps/WIP POC of decoupling the Media State Owner from the DOM. +// Note that everything will still work if you use: +// 1. an audio/video element directly +// 2. a custom element a la media-elements +type CreateMediaStateOwner = typeof createMediaStateOwner; +const useMediaStateOwner = ( + ref: Ref, + createMediaStateOwner: CreateMediaStateOwner /*, props? */ +) => { + const mediaStateOwnerRef = useRef(createMediaStateOwner(/* props? */)); + useImperativeHandle(ref, () => mediaStateOwnerRef.current, []); + /** @TODO Parameterize this (CJP) */ + type ComponentProps = DetailedHTMLProps< + VideoHTMLAttributes, + HTMLVideoElement + >; + return { + updateMediaElement( + mediaEl: HTMLMediaElement | null, + props: ComponentProps + ) { + // NOTE: The details here will almost definitely change for a less "bare bones"/"POC" implementation of Media State Owner impl. (CJP) + mediaStateOwnerRef.current.mediaElement = mediaEl ?? undefined; + mediaStateOwnerRef.current.src = props.src as string; + if (props.muted) { + mediaStateOwnerRef.current.muted = props.muted; + } + }, + }; +}; + +const DefaultVideoComponent: ElementType< + Omit< + DetailedHTMLProps, HTMLVideoElement>, + 'ref' + > & { ref: Ref } +> = ({ children, ref, ...props }) => { + const { updateMediaElement } = useMediaStateOwner(ref, createMediaStateOwner); + return ( + + ); +}; + +/** + * @description This is a "thin wrapper" around the media component whose primary responsibility is to wire up the element + * to the 's MediaStore for the media state. + * @param props - Identical to both a