@videojs/html 10.3.0 → 10.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/default/define/audio/compat-skin.css +91 -38
- package/dist/default/define/audio/compat-skin2.js +1 -1
- package/dist/default/define/audio/neutral-skin.css +52 -31
- package/dist/default/define/audio/neutral-skin2.js +1 -1
- package/dist/default/define/audio/scaffold-skin.css +105 -40
- package/dist/default/define/audio/scaffold-skin2.js +1 -1
- package/dist/default/define/audio/skin.css +53 -31
- package/dist/default/define/audio/skin2.js +1 -1
- package/dist/default/define/live-audio/compat-skin.css +91 -38
- package/dist/default/define/live-audio/compat-skin2.js +1 -1
- package/dist/default/define/live-audio/neutral-skin.css +50 -29
- package/dist/default/define/live-audio/neutral-skin2.js +1 -1
- package/dist/default/define/live-audio/scaffold-skin.css +105 -40
- package/dist/default/define/live-audio/scaffold-skin2.js +1 -1
- package/dist/default/define/live-audio/skin.css +51 -29
- package/dist/default/define/live-audio/skin2.js +1 -1
- package/dist/default/define/live-video/compat-skin.css +142 -61
- package/dist/default/define/live-video/compat-skin2.js +1 -1
- package/dist/default/define/live-video/neutral-skin.css +241 -55
- package/dist/default/define/live-video/neutral-skin2.js +1 -1
- package/dist/default/define/live-video/scaffold-skin.css +159 -63
- package/dist/default/define/live-video/scaffold-skin2.js +1 -1
- package/dist/default/define/live-video/skin.css +245 -60
- package/dist/default/define/live-video/skin2.js +1 -1
- package/dist/default/define/ui/time-slider-markers.js +5 -0
- package/dist/default/define/video/compat-skin.css +150 -61
- package/dist/default/define/video/compat-skin2.js +1 -1
- package/dist/default/define/video/neutral-skin.css +322 -66
- package/dist/default/define/video/neutral-skin2.js +1 -1
- package/dist/default/define/video/scaffold-skin.css +168 -63
- package/dist/default/define/video/scaffold-skin2.js +1 -1
- package/dist/default/define/video/skin.css +348 -66
- package/dist/default/define/video/skin2.js +1 -1
- package/dist/default/index.js +3 -1
- package/dist/default/internal/skins/compat-audio/skin.css +91 -38
- package/dist/default/internal/skins/compat-live-audio/skin.css +91 -38
- package/dist/default/internal/skins/compat-live-video/skin.css +142 -61
- package/dist/default/internal/skins/compat-live-video/template.js +2 -0
- package/dist/default/internal/skins/compat-video/skin.css +150 -61
- package/dist/default/internal/skins/compat-video/template.js +2 -0
- package/dist/default/internal/skins/default-audio/skin.css +53 -31
- package/dist/default/internal/skins/default-live-audio/skin.css +51 -29
- package/dist/default/internal/skins/default-live-video/skin.css +245 -60
- package/dist/default/internal/skins/default-live-video/template.js +14 -0
- package/dist/default/internal/skins/default-video/register.js +3 -0
- package/dist/default/internal/skins/default-video/skin.css +348 -66
- package/dist/default/internal/skins/default-video/template.js +33 -5
- package/dist/default/internal/skins/neutral-audio/skin.css +52 -31
- package/dist/default/internal/skins/neutral-live-audio/skin.css +50 -29
- package/dist/default/internal/skins/neutral-live-video/skin.css +241 -55
- package/dist/default/internal/skins/neutral-live-video/template.js +14 -0
- package/dist/default/internal/skins/neutral-video/skin.css +322 -66
- package/dist/default/internal/skins/neutral-video/template.js +25 -11
- package/dist/default/internal/skins/scaffold-audio/skin.css +105 -40
- package/dist/default/internal/skins/scaffold-live-audio/skin.css +105 -40
- package/dist/default/internal/skins/scaffold-live-video/skin.css +159 -63
- package/dist/default/internal/skins/scaffold-live-video/template.js +2 -0
- package/dist/default/internal/skins/scaffold-video/skin.css +168 -63
- package/dist/default/internal/skins/scaffold-video/template.js +3 -1
- package/dist/default/media/background-video/adapter.js +13 -35
- package/dist/default/media/background-video/base.js +95 -0
- package/dist/default/media/background-video/template.js +13 -20
- package/dist/default/media/hls-background-video/adapter.js +16 -35
- package/dist/default/ui/captions-radio-group/element.js +14 -1
- package/dist/default/ui/controls/element.js +6 -3
- package/dist/default/ui/time-slider/markers.js +160 -0
- package/dist/default/version.js +1 -1
- package/dist/dev/define/audio/compat-skin.css +91 -38
- package/dist/dev/define/audio/compat-skin2.js +1 -1
- package/dist/dev/define/audio/compat-skin2.js.map +1 -1
- package/dist/dev/define/audio/neutral-skin.css +52 -31
- package/dist/dev/define/audio/neutral-skin2.js +1 -1
- package/dist/dev/define/audio/neutral-skin2.js.map +1 -1
- package/dist/dev/define/audio/scaffold-skin.css +105 -40
- package/dist/dev/define/audio/scaffold-skin2.js +1 -1
- package/dist/dev/define/audio/scaffold-skin2.js.map +1 -1
- package/dist/dev/define/audio/skin.css +53 -31
- package/dist/dev/define/audio/skin2.js +1 -1
- package/dist/dev/define/audio/skin2.js.map +1 -1
- package/dist/dev/define/live-audio/compat-skin.css +91 -38
- package/dist/dev/define/live-audio/compat-skin2.js +1 -1
- package/dist/dev/define/live-audio/compat-skin2.js.map +1 -1
- package/dist/dev/define/live-audio/neutral-skin.css +50 -29
- package/dist/dev/define/live-audio/neutral-skin2.js +1 -1
- package/dist/dev/define/live-audio/neutral-skin2.js.map +1 -1
- package/dist/dev/define/live-audio/scaffold-skin.css +105 -40
- package/dist/dev/define/live-audio/scaffold-skin2.js +1 -1
- package/dist/dev/define/live-audio/scaffold-skin2.js.map +1 -1
- package/dist/dev/define/live-audio/skin.css +51 -29
- package/dist/dev/define/live-audio/skin2.js +1 -1
- package/dist/dev/define/live-audio/skin2.js.map +1 -1
- package/dist/dev/define/live-video/compat-skin.css +142 -61
- package/dist/dev/define/live-video/compat-skin2.js +1 -1
- package/dist/dev/define/live-video/compat-skin2.js.map +1 -1
- package/dist/dev/define/live-video/neutral-skin.css +241 -55
- package/dist/dev/define/live-video/neutral-skin2.js +1 -1
- package/dist/dev/define/live-video/neutral-skin2.js.map +1 -1
- package/dist/dev/define/live-video/scaffold-skin.css +159 -63
- package/dist/dev/define/live-video/scaffold-skin2.js +1 -1
- package/dist/dev/define/live-video/scaffold-skin2.js.map +1 -1
- package/dist/dev/define/live-video/skin.css +245 -60
- package/dist/dev/define/live-video/skin2.js +1 -1
- package/dist/dev/define/live-video/skin2.js.map +1 -1
- package/dist/dev/define/ui/time-slider-markers.d.ts +8 -0
- package/dist/dev/define/ui/time-slider-markers.js +7 -0
- package/dist/dev/define/ui/time-slider-markers.js.map +1 -0
- package/dist/dev/define/video/compat-skin.css +150 -61
- package/dist/dev/define/video/compat-skin2.js +1 -1
- package/dist/dev/define/video/compat-skin2.js.map +1 -1
- package/dist/dev/define/video/neutral-skin.css +322 -66
- package/dist/dev/define/video/neutral-skin2.js +1 -1
- package/dist/dev/define/video/neutral-skin2.js.map +1 -1
- package/dist/dev/define/video/scaffold-skin.css +168 -63
- package/dist/dev/define/video/scaffold-skin2.js +1 -1
- package/dist/dev/define/video/scaffold-skin2.js.map +1 -1
- package/dist/dev/define/video/skin.css +348 -66
- package/dist/dev/define/video/skin2.js +1 -1
- package/dist/dev/define/video/skin2.js.map +1 -1
- package/dist/dev/index.d.ts +5 -4
- package/dist/dev/index.js +3 -1
- package/dist/dev/internal/skins/compat-audio/skin.css +91 -38
- package/dist/dev/internal/skins/compat-live-audio/skin.css +91 -38
- package/dist/dev/internal/skins/compat-live-video/skin.css +142 -61
- package/dist/dev/internal/skins/compat-live-video/template.js +2 -0
- package/dist/dev/internal/skins/compat-live-video/template.js.map +1 -1
- package/dist/dev/internal/skins/compat-video/skin.css +150 -61
- package/dist/dev/internal/skins/compat-video/template.js +2 -0
- package/dist/dev/internal/skins/compat-video/template.js.map +1 -1
- package/dist/dev/internal/skins/default-audio/skin.css +53 -31
- package/dist/dev/internal/skins/default-live-audio/skin.css +51 -29
- package/dist/dev/internal/skins/default-live-video/register.js.map +1 -1
- package/dist/dev/internal/skins/default-live-video/skin.css +245 -60
- package/dist/dev/internal/skins/default-live-video/template.js +14 -0
- package/dist/dev/internal/skins/default-live-video/template.js.map +1 -1
- package/dist/dev/internal/skins/default-video/register.d.ts +1 -0
- package/dist/dev/internal/skins/default-video/register.js +3 -0
- package/dist/dev/internal/skins/default-video/register.js.map +1 -1
- package/dist/dev/internal/skins/default-video/skin.css +348 -66
- package/dist/dev/internal/skins/default-video/template.js +33 -5
- package/dist/dev/internal/skins/default-video/template.js.map +1 -1
- package/dist/dev/internal/skins/neutral-audio/skin.css +52 -31
- package/dist/dev/internal/skins/neutral-live-audio/skin.css +50 -29
- package/dist/dev/internal/skins/neutral-live-video/register.js.map +1 -1
- package/dist/dev/internal/skins/neutral-live-video/skin.css +241 -55
- package/dist/dev/internal/skins/neutral-live-video/template.js +14 -0
- package/dist/dev/internal/skins/neutral-live-video/template.js.map +1 -1
- package/dist/dev/internal/skins/neutral-video/register.js.map +1 -1
- package/dist/dev/internal/skins/neutral-video/skin.css +322 -66
- package/dist/dev/internal/skins/neutral-video/template.js +25 -11
- package/dist/dev/internal/skins/neutral-video/template.js.map +1 -1
- package/dist/dev/internal/skins/scaffold-audio/skin.css +105 -40
- package/dist/dev/internal/skins/scaffold-live-audio/skin.css +105 -40
- package/dist/dev/internal/skins/scaffold-live-video/skin.css +159 -63
- package/dist/dev/internal/skins/scaffold-live-video/template.js +2 -0
- package/dist/dev/internal/skins/scaffold-live-video/template.js.map +1 -1
- package/dist/dev/internal/skins/scaffold-video/skin.css +168 -63
- package/dist/dev/internal/skins/scaffold-video/template.js +3 -1
- package/dist/dev/internal/skins/scaffold-video/template.js.map +1 -1
- package/dist/dev/media/background-video/adapter.d.ts +7 -13
- package/dist/dev/media/background-video/adapter.js +13 -35
- package/dist/dev/media/background-video/adapter.js.map +1 -1
- package/dist/dev/media/background-video/base.d.ts +44 -0
- package/dist/dev/media/background-video/base.js +97 -0
- package/dist/dev/media/background-video/base.js.map +1 -0
- package/dist/dev/media/background-video/template.d.ts +3 -0
- package/dist/dev/media/background-video/template.js +13 -20
- package/dist/dev/media/background-video/template.js.map +1 -1
- package/dist/dev/media/hls-background-video/adapter.d.ts +8 -18
- package/dist/dev/media/hls-background-video/adapter.js +16 -35
- package/dist/dev/media/hls-background-video/adapter.js.map +1 -1
- package/dist/dev/ui/captions-button/element.d.ts +2 -0
- package/dist/dev/ui/captions-radio-group/element.d.ts +2 -1
- package/dist/dev/ui/captions-radio-group/element.js +14 -1
- package/dist/dev/ui/captions-radio-group/element.js.map +1 -1
- package/dist/dev/ui/controls/element.d.ts +2 -2
- package/dist/dev/ui/controls/element.js +6 -3
- package/dist/dev/ui/controls/element.js.map +1 -1
- package/dist/dev/ui/time-slider/markers.d.ts +48 -0
- package/dist/dev/ui/time-slider/markers.js +165 -0
- package/dist/dev/ui/time-slider/markers.js.map +1 -0
- package/dist/dev/version.js +1 -1
- package/docs/README.md +1 -1
- package/docs/guides/autoplay.md +1 -1
- package/docs/guides/background-video.md +2 -4
- package/docs/guides/browser-support.md +22 -16
- package/docs/guides/cdn.md +9 -9
- package/docs/guides/customize-skins.md +3 -0
- package/docs/guides/installation-cdn.md +2 -2
- package/docs/guides/installation-shadcn.md +1 -1
- package/docs/guides/installation-svelte.md +2 -2
- package/docs/guides/installation-vue.md +2 -2
- package/docs/guides/installation.md +2 -2
- package/docs/guides/internationalization.md +5 -5
- package/docs/guides/keyboard-shortcuts.md +10 -0
- package/docs/guides/llms.txt +2 -1
- package/docs/guides/migrate-from-media-chrome.md +4 -4
- package/docs/guides/migrate-from-mux-player.md +6 -6
- package/docs/guides/migrate-from-plyr.md +7 -7
- package/docs/guides/migrate-from-video-js-8.md +6 -6
- package/docs/guides/migrate-from-vidstack.md +4 -4
- package/docs/guides/presets.md +4 -4
- package/docs/guides/self-hosting.md +5 -5
- package/docs/guides/skins.md +8 -7
- package/docs/guides/timed-metadata.md +318 -0
- package/docs/llms.txt +16 -2
- package/docs/reference/api/chapters-track.md +71 -0
- package/docs/reference/api/define-text-track.md +113 -0
- package/docs/reference/api/feature-text-cues.md +133 -0
- package/docs/reference/api/feature-text-tracks.md +11 -5
- package/docs/reference/api/get-active-text-cues.md +69 -0
- package/docs/reference/api/get-text-cues.md +69 -0
- package/docs/reference/api/get-text-tracks.md +41 -0
- package/docs/reference/api/hls-metadata-track.md +48 -0
- package/docs/reference/api/html-create-player.md +2 -2
- package/docs/reference/api/llms.txt +13 -1
- package/docs/reference/api/media-capabilities.md +4 -4
- package/docs/reference/api/player-store.md +9 -4
- package/docs/reference/api/preset-audio.md +3 -1
- package/docs/reference/api/preset-background.md +1 -1
- package/docs/reference/api/preset-live-audio.md +3 -1
- package/docs/reference/api/preset-live-video.md +2 -1
- package/docs/reference/api/preset-video.md +2 -1
- package/docs/reference/components/audio-compat-skin.md +1 -1
- package/docs/reference/components/audio-neutral-skin.md +1 -1
- package/docs/reference/components/audio-scaffold-skin.md +1 -1
- package/docs/reference/components/audio-skin.md +1 -1
- package/docs/reference/components/audio.md +19 -1
- package/docs/reference/components/background-video-skin.md +1 -1
- package/docs/reference/components/background-video.md +26 -11
- package/docs/reference/components/captions-radio-group.md +1 -1
- package/docs/reference/components/cloudflare-video.md +1 -1
- package/docs/reference/components/controls.md +16 -3
- package/docs/reference/components/dailymotion-video.md +2 -2
- package/docs/reference/components/dash-video.md +20 -3
- package/docs/reference/components/google-analytics.md +1 -1
- package/docs/reference/components/google-cast.md +1 -1
- package/docs/reference/components/hls-audio.md +56 -2
- package/docs/reference/components/hls-background-video.md +22 -5
- package/docs/reference/components/hls-video.md +99 -7
- package/docs/reference/components/hlsjs-video.md +52 -13
- package/docs/reference/components/live-audio-compat-skin.md +1 -1
- package/docs/reference/components/live-audio-neutral-skin.md +1 -1
- package/docs/reference/components/live-audio-scaffold-skin.md +1 -1
- package/docs/reference/components/live-audio-skin.md +1 -1
- package/docs/reference/components/live-video-compat-skin.md +5 -1
- package/docs/reference/components/live-video-neutral-skin.md +5 -1
- package/docs/reference/components/live-video-scaffold-skin.md +5 -1
- package/docs/reference/components/live-video-skin.md +5 -1
- package/docs/reference/components/llms.txt +2 -1
- package/docs/reference/components/mixcloud-audio.md +2 -2
- package/docs/reference/components/mux-audio.md +34 -3
- package/docs/reference/components/mux-background-video.md +1 -1
- package/docs/reference/components/mux-data.md +1 -1
- package/docs/reference/components/mux-video.md +17 -3
- package/docs/reference/components/native-hls-video.md +32 -3
- package/docs/reference/components/playerjs-video.md +2 -2
- package/docs/reference/components/shaka-video.md +2 -3
- package/docs/reference/components/soundcloud-audio.md +2 -2
- package/docs/reference/components/spotify-audio.md +2 -2
- package/docs/reference/components/tiktok-video.md +2 -2
- package/docs/reference/components/time-slider-markers.md +194 -0
- package/docs/reference/components/time-slider.md +14 -0
- package/docs/reference/components/twitch-video.md +1 -1
- package/docs/reference/components/video-compat-skin.md +5 -1
- package/docs/reference/components/video-neutral-skin.md +5 -1
- package/docs/reference/components/video-scaffold-skin.md +5 -1
- package/docs/reference/components/video-skin.md +5 -1
- package/docs/reference/components/video.md +19 -1
- package/docs/reference/components/vimeo-video.md +1 -2
- package/docs/reference/components/wistia-video.md +1 -1
- package/docs/reference/components/youtube-video.md +1 -2
- package/package.json +48 -48
|
@@ -3,13 +3,13 @@ import { PlayerController } from "../../player/controller.js";
|
|
|
3
3
|
import { UIElement } from "../ui-element.js";
|
|
4
4
|
import { controlsContext } from "./context.js";
|
|
5
5
|
import { ControlsCore, ControlsDataAttrs, POPUP_HOST_SELECTOR } from "@videojs/core";
|
|
6
|
-
import { applyStateDataAttrs, logMissingFeature, selectControls } from "@videojs/core/dom";
|
|
6
|
+
import { applyStateDataAttrs, logMissingFeature, selectControls, selectPlayback } from "@videojs/core/dom";
|
|
7
7
|
import { ContextProvider } from "@videojs/element/context";
|
|
8
8
|
import { isFunction } from "@videojs/utils/predicate";
|
|
9
9
|
//#region src/ui/controls/element.ts
|
|
10
10
|
/**
|
|
11
|
-
* Tracks controls visibility, reflects
|
|
12
|
-
* the controls closes any popup open inside it.
|
|
11
|
+
* Tracks controls visibility and whether playback has started, reflects them as data attributes, and shares them with
|
|
12
|
+
* its descendant controls parts. Hiding the controls closes any popup open inside it.
|
|
13
13
|
*/
|
|
14
14
|
var ControlsElement = class extends UIElement {
|
|
15
15
|
constructor(..._args) {
|
|
@@ -17,6 +17,7 @@ var ControlsElement = class extends UIElement {
|
|
|
17
17
|
this.visibility = ControlsCore.defaultProps.visibility;
|
|
18
18
|
this.#core = new ControlsCore();
|
|
19
19
|
this.#mediaState = new PlayerController(this, playerContext, selectControls);
|
|
20
|
+
this.#playback = new PlayerController(this, playerContext, selectPlayback);
|
|
20
21
|
this.#provider = new ContextProvider(this, { context: controlsContext });
|
|
21
22
|
this.#visible = true;
|
|
22
23
|
}
|
|
@@ -28,6 +29,7 @@ var ControlsElement = class extends UIElement {
|
|
|
28
29
|
}
|
|
29
30
|
#core;
|
|
30
31
|
#mediaState;
|
|
32
|
+
#playback;
|
|
31
33
|
#provider;
|
|
32
34
|
#visible;
|
|
33
35
|
connectedCallback() {
|
|
@@ -38,6 +40,7 @@ var ControlsElement = class extends UIElement {
|
|
|
38
40
|
super.update(_changed);
|
|
39
41
|
this.#core.setProps({ visibility: this.visibility });
|
|
40
42
|
this.#core.setMedia(this.#mediaState.value ?? null);
|
|
43
|
+
this.#core.setPlayback(this.#playback.value ?? null);
|
|
41
44
|
const state = this.#core.getState();
|
|
42
45
|
if (!state) return;
|
|
43
46
|
applyStateDataAttrs(this, state, ControlsDataAttrs);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"element.js","names":[],"sources":["../../../../src/ui/controls/element.ts"],"sourcesContent":["import { ControlsCore, ControlsDataAttrs, type ControlsVisibility, POPUP_HOST_SELECTOR } from '@videojs/core';\nimport { applyStateDataAttrs, logMissingFeature, selectControls } from '@videojs/core/dom';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport { ContextProvider } from '@videojs/element/context';\nimport { isFunction } from '@videojs/utils/predicate';\n\nimport { playerContext } from '../../player/context';\nimport { PlayerController } from '../../player/controller';\nimport { UIElement } from '../ui-element';\nimport { controlsContext } from './context';\n\n/**\n * Tracks controls visibility, reflects
|
|
1
|
+
{"version":3,"file":"element.js","names":[],"sources":["../../../../src/ui/controls/element.ts"],"sourcesContent":["import { ControlsCore, ControlsDataAttrs, type ControlsVisibility, POPUP_HOST_SELECTOR } from '@videojs/core';\nimport { applyStateDataAttrs, logMissingFeature, selectControls, selectPlayback } from '@videojs/core/dom';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport { ContextProvider } from '@videojs/element/context';\nimport { isFunction } from '@videojs/utils/predicate';\n\nimport { playerContext } from '../../player/context';\nimport { PlayerController } from '../../player/controller';\nimport { UIElement } from '../ui-element';\nimport { controlsContext } from './context';\n\n/**\n * Tracks controls visibility and whether playback has started, reflects them as data attributes, and shares them with\n * its descendant controls parts. Hiding the controls closes any popup open inside it.\n */\nexport class ControlsElement extends UIElement {\n static readonly tagName = 'media-controls';\n\n static override properties = {\n visibility: { type: String },\n } satisfies PropertyDeclarationMap<'visibility'>;\n\n visibility: ControlsVisibility = ControlsCore.defaultProps.visibility;\n\n readonly #core = new ControlsCore();\n readonly #mediaState = new PlayerController(this, playerContext, selectControls);\n readonly #playback = new PlayerController(this, playerContext, selectPlayback);\n readonly #provider = new ContextProvider(this, { context: controlsContext });\n #visible = true;\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n if (__DEV__ && this.visibility === 'auto' && !this.#mediaState.value && this.#mediaState.displayName) {\n logMissingFeature(this.localName, this.#mediaState.displayName);\n }\n }\n\n protected override update(_changed: PropertyValues): void {\n super.update(_changed);\n\n this.#core.setProps({ visibility: this.visibility });\n this.#core.setMedia(this.#mediaState.value ?? null);\n this.#core.setPlayback(this.#playback.value ?? null);\n\n const state = this.#core.getState();\n if (!state) return;\n\n applyStateDataAttrs(this, state, ControlsDataAttrs);\n\n this.#provider.setValue({\n state,\n stateAttrMap: ControlsDataAttrs,\n });\n\n const wasVisible = this.#visible;\n\n this.#visible = state.visible;\n\n if (wasVisible && !state.visible) {\n this.#closeOwnedOverlays();\n }\n }\n\n #closeOwnedOverlays(): void {\n for (const element of this.querySelectorAll(POPUP_HOST_SELECTOR)) {\n const host = element as Element & { close?: unknown };\n if (!isFunction(host.close)) continue;\n\n host.close('imperative-action');\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAeA,IAAa,kBAAb,cAAqC,UAAU;;;EAOZ,KAAA,aAAA,aAAa,aAAa;EAE1C,KAAA,QAAA,IAAI,aAAa;EACX,KAAA,cAAA,IAAI,iBAAiB,MAAM,eAAe,cAAc;EAC1D,KAAA,YAAA,IAAI,iBAAiB,MAAM,eAAe,cAAc;EACxD,KAAA,YAAA,IAAI,gBAAgB,MAAM,EAAE,SAAS,gBAAgB,CAAC;EAChE,KAAA,WAAA;;;EAZe,KAAA,UAAA;;;EAEG,KAAA,aAAA,EAC3B,YAAY,EAAE,MAAM,OAAO,EAC7B;;CAIA;CACA;CACA;CACA;CACA;CAEA,oBAAmC;EACjC,MAAM,kBAAkB;EAExB,IAAe,KAAK,eAAe,UAAU,CAAC,KAAK,YAAY,SAAS,KAAK,YAAY,aACvF,kBAAkB,KAAK,WAAW,KAAK,YAAY,WAAW;CAElE;CAEA,OAA0B,UAAgC;EACxD,MAAM,OAAO,QAAQ;EAErB,KAAK,MAAM,SAAS,EAAE,YAAY,KAAK,WAAW,CAAC;EACnD,KAAK,MAAM,SAAS,KAAK,YAAY,SAAS,IAAI;EAClD,KAAK,MAAM,YAAY,KAAK,UAAU,SAAS,IAAI;EAEnD,MAAM,QAAQ,KAAK,MAAM,SAAS;EAClC,IAAI,CAAC,OAAO;EAEZ,oBAAoB,MAAM,OAAO,iBAAiB;EAElD,KAAK,UAAU,SAAS;GACtB;GACA,cAAc;EAChB,CAAC;EAED,MAAM,aAAa,KAAK;EAExB,KAAK,WAAW,MAAM;EAEtB,IAAI,cAAc,CAAC,MAAM,SACvB,KAAK,oBAAoB;CAE7B;CAEA,sBAA4B;EAC1B,KAAK,MAAM,WAAW,KAAK,iBAAiB,mBAAmB,GAAG;GAChE,MAAM,OAAO;GACb,IAAI,CAAC,WAAW,KAAK,KAAK,GAAG;GAE7B,KAAK,MAAM,mBAAmB;EAChC;CACF;AACF"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { UIElement } from "../ui-element.js";
|
|
2
|
+
import { TextTrackDefinition } from "@videojs/core";
|
|
3
|
+
import { PropertyValues } from "@videojs/element";
|
|
4
|
+
import { TextTrackFilter, TextTrackKind } from "@videojs/media";
|
|
5
|
+
//#region src/ui/time-slider/markers.d.ts
|
|
6
|
+
type TextTrackQuery = TextTrackFilter | TextTrackDefinition;
|
|
7
|
+
/**
|
|
8
|
+
* Draws a marker on the time slider for each cue on the text tracks a filter matches, such as ad breaks. Pick tracks
|
|
9
|
+
* with the `kind`, `label`, and `language` attributes, or with the `filter` property; with neither, nothing is drawn.
|
|
10
|
+
* The store reads the matching tracks while the element is connected, so tracks it doesn't read by default work too.
|
|
11
|
+
*
|
|
12
|
+
* Each marker clones the light-DOM template, which must contain exactly one HTML root element, or is a `<div>` without
|
|
13
|
+
* one. Markers are decorative: the slider's own value is what assistive technology reads.
|
|
14
|
+
*/
|
|
15
|
+
export declare class TimeSliderMarkersElement extends UIElement {
|
|
16
|
+
#private;
|
|
17
|
+
static readonly tagName = "media-time-slider-markers";
|
|
18
|
+
static properties: {
|
|
19
|
+
kind: {
|
|
20
|
+
type: StringConstructor;
|
|
21
|
+
};
|
|
22
|
+
label: {
|
|
23
|
+
type: StringConstructor;
|
|
24
|
+
};
|
|
25
|
+
language: {
|
|
26
|
+
type: StringConstructor;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
/** Draw cues from tracks of this kind. */
|
|
30
|
+
kind: TextTrackKind | null | undefined;
|
|
31
|
+
/** Draw cues from tracks with this label. */
|
|
32
|
+
label: string | null | undefined;
|
|
33
|
+
/** Draw cues from tracks in this language. */
|
|
34
|
+
language: string | null | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Picks the tracks whose cues are drawn: a filter object, a function, or a track definition. Takes priority over the
|
|
37
|
+
* `kind`, `label`, and `language` attributes. Set as a JavaScript property; it has no attribute.
|
|
38
|
+
*/
|
|
39
|
+
get filter(): TextTrackQuery | undefined;
|
|
40
|
+
set filter(value: TextTrackQuery | undefined);
|
|
41
|
+
connectedCallback(): void;
|
|
42
|
+
disconnectedCallback(): void;
|
|
43
|
+
destroyCallback(): void;
|
|
44
|
+
protected willUpdate(changed: PropertyValues): void;
|
|
45
|
+
protected update(changed: PropertyValues): void;
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
//# sourceMappingURL=markers.d.ts.map
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { playerContext } from "../../player/context.js";
|
|
2
|
+
import { PlayerController } from "../../player/controller.js";
|
|
3
|
+
import { UIElement } from "../ui-element.js";
|
|
4
|
+
import { sliderContext } from "../slider/context.js";
|
|
5
|
+
import { TimeSliderMarkerCSSVars, TimeSliderMarkerDataAttrs, TimeSliderMarkersCore, getActiveTextCues, getTextCues } from "@videojs/core";
|
|
6
|
+
import { applyStateDataAttrs, selectBuffer, selectTextCues, selectTime } from "@videojs/core/dom";
|
|
7
|
+
import { getTimeRangeEnd } from "@videojs/media";
|
|
8
|
+
import { ContextConsumer } from "@videojs/element/context";
|
|
9
|
+
import { cloneTemplateRoot, getTemplateElement, getTemplateRoot } from "@videojs/utils/dom";
|
|
10
|
+
import { isNil } from "@videojs/utils/predicate";
|
|
11
|
+
//#region src/ui/time-slider/markers.ts
|
|
12
|
+
/**
|
|
13
|
+
* Draws a marker on the time slider for each cue on the text tracks a filter matches, such as ad breaks. Pick tracks
|
|
14
|
+
* with the `kind`, `label`, and `language` attributes, or with the `filter` property; with neither, nothing is drawn.
|
|
15
|
+
* The store reads the matching tracks while the element is connected, so tracks it doesn't read by default work too.
|
|
16
|
+
*
|
|
17
|
+
* Each marker clones the light-DOM template, which must contain exactly one HTML root element, or is a `<div>` without
|
|
18
|
+
* one. Markers are decorative: the slider's own value is what assistive technology reads.
|
|
19
|
+
*/
|
|
20
|
+
var TimeSliderMarkersElement = class extends UIElement {
|
|
21
|
+
static {
|
|
22
|
+
this.tagName = "media-time-slider-markers";
|
|
23
|
+
}
|
|
24
|
+
static {
|
|
25
|
+
this.properties = {
|
|
26
|
+
kind: { type: String },
|
|
27
|
+
label: { type: String },
|
|
28
|
+
language: { type: String }
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
#core = new TimeSliderMarkersCore();
|
|
32
|
+
#slider = new ContextConsumer(this, {
|
|
33
|
+
context: sliderContext,
|
|
34
|
+
subscribe: true
|
|
35
|
+
});
|
|
36
|
+
#textCues = new PlayerController(this, playerContext, selectTextCues);
|
|
37
|
+
#time = new PlayerController(this, playerContext, selectTime);
|
|
38
|
+
#buffer = new PlayerController(this, playerContext, selectBuffer);
|
|
39
|
+
#rendered = /* @__PURE__ */ new Map();
|
|
40
|
+
#filter;
|
|
41
|
+
#attributeFilter;
|
|
42
|
+
#watching = null;
|
|
43
|
+
#templateRoot = null;
|
|
44
|
+
#templateChecked = false;
|
|
45
|
+
/**
|
|
46
|
+
* Picks the tracks whose cues are drawn: a filter object, a function, or a track definition. Takes priority over the
|
|
47
|
+
* `kind`, `label`, and `language` attributes. Set as a JavaScript property; it has no attribute.
|
|
48
|
+
*/
|
|
49
|
+
get filter() {
|
|
50
|
+
return this.#filter;
|
|
51
|
+
}
|
|
52
|
+
set filter(value) {
|
|
53
|
+
this.#filter = value;
|
|
54
|
+
this.requestUpdate();
|
|
55
|
+
}
|
|
56
|
+
connectedCallback() {
|
|
57
|
+
super.connectedCallback();
|
|
58
|
+
this.setAttribute("aria-hidden", "true");
|
|
59
|
+
}
|
|
60
|
+
disconnectedCallback() {
|
|
61
|
+
this.#unwatch();
|
|
62
|
+
super.disconnectedCallback();
|
|
63
|
+
}
|
|
64
|
+
destroyCallback() {
|
|
65
|
+
this.#unwatch();
|
|
66
|
+
super.destroyCallback();
|
|
67
|
+
}
|
|
68
|
+
willUpdate(changed) {
|
|
69
|
+
super.willUpdate(changed);
|
|
70
|
+
if (changed.has("kind") || changed.has("label") || changed.has("language")) this.#attributeFilter = this.#getAttributeFilter();
|
|
71
|
+
this.#watch(this.#getFilter());
|
|
72
|
+
}
|
|
73
|
+
update(changed) {
|
|
74
|
+
super.update(changed);
|
|
75
|
+
const slider = this.#slider.value;
|
|
76
|
+
const templateRoot = this.#getTemplateRoot();
|
|
77
|
+
if (!slider) return;
|
|
78
|
+
applyStateDataAttrs(this, slider.state, slider.stateAttrMap);
|
|
79
|
+
const filter = this.#getFilter();
|
|
80
|
+
const textCues = this.#textCues.value;
|
|
81
|
+
const time = this.#time.value;
|
|
82
|
+
const max = getTimeRangeEnd({
|
|
83
|
+
duration: time?.duration ?? 0,
|
|
84
|
+
seekable: this.#buffer.value?.seekable ?? []
|
|
85
|
+
});
|
|
86
|
+
const markers = filter && textCues ? this.#core.getMarkers({
|
|
87
|
+
cues: getTextCues(textCues, filter),
|
|
88
|
+
activeCues: getActiveTextCues(textCues, filter),
|
|
89
|
+
min: 0,
|
|
90
|
+
max,
|
|
91
|
+
orientation: slider.state.orientation
|
|
92
|
+
}) : [];
|
|
93
|
+
const next = /* @__PURE__ */ new Map();
|
|
94
|
+
for (const marker of markers) {
|
|
95
|
+
const root = this.#rendered.get(marker.key) ?? this.#createMarker(templateRoot);
|
|
96
|
+
root.style.setProperty(TimeSliderMarkerCSSVars.start, marker.startPercent);
|
|
97
|
+
root.style.setProperty(TimeSliderMarkerCSSVars.end, marker.endPercent);
|
|
98
|
+
root.style.setProperty(TimeSliderMarkerCSSVars.width, marker.width ?? marker.height ?? "0%");
|
|
99
|
+
applyStateDataAttrs(root, slider.state, slider.stateAttrMap);
|
|
100
|
+
applyStateDataAttrs(root, marker, TimeSliderMarkerDataAttrs);
|
|
101
|
+
next.set(marker.key, root);
|
|
102
|
+
}
|
|
103
|
+
for (const [key, root] of this.#rendered) if (!next.has(key)) root.remove();
|
|
104
|
+
let before = null;
|
|
105
|
+
for (const root of [...next.values()].reverse()) {
|
|
106
|
+
if (root.parentNode !== this || root.nextSibling !== before) this.insertBefore(root, before);
|
|
107
|
+
before = root;
|
|
108
|
+
}
|
|
109
|
+
this.#rendered.clear();
|
|
110
|
+
for (const [key, rendered] of next) this.#rendered.set(key, rendered);
|
|
111
|
+
}
|
|
112
|
+
#getFilter() {
|
|
113
|
+
return this.#filter ?? this.#attributeFilter;
|
|
114
|
+
}
|
|
115
|
+
/** A filter from the attributes that are present, or none when no attribute is. */
|
|
116
|
+
#getAttributeFilter() {
|
|
117
|
+
const { kind, label, language } = this;
|
|
118
|
+
if (isNil(kind) && isNil(label) && isNil(language)) return void 0;
|
|
119
|
+
return {
|
|
120
|
+
kind: kind ?? void 0,
|
|
121
|
+
label: label ?? void 0,
|
|
122
|
+
language: language ?? void 0
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/** Ask the store to read the tracks the filter matches while the element is connected. */
|
|
126
|
+
#watch(filter) {
|
|
127
|
+
const watch = this.isConnected ? this.#textCues.value?.watchTextCues : void 0;
|
|
128
|
+
if (this.#watching?.watch === watch && this.#watching?.filter === filter) return;
|
|
129
|
+
this.#unwatch();
|
|
130
|
+
if (watch && filter) this.#watching = {
|
|
131
|
+
watch,
|
|
132
|
+
filter,
|
|
133
|
+
stop: watch(filter)
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
#unwatch() {
|
|
137
|
+
this.#watching?.stop();
|
|
138
|
+
this.#watching = null;
|
|
139
|
+
}
|
|
140
|
+
#createMarker(templateRoot) {
|
|
141
|
+
return templateRoot ? cloneTemplateRoot(templateRoot, this.ownerDocument) : this.ownerDocument.createElement("div");
|
|
142
|
+
}
|
|
143
|
+
/** The template's root, found once; until there is a template, other content is cleared and markers are `<div>`s. */
|
|
144
|
+
#getTemplateRoot() {
|
|
145
|
+
if (this.#templateChecked) return this.#templateRoot;
|
|
146
|
+
const template = getTemplateElement(this);
|
|
147
|
+
const rendered = new Set(this.#rendered.values());
|
|
148
|
+
for (const node of [...this.childNodes]) if (node !== template && !rendered.has(node)) node.remove();
|
|
149
|
+
if (!template) return null;
|
|
150
|
+
this.#templateChecked = true;
|
|
151
|
+
for (const node of rendered) node.remove();
|
|
152
|
+
this.#rendered.clear();
|
|
153
|
+
const root = getTemplateRoot(template);
|
|
154
|
+
if (root?.namespaceURI !== "http://www.w3.org/1999/xhtml") {
|
|
155
|
+
console.warn(`[${this.localName}] template must contain exactly one HTML root element.`);
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
this.#templateRoot = root;
|
|
159
|
+
return this.#templateRoot;
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
//#endregion
|
|
163
|
+
export { TimeSliderMarkersElement };
|
|
164
|
+
|
|
165
|
+
//# sourceMappingURL=markers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markers.js","names":[],"sources":["../../../../src/ui/time-slider/markers.ts"],"sourcesContent":["import {\n getActiveTextCues,\n getTextCues,\n type TextTrackDefinition,\n TimeSliderMarkerCSSVars,\n TimeSliderMarkerDataAttrs,\n TimeSliderMarkersCore,\n} from '@videojs/core';\nimport { applyStateDataAttrs, selectBuffer, selectTextCues, selectTime } from '@videojs/core/dom';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport { ContextConsumer } from '@videojs/element/context';\nimport { getTimeRangeEnd, type TextTrackFilter, type TextTrackKind } from '@videojs/media';\nimport { cloneTemplateRoot, getTemplateElement, getTemplateRoot } from '@videojs/utils/dom';\nimport { isNil } from '@videojs/utils/predicate';\n\nimport { playerContext } from '../../player/context';\nimport { PlayerController } from '../../player/controller';\nimport { sliderContext } from '../slider/context';\nimport { UIElement } from '../ui-element';\n\ntype TextTrackQuery = TextTrackFilter | TextTrackDefinition;\n\ninterface TextCuesWatch {\n watch: (filter: TextTrackFilter) => () => void;\n filter: TextTrackQuery;\n stop: () => void;\n}\n\n/**\n * Draws a marker on the time slider for each cue on the text tracks a filter matches, such as ad breaks. Pick tracks\n * with the `kind`, `label`, and `language` attributes, or with the `filter` property; with neither, nothing is drawn.\n * The store reads the matching tracks while the element is connected, so tracks it doesn't read by default work too.\n *\n * Each marker clones the light-DOM template, which must contain exactly one HTML root element, or is a `<div>` without\n * one. Markers are decorative: the slider's own value is what assistive technology reads.\n */\nexport class TimeSliderMarkersElement extends UIElement {\n static readonly tagName = 'media-time-slider-markers';\n\n static override properties = {\n kind: { type: String },\n label: { type: String },\n language: { type: String },\n } satisfies PropertyDeclarationMap<'kind' | 'label' | 'language'>;\n\n /** Draw cues from tracks of this kind. */\n kind: TextTrackKind | null | undefined;\n /** Draw cues from tracks with this label. */\n label: string | null | undefined;\n /** Draw cues from tracks in this language. */\n language: string | null | undefined;\n\n readonly #core = new TimeSliderMarkersCore();\n readonly #slider = new ContextConsumer(this, { context: sliderContext, subscribe: true });\n readonly #textCues = new PlayerController(this, playerContext, selectTextCues);\n readonly #time = new PlayerController(this, playerContext, selectTime);\n readonly #buffer = new PlayerController(this, playerContext, selectBuffer);\n readonly #rendered = new Map<string, HTMLElement>();\n #filter: TextTrackQuery | undefined;\n #attributeFilter: TextTrackFilter | undefined;\n #watching: TextCuesWatch | null = null;\n #templateRoot: HTMLElement | null = null;\n #templateChecked = false;\n\n /**\n * Picks the tracks whose cues are drawn: a filter object, a function, or a track definition. Takes priority over the\n * `kind`, `label`, and `language` attributes. Set as a JavaScript property; it has no attribute.\n */\n get filter(): TextTrackQuery | undefined {\n return this.#filter;\n }\n\n set filter(value: TextTrackQuery | undefined) {\n this.#filter = value;\n this.requestUpdate();\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.setAttribute('aria-hidden', 'true');\n }\n\n override disconnectedCallback(): void {\n this.#unwatch();\n super.disconnectedCallback();\n }\n\n override destroyCallback(): void {\n this.#unwatch();\n super.destroyCallback();\n }\n\n protected override willUpdate(changed: PropertyValues): void {\n super.willUpdate(changed);\n\n if (changed.has('kind') || changed.has('label') || changed.has('language')) {\n this.#attributeFilter = this.#getAttributeFilter();\n }\n\n this.#watch(this.#getFilter());\n }\n\n protected override update(changed: PropertyValues): void {\n super.update(changed);\n\n const slider = this.#slider.value;\n const templateRoot = this.#getTemplateRoot();\n\n if (!slider) return;\n\n applyStateDataAttrs(this, slider.state, slider.stateAttrMap);\n\n const filter = this.#getFilter();\n const textCues = this.#textCues.value;\n const time = this.#time.value;\n const max = getTimeRangeEnd({ duration: time?.duration ?? 0, seekable: this.#buffer.value?.seekable ?? [] });\n\n const markers =\n filter && textCues\n ? this.#core.getMarkers({\n cues: getTextCues(textCues, filter),\n activeCues: getActiveTextCues(textCues, filter),\n min: 0,\n max,\n orientation: slider.state.orientation,\n })\n : [];\n\n const next = new Map<string, HTMLElement>();\n\n for (const marker of markers) {\n const root = this.#rendered.get(marker.key) ?? this.#createMarker(templateRoot);\n\n root.style.setProperty(TimeSliderMarkerCSSVars.start, marker.startPercent);\n root.style.setProperty(TimeSliderMarkerCSSVars.end, marker.endPercent);\n root.style.setProperty(TimeSliderMarkerCSSVars.width, marker.width ?? marker.height ?? '0%');\n applyStateDataAttrs(root, slider.state, slider.stateAttrMap);\n applyStateDataAttrs(root, marker, TimeSliderMarkerDataAttrs);\n\n next.set(marker.key, root);\n }\n\n for (const [key, root] of this.#rendered) {\n if (!next.has(key)) root.remove();\n }\n\n let before: ChildNode | null = null;\n\n for (const root of [...next.values()].reverse()) {\n if (root.parentNode !== this || root.nextSibling !== before) this.insertBefore(root, before);\n\n before = root;\n }\n\n this.#rendered.clear();\n\n for (const [key, rendered] of next) this.#rendered.set(key, rendered);\n }\n\n #getFilter(): TextTrackQuery | undefined {\n return this.#filter ?? this.#attributeFilter;\n }\n\n /** A filter from the attributes that are present, or none when no attribute is. */\n #getAttributeFilter(): TextTrackFilter | undefined {\n const { kind, label, language } = this;\n if (isNil(kind) && isNil(label) && isNil(language)) return undefined;\n\n return { kind: kind ?? undefined, label: label ?? undefined, language: language ?? undefined };\n }\n\n /** Ask the store to read the tracks the filter matches while the element is connected. */\n #watch(filter: TextTrackQuery | undefined): void {\n const watch = this.isConnected ? this.#textCues.value?.watchTextCues : undefined;\n if (this.#watching?.watch === watch && this.#watching?.filter === filter) return;\n\n this.#unwatch();\n\n if (watch && filter) this.#watching = { watch, filter, stop: watch(filter) };\n }\n\n #unwatch(): void {\n this.#watching?.stop();\n this.#watching = null;\n }\n\n #createMarker(templateRoot: HTMLElement | null): HTMLElement {\n return templateRoot ? cloneTemplateRoot(templateRoot, this.ownerDocument) : this.ownerDocument.createElement('div');\n }\n\n /** The template's root, found once; until there is a template, other content is cleared and markers are `<div>`s. */\n #getTemplateRoot(): HTMLElement | null {\n if (this.#templateChecked) return this.#templateRoot;\n\n const template = getTemplateElement(this);\n const rendered = new Set<ChildNode>(this.#rendered.values());\n\n for (const node of [...this.childNodes]) {\n if (node !== template && !rendered.has(node)) node.remove();\n }\n\n if (!template) return null;\n\n this.#templateChecked = true;\n\n // Markers drawn before the template arrived are redrawn from it.\n for (const node of rendered) node.remove();\n\n this.#rendered.clear();\n\n const root = getTemplateRoot(template);\n\n if (root?.namespaceURI !== 'http://www.w3.org/1999/xhtml') {\n if (__DEV__) {\n console.warn(`[${this.localName}] template must contain exactly one HTML root element.`);\n }\n\n return null;\n }\n\n // SAFETY: the root was just checked to be in the XHTML namespace, so it is an HTML element.\n this.#templateRoot = root as HTMLElement;\n return this.#templateRoot;\n }\n}\n"],"mappings":"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"}
|
package/dist/dev/version.js
CHANGED
package/docs/README.md
CHANGED
package/docs/guides/autoplay.md
CHANGED
|
@@ -106,7 +106,7 @@ Calling `play()` from player state returns the native promise from the media ele
|
|
|
106
106
|
|
|
107
107
|
Use `<background-video>` for an MP4 or WebM file, `<hls-background-video>` for an HLS stream, or `<mux-background-video>` for a complete Mux HLS URL.
|
|
108
108
|
|
|
109
|
-
These components default to muted, looping playback without player controls. Provide a separate motion control and respect reduced-motion preferences. For setup and motion controls, follow [Add a background video](./background-video.md). That guide also covers streaming backgrounds, which
|
|
109
|
+
These components default to muted, looping playback without player controls. Provide a separate motion control and respect reduced-motion preferences. For setup and motion controls, follow [Add a background video](./background-video.md). That guide also covers streaming backgrounds, which use the same pause and play pattern.
|
|
110
110
|
|
|
111
111
|
### Autoplay with sound
|
|
112
112
|
|
|
@@ -190,7 +190,7 @@ Set size, position, and transforms on the decorative wrapper so the poster and v
|
|
|
190
190
|
- Use a source the browser can play directly, such as MP4 or WebM.
|
|
191
191
|
- Safari can play HLS URLs directly. Other browsers cannot do so reliably, so use an HLS variation below when the same `.m3u8` URL must work across browsers.
|
|
192
192
|
- `<background-video>` does not create a poster or report analytics. Keep the poster in your page and add analytics only when you need them.
|
|
193
|
-
- Provide a way to pause or hide persistent background motion. The example includes that control and follows `prefers-reduced-motion`.
|
|
193
|
+
- Provide a way to pause or hide persistent background motion. The example includes that control and follows `prefers-reduced-motion`. The streaming variations below pause and play through the same `target` property.
|
|
194
194
|
- If the video communicates information, remove `aria-hidden`, give it an accessible name and controls, and use a regular video player.
|
|
195
195
|
|
|
196
196
|
## Common variations
|
|
@@ -202,9 +202,7 @@ Choose a variation based on the source you already have:
|
|
|
202
202
|
| Cross-browser HLS with a small background-only player | [`<hls-background-video>`](../reference/components/hls-background-video.md) |
|
|
203
203
|
| The same background-only player for a Mux HLS URL | [`<mux-background-video>`](../reference/components/mux-background-video.md) |
|
|
204
204
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
Keep the poster and motion button from the primary example. Change `setMotion` to create and append a streaming element only when motion is enabled, and remove it when motion is disabled. Do not set `keep-alive`: removal must destroy playback. Create a new element each time motion is enabled; do not reuse the removed one. These elements expose the inner video as `video`, rather than the native background element’s `target`.
|
|
205
|
+
The primary example works unchanged with the streaming elements: replace `<background-video>` with `<hls-background-video>` or `<mux-background-video>`, keep `noautoplay`, and update the selector in the script. Like `<background-video>`, they expose the native video as `target` for `play()` and `pause()`. Pausing keeps the stream and its position, so motion resumes where it stopped. To stop network activity as well, remove the element instead. Without `keep-alive`, removal releases the engine.
|
|
208
206
|
|
|
209
207
|
### Play an HLS video
|
|
210
208
|
|
|
@@ -2,25 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
Browsers and rendering environments supported by Video.js 10, and how the packaged skins reach them
|
|
4
4
|
|
|
5
|
-
*Supported browsers
|
|
5
|
+
*Supported browsers, the versions of each that Video.js supports, and the older versions the Compat skin also reaches*
|
|
6
6
|
|
|
7
|
-
| Browser | Versions |
|
|
8
|
-
| --- | --- |
|
|
9
|
-
| Chrome | 111 and later |
|
|
10
|
-
| Edge | 111 and later |
|
|
11
|
-
| Firefox | 121 and later |
|
|
12
|
-
| Safari | 16.4 and later |
|
|
13
|
-
| Safari on iOS | 16.4 and later |
|
|
7
|
+
| Browser | Versions | Compat skin |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| Chrome | 111 and later | 99 and later |
|
|
10
|
+
| Edge | 111 and later | 99 and later |
|
|
11
|
+
| Firefox | 121 and later | 97 and later |
|
|
12
|
+
| Safari | 16.4 and later | 15.4 and later |
|
|
13
|
+
| Safari on iOS | 16.4 and later | 15.4 and later |
|
|
14
14
|
|
|
15
|
-
These versions account for 92.5% of global web usage according to [caniuse-lite](https://github.com/browserslist/caniuse-lite) 1.0.30001815, and
|
|
15
|
+
These versions account for 92.5% of global web usage according to [caniuse-lite](https://github.com/browserslist/caniuse-lite) 1.0.30001815, and the Compat versions account for 94.4%. These figures update when we update that data.
|
|
16
16
|
|
|
17
|
-
We test in and fix bugs for
|
|
17
|
+
We test in and fix bugs for the main versions. Each of those minimums comes from a feature with no fallback: `:has()` sets Firefox, [`color-mix()`](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-mix) and [`oklch()`](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch) set Chrome and Edge (Chrome 111, Firefox 113, Safari 16.2), and the JavaScript sets Safari, because it uses ES2022 syntax and [`adoptedStyleSheets`](https://developer.mozilla.org/en-US/docs/Web/API/Document/adoptedStyleSheets). Newer JavaScript APIs are feature-detected.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
The [Compat skin](./skins.md#choose-a-skin) also reaches the older versions in the last column. It leaves out backdrop blur, anchor-positioned menu highlights, and squircle corners, and its stylesheets fall back to plain colors where `color-mix()` and `oklch()` are missing. Below the main versions, it keeps its narrow layout and default size, because container queries and media query ranges are missing, and the time slider preview stays hidden on keyboard focus. Every build checks its stylesheets against these older versions, and our browser tests run at the main versions.
|
|
20
|
+
|
|
21
|
+
The Scaffold skin, a starting point for your own design, reaches the same older versions.
|
|
22
|
+
|
|
23
|
+
The HTML player’s JavaScript needs Firefox 101 and Safari 16.4, so with HTML the Compat skin reaches Chrome and Edge 99, Firefox 101, and Safari 16.4.
|
|
24
|
+
|
|
25
|
+
The older versions apply to the packaged skins. Tailwind skins follow Tailwind’s own browser support, and registry skins in plain CSS need `@scope` unless you [flatten it](#flatten-scope-in-registry-skins). If your build lowers CSS for its own targets, include these older versions in them, or it may rewrite the fallbacks.
|
|
20
26
|
|
|
21
27
|
## CSS requirements
|
|
22
28
|
|
|
23
|
-
The packaged skins are generated CSS, and the build lowers them for the
|
|
29
|
+
The packaged skins are generated CSS, and the build lowers them for the main versions above. It flattens CSS nesting, adds vendor prefixes such as `-webkit-backdrop-filter`, and writes each skin’s scope as a [`:where()`](https://developer.mozilla.org/en-US/docs/Web/CSS/:where) selector, which adds no specificity, rather than [`@scope`](https://developer.mozilla.org/en-US/docs/Web/CSS/@scope).
|
|
24
30
|
|
|
25
31
|
Skins you add as source through the [Shadcn registry](./installation-shadcn.md) keep `@scope`, which reads more clearly in files you edit. Their plain CSS versions need Chrome and Edge 118, Firefox 146, and Safari and iOS 17.4 unless you [flatten `@scope` in your build](#flatten-scope-in-registry-skins); the Tailwind versions style elements with utility classes and follow the versions above.
|
|
26
32
|
|
|
@@ -40,16 +46,16 @@ The table reads the first fully supporting version of each feature from [caniuse
|
|
|
40
46
|
| --- | --- | --- | --- | --- |
|
|
41
47
|
| [`@scope`](https://caniuse.com/css-cascade-scope) Has a fallback. Packaged skins use :where() selectors instead; registry CSS skins need it. | 118 | 146 | 17.4 | 91.7% |
|
|
42
48
|
| [`@layer`](https://caniuse.com/css-cascade-layers) Required. No component styling. | 99 | 97 | 15.4 | 96.0% |
|
|
43
|
-
| [`:has()`](https://caniuse.com/css-has) Required. Menu and slider focus states are lost. | 105 | 121 | 15.4 | 94.8% |
|
|
44
|
-
| [`@container`](https://caniuse.com/css-container-queries) Required. Controls do not adapt to player width. | 106 | 110 | 16 | 94.8% |
|
|
49
|
+
| [`:has()`](https://caniuse.com/css-has) Required. Menu and slider focus states are lost. Compat loses only the time slider preview on keyboard focus. | 105 | 121 | 15.4 | 94.8% |
|
|
50
|
+
| [`@container`](https://caniuse.com/css-container-queries) Required. Controls do not adapt to player width. Compat keeps its narrow layout, without the center controls or the duration. | 106 | 110 | 16 | 94.8% |
|
|
45
51
|
| [`Media query range syntax`](https://caniuse.com/css-media-range-syntax) Required. Large-screen sizing is lost. | 104 | 63 | 16.4 | 94.8% |
|
|
46
52
|
| [`:dir()`](https://caniuse.com/css-dir-pseudo) Has a fallback. Right-to-left layout follows the dir attribute instead. | 120 | 17 | 16.4 | 92.5% |
|
|
47
53
|
| [`Relative color syntax`](https://caniuse.com/css-relative-colors) Degrades. Control scrims fall back to color-mix(), and subtle shadows are lost. | 131 | 133 | 18 | 87.0% |
|
|
48
54
|
| [`scrollbar-color and scrollbar-width`](https://caniuse.com/css-scrollbar) Degrades. Menus show default scrollbars. | 121 | 64 | 26.2 | 87.0% |
|
|
49
|
-
| [`backdrop-filter`](https://caniuse.com/css-backdrop-filter) Degrades. Surfaces lose their blur. | 76 / 17 | 103 | 9 | 96.4% |
|
|
55
|
+
| [`backdrop-filter`](https://caniuse.com/css-backdrop-filter) Degrades. Surfaces lose their blur. Compat does not use it. | 76 / 17 | 103 | 9 | 96.4% |
|
|
50
56
|
| [`Anchor positioning`](https://caniuse.com/css-anchor-positioning) Has a fallback. Popups are positioned by JavaScript. | Not supported | Not supported | 27 | 0.0% |
|
|
51
57
|
|
|
52
|
-
|
|
58
|
+
Below the main versions, only the Compat and Scaffold skins are supported. Without `:has()`, `@container`, `@layer`, `color-mix()`, or `oklch()`, the Default and Neutral skins lose focus states, layout, or colors.
|
|
53
59
|
|
|
54
60
|
## Build the skin CSS yourself
|
|
55
61
|
|
package/docs/guides/cdn.md
CHANGED
|
@@ -37,8 +37,8 @@ A skin bundle registers every UI element its skin is built from. Any element the
|
|
|
37
37
|
Each [UI element](./ui-components.md) is its own bundle under `ui/`, for markup that a skin bundle does not already cover: a player-only bundle, [skin source](./customize-skins.md#style-skin-source) that adds a component the packaged skin lacks, or a [dialog](../reference/components/dialog.md) your page opens beside a packaged skin.
|
|
38
38
|
|
|
39
39
|
```html
|
|
40
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.
|
|
41
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.
|
|
40
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.4.0/video-player.js"></script>
|
|
41
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.4.0/ui/play-button.js"></script>
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
Each path mirrors its npm subpath: `ui/play-button.js` registers the element that `@videojs/html/ui/play-button` does. Compound components list one bundle per part in their reference page’s Import section, and all of the bundles share chunks with the player.
|
|
@@ -48,8 +48,8 @@ Each path mirrors its npm subpath: `ui/play-button.js` registers the element tha
|
|
|
48
48
|
The default presets play through the browser’s own `<video>` and `<audio>`. Every other [media component](./media-sources.md) is its own bundle under `media/`, loaded beside the player bundle:
|
|
49
49
|
|
|
50
50
|
```html
|
|
51
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.
|
|
52
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.
|
|
51
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.4.0/video.js"></script>
|
|
52
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.4.0/media/hlsjs-video.js"></script>
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
Each path mirrors its npm subpath. Elements with more than one playback engine keep the extra flavors in a directory named for the element, such as `media/mux-video/spf.js`. Load one flavor per page: every flavor claims the same tag name, and the first registration wins.
|
|
@@ -59,9 +59,9 @@ Each path mirrors its npm subpath. Elements with more than one playback engine k
|
|
|
59
59
|
Each [extension](./architecture.md) is its own bundle under `extensions/`, loaded beside the player and media bundles:
|
|
60
60
|
|
|
61
61
|
```html
|
|
62
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.
|
|
63
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.
|
|
64
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.
|
|
62
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.4.0/video.js"></script>
|
|
63
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.4.0/media/mux-video.js"></script>
|
|
64
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.4.0/extensions/mux-data.js"></script>
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
As with media, each path mirrors its npm subpath: `extensions/mux-data.js` registers the element that `@videojs/html/extensions/mux-data` does.
|
|
@@ -71,8 +71,8 @@ As with media, each path mirrors its npm subpath: `extensions/mux-data.js` regis
|
|
|
71
71
|
English ships inside the skin bundles. Each other locale is a bundle under `locales/` that registers its translations on import. Load it before the player script to avoid a flash of English:
|
|
72
72
|
|
|
73
73
|
```html
|
|
74
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.
|
|
75
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.
|
|
74
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.4.0/locales/es.js"></script>
|
|
75
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.4.0/video.js"></script>
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
One bundle exists per locale pack, plus bare-language aliases such as `pt`. For custom strings, see [Internationalize the player](./internationalization.md).
|
|
@@ -31,6 +31,7 @@ Packaged skins expose [CSS custom properties](https://developer.mozilla.org/en-U
|
|
|
31
31
|
| `--media-accent-text-color` | Text and icons shown on the accent color | [`<color>`](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value) | `black` |
|
|
32
32
|
| `--media-border-color` | The hairline around the player | [`<color>`](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value) | `transparent` |
|
|
33
33
|
| `--media-border-radius` | The player corner radius | A valid [border-radius value](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/border-radius#values) | `1rem` |
|
|
34
|
+
| `--media-controls-before-start` | Whether the video skins show their controls before playback starts | `hidden` (default) or `visible` | `visible` |
|
|
34
35
|
| `--media-font-family` | The player interface font stack | A valid [font-family value](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/font-family) | `Roboto, sans-serif` |
|
|
35
36
|
| `--media-object-fit` | How the media and poster fill the player | A valid [object-fit value](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/object-fit) | `cover` |
|
|
36
37
|
| `--media-object-position` | Where the media and poster sit when they do not fill the player | A valid [object-position value](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/object-position) | `top` |
|
|
@@ -40,6 +41,8 @@ If you omit `--media-accent-text-color`, the skins choose a contrasting text col
|
|
|
40
41
|
|
|
41
42
|
The skins use [`Inter`](https://rsms.me/inter/) when your page loads it and fall back to the system UI font. Video.js does not load the webfont for you. Set `--media-font-family` to use another font. The Scaffold skin inherits your page’s font instead, and it has no hairline, so `--media-border-color` doesn’t change it.
|
|
42
43
|
|
|
44
|
+
Before playback starts, the video and live video skins show only the large center play button. The controls appear once playback starts or the media begins to autoplay. Set `--media-controls-before-start: visible` to show the controls from the start, for example so viewers can pick captions or quality before they press play.
|
|
45
|
+
|
|
43
46
|
The media component and poster share `--media-object-fit` and `--media-object-position`, so a `cover` poster stays aligned with `cover` video. See [Add a poster and loading placeholder](./poster.md).
|
|
44
47
|
|
|
45
48
|
### Set the color scheme
|
|
@@ -89,7 +89,7 @@ Defaulted options: project, preset, skin, source-url, media, extensions, templat
|
|
|
89
89
|
## Reproduce or change these instructions
|
|
90
90
|
|
|
91
91
|
```sh
|
|
92
|
-
npx @videojs/cli@10.
|
|
92
|
+
npx @videojs/cli@10.4.0 agents init --method cdn --framework html --project existing --preset video --skin default --media html5-video --extensions none --source-url https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4 --template none
|
|
93
93
|
```
|
|
94
94
|
|
|
95
95
|
## Load Video.js
|
|
@@ -101,7 +101,7 @@ Add these module scripts to the page head. Module scripts are deferred, so they
|
|
|
101
101
|
_Merge this into the page `<head>`._
|
|
102
102
|
|
|
103
103
|
```html
|
|
104
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.
|
|
104
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.4.0/video.js"></script>
|
|
105
105
|
```
|
|
106
106
|
|
|
107
107
|
## Add your player
|
|
@@ -94,7 +94,7 @@ Defaulted options: project, preset, skin, source-url, media, extensions, templat
|
|
|
94
94
|
## Reproduce or change these instructions
|
|
95
95
|
|
|
96
96
|
```sh
|
|
97
|
-
npx @videojs/cli@10.
|
|
97
|
+
npx @videojs/cli@10.4.0 agents init --method shadcn --framework html --project existing --preset video --skin default --media html5-video --extensions none --source-url https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4 --package-manager pnpm --template vite --styling css
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
## Configure app aliases
|
|
@@ -90,13 +90,13 @@ Defaulted options: project, preset, skin, source-url, media, extensions, templat
|
|
|
90
90
|
## Reproduce or change these instructions
|
|
91
91
|
|
|
92
92
|
```sh
|
|
93
|
-
npx @videojs/cli@10.
|
|
93
|
+
npx @videojs/cli@10.4.0 agents init --method packaged --framework svelte --project existing --preset video --skin default --media html5-video --extensions none --source-url https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4 --package-manager pnpm --template vite
|
|
94
94
|
```
|
|
95
95
|
|
|
96
96
|
## Install the packages
|
|
97
97
|
|
|
98
98
|
```bash
|
|
99
|
-
pnpm add @videojs/html@10.
|
|
99
|
+
pnpm add @videojs/html@10.4.0
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
## Add your player
|
|
@@ -90,13 +90,13 @@ Defaulted options: project, preset, skin, source-url, media, extensions, templat
|
|
|
90
90
|
## Reproduce or change these instructions
|
|
91
91
|
|
|
92
92
|
```sh
|
|
93
|
-
npx @videojs/cli@10.
|
|
93
|
+
npx @videojs/cli@10.4.0 agents init --method packaged --framework vue --project existing --preset video --skin default --media html5-video --extensions none --source-url https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4 --package-manager pnpm --template vite
|
|
94
94
|
```
|
|
95
95
|
|
|
96
96
|
## Install the packages
|
|
97
97
|
|
|
98
98
|
```bash
|
|
99
|
-
pnpm add @videojs/html@10.
|
|
99
|
+
pnpm add @videojs/html@10.4.0
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
## Register custom elements
|
|
@@ -92,13 +92,13 @@ Defaulted options: project, preset, skin, source-url, media, extensions, templat
|
|
|
92
92
|
## Reproduce or change these instructions
|
|
93
93
|
|
|
94
94
|
```sh
|
|
95
|
-
npx @videojs/cli@10.
|
|
95
|
+
npx @videojs/cli@10.4.0 agents init --method packaged --framework html --project existing --preset video --skin default --media html5-video --extensions none --source-url https://stream.mux.com/BV3YZtogl89mg9VcNBhhnHm02Y34zI1nlMuMQfAbl3dM/highest.mp4 --package-manager pnpm --template vite
|
|
96
96
|
```
|
|
97
97
|
|
|
98
98
|
## Install the packages
|
|
99
99
|
|
|
100
100
|
```bash
|
|
101
|
-
pnpm add @videojs/html@10.
|
|
101
|
+
pnpm add @videojs/html@10.4.0
|
|
102
102
|
```
|
|
103
103
|
|
|
104
104
|
## Add your player
|
|
@@ -199,8 +199,8 @@ import '@videojs/html/i18n/locales/ja/register';
|
|
|
199
199
|
CDN locale modules call `registerI18n` on import. Pin every URL to the same version:
|
|
200
200
|
|
|
201
201
|
```html
|
|
202
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.
|
|
203
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.
|
|
202
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.4.0/locales/es.js"></script>
|
|
203
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.4.0/video.js"></script>
|
|
204
204
|
```
|
|
205
205
|
|
|
206
206
|
Use the same pinned version for your locale pack, `i18n.js`, and player script. Copies loaded in the same window share a registry; matching versions keeps their translation keys and APIs compatible. Import the full locale pack before partial overrides, and register before the player loads to translate the first render:
|
|
@@ -208,15 +208,15 @@ Use the same pinned version for your locale pack, `i18n.js`, and player script.
|
|
|
208
208
|
**my-locale.js**
|
|
209
209
|
|
|
210
210
|
```js
|
|
211
|
-
import 'https://cdn.jsdelivr.net/npm/@videojs/cdn@10.
|
|
212
|
-
import { registerI18n } from 'https://cdn.jsdelivr.net/npm/@videojs/cdn@10.
|
|
211
|
+
import 'https://cdn.jsdelivr.net/npm/@videojs/cdn@10.4.0/locales/es.js';
|
|
212
|
+
import { registerI18n } from 'https://cdn.jsdelivr.net/npm/@videojs/cdn@10.4.0/i18n.js';
|
|
213
213
|
|
|
214
214
|
registerI18n('es', { buttons: { play: 'Reproducir', pause: 'Pausa' } });
|
|
215
215
|
```
|
|
216
216
|
|
|
217
217
|
```html
|
|
218
218
|
<script type="module" src="/my-locale.js"></script>
|
|
219
|
-
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.
|
|
219
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@videojs/cdn@10.4.0/video.js"></script>
|
|
220
220
|
```
|
|
221
221
|
|
|
222
222
|
### Switch locale at runtime
|
|
@@ -73,6 +73,16 @@ How the container splits into regions depends on which regions you bind for the
|
|
|
73
73
|
|
|
74
74
|
For a packaged skin, [add the skin source to your project](./customize-skins.md#style-skin-source) and edit its `<media-hotkey>` declarations. Adding another binding alongside the packaged skin does not replace its bindings. For a custom UI, edit your own `<media-hotkey>` set directly.
|
|
75
75
|
|
|
76
|
+
### Tap to play on touch
|
|
77
|
+
|
|
78
|
+
The packaged skins toggle controls on a touch tap, and the center play button starts playback. To play and pause with a tap anywhere on the video instead, bind `togglePaused` in place of `toggleControls` for touch:
|
|
79
|
+
|
|
80
|
+
```html
|
|
81
|
+
<media-gesture type="tap" action="togglePaused" pointer="touch"></media-gesture>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
A tap then pauses playback as well, and taps no longer show or hide the controls.
|
|
85
|
+
|
|
76
86
|
### Seek step size
|
|
77
87
|
|
|
78
88
|
Set the `seekStep` distance with `value`. Match it to your content: 5 seconds for short clips, 15 or 30 seconds for long-form video.
|