@videojs/html 10.2.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 +161 -41
- package/dist/default/define/audio/compat-skin2.js +1 -1
- package/dist/default/define/audio/neutral-skin.css +73 -34
- package/dist/default/define/audio/neutral-skin2.js +1 -1
- package/dist/default/define/audio/scaffold-skin.css +166 -42
- package/dist/default/define/audio/scaffold-skin2.js +1 -1
- package/dist/default/define/audio/skin.css +72 -34
- package/dist/default/define/audio/skin2.js +1 -1
- package/dist/default/define/extensions/google-analytics.js +6 -0
- package/dist/default/define/live-audio/compat-skin.css +143 -41
- package/dist/default/define/live-audio/compat-skin2.js +1 -1
- package/dist/default/define/live-audio/neutral-skin.css +56 -31
- package/dist/default/define/live-audio/neutral-skin2.js +1 -1
- package/dist/default/define/live-audio/scaffold-skin.css +148 -42
- package/dist/default/define/live-audio/scaffold-skin2.js +1 -1
- package/dist/default/define/live-audio/skin.css +55 -31
- package/dist/default/define/live-audio/skin2.js +1 -1
- package/dist/default/define/live-video/compat-skin.css +234 -51
- package/dist/default/define/live-video/compat-skin2.js +1 -1
- package/dist/default/define/live-video/neutral-skin.css +300 -46
- package/dist/default/define/live-video/neutral-skin2.js +1 -1
- package/dist/default/define/live-video/scaffold-skin.css +231 -53
- package/dist/default/define/live-video/scaffold-skin2.js +1 -1
- package/dist/default/define/live-video/skin.css +314 -49
- package/dist/default/define/live-video/skin2.js +1 -1
- package/dist/default/define/media/dailymotion-video.js +11 -0
- package/dist/default/define/media/mixcloud-audio.js +11 -0
- package/dist/default/define/media/soundcloud-audio.js +11 -0
- package/dist/default/define/ui/time-slider-markers.js +5 -0
- package/dist/default/define/video/compat-skin.css +242 -51
- package/dist/default/define/video/compat-skin2.js +1 -1
- package/dist/default/define/video/neutral-skin.css +382 -57
- package/dist/default/define/video/neutral-skin2.js +1 -1
- package/dist/default/define/video/scaffold-skin.css +240 -53
- package/dist/default/define/video/scaffold-skin2.js +1 -1
- package/dist/default/define/video/skin.css +415 -55
- package/dist/default/define/video/skin2.js +1 -1
- package/dist/default/extensions/google-analytics/extension.js +75 -0
- package/dist/default/extensions/mux-data/extension.js +7 -2
- package/dist/default/index.js +3 -1
- package/dist/default/internal/skins/compat-audio/skin.css +161 -41
- package/dist/default/internal/skins/compat-audio/template.js +1 -1
- package/dist/default/internal/skins/compat-live-audio/skin.css +143 -41
- package/dist/default/internal/skins/compat-live-video/skin.css +234 -51
- package/dist/default/internal/skins/compat-live-video/template.js +2 -0
- package/dist/default/internal/skins/compat-video/skin.css +242 -51
- package/dist/default/internal/skins/compat-video/template.js +2 -0
- package/dist/default/internal/skins/default-audio/skin.css +72 -34
- package/dist/default/internal/skins/default-live-audio/skin.css +55 -31
- package/dist/default/internal/skins/default-live-video/skin.css +314 -49
- 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 +415 -55
- package/dist/default/internal/skins/default-video/template.js +33 -5
- package/dist/default/internal/skins/neutral-audio/skin.css +73 -34
- package/dist/default/internal/skins/neutral-live-audio/skin.css +56 -31
- package/dist/default/internal/skins/neutral-live-video/skin.css +300 -46
- package/dist/default/internal/skins/neutral-live-video/template.js +14 -0
- package/dist/default/internal/skins/neutral-video/skin.css +382 -57
- package/dist/default/internal/skins/neutral-video/template.js +25 -11
- package/dist/default/internal/skins/scaffold-audio/skin.css +166 -42
- package/dist/default/internal/skins/scaffold-audio/template.js +1 -1
- package/dist/default/internal/skins/scaffold-live-audio/skin.css +148 -42
- package/dist/default/internal/skins/scaffold-live-video/skin.css +231 -53
- package/dist/default/internal/skins/scaffold-live-video/template.js +2 -0
- package/dist/default/internal/skins/scaffold-video/skin.css +240 -53
- 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/dailymotion-video/adapter.js +31 -0
- package/dist/default/media/hls-background-video/adapter.js +23 -35
- package/dist/default/media/mixcloud-audio/adapter.js +16 -0
- package/dist/default/media/soundcloud-audio/adapter.js +16 -0
- package/dist/default/player/element.js +1 -5
- package/dist/default/presets/background/skin.js +2 -2
- package/dist/default/presets/skin.js +4 -3
- package/dist/default/ui/captions-radio-group/element.js +14 -1
- package/dist/default/ui/controls/element.js +6 -3
- package/dist/default/ui/dialog/element.js +13 -1
- package/dist/default/ui/gesture/element.js +3 -0
- package/dist/default/ui/media-button-element.js +10 -1
- package/dist/default/ui/playback-rate-button/element.js +7 -2
- package/dist/default/ui/playback-rate-radio-group/element.js +10 -3
- package/dist/default/ui/radio-options/controller.js +18 -5
- 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 +161 -41
- 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 +73 -34
- 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 +166 -42
- 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 +72 -34
- package/dist/dev/define/audio/skin2.js +1 -1
- package/dist/dev/define/audio/skin2.js.map +1 -1
- package/dist/dev/define/extensions/google-analytics.d.ts +11 -0
- package/dist/dev/define/extensions/google-analytics.js +8 -0
- package/dist/dev/define/extensions/google-analytics.js.map +1 -0
- package/dist/dev/define/live-audio/compat-skin.css +143 -41
- 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 +56 -31
- 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 +148 -42
- 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 +55 -31
- 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 +234 -51
- 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 +300 -46
- 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 +231 -53
- 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 +314 -49
- 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/media/dailymotion-video.d.ts +15 -0
- package/dist/dev/define/media/dailymotion-video.js +13 -0
- package/dist/dev/define/media/dailymotion-video.js.map +1 -0
- package/dist/dev/define/media/mixcloud-audio.d.ts +15 -0
- package/dist/dev/define/media/mixcloud-audio.js +13 -0
- package/dist/dev/define/media/mixcloud-audio.js.map +1 -0
- package/dist/dev/define/media/soundcloud-audio.d.ts +15 -0
- package/dist/dev/define/media/soundcloud-audio.js +13 -0
- package/dist/dev/define/media/soundcloud-audio.js.map +1 -0
- 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 +242 -51
- 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 +382 -57
- 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 +240 -53
- 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 +415 -55
- package/dist/dev/define/video/skin2.js +1 -1
- package/dist/dev/define/video/skin2.js.map +1 -1
- package/dist/dev/extensions/google-analytics/extension.d.ts +52 -0
- package/dist/dev/extensions/google-analytics/extension.js +77 -0
- package/dist/dev/extensions/google-analytics/extension.js.map +1 -0
- package/dist/dev/extensions/google-analytics/index.d.ts +2 -0
- package/dist/dev/extensions/mux-data/extension.d.ts +4 -1
- package/dist/dev/extensions/mux-data/extension.js +7 -2
- package/dist/dev/extensions/mux-data/extension.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 +161 -41
- package/dist/dev/internal/skins/compat-audio/template.js +1 -1
- package/dist/dev/internal/skins/compat-audio/template.js.map +1 -1
- package/dist/dev/internal/skins/compat-live-audio/skin.css +143 -41
- package/dist/dev/internal/skins/compat-live-video/skin.css +234 -51
- 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 +242 -51
- 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 +72 -34
- package/dist/dev/internal/skins/default-live-audio/skin.css +55 -31
- package/dist/dev/internal/skins/default-live-video/register.js.map +1 -1
- package/dist/dev/internal/skins/default-live-video/skin.css +314 -49
- 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 +415 -55
- 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 +73 -34
- package/dist/dev/internal/skins/neutral-live-audio/skin.css +56 -31
- package/dist/dev/internal/skins/neutral-live-video/register.js.map +1 -1
- package/dist/dev/internal/skins/neutral-live-video/skin.css +300 -46
- 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 +382 -57
- 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 +166 -42
- package/dist/dev/internal/skins/scaffold-audio/template.js +1 -1
- package/dist/dev/internal/skins/scaffold-audio/template.js.map +1 -1
- package/dist/dev/internal/skins/scaffold-live-audio/skin.css +148 -42
- package/dist/dev/internal/skins/scaffold-live-video/skin.css +231 -53
- 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 +240 -53
- 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/dailymotion-video/adapter.d.ts +17 -0
- package/dist/dev/media/dailymotion-video/adapter.js +47 -0
- package/dist/dev/media/dailymotion-video/adapter.js.map +1 -0
- package/dist/dev/media/dailymotion-video/index.d.ts +2 -0
- package/dist/dev/media/hls-background-video/adapter.d.ts +14 -19
- package/dist/dev/media/hls-background-video/adapter.js +23 -35
- package/dist/dev/media/hls-background-video/adapter.js.map +1 -1
- package/dist/dev/media/mixcloud-audio/adapter.d.ts +11 -0
- package/dist/dev/media/mixcloud-audio/adapter.js +52 -0
- package/dist/dev/media/mixcloud-audio/adapter.js.map +1 -0
- package/dist/dev/media/mixcloud-audio/index.d.ts +2 -0
- package/dist/dev/media/soundcloud-audio/adapter.d.ts +11 -0
- package/dist/dev/media/soundcloud-audio/adapter.js +53 -0
- package/dist/dev/media/soundcloud-audio/adapter.js.map +1 -0
- package/dist/dev/media/soundcloud-audio/index.d.ts +2 -0
- package/dist/dev/player/element.js +1 -5
- package/dist/dev/player/element.js.map +1 -1
- package/dist/dev/presets/background/skin.d.ts +2 -1
- package/dist/dev/presets/background/skin.js +2 -2
- package/dist/dev/presets/background/skin.js.map +1 -1
- package/dist/dev/presets/skin.d.ts +4 -3
- package/dist/dev/presets/skin.js +4 -3
- package/dist/dev/presets/skin.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/dialog/element.js +13 -1
- package/dist/dev/ui/dialog/element.js.map +1 -1
- package/dist/dev/ui/gesture/element.js +3 -0
- package/dist/dev/ui/gesture/element.js.map +1 -1
- package/dist/dev/ui/media-button-element.d.ts +9 -0
- package/dist/dev/ui/media-button-element.js +10 -1
- package/dist/dev/ui/media-button-element.js.map +1 -1
- package/dist/dev/ui/play-button/element.d.ts +2 -0
- package/dist/dev/ui/playback-rate-button/element.d.ts +9 -1
- package/dist/dev/ui/playback-rate-button/element.js +7 -2
- package/dist/dev/ui/playback-rate-button/element.js.map +1 -1
- package/dist/dev/ui/playback-rate-radio-group/element.d.ts +4 -0
- package/dist/dev/ui/playback-rate-radio-group/element.js +10 -3
- package/dist/dev/ui/playback-rate-radio-group/element.js.map +1 -1
- package/dist/dev/ui/radio-options/controller.js +18 -5
- package/dist/dev/ui/radio-options/controller.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 +2 -2
- package/docs/guides/background-video.md +2 -4
- package/docs/guides/browser-support.md +23 -15
- package/docs/guides/build-your-own-skin.md +3 -1
- package/docs/guides/cdn.md +10 -9
- package/docs/guides/content-security-policy.md +3 -0
- package/docs/guides/customize-skins.md +7 -2
- package/docs/guides/features.md +1 -1
- package/docs/guides/google-analytics.md +199 -0
- package/docs/guides/installation-cdn.md +4 -4
- package/docs/guides/installation-shadcn.md +3 -3
- package/docs/guides/installation-svelte.md +4 -4
- package/docs/guides/installation-vue.md +4 -4
- package/docs/guides/installation.md +4 -4
- package/docs/guides/internationalization.md +5 -5
- package/docs/guides/keyboard-shortcuts.md +11 -1
- package/docs/guides/llms.txt +3 -1
- package/docs/guides/media-sources.md +3 -0
- package/docs/guides/migrate-from-media-chrome.md +4 -4
- package/docs/guides/migrate-from-mux-player.md +9 -9
- package/docs/guides/migrate-from-plyr.md +8 -8
- package/docs/guides/migrate-from-video-js-8.md +8 -9
- package/docs/guides/migrate-from-vidstack.md +10 -10
- package/docs/guides/mux-data.md +22 -0
- package/docs/guides/presets.md +5 -5
- package/docs/guides/self-hosting.md +5 -5
- package/docs/guides/skins.md +21 -5
- package/docs/guides/timed-metadata.md +318 -0
- package/docs/guides/ui-components.md +1 -1
- package/docs/llms.txt +25 -6
- package/docs/reference/api/chapters-track.md +71 -0
- package/docs/reference/api/define-text-track.md +113 -0
- package/docs/reference/api/feature-playback-rate.md +54 -3
- package/docs/reference/api/feature-playback.md +5 -1
- 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 +15 -7
- package/docs/reference/api/preset-audio.md +15 -5
- package/docs/reference/api/preset-background.md +2 -2
- package/docs/reference/api/preset-live-audio.md +15 -5
- package/docs/reference/api/preset-live-video.md +14 -5
- package/docs/reference/api/preset-video.md +14 -5
- package/docs/reference/api/resolve-adapter-type.md +4 -1
- package/docs/reference/api/ui-element.md +2 -2
- package/docs/reference/components/alert-dialog.md +21 -16
- package/docs/reference/components/audio-compat-skin.md +8 -2
- package/docs/reference/components/audio-neutral-skin.md +2 -2
- package/docs/reference/components/audio-scaffold-skin.md +2 -2
- package/docs/reference/components/audio-skin.md +2 -2
- package/docs/reference/components/audio-track-radio-group.md +2 -2
- 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/buffering-indicator.md +2 -2
- package/docs/reference/components/captions-radio-group.md +3 -3
- package/docs/reference/components/cloudflare-video.md +1 -1
- package/docs/reference/components/controls.md +16 -3
- package/docs/reference/components/dailymotion-video.md +192 -0
- package/docs/reference/components/dash-video.md +20 -2
- package/docs/reference/components/dialog.md +49 -22
- package/docs/reference/components/error-dialog.md +13 -10
- package/docs/reference/components/gesture.md +2 -2
- package/docs/reference/components/google-analytics.md +51 -0
- 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 +25 -5
- package/docs/reference/components/hls-video.md +99 -7
- package/docs/reference/components/hlsjs-video.md +53 -12
- package/docs/reference/components/hotkey.md +2 -2
- package/docs/reference/components/live-audio-compat-skin.md +8 -2
- package/docs/reference/components/live-audio-neutral-skin.md +2 -2
- package/docs/reference/components/live-audio-scaffold-skin.md +2 -2
- package/docs/reference/components/live-audio-skin.md +2 -2
- package/docs/reference/components/live-video-compat-skin.md +12 -2
- package/docs/reference/components/live-video-neutral-skin.md +6 -2
- package/docs/reference/components/live-video-scaffold-skin.md +6 -2
- package/docs/reference/components/live-video-skin.md +6 -2
- package/docs/reference/components/llms.txt +10 -5
- package/docs/reference/components/mixcloud-audio.md +203 -0
- package/docs/reference/components/mux-audio.md +35 -2
- package/docs/reference/components/mux-background-video.md +1 -1
- package/docs/reference/components/mux-data.md +20 -2
- package/docs/reference/components/mux-video.md +18 -2
- package/docs/reference/components/native-hls-video.md +32 -2
- package/docs/reference/components/play-button.md +7 -5
- package/docs/reference/components/playback-rate-button.md +26 -7
- package/docs/reference/components/playback-rate-radio-group.md +7 -4
- package/docs/reference/components/player.md +3 -3
- package/docs/reference/components/playerjs-video.md +2 -2
- package/docs/reference/components/quality-radio-group.md +2 -2
- package/docs/reference/components/shaka-video.md +2 -2
- package/docs/reference/components/soundcloud-audio.md +227 -0
- package/docs/reference/components/spotify-audio.md +3 -3
- package/docs/reference/components/tiktok-video.md +3 -3
- 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 +2 -3
- package/docs/reference/components/video-compat-skin.md +12 -2
- package/docs/reference/components/video-neutral-skin.md +6 -2
- package/docs/reference/components/video-scaffold-skin.md +6 -2
- package/docs/reference/components/video-skin.md +6 -2
- package/docs/reference/components/video.md +19 -1
- package/docs/reference/components/vimeo-video.md +1 -1
- package/docs/reference/components/wistia-video.md +1 -1
- package/docs/reference/components/youtube-video.md +1 -1
- package/package.json +60 -40
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { MediaAttachMixin } from "../../store/media-attach-mixin.js";
|
|
2
|
+
import { getTemplateHTML, getTemplateVideo } from "./template.js";
|
|
3
|
+
import { namedNodeMapToObject } from "@videojs/utils/dom";
|
|
4
|
+
import { pick } from "@videojs/utils/object";
|
|
5
|
+
//#region src/media/background-video/base.ts
|
|
6
|
+
const HTMLElementBase = globalThis.HTMLElement ?? class {};
|
|
7
|
+
const MediaAttachBase = MediaAttachMixin(HTMLElementBase);
|
|
8
|
+
const PLAYBACK_DEFAULTS = [
|
|
9
|
+
"muted",
|
|
10
|
+
"loop",
|
|
11
|
+
"autoplay"
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* The shadow setup, `src` wiring, and `target` that `<background-video>` and `<hls-background-video>` share. Each
|
|
15
|
+
* subclass supplies its own `src` and declares which playback defaults authors may opt out of.
|
|
16
|
+
*
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
var BackgroundVideoBase = class extends MediaAttachBase {
|
|
20
|
+
static {
|
|
21
|
+
this.shadowRootOptions = { mode: "open" };
|
|
22
|
+
}
|
|
23
|
+
static {
|
|
24
|
+
this.getTemplateHTML = getTemplateHTML;
|
|
25
|
+
}
|
|
26
|
+
static {
|
|
27
|
+
this.optOuts = [
|
|
28
|
+
"muted",
|
|
29
|
+
"loop",
|
|
30
|
+
"autoplay"
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
static {
|
|
34
|
+
this.passthroughAttributes = [
|
|
35
|
+
"controls",
|
|
36
|
+
"controlslist",
|
|
37
|
+
"crossorigin",
|
|
38
|
+
"preload"
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
static get observedAttributes() {
|
|
42
|
+
return [
|
|
43
|
+
"src",
|
|
44
|
+
...this.optOuts,
|
|
45
|
+
...this.optOuts.map((name) => `no${name}`),
|
|
46
|
+
...this.passthroughAttributes
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
constructor() {
|
|
50
|
+
super();
|
|
51
|
+
const ctor = this.constructor;
|
|
52
|
+
if (!this.shadowRoot) {
|
|
53
|
+
const attrs = {
|
|
54
|
+
...pick(namedNodeMapToObject(this.attributes), ctor.passthroughAttributes),
|
|
55
|
+
playsinline: "",
|
|
56
|
+
disableremoteplayback: "",
|
|
57
|
+
disablepictureinpicture: ""
|
|
58
|
+
};
|
|
59
|
+
for (const name of PLAYBACK_DEFAULTS) if (this.#isDefaultOn(name)) attrs[name] = "";
|
|
60
|
+
this.attachShadow(ctor.shadowRootOptions);
|
|
61
|
+
this.shadowRoot.innerHTML = ctor.getTemplateHTML(attrs);
|
|
62
|
+
}
|
|
63
|
+
this.syncPlaybackDefaults();
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Writes muted, loop, and autoplay onto the inner video as properties. The template's attributes only cover markup
|
|
67
|
+
* parsed with its attributes in place; an element created by script gets its `no*` attributes afterwards, and neither
|
|
68
|
+
* Chrome nor Firefox honor a `muted` attribute set after `document.createElement`.
|
|
69
|
+
*/
|
|
70
|
+
syncPlaybackDefaults() {
|
|
71
|
+
const target = this.target;
|
|
72
|
+
if (!target) return;
|
|
73
|
+
for (const name of PLAYBACK_DEFAULTS) target[name] = this.#isDefaultOn(name);
|
|
74
|
+
}
|
|
75
|
+
/** On unless its `no*` attribute is set and allowed; an explicit attribute such as `muted` wins over its opt-out. */
|
|
76
|
+
#isDefaultOn(name) {
|
|
77
|
+
const { optOuts } = this.constructor;
|
|
78
|
+
return this.hasAttribute(name) || !optOuts.includes(name) || !this.hasAttribute(`no${name}`);
|
|
79
|
+
}
|
|
80
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
81
|
+
if (oldValue === newValue) return;
|
|
82
|
+
const { passthroughAttributes } = this.constructor;
|
|
83
|
+
if (name === "src") this.src = newValue ?? "";
|
|
84
|
+
else if (passthroughAttributes.includes(name)) {
|
|
85
|
+
if (newValue === null) this.target?.removeAttribute(name);
|
|
86
|
+
else this.target?.setAttribute(name, newValue);
|
|
87
|
+
} else this.syncPlaybackDefaults();
|
|
88
|
+
}
|
|
89
|
+
/** The inner `<video>` in the shadow root: what plays, and what `play()` / `pause()` belong on. */
|
|
90
|
+
get target() {
|
|
91
|
+
return getTemplateVideo(this.shadowRoot);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
//#endregion
|
|
95
|
+
export { BackgroundVideoBase };
|
|
@@ -1,32 +1,25 @@
|
|
|
1
1
|
import { serializeAttributes } from "@videojs/utils/dom";
|
|
2
|
-
import { pick } from "@videojs/utils/object";
|
|
3
2
|
//#region src/media/background-video/template.ts
|
|
4
3
|
/**
|
|
5
|
-
* Attributes forwarded to the inner `<video>`. `src` is deliberately not one of them: each element decides what to do
|
|
6
|
-
* with it, whether that is assigning the inner video or handing it to a playback engine, and serializing it into the
|
|
7
|
-
* template would start a native load either way.
|
|
8
|
-
*/
|
|
9
|
-
const VideoAttributes = [
|
|
10
|
-
"autoplay",
|
|
11
|
-
"controls",
|
|
12
|
-
"controlslist",
|
|
13
|
-
"crossorigin",
|
|
14
|
-
"disablepictureinpicture",
|
|
15
|
-
"disableremoteplayback",
|
|
16
|
-
"loop",
|
|
17
|
-
"muted",
|
|
18
|
-
"playsinline",
|
|
19
|
-
"preload"
|
|
20
|
-
];
|
|
21
|
-
/**
|
|
22
4
|
* The shadow template both background-video elements render: a `<slot>` for a placeholder image, and a `<video>`
|
|
23
5
|
* stretched over the host.
|
|
24
6
|
*
|
|
7
|
+
* `attrs` go onto the `<video>` as given; each element decides which of its own attributes to forward. `src` is never
|
|
8
|
+
* among them, since serializing it would start a native load before an engine could take it.
|
|
9
|
+
*
|
|
25
10
|
* Shared so the two can't drift in presentation. `object-fit` and `object-position` are the only styling hooks — a
|
|
26
11
|
* background video has no controls to theme.
|
|
27
12
|
*/
|
|
28
13
|
function getTemplateHTML(attrs) {
|
|
29
|
-
return `<style> :host { position: relative; } video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: var(--media-object-fit, inherit); object-position: var(--media-object-position, 50% 50%); } </style><slot></slot><video${serializeAttributes(
|
|
14
|
+
return `<style> :host { position: relative; } video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: var(--media-object-fit, inherit); object-position: var(--media-object-position, 50% 50%); } </style><slot></slot><video${serializeAttributes(attrs)}></video>`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The `<video>` from `getTemplateHTML`. Always the shadow one: the template has no slot that would render a light-DOM
|
|
18
|
+
* `<video>`, so anything found there is either the placeholder or not displayed at all.
|
|
19
|
+
*/
|
|
20
|
+
function getTemplateVideo(shadowRoot) {
|
|
21
|
+
const video = shadowRoot?.querySelector("video");
|
|
22
|
+
return video instanceof HTMLVideoElement ? video : null;
|
|
30
23
|
}
|
|
31
24
|
//#endregion
|
|
32
|
-
export {
|
|
25
|
+
export { getTemplateHTML, getTemplateVideo };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { MediaAttachMixin } from "../../store/media-attach-mixin.js";
|
|
2
|
+
import { CustomMediaElement } from "@videojs/media/dom";
|
|
3
|
+
import { DailymotionAdapter } from "@videojs/dailymotion-video";
|
|
4
|
+
//#region src/media/dailymotion-video/adapter.ts
|
|
5
|
+
var DailymotionCustomMediaElement = class extends CustomMediaElement("iframe", DailymotionAdapter) {
|
|
6
|
+
static {
|
|
7
|
+
this.getTemplateHTML = () => `<style> :host { display: inline-block; min-width: 300px; min-height: 150px; position: relative; } ::slotted([slot=media]) { position: absolute; inset: 0; } </style><slot name="media"></slot>`;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var DailymotionVideo = class extends MediaAttachMixin(DailymotionCustomMediaElement) {
|
|
11
|
+
constructor() {
|
|
12
|
+
super();
|
|
13
|
+
this.adapter.addEventListener("volumechange", () => {
|
|
14
|
+
const { muted } = this.adapter;
|
|
15
|
+
if (this.hasAttribute("muted") !== muted) this.toggleAttribute("muted", muted);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
connectedCallback() {
|
|
19
|
+
super.connectedCallback?.();
|
|
20
|
+
const existing = this.querySelector(":scope > [slot=media]");
|
|
21
|
+
if (existing) {
|
|
22
|
+
if (this.adapter.src && !existing.hasChildNodes() && !this.adapter.error) this.adapter.load();
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const container = document.createElement("div");
|
|
26
|
+
container.slot = "media";
|
|
27
|
+
this.append(container);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
31
|
+
export { DailymotionVideo };
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getTemplateHTML } from "../background-video/template.js";
|
|
3
|
-
import { namedNodeMapToObject } from "@videojs/utils/dom";
|
|
1
|
+
import { BackgroundVideoBase } from "../background-video/base.js";
|
|
4
2
|
import { HlsBackgroundVideoAdapter } from "@videojs/spf/adapters/hls-background-video";
|
|
5
3
|
//#region src/media/hls-background-video/adapter.ts
|
|
6
|
-
const HTMLElementBase = globalThis.HTMLElement ?? class {};
|
|
7
|
-
const HlsBackgroundVideoBase = MediaAttachMixin(HTMLElementBase);
|
|
8
4
|
/**
|
|
9
5
|
* A muted, looping, chrome-less video over the SPF background-video engine.
|
|
10
6
|
*
|
|
@@ -16,8 +12,9 @@ const HlsBackgroundVideoBase = MediaAttachMixin(HTMLElementBase);
|
|
|
16
12
|
* package, whose `audio`, `debug`, `preload`, and `max-resolution` attributes are all deliberately absent. Capping
|
|
17
13
|
* which rendition is fetched is a delivery param on the URL — `?max_resolution=720p` on a Mux stream, for one — which
|
|
18
14
|
* keeps the renditions it excludes out of the manifest rather than merely unpicked; `preload` would have nothing to
|
|
19
|
-
* say, since the engine loads from the moment it has a source.
|
|
20
|
-
* `noloop`
|
|
15
|
+
* say, since the engine loads from the moment it has a source. Muted is fixed on: the engine drops audio, so there is
|
|
16
|
+
* nothing to unmute. `noloop` and `noautoplay` opt out as on `<background-video>`, so a page can play the video once,
|
|
17
|
+
* or hold it until it has checked the motion preference.
|
|
21
18
|
*
|
|
22
19
|
* Takes no structured `source` — `src` is an HLS URL, as the package it replaces required. Mux playback-ID identity,
|
|
23
20
|
* poster, and storyboard belong to `<mux-video>`; none of them mean anything without controls to hang them on.
|
|
@@ -39,40 +36,36 @@ const HlsBackgroundVideoBase = MediaAttachMixin(HTMLElementBase);
|
|
|
39
36
|
* `<mux-background-video>` is this element under the name the package it replaces used. Same class, so the tag is a
|
|
40
37
|
* naming choice and nothing more.
|
|
41
38
|
*/
|
|
42
|
-
var HlsBackgroundVideo = class extends
|
|
39
|
+
var HlsBackgroundVideo = class extends BackgroundVideoBase {
|
|
43
40
|
static {
|
|
44
|
-
this.
|
|
41
|
+
this.optOuts = ["loop", "autoplay"];
|
|
45
42
|
}
|
|
46
43
|
static {
|
|
47
|
-
this.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
44
|
+
this.passthroughAttributes = [
|
|
45
|
+
"controls",
|
|
46
|
+
"controlslist",
|
|
47
|
+
"crossorigin"
|
|
48
|
+
];
|
|
51
49
|
}
|
|
52
50
|
#media = new HlsBackgroundVideoAdapter();
|
|
53
51
|
constructor() {
|
|
54
52
|
super();
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
...namedNodeMapToObject(this.attributes),
|
|
59
|
-
muted: "",
|
|
60
|
-
loop: "",
|
|
61
|
-
autoplay: "",
|
|
62
|
-
playsinline: "",
|
|
63
|
-
disableremoteplayback: "",
|
|
64
|
-
disablepictureinpicture: ""
|
|
65
|
-
};
|
|
66
|
-
this.shadowRoot.innerHTML = getTemplateHTML(attrs);
|
|
67
|
-
}
|
|
68
|
-
const video = this.video;
|
|
69
|
-
if (video) this.#media.attach(video);
|
|
53
|
+
const target = this.target;
|
|
54
|
+
if (target) this.#media.attach(target);
|
|
55
|
+
this.syncPlaybackDefaults();
|
|
70
56
|
this.#media.addEventListener("error", () => this.dispatchEvent(new Event("error")));
|
|
71
57
|
}
|
|
72
58
|
/** Register the Media (not the inner `<video>`) with the provider. */
|
|
73
59
|
getMediaTarget() {
|
|
74
60
|
return this.#media;
|
|
75
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* The Media driving the inner `<video>`, matching `adapter` on `CustomMediaElement`. Call `adapter.destroy()` to
|
|
64
|
+
* release the engine after `keep-alive` kept it running past removal.
|
|
65
|
+
*/
|
|
66
|
+
get adapter() {
|
|
67
|
+
return this.#media;
|
|
68
|
+
}
|
|
76
69
|
disconnectedCallback() {
|
|
77
70
|
super.disconnectedCallback?.();
|
|
78
71
|
if (this.hasAttribute("keep-alive")) return;
|
|
@@ -80,14 +73,9 @@ var HlsBackgroundVideo = class extends HlsBackgroundVideoBase {
|
|
|
80
73
|
if (!this.isConnected) this.#media.destroy();
|
|
81
74
|
});
|
|
82
75
|
}
|
|
83
|
-
|
|
84
|
-
if (oldValue === newValue) return;
|
|
85
|
-
if (name === "src") this.src = newValue ?? "";
|
|
86
|
-
}
|
|
87
|
-
/** The inner `<video>` the engine renders into. */
|
|
76
|
+
/** Same element as `target`. */
|
|
88
77
|
get video() {
|
|
89
|
-
|
|
90
|
-
return video instanceof HTMLVideoElement ? video : null;
|
|
78
|
+
return this.target;
|
|
91
79
|
}
|
|
92
80
|
/**
|
|
93
81
|
* What made the current source unplayable, or `null`. An SVTA code rather than a `MediaError` one — 99001 where this
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { MediaAttachMixin } from "../../store/media-attach-mixin.js";
|
|
2
|
+
import { CustomMediaElement } from "@videojs/media/dom";
|
|
3
|
+
import { escapeHtml } from "@videojs/utils/string";
|
|
4
|
+
import { MixcloudAdapter, buildMixcloudIframeSrc } from "@videojs/mixcloud-audio";
|
|
5
|
+
//#region src/media/mixcloud-audio/adapter.ts
|
|
6
|
+
var MixcloudCustomMediaElement = class extends CustomMediaElement("iframe", MixcloudAdapter) {
|
|
7
|
+
static {
|
|
8
|
+
this.getTemplateHTML = (attrs) => {
|
|
9
|
+
const initialSrc = buildMixcloudIframeSrc(attrs.src ?? "");
|
|
10
|
+
return `<style> :host { display: block; position: relative; height: 120px; } iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; } /* * The widget is Mixcloud's own chrome, so without controls it is a * transport and nothing else. Hidden rather than merely inert, and * important so a consumer's own display rule cannot put it back on * screen. An iframe in a hidden subtree still loads and plays its src. */ :host(:not([controls])) { display: none !important; } </style><iframe part="iframe" title="Mixcloud audio player" ${initialSrc ? ` src="${escapeHtml(initialSrc)}"` : ""} allow="autoplay; encrypted-media" frameborder="0" width="100%" height="100%" referrerpolicy="${escapeHtml(attrs.referrerpolicy ?? "")}" ></iframe>`;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
var MixcloudAudio = class extends MediaAttachMixin(MixcloudCustomMediaElement) {};
|
|
15
|
+
//#endregion
|
|
16
|
+
export { MixcloudAudio };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { MediaAttachMixin } from "../../store/media-attach-mixin.js";
|
|
2
|
+
import { CustomMediaElement } from "@videojs/media/dom";
|
|
3
|
+
import { escapeHtml } from "@videojs/utils/string";
|
|
4
|
+
import { SoundCloudAdapter, buildSoundCloudIframeSrc } from "@videojs/soundcloud-audio";
|
|
5
|
+
//#region src/media/soundcloud-audio/adapter.ts
|
|
6
|
+
var SoundCloudCustomMediaElement = class extends CustomMediaElement("iframe", SoundCloudAdapter) {
|
|
7
|
+
static {
|
|
8
|
+
this.getTemplateHTML = (attrs) => {
|
|
9
|
+
const initialSrc = buildSoundCloudIframeSrc(attrs.src ?? "");
|
|
10
|
+
return `<style> :host { display: block; position: relative; height: 166px; } iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; } /* * The widget is SoundCloud's own chrome, so without controls it is a * transport and nothing else. Hidden rather than merely inert, and * important so a consumer's own display rule cannot put it back on * screen. An iframe in a hidden subtree still loads and plays its src. */ :host(:not([controls])) { display: none !important; } </style><iframe part="iframe" title="SoundCloud audio player" ${initialSrc ? ` src="${escapeHtml(initialSrc)}"` : ""} allow="autoplay; encrypted-media" scrolling="no" frameborder="0" width="100%" height="100%" referrerpolicy="${escapeHtml(attrs.referrerpolicy ?? "")}" ></iframe>`;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
var SoundCloudAudio = class extends MediaAttachMixin(SoundCloudCustomMediaElement) {};
|
|
15
|
+
//#endregion
|
|
16
|
+
export { SoundCloudAudio };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { UIElement } from "../ui/ui-element.js";
|
|
2
2
|
import { PlayerExtensionCoordinator, setPlayerConfigValue } from "@videojs/core/dom";
|
|
3
|
-
import { ContextProvider
|
|
3
|
+
import { ContextProvider } from "@videojs/element/context";
|
|
4
4
|
import { camelCase, kebabCase } from "@videojs/utils/string";
|
|
5
5
|
import { isNull } from "@videojs/utils/predicate";
|
|
6
6
|
//#region src/player/element.ts
|
|
@@ -27,7 +27,6 @@ function createPlayerElement(options) {
|
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
#store = options.factory();
|
|
30
|
-
#contextRoot = new ContextRoot();
|
|
31
30
|
#configuredStore = null;
|
|
32
31
|
#detach = null;
|
|
33
32
|
#connected = false;
|
|
@@ -94,7 +93,6 @@ function createPlayerElement(options) {
|
|
|
94
93
|
}
|
|
95
94
|
connectedCallback() {
|
|
96
95
|
this.#connected = true;
|
|
97
|
-
this.#contextRoot.attach(this);
|
|
98
96
|
super.connectedCallback();
|
|
99
97
|
this.#syncInitialConfig();
|
|
100
98
|
this.#playerProvider.setValue(this.store);
|
|
@@ -111,13 +109,11 @@ function createPlayerElement(options) {
|
|
|
111
109
|
}
|
|
112
110
|
disconnectedCallback() {
|
|
113
111
|
this.#connected = false;
|
|
114
|
-
this.#contextRoot.detach(this);
|
|
115
112
|
this.#observer.disconnect();
|
|
116
113
|
this.#detachStore();
|
|
117
114
|
super.disconnectedCallback();
|
|
118
115
|
}
|
|
119
116
|
destroyCallback() {
|
|
120
|
-
this.#contextRoot.detach(this);
|
|
121
117
|
this.#observer.disconnect();
|
|
122
118
|
this.#detachStore();
|
|
123
119
|
this.#extensions.destroy();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import skin_default from "../../define/background/skin2.js";
|
|
2
|
-
import { ReactiveElement } from "@videojs/element";
|
|
2
|
+
import { DestroyMixin, ReactiveElement } from "@videojs/element";
|
|
3
3
|
import { ensureGlobalStyle } from "@videojs/utils/dom";
|
|
4
4
|
//#region src/presets/background/skin.ts
|
|
5
5
|
const STYLES_ID = "__media-background-styles";
|
|
@@ -12,7 +12,7 @@ function getTemplateHTML() {
|
|
|
12
12
|
</media-container>
|
|
13
13
|
`;
|
|
14
14
|
}
|
|
15
|
-
var BackgroundVideoSkinElement = class BackgroundVideoSkinElement extends ReactiveElement {
|
|
15
|
+
var BackgroundVideoSkinElement = class BackgroundVideoSkinElement extends DestroyMixin(ReactiveElement) {
|
|
16
16
|
static {
|
|
17
17
|
this.tagName = "background-video-skin";
|
|
18
18
|
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
+
import { UIElement } from "../ui/ui-element.js";
|
|
1
2
|
import global_default from "../define/global.js";
|
|
2
3
|
import shadow_default from "../define/shadow.js";
|
|
3
|
-
import { ReactiveElement } from "@videojs/element";
|
|
4
4
|
import { applyShadowStyles, createShadowStyle, ensureGlobalStyle, renderTemplate } from "@videojs/utils/dom";
|
|
5
5
|
//#region src/presets/skin.ts
|
|
6
6
|
const STYLES_ID = "__media-styles";
|
|
7
7
|
const shadowSheet = createShadowStyle(shadow_default);
|
|
8
8
|
/**
|
|
9
9
|
* Base element for skin definitions. Attaches a shadow root, clones `static template` into it, and applies shared +
|
|
10
|
-
* per-skin styles via `adoptedStyleSheets` (or `<style>` fallback).
|
|
10
|
+
* per-skin styles via `adoptedStyleSheets` (or `<style>` fallback). Destroying it also destroys the controls in its
|
|
11
|
+
* shadow root.
|
|
11
12
|
*/
|
|
12
|
-
var SkinElement = class extends
|
|
13
|
+
var SkinElement = class extends UIElement {
|
|
13
14
|
static {
|
|
14
15
|
this.shadowRootOptions = { mode: "open" };
|
|
15
16
|
}
|
|
@@ -11,7 +11,8 @@ import { translateText } from "@videojs/core/i18n";
|
|
|
11
11
|
/**
|
|
12
12
|
* Menu radio group that generates an Off `<media-menu-radio-item>` plus one per captions and subtitles track, and
|
|
13
13
|
* shares the selected label and availability with an enclosing menu. An optional `<template>` holding one
|
|
14
|
-
* `<media-menu-radio-item>` customizes each generated item
|
|
14
|
+
* `<media-menu-radio-item>` customizes each generated item; its `data-part` `label` and `badge` descendants receive the
|
|
15
|
+
* track's text.
|
|
15
16
|
*/
|
|
16
17
|
var CaptionsRadioGroupElement = class extends MenuRadioGroupElement {
|
|
17
18
|
constructor(..._args) {
|
|
@@ -23,6 +24,8 @@ var CaptionsRadioGroupElement = class extends MenuRadioGroupElement {
|
|
|
23
24
|
this.#i18n = new I18nController(this, i18nContext);
|
|
24
25
|
this.#mediaState = new PlayerController(this, playerContext, selectTextTrack);
|
|
25
26
|
this.#options = new RadioOptionsController(this, {
|
|
27
|
+
renderItem: (item, label, option) => this.#setContent(item, label, option.badge),
|
|
28
|
+
getOptionCacheKey: (option) => option.badge ?? "",
|
|
26
29
|
setItemAttributes: (item, option) => item.setAttribute("data-track", option.value),
|
|
27
30
|
onValueChange: (value) => {
|
|
28
31
|
const media = this.#mediaState.value;
|
|
@@ -66,6 +69,16 @@ var CaptionsRadioGroupElement = class extends MenuRadioGroupElement {
|
|
|
66
69
|
super.update(changed);
|
|
67
70
|
if (state) applyStateDataAttrs(this, state, CaptionsRadioGroupDataAttrs);
|
|
68
71
|
}
|
|
72
|
+
#setContent(item, label, badge) {
|
|
73
|
+
const labelPart = item.querySelector("[data-part~=\"label\"]");
|
|
74
|
+
const badgePart = item.querySelector("[data-part~=\"badge\"]");
|
|
75
|
+
if (labelPart) labelPart.textContent = label;
|
|
76
|
+
if (badgePart) {
|
|
77
|
+
badgePart.textContent = badge ?? "";
|
|
78
|
+
badgePart.hidden = !badge;
|
|
79
|
+
}
|
|
80
|
+
if (!labelPart && !badgePart) item.textContent = [label, badge].filter(Boolean).join(" ");
|
|
81
|
+
}
|
|
69
82
|
};
|
|
70
83
|
//#endregion
|
|
71
84
|
export { CaptionsRadioGroupElement };
|
|
@@ -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, selectControls } from "@videojs/core/dom";
|
|
6
|
+
import { applyStateDataAttrs, 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() {
|
|
@@ -37,6 +39,7 @@ var ControlsElement = class extends UIElement {
|
|
|
37
39
|
super.update(_changed);
|
|
38
40
|
this.#core.setProps({ visibility: this.visibility });
|
|
39
41
|
this.#core.setMedia(this.#mediaState.value ?? null);
|
|
42
|
+
this.#core.setPlayback(this.#playback.value ?? null);
|
|
40
43
|
const state = this.#core.getState();
|
|
41
44
|
if (!state) return;
|
|
42
45
|
applyStateDataAttrs(this, state, ControlsDataAttrs);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { containerContext } from "../../player/context.js";
|
|
1
2
|
import { UIElement } from "../ui-element.js";
|
|
2
3
|
import { PositionController } from "../position-controller.js";
|
|
3
4
|
import { dialogContext } from "./context.js";
|
|
4
5
|
import { DialogCore, DialogDataAttrs } from "@videojs/core";
|
|
5
6
|
import { applyElementProps, applyStateDataAttrs, createDialog, createTransition } from "@videojs/core/dom";
|
|
6
|
-
import { ContextProvider } from "@videojs/element/context";
|
|
7
|
+
import { ContextConsumer, ContextProvider } from "@videojs/element/context";
|
|
7
8
|
import { SnapshotController } from "@videojs/store/html";
|
|
8
9
|
//#region src/ui/dialog/element.ts
|
|
9
10
|
let idCounter = 0;
|
|
@@ -25,12 +26,14 @@ var DialogElementBase = class extends UIElement {
|
|
|
25
26
|
#stateAttrMap;
|
|
26
27
|
#provider;
|
|
27
28
|
#position;
|
|
29
|
+
#container;
|
|
28
30
|
#popupId;
|
|
29
31
|
#titleId;
|
|
30
32
|
#descriptionId;
|
|
31
33
|
#bindTrigger;
|
|
32
34
|
#dialog;
|
|
33
35
|
#snapshot;
|
|
36
|
+
#modalitySnapshot;
|
|
34
37
|
#triggerAbort;
|
|
35
38
|
#triggerElement;
|
|
36
39
|
constructor({ core = new DialogCore(), stateAttrMap = DialogDataAttrs, idPrefix = "dialog", bindTrigger = true } = {}) {
|
|
@@ -40,8 +43,13 @@ var DialogElementBase = class extends UIElement {
|
|
|
40
43
|
this.closeOnEscape = DialogCore.defaultProps.closeOnEscape;
|
|
41
44
|
this.#provider = new ContextProvider(this, { context: dialogContext });
|
|
42
45
|
this.#position = new PositionController(this);
|
|
46
|
+
this.#container = new ContextConsumer(this, {
|
|
47
|
+
context: containerContext,
|
|
48
|
+
subscribe: true
|
|
49
|
+
});
|
|
43
50
|
this.#dialog = null;
|
|
44
51
|
this.#snapshot = null;
|
|
52
|
+
this.#modalitySnapshot = null;
|
|
45
53
|
this.#triggerAbort = null;
|
|
46
54
|
this.#triggerElement = null;
|
|
47
55
|
this.#core = core;
|
|
@@ -69,6 +77,8 @@ var DialogElementBase = class extends UIElement {
|
|
|
69
77
|
});
|
|
70
78
|
if (this.#snapshot) this.#snapshot.track(this.#dialog.input);
|
|
71
79
|
else this.#snapshot = new SnapshotController(this, this.#dialog.input);
|
|
80
|
+
if (this.#modalitySnapshot) this.#modalitySnapshot.track(this.#dialog.modality);
|
|
81
|
+
else this.#modalitySnapshot = new SnapshotController(this, this.#dialog.modality);
|
|
72
82
|
}
|
|
73
83
|
firstUpdated(changed) {
|
|
74
84
|
super.firstUpdated(changed);
|
|
@@ -86,6 +96,7 @@ var DialogElementBase = class extends UIElement {
|
|
|
86
96
|
willUpdate(changed) {
|
|
87
97
|
super.willUpdate(changed);
|
|
88
98
|
this.#core.setProps(this);
|
|
99
|
+
this.#dialog?.setInteractionRoot(this.#container.value?.container ?? null);
|
|
89
100
|
if (this.#dialog && changed.has("open")) {
|
|
90
101
|
const { active: inputOpen } = this.#dialog.input.current;
|
|
91
102
|
if (this.open !== inputOpen) {
|
|
@@ -101,6 +112,7 @@ var DialogElementBase = class extends UIElement {
|
|
|
101
112
|
this.#syncTrigger(triggerElement);
|
|
102
113
|
const input = this.#dialog.input.current;
|
|
103
114
|
this.#core.setInput(input);
|
|
115
|
+
this.#core.setDocumentModal(this.#dialog.modality.current.documentModal);
|
|
104
116
|
const state = this.#core.getState();
|
|
105
117
|
applyStateDataAttrs(this, state, this.#stateAttrMap);
|
|
106
118
|
if (this.#triggerElement) applyElementProps(this.#triggerElement, this.#core.getTriggerAttrs(state, this.#popupId));
|
|
@@ -61,14 +61,17 @@ var GestureElement = class extends UIElement {
|
|
|
61
61
|
if (!resolver) return;
|
|
62
62
|
const { value, region } = this;
|
|
63
63
|
const actionValue = getGestureActionValue(this.action, region, value);
|
|
64
|
+
let state;
|
|
64
65
|
const onActivate = (event) => {
|
|
65
66
|
resolver({
|
|
66
67
|
store,
|
|
68
|
+
state,
|
|
67
69
|
value: actionValue,
|
|
68
70
|
event
|
|
69
71
|
});
|
|
70
72
|
};
|
|
71
73
|
const options = {
|
|
74
|
+
onPointerDown: () => state = store.state,
|
|
72
75
|
pointer: this.pointer,
|
|
73
76
|
region,
|
|
74
77
|
disabled: this.disabled,
|
|
@@ -71,6 +71,7 @@ var MediaButtonElement = class extends UIElement {
|
|
|
71
71
|
if (!media) return void 0;
|
|
72
72
|
this.core.setMedia(media);
|
|
73
73
|
const state = this.core.getState();
|
|
74
|
+
if (this.core.getTooltipLabel) return translateText(this.core.getTooltipLabel(state), this.#i18n.value);
|
|
74
75
|
return translateText(this.core.getLabel(state), this.#i18n.value, this.core.getLabelParams?.(state));
|
|
75
76
|
}
|
|
76
77
|
willUpdate(changed) {
|
|
@@ -89,9 +90,17 @@ var MediaButtonElement = class extends UIElement {
|
|
|
89
90
|
applyElementProps(this, {
|
|
90
91
|
...attrs,
|
|
91
92
|
"aria-keyshortcuts": this.#hotkeyRegistry?.aria,
|
|
92
|
-
...isHideable(state) && { hidden: state.hidden ? "" : void 0 }
|
|
93
|
+
...isHideable(state) && this.reflectsHidden() && { hidden: state.hidden ? "" : void 0 }
|
|
93
94
|
});
|
|
94
95
|
applyStateDataAttrs(this, state, this.stateAttrMap);
|
|
96
|
+
for (const [name, value] of Object.entries(this.core.getCSSVars?.(state) ?? {})) this.style.setProperty(name, value);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Whether this button writes its core's `hidden` state to the `hidden` attribute. A subclass returns `false` while
|
|
100
|
+
* another owner, such as a linked menu, manages its visibility.
|
|
101
|
+
*/
|
|
102
|
+
reflectsHidden() {
|
|
103
|
+
return true;
|
|
95
104
|
}
|
|
96
105
|
#syncHotkeyShortcut() {
|
|
97
106
|
const shortcut = this.getShortcut();
|
|
@@ -8,6 +8,7 @@ var PlaybackRateButtonElement = class extends MediaButtonElement {
|
|
|
8
8
|
constructor(..._args) {
|
|
9
9
|
super(..._args);
|
|
10
10
|
this.commandfor = void 0;
|
|
11
|
+
this.rates = void 0;
|
|
11
12
|
this.core = new PlaybackRateButtonCore();
|
|
12
13
|
this.stateAttrMap = PlaybackRateButtonDataAttrs;
|
|
13
14
|
this.mediaState = new PlayerController(this, playerContext, selectPlaybackRate);
|
|
@@ -20,7 +21,8 @@ var PlaybackRateButtonElement = class extends MediaButtonElement {
|
|
|
20
21
|
this.properties = {
|
|
21
22
|
label: { type: String },
|
|
22
23
|
disabled: { type: Boolean },
|
|
23
|
-
commandfor: { type: String }
|
|
24
|
+
commandfor: { type: String },
|
|
25
|
+
rates: { type: String }
|
|
24
26
|
};
|
|
25
27
|
}
|
|
26
28
|
activate(state, event) {
|
|
@@ -33,9 +35,12 @@ var PlaybackRateButtonElement = class extends MediaButtonElement {
|
|
|
33
35
|
getIsButtonDisabled() {
|
|
34
36
|
const media = this.mediaState.value;
|
|
35
37
|
if (super.getIsButtonDisabled()) return true;
|
|
36
|
-
if (this.commandfor && media && media.
|
|
38
|
+
if (this.commandfor && media && this.core.getRates(media).length === 0) return true;
|
|
37
39
|
return false;
|
|
38
40
|
}
|
|
41
|
+
reflectsHidden() {
|
|
42
|
+
return !this.commandfor;
|
|
43
|
+
}
|
|
39
44
|
willUpdate(changed) {
|
|
40
45
|
super.willUpdate(changed);
|
|
41
46
|
if (changed.has("commandfor")) {
|
|
@@ -17,12 +17,17 @@ var PlaybackRateRadioGroupElement = class extends MenuRadioGroupElement {
|
|
|
17
17
|
constructor(..._args) {
|
|
18
18
|
super(..._args);
|
|
19
19
|
this.disabled = false;
|
|
20
|
+
this.rates = void 0;
|
|
20
21
|
this.formatRate = PlaybackRateRadioGroupCore.defaultProps.formatRate;
|
|
21
22
|
this.#core = new PlaybackRateRadioGroupCore();
|
|
22
23
|
this.#i18n = new I18nController(this, i18nContext);
|
|
23
24
|
this.#mediaState = new PlayerController(this, playerContext, selectPlaybackRate);
|
|
24
25
|
this.#options = new RadioOptionsController(this, {
|
|
25
|
-
setItemAttributes: (item, option) =>
|
|
26
|
+
setItemAttributes: (item, option) => {
|
|
27
|
+
item.setAttribute("data-rate", option.value);
|
|
28
|
+
item.toggleAttribute("data-custom", option.custom);
|
|
29
|
+
},
|
|
30
|
+
getOptionCacheKey: (option) => option.custom ? "custom" : "",
|
|
26
31
|
onValueChange: (value) => {
|
|
27
32
|
const media = this.#mediaState.value;
|
|
28
33
|
if (media) this.#core.selectValue(media, value);
|
|
@@ -35,7 +40,8 @@ var PlaybackRateRadioGroupElement = class extends MenuRadioGroupElement {
|
|
|
35
40
|
static {
|
|
36
41
|
this.properties = {
|
|
37
42
|
...MenuRadioGroupElement.properties,
|
|
38
|
-
disabled: { type: Boolean }
|
|
43
|
+
disabled: { type: Boolean },
|
|
44
|
+
rates: { type: String }
|
|
39
45
|
};
|
|
40
46
|
}
|
|
41
47
|
#core;
|
|
@@ -52,7 +58,8 @@ var PlaybackRateRadioGroupElement = class extends MenuRadioGroupElement {
|
|
|
52
58
|
if (media) {
|
|
53
59
|
this.#core.setProps({
|
|
54
60
|
formatRate: this.formatRate,
|
|
55
|
-
disabled: this.disabled
|
|
61
|
+
disabled: this.disabled,
|
|
62
|
+
rates: this.rates
|
|
56
63
|
});
|
|
57
64
|
this.#core.setMedia(media);
|
|
58
65
|
state = this.#core.getState();
|