import { MediaProvider, MediaSkinDefault, MediaSkinToasted, Video } from '@vjs-10/react'; import './globals.css'; import { useCallback, useMemo, useState, type ChangeEventHandler } from 'react'; const skins = [{ key: 'default', name: 'Frosted', component: MediaSkinDefault, }, { key: 'toasted', name: 'Toasted', component: MediaSkinToasted, }] as const; type SkinKey = (typeof skins)[number]['key']; const mediaSources = [{ key: '1', name: 'Mux 1', value: 'https://stream.mux.com/fXNzVtmtWuyz00xnSrJg4OJH6PyNo6D02UzmgeKGkP5YQ.m3u8' }, { key: '2', name: 'Mux 2', value: 'https://stream.mux.com/a4nOgmxGWg6gULfcBbAa00gXyfcwPnAFldF8RdsNyk8M.m3u8' }, { key: '3', name: 'Mux 3', value: 'https://stream.mux.com/A3VXy02VoUinw01pwyomEO3bHnG4P32xzV7u1j1FSzjNg/high.mp4' }, { key: '4', name: 'Mux 4', value: 'https://stream.mux.com/lyrKpPcGfqyzeI00jZAfW6MvP6GNPrkML.m3u8' }] as const; type MediaSourceKey = (typeof mediaSources)[number]['key']; function getParam(key: string, defaultValue: T): T { const params = new URLSearchParams(window.location.search); return params.get(key) as T || defaultValue; } function setParam(key: string, value: string) { const params = new URLSearchParams(window.location.search); params.set(key, value); const search = params.toString(); const url = window.location.pathname + (search ? `?${search}` : ''); window.history.replaceState(null, '', url); } const DEFAULT_SKIN: SkinKey = 'toasted'; const DEFAULT_MEDIA_SOURCE: MediaSourceKey = '1'; export default function App(): JSX.Element { const [skinKey, setSkinKey] = useState(getParam('skin', DEFAULT_SKIN)); const [mediaSourceKey, setMediaSourceKey] = useState(getParam('source', DEFAULT_MEDIA_SOURCE)); const mediaSource = useMemo(() => { let match = mediaSources.find(m => m.key === mediaSourceKey); if (!match) { match = mediaSources.find(m => m.key === DEFAULT_MEDIA_SOURCE)!; setMediaSourceKey(match.key); } return match.value; }, [mediaSourceKey]); const Skin = useMemo(() => { let match = skins.find(s => s.key === skinKey); if (!match) { match = skins.find(s => s.key === DEFAULT_SKIN)!; setSkinKey(match.key); } return match.component; }, [skinKey]); const onChangeSkin: ChangeEventHandler = useCallback((event) => { const value = event.target.value as SkinKey; setSkinKey(value); setParam('skin', value); }, []); const onChangeMediaSource: ChangeEventHandler = useCallback((event) => { const value = event.target.value as MediaSourceKey; setMediaSourceKey(value); setParam('source', value); }, []); // Force a re-render on changes. const key = `${skinKey}-${mediaSourceKey}`; const skinClassName = useMemo(() => { switch (skinKey) { case 'default': return 'rounded-4xl shadow shadow-lg shadow-black/15'; case 'toasted': return 'rounded-lg shadow shadow-lg shadow-black/15'; default: return ''; } }, [skinKey]); const playbackId = mediaSource.match(/stream\.mux\.com\/([^./]+)/)?.[1]; const poster = playbackId ? `https://image.mux.com/${playbackId}/thumbnail.webp` : undefined; return ( <>

Playground

Test out the various skins for Video.js.
{/* @ts-ignore -- types are incorrect */}
); }