@hanifhan1f/vidstack 1.12.33 → 1.12.35

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 (210) hide show
  1. package/cdn/with-layouts/chunks/{vidstack-BCLumCST.js → vidstack-BEgmmcDO.js} +56 -52
  2. package/cdn/with-layouts/chunks/{vidstack-DJyGEdCH.js → vidstack-t3PBZMbl.js} +1 -1
  3. package/cdn/with-layouts/vidstack.js +1 -1
  4. package/dev/chunks/{vidstack-B__DfQsT.js → vidstack-BReSQAMt.js} +10 -6
  5. package/dev/define/templates/vidstack-audio-layout.js +1 -1
  6. package/dev/define/templates/vidstack-video-layout.js +7 -5
  7. package/dev/define/vidstack-player-default-layout.js +1 -1
  8. package/dev/define/vidstack-player-layouts.js +1 -1
  9. package/dev/vidstack-elements.js +1 -1
  10. package/dev/vidstack.js +0 -4
  11. package/elements.d.ts +1 -1
  12. package/global/player.d.ts +1 -1
  13. package/global/plyr.d.ts +2 -2
  14. package/index.d.ts +2 -2
  15. package/package.json +1 -1
  16. package/prod/chunks/{vidstack-BnEo_Sla.js → vidstack-B0glDgAI.js} +10 -6
  17. package/prod/define/templates/vidstack-audio-layout.js +1 -1
  18. package/prod/define/templates/vidstack-video-layout.js +7 -5
  19. package/prod/define/vidstack-player-default-layout.js +1 -1
  20. package/prod/define/vidstack-player-layouts.js +1 -1
  21. package/prod/vidstack-elements.js +1 -1
  22. package/server/chunks/{vidstack-BIGdJnUK.js → vidstack-nANS1jfu.js} +16 -10
  23. package/server/define/vidstack-player-default-layout.js +1 -1
  24. package/server/define/vidstack-player-layouts.js +1 -1
  25. package/server/vidstack-elements.js +1 -1
  26. package/types/{vidstack-DYLKXUvI.d.ts → vidstack-CZqFq0VF.d.ts} +13 -1
  27. package/cdn/chunks/vidstack-8JHLDxl5.js +0 -1
  28. package/cdn/chunks/vidstack-BF7lZRtq.js +0 -3
  29. package/cdn/chunks/vidstack-BYgY9wmd.js +0 -1
  30. package/cdn/chunks/vidstack-BYpysj84.js +0 -1
  31. package/cdn/chunks/vidstack-Bjo5esRp.js +0 -1
  32. package/cdn/chunks/vidstack-BkxGdzTJ.js +0 -16
  33. package/cdn/chunks/vidstack-BuL67v3q.js +0 -1
  34. package/cdn/chunks/vidstack-Bzk6lVKb.js +0 -1
  35. package/cdn/chunks/vidstack-C0msPRTd.js +0 -3
  36. package/cdn/chunks/vidstack-C1FlyyzK.js +0 -1
  37. package/cdn/chunks/vidstack-CIjxJCz3.js +0 -1
  38. package/cdn/chunks/vidstack-CioT3Yw2.js +0 -1
  39. package/cdn/chunks/vidstack-Cj0I-Rec.js +0 -1
  40. package/cdn/chunks/vidstack-CmpbA3Yd.js +0 -16
  41. package/cdn/chunks/vidstack-CnWKPIKT.js +0 -16
  42. package/cdn/chunks/vidstack-CrqkytHl.js +0 -1
  43. package/cdn/chunks/vidstack-D0M8R0ZU.js +0 -1
  44. package/cdn/chunks/vidstack-D40FSa5B.js +0 -3
  45. package/cdn/chunks/vidstack-D84Fzc__.js +0 -16
  46. package/cdn/chunks/vidstack-DD2JwFVU.js +0 -1
  47. package/cdn/chunks/vidstack-DQvyz7Mm.js +0 -1
  48. package/cdn/chunks/vidstack-Dd9fqVv6.js +0 -1
  49. package/cdn/chunks/vidstack-DfDZuHNP.js +0 -1
  50. package/cdn/chunks/vidstack-uMxrPflF.js +0 -1
  51. package/cdn/chunks/vidstack-xjJ-ui_l.js +0 -1
  52. package/cdn/chunks/vidstack-zemsqC5d.js +0 -1
  53. package/cdn/providers/vidstack-audio-2Dt_Ivbp.js +0 -1
  54. package/cdn/providers/vidstack-audio-BOGYlExy.js +0 -1
  55. package/cdn/providers/vidstack-dash-CUtD4e6q.js +0 -1
  56. package/cdn/providers/vidstack-dash-D4ZARr66.js +0 -1
  57. package/cdn/providers/vidstack-google-cast-BdORATUX.js +0 -1
  58. package/cdn/providers/vidstack-hls-8-552IuX.js +0 -1
  59. package/cdn/providers/vidstack-hls-R25Kb6DP.js +0 -1
  60. package/cdn/providers/vidstack-html-BvVaN2VT.js +0 -1
  61. package/cdn/providers/vidstack-html-DaAUJYsD.js +0 -1
  62. package/cdn/providers/vidstack-video-BnwQZKER.js +0 -1
  63. package/cdn/providers/vidstack-video-Csvox7SO.js +0 -1
  64. package/cdn/providers/vidstack-vimeo-D4Z96kg2.js +0 -1
  65. package/cdn/providers/vidstack-vimeo-gJmBqtLK.js +0 -1
  66. package/cdn/providers/vidstack-youtube-Chl_dTAz.js +0 -1
  67. package/cdn/providers/vidstack-youtube-DiND6h3s.js +0 -1
  68. package/cdn/with-layouts/chunks/vidstack-4liSokT6.js +0 -1
  69. package/cdn/with-layouts/chunks/vidstack-B97B8XDc.js +0 -3
  70. package/cdn/with-layouts/chunks/vidstack-BD5YoTt5.js +0 -937
  71. package/cdn/with-layouts/chunks/vidstack-BGhRKayG.js +0 -914
  72. package/cdn/with-layouts/chunks/vidstack-BL_lNyW_.js +0 -1
  73. package/cdn/with-layouts/chunks/vidstack-BMhNagfl.js +0 -1
  74. package/cdn/with-layouts/chunks/vidstack-BP3ybDy9.js +0 -912
  75. package/cdn/with-layouts/chunks/vidstack-BbFHhcVG.js +0 -1
  76. package/cdn/with-layouts/chunks/vidstack-BjOOdDcQ.js +0 -1
  77. package/cdn/with-layouts/chunks/vidstack-C5AP9wid.js +0 -1
  78. package/cdn/with-layouts/chunks/vidstack-CS2aNc61.js +0 -1
  79. package/cdn/with-layouts/chunks/vidstack-CXEcXyBI.js +0 -1
  80. package/cdn/with-layouts/chunks/vidstack-Ciq-n5rg.js +0 -1
  81. package/cdn/with-layouts/chunks/vidstack-CmuGllcj.js +0 -1
  82. package/cdn/with-layouts/chunks/vidstack-CyNByJUW.js +0 -912
  83. package/cdn/with-layouts/chunks/vidstack-D-3_fAsK.js +0 -1
  84. package/cdn/with-layouts/chunks/vidstack-DCaNJN4T.js +0 -1
  85. package/cdn/with-layouts/chunks/vidstack-DKqYI_HJ.js +0 -1
  86. package/cdn/with-layouts/chunks/vidstack-DLGH9jfs.js +0 -1
  87. package/cdn/with-layouts/chunks/vidstack-DLVdcWrK.js +0 -3
  88. package/cdn/with-layouts/chunks/vidstack-DPO7J4-v.js +0 -3
  89. package/cdn/with-layouts/chunks/vidstack-DWjB11vV.js +0 -1
  90. package/cdn/with-layouts/chunks/vidstack-Dd3L-eQj.js +0 -1
  91. package/cdn/with-layouts/chunks/vidstack-Dh2GOjra.js +0 -1
  92. package/cdn/with-layouts/chunks/vidstack-DhNpv7SU.js +0 -1
  93. package/cdn/with-layouts/chunks/vidstack-QW5tTAS4.js +0 -897
  94. package/cdn/with-layouts/chunks/vidstack-T2rZVigk.js +0 -912
  95. package/cdn/with-layouts/chunks/vidstack-Xe_d7ovA.js +0 -1
  96. package/cdn/with-layouts/chunks/vidstack-wt2OT4N7.js +0 -1
  97. package/cdn/with-layouts/providers/vidstack-audio-Bw1csc6N.js +0 -1
  98. package/cdn/with-layouts/providers/vidstack-audio-CwoQJvl2.js +0 -1
  99. package/cdn/with-layouts/providers/vidstack-dash-CJsKJfLI.js +0 -1
  100. package/cdn/with-layouts/providers/vidstack-dash-DHRMFG4Y.js +0 -1
  101. package/cdn/with-layouts/providers/vidstack-google-cast-BSYJYn-o.js +0 -1
  102. package/cdn/with-layouts/providers/vidstack-hls-DG1rTEqu.js +0 -1
  103. package/cdn/with-layouts/providers/vidstack-hls-ji26kFdQ.js +0 -1
  104. package/cdn/with-layouts/providers/vidstack-html-BvHMxtoe.js +0 -1
  105. package/cdn/with-layouts/providers/vidstack-html-CoKFAYW5.js +0 -1
  106. package/cdn/with-layouts/providers/vidstack-video-1Uj5cNP2.js +0 -1
  107. package/cdn/with-layouts/providers/vidstack-video-CIxFJ9Z1.js +0 -1
  108. package/cdn/with-layouts/providers/vidstack-vimeo-CNLKOGMa.js +0 -1
  109. package/cdn/with-layouts/providers/vidstack-vimeo-DACTbJaQ.js +0 -1
  110. package/cdn/with-layouts/providers/vidstack-youtube-D1e-LE-8.js +0 -1
  111. package/cdn/with-layouts/providers/vidstack-youtube-RoLp-I6u.js +0 -1
  112. package/dev/chunks/vidstack-03oQOdB7.js +0 -58
  113. package/dev/chunks/vidstack-0XhA3AD_.js +0 -5181
  114. package/dev/chunks/vidstack-44ILR0Cb.js +0 -1521
  115. package/dev/chunks/vidstack-B4XOm7dP.js +0 -104
  116. package/dev/chunks/vidstack-BJsZjPkB.js +0 -204
  117. package/dev/chunks/vidstack-BXSB7eI9.js +0 -58
  118. package/dev/chunks/vidstack-BaGbgcvz.js +0 -107
  119. package/dev/chunks/vidstack-Blfm1k-4.js +0 -1520
  120. package/dev/chunks/vidstack-Bo8BNFJ2.js +0 -2986
  121. package/dev/chunks/vidstack-Bs54kFSz.js +0 -66
  122. package/dev/chunks/vidstack-C3N4zIuV.js +0 -254
  123. package/dev/chunks/vidstack-C4aPQ7hZ.js +0 -1482
  124. package/dev/chunks/vidstack-C6OqdJO7.js +0 -114
  125. package/dev/chunks/vidstack-CAL4iu_K.js +0 -1482
  126. package/dev/chunks/vidstack-CEjYxSqZ.js +0 -297
  127. package/dev/chunks/vidstack-CJCnHmKE.js +0 -104
  128. package/dev/chunks/vidstack-CQdFhXSo.js +0 -204
  129. package/dev/chunks/vidstack-CSryZFvY.js +0 -1521
  130. package/dev/chunks/vidstack-C_rvOKWp.js +0 -33
  131. package/dev/chunks/vidstack-CaudO1jl.js +0 -109
  132. package/dev/chunks/vidstack-CcQdBWil.js +0 -58
  133. package/dev/chunks/vidstack-Cky9ors4.js +0 -297
  134. package/dev/chunks/vidstack-DAOcbKGP.js +0 -254
  135. package/dev/chunks/vidstack-DD_3HszA.js +0 -1520
  136. package/dev/chunks/vidstack-DKaohJzR.js +0 -5181
  137. package/dev/chunks/vidstack-DLXCqdYV.js +0 -3010
  138. package/dev/chunks/vidstack-DS7nRfge.js +0 -204
  139. package/dev/chunks/vidstack-DWtK42Sh.js +0 -1483
  140. package/dev/chunks/vidstack-D_LvMxPr.js +0 -204
  141. package/dev/chunks/vidstack-Db1-Hg_U.js +0 -297
  142. package/dev/chunks/vidstack-DrczgsqN.js +0 -297
  143. package/dev/chunks/vidstack-EoLRQZbs.js +0 -2986
  144. package/dev/chunks/vidstack-FKkY62Dr.js +0 -104
  145. package/dev/chunks/vidstack-el2dbO0m.js +0 -5181
  146. package/dev/chunks/vidstack-rvhuswgi.js +0 -2986
  147. package/prod/chunks/vidstack-BAqdCFIm.js +0 -4771
  148. package/prod/chunks/vidstack-BHqGlnGz.js +0 -1482
  149. package/prod/chunks/vidstack-BP49Gz0m.js +0 -58
  150. package/prod/chunks/vidstack-BRZe2BNi.js +0 -107
  151. package/prod/chunks/vidstack-BRnfTkxi.js +0 -297
  152. package/prod/chunks/vidstack-BaaRY-9x.js +0 -201
  153. package/prod/chunks/vidstack-BexQYZop.js +0 -2976
  154. package/prod/chunks/vidstack-BpLd9ASW.js +0 -246
  155. package/prod/chunks/vidstack-C-yd_bAJ.js +0 -4771
  156. package/prod/chunks/vidstack-C05ipjAK.js +0 -1520
  157. package/prod/chunks/vidstack-CA4tDJdF.js +0 -33
  158. package/prod/chunks/vidstack-CFXAYpuh.js +0 -1521
  159. package/prod/chunks/vidstack-CIvL96_j.js +0 -297
  160. package/prod/chunks/vidstack-CYVCrFjx.js +0 -201
  161. package/prod/chunks/vidstack-Cs0fH84E.js +0 -1521
  162. package/prod/chunks/vidstack-D7hJcnN-.js +0 -297
  163. package/prod/chunks/vidstack-DDePVDjt.js +0 -2976
  164. package/prod/chunks/vidstack-DESBVLFp.js +0 -104
  165. package/prod/chunks/vidstack-DMDDSV3t.js +0 -104
  166. package/prod/chunks/vidstack-DXfGRhxZ.js +0 -201
  167. package/prod/chunks/vidstack-D_atbNqH.js +0 -3000
  168. package/prod/chunks/vidstack-DcMkaIHJ.js +0 -2976
  169. package/prod/chunks/vidstack-DnRxQoqP.js +0 -104
  170. package/prod/chunks/vidstack-DwenML7x.js +0 -4771
  171. package/prod/chunks/vidstack-IDWYvfna.js +0 -58
  172. package/prod/chunks/vidstack-Ko2EJadT.js +0 -1483
  173. package/prod/chunks/vidstack-MbEMbVfP.js +0 -109
  174. package/prod/chunks/vidstack-ShUhyBfI.js +0 -201
  175. package/prod/chunks/vidstack-SnIdjCkV.js +0 -58
  176. package/prod/chunks/vidstack-V1jwkH0s.js +0 -66
  177. package/prod/chunks/vidstack-V9U6gsde.js +0 -1482
  178. package/prod/chunks/vidstack-XA3zT5W9.js +0 -297
  179. package/prod/chunks/vidstack-bdt7uOlN.js +0 -114
  180. package/prod/chunks/vidstack-kdaDngIm.js +0 -1520
  181. package/prod/chunks/vidstack-oNEzlviH.js +0 -246
  182. package/server/chunks/vidstack-B2Bc9g7_.js +0 -2000
  183. package/server/chunks/vidstack-B4CWj0Hp.js +0 -381
  184. package/server/chunks/vidstack-B8P1aUCK.js +0 -1503
  185. package/server/chunks/vidstack-B8_v1VQn.js +0 -3059
  186. package/server/chunks/vidstack-BGgfNYAH.js +0 -141
  187. package/server/chunks/vidstack-BGmwlunt.js +0 -3035
  188. package/server/chunks/vidstack-BO8FLks6.js +0 -295
  189. package/server/chunks/vidstack-BosyhF3p.js +0 -207
  190. package/server/chunks/vidstack-C19bj3Wq.js +0 -307
  191. package/server/chunks/vidstack-C8F1EUBn.js +0 -104
  192. package/server/chunks/vidstack-CFTkUXGK.js +0 -295
  193. package/server/chunks/vidstack-CQMB7Msg.js +0 -1502
  194. package/server/chunks/vidstack-CWho6PlG.js +0 -141
  195. package/server/chunks/vidstack-CdBfecZT.js +0 -205
  196. package/server/chunks/vidstack-Cv_Art04.js +0 -4635
  197. package/server/chunks/vidstack-DE4b5Bgx.js +0 -2002
  198. package/server/chunks/vidstack-Db22EuE_.js +0 -207
  199. package/server/chunks/vidstack-DbvCOsqU.js +0 -107
  200. package/server/chunks/vidstack-DgHfFDiw.js +0 -1962
  201. package/server/chunks/vidstack-DhF59-Up.js +0 -4635
  202. package/server/chunks/vidstack-DnkB7eGO.js +0 -207
  203. package/server/chunks/vidstack-DoHmOxNm.js +0 -295
  204. package/server/chunks/vidstack-DsnTqzpL.js +0 -29
  205. package/server/chunks/vidstack-DzWvfg1d.js +0 -1503
  206. package/server/chunks/vidstack-FHGkN5xj.js +0 -566
  207. package/server/chunks/vidstack-PnFpou7g.js +0 -3035
  208. package/server/chunks/vidstack-f5-aflD2.js +0 -104
  209. package/server/chunks/vidstack-gEJMQpTE.js +0 -2001
  210. package/server/chunks/vidstack-n4zAyLEV.js +0 -2139
@@ -1,2002 +0,0 @@
1
- import { createContext, useContext, prop, Component, computed, provideContext, signal, isBoolean, effect, setAttribute, uppercaseFirstChar, isNil, isString, noop, isFunction, unwrap, isArray, camelToKebabCase, tick, peek, isKeyboardClick, toggleClass, Host, listenEvent } from './vidstack-B8LynzY5.js';
2
- import { useMediaContext, watchColorScheme, useMediaState, getDownloadFile, appendParamsToURL, watchActiveTextTrack, useResizeObserver, useActive, useTransitionActive, isHTMLElement, createSlot } from './vidstack-B4CWj0Hp.js';
3
- import { $signal, LayoutIconsLoader, Icon, SlotManager } from './vidstack-CdBfecZT.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, sortVideoQualities } from './vidstack-BOTZD4tC.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: 5,
31
- sliderChaptersMinWidth: 325,
32
- hideQualityBitrate: false,
33
- episodes: null,
34
- episodesTitle: "Episodes",
35
- smallWhen: false,
36
- thumbnails: null,
37
- translations: null,
38
- when: false
39
- };
40
-
41
- class DefaultLayout extends Component {
42
- static props = defaultLayoutProps;
43
- #media;
44
- #when = computed(() => {
45
- const when = this.$props.when();
46
- return this.#matches(when);
47
- });
48
- #smallWhen = computed(() => {
49
- const when = this.$props.smallWhen();
50
- return this.#matches(when);
51
- });
52
- get isMatch() {
53
- return this.#when();
54
- }
55
- get isSmallLayout() {
56
- return this.#smallWhen();
57
- }
58
- onSetup() {
59
- this.#media = useMediaContext();
60
- this.setAttributes({
61
- "data-match": this.#when,
62
- "data-sm": () => this.#smallWhen() ? "" : null,
63
- "data-lg": () => !this.#smallWhen() ? "" : null,
64
- "data-size": () => this.#smallWhen() ? "sm" : "lg",
65
- "data-no-scrub-gesture": this.$props.noScrubGesture
66
- });
67
- provideContext(defaultLayoutContext, {
68
- ...this.$props,
69
- when: this.#when,
70
- smallWhen: this.#smallWhen,
71
- userPrefersAnnouncements: signal(true),
72
- userPrefersKeyboardAnimations: signal(true),
73
- menuPortal: signal(null)
74
- });
75
- }
76
- onAttach(el) {
77
- watchColorScheme(el, this.$props.colorScheme);
78
- }
79
- #matches(query) {
80
- return query !== "never" && (isBoolean(query) ? query : computed(() => query(this.#media.player.state))());
81
- }
82
- }
83
- const defaultlayout__proto = DefaultLayout.prototype;
84
- prop(defaultlayout__proto, "isMatch");
85
- prop(defaultlayout__proto, "isSmallLayout");
86
-
87
- let DefaultAudioLayout$1 = class DefaultAudioLayout extends DefaultLayout {
88
- static props = {
89
- ...super.props,
90
- when: ({ viewType }) => viewType === "audio",
91
- smallWhen: ({ width }) => width < 576
92
- };
93
- };
94
-
95
- function setLayoutName(name, isMatch) {
96
- effect(() => {
97
- const { player } = useMediaContext(), el = player.el;
98
- el && setAttribute(el, "data-layout", isMatch() && name);
99
- return () => el?.removeAttribute("data-layout");
100
- });
101
- }
102
-
103
- function i18n(translations, word) {
104
- return translations()?.[word] ?? word;
105
- }
106
-
107
- function DefaultAnnouncer() {
108
- return $signal(() => {
109
- const { translations, userPrefersAnnouncements } = useDefaultLayoutContext();
110
- if (!userPrefersAnnouncements()) return null;
111
- return html`<media-announcer .translations=${$signal(translations)}></media-announcer>`;
112
- });
113
- }
114
-
115
- function IconSlot(name, classes = "") {
116
- return html`<slot
117
- name=${`${name}-icon`}
118
- data-class=${`vds-icon vds-${name}-icon${classes ? ` ${classes}` : ""}`}
119
- ></slot>`;
120
- }
121
- function IconSlots(names) {
122
- return names.map((name) => IconSlot(name));
123
- }
124
-
125
- function $i18n(translations, word) {
126
- return $signal(() => i18n(translations, word));
127
- }
128
-
129
- function DefaultAirPlayButton({ tooltip }) {
130
- const { translations } = useDefaultLayoutContext(), { remotePlaybackState } = useMediaState(), $label = $signal(() => {
131
- const airPlayText = i18n(translations, "AirPlay"), stateText = uppercaseFirstChar(remotePlaybackState());
132
- return `${airPlayText} ${stateText}`;
133
- }), $airPlayText = $i18n(translations, "AirPlay");
134
- return html`
135
- <media-tooltip class="vds-airplay-tooltip vds-tooltip">
136
- <media-tooltip-trigger>
137
- <media-airplay-button class="vds-airplay-button vds-button" aria-label=${$label}>
138
- ${IconSlot("airplay")}
139
- </media-airplay-button>
140
- </media-tooltip-trigger>
141
- <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
142
- <span class="vds-airplay-tooltip-text">${$airPlayText}</span>
143
- </media-tooltip-content>
144
- </media-tooltip>
145
- `;
146
- }
147
- function DefaultPlayButton({ tooltip }) {
148
- const { translations } = useDefaultLayoutContext(), $playText = $i18n(translations, "Play"), $pauseText = $i18n(translations, "Pause");
149
- return html`
150
- <media-tooltip class="vds-play-tooltip vds-tooltip">
151
- <media-tooltip-trigger>
152
- <media-play-button
153
- class="vds-play-button vds-button"
154
- aria-label=${$i18n(translations, "Play")}
155
- >
156
- ${IconSlots(["play", "pause", "replay"])}
157
- </media-play-button>
158
- </media-tooltip-trigger>
159
- <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
160
- <span class="vds-play-tooltip-text">${$playText}</span>
161
- <span class="vds-pause-tooltip-text">${$pauseText}</span>
162
- </media-tooltip-content>
163
- </media-tooltip>
164
- `;
165
- }
166
- function DefaultMuteButton({
167
- tooltip,
168
- ref: ref$1 = noop
169
- }) {
170
- const { translations } = useDefaultLayoutContext(), $muteText = $i18n(translations, "Mute"), $unmuteText = $i18n(translations, "Unmute");
171
- return html`
172
- <media-tooltip class="vds-mute-tooltip vds-tooltip">
173
- <media-tooltip-trigger>
174
- <media-mute-button
175
- class="vds-mute-button vds-button"
176
- aria-label=${$i18n(translations, "Mute")}
177
- ${ref(ref$1)}
178
- >
179
- ${IconSlots(["mute", "volume-low", "volume-high"])}
180
- </media-mute-button>
181
- </media-tooltip-trigger>
182
- <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
183
- <span class="vds-mute-tooltip-text">${$unmuteText}</span>
184
- <span class="vds-unmute-tooltip-text">${$muteText}</span>
185
- </media-tooltip-content>
186
- </media-tooltip>
187
- `;
188
- }
189
- function DefaultCaptionButton({ tooltip }) {
190
- const { translations } = useDefaultLayoutContext(), $ccOnText = $i18n(translations, "Closed-Captions On"), $ccOffText = $i18n(translations, "Closed-Captions Off");
191
- return html`
192
- <media-tooltip class="vds-caption-tooltip vds-tooltip">
193
- <media-tooltip-trigger>
194
- <media-caption-button
195
- class="vds-caption-button vds-button"
196
- aria-label=${$i18n(translations, "Captions")}
197
- >
198
- ${IconSlots(["cc-on", "cc-off"])}
199
- </media-caption-button>
200
- </media-tooltip-trigger>
201
- <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
202
- <span class="vds-cc-on-tooltip-text">${$ccOffText}</span>
203
- <span class="vds-cc-off-tooltip-text">${$ccOnText}</span>
204
- </media-tooltip-content>
205
- </media-tooltip>
206
- `;
207
- }
208
- function DefaultPIPButton() {
209
- const { translations } = useDefaultLayoutContext(), $enterText = $i18n(translations, "Enter PiP"), $exitText = $i18n(translations, "Exit PiP");
210
- return html`
211
- <media-tooltip class="vds-pip-tooltip vds-tooltip">
212
- <media-tooltip-trigger>
213
- <media-pip-button
214
- class="vds-pip-button vds-button"
215
- aria-label=${$i18n(translations, "PiP")}
216
- >
217
- ${IconSlots(["pip-enter", "pip-exit"])}
218
- </media-pip-button>
219
- </media-tooltip-trigger>
220
- <media-tooltip-content class="vds-tooltip-content">
221
- <span class="vds-pip-enter-tooltip-text">${$enterText}</span>
222
- <span class="vds-pip-exit-tooltip-text">${$exitText}</span>
223
- </media-tooltip-content>
224
- </media-tooltip>
225
- `;
226
- }
227
- function DefaultFullscreenButton({ tooltip }) {
228
- const { translations } = useDefaultLayoutContext(), $enterText = $i18n(translations, "Enter Fullscreen"), $exitText = $i18n(translations, "Exit Fullscreen");
229
- return html`
230
- <media-tooltip class="vds-fullscreen-tooltip vds-tooltip">
231
- <media-tooltip-trigger>
232
- <media-fullscreen-button
233
- class="vds-fullscreen-button vds-button"
234
- aria-label=${$i18n(translations, "Fullscreen")}
235
- >
236
- ${IconSlots(["fs-enter", "fs-exit"])}
237
- </media-fullscreen-button>
238
- </media-tooltip-trigger>
239
- <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
240
- <span class="vds-fs-enter-tooltip-text">${$enterText}</span>
241
- <span class="vds-fs-exit-tooltip-text">${$exitText}</span>
242
- </media-tooltip-content>
243
- </media-tooltip>
244
- `;
245
- }
246
- function DefaultSeekButton({
247
- backward,
248
- tooltip
249
- }) {
250
- const { translations, seekStep } = useDefaultLayoutContext(), seekText = !backward ? "Seek Forward" : "Seek Backward", $label = $i18n(translations, seekText), $seconds = () => (backward ? -1 : 1) * seekStep();
251
- return html`
252
- <media-tooltip class="vds-seek-tooltip vds-tooltip">
253
- <media-tooltip-trigger>
254
- <media-seek-button
255
- class="vds-seek-button vds-button"
256
- seconds=${$signal($seconds)}
257
- aria-label=${$label}
258
- >
259
- ${!backward ? IconSlot("seek-forward") : IconSlot("seek-backward")}
260
- </media-seek-button>
261
- </media-tooltip-trigger>
262
- <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
263
- ${$i18n(translations, seekText)}
264
- </media-tooltip-content>
265
- </media-tooltip>
266
- `;
267
- }
268
- function DefaultLiveButton() {
269
- const { translations } = useDefaultLayoutContext(), { live } = useMediaState(), $label = $i18n(translations, "Skip To Live"), $liveText = $i18n(translations, "LIVE");
270
- return live() ? html`
271
- <media-live-button class="vds-live-button" aria-label=${$label}>
272
- <span class="vds-live-button-text">${$liveText}</span>
273
- </media-live-button>
274
- ` : null;
275
- }
276
- function DefaultDownloadButton() {
277
- return $signal(() => {
278
- const { download, translations } = useDefaultLayoutContext(), $download = download();
279
- if (isNil($download)) return null;
280
- const { source, title } = useMediaState(), $src = source(), file = getDownloadFile({
281
- title: title(),
282
- src: $src,
283
- download: $download
284
- });
285
- return isString(file?.url) ? html`
286
- <media-tooltip class="vds-download-tooltip vds-tooltip">
287
- <media-tooltip-trigger>
288
- <a
289
- role="button"
290
- class="vds-download-button vds-button"
291
- aria-label=${$i18n(translations, "Download")}
292
- href=${appendParamsToURL(file.url, { download: file.name })}
293
- download=${file.name}
294
- target="_blank"
295
- >
296
- <slot name="download-icon" data-class="vds-icon" />
297
- </a>
298
- </media-tooltip-trigger>
299
- <media-tooltip-content class="vds-tooltip-content" placement="top">
300
- ${$i18n(translations, "Download")}
301
- </media-tooltip-content>
302
- </media-tooltip>
303
- ` : null;
304
- });
305
- }
306
- function DefaultEpisodeButton({ tooltip } = {}) {
307
- const $label = "Episodes", $episodesText = "Episodes";
308
- function openEpisodes(e) {
309
- e.stopPropagation();
310
- e.currentTarget?.dispatchEvent(
311
- new CustomEvent("vds-episodes-open", { bubbles: true, composed: true })
312
- );
313
- }
314
- const content = html`
315
- <button
316
- type="button"
317
- class="vds-episode-button vds-button"
318
- aria-label=${$label}
319
- @pointerup=${openEpisodes}
320
- >
321
- ${IconSlot("menu-episodes")}
322
- </button>
323
- `;
324
- if (!tooltip) return content;
325
- return html`
326
- <media-tooltip class="vds-episode-tooltip vds-tooltip">
327
- <media-tooltip-trigger> ${content} </media-tooltip-trigger>
328
- <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
329
- <span class="vds-episode-tooltip-text">${$episodesText}</span>
330
- </media-tooltip-content>
331
- </media-tooltip>
332
- `;
333
- }
334
-
335
- function DefaultCaptions() {
336
- const { translations } = useDefaultLayoutContext();
337
- return html`
338
- <media-captions
339
- class="vds-captions"
340
- .exampleText=${$i18n(translations, "Captions look like this")}
341
- ></media-captions>
342
- `;
343
- }
344
-
345
- function DefaultControlsSpacer() {
346
- return html`<div class="vds-controls-spacer"></div>`;
347
- }
348
-
349
- function MenuPortal(container, template) {
350
- return html`
351
- <media-menu-portal .container=${$signal(container)} disabled="fullscreen">
352
- ${template}
353
- </media-menu-portal>
354
- `;
355
- }
356
- function createMenuContainer(layoutEl, rootSelector, className, isSmallLayout) {
357
- let root = isString(rootSelector) ? document.querySelector(rootSelector) : rootSelector;
358
- if (!root) root = layoutEl?.closest("dialog");
359
- if (!root) root = document.body;
360
- const container = document.createElement("div");
361
- container.style.display = "contents";
362
- container.classList.add(className);
363
- root.append(container);
364
- effect(() => {
365
- if (!container) return;
366
- const { viewType } = useMediaState(), isSmall = isSmallLayout();
367
- setAttribute(container, "data-view-type", viewType());
368
- setAttribute(container, "data-sm", isSmall);
369
- setAttribute(container, "data-lg", !isSmall);
370
- setAttribute(container, "data-size", isSmall ? "sm" : "lg");
371
- });
372
- const { colorScheme } = useDefaultLayoutContext();
373
- watchColorScheme(container, colorScheme);
374
- return container;
375
- }
376
-
377
- function DefaultChaptersMenu({
378
- placement,
379
- tooltip,
380
- portal
381
- }) {
382
- const { textTracks } = useMediaContext(), { viewType, seekableStart, seekableEnd } = useMediaState(), {
383
- translations,
384
- thumbnails,
385
- menuPortal,
386
- noModal,
387
- menuGroup,
388
- smallWhen: smWhen
389
- } = useDefaultLayoutContext(), $disabled = computed(() => {
390
- const $startTime = seekableStart(), $endTime = seekableEnd(), $track = signal(null);
391
- watchActiveTextTrack(textTracks, "chapters", $track.set);
392
- const cues = $track()?.cues.filter(
393
- (cue) => cue.startTime <= $endTime && cue.endTime >= $startTime
394
- );
395
- return !cues?.length;
396
- });
397
- if ($disabled()) return null;
398
- const $placement = computed(
399
- () => noModal() ? unwrap(placement) : !smWhen() ? unwrap(placement) : null
400
- ), $offset = computed(
401
- () => !smWhen() && menuGroup() === "bottom" && viewType() === "video" ? 26 : 0
402
- ), $isOpen = signal(false);
403
- function onOpen() {
404
- $isOpen.set(true);
405
- }
406
- function onClose() {
407
- $isOpen.set(false);
408
- }
409
- const items = html`
410
- <media-menu-items
411
- class="vds-chapters-menu-items vds-menu-items"
412
- placement=${$signal($placement)}
413
- offset=${$signal($offset)}
414
- >
415
- ${$signal(() => {
416
- if (!$isOpen()) return null;
417
- return html`
418
- <media-chapters-radio-group
419
- class="vds-chapters-radio-group vds-radio-group"
420
- .thumbnails=${$signal(thumbnails)}
421
- >
422
- <template>
423
- <media-radio class="vds-chapter-radio vds-radio">
424
- <media-thumbnail class="vds-thumbnail"></media-thumbnail>
425
- <div class="vds-chapter-radio-content">
426
- <span class="vds-chapter-radio-label" data-part="label"></span>
427
- <span class="vds-chapter-radio-start-time" data-part="start-time"></span>
428
- <span class="vds-chapter-radio-duration" data-part="duration"></span>
429
- </div>
430
- </media-radio>
431
- </template>
432
- </media-chapters-radio-group>
433
- `;
434
- })}
435
- </media-menu-items>
436
- `;
437
- return html`
438
- <media-menu class="vds-chapters-menu vds-menu" @open=${onOpen} @close=${onClose}>
439
- <media-tooltip class="vds-tooltip">
440
- <media-tooltip-trigger>
441
- <media-menu-button
442
- class="vds-menu-button vds-button"
443
- aria-label=${$i18n(translations, "Chapters")}
444
- >
445
- ${IconSlot("menu-chapters")}
446
- </media-menu-button>
447
- </media-tooltip-trigger>
448
- <media-tooltip-content
449
- class="vds-tooltip-content"
450
- placement=${isFunction(tooltip) ? $signal(tooltip) : tooltip}
451
- >
452
- ${$i18n(translations, "Chapters")}
453
- </media-tooltip-content>
454
- </media-tooltip>
455
- ${MenuPortal(menuPortal, items) }
456
- </media-menu>
457
- `;
458
- }
459
-
460
- const FONT_COLOR_OPTION = {
461
- type: "color"
462
- };
463
- const FONT_FAMILY_OPTION = {
464
- type: "radio",
465
- values: {
466
- "Monospaced Serif": "mono-serif",
467
- "Proportional Serif": "pro-serif",
468
- "Monospaced Sans-Serif": "mono-sans",
469
- "Proportional Sans-Serif": "pro-sans",
470
- Casual: "casual",
471
- Cursive: "cursive",
472
- "Small Capitals": "capitals"
473
- }
474
- };
475
- const FONT_SIZE_OPTION = {
476
- type: "slider",
477
- min: 0,
478
- max: 400,
479
- step: 25,
480
- upIcon: null,
481
- downIcon: null
482
- };
483
- const FONT_OPACITY_OPTION = {
484
- type: "slider",
485
- min: 0,
486
- max: 100,
487
- step: 5,
488
- upIcon: null,
489
- downIcon: null
490
- };
491
- const FONT_TEXT_SHADOW_OPTION = {
492
- type: "radio",
493
- values: ["None", "Drop Shadow", "Raised", "Depressed", "Outline"]
494
- };
495
- const FONT_DEFAULTS = {
496
- fontFamily: "pro-sans",
497
- fontSize: "100%",
498
- textColor: "#ffffff",
499
- textOpacity: "100%",
500
- textShadow: "none",
501
- textBg: "#000000",
502
- textBgOpacity: "100%",
503
- displayBg: "#000000",
504
- displayBgOpacity: "0%"
505
- };
506
- const FONT_SIGNALS = Object.keys(FONT_DEFAULTS).reduce(
507
- (prev, type) => ({
508
- ...prev,
509
- [type]: signal(FONT_DEFAULTS[type])
510
- }),
511
- {}
512
- );
513
- function onFontReset() {
514
- for (const type of Object.keys(FONT_SIGNALS)) {
515
- const defaultValue = FONT_DEFAULTS[type];
516
- FONT_SIGNALS[type].set(defaultValue);
517
- }
518
- }
519
-
520
- let sectionId = 0;
521
- function DefaultMenuSection({ label = "", value = "", children }) {
522
- if (!label) {
523
- return html`
524
- <div class="vds-menu-section">
525
- <div class="vds-menu-section-body">${children}</div>
526
- </div>
527
- `;
528
- }
529
- const id = `vds-menu-section-${++sectionId}`;
530
- return html`
531
- <section class="vds-menu-section" role="group" aria-labelledby=${id}>
532
- <div class="vds-menu-section-title">
533
- <header id=${id}>${label}</header>
534
- ${value ? html`<div class="vds-menu-section-value">${value}</div>` : null}
535
- </div>
536
- <div class="vds-menu-section-body">${children}</div>
537
- </section>
538
- `;
539
- }
540
- function DefaultMenuItem({ label, children }) {
541
- return html`
542
- <div class="vds-menu-item">
543
- <div class="vds-menu-item-label">${label}</div>
544
- ${children}
545
- </div>
546
- `;
547
- }
548
- function DefaultMenuButton({
549
- label,
550
- icon,
551
- hint
552
- }) {
553
- return html`
554
- <media-menu-button class="vds-menu-item">
555
- ${IconSlot("menu-arrow-left", "vds-menu-close-icon")}
556
- ${icon ? IconSlot(icon, "vds-menu-item-icon") : null}
557
- <span class="vds-menu-item-label">${$signal(label)}</span>
558
- <span class="vds-menu-item-hint" data-part="hint">${hint ? $signal(hint) : null} </span>
559
- ${IconSlot("menu-arrow-right", "vds-menu-open-icon")}
560
- </media-menu-button>
561
- `;
562
- }
563
- function DefaultRadioGroup({
564
- value = null,
565
- options,
566
- hideLabel = false,
567
- children = null,
568
- onChange = null
569
- }) {
570
- function renderRadio(option) {
571
- const { value: value2, label: content } = option;
572
- return html`
573
- <media-radio class="vds-radio" value=${value2}>
574
- ${IconSlot("menu-radio-check")}
575
- ${!hideLabel ? html`
576
- <span class="vds-radio-label" data-part="label">
577
- ${isString(content) ? content : $signal(content)}
578
- </span>
579
- ` : null}
580
- ${isFunction(children) ? children(option) : children}
581
- </media-radio>
582
- `;
583
- }
584
- return html`
585
- <media-radio-group
586
- class="vds-radio-group"
587
- value=${isString(value) ? value : value ? $signal(value) : ""}
588
- @change=${onChange}
589
- >
590
- ${isArray(options) ? options.map(renderRadio) : $signal(() => options().map(renderRadio))}
591
- </media-radio-group>
592
- `;
593
- }
594
- function createRadioOptions(entries) {
595
- return isArray(entries) ? entries.map((entry) => ({ label: entry, value: entry.toLowerCase() })) : Object.keys(entries).map((label) => ({ label, value: entries[label] }));
596
- }
597
-
598
- function DefaultSliderParts() {
599
- return html`
600
- <div class="vds-slider-track"></div>
601
- <div class="vds-slider-track-fill vds-slider-track"></div>
602
- <div class="vds-slider-thumb"></div>
603
- `;
604
- }
605
- function DefaultSliderSteps() {
606
- return html`
607
- <media-slider-steps class="vds-slider-steps">
608
- <template>
609
- <div class="vds-slider-step"></div>
610
- </template>
611
- </media-slider-steps>
612
- `;
613
- }
614
- function DefaultMenuSliderItem({
615
- label = null,
616
- value = null,
617
- upIcon = "",
618
- downIcon = "",
619
- children,
620
- isMin,
621
- isMax
622
- }) {
623
- const hasTitle = label || value, content = [
624
- downIcon ? IconSlot(downIcon, "down") : null,
625
- children,
626
- upIcon ? IconSlot(upIcon, "up") : null
627
- ];
628
- return html`
629
- <div
630
- class=${`vds-menu-item vds-menu-slider-item${hasTitle ? " group" : ""}`}
631
- data-min=${$signal(() => isMin() ? "" : null)}
632
- data-max=${$signal(() => isMax() ? "" : null)}
633
- >
634
- ${hasTitle ? html`
635
- <div class="vds-menu-slider-title">
636
- ${[
637
- label ? html`<div>${label}</div>` : null,
638
- value ? html`<div>${value}</div>` : null
639
- ]}
640
- </div>
641
- <div class="vds-menu-slider-body">${content}</div>
642
- ` : content}
643
- </div>
644
- `;
645
- }
646
-
647
- const FONT_SIZE_OPTION_WITH_ICONS = {
648
- ...FONT_SIZE_OPTION,
649
- upIcon: "menu-opacity-up",
650
- downIcon: "menu-opacity-down"
651
- };
652
- const FONT_OPACITY_OPTION_WITH_ICONS = {
653
- ...FONT_OPACITY_OPTION,
654
- upIcon: "menu-opacity-up",
655
- downIcon: "menu-opacity-down"
656
- };
657
- function DefaultFontMenu() {
658
- return $signal(() => {
659
- const { hasCaptions } = useMediaState(), { translations } = useDefaultLayoutContext();
660
- if (!hasCaptions()) return null;
661
- return html`
662
- <media-menu class="vds-font-menu vds-menu">
663
- ${DefaultMenuButton({
664
- label: () => i18n(translations, "Caption Styles")
665
- })}
666
- <media-menu-items class="vds-menu-items">
667
- ${[
668
- DefaultMenuSection({
669
- label: $i18n(translations, "Font"),
670
- children: [DefaultFontFamilyMenu(), DefaultFontSizeSlider()]
671
- }),
672
- DefaultMenuSection({
673
- label: $i18n(translations, "Text"),
674
- children: [
675
- DefaultTextColorInput(),
676
- DefaultTextShadowMenu(),
677
- DefaultTextOpacitySlider()
678
- ]
679
- }),
680
- DefaultMenuSection({
681
- label: $i18n(translations, "Text Background"),
682
- children: [DefaultTextBgInput(), DefaultTextBgOpacitySlider()]
683
- }),
684
- DefaultMenuSection({
685
- label: $i18n(translations, "Display Background"),
686
- children: [DefaultDisplayBgInput(), DefaultDisplayOpacitySlider()]
687
- }),
688
- DefaultMenuSection({
689
- children: [DefaultResetMenuItem()]
690
- })
691
- ]}
692
- </media-menu-items>
693
- </media-menu>
694
- `;
695
- });
696
- }
697
- function DefaultFontFamilyMenu() {
698
- return DefaultFontSetting({
699
- label: "Family",
700
- option: FONT_FAMILY_OPTION,
701
- type: "fontFamily"
702
- });
703
- }
704
- function DefaultFontSizeSlider() {
705
- return DefaultFontSetting({
706
- label: "Size",
707
- option: FONT_SIZE_OPTION_WITH_ICONS,
708
- type: "fontSize"
709
- });
710
- }
711
- function DefaultTextColorInput() {
712
- return DefaultFontSetting({
713
- label: "Color",
714
- option: FONT_COLOR_OPTION,
715
- type: "textColor"
716
- });
717
- }
718
- function DefaultTextOpacitySlider() {
719
- return DefaultFontSetting({
720
- label: "Opacity",
721
- option: FONT_OPACITY_OPTION_WITH_ICONS,
722
- type: "textOpacity"
723
- });
724
- }
725
- function DefaultTextShadowMenu() {
726
- return DefaultFontSetting({
727
- label: "Shadow",
728
- option: FONT_TEXT_SHADOW_OPTION,
729
- type: "textShadow"
730
- });
731
- }
732
- function DefaultTextBgInput() {
733
- return DefaultFontSetting({
734
- label: "Color",
735
- option: FONT_COLOR_OPTION,
736
- type: "textBg"
737
- });
738
- }
739
- function DefaultTextBgOpacitySlider() {
740
- return DefaultFontSetting({
741
- label: "Opacity",
742
- option: FONT_OPACITY_OPTION_WITH_ICONS,
743
- type: "textBgOpacity"
744
- });
745
- }
746
- function DefaultDisplayBgInput() {
747
- return DefaultFontSetting({
748
- label: "Color",
749
- option: FONT_COLOR_OPTION,
750
- type: "displayBg"
751
- });
752
- }
753
- function DefaultDisplayOpacitySlider() {
754
- return DefaultFontSetting({
755
- label: "Opacity",
756
- option: FONT_OPACITY_OPTION_WITH_ICONS,
757
- type: "displayBgOpacity"
758
- });
759
- }
760
- function DefaultResetMenuItem() {
761
- const { translations } = useDefaultLayoutContext(), $label = () => i18n(translations, "Reset");
762
- return html`
763
- <button class="vds-menu-item" role="menuitem" @click=${onFontReset}>
764
- <span class="vds-menu-item-label">${$signal($label)}</span>
765
- </button>
766
- `;
767
- }
768
- function DefaultFontSetting({ label, option, type }) {
769
- const { player } = useMediaContext(), { translations } = useDefaultLayoutContext(), $currentValue = FONT_SIGNALS[type], $label = () => i18n(translations, label);
770
- function notify() {
771
- tick();
772
- player.dispatchEvent(new Event("vds-font-change"));
773
- }
774
- if (option.type === "color") {
775
- let onColorChange2 = function(event) {
776
- $currentValue.set(event.target.value);
777
- notify();
778
- };
779
- return DefaultMenuItem({
780
- label: $signal($label),
781
- children: html`
782
- <input
783
- class="vds-color-picker"
784
- type="color"
785
- .value=${$signal($currentValue)}
786
- @input=${onColorChange2}
787
- />
788
- `
789
- });
790
- }
791
- if (option.type === "slider") {
792
- let onSliderValueChange2 = function(event) {
793
- $currentValue.set(event.detail + "%");
794
- notify();
795
- };
796
- const { min, max, step, upIcon, downIcon } = option;
797
- return DefaultMenuSliderItem({
798
- label: $signal($label),
799
- value: $signal($currentValue),
800
- upIcon,
801
- downIcon,
802
- isMin: () => $currentValue() === min + "%",
803
- isMax: () => $currentValue() === max + "%",
804
- children: html`
805
- <media-slider
806
- class="vds-slider"
807
- min=${min}
808
- max=${max}
809
- step=${step}
810
- key-step=${step}
811
- .value=${$signal(() => parseInt($currentValue()))}
812
- aria-label=${$signal($label)}
813
- @value-change=${onSliderValueChange2}
814
- @drag-value-change=${onSliderValueChange2}
815
- >
816
- ${DefaultSliderParts()}${DefaultSliderSteps()}
817
- </media-slider>
818
- `
819
- });
820
- }
821
- const radioOptions = createRadioOptions(option.values), $hint = () => {
822
- const value = $currentValue(), label2 = radioOptions.find((radio) => radio.value === value)?.label || "";
823
- return i18n(translations, isString(label2) ? label2 : label2());
824
- };
825
- return html`
826
- <media-menu class=${`vds-${camelToKebabCase(type)}-menu vds-menu`}>
827
- ${DefaultMenuButton({ label: $label, hint: $hint })}
828
- <media-menu-items class="vds-menu-items">
829
- ${DefaultRadioGroup({
830
- value: $currentValue,
831
- options: radioOptions,
832
- onChange({ detail: value }) {
833
- $currentValue.set(value);
834
- notify();
835
- }
836
- })}
837
- </media-menu-items>
838
- </media-menu>
839
- `;
840
- }
841
-
842
- function DefaultMenuCheckbox({
843
- label,
844
- checked,
845
- defaultChecked = false,
846
- storageKey,
847
- onChange
848
- }) {
849
- const { translations } = useDefaultLayoutContext(), savedValue = storageKey ? localStorage.getItem(storageKey) : null, $checked = signal(!!(savedValue ?? defaultChecked)), $active = signal(false), $ariaChecked = $signal($ariaBool($checked)), $label = $i18n(translations, label);
850
- if (storageKey) onChange(peek($checked));
851
- if (checked) {
852
- effect(() => void $checked.set(checked()));
853
- }
854
- function onPress(event) {
855
- if (event?.button === 1) return;
856
- $checked.set((checked2) => !checked2);
857
- if (storageKey) localStorage.setItem(storageKey, $checked() ? "1" : "");
858
- onChange($checked(), event);
859
- $active.set(false);
860
- }
861
- function onKeyDown(event) {
862
- if (isKeyboardClick(event)) onPress();
863
- }
864
- function onActive(event) {
865
- if (event.button !== 0) return;
866
- $active.set(true);
867
- }
868
- return html`
869
- <div
870
- class="vds-menu-checkbox"
871
- role="menuitemcheckbox"
872
- tabindex="0"
873
- aria-label=${$label}
874
- aria-checked=${$ariaChecked}
875
- data-active=${$signal(() => $active() ? "" : null)}
876
- @pointerup=${onPress}
877
- @pointerdown=${onActive}
878
- @keydown=${onKeyDown}
879
- ></div>
880
- `;
881
- }
882
-
883
- function DefaultAccessibilityMenu() {
884
- return $signal(() => {
885
- const { translations } = useDefaultLayoutContext();
886
- return html`
887
- <media-menu class="vds-accessibility-menu vds-menu">
888
- ${DefaultMenuButton({
889
- label: () => i18n(translations, "Accessibility"),
890
- icon: "menu-accessibility"
891
- })}
892
- <media-menu-items class="vds-menu-items">
893
- ${[
894
- DefaultMenuSection({
895
- children: [
896
- DefaultAnnouncementsMenuCheckbox(),
897
- DefaultKeyboardAnimationsMenuCheckbox()
898
- ]
899
- }),
900
- DefaultMenuSection({
901
- children: [DefaultFontMenu()]
902
- })
903
- ]}
904
- </media-menu-items>
905
- </media-menu>
906
- `;
907
- });
908
- }
909
- function DefaultAnnouncementsMenuCheckbox() {
910
- const { userPrefersAnnouncements, translations } = useDefaultLayoutContext(), label = "Announcements";
911
- return DefaultMenuItem({
912
- label: $i18n(translations, label),
913
- children: DefaultMenuCheckbox({
914
- label,
915
- storageKey: "vds-player::announcements",
916
- onChange(checked) {
917
- userPrefersAnnouncements.set(checked);
918
- }
919
- })
920
- });
921
- }
922
- function DefaultKeyboardAnimationsMenuCheckbox() {
923
- return $signal(() => {
924
- const { translations, userPrefersKeyboardAnimations, noKeyboardAnimations } = useDefaultLayoutContext(), { viewType } = useMediaState(), $disabled = computed(() => viewType() !== "video" || noKeyboardAnimations());
925
- if ($disabled()) return null;
926
- const label = "Keyboard Animations";
927
- return DefaultMenuItem({
928
- label: $i18n(translations, label),
929
- children: DefaultMenuCheckbox({
930
- label,
931
- defaultChecked: true,
932
- storageKey: "vds-player::keyboard-animations",
933
- onChange(checked) {
934
- userPrefersKeyboardAnimations.set(checked);
935
- }
936
- })
937
- });
938
- });
939
- }
940
-
941
- function DefaultAudioMenu() {
942
- return $signal(() => {
943
- const { noAudioGain, translations } = useDefaultLayoutContext(), { audioTracks, canSetAudioGain } = useMediaState(), $disabled = computed(() => {
944
- const hasGainSlider = canSetAudioGain() && !noAudioGain();
945
- return !hasGainSlider && audioTracks().length <= 1;
946
- });
947
- if ($disabled()) return null;
948
- return html`
949
- <media-menu class="vds-audio-menu vds-menu">
950
- ${DefaultMenuButton({
951
- label: () => i18n(translations, "Audio"),
952
- icon: "menu-audio"
953
- })}
954
- <media-menu-items class="vds-menu-items">
955
- ${[DefaultAudioTracksMenu(), DefaultAudioBoostSection()]}
956
- </media-menu-items>
957
- </media-menu>
958
- `;
959
- });
960
- }
961
- function DefaultAudioTracksMenu() {
962
- return $signal(() => {
963
- const { translations } = useDefaultLayoutContext(), { audioTracks } = useMediaState(), $defaultText = $i18n(translations, "Default"), $disabled = computed(() => audioTracks().length <= 1);
964
- if ($disabled()) return null;
965
- return DefaultMenuSection({
966
- children: html`
967
- <media-menu class="vds-audio-tracks-menu vds-menu">
968
- ${DefaultMenuButton({
969
- label: () => i18n(translations, "Track")
970
- })}
971
- <media-menu-items class="vds-menu-items">
972
- <media-audio-radio-group
973
- class="vds-audio-track-radio-group vds-radio-group"
974
- empty-label=${$defaultText}
975
- >
976
- <template>
977
- <media-radio class="vds-audio-track-radio vds-radio">
978
- <slot name="menu-radio-check-icon" data-class="vds-icon"></slot>
979
- <span class="vds-radio-label" data-part="label"></span>
980
- </media-radio>
981
- </template>
982
- </media-audio-radio-group>
983
- </media-menu-items>
984
- </media-menu>
985
- `
986
- });
987
- });
988
- }
989
- function DefaultAudioBoostSection() {
990
- return $signal(() => {
991
- const { noAudioGain, translations } = useDefaultLayoutContext(), { canSetAudioGain } = useMediaState(), $disabled = computed(() => !canSetAudioGain() || noAudioGain());
992
- if ($disabled()) return null;
993
- const { audioGain } = useMediaState();
994
- return DefaultMenuSection({
995
- label: $i18n(translations, "Boost"),
996
- value: $signal(() => Math.round(((audioGain() ?? 1) - 1) * 100) + "%"),
997
- children: [
998
- DefaultMenuSliderItem({
999
- upIcon: "menu-audio-boost-up",
1000
- downIcon: "menu-audio-boost-down",
1001
- children: DefaultAudioGainSlider(),
1002
- isMin: () => ((audioGain() ?? 1) - 1) * 100 <= getGainMin(),
1003
- isMax: () => ((audioGain() ?? 1) - 1) * 100 === getGainMax()
1004
- })
1005
- ]
1006
- });
1007
- });
1008
- }
1009
- function DefaultAudioGainSlider() {
1010
- const { translations } = useDefaultLayoutContext(), $label = $i18n(translations, "Boost"), $min = getGainMin, $max = getGainMax, $step = getGainStep;
1011
- return html`
1012
- <media-audio-gain-slider
1013
- class="vds-audio-gain-slider vds-slider"
1014
- aria-label=${$label}
1015
- min=${$signal($min)}
1016
- max=${$signal($max)}
1017
- step=${$signal($step)}
1018
- key-step=${$signal($step)}
1019
- >
1020
- ${DefaultSliderParts()}${DefaultSliderSteps()}
1021
- </media-audio-gain-slider>
1022
- `;
1023
- }
1024
- function getGainMin() {
1025
- const { audioGains } = useDefaultLayoutContext(), gains = audioGains();
1026
- return isArray(gains) ? gains[0] ?? 0 : gains.min;
1027
- }
1028
- function getGainMax() {
1029
- const { audioGains } = useDefaultLayoutContext(), gains = audioGains();
1030
- return isArray(gains) ? gains[gains.length - 1] ?? 300 : gains.max;
1031
- }
1032
- function getGainStep() {
1033
- const { audioGains } = useDefaultLayoutContext(), gains = audioGains();
1034
- return isArray(gains) ? gains[1] - gains[0] || 25 : gains.step;
1035
- }
1036
-
1037
- function DefaultCaptionsMenu() {
1038
- return $signal(() => {
1039
- const { translations } = useDefaultLayoutContext(), { hasCaptions, textTracks } = useMediaState(), $offText = $i18n(translations, "Off");
1040
- if (!hasCaptions()) return null;
1041
- return html`
1042
- <media-menu class="vds-captions-menu vds-menu">
1043
- ${DefaultMenuButton({
1044
- label: () => i18n(translations, "Captions"),
1045
- icon: "menu-captions"
1046
- })}
1047
- <media-menu-items class="vds-menu-items">
1048
- <media-captions-radio-group
1049
- class="vds-captions-radio-group vds-radio-group"
1050
- off-label=${$offText}
1051
- >
1052
- <template>
1053
- <media-radio class="vds-caption-radio vds-radio">
1054
- <slot name="menu-radio-check-icon" data-class="vds-icon"></slot>
1055
- <span class="vds-caption-flag" data-part="flag"></span>
1056
- <span class="vds-radio-label" data-part="label"></span>
1057
- </media-radio>
1058
- </template>
1059
- </media-captions-radio-group>
1060
- </media-menu-items>
1061
- </media-menu>
1062
- `;
1063
- });
1064
- }
1065
-
1066
- function DefaultPlaybackMenu() {
1067
- return $signal(() => {
1068
- const { translations } = useDefaultLayoutContext();
1069
- return html`
1070
- <media-menu class="vds-playback-menu vds-menu">
1071
- ${DefaultMenuButton({
1072
- label: () => i18n(translations, "Playback"),
1073
- icon: "menu-playback"
1074
- })}
1075
- <media-menu-items class="vds-menu-items">
1076
- ${[
1077
- DefaultMenuSection({
1078
- children: DefaultLoopCheckbox()
1079
- }),
1080
- DefaultSpeedMenuSection(),
1081
- DefaultQualityMenuSection()
1082
- ]}
1083
- </media-menu-items>
1084
- </media-menu>
1085
- `;
1086
- });
1087
- }
1088
- function DefaultLoopCheckbox() {
1089
- const { remote } = useMediaContext(), { translations } = useDefaultLayoutContext(), label = "Loop";
1090
- return DefaultMenuItem({
1091
- label: $i18n(translations, label),
1092
- children: DefaultMenuCheckbox({
1093
- label,
1094
- storageKey: "vds-player::user-loop",
1095
- onChange(checked, trigger) {
1096
- remote.userPrefersLoopChange(checked, trigger);
1097
- }
1098
- })
1099
- });
1100
- }
1101
- function DefaultSpeedMenuSection() {
1102
- return $signal(() => {
1103
- const { translations } = useDefaultLayoutContext(), { canSetPlaybackRate, playbackRate } = useMediaState();
1104
- if (!canSetPlaybackRate()) return null;
1105
- return DefaultMenuSection({
1106
- label: $i18n(translations, "Speed"),
1107
- value: $signal(
1108
- () => playbackRate() === 1 ? i18n(translations, "Normal") : playbackRate() + "x"
1109
- ),
1110
- children: [
1111
- DefaultMenuSliderItem({
1112
- upIcon: "menu-speed-up",
1113
- downIcon: "menu-speed-down",
1114
- children: DefaultSpeedSlider(),
1115
- isMin: () => playbackRate() === getSpeedMin(),
1116
- isMax: () => playbackRate() === getSpeedMax()
1117
- })
1118
- ]
1119
- });
1120
- });
1121
- }
1122
- function getSpeedMin() {
1123
- const { playbackRates } = useDefaultLayoutContext(), rates = playbackRates();
1124
- return isArray(rates) ? rates[0] ?? 0 : rates.min;
1125
- }
1126
- function getSpeedMax() {
1127
- const { playbackRates } = useDefaultLayoutContext(), rates = playbackRates();
1128
- return isArray(rates) ? rates[rates.length - 1] ?? 2 : rates.max;
1129
- }
1130
- function getSpeedStep() {
1131
- const { playbackRates } = useDefaultLayoutContext(), rates = playbackRates();
1132
- return isArray(rates) ? rates[1] - rates[0] || 0.25 : rates.step;
1133
- }
1134
- function DefaultSpeedSlider() {
1135
- const { translations } = useDefaultLayoutContext(), $label = $i18n(translations, "Speed"), $min = getSpeedMin, $max = getSpeedMax, $step = getSpeedStep;
1136
- return html`
1137
- <media-speed-slider
1138
- class="vds-speed-slider vds-slider"
1139
- aria-label=${$label}
1140
- min=${$signal($min)}
1141
- max=${$signal($max)}
1142
- step=${$signal($step)}
1143
- key-step=${$signal($step)}
1144
- >
1145
- ${DefaultSliderParts()}${DefaultSliderSteps()}
1146
- </media-speed-slider>
1147
- `;
1148
- }
1149
- function DefaultAutoQualityCheckbox() {
1150
- const { remote, qualities } = useMediaContext(), { autoQuality, canSetQuality, qualities: $qualities } = useMediaState(), { translations } = useDefaultLayoutContext(), label = "Auto", $disabled = computed(() => !canSetQuality() || $qualities().length <= 1);
1151
- if ($disabled()) return null;
1152
- return DefaultMenuItem({
1153
- label: $i18n(translations, label),
1154
- children: DefaultMenuCheckbox({
1155
- label,
1156
- checked: autoQuality,
1157
- onChange(checked, trigger) {
1158
- if (checked) {
1159
- remote.requestAutoQuality(trigger);
1160
- } else {
1161
- remote.changeQuality(qualities.selectedIndex, trigger);
1162
- }
1163
- }
1164
- })
1165
- });
1166
- }
1167
- function DefaultQualityMenuSection() {
1168
- return $signal(() => {
1169
- const { hideQualityBitrate, translations } = useDefaultLayoutContext(), { canSetQuality, qualities, quality } = useMediaState(), $disabled = computed(() => !canSetQuality() || qualities().length <= 1), $sortedQualities = computed(() => sortVideoQualities(qualities()));
1170
- if ($disabled()) return null;
1171
- return DefaultMenuSection({
1172
- label: $i18n(translations, "Quality"),
1173
- value: $signal(() => {
1174
- const height = quality()?.height, bitrate = !hideQualityBitrate() ? quality()?.bitrate : null, bitrateText = bitrate && bitrate > 0 ? `${(bitrate / 1e6).toFixed(2)} Mbps` : null, autoText = i18n(translations, "Auto");
1175
- return height ? `${height}p${bitrateText ? ` (${bitrateText})` : ""}` : autoText;
1176
- }),
1177
- children: [
1178
- DefaultMenuSliderItem({
1179
- upIcon: "menu-quality-up",
1180
- downIcon: "menu-quality-down",
1181
- children: DefaultQualitySlider(),
1182
- isMin: () => $sortedQualities()[0] === quality(),
1183
- isMax: () => $sortedQualities().at(-1) === quality()
1184
- }),
1185
- DefaultAutoQualityCheckbox()
1186
- ]
1187
- });
1188
- });
1189
- }
1190
- function DefaultQualitySlider() {
1191
- const { translations } = useDefaultLayoutContext(), $label = $i18n(translations, "Quality");
1192
- return html`
1193
- <media-quality-slider class="vds-quality-slider vds-slider" aria-label=${$label}>
1194
- ${DefaultSliderParts()}${DefaultSliderSteps()}
1195
- </media-quality-slider>
1196
- `;
1197
- }
1198
-
1199
- function DefaultSettingsMenu({
1200
- placement,
1201
- portal,
1202
- tooltip
1203
- }) {
1204
- return $signal(() => {
1205
- const { viewType } = useMediaState(), {
1206
- translations,
1207
- menuPortal,
1208
- noModal,
1209
- menuGroup,
1210
- smallWhen: smWhen
1211
- } = useDefaultLayoutContext(), $placement = computed(
1212
- () => noModal() ? unwrap(placement) : !smWhen() ? unwrap(placement) : null
1213
- ), $offset = computed(
1214
- () => !smWhen() && menuGroup() === "bottom" && viewType() === "video" ? 26 : 0
1215
- ), $isOpen = signal(false);
1216
- function onOpen() {
1217
- $isOpen.set(true);
1218
- }
1219
- function onClose() {
1220
- $isOpen.set(false);
1221
- }
1222
- const items = html`
1223
- <media-menu-items
1224
- class="vds-settings-menu-items vds-menu-items"
1225
- placement=${$signal($placement)}
1226
- offset=${$signal($offset)}
1227
- >
1228
- ${$signal(() => {
1229
- if (!$isOpen()) {
1230
- return null;
1231
- }
1232
- return [
1233
- DefaultPlaybackMenu(),
1234
- DefaultAccessibilityMenu(),
1235
- DefaultAudioMenu(),
1236
- DefaultCaptionsMenu()
1237
- ];
1238
- })}
1239
- </media-menu-items>
1240
- `;
1241
- return html`
1242
- <media-menu class="vds-settings-menu vds-menu" @open=${onOpen} @close=${onClose}>
1243
- <media-tooltip class="vds-tooltip">
1244
- <media-tooltip-trigger>
1245
- <media-menu-button
1246
- class="vds-menu-button vds-button"
1247
- aria-label=${$i18n(translations, "Settings")}
1248
- >
1249
- ${IconSlot("menu-settings", "vds-rotate-icon")}
1250
- </media-menu-button>
1251
- </media-tooltip-trigger>
1252
- <media-tooltip-content
1253
- class="vds-tooltip-content"
1254
- placement=${isFunction(tooltip) ? $signal(tooltip) : tooltip}
1255
- >
1256
- ${$i18n(translations, "Settings")}
1257
- </media-tooltip-content>
1258
- </media-tooltip>
1259
- ${MenuPortal(menuPortal, items) }
1260
- </media-menu>
1261
- `;
1262
- });
1263
- }
1264
-
1265
- function DefaultVolumePopup({
1266
- orientation,
1267
- tooltip
1268
- }) {
1269
- return $signal(() => {
1270
- const { pointer, muted, canSetVolume } = useMediaState();
1271
- if (pointer() === "coarse" && !muted()) return null;
1272
- if (!canSetVolume()) {
1273
- return DefaultMuteButton({ tooltip });
1274
- }
1275
- const $rootRef = signal(void 0), $isRootActive = useActive($rootRef);
1276
- return html`
1277
- <div class="vds-volume" ?data-active=${$signal($isRootActive)} ${ref($rootRef.set)}>
1278
- ${DefaultMuteButton({ tooltip })}
1279
- <div class="vds-volume-popup">${DefaultVolumeSlider({ orientation })}</div>
1280
- </div>
1281
- `;
1282
- });
1283
- }
1284
- function DefaultVolumeSlider({ orientation } = {}) {
1285
- const { translations } = useDefaultLayoutContext(), $label = $i18n(translations, "Volume");
1286
- return html`
1287
- <media-volume-slider
1288
- class="vds-volume-slider vds-slider"
1289
- aria-label=${$label}
1290
- orientation=${ifDefined(orientation)}
1291
- >
1292
- <div class="vds-slider-track"></div>
1293
- <div class="vds-slider-track-fill vds-slider-track"></div>
1294
- <media-slider-preview class="vds-slider-preview" no-clamp>
1295
- <media-slider-value class="vds-slider-value"></media-slider-value>
1296
- </media-slider-preview>
1297
- <div class="vds-slider-thumb"></div>
1298
- </media-volume-slider>
1299
- `;
1300
- }
1301
- function DefaultTimeSlider() {
1302
- const $ref = signal(void 0), $width = signal(0), {
1303
- thumbnails,
1304
- translations,
1305
- sliderChaptersMinWidth,
1306
- disableTimeSlider,
1307
- seekStep,
1308
- noScrubGesture
1309
- } = useDefaultLayoutContext(), $label = $i18n(translations, "Seek"), $isDisabled = $signal(disableTimeSlider), $isChaptersDisabled = $signal(() => $width() < sliderChaptersMinWidth()), $thumbnails = $signal(thumbnails);
1310
- useResizeObserver($ref, () => {
1311
- const el = $ref();
1312
- el && $width.set(el.clientWidth);
1313
- });
1314
- return html`
1315
- <media-time-slider
1316
- class="vds-time-slider vds-slider"
1317
- aria-label=${$label}
1318
- key-step=${$signal(seekStep)}
1319
- ?disabled=${$isDisabled}
1320
- ?no-swipe-gesture=${$signal(noScrubGesture)}
1321
- ${ref($ref.set)}
1322
- >
1323
- <media-slider-chapters class="vds-slider-chapters" ?disabled=${$isChaptersDisabled}>
1324
- <template>
1325
- <div class="vds-slider-chapter">
1326
- <div class="vds-slider-track"></div>
1327
- <div class="vds-slider-track-fill vds-slider-track"></div>
1328
- <div class="vds-slider-progress vds-slider-track"></div>
1329
- </div>
1330
- </template>
1331
- </media-slider-chapters>
1332
- <div class="vds-slider-thumb"></div>
1333
- <media-slider-preview class="vds-slider-preview">
1334
- <media-slider-thumbnail
1335
- class="vds-slider-thumbnail vds-thumbnail"
1336
- .src=${$thumbnails}
1337
- ></media-slider-thumbnail>
1338
- <div class="vds-slider-chapter-title" data-part="chapter-title"></div>
1339
- <media-slider-value class="vds-slider-value"></media-slider-value>
1340
- </media-slider-preview>
1341
- </media-time-slider>
1342
- `;
1343
- }
1344
-
1345
- function DefaultTimeGroup() {
1346
- return html`
1347
- <div class="vds-time-group">
1348
- ${$signal(() => {
1349
- const { duration } = useMediaState();
1350
- if (!duration()) return null;
1351
- return [
1352
- html`<media-time class="vds-time" type="current"></media-time>`,
1353
- html`<div class="vds-time-divider">/</div>`,
1354
- html`<media-time class="vds-time" type="duration"></media-time>`
1355
- ];
1356
- })}
1357
- </div>
1358
- `;
1359
- }
1360
- function DefaultTimeInvert() {
1361
- return $signal(() => {
1362
- const { live, duration } = useMediaState();
1363
- return live() ? DefaultLiveButton() : duration() ? html`<media-time class="vds-time" type="current" toggle remainder></media-time>` : null;
1364
- });
1365
- }
1366
- function DefaultTimeInfo() {
1367
- return $signal(() => {
1368
- const { live } = useMediaState();
1369
- return live() ? DefaultLiveButton() : DefaultTimeGroup();
1370
- });
1371
- }
1372
-
1373
- function DefaultTitle() {
1374
- return $signal(() => {
1375
- const { textTracks } = useMediaContext(), { title, started } = useMediaState(), $hasChapters = signal(null);
1376
- watchActiveTextTrack(textTracks, "chapters", $hasChapters.set);
1377
- return $hasChapters() && (started() || !title()) ? DefaultChapterTitle() : html`<media-title class="vds-chapter-title"></media-title>`;
1378
- });
1379
- }
1380
- function DefaultChapterTitle() {
1381
- return html`<media-chapter-title class="vds-chapter-title"></media-chapter-title>`;
1382
- }
1383
-
1384
- function DefaultAudioLayout() {
1385
- return [
1386
- DefaultAnnouncer(),
1387
- DefaultCaptions(),
1388
- html`
1389
- <media-controls class="vds-controls">
1390
- <media-controls-group class="vds-controls-group">
1391
- ${[
1392
- DefaultSeekButton({ backward: true, tooltip: "top start" }),
1393
- DefaultPlayButton({ tooltip: "top" }),
1394
- DefaultSeekButton({ tooltip: "top" }),
1395
- DefaultAudioTitle(),
1396
- DefaultTimeSlider(),
1397
- DefaultTimeInvert(),
1398
- DefaultVolumePopup({ orientation: "vertical", tooltip: "top" }),
1399
- DefaultCaptionButton({ tooltip: "top" }),
1400
- DefaultDownloadButton(),
1401
- DefaultAirPlayButton({ tooltip: "top" }),
1402
- DefaultAudioMenus()
1403
- ]}
1404
- </media-controls-group>
1405
- </media-controls>
1406
- `
1407
- ];
1408
- }
1409
- function DefaultAudioTitle() {
1410
- return $signal(() => {
1411
- let $ref = signal(void 0), $isTextOverflowing = signal(false), media = useMediaContext(), { title, started, currentTime, ended } = useMediaState(), { translations } = useDefaultLayoutContext(), $isTransitionActive = useTransitionActive($ref), $isContinued = () => started() || currentTime() > 0;
1412
- const $title = () => {
1413
- const word = ended() ? "Replay" : $isContinued() ? "Continue" : "Play";
1414
- return `${i18n(translations, word)}: ${title()}`;
1415
- };
1416
- effect(() => {
1417
- if ($isTransitionActive() && document.activeElement === document.body) {
1418
- media.player.el?.focus({ preventScroll: true });
1419
- }
1420
- });
1421
- function onResize() {
1422
- const el = $ref(), isOverflowing = !!el && !$isTransitionActive() && el.clientWidth < el.children[0].clientWidth;
1423
- el && toggleClass(el, "vds-marquee", isOverflowing);
1424
- $isTextOverflowing.set(isOverflowing);
1425
- }
1426
- function Title() {
1427
- return html`
1428
- <span class="vds-title-text">
1429
- ${$signal($title)}${$signal(() => $isContinued() ? DefaultChapterTitle() : null)}
1430
- </span>
1431
- `;
1432
- }
1433
- useResizeObserver($ref, onResize);
1434
- return title() ? html`
1435
- <span class="vds-title" title=${$signal($title)} ${ref($ref.set)}>
1436
- ${[
1437
- Title(),
1438
- $signal(() => $isTextOverflowing() && !$isTransitionActive() ? Title() : null)
1439
- ]}
1440
- </span>
1441
- ` : DefaultControlsSpacer();
1442
- });
1443
- }
1444
- function DefaultAudioMenus() {
1445
- const placement = "top end";
1446
- return [
1447
- DefaultChaptersMenu({ tooltip: "top", placement, portal: true }),
1448
- DefaultSettingsMenu({ tooltip: "top end", placement, portal: true })
1449
- ];
1450
- }
1451
-
1452
- class DefaultLayoutIconsLoader extends LayoutIconsLoader {
1453
- async loadIcons() {
1454
- const paths = (await import('./vidstack-P_QDjYIl.js')).icons, icons = {};
1455
- for (const iconName of Object.keys(paths)) {
1456
- icons[iconName] = Icon({ name: iconName, paths: paths[iconName] });
1457
- }
1458
- return icons;
1459
- }
1460
- }
1461
-
1462
- class MediaAudioLayoutElement extends Host(LitElement, DefaultAudioLayout$1) {
1463
- static tagName = "media-audio-layout";
1464
- static attrs = {
1465
- smallWhen: {
1466
- converter(value) {
1467
- return value !== "never" && !!value;
1468
- }
1469
- }
1470
- };
1471
- #media;
1472
- #scrubbing = signal(false);
1473
- onSetup() {
1474
- this.forwardKeepAlive = false;
1475
- this.#media = useMediaContext();
1476
- this.classList.add("vds-audio-layout");
1477
- this.#setupWatchScrubbing();
1478
- }
1479
- onConnect() {
1480
- setLayoutName("audio", () => this.isMatch);
1481
- this.#setupMenuContainer();
1482
- }
1483
- render() {
1484
- return $signal(this.#render.bind(this));
1485
- }
1486
- #render() {
1487
- return this.isMatch ? DefaultAudioLayout() : null;
1488
- }
1489
- #setupMenuContainer() {
1490
- const { menuPortal } = useDefaultLayoutContext();
1491
- effect(() => {
1492
- if (!this.isMatch) return;
1493
- const container = createMenuContainer(
1494
- this,
1495
- this.menuContainer,
1496
- "vds-audio-layout",
1497
- () => this.isSmallLayout
1498
- ), roots = container ? [this, container] : [this];
1499
- const iconsManager = this.$props.customIcons() ? new SlotManager(roots) : new DefaultLayoutIconsLoader(roots);
1500
- iconsManager.connect();
1501
- menuPortal.set(container);
1502
- return () => {
1503
- container.remove();
1504
- menuPortal.set(null);
1505
- };
1506
- });
1507
- }
1508
- #setupWatchScrubbing() {
1509
- const { pointer } = this.#media.$state;
1510
- effect(() => {
1511
- if (pointer() !== "coarse") return;
1512
- effect(this.#watchScrubbing.bind(this));
1513
- });
1514
- }
1515
- #watchScrubbing() {
1516
- if (!this.#scrubbing()) {
1517
- listenEvent(this, "pointerdown", this.#onStartScrubbing.bind(this));
1518
- return;
1519
- }
1520
- listenEvent(window, "pointerdown", this.#onStopScrubbing.bind(this));
1521
- }
1522
- #onStartScrubbing(event) {
1523
- const { target } = event, hasTimeSlider = !!(isHTMLElement(target) && target.closest(".vds-time-slider"));
1524
- if (!hasTimeSlider) return;
1525
- event.stopImmediatePropagation();
1526
- this.setAttribute("data-scrubbing", "");
1527
- this.#scrubbing.set(true);
1528
- }
1529
- #onStopScrubbing() {
1530
- this.#scrubbing.set(false);
1531
- this.removeAttribute("data-scrubbing");
1532
- }
1533
- }
1534
-
1535
- class DefaultVideoLayout extends DefaultLayout {
1536
- static props = {
1537
- ...super.props,
1538
- when: ({ viewType }) => viewType === "video",
1539
- smallWhen: ({ width, height }) => width < 576 || height < 380
1540
- };
1541
- }
1542
-
1543
- function DefaultKeyboardDisplay() {
1544
- return $signal(() => {
1545
- const media = useMediaContext(), { noKeyboardAnimations, userPrefersKeyboardAnimations } = useDefaultLayoutContext(), $disabled = computed(() => noKeyboardAnimations() || !userPrefersKeyboardAnimations());
1546
- if ($disabled()) {
1547
- return null;
1548
- }
1549
- const visible = signal(false), { lastKeyboardAction } = media.$state;
1550
- effect(() => {
1551
- visible.set(!!lastKeyboardAction());
1552
- const id = setTimeout(() => visible.set(false), 500);
1553
- return () => {
1554
- visible.set(false);
1555
- window.clearTimeout(id);
1556
- };
1557
- });
1558
- const $actionDataAttr = computed(() => {
1559
- const action = lastKeyboardAction()?.action;
1560
- return action && visible() ? camelToKebabCase(action) : null;
1561
- });
1562
- const $classList = computed(() => `vds-kb-action${!visible() ? " hidden" : ""}`), $text = computed(getText), $iconSlot = computed(() => {
1563
- const name = getIconName();
1564
- return name ? createSlot(name) : null;
1565
- });
1566
- function Icon() {
1567
- const $slot = $iconSlot();
1568
- if (!$slot) return null;
1569
- return html`
1570
- <div class="vds-kb-bezel">
1571
- <div class="vds-kb-icon">${$slot}</div>
1572
- </div>
1573
- `;
1574
- }
1575
- return html`
1576
- <div class=${$signal($classList)} data-action=${$signal($actionDataAttr)}>
1577
- <div class="vds-kb-text-wrapper">
1578
- <div class="vds-kb-text">${$signal($text)}</div>
1579
- </div>
1580
- ${$signal(() => keyed(lastKeyboardAction(), Icon()))}
1581
- </div>
1582
- `;
1583
- });
1584
- }
1585
- function getText() {
1586
- const { $state } = useMediaContext(), action = $state.lastKeyboardAction()?.action, audioGain = $state.audioGain() ?? 1;
1587
- switch (action) {
1588
- case "toggleMuted":
1589
- return $state.muted() ? "0%" : getVolumeText($state.volume(), audioGain);
1590
- case "volumeUp":
1591
- case "volumeDown":
1592
- return getVolumeText($state.volume(), audioGain);
1593
- default:
1594
- return "";
1595
- }
1596
- }
1597
- function getVolumeText(volume, gain) {
1598
- return `${Math.round(volume * gain * 100)}%`;
1599
- }
1600
- function getIconName() {
1601
- const { $state } = useMediaContext(), action = $state.lastKeyboardAction()?.action;
1602
- switch (action) {
1603
- case "togglePaused":
1604
- return !$state.paused() ? "kb-play-icon" : "kb-pause-icon";
1605
- case "toggleMuted":
1606
- return $state.muted() || $state.volume() === 0 ? "kb-mute-icon" : $state.volume() >= 0.5 ? "kb-volume-up-icon" : "kb-volume-down-icon";
1607
- case "toggleFullscreen":
1608
- return `kb-fs-${$state.fullscreen() ? "enter" : "exit"}-icon`;
1609
- case "togglePictureInPicture":
1610
- return `kb-pip-${$state.pictureInPicture() ? "enter" : "exit"}-icon`;
1611
- case "toggleCaptions":
1612
- return $state.hasCaptions() ? `kb-cc-${$state.textTrack() ? "on" : "off"}-icon` : null;
1613
- case "volumeUp":
1614
- return "kb-volume-up-icon";
1615
- case "volumeDown":
1616
- return "kb-volume-down-icon";
1617
- case "seekForward":
1618
- return "kb-seek-forward-icon";
1619
- case "seekBackward":
1620
- return "kb-seek-backward-icon";
1621
- default:
1622
- return null;
1623
- }
1624
- }
1625
-
1626
- function DefaultVideoLayoutLarge() {
1627
- const { episodes, smallWhen: smWhen } = useDefaultLayoutContext(), { fullscreen } = useMediaState(), $episodesOpen = signal(false);
1628
- effect(() => {
1629
- if (!fullscreen()) $episodesOpen.set(false);
1630
- });
1631
- function onEpisodesToggle() {
1632
- if (!fullscreen() && !smWhen() || !episodes()?.length) return;
1633
- $episodesOpen.set(!$episodesOpen());
1634
- }
1635
- function onEpisodesClose() {
1636
- $episodesOpen.set(false);
1637
- }
1638
- return [
1639
- DefaultAnnouncer(),
1640
- DefaultVideoGestures(),
1641
- DefaultBufferingIndicator(),
1642
- DefaultKeyboardDisplay(),
1643
- DefaultCaptions(),
1644
- html`<div class="vds-scrim"></div>`,
1645
- html`
1646
- <media-controls class="vds-controls" @vds-episodes-open=${onEpisodesToggle}>
1647
- ${[
1648
- DefaultControlsGroupTop(),
1649
- DefaultControlsSpacer(),
1650
- html`
1651
- <media-controls-group class="vds-controls-group">
1652
- ${DefaultTimeSlider()}
1653
- </media-controls-group>
1654
- `,
1655
- html`
1656
- <media-controls-group class="vds-controls-group vds-controls-group-bottom">
1657
- ${[
1658
- DefaultSeekButton({ backward: true, tooltip: "top" }),
1659
- DefaultPlayButton({ tooltip: "top start" }),
1660
- DefaultSeekButton({ backward: false, tooltip: "top" }),
1661
- DefaultVolumePopup({ orientation: "horizontal", tooltip: "top" }),
1662
- DefaultTimeInfo(),
1663
- DefaultTitle(),
1664
- DefaultControlsSpacer(),
1665
- $signal(
1666
- () => (fullscreen() || smWhen()) && episodes()?.length ? DefaultEpisodeButton({ tooltip: "top" }) : null
1667
- ),
1668
- DefaultCaptionButton({ tooltip: "top" }),
1669
- DefaultBottomMenuGroup(),
1670
- DefaultDownloadButton(),
1671
- DefaultPIPButton(),
1672
- DefaultFullscreenButton({ tooltip: "top end" })
1673
- ]}
1674
- </media-controls-group>
1675
- `
1676
- ]}
1677
- </media-controls>
1678
- `,
1679
- DefaultEpisodesSidebar($episodesOpen, onEpisodesClose)
1680
- ];
1681
- }
1682
- function DefaultBottomMenuGroup() {
1683
- return $signal(() => {
1684
- const { menuGroup } = useDefaultLayoutContext();
1685
- return menuGroup() === "bottom" ? DefaultVideoMenus() : null;
1686
- });
1687
- }
1688
- function DefaultControlsGroupTop() {
1689
- return html`
1690
- <media-controls-group class="vds-controls-group">
1691
- ${$signal(() => {
1692
- const { menuGroup } = useDefaultLayoutContext();
1693
- return menuGroup() === "top" ? [DefaultControlsSpacer(), DefaultVideoMenus()] : null;
1694
- })}
1695
- </media-controls-group>
1696
- `;
1697
- }
1698
- function DefaultVideoLayoutSmall() {
1699
- const { episodes, smallWhen: smWhen } = useDefaultLayoutContext(), { fullscreen } = useMediaState(), $episodesOpen = signal(false);
1700
- effect(() => {
1701
- if (!fullscreen()) $episodesOpen.set(false);
1702
- });
1703
- function onEpisodesToggle() {
1704
- if (!fullscreen() && !smWhen() || !episodes()?.length) return;
1705
- $episodesOpen.set(!$episodesOpen());
1706
- }
1707
- function onEpisodesClose() {
1708
- $episodesOpen.set(false);
1709
- }
1710
- return [
1711
- DefaultAnnouncer(),
1712
- DefaultVideoGestures(),
1713
- DefaultBufferingIndicator(),
1714
- DefaultCaptions(),
1715
- DefaultKeyboardDisplay(),
1716
- html`<div class="vds-scrim"></div>`,
1717
- html`
1718
- <media-controls class="vds-controls" @vds-episodes-open=${onEpisodesToggle}>
1719
- <media-controls-group class="vds-controls-group">
1720
- ${[
1721
- DefaultControlsSpacer(),
1722
- DefaultCaptionButton({ tooltip: "bottom" }),
1723
- DefaultDownloadButton(),
1724
- DefaultVideoMenus(),
1725
- DefaultVolumePopup({ orientation: "vertical", tooltip: "bottom end" })
1726
- ]}
1727
- </media-controls-group>
1728
-
1729
- ${DefaultControlsSpacer()}
1730
-
1731
- <media-controls-group class="vds-controls-group">
1732
- ${DefaultTimeSlider()}
1733
- </media-controls-group>
1734
-
1735
- <media-controls-group class="vds-controls-group vds-controls-group-bottom">
1736
- ${[
1737
- DefaultSeekButton({ backward: true, tooltip: "top" }),
1738
- DefaultPlayButton({ tooltip: "top" }),
1739
- DefaultSeekButton({ backward: false, tooltip: "top" }),
1740
- DefaultTimeInfo(),
1741
- DefaultControlsSpacer(),
1742
- $signal(
1743
- () => (fullscreen() || smWhen()) && episodes()?.length ? DefaultEpisodeButton({ tooltip: "top" }) : null
1744
- ),
1745
- DefaultFullscreenButton({ tooltip: "top end" })
1746
- ]}
1747
- </media-controls-group>
1748
- </media-controls>
1749
- `,
1750
- StartDuration(),
1751
- DefaultEpisodesSidebar($episodesOpen, onEpisodesClose)
1752
- ];
1753
- }
1754
- function DefaultVideoLoadLayout() {
1755
- return html`
1756
- <div class="vds-load-container">
1757
- ${[DefaultBufferingIndicator(), DefaultPlayButton({ tooltip: "top" })]}
1758
- </div>
1759
- `;
1760
- }
1761
- function StartDuration() {
1762
- return $signal(() => {
1763
- const { duration } = useMediaState();
1764
- if (duration() === 0) return null;
1765
- return html`
1766
- <div class="vds-start-duration">
1767
- <media-time class="vds-time" type="duration"></media-time>
1768
- </div>
1769
- `;
1770
- });
1771
- }
1772
- function DefaultBufferingIndicator() {
1773
- return html`
1774
- <div class="vds-buffering-indicator">
1775
- <media-spinner class="vds-buffering-spinner"></media-spinner>
1776
- </div>
1777
- `;
1778
- }
1779
- function formatMinutesLeftLabel(secondsLeft) {
1780
- if (secondsLeft <= 0) return null;
1781
- if (secondsLeft < 60) return "<1m left";
1782
- return `${Math.floor(secondsLeft / 60)}m left`;
1783
- }
1784
- function DefaultEpisodesSidebar($open, onClose) {
1785
- const { episodes, episodesTitle, smallWhen: smWhen } = useDefaultLayoutContext(), { fullscreen, currentTime, duration } = useMediaState();
1786
- return $signal(() => {
1787
- const list = episodes() ?? [];
1788
- if (!fullscreen() && !smWhen() || !list.length) return null;
1789
- const ct = currentTime(), dur = duration();
1790
- return html`
1791
- <div
1792
- class="vds-episodes-backdrop"
1793
- data-open=${$open() ? "true" : "false"}
1794
- @pointerup=${(event) => {
1795
- if (event.target === event.currentTarget) onClose();
1796
- }}
1797
- >
1798
- <aside
1799
- class="vds-episodes-panel"
1800
- data-open=${$open() ? "true" : "false"}
1801
- @keydown=${(event) => {
1802
- if (event.key === "Escape") onClose();
1803
- }}
1804
- >
1805
- <header class="vds-episodes-panel-header">
1806
- <h3 class="vds-episodes-panel-title">${episodesTitle()}</h3>
1807
- <button
1808
- type="button"
1809
- class="vds-episodes-close-btn"
1810
- aria-label="Close episodes"
1811
- @pointerup=${(event) => {
1812
- event.stopPropagation();
1813
- onClose();
1814
- }}
1815
- >
1816
- <span aria-hidden="true">✕</span>
1817
- </button>
1818
- </header>
1819
- <div class="vds-episodes-list" role="list">
1820
- ${list.map((episode, index) => {
1821
- const episodeName = episode.episodeTitle || `Episode ${episode.episodeNumber ?? index + 1}`, seasonEpLabel = episode.seasonNumber != null && episode.episodeNumber != null ? `S${String(episode.seasonNumber).padStart(2, "0")} \xB7 E${String(
1822
- episode.episodeNumber
1823
- ).padStart(2, "0")}` : episodeName, isActive = episode.isActive === true;
1824
- let runtimeText = null;
1825
- if (isActive && dur > 0) {
1826
- const secsLeft = Math.max(0, dur - ct);
1827
- runtimeText = formatMinutesLeftLabel(secsLeft);
1828
- } else if (episode.timeLeft != null && episode.timeLeft > 0) {
1829
- runtimeText = `${episode.timeLeft}m left`;
1830
- } else if (Number.isFinite(episode.runtime) && (episode.runtime ?? 0) > 0) {
1831
- runtimeText = `${episode.runtime}m`;
1832
- }
1833
- let progressPct = 0;
1834
- if (isActive && dur > 0) {
1835
- progressPct = Math.min(100, ct / dur * 100);
1836
- } else if (episode.progressPercent != null && episode.progressPercent > 0) {
1837
- progressPct = Math.min(100, episode.progressPercent);
1838
- }
1839
- const showSubtitle = !!episode.episodeTitle && episode.episodeTitle.trim() !== "" && episode.episodeTitle !== episode.title;
1840
- const onEpisodeSelect = (event) => {
1841
- event.stopPropagation();
1842
- if (isActive) return;
1843
- event.currentTarget?.dispatchEvent(
1844
- new CustomEvent("vds-episode-select", {
1845
- bubbles: true,
1846
- composed: true,
1847
- detail: { episode, index }
1848
- })
1849
- );
1850
- onClose();
1851
- };
1852
- return html`
1853
- <article
1854
- class="vds-episode-item"
1855
- data-active=${isActive ? "true" : "false"}
1856
- aria-current=${isActive ? "true" : void 0}
1857
- role="button"
1858
- tabindex="0"
1859
- aria-label=${episode.title || episodeName}
1860
- @pointerup=${onEpisodeSelect}
1861
- @keydown=${(event) => {
1862
- if (event.key === "Enter" || event.key === " ") onEpisodeSelect(event);
1863
- }}
1864
- >
1865
- <div class="vds-episode-thumb-wrap">
1866
- ${episode.thumbnail ? html`
1867
- <img
1868
- class="vds-episode-thumb"
1869
- src=${episode.thumbnail}
1870
- alt=${episode.title || episodeName}
1871
- loading="lazy"
1872
- decoding="async"
1873
- />
1874
- ` : html`<div class="vds-episode-thumb vds-episode-thumb-placeholder"></div>`}
1875
- ${isActive ? html`
1876
- <div class="vds-episode-active-overlay" aria-hidden="true">
1877
- <span class="vds-episode-playing-badge">Now playing</span>
1878
- </div>
1879
- ` : null}
1880
- ${progressPct > 0 ? html`
1881
- <div class="vds-episode-progress-track" aria-hidden="true">
1882
- <div
1883
- class="vds-episode-progress-fill"
1884
- style=${`width: ${progressPct}%;`}
1885
- ></div>
1886
- </div>
1887
- ` : null}
1888
- </div>
1889
- <div class="vds-episode-body">
1890
- <div class="vds-episode-meta-row">
1891
- <span class="vds-episode-label">${seasonEpLabel}</span>
1892
- ${runtimeText ? html`<span class="vds-episode-runtime">${runtimeText}</span>` : null}
1893
- </div>
1894
- <h4 class="vds-episode-title" title=${episode.title || ""}>
1895
- ${episode.title || "-"}
1896
- </h4>
1897
- ${showSubtitle ? html`<p class="vds-episode-subtitle" title=${episode.episodeTitle}>
1898
- ${episode.episodeTitle}
1899
- </p>` : null}
1900
- ${episode.overview ? html`<p class="vds-episode-desc" title=${episode.overview}>
1901
- ${episode.overview}
1902
- </p>` : null}
1903
- </div>
1904
- </article>
1905
- `;
1906
- })}
1907
- </div>
1908
- </aside>
1909
- </div>
1910
- `;
1911
- });
1912
- }
1913
- function DefaultVideoMenus() {
1914
- const { menuGroup, smallWhen: smWhen } = useDefaultLayoutContext(), $side = () => menuGroup() === "top" || smWhen() ? "bottom" : "top", $tooltip = computed(() => `${$side()} ${menuGroup() === "top" ? "end" : "center"}`), $placement = computed(() => `${$side()} end`);
1915
- return [
1916
- DefaultChaptersMenu({ tooltip: $tooltip, placement: $placement, portal: true }),
1917
- DefaultSettingsMenu({ tooltip: $tooltip, placement: $placement, portal: true })
1918
- ];
1919
- }
1920
- function DefaultVideoGestures() {
1921
- return $signal(() => {
1922
- const { noGestures } = useDefaultLayoutContext();
1923
- if (noGestures()) return null;
1924
- return html`
1925
- <div class="vds-gestures">
1926
- <media-gesture class="vds-gesture" event="pointerup" action="toggle:paused"></media-gesture>
1927
- <media-gesture
1928
- class="vds-gesture"
1929
- event="pointerup"
1930
- action="toggle:controls"
1931
- ></media-gesture>
1932
- <media-gesture
1933
- class="vds-gesture"
1934
- event="dblpointerup"
1935
- action="toggle:fullscreen"
1936
- ></media-gesture>
1937
- <media-gesture class="vds-gesture" event="dblpointerup" action="seek:-10"></media-gesture>
1938
- <media-gesture class="vds-gesture" event="dblpointerup" action="seek:10"></media-gesture>
1939
- </div>
1940
- `;
1941
- });
1942
- }
1943
-
1944
- class MediaVideoLayoutElement extends Host(LitElement, DefaultVideoLayout) {
1945
- static tagName = "media-video-layout";
1946
- static attrs = {
1947
- smallWhen: {
1948
- converter(value) {
1949
- return value !== "never" && !!value;
1950
- }
1951
- },
1952
- episodes: {
1953
- converter(value) {
1954
- if (!value) return null;
1955
- try {
1956
- const parsed = JSON.parse(value);
1957
- return Array.isArray(parsed) ? parsed : null;
1958
- } catch {
1959
- return null;
1960
- }
1961
- }
1962
- }
1963
- };
1964
- #media;
1965
- onSetup() {
1966
- this.forwardKeepAlive = false;
1967
- this.#media = useMediaContext();
1968
- this.classList.add("vds-video-layout");
1969
- }
1970
- onConnect() {
1971
- setLayoutName("video", () => this.isMatch);
1972
- this.#setupMenuContainer();
1973
- }
1974
- render() {
1975
- return $signal(this.#render.bind(this));
1976
- }
1977
- #setupMenuContainer() {
1978
- const { menuPortal } = useDefaultLayoutContext();
1979
- effect(() => {
1980
- if (!this.isMatch) return;
1981
- const container = createMenuContainer(
1982
- this,
1983
- this.menuContainer,
1984
- "vds-video-layout",
1985
- () => this.isSmallLayout
1986
- ), roots = container ? [this, container] : [this];
1987
- const iconsManager = this.$props.customIcons() ? new SlotManager(roots) : new DefaultLayoutIconsLoader(roots);
1988
- iconsManager.connect();
1989
- menuPortal.set(container);
1990
- return () => {
1991
- container.remove();
1992
- menuPortal.set(null);
1993
- };
1994
- });
1995
- }
1996
- #render() {
1997
- const { load } = this.#media.$props, { canLoad, streamType, nativeControls } = this.#media.$state;
1998
- return !nativeControls() && this.isMatch ? load() === "play" && !canLoad() ? DefaultVideoLoadLayout() : streamType() === "unknown" ? DefaultBufferingIndicator() : this.isSmallLayout ? DefaultVideoLayoutSmall() : DefaultVideoLayoutLarge() : null;
1999
- }
2000
- }
2001
-
2002
- export { MediaAudioLayoutElement, MediaVideoLayoutElement };