diff --git a/.claude/plans/player-api-implementation.md b/.claude/plans/player-api-implementation.md index 8c172912..0d03fe73 100644 --- a/.claude/plans/player-api-implementation.md +++ b/.claude/plans/player-api-implementation.md @@ -1202,19 +1202,15 @@ export function createPlayer[]>( ## Phase 5: Cleanup -### PR 15: refactor(store): remove createStore from react and lit +### PR 15: refactor(store): remove createStore from lit Remove deprecated exports, update package indexes. +**Note:** React cleanup (`createStore`, `useStoreContext`, etc.) was done in Phase 3 (PR 11). + **Files:** ``` -packages/store/src/react/create-store.tsx (delete) -packages/store/src/react/context.tsx (delete) -packages/store/src/react/index.ts (update) -packages/store/src/react/tests/create-store.test.tsx (delete) -packages/store/src/react/tests/context.test.tsx (delete) - packages/store/src/lit/create-store.ts (delete) packages/store/src/lit/mixins/provider-mixin.ts (delete) packages/store/src/lit/mixins/container-mixin.ts (delete) diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index c442bc3d..72f6f4d2 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -1,8 +1,50 @@ 'use client'; -// Features (re-export for convenience) -export { media } from '@videojs/core/dom'; -// Store -export * from '@videojs/store/react'; -// Media +// Re-exports from core/dom +export { + type BufferState, + type FeatureAvailability, + features, + type Media, + type MediaContainer, + type PlaybackState, + type PlayerTarget, + type SourceState, + selectBuffer, + selectPlayback, + selectSource, + selectTime, + selectVolume, + type TimeState, + type VolumeState, +} from '@videojs/core/dom'; + +export type { AnyFeature, Feature, InferFeatureState } from '@videojs/store'; + +// Re-exports (for custom features) +export { createFeatureSelector, defineFeature } from '@videojs/store'; +export type { Comparator, Selector } from '@videojs/store/react'; + +// Re-exports (for advanced store access) +export { useSelector, useStore } from '@videojs/store/react'; + +// Media primitives +export { Audio, type AudioProps } from './media/audio'; export { Video, type VideoProps } from './media/video'; +export { + Container, + type ContainerProps, + type PlayerContextValue, + useMedia, + useMediaRegistration, + usePlayer, + usePlayerContext, +} from './player/context'; + +// Player API +export { + type CreatePlayerConfig, + type CreatePlayerResult, + createPlayer, + type ProviderProps, +} from './player/create-player'; diff --git a/packages/react/src/media/audio.tsx b/packages/react/src/media/audio.tsx new file mode 100644 index 00000000..d1f31dd1 --- /dev/null +++ b/packages/react/src/media/audio.tsx @@ -0,0 +1,32 @@ +'use client'; + +import type { AudioHTMLAttributes } from 'react'; +import { forwardRef, useCallback } from 'react'; + +import { useMediaRegistration } from '../player/context'; +import { useComposedRefs } from '../utils/use-composed-refs'; + +export interface AudioProps extends AudioHTMLAttributes {} + +export const Audio = forwardRef(function Audio({ children, ...props }, ref) { + const setMedia = useMediaRegistration(); + + const mediaRef = useCallback( + (el: HTMLAudioElement | null) => { + setMedia?.(el); + }, + [setMedia] + ); + + const composedRef = useComposedRefs(ref, mediaRef); + + return ( + + ); +}); + +export namespace Audio { + export type Props = AudioProps; +} diff --git a/packages/react/src/media/tests/audio.test.tsx b/packages/react/src/media/tests/audio.test.tsx new file mode 100644 index 00000000..bb28163e --- /dev/null +++ b/packages/react/src/media/tests/audio.test.tsx @@ -0,0 +1,97 @@ +import { render } from '@testing-library/react'; +import type { ReactNode } from 'react'; +import { createRef } from 'react'; +import { describe, expect, it, vi } from 'vitest'; + +import { PlayerContextProvider, type PlayerContextValue } from '../../player/context'; +import { Audio } from '../audio'; + +describe('Audio', () => { + function createMockStore() { + return { + state: { volume: 1, muted: false }, + attach: vi.fn(() => vi.fn()), + subscribe: vi.fn(() => vi.fn()), + destroy: vi.fn(), + }; + } + + function createWrapper(value: PlayerContextValue) { + return function Wrapper({ children }: { children: ReactNode }) { + return {children}; + }; + } + + describe('standalone (without Provider)', () => { + it('renders without error', () => { + const { container } = render(