@videojs/html 10.1.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 +116 -65
- package/dist/default/define/audio/compat-skin2.js +1 -1
- package/dist/default/define/audio/neutral-skin.css +25 -16
- package/dist/default/define/audio/neutral-skin2.js +1 -1
- package/dist/default/define/audio/scaffold-skin.css +93 -51
- package/dist/default/define/audio/scaffold-skin2.js +1 -1
- package/dist/default/define/audio/skin.css +21 -6
- 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 +98 -65
- package/dist/default/define/live-audio/compat-skin2.js +1 -1
- package/dist/default/define/live-audio/neutral-skin.css +8 -5
- package/dist/default/define/live-audio/neutral-skin2.js +1 -1
- package/dist/default/define/live-audio/scaffold-skin.css +75 -51
- package/dist/default/define/live-audio/scaffold-skin2.js +1 -1
- package/dist/default/define/live-audio/skin.css +6 -5
- package/dist/default/define/live-audio/skin2.js +1 -1
- package/dist/default/define/live-video/compat-skin.css +123 -21
- 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 +107 -26
- 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 +123 -21
- package/dist/default/define/video/compat-skin2.js +1 -1
- package/dist/default/define/video/neutral-skin.css +85 -24
- package/dist/default/define/video/neutral-skin2.js +1 -1
- package/dist/default/define/video/scaffold-skin.css +107 -26
- 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/register.js +0 -10
- package/dist/default/internal/skins/compat-audio/skin.css +116 -65
- package/dist/default/internal/skins/compat-audio/template.js +15 -39
- package/dist/default/internal/skins/compat-live-audio/register.js +0 -10
- package/dist/default/internal/skins/compat-live-audio/skin.css +98 -65
- package/dist/default/internal/skins/compat-live-audio/template.js +2 -26
- package/dist/default/internal/skins/compat-live-video/skin.css +123 -21
- package/dist/default/internal/skins/compat-video/skin.css +123 -21
- package/dist/default/internal/skins/default-audio/skin.css +21 -6
- package/dist/default/internal/skins/default-live-audio/skin.css +6 -5
- 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 +25 -16
- package/dist/default/internal/skins/neutral-audio/template.js +1 -1
- package/dist/default/internal/skins/neutral-live-audio/skin.css +8 -5
- package/dist/default/internal/skins/neutral-live-video/skin.css +82 -14
- package/dist/default/internal/skins/neutral-video/skin.css +85 -24
- package/dist/default/internal/skins/neutral-video/template.js +1 -1
- package/dist/default/internal/skins/scaffold-audio/register.js +0 -10
- package/dist/default/internal/skins/scaffold-audio/skin.css +93 -51
- package/dist/default/internal/skins/scaffold-audio/template.js +15 -39
- package/dist/default/internal/skins/scaffold-live-audio/register.js +0 -10
- package/dist/default/internal/skins/scaffold-live-audio/skin.css +75 -51
- package/dist/default/internal/skins/scaffold-live-audio/template.js +2 -26
- package/dist/default/internal/skins/scaffold-live-video/skin.css +107 -26
- package/dist/default/internal/skins/scaffold-video/skin.css +107 -26
- package/dist/default/media/dailymotion-video/adapter.js +31 -0
- package/dist/default/media/hls-audio/adapter.js +1 -1
- package/dist/default/media/hls-background-video/adapter.js +8 -1
- package/dist/default/media/hls-video/adapter.js +1 -1
- 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/ui/slider/element.js +3 -1
- package/dist/default/ui/time-slider/element.js +19 -7
- package/dist/default/ui/volume-slider/element.js +3 -1
- package/dist/default/version.js +1 -1
- package/dist/dev/define/audio/compat-skin.css +116 -65
- 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 +25 -16
- 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 +93 -51
- 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 -6
- 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 +98 -65
- 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 -5
- 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 +75 -51
- 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 -5
- 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 +123 -21
- 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 +107 -26
- 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 +123 -21
- 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 +85 -24
- 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 +107 -26
- 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/register.d.ts +3 -5
- package/dist/dev/internal/skins/compat-audio/register.js +0 -10
- package/dist/dev/internal/skins/compat-audio/register.js.map +1 -1
- package/dist/dev/internal/skins/compat-audio/skin.css +116 -65
- package/dist/dev/internal/skins/compat-audio/template.js +15 -39
- package/dist/dev/internal/skins/compat-audio/template.js.map +1 -1
- package/dist/dev/internal/skins/compat-live-audio/register.d.ts +0 -2
- package/dist/dev/internal/skins/compat-live-audio/register.js +0 -10
- package/dist/dev/internal/skins/compat-live-audio/register.js.map +1 -1
- package/dist/dev/internal/skins/compat-live-audio/skin.css +98 -65
- package/dist/dev/internal/skins/compat-live-audio/template.js +2 -26
- package/dist/dev/internal/skins/compat-live-audio/template.js.map +1 -1
- package/dist/dev/internal/skins/compat-live-video/register.d.ts +2 -2
- package/dist/dev/internal/skins/compat-live-video/skin.css +123 -21
- package/dist/dev/internal/skins/compat-video/register.d.ts +5 -5
- package/dist/dev/internal/skins/compat-video/skin.css +123 -21
- package/dist/dev/internal/skins/default-audio/register.d.ts +1 -1
- package/dist/dev/internal/skins/default-audio/skin.css +21 -6
- package/dist/dev/internal/skins/default-live-audio/skin.css +6 -5
- package/dist/dev/internal/skins/default-live-video/register.d.ts +2 -2
- package/dist/dev/internal/skins/default-live-video/skin.css +96 -16
- package/dist/dev/internal/skins/default-video/register.d.ts +3 -3
- package/dist/dev/internal/skins/default-video/skin.css +94 -16
- package/dist/dev/internal/skins/neutral-audio/register.d.ts +3 -3
- package/dist/dev/internal/skins/neutral-audio/skin.css +25 -16
- package/dist/dev/internal/skins/neutral-audio/template.js +1 -1
- package/dist/dev/internal/skins/neutral-audio/template.js.map +1 -1
- package/dist/dev/internal/skins/neutral-live-audio/skin.css +8 -5
- package/dist/dev/internal/skins/neutral-live-video/register.d.ts +2 -2
- package/dist/dev/internal/skins/neutral-live-video/skin.css +82 -14
- package/dist/dev/internal/skins/neutral-video/register.d.ts +5 -5
- package/dist/dev/internal/skins/neutral-video/skin.css +85 -24
- package/dist/dev/internal/skins/neutral-video/template.js +1 -1
- package/dist/dev/internal/skins/neutral-video/template.js.map +1 -1
- package/dist/dev/internal/skins/scaffold-audio/register.d.ts +3 -5
- package/dist/dev/internal/skins/scaffold-audio/register.js +0 -10
- package/dist/dev/internal/skins/scaffold-audio/register.js.map +1 -1
- package/dist/dev/internal/skins/scaffold-audio/skin.css +93 -51
- package/dist/dev/internal/skins/scaffold-audio/template.js +15 -39
- package/dist/dev/internal/skins/scaffold-audio/template.js.map +1 -1
- package/dist/dev/internal/skins/scaffold-live-audio/register.d.ts +0 -2
- package/dist/dev/internal/skins/scaffold-live-audio/register.js +0 -10
- package/dist/dev/internal/skins/scaffold-live-audio/register.js.map +1 -1
- package/dist/dev/internal/skins/scaffold-live-audio/skin.css +75 -51
- package/dist/dev/internal/skins/scaffold-live-audio/template.js +2 -26
- package/dist/dev/internal/skins/scaffold-live-audio/template.js.map +1 -1
- package/dist/dev/internal/skins/scaffold-live-video/register.d.ts +2 -2
- package/dist/dev/internal/skins/scaffold-live-video/skin.css +107 -26
- package/dist/dev/internal/skins/scaffold-video/register.d.ts +5 -5
- package/dist/dev/internal/skins/scaffold-video/skin.css +107 -26
- 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-audio/adapter.d.ts +1 -1
- package/dist/dev/media/hls-audio/adapter.js +1 -1
- package/dist/dev/media/hls-audio/adapter.js.map +1 -1
- package/dist/dev/media/hls-background-video/adapter.d.ts +6 -1
- package/dist/dev/media/hls-background-video/adapter.js +8 -1
- package/dist/dev/media/hls-background-video/adapter.js.map +1 -1
- package/dist/dev/media/hls-video/adapter.d.ts +1 -1
- package/dist/dev/media/hls-video/adapter.js +1 -1
- package/dist/dev/media/hls-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/ui/slider/element.js +3 -1
- package/dist/dev/ui/slider/element.js.map +1 -1
- package/dist/dev/ui/time-slider/element.js +19 -7
- package/dist/dev/ui/time-slider/element.js.map +1 -1
- package/dist/dev/ui/volume-slider/element.js +3 -1
- package/dist/dev/ui/volume-slider/element.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 +13 -11
- package/docs/guides/build-your-own-skin.md +383 -0
- package/docs/guides/cdn.md +10 -9
- package/docs/guides/content-security-policy.md +3 -0
- package/docs/guides/customize-skins.md +6 -3
- 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 +3 -1
- package/docs/guides/media-sources.md +3 -0
- package/docs/guides/migrate-from-media-chrome.md +4 -4
- package/docs/guides/migrate-from-mux-player.md +9 -9
- package/docs/guides/migrate-from-plyr.md +8 -8
- package/docs/guides/migrate-from-video-js-8.md +9 -10
- package/docs/guides/migrate-from-vidstack.md +9 -9
- package/docs/guides/mux-data.md +22 -0
- package/docs/guides/presets.md +1 -1
- package/docs/guides/self-hosting.md +9 -6
- package/docs/guides/skins.md +17 -1
- package/docs/guides/ui-components.md +1 -1
- package/docs/llms.txt +12 -6
- 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 +2 -48
- package/docs/reference/components/hls-background-video.md +4 -1
- package/docs/reference/components/hls-video.md +2 -66
- 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 +22 -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/slider.md +2 -0
- 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/time-slider.md +7 -5
- 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/volume-slider.md +8 -6
- package/docs/reference/components/wistia-video.md +1 -1
- package/docs/reference/components/youtube-video.md +2 -1
- package/package.json +62 -43
|
@@ -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;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.js","names":[],"sources":["../../../../src/ui/radio-options/controller.ts"],"sourcesContent":["import type { RadioOption, RadioOptionsState } from '@videojs/core';\nimport { applyElementProps } from '@videojs/core/dom';\nimport { type Translator, translateText } from '@videojs/core/i18n';\nimport type { ReactiveController, ReactiveControllerHost } from '@videojs/element';\nimport { cloneTemplateRoot, getTemplateElement, getTemplateRoot } from '@videojs/utils/dom';\n\nimport { cacheKey } from '../../i18n/cache-key';\nimport { MenuItemIndicatorElement } from '../menu/item-indicator';\nimport { MenuRadioItemElement } from '../menu/radio-item';\n\nexport type RadioOptionsControllerHost = ReactiveControllerHost &\n HTMLElement & {\n value: string;\n };\n\nexport interface RadioOptionsControllerConfig<Option extends RadioOption> {\n renderItem?: ((item: MenuRadioItemElement, label: string, option: Option) => void) | undefined;\n setItemAttributes?: ((item: MenuRadioItemElement, option: Option) => void) | undefined;\n getOptionCacheKey?: ((option: Option) => string) | undefined;\n onValueChange: (value: string) => void;\n}\n\n/** Renders normalized options into menu radio items and manages their interaction lifecycle. */\nexport class RadioOptionsController<Option extends RadioOption> implements ReactiveController {\n readonly #host: RadioOptionsControllerHost;\n readonly #config: RadioOptionsControllerConfig<Option>;\n\n #contentKey = '';\n #translator: Translator | null = null;\n #disconnect: AbortController | null = null;\n\n constructor(host: RadioOptionsControllerHost, config: RadioOptionsControllerConfig<Option>) {\n this.#host = host;\n this.#config = config;\n host.addController(this);\n }\n\n hostConnected(): void {\n this.#disconnect = new AbortController();\n this.#host.addEventListener('value-change', this.#handleValueChange, { signal: this.#disconnect.signal });\n }\n\n hostDisconnected(): void {\n this.#disconnect?.abort();\n this.#disconnect = null;\n }\n\n hostDestroyed(): void {\n this.hostDisconnected();\n }\n\n sync(state: RadioOptionsState<Option>, translator: Translator, locale: string): void {\n this.#host.value = state.value;\n applyElementProps(this.#host, {\n 'aria-disabled': state.disabled ? 'true' : undefined,\n hidden: state.hidden ? '' : undefined,\n });\n\n const template = getTemplateElement(this.#host);\n const templateRoot = template ? getTemplateRoot(template) : null;\n const itemRoot = templateRoot?.localName === MenuRadioItemElement.tagName ? templateRoot : null;\n\n const contentKey = `${state.options\n .map(\n (option) =>\n `${option.value}:${cacheKey(option.label, option.labelParams)}:${this.#config.getOptionCacheKey?.(option) ?? ''}`\n )\n .join('|')}::${locale}::${template?.innerHTML ?? ''}`;\n\n if (contentKey !== this.#contentKey || translator !== this.#translator) {\n this.#contentKey = contentKey;\n this.#translator = translator;\n\n
|
|
1
|
+
{"version":3,"file":"controller.js","names":[],"sources":["../../../../src/ui/radio-options/controller.ts"],"sourcesContent":["import type { RadioOption, RadioOptionsState } from '@videojs/core';\nimport { applyElementProps } from '@videojs/core/dom';\nimport { type Translator, translateText } from '@videojs/core/i18n';\nimport type { ReactiveController, ReactiveControllerHost } from '@videojs/element';\nimport { cloneTemplateRoot, getTemplateElement, getTemplateRoot } from '@videojs/utils/dom';\nimport { isUndefined } from '@videojs/utils/predicate';\n\nimport { cacheKey } from '../../i18n/cache-key';\nimport { MenuItemIndicatorElement } from '../menu/item-indicator';\nimport { MenuRadioItemElement } from '../menu/radio-item';\n\nexport type RadioOptionsControllerHost = ReactiveControllerHost &\n HTMLElement & {\n value: string;\n };\n\nexport interface RadioOptionsControllerConfig<Option extends RadioOption> {\n renderItem?: ((item: MenuRadioItemElement, label: string, option: Option) => void) | undefined;\n setItemAttributes?: ((item: MenuRadioItemElement, option: Option) => void) | undefined;\n getOptionCacheKey?: ((option: Option) => string) | undefined;\n onValueChange: (value: string) => void;\n}\n\n/** Renders normalized options into menu radio items and manages their interaction lifecycle. */\nexport class RadioOptionsController<Option extends RadioOption> implements ReactiveController {\n readonly #host: RadioOptionsControllerHost;\n readonly #config: RadioOptionsControllerConfig<Option>;\n\n #contentKey = '';\n #translator: Translator | null = null;\n #disconnect: AbortController | null = null;\n\n constructor(host: RadioOptionsControllerHost, config: RadioOptionsControllerConfig<Option>) {\n this.#host = host;\n this.#config = config;\n host.addController(this);\n }\n\n hostConnected(): void {\n this.#disconnect = new AbortController();\n this.#host.addEventListener('value-change', this.#handleValueChange, { signal: this.#disconnect.signal });\n }\n\n hostDisconnected(): void {\n this.#disconnect?.abort();\n this.#disconnect = null;\n }\n\n hostDestroyed(): void {\n this.hostDisconnected();\n }\n\n sync(state: RadioOptionsState<Option>, translator: Translator, locale: string): void {\n this.#host.value = state.value;\n applyElementProps(this.#host, {\n 'aria-disabled': state.disabled ? 'true' : undefined,\n hidden: state.hidden ? '' : undefined,\n });\n\n const template = getTemplateElement(this.#host);\n const templateRoot = template ? getTemplateRoot(template) : null;\n const itemRoot = templateRoot?.localName === MenuRadioItemElement.tagName ? templateRoot : null;\n\n const contentKey = `${state.options\n .map(\n (option) =>\n `${option.value}:${cacheKey(option.label, option.labelParams)}:${cacheKey(option.ariaLabel ?? '', option.ariaLabelParams)}:${this.#config.getOptionCacheKey?.(option) ?? ''}`\n )\n .join('|')}::${locale}::${template?.innerHTML ?? ''}`;\n\n if (contentKey !== this.#contentKey || translator !== this.#translator) {\n this.#contentKey = contentKey;\n this.#translator = translator;\n\n const staleChildren = [...this.#host.children].filter((child) => child !== template);\n const focusedValue = this.#getFocusedItem()?.value;\n\n const items = state.options.map((option) => {\n const item = itemRoot\n ? (cloneTemplateRoot(itemRoot, this.#host.ownerDocument) as MenuRadioItemElement)\n : (this.#host.ownerDocument.createElement(MenuRadioItemElement.tagName) as MenuRadioItemElement);\n\n item.value = option.value;\n this.#config.setItemAttributes?.(item, option);\n const label = translateText(option.label, translator, option.labelParams);\n\n if (this.#config.renderItem) this.#config.renderItem(item, label, option);\n else this.#setItemLabel(item, label);\n\n if (!isUndefined(option.ariaLabel)) {\n item.setAttribute('aria-label', translateText(option.ariaLabel, translator, option.ariaLabelParams));\n }\n\n return item;\n });\n\n this.#host.append(...items);\n\n const removeStale = () => {\n for (const child of staleChildren) child.remove();\n };\n\n // Removing the focused item fires a `focusout` with no destination, which closes an open menu. Its replacement\n // registers with the menu, and becomes focusable, on its first update, so the old items stay until focus can move.\n const replacement = isUndefined(focusedValue)\n ? undefined\n : (items.find((item) => item.value === focusedValue) ?? items.find((item) => item.value === state.value));\n\n if (replacement) {\n void replacement.updateComplete.then(() => {\n replacement.focus();\n removeStale();\n });\n } else {\n removeStale();\n }\n }\n\n const optionsByValue = new Map(state.options.map((option) => [option.value, option]));\n\n for (const item of this.#host.querySelectorAll<MenuRadioItemElement>(MenuRadioItemElement.tagName)) {\n const checked = item.value === state.value;\n const option = optionsByValue.get(item.value);\n\n item.disabled = state.disabled || option?.disabled === true;\n\n for (const indicator of item.querySelectorAll<MenuItemIndicatorElement>(MenuItemIndicatorElement.tagName)) {\n indicator.checked = checked;\n }\n }\n }\n\n #handleValueChange = (event: Event): void => {\n if (event.target !== this.#host) return;\n\n const { value } = (event as CustomEvent<{ value: string }>).detail;\n\n this.#config.onValueChange(value);\n };\n\n #getFocusedItem(): MenuRadioItemElement | null {\n const active = (this.#host.getRootNode() as Document | ShadowRoot).activeElement;\n\n return active instanceof MenuRadioItemElement && active.parentElement === this.#host ? active : null;\n }\n\n #setItemLabel(item: MenuRadioItemElement, label: string): void {\n const labelPart = item.querySelector<HTMLElement>('[data-part~=\"label\"]');\n\n if (labelPart) labelPart.textContent = label;\n else item.textContent = label;\n }\n}\n"],"mappings":"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"}
|
|
@@ -103,7 +103,9 @@ var SliderElement = class extends UIElement {
|
|
|
103
103
|
this.dispatchEvent(new CustomEvent("drag-end", { bubbles: true }));
|
|
104
104
|
},
|
|
105
105
|
adjustPercent: (raw, thumbSize, trackSize) => this.#core.adjustPercentForAlignment(raw, thumbSize, trackSize),
|
|
106
|
-
onResize: () =>
|
|
106
|
+
onResize: () => {
|
|
107
|
+
if (this.thumbAlignment === "edge") this.requestUpdate();
|
|
108
|
+
}
|
|
107
109
|
});
|
|
108
110
|
applyElementProps(this, this.#slider.rootProps, { signal });
|
|
109
111
|
applyStyles(this, this.#slider.rootStyle);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"element.js","names":[],"sources":["../../../../src/ui/slider/element.ts"],"sourcesContent":["import { SliderCore, SliderDataAttrs, type SliderProps } from '@videojs/core';\nimport {\n applyElementProps,\n applyStateDataAttrs,\n createSlider,\n getSliderCSSVars,\n type SliderApi,\n selectControls,\n} from '@videojs/core/dom';\nimport { type Text, translateText } from '@videojs/core/i18n';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport { ContextProvider } from '@videojs/element/context';\nimport { applyStyles } from '@videojs/utils/dom';\n\nimport { i18nContext } from '../../i18n/context';\nimport { I18nController } from '../../i18n/controller';\nimport { playerContext } from '../../player/context';\nimport { PlayerController } from '../../player/controller';\nimport { UIElement } from '../ui-element';\nimport { sliderContext } from './context';\n\n/**\n * @fires value-change - Fired while the slider value changes during an interaction.\n * @fires value-commit - Fired when an interaction commits the slider value.\n * @fires drag-start - Fired when a pointer drag starts.\n * @fires drag-end - Fired when a pointer drag ends.\n */\nexport class SliderElement extends UIElement {\n static readonly tagName = 'media-slider';\n\n static override properties = {\n label: { type: String },\n value: { type: Number },\n min: { type: Number },\n max: { type: Number },\n step: { type: Number },\n largeStep: { type: Number, attribute: 'large-step' },\n orientation: { type: String },\n disabled: { type: Boolean },\n thumbAlignment: { type: String, attribute: 'thumb-alignment' },\n } satisfies PropertyDeclarationMap<keyof SliderProps>;\n\n label: Text | string = '';\n value = SliderCore.defaultProps.value;\n min = SliderCore.defaultProps.min;\n max = SliderCore.defaultProps.max;\n step = SliderCore.defaultProps.step;\n largeStep = SliderCore.defaultProps.largeStep;\n orientation = SliderCore.defaultProps.orientation;\n disabled = SliderCore.defaultProps.disabled;\n thumbAlignment = SliderCore.defaultProps.thumbAlignment;\n\n readonly #core = new SliderCore();\n readonly #controlsState = new PlayerController(this, playerContext, selectControls);\n readonly #i18n = new I18nController(this, i18nContext);\n readonly #provider = new ContextProvider(this, { context: sliderContext });\n\n #slider: SliderApi | null = null;\n #disconnect: AbortController | null = null;\n #releaseControlsLock: (() => void) | null = null;\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n if (this.destroyed) return;\n\n this.#disconnect = new AbortController();\n const signal = this.#disconnect.signal;\n\n this.#slider = createSlider({\n getElement: () => this,\n getThumbElement: () => this.querySelector<HTMLElement>('media-slider-thumb'),\n getOrientation: () => this.orientation,\n isDisabled: () => this.disabled,\n getPercent: () => this.#core.percentFromValue(this.value),\n getStepPercent: () => this.#core.getStepPercent(),\n getLargeStepPercent: () => this.#core.getLargeStepPercent(),\n onValueChange: (percent) => {\n this.value = this.#core.valueFromPercent(percent);\n this.dispatchEvent(new CustomEvent('value-change', { detail: { value: this.value }, bubbles: true }));\n },\n onValueCommit: (percent) => {\n this.value = this.#core.valueFromPercent(percent);\n this.dispatchEvent(new CustomEvent('value-commit', { detail: { value: this.value }, bubbles: true }));\n },\n onPressStart: () => {\n this.#releaseControlsLock ??= this.#controlsState.value?.requestControlsLock() ?? null;\n },\n onPressEnd: () => this.#releaseControlsVisibilityLock(),\n onDragStart: () => {\n this.dispatchEvent(new CustomEvent('drag-start', { bubbles: true }));\n },\n onDragEnd: () => {\n this.dispatchEvent(new CustomEvent('drag-end', { bubbles: true }));\n },\n adjustPercent: (raw, thumbSize, trackSize) => this.#core.adjustPercentForAlignment(raw, thumbSize, trackSize),\n onResize: () => this.requestUpdate(),\n });\n\n applyElementProps(this, this.#slider.rootProps, { signal });\n applyStyles(this, this.#slider.rootStyle);\n this.#slider.input.subscribe(() => this.requestUpdate(), { signal });\n }\n\n override disconnectedCallback(): void {\n this.#releaseControlsVisibilityLock();\n super.disconnectedCallback();\n this.#disconnect?.abort();\n this.#disconnect = null;\n }\n\n override destroyCallback(): void {\n this.#releaseControlsVisibilityLock();\n this.#slider?.destroy();\n super.destroyCallback();\n }\n\n #releaseControlsVisibilityLock(): void {\n this.#releaseControlsLock?.();\n this.#releaseControlsLock = null;\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 if (!this.#slider) return;\n\n this.#core.setInput(this.#slider.input.current);\n const state = this.#core.getSliderState(this.value);\n\n const cssVars = getSliderCSSVars(this.#slider.adjustForAlignment(state));\n\n applyStyles(this, cssVars);\n\n // Apply state data attributes to the root element.\n applyStateDataAttrs(this, state, SliderDataAttrs);\n\n // Provide context to child elements (thumb, value, track, etc.).\n this.#provider.setValue({\n state,\n stateAttrMap: SliderDataAttrs,\n pointerValue: this.#core.valueFromPercent(state.pointerPercent),\n thumbAttrs: (() => {\n const attrs = this.#core.getAttrs(state);\n\n return { ...attrs, 'aria-label': translateText(attrs['aria-label'], this.#i18n.value) };\n })(),\n thumbProps: this.#slider.thumbProps,\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA2BA,IAAa,gBAAb,cAAmC,UAAU;;;EAepB,KAAA,QAAA;EACf,KAAA,QAAA,WAAW,aAAa;EAC1B,KAAA,MAAA,WAAW,aAAa;EACxB,KAAA,MAAA,WAAW,aAAa;EACvB,KAAA,OAAA,WAAW,aAAa;EACnB,KAAA,YAAA,WAAW,aAAa;EACtB,KAAA,cAAA,WAAW,aAAa;EAC3B,KAAA,WAAA,WAAW,aAAa;EAClB,KAAA,iBAAA,WAAW,aAAa;EAExB,KAAA,QAAA,IAAI,WAAW;EACN,KAAA,iBAAA,IAAI,iBAAiB,MAAM,eAAe,cAAc;EACjE,KAAA,QAAA,IAAI,eAAe,MAAM,WAAW;EAChC,KAAA,YAAA,IAAI,gBAAgB,MAAM,EAAE,SAAS,cAAc,CAAC;EAE7C,KAAA,UAAA;EACU,KAAA,cAAA;EACM,KAAA,uBAAA;;;EA/BlB,KAAA,UAAA;;;EAEG,KAAA,aAAA;GAC3B,OAAO,EAAE,MAAM,OAAO;GACtB,OAAO,EAAE,MAAM,OAAO;GACtB,KAAK,EAAE,MAAM,OAAO;GACpB,KAAK,EAAE,MAAM,OAAO;GACpB,MAAM,EAAE,MAAM,OAAO;GACrB,WAAW;IAAE,MAAM;IAAQ,WAAW;GAAa;GACnD,aAAa,EAAE,MAAM,OAAO;GAC5B,UAAU,EAAE,MAAM,QAAQ;GAC1B,gBAAgB;IAAE,MAAM;IAAQ,WAAW;GAAkB;EAC/D;;CAYA;CACA;CACA;CACA;CAEA;CACA;CACA;CAEA,oBAAmC;EACjC,MAAM,kBAAkB;EAExB,IAAI,KAAK,WAAW;EAEpB,KAAK,cAAc,IAAI,gBAAgB;EACvC,MAAM,SAAS,KAAK,YAAY;EAEhC,KAAK,UAAU,aAAa;GAC1B,kBAAkB;GAClB,uBAAuB,KAAK,cAA2B,oBAAoB;GAC3E,sBAAsB,KAAK;GAC3B,kBAAkB,KAAK;GACvB,kBAAkB,KAAK,MAAM,iBAAiB,KAAK,KAAK;GACxD,sBAAsB,KAAK,MAAM,eAAe;GAChD,2BAA2B,KAAK,MAAM,oBAAoB;GAC1D,gBAAgB,YAAY;IAC1B,KAAK,QAAQ,KAAK,MAAM,iBAAiB,OAAO;IAChD,KAAK,cAAc,IAAI,YAAY,gBAAgB;KAAE,QAAQ,EAAE,OAAO,KAAK,MAAM;KAAG,SAAS;IAAK,CAAC,CAAC;GACtG;GACA,gBAAgB,YAAY;IAC1B,KAAK,QAAQ,KAAK,MAAM,iBAAiB,OAAO;IAChD,KAAK,cAAc,IAAI,YAAY,gBAAgB;KAAE,QAAQ,EAAE,OAAO,KAAK,MAAM;KAAG,SAAS;IAAK,CAAC,CAAC;GACtG;GACA,oBAAoB;IAClB,KAAK,yBAAyB,KAAK,eAAe,OAAO,oBAAoB,KAAK;GACpF;GACA,kBAAkB,KAAK,+BAA+B;GACtD,mBAAmB;IACjB,KAAK,cAAc,IAAI,YAAY,cAAc,EAAE,SAAS,KAAK,CAAC,CAAC;GACrE;GACA,iBAAiB;IACf,KAAK,cAAc,IAAI,YAAY,YAAY,EAAE,SAAS,KAAK,CAAC,CAAC;GACnE;GACA,gBAAgB,KAAK,WAAW,cAAc,KAAK,MAAM,0BAA0B,KAAK,WAAW,SAAS;
|
|
1
|
+
{"version":3,"file":"element.js","names":[],"sources":["../../../../src/ui/slider/element.ts"],"sourcesContent":["import { SliderCore, SliderDataAttrs, type SliderProps } from '@videojs/core';\nimport {\n applyElementProps,\n applyStateDataAttrs,\n createSlider,\n getSliderCSSVars,\n type SliderApi,\n selectControls,\n} from '@videojs/core/dom';\nimport { type Text, translateText } from '@videojs/core/i18n';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport { ContextProvider } from '@videojs/element/context';\nimport { applyStyles } from '@videojs/utils/dom';\n\nimport { i18nContext } from '../../i18n/context';\nimport { I18nController } from '../../i18n/controller';\nimport { playerContext } from '../../player/context';\nimport { PlayerController } from '../../player/controller';\nimport { UIElement } from '../ui-element';\nimport { sliderContext } from './context';\n\n/**\n * @fires value-change - Fired while the slider value changes during an interaction.\n * @fires value-commit - Fired when an interaction commits the slider value.\n * @fires drag-start - Fired when a pointer drag starts.\n * @fires drag-end - Fired when a pointer drag ends.\n */\nexport class SliderElement extends UIElement {\n static readonly tagName = 'media-slider';\n\n static override properties = {\n label: { type: String },\n value: { type: Number },\n min: { type: Number },\n max: { type: Number },\n step: { type: Number },\n largeStep: { type: Number, attribute: 'large-step' },\n orientation: { type: String },\n disabled: { type: Boolean },\n thumbAlignment: { type: String, attribute: 'thumb-alignment' },\n } satisfies PropertyDeclarationMap<keyof SliderProps>;\n\n label: Text | string = '';\n value = SliderCore.defaultProps.value;\n min = SliderCore.defaultProps.min;\n max = SliderCore.defaultProps.max;\n step = SliderCore.defaultProps.step;\n largeStep = SliderCore.defaultProps.largeStep;\n orientation = SliderCore.defaultProps.orientation;\n disabled = SliderCore.defaultProps.disabled;\n thumbAlignment = SliderCore.defaultProps.thumbAlignment;\n\n readonly #core = new SliderCore();\n readonly #controlsState = new PlayerController(this, playerContext, selectControls);\n readonly #i18n = new I18nController(this, i18nContext);\n readonly #provider = new ContextProvider(this, { context: sliderContext });\n\n #slider: SliderApi | null = null;\n #disconnect: AbortController | null = null;\n #releaseControlsLock: (() => void) | null = null;\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n if (this.destroyed) return;\n\n this.#disconnect = new AbortController();\n const signal = this.#disconnect.signal;\n\n this.#slider = createSlider({\n getElement: () => this,\n getThumbElement: () => this.querySelector<HTMLElement>('media-slider-thumb'),\n getOrientation: () => this.orientation,\n isDisabled: () => this.disabled,\n getPercent: () => this.#core.percentFromValue(this.value),\n getStepPercent: () => this.#core.getStepPercent(),\n getLargeStepPercent: () => this.#core.getLargeStepPercent(),\n onValueChange: (percent) => {\n this.value = this.#core.valueFromPercent(percent);\n this.dispatchEvent(new CustomEvent('value-change', { detail: { value: this.value }, bubbles: true }));\n },\n onValueCommit: (percent) => {\n this.value = this.#core.valueFromPercent(percent);\n this.dispatchEvent(new CustomEvent('value-commit', { detail: { value: this.value }, bubbles: true }));\n },\n onPressStart: () => {\n this.#releaseControlsLock ??= this.#controlsState.value?.requestControlsLock() ?? null;\n },\n onPressEnd: () => this.#releaseControlsVisibilityLock(),\n onDragStart: () => {\n this.dispatchEvent(new CustomEvent('drag-start', { bubbles: true }));\n },\n onDragEnd: () => {\n this.dispatchEvent(new CustomEvent('drag-end', { bubbles: true }));\n },\n adjustPercent: (raw, thumbSize, trackSize) => this.#core.adjustPercentForAlignment(raw, thumbSize, trackSize),\n // Only edge alignment depends on the slider's size.\n onResize: () => {\n if (this.thumbAlignment === 'edge') this.requestUpdate();\n },\n });\n\n applyElementProps(this, this.#slider.rootProps, { signal });\n applyStyles(this, this.#slider.rootStyle);\n this.#slider.input.subscribe(() => this.requestUpdate(), { signal });\n }\n\n override disconnectedCallback(): void {\n this.#releaseControlsVisibilityLock();\n super.disconnectedCallback();\n this.#disconnect?.abort();\n this.#disconnect = null;\n }\n\n override destroyCallback(): void {\n this.#releaseControlsVisibilityLock();\n this.#slider?.destroy();\n super.destroyCallback();\n }\n\n #releaseControlsVisibilityLock(): void {\n this.#releaseControlsLock?.();\n this.#releaseControlsLock = null;\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 if (!this.#slider) return;\n\n this.#core.setInput(this.#slider.input.current);\n const state = this.#core.getSliderState(this.value);\n\n const cssVars = getSliderCSSVars(this.#slider.adjustForAlignment(state));\n\n applyStyles(this, cssVars);\n\n // Apply state data attributes to the root element.\n applyStateDataAttrs(this, state, SliderDataAttrs);\n\n // Provide context to child elements (thumb, value, track, etc.).\n this.#provider.setValue({\n state,\n stateAttrMap: SliderDataAttrs,\n pointerValue: this.#core.valueFromPercent(state.pointerPercent),\n thumbAttrs: (() => {\n const attrs = this.#core.getAttrs(state);\n\n return { ...attrs, 'aria-label': translateText(attrs['aria-label'], this.#i18n.value) };\n })(),\n thumbProps: this.#slider.thumbProps,\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -84,6 +84,15 @@ var TimeSliderElement = class extends UIElement {
|
|
|
84
84
|
if (this.destroyed) return;
|
|
85
85
|
this.#disconnect = new AbortController();
|
|
86
86
|
const signal = this.#disconnect.signal;
|
|
87
|
+
let dragSeekPercent;
|
|
88
|
+
const seek = (percent) => {
|
|
89
|
+
const media = this.#timeState.value;
|
|
90
|
+
if (media) {
|
|
91
|
+
const time = this.#core.rawValueFromPercent(percent);
|
|
92
|
+
this.#seek.seek(percent);
|
|
93
|
+
media.seek(time);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
87
96
|
this.#slider = createSlider({
|
|
88
97
|
getElement: () => this,
|
|
89
98
|
getThumbElement: () => this.querySelector("media-slider-thumb"),
|
|
@@ -106,13 +115,14 @@ var TimeSliderElement = class extends UIElement {
|
|
|
106
115
|
},
|
|
107
116
|
getStepPercent: () => this.#core.getStepPercent(),
|
|
108
117
|
getLargeStepPercent: () => this.#core.getLargeStepPercent(),
|
|
118
|
+
onValueChange: (percent) => {
|
|
119
|
+
if (!this.#slider?.input.current.dragging || percent === dragSeekPercent) return;
|
|
120
|
+
dragSeekPercent = percent;
|
|
121
|
+
seek(percent);
|
|
122
|
+
},
|
|
109
123
|
onValueCommit: (percent) => {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const time = this.#core.rawValueFromPercent(percent);
|
|
113
|
-
this.#seek.seek(percent);
|
|
114
|
-
media.seek(time);
|
|
115
|
-
}
|
|
124
|
+
if (percent !== dragSeekPercent) seek(percent);
|
|
125
|
+
dragSeekPercent = void 0;
|
|
116
126
|
},
|
|
117
127
|
changeThrottle: this.changeThrottle,
|
|
118
128
|
onPressStart: () => {
|
|
@@ -128,7 +138,9 @@ var TimeSliderElement = class extends UIElement {
|
|
|
128
138
|
this.dispatchEvent(new CustomEvent("drag-end", { bubbles: true }));
|
|
129
139
|
},
|
|
130
140
|
adjustPercent: (raw, thumbSize, trackSize) => this.#core.adjustPercentForAlignment(raw, thumbSize, trackSize),
|
|
131
|
-
onResize: () =>
|
|
141
|
+
onResize: () => {
|
|
142
|
+
if (this.thumbAlignment === "edge") this.requestUpdate();
|
|
143
|
+
}
|
|
132
144
|
});
|
|
133
145
|
applyElementProps(this, this.#slider.rootProps, { signal });
|
|
134
146
|
applyStyles(this, this.#slider.rootStyle);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"element.js","names":[],"sources":["../../../../src/ui/time-slider/element.ts"],"sourcesContent":["import { SliderCSSVars, TimeSliderCore, TimeSliderDataAttrs, type TimeSliderProps } from '@videojs/core';\nimport {\n applyElementProps,\n applyStateDataAttrs,\n createSlider,\n createTimeSliderSeek,\n getTimeSliderCSSVars,\n logMissingFeature,\n type SliderApi,\n selectBuffer,\n selectControls,\n selectPlayback,\n selectTime,\n} from '@videojs/core/dom';\nimport { type Text, translateText } from '@videojs/core/i18n';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport { ContextProvider } from '@videojs/element/context';\nimport { hasTimeRange, isMediaPlaying } from '@videojs/media';\nimport { applyStyles } from '@videojs/utils/dom';\nimport { formatTime } from '@videojs/utils/time';\n\nimport { i18nContext } from '../../i18n/context';\nimport { I18nController } from '../../i18n/controller';\nimport { playerContext } from '../../player/context';\nimport { PlayerController } from '../../player/controller';\nimport { sliderContext } from '../slider/context';\nimport { UIElement } from '../ui-element';\n\n/**\n * @fires drag-start - Fired when a pointer drag starts.\n * @fires drag-end - Fired when a pointer drag ends.\n */\nexport class TimeSliderElement extends UIElement {\n static readonly tagName = 'media-time-slider';\n\n static override properties = {\n label: { type: String },\n changeThrottle: { type: Number, attribute: 'change-throttle' },\n step: { type: Number },\n largeStep: { type: Number, attribute: 'large-step' },\n orientation: { type: String },\n disabled: { type: Boolean },\n thumbAlignment: { type: String, attribute: 'thumb-alignment' },\n pauseOnDrag: { type: Boolean, attribute: 'pause-on-drag' },\n } satisfies PropertyDeclarationMap<Exclude<keyof TimeSliderProps, 'value' | 'min' | 'max'>>;\n\n label: Text | string = '';\n changeThrottle = TimeSliderCore.defaultProps.changeThrottle;\n step = TimeSliderCore.defaultProps.step;\n largeStep = TimeSliderCore.defaultProps.largeStep;\n orientation = TimeSliderCore.defaultProps.orientation;\n disabled = TimeSliderCore.defaultProps.disabled;\n thumbAlignment = TimeSliderCore.defaultProps.thumbAlignment;\n pauseOnDrag = TimeSliderCore.defaultProps.pauseOnDrag;\n\n readonly #core = new TimeSliderCore();\n readonly #controlsState = new PlayerController(this, playerContext, selectControls);\n readonly #provider = new ContextProvider(this, { context: sliderContext });\n readonly #timeState = new PlayerController(this, playerContext, selectTime);\n readonly #bufferState = new PlayerController(this, playerContext, selectBuffer);\n readonly #playbackState = new PlayerController(this, playerContext, selectPlayback);\n readonly #seek = createTimeSliderSeek(SliderCSSVars.fill);\n readonly #i18n = new I18nController(this, i18nContext);\n\n #cssVars: Record<string, string> = {};\n #slider: SliderApi | null = null;\n #disconnect: AbortController | null = null;\n #releaseControlsLock: (() => void) | null = null;\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n if (this.destroyed) return;\n\n this.#disconnect = new AbortController();\n const signal = this.#disconnect.signal;\n\n this.#slider = createSlider({\n getElement: () => this,\n getThumbElement: () => this.querySelector<HTMLElement>('media-slider-thumb'),\n getOrientation: () => this.orientation,\n isDisabled: () => {\n const time = this.#timeState.value;\n const buffer = this.#bufferState.value;\n\n // `bufferFeature` is optional: compositions that omit it still get a working slider, with an empty buffer.\n return this.disabled || !time || !hasTimeRange({ ...time, ...(buffer ?? { buffered: [], seekable: [] }) });\n },\n getPercent: () => {\n const media = this.#timeState.value;\n if (!media) return 0;\n\n return this.#core.percentFromValue(media.currentTime);\n },\n getStepPercent: () => this.#core.getStepPercent(),\n getLargeStepPercent: () => this.#core.getLargeStepPercent(),\n onValueCommit: (percent) => {\n const media = this.#timeState.value;\n\n if (media) {\n const time = this.#core.rawValueFromPercent(percent);\n\n this.#seek.seek(percent);\n media.seek(time);\n }\n },\n changeThrottle: this.changeThrottle,\n onPressStart: () => {\n this.#releaseControlsLock ??= this.#controlsState.value?.requestControlsLock() ?? null;\n },\n onPressEnd: () => this.#releaseControlsVisibilityLock(),\n onDragStart: () => {\n this.#core.startDrag(this.#playbackState.value);\n this.dispatchEvent(new CustomEvent('drag-start', { bubbles: true }));\n },\n onDragEnd: () => {\n this.#core.endDrag(this.#playbackState.value);\n this.dispatchEvent(new CustomEvent('drag-end', { bubbles: true }));\n },\n adjustPercent: (raw, thumbSize, trackSize) => this.#core.adjustPercentForAlignment(raw, thumbSize, trackSize),\n onResize: () => this.requestUpdate(),\n });\n\n applyElementProps(this, this.#slider.rootProps, { signal });\n applyStyles(this, this.#slider.rootStyle);\n this.#slider.input.subscribe(() => this.requestUpdate(), { signal });\n this.#seek.state.subscribe(() => this.requestUpdate(), { signal });\n\n if (__DEV__ && !this.#timeState.value) {\n logMissingFeature(this.localName, this.#timeState.displayName!);\n }\n }\n\n override disconnectedCallback(): void {\n this.#releaseControlsVisibilityLock();\n this.#resumeIfDragPaused();\n this.#seek.destroy();\n super.disconnectedCallback();\n this.#disconnect?.abort();\n this.#disconnect = null;\n }\n\n override destroyCallback(): void {\n this.#releaseControlsVisibilityLock();\n this.#resumeIfDragPaused();\n this.#seek.destroy();\n this.#slider?.destroy();\n super.destroyCallback();\n }\n\n // createSlider's destroy() does not fire onDragEnd, so a teardown mid-drag\n // would leave playback paused. Called from both disconnect and destroy paths\n // before super so the PlayerController is still attached.\n #resumeIfDragPaused(): void {\n this.#core.endDrag(this.#playbackState.value);\n }\n\n #releaseControlsVisibilityLock(): void {\n this.#releaseControlsLock?.();\n this.#releaseControlsLock = null;\n }\n\n protected override willUpdate(_changed: PropertyValues): void {\n super.willUpdate(_changed);\n this.#core.setProps({\n label: this.label,\n changeThrottle: this.changeThrottle,\n step: this.step,\n largeStep: this.largeStep,\n orientation: this.orientation,\n disabled: this.disabled,\n thumbAlignment: this.thumbAlignment,\n pauseOnDrag: this.pauseOnDrag,\n });\n this.#core.setFormatLocale(this.#i18n.locale);\n }\n\n protected override update(_changed: PropertyValues): void {\n super.update(_changed);\n\n if (!this.#slider) return;\n\n const time = this.#timeState.value;\n const buffer = this.#bufferState.value;\n\n if (!time) {\n this.#seek.destroy();\n this.removeAttribute('data-playing');\n return;\n }\n\n this.#core.setInput(this.#slider.input.current);\n const media = { ...time, ...(buffer ?? { buffered: [], seekable: [] }) };\n\n this.#core.setMedia(media);\n const state = this.#core.getState();\n\n this.#seek.update(state.seeking, state.fillPercent, this);\n const percent = this.#seek.state.current.percent;\n\n this.toggleAttribute(\n 'data-playing',\n isMediaPlaying(this.#playbackState.value) &&\n !state.disabled &&\n !state.dragging &&\n !state.seeking &&\n percent === undefined\n );\n\n const fill = percent === undefined || state.dragging || state.disabled ? state : { ...state, fillPercent: percent };\n const cssVars = getTimeSliderCSSVars(this.#slider.adjustForAlignment(fill));\n const styles = Object.fromEntries(Object.entries(cssVars).filter(([name, value]) => this.#cssVars[name] !== value));\n\n applyStyles(this, styles);\n this.#cssVars = cssVars;\n\n const thumbAttrs = this.#core.getAttrs(state);\n\n // Domain-specific data attributes on root (includes data-seeking).\n applyStateDataAttrs(this, state, TimeSliderDataAttrs);\n\n // Provide context to child elements with base slider data attrs.\n this.#provider.setValue({\n state,\n stateAttrMap: TimeSliderDataAttrs,\n pointerValue: this.#core.rawValueFromPercent(state.pointerPercent),\n thumbAttrs: {\n ...thumbAttrs,\n 'aria-label': translateText(thumbAttrs['aria-label'], this.#i18n.value),\n 'aria-valuetext': translateText(\n thumbAttrs['aria-valuetext'],\n this.#i18n.value,\n this.#core.getValueTextParams(state)\n ),\n },\n thumbProps: this.#slider.thumbProps,\n formatValue: (value) => formatTime(value, state.duration, { locale: this.#i18n.locale }),\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"element.js","names":[],"sources":["../../../../src/ui/time-slider/element.ts"],"sourcesContent":["import { SliderCSSVars, TimeSliderCore, TimeSliderDataAttrs, type TimeSliderProps } from '@videojs/core';\nimport {\n applyElementProps,\n applyStateDataAttrs,\n createSlider,\n createTimeSliderSeek,\n getTimeSliderCSSVars,\n logMissingFeature,\n type SliderApi,\n selectBuffer,\n selectControls,\n selectPlayback,\n selectTime,\n} from '@videojs/core/dom';\nimport { type Text, translateText } from '@videojs/core/i18n';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport { ContextProvider } from '@videojs/element/context';\nimport { hasTimeRange, isMediaPlaying } from '@videojs/media';\nimport { applyStyles } from '@videojs/utils/dom';\nimport { formatTime } from '@videojs/utils/time';\n\nimport { i18nContext } from '../../i18n/context';\nimport { I18nController } from '../../i18n/controller';\nimport { playerContext } from '../../player/context';\nimport { PlayerController } from '../../player/controller';\nimport { sliderContext } from '../slider/context';\nimport { UIElement } from '../ui-element';\n\n/**\n * @fires drag-start - Fired when a pointer drag starts.\n * @fires drag-end - Fired when a pointer drag ends.\n */\nexport class TimeSliderElement extends UIElement {\n static readonly tagName = 'media-time-slider';\n\n static override properties = {\n label: { type: String },\n changeThrottle: { type: Number, attribute: 'change-throttle' },\n step: { type: Number },\n largeStep: { type: Number, attribute: 'large-step' },\n orientation: { type: String },\n disabled: { type: Boolean },\n thumbAlignment: { type: String, attribute: 'thumb-alignment' },\n pauseOnDrag: { type: Boolean, attribute: 'pause-on-drag' },\n } satisfies PropertyDeclarationMap<Exclude<keyof TimeSliderProps, 'value' | 'min' | 'max'>>;\n\n label: Text | string = '';\n changeThrottle = TimeSliderCore.defaultProps.changeThrottle;\n step = TimeSliderCore.defaultProps.step;\n largeStep = TimeSliderCore.defaultProps.largeStep;\n orientation = TimeSliderCore.defaultProps.orientation;\n disabled = TimeSliderCore.defaultProps.disabled;\n thumbAlignment = TimeSliderCore.defaultProps.thumbAlignment;\n pauseOnDrag = TimeSliderCore.defaultProps.pauseOnDrag;\n\n readonly #core = new TimeSliderCore();\n readonly #controlsState = new PlayerController(this, playerContext, selectControls);\n readonly #provider = new ContextProvider(this, { context: sliderContext });\n readonly #timeState = new PlayerController(this, playerContext, selectTime);\n readonly #bufferState = new PlayerController(this, playerContext, selectBuffer);\n readonly #playbackState = new PlayerController(this, playerContext, selectPlayback);\n readonly #seek = createTimeSliderSeek(SliderCSSVars.fill);\n readonly #i18n = new I18nController(this, i18nContext);\n\n #cssVars: Record<string, string> = {};\n #slider: SliderApi | null = null;\n #disconnect: AbortController | null = null;\n #releaseControlsLock: (() => void) | null = null;\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n if (this.destroyed) return;\n\n this.#disconnect = new AbortController();\n const signal = this.#disconnect.signal;\n\n let dragSeekPercent: number | undefined;\n\n const seek = (percent: number) => {\n const media = this.#timeState.value;\n\n if (media) {\n const time = this.#core.rawValueFromPercent(percent);\n\n this.#seek.seek(percent);\n media.seek(time);\n }\n };\n\n this.#slider = createSlider({\n getElement: () => this,\n getThumbElement: () => this.querySelector<HTMLElement>('media-slider-thumb'),\n getOrientation: () => this.orientation,\n isDisabled: () => {\n const time = this.#timeState.value;\n const buffer = this.#bufferState.value;\n\n // `bufferFeature` is optional: compositions that omit it still get a working slider, with an empty buffer.\n return this.disabled || !time || !hasTimeRange({ ...time, ...(buffer ?? { buffered: [], seekable: [] }) });\n },\n getPercent: () => {\n const media = this.#timeState.value;\n if (!media) return 0;\n\n return this.#core.percentFromValue(media.currentTime);\n },\n getStepPercent: () => this.#core.getStepPercent(),\n getLargeStepPercent: () => this.#core.getLargeStepPercent(),\n // Seek on each (throttled) change while dragging so the frame follows the thumb.\n // Presses and key steps seek once, on commit.\n onValueChange: (percent) => {\n if (!this.#slider?.input.current.dragging || percent === dragSeekPercent) return;\n\n dragSeekPercent = percent;\n seek(percent);\n },\n onValueCommit: (percent) => {\n // Skip the commit when the drag already sought this position.\n if (percent !== dragSeekPercent) seek(percent);\n\n dragSeekPercent = undefined;\n },\n changeThrottle: this.changeThrottle,\n onPressStart: () => {\n this.#releaseControlsLock ??= this.#controlsState.value?.requestControlsLock() ?? null;\n },\n onPressEnd: () => this.#releaseControlsVisibilityLock(),\n onDragStart: () => {\n this.#core.startDrag(this.#playbackState.value);\n this.dispatchEvent(new CustomEvent('drag-start', { bubbles: true }));\n },\n onDragEnd: () => {\n this.#core.endDrag(this.#playbackState.value);\n this.dispatchEvent(new CustomEvent('drag-end', { bubbles: true }));\n },\n adjustPercent: (raw, thumbSize, trackSize) => this.#core.adjustPercentForAlignment(raw, thumbSize, trackSize),\n // Only edge alignment depends on the slider's size.\n onResize: () => {\n if (this.thumbAlignment === 'edge') this.requestUpdate();\n },\n });\n\n applyElementProps(this, this.#slider.rootProps, { signal });\n applyStyles(this, this.#slider.rootStyle);\n this.#slider.input.subscribe(() => this.requestUpdate(), { signal });\n this.#seek.state.subscribe(() => this.requestUpdate(), { signal });\n\n if (__DEV__ && !this.#timeState.value) {\n logMissingFeature(this.localName, this.#timeState.displayName!);\n }\n }\n\n override disconnectedCallback(): void {\n this.#releaseControlsVisibilityLock();\n this.#resumeIfDragPaused();\n this.#seek.destroy();\n super.disconnectedCallback();\n this.#disconnect?.abort();\n this.#disconnect = null;\n }\n\n override destroyCallback(): void {\n this.#releaseControlsVisibilityLock();\n this.#resumeIfDragPaused();\n this.#seek.destroy();\n this.#slider?.destroy();\n super.destroyCallback();\n }\n\n // createSlider's destroy() does not fire onDragEnd, so a teardown mid-drag\n // would leave playback paused. Called from both disconnect and destroy paths\n // before super so the PlayerController is still attached.\n #resumeIfDragPaused(): void {\n this.#core.endDrag(this.#playbackState.value);\n }\n\n #releaseControlsVisibilityLock(): void {\n this.#releaseControlsLock?.();\n this.#releaseControlsLock = null;\n }\n\n protected override willUpdate(_changed: PropertyValues): void {\n super.willUpdate(_changed);\n this.#core.setProps({\n label: this.label,\n changeThrottle: this.changeThrottle,\n step: this.step,\n largeStep: this.largeStep,\n orientation: this.orientation,\n disabled: this.disabled,\n thumbAlignment: this.thumbAlignment,\n pauseOnDrag: this.pauseOnDrag,\n });\n this.#core.setFormatLocale(this.#i18n.locale);\n }\n\n protected override update(_changed: PropertyValues): void {\n super.update(_changed);\n\n if (!this.#slider) return;\n\n const time = this.#timeState.value;\n const buffer = this.#bufferState.value;\n\n if (!time) {\n this.#seek.destroy();\n this.removeAttribute('data-playing');\n return;\n }\n\n this.#core.setInput(this.#slider.input.current);\n const media = { ...time, ...(buffer ?? { buffered: [], seekable: [] }) };\n\n this.#core.setMedia(media);\n const state = this.#core.getState();\n\n this.#seek.update(state.seeking, state.fillPercent, this);\n const percent = this.#seek.state.current.percent;\n\n this.toggleAttribute(\n 'data-playing',\n isMediaPlaying(this.#playbackState.value) &&\n !state.disabled &&\n !state.dragging &&\n !state.seeking &&\n percent === undefined\n );\n\n const fill = percent === undefined || state.dragging || state.disabled ? state : { ...state, fillPercent: percent };\n const cssVars = getTimeSliderCSSVars(this.#slider.adjustForAlignment(fill));\n const styles = Object.fromEntries(Object.entries(cssVars).filter(([name, value]) => this.#cssVars[name] !== value));\n\n applyStyles(this, styles);\n this.#cssVars = cssVars;\n\n const thumbAttrs = this.#core.getAttrs(state);\n\n // Domain-specific data attributes on root (includes data-seeking).\n applyStateDataAttrs(this, state, TimeSliderDataAttrs);\n\n // Provide context to child elements with base slider data attrs.\n this.#provider.setValue({\n state,\n stateAttrMap: TimeSliderDataAttrs,\n pointerValue: this.#core.rawValueFromPercent(state.pointerPercent),\n thumbAttrs: {\n ...thumbAttrs,\n 'aria-label': translateText(thumbAttrs['aria-label'], this.#i18n.value),\n 'aria-valuetext': translateText(\n thumbAttrs['aria-valuetext'],\n this.#i18n.value,\n this.#core.getValueTextParams(state)\n ),\n },\n thumbProps: this.#slider.thumbProps,\n formatValue: (value) => formatTime(value, state.duration, { locale: this.#i18n.locale }),\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -97,7 +97,9 @@ var VolumeSliderElement = class extends UIElement {
|
|
|
97
97
|
this.dispatchEvent(new CustomEvent("drag-end", { bubbles: true }));
|
|
98
98
|
},
|
|
99
99
|
adjustPercent: (raw, thumbSize, trackSize) => this.#core.adjustPercentForAlignment(raw, thumbSize, trackSize),
|
|
100
|
-
onResize: () =>
|
|
100
|
+
onResize: () => {
|
|
101
|
+
if (this.thumbAlignment === "edge") this.requestUpdate();
|
|
102
|
+
}
|
|
101
103
|
});
|
|
102
104
|
const wheelProps = createWheelStep({
|
|
103
105
|
isDisabled,
|