diff --git a/.claude/plans/player-api/examples.md b/.claude/plans/player-api/examples.md index e7b93b82..d1d9a422 100644 --- a/.claude/plans/player-api/examples.md +++ b/.claude/plans/player-api/examples.md @@ -2,6 +2,8 @@ Usage examples for React, HTML, and Lit. +> **Note:** Some examples here are for demonstration. In practice, UI primitives like ``, ``, etc. would be provided. + ## React ### Declarative (Skin) @@ -23,7 +25,7 @@ function App() { } ``` -### Custom Player (Preset) +### Custom Player ```tsx import { createPlayer, presets, Video } from '@videojs/react'; @@ -44,103 +46,57 @@ function App() { function Controls() { const player = usePlayer(); - return ( -
- - - player.setVolume(Number(e.target.value))} - /> -
- ); + return ; } ``` ### Extended Preset ```tsx -import { createPlayer, createPlayerFeature, features, presets, Video } from '@videojs/react'; +import { createPlayer, features, presets } from '@videojs/react'; -// Custom analytics feature -const analytics = createPlayerFeature({ - initialState: { events: [] as string[] }, - getSnapshot: ({ initialState }) => initialState, - subscribe: ({ target, update }) => { - target.media.subscribe( - (s) => s.paused, - (paused) => { - console.log(paused ? 'paused' : 'playing'); - update(); - } - ); +const { Provider, usePlayer } = createPlayer({ + features: [...presets.website, features.keyboard], +}); +``` + +### Custom Feature + +```tsx +import { createPlayer, createPlayerFeature, presets } from '@videojs/react'; + +const pip = createPlayerFeature({ + initialState: { active: false }, + getSnapshot: ({ target }) => ({ + active: document.pictureInPictureElement === target.media.element, + }), + subscribe: ({ update, signal }) => { + document.addEventListener('enterpictureinpicture', update, { signal }); + document.addEventListener('leavepictureinpicture', update, { signal }); }, request: { - trackEvent: (name: string) => { - console.log('Track:', name); - }, + enterPip: (_, { target }) => target.media.element.requestPictureInPicture(), + exitPip: () => document.exitPictureInPicture(), }, }); -const { Provider, Container, usePlayer } = createPlayer({ - features: [...presets.website, analytics], +const { Provider, usePlayer } = createPlayer({ + features: [...presets.website, pip], }); - -function App() { - return ( - - - - - ); -} - -function Controls() { - const player = usePlayer(); - - const handlePlay = () => { - player.play(); - player.trackEvent('play_clicked'); - }; - - return ; -} ``` ### Media Escape Hatch -```tsx -import { createPlayer, presets } from '@videojs/react'; +Direct media access when player features don't expose what you need. +```tsx const { usePlayer, useMedia } = createPlayer(presets.website); function DebugPanel() { const player = usePlayer(); const media = useMedia(); - return ( -
-      {JSON.stringify(
-        {
-          // Player state (preferred)
-          isFullscreen: player.isFullscreen,
-
-          // Media state directly (escape hatch)
-          mediaFullscreen: media.isFullscreen,
-          readyState: media.readyState,
-          networkState: media.networkState,
-        },
-        null,
-        2
-      )}
-    
- ); + // player.isFullscreen vs media.isFullscreen (raw) } ``` @@ -153,15 +109,7 @@ const { Provider, useMedia } = createMedia([features.playback, features.time]); function AudioPlayer() { const media = useMedia(); - // Programmatic control, no UI - useEffect(() => { - if (media.currentTime > 30) { - media.pause(); - } - }, [media.currentTime]); - - return