mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat(site): add util reference pipeline (#537)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
c11395ece1
commit
78112fbefd
@@ -5,7 +5,7 @@ frameworkTitle:
|
||||
description: Loading indicator that displays when the video player is buffering or waiting for data
|
||||
---
|
||||
|
||||
import ApiReference from "@/components/docs/api-reference/ApiReference.astro";
|
||||
import ComponentReference from "@/components/docs/api-reference/ComponentReference.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
import StyleCase from "@/components/docs/StyleCase.astro";
|
||||
import Demo from "@/components/docs/demos/Demo.astro";
|
||||
@@ -70,4 +70,4 @@ Hide and show the indicator based on the `data-visible` attribute.
|
||||
</StyleCase>
|
||||
</FrameworkCase>
|
||||
|
||||
<ApiReference component="BufferingIndicator" />
|
||||
<ComponentReference component="BufferingIndicator" />
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
title: ContainerMixin
|
||||
description: Mixin that consumes player context and auto-attaches media elements
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
|
||||
`ContainerMixin` creates a class that consumes the player store from context and automatically attaches `<video>` or `<audio>` elements found within it. It uses a `MutationObserver` to watch for media element changes and calls `store.attach()` to keep the store's media target in sync.
|
||||
|
||||
### When to use ContainerMixin
|
||||
|
||||
Use `ContainerMixin` when the <DocsLink slug="reference/provider-mixin">provider</DocsLink> and container live in different elements. This is common when the store owner sits higher in the tree (e.g., a layout shell) while the media element sits deeper in a content area.
|
||||
|
||||
For a single element that both owns the store and attaches media, use <DocsLink slug="reference/player-mixin">`PlayerMixin`</DocsLink> instead.
|
||||
|
||||
### How media discovery works
|
||||
|
||||
On `connectedCallback`, `ContainerMixin` sets up a `MutationObserver` on its children. When a `<video>` or `<audio>` element is added or removed, it calls `store.attach({ media, container })` or cleans up the previous attachment. The observer is torn down on `disconnectedCallback`.
|
||||
|
||||
### Split composition
|
||||
|
||||
Pair `ContainerMixin` with <DocsLink slug="reference/provider-mixin">`ProviderMixin`</DocsLink> for full control over which element owns the store and which discovers the media:
|
||||
|
||||
```ts
|
||||
const { ProviderMixin, ContainerMixin } = createPlayer({ features: features.video });
|
||||
|
||||
// Provider owns the store, sits at the top
|
||||
class PlayerShell extends ProviderMixin(MediaElement) {}
|
||||
|
||||
// Container discovers media, sits deeper in the tree
|
||||
class MediaRegion extends ContainerMixin(MediaElement) {}
|
||||
```
|
||||
|
||||
<UtilReference util="ContainerMixin" />
|
||||
@@ -5,7 +5,7 @@ frameworkTitle:
|
||||
description: Container component for composing and auto-hiding video player controls on user interaction
|
||||
---
|
||||
|
||||
import ApiReference from "@/components/docs/api-reference/ApiReference.astro";
|
||||
import ComponentReference from "@/components/docs/api-reference/ComponentReference.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
import StyleCase from "@/components/docs/StyleCase.astro";
|
||||
import Demo from "@/components/docs/demos/Demo.astro";
|
||||
@@ -105,4 +105,4 @@ No ARIA role is applied to `<media-controls>` — it is a layout wrapper, not a
|
||||
</StyleCase>
|
||||
</FrameworkCase>
|
||||
|
||||
<ApiReference component="Controls" />
|
||||
<ComponentReference component="Controls" />
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
title: createPlayer
|
||||
description: Factory function that creates a player instance with typed store, Provider component, Container, and hooks
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import Demo from "@/components/docs/demos/Demo.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
import StyleCase from "@/components/docs/StyleCase.astro";
|
||||
import BasicUsageDemoReact from "@/components/docs/demos/create-player/react/css/BasicUsage";
|
||||
import basicUsageReactTsx from "@/components/docs/demos/create-player/react/css/BasicUsage.tsx?raw";
|
||||
import basicUsageReactCss from "@/components/docs/demos/create-player/react/css/BasicUsage.css?raw";
|
||||
|
||||
`createPlayer` is the entry point for setting up a Video.js player in React. It accepts a configuration object with a `features` array and returns hooks and components for building a player.
|
||||
|
||||
The hook is typed according to the provided features, giving you full type safety for state selectors and actions.
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
<StyleCase styles={["css"]}>
|
||||
<Demo
|
||||
files={[
|
||||
{ title: "App.tsx", code: basicUsageReactTsx, lang: "tsx" },
|
||||
{ title: "App.css", code: basicUsageReactCss, lang: "css" },
|
||||
]}
|
||||
>
|
||||
<BasicUsageDemoReact client:idle />
|
||||
</Demo>
|
||||
</StyleCase>
|
||||
</FrameworkCase>
|
||||
|
||||
<UtilReference util="createPlayer" />
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
title: createSelector
|
||||
description: Create a type-safe selector for a store slice's state
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
|
||||
`createSelector` creates a type-safe selector function for a given slice. The returned selector extracts that slice's state from the full store state, or returns `undefined` if the slice is not configured.
|
||||
|
||||
The built-in selectors (<DocsLink slug="reference/select-playback">`selectPlayback`</DocsLink>, <DocsLink slug="reference/select-buffer">`selectBuffer`</DocsLink>, etc.) are all created with `createSelector`. Use it to create selectors for custom slices.
|
||||
|
||||
```ts
|
||||
import { createSelector } from '@videojs/store';
|
||||
import { myCustomSlice } from './my-custom-slice';
|
||||
|
||||
const selectCustom = createSelector(myCustomSlice);
|
||||
|
||||
// Use with usePlayer (React) or PlayerController (HTML)
|
||||
const state = selectCustom(store.state);
|
||||
```
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
Pass selectors to <DocsLink slug="reference/use-player">`usePlayer`</DocsLink> or <DocsLink slug="reference/use-store">`useStore`</DocsLink> for reactive subscriptions.
|
||||
</FrameworkCase>
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
Pass selectors to <DocsLink slug="reference/player-controller">`PlayerController`</DocsLink> or <DocsLink slug="reference/store-controller">`StoreController`</DocsLink> for reactive subscriptions.
|
||||
</FrameworkCase>
|
||||
|
||||
<UtilReference util="createSelector" />
|
||||
@@ -5,7 +5,7 @@ frameworkTitle:
|
||||
description: Accessible fullscreen toggle button with keyboard support and state reflection
|
||||
---
|
||||
|
||||
import ApiReference from "@/components/docs/api-reference/ApiReference.astro";
|
||||
import ComponentReference from "@/components/docs/api-reference/ComponentReference.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
import StyleCase from "@/components/docs/StyleCase.astro";
|
||||
import Demo from "@/components/docs/demos/Demo.astro";
|
||||
@@ -93,4 +93,4 @@ Renders a `<button>` with an automatic `aria-label`: "Enter fullscreen" or "Exit
|
||||
</StyleCase>
|
||||
</FrameworkCase>
|
||||
|
||||
<ApiReference component="FullscreenButton" />
|
||||
<ComponentReference component="FullscreenButton" />
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
title: createPlayer
|
||||
description: Factory function that creates a player instance with typed store, mixins, and controller for HTML custom elements
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import Demo from "@/components/docs/demos/Demo.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
import StyleCase from "@/components/docs/StyleCase.astro";
|
||||
import BasicUsageDemoHtml from "@/components/docs/demos/html-create-player/html/css/BasicUsage.astro";
|
||||
import basicUsageHtml from "@/components/docs/demos/html-create-player/html/css/BasicUsage.html?raw";
|
||||
import basicUsageHtmlCss from "@/components/docs/demos/html-create-player/html/css/BasicUsage.css?raw";
|
||||
import basicUsageHtmlTs from "@/components/docs/demos/html-create-player/html/css/BasicUsage.ts?raw";
|
||||
|
||||
`createPlayer` is the entry point for setting up a Video.js player with HTML custom elements. It accepts a configuration object with a `features` array and returns everything needed to build a player: a pre-composed `PlayerElement`, typed <DocsLink slug="reference/player-controller">`PlayerController`</DocsLink>, `context`, individual mixins, and a `create` factory.
|
||||
|
||||
```ts
|
||||
import { createPlayer, features, MediaElement } from '@videojs/html';
|
||||
|
||||
const {
|
||||
PlayerElement,
|
||||
PlayerController,
|
||||
context,
|
||||
PlayerMixin,
|
||||
ProviderMixin,
|
||||
ContainerMixin,
|
||||
create,
|
||||
} = createPlayer({ features: features.video });
|
||||
|
||||
// Register the pre-composed player element
|
||||
customElements.define('video-player', PlayerElement);
|
||||
```
|
||||
|
||||
The simplest approach is to register `PlayerElement` directly. For custom behavior, use the individual mixins to compose your own element classes.
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
<StyleCase styles={["css"]}>
|
||||
<Demo files={[
|
||||
{ title: "index.html", code: basicUsageHtml, lang: "html" },
|
||||
{ title: "index.css", code: basicUsageHtmlCss, lang: "css" },
|
||||
{ title: "index.ts", code: basicUsageHtmlTs, lang: "ts" },
|
||||
]}>
|
||||
<BasicUsageDemoHtml />
|
||||
</Demo>
|
||||
</StyleCase>
|
||||
|
||||
<UtilReference util="createPlayer" slug="html-create-player" />
|
||||
@@ -5,7 +5,7 @@ frameworkTitle:
|
||||
description: Accessible mute/unmute button with keyboard support and volume state reflection
|
||||
---
|
||||
|
||||
import ApiReference from "@/components/docs/api-reference/ApiReference.astro";
|
||||
import ComponentReference from "@/components/docs/api-reference/ComponentReference.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
import StyleCase from "@/components/docs/StyleCase.astro";
|
||||
import Demo from "@/components/docs/demos/Demo.astro";
|
||||
@@ -124,4 +124,4 @@ Renders a `<button>` with an automatic `aria-label`: "Unmute" when muted, "Mute"
|
||||
</StyleCase>
|
||||
</FrameworkCase>
|
||||
|
||||
<ApiReference component="MuteButton" />
|
||||
<ComponentReference component="MuteButton" />
|
||||
|
||||
@@ -5,7 +5,7 @@ frameworkTitle:
|
||||
description: Accessible picture-in-picture toggle button with keyboard support and state reflection
|
||||
---
|
||||
|
||||
import ApiReference from "@/components/docs/api-reference/ApiReference.astro";
|
||||
import ComponentReference from "@/components/docs/api-reference/ComponentReference.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
import StyleCase from "@/components/docs/StyleCase.astro";
|
||||
import Demo from "@/components/docs/demos/Demo.astro";
|
||||
@@ -89,4 +89,4 @@ Renders a `<button>` with an automatic `aria-label`: "Enter PiP" or "Exit PiP".
|
||||
</StyleCase>
|
||||
</FrameworkCase>
|
||||
|
||||
<ApiReference component="PipButton" />
|
||||
<ComponentReference component="PipButton" />
|
||||
|
||||
@@ -5,7 +5,7 @@ frameworkTitle:
|
||||
description: Accessible play/pause button with keyboard support and customizable rendering
|
||||
---
|
||||
|
||||
import ApiReference from "@/components/docs/api-reference/ApiReference.astro";
|
||||
import ComponentReference from "@/components/docs/api-reference/ComponentReference.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
import StyleCase from "@/components/docs/StyleCase.astro";
|
||||
import Demo from "@/components/docs/demos/Demo.astro";
|
||||
@@ -92,4 +92,4 @@ Renders a `<button>` element with an automatic `aria-label` that updates based o
|
||||
</StyleCase>
|
||||
</FrameworkCase>
|
||||
|
||||
<ApiReference component="PlayButton" />
|
||||
<ComponentReference component="PlayButton" />
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
title: playerContext
|
||||
description: The default player context instance for consuming the player store in controllers
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
|
||||
`playerContext` is a Web Components context token that carries the player store through the DOM tree. Provider elements publish the store to this context, and consumer elements (via <DocsLink slug="reference/player-controller">`PlayerController`</DocsLink> or <DocsLink slug="reference/container-mixin">`ContainerMixin`</DocsLink>) read from it.
|
||||
|
||||
Pass it as the second argument to `PlayerController`:
|
||||
|
||||
```ts
|
||||
import { PlayerController, MediaElement, playerContext, selectPlayback } from '@videojs/html';
|
||||
|
||||
class PlayButton extends MediaElement {
|
||||
#playback = new PlayerController(this, playerContext, selectPlayback);
|
||||
|
||||
render() {
|
||||
const playback = this.#playback.value;
|
||||
// Use playback state to render
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Import directly or destructure from createPlayer
|
||||
|
||||
<DocsLink slug="reference/html-create-player">`createPlayer`</DocsLink> returns a `context` property that is the same `playerContext` instance. Both approaches reference the same object:
|
||||
|
||||
```ts
|
||||
// Direct import
|
||||
import { playerContext } from '@videojs/html';
|
||||
|
||||
// Destructured — identical object
|
||||
const { context } = createPlayer({ features: features.video });
|
||||
context === playerContext; // true
|
||||
```
|
||||
|
||||
Use the direct import when building reusable elements that don't depend on a specific `createPlayer` call. Destructure from `createPlayer` when you want all player utilities from a single result.
|
||||
|
||||
### When you need this
|
||||
|
||||
Most elements should use <DocsLink slug="reference/player-controller">`PlayerController`</DocsLink> (which accepts a context argument) rather than importing `playerContext` directly. Import it directly when you need to pass the context token to a lower-level API like <DocsLink slug="reference/container-mixin">`ContainerMixin`</DocsLink> or <DocsLink slug="reference/provider-mixin">`ProviderMixin`</DocsLink>.
|
||||
|
||||
<UtilReference util="playerContext" />
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
title: PlayerController
|
||||
description: Reactive controller for accessing player store state in HTML custom elements
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import Demo from "@/components/docs/demos/Demo.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
import StyleCase from "@/components/docs/StyleCase.astro";
|
||||
import BasicUsageDemoHtml from "@/components/docs/demos/player-controller/html/css/BasicUsage.astro";
|
||||
import basicUsageHtml from "@/components/docs/demos/player-controller/html/css/BasicUsage.html?raw";
|
||||
import basicUsageHtmlCss from "@/components/docs/demos/player-controller/html/css/BasicUsage.css?raw";
|
||||
import basicUsageHtmlTs from "@/components/docs/demos/player-controller/html/css/BasicUsage.ts?raw";
|
||||
|
||||
`PlayerController` is a reactive controller that consumes the player store from <DocsLink slug="reference/player-context">`playerContext`</DocsLink>. Without a selector it returns the store instance directly (no subscription — use this for actions). With a selector it returns the selected value and subscribes to changes, triggering a host update on shallow-equal change. Access the current value via `.value`, which returns `undefined` until connected to a provider.
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
<StyleCase styles={["css"]}>
|
||||
<Demo
|
||||
files={[
|
||||
{ title: "index.html", code: basicUsageHtml, lang: "html" },
|
||||
{ title: "index.css", code: basicUsageHtmlCss, lang: "css" },
|
||||
{ title: "index.ts", code: basicUsageHtmlTs, lang: "ts" },
|
||||
]}
|
||||
>
|
||||
<BasicUsageDemoHtml />
|
||||
</Demo>
|
||||
</StyleCase>
|
||||
</FrameworkCase>
|
||||
|
||||
<UtilReference util="PlayerController" />
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
title: PlayerMixin
|
||||
description: Composed mixin combining ProviderMixin and ContainerMixin for a complete player element
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
|
||||
`PlayerMixin` combines <DocsLink slug="reference/provider-mixin">`ProviderMixin`</DocsLink> and <DocsLink slug="reference/container-mixin">`ContainerMixin`</DocsLink> into a single mixin. The resulting class both owns the player store and auto-attaches media elements, making it a complete player element. It is equivalent to `ProviderMixin(ContainerMixin(Base))` — it creates the store on connect, observes the DOM for `<video>` or `<audio>` children, and publishes the store to descendant elements via context.
|
||||
|
||||
### Choose your approach
|
||||
|
||||
| Approach | When to use |
|
||||
|----------|-------------|
|
||||
| `PlayerElement` | Simplest setup. Register and use directly -- no custom class needed. |
|
||||
| `PlayerMixin(Base)` | Custom player element with additional lifecycle logic or methods. |
|
||||
| <DocsLink slug="reference/provider-mixin">`ProviderMixin`</DocsLink> + <DocsLink slug="reference/container-mixin">`ContainerMixin`</DocsLink> | Provider and container are separate elements (e.g., store owner is a layout shell, media lives in a content region). |
|
||||
|
||||
### PlayerElement vs PlayerMixin
|
||||
|
||||
For the simplest setup, use the pre-composed `PlayerElement` from `createPlayer`:
|
||||
|
||||
```ts
|
||||
const { PlayerElement } = createPlayer({ features: features.video });
|
||||
customElements.define('video-player', PlayerElement);
|
||||
```
|
||||
|
||||
Use `PlayerMixin` when you need to add custom behavior:
|
||||
|
||||
```ts
|
||||
class MyPlayer extends PlayerMixin(MediaElement) {
|
||||
connectedCallback() {
|
||||
super.connectedCallback();
|
||||
this.store.subscribe(() => {
|
||||
// Custom logic on state changes
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<UtilReference util="PlayerMixin" />
|
||||
@@ -5,7 +5,7 @@ frameworkTitle:
|
||||
description: Poster image component that displays a thumbnail until video playback starts
|
||||
---
|
||||
|
||||
import ApiReference from "@/components/docs/api-reference/ApiReference.astro";
|
||||
import ComponentReference from "@/components/docs/api-reference/ComponentReference.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
import StyleCase from "@/components/docs/StyleCase.astro";
|
||||
import Demo from "@/components/docs/demos/Demo.astro";
|
||||
@@ -90,4 +90,4 @@ Unlike the native `<video poster>` attribute, this component allows you to provi
|
||||
</StyleCase>
|
||||
</FrameworkCase>
|
||||
|
||||
<ApiReference component="Poster" />
|
||||
<ComponentReference component="Poster" />
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
title: ProviderMixin
|
||||
description: Mixin that provides player context to descendant elements
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
|
||||
`ProviderMixin` creates a class that provides the player store to descendant elements via context. It owns the store lifecycle: creates the store lazily on first access and destroys it on disconnect.
|
||||
|
||||
### Store lifecycle
|
||||
|
||||
The store is created lazily using the factory from `createPlayer`. On `connectedCallback`, the mixin publishes the store to context so descendant elements can consume it. On `disconnectedCallback`, it calls `store.destroy()` and cleans up.
|
||||
|
||||
Any <DocsLink slug="reference/player-controller">`PlayerController`</DocsLink> or <DocsLink slug="reference/container-mixin">`ContainerMixin`</DocsLink> element below the provider in the DOM tree receives the store automatically through context.
|
||||
|
||||
### When to split provider and container
|
||||
|
||||
Use `ProviderMixin` separate from <DocsLink slug="reference/container-mixin">`ContainerMixin`</DocsLink> when the store owner is a different element from the one containing the media. This is common in complex layouts:
|
||||
|
||||
```ts
|
||||
const { ProviderMixin, ContainerMixin } = createPlayer({ features: features.video });
|
||||
|
||||
// Layout shell owns the store
|
||||
class AppShell extends ProviderMixin(MediaElement) {}
|
||||
|
||||
// Content region discovers and attaches the media element
|
||||
class VideoRegion extends ContainerMixin(MediaElement) {}
|
||||
```
|
||||
|
||||
When a single element should handle both, use <DocsLink slug="reference/player-mixin">`PlayerMixin`</DocsLink> instead.
|
||||
|
||||
<UtilReference util="ProviderMixin" />
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
title: renderElement
|
||||
description: Utility for rendering UI component elements with state-driven props and render prop support
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import Demo from "@/components/docs/demos/Demo.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
import StyleCase from "@/components/docs/StyleCase.astro";
|
||||
import BasicUsageDemoReact from "@/components/docs/demos/render-element/react/css/BasicUsage";
|
||||
import basicUsageReactTsx from "@/components/docs/demos/render-element/react/css/BasicUsage.tsx?raw";
|
||||
import basicUsageReactCss from "@/components/docs/demos/render-element/react/css/BasicUsage.css?raw";
|
||||
|
||||
`renderElement` renders a UI component element, handling default tag rendering, render props (element or function), props merging, ref composition, and state-driven `className`/`style`.
|
||||
|
||||
```tsx
|
||||
import { renderElement } from "@videojs/react";
|
||||
|
||||
function PlayButton({ className, style, render, ...props }) {
|
||||
const state = { paused: true };
|
||||
|
||||
return renderElement(
|
||||
"button",
|
||||
{ className, style, render },
|
||||
{
|
||||
state,
|
||||
ref: buttonRef,
|
||||
props: [{ type: "button", "aria-label": "Play" }, props],
|
||||
},
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
The `className` and `style` component props accept either static values or functions that receive the current state:
|
||||
|
||||
```tsx
|
||||
<PlayButton
|
||||
className={(state) => (state.paused ? "paused" : "playing")}
|
||||
style={(state) => ({ opacity: state.paused ? 0.5 : 1 })}
|
||||
/>
|
||||
```
|
||||
|
||||
The `render` prop lets consumers fully customize the rendered element while preserving all internal props and refs:
|
||||
|
||||
```tsx
|
||||
<PlayButton
|
||||
render={(props, state) => (
|
||||
<button {...props}>{state.paused ? "Play" : "Pause"}</button>
|
||||
)}
|
||||
/>
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
<StyleCase styles={["css"]}>
|
||||
<Demo
|
||||
files={[
|
||||
{ title: "App.tsx", code: basicUsageReactTsx, lang: "tsx" },
|
||||
{ title: "App.css", code: basicUsageReactCss, lang: "css" },
|
||||
]}
|
||||
>
|
||||
<BasicUsageDemoReact client:idle />
|
||||
</Demo>
|
||||
</StyleCase>
|
||||
</FrameworkCase>
|
||||
|
||||
<UtilReference util="renderElement" />
|
||||
@@ -5,7 +5,7 @@ frameworkTitle:
|
||||
description: Accessible seek button for skipping forward or backward by a configurable number of seconds
|
||||
---
|
||||
|
||||
import ApiReference from "@/components/docs/api-reference/ApiReference.astro";
|
||||
import ComponentReference from "@/components/docs/api-reference/ComponentReference.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
import StyleCase from "@/components/docs/StyleCase.astro";
|
||||
import Demo from "@/components/docs/demos/Demo.astro";
|
||||
@@ -74,4 +74,4 @@ Renders a `<button>` with an automatic `aria-label` describing the action, e.g.
|
||||
</StyleCase>
|
||||
</FrameworkCase>
|
||||
|
||||
<ApiReference component="SeekButton" />
|
||||
<ComponentReference component="SeekButton" />
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
---
|
||||
title: selectBuffer
|
||||
description: Select the buffer state slice from the player store
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
Pass `selectBuffer` to <DocsLink slug="reference/use-player">`usePlayer`</DocsLink> to subscribe to buffer state. Returns `undefined` if the buffer feature is not configured.
|
||||
</FrameworkCase>
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
Pass `selectBuffer` to <DocsLink slug="reference/player-controller">`PlayerController`</DocsLink> to subscribe to buffer state. Returns `undefined` if the buffer feature is not configured.
|
||||
</FrameworkCase>
|
||||
|
||||
The returned state includes buffered ranges and percent buffered.
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
```tsx
|
||||
import { usePlayer } from '@videojs/react';
|
||||
import { selectBuffer } from '@videojs/core/dom';
|
||||
|
||||
function BufferBar() {
|
||||
const buffer = usePlayer(selectBuffer);
|
||||
if (!buffer) return null;
|
||||
|
||||
return (
|
||||
<div style={{ width: `${buffer.percentBuffered * 100}%` }} />
|
||||
);
|
||||
}
|
||||
```
|
||||
</FrameworkCase>
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
```ts
|
||||
import { createPlayer, features, MediaElement } from '@videojs/html';
|
||||
import { selectBuffer } from '@videojs/core/dom';
|
||||
|
||||
const { PlayerController, context } = createPlayer({ features: features.video });
|
||||
|
||||
class BufferBar extends MediaElement {
|
||||
#buffer = new PlayerController(this, context, selectBuffer);
|
||||
}
|
||||
```
|
||||
</FrameworkCase>
|
||||
|
||||
<UtilReference util="selectBuffer" />
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
title: selectControls
|
||||
description: Select the controls state slice from the player store
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
Pass `selectControls` to <DocsLink slug="reference/use-player">`usePlayer`</DocsLink> to subscribe to controls state. Returns `undefined` if the controls feature is not configured.
|
||||
</FrameworkCase>
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
Pass `selectControls` to <DocsLink slug="reference/player-controller">`PlayerController`</DocsLink> to subscribe to controls state. Returns `undefined` if the controls feature is not configured.
|
||||
</FrameworkCase>
|
||||
|
||||
The returned state includes whether controls are visible and whether the user is active (interacting with the player).
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
```tsx
|
||||
import { usePlayer } from '@videojs/react';
|
||||
import { selectControls } from '@videojs/core/dom';
|
||||
|
||||
function ControlsOverlay({ children }: { children: React.ReactNode }) {
|
||||
const controls = usePlayer(selectControls);
|
||||
if (!controls) return null;
|
||||
|
||||
return (
|
||||
<div style={{ opacity: controls.visible ? 1 : 0 }}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
</FrameworkCase>
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
```ts
|
||||
import { createPlayer, features, MediaElement } from '@videojs/html';
|
||||
import { selectControls } from '@videojs/core/dom';
|
||||
|
||||
const { PlayerController, context } = createPlayer({ features: features.video });
|
||||
|
||||
class ControlsOverlay extends MediaElement {
|
||||
#controls = new PlayerController(this, context, selectControls);
|
||||
}
|
||||
```
|
||||
</FrameworkCase>
|
||||
|
||||
<UtilReference util="selectControls" />
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
title: selectFullscreen
|
||||
description: Select the fullscreen state slice from the player store
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
Pass `selectFullscreen` to <DocsLink slug="reference/use-player">`usePlayer`</DocsLink> to subscribe to fullscreen state. Returns `undefined` if the fullscreen feature is not configured.
|
||||
</FrameworkCase>
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
Pass `selectFullscreen` to <DocsLink slug="reference/player-controller">`PlayerController`</DocsLink> to subscribe to fullscreen state. Returns `undefined` if the fullscreen feature is not configured.
|
||||
</FrameworkCase>
|
||||
|
||||
The returned state includes whether fullscreen is active and its availability on the current platform.
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
```tsx
|
||||
import { usePlayer } from '@videojs/react';
|
||||
import { selectFullscreen } from '@videojs/core/dom';
|
||||
|
||||
function FullscreenButton() {
|
||||
const fs = usePlayer(selectFullscreen);
|
||||
if (!fs || fs.availability !== 'available') return null;
|
||||
|
||||
return (
|
||||
<button onClick={fs.toggle}>
|
||||
{fs.active ? 'Exit fullscreen' : 'Fullscreen'}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
```
|
||||
</FrameworkCase>
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
```ts
|
||||
import { createPlayer, features, MediaElement } from '@videojs/html';
|
||||
import { selectFullscreen } from '@videojs/core/dom';
|
||||
|
||||
const { PlayerController, context } = createPlayer({ features: features.video });
|
||||
|
||||
class FullscreenButton extends MediaElement {
|
||||
#fullscreen = new PlayerController(this, context, selectFullscreen);
|
||||
}
|
||||
```
|
||||
</FrameworkCase>
|
||||
|
||||
<UtilReference util="selectFullscreen" />
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
title: selectPiP
|
||||
description: Select the picture-in-picture state slice from the player store
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
Pass `selectPiP` to <DocsLink slug="reference/use-player">`usePlayer`</DocsLink> to subscribe to picture-in-picture state. Returns `undefined` if the PiP feature is not configured.
|
||||
</FrameworkCase>
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
Pass `selectPiP` to <DocsLink slug="reference/player-controller">`PlayerController`</DocsLink> to subscribe to picture-in-picture state. Returns `undefined` if the PiP feature is not configured.
|
||||
</FrameworkCase>
|
||||
|
||||
The returned state includes whether PiP is active and its availability on the current platform.
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
```tsx
|
||||
import { usePlayer } from '@videojs/react';
|
||||
import { selectPiP } from '@videojs/core/dom';
|
||||
|
||||
function PiPButton() {
|
||||
const pip = usePlayer(selectPiP);
|
||||
if (!pip || pip.availability !== 'available') return null;
|
||||
|
||||
return (
|
||||
<button onClick={pip.toggle}>
|
||||
{pip.active ? 'Exit PiP' : 'Picture-in-Picture'}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
```
|
||||
</FrameworkCase>
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
```ts
|
||||
import { createPlayer, features, MediaElement } from '@videojs/html';
|
||||
import { selectPiP } from '@videojs/core/dom';
|
||||
|
||||
const { PlayerController, context } = createPlayer({ features: features.video });
|
||||
|
||||
class PiPButton extends MediaElement {
|
||||
#pip = new PlayerController(this, context, selectPiP);
|
||||
}
|
||||
```
|
||||
</FrameworkCase>
|
||||
|
||||
<UtilReference util="selectPiP" />
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
title: selectPlayback
|
||||
description: Select the playback state slice from the player store
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
Pass `selectPlayback` to <DocsLink slug="reference/use-player">`usePlayer`</DocsLink> to subscribe to playback state. Returns `undefined` if the playback feature is not configured.
|
||||
</FrameworkCase>
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
Pass `selectPlayback` to <DocsLink slug="reference/player-controller">`PlayerController`</DocsLink> to subscribe to playback state. Returns `undefined` if the playback feature is not configured.
|
||||
</FrameworkCase>
|
||||
|
||||
The returned state includes `paused`, `ended`, and action methods like `play`, `pause`, and `toggle`.
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
```tsx
|
||||
import { usePlayer } from '@videojs/react';
|
||||
import { selectPlayback } from '@videojs/core/dom';
|
||||
|
||||
function PlayButton() {
|
||||
const playback = usePlayer(selectPlayback);
|
||||
if (!playback) return null;
|
||||
return <button onClick={playback.toggle}>{playback.paused ? 'Play' : 'Pause'}</button>;
|
||||
}
|
||||
```
|
||||
</FrameworkCase>
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
```ts
|
||||
import { createPlayer, features, MediaElement } from '@videojs/html';
|
||||
import { selectPlayback } from '@videojs/core/dom';
|
||||
|
||||
const { PlayerController, context } = createPlayer({ features: features.video });
|
||||
|
||||
class PlayButton extends MediaElement {
|
||||
#playback = new PlayerController(this, context, selectPlayback);
|
||||
}
|
||||
```
|
||||
</FrameworkCase>
|
||||
|
||||
<UtilReference util="selectPlayback" />
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
title: selectSource
|
||||
description: Select the source state slice from the player store
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
Pass `selectSource` to <DocsLink slug="reference/use-player">`usePlayer`</DocsLink> to subscribe to source state. Returns `undefined` if the source feature is not configured.
|
||||
</FrameworkCase>
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
Pass `selectSource` to <DocsLink slug="reference/player-controller">`PlayerController`</DocsLink> to subscribe to source state. Returns `undefined` if the source feature is not configured.
|
||||
</FrameworkCase>
|
||||
|
||||
The returned state includes the current `src` and `type`.
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
```tsx
|
||||
import { usePlayer } from '@videojs/react';
|
||||
import { selectSource } from '@videojs/core/dom';
|
||||
|
||||
function SourceInfo() {
|
||||
const source = usePlayer(selectSource);
|
||||
if (!source) return null;
|
||||
|
||||
return <span>{source.src}</span>;
|
||||
}
|
||||
```
|
||||
</FrameworkCase>
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
```ts
|
||||
import { createPlayer, features, MediaElement } from '@videojs/html';
|
||||
import { selectSource } from '@videojs/core/dom';
|
||||
|
||||
const { PlayerController, context } = createPlayer({ features: features.video });
|
||||
|
||||
class SourceInfo extends MediaElement {
|
||||
#source = new PlayerController(this, context, selectSource);
|
||||
}
|
||||
```
|
||||
</FrameworkCase>
|
||||
|
||||
<UtilReference util="selectSource" />
|
||||
@@ -0,0 +1,51 @@
|
||||
---
|
||||
title: selectTime
|
||||
description: Select the time state slice from the player store
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
Pass `selectTime` to <DocsLink slug="reference/use-player">`usePlayer`</DocsLink> to subscribe to time state. Returns `undefined` if the time feature is not configured.
|
||||
</FrameworkCase>
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
Pass `selectTime` to <DocsLink slug="reference/player-controller">`PlayerController`</DocsLink> to subscribe to time state. Returns `undefined` if the time feature is not configured.
|
||||
</FrameworkCase>
|
||||
|
||||
The returned state includes `currentTime`, `duration`, and the `seek` action method.
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
```tsx
|
||||
import { usePlayer } from '@videojs/react';
|
||||
import { selectTime } from '@videojs/core/dom';
|
||||
|
||||
function TimeDisplay() {
|
||||
const time = usePlayer(selectTime);
|
||||
if (!time) return null;
|
||||
|
||||
return (
|
||||
<span>
|
||||
{Math.floor(time.currentTime)} / {Math.floor(time.duration)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
```
|
||||
</FrameworkCase>
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
```ts
|
||||
import { createPlayer, features, MediaElement } from '@videojs/html';
|
||||
import { selectTime } from '@videojs/core/dom';
|
||||
|
||||
const { PlayerController, context } = createPlayer({ features: features.video });
|
||||
|
||||
class TimeDisplay extends MediaElement {
|
||||
#time = new PlayerController(this, context, selectTime);
|
||||
}
|
||||
```
|
||||
</FrameworkCase>
|
||||
|
||||
<UtilReference util="selectTime" />
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
title: selectVolume
|
||||
description: Select the volume state slice from the player store
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
Pass `selectVolume` to <DocsLink slug="reference/use-player">`usePlayer`</DocsLink> to subscribe to volume state. Returns `undefined` if the volume feature is not configured.
|
||||
</FrameworkCase>
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
Pass `selectVolume` to <DocsLink slug="reference/player-controller">`PlayerController`</DocsLink> to subscribe to volume state. Returns `undefined` if the volume feature is not configured.
|
||||
</FrameworkCase>
|
||||
|
||||
The returned state includes `volume`, `muted`, and action methods like `setVolume` and `setMuted`.
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
```tsx
|
||||
import { usePlayer } from '@videojs/react';
|
||||
import { selectVolume } from '@videojs/core/dom';
|
||||
|
||||
function VolumeSlider() {
|
||||
const vol = usePlayer(selectVolume);
|
||||
if (!vol) return null;
|
||||
|
||||
return (
|
||||
<input
|
||||
type="range"
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
value={vol.volume}
|
||||
onChange={(e) => vol.setVolume(Number(e.target.value))}
|
||||
/>
|
||||
);
|
||||
}
|
||||
```
|
||||
</FrameworkCase>
|
||||
|
||||
<FrameworkCase frameworks={["html"]}>
|
||||
```ts
|
||||
import { createPlayer, features, MediaElement } from '@videojs/html';
|
||||
import { selectVolume } from '@videojs/core/dom';
|
||||
|
||||
const { PlayerController, context } = createPlayer({ features: features.video });
|
||||
|
||||
class VolumeSlider extends MediaElement {
|
||||
#volume = new PlayerController(this, context, selectVolume);
|
||||
}
|
||||
```
|
||||
</FrameworkCase>
|
||||
|
||||
<UtilReference util="selectVolume" />
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
title: SnapshotController
|
||||
description: Reactive controller for subscribing to a State container in HTML custom elements
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
|
||||
`SnapshotController` subscribes to a `State` container and triggers host updates when state changes. It has two overloads:
|
||||
|
||||
**Full state** -- returns the entire state object. Re-renders on any state change.
|
||||
|
||||
```ts
|
||||
class Display extends HTMLElement {
|
||||
#state = new SnapshotController(this, sliderState);
|
||||
|
||||
render() {
|
||||
const value = this.#state.value;
|
||||
// Full state object
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**With selector** -- returns a derived value from state. Re-renders only when the selected value changes (using shallow equality).
|
||||
|
||||
```ts
|
||||
class SliderValue extends HTMLElement {
|
||||
#value = new SnapshotController(this, sliderState, (s) => s.value);
|
||||
|
||||
render() {
|
||||
return this.#value.value; // Only the selected slice
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Use `.track(state)` to switch to a different `State` container at runtime.
|
||||
|
||||
### SnapshotController vs StoreController
|
||||
|
||||
Both are reactive controllers, but they operate at different levels:
|
||||
|
||||
| | `SnapshotController` | <DocsLink slug="reference/store-controller">`StoreController`</DocsLink> |
|
||||
| -------------- | ------------------------------ | ------------------------------------------------------------------------ |
|
||||
| **Input** | `State` container | Store instance or context |
|
||||
| **Subscribes** | Always | Only with a selector |
|
||||
| **Use case** | Subscribe to raw state changes | Access store actions and optionally subscribe |
|
||||
|
||||
`SnapshotController` is lower-level. It works with `State` containers directly -- the reactive primitives that back a store. Use it when building custom controllers or working outside the player store system.
|
||||
|
||||
<DocsLink slug="reference/store-controller">`StoreController`</DocsLink> is
|
||||
higher-level. It resolves a store from a context or direct reference and
|
||||
internally creates a `SnapshotController` when you pass a selector. Use it for
|
||||
player UI elements.
|
||||
|
||||
### Lifecycle
|
||||
|
||||
`SnapshotController` subscribes on `hostConnected()` and unsubscribes on `hostDisconnected()`. The React equivalent is <DocsLink slug="reference/use-snapshot">`useSnapshot`</DocsLink>.
|
||||
|
||||
<UtilReference util="SnapshotController" />
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
title: StoreController
|
||||
description: Reactive controller for subscribing to store state in HTML custom elements
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
|
||||
`StoreController` is a reactive controller for accessing store state and actions in custom elements. It accepts a store instance or a context, resolving the store automatically.
|
||||
|
||||
**Without selector** -- returns the store instance directly. Does NOT subscribe to changes. Use this to access store actions.
|
||||
|
||||
```ts
|
||||
class VolumeControl extends HTMLElement {
|
||||
#store = new StoreController(this, storeSource);
|
||||
|
||||
handleClick() {
|
||||
this.#store.value.setVolume(0.5);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**With selector** -- returns the selected value and subscribes to changes. Triggers a host update when the selected value changes (using shallow equality).
|
||||
|
||||
```ts
|
||||
class PlayButton extends HTMLElement {
|
||||
#playback = new StoreController(this, storeSource, selectPlayback);
|
||||
|
||||
render() {
|
||||
const playback = this.#playback.value;
|
||||
// Re-renders when playback state changes
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### StoreController vs PlayerController vs SnapshotController
|
||||
|
||||
| | `StoreController` | <DocsLink slug="reference/player-controller">`PlayerController`</DocsLink> | <DocsLink slug="reference/snapshot-controller">`SnapshotController`</DocsLink> |
|
||||
|---|---|---|---|
|
||||
| **Input** | Any store or context | Player store context | `State` container |
|
||||
| **Typed to** | Generic store | Player features | Raw state |
|
||||
| **Use case** | General-purpose store access | Player UI elements | Low-level state subscription |
|
||||
|
||||
<DocsLink slug="reference/player-controller">`PlayerController`</DocsLink> is a typed wrapper around `StoreController` scoped to the player store. For player UI, prefer `PlayerController`. Use `StoreController` when working with a custom store outside the player system.
|
||||
|
||||
When you pass a selector, `StoreController` internally creates a <DocsLink slug="reference/snapshot-controller">`SnapshotController`</DocsLink> on the store's `$state` container. Without a selector, no subscription is created -- you get the store instance for imperative access to actions.
|
||||
|
||||
<UtilReference util="StoreController" />
|
||||
@@ -5,7 +5,7 @@ frameworkTitle:
|
||||
description: Time display components for showing current time, duration, and remaining time in a video player
|
||||
---
|
||||
|
||||
import ApiReference from "@/components/docs/api-reference/ApiReference.astro";
|
||||
import ComponentReference from "@/components/docs/api-reference/ComponentReference.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
import StyleCase from "@/components/docs/StyleCase.astro";
|
||||
import Demo from "@/components/docs/demos/Demo.astro";
|
||||
@@ -238,4 +238,4 @@ No `aria-live` region is used — time updates too frequently and might overwhel
|
||||
</StyleCase>
|
||||
</FrameworkCase>
|
||||
|
||||
<ApiReference component="Time" />
|
||||
<ComponentReference component="Time" />
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
title: useButton
|
||||
description: Hook for creating accessible button components with keyboard and pointer interaction
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import Demo from "@/components/docs/demos/Demo.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
import StyleCase from "@/components/docs/StyleCase.astro";
|
||||
import BasicUsageDemoReact from "@/components/docs/demos/use-button/react/css/BasicUsage";
|
||||
import basicUsageReactTsx from "@/components/docs/demos/use-button/react/css/BasicUsage.tsx?raw";
|
||||
import basicUsageReactCss from "@/components/docs/demos/use-button/react/css/BasicUsage.css?raw";
|
||||
|
||||
`useButton` provides button behavior including keyboard activation and accessibility checks. It returns a `getButtonProps` function for spreading onto a `<button>` element and a `buttonRef` for validation.
|
||||
|
||||
`getButtonProps` merges internal button props (click/keyboard handlers, disabled state) with any external props you pass in. Use <DocsLink slug="reference/render-element">`renderElement`</DocsLink> to render the button with state-driven props and render prop support. In development mode, `buttonRef` warns if the rendered element is not a `<button>`.
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
<StyleCase styles={["css"]}>
|
||||
<Demo
|
||||
files={[
|
||||
{ title: "App.tsx", code: basicUsageReactTsx, lang: "tsx" },
|
||||
{ title: "App.css", code: basicUsageReactCss, lang: "css" },
|
||||
]}
|
||||
>
|
||||
<BasicUsageDemoReact client:idle />
|
||||
</Demo>
|
||||
</StyleCase>
|
||||
</FrameworkCase>
|
||||
|
||||
<UtilReference util="useButton" />
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
title: useMediaRegistration
|
||||
description: Hook to register a custom media element with the player context
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
|
||||
`useMediaRegistration` returns a setter function for registering a media element with the player context. The built-in `<Video>` and `<Audio>` components use this internally -- you only need it when building a custom media element.
|
||||
|
||||
```tsx
|
||||
import { useMediaRegistration } from "@videojs/react";
|
||||
import { useRef, useEffect } from "react";
|
||||
|
||||
function CustomMedia({ src }: { src: string }) {
|
||||
const setMedia = useMediaRegistration();
|
||||
const ref = useRef<HTMLVideoElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (ref.current && setMedia) {
|
||||
setMedia(ref.current);
|
||||
return () => setMedia(null);
|
||||
}
|
||||
}, [setMedia]);
|
||||
|
||||
return <video ref={ref} src={src} />;
|
||||
}
|
||||
```
|
||||
|
||||
## Who needs this
|
||||
|
||||
You only need `useMediaRegistration` if you're replacing the built-in `<Video>` or `<Audio>` components with a custom element. For example, if you're...
|
||||
|
||||
- Wrapping a third-party video player
|
||||
- Using a `<canvas>` or WebGL-based renderer
|
||||
- Building a custom `<audio>` element with additional markup
|
||||
|
||||
For standard `<video>` and `<audio>` playback, use the built-in components.
|
||||
|
||||
## Cleanup pattern
|
||||
|
||||
Always return a cleanup function that passes `null` to the setter. This detaches the media element when the component unmounts, preventing stale references in the store.
|
||||
|
||||
## Safe outside Provider
|
||||
|
||||
Returns `undefined` when called outside a Player `Provider`. Check the return value before using it -- this avoids crashes in components that may render outside the player tree.
|
||||
|
||||
<UtilReference util="useMediaRegistration" />
|
||||
@@ -0,0 +1,34 @@
|
||||
---
|
||||
title: useMedia
|
||||
description: Hook to access the underlying media element from within a Player Provider
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import Demo from "@/components/docs/demos/Demo.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
import StyleCase from "@/components/docs/StyleCase.astro";
|
||||
import BasicUsageDemoReact from "@/components/docs/demos/use-media/react/css/BasicUsage";
|
||||
import basicUsageReactTsx from "@/components/docs/demos/use-media/react/css/BasicUsage.tsx?raw";
|
||||
import basicUsageReactCss from "@/components/docs/demos/use-media/react/css/BasicUsage.css?raw";
|
||||
|
||||
`useMedia` returns the current `HTMLMediaElement` (or `null` if no media element has been registered yet). Use it to interact directly with the native media element when needed. It must be called within a Player `Provider`. The media element becomes available after a `<Video>` or `<Audio>` component mounts inside the provider tree. To register a custom media element instead of the built-in components, see <DocsLink slug="reference/use-media-registration">`useMediaRegistration`</DocsLink>.
|
||||
|
||||
## Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
<StyleCase styles={["css"]}>
|
||||
<Demo
|
||||
files={[
|
||||
{ title: "App.tsx", code: basicUsageReactTsx, lang: "tsx" },
|
||||
{ title: "App.css", code: basicUsageReactCss, lang: "css" },
|
||||
]}
|
||||
>
|
||||
<BasicUsageDemoReact client:idle />
|
||||
</Demo>
|
||||
</StyleCase>
|
||||
</FrameworkCase>
|
||||
|
||||
<UtilReference util="useMedia" />
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
title: usePlayerContext
|
||||
description: Hook to access the full player context including store, media element, and media setter
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
|
||||
`usePlayerContext` returns the full `PlayerContextValue` object, which includes the store, the current media element, and the media setter.
|
||||
|
||||
```tsx
|
||||
import { usePlayerContext } from "@videojs/react";
|
||||
|
||||
function DebugPanel() {
|
||||
const { store, media, setMedia } = usePlayerContext();
|
||||
|
||||
return (
|
||||
<pre>
|
||||
{JSON.stringify(
|
||||
{
|
||||
hasStore: !!store,
|
||||
hasMedia: !!media,
|
||||
tagName: media?.tagName,
|
||||
},
|
||||
null,
|
||||
2,
|
||||
)}
|
||||
</pre>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
Throws an error if called outside a Player `Provider`.
|
||||
|
||||
### Prefer higher-level hooks
|
||||
|
||||
For most use cases, use the focused hooks instead:
|
||||
|
||||
| Need | Hook |
|
||||
| -------------------------- | ----------------------------------------------------------------------------------- |
|
||||
| Store access with selector | <DocsLink slug="reference/use-player">`usePlayer`</DocsLink> |
|
||||
| Current media element | <DocsLink slug="reference/use-media">`useMedia`</DocsLink> |
|
||||
| Register custom media | <DocsLink slug="reference/use-media-registration">`useMediaRegistration`</DocsLink> |
|
||||
|
||||
These hooks read from the same context internally. `usePlayerContext` exposes the raw context value -- use it when you need multiple context fields in one call or when building a custom abstraction over the player context.
|
||||
|
||||
<UtilReference util="usePlayerContext" />
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
title: usePlayer
|
||||
description: Hook to access the player store from within a Player Provider
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import Demo from "@/components/docs/demos/Demo.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
import StyleCase from "@/components/docs/StyleCase.astro";
|
||||
import StoreAccessDemoReact from "@/components/docs/demos/use-player/react/css/StoreAccess";
|
||||
import storeAccessReactTsx from "@/components/docs/demos/use-player/react/css/StoreAccess.tsx?raw";
|
||||
import storeAccessReactCss from "@/components/docs/demos/use-player/react/css/StoreAccess.css?raw";
|
||||
import SelectorDemoReact from "@/components/docs/demos/use-player/react/css/Selector";
|
||||
import selectorReactTsx from "@/components/docs/demos/use-player/react/css/Selector.tsx?raw";
|
||||
import selectorReactCss from "@/components/docs/demos/use-player/react/css/Selector.css?raw";
|
||||
|
||||
`usePlayer` gives you access to the player store from any component within a Player `Provider`. It has two overloads — without arguments for direct store access, or with a selector for reactive state subscriptions. The scoped `usePlayer` returned from <DocsLink slug="reference/create-player">`createPlayer`</DocsLink> is typed to your specific features, while the standalone export from `@videojs/react` returns an untyped store.
|
||||
|
||||
## Examples
|
||||
|
||||
### Store Access
|
||||
|
||||
Call `usePlayer()` without arguments to get the store instance. Use this for imperative actions like play, pause, and volume changes. The component does not re-render on state changes.
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
<StyleCase styles={["css"]}>
|
||||
<Demo
|
||||
files={[
|
||||
{ title: "App.tsx", code: storeAccessReactTsx, lang: "tsx" },
|
||||
{ title: "App.css", code: storeAccessReactCss, lang: "css" },
|
||||
]}
|
||||
>
|
||||
<StoreAccessDemoReact client:idle />
|
||||
</Demo>
|
||||
</StyleCase>
|
||||
</FrameworkCase>
|
||||
|
||||
### Selector Subscription
|
||||
|
||||
Pass a selector function to subscribe to specific state. The component re-renders when the selected value changes, using shallow equality by default.
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
<StyleCase styles={["css"]}>
|
||||
<Demo
|
||||
files={[
|
||||
{ title: "App.tsx", code: selectorReactTsx, lang: "tsx" },
|
||||
{ title: "App.css", code: selectorReactCss, lang: "css" },
|
||||
]}
|
||||
>
|
||||
<SelectorDemoReact client:idle />
|
||||
</Demo>
|
||||
</StyleCase>
|
||||
</FrameworkCase>
|
||||
|
||||
<UtilReference util="usePlayer" />
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
title: useSelector
|
||||
description: Low-level hook for subscribing to derived state with customizable equality checks
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
|
||||
`useSelector` is a low-level hook that subscribes to an external store using React's `useSyncExternalStore`. It accepts a `subscribe` function, a `getSnapshot` function, a `selector` to derive state, and an optional `isEqual` comparator (defaults to `shallowEqual`).
|
||||
|
||||
```tsx
|
||||
import { useSelector, shallowEqual } from "@videojs/store/react";
|
||||
|
||||
function TimeDisplay({ store }) {
|
||||
const time = useSelector(
|
||||
(cb) => store.subscribe(cb),
|
||||
() => store.state,
|
||||
(state) => ({ current: state.currentTime, duration: state.duration }),
|
||||
shallowEqual,
|
||||
);
|
||||
|
||||
return (
|
||||
<span>
|
||||
{time.current} / {time.duration}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Relationship to useStore and useSnapshot
|
||||
|
||||
Both `useStore` and `useSnapshot` are built on `useSelector`:
|
||||
|
||||
| Hook | Input | Use case |
|
||||
| ---------------------------------------------------------------- | ------------------------- | --------------------------------------- |
|
||||
| <DocsLink slug="reference/use-store">`useStore`</DocsLink> | Store instance | Player and store access with selector |
|
||||
| <DocsLink slug="reference/use-snapshot">`useSnapshot`</DocsLink> | `State` container | Subscribe to raw state changes |
|
||||
| `useSelector` | Custom subscribe/snapshot | Full control over subscription plumbing |
|
||||
|
||||
Prefer <DocsLink slug="reference/use-store">`useStore`</DocsLink> for store-backed state and <DocsLink slug="reference/use-snapshot">`useSnapshot`</DocsLink> for `State` containers. Use `useSelector` when you need to integrate with a non-standard external source or customize the equality comparison.
|
||||
|
||||
### Equality comparison
|
||||
|
||||
The `isEqual` parameter controls when React re-renders. The default `shallowEqual` compares object properties one level deep -- sufficient for most selector return values. Pass a custom comparator for deeply nested objects or when you need reference equality (`Object.is`).
|
||||
|
||||
<UtilReference util="useSelector" />
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
title: useSnapshot
|
||||
description: Hook to subscribe to a State container's current value
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
|
||||
`useSnapshot` subscribes to a `State` container and returns its current value, re-rendering when the value changes. It has two overloads:
|
||||
|
||||
**Full state** -- returns the entire state object.
|
||||
|
||||
```tsx
|
||||
function Display({ state }) {
|
||||
const value = useSnapshot(state);
|
||||
return <span>{value.count}</span>;
|
||||
}
|
||||
```
|
||||
|
||||
**With selector** -- returns a derived value from the state, re-rendering only when the selected value changes. Pass a custom comparator as the third argument when needed.
|
||||
|
||||
```tsx
|
||||
function Count({ state }) {
|
||||
const count = useSnapshot(state, (s) => s.count);
|
||||
return <span>{count}</span>;
|
||||
}
|
||||
```
|
||||
|
||||
### State containers vs stores
|
||||
|
||||
A `State` container is a reactive primitive that holds an object value and notifies subscribers on change. Stores are built on top of `State` containers but add features, actions, and lifecycle.
|
||||
|
||||
| Hook | Input | Subscribes to |
|
||||
| ---------------------------------------------------------- | -------------- | -------------------------------- |
|
||||
| `useSnapshot` | `State<T>` | Raw state container |
|
||||
| <DocsLink slug="reference/use-store">`useStore`</DocsLink> | Store instance | Store-backed state with features |
|
||||
|
||||
Use `useSnapshot` when working with standalone `State` containers outside the player store system -- for example, custom state in component libraries. For player state, use <DocsLink slug="reference/use-player">`usePlayer`</DocsLink> or <DocsLink slug="reference/use-store">`useStore`</DocsLink>.
|
||||
|
||||
`useSnapshot` is built on <DocsLink slug="reference/use-selector">`useSelector`</DocsLink> and uses `shallowEqual` by default. The HTML equivalent is `SnapshotController`.
|
||||
|
||||
<UtilReference util="useSnapshot" />
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
title: useStore
|
||||
description: Hook to access store state and actions with optional selector-based subscriptions
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
import Demo from "@/components/docs/demos/Demo.astro";
|
||||
import DocsLink from "@/components/docs/DocsLink.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
import StyleCase from "@/components/docs/StyleCase.astro";
|
||||
import StoreAccessDemoReact from "@/components/docs/demos/use-store/react/css/StoreAccess";
|
||||
import storeAccessReactTsx from "@/components/docs/demos/use-store/react/css/StoreAccess.tsx?raw";
|
||||
import storeAccessReactCss from "@/components/docs/demos/use-store/react/css/StoreAccess.css?raw";
|
||||
import SelectorDemoReact from "@/components/docs/demos/use-store/react/css/Selector";
|
||||
import selectorReactTsx from "@/components/docs/demos/use-store/react/css/Selector.tsx?raw";
|
||||
import selectorReactCss from "@/components/docs/demos/use-store/react/css/Selector.css?raw";
|
||||
|
||||
`useStore` subscribes to a store instance directly. It has the same two overloads as <DocsLink slug="reference/use-player">`usePlayer`</DocsLink> — without a selector for store access, or with a selector for reactive state. Within a player provider, `usePlayer` is usually simpler since it reads the store from context. Reach for `useStore` when you have a store instance directly or need to derive computed values from the store.
|
||||
|
||||
## Examples
|
||||
|
||||
### Store Access
|
||||
|
||||
Call `useStore(store)` without a selector to get the store instance back for imperative actions. The component does not subscribe to state changes.
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
<StyleCase styles={["css"]}>
|
||||
<Demo
|
||||
files={[
|
||||
{ title: "App.tsx", code: storeAccessReactTsx, lang: "tsx" },
|
||||
{ title: "App.css", code: storeAccessReactCss, lang: "css" },
|
||||
]}
|
||||
>
|
||||
<StoreAccessDemoReact client:idle />
|
||||
</Demo>
|
||||
</StyleCase>
|
||||
</FrameworkCase>
|
||||
|
||||
### Selector Subscription
|
||||
|
||||
Pass a selector to derive and subscribe to computed values from the store. The component re-renders when the derived value changes, using shallow equality by default.
|
||||
|
||||
<FrameworkCase frameworks={["react"]}>
|
||||
<StyleCase styles={["css"]}>
|
||||
<Demo
|
||||
files={[
|
||||
{ title: "App.tsx", code: selectorReactTsx, lang: "tsx" },
|
||||
{ title: "App.css", code: selectorReactCss, lang: "css" },
|
||||
]}
|
||||
>
|
||||
<SelectorDemoReact client:idle />
|
||||
</Demo>
|
||||
</StyleCase>
|
||||
</FrameworkCase>
|
||||
|
||||
<UtilReference util="useStore" />
|
||||
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Write reference pages
|
||||
description: How to create component API reference pages for the Video.js documentation site
|
||||
description: How to create API reference pages for the Video.js documentation site
|
||||
---
|
||||
|
||||
import Aside from '@/components/Aside.astro';
|
||||
import DocsLink from '@/components/docs/DocsLink.astro';
|
||||
|
||||
This guide covers how to create component reference pages — the API documentation under `reference/` in the docs sidebar.
|
||||
This guide covers how to create API reference pages — both component references and util references (hooks, controllers, mixins) under `reference/` in the docs sidebar.
|
||||
|
||||
<Aside type="tip">
|
||||
Reference pages are scaffolded with the `api-reference` Claude skill. Run `/api-reference play-button` to generate a reference page interactively.
|
||||
@@ -24,13 +24,13 @@ The component should be feature-complete enough that its props, state, and data
|
||||
|
||||
## Generate the API reference JSON
|
||||
|
||||
The api-docs-builder extracts type information from TypeScript sources and outputs JSON files that the `<ApiReference />` component renders as tables.
|
||||
The api-docs-builder extracts type information from TypeScript sources and outputs JSON files that `<ComponentReference />` and `<UtilReference />` components render as tables.
|
||||
|
||||
```bash
|
||||
pnpm -F site api-docs
|
||||
```
|
||||
|
||||
This generates JSON to `site/src/content/generated-api-reference/{name}.json`. These files are gitignored and regenerated automatically on `pnpm dev` and `pnpm build`.
|
||||
This generates JSON to `site/src/content/generated-component-reference/{name}.json` and `site/src/content/generated-util-reference/{name}.json`. These files are gitignored and regenerated automatically on `pnpm dev` and `pnpm build`.
|
||||
|
||||
### Builder naming conventions
|
||||
|
||||
@@ -127,7 +127,7 @@ Use `frameworkTitle` to show the HTML custom element tag name when the HTML fram
|
||||
### Imports
|
||||
|
||||
```tsx
|
||||
import ApiReference from "@/components/docs/api-reference/ApiReference.astro";
|
||||
import ComponentReference from "@/components/docs/api-reference/ComponentReference.astro";
|
||||
import FrameworkCase from "@/components/docs/FrameworkCase.astro";
|
||||
import Demo from "@/components/docs/demos/Demo.astro";
|
||||
|
||||
@@ -166,17 +166,84 @@ After imports, the page follows this order:
|
||||
- **Accessibility** — ARIA attributes, keyboard interactions
|
||||
- Other sections as appropriate
|
||||
3. **Examples** — at least BasicUsage, wrapped in `<Demo>` with `<FrameworkCase>`
|
||||
4. **`<ApiReference />`** — renders the generated JSON as props, state, and data attribute tables
|
||||
4. **`<ComponentReference />`** — renders the generated JSON as props, state, and data attribute tables
|
||||
|
||||
```mdx
|
||||
<ApiReference component="PlayButton" />
|
||||
<ComponentReference component="PlayButton" />
|
||||
```
|
||||
|
||||
The component automatically handles single-part and multi-part layouts.
|
||||
|
||||
## Create a util reference page
|
||||
|
||||
Util reference pages document React hooks/utilities and HTML controllers/mixins. Unlike component pages, they don't have demos or anatomy sections.
|
||||
|
||||
### Structure
|
||||
|
||||
```mdx
|
||||
---
|
||||
title: usePlayer
|
||||
description: Hook to access the player store
|
||||
---
|
||||
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
|
||||
## Import
|
||||
|
||||
\`\`\`tsx
|
||||
import { usePlayer } from '@videojs/react';
|
||||
\`\`\`
|
||||
|
||||
## Usage
|
||||
|
||||
Explain usage patterns, overloads, and code examples.
|
||||
|
||||
<UtilReference util="usePlayer" />
|
||||
```
|
||||
|
||||
### Key differences from component pages
|
||||
|
||||
- No `frameworkTitle` — util pages are framework-specific (React-only or HTML-only)
|
||||
- No demos or anatomy — focus on import, usage examples, and the generated reference tables
|
||||
- Use `<UtilReference util="..." />` instead of `<ComponentReference component="..." />`
|
||||
- The `util` prop takes the PascalCase or camelCase name (e.g., `"usePlayer"`, `"PlayerController"`)
|
||||
|
||||
### Util auto-discovery rules
|
||||
|
||||
The builder discovers utils from package entry points two ways:
|
||||
|
||||
**Naming conventions** (no tag needed):
|
||||
- `use*` hooks: `usePlayer`, `useMedia`
|
||||
- `*Controller` classes: `PlayerController`, `StoreController`
|
||||
- `create*` factories and mixins: `createPlayer`, `createProviderMixin`
|
||||
- `select*` selectors: `selectPlayback`, `selectVolume`
|
||||
|
||||
**`@public` JSDoc tag** (everything else):
|
||||
- Utilities that don't match a convention: `mergeProps`, `renderElement`
|
||||
- Context objects: `playerContext`
|
||||
|
||||
If your export matches a naming convention, skip the `@public` tag.
|
||||
|
||||
### The slug prop
|
||||
|
||||
The `util` prop takes the export name (`"usePlayer"`, `"PlayerController"`). If the generated JSON slug doesn't match `kebabCase(util)` -- like the HTML `createPlayer` whose slug is `html-create-player` -- pass `slug` explicitly:
|
||||
|
||||
```mdx
|
||||
<UtilReference util="createPlayer" slug="html-create-player" />
|
||||
```
|
||||
|
||||
### Generated JSON
|
||||
|
||||
Util reference JSON is at `site/src/content/generated-util-reference/{slug}.json`. The builder generates it from the discovery pipeline in `site/scripts/api-docs-builder/src/util-handler.ts`.
|
||||
|
||||
## Add to the sidebar
|
||||
|
||||
Open `site/src/docs.config.ts` and add your page alphabetically within the Components section:
|
||||
Open `site/src/docs.config.ts` and add your page alphabetically within the appropriate section:
|
||||
|
||||
- **Components** — UI component reference pages
|
||||
- **Selectors** — State selectors (visible to both frameworks)
|
||||
- **Hooks & Utilities** (`frameworks: ['react']`) — React hooks and utilities
|
||||
- **Controllers & Mixins** (`frameworks: ['html']`) — HTML controllers and mixins
|
||||
|
||||
```ts
|
||||
{
|
||||
@@ -200,6 +267,11 @@ Open `site/src/docs.config.ts` and add your page alphabetically within the Compo
|
||||
|
||||
For reference, look at existing pages:
|
||||
|
||||
**Component pages:**
|
||||
- <DocsLink slug="reference/play-button">PlayButton</DocsLink> — single-part, interactive
|
||||
- <DocsLink slug="reference/controls">Controls</DocsLink> — behavior-heavy (auto-hide)
|
||||
- <DocsLink slug="reference/time">Time</DocsLink> — multi-part, formatting
|
||||
|
||||
**Util pages:**
|
||||
- <DocsLink slug="reference/use-player">usePlayer</DocsLink> — React hook, multi-overload
|
||||
- <DocsLink slug="reference/player-controller">PlayerController</DocsLink> — HTML controller
|
||||
|
||||
Reference in New Issue
Block a user