'use client'; import type { AnyPlayerFeature, AnyPlayerStore, AudioFeatures, AudioPlayerStore, Media, PlayerStore, PlayerTarget, VideoFeatures, VideoPlayerStore, } from '@videojs/core/dom'; import type { InferStoreState } from '@videojs/store'; import { combine, createStore } from '@videojs/store'; import { useStore } from '@videojs/store/react'; import type { FC, ReactNode } from 'react'; import { useEffect, useState } from 'react'; import { useDestroy } from '../utils/use-destroy'; import { Container, PlayerContextProvider, useMedia, usePlayerContext } from './context'; export interface CreatePlayerConfig { features: Features; displayName?: string; } export interface ProviderProps { children: ReactNode; } export interface CreatePlayerResult { Provider: FC; Container: typeof Container; usePlayer: UsePlayerHook; useMedia: () => Media | null; } export type UsePlayerHook = { (): Store; (selector: (state: InferStoreState) => R): R; }; /** * Create a player instance with typed store, Provider component, Container, and hooks. * * @label Video * @param config - Player configuration with features and optional display name. */ export function createPlayer(config: CreatePlayerConfig): CreatePlayerResult; /** * Create a player for audio media. * * @label Audio * @param config - Player configuration with features and optional display name. */ export function createPlayer(config: CreatePlayerConfig): CreatePlayerResult; /** * Create a player with custom features. * * @label Generic * @param config - Player configuration with features and optional display name. */ export function createPlayer( config: CreatePlayerConfig ): CreatePlayerResult>; export function createPlayer(config: CreatePlayerConfig): CreatePlayerResult { function Provider({ children }: ProviderProps): ReactNode { const [store] = useState(() => createStore()(combine(...config.features))); const [media, setMedia] = useState(null); const [container, setContainer] = useState(null); useDestroy(store); useEffect(() => { if (!media) return; return store.attach({ media, container }); }, [media, container, store]); return ( {children} ); } if (__DEV__ && config.displayName) { Provider.displayName = `${config.displayName}.Provider`; } function usePlayer(selector?: (state: object) => R): AnyPlayerStore | R { const { store } = usePlayerContext(); return useStore(store, selector as any); } return { Provider, Container, usePlayer, useMedia, }; }