mirror of
https://github.com/zoriya/v10.git
synced 2026-08-07 22:56:34 +00:00
106 lines
3.0 KiB
TypeScript
106 lines
3.0 KiB
TypeScript
'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 extends AnyPlayerFeature[]> {
|
|
features: Features;
|
|
displayName?: string;
|
|
}
|
|
|
|
export interface ProviderProps {
|
|
children: ReactNode;
|
|
}
|
|
|
|
export interface CreatePlayerResult<Store extends PlayerStore> {
|
|
Provider: FC<ProviderProps>;
|
|
Container: typeof Container;
|
|
usePlayer: UsePlayerHook<Store>;
|
|
useMedia: () => Media | null;
|
|
}
|
|
|
|
export type UsePlayerHook<Store extends PlayerStore> = {
|
|
(): Store;
|
|
<R>(selector: (state: InferStoreState<Store>) => 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<VideoFeatures>): CreatePlayerResult<VideoPlayerStore>;
|
|
|
|
/**
|
|
* Create a player for audio media.
|
|
*
|
|
* @label Audio
|
|
* @param config - Player configuration with features and optional display name.
|
|
*/
|
|
export function createPlayer(config: CreatePlayerConfig<AudioFeatures>): CreatePlayerResult<AudioPlayerStore>;
|
|
|
|
/**
|
|
* Create a player with custom features.
|
|
*
|
|
* @label Generic
|
|
* @param config - Player configuration with features and optional display name.
|
|
*/
|
|
export function createPlayer<const Features extends AnyPlayerFeature[]>(
|
|
config: CreatePlayerConfig<Features>
|
|
): CreatePlayerResult<PlayerStore<Features>>;
|
|
|
|
export function createPlayer(config: CreatePlayerConfig<AnyPlayerFeature[]>): CreatePlayerResult<AnyPlayerStore> {
|
|
function Provider({ children }: ProviderProps): ReactNode {
|
|
const [store] = useState(() => createStore<PlayerTarget>()(combine(...config.features)));
|
|
const [media, setMedia] = useState<Media | null>(null);
|
|
const [container, setContainer] = useState<HTMLElement | null>(null);
|
|
|
|
useDestroy(store);
|
|
|
|
useEffect(() => {
|
|
if (!media) return;
|
|
return store.attach({ media, container });
|
|
}, [media, container, store]);
|
|
|
|
return (
|
|
<PlayerContextProvider value={{ store, media, setMedia, container, setContainer }}>
|
|
{children}
|
|
</PlayerContextProvider>
|
|
);
|
|
}
|
|
|
|
if (__DEV__ && config.displayName) {
|
|
Provider.displayName = `${config.displayName}.Provider`;
|
|
}
|
|
|
|
function usePlayer<R>(selector?: (state: object) => R): AnyPlayerStore | R {
|
|
const { store } = usePlayerContext();
|
|
return useStore(store, selector as any);
|
|
}
|
|
|
|
return {
|
|
Provider,
|
|
Container,
|
|
usePlayer,
|
|
useMedia,
|
|
};
|
|
}
|