From ed2273059228324ee69de6f27d5e1c9567f8f176 Mon Sep 17 00:00:00 2001 From: rahim Date: Fri, 27 Feb 2026 16:42:47 -0800 Subject: [PATCH] refactor(html): separate provider and container concerns in createPlayer (#635) --- packages/html/src/define/audio/player.ts | 6 ++- packages/html/src/define/background/player.ts | 6 ++- packages/html/src/define/media/container.ts | 17 +++++++ packages/html/src/define/video/player.ts | 6 ++- packages/html/src/index.ts | 1 - packages/html/src/player/create-player.ts | 23 ++-------- packages/html/src/player/player-mixin.ts | 33 ------------- .../src/player/tests/create-player.test.ts | 24 ++++++---- packages/html/src/store/types.ts | 8 ---- packages/sandbox/templates/html/main.ts | 12 ++--- .../html/css/BasicUsage.html | 22 +++++---- .../demos/controls/html/css/BasicUsage.html | 34 +++++++------- .../html/css/BasicUsage.html | 24 +++++----- .../html/css/BasicUsage.html | 22 +++++---- .../html-create-player/html/css/BasicUsage.ts | 5 +- .../mute-button/html/css/BasicUsage.html | 24 +++++----- .../mute-button/html/css/VolumeLevels.html | 28 +++++------ .../demos/pip-button/html/css/BasicUsage.html | 24 +++++----- .../play-button/html/css/BasicUsage.html | 24 +++++----- .../html/css/BasicUsage.html | 34 +++++++------- .../player-controller/html/css/BasicUsage.ts | 5 +- .../demos/poster/html/css/BasicUsage.html | 30 ++++++------ .../seek-button/html/css/BasicUsage.html | 32 +++++++------ .../demos/time/html/css/CurrentDuration.html | 26 ++++++----- .../docs/demos/time/html/css/CurrentTime.html | 18 ++++---- .../time/html/css/CustomNegativeSign.html | 26 ++++++----- .../demos/time/html/css/CustomSeparator.html | 26 ++++++----- .../docs/demos/time/html/css/Remaining.html | 18 ++++---- .../docs/reference/container-mixin.mdx | 8 +++- .../docs/reference/html-create-player.mdx | 41 ++++++++++++++--- .../content/docs/reference/player-mixin.mdx | 46 ++++++++----------- .../content/docs/reference/provider-mixin.mdx | 8 +++- site/src/docs.config.ts | 2 +- 33 files changed, 348 insertions(+), 315 deletions(-) create mode 100644 packages/html/src/define/media/container.ts delete mode 100644 packages/html/src/player/player-mixin.ts diff --git a/packages/html/src/define/audio/player.ts b/packages/html/src/define/audio/player.ts index ccba4e13..df5b15a2 100644 --- a/packages/html/src/define/audio/player.ts +++ b/packages/html/src/define/audio/player.ts @@ -1,11 +1,13 @@ import { features } from '@videojs/core/dom'; import { createPlayer } from '../../player/create-player'; +import { MediaElement } from '../../ui/media-element'; +import '../media/container'; -const { PlayerElement } = createPlayer({ +const { ProviderMixin } = createPlayer({ features: features.audio, }); -export class AudioPlayerElement extends PlayerElement { +export class AudioPlayerElement extends ProviderMixin(MediaElement) { static readonly tagName = 'audio-player'; } diff --git a/packages/html/src/define/background/player.ts b/packages/html/src/define/background/player.ts index ca87fa4a..0f0a3fe2 100644 --- a/packages/html/src/define/background/player.ts +++ b/packages/html/src/define/background/player.ts @@ -1,11 +1,13 @@ import { features } from '@videojs/core/dom'; import { createPlayer } from '../../player/create-player'; +import { MediaElement } from '../../ui/media-element'; +import '../media/container'; -const { PlayerElement } = createPlayer({ +const { ProviderMixin } = createPlayer({ features: features.background, }); -export class BackgroundVideoPlayerElement extends PlayerElement { +export class BackgroundVideoPlayerElement extends ProviderMixin(MediaElement) { static readonly tagName = 'background-video-player'; } diff --git a/packages/html/src/define/media/container.ts b/packages/html/src/define/media/container.ts new file mode 100644 index 00000000..b02495e3 --- /dev/null +++ b/packages/html/src/define/media/container.ts @@ -0,0 +1,17 @@ +import { playerContext } from '../../player/context'; +import { createContainerMixin } from '../../store/container-mixin'; +import { MediaElement } from '../../ui/media-element'; + +const ContainerMixin = createContainerMixin(playerContext); + +export class MediaContainerElement extends ContainerMixin(MediaElement) { + static readonly tagName = 'media-container'; +} + +customElements.define(MediaContainerElement.tagName, MediaContainerElement); + +declare global { + interface HTMLElementTagNameMap { + [MediaContainerElement.tagName]: MediaContainerElement; + } +} diff --git a/packages/html/src/define/video/player.ts b/packages/html/src/define/video/player.ts index 20580df5..a1e6408b 100644 --- a/packages/html/src/define/video/player.ts +++ b/packages/html/src/define/video/player.ts @@ -1,11 +1,13 @@ import { features } from '@videojs/core/dom'; import { createPlayer } from '../../player/create-player'; +import { MediaElement } from '../../ui/media-element'; +import '../media/container'; -const { PlayerElement } = createPlayer({ +const { ProviderMixin } = createPlayer({ features: features.video, }); -export class VideoPlayerElement extends PlayerElement { +export class VideoPlayerElement extends ProviderMixin(MediaElement) { static readonly tagName = 'video-player'; } diff --git a/packages/html/src/index.ts b/packages/html/src/index.ts index 7f496297..0f2d4412 100644 --- a/packages/html/src/index.ts +++ b/packages/html/src/index.ts @@ -9,7 +9,6 @@ export { createSelector, shallowEqual } from '@videojs/store'; export * from './player/context'; export * from './player/create-player'; export * from './player/player-controller'; -export * from './player/player-mixin'; export * from './store/container-mixin'; export * from './store/provider-mixin'; export * from './store/types'; diff --git a/packages/html/src/player/create-player.ts b/packages/html/src/player/create-player.ts index ab4da3e3..55fa2810 100644 --- a/packages/html/src/player/create-player.ts +++ b/packages/html/src/player/create-player.ts @@ -11,11 +11,8 @@ import { combine, createStore } from '@videojs/store'; import { type ContainerMixin, createContainerMixin } from '../store/container-mixin'; import { createProviderMixin, type ProviderMixin } from '../store/provider-mixin'; -import type { PlayerElementConstructor } from '../store/types'; -import { MediaElement } from '../ui/media-element'; import { type PlayerContext, playerContext } from './context'; import { PlayerController } from './player-controller'; -import { createPlayerMixin, type PlayerMixin } from './player-mixin'; export interface CreatePlayerConfig { features: Features; @@ -31,12 +28,6 @@ export interface CreatePlayerResult { /** Player controller bound to this player's context. */ PlayerController: PlayerController.Constructor; - /** Pre-composed player element ready for customElements.define(). */ - PlayerElement: PlayerElementConstructor; - - /** Mixin for a complete player element (provider + container). */ - PlayerMixin: PlayerMixin; - /** Mixin that provides player context to descendants. */ ProviderMixin: ProviderMixin; @@ -52,15 +43,13 @@ export interface CreatePlayerResult { * import { features } from '@videojs/core/dom'; * import { createPlayer, MediaElement } from '@videojs/html'; * - * const { PlayerElement, PlayerController, context } = createPlayer({ + * const { ProviderMixin, ContainerMixin, PlayerController, context } = createPlayer({ * features: features.video, * }); * - * // Simple: register pre-composed PlayerElement - * customElements.define('video-player', PlayerElement); - * - * // Custom: extend with PlayerMixin - * class MyPlayer extends PlayerMixin(MediaElement) {} + * // Provider element: owns the store, provides context to descendants + * class VideoPlayer extends ProviderMixin(MediaElement) {} + * customElements.define('video-player', VideoPlayer); * * // Control element with selector * class PlayButton extends MediaElement { @@ -98,8 +87,6 @@ export function createPlayer(config: CreatePlayerConfig): Cr return createStore()(slice); } - const PlayerMixin = createPlayerMixin(playerContext, create); - const PlayerElement = PlayerMixin(MediaElement); const ProviderMixin = createProviderMixin(playerContext, create); const ContainerMixin = createContainerMixin(playerContext); @@ -107,8 +94,6 @@ export function createPlayer(config: CreatePlayerConfig): Cr context: playerContext, create, PlayerController, - PlayerElement, - PlayerMixin, ProviderMixin, ContainerMixin, }; diff --git a/packages/html/src/player/player-mixin.ts b/packages/html/src/player/player-mixin.ts deleted file mode 100644 index 3ab04a3a..00000000 --- a/packages/html/src/player/player-mixin.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { PlayerStore } from '@videojs/core/dom'; -import type { MediaElementConstructor } from '@/ui/media-element'; -import { createContainerMixin } from '../store/container-mixin'; -import { createProviderMixin } from '../store/provider-mixin'; -import type { PlayerProviderConstructor } from '../store/types'; -import type { PlayerContext } from './context'; - -type Result = Class & - PlayerProviderConstructor; - -export type PlayerMixin = ( - BaseClass: Class -) => Result; - -/** - * Creates a mixin that combines provider and container functionality. - * - * Use for a complete player element that owns the store and attaches media. - * - * @param context - Player context for descendant consumption. - * @param factory - Factory function that creates a store instance. - */ -export function createPlayerMixin( - context: PlayerContext, - factory: () => Store -): PlayerMixin { - const ProviderMixin = createProviderMixin(context, factory); - const ContainerMixin = createContainerMixin(context); - - return (BaseClass: Class) => { - return ProviderMixin(ContainerMixin(BaseClass)) as unknown as Result; - }; -} diff --git a/packages/html/src/player/tests/create-player.test.ts b/packages/html/src/player/tests/create-player.test.ts index 374eecdf..86795021 100644 --- a/packages/html/src/player/tests/create-player.test.ts +++ b/packages/html/src/player/tests/create-player.test.ts @@ -1,6 +1,7 @@ import { features } from '@videojs/core/dom'; import { describe, expect, it } from 'vitest'; +import { MediaElement } from '../../ui/media-element'; import { createPlayer } from '../create-player'; describe('createPlayer', () => { @@ -10,8 +11,6 @@ describe('createPlayer', () => { expect(result.context).toBeDefined(); expect(result.create).toBeInstanceOf(Function); expect(result.PlayerController).toBeDefined(); - expect(result.PlayerElement).toBeDefined(); - expect(result.PlayerMixin).toBeInstanceOf(Function); expect(result.ProviderMixin).toBeInstanceOf(Function); expect(result.ContainerMixin).toBeInstanceOf(Function); }); @@ -25,11 +24,20 @@ describe('createPlayer', () => { expect(store.destroy).toBeInstanceOf(Function); }); - it('PlayerElement is a valid custom element class', () => { - const { PlayerElement } = createPlayer({ features: features.video }); + it('ProviderMixin produces a valid custom element class', () => { + const { ProviderMixin } = createPlayer({ features: features.video }); + const ProviderElement = ProviderMixin(MediaElement); - expect(typeof PlayerElement).toBe('function'); - expect(PlayerElement.prototype).toBeDefined(); + expect(typeof ProviderElement).toBe('function'); + expect(ProviderElement.prototype).toBeDefined(); + }); + + it('ContainerMixin produces a valid custom element class', () => { + const { ContainerMixin } = createPlayer({ features: features.video }); + const ContainerElement = ContainerMixin(MediaElement); + + expect(typeof ContainerElement).toBe('function'); + expect(ContainerElement.prototype).toBeDefined(); }); it('creates audio player with expected exports', () => { @@ -38,8 +46,6 @@ describe('createPlayer', () => { expect(result.context).toBeDefined(); expect(result.create).toBeInstanceOf(Function); expect(result.PlayerController).toBeDefined(); - expect(result.PlayerElement).toBeDefined(); - expect(result.PlayerMixin).toBeInstanceOf(Function); expect(result.ProviderMixin).toBeInstanceOf(Function); expect(result.ContainerMixin).toBeInstanceOf(Function); }); @@ -50,8 +56,6 @@ describe('createPlayer', () => { expect(result.context).toBeDefined(); expect(result.create).toBeInstanceOf(Function); expect(result.PlayerController).toBeDefined(); - expect(result.PlayerElement).toBeDefined(); - expect(result.PlayerMixin).toBeInstanceOf(Function); expect(result.ProviderMixin).toBeInstanceOf(Function); expect(result.ContainerMixin).toBeInstanceOf(Function); }); diff --git a/packages/html/src/store/types.ts b/packages/html/src/store/types.ts index 054f27f2..a44b3130 100644 --- a/packages/html/src/store/types.ts +++ b/packages/html/src/store/types.ts @@ -2,14 +2,6 @@ import type { PlayerStore } from '@videojs/core/dom'; import type { Constructor } from '@videojs/utils/types'; import type { MediaElement } from '@/ui/media-element'; -// ---------------------------------------- -// PlayerElement -// ---------------------------------------- - -export interface PlayerElement extends MediaElement, PlayerProvider {} - -export interface PlayerElementConstructor extends Constructor> {} - // ---------------------------------------- // PlayerProvider // ---------------------------------------- diff --git a/packages/sandbox/templates/html/main.ts b/packages/sandbox/templates/html/main.ts index d685fa3e..91c598cc 100644 --- a/packages/sandbox/templates/html/main.ts +++ b/packages/sandbox/templates/html/main.ts @@ -1,18 +1,14 @@ // HTML sandbox — Web player (DOM/Browser) // http://localhost:5173/html/ -import { createPlayer, features } from '@videojs/html'; - -const { PlayerElement } = createPlayer({ - features: features.video, -}); - -customElements.define('video-player', PlayerElement); +import '@videojs/html/video/player'; const html = String.raw; document.getElementById('root')!.innerHTML = html` - + + + `; diff --git a/site/src/components/docs/demos/buffering-indicator/html/css/BasicUsage.html b/site/src/components/docs/demos/buffering-indicator/html/css/BasicUsage.html index 2572a7ff..fdd3f595 100644 --- a/site/src/components/docs/demos/buffering-indicator/html/css/BasicUsage.html +++ b/site/src/components/docs/demos/buffering-indicator/html/css/BasicUsage.html @@ -1,12 +1,14 @@ - - -
-
+ + + +
+
+
diff --git a/site/src/components/docs/demos/controls/html/css/BasicUsage.html b/site/src/components/docs/demos/controls/html/css/BasicUsage.html index d01832b4..2caa3b91 100644 --- a/site/src/components/docs/demos/controls/html/css/BasicUsage.html +++ b/site/src/components/docs/demos/controls/html/css/BasicUsage.html @@ -1,19 +1,21 @@ - + + - - - - Play - Pause - - - - + + + + Play + Pause + + + + + diff --git a/site/src/components/docs/demos/fullscreen-button/html/css/BasicUsage.html b/site/src/components/docs/demos/fullscreen-button/html/css/BasicUsage.html index a81dae2c..0384682b 100644 --- a/site/src/components/docs/demos/fullscreen-button/html/css/BasicUsage.html +++ b/site/src/components/docs/demos/fullscreen-button/html/css/BasicUsage.html @@ -1,13 +1,15 @@ - - - Exit Fullscreen - Fullscreen - + + + + Exit Fullscreen + Fullscreen + + diff --git a/site/src/components/docs/demos/html-create-player/html/css/BasicUsage.html b/site/src/components/docs/demos/html-create-player/html/css/BasicUsage.html index 49156b89..4aadfc79 100644 --- a/site/src/components/docs/demos/html-create-player/html/css/BasicUsage.html +++ b/site/src/components/docs/demos/html-create-player/html/css/BasicUsage.html @@ -1,12 +1,14 @@ - - - Play - Pause - + + + + Play + Pause + + diff --git a/site/src/components/docs/demos/html-create-player/html/css/BasicUsage.ts b/site/src/components/docs/demos/html-create-player/html/css/BasicUsage.ts index 71a83c8c..14f6ba0e 100644 --- a/site/src/components/docs/demos/html-create-player/html/css/BasicUsage.ts +++ b/site/src/components/docs/demos/html-create-player/html/css/BasicUsage.ts @@ -7,12 +7,13 @@ import { MediaElement, selectPlayback, } from '@videojs/html'; +import '@videojs/html/media/container'; -const { PlayerElement, PlayerController, context } = createPlayer({ +const { ProviderMixin, PlayerController, context } = createPlayer({ features: [...features.video], }); -class VideoPlayer extends PlayerElement { +class VideoPlayer extends ProviderMixin(MediaElement) { static readonly tagName = 'demo-video-player'; } diff --git a/site/src/components/docs/demos/mute-button/html/css/BasicUsage.html b/site/src/components/docs/demos/mute-button/html/css/BasicUsage.html index cda6f540..39799edd 100644 --- a/site/src/components/docs/demos/mute-button/html/css/BasicUsage.html +++ b/site/src/components/docs/demos/mute-button/html/css/BasicUsage.html @@ -1,13 +1,15 @@ - - - Unmute - Mute - + + + + Unmute + Mute + + diff --git a/site/src/components/docs/demos/mute-button/html/css/VolumeLevels.html b/site/src/components/docs/demos/mute-button/html/css/VolumeLevels.html index 0446f917..ddd2f809 100644 --- a/site/src/components/docs/demos/mute-button/html/css/VolumeLevels.html +++ b/site/src/components/docs/demos/mute-button/html/css/VolumeLevels.html @@ -1,15 +1,17 @@ - - - Off - Low - Medium - High - + + + + Off + Low + Medium + High + + diff --git a/site/src/components/docs/demos/pip-button/html/css/BasicUsage.html b/site/src/components/docs/demos/pip-button/html/css/BasicUsage.html index 5709d98b..77d0252e 100644 --- a/site/src/components/docs/demos/pip-button/html/css/BasicUsage.html +++ b/site/src/components/docs/demos/pip-button/html/css/BasicUsage.html @@ -1,13 +1,15 @@ - - - Exit PiP - Enter PiP - + + + + Exit PiP + Enter PiP + + diff --git a/site/src/components/docs/demos/play-button/html/css/BasicUsage.html b/site/src/components/docs/demos/play-button/html/css/BasicUsage.html index 9784d362..e7a0ae96 100644 --- a/site/src/components/docs/demos/play-button/html/css/BasicUsage.html +++ b/site/src/components/docs/demos/play-button/html/css/BasicUsage.html @@ -1,13 +1,15 @@ - - - Play - Pause - Replay - + + + + Play + Pause + Replay + + diff --git a/site/src/components/docs/demos/player-controller/html/css/BasicUsage.html b/site/src/components/docs/demos/player-controller/html/css/BasicUsage.html index 3da148dc..cf8ca55b 100644 --- a/site/src/components/docs/demos/player-controller/html/css/BasicUsage.html +++ b/site/src/components/docs/demos/player-controller/html/css/BasicUsage.html @@ -1,18 +1,20 @@ - -
- - - - - - - Paused: Yes | Time: 0.0s | Volume: 100% - -
+ + +
+ + + + + + + Paused: Yes | Time: 0.0s | Volume: 100% + +
+
diff --git a/site/src/components/docs/demos/player-controller/html/css/BasicUsage.ts b/site/src/components/docs/demos/player-controller/html/css/BasicUsage.ts index 09f18635..5df3dda4 100644 --- a/site/src/components/docs/demos/player-controller/html/css/BasicUsage.ts +++ b/site/src/components/docs/demos/player-controller/html/css/BasicUsage.ts @@ -1,10 +1,11 @@ import { applyElementProps, createButton, createPlayer, features, MediaElement } from '@videojs/html'; +import '@videojs/html/media/container'; -const { PlayerElement, PlayerController, context } = createPlayer({ +const { ProviderMixin, PlayerController, context } = createPlayer({ features: [...features.video], }); -class DemoPlayer extends PlayerElement { +class DemoPlayer extends ProviderMixin(MediaElement) { static readonly tagName = 'demo-ctrl-player'; } diff --git a/site/src/components/docs/demos/poster/html/css/BasicUsage.html b/site/src/components/docs/demos/poster/html/css/BasicUsage.html index 5d7f1088..4369eca1 100644 --- a/site/src/components/docs/demos/poster/html/css/BasicUsage.html +++ b/site/src/components/docs/demos/poster/html/css/BasicUsage.html @@ -1,19 +1,21 @@ - + + - - Video thumbnail - + + Video thumbnail + - - Play - Pause - + + Play + Pause + + diff --git a/site/src/components/docs/demos/seek-button/html/css/BasicUsage.html b/site/src/components/docs/demos/seek-button/html/css/BasicUsage.html index 896b1eda..41ecb5a1 100644 --- a/site/src/components/docs/demos/seek-button/html/css/BasicUsage.html +++ b/site/src/components/docs/demos/seek-button/html/css/BasicUsage.html @@ -1,17 +1,19 @@ - -
- - ⏪ 5s - - - 10s ⏩ - -
+ + +
+ + ⏪ 5s + + + 10s ⏩ + +
+
diff --git a/site/src/components/docs/demos/time/html/css/CurrentDuration.html b/site/src/components/docs/demos/time/html/css/CurrentDuration.html index 843cceaf..70e99b00 100644 --- a/site/src/components/docs/demos/time/html/css/CurrentDuration.html +++ b/site/src/components/docs/demos/time/html/css/CurrentDuration.html @@ -1,14 +1,16 @@ - - - - - - + + + + + + + + diff --git a/site/src/components/docs/demos/time/html/css/CurrentTime.html b/site/src/components/docs/demos/time/html/css/CurrentTime.html index 777247fc..8caa1487 100644 --- a/site/src/components/docs/demos/time/html/css/CurrentTime.html +++ b/site/src/components/docs/demos/time/html/css/CurrentTime.html @@ -1,10 +1,12 @@ - - + + + + diff --git a/site/src/components/docs/demos/time/html/css/CustomNegativeSign.html b/site/src/components/docs/demos/time/html/css/CustomNegativeSign.html index b41d2084..5f199e3f 100644 --- a/site/src/components/docs/demos/time/html/css/CustomNegativeSign.html +++ b/site/src/components/docs/demos/time/html/css/CustomNegativeSign.html @@ -1,14 +1,16 @@ - - + + + + diff --git a/site/src/components/docs/demos/time/html/css/CustomSeparator.html b/site/src/components/docs/demos/time/html/css/CustomSeparator.html index 29dea2b7..bd2e7fd0 100644 --- a/site/src/components/docs/demos/time/html/css/CustomSeparator.html +++ b/site/src/components/docs/demos/time/html/css/CustomSeparator.html @@ -1,14 +1,16 @@ - - - - of - - + + + + + of + + + diff --git a/site/src/components/docs/demos/time/html/css/Remaining.html b/site/src/components/docs/demos/time/html/css/Remaining.html index 90d80f5c..d123fe56 100644 --- a/site/src/components/docs/demos/time/html/css/Remaining.html +++ b/site/src/components/docs/demos/time/html/css/Remaining.html @@ -1,10 +1,12 @@ - - + + + + diff --git a/site/src/content/docs/reference/container-mixin.mdx b/site/src/content/docs/reference/container-mixin.mdx index 96f609a3..9ff465ad 100644 --- a/site/src/content/docs/reference/container-mixin.mdx +++ b/site/src/content/docs/reference/container-mixin.mdx @@ -12,7 +12,13 @@ import DocsLink from "@/components/docs/DocsLink.astro"; Use `ContainerMixin` when the provider 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 `PlayerMixin` instead. +For a single element that both owns the store and attaches media, compose both mixins on the same base class: + +```ts +const { ProviderMixin, ContainerMixin } = createPlayer({ features: features.video }); + +class VideoPlayer extends ProviderMixin(ContainerMixin(MediaElement)) {} +``` ### How media discovery works diff --git a/site/src/content/docs/reference/html-create-player.mdx b/site/src/content/docs/reference/html-create-player.mdx index 95ae3b39..33f81e9a 100644 --- a/site/src/content/docs/reference/html-create-player.mdx +++ b/site/src/content/docs/reference/html-create-player.mdx @@ -6,33 +6,60 @@ description: Factory function that creates a player instance with typed store, m 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 `PlayerController`, `context`, individual mixins, and a `create` factory. +`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 a typed `PlayerController`, `context`, `ProviderMixin`, `ContainerMixin`, and a `create` store 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); +// Provider element: owns and publishes the store +class VideoPlayer extends ProviderMixin(MediaElement) {} + +// Container element: discovers