@videojs/html 10.0.0-beta.14 → 10.0.0-beta.16

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 (301) hide show
  1. package/cdn/audio-minimal-ui.dev.js +4 -5
  2. package/cdn/audio-minimal-ui.js +1 -1
  3. package/cdn/audio-minimal.dev.js +7 -8
  4. package/cdn/audio-minimal.dev.js.map +1 -1
  5. package/cdn/audio-minimal.js +1 -1
  6. package/cdn/audio-minimal.js.map +1 -1
  7. package/cdn/audio-ui.dev.js +5 -5
  8. package/cdn/audio-ui.js +1 -1
  9. package/cdn/audio.dev.js +23 -7
  10. package/cdn/audio.dev.js.map +1 -1
  11. package/cdn/audio.js +1 -1
  12. package/cdn/audio.js.map +1 -1
  13. package/cdn/background.dev.js +3 -3
  14. package/cdn/background.js +1 -1
  15. package/cdn/background.js.map +1 -1
  16. package/cdn/context-C-IpVHEt.js +14 -0
  17. package/cdn/context-C-IpVHEt.js.map +1 -0
  18. package/cdn/{context-BjrbhiSk.js → context-CvJ83xGk.js} +2 -83
  19. package/cdn/context-CvJ83xGk.js.map +1 -0
  20. package/cdn/create-player-B_oNyyb5.js +7 -0
  21. package/cdn/create-player-B_oNyyb5.js.map +1 -0
  22. package/cdn/{create-player-Cz5Y4DmL.js → create-player-DckZq-sE.js} +59 -1419
  23. package/cdn/create-player-DckZq-sE.js.map +1 -0
  24. package/cdn/{hls-DwNUcXDb.js → hls-CJCXZSGG.js} +43 -5
  25. package/cdn/hls-CJCXZSGG.js.map +1 -0
  26. package/cdn/{hls-A02jAc_G.js → hls-lPH0rWmB.js} +3 -3
  27. package/cdn/hls-lPH0rWmB.js.map +1 -0
  28. package/cdn/hotkey-B7OaweHa.js +154 -0
  29. package/cdn/hotkey-B7OaweHa.js.map +1 -0
  30. package/cdn/hotkey-BLEt77Z0.js +2 -0
  31. package/cdn/hotkey-BLEt77Z0.js.map +1 -0
  32. package/cdn/media/dash-video.dev.js +3 -4
  33. package/cdn/media/dash-video.dev.js.map +1 -1
  34. package/cdn/media/dash-video.js +2 -2
  35. package/cdn/media/hls-video.dev.js +4 -5
  36. package/cdn/media/hls-video.dev.js.map +1 -1
  37. package/cdn/media/hls-video.js +1 -1
  38. package/cdn/media/hls-video.js.map +1 -1
  39. package/cdn/media/mux-audio.dev.d.ts +1 -0
  40. package/cdn/media/mux-audio.dev.js +29 -0
  41. package/cdn/media/mux-audio.dev.js.map +1 -0
  42. package/cdn/media/mux-audio.js +2 -0
  43. package/cdn/media/mux-audio.js.map +1 -0
  44. package/cdn/media/mux-video.dev.js +5 -3099
  45. package/cdn/media/mux-video.dev.js.map +1 -1
  46. package/cdn/media/mux-video.js +1 -24
  47. package/cdn/media/mux-video.js.map +1 -1
  48. package/cdn/media/native-hls-video.dev.js +4 -4
  49. package/cdn/media/native-hls-video.js +1 -1
  50. package/cdn/media/simple-hls-video.dev.js +965 -680
  51. package/cdn/media/simple-hls-video.dev.js.map +1 -1
  52. package/cdn/media/simple-hls-video.js +6 -6
  53. package/cdn/media/simple-hls-video.js.map +1 -1
  54. package/cdn/{media-attach-mixin-DfKkofgF.js → media-attach-mixin-CMH1ziXP.js} +2 -2
  55. package/cdn/{media-attach-mixin-DfKkofgF.js.map → media-attach-mixin-CMH1ziXP.js.map} +1 -1
  56. package/cdn/{media-attach-mixin-Dv2D43tb.js → media-attach-mixin-DUzmXEJ3.js} +2 -2
  57. package/cdn/{media-attach-mixin-Dv2D43tb.js.map → media-attach-mixin-DUzmXEJ3.js.map} +1 -1
  58. package/cdn/{media-props-mixin-CNJVvHAH.js → media-props-mixin-CZLZIhGT.js} +100 -9
  59. package/cdn/media-props-mixin-CZLZIhGT.js.map +1 -0
  60. package/cdn/media-props-mixin-DrjlZybt.js +47 -0
  61. package/cdn/media-props-mixin-DrjlZybt.js.map +1 -0
  62. package/cdn/{minimal-BUUGNZK7.js → minimal-D9Dw-L2P.js} +1 -1
  63. package/cdn/{minimal-BUUGNZK7.js.map → minimal-D9Dw-L2P.js.map} +1 -1
  64. package/cdn/{minimal-CJGOJ6pE.js → minimal-Dc5nNl_-.js} +1 -1
  65. package/cdn/{minimal-CJGOJ6pE.js.map → minimal-Dc5nNl_-.js.map} +1 -1
  66. package/cdn/mux-CBXn2z5k.js +3102 -0
  67. package/cdn/mux-CBXn2z5k.js.map +1 -0
  68. package/cdn/mux-DmGzBNIq.js +25 -0
  69. package/cdn/mux-DmGzBNIq.js.map +1 -0
  70. package/cdn/{native-hls-CPgjPTAQ.js → native-hls-BCOLtRUl.js} +2 -3
  71. package/cdn/{native-hls-CPgjPTAQ.js.map → native-hls-BCOLtRUl.js.map} +1 -1
  72. package/cdn/native-hls-BU8--1Kg.js +2 -0
  73. package/cdn/{native-hls-Db2TurPW.js.map → native-hls-BU8--1Kg.js.map} +1 -1
  74. package/cdn/player-DAmuLGE1.js +2 -0
  75. package/cdn/{player-DlGhe0FD.js.map → player-DAmuLGE1.js.map} +1 -1
  76. package/cdn/{player-XArb4DyB.js → player-Dbl1MUJ2.js} +3 -3
  77. package/cdn/{player-XArb4DyB.js.map → player-Dbl1MUJ2.js.map} +1 -1
  78. package/cdn/poster-B9COb7AR.js +2 -0
  79. package/cdn/poster-B9COb7AR.js.map +1 -0
  80. package/cdn/poster-qAhnKWea.js +480 -0
  81. package/cdn/poster-qAhnKWea.js.map +1 -0
  82. package/cdn/{skin-element-Dk_f7DE8.js → skin-element-DbmY-ske.js} +2 -2
  83. package/cdn/{skin-element-Dk_f7DE8.js.map → skin-element-DbmY-ske.js.map} +1 -1
  84. package/cdn/{skin-element-D40glySA.js → skin-element-ih3VrnYx.js} +2 -2
  85. package/cdn/{skin-element-D40glySA.js.map → skin-element-ih3VrnYx.js.map} +1 -1
  86. package/cdn/video-minimal-ui.dev.js +4 -5
  87. package/cdn/video-minimal-ui.js +1 -1
  88. package/cdn/video-minimal.dev.js +7 -8
  89. package/cdn/video-minimal.dev.js.map +1 -1
  90. package/cdn/video-minimal.js +1 -1
  91. package/cdn/video-minimal.js.map +1 -1
  92. package/cdn/video-ui.dev.js +5 -5
  93. package/cdn/video-ui.js +1 -1
  94. package/cdn/video.dev.js +26 -7
  95. package/cdn/video.dev.js.map +1 -1
  96. package/cdn/video.js +1 -1
  97. package/cdn/video.js.map +1 -1
  98. package/cdn/volume-slider-BbIc1N4U.js +8 -0
  99. package/cdn/volume-slider-BbIc1N4U.js.map +1 -0
  100. package/cdn/{volume-slider-CxGbFVVX.js → volume-slider-C6ek7oC9.js} +1855 -386
  101. package/cdn/volume-slider-C6ek7oC9.js.map +1 -0
  102. package/dist/default/_virtual/inline-css_src/define/audio/minimal-skin.js +1 -1
  103. package/dist/default/_virtual/inline-css_src/define/audio/minimal-skin.js.map +1 -1
  104. package/dist/default/_virtual/inline-css_src/define/audio/skin.js +1 -1
  105. package/dist/default/_virtual/inline-css_src/define/audio/skin.js.map +1 -1
  106. package/dist/default/_virtual/inline-css_src/define/video/minimal-skin.js +1 -1
  107. package/dist/default/_virtual/inline-css_src/define/video/minimal-skin.js.map +1 -1
  108. package/dist/default/_virtual/inline-css_src/define/video/skin.js +1 -1
  109. package/dist/default/_virtual/inline-css_src/define/video/skin.js.map +1 -1
  110. package/dist/default/define/audio/minimal-skin.css +23 -0
  111. package/dist/default/define/audio/skin.css +23 -0
  112. package/dist/default/define/audio/skin.js +1 -1
  113. package/dist/default/define/audio/skin.js.map +1 -1
  114. package/dist/default/define/audio/ui.js +1 -0
  115. package/dist/default/define/background/skin.js +1 -1
  116. package/dist/default/define/media/mux-audio.js +13 -0
  117. package/dist/default/define/media/mux-audio.js.map +1 -0
  118. package/dist/default/define/skin-element.js +1 -1
  119. package/dist/default/define/ui/hotkey.js +7 -0
  120. package/dist/default/define/ui/hotkey.js.map +1 -0
  121. package/dist/default/define/ui/slider.js +1 -1
  122. package/dist/default/define/ui/time-slider.js +1 -1
  123. package/dist/default/define/ui/volume-slider.js +1 -1
  124. package/dist/default/define/video/minimal-skin.css +23 -0
  125. package/dist/default/define/video/skin.css +23 -0
  126. package/dist/default/define/video/skin.js +1 -1
  127. package/dist/default/define/video/skin.js.map +1 -1
  128. package/dist/default/define/video/ui.js +1 -0
  129. package/dist/default/index.js +5 -1
  130. package/dist/default/media/container-element.js +16 -0
  131. package/dist/default/media/container-element.js.map +1 -1
  132. package/dist/default/media/mux-audio/index.js +18 -0
  133. package/dist/default/media/mux-audio/index.js.map +1 -0
  134. package/dist/default/player/context.js.map +1 -1
  135. package/dist/default/ui/alert-dialog/alert-dialog-element.js +1 -0
  136. package/dist/default/ui/alert-dialog/alert-dialog-element.js.map +1 -1
  137. package/dist/default/ui/buffering-indicator/buffering-indicator-element.js +1 -0
  138. package/dist/default/ui/buffering-indicator/buffering-indicator-element.js.map +1 -1
  139. package/dist/default/ui/captions-button/captions-button-element.js +1 -0
  140. package/dist/default/ui/captions-button/captions-button-element.js.map +1 -1
  141. package/dist/default/ui/error-dialog/error-dialog-element.js +1 -0
  142. package/dist/default/ui/error-dialog/error-dialog-element.js.map +1 -1
  143. package/dist/default/ui/fullscreen-button/fullscreen-button-element.js +1 -0
  144. package/dist/default/ui/fullscreen-button/fullscreen-button-element.js.map +1 -1
  145. package/dist/default/ui/hotkey/aria-key-shortcuts-controller.js +28 -0
  146. package/dist/default/ui/hotkey/aria-key-shortcuts-controller.js.map +1 -0
  147. package/dist/default/ui/hotkey/hotkey-element.js +81 -0
  148. package/dist/default/ui/hotkey/hotkey-element.js.map +1 -0
  149. package/dist/default/ui/media-button-element.js +9 -1
  150. package/dist/default/ui/media-button-element.js.map +1 -1
  151. package/dist/default/ui/mute-button/mute-button-element.js +1 -0
  152. package/dist/default/ui/mute-button/mute-button-element.js.map +1 -1
  153. package/dist/default/ui/pip-button/pip-button-element.js +1 -0
  154. package/dist/default/ui/pip-button/pip-button-element.js.map +1 -1
  155. package/dist/default/ui/play-button/play-button-element.js +1 -0
  156. package/dist/default/ui/play-button/play-button-element.js.map +1 -1
  157. package/dist/default/ui/popover/popover-element.js +7 -55
  158. package/dist/default/ui/popover/popover-element.js.map +1 -1
  159. package/dist/default/ui/position-controller.js +76 -0
  160. package/dist/default/ui/position-controller.js.map +1 -0
  161. package/dist/default/ui/slider/slider-element.js +1 -1
  162. package/dist/default/ui/slider/slider-preview-element.js +1 -1
  163. package/dist/default/ui/time-slider/time-slider-element.js +5 -5
  164. package/dist/default/ui/time-slider/time-slider-element.js.map +1 -1
  165. package/dist/default/ui/tooltip/tooltip-element.js +8 -54
  166. package/dist/default/ui/tooltip/tooltip-element.js.map +1 -1
  167. package/dist/default/ui/volume-slider/volume-slider-element.js +1 -1
  168. package/dist/dev/_virtual/inline-css_src/define/audio/minimal-skin.js +1 -1
  169. package/dist/dev/_virtual/inline-css_src/define/audio/minimal-skin.js.map +1 -1
  170. package/dist/dev/_virtual/inline-css_src/define/audio/skin.js +1 -1
  171. package/dist/dev/_virtual/inline-css_src/define/audio/skin.js.map +1 -1
  172. package/dist/dev/_virtual/inline-css_src/define/video/minimal-skin.js +1 -1
  173. package/dist/dev/_virtual/inline-css_src/define/video/minimal-skin.js.map +1 -1
  174. package/dist/dev/_virtual/inline-css_src/define/video/skin.js +1 -1
  175. package/dist/dev/_virtual/inline-css_src/define/video/skin.js.map +1 -1
  176. package/dist/dev/define/audio/minimal-skin.css +23 -0
  177. package/dist/dev/define/audio/skin.css +23 -0
  178. package/dist/dev/define/audio/skin.d.ts.map +1 -1
  179. package/dist/dev/define/audio/skin.js +16 -0
  180. package/dist/dev/define/audio/skin.js.map +1 -1
  181. package/dist/dev/define/audio/ui.js +1 -0
  182. package/dist/dev/define/background/skin.js +1 -1
  183. package/dist/dev/define/media/mux-audio.d.ts +14 -0
  184. package/dist/dev/define/media/mux-audio.d.ts.map +1 -0
  185. package/dist/dev/define/media/mux-audio.js +13 -0
  186. package/dist/dev/define/media/mux-audio.js.map +1 -0
  187. package/dist/dev/define/skin-element.d.ts +1 -1
  188. package/dist/dev/define/skin-element.js +1 -1
  189. package/dist/dev/define/ui/hotkey.d.ts +9 -0
  190. package/dist/dev/define/ui/hotkey.d.ts.map +1 -0
  191. package/dist/dev/define/ui/hotkey.js +7 -0
  192. package/dist/dev/define/ui/hotkey.js.map +1 -0
  193. package/dist/dev/define/ui/slider.js +1 -1
  194. package/dist/dev/define/ui/time-slider.js +1 -1
  195. package/dist/dev/define/ui/volume-slider.js +1 -1
  196. package/dist/dev/define/video/minimal-skin.css +23 -0
  197. package/dist/dev/define/video/skin.css +23 -0
  198. package/dist/dev/define/video/skin.d.ts.map +1 -1
  199. package/dist/dev/define/video/skin.js +19 -0
  200. package/dist/dev/define/video/skin.js.map +1 -1
  201. package/dist/dev/define/video/ui.js +1 -0
  202. package/dist/dev/index.d.ts +6 -2
  203. package/dist/dev/index.js +5 -1
  204. package/dist/dev/media/container-element.d.ts +3 -0
  205. package/dist/dev/media/container-element.d.ts.map +1 -1
  206. package/dist/dev/media/container-element.js +16 -0
  207. package/dist/dev/media/container-element.js.map +1 -1
  208. package/dist/dev/media/mux-audio/index.d.ts +11 -0
  209. package/dist/dev/media/mux-audio/index.d.ts.map +1 -0
  210. package/dist/dev/media/mux-audio/index.js +18 -0
  211. package/dist/dev/media/mux-audio/index.js.map +1 -0
  212. package/dist/dev/player/context.d.ts +4 -2
  213. package/dist/dev/player/context.d.ts.map +1 -1
  214. package/dist/dev/player/context.js.map +1 -1
  215. package/dist/dev/ui/alert-dialog/alert-dialog-element.d.ts.map +1 -1
  216. package/dist/dev/ui/alert-dialog/alert-dialog-element.js +1 -0
  217. package/dist/dev/ui/alert-dialog/alert-dialog-element.js.map +1 -1
  218. package/dist/dev/ui/buffering-indicator/buffering-indicator-element.d.ts.map +1 -1
  219. package/dist/dev/ui/buffering-indicator/buffering-indicator-element.js +1 -0
  220. package/dist/dev/ui/buffering-indicator/buffering-indicator-element.js.map +1 -1
  221. package/dist/dev/ui/captions-button/captions-button-element.d.ts +1 -0
  222. package/dist/dev/ui/captions-button/captions-button-element.d.ts.map +1 -1
  223. package/dist/dev/ui/captions-button/captions-button-element.js +1 -0
  224. package/dist/dev/ui/captions-button/captions-button-element.js.map +1 -1
  225. package/dist/dev/ui/context-part-element.d.ts +1 -1
  226. package/dist/dev/ui/error-dialog/error-dialog-element.d.ts.map +1 -1
  227. package/dist/dev/ui/error-dialog/error-dialog-element.js +1 -0
  228. package/dist/dev/ui/error-dialog/error-dialog-element.js.map +1 -1
  229. package/dist/dev/ui/fullscreen-button/fullscreen-button-element.d.ts +1 -0
  230. package/dist/dev/ui/fullscreen-button/fullscreen-button-element.d.ts.map +1 -1
  231. package/dist/dev/ui/fullscreen-button/fullscreen-button-element.js +1 -0
  232. package/dist/dev/ui/fullscreen-button/fullscreen-button-element.js.map +1 -1
  233. package/dist/dev/ui/hotkey/aria-key-shortcuts-controller.d.ts +15 -0
  234. package/dist/dev/ui/hotkey/aria-key-shortcuts-controller.d.ts.map +1 -0
  235. package/dist/dev/ui/hotkey/aria-key-shortcuts-controller.js +28 -0
  236. package/dist/dev/ui/hotkey/aria-key-shortcuts-controller.js.map +1 -0
  237. package/dist/dev/ui/hotkey/hotkey-element.d.ts +21 -0
  238. package/dist/dev/ui/hotkey/hotkey-element.d.ts.map +1 -0
  239. package/dist/dev/ui/hotkey/hotkey-element.js +81 -0
  240. package/dist/dev/ui/hotkey/hotkey-element.js.map +1 -0
  241. package/dist/dev/ui/media-button-element.d.ts +2 -0
  242. package/dist/dev/ui/media-button-element.d.ts.map +1 -1
  243. package/dist/dev/ui/media-button-element.js +9 -1
  244. package/dist/dev/ui/media-button-element.js.map +1 -1
  245. package/dist/dev/ui/mute-button/mute-button-element.d.ts +1 -0
  246. package/dist/dev/ui/mute-button/mute-button-element.d.ts.map +1 -1
  247. package/dist/dev/ui/mute-button/mute-button-element.js +1 -0
  248. package/dist/dev/ui/mute-button/mute-button-element.js.map +1 -1
  249. package/dist/dev/ui/pip-button/pip-button-element.d.ts +1 -0
  250. package/dist/dev/ui/pip-button/pip-button-element.d.ts.map +1 -1
  251. package/dist/dev/ui/pip-button/pip-button-element.js +1 -0
  252. package/dist/dev/ui/pip-button/pip-button-element.js.map +1 -1
  253. package/dist/dev/ui/play-button/play-button-element.d.ts +1 -0
  254. package/dist/dev/ui/play-button/play-button-element.d.ts.map +1 -1
  255. package/dist/dev/ui/play-button/play-button-element.js +1 -0
  256. package/dist/dev/ui/play-button/play-button-element.js.map +1 -1
  257. package/dist/dev/ui/popover/popover-element.d.ts.map +1 -1
  258. package/dist/dev/ui/popover/popover-element.js +7 -55
  259. package/dist/dev/ui/popover/popover-element.js.map +1 -1
  260. package/dist/dev/ui/position-controller.js +76 -0
  261. package/dist/dev/ui/position-controller.js.map +1 -0
  262. package/dist/dev/ui/slider/slider-element.js +1 -1
  263. package/dist/dev/ui/slider/slider-preview-element.d.ts +21 -0
  264. package/dist/dev/ui/slider/slider-preview-element.d.ts.map +1 -0
  265. package/dist/dev/ui/slider/slider-preview-element.js +1 -1
  266. package/dist/dev/ui/time-slider/time-slider-element.d.ts +2 -2
  267. package/dist/dev/ui/time-slider/time-slider-element.js +5 -5
  268. package/dist/dev/ui/time-slider/time-slider-element.js.map +1 -1
  269. package/dist/dev/ui/tooltip/tooltip-element.d.ts.map +1 -1
  270. package/dist/dev/ui/tooltip/tooltip-element.js +8 -54
  271. package/dist/dev/ui/tooltip/tooltip-element.js.map +1 -1
  272. package/dist/dev/ui/volume-slider/volume-slider-element.js +1 -1
  273. package/package.json +8 -8
  274. package/cdn/context-BjrbhiSk.js.map +0 -1
  275. package/cdn/context-CdkhXQEw.js +0 -14
  276. package/cdn/context-CdkhXQEw.js.map +0 -1
  277. package/cdn/create-player-Cz5Y4DmL.js.map +0 -1
  278. package/cdn/create-player-DSGjDLpM.js +0 -7
  279. package/cdn/create-player-DSGjDLpM.js.map +0 -1
  280. package/cdn/delegate-B626t_Va.js +0 -2
  281. package/cdn/delegate-B626t_Va.js.map +0 -1
  282. package/cdn/delegate-BCw-LjP_.js +0 -56
  283. package/cdn/delegate-BCw-LjP_.js.map +0 -1
  284. package/cdn/hls-A02jAc_G.js.map +0 -1
  285. package/cdn/hls-DwNUcXDb.js.map +0 -1
  286. package/cdn/media-props-mixin-CNJVvHAH.js.map +0 -1
  287. package/cdn/media-props-mixin-CmboksUe.js +0 -47
  288. package/cdn/media-props-mixin-CmboksUe.js.map +0 -1
  289. package/cdn/native-hls-Db2TurPW.js +0 -2
  290. package/cdn/player-DlGhe0FD.js +0 -2
  291. package/cdn/poster-BUuGv2Va.js +0 -215
  292. package/cdn/poster-BUuGv2Va.js.map +0 -1
  293. package/cdn/poster-Crn2YX3_.js +0 -2
  294. package/cdn/poster-Crn2YX3_.js.map +0 -1
  295. package/cdn/volume-slider-BSbnD5gg.js +0 -8
  296. package/cdn/volume-slider-BSbnD5gg.js.map +0 -1
  297. package/cdn/volume-slider-CxGbFVVX.js.map +0 -1
  298. /package/cdn/{minimal-ui-BL9eBXck.js → minimal-ui-DXFwjywa.js} +0 -0
  299. /package/cdn/{minimal-ui-a1UOKF79.js → minimal-ui-jrmrxIOn.js} +0 -0
  300. /package/cdn/{ui-CFIgmrlA.js → ui-18UYtw8D.js} +0 -0
  301. /package/cdn/{ui-Ccp_LyCf.js → ui-8HVY3XSt.js} +0 -0
@@ -1,5 +1,6 @@
1
- import { C as getAnchorPositionStyle, D as createButton, E as createPopover, F as selectPlaybackRate, G as isUndefined, H as createState, I as selectTextTrack, J as tryHidePopover, L as selectTime, O as createAlertDialog, P as selectPlayback, R as selectVolume, S as getAnchorNameStyle, T as resolveOffsets, U as isFunction, W as isNumber, X as supportsAnchorPositioning, Y as tryShowPopover, _ as getSliderPreviewStyle, a as MediaElement, b as clamp, c as applyStateDataAttrs, d as createWheelStep, f as createTransition, g as getSliderCSSVars, h as ThumbnailCore, j as selectError, k as selectBuffer, l as logMissingFeature, m as createThumbnail, n as PlayerController, o as ContextProvider, p as createTooltip, q as applyStyles, r as SnapshotController, s as ContextConsumer, u as applyElementProps, v as getTimeSliderCSSVars, w as getPopupPositionRect, x as roundToStep, y as createSlider } from "./create-player-Cz5Y4DmL.js";
2
- import { i as createContext, r as playerContext, s as safeDefine } from "./context-BjrbhiSk.js";
1
+ import { C as noop, D as isNull, E as isFunction, O as isNumber, S as createState, T as AbortControllerRegistry, _ as pipFeature, a as MediaElement, b as controlsFeature, d as volumeFeature, f as timeFeature, g as playbackFeature, h as playbackRateFeature, j as resolveEventTarget, k as isUndefined, m as sourceFeature, n as PlayerController, o as ContextProvider, p as textTrackFeature, r as SnapshotController, s as ContextConsumer, v as fullscreenFeature, w as throwNoTargetError, x as bufferFeature, y as errorFeature } from "./create-player-DckZq-sE.js";
2
+ import { t as listen } from "./listen-w-Aun0yN.js";
3
+ import { i as createContext, o as safeDefine, r as playerContext, t as containerContext } from "./context-CvJ83xGk.js";
3
4
 
4
5
  //#region ../utils/dist/dom/direction.js
5
6
  /** Check whether an element's text direction is right-to-left. */
@@ -9,6 +10,98 @@ function isRTL(element) {
9
10
  return getComputedStyle(element).direction === "rtl";
10
11
  }
11
12
 
13
+ //#endregion
14
+ //#region ../utils/dist/dom/supports.js
15
+ function supportsAnchorPositioning() {
16
+ return typeof CSS !== "undefined" && CSS.supports("anchor-name: --a");
17
+ }
18
+
19
+ //#endregion
20
+ //#region ../utils/dist/dom/platform.js
21
+ function isMacOS() {
22
+ return typeof navigator !== "undefined" && /mac/i.test(navigator.userAgent);
23
+ }
24
+
25
+ //#endregion
26
+ //#region ../utils/dist/dom/popover.js
27
+ function tryShowPopover(el) {
28
+ try {
29
+ el?.showPopover?.();
30
+ } catch {}
31
+ }
32
+ function tryHidePopover(el) {
33
+ try {
34
+ el?.hidePopover?.();
35
+ } catch {}
36
+ }
37
+
38
+ //#endregion
39
+ //#region ../utils/dist/dom/predicates.js
40
+ const EDITABLE_INPUT_TYPES = new Set([
41
+ "text",
42
+ "search",
43
+ "url",
44
+ "tel",
45
+ "email",
46
+ "password",
47
+ "number"
48
+ ]);
49
+ function isEditableElement(el) {
50
+ if (el instanceof HTMLTextAreaElement) return true;
51
+ if (el instanceof HTMLSelectElement) return true;
52
+ if (el instanceof HTMLInputElement) return EDITABLE_INPUT_TYPES.has(el.type.toLowerCase());
53
+ if (!(el instanceof HTMLElement)) return false;
54
+ const editable = el.getAttribute("contenteditable");
55
+ return editable !== null && editable !== "false";
56
+ }
57
+ /** Whether the keyboard event target is an editable element (input, textarea, etc). */
58
+ function isEditableTarget(event) {
59
+ const target = resolveEventTarget(event);
60
+ return target instanceof Element && isEditableElement(target);
61
+ }
62
+
63
+ //#endregion
64
+ //#region ../utils/dist/string/casing.js
65
+ function kebabCase(str) {
66
+ return str.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
67
+ }
68
+
69
+ //#endregion
70
+ //#region ../utils/dist/dom/style.js
71
+ function applyStyles(element, styles) {
72
+ for (const [prop, value] of Object.entries(styles)) if (typeof value === "string") {
73
+ const key = prop.startsWith("--") ? prop : kebabCase(prop);
74
+ element.style.setProperty(key, value);
75
+ }
76
+ }
77
+ function resolveCSSLength(el, value) {
78
+ const trimmed = value.trim();
79
+ if (!trimmed) return 0;
80
+ const parsed = Number.parseFloat(trimmed);
81
+ if (Number.isNaN(parsed)) return 0;
82
+ if (/^-?\d*\.?\d+$/.test(trimmed) || trimmed.endsWith("px")) return parsed;
83
+ const doc = el.ownerDocument;
84
+ const root = doc?.documentElement;
85
+ if (trimmed.endsWith("rem")) return parsed * (root ? Number.parseFloat(getComputedStyle(root).fontSize) || 16 : 16);
86
+ if (trimmed.endsWith("em")) return parsed * (el instanceof HTMLElement ? Number.parseFloat(getComputedStyle(el).fontSize) || 16 : 16);
87
+ if (!doc) return parsed;
88
+ const measurementEl = doc.createElement("div");
89
+ measurementEl.style.position = "absolute";
90
+ measurementEl.style.visibility = "hidden";
91
+ measurementEl.style.pointerEvents = "none";
92
+ measurementEl.style.inlineSize = trimmed;
93
+ measurementEl.style.blockSize = "0";
94
+ measurementEl.style.padding = "0";
95
+ measurementEl.style.border = "0";
96
+ measurementEl.style.inset = "0";
97
+ const parent = doc.body ?? doc.documentElement;
98
+ if (!parent) return parsed;
99
+ parent.appendChild(measurementEl);
100
+ const pixels = measurementEl.getBoundingClientRect().width;
101
+ measurementEl.remove();
102
+ return Number.isFinite(pixels) ? pixels : parsed;
103
+ }
104
+
12
105
  //#endregion
13
106
  //#region ../utils/dist/object/defaults.js
14
107
  /**
@@ -28,250 +121,1695 @@ function defaults(object, defaultValues) {
28
121
  }
29
122
 
30
123
  //#endregion
31
- //#region ../core/dist/dev/core/ui/transition.js
32
- function getTransitionFlags(status) {
33
- return {
34
- transitionStarting: status === "starting",
35
- transitionEnding: status === "ending"
36
- };
124
+ //#region ../utils/dist/object/pick.js
125
+ /**
126
+ * Creates a new object with only the specified keys.
127
+ *
128
+ * @example
129
+ * const obj = { a: 1, b: 2, c: 3 };
130
+ * pick(obj, ['a', 'c']); // { a: 1, c: 3 }
131
+ */
132
+ function pick(obj, keys) {
133
+ const result = {};
134
+ for (const key of keys) result[key] = obj[key];
135
+ return result;
37
136
  }
38
137
 
39
138
  //#endregion
40
- //#region ../core/dist/dev/core/ui/alert-dialog/alert-dialog-core.js
41
- var AlertDialogCore = class {
42
- static defaultProps = {
43
- open: false,
44
- defaultOpen: false
139
+ //#region ../store/dist/dev/core/selector.js
140
+ const stateContext = {
141
+ target: throwNoTargetError,
142
+ signals: new AbortControllerRegistry(),
143
+ get: throwNoTargetError,
144
+ set: throwNoTargetError
145
+ };
146
+ /**
147
+ * Create a type-safe selector for a slice's state.
148
+ *
149
+ * The selector returns the slice's state, or `undefined` if the slice
150
+ * is not configured in the store.
151
+ *
152
+ * @example
153
+ * ```ts
154
+ * const selectPlayback = createSelector(playbackSlice);
155
+ * selectPlayback(store.state); // { paused, play, pause, ... } | undefined
156
+ * selectPlayback.displayName; // 'playback' (from slice name)
157
+ * ```
158
+ *
159
+ * @param slice - The slice to create a selector for.
160
+ */
161
+ function createSelector(slice) {
162
+ const initialState = slice.state(stateContext);
163
+ const keys = Object.keys(initialState);
164
+ const firstKey = keys[0];
165
+ if (!firstKey) return Object.assign(() => void 0, { displayName: slice.name });
166
+ return Object.assign((state) => {
167
+ if (!(firstKey in state)) return void 0;
168
+ return pick(state, keys);
169
+ }, { displayName: slice.name });
170
+ }
171
+
172
+ //#endregion
173
+ //#region ../utils/dist/function/throttle.js
174
+ /**
175
+ * Throttle: limits `fn` to at most once per `ms` window.
176
+ *
177
+ * - Default (no options): trailing-edge only — the first call schedules a
178
+ * timer; subsequent calls within the window update the arguments. The
179
+ * function fires once per window with the latest arguments.
180
+ * - `{ leading: true }`: leading + trailing — the first call invokes
181
+ * immediately and opens a cooldown window. Subsequent calls within the
182
+ * window are coalesced to a single trailing-edge invocation.
183
+ */
184
+ function throttle(fn, ms, options) {
185
+ const leading = options?.leading ?? false;
186
+ let timerId = null;
187
+ let latestArgs;
188
+ let hasPending = false;
189
+ function startCooldown() {
190
+ timerId = setTimeout(() => {
191
+ timerId = null;
192
+ if (hasPending) {
193
+ hasPending = false;
194
+ fn(...latestArgs);
195
+ startCooldown();
196
+ }
197
+ }, ms);
198
+ }
199
+ const throttled = (...args) => {
200
+ latestArgs = args;
201
+ if (leading) if (timerId === null) {
202
+ fn(...latestArgs);
203
+ startCooldown();
204
+ } else hasPending = true;
205
+ else {
206
+ if (timerId !== null) return;
207
+ timerId = setTimeout(() => {
208
+ timerId = null;
209
+ fn(...latestArgs);
210
+ }, ms);
211
+ }
45
212
  };
46
- /** Accept props for API consistency. Props are consumed by platform layers. */
47
- setProps(_props) {}
48
- #input = null;
49
- #titleId = void 0;
50
- #descriptionId = void 0;
51
- setInput(input) {
52
- this.#input = input;
213
+ throttled.cancel = () => {
214
+ if (timerId !== null) {
215
+ clearTimeout(timerId);
216
+ timerId = null;
217
+ }
218
+ hasPending = false;
219
+ };
220
+ return throttled;
221
+ }
222
+
223
+ //#endregion
224
+ //#region ../core/dist/dev/dom/store/selectors.js
225
+ /** Select the buffer state (buffered ranges, percent buffered). */
226
+ const selectBuffer = createSelector(bufferFeature);
227
+ /** Select the controls state (controls visible, user-active). */
228
+ const selectControls = createSelector(controlsFeature);
229
+ /** Select the error state (error, dismissed, dismissError). */
230
+ const selectError = createSelector(errorFeature);
231
+ /** Select the fullscreen state (fullscreen active, availability). */
232
+ const selectFullscreen = createSelector(fullscreenFeature);
233
+ /** Select the PiP state (picture-in-picture active, availability). */
234
+ const selectPiP = createSelector(pipFeature);
235
+ /** Select the playback state (paused, ended, play, pause, toggle). */
236
+ const selectPlayback = createSelector(playbackFeature);
237
+ /** Select the playback rate state (playbackRate, playbackRates, setPlaybackRate). */
238
+ const selectPlaybackRate = createSelector(playbackRateFeature);
239
+ /** Select the source state (src, type). */
240
+ const selectSource = createSelector(sourceFeature);
241
+ /** Select the text track state (chapters cues, thumbnail cues). */
242
+ const selectTextTrack = createSelector(textTrackFeature);
243
+ /** Select the time state (currentTime, duration, seek). */
244
+ const selectTime = createSelector(timeFeature);
245
+ /** Select the volume state (volume, muted, setVolume, setMuted). */
246
+ const selectVolume = createSelector(volumeFeature);
247
+
248
+ //#endregion
249
+ //#region ../core/dist/dev/dom/hotkey/aria.js
250
+ const ARIA_MODIFIER_MAP = {
251
+ shift: "Shift",
252
+ ctrl: "Control",
253
+ alt: "Alt",
254
+ meta: "Meta"
255
+ };
256
+ const MODIFIER_ORDER = [
257
+ "ctrl",
258
+ "shift",
259
+ "alt",
260
+ "meta"
261
+ ];
262
+ /**
263
+ * Convert parsed key bindings to a WAI-ARIA `aria-keyshortcuts` formatted string.
264
+ *
265
+ * @example
266
+ * ```ts
267
+ * toAriaKeyShortcut(parseHotkeyPattern('Ctrl+Shift+f'));
268
+ * // "Control+Shift+f"
269
+ *
270
+ * toAriaKeyShortcut([...parseHotkeyPattern('k'), ...parseHotkeyPattern('Space')]);
271
+ * // "k Space"
272
+ * ```
273
+ */
274
+ function toAriaKeyShortcut(bindings) {
275
+ return bindings.map((b) => {
276
+ const parts = [];
277
+ for (const mod of MODIFIER_ORDER) if (b.modifiers.has(mod)) parts.push(ARIA_MODIFIER_MAP[mod]);
278
+ parts.push(b.originalKey);
279
+ return parts.join("+");
280
+ }).join(" ");
281
+ }
282
+
283
+ //#endregion
284
+ //#region ../core/dist/dev/dom/hotkey/coordinator.js
285
+ const ACTIVATION_KEYS = new Set([" ", "Enter"]);
286
+ /** Whether the event is an activation key on an interactive element (button, slider). */
287
+ function isInteractiveActivation(event) {
288
+ if (!ACTIVATION_KEYS.has(event.key)) return false;
289
+ const target = resolveEventTarget(event);
290
+ if (!(target instanceof HTMLElement)) return false;
291
+ if (target instanceof HTMLButtonElement) return true;
292
+ const role = target.getAttribute("role");
293
+ return role === "button" || role === "slider";
294
+ }
295
+ var HotkeyCoordinator = class {
296
+ #target;
297
+ #bindings = [];
298
+ #nextId = 0;
299
+ #disconnect = null;
300
+ #docDisconnect = null;
301
+ /** Action name → bound keys. Controls query this to set `aria-keyshortcuts`. */
302
+ #ariaRegistry = /* @__PURE__ */ new Map();
303
+ #destroyed = false;
304
+ constructor(target) {
305
+ this.#target = target;
306
+ }
307
+ add(options) {
308
+ const parsed = parseHotkeyPattern(options.keys);
309
+ const binding = {
310
+ parsed,
311
+ options,
312
+ id: this.#nextId++
313
+ };
314
+ this.#bindings.push(binding);
315
+ this.#sortBindings();
316
+ if (options.action) this.#addToAriaRegistry(options.action, parsed);
317
+ if (options.target === "document") this.#connectDocument();
318
+ else this.#connect();
319
+ let removed = false;
320
+ return () => {
321
+ if (removed) return;
322
+ removed = true;
323
+ const idx = this.#bindings.indexOf(binding);
324
+ if (idx !== -1) this.#bindings.splice(idx, 1);
325
+ if (options.action) this.#removeFromAriaRegistry(options.action, parsed);
326
+ this.#maybeDisconnect();
327
+ };
53
328
  }
54
- setTitleId(id) {
55
- this.#titleId = id;
329
+ getAriaKeys(action) {
330
+ const bindings = this.#ariaRegistry.get(action);
331
+ if (!bindings?.length) return void 0;
332
+ return toAriaKeyShortcut(bindings);
56
333
  }
57
- setDescriptionId(id) {
58
- this.#descriptionId = id;
334
+ destroy() {
335
+ if (this.#destroyed) return;
336
+ this.#destroyed = true;
337
+ this.#disconnect?.abort();
338
+ this.#disconnect = null;
339
+ this.#docDisconnect?.abort();
340
+ this.#docDisconnect = null;
341
+ this.#bindings = [];
342
+ this.#ariaRegistry.clear();
343
+ }
344
+ #sortBindings() {
345
+ this.#bindings.sort((a, b) => {
346
+ const specDiff = b.parsed[0].modifiers.size - a.parsed[0].modifiers.size;
347
+ if (specDiff !== 0) return specDiff;
348
+ return a.id - b.id;
349
+ });
59
350
  }
60
- getState() {
61
- const input = this.#input;
62
- return {
63
- open: input.active,
64
- status: input.status,
65
- titleId: this.#titleId,
66
- descriptionId: this.#descriptionId,
67
- ...getTransitionFlags(input.status)
68
- };
351
+ #connect() {
352
+ if (this.#disconnect) return;
353
+ this.#disconnect = new AbortController();
354
+ listen(this.#target, "keydown", this.#handleEvent, { signal: this.#disconnect.signal });
355
+ }
356
+ #connectDocument() {
357
+ if (this.#docDisconnect) return;
358
+ this.#docDisconnect = new AbortController();
359
+ listen(document, "keydown", this.#handleEvent, { signal: this.#docDisconnect.signal });
360
+ }
361
+ #maybeDisconnect() {
362
+ const hasPlayer = this.#bindings.some((b) => b.options.target !== "document");
363
+ const hasDoc = this.#bindings.some((b) => b.options.target === "document");
364
+ if (!hasPlayer) {
365
+ this.#disconnect?.abort();
366
+ this.#disconnect = null;
367
+ }
368
+ if (!hasDoc) {
369
+ this.#docDisconnect?.abort();
370
+ this.#docDisconnect = null;
371
+ }
69
372
  }
70
- getAttrs(state) {
71
- return {
72
- role: "alertdialog",
73
- "aria-modal": "true",
74
- "aria-labelledby": state.titleId,
75
- "aria-describedby": state.descriptionId
76
- };
373
+ #handleEvent = (event) => {
374
+ if (event.key === "Unidentified") return;
375
+ if (isInteractiveActivation(event)) return;
376
+ const editable = isEditableTarget(event);
377
+ for (const binding of this.#bindings) {
378
+ const { options, parsed } = binding;
379
+ if (options.disabled) continue;
380
+ if (event.repeat && options.repeatable === false) continue;
381
+ if (options.target === "document" !== (event.currentTarget === document)) continue;
382
+ for (const p of parsed) {
383
+ if (!matchesHotkeyEvent(p, event)) continue;
384
+ if (editable && p.modifiers.size === 0) continue;
385
+ event.preventDefault();
386
+ options.onActivate(event, p.originalKey);
387
+ return;
388
+ }
389
+ }
390
+ };
391
+ #addToAriaRegistry(action, bindings) {
392
+ let existing = this.#ariaRegistry.get(action);
393
+ if (!existing) {
394
+ existing = [];
395
+ this.#ariaRegistry.set(action, existing);
396
+ }
397
+ existing.push(...bindings);
398
+ }
399
+ #removeFromAriaRegistry(action, bindings) {
400
+ const existing = this.#ariaRegistry.get(action);
401
+ if (!existing) return;
402
+ const filtered = existing.filter((b) => !bindings.includes(b));
403
+ if (filtered.length === 0) this.#ariaRegistry.delete(action);
404
+ else this.#ariaRegistry.set(action, filtered);
77
405
  }
78
406
  };
79
407
 
80
408
  //#endregion
81
- //#region ../core/dist/dev/core/ui/alert-dialog/alert-dialog-data-attrs.js
82
- const AlertDialogDataAttrs = {
83
- open: "data-open",
84
- transitionStarting: "data-starting-style",
85
- transitionEnding: "data-ending-style"
86
- };
409
+ //#region ../core/dist/dev/dom/hotkey/hotkey.js
410
+ const MODIFIER_KEYS = new Set([
411
+ "shift",
412
+ "ctrl",
413
+ "alt",
414
+ "meta"
415
+ ]);
416
+ /**
417
+ * Parse a key pattern string into one or more bindings.
418
+ *
419
+ * @example
420
+ * ```ts
421
+ * parseHotkeyPattern('>');
422
+ * // [{ modifiers: Set(), key: '>', originalKey: '>' }]
423
+ *
424
+ * parseHotkeyPattern('0-9');
425
+ * // 10 bindings, one per digit
426
+ * ```
427
+ */
428
+ function parseHotkeyPattern(pattern) {
429
+ if (pattern === "0-9") return Array.from({ length: 10 }, (_, i) => ({
430
+ modifiers: /* @__PURE__ */ new Set(),
431
+ key: String(i),
432
+ originalKey: String(i)
433
+ }));
434
+ const segments = pattern.split("+");
435
+ const rawKey = segments.pop();
436
+ const modifiers = /* @__PURE__ */ new Set();
437
+ for (const seg of segments) {
438
+ const lower = seg.toLowerCase();
439
+ if (lower === "mod") modifiers.add(isMacOS() ? "meta" : "ctrl");
440
+ else if (MODIFIER_KEYS.has(lower)) modifiers.add(lower);
441
+ else console.warn(`[vjs-hotkey] Unknown modifier: "${seg}" in pattern "${pattern}"`);
442
+ }
443
+ return [{
444
+ modifiers,
445
+ key: rawKey === "Space" ? " " : rawKey.toLowerCase(),
446
+ originalKey: rawKey
447
+ }];
448
+ }
449
+ /**
450
+ * Single non-letter character — layout-dependent modifiers (Shift, Alt/Option)
451
+ * were used to produce the character itself, not as deliberate modifiers
452
+ * (e.g. Shift+. → ">", Option+Shift → ">" on some Mac layouts).
453
+ * Letters excluded because Shift changes case intentionally (k vs K).
454
+ * Named keys excluded because event.key.length > 1 (ArrowLeft, Tab, etc.).
455
+ */
456
+ function isImplicitModifierKey(key) {
457
+ return key.length === 1 && !/[a-z]/i.test(key);
458
+ }
459
+ /** Whether a parsed binding matches a keyboard event. */
460
+ function matchesHotkeyEvent(binding, event) {
461
+ if (event.key === "Unidentified") return false;
462
+ if (event.key.toLowerCase() !== binding.key) return false;
463
+ const implicit = isImplicitModifierKey(event.key);
464
+ const shiftKey = implicit ? event.shiftKey && binding.modifiers.has("shift") : event.shiftKey;
465
+ const altKey = implicit ? event.altKey && binding.modifiers.has("alt") : event.altKey;
466
+ if (shiftKey !== binding.modifiers.has("shift")) return false;
467
+ if (event.ctrlKey !== binding.modifiers.has("ctrl")) return false;
468
+ if (altKey !== binding.modifiers.has("alt")) return false;
469
+ if (event.metaKey !== binding.modifiers.has("meta")) return false;
470
+ return true;
471
+ }
472
+ const coordinators = /* @__PURE__ */ new WeakMap();
473
+ /** Look up the coordinator for a target element, if one exists. */
474
+ function findHotkeyCoordinator(target) {
475
+ return coordinators.get(target);
476
+ }
477
+ function getCoordinator(target) {
478
+ let coordinator = coordinators.get(target);
479
+ if (!coordinator) {
480
+ coordinator = new HotkeyCoordinator(target);
481
+ coordinators.set(target, coordinator);
482
+ }
483
+ return coordinator;
484
+ }
485
+ /**
486
+ * Register a hotkey binding on a target element.
487
+ *
488
+ * @example
489
+ * ```ts
490
+ * const cleanup = createHotkey(container, {
491
+ * keys: 'k',
492
+ * onActivate: () => store.paused ? store.play() : store.pause(),
493
+ * });
494
+ *
495
+ * // Later: remove the binding
496
+ * cleanup();
497
+ * ```
498
+ *
499
+ * @returns A cleanup function that removes the binding.
500
+ */
501
+ function createHotkey(target, options) {
502
+ return getCoordinator(target).add(options);
503
+ }
87
504
 
88
505
  //#endregion
89
- //#region ../core/dist/dev/core/ui/buffering-indicator/buffering-indicator-core.js
90
- var BufferingIndicatorCore = class BufferingIndicatorCore {
91
- static defaultProps = { delay: 500 };
92
- state = createState({ visible: false });
93
- #props = { ...BufferingIndicatorCore.defaultProps };
94
- #timer = null;
95
- setProps(props) {
96
- this.#props = defaults(props, BufferingIndicatorCore.defaultProps);
506
+ //#region ../core/dist/dev/dom/ui/dismiss-layer.js
507
+ function createDismissLayer(options) {
508
+ const { transition } = options;
509
+ const state = transition.state;
510
+ const abort = new AbortController();
511
+ let docAbort = null;
512
+ function open() {
513
+ if (abort.signal.aborted) return null;
514
+ const { active, status } = state.current;
515
+ if (active && status !== "ending") return null;
516
+ if (status === "ending") transition.cancel();
517
+ return transition.open();
518
+ }
519
+ function close(element) {
520
+ const { active, status } = state.current;
521
+ if (abort.signal.aborted || !active || status === "ending") return null;
522
+ return transition.close(element);
523
+ }
524
+ function setupDocumentListeners() {
525
+ cleanupDocumentListeners();
526
+ if (typeof document === "undefined") return;
527
+ docAbort = new AbortController();
528
+ const { signal } = docAbort;
529
+ listen(document, "keydown", handleKeydown, { signal });
530
+ options.onDocumentActive?.(signal);
531
+ }
532
+ function cleanupDocumentListeners() {
533
+ docAbort?.abort();
534
+ docAbort = null;
535
+ }
536
+ function handleKeydown(event) {
537
+ if (event.key !== "Escape") return;
538
+ if (!state.current.active) return;
539
+ if (!(options.closeOnEscape?.() ?? true)) return;
540
+ options.onEscapeDismiss(event);
541
+ }
542
+ const unsubscribe = state.subscribe(() => {
543
+ if (state.current.active) setupDocumentListeners();
544
+ else cleanupDocumentListeners();
545
+ });
546
+ abort.signal.addEventListener("abort", () => {
547
+ unsubscribe();
548
+ transition.destroy();
549
+ cleanupDocumentListeners();
550
+ });
551
+ function destroy() {
552
+ if (abort.signal.aborted) return;
553
+ abort.abort();
97
554
  }
98
- destroy() {
99
- this.#clearTimer();
100
- }
101
- update(media) {
102
- const buffering = media.waiting && !media.paused;
103
- if (buffering && !this.state.current.visible && !this.#timer) this.#timer = setTimeout(() => {
104
- this.#timer = null;
105
- this.state.patch({ visible: true });
106
- }, this.#props.delay);
107
- else if (!buffering) {
108
- this.#clearTimer();
109
- this.state.patch({ visible: false });
555
+ return {
556
+ input: state,
557
+ open,
558
+ close,
559
+ signal: abort.signal,
560
+ destroy
561
+ };
562
+ }
563
+
564
+ //#endregion
565
+ //#region ../core/dist/dev/dom/ui/alert-dialog.js
566
+ function createAlertDialog(options) {
567
+ const { onOpenChange } = options;
568
+ let element = null;
569
+ let previousFocus = null;
570
+ let elementAbort = null;
571
+ const layer = createDismissLayer({
572
+ transition: options.transition,
573
+ closeOnEscape: options.closeOnEscape,
574
+ onEscapeDismiss(event) {
575
+ event.stopPropagation();
576
+ applyClose();
110
577
  }
578
+ });
579
+ const state = layer.input;
580
+ function applyOpen() {
581
+ previousFocus = document.activeElement;
582
+ const opening = layer.open();
583
+ if (!opening) return;
584
+ onOpenChange(true);
585
+ requestAnimationFrame(() => {
586
+ if (layer.signal.aborted || !state.current.active) return;
587
+ element?.focus();
588
+ });
589
+ opening.then(() => {
590
+ if (layer.signal.aborted || !state.current.active) return;
591
+ options.onOpenChangeComplete?.(true);
592
+ });
593
+ }
594
+ function applyClose() {
595
+ const closing = layer.close(element);
596
+ if (!closing) return;
597
+ onOpenChange(false);
598
+ closing.then(() => {
599
+ if (layer.signal.aborted) return;
600
+ if (previousFocus) {
601
+ previousFocus.focus();
602
+ previousFocus = null;
603
+ }
604
+ options.onOpenChangeComplete?.(false);
605
+ });
111
606
  }
112
- #clearTimer() {
113
- if (this.#timer !== null) {
114
- clearTimeout(this.#timer);
115
- this.#timer = null;
607
+ function setupElementListeners() {
608
+ cleanupElementListeners();
609
+ if (!element) return;
610
+ elementAbort = new AbortController();
611
+ const { signal } = elementAbort;
612
+ listen(element, "click", handleElementClick, { signal });
613
+ }
614
+ function cleanupElementListeners() {
615
+ elementAbort?.abort();
616
+ elementAbort = null;
617
+ }
618
+ function handleElementClick(event) {
619
+ if (event.target instanceof HTMLButtonElement) applyClose();
620
+ }
621
+ function setElement(el) {
622
+ element = el;
623
+ setupElementListeners();
624
+ }
625
+ layer.signal.addEventListener("abort", () => {
626
+ cleanupElementListeners();
627
+ element = null;
628
+ previousFocus = null;
629
+ });
630
+ return {
631
+ input: state,
632
+ open: applyOpen,
633
+ close: applyClose,
634
+ setElement,
635
+ destroy: layer.destroy
636
+ };
637
+ }
638
+
639
+ //#endregion
640
+ //#region ../core/dist/dev/dom/ui/button.js
641
+ function createButton(options) {
642
+ const { onActivate, isDisabled } = options;
643
+ return {
644
+ role: "button",
645
+ tabIndex: 0,
646
+ onClick(event) {
647
+ if (isDisabled()) {
648
+ event.preventDefault();
649
+ return;
650
+ }
651
+ onActivate();
652
+ },
653
+ onPointerDown(event) {
654
+ if (isDisabled()) event.preventDefault();
655
+ },
656
+ onMouseDown(event) {
657
+ if (isDisabled()) event.preventDefault();
658
+ },
659
+ onKeyDown(event) {
660
+ if (event.target !== event.currentTarget) return;
661
+ if (isDisabled()) {
662
+ if (event.key !== "Tab") event.preventDefault();
663
+ return;
664
+ }
665
+ if (event.key === "Enter") {
666
+ event.preventDefault();
667
+ onActivate();
668
+ } else if (event.key === " ") event.preventDefault();
669
+ },
670
+ onKeyUp(event) {
671
+ if (event.target !== event.currentTarget) return;
672
+ if (isDisabled()) return;
673
+ if (event.key === " ") onActivate();
674
+ }
675
+ };
676
+ }
677
+
678
+ //#endregion
679
+ //#region ../core/dist/dev/dom/ui/popover/popover.js
680
+ function createPopover(options) {
681
+ const { onOpenChange, closeOnOutsideClick } = options;
682
+ let triggerEl = null;
683
+ let popupEl = null;
684
+ let hoverTimeout = null;
685
+ const capturedPointers = /* @__PURE__ */ new Set();
686
+ const layer = createDismissLayer({
687
+ transition: options.transition,
688
+ closeOnEscape: options.closeOnEscape,
689
+ onEscapeDismiss(event) {
690
+ event.preventDefault();
691
+ applyClose("escape", event);
692
+ },
693
+ onDocumentActive(signal) {
694
+ listen(document, "pointerdown", handleDocumentPointerdown, {
695
+ capture: true,
696
+ signal
697
+ });
698
+ }
699
+ });
700
+ const state = layer.input;
701
+ function clearHoverTimeout() {
702
+ if (hoverTimeout !== null) {
703
+ clearTimeout(hoverTimeout);
704
+ hoverTimeout = null;
116
705
  }
117
706
  }
118
- };
707
+ function canHover() {
708
+ return globalThis.matchMedia?.("(hover: hover)")?.matches ?? false;
709
+ }
710
+ function canOpenOnFocus() {
711
+ if (!canHover()) return false;
712
+ return globalThis.matchMedia?.("(pointer: fine)")?.matches ?? false;
713
+ }
714
+ function canToggleOnClick() {
715
+ if (!options.openOnHover?.()) return true;
716
+ return canHover();
717
+ }
718
+ /**
719
+ * The transition handler manages animation lifecycle via `createState`:
720
+ *
721
+ * **Open:** `transition.open()` patches `{ active: true, status: 'starting' }`.
722
+ * After one RAF it patches `{ status: 'idle' }` and the promise resolves.
723
+ * Frameworks render `data-starting-style` / `data-ending-style` via
724
+ * `getPopupAttrs(state)` — no imperative DOM mutation needed.
725
+ *
726
+ * **Close:** `transition.close(el)` patches `{ status: 'ending' }` (keeping
727
+ * `active: true` so the element stays mounted). After a double-RAF it waits
728
+ * for `getAnimations()` to settle, then patches `{ active: false, status: 'idle' }`.
729
+ *
730
+ * `onOpenChange` fires immediately (before animations).
731
+ * `onOpenChangeComplete` fires after animations finish.
732
+ */
733
+ function applyOpen(reason, event) {
734
+ const opening = layer.open();
735
+ if (!opening) return;
736
+ onOpenChange(true, event ? {
737
+ reason,
738
+ event
739
+ } : { reason });
740
+ opening.then(() => {
741
+ if (layer.signal.aborted || !state.current.active) return;
742
+ options.onOpenChangeComplete?.(true);
743
+ });
744
+ }
745
+ function applyClose(reason, event) {
746
+ const closing = layer.close(popupEl);
747
+ if (!closing) return;
748
+ onOpenChange(false, event ? {
749
+ reason,
750
+ event
751
+ } : { reason });
752
+ closing.then(() => {
753
+ if (layer.signal.aborted) return;
754
+ tryHidePopover(popupEl);
755
+ options.onOpenChangeComplete?.(false);
756
+ });
757
+ }
758
+ function open(reason = "click") {
759
+ applyOpen(reason);
760
+ }
761
+ function close(reason = "click") {
762
+ applyClose(reason);
763
+ }
764
+ function handleDocumentPointerdown(event) {
765
+ if (!closeOnOutsideClick() || !state.current.active) return;
766
+ const path = event.composedPath();
767
+ if (triggerEl && path.includes(triggerEl) || popupEl && path.includes(popupEl)) return;
768
+ applyClose("outside-click", event);
769
+ }
770
+ layer.signal.addEventListener("abort", () => {
771
+ clearHoverTimeout();
772
+ capturedPointers.clear();
773
+ triggerEl = null;
774
+ popupEl = null;
775
+ });
776
+ const triggerProps = {
777
+ onClick(event) {
778
+ if (!canToggleOnClick()) return;
779
+ if (state.current.active && state.current.status !== "ending") applyClose("click", event);
780
+ else applyOpen("click", event);
781
+ },
782
+ onPointerEnter(_event) {
783
+ if (!options.openOnHover?.()) return;
784
+ if (!canHover()) return;
785
+ clearHoverTimeout();
786
+ if (state.current.active) return;
787
+ const delay = options.delay?.() ?? 300;
788
+ hoverTimeout = setTimeout(() => applyOpen("hover"), delay);
789
+ },
790
+ onPointerLeave(_event) {
791
+ if (!options.openOnHover?.()) return;
792
+ if (!canHover()) return;
793
+ clearHoverTimeout();
794
+ if (!state.current.active) return;
795
+ const closeDelay = options.closeDelay?.() ?? 0;
796
+ hoverTimeout = setTimeout(() => applyClose("hover"), closeDelay);
797
+ },
798
+ onFocusIn(_event) {
799
+ if (options.openOnHover?.()) {
800
+ if (!canOpenOnFocus()) return;
801
+ applyOpen("focus");
802
+ }
803
+ },
804
+ onFocusOut(event) {
805
+ const relatedTarget = event.relatedTarget;
806
+ if (relatedTarget && (triggerEl?.contains(relatedTarget) || popupEl?.contains(relatedTarget))) return;
807
+ if (options.openOnHover?.()) applyClose("blur");
808
+ }
809
+ };
810
+ const popupProps = {
811
+ onPointerEnter(_event) {
812
+ if (!options.openOnHover?.()) return;
813
+ clearHoverTimeout();
814
+ },
815
+ onPointerLeave(_event) {
816
+ if (!options.openOnHover?.()) return;
817
+ if (capturedPointers.size > 0) return;
818
+ clearHoverTimeout();
819
+ if (!state.current.active) return;
820
+ const closeDelay = options.closeDelay?.() ?? 0;
821
+ hoverTimeout = setTimeout(() => applyClose("hover"), closeDelay);
822
+ },
823
+ onGotPointerCapture(event) {
824
+ capturedPointers.add(event.pointerId);
825
+ },
826
+ onLostPointerCapture(event) {
827
+ capturedPointers.delete(event.pointerId);
828
+ },
829
+ onFocusOut(event) {
830
+ const relatedTarget = event.relatedTarget;
831
+ if (relatedTarget && (triggerEl?.contains(relatedTarget) || popupEl?.contains(relatedTarget))) return;
832
+ applyClose("blur");
833
+ }
834
+ };
835
+ function setTriggerElement(el) {
836
+ triggerEl = el;
837
+ }
838
+ function setPopupElement(el) {
839
+ if (!el && popupEl && state.current.active) tryHidePopover(popupEl);
840
+ popupEl = el;
841
+ if (el) {
842
+ if (state.current.active) tryShowPopover(el);
843
+ }
844
+ }
845
+ return {
846
+ input: state,
847
+ triggerProps,
848
+ popupProps,
849
+ get triggerElement() {
850
+ return triggerEl;
851
+ },
852
+ setTriggerElement,
853
+ setPopupElement,
854
+ open,
855
+ close,
856
+ destroy: layer.destroy
857
+ };
858
+ }
119
859
 
120
860
  //#endregion
121
- //#region ../core/dist/dev/core/ui/buffering-indicator/buffering-indicator-data-attrs.js
122
- const BufferingIndicatorDataAttrs = { visible: "data-visible" };
861
+ //#region ../core/dist/dev/core/ui/popover/popover-css-vars.js
862
+ const PopoverCSSVars = {
863
+ sideOffset: "--media-popover-side-offset",
864
+ alignOffset: "--media-popover-align-offset",
865
+ anchorWidth: "--media-popover-anchor-width",
866
+ anchorHeight: "--media-popover-anchor-height",
867
+ availableWidth: "--media-popover-available-width",
868
+ availableHeight: "--media-popover-available-height"
869
+ };
123
870
 
124
871
  //#endregion
125
- //#region ../core/dist/dev/core/ui/captions-button/captions-button-core.js
126
- var CaptionsButtonCore = class CaptionsButtonCore {
127
- static defaultProps = {
128
- label: "",
129
- disabled: false
872
+ //#region ../core/dist/dev/dom/ui/popover/popover-positioning.js
873
+ const OPPOSITE_SIDE = {
874
+ top: "bottom",
875
+ bottom: "top",
876
+ left: "right",
877
+ right: "left"
878
+ };
879
+ /**
880
+ * Get positioning styles for the popup element.
881
+ *
882
+ * When the browser supports CSS Anchor Positioning, returns native CSS properties
883
+ * that reference the provided CSS var names for side/align offsets — no JS offset
884
+ * values needed.
885
+ *
886
+ * When rects are provided and anchor positioning is unsupported, falls back to
887
+ * manual JS-computed positioning. The caller must resolve offset CSS vars via
888
+ * `getComputedStyle` and pass them as `offsets`.
889
+ *
890
+ * Returns camelCase keys for standard CSS properties and `--*` keys for
891
+ * custom properties — compatible with both React's `style` prop and
892
+ * `applyStyles()` from `@videojs/utils/dom`.
893
+ */
894
+ function getAnchorPositionStyle(anchorName, opts, triggerRect, popupRect, boundaryRect, offsets, cssVars = PopoverCSSVars) {
895
+ if (supportsAnchorPositioning()) return getAnchorPositionCSS(anchorName, opts, cssVars);
896
+ if (triggerRect && popupRect) return {
897
+ ...getManualPositionStyle(triggerRect, popupRect, opts, offsets ?? {
898
+ sideOffset: 0,
899
+ alignOffset: 0
900
+ }),
901
+ ...boundaryRect ? getPositioningCSSVars(triggerRect, boundaryRect, opts.side, cssVars) : {},
902
+ position: "fixed",
903
+ inset: "auto",
904
+ margin: "0"
130
905
  };
131
- state = createState({
132
- subtitlesShowing: false,
133
- availability: "unavailable",
134
- label: ""
906
+ return {};
907
+ }
908
+ /** Generate style to set on the trigger for CSS Anchor Positioning. */
909
+ function getAnchorNameStyle(anchorName) {
910
+ if (!supportsAnchorPositioning()) return {};
911
+ return { anchorName: `--${anchorName}` };
912
+ }
913
+ function getAnchorPositionCSS(anchorName, opts, cssVars = PopoverCSSVars) {
914
+ const SIDE_OFFSET_VAR = `var(${cssVars.sideOffset}, 0px)`;
915
+ const ALIGN_OFFSET_VAR = `var(${cssVars.alignOffset}, 0px)`;
916
+ const { side, align } = opts;
917
+ const style = {
918
+ positionAnchor: `--${anchorName}`,
919
+ position: "fixed",
920
+ inset: "auto",
921
+ margin: "0",
922
+ justifySelf: "normal",
923
+ alignSelf: "normal",
924
+ marginInlineStart: "0",
925
+ marginBlockStart: "0"
926
+ };
927
+ const insetProp = OPPOSITE_SIDE[side];
928
+ if (side === "top" || side === "bottom") {
929
+ style[insetProp] = `calc(anchor(${side}) + ${SIDE_OFFSET_VAR})`;
930
+ if (align === "start") style.left = `calc(anchor(left) + ${ALIGN_OFFSET_VAR})`;
931
+ else if (align === "end") style.right = `calc(anchor(right) + ${ALIGN_OFFSET_VAR})`;
932
+ else {
933
+ style.justifySelf = "anchor-center";
934
+ style.marginInlineStart = ALIGN_OFFSET_VAR;
935
+ }
936
+ } else {
937
+ style[insetProp] = `calc(anchor(${side}) + ${SIDE_OFFSET_VAR})`;
938
+ if (align === "start") style.top = `calc(anchor(top) + ${ALIGN_OFFSET_VAR})`;
939
+ else if (align === "end") style.bottom = `calc(anchor(bottom) + ${ALIGN_OFFSET_VAR})`;
940
+ else {
941
+ style.alignSelf = "anchor-center";
942
+ style.marginBlockStart = ALIGN_OFFSET_VAR;
943
+ }
944
+ }
945
+ return style;
946
+ }
947
+ /**
948
+ * Compute CSS variables for sizing constraints relative to the anchor/boundary.
949
+ *
950
+ * Accepts a `cssVars` map so the same logic works for both popover
951
+ * (`--media-popover-*`) and tooltip (`--media-tooltip-*`) namespaces.
952
+ */
953
+ function getPositioningCSSVars(triggerRect, boundaryRect, side, cssVars = PopoverCSSVars) {
954
+ const vars = {};
955
+ vars[cssVars.anchorWidth] = `${triggerRect.width}px`;
956
+ vars[cssVars.anchorHeight] = `${triggerRect.height}px`;
957
+ if (side === "top" || side === "bottom") {
958
+ vars[cssVars.availableHeight] = side === "top" ? `${triggerRect.top - boundaryRect.top}px` : `${boundaryRect.bottom - triggerRect.bottom}px`;
959
+ vars[cssVars.availableWidth] = `${boundaryRect.width}px`;
960
+ } else {
961
+ vars[cssVars.availableWidth] = side === "left" ? `${triggerRect.left - boundaryRect.left}px` : `${boundaryRect.right - triggerRect.right}px`;
962
+ vars[cssVars.availableHeight] = `${boundaryRect.height}px`;
963
+ }
964
+ return vars;
965
+ }
966
+ /**
967
+ * Compute manual positioning when CSS Anchor Positioning is not supported.
968
+ *
969
+ * Returns inline `top`/`left` styles in **viewport coordinates** for use
970
+ * with `position: fixed` (the popup is in the top layer). All rects from
971
+ * `getBoundingClientRect()` are already viewport-relative.
972
+ *
973
+ * Offsets are resolved by the caller from CSS custom properties via
974
+ * `getComputedStyle()` and passed as `offsets`.
975
+ */
976
+ function getManualPositionStyle(triggerRect, popupRect, opts, offsets = {
977
+ sideOffset: 0,
978
+ alignOffset: 0
979
+ }) {
980
+ const { side, align } = opts;
981
+ const { sideOffset, alignOffset } = offsets;
982
+ let top = 0;
983
+ let left = 0;
984
+ if (side === "top") top = triggerRect.top - popupRect.height - sideOffset;
985
+ else if (side === "bottom") top = triggerRect.bottom + sideOffset;
986
+ else if (side === "left") left = triggerRect.left - popupRect.width - sideOffset;
987
+ else left = triggerRect.right + sideOffset;
988
+ if (side === "top" || side === "bottom") if (align === "start") left = triggerRect.left + alignOffset;
989
+ else if (align === "end") left = triggerRect.right - popupRect.width + alignOffset;
990
+ else left = triggerRect.left + (triggerRect.width - popupRect.width) / 2 + alignOffset;
991
+ else if (align === "start") top = triggerRect.top + alignOffset;
992
+ else if (align === "end") top = triggerRect.bottom - popupRect.height + alignOffset;
993
+ else top = triggerRect.top + (triggerRect.height - popupRect.height) / 2 + alignOffset;
994
+ return {
995
+ top: `${top}px`,
996
+ left: `${left}px`
997
+ };
998
+ }
999
+ /**
1000
+ * Read side-offset and align-offset CSS custom properties from the
1001
+ * popup element's computed style, returning numeric pixel values.
1002
+ */
1003
+ function resolveOffsets(el, cssVars = PopoverCSSVars) {
1004
+ const computed = getComputedStyle(el);
1005
+ return {
1006
+ sideOffset: resolveCSSLength(el, computed.getPropertyValue(cssVars.sideOffset)),
1007
+ alignOffset: resolveCSSLength(el, computed.getPropertyValue(cssVars.alignOffset))
1008
+ };
1009
+ }
1010
+ /**
1011
+ * Measure the popup's layout box for positioning.
1012
+ *
1013
+ * `getBoundingClientRect()` includes active transforms, which causes the
1014
+ * fallback position to drift while opening/closing animations scale the popup.
1015
+ * Using `offsetWidth`/`offsetHeight` preserves the untransformed size.
1016
+ */
1017
+ function getPopupPositionRect(el) {
1018
+ const rect = el.getBoundingClientRect();
1019
+ const width = el.offsetWidth || rect.width;
1020
+ const height = el.offsetHeight || rect.height;
1021
+ const adjustedRect = {
1022
+ ...rect,
1023
+ width,
1024
+ height,
1025
+ right: rect.left + width,
1026
+ bottom: rect.top + height
1027
+ };
1028
+ return {
1029
+ ...adjustedRect,
1030
+ toJSON: () => adjustedRect
1031
+ };
1032
+ }
1033
+
1034
+ //#endregion
1035
+ //#region ../utils/dist/number/number.js
1036
+ /** Clamp a value between min and max (inclusive). */
1037
+ function clamp(value, min, max) {
1038
+ return Math.max(min, Math.min(max, value));
1039
+ }
1040
+ /** Snap a value to the nearest step, offset from min. */
1041
+ function roundToStep(value, step, min) {
1042
+ const nearest = Math.round((value - min) / step) * step + min;
1043
+ const dot = `${step}`.indexOf(".");
1044
+ return dot === -1 ? nearest : Number(nearest.toFixed(`${step}`.length - dot - 1));
1045
+ }
1046
+
1047
+ //#endregion
1048
+ //#region ../core/dist/dev/dom/utils/pointer.js
1049
+ /** Convert a pointer event position to a 0–100 percent along an element's rect. */
1050
+ function getPercentFromPointerEvent(event, rect, orientation, isRTL) {
1051
+ let ratio;
1052
+ if (orientation === "vertical") ratio = 1 - (event.clientY - rect.top) / rect.height;
1053
+ else if (isRTL) ratio = (rect.right - event.clientX) / rect.width;
1054
+ else ratio = (event.clientX - rect.left) / rect.width;
1055
+ if (!Number.isFinite(ratio)) return 0;
1056
+ return clamp(ratio * 100, 0, 100);
1057
+ }
1058
+
1059
+ //#endregion
1060
+ //#region ../core/dist/dev/dom/ui/slider.js
1061
+ function createSlider(options) {
1062
+ const input = createState({
1063
+ pointerPercent: 0,
1064
+ dragPercent: 0,
1065
+ dragging: false,
1066
+ pointing: false,
1067
+ focused: false
135
1068
  });
136
- #props = { ...CaptionsButtonCore.defaultProps };
137
- #media = null;
138
- constructor(props) {
139
- if (props) this.setProps(props);
1069
+ const abort = new AbortController();
1070
+ const changeThrottleMs = options.changeThrottle ?? 0;
1071
+ let isDragging = false, cachedRTL = false, cachedRect = null, capturedPointerId = null, lastDragPercent = 0, committedOnRelease = false;
1072
+ const throttledChange = changeThrottleMs > 0 ? throttle((percent) => options.onValueChange?.(percent), changeThrottleMs, { leading: true }) : null;
1073
+ /** Fire `onValueChange` — throttled during drag when `changeThrottle > 0`. */
1074
+ function fireChange(percent, duringDrag) {
1075
+ if (duringDrag && throttledChange) throttledChange(percent);
1076
+ else options.onValueChange?.(percent);
1077
+ }
1078
+ function releaseCapture() {
1079
+ if (isNull(capturedPointerId)) return;
1080
+ const id = capturedPointerId;
1081
+ capturedPointerId = null;
1082
+ try {
1083
+ options.getElement().releasePointerCapture(id);
1084
+ } catch {}
140
1085
  }
141
- setProps(props) {
142
- this.#props = defaults(props, CaptionsButtonCore.defaultProps);
1086
+ function endDrag() {
1087
+ if (!isDragging) input.patch({ pointing: false });
1088
+ else {
1089
+ if (!committedOnRelease) options.onValueCommit?.(lastDragPercent);
1090
+ isDragging = false;
1091
+ input.patch({
1092
+ dragging: false,
1093
+ pointing: false
1094
+ });
1095
+ options.onDragEnd?.();
1096
+ }
1097
+ committedOnRelease = false;
1098
+ cleanup();
1099
+ }
1100
+ function cleanup() {
1101
+ throttledChange?.cancel();
1102
+ capturedPointerId = null;
1103
+ cachedRect = null;
1104
+ }
1105
+ const rootProps = {
1106
+ onPointerDown(event) {
1107
+ if (options.isDisabled()) return;
1108
+ event.preventDefault();
1109
+ const el = options.getElement();
1110
+ cachedRect = el.getBoundingClientRect();
1111
+ cachedRTL = options.isRTL();
1112
+ committedOnRelease = false;
1113
+ releaseCapture();
1114
+ capturedPointerId = event.pointerId;
1115
+ el.setPointerCapture(event.pointerId);
1116
+ const percent = getPercentFromPointerEvent(event, cachedRect, options.getOrientation(), cachedRTL);
1117
+ isDragging = true;
1118
+ lastDragPercent = percent;
1119
+ input.patch({
1120
+ pointing: true,
1121
+ dragging: true,
1122
+ pointerPercent: percent,
1123
+ dragPercent: percent
1124
+ });
1125
+ options.onDragStart?.();
1126
+ options.onValueChange?.(percent);
1127
+ options.getThumbElement?.()?.focus({
1128
+ preventScroll: true,
1129
+ focusVisible: false
1130
+ });
1131
+ },
1132
+ onPointerMove(event) {
1133
+ if (options.isDisabled()) return;
1134
+ if (!isNull(capturedPointerId)) {
1135
+ if (event.pointerType !== "touch" && event.buttons === 0) {
1136
+ endDrag();
1137
+ return;
1138
+ }
1139
+ const percent = getPercentFromPointerEvent(event, cachedRect, options.getOrientation(), cachedRTL);
1140
+ lastDragPercent = percent;
1141
+ input.patch({
1142
+ dragPercent: percent,
1143
+ pointerPercent: percent
1144
+ });
1145
+ fireChange(percent, true);
1146
+ return;
1147
+ }
1148
+ const percent = getPercentFromPointerEvent(event, options.getElement().getBoundingClientRect(), options.getOrientation(), options.isRTL());
1149
+ input.patch({
1150
+ pointing: true,
1151
+ pointerPercent: percent
1152
+ });
1153
+ },
1154
+ onPointerUp(event) {
1155
+ if (isNull(capturedPointerId)) return;
1156
+ const percent = getPercentFromPointerEvent(event, cachedRect, options.getOrientation(), cachedRTL);
1157
+ throttledChange?.cancel();
1158
+ options.onValueChange?.(percent);
1159
+ options.onValueCommit?.(percent);
1160
+ committedOnRelease = true;
1161
+ },
1162
+ onPointerLeave() {
1163
+ if (!isNull(capturedPointerId)) return;
1164
+ input.patch({ pointing: false });
1165
+ },
1166
+ onLostPointerCapture() {
1167
+ endDrag();
1168
+ }
1169
+ };
1170
+ const thumbProps = {
1171
+ onKeyDown(event) {
1172
+ if (options.isDisabled()) {
1173
+ if (event.key !== "Tab") event.preventDefault();
1174
+ return;
1175
+ }
1176
+ const stepPercent = options.getStepPercent();
1177
+ const largeStepPercent = options.getLargeStepPercent();
1178
+ const rounded = roundToStep(options.getPercent(), stepPercent, 0);
1179
+ const horizontalSign = options.isRTL() ? -1 : 1;
1180
+ const step = event.shiftKey ? largeStepPercent : stepPercent;
1181
+ let newPercent = null;
1182
+ switch (event.key) {
1183
+ case "ArrowRight":
1184
+ newPercent = rounded + step * horizontalSign;
1185
+ break;
1186
+ case "ArrowLeft":
1187
+ newPercent = rounded - step * horizontalSign;
1188
+ break;
1189
+ case "ArrowUp":
1190
+ newPercent = rounded + step;
1191
+ break;
1192
+ case "ArrowDown":
1193
+ newPercent = rounded - step;
1194
+ break;
1195
+ case "PageUp":
1196
+ newPercent = rounded + largeStepPercent;
1197
+ break;
1198
+ case "PageDown":
1199
+ newPercent = rounded - largeStepPercent;
1200
+ break;
1201
+ case "Home":
1202
+ newPercent = 0;
1203
+ break;
1204
+ case "End":
1205
+ newPercent = 100;
1206
+ break;
1207
+ default:
1208
+ if (!event.metaKey && !event.ctrlKey && !event.altKey && event.key >= "0" && event.key <= "9") newPercent = Number(event.key) * 10;
1209
+ break;
1210
+ }
1211
+ if (newPercent !== null) {
1212
+ event.preventDefault();
1213
+ newPercent = clamp(newPercent, 0, 100);
1214
+ input.patch({
1215
+ pointerPercent: newPercent,
1216
+ dragPercent: newPercent
1217
+ });
1218
+ options.onValueChange?.(newPercent);
1219
+ options.onValueCommit?.(newPercent);
1220
+ }
1221
+ },
1222
+ onFocus() {
1223
+ input.patch({ focused: true });
1224
+ },
1225
+ onBlur() {
1226
+ input.patch({ focused: false });
1227
+ }
1228
+ };
1229
+ function adjustForAlignment(state) {
1230
+ if (!options.adjustPercent || state.thumbAlignment !== "edge") return state;
1231
+ const rootEl = options.getElement();
1232
+ const thumbEl = options.getThumbElement?.();
1233
+ if (!thumbEl) return state;
1234
+ const isHorizontal = state.orientation === "horizontal";
1235
+ const thumbSize = isHorizontal ? thumbEl.offsetWidth : thumbEl.offsetHeight;
1236
+ const trackSize = isHorizontal ? rootEl.offsetWidth : rootEl.offsetHeight;
1237
+ return {
1238
+ ...state,
1239
+ fillPercent: options.adjustPercent(state.fillPercent, thumbSize, trackSize),
1240
+ pointerPercent: options.adjustPercent(state.pointerPercent, thumbSize, trackSize)
1241
+ };
143
1242
  }
144
- getLabel(state) {
145
- const { label } = this.#props;
146
- if (isFunction(label)) {
147
- const customLabel = label(state);
148
- if (customLabel) return customLabel;
149
- } else if (label) return label;
150
- return state.subtitlesShowing ? "Disable captions" : "Enable captions";
1243
+ let resizeObserver = null;
1244
+ if (options.onResize) {
1245
+ resizeObserver = new ResizeObserver(() => options.onResize());
1246
+ resizeObserver.observe(options.getElement());
151
1247
  }
152
- getAttrs(state) {
1248
+ return {
1249
+ input,
1250
+ rootProps,
1251
+ rootStyle: {
1252
+ touchAction: "none",
1253
+ userSelect: "none"
1254
+ },
1255
+ thumbProps,
1256
+ adjustForAlignment,
1257
+ destroy() {
1258
+ if (abort.signal.aborted) return;
1259
+ abort.abort();
1260
+ resizeObserver?.disconnect();
1261
+ releaseCapture();
1262
+ cleanup();
1263
+ }
1264
+ };
1265
+ }
1266
+
1267
+ //#endregion
1268
+ //#region ../core/dist/dev/core/ui/slider/slider-css-vars.js
1269
+ /** CSS custom property names for slider visual state. */
1270
+ const SliderCSSVars = {
1271
+ fill: "--media-slider-fill",
1272
+ pointer: "--media-slider-pointer",
1273
+ buffer: "--media-slider-buffer"
1274
+ };
1275
+
1276
+ //#endregion
1277
+ //#region ../core/dist/dev/dom/ui/slider-css-vars.js
1278
+ function getSliderCSSVars(state) {
1279
+ return {
1280
+ [SliderCSSVars.fill]: `${state.fillPercent.toFixed(3)}%`,
1281
+ [SliderCSSVars.pointer]: `${state.pointerPercent.toFixed(3)}%`
1282
+ };
1283
+ }
1284
+ function getTimeSliderCSSVars(state) {
1285
+ return {
1286
+ ...getSliderCSSVars(state),
1287
+ [SliderCSSVars.buffer]: `${state.bufferPercent.toFixed(3)}%`
1288
+ };
1289
+ }
1290
+ /** Compute structural positioning styles for a slider preview element. */
1291
+ function getSliderPreviewStyle(width, overflow) {
1292
+ const halfWidth = width / 2;
1293
+ return {
1294
+ position: "absolute",
1295
+ left: overflow === "visible" ? `calc(var(${SliderCSSVars.pointer}) - ${halfWidth}px)` : `min(max(0px, calc(var(${SliderCSSVars.pointer}) - ${halfWidth}px)), calc(100% - ${width}px))`,
1296
+ width: "max-content",
1297
+ pointerEvents: "none"
1298
+ };
1299
+ }
1300
+
1301
+ //#endregion
1302
+ //#region ../core/dist/dev/core/ui/thumbnail/thumbnail-core.js
1303
+ var ThumbnailCore = class {
1304
+ findActiveThumbnail(thumbnails, time) {
1305
+ if (thumbnails.length === 0) return void 0;
1306
+ let low = 0;
1307
+ let high = thumbnails.length - 1;
1308
+ let result;
1309
+ while (low <= high) {
1310
+ const mid = low + high >>> 1;
1311
+ const image = thumbnails[mid];
1312
+ if (time >= image.startTime) {
1313
+ result = image;
1314
+ low = mid + 1;
1315
+ } else high = mid - 1;
1316
+ }
1317
+ return result;
1318
+ }
1319
+ /**
1320
+ * Parse CSS constraint strings into numeric `ThumbnailConstraints`.
1321
+ *
1322
+ * Accepts any object with string `minWidth`/`maxWidth`/`minHeight`/`maxHeight`
1323
+ * properties — `CSSStyleDeclaration` satisfies this structurally.
1324
+ */
1325
+ parseConstraints(raw) {
1326
+ const minW = parseFloat(raw.minWidth);
1327
+ const maxW = parseFloat(raw.maxWidth);
1328
+ const minH = parseFloat(raw.minHeight);
1329
+ const maxH = parseFloat(raw.maxHeight);
153
1330
  return {
154
- "aria-label": this.getLabel(state),
155
- "aria-disabled": this.#props.disabled ? "true" : void 0
1331
+ minWidth: Number.isFinite(minW) ? minW : 0,
1332
+ maxWidth: Number.isFinite(maxW) ? maxW : Infinity,
1333
+ minHeight: Number.isFinite(minH) ? minH : 0,
1334
+ maxHeight: Number.isFinite(maxH) ? maxH : Infinity
156
1335
  };
157
1336
  }
158
- setMedia(media) {
159
- this.#media = media;
1337
+ /**
1338
+ * Calculate a uniform scale factor that fits `tileWidth × tileHeight` within the
1339
+ * given CSS min/max constraints while preserving aspect ratio.
1340
+ *
1341
+ * - Scales down when the tile exceeds max constraints.
1342
+ * - Scales up when the tile is smaller than min constraints.
1343
+ * - Returns `1` when no scaling is needed.
1344
+ */
1345
+ calculateScale(tileWidth, tileHeight, constraints) {
1346
+ const { minWidth, maxWidth, minHeight, maxHeight } = constraints;
1347
+ const maxRatio = Math.min(maxWidth / tileWidth, maxHeight / tileHeight);
1348
+ const minRatio = Math.max(minWidth / tileWidth, minHeight / tileHeight);
1349
+ if (Number.isFinite(maxRatio) && maxRatio < 1) return maxRatio;
1350
+ if (Number.isFinite(minRatio) && minRatio > 1) return minRatio;
1351
+ return 1;
160
1352
  }
161
- getState() {
162
- const media = this.#media;
163
- const availability = media.textTrackList.some((t) => t.kind === "captions" || t.kind === "subtitles") ? "available" : "unavailable";
164
- this.state.patch({
165
- subtitlesShowing: media.subtitlesShowing,
166
- availability
167
- });
168
- this.state.patch({ label: this.getLabel(this.state.current) });
169
- return this.state.current;
1353
+ /**
1354
+ * Compute container and image dimensions for the current thumbnail, scaled to
1355
+ * fit within the element's CSS min/max constraints.
1356
+ *
1357
+ * The container clips the sprite sheet via `overflow: hidden`, and the image is
1358
+ * positioned with `transform: translate()` to show the correct tile.
1359
+ */
1360
+ resize(thumbnail, imgNaturalWidth, imgNaturalHeight, constraints) {
1361
+ const tileWidth = thumbnail.width ?? imgNaturalWidth;
1362
+ const tileHeight = thumbnail.height ?? imgNaturalHeight;
1363
+ if (!tileWidth || !tileHeight) return void 0;
1364
+ const scale = this.calculateScale(tileWidth, tileHeight, constraints);
1365
+ const coordX = thumbnail.coords?.x ?? 0;
1366
+ const coordY = thumbnail.coords?.y ?? 0;
1367
+ const inset = scale !== 1 ? 1 : 0;
1368
+ return {
1369
+ scale,
1370
+ containerWidth: Math.max(0, Math.floor(tileWidth * scale) - inset * 2),
1371
+ containerHeight: Math.max(0, Math.floor(tileHeight * scale) - inset * 2),
1372
+ imageWidth: Math.ceil(imgNaturalWidth * scale),
1373
+ imageHeight: Math.ceil(imgNaturalHeight * scale),
1374
+ offsetX: Math.ceil(coordX * scale) + inset,
1375
+ offsetY: Math.ceil(coordY * scale) + inset
1376
+ };
170
1377
  }
171
- toggle(media) {
172
- if (this.#props.disabled) return;
173
- media.toggleSubtitles();
1378
+ getState(loading, error, thumbnail) {
1379
+ return {
1380
+ loading,
1381
+ error,
1382
+ hidden: !loading && !thumbnail
1383
+ };
1384
+ }
1385
+ getAttrs(_state) {
1386
+ return {
1387
+ role: "img",
1388
+ "aria-hidden": "true"
1389
+ };
174
1390
  }
175
1391
  };
176
1392
 
177
1393
  //#endregion
178
- //#region ../core/dist/dev/core/ui/captions-button/captions-button-data-attrs.js
179
- const CaptionsButtonDataAttrs = {
180
- subtitlesShowing: "data-active",
181
- availability: "data-availability"
1394
+ //#region ../core/dist/dev/dom/ui/thumbnail.js
1395
+ function createThumbnail(options) {
1396
+ const { getContainer, getImg, onStateChange } = options;
1397
+ const core = new ThumbnailCore();
1398
+ const abort = new AbortController();
1399
+ const signal = abort.signal;
1400
+ let loading = false;
1401
+ let error = false;
1402
+ let naturalWidth = 0;
1403
+ let naturalHeight = 0;
1404
+ let lastSrc = "";
1405
+ let imgBound = false;
1406
+ let resizeObserver = null;
1407
+ function onImgLoad() {
1408
+ const img = getImg();
1409
+ if (img) {
1410
+ naturalWidth = img.naturalWidth;
1411
+ naturalHeight = img.naturalHeight;
1412
+ }
1413
+ loading = false;
1414
+ error = false;
1415
+ onStateChange();
1416
+ }
1417
+ function onImgError() {
1418
+ loading = false;
1419
+ error = true;
1420
+ onStateChange();
1421
+ }
1422
+ function bindImg(img) {
1423
+ listen(img, "load", onImgLoad, { signal });
1424
+ listen(img, "error", onImgError, { signal });
1425
+ }
1426
+ function ensureBindings() {
1427
+ if (!imgBound) {
1428
+ const img = getImg();
1429
+ if (img) {
1430
+ bindImg(img);
1431
+ imgBound = true;
1432
+ }
1433
+ }
1434
+ if (!resizeObserver) {
1435
+ const container = getContainer();
1436
+ if (container) {
1437
+ resizeObserver = new ResizeObserver(onStateChange);
1438
+ resizeObserver.observe(container);
1439
+ }
1440
+ }
1441
+ }
1442
+ function updateSrc(url) {
1443
+ ensureBindings();
1444
+ const src = url ?? "";
1445
+ if (src === lastSrc) return;
1446
+ lastSrc = src;
1447
+ if (src) {
1448
+ loading = true;
1449
+ error = false;
1450
+ } else {
1451
+ loading = false;
1452
+ error = false;
1453
+ naturalWidth = 0;
1454
+ naturalHeight = 0;
1455
+ }
1456
+ }
1457
+ function connect() {
1458
+ ensureBindings();
1459
+ const img = getImg();
1460
+ if (img?.complete && lastSrc) {
1461
+ if (img.naturalWidth > 0) {
1462
+ naturalWidth = img.naturalWidth;
1463
+ naturalHeight = img.naturalHeight;
1464
+ loading = false;
1465
+ error = false;
1466
+ } else {
1467
+ loading = false;
1468
+ error = true;
1469
+ }
1470
+ onStateChange();
1471
+ }
1472
+ }
1473
+ function destroy() {
1474
+ abort.abort();
1475
+ resizeObserver?.disconnect();
1476
+ resizeObserver = null;
1477
+ }
1478
+ return {
1479
+ get loading() {
1480
+ return loading;
1481
+ },
1482
+ get error() {
1483
+ return error;
1484
+ },
1485
+ get naturalWidth() {
1486
+ return naturalWidth;
1487
+ },
1488
+ get naturalHeight() {
1489
+ return naturalHeight;
1490
+ },
1491
+ readConstraints() {
1492
+ const el = getContainer();
1493
+ if (!el) return {
1494
+ minWidth: 0,
1495
+ maxWidth: Infinity,
1496
+ minHeight: 0,
1497
+ maxHeight: Infinity
1498
+ };
1499
+ return core.parseConstraints(getComputedStyle(el));
1500
+ },
1501
+ updateSrc,
1502
+ connect,
1503
+ destroy
1504
+ };
1505
+ }
1506
+
1507
+ //#endregion
1508
+ //#region ../core/dist/dev/dom/ui/tooltip/tooltip.js
1509
+ /** Map popover reasons to tooltip reasons, filtering out click/outside-click. */
1510
+ const REASON_MAP = {
1511
+ hover: "hover",
1512
+ focus: "focus",
1513
+ escape: "escape",
1514
+ blur: "blur"
182
1515
  };
1516
+ function createTooltip(options) {
1517
+ const popoverOpts = {
1518
+ transition: options.transition,
1519
+ onOpenChange(open, details) {
1520
+ const reason = REASON_MAP[details.reason];
1521
+ if (!reason) return;
1522
+ const group = options.group?.();
1523
+ if (open) group?.notifyOpen();
1524
+ else group?.notifyClose();
1525
+ const tooltipDetails = details.event ? {
1526
+ reason,
1527
+ event: details.event
1528
+ } : { reason };
1529
+ options.onOpenChange(open, tooltipDetails);
1530
+ },
1531
+ closeOnEscape: () => true,
1532
+ closeOnOutsideClick: () => false,
1533
+ openOnHover: () => true,
1534
+ delay: () => {
1535
+ const group = options.group?.();
1536
+ if (group?.shouldSkipDelay()) return 0;
1537
+ return options.delay?.() ?? group?.delay ?? 600;
1538
+ },
1539
+ closeDelay: () => {
1540
+ const group = options.group?.();
1541
+ return options.closeDelay?.() ?? group?.closeDelay ?? 0;
1542
+ }
1543
+ };
1544
+ if (options.onOpenChangeComplete) popoverOpts.onOpenChangeComplete = options.onOpenChangeComplete;
1545
+ const popover = createPopover(popoverOpts);
1546
+ let isPointerDown = false;
1547
+ const { onClick: _, ...baseTriggerProps } = popover.triggerProps;
1548
+ const triggerProps = {
1549
+ ...baseTriggerProps,
1550
+ onPointerDown() {
1551
+ isPointerDown = true;
1552
+ },
1553
+ onPointerEnter(event) {
1554
+ if (options.disabled?.()) return;
1555
+ if (event.pointerType === "touch") return;
1556
+ baseTriggerProps.onPointerEnter(event);
1557
+ },
1558
+ onFocusIn(event) {
1559
+ if (options.disabled?.()) return;
1560
+ if (isPointerDown) {
1561
+ isPointerDown = false;
1562
+ return;
1563
+ }
1564
+ baseTriggerProps.onFocusIn(event);
1565
+ }
1566
+ };
1567
+ const popupProps = {
1568
+ ...popover.popupProps,
1569
+ onPointerEnter(event) {
1570
+ if (options.disableHoverablePopup?.()) return;
1571
+ popover.popupProps.onPointerEnter(event);
1572
+ }
1573
+ };
1574
+ return {
1575
+ ...popover,
1576
+ triggerProps,
1577
+ popupProps,
1578
+ get triggerElement() {
1579
+ return popover.triggerElement;
1580
+ },
1581
+ open: () => popover.open("hover"),
1582
+ close: () => popover.close("hover")
1583
+ };
1584
+ }
1585
+
1586
+ //#endregion
1587
+ //#region ../core/dist/dev/dom/ui/transition.js
1588
+ /**
1589
+ * Manages open/close transition lifecycle via `createState`.
1590
+ *
1591
+ * **Open:** patches `{ active: true, status: 'starting' }`, then after a
1592
+ * double-RAF patches `{ status: 'idle' }` so the browser paints the
1593
+ * initial ("from") state before transitioning.
1594
+ *
1595
+ * **Close:** patches `{ status: 'ending' }` (keeping `active: true` so the
1596
+ * element stays mounted), then after a double-RAF waits for
1597
+ * `getAnimations()` to settle before patching `{ active: false, status: 'idle' }`.
1598
+ */
1599
+ function createTransition() {
1600
+ const state = createState({
1601
+ active: false,
1602
+ status: "idle"
1603
+ });
1604
+ let destroyed = false;
1605
+ let rafId1 = 0;
1606
+ let rafId2 = 0;
1607
+ function open() {
1608
+ cancelAnimationFrame(rafId1);
1609
+ cancelAnimationFrame(rafId2);
1610
+ rafId1 = 0;
1611
+ rafId2 = 0;
1612
+ state.patch({
1613
+ active: true,
1614
+ status: "starting"
1615
+ });
1616
+ return new Promise((resolve) => {
1617
+ rafId1 = requestAnimationFrame(() => {
1618
+ rafId1 = 0;
1619
+ rafId2 = requestAnimationFrame(() => {
1620
+ rafId2 = 0;
1621
+ if (destroyed || !state.current.active) return resolve();
1622
+ state.patch({ status: "idle" });
1623
+ resolve();
1624
+ });
1625
+ });
1626
+ });
1627
+ }
1628
+ function close(el) {
1629
+ cancelAnimationFrame(rafId1);
1630
+ cancelAnimationFrame(rafId2);
1631
+ rafId1 = 0;
1632
+ rafId2 = 0;
1633
+ state.patch({ status: "ending" });
1634
+ return new Promise((resolve) => {
1635
+ rafId1 = requestAnimationFrame(() => {
1636
+ rafId1 = 0;
1637
+ rafId2 = requestAnimationFrame(() => {
1638
+ rafId2 = 0;
1639
+ if (destroyed) return resolve();
1640
+ waitForAnimations(el).finally(() => {
1641
+ if (destroyed || state.current.status !== "ending") return resolve();
1642
+ state.patch({
1643
+ active: false,
1644
+ status: "idle"
1645
+ });
1646
+ resolve();
1647
+ });
1648
+ });
1649
+ });
1650
+ });
1651
+ }
1652
+ function cancel() {
1653
+ cancelAnimationFrame(rafId1);
1654
+ cancelAnimationFrame(rafId2);
1655
+ rafId1 = 0;
1656
+ rafId2 = 0;
1657
+ if (state.current.status !== "idle") state.patch({ status: "idle" });
1658
+ }
1659
+ return {
1660
+ state,
1661
+ open,
1662
+ close,
1663
+ cancel,
1664
+ destroy() {
1665
+ if (destroyed) return;
1666
+ destroyed = true;
1667
+ cancel();
1668
+ }
1669
+ };
1670
+ }
1671
+ function waitForAnimations(el) {
1672
+ if (!el) return Promise.resolve();
1673
+ const animations = el.getAnimations?.() ?? [];
1674
+ if (animations.length === 0) return Promise.resolve();
1675
+ return Promise.all(animations.map((a) => a.finished)).then(noop, noop);
1676
+ }
1677
+
1678
+ //#endregion
1679
+ //#region ../core/dist/dev/dom/ui/wheel-step.js
1680
+ function createWheelStep(options) {
1681
+ return { onWheel(event) {
1682
+ if (options.isDisabled()) return;
1683
+ const direction = Math.sign(event.deltaY);
1684
+ if (direction === 0) return;
1685
+ event.preventDefault();
1686
+ const stepPercent = options.getStepPercent();
1687
+ const newPercent = clamp(options.getPercent() - direction * stepPercent, 0, 100);
1688
+ options.onValueChange?.(newPercent);
1689
+ } };
1690
+ }
1691
+
1692
+ //#endregion
1693
+ //#region ../core/dist/dev/dom/utils/element-props.js
1694
+ /**
1695
+ * Apply props to a DOM element.
1696
+ *
1697
+ * Handles both attributes and event listeners:
1698
+ * - Event props (onClick, onKeyDown, etc.) are attached as listeners
1699
+ * - Boolean props: `true` sets empty attribute, `false` removes
1700
+ * - `undefined` removes the attribute
1701
+ * - Other props are set as string attributes
1702
+ */
1703
+ function applyElementProps(element, props, options) {
1704
+ const signal = options?.signal;
1705
+ for (const [key, value] of Object.entries(props)) if (isFunction(value) && key.startsWith("on")) listen(element, key.slice(2).toLowerCase(), value, signal ? { signal } : void 0);
1706
+ else if (isUndefined(value) || value === false) element.removeAttribute(key);
1707
+ else if (value === true) element.setAttribute(key, "");
1708
+ else element.setAttribute(key, String(value));
1709
+ }
183
1710
 
184
1711
  //#endregion
185
- //#region ../core/dist/dev/core/ui/controls/controls-core.js
186
- var ControlsCore = class {
187
- #media = null;
188
- setMedia(media) {
189
- this.#media = media;
190
- }
191
- getState() {
192
- const media = this.#media;
193
- return {
194
- visible: media.controlsVisible,
195
- userActive: media.userActive
196
- };
197
- }
198
- };
1712
+ //#region ../core/dist/dev/dom/utils/log.js
1713
+ const warned = /* @__PURE__ */ new Set();
1714
+ function logMissingFeature(displayName, featureName) {
1715
+ const key = `${displayName}:${featureName}`;
1716
+ if (warned.has(key)) return;
1717
+ warned.add(key);
1718
+ console.warn(`${displayName} requires ${featureName} feature`);
1719
+ }
199
1720
 
200
1721
  //#endregion
201
- //#region ../core/dist/dev/core/ui/controls/controls-data-attrs.js
202
- const ControlsDataAttrs = {
203
- visible: "data-visible",
204
- userActive: "data-user-active"
205
- };
1722
+ //#region ../core/dist/dev/dom/utils/state-data-attrs.js
1723
+ /**
1724
+ * Apply state as data attributes to an element.
1725
+ *
1726
+ * - `true` → sets `data-keyname=""`
1727
+ * - truthy string/number → sets `data-keyname="value"`
1728
+ * - falsy → removes the attribute
1729
+ *
1730
+ * @example
1731
+ * ```ts
1732
+ * const state = { paused: true, ended: false };
1733
+ * applyStateDataAttrs(element, state);
1734
+ * // element has data-paused="", data-ended is removed
1735
+ * ```
1736
+ */
1737
+ function applyStateDataAttrs(element, state, map) {
1738
+ for (const key in state) {
1739
+ if (map && !(key in map)) continue;
1740
+ const name = map?.[key] ?? toDataAttrName(key), value = state[key];
1741
+ if (value === true) element.setAttribute(name, "");
1742
+ else if (value) element.setAttribute(name, String(value));
1743
+ else element.removeAttribute(name);
1744
+ }
1745
+ }
1746
+ function toDataAttrName(key) {
1747
+ return `data-${key.toLowerCase()}`;
1748
+ }
206
1749
 
207
1750
  //#endregion
208
- //#region ../core/dist/dev/core/ui/error-dialog/error-dialog-core.js
209
- /** Error-dialog core: an alert dialog whose open state is driven by media error state. */
210
- var ErrorDialogCore = class extends AlertDialogCore {
211
- setProps() {}
212
- };
1751
+ //#region ../core/dist/dev/core/ui/transition.js
1752
+ function getTransitionFlags(status) {
1753
+ return {
1754
+ transitionStarting: status === "starting",
1755
+ transitionEnding: status === "ending"
1756
+ };
1757
+ }
213
1758
 
214
1759
  //#endregion
215
- //#region ../core/dist/dev/core/ui/fullscreen-button/fullscreen-button-core.js
216
- var FullscreenButtonCore = class FullscreenButtonCore {
1760
+ //#region ../core/dist/dev/core/ui/alert-dialog/alert-dialog-core.js
1761
+ var AlertDialogCore = class {
217
1762
  static defaultProps = {
218
- label: "",
219
- disabled: false
1763
+ open: false,
1764
+ defaultOpen: false
220
1765
  };
221
- state = createState({
222
- fullscreen: false,
223
- availability: "available",
224
- label: ""
225
- });
226
- #props = { ...FullscreenButtonCore.defaultProps };
227
- #media = null;
228
- constructor(props) {
229
- if (props) this.setProps(props);
1766
+ /** Accept props for API consistency. Props are consumed by platform layers. */
1767
+ setProps(_props) {}
1768
+ #input = null;
1769
+ #titleId = void 0;
1770
+ #descriptionId = void 0;
1771
+ setInput(input) {
1772
+ this.#input = input;
230
1773
  }
231
- setProps(props) {
232
- this.#props = defaults(props, FullscreenButtonCore.defaultProps);
1774
+ setTitleId(id) {
1775
+ this.#titleId = id;
233
1776
  }
234
- getLabel(state) {
235
- const { label } = this.#props;
236
- if (isFunction(label)) {
237
- const customLabel = label(state);
238
- if (customLabel) return customLabel;
239
- } else if (label) return label;
240
- return state.fullscreen ? "Exit fullscreen" : "Enter fullscreen";
1777
+ setDescriptionId(id) {
1778
+ this.#descriptionId = id;
241
1779
  }
242
- getAttrs(state) {
1780
+ getState() {
1781
+ const input = this.#input;
243
1782
  return {
244
- "aria-label": this.getLabel(state),
245
- "aria-disabled": this.#props.disabled ? "true" : void 0
1783
+ open: input.active,
1784
+ status: input.status,
1785
+ titleId: this.#titleId,
1786
+ descriptionId: this.#descriptionId,
1787
+ ...getTransitionFlags(input.status)
246
1788
  };
247
1789
  }
248
- setMedia(media) {
249
- this.#media = media;
250
- }
251
- getState() {
252
- const media = this.#media;
253
- this.state.patch({
254
- fullscreen: media.fullscreen,
255
- availability: media.fullscreenAvailability
256
- });
257
- this.state.patch({ label: this.getLabel(this.state.current) });
258
- return this.state.current;
259
- }
260
- async toggle(media) {
261
- if (this.#props.disabled) return;
262
- if (media.fullscreenAvailability !== "available") return;
263
- try {
264
- if (media.fullscreen) await media.exitFullscreen();
265
- else await media.requestFullscreen();
266
- } catch {}
1790
+ getAttrs(state) {
1791
+ return {
1792
+ role: "alertdialog",
1793
+ "aria-modal": "true",
1794
+ "aria-labelledby": state.titleId,
1795
+ "aria-describedby": state.descriptionId
1796
+ };
267
1797
  }
268
1798
  };
269
1799
 
270
1800
  //#endregion
271
- //#region ../core/dist/dev/core/ui/fullscreen-button/fullscreen-button-data-attrs.js
272
- const FullscreenButtonDataAttrs = {
273
- fullscreen: "data-fullscreen",
274
- availability: "data-availability"
1801
+ //#region ../core/dist/dev/core/ui/alert-dialog/alert-dialog-data-attrs.js
1802
+ const AlertDialogDataAttrs = {
1803
+ open: "data-open",
1804
+ transitionStarting: "data-starting-style",
1805
+ transitionEnding: "data-ending-style"
1806
+ };
1807
+
1808
+ //#endregion
1809
+ //#region ../core/dist/dev/core/ui/error-dialog/error-dialog-core.js
1810
+ /** Error-dialog core: an alert dialog whose open state is driven by media error state. */
1811
+ var ErrorDialogCore = class extends AlertDialogCore {
1812
+ setProps() {}
275
1813
  };
276
1814
 
277
1815
  //#endregion
@@ -339,69 +1877,6 @@ const MuteButtonDataAttrs = {
339
1877
  volumeLevel: "data-volume-level"
340
1878
  };
341
1879
 
342
- //#endregion
343
- //#region ../core/dist/dev/core/ui/pip-button/pip-button-core.js
344
- var PiPButtonCore = class PiPButtonCore {
345
- static defaultProps = {
346
- label: "",
347
- disabled: false
348
- };
349
- state = createState({
350
- pip: false,
351
- availability: "available",
352
- label: ""
353
- });
354
- #props = { ...PiPButtonCore.defaultProps };
355
- #media = null;
356
- constructor(props) {
357
- if (props) this.setProps(props);
358
- }
359
- setProps(props) {
360
- this.#props = defaults(props, PiPButtonCore.defaultProps);
361
- }
362
- getLabel(state) {
363
- const { label } = this.#props;
364
- if (isFunction(label)) {
365
- const customLabel = label(state);
366
- if (customLabel) return customLabel;
367
- } else if (label) return label;
368
- return state.pip ? "Exit picture-in-picture" : "Enter picture-in-picture";
369
- }
370
- getAttrs(state) {
371
- return {
372
- "aria-label": this.getLabel(state),
373
- "aria-disabled": this.#props.disabled ? "true" : void 0
374
- };
375
- }
376
- setMedia(media) {
377
- this.#media = media;
378
- }
379
- getState() {
380
- const media = this.#media;
381
- this.state.patch({
382
- pip: media.pip,
383
- availability: media.pipAvailability
384
- });
385
- this.state.patch({ label: this.getLabel(this.state.current) });
386
- return this.state.current;
387
- }
388
- async toggle(media) {
389
- if (this.#props.disabled) return;
390
- if (media.pipAvailability !== "available") return;
391
- try {
392
- if (media.pip) await media.exitPictureInPicture();
393
- else await media.requestPictureInPicture();
394
- } catch {}
395
- }
396
- };
397
-
398
- //#endregion
399
- //#region ../core/dist/dev/core/ui/pip-button/pip-button-data-attrs.js
400
- const PiPButtonDataAttrs = {
401
- pip: "data-pip",
402
- availability: "data-availability"
403
- };
404
-
405
1880
  //#endregion
406
1881
  //#region ../core/dist/dev/core/ui/play-button/play-button-core.js
407
1882
  var PlayButtonCore = class PlayButtonCore {
@@ -585,22 +2060,6 @@ const PopoverDataAttrs = {
585
2060
  transitionEnding: "data-ending-style"
586
2061
  };
587
2062
 
588
- //#endregion
589
- //#region ../core/dist/dev/core/ui/poster/poster-core.js
590
- var PosterCore = class {
591
- #media = null;
592
- setMedia(media) {
593
- this.#media = media;
594
- }
595
- getState() {
596
- return { visible: !this.#media.started };
597
- }
598
- };
599
-
600
- //#endregion
601
- //#region ../core/dist/dev/core/ui/poster/poster-data-attrs.js
602
- const PosterDataAttrs = { visible: "data-visible" };
603
-
604
2063
  //#endregion
605
2064
  //#region ../core/dist/dev/core/ui/seek-button/seek-button-core.js
606
2065
  var SeekButtonCore = class SeekButtonCore {
@@ -1028,7 +2487,7 @@ var TimeSliderCore = class TimeSliderCore extends SliderCore {
1028
2487
  static defaultProps = {
1029
2488
  ...SliderCore.defaultProps,
1030
2489
  label: "Seek",
1031
- commitThrottle: 100
2490
+ changeThrottle: 100
1032
2491
  };
1033
2492
  #props = { ...TimeSliderCore.defaultProps };
1034
2493
  #media = null;
@@ -1048,14 +2507,12 @@ var TimeSliderCore = class TimeSliderCore extends SliderCore {
1048
2507
  }
1049
2508
  getState() {
1050
2509
  const { duration, currentTime, seeking, buffered } = this.#media;
1051
- const { dragging, dragPercent } = this.input;
1052
2510
  super.setProps({
1053
2511
  ...this.#props,
1054
2512
  min: 0,
1055
2513
  max: duration
1056
2514
  });
1057
- const value = dragging ? clamp(dragPercent / 100 * duration, 0, duration) : currentTime;
1058
- const base = super.getSliderState(value);
2515
+ const base = super.getSliderState(currentTime);
1059
2516
  const bufferedEnd = buffered.length > 0 ? buffered[buffered.length - 1][1] : 0;
1060
2517
  const bufferPercent = duration > 0 ? bufferedEnd / duration * 100 : 0;
1061
2518
  return {
@@ -1071,11 +2528,13 @@ var TimeSliderCore = class TimeSliderCore extends SliderCore {
1071
2528
  }
1072
2529
  getAttrs(state) {
1073
2530
  const base = super.getAttrs(state);
1074
- const currentPhrase = formatTimeAsPhrase(state.value);
2531
+ const announceValue = state.dragging ? this.rawValueFromPercent(state.pointerPercent) : state.value;
2532
+ const currentPhrase = formatTimeAsPhrase(announceValue);
1075
2533
  const durationPhrase = formatTimeAsPhrase(state.duration);
1076
2534
  const valuetext = durationPhrase ? `${currentPhrase} of ${durationPhrase}` : currentPhrase;
1077
2535
  return {
1078
2536
  ...base,
2537
+ "aria-valuenow": announceValue,
1079
2538
  "aria-valuetext": valuetext
1080
2539
  };
1081
2540
  }
@@ -1249,6 +2708,29 @@ const VolumeSliderDataAttrs = {
1249
2708
  availability: "data-availability"
1250
2709
  };
1251
2710
 
2711
+ //#endregion
2712
+ //#region src/ui/hotkey/aria-key-shortcuts-controller.ts
2713
+ /** Provides `aria-keyshortcuts` for a given hotkey action name. */
2714
+ var AriaKeyShortcutsController = class {
2715
+ #action;
2716
+ #container;
2717
+ constructor(host, action) {
2718
+ this.#action = action;
2719
+ this.#container = new ContextConsumer(host, {
2720
+ context: containerContext,
2721
+ subscribe: true
2722
+ });
2723
+ host.addController(this);
2724
+ }
2725
+ get value() {
2726
+ const container = this.#container.value?.container;
2727
+ if (!container) return void 0;
2728
+ return findHotkeyCoordinator(container)?.getAriaKeys(this.#action);
2729
+ }
2730
+ hostConnected() {}
2731
+ hostDisconnected() {}
2732
+ };
2733
+
1252
2734
  //#endregion
1253
2735
  //#region src/ui/media-button-element.ts
1254
2736
  /** Abstract base for HTML custom elements that render a media-control button. */
@@ -1257,6 +2739,7 @@ var MediaButtonElement = class extends MediaElement {
1257
2739
  super(..._args);
1258
2740
  this.disabled = false;
1259
2741
  this.label = "";
2742
+ this.hotkeyAction = void 0;
1260
2743
  }
1261
2744
  static {
1262
2745
  this.properties = {
@@ -1268,8 +2751,11 @@ var MediaButtonElement = class extends MediaElement {
1268
2751
  return this.core.state;
1269
2752
  }
1270
2753
  #disconnect = null;
2754
+ #hotkeyRegistry = null;
1271
2755
  connectedCallback() {
1272
2756
  super.connectedCallback();
2757
+ if (this.destroyed) return;
2758
+ if (this.hotkeyAction && !this.#hotkeyRegistry) this.#hotkeyRegistry = new AriaKeyShortcutsController(this, this.hotkeyAction);
1273
2759
  this.#disconnect = new AbortController();
1274
2760
  const buttonProps = createButton({
1275
2761
  onActivate: () => this.activate(this.mediaState.value),
@@ -1297,7 +2783,10 @@ var MediaButtonElement = class extends MediaElement {
1297
2783
  if (!media) return;
1298
2784
  this.core.setMedia(media);
1299
2785
  const state = this.core.getState();
1300
- applyElementProps(this, this.core.getAttrs?.(state) ?? {});
2786
+ applyElementProps(this, {
2787
+ ...this.core.getAttrs?.(state),
2788
+ "aria-keyshortcuts": this.#hotkeyRegistry?.value
2789
+ });
1301
2790
  applyStateDataAttrs(this, state, this.stateAttrMap);
1302
2791
  }
1303
2792
  };
@@ -1432,6 +2921,7 @@ var ErrorDialogElement = class extends MediaElement {
1432
2921
  }
1433
2922
  connectedCallback() {
1434
2923
  super.connectedCallback();
2924
+ if (this.destroyed) return;
1435
2925
  this.#dialog = createAlertDialog({
1436
2926
  transition: createTransition(),
1437
2927
  onOpenChange: (nextOpen) => {
@@ -1490,6 +2980,7 @@ var MuteButtonElement = class extends MediaButtonElement {
1490
2980
  this.core = new MuteButtonCore();
1491
2981
  this.stateAttrMap = MuteButtonDataAttrs;
1492
2982
  this.mediaState = new PlayerController(this, playerContext, selectVolume);
2983
+ this.hotkeyAction = "toggleMuted";
1493
2984
  }
1494
2985
  static {
1495
2986
  this.tagName = "media-mute-button";
@@ -1511,6 +3002,7 @@ var PlayButtonElement = class extends MediaButtonElement {
1511
3002
  this.core = new PlayButtonCore();
1512
3003
  this.stateAttrMap = PlayButtonDataAttrs;
1513
3004
  this.mediaState = new PlayerController(this, playerContext, selectPlayback);
3005
+ this.hotkeyAction = "togglePaused";
1514
3006
  }
1515
3007
  static {
1516
3008
  this.tagName = "media-play-button";
@@ -1545,6 +3037,79 @@ var PlaybackRateButtonElement = class extends MediaButtonElement {
1545
3037
  //#region src/define/ui/playback-rate-button.ts
1546
3038
  safeDefine(PlaybackRateButtonElement);
1547
3039
 
3040
+ //#endregion
3041
+ //#region src/ui/position-controller.ts
3042
+ /**
3043
+ * Reactive controller that manages JS-fallback positioning for floating
3044
+ * popup elements (tooltips, popovers). Tracks scroll, resize, and
3045
+ * ResizeObserver events to keep the popup aligned with its trigger.
3046
+ *
3047
+ * When native CSS Anchor Positioning is supported, `sync()` is a no-op.
3048
+ */
3049
+ var PositionController = class {
3050
+ #host;
3051
+ #abort = null;
3052
+ #frame = 0;
3053
+ #resizeObserver = null;
3054
+ #trigger = null;
3055
+ constructor(host) {
3056
+ this.#host = host;
3057
+ host.addController(this);
3058
+ }
3059
+ /** Discover a trigger element linked via `commandfor` attribute. */
3060
+ findTrigger() {
3061
+ if (!this.#host.id) return null;
3062
+ return this.#host.getRootNode().querySelector(`[commandfor="${this.#host.id}"]`);
3063
+ }
3064
+ /** Start or update position tracking for the given trigger. */
3065
+ sync(trigger) {
3066
+ if (supportsAnchorPositioning()) return;
3067
+ if (!trigger) return;
3068
+ if (this.#abort && this.#trigger === trigger) return;
3069
+ this.cleanup();
3070
+ this.#abort = new AbortController();
3071
+ this.#trigger = trigger;
3072
+ const { signal } = this.#abort;
3073
+ const reposition = () => {
3074
+ cancelAnimationFrame(this.#frame);
3075
+ this.#frame = requestAnimationFrame(() => {
3076
+ if (signal.aborted) return;
3077
+ this.#host.requestUpdate();
3078
+ });
3079
+ };
3080
+ window.addEventListener("scroll", reposition, {
3081
+ capture: true,
3082
+ passive: true,
3083
+ signal
3084
+ });
3085
+ window.addEventListener("resize", reposition, { signal });
3086
+ if (typeof ResizeObserver === "function") {
3087
+ this.#resizeObserver = new ResizeObserver(() => {
3088
+ reposition();
3089
+ });
3090
+ this.#resizeObserver.observe(trigger);
3091
+ this.#resizeObserver.observe(this.#host);
3092
+ }
3093
+ reposition();
3094
+ }
3095
+ /** Stop all position tracking. */
3096
+ cleanup() {
3097
+ this.#abort?.abort();
3098
+ this.#abort = null;
3099
+ this.#trigger = null;
3100
+ cancelAnimationFrame(this.#frame);
3101
+ this.#frame = 0;
3102
+ this.#resizeObserver?.disconnect();
3103
+ this.#resizeObserver = null;
3104
+ }
3105
+ hostDisconnected() {
3106
+ this.cleanup();
3107
+ }
3108
+ hostDestroyed() {
3109
+ this.cleanup();
3110
+ }
3111
+ };
3112
+
1548
3113
  //#endregion
1549
3114
  //#region src/ui/popover/popover-element.ts
1550
3115
  var PopoverElement = class extends MediaElement {
@@ -1594,15 +3159,12 @@ var PopoverElement = class extends MediaElement {
1594
3159
  };
1595
3160
  }
1596
3161
  #core = new PopoverCore();
3162
+ #position = new PositionController(this);
1597
3163
  #popover = null;
1598
3164
  #snapshot = null;
1599
3165
  #disconnect = null;
1600
3166
  #triggerAbort = null;
1601
3167
  #currentTrigger = null;
1602
- #positionAbort = null;
1603
- #positionFrame = 0;
1604
- #resizeObserver = null;
1605
- #positionTrigger = null;
1606
3168
  connectedCallback() {
1607
3169
  super.connectedCallback();
1608
3170
  if (this.destroyed) return;
@@ -1633,12 +3195,10 @@ var PopoverElement = class extends MediaElement {
1633
3195
  }
1634
3196
  disconnectedCallback() {
1635
3197
  super.disconnectedCallback();
1636
- this.#cleanupPositioning();
1637
3198
  this.#disconnect?.abort();
1638
3199
  this.#disconnect = null;
1639
3200
  }
1640
3201
  destroyCallback() {
1641
- this.#cleanupPositioning();
1642
3202
  this.#cleanupTrigger();
1643
3203
  this.#popover?.destroy();
1644
3204
  super.destroyCallback();
@@ -1655,7 +3215,7 @@ var PopoverElement = class extends MediaElement {
1655
3215
  update(_changed) {
1656
3216
  super.update(_changed);
1657
3217
  if (!this.#popover) return;
1658
- const triggerEl = this.#findTrigger();
3218
+ const triggerEl = this.#position.findTrigger();
1659
3219
  this.#syncTrigger(triggerEl);
1660
3220
  const input = this.#popover.input.current;
1661
3221
  this.#core.setInput(input);
@@ -1669,7 +3229,7 @@ var PopoverElement = class extends MediaElement {
1669
3229
  applyStyles(this.#currentTrigger, getAnchorNameStyle(this.id));
1670
3230
  }
1671
3231
  if (!state.open) {
1672
- this.#cleanupPositioning();
3232
+ this.#position.cleanup();
1673
3233
  return;
1674
3234
  }
1675
3235
  const posOpts = {
@@ -1684,15 +3244,11 @@ var PopoverElement = class extends MediaElement {
1684
3244
  const offsets = resolveOffsets(this);
1685
3245
  applyStyles(this, getAnchorPositionStyle(this.id, posOpts, triggerRect, selfRect, boundaryRect, offsets));
1686
3246
  }
1687
- this.#syncPositioning();
1688
- }
1689
- #findTrigger() {
1690
- if (!this.id) return null;
1691
- return this.getRootNode().querySelector(`[commandfor="${this.id}"]`);
3247
+ this.#position.sync(this.#currentTrigger);
1692
3248
  }
1693
3249
  #syncTrigger(triggerEl) {
1694
3250
  if (triggerEl === this.#currentTrigger) return;
1695
- this.#cleanupPositioning();
3251
+ this.#position.cleanup();
1696
3252
  this.#cleanupTrigger();
1697
3253
  this.#currentTrigger = triggerEl;
1698
3254
  this.#popover?.setTriggerElement(triggerEl);
@@ -1714,46 +3270,6 @@ var PopoverElement = class extends MediaElement {
1714
3270
  this.#triggerAbort = null;
1715
3271
  this.#currentTrigger = null;
1716
3272
  }
1717
- #syncPositioning() {
1718
- if (supportsAnchorPositioning()) return;
1719
- const triggerEl = this.#currentTrigger;
1720
- if (!triggerEl) return;
1721
- if (this.#positionAbort && this.#positionTrigger === triggerEl) return;
1722
- this.#cleanupPositioning();
1723
- this.#positionAbort = new AbortController();
1724
- this.#positionTrigger = triggerEl;
1725
- const { signal } = this.#positionAbort;
1726
- const reposition = () => {
1727
- cancelAnimationFrame(this.#positionFrame);
1728
- this.#positionFrame = requestAnimationFrame(() => {
1729
- if (signal.aborted) return;
1730
- this.requestUpdate();
1731
- });
1732
- };
1733
- window.addEventListener("scroll", reposition, {
1734
- capture: true,
1735
- passive: true,
1736
- signal
1737
- });
1738
- window.addEventListener("resize", reposition, { signal });
1739
- if (typeof ResizeObserver === "function") {
1740
- this.#resizeObserver = new ResizeObserver(() => {
1741
- reposition();
1742
- });
1743
- this.#resizeObserver.observe(triggerEl);
1744
- this.#resizeObserver.observe(this);
1745
- }
1746
- reposition();
1747
- }
1748
- #cleanupPositioning() {
1749
- this.#positionAbort?.abort();
1750
- this.#positionAbort = null;
1751
- this.#positionTrigger = null;
1752
- cancelAnimationFrame(this.#positionFrame);
1753
- this.#positionFrame = 0;
1754
- this.#resizeObserver?.disconnect();
1755
- this.#resizeObserver = null;
1756
- }
1757
3273
  };
1758
3274
 
1759
3275
  //#endregion
@@ -2183,7 +3699,7 @@ var TimeSliderElement = class extends MediaElement {
2183
3699
  constructor(..._args) {
2184
3700
  super(..._args);
2185
3701
  this.label = TimeSliderCore.defaultProps.label;
2186
- this.commitThrottle = TimeSliderCore.defaultProps.commitThrottle;
3702
+ this.changeThrottle = TimeSliderCore.defaultProps.changeThrottle;
2187
3703
  this.step = TimeSliderCore.defaultProps.step;
2188
3704
  this.largeStep = TimeSliderCore.defaultProps.largeStep;
2189
3705
  this.orientation = TimeSliderCore.defaultProps.orientation;
@@ -2196,9 +3712,9 @@ var TimeSliderElement = class extends MediaElement {
2196
3712
  static {
2197
3713
  this.properties = {
2198
3714
  label: { type: String },
2199
- commitThrottle: {
3715
+ changeThrottle: {
2200
3716
  type: Number,
2201
- attribute: "commit-throttle"
3717
+ attribute: "change-throttle"
2202
3718
  },
2203
3719
  step: { type: Number },
2204
3720
  largeStep: {
@@ -2241,7 +3757,7 @@ var TimeSliderElement = class extends MediaElement {
2241
3757
  const media = this.#timeState.value;
2242
3758
  if (media) media.seek(this.#core.rawValueFromPercent(percent));
2243
3759
  },
2244
- commitThrottle: this.commitThrottle,
3760
+ changeThrottle: this.changeThrottle,
2245
3761
  onDragStart: () => {
2246
3762
  this.dispatchEvent(new CustomEvent("drag-start", { bubbles: true }));
2247
3763
  },
@@ -2358,17 +3874,15 @@ var TooltipElement = class extends MediaElement {
2358
3874
  }
2359
3875
  #core = new TooltipCore();
2360
3876
  #groupConsumer = new ContextConsumer(this, { context: tooltipGroupContext });
3877
+ #position = new PositionController(this);
2361
3878
  #tooltip = null;
2362
3879
  #snapshot = null;
2363
3880
  #disconnect = null;
2364
3881
  #triggerAbort = null;
2365
3882
  #currentTrigger = null;
2366
- #positionAbort = null;
2367
- #positionFrame = 0;
2368
- #resizeObserver = null;
2369
- #positionTrigger = null;
2370
3883
  connectedCallback() {
2371
3884
  super.connectedCallback();
3885
+ if (this.destroyed) return;
2372
3886
  this.#disconnect = new AbortController();
2373
3887
  this.#tooltip = createTooltip({
2374
3888
  transition: createTransition(),
@@ -2396,7 +3910,6 @@ var TooltipElement = class extends MediaElement {
2396
3910
  }
2397
3911
  disconnectedCallback() {
2398
3912
  super.disconnectedCallback();
2399
- this.#cleanupPositioning();
2400
3913
  this.#cleanupTrigger();
2401
3914
  this.#tooltip?.destroy();
2402
3915
  this.#tooltip = null;
@@ -2415,7 +3928,7 @@ var TooltipElement = class extends MediaElement {
2415
3928
  update(_changed) {
2416
3929
  super.update(_changed);
2417
3930
  if (!this.#tooltip) return;
2418
- const triggerEl = this.#findTrigger();
3931
+ const triggerEl = this.#position.findTrigger();
2419
3932
  this.#syncTrigger(triggerEl);
2420
3933
  const input = this.#tooltip.input.current;
2421
3934
  this.#core.setInput(input);
@@ -2426,7 +3939,7 @@ var TooltipElement = class extends MediaElement {
2426
3939
  else tryHidePopover(this);
2427
3940
  if (this.#currentTrigger) applyStyles(this.#currentTrigger, getAnchorNameStyle(this.id));
2428
3941
  if (!state.open) {
2429
- this.#cleanupPositioning();
3942
+ this.#position.cleanup();
2430
3943
  return;
2431
3944
  }
2432
3945
  const posOpts = {
@@ -2441,15 +3954,11 @@ var TooltipElement = class extends MediaElement {
2441
3954
  const offsets = resolveOffsets(this, TooltipCSSVars);
2442
3955
  applyStyles(this, getAnchorPositionStyle(this.id, posOpts, triggerRect, selfRect, boundaryRect, offsets, TooltipCSSVars));
2443
3956
  }
2444
- this.#syncPositioning();
2445
- }
2446
- #findTrigger() {
2447
- if (!this.id) return null;
2448
- return this.getRootNode().querySelector(`[commandfor="${this.id}"]`);
3957
+ this.#position.sync(this.#currentTrigger);
2449
3958
  }
2450
3959
  #syncTrigger(triggerEl) {
2451
3960
  if (triggerEl === this.#currentTrigger) return;
2452
- this.#cleanupPositioning();
3961
+ this.#position.cleanup();
2453
3962
  this.#cleanupTrigger();
2454
3963
  this.#currentTrigger = triggerEl;
2455
3964
  this.#tooltip?.setTriggerElement(triggerEl);
@@ -2471,46 +3980,6 @@ var TooltipElement = class extends MediaElement {
2471
3980
  this.#triggerAbort = null;
2472
3981
  this.#currentTrigger = null;
2473
3982
  }
2474
- #syncPositioning() {
2475
- if (supportsAnchorPositioning()) return;
2476
- const triggerEl = this.#currentTrigger;
2477
- if (!triggerEl) return;
2478
- if (this.#positionAbort && this.#positionTrigger === triggerEl) return;
2479
- this.#cleanupPositioning();
2480
- this.#positionAbort = new AbortController();
2481
- this.#positionTrigger = triggerEl;
2482
- const { signal } = this.#positionAbort;
2483
- const reposition = () => {
2484
- cancelAnimationFrame(this.#positionFrame);
2485
- this.#positionFrame = requestAnimationFrame(() => {
2486
- if (signal.aborted) return;
2487
- this.requestUpdate();
2488
- });
2489
- };
2490
- window.addEventListener("scroll", reposition, {
2491
- capture: true,
2492
- passive: true,
2493
- signal
2494
- });
2495
- window.addEventListener("resize", reposition, { signal });
2496
- if (typeof ResizeObserver === "function") {
2497
- this.#resizeObserver = new ResizeObserver(() => {
2498
- reposition();
2499
- });
2500
- this.#resizeObserver.observe(triggerEl);
2501
- this.#resizeObserver.observe(this);
2502
- }
2503
- reposition();
2504
- }
2505
- #cleanupPositioning() {
2506
- this.#positionAbort?.abort();
2507
- this.#positionAbort = null;
2508
- this.#positionTrigger = null;
2509
- cancelAnimationFrame(this.#positionFrame);
2510
- this.#positionFrame = 0;
2511
- this.#resizeObserver?.disconnect();
2512
- this.#resizeObserver = null;
2513
- }
2514
3983
  };
2515
3984
 
2516
3985
  //#endregion
@@ -2685,5 +4154,5 @@ safeDefine(SliderTrackElement);
2685
4154
  safeDefine(SliderValueElement);
2686
4155
 
2687
4156
  //#endregion
2688
- export { PiPButtonDataAttrs as a, FullscreenButtonCore as c, CaptionsButtonDataAttrs as d, CaptionsButtonCore as f, PosterCore as i, ControlsDataAttrs as l, BufferingIndicatorCore as m, MediaButtonElement as n, PiPButtonCore as o, BufferingIndicatorDataAttrs as p, PosterDataAttrs as r, FullscreenButtonDataAttrs as s, ContextPartElement as t, ControlsCore as u };
2689
- //# sourceMappingURL=volume-slider-CxGbFVVX.js.map
4157
+ export { createHotkey as a, selectPiP as c, selectTextTrack as d, selectTime as f, logMissingFeature as i, selectPlayback as l, defaults as m, MediaButtonElement as n, selectControls as o, selectVolume as p, applyStateDataAttrs as r, selectFullscreen as s, ContextPartElement as t, selectPlaybackRate as u };
4158
+ //# sourceMappingURL=volume-slider-C6ek7oC9.js.map