@hanifhan1f/vidstack 1.12.34 → 1.12.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/cdn/with-layouts/chunks/{vidstack-BCLumCST.js → vidstack-BEgmmcDO.js} +56 -52
  2. package/cdn/with-layouts/chunks/{vidstack-DJyGEdCH.js → vidstack-t3PBZMbl.js} +1 -1
  3. package/cdn/with-layouts/vidstack.js +1 -1
  4. package/dev/chunks/{vidstack-B__DfQsT.js → vidstack-BReSQAMt.js} +10 -6
  5. package/dev/define/templates/vidstack-audio-layout.js +1 -1
  6. package/dev/define/templates/vidstack-video-layout.js +7 -5
  7. package/dev/define/vidstack-player-default-layout.js +1 -1
  8. package/dev/define/vidstack-player-layouts.js +1 -1
  9. package/dev/vidstack-elements.js +1 -1
  10. package/dev/vidstack.js +0 -4
  11. package/elements.d.ts +1 -1
  12. package/global/player.d.ts +1 -1
  13. package/global/plyr.d.ts +2 -2
  14. package/index.d.ts +2 -2
  15. package/package.json +1 -1
  16. package/prod/chunks/{vidstack-BnEo_Sla.js → vidstack-B0glDgAI.js} +10 -6
  17. package/prod/define/templates/vidstack-audio-layout.js +1 -1
  18. package/prod/define/templates/vidstack-video-layout.js +7 -5
  19. package/prod/define/vidstack-player-default-layout.js +1 -1
  20. package/prod/define/vidstack-player-layouts.js +1 -1
  21. package/prod/vidstack-elements.js +1 -1
  22. package/server/chunks/{vidstack-BIGdJnUK.js → vidstack-nANS1jfu.js} +16 -10
  23. package/server/define/vidstack-player-default-layout.js +1 -1
  24. package/server/define/vidstack-player-layouts.js +1 -1
  25. package/server/vidstack-elements.js +1 -1
  26. package/types/{vidstack-DYLKXUvI.d.ts → vidstack-CZqFq0VF.d.ts} +13 -1
  27. package/cdn/chunks/vidstack-8JHLDxl5.js +0 -1
  28. package/cdn/chunks/vidstack-BF7lZRtq.js +0 -3
  29. package/cdn/chunks/vidstack-BYgY9wmd.js +0 -1
  30. package/cdn/chunks/vidstack-BYpysj84.js +0 -1
  31. package/cdn/chunks/vidstack-Bjo5esRp.js +0 -1
  32. package/cdn/chunks/vidstack-BkxGdzTJ.js +0 -16
  33. package/cdn/chunks/vidstack-BuL67v3q.js +0 -1
  34. package/cdn/chunks/vidstack-Bzk6lVKb.js +0 -1
  35. package/cdn/chunks/vidstack-C0msPRTd.js +0 -3
  36. package/cdn/chunks/vidstack-C1FlyyzK.js +0 -1
  37. package/cdn/chunks/vidstack-CIjxJCz3.js +0 -1
  38. package/cdn/chunks/vidstack-CioT3Yw2.js +0 -1
  39. package/cdn/chunks/vidstack-Cj0I-Rec.js +0 -1
  40. package/cdn/chunks/vidstack-CmpbA3Yd.js +0 -16
  41. package/cdn/chunks/vidstack-CnWKPIKT.js +0 -16
  42. package/cdn/chunks/vidstack-CrqkytHl.js +0 -1
  43. package/cdn/chunks/vidstack-D0M8R0ZU.js +0 -1
  44. package/cdn/chunks/vidstack-D40FSa5B.js +0 -3
  45. package/cdn/chunks/vidstack-D84Fzc__.js +0 -16
  46. package/cdn/chunks/vidstack-DD2JwFVU.js +0 -1
  47. package/cdn/chunks/vidstack-DQvyz7Mm.js +0 -1
  48. package/cdn/chunks/vidstack-Dd9fqVv6.js +0 -1
  49. package/cdn/chunks/vidstack-DfDZuHNP.js +0 -1
  50. package/cdn/chunks/vidstack-uMxrPflF.js +0 -1
  51. package/cdn/chunks/vidstack-xjJ-ui_l.js +0 -1
  52. package/cdn/chunks/vidstack-zemsqC5d.js +0 -1
  53. package/cdn/providers/vidstack-audio-2Dt_Ivbp.js +0 -1
  54. package/cdn/providers/vidstack-audio-BOGYlExy.js +0 -1
  55. package/cdn/providers/vidstack-dash-CUtD4e6q.js +0 -1
  56. package/cdn/providers/vidstack-dash-D4ZARr66.js +0 -1
  57. package/cdn/providers/vidstack-google-cast-BdORATUX.js +0 -1
  58. package/cdn/providers/vidstack-hls-8-552IuX.js +0 -1
  59. package/cdn/providers/vidstack-hls-R25Kb6DP.js +0 -1
  60. package/cdn/providers/vidstack-html-BvVaN2VT.js +0 -1
  61. package/cdn/providers/vidstack-html-DaAUJYsD.js +0 -1
  62. package/cdn/providers/vidstack-video-BnwQZKER.js +0 -1
  63. package/cdn/providers/vidstack-video-Csvox7SO.js +0 -1
  64. package/cdn/providers/vidstack-vimeo-D4Z96kg2.js +0 -1
  65. package/cdn/providers/vidstack-vimeo-gJmBqtLK.js +0 -1
  66. package/cdn/providers/vidstack-youtube-Chl_dTAz.js +0 -1
  67. package/cdn/providers/vidstack-youtube-DiND6h3s.js +0 -1
  68. package/cdn/with-layouts/chunks/vidstack-4liSokT6.js +0 -1
  69. package/cdn/with-layouts/chunks/vidstack-B97B8XDc.js +0 -3
  70. package/cdn/with-layouts/chunks/vidstack-BD5YoTt5.js +0 -937
  71. package/cdn/with-layouts/chunks/vidstack-BGhRKayG.js +0 -914
  72. package/cdn/with-layouts/chunks/vidstack-BL_lNyW_.js +0 -1
  73. package/cdn/with-layouts/chunks/vidstack-BMhNagfl.js +0 -1
  74. package/cdn/with-layouts/chunks/vidstack-BP3ybDy9.js +0 -912
  75. package/cdn/with-layouts/chunks/vidstack-BbFHhcVG.js +0 -1
  76. package/cdn/with-layouts/chunks/vidstack-BjOOdDcQ.js +0 -1
  77. package/cdn/with-layouts/chunks/vidstack-C5AP9wid.js +0 -1
  78. package/cdn/with-layouts/chunks/vidstack-CS2aNc61.js +0 -1
  79. package/cdn/with-layouts/chunks/vidstack-CXEcXyBI.js +0 -1
  80. package/cdn/with-layouts/chunks/vidstack-Ciq-n5rg.js +0 -1
  81. package/cdn/with-layouts/chunks/vidstack-CmuGllcj.js +0 -1
  82. package/cdn/with-layouts/chunks/vidstack-CyNByJUW.js +0 -912
  83. package/cdn/with-layouts/chunks/vidstack-D-3_fAsK.js +0 -1
  84. package/cdn/with-layouts/chunks/vidstack-DCaNJN4T.js +0 -1
  85. package/cdn/with-layouts/chunks/vidstack-DKqYI_HJ.js +0 -1
  86. package/cdn/with-layouts/chunks/vidstack-DLGH9jfs.js +0 -1
  87. package/cdn/with-layouts/chunks/vidstack-DLVdcWrK.js +0 -3
  88. package/cdn/with-layouts/chunks/vidstack-DPO7J4-v.js +0 -3
  89. package/cdn/with-layouts/chunks/vidstack-DWjB11vV.js +0 -1
  90. package/cdn/with-layouts/chunks/vidstack-Dd3L-eQj.js +0 -1
  91. package/cdn/with-layouts/chunks/vidstack-Dh2GOjra.js +0 -1
  92. package/cdn/with-layouts/chunks/vidstack-DhNpv7SU.js +0 -1
  93. package/cdn/with-layouts/chunks/vidstack-QW5tTAS4.js +0 -897
  94. package/cdn/with-layouts/chunks/vidstack-T2rZVigk.js +0 -912
  95. package/cdn/with-layouts/chunks/vidstack-Xe_d7ovA.js +0 -1
  96. package/cdn/with-layouts/chunks/vidstack-wt2OT4N7.js +0 -1
  97. package/cdn/with-layouts/providers/vidstack-audio-Bw1csc6N.js +0 -1
  98. package/cdn/with-layouts/providers/vidstack-audio-CwoQJvl2.js +0 -1
  99. package/cdn/with-layouts/providers/vidstack-dash-CJsKJfLI.js +0 -1
  100. package/cdn/with-layouts/providers/vidstack-dash-DHRMFG4Y.js +0 -1
  101. package/cdn/with-layouts/providers/vidstack-google-cast-BSYJYn-o.js +0 -1
  102. package/cdn/with-layouts/providers/vidstack-hls-DG1rTEqu.js +0 -1
  103. package/cdn/with-layouts/providers/vidstack-hls-ji26kFdQ.js +0 -1
  104. package/cdn/with-layouts/providers/vidstack-html-BvHMxtoe.js +0 -1
  105. package/cdn/with-layouts/providers/vidstack-html-CoKFAYW5.js +0 -1
  106. package/cdn/with-layouts/providers/vidstack-video-1Uj5cNP2.js +0 -1
  107. package/cdn/with-layouts/providers/vidstack-video-CIxFJ9Z1.js +0 -1
  108. package/cdn/with-layouts/providers/vidstack-vimeo-CNLKOGMa.js +0 -1
  109. package/cdn/with-layouts/providers/vidstack-vimeo-DACTbJaQ.js +0 -1
  110. package/cdn/with-layouts/providers/vidstack-youtube-D1e-LE-8.js +0 -1
  111. package/cdn/with-layouts/providers/vidstack-youtube-RoLp-I6u.js +0 -1
  112. package/dev/chunks/vidstack-03oQOdB7.js +0 -58
  113. package/dev/chunks/vidstack-0XhA3AD_.js +0 -5181
  114. package/dev/chunks/vidstack-44ILR0Cb.js +0 -1521
  115. package/dev/chunks/vidstack-B4XOm7dP.js +0 -104
  116. package/dev/chunks/vidstack-BJsZjPkB.js +0 -204
  117. package/dev/chunks/vidstack-BXSB7eI9.js +0 -58
  118. package/dev/chunks/vidstack-BaGbgcvz.js +0 -107
  119. package/dev/chunks/vidstack-Blfm1k-4.js +0 -1520
  120. package/dev/chunks/vidstack-Bo8BNFJ2.js +0 -2986
  121. package/dev/chunks/vidstack-Bs54kFSz.js +0 -66
  122. package/dev/chunks/vidstack-C3N4zIuV.js +0 -254
  123. package/dev/chunks/vidstack-C4aPQ7hZ.js +0 -1482
  124. package/dev/chunks/vidstack-C6OqdJO7.js +0 -114
  125. package/dev/chunks/vidstack-CAL4iu_K.js +0 -1482
  126. package/dev/chunks/vidstack-CEjYxSqZ.js +0 -297
  127. package/dev/chunks/vidstack-CJCnHmKE.js +0 -104
  128. package/dev/chunks/vidstack-CQdFhXSo.js +0 -204
  129. package/dev/chunks/vidstack-CSryZFvY.js +0 -1521
  130. package/dev/chunks/vidstack-C_rvOKWp.js +0 -33
  131. package/dev/chunks/vidstack-CaudO1jl.js +0 -109
  132. package/dev/chunks/vidstack-CcQdBWil.js +0 -58
  133. package/dev/chunks/vidstack-Cky9ors4.js +0 -297
  134. package/dev/chunks/vidstack-DAOcbKGP.js +0 -254
  135. package/dev/chunks/vidstack-DD_3HszA.js +0 -1520
  136. package/dev/chunks/vidstack-DKaohJzR.js +0 -5181
  137. package/dev/chunks/vidstack-DLXCqdYV.js +0 -3010
  138. package/dev/chunks/vidstack-DS7nRfge.js +0 -204
  139. package/dev/chunks/vidstack-DWtK42Sh.js +0 -1483
  140. package/dev/chunks/vidstack-D_LvMxPr.js +0 -204
  141. package/dev/chunks/vidstack-Db1-Hg_U.js +0 -297
  142. package/dev/chunks/vidstack-DrczgsqN.js +0 -297
  143. package/dev/chunks/vidstack-EoLRQZbs.js +0 -2986
  144. package/dev/chunks/vidstack-FKkY62Dr.js +0 -104
  145. package/dev/chunks/vidstack-el2dbO0m.js +0 -5181
  146. package/dev/chunks/vidstack-rvhuswgi.js +0 -2986
  147. package/prod/chunks/vidstack-BAqdCFIm.js +0 -4771
  148. package/prod/chunks/vidstack-BHqGlnGz.js +0 -1482
  149. package/prod/chunks/vidstack-BP49Gz0m.js +0 -58
  150. package/prod/chunks/vidstack-BRZe2BNi.js +0 -107
  151. package/prod/chunks/vidstack-BRnfTkxi.js +0 -297
  152. package/prod/chunks/vidstack-BaaRY-9x.js +0 -201
  153. package/prod/chunks/vidstack-BexQYZop.js +0 -2976
  154. package/prod/chunks/vidstack-BpLd9ASW.js +0 -246
  155. package/prod/chunks/vidstack-C-yd_bAJ.js +0 -4771
  156. package/prod/chunks/vidstack-C05ipjAK.js +0 -1520
  157. package/prod/chunks/vidstack-CA4tDJdF.js +0 -33
  158. package/prod/chunks/vidstack-CFXAYpuh.js +0 -1521
  159. package/prod/chunks/vidstack-CIvL96_j.js +0 -297
  160. package/prod/chunks/vidstack-CYVCrFjx.js +0 -201
  161. package/prod/chunks/vidstack-Cs0fH84E.js +0 -1521
  162. package/prod/chunks/vidstack-D7hJcnN-.js +0 -297
  163. package/prod/chunks/vidstack-DDePVDjt.js +0 -2976
  164. package/prod/chunks/vidstack-DESBVLFp.js +0 -104
  165. package/prod/chunks/vidstack-DMDDSV3t.js +0 -104
  166. package/prod/chunks/vidstack-DXfGRhxZ.js +0 -201
  167. package/prod/chunks/vidstack-D_atbNqH.js +0 -3000
  168. package/prod/chunks/vidstack-DcMkaIHJ.js +0 -2976
  169. package/prod/chunks/vidstack-DnRxQoqP.js +0 -104
  170. package/prod/chunks/vidstack-DwenML7x.js +0 -4771
  171. package/prod/chunks/vidstack-IDWYvfna.js +0 -58
  172. package/prod/chunks/vidstack-Ko2EJadT.js +0 -1483
  173. package/prod/chunks/vidstack-MbEMbVfP.js +0 -109
  174. package/prod/chunks/vidstack-ShUhyBfI.js +0 -201
  175. package/prod/chunks/vidstack-SnIdjCkV.js +0 -58
  176. package/prod/chunks/vidstack-V1jwkH0s.js +0 -66
  177. package/prod/chunks/vidstack-V9U6gsde.js +0 -1482
  178. package/prod/chunks/vidstack-XA3zT5W9.js +0 -297
  179. package/prod/chunks/vidstack-bdt7uOlN.js +0 -114
  180. package/prod/chunks/vidstack-kdaDngIm.js +0 -1520
  181. package/prod/chunks/vidstack-oNEzlviH.js +0 -246
  182. package/server/chunks/vidstack-B2Bc9g7_.js +0 -2000
  183. package/server/chunks/vidstack-B4CWj0Hp.js +0 -381
  184. package/server/chunks/vidstack-B8P1aUCK.js +0 -1503
  185. package/server/chunks/vidstack-B8_v1VQn.js +0 -3059
  186. package/server/chunks/vidstack-BGgfNYAH.js +0 -141
  187. package/server/chunks/vidstack-BGmwlunt.js +0 -3035
  188. package/server/chunks/vidstack-BO8FLks6.js +0 -295
  189. package/server/chunks/vidstack-BosyhF3p.js +0 -207
  190. package/server/chunks/vidstack-C19bj3Wq.js +0 -307
  191. package/server/chunks/vidstack-C8F1EUBn.js +0 -104
  192. package/server/chunks/vidstack-CFTkUXGK.js +0 -295
  193. package/server/chunks/vidstack-CQMB7Msg.js +0 -1502
  194. package/server/chunks/vidstack-CWho6PlG.js +0 -141
  195. package/server/chunks/vidstack-CdBfecZT.js +0 -205
  196. package/server/chunks/vidstack-Cv_Art04.js +0 -4635
  197. package/server/chunks/vidstack-DE4b5Bgx.js +0 -2002
  198. package/server/chunks/vidstack-Db22EuE_.js +0 -207
  199. package/server/chunks/vidstack-DbvCOsqU.js +0 -107
  200. package/server/chunks/vidstack-DgHfFDiw.js +0 -1962
  201. package/server/chunks/vidstack-DhF59-Up.js +0 -4635
  202. package/server/chunks/vidstack-DnkB7eGO.js +0 -207
  203. package/server/chunks/vidstack-DoHmOxNm.js +0 -295
  204. package/server/chunks/vidstack-DsnTqzpL.js +0 -29
  205. package/server/chunks/vidstack-DzWvfg1d.js +0 -1503
  206. package/server/chunks/vidstack-FHGkN5xj.js +0 -566
  207. package/server/chunks/vidstack-PnFpou7g.js +0 -3035
  208. package/server/chunks/vidstack-f5-aflD2.js +0 -104
  209. package/server/chunks/vidstack-gEJMQpTE.js +0 -2001
  210. package/server/chunks/vidstack-n4zAyLEV.js +0 -2139
@@ -1,1503 +0,0 @@
1
- import { Component, State, effect, tick, peek, setAttribute, isString, setStyle, createContext, signal, EventsController, provideContext, onDispose, useContext, prop, useState, isNull, functionThrottle, computed, method, scoped, createScope, animationFrameThrottle, functionDebounce, hasProvidedContext, isNumber, listenEvent, isPointerEvent, isTouchEvent, isMouseEvent, DOMEvent, kebabToCamelCase } from './vidstack-B8LynzY5.js';
2
- import { useMediaContext, setAttributeIfEmpty, requestScopedAnimationFrame, autoPlacement, setARIALabel, watchActiveTextTrack, isCueActive, isTouchPinchEvent } from './vidstack-B4CWj0Hp.js';
3
- import { formatSpokenTime, Popper, ToggleButtonController, Slider, SliderController, sliderState, sliderValueFormatContext, TimeSlider, RadioGroupController, menuContext, formatTime } from './vidstack-B8_v1VQn.js';
4
- import { FocusVisibleController, $keyboard, round, isTrackCaptionKind } from './vidstack-C19bj3Wq.js';
5
- import { $ariaBool, sortVideoQualities } from './vidstack-BOTZD4tC.js';
6
-
7
- class MediaAnnouncer extends Component {
8
- static props = {
9
- translations: null
10
- };
11
- static state = new State({
12
- label: null,
13
- busy: false
14
- });
15
- #media;
16
- #initializing = false;
17
- onSetup() {
18
- this.#media = useMediaContext();
19
- }
20
- onAttach(el) {
21
- el.style.display = "contents";
22
- }
23
- onConnect(el) {
24
- el.setAttribute("data-media-announcer", "");
25
- setAttributeIfEmpty(el, "role", "status");
26
- setAttributeIfEmpty(el, "aria-live", "polite");
27
- const { busy } = this.$state;
28
- this.setAttributes({
29
- "aria-busy": () => busy() ? "true" : null
30
- });
31
- this.#initializing = true;
32
- effect(this.#watchPaused.bind(this));
33
- effect(this.#watchVolume.bind(this));
34
- effect(this.#watchCaptions.bind(this));
35
- effect(this.#watchFullscreen.bind(this));
36
- effect(this.#watchPiP.bind(this));
37
- effect(this.#watchSeeking.bind(this));
38
- effect(this.#watchLabel.bind(this));
39
- tick();
40
- this.#initializing = false;
41
- }
42
- #watchPaused() {
43
- const { paused } = this.#media.$state;
44
- this.#setLabel(!paused() ? "Play" : "Pause");
45
- }
46
- #watchFullscreen() {
47
- const { fullscreen } = this.#media.$state;
48
- this.#setLabel(fullscreen() ? "Enter Fullscreen" : "Exit Fullscreen");
49
- }
50
- #watchPiP() {
51
- const { pictureInPicture } = this.#media.$state;
52
- this.#setLabel(pictureInPicture() ? "Enter PiP" : "Exit PiP");
53
- }
54
- #watchCaptions() {
55
- const { textTrack } = this.#media.$state;
56
- this.#setLabel(textTrack() ? "Closed-Captions On" : "Closed-Captions Off");
57
- }
58
- #watchVolume() {
59
- const { muted, volume, audioGain } = this.#media.$state;
60
- this.#setLabel(
61
- muted() || volume() === 0 ? "Mute" : `${Math.round(volume() * (audioGain() ?? 1) * 100)}% ${this.#translate("Volume")}`
62
- );
63
- }
64
- #startedSeekingAt = -1;
65
- #seekTimer = -1;
66
- #watchSeeking() {
67
- const { seeking, currentTime } = this.#media.$state, isSeeking = seeking();
68
- if (this.#startedSeekingAt > 0) {
69
- window.clearTimeout(this.#seekTimer);
70
- this.#seekTimer = window.setTimeout(() => {
71
- if (!this.scope) return;
72
- const newTime = peek(currentTime), seconds = Math.abs(newTime - this.#startedSeekingAt);
73
- if (seconds >= 1) {
74
- const isForward = newTime >= this.#startedSeekingAt, spokenTime = formatSpokenTime(seconds);
75
- this.#setLabel(
76
- `${this.#translate(isForward ? "Seek Forward" : "Seek Backward")} ${spokenTime}`
77
- );
78
- }
79
- this.#startedSeekingAt = -1;
80
- this.#seekTimer = -1;
81
- }, 300);
82
- } else if (isSeeking) {
83
- this.#startedSeekingAt = peek(currentTime);
84
- }
85
- }
86
- #translate(word) {
87
- const { translations } = this.$props;
88
- return translations?.()?.[word || ""] ?? word;
89
- }
90
- #watchLabel() {
91
- const { label, busy } = this.$state, $label = this.#translate(label());
92
- if (this.#initializing) return;
93
- busy.set(true);
94
- const id = window.setTimeout(() => void busy.set(false), 150);
95
- this.el && setAttribute(this.el, "aria-label", $label);
96
- if (isString($label)) {
97
- this.dispatch("change", { detail: $label });
98
- }
99
- return () => window.clearTimeout(id);
100
- }
101
- #setLabel(word) {
102
- const { label } = this.$state;
103
- label.set(word);
104
- }
105
- }
106
-
107
- class Controls extends Component {
108
- static props = {
109
- hideDelay: 2e3,
110
- hideOnMouseLeave: false
111
- };
112
- #media;
113
- onSetup() {
114
- this.#media = useMediaContext();
115
- effect(this.#watchProps.bind(this));
116
- }
117
- onAttach(el) {
118
- const { pictureInPicture, fullscreen } = this.#media.$state;
119
- setStyle(el, "pointer-events", "none");
120
- setAttributeIfEmpty(el, "role", "group");
121
- this.setAttributes({
122
- "data-visible": this.#isShowing.bind(this),
123
- "data-fullscreen": fullscreen,
124
- "data-pip": pictureInPicture
125
- });
126
- effect(() => {
127
- this.dispatch("change", { detail: this.#isShowing() });
128
- });
129
- effect(this.#hideControls.bind(this));
130
- effect(() => {
131
- const isFullscreen = fullscreen();
132
- for (const side of ["top", "right", "bottom", "left"]) {
133
- setStyle(el, `padding-${side}`, isFullscreen && `env(safe-area-inset-${side})`);
134
- }
135
- });
136
- }
137
- #hideControls() {
138
- if (!this.el) return;
139
- const { nativeControls } = this.#media.$state, isHidden = nativeControls();
140
- setAttribute(this.el, "aria-hidden", isHidden ? "true" : null);
141
- setStyle(this.el, "display", isHidden ? "none" : null);
142
- }
143
- #watchProps() {
144
- const { controls } = this.#media.player, { hideDelay, hideOnMouseLeave } = this.$props;
145
- controls.defaultDelay = hideDelay() === 2e3 ? this.#media.$props.controlsDelay() : hideDelay();
146
- controls.hideOnMouseLeave = hideOnMouseLeave();
147
- }
148
- #isShowing() {
149
- const { controlsVisible } = this.#media.$state;
150
- return controlsVisible();
151
- }
152
- }
153
-
154
- class ControlsGroup extends Component {
155
- onAttach(el) {
156
- if (!el.style.pointerEvents) setStyle(el, "pointer-events", "auto");
157
- }
158
- }
159
-
160
- const tooltipContext = createContext();
161
-
162
- let id = 0;
163
- class Tooltip extends Component {
164
- static props = {
165
- showDelay: 700
166
- };
167
- #id = `media-tooltip-${++id}`;
168
- #trigger = signal(null);
169
- #content = signal(null);
170
- #showing = signal(false);
171
- constructor() {
172
- super();
173
- new FocusVisibleController();
174
- const { showDelay } = this.$props;
175
- new Popper({
176
- trigger: this.#trigger,
177
- content: this.#content,
178
- showDelay,
179
- listen(trigger, show, hide) {
180
- effect(() => {
181
- if ($keyboard()) ;
182
- });
183
- new EventsController(trigger).add("touchstart", (e) => e.preventDefault(), { passive: false }).add("mouseenter", show).add("mouseleave", hide);
184
- },
185
- onChange: this.#onShowingChange.bind(this)
186
- });
187
- }
188
- onAttach(el) {
189
- el.style.setProperty("display", "contents");
190
- }
191
- onSetup() {
192
- provideContext(tooltipContext, {
193
- trigger: this.#trigger,
194
- content: this.#content,
195
- showing: this.#showing,
196
- attachTrigger: this.#attachTrigger.bind(this),
197
- detachTrigger: this.#detachTrigger.bind(this),
198
- attachContent: this.#attachContent.bind(this),
199
- detachContent: this.#detachContent.bind(this)
200
- });
201
- }
202
- #attachTrigger(el) {
203
- this.#trigger.set(el);
204
- let tooltipName = el.getAttribute("data-media-tooltip");
205
- if (tooltipName) {
206
- this.el?.setAttribute(`data-media-${tooltipName}-tooltip`, "");
207
- }
208
- setAttribute(el, "data-describedby", this.#id);
209
- }
210
- #detachTrigger(el) {
211
- el.removeAttribute("data-describedby");
212
- el.removeAttribute("aria-describedby");
213
- this.#trigger.set(null);
214
- }
215
- #attachContent(el) {
216
- el.setAttribute("id", this.#id);
217
- el.style.display = "none";
218
- setAttributeIfEmpty(el, "role", "tooltip");
219
- this.#content.set(el);
220
- }
221
- #detachContent(el) {
222
- el.removeAttribute("id");
223
- el.removeAttribute("role");
224
- this.#content.set(null);
225
- }
226
- #onShowingChange(isShowing) {
227
- const trigger = this.#trigger(), content = this.#content();
228
- if (trigger) {
229
- setAttribute(trigger, "aria-describedby", isShowing ? this.#id : null);
230
- }
231
- for (const el of [this.el, trigger, content]) {
232
- el && setAttribute(el, "data-visible", isShowing);
233
- }
234
- this.#showing.set(isShowing);
235
- }
236
- }
237
-
238
- class TooltipTrigger extends Component {
239
- constructor() {
240
- super();
241
- new FocusVisibleController();
242
- }
243
- onConnect(el) {
244
- onDispose(
245
- requestScopedAnimationFrame(() => {
246
- if (!this.connectScope) return;
247
- this.#attach();
248
- const tooltip = useContext(tooltipContext);
249
- onDispose(() => {
250
- const button = this.#getButton();
251
- button && tooltip.detachTrigger(button);
252
- });
253
- })
254
- );
255
- }
256
- #attach() {
257
- const button = this.#getButton(), tooltip = useContext(tooltipContext);
258
- button && tooltip.attachTrigger(button);
259
- }
260
- #getButton() {
261
- const candidate = this.el.firstElementChild;
262
- return candidate?.localName === "button" || candidate?.getAttribute("role") === "button" ? candidate : this.el;
263
- }
264
- }
265
-
266
- class TooltipContent extends Component {
267
- static props = {
268
- placement: "top center",
269
- offset: 0,
270
- alignOffset: 0
271
- };
272
- constructor() {
273
- super();
274
- new FocusVisibleController();
275
- const { placement } = this.$props;
276
- this.setAttributes({
277
- "data-placement": placement
278
- });
279
- }
280
- onAttach(el) {
281
- this.#attach(el);
282
- Object.assign(el.style, {
283
- position: "absolute",
284
- top: 0,
285
- left: 0,
286
- width: "max-content"
287
- });
288
- }
289
- onConnect(el) {
290
- this.#attach(el);
291
- const tooltip = useContext(tooltipContext);
292
- onDispose(() => tooltip.detachContent(el));
293
- onDispose(
294
- requestScopedAnimationFrame(() => {
295
- if (!this.connectScope) return;
296
- effect(this.#watchPlacement.bind(this));
297
- })
298
- );
299
- }
300
- #attach(el) {
301
- const tooltip = useContext(tooltipContext);
302
- tooltip.attachContent(el);
303
- }
304
- #watchPlacement() {
305
- const { showing } = useContext(tooltipContext);
306
- if (!showing()) return;
307
- const { placement, offset: mainOffset, alignOffset } = this.$props;
308
- return autoPlacement(this.el, this.#getTrigger(), placement(), {
309
- offsetVarName: "media-tooltip",
310
- xOffset: alignOffset(),
311
- yOffset: mainOffset()
312
- });
313
- }
314
- #getTrigger() {
315
- return useContext(tooltipContext).trigger();
316
- }
317
- }
318
-
319
- class ToggleButton extends Component {
320
- static props = {
321
- disabled: false,
322
- defaultPressed: false
323
- };
324
- #pressed = signal(false);
325
- /**
326
- * Whether the toggle is currently in a `pressed` state.
327
- */
328
- get pressed() {
329
- return this.#pressed();
330
- }
331
- constructor() {
332
- super();
333
- new ToggleButtonController({
334
- isPresssed: this.#pressed
335
- });
336
- }
337
- }
338
- const togglebutton__proto = ToggleButton.prototype;
339
- prop(togglebutton__proto, "pressed");
340
-
341
- class GoogleCastButton extends Component {
342
- static props = ToggleButtonController.props;
343
- #media;
344
- constructor() {
345
- super();
346
- new ToggleButtonController({
347
- isPresssed: this.#isPressed.bind(this),
348
- onPress: this.#onPress.bind(this)
349
- });
350
- }
351
- onSetup() {
352
- this.#media = useMediaContext();
353
- const { canGoogleCast, isGoogleCastConnected } = this.#media.$state;
354
- this.setAttributes({
355
- "data-active": isGoogleCastConnected,
356
- "data-supported": canGoogleCast,
357
- "data-state": this.#getState.bind(this),
358
- "aria-hidden": $ariaBool(() => !canGoogleCast())
359
- });
360
- }
361
- onAttach(el) {
362
- el.setAttribute("data-media-tooltip", "google-cast");
363
- setARIALabel(el, this.#getDefaultLabel.bind(this));
364
- }
365
- #onPress(event) {
366
- const remote = this.#media.remote;
367
- remote.requestGoogleCast(event);
368
- }
369
- #isPressed() {
370
- const { remotePlaybackType, remotePlaybackState } = this.#media.$state;
371
- return remotePlaybackType() === "google-cast" && remotePlaybackState() !== "disconnected";
372
- }
373
- #getState() {
374
- const { remotePlaybackType, remotePlaybackState } = this.#media.$state;
375
- return remotePlaybackType() === "google-cast" && remotePlaybackState();
376
- }
377
- #getDefaultLabel() {
378
- const { remotePlaybackState } = this.#media.$state;
379
- return `Google Cast ${remotePlaybackState()}`;
380
- }
381
- }
382
-
383
- class SliderVideo extends Component {
384
- static props = {
385
- src: null,
386
- crossOrigin: null
387
- };
388
- static state = new State({
389
- video: null,
390
- src: null,
391
- crossOrigin: null,
392
- canPlay: false,
393
- error: null,
394
- hidden: false
395
- });
396
- #media;
397
- #slider;
398
- get video() {
399
- return this.$state.video();
400
- }
401
- onSetup() {
402
- this.#media = useMediaContext();
403
- this.#slider = useState(Slider.state);
404
- this.#watchCrossOrigin();
405
- this.setAttributes({
406
- "data-loading": this.#isLoading.bind(this),
407
- "data-hidden": this.$state.hidden,
408
- "data-error": this.#hasError.bind(this),
409
- "aria-hidden": $ariaBool(this.$state.hidden)
410
- });
411
- }
412
- onAttach(el) {
413
- effect(this.#watchVideo.bind(this));
414
- effect(this.#watchSrc.bind(this));
415
- effect(this.#watchCrossOrigin.bind(this));
416
- effect(this.#watchHidden.bind(this));
417
- effect(this.#onSrcChange.bind(this));
418
- effect(this.#onUpdateTime.bind(this));
419
- }
420
- #watchVideo() {
421
- const video = this.$state.video();
422
- if (!video) return;
423
- if (video.readyState >= 2) this.#onCanPlay();
424
- new EventsController(video).add("canplay", this.#onCanPlay.bind(this)).add("error", this.#onError.bind(this));
425
- }
426
- #watchSrc() {
427
- const { src } = this.$state, { canLoad } = this.#media.$state;
428
- src.set(canLoad() ? this.$props.src() : null);
429
- }
430
- #watchCrossOrigin() {
431
- const { crossOrigin: crossOriginProp } = this.$props, { crossOrigin: crossOriginState } = this.$state, { crossOrigin: mediaCrossOrigin } = this.#media.$state, crossOrigin = crossOriginProp() !== null ? crossOriginProp() : mediaCrossOrigin();
432
- crossOriginState.set(crossOrigin === true ? "anonymous" : crossOrigin);
433
- }
434
- #isLoading() {
435
- const { canPlay, hidden } = this.$state;
436
- return !canPlay() && !hidden();
437
- }
438
- #hasError() {
439
- const { error } = this.$state;
440
- return !isNull(error);
441
- }
442
- #watchHidden() {
443
- const { src, hidden } = this.$state, { canLoad, duration } = this.#media.$state;
444
- hidden.set(canLoad() && (!src() || this.#hasError() || !Number.isFinite(duration())));
445
- }
446
- #onSrcChange() {
447
- const { src, canPlay, error } = this.$state;
448
- src();
449
- canPlay.set(false);
450
- error.set(null);
451
- }
452
- #onCanPlay(event) {
453
- const { canPlay, error } = this.$state;
454
- canPlay.set(true);
455
- error.set(null);
456
- this.dispatch("can-play", { trigger: event });
457
- }
458
- #onError(event) {
459
- const { canPlay, error } = this.$state;
460
- canPlay.set(false);
461
- error.set(event);
462
- this.dispatch("error", { trigger: event });
463
- }
464
- #onUpdateTime() {
465
- const { video, canPlay } = this.$state, { duration } = this.#media.$state, { pointerRate } = this.#slider, media = video(), canUpdate = canPlay() && media && Number.isFinite(duration()) && Number.isFinite(pointerRate());
466
- if (canUpdate) {
467
- media.currentTime = pointerRate() * duration();
468
- }
469
- }
470
- }
471
- const slidervideo__proto = SliderVideo.prototype;
472
- prop(slidervideo__proto, "video");
473
-
474
- class AudioGainSlider extends Component {
475
- static props = {
476
- ...SliderController.props,
477
- step: 25,
478
- keyStep: 25,
479
- shiftKeyMultiplier: 2,
480
- min: 0,
481
- max: 300
482
- };
483
- static state = sliderState;
484
- #media;
485
- onSetup() {
486
- this.#media = useMediaContext();
487
- provideContext(sliderValueFormatContext, {
488
- default: "percent",
489
- percent: (_, decimalPlaces) => {
490
- return round(this.$state.value(), decimalPlaces) + "%";
491
- }
492
- });
493
- new SliderController({
494
- getStep: this.$props.step,
495
- getKeyStep: this.$props.keyStep,
496
- roundValue: Math.round,
497
- isDisabled: this.#isDisabled.bind(this),
498
- aria: {
499
- valueNow: this.#getARIAValueNow.bind(this),
500
- valueText: this.#getARIAValueText.bind(this)
501
- },
502
- onDragValueChange: this.#onDragValueChange.bind(this),
503
- onValueChange: this.#onValueChange.bind(this)
504
- }).attach(this);
505
- effect(this.#watchMinMax.bind(this));
506
- effect(this.#watchAudioGain.bind(this));
507
- }
508
- onAttach(el) {
509
- el.setAttribute("data-media-audio-gain-slider", "");
510
- setAttributeIfEmpty(el, "aria-label", "Audio Boost");
511
- const { canSetAudioGain } = this.#media.$state;
512
- this.setAttributes({
513
- "data-supported": canSetAudioGain,
514
- "aria-hidden": $ariaBool(() => !canSetAudioGain())
515
- });
516
- }
517
- #getARIAValueNow() {
518
- const { value } = this.$state;
519
- return Math.round(value());
520
- }
521
- #getARIAValueText() {
522
- const { value } = this.$state;
523
- return value() + "%";
524
- }
525
- #watchMinMax() {
526
- const { min, max } = this.$props;
527
- this.$state.min.set(min());
528
- this.$state.max.set(max());
529
- }
530
- #watchAudioGain() {
531
- const { audioGain } = this.#media.$state, value = ((audioGain() ?? 1) - 1) * 100;
532
- this.$state.value.set(value);
533
- this.dispatch("value-change", { detail: value });
534
- }
535
- #isDisabled() {
536
- const { disabled } = this.$props, { canSetAudioGain } = this.#media.$state;
537
- return disabled() || !canSetAudioGain();
538
- }
539
- #onAudioGainChange(event) {
540
- if (!event.trigger) return;
541
- const gain = round(1 + event.detail / 100, 2);
542
- this.#media.remote.changeAudioGain(gain, event);
543
- }
544
- #onValueChange(event) {
545
- this.#onAudioGainChange(event);
546
- }
547
- #onDragValueChange(event) {
548
- this.#onAudioGainChange(event);
549
- }
550
- }
551
-
552
- class SpeedSlider extends Component {
553
- static props = {
554
- ...SliderController.props,
555
- step: 0.25,
556
- keyStep: 0.25,
557
- shiftKeyMultiplier: 2,
558
- min: 0,
559
- max: 2
560
- };
561
- static state = sliderState;
562
- #media;
563
- onSetup() {
564
- this.#media = useMediaContext();
565
- new SliderController({
566
- getStep: this.$props.step,
567
- getKeyStep: this.$props.keyStep,
568
- roundValue: this.#roundValue,
569
- isDisabled: this.#isDisabled.bind(this),
570
- aria: {
571
- valueNow: this.#getARIAValueNow.bind(this),
572
- valueText: this.#getARIAValueText.bind(this)
573
- },
574
- onDragValueChange: this.#onDragValueChange.bind(this),
575
- onValueChange: this.#onValueChange.bind(this)
576
- }).attach(this);
577
- effect(this.#watchMinMax.bind(this));
578
- effect(this.#watchPlaybackRate.bind(this));
579
- }
580
- onAttach(el) {
581
- el.setAttribute("data-media-speed-slider", "");
582
- setAttributeIfEmpty(el, "aria-label", "Speed");
583
- const { canSetPlaybackRate } = this.#media.$state;
584
- this.setAttributes({
585
- "data-supported": canSetPlaybackRate,
586
- "aria-hidden": $ariaBool(() => !canSetPlaybackRate())
587
- });
588
- }
589
- #getARIAValueNow() {
590
- const { value } = this.$state;
591
- return value();
592
- }
593
- #getARIAValueText() {
594
- const { value } = this.$state;
595
- return value() + "x";
596
- }
597
- #watchMinMax() {
598
- const { min, max } = this.$props;
599
- this.$state.min.set(min());
600
- this.$state.max.set(max());
601
- }
602
- #watchPlaybackRate() {
603
- const { playbackRate } = this.#media.$state;
604
- const newValue = playbackRate();
605
- this.$state.value.set(newValue);
606
- this.dispatch("value-change", { detail: newValue });
607
- }
608
- #roundValue(value) {
609
- return round(value, 2);
610
- }
611
- #isDisabled() {
612
- const { disabled } = this.$props, { canSetPlaybackRate } = this.#media.$state;
613
- return disabled() || !canSetPlaybackRate();
614
- }
615
- #throttledSpeedChange = functionThrottle(this.#onPlaybackRateChange.bind(this), 25);
616
- #onPlaybackRateChange(event) {
617
- if (!event.trigger) return;
618
- const rate = event.detail;
619
- this.#media.remote.changePlaybackRate(rate, event);
620
- }
621
- #onValueChange(event) {
622
- this.#throttledSpeedChange(event);
623
- }
624
- #onDragValueChange(event) {
625
- this.#throttledSpeedChange(event);
626
- }
627
- }
628
-
629
- class QualitySlider extends Component {
630
- static props = {
631
- ...SliderController.props,
632
- step: 1,
633
- keyStep: 1,
634
- shiftKeyMultiplier: 1
635
- };
636
- static state = sliderState;
637
- #media;
638
- #sortedQualities = computed(() => {
639
- const { qualities } = this.#media.$state;
640
- return sortVideoQualities(qualities());
641
- });
642
- onSetup() {
643
- this.#media = useMediaContext();
644
- new SliderController({
645
- getStep: this.$props.step,
646
- getKeyStep: this.$props.keyStep,
647
- roundValue: Math.round,
648
- isDisabled: this.#isDisabled.bind(this),
649
- aria: {
650
- valueNow: this.#getARIAValueNow.bind(this),
651
- valueText: this.#getARIAValueText.bind(this)
652
- },
653
- onDragValueChange: this.#onDragValueChange.bind(this),
654
- onValueChange: this.#onValueChange.bind(this)
655
- }).attach(this);
656
- effect(this.#watchMax.bind(this));
657
- effect(this.#watchQuality.bind(this));
658
- }
659
- onAttach(el) {
660
- el.setAttribute("data-media-quality-slider", "");
661
- setAttributeIfEmpty(el, "aria-label", "Video Quality");
662
- const { qualities, canSetQuality } = this.#media.$state, $supported = computed(() => canSetQuality() && qualities().length > 0);
663
- this.setAttributes({
664
- "data-supported": $supported,
665
- "aria-hidden": $ariaBool(() => !$supported())
666
- });
667
- }
668
- #getARIAValueNow() {
669
- const { value } = this.$state;
670
- return value();
671
- }
672
- #getARIAValueText() {
673
- const { quality } = this.#media.$state;
674
- if (!quality()) return "";
675
- const { height, bitrate, label } = quality(), bitrateText = bitrate && bitrate > 0 ? `${(bitrate / 1e6).toFixed(2)} Mbps` : null;
676
- const rootText = label ?? (height ? `${height}p` : "");
677
- return rootText ? `${rootText}${bitrateText ? ` (${bitrateText})` : ""}` : "Auto";
678
- }
679
- #watchMax() {
680
- const $qualities = this.#sortedQualities();
681
- this.$state.max.set(Math.max(0, $qualities.length - 1));
682
- }
683
- #watchQuality() {
684
- let { quality } = this.#media.$state, $qualities = this.#sortedQualities(), value = Math.max(0, $qualities.indexOf(quality()));
685
- this.$state.value.set(value);
686
- this.dispatch("value-change", { detail: value });
687
- }
688
- #isDisabled() {
689
- const { disabled } = this.$props, { canSetQuality, qualities } = this.#media.$state;
690
- return disabled() || qualities().length <= 1 || !canSetQuality();
691
- }
692
- #throttledQualityChange = functionThrottle(this.#onQualityChange.bind(this), 25);
693
- #onQualityChange(event) {
694
- if (!event.trigger) return;
695
- const { qualities } = this.#media, quality = peek(this.#sortedQualities)[event.detail];
696
- this.#media.remote.changeQuality(qualities.indexOf(quality), event);
697
- }
698
- #onValueChange(event) {
699
- this.#throttledQualityChange(event);
700
- }
701
- #onDragValueChange(event) {
702
- this.#throttledQualityChange(event);
703
- }
704
- }
705
-
706
- class SliderChapters extends Component {
707
- static props = {
708
- disabled: false
709
- };
710
- #media;
711
- #sliderState;
712
- #updateScope;
713
- #titleRef = null;
714
- #refs = [];
715
- #$track = signal(null);
716
- #$cues = signal([]);
717
- #activeIndex = signal(-1);
718
- #activePointerIndex = signal(-1);
719
- #bufferedIndex = 0;
720
- get cues() {
721
- return this.#$cues();
722
- }
723
- get activeCue() {
724
- return this.#$cues()[this.#activeIndex()] || null;
725
- }
726
- get activePointerCue() {
727
- return this.#$cues()[this.#activePointerIndex()] || null;
728
- }
729
- onSetup() {
730
- this.#media = useMediaContext();
731
- this.#sliderState = useState(TimeSlider.state);
732
- }
733
- onAttach(el) {
734
- watchActiveTextTrack(this.#media.textTracks, "chapters", this.#setTrack.bind(this));
735
- effect(this.#watchSource.bind(this));
736
- }
737
- onConnect() {
738
- onDispose(() => this.#reset.bind(this));
739
- }
740
- onDestroy() {
741
- this.#setTrack(null);
742
- }
743
- setRefs(refs) {
744
- this.#refs = refs;
745
- this.#updateScope?.dispose();
746
- if (this.#refs.length === 1) {
747
- const el = this.#refs[0];
748
- el.style.width = "100%";
749
- el.style.setProperty("--chapter-fill", "var(--slider-fill)");
750
- el.style.setProperty("--chapter-progress", "var(--slider-progress)");
751
- } else if (this.#refs.length > 0) {
752
- scoped(() => this.#watch(), this.#updateScope = createScope());
753
- }
754
- }
755
- #setTrack(track) {
756
- if (peek(this.#$track) === track) return;
757
- this.#reset();
758
- this.#$track.set(track);
759
- }
760
- #reset() {
761
- this.#refs = [];
762
- this.#$cues.set([]);
763
- this.#activeIndex.set(-1);
764
- this.#activePointerIndex.set(-1);
765
- this.#bufferedIndex = 0;
766
- this.#updateScope?.dispose();
767
- }
768
- #watch() {
769
- if (!this.#refs.length) return;
770
- effect(this.#watchUpdates.bind(this));
771
- }
772
- #watchUpdates() {
773
- const { hidden } = this.#sliderState;
774
- if (hidden()) return;
775
- effect(this.#watchContainerWidths.bind(this));
776
- effect(this.#watchFillPercent.bind(this));
777
- effect(this.#watchPointerPercent.bind(this));
778
- effect(this.#watchBufferedPercent.bind(this));
779
- }
780
- #watchContainerWidths() {
781
- const cues = this.#$cues();
782
- if (!cues.length) return;
783
- let cue, { seekableStart, seekableEnd } = this.#media.$state, startTime = seekableStart(), endTime = seekableEnd() || cues[cues.length - 1].endTime, duration = endTime - startTime, remainingWidth = 100;
784
- for (let i = 0; i < cues.length; i++) {
785
- cue = cues[i];
786
- if (this.#refs[i]) {
787
- const width = i === cues.length - 1 ? remainingWidth : round((cue.endTime - Math.max(startTime, cue.startTime)) / duration * 100, 3);
788
- this.#refs[i].style.width = width + "%";
789
- remainingWidth -= width;
790
- }
791
- }
792
- }
793
- #watchFillPercent() {
794
- let { liveEdge, seekableStart, seekableEnd } = this.#media.$state, { fillPercent, value } = this.#sliderState, cues = this.#$cues(), isLiveEdge = liveEdge(), prevActiveIndex = peek(this.#activeIndex), currentChapter = cues[prevActiveIndex];
795
- let currentActiveIndex = isLiveEdge ? this.#$cues.length - 1 : this.#findActiveChapterIndex(
796
- currentChapter ? currentChapter.startTime / seekableEnd() * 100 <= peek(value) ? prevActiveIndex : 0 : 0,
797
- fillPercent()
798
- );
799
- if (isLiveEdge || !currentChapter) {
800
- this.#updateFillPercents(0, cues.length, 100);
801
- } else if (currentActiveIndex > prevActiveIndex) {
802
- this.#updateFillPercents(prevActiveIndex, currentActiveIndex, 100);
803
- } else if (currentActiveIndex < prevActiveIndex) {
804
- this.#updateFillPercents(currentActiveIndex + 1, prevActiveIndex + 1, 0);
805
- }
806
- const percent = isLiveEdge ? 100 : this.#calcPercent(
807
- cues[currentActiveIndex],
808
- fillPercent(),
809
- seekableStart(),
810
- this.#getEndTime(cues)
811
- );
812
- this.#updateFillPercent(this.#refs[currentActiveIndex], percent);
813
- this.#activeIndex.set(currentActiveIndex);
814
- }
815
- #watchPointerPercent() {
816
- let { hidden, pointerPercent } = this.#sliderState;
817
- if (hidden()) {
818
- this.#activePointerIndex.set(-1);
819
- return;
820
- }
821
- const activeIndex = this.#findActiveChapterIndex(0, pointerPercent());
822
- this.#activePointerIndex.set(activeIndex);
823
- }
824
- #updateFillPercents(start, end, percent) {
825
- for (let i = start; i < end; i++) this.#updateFillPercent(this.#refs[i], percent);
826
- }
827
- #updateFillPercent(ref, percent) {
828
- if (!ref) return;
829
- ref.style.setProperty("--chapter-fill", percent + "%");
830
- setAttribute(ref, "data-active", percent > 0 && percent < 100);
831
- setAttribute(ref, "data-ended", percent === 100);
832
- }
833
- #findActiveChapterIndex(startIndex, percent) {
834
- let chapterPercent = 0, cues = this.#$cues();
835
- if (percent === 0) return 0;
836
- else if (percent === 100) return cues.length - 1;
837
- let { seekableStart } = this.#media.$state, startTime = seekableStart(), endTime = this.#getEndTime(cues);
838
- for (let i = startIndex; i < cues.length; i++) {
839
- chapterPercent = this.#calcPercent(cues[i], percent, startTime, endTime);
840
- if (chapterPercent >= 0 && chapterPercent < 100) return i;
841
- }
842
- return 0;
843
- }
844
- #watchBufferedPercent() {
845
- this.#updateBufferedPercent(this.#bufferedPercent());
846
- }
847
- #updateBufferedPercent = animationFrameThrottle();
848
- #bufferedPercent = computed(this.#calcMediaBufferedPercent.bind(this));
849
- #calcMediaBufferedPercent() {
850
- const { bufferedEnd, duration } = this.#media.$state;
851
- return round(Math.min(bufferedEnd() / Math.max(duration(), 1), 1), 3) * 100;
852
- }
853
- #getEndTime(cues) {
854
- const { seekableEnd } = this.#media.$state, endTime = seekableEnd();
855
- return Number.isFinite(endTime) ? endTime : cues[cues.length - 1]?.endTime || 0;
856
- }
857
- #calcPercent(cue, percent, startTime, endTime) {
858
- if (!cue) return 0;
859
- const cues = this.#$cues();
860
- if (cues.length === 0) return 0;
861
- const duration = endTime - startTime, cueStartTime = Math.max(0, cue.startTime - startTime), cueEndTime = Math.min(endTime, cue.endTime) - startTime;
862
- const startRatio = cueStartTime / duration, startPercent = startRatio * 100, endPercent = Math.min(1, startRatio + (cueEndTime - cueStartTime) / duration) * 100;
863
- return Math.max(
864
- 0,
865
- round(
866
- percent >= endPercent ? 100 : (percent - startPercent) / (endPercent - startPercent) * 100,
867
- 3
868
- )
869
- );
870
- }
871
- #fillGaps(cues) {
872
- let chapters = [], { seekableStart, seekableEnd, duration } = this.#media.$state, startTime = seekableStart(), endTime = seekableEnd();
873
- cues = cues.filter((cue) => cue.startTime <= endTime && cue.endTime >= startTime);
874
- const firstCue = cues[0];
875
- if (firstCue && firstCue.startTime > startTime) {
876
- chapters.push(new window.VTTCue(startTime, firstCue.startTime, ""));
877
- }
878
- for (let i = 0; i < cues.length - 1; i++) {
879
- const currentCue = cues[i], nextCue = cues[i + 1];
880
- chapters.push(currentCue);
881
- if (nextCue) {
882
- const timeDiff = nextCue.startTime - currentCue.endTime;
883
- if (timeDiff > 0) {
884
- chapters.push(new window.VTTCue(currentCue.endTime, currentCue.endTime + timeDiff, ""));
885
- }
886
- }
887
- }
888
- const lastCue = cues[cues.length - 1];
889
- if (lastCue) {
890
- chapters.push(lastCue);
891
- const endTime2 = duration();
892
- if (endTime2 >= 0 && endTime2 - lastCue.endTime > 1) {
893
- chapters.push(new window.VTTCue(lastCue.endTime, duration(), ""));
894
- }
895
- }
896
- return chapters;
897
- }
898
- #watchSource() {
899
- const { source } = this.#media.$state;
900
- source();
901
- this.#onTrackChange();
902
- }
903
- #onTrackChange() {
904
- if (!this.scope) return;
905
- const { disabled } = this.$props;
906
- if (disabled()) {
907
- this.#$cues.set([]);
908
- this.#activeIndex.set(0);
909
- this.#bufferedIndex = 0;
910
- return;
911
- }
912
- const track = this.#$track();
913
- if (track) {
914
- const onCuesChange = this.#onCuesChange.bind(this);
915
- onCuesChange();
916
- new EventsController(track).add("add-cue", onCuesChange).add("remove-cue", onCuesChange);
917
- effect(this.#watchMediaDuration.bind(this));
918
- }
919
- this.#titleRef = this.#findChapterTitleRef();
920
- if (this.#titleRef) effect(this.#onChapterTitleChange.bind(this));
921
- return () => {
922
- if (this.#titleRef) {
923
- this.#titleRef.textContent = "";
924
- this.#titleRef = null;
925
- }
926
- };
927
- }
928
- #watchMediaDuration() {
929
- this.#media.$state.duration();
930
- this.#onCuesChange();
931
- }
932
- #onCuesChange = functionDebounce(
933
- () => {
934
- const track = peek(this.#$track);
935
- if (!this.scope || !track || !track.cues.length) return;
936
- this.#$cues.set(this.#fillGaps(track.cues));
937
- this.#activeIndex.set(0);
938
- this.#bufferedIndex = 0;
939
- },
940
- 150,
941
- true
942
- );
943
- #onChapterTitleChange() {
944
- const cue = this.activePointerCue || this.activeCue;
945
- if (this.#titleRef) this.#titleRef.textContent = cue?.text || "";
946
- }
947
- #findParentSlider() {
948
- let node = this.el;
949
- while (node && node.getAttribute("role") !== "slider") {
950
- node = node.parentElement;
951
- }
952
- return node;
953
- }
954
- #findChapterTitleRef() {
955
- const slider = this.#findParentSlider();
956
- return slider ? slider.querySelector('[data-part="chapter-title"]') : null;
957
- }
958
- }
959
- const sliderchapters__proto = SliderChapters.prototype;
960
- prop(sliderchapters__proto, "cues");
961
- prop(sliderchapters__proto, "activeCue");
962
- prop(sliderchapters__proto, "activePointerCue");
963
- method(sliderchapters__proto, "setRefs");
964
-
965
- class RadioGroup extends Component {
966
- static props = {
967
- value: ""
968
- };
969
- #controller;
970
- /**
971
- * A list of radio values that belong this group.
972
- */
973
- get values() {
974
- return this.#controller.values;
975
- }
976
- /**
977
- * The radio value that is checked in this group.
978
- */
979
- get value() {
980
- return this.#controller.value;
981
- }
982
- set value(newValue) {
983
- this.#controller.value = newValue;
984
- }
985
- constructor() {
986
- super();
987
- this.#controller = new RadioGroupController();
988
- this.#controller.onValueChange = this.#onValueChange.bind(this);
989
- }
990
- onSetup() {
991
- this.#watchValue();
992
- }
993
- #watchValue() {
994
- this.#controller.value = this.$props.value();
995
- }
996
- #onValueChange(value, trigger) {
997
- const event = this.createEvent("change", { detail: value, trigger });
998
- this.dispatch(event);
999
- }
1000
- }
1001
- const radiogroup__proto = RadioGroup.prototype;
1002
- prop(radiogroup__proto, "values");
1003
- prop(radiogroup__proto, "value");
1004
-
1005
- var __defProp = Object.defineProperty;
1006
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
1007
- var __decorateClass = (decorators, target, key, kind) => {
1008
- var result = __getOwnPropDesc(target, key) ;
1009
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
1010
- if (decorator = decorators[i])
1011
- result = (decorator(target, key, result) ) || result;
1012
- if (result) __defProp(target, key, result);
1013
- return result;
1014
- };
1015
- class ChaptersRadioGroup extends Component {
1016
- static props = {
1017
- thumbnails: null
1018
- };
1019
- #media;
1020
- #menu;
1021
- #controller;
1022
- #track = signal(null);
1023
- #cues = signal([]);
1024
- get value() {
1025
- return this.#controller.value;
1026
- }
1027
- get disabled() {
1028
- return !this.#cues()?.length;
1029
- }
1030
- constructor() {
1031
- super();
1032
- this.#controller = new RadioGroupController();
1033
- this.#controller.onValueChange = this.#onValueChange.bind(this);
1034
- }
1035
- onSetup() {
1036
- this.#media = useMediaContext();
1037
- if (hasProvidedContext(menuContext)) {
1038
- this.#menu = useContext(menuContext);
1039
- }
1040
- const { thumbnails } = this.$props;
1041
- this.setAttributes({
1042
- "data-thumbnails": () => !!thumbnails()
1043
- });
1044
- }
1045
- onAttach(el) {
1046
- this.#menu?.attachObserver({
1047
- onOpen: this.#onOpen.bind(this)
1048
- });
1049
- }
1050
- getOptions() {
1051
- const { seekableStart, seekableEnd } = this.#media.$state, startTime = seekableStart(), endTime = seekableEnd();
1052
- return this.#cues().map((cue, i) => ({
1053
- cue,
1054
- value: i.toString(),
1055
- label: cue.text,
1056
- startTime: formatTime(Math.max(0, cue.startTime - startTime)),
1057
- duration: formatSpokenTime(
1058
- Math.min(endTime, cue.endTime) - Math.max(startTime, cue.startTime)
1059
- )
1060
- }));
1061
- }
1062
- #onOpen() {
1063
- peek(() => this.#watchCurrentTime());
1064
- }
1065
- onConnect(el) {
1066
- effect(this.#watchCurrentTime.bind(this));
1067
- effect(this.#watchControllerDisabled.bind(this));
1068
- effect(this.#watchTrack.bind(this));
1069
- watchActiveTextTrack(this.#media.textTracks, "chapters", this.#track.set);
1070
- }
1071
- #watchTrack() {
1072
- const track = this.#track();
1073
- if (!track) return;
1074
- const onCuesChange = this.#onCuesChange.bind(this, track);
1075
- onCuesChange();
1076
- new EventsController(track).add("add-cue", onCuesChange).add("remove-cue", onCuesChange);
1077
- return () => {
1078
- this.#cues.set([]);
1079
- };
1080
- }
1081
- #onCuesChange(track) {
1082
- const { seekableStart, seekableEnd } = this.#media.$state, startTime = seekableStart(), endTime = seekableEnd();
1083
- this.#cues.set(
1084
- [...track.cues].filter((cue) => cue.startTime <= endTime && cue.endTime >= startTime)
1085
- );
1086
- }
1087
- #watchCurrentTime() {
1088
- if (!this.#menu?.expanded()) return;
1089
- const track = this.#track();
1090
- if (!track) {
1091
- this.#controller.value = "-1";
1092
- return;
1093
- }
1094
- const { realCurrentTime, seekableStart, seekableEnd } = this.#media.$state, startTime = seekableStart(), endTime = seekableEnd(), time = realCurrentTime(), activeCueIndex = this.#cues().findIndex((cue) => isCueActive(cue, time));
1095
- this.#controller.value = activeCueIndex.toString();
1096
- if (activeCueIndex >= 0) {
1097
- requestScopedAnimationFrame(() => {
1098
- if (!this.connectScope) return;
1099
- const cue = this.#cues()[activeCueIndex], radio = this.el.querySelector(`[aria-checked='true']`), cueStartTime = Math.max(startTime, cue.startTime), duration = Math.min(endTime, cue.endTime) - cueStartTime, playedPercent = Math.max(0, time - cueStartTime) / duration * 100;
1100
- radio && setStyle(radio, "--progress", round(playedPercent, 3) + "%");
1101
- });
1102
- }
1103
- }
1104
- #watchControllerDisabled() {
1105
- this.#menu?.disable(this.disabled);
1106
- }
1107
- #onValueChange(value, trigger) {
1108
- if (this.disabled || !trigger) return;
1109
- const index = +value, cues = this.#cues(), { clipStartTime } = this.#media.$state;
1110
- if (isNumber(index) && cues?.[index]) {
1111
- this.#controller.value = index.toString();
1112
- this.#media.remote.seek(cues[index].startTime - clipStartTime(), trigger);
1113
- this.dispatch("change", { detail: cues[index], trigger });
1114
- }
1115
- }
1116
- }
1117
- __decorateClass([
1118
- prop
1119
- ], ChaptersRadioGroup.prototype, "value");
1120
- __decorateClass([
1121
- prop
1122
- ], ChaptersRadioGroup.prototype, "disabled");
1123
- __decorateClass([
1124
- method
1125
- ], ChaptersRadioGroup.prototype, "getOptions");
1126
-
1127
- const DEFAULT_AUDIO_GAINS = [1, 1.25, 1.5, 1.75, 2, 2.5, 3, 4];
1128
- class AudioGainRadioGroup extends Component {
1129
- static props = {
1130
- normalLabel: "Disabled",
1131
- gains: DEFAULT_AUDIO_GAINS
1132
- };
1133
- #media;
1134
- #menu;
1135
- #controller;
1136
- get value() {
1137
- return this.#controller.value;
1138
- }
1139
- get disabled() {
1140
- const { gains } = this.$props, { canSetAudioGain } = this.#media.$state;
1141
- return !canSetAudioGain() || gains().length === 0;
1142
- }
1143
- constructor() {
1144
- super();
1145
- this.#controller = new RadioGroupController();
1146
- this.#controller.onValueChange = this.#onValueChange.bind(this);
1147
- }
1148
- onSetup() {
1149
- this.#media = useMediaContext();
1150
- if (hasProvidedContext(menuContext)) {
1151
- this.#menu = useContext(menuContext);
1152
- }
1153
- }
1154
- onConnect(el) {
1155
- effect(this.#watchValue.bind(this));
1156
- effect(this.#watchHintText.bind(this));
1157
- effect(this.#watchControllerDisabled.bind(this));
1158
- }
1159
- getOptions() {
1160
- const { gains, normalLabel } = this.$props;
1161
- return gains().map((gain) => ({
1162
- label: gain === 1 || gain === null ? normalLabel : String(gain * 100) + "%",
1163
- value: gain.toString()
1164
- }));
1165
- }
1166
- #watchValue() {
1167
- this.#controller.value = this.#getValue();
1168
- }
1169
- #watchHintText() {
1170
- const { normalLabel } = this.$props, { audioGain } = this.#media.$state, gain = audioGain();
1171
- this.#menu?.hint.set(gain === 1 || gain == null ? normalLabel() : String(gain * 100) + "%");
1172
- }
1173
- #watchControllerDisabled() {
1174
- this.#menu?.disable(this.disabled);
1175
- }
1176
- #getValue() {
1177
- const { audioGain } = this.#media.$state;
1178
- return audioGain()?.toString() ?? "1";
1179
- }
1180
- #onValueChange(value, trigger) {
1181
- if (this.disabled) return;
1182
- const gain = +value;
1183
- this.#media.remote.changeAudioGain(gain, trigger);
1184
- this.dispatch("change", { detail: gain, trigger });
1185
- }
1186
- }
1187
- const audiogainradiogroup__proto = AudioGainRadioGroup.prototype;
1188
- prop(audiogainradiogroup__proto, "value");
1189
- prop(audiogainradiogroup__proto, "disabled");
1190
- method(audiogainradiogroup__proto, "getOptions");
1191
-
1192
- class Gesture extends Component {
1193
- static props = {
1194
- disabled: false,
1195
- event: void 0,
1196
- action: void 0
1197
- };
1198
- #media;
1199
- #provider = null;
1200
- onSetup() {
1201
- this.#media = useMediaContext();
1202
- const { event, action } = this.$props;
1203
- this.setAttributes({
1204
- event,
1205
- action
1206
- });
1207
- }
1208
- onAttach(el) {
1209
- el.setAttribute("data-media-gesture", "");
1210
- el.style.setProperty("pointer-events", "none");
1211
- }
1212
- onConnect(el) {
1213
- this.#provider = this.#media.player.el?.querySelector(
1214
- "[data-media-provider]"
1215
- );
1216
- effect(this.#attachListener.bind(this));
1217
- }
1218
- #attachListener() {
1219
- let eventType = this.$props.event(), disabled = this.$props.disabled();
1220
- if (!this.#provider || !eventType || disabled) return;
1221
- if (/^dbl/.test(eventType)) {
1222
- eventType = eventType.split(/^dbl/)[1];
1223
- }
1224
- if (eventType === "pointerup" || eventType === "pointerdown") {
1225
- const pointer = this.#media.$state.pointer();
1226
- if (pointer === "coarse") {
1227
- eventType = eventType === "pointerup" ? "touchend" : "touchstart";
1228
- }
1229
- }
1230
- listenEvent(
1231
- this.#provider,
1232
- eventType,
1233
- this.#acceptEvent.bind(this));
1234
- }
1235
- #presses = 0;
1236
- #pressTimerId = -1;
1237
- #acceptEvent(event) {
1238
- if (this.$props.disabled() || isPointerEvent(event) && (event.button !== 0 || this.#media.activeMenu) || isTouchEvent(event) && this.#media.activeMenu || isTouchPinchEvent(event) || !this.#inBounds(event)) {
1239
- return;
1240
- }
1241
- event.MEDIA_GESTURE = true;
1242
- event.preventDefault();
1243
- const eventType = peek(this.$props.event), isDblEvent = eventType?.startsWith("dbl");
1244
- if (!isDblEvent) {
1245
- if (this.#presses === 0) {
1246
- setTimeout(() => {
1247
- if (this.#presses === 1) this.#handleEvent(event);
1248
- }, 250);
1249
- }
1250
- } else if (this.#presses === 1) {
1251
- queueMicrotask(() => this.#handleEvent(event));
1252
- clearTimeout(this.#pressTimerId);
1253
- this.#presses = 0;
1254
- return;
1255
- }
1256
- if (this.#presses === 0) {
1257
- this.#pressTimerId = window.setTimeout(() => {
1258
- this.#presses = 0;
1259
- }, 275);
1260
- }
1261
- this.#presses++;
1262
- }
1263
- #handleEvent(event) {
1264
- this.el.setAttribute("data-triggered", "");
1265
- requestAnimationFrame(() => {
1266
- if (this.#isTopLayer()) {
1267
- this.#performAction(peek(this.$props.action), event);
1268
- }
1269
- requestAnimationFrame(() => {
1270
- this.el.removeAttribute("data-triggered");
1271
- });
1272
- });
1273
- }
1274
- /** Validate event occurred in gesture bounds. */
1275
- #inBounds(event) {
1276
- if (!this.el) return false;
1277
- if (isPointerEvent(event) || isMouseEvent(event) || isTouchEvent(event)) {
1278
- const touch = isTouchEvent(event) ? event.changedTouches[0] ?? event.touches[0] : void 0;
1279
- const clientX = touch?.clientX ?? event.clientX;
1280
- const clientY = touch?.clientY ?? event.clientY;
1281
- const rect = this.el.getBoundingClientRect();
1282
- const inBounds = clientY >= rect.top && clientY <= rect.bottom && clientX >= rect.left && clientX <= rect.right;
1283
- return event.type.includes("leave") ? !inBounds : inBounds;
1284
- }
1285
- return true;
1286
- }
1287
- /** Validate gesture has the highest z-index in this triggered group. */
1288
- #isTopLayer() {
1289
- const gestures = this.#media.player.el.querySelectorAll(
1290
- "[data-media-gesture][data-triggered]"
1291
- );
1292
- return Array.from(gestures).sort(
1293
- (a, b) => +getComputedStyle(b).zIndex - +getComputedStyle(a).zIndex
1294
- )[0] === this.el;
1295
- }
1296
- #performAction(action, trigger) {
1297
- if (!action) return;
1298
- const willTriggerEvent = new DOMEvent("will-trigger", {
1299
- detail: action,
1300
- cancelable: true,
1301
- trigger
1302
- });
1303
- this.dispatchEvent(willTriggerEvent);
1304
- if (willTriggerEvent.defaultPrevented) return;
1305
- const [method, value] = action.replace(/:([a-z])/, "-$1").split(":");
1306
- if (action.includes(":fullscreen")) {
1307
- this.#media.remote.toggleFullscreen("prefer-media", trigger);
1308
- } else if (action.includes("seek:")) {
1309
- this.#media.remote.seek(peek(this.#media.$state.currentTime) + (+value || 0), trigger);
1310
- } else {
1311
- this.#media.remote[kebabToCamelCase(method)](trigger);
1312
- }
1313
- this.dispatch("trigger", {
1314
- detail: action,
1315
- trigger
1316
- });
1317
- }
1318
- }
1319
-
1320
- class CaptionsTextRenderer {
1321
- priority = 10;
1322
- #track = null;
1323
- #renderer;
1324
- #events;
1325
- constructor(renderer) {
1326
- this.#renderer = renderer;
1327
- }
1328
- attach() {
1329
- }
1330
- canRender() {
1331
- return true;
1332
- }
1333
- detach() {
1334
- this.#events?.abort();
1335
- this.#events = void 0;
1336
- this.#renderer.reset();
1337
- this.#track = null;
1338
- }
1339
- changeTrack(track) {
1340
- if (!track || this.#track === track) return;
1341
- this.#events?.abort();
1342
- this.#events = new EventsController(track);
1343
- if (track.readyState < 2) {
1344
- this.#renderer.reset();
1345
- this.#events.add("load", () => this.#changeTrack(track), { once: true });
1346
- } else {
1347
- this.#changeTrack(track);
1348
- }
1349
- this.#events.add("add-cue", (event) => {
1350
- this.#renderer.addCue(event.detail);
1351
- }).add("remove-cue", (event) => {
1352
- this.#renderer.removeCue(event.detail);
1353
- });
1354
- this.#track = track;
1355
- }
1356
- #changeTrack(track) {
1357
- this.#renderer.changeTrack({
1358
- cues: [...track.cues],
1359
- regions: [...track.regions]
1360
- });
1361
- }
1362
- }
1363
-
1364
- class Captions extends Component {
1365
- static props = {
1366
- textDir: "ltr",
1367
- exampleText: "Captions look like this."
1368
- };
1369
- #media;
1370
- static lib = signal(null);
1371
- onSetup() {
1372
- this.#media = useMediaContext();
1373
- this.setAttributes({
1374
- "aria-hidden": $ariaBool(this.#isHidden.bind(this))
1375
- });
1376
- }
1377
- onAttach(el) {
1378
- el.style.setProperty("pointer-events", "none");
1379
- }
1380
- onConnect(el) {
1381
- if (!Captions.lib()) {
1382
- import('media-captions').then((lib) => Captions.lib.set(lib));
1383
- }
1384
- effect(this.#watchViewType.bind(this));
1385
- }
1386
- #isHidden() {
1387
- const { textTrack, remotePlaybackState, iOSControls } = this.#media.$state, track = textTrack();
1388
- return iOSControls() || remotePlaybackState() === "connected" || !track || !isTrackCaptionKind(track);
1389
- }
1390
- #watchViewType() {
1391
- if (!Captions.lib()) return;
1392
- const { viewType } = this.#media.$state;
1393
- if (viewType() === "audio") {
1394
- return this.#setupAudioView();
1395
- } else {
1396
- return this.#setupVideoView();
1397
- }
1398
- }
1399
- #setupAudioView() {
1400
- effect(this.#onTrackChange.bind(this));
1401
- this.#listenToFontStyleChanges(null);
1402
- return () => {
1403
- this.el.textContent = "";
1404
- };
1405
- }
1406
- #onTrackChange() {
1407
- if (this.#isHidden()) return;
1408
- this.#onCueChange();
1409
- const { textTrack } = this.#media.$state;
1410
- listenEvent(textTrack(), "cue-change", this.#onCueChange.bind(this));
1411
- effect(this.#onUpdateTimedNodes.bind(this));
1412
- }
1413
- #onCueChange() {
1414
- this.el.textContent = "";
1415
- if (this.#hideExampleTimer >= 0) {
1416
- this.#removeExample();
1417
- }
1418
- const { realCurrentTime, textTrack } = this.#media.$state, { renderVTTCueString } = Captions.lib(), time = peek(realCurrentTime), activeCues = peek(textTrack).activeCues;
1419
- for (const cue of activeCues) {
1420
- const displayEl = this.#createCueDisplayElement(), cueEl = this.#createCueElement();
1421
- cueEl.innerHTML = renderVTTCueString(cue, time);
1422
- displayEl.append(cueEl);
1423
- this.el.append(cueEl);
1424
- }
1425
- }
1426
- #onUpdateTimedNodes() {
1427
- const { realCurrentTime } = this.#media.$state, { updateTimedVTTCueNodes } = Captions.lib();
1428
- updateTimedVTTCueNodes(this.el, realCurrentTime());
1429
- }
1430
- #setupVideoView() {
1431
- const { CaptionsRenderer } = Captions.lib(), renderer = new CaptionsRenderer(this.el), textRenderer = new CaptionsTextRenderer(renderer);
1432
- this.#media.textRenderers.add(textRenderer);
1433
- effect(this.#watchTextDirection.bind(this, renderer));
1434
- effect(this.#watchMediaTime.bind(this, renderer));
1435
- this.#listenToFontStyleChanges(renderer);
1436
- return () => {
1437
- this.el.textContent = "";
1438
- this.#media.textRenderers.remove(textRenderer);
1439
- renderer.destroy();
1440
- };
1441
- }
1442
- #watchTextDirection(renderer) {
1443
- renderer.dir = this.$props.textDir();
1444
- }
1445
- #watchMediaTime(renderer) {
1446
- if (this.#isHidden()) return;
1447
- const { realCurrentTime, textTrack } = this.#media.$state;
1448
- renderer.currentTime = realCurrentTime();
1449
- if (this.#hideExampleTimer >= 0 && textTrack()?.activeCues[0]) {
1450
- this.#removeExample();
1451
- }
1452
- }
1453
- #listenToFontStyleChanges(renderer) {
1454
- const player = this.#media.player;
1455
- if (!player) return;
1456
- this.#onFontStyleChange.bind(this, renderer);
1457
- }
1458
- #onFontStyleChange(renderer) {
1459
- if (this.#hideExampleTimer >= 0) {
1460
- this.#hideExample();
1461
- return;
1462
- }
1463
- const { textTrack } = this.#media.$state;
1464
- if (!textTrack()?.activeCues[0]) {
1465
- this.#showExample();
1466
- } else {
1467
- renderer?.update(true);
1468
- }
1469
- }
1470
- #showExample() {
1471
- const display = this.#createCueDisplayElement();
1472
- setAttribute(display, "data-example", "");
1473
- const cue = this.#createCueElement();
1474
- setAttribute(cue, "data-example", "");
1475
- cue.textContent = this.$props.exampleText();
1476
- display?.append(cue);
1477
- this.el?.append(display);
1478
- this.el?.setAttribute("data-example", "");
1479
- this.#hideExample();
1480
- }
1481
- #hideExampleTimer = -1;
1482
- #hideExample() {
1483
- window.clearTimeout(this.#hideExampleTimer);
1484
- this.#hideExampleTimer = window.setTimeout(this.#removeExample.bind(this), 2500);
1485
- }
1486
- #removeExample() {
1487
- this.el?.removeAttribute("data-example");
1488
- if (this.el?.querySelector("[data-example]")) this.el.textContent = "";
1489
- this.#hideExampleTimer = -1;
1490
- }
1491
- #createCueDisplayElement() {
1492
- const el = document.createElement("div");
1493
- setAttribute(el, "data-part", "cue-display");
1494
- return el;
1495
- }
1496
- #createCueElement() {
1497
- const el = document.createElement("div");
1498
- setAttribute(el, "data-part", "cue");
1499
- return el;
1500
- }
1501
- }
1502
-
1503
- export { AudioGainRadioGroup, AudioGainSlider, Captions, ChaptersRadioGroup, Controls, ControlsGroup, DEFAULT_AUDIO_GAINS, Gesture, GoogleCastButton, MediaAnnouncer, QualitySlider, RadioGroup, SliderChapters, SliderVideo, SpeedSlider, ToggleButton, Tooltip, TooltipContent, TooltipTrigger };