@hanifhan1f/vidstack-react 1.12.17 → 1.12.18

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