mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
docs(site): add thumbnail reference page (#654)
This commit is contained in:
@@ -15,6 +15,11 @@ export interface PlayerContextValue {
|
||||
}
|
||||
|
||||
const PlayerContext = createContext<PlayerContextValue | null>(null);
|
||||
const EMPTY_UNSUBSCRIBE = () => {};
|
||||
const EMPTY_STORE = {
|
||||
state: {} as UnknownState,
|
||||
subscribe: () => EMPTY_UNSUBSCRIBE,
|
||||
} as Pick<UnknownStore, 'state' | 'subscribe'>;
|
||||
|
||||
export function PlayerContextProvider({
|
||||
value,
|
||||
@@ -51,6 +56,23 @@ export function usePlayer<R>(selector?: (state: UnknownState) => R) {
|
||||
return useStore(store, selector as any);
|
||||
}
|
||||
|
||||
/**
|
||||
* Access player state when available, but return `undefined` outside Provider.
|
||||
*
|
||||
* This is useful for components that can operate without player context
|
||||
* (e.g. they accept fully explicit props as a fallback).
|
||||
*/
|
||||
/** @label Without Selector */
|
||||
export function useOptionalPlayer(): UnknownStore | undefined;
|
||||
/** @label With Selector */
|
||||
export function useOptionalPlayer<R>(selector: (state: UnknownState) => R): R | undefined;
|
||||
export function useOptionalPlayer<R>(selector?: (state: UnknownState) => R) {
|
||||
const ctx = useContext(PlayerContext);
|
||||
const store = (ctx?.store ?? (EMPTY_STORE as unknown as UnknownStore)) as UnknownStore;
|
||||
const value = useStore(store, (ctx ? selector : undefined) as any);
|
||||
return ctx ? value : undefined;
|
||||
}
|
||||
|
||||
/** Access the media element from within a Player Provider. */
|
||||
export function useMedia(): Media | null {
|
||||
const { media } = usePlayerContext();
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
type PlayerContextValue,
|
||||
useMedia,
|
||||
useMediaRegistration,
|
||||
useOptionalPlayer,
|
||||
usePlayer,
|
||||
usePlayerContext,
|
||||
} from '../context';
|
||||
@@ -83,6 +84,47 @@ describe('usePlayer', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('useOptionalPlayer', () => {
|
||||
it('returns undefined outside Provider', () => {
|
||||
const { result } = renderHook(() => useOptionalPlayer());
|
||||
expect(result.current).toBeUndefined();
|
||||
});
|
||||
|
||||
it('returns undefined outside Provider with selector', () => {
|
||||
const { result } = renderHook(() => useOptionalPlayer((state: any) => state.paused));
|
||||
expect(result.current).toBeUndefined();
|
||||
});
|
||||
|
||||
it('does not run selector outside Provider', () => {
|
||||
const selector = vi.fn(() => true);
|
||||
const { result } = renderHook(() => useOptionalPlayer(selector));
|
||||
expect(result.current).toBeUndefined();
|
||||
expect(selector).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('returns store inside Provider', () => {
|
||||
const store = createMockStore();
|
||||
const value: PlayerContextValue = { store: store as any, media: null, setMedia: vi.fn() };
|
||||
|
||||
const { result } = renderHook(() => useOptionalPlayer(), {
|
||||
wrapper: createWrapper(value),
|
||||
});
|
||||
|
||||
expect(result.current).toBe(store);
|
||||
});
|
||||
|
||||
it('returns selected state inside Provider', () => {
|
||||
const store = createMockStore();
|
||||
const value: PlayerContextValue = { store: store as any, media: null, setMedia: vi.fn() };
|
||||
|
||||
const { result } = renderHook(() => useOptionalPlayer((state: any) => state.paused), {
|
||||
wrapper: createWrapper(value),
|
||||
});
|
||||
|
||||
expect(result.current).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useMedia', () => {
|
||||
it('returns media from context', () => {
|
||||
const store = createMockStore();
|
||||
|
||||
@@ -11,7 +11,7 @@ import { createThumbnail, selectTextTrack } from '@videojs/core/dom';
|
||||
import type { CSSProperties } from 'react';
|
||||
import { forwardRef, useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { usePlayer } from '../../player/context';
|
||||
import { useOptionalPlayer } from '../../player/context';
|
||||
import type { UIComponentProps } from '../../utils/types';
|
||||
import { renderElement } from '../../utils/use-render';
|
||||
|
||||
@@ -36,7 +36,7 @@ export const Thumbnail = forwardRef<HTMLDivElement, ThumbnailProps>(function Thu
|
||||
const [core] = useState(() => new ThumbnailCore());
|
||||
const divRef = useRef<HTMLDivElement>(null);
|
||||
const imgRef = useRef<HTMLImageElement>(null);
|
||||
const textTrack = usePlayer(selectTextTrack);
|
||||
const textTrack = useOptionalPlayer(selectTextTrack);
|
||||
|
||||
// Force re-render when the handle's state changes (img load/error, resize).
|
||||
const [, setRenderToken] = useState(0);
|
||||
|
||||
Reference in New Issue
Block a user