@hanifhan1f/vidstack 1.12.25 → 1.12.27

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 (92) hide show
  1. package/cdn/chunks/vidstack-8JHLDxl5.js +1 -0
  2. package/cdn/chunks/vidstack-Bpnl-N6k.js +1 -0
  3. package/cdn/chunks/vidstack-CnWKPIKT.js +16 -0
  4. package/cdn/chunks/vidstack-CqzAnF2W.js +16 -0
  5. package/cdn/vidstack.js +1 -1
  6. package/cdn/with-layouts/chunks/vidstack-BD5YoTt5.js +937 -0
  7. package/cdn/with-layouts/chunks/vidstack-DCaNJN4T.js +1 -0
  8. package/cdn/with-layouts/chunks/vidstack-Dd3L-eQj.js +1 -0
  9. package/cdn/with-layouts/chunks/vidstack-T2rZVigk.js +912 -0
  10. package/cdn/with-layouts/vidstack.js +1 -1
  11. package/dev/chunks/vidstack--aukHYxl.js +1520 -0
  12. package/dev/chunks/vidstack-B__DfQsT.js +1621 -0
  13. package/dev/chunks/vidstack-BoLIUOyq.js +204 -0
  14. package/dev/chunks/vidstack-CSryZFvY.js +1521 -0
  15. package/dev/chunks/vidstack-Cky9ors4.js +297 -0
  16. package/dev/chunks/vidstack-Crz0ROkT.js +3009 -0
  17. package/dev/chunks/vidstack-D-sqb6YI.js +308 -0
  18. package/dev/chunks/vidstack-DLXCqdYV.js +3010 -0
  19. package/dev/chunks/vidstack-DS7nRfge.js +204 -0
  20. package/dev/chunks/vidstack-Dco6kA4h.js +104 -0
  21. package/dev/chunks/vidstack-DpS0Kt4b.js +297 -0
  22. package/dev/chunks/vidstack-zJT-7ncH.js +5182 -0
  23. package/dev/define/plyr-layout.js +3 -4
  24. package/dev/define/templates/vidstack-audio-layout.js +4 -4
  25. package/dev/define/templates/vidstack-video-layout.js +4 -4
  26. package/dev/define/vidstack-player-default-layout.js +4 -4
  27. package/dev/define/vidstack-player-layouts.js +4 -4
  28. package/dev/define/vidstack-player-ui.js +5 -6
  29. package/dev/define/vidstack-player.js +3 -4
  30. package/dev/global/plyr.js +5 -6
  31. package/dev/global/vidstack-player.js +3 -4
  32. package/dev/providers/vidstack-dash.js +1 -2
  33. package/dev/providers/vidstack-hls.js +1 -2
  34. package/dev/providers/vidstack-video.js +1 -2
  35. package/dev/providers/vidstack-vimeo.js +1 -2
  36. package/dev/vidstack-elements.js +8 -9
  37. package/dev/vidstack.js +6 -7
  38. package/package.json +2 -1
  39. package/prod/chunks/vidstack-BVSJtdRd.js +297 -0
  40. package/prod/chunks/vidstack-BnEo_Sla.js +1621 -0
  41. package/prod/chunks/vidstack-CFXAYpuh.js +1521 -0
  42. package/prod/chunks/vidstack-CIvL96_j.js +297 -0
  43. package/prod/chunks/vidstack-CLTPjjXX.js +4772 -0
  44. package/prod/chunks/vidstack-CSHHV2zO.js +201 -0
  45. package/prod/chunks/vidstack-CYVCrFjx.js +201 -0
  46. package/prod/chunks/vidstack-D_atbNqH.js +3000 -0
  47. package/prod/chunks/vidstack-Eo46ZHu7.js +2999 -0
  48. package/prod/chunks/vidstack-sP7TQMB1.js +300 -0
  49. package/prod/chunks/vidstack-uVm3xX8H.js +104 -0
  50. package/prod/chunks/vidstack-zknLxihl.js +1520 -0
  51. package/prod/define/plyr-layout.js +3 -4
  52. package/prod/define/templates/vidstack-audio-layout.js +4 -4
  53. package/prod/define/templates/vidstack-video-layout.js +4 -4
  54. package/prod/define/vidstack-player-default-layout.js +4 -4
  55. package/prod/define/vidstack-player-layouts.js +4 -4
  56. package/prod/define/vidstack-player-ui.js +5 -6
  57. package/prod/define/vidstack-player.js +3 -4
  58. package/prod/global/plyr.js +5 -6
  59. package/prod/global/vidstack-player.js +3 -4
  60. package/prod/providers/vidstack-dash.js +1 -2
  61. package/prod/providers/vidstack-hls.js +1 -2
  62. package/prod/providers/vidstack-video.js +1 -2
  63. package/prod/providers/vidstack-vimeo.js +1 -2
  64. package/prod/vidstack-elements.js +8 -9
  65. package/prod/vidstack.js +6 -7
  66. package/server/chunks/vidstack-B3eA67nX.js +205 -0
  67. package/server/chunks/vidstack-B8P1aUCK.js +1503 -0
  68. package/server/chunks/vidstack-B8_v1VQn.js +3059 -0
  69. package/server/chunks/vidstack-BK4xGWUK.js +207 -0
  70. package/server/chunks/vidstack-BO8FLks6.js +295 -0
  71. package/server/chunks/vidstack-BaXvZgx2.js +141 -0
  72. package/server/chunks/vidstack-BlvJg_5A.js +4636 -0
  73. package/server/chunks/vidstack-CBhikwSz.js +67 -0
  74. package/server/chunks/vidstack-COczNXom.js +3059 -0
  75. package/server/chunks/vidstack-CyZPtpwO.js +1503 -0
  76. package/server/chunks/vidstack-Db22EuE_.js +207 -0
  77. package/server/chunks/vidstack-Dh1ZDEI-.js +29 -0
  78. package/server/chunks/vidstack-Dm-ETAZh.js +295 -0
  79. package/server/chunks/vidstack-NpAD9hfP.js +620 -0
  80. package/server/chunks/vidstack-O4BgIcQI.js +104 -0
  81. package/server/chunks/vidstack-n4zAyLEV.js +2139 -0
  82. package/server/chunks/vidstack-za5Yh5DQ.js +566 -0
  83. package/server/chunks/vidstack-zoXyfYxa.js +107 -0
  84. package/server/define/plyr-layout.js +7 -7
  85. package/server/define/vidstack-player-default-layout.js +3 -3
  86. package/server/define/vidstack-player-layouts.js +5 -5
  87. package/server/define/vidstack-player-ui.js +6 -6
  88. package/server/define/vidstack-player.js +4 -4
  89. package/server/global/plyr.js +9 -9
  90. package/server/global/vidstack-player.js +4 -4
  91. package/server/vidstack-elements.js +13 -13
  92. package/server/vidstack.js +8 -8
@@ -0,0 +1,1621 @@
1
+ import { createContext, useContext, prop, Component, computed, provideContext, signal, isBoolean, effect, setAttribute, uppercaseFirstChar, isNil, isString, noop, isFunction, unwrap, camelToKebabCase, onDispose, scoped, keysOf, isArray, tick, peek, isKeyboardClick } from './vidstack-BNpgCJJ1.js';
2
+ import { useMediaContext, useMediaState } from './vidstack-tt3O1zL6.js';
3
+ import { watchColorScheme, $ariaBool, useResizeObserver, useActive } from './vidstack-DB9WDRL5.js';
4
+ import { html } from 'lit-html';
5
+ import { $signal, LayoutIconsLoader, Icon } from './vidstack-zfCm-GM5.js';
6
+ import { watchActiveTextTrack, isTrackCaptionKind } from './vidstack-sP7TQMB1.js';
7
+ import { sortVideoQualities } from './vidstack-BTM4ERc7.js';
8
+ import { ifDefined } from 'lit-html/directives/if-defined.js';
9
+ import { ref } from 'lit-html/directives/ref.js';
10
+ import { getDownloadFile, appendParamsToURL } from './vidstack-KShKSmYu.js';
11
+
12
+ const defaultLayoutContext = createContext();
13
+ function useDefaultLayoutContext() {
14
+ return useContext(defaultLayoutContext);
15
+ }
16
+
17
+ const defaultLayoutProps = {
18
+ colorScheme: "system",
19
+ download: null,
20
+ customIcons: false,
21
+ disableTimeSlider: false,
22
+ menuContainer: null,
23
+ menuGroup: "bottom",
24
+ noAudioGain: false,
25
+ noGestures: false,
26
+ noKeyboardAnimations: false,
27
+ noModal: false,
28
+ noScrubGesture: false,
29
+ playbackRates: { min: 0, max: 2, step: 0.25 },
30
+ audioGains: { min: 0, max: 300, step: 25 },
31
+ seekStep: 5,
32
+ sliderChaptersMinWidth: 325,
33
+ hideQualityBitrate: false,
34
+ episodes: null,
35
+ episodesTitle: "Episodes",
36
+ smallWhen: false,
37
+ thumbnails: null,
38
+ translations: null,
39
+ when: false
40
+ };
41
+
42
+ class DefaultLayout extends Component {
43
+ static props = defaultLayoutProps;
44
+ #media;
45
+ #when = computed(() => {
46
+ const when = this.$props.when();
47
+ return this.#matches(when);
48
+ });
49
+ #smallWhen = computed(() => {
50
+ const when = this.$props.smallWhen();
51
+ return this.#matches(when);
52
+ });
53
+ get isMatch() {
54
+ return this.#when();
55
+ }
56
+ get isSmallLayout() {
57
+ return this.#smallWhen();
58
+ }
59
+ onSetup() {
60
+ this.#media = useMediaContext();
61
+ this.setAttributes({
62
+ "data-match": this.#when,
63
+ "data-sm": () => this.#smallWhen() ? "" : null,
64
+ "data-lg": () => !this.#smallWhen() ? "" : null,
65
+ "data-size": () => this.#smallWhen() ? "sm" : "lg",
66
+ "data-no-scrub-gesture": this.$props.noScrubGesture
67
+ });
68
+ provideContext(defaultLayoutContext, {
69
+ ...this.$props,
70
+ when: this.#when,
71
+ smallWhen: this.#smallWhen,
72
+ userPrefersAnnouncements: signal(true),
73
+ userPrefersKeyboardAnimations: signal(true),
74
+ menuPortal: signal(null)
75
+ });
76
+ }
77
+ onAttach(el) {
78
+ watchColorScheme(el, this.$props.colorScheme);
79
+ }
80
+ #matches(query) {
81
+ return query !== "never" && (isBoolean(query) ? query : computed(() => query(this.#media.player.state))());
82
+ }
83
+ }
84
+ const defaultlayout__proto = DefaultLayout.prototype;
85
+ prop(defaultlayout__proto, "isMatch");
86
+ prop(defaultlayout__proto, "isSmallLayout");
87
+
88
+ function setLayoutName(name, isMatch) {
89
+ effect(() => {
90
+ const { player } = useMediaContext(), el = player.el;
91
+ el && setAttribute(el, "data-layout", isMatch() && name);
92
+ return () => el?.removeAttribute("data-layout");
93
+ });
94
+ }
95
+
96
+ function i18n(translations, word) {
97
+ return translations()?.[word] ?? word;
98
+ }
99
+
100
+ function DefaultAnnouncer() {
101
+ return $signal(() => {
102
+ const { translations, userPrefersAnnouncements } = useDefaultLayoutContext();
103
+ if (!userPrefersAnnouncements()) return null;
104
+ return html`<media-announcer .translations=${$signal(translations)}></media-announcer>`;
105
+ });
106
+ }
107
+
108
+ function IconSlot(name, classes = "") {
109
+ return html`<slot
110
+ name=${`${name}-icon`}
111
+ data-class=${`vds-icon vds-${name}-icon${classes ? ` ${classes}` : ""}`}
112
+ ></slot>`;
113
+ }
114
+ function IconSlots(names) {
115
+ return names.map((name) => IconSlot(name));
116
+ }
117
+
118
+ function $i18n(translations, word) {
119
+ return $signal(() => i18n(translations, word));
120
+ }
121
+
122
+ function DefaultAirPlayButton({ tooltip }) {
123
+ const { translations } = useDefaultLayoutContext(), { remotePlaybackState } = useMediaState(), $label = $signal(() => {
124
+ const airPlayText = i18n(translations, "AirPlay"), stateText = uppercaseFirstChar(remotePlaybackState());
125
+ return `${airPlayText} ${stateText}`;
126
+ }), $airPlayText = $i18n(translations, "AirPlay");
127
+ return html`
128
+ <media-tooltip class="vds-airplay-tooltip vds-tooltip">
129
+ <media-tooltip-trigger>
130
+ <media-airplay-button class="vds-airplay-button vds-button" aria-label=${$label}>
131
+ ${IconSlot("airplay")}
132
+ </media-airplay-button>
133
+ </media-tooltip-trigger>
134
+ <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
135
+ <span class="vds-airplay-tooltip-text">${$airPlayText}</span>
136
+ </media-tooltip-content>
137
+ </media-tooltip>
138
+ `;
139
+ }
140
+ function DefaultPlayButton({ tooltip }) {
141
+ const { translations } = useDefaultLayoutContext(), $playText = $i18n(translations, "Play"), $pauseText = $i18n(translations, "Pause");
142
+ return html`
143
+ <media-tooltip class="vds-play-tooltip vds-tooltip">
144
+ <media-tooltip-trigger>
145
+ <media-play-button
146
+ class="vds-play-button vds-button"
147
+ aria-label=${$i18n(translations, "Play")}
148
+ >
149
+ ${IconSlots(["play", "pause", "replay"])}
150
+ </media-play-button>
151
+ </media-tooltip-trigger>
152
+ <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
153
+ <span class="vds-play-tooltip-text">${$playText}</span>
154
+ <span class="vds-pause-tooltip-text">${$pauseText}</span>
155
+ </media-tooltip-content>
156
+ </media-tooltip>
157
+ `;
158
+ }
159
+ function DefaultMuteButton({
160
+ tooltip,
161
+ ref: ref$1 = noop
162
+ }) {
163
+ const { translations } = useDefaultLayoutContext(), $muteText = $i18n(translations, "Mute"), $unmuteText = $i18n(translations, "Unmute");
164
+ return html`
165
+ <media-tooltip class="vds-mute-tooltip vds-tooltip">
166
+ <media-tooltip-trigger>
167
+ <media-mute-button
168
+ class="vds-mute-button vds-button"
169
+ aria-label=${$i18n(translations, "Mute")}
170
+ ${ref(ref$1)}
171
+ >
172
+ ${IconSlots(["mute", "volume-low", "volume-high"])}
173
+ </media-mute-button>
174
+ </media-tooltip-trigger>
175
+ <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
176
+ <span class="vds-mute-tooltip-text">${$unmuteText}</span>
177
+ <span class="vds-unmute-tooltip-text">${$muteText}</span>
178
+ </media-tooltip-content>
179
+ </media-tooltip>
180
+ `;
181
+ }
182
+ function DefaultCaptionButton({ tooltip }) {
183
+ const { translations } = useDefaultLayoutContext(), $ccOnText = $i18n(translations, "Closed-Captions On"), $ccOffText = $i18n(translations, "Closed-Captions Off");
184
+ return html`
185
+ <media-tooltip class="vds-caption-tooltip vds-tooltip">
186
+ <media-tooltip-trigger>
187
+ <media-caption-button
188
+ class="vds-caption-button vds-button"
189
+ aria-label=${$i18n(translations, "Captions")}
190
+ >
191
+ ${IconSlots(["cc-on", "cc-off"])}
192
+ </media-caption-button>
193
+ </media-tooltip-trigger>
194
+ <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
195
+ <span class="vds-cc-on-tooltip-text">${$ccOffText}</span>
196
+ <span class="vds-cc-off-tooltip-text">${$ccOnText}</span>
197
+ </media-tooltip-content>
198
+ </media-tooltip>
199
+ `;
200
+ }
201
+ function DefaultPIPButton() {
202
+ const { translations } = useDefaultLayoutContext(), $enterText = $i18n(translations, "Enter PiP"), $exitText = $i18n(translations, "Exit PiP");
203
+ return html`
204
+ <media-tooltip class="vds-pip-tooltip vds-tooltip">
205
+ <media-tooltip-trigger>
206
+ <media-pip-button
207
+ class="vds-pip-button vds-button"
208
+ aria-label=${$i18n(translations, "PiP")}
209
+ >
210
+ ${IconSlots(["pip-enter", "pip-exit"])}
211
+ </media-pip-button>
212
+ </media-tooltip-trigger>
213
+ <media-tooltip-content class="vds-tooltip-content">
214
+ <span class="vds-pip-enter-tooltip-text">${$enterText}</span>
215
+ <span class="vds-pip-exit-tooltip-text">${$exitText}</span>
216
+ </media-tooltip-content>
217
+ </media-tooltip>
218
+ `;
219
+ }
220
+ function DefaultFullscreenButton({ tooltip }) {
221
+ const { translations } = useDefaultLayoutContext(), $enterText = $i18n(translations, "Enter Fullscreen"), $exitText = $i18n(translations, "Exit Fullscreen");
222
+ return html`
223
+ <media-tooltip class="vds-fullscreen-tooltip vds-tooltip">
224
+ <media-tooltip-trigger>
225
+ <media-fullscreen-button
226
+ class="vds-fullscreen-button vds-button"
227
+ aria-label=${$i18n(translations, "Fullscreen")}
228
+ >
229
+ ${IconSlots(["fs-enter", "fs-exit"])}
230
+ </media-fullscreen-button>
231
+ </media-tooltip-trigger>
232
+ <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
233
+ <span class="vds-fs-enter-tooltip-text">${$enterText}</span>
234
+ <span class="vds-fs-exit-tooltip-text">${$exitText}</span>
235
+ </media-tooltip-content>
236
+ </media-tooltip>
237
+ `;
238
+ }
239
+ function DefaultSeekButton({
240
+ backward,
241
+ tooltip
242
+ }) {
243
+ const { translations, seekStep } = useDefaultLayoutContext(), seekText = !backward ? "Seek Forward" : "Seek Backward", $label = $i18n(translations, seekText), $seconds = () => (backward ? -1 : 1) * seekStep();
244
+ return html`
245
+ <media-tooltip class="vds-seek-tooltip vds-tooltip">
246
+ <media-tooltip-trigger>
247
+ <media-seek-button
248
+ class="vds-seek-button vds-button"
249
+ seconds=${$signal($seconds)}
250
+ aria-label=${$label}
251
+ >
252
+ ${!backward ? IconSlot("seek-forward") : IconSlot("seek-backward")}
253
+ </media-seek-button>
254
+ </media-tooltip-trigger>
255
+ <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
256
+ ${$i18n(translations, seekText)}
257
+ </media-tooltip-content>
258
+ </media-tooltip>
259
+ `;
260
+ }
261
+ function DefaultLiveButton() {
262
+ const { translations } = useDefaultLayoutContext(), { live } = useMediaState(), $label = $i18n(translations, "Skip To Live"), $liveText = $i18n(translations, "LIVE");
263
+ return live() ? html`
264
+ <media-live-button class="vds-live-button" aria-label=${$label}>
265
+ <span class="vds-live-button-text">${$liveText}</span>
266
+ </media-live-button>
267
+ ` : null;
268
+ }
269
+ function DefaultDownloadButton() {
270
+ return $signal(() => {
271
+ const { download, translations } = useDefaultLayoutContext(), $download = download();
272
+ if (isNil($download)) return null;
273
+ const { source, title } = useMediaState(), $src = source(), file = getDownloadFile({
274
+ title: title(),
275
+ src: $src,
276
+ download: $download
277
+ });
278
+ return isString(file?.url) ? html`
279
+ <media-tooltip class="vds-download-tooltip vds-tooltip">
280
+ <media-tooltip-trigger>
281
+ <a
282
+ role="button"
283
+ class="vds-download-button vds-button"
284
+ aria-label=${$i18n(translations, "Download")}
285
+ href=${appendParamsToURL(file.url, { download: file.name })}
286
+ download=${file.name}
287
+ target="_blank"
288
+ >
289
+ <slot name="download-icon" data-class="vds-icon" />
290
+ </a>
291
+ </media-tooltip-trigger>
292
+ <media-tooltip-content class="vds-tooltip-content" placement="top">
293
+ ${$i18n(translations, "Download")}
294
+ </media-tooltip-content>
295
+ </media-tooltip>
296
+ ` : null;
297
+ });
298
+ }
299
+ function DefaultEpisodeButton({ tooltip } = {}) {
300
+ const $label = "Episodes", $episodesText = "Episodes";
301
+ function openEpisodes(e) {
302
+ e.stopPropagation();
303
+ e.currentTarget?.dispatchEvent(
304
+ new CustomEvent("vds-episodes-open", { bubbles: true, composed: true })
305
+ );
306
+ }
307
+ const content = html`
308
+ <button
309
+ type="button"
310
+ class="vds-episode-button vds-button"
311
+ aria-label=${$label}
312
+ @pointerup=${openEpisodes}
313
+ >
314
+ ${IconSlot("menu-episodes")}
315
+ </button>
316
+ `;
317
+ if (!tooltip) return content;
318
+ return html`
319
+ <media-tooltip class="vds-episode-tooltip vds-tooltip">
320
+ <media-tooltip-trigger> ${content} </media-tooltip-trigger>
321
+ <media-tooltip-content class="vds-tooltip-content" placement=${tooltip}>
322
+ <span class="vds-episode-tooltip-text">${$episodesText}</span>
323
+ </media-tooltip-content>
324
+ </media-tooltip>
325
+ `;
326
+ }
327
+
328
+ function DefaultCaptions() {
329
+ const { translations } = useDefaultLayoutContext();
330
+ return html`
331
+ <media-captions
332
+ class="vds-captions"
333
+ .exampleText=${$i18n(translations, "Captions look like this")}
334
+ ></media-captions>
335
+ `;
336
+ }
337
+
338
+ function DefaultControlsSpacer() {
339
+ return html`<div class="vds-controls-spacer"></div>`;
340
+ }
341
+
342
+ function MenuPortal(container, template) {
343
+ return html`
344
+ <media-menu-portal .container=${$signal(container)} disabled="fullscreen">
345
+ ${template}
346
+ </media-menu-portal>
347
+ `;
348
+ }
349
+ function createMenuContainer(layoutEl, rootSelector, className, isSmallLayout) {
350
+ let root = isString(rootSelector) ? document.querySelector(rootSelector) : rootSelector;
351
+ if (!root) root = layoutEl?.closest("dialog");
352
+ if (!root) root = document.body;
353
+ const container = document.createElement("div");
354
+ container.style.display = "contents";
355
+ container.classList.add(className);
356
+ root.append(container);
357
+ effect(() => {
358
+ if (!container) return;
359
+ const { viewType } = useMediaState(), isSmall = isSmallLayout();
360
+ setAttribute(container, "data-view-type", viewType());
361
+ setAttribute(container, "data-sm", isSmall);
362
+ setAttribute(container, "data-lg", !isSmall);
363
+ setAttribute(container, "data-size", isSmall ? "sm" : "lg");
364
+ });
365
+ const { colorScheme } = useDefaultLayoutContext();
366
+ watchColorScheme(container, colorScheme);
367
+ return container;
368
+ }
369
+
370
+ function DefaultChaptersMenu({
371
+ placement,
372
+ tooltip,
373
+ portal
374
+ }) {
375
+ const { textTracks } = useMediaContext(), { viewType, seekableStart, seekableEnd } = useMediaState(), {
376
+ translations,
377
+ thumbnails,
378
+ menuPortal,
379
+ noModal,
380
+ menuGroup,
381
+ smallWhen: smWhen
382
+ } = useDefaultLayoutContext(), $disabled = computed(() => {
383
+ const $startTime = seekableStart(), $endTime = seekableEnd(), $track = signal(null);
384
+ watchActiveTextTrack(textTracks, "chapters", $track.set);
385
+ const cues = $track()?.cues.filter(
386
+ (cue) => cue.startTime <= $endTime && cue.endTime >= $startTime
387
+ );
388
+ return !cues?.length;
389
+ });
390
+ if ($disabled()) return null;
391
+ const $placement = computed(
392
+ () => noModal() ? unwrap(placement) : !smWhen() ? unwrap(placement) : null
393
+ ), $offset = computed(
394
+ () => !smWhen() && menuGroup() === "bottom" && viewType() === "video" ? 26 : 0
395
+ ), $isOpen = signal(false);
396
+ function onOpen() {
397
+ $isOpen.set(true);
398
+ }
399
+ function onClose() {
400
+ $isOpen.set(false);
401
+ }
402
+ const items = html`
403
+ <media-menu-items
404
+ class="vds-chapters-menu-items vds-menu-items"
405
+ placement=${$signal($placement)}
406
+ offset=${$signal($offset)}
407
+ >
408
+ ${$signal(() => {
409
+ if (!$isOpen()) return null;
410
+ return html`
411
+ <media-chapters-radio-group
412
+ class="vds-chapters-radio-group vds-radio-group"
413
+ .thumbnails=${$signal(thumbnails)}
414
+ >
415
+ <template>
416
+ <media-radio class="vds-chapter-radio vds-radio">
417
+ <media-thumbnail class="vds-thumbnail"></media-thumbnail>
418
+ <div class="vds-chapter-radio-content">
419
+ <span class="vds-chapter-radio-label" data-part="label"></span>
420
+ <span class="vds-chapter-radio-start-time" data-part="start-time"></span>
421
+ <span class="vds-chapter-radio-duration" data-part="duration"></span>
422
+ </div>
423
+ </media-radio>
424
+ </template>
425
+ </media-chapters-radio-group>
426
+ `;
427
+ })}
428
+ </media-menu-items>
429
+ `;
430
+ return html`
431
+ <media-menu class="vds-chapters-menu vds-menu" @open=${onOpen} @close=${onClose}>
432
+ <media-tooltip class="vds-tooltip">
433
+ <media-tooltip-trigger>
434
+ <media-menu-button
435
+ class="vds-menu-button vds-button"
436
+ aria-label=${$i18n(translations, "Chapters")}
437
+ >
438
+ ${IconSlot("menu-chapters")}
439
+ </media-menu-button>
440
+ </media-tooltip-trigger>
441
+ <media-tooltip-content
442
+ class="vds-tooltip-content"
443
+ placement=${isFunction(tooltip) ? $signal(tooltip) : tooltip}
444
+ >
445
+ ${$i18n(translations, "Chapters")}
446
+ </media-tooltip-content>
447
+ </media-tooltip>
448
+ ${MenuPortal(menuPortal, items) }
449
+ </media-menu>
450
+ `;
451
+ }
452
+
453
+ function hexToRgb(hex) {
454
+ const { style } = new Option();
455
+ style.color = hex;
456
+ return style.color.match(/\((.*?)\)/)[1].replace(/,/g, " ");
457
+ }
458
+
459
+ const FONT_COLOR_OPTION = {
460
+ type: "color"
461
+ };
462
+ const FONT_FAMILY_OPTION = {
463
+ type: "radio",
464
+ values: {
465
+ "Monospaced Serif": "mono-serif",
466
+ "Proportional Serif": "pro-serif",
467
+ "Monospaced Sans-Serif": "mono-sans",
468
+ "Proportional Sans-Serif": "pro-sans",
469
+ Casual: "casual",
470
+ Cursive: "cursive",
471
+ "Small Capitals": "capitals"
472
+ }
473
+ };
474
+ const FONT_SIZE_OPTION = {
475
+ type: "slider",
476
+ min: 0,
477
+ max: 400,
478
+ step: 25,
479
+ upIcon: null,
480
+ downIcon: null
481
+ };
482
+ const FONT_OPACITY_OPTION = {
483
+ type: "slider",
484
+ min: 0,
485
+ max: 100,
486
+ step: 5,
487
+ upIcon: null,
488
+ downIcon: null
489
+ };
490
+ const FONT_TEXT_SHADOW_OPTION = {
491
+ type: "radio",
492
+ values: ["None", "Drop Shadow", "Raised", "Depressed", "Outline"]
493
+ };
494
+ const FONT_DEFAULTS = {
495
+ fontFamily: "pro-sans",
496
+ fontSize: "100%",
497
+ textColor: "#ffffff",
498
+ textOpacity: "100%",
499
+ textShadow: "none",
500
+ textBg: "#000000",
501
+ textBgOpacity: "100%",
502
+ displayBg: "#000000",
503
+ displayBgOpacity: "0%"
504
+ };
505
+ const FONT_SIGNALS = Object.keys(FONT_DEFAULTS).reduce(
506
+ (prev, type) => ({
507
+ ...prev,
508
+ [type]: signal(FONT_DEFAULTS[type])
509
+ }),
510
+ {}
511
+ );
512
+ {
513
+ for (const type of Object.keys(FONT_SIGNALS)) {
514
+ const value = localStorage.getItem(`vds-player:${camelToKebabCase(type)}`);
515
+ if (isString(value)) FONT_SIGNALS[type].set(value);
516
+ }
517
+ }
518
+ function onFontReset() {
519
+ for (const type of Object.keys(FONT_SIGNALS)) {
520
+ const defaultValue = FONT_DEFAULTS[type];
521
+ FONT_SIGNALS[type].set(defaultValue);
522
+ }
523
+ }
524
+
525
+ let isWatchingVars = false, players = /* @__PURE__ */ new Set();
526
+ function updateFontCssVars() {
527
+ const { player } = useMediaContext();
528
+ players.add(player);
529
+ onDispose(() => players.delete(player));
530
+ if (!isWatchingVars) {
531
+ scoped(() => {
532
+ for (const type of keysOf(FONT_SIGNALS)) {
533
+ const $value = FONT_SIGNALS[type], defaultValue = FONT_DEFAULTS[type], varName = `--media-user-${camelToKebabCase(type)}`, storageKey = `vds-player:${camelToKebabCase(type)}`;
534
+ effect(() => {
535
+ const value = $value(), isDefaultVarValue = value === defaultValue, varValue = !isDefaultVarValue ? getCssVarValue(player, type, value) : null;
536
+ for (const player2 of players) {
537
+ player2.el?.style.setProperty(varName, varValue);
538
+ }
539
+ if (isDefaultVarValue) {
540
+ localStorage.removeItem(storageKey);
541
+ } else {
542
+ localStorage.setItem(storageKey, value);
543
+ }
544
+ });
545
+ }
546
+ }, null);
547
+ isWatchingVars = true;
548
+ }
549
+ }
550
+ function getCssVarValue(player, type, value) {
551
+ switch (type) {
552
+ case "fontFamily":
553
+ const fontVariant = value === "capitals" ? "small-caps" : "";
554
+ player.el?.style.setProperty("--media-user-font-variant", fontVariant);
555
+ return getFontFamilyCSSVarValue(value);
556
+ case "fontSize":
557
+ case "textOpacity":
558
+ case "textBgOpacity":
559
+ case "displayBgOpacity":
560
+ return percentToRatio(value);
561
+ case "textColor":
562
+ return `rgb(${hexToRgb(value)} / var(--media-user-text-opacity, 1))`;
563
+ case "textShadow":
564
+ return getTextShadowCssVarValue(value);
565
+ case "textBg":
566
+ return `rgb(${hexToRgb(value)} / var(--media-user-text-bg-opacity, 1))`;
567
+ case "displayBg":
568
+ return `rgb(${hexToRgb(value)} / var(--media-user-display-bg-opacity, 1))`;
569
+ }
570
+ }
571
+ function percentToRatio(value) {
572
+ return (parseInt(value) / 100).toString();
573
+ }
574
+ function getFontFamilyCSSVarValue(value) {
575
+ switch (value) {
576
+ case "mono-serif":
577
+ return '"Courier New", Courier, "Nimbus Mono L", "Cutive Mono", monospace';
578
+ case "mono-sans":
579
+ return '"Deja Vu Sans Mono", "Lucida Console", Monaco, Consolas, "PT Mono", monospace';
580
+ case "pro-sans":
581
+ return 'Roboto, "Arial Unicode Ms", Arial, Helvetica, Verdana, "PT Sans Caption", sans-serif';
582
+ case "casual":
583
+ return '"Comic Sans MS", Impact, Handlee, fantasy';
584
+ case "cursive":
585
+ return '"Monotype Corsiva", "URW Chancery L", "Apple Chancery", "Dancing Script", cursive';
586
+ case "capitals":
587
+ return '"Arial Unicode Ms", Arial, Helvetica, Verdana, "Marcellus SC", sans-serif + font-variant=small-caps';
588
+ default:
589
+ return '"Times New Roman", Times, Georgia, Cambria, "PT Serif Caption", serif';
590
+ }
591
+ }
592
+ function getTextShadowCssVarValue(value) {
593
+ switch (value) {
594
+ case "drop shadow":
595
+ return "rgb(34, 34, 34) 1.86389px 1.86389px 2.79583px, rgb(34, 34, 34) 1.86389px 1.86389px 3.72778px, rgb(34, 34, 34) 1.86389px 1.86389px 4.65972px";
596
+ case "raised":
597
+ return "rgb(34, 34, 34) 1px 1px, rgb(34, 34, 34) 2px 2px";
598
+ case "depressed":
599
+ return "rgb(204, 204, 204) 1px 1px, rgb(34, 34, 34) -1px -1px";
600
+ case "outline":
601
+ return "rgb(34, 34, 34) 0px 0px 1.86389px, rgb(34, 34, 34) 0px 0px 1.86389px, rgb(34, 34, 34) 0px 0px 1.86389px, rgb(34, 34, 34) 0px 0px 1.86389px, rgb(34, 34, 34) 0px 0px 1.86389px";
602
+ default:
603
+ return "";
604
+ }
605
+ }
606
+
607
+ let sectionId = 0;
608
+ function DefaultMenuSection({ label = "", value = "", children }) {
609
+ if (!label) {
610
+ return html`
611
+ <div class="vds-menu-section">
612
+ <div class="vds-menu-section-body">${children}</div>
613
+ </div>
614
+ `;
615
+ }
616
+ const id = `vds-menu-section-${++sectionId}`;
617
+ return html`
618
+ <section class="vds-menu-section" role="group" aria-labelledby=${id}>
619
+ <div class="vds-menu-section-title">
620
+ <header id=${id}>${label}</header>
621
+ ${value ? html`<div class="vds-menu-section-value">${value}</div>` : null}
622
+ </div>
623
+ <div class="vds-menu-section-body">${children}</div>
624
+ </section>
625
+ `;
626
+ }
627
+ function DefaultMenuItem({ label, children }) {
628
+ return html`
629
+ <div class="vds-menu-item">
630
+ <div class="vds-menu-item-label">${label}</div>
631
+ ${children}
632
+ </div>
633
+ `;
634
+ }
635
+ function DefaultMenuButton({
636
+ label,
637
+ icon,
638
+ hint
639
+ }) {
640
+ return html`
641
+ <media-menu-button class="vds-menu-item">
642
+ ${IconSlot("menu-arrow-left", "vds-menu-close-icon")}
643
+ ${icon ? IconSlot(icon, "vds-menu-item-icon") : null}
644
+ <span class="vds-menu-item-label">${$signal(label)}</span>
645
+ <span class="vds-menu-item-hint" data-part="hint">${hint ? $signal(hint) : null} </span>
646
+ ${IconSlot("menu-arrow-right", "vds-menu-open-icon")}
647
+ </media-menu-button>
648
+ `;
649
+ }
650
+ function DefaultRadioGroup({
651
+ value = null,
652
+ options,
653
+ hideLabel = false,
654
+ children = null,
655
+ onChange = null
656
+ }) {
657
+ function renderRadio(option) {
658
+ const { value: value2, label: content } = option;
659
+ return html`
660
+ <media-radio class="vds-radio" value=${value2}>
661
+ ${IconSlot("menu-radio-check")}
662
+ ${!hideLabel ? html`
663
+ <span class="vds-radio-label" data-part="label">
664
+ ${isString(content) ? content : $signal(content)}
665
+ </span>
666
+ ` : null}
667
+ ${isFunction(children) ? children(option) : children}
668
+ </media-radio>
669
+ `;
670
+ }
671
+ return html`
672
+ <media-radio-group
673
+ class="vds-radio-group"
674
+ value=${isString(value) ? value : value ? $signal(value) : ""}
675
+ @change=${onChange}
676
+ >
677
+ ${isArray(options) ? options.map(renderRadio) : $signal(() => options().map(renderRadio))}
678
+ </media-radio-group>
679
+ `;
680
+ }
681
+ function createRadioOptions(entries) {
682
+ return isArray(entries) ? entries.map((entry) => ({ label: entry, value: entry.toLowerCase() })) : Object.keys(entries).map((label) => ({ label, value: entries[label] }));
683
+ }
684
+
685
+ function DefaultSliderParts() {
686
+ return html`
687
+ <div class="vds-slider-track"></div>
688
+ <div class="vds-slider-track-fill vds-slider-track"></div>
689
+ <div class="vds-slider-thumb"></div>
690
+ `;
691
+ }
692
+ function DefaultSliderSteps() {
693
+ return html`
694
+ <media-slider-steps class="vds-slider-steps">
695
+ <template>
696
+ <div class="vds-slider-step"></div>
697
+ </template>
698
+ </media-slider-steps>
699
+ `;
700
+ }
701
+ function DefaultMenuSliderItem({
702
+ label = null,
703
+ value = null,
704
+ upIcon = "",
705
+ downIcon = "",
706
+ children,
707
+ isMin,
708
+ isMax
709
+ }) {
710
+ const hasTitle = label || value, content = [
711
+ downIcon ? IconSlot(downIcon, "down") : null,
712
+ children,
713
+ upIcon ? IconSlot(upIcon, "up") : null
714
+ ];
715
+ return html`
716
+ <div
717
+ class=${`vds-menu-item vds-menu-slider-item${hasTitle ? " group" : ""}`}
718
+ data-min=${$signal(() => isMin() ? "" : null)}
719
+ data-max=${$signal(() => isMax() ? "" : null)}
720
+ >
721
+ ${hasTitle ? html`
722
+ <div class="vds-menu-slider-title">
723
+ ${[
724
+ label ? html`<div>${label}</div>` : null,
725
+ value ? html`<div>${value}</div>` : null
726
+ ]}
727
+ </div>
728
+ <div class="vds-menu-slider-body">${content}</div>
729
+ ` : content}
730
+ </div>
731
+ `;
732
+ }
733
+
734
+ const FONT_SIZE_OPTION_WITH_ICONS = {
735
+ ...FONT_SIZE_OPTION,
736
+ upIcon: "menu-opacity-up",
737
+ downIcon: "menu-opacity-down"
738
+ };
739
+ const FONT_OPACITY_OPTION_WITH_ICONS = {
740
+ ...FONT_OPACITY_OPTION,
741
+ upIcon: "menu-opacity-up",
742
+ downIcon: "menu-opacity-down"
743
+ };
744
+ function DefaultFontMenu() {
745
+ return $signal(() => {
746
+ const { hasCaptions } = useMediaState(), { translations } = useDefaultLayoutContext();
747
+ if (!hasCaptions()) return null;
748
+ return html`
749
+ <media-menu class="vds-font-menu vds-menu">
750
+ ${DefaultMenuButton({
751
+ label: () => i18n(translations, "Caption Styles")
752
+ })}
753
+ <media-menu-items class="vds-menu-items">
754
+ ${[
755
+ DefaultMenuSection({
756
+ label: $i18n(translations, "Font"),
757
+ children: [DefaultFontFamilyMenu(), DefaultFontSizeSlider()]
758
+ }),
759
+ DefaultMenuSection({
760
+ label: $i18n(translations, "Text"),
761
+ children: [
762
+ DefaultTextColorInput(),
763
+ DefaultTextShadowMenu(),
764
+ DefaultTextOpacitySlider()
765
+ ]
766
+ }),
767
+ DefaultMenuSection({
768
+ label: $i18n(translations, "Text Background"),
769
+ children: [DefaultTextBgInput(), DefaultTextBgOpacitySlider()]
770
+ }),
771
+ DefaultMenuSection({
772
+ label: $i18n(translations, "Display Background"),
773
+ children: [DefaultDisplayBgInput(), DefaultDisplayOpacitySlider()]
774
+ }),
775
+ DefaultMenuSection({
776
+ children: [DefaultResetMenuItem()]
777
+ })
778
+ ]}
779
+ </media-menu-items>
780
+ </media-menu>
781
+ `;
782
+ });
783
+ }
784
+ function DefaultFontFamilyMenu() {
785
+ return DefaultFontSetting({
786
+ label: "Family",
787
+ option: FONT_FAMILY_OPTION,
788
+ type: "fontFamily"
789
+ });
790
+ }
791
+ function DefaultFontSizeSlider() {
792
+ return DefaultFontSetting({
793
+ label: "Size",
794
+ option: FONT_SIZE_OPTION_WITH_ICONS,
795
+ type: "fontSize"
796
+ });
797
+ }
798
+ function DefaultTextColorInput() {
799
+ return DefaultFontSetting({
800
+ label: "Color",
801
+ option: FONT_COLOR_OPTION,
802
+ type: "textColor"
803
+ });
804
+ }
805
+ function DefaultTextOpacitySlider() {
806
+ return DefaultFontSetting({
807
+ label: "Opacity",
808
+ option: FONT_OPACITY_OPTION_WITH_ICONS,
809
+ type: "textOpacity"
810
+ });
811
+ }
812
+ function DefaultTextShadowMenu() {
813
+ return DefaultFontSetting({
814
+ label: "Shadow",
815
+ option: FONT_TEXT_SHADOW_OPTION,
816
+ type: "textShadow"
817
+ });
818
+ }
819
+ function DefaultTextBgInput() {
820
+ return DefaultFontSetting({
821
+ label: "Color",
822
+ option: FONT_COLOR_OPTION,
823
+ type: "textBg"
824
+ });
825
+ }
826
+ function DefaultTextBgOpacitySlider() {
827
+ return DefaultFontSetting({
828
+ label: "Opacity",
829
+ option: FONT_OPACITY_OPTION_WITH_ICONS,
830
+ type: "textBgOpacity"
831
+ });
832
+ }
833
+ function DefaultDisplayBgInput() {
834
+ return DefaultFontSetting({
835
+ label: "Color",
836
+ option: FONT_COLOR_OPTION,
837
+ type: "displayBg"
838
+ });
839
+ }
840
+ function DefaultDisplayOpacitySlider() {
841
+ return DefaultFontSetting({
842
+ label: "Opacity",
843
+ option: FONT_OPACITY_OPTION_WITH_ICONS,
844
+ type: "displayBgOpacity"
845
+ });
846
+ }
847
+ function DefaultResetMenuItem() {
848
+ const { translations } = useDefaultLayoutContext(), $label = () => i18n(translations, "Reset");
849
+ return html`
850
+ <button class="vds-menu-item" role="menuitem" @click=${onFontReset}>
851
+ <span class="vds-menu-item-label">${$signal($label)}</span>
852
+ </button>
853
+ `;
854
+ }
855
+ function DefaultFontSetting({ label, option, type }) {
856
+ const { player } = useMediaContext(), { translations } = useDefaultLayoutContext(), $currentValue = FONT_SIGNALS[type], $label = () => i18n(translations, label);
857
+ function notify() {
858
+ tick();
859
+ player.dispatchEvent(new Event("vds-font-change"));
860
+ }
861
+ if (option.type === "color") {
862
+ let onColorChange2 = function(event) {
863
+ $currentValue.set(event.target.value);
864
+ notify();
865
+ };
866
+ return DefaultMenuItem({
867
+ label: $signal($label),
868
+ children: html`
869
+ <input
870
+ class="vds-color-picker"
871
+ type="color"
872
+ .value=${$signal($currentValue)}
873
+ @input=${onColorChange2}
874
+ />
875
+ `
876
+ });
877
+ }
878
+ if (option.type === "slider") {
879
+ let onSliderValueChange2 = function(event) {
880
+ $currentValue.set(event.detail + "%");
881
+ notify();
882
+ };
883
+ const { min, max, step, upIcon, downIcon } = option;
884
+ return DefaultMenuSliderItem({
885
+ label: $signal($label),
886
+ value: $signal($currentValue),
887
+ upIcon,
888
+ downIcon,
889
+ isMin: () => $currentValue() === min + "%",
890
+ isMax: () => $currentValue() === max + "%",
891
+ children: html`
892
+ <media-slider
893
+ class="vds-slider"
894
+ min=${min}
895
+ max=${max}
896
+ step=${step}
897
+ key-step=${step}
898
+ .value=${$signal(() => parseInt($currentValue()))}
899
+ aria-label=${$signal($label)}
900
+ @value-change=${onSliderValueChange2}
901
+ @drag-value-change=${onSliderValueChange2}
902
+ >
903
+ ${DefaultSliderParts()}${DefaultSliderSteps()}
904
+ </media-slider>
905
+ `
906
+ });
907
+ }
908
+ const radioOptions = createRadioOptions(option.values), $hint = () => {
909
+ const value = $currentValue(), label2 = radioOptions.find((radio) => radio.value === value)?.label || "";
910
+ return i18n(translations, isString(label2) ? label2 : label2());
911
+ };
912
+ return html`
913
+ <media-menu class=${`vds-${camelToKebabCase(type)}-menu vds-menu`}>
914
+ ${DefaultMenuButton({ label: $label, hint: $hint })}
915
+ <media-menu-items class="vds-menu-items">
916
+ ${DefaultRadioGroup({
917
+ value: $currentValue,
918
+ options: radioOptions,
919
+ onChange({ detail: value }) {
920
+ $currentValue.set(value);
921
+ notify();
922
+ }
923
+ })}
924
+ </media-menu-items>
925
+ </media-menu>
926
+ `;
927
+ }
928
+
929
+ function DefaultMenuCheckbox({
930
+ label,
931
+ checked,
932
+ defaultChecked = false,
933
+ storageKey,
934
+ onChange
935
+ }) {
936
+ const { translations } = useDefaultLayoutContext(), savedValue = storageKey ? localStorage.getItem(storageKey) : null, $checked = signal(!!(savedValue ?? defaultChecked)), $active = signal(false), $ariaChecked = $signal($ariaBool($checked)), $label = $i18n(translations, label);
937
+ if (storageKey) onChange(peek($checked));
938
+ if (checked) {
939
+ effect(() => void $checked.set(checked()));
940
+ }
941
+ function onPress(event) {
942
+ if (event?.button === 1) return;
943
+ $checked.set((checked2) => !checked2);
944
+ if (storageKey) localStorage.setItem(storageKey, $checked() ? "1" : "");
945
+ onChange($checked(), event);
946
+ $active.set(false);
947
+ }
948
+ function onKeyDown(event) {
949
+ if (isKeyboardClick(event)) onPress();
950
+ }
951
+ function onActive(event) {
952
+ if (event.button !== 0) return;
953
+ $active.set(true);
954
+ }
955
+ return html`
956
+ <div
957
+ class="vds-menu-checkbox"
958
+ role="menuitemcheckbox"
959
+ tabindex="0"
960
+ aria-label=${$label}
961
+ aria-checked=${$ariaChecked}
962
+ data-active=${$signal(() => $active() ? "" : null)}
963
+ @pointerup=${onPress}
964
+ @pointerdown=${onActive}
965
+ @keydown=${onKeyDown}
966
+ ></div>
967
+ `;
968
+ }
969
+
970
+ function DefaultAccessibilityMenu() {
971
+ return $signal(() => {
972
+ const { translations } = useDefaultLayoutContext();
973
+ return html`
974
+ <media-menu class="vds-accessibility-menu vds-menu">
975
+ ${DefaultMenuButton({
976
+ label: () => i18n(translations, "Accessibility"),
977
+ icon: "menu-accessibility"
978
+ })}
979
+ <media-menu-items class="vds-menu-items">
980
+ ${[
981
+ DefaultMenuSection({
982
+ children: [
983
+ DefaultAnnouncementsMenuCheckbox(),
984
+ DefaultKeyboardAnimationsMenuCheckbox()
985
+ ]
986
+ }),
987
+ DefaultMenuSection({
988
+ children: [DefaultFontMenu()]
989
+ })
990
+ ]}
991
+ </media-menu-items>
992
+ </media-menu>
993
+ `;
994
+ });
995
+ }
996
+ function DefaultAnnouncementsMenuCheckbox() {
997
+ const { userPrefersAnnouncements, translations } = useDefaultLayoutContext(), label = "Announcements";
998
+ return DefaultMenuItem({
999
+ label: $i18n(translations, label),
1000
+ children: DefaultMenuCheckbox({
1001
+ label,
1002
+ storageKey: "vds-player::announcements",
1003
+ onChange(checked) {
1004
+ userPrefersAnnouncements.set(checked);
1005
+ }
1006
+ })
1007
+ });
1008
+ }
1009
+ function DefaultKeyboardAnimationsMenuCheckbox() {
1010
+ return $signal(() => {
1011
+ const { translations, userPrefersKeyboardAnimations, noKeyboardAnimations } = useDefaultLayoutContext(), { viewType } = useMediaState(), $disabled = computed(() => viewType() !== "video" || noKeyboardAnimations());
1012
+ if ($disabled()) return null;
1013
+ const label = "Keyboard Animations";
1014
+ return DefaultMenuItem({
1015
+ label: $i18n(translations, label),
1016
+ children: DefaultMenuCheckbox({
1017
+ label,
1018
+ defaultChecked: true,
1019
+ storageKey: "vds-player::keyboard-animations",
1020
+ onChange(checked) {
1021
+ userPrefersKeyboardAnimations.set(checked);
1022
+ }
1023
+ })
1024
+ });
1025
+ });
1026
+ }
1027
+
1028
+ function DefaultAudioMenu() {
1029
+ return $signal(() => {
1030
+ const { noAudioGain, translations } = useDefaultLayoutContext(), { audioTracks, canSetAudioGain } = useMediaState(), $disabled = computed(() => {
1031
+ const hasGainSlider = canSetAudioGain() && !noAudioGain();
1032
+ return !hasGainSlider && audioTracks().length <= 1;
1033
+ });
1034
+ if ($disabled()) return null;
1035
+ return html`
1036
+ <media-menu class="vds-audio-menu vds-menu">
1037
+ ${DefaultMenuButton({
1038
+ label: () => i18n(translations, "Audio"),
1039
+ icon: "menu-audio"
1040
+ })}
1041
+ <media-menu-items class="vds-menu-items">
1042
+ ${[DefaultAudioTracksMenu(), DefaultAudioBoostSection()]}
1043
+ </media-menu-items>
1044
+ </media-menu>
1045
+ `;
1046
+ });
1047
+ }
1048
+ function DefaultAudioTracksMenu() {
1049
+ return $signal(() => {
1050
+ const { translations } = useDefaultLayoutContext(), { audioTracks } = useMediaState(), $defaultText = $i18n(translations, "Default"), $disabled = computed(() => audioTracks().length <= 1);
1051
+ if ($disabled()) return null;
1052
+ return DefaultMenuSection({
1053
+ children: html`
1054
+ <media-menu class="vds-audio-tracks-menu vds-menu">
1055
+ ${DefaultMenuButton({
1056
+ label: () => i18n(translations, "Track")
1057
+ })}
1058
+ <media-menu-items class="vds-menu-items">
1059
+ <media-audio-radio-group
1060
+ class="vds-audio-track-radio-group vds-radio-group"
1061
+ empty-label=${$defaultText}
1062
+ >
1063
+ <template>
1064
+ <media-radio class="vds-audio-track-radio vds-radio">
1065
+ <slot name="menu-radio-check-icon" data-class="vds-icon"></slot>
1066
+ <span class="vds-radio-label" data-part="label"></span>
1067
+ </media-radio>
1068
+ </template>
1069
+ </media-audio-radio-group>
1070
+ </media-menu-items>
1071
+ </media-menu>
1072
+ `
1073
+ });
1074
+ });
1075
+ }
1076
+ function DefaultAudioBoostSection() {
1077
+ return $signal(() => {
1078
+ const { noAudioGain, translations } = useDefaultLayoutContext(), { canSetAudioGain } = useMediaState(), $disabled = computed(() => !canSetAudioGain() || noAudioGain());
1079
+ if ($disabled()) return null;
1080
+ const { audioGain } = useMediaState();
1081
+ return DefaultMenuSection({
1082
+ label: $i18n(translations, "Boost"),
1083
+ value: $signal(() => Math.round(((audioGain() ?? 1) - 1) * 100) + "%"),
1084
+ children: [
1085
+ DefaultMenuSliderItem({
1086
+ upIcon: "menu-audio-boost-up",
1087
+ downIcon: "menu-audio-boost-down",
1088
+ children: DefaultAudioGainSlider(),
1089
+ isMin: () => ((audioGain() ?? 1) - 1) * 100 <= getGainMin(),
1090
+ isMax: () => ((audioGain() ?? 1) - 1) * 100 === getGainMax()
1091
+ })
1092
+ ]
1093
+ });
1094
+ });
1095
+ }
1096
+ function DefaultAudioGainSlider() {
1097
+ const { translations } = useDefaultLayoutContext(), $label = $i18n(translations, "Boost"), $min = getGainMin, $max = getGainMax, $step = getGainStep;
1098
+ return html`
1099
+ <media-audio-gain-slider
1100
+ class="vds-audio-gain-slider vds-slider"
1101
+ aria-label=${$label}
1102
+ min=${$signal($min)}
1103
+ max=${$signal($max)}
1104
+ step=${$signal($step)}
1105
+ key-step=${$signal($step)}
1106
+ >
1107
+ ${DefaultSliderParts()}${DefaultSliderSteps()}
1108
+ </media-audio-gain-slider>
1109
+ `;
1110
+ }
1111
+ function getGainMin() {
1112
+ const { audioGains } = useDefaultLayoutContext(), gains = audioGains();
1113
+ return isArray(gains) ? gains[0] ?? 0 : gains.min;
1114
+ }
1115
+ function getGainMax() {
1116
+ const { audioGains } = useDefaultLayoutContext(), gains = audioGains();
1117
+ return isArray(gains) ? gains[gains.length - 1] ?? 300 : gains.max;
1118
+ }
1119
+ function getGainStep() {
1120
+ const { audioGains } = useDefaultLayoutContext(), gains = audioGains();
1121
+ return isArray(gains) ? gains[1] - gains[0] || 25 : gains.step;
1122
+ }
1123
+
1124
+ const LANG_FLAGS = {
1125
+ en: "gb",
1126
+ eng: "gb",
1127
+ english: "gb",
1128
+ id: "id",
1129
+ ind: "id",
1130
+ indonesian: "id",
1131
+ ja: "jp",
1132
+ jpn: "jp",
1133
+ japanese: "jp",
1134
+ ko: "kr",
1135
+ kor: "kr",
1136
+ korean: "kr",
1137
+ zh: "cn",
1138
+ zho: "cn",
1139
+ chi: "cn",
1140
+ chinese: "cn",
1141
+ es: "es",
1142
+ spa: "es",
1143
+ spanish: "es",
1144
+ fr: "fr",
1145
+ fra: "fr",
1146
+ french: "fr",
1147
+ de: "de",
1148
+ deu: "de",
1149
+ ger: "de",
1150
+ german: "de",
1151
+ pt: "br",
1152
+ por: "br",
1153
+ portuguese: "br",
1154
+ ru: "ru",
1155
+ rus: "ru",
1156
+ russian: "ru",
1157
+ ar: "sa",
1158
+ ara: "sa",
1159
+ arabic: "sa",
1160
+ hi: "in",
1161
+ hin: "in",
1162
+ hindi: "in",
1163
+ th: "th",
1164
+ tha: "th",
1165
+ thai: "th",
1166
+ vi: "vn",
1167
+ vie: "vn",
1168
+ vietnamese: "vn",
1169
+ it: "it",
1170
+ ita: "it",
1171
+ italian: "it",
1172
+ tr: "tr",
1173
+ tur: "tr",
1174
+ turkish: "tr",
1175
+ pl: "pl",
1176
+ pol: "pl",
1177
+ polish: "pl",
1178
+ nl: "nl",
1179
+ nld: "nl",
1180
+ dutch: "nl",
1181
+ ms: "my",
1182
+ msa: "my",
1183
+ malay: "my"
1184
+ };
1185
+ function getFlagCode(label) {
1186
+ const lower = label.toLowerCase().replace(/\s\d+$/, "").trim();
1187
+ if (LANG_FLAGS[lower]) return LANG_FLAGS[lower];
1188
+ for (const [key, code] of Object.entries(LANG_FLAGS)) {
1189
+ if (lower.startsWith(key) || lower.includes(key)) return code;
1190
+ }
1191
+ return null;
1192
+ }
1193
+ function DefaultCaptionsMenu() {
1194
+ return $signal(() => {
1195
+ const { translations } = useDefaultLayoutContext(), { hasCaptions, textTracks, textTrack } = useMediaState(), $offText = $i18n(translations, "Off"), media = useMediaContext();
1196
+ if (!hasCaptions()) return null;
1197
+ const activeTrack = textTrack();
1198
+ const tracks = textTracks().filter(isTrackCaptionKind);
1199
+ const grouped = /* @__PURE__ */ new Map();
1200
+ for (const track of tracks) {
1201
+ const normalizedLabel = track.label.replace(/\s\d+$/, "").trim();
1202
+ if (!grouped.has(normalizedLabel)) {
1203
+ grouped.set(normalizedLabel, []);
1204
+ }
1205
+ grouped.get(normalizedLabel).push(track);
1206
+ }
1207
+ const priorities = ["indonesian", "english", "japanese", "korean", "chinese"];
1208
+ const getPriority = (label) => {
1209
+ const lower = label.toLowerCase();
1210
+ const pIndex = priorities.findIndex((p) => lower.includes(p));
1211
+ return pIndex !== -1 ? pIndex : 999;
1212
+ };
1213
+ const sortedGroups = Array.from(grouped.entries()).sort((a, b) => {
1214
+ const pa = getPriority(a[0]);
1215
+ const pb = getPriority(b[0]);
1216
+ if (pa !== pb) return pa - pb;
1217
+ return a[0].localeCompare(b[0]);
1218
+ });
1219
+ const isOff = tracks.every((t) => t.mode !== "showing");
1220
+ const onOffSelect = (e) => {
1221
+ const selected = media.textTracks.selected;
1222
+ if (selected) {
1223
+ const idx = media.textTracks.indexOf(selected);
1224
+ media.remote.changeTextTrackMode(idx, "disabled", e);
1225
+ }
1226
+ };
1227
+ return html`
1228
+ <media-menu class="vds-captions-menu vds-menu">
1229
+ ${DefaultMenuButton({
1230
+ label: () => i18n(translations, "Captions"),
1231
+ icon: "menu-captions"
1232
+ })}
1233
+ <media-menu-items class="vds-menu-items">
1234
+
1235
+ <media-radio-group value=${isOff ? "off" : "none"}>
1236
+ <media-radio
1237
+ class="vds-caption-radio vds-radio"
1238
+ value="off"
1239
+ @change=${onOffSelect}
1240
+ >
1241
+ <slot name="menu-radio-check-icon" data-class="vds-icon"></slot>
1242
+ <span class="vds-radio-label">${$offText}</span>
1243
+ </media-radio>
1244
+ </media-radio-group>
1245
+
1246
+ ${sortedGroups.map(([groupLabel, groupTracks]) => {
1247
+ const flagCode = getFlagCode(groupLabel);
1248
+ const title = html`
1249
+ <div style="display: flex; align-items: center; gap: 8px;">
1250
+ ${flagCode ? html`<span class="fi fi-${flagCode}" style="font-size: 1.25em; border-radius: 2px; width: 1.33em; height: 1em; display: inline-block; background-image: url('https://cdnjs.cloudflare.com/ajax/libs/flag-icons/7.1.0/flags/4x3/${flagCode}.svg'); background-size: cover; background-position: center;"></span>` : ""}
1251
+ <span>${groupLabel}</span>
1252
+ </div>
1253
+ `;
1254
+ const activeIndex = groupTracks.findIndex((t) => t === activeTrack);
1255
+ return html`
1256
+ <media-menu class="vds-captions-group-menu vds-menu">
1257
+ ${DefaultMenuButton({
1258
+ label: () => title
1259
+ })}
1260
+ <media-menu-items class="vds-menu-items">
1261
+ <media-radio-group value=${String(activeIndex)}>
1262
+ ${groupTracks.map((track, idx) => {
1263
+ const displayLabel = groupTracks.length > 1 ? `${groupLabel} ${idx + 1}` : groupLabel;
1264
+ const onSelect = (e) => {
1265
+ const globalIdx = media.textTracks.indexOf(track);
1266
+ media.remote.changeTextTrackMode(globalIdx, "showing", e);
1267
+ };
1268
+ return html`
1269
+ <media-radio
1270
+ class="vds-caption-radio vds-radio"
1271
+ value=${String(idx)}
1272
+ @change=${onSelect}
1273
+ >
1274
+ <slot name="menu-radio-check-icon" data-class="vds-icon"></slot>
1275
+ <span class="vds-radio-label">${displayLabel}</span>
1276
+ </media-radio>
1277
+ `;
1278
+ })}
1279
+ </media-radio-group>
1280
+ </media-menu-items>
1281
+ </media-menu>
1282
+ `;
1283
+ })}
1284
+
1285
+ </media-menu-items>
1286
+ </media-menu>
1287
+ `;
1288
+ });
1289
+ }
1290
+
1291
+ function DefaultPlaybackMenu() {
1292
+ return $signal(() => {
1293
+ const { translations } = useDefaultLayoutContext();
1294
+ return html`
1295
+ <media-menu class="vds-playback-menu vds-menu">
1296
+ ${DefaultMenuButton({
1297
+ label: () => i18n(translations, "Playback"),
1298
+ icon: "menu-playback"
1299
+ })}
1300
+ <media-menu-items class="vds-menu-items">
1301
+ ${[
1302
+ DefaultMenuSection({
1303
+ children: DefaultLoopCheckbox()
1304
+ }),
1305
+ DefaultSpeedMenuSection(),
1306
+ DefaultQualityMenuSection()
1307
+ ]}
1308
+ </media-menu-items>
1309
+ </media-menu>
1310
+ `;
1311
+ });
1312
+ }
1313
+ function DefaultLoopCheckbox() {
1314
+ const { remote } = useMediaContext(), { translations } = useDefaultLayoutContext(), label = "Loop";
1315
+ return DefaultMenuItem({
1316
+ label: $i18n(translations, label),
1317
+ children: DefaultMenuCheckbox({
1318
+ label,
1319
+ storageKey: "vds-player::user-loop",
1320
+ onChange(checked, trigger) {
1321
+ remote.userPrefersLoopChange(checked, trigger);
1322
+ }
1323
+ })
1324
+ });
1325
+ }
1326
+ function DefaultSpeedMenuSection() {
1327
+ return $signal(() => {
1328
+ const { translations } = useDefaultLayoutContext(), { canSetPlaybackRate, playbackRate } = useMediaState();
1329
+ if (!canSetPlaybackRate()) return null;
1330
+ return DefaultMenuSection({
1331
+ label: $i18n(translations, "Speed"),
1332
+ value: $signal(
1333
+ () => playbackRate() === 1 ? i18n(translations, "Normal") : playbackRate() + "x"
1334
+ ),
1335
+ children: [
1336
+ DefaultMenuSliderItem({
1337
+ upIcon: "menu-speed-up",
1338
+ downIcon: "menu-speed-down",
1339
+ children: DefaultSpeedSlider(),
1340
+ isMin: () => playbackRate() === getSpeedMin(),
1341
+ isMax: () => playbackRate() === getSpeedMax()
1342
+ })
1343
+ ]
1344
+ });
1345
+ });
1346
+ }
1347
+ function getSpeedMin() {
1348
+ const { playbackRates } = useDefaultLayoutContext(), rates = playbackRates();
1349
+ return isArray(rates) ? rates[0] ?? 0 : rates.min;
1350
+ }
1351
+ function getSpeedMax() {
1352
+ const { playbackRates } = useDefaultLayoutContext(), rates = playbackRates();
1353
+ return isArray(rates) ? rates[rates.length - 1] ?? 2 : rates.max;
1354
+ }
1355
+ function getSpeedStep() {
1356
+ const { playbackRates } = useDefaultLayoutContext(), rates = playbackRates();
1357
+ return isArray(rates) ? rates[1] - rates[0] || 0.25 : rates.step;
1358
+ }
1359
+ function DefaultSpeedSlider() {
1360
+ const { translations } = useDefaultLayoutContext(), $label = $i18n(translations, "Speed"), $min = getSpeedMin, $max = getSpeedMax, $step = getSpeedStep;
1361
+ return html`
1362
+ <media-speed-slider
1363
+ class="vds-speed-slider vds-slider"
1364
+ aria-label=${$label}
1365
+ min=${$signal($min)}
1366
+ max=${$signal($max)}
1367
+ step=${$signal($step)}
1368
+ key-step=${$signal($step)}
1369
+ >
1370
+ ${DefaultSliderParts()}${DefaultSliderSteps()}
1371
+ </media-speed-slider>
1372
+ `;
1373
+ }
1374
+ function DefaultAutoQualityCheckbox() {
1375
+ const { remote, qualities } = useMediaContext(), { autoQuality, canSetQuality, qualities: $qualities } = useMediaState(), { translations } = useDefaultLayoutContext(), label = "Auto", $disabled = computed(() => !canSetQuality() || $qualities().length <= 1);
1376
+ if ($disabled()) return null;
1377
+ return DefaultMenuItem({
1378
+ label: $i18n(translations, label),
1379
+ children: DefaultMenuCheckbox({
1380
+ label,
1381
+ checked: autoQuality,
1382
+ onChange(checked, trigger) {
1383
+ if (checked) {
1384
+ remote.requestAutoQuality(trigger);
1385
+ } else {
1386
+ remote.changeQuality(qualities.selectedIndex, trigger);
1387
+ }
1388
+ }
1389
+ })
1390
+ });
1391
+ }
1392
+ function DefaultQualityMenuSection() {
1393
+ return $signal(() => {
1394
+ const { hideQualityBitrate, translations } = useDefaultLayoutContext(), { canSetQuality, qualities, quality } = useMediaState(), $disabled = computed(() => !canSetQuality() || qualities().length <= 1), $sortedQualities = computed(() => sortVideoQualities(qualities()));
1395
+ if ($disabled()) return null;
1396
+ return DefaultMenuSection({
1397
+ label: $i18n(translations, "Quality"),
1398
+ value: $signal(() => {
1399
+ const height = quality()?.height, label = quality()?.label, bitrate = !hideQualityBitrate() ? quality()?.bitrate : null, bitrateText = bitrate && bitrate > 0 ? `${(bitrate / 1e6).toFixed(2)} Mbps` : null, autoText = i18n(translations, "Auto");
1400
+ const rootText = label ?? (height ? `${height}p` : "");
1401
+ return rootText ? `${rootText}${bitrateText ? ` (${bitrateText})` : ""}` : autoText;
1402
+ }),
1403
+ children: [
1404
+ DefaultMenuSliderItem({
1405
+ upIcon: "menu-quality-up",
1406
+ downIcon: "menu-quality-down",
1407
+ children: DefaultQualitySlider(),
1408
+ isMin: () => $sortedQualities()[0] === quality(),
1409
+ isMax: () => $sortedQualities().at(-1) === quality()
1410
+ }),
1411
+ DefaultAutoQualityCheckbox()
1412
+ ]
1413
+ });
1414
+ });
1415
+ }
1416
+ function DefaultQualitySlider() {
1417
+ const { translations } = useDefaultLayoutContext(), $label = $i18n(translations, "Quality");
1418
+ return html`
1419
+ <media-quality-slider class="vds-quality-slider vds-slider" aria-label=${$label}>
1420
+ ${DefaultSliderParts()}${DefaultSliderSteps()}
1421
+ </media-quality-slider>
1422
+ `;
1423
+ }
1424
+
1425
+ function DefaultSettingsMenu({
1426
+ placement,
1427
+ portal,
1428
+ tooltip
1429
+ }) {
1430
+ return $signal(() => {
1431
+ const { viewType } = useMediaState(), {
1432
+ translations,
1433
+ menuPortal,
1434
+ noModal,
1435
+ menuGroup,
1436
+ smallWhen: smWhen
1437
+ } = useDefaultLayoutContext(), $placement = computed(
1438
+ () => noModal() ? unwrap(placement) : !smWhen() ? unwrap(placement) : null
1439
+ ), $offset = computed(
1440
+ () => !smWhen() && menuGroup() === "bottom" && viewType() === "video" ? 26 : 0
1441
+ ), $isOpen = signal(false);
1442
+ updateFontCssVars();
1443
+ function onOpen() {
1444
+ $isOpen.set(true);
1445
+ }
1446
+ function onClose() {
1447
+ $isOpen.set(false);
1448
+ }
1449
+ const items = html`
1450
+ <media-menu-items
1451
+ class="vds-settings-menu-items vds-menu-items"
1452
+ placement=${$signal($placement)}
1453
+ offset=${$signal($offset)}
1454
+ >
1455
+ ${$signal(() => {
1456
+ if (!$isOpen()) {
1457
+ return null;
1458
+ }
1459
+ return [
1460
+ DefaultPlaybackMenu(),
1461
+ DefaultAccessibilityMenu(),
1462
+ DefaultAudioMenu(),
1463
+ DefaultCaptionsMenu()
1464
+ ];
1465
+ })}
1466
+ </media-menu-items>
1467
+ `;
1468
+ return html`
1469
+ <media-menu class="vds-settings-menu vds-menu" @open=${onOpen} @close=${onClose}>
1470
+ <media-tooltip class="vds-tooltip">
1471
+ <media-tooltip-trigger>
1472
+ <media-menu-button
1473
+ class="vds-menu-button vds-button"
1474
+ aria-label=${$i18n(translations, "Settings")}
1475
+ >
1476
+ ${IconSlot("menu-settings", "vds-rotate-icon")}
1477
+ </media-menu-button>
1478
+ </media-tooltip-trigger>
1479
+ <media-tooltip-content
1480
+ class="vds-tooltip-content"
1481
+ placement=${isFunction(tooltip) ? $signal(tooltip) : tooltip}
1482
+ >
1483
+ ${$i18n(translations, "Settings")}
1484
+ </media-tooltip-content>
1485
+ </media-tooltip>
1486
+ ${MenuPortal(menuPortal, items) }
1487
+ </media-menu>
1488
+ `;
1489
+ });
1490
+ }
1491
+
1492
+ function DefaultVolumePopup({
1493
+ orientation,
1494
+ tooltip
1495
+ }) {
1496
+ return $signal(() => {
1497
+ const { pointer, muted, canSetVolume } = useMediaState();
1498
+ if (pointer() === "coarse" && !muted()) return null;
1499
+ if (!canSetVolume()) {
1500
+ return DefaultMuteButton({ tooltip });
1501
+ }
1502
+ const $rootRef = signal(void 0), $isRootActive = useActive($rootRef);
1503
+ return html`
1504
+ <div class="vds-volume" ?data-active=${$signal($isRootActive)} ${ref($rootRef.set)}>
1505
+ ${DefaultMuteButton({ tooltip })}
1506
+ <div class="vds-volume-popup">${DefaultVolumeSlider({ orientation })}</div>
1507
+ </div>
1508
+ `;
1509
+ });
1510
+ }
1511
+ function DefaultVolumeSlider({ orientation } = {}) {
1512
+ const { translations } = useDefaultLayoutContext(), $label = $i18n(translations, "Volume");
1513
+ return html`
1514
+ <media-volume-slider
1515
+ class="vds-volume-slider vds-slider"
1516
+ aria-label=${$label}
1517
+ orientation=${ifDefined(orientation)}
1518
+ >
1519
+ <div class="vds-slider-track"></div>
1520
+ <div class="vds-slider-track-fill vds-slider-track"></div>
1521
+ <media-slider-preview class="vds-slider-preview" no-clamp>
1522
+ <media-slider-value class="vds-slider-value"></media-slider-value>
1523
+ </media-slider-preview>
1524
+ <div class="vds-slider-thumb"></div>
1525
+ </media-volume-slider>
1526
+ `;
1527
+ }
1528
+ function DefaultTimeSlider() {
1529
+ const $ref = signal(void 0), $width = signal(0), {
1530
+ thumbnails,
1531
+ translations,
1532
+ sliderChaptersMinWidth,
1533
+ disableTimeSlider,
1534
+ seekStep,
1535
+ noScrubGesture
1536
+ } = useDefaultLayoutContext(), $label = $i18n(translations, "Seek"), $isDisabled = $signal(disableTimeSlider), $isChaptersDisabled = $signal(() => $width() < sliderChaptersMinWidth()), $thumbnails = $signal(thumbnails);
1537
+ useResizeObserver($ref, () => {
1538
+ const el = $ref();
1539
+ el && $width.set(el.clientWidth);
1540
+ });
1541
+ return html`
1542
+ <media-time-slider
1543
+ class="vds-time-slider vds-slider"
1544
+ aria-label=${$label}
1545
+ key-step=${$signal(seekStep)}
1546
+ ?disabled=${$isDisabled}
1547
+ ?no-swipe-gesture=${$signal(noScrubGesture)}
1548
+ ${ref($ref.set)}
1549
+ >
1550
+ <media-slider-chapters class="vds-slider-chapters" ?disabled=${$isChaptersDisabled}>
1551
+ <template>
1552
+ <div class="vds-slider-chapter">
1553
+ <div class="vds-slider-track"></div>
1554
+ <div class="vds-slider-track-fill vds-slider-track"></div>
1555
+ <div class="vds-slider-progress vds-slider-track"></div>
1556
+ </div>
1557
+ </template>
1558
+ </media-slider-chapters>
1559
+ <div class="vds-slider-thumb"></div>
1560
+ <media-slider-preview class="vds-slider-preview">
1561
+ <media-slider-thumbnail
1562
+ class="vds-slider-thumbnail vds-thumbnail"
1563
+ .src=${$thumbnails}
1564
+ ></media-slider-thumbnail>
1565
+ <div class="vds-slider-chapter-title" data-part="chapter-title"></div>
1566
+ <media-slider-value class="vds-slider-value"></media-slider-value>
1567
+ </media-slider-preview>
1568
+ </media-time-slider>
1569
+ `;
1570
+ }
1571
+
1572
+ function DefaultTimeGroup() {
1573
+ return html`
1574
+ <div class="vds-time-group">
1575
+ ${$signal(() => {
1576
+ const { duration } = useMediaState();
1577
+ if (!duration()) return null;
1578
+ return [
1579
+ html`<media-time class="vds-time" type="current"></media-time>`,
1580
+ html`<div class="vds-time-divider">/</div>`,
1581
+ html`<media-time class="vds-time" type="duration"></media-time>`
1582
+ ];
1583
+ })}
1584
+ </div>
1585
+ `;
1586
+ }
1587
+ function DefaultTimeInvert() {
1588
+ return $signal(() => {
1589
+ const { live, duration } = useMediaState();
1590
+ return live() ? DefaultLiveButton() : duration() ? html`<media-time class="vds-time" type="current" toggle remainder></media-time>` : null;
1591
+ });
1592
+ }
1593
+ function DefaultTimeInfo() {
1594
+ return $signal(() => {
1595
+ const { live } = useMediaState();
1596
+ return live() ? DefaultLiveButton() : DefaultTimeGroup();
1597
+ });
1598
+ }
1599
+
1600
+ function DefaultTitle() {
1601
+ return $signal(() => {
1602
+ const { textTracks } = useMediaContext(), { title, started } = useMediaState(), $hasChapters = signal(null);
1603
+ watchActiveTextTrack(textTracks, "chapters", $hasChapters.set);
1604
+ return $hasChapters() && (started() || !title()) ? DefaultChapterTitle() : html`<media-title class="vds-chapter-title"></media-title>`;
1605
+ });
1606
+ }
1607
+ function DefaultChapterTitle() {
1608
+ return html`<media-chapter-title class="vds-chapter-title"></media-chapter-title>`;
1609
+ }
1610
+
1611
+ class DefaultLayoutIconsLoader extends LayoutIconsLoader {
1612
+ async loadIcons() {
1613
+ const paths = (await import('./vidstack-mxJIo4Sg.js')).icons, icons = {};
1614
+ for (const iconName of Object.keys(paths)) {
1615
+ icons[iconName] = Icon({ name: iconName, paths: paths[iconName] });
1616
+ }
1617
+ return icons;
1618
+ }
1619
+ }
1620
+
1621
+ export { DefaultAirPlayButton, DefaultAnnouncer, DefaultCaptionButton, DefaultCaptions, DefaultChapterTitle, DefaultChaptersMenu, DefaultControlsSpacer, DefaultDownloadButton, DefaultEpisodeButton, DefaultFullscreenButton, DefaultLayout, DefaultLayoutIconsLoader, DefaultPIPButton, DefaultPlayButton, DefaultSeekButton, DefaultSettingsMenu, DefaultTimeInfo, DefaultTimeInvert, DefaultTimeSlider, DefaultTitle, DefaultVolumePopup, createMenuContainer, i18n, setLayoutName, useDefaultLayoutContext };