@locpd/vidstack 1.12.14

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.
Files changed (242) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +22 -0
  3. package/analyze.json.d.ts +8 -0
  4. package/bundle.d.ts +1 -0
  5. package/cdn/chunks/vidstack-2f5gzOW6.js +1 -0
  6. package/cdn/chunks/vidstack-BYgY9wmd.js +1 -0
  7. package/cdn/chunks/vidstack-BfBBPhXV.js +1 -0
  8. package/cdn/chunks/vidstack-Bjo5esRp.js +1 -0
  9. package/cdn/chunks/vidstack-BuL67v3q.js +1 -0
  10. package/cdn/chunks/vidstack-C0msPRTd.js +3 -0
  11. package/cdn/chunks/vidstack-CJNLoJPa.js +1 -0
  12. package/cdn/chunks/vidstack-CQSpZ7X8.js +16 -0
  13. package/cdn/chunks/vidstack-C_AxqLKV.js +1 -0
  14. package/cdn/chunks/vidstack-CioT3Yw2.js +1 -0
  15. package/cdn/chunks/vidstack-CrqkytHl.js +1 -0
  16. package/cdn/chunks/vidstack-D0M8R0ZU.js +1 -0
  17. package/cdn/chunks/vidstack-D40FSa5B.js +3 -0
  18. package/cdn/chunks/vidstack-DD2JwFVU.js +1 -0
  19. package/cdn/chunks/vidstack-DRH_1tFW.js +1 -0
  20. package/cdn/chunks/vidstack-DfDZuHNP.js +1 -0
  21. package/cdn/chunks/vidstack-DiNS2Vx5.js +1 -0
  22. package/cdn/chunks/vidstack-xjJ-ui_l.js +1 -0
  23. package/cdn/providers/vidstack-audio-2Dt_Ivbp.js +1 -0
  24. package/cdn/providers/vidstack-dash-CUtD4e6q.js +1 -0
  25. package/cdn/providers/vidstack-google-cast-BdORATUX.js +1 -0
  26. package/cdn/providers/vidstack-hls-R25Kb6DP.js +1 -0
  27. package/cdn/providers/vidstack-html-DaAUJYsD.js +1 -0
  28. package/cdn/providers/vidstack-video-Csvox7SO.js +1 -0
  29. package/cdn/providers/vidstack-vimeo-D4Z96kg2.js +1 -0
  30. package/cdn/providers/vidstack-youtube-DiND6h3s.js +1 -0
  31. package/cdn/vidstack.js +1 -0
  32. package/cdn/with-layouts/chunks/vidstack-2f5gzOW6.js +1 -0
  33. package/cdn/with-layouts/chunks/vidstack-45yH5los.js +1 -0
  34. package/cdn/with-layouts/chunks/vidstack-BBVMdOnf.js +1 -0
  35. package/cdn/with-layouts/chunks/vidstack-BB_ulI_T.js +1 -0
  36. package/cdn/with-layouts/chunks/vidstack-BcAewM33.js +1 -0
  37. package/cdn/with-layouts/chunks/vidstack-BfBBPhXV.js +1 -0
  38. package/cdn/with-layouts/chunks/vidstack-Bxv1Qnxe.js +1 -0
  39. package/cdn/with-layouts/chunks/vidstack-C2ZbG62f.js +3 -0
  40. package/cdn/with-layouts/chunks/vidstack-CCYIOKgL.js +1 -0
  41. package/cdn/with-layouts/chunks/vidstack-CL6PeIO1.js +1 -0
  42. package/cdn/with-layouts/chunks/vidstack-C_AxqLKV.js +1 -0
  43. package/cdn/with-layouts/chunks/vidstack-CifDkwDH.js +795 -0
  44. package/cdn/with-layouts/chunks/vidstack-Cry7aD59.js +3 -0
  45. package/cdn/with-layouts/chunks/vidstack-D065okCn.js +1 -0
  46. package/cdn/with-layouts/chunks/vidstack-DGuMoXmI.js +1 -0
  47. package/cdn/with-layouts/chunks/vidstack-DRH_1tFW.js +1 -0
  48. package/cdn/with-layouts/chunks/vidstack-DVBs1XoQ.js +1 -0
  49. package/cdn/with-layouts/chunks/vidstack-Dge3KT8k.js +1 -0
  50. package/cdn/with-layouts/chunks/vidstack-DiNS2Vx5.js +1 -0
  51. package/cdn/with-layouts/chunks/vidstack-HvYfJoen.js +1 -0
  52. package/cdn/with-layouts/providers/vidstack-audio-DE5vKIzW.js +1 -0
  53. package/cdn/with-layouts/providers/vidstack-dash-CA2agUuZ.js +1 -0
  54. package/cdn/with-layouts/providers/vidstack-google-cast-CGs-t8HM.js +1 -0
  55. package/cdn/with-layouts/providers/vidstack-hls-BHMbMFFR.js +1 -0
  56. package/cdn/with-layouts/providers/vidstack-html-Dm9gmNk6.js +1 -0
  57. package/cdn/with-layouts/providers/vidstack-video-C5it_Lbl.js +1 -0
  58. package/cdn/with-layouts/providers/vidstack-vimeo-BabLn9sy.js +1 -0
  59. package/cdn/with-layouts/providers/vidstack-youtube-D8UlccUL.js +1 -0
  60. package/cdn/with-layouts/vidstack.js +1 -0
  61. package/dev/chunks/vidstack-B7Zi3v_O.js +104 -0
  62. package/dev/chunks/vidstack-BFg1ZqiG.js +91 -0
  63. package/dev/chunks/vidstack-BGB2pa9s.js +58 -0
  64. package/dev/chunks/vidstack-BaIbHZE3.js +1519 -0
  65. package/dev/chunks/vidstack-Bb2rASIc.js +5188 -0
  66. package/dev/chunks/vidstack-Bcmx8pmK.js +224 -0
  67. package/dev/chunks/vidstack-Bl4b0Nen.js +29 -0
  68. package/dev/chunks/vidstack-Bo5OTJ06.js +58 -0
  69. package/dev/chunks/vidstack-BoAGnlRt.js +58 -0
  70. package/dev/chunks/vidstack-Bpr4fI4n.js +7 -0
  71. package/dev/chunks/vidstack-Bt8MP2DK.js +204 -0
  72. package/dev/chunks/vidstack-Bu2kfzUd.js +1637 -0
  73. package/dev/chunks/vidstack-C-ffXlSV.js +2995 -0
  74. package/dev/chunks/vidstack-C-ztJq-f.js +109 -0
  75. package/dev/chunks/vidstack-CFNlaVTR.js +55 -0
  76. package/dev/chunks/vidstack-C_l97D5j.js +254 -0
  77. package/dev/chunks/vidstack-CjhKISI0.js +114 -0
  78. package/dev/chunks/vidstack-CofXIJAy.js +57 -0
  79. package/dev/chunks/vidstack-CwTj4H1w.js +18 -0
  80. package/dev/chunks/vidstack-DDwbYVHV.js +66 -0
  81. package/dev/chunks/vidstack-DFImIcIL.js +11 -0
  82. package/dev/chunks/vidstack-DGDvUbvO.js +33 -0
  83. package/dev/chunks/vidstack-DO0kqA99.js +107 -0
  84. package/dev/chunks/vidstack-DXxIKXmd.js +50 -0
  85. package/dev/chunks/vidstack-DajrMUR0.js +297 -0
  86. package/dev/chunks/vidstack-DbBJlz7I.js +10 -0
  87. package/dev/chunks/vidstack-Dihypf8P.js +11 -0
  88. package/dev/chunks/vidstack-DlAhl87f.js +1193 -0
  89. package/dev/chunks/vidstack-Dm1xEU9Q.js +34 -0
  90. package/dev/chunks/vidstack-Dv_LIPFu.js +14 -0
  91. package/dev/chunks/vidstack-igYn0Apa.js +254 -0
  92. package/dev/chunks/vidstack-krOAtKMi.js +32 -0
  93. package/dev/chunks/vidstack-qh1N5_f_.js +26 -0
  94. package/dev/chunks/vidstack-rB-wqXw1.js +107 -0
  95. package/dev/chunks/vidstack-zG6PIeGg.js +66 -0
  96. package/dev/define/plyr-layout.js +51 -0
  97. package/dev/define/templates/plyr-layout.js +571 -0
  98. package/dev/define/templates/vidstack-audio-layout.js +167 -0
  99. package/dev/define/templates/vidstack-video-layout.js +390 -0
  100. package/dev/define/vidstack-icons.js +1 -0
  101. package/dev/define/vidstack-player-default-layout.js +21 -0
  102. package/dev/define/vidstack-player-layouts.js +25 -0
  103. package/dev/define/vidstack-player-ui.js +70 -0
  104. package/dev/define/vidstack-player.js +19 -0
  105. package/dev/global/plyr.js +501 -0
  106. package/dev/global/vidstack-player.js +129 -0
  107. package/dev/providers/vidstack-audio.js +35 -0
  108. package/dev/providers/vidstack-dash.js +516 -0
  109. package/dev/providers/vidstack-google-cast.js +474 -0
  110. package/dev/providers/vidstack-hls.js +408 -0
  111. package/dev/providers/vidstack-html.js +567 -0
  112. package/dev/providers/vidstack-video.js +207 -0
  113. package/dev/providers/vidstack-vimeo.js +554 -0
  114. package/dev/providers/vidstack-youtube.js +286 -0
  115. package/dev/vidstack-elements.js +36 -0
  116. package/dev/vidstack.js +91 -0
  117. package/dom.d.ts +91 -0
  118. package/elements.d.ts +1433 -0
  119. package/empty.vtt +1 -0
  120. package/global/player.d.ts +52 -0
  121. package/global/plyr.d.ts +343 -0
  122. package/google-cast.d.ts +1422 -0
  123. package/icons.d.ts +1 -0
  124. package/index.d.ts +402 -0
  125. package/package.json +199 -0
  126. package/player/index.d.ts +3 -0
  127. package/player/layouts/default.d.ts +3 -0
  128. package/player/layouts/index.d.ts +3 -0
  129. package/player/layouts/plyr.d.ts +3 -0
  130. package/player/styles/base.css +153 -0
  131. package/player/styles/default/buffering.css +55 -0
  132. package/player/styles/default/buttons.css +175 -0
  133. package/player/styles/default/captions.css +181 -0
  134. package/player/styles/default/chapter-title.css +26 -0
  135. package/player/styles/default/controls.css +56 -0
  136. package/player/styles/default/gestures.css +19 -0
  137. package/player/styles/default/icons.css +6 -0
  138. package/player/styles/default/keyboard.css +148 -0
  139. package/player/styles/default/layouts/audio.css +417 -0
  140. package/player/styles/default/layouts/video.css +590 -0
  141. package/player/styles/default/menus.css +959 -0
  142. package/player/styles/default/poster.css +52 -0
  143. package/player/styles/default/sliders.css +391 -0
  144. package/player/styles/default/theme.css +2461 -0
  145. package/player/styles/default/thumbnail.css +40 -0
  146. package/player/styles/default/time.css +45 -0
  147. package/player/styles/default/tooltips.css +141 -0
  148. package/player/styles/plyr/theme.css +1237 -0
  149. package/player/ui.d.ts +3 -0
  150. package/plugins.d.ts +19 -0
  151. package/plugins.js +13 -0
  152. package/prod/chunks/vidstack-B01xzxC4.js +7 -0
  153. package/prod/chunks/vidstack-BCeb7ryV.js +201 -0
  154. package/prod/chunks/vidstack-BGSTndAW.js +1590 -0
  155. package/prod/chunks/vidstack-BPitBBjh.js +1519 -0
  156. package/prod/chunks/vidstack-BQlOPwOu.js +45 -0
  157. package/prod/chunks/vidstack-BSDzlwxO.js +4778 -0
  158. package/prod/chunks/vidstack-BT0m6zEi.js +109 -0
  159. package/prod/chunks/vidstack-BTigPj2h.js +55 -0
  160. package/prod/chunks/vidstack-BiyXcJ_M.js +107 -0
  161. package/prod/chunks/vidstack-BoVf5n1M.js +2985 -0
  162. package/prod/chunks/vidstack-Bq6c3Bam.js +58 -0
  163. package/prod/chunks/vidstack-ByLCIBtB.js +297 -0
  164. package/prod/chunks/vidstack-C2US-gSO.js +248 -0
  165. package/prod/chunks/vidstack-C9vIqaYT.js +10 -0
  166. package/prod/chunks/vidstack-CF6fixCQ.js +1193 -0
  167. package/prod/chunks/vidstack-CTojmhKq.js +66 -0
  168. package/prod/chunks/vidstack-ChQTHmIQ.js +77 -0
  169. package/prod/chunks/vidstack-Cm6_unwd.js +246 -0
  170. package/prod/chunks/vidstack-CwTj4H1w.js +18 -0
  171. package/prod/chunks/vidstack-D3ltXc3a.js +33 -0
  172. package/prod/chunks/vidstack-D5EzK014.js +14 -0
  173. package/prod/chunks/vidstack-DDXt6fpN.js +58 -0
  174. package/prod/chunks/vidstack-DJDnh4xT.js +11 -0
  175. package/prod/chunks/vidstack-DXxIKXmd.js +50 -0
  176. package/prod/chunks/vidstack-D_-9AA6_.js +29 -0
  177. package/prod/chunks/vidstack-DbkZGjSn.js +107 -0
  178. package/prod/chunks/vidstack-Dihypf8P.js +11 -0
  179. package/prod/chunks/vidstack-Dm1xEU9Q.js +34 -0
  180. package/prod/chunks/vidstack-Dq5Yu0Vr.js +205 -0
  181. package/prod/chunks/vidstack-DqAw8m9J.js +26 -0
  182. package/prod/chunks/vidstack-DsPOyKtl.js +57 -0
  183. package/prod/chunks/vidstack-krOAtKMi.js +32 -0
  184. package/prod/chunks/vidstack-nLyr4NEP.js +58 -0
  185. package/prod/chunks/vidstack-xMS8dnYq.js +114 -0
  186. package/prod/chunks/vidstack-yEGTpgeA.js +104 -0
  187. package/prod/define/plyr-layout.js +51 -0
  188. package/prod/define/templates/plyr-layout.js +571 -0
  189. package/prod/define/templates/vidstack-audio-layout.js +167 -0
  190. package/prod/define/templates/vidstack-video-layout.js +390 -0
  191. package/prod/define/vidstack-icons.js +1 -0
  192. package/prod/define/vidstack-player-default-layout.js +21 -0
  193. package/prod/define/vidstack-player-layouts.js +25 -0
  194. package/prod/define/vidstack-player-ui.js +70 -0
  195. package/prod/define/vidstack-player.js +19 -0
  196. package/prod/global/plyr.js +493 -0
  197. package/prod/global/vidstack-player.js +129 -0
  198. package/prod/providers/vidstack-audio.js +35 -0
  199. package/prod/providers/vidstack-dash.js +501 -0
  200. package/prod/providers/vidstack-google-cast.js +468 -0
  201. package/prod/providers/vidstack-hls.js +393 -0
  202. package/prod/providers/vidstack-html.js +555 -0
  203. package/prod/providers/vidstack-video.js +204 -0
  204. package/prod/providers/vidstack-vimeo.js +548 -0
  205. package/prod/providers/vidstack-youtube.js +286 -0
  206. package/prod/vidstack-elements.js +36 -0
  207. package/prod/vidstack.js +158 -0
  208. package/server/chunks/vidstack-6juFdkKy.js +29 -0
  209. package/server/chunks/vidstack-B7iHmv7_.js +307 -0
  210. package/server/chunks/vidstack-BmxyML9v.js +1619 -0
  211. package/server/chunks/vidstack-BskfxwD3.js +566 -0
  212. package/server/chunks/vidstack-BvLV0SMz.js +4642 -0
  213. package/server/chunks/vidstack-BvWwluXZ.js +205 -0
  214. package/server/chunks/vidstack-C-413dj2.js +8 -0
  215. package/server/chunks/vidstack-C26K8z_-.js +55 -0
  216. package/server/chunks/vidstack-CJJiksDz.js +107 -0
  217. package/server/chunks/vidstack-CUNv52x1.js +141 -0
  218. package/server/chunks/vidstack-CqyBCODe.js +295 -0
  219. package/server/chunks/vidstack-CwTj4H1w.js +18 -0
  220. package/server/chunks/vidstack-DHAyGSOl.js +1502 -0
  221. package/server/chunks/vidstack-DLU3cjcp.js +381 -0
  222. package/server/chunks/vidstack-DXxIKXmd.js +50 -0
  223. package/server/chunks/vidstack-DbtDXDS2.js +104 -0
  224. package/server/chunks/vidstack-Dm1xEU9Q.js +34 -0
  225. package/server/chunks/vidstack-DzTHw_bw.js +207 -0
  226. package/server/chunks/vidstack-Wn3NH5Sg.js +1566 -0
  227. package/server/chunks/vidstack-krOAtKMi.js +32 -0
  228. package/server/chunks/vidstack-wNViAkr4.js +3045 -0
  229. package/server/define/plyr-layout.js +16 -0
  230. package/server/define/vidstack-icons.js +1 -0
  231. package/server/define/vidstack-player-default-layout.js +13 -0
  232. package/server/define/vidstack-player-layouts.js +16 -0
  233. package/server/define/vidstack-player-ui.js +11 -0
  234. package/server/define/vidstack-player.js +6 -0
  235. package/server/global/plyr.js +322 -0
  236. package/server/global/vidstack-player.js +58 -0
  237. package/server/vidstack-elements.js +46 -0
  238. package/server/vidstack.js +148 -0
  239. package/tailwind.cjs +101 -0
  240. package/tailwind.d.cts +15 -0
  241. package/types/vidstack-BOvzfZjK.d.ts +1269 -0
  242. package/types/vidstack-Cttpg6GU.d.ts +7474 -0
@@ -0,0 +1,1619 @@
1
+ import { createContext, useContext, prop, Component, computed, provideContext, signal, isBoolean, effect, setAttribute, uppercaseFirstChar, isNil, isString, noop, isFunction, unwrap, peek, isKeyboardClick, isArray, camelToKebabCase, tick, toggleClass, Host, listenEvent } from './vidstack-Wn3NH5Sg.js';
2
+ import { useMediaContext, watchColorScheme, useMediaState, getDownloadFile, appendParamsToURL, watchActiveTextTrack, useResizeObserver, useActive, useTransitionActive, isHTMLElement, createSlot } from './vidstack-DLU3cjcp.js';
3
+ import { $signal, LayoutIconsLoader, Icon, SlotManager } from './vidstack-BvWwluXZ.js';
4
+ import { LitElement } from './vidstack-CwTj4H1w.js';
5
+ import { html } from 'lit-html';
6
+ import { ref } from 'lit-html/directives/ref.js';
7
+ import { keyed } from 'lit-html/directives/keyed.js';
8
+ import { $ariaBool } from './vidstack-C-413dj2.js';
9
+ import { ifDefined } from 'lit-html/directives/if-defined.js';
10
+
11
+ const defaultLayoutContext = createContext();
12
+ function useDefaultLayoutContext() {
13
+ return useContext(defaultLayoutContext);
14
+ }
15
+
16
+ const defaultLayoutProps = {
17
+ colorScheme: "system",
18
+ download: null,
19
+ customIcons: false,
20
+ disableTimeSlider: false,
21
+ menuContainer: null,
22
+ menuGroup: "bottom",
23
+ noAudioGain: false,
24
+ noGestures: false,
25
+ noKeyboardAnimations: false,
26
+ noModal: false,
27
+ noScrubGesture: false,
28
+ playbackRates: { min: 0, max: 2, step: 0.25 },
29
+ audioGains: { min: 0, max: 300, step: 25 },
30
+ seekStep: 10,
31
+ sliderChaptersMinWidth: 325,
32
+ hideQualityBitrate: false,
33
+ smallWhen: false,
34
+ thumbnails: null,
35
+ translations: null,
36
+ when: false
37
+ };
38
+
39
+ class DefaultLayout extends Component {
40
+ static props = defaultLayoutProps;
41
+ #media;
42
+ #when = computed(() => {
43
+ const when = this.$props.when();
44
+ return this.#matches(when);
45
+ });
46
+ #smallWhen = computed(() => {
47
+ const when = this.$props.smallWhen();
48
+ return this.#matches(when);
49
+ });
50
+ get isMatch() {
51
+ return this.#when();
52
+ }
53
+ get isSmallLayout() {
54
+ return this.#smallWhen();
55
+ }
56
+ onSetup() {
57
+ this.#media = useMediaContext();
58
+ this.setAttributes({
59
+ "data-match": this.#when,
60
+ "data-sm": () => this.#smallWhen() ? "" : null,
61
+ "data-lg": () => !this.#smallWhen() ? "" : null,
62
+ "data-size": () => this.#smallWhen() ? "sm" : "lg",
63
+ "data-no-scrub-gesture": this.$props.noScrubGesture
64
+ });
65
+ provideContext(defaultLayoutContext, {
66
+ ...this.$props,
67
+ when: this.#when,
68
+ smallWhen: this.#smallWhen,
69
+ userPrefersAnnouncements: signal(true),
70
+ userPrefersKeyboardAnimations: signal(true),
71
+ menuPortal: signal(null)
72
+ });
73
+ }
74
+ onAttach(el) {
75
+ watchColorScheme(el, this.$props.colorScheme);
76
+ }
77
+ #matches(query) {
78
+ return query !== "never" && (isBoolean(query) ? query : computed(() => query(this.#media.player.state))());
79
+ }
80
+ }
81
+ const defaultlayout__proto = DefaultLayout.prototype;
82
+ prop(defaultlayout__proto, "isMatch");
83
+ prop(defaultlayout__proto, "isSmallLayout");
84
+
85
+ let DefaultAudioLayout$1 = class DefaultAudioLayout extends DefaultLayout {
86
+ static props = {
87
+ ...super.props,
88
+ when: ({ viewType }) => viewType === "audio",
89
+ smallWhen: ({ width }) => width < 576
90
+ };
91
+ };
92
+
93
+ function setLayoutName(name, isMatch) {
94
+ effect(() => {
95
+ const { player } = useMediaContext(), el = player.el;
96
+ el && setAttribute(el, "data-layout", isMatch() && name);
97
+ return () => el?.removeAttribute("data-layout");
98
+ });
99
+ }
100
+
101
+ function i18n(translations, word) {
102
+ return translations()?.[word] ?? word;
103
+ }
104
+
105
+ function DefaultAnnouncer() {
106
+ return $signal(() => {
107
+ const { translations, userPrefersAnnouncements } = useDefaultLayoutContext();
108
+ if (!userPrefersAnnouncements()) return null;
109
+ return html`<media-announcer .translations=${$signal(translations)}></media-announcer>`;
110
+ });
111
+ }
112
+
113
+ function IconSlot(name, classes = "") {
114
+ return html`<slot
115
+ name=${`${name}-icon`}
116
+ data-class=${`vds-icon vds-${name}-icon${classes ? ` ${classes}` : ""}`}
117
+ ></slot>`;
118
+ }
119
+ function IconSlots(names) {
120
+ return names.map((name) => IconSlot(name));
121
+ }
122
+
123
+ function $i18n(translations, word) {
124
+ return $signal(() => i18n(translations, word));
125
+ }
126
+
127
+ function DefaultAirPlayButton({ tooltip }) {
128
+ const { translations } = useDefaultLayoutContext(), { remotePlaybackState } = useMediaState(), $label = $signal(() => {
129
+ const airPlayText = i18n(translations, "AirPlay"), stateText = uppercaseFirstChar(remotePlaybackState());
130
+ return `${airPlayText} ${stateText}`;
131
+ }), $airPlayText = $i18n(translations, "AirPlay");
132
+ return html`
133
+ <media-tooltip class="vds-airplay-tooltip vds-tooltip">
134
+ <media-tooltip-trigger>
135
+ <media-airplay-button class="vds-airplay-button vds-button" aria-label=${$label}>
136
+ ${IconSlot("airplay")}
137
+ </media-airplay-button>
138
+ </media-tooltip-trigger>
139
+ <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
140
+ <span class="vds-airplay-tooltip-text">${$airPlayText}</span>
141
+ </media-tooltip-content>
142
+ </media-tooltip>
143
+ `;
144
+ }
145
+ function DefaultPlayButton({ tooltip }) {
146
+ const { translations } = useDefaultLayoutContext(), $playText = $i18n(translations, "Play"), $pauseText = $i18n(translations, "Pause");
147
+ return html`
148
+ <media-tooltip class="vds-play-tooltip vds-tooltip">
149
+ <media-tooltip-trigger>
150
+ <media-play-button
151
+ class="vds-play-button vds-button"
152
+ aria-label=${$i18n(translations, "Play")}
153
+ >
154
+ ${IconSlots(["play", "pause", "replay"])}
155
+ </media-play-button>
156
+ </media-tooltip-trigger>
157
+ <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
158
+ <span class="vds-play-tooltip-text">${$playText}</span>
159
+ <span class="vds-pause-tooltip-text">${$pauseText}</span>
160
+ </media-tooltip-content>
161
+ </media-tooltip>
162
+ `;
163
+ }
164
+ function DefaultMuteButton({
165
+ tooltip,
166
+ ref: ref$1 = noop
167
+ }) {
168
+ const { translations } = useDefaultLayoutContext(), $muteText = $i18n(translations, "Mute"), $unmuteText = $i18n(translations, "Unmute");
169
+ return html`
170
+ <media-tooltip class="vds-mute-tooltip vds-tooltip">
171
+ <media-tooltip-trigger>
172
+ <media-mute-button
173
+ class="vds-mute-button vds-button"
174
+ aria-label=${$i18n(translations, "Mute")}
175
+ ${ref(ref$1)}
176
+ >
177
+ ${IconSlots(["mute", "volume-low", "volume-high"])}
178
+ </media-mute-button>
179
+ </media-tooltip-trigger>
180
+ <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
181
+ <span class="vds-mute-tooltip-text">${$unmuteText}</span>
182
+ <span class="vds-unmute-tooltip-text">${$muteText}</span>
183
+ </media-tooltip-content>
184
+ </media-tooltip>
185
+ `;
186
+ }
187
+ function DefaultCaptionButton({ tooltip }) {
188
+ const { translations } = useDefaultLayoutContext(), $ccOnText = $i18n(translations, "Closed-Captions On"), $ccOffText = $i18n(translations, "Closed-Captions Off");
189
+ return html`
190
+ <media-tooltip class="vds-caption-tooltip vds-tooltip">
191
+ <media-tooltip-trigger>
192
+ <media-caption-button
193
+ class="vds-caption-button vds-button"
194
+ aria-label=${$i18n(translations, "Captions")}
195
+ >
196
+ ${IconSlots(["cc-on", "cc-off"])}
197
+ </media-caption-button>
198
+ </media-tooltip-trigger>
199
+ <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
200
+ <span class="vds-cc-on-tooltip-text">${$ccOffText}</span>
201
+ <span class="vds-cc-off-tooltip-text">${$ccOnText}</span>
202
+ </media-tooltip-content>
203
+ </media-tooltip>
204
+ `;
205
+ }
206
+ function DefaultPIPButton() {
207
+ const { translations } = useDefaultLayoutContext(), $enterText = $i18n(translations, "Enter PiP"), $exitText = $i18n(translations, "Exit PiP");
208
+ return html`
209
+ <media-tooltip class="vds-pip-tooltip vds-tooltip">
210
+ <media-tooltip-trigger>
211
+ <media-pip-button
212
+ class="vds-pip-button vds-button"
213
+ aria-label=${$i18n(translations, "PiP")}
214
+ >
215
+ ${IconSlots(["pip-enter", "pip-exit"])}
216
+ </media-pip-button>
217
+ </media-tooltip-trigger>
218
+ <media-tooltip-content class="vds-tooltip-content">
219
+ <span class="vds-pip-enter-tooltip-text">${$enterText}</span>
220
+ <span class="vds-pip-exit-tooltip-text">${$exitText}</span>
221
+ </media-tooltip-content>
222
+ </media-tooltip>
223
+ `;
224
+ }
225
+ function DefaultFullscreenButton({ tooltip }) {
226
+ const { translations } = useDefaultLayoutContext(), $enterText = $i18n(translations, "Enter Fullscreen"), $exitText = $i18n(translations, "Exit Fullscreen");
227
+ return html`
228
+ <media-tooltip class="vds-fullscreen-tooltip vds-tooltip">
229
+ <media-tooltip-trigger>
230
+ <media-fullscreen-button
231
+ class="vds-fullscreen-button vds-button"
232
+ aria-label=${$i18n(translations, "Fullscreen")}
233
+ >
234
+ ${IconSlots(["fs-enter", "fs-exit"])}
235
+ </media-fullscreen-button>
236
+ </media-tooltip-trigger>
237
+ <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
238
+ <span class="vds-fs-enter-tooltip-text">${$enterText}</span>
239
+ <span class="vds-fs-exit-tooltip-text">${$exitText}</span>
240
+ </media-tooltip-content>
241
+ </media-tooltip>
242
+ `;
243
+ }
244
+ function DefaultSeekButton({
245
+ backward,
246
+ tooltip
247
+ }) {
248
+ const { translations, seekStep } = useDefaultLayoutContext(), seekText = !backward ? "Seek Forward" : "Seek Backward", $label = $i18n(translations, seekText), $seconds = () => (backward ? -1 : 1) * seekStep();
249
+ return html`
250
+ <media-tooltip class="vds-seek-tooltip vds-tooltip">
251
+ <media-tooltip-trigger>
252
+ <media-seek-button
253
+ class="vds-seek-button vds-button"
254
+ seconds=${$signal($seconds)}
255
+ aria-label=${$label}
256
+ >
257
+ ${!backward ? IconSlot("seek-forward") : IconSlot("seek-backward")}
258
+ </media-seek-button>
259
+ </media-tooltip-trigger>
260
+ <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
261
+ ${$i18n(translations, seekText)}
262
+ </media-tooltip-content>
263
+ </media-tooltip>
264
+ `;
265
+ }
266
+ function DefaultLiveButton() {
267
+ const { translations } = useDefaultLayoutContext(), { live } = useMediaState(), $label = $i18n(translations, "Skip To Live"), $liveText = $i18n(translations, "LIVE");
268
+ return live() ? html`
269
+ <media-live-button class="vds-live-button" aria-label=${$label}>
270
+ <span class="vds-live-button-text">${$liveText}</span>
271
+ </media-live-button>
272
+ ` : null;
273
+ }
274
+ function DefaultDownloadButton() {
275
+ return $signal(() => {
276
+ const { download, translations } = useDefaultLayoutContext(), $download = download();
277
+ if (isNil($download)) return null;
278
+ const { source, title } = useMediaState(), $src = source(), file = getDownloadFile({
279
+ title: title(),
280
+ src: $src,
281
+ download: $download
282
+ });
283
+ return isString(file?.url) ? html`
284
+ <media-tooltip class="vds-download-tooltip vds-tooltip">
285
+ <media-tooltip-trigger>
286
+ <a
287
+ role="button"
288
+ class="vds-download-button vds-button"
289
+ aria-label=${$i18n(translations, "Download")}
290
+ href=${appendParamsToURL(file.url, { download: file.name })}
291
+ download=${file.name}
292
+ target="_blank"
293
+ >
294
+ <slot name="download-icon" data-class="vds-icon" />
295
+ </a>
296
+ </media-tooltip-trigger>
297
+ <media-tooltip-content class="vds-tooltip-content" placement="top">
298
+ ${$i18n(translations, "Download")}
299
+ </media-tooltip-content>
300
+ </media-tooltip>
301
+ ` : null;
302
+ });
303
+ }
304
+
305
+ function DefaultCaptions() {
306
+ const { translations } = useDefaultLayoutContext();
307
+ return html`
308
+ <media-captions
309
+ class="vds-captions"
310
+ .exampleText=${$i18n(translations, "Captions look like this")}
311
+ ></media-captions>
312
+ `;
313
+ }
314
+
315
+ function DefaultControlsSpacer() {
316
+ return html`<div class="vds-controls-spacer"></div>`;
317
+ }
318
+
319
+ function MenuPortal(container, template) {
320
+ return html`
321
+ <media-menu-portal .container=${$signal(container)} disabled="fullscreen">
322
+ ${template}
323
+ </media-menu-portal>
324
+ `;
325
+ }
326
+ function createMenuContainer(layoutEl, rootSelector, className, isSmallLayout) {
327
+ let root = isString(rootSelector) ? document.querySelector(rootSelector) : rootSelector;
328
+ if (!root) root = layoutEl?.closest("dialog");
329
+ if (!root) root = document.body;
330
+ const container = document.createElement("div");
331
+ container.style.display = "contents";
332
+ container.classList.add(className);
333
+ root.append(container);
334
+ effect(() => {
335
+ if (!container) return;
336
+ const { viewType } = useMediaState(), isSmall = isSmallLayout();
337
+ setAttribute(container, "data-view-type", viewType());
338
+ setAttribute(container, "data-sm", isSmall);
339
+ setAttribute(container, "data-lg", !isSmall);
340
+ setAttribute(container, "data-size", isSmall ? "sm" : "lg");
341
+ });
342
+ const { colorScheme } = useDefaultLayoutContext();
343
+ watchColorScheme(container, colorScheme);
344
+ return container;
345
+ }
346
+
347
+ function DefaultChaptersMenu({
348
+ placement,
349
+ tooltip,
350
+ portal
351
+ }) {
352
+ const { textTracks } = useMediaContext(), { viewType, seekableStart, seekableEnd } = useMediaState(), {
353
+ translations,
354
+ thumbnails,
355
+ menuPortal,
356
+ noModal,
357
+ menuGroup,
358
+ smallWhen: smWhen
359
+ } = useDefaultLayoutContext(), $disabled = computed(() => {
360
+ const $startTime = seekableStart(), $endTime = seekableEnd(), $track = signal(null);
361
+ watchActiveTextTrack(textTracks, "chapters", $track.set);
362
+ const cues = $track()?.cues.filter(
363
+ (cue) => cue.startTime <= $endTime && cue.endTime >= $startTime
364
+ );
365
+ return !cues?.length;
366
+ });
367
+ if ($disabled()) return null;
368
+ const $placement = computed(
369
+ () => noModal() ? unwrap(placement) : !smWhen() ? unwrap(placement) : null
370
+ ), $offset = computed(
371
+ () => !smWhen() && menuGroup() === "bottom" && viewType() === "video" ? 26 : 0
372
+ ), $isOpen = signal(false);
373
+ function onOpen() {
374
+ $isOpen.set(true);
375
+ }
376
+ function onClose() {
377
+ $isOpen.set(false);
378
+ }
379
+ const items = html`
380
+ <media-menu-items
381
+ class="vds-chapters-menu-items vds-menu-items"
382
+ placement=${$signal($placement)}
383
+ offset=${$signal($offset)}
384
+ >
385
+ ${$signal(() => {
386
+ if (!$isOpen()) return null;
387
+ return html`
388
+ <media-chapters-radio-group
389
+ class="vds-chapters-radio-group vds-radio-group"
390
+ .thumbnails=${$signal(thumbnails)}
391
+ >
392
+ <template>
393
+ <media-radio class="vds-chapter-radio vds-radio">
394
+ <media-thumbnail class="vds-thumbnail"></media-thumbnail>
395
+ <div class="vds-chapter-radio-content">
396
+ <span class="vds-chapter-radio-label" data-part="label"></span>
397
+ <span class="vds-chapter-radio-start-time" data-part="start-time"></span>
398
+ <span class="vds-chapter-radio-duration" data-part="duration"></span>
399
+ </div>
400
+ </media-radio>
401
+ </template>
402
+ </media-chapters-radio-group>
403
+ `;
404
+ })}
405
+ </media-menu-items>
406
+ `;
407
+ return html`
408
+ <media-menu class="vds-chapters-menu vds-menu" @open=${onOpen} @close=${onClose}>
409
+ <media-tooltip class="vds-tooltip">
410
+ <media-tooltip-trigger>
411
+ <media-menu-button
412
+ class="vds-menu-button vds-button"
413
+ aria-label=${$i18n(translations, "Chapters")}
414
+ >
415
+ ${IconSlot("menu-chapters")}
416
+ </media-menu-button>
417
+ </media-tooltip-trigger>
418
+ <media-tooltip-content
419
+ class="vds-tooltip-content"
420
+ placement=${isFunction(tooltip) ? $signal(tooltip) : tooltip}
421
+ >
422
+ ${$i18n(translations, "Chapters")}
423
+ </media-tooltip-content>
424
+ </media-tooltip>
425
+ ${MenuPortal(menuPortal, items) }
426
+ </media-menu>
427
+ `;
428
+ }
429
+
430
+ const FONT_COLOR_OPTION = {
431
+ type: "color"
432
+ };
433
+ const FONT_FAMILY_OPTION = {
434
+ type: "radio",
435
+ values: {
436
+ "Monospaced Serif": "mono-serif",
437
+ "Proportional Serif": "pro-serif",
438
+ "Monospaced Sans-Serif": "mono-sans",
439
+ "Proportional Sans-Serif": "pro-sans",
440
+ Casual: "casual",
441
+ Cursive: "cursive",
442
+ "Small Capitals": "capitals"
443
+ }
444
+ };
445
+ const FONT_SIZE_OPTION = {
446
+ type: "slider",
447
+ min: 0,
448
+ max: 400,
449
+ step: 25,
450
+ upIcon: null,
451
+ downIcon: null
452
+ };
453
+ const FONT_OPACITY_OPTION = {
454
+ type: "slider",
455
+ min: 0,
456
+ max: 100,
457
+ step: 5,
458
+ upIcon: null,
459
+ downIcon: null
460
+ };
461
+ const FONT_TEXT_SHADOW_OPTION = {
462
+ type: "radio",
463
+ values: ["None", "Drop Shadow", "Raised", "Depressed", "Outline"]
464
+ };
465
+ const FONT_DEFAULTS = {
466
+ fontFamily: "pro-sans",
467
+ fontSize: "100%",
468
+ textColor: "#ffffff",
469
+ textOpacity: "100%",
470
+ textShadow: "none",
471
+ textBg: "#000000",
472
+ textBgOpacity: "100%",
473
+ displayBg: "#000000",
474
+ displayBgOpacity: "0%"
475
+ };
476
+ const FONT_SIGNALS = Object.keys(FONT_DEFAULTS).reduce(
477
+ (prev, type) => ({
478
+ ...prev,
479
+ [type]: signal(FONT_DEFAULTS[type])
480
+ }),
481
+ {}
482
+ );
483
+ function onFontReset() {
484
+ for (const type of Object.keys(FONT_SIGNALS)) {
485
+ const defaultValue = FONT_DEFAULTS[type];
486
+ FONT_SIGNALS[type].set(defaultValue);
487
+ }
488
+ }
489
+
490
+ function DefaultMenuCheckbox({
491
+ label,
492
+ checked,
493
+ defaultChecked = false,
494
+ storageKey,
495
+ onChange
496
+ }) {
497
+ const { translations } = useDefaultLayoutContext(), savedValue = localStorage.getItem(storageKey) , $checked = signal(!!(savedValue ?? defaultChecked)), $active = signal(false), $ariaChecked = $signal($ariaBool($checked)), $label = $i18n(translations, label);
498
+ onChange(peek($checked));
499
+ if (checked) {
500
+ effect(() => void $checked.set(checked()));
501
+ }
502
+ function onPress(event) {
503
+ if (event?.button === 1) return;
504
+ $checked.set((checked2) => !checked2);
505
+ localStorage.setItem(storageKey, $checked() ? "1" : "");
506
+ onChange($checked(), event);
507
+ $active.set(false);
508
+ }
509
+ function onKeyDown(event) {
510
+ if (isKeyboardClick(event)) onPress();
511
+ }
512
+ function onActive(event) {
513
+ if (event.button !== 0) return;
514
+ $active.set(true);
515
+ }
516
+ return html`
517
+ <div
518
+ class="vds-menu-checkbox"
519
+ role="menuitemcheckbox"
520
+ tabindex="0"
521
+ aria-label=${$label}
522
+ aria-checked=${$ariaChecked}
523
+ data-active=${$signal(() => $active() ? "" : null)}
524
+ @pointerup=${onPress}
525
+ @pointerdown=${onActive}
526
+ @keydown=${onKeyDown}
527
+ ></div>
528
+ `;
529
+ }
530
+
531
+ let sectionId = 0;
532
+ function DefaultMenuSection({ label = "", value = "", children }) {
533
+ if (!label) {
534
+ return html`
535
+ <div class="vds-menu-section">
536
+ <div class="vds-menu-section-body">${children}</div>
537
+ </div>
538
+ `;
539
+ }
540
+ const id = `vds-menu-section-${++sectionId}`;
541
+ return html`
542
+ <section class="vds-menu-section" role="group" aria-labelledby=${id}>
543
+ <div class="vds-menu-section-title">
544
+ <header id=${id}>${label}</header>
545
+ ${value ? html`<div class="vds-menu-section-value">${value}</div>` : null}
546
+ </div>
547
+ <div class="vds-menu-section-body">${children}</div>
548
+ </section>
549
+ `;
550
+ }
551
+ function DefaultMenuItem({ label, children }) {
552
+ return html`
553
+ <div class="vds-menu-item">
554
+ <div class="vds-menu-item-label">${label}</div>
555
+ ${children}
556
+ </div>
557
+ `;
558
+ }
559
+ function DefaultMenuButton({
560
+ label,
561
+ icon,
562
+ hint
563
+ }) {
564
+ return html`
565
+ <media-menu-button class="vds-menu-item">
566
+ ${IconSlot("menu-arrow-left", "vds-menu-close-icon")}
567
+ ${icon ? IconSlot(icon, "vds-menu-item-icon") : null}
568
+ <span class="vds-menu-item-label">${$signal(label)}</span>
569
+ <span class="vds-menu-item-hint" data-part="hint">${hint ? $signal(hint) : null} </span>
570
+ ${IconSlot("menu-arrow-right", "vds-menu-open-icon")}
571
+ </media-menu-button>
572
+ `;
573
+ }
574
+ function DefaultRadioGroup({
575
+ value = null,
576
+ options,
577
+ hideLabel = false,
578
+ children = null,
579
+ onChange = null
580
+ }) {
581
+ function renderRadio(option) {
582
+ const { value: value2, label: content } = option;
583
+ return html`
584
+ <media-radio class="vds-radio" value=${value2}>
585
+ ${IconSlot("menu-radio-check")}
586
+ ${!hideLabel ? html`
587
+ <span class="vds-radio-label" data-part="label">
588
+ ${isString(content) ? content : $signal(content)}
589
+ </span>
590
+ ` : null}
591
+ ${isFunction(children) ? children(option) : children}
592
+ </media-radio>
593
+ `;
594
+ }
595
+ return html`
596
+ <media-radio-group
597
+ class="vds-radio-group"
598
+ value=${isString(value) ? value : value ? $signal(value) : ""}
599
+ @change=${onChange}
600
+ >
601
+ ${isArray(options) ? options.map(renderRadio) : $signal(() => options().map(renderRadio))}
602
+ </media-radio-group>
603
+ `;
604
+ }
605
+ function createRadioOptions(entries) {
606
+ return isArray(entries) ? entries.map((entry) => ({ label: entry, value: entry.toLowerCase() })) : Object.keys(entries).map((label) => ({ label, value: entries[label] }));
607
+ }
608
+
609
+ function DefaultDualCaptionsMenuCheckbox() {
610
+ const { remote } = useMediaContext(), { translations } = useDefaultLayoutContext(), label = "Dual Captions Separation";
611
+ return DefaultMenuItem({
612
+ label: $i18n(translations, label),
613
+ children: DefaultMenuCheckbox({
614
+ label,
615
+ storageKey: "vds-player::user-dual-captions-separation",
616
+ onChange(checked, trigger) {
617
+ remote.userDualCaptionChange(checked, trigger);
618
+ }
619
+ })
620
+ });
621
+ }
622
+
623
+ function DefaultSliderParts() {
624
+ return html`
625
+ <div class="vds-slider-track"></div>
626
+ <div class="vds-slider-track-fill vds-slider-track"></div>
627
+ <div class="vds-slider-thumb"></div>
628
+ `;
629
+ }
630
+ function DefaultSliderSteps() {
631
+ return html`
632
+ <media-slider-steps class="vds-slider-steps">
633
+ <template>
634
+ <div class="vds-slider-step"></div>
635
+ </template>
636
+ </media-slider-steps>
637
+ `;
638
+ }
639
+ function DefaultMenuSliderItem({
640
+ label = null,
641
+ value = null,
642
+ upIcon = "",
643
+ downIcon = "",
644
+ children,
645
+ isMin,
646
+ isMax
647
+ }) {
648
+ const hasTitle = label || value, content = [
649
+ downIcon ? IconSlot(downIcon, "down") : null,
650
+ children,
651
+ upIcon ? IconSlot(upIcon, "up") : null
652
+ ];
653
+ return html`
654
+ <div
655
+ class=${`vds-menu-item vds-menu-slider-item${hasTitle ? " group" : ""}`}
656
+ data-min=${$signal(() => isMin() ? "" : null)}
657
+ data-max=${$signal(() => isMax() ? "" : null)}
658
+ >
659
+ ${hasTitle ? html`
660
+ <div class="vds-menu-slider-title">
661
+ ${[
662
+ label ? html`<div>${label}</div>` : null,
663
+ value ? html`<div>${value}</div>` : null
664
+ ]}
665
+ </div>
666
+ <div class="vds-menu-slider-body">${content}</div>
667
+ ` : content}
668
+ </div>
669
+ `;
670
+ }
671
+
672
+ const FONT_SIZE_OPTION_WITH_ICONS = {
673
+ ...FONT_SIZE_OPTION,
674
+ upIcon: "menu-opacity-up",
675
+ downIcon: "menu-opacity-down"
676
+ };
677
+ const FONT_OPACITY_OPTION_WITH_ICONS = {
678
+ ...FONT_OPACITY_OPTION,
679
+ upIcon: "menu-opacity-up",
680
+ downIcon: "menu-opacity-down"
681
+ };
682
+ function DefaultFontMenu() {
683
+ return $signal(() => {
684
+ const { hasCaptions } = useMediaState(), { translations } = useDefaultLayoutContext();
685
+ if (!hasCaptions()) return null;
686
+ return html`
687
+ <media-menu class="vds-font-menu vds-menu">
688
+ ${DefaultMenuButton({
689
+ label: () => i18n(translations, "Caption Styles")
690
+ })}
691
+ <media-menu-items class="vds-menu-items">
692
+ ${[
693
+ DefaultMenuSection({
694
+ label: $i18n(translations, "Font"),
695
+ children: [DefaultFontFamilyMenu(), DefaultFontSizeSlider()]
696
+ }),
697
+ DefaultMenuSection({
698
+ label: $i18n(translations, "Text"),
699
+ children: [
700
+ DefaultTextColorInput(),
701
+ DefaultTextShadowMenu(),
702
+ DefaultTextOpacitySlider()
703
+ ]
704
+ }),
705
+ DefaultMenuSection({
706
+ label: $i18n(translations, "Text Background"),
707
+ children: [DefaultTextBgInput(), DefaultTextBgOpacitySlider()]
708
+ }),
709
+ DefaultMenuSection({
710
+ label: $i18n(translations, "Display Background"),
711
+ children: [DefaultDisplayBgInput(), DefaultDisplayOpacitySlider()]
712
+ }),
713
+ DefaultMenuSection({
714
+ children: [DefaultResetMenuItem()]
715
+ })
716
+ ]}
717
+ </media-menu-items>
718
+ </media-menu>
719
+ `;
720
+ });
721
+ }
722
+ function DefaultFontFamilyMenu() {
723
+ return DefaultFontSetting({
724
+ label: "Family",
725
+ option: FONT_FAMILY_OPTION,
726
+ type: "fontFamily"
727
+ });
728
+ }
729
+ function DefaultFontSizeSlider() {
730
+ return DefaultFontSetting({
731
+ label: "Size",
732
+ option: FONT_SIZE_OPTION_WITH_ICONS,
733
+ type: "fontSize"
734
+ });
735
+ }
736
+ function DefaultTextColorInput() {
737
+ return DefaultFontSetting({
738
+ label: "Color",
739
+ option: FONT_COLOR_OPTION,
740
+ type: "textColor"
741
+ });
742
+ }
743
+ function DefaultTextOpacitySlider() {
744
+ return DefaultFontSetting({
745
+ label: "Opacity",
746
+ option: FONT_OPACITY_OPTION_WITH_ICONS,
747
+ type: "textOpacity"
748
+ });
749
+ }
750
+ function DefaultTextShadowMenu() {
751
+ return DefaultFontSetting({
752
+ label: "Shadow",
753
+ option: FONT_TEXT_SHADOW_OPTION,
754
+ type: "textShadow"
755
+ });
756
+ }
757
+ function DefaultTextBgInput() {
758
+ return DefaultFontSetting({
759
+ label: "Color",
760
+ option: FONT_COLOR_OPTION,
761
+ type: "textBg"
762
+ });
763
+ }
764
+ function DefaultTextBgOpacitySlider() {
765
+ return DefaultFontSetting({
766
+ label: "Opacity",
767
+ option: FONT_OPACITY_OPTION_WITH_ICONS,
768
+ type: "textBgOpacity"
769
+ });
770
+ }
771
+ function DefaultDisplayBgInput() {
772
+ return DefaultFontSetting({
773
+ label: "Color",
774
+ option: FONT_COLOR_OPTION,
775
+ type: "displayBg"
776
+ });
777
+ }
778
+ function DefaultDisplayOpacitySlider() {
779
+ return DefaultFontSetting({
780
+ label: "Opacity",
781
+ option: FONT_OPACITY_OPTION_WITH_ICONS,
782
+ type: "displayBgOpacity"
783
+ });
784
+ }
785
+ function DefaultResetMenuItem() {
786
+ const { translations } = useDefaultLayoutContext(), $label = () => i18n(translations, "Reset");
787
+ return html`
788
+ <button class="vds-menu-item" role="menuitem" @click=${onFontReset}>
789
+ <span class="vds-menu-item-label">${$signal($label)}</span>
790
+ </button>
791
+ `;
792
+ }
793
+ function DefaultFontSetting({ label, option, type }) {
794
+ const { player } = useMediaContext(), { translations } = useDefaultLayoutContext(), $currentValue = FONT_SIGNALS[type], $label = () => i18n(translations, label);
795
+ function notify() {
796
+ tick();
797
+ player.dispatchEvent(new Event("vds-font-change"));
798
+ }
799
+ if (option.type === "color") {
800
+ let onColorChange2 = function(event) {
801
+ $currentValue.set(event.target.value);
802
+ notify();
803
+ };
804
+ return DefaultMenuItem({
805
+ label: $signal($label),
806
+ children: html`
807
+ <input
808
+ class="vds-color-picker"
809
+ type="color"
810
+ .value=${$signal($currentValue)}
811
+ @input=${onColorChange2}
812
+ />
813
+ `
814
+ });
815
+ }
816
+ if (option.type === "slider") {
817
+ let onSliderValueChange2 = function(event) {
818
+ $currentValue.set(event.detail + "%");
819
+ notify();
820
+ };
821
+ const { min, max, step, upIcon, downIcon } = option;
822
+ return DefaultMenuSliderItem({
823
+ label: $signal($label),
824
+ value: $signal($currentValue),
825
+ upIcon,
826
+ downIcon,
827
+ isMin: () => $currentValue() === min + "%",
828
+ isMax: () => $currentValue() === max + "%",
829
+ children: html`
830
+ <media-slider
831
+ class="vds-slider"
832
+ min=${min}
833
+ max=${max}
834
+ step=${step}
835
+ key-step=${step}
836
+ .value=${$signal(() => parseInt($currentValue()))}
837
+ aria-label=${$signal($label)}
838
+ @value-change=${onSliderValueChange2}
839
+ @drag-value-change=${onSliderValueChange2}
840
+ >
841
+ ${DefaultSliderParts()}${DefaultSliderSteps()}
842
+ </media-slider>
843
+ `
844
+ });
845
+ }
846
+ const radioOptions = createRadioOptions(option.values), $hint = () => {
847
+ const value = $currentValue(), label2 = radioOptions.find((radio) => radio.value === value)?.label || "";
848
+ return i18n(translations, isString(label2) ? label2 : label2());
849
+ };
850
+ return html`
851
+ <media-menu class=${`vds-${camelToKebabCase(type)}-menu vds-menu`}>
852
+ ${DefaultMenuButton({ label: $label, hint: $hint })}
853
+ <media-menu-items class="vds-menu-items">
854
+ ${DefaultRadioGroup({
855
+ value: $currentValue,
856
+ options: radioOptions,
857
+ onChange({ detail: value }) {
858
+ $currentValue.set(value);
859
+ notify();
860
+ }
861
+ })}
862
+ </media-menu-items>
863
+ </media-menu>
864
+ `;
865
+ }
866
+
867
+ function DefaultSpeedMenuSection() {
868
+ return $signal(() => {
869
+ const { translations } = useDefaultLayoutContext(), { canSetPlaybackRate, playbackRate } = useMediaState();
870
+ if (!canSetPlaybackRate()) return null;
871
+ return DefaultMenuSection({
872
+ label: $i18n(translations, "Speed"),
873
+ value: $signal(
874
+ () => playbackRate() === 1 ? i18n(translations, "Normal") : playbackRate() + "x"
875
+ ),
876
+ children: [
877
+ DefaultMenuSliderItem({
878
+ upIcon: "menu-speed-up",
879
+ downIcon: "menu-speed-down",
880
+ children: DefaultSpeedSlider(),
881
+ isMin: () => playbackRate() === getSpeedMin(),
882
+ isMax: () => playbackRate() === getSpeedMax()
883
+ })
884
+ ]
885
+ });
886
+ });
887
+ }
888
+ function getSpeedMin() {
889
+ const { playbackRates } = useDefaultLayoutContext(), rates = playbackRates();
890
+ return isArray(rates) ? rates[0] ?? 0 : rates.min;
891
+ }
892
+ function getSpeedMax() {
893
+ const { playbackRates } = useDefaultLayoutContext(), rates = playbackRates();
894
+ return isArray(rates) ? rates[rates.length - 1] ?? 2 : rates.max;
895
+ }
896
+ function getSpeedStep() {
897
+ const { playbackRates } = useDefaultLayoutContext(), rates = playbackRates();
898
+ return isArray(rates) ? rates[1] - rates[0] || 0.25 : rates.step;
899
+ }
900
+ function DefaultSpeedSlider() {
901
+ const { translations } = useDefaultLayoutContext(), $label = $i18n(translations, "Speed"), $min = getSpeedMin, $max = getSpeedMax, $step = getSpeedStep;
902
+ return html`
903
+ <media-speed-slider
904
+ class="vds-speed-slider vds-slider"
905
+ aria-label=${$label}
906
+ min=${$signal($min)}
907
+ max=${$signal($max)}
908
+ step=${$signal($step)}
909
+ key-step=${$signal($step)}
910
+ >
911
+ ${DefaultSliderParts()}${DefaultSliderSteps()}
912
+ </media-speed-slider>
913
+ `;
914
+ }
915
+
916
+ function DefaultSettingsMenu({
917
+ placement,
918
+ portal,
919
+ tooltip
920
+ }) {
921
+ return $signal(() => {
922
+ const { viewType } = useMediaState(), {
923
+ translations,
924
+ menuPortal,
925
+ noModal,
926
+ menuGroup,
927
+ smallWhen: smWhen
928
+ } = useDefaultLayoutContext(), $placement = computed(
929
+ () => noModal() ? unwrap(placement) : !smWhen() ? unwrap(placement) : null
930
+ ), $offset = computed(
931
+ () => !smWhen() && menuGroup() === "bottom" && viewType() === "video" ? 26 : 0
932
+ ), $isOpen = signal(false);
933
+ function onOpen() {
934
+ $isOpen.set(true);
935
+ }
936
+ function onClose() {
937
+ $isOpen.set(false);
938
+ }
939
+ const items = html`
940
+ <media-menu-items
941
+ class="vds-settings-menu-items vds-menu-items"
942
+ placement=${$signal($placement)}
943
+ offset=${$signal($offset)}
944
+ >
945
+ ${$signal(() => {
946
+ if (!$isOpen()) {
947
+ return null;
948
+ }
949
+ return [DefaultSpeedMenuSection(), DefaultFontMenu(), DefaultDualCaptionsMenuCheckbox()];
950
+ })}
951
+ </media-menu-items>
952
+ `;
953
+ return html`
954
+ <media-menu class="vds-settings-menu vds-menu" @open=${onOpen} @close=${onClose}>
955
+ <media-tooltip class="vds-tooltip">
956
+ <media-tooltip-trigger>
957
+ <media-menu-button
958
+ class="vds-menu-button vds-button"
959
+ aria-label=${$i18n(translations, "Settings")}
960
+ >
961
+ ${IconSlot("menu-settings", "vds-rotate-icon")}
962
+ </media-menu-button>
963
+ </media-tooltip-trigger>
964
+ <media-tooltip-content
965
+ class="vds-tooltip-content"
966
+ placement=${isFunction(tooltip) ? $signal(tooltip) : tooltip}
967
+ >
968
+ ${$i18n(translations, "Settings")}
969
+ </media-tooltip-content>
970
+ </media-tooltip>
971
+ ${MenuPortal(menuPortal, items) }
972
+ </media-menu>
973
+ `;
974
+ });
975
+ }
976
+
977
+ function DefaultVolumePopup({
978
+ orientation,
979
+ tooltip
980
+ }) {
981
+ return $signal(() => {
982
+ const { pointer, muted, canSetVolume } = useMediaState();
983
+ if (pointer() === "coarse" && !muted()) return null;
984
+ if (!canSetVolume()) {
985
+ return DefaultMuteButton({ tooltip });
986
+ }
987
+ const $rootRef = signal(void 0), $isRootActive = useActive($rootRef);
988
+ return html`
989
+ <div class="vds-volume" ?data-active=${$signal($isRootActive)} ${ref($rootRef.set)}>
990
+ ${DefaultMuteButton({ tooltip })}
991
+ <div class="vds-volume-popup">${DefaultVolumeSlider({ orientation })}</div>
992
+ </div>
993
+ `;
994
+ });
995
+ }
996
+ function DefaultVolumeSlider({ orientation } = {}) {
997
+ const { translations } = useDefaultLayoutContext(), $label = $i18n(translations, "Volume");
998
+ return html`
999
+ <media-volume-slider
1000
+ class="vds-volume-slider vds-slider"
1001
+ aria-label=${$label}
1002
+ orientation=${ifDefined(orientation)}
1003
+ >
1004
+ <div class="vds-slider-track"></div>
1005
+ <div class="vds-slider-track-fill vds-slider-track"></div>
1006
+ <media-slider-preview class="vds-slider-preview" no-clamp>
1007
+ <media-slider-value class="vds-slider-value"></media-slider-value>
1008
+ </media-slider-preview>
1009
+ <div class="vds-slider-thumb"></div>
1010
+ </media-volume-slider>
1011
+ `;
1012
+ }
1013
+ function DefaultTimeSlider() {
1014
+ const $ref = signal(void 0), $width = signal(0), {
1015
+ thumbnails,
1016
+ translations,
1017
+ sliderChaptersMinWidth,
1018
+ disableTimeSlider,
1019
+ seekStep,
1020
+ noScrubGesture
1021
+ } = useDefaultLayoutContext(), $label = $i18n(translations, "Seek"), $isDisabled = $signal(disableTimeSlider), $isChaptersDisabled = $signal(() => $width() < sliderChaptersMinWidth()), $thumbnails = $signal(thumbnails);
1022
+ useResizeObserver($ref, () => {
1023
+ const el = $ref();
1024
+ el && $width.set(el.clientWidth);
1025
+ });
1026
+ return html`
1027
+ <media-time-slider
1028
+ class="vds-time-slider vds-slider"
1029
+ aria-label=${$label}
1030
+ key-step=${$signal(seekStep)}
1031
+ ?disabled=${$isDisabled}
1032
+ ?no-swipe-gesture=${$signal(noScrubGesture)}
1033
+ ${ref($ref.set)}
1034
+ >
1035
+ <media-slider-chapters class="vds-slider-chapters" ?disabled=${$isChaptersDisabled}>
1036
+ <template>
1037
+ <div class="vds-slider-chapter">
1038
+ <div class="vds-slider-track"></div>
1039
+ <div class="vds-slider-track-fill vds-slider-track"></div>
1040
+ <div class="vds-slider-progress vds-slider-track"></div>
1041
+ </div>
1042
+ </template>
1043
+ </media-slider-chapters>
1044
+ <div class="vds-slider-thumb"></div>
1045
+ <media-slider-preview class="vds-slider-preview">
1046
+ <media-slider-thumbnail
1047
+ class="vds-slider-thumbnail vds-thumbnail"
1048
+ .src=${$thumbnails}
1049
+ ></media-slider-thumbnail>
1050
+ <div class="vds-slider-chapter-title" data-part="chapter-title"></div>
1051
+ <media-slider-value class="vds-slider-value"></media-slider-value>
1052
+ </media-slider-preview>
1053
+ </media-time-slider>
1054
+ `;
1055
+ }
1056
+
1057
+ function DefaultTimeGroup() {
1058
+ return html`
1059
+ <div class="vds-time-group">
1060
+ ${$signal(() => {
1061
+ const { duration } = useMediaState();
1062
+ if (!duration()) return null;
1063
+ return [
1064
+ html`<media-time class="vds-time" type="current"></media-time>`,
1065
+ html`<div class="vds-time-divider">/</div>`,
1066
+ html`<media-time class="vds-time" type="duration"></media-time>`
1067
+ ];
1068
+ })}
1069
+ </div>
1070
+ `;
1071
+ }
1072
+ function DefaultTimeInvert() {
1073
+ return $signal(() => {
1074
+ const { live, duration } = useMediaState();
1075
+ return live() ? DefaultLiveButton() : duration() ? html`<media-time class="vds-time" type="current" toggle remainder></media-time>` : null;
1076
+ });
1077
+ }
1078
+ function DefaultTimeInfo() {
1079
+ return $signal(() => {
1080
+ const { live } = useMediaState();
1081
+ return live() ? DefaultLiveButton() : DefaultTimeGroup();
1082
+ });
1083
+ }
1084
+
1085
+ function DefaultTitle() {
1086
+ return $signal(() => {
1087
+ const { textTracks } = useMediaContext(), { title, started } = useMediaState(), $hasChapters = signal(null);
1088
+ watchActiveTextTrack(textTracks, "chapters", $hasChapters.set);
1089
+ return $hasChapters() && (started() || !title()) ? DefaultChapterTitle() : html`<media-title class="vds-chapter-title"></media-title>`;
1090
+ });
1091
+ }
1092
+ function DefaultChapterTitle() {
1093
+ return html`<media-chapter-title class="vds-chapter-title"></media-chapter-title>`;
1094
+ }
1095
+
1096
+ function DefaultAudioLayout() {
1097
+ return [
1098
+ DefaultAnnouncer(),
1099
+ DefaultCaptions(),
1100
+ html`
1101
+ <media-controls class="vds-controls">
1102
+ <media-controls-group class="vds-controls-group">
1103
+ ${[
1104
+ DefaultSeekButton({ backward: true, tooltip: "top start" }),
1105
+ DefaultPlayButton({ tooltip: "top" }),
1106
+ DefaultSeekButton({ tooltip: "top" }),
1107
+ DefaultAudioTitle(),
1108
+ DefaultTimeSlider(),
1109
+ DefaultTimeInvert(),
1110
+ DefaultVolumePopup({ orientation: "vertical", tooltip: "top" }),
1111
+ DefaultCaptionButton({ tooltip: "top" }),
1112
+ DefaultDownloadButton(),
1113
+ DefaultAirPlayButton({ tooltip: "top" }),
1114
+ DefaultAudioMenus()
1115
+ ]}
1116
+ </media-controls-group>
1117
+ </media-controls>
1118
+ `
1119
+ ];
1120
+ }
1121
+ function DefaultAudioTitle() {
1122
+ return $signal(() => {
1123
+ let $ref = signal(void 0), $isTextOverflowing = signal(false), media = useMediaContext(), { title, started, currentTime, ended } = useMediaState(), { translations } = useDefaultLayoutContext(), $isTransitionActive = useTransitionActive($ref), $isContinued = () => started() || currentTime() > 0;
1124
+ const $title = () => {
1125
+ const word = ended() ? "Replay" : $isContinued() ? "Continue" : "Play";
1126
+ return `${i18n(translations, word)}: ${title()}`;
1127
+ };
1128
+ effect(() => {
1129
+ if ($isTransitionActive() && document.activeElement === document.body) {
1130
+ media.player.el?.focus({ preventScroll: true });
1131
+ }
1132
+ });
1133
+ function onResize() {
1134
+ const el = $ref(), isOverflowing = !!el && !$isTransitionActive() && el.clientWidth < el.children[0].clientWidth;
1135
+ el && toggleClass(el, "vds-marquee", isOverflowing);
1136
+ $isTextOverflowing.set(isOverflowing);
1137
+ }
1138
+ function Title() {
1139
+ return html`
1140
+ <span class="vds-title-text">
1141
+ ${$signal($title)}${$signal(() => $isContinued() ? DefaultChapterTitle() : null)}
1142
+ </span>
1143
+ `;
1144
+ }
1145
+ useResizeObserver($ref, onResize);
1146
+ return title() ? html`
1147
+ <span class="vds-title" title=${$signal($title)} ${ref($ref.set)}>
1148
+ ${[
1149
+ Title(),
1150
+ $signal(() => $isTextOverflowing() && !$isTransitionActive() ? Title() : null)
1151
+ ]}
1152
+ </span>
1153
+ ` : DefaultControlsSpacer();
1154
+ });
1155
+ }
1156
+ function DefaultAudioMenus() {
1157
+ const placement = "top end";
1158
+ return [
1159
+ DefaultChaptersMenu({ tooltip: "top", placement, portal: true }),
1160
+ DefaultSettingsMenu({ tooltip: "top end", placement, portal: true })
1161
+ ];
1162
+ }
1163
+
1164
+ class DefaultLayoutIconsLoader extends LayoutIconsLoader {
1165
+ async loadIcons() {
1166
+ const paths = (await import('./vidstack-C26K8z_-.js')).icons, icons = {};
1167
+ for (const iconName of Object.keys(paths)) {
1168
+ icons[iconName] = Icon({ name: iconName, paths: paths[iconName] });
1169
+ }
1170
+ return icons;
1171
+ }
1172
+ }
1173
+
1174
+ class MediaAudioLayoutElement extends Host(LitElement, DefaultAudioLayout$1) {
1175
+ static tagName = "media-audio-layout";
1176
+ static attrs = {
1177
+ smallWhen: {
1178
+ converter(value) {
1179
+ return value !== "never" && !!value;
1180
+ }
1181
+ }
1182
+ };
1183
+ #media;
1184
+ #scrubbing = signal(false);
1185
+ onSetup() {
1186
+ this.forwardKeepAlive = false;
1187
+ this.#media = useMediaContext();
1188
+ this.classList.add("vds-audio-layout");
1189
+ this.#setupWatchScrubbing();
1190
+ }
1191
+ onConnect() {
1192
+ setLayoutName("audio", () => this.isMatch);
1193
+ this.#setupMenuContainer();
1194
+ }
1195
+ render() {
1196
+ return $signal(this.#render.bind(this));
1197
+ }
1198
+ #render() {
1199
+ return this.isMatch ? DefaultAudioLayout() : null;
1200
+ }
1201
+ #setupMenuContainer() {
1202
+ const { menuPortal } = useDefaultLayoutContext();
1203
+ effect(() => {
1204
+ if (!this.isMatch) return;
1205
+ const container = createMenuContainer(
1206
+ this,
1207
+ this.menuContainer,
1208
+ "vds-audio-layout",
1209
+ () => this.isSmallLayout
1210
+ ), roots = container ? [this, container] : [this];
1211
+ const iconsManager = this.$props.customIcons() ? new SlotManager(roots) : new DefaultLayoutIconsLoader(roots);
1212
+ iconsManager.connect();
1213
+ menuPortal.set(container);
1214
+ return () => {
1215
+ container.remove();
1216
+ menuPortal.set(null);
1217
+ };
1218
+ });
1219
+ }
1220
+ #setupWatchScrubbing() {
1221
+ const { pointer } = this.#media.$state;
1222
+ effect(() => {
1223
+ if (pointer() !== "coarse") return;
1224
+ effect(this.#watchScrubbing.bind(this));
1225
+ });
1226
+ }
1227
+ #watchScrubbing() {
1228
+ if (!this.#scrubbing()) {
1229
+ listenEvent(this, "pointerdown", this.#onStartScrubbing.bind(this));
1230
+ return;
1231
+ }
1232
+ listenEvent(window, "pointerdown", this.#onStopScrubbing.bind(this));
1233
+ }
1234
+ #onStartScrubbing(event) {
1235
+ const { target } = event, hasTimeSlider = !!(isHTMLElement(target) && target.closest(".vds-time-slider"));
1236
+ if (!hasTimeSlider) return;
1237
+ event.stopImmediatePropagation();
1238
+ this.setAttribute("data-scrubbing", "");
1239
+ this.#scrubbing.set(true);
1240
+ }
1241
+ #onStopScrubbing() {
1242
+ this.#scrubbing.set(false);
1243
+ this.removeAttribute("data-scrubbing");
1244
+ }
1245
+ }
1246
+
1247
+ class DefaultVideoLayout extends DefaultLayout {
1248
+ static props = {
1249
+ ...super.props,
1250
+ when: ({ viewType }) => viewType === "video",
1251
+ smallWhen: ({ width, height }) => width < 576 || height < 380
1252
+ };
1253
+ }
1254
+
1255
+ function DefaultKeyboardDisplay() {
1256
+ return $signal(() => {
1257
+ const media = useMediaContext(), { noKeyboardAnimations, userPrefersKeyboardAnimations } = useDefaultLayoutContext(), $disabled = computed(() => noKeyboardAnimations() || !userPrefersKeyboardAnimations());
1258
+ if ($disabled()) {
1259
+ return null;
1260
+ }
1261
+ const visible = signal(false), { lastKeyboardAction } = media.$state;
1262
+ effect(() => {
1263
+ visible.set(!!lastKeyboardAction());
1264
+ const id = setTimeout(() => visible.set(false), 500);
1265
+ return () => {
1266
+ visible.set(false);
1267
+ window.clearTimeout(id);
1268
+ };
1269
+ });
1270
+ const $actionDataAttr = computed(() => {
1271
+ const action = lastKeyboardAction()?.action;
1272
+ return action && visible() ? camelToKebabCase(action) : null;
1273
+ });
1274
+ const $classList = computed(() => `vds-kb-action${!visible() ? " hidden" : ""}`), $text = computed(getText), $iconSlot = computed(() => {
1275
+ const name = getIconName();
1276
+ return name ? createSlot(name) : null;
1277
+ });
1278
+ function Icon() {
1279
+ const $slot = $iconSlot();
1280
+ if (!$slot) return null;
1281
+ return html`
1282
+ <div class="vds-kb-bezel">
1283
+ <div class="vds-kb-icon">${$slot}</div>
1284
+ </div>
1285
+ `;
1286
+ }
1287
+ return html`
1288
+ <div class=${$signal($classList)} data-action=${$signal($actionDataAttr)}>
1289
+ <div class="vds-kb-text-wrapper">
1290
+ <div class="vds-kb-text">${$signal($text)}</div>
1291
+ </div>
1292
+ ${$signal(() => keyed(lastKeyboardAction(), Icon()))}
1293
+ </div>
1294
+ `;
1295
+ });
1296
+ }
1297
+ function getText() {
1298
+ const { $state } = useMediaContext(), action = $state.lastKeyboardAction()?.action, audioGain = $state.audioGain() ?? 1;
1299
+ switch (action) {
1300
+ case "toggleMuted":
1301
+ return $state.muted() ? "0%" : getVolumeText($state.volume(), audioGain);
1302
+ case "volumeUp":
1303
+ case "volumeDown":
1304
+ return getVolumeText($state.volume(), audioGain);
1305
+ default:
1306
+ return "";
1307
+ }
1308
+ }
1309
+ function getVolumeText(volume, gain) {
1310
+ return `${Math.round(volume * gain * 100)}%`;
1311
+ }
1312
+ function getIconName() {
1313
+ const { $state } = useMediaContext(), action = $state.lastKeyboardAction()?.action;
1314
+ switch (action) {
1315
+ case "togglePaused":
1316
+ return !$state.paused() ? "kb-play-icon" : "kb-pause-icon";
1317
+ case "toggleMuted":
1318
+ return $state.muted() || $state.volume() === 0 ? "kb-mute-icon" : $state.volume() >= 0.5 ? "kb-volume-up-icon" : "kb-volume-down-icon";
1319
+ case "toggleFullscreen":
1320
+ return `kb-fs-${$state.fullscreen() ? "enter" : "exit"}-icon`;
1321
+ case "togglePictureInPicture":
1322
+ return `kb-pip-${$state.pictureInPicture() ? "enter" : "exit"}-icon`;
1323
+ case "toggleCaptions":
1324
+ return $state.hasCaptions() ? `kb-cc-${$state.textTrack() ? "on" : "off"}-icon` : null;
1325
+ case "volumeUp":
1326
+ return "kb-volume-up-icon";
1327
+ case "volumeDown":
1328
+ return "kb-volume-down-icon";
1329
+ case "seekForward":
1330
+ return "kb-seek-forward-icon";
1331
+ case "seekBackward":
1332
+ return "kb-seek-backward-icon";
1333
+ default:
1334
+ return null;
1335
+ }
1336
+ }
1337
+
1338
+ function DefaultCaptionsMenu({
1339
+ placement,
1340
+ portal,
1341
+ tooltip
1342
+ }) {
1343
+ return $signal(() => {
1344
+ const {
1345
+ translations,
1346
+ menuPortal,
1347
+ noModal,
1348
+ menuGroup,
1349
+ smallWhen: smWhen
1350
+ } = useDefaultLayoutContext(), { viewType, hasCaptions } = useMediaState(), $offText = $i18n(translations, "Off");
1351
+ if (!hasCaptions()) return null;
1352
+ const $placement = computed(
1353
+ () => noModal() ? unwrap(placement) : !smWhen() ? unwrap(placement) : null
1354
+ ), $offset = computed(
1355
+ () => !smWhen() && menuGroup() === "bottom" && viewType() === "video" ? 26 : 0
1356
+ ), $isOpen = signal(false);
1357
+ function onOpen() {
1358
+ $isOpen.set(true);
1359
+ }
1360
+ function onClose() {
1361
+ $isOpen.set(false);
1362
+ }
1363
+ const items = html`
1364
+ <media-menu-items
1365
+ class="vds-settings-menu-items vds-menu-items"
1366
+ placement=${$signal($placement)}
1367
+ offset=${$signal($offset)}
1368
+ >
1369
+ ${$signal(() => {
1370
+ if (!$isOpen()) {
1371
+ return null;
1372
+ }
1373
+ return html`
1374
+ <media-captions-radio-group
1375
+ class="vds-captions-radio-group vds-radio-group"
1376
+ off-label=${$offText}
1377
+ >
1378
+ <template>
1379
+ <media-radio class="vds-caption-radio vds-radio">
1380
+ <slot name="menu-radio-check-icon" data-class="vds-icon"></slot>
1381
+ <span class="vds-radio-label" data-part="label"></span>
1382
+ </media-radio>
1383
+ </template>
1384
+ </media-captions-radio-group>
1385
+ `;
1386
+ })}
1387
+ </media-menu-items>
1388
+ `;
1389
+ return html`
1390
+ <media-menu class="vds-captions-menu vds-menu" @open=${onOpen} @close=${onClose}>
1391
+ <media-tooltip class="vds-tooltip">
1392
+ <media-tooltip-trigger>
1393
+ <media-menu-button
1394
+ class="vds-menu-button vds-button"
1395
+ aria-label=${$i18n(translations, "Captions")}
1396
+ >
1397
+ ${IconSlot("cc-off")}
1398
+ </media-menu-button>
1399
+ </media-tooltip-trigger>
1400
+ <media-tooltip-content
1401
+ class="vds-tooltip-content"
1402
+ placement=${isFunction(tooltip) ? $signal(tooltip) : tooltip}
1403
+ >
1404
+ ${$i18n(translations, "Captions")}
1405
+ </media-tooltip-content>
1406
+ </media-tooltip>
1407
+ ${MenuPortal(menuPortal, items) }
1408
+ </media-menu>
1409
+ `;
1410
+ });
1411
+ }
1412
+
1413
+ function DefaultVideoLayoutLarge() {
1414
+ return [
1415
+ DefaultAnnouncer(),
1416
+ DefaultVideoGestures(),
1417
+ DefaultBufferingIndicator(),
1418
+ DefaultKeyboardDisplay(),
1419
+ DefaultCaptions(),
1420
+ html`<div class="vds-scrim"></div>`,
1421
+ html`
1422
+ <media-controls class="vds-controls">
1423
+ ${[
1424
+ DefaultControlsGroupTop(),
1425
+ DefaultControlsSpacer(),
1426
+ html`<media-controls-group class="vds-controls-group"></media-controls-group>`,
1427
+ DefaultControlsSpacer(),
1428
+ html`
1429
+ <media-controls-group class="vds-controls-group">
1430
+ ${DefaultTimeSlider()}
1431
+ </media-controls-group>
1432
+ `,
1433
+ html`
1434
+ <media-controls-group class="vds-controls-group">
1435
+ ${[
1436
+ DefaultPlayButton({ tooltip: "top start" }),
1437
+ DefaultSeekButton({ backward: true, tooltip: "top" }),
1438
+ DefaultSeekButton({ backward: false, tooltip: "top" }),
1439
+ DefaultVolumePopup({ orientation: "horizontal", tooltip: "top" }),
1440
+ DefaultTimeInfo(),
1441
+ DefaultTitle(),
1442
+ DefaultBottomMenuGroup(),
1443
+ DefaultAirPlayButton({ tooltip: "top" }),
1444
+ DefaultDownloadButton(),
1445
+ DefaultPIPButton(),
1446
+ DefaultFullscreenButton({ tooltip: "top end" })
1447
+ ]}
1448
+ </media-controls-group>
1449
+ `
1450
+ ]}
1451
+ </media-controls>
1452
+ `
1453
+ ];
1454
+ }
1455
+ function DefaultBottomMenuGroup() {
1456
+ return $signal(() => {
1457
+ const { menuGroup } = useDefaultLayoutContext();
1458
+ return menuGroup() === "bottom" ? DefaultVideoMenus() : null;
1459
+ });
1460
+ }
1461
+ function DefaultControlsGroupTop() {
1462
+ return html`
1463
+ <media-controls-group class="vds-controls-group">
1464
+ ${$signal(() => {
1465
+ const { menuGroup } = useDefaultLayoutContext();
1466
+ return menuGroup() === "top" ? [DefaultControlsSpacer(), DefaultVideoMenus()] : null;
1467
+ })}
1468
+ </media-controls-group>
1469
+ `;
1470
+ }
1471
+ function DefaultVideoLayoutSmall() {
1472
+ return [
1473
+ DefaultAnnouncer(),
1474
+ DefaultVideoGestures(),
1475
+ DefaultBufferingIndicator(),
1476
+ DefaultCaptions(),
1477
+ DefaultKeyboardDisplay(),
1478
+ html`<div class="vds-scrim"></div>`,
1479
+ html`
1480
+ <media-controls class="vds-controls">
1481
+ <media-controls-group class="vds-controls-group">
1482
+ ${[
1483
+ DefaultAirPlayButton({ tooltip: "top start" }),
1484
+ DefaultControlsSpacer(),
1485
+ DefaultDownloadButton(),
1486
+ DefaultVideoMenus(),
1487
+ DefaultVolumePopup({ orientation: "vertical", tooltip: "bottom end" })
1488
+ ]}
1489
+ </media-controls-group>
1490
+
1491
+ ${DefaultControlsSpacer()}
1492
+
1493
+ <media-controls-group class="vds-controls-group" style="pointer-events: none;">
1494
+ ${[
1495
+ DefaultControlsSpacer(),
1496
+ DefaultPlayButton({ tooltip: "top" }),
1497
+ DefaultControlsSpacer()
1498
+ ]}
1499
+ </media-controls-group>
1500
+
1501
+ ${DefaultControlsSpacer()}
1502
+
1503
+ <media-controls-group class="vds-controls-group">
1504
+ ${[DefaultTimeInfo(), DefaultTitle(), DefaultFullscreenButton({ tooltip: "top end" })]}
1505
+ </media-controls-group>
1506
+
1507
+ <media-controls-group class="vds-controls-group">
1508
+ ${DefaultTimeSlider()}
1509
+ </media-controls-group>
1510
+ </media-controls>
1511
+ `,
1512
+ StartDuration()
1513
+ ];
1514
+ }
1515
+ function DefaultVideoLoadLayout() {
1516
+ return html`
1517
+ <div class="vds-load-container">
1518
+ ${[DefaultBufferingIndicator(), DefaultPlayButton({ tooltip: "top" })]}
1519
+ </div>
1520
+ `;
1521
+ }
1522
+ function StartDuration() {
1523
+ return $signal(() => {
1524
+ const { duration } = useMediaState();
1525
+ if (duration() === 0) return null;
1526
+ return html`
1527
+ <div class="vds-start-duration">
1528
+ <media-time class="vds-time" type="duration"></media-time>
1529
+ </div>
1530
+ `;
1531
+ });
1532
+ }
1533
+ function DefaultBufferingIndicator() {
1534
+ return html`
1535
+ <div class="vds-buffering-indicator">
1536
+ <media-spinner class="vds-buffering-spinner"></media-spinner>
1537
+ </div>
1538
+ `;
1539
+ }
1540
+ function DefaultVideoMenus() {
1541
+ const { menuGroup, smallWhen: smWhen } = useDefaultLayoutContext(), $side = () => menuGroup() === "top" || smWhen() ? "bottom" : "top", $tooltip = computed(() => `${$side()} ${menuGroup() === "top" ? "end" : "center"}`), $placement = computed(() => `${$side()} end`);
1542
+ return [
1543
+ DefaultChaptersMenu({ tooltip: $tooltip, placement: $placement, portal: true }),
1544
+ DefaultCaptionsMenu({ tooltip: $tooltip, placement: $placement, portal: true }),
1545
+ DefaultSettingsMenu({ tooltip: $tooltip, placement: $placement, portal: true })
1546
+ ];
1547
+ }
1548
+ function DefaultVideoGestures() {
1549
+ return $signal(() => {
1550
+ const { noGestures } = useDefaultLayoutContext();
1551
+ if (noGestures()) return null;
1552
+ return html`
1553
+ <div class="vds-gestures">
1554
+ <media-gesture class="vds-gesture" event="pointerup" action="toggle:paused"></media-gesture>
1555
+ <media-gesture
1556
+ class="vds-gesture"
1557
+ event="pointerup"
1558
+ action="toggle:controls"
1559
+ ></media-gesture>
1560
+ <media-gesture
1561
+ class="vds-gesture"
1562
+ event="dblpointerup"
1563
+ action="toggle:fullscreen"
1564
+ ></media-gesture>
1565
+ <media-gesture class="vds-gesture" event="dblpointerup" action="seek:-10"></media-gesture>
1566
+ <media-gesture class="vds-gesture" event="dblpointerup" action="seek:10"></media-gesture>
1567
+ </div>
1568
+ `;
1569
+ });
1570
+ }
1571
+
1572
+ class MediaVideoLayoutElement extends Host(LitElement, DefaultVideoLayout) {
1573
+ static tagName = "media-video-layout";
1574
+ static attrs = {
1575
+ smallWhen: {
1576
+ converter(value) {
1577
+ return value !== "never" && !!value;
1578
+ }
1579
+ }
1580
+ };
1581
+ #media;
1582
+ onSetup() {
1583
+ this.forwardKeepAlive = false;
1584
+ this.#media = useMediaContext();
1585
+ this.classList.add("vds-video-layout");
1586
+ }
1587
+ onConnect() {
1588
+ setLayoutName("video", () => this.isMatch);
1589
+ this.#setupMenuContainer();
1590
+ }
1591
+ render() {
1592
+ return $signal(this.#render.bind(this));
1593
+ }
1594
+ #setupMenuContainer() {
1595
+ const { menuPortal } = useDefaultLayoutContext();
1596
+ effect(() => {
1597
+ if (!this.isMatch) return;
1598
+ const container = createMenuContainer(
1599
+ this,
1600
+ this.menuContainer,
1601
+ "vds-video-layout",
1602
+ () => this.isSmallLayout
1603
+ ), roots = container ? [this, container] : [this];
1604
+ const iconsManager = this.$props.customIcons() ? new SlotManager(roots) : new DefaultLayoutIconsLoader(roots);
1605
+ iconsManager.connect();
1606
+ menuPortal.set(container);
1607
+ return () => {
1608
+ container.remove();
1609
+ menuPortal.set(null);
1610
+ };
1611
+ });
1612
+ }
1613
+ #render() {
1614
+ const { load } = this.#media.$props, { canLoad, streamType, nativeControls } = this.#media.$state;
1615
+ return !nativeControls() && this.isMatch ? load() === "play" && !canLoad() ? DefaultVideoLoadLayout() : streamType() === "unknown" ? DefaultBufferingIndicator() : this.isSmallLayout ? DefaultVideoLayoutSmall() : DefaultVideoLayoutLarge() : null;
1616
+ }
1617
+ }
1618
+
1619
+ export { MediaAudioLayoutElement, MediaVideoLayoutElement };