@videojs/html 10.2.0 → 10.3.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 +72 -5
- package/dist/default/define/audio/compat-skin2.js +1 -1
- package/dist/default/define/audio/neutral-skin.css +23 -5
- package/dist/default/define/audio/neutral-skin2.js +1 -1
- package/dist/default/define/audio/scaffold-skin.css +63 -4
- package/dist/default/define/audio/scaffold-skin2.js +1 -1
- package/dist/default/define/audio/skin.css +21 -5
- 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 +54 -5
- package/dist/default/define/live-audio/compat-skin2.js +1 -1
- package/dist/default/define/live-audio/neutral-skin.css +8 -4
- package/dist/default/define/live-audio/neutral-skin2.js +1 -1
- package/dist/default/define/live-audio/scaffold-skin.css +45 -4
- package/dist/default/define/live-audio/scaffold-skin2.js +1 -1
- package/dist/default/define/live-audio/skin.css +6 -4
- package/dist/default/define/live-audio/skin2.js +1 -1
- package/dist/default/define/live-video/compat-skin.css +115 -13
- package/dist/default/define/live-video/compat-skin2.js +1 -1
- package/dist/default/define/live-video/neutral-skin.css +82 -14
- package/dist/default/define/live-video/neutral-skin2.js +1 -1
- package/dist/default/define/live-video/scaffold-skin.css +95 -13
- package/dist/default/define/live-video/scaffold-skin2.js +1 -1
- package/dist/default/define/live-video/skin.css +96 -16
- 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/video/compat-skin.css +115 -13
- package/dist/default/define/video/compat-skin2.js +1 -1
- package/dist/default/define/video/neutral-skin.css +83 -14
- package/dist/default/define/video/neutral-skin2.js +1 -1
- package/dist/default/define/video/scaffold-skin.css +95 -13
- package/dist/default/define/video/scaffold-skin2.js +1 -1
- package/dist/default/define/video/skin.css +94 -16
- 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/internal/skins/compat-audio/skin.css +72 -5
- package/dist/default/internal/skins/compat-audio/template.js +1 -1
- package/dist/default/internal/skins/compat-live-audio/skin.css +54 -5
- package/dist/default/internal/skins/compat-live-video/skin.css +115 -13
- package/dist/default/internal/skins/compat-video/skin.css +115 -13
- package/dist/default/internal/skins/default-audio/skin.css +21 -5
- package/dist/default/internal/skins/default-live-audio/skin.css +6 -4
- package/dist/default/internal/skins/default-live-video/skin.css +96 -16
- package/dist/default/internal/skins/default-video/skin.css +94 -16
- package/dist/default/internal/skins/neutral-audio/skin.css +23 -5
- package/dist/default/internal/skins/neutral-live-audio/skin.css +8 -4
- package/dist/default/internal/skins/neutral-live-video/skin.css +82 -14
- package/dist/default/internal/skins/neutral-video/skin.css +83 -14
- package/dist/default/internal/skins/scaffold-audio/skin.css +63 -4
- package/dist/default/internal/skins/scaffold-audio/template.js +1 -1
- package/dist/default/internal/skins/scaffold-live-audio/skin.css +45 -4
- package/dist/default/internal/skins/scaffold-live-video/skin.css +95 -13
- package/dist/default/internal/skins/scaffold-video/skin.css +95 -13
- package/dist/default/media/dailymotion-video/adapter.js +31 -0
- package/dist/default/media/hls-background-video/adapter.js +7 -0
- 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/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/version.js +1 -1
- package/dist/dev/define/audio/compat-skin.css +72 -5
- 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 +23 -5
- 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 +63 -4
- 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 +21 -5
- 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 +54 -5
- 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 +8 -4
- 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 +45 -4
- 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 +6 -4
- 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 +115 -13
- 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 +82 -14
- 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 +95 -13
- 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 +96 -16
- 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/video/compat-skin.css +115 -13
- 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 +83 -14
- 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 +95 -13
- 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 +94 -16
- 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 +3 -3
- package/dist/dev/internal/skins/compat-audio/skin.css +72 -5
- 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 +54 -5
- package/dist/dev/internal/skins/compat-live-video/skin.css +115 -13
- package/dist/dev/internal/skins/compat-video/skin.css +115 -13
- package/dist/dev/internal/skins/default-audio/skin.css +21 -5
- package/dist/dev/internal/skins/default-live-audio/skin.css +6 -4
- package/dist/dev/internal/skins/default-live-video/skin.css +96 -16
- package/dist/dev/internal/skins/default-video/skin.css +94 -16
- package/dist/dev/internal/skins/neutral-audio/skin.css +23 -5
- package/dist/dev/internal/skins/neutral-live-audio/skin.css +8 -4
- package/dist/dev/internal/skins/neutral-live-video/skin.css +82 -14
- package/dist/dev/internal/skins/neutral-video/skin.css +83 -14
- package/dist/dev/internal/skins/scaffold-audio/skin.css +63 -4
- 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 +45 -4
- package/dist/dev/internal/skins/scaffold-live-video/skin.css +95 -13
- package/dist/dev/internal/skins/scaffold-video/skin.css +95 -13
- 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 +6 -1
- package/dist/dev/media/hls-background-video/adapter.js +7 -0
- 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/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/version.js +1 -1
- package/docs/README.md +1 -1
- package/docs/guides/autoplay.md +1 -1
- package/docs/guides/browser-support.md +2 -0
- 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 +4 -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 +1 -1
- package/docs/guides/llms.txt +2 -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 +8 -8
- package/docs/guides/mux-data.md +22 -0
- package/docs/guides/presets.md +1 -1
- package/docs/guides/self-hosting.md +5 -5
- package/docs/guides/skins.md +16 -1
- package/docs/guides/ui-components.md +1 -1
- package/docs/llms.txt +10 -5
- package/docs/reference/api/feature-playback-rate.md +54 -3
- package/docs/reference/api/feature-playback.md +5 -1
- package/docs/reference/api/html-create-player.md +2 -2
- package/docs/reference/api/llms.txt +1 -1
- package/docs/reference/api/media-capabilities.md +1 -1
- package/docs/reference/api/player-store.md +6 -3
- package/docs/reference/api/preset-audio.md +13 -5
- package/docs/reference/api/preset-background.md +2 -2
- package/docs/reference/api/preset-live-audio.md +13 -5
- package/docs/reference/api/preset-live-video.md +13 -5
- package/docs/reference/api/preset-video.md +13 -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/background-video-skin.md +1 -1
- package/docs/reference/components/background-video.md +1 -1
- package/docs/reference/components/buffering-indicator.md +2 -2
- package/docs/reference/components/captions-radio-group.md +2 -2
- package/docs/reference/components/cloudflare-video.md +1 -1
- package/docs/reference/components/dailymotion-video.md +192 -0
- package/docs/reference/components/dash-video.md +2 -1
- 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 +1 -1
- package/docs/reference/components/hls-background-video.md +4 -1
- package/docs/reference/components/hls-video.md +1 -1
- package/docs/reference/components/hlsjs-video.md +3 -1
- 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 +8 -2
- package/docs/reference/components/live-video-neutral-skin.md +2 -2
- package/docs/reference/components/live-video-scaffold-skin.md +2 -2
- package/docs/reference/components/live-video-skin.md +2 -2
- package/docs/reference/components/llms.txt +9 -5
- package/docs/reference/components/mixcloud-audio.md +203 -0
- package/docs/reference/components/mux-audio.md +3 -1
- 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 +3 -1
- package/docs/reference/components/native-hls-video.md +2 -1
- 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 +1 -1
- package/docs/reference/components/quality-radio-group.md +2 -2
- package/docs/reference/components/shaka-video.md +2 -1
- package/docs/reference/components/soundcloud-audio.md +227 -0
- package/docs/reference/components/spotify-audio.md +2 -2
- package/docs/reference/components/tiktok-video.md +2 -2
- package/docs/reference/components/twitch-video.md +2 -3
- package/docs/reference/components/video-compat-skin.md +8 -2
- package/docs/reference/components/video-neutral-skin.md +2 -2
- package/docs/reference/components/video-scaffold-skin.md +2 -2
- package/docs/reference/components/video-skin.md +2 -2
- package/docs/reference/components/vimeo-video.md +2 -1
- package/docs/reference/components/wistia-video.md +1 -1
- package/docs/reference/components/youtube-video.md +2 -1
- package/package.json +60 -40
|
@@ -223,6 +223,10 @@
|
|
|
223
223
|
display: none;
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
:where(.media-skin[data-theme="scaffold"][data-preset="video"]) .media-dialog-backdrop[data-scope="document"] {
|
|
227
|
+
position: fixed;
|
|
228
|
+
}
|
|
229
|
+
|
|
226
230
|
:where(.media-skin[data-theme="scaffold"][data-preset="video"]) .media-dialog-close {
|
|
227
231
|
height: calc(var(--media-spacing) * 8);
|
|
228
232
|
width: auto;
|
|
@@ -268,6 +272,11 @@
|
|
|
268
272
|
outline-color: var(--media-ring);
|
|
269
273
|
}
|
|
270
274
|
|
|
275
|
+
:where(.media-skin[data-theme="scaffold"][data-preset="video"]) .media-dialog-popup[data-scope="document"] {
|
|
276
|
+
max-height: calc(100dvh - var(--media-spacing) * 8);
|
|
277
|
+
position: fixed;
|
|
278
|
+
}
|
|
279
|
+
|
|
271
280
|
@media (forced-colors: active) {
|
|
272
281
|
:where(.media-skin[data-theme="scaffold"][data-preset="video"]) .media-dialog-popup {
|
|
273
282
|
border: 1px solid canvastext;
|
|
@@ -431,6 +440,18 @@
|
|
|
431
440
|
overflow: hidden;
|
|
432
441
|
}
|
|
433
442
|
|
|
443
|
+
.media-poster > slot::slotted(img) {
|
|
444
|
+
object-fit: var(--media-object-fit, contain);
|
|
445
|
+
object-position: var(--media-object-position, center);
|
|
446
|
+
width: 100%;
|
|
447
|
+
display: block;
|
|
448
|
+
height: 100% !important;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
.media-poster > slot::slotted(img:not([src]):not([srcset])) {
|
|
452
|
+
visibility: hidden;
|
|
453
|
+
}
|
|
454
|
+
|
|
434
455
|
:where(.media-skin[data-theme="scaffold"][data-preset="video"]) .media-poster {
|
|
435
456
|
width: 100%;
|
|
436
457
|
height: 100%;
|
|
@@ -602,8 +623,13 @@
|
|
|
602
623
|
}
|
|
603
624
|
|
|
604
625
|
:where(.media-skin[data-theme="scaffold"][data-preset="video"]) .media-tooltip-shortcut {
|
|
626
|
+
text-align: center;
|
|
627
|
+
min-width: 1.5em;
|
|
605
628
|
font-family: inherit;
|
|
606
629
|
font-size: calc(var(--media-spacing) * 2.75);
|
|
630
|
+
background-color: oklab(100% 0 5.96046e-8 / .1);
|
|
631
|
+
padding: .1em;
|
|
632
|
+
line-height: 1.25;
|
|
607
633
|
}
|
|
608
634
|
|
|
609
635
|
:where(.media-skin[data-theme="scaffold"][data-preset="video"]) .media-button-icon {
|
|
@@ -676,6 +702,10 @@
|
|
|
676
702
|
outline: 2px solid;
|
|
677
703
|
}
|
|
678
704
|
|
|
705
|
+
:where(.media-skin[data-theme="scaffold"][data-preset="video"]) .media-menu-radio-item[data-custom] {
|
|
706
|
+
font-style: italic;
|
|
707
|
+
}
|
|
708
|
+
|
|
679
709
|
:where(.media-skin[data-theme="scaffold"][data-preset="video"]) .media-menu-radio-item[data-highlighted] {
|
|
680
710
|
background-color: var(--media-button-highlight);
|
|
681
711
|
}
|
|
@@ -1768,7 +1798,7 @@
|
|
|
1768
1798
|
|
|
1769
1799
|
:where(.media-skin[data-theme="scaffold"][data-preset="video"]) .video-controls-backdrop {
|
|
1770
1800
|
pointer-events: none;
|
|
1771
|
-
background-
|
|
1801
|
+
background-image: linear-gradient(to top, #00000080, #0000 40% 60%, #0006);
|
|
1772
1802
|
position: absolute;
|
|
1773
1803
|
inset: 0;
|
|
1774
1804
|
}
|
|
@@ -1803,6 +1833,9 @@
|
|
|
1803
1833
|
:where(.media-skin[data-theme="scaffold"][data-preset="video"]) .media-container, :where(.media-skin[data-theme="scaffold"][data-preset="video"]).media-container {
|
|
1804
1834
|
border-radius: var(--media-video-border-radius);
|
|
1805
1835
|
width: 100%;
|
|
1836
|
+
min-width: 0;
|
|
1837
|
+
height: 100%;
|
|
1838
|
+
min-height: 0;
|
|
1806
1839
|
font-family: var(--media-font-family, inherit);
|
|
1807
1840
|
font-size: calc(var(--media-spacing) * 3.25);
|
|
1808
1841
|
color: var(--media-foreground);
|
|
@@ -1822,9 +1855,19 @@
|
|
|
1822
1855
|
}
|
|
1823
1856
|
|
|
1824
1857
|
:where(.media-skin[data-theme="scaffold"][data-preset="video"]) .media-video, :where(.media-skin[data-theme="scaffold"][data-preset="video"]).media-video {
|
|
1825
|
-
aspect-ratio: 16 / 9;
|
|
1826
1858
|
background-color: #000;
|
|
1827
1859
|
}
|
|
1860
|
+
|
|
1861
|
+
.media-container > slot::slotted(video), :scope.media-container > slot::slotted(video) {
|
|
1862
|
+
border-radius: inherit;
|
|
1863
|
+
object-fit: var(--media-object-fit, contain);
|
|
1864
|
+
object-position: var(--media-object-position, center);
|
|
1865
|
+
width: 100%;
|
|
1866
|
+
max-width: 100%;
|
|
1867
|
+
margin: 0;
|
|
1868
|
+
display: block;
|
|
1869
|
+
height: 100% !important;
|
|
1870
|
+
}
|
|
1828
1871
|
}
|
|
1829
1872
|
|
|
1830
1873
|
@layer utilities;
|
|
@@ -1842,7 +1885,7 @@
|
|
|
1842
1885
|
--media-accent: var(--media-accent-color, color-mix(in oklab, var(--media-default-accent-color) 10%, transparent));
|
|
1843
1886
|
--media-accent-foreground: var(--media-accent-text-color, currentColor);
|
|
1844
1887
|
--media-muted: oklch(100% 0 0 / .15);
|
|
1845
|
-
--media-muted-foreground:
|
|
1888
|
+
--media-muted-foreground: color-mix(in oklab, var(--media-foreground) 65%, transparent);
|
|
1846
1889
|
--media-border: oklch(0% 0 0 / .1);
|
|
1847
1890
|
--media-ring: oklch(100% 0 0);
|
|
1848
1891
|
--media-backdrop: oklch(0% 0 0);
|
|
@@ -1855,9 +1898,9 @@
|
|
|
1855
1898
|
--media-shadow-current-color: oklch(from currentColor 0 0 0 / clamp(0, calc((l - .5) * .5), .15));
|
|
1856
1899
|
--media-shadow-subtle-current-color: color-mix(in oklab, var(--media-shadow-current-color) 40%, transparent);
|
|
1857
1900
|
--media-text-shadow-dialog: 0 1px 0 #00000040;
|
|
1858
|
-
--media-backdrop-filter-surface: blur(16px) saturate(
|
|
1901
|
+
--media-backdrop-filter-surface: blur(16px) saturate(125%);
|
|
1859
1902
|
--media-backdrop-filter-indicator: blur(8px);
|
|
1860
|
-
--media-backdrop-filter-dialog: blur(16px) saturate(
|
|
1903
|
+
--media-backdrop-filter-dialog: blur(16px) saturate(125%);
|
|
1861
1904
|
--media-control-corner-shape: round;
|
|
1862
1905
|
--media-control-radius: 99px;
|
|
1863
1906
|
--media-control-size: calc(var(--media-spacing) * 9);
|
|
@@ -1957,10 +2000,20 @@
|
|
|
1957
2000
|
@layer base.preset {
|
|
1958
2001
|
.media-skin:is([data-preset="video"], [data-preset="live-video"]) {
|
|
1959
2002
|
--media-frame-border: var(--media-border-color, #0000001a);
|
|
2003
|
+
--media-controls-gradient-height: max(40%, calc(var(--media-spacing) * 40));
|
|
2004
|
+
--media-controls-bottom-gradient-height: max(50%, calc(var(--media-spacing) * 60));
|
|
1960
2005
|
--media-controls-gradient: linear-gradient(to top,
|
|
1961
|
-
color-mix(in oklab, var(--media-backdrop)
|
|
1962
|
-
color-mix(in oklab, var(--media-backdrop)
|
|
1963
|
-
color-mix(in oklab, var(--media-backdrop)
|
|
2006
|
+
color-mix(in oklab, var(--media-backdrop) 60%, transparent),
|
|
2007
|
+
color-mix(in oklab, var(--media-backdrop) 50.7%, transparent) 25%,
|
|
2008
|
+
color-mix(in oklab, var(--media-backdrop) 30%, transparent) 50%,
|
|
2009
|
+
color-mix(in oklab, var(--media-backdrop) 9.3%, transparent) 75%,
|
|
2010
|
+
transparent);
|
|
2011
|
+
--media-controls-top-gradient: linear-gradient(to bottom,
|
|
2012
|
+
color-mix(in oklab, var(--media-backdrop) 55%, transparent),
|
|
2013
|
+
color-mix(in oklab, var(--media-backdrop) 46.48%, transparent) 25%,
|
|
2014
|
+
color-mix(in oklab, var(--media-backdrop) 27.5%, transparent) 50%,
|
|
2015
|
+
color-mix(in oklab, var(--media-backdrop) 8.53%, transparent) 75%,
|
|
2016
|
+
transparent);
|
|
1964
2017
|
--media-caption-controls-y: calc(var(--media-spacing) * -16);
|
|
1965
2018
|
--media-slider-preview-offset: calc(var(--media-spacing) * 9);
|
|
1966
2019
|
--media-thumbnail-gradient: linear-gradient(to top,
|
|
@@ -1972,9 +2025,17 @@
|
|
|
1972
2025
|
@supports (color: oklch(from red l c h)) and (background-image: linear-gradient(in oklab, red, red)) {
|
|
1973
2026
|
.media-skin:is([data-preset="video"], [data-preset="live-video"]) {
|
|
1974
2027
|
--media-controls-gradient: linear-gradient(to top in oklab,
|
|
1975
|
-
oklch(from var(--media-backdrop) l c h / .
|
|
1976
|
-
oklch(from var(--media-backdrop) l c h / .
|
|
1977
|
-
oklch(from var(--media-backdrop) l c h / .
|
|
2028
|
+
oklch(from var(--media-backdrop) l c h / .6),
|
|
2029
|
+
oklch(from var(--media-backdrop) l c h / .507) 25%,
|
|
2030
|
+
oklch(from var(--media-backdrop) l c h / .3) 50%,
|
|
2031
|
+
oklch(from var(--media-backdrop) l c h / .093) 75%,
|
|
2032
|
+
transparent);
|
|
2033
|
+
--media-controls-top-gradient: linear-gradient(to bottom in oklab,
|
|
2034
|
+
oklch(from var(--media-backdrop) l c h / .55),
|
|
2035
|
+
oklch(from var(--media-backdrop) l c h / .4647) 25%,
|
|
2036
|
+
oklch(from var(--media-backdrop) l c h / .275) 50%,
|
|
2037
|
+
oklch(from var(--media-backdrop) l c h / .0853) 75%,
|
|
2038
|
+
transparent);
|
|
1978
2039
|
}
|
|
1979
2040
|
}
|
|
1980
2041
|
|
|
@@ -1989,9 +2050,20 @@
|
|
|
1989
2050
|
|
|
1990
2051
|
.media-skin:is([data-preset="video"], [data-preset="live-video"])[data-theme="neutral"] {
|
|
1991
2052
|
--media-frame-border: var(--media-border-color, #00000026);
|
|
2053
|
+
--media-controls-gradient-height: 40%;
|
|
2054
|
+
--media-controls-bottom-gradient-height: 40%;
|
|
1992
2055
|
--media-controls-gradient: linear-gradient(to top,
|
|
1993
2056
|
color-mix(in oklab, var(--media-backdrop) 50%, transparent),
|
|
1994
|
-
color-mix(in oklab, var(--media-backdrop)
|
|
2057
|
+
color-mix(in oklab, var(--media-backdrop) 42.2%, transparent) 25%,
|
|
2058
|
+
color-mix(in oklab, var(--media-backdrop) 25%, transparent) 50%,
|
|
2059
|
+
color-mix(in oklab, var(--media-backdrop) 7.8%, transparent) 75%,
|
|
2060
|
+
transparent);
|
|
2061
|
+
--media-controls-top-gradient: linear-gradient(to bottom,
|
|
2062
|
+
color-mix(in oklab, var(--media-backdrop) 50%, transparent),
|
|
2063
|
+
color-mix(in oklab, var(--media-backdrop) 42.2%, transparent) 25%,
|
|
2064
|
+
color-mix(in oklab, var(--media-backdrop) 25%, transparent) 50%,
|
|
2065
|
+
color-mix(in oklab, var(--media-backdrop) 7.8%, transparent) 75%,
|
|
2066
|
+
transparent);
|
|
1995
2067
|
--media-indicator-gradient: linear-gradient(to bottom,
|
|
1996
2068
|
color-mix(in oklab, var(--media-backdrop) 35%, transparent),
|
|
1997
2069
|
color-mix(in oklab, var(--media-backdrop) 20%, transparent) calc(var(--media-spacing) * 12),
|
|
@@ -2001,6 +2073,7 @@
|
|
|
2001
2073
|
}
|
|
2002
2074
|
|
|
2003
2075
|
.media-skin:is([data-preset="video"], [data-preset="live-video"])[data-theme="compat"] {
|
|
2076
|
+
--media-controls-gradient: linear-gradient(to top, #00000080, transparent 40% 60%, #0006);
|
|
2004
2077
|
--media-caption-controls-y: calc(var(--media-spacing) * -18);
|
|
2005
2078
|
}
|
|
2006
2079
|
|
|
@@ -2012,7 +2085,16 @@
|
|
|
2012
2085
|
.media-skin:is([data-preset="video"], [data-preset="live-video"])[data-theme="neutral"] {
|
|
2013
2086
|
--media-controls-gradient: linear-gradient(to top in oklab,
|
|
2014
2087
|
oklch(from var(--media-backdrop) l c h / .5),
|
|
2015
|
-
oklch(from var(--media-backdrop) l c h / .
|
|
2088
|
+
oklch(from var(--media-backdrop) l c h / .422) 25%,
|
|
2089
|
+
oklch(from var(--media-backdrop) l c h / .25) 50%,
|
|
2090
|
+
oklch(from var(--media-backdrop) l c h / .078) 75%,
|
|
2091
|
+
transparent);
|
|
2092
|
+
--media-controls-top-gradient: linear-gradient(to bottom in oklab,
|
|
2093
|
+
oklch(from var(--media-backdrop) l c h / .5),
|
|
2094
|
+
oklch(from var(--media-backdrop) l c h / .422) 25%,
|
|
2095
|
+
oklch(from var(--media-backdrop) l c h / .25) 50%,
|
|
2096
|
+
oklch(from var(--media-backdrop) l c h / .078) 75%,
|
|
2097
|
+
transparent);
|
|
2016
2098
|
}
|
|
2017
2099
|
}
|
|
2018
2100
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { CustomMediaConstructor } from "../../index.js";
|
|
2
|
+
import { DailymotionAdapter } from "@videojs/dailymotion-video";
|
|
3
|
+
//#region src/media/dailymotion-video/adapter.d.ts
|
|
4
|
+
interface DailymotionCustomMediaElement {
|
|
5
|
+
connectedCallback?(): void;
|
|
6
|
+
}
|
|
7
|
+
declare const DailymotionCustomMediaElement_base: CustomMediaConstructor<typeof DailymotionAdapter>;
|
|
8
|
+
declare class DailymotionCustomMediaElement extends DailymotionCustomMediaElement_base {
|
|
9
|
+
static getTemplateHTML: () => string;
|
|
10
|
+
}
|
|
11
|
+
declare const DailymotionVideo_base: typeof DailymotionCustomMediaElement;
|
|
12
|
+
export declare class DailymotionVideo extends DailymotionVideo_base {
|
|
13
|
+
constructor();
|
|
14
|
+
connectedCallback(): void;
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1,47 @@
|
|
|
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 = () => `
|
|
8
|
+
<style>
|
|
9
|
+
:host {
|
|
10
|
+
display: inline-block;
|
|
11
|
+
min-width: 300px;
|
|
12
|
+
min-height: 150px;
|
|
13
|
+
position: relative;
|
|
14
|
+
}
|
|
15
|
+
::slotted([slot=media]) {
|
|
16
|
+
position: absolute;
|
|
17
|
+
inset: 0;
|
|
18
|
+
}
|
|
19
|
+
</style>
|
|
20
|
+
<slot name="media"></slot>
|
|
21
|
+
`;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
var DailymotionVideo = class extends MediaAttachMixin(DailymotionCustomMediaElement) {
|
|
25
|
+
constructor() {
|
|
26
|
+
super();
|
|
27
|
+
this.adapter.addEventListener("volumechange", () => {
|
|
28
|
+
const { muted } = this.adapter;
|
|
29
|
+
if (this.hasAttribute("muted") !== muted) this.toggleAttribute("muted", muted);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
connectedCallback() {
|
|
33
|
+
super.connectedCallback?.();
|
|
34
|
+
const existing = this.querySelector(":scope > [slot=media]");
|
|
35
|
+
if (existing) {
|
|
36
|
+
if (this.adapter.src && !existing.hasChildNodes() && !this.adapter.error) this.adapter.load();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const container = document.createElement("div");
|
|
40
|
+
container.slot = "media";
|
|
41
|
+
this.append(container);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
export { DailymotionVideo };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","names":[],"sources":["../../../../src/media/dailymotion-video/adapter.ts"],"sourcesContent":["import { DailymotionAdapter } from '@videojs/dailymotion-video';\nimport { CustomMediaElement } from '@videojs/media/dom';\n\nimport { MediaAttachMixin } from '../../store/media-attach-mixin';\n\n// `CustomMediaElement` implements `connectedCallback` but doesn't type it; declared so `super` can reach it.\ninterface DailymotionCustomMediaElement {\n connectedCallback?(): void;\n}\n\n// The target is a container the SDK builds its iframe in. `'iframe'` still tells `CustomMediaElement` it hosts an\n// embed: no attributes are mirrored onto the target, and the host is marked as a cross-origin frame. Unlike the other\n// embed hosts, it never keeps the player out of hit-testing: Dailymotion's terms forbid blocking any part of its player.\nclass DailymotionCustomMediaElement extends CustomMediaElement('iframe', DailymotionAdapter) {\n static override getTemplateHTML = (): string => /*html*/ `\n <style>\n :host {\n display: inline-block;\n min-width: 300px;\n min-height: 150px;\n position: relative;\n }\n ::slotted([slot=media]) {\n position: absolute;\n inset: 0;\n }\n </style>\n <slot name=\"media\"></slot>\n `;\n}\n\nexport class DailymotionVideo extends MediaAttachMixin(DailymotionCustomMediaElement) {\n constructor() {\n super();\n\n // Dailymotion can mute the player on its own (a browser's muted autoplay, a click on its own mute button). Writes\n // to `muted` go through the `muted` attribute, so it follows the player, or a later unmute would find nothing to\n // change. The attribute change sets the same value back, which the adapter ignores.\n this.adapter.addEventListener('volumechange', () => {\n const { muted } = this.adapter;\n\n if (this.hasAttribute('muted') !== muted) this.toggleAttribute('muted', muted);\n });\n }\n\n override connectedCallback(): void {\n super.connectedCallback?.();\n\n // The SDK finds the container by id from the document, so it lives in the light DOM, slotted as `media` to become\n // the adapter's target. Added here because a constructor may not add children.\n const existing = this.querySelector(':scope > [slot=media]');\n\n if (existing) {\n // Attached before the host was in the page, the container stayed empty; load the source now.\n if (this.adapter.src && !existing.hasChildNodes() && !this.adapter.error) this.adapter.load();\n\n return;\n }\n\n const container = document.createElement('div');\n\n container.slot = 'media';\n this.append(container);\n }\n}\n"],"mappings":";;;;AAaA,IAAM,gCAAN,cAA4C,mBAAmB,UAAU,kBAAkB,CAAC,CAAC;;EAClC,KAAA,wBAAA;;;;;;;;;;;;;;;;AAe3D;AAEA,IAAa,mBAAb,cAAsC,iBAAiB,6BAA6B,CAAC,CAAC;CACpF,cAAc;EACZ,MAAM;EAKN,KAAK,QAAQ,iBAAiB,sBAAsB;GAClD,MAAM,EAAE,UAAU,KAAK;GAEvB,IAAI,KAAK,aAAa,OAAO,MAAM,OAAO,KAAK,gBAAgB,SAAS,KAAK;EAC/E,CAAC;CACH;CAEA,oBAAmC;EACjC,MAAM,oBAAoB;EAI1B,MAAM,WAAW,KAAK,cAAc,uBAAuB;EAE3D,IAAI,UAAU;GAEZ,IAAI,KAAK,QAAQ,OAAO,CAAC,SAAS,cAAc,KAAK,CAAC,KAAK,QAAQ,OAAO,KAAK,QAAQ,KAAK;GAE5F;EACF;EAEA,MAAM,YAAY,SAAS,cAAc,KAAK;EAE9C,UAAU,OAAO;EACjB,KAAK,OAAO,SAAS;CACvB;AACF"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getTemplateHTML } from "../background-video/template.js";
|
|
2
2
|
import { Media } from "@videojs/media/dom";
|
|
3
|
-
import { HlsVideoMediaError } from "@videojs/spf/adapters/hls-background-video";
|
|
3
|
+
import { HlsBackgroundVideoAdapter, HlsVideoMediaError } from "@videojs/spf/adapters/hls-background-video";
|
|
4
4
|
//#region src/media/hls-background-video/adapter.d.ts
|
|
5
5
|
interface LifecycleElement extends HTMLElement {
|
|
6
6
|
connectedCallback?(): void;
|
|
@@ -53,6 +53,11 @@ export declare class HlsBackgroundVideo extends HlsBackgroundVideoBase {
|
|
|
53
53
|
constructor();
|
|
54
54
|
/** Register the Media (not the inner `<video>`) with the provider. */
|
|
55
55
|
getMediaTarget(): Media | null;
|
|
56
|
+
/**
|
|
57
|
+
* The Media driving the inner `<video>`, matching `adapter` on `CustomMediaElement`. Call `adapter.destroy()` to
|
|
58
|
+
* release the engine after `keep-alive` kept it running past removal.
|
|
59
|
+
*/
|
|
60
|
+
get adapter(): HlsBackgroundVideoAdapter;
|
|
56
61
|
disconnectedCallback(): void;
|
|
57
62
|
attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void;
|
|
58
63
|
/** The inner `<video>` the engine renders into. */
|
|
@@ -73,6 +73,13 @@ var HlsBackgroundVideo = class extends HlsBackgroundVideoBase {
|
|
|
73
73
|
getMediaTarget() {
|
|
74
74
|
return this.#media;
|
|
75
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* The Media driving the inner `<video>`, matching `adapter` on `CustomMediaElement`. Call `adapter.destroy()` to
|
|
78
|
+
* release the engine after `keep-alive` kept it running past removal.
|
|
79
|
+
*/
|
|
80
|
+
get adapter() {
|
|
81
|
+
return this.#media;
|
|
82
|
+
}
|
|
76
83
|
disconnectedCallback() {
|
|
77
84
|
super.disconnectedCallback?.();
|
|
78
85
|
if (this.hasAttribute("keep-alive")) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.js","names":[],"sources":["../../../../src/media/hls-background-video/adapter.ts"],"sourcesContent":["import type { Media } from '@videojs/media/dom';\nimport { HlsBackgroundVideoAdapter, type HlsVideoMediaError } from '@videojs/spf/adapters/hls-background-video';\nimport { namedNodeMapToObject } from '@videojs/utils/dom';\n\nimport { MediaAttachMixin } from '../../store/media-attach-mixin';\nimport { getTemplateHTML } from '../background-video/template';\n\nconst HTMLElementBase = globalThis.HTMLElement ?? class {};\n\n// `MediaAttachMixin` is typed as returning its base, so its `disconnectedCallback`\n// isn't visible for `super` to reach. `LifecycleElement` declares the lifecycle\n// callbacks this element overrides; method syntax lets a subclass override them.\ninterface LifecycleElement extends HTMLElement {\n connectedCallback?(): void;\n disconnectedCallback?(): void;\n adoptedCallback?(): void;\n attributeChangedCallback?(name: string, oldValue: string | null, newValue: string | null): void;\n}\n\nconst HlsBackgroundVideoBase = MediaAttachMixin(HTMLElementBase) as unknown as new () => LifecycleElement;\n\n/**\n * A muted, looping, chrome-less video over the SPF background-video engine.\n *\n * The SPF-backed counterpart to `<background-video>`, which plays its source natively. This one streams HLS through the\n * engine, which pins a single rendition for the session rather than adapting, and drops audio and text handling\n * entirely — the shape an ambient hero video actually wants.\n *\n * Nearer an image than a player, and `src` is the whole surface. Replaces the standalone `mux-background-video`\n * package, whose `audio`, `debug`, `preload`, and `max-resolution` attributes are all deliberately absent. Capping\n * which rendition is fetched is a delivery param on the URL — `?max_resolution=720p` on a Mux stream, for one — which\n * keeps the renditions it excludes out of the manifest rather than merely unpicked; `preload` would have nothing to\n * say, since the engine loads from the moment it has a source. And unlike `<background-video>` there are no `nomuted` /\n * `noloop` / `noautoplay` opt-outs: those three are what this element is for, so the adapter fixes them on at attach.\n *\n * Takes no structured `source` — `src` is an HLS URL, as the package it replaces required. Mux playback-ID identity,\n * poster, and storyboard belong to `<mux-video>`; none of them mean anything without controls to hang them on.\n *\n * Nothing about an unplayable source reaches the inner `<video>` on its own, so `error` on it stays null and the\n * element sits at `readyState 0`. The engine reports each condition and logs it, the Media promotes the fatal one, and\n * this element re-fires it as its own `error` / `'error'` — the one place a consumer holding the element can see a\n * source that never appears.\n *\n * @example\n * ```html\n * <hls-background-video src=\"https://stream.mux.com/PLAYBACK_ID.m3u8?max_resolution=720p\">\n * <img src=\"https://image.mux.com/PLAYBACK_ID/thumbnail.webp?time=0\" alt=\"\" />\n * </hls-background-video>\n * ```;\n *\n * @fires error - Fired when a fatal condition is reported. Read `error` for it.\n *\n * `<mux-background-video>` is this element under the name the package it replaces used. Same class, so the tag is a\n * naming choice and nothing more.\n */\n// Deliberately not `CustomMediaElement`, matching `<background-video>`: a\n// background video needs one property, not the full WHATWG media API.\nexport class HlsBackgroundVideo extends HlsBackgroundVideoBase {\n static shadowRootOptions = { mode: 'open' as ShadowRootMode };\n static getTemplateHTML = getTemplateHTML;\n\n static get observedAttributes(): string[] {\n return ['src'];\n }\n\n #media = new HlsBackgroundVideoAdapter();\n\n constructor() {\n super();\n\n if (!this.shadowRoot) {\n this.attachShadow((this.constructor as typeof HlsBackgroundVideo).shadowRootOptions);\n\n const attrs = {\n ...namedNodeMapToObject(this.attributes),\n muted: '',\n loop: '',\n autoplay: '',\n playsinline: '',\n disableremoteplayback: '',\n disablepictureinpicture: '',\n };\n\n this.shadowRoot!.innerHTML = getTemplateHTML(attrs);\n }\n\n // Neither Chrome nor Firefox honor a `muted` attribute set after\n // `document.createElement`, and autoplay is refused without it. Attaching is\n // what sets the property — along with the rest of the fixed behavior — so\n // nothing here needs to repeat it.\n const video = this.video;\n\n if (video) this.#media.attach(video);\n\n // Re-fired rather than bridged on demand the way `CustomMediaElement` does\n // it: one listener for the one event this element has, on a Media it owns\n // for its whole life, is less than the machinery to defer it would cost.\n this.#media.addEventListener('error', () => this.dispatchEvent(new Event('error')));\n }\n\n /** Register the Media (not the inner `<video>`) with the provider. */\n getMediaTarget(): Media | null {\n return this.#media as unknown as Media;\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback?.();\n\n if (this.hasAttribute('keep-alive')) return;\n\n // Deferred so a synchronous reparent (remove then insert) doesn't tear down\n // the engine, matching `CustomMediaElement`.\n queueMicrotask(() => {\n if (!this.isConnected) this.#media.destroy();\n });\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n if (name === 'src') this.src = newValue ?? '';\n }\n\n /** The inner `<video>` the engine renders into. */\n get video(): HTMLVideoElement | null {\n const video = this.shadowRoot?.querySelector('video');\n\n return video instanceof HTMLVideoElement ? video : null;\n }\n\n /**\n * What made the current source unplayable, or `null`. An SVTA code rather than a `MediaError` one — 99001 where this\n * player has no pipeline for what the source needs, with the specifics logged. Reset by a new source, and not on the\n * inner `<video>`, which never learns of it.\n */\n get error(): HlsVideoMediaError | null {\n return this.#media.error;\n }\n\n /** HLS manifest URL. Assigning a new one restarts playback from scratch. */\n get src(): string {\n return this.#media.src;\n }\n\n set src(value: string) {\n this.#media.src = value;\n }\n}\n"],"mappings":";;;;;AAOA,MAAM,kBAAkB,WAAW,eAAe,MAAM,CAAC;AAYzD,MAAM,yBAAyB,iBAAiB,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsC/D,IAAa,qBAAb,cAAwC,uBAAuB;;EAClC,KAAA,oBAAA,EAAE,MAAM,OAAyB;;;EACnC,KAAA,kBAAA;;CAEzB,WAAW,qBAA+B;EACxC,OAAO,CAAC,KAAK;CACf;CAEA,SAAS,IAAI,0BAA0B;CAEvC,cAAc;EACZ,MAAM;EAEN,IAAI,CAAC,KAAK,YAAY;GACpB,KAAK,aAAc,KAAK,YAA0C,iBAAiB;GAEnF,MAAM,QAAQ;IACZ,GAAG,qBAAqB,KAAK,UAAU;IACvC,OAAO;IACP,MAAM;IACN,UAAU;IACV,aAAa;IACb,uBAAuB;IACvB,yBAAyB;GAC3B;GAEA,KAAK,WAAY,YAAY,gBAAgB,KAAK;EACpD;EAMA,MAAM,QAAQ,KAAK;EAEnB,IAAI,OAAO,KAAK,OAAO,OAAO,KAAK;EAKnC,KAAK,OAAO,iBAAiB,eAAe,KAAK,cAAc,IAAI,MAAM,OAAO,CAAC,CAAC;CACpF;;CAGA,iBAA+B;EAC7B,OAAO,KAAK;CACd;CAEA,uBAAsC;EACpC,MAAM,uBAAuB;
|
|
1
|
+
{"version":3,"file":"adapter.js","names":[],"sources":["../../../../src/media/hls-background-video/adapter.ts"],"sourcesContent":["import type { Media } from '@videojs/media/dom';\nimport { HlsBackgroundVideoAdapter, type HlsVideoMediaError } from '@videojs/spf/adapters/hls-background-video';\nimport { namedNodeMapToObject } from '@videojs/utils/dom';\n\nimport { MediaAttachMixin } from '../../store/media-attach-mixin';\nimport { getTemplateHTML } from '../background-video/template';\n\nconst HTMLElementBase = globalThis.HTMLElement ?? class {};\n\n// `MediaAttachMixin` is typed as returning its base, so its `disconnectedCallback`\n// isn't visible for `super` to reach. `LifecycleElement` declares the lifecycle\n// callbacks this element overrides; method syntax lets a subclass override them.\ninterface LifecycleElement extends HTMLElement {\n connectedCallback?(): void;\n disconnectedCallback?(): void;\n adoptedCallback?(): void;\n attributeChangedCallback?(name: string, oldValue: string | null, newValue: string | null): void;\n}\n\nconst HlsBackgroundVideoBase = MediaAttachMixin(HTMLElementBase) as unknown as new () => LifecycleElement;\n\n/**\n * A muted, looping, chrome-less video over the SPF background-video engine.\n *\n * The SPF-backed counterpart to `<background-video>`, which plays its source natively. This one streams HLS through the\n * engine, which pins a single rendition for the session rather than adapting, and drops audio and text handling\n * entirely — the shape an ambient hero video actually wants.\n *\n * Nearer an image than a player, and `src` is the whole surface. Replaces the standalone `mux-background-video`\n * package, whose `audio`, `debug`, `preload`, and `max-resolution` attributes are all deliberately absent. Capping\n * which rendition is fetched is a delivery param on the URL — `?max_resolution=720p` on a Mux stream, for one — which\n * keeps the renditions it excludes out of the manifest rather than merely unpicked; `preload` would have nothing to\n * say, since the engine loads from the moment it has a source. And unlike `<background-video>` there are no `nomuted` /\n * `noloop` / `noautoplay` opt-outs: those three are what this element is for, so the adapter fixes them on at attach.\n *\n * Takes no structured `source` — `src` is an HLS URL, as the package it replaces required. Mux playback-ID identity,\n * poster, and storyboard belong to `<mux-video>`; none of them mean anything without controls to hang them on.\n *\n * Nothing about an unplayable source reaches the inner `<video>` on its own, so `error` on it stays null and the\n * element sits at `readyState 0`. The engine reports each condition and logs it, the Media promotes the fatal one, and\n * this element re-fires it as its own `error` / `'error'` — the one place a consumer holding the element can see a\n * source that never appears.\n *\n * @example\n * ```html\n * <hls-background-video src=\"https://stream.mux.com/PLAYBACK_ID.m3u8?max_resolution=720p\">\n * <img src=\"https://image.mux.com/PLAYBACK_ID/thumbnail.webp?time=0\" alt=\"\" />\n * </hls-background-video>\n * ```;\n *\n * @fires error - Fired when a fatal condition is reported. Read `error` for it.\n *\n * `<mux-background-video>` is this element under the name the package it replaces used. Same class, so the tag is a\n * naming choice and nothing more.\n */\n// Deliberately not `CustomMediaElement`, matching `<background-video>`: a\n// background video needs one property, not the full WHATWG media API.\nexport class HlsBackgroundVideo extends HlsBackgroundVideoBase {\n static shadowRootOptions = { mode: 'open' as ShadowRootMode };\n static getTemplateHTML = getTemplateHTML;\n\n static get observedAttributes(): string[] {\n return ['src'];\n }\n\n #media = new HlsBackgroundVideoAdapter();\n\n constructor() {\n super();\n\n if (!this.shadowRoot) {\n this.attachShadow((this.constructor as typeof HlsBackgroundVideo).shadowRootOptions);\n\n const attrs = {\n ...namedNodeMapToObject(this.attributes),\n muted: '',\n loop: '',\n autoplay: '',\n playsinline: '',\n disableremoteplayback: '',\n disablepictureinpicture: '',\n };\n\n this.shadowRoot!.innerHTML = getTemplateHTML(attrs);\n }\n\n // Neither Chrome nor Firefox honor a `muted` attribute set after\n // `document.createElement`, and autoplay is refused without it. Attaching is\n // what sets the property — along with the rest of the fixed behavior — so\n // nothing here needs to repeat it.\n const video = this.video;\n\n if (video) this.#media.attach(video);\n\n // Re-fired rather than bridged on demand the way `CustomMediaElement` does\n // it: one listener for the one event this element has, on a Media it owns\n // for its whole life, is less than the machinery to defer it would cost.\n this.#media.addEventListener('error', () => this.dispatchEvent(new Event('error')));\n }\n\n /** Register the Media (not the inner `<video>`) with the provider. */\n getMediaTarget(): Media | null {\n return this.#media as unknown as Media;\n }\n\n /**\n * The Media driving the inner `<video>`, matching `adapter` on `CustomMediaElement`. Call `adapter.destroy()` to\n * release the engine after `keep-alive` kept it running past removal.\n */\n get adapter(): HlsBackgroundVideoAdapter {\n return this.#media;\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback?.();\n\n // Only the element's own `keep-alive` counts: an ancestor's `destroy()` can't reach this engine, so inheriting it\n // would leave the engine running with nothing to release it.\n if (this.hasAttribute('keep-alive')) return;\n\n // Deferred so a synchronous reparent (remove then insert) doesn't tear down\n // the engine, matching `CustomMediaElement`.\n queueMicrotask(() => {\n if (!this.isConnected) this.#media.destroy();\n });\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n if (name === 'src') this.src = newValue ?? '';\n }\n\n /** The inner `<video>` the engine renders into. */\n get video(): HTMLVideoElement | null {\n const video = this.shadowRoot?.querySelector('video');\n\n return video instanceof HTMLVideoElement ? video : null;\n }\n\n /**\n * What made the current source unplayable, or `null`. An SVTA code rather than a `MediaError` one — 99001 where this\n * player has no pipeline for what the source needs, with the specifics logged. Reset by a new source, and not on the\n * inner `<video>`, which never learns of it.\n */\n get error(): HlsVideoMediaError | null {\n return this.#media.error;\n }\n\n /** HLS manifest URL. Assigning a new one restarts playback from scratch. */\n get src(): string {\n return this.#media.src;\n }\n\n set src(value: string) {\n this.#media.src = value;\n }\n}\n"],"mappings":";;;;;AAOA,MAAM,kBAAkB,WAAW,eAAe,MAAM,CAAC;AAYzD,MAAM,yBAAyB,iBAAiB,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsC/D,IAAa,qBAAb,cAAwC,uBAAuB;;EAClC,KAAA,oBAAA,EAAE,MAAM,OAAyB;;;EACnC,KAAA,kBAAA;;CAEzB,WAAW,qBAA+B;EACxC,OAAO,CAAC,KAAK;CACf;CAEA,SAAS,IAAI,0BAA0B;CAEvC,cAAc;EACZ,MAAM;EAEN,IAAI,CAAC,KAAK,YAAY;GACpB,KAAK,aAAc,KAAK,YAA0C,iBAAiB;GAEnF,MAAM,QAAQ;IACZ,GAAG,qBAAqB,KAAK,UAAU;IACvC,OAAO;IACP,MAAM;IACN,UAAU;IACV,aAAa;IACb,uBAAuB;IACvB,yBAAyB;GAC3B;GAEA,KAAK,WAAY,YAAY,gBAAgB,KAAK;EACpD;EAMA,MAAM,QAAQ,KAAK;EAEnB,IAAI,OAAO,KAAK,OAAO,OAAO,KAAK;EAKnC,KAAK,OAAO,iBAAiB,eAAe,KAAK,cAAc,IAAI,MAAM,OAAO,CAAC,CAAC;CACpF;;CAGA,iBAA+B;EAC7B,OAAO,KAAK;CACd;;;;;CAMA,IAAI,UAAqC;EACvC,OAAO,KAAK;CACd;CAEA,uBAAsC;EACpC,MAAM,uBAAuB;EAI7B,IAAI,KAAK,aAAa,YAAY,GAAG;EAIrC,qBAAqB;GACnB,IAAI,CAAC,KAAK,aAAa,KAAK,OAAO,QAAQ;EAC7C,CAAC;CACH;CAEA,yBAAyB,MAAc,UAAyB,UAA+B;EAC7F,IAAI,aAAa,UAAU;EAE3B,IAAI,SAAS,OAAO,KAAK,MAAM,YAAY;CAC7C;;CAGA,IAAI,QAAiC;EACnC,MAAM,QAAQ,KAAK,YAAY,cAAc,OAAO;EAEpD,OAAO,iBAAiB,mBAAmB,QAAQ;CACrD;;;;;;CAOA,IAAI,QAAmC;EACrC,OAAO,KAAK,OAAO;CACrB;;CAGA,IAAI,MAAc;EAChB,OAAO,KAAK,OAAO;CACrB;CAEA,IAAI,IAAI,OAAe;EACrB,KAAK,OAAO,MAAM;CACpB;AACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { CustomMediaConstructor } from "../../index.js";
|
|
2
|
+
import { MixcloudAdapter } from "@videojs/mixcloud-audio";
|
|
3
|
+
//#region src/media/mixcloud-audio/adapter.d.ts
|
|
4
|
+
declare const MixcloudCustomMediaElement_base: CustomMediaConstructor<typeof MixcloudAdapter>;
|
|
5
|
+
declare class MixcloudCustomMediaElement extends MixcloudCustomMediaElement_base {
|
|
6
|
+
static getTemplateHTML: (attrs: Record<string, string>) => string;
|
|
7
|
+
}
|
|
8
|
+
declare const MixcloudAudio_base: typeof MixcloudCustomMediaElement;
|
|
9
|
+
export declare class MixcloudAudio extends MixcloudAudio_base {}
|
|
10
|
+
//#endregion
|
|
11
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1,52 @@
|
|
|
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 `
|
|
11
|
+
<style>
|
|
12
|
+
:host {
|
|
13
|
+
display: block;
|
|
14
|
+
position: relative;
|
|
15
|
+
height: 120px;
|
|
16
|
+
}
|
|
17
|
+
iframe {
|
|
18
|
+
position: absolute;
|
|
19
|
+
inset: 0;
|
|
20
|
+
width: 100%;
|
|
21
|
+
height: 100%;
|
|
22
|
+
border: 0;
|
|
23
|
+
}
|
|
24
|
+
/*
|
|
25
|
+
* The widget is Mixcloud's own chrome, so without controls it is a
|
|
26
|
+
* transport and nothing else. Hidden rather than merely inert, and
|
|
27
|
+
* important so a consumer's own display rule cannot put it back on
|
|
28
|
+
* screen. An iframe in a hidden subtree still loads and plays its src.
|
|
29
|
+
*/
|
|
30
|
+
:host(:not([controls])) {
|
|
31
|
+
display: none !important;
|
|
32
|
+
}
|
|
33
|
+
</style>
|
|
34
|
+
<iframe
|
|
35
|
+
part="iframe"
|
|
36
|
+
title="Mixcloud audio player"
|
|
37
|
+
${initialSrc ? ` src="${escapeHtml(initialSrc)}"` : ""}
|
|
38
|
+
allow="autoplay; encrypted-media"
|
|
39
|
+
frameborder="0"
|
|
40
|
+
width="100%"
|
|
41
|
+
height="100%"
|
|
42
|
+
referrerpolicy="${escapeHtml(attrs.referrerpolicy ?? "")}"
|
|
43
|
+
></iframe>
|
|
44
|
+
`;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var MixcloudAudio = class extends MediaAttachMixin(MixcloudCustomMediaElement) {};
|
|
49
|
+
//#endregion
|
|
50
|
+
export { MixcloudAudio };
|
|
51
|
+
|
|
52
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","names":[],"sources":["../../../../src/media/mixcloud-audio/adapter.ts"],"sourcesContent":["import { CustomMediaElement } from '@videojs/media/dom';\nimport { buildMixcloudIframeSrc, MixcloudAdapter } from '@videojs/mixcloud-audio';\nimport { escapeHtml } from '@videojs/utils/string';\n\nimport { MediaAttachMixin } from '../../store/media-attach-mixin';\n\nclass MixcloudCustomMediaElement extends CustomMediaElement('iframe', MixcloudAdapter) {\n static override getTemplateHTML = (attrs: Record<string, string>): string => {\n const initialSrc = buildMixcloudIframeSrc(attrs.src ?? '');\n const srcAttr = initialSrc ? ` src=\"${escapeHtml(initialSrc)}\"` : '';\n\n return /*html*/ `\n <style>\n :host {\n display: block;\n position: relative;\n height: 120px;\n }\n iframe {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n border: 0;\n }\n /*\n * The widget is Mixcloud's own chrome, so without controls it is a\n * transport and nothing else. Hidden rather than merely inert, and\n * important so a consumer's own display rule cannot put it back on\n * screen. An iframe in a hidden subtree still loads and plays its src.\n */\n :host(:not([controls])) {\n display: none !important;\n }\n </style>\n <iframe\n part=\"iframe\"\n title=\"Mixcloud audio player\"\n ${srcAttr}\n allow=\"autoplay; encrypted-media\"\n frameborder=\"0\"\n width=\"100%\"\n height=\"100%\"\n referrerpolicy=\"${escapeHtml(attrs.referrerpolicy ?? '')}\"\n ></iframe>\n `;\n };\n}\n\nexport class MixcloudAudio extends MediaAttachMixin(MixcloudCustomMediaElement) {}\n"],"mappings":";;;;;AAMA,IAAM,6BAAN,cAAyC,mBAAmB,UAAU,eAAe,CAAC,CAAC;;EAClD,KAAA,mBAAA,UAA0C;GAC3E,MAAM,aAAa,uBAAuB,MAAM,OAAO,EAAE;GAGzD,OAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;UAFA,aAAa,SAAS,WAAW,UAAU,EAAE,KAAK,GA6BpD;;;;;0BAKQ,WAAW,MAAM,kBAAkB,EAAE,EAAE;;;EAG/D;;AACF;AAEA,IAAa,gBAAb,cAAmC,iBAAiB,0BAA0B,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { CustomMediaConstructor } from "../../index.js";
|
|
2
|
+
import { SoundCloudAdapter } from "@videojs/soundcloud-audio";
|
|
3
|
+
//#region src/media/soundcloud-audio/adapter.d.ts
|
|
4
|
+
declare const SoundCloudCustomMediaElement_base: CustomMediaConstructor<typeof SoundCloudAdapter>;
|
|
5
|
+
declare class SoundCloudCustomMediaElement extends SoundCloudCustomMediaElement_base {
|
|
6
|
+
static getTemplateHTML: (attrs: Record<string, string>) => string;
|
|
7
|
+
}
|
|
8
|
+
declare const SoundCloudAudio_base: typeof SoundCloudCustomMediaElement;
|
|
9
|
+
export declare class SoundCloudAudio extends SoundCloudAudio_base {}
|
|
10
|
+
//#endregion
|
|
11
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1,53 @@
|
|
|
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 `
|
|
11
|
+
<style>
|
|
12
|
+
:host {
|
|
13
|
+
display: block;
|
|
14
|
+
position: relative;
|
|
15
|
+
height: 166px;
|
|
16
|
+
}
|
|
17
|
+
iframe {
|
|
18
|
+
position: absolute;
|
|
19
|
+
inset: 0;
|
|
20
|
+
width: 100%;
|
|
21
|
+
height: 100%;
|
|
22
|
+
border: 0;
|
|
23
|
+
}
|
|
24
|
+
/*
|
|
25
|
+
* The widget is SoundCloud's own chrome, so without controls it is a
|
|
26
|
+
* transport and nothing else. Hidden rather than merely inert, and
|
|
27
|
+
* important so a consumer's own display rule cannot put it back on
|
|
28
|
+
* screen. An iframe in a hidden subtree still loads and plays its src.
|
|
29
|
+
*/
|
|
30
|
+
:host(:not([controls])) {
|
|
31
|
+
display: none !important;
|
|
32
|
+
}
|
|
33
|
+
</style>
|
|
34
|
+
<iframe
|
|
35
|
+
part="iframe"
|
|
36
|
+
title="SoundCloud audio player"
|
|
37
|
+
${initialSrc ? ` src="${escapeHtml(initialSrc)}"` : ""}
|
|
38
|
+
allow="autoplay; encrypted-media"
|
|
39
|
+
scrolling="no"
|
|
40
|
+
frameborder="0"
|
|
41
|
+
width="100%"
|
|
42
|
+
height="100%"
|
|
43
|
+
referrerpolicy="${escapeHtml(attrs.referrerpolicy ?? "")}"
|
|
44
|
+
></iframe>
|
|
45
|
+
`;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var SoundCloudAudio = class extends MediaAttachMixin(SoundCloudCustomMediaElement) {};
|
|
50
|
+
//#endregion
|
|
51
|
+
export { SoundCloudAudio };
|
|
52
|
+
|
|
53
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","names":[],"sources":["../../../../src/media/soundcloud-audio/adapter.ts"],"sourcesContent":["import { CustomMediaElement } from '@videojs/media/dom';\nimport { buildSoundCloudIframeSrc, SoundCloudAdapter } from '@videojs/soundcloud-audio';\nimport { escapeHtml } from '@videojs/utils/string';\n\nimport { MediaAttachMixin } from '../../store/media-attach-mixin';\n\nclass SoundCloudCustomMediaElement extends CustomMediaElement('iframe', SoundCloudAdapter) {\n static override getTemplateHTML = (attrs: Record<string, string>): string => {\n const initialSrc = buildSoundCloudIframeSrc(attrs.src ?? '');\n const srcAttr = initialSrc ? ` src=\"${escapeHtml(initialSrc)}\"` : '';\n\n return /*html*/ `\n <style>\n :host {\n display: block;\n position: relative;\n height: 166px;\n }\n iframe {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n border: 0;\n }\n /*\n * The widget is SoundCloud's own chrome, so without controls it is a\n * transport and nothing else. Hidden rather than merely inert, and\n * important so a consumer's own display rule cannot put it back on\n * screen. An iframe in a hidden subtree still loads and plays its src.\n */\n :host(:not([controls])) {\n display: none !important;\n }\n </style>\n <iframe\n part=\"iframe\"\n title=\"SoundCloud audio player\"\n ${srcAttr}\n allow=\"autoplay; encrypted-media\"\n scrolling=\"no\"\n frameborder=\"0\"\n width=\"100%\"\n height=\"100%\"\n referrerpolicy=\"${escapeHtml(attrs.referrerpolicy ?? '')}\"\n ></iframe>\n `;\n };\n}\n\nexport class SoundCloudAudio extends MediaAttachMixin(SoundCloudCustomMediaElement) {}\n"],"mappings":";;;;;AAMA,IAAM,+BAAN,cAA2C,mBAAmB,UAAU,iBAAiB,CAAC,CAAC;;EACtD,KAAA,mBAAA,UAA0C;GAC3E,MAAM,aAAa,yBAAyB,MAAM,OAAO,EAAE;GAG3D,OAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;UAFA,aAAa,SAAS,WAAW,UAAU,EAAE,KAAK,GA6BpD;;;;;;0BAMQ,WAAW,MAAM,kBAAkB,EAAE,EAAE;;;EAG/D;;AACF;AAEA,IAAa,kBAAb,cAAqC,iBAAiB,4BAA4B,CAAC,CAAC,CAAC"}
|
|
@@ -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
|
|
@@ -29,7 +29,6 @@ function createPlayerElement(options) {
|
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
#store = options.factory();
|
|
32
|
-
#contextRoot = new ContextRoot();
|
|
33
32
|
#configuredStore = null;
|
|
34
33
|
#detach = null;
|
|
35
34
|
#connected = false;
|
|
@@ -96,7 +95,6 @@ function createPlayerElement(options) {
|
|
|
96
95
|
}
|
|
97
96
|
connectedCallback() {
|
|
98
97
|
this.#connected = true;
|
|
99
|
-
this.#contextRoot.attach(this);
|
|
100
98
|
super.connectedCallback();
|
|
101
99
|
this.#syncInitialConfig();
|
|
102
100
|
this.#playerProvider.setValue(this.store);
|
|
@@ -113,13 +111,11 @@ function createPlayerElement(options) {
|
|
|
113
111
|
}
|
|
114
112
|
disconnectedCallback() {
|
|
115
113
|
this.#connected = false;
|
|
116
|
-
this.#contextRoot.detach(this);
|
|
117
114
|
this.#observer.disconnect();
|
|
118
115
|
this.#detachStore();
|
|
119
116
|
super.disconnectedCallback();
|
|
120
117
|
}
|
|
121
118
|
destroyCallback() {
|
|
122
|
-
this.#contextRoot.detach(this);
|
|
123
119
|
this.#observer.disconnect();
|
|
124
120
|
this.#detachStore();
|
|
125
121
|
this.#extensions.destroy();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"element.js","names":[],"sources":["../../../src/player/element.ts"],"sourcesContent":["import {\n type MediaContainer,\n type PlayerExtension,\n PlayerExtensionCoordinator,\n type PlayerFeatureConfig,\n type PlayerStore,\n type PlayerTarget,\n setPlayerConfigValue,\n} from '@videojs/core/dom';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport { ContextProvider, ContextRoot } from '@videojs/element/context';\nimport type { Media } from '@videojs/media/dom';\nimport { isNull } from '@videojs/utils/predicate';\nimport { camelCase, kebabCase } from '@videojs/utils/string';\n\nimport type { PlayerElementConstructor } from '../store/types';\nimport { UIElement } from '../ui/ui-element';\nimport type { ContainerContext, ExtensionContext, MediaContext, PlayerContext } from './context';\n\nexport interface CreatePlayerElementOptions<Store extends PlayerStore> {\n playerContext: PlayerContext<Store>;\n mediaContext: MediaContext;\n containerContext: ContainerContext;\n extensionContext: ExtensionContext;\n factory: () => Store;\n config: PlayerFeatureConfig;\n}\n\ninterface Registration<Value> {\n value: Value;\n}\n\ninterface ConfigInput {\n property: string;\n attribute: string;\n entry: PlayerFeatureConfig[string];\n}\n\nfunction resolveInputs(config: PlayerFeatureConfig): ConfigInput[] {\n return Object.entries(config).map(([key, entry]) => {\n const declared = entry.html?.attribute;\n const attribute = declared ?? kebabCase(key);\n\n if (__DEV__ && declared && declared !== kebabCase(declared)) {\n console.warn(`[vjs-html] config html.attribute \"${declared}\" is not kebab-case and will never match`);\n }\n\n return { property: camelCase(attribute), attribute, entry };\n });\n}\n\n/** Creates a configured player element class that owns the store and attach lifecycle. */\nexport function createPlayerElement<Store extends PlayerStore>(\n options: CreatePlayerElementOptions<Store>\n): PlayerElementConstructor<Store>;\nexport function createPlayerElement<Store extends PlayerStore>(\n options: CreatePlayerElementOptions<Store>\n): typeof UIElement {\n const inputs = resolveInputs(options.config);\n\n class ConfiguredPlayerElement extends UIElement {\n static properties = {\n ...UIElement.properties,\n ...Object.fromEntries(inputs.map(({ property, attribute }) => [property, { type: String, attribute }])),\n } satisfies PropertyDeclarationMap;\n\n #store: Store | null = options.factory();\n readonly #contextRoot = new ContextRoot();\n #configuredStore: Store | null = null;\n #detach: (() => void) | null = null;\n #connected = false;\n #media: Media | null = null;\n #nativeMedia: HTMLMediaElement | null = null;\n #container: MediaContainer | null = null;\n // The raw target the store is attached to; `store.target.media` may be the extensions' facade over it.\n #attached: PlayerTarget | null = null;\n #mediaRegistrations: Registration<Media>[] = [];\n #containerRegistrations: Registration<MediaContainer>[] = [];\n #observer = new MutationObserver(() => this.#syncNativeMedia());\n #extensions = new PlayerExtensionCoordinator(() => this.#syncExtensions());\n\n #registerExtension = (extension: PlayerExtension): (() => void) => this.#extensions.register(extension);\n\n #registerMedia = (media: Media): (() => void) => {\n const registration = { value: media };\n\n this.#mediaRegistrations.push(registration);\n this.#syncMedia();\n\n return () => {\n const index = this.#mediaRegistrations.indexOf(registration);\n if (index < 0) return;\n\n this.#mediaRegistrations.splice(index, 1);\n this.#syncNativeMedia();\n this.#syncMedia();\n };\n };\n\n #registerContainer = (container: MediaContainer): (() => void) => {\n const registration = { value: container };\n\n this.#containerRegistrations.push(registration);\n this.#syncContainer();\n\n return () => {\n const index = this.#containerRegistrations.indexOf(registration);\n if (index < 0) return;\n\n this.#containerRegistrations.splice(index, 1);\n this.#syncContainer();\n };\n };\n\n #playerProvider = new ContextProvider(this, {\n context: options.playerContext,\n initialValue: this.store,\n });\n\n #mediaProvider = new ContextProvider(this, {\n context: options.mediaContext,\n initialValue: { media: this.#media, registerMedia: this.#registerMedia },\n });\n\n #containerProvider = new ContextProvider(this, {\n context: options.containerContext,\n initialValue: {\n container: this.#container,\n registerContainer: this.#registerContainer,\n },\n });\n\n constructor() {\n super();\n // Registers itself as a controller on this element; the value never changes, so nothing reads it back.\n new ContextProvider(this, {\n context: options.extensionContext,\n initialValue: { registerExtension: this.#registerExtension },\n });\n }\n\n get store(): Store {\n if (isNull(this.#store)) {\n this.#store = options.factory();\n }\n\n return this.#store;\n }\n\n override connectedCallback(): void {\n this.#connected = true;\n // Retry part subscriptions when their parent is registered later.\n this.#contextRoot.attach(this);\n super.connectedCallback();\n this.#syncInitialConfig();\n this.#playerProvider.setValue(this.store);\n this.#publishMedia();\n this.#publishContainer();\n this.#observer.observe(this, { childList: true, subtree: true });\n queueMicrotask(() => {\n if (this.#connected) this.#syncNativeMedia();\n });\n this.#tryAttach();\n }\n\n override disconnectedCallback(): void {\n this.#connected = false;\n this.#contextRoot.detach(this);\n this.#observer.disconnect();\n this.#detachStore();\n super.disconnectedCallback();\n }\n\n override destroyCallback(): void {\n this.#contextRoot.detach(this);\n this.#observer.disconnect();\n this.#detachStore();\n this.#extensions.destroy();\n this.#store?.destroy();\n this.#store = null;\n super.destroyCallback();\n }\n\n protected override willUpdate(changed: PropertyValues): void {\n super.willUpdate(changed);\n\n for (const { property, entry } of inputs) {\n if (!changed.has(property)) continue;\n\n // SAFETY: `resolveInputs` derives properties installed by this class's static property map.\n const configProperty = property as keyof this;\n\n setPlayerConfigValue(this.store, entry, this[configProperty]);\n }\n }\n\n #syncMedia(): void {\n const registered = this.#mediaRegistrations.at(-1)?.value ?? null;\n const media = registered ?? this.#nativeMedia;\n if (this.#media === media) return;\n\n this.#media = media;\n this.#publishMedia();\n this.#tryAttach();\n }\n\n #syncContainer(): void {\n const container = this.#containerRegistrations.at(-1)?.value ?? null;\n if (this.#container === container) return;\n\n this.#container = container;\n this.#publishContainer();\n this.#tryAttach();\n }\n\n #syncNativeMedia(): void {\n const media = this.querySelector<HTMLMediaElement>('video, audio');\n if (this.#nativeMedia === media) return;\n\n this.#nativeMedia = media;\n this.#syncMedia();\n }\n\n #publishMedia(): void {\n this.#mediaProvider.setValue({ media: this.#media, registerMedia: this.#registerMedia });\n }\n\n #publishContainer(): void {\n this.#containerProvider.setValue({\n container: this.#container,\n registerContainer: this.#registerContainer,\n });\n }\n\n #tryAttach(): void {\n if (!this.#connected || !this.#store) return;\n\n if (!this.#media) {\n this.#detachStore();\n return;\n }\n\n const target: PlayerTarget = {\n media: this.#media,\n container: this.#container,\n };\n\n const hasMediaChanged = this.#attached?.media !== target.media;\n const hasContainerChanged = this.#attached?.container !== target.container;\n\n if (hasMediaChanged || hasContainerChanged) this.#attach(target);\n }\n\n /**\n * Extensions attach before the store so their overrides are in place when features first read the media; the store\n * then sees the media through the extensions' facade. Extensions follow the media only, so a container change\n * re-attaches the store but leaves them attached.\n */\n #attach(target: PlayerTarget): void {\n const store = this.#store;\n if (!store) return;\n\n this.#detach?.();\n this.#attached = target;\n this.#extensions.attach(target);\n this.#detach = store.attach({ media: this.#extensions.getStoreMedia(target.media), container: target.container });\n }\n\n /**\n * An extension that overrides media members was added or removed. Features hold members read at attach time (such\n * as `remote`), so the store re-attaches to the same target to pick up what the extensions now own. Observers such\n * as analytics never get here. Extensions themselves stay attached.\n */\n #syncExtensions(): void {\n if (this.#attached) this.#attach(this.#attached);\n }\n\n #detachStore(): void {\n this.#detach?.();\n this.#detach = null;\n this.#extensions.detach();\n this.#attached = null;\n }\n\n #syncInitialConfig(): void {\n const store = this.store;\n if (this.#configuredStore === store) return;\n\n for (const { property, entry } of inputs) {\n // SAFETY: `resolveInputs` derives properties installed by this class's static property map.\n const configProperty = property as keyof this;\n\n setPlayerConfigValue(store, entry, this[configProperty]);\n }\n\n this.#configuredStore = store;\n }\n }\n\n return ConfiguredPlayerElement;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"element.js","names":[],"sources":["../../../src/player/element.ts"],"sourcesContent":["import {\n type MediaContainer,\n type PlayerExtension,\n PlayerExtensionCoordinator,\n type PlayerFeatureConfig,\n type PlayerStore,\n type PlayerTarget,\n setPlayerConfigValue,\n} from '@videojs/core/dom';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport { ContextProvider } from '@videojs/element/context';\nimport type { Media } from '@videojs/media/dom';\nimport { isNull } from '@videojs/utils/predicate';\nimport { camelCase, kebabCase } from '@videojs/utils/string';\n\nimport type { PlayerElementConstructor } from '../store/types';\nimport { UIElement } from '../ui/ui-element';\nimport type { ContainerContext, ExtensionContext, MediaContext, PlayerContext } from './context';\n\nexport interface CreatePlayerElementOptions<Store extends PlayerStore> {\n playerContext: PlayerContext<Store>;\n mediaContext: MediaContext;\n containerContext: ContainerContext;\n extensionContext: ExtensionContext;\n factory: () => Store;\n config: PlayerFeatureConfig;\n}\n\ninterface Registration<Value> {\n value: Value;\n}\n\ninterface ConfigInput {\n property: string;\n attribute: string;\n entry: PlayerFeatureConfig[string];\n}\n\nfunction resolveInputs(config: PlayerFeatureConfig): ConfigInput[] {\n return Object.entries(config).map(([key, entry]) => {\n const declared = entry.html?.attribute;\n const attribute = declared ?? kebabCase(key);\n\n if (__DEV__ && declared && declared !== kebabCase(declared)) {\n console.warn(`[vjs-html] config html.attribute \"${declared}\" is not kebab-case and will never match`);\n }\n\n return { property: camelCase(attribute), attribute, entry };\n });\n}\n\n/** Creates a configured player element class that owns the store and attach lifecycle. */\nexport function createPlayerElement<Store extends PlayerStore>(\n options: CreatePlayerElementOptions<Store>\n): PlayerElementConstructor<Store>;\nexport function createPlayerElement<Store extends PlayerStore>(\n options: CreatePlayerElementOptions<Store>\n): typeof UIElement {\n const inputs = resolveInputs(options.config);\n\n class ConfiguredPlayerElement extends UIElement {\n static properties = {\n ...UIElement.properties,\n ...Object.fromEntries(inputs.map(({ property, attribute }) => [property, { type: String, attribute }])),\n } satisfies PropertyDeclarationMap;\n\n #store: Store | null = options.factory();\n #configuredStore: Store | null = null;\n #detach: (() => void) | null = null;\n #connected = false;\n #media: Media | null = null;\n #nativeMedia: HTMLMediaElement | null = null;\n #container: MediaContainer | null = null;\n // The raw target the store is attached to; `store.target.media` may be the extensions' facade over it.\n #attached: PlayerTarget | null = null;\n #mediaRegistrations: Registration<Media>[] = [];\n #containerRegistrations: Registration<MediaContainer>[] = [];\n #observer = new MutationObserver(() => this.#syncNativeMedia());\n #extensions = new PlayerExtensionCoordinator(() => this.#syncExtensions());\n\n #registerExtension = (extension: PlayerExtension): (() => void) => this.#extensions.register(extension);\n\n #registerMedia = (media: Media): (() => void) => {\n const registration = { value: media };\n\n this.#mediaRegistrations.push(registration);\n this.#syncMedia();\n\n return () => {\n const index = this.#mediaRegistrations.indexOf(registration);\n if (index < 0) return;\n\n this.#mediaRegistrations.splice(index, 1);\n this.#syncNativeMedia();\n this.#syncMedia();\n };\n };\n\n #registerContainer = (container: MediaContainer): (() => void) => {\n const registration = { value: container };\n\n this.#containerRegistrations.push(registration);\n this.#syncContainer();\n\n return () => {\n const index = this.#containerRegistrations.indexOf(registration);\n if (index < 0) return;\n\n this.#containerRegistrations.splice(index, 1);\n this.#syncContainer();\n };\n };\n\n #playerProvider = new ContextProvider(this, {\n context: options.playerContext,\n initialValue: this.store,\n });\n\n #mediaProvider = new ContextProvider(this, {\n context: options.mediaContext,\n initialValue: { media: this.#media, registerMedia: this.#registerMedia },\n });\n\n #containerProvider = new ContextProvider(this, {\n context: options.containerContext,\n initialValue: {\n container: this.#container,\n registerContainer: this.#registerContainer,\n },\n });\n\n constructor() {\n super();\n // Registers itself as a controller on this element; the value never changes, so nothing reads it back.\n new ContextProvider(this, {\n context: options.extensionContext,\n initialValue: { registerExtension: this.#registerExtension },\n });\n }\n\n get store(): Store {\n if (isNull(this.#store)) {\n this.#store = options.factory();\n }\n\n return this.#store;\n }\n\n override connectedCallback(): void {\n this.#connected = true;\n super.connectedCallback();\n this.#syncInitialConfig();\n this.#playerProvider.setValue(this.store);\n this.#publishMedia();\n this.#publishContainer();\n this.#observer.observe(this, { childList: true, subtree: true });\n queueMicrotask(() => {\n if (this.#connected) this.#syncNativeMedia();\n });\n this.#tryAttach();\n }\n\n override disconnectedCallback(): void {\n this.#connected = false;\n this.#observer.disconnect();\n this.#detachStore();\n super.disconnectedCallback();\n }\n\n override destroyCallback(): void {\n this.#observer.disconnect();\n this.#detachStore();\n this.#extensions.destroy();\n this.#store?.destroy();\n this.#store = null;\n super.destroyCallback();\n }\n\n protected override willUpdate(changed: PropertyValues): void {\n super.willUpdate(changed);\n\n for (const { property, entry } of inputs) {\n if (!changed.has(property)) continue;\n\n // SAFETY: `resolveInputs` derives properties installed by this class's static property map.\n const configProperty = property as keyof this;\n\n setPlayerConfigValue(this.store, entry, this[configProperty]);\n }\n }\n\n #syncMedia(): void {\n const registered = this.#mediaRegistrations.at(-1)?.value ?? null;\n const media = registered ?? this.#nativeMedia;\n if (this.#media === media) return;\n\n this.#media = media;\n this.#publishMedia();\n this.#tryAttach();\n }\n\n #syncContainer(): void {\n const container = this.#containerRegistrations.at(-1)?.value ?? null;\n if (this.#container === container) return;\n\n this.#container = container;\n this.#publishContainer();\n this.#tryAttach();\n }\n\n #syncNativeMedia(): void {\n const media = this.querySelector<HTMLMediaElement>('video, audio');\n if (this.#nativeMedia === media) return;\n\n this.#nativeMedia = media;\n this.#syncMedia();\n }\n\n #publishMedia(): void {\n this.#mediaProvider.setValue({ media: this.#media, registerMedia: this.#registerMedia });\n }\n\n #publishContainer(): void {\n this.#containerProvider.setValue({\n container: this.#container,\n registerContainer: this.#registerContainer,\n });\n }\n\n #tryAttach(): void {\n if (!this.#connected || !this.#store) return;\n\n if (!this.#media) {\n this.#detachStore();\n return;\n }\n\n const target: PlayerTarget = {\n media: this.#media,\n container: this.#container,\n };\n\n const hasMediaChanged = this.#attached?.media !== target.media;\n const hasContainerChanged = this.#attached?.container !== target.container;\n\n if (hasMediaChanged || hasContainerChanged) this.#attach(target);\n }\n\n /**\n * Extensions attach before the store so their overrides are in place when features first read the media; the store\n * then sees the media through the extensions' facade. Extensions follow the media only, so a container change\n * re-attaches the store but leaves them attached.\n */\n #attach(target: PlayerTarget): void {\n const store = this.#store;\n if (!store) return;\n\n this.#detach?.();\n this.#attached = target;\n this.#extensions.attach(target);\n this.#detach = store.attach({ media: this.#extensions.getStoreMedia(target.media), container: target.container });\n }\n\n /**\n * An extension that overrides media members was added or removed. Features hold members read at attach time (such\n * as `remote`), so the store re-attaches to the same target to pick up what the extensions now own. Observers such\n * as analytics never get here. Extensions themselves stay attached.\n */\n #syncExtensions(): void {\n if (this.#attached) this.#attach(this.#attached);\n }\n\n #detachStore(): void {\n this.#detach?.();\n this.#detach = null;\n this.#extensions.detach();\n this.#attached = null;\n }\n\n #syncInitialConfig(): void {\n const store = this.store;\n if (this.#configuredStore === store) return;\n\n for (const { property, entry } of inputs) {\n // SAFETY: `resolveInputs` derives properties installed by this class's static property map.\n const configProperty = property as keyof this;\n\n setPlayerConfigValue(store, entry, this[configProperty]);\n }\n\n this.#configuredStore = store;\n }\n }\n\n return ConfiguredPlayerElement;\n}\n"],"mappings":"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"}
|