@banou/media-player 0.8.4 → 0.8.5

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.
package/dist/index.js CHANGED
@@ -4,10 +4,10 @@ import { css as p, keyframes as m } from "@emotion/react";
4
4
  import { createPlayer as h, useContainerAttach as g, useMediaAttach as _ } from "@videojs/react";
5
5
  import { definePlayerFeature as v, videoFeatures as y } from "@videojs/core/dom";
6
6
  import { Fragment as b, jsx as x, jsxs as S } from "@emotion/react/jsx-runtime";
7
- import { ChevronLeft as C, ChevronRight as w, Maximize as T, Minimize as E, Pause as D, Play as O, RotateCcw as k, Settings as A, Volume1 as j, Volume2 as M, VolumeX as ee } from "react-feather";
8
- import { Tooltip as te } from "react-tooltip";
7
+ import { ChevronLeft as C, ChevronRight as w, Maximize as T, Minimize as E, Pause as D, Play as O, RotateCcw as k, Settings as A, Volume1 as j, Volume2 as ee, VolumeX as te } from "react-feather";
8
+ import { Tooltip as ne } from "react-tooltip";
9
9
  //#region src/lib/react/source-feature.ts
10
- var ne = {
10
+ var re = {
11
11
  indexes: [],
12
12
  thumbnails: [],
13
13
  subtitleTracks: [],
@@ -22,19 +22,19 @@ var ne = {
22
22
  playbackError: null,
23
23
  ready: !1,
24
24
  setSourceState: () => {}
25
- }, N = v({
25
+ }, M = v({
26
26
  name: "source",
27
- state: () => ({ ...ne }),
27
+ state: () => ({ ...re }),
28
28
  attach({ set: e }) {
29
29
  e({
30
30
  setSourceState: (t) => e(t),
31
31
  setHideUI: (t) => e({ hideUI: t })
32
32
  });
33
33
  }
34
- }), P = h({
35
- features: [...y, N],
34
+ }), N = h({
35
+ features: [...y, M],
36
36
  displayName: "MediaPlayer"
37
- }), F = P.usePlayer, re = (e) => {
37
+ }), P = N.usePlayer, ie = (e) => {
38
38
  if (!(!e || e === "und")) try {
39
39
  return new Intl.DisplayNames([navigator.language || "en"], {
40
40
  type: "language",
@@ -43,23 +43,23 @@ var ne = {
43
43
  } catch {
44
44
  return;
45
45
  }
46
- }, I = (e) => e?.replace(/_/g, " ").trim() || void 0, L = (e) => {
47
- let t = e.map((e) => re(e.language) ?? I(e.title) ?? `Track ${e.streamIndex}`), n = t.reduce((e, t) => ({
46
+ }, F = (e) => e?.replace(/_/g, " ").trim() || void 0, ae = (e) => {
47
+ let t = e.map((e) => ie(e.language) ?? F(e.title) ?? `Track ${e.streamIndex}`), n = t.reduce((e, t) => ({
48
48
  ...e,
49
49
  [t]: (e[t] ?? 0) + 1
50
50
  }), {});
51
51
  return e.map((e, r) => {
52
- let i = t[r], a = I(e.title);
52
+ let i = t[r], a = F(e.title);
53
53
  return {
54
54
  track: e,
55
55
  label: (n[i] ?? 0) > 1 && a && a !== i ? `${i} (${a})` : i
56
56
  };
57
57
  });
58
- }, R = (e) => L(e).map(({ track: e, label: t }) => ({
58
+ }, I = (e) => ae(e).map(({ track: e, label: t }) => ({
59
59
  id: e.streamIndex,
60
60
  label: t
61
- })), ie = (t, n, r) => {
62
- let i = F(), { read: a, size: o, publicPath: s = "", libavWorkerUrl: u = "", jassubWorkerUrl: p = "", jassubWasmUrl: m = "", jassubLegacyWasmUrl: h, defaultFontUrl: g, bufferSize: _, autoplay: v = !1 } = r ?? {}, [y, b] = f(void 0), x = d(null), S = d(0), C = d(!1), w = d(a);
61
+ })), oe = (t, n, r) => {
62
+ let i = P(), { read: a, size: o, publicPath: s = "", libavWorkerUrl: u = "", jassubWorkerUrl: p = "", jassubWasmUrl: m = "", jassubLegacyWasmUrl: h, defaultFontUrl: g, bufferSize: _, autoplay: v = !1 } = r ?? {}, [y, b] = f(void 0), x = d(null), S = d(0), C = d(!1), w = d(a);
63
63
  w.current = a;
64
64
  let T = d(r?.onSeek);
65
65
  T.current = r?.onSeek;
@@ -70,7 +70,7 @@ var ne = {
70
70
  C.current = !0, i.setSourceState({ selectedSubtitleTrack: t }), x.current?.selectSubtitleStream(t);
71
71
  }, [i]), O = c((e) => {
72
72
  typeof e == "number" && (i.setSourceState({ selectedAudioTrack: e }), b(e));
73
- }, [i]), k = F((e) => e.setSourceState);
73
+ }, [i]), k = P((e) => e.setSourceState);
74
74
  l(() => {
75
75
  k({
76
76
  selectSubtitleTrack: D,
@@ -115,13 +115,13 @@ var ne = {
115
115
  onSeek: (e) => T.current?.(e),
116
116
  onSubtitleStreams: (e) => {
117
117
  r || i.setSourceState({
118
- subtitleTracks: R(e),
118
+ subtitleTracks: I(e),
119
119
  ...C.current ? {} : { selectedSubtitleTrack: e[0]?.streamIndex }
120
120
  });
121
121
  },
122
122
  onAudioStreams: (e, t) => {
123
123
  r || i.setSourceState({
124
- audioTracks: R(e),
124
+ audioTracks: I(e),
125
125
  selectedAudioTrack: t
126
126
  });
127
127
  }
@@ -154,13 +154,13 @@ var ne = {
154
154
  y,
155
155
  v
156
156
  ]);
157
- }, ae = 5e3, oe = 6e4, z = ({ publicPath: e, workerUrl: n, length: r, read: i, downloadedRanges: a }) => {
157
+ }, se = 5e3, ce = 6e4, L = ({ publicPath: e, workerUrl: n, length: r, read: i, downloadedRanges: a }) => {
158
158
  let [o, s] = f([]), c = d(null), p = d(i);
159
159
  p.current = i;
160
160
  let m = u(() => a?.map(({ startByteOffset: e, endByteOffset: t }) => [e, t]), [a?.map(({ startByteOffset: e, endByteOffset: t }) => `${e}-${t}`).join(",")]), h = d(m);
161
161
  return h.current = m, l(() => {
162
162
  if (!r || !i || !e || !n) return;
163
- let a = !1, o = null, l, u = ae, d = () => {
163
+ let a = !1, o = null, l, u = se, d = () => {
164
164
  t({
165
165
  publicPath: e,
166
166
  workerUrl: n,
@@ -176,7 +176,7 @@ var ne = {
176
176
  }
177
177
  o = e, c.current = e, e.update(h.current);
178
178
  }, () => {
179
- a || (l = setTimeout(d, u), u = Math.min(u * 2, oe));
179
+ a || (l = setTimeout(d, u), u = Math.min(u * 2, ce));
180
180
  });
181
181
  };
182
182
  return d(), () => {
@@ -189,8 +189,8 @@ var ne = {
189
189
  ]), l(() => {
190
190
  c.current?.update(m);
191
191
  }, [m]), o;
192
- }, B = (e, t) => {
193
- let n = F(), r = d(null);
192
+ }, R = (e, t) => {
193
+ let n = P(), r = d(null);
194
194
  l(() => {
195
195
  if (!e || !t) return;
196
196
  let a = i({
@@ -212,7 +212,7 @@ var ne = {
212
212
  });
213
213
  }, []);
214
214
  return e && t ? a : null;
215
- }, V = {
215
+ }, z = {
216
216
  headings: {
217
217
  large: "\n font-weight: 600;\n font-size: calc(2.8 * var(--mp-unit));\n line-height: calc(3.4 * var(--mp-unit));\n @media (min-width: 960px) {\n font-size: calc(3.4 * var(--mp-unit));\n line-height: calc(4.1 * var(--mp-unit));\n }\n ",
218
218
  medium: "\n font-weight: 600;\n font-size: calc(2.4 * var(--mp-unit));\n line-height: calc(2.9 * var(--mp-unit));\n @media (min-width: 960px) {\n font-size: calc(2.8 * var(--mp-unit));\n line-height: calc(3.4 * var(--mp-unit));\n }\n ",
@@ -239,14 +239,14 @@ var ne = {
239
239
  medium: "\n font-weight: 500;\n font-size: calc(0.8 * var(--mp-unit));\n line-height: calc(1.1 * var(--mp-unit));\n @media (min-width: 960px) {\n font-size: calc(1 * var(--mp-unit));\n line-height: calc(1.4 * var(--mp-unit));\n }\n ",
240
240
  regular: "\n font-weight: 400;\n font-size: calc(0.8 * var(--mp-unit));\n line-height: calc(1.1 * var(--mp-unit));\n @media (min-width: 960px) {\n font-size: calc(1 * var(--mp-unit));\n line-height: calc(1.4 * var(--mp-unit));\n }\n "
241
241
  }
242
- }, se = p`
242
+ }, le = p`
243
243
  top: unset !important;
244
244
  left: unset !important;
245
245
  width: 100%;
246
246
  height: 100%;
247
247
  margin: auto;
248
248
  pointer-events: none;
249
- `, ce = p`
249
+ `, ue = p`
250
250
  position: absolute;
251
251
  top: 0;
252
252
  left: 0;
@@ -254,7 +254,7 @@ var ne = {
254
254
  padding: calc(1.2 * var(--mp-unit)) calc(1.6 * var(--mp-unit));
255
255
  /* clears a notch once the player is fullscreen; resolves to zero everywhere else */
256
256
  padding-top: calc(calc(1.2 * var(--mp-unit)) + env(safe-area-inset-top, 0px));
257
- ${V.headings.small}
257
+ ${z.headings.small}
258
258
  color: white;
259
259
  text-shadow: 0 0 4px rgba(0, 0, 0, 1);
260
260
  z-index: 2;
@@ -275,7 +275,7 @@ var ne = {
275
275
 
276
276
  background: linear-gradient(180deg, rgba(0,0,0,0.4) 0%, rgba(0,0,0,0.3) 30%, rgba(0,0,0,0.2) 60%, rgba(0,0,0,0.1) 80%, transparent 100%);
277
277
  transition: opacity 0.1s cubic-bezier(.4,0,1,1);
278
- `, le = p`
278
+ `, de = p`
279
279
  position: absolute;
280
280
  inset: 0;
281
281
  z-index: 2;
@@ -295,43 +295,43 @@ var ne = {
295
295
  to { transform: rotate(360deg); }
296
296
  `} 0.8s linear infinite;
297
297
  }
298
- `, ue = p`
298
+ `, fe = p`
299
299
  position: absolute;
300
300
  inset: auto 0 20%;
301
301
  z-index: 3;
302
302
  padding: 0 calc(2 * var(--mp-unit));
303
303
  text-align: center;
304
304
  color: #fff;
305
- ${V.bLarge.regular}
305
+ ${z.bLarge.regular}
306
306
  text-shadow: 0 0 4px rgba(0, 0, 0, 1);
307
307
  pointer-events: none;
308
- `, de = (e) => e instanceof Error ? e.message : typeof e == "string" ? e : "Playback failed", fe = ({ onCanvasRef: e }) => {
309
- let t = F((e) => e.title), n = F((e) => e.hideUI), r = F((e) => e.playbackError), i = F((e) => e.ready), a = F((e) => e.size), o = F((e) => e.waiting);
308
+ `, pe = (e) => e instanceof Error ? e.message : typeof e == "string" ? e : "Playback failed", me = ({ onCanvasRef: e }) => {
309
+ let t = P((e) => e.title), n = P((e) => e.hideUI), r = P((e) => e.playbackError), i = P((e) => e.ready), a = P((e) => e.size), o = P((e) => e.waiting);
310
310
  return /* @__PURE__ */ S(b, { children: [
311
311
  t ? /* @__PURE__ */ x("div", {
312
312
  className: "title",
313
- css: ce,
313
+ css: ue,
314
314
  style: { ...n ? {
315
315
  opacity: "0",
316
316
  pointerEvents: "none"
317
317
  } : {} },
318
318
  children: t
319
319
  }) : void 0,
320
- (a ? !i : o) && !r ? /* @__PURE__ */ x("div", { css: le }) : void 0,
320
+ (a ? !i : o) && !r ? /* @__PURE__ */ x("div", { css: de }) : void 0,
321
321
  r ? /* @__PURE__ */ x("div", {
322
- css: ue,
323
- children: de(r)
322
+ css: fe,
323
+ children: pe(r)
324
324
  }) : void 0,
325
325
  /* @__PURE__ */ x("canvas", {
326
326
  ref: e,
327
- css: se
327
+ css: le
328
328
  })
329
329
  ] });
330
- }, H = 1e-4, U = 1, W = (e) => Math.max(H, Math.min(U, e)) ** 2, G = (e) => Math.max(H, Math.min(U, e)) ** (U / 2), K = (e) => {
330
+ }, B = 1e-4, V = 1, H = (e) => Math.max(B, Math.min(V, e)) ** 2, U = (e) => Math.max(B, Math.min(V, e)) ** (V / 2), W = (e) => {
331
331
  if (e === void 0) return "0:00";
332
332
  let t = Math.floor(e / 3600), n = Math.floor(e % 3600 / 60), r = Math.floor(e % 60);
333
333
  return t > 0 ? `${t}:${n < 10 ? "0" : ""}${n}:${r < 10 ? "0" : ""}${r}` : `${n}:${r < 10 ? "0" : ""}${r}`;
334
- }, pe = (e, t) => `${K(e)} / ${K(t)}`, me = (e) => p`
334
+ }, he = (e, t) => `${W(e)} / ${W(t)}`, ge = (e) => p`
335
335
  display: flex;
336
336
  justify-content: flex-end;
337
337
 
@@ -341,7 +341,7 @@ var ne = {
341
341
  z-index: 3;
342
342
 
343
343
  * {
344
- ${V.bMedium.regular}
344
+ ${z.bMedium.regular}
345
345
  }
346
346
 
347
347
  ${e === "sm" && p`
@@ -353,7 +353,7 @@ var ne = {
353
353
  ${e === "lg" && p`
354
354
  padding: calc(1.2 * var(--mp-unit))!important;
355
355
  `}
356
- `, q = ({ id: e, toolTipText: t, text: n, delayShow: r = 0, closeDelay: i = 0, offset: a = 20, tooltipPlace: o = "top", disabled: s = !1, size: c = "md" }) => /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x("div", {
356
+ `, G = ({ id: e, toolTipText: t, text: n, delayShow: r = 0, closeDelay: i = 0, offset: a = 20, tooltipPlace: o = "top", disabled: s = !1, size: c = "md" }) => /* @__PURE__ */ S(b, { children: [/* @__PURE__ */ x("div", {
357
357
  "data-tooltip-id": e,
358
358
  "data-open": !0,
359
359
  "data-tooltip-offset": a,
@@ -361,12 +361,12 @@ var ne = {
361
361
  "data-tooltip-delay-hide": i,
362
362
  "data-tooltip-place": o,
363
363
  children: n
364
- }), !s && /* @__PURE__ */ x(te, {
365
- css: me(c),
364
+ }), !s && /* @__PURE__ */ x(ne, {
365
+ css: ge(c),
366
366
  id: e,
367
367
  noArrow: !0,
368
368
  children: t
369
- })] }), J = ({ ref: e, onChange: t, orientation: n = "horizontal", disabled: r = !1 }) => {
369
+ })] }), K = ({ ref: e, onChange: t, orientation: n = "horizontal", disabled: r = !1 }) => {
370
370
  let [i, a] = f(!1), o = d(t);
371
371
  o.current = t;
372
372
  let s = d(null), u = c((t, r) => {
@@ -393,7 +393,7 @@ var ne = {
393
393
  style: { touchAction: "none" }
394
394
  }
395
395
  };
396
- }, he = p`
396
+ }, _e = p`
397
397
  position: relative;
398
398
  height: calc(.4 * var(--mp-unit));
399
399
 
@@ -437,14 +437,28 @@ var ne = {
437
437
  display: flex;
438
438
  justify-content: center;
439
439
 
440
+ /* The seekbar's other hover affordance, the thumbnail below, gets a rounded box and a drop
441
+ shadow. A source that ships no thumbnails, which is every source whose media the player does
442
+ not own, leaves this readout as the entire preview, so it carries the same treatment instead
443
+ of sitting as bare text on the picture. The ink comes from the player root. */
444
+ background-color: rgba(28, 28, 28, .95);
445
+ border-radius: calc(.4 * var(--mp-unit));
446
+ padding: 0 calc(.6 * var(--mp-unit));
447
+ box-shadow: 0 0 calc(1 * var(--mp-unit)) rgba(0, 0, 0, .5);
448
+
440
449
  text-shadow: 0 0 4px rgba(0, 0, 0, 1);
441
- ${V.bMedium.bold}
450
+ ${z.bMedium.bold}
442
451
 
443
452
  position: absolute;
444
- top: calc(-2.5 * var(--mp-unit));
445
- width: calc(5 * var(--mp-unit));
453
+ /* Anchored on its bottom edge rather than its top: now that it has a background its height
454
+ follows the font size, and a top-anchored box would grow downward into the track. */
455
+ bottom: calc(1.2 * var(--mp-unit));
456
+ /* Sized to its content, replacing a fixed 5 unit box that \`1:04:09\` overflows. Transparent, that
457
+ overflow was invisible; filled, it would not be. */
458
+ width: max-content;
459
+ white-space: nowrap;
460
+ transform: translateX(-50%);
446
461
 
447
- margin-left: calc(-2.5 * var(--mp-unit));
448
462
  pointer-events: none;
449
463
  }
450
464
 
@@ -550,8 +564,8 @@ var ne = {
550
564
  --thumbnail-width: calc(18 * var(--mp-unit));
551
565
  --thumbnail-half: calc(9 * var(--mp-unit));
552
566
  }
553
- `, ge = () => {
554
- let e = F(), t = F((e) => e.currentTime), n = F((e) => e.duration), r = F((e) => e.size), i = F((e) => e.downloadedRanges), a = F((e) => e.indexes), o = F((e) => e.thumbnails), s = F((e) => e.thumbnailAt), c = d(null), [p, m] = f(void 0), [h, g] = f(void 0), _ = d(void 0), { dragging: v, handlers: y } = J({
567
+ `, ve = () => {
568
+ let e = P(), t = P((e) => e.currentTime), n = P((e) => e.duration), r = P((e) => e.size), i = P((e) => e.downloadedRanges), a = P((e) => e.indexes), o = P((e) => e.thumbnails), s = P((e) => e.thumbnailAt), c = d(null), [p, m] = f(void 0), [h, g] = f(void 0), _ = d(void 0), { dragging: v, handlers: y } = K({
555
569
  ref: c,
556
570
  onChange: (e) => {
557
571
  m(e), _.current !== "mouse" && g(e * n);
@@ -609,7 +623,7 @@ var ne = {
609
623
  h
610
624
  ]);
611
625
  return /* @__PURE__ */ S("div", {
612
- css: he,
626
+ css: _e,
613
627
  ref: c,
614
628
  className: v ? "progress-bar dragging" : "progress-bar",
615
629
  onMouseMove: T,
@@ -618,7 +632,7 @@ var ne = {
618
632
  /* @__PURE__ */ x("div", { className: "background-bar" }),
619
633
  h ? /* @__PURE__ */ x("div", {
620
634
  className: "cursor-time",
621
- style: { left: `clamp(calc(1.8 * var(--mp-unit)), ${D(h)}%, calc(100% - calc(1.8 * var(--mp-unit))))` },
635
+ style: { left: `clamp(calc(3 * var(--mp-unit)), ${D(h)}%, calc(100% - calc(3 * var(--mp-unit))))` },
622
636
  children: k
623
637
  }) : void 0,
624
638
  /* @__PURE__ */ x("div", { className: "progress" }),
@@ -650,7 +664,7 @@ var ne = {
650
664
  })
651
665
  ]
652
666
  });
653
- }, _e = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23fff'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20class='icon%20icon-tabler%20icons-tabler-outline%20icon-tabler-picture-in-picture'%3e%3cpath%20stroke='none'%20d='M0%200h24v24H0z'%20fill='none'%20/%3e%3cpath%20d='M11%2019h-6a2%202%200%200%201%20-2%20-2v-10a2%202%200%200%201%202%20-2h14a2%202%200%200%201%202%202v4'%20/%3e%3cpath%20d='M14%2014m0%201a1%201%200%200%201%201%20-1h5a1%201%200%200%201%201%201v3a1%201%200%200%201%20-1%201h-5a1%201%200%200%201%20-1%20-1z'%20/%3e%3c/svg%3e", ve = p`
667
+ }, ye = "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='24'%20height='24'%20viewBox='0%200%2024%2024'%20fill='none'%20stroke='%23fff'%20stroke-width='2'%20stroke-linecap='round'%20stroke-linejoin='round'%20class='icon%20icon-tabler%20icons-tabler-outline%20icon-tabler-picture-in-picture'%3e%3cpath%20stroke='none'%20d='M0%200h24v24H0z'%20fill='none'%20/%3e%3cpath%20d='M11%2019h-6a2%202%200%200%201%20-2%20-2v-10a2%202%200%200%201%202%20-2h14a2%202%200%200%201%202%202v4'%20/%3e%3cpath%20d='M14%2014m0%201a1%201%200%200%201%201%20-1h5a1%201%200%200%201%201%201v3a1%201%200%200%201%20-1%201h-5a1%201%200%200%201%20-1%20-1z'%20/%3e%3c/svg%3e", be = p`
654
668
  display: flex;
655
669
  align-items: center;
656
670
  justify-content: center;
@@ -703,8 +717,8 @@ width: 100%;
703
717
  }
704
718
  }
705
719
  }
706
- `, ye = () => {
707
- let e = F(), t = F((e) => e.playbackRate), n = d(null), r = d(null), i = .25, a = 3 - i, o = (e, t = .05) => Math.round(e / t) * t, s = o(t || 1), c = (e) => (e - i) / a * 100, u = (e) => o(i + e * a), { handlers: f } = J({
720
+ `, xe = () => {
721
+ let e = P(), t = P((e) => e.playbackRate), n = d(null), r = d(null), i = .25, a = 3 - i, o = (e, t = .05) => Math.round(e / t) * t, s = o(t || 1), c = (e) => (e - i) / a * 100, u = (e) => o(i + e * a), { handlers: f } = K({
708
722
  ref: r,
709
723
  onChange: (t) => e.setPlaybackRate(u(t))
710
724
  }), p = (t) => {
@@ -720,7 +734,7 @@ width: 100%;
720
734
  }, [t]);
721
735
  let m = c(s);
722
736
  return /* @__PURE__ */ S("div", {
723
- css: ve,
737
+ css: be,
724
738
  children: [/* @__PURE__ */ S("div", { children: [s.toFixed(2), "x"] }), /* @__PURE__ */ x("div", {
725
739
  className: "playback-slider",
726
740
  ref: n,
@@ -738,37 +752,38 @@ width: 100%;
738
752
  })
739
753
  })]
740
754
  });
741
- }, be = p`
742
- position: relative;
743
-
744
- .settings {
745
- /* the icon keeps its size, the pressable box grows around it */
746
- @media (pointer: coarse) {
747
- box-sizing: border-box;
748
- justify-content: center;
749
-
750
- min-width: 44px;
751
- min-height: 44px;
752
- }
753
- }
754
-
755
+ }, q = p`
755
756
  .popover {
756
757
  position: absolute;
757
- /* the gear sits a couple of buttons in from the right edge, so a centred popover hangs off that
758
- edge on a phone. It anchors to the button instead until the viewport has room to centre it. */
759
- right: 0;
760
- transform: none;
758
+ /* Anchored to the PLAYER's right edge, never to the gear. The gear is not the last control in the
759
+ bar, so a menu centred on it puts its own edges wherever the button happens to sit: with no
760
+ picture-in-picture button, which is every source whose media the player does not own, an edge
761
+ landed outside the box, and the root's \`overflow: hidden\` cut it off, taking the rows under it
762
+ out of reach. The inset matches the bar's own padding so the menu lines up with the last button. */
763
+ right: calc(12px + env(safe-area-inset-right, 0px));
764
+ bottom: calc(100% + 8px);
761
765
 
762
766
  overflow-y: auto;
763
767
  width: 180px;
764
- max-width: calc(100vw - 24px);
765
- height: 160px;
766
- top: -180px;
768
+ /* \`100%\` is the control bar, which is the width of the PLAYER. The old \`100vw\` was the viewport,
769
+ which equals the player only when the player is the whole document, and it is the wrong kind of
770
+ guard besides: a max-width shrinks the box, it never moves it back inside. */
771
+ max-width: calc(100% - 24px);
772
+ /* Sized to its rows, capped at what fits. A fixed height left the settings menu two thirds empty
773
+ once subtitles moved out to its own button, and a long track list scrolls at the cap either way. */
774
+ height: max-content;
775
+ /* The room actually above the bar. A short player had the top of the menu clipped by that same
776
+ \`overflow: hidden\`. With no size container in the ancestry this resolves against the small
777
+ viewport, so it can only ever shrink the box, never grow it. */
778
+ max-height: min(160px, calc(100cqh - 100% - 16px));
767
779
  @media (min-width: 768px) {
768
- right: 50%;
769
- transform: translateX(50%);
780
+ right: calc(16px + env(safe-area-inset-right, 0px));
770
781
  width: 250px;
771
- height: 160px;
782
+ max-width: calc(100% - 32px);
783
+ }
784
+ @media (min-width: 2560px) {
785
+ right: calc(24px + env(safe-area-inset-right, 0px));
786
+ max-width: calc(100% - 48px);
772
787
  }
773
788
 
774
789
  display: flex;
@@ -776,7 +791,7 @@ position: relative;
776
791
 
777
792
  border-radius: 8px;
778
793
  background-color: rgba(28,28,28,0.95);
779
- ${V.bMedium.regular}
794
+ ${z.bMedium.regular}
780
795
 
781
796
  z-index: 4;
782
797
 
@@ -819,7 +834,7 @@ position: relative;
819
834
 
820
835
  .secondary {
821
836
  color: #eee;
822
- ${V.bSmall.regular}
837
+ ${z.bSmall.regular}
823
838
  }
824
839
  }
825
840
  }
@@ -843,45 +858,6 @@ position: relative;
843
858
  }
844
859
  }
845
860
 
846
- .playback-rate {
847
- .slider {
848
- width: 100%;
849
- }
850
- .options {
851
- display: grid;
852
- grid-template-columns: 1fr 1fr 1fr 1fr;
853
- align-items: center;
854
-
855
- padding: 8px 12px;
856
- /* four presets across a 180px popover leave targets 34px wide, so a finger gets two rows of two
857
- until the popover is wide enough for the row of four */
858
- @media (pointer: coarse) {
859
- grid-template-columns: 1fr 1fr;
860
- }
861
- @media (pointer: coarse) and (min-width: 768px) {
862
- grid-template-columns: 1fr 1fr 1fr 1fr;
863
- }
864
-
865
- > div {
866
- display: flex;
867
- align-items: center;
868
- border-radius: 4px;
869
-
870
- padding: 8px 6px;
871
- height: 100%;
872
- @media (pointer: coarse) {
873
- box-sizing: border-box;
874
- min-height: 44px;
875
- }
876
-
877
- cursor: pointer;
878
- :hover {
879
- background-color: rgba(255,255,255,.1);
880
- }
881
- }
882
- }
883
- }
884
-
885
861
  .track-list {
886
862
  .description {
887
863
  word-break: break-word;
@@ -900,10 +876,10 @@ position: relative;
900
876
  .failed {
901
877
  border-bottom: 1px solid #4D4D4E;
902
878
  color: #f66;
903
- ${V.bSmall.regular}
879
+ ${z.bSmall.regular}
904
880
  }
905
881
  }
906
- `, Y = ({ title: e, tracks: t, selected: n, onSelect: r, onBack: i, offLabel: a, pending: o, failed: s }) => {
882
+ `, J = ({ title: e, tracks: t, selected: n, onSelect: r, onBack: i, offLabel: a, pending: o, failed: s }) => {
907
883
  let c = o !== void 0, l = (e, i, a) => {
908
884
  let s = c && o === e, l = c || t.find((t) => t.id === e)?.disabled;
909
885
  return /* @__PURE__ */ S("div", {
@@ -918,9 +894,9 @@ position: relative;
918
894
  className: "popover track-list",
919
895
  children: [
920
896
  /* @__PURE__ */ S("div", {
921
- className: "back",
897
+ className: i ? "back" : "back no-hover",
922
898
  onClick: i,
923
- children: [/* @__PURE__ */ x(C, {}), /* @__PURE__ */ x("span", { children: e })]
899
+ children: [i ? /* @__PURE__ */ x(C, {}) : null, /* @__PURE__ */ x("span", { children: e })]
924
900
  }),
925
901
  s ? /* @__PURE__ */ x("div", {
926
902
  className: "no-hover failed",
@@ -930,142 +906,278 @@ position: relative;
930
906
  t.map(({ id: e, label: t }) => l(e, t, "description"))
931
907
  ]
932
908
  });
933
- }, xe = () => {
934
- let e = F(), t = F((e) => e.playbackRate), n = F((e) => e.subtitleTracks), r = F((e) => e.selectedSubtitleTrack), i = F((e) => e.selectSubtitleTrack), a = F((e) => e.audioTracks), o = F((e) => e.selectedAudioTrack), s = F((e) => e.selectAudioTrack), c = F((e) => e.subtitleOffLabel), [u, p] = f(!1), [m, h] = f(0), g = d(null), [_, v] = f(void 0), [y, b] = f(!1), T = () => {
935
- p(!u), h(0), b(!1);
936
- }, E = () => {
937
- p(!1), h(0);
938
- }, D = (t) => {
939
- e.setPlaybackRate(t), h(0);
909
+ }, Y = ({ onReset: e } = {}) => {
910
+ let t = d(null), [n, r] = f(!1), [i, a] = f(void 0), [o, s] = f(!1), c = d(e);
911
+ c.current = e;
912
+ let u = () => {
913
+ r(!1), c.current?.();
940
914
  };
941
- l(() => {
915
+ return l(() => {
942
916
  let e = (e) => {
943
- u && g.current && !g.current.contains(e.target) && T();
917
+ n && t.current && !t.current.contains(e.target) && u();
944
918
  };
945
919
  return document.addEventListener("pointerdown", e), () => document.removeEventListener("pointerdown", e);
946
- }, [u]);
947
- let O = (e, t) => {
948
- if (_ !== void 0) return;
949
- b(!1);
950
- let n;
951
- try {
952
- n = t();
953
- } catch (e) {
954
- console.warn("[media-player] track selection failed:", e), b(!0);
955
- return;
956
- }
957
- if (!(n instanceof Promise)) {
958
- E();
959
- return;
920
+ }, [n]), {
921
+ open: n,
922
+ toggle: () => {
923
+ r((e) => !e), s(!1), c.current?.();
924
+ },
925
+ close: u,
926
+ containerRef: t,
927
+ pending: i,
928
+ failed: o,
929
+ runSelect: (e, t) => {
930
+ if (i !== void 0) return;
931
+ s(!1);
932
+ let n;
933
+ try {
934
+ n = t();
935
+ } catch (e) {
936
+ console.warn("[media-player] track selection failed:", e), s(!0);
937
+ return;
938
+ }
939
+ if (!(n instanceof Promise)) {
940
+ u();
941
+ return;
942
+ }
943
+ a(e), n.then(() => {
944
+ a(void 0), u();
945
+ }, (e) => {
946
+ console.warn("[media-player] track selection failed:", e), a(void 0), s(!0);
947
+ });
960
948
  }
961
- v(e), n.then(() => {
962
- v(void 0), E();
963
- }, (e) => {
964
- console.warn("[media-player] track selection failed:", e), v(void 0), b(!0);
965
- });
966
- }, k = (e) => O(e ?? null, () => i(e)), j = (e) => {
967
- e !== void 0 && O(e, () => s(e));
968
- }, M = (e) => () => {
969
- h(e);
949
+ };
950
+ }, Se = p`
951
+ /* Deliberately NOT a containing block. The menu anchors to the control bar instead, which is exactly
952
+ as wide as the player box and can therefore be clamped to it. The outside-click check uses
953
+ \`contains\` on the ref, which is DOM containment and needs no position, and the bar's other
954
+ tooltips already resolve against the control bar with no positioned wrapper of their own. */
955
+ position: static;
956
+
957
+ .settings {
958
+ /* the icon keeps its size, the pressable box grows around it */
959
+ @media (pointer: coarse) {
960
+ box-sizing: border-box;
961
+ justify-content: center;
962
+
963
+ min-width: 44px;
964
+ min-height: 44px;
965
+ }
966
+ }
967
+
968
+ ${q}
969
+
970
+ .playback-rate {
971
+ .slider {
972
+ width: 100%;
973
+ }
974
+ .options {
975
+ display: grid;
976
+ grid-template-columns: 1fr 1fr 1fr 1fr;
977
+ align-items: center;
978
+
979
+ padding: 8px 12px;
980
+ /* four presets across a 180px popover leave targets 34px wide, so a finger gets two rows of two
981
+ until the popover is wide enough for the row of four */
982
+ @media (pointer: coarse) {
983
+ grid-template-columns: 1fr 1fr;
984
+ }
985
+ @media (pointer: coarse) and (min-width: 768px) {
986
+ grid-template-columns: 1fr 1fr 1fr 1fr;
987
+ }
988
+
989
+ > div {
990
+ display: flex;
991
+ align-items: center;
992
+ border-radius: 4px;
993
+
994
+ padding: 8px 6px;
995
+ height: 100%;
996
+ @media (pointer: coarse) {
997
+ box-sizing: border-box;
998
+ min-height: 44px;
999
+ }
1000
+
1001
+ cursor: pointer;
1002
+ :hover {
1003
+ background-color: rgba(255,255,255,.1);
1004
+ }
1005
+ }
1006
+ }
1007
+ }
1008
+
1009
+ `, Ce = () => {
1010
+ let e = P(), t = P((e) => e.playbackRate), n = P((e) => e.audioTracks), r = P((e) => e.selectedAudioTrack), i = P((e) => e.selectAudioTrack), [a, o] = f(0), { open: s, toggle: c, containerRef: l, pending: u, failed: d, runSelect: p } = Y({ onReset: () => o(0) }), m = (t) => {
1011
+ e.setPlaybackRate(t), o(0);
1012
+ }, h = (e) => {
1013
+ e !== void 0 && p(e, () => i(e));
1014
+ }, g = (e) => () => {
1015
+ o(e);
970
1016
  };
971
1017
  return /* @__PURE__ */ S("div", {
972
- css: be,
973
- ref: g,
1018
+ css: Se,
1019
+ ref: l,
974
1020
  children: [
975
- /* @__PURE__ */ x(q, {
1021
+ /* @__PURE__ */ x(G, {
976
1022
  id: "settings",
977
- disabled: u,
1023
+ disabled: s,
978
1024
  text: /* @__PURE__ */ x("button", {
979
1025
  className: "settings",
980
1026
  type: "button",
981
- onClick: T,
1027
+ onClick: c,
982
1028
  children: /* @__PURE__ */ x(A, {})
983
1029
  }),
984
1030
  toolTipText: /* @__PURE__ */ x("span", { children: "Settings" })
985
1031
  }),
986
- u && m === 0 && /* @__PURE__ */ S("div", {
1032
+ s && a === 0 && /* @__PURE__ */ S("div", {
987
1033
  className: "popover menu",
988
- children: [
989
- a.length > 1 ? /* @__PURE__ */ S("div", {
990
- onClick: M(3),
991
- children: [/* @__PURE__ */ x("div", { children: "Audio" }), /* @__PURE__ */ x("div", { children: /* @__PURE__ */ x(w, {}) })]
992
- }) : null,
993
- n.length > 0 ? /* @__PURE__ */ S("div", {
994
- onClick: M(2),
995
- children: [/* @__PURE__ */ x("div", { children: "Subtitles" }), /* @__PURE__ */ x("div", { children: /* @__PURE__ */ x(w, {}) })]
996
- }) : null,
997
- /* @__PURE__ */ S("div", {
998
- onClick: M(1),
999
- children: [/* @__PURE__ */ x("div", { children: "Playback speed" }), /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("span", {
1000
- className: "secondary",
1001
- children: t === 1 ? "(Default)" : t.toFixed(2)
1002
- }), /* @__PURE__ */ x(w, {})] })]
1003
- })
1004
- ]
1034
+ children: [n.length > 1 ? /* @__PURE__ */ S("div", {
1035
+ onClick: g(2),
1036
+ children: [/* @__PURE__ */ x("div", { children: "Audio" }), /* @__PURE__ */ x("div", { children: /* @__PURE__ */ x(w, {}) })]
1037
+ }) : null, /* @__PURE__ */ S("div", {
1038
+ onClick: g(1),
1039
+ children: [/* @__PURE__ */ x("div", { children: "Playback speed" }), /* @__PURE__ */ S("div", { children: [/* @__PURE__ */ x("span", {
1040
+ className: "secondary",
1041
+ children: t === 1 ? "(Default)" : t.toFixed(2)
1042
+ }), /* @__PURE__ */ x(w, {})] })]
1043
+ })]
1005
1044
  }),
1006
- u && m === 1 && /* @__PURE__ */ S("div", {
1045
+ s && a === 1 && /* @__PURE__ */ S("div", {
1007
1046
  className: "popover playback-rate",
1008
1047
  children: [
1009
1048
  /* @__PURE__ */ S("div", {
1010
1049
  className: "back",
1011
- onClick: M(0),
1050
+ onClick: g(0),
1012
1051
  children: [/* @__PURE__ */ x(C, {}), /* @__PURE__ */ x("span", { children: "Playback speed" })]
1013
1052
  }),
1014
1053
  /* @__PURE__ */ x("div", {
1015
1054
  className: "slider no-hover",
1016
- children: /* @__PURE__ */ x(ye, {})
1055
+ children: /* @__PURE__ */ x(xe, {})
1017
1056
  }),
1018
1057
  /* @__PURE__ */ S("div", {
1019
1058
  className: "options no-hover",
1020
1059
  children: [
1021
1060
  /* @__PURE__ */ x("div", {
1022
- onClick: () => D(.5),
1061
+ onClick: () => m(.5),
1023
1062
  children: "0.5x"
1024
1063
  }),
1025
1064
  /* @__PURE__ */ x("div", {
1026
- onClick: () => D(1),
1065
+ onClick: () => m(1),
1027
1066
  children: "1x"
1028
1067
  }),
1029
1068
  /* @__PURE__ */ x("div", {
1030
- onClick: () => D(1.5),
1069
+ onClick: () => m(1.5),
1031
1070
  children: "1.5x"
1032
1071
  }),
1033
1072
  /* @__PURE__ */ x("div", {
1034
- onClick: () => D(2),
1073
+ onClick: () => m(2),
1035
1074
  children: "2x"
1036
1075
  })
1037
1076
  ]
1038
1077
  })
1039
1078
  ]
1040
1079
  }),
1041
- u && m === 2 && /* @__PURE__ */ x(Y, {
1042
- title: "Subtitles",
1080
+ s && a === 2 && /* @__PURE__ */ x(J, {
1081
+ title: "Audio",
1043
1082
  tracks: n,
1044
1083
  selected: r,
1045
- onSelect: k,
1046
- onBack: M(0),
1047
- offLabel: c ?? "Disable",
1048
- pending: _,
1049
- failed: y
1050
- }),
1051
- u && m === 3 && /* @__PURE__ */ x(Y, {
1052
- title: "Audio",
1053
- tracks: a,
1054
- selected: o,
1055
- onSelect: j,
1056
- onBack: M(0),
1057
- pending: _,
1058
- failed: y
1084
+ onSelect: h,
1085
+ onBack: g(0),
1086
+ pending: u,
1087
+ failed: d
1059
1088
  })
1060
1089
  ]
1061
1090
  });
1062
- }, Se = {
1091
+ }, X = {
1092
+ xmlns: "http://www.w3.org/2000/svg",
1093
+ width: 24,
1094
+ height: 24,
1095
+ viewBox: "0 0 24 24",
1096
+ fill: "none",
1097
+ stroke: "currentColor",
1098
+ strokeWidth: 2,
1099
+ strokeLinecap: "round",
1100
+ strokeLinejoin: "round"
1101
+ }, we = (e) => /* @__PURE__ */ S("svg", {
1102
+ ...X,
1103
+ ...e,
1104
+ children: [/* @__PURE__ */ x("rect", {
1105
+ x: "3",
1106
+ y: "5",
1107
+ width: "18",
1108
+ height: "14",
1109
+ rx: "2",
1110
+ ry: "2"
1111
+ }), /* @__PURE__ */ x("path", { d: "M7 15h4m4 0h2M7 11h2m4 0h4" })]
1112
+ }), Te = (e) => /* @__PURE__ */ S("svg", {
1113
+ ...X,
1114
+ ...e,
1115
+ children: [
1116
+ /* @__PURE__ */ x("rect", {
1117
+ x: "3",
1118
+ y: "5",
1119
+ width: "18",
1120
+ height: "14",
1121
+ rx: "2",
1122
+ ry: "2"
1123
+ }),
1124
+ /* @__PURE__ */ x("path", { d: "M7 15h4m4 0h2M7 11h2m4 0h4" }),
1125
+ /* @__PURE__ */ x("line", {
1126
+ x1: "2",
1127
+ y1: "2",
1128
+ x2: "22",
1129
+ y2: "22"
1130
+ })
1131
+ ]
1132
+ }), Ee = p`
1133
+ /* Not a containing block, for the reason given on popoverStyle: the menu anchors to the control bar,
1134
+ which is the width of the player box, so it can be clamped to it. */
1135
+ position: static;
1136
+
1137
+ .subtitles {
1138
+ /* the icon keeps its size, the pressable box grows around it */
1139
+ @media (pointer: coarse) {
1140
+ box-sizing: border-box;
1141
+ justify-content: center;
1142
+
1143
+ min-width: 44px;
1144
+ min-height: 44px;
1145
+ }
1146
+ }
1147
+
1148
+ ${q}
1149
+ `, De = () => {
1150
+ let e = P((e) => e.subtitleTracks), t = P((e) => e.selectedSubtitleTrack), n = P((e) => e.selectSubtitleTrack), r = P((e) => e.subtitleOffLabel), { open: i, toggle: a, containerRef: o, pending: s, failed: c, runSelect: l } = Y();
1151
+ return e.length === 0 ? null : /* @__PURE__ */ S("div", {
1152
+ css: Ee,
1153
+ ref: o,
1154
+ children: [/* @__PURE__ */ x(G, {
1155
+ id: "subtitles",
1156
+ disabled: i,
1157
+ text: /* @__PURE__ */ x("button", {
1158
+ className: "subtitles",
1159
+ type: "button",
1160
+ onClick: a,
1161
+ children: t === void 0 ? /* @__PURE__ */ x(Te, { className: "captions-off" }) : /* @__PURE__ */ x(we, { className: "captions" })
1162
+ }),
1163
+ toolTipText: /* @__PURE__ */ x("span", { children: "Subtitles" })
1164
+ }), i && /* @__PURE__ */ x(J, {
1165
+ title: "Subtitles",
1166
+ tracks: e,
1167
+ selected: t,
1168
+ onSelect: (e) => l(e ?? null, () => n(e)),
1169
+ offLabel: r ?? "Disable",
1170
+ pending: s,
1171
+ failed: c
1172
+ })]
1173
+ });
1174
+ }, Oe = {
1063
1175
  primary: "#EAEBEE",
1064
1176
  secondary: "#D0D0D9",
1065
1177
  hover: "rgba(255, 255, 255, 0.13)",
1066
1178
  borderPrimary: "#384F70",
1067
1179
  backgroundTooltip: "#222222"
1068
- }, Ce = p`
1180
+ }, ke = p`
1069
1181
  display: flex;
1070
1182
  align-items: center;
1071
1183
 
@@ -1108,8 +1220,8 @@ position: relative;
1108
1220
  width: 10px;
1109
1221
  height: 10px;
1110
1222
  }
1111
- `, we = ({ value: e, onChange: t }) => {
1112
- let n = F((e) => e.volume), r = F((e) => e.muted), i = d(null), a = d(null), { handlers: o } = J({
1223
+ `, Ae = ({ value: e, onChange: t }) => {
1224
+ let n = P((e) => e.volume), r = P((e) => e.muted), i = d(null), a = d(null), { handlers: o } = K({
1113
1225
  ref: a,
1114
1226
  onChange: t
1115
1227
  }), s = (n) => {
@@ -1123,12 +1235,12 @@ position: relative;
1123
1235
  e && e.removeEventListener("wheel", s);
1124
1236
  };
1125
1237
  }, [e]);
1126
- let c = e * 100, f = u(() => Math.round(r ? 0 : G(n) * 100), [n, r]);
1127
- return /* @__PURE__ */ x(q, {
1238
+ let c = e * 100, f = u(() => Math.round(r ? 0 : U(n) * 100), [n, r]);
1239
+ return /* @__PURE__ */ x(G, {
1128
1240
  id: "volume-slider",
1129
1241
  text: /* @__PURE__ */ x("div", {
1130
1242
  ref: i,
1131
- css: Ce,
1243
+ css: ke,
1132
1244
  ...o,
1133
1245
  children: /* @__PURE__ */ x("div", {
1134
1246
  ref: a,
@@ -1147,7 +1259,7 @@ position: relative;
1147
1259
  children: [f, "%"]
1148
1260
  })
1149
1261
  });
1150
- }, Te = p`
1262
+ }, je = p`
1151
1263
  position: relative;
1152
1264
  display: flex;
1153
1265
  align-items: center;
@@ -1172,7 +1284,7 @@ position: relative;
1172
1284
  border-radius: 4px;
1173
1285
 
1174
1286
  .volume-value {
1175
- ${V.bMedium.regular};
1287
+ ${z.bMedium.regular};
1176
1288
  color: #ffffff;
1177
1289
  }
1178
1290
  }
@@ -1210,18 +1322,18 @@ position: relative;
1210
1322
  }
1211
1323
  }
1212
1324
 
1213
- `, Ee = ({ ref: e }) => {
1214
- let t = F(), n = F((e) => e.volume), r = F((e) => e.muted), i = u(() => G(n), [n]);
1325
+ `, Me = ({ ref: e }) => {
1326
+ let t = P(), n = P((e) => e.volume), r = P((e) => e.muted), i = u(() => U(n), [n]);
1215
1327
  return /* @__PURE__ */ S("div", {
1216
- css: Te,
1217
- children: [/* @__PURE__ */ x(q, {
1328
+ css: je,
1329
+ children: [/* @__PURE__ */ x(G, {
1218
1330
  id: "sound",
1219
1331
  text: /* @__PURE__ */ x("button", {
1220
1332
  className: "sound",
1221
1333
  type: "button",
1222
1334
  onClick: () => t.toggleMuted(),
1223
1335
  ref: e,
1224
- children: x(r || n === 0 ? ee : n <= .5 ? j : M, {
1336
+ children: x(r || n === 0 ? te : n <= .5 ? j : ee, {
1225
1337
  size: 18,
1226
1338
  color: "#fff"
1227
1339
  })
@@ -1231,16 +1343,16 @@ position: relative;
1231
1343
  className: "volume-slider-container",
1232
1344
  children: /* @__PURE__ */ x("div", {
1233
1345
  className: "volume-slider-background",
1234
- children: /* @__PURE__ */ x(we, {
1346
+ children: /* @__PURE__ */ x(Ae, {
1235
1347
  value: r ? 0 : i,
1236
1348
  onChange: (e) => {
1237
- t.setVolume(W(e));
1349
+ t.setVolume(H(e));
1238
1350
  }
1239
1351
  })
1240
1352
  })
1241
1353
  })]
1242
1354
  });
1243
- }, X = .05, Z = 5, De = p`
1355
+ }, Z = .05, Q = 5, Ne = p`
1244
1356
  position: absolute;
1245
1357
  bottom: 0;
1246
1358
  width: 100%;
@@ -1292,7 +1404,7 @@ position: relative;
1292
1404
  }
1293
1405
  }
1294
1406
 
1295
- .play, .sound, .time, .settings, .picture-in-picture, .full-screen {
1407
+ .play, .sound, .time, .subtitles, .settings, .picture-in-picture, .full-screen {
1296
1408
  display: flex;
1297
1409
  align-items: center;
1298
1410
 
@@ -1310,7 +1422,7 @@ position: relative;
1310
1422
  }
1311
1423
  }
1312
1424
 
1313
- .play, .sound, .settings, .picture-in-picture, .full-screen {
1425
+ .play, .sound, .subtitles, .settings, .picture-in-picture, .full-screen {
1314
1426
  border-radius: 4px;
1315
1427
 
1316
1428
  padding: 8px;
@@ -1324,7 +1436,7 @@ position: relative;
1324
1436
  cursor: pointer;
1325
1437
 
1326
1438
  :hover {
1327
- background-color: ${Se.hover};
1439
+ background-color: ${Oe.hover};
1328
1440
  }
1329
1441
 
1330
1442
  /* the hit area grows, the icon does not, keyed on the pointer because a narrow desktop
@@ -1341,7 +1453,7 @@ position: relative;
1341
1453
 
1342
1454
  .left {
1343
1455
  .time {
1344
- ${V.bMedium.regular}
1456
+ ${z.bMedium.regular}
1345
1457
  text-shadow: 0 0 4px rgba(0, 0, 0, 1);
1346
1458
  }
1347
1459
  }
@@ -1362,10 +1474,10 @@ position: relative;
1362
1474
  }
1363
1475
  }
1364
1476
  }
1365
- `, Oe = () => {
1366
- let e = F(), t = F((e) => e.paused), n = F((e) => e.currentTime), r = F((e) => e.duration), i = F((e) => e.fullscreen), a = F((e) => e.hideUI), o = F((e) => e.togglePictureInPicture), [s, u] = f(null), d = r > 0 && n === r, p = c(({ direction: t, stepSize: n }) => {
1367
- let r = G(e.volume), i = t === "up" ? n : -n, a = Math.max(0, Math.min(1, r + i)), o = e.muted;
1368
- e.setVolume(W(a)), o && !e.muted && e.toggleMuted();
1477
+ `, Pe = () => {
1478
+ let e = P(), t = P((e) => e.paused), n = P((e) => e.currentTime), r = P((e) => e.duration), i = P((e) => e.fullscreen), a = P((e) => e.hideUI), o = P((e) => e.togglePictureInPicture), [s, u] = f(null), d = r > 0 && n === r, p = c(({ direction: t, stepSize: n }) => {
1479
+ let r = U(e.volume), i = t === "up" ? n : -n, a = Math.max(0, Math.min(1, r + i)), o = e.muted;
1480
+ e.setVolume(H(a)), o && !e.muted && e.toggleMuted();
1369
1481
  }, [e]);
1370
1482
  l(() => {
1371
1483
  let t = (t) => {
@@ -1378,16 +1490,16 @@ position: relative;
1378
1490
  else if (t.key === "m") e.toggleMuted();
1379
1491
  else if (t.key === "ArrowUp") p({
1380
1492
  direction: "up",
1381
- stepSize: X
1493
+ stepSize: Z
1382
1494
  });
1383
1495
  else if (t.key === "ArrowDown") p({
1384
1496
  direction: "down",
1385
- stepSize: X
1497
+ stepSize: Z
1386
1498
  });
1387
1499
  else if (t.key === "ArrowRight") {
1388
1500
  if (!e.duration) return;
1389
- e.seek(Math.min(e.currentTime + Z, e.duration));
1390
- } else t.key === "ArrowLeft" ? e.seek(Math.max(e.currentTime - Z, 0)) : r = !1;
1501
+ e.seek(Math.min(e.currentTime + Q, e.duration));
1502
+ } else t.key === "ArrowLeft" ? e.seek(Math.max(e.currentTime - Q, 0)) : r = !1;
1391
1503
  r && t.preventDefault();
1392
1504
  };
1393
1505
  return window.addEventListener("keydown", t), () => window.removeEventListener("keydown", t);
@@ -1395,26 +1507,26 @@ position: relative;
1395
1507
  let m = c((e) => {
1396
1508
  e.preventDefault(), e.deltaY < 0 ? p({
1397
1509
  direction: "up",
1398
- stepSize: X
1510
+ stepSize: Z
1399
1511
  }) : p({
1400
1512
  direction: "down",
1401
- stepSize: X
1513
+ stepSize: Z
1402
1514
  });
1403
1515
  }, [p]);
1404
1516
  return l(() => {
1405
1517
  if (s) return s.addEventListener("wheel", m, { passive: !1 }), () => s.removeEventListener("wheel", m);
1406
1518
  }, [s, m]), /* @__PURE__ */ S("div", {
1407
- css: De,
1519
+ css: Ne,
1408
1520
  style: { ...a ? {
1409
1521
  opacity: "0",
1410
1522
  pointerEvents: "none"
1411
1523
  } : {} },
1412
- children: [/* @__PURE__ */ x(ge, {}), /* @__PURE__ */ S("div", {
1524
+ children: [/* @__PURE__ */ x(ve, {}), /* @__PURE__ */ S("div", {
1413
1525
  className: "actions",
1414
1526
  children: [/* @__PURE__ */ S("div", {
1415
1527
  className: "left",
1416
1528
  children: [
1417
- /* @__PURE__ */ x(q, {
1529
+ /* @__PURE__ */ x(G, {
1418
1530
  id: "play",
1419
1531
  tooltipPlace: "top-start",
1420
1532
  text: /* @__PURE__ */ x("button", {
@@ -1425,27 +1537,28 @@ position: relative;
1425
1537
  }),
1426
1538
  toolTipText: /* @__PURE__ */ x("span", { children: d ? "Replay (k)" : t ? "Play (k)" : "Pause (k)" })
1427
1539
  }),
1428
- /* @__PURE__ */ x(Ee, { ref: u }),
1540
+ /* @__PURE__ */ x(Me, { ref: u }),
1429
1541
  /* @__PURE__ */ x("div", {
1430
1542
  className: "time",
1431
- children: pe(n, r)
1543
+ children: he(n, r)
1432
1544
  })
1433
1545
  ]
1434
1546
  }), /* @__PURE__ */ S("div", {
1435
1547
  className: "right",
1436
1548
  children: [
1437
- /* @__PURE__ */ x(xe, {}),
1438
- o ? /* @__PURE__ */ x(q, {
1549
+ /* @__PURE__ */ x(De, {}),
1550
+ /* @__PURE__ */ x(Ce, {}),
1551
+ o ? /* @__PURE__ */ x(G, {
1439
1552
  id: "picture-in-picture",
1440
1553
  text: /* @__PURE__ */ x("button", {
1441
1554
  className: "picture-in-picture",
1442
1555
  type: "button",
1443
1556
  onClick: o,
1444
- children: /* @__PURE__ */ x("img", { src: _e })
1557
+ children: /* @__PURE__ */ x("img", { src: ye })
1445
1558
  }),
1446
1559
  toolTipText: /* @__PURE__ */ x("span", { children: "Picture in picture" })
1447
1560
  }) : null,
1448
- /* @__PURE__ */ x(q, {
1561
+ /* @__PURE__ */ x(G, {
1449
1562
  id: "full-screen",
1450
1563
  tooltipPlace: "top-end",
1451
1564
  text: /* @__PURE__ */ x("button", {
@@ -1460,7 +1573,7 @@ position: relative;
1460
1573
  })]
1461
1574
  })]
1462
1575
  });
1463
- }, ke = 3e3, Ae = p`
1576
+ }, Fe = 3e3, Ie = p`
1464
1577
  position: absolute;
1465
1578
  inset: 0;
1466
1579
  z-index: 2;
@@ -1471,7 +1584,7 @@ position: relative;
1471
1584
  hoverable while faded out, popping a tooltip over nothing. It cascades where pointer-events does
1472
1585
  not, and transitioning it holds the item on screen for the length of the fade. */
1473
1586
  transition: opacity 0.1s cubic-bezier(.4,0,1,1), visibility 0.1s;
1474
- `, je = p`
1587
+ `, Le = p`
1475
1588
  position: relative;
1476
1589
  background-color: black;
1477
1590
  display: flex;
@@ -1503,20 +1616,20 @@ position: relative;
1503
1616
  &.hide {
1504
1617
  cursor: none;
1505
1618
  }
1506
- `, Q = (e, t = "") => a.toArray(e).flatMap((e, n) => {
1619
+ `, $ = (e, t = "") => a.toArray(e).flatMap((e, n) => {
1507
1620
  let r = `${t}${s(e) && e.key != null ? e.key : n}`;
1508
- return s(e) && e.type === o ? Q(e.props.children, `${r}/`) : [{
1621
+ return s(e) && e.type === o ? $(e.props.children, `${r}/`) : [{
1509
1622
  key: r,
1510
1623
  item: e
1511
1624
  }];
1512
- }), Me = ({ ref: e, onVideoRef: t, onCanvasRef: n, overlay: r, controls: i, children: a }) => {
1513
- let o = F(), s = F((e) => e.hideUI), c = F((e) => e.setHideUI), u = d(void 0), f = d("mouse");
1625
+ }), Re = ({ ref: e, onVideoRef: t, onCanvasRef: n, overlay: r, controls: i, children: a }) => {
1626
+ let o = P(), s = P((e) => e.hideUI), c = P((e) => e.setHideUI), u = d(void 0), f = d("mouse");
1514
1627
  l(() => () => clearTimeout(u.current), []);
1515
1628
  let p = () => {
1516
- c(!1), clearTimeout(u.current), u.current = setTimeout(() => c(!0), ke);
1629
+ c(!1), clearTimeout(u.current), u.current = setTimeout(() => c(!0), Fe);
1517
1630
  };
1518
1631
  return /* @__PURE__ */ S("div", {
1519
- css: je,
1632
+ css: Le,
1520
1633
  ref: e,
1521
1634
  onPointerMove: (e) => {
1522
1635
  f.current = e.pointerType, e.pointerType === "mouse" && p();
@@ -1532,9 +1645,9 @@ position: relative;
1532
1645
  },
1533
1646
  className: s ? "hide" : "",
1534
1647
  children: [
1535
- /* @__PURE__ */ x(fe, { onCanvasRef: n }),
1536
- Q(r).map(({ key: e, item: t }) => /* @__PURE__ */ x("div", {
1537
- css: Ae,
1648
+ /* @__PURE__ */ x(me, { onCanvasRef: n }),
1649
+ $(r).map(({ key: e, item: t }) => /* @__PURE__ */ x("div", {
1650
+ css: Ie,
1538
1651
  style: { ...s ? {
1539
1652
  opacity: "0",
1540
1653
  visibility: "hidden",
@@ -1542,7 +1655,7 @@ position: relative;
1542
1655
  } : {} },
1543
1656
  children: t
1544
1657
  }, e)),
1545
- i === !1 ? null : /* @__PURE__ */ x(Oe, {}),
1658
+ i === !1 ? null : /* @__PURE__ */ x(Pe, {}),
1546
1659
  /* @__PURE__ */ S("div", {
1547
1660
  className: "video",
1548
1661
  onClick: () => {
@@ -1559,16 +1672,16 @@ position: relative;
1559
1672
  })
1560
1673
  ]
1561
1674
  });
1562
- }, Ne = ({ options: e, children: t }) => {
1675
+ }, ze = ({ options: e, children: t }) => {
1563
1676
  let n = "media" in e ? e : null, r = n ? null : e, { title: i } = e, { size: a, downloadedRanges: o, publicPath: s, libavWorkerUrl: c, read: u, thumbnailRead: d, thumbnailsEnabled: p } = r ?? {}, m = _(), h = g(), [v, y] = f(null), [b, S] = f(null), C = n?.media ?? v;
1564
- l(() => (m?.(C), () => m?.(null)), [C, m]), ie(v, b, r);
1565
- let w = z({
1677
+ l(() => (m?.(C), () => m?.(null)), [C, m]), oe(v, b, r);
1678
+ let w = L({
1566
1679
  publicPath: s,
1567
1680
  workerUrl: c,
1568
1681
  length: p === !1 ? void 0 : a,
1569
1682
  read: d ?? u,
1570
1683
  downloadedRanges: o
1571
- }), T = n?.thumbnails?.all ?? w, E = B(v, b), D = F((e) => e.setSourceState);
1684
+ }), T = n?.thumbnails?.all ?? w, E = R(v, b), D = P((e) => e.setSourceState);
1572
1685
  l(() => {
1573
1686
  D({
1574
1687
  title: i,
@@ -1616,7 +1729,7 @@ position: relative;
1616
1729
  selectedAudioTrack: A.selectedId ?? void 0,
1617
1730
  selectAudioTrack: (e) => A.select(String(e))
1618
1731
  });
1619
- }, [D, A]), /* @__PURE__ */ x(Me, {
1732
+ }, [D, A]), /* @__PURE__ */ x(Re, {
1620
1733
  ref: h,
1621
1734
  onVideoRef: n ? void 0 : y,
1622
1735
  onCanvasRef: S,
@@ -1624,7 +1737,7 @@ position: relative;
1624
1737
  controls: e.controls,
1625
1738
  children: t
1626
1739
  });
1627
- }, Pe = p`
1740
+ }, Be = p`
1628
1741
  /**
1629
1742
  * The chrome's whole scale, in one place.
1630
1743
  *
@@ -1636,6 +1749,45 @@ position: relative;
1636
1749
  */
1637
1750
  --mp-unit: 10px;
1638
1751
 
1752
+ /**
1753
+ * The chrome's own typeface, for exactly the reason the unit above exists.
1754
+ *
1755
+ * \`font-family\` inherits, and this library declared it nowhere, so every label drew in whatever the
1756
+ * embedding document happened to set, and in the UA's serif where it set nothing. Not hypothetical:
1757
+ * stub mounts the player in a second document, \`embed.html\`, which sets no font and loads no face,
1758
+ * and the entire settings menu came out in Times New Roman.
1759
+ *
1760
+ * Named faces only, no bundled webfont. The chrome is a handful of short labels, so a font request
1761
+ * on the critical path of a document whose job is to paint video buys a round trip and a flash of
1762
+ * unstyled text for nothing.
1763
+ *
1764
+ * Read through \`var()\` so a host with a brand face sets \`--mp-font-family\` on any ancestor and it
1765
+ * inherits in. A bare \`font-family\` on the host can no longer reach the chrome: this declaration is
1766
+ * on the player element itself and beats anything inherited.
1767
+ */
1768
+ font-family: var(
1769
+ --mp-font-family,
1770
+ system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif,
1771
+ 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji'
1772
+ );
1773
+
1774
+ /**
1775
+ * The chrome's default ink, same argument again.
1776
+ *
1777
+ * Most text here names its own colour, but the two time readouts do not: the elapsed/duration pair
1778
+ * and the seekbar's hover time carry a font token and a black text-shadow and nothing else.
1779
+ * Inherited from a host that declares none that resolves to \`canvastext\`, which is black text under
1780
+ * a black halo on a dark gradient.
1781
+ */
1782
+ color: #fff;
1783
+
1784
+ /**
1785
+ * The settings menu scrolls, and a UA that has not been told the surface is dark paints that
1786
+ * scrollbar in its light theme: a white track down the side of a #1c1c1c menu. Declared here rather
1787
+ * than asked of the host, so it reaches the menu and nothing outside the player.
1788
+ */
1789
+ color-scheme: dark;
1790
+
1639
1791
  /**
1640
1792
  * The other half of owning the chrome's own scale.
1641
1793
  *
@@ -1655,17 +1807,17 @@ position: relative;
1655
1807
  height: 100%;
1656
1808
  width: 100%;
1657
1809
  overflow: hidden;
1658
- `, $ = (e) => /* @__PURE__ */ x("div", {
1659
- css: Pe,
1660
- children: /* @__PURE__ */ x(P.Provider, { children: /* @__PURE__ */ x(Ne, {
1810
+ `, Ve = (e) => /* @__PURE__ */ x("div", {
1811
+ css: Be,
1812
+ children: /* @__PURE__ */ x(N.Provider, { children: /* @__PURE__ */ x(ze, {
1661
1813
  options: e,
1662
1814
  children: e.children
1663
1815
  }) })
1664
- }), Fe = (e) => !!e && typeof e == "object" && "at" in e, Ie = (e) => !!e && typeof e == "object" && "selection" in e, Le = ({ blob: e, name: t }) => ({
1816
+ }), He = (e) => !!e && typeof e == "object" && "at" in e, Ue = (e) => !!e && typeof e == "object" && "selection" in e, We = ({ blob: e, name: t }) => ({
1665
1817
  length: e.size,
1666
1818
  name: t ?? (e instanceof File ? e.name : void 0),
1667
1819
  read: (t, n) => e.slice(t, t + n).arrayBuffer()
1668
- }), Re = async (e, t) => {
1820
+ }), Ge = async (e, t) => {
1669
1821
  let n = await fetch(e, {
1670
1822
  headers: { Range: "bytes=0-1" },
1671
1823
  credentials: t
@@ -1675,8 +1827,8 @@ position: relative;
1675
1827
  if (!Number.isFinite(i) || i <= 0) throw Error("The source did not report its length");
1676
1828
  if (!r && n.status !== 206) throw Error("The source does not support range requests");
1677
1829
  return i;
1678
- }, ze = async ({ url: e, length: t, name: n, credentials: r }) => {
1679
- let i = t ?? await Re(e, r);
1830
+ }, Ke = async ({ url: e, length: t, name: n, credentials: r }) => {
1831
+ let i = t ?? await Ge(e, r);
1680
1832
  return {
1681
1833
  length: i,
1682
1834
  name: n,
@@ -1689,9 +1841,9 @@ position: relative;
1689
1841
  return a.arrayBuffer();
1690
1842
  }
1691
1843
  };
1692
- }, Be = async (e) => {
1693
- if ("blob" in e) return Le(e);
1694
- if ("url" in e) return ze(e);
1844
+ }, qe = async (e) => {
1845
+ if ("blob" in e) return We(e);
1846
+ if ("url" in e) return Ke(e);
1695
1847
  if ("read" in e) return {
1696
1848
  length: e.length,
1697
1849
  name: e.name,
@@ -1700,4 +1852,4 @@ position: relative;
1700
1852
  throw Error(`Unknown source type: ${e}`);
1701
1853
  };
1702
1854
  //#endregion
1703
- export { $ as MediaPlayer, $ as default, P as Player, n as SUBTITLES_OFF, i as createPictureInPicture, r as createSubtitleRenderer, t as createThumbnailGenerator, Be as inputToRemuxerInput, Ie as isDelegatedTracks, Fe as isExternalThumbnails, N as sourceFeature, e as startPlayback, B as usePictureInPicture, F as usePlayer, z as useSeekThumbnails };
1855
+ export { Ve as MediaPlayer, Ve as default, N as Player, n as SUBTITLES_OFF, i as createPictureInPicture, r as createSubtitleRenderer, t as createThumbnailGenerator, qe as inputToRemuxerInput, Ue as isDelegatedTracks, He as isExternalThumbnails, M as sourceFeature, e as startPlayback, R as usePictureInPicture, P as usePlayer, L as useSeekThumbnails };