@hanifhan1f/vidstack-react 1.12.17 → 1.12.19

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.
@@ -1,1497 +0,0 @@
1
- "use client"
2
-
3
- import * as React from 'react';
4
- import { useSignal, composeRefs, isBoolean, uppercaseFirstChar, isUndefined, isString, signal, camelToKebabCase, onDispose, scoped, keysOf, effect, isArray, isKeyboardClick, listenEvent, toggleClass, useContext } from './vidstack-CZgUA94N.js';
5
- import { createComputed, createSignal, MediaAnnouncer, Root, Trigger, Content, GoogleCastButton, Captions, useChapterOptions, Root$1 as Root$5, Root$2 as Root$6, Root$3 as Root$7, useScoped, Root$4 as Root$a, Group, useChapterTitle, createEffect, useActiveTextTrack, ChapterTitle as ChapterTitle$1, Title, Root$5 as Root$b, Track as Track$1, TrackFill as TrackFill$1 } from './vidstack-C5Rzkyfp.js';
6
- import { useColorSchemePreference, useActive, useResizeObserver, useLayoutName, useTransitionActive } from './vidstack-xo_SmgiV.js';
7
- import { useMediaContext, MuteButton, SeekButton, LiveButton, PlayButton, CaptionButton, appendParamsToURL, PIPButton, FullscreenButton, AirPlayButton, Items, Root$3 as Root$1, Item, Root as Root$2, Img, Root$2 as Root$3, Button, Portal, Track, TrackFill, Thumb, Steps, useMediaPlayer, Root$5 as Root$4, useAudioOptions, useCaptionOptions, Root$4 as Root$8, Preview, Value, Root$1 as Root$9, Chapters, Progress, Thumbnail, ChapterTitle, Time, Gesture } from './vidstack-Bh7M8kL6.js';
8
- import { useMediaState, isTrackCaptionKind, getDownloadFile, isRemotionSrc, IS_SERVER, useMediaContext as useMediaContext$1, sortVideoQualities, Primitive, mediaContext } from './vidstack-BbPEqH3g.js';
9
- import { flushSync } from 'react-dom';
10
- import { RemotionThumbnail, RemotionSliderThumbnail } from './vidstack-vqp2QaHR.js';
11
-
12
- const DefaultLayoutContext = React.createContext({});
13
- DefaultLayoutContext.displayName = "DefaultLayoutContext";
14
- function useDefaultLayoutContext() {
15
- return React.useContext(DefaultLayoutContext);
16
- }
17
- function useDefaultLayoutWord(word) {
18
- const { translations } = useDefaultLayoutContext();
19
- return i18n(translations, word);
20
- }
21
- function i18n(translations, word) {
22
- return translations?.[word] ?? word;
23
- }
24
-
25
- function useColorSchemeClass(colorScheme) {
26
- const systemColorPreference = useColorSchemePreference();
27
- if (colorScheme === "default") {
28
- return null;
29
- } else if (colorScheme === "system") {
30
- return systemColorPreference;
31
- } else {
32
- return colorScheme;
33
- }
34
- }
35
-
36
- function createDefaultMediaLayout({
37
- type,
38
- smLayoutWhen,
39
- renderLayout
40
- }) {
41
- const Layout = React.forwardRef(
42
- ({
43
- children,
44
- className,
45
- disableTimeSlider = false,
46
- hideQualityBitrate = false,
47
- icons,
48
- colorScheme = "system",
49
- download = null,
50
- menuContainer = null,
51
- menuGroup = "bottom",
52
- noAudioGain = false,
53
- audioGains = { min: 0, max: 300, step: 25 },
54
- noGestures = false,
55
- noKeyboardAnimations = false,
56
- noModal = false,
57
- noScrubGesture,
58
- playbackRates = { min: 0, max: 2, step: 0.25 },
59
- seekStep = 10,
60
- episodes = null,
61
- episodesTitle = "Episodes",
62
- showMenuDelay,
63
- showTooltipDelay = 700,
64
- sliderChaptersMinWidth = 325,
65
- slots,
66
- smallLayoutWhen = smLayoutWhen,
67
- thumbnails = null,
68
- translations,
69
- ...props
70
- }, forwardRef) => {
71
- const media = useMediaContext(), $load = useSignal(media.$props.load), $canLoad = useMediaState("canLoad"), $viewType = useMediaState("viewType"), $streamType = useMediaState("streamType"), $smallWhen = createComputed(() => {
72
- return isBoolean(smallLayoutWhen) ? smallLayoutWhen : smallLayoutWhen(media.player.state);
73
- }, [smallLayoutWhen]), userPrefersAnnouncements = createSignal(true), userPrefersKeyboardAnimations = createSignal(true), isMatch = $viewType === type, isSmallLayout = $smallWhen(), isForcedLayout = isBoolean(smallLayoutWhen), isLoadLayout = $load === "play" && !$canLoad, canRender = $canLoad || isForcedLayout || isLoadLayout, colorSchemeClass = useColorSchemeClass(colorScheme), layoutEl = createSignal(null);
74
- useSignal($smallWhen);
75
- return /* @__PURE__ */ React.createElement(
76
- "div",
77
- {
78
- ...props,
79
- className: `vds-${type}-layout` + (colorSchemeClass ? ` ${colorSchemeClass}` : "") + (className ? ` ${className}` : ""),
80
- "data-match": isMatch ? "" : null,
81
- "data-sm": isSmallLayout ? "" : null,
82
- "data-lg": !isSmallLayout ? "" : null,
83
- "data-size": isSmallLayout ? "sm" : "lg",
84
- "data-no-scrub-gesture": noScrubGesture ? "" : null,
85
- ref: composeRefs(layoutEl.set, forwardRef)
86
- },
87
- canRender && isMatch ? /* @__PURE__ */ React.createElement(
88
- DefaultLayoutContext.Provider,
89
- {
90
- value: {
91
- disableTimeSlider,
92
- hideQualityBitrate,
93
- icons,
94
- colorScheme,
95
- download,
96
- isSmallLayout,
97
- menuContainer,
98
- menuGroup,
99
- noAudioGain,
100
- audioGains,
101
- layoutEl,
102
- noGestures,
103
- noKeyboardAnimations,
104
- noModal,
105
- noScrubGesture,
106
- showMenuDelay,
107
- showTooltipDelay,
108
- sliderChaptersMinWidth,
109
- slots,
110
- seekStep,
111
- episodes,
112
- episodesTitle,
113
- playbackRates,
114
- thumbnails,
115
- translations,
116
- userPrefersAnnouncements,
117
- userPrefersKeyboardAnimations
118
- }
119
- },
120
- renderLayout({ streamType: $streamType, isSmallLayout, isLoadLayout }),
121
- children
122
- ) : null
123
- );
124
- }
125
- );
126
- Layout.displayName = "DefaultMediaLayout";
127
- return Layout;
128
- }
129
-
130
- function useDefaultAudioLayoutSlots() {
131
- return React.useContext(DefaultLayoutContext).slots;
132
- }
133
- function useDefaultVideoLayoutSlots() {
134
- return React.useContext(DefaultLayoutContext).slots;
135
- }
136
- function slot(slots, name, defaultValue) {
137
- const slot2 = slots?.[name], capitalizedName = uppercaseFirstChar(name);
138
- return /* @__PURE__ */ React.createElement(React.Fragment, null, slots?.[`before${capitalizedName}`], isUndefined(slot2) ? defaultValue : slot2, slots?.[`after${capitalizedName}`]);
139
- }
140
-
141
- function DefaultAnnouncer() {
142
- const { userPrefersAnnouncements, translations } = useDefaultLayoutContext(), $userPrefersAnnouncements = useSignal(userPrefersAnnouncements);
143
- if (!$userPrefersAnnouncements) return null;
144
- return /* @__PURE__ */ React.createElement(MediaAnnouncer, { translations });
145
- }
146
- DefaultAnnouncer.displayName = "DefaultAnnouncer";
147
-
148
- function DefaultTooltip({ content, placement, children }) {
149
- const { showTooltipDelay } = useDefaultLayoutContext();
150
- return /* @__PURE__ */ React.createElement(Root, { showDelay: showTooltipDelay }, /* @__PURE__ */ React.createElement(Trigger, { asChild: true }, children), /* @__PURE__ */ React.createElement(Content, { className: "vds-tooltip-content", placement }, content));
151
- }
152
- DefaultTooltip.displayName = "DefaultTooltip";
153
-
154
- function DefaultPlayButton({ tooltip }) {
155
- const { icons: Icons } = useDefaultLayoutContext(), playText = useDefaultLayoutWord("Play"), pauseText = useDefaultLayoutWord("Pause"), $paused = useMediaState("paused"), $ended = useMediaState("ended");
156
- return /* @__PURE__ */ React.createElement(DefaultTooltip, { content: $paused ? playText : pauseText, placement: tooltip }, /* @__PURE__ */ React.createElement(PlayButton, { className: "vds-play-button vds-button", "aria-label": playText }, $ended ? /* @__PURE__ */ React.createElement(Icons.PlayButton.Replay, { className: "vds-icon" }) : $paused ? /* @__PURE__ */ React.createElement(Icons.PlayButton.Play, { className: "vds-icon" }) : /* @__PURE__ */ React.createElement(Icons.PlayButton.Pause, { className: "vds-icon" })));
157
- }
158
- DefaultPlayButton.displayName = "DefaultPlayButton";
159
- const DefaultMuteButton = React.forwardRef(
160
- ({ tooltip }, forwardRef) => {
161
- const { icons: Icons } = useDefaultLayoutContext(), muteText = useDefaultLayoutWord("Mute"), unmuteText = useDefaultLayoutWord("Unmute"), $muted = useMediaState("muted"), $volume = useMediaState("volume");
162
- return /* @__PURE__ */ React.createElement(DefaultTooltip, { content: $muted ? unmuteText : muteText, placement: tooltip }, /* @__PURE__ */ React.createElement(MuteButton, { className: "vds-mute-button vds-button", "aria-label": muteText, ref: forwardRef }, $muted || $volume == 0 ? /* @__PURE__ */ React.createElement(Icons.MuteButton.Mute, { className: "vds-icon" }) : $volume < 0.5 ? /* @__PURE__ */ React.createElement(Icons.MuteButton.VolumeLow, { className: "vds-icon" }) : /* @__PURE__ */ React.createElement(Icons.MuteButton.VolumeHigh, { className: "vds-icon" })));
163
- }
164
- );
165
- DefaultMuteButton.displayName = "DefaultMuteButton";
166
- function DefaultCaptionButton({ tooltip }) {
167
- const { icons: Icons } = useDefaultLayoutContext(), captionsText = useDefaultLayoutWord("Captions"), onText = useDefaultLayoutWord("Closed-Captions On"), offText = useDefaultLayoutWord("Closed-Captions Off"), $track = useMediaState("textTrack"), isOn = $track && isTrackCaptionKind($track);
168
- return /* @__PURE__ */ React.createElement(DefaultTooltip, { content: isOn ? onText : offText, placement: tooltip }, /* @__PURE__ */ React.createElement(CaptionButton, { className: "vds-caption-button vds-button", "aria-label": captionsText }, isOn ? /* @__PURE__ */ React.createElement(Icons.CaptionButton.On, { className: "vds-icon" }) : /* @__PURE__ */ React.createElement(Icons.CaptionButton.Off, { className: "vds-icon" })));
169
- }
170
- DefaultCaptionButton.displayName = "DefaultCaptionButton";
171
- function DefaultPIPButton({ tooltip }) {
172
- const { icons: Icons } = useDefaultLayoutContext(), pipText = useDefaultLayoutWord("PiP"), enterText = useDefaultLayoutWord("Enter PiP"), exitText = useDefaultLayoutWord("Exit PiP"), $pip = useMediaState("pictureInPicture");
173
- return /* @__PURE__ */ React.createElement(DefaultTooltip, { content: $pip ? exitText : enterText, placement: tooltip }, /* @__PURE__ */ React.createElement(PIPButton, { className: "vds-pip-button vds-button", "aria-label": pipText }, $pip ? /* @__PURE__ */ React.createElement(Icons.PIPButton.Exit, { className: "vds-icon" }) : /* @__PURE__ */ React.createElement(Icons.PIPButton.Enter, { className: "vds-icon" })));
174
- }
175
- DefaultPIPButton.displayName = "DefaultPIPButton";
176
- function DefaultFullscreenButton({ tooltip }) {
177
- const { icons: Icons } = useDefaultLayoutContext(), fullscreenText = useDefaultLayoutWord("Fullscreen"), enterText = useDefaultLayoutWord("Enter Fullscreen"), exitText = useDefaultLayoutWord("Exit Fullscreen"), $fullscreen = useMediaState("fullscreen");
178
- return /* @__PURE__ */ React.createElement(DefaultTooltip, { content: $fullscreen ? exitText : enterText, placement: tooltip }, /* @__PURE__ */ React.createElement(FullscreenButton, { className: "vds-fullscreen-button vds-button", "aria-label": fullscreenText }, $fullscreen ? /* @__PURE__ */ React.createElement(Icons.FullscreenButton.Exit, { className: "vds-icon" }) : /* @__PURE__ */ React.createElement(Icons.FullscreenButton.Enter, { className: "vds-icon" })));
179
- }
180
- DefaultFullscreenButton.displayName = "DefaultFullscreenButton";
181
- function DefaultSeekButton({
182
- backward,
183
- tooltip
184
- }) {
185
- const { icons: Icons, seekStep } = useDefaultLayoutContext(), seekForwardText = useDefaultLayoutWord("Seek Forward"), seekBackwardText = useDefaultLayoutWord("Seek Backward"), seconds = (backward ? -1 : 1) * seekStep, label = seconds >= 0 ? seekForwardText : seekBackwardText;
186
- return /* @__PURE__ */ React.createElement(DefaultTooltip, { content: label, placement: tooltip }, /* @__PURE__ */ React.createElement(SeekButton, { className: "vds-seek-button vds-button", seconds, "aria-label": label }, seconds >= 0 ? /* @__PURE__ */ React.createElement(Icons.SeekButton.Forward, { className: "vds-icon" }) : /* @__PURE__ */ React.createElement(Icons.SeekButton.Backward, { className: "vds-icon" })));
187
- }
188
- DefaultSeekButton.displayName = "DefaultSeekButton";
189
- function DefaultEpisodeButton({ tooltip, onPress }) {
190
- const { icons: Icons } = useDefaultLayoutContext(), episodesText = useDefaultLayoutWord("Episodes");
191
- return /* @__PURE__ */ React.createElement(DefaultTooltip, { content: episodesText, placement: tooltip }, /* @__PURE__ */ React.createElement(
192
- "button",
193
- {
194
- type: "button",
195
- className: "vds-episode-button vds-button",
196
- "aria-label": episodesText,
197
- onPointerUp: (event) => {
198
- event.stopPropagation();
199
- onPress?.(event);
200
- }
201
- },
202
- /* @__PURE__ */ React.createElement(Icons.Menu.Chapters, { className: "vds-icon" })
203
- ));
204
- }
205
- DefaultEpisodeButton.displayName = "DefaultEpisodeButton";
206
- function DefaultAirPlayButton({ tooltip }) {
207
- const { icons: Icons } = useDefaultLayoutContext(), airPlayText = useDefaultLayoutWord("AirPlay"), $state = useMediaState("remotePlaybackState"), stateText = useDefaultLayoutWord(uppercaseFirstChar($state)), label = `${airPlayText} ${stateText}`, Icon = ($state === "connecting" ? Icons.AirPlayButton.Connecting : $state === "connected" ? Icons.AirPlayButton.Connected : null) ?? Icons.AirPlayButton.Default;
208
- return /* @__PURE__ */ React.createElement(DefaultTooltip, { content: airPlayText, placement: tooltip }, /* @__PURE__ */ React.createElement(AirPlayButton, { className: "vds-airplay-button vds-button", "aria-label": label }, /* @__PURE__ */ React.createElement(Icon, { className: "vds-icon" })));
209
- }
210
- DefaultAirPlayButton.displayName = "DefaultAirPlayButton";
211
- function DefaultGoogleCastButton({ tooltip }) {
212
- const { icons: Icons } = useDefaultLayoutContext(), googleCastText = useDefaultLayoutWord("Google Cast"), $state = useMediaState("remotePlaybackState"), stateText = useDefaultLayoutWord(uppercaseFirstChar($state)), label = `${googleCastText} ${stateText}`, Icon = ($state === "connecting" ? Icons.GoogleCastButton.Connecting : $state === "connected" ? Icons.GoogleCastButton.Connected : null) ?? Icons.GoogleCastButton.Default;
213
- return /* @__PURE__ */ React.createElement(DefaultTooltip, { content: googleCastText, placement: tooltip }, /* @__PURE__ */ React.createElement(GoogleCastButton, { className: "vds-google-cast-button vds-button", "aria-label": label }, /* @__PURE__ */ React.createElement(Icon, { className: "vds-icon" })));
214
- }
215
- DefaultGoogleCastButton.displayName = "DefaultGoogleCastButton";
216
- function DefaultLiveButton() {
217
- const $live = useMediaState("live"), label = useDefaultLayoutWord("Skip To Live"), liveText = useDefaultLayoutWord("LIVE");
218
- return $live ? /* @__PURE__ */ React.createElement(LiveButton, { className: "vds-live-button", "aria-label": label }, /* @__PURE__ */ React.createElement("span", { className: "vds-live-button-text" }, liveText)) : null;
219
- }
220
- DefaultLiveButton.displayName = "DefaultLiveButton";
221
- function DefaultDownloadButton() {
222
- const { download, icons: Icons } = useDefaultLayoutContext(), $src = useMediaState("source"), $title = useMediaState("title"), file = getDownloadFile({
223
- title: $title,
224
- src: $src,
225
- download
226
- }), downloadText = useDefaultLayoutWord("Download");
227
- return isString(file?.url) ? /* @__PURE__ */ React.createElement(DefaultTooltip, { content: downloadText, placement: "top" }, /* @__PURE__ */ React.createElement(
228
- "a",
229
- {
230
- role: "button",
231
- className: "vds-download-button vds-button",
232
- "aria-label": downloadText,
233
- href: appendParamsToURL(file.url, { download: file.name }),
234
- download: file.name,
235
- target: "_blank"
236
- },
237
- Icons.DownloadButton ? /* @__PURE__ */ React.createElement(Icons.DownloadButton.Default, { className: "vds-icon" }) : null
238
- )) : null;
239
- }
240
- DefaultDownloadButton.displayName = "DefaultDownloadButton";
241
-
242
- function DefaultCaptions() {
243
- const exampleText = useDefaultLayoutWord("Captions look like this");
244
- return /* @__PURE__ */ React.createElement(Captions, { className: "vds-captions", exampleText });
245
- }
246
- DefaultCaptions.displayName = "DefaultCaptions";
247
-
248
- function DefaultControlsSpacer() {
249
- return /* @__PURE__ */ React.createElement("div", { className: "vds-controls-spacer" });
250
- }
251
- DefaultControlsSpacer.displayName = "DefaultControlsSpacer";
252
-
253
- function useParentDialogEl() {
254
- const { layoutEl } = useDefaultLayoutContext(), $layoutEl = useSignal(layoutEl);
255
- return React.useMemo(() => $layoutEl?.closest("dialog"), [$layoutEl]);
256
- }
257
-
258
- function DefaultChaptersMenu({ tooltip, placement, portalClass = "" }) {
259
- const {
260
- showMenuDelay,
261
- noModal,
262
- isSmallLayout,
263
- icons: Icons,
264
- menuGroup,
265
- menuContainer,
266
- colorScheme
267
- } = useDefaultLayoutContext(), chaptersText = useDefaultLayoutWord("Chapters"), options = useChapterOptions(), disabled = !options.length, { thumbnails } = useDefaultLayoutContext(), $src = useMediaState("currentSrc"), $viewType = useMediaState("viewType"), $offset = !isSmallLayout && menuGroup === "bottom" && $viewType === "video" ? 26 : 0, $RemotionThumbnail = useSignal(RemotionThumbnail), colorSchemeClass = useColorSchemeClass(colorScheme), [isOpen, setIsOpen] = React.useState(false), dialogEl = useParentDialogEl();
268
- if (disabled) return null;
269
- function onOpen() {
270
- flushSync(() => {
271
- setIsOpen(true);
272
- });
273
- }
274
- function onClose() {
275
- setIsOpen(false);
276
- }
277
- const Content = /* @__PURE__ */ React.createElement(
278
- Items,
279
- {
280
- className: "vds-chapters-menu-items vds-menu-items",
281
- placement,
282
- offset: $offset
283
- },
284
- isOpen ? /* @__PURE__ */ React.createElement(
285
- Root$1,
286
- {
287
- className: "vds-chapters-radio-group vds-radio-group",
288
- value: options.selectedValue,
289
- "data-thumbnails": thumbnails ? "" : null
290
- },
291
- options.map(
292
- ({ cue, label, value, startTimeText, durationText, select, setProgressVar }) => /* @__PURE__ */ React.createElement(
293
- Item,
294
- {
295
- className: "vds-chapter-radio vds-radio",
296
- value,
297
- key: value,
298
- onSelect: select,
299
- ref: setProgressVar
300
- },
301
- thumbnails ? /* @__PURE__ */ React.createElement(Root$2, { src: thumbnails, className: "vds-thumbnail", time: cue.startTime }, /* @__PURE__ */ React.createElement(Img, null)) : $RemotionThumbnail && isRemotionSrc($src) ? /* @__PURE__ */ React.createElement($RemotionThumbnail, { className: "vds-thumbnail", frame: cue.startTime * $src.fps }) : null,
302
- /* @__PURE__ */ React.createElement("div", { className: "vds-chapter-radio-content" }, /* @__PURE__ */ React.createElement("span", { className: "vds-chapter-radio-label" }, label), /* @__PURE__ */ React.createElement("span", { className: "vds-chapter-radio-start-time" }, startTimeText), /* @__PURE__ */ React.createElement("span", { className: "vds-chapter-radio-duration" }, durationText))
303
- )
304
- )
305
- ) : null
306
- );
307
- return /* @__PURE__ */ React.createElement(
308
- Root$3,
309
- {
310
- className: "vds-chapters-menu vds-menu",
311
- showDelay: showMenuDelay,
312
- onOpen,
313
- onClose
314
- },
315
- /* @__PURE__ */ React.createElement(DefaultTooltip, { content: chaptersText, placement: tooltip }, /* @__PURE__ */ React.createElement(
316
- Button,
317
- {
318
- className: "vds-menu-button vds-button",
319
- disabled,
320
- "aria-label": chaptersText
321
- },
322
- /* @__PURE__ */ React.createElement(Icons.Menu.Chapters, { className: "vds-icon" })
323
- )),
324
- noModal || !isSmallLayout ? Content : /* @__PURE__ */ React.createElement(
325
- Portal,
326
- {
327
- container: menuContainer ?? dialogEl,
328
- className: portalClass + (colorSchemeClass ? ` ${colorSchemeClass}` : ""),
329
- disabled: "fullscreen",
330
- "data-sm": isSmallLayout ? "" : null,
331
- "data-lg": !isSmallLayout ? "" : null,
332
- "data-size": isSmallLayout ? "sm" : "lg"
333
- },
334
- Content
335
- )
336
- );
337
- }
338
- DefaultChaptersMenu.displayName = "DefaultChaptersMenu";
339
-
340
- const FONT_COLOR_OPTION = {
341
- type: "color"
342
- };
343
- const FONT_FAMILY_OPTION = {
344
- type: "radio",
345
- values: {
346
- "Monospaced Serif": "mono-serif",
347
- "Proportional Serif": "pro-serif",
348
- "Monospaced Sans-Serif": "mono-sans",
349
- "Proportional Sans-Serif": "pro-sans",
350
- Casual: "casual",
351
- Cursive: "cursive",
352
- "Small Capitals": "capitals"
353
- }
354
- };
355
- const FONT_SIZE_OPTION = {
356
- type: "slider",
357
- min: 0,
358
- max: 400,
359
- step: 25,
360
- upIcon: null,
361
- downIcon: null
362
- };
363
- const FONT_OPACITY_OPTION = {
364
- type: "slider",
365
- min: 0,
366
- max: 100,
367
- step: 5,
368
- upIcon: null,
369
- downIcon: null
370
- };
371
- const FONT_TEXT_SHADOW_OPTION = {
372
- type: "radio",
373
- values: ["None", "Drop Shadow", "Raised", "Depressed", "Outline"]
374
- };
375
- const FONT_DEFAULTS = {
376
- fontFamily: "pro-sans",
377
- fontSize: "100%",
378
- textColor: "#ffffff",
379
- textOpacity: "100%",
380
- textShadow: "none",
381
- textBg: "#000000",
382
- textBgOpacity: "100%",
383
- displayBg: "#000000",
384
- displayBgOpacity: "0%"
385
- };
386
- const FONT_SIGNALS = Object.keys(FONT_DEFAULTS).reduce(
387
- (prev, type) => ({
388
- ...prev,
389
- [type]: signal(FONT_DEFAULTS[type])
390
- }),
391
- {}
392
- );
393
- if (!IS_SERVER) {
394
- for (const type of Object.keys(FONT_SIGNALS)) {
395
- const value = localStorage.getItem(`vds-player:${camelToKebabCase(type)}`);
396
- if (isString(value)) FONT_SIGNALS[type].set(value);
397
- }
398
- }
399
- function onFontReset() {
400
- for (const type of Object.keys(FONT_SIGNALS)) {
401
- const defaultValue = FONT_DEFAULTS[type];
402
- FONT_SIGNALS[type].set(defaultValue);
403
- }
404
- }
405
-
406
- function hexToRgb(hex) {
407
- const { style } = new Option();
408
- style.color = hex;
409
- return style.color.match(/\((.*?)\)/)[1].replace(/,/g, " ");
410
- }
411
-
412
- let isWatchingVars = false, players = /* @__PURE__ */ new Set();
413
- function updateFontCssVars() {
414
- if (IS_SERVER) return;
415
- const { player } = useMediaContext$1();
416
- players.add(player);
417
- onDispose(() => players.delete(player));
418
- if (!isWatchingVars) {
419
- scoped(() => {
420
- for (const type of keysOf(FONT_SIGNALS)) {
421
- const $value = FONT_SIGNALS[type], defaultValue = FONT_DEFAULTS[type], varName = `--media-user-${camelToKebabCase(type)}`, storageKey = `vds-player:${camelToKebabCase(type)}`;
422
- effect(() => {
423
- const value = $value(), isDefaultVarValue = value === defaultValue, varValue = !isDefaultVarValue ? getCssVarValue(player, type, value) : null;
424
- for (const player2 of players) {
425
- player2.el?.style.setProperty(varName, varValue);
426
- }
427
- if (isDefaultVarValue) {
428
- localStorage.removeItem(storageKey);
429
- } else {
430
- localStorage.setItem(storageKey, value);
431
- }
432
- });
433
- }
434
- }, null);
435
- isWatchingVars = true;
436
- }
437
- }
438
- function getCssVarValue(player, type, value) {
439
- switch (type) {
440
- case "fontFamily":
441
- const fontVariant = value === "capitals" ? "small-caps" : "";
442
- player.el?.style.setProperty("--media-user-font-variant", fontVariant);
443
- return getFontFamilyCSSVarValue(value);
444
- case "fontSize":
445
- case "textOpacity":
446
- case "textBgOpacity":
447
- case "displayBgOpacity":
448
- return percentToRatio(value);
449
- case "textColor":
450
- return `rgb(${hexToRgb(value)} / var(--media-user-text-opacity, 1))`;
451
- case "textShadow":
452
- return getTextShadowCssVarValue(value);
453
- case "textBg":
454
- return `rgb(${hexToRgb(value)} / var(--media-user-text-bg-opacity, 1))`;
455
- case "displayBg":
456
- return `rgb(${hexToRgb(value)} / var(--media-user-display-bg-opacity, 1))`;
457
- }
458
- }
459
- function percentToRatio(value) {
460
- return (parseInt(value) / 100).toString();
461
- }
462
- function getFontFamilyCSSVarValue(value) {
463
- switch (value) {
464
- case "mono-serif":
465
- return '"Courier New", Courier, "Nimbus Mono L", "Cutive Mono", monospace';
466
- case "mono-sans":
467
- return '"Deja Vu Sans Mono", "Lucida Console", Monaco, Consolas, "PT Mono", monospace';
468
- case "pro-sans":
469
- return 'Roboto, "Arial Unicode Ms", Arial, Helvetica, Verdana, "PT Sans Caption", sans-serif';
470
- case "casual":
471
- return '"Comic Sans MS", Impact, Handlee, fantasy';
472
- case "cursive":
473
- return '"Monotype Corsiva", "URW Chancery L", "Apple Chancery", "Dancing Script", cursive';
474
- case "capitals":
475
- return '"Arial Unicode Ms", Arial, Helvetica, Verdana, "Marcellus SC", sans-serif + font-variant=small-caps';
476
- default:
477
- return '"Times New Roman", Times, Georgia, Cambria, "PT Serif Caption", serif';
478
- }
479
- }
480
- function getTextShadowCssVarValue(value) {
481
- switch (value) {
482
- case "drop shadow":
483
- 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";
484
- case "raised":
485
- return "rgb(34, 34, 34) 1px 1px, rgb(34, 34, 34) 2px 2px";
486
- case "depressed":
487
- return "rgb(204, 204, 204) 1px 1px, rgb(34, 34, 34) -1px -1px";
488
- case "outline":
489
- 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";
490
- default:
491
- return "";
492
- }
493
- }
494
-
495
- function DefaultMenuSection({ label, value, children }) {
496
- const id = React.useId();
497
- if (!label) {
498
- return /* @__PURE__ */ React.createElement("div", { className: "vds-menu-section" }, /* @__PURE__ */ React.createElement("div", { className: "vds-menu-section-body" }, children));
499
- }
500
- return /* @__PURE__ */ React.createElement("section", { className: "vds-menu-section", role: "group", "aria-labelledby": id }, /* @__PURE__ */ React.createElement("div", { className: "vds-menu-section-title" }, /* @__PURE__ */ React.createElement("header", { id }, label), value ? /* @__PURE__ */ React.createElement("div", { className: "vds-menu-section-value" }, value) : null), /* @__PURE__ */ React.createElement("div", { className: "vds-menu-section-body" }, children));
501
- }
502
- DefaultMenuSection.displayName = "DefaultMenuSection";
503
- function DefaultMenuButton({ label, hint = "", Icon, disabled = false }) {
504
- const { icons: Icons } = React.useContext(DefaultLayoutContext);
505
- return /* @__PURE__ */ React.createElement(Button, { className: "vds-menu-item", disabled }, /* @__PURE__ */ React.createElement(Icons.Menu.ArrowLeft, { className: "vds-menu-close-icon vds-icon" }), Icon ? /* @__PURE__ */ React.createElement(Icon, { className: "vds-menu-item-icon vds-icon" }) : null, /* @__PURE__ */ React.createElement("span", { className: "vds-menu-item-label" }, label), /* @__PURE__ */ React.createElement("span", { className: "vds-menu-item-hint" }, hint), /* @__PURE__ */ React.createElement(Icons.Menu.ArrowRight, { className: "vds-menu-open-icon vds-icon" }));
506
- }
507
- DefaultMenuButton.displayName = "DefaultMenuButton";
508
- function DefaultMenuItem({ label, children }) {
509
- return /* @__PURE__ */ React.createElement("div", { className: "vds-menu-item" }, /* @__PURE__ */ React.createElement("div", { className: "vds-menu-item-label" }, label), children);
510
- }
511
- DefaultMenuItem.displayName = "DefaultMenuItem";
512
- function DefaultMenuRadioGroup({ value, options, onChange }) {
513
- const { icons: Icons } = useDefaultLayoutContext();
514
- return /* @__PURE__ */ React.createElement(Root$1, { className: "vds-radio-group", value, onChange }, options.map((option) => /* @__PURE__ */ React.createElement(Item, { className: "vds-radio", value: option.value, key: option.value }, /* @__PURE__ */ React.createElement(Icons.Menu.RadioCheck, { className: "vds-icon" }), /* @__PURE__ */ React.createElement("span", { className: "vds-radio-label", "data-part": "label" }, option.label))));
515
- }
516
- DefaultMenuRadioGroup.displayName = "DefaultMenuRadioGroup";
517
- function createRadioOptions(entries) {
518
- return React.useMemo(
519
- () => isArray(entries) ? entries.map((entry) => ({ label: entry, value: entry.toLowerCase() })) : Object.keys(entries).map((label) => ({ label, value: entries[label] })),
520
- [entries]
521
- );
522
- }
523
-
524
- function DefaultMenuSliderItem({
525
- label,
526
- value,
527
- UpIcon,
528
- DownIcon,
529
- children,
530
- isMin,
531
- isMax
532
- }) {
533
- const hasTitle = label || value, Content = /* @__PURE__ */ React.createElement(React.Fragment, null, DownIcon ? /* @__PURE__ */ React.createElement(DownIcon, { className: "vds-icon down" }) : null, children, UpIcon ? /* @__PURE__ */ React.createElement(UpIcon, { className: "vds-icon up" }) : null);
534
- return /* @__PURE__ */ React.createElement(
535
- "div",
536
- {
537
- className: `vds-menu-item vds-menu-slider-item${hasTitle ? " group" : ""}`,
538
- "data-min": isMin ? "" : null,
539
- "data-max": isMax ? "" : null
540
- },
541
- hasTitle ? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "vds-menu-slider-title" }, label ? /* @__PURE__ */ React.createElement("div", null, label) : null, value ? /* @__PURE__ */ React.createElement("div", null, value) : null), /* @__PURE__ */ React.createElement("div", { className: "vds-menu-slider-body" }, Content)) : Content
542
- );
543
- }
544
- DefaultMenuSliderItem.displayName = "DefaultMenuSliderItem";
545
- function DefaultSliderParts() {
546
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Track, { className: "vds-slider-track" }), /* @__PURE__ */ React.createElement(TrackFill, { className: "vds-slider-track-fill vds-slider-track" }), /* @__PURE__ */ React.createElement(Thumb, { className: "vds-slider-thumb" }));
547
- }
548
- DefaultSliderParts.displayName = "DefaultSliderParts";
549
- function DefaultSliderSteps() {
550
- return /* @__PURE__ */ React.createElement(Steps, { className: "vds-slider-steps" }, (step) => /* @__PURE__ */ React.createElement("div", { className: "vds-slider-step", key: String(step) }));
551
- }
552
- DefaultSliderSteps.displayName = "DefaultSliderSteps";
553
-
554
- function DefaultFontMenu() {
555
- const label = useDefaultLayoutWord("Caption Styles"), $hasCaptions = useMediaState("hasCaptions"), fontSectionLabel = useDefaultLayoutWord("Font"), textSectionLabel = useDefaultLayoutWord("Text"), textBgSectionLabel = useDefaultLayoutWord("Text Background"), displayBgSectionLabel = useDefaultLayoutWord("Display Background");
556
- if (!$hasCaptions) return null;
557
- return /* @__PURE__ */ React.createElement(Root$3, { className: "vds-font-menu vds-menu" }, /* @__PURE__ */ React.createElement(DefaultMenuButton, { label }), /* @__PURE__ */ React.createElement(Items, { className: "vds-font-style-items vds-menu-items" }, /* @__PURE__ */ React.createElement(DefaultMenuSection, { label: fontSectionLabel }, /* @__PURE__ */ React.createElement(DefaultFontFamilyMenu, null), /* @__PURE__ */ React.createElement(DefaultFontSizeSlider, null)), /* @__PURE__ */ React.createElement(DefaultMenuSection, { label: textSectionLabel }, /* @__PURE__ */ React.createElement(DefaultTextColorInput, null), /* @__PURE__ */ React.createElement(DefaultTextShadowMenu, null), /* @__PURE__ */ React.createElement(DefaultTextOpacitySlider, null)), /* @__PURE__ */ React.createElement(DefaultMenuSection, { label: textBgSectionLabel }, /* @__PURE__ */ React.createElement(DefaultTextBgInput, null), /* @__PURE__ */ React.createElement(DefaultTextBgOpacitySlider, null)), /* @__PURE__ */ React.createElement(DefaultMenuSection, { label: displayBgSectionLabel }, /* @__PURE__ */ React.createElement(DefaultDisplayBgInput, null), /* @__PURE__ */ React.createElement(DefaultDisplayBgOpacitySlider, null)), /* @__PURE__ */ React.createElement(DefaultMenuSection, null, /* @__PURE__ */ React.createElement(DefaultResetMenuItem, null))));
558
- }
559
- DefaultFontMenu.displayName = "DefaultFontMenu";
560
- function DefaultFontFamilyMenu() {
561
- return /* @__PURE__ */ React.createElement(DefaultFontSetting, { label: "Family", type: "fontFamily", option: FONT_FAMILY_OPTION });
562
- }
563
- DefaultFontFamilyMenu.displayName = "DefaultFontFamilyMenu";
564
- function DefaultFontSizeSlider() {
565
- const { icons: Icons } = useDefaultLayoutContext(), option = {
566
- ...FONT_SIZE_OPTION,
567
- upIcon: Icons.Menu.FontSizeUp,
568
- downIcon: Icons.Menu.FontSizeDown
569
- };
570
- return /* @__PURE__ */ React.createElement(DefaultFontSetting, { label: "Size", type: "fontSize", option });
571
- }
572
- DefaultFontSizeSlider.displayName = "DefaultFontSizeSlider";
573
- function DefaultTextColorInput() {
574
- return /* @__PURE__ */ React.createElement(DefaultFontSetting, { label: "Color", type: "textColor", option: FONT_COLOR_OPTION });
575
- }
576
- DefaultTextColorInput.displayName = "DefaultTextColorInput";
577
- function DefaultTextOpacitySlider() {
578
- const { icons: Icons } = useDefaultLayoutContext(), option = {
579
- ...FONT_OPACITY_OPTION,
580
- upIcon: Icons.Menu.OpacityUp,
581
- downIcon: Icons.Menu.OpacityDown
582
- };
583
- return /* @__PURE__ */ React.createElement(DefaultFontSetting, { label: "Opacity", type: "textOpacity", option });
584
- }
585
- DefaultTextOpacitySlider.displayName = "DefaultTextOpacitySlider";
586
- function DefaultTextShadowMenu() {
587
- return /* @__PURE__ */ React.createElement(DefaultFontSetting, { label: "Shadow", type: "textShadow", option: FONT_TEXT_SHADOW_OPTION });
588
- }
589
- DefaultTextShadowMenu.displayName = "DefaultTextShadowMenu";
590
- function DefaultTextBgInput() {
591
- return /* @__PURE__ */ React.createElement(DefaultFontSetting, { label: "Color", type: "textBg", option: FONT_COLOR_OPTION });
592
- }
593
- DefaultTextBgInput.displayName = "DefaultTextBgInput";
594
- function DefaultTextBgOpacitySlider() {
595
- const { icons: Icons } = useDefaultLayoutContext(), option = {
596
- ...FONT_OPACITY_OPTION,
597
- upIcon: Icons.Menu.OpacityUp,
598
- downIcon: Icons.Menu.OpacityDown
599
- };
600
- return /* @__PURE__ */ React.createElement(DefaultFontSetting, { label: "Opacity", type: "textBgOpacity", option });
601
- }
602
- DefaultTextBgOpacitySlider.displayName = "DefaultTextBgOpacitySlider";
603
- function DefaultDisplayBgInput() {
604
- return /* @__PURE__ */ React.createElement(DefaultFontSetting, { label: "Color", type: "displayBg", option: FONT_COLOR_OPTION });
605
- }
606
- DefaultDisplayBgInput.displayName = "DefaultDisplayBgInput";
607
- function DefaultDisplayBgOpacitySlider() {
608
- const { icons: Icons } = useDefaultLayoutContext(), option = {
609
- ...FONT_OPACITY_OPTION,
610
- upIcon: Icons.Menu.OpacityUp,
611
- downIcon: Icons.Menu.OpacityDown
612
- };
613
- return /* @__PURE__ */ React.createElement(DefaultFontSetting, { label: "Opacity", type: "displayBgOpacity", option });
614
- }
615
- DefaultDisplayBgOpacitySlider.displayName = "DefaultDisplayBgOpacitySlider";
616
- function DefaultFontSetting({ label, option, type }) {
617
- const player = useMediaPlayer(), $currentValue = FONT_SIGNALS[type], $value = useSignal($currentValue), translatedLabel = useDefaultLayoutWord(label);
618
- const notify = React.useCallback(() => {
619
- player?.dispatchEvent(new Event("vds-font-change"));
620
- }, [player]);
621
- const onChange = React.useCallback(
622
- (newValue) => {
623
- $currentValue.set(newValue);
624
- notify();
625
- },
626
- [$currentValue, notify]
627
- );
628
- if (option.type === "color") {
629
- let onColorChange2 = function(event) {
630
- onChange(event.target.value);
631
- };
632
- return /* @__PURE__ */ React.createElement(DefaultMenuItem, { label: translatedLabel }, /* @__PURE__ */ React.createElement("input", { className: "vds-color-picker", type: "color", value: $value, onChange: onColorChange2 }));
633
- }
634
- if (option.type === "slider") {
635
- let onSliderValueChange2 = function(value) {
636
- onChange(value + "%");
637
- };
638
- const { min, max, step, upIcon, downIcon } = option;
639
- return /* @__PURE__ */ React.createElement(
640
- DefaultMenuSliderItem,
641
- {
642
- label: translatedLabel,
643
- value: $value,
644
- UpIcon: upIcon,
645
- DownIcon: downIcon,
646
- isMin: $value === min + "%",
647
- isMax: $value === max + "%"
648
- },
649
- /* @__PURE__ */ React.createElement(
650
- Root$4,
651
- {
652
- className: "vds-slider",
653
- min,
654
- max,
655
- step,
656
- keyStep: step,
657
- value: parseInt($value),
658
- "aria-label": translatedLabel,
659
- onValueChange: onSliderValueChange2,
660
- onDragValueChange: onSliderValueChange2
661
- },
662
- /* @__PURE__ */ React.createElement(DefaultSliderParts, null),
663
- /* @__PURE__ */ React.createElement(DefaultSliderSteps, null)
664
- )
665
- );
666
- }
667
- if (option.type === "radio") {
668
- return /* @__PURE__ */ React.createElement(
669
- DefaultFontRadioGroup,
670
- {
671
- id: camelToKebabCase(type),
672
- label: translatedLabel,
673
- value: $value,
674
- values: option.values,
675
- onChange
676
- }
677
- );
678
- }
679
- return null;
680
- }
681
- DefaultFontSetting.displayName = "DefaultFontSetting";
682
- function DefaultFontRadioGroup({ id, label, value, values, onChange }) {
683
- const radioOptions = createRadioOptions(values), { translations } = useDefaultLayoutContext(), hint = React.useMemo(() => {
684
- const label2 = radioOptions.find((radio) => radio.value === value)?.label || "";
685
- return i18n(translations, label2);
686
- }, [value, radioOptions]);
687
- return /* @__PURE__ */ React.createElement(Root$3, { className: `vds-${id}-menu vds-menu` }, /* @__PURE__ */ React.createElement(DefaultMenuButton, { label, hint }), /* @__PURE__ */ React.createElement(Items, { className: "vds-menu-items" }, /* @__PURE__ */ React.createElement(DefaultMenuRadioGroup, { value, options: radioOptions, onChange })));
688
- }
689
- DefaultFontRadioGroup.displayName = "DefaultFontRadioGroup";
690
- function DefaultResetMenuItem() {
691
- const resetText = useDefaultLayoutWord("Reset");
692
- return /* @__PURE__ */ React.createElement("button", { className: "vds-menu-item", role: "menuitem", onClick: onFontReset }, /* @__PURE__ */ React.createElement("span", { className: "vds-menu-item-label" }, resetText));
693
- }
694
- DefaultResetMenuItem.displayName = "DefaultResetMenuItem";
695
-
696
- function DefaultMenuCheckbox({
697
- label,
698
- checked,
699
- storageKey,
700
- defaultChecked = false,
701
- onChange
702
- }) {
703
- const [isChecked, setIsChecked] = React.useState(defaultChecked), [isActive, setIsActive] = React.useState(false);
704
- React.useEffect(() => {
705
- const savedValue = storageKey ? localStorage.getItem(storageKey) : null, checked2 = !!(savedValue ?? defaultChecked);
706
- setIsChecked(checked2);
707
- onChange?.(checked2);
708
- }, []);
709
- React.useEffect(() => {
710
- if (isBoolean(checked)) setIsChecked(checked);
711
- }, [checked]);
712
- function onPress(event) {
713
- if (event && "button" in event && event?.button === 1) return;
714
- const toggledCheck = !isChecked;
715
- setIsChecked(toggledCheck);
716
- if (storageKey) localStorage.setItem(storageKey, toggledCheck ? "1" : "");
717
- onChange?.(toggledCheck, event?.nativeEvent);
718
- setIsActive(false);
719
- }
720
- function onActive(event) {
721
- if (event.button !== 0) return;
722
- setIsActive(true);
723
- }
724
- function onKeyDown(event) {
725
- if (isKeyboardClick(event.nativeEvent)) onPress();
726
- }
727
- return /* @__PURE__ */ React.createElement(
728
- "div",
729
- {
730
- className: "vds-menu-checkbox",
731
- role: "menuitemcheckbox",
732
- tabIndex: 0,
733
- "aria-label": label,
734
- "aria-checked": isChecked ? "true" : "false",
735
- "data-active": isActive ? "" : null,
736
- onPointerUp: onPress,
737
- onPointerDown: onActive,
738
- onKeyDown
739
- }
740
- );
741
- }
742
- DefaultMenuCheckbox.displayName = "DefaultMenuCheckbox";
743
-
744
- function DefaultAccessibilityMenu({ slots }) {
745
- const label = useDefaultLayoutWord("Accessibility"), { icons: Icons } = useDefaultLayoutContext();
746
- return /* @__PURE__ */ React.createElement(Root$3, { className: "vds-accessibility-menu vds-menu" }, /* @__PURE__ */ React.createElement(DefaultMenuButton, { label, Icon: Icons.Menu.Accessibility }), /* @__PURE__ */ React.createElement(Items, { className: "vds-menu-items" }, slot(slots, "accessibilityMenuItemsStart", null), /* @__PURE__ */ React.createElement(DefaultMenuSection, null, /* @__PURE__ */ React.createElement(DefaultAnnouncementsMenuCheckbox, null), /* @__PURE__ */ React.createElement(DefaultKeyboardAnimationsMenuCheckbox, null)), /* @__PURE__ */ React.createElement(DefaultMenuSection, null, /* @__PURE__ */ React.createElement(DefaultFontMenu, null)), slot(slots, "accessibilityMenuItemsEnd", null)));
747
- }
748
- DefaultAccessibilityMenu.displayName = "DefaultAccessibilityMenu";
749
- function DefaultAnnouncementsMenuCheckbox() {
750
- const { userPrefersAnnouncements } = useDefaultLayoutContext(), label = useDefaultLayoutWord("Announcements");
751
- function onChange(checked) {
752
- userPrefersAnnouncements.set(checked);
753
- }
754
- return /* @__PURE__ */ React.createElement(DefaultMenuItem, { label }, /* @__PURE__ */ React.createElement(
755
- DefaultMenuCheckbox,
756
- {
757
- label,
758
- defaultChecked: true,
759
- storageKey: "vds-player::announcements",
760
- onChange
761
- }
762
- ));
763
- }
764
- DefaultAnnouncementsMenuCheckbox.displayName = "DefaultAnnouncementsMenuCheckbox";
765
- function DefaultKeyboardAnimationsMenuCheckbox() {
766
- const $viewType = useMediaState("viewType"), { userPrefersKeyboardAnimations, noKeyboardAnimations } = useDefaultLayoutContext(), label = useDefaultLayoutWord("Keyboard Animations");
767
- if ($viewType !== "video" || noKeyboardAnimations) return null;
768
- function onChange(checked) {
769
- userPrefersKeyboardAnimations.set(checked);
770
- }
771
- return /* @__PURE__ */ React.createElement(DefaultMenuItem, { label }, /* @__PURE__ */ React.createElement(
772
- DefaultMenuCheckbox,
773
- {
774
- label,
775
- defaultChecked: true,
776
- storageKey: "vds-player::keyboard-animations",
777
- onChange
778
- }
779
- ));
780
- }
781
- DefaultKeyboardAnimationsMenuCheckbox.displayName = "DefaultKeyboardAnimationsMenuCheckbox";
782
-
783
- function DefaultAudioMenu({ slots }) {
784
- const label = useDefaultLayoutWord("Audio"), $canSetAudioGain = useMediaState("canSetAudioGain"), $audioTracks = useMediaState("audioTracks"), { noAudioGain, icons: Icons } = useDefaultLayoutContext(), hasGainSlider = $canSetAudioGain && !noAudioGain, $disabled = !hasGainSlider && $audioTracks.length <= 1;
785
- if ($disabled) return null;
786
- return /* @__PURE__ */ React.createElement(Root$3, { className: "vds-audio-menu vds-menu" }, /* @__PURE__ */ React.createElement(DefaultMenuButton, { label, Icon: Icons.Menu.Audio }), /* @__PURE__ */ React.createElement(Items, { className: "vds-menu-items" }, slot(slots, "audioMenuItemsStart", null), /* @__PURE__ */ React.createElement(DefaultAudioTracksMenu, null), hasGainSlider ? /* @__PURE__ */ React.createElement(DefaultAudioBoostMenuSection, null) : null, slot(slots, "audioMenuItemsEnd", null)));
787
- }
788
- DefaultAudioMenu.displayName = "DefaultAudioMenu";
789
- function DefaultAudioBoostMenuSection() {
790
- const $audioGain = useMediaState("audioGain"), label = useDefaultLayoutWord("Boost"), value = Math.round((($audioGain ?? 1) - 1) * 100) + "%", $canSetAudioGain = useMediaState("canSetAudioGain"), { noAudioGain, icons: Icons } = useDefaultLayoutContext(), $disabled = !$canSetAudioGain || noAudioGain, min = useGainMin(), max = useGainMax();
791
- if ($disabled) return null;
792
- return /* @__PURE__ */ React.createElement(DefaultMenuSection, { label, value }, /* @__PURE__ */ React.createElement(
793
- DefaultMenuSliderItem,
794
- {
795
- UpIcon: Icons.Menu.AudioBoostUp,
796
- DownIcon: Icons.Menu.AudioBoostDown,
797
- isMin: (($audioGain ?? 1) - 1) * 100 <= min,
798
- isMax: (($audioGain ?? 1) - 1) * 100 === max
799
- },
800
- /* @__PURE__ */ React.createElement(DefaultAudioGainSlider, null)
801
- ));
802
- }
803
- DefaultAudioBoostMenuSection.displayName = "DefaultAudioBoostMenuSection";
804
- function useGainMin() {
805
- const { audioGains } = useDefaultLayoutContext(), min = isArray(audioGains) ? audioGains[0] : audioGains?.min;
806
- return min ?? 0;
807
- }
808
- function useGainMax() {
809
- const { audioGains } = useDefaultLayoutContext(), max = isArray(audioGains) ? audioGains[audioGains.length - 1] : audioGains?.max;
810
- return max ?? 300;
811
- }
812
- function useGainStep() {
813
- const { audioGains } = useDefaultLayoutContext(), step = isArray(audioGains) ? audioGains[1] - audioGains[0] : audioGains?.step;
814
- return step || 25;
815
- }
816
- function DefaultAudioGainSlider() {
817
- const label = useDefaultLayoutWord("Audio Boost"), min = useGainMin(), max = useGainMax(), step = useGainStep();
818
- return /* @__PURE__ */ React.createElement(
819
- Root$5,
820
- {
821
- className: "vds-audio-gain-slider vds-slider",
822
- "aria-label": label,
823
- min,
824
- max,
825
- step,
826
- keyStep: step
827
- },
828
- /* @__PURE__ */ React.createElement(DefaultSliderParts, null),
829
- /* @__PURE__ */ React.createElement(DefaultSliderSteps, null)
830
- );
831
- }
832
- DefaultAudioGainSlider.displayName = "DefaultAudioGainSlider";
833
- function DefaultAudioTracksMenu() {
834
- const { icons: Icons } = useDefaultLayoutContext(), label = useDefaultLayoutWord("Track"), defaultText = useDefaultLayoutWord("Default"), $track = useMediaState("audioTrack"), options = useAudioOptions();
835
- if (options.disabled) return null;
836
- return /* @__PURE__ */ React.createElement(Root$3, { className: "vds-audio-track-menu vds-menu" }, /* @__PURE__ */ React.createElement(
837
- DefaultMenuButton,
838
- {
839
- label,
840
- hint: $track?.label ?? defaultText,
841
- disabled: options.disabled,
842
- Icon: Icons.Menu.Audio
843
- }
844
- ), /* @__PURE__ */ React.createElement(Items, { className: "vds-menu-items" }, /* @__PURE__ */ React.createElement(
845
- Root$1,
846
- {
847
- className: "vds-audio-radio-group vds-radio-group",
848
- value: options.selectedValue
849
- },
850
- options.map(({ label: label2, value, select }) => /* @__PURE__ */ React.createElement(
851
- Item,
852
- {
853
- className: "vds-audio-radio vds-radio",
854
- value,
855
- onSelect: select,
856
- key: value
857
- },
858
- /* @__PURE__ */ React.createElement(Icons.Menu.RadioCheck, { className: "vds-icon" }),
859
- /* @__PURE__ */ React.createElement("span", { className: "vds-radio-label" }, label2)
860
- ))
861
- )));
862
- }
863
- DefaultAudioTracksMenu.displayName = "DefaultAudioTracksMenu";
864
-
865
- function DefaultCaptionMenu({ slots }) {
866
- const { icons: Icons } = useDefaultLayoutContext(), label = useDefaultLayoutWord("Captions"), offText = useDefaultLayoutWord("Off"), options = useCaptionOptions({ off: offText }), hint = options.selectedTrack?.label ?? offText;
867
- if (options.disabled) return null;
868
- return /* @__PURE__ */ React.createElement(Root$3, { className: "vds-captions-menu vds-menu" }, /* @__PURE__ */ React.createElement(
869
- DefaultMenuButton,
870
- {
871
- label,
872
- hint,
873
- disabled: options.disabled,
874
- Icon: Icons.Menu.Captions
875
- }
876
- ), /* @__PURE__ */ React.createElement(Items, { className: "vds-menu-items" }, slot(slots, "captionsMenuItemsStart", null), /* @__PURE__ */ React.createElement(
877
- Root$1,
878
- {
879
- className: "vds-captions-radio-group vds-radio-group",
880
- value: options.selectedValue
881
- },
882
- options.map(({ label: label2, value, select }) => /* @__PURE__ */ React.createElement(
883
- Item,
884
- {
885
- className: "vds-caption-radio vds-radio",
886
- value,
887
- onSelect: select,
888
- key: value
889
- },
890
- /* @__PURE__ */ React.createElement(Icons.Menu.RadioCheck, { className: "vds-icon" }),
891
- /* @__PURE__ */ React.createElement("span", { className: "vds-radio-label" }, label2)
892
- ))
893
- ), slot(slots, "captionsMenuItemsEnd", null)));
894
- }
895
- DefaultCaptionMenu.displayName = "DefaultCaptionMenu";
896
-
897
- function DefaultPlaybackMenu({ slots }) {
898
- const label = useDefaultLayoutWord("Playback"), { icons: Icons } = useDefaultLayoutContext();
899
- return /* @__PURE__ */ React.createElement(Root$3, { className: "vds-playback-menu vds-menu" }, /* @__PURE__ */ React.createElement(DefaultMenuButton, { label, Icon: Icons.Menu.Playback }), /* @__PURE__ */ React.createElement(Items, { className: "vds-menu-items" }, slot(slots, "playbackMenuItemsStart", null), /* @__PURE__ */ React.createElement(DefaultMenuSection, null, slot(slots, "playbackMenuLoop", /* @__PURE__ */ React.createElement(DefaultLoopMenuCheckbox, null))), /* @__PURE__ */ React.createElement(DefaultSpeedMenuSection, null), /* @__PURE__ */ React.createElement(DefaultQualityMenuSection, null), slot(slots, "playbackMenuItemsEnd", null)));
900
- }
901
- DefaultPlaybackMenu.displayName = "DefaultPlaybackMenu";
902
- function DefaultLoopMenuCheckbox() {
903
- const { remote } = useMediaContext(), label = useDefaultLayoutWord("Loop");
904
- function onChange(checked, trigger) {
905
- remote.userPrefersLoopChange(checked, trigger);
906
- }
907
- return /* @__PURE__ */ React.createElement(DefaultMenuItem, { label }, /* @__PURE__ */ React.createElement(DefaultMenuCheckbox, { label, storageKey: "vds-player::user-loop", onChange }));
908
- }
909
- DefaultLoopMenuCheckbox.displayName = "DefaultLoopMenuCheckbox";
910
- function DefaultAutoQualityMenuCheckbox() {
911
- const { remote, qualities } = useMediaContext(), $autoQuality = useMediaState("autoQuality"), label = useDefaultLayoutWord("Auto");
912
- function onChange(checked, trigger) {
913
- if (checked) {
914
- remote.requestAutoQuality(trigger);
915
- } else {
916
- remote.changeQuality(qualities.selectedIndex, trigger);
917
- }
918
- }
919
- return /* @__PURE__ */ React.createElement(DefaultMenuItem, { label }, /* @__PURE__ */ React.createElement(
920
- DefaultMenuCheckbox,
921
- {
922
- label,
923
- checked: $autoQuality,
924
- onChange,
925
- defaultChecked: $autoQuality
926
- }
927
- ));
928
- }
929
- DefaultAutoQualityMenuCheckbox.displayName = "DefaultAutoQualityMenuCheckbox";
930
- function DefaultQualityMenuSection() {
931
- const { hideQualityBitrate, icons: Icons } = useDefaultLayoutContext(), $canSetQuality = useMediaState("canSetQuality"), $qualities = useMediaState("qualities"), $quality = useMediaState("quality"), label = useDefaultLayoutWord("Quality"), autoText = useDefaultLayoutWord("Auto"), sortedQualities = React.useMemo(() => sortVideoQualities($qualities), [$qualities]);
932
- if (!$canSetQuality || $qualities.length <= 1) return null;
933
- const height = $quality?.height, bitrate = !hideQualityBitrate ? $quality?.bitrate : null, bitrateText = bitrate && bitrate > 0 ? `${(bitrate / 1e6).toFixed(2)} Mbps` : null, value = height ? `${height}p${bitrateText ? ` (${bitrateText})` : ""}` : autoText, isMin = sortedQualities[0] === $quality, isMax = sortedQualities.at(-1) === $quality;
934
- return /* @__PURE__ */ React.createElement(DefaultMenuSection, { label, value }, /* @__PURE__ */ React.createElement(
935
- DefaultMenuSliderItem,
936
- {
937
- UpIcon: Icons.Menu.QualityUp,
938
- DownIcon: Icons.Menu.QualityDown,
939
- isMin,
940
- isMax
941
- },
942
- /* @__PURE__ */ React.createElement(DefaultQualitySlider, null)
943
- ), /* @__PURE__ */ React.createElement(DefaultAutoQualityMenuCheckbox, null));
944
- }
945
- DefaultQualityMenuSection.displayName = "DefaultQualityMenuSection";
946
- function DefaultQualitySlider() {
947
- const label = useDefaultLayoutWord("Quality");
948
- return /* @__PURE__ */ React.createElement(Root$7, { className: "vds-quality-slider vds-slider", "aria-label": label }, /* @__PURE__ */ React.createElement(DefaultSliderParts, null), /* @__PURE__ */ React.createElement(DefaultSliderSteps, null));
949
- }
950
- DefaultQualitySlider.displayName = "DefaultQualitySlider";
951
- function DefaultSpeedMenuSection() {
952
- const { icons: Icons } = useDefaultLayoutContext(), $playbackRate = useMediaState("playbackRate"), $canSetPlaybackRate = useMediaState("canSetPlaybackRate"), label = useDefaultLayoutWord("Speed"), normalText = useDefaultLayoutWord("Normal"), min = useSpeedMin(), max = useSpeedMax(), value = $playbackRate === 1 ? normalText : $playbackRate + "x";
953
- if (!$canSetPlaybackRate) return null;
954
- return /* @__PURE__ */ React.createElement(DefaultMenuSection, { label, value }, /* @__PURE__ */ React.createElement(
955
- DefaultMenuSliderItem,
956
- {
957
- UpIcon: Icons.Menu.SpeedUp,
958
- DownIcon: Icons.Menu.SpeedDown,
959
- isMin: $playbackRate === min,
960
- isMax: $playbackRate === max
961
- },
962
- /* @__PURE__ */ React.createElement(DefaultSpeedSlider, null)
963
- ));
964
- }
965
- function useSpeedMin() {
966
- const { playbackRates } = useDefaultLayoutContext(), rates = playbackRates;
967
- return (isArray(rates) ? rates[0] : rates?.min) ?? 0;
968
- }
969
- function useSpeedMax() {
970
- const { playbackRates } = useDefaultLayoutContext(), rates = playbackRates;
971
- return (isArray(rates) ? rates[rates.length - 1] : rates?.max) ?? 2;
972
- }
973
- function useSpeedStep() {
974
- const { playbackRates } = useDefaultLayoutContext(), rates = playbackRates;
975
- return (isArray(rates) ? rates[1] - rates[0] : rates?.step) || 0.25;
976
- }
977
- function DefaultSpeedSlider() {
978
- const label = useDefaultLayoutWord("Speed"), min = useSpeedMin(), max = useSpeedMax(), step = useSpeedStep();
979
- return /* @__PURE__ */ React.createElement(
980
- Root$6,
981
- {
982
- className: "vds-speed-slider vds-slider",
983
- "aria-label": label,
984
- min,
985
- max,
986
- step,
987
- keyStep: step
988
- },
989
- /* @__PURE__ */ React.createElement(DefaultSliderParts, null),
990
- /* @__PURE__ */ React.createElement(DefaultSliderSteps, null)
991
- );
992
- }
993
- DefaultSpeedSlider.displayName = "DefaultSpeedSlider";
994
-
995
- function DefaultSettingsMenu({
996
- tooltip,
997
- placement,
998
- portalClass = "",
999
- slots
1000
- }) {
1001
- const {
1002
- showMenuDelay,
1003
- icons: Icons,
1004
- isSmallLayout,
1005
- menuContainer,
1006
- menuGroup,
1007
- noModal,
1008
- colorScheme
1009
- } = useDefaultLayoutContext(), settingsText = useDefaultLayoutWord("Settings"), $viewType = useMediaState("viewType"), $offset = !isSmallLayout && menuGroup === "bottom" && $viewType === "video" ? 26 : 0, colorSchemeClass = useColorSchemeClass(colorScheme), [isOpen, setIsOpen] = React.useState(false), dialogEl = useParentDialogEl();
1010
- useScoped(updateFontCssVars);
1011
- function onOpen() {
1012
- flushSync(() => {
1013
- setIsOpen(true);
1014
- });
1015
- }
1016
- function onClose() {
1017
- setIsOpen(false);
1018
- }
1019
- const Content = /* @__PURE__ */ React.createElement(
1020
- Items,
1021
- {
1022
- className: "vds-settings-menu-items vds-menu-items",
1023
- placement,
1024
- offset: $offset
1025
- },
1026
- isOpen ? /* @__PURE__ */ React.createElement(React.Fragment, null, slot(slots, "settingsMenuItemsStart", null), slot(slots, "settingsMenuStartItems", null), /* @__PURE__ */ React.createElement(DefaultPlaybackMenu, { slots }), /* @__PURE__ */ React.createElement(DefaultAccessibilityMenu, { slots }), /* @__PURE__ */ React.createElement(DefaultAudioMenu, { slots }), /* @__PURE__ */ React.createElement(DefaultCaptionMenu, { slots }), slot(slots, "settingsMenuEndItems", null), slot(slots, "settingsMenuItemsEnd", null)) : null
1027
- );
1028
- return /* @__PURE__ */ React.createElement(
1029
- Root$3,
1030
- {
1031
- className: "vds-settings-menu vds-menu",
1032
- showDelay: showMenuDelay,
1033
- onOpen,
1034
- onClose
1035
- },
1036
- /* @__PURE__ */ React.createElement(DefaultTooltip, { content: settingsText, placement: tooltip }, /* @__PURE__ */ React.createElement(Button, { className: "vds-menu-button vds-button", "aria-label": settingsText }, /* @__PURE__ */ React.createElement(Icons.Menu.Settings, { className: "vds-icon vds-rotate-icon" }))),
1037
- noModal || !isSmallLayout ? Content : /* @__PURE__ */ React.createElement(
1038
- Portal,
1039
- {
1040
- className: portalClass + (colorSchemeClass ? ` ${colorSchemeClass}` : ""),
1041
- container: menuContainer ?? dialogEl,
1042
- disabled: "fullscreen",
1043
- "data-sm": isSmallLayout ? "" : null,
1044
- "data-lg": !isSmallLayout ? "" : null,
1045
- "data-size": isSmallLayout ? "sm" : "lg",
1046
- "data-view-type": $viewType
1047
- },
1048
- Content
1049
- )
1050
- );
1051
- }
1052
- DefaultSettingsMenu.displayName = "DefaultSettingsMenu";
1053
-
1054
- function DefaultVolumePopup({ tooltip, orientation, slots }) {
1055
- const $pointer = useMediaState("pointer"), $muted = useMediaState("muted"), $canSetVolume = useMediaState("canSetVolume"), [rootEl, setRootEl] = React.useState(null), isRootActive = useActive(rootEl), muteButton = slot(slots, "muteButton", /* @__PURE__ */ React.createElement(DefaultMuteButton, { tooltip }));
1056
- if (!$canSetVolume) {
1057
- return muteButton;
1058
- }
1059
- return $pointer === "coarse" && !$muted ? null : /* @__PURE__ */ React.createElement("div", { className: "vds-volume", "data-active": isRootActive ? "" : null, ref: setRootEl }, muteButton, /* @__PURE__ */ React.createElement("div", { className: "vds-volume-popup" }, slot(slots, "volumeSlider", /* @__PURE__ */ React.createElement(DefaultVolumeSlider, { orientation }))));
1060
- }
1061
- DefaultVolumePopup.displayName = "DefaultVolumePopup";
1062
- function DefaultVolumeSlider(props) {
1063
- const label = useDefaultLayoutWord("Volume");
1064
- return /* @__PURE__ */ React.createElement(Root$8, { className: "vds-volume-slider vds-slider", "aria-label": label, ...props }, /* @__PURE__ */ React.createElement(Track, { className: "vds-slider-track" }), /* @__PURE__ */ React.createElement(TrackFill, { className: "vds-slider-track-fill vds-slider-track" }), /* @__PURE__ */ React.createElement(Thumb, { className: "vds-slider-thumb" }), /* @__PURE__ */ React.createElement(Preview, { className: "vds-slider-preview", noClamp: true }, /* @__PURE__ */ React.createElement(Value, { className: "vds-slider-value" })));
1065
- }
1066
- DefaultVolumeSlider.displayName = "DefaultVolumeSlider";
1067
- function DefaultTimeSlider() {
1068
- const [instance, setInstance] = React.useState(null), [width, setWidth] = React.useState(0), $src = useMediaState("currentSrc"), { thumbnails, sliderChaptersMinWidth, disableTimeSlider, seekStep, noScrubGesture } = useDefaultLayoutContext(), label = useDefaultLayoutWord("Seek"), $RemotionSliderThumbnail = useSignal(RemotionSliderThumbnail);
1069
- const onResize = React.useCallback(() => {
1070
- const el = instance?.el;
1071
- el && setWidth(el.clientWidth);
1072
- }, [instance]);
1073
- useResizeObserver(instance?.el, onResize);
1074
- return /* @__PURE__ */ React.createElement(
1075
- Root$9,
1076
- {
1077
- className: "vds-time-slider vds-slider",
1078
- "aria-label": label,
1079
- disabled: disableTimeSlider,
1080
- noSwipeGesture: noScrubGesture,
1081
- keyStep: seekStep,
1082
- ref: setInstance
1083
- },
1084
- /* @__PURE__ */ React.createElement(
1085
- Chapters,
1086
- {
1087
- className: "vds-slider-chapters",
1088
- disabled: width < sliderChaptersMinWidth
1089
- },
1090
- (cues, forwardRef) => cues.map((cue) => /* @__PURE__ */ React.createElement("div", { className: "vds-slider-chapter", key: cue.startTime, ref: forwardRef }, /* @__PURE__ */ React.createElement(Track, { className: "vds-slider-track" }), /* @__PURE__ */ React.createElement(TrackFill, { className: "vds-slider-track-fill vds-slider-track" }), /* @__PURE__ */ React.createElement(Progress, { className: "vds-slider-progress vds-slider-track" })))
1091
- ),
1092
- /* @__PURE__ */ React.createElement(Thumb, { className: "vds-slider-thumb" }),
1093
- /* @__PURE__ */ React.createElement(Preview, { className: "vds-slider-preview" }, thumbnails ? /* @__PURE__ */ React.createElement(
1094
- Thumbnail.Root,
1095
- {
1096
- src: thumbnails,
1097
- className: "vds-slider-thumbnail vds-thumbnail"
1098
- },
1099
- /* @__PURE__ */ React.createElement(Thumbnail.Img, null)
1100
- ) : $RemotionSliderThumbnail && isRemotionSrc($src) ? /* @__PURE__ */ React.createElement($RemotionSliderThumbnail, { className: "vds-slider-thumbnail vds-thumbnail" }) : null, /* @__PURE__ */ React.createElement(ChapterTitle, { className: "vds-slider-chapter-title" }), /* @__PURE__ */ React.createElement(Value, { className: "vds-slider-value" }))
1101
- );
1102
- }
1103
- DefaultTimeSlider.displayName = "DefaultTimeSlider";
1104
-
1105
- function DefaultTimeGroup({ slots }) {
1106
- const $duration = useMediaState("duration");
1107
- if (!$duration) return null;
1108
- return /* @__PURE__ */ React.createElement("div", { className: "vds-time-group" }, slot(slots, "currentTime", /* @__PURE__ */ React.createElement(Time, { className: "vds-time", type: "current" })), slot(slots, "timeDivider", /* @__PURE__ */ React.createElement("div", { className: "vds-time-divider" }, "/")), slot(slots, "endTime", /* @__PURE__ */ React.createElement(Time, { className: "vds-time", type: "duration" })));
1109
- }
1110
- DefaultTimeGroup.displayName = "DefaultTimeGroup";
1111
- function DefaultTimeInfo({ slots }) {
1112
- const $live = useMediaState("live");
1113
- return $live ? slot(slots, "liveButton", /* @__PURE__ */ React.createElement(DefaultLiveButton, null)) : /* @__PURE__ */ React.createElement(DefaultTimeGroup, { slots });
1114
- }
1115
- DefaultTimeInfo.displayName = "DefaultTimeInfo";
1116
- function DefaultTimeInvert({ slots }) {
1117
- const $live = useMediaState("live"), $duration = useMediaState("duration");
1118
- return $live ? slot(slots, "liveButton", /* @__PURE__ */ React.createElement(DefaultLiveButton, null)) : slot(
1119
- slots,
1120
- "endTime",
1121
- $duration ? /* @__PURE__ */ React.createElement(Time, { className: "vds-time", type: "current", toggle: true, remainder: true }) : null
1122
- );
1123
- }
1124
- DefaultTimeInvert.displayName = "DefaultTimeInvert";
1125
-
1126
- const MediaLayout$1 = createDefaultMediaLayout({
1127
- type: "audio",
1128
- smLayoutWhen({ width }) {
1129
- return width < 576;
1130
- },
1131
- renderLayout: () => /* @__PURE__ */ React.createElement(AudioLayout, null)
1132
- });
1133
- function DefaultAudioLayout(props) {
1134
- const [scrubbing, setScrubbing] = React.useState(false), $pointer = useMediaState("pointer");
1135
- const onStartScrubbing = React.useCallback((event) => {
1136
- const { target } = event, hasTimeSlider = !!(target instanceof HTMLElement && target.closest(".vds-time-slider"));
1137
- if (!hasTimeSlider) return;
1138
- event.nativeEvent.stopImmediatePropagation();
1139
- setScrubbing(true);
1140
- }, []);
1141
- const onStopScrubbing = React.useCallback(() => {
1142
- setScrubbing(false);
1143
- }, []);
1144
- React.useEffect(() => {
1145
- if (scrubbing) return listenEvent(window, "pointerdown", onStopScrubbing);
1146
- }, [scrubbing, onStopScrubbing]);
1147
- return /* @__PURE__ */ React.createElement(
1148
- MediaLayout$1,
1149
- {
1150
- ...props,
1151
- "data-scrubbing": scrubbing ? "" : null,
1152
- onPointerDown: scrubbing ? (e) => e.stopPropagation() : void 0,
1153
- onPointerDownCapture: $pointer === "coarse" && !scrubbing ? onStartScrubbing : void 0
1154
- }
1155
- );
1156
- }
1157
- DefaultAudioLayout.displayName = "DefaultAudioLayout";
1158
- function AudioLayout() {
1159
- const slots = useDefaultAudioLayoutSlots();
1160
- useLayoutName("audio");
1161
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(DefaultAnnouncer, null), /* @__PURE__ */ React.createElement(DefaultCaptions, null), /* @__PURE__ */ React.createElement(Root$a, { className: "vds-controls" }, /* @__PURE__ */ React.createElement(Group, { className: "vds-controls-group" }, slot(slots, "seekBackwardButton", /* @__PURE__ */ React.createElement(DefaultSeekButton, { backward: true, tooltip: "top start" })), slot(slots, "playButton", /* @__PURE__ */ React.createElement(DefaultPlayButton, { tooltip: "top center" })), slot(slots, "seekForwardButton", /* @__PURE__ */ React.createElement(DefaultSeekButton, { tooltip: "top center" })), /* @__PURE__ */ React.createElement(DefaultAudioTitle, null), slot(slots, "timeSlider", /* @__PURE__ */ React.createElement(DefaultTimeSlider, null)), /* @__PURE__ */ React.createElement(DefaultTimeInvert, { slots }), /* @__PURE__ */ React.createElement(DefaultVolumePopup, { orientation: "vertical", tooltip: "top", slots }), slot(slots, "captionButton", /* @__PURE__ */ React.createElement(DefaultCaptionButton, { tooltip: "top center" })), slot(slots, "downloadButton", /* @__PURE__ */ React.createElement(DefaultDownloadButton, null)), /* @__PURE__ */ React.createElement(DefaultAudioMenus, { slots }))));
1162
- }
1163
- AudioLayout.displayName = "AudioLayout";
1164
- function DefaultAudioMenus({ slots }) {
1165
- const { isSmallLayout, noModal } = useDefaultLayoutContext(), placement = noModal ? "top end" : !isSmallLayout ? "top end" : null;
1166
- return /* @__PURE__ */ React.createElement(React.Fragment, null, slot(
1167
- slots,
1168
- "chaptersMenu",
1169
- /* @__PURE__ */ React.createElement(DefaultChaptersMenu, { tooltip: "top", placement, portalClass: "vds-audio-layout" })
1170
- ), slot(
1171
- slots,
1172
- "settingsMenu",
1173
- /* @__PURE__ */ React.createElement(
1174
- DefaultSettingsMenu,
1175
- {
1176
- tooltip: "top end",
1177
- placement,
1178
- portalClass: "vds-audio-layout",
1179
- slots
1180
- }
1181
- )
1182
- ));
1183
- }
1184
- DefaultAudioMenus.displayName = "DefaultAudioMenus";
1185
- function DefaultAudioTitle() {
1186
- const [rootEl, setRootEl] = React.useState(null), media = useMediaContext(), { translations } = useDefaultLayoutContext(), [isTextOverflowing, setIsTextOverflowing] = React.useState(false);
1187
- const isContinued = createComputed(() => {
1188
- const { started, currentTime } = media.$state;
1189
- return started() || currentTime() > 0;
1190
- });
1191
- const $title = useSignal(
1192
- createComputed(() => {
1193
- const { title, ended } = media.$state;
1194
- if (!title()) return "";
1195
- const word = ended() ? "Replay" : isContinued() ? "Continue" : "Play";
1196
- return `${i18n(translations, word)}: ${title()}`;
1197
- })
1198
- );
1199
- const chapterTitle = useChapterTitle(), $isContinued = useSignal(isContinued), $chapterTitle = $isContinued ? chapterTitle : "", isTransitionActive = useTransitionActive(rootEl);
1200
- React.useEffect(() => {
1201
- if (isTransitionActive && document.activeElement === document.body) {
1202
- media.player.el?.focus({ preventScroll: true });
1203
- }
1204
- }, []);
1205
- const onResize = React.useCallback(() => {
1206
- const el = rootEl, isOverflowing = !!el && !isTransitionActive && el.clientWidth < el.children[0].clientWidth;
1207
- if (el) toggleClass(el, "vds-marquee", isOverflowing);
1208
- setIsTextOverflowing(isOverflowing);
1209
- }, [rootEl, isTransitionActive]);
1210
- useResizeObserver(rootEl, onResize);
1211
- return $title ? /* @__PURE__ */ React.createElement("span", { className: "vds-title", title: $title, ref: setRootEl }, /* @__PURE__ */ React.createElement(AudioTitle, { title: $title, chapterTitle: $chapterTitle }), isTextOverflowing && !isTransitionActive ? /* @__PURE__ */ React.createElement(AudioTitle, { title: $title, chapterTitle: $chapterTitle }) : null) : /* @__PURE__ */ React.createElement(DefaultControlsSpacer, null);
1212
- }
1213
- DefaultAudioTitle.displayName = "DefaultAudioTitle";
1214
- function AudioTitle({ title, chapterTitle }) {
1215
- const slots = useDefaultAudioLayoutSlots();
1216
- return /* @__PURE__ */ React.createElement("span", { className: "vds-title-text" }, slot(slots, "title", title), slot(slots, "chapterTitle", /* @__PURE__ */ React.createElement("span", { className: "vds-chapter-title" }, chapterTitle)));
1217
- }
1218
- AudioTitle.displayName = "AudioTitle";
1219
-
1220
- const DefaultKeyboardDisplay = React.forwardRef(
1221
- ({ icons: Icons, ...props }, forwardRef) => {
1222
- const [visible, setVisible] = React.useState(false), [Icon, setIcon] = React.useState(null), [count, setCount] = React.useState(0), $lastKeyboardAction = useMediaState("lastKeyboardAction");
1223
- React.useEffect(() => {
1224
- setCount((n) => n + 1);
1225
- }, [$lastKeyboardAction]);
1226
- const actionDataAttr = React.useMemo(() => {
1227
- const action = $lastKeyboardAction?.action;
1228
- return action && visible ? camelToKebabCase(action) : null;
1229
- }, [visible, $lastKeyboardAction]);
1230
- const className = React.useMemo(
1231
- () => `vds-kb-action${!visible ? " hidden" : ""}${props.className ? ` ${props.className}` : ""}`,
1232
- [visible]
1233
- );
1234
- const $$text = createComputed(getText), $text = useSignal($$text);
1235
- createEffect(() => {
1236
- const Icon2 = getIcon(Icons);
1237
- setIcon(() => Icon2);
1238
- }, [Icons]);
1239
- React.useEffect(() => {
1240
- setVisible(!!$lastKeyboardAction);
1241
- const id = setTimeout(() => setVisible(false), 500);
1242
- return () => {
1243
- setVisible(false);
1244
- window.clearTimeout(id);
1245
- };
1246
- }, [$lastKeyboardAction]);
1247
- return Icon ? /* @__PURE__ */ React.createElement(
1248
- Primitive.div,
1249
- {
1250
- ...props,
1251
- className,
1252
- "data-action": actionDataAttr,
1253
- ref: forwardRef
1254
- },
1255
- /* @__PURE__ */ React.createElement("div", { className: "vds-kb-text-wrapper" }, /* @__PURE__ */ React.createElement("div", { className: "vds-kb-text" }, $text)),
1256
- /* @__PURE__ */ React.createElement("div", { className: "vds-kb-bezel", key: count }, /* @__PURE__ */ React.createElement("div", { className: "vds-kb-icon" }, /* @__PURE__ */ React.createElement(Icon, null)))
1257
- ) : null;
1258
- }
1259
- );
1260
- DefaultKeyboardDisplay.displayName = "DefaultKeyboardDisplay";
1261
- function getText() {
1262
- const { $state } = useContext(mediaContext), action = $state.lastKeyboardAction()?.action, audioGain = $state.audioGain() ?? 1;
1263
- switch (action) {
1264
- case "toggleMuted":
1265
- return $state.muted() ? "0%" : getVolumeText($state.volume(), audioGain);
1266
- case "volumeUp":
1267
- case "volumeDown":
1268
- return getVolumeText($state.volume(), audioGain);
1269
- default:
1270
- return "";
1271
- }
1272
- }
1273
- function getVolumeText(volume, gain) {
1274
- return `${Math.round(volume * gain * 100)}%`;
1275
- }
1276
- function getIcon(Icons) {
1277
- const { $state } = useContext(mediaContext), action = $state.lastKeyboardAction()?.action;
1278
- switch (action) {
1279
- case "togglePaused":
1280
- return !$state.paused() ? Icons.Play : Icons.Pause;
1281
- case "toggleMuted":
1282
- return $state.muted() || $state.volume() === 0 ? Icons.Mute : $state.volume() >= 0.5 ? Icons.VolumeUp : Icons.VolumeDown;
1283
- case "toggleFullscreen":
1284
- return $state.fullscreen() ? Icons.EnterFullscreen : Icons.ExitFullscreen;
1285
- case "togglePictureInPicture":
1286
- return $state.pictureInPicture() ? Icons.EnterPiP : Icons.ExitPiP;
1287
- case "toggleCaptions":
1288
- return $state.hasCaptions() ? $state.textTrack() ? Icons.CaptionsOn : Icons.CaptionsOff : null;
1289
- case "volumeUp":
1290
- return Icons.VolumeUp;
1291
- case "volumeDown":
1292
- return Icons.VolumeDown;
1293
- case "seekForward":
1294
- return Icons.SeekForward;
1295
- case "seekBackward":
1296
- return Icons.SeekBackward;
1297
- default:
1298
- return null;
1299
- }
1300
- }
1301
-
1302
- function DefaultTitle() {
1303
- const $started = useMediaState("started"), $title = useMediaState("title"), $hasChapters = useActiveTextTrack("chapters");
1304
- return $hasChapters && ($started || !$title) ? /* @__PURE__ */ React.createElement(ChapterTitle$1, { className: "vds-chapter-title" }) : /* @__PURE__ */ React.createElement(Title, { className: "vds-chapter-title" });
1305
- }
1306
- DefaultTitle.displayName = "DefaultTitle";
1307
-
1308
- const MediaLayout = createDefaultMediaLayout({
1309
- type: "video",
1310
- smLayoutWhen({ width, height }) {
1311
- return width < 576 || height < 380;
1312
- },
1313
- renderLayout(props) {
1314
- return /* @__PURE__ */ React.createElement(VideoLayout, { ...props });
1315
- }
1316
- });
1317
- function DefaultVideoLayout(props) {
1318
- return /* @__PURE__ */ React.createElement(MediaLayout, { ...props });
1319
- }
1320
- DefaultVideoLayout.displayName = "DefaultVideoLayout";
1321
- function VideoLayout({ streamType, isLoadLayout, isSmallLayout }) {
1322
- useLayoutName("video");
1323
- return isLoadLayout ? /* @__PURE__ */ React.createElement(DefaultVideoLoadLayout, null) : streamType === "unknown" ? /* @__PURE__ */ React.createElement(DefaultBufferingIndicator, null) : isSmallLayout ? /* @__PURE__ */ React.createElement(DefaultVideoSmallLayout, null) : /* @__PURE__ */ React.createElement(DefaultVideoLargeLayout, null);
1324
- }
1325
- VideoLayout.displayName = "VideoLayout";
1326
- function DefaultVideoLargeLayout() {
1327
- const { menuGroup, episodes, episodesTitle, isSmallLayout } = useDefaultLayoutContext(), baseSlots = useDefaultVideoLayoutSlots(), slots = { ...baseSlots, ...baseSlots?.largeLayout }, $fullscreen = useMediaState("fullscreen"), [episodesOpen, setEpisodesOpen] = React.useState(false), list = episodes ?? [];
1328
- React.useEffect(() => {
1329
- if (!$fullscreen) setEpisodesOpen(false);
1330
- }, [$fullscreen]);
1331
- const canOpenEpisodes = ($fullscreen || isSmallLayout) && list.length > 0;
1332
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(DefaultAnnouncer, null), /* @__PURE__ */ React.createElement(DefaultVideoGestures, null), /* @__PURE__ */ React.createElement(DefaultVideoKeyboardDisplay, null), slot(slots, "bufferingIndicator", /* @__PURE__ */ React.createElement(DefaultBufferingIndicator, null)), slot(slots, "captions", /* @__PURE__ */ React.createElement(DefaultCaptions, null)), /* @__PURE__ */ React.createElement(Root$a, { className: "vds-controls" }, /* @__PURE__ */ React.createElement(Group, { className: "vds-controls-group" }, slot(slots, "topControlsGroupStart", null), /* @__PURE__ */ React.createElement(DefaultControlsSpacer, null), slot(slots, "topControlsGroupCenter", null), /* @__PURE__ */ React.createElement(DefaultControlsSpacer, null), slot(slots, "topControlsGroupEnd", null), menuGroup === "top" && /* @__PURE__ */ React.createElement(DefaultVideoMenus, { slots })), /* @__PURE__ */ React.createElement(DefaultControlsSpacer, null), /* @__PURE__ */ React.createElement(Group, { className: "vds-controls-group" }, slot(slots, "centerControlsGroupStart", null), /* @__PURE__ */ React.createElement(DefaultControlsSpacer, null), slot(slots, "centerControlsGroupCenter", null), /* @__PURE__ */ React.createElement(DefaultControlsSpacer, null), slot(slots, "centerControlsGroupEnd", null)), /* @__PURE__ */ React.createElement(DefaultControlsSpacer, null), /* @__PURE__ */ React.createElement(Group, { className: "vds-controls-group" }, slot(slots, "timeSlider", /* @__PURE__ */ React.createElement(DefaultTimeSlider, null))), /* @__PURE__ */ React.createElement(Group, { className: "vds-controls-group" }, slot(slots, "playButton", /* @__PURE__ */ React.createElement(DefaultPlayButton, { tooltip: "top start" })), /* @__PURE__ */ React.createElement(DefaultSeekButton, { backward: true, tooltip: "top" }), /* @__PURE__ */ React.createElement(DefaultSeekButton, { tooltip: "top" }), /* @__PURE__ */ React.createElement(DefaultVolumePopup, { orientation: "horizontal", tooltip: "top", slots }), /* @__PURE__ */ React.createElement(DefaultTimeInfo, { slots }), slot(slots, "chapterTitle", /* @__PURE__ */ React.createElement(DefaultTitle, null)), canOpenEpisodes ? /* @__PURE__ */ React.createElement(DefaultEpisodeButton, { tooltip: "top", onPress: () => setEpisodesOpen((open) => !open) }) : null, slot(slots, "captionButton", /* @__PURE__ */ React.createElement(DefaultCaptionButton, { tooltip: "top" })), menuGroup === "bottom" && /* @__PURE__ */ React.createElement(DefaultVideoMenus, { slots }), slot(slots, "airPlayButton", /* @__PURE__ */ React.createElement(DefaultAirPlayButton, { tooltip: "top" })), slot(slots, "googleCastButton", /* @__PURE__ */ React.createElement(DefaultGoogleCastButton, { tooltip: "top" })), slot(slots, "downloadButton", /* @__PURE__ */ React.createElement(DefaultDownloadButton, null)), slot(slots, "pipButton", /* @__PURE__ */ React.createElement(DefaultPIPButton, { tooltip: "top" })), slot(slots, "fullscreenButton", /* @__PURE__ */ React.createElement(DefaultFullscreenButton, { tooltip: "top end" })))), /* @__PURE__ */ React.createElement(
1333
- DefaultEpisodesSidebar,
1334
- {
1335
- open: episodesOpen,
1336
- onClose: () => setEpisodesOpen(false),
1337
- episodes: list,
1338
- episodesTitle: episodesTitle ?? "Episodes"
1339
- }
1340
- ));
1341
- }
1342
- DefaultVideoLargeLayout.displayName = "DefaultVideoLargeLayout";
1343
- function DefaultVideoSmallLayout() {
1344
- const { episodes, episodesTitle, isSmallLayout } = useDefaultLayoutContext(), baseSlots = useDefaultVideoLayoutSlots(), slots = { ...baseSlots, ...baseSlots?.smallLayout }, $fullscreen = useMediaState("fullscreen"), [episodesOpen, setEpisodesOpen] = React.useState(false), list = episodes ?? [];
1345
- React.useEffect(() => {
1346
- if (!$fullscreen) setEpisodesOpen(false);
1347
- }, [$fullscreen]);
1348
- const canOpenEpisodes = ($fullscreen || isSmallLayout) && list.length > 0;
1349
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(DefaultAnnouncer, null), /* @__PURE__ */ React.createElement(DefaultVideoGestures, null), /* @__PURE__ */ React.createElement(DefaultVideoKeyboardDisplay, null), slot(slots, "bufferingIndicator", /* @__PURE__ */ React.createElement(DefaultBufferingIndicator, null)), slot(slots, "captions", /* @__PURE__ */ React.createElement(DefaultCaptions, null)), /* @__PURE__ */ React.createElement(Root$a, { className: "vds-controls" }, /* @__PURE__ */ React.createElement(Group, { className: "vds-controls-group" }, slot(slots, "topControlsGroupStart", null), slot(slots, "airPlayButton", /* @__PURE__ */ React.createElement(DefaultAirPlayButton, { tooltip: "top start" })), slot(slots, "googleCastButton", /* @__PURE__ */ React.createElement(DefaultGoogleCastButton, { tooltip: "top start" })), /* @__PURE__ */ React.createElement(DefaultControlsSpacer, null), slot(slots, "topControlsGroupCenter", null), /* @__PURE__ */ React.createElement(DefaultControlsSpacer, null), slot(slots, "captionButton", /* @__PURE__ */ React.createElement(DefaultCaptionButton, { tooltip: "bottom" })), slot(slots, "downloadButton", /* @__PURE__ */ React.createElement(DefaultDownloadButton, null)), /* @__PURE__ */ React.createElement(DefaultVideoMenus, { slots }), /* @__PURE__ */ React.createElement(DefaultVolumePopup, { orientation: "vertical", tooltip: "bottom end", slots }), slot(slots, "topControlsGroupEnd", null)), /* @__PURE__ */ React.createElement(DefaultControlsSpacer, null), /* @__PURE__ */ React.createElement(Group, { className: "vds-controls-group" }, slot(slots, "centerControlsGroupStart", null), /* @__PURE__ */ React.createElement(DefaultControlsSpacer, null), /* @__PURE__ */ React.createElement(DefaultSeekButton, { backward: true, tooltip: "top" }), slot(slots, "centerControlsGroupCenter", null), slot(slots, "playButton", /* @__PURE__ */ React.createElement(DefaultPlayButton, { tooltip: "top" })), /* @__PURE__ */ React.createElement(DefaultSeekButton, { tooltip: "top" }), canOpenEpisodes ? /* @__PURE__ */ React.createElement(DefaultEpisodeButton, { tooltip: "top", onPress: () => setEpisodesOpen((open) => !open) }) : null, /* @__PURE__ */ React.createElement(DefaultControlsSpacer, null), slot(slots, "centerControlsGroupEnd", null)), /* @__PURE__ */ React.createElement(DefaultControlsSpacer, null), /* @__PURE__ */ React.createElement(Group, { className: "vds-controls-group" }, /* @__PURE__ */ React.createElement(DefaultTimeInfo, { slots }), slot(slots, "chapterTitle", /* @__PURE__ */ React.createElement(DefaultTitle, null)), slot(slots, "fullscreenButton", /* @__PURE__ */ React.createElement(DefaultFullscreenButton, { tooltip: "top end" }))), /* @__PURE__ */ React.createElement(Group, { className: "vds-controls-group" }, slot(slots, "timeSlider", /* @__PURE__ */ React.createElement(DefaultTimeSlider, null)))), slot(slots, "startDuration", /* @__PURE__ */ React.createElement(DefaultVideoStartDuration, null)), /* @__PURE__ */ React.createElement(
1350
- DefaultEpisodesSidebar,
1351
- {
1352
- open: episodesOpen,
1353
- onClose: () => setEpisodesOpen(false),
1354
- episodes: list,
1355
- episodesTitle: episodesTitle ?? "Episodes"
1356
- }
1357
- ));
1358
- }
1359
- DefaultVideoSmallLayout.displayName = "DefaultVideoSmallLayout";
1360
- function DefaultVideoStartDuration() {
1361
- const $duration = useMediaState("duration");
1362
- if ($duration === 0) return null;
1363
- return /* @__PURE__ */ React.createElement("div", { className: "vds-start-duration" }, /* @__PURE__ */ React.createElement(Time, { className: "vds-time", type: "duration" }));
1364
- }
1365
- DefaultVideoStartDuration.displayName = "DefaultVideoStartDuration";
1366
- function DefaultVideoGestures() {
1367
- const { noGestures } = useDefaultLayoutContext();
1368
- if (noGestures) return null;
1369
- return /* @__PURE__ */ React.createElement("div", { className: "vds-gestures" }, /* @__PURE__ */ React.createElement(Gesture, { className: "vds-gesture", event: "pointerup", action: "toggle:paused" }), /* @__PURE__ */ React.createElement(Gesture, { className: "vds-gesture", event: "pointerup", action: "toggle:controls" }), /* @__PURE__ */ React.createElement(Gesture, { className: "vds-gesture", event: "dblpointerup", action: "toggle:fullscreen" }), /* @__PURE__ */ React.createElement(Gesture, { className: "vds-gesture", event: "dblpointerup", action: "seek:-10" }), /* @__PURE__ */ React.createElement(Gesture, { className: "vds-gesture", event: "dblpointerup", action: "seek:10" }));
1370
- }
1371
- DefaultVideoGestures.displayName = "DefaultVideoGestures";
1372
- function DefaultBufferingIndicator() {
1373
- return /* @__PURE__ */ React.createElement("div", { className: "vds-buffering-indicator" }, /* @__PURE__ */ React.createElement(Root$b, { className: "vds-buffering-spinner" }, /* @__PURE__ */ React.createElement(Track$1, { className: "vds-buffering-track" }), /* @__PURE__ */ React.createElement(TrackFill$1, { className: "vds-buffering-track-fill" })));
1374
- }
1375
- DefaultBufferingIndicator.displayName = "DefaultBufferingIndicator";
1376
- function DefaultVideoMenus({ slots }) {
1377
- const { isSmallLayout, noModal, menuGroup } = useDefaultLayoutContext(), side = menuGroup === "top" || isSmallLayout ? "bottom" : "top", tooltip = `${side} end`, placement = noModal ? `${side} end` : !isSmallLayout ? `${side} end` : null;
1378
- return /* @__PURE__ */ React.createElement(React.Fragment, null, slot(
1379
- slots,
1380
- "chaptersMenu",
1381
- /* @__PURE__ */ React.createElement(
1382
- DefaultChaptersMenu,
1383
- {
1384
- tooltip,
1385
- placement,
1386
- portalClass: "vds-video-layout"
1387
- }
1388
- )
1389
- ), slot(
1390
- slots,
1391
- "settingsMenu",
1392
- /* @__PURE__ */ React.createElement(
1393
- DefaultSettingsMenu,
1394
- {
1395
- tooltip,
1396
- placement,
1397
- portalClass: "vds-video-layout",
1398
- slots
1399
- }
1400
- )
1401
- ));
1402
- }
1403
- DefaultVideoMenus.displayName = "DefaultVideoMenus";
1404
- function DefaultEpisodesSidebar({
1405
- open,
1406
- onClose,
1407
- episodes,
1408
- episodesTitle
1409
- }) {
1410
- const $fullscreen = useMediaState("fullscreen"), { isSmallLayout } = useDefaultLayoutContext();
1411
- if (!$fullscreen && !isSmallLayout || episodes.length === 0) return null;
1412
- return /* @__PURE__ */ React.createElement(
1413
- "div",
1414
- {
1415
- className: "vds-episodes-backdrop",
1416
- "data-open": open ? "true" : "false",
1417
- onPointerUp: (event) => {
1418
- if (event.target === event.currentTarget) onClose();
1419
- }
1420
- },
1421
- /* @__PURE__ */ React.createElement(
1422
- "aside",
1423
- {
1424
- className: "vds-episodes-panel",
1425
- "data-open": open ? "true" : "false",
1426
- onKeyDown: (event) => {
1427
- if (event.key === "Escape") onClose();
1428
- }
1429
- },
1430
- /* @__PURE__ */ React.createElement("header", { className: "vds-episodes-panel-header" }, /* @__PURE__ */ React.createElement("h3", { className: "vds-episodes-panel-title" }, episodesTitle), /* @__PURE__ */ React.createElement(
1431
- "button",
1432
- {
1433
- type: "button",
1434
- className: "vds-episodes-close-btn",
1435
- "aria-label": "Close episodes",
1436
- onPointerUp: (event) => {
1437
- event.stopPropagation();
1438
- onClose();
1439
- }
1440
- },
1441
- /* @__PURE__ */ React.createElement("span", { "aria-hidden": "true" }, "x")
1442
- )),
1443
- /* @__PURE__ */ React.createElement("div", { className: "vds-episodes-list", role: "list" }, episodes.map((episode, index) => {
1444
- const episodeName = episode.episodeTitle || `Episode ${episode.episodeNumber ?? index + 1}`, runtimeText = Number.isFinite(episode.runtime) && (episode.runtime ?? 0) > 0 ? `${episode.runtime} min left` : null, seasonEpLabel = episode.seasonNumber != null && episode.episodeNumber != null ? `S${String(episode.seasonNumber).padStart(2, "0")} \xB7 E${String(episode.episodeNumber).padStart(2, "0")}` : episodeName;
1445
- const onEpisodeSelect = (event) => {
1446
- event.stopPropagation();
1447
- event.currentTarget.dispatchEvent(
1448
- new CustomEvent("vds-episode-select", {
1449
- bubbles: true,
1450
- composed: true,
1451
- detail: { episode, index }
1452
- })
1453
- );
1454
- onClose();
1455
- };
1456
- return /* @__PURE__ */ React.createElement(
1457
- "article",
1458
- {
1459
- key: `${episode.episodeNumber ?? index}-${episode.title ?? ""}`,
1460
- className: "vds-episode-item",
1461
- role: "button",
1462
- tabIndex: 0,
1463
- "aria-label": episode.title || episodeName,
1464
- onPointerUp: onEpisodeSelect,
1465
- onKeyDown: (event) => {
1466
- if (event.key === "Enter" || event.key === " ") onEpisodeSelect(event);
1467
- }
1468
- },
1469
- /* @__PURE__ */ React.createElement("div", { className: "vds-episode-thumb-wrap" }, episode.thumbnail ? /* @__PURE__ */ React.createElement(
1470
- "img",
1471
- {
1472
- className: "vds-episode-thumb",
1473
- src: episode.thumbnail,
1474
- alt: episode.title || episodeName,
1475
- loading: "lazy",
1476
- decoding: "async"
1477
- }
1478
- ) : /* @__PURE__ */ React.createElement("div", { className: "vds-episode-thumb vds-episode-thumb-placeholder" })),
1479
- /* @__PURE__ */ React.createElement("div", { className: "vds-episode-body" }, /* @__PURE__ */ React.createElement("div", { className: "vds-episode-meta-row" }, /* @__PURE__ */ React.createElement("span", { className: "vds-episode-label" }, seasonEpLabel), runtimeText ? /* @__PURE__ */ React.createElement("span", { className: "vds-episode-runtime" }, runtimeText) : null), /* @__PURE__ */ React.createElement("h4", { className: "vds-episode-title", title: episode.title || "" }, episode.title || "-"), /* @__PURE__ */ React.createElement("p", { className: "vds-episode-subtitle", title: episodeName }, episodeName), episode.overview ? /* @__PURE__ */ React.createElement("p", { className: "vds-episode-desc", title: episode.overview }, episode.overview) : null)
1480
- );
1481
- }))
1482
- )
1483
- );
1484
- }
1485
- function DefaultVideoLoadLayout() {
1486
- const { isSmallLayout } = useDefaultLayoutContext(), baseSlots = useDefaultVideoLayoutSlots(), slots = { ...baseSlots, ...baseSlots?.[isSmallLayout ? "smallLayout" : "largeLayout"] };
1487
- return /* @__PURE__ */ React.createElement("div", { className: "vds-load-container" }, slot(slots, "bufferingIndicator", /* @__PURE__ */ React.createElement(DefaultBufferingIndicator, null)), slot(slots, "loadButton", /* @__PURE__ */ React.createElement(DefaultPlayButton, { tooltip: "top" })));
1488
- }
1489
- DefaultVideoLoadLayout.displayName = "DefaultVideoLoadLayout";
1490
- function DefaultVideoKeyboardDisplay() {
1491
- const { noKeyboardAnimations, icons, userPrefersKeyboardAnimations } = useDefaultLayoutContext(), $userPrefersKeyboardAnimations = useSignal(userPrefersKeyboardAnimations), disabled = noKeyboardAnimations || !$userPrefersKeyboardAnimations;
1492
- if (disabled || !icons.KeyboardDisplay) return null;
1493
- return /* @__PURE__ */ React.createElement(DefaultKeyboardDisplay, { icons: icons.KeyboardDisplay });
1494
- }
1495
- DefaultVideoKeyboardDisplay.displayName = "DefaultVideoKeyboardDisplay";
1496
-
1497
- export { DefaultAudioLayout, DefaultBufferingIndicator, DefaultKeyboardDisplay, DefaultLayoutContext, DefaultMenuButton, DefaultMenuCheckbox, DefaultMenuItem, DefaultMenuRadioGroup, DefaultMenuSection, DefaultMenuSliderItem, DefaultSliderParts, DefaultSliderSteps, DefaultTooltip, DefaultVideoGestures, DefaultVideoLargeLayout, DefaultVideoLayout, DefaultVideoSmallLayout, createRadioOptions, i18n, useDefaultLayoutContext, useDefaultLayoutWord };