@videojs/html 10.2.0 → 10.4.0

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 (374) hide show
  1. package/dist/default/define/audio/compat-skin.css +161 -41
  2. package/dist/default/define/audio/compat-skin2.js +1 -1
  3. package/dist/default/define/audio/neutral-skin.css +73 -34
  4. package/dist/default/define/audio/neutral-skin2.js +1 -1
  5. package/dist/default/define/audio/scaffold-skin.css +166 -42
  6. package/dist/default/define/audio/scaffold-skin2.js +1 -1
  7. package/dist/default/define/audio/skin.css +72 -34
  8. package/dist/default/define/audio/skin2.js +1 -1
  9. package/dist/default/define/extensions/google-analytics.js +6 -0
  10. package/dist/default/define/live-audio/compat-skin.css +143 -41
  11. package/dist/default/define/live-audio/compat-skin2.js +1 -1
  12. package/dist/default/define/live-audio/neutral-skin.css +56 -31
  13. package/dist/default/define/live-audio/neutral-skin2.js +1 -1
  14. package/dist/default/define/live-audio/scaffold-skin.css +148 -42
  15. package/dist/default/define/live-audio/scaffold-skin2.js +1 -1
  16. package/dist/default/define/live-audio/skin.css +55 -31
  17. package/dist/default/define/live-audio/skin2.js +1 -1
  18. package/dist/default/define/live-video/compat-skin.css +234 -51
  19. package/dist/default/define/live-video/compat-skin2.js +1 -1
  20. package/dist/default/define/live-video/neutral-skin.css +300 -46
  21. package/dist/default/define/live-video/neutral-skin2.js +1 -1
  22. package/dist/default/define/live-video/scaffold-skin.css +231 -53
  23. package/dist/default/define/live-video/scaffold-skin2.js +1 -1
  24. package/dist/default/define/live-video/skin.css +314 -49
  25. package/dist/default/define/live-video/skin2.js +1 -1
  26. package/dist/default/define/media/dailymotion-video.js +11 -0
  27. package/dist/default/define/media/mixcloud-audio.js +11 -0
  28. package/dist/default/define/media/soundcloud-audio.js +11 -0
  29. package/dist/default/define/ui/time-slider-markers.js +5 -0
  30. package/dist/default/define/video/compat-skin.css +242 -51
  31. package/dist/default/define/video/compat-skin2.js +1 -1
  32. package/dist/default/define/video/neutral-skin.css +382 -57
  33. package/dist/default/define/video/neutral-skin2.js +1 -1
  34. package/dist/default/define/video/scaffold-skin.css +240 -53
  35. package/dist/default/define/video/scaffold-skin2.js +1 -1
  36. package/dist/default/define/video/skin.css +415 -55
  37. package/dist/default/define/video/skin2.js +1 -1
  38. package/dist/default/extensions/google-analytics/extension.js +75 -0
  39. package/dist/default/extensions/mux-data/extension.js +7 -2
  40. package/dist/default/index.js +3 -1
  41. package/dist/default/internal/skins/compat-audio/skin.css +161 -41
  42. package/dist/default/internal/skins/compat-audio/template.js +1 -1
  43. package/dist/default/internal/skins/compat-live-audio/skin.css +143 -41
  44. package/dist/default/internal/skins/compat-live-video/skin.css +234 -51
  45. package/dist/default/internal/skins/compat-live-video/template.js +2 -0
  46. package/dist/default/internal/skins/compat-video/skin.css +242 -51
  47. package/dist/default/internal/skins/compat-video/template.js +2 -0
  48. package/dist/default/internal/skins/default-audio/skin.css +72 -34
  49. package/dist/default/internal/skins/default-live-audio/skin.css +55 -31
  50. package/dist/default/internal/skins/default-live-video/skin.css +314 -49
  51. package/dist/default/internal/skins/default-live-video/template.js +14 -0
  52. package/dist/default/internal/skins/default-video/register.js +3 -0
  53. package/dist/default/internal/skins/default-video/skin.css +415 -55
  54. package/dist/default/internal/skins/default-video/template.js +33 -5
  55. package/dist/default/internal/skins/neutral-audio/skin.css +73 -34
  56. package/dist/default/internal/skins/neutral-live-audio/skin.css +56 -31
  57. package/dist/default/internal/skins/neutral-live-video/skin.css +300 -46
  58. package/dist/default/internal/skins/neutral-live-video/template.js +14 -0
  59. package/dist/default/internal/skins/neutral-video/skin.css +382 -57
  60. package/dist/default/internal/skins/neutral-video/template.js +25 -11
  61. package/dist/default/internal/skins/scaffold-audio/skin.css +166 -42
  62. package/dist/default/internal/skins/scaffold-audio/template.js +1 -1
  63. package/dist/default/internal/skins/scaffold-live-audio/skin.css +148 -42
  64. package/dist/default/internal/skins/scaffold-live-video/skin.css +231 -53
  65. package/dist/default/internal/skins/scaffold-live-video/template.js +2 -0
  66. package/dist/default/internal/skins/scaffold-video/skin.css +240 -53
  67. package/dist/default/internal/skins/scaffold-video/template.js +3 -1
  68. package/dist/default/media/background-video/adapter.js +13 -35
  69. package/dist/default/media/background-video/base.js +95 -0
  70. package/dist/default/media/background-video/template.js +13 -20
  71. package/dist/default/media/dailymotion-video/adapter.js +31 -0
  72. package/dist/default/media/hls-background-video/adapter.js +23 -35
  73. package/dist/default/media/mixcloud-audio/adapter.js +16 -0
  74. package/dist/default/media/soundcloud-audio/adapter.js +16 -0
  75. package/dist/default/player/element.js +1 -5
  76. package/dist/default/presets/background/skin.js +2 -2
  77. package/dist/default/presets/skin.js +4 -3
  78. package/dist/default/ui/captions-radio-group/element.js +14 -1
  79. package/dist/default/ui/controls/element.js +6 -3
  80. package/dist/default/ui/dialog/element.js +13 -1
  81. package/dist/default/ui/gesture/element.js +3 -0
  82. package/dist/default/ui/media-button-element.js +10 -1
  83. package/dist/default/ui/playback-rate-button/element.js +7 -2
  84. package/dist/default/ui/playback-rate-radio-group/element.js +10 -3
  85. package/dist/default/ui/radio-options/controller.js +18 -5
  86. package/dist/default/ui/time-slider/markers.js +160 -0
  87. package/dist/default/version.js +1 -1
  88. package/dist/dev/define/audio/compat-skin.css +161 -41
  89. package/dist/dev/define/audio/compat-skin2.js +1 -1
  90. package/dist/dev/define/audio/compat-skin2.js.map +1 -1
  91. package/dist/dev/define/audio/neutral-skin.css +73 -34
  92. package/dist/dev/define/audio/neutral-skin2.js +1 -1
  93. package/dist/dev/define/audio/neutral-skin2.js.map +1 -1
  94. package/dist/dev/define/audio/scaffold-skin.css +166 -42
  95. package/dist/dev/define/audio/scaffold-skin2.js +1 -1
  96. package/dist/dev/define/audio/scaffold-skin2.js.map +1 -1
  97. package/dist/dev/define/audio/skin.css +72 -34
  98. package/dist/dev/define/audio/skin2.js +1 -1
  99. package/dist/dev/define/audio/skin2.js.map +1 -1
  100. package/dist/dev/define/extensions/google-analytics.d.ts +11 -0
  101. package/dist/dev/define/extensions/google-analytics.js +8 -0
  102. package/dist/dev/define/extensions/google-analytics.js.map +1 -0
  103. package/dist/dev/define/live-audio/compat-skin.css +143 -41
  104. package/dist/dev/define/live-audio/compat-skin2.js +1 -1
  105. package/dist/dev/define/live-audio/compat-skin2.js.map +1 -1
  106. package/dist/dev/define/live-audio/neutral-skin.css +56 -31
  107. package/dist/dev/define/live-audio/neutral-skin2.js +1 -1
  108. package/dist/dev/define/live-audio/neutral-skin2.js.map +1 -1
  109. package/dist/dev/define/live-audio/scaffold-skin.css +148 -42
  110. package/dist/dev/define/live-audio/scaffold-skin2.js +1 -1
  111. package/dist/dev/define/live-audio/scaffold-skin2.js.map +1 -1
  112. package/dist/dev/define/live-audio/skin.css +55 -31
  113. package/dist/dev/define/live-audio/skin2.js +1 -1
  114. package/dist/dev/define/live-audio/skin2.js.map +1 -1
  115. package/dist/dev/define/live-video/compat-skin.css +234 -51
  116. package/dist/dev/define/live-video/compat-skin2.js +1 -1
  117. package/dist/dev/define/live-video/compat-skin2.js.map +1 -1
  118. package/dist/dev/define/live-video/neutral-skin.css +300 -46
  119. package/dist/dev/define/live-video/neutral-skin2.js +1 -1
  120. package/dist/dev/define/live-video/neutral-skin2.js.map +1 -1
  121. package/dist/dev/define/live-video/scaffold-skin.css +231 -53
  122. package/dist/dev/define/live-video/scaffold-skin2.js +1 -1
  123. package/dist/dev/define/live-video/scaffold-skin2.js.map +1 -1
  124. package/dist/dev/define/live-video/skin.css +314 -49
  125. package/dist/dev/define/live-video/skin2.js +1 -1
  126. package/dist/dev/define/live-video/skin2.js.map +1 -1
  127. package/dist/dev/define/media/dailymotion-video.d.ts +15 -0
  128. package/dist/dev/define/media/dailymotion-video.js +13 -0
  129. package/dist/dev/define/media/dailymotion-video.js.map +1 -0
  130. package/dist/dev/define/media/mixcloud-audio.d.ts +15 -0
  131. package/dist/dev/define/media/mixcloud-audio.js +13 -0
  132. package/dist/dev/define/media/mixcloud-audio.js.map +1 -0
  133. package/dist/dev/define/media/soundcloud-audio.d.ts +15 -0
  134. package/dist/dev/define/media/soundcloud-audio.js +13 -0
  135. package/dist/dev/define/media/soundcloud-audio.js.map +1 -0
  136. package/dist/dev/define/ui/time-slider-markers.d.ts +8 -0
  137. package/dist/dev/define/ui/time-slider-markers.js +7 -0
  138. package/dist/dev/define/ui/time-slider-markers.js.map +1 -0
  139. package/dist/dev/define/video/compat-skin.css +242 -51
  140. package/dist/dev/define/video/compat-skin2.js +1 -1
  141. package/dist/dev/define/video/compat-skin2.js.map +1 -1
  142. package/dist/dev/define/video/neutral-skin.css +382 -57
  143. package/dist/dev/define/video/neutral-skin2.js +1 -1
  144. package/dist/dev/define/video/neutral-skin2.js.map +1 -1
  145. package/dist/dev/define/video/scaffold-skin.css +240 -53
  146. package/dist/dev/define/video/scaffold-skin2.js +1 -1
  147. package/dist/dev/define/video/scaffold-skin2.js.map +1 -1
  148. package/dist/dev/define/video/skin.css +415 -55
  149. package/dist/dev/define/video/skin2.js +1 -1
  150. package/dist/dev/define/video/skin2.js.map +1 -1
  151. package/dist/dev/extensions/google-analytics/extension.d.ts +52 -0
  152. package/dist/dev/extensions/google-analytics/extension.js +77 -0
  153. package/dist/dev/extensions/google-analytics/extension.js.map +1 -0
  154. package/dist/dev/extensions/google-analytics/index.d.ts +2 -0
  155. package/dist/dev/extensions/mux-data/extension.d.ts +4 -1
  156. package/dist/dev/extensions/mux-data/extension.js +7 -2
  157. package/dist/dev/extensions/mux-data/extension.js.map +1 -1
  158. package/dist/dev/index.d.ts +5 -4
  159. package/dist/dev/index.js +3 -1
  160. package/dist/dev/internal/skins/compat-audio/skin.css +161 -41
  161. package/dist/dev/internal/skins/compat-audio/template.js +1 -1
  162. package/dist/dev/internal/skins/compat-audio/template.js.map +1 -1
  163. package/dist/dev/internal/skins/compat-live-audio/skin.css +143 -41
  164. package/dist/dev/internal/skins/compat-live-video/skin.css +234 -51
  165. package/dist/dev/internal/skins/compat-live-video/template.js +2 -0
  166. package/dist/dev/internal/skins/compat-live-video/template.js.map +1 -1
  167. package/dist/dev/internal/skins/compat-video/skin.css +242 -51
  168. package/dist/dev/internal/skins/compat-video/template.js +2 -0
  169. package/dist/dev/internal/skins/compat-video/template.js.map +1 -1
  170. package/dist/dev/internal/skins/default-audio/skin.css +72 -34
  171. package/dist/dev/internal/skins/default-live-audio/skin.css +55 -31
  172. package/dist/dev/internal/skins/default-live-video/register.js.map +1 -1
  173. package/dist/dev/internal/skins/default-live-video/skin.css +314 -49
  174. package/dist/dev/internal/skins/default-live-video/template.js +14 -0
  175. package/dist/dev/internal/skins/default-live-video/template.js.map +1 -1
  176. package/dist/dev/internal/skins/default-video/register.d.ts +1 -0
  177. package/dist/dev/internal/skins/default-video/register.js +3 -0
  178. package/dist/dev/internal/skins/default-video/register.js.map +1 -1
  179. package/dist/dev/internal/skins/default-video/skin.css +415 -55
  180. package/dist/dev/internal/skins/default-video/template.js +33 -5
  181. package/dist/dev/internal/skins/default-video/template.js.map +1 -1
  182. package/dist/dev/internal/skins/neutral-audio/skin.css +73 -34
  183. package/dist/dev/internal/skins/neutral-live-audio/skin.css +56 -31
  184. package/dist/dev/internal/skins/neutral-live-video/register.js.map +1 -1
  185. package/dist/dev/internal/skins/neutral-live-video/skin.css +300 -46
  186. package/dist/dev/internal/skins/neutral-live-video/template.js +14 -0
  187. package/dist/dev/internal/skins/neutral-live-video/template.js.map +1 -1
  188. package/dist/dev/internal/skins/neutral-video/register.js.map +1 -1
  189. package/dist/dev/internal/skins/neutral-video/skin.css +382 -57
  190. package/dist/dev/internal/skins/neutral-video/template.js +25 -11
  191. package/dist/dev/internal/skins/neutral-video/template.js.map +1 -1
  192. package/dist/dev/internal/skins/scaffold-audio/skin.css +166 -42
  193. package/dist/dev/internal/skins/scaffold-audio/template.js +1 -1
  194. package/dist/dev/internal/skins/scaffold-audio/template.js.map +1 -1
  195. package/dist/dev/internal/skins/scaffold-live-audio/skin.css +148 -42
  196. package/dist/dev/internal/skins/scaffold-live-video/skin.css +231 -53
  197. package/dist/dev/internal/skins/scaffold-live-video/template.js +2 -0
  198. package/dist/dev/internal/skins/scaffold-live-video/template.js.map +1 -1
  199. package/dist/dev/internal/skins/scaffold-video/skin.css +240 -53
  200. package/dist/dev/internal/skins/scaffold-video/template.js +3 -1
  201. package/dist/dev/internal/skins/scaffold-video/template.js.map +1 -1
  202. package/dist/dev/media/background-video/adapter.d.ts +7 -13
  203. package/dist/dev/media/background-video/adapter.js +13 -35
  204. package/dist/dev/media/background-video/adapter.js.map +1 -1
  205. package/dist/dev/media/background-video/base.d.ts +44 -0
  206. package/dist/dev/media/background-video/base.js +97 -0
  207. package/dist/dev/media/background-video/base.js.map +1 -0
  208. package/dist/dev/media/background-video/template.d.ts +3 -0
  209. package/dist/dev/media/background-video/template.js +13 -20
  210. package/dist/dev/media/background-video/template.js.map +1 -1
  211. package/dist/dev/media/dailymotion-video/adapter.d.ts +17 -0
  212. package/dist/dev/media/dailymotion-video/adapter.js +47 -0
  213. package/dist/dev/media/dailymotion-video/adapter.js.map +1 -0
  214. package/dist/dev/media/dailymotion-video/index.d.ts +2 -0
  215. package/dist/dev/media/hls-background-video/adapter.d.ts +14 -19
  216. package/dist/dev/media/hls-background-video/adapter.js +23 -35
  217. package/dist/dev/media/hls-background-video/adapter.js.map +1 -1
  218. package/dist/dev/media/mixcloud-audio/adapter.d.ts +11 -0
  219. package/dist/dev/media/mixcloud-audio/adapter.js +52 -0
  220. package/dist/dev/media/mixcloud-audio/adapter.js.map +1 -0
  221. package/dist/dev/media/mixcloud-audio/index.d.ts +2 -0
  222. package/dist/dev/media/soundcloud-audio/adapter.d.ts +11 -0
  223. package/dist/dev/media/soundcloud-audio/adapter.js +53 -0
  224. package/dist/dev/media/soundcloud-audio/adapter.js.map +1 -0
  225. package/dist/dev/media/soundcloud-audio/index.d.ts +2 -0
  226. package/dist/dev/player/element.js +1 -5
  227. package/dist/dev/player/element.js.map +1 -1
  228. package/dist/dev/presets/background/skin.d.ts +2 -1
  229. package/dist/dev/presets/background/skin.js +2 -2
  230. package/dist/dev/presets/background/skin.js.map +1 -1
  231. package/dist/dev/presets/skin.d.ts +4 -3
  232. package/dist/dev/presets/skin.js +4 -3
  233. package/dist/dev/presets/skin.js.map +1 -1
  234. package/dist/dev/ui/captions-button/element.d.ts +2 -0
  235. package/dist/dev/ui/captions-radio-group/element.d.ts +2 -1
  236. package/dist/dev/ui/captions-radio-group/element.js +14 -1
  237. package/dist/dev/ui/captions-radio-group/element.js.map +1 -1
  238. package/dist/dev/ui/controls/element.d.ts +2 -2
  239. package/dist/dev/ui/controls/element.js +6 -3
  240. package/dist/dev/ui/controls/element.js.map +1 -1
  241. package/dist/dev/ui/dialog/element.js +13 -1
  242. package/dist/dev/ui/dialog/element.js.map +1 -1
  243. package/dist/dev/ui/gesture/element.js +3 -0
  244. package/dist/dev/ui/gesture/element.js.map +1 -1
  245. package/dist/dev/ui/media-button-element.d.ts +9 -0
  246. package/dist/dev/ui/media-button-element.js +10 -1
  247. package/dist/dev/ui/media-button-element.js.map +1 -1
  248. package/dist/dev/ui/play-button/element.d.ts +2 -0
  249. package/dist/dev/ui/playback-rate-button/element.d.ts +9 -1
  250. package/dist/dev/ui/playback-rate-button/element.js +7 -2
  251. package/dist/dev/ui/playback-rate-button/element.js.map +1 -1
  252. package/dist/dev/ui/playback-rate-radio-group/element.d.ts +4 -0
  253. package/dist/dev/ui/playback-rate-radio-group/element.js +10 -3
  254. package/dist/dev/ui/playback-rate-radio-group/element.js.map +1 -1
  255. package/dist/dev/ui/radio-options/controller.js +18 -5
  256. package/dist/dev/ui/radio-options/controller.js.map +1 -1
  257. package/dist/dev/ui/time-slider/markers.d.ts +48 -0
  258. package/dist/dev/ui/time-slider/markers.js +165 -0
  259. package/dist/dev/ui/time-slider/markers.js.map +1 -0
  260. package/dist/dev/version.js +1 -1
  261. package/docs/README.md +1 -1
  262. package/docs/guides/autoplay.md +2 -2
  263. package/docs/guides/background-video.md +2 -4
  264. package/docs/guides/browser-support.md +23 -15
  265. package/docs/guides/build-your-own-skin.md +3 -1
  266. package/docs/guides/cdn.md +10 -9
  267. package/docs/guides/content-security-policy.md +3 -0
  268. package/docs/guides/customize-skins.md +7 -2
  269. package/docs/guides/features.md +1 -1
  270. package/docs/guides/google-analytics.md +199 -0
  271. package/docs/guides/installation-cdn.md +4 -4
  272. package/docs/guides/installation-shadcn.md +3 -3
  273. package/docs/guides/installation-svelte.md +4 -4
  274. package/docs/guides/installation-vue.md +4 -4
  275. package/docs/guides/installation.md +4 -4
  276. package/docs/guides/internationalization.md +5 -5
  277. package/docs/guides/keyboard-shortcuts.md +11 -1
  278. package/docs/guides/llms.txt +3 -1
  279. package/docs/guides/media-sources.md +3 -0
  280. package/docs/guides/migrate-from-media-chrome.md +4 -4
  281. package/docs/guides/migrate-from-mux-player.md +9 -9
  282. package/docs/guides/migrate-from-plyr.md +8 -8
  283. package/docs/guides/migrate-from-video-js-8.md +8 -9
  284. package/docs/guides/migrate-from-vidstack.md +10 -10
  285. package/docs/guides/mux-data.md +22 -0
  286. package/docs/guides/presets.md +5 -5
  287. package/docs/guides/self-hosting.md +5 -5
  288. package/docs/guides/skins.md +21 -5
  289. package/docs/guides/timed-metadata.md +318 -0
  290. package/docs/guides/ui-components.md +1 -1
  291. package/docs/llms.txt +25 -6
  292. package/docs/reference/api/chapters-track.md +71 -0
  293. package/docs/reference/api/define-text-track.md +113 -0
  294. package/docs/reference/api/feature-playback-rate.md +54 -3
  295. package/docs/reference/api/feature-playback.md +5 -1
  296. package/docs/reference/api/feature-text-cues.md +133 -0
  297. package/docs/reference/api/feature-text-tracks.md +11 -5
  298. package/docs/reference/api/get-active-text-cues.md +69 -0
  299. package/docs/reference/api/get-text-cues.md +69 -0
  300. package/docs/reference/api/get-text-tracks.md +41 -0
  301. package/docs/reference/api/hls-metadata-track.md +48 -0
  302. package/docs/reference/api/html-create-player.md +2 -2
  303. package/docs/reference/api/llms.txt +13 -1
  304. package/docs/reference/api/media-capabilities.md +4 -4
  305. package/docs/reference/api/player-store.md +15 -7
  306. package/docs/reference/api/preset-audio.md +15 -5
  307. package/docs/reference/api/preset-background.md +2 -2
  308. package/docs/reference/api/preset-live-audio.md +15 -5
  309. package/docs/reference/api/preset-live-video.md +14 -5
  310. package/docs/reference/api/preset-video.md +14 -5
  311. package/docs/reference/api/resolve-adapter-type.md +4 -1
  312. package/docs/reference/api/ui-element.md +2 -2
  313. package/docs/reference/components/alert-dialog.md +21 -16
  314. package/docs/reference/components/audio-compat-skin.md +8 -2
  315. package/docs/reference/components/audio-neutral-skin.md +2 -2
  316. package/docs/reference/components/audio-scaffold-skin.md +2 -2
  317. package/docs/reference/components/audio-skin.md +2 -2
  318. package/docs/reference/components/audio-track-radio-group.md +2 -2
  319. package/docs/reference/components/audio.md +19 -1
  320. package/docs/reference/components/background-video-skin.md +1 -1
  321. package/docs/reference/components/background-video.md +26 -11
  322. package/docs/reference/components/buffering-indicator.md +2 -2
  323. package/docs/reference/components/captions-radio-group.md +3 -3
  324. package/docs/reference/components/cloudflare-video.md +1 -1
  325. package/docs/reference/components/controls.md +16 -3
  326. package/docs/reference/components/dailymotion-video.md +192 -0
  327. package/docs/reference/components/dash-video.md +20 -2
  328. package/docs/reference/components/dialog.md +49 -22
  329. package/docs/reference/components/error-dialog.md +13 -10
  330. package/docs/reference/components/gesture.md +2 -2
  331. package/docs/reference/components/google-analytics.md +51 -0
  332. package/docs/reference/components/google-cast.md +1 -1
  333. package/docs/reference/components/hls-audio.md +56 -2
  334. package/docs/reference/components/hls-background-video.md +25 -5
  335. package/docs/reference/components/hls-video.md +99 -7
  336. package/docs/reference/components/hlsjs-video.md +53 -12
  337. package/docs/reference/components/hotkey.md +2 -2
  338. package/docs/reference/components/live-audio-compat-skin.md +8 -2
  339. package/docs/reference/components/live-audio-neutral-skin.md +2 -2
  340. package/docs/reference/components/live-audio-scaffold-skin.md +2 -2
  341. package/docs/reference/components/live-audio-skin.md +2 -2
  342. package/docs/reference/components/live-video-compat-skin.md +12 -2
  343. package/docs/reference/components/live-video-neutral-skin.md +6 -2
  344. package/docs/reference/components/live-video-scaffold-skin.md +6 -2
  345. package/docs/reference/components/live-video-skin.md +6 -2
  346. package/docs/reference/components/llms.txt +10 -5
  347. package/docs/reference/components/mixcloud-audio.md +203 -0
  348. package/docs/reference/components/mux-audio.md +35 -2
  349. package/docs/reference/components/mux-background-video.md +1 -1
  350. package/docs/reference/components/mux-data.md +20 -2
  351. package/docs/reference/components/mux-video.md +18 -2
  352. package/docs/reference/components/native-hls-video.md +32 -2
  353. package/docs/reference/components/play-button.md +7 -5
  354. package/docs/reference/components/playback-rate-button.md +26 -7
  355. package/docs/reference/components/playback-rate-radio-group.md +7 -4
  356. package/docs/reference/components/player.md +3 -3
  357. package/docs/reference/components/playerjs-video.md +2 -2
  358. package/docs/reference/components/quality-radio-group.md +2 -2
  359. package/docs/reference/components/shaka-video.md +2 -2
  360. package/docs/reference/components/soundcloud-audio.md +227 -0
  361. package/docs/reference/components/spotify-audio.md +3 -3
  362. package/docs/reference/components/tiktok-video.md +3 -3
  363. package/docs/reference/components/time-slider-markers.md +194 -0
  364. package/docs/reference/components/time-slider.md +14 -0
  365. package/docs/reference/components/twitch-video.md +2 -3
  366. package/docs/reference/components/video-compat-skin.md +12 -2
  367. package/docs/reference/components/video-neutral-skin.md +6 -2
  368. package/docs/reference/components/video-scaffold-skin.md +6 -2
  369. package/docs/reference/components/video-skin.md +6 -2
  370. package/docs/reference/components/video.md +19 -1
  371. package/docs/reference/components/vimeo-video.md +1 -1
  372. package/docs/reference/components/wistia-video.md +1 -1
  373. package/docs/reference/components/youtube-video.md +1 -1
  374. package/package.json +60 -40
@@ -1,10 +1,6 @@
1
- import { MediaAttachMixin } from "../../store/media-attach-mixin.js";
2
- import { getTemplateHTML } from "../background-video/template.js";
3
- import { namedNodeMapToObject } from "@videojs/utils/dom";
1
+ import { BackgroundVideoBase } from "../background-video/base.js";
4
2
  import { HlsBackgroundVideoAdapter } from "@videojs/spf/adapters/hls-background-video";
5
3
  //#region src/media/hls-background-video/adapter.ts
6
- const HTMLElementBase = globalThis.HTMLElement ?? class {};
7
- const HlsBackgroundVideoBase = MediaAttachMixin(HTMLElementBase);
8
4
  /**
9
5
  * A muted, looping, chrome-less video over the SPF background-video engine.
10
6
  *
@@ -16,8 +12,9 @@ const HlsBackgroundVideoBase = MediaAttachMixin(HTMLElementBase);
16
12
  * package, whose `audio`, `debug`, `preload`, and `max-resolution` attributes are all deliberately absent. Capping
17
13
  * which rendition is fetched is a delivery param on the URL — `?max_resolution=720p` on a Mux stream, for one — which
18
14
  * keeps the renditions it excludes out of the manifest rather than merely unpicked; `preload` would have nothing to
19
- * say, since the engine loads from the moment it has a source. And unlike `<background-video>` there are no `nomuted` /
20
- * `noloop` / `noautoplay` opt-outs: those three are what this element is for, so the adapter fixes them on at attach.
15
+ * say, since the engine loads from the moment it has a source. Muted is fixed on: the engine drops audio, so there is
16
+ * nothing to unmute. `noloop` and `noautoplay` opt out as on `<background-video>`, so a page can play the video once,
17
+ * or hold it until it has checked the motion preference.
21
18
  *
22
19
  * Takes no structured `source` — `src` is an HLS URL, as the package it replaces required. Mux playback-ID identity,
23
20
  * poster, and storyboard belong to `<mux-video>`; none of them mean anything without controls to hang them on.
@@ -39,40 +36,36 @@ const HlsBackgroundVideoBase = MediaAttachMixin(HTMLElementBase);
39
36
  * `<mux-background-video>` is this element under the name the package it replaces used. Same class, so the tag is a
40
37
  * naming choice and nothing more.
41
38
  */
42
- var HlsBackgroundVideo = class extends HlsBackgroundVideoBase {
39
+ var HlsBackgroundVideo = class extends BackgroundVideoBase {
43
40
  static {
44
- this.shadowRootOptions = { mode: "open" };
41
+ this.optOuts = ["loop", "autoplay"];
45
42
  }
46
43
  static {
47
- this.getTemplateHTML = getTemplateHTML;
48
- }
49
- static get observedAttributes() {
50
- return ["src"];
44
+ this.passthroughAttributes = [
45
+ "controls",
46
+ "controlslist",
47
+ "crossorigin"
48
+ ];
51
49
  }
52
50
  #media = new HlsBackgroundVideoAdapter();
53
51
  constructor() {
54
52
  super();
55
- if (!this.shadowRoot) {
56
- this.attachShadow(this.constructor.shadowRootOptions);
57
- const attrs = {
58
- ...namedNodeMapToObject(this.attributes),
59
- muted: "",
60
- loop: "",
61
- autoplay: "",
62
- playsinline: "",
63
- disableremoteplayback: "",
64
- disablepictureinpicture: ""
65
- };
66
- this.shadowRoot.innerHTML = getTemplateHTML(attrs);
67
- }
68
- const video = this.video;
69
- if (video) this.#media.attach(video);
53
+ const target = this.target;
54
+ if (target) this.#media.attach(target);
55
+ this.syncPlaybackDefaults();
70
56
  this.#media.addEventListener("error", () => this.dispatchEvent(new Event("error")));
71
57
  }
72
58
  /** Register the Media (not the inner `<video>`) with the provider. */
73
59
  getMediaTarget() {
74
60
  return this.#media;
75
61
  }
62
+ /**
63
+ * The Media driving the inner `<video>`, matching `adapter` on `CustomMediaElement`. Call `adapter.destroy()` to
64
+ * release the engine after `keep-alive` kept it running past removal.
65
+ */
66
+ get adapter() {
67
+ return this.#media;
68
+ }
76
69
  disconnectedCallback() {
77
70
  super.disconnectedCallback?.();
78
71
  if (this.hasAttribute("keep-alive")) return;
@@ -80,14 +73,9 @@ var HlsBackgroundVideo = class extends HlsBackgroundVideoBase {
80
73
  if (!this.isConnected) this.#media.destroy();
81
74
  });
82
75
  }
83
- attributeChangedCallback(name, oldValue, newValue) {
84
- if (oldValue === newValue) return;
85
- if (name === "src") this.src = newValue ?? "";
86
- }
87
- /** The inner `<video>` the engine renders into. */
76
+ /** Same element as `target`. */
88
77
  get video() {
89
- const video = this.shadowRoot?.querySelector("video");
90
- return video instanceof HTMLVideoElement ? video : null;
78
+ return this.target;
91
79
  }
92
80
  /**
93
81
  * What made the current source unplayable, or `null`. An SVTA code rather than a `MediaError` one — 99001 where this
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.js","names":[],"sources":["../../../../src/media/hls-background-video/adapter.ts"],"sourcesContent":["import type { Media } from '@videojs/media/dom';\nimport { HlsBackgroundVideoAdapter, type HlsVideoMediaError } from '@videojs/spf/adapters/hls-background-video';\nimport { namedNodeMapToObject } from '@videojs/utils/dom';\n\nimport { MediaAttachMixin } from '../../store/media-attach-mixin';\nimport { getTemplateHTML } from '../background-video/template';\n\nconst HTMLElementBase = globalThis.HTMLElement ?? class {};\n\n// `MediaAttachMixin` is typed as returning its base, so its `disconnectedCallback`\n// isn't visible for `super` to reach. `LifecycleElement` declares the lifecycle\n// callbacks this element overrides; method syntax lets a subclass override them.\ninterface LifecycleElement extends HTMLElement {\n connectedCallback?(): void;\n disconnectedCallback?(): void;\n adoptedCallback?(): void;\n attributeChangedCallback?(name: string, oldValue: string | null, newValue: string | null): void;\n}\n\nconst HlsBackgroundVideoBase = MediaAttachMixin(HTMLElementBase) as unknown as new () => LifecycleElement;\n\n/**\n * A muted, looping, chrome-less video over the SPF background-video engine.\n *\n * The SPF-backed counterpart to `<background-video>`, which plays its source natively. This one streams HLS through the\n * engine, which pins a single rendition for the session rather than adapting, and drops audio and text handling\n * entirely — the shape an ambient hero video actually wants.\n *\n * Nearer an image than a player, and `src` is the whole surface. Replaces the standalone `mux-background-video`\n * package, whose `audio`, `debug`, `preload`, and `max-resolution` attributes are all deliberately absent. Capping\n * which rendition is fetched is a delivery param on the URL — `?max_resolution=720p` on a Mux stream, for one — which\n * keeps the renditions it excludes out of the manifest rather than merely unpicked; `preload` would have nothing to\n * say, since the engine loads from the moment it has a source. And unlike `<background-video>` there are no `nomuted` /\n * `noloop` / `noautoplay` opt-outs: those three are what this element is for, so the adapter fixes them on at attach.\n *\n * Takes no structured `source` — `src` is an HLS URL, as the package it replaces required. Mux playback-ID identity,\n * poster, and storyboard belong to `<mux-video>`; none of them mean anything without controls to hang them on.\n *\n * Nothing about an unplayable source reaches the inner `<video>` on its own, so `error` on it stays null and the\n * element sits at `readyState 0`. The engine reports each condition and logs it, the Media promotes the fatal one, and\n * this element re-fires it as its own `error` / `'error'` — the one place a consumer holding the element can see a\n * source that never appears.\n *\n * @example\n * ```html\n * <hls-background-video src=\"https://stream.mux.com/PLAYBACK_ID.m3u8?max_resolution=720p\">\n * <img src=\"https://image.mux.com/PLAYBACK_ID/thumbnail.webp?time=0\" alt=\"\" />\n * </hls-background-video>\n * ```;\n *\n * @fires error - Fired when a fatal condition is reported. Read `error` for it.\n *\n * `<mux-background-video>` is this element under the name the package it replaces used. Same class, so the tag is a\n * naming choice and nothing more.\n */\n// Deliberately not `CustomMediaElement`, matching `<background-video>`: a\n// background video needs one property, not the full WHATWG media API.\nexport class HlsBackgroundVideo extends HlsBackgroundVideoBase {\n static shadowRootOptions = { mode: 'open' as ShadowRootMode };\n static getTemplateHTML = getTemplateHTML;\n\n static get observedAttributes(): string[] {\n return ['src'];\n }\n\n #media = new HlsBackgroundVideoAdapter();\n\n constructor() {\n super();\n\n if (!this.shadowRoot) {\n this.attachShadow((this.constructor as typeof HlsBackgroundVideo).shadowRootOptions);\n\n const attrs = {\n ...namedNodeMapToObject(this.attributes),\n muted: '',\n loop: '',\n autoplay: '',\n playsinline: '',\n disableremoteplayback: '',\n disablepictureinpicture: '',\n };\n\n this.shadowRoot!.innerHTML = getTemplateHTML(attrs);\n }\n\n // Neither Chrome nor Firefox honor a `muted` attribute set after\n // `document.createElement`, and autoplay is refused without it. Attaching is\n // what sets the property — along with the rest of the fixed behavior — so\n // nothing here needs to repeat it.\n const video = this.video;\n\n if (video) this.#media.attach(video);\n\n // Re-fired rather than bridged on demand the way `CustomMediaElement` does\n // it: one listener for the one event this element has, on a Media it owns\n // for its whole life, is less than the machinery to defer it would cost.\n this.#media.addEventListener('error', () => this.dispatchEvent(new Event('error')));\n }\n\n /** Register the Media (not the inner `<video>`) with the provider. */\n getMediaTarget(): Media | null {\n return this.#media as unknown as Media;\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback?.();\n\n if (this.hasAttribute('keep-alive')) return;\n\n // Deferred so a synchronous reparent (remove then insert) doesn't tear down\n // the engine, matching `CustomMediaElement`.\n queueMicrotask(() => {\n if (!this.isConnected) this.#media.destroy();\n });\n }\n\n attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null): void {\n if (oldValue === newValue) return;\n\n if (name === 'src') this.src = newValue ?? '';\n }\n\n /** The inner `<video>` the engine renders into. */\n get video(): HTMLVideoElement | null {\n const video = this.shadowRoot?.querySelector('video');\n\n return video instanceof HTMLVideoElement ? video : null;\n }\n\n /**\n * What made the current source unplayable, or `null`. An SVTA code rather than a `MediaError` one — 99001 where this\n * player has no pipeline for what the source needs, with the specifics logged. Reset by a new source, and not on the\n * inner `<video>`, which never learns of it.\n */\n get error(): HlsVideoMediaError | null {\n return this.#media.error;\n }\n\n /** HLS manifest URL. Assigning a new one restarts playback from scratch. */\n get src(): string {\n return this.#media.src;\n }\n\n set src(value: string) {\n this.#media.src = value;\n }\n}\n"],"mappings":";;;;;AAOA,MAAM,kBAAkB,WAAW,eAAe,MAAM,CAAC;AAYzD,MAAM,yBAAyB,iBAAiB,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsC/D,IAAa,qBAAb,cAAwC,uBAAuB;;EAClC,KAAA,oBAAA,EAAE,MAAM,OAAyB;;;EACnC,KAAA,kBAAA;;CAEzB,WAAW,qBAA+B;EACxC,OAAO,CAAC,KAAK;CACf;CAEA,SAAS,IAAI,0BAA0B;CAEvC,cAAc;EACZ,MAAM;EAEN,IAAI,CAAC,KAAK,YAAY;GACpB,KAAK,aAAc,KAAK,YAA0C,iBAAiB;GAEnF,MAAM,QAAQ;IACZ,GAAG,qBAAqB,KAAK,UAAU;IACvC,OAAO;IACP,MAAM;IACN,UAAU;IACV,aAAa;IACb,uBAAuB;IACvB,yBAAyB;GAC3B;GAEA,KAAK,WAAY,YAAY,gBAAgB,KAAK;EACpD;EAMA,MAAM,QAAQ,KAAK;EAEnB,IAAI,OAAO,KAAK,OAAO,OAAO,KAAK;EAKnC,KAAK,OAAO,iBAAiB,eAAe,KAAK,cAAc,IAAI,MAAM,OAAO,CAAC,CAAC;CACpF;;CAGA,iBAA+B;EAC7B,OAAO,KAAK;CACd;CAEA,uBAAsC;EACpC,MAAM,uBAAuB;EAE7B,IAAI,KAAK,aAAa,YAAY,GAAG;EAIrC,qBAAqB;GACnB,IAAI,CAAC,KAAK,aAAa,KAAK,OAAO,QAAQ;EAC7C,CAAC;CACH;CAEA,yBAAyB,MAAc,UAAyB,UAA+B;EAC7F,IAAI,aAAa,UAAU;EAE3B,IAAI,SAAS,OAAO,KAAK,MAAM,YAAY;CAC7C;;CAGA,IAAI,QAAiC;EACnC,MAAM,QAAQ,KAAK,YAAY,cAAc,OAAO;EAEpD,OAAO,iBAAiB,mBAAmB,QAAQ;CACrD;;;;;;CAOA,IAAI,QAAmC;EACrC,OAAO,KAAK,OAAO;CACrB;;CAGA,IAAI,MAAc;EAChB,OAAO,KAAK,OAAO;CACrB;CAEA,IAAI,IAAI,OAAe;EACrB,KAAK,OAAO,MAAM;CACpB;AACF"}
1
+ {"version":3,"file":"adapter.js","names":[],"sources":["../../../../src/media/hls-background-video/adapter.ts"],"sourcesContent":["import type { Media } from '@videojs/media/dom';\nimport { HlsBackgroundVideoAdapter, type HlsVideoMediaError } from '@videojs/spf/adapters/hls-background-video';\n\nimport { BackgroundVideoBase, type BackgroundVideoOptOut } from '../background-video/base';\n\n/**\n * A muted, looping, chrome-less video over the SPF background-video engine.\n *\n * The SPF-backed counterpart to `<background-video>`, which plays its source natively. This one streams HLS through the\n * engine, which pins a single rendition for the session rather than adapting, and drops audio and text handling\n * entirely — the shape an ambient hero video actually wants.\n *\n * Nearer an image than a player, and `src` is the whole surface. Replaces the standalone `mux-background-video`\n * package, whose `audio`, `debug`, `preload`, and `max-resolution` attributes are all deliberately absent. Capping\n * which rendition is fetched is a delivery param on the URL — `?max_resolution=720p` on a Mux stream, for one — which\n * keeps the renditions it excludes out of the manifest rather than merely unpicked; `preload` would have nothing to\n * say, since the engine loads from the moment it has a source. Muted is fixed on: the engine drops audio, so there is\n * nothing to unmute. `noloop` and `noautoplay` opt out as on `<background-video>`, so a page can play the video once,\n * or hold it until it has checked the motion preference.\n *\n * Takes no structured `source` — `src` is an HLS URL, as the package it replaces required. Mux playback-ID identity,\n * poster, and storyboard belong to `<mux-video>`; none of them mean anything without controls to hang them on.\n *\n * Nothing about an unplayable source reaches the inner `<video>` on its own, so `error` on it stays null and the\n * element sits at `readyState 0`. The engine reports each condition and logs it, the Media promotes the fatal one, and\n * this element re-fires it as its own `error` / `'error'` — the one place a consumer holding the element can see a\n * source that never appears.\n *\n * @example\n * ```html\n * <hls-background-video src=\"https://stream.mux.com/PLAYBACK_ID.m3u8?max_resolution=720p\">\n * <img src=\"https://image.mux.com/PLAYBACK_ID/thumbnail.webp?time=0\" alt=\"\" />\n * </hls-background-video>\n * ```;\n *\n * @fires error - Fired when a fatal condition is reported. Read `error` for it.\n *\n * `<mux-background-video>` is this element under the name the package it replaces used. Same class, so the tag is a\n * naming choice and nothing more.\n */\n// Deliberately not `CustomMediaElement`, matching `<background-video>`: a\n// background video needs one property, not the full WHATWG media API.\nexport class HlsBackgroundVideo extends BackgroundVideoBase {\n static override optOuts: readonly BackgroundVideoOptOut[] = ['loop', 'autoplay'];\n // No `preload`: the engine loads as soon as it has a source, and attaching fixes `preload=\"auto\"`.\n static override passthroughAttributes: readonly string[] = ['controls', 'controlslist', 'crossorigin'];\n\n #media = new HlsBackgroundVideoAdapter();\n\n constructor() {\n super();\n\n const target = this.target;\n\n if (target) this.#media.attach(target);\n\n // Attaching fixes loop and autoplay on, so their opt-outs have to be reapplied after it.\n this.syncPlaybackDefaults();\n\n // Re-fired rather than bridged on demand the way `CustomMediaElement` does\n // it: one listener for the one event this element has, on a Media it owns\n // for its whole life, is less than the machinery to defer it would cost.\n this.#media.addEventListener('error', () => this.dispatchEvent(new Event('error')));\n }\n\n /** Register the Media (not the inner `<video>`) with the provider. */\n getMediaTarget(): Media | null {\n return this.#media as unknown as Media;\n }\n\n /**\n * The Media driving the inner `<video>`, matching `adapter` on `CustomMediaElement`. Call `adapter.destroy()` to\n * release the engine after `keep-alive` kept it running past removal.\n */\n get adapter(): HlsBackgroundVideoAdapter {\n return this.#media;\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback?.();\n\n // Only the element's own `keep-alive` counts: an ancestor's `destroy()` can't reach this engine, so inheriting it\n // would leave the engine running with nothing to release it.\n if (this.hasAttribute('keep-alive')) return;\n\n // Deferred so a synchronous reparent (remove then insert) doesn't tear down\n // the engine, matching `CustomMediaElement`.\n queueMicrotask(() => {\n if (!this.isConnected) this.#media.destroy();\n });\n }\n\n /** Same element as `target`. */\n get video(): HTMLVideoElement | null {\n return this.target;\n }\n\n /**\n * What made the current source unplayable, or `null`. An SVTA code rather than a `MediaError` one — 99001 where this\n * player has no pipeline for what the source needs, with the specifics logged. Reset by a new source, and not on the\n * inner `<video>`, which never learns of it.\n */\n get error(): HlsVideoMediaError | null {\n return this.#media.error;\n }\n\n /** HLS manifest URL. Assigning a new one restarts playback from scratch. */\n override get src(): string {\n return this.#media.src;\n }\n\n override set src(value: string) {\n this.#media.src = value;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0CA,IAAa,qBAAb,cAAwC,oBAAoB;;EACE,KAAA,UAAA,CAAC,QAAQ,UAAU;;;EAEpB,KAAA,wBAAA;GAAC;GAAY;GAAgB;EAAa;;CAErG,SAAS,IAAI,0BAA0B;CAEvC,cAAc;EACZ,MAAM;EAEN,MAAM,SAAS,KAAK;EAEpB,IAAI,QAAQ,KAAK,OAAO,OAAO,MAAM;EAGrC,KAAK,qBAAqB;EAK1B,KAAK,OAAO,iBAAiB,eAAe,KAAK,cAAc,IAAI,MAAM,OAAO,CAAC,CAAC;CACpF;;CAGA,iBAA+B;EAC7B,OAAO,KAAK;CACd;;;;;CAMA,IAAI,UAAqC;EACvC,OAAO,KAAK;CACd;CAEA,uBAAsC;EACpC,MAAM,uBAAuB;EAI7B,IAAI,KAAK,aAAa,YAAY,GAAG;EAIrC,qBAAqB;GACnB,IAAI,CAAC,KAAK,aAAa,KAAK,OAAO,QAAQ;EAC7C,CAAC;CACH;;CAGA,IAAI,QAAiC;EACnC,OAAO,KAAK;CACd;;;;;;CAOA,IAAI,QAAmC;EACrC,OAAO,KAAK,OAAO;CACrB;;CAGA,IAAa,MAAc;EACzB,OAAO,KAAK,OAAO;CACrB;CAEA,IAAa,IAAI,OAAe;EAC9B,KAAK,OAAO,MAAM;CACpB;AACF"}
@@ -0,0 +1,11 @@
1
+ import { CustomMediaConstructor } from "../../index.js";
2
+ import { MixcloudAdapter } from "@videojs/mixcloud-audio";
3
+ //#region src/media/mixcloud-audio/adapter.d.ts
4
+ declare const MixcloudCustomMediaElement_base: CustomMediaConstructor<typeof MixcloudAdapter>;
5
+ declare class MixcloudCustomMediaElement extends MixcloudCustomMediaElement_base {
6
+ static getTemplateHTML: (attrs: Record<string, string>) => string;
7
+ }
8
+ declare const MixcloudAudio_base: typeof MixcloudCustomMediaElement;
9
+ export declare class MixcloudAudio extends MixcloudAudio_base {}
10
+ //#endregion
11
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1,52 @@
1
+ import { MediaAttachMixin } from "../../store/media-attach-mixin.js";
2
+ import { CustomMediaElement } from "@videojs/media/dom";
3
+ import { escapeHtml } from "@videojs/utils/string";
4
+ import { MixcloudAdapter, buildMixcloudIframeSrc } from "@videojs/mixcloud-audio";
5
+ //#region src/media/mixcloud-audio/adapter.ts
6
+ var MixcloudCustomMediaElement = class extends CustomMediaElement("iframe", MixcloudAdapter) {
7
+ static {
8
+ this.getTemplateHTML = (attrs) => {
9
+ const initialSrc = buildMixcloudIframeSrc(attrs.src ?? "");
10
+ return `
11
+ <style>
12
+ :host {
13
+ display: block;
14
+ position: relative;
15
+ height: 120px;
16
+ }
17
+ iframe {
18
+ position: absolute;
19
+ inset: 0;
20
+ width: 100%;
21
+ height: 100%;
22
+ border: 0;
23
+ }
24
+ /*
25
+ * The widget is Mixcloud's own chrome, so without controls it is a
26
+ * transport and nothing else. Hidden rather than merely inert, and
27
+ * important so a consumer's own display rule cannot put it back on
28
+ * screen. An iframe in a hidden subtree still loads and plays its src.
29
+ */
30
+ :host(:not([controls])) {
31
+ display: none !important;
32
+ }
33
+ </style>
34
+ <iframe
35
+ part="iframe"
36
+ title="Mixcloud audio player"
37
+ ${initialSrc ? ` src="${escapeHtml(initialSrc)}"` : ""}
38
+ allow="autoplay; encrypted-media"
39
+ frameborder="0"
40
+ width="100%"
41
+ height="100%"
42
+ referrerpolicy="${escapeHtml(attrs.referrerpolicy ?? "")}"
43
+ ></iframe>
44
+ `;
45
+ };
46
+ }
47
+ };
48
+ var MixcloudAudio = class extends MediaAttachMixin(MixcloudCustomMediaElement) {};
49
+ //#endregion
50
+ export { MixcloudAudio };
51
+
52
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","names":[],"sources":["../../../../src/media/mixcloud-audio/adapter.ts"],"sourcesContent":["import { CustomMediaElement } from '@videojs/media/dom';\nimport { buildMixcloudIframeSrc, MixcloudAdapter } from '@videojs/mixcloud-audio';\nimport { escapeHtml } from '@videojs/utils/string';\n\nimport { MediaAttachMixin } from '../../store/media-attach-mixin';\n\nclass MixcloudCustomMediaElement extends CustomMediaElement('iframe', MixcloudAdapter) {\n static override getTemplateHTML = (attrs: Record<string, string>): string => {\n const initialSrc = buildMixcloudIframeSrc(attrs.src ?? '');\n const srcAttr = initialSrc ? ` src=\"${escapeHtml(initialSrc)}\"` : '';\n\n return /*html*/ `\n <style>\n :host {\n display: block;\n position: relative;\n height: 120px;\n }\n iframe {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n border: 0;\n }\n /*\n * The widget is Mixcloud's own chrome, so without controls it is a\n * transport and nothing else. Hidden rather than merely inert, and\n * important so a consumer's own display rule cannot put it back on\n * screen. An iframe in a hidden subtree still loads and plays its src.\n */\n :host(:not([controls])) {\n display: none !important;\n }\n </style>\n <iframe\n part=\"iframe\"\n title=\"Mixcloud audio player\"\n ${srcAttr}\n allow=\"autoplay; encrypted-media\"\n frameborder=\"0\"\n width=\"100%\"\n height=\"100%\"\n referrerpolicy=\"${escapeHtml(attrs.referrerpolicy ?? '')}\"\n ></iframe>\n `;\n };\n}\n\nexport class MixcloudAudio extends MediaAttachMixin(MixcloudCustomMediaElement) {}\n"],"mappings":";;;;;AAMA,IAAM,6BAAN,cAAyC,mBAAmB,UAAU,eAAe,CAAC,CAAC;;EAClD,KAAA,mBAAA,UAA0C;GAC3E,MAAM,aAAa,uBAAuB,MAAM,OAAO,EAAE;GAGzD,OAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;UAFA,aAAa,SAAS,WAAW,UAAU,EAAE,KAAK,GA6BpD;;;;;0BAKQ,WAAW,MAAM,kBAAkB,EAAE,EAAE;;;EAG/D;;AACF;AAEA,IAAa,gBAAb,cAAmC,iBAAiB,0BAA0B,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { MixcloudAudio } from "./adapter.js";
2
+ export { MixcloudAudio };
@@ -0,0 +1,11 @@
1
+ import { CustomMediaConstructor } from "../../index.js";
2
+ import { SoundCloudAdapter } from "@videojs/soundcloud-audio";
3
+ //#region src/media/soundcloud-audio/adapter.d.ts
4
+ declare const SoundCloudCustomMediaElement_base: CustomMediaConstructor<typeof SoundCloudAdapter>;
5
+ declare class SoundCloudCustomMediaElement extends SoundCloudCustomMediaElement_base {
6
+ static getTemplateHTML: (attrs: Record<string, string>) => string;
7
+ }
8
+ declare const SoundCloudAudio_base: typeof SoundCloudCustomMediaElement;
9
+ export declare class SoundCloudAudio extends SoundCloudAudio_base {}
10
+ //#endregion
11
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1,53 @@
1
+ import { MediaAttachMixin } from "../../store/media-attach-mixin.js";
2
+ import { CustomMediaElement } from "@videojs/media/dom";
3
+ import { escapeHtml } from "@videojs/utils/string";
4
+ import { SoundCloudAdapter, buildSoundCloudIframeSrc } from "@videojs/soundcloud-audio";
5
+ //#region src/media/soundcloud-audio/adapter.ts
6
+ var SoundCloudCustomMediaElement = class extends CustomMediaElement("iframe", SoundCloudAdapter) {
7
+ static {
8
+ this.getTemplateHTML = (attrs) => {
9
+ const initialSrc = buildSoundCloudIframeSrc(attrs.src ?? "");
10
+ return `
11
+ <style>
12
+ :host {
13
+ display: block;
14
+ position: relative;
15
+ height: 166px;
16
+ }
17
+ iframe {
18
+ position: absolute;
19
+ inset: 0;
20
+ width: 100%;
21
+ height: 100%;
22
+ border: 0;
23
+ }
24
+ /*
25
+ * The widget is SoundCloud's own chrome, so without controls it is a
26
+ * transport and nothing else. Hidden rather than merely inert, and
27
+ * important so a consumer's own display rule cannot put it back on
28
+ * screen. An iframe in a hidden subtree still loads and plays its src.
29
+ */
30
+ :host(:not([controls])) {
31
+ display: none !important;
32
+ }
33
+ </style>
34
+ <iframe
35
+ part="iframe"
36
+ title="SoundCloud audio player"
37
+ ${initialSrc ? ` src="${escapeHtml(initialSrc)}"` : ""}
38
+ allow="autoplay; encrypted-media"
39
+ scrolling="no"
40
+ frameborder="0"
41
+ width="100%"
42
+ height="100%"
43
+ referrerpolicy="${escapeHtml(attrs.referrerpolicy ?? "")}"
44
+ ></iframe>
45
+ `;
46
+ };
47
+ }
48
+ };
49
+ var SoundCloudAudio = class extends MediaAttachMixin(SoundCloudCustomMediaElement) {};
50
+ //#endregion
51
+ export { SoundCloudAudio };
52
+
53
+ //# sourceMappingURL=adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.js","names":[],"sources":["../../../../src/media/soundcloud-audio/adapter.ts"],"sourcesContent":["import { CustomMediaElement } from '@videojs/media/dom';\nimport { buildSoundCloudIframeSrc, SoundCloudAdapter } from '@videojs/soundcloud-audio';\nimport { escapeHtml } from '@videojs/utils/string';\n\nimport { MediaAttachMixin } from '../../store/media-attach-mixin';\n\nclass SoundCloudCustomMediaElement extends CustomMediaElement('iframe', SoundCloudAdapter) {\n static override getTemplateHTML = (attrs: Record<string, string>): string => {\n const initialSrc = buildSoundCloudIframeSrc(attrs.src ?? '');\n const srcAttr = initialSrc ? ` src=\"${escapeHtml(initialSrc)}\"` : '';\n\n return /*html*/ `\n <style>\n :host {\n display: block;\n position: relative;\n height: 166px;\n }\n iframe {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n border: 0;\n }\n /*\n * The widget is SoundCloud's own chrome, so without controls it is a\n * transport and nothing else. Hidden rather than merely inert, and\n * important so a consumer's own display rule cannot put it back on\n * screen. An iframe in a hidden subtree still loads and plays its src.\n */\n :host(:not([controls])) {\n display: none !important;\n }\n </style>\n <iframe\n part=\"iframe\"\n title=\"SoundCloud audio player\"\n ${srcAttr}\n allow=\"autoplay; encrypted-media\"\n scrolling=\"no\"\n frameborder=\"0\"\n width=\"100%\"\n height=\"100%\"\n referrerpolicy=\"${escapeHtml(attrs.referrerpolicy ?? '')}\"\n ></iframe>\n `;\n };\n}\n\nexport class SoundCloudAudio extends MediaAttachMixin(SoundCloudCustomMediaElement) {}\n"],"mappings":";;;;;AAMA,IAAM,+BAAN,cAA2C,mBAAmB,UAAU,iBAAiB,CAAC,CAAC;;EACtD,KAAA,mBAAA,UAA0C;GAC3E,MAAM,aAAa,yBAAyB,MAAM,OAAO,EAAE;GAG3D,OAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;UAFA,aAAa,SAAS,WAAW,UAAU,EAAE,KAAK,GA6BpD;;;;;;0BAMQ,WAAW,MAAM,kBAAkB,EAAE,EAAE;;;EAG/D;;AACF;AAEA,IAAa,kBAAb,cAAqC,iBAAiB,4BAA4B,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { SoundCloudAudio } from "./adapter.js";
2
+ export { SoundCloudAudio };
@@ -1,6 +1,6 @@
1
1
  import { UIElement } from "../ui/ui-element.js";
2
2
  import { PlayerExtensionCoordinator, setPlayerConfigValue } from "@videojs/core/dom";
3
- import { ContextProvider, ContextRoot } from "@videojs/element/context";
3
+ import { ContextProvider } from "@videojs/element/context";
4
4
  import { camelCase, kebabCase } from "@videojs/utils/string";
5
5
  import { isNull } from "@videojs/utils/predicate";
6
6
  //#region src/player/element.ts
@@ -29,7 +29,6 @@ function createPlayerElement(options) {
29
29
  };
30
30
  }
31
31
  #store = options.factory();
32
- #contextRoot = new ContextRoot();
33
32
  #configuredStore = null;
34
33
  #detach = null;
35
34
  #connected = false;
@@ -96,7 +95,6 @@ function createPlayerElement(options) {
96
95
  }
97
96
  connectedCallback() {
98
97
  this.#connected = true;
99
- this.#contextRoot.attach(this);
100
98
  super.connectedCallback();
101
99
  this.#syncInitialConfig();
102
100
  this.#playerProvider.setValue(this.store);
@@ -113,13 +111,11 @@ function createPlayerElement(options) {
113
111
  }
114
112
  disconnectedCallback() {
115
113
  this.#connected = false;
116
- this.#contextRoot.detach(this);
117
114
  this.#observer.disconnect();
118
115
  this.#detachStore();
119
116
  super.disconnectedCallback();
120
117
  }
121
118
  destroyCallback() {
122
- this.#contextRoot.detach(this);
123
119
  this.#observer.disconnect();
124
120
  this.#detachStore();
125
121
  this.#extensions.destroy();
@@ -1 +1 @@
1
- {"version":3,"file":"element.js","names":[],"sources":["../../../src/player/element.ts"],"sourcesContent":["import {\n type MediaContainer,\n type PlayerExtension,\n PlayerExtensionCoordinator,\n type PlayerFeatureConfig,\n type PlayerStore,\n type PlayerTarget,\n setPlayerConfigValue,\n} from '@videojs/core/dom';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport { ContextProvider, ContextRoot } from '@videojs/element/context';\nimport type { Media } from '@videojs/media/dom';\nimport { isNull } from '@videojs/utils/predicate';\nimport { camelCase, kebabCase } from '@videojs/utils/string';\n\nimport type { PlayerElementConstructor } from '../store/types';\nimport { UIElement } from '../ui/ui-element';\nimport type { ContainerContext, ExtensionContext, MediaContext, PlayerContext } from './context';\n\nexport interface CreatePlayerElementOptions<Store extends PlayerStore> {\n playerContext: PlayerContext<Store>;\n mediaContext: MediaContext;\n containerContext: ContainerContext;\n extensionContext: ExtensionContext;\n factory: () => Store;\n config: PlayerFeatureConfig;\n}\n\ninterface Registration<Value> {\n value: Value;\n}\n\ninterface ConfigInput {\n property: string;\n attribute: string;\n entry: PlayerFeatureConfig[string];\n}\n\nfunction resolveInputs(config: PlayerFeatureConfig): ConfigInput[] {\n return Object.entries(config).map(([key, entry]) => {\n const declared = entry.html?.attribute;\n const attribute = declared ?? kebabCase(key);\n\n if (__DEV__ && declared && declared !== kebabCase(declared)) {\n console.warn(`[vjs-html] config html.attribute \"${declared}\" is not kebab-case and will never match`);\n }\n\n return { property: camelCase(attribute), attribute, entry };\n });\n}\n\n/** Creates a configured player element class that owns the store and attach lifecycle. */\nexport function createPlayerElement<Store extends PlayerStore>(\n options: CreatePlayerElementOptions<Store>\n): PlayerElementConstructor<Store>;\nexport function createPlayerElement<Store extends PlayerStore>(\n options: CreatePlayerElementOptions<Store>\n): typeof UIElement {\n const inputs = resolveInputs(options.config);\n\n class ConfiguredPlayerElement extends UIElement {\n static properties = {\n ...UIElement.properties,\n ...Object.fromEntries(inputs.map(({ property, attribute }) => [property, { type: String, attribute }])),\n } satisfies PropertyDeclarationMap;\n\n #store: Store | null = options.factory();\n readonly #contextRoot = new ContextRoot();\n #configuredStore: Store | null = null;\n #detach: (() => void) | null = null;\n #connected = false;\n #media: Media | null = null;\n #nativeMedia: HTMLMediaElement | null = null;\n #container: MediaContainer | null = null;\n // The raw target the store is attached to; `store.target.media` may be the extensions' facade over it.\n #attached: PlayerTarget | null = null;\n #mediaRegistrations: Registration<Media>[] = [];\n #containerRegistrations: Registration<MediaContainer>[] = [];\n #observer = new MutationObserver(() => this.#syncNativeMedia());\n #extensions = new PlayerExtensionCoordinator(() => this.#syncExtensions());\n\n #registerExtension = (extension: PlayerExtension): (() => void) => this.#extensions.register(extension);\n\n #registerMedia = (media: Media): (() => void) => {\n const registration = { value: media };\n\n this.#mediaRegistrations.push(registration);\n this.#syncMedia();\n\n return () => {\n const index = this.#mediaRegistrations.indexOf(registration);\n if (index < 0) return;\n\n this.#mediaRegistrations.splice(index, 1);\n this.#syncNativeMedia();\n this.#syncMedia();\n };\n };\n\n #registerContainer = (container: MediaContainer): (() => void) => {\n const registration = { value: container };\n\n this.#containerRegistrations.push(registration);\n this.#syncContainer();\n\n return () => {\n const index = this.#containerRegistrations.indexOf(registration);\n if (index < 0) return;\n\n this.#containerRegistrations.splice(index, 1);\n this.#syncContainer();\n };\n };\n\n #playerProvider = new ContextProvider(this, {\n context: options.playerContext,\n initialValue: this.store,\n });\n\n #mediaProvider = new ContextProvider(this, {\n context: options.mediaContext,\n initialValue: { media: this.#media, registerMedia: this.#registerMedia },\n });\n\n #containerProvider = new ContextProvider(this, {\n context: options.containerContext,\n initialValue: {\n container: this.#container,\n registerContainer: this.#registerContainer,\n },\n });\n\n constructor() {\n super();\n // Registers itself as a controller on this element; the value never changes, so nothing reads it back.\n new ContextProvider(this, {\n context: options.extensionContext,\n initialValue: { registerExtension: this.#registerExtension },\n });\n }\n\n get store(): Store {\n if (isNull(this.#store)) {\n this.#store = options.factory();\n }\n\n return this.#store;\n }\n\n override connectedCallback(): void {\n this.#connected = true;\n // Retry part subscriptions when their parent is registered later.\n this.#contextRoot.attach(this);\n super.connectedCallback();\n this.#syncInitialConfig();\n this.#playerProvider.setValue(this.store);\n this.#publishMedia();\n this.#publishContainer();\n this.#observer.observe(this, { childList: true, subtree: true });\n queueMicrotask(() => {\n if (this.#connected) this.#syncNativeMedia();\n });\n this.#tryAttach();\n }\n\n override disconnectedCallback(): void {\n this.#connected = false;\n this.#contextRoot.detach(this);\n this.#observer.disconnect();\n this.#detachStore();\n super.disconnectedCallback();\n }\n\n override destroyCallback(): void {\n this.#contextRoot.detach(this);\n this.#observer.disconnect();\n this.#detachStore();\n this.#extensions.destroy();\n this.#store?.destroy();\n this.#store = null;\n super.destroyCallback();\n }\n\n protected override willUpdate(changed: PropertyValues): void {\n super.willUpdate(changed);\n\n for (const { property, entry } of inputs) {\n if (!changed.has(property)) continue;\n\n // SAFETY: `resolveInputs` derives properties installed by this class's static property map.\n const configProperty = property as keyof this;\n\n setPlayerConfigValue(this.store, entry, this[configProperty]);\n }\n }\n\n #syncMedia(): void {\n const registered = this.#mediaRegistrations.at(-1)?.value ?? null;\n const media = registered ?? this.#nativeMedia;\n if (this.#media === media) return;\n\n this.#media = media;\n this.#publishMedia();\n this.#tryAttach();\n }\n\n #syncContainer(): void {\n const container = this.#containerRegistrations.at(-1)?.value ?? null;\n if (this.#container === container) return;\n\n this.#container = container;\n this.#publishContainer();\n this.#tryAttach();\n }\n\n #syncNativeMedia(): void {\n const media = this.querySelector<HTMLMediaElement>('video, audio');\n if (this.#nativeMedia === media) return;\n\n this.#nativeMedia = media;\n this.#syncMedia();\n }\n\n #publishMedia(): void {\n this.#mediaProvider.setValue({ media: this.#media, registerMedia: this.#registerMedia });\n }\n\n #publishContainer(): void {\n this.#containerProvider.setValue({\n container: this.#container,\n registerContainer: this.#registerContainer,\n });\n }\n\n #tryAttach(): void {\n if (!this.#connected || !this.#store) return;\n\n if (!this.#media) {\n this.#detachStore();\n return;\n }\n\n const target: PlayerTarget = {\n media: this.#media,\n container: this.#container,\n };\n\n const hasMediaChanged = this.#attached?.media !== target.media;\n const hasContainerChanged = this.#attached?.container !== target.container;\n\n if (hasMediaChanged || hasContainerChanged) this.#attach(target);\n }\n\n /**\n * Extensions attach before the store so their overrides are in place when features first read the media; the store\n * then sees the media through the extensions' facade. Extensions follow the media only, so a container change\n * re-attaches the store but leaves them attached.\n */\n #attach(target: PlayerTarget): void {\n const store = this.#store;\n if (!store) return;\n\n this.#detach?.();\n this.#attached = target;\n this.#extensions.attach(target);\n this.#detach = store.attach({ media: this.#extensions.getStoreMedia(target.media), container: target.container });\n }\n\n /**\n * An extension that overrides media members was added or removed. Features hold members read at attach time (such\n * as `remote`), so the store re-attaches to the same target to pick up what the extensions now own. Observers such\n * as analytics never get here. Extensions themselves stay attached.\n */\n #syncExtensions(): void {\n if (this.#attached) this.#attach(this.#attached);\n }\n\n #detachStore(): void {\n this.#detach?.();\n this.#detach = null;\n this.#extensions.detach();\n this.#attached = null;\n }\n\n #syncInitialConfig(): void {\n const store = this.store;\n if (this.#configuredStore === store) return;\n\n for (const { property, entry } of inputs) {\n // SAFETY: `resolveInputs` derives properties installed by this class's static property map.\n const configProperty = property as keyof this;\n\n setPlayerConfigValue(store, entry, this[configProperty]);\n }\n\n this.#configuredStore = store;\n }\n }\n\n return ConfiguredPlayerElement;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"element.js","names":[],"sources":["../../../src/player/element.ts"],"sourcesContent":["import {\n type MediaContainer,\n type PlayerExtension,\n PlayerExtensionCoordinator,\n type PlayerFeatureConfig,\n type PlayerStore,\n type PlayerTarget,\n setPlayerConfigValue,\n} from '@videojs/core/dom';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\nimport { ContextProvider } from '@videojs/element/context';\nimport type { Media } from '@videojs/media/dom';\nimport { isNull } from '@videojs/utils/predicate';\nimport { camelCase, kebabCase } from '@videojs/utils/string';\n\nimport type { PlayerElementConstructor } from '../store/types';\nimport { UIElement } from '../ui/ui-element';\nimport type { ContainerContext, ExtensionContext, MediaContext, PlayerContext } from './context';\n\nexport interface CreatePlayerElementOptions<Store extends PlayerStore> {\n playerContext: PlayerContext<Store>;\n mediaContext: MediaContext;\n containerContext: ContainerContext;\n extensionContext: ExtensionContext;\n factory: () => Store;\n config: PlayerFeatureConfig;\n}\n\ninterface Registration<Value> {\n value: Value;\n}\n\ninterface ConfigInput {\n property: string;\n attribute: string;\n entry: PlayerFeatureConfig[string];\n}\n\nfunction resolveInputs(config: PlayerFeatureConfig): ConfigInput[] {\n return Object.entries(config).map(([key, entry]) => {\n const declared = entry.html?.attribute;\n const attribute = declared ?? kebabCase(key);\n\n if (__DEV__ && declared && declared !== kebabCase(declared)) {\n console.warn(`[vjs-html] config html.attribute \"${declared}\" is not kebab-case and will never match`);\n }\n\n return { property: camelCase(attribute), attribute, entry };\n });\n}\n\n/** Creates a configured player element class that owns the store and attach lifecycle. */\nexport function createPlayerElement<Store extends PlayerStore>(\n options: CreatePlayerElementOptions<Store>\n): PlayerElementConstructor<Store>;\nexport function createPlayerElement<Store extends PlayerStore>(\n options: CreatePlayerElementOptions<Store>\n): typeof UIElement {\n const inputs = resolveInputs(options.config);\n\n class ConfiguredPlayerElement extends UIElement {\n static properties = {\n ...UIElement.properties,\n ...Object.fromEntries(inputs.map(({ property, attribute }) => [property, { type: String, attribute }])),\n } satisfies PropertyDeclarationMap;\n\n #store: Store | null = options.factory();\n #configuredStore: Store | null = null;\n #detach: (() => void) | null = null;\n #connected = false;\n #media: Media | null = null;\n #nativeMedia: HTMLMediaElement | null = null;\n #container: MediaContainer | null = null;\n // The raw target the store is attached to; `store.target.media` may be the extensions' facade over it.\n #attached: PlayerTarget | null = null;\n #mediaRegistrations: Registration<Media>[] = [];\n #containerRegistrations: Registration<MediaContainer>[] = [];\n #observer = new MutationObserver(() => this.#syncNativeMedia());\n #extensions = new PlayerExtensionCoordinator(() => this.#syncExtensions());\n\n #registerExtension = (extension: PlayerExtension): (() => void) => this.#extensions.register(extension);\n\n #registerMedia = (media: Media): (() => void) => {\n const registration = { value: media };\n\n this.#mediaRegistrations.push(registration);\n this.#syncMedia();\n\n return () => {\n const index = this.#mediaRegistrations.indexOf(registration);\n if (index < 0) return;\n\n this.#mediaRegistrations.splice(index, 1);\n this.#syncNativeMedia();\n this.#syncMedia();\n };\n };\n\n #registerContainer = (container: MediaContainer): (() => void) => {\n const registration = { value: container };\n\n this.#containerRegistrations.push(registration);\n this.#syncContainer();\n\n return () => {\n const index = this.#containerRegistrations.indexOf(registration);\n if (index < 0) return;\n\n this.#containerRegistrations.splice(index, 1);\n this.#syncContainer();\n };\n };\n\n #playerProvider = new ContextProvider(this, {\n context: options.playerContext,\n initialValue: this.store,\n });\n\n #mediaProvider = new ContextProvider(this, {\n context: options.mediaContext,\n initialValue: { media: this.#media, registerMedia: this.#registerMedia },\n });\n\n #containerProvider = new ContextProvider(this, {\n context: options.containerContext,\n initialValue: {\n container: this.#container,\n registerContainer: this.#registerContainer,\n },\n });\n\n constructor() {\n super();\n // Registers itself as a controller on this element; the value never changes, so nothing reads it back.\n new ContextProvider(this, {\n context: options.extensionContext,\n initialValue: { registerExtension: this.#registerExtension },\n });\n }\n\n get store(): Store {\n if (isNull(this.#store)) {\n this.#store = options.factory();\n }\n\n return this.#store;\n }\n\n override connectedCallback(): void {\n this.#connected = true;\n super.connectedCallback();\n this.#syncInitialConfig();\n this.#playerProvider.setValue(this.store);\n this.#publishMedia();\n this.#publishContainer();\n this.#observer.observe(this, { childList: true, subtree: true });\n queueMicrotask(() => {\n if (this.#connected) this.#syncNativeMedia();\n });\n this.#tryAttach();\n }\n\n override disconnectedCallback(): void {\n this.#connected = false;\n this.#observer.disconnect();\n this.#detachStore();\n super.disconnectedCallback();\n }\n\n override destroyCallback(): void {\n this.#observer.disconnect();\n this.#detachStore();\n this.#extensions.destroy();\n this.#store?.destroy();\n this.#store = null;\n super.destroyCallback();\n }\n\n protected override willUpdate(changed: PropertyValues): void {\n super.willUpdate(changed);\n\n for (const { property, entry } of inputs) {\n if (!changed.has(property)) continue;\n\n // SAFETY: `resolveInputs` derives properties installed by this class's static property map.\n const configProperty = property as keyof this;\n\n setPlayerConfigValue(this.store, entry, this[configProperty]);\n }\n }\n\n #syncMedia(): void {\n const registered = this.#mediaRegistrations.at(-1)?.value ?? null;\n const media = registered ?? this.#nativeMedia;\n if (this.#media === media) return;\n\n this.#media = media;\n this.#publishMedia();\n this.#tryAttach();\n }\n\n #syncContainer(): void {\n const container = this.#containerRegistrations.at(-1)?.value ?? null;\n if (this.#container === container) return;\n\n this.#container = container;\n this.#publishContainer();\n this.#tryAttach();\n }\n\n #syncNativeMedia(): void {\n const media = this.querySelector<HTMLMediaElement>('video, audio');\n if (this.#nativeMedia === media) return;\n\n this.#nativeMedia = media;\n this.#syncMedia();\n }\n\n #publishMedia(): void {\n this.#mediaProvider.setValue({ media: this.#media, registerMedia: this.#registerMedia });\n }\n\n #publishContainer(): void {\n this.#containerProvider.setValue({\n container: this.#container,\n registerContainer: this.#registerContainer,\n });\n }\n\n #tryAttach(): void {\n if (!this.#connected || !this.#store) return;\n\n if (!this.#media) {\n this.#detachStore();\n return;\n }\n\n const target: PlayerTarget = {\n media: this.#media,\n container: this.#container,\n };\n\n const hasMediaChanged = this.#attached?.media !== target.media;\n const hasContainerChanged = this.#attached?.container !== target.container;\n\n if (hasMediaChanged || hasContainerChanged) this.#attach(target);\n }\n\n /**\n * Extensions attach before the store so their overrides are in place when features first read the media; the store\n * then sees the media through the extensions' facade. Extensions follow the media only, so a container change\n * re-attaches the store but leaves them attached.\n */\n #attach(target: PlayerTarget): void {\n const store = this.#store;\n if (!store) return;\n\n this.#detach?.();\n this.#attached = target;\n this.#extensions.attach(target);\n this.#detach = store.attach({ media: this.#extensions.getStoreMedia(target.media), container: target.container });\n }\n\n /**\n * An extension that overrides media members was added or removed. Features hold members read at attach time (such\n * as `remote`), so the store re-attaches to the same target to pick up what the extensions now own. Observers such\n * as analytics never get here. Extensions themselves stay attached.\n */\n #syncExtensions(): void {\n if (this.#attached) this.#attach(this.#attached);\n }\n\n #detachStore(): void {\n this.#detach?.();\n this.#detach = null;\n this.#extensions.detach();\n this.#attached = null;\n }\n\n #syncInitialConfig(): void {\n const store = this.store;\n if (this.#configuredStore === store) return;\n\n for (const { property, entry } of inputs) {\n // SAFETY: `resolveInputs` derives properties installed by this class's static property map.\n const configProperty = property as keyof this;\n\n setPlayerConfigValue(store, entry, this[configProperty]);\n }\n\n this.#configuredStore = store;\n }\n }\n\n return ConfiguredPlayerElement;\n}\n"],"mappings":"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"}
@@ -1,7 +1,8 @@
1
1
  import { ReactiveElement } from "@videojs/element";
2
2
  //#region src/presets/background/skin.d.ts
3
3
  declare function getTemplateHTML(): string;
4
- export declare class BackgroundVideoSkinElement extends ReactiveElement {
4
+ declare const BackgroundVideoSkinElement_base: typeof ReactiveElement & (new (...args: any[]) => import("@videojs/element").Destroyable);
5
+ export declare class BackgroundVideoSkinElement extends BackgroundVideoSkinElement_base {
5
6
  static readonly tagName = "background-video-skin";
6
7
  static shadowRootOptions: ShadowRootInit;
7
8
  static getTemplateHTML: typeof getTemplateHTML;
@@ -1,5 +1,5 @@
1
1
  import skin_default from "../../define/background/skin2.js";
2
- import { ReactiveElement } from "@videojs/element";
2
+ import { DestroyMixin, ReactiveElement } from "@videojs/element";
3
3
  import { ensureGlobalStyle } from "@videojs/utils/dom";
4
4
  //#region src/presets/background/skin.ts
5
5
  const STYLES_ID = "__media-background-styles";
@@ -12,7 +12,7 @@ function getTemplateHTML() {
12
12
  </media-container>
13
13
  `;
14
14
  }
15
- var BackgroundVideoSkinElement = class BackgroundVideoSkinElement extends ReactiveElement {
15
+ var BackgroundVideoSkinElement = class BackgroundVideoSkinElement extends DestroyMixin(ReactiveElement) {
16
16
  static {
17
17
  this.tagName = "background-video-skin";
18
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"skin.js","names":["styles"],"sources":["../../../../src/presets/background/skin.ts"],"sourcesContent":["import { ReactiveElement } from '@videojs/element';\nimport { ensureGlobalStyle } from '@videojs/utils/dom';\n\nimport styles from '../../define/background/skin.css?inline';\n\nconst STYLES_ID = '__media-background-styles';\n\nfunction getTemplateHTML() {\n return /* html */ `\n <media-container>\n <!-- @deprecated slot=\"media\" is no longer required, use the default slot instead -->\n <slot name=\"media\"></slot>\n <slot></slot>\n </media-container>\n `;\n}\n\nexport class BackgroundVideoSkinElement extends ReactiveElement {\n static readonly tagName = 'background-video-skin';\n static shadowRootOptions: ShadowRootInit = { mode: 'open' };\n static getTemplateHTML = getTemplateHTML;\n\n constructor() {\n super();\n\n ensureGlobalStyle(STYLES_ID, styles);\n\n if (!this.shadowRoot) {\n this.attachShadow(BackgroundVideoSkinElement.shadowRootOptions);\n this.shadowRoot!.innerHTML = getTemplateHTML();\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n [BackgroundVideoSkinElement.tagName]: BackgroundVideoSkinElement;\n }\n}\n"],"mappings":";;;;AAKA,MAAM,YAAY;AAElB,SAAS,kBAAkB;CACzB,OAAkB;;;;;;;AAOpB;AAEA,IAAa,6BAAb,MAAa,mCAAmC,gBAAgB;;EACpC,KAAA,UAAA;;;EACiB,KAAA,oBAAA,EAAE,MAAM,OAAO;;;EACjC,KAAA,kBAAA;;CAEzB,cAAc;EACZ,MAAM;EAEN,kBAAkB,WAAWA,YAAM;EAEnC,IAAI,CAAC,KAAK,YAAY;GACpB,KAAK,aAAa,2BAA2B,iBAAiB;GAC9D,KAAK,WAAY,YAAY,gBAAgB;EAC/C;CACF;AACF"}
1
+ {"version":3,"file":"skin.js","names":["styles"],"sources":["../../../../src/presets/background/skin.ts"],"sourcesContent":["import { DestroyMixin, ReactiveElement } from '@videojs/element';\nimport { ensureGlobalStyle } from '@videojs/utils/dom';\n\nimport styles from '../../define/background/skin.css?inline';\n\nconst STYLES_ID = '__media-background-styles';\n\nfunction getTemplateHTML() {\n return /* html */ `\n <media-container>\n <!-- @deprecated slot=\"media\" is no longer required, use the default slot instead -->\n <slot name=\"media\"></slot>\n <slot></slot>\n </media-container>\n `;\n}\n\nexport class BackgroundVideoSkinElement extends DestroyMixin(ReactiveElement) {\n static readonly tagName = 'background-video-skin';\n static shadowRootOptions: ShadowRootInit = { mode: 'open' };\n static getTemplateHTML = getTemplateHTML;\n\n constructor() {\n super();\n\n ensureGlobalStyle(STYLES_ID, styles);\n\n if (!this.shadowRoot) {\n this.attachShadow(BackgroundVideoSkinElement.shadowRootOptions);\n this.shadowRoot!.innerHTML = getTemplateHTML();\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n [BackgroundVideoSkinElement.tagName]: BackgroundVideoSkinElement;\n }\n}\n"],"mappings":";;;;AAKA,MAAM,YAAY;AAElB,SAAS,kBAAkB;CACzB,OAAkB;;;;;;;AAOpB;AAEA,IAAa,6BAAb,MAAa,mCAAmC,aAAa,eAAe,CAAC,CAAC;;EAClD,KAAA,UAAA;;;EACiB,KAAA,oBAAA,EAAE,MAAM,OAAO;;;EACjC,KAAA,kBAAA;;CAEzB,cAAc;EACZ,MAAM;EAEN,kBAAkB,WAAWA,YAAM;EAEnC,IAAI,CAAC,KAAK,YAAY;GACpB,KAAK,aAAa,2BAA2B,iBAAiB;GAC9D,KAAK,WAAY,YAAY,gBAAgB;EAC/C;CACF;AACF"}
@@ -1,11 +1,12 @@
1
- import { ReactiveElement } from "@videojs/element";
1
+ import { UIElement } from "../ui/ui-element.js";
2
2
  import { ShadowStyle } from "@videojs/utils/dom";
3
3
  //#region src/presets/skin.d.ts
4
4
  /**
5
5
  * Base element for skin definitions. Attaches a shadow root, clones `static template` into it, and applies shared +
6
- * per-skin styles via `adoptedStyleSheets` (or `<style>` fallback).
6
+ * per-skin styles via `adoptedStyleSheets` (or `<style>` fallback). Destroying it also destroys the controls in its
7
+ * shadow root.
7
8
  */
8
- export declare class SkinElement extends ReactiveElement {
9
+ export declare class SkinElement extends UIElement {
9
10
  static shadowRootOptions: ShadowRootInit;
10
11
  static styles?: ShadowStyle;
11
12
  static template?: HTMLTemplateElement | null;
@@ -1,15 +1,16 @@
1
+ import { UIElement } from "../ui/ui-element.js";
1
2
  import global_default from "../define/global.js";
2
3
  import shadow_default from "../define/shadow.js";
3
- import { ReactiveElement } from "@videojs/element";
4
4
  import { applyShadowStyles, createShadowStyle, ensureGlobalStyle, renderTemplate } from "@videojs/utils/dom";
5
5
  //#region src/presets/skin.ts
6
6
  const STYLES_ID = "__media-styles";
7
7
  const shadowSheet = createShadowStyle(shadow_default);
8
8
  /**
9
9
  * Base element for skin definitions. Attaches a shadow root, clones `static template` into it, and applies shared +
10
- * per-skin styles via `adoptedStyleSheets` (or `<style>` fallback).
10
+ * per-skin styles via `adoptedStyleSheets` (or `<style>` fallback). Destroying it also destroys the controls in its
11
+ * shadow root.
11
12
  */
12
- var SkinElement = class extends ReactiveElement {
13
+ var SkinElement = class extends UIElement {
13
14
  static {
14
15
  this.shadowRootOptions = { mode: "open" };
15
16
  }
@@ -1 +1 @@
1
- {"version":3,"file":"skin.js","names":["shadowStyles","globalStyles"],"sources":["../../../src/presets/skin.ts"],"sourcesContent":["import { ReactiveElement } from '@videojs/element';\nimport {\n applyShadowStyles,\n createShadowStyle,\n ensureGlobalStyle,\n renderTemplate,\n type ShadowStyle,\n} from '@videojs/utils/dom';\n\nimport globalStyles from '../define/global.css?inline';\nimport shadowStyles from '../define/shadow.css?inline';\n\nconst STYLES_ID = '__media-styles';\nconst shadowSheet = createShadowStyle(shadowStyles);\n\n/**\n * Base element for skin definitions. Attaches a shadow root, clones `static template` into it, and applies shared +\n * per-skin styles via `adoptedStyleSheets` (or `<style>` fallback).\n */\nexport class SkinElement extends ReactiveElement {\n static shadowRootOptions: ShadowRootInit = { mode: 'open' };\n static styles?: ShadowStyle;\n static template?: HTMLTemplateElement | null;\n\n constructor() {\n super();\n\n ensureGlobalStyle(STYLES_ID, globalStyles);\n\n if (!this.shadowRoot) {\n const ctor = this.constructor as typeof SkinElement;\n\n this.attachShadow(ctor.shadowRootOptions);\n\n if (ctor.template) {\n renderTemplate(this.shadowRoot!, ctor.template);\n }\n\n const sheets: ShadowStyle[] = [shadowSheet];\n\n if (ctor.styles) {\n sheets.push(ctor.styles);\n }\n\n applyShadowStyles(this.shadowRoot!, sheets);\n }\n }\n}\n"],"mappings":";;;;;AAYA,MAAM,YAAY;AAClB,MAAM,cAAc,kBAAkBA,cAAY;;;;;AAMlD,IAAa,cAAb,cAAiC,gBAAgB;;EACJ,KAAA,oBAAA,EAAE,MAAM,OAAO;;CAI1D,cAAc;EACZ,MAAM;EAEN,kBAAkB,WAAWC,cAAY;EAEzC,IAAI,CAAC,KAAK,YAAY;GACpB,MAAM,OAAO,KAAK;GAElB,KAAK,aAAa,KAAK,iBAAiB;GAExC,IAAI,KAAK,UACP,eAAe,KAAK,YAAa,KAAK,QAAQ;GAGhD,MAAM,SAAwB,CAAC,WAAW;GAE1C,IAAI,KAAK,QACP,OAAO,KAAK,KAAK,MAAM;GAGzB,kBAAkB,KAAK,YAAa,MAAM;EAC5C;CACF;AACF"}
1
+ {"version":3,"file":"skin.js","names":["shadowStyles","globalStyles"],"sources":["../../../src/presets/skin.ts"],"sourcesContent":["import {\n applyShadowStyles,\n createShadowStyle,\n ensureGlobalStyle,\n renderTemplate,\n type ShadowStyle,\n} from '@videojs/utils/dom';\n\nimport { UIElement } from '../ui/ui-element';\n\nimport globalStyles from '../define/global.css?inline';\nimport shadowStyles from '../define/shadow.css?inline';\n\nconst STYLES_ID = '__media-styles';\nconst shadowSheet = createShadowStyle(shadowStyles);\n\n/**\n * Base element for skin definitions. Attaches a shadow root, clones `static template` into it, and applies shared +\n * per-skin styles via `adoptedStyleSheets` (or `<style>` fallback). Destroying it also destroys the controls in its\n * shadow root.\n */\nexport class SkinElement extends UIElement {\n static shadowRootOptions: ShadowRootInit = { mode: 'open' };\n static styles?: ShadowStyle;\n static template?: HTMLTemplateElement | null;\n\n constructor() {\n super();\n\n ensureGlobalStyle(STYLES_ID, globalStyles);\n\n if (!this.shadowRoot) {\n const ctor = this.constructor as typeof SkinElement;\n\n this.attachShadow(ctor.shadowRootOptions);\n\n if (ctor.template) {\n renderTemplate(this.shadowRoot!, ctor.template);\n }\n\n const sheets: ShadowStyle[] = [shadowSheet];\n\n if (ctor.styles) {\n sheets.push(ctor.styles);\n }\n\n applyShadowStyles(this.shadowRoot!, sheets);\n }\n }\n}\n"],"mappings":";;;;;AAaA,MAAM,YAAY;AAClB,MAAM,cAAc,kBAAkBA,cAAY;;;;;;AAOlD,IAAa,cAAb,cAAiC,UAAU;;EACE,KAAA,oBAAA,EAAE,MAAM,OAAO;;CAI1D,cAAc;EACZ,MAAM;EAEN,kBAAkB,WAAWC,cAAY;EAEzC,IAAI,CAAC,KAAK,YAAY;GACpB,MAAM,OAAO,KAAK;GAElB,KAAK,aAAa,KAAK,iBAAiB;GAExC,IAAI,KAAK,UACP,eAAe,KAAK,YAAa,KAAK,QAAQ;GAGhD,MAAM,SAAwB,CAAC,WAAW;GAE1C,IAAI,KAAK,QACP,OAAO,KAAK,KAAK,MAAM;GAGzB,kBAAkB,KAAK,YAAa,MAAM;EAC5C;CACF;AACF"}
@@ -40,6 +40,8 @@ export declare class CaptionsButtonElement extends MediaButtonElement<CaptionsBu
40
40
  selectSubtitlesTrack: (id: string | null) => void;
41
41
  chaptersCues: import("@videojs/media").MediaTextCue[];
42
42
  thumbnailsTrack: import("@videojs/media").MediaThumbnailsTrack | null;
43
+ addTextTrack: import("@videojs/core").AddTextTrack;
44
+ removeTextTrack: (id: string) => void;
43
45
  } | undefined>;
44
46
  protected readonly hotkeyAction = "toggleSubtitles";
45
47
  connectedCallback(): void;
@@ -6,7 +6,8 @@ import { Text } from "@videojs/core/i18n";
6
6
  /**
7
7
  * Menu radio group that generates an Off `<media-menu-radio-item>` plus one per captions and subtitles track, and
8
8
  * shares the selected label and availability with an enclosing menu. An optional `<template>` holding one
9
- * `<media-menu-radio-item>` customizes each generated item.
9
+ * `<media-menu-radio-item>` customizes each generated item; its `data-part` `label` and `badge` descendants receive the
10
+ * track's text.
10
11
  */
11
12
  export declare class CaptionsRadioGroupElement extends MenuRadioGroupElement {
12
13
  #private;
@@ -11,7 +11,8 @@ import { translateText } from "@videojs/core/i18n";
11
11
  /**
12
12
  * Menu radio group that generates an Off `<media-menu-radio-item>` plus one per captions and subtitles track, and
13
13
  * shares the selected label and availability with an enclosing menu. An optional `<template>` holding one
14
- * `<media-menu-radio-item>` customizes each generated item.
14
+ * `<media-menu-radio-item>` customizes each generated item; its `data-part` `label` and `badge` descendants receive the
15
+ * track's text.
15
16
  */
16
17
  var CaptionsRadioGroupElement = class extends MenuRadioGroupElement {
17
18
  constructor(..._args) {
@@ -23,6 +24,8 @@ var CaptionsRadioGroupElement = class extends MenuRadioGroupElement {
23
24
  this.#i18n = new I18nController(this, i18nContext);
24
25
  this.#mediaState = new PlayerController(this, playerContext, selectTextTrack);
25
26
  this.#options = new RadioOptionsController(this, {
27
+ renderItem: (item, label, option) => this.#setContent(item, label, option.badge),
28
+ getOptionCacheKey: (option) => option.badge ?? "",
26
29
  setItemAttributes: (item, option) => item.setAttribute("data-track", option.value),
27
30
  onValueChange: (value) => {
28
31
  const media = this.#mediaState.value;
@@ -67,6 +70,16 @@ var CaptionsRadioGroupElement = class extends MenuRadioGroupElement {
67
70
  super.update(changed);
68
71
  if (state) applyStateDataAttrs(this, state, CaptionsRadioGroupDataAttrs);
69
72
  }
73
+ #setContent(item, label, badge) {
74
+ const labelPart = item.querySelector("[data-part~=\"label\"]");
75
+ const badgePart = item.querySelector("[data-part~=\"badge\"]");
76
+ if (labelPart) labelPart.textContent = label;
77
+ if (badgePart) {
78
+ badgePart.textContent = badge ?? "";
79
+ badgePart.hidden = !badge;
80
+ }
81
+ if (!labelPart && !badgePart) item.textContent = [label, badge].filter(Boolean).join(" ");
82
+ }
70
83
  };
71
84
  //#endregion
72
85
  export { CaptionsRadioGroupElement };
@@ -1 +1 @@
1
- {"version":3,"file":"element.js","names":[],"sources":["../../../../src/ui/captions-radio-group/element.ts"],"sourcesContent":["import {\n CaptionsRadioGroupCore,\n CaptionsRadioGroupDataAttrs,\n type CaptionsRadioGroupOption,\n type CaptionsRadioGroupState,\n} from '@videojs/core';\nimport { applyStateDataAttrs, logMissingFeature, selectTextTrack } from '@videojs/core/dom';\nimport { type Text, translateText } from '@videojs/core/i18n';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\n\nimport { i18nContext } from '../../i18n/context';\nimport { I18nController } from '../../i18n/controller';\nimport { playerContext } from '../../player/context';\nimport { PlayerController } from '../../player/controller';\nimport { MenuRadioGroupElement } from '../menu/radio-group';\nimport { RadioOptionsController } from '../radio-options/controller';\n\n/**\n * Menu radio group that generates an Off `<media-menu-radio-item>` plus one per captions and subtitles track, and\n * shares the selected label and availability with an enclosing menu. An optional `<template>` holding one\n * `<media-menu-radio-item>` customizes each generated item.\n */\nexport class CaptionsRadioGroupElement extends MenuRadioGroupElement {\n static override readonly tagName = 'media-captions-radio-group';\n\n static override properties = {\n ...MenuRadioGroupElement.properties,\n disabled: { type: Boolean },\n label: { type: String },\n } satisfies PropertyDeclarationMap<'value' | 'label' | 'disabled'>;\n\n disabled = false;\n label: Text | string = '';\n formatTrack = CaptionsRadioGroupCore.defaultProps.formatTrack;\n\n readonly #core = new CaptionsRadioGroupCore();\n readonly #i18n = new I18nController(this, i18nContext);\n readonly #mediaState = new PlayerController(this, playerContext, selectTextTrack);\n readonly #options = new RadioOptionsController<CaptionsRadioGroupOption>(this, {\n setItemAttributes: (item, option) => item.setAttribute('data-track', option.value),\n onValueChange: (value) => {\n const media = this.#mediaState.value;\n\n if (media) this.#core.selectValue(media, value);\n },\n });\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n if (this.destroyed) return;\n\n if (__DEV__ && !this.#mediaState.value && this.#mediaState.displayName) {\n logMissingFeature(this.localName, this.#mediaState.displayName);\n }\n }\n\n protected override update(changed: PropertyValues): void {\n const media = this.#mediaState.value;\n let state: CaptionsRadioGroupState | null = null;\n\n if (media) {\n this.#core.setProps({ formatTrack: this.formatTrack, disabled: this.disabled, label: this.label });\n this.#core.setMedia(media);\n state = this.#core.getState();\n\n this.applyDefaultAriaLabel(translateText(this.#core.getLabel(state), this.#i18n.value));\n this.#options.sync(state, this.#i18n.value, this.#i18n.locale);\n this.publishMenuOptionState(state.disabled, state.hidden, state.availability);\n } else {\n this.publishMenuOptionState(true, true, 'unsupported');\n }\n\n super.update(changed);\n\n if (state) applyStateDataAttrs(this, state, CaptionsRadioGroupDataAttrs);\n }\n}\n\nexport namespace CaptionsRadioGroupElement {\n export type State = CaptionsRadioGroupState;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAsBA,IAAa,4BAAb,cAA+C,sBAAsB;;;EASxD,KAAA,WAAA;EACY,KAAA,QAAA;EACT,KAAA,cAAA,uBAAuB,aAAa;EAEjC,KAAA,QAAA,IAAI,uBAAuB;EAC3B,KAAA,QAAA,IAAI,eAAe,MAAM,WAAW;EAC9B,KAAA,cAAA,IAAI,iBAAiB,MAAM,eAAe,eAAe;EAC5D,KAAA,WAAA,IAAI,uBAAiD,MAAM;GAC7E,oBAAoB,MAAM,WAAW,KAAK,aAAa,cAAc,OAAO,KAAK;GACjF,gBAAgB,UAAU;IACxB,MAAM,QAAQ,KAAK,YAAY;IAE/B,IAAI,OAAO,KAAK,MAAM,YAAY,OAAO,KAAK;GAChD;EACF,CAAC;;;EAtBkC,KAAA,UAAA;;;EAEN,KAAA,aAAA;GAC3B,GAAG,sBAAsB;GACzB,UAAU,EAAE,MAAM,QAAQ;GAC1B,OAAO,EAAE,MAAM,OAAO;EACxB;;CAMA;CACA;CACA;CACA;CASA,oBAAmC;EACjC,MAAM,kBAAkB;EAExB,IAAI,KAAK,WAAW;EAEpB,IAAe,CAAC,KAAK,YAAY,SAAS,KAAK,YAAY,aACzD,kBAAkB,KAAK,WAAW,KAAK,YAAY,WAAW;CAElE;CAEA,OAA0B,SAA+B;EACvD,MAAM,QAAQ,KAAK,YAAY;EAC/B,IAAI,QAAwC;EAE5C,IAAI,OAAO;GACT,KAAK,MAAM,SAAS;IAAE,aAAa,KAAK;IAAa,UAAU,KAAK;IAAU,OAAO,KAAK;GAAM,CAAC;GACjG,KAAK,MAAM,SAAS,KAAK;GACzB,QAAQ,KAAK,MAAM,SAAS;GAE5B,KAAK,sBAAsB,cAAc,KAAK,MAAM,SAAS,KAAK,GAAG,KAAK,MAAM,KAAK,CAAC;GACtF,KAAK,SAAS,KAAK,OAAO,KAAK,MAAM,OAAO,KAAK,MAAM,MAAM;GAC7D,KAAK,uBAAuB,MAAM,UAAU,MAAM,QAAQ,MAAM,YAAY;EAC9E,OACE,KAAK,uBAAuB,MAAM,MAAM,aAAa;EAGvD,MAAM,OAAO,OAAO;EAEpB,IAAI,OAAO,oBAAoB,MAAM,OAAO,2BAA2B;CACzE;AACF"}
1
+ {"version":3,"file":"element.js","names":[],"sources":["../../../../src/ui/captions-radio-group/element.ts"],"sourcesContent":["import {\n CaptionsRadioGroupCore,\n CaptionsRadioGroupDataAttrs,\n type CaptionsRadioGroupOption,\n type CaptionsRadioGroupState,\n} from '@videojs/core';\nimport { applyStateDataAttrs, logMissingFeature, selectTextTrack } from '@videojs/core/dom';\nimport { type Text, translateText } from '@videojs/core/i18n';\nimport type { PropertyDeclarationMap, PropertyValues } from '@videojs/element';\n\nimport { i18nContext } from '../../i18n/context';\nimport { I18nController } from '../../i18n/controller';\nimport { playerContext } from '../../player/context';\nimport { PlayerController } from '../../player/controller';\nimport { MenuRadioGroupElement } from '../menu/radio-group';\nimport type { MenuRadioItemElement } from '../menu/radio-item';\nimport { RadioOptionsController } from '../radio-options/controller';\n\n/**\n * Menu radio group that generates an Off `<media-menu-radio-item>` plus one per captions and subtitles track, and\n * shares the selected label and availability with an enclosing menu. An optional `<template>` holding one\n * `<media-menu-radio-item>` customizes each generated item; its `data-part` `label` and `badge` descendants receive the\n * track's text.\n */\nexport class CaptionsRadioGroupElement extends MenuRadioGroupElement {\n static override readonly tagName = 'media-captions-radio-group';\n\n static override properties = {\n ...MenuRadioGroupElement.properties,\n disabled: { type: Boolean },\n label: { type: String },\n } satisfies PropertyDeclarationMap<'value' | 'label' | 'disabled'>;\n\n disabled = false;\n label: Text | string = '';\n formatTrack = CaptionsRadioGroupCore.defaultProps.formatTrack;\n\n readonly #core = new CaptionsRadioGroupCore();\n readonly #i18n = new I18nController(this, i18nContext);\n readonly #mediaState = new PlayerController(this, playerContext, selectTextTrack);\n readonly #options = new RadioOptionsController<CaptionsRadioGroupOption>(this, {\n renderItem: (item, label, option) => this.#setContent(item, label, option.badge),\n getOptionCacheKey: (option) => option.badge ?? '',\n setItemAttributes: (item, option) => item.setAttribute('data-track', option.value),\n onValueChange: (value) => {\n const media = this.#mediaState.value;\n\n if (media) this.#core.selectValue(media, value);\n },\n });\n\n override connectedCallback(): void {\n super.connectedCallback();\n\n if (this.destroyed) return;\n\n if (__DEV__ && !this.#mediaState.value && this.#mediaState.displayName) {\n logMissingFeature(this.localName, this.#mediaState.displayName);\n }\n }\n\n protected override update(changed: PropertyValues): void {\n const media = this.#mediaState.value;\n let state: CaptionsRadioGroupState | null = null;\n\n if (media) {\n this.#core.setProps({ formatTrack: this.formatTrack, disabled: this.disabled, label: this.label });\n this.#core.setMedia(media);\n state = this.#core.getState();\n\n this.applyDefaultAriaLabel(translateText(this.#core.getLabel(state), this.#i18n.value));\n this.#options.sync(state, this.#i18n.value, this.#i18n.locale);\n this.publishMenuOptionState(state.disabled, state.hidden, state.availability);\n } else {\n this.publishMenuOptionState(true, true, 'unsupported');\n }\n\n super.update(changed);\n\n if (state) applyStateDataAttrs(this, state, CaptionsRadioGroupDataAttrs);\n }\n\n #setContent(item: MenuRadioItemElement, label: string, badge: string | undefined): void {\n const labelPart = item.querySelector<HTMLElement>('[data-part~=\"label\"]');\n const badgePart = item.querySelector<HTMLElement>('[data-part~=\"badge\"]');\n\n if (labelPart) {\n labelPart.textContent = label;\n }\n\n if (badgePart) {\n badgePart.textContent = badge ?? '';\n badgePart.hidden = !badge;\n }\n\n if (!labelPart && !badgePart) {\n item.textContent = [label, badge].filter(Boolean).join(' ');\n }\n }\n}\n\nexport namespace CaptionsRadioGroupElement {\n export type State = CaptionsRadioGroupState;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAwBA,IAAa,4BAAb,cAA+C,sBAAsB;;;EASxD,KAAA,WAAA;EACY,KAAA,QAAA;EACT,KAAA,cAAA,uBAAuB,aAAa;EAEjC,KAAA,QAAA,IAAI,uBAAuB;EAC3B,KAAA,QAAA,IAAI,eAAe,MAAM,WAAW;EAC9B,KAAA,cAAA,IAAI,iBAAiB,MAAM,eAAe,eAAe;EAC5D,KAAA,WAAA,IAAI,uBAAiD,MAAM;GAC7E,aAAa,MAAM,OAAO,WAAW,KAAK,YAAY,MAAM,OAAO,OAAO,KAAK;GAC/E,oBAAoB,WAAW,OAAO,SAAS;GAC/C,oBAAoB,MAAM,WAAW,KAAK,aAAa,cAAc,OAAO,KAAK;GACjF,gBAAgB,UAAU;IACxB,MAAM,QAAQ,KAAK,YAAY;IAE/B,IAAI,OAAO,KAAK,MAAM,YAAY,OAAO,KAAK;GAChD;EACF,CAAC;;;EAxBkC,KAAA,UAAA;;;EAEN,KAAA,aAAA;GAC3B,GAAG,sBAAsB;GACzB,UAAU,EAAE,MAAM,QAAQ;GAC1B,OAAO,EAAE,MAAM,OAAO;EACxB;;CAMA;CACA;CACA;CACA;CAWA,oBAAmC;EACjC,MAAM,kBAAkB;EAExB,IAAI,KAAK,WAAW;EAEpB,IAAe,CAAC,KAAK,YAAY,SAAS,KAAK,YAAY,aACzD,kBAAkB,KAAK,WAAW,KAAK,YAAY,WAAW;CAElE;CAEA,OAA0B,SAA+B;EACvD,MAAM,QAAQ,KAAK,YAAY;EAC/B,IAAI,QAAwC;EAE5C,IAAI,OAAO;GACT,KAAK,MAAM,SAAS;IAAE,aAAa,KAAK;IAAa,UAAU,KAAK;IAAU,OAAO,KAAK;GAAM,CAAC;GACjG,KAAK,MAAM,SAAS,KAAK;GACzB,QAAQ,KAAK,MAAM,SAAS;GAE5B,KAAK,sBAAsB,cAAc,KAAK,MAAM,SAAS,KAAK,GAAG,KAAK,MAAM,KAAK,CAAC;GACtF,KAAK,SAAS,KAAK,OAAO,KAAK,MAAM,OAAO,KAAK,MAAM,MAAM;GAC7D,KAAK,uBAAuB,MAAM,UAAU,MAAM,QAAQ,MAAM,YAAY;EAC9E,OACE,KAAK,uBAAuB,MAAM,MAAM,aAAa;EAGvD,MAAM,OAAO,OAAO;EAEpB,IAAI,OAAO,oBAAoB,MAAM,OAAO,2BAA2B;CACzE;CAEA,YAAY,MAA4B,OAAe,OAAiC;EACtF,MAAM,YAAY,KAAK,cAA2B,wBAAsB;EACxE,MAAM,YAAY,KAAK,cAA2B,wBAAsB;EAExE,IAAI,WACF,UAAU,cAAc;EAG1B,IAAI,WAAW;GACb,UAAU,cAAc,SAAS;GACjC,UAAU,SAAS,CAAC;EACtB;EAEA,IAAI,CAAC,aAAa,CAAC,WACjB,KAAK,cAAc,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAE9D;AACF"}
@@ -3,8 +3,8 @@ import { ControlsVisibility } from "@videojs/core";
3
3
  import { PropertyValues } from "@videojs/element";
4
4
  //#region src/ui/controls/element.d.ts
5
5
  /**
6
- * Tracks controls visibility, reflects it as data attributes, and shares it with its descendant controls parts. Hiding
7
- * the controls closes any popup open inside it.
6
+ * Tracks controls visibility and whether playback has started, reflects them as data attributes, and shares them with
7
+ * its descendant controls parts. Hiding the controls closes any popup open inside it.
8
8
  */
9
9
  export declare class ControlsElement extends UIElement {
10
10
  #private;