@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
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ReactiveElement } from "@videojs/element";
|
|
2
2
|
//#region src/presets/background/skin.d.ts
|
|
3
3
|
declare function getTemplateHTML(): string;
|
|
4
|
-
|
|
4
|
+
declare const BackgroundVideoSkinElement_base: typeof ReactiveElement & (new (...args: any[]) => import("@videojs/element").Destroyable);
|
|
5
|
+
export declare class BackgroundVideoSkinElement extends BackgroundVideoSkinElement_base {
|
|
5
6
|
static readonly tagName = "background-video-skin";
|
|
6
7
|
static shadowRootOptions: ShadowRootInit;
|
|
7
8
|
static getTemplateHTML: typeof getTemplateHTML;
|
|
@@ -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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skin.js","names":["styles"],"sources":["../../../../src/presets/background/skin.ts"],"sourcesContent":["import { ReactiveElement } from '@videojs/element';\nimport { ensureGlobalStyle } from '@videojs/utils/dom';\n\nimport styles from '../../define/background/skin.css?inline';\n\nconst STYLES_ID = '__media-background-styles';\n\nfunction getTemplateHTML() {\n return /* html */ `\n <media-container>\n <!-- @deprecated slot=\"media\" is no longer required, use the default slot instead -->\n <slot name=\"media\"></slot>\n <slot></slot>\n </media-container>\n `;\n}\n\nexport class BackgroundVideoSkinElement extends ReactiveElement {\n static readonly tagName = 'background-video-skin';\n static shadowRootOptions: ShadowRootInit = { mode: 'open' };\n static getTemplateHTML = getTemplateHTML;\n\n constructor() {\n super();\n\n ensureGlobalStyle(STYLES_ID, styles);\n\n if (!this.shadowRoot) {\n this.attachShadow(BackgroundVideoSkinElement.shadowRootOptions);\n this.shadowRoot!.innerHTML = getTemplateHTML();\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n [BackgroundVideoSkinElement.tagName]: BackgroundVideoSkinElement;\n }\n}\n"],"mappings":";;;;AAKA,MAAM,YAAY;AAElB,SAAS,kBAAkB;CACzB,OAAkB;;;;;;;AAOpB;AAEA,IAAa,6BAAb,MAAa,mCAAmC,
|
|
1
|
+
{"version":3,"file":"skin.js","names":["styles"],"sources":["../../../../src/presets/background/skin.ts"],"sourcesContent":["import { DestroyMixin, ReactiveElement } from '@videojs/element';\nimport { ensureGlobalStyle } from '@videojs/utils/dom';\n\nimport styles from '../../define/background/skin.css?inline';\n\nconst STYLES_ID = '__media-background-styles';\n\nfunction getTemplateHTML() {\n return /* html */ `\n <media-container>\n <!-- @deprecated slot=\"media\" is no longer required, use the default slot instead -->\n <slot name=\"media\"></slot>\n <slot></slot>\n </media-container>\n `;\n}\n\nexport class BackgroundVideoSkinElement extends DestroyMixin(ReactiveElement) {\n static readonly tagName = 'background-video-skin';\n static shadowRootOptions: ShadowRootInit = { mode: 'open' };\n static getTemplateHTML = getTemplateHTML;\n\n constructor() {\n super();\n\n ensureGlobalStyle(STYLES_ID, styles);\n\n if (!this.shadowRoot) {\n this.attachShadow(BackgroundVideoSkinElement.shadowRootOptions);\n this.shadowRoot!.innerHTML = getTemplateHTML();\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n [BackgroundVideoSkinElement.tagName]: BackgroundVideoSkinElement;\n }\n}\n"],"mappings":";;;;AAKA,MAAM,YAAY;AAElB,SAAS,kBAAkB;CACzB,OAAkB;;;;;;;AAOpB;AAEA,IAAa,6BAAb,MAAa,mCAAmC,aAAa,eAAe,CAAC,CAAC;;EAClD,KAAA,UAAA;;;EACiB,KAAA,oBAAA,EAAE,MAAM,OAAO;;;EACjC,KAAA,kBAAA;;CAEzB,cAAc;EACZ,MAAM;EAEN,kBAAkB,WAAWA,YAAM;EAEnC,IAAI,CAAC,KAAK,YAAY;GACpB,KAAK,aAAa,2BAA2B,iBAAiB;GAC9D,KAAK,WAAY,YAAY,gBAAgB;EAC/C;CACF;AACF"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { UIElement } from "../ui/ui-element.js";
|
|
2
2
|
import { ShadowStyle } from "@videojs/utils/dom";
|
|
3
3
|
//#region src/presets/skin.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Base element for skin definitions. Attaches a shadow root, clones `static template` into it, and applies shared +
|
|
6
|
-
* per-skin styles via `adoptedStyleSheets` (or `<style>` fallback).
|
|
6
|
+
* per-skin styles via `adoptedStyleSheets` (or `<style>` fallback). Destroying it also destroys the controls in its
|
|
7
|
+
* shadow root.
|
|
7
8
|
*/
|
|
8
|
-
export declare class SkinElement extends
|
|
9
|
+
export declare class SkinElement extends UIElement {
|
|
9
10
|
static shadowRootOptions: ShadowRootInit;
|
|
10
11
|
static styles?: ShadowStyle;
|
|
11
12
|
static template?: HTMLTemplateElement | null;
|
package/dist/dev/presets/skin.js
CHANGED
|
@@ -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
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skin.js","names":["shadowStyles","globalStyles"],"sources":["../../../src/presets/skin.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"skin.js","names":["shadowStyles","globalStyles"],"sources":["../../../src/presets/skin.ts"],"sourcesContent":["import {\n applyShadowStyles,\n createShadowStyle,\n ensureGlobalStyle,\n renderTemplate,\n type ShadowStyle,\n} from '@videojs/utils/dom';\n\nimport { UIElement } from '../ui/ui-element';\n\nimport globalStyles from '../define/global.css?inline';\nimport shadowStyles from '../define/shadow.css?inline';\n\nconst STYLES_ID = '__media-styles';\nconst shadowSheet = createShadowStyle(shadowStyles);\n\n/**\n * Base element for skin definitions. Attaches a shadow root, clones `static template` into it, and applies shared +\n * per-skin styles via `adoptedStyleSheets` (or `<style>` fallback). Destroying it also destroys the controls in its\n * shadow root.\n */\nexport class SkinElement extends UIElement {\n static shadowRootOptions: ShadowRootInit = { mode: 'open' };\n static styles?: ShadowStyle;\n static template?: HTMLTemplateElement | null;\n\n constructor() {\n super();\n\n ensureGlobalStyle(STYLES_ID, globalStyles);\n\n if (!this.shadowRoot) {\n const ctor = this.constructor as typeof SkinElement;\n\n this.attachShadow(ctor.shadowRootOptions);\n\n if (ctor.template) {\n renderTemplate(this.shadowRoot!, ctor.template);\n }\n\n const sheets: ShadowStyle[] = [shadowSheet];\n\n if (ctor.styles) {\n sheets.push(ctor.styles);\n }\n\n applyShadowStyles(this.shadowRoot!, sheets);\n }\n }\n}\n"],"mappings":";;;;;AAaA,MAAM,YAAY;AAClB,MAAM,cAAc,kBAAkBA,cAAY;;;;;;AAOlD,IAAa,cAAb,cAAiC,UAAU;;EACE,KAAA,oBAAA,EAAE,MAAM,OAAO;;CAI1D,cAAc;EACZ,MAAM;EAEN,kBAAkB,WAAWC,cAAY;EAEzC,IAAI,CAAC,KAAK,YAAY;GACpB,MAAM,OAAO,KAAK;GAElB,KAAK,aAAa,KAAK,iBAAiB;GAExC,IAAI,KAAK,UACP,eAAe,KAAK,YAAa,KAAK,QAAQ;GAGhD,MAAM,SAAwB,CAAC,WAAW;GAE1C,IAAI,KAAK,QACP,OAAO,KAAK,KAAK,MAAM;GAGzB,kBAAkB,KAAK,YAAa,MAAM;EAC5C;CACF;AACF"}
|
|
@@ -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));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"element.js","names":[],"sources":["../../../../src/ui/dialog/element.ts"],"sourcesContent":["import {\n DialogCore,\n DialogDataAttrs,\n type DialogInput,\n type DialogState,\n type StateAttrMap,\n type DialogProps,\n} from '@videojs/core';\nimport {\n applyElementProps,\n applyStateDataAttrs,\n createDialog,\n createTransition,\n type DialogApi,\n} from '@videojs/core/dom';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport { ContextProvider } from '@videojs/element/context';\nimport { SnapshotController } from '@videojs/store/html';\n\nimport { PositionController } from '../position-controller';\nimport { UIElement } from '../ui-element';\nimport { dialogContext } from './context';\n\nlet idCounter = 0;\n\nexport interface DialogElementBaseOptions {\n /** @internal */\n core?: DialogCore;\n /** @internal */\n stateAttrMap?: StateAttrMap<DialogState>;\n idPrefix?: string;\n bindTrigger?: boolean;\n}\n\nexport class DialogElementBase extends UIElement {\n static override properties = {\n open: { type: Boolean },\n defaultOpen: { type: Boolean, attribute: 'default-open' },\n closeOnEscape: { type: Boolean, attribute: 'close-on-escape' },\n } satisfies PropertyDeclarationMap<keyof DialogProps>;\n\n open = DialogCore.defaultProps.open;\n defaultOpen = DialogCore.defaultProps.defaultOpen;\n closeOnEscape = DialogCore.defaultProps.closeOnEscape;\n\n readonly #core: DialogCore;\n readonly #stateAttrMap: StateAttrMap<DialogState>;\n readonly #provider = new ContextProvider(this, { context: dialogContext });\n readonly #position = new PositionController(this);\n readonly #popupId: string;\n readonly #titleId: string;\n readonly #descriptionId: string;\n readonly #bindTrigger: boolean;\n\n #dialog: DialogApi | null = null;\n #snapshot: SnapshotController<DialogInput> | null = null;\n #triggerAbort: AbortController | null = null;\n #triggerElement: HTMLElement | null = null;\n\n constructor({\n core = new DialogCore(),\n stateAttrMap = DialogDataAttrs,\n idPrefix = 'dialog',\n bindTrigger = true,\n }: DialogElementBaseOptions = {}) {\n super();\n this.#core = core;\n this.#stateAttrMap = stateAttrMap;\n this.#bindTrigger = bindTrigger;\n this.#popupId = `vjs-${idPrefix}-popup-${idCounter++}`;\n this.#titleId = `vjs-${idPrefix}-title-${idCounter++}`;\n this.#descriptionId = `vjs-${idPrefix}-desc-${idCounter++}`;\n this.#core.setTitleId(this.#titleId);\n this.#core.setDescriptionId(this.#descriptionId);\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n if (this.destroyed) return;\n\n this.#dialog = createDialog({\n transition: createTransition(),\n closeOnEscape: () => this.closeOnEscape,\n onOpenChange: (nextOpen: boolean) => {\n this.open = nextOpen;\n this.dispatchEvent(new CustomEvent('open-change', { detail: { open: nextOpen } }));\n },\n onOpenChangeComplete: (nextOpen: boolean) => {\n this.dispatchEvent(new CustomEvent('open-change-complete', { detail: { open: nextOpen } }));\n },\n });\n\n if (this.#snapshot) {\n this.#snapshot.track(this.#dialog.input);\n } else {\n this.#snapshot = new SnapshotController(this, this.#dialog.input);\n }\n }\n\n protected override firstUpdated(changed: PropertyValues): void {\n super.firstUpdated(changed);\n\n if (this.defaultOpen && !this.open) this.#dialog?.open();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.#cleanupTrigger();\n this.#dialog?.destroy();\n this.#dialog = null;\n }\n\n close(): void {\n this.#dialog?.close();\n }\n\n protected override willUpdate(changed: PropertyValues): void {\n super.willUpdate(changed);\n this.#core.setProps(this);\n\n if (this.#dialog && changed.has('open')) {\n const { active: inputOpen } = this.#dialog.input.current;\n\n if (this.open !== inputOpen) {\n if (this.open) this.#dialog.open();\n else this.#dialog.close();\n }\n }\n }\n\n protected override update(_changed: PropertyValues): void {\n super.update(_changed);\n\n if (!this.#dialog) return;\n\n const triggerElement = this.#bindTrigger ? this.#position.findTrigger() : null;\n\n this.#syncTrigger(triggerElement);\n\n const input = this.#dialog.input.current;\n\n this.#core.setInput(input);\n const state = this.#core.getState();\n\n applyStateDataAttrs(this, state, this.#stateAttrMap);\n\n if (this.#triggerElement) {\n applyElementProps(this.#triggerElement, this.#core.getTriggerAttrs(state, this.#popupId));\n }\n\n this.#provider.setValue({\n state,\n stateAttrMap: this.#stateAttrMap,\n dialog: this.#dialog,\n popupId: this.#popupId,\n popupAttrs: this.#core.getPopupAttrs(state),\n close: () => this.#dialog?.close(),\n });\n }\n\n #syncTrigger(triggerElement: HTMLElement | null): void {\n if (triggerElement === this.#triggerElement) return;\n\n this.#cleanupTrigger();\n this.#triggerElement = triggerElement;\n this.#dialog?.setTriggerElement(triggerElement);\n\n if (triggerElement && this.#dialog) {\n this.#triggerAbort = new AbortController();\n applyElementProps(triggerElement, this.#dialog.triggerProps, { signal: this.#triggerAbort.signal });\n }\n }\n\n #cleanupTrigger(): void {\n if (this.#triggerElement) {\n applyElementProps(this.#triggerElement, {\n 'aria-expanded': undefined,\n 'aria-haspopup': undefined,\n 'aria-controls': undefined,\n });\n }\n\n this.#triggerAbort?.abort();\n this.#triggerAbort = null;\n this.#triggerElement = null;\n this.#dialog?.setTriggerElement(null);\n }\n}\n\nexport class DialogElement extends DialogElementBase {\n static readonly tagName = 'media-dialog';\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"element.js","names":[],"sources":["../../../../src/ui/dialog/element.ts"],"sourcesContent":["import {\n DialogCore,\n DialogDataAttrs,\n type DialogInput,\n type DialogState,\n type StateAttrMap,\n type DialogProps,\n} from '@videojs/core';\nimport {\n applyElementProps,\n applyStateDataAttrs,\n createDialog,\n createTransition,\n type DialogApi,\n type DialogModality,\n} from '@videojs/core/dom';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport { ContextConsumer, ContextProvider } from '@videojs/element/context';\nimport { SnapshotController } from '@videojs/store/html';\n\nimport { containerContext } from '../../player/context';\nimport { PositionController } from '../position-controller';\nimport { UIElement } from '../ui-element';\nimport { dialogContext } from './context';\n\nlet idCounter = 0;\n\nexport interface DialogElementBaseOptions {\n /** @internal */\n core?: DialogCore;\n /** @internal */\n stateAttrMap?: StateAttrMap<DialogState>;\n idPrefix?: string;\n bindTrigger?: boolean;\n}\n\nexport class DialogElementBase extends UIElement {\n static override properties = {\n open: { type: Boolean },\n defaultOpen: { type: Boolean, attribute: 'default-open' },\n closeOnEscape: { type: Boolean, attribute: 'close-on-escape' },\n } satisfies PropertyDeclarationMap<keyof DialogProps>;\n\n open = DialogCore.defaultProps.open;\n defaultOpen = DialogCore.defaultProps.defaultOpen;\n closeOnEscape = DialogCore.defaultProps.closeOnEscape;\n\n readonly #core: DialogCore;\n readonly #stateAttrMap: StateAttrMap<DialogState>;\n readonly #provider = new ContextProvider(this, { context: dialogContext });\n readonly #position = new PositionController(this);\n readonly #container = new ContextConsumer(this, { context: containerContext, subscribe: true });\n readonly #popupId: string;\n readonly #titleId: string;\n readonly #descriptionId: string;\n readonly #bindTrigger: boolean;\n\n #dialog: DialogApi | null = null;\n #snapshot: SnapshotController<DialogInput> | null = null;\n #modalitySnapshot: SnapshotController<DialogModality> | null = null;\n #triggerAbort: AbortController | null = null;\n #triggerElement: HTMLElement | null = null;\n\n constructor({\n core = new DialogCore(),\n stateAttrMap = DialogDataAttrs,\n idPrefix = 'dialog',\n bindTrigger = true,\n }: DialogElementBaseOptions = {}) {\n super();\n this.#core = core;\n this.#stateAttrMap = stateAttrMap;\n this.#bindTrigger = bindTrigger;\n this.#popupId = `vjs-${idPrefix}-popup-${idCounter++}`;\n this.#titleId = `vjs-${idPrefix}-title-${idCounter++}`;\n this.#descriptionId = `vjs-${idPrefix}-desc-${idCounter++}`;\n this.#core.setTitleId(this.#titleId);\n this.#core.setDescriptionId(this.#descriptionId);\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n if (this.destroyed) return;\n\n this.#dialog = createDialog({\n transition: createTransition(),\n closeOnEscape: () => this.closeOnEscape,\n onOpenChange: (nextOpen: boolean) => {\n this.open = nextOpen;\n this.dispatchEvent(new CustomEvent('open-change', { detail: { open: nextOpen } }));\n },\n onOpenChangeComplete: (nextOpen: boolean) => {\n this.dispatchEvent(new CustomEvent('open-change-complete', { detail: { open: nextOpen } }));\n },\n });\n\n if (this.#snapshot) {\n this.#snapshot.track(this.#dialog.input);\n } else {\n this.#snapshot = new SnapshotController(this, this.#dialog.input);\n }\n\n if (this.#modalitySnapshot) {\n this.#modalitySnapshot.track(this.#dialog.modality);\n } else {\n this.#modalitySnapshot = new SnapshotController(this, this.#dialog.modality);\n }\n }\n\n protected override firstUpdated(changed: PropertyValues): void {\n super.firstUpdated(changed);\n\n if (this.defaultOpen && !this.open) this.#dialog?.open();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.#cleanupTrigger();\n this.#dialog?.destroy();\n this.#dialog = null;\n }\n\n close(): void {\n this.#dialog?.close();\n }\n\n protected override willUpdate(changed: PropertyValues): void {\n super.willUpdate(changed);\n this.#core.setProps(this);\n this.#dialog?.setInteractionRoot(this.#container.value?.container ?? null);\n\n if (this.#dialog && changed.has('open')) {\n const { active: inputOpen } = this.#dialog.input.current;\n\n if (this.open !== inputOpen) {\n if (this.open) this.#dialog.open();\n else this.#dialog.close();\n }\n }\n }\n\n protected override update(_changed: PropertyValues): void {\n super.update(_changed);\n\n if (!this.#dialog) return;\n\n const triggerElement = this.#bindTrigger ? this.#position.findTrigger() : null;\n\n this.#syncTrigger(triggerElement);\n\n const input = this.#dialog.input.current;\n\n this.#core.setInput(input);\n this.#core.setDocumentModal(this.#dialog.modality.current.documentModal);\n const state = this.#core.getState();\n\n applyStateDataAttrs(this, state, this.#stateAttrMap);\n\n if (this.#triggerElement) {\n applyElementProps(this.#triggerElement, this.#core.getTriggerAttrs(state, this.#popupId));\n }\n\n this.#provider.setValue({\n state,\n stateAttrMap: this.#stateAttrMap,\n dialog: this.#dialog,\n popupId: this.#popupId,\n popupAttrs: this.#core.getPopupAttrs(state),\n close: () => this.#dialog?.close(),\n });\n }\n\n #syncTrigger(triggerElement: HTMLElement | null): void {\n if (triggerElement === this.#triggerElement) return;\n\n this.#cleanupTrigger();\n this.#triggerElement = triggerElement;\n this.#dialog?.setTriggerElement(triggerElement);\n\n if (triggerElement && this.#dialog) {\n this.#triggerAbort = new AbortController();\n applyElementProps(triggerElement, this.#dialog.triggerProps, { signal: this.#triggerAbort.signal });\n }\n }\n\n #cleanupTrigger(): void {\n if (this.#triggerElement) {\n applyElementProps(this.#triggerElement, {\n 'aria-expanded': undefined,\n 'aria-haspopup': undefined,\n 'aria-controls': undefined,\n });\n }\n\n this.#triggerAbort?.abort();\n this.#triggerAbort = null;\n this.#triggerElement = null;\n this.#dialog?.setTriggerElement(null);\n }\n}\n\nexport class DialogElement extends DialogElementBase {\n static readonly tagName = 'media-dialog';\n}\n"],"mappings":"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"}
|
|
@@ -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,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"element.js","names":[],"sources":["../../../../src/ui/gesture/element.ts"],"sourcesContent":["import type { GestureProps } from '@videojs/core';\nimport {\n createDoubleTapGesture,\n createTapGesture,\n getGestureActionValue,\n resolveGestureAction,\n} from '@videojs/core/dom';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport { ContextConsumer } from '@videojs/element/context';\n\nimport { containerContext, playerContext } from '../../player/context';\nimport { PlayerController } from '../../player/controller';\nimport { UIElement } from '../ui-element';\n\nexport class GestureElement extends UIElement {\n static readonly tagName = 'media-gesture';\n\n static override properties: PropertyDeclarationMap = {\n type: { type: String },\n action: { type: String },\n value: { type: Number },\n pointer: { type: String },\n region: { type: String },\n disabled: { type: Boolean },\n };\n\n type: GestureProps['type'] | '' = '';\n action: GestureProps['action'] = '';\n value: GestureProps['value'] = undefined;\n pointer: GestureProps['pointer'] = undefined;\n region: GestureProps['region'] = undefined;\n disabled: NonNullable<GestureProps['disabled']> = false;\n\n readonly #player = new PlayerController(this, playerContext);\n readonly #container = new ContextConsumer(this, {\n context: containerContext,\n callback: () => this.requestUpdate(),\n subscribe: true,\n });\n #cleanup: (() => void) | null = null;\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.style.display = 'none';\n this.#register();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.#unregister();\n }\n\n protected override update(changed: PropertyValues): void {\n super.update(changed);\n\n // Re-register when attributes change.\n if (this.isConnected) {\n this.#unregister();\n this.#register();\n }\n }\n\n #register(): void {\n const store = this.#player.value;\n const container = this.#container.value?.container;\n if (!this.type || !this.action || !store || !container) return;\n\n const resolver = resolveGestureAction(this.action);\n if (!resolver) return;\n\n const { value, region } = this;\n const actionValue = getGestureActionValue(this.action, region, value);\n\n const onActivate = (event: PointerEvent) => {\n resolver({ store, value: actionValue, event });\n };\n\n const options = {\n pointer: this.pointer,\n region,\n disabled: this.disabled,\n action: this.action,\n value: actionValue,\n };\n\n if (this.type === 'doubletap') {\n this.#cleanup = createDoubleTapGesture(container, onActivate, options);\n } else if (this.type === 'tap') {\n this.#cleanup = createTapGesture(container, onActivate, options);\n }\n }\n\n #unregister(): void {\n this.#cleanup?.();\n this.#cleanup = null;\n }\n}\n"],"mappings":";;;;;;AAcA,IAAa,iBAAb,cAAoC,UAAU;;;EAYV,KAAA,OAAA;EACD,KAAA,SAAA;EACF,KAAA,QAAA,KAAA;EACI,KAAA,UAAA,KAAA;EACF,KAAA,SAAA,KAAA;EACiB,KAAA,WAAA;EAE/B,KAAA,UAAA,IAAI,iBAAiB,MAAM,aAAa;EACrC,KAAA,aAAA,IAAI,gBAAgB,MAAM;GAC9C,SAAS;GACT,gBAAgB,KAAK,cAAc;GACnC,WAAW;EACb,CAAC;EAC+B,KAAA,WAAA;;;EAxBN,KAAA,UAAA;;;EAE2B,KAAA,aAAA;GACnD,MAAM,EAAE,MAAM,OAAO;GACrB,QAAQ,EAAE,MAAM,OAAO;GACvB,OAAO,EAAE,MAAM,OAAO;GACtB,SAAS,EAAE,MAAM,OAAO;GACxB,QAAQ,EAAE,MAAM,OAAO;GACvB,UAAU,EAAE,MAAM,QAAQ;EAC5B;;CASA;CACA;CAKA;CAEA,oBAAmC;EACjC,MAAM,kBAAkB;EACxB,KAAK,MAAM,UAAU;EACrB,KAAK,UAAU;CACjB;CAEA,uBAAsC;EACpC,MAAM,qBAAqB;EAC3B,KAAK,YAAY;CACnB;CAEA,OAA0B,SAA+B;EACvD,MAAM,OAAO,OAAO;EAGpB,IAAI,KAAK,aAAa;GACpB,KAAK,YAAY;GACjB,KAAK,UAAU;EACjB;CACF;CAEA,YAAkB;EAChB,MAAM,QAAQ,KAAK,QAAQ;EAC3B,MAAM,YAAY,KAAK,WAAW,OAAO;EACzC,IAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,UAAU,CAAC,SAAS,CAAC,WAAW;EAExD,MAAM,WAAW,qBAAqB,KAAK,MAAM;EACjD,IAAI,CAAC,UAAU;EAEf,MAAM,EAAE,OAAO,WAAW;EAC1B,MAAM,cAAc,sBAAsB,KAAK,QAAQ,QAAQ,KAAK;EAEpE,MAAM,cAAc,UAAwB;GAC1C,SAAS;IAAE;IAAO,OAAO;IAAa;GAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"element.js","names":[],"sources":["../../../../src/ui/gesture/element.ts"],"sourcesContent":["import type { GestureProps } from '@videojs/core';\nimport {\n createDoubleTapGesture,\n createTapGesture,\n getGestureActionValue,\n resolveGestureAction,\n} from '@videojs/core/dom';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport { ContextConsumer } from '@videojs/element/context';\n\nimport { containerContext, playerContext } from '../../player/context';\nimport { PlayerController } from '../../player/controller';\nimport { UIElement } from '../ui-element';\n\nexport class GestureElement extends UIElement {\n static readonly tagName = 'media-gesture';\n\n static override properties: PropertyDeclarationMap = {\n type: { type: String },\n action: { type: String },\n value: { type: Number },\n pointer: { type: String },\n region: { type: String },\n disabled: { type: Boolean },\n };\n\n type: GestureProps['type'] | '' = '';\n action: GestureProps['action'] = '';\n value: GestureProps['value'] = undefined;\n pointer: GestureProps['pointer'] = undefined;\n region: GestureProps['region'] = undefined;\n disabled: NonNullable<GestureProps['disabled']> = false;\n\n readonly #player = new PlayerController(this, playerContext);\n readonly #container = new ContextConsumer(this, {\n context: containerContext,\n callback: () => this.requestUpdate(),\n subscribe: true,\n });\n #cleanup: (() => void) | null = null;\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.style.display = 'none';\n this.#register();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.#unregister();\n }\n\n protected override update(changed: PropertyValues): void {\n super.update(changed);\n\n // Re-register when attributes change.\n if (this.isConnected) {\n this.#unregister();\n this.#register();\n }\n }\n\n #register(): void {\n const store = this.#player.value;\n const container = this.#container.value?.container;\n if (!this.type || !this.action || !store || !container) return;\n\n const resolver = resolveGestureAction(this.action);\n if (!resolver) return;\n\n const { value, region } = this;\n const actionValue = getGestureActionValue(this.action, region, value);\n\n let state: object | undefined;\n\n const onActivate = (event: PointerEvent) => {\n resolver({ store, state, value: actionValue, event });\n };\n\n const options = {\n onPointerDown: () => (state = store.state),\n pointer: this.pointer,\n region,\n disabled: this.disabled,\n action: this.action,\n value: actionValue,\n };\n\n if (this.type === 'doubletap') {\n this.#cleanup = createDoubleTapGesture(container, onActivate, options);\n } else if (this.type === 'tap') {\n this.#cleanup = createTapGesture(container, onActivate, options);\n }\n }\n\n #unregister(): void {\n this.#cleanup?.();\n this.#cleanup = null;\n }\n}\n"],"mappings":";;;;;;AAcA,IAAa,iBAAb,cAAoC,UAAU;;;EAYV,KAAA,OAAA;EACD,KAAA,SAAA;EACF,KAAA,QAAA,KAAA;EACI,KAAA,UAAA,KAAA;EACF,KAAA,SAAA,KAAA;EACiB,KAAA,WAAA;EAE/B,KAAA,UAAA,IAAI,iBAAiB,MAAM,aAAa;EACrC,KAAA,aAAA,IAAI,gBAAgB,MAAM;GAC9C,SAAS;GACT,gBAAgB,KAAK,cAAc;GACnC,WAAW;EACb,CAAC;EAC+B,KAAA,WAAA;;;EAxBN,KAAA,UAAA;;;EAE2B,KAAA,aAAA;GACnD,MAAM,EAAE,MAAM,OAAO;GACrB,QAAQ,EAAE,MAAM,OAAO;GACvB,OAAO,EAAE,MAAM,OAAO;GACtB,SAAS,EAAE,MAAM,OAAO;GACxB,QAAQ,EAAE,MAAM,OAAO;GACvB,UAAU,EAAE,MAAM,QAAQ;EAC5B;;CASA;CACA;CAKA;CAEA,oBAAmC;EACjC,MAAM,kBAAkB;EACxB,KAAK,MAAM,UAAU;EACrB,KAAK,UAAU;CACjB;CAEA,uBAAsC;EACpC,MAAM,qBAAqB;EAC3B,KAAK,YAAY;CACnB;CAEA,OAA0B,SAA+B;EACvD,MAAM,OAAO,OAAO;EAGpB,IAAI,KAAK,aAAa;GACpB,KAAK,YAAY;GACjB,KAAK,UAAU;EACjB;CACF;CAEA,YAAkB;EAChB,MAAM,QAAQ,KAAK,QAAQ;EAC3B,MAAM,YAAY,KAAK,WAAW,OAAO;EACzC,IAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,UAAU,CAAC,SAAS,CAAC,WAAW;EAExD,MAAM,WAAW,qBAAqB,KAAK,MAAM;EACjD,IAAI,CAAC,UAAU;EAEf,MAAM,EAAE,OAAO,WAAW;EAC1B,MAAM,cAAc,sBAAsB,KAAK,QAAQ,QAAQ,KAAK;EAEpE,IAAI;EAEJ,MAAM,cAAc,UAAwB;GAC1C,SAAS;IAAE;IAAO;IAAO,OAAO;IAAa;GAAM,CAAC;EACtD;EAEA,MAAM,UAAU;GACd,qBAAsB,QAAQ,MAAM;GACpC,SAAS,KAAK;GACd;GACA,UAAU,KAAK;GACf,QAAQ,KAAK;GACb,OAAO;EACT;EAEA,IAAI,KAAK,SAAS,aAChB,KAAK,WAAW,uBAAuB,WAAW,YAAY,OAAO;OAChE,IAAI,KAAK,SAAS,OACvB,KAAK,WAAW,iBAAiB,WAAW,YAAY,OAAO;CAEnE;CAEA,cAAoB;EAClB,KAAK,WAAW;EAChB,KAAK,WAAW;CAClB;AACF"}
|
|
@@ -11,6 +11,10 @@ type LabelParams = Record<string, string | number>;
|
|
|
11
11
|
type MediaButtonCore<ComponentState extends ButtonState, MediaState> = MediaButtonComponent<object, ComponentState> & {
|
|
12
12
|
setMedia(media: MediaState): void;
|
|
13
13
|
getLabelParams?: (state: ComponentState) => LabelParams | undefined;
|
|
14
|
+
/** Shorter text for the tooltip than the accessible name, when the two differ. */
|
|
15
|
+
getTooltipLabel?: (state: ComponentState) => Text | string;
|
|
16
|
+
/** CSS custom properties the button publishes for skins. */
|
|
17
|
+
getCSSVars?: (state: ComponentState) => Record<string, string>;
|
|
14
18
|
};
|
|
15
19
|
/**
|
|
16
20
|
* Abstract base for HTML custom elements that render a media-control button. `ComponentState` is the state the button
|
|
@@ -42,6 +46,11 @@ export declare abstract class MediaButtonElement<ComponentState extends ButtonSt
|
|
|
42
46
|
getResolvedLabel(): string | undefined;
|
|
43
47
|
protected willUpdate(changed: PropertyValues): void;
|
|
44
48
|
protected update(changed: PropertyValues): void;
|
|
49
|
+
/**
|
|
50
|
+
* Whether this button writes its core's `hidden` state to the `hidden` attribute. A subclass returns `false` while
|
|
51
|
+
* another owner, such as a linked menu, manages its visibility.
|
|
52
|
+
*/
|
|
53
|
+
protected reflectsHidden(): boolean;
|
|
45
54
|
}
|
|
46
55
|
//#endregion
|
|
47
56
|
//# sourceMappingURL=media-button-element.d.ts.map
|
|
@@ -74,6 +74,7 @@ var MediaButtonElement = class extends UIElement {
|
|
|
74
74
|
if (!media) return void 0;
|
|
75
75
|
this.core.setMedia(media);
|
|
76
76
|
const state = this.core.getState();
|
|
77
|
+
if (this.core.getTooltipLabel) return translateText(this.core.getTooltipLabel(state), this.#i18n.value);
|
|
77
78
|
return translateText(this.core.getLabel(state), this.#i18n.value, this.core.getLabelParams?.(state));
|
|
78
79
|
}
|
|
79
80
|
willUpdate(changed) {
|
|
@@ -92,9 +93,17 @@ var MediaButtonElement = class extends UIElement {
|
|
|
92
93
|
applyElementProps(this, {
|
|
93
94
|
...attrs,
|
|
94
95
|
"aria-keyshortcuts": this.#hotkeyRegistry?.aria,
|
|
95
|
-
...isHideable(state) && { hidden: state.hidden ? "" : void 0 }
|
|
96
|
+
...isHideable(state) && this.reflectsHidden() && { hidden: state.hidden ? "" : void 0 }
|
|
96
97
|
});
|
|
97
98
|
applyStateDataAttrs(this, state, this.stateAttrMap);
|
|
99
|
+
for (const [name, value] of Object.entries(this.core.getCSSVars?.(state) ?? {})) this.style.setProperty(name, value);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Whether this button writes its core's `hidden` state to the `hidden` attribute. A subclass returns `false` while
|
|
103
|
+
* another owner, such as a linked menu, manages its visibility.
|
|
104
|
+
*/
|
|
105
|
+
reflectsHidden() {
|
|
106
|
+
return true;
|
|
98
107
|
}
|
|
99
108
|
#syncHotkeyShortcut() {
|
|
100
109
|
const shortcut = this.getShortcut();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media-button-element.js","names":[],"sources":["../../../src/ui/media-button-element.ts"],"sourcesContent":["import type { ButtonState, MediaButtonComponent, StateAttrMap } from '@videojs/core';\nimport {\n applyElementProps,\n applyStateDataAttrs,\n type ButtonActivationSource,\n createButton,\n HOTKEY_SHORTCUT_CHANGE_EVENT,\n logMissingFeature,\n type UIEvent,\n} from '@videojs/core/dom';\nimport { isText, resolveText, type Text, translateText } from '@videojs/core/i18n';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport type { State } from '@videojs/store';\nimport { isBoolean, isObject } from '@videojs/utils/predicate';\n\nimport { i18nContext } from '../i18n/context';\nimport { I18nController } from '../i18n/controller';\nimport type { PlayerController } from '../player/controller';\nimport { AriaKeyShortcutsController } from './hotkey/aria-key-shortcuts-controller';\nimport { UIElement } from './ui-element';\n\ntype LabelParams = Record<string, string | number>;\n\n/** The core a media button element drives: it reads `MediaState` and computes `ComponentState`. */\ntype MediaButtonCore<ComponentState extends ButtonState, MediaState> = MediaButtonComponent<object, ComponentState> & {\n setMedia(media: MediaState): void;\n getLabelParams?: (state: ComponentState) => LabelParams | undefined;\n};\n\n/**\n * Abstract base for HTML custom elements that render a media-control button. `ComponentState` is the state the button\n * reflects to data attributes, and `MediaState` is the player state it reads and acts on. Pass both: a subclass that\n * omits them still compiles, but types `activate(state)` and `mediaState` as the `ButtonState` and `object` defaults.\n */\nexport abstract class MediaButtonElement<\n ComponentState extends ButtonState = ButtonState,\n MediaState extends object = object,\n> extends UIElement {\n static override properties: PropertyDeclarationMap = {\n label: { type: String },\n disabled: { type: Boolean },\n };\n\n disabled = false;\n label: Text | string = '';\n\n protected abstract readonly core: MediaButtonCore<ComponentState, MediaState>;\n protected abstract readonly stateAttrMap: StateAttrMap<ComponentState>;\n protected abstract readonly mediaState: PlayerController<any, MediaState | undefined>;\n\n protected abstract activate(state: MediaState, event: UIEvent, source: ButtonActivationSource): void | Promise<void>;\n\n protected getIsButtonDisabled(): boolean {\n return this.disabled || !this.mediaState.value;\n }\n\n protected handleActivate(event: UIEvent, source: ButtonActivationSource): void {\n // `createButton` invokes `onActivate` synchronously from click/keyup\n // handlers, so any rejection here would be unhandled. Log in dev for\n // visibility but absorb the failure at this UI boundary.\n Promise.resolve(this.activate(this.mediaState.value!, event, source)).catch((error) => {\n if (__DEV__) console.error(`[${this.localName}]`, error);\n });\n }\n\n /** Override to set the hotkey action name for `aria-keyshortcuts`. */\n protected readonly hotkeyAction: string | undefined = undefined;\n\n /** Override to match hotkeys that use action values, such as seek steps. */\n protected get hotkeyValue(): number | undefined {\n return undefined;\n }\n\n get $state(): State<ButtonState> {\n return this.core.state;\n }\n\n #disconnect: AbortController | null = null;\n #hotkeyRegistry: AriaKeyShortcutsController | null = null;\n #lastHotkeyShortcut: string | undefined;\n readonly #i18n = new I18nController(this, i18nContext);\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n if (this.destroyed) return;\n\n if (this.hotkeyAction && !this.#hotkeyRegistry) {\n this.#hotkeyRegistry = new AriaKeyShortcutsController(this, this.hotkeyAction, {\n value: () => this.hotkeyValue,\n });\n }\n\n this.#disconnect = new AbortController();\n\n const buttonProps = createButton({\n onActivate: (event, source) => this.handleActivate(event, source),\n isDisabled: () => this.getIsButtonDisabled(),\n });\n\n applyElementProps(this, buttonProps, { signal: this.#disconnect.signal });\n\n if (__DEV__ && !this.mediaState.value && this.mediaState.displayName) {\n logMissingFeature(this.localName, this.mediaState.displayName);\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.#disconnect?.abort();\n this.#disconnect = null;\n }\n\n /** Returns the button's current label derived from media state. */\n getLabel(): string | undefined {\n return this.core.state.current.label ? resolveText(this.core.state.current.label) : undefined;\n }\n\n getShortcut(): string | undefined {\n return this.#hotkeyRegistry?.shortcut;\n }\n\n /** Resolved label for tooltips and other display surfaces. */\n getResolvedLabel(): string | undefined {\n const media = this.mediaState.value;\n if (!media) return undefined;\n\n this.core.setMedia(media);\n const state = this.core.getState();\n\n return translateText(this.core.getLabel(state), this.#i18n.value, this.core.getLabelParams?.(state));\n }\n\n protected override willUpdate(changed: PropertyValues): void {\n super.willUpdate(changed);\n this.core.setProps?.(this);\n }\n\n protected override update(changed: PropertyValues): void {\n super.update(changed);\n\n const media = this.mediaState.value;\n\n this.#syncHotkeyShortcut();\n\n if (!media) return;\n\n this.core.setMedia(media);\n const state = this.core.getState();\n const attrs = (this.core.getAttrs?.(state) ?? {}) as Record<string, unknown>;\n\n if (isText(attrs['aria-label'])) {\n attrs['aria-label'] = translateText(attrs['aria-label'], this.#i18n.value, this.core.getLabelParams?.(state));\n }\n\n applyElementProps(this, {\n ...attrs,\n 'aria-keyshortcuts': this.#hotkeyRegistry?.aria,\n // A button whose core reports itself hidden takes the real attribute, not\n // just the data one: `data-hidden` is a styling hook a skin may or may not\n // act on, where `hidden` removes the control the way the React components\n // do by rendering nothing.\n ...(isHideable(state) && { hidden: state.hidden ? '' : undefined }),\n });\n applyStateDataAttrs(this, state, this.stateAttrMap);\n }\n\n #syncHotkeyShortcut(): void {\n const shortcut = this.getShortcut();\n if (shortcut === this.#lastHotkeyShortcut) return;\n\n this.#lastHotkeyShortcut = shortcut;\n this.dispatchEvent(new CustomEvent(HOTKEY_SHORTCUT_CHANGE_EVENT));\n }\n}\n\n/** Whether a button's core reports whether it should be shown at all. */\nfunction isHideable(state: unknown): state is { hidden: boolean } {\n return isObject(state) && isBoolean((state as { hidden?: unknown }).hidden);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"media-button-element.js","names":[],"sources":["../../../src/ui/media-button-element.ts"],"sourcesContent":["import type { ButtonState, MediaButtonComponent, StateAttrMap } from '@videojs/core';\nimport {\n applyElementProps,\n applyStateDataAttrs,\n type ButtonActivationSource,\n createButton,\n HOTKEY_SHORTCUT_CHANGE_EVENT,\n logMissingFeature,\n type UIEvent,\n} from '@videojs/core/dom';\nimport { isText, resolveText, type Text, translateText } from '@videojs/core/i18n';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport type { State } from '@videojs/store';\nimport { isBoolean, isObject } from '@videojs/utils/predicate';\n\nimport { i18nContext } from '../i18n/context';\nimport { I18nController } from '../i18n/controller';\nimport type { PlayerController } from '../player/controller';\nimport { AriaKeyShortcutsController } from './hotkey/aria-key-shortcuts-controller';\nimport { UIElement } from './ui-element';\n\ntype LabelParams = Record<string, string | number>;\n\n/** The core a media button element drives: it reads `MediaState` and computes `ComponentState`. */\ntype MediaButtonCore<ComponentState extends ButtonState, MediaState> = MediaButtonComponent<object, ComponentState> & {\n setMedia(media: MediaState): void;\n getLabelParams?: (state: ComponentState) => LabelParams | undefined;\n /** Shorter text for the tooltip than the accessible name, when the two differ. */\n getTooltipLabel?: (state: ComponentState) => Text | string;\n /** CSS custom properties the button publishes for skins. */\n getCSSVars?: (state: ComponentState) => Record<string, string>;\n};\n\n/**\n * Abstract base for HTML custom elements that render a media-control button. `ComponentState` is the state the button\n * reflects to data attributes, and `MediaState` is the player state it reads and acts on. Pass both: a subclass that\n * omits them still compiles, but types `activate(state)` and `mediaState` as the `ButtonState` and `object` defaults.\n */\nexport abstract class MediaButtonElement<\n ComponentState extends ButtonState = ButtonState,\n MediaState extends object = object,\n> extends UIElement {\n static override properties: PropertyDeclarationMap = {\n label: { type: String },\n disabled: { type: Boolean },\n };\n\n disabled = false;\n label: Text | string = '';\n\n protected abstract readonly core: MediaButtonCore<ComponentState, MediaState>;\n protected abstract readonly stateAttrMap: StateAttrMap<ComponentState>;\n protected abstract readonly mediaState: PlayerController<any, MediaState | undefined>;\n\n protected abstract activate(state: MediaState, event: UIEvent, source: ButtonActivationSource): void | Promise<void>;\n\n protected getIsButtonDisabled(): boolean {\n return this.disabled || !this.mediaState.value;\n }\n\n protected handleActivate(event: UIEvent, source: ButtonActivationSource): void {\n // `createButton` invokes `onActivate` synchronously from click/keyup\n // handlers, so any rejection here would be unhandled. Log in dev for\n // visibility but absorb the failure at this UI boundary.\n Promise.resolve(this.activate(this.mediaState.value!, event, source)).catch((error) => {\n if (__DEV__) console.error(`[${this.localName}]`, error);\n });\n }\n\n /** Override to set the hotkey action name for `aria-keyshortcuts`. */\n protected readonly hotkeyAction: string | undefined = undefined;\n\n /** Override to match hotkeys that use action values, such as seek steps. */\n protected get hotkeyValue(): number | undefined {\n return undefined;\n }\n\n get $state(): State<ButtonState> {\n return this.core.state;\n }\n\n #disconnect: AbortController | null = null;\n #hotkeyRegistry: AriaKeyShortcutsController | null = null;\n #lastHotkeyShortcut: string | undefined;\n readonly #i18n = new I18nController(this, i18nContext);\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n if (this.destroyed) return;\n\n if (this.hotkeyAction && !this.#hotkeyRegistry) {\n this.#hotkeyRegistry = new AriaKeyShortcutsController(this, this.hotkeyAction, {\n value: () => this.hotkeyValue,\n });\n }\n\n this.#disconnect = new AbortController();\n\n const buttonProps = createButton({\n onActivate: (event, source) => this.handleActivate(event, source),\n isDisabled: () => this.getIsButtonDisabled(),\n });\n\n applyElementProps(this, buttonProps, { signal: this.#disconnect.signal });\n\n if (__DEV__ && !this.mediaState.value && this.mediaState.displayName) {\n logMissingFeature(this.localName, this.mediaState.displayName);\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.#disconnect?.abort();\n this.#disconnect = null;\n }\n\n /** Returns the button's current label derived from media state. */\n getLabel(): string | undefined {\n return this.core.state.current.label ? resolveText(this.core.state.current.label) : undefined;\n }\n\n getShortcut(): string | undefined {\n return this.#hotkeyRegistry?.shortcut;\n }\n\n /** Resolved label for tooltips and other display surfaces. */\n getResolvedLabel(): string | undefined {\n const media = this.mediaState.value;\n if (!media) return undefined;\n\n this.core.setMedia(media);\n const state = this.core.getState();\n\n if (this.core.getTooltipLabel) return translateText(this.core.getTooltipLabel(state), this.#i18n.value);\n\n return translateText(this.core.getLabel(state), this.#i18n.value, this.core.getLabelParams?.(state));\n }\n\n protected override willUpdate(changed: PropertyValues): void {\n super.willUpdate(changed);\n this.core.setProps?.(this);\n }\n\n protected override update(changed: PropertyValues): void {\n super.update(changed);\n\n const media = this.mediaState.value;\n\n this.#syncHotkeyShortcut();\n\n if (!media) return;\n\n this.core.setMedia(media);\n const state = this.core.getState();\n const attrs = (this.core.getAttrs?.(state) ?? {}) as Record<string, unknown>;\n\n if (isText(attrs['aria-label'])) {\n attrs['aria-label'] = translateText(attrs['aria-label'], this.#i18n.value, this.core.getLabelParams?.(state));\n }\n\n applyElementProps(this, {\n ...attrs,\n 'aria-keyshortcuts': this.#hotkeyRegistry?.aria,\n // A button whose core reports itself hidden takes the real attribute, not\n // just the data one: `data-hidden` is a styling hook a skin may or may not\n // act on, where `hidden` removes the control the way the React components\n // do by rendering nothing.\n ...(isHideable(state) && this.reflectsHidden() && { hidden: state.hidden ? '' : undefined }),\n });\n applyStateDataAttrs(this, state, this.stateAttrMap);\n\n for (const [name, value] of Object.entries(this.core.getCSSVars?.(state) ?? {})) {\n this.style.setProperty(name, value);\n }\n }\n\n /**\n * Whether this button writes its core's `hidden` state to the `hidden` attribute. A subclass returns `false` while\n * another owner, such as a linked menu, manages its visibility.\n */\n protected reflectsHidden(): boolean {\n return true;\n }\n\n #syncHotkeyShortcut(): void {\n const shortcut = this.getShortcut();\n if (shortcut === this.#lastHotkeyShortcut) return;\n\n this.#lastHotkeyShortcut = shortcut;\n this.dispatchEvent(new CustomEvent(HOTKEY_SHORTCUT_CHANGE_EVENT));\n }\n}\n\n/** Whether a button's core reports whether it should be shown at all. */\nfunction isHideable(state: unknown): state is { hidden: boolean } {\n return isObject(state) && isBoolean((state as { hidden?: unknown }).hidden);\n}\n"],"mappings":"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"}
|
|
@@ -18,20 +18,28 @@ export declare class PlaybackRateButtonElement extends MediaButtonElement<Playba
|
|
|
18
18
|
commandfor: {
|
|
19
19
|
type: StringConstructor;
|
|
20
20
|
};
|
|
21
|
+
rates: {
|
|
22
|
+
type: StringConstructor;
|
|
23
|
+
};
|
|
21
24
|
};
|
|
22
25
|
commandfor: string | undefined;
|
|
26
|
+
rates: readonly number[] | string | undefined;
|
|
23
27
|
protected readonly core: PlaybackRateButtonCore;
|
|
24
28
|
protected readonly stateAttrMap: {
|
|
25
29
|
readonly rate: 'data-rate';
|
|
30
|
+
readonly availability: 'data-availability';
|
|
31
|
+
readonly hidden: 'data-hidden';
|
|
26
32
|
};
|
|
27
33
|
protected readonly mediaState: PlayerController<index_d_exports.AnyPlayerStore, {
|
|
28
|
-
readonly playbackRates: readonly number[];
|
|
29
34
|
playbackRate: number;
|
|
35
|
+
playbackRateAvailability: import("@videojs/media").MediaFeatureAvailability;
|
|
30
36
|
setPlaybackRate: (rate: number) => void;
|
|
37
|
+
readonly playbackRates: readonly number[];
|
|
31
38
|
} | undefined>;
|
|
32
39
|
protected readonly hotkeyAction = "speedUp";
|
|
33
40
|
protected activate(state: MediaPlaybackRateState, event?: UIEvent): void;
|
|
34
41
|
protected getIsButtonDisabled(): boolean;
|
|
42
|
+
protected reflectsHidden(): boolean;
|
|
35
43
|
protected willUpdate(changed: PropertyValues): void;
|
|
36
44
|
protected update(changed: PropertyValues): void;
|
|
37
45
|
}
|
|
@@ -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")) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"element.js","names":[],"sources":["../../../../src/ui/playback-rate-button/element.ts"],"sourcesContent":["import { PlaybackRateButtonCore, PlaybackRateButtonDataAttrs, type PlaybackRateButtonState } from '@videojs/core';\nimport { applyElementProps, selectPlaybackRate, type UIEvent } from '@videojs/core/dom';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport type { MediaPlaybackRateState } from '@videojs/media';\n\nimport { playerContext } from '../../player/context';\nimport { PlayerController } from '../../player/controller';\nimport { MediaButtonElement } from '../media-button-element';\n\nexport class PlaybackRateButtonElement extends MediaButtonElement<PlaybackRateButtonState, MediaPlaybackRateState> {\n static readonly tagName = 'media-playback-rate-button';\n\n static override properties = {\n label: { type: String },\n disabled: { type: Boolean },\n commandfor: { type: String },\n } satisfies PropertyDeclarationMap<'label' | 'disabled' | 'commandfor'>;\n\n commandfor: string | undefined = undefined;\n\n protected readonly core = new PlaybackRateButtonCore();\n protected readonly stateAttrMap = PlaybackRateButtonDataAttrs;\n protected readonly mediaState = new PlayerController(this, playerContext, selectPlaybackRate);\n protected override readonly hotkeyAction = 'speedUp';\n\n protected activate(state: MediaPlaybackRateState, event?: UIEvent): void {\n if (this.commandfor) {\n if (event instanceof KeyboardEvent) {\n // Custom elements do not synthesize a click from keyboard activation.\n // Dispatch one so the linked menu follows its normal open lifecycle.\n this.click();\n }\n\n return;\n }\n\n this.core.cycle(state);\n }\n\n protected override getIsButtonDisabled(): boolean {\n const media = this.mediaState.value;\n\n if (super.getIsButtonDisabled()) return true;\n\n if (this.commandfor && media && media.
|
|
1
|
+
{"version":3,"file":"element.js","names":[],"sources":["../../../../src/ui/playback-rate-button/element.ts"],"sourcesContent":["import { PlaybackRateButtonCore, PlaybackRateButtonDataAttrs, type PlaybackRateButtonState } from '@videojs/core';\nimport { applyElementProps, selectPlaybackRate, type UIEvent } from '@videojs/core/dom';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport type { MediaPlaybackRateState } from '@videojs/media';\n\nimport { playerContext } from '../../player/context';\nimport { PlayerController } from '../../player/controller';\nimport { MediaButtonElement } from '../media-button-element';\n\nexport class PlaybackRateButtonElement extends MediaButtonElement<PlaybackRateButtonState, MediaPlaybackRateState> {\n static readonly tagName = 'media-playback-rate-button';\n\n static override properties = {\n label: { type: String },\n disabled: { type: Boolean },\n commandfor: { type: String },\n rates: { type: String },\n } satisfies PropertyDeclarationMap<'label' | 'disabled' | 'commandfor' | 'rates'>;\n\n commandfor: string | undefined = undefined;\n rates: readonly number[] | string | undefined = undefined;\n\n protected readonly core = new PlaybackRateButtonCore();\n protected readonly stateAttrMap = PlaybackRateButtonDataAttrs;\n protected readonly mediaState = new PlayerController(this, playerContext, selectPlaybackRate);\n protected override readonly hotkeyAction = 'speedUp';\n\n protected activate(state: MediaPlaybackRateState, event?: UIEvent): void {\n if (this.commandfor) {\n if (event instanceof KeyboardEvent) {\n // Custom elements do not synthesize a click from keyboard activation.\n // Dispatch one so the linked menu follows its normal open lifecycle.\n this.click();\n }\n\n return;\n }\n\n this.core.cycle(state);\n }\n\n protected override getIsButtonDisabled(): boolean {\n const media = this.mediaState.value;\n\n if (super.getIsButtonDisabled()) return true;\n\n if (this.commandfor && media && this.core.getRates(media).length === 0) return true;\n\n return false;\n }\n\n // A linked menu hides its trigger from the rate options' availability and\n // treats a `hidden` trigger as author-hidden, so the button must not write\n // its own pre-attach `hidden` state there.\n protected override reflectsHidden(): boolean {\n return !this.commandfor;\n }\n\n protected override willUpdate(changed: PropertyValues): void {\n super.willUpdate(changed);\n\n if (changed.has('commandfor')) {\n if (this.commandfor) {\n this.setAttribute('commandfor', this.commandfor);\n } else {\n this.removeAttribute('commandfor');\n }\n }\n }\n\n protected override update(changed: PropertyValues): void {\n super.update(changed);\n\n const media = this.mediaState.value;\n if (!media || !this.commandfor) return;\n\n applyElementProps(this, {\n 'aria-disabled': this.getIsButtonDisabled() ? 'true' : undefined,\n });\n }\n}\n\nexport namespace PlaybackRateButtonElement {\n export type State = PlaybackRateButtonState;\n}\n"],"mappings":";;;;;;AASA,IAAa,4BAAb,cAA+C,mBAAoE;;;EAUhF,KAAA,aAAA,KAAA;EACe,KAAA,QAAA,KAAA;EAEtB,KAAA,OAAA,IAAI,uBAAuB;EACnB,KAAA,eAAA;EACF,KAAA,aAAA,IAAI,iBAAiB,MAAM,eAAe,kBAAkB;EACjD,KAAA,eAAA;;;EAfjB,KAAA,UAAA;;;EAEG,KAAA,aAAA;GAC3B,OAAO,EAAE,MAAM,OAAO;GACtB,UAAU,EAAE,MAAM,QAAQ;GAC1B,YAAY,EAAE,MAAM,OAAO;GAC3B,OAAO,EAAE,MAAM,OAAO;EACxB;;CAUA,SAAmB,OAA+B,OAAuB;EACvE,IAAI,KAAK,YAAY;GACnB,IAAI,iBAAiB,eAGnB,KAAK,MAAM;GAGb;EACF;EAEA,KAAK,KAAK,MAAM,KAAK;CACvB;CAEA,sBAAkD;EAChD,MAAM,QAAQ,KAAK,WAAW;EAE9B,IAAI,MAAM,oBAAoB,GAAG,OAAO;EAExC,IAAI,KAAK,cAAc,SAAS,KAAK,KAAK,SAAS,KAAK,CAAC,CAAC,WAAW,GAAG,OAAO;EAE/E,OAAO;CACT;CAKA,iBAA6C;EAC3C,OAAO,CAAC,KAAK;CACf;CAEA,WAA8B,SAA+B;EAC3D,MAAM,WAAW,OAAO;EAExB,IAAI,QAAQ,IAAI,YAAY,GAAG;GAC7B,IAAI,KAAK,YACP,KAAK,aAAa,cAAc,KAAK,UAAU;QAE/C,KAAK,gBAAgB,YAAY;EAErC;CACF;CAEA,OAA0B,SAA+B;EACvD,MAAM,OAAO,OAAO;EAGpB,IAAI,CADU,KAAK,WAAW,SAChB,CAAC,KAAK,YAAY;EAEhC,kBAAkB,MAAM,EACtB,iBAAiB,KAAK,oBAAoB,IAAI,SAAS,KAAA,EACzD,CAAC;CACH;AACF"}
|
|
@@ -17,8 +17,12 @@ export declare class PlaybackRateRadioGroupElement extends MenuRadioGroupElement
|
|
|
17
17
|
disabled: {
|
|
18
18
|
type: BooleanConstructor;
|
|
19
19
|
};
|
|
20
|
+
rates: {
|
|
21
|
+
type: StringConstructor;
|
|
22
|
+
};
|
|
20
23
|
};
|
|
21
24
|
disabled: boolean;
|
|
25
|
+
rates: readonly number[] | string | undefined;
|
|
22
26
|
formatRate: (rate: number) => string;
|
|
23
27
|
connectedCallback(): void;
|
|
24
28
|
protected update(changed: PropertyValues): void;
|
|
@@ -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;
|
|
@@ -53,7 +59,8 @@ var PlaybackRateRadioGroupElement = class extends MenuRadioGroupElement {
|
|
|
53
59
|
if (media) {
|
|
54
60
|
this.#core.setProps({
|
|
55
61
|
formatRate: this.formatRate,
|
|
56
|
-
disabled: this.disabled
|
|
62
|
+
disabled: this.disabled,
|
|
63
|
+
rates: this.rates
|
|
57
64
|
});
|
|
58
65
|
this.#core.setMedia(media);
|
|
59
66
|
state = this.#core.getState();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"element.js","names":[],"sources":["../../../../src/ui/playback-rate-radio-group/element.ts"],"sourcesContent":["import {\n PlaybackRateRadioGroupCore,\n PlaybackRateRadioGroupDataAttrs,\n type PlaybackRateRadioGroupOption,\n type PlaybackRateRadioGroupState,\n} from '@videojs/core';\nimport { applyStateDataAttrs, logMissingFeature, selectPlaybackRate } from '@videojs/core/dom';\nimport { translateText } from '@videojs/core/i18n';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\n\nimport { i18nContext } from '../../i18n/context';\nimport { I18nController } from '../../i18n/controller';\nimport { playerContext } from '../../player/context';\nimport { PlayerController } from '../../player/controller';\nimport { MenuRadioGroupElement } from '../menu/radio-group';\nimport { RadioOptionsController } from '../radio-options/controller';\n\n/**\n * Menu radio group that generates a `<media-menu-radio-item>` per available playback rate and shares the selected label\n * and availability with an enclosing menu. An optional `<template>` holding one `<media-menu-radio-item>` customizes\n * each generated item.\n */\nexport class PlaybackRateRadioGroupElement extends MenuRadioGroupElement {\n static override readonly tagName = 'media-playback-rate-radio-group';\n\n static override properties = {\n ...MenuRadioGroupElement.properties,\n disabled: { type: Boolean },\n } satisfies PropertyDeclarationMap<'value' | 'disabled'>;\n\n disabled = false;\n formatRate = PlaybackRateRadioGroupCore.defaultProps.formatRate;\n\n readonly #core = new PlaybackRateRadioGroupCore();\n readonly #i18n = new I18nController(this, i18nContext);\n readonly #mediaState = new PlayerController(this, playerContext, selectPlaybackRate);\n readonly #options = new RadioOptionsController<PlaybackRateRadioGroupOption>(this, {\n setItemAttributes: (item, option) => item.setAttribute('data-rate', option.value),\n onValueChange: (value) => {\n const media = this.#mediaState.value;\n\n if (media) this.#core.selectValue(media, value);\n },\n });\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n if (this.destroyed) return;\n\n if (__DEV__ && !this.#mediaState.value && this.#mediaState.displayName) {\n logMissingFeature(this.localName, this.#mediaState.displayName);\n }\n }\n\n protected override update(changed: PropertyValues): void {\n const media = this.#mediaState.value;\n let state: PlaybackRateRadioGroupState | null = null;\n\n if (media) {\n this.#core.setProps({ formatRate: this.formatRate, disabled: this.disabled });\n this.#core.setMedia(media);\n state = this.#core.getState();\n\n this.applyDefaultAriaLabel(\n translateText(this.#core.getLabel(state), this.#i18n.value, this.#core.getLabelParams(state))\n );\n this.#options.sync(state, this.#i18n.value, this.#i18n.locale);\n this.publishMenuOptionState(state.disabled, state.hidden, state.availability);\n } else {\n this.publishMenuOptionState(true, true, 'unsupported');\n }\n\n super.update(changed);\n\n if (state) applyStateDataAttrs(this, state, PlaybackRateRadioGroupDataAttrs);\n }\n}\n\nexport namespace PlaybackRateRadioGroupElement {\n export type State = PlaybackRateRadioGroupState;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAsBA,IAAa,gCAAb,cAAmD,sBAAsB;;;
|
|
1
|
+
{"version":3,"file":"element.js","names":[],"sources":["../../../../src/ui/playback-rate-radio-group/element.ts"],"sourcesContent":["import {\n PlaybackRateRadioGroupCore,\n PlaybackRateRadioGroupDataAttrs,\n type PlaybackRateRadioGroupOption,\n type PlaybackRateRadioGroupState,\n} from '@videojs/core';\nimport { applyStateDataAttrs, logMissingFeature, selectPlaybackRate } from '@videojs/core/dom';\nimport { translateText } from '@videojs/core/i18n';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\n\nimport { i18nContext } from '../../i18n/context';\nimport { I18nController } from '../../i18n/controller';\nimport { playerContext } from '../../player/context';\nimport { PlayerController } from '../../player/controller';\nimport { MenuRadioGroupElement } from '../menu/radio-group';\nimport { RadioOptionsController } from '../radio-options/controller';\n\n/**\n * Menu radio group that generates a `<media-menu-radio-item>` per available playback rate and shares the selected label\n * and availability with an enclosing menu. An optional `<template>` holding one `<media-menu-radio-item>` customizes\n * each generated item.\n */\nexport class PlaybackRateRadioGroupElement extends MenuRadioGroupElement {\n static override readonly tagName = 'media-playback-rate-radio-group';\n\n static override properties = {\n ...MenuRadioGroupElement.properties,\n disabled: { type: Boolean },\n rates: { type: String },\n } satisfies PropertyDeclarationMap<'value' | 'disabled' | 'rates'>;\n\n disabled = false;\n rates: readonly number[] | string | undefined = undefined;\n formatRate = PlaybackRateRadioGroupCore.defaultProps.formatRate;\n\n readonly #core = new PlaybackRateRadioGroupCore();\n readonly #i18n = new I18nController(this, i18nContext);\n readonly #mediaState = new PlayerController(this, playerContext, selectPlaybackRate);\n readonly #options = new RadioOptionsController<PlaybackRateRadioGroupOption>(this, {\n setItemAttributes: (item, option) => {\n item.setAttribute('data-rate', option.value);\n item.toggleAttribute('data-custom', option.custom);\n },\n getOptionCacheKey: (option) => (option.custom ? 'custom' : ''),\n onValueChange: (value) => {\n const media = this.#mediaState.value;\n\n if (media) this.#core.selectValue(media, value);\n },\n });\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n if (this.destroyed) return;\n\n if (__DEV__ && !this.#mediaState.value && this.#mediaState.displayName) {\n logMissingFeature(this.localName, this.#mediaState.displayName);\n }\n }\n\n protected override update(changed: PropertyValues): void {\n const media = this.#mediaState.value;\n let state: PlaybackRateRadioGroupState | null = null;\n\n if (media) {\n this.#core.setProps({ formatRate: this.formatRate, disabled: this.disabled, rates: this.rates });\n this.#core.setMedia(media);\n state = this.#core.getState();\n\n this.applyDefaultAriaLabel(\n translateText(this.#core.getLabel(state), this.#i18n.value, this.#core.getLabelParams(state))\n );\n this.#options.sync(state, this.#i18n.value, this.#i18n.locale);\n this.publishMenuOptionState(state.disabled, state.hidden, state.availability);\n } else {\n this.publishMenuOptionState(true, true, 'unsupported');\n }\n\n super.update(changed);\n\n if (state) applyStateDataAttrs(this, state, PlaybackRateRadioGroupDataAttrs);\n }\n}\n\nexport namespace PlaybackRateRadioGroupElement {\n export type State = PlaybackRateRadioGroupState;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAsBA,IAAa,gCAAb,cAAmD,sBAAsB;;;EAS5D,KAAA,WAAA;EACqC,KAAA,QAAA,KAAA;EACnC,KAAA,aAAA,2BAA2B,aAAa;EAEpC,KAAA,QAAA,IAAI,2BAA2B;EAC/B,KAAA,QAAA,IAAI,eAAe,MAAM,WAAW;EAC9B,KAAA,cAAA,IAAI,iBAAiB,MAAM,eAAe,kBAAkB;EAC/D,KAAA,WAAA,IAAI,uBAAqD,MAAM;GACjF,oBAAoB,MAAM,WAAW;IACnC,KAAK,aAAa,aAAa,OAAO,KAAK;IAC3C,KAAK,gBAAgB,eAAe,OAAO,MAAM;GACnD;GACA,oBAAoB,WAAY,OAAO,SAAS,WAAW;GAC3D,gBAAgB,UAAU;IACxB,MAAM,QAAQ,KAAK,YAAY;IAE/B,IAAI,OAAO,KAAK,MAAM,YAAY,OAAO,KAAK;GAChD;EACF,CAAC;;;EA1BkC,KAAA,UAAA;;;EAEN,KAAA,aAAA;GAC3B,GAAG,sBAAsB;GACzB,UAAU,EAAE,MAAM,QAAQ;GAC1B,OAAO,EAAE,MAAM,OAAO;EACxB;;CAMA;CACA;CACA;CACA;CAaA,oBAAmC;EACjC,MAAM,kBAAkB;EAExB,IAAI,KAAK,WAAW;EAEpB,IAAe,CAAC,KAAK,YAAY,SAAS,KAAK,YAAY,aACzD,kBAAkB,KAAK,WAAW,KAAK,YAAY,WAAW;CAElE;CAEA,OAA0B,SAA+B;EACvD,MAAM,QAAQ,KAAK,YAAY;EAC/B,IAAI,QAA4C;EAEhD,IAAI,OAAO;GACT,KAAK,MAAM,SAAS;IAAE,YAAY,KAAK;IAAY,UAAU,KAAK;IAAU,OAAO,KAAK;GAAM,CAAC;GAC/F,KAAK,MAAM,SAAS,KAAK;GACzB,QAAQ,KAAK,MAAM,SAAS;GAE5B,KAAK,sBACH,cAAc,KAAK,MAAM,SAAS,KAAK,GAAG,KAAK,MAAM,OAAO,KAAK,MAAM,eAAe,KAAK,CAAC,CAC9F;GACA,KAAK,SAAS,KAAK,OAAO,KAAK,MAAM,OAAO,KAAK,MAAM,MAAM;GAC7D,KAAK,uBAAuB,MAAM,UAAU,MAAM,QAAQ,MAAM,YAAY;EAC9E,OACE,KAAK,uBAAuB,MAAM,MAAM,aAAa;EAGvD,MAAM,OAAO,OAAO;EAEpB,IAAI,OAAO,oBAAoB,MAAM,OAAO,+BAA+B;CAC7E;AACF"}
|
|
@@ -4,6 +4,7 @@ import { MenuItemIndicatorElement } from "../menu/item-indicator.js";
|
|
|
4
4
|
import { applyElementProps } from "@videojs/core/dom";
|
|
5
5
|
import { translateText } from "@videojs/core/i18n";
|
|
6
6
|
import { cloneTemplateRoot, getTemplateElement, getTemplateRoot } from "@videojs/utils/dom";
|
|
7
|
+
import { isUndefined } from "@videojs/utils/predicate";
|
|
7
8
|
//#region src/ui/radio-options/controller.ts
|
|
8
9
|
/** Renders normalized options into menu radio items and manages their interaction lifecycle. */
|
|
9
10
|
var RadioOptionsController = class {
|
|
@@ -37,14 +38,12 @@ var RadioOptionsController = class {
|
|
|
37
38
|
const template = getTemplateElement(this.#host);
|
|
38
39
|
const templateRoot = template ? getTemplateRoot(template) : null;
|
|
39
40
|
const itemRoot = templateRoot?.localName === MenuRadioItemElement.tagName ? templateRoot : null;
|
|
40
|
-
const contentKey = `${state.options.map((option) => `${option.value}:${cacheKey(option.label, option.labelParams)}:${this.#config.getOptionCacheKey?.(option) ?? ""}`).join("|")}::${locale}::${template?.innerHTML ?? ""}`;
|
|
41
|
+
const contentKey = `${state.options.map((option) => `${option.value}:${cacheKey(option.label, option.labelParams)}:${cacheKey(option.ariaLabel ?? "", option.ariaLabelParams)}:${this.#config.getOptionCacheKey?.(option) ?? ""}`).join("|")}::${locale}::${template?.innerHTML ?? ""}`;
|
|
41
42
|
if (contentKey !== this.#contentKey || translator !== this.#translator) {
|
|
42
43
|
this.#contentKey = contentKey;
|
|
43
44
|
this.#translator = translator;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
child.remove();
|
|
47
|
-
}
|
|
45
|
+
const staleChildren = [...this.#host.children].filter((child) => child !== template);
|
|
46
|
+
const focusedValue = this.#getFocusedItem()?.value;
|
|
48
47
|
const items = state.options.map((option) => {
|
|
49
48
|
const item = itemRoot ? cloneTemplateRoot(itemRoot, this.#host.ownerDocument) : this.#host.ownerDocument.createElement(MenuRadioItemElement.tagName);
|
|
50
49
|
item.value = option.value;
|
|
@@ -52,9 +51,19 @@ var RadioOptionsController = class {
|
|
|
52
51
|
const label = translateText(option.label, translator, option.labelParams);
|
|
53
52
|
if (this.#config.renderItem) this.#config.renderItem(item, label, option);
|
|
54
53
|
else this.#setItemLabel(item, label);
|
|
54
|
+
if (!isUndefined(option.ariaLabel)) item.setAttribute("aria-label", translateText(option.ariaLabel, translator, option.ariaLabelParams));
|
|
55
55
|
return item;
|
|
56
56
|
});
|
|
57
57
|
this.#host.append(...items);
|
|
58
|
+
const removeStale = () => {
|
|
59
|
+
for (const child of staleChildren) child.remove();
|
|
60
|
+
};
|
|
61
|
+
const replacement = isUndefined(focusedValue) ? void 0 : items.find((item) => item.value === focusedValue) ?? items.find((item) => item.value === state.value);
|
|
62
|
+
if (replacement) replacement.updateComplete.then(() => {
|
|
63
|
+
replacement.focus();
|
|
64
|
+
removeStale();
|
|
65
|
+
});
|
|
66
|
+
else removeStale();
|
|
58
67
|
}
|
|
59
68
|
const optionsByValue = new Map(state.options.map((option) => [option.value, option]));
|
|
60
69
|
for (const item of this.#host.querySelectorAll(MenuRadioItemElement.tagName)) {
|
|
@@ -69,6 +78,10 @@ var RadioOptionsController = class {
|
|
|
69
78
|
const { value } = event.detail;
|
|
70
79
|
this.#config.onValueChange(value);
|
|
71
80
|
};
|
|
81
|
+
#getFocusedItem() {
|
|
82
|
+
const active = this.#host.getRootNode().activeElement;
|
|
83
|
+
return active instanceof MenuRadioItemElement && active.parentElement === this.#host ? active : null;
|
|
84
|
+
}
|
|
72
85
|
#setItemLabel(item, label) {
|
|
73
86
|
const labelPart = item.querySelector("[data-part~=\"label\"]");
|
|
74
87
|
if (labelPart) labelPart.textContent = label;
|