@docyrus/shadcn 1.1.0 → 1.2.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 (766) hide show
  1. package/dist/base-lyra/accordion.js.map +1 -1
  2. package/dist/base-lyra/alert-dialog.js.map +1 -1
  3. package/dist/base-lyra/alert.js.map +1 -1
  4. package/dist/base-lyra/aspect-ratio.js.map +1 -1
  5. package/dist/base-lyra/avatar.js.map +1 -1
  6. package/dist/base-lyra/badge.js.map +1 -1
  7. package/dist/base-lyra/breadcrumb.js.map +1 -1
  8. package/dist/base-lyra/button-group.js.map +1 -1
  9. package/dist/base-lyra/button.js.map +1 -1
  10. package/dist/base-lyra/calendar.js.map +1 -1
  11. package/dist/base-lyra/card.js.map +1 -1
  12. package/dist/base-lyra/carousel.js.map +1 -1
  13. package/dist/base-lyra/chart.js.map +1 -1
  14. package/dist/base-lyra/checkbox.js.map +1 -1
  15. package/dist/base-lyra/combobox.js.map +1 -1
  16. package/dist/base-lyra/command.js.map +1 -1
  17. package/dist/base-lyra/context-menu.js.map +1 -1
  18. package/dist/base-lyra/dialog.js.map +1 -1
  19. package/dist/base-lyra/drawer.js.map +1 -1
  20. package/dist/base-lyra/dropdown-menu.js.map +1 -1
  21. package/dist/base-lyra/empty.js.map +1 -1
  22. package/dist/base-lyra/field.js.map +1 -1
  23. package/dist/base-lyra/hover-card.js.map +1 -1
  24. package/dist/base-lyra/index.js +8 -6
  25. package/dist/base-lyra/index.js.map +1 -1
  26. package/dist/base-lyra/input-group.js.map +1 -1
  27. package/dist/base-lyra/input-otp.js.map +1 -1
  28. package/dist/base-lyra/input.js.map +1 -1
  29. package/dist/base-lyra/item.js.map +1 -1
  30. package/dist/base-lyra/kbd.js.map +1 -1
  31. package/dist/base-lyra/label.js.map +1 -1
  32. package/dist/base-lyra/menubar.js.map +1 -1
  33. package/dist/base-lyra/native-select.js.map +1 -1
  34. package/dist/base-lyra/navigation-menu.js.map +1 -1
  35. package/dist/base-lyra/pagination.js.map +1 -1
  36. package/dist/base-lyra/popover.js.map +1 -1
  37. package/dist/base-lyra/progress.js.map +1 -1
  38. package/dist/base-lyra/radio-group.js.map +1 -1
  39. package/dist/base-lyra/resizable.js.map +1 -1
  40. package/dist/base-lyra/scroll-area.js.map +1 -1
  41. package/dist/base-lyra/select.js.map +1 -1
  42. package/dist/base-lyra/separator.js.map +1 -1
  43. package/dist/base-lyra/sheet.js.map +1 -1
  44. package/dist/base-lyra/sidebar.js +8 -6
  45. package/dist/base-lyra/sidebar.js.map +1 -1
  46. package/dist/base-lyra/skeleton.js.map +1 -1
  47. package/dist/base-lyra/slider.js.map +1 -1
  48. package/dist/base-lyra/spinner.js.map +1 -1
  49. package/dist/base-lyra/switch.js.map +1 -1
  50. package/dist/base-lyra/table.js.map +1 -1
  51. package/dist/base-lyra/tabs.js.map +1 -1
  52. package/dist/base-lyra/textarea.js.map +1 -1
  53. package/dist/base-lyra/toggle-group.js.map +1 -1
  54. package/dist/base-lyra/toggle.js.map +1 -1
  55. package/dist/base-lyra/tooltip.js.map +1 -1
  56. package/dist/base-maia/accordion.js.map +1 -1
  57. package/dist/base-maia/alert-dialog.js.map +1 -1
  58. package/dist/base-maia/alert.js.map +1 -1
  59. package/dist/base-maia/aspect-ratio.js.map +1 -1
  60. package/dist/base-maia/avatar.js.map +1 -1
  61. package/dist/base-maia/badge.js.map +1 -1
  62. package/dist/base-maia/breadcrumb.js.map +1 -1
  63. package/dist/base-maia/button-group.js.map +1 -1
  64. package/dist/base-maia/button.js.map +1 -1
  65. package/dist/base-maia/calendar.js.map +1 -1
  66. package/dist/base-maia/card.js.map +1 -1
  67. package/dist/base-maia/carousel.js.map +1 -1
  68. package/dist/base-maia/chart.js.map +1 -1
  69. package/dist/base-maia/checkbox.js.map +1 -1
  70. package/dist/base-maia/combobox.js.map +1 -1
  71. package/dist/base-maia/command.js.map +1 -1
  72. package/dist/base-maia/context-menu.js.map +1 -1
  73. package/dist/base-maia/dialog.js.map +1 -1
  74. package/dist/base-maia/drawer.js.map +1 -1
  75. package/dist/base-maia/dropdown-menu.js.map +1 -1
  76. package/dist/base-maia/empty.js.map +1 -1
  77. package/dist/base-maia/field.js.map +1 -1
  78. package/dist/base-maia/hover-card.js.map +1 -1
  79. package/dist/base-maia/index.js +8 -6
  80. package/dist/base-maia/index.js.map +1 -1
  81. package/dist/base-maia/input-group.js.map +1 -1
  82. package/dist/base-maia/input-otp.js.map +1 -1
  83. package/dist/base-maia/input.js.map +1 -1
  84. package/dist/base-maia/item.js.map +1 -1
  85. package/dist/base-maia/kbd.js.map +1 -1
  86. package/dist/base-maia/label.js.map +1 -1
  87. package/dist/base-maia/menubar.js.map +1 -1
  88. package/dist/base-maia/native-select.js.map +1 -1
  89. package/dist/base-maia/navigation-menu.js.map +1 -1
  90. package/dist/base-maia/pagination.js.map +1 -1
  91. package/dist/base-maia/popover.js.map +1 -1
  92. package/dist/base-maia/progress.js.map +1 -1
  93. package/dist/base-maia/radio-group.js.map +1 -1
  94. package/dist/base-maia/resizable.js.map +1 -1
  95. package/dist/base-maia/scroll-area.js.map +1 -1
  96. package/dist/base-maia/select.js.map +1 -1
  97. package/dist/base-maia/separator.js.map +1 -1
  98. package/dist/base-maia/sheet.js.map +1 -1
  99. package/dist/base-maia/sidebar.js +8 -6
  100. package/dist/base-maia/sidebar.js.map +1 -1
  101. package/dist/base-maia/skeleton.js.map +1 -1
  102. package/dist/base-maia/slider.js.map +1 -1
  103. package/dist/base-maia/spinner.js.map +1 -1
  104. package/dist/base-maia/switch.js.map +1 -1
  105. package/dist/base-maia/table.js.map +1 -1
  106. package/dist/base-maia/tabs.js.map +1 -1
  107. package/dist/base-maia/textarea.js.map +1 -1
  108. package/dist/base-maia/toggle-group.js.map +1 -1
  109. package/dist/base-maia/toggle.js.map +1 -1
  110. package/dist/base-maia/tooltip.js.map +1 -1
  111. package/dist/base-mira/accordion.js.map +1 -1
  112. package/dist/base-mira/alert-dialog.js.map +1 -1
  113. package/dist/base-mira/alert.js.map +1 -1
  114. package/dist/base-mira/aspect-ratio.js.map +1 -1
  115. package/dist/base-mira/avatar.js.map +1 -1
  116. package/dist/base-mira/badge.js.map +1 -1
  117. package/dist/base-mira/breadcrumb.js.map +1 -1
  118. package/dist/base-mira/button-group.js.map +1 -1
  119. package/dist/base-mira/button.js.map +1 -1
  120. package/dist/base-mira/calendar.js.map +1 -1
  121. package/dist/base-mira/card.js.map +1 -1
  122. package/dist/base-mira/carousel.js.map +1 -1
  123. package/dist/base-mira/chart.js.map +1 -1
  124. package/dist/base-mira/checkbox.js.map +1 -1
  125. package/dist/base-mira/combobox.js.map +1 -1
  126. package/dist/base-mira/command.js.map +1 -1
  127. package/dist/base-mira/context-menu.js.map +1 -1
  128. package/dist/base-mira/dialog.js.map +1 -1
  129. package/dist/base-mira/drawer.js.map +1 -1
  130. package/dist/base-mira/dropdown-menu.js.map +1 -1
  131. package/dist/base-mira/empty.js.map +1 -1
  132. package/dist/base-mira/field.js.map +1 -1
  133. package/dist/base-mira/hover-card.js.map +1 -1
  134. package/dist/base-mira/index.js +8 -6
  135. package/dist/base-mira/index.js.map +1 -1
  136. package/dist/base-mira/input-group.js.map +1 -1
  137. package/dist/base-mira/input-otp.js.map +1 -1
  138. package/dist/base-mira/input.js.map +1 -1
  139. package/dist/base-mira/item.js.map +1 -1
  140. package/dist/base-mira/kbd.js.map +1 -1
  141. package/dist/base-mira/label.js.map +1 -1
  142. package/dist/base-mira/menubar.js.map +1 -1
  143. package/dist/base-mira/native-select.js.map +1 -1
  144. package/dist/base-mira/navigation-menu.js.map +1 -1
  145. package/dist/base-mira/pagination.js.map +1 -1
  146. package/dist/base-mira/popover.js.map +1 -1
  147. package/dist/base-mira/progress.js.map +1 -1
  148. package/dist/base-mira/radio-group.js.map +1 -1
  149. package/dist/base-mira/resizable.js.map +1 -1
  150. package/dist/base-mira/scroll-area.js.map +1 -1
  151. package/dist/base-mira/select.js.map +1 -1
  152. package/dist/base-mira/separator.js.map +1 -1
  153. package/dist/base-mira/sheet.js.map +1 -1
  154. package/dist/base-mira/sidebar.js +8 -6
  155. package/dist/base-mira/sidebar.js.map +1 -1
  156. package/dist/base-mira/skeleton.js.map +1 -1
  157. package/dist/base-mira/slider.js.map +1 -1
  158. package/dist/base-mira/spinner.js.map +1 -1
  159. package/dist/base-mira/switch.js.map +1 -1
  160. package/dist/base-mira/table.js.map +1 -1
  161. package/dist/base-mira/tabs.js.map +1 -1
  162. package/dist/base-mira/textarea.js.map +1 -1
  163. package/dist/base-mira/toggle-group.js.map +1 -1
  164. package/dist/base-mira/toggle.js.map +1 -1
  165. package/dist/base-mira/tooltip.js.map +1 -1
  166. package/dist/base-nova/accordion.js.map +1 -1
  167. package/dist/base-nova/alert-dialog.js.map +1 -1
  168. package/dist/base-nova/alert.js.map +1 -1
  169. package/dist/base-nova/aspect-ratio.js.map +1 -1
  170. package/dist/base-nova/avatar.js.map +1 -1
  171. package/dist/base-nova/badge.js.map +1 -1
  172. package/dist/base-nova/breadcrumb.js.map +1 -1
  173. package/dist/base-nova/button-group.js.map +1 -1
  174. package/dist/base-nova/button.js.map +1 -1
  175. package/dist/base-nova/calendar.js.map +1 -1
  176. package/dist/base-nova/card.js.map +1 -1
  177. package/dist/base-nova/carousel.js.map +1 -1
  178. package/dist/base-nova/chart.js.map +1 -1
  179. package/dist/base-nova/checkbox.js.map +1 -1
  180. package/dist/base-nova/combobox.js.map +1 -1
  181. package/dist/base-nova/command.js.map +1 -1
  182. package/dist/base-nova/context-menu.js.map +1 -1
  183. package/dist/base-nova/dialog.js.map +1 -1
  184. package/dist/base-nova/drawer.js.map +1 -1
  185. package/dist/base-nova/dropdown-menu.js.map +1 -1
  186. package/dist/base-nova/empty.js.map +1 -1
  187. package/dist/base-nova/field.js.map +1 -1
  188. package/dist/base-nova/hover-card.js.map +1 -1
  189. package/dist/base-nova/index.js +8 -6
  190. package/dist/base-nova/index.js.map +1 -1
  191. package/dist/base-nova/input-group.js.map +1 -1
  192. package/dist/base-nova/input-otp.js.map +1 -1
  193. package/dist/base-nova/input.js.map +1 -1
  194. package/dist/base-nova/item.js.map +1 -1
  195. package/dist/base-nova/kbd.js.map +1 -1
  196. package/dist/base-nova/label.js.map +1 -1
  197. package/dist/base-nova/menubar.js.map +1 -1
  198. package/dist/base-nova/native-select.js.map +1 -1
  199. package/dist/base-nova/navigation-menu.js.map +1 -1
  200. package/dist/base-nova/pagination.js.map +1 -1
  201. package/dist/base-nova/popover.js.map +1 -1
  202. package/dist/base-nova/progress.js.map +1 -1
  203. package/dist/base-nova/radio-group.js.map +1 -1
  204. package/dist/base-nova/resizable.js.map +1 -1
  205. package/dist/base-nova/scroll-area.js.map +1 -1
  206. package/dist/base-nova/select.js.map +1 -1
  207. package/dist/base-nova/separator.js.map +1 -1
  208. package/dist/base-nova/sheet.js.map +1 -1
  209. package/dist/base-nova/sidebar.js +8 -6
  210. package/dist/base-nova/sidebar.js.map +1 -1
  211. package/dist/base-nova/skeleton.js.map +1 -1
  212. package/dist/base-nova/slider.js.map +1 -1
  213. package/dist/base-nova/spinner.js.map +1 -1
  214. package/dist/base-nova/switch.js.map +1 -1
  215. package/dist/base-nova/table.js.map +1 -1
  216. package/dist/base-nova/tabs.js.map +1 -1
  217. package/dist/base-nova/textarea.js.map +1 -1
  218. package/dist/base-nova/toggle-group.js.map +1 -1
  219. package/dist/base-nova/toggle.js.map +1 -1
  220. package/dist/base-nova/tooltip.js.map +1 -1
  221. package/dist/base-vega/accordion.js.map +1 -1
  222. package/dist/base-vega/alert-dialog.js.map +1 -1
  223. package/dist/base-vega/alert.js.map +1 -1
  224. package/dist/base-vega/aspect-ratio.js.map +1 -1
  225. package/dist/base-vega/avatar.js.map +1 -1
  226. package/dist/base-vega/badge.js.map +1 -1
  227. package/dist/base-vega/breadcrumb.js.map +1 -1
  228. package/dist/base-vega/button-group.js.map +1 -1
  229. package/dist/base-vega/button.js.map +1 -1
  230. package/dist/base-vega/calendar.js.map +1 -1
  231. package/dist/base-vega/card.js.map +1 -1
  232. package/dist/base-vega/carousel.js.map +1 -1
  233. package/dist/base-vega/chart.js.map +1 -1
  234. package/dist/base-vega/checkbox.js.map +1 -1
  235. package/dist/base-vega/combobox.js.map +1 -1
  236. package/dist/base-vega/command.js.map +1 -1
  237. package/dist/base-vega/context-menu.js.map +1 -1
  238. package/dist/base-vega/dialog.js.map +1 -1
  239. package/dist/base-vega/drawer.js.map +1 -1
  240. package/dist/base-vega/dropdown-menu.js.map +1 -1
  241. package/dist/base-vega/empty.js.map +1 -1
  242. package/dist/base-vega/field.js.map +1 -1
  243. package/dist/base-vega/hover-card.js.map +1 -1
  244. package/dist/base-vega/index.js +8 -6
  245. package/dist/base-vega/index.js.map +1 -1
  246. package/dist/base-vega/input-group.js.map +1 -1
  247. package/dist/base-vega/input-otp.js.map +1 -1
  248. package/dist/base-vega/input.js.map +1 -1
  249. package/dist/base-vega/item.js.map +1 -1
  250. package/dist/base-vega/kbd.js.map +1 -1
  251. package/dist/base-vega/label.js.map +1 -1
  252. package/dist/base-vega/menubar.js.map +1 -1
  253. package/dist/base-vega/native-select.js.map +1 -1
  254. package/dist/base-vega/navigation-menu.js.map +1 -1
  255. package/dist/base-vega/pagination.js.map +1 -1
  256. package/dist/base-vega/popover.js.map +1 -1
  257. package/dist/base-vega/progress.js.map +1 -1
  258. package/dist/base-vega/radio-group.js.map +1 -1
  259. package/dist/base-vega/resizable.js.map +1 -1
  260. package/dist/base-vega/scroll-area.js.map +1 -1
  261. package/dist/base-vega/select.js.map +1 -1
  262. package/dist/base-vega/separator.js.map +1 -1
  263. package/dist/base-vega/sheet.js.map +1 -1
  264. package/dist/base-vega/sidebar.js +8 -6
  265. package/dist/base-vega/sidebar.js.map +1 -1
  266. package/dist/base-vega/skeleton.js.map +1 -1
  267. package/dist/base-vega/slider.js.map +1 -1
  268. package/dist/base-vega/spinner.js.map +1 -1
  269. package/dist/base-vega/switch.js.map +1 -1
  270. package/dist/base-vega/table.js.map +1 -1
  271. package/dist/base-vega/tabs.js.map +1 -1
  272. package/dist/base-vega/textarea.js.map +1 -1
  273. package/dist/base-vega/toggle-group.js.map +1 -1
  274. package/dist/base-vega/toggle.js.map +1 -1
  275. package/dist/base-vega/tooltip.js.map +1 -1
  276. package/dist/hooks/index.d.ts +7 -0
  277. package/dist/hooks/index.js +181 -10
  278. package/dist/hooks/index.js.map +1 -1
  279. package/dist/hooks/use-as-ref.d.ts +5 -0
  280. package/dist/hooks/use-as-ref.js +17 -0
  281. package/dist/hooks/use-as-ref.js.map +1 -0
  282. package/dist/hooks/use-badge-overflow.d.ts +24 -0
  283. package/dist/hooks/use-badge-overflow.js +130 -0
  284. package/dist/hooks/use-badge-overflow.js.map +1 -0
  285. package/dist/hooks/use-callback-ref.d.ts +10 -0
  286. package/dist/hooks/use-callback-ref.js +17 -0
  287. package/dist/hooks/use-callback-ref.js.map +1 -0
  288. package/dist/hooks/use-debounced-callback.d.ts +3 -0
  289. package/dist/hooks/use-debounced-callback.js +38 -0
  290. package/dist/hooks/use-debounced-callback.js.map +1 -0
  291. package/dist/hooks/use-file-upload.d.ts +48 -0
  292. package/dist/hooks/use-file-upload.js +279 -0
  293. package/dist/hooks/use-file-upload.js.map +1 -0
  294. package/dist/hooks/use-isomorphic-layout-effect.d.ts +5 -0
  295. package/dist/hooks/use-isomorphic-layout-effect.js +8 -0
  296. package/dist/hooks/use-isomorphic-layout-effect.js.map +1 -0
  297. package/dist/hooks/use-lazy-ref.d.ts +5 -0
  298. package/dist/hooks/use-lazy-ref.js +14 -0
  299. package/dist/hooks/use-lazy-ref.js.map +1 -0
  300. package/dist/hooks/use-mobile.d.ts +1 -1
  301. package/dist/hooks/use-mobile.js +8 -6
  302. package/dist/hooks/use-mobile.js.map +1 -1
  303. package/dist/index.d.ts +1561 -57
  304. package/dist/index.js +23035 -2534
  305. package/dist/index.js.map +1 -1
  306. package/dist/lib/compose-refs.d.ts +15 -0
  307. package/dist/lib/compose-refs.js +42 -0
  308. package/dist/lib/compose-refs.js.map +1 -0
  309. package/dist/lib/format.d.ts +3 -0
  310. package/dist/lib/format.js +18 -0
  311. package/dist/lib/format.js.map +1 -0
  312. package/dist/lib/index.d.ts +3 -0
  313. package/dist/lib/index.js +53 -2
  314. package/dist/lib/index.js.map +1 -1
  315. package/dist/lib/utils.d.ts +6 -0
  316. package/dist/lib/utils.js.map +1 -1
  317. package/dist/new-york/accordion.js.map +1 -1
  318. package/dist/new-york/alert-dialog.js.map +1 -1
  319. package/dist/new-york/alert.js.map +1 -1
  320. package/dist/new-york/avatar.js.map +1 -1
  321. package/dist/new-york/badge.js.map +1 -1
  322. package/dist/new-york/breadcrumb.js.map +1 -1
  323. package/dist/new-york/button-group.js.map +1 -1
  324. package/dist/new-york/button.js.map +1 -1
  325. package/dist/new-york/calendar.js.map +1 -1
  326. package/dist/new-york/card.js.map +1 -1
  327. package/dist/new-york/carousel.js.map +1 -1
  328. package/dist/new-york/chart.js.map +1 -1
  329. package/dist/new-york/checkbox.js.map +1 -1
  330. package/dist/new-york/combobox.js.map +1 -1
  331. package/dist/new-york/command.js.map +1 -1
  332. package/dist/new-york/context-menu.js.map +1 -1
  333. package/dist/new-york/dialog.js.map +1 -1
  334. package/dist/new-york/drawer.js.map +1 -1
  335. package/dist/new-york/dropdown-menu.js.map +1 -1
  336. package/dist/new-york/empty.js.map +1 -1
  337. package/dist/new-york/field.js.map +1 -1
  338. package/dist/new-york/form.js.map +1 -1
  339. package/dist/new-york/hover-card.js.map +1 -1
  340. package/dist/new-york/index.js +8 -6
  341. package/dist/new-york/index.js.map +1 -1
  342. package/dist/new-york/input-group.js.map +1 -1
  343. package/dist/new-york/input-otp.js.map +1 -1
  344. package/dist/new-york/input.js.map +1 -1
  345. package/dist/new-york/item.js.map +1 -1
  346. package/dist/new-york/kbd.js.map +1 -1
  347. package/dist/new-york/label.js.map +1 -1
  348. package/dist/new-york/menubar.js.map +1 -1
  349. package/dist/new-york/native-select.js.map +1 -1
  350. package/dist/new-york/navigation-menu.js.map +1 -1
  351. package/dist/new-york/pagination.js.map +1 -1
  352. package/dist/new-york/popover.js.map +1 -1
  353. package/dist/new-york/progress.js.map +1 -1
  354. package/dist/new-york/radio-group.js.map +1 -1
  355. package/dist/new-york/resizable.js.map +1 -1
  356. package/dist/new-york/scroll-area.js.map +1 -1
  357. package/dist/new-york/select.js.map +1 -1
  358. package/dist/new-york/separator.js.map +1 -1
  359. package/dist/new-york/sheet.js.map +1 -1
  360. package/dist/new-york/sidebar.js +8 -6
  361. package/dist/new-york/sidebar.js.map +1 -1
  362. package/dist/new-york/skeleton.js.map +1 -1
  363. package/dist/new-york/slider.js.map +1 -1
  364. package/dist/new-york/spinner.js.map +1 -1
  365. package/dist/new-york/switch.js.map +1 -1
  366. package/dist/new-york/table.js.map +1 -1
  367. package/dist/new-york/tabs.js.map +1 -1
  368. package/dist/new-york/textarea.js.map +1 -1
  369. package/dist/new-york/toggle-group.js.map +1 -1
  370. package/dist/new-york/toggle.js.map +1 -1
  371. package/dist/new-york/tooltip.js.map +1 -1
  372. package/dist/radix-lyra/accordion.js.map +1 -1
  373. package/dist/radix-lyra/alert-dialog.js.map +1 -1
  374. package/dist/radix-lyra/alert.js.map +1 -1
  375. package/dist/radix-lyra/avatar.js.map +1 -1
  376. package/dist/radix-lyra/badge.js.map +1 -1
  377. package/dist/radix-lyra/breadcrumb.js.map +1 -1
  378. package/dist/radix-lyra/button-group.js.map +1 -1
  379. package/dist/radix-lyra/button.js.map +1 -1
  380. package/dist/radix-lyra/calendar.js.map +1 -1
  381. package/dist/radix-lyra/card.js.map +1 -1
  382. package/dist/radix-lyra/carousel.js.map +1 -1
  383. package/dist/radix-lyra/chart.js.map +1 -1
  384. package/dist/radix-lyra/checkbox.js.map +1 -1
  385. package/dist/radix-lyra/combobox.js.map +1 -1
  386. package/dist/radix-lyra/command.js.map +1 -1
  387. package/dist/radix-lyra/context-menu.js.map +1 -1
  388. package/dist/radix-lyra/dialog.js.map +1 -1
  389. package/dist/radix-lyra/drawer.js.map +1 -1
  390. package/dist/radix-lyra/dropdown-menu.js.map +1 -1
  391. package/dist/radix-lyra/empty.js.map +1 -1
  392. package/dist/radix-lyra/field.js.map +1 -1
  393. package/dist/radix-lyra/hover-card.js.map +1 -1
  394. package/dist/radix-lyra/index.js +8 -6
  395. package/dist/radix-lyra/index.js.map +1 -1
  396. package/dist/radix-lyra/input-group.js.map +1 -1
  397. package/dist/radix-lyra/input-otp.js.map +1 -1
  398. package/dist/radix-lyra/input.js.map +1 -1
  399. package/dist/radix-lyra/item.js.map +1 -1
  400. package/dist/radix-lyra/kbd.js.map +1 -1
  401. package/dist/radix-lyra/label.js.map +1 -1
  402. package/dist/radix-lyra/menubar.js.map +1 -1
  403. package/dist/radix-lyra/native-select.js.map +1 -1
  404. package/dist/radix-lyra/navigation-menu.js.map +1 -1
  405. package/dist/radix-lyra/pagination.js.map +1 -1
  406. package/dist/radix-lyra/popover.js.map +1 -1
  407. package/dist/radix-lyra/progress.js.map +1 -1
  408. package/dist/radix-lyra/radio-group.js.map +1 -1
  409. package/dist/radix-lyra/resizable.js.map +1 -1
  410. package/dist/radix-lyra/scroll-area.js.map +1 -1
  411. package/dist/radix-lyra/select.js.map +1 -1
  412. package/dist/radix-lyra/separator.js.map +1 -1
  413. package/dist/radix-lyra/sheet.js.map +1 -1
  414. package/dist/radix-lyra/sidebar.js +8 -6
  415. package/dist/radix-lyra/sidebar.js.map +1 -1
  416. package/dist/radix-lyra/skeleton.js.map +1 -1
  417. package/dist/radix-lyra/slider.js.map +1 -1
  418. package/dist/radix-lyra/spinner.js.map +1 -1
  419. package/dist/radix-lyra/switch.js.map +1 -1
  420. package/dist/radix-lyra/table.js.map +1 -1
  421. package/dist/radix-lyra/tabs.js.map +1 -1
  422. package/dist/radix-lyra/textarea.js.map +1 -1
  423. package/dist/radix-lyra/toggle-group.js.map +1 -1
  424. package/dist/radix-lyra/toggle.js.map +1 -1
  425. package/dist/radix-lyra/tooltip.js.map +1 -1
  426. package/dist/radix-maia/accordion.js.map +1 -1
  427. package/dist/radix-maia/alert-dialog.js.map +1 -1
  428. package/dist/radix-maia/alert.js.map +1 -1
  429. package/dist/radix-maia/avatar.js.map +1 -1
  430. package/dist/radix-maia/badge.js.map +1 -1
  431. package/dist/radix-maia/breadcrumb.js.map +1 -1
  432. package/dist/radix-maia/button-group.js.map +1 -1
  433. package/dist/radix-maia/button.js.map +1 -1
  434. package/dist/radix-maia/calendar.js.map +1 -1
  435. package/dist/radix-maia/card.js.map +1 -1
  436. package/dist/radix-maia/carousel.js.map +1 -1
  437. package/dist/radix-maia/chart.js.map +1 -1
  438. package/dist/radix-maia/checkbox.js.map +1 -1
  439. package/dist/radix-maia/combobox.js.map +1 -1
  440. package/dist/radix-maia/command.js.map +1 -1
  441. package/dist/radix-maia/context-menu.js.map +1 -1
  442. package/dist/radix-maia/dialog.js.map +1 -1
  443. package/dist/radix-maia/drawer.js.map +1 -1
  444. package/dist/radix-maia/dropdown-menu.js.map +1 -1
  445. package/dist/radix-maia/empty.js.map +1 -1
  446. package/dist/radix-maia/field.js.map +1 -1
  447. package/dist/radix-maia/hover-card.js.map +1 -1
  448. package/dist/radix-maia/index.js +8 -6
  449. package/dist/radix-maia/index.js.map +1 -1
  450. package/dist/radix-maia/input-group.js.map +1 -1
  451. package/dist/radix-maia/input-otp.js.map +1 -1
  452. package/dist/radix-maia/input.js.map +1 -1
  453. package/dist/radix-maia/item.js.map +1 -1
  454. package/dist/radix-maia/kbd.js.map +1 -1
  455. package/dist/radix-maia/label.js.map +1 -1
  456. package/dist/radix-maia/menubar.js.map +1 -1
  457. package/dist/radix-maia/native-select.js.map +1 -1
  458. package/dist/radix-maia/navigation-menu.js.map +1 -1
  459. package/dist/radix-maia/pagination.js.map +1 -1
  460. package/dist/radix-maia/popover.js.map +1 -1
  461. package/dist/radix-maia/progress.js.map +1 -1
  462. package/dist/radix-maia/radio-group.js.map +1 -1
  463. package/dist/radix-maia/resizable.js.map +1 -1
  464. package/dist/radix-maia/scroll-area.js.map +1 -1
  465. package/dist/radix-maia/select.js.map +1 -1
  466. package/dist/radix-maia/separator.js.map +1 -1
  467. package/dist/radix-maia/sheet.js.map +1 -1
  468. package/dist/radix-maia/sidebar.js +8 -6
  469. package/dist/radix-maia/sidebar.js.map +1 -1
  470. package/dist/radix-maia/skeleton.js.map +1 -1
  471. package/dist/radix-maia/slider.js.map +1 -1
  472. package/dist/radix-maia/spinner.js.map +1 -1
  473. package/dist/radix-maia/switch.js.map +1 -1
  474. package/dist/radix-maia/table.js.map +1 -1
  475. package/dist/radix-maia/tabs.js.map +1 -1
  476. package/dist/radix-maia/textarea.js.map +1 -1
  477. package/dist/radix-maia/toggle-group.js.map +1 -1
  478. package/dist/radix-maia/toggle.js.map +1 -1
  479. package/dist/radix-maia/tooltip.js.map +1 -1
  480. package/dist/radix-mira/accordion.js.map +1 -1
  481. package/dist/radix-mira/alert-dialog.js.map +1 -1
  482. package/dist/radix-mira/alert.js.map +1 -1
  483. package/dist/radix-mira/avatar.js.map +1 -1
  484. package/dist/radix-mira/badge.js.map +1 -1
  485. package/dist/radix-mira/breadcrumb.js.map +1 -1
  486. package/dist/radix-mira/button-group.js.map +1 -1
  487. package/dist/radix-mira/button.js.map +1 -1
  488. package/dist/radix-mira/calendar.js.map +1 -1
  489. package/dist/radix-mira/card.js.map +1 -1
  490. package/dist/radix-mira/carousel.js.map +1 -1
  491. package/dist/radix-mira/chart.js.map +1 -1
  492. package/dist/radix-mira/checkbox.js.map +1 -1
  493. package/dist/radix-mira/combobox.js.map +1 -1
  494. package/dist/radix-mira/command.js.map +1 -1
  495. package/dist/radix-mira/context-menu.js.map +1 -1
  496. package/dist/radix-mira/dialog.js.map +1 -1
  497. package/dist/radix-mira/drawer.js.map +1 -1
  498. package/dist/radix-mira/dropdown-menu.js.map +1 -1
  499. package/dist/radix-mira/empty.js.map +1 -1
  500. package/dist/radix-mira/field.js.map +1 -1
  501. package/dist/radix-mira/hover-card.js.map +1 -1
  502. package/dist/radix-mira/index.js +8 -6
  503. package/dist/radix-mira/index.js.map +1 -1
  504. package/dist/radix-mira/input-group.js.map +1 -1
  505. package/dist/radix-mira/input-otp.js.map +1 -1
  506. package/dist/radix-mira/input.js.map +1 -1
  507. package/dist/radix-mira/item.js.map +1 -1
  508. package/dist/radix-mira/kbd.js.map +1 -1
  509. package/dist/radix-mira/label.js.map +1 -1
  510. package/dist/radix-mira/menubar.js.map +1 -1
  511. package/dist/radix-mira/native-select.js.map +1 -1
  512. package/dist/radix-mira/navigation-menu.js.map +1 -1
  513. package/dist/radix-mira/pagination.js.map +1 -1
  514. package/dist/radix-mira/popover.js.map +1 -1
  515. package/dist/radix-mira/progress.js.map +1 -1
  516. package/dist/radix-mira/radio-group.js.map +1 -1
  517. package/dist/radix-mira/resizable.js.map +1 -1
  518. package/dist/radix-mira/scroll-area.js.map +1 -1
  519. package/dist/radix-mira/select.js.map +1 -1
  520. package/dist/radix-mira/separator.js.map +1 -1
  521. package/dist/radix-mira/sheet.js.map +1 -1
  522. package/dist/radix-mira/sidebar.js +8 -6
  523. package/dist/radix-mira/sidebar.js.map +1 -1
  524. package/dist/radix-mira/skeleton.js.map +1 -1
  525. package/dist/radix-mira/slider.js.map +1 -1
  526. package/dist/radix-mira/spinner.js.map +1 -1
  527. package/dist/radix-mira/switch.js.map +1 -1
  528. package/dist/radix-mira/table.js.map +1 -1
  529. package/dist/radix-mira/tabs.js.map +1 -1
  530. package/dist/radix-mira/textarea.js.map +1 -1
  531. package/dist/radix-mira/toggle-group.js.map +1 -1
  532. package/dist/radix-mira/toggle.js.map +1 -1
  533. package/dist/radix-mira/tooltip.js.map +1 -1
  534. package/dist/radix-nova/accordion.js.map +1 -1
  535. package/dist/radix-nova/alert-dialog.js.map +1 -1
  536. package/dist/radix-nova/alert.js.map +1 -1
  537. package/dist/radix-nova/avatar.js.map +1 -1
  538. package/dist/radix-nova/badge.js.map +1 -1
  539. package/dist/radix-nova/breadcrumb.js.map +1 -1
  540. package/dist/radix-nova/button-group.js.map +1 -1
  541. package/dist/radix-nova/button.js.map +1 -1
  542. package/dist/radix-nova/calendar.js.map +1 -1
  543. package/dist/radix-nova/card.js.map +1 -1
  544. package/dist/radix-nova/carousel.js.map +1 -1
  545. package/dist/radix-nova/chart.js.map +1 -1
  546. package/dist/radix-nova/checkbox.js.map +1 -1
  547. package/dist/radix-nova/combobox.js.map +1 -1
  548. package/dist/radix-nova/command.js.map +1 -1
  549. package/dist/radix-nova/context-menu.js.map +1 -1
  550. package/dist/radix-nova/dialog.js.map +1 -1
  551. package/dist/radix-nova/drawer.js.map +1 -1
  552. package/dist/radix-nova/dropdown-menu.js.map +1 -1
  553. package/dist/radix-nova/empty.js.map +1 -1
  554. package/dist/radix-nova/field.js.map +1 -1
  555. package/dist/radix-nova/hover-card.js.map +1 -1
  556. package/dist/radix-nova/index.js +8 -6
  557. package/dist/radix-nova/index.js.map +1 -1
  558. package/dist/radix-nova/input-group.js.map +1 -1
  559. package/dist/radix-nova/input-otp.js.map +1 -1
  560. package/dist/radix-nova/input.js.map +1 -1
  561. package/dist/radix-nova/item.js.map +1 -1
  562. package/dist/radix-nova/kbd.js.map +1 -1
  563. package/dist/radix-nova/label.js.map +1 -1
  564. package/dist/radix-nova/menubar.js.map +1 -1
  565. package/dist/radix-nova/native-select.js.map +1 -1
  566. package/dist/radix-nova/navigation-menu.js.map +1 -1
  567. package/dist/radix-nova/pagination.js.map +1 -1
  568. package/dist/radix-nova/popover.js.map +1 -1
  569. package/dist/radix-nova/progress.js.map +1 -1
  570. package/dist/radix-nova/radio-group.js.map +1 -1
  571. package/dist/radix-nova/resizable.js.map +1 -1
  572. package/dist/radix-nova/scroll-area.js.map +1 -1
  573. package/dist/radix-nova/select.js.map +1 -1
  574. package/dist/radix-nova/separator.js.map +1 -1
  575. package/dist/radix-nova/sheet.js.map +1 -1
  576. package/dist/radix-nova/sidebar.js +8 -6
  577. package/dist/radix-nova/sidebar.js.map +1 -1
  578. package/dist/radix-nova/skeleton.js.map +1 -1
  579. package/dist/radix-nova/slider.js.map +1 -1
  580. package/dist/radix-nova/spinner.js.map +1 -1
  581. package/dist/radix-nova/switch.js.map +1 -1
  582. package/dist/radix-nova/table.js.map +1 -1
  583. package/dist/radix-nova/tabs.js.map +1 -1
  584. package/dist/radix-nova/textarea.js.map +1 -1
  585. package/dist/radix-nova/toggle-group.js.map +1 -1
  586. package/dist/radix-nova/toggle.js.map +1 -1
  587. package/dist/radix-nova/tooltip.js.map +1 -1
  588. package/dist/radix-vega/accordion.js.map +1 -1
  589. package/dist/radix-vega/action-bar.d.ts +41 -0
  590. package/dist/radix-vega/action-bar.js +589 -0
  591. package/dist/radix-vega/action-bar.js.map +1 -0
  592. package/dist/radix-vega/alert-dialog.js.map +1 -1
  593. package/dist/radix-vega/alert.js.map +1 -1
  594. package/dist/radix-vega/avatar-group.d.ts +19 -0
  595. package/dist/radix-vega/avatar-group.js +193 -0
  596. package/dist/radix-vega/avatar-group.js.map +1 -0
  597. package/dist/radix-vega/avatar.d.ts +1 -3
  598. package/dist/radix-vega/avatar.js +1 -27
  599. package/dist/radix-vega/avatar.js.map +1 -1
  600. package/dist/radix-vega/badge-overflow.d.ts +21 -0
  601. package/dist/radix-vega/badge-overflow.js +223 -0
  602. package/dist/radix-vega/badge-overflow.js.map +1 -0
  603. package/dist/radix-vega/badge.d.ts +1 -1
  604. package/dist/radix-vega/badge.js.map +1 -1
  605. package/dist/radix-vega/breadcrumb.js.map +1 -1
  606. package/dist/radix-vega/button-group.js.map +1 -1
  607. package/dist/radix-vega/button.d.ts +2 -2
  608. package/dist/radix-vega/button.js.map +1 -1
  609. package/dist/radix-vega/calendar.js.map +1 -1
  610. package/dist/radix-vega/card.js.map +1 -1
  611. package/dist/radix-vega/carousel.js.map +1 -1
  612. package/dist/radix-vega/chart.js.map +1 -1
  613. package/dist/radix-vega/checkbox-group.d.ts +12 -0
  614. package/dist/radix-vega/checkbox-group.js +119 -0
  615. package/dist/radix-vega/checkbox-group.js.map +1 -0
  616. package/dist/radix-vega/checkbox.js.map +1 -1
  617. package/dist/radix-vega/circular-progress.d.ts +27 -0
  618. package/dist/radix-vega/circular-progress.js +252 -0
  619. package/dist/radix-vega/circular-progress.js.map +1 -0
  620. package/dist/radix-vega/color-picker.d.ts +85 -0
  621. package/dist/radix-vega/color-picker.js +1683 -0
  622. package/dist/radix-vega/color-picker.js.map +1 -0
  623. package/dist/radix-vega/color-swatch.d.ts +17 -0
  624. package/dist/radix-vega/color-swatch.js +95 -0
  625. package/dist/radix-vega/color-swatch.js.map +1 -0
  626. package/dist/radix-vega/combobox.d.ts +18 -22
  627. package/dist/radix-vega/combobox.js +118 -276
  628. package/dist/radix-vega/combobox.js.map +1 -1
  629. package/dist/radix-vega/command.js.map +1 -1
  630. package/dist/radix-vega/compare-slider.d.ts +32 -0
  631. package/dist/radix-vega/compare-slider.js +393 -0
  632. package/dist/radix-vega/compare-slider.js.map +1 -0
  633. package/dist/radix-vega/context-menu.js.map +1 -1
  634. package/dist/radix-vega/cropper.d.ts +89 -0
  635. package/dist/radix-vega/cropper.js +1396 -0
  636. package/dist/radix-vega/cropper.js.map +1 -0
  637. package/dist/radix-vega/dialog.js.map +1 -1
  638. package/dist/radix-vega/drawer.js.map +1 -1
  639. package/dist/radix-vega/dropdown-menu.js.map +1 -1
  640. package/dist/radix-vega/editable.d.ts +100 -0
  641. package/dist/radix-vega/editable.js +684 -0
  642. package/dist/radix-vega/editable.js.map +1 -0
  643. package/dist/radix-vega/empty.js.map +1 -1
  644. package/dist/radix-vega/field.js.map +1 -1
  645. package/dist/radix-vega/file-upload.d.ts +89 -0
  646. package/dist/radix-vega/file-upload.js +1089 -0
  647. package/dist/radix-vega/file-upload.js.map +1 -0
  648. package/dist/radix-vega/gauge.d.ts +27 -0
  649. package/dist/radix-vega/gauge.js +359 -0
  650. package/dist/radix-vega/gauge.js.map +1 -0
  651. package/dist/radix-vega/hover-card.js.map +1 -1
  652. package/dist/radix-vega/index.d.ts +50 -3
  653. package/dist/radix-vega/index.js +23001 -2667
  654. package/dist/radix-vega/index.js.map +1 -1
  655. package/dist/radix-vega/input-group.d.ts +1 -1
  656. package/dist/radix-vega/input-group.js.map +1 -1
  657. package/dist/radix-vega/input-otp.js.map +1 -1
  658. package/dist/radix-vega/input.js.map +1 -1
  659. package/dist/radix-vega/item.d.ts +2 -2
  660. package/dist/radix-vega/item.js.map +1 -1
  661. package/dist/radix-vega/kanban.d.ts +62 -0
  662. package/dist/radix-vega/kanban.js +831 -0
  663. package/dist/radix-vega/kanban.js.map +1 -0
  664. package/dist/radix-vega/kbd.js.map +1 -1
  665. package/dist/radix-vega/key-value.d.ts +82 -0
  666. package/dist/radix-vega/key-value.js +765 -0
  667. package/dist/radix-vega/key-value.js.map +1 -0
  668. package/dist/radix-vega/label.js.map +1 -1
  669. package/dist/radix-vega/listbox.d.ts +11 -0
  670. package/dist/radix-vega/listbox.js +90 -0
  671. package/dist/radix-vega/listbox.js.map +1 -0
  672. package/dist/radix-vega/mask-input.d.ts +64 -0
  673. package/dist/radix-vega/mask-input.js +1186 -0
  674. package/dist/radix-vega/mask-input.js.map +1 -0
  675. package/dist/radix-vega/media-player.d.ts +127 -0
  676. package/dist/radix-vega/media-player.js +2696 -0
  677. package/dist/radix-vega/media-player.js.map +1 -0
  678. package/dist/radix-vega/mention.d.ts +11 -0
  679. package/dist/radix-vega/mention.js +94 -0
  680. package/dist/radix-vega/mention.js.map +1 -0
  681. package/dist/radix-vega/menubar.js.map +1 -1
  682. package/dist/radix-vega/native-select.js.map +1 -1
  683. package/dist/radix-vega/navigation-menu.js.map +1 -1
  684. package/dist/radix-vega/pagination.js.map +1 -1
  685. package/dist/radix-vega/phone-input.d.ts +48 -0
  686. package/dist/radix-vega/phone-input.js +957 -0
  687. package/dist/radix-vega/phone-input.js.map +1 -0
  688. package/dist/radix-vega/popover.js.map +1 -1
  689. package/dist/radix-vega/progress.js.map +1 -1
  690. package/dist/radix-vega/qr-code.d.ts +53 -0
  691. package/dist/radix-vega/qr-code.js +396 -0
  692. package/dist/radix-vega/qr-code.js.map +1 -0
  693. package/dist/radix-vega/radio-group.js.map +1 -1
  694. package/dist/radix-vega/rating.d.ts +47 -0
  695. package/dist/radix-vega/rating.js +749 -0
  696. package/dist/radix-vega/rating.js.map +1 -0
  697. package/dist/radix-vega/relative-time-card.d.ts +22 -0
  698. package/dist/radix-vega/relative-time-card.js +236 -0
  699. package/dist/radix-vega/relative-time-card.js.map +1 -0
  700. package/dist/radix-vega/resizable.js.map +1 -1
  701. package/dist/radix-vega/responsive-dialog.d.ts +20 -0
  702. package/dist/radix-vega/responsive-dialog.js +483 -0
  703. package/dist/radix-vega/responsive-dialog.js.map +1 -0
  704. package/dist/radix-vega/scroll-area.js.map +1 -1
  705. package/dist/radix-vega/scroll-spy.d.ts +39 -0
  706. package/dist/radix-vega/scroll-spy.js +372 -0
  707. package/dist/radix-vega/scroll-spy.js.map +1 -0
  708. package/dist/radix-vega/scroller.d.ts +20 -0
  709. package/dist/radix-vega/scroller.js +352 -0
  710. package/dist/radix-vega/scroller.js.map +1 -0
  711. package/dist/radix-vega/segmented-input.d.ts +29 -0
  712. package/dist/radix-vega/segmented-input.js +178 -0
  713. package/dist/radix-vega/segmented-input.js.map +1 -0
  714. package/dist/radix-vega/select.js.map +1 -1
  715. package/dist/radix-vega/separator.js.map +1 -1
  716. package/dist/radix-vega/sheet.js.map +1 -1
  717. package/dist/radix-vega/sidebar.js +8 -6
  718. package/dist/radix-vega/sidebar.js.map +1 -1
  719. package/dist/radix-vega/skeleton.js.map +1 -1
  720. package/dist/radix-vega/slider.js.map +1 -1
  721. package/dist/radix-vega/sortable.d.ts +51 -0
  722. package/dist/radix-vega/sortable.js +444 -0
  723. package/dist/radix-vega/sortable.js.map +1 -0
  724. package/dist/radix-vega/speed-dial.d.ts +46 -0
  725. package/dist/radix-vega/speed-dial.js +898 -0
  726. package/dist/radix-vega/speed-dial.js.map +1 -0
  727. package/dist/radix-vega/spinner.js.map +1 -1
  728. package/dist/radix-vega/stack.d.ts +21 -0
  729. package/dist/radix-vega/stack.js +268 -0
  730. package/dist/radix-vega/stack.js.map +1 -0
  731. package/dist/radix-vega/stat.d.ts +24 -0
  732. package/dist/radix-vega/stat.js +147 -0
  733. package/dist/radix-vega/stat.js.map +1 -0
  734. package/dist/radix-vega/status.d.ts +18 -0
  735. package/dist/radix-vega/status.js +71 -0
  736. package/dist/radix-vega/status.js.map +1 -0
  737. package/dist/radix-vega/stepper.d.ts +73 -0
  738. package/dist/radix-vega/stepper.js +973 -0
  739. package/dist/radix-vega/stepper.js.map +1 -0
  740. package/dist/radix-vega/swap.d.ts +29 -0
  741. package/dist/radix-vega/swap.js +214 -0
  742. package/dist/radix-vega/swap.js.map +1 -0
  743. package/dist/radix-vega/switch.js.map +1 -1
  744. package/dist/radix-vega/table.js.map +1 -1
  745. package/dist/radix-vega/tabs.d.ts +1 -1
  746. package/dist/radix-vega/tabs.js.map +1 -1
  747. package/dist/radix-vega/tags-input.d.ts +12 -0
  748. package/dist/radix-vega/tags-input.js +98 -0
  749. package/dist/radix-vega/tags-input.js.map +1 -0
  750. package/dist/radix-vega/textarea.js.map +1 -1
  751. package/dist/radix-vega/time-picker.d.ts +88 -0
  752. package/dist/radix-vega/time-picker.js +1750 -0
  753. package/dist/radix-vega/time-picker.js.map +1 -0
  754. package/dist/radix-vega/timeline.d.ts +32 -0
  755. package/dist/radix-vega/timeline.js +611 -0
  756. package/dist/radix-vega/timeline.js.map +1 -0
  757. package/dist/radix-vega/toggle-group.js.map +1 -1
  758. package/dist/radix-vega/toggle.js.map +1 -1
  759. package/dist/radix-vega/tooltip.js.map +1 -1
  760. package/dist/radix-vega/tour.d.ts +109 -0
  761. package/dist/radix-vega/tour.js +1314 -0
  762. package/dist/radix-vega/tour.js.map +1 -0
  763. package/dist/radix-vega/visually-hidden-input.d.ts +8 -0
  764. package/dist/radix-vega/visually-hidden-input.js +33 -0
  765. package/dist/radix-vega/visually-hidden-input.js.map +1 -0
  766. package/package.json +29 -1
@@ -0,0 +1,2696 @@
1
+ import { useDirection } from '@radix-ui/react-direction';
2
+ import * as SliderPrimitive from '@radix-ui/react-slider';
3
+ import { Slot } from '@radix-ui/react-slot';
4
+ import { Loader2Icon, AlertTriangleIcon, RefreshCcwIcon, RotateCcwIcon, VolumeXIcon, Volume2Icon, Volume1Icon, PlayIcon, PauseIcon, RewindIcon, FastForwardIcon, CheckIcon, RepeatIcon, Minimize2Icon, Maximize2Icon, PictureInPicture2Icon, PictureInPictureIcon, SubtitlesIcon, CaptionsOffIcon, DownloadIcon, SettingsIcon, ChevronRightIcon } from 'lucide-react';
5
+ import { MediaProvider, useMediaFullscreenRef, useMediaDispatch, useMediaSelector, MediaActionTypes, useMediaRef, timeUtils } from 'media-chrome/react/media-store';
6
+ export { useMediaSelector as useMediaPlayer } from 'media-chrome/react/media-store';
7
+ import * as React3 from 'react';
8
+ import * as ReactDOM from 'react-dom';
9
+ import { cva } from 'class-variance-authority';
10
+ import { Slot as Slot$1, DropdownMenu as DropdownMenu$1, Tooltip as Tooltip$1 } from 'radix-ui';
11
+ import { clsx } from 'clsx';
12
+ import { twMerge } from 'tailwind-merge';
13
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
14
+
15
+ function cn(...inputs) {
16
+ return twMerge(clsx(inputs));
17
+ }
18
+ var badgeVariants = cva(
19
+ "h-5 gap-1 rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium transition-all has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&>svg]:size-3! inline-flex items-center justify-center w-fit whitespace-nowrap shrink-0 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive overflow-hidden group/badge",
20
+ {
21
+ variants: {
22
+ variant: {
23
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
24
+ secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
25
+ destructive: "bg-destructive/10 [a]:hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 text-destructive dark:bg-destructive/20",
26
+ outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
27
+ ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
28
+ link: "text-primary underline-offset-4 hover:underline"
29
+ }
30
+ },
31
+ defaultVariants: {
32
+ variant: "default"
33
+ }
34
+ }
35
+ );
36
+ function Badge({
37
+ className,
38
+ variant = "default",
39
+ asChild = false,
40
+ ...props
41
+ }) {
42
+ const Comp = asChild ? Slot$1.Root : "span";
43
+ return /* @__PURE__ */ jsx(
44
+ Comp,
45
+ {
46
+ "data-slot": "badge",
47
+ "data-variant": variant,
48
+ className: cn(badgeVariants({ variant }), className),
49
+ ...props
50
+ }
51
+ );
52
+ }
53
+ var buttonVariants = cva(
54
+ "focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 rounded-md border border-transparent bg-clip-padding text-sm font-medium focus-visible:ring-3 aria-invalid:ring-3 [&_svg:not([class*='size-'])]:size-4 inline-flex items-center justify-center whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none shrink-0 [&_svg]:shrink-0 outline-none group/button select-none",
55
+ {
56
+ variants: {
57
+ variant: {
58
+ default: "bg-primary text-primary-foreground hover:bg-primary/80",
59
+ outline: "border-border bg-background hover:bg-muted hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 aria-expanded:bg-muted aria-expanded:text-foreground shadow-xs",
60
+ secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
61
+ ghost: "hover:bg-muted hover:text-foreground dark:hover:bg-muted/50 aria-expanded:bg-muted aria-expanded:text-foreground",
62
+ destructive: "bg-destructive/10 hover:bg-destructive/20 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/20 text-destructive focus-visible:border-destructive/40 dark:hover:bg-destructive/30",
63
+ link: "text-primary underline-offset-4 hover:underline"
64
+ },
65
+ size: {
66
+ default: "h-9 gap-1.5 px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
67
+ xs: "h-6 gap-1 rounded-[min(var(--radius-md),8px)] px-2 text-xs in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
68
+ sm: "h-8 gap-1 rounded-[min(var(--radius-md),10px)] px-2.5 in-data-[slot=button-group]:rounded-md has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5",
69
+ lg: "h-10 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
70
+ icon: "size-9",
71
+ "icon-xs": "size-6 rounded-[min(var(--radius-md),8px)] in-data-[slot=button-group]:rounded-md [&_svg:not([class*='size-'])]:size-3",
72
+ "icon-sm": "size-8 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-md",
73
+ "icon-lg": "size-10"
74
+ }
75
+ },
76
+ defaultVariants: {
77
+ variant: "default",
78
+ size: "default"
79
+ }
80
+ }
81
+ );
82
+ function Button({
83
+ className,
84
+ variant = "default",
85
+ size = "default",
86
+ asChild = false,
87
+ ...props
88
+ }) {
89
+ const Comp = asChild ? Slot$1.Root : "button";
90
+ return /* @__PURE__ */ jsx(
91
+ Comp,
92
+ {
93
+ "data-slot": "button",
94
+ "data-variant": variant,
95
+ "data-size": size,
96
+ className: cn(buttonVariants({ variant, size, className })),
97
+ ...props
98
+ }
99
+ );
100
+ }
101
+ function DropdownMenu({
102
+ ...props
103
+ }) {
104
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Root, { "data-slot": "dropdown-menu", ...props });
105
+ }
106
+ function DropdownMenuTrigger({
107
+ ...props
108
+ }) {
109
+ return /* @__PURE__ */ jsx(
110
+ DropdownMenu$1.Trigger,
111
+ {
112
+ "data-slot": "dropdown-menu-trigger",
113
+ ...props
114
+ }
115
+ );
116
+ }
117
+ function DropdownMenuContent({
118
+ className,
119
+ align = "start",
120
+ sideOffset = 4,
121
+ ...props
122
+ }) {
123
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Portal, { children: /* @__PURE__ */ jsx(
124
+ DropdownMenu$1.Content,
125
+ {
126
+ "data-slot": "dropdown-menu-content",
127
+ sideOffset,
128
+ align,
129
+ className: cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground min-w-32 rounded-md p-1 shadow-md ring-1 duration-100 z-50 max-h-(--radix-dropdown-menu-content-available-height) w-(--radix-dropdown-menu-trigger-width) origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto data-[state=closed]:overflow-hidden", className),
130
+ ...props
131
+ }
132
+ ) });
133
+ }
134
+ function DropdownMenuItem({
135
+ className,
136
+ inset,
137
+ variant = "default",
138
+ ...props
139
+ }) {
140
+ return /* @__PURE__ */ jsx(
141
+ DropdownMenu$1.Item,
142
+ {
143
+ "data-slot": "dropdown-menu-item",
144
+ "data-inset": inset,
145
+ "data-variant": variant,
146
+ className: cn(
147
+ "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:text-destructive not-data-[variant=destructive]:focus:**:text-accent-foreground gap-2 rounded-sm px-2 py-1.5 text-sm data-inset:pl-8 [&_svg:not([class*='size-'])]:size-4 group/dropdown-menu-item relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
148
+ className
149
+ ),
150
+ ...props
151
+ }
152
+ );
153
+ }
154
+ function DropdownMenuLabel({
155
+ className,
156
+ inset,
157
+ ...props
158
+ }) {
159
+ return /* @__PURE__ */ jsx(
160
+ DropdownMenu$1.Label,
161
+ {
162
+ "data-slot": "dropdown-menu-label",
163
+ "data-inset": inset,
164
+ className: cn("text-muted-foreground px-2 py-1.5 text-xs font-medium data-inset:pl-8", className),
165
+ ...props
166
+ }
167
+ );
168
+ }
169
+ function DropdownMenuSub({
170
+ ...props
171
+ }) {
172
+ return /* @__PURE__ */ jsx(DropdownMenu$1.Sub, { "data-slot": "dropdown-menu-sub", ...props });
173
+ }
174
+ function DropdownMenuSubTrigger({
175
+ className,
176
+ inset,
177
+ children,
178
+ ...props
179
+ }) {
180
+ return /* @__PURE__ */ jsxs(
181
+ DropdownMenu$1.SubTrigger,
182
+ {
183
+ "data-slot": "dropdown-menu-sub-trigger",
184
+ "data-inset": inset,
185
+ className: cn(
186
+ "focus:bg-accent focus:text-accent-foreground data-open:bg-accent data-open:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground gap-2 rounded-sm px-2 py-1.5 text-sm data-inset:pl-8 [&_svg:not([class*='size-'])]:size-4 flex cursor-default items-center outline-hidden select-none [&_svg]:pointer-events-none [&_svg]:shrink-0",
187
+ className
188
+ ),
189
+ ...props,
190
+ children: [
191
+ children,
192
+ /* @__PURE__ */ jsx(ChevronRightIcon, { className: "ml-auto" })
193
+ ]
194
+ }
195
+ );
196
+ }
197
+ function DropdownMenuSubContent({
198
+ className,
199
+ ...props
200
+ }) {
201
+ return /* @__PURE__ */ jsx(
202
+ DropdownMenu$1.SubContent,
203
+ {
204
+ "data-slot": "dropdown-menu-sub-content",
205
+ className: cn("data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground min-w-[96px] rounded-md p-1 shadow-lg ring-1 duration-100 z-50 origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden", className),
206
+ ...props
207
+ }
208
+ );
209
+ }
210
+ function Tooltip({
211
+ ...props
212
+ }) {
213
+ return /* @__PURE__ */ jsx(Tooltip$1.Root, { "data-slot": "tooltip", ...props });
214
+ }
215
+ function TooltipTrigger({
216
+ ...props
217
+ }) {
218
+ return /* @__PURE__ */ jsx(Tooltip$1.Trigger, { "data-slot": "tooltip-trigger", ...props });
219
+ }
220
+ function TooltipContent({
221
+ className,
222
+ sideOffset = 0,
223
+ children,
224
+ ...props
225
+ }) {
226
+ return /* @__PURE__ */ jsx(Tooltip$1.Portal, { children: /* @__PURE__ */ jsxs(
227
+ Tooltip$1.Content,
228
+ {
229
+ "data-slot": "tooltip-content",
230
+ sideOffset,
231
+ className: cn(
232
+ "data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 rounded-md px-3 py-1.5 text-xs bg-foreground text-background z-50 w-fit max-w-xs origin-(--radix-tooltip-content-transform-origin)",
233
+ className
234
+ ),
235
+ ...props,
236
+ children: [
237
+ children,
238
+ /* @__PURE__ */ jsx(Tooltip$1.Arrow, { className: "size-2.5 rotate-45 rounded-[2px] bg-foreground fill-foreground z-50 translate-y-[calc(-50%_-_2px)]" })
239
+ ]
240
+ }
241
+ ) });
242
+ }
243
+ function setRef(ref, value) {
244
+ if (typeof ref === "function") {
245
+ return ref(value);
246
+ }
247
+ if (ref !== null && ref !== void 0) {
248
+ ref.current = value;
249
+ }
250
+ }
251
+ function composeRefs(...refs) {
252
+ return (node) => {
253
+ let hasCleanup = false;
254
+ const cleanups = refs.map((ref) => {
255
+ const cleanup = setRef(ref, node);
256
+ if (!hasCleanup && typeof cleanup === "function") {
257
+ hasCleanup = true;
258
+ }
259
+ return cleanup;
260
+ });
261
+ if (hasCleanup) {
262
+ return () => {
263
+ for (let i = 0; i < cleanups.length; i++) {
264
+ const cleanup = cleanups[i];
265
+ if (typeof cleanup === "function") {
266
+ cleanup();
267
+ } else {
268
+ setRef(refs[i], null);
269
+ }
270
+ }
271
+ };
272
+ }
273
+ };
274
+ }
275
+ function useComposedRefs(...refs) {
276
+ return React3.useCallback(composeRefs(...refs), refs);
277
+ }
278
+ function useLazyRef(fn) {
279
+ const ref = React3.useRef(null);
280
+ if (ref.current === null) {
281
+ ref.current = fn();
282
+ }
283
+ return ref;
284
+ }
285
+ var ROOT_NAME = "MediaPlayer";
286
+ var SEEK_NAME = "MediaPlayerSeek";
287
+ var SETTINGS_NAME = "MediaPlayerSettings";
288
+ var VOLUME_NAME = "MediaPlayerVolume";
289
+ var PLAYBACK_SPEED_NAME = "MediaPlayerPlaybackSpeed";
290
+ var FLOATING_MENU_SIDE_OFFSET = 10;
291
+ var SPEEDS = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
292
+ var SEEK_STEP_SHORT = 5;
293
+ var SEEK_STEP_LONG = 10;
294
+ var SEEK_COLLISION_PADDING = 10;
295
+ var SEEK_TOOLTIP_WIDTH_FALLBACK = 240;
296
+ var SEEK_HOVER_PERCENT = "--seek-hover-percent";
297
+ var SEEK_TOOLTIP_X = "--seek-tooltip-x";
298
+ var SEEK_TOOLTIP_Y = "--seek-tooltip-y";
299
+ var SPRITE_CONTAINER_WIDTH = 224;
300
+ var SPRITE_CONTAINER_HEIGHT = 128;
301
+ var StoreContext = React3.createContext(null);
302
+ function useStoreContext(consumerName) {
303
+ const context = React3.useContext(StoreContext);
304
+ if (!context) {
305
+ throw new Error(`\`${consumerName}\` must be used within \`${ROOT_NAME}\``);
306
+ }
307
+ return context;
308
+ }
309
+ function useStore(selector) {
310
+ const store = useStoreContext("useStore");
311
+ const getSnapshot = React3.useCallback(
312
+ () => selector(store.getState()),
313
+ [store, selector]
314
+ );
315
+ return React3.useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);
316
+ }
317
+ var MediaPlayerContext = React3.createContext(
318
+ null
319
+ );
320
+ function useMediaPlayerContext(consumerName) {
321
+ const context = React3.useContext(MediaPlayerContext);
322
+ if (!context) {
323
+ throw new Error(`\`${consumerName}\` must be used within \`${ROOT_NAME}\``);
324
+ }
325
+ return context;
326
+ }
327
+ function MediaPlayer(props) {
328
+ const listenersRef = useLazyRef(() => /* @__PURE__ */ new Set());
329
+ const stateRef = useLazyRef(() => ({
330
+ controlsVisible: true,
331
+ dragging: false,
332
+ menuOpen: false,
333
+ volumeIndicatorVisible: false
334
+ }));
335
+ const store = React3.useMemo(() => {
336
+ return {
337
+ subscribe: (cb) => {
338
+ listenersRef.current.add(cb);
339
+ return () => listenersRef.current.delete(cb);
340
+ },
341
+ getState: () => stateRef.current,
342
+ setState: (key, value) => {
343
+ if (Object.is(stateRef.current[key], value)) return;
344
+ stateRef.current[key] = value;
345
+ store.notify();
346
+ },
347
+ notify: () => {
348
+ for (const cb of listenersRef.current) {
349
+ cb();
350
+ }
351
+ }
352
+ };
353
+ }, [listenersRef, stateRef]);
354
+ return /* @__PURE__ */ jsx(MediaProvider, { children: /* @__PURE__ */ jsx(StoreContext.Provider, { value: store, children: /* @__PURE__ */ jsx(MediaPlayerImpl, { ...props }) }) });
355
+ }
356
+ function MediaPlayerImpl(props) {
357
+ const {
358
+ onPlay,
359
+ onPause,
360
+ onEnded,
361
+ onTimeUpdate,
362
+ onFullscreenChange,
363
+ onVolumeChange,
364
+ onMuted,
365
+ onMediaError,
366
+ onPipError,
367
+ dir: dirProp,
368
+ label,
369
+ tooltipDelayDuration = 600,
370
+ tooltipSideOffset = FLOATING_MENU_SIDE_OFFSET,
371
+ asChild,
372
+ autoHide = false,
373
+ disabled = false,
374
+ withoutTooltip = false,
375
+ children,
376
+ className,
377
+ ref,
378
+ ...rootImplProps
379
+ } = props;
380
+ const mediaId = React3.useId();
381
+ const labelId = React3.useId();
382
+ const descriptionId = React3.useId();
383
+ const rootRef = React3.useRef(null);
384
+ const fullscreenRef = useMediaFullscreenRef();
385
+ const composedRef = useComposedRefs(ref, rootRef, fullscreenRef);
386
+ const dir = useDirection(dirProp);
387
+ const dispatch = useMediaDispatch();
388
+ const mediaRef = React3.useRef(
389
+ null
390
+ );
391
+ const store = useStoreContext(ROOT_NAME);
392
+ const controlsVisible = useStore((state) => state.controlsVisible);
393
+ const dragging = useStore((state) => state.dragging);
394
+ const menuOpen = useStore((state) => state.menuOpen);
395
+ const hideControlsTimeoutRef = React3.useRef(null);
396
+ const lastMouseMoveRef = React3.useRef(Date.now());
397
+ const volumeIndicatorTimeoutRef = React3.useRef(null);
398
+ const mediaPaused = useMediaSelector((state) => state.mediaPaused ?? true);
399
+ const isFullscreen = useMediaSelector(
400
+ (state) => state.mediaIsFullscreen ?? false
401
+ );
402
+ const [mounted, setMounted] = React3.useState(false);
403
+ React3.useLayoutEffect(() => {
404
+ setMounted(true);
405
+ }, []);
406
+ const portalContainer = mounted ? isFullscreen ? rootRef.current : globalThis.document.body : null;
407
+ const isVideo = typeof HTMLVideoElement !== "undefined" && mediaRef.current instanceof HTMLVideoElement || mediaRef.current?.tagName?.toLowerCase() === "mux-player";
408
+ const onControlsShow = React3.useCallback(() => {
409
+ store.setState("controlsVisible", true);
410
+ lastMouseMoveRef.current = Date.now();
411
+ if (hideControlsTimeoutRef.current) {
412
+ clearTimeout(hideControlsTimeoutRef.current);
413
+ }
414
+ if (autoHide && !mediaPaused && !menuOpen && !dragging) {
415
+ hideControlsTimeoutRef.current = setTimeout(() => {
416
+ store.setState("controlsVisible", false);
417
+ }, 3e3);
418
+ }
419
+ }, [store.setState, autoHide, mediaPaused, menuOpen, dragging]);
420
+ const onVolumeIndicatorTrigger = React3.useCallback(() => {
421
+ if (menuOpen) return;
422
+ store.setState("volumeIndicatorVisible", true);
423
+ if (volumeIndicatorTimeoutRef.current) {
424
+ clearTimeout(volumeIndicatorTimeoutRef.current);
425
+ }
426
+ volumeIndicatorTimeoutRef.current = setTimeout(() => {
427
+ store.setState("volumeIndicatorVisible", false);
428
+ }, 2e3);
429
+ if (autoHide) {
430
+ onControlsShow();
431
+ }
432
+ }, [store.setState, menuOpen, autoHide, onControlsShow]);
433
+ const onMouseLeave = React3.useCallback(
434
+ (event) => {
435
+ rootImplProps.onMouseLeave?.(event);
436
+ if (event.defaultPrevented) return;
437
+ if (autoHide && !mediaPaused && !menuOpen && !dragging) {
438
+ store.setState("controlsVisible", false);
439
+ }
440
+ },
441
+ [
442
+ store.setState,
443
+ rootImplProps.onMouseLeave,
444
+ autoHide,
445
+ mediaPaused,
446
+ menuOpen,
447
+ dragging
448
+ ]
449
+ );
450
+ const onMouseMove = React3.useCallback(
451
+ (event) => {
452
+ rootImplProps.onMouseMove?.(event);
453
+ if (event.defaultPrevented) return;
454
+ if (autoHide) {
455
+ onControlsShow();
456
+ }
457
+ },
458
+ [autoHide, rootImplProps.onMouseMove, onControlsShow]
459
+ );
460
+ React3.useEffect(() => {
461
+ if (mediaPaused || menuOpen || dragging) {
462
+ store.setState("controlsVisible", true);
463
+ if (hideControlsTimeoutRef.current) {
464
+ clearTimeout(hideControlsTimeoutRef.current);
465
+ }
466
+ return;
467
+ }
468
+ if (autoHide) {
469
+ onControlsShow();
470
+ }
471
+ }, [
472
+ store.setState,
473
+ onControlsShow,
474
+ autoHide,
475
+ menuOpen,
476
+ mediaPaused,
477
+ dragging
478
+ ]);
479
+ const onKeyDown = React3.useCallback(
480
+ (event) => {
481
+ if (disabled) return;
482
+ rootImplProps.onKeyDown?.(event);
483
+ if (event.defaultPrevented) return;
484
+ const mediaElement = mediaRef.current;
485
+ if (!mediaElement) return;
486
+ const isMediaFocused = document.activeElement === mediaElement;
487
+ const isPlayerFocused = document.activeElement?.closest('[data-slot="media-player"]') !== null;
488
+ if (!isMediaFocused && !isPlayerFocused) return;
489
+ if (autoHide) onControlsShow();
490
+ switch (event.key.toLowerCase()) {
491
+ case " ":
492
+ case "k":
493
+ event.preventDefault();
494
+ dispatch({
495
+ type: mediaElement.paused ? MediaActionTypes.MEDIA_PLAY_REQUEST : MediaActionTypes.MEDIA_PAUSE_REQUEST
496
+ });
497
+ break;
498
+ case "f":
499
+ event.preventDefault();
500
+ dispatch({
501
+ type: document.fullscreenElement ? MediaActionTypes.MEDIA_EXIT_FULLSCREEN_REQUEST : MediaActionTypes.MEDIA_ENTER_FULLSCREEN_REQUEST
502
+ });
503
+ break;
504
+ case "m": {
505
+ event.preventDefault();
506
+ if (isVideo) {
507
+ onVolumeIndicatorTrigger();
508
+ }
509
+ dispatch({
510
+ type: mediaElement.muted ? MediaActionTypes.MEDIA_UNMUTE_REQUEST : MediaActionTypes.MEDIA_MUTE_REQUEST
511
+ });
512
+ break;
513
+ }
514
+ case "arrowright":
515
+ event.preventDefault();
516
+ if (isVideo || mediaElement instanceof HTMLAudioElement && event.shiftKey) {
517
+ dispatch({
518
+ type: MediaActionTypes.MEDIA_SEEK_REQUEST,
519
+ detail: Math.min(
520
+ mediaElement.duration,
521
+ mediaElement.currentTime + SEEK_STEP_SHORT
522
+ )
523
+ });
524
+ }
525
+ break;
526
+ case "arrowleft":
527
+ event.preventDefault();
528
+ if (isVideo || mediaElement instanceof HTMLAudioElement && event.shiftKey) {
529
+ dispatch({
530
+ type: MediaActionTypes.MEDIA_SEEK_REQUEST,
531
+ detail: Math.max(0, mediaElement.currentTime - SEEK_STEP_SHORT)
532
+ });
533
+ }
534
+ break;
535
+ case "arrowup":
536
+ event.preventDefault();
537
+ if (isVideo) {
538
+ onVolumeIndicatorTrigger();
539
+ dispatch({
540
+ type: MediaActionTypes.MEDIA_VOLUME_REQUEST,
541
+ detail: Math.min(1, mediaElement.volume + 0.1)
542
+ });
543
+ }
544
+ break;
545
+ case "arrowdown":
546
+ event.preventDefault();
547
+ if (isVideo) {
548
+ onVolumeIndicatorTrigger();
549
+ dispatch({
550
+ type: MediaActionTypes.MEDIA_VOLUME_REQUEST,
551
+ detail: Math.max(0, mediaElement.volume - 0.1)
552
+ });
553
+ }
554
+ break;
555
+ case "<": {
556
+ event.preventDefault();
557
+ const currentRate = mediaElement.playbackRate;
558
+ const currentIndex = SPEEDS.indexOf(currentRate);
559
+ const newIndex = Math.max(0, currentIndex - 1);
560
+ const newRate = SPEEDS[newIndex] ?? 1;
561
+ dispatch({
562
+ type: MediaActionTypes.MEDIA_PLAYBACK_RATE_REQUEST,
563
+ detail: newRate
564
+ });
565
+ break;
566
+ }
567
+ case ">": {
568
+ event.preventDefault();
569
+ const currentRate = mediaElement.playbackRate;
570
+ const currentIndex = SPEEDS.indexOf(currentRate);
571
+ const newIndex = Math.min(SPEEDS.length - 1, currentIndex + 1);
572
+ const newRate = SPEEDS[newIndex] ?? 1;
573
+ dispatch({
574
+ type: MediaActionTypes.MEDIA_PLAYBACK_RATE_REQUEST,
575
+ detail: newRate
576
+ });
577
+ break;
578
+ }
579
+ case "c":
580
+ event.preventDefault();
581
+ if (isVideo && mediaElement.textTracks.length > 0) {
582
+ dispatch({
583
+ type: MediaActionTypes.MEDIA_TOGGLE_SUBTITLES_REQUEST
584
+ });
585
+ }
586
+ break;
587
+ case "d": {
588
+ const hasDownload = mediaElement.querySelector(
589
+ '[data-slot="media-player-download"]'
590
+ );
591
+ if (!hasDownload) break;
592
+ event.preventDefault();
593
+ if (mediaElement.currentSrc) {
594
+ const link = document.createElement("a");
595
+ link.href = mediaElement.currentSrc;
596
+ link.download = "";
597
+ document.body.appendChild(link);
598
+ link.click();
599
+ document.body.removeChild(link);
600
+ }
601
+ break;
602
+ }
603
+ case "p": {
604
+ event.preventDefault();
605
+ if (isVideo && "requestPictureInPicture" in mediaElement) {
606
+ const isPip = document.pictureInPictureElement === mediaElement;
607
+ dispatch({
608
+ type: isPip ? MediaActionTypes.MEDIA_EXIT_PIP_REQUEST : MediaActionTypes.MEDIA_ENTER_PIP_REQUEST
609
+ });
610
+ if (isPip) {
611
+ document.exitPictureInPicture().catch((error) => {
612
+ onPipError?.(error, "exit");
613
+ });
614
+ } else {
615
+ mediaElement.requestPictureInPicture().catch((error) => {
616
+ onPipError?.(error, "enter");
617
+ });
618
+ }
619
+ }
620
+ break;
621
+ }
622
+ case "r": {
623
+ event.preventDefault();
624
+ mediaElement.loop = !mediaElement.loop;
625
+ break;
626
+ }
627
+ case "j": {
628
+ event.preventDefault();
629
+ dispatch({
630
+ type: MediaActionTypes.MEDIA_SEEK_REQUEST,
631
+ detail: Math.max(0, mediaElement.currentTime - SEEK_STEP_LONG)
632
+ });
633
+ break;
634
+ }
635
+ case "l": {
636
+ event.preventDefault();
637
+ dispatch({
638
+ type: MediaActionTypes.MEDIA_SEEK_REQUEST,
639
+ detail: Math.min(
640
+ mediaElement.duration,
641
+ mediaElement.currentTime + SEEK_STEP_LONG
642
+ )
643
+ });
644
+ break;
645
+ }
646
+ case "0":
647
+ case "1":
648
+ case "2":
649
+ case "3":
650
+ case "4":
651
+ case "5":
652
+ case "6":
653
+ case "7":
654
+ case "8":
655
+ case "9": {
656
+ event.preventDefault();
657
+ const percent = Number.parseInt(event.key, 10) / 10;
658
+ const seekTime = mediaElement.duration * percent;
659
+ dispatch({
660
+ type: MediaActionTypes.MEDIA_SEEK_REQUEST,
661
+ detail: seekTime
662
+ });
663
+ break;
664
+ }
665
+ case "home": {
666
+ event.preventDefault();
667
+ dispatch({
668
+ type: MediaActionTypes.MEDIA_SEEK_REQUEST,
669
+ detail: 0
670
+ });
671
+ break;
672
+ }
673
+ case "end": {
674
+ event.preventDefault();
675
+ dispatch({
676
+ type: MediaActionTypes.MEDIA_SEEK_REQUEST,
677
+ detail: mediaElement.duration
678
+ });
679
+ break;
680
+ }
681
+ }
682
+ },
683
+ [
684
+ dispatch,
685
+ rootImplProps.onKeyDown,
686
+ onVolumeIndicatorTrigger,
687
+ onPipError,
688
+ disabled,
689
+ isVideo,
690
+ onControlsShow,
691
+ autoHide
692
+ ]
693
+ );
694
+ const onKeyUp = React3.useCallback(
695
+ (event) => {
696
+ rootImplProps.onKeyUp?.(event);
697
+ const key = event.key.toLowerCase();
698
+ if (key === "arrowup" || key === "arrowdown" || key === "m") {
699
+ onVolumeIndicatorTrigger();
700
+ }
701
+ },
702
+ [rootImplProps.onKeyUp, onVolumeIndicatorTrigger]
703
+ );
704
+ React3.useEffect(() => {
705
+ const mediaElement = mediaRef.current;
706
+ if (!mediaElement) return;
707
+ if (onPlay) mediaElement.addEventListener("play", onPlay);
708
+ if (onPause) mediaElement.addEventListener("pause", onPause);
709
+ if (onEnded) mediaElement.addEventListener("ended", onEnded);
710
+ if (onTimeUpdate)
711
+ mediaElement.addEventListener(
712
+ "timeupdate",
713
+ () => onTimeUpdate?.(mediaElement.currentTime)
714
+ );
715
+ if (onVolumeChange)
716
+ mediaElement.addEventListener("volumechange", () => {
717
+ onVolumeChange?.(mediaElement.volume);
718
+ onMuted?.(mediaElement.muted);
719
+ });
720
+ if (onMediaError)
721
+ mediaElement.addEventListener(
722
+ "error",
723
+ () => onMediaError?.(mediaElement.error)
724
+ );
725
+ if (onFullscreenChange) {
726
+ document.addEventListener(
727
+ "fullscreenchange",
728
+ () => onFullscreenChange?.(!!document.fullscreenElement)
729
+ );
730
+ }
731
+ return () => {
732
+ if (onPlay) mediaElement.removeEventListener("play", onPlay);
733
+ if (onPause) mediaElement.removeEventListener("pause", onPause);
734
+ if (onEnded) mediaElement.removeEventListener("ended", onEnded);
735
+ if (onTimeUpdate)
736
+ mediaElement.removeEventListener(
737
+ "timeupdate",
738
+ () => onTimeUpdate?.(mediaElement.currentTime)
739
+ );
740
+ if (onVolumeChange)
741
+ mediaElement.removeEventListener("volumechange", () => {
742
+ onVolumeChange?.(mediaElement.volume);
743
+ onMuted?.(mediaElement.muted);
744
+ });
745
+ if (onMediaError)
746
+ mediaElement.removeEventListener(
747
+ "error",
748
+ () => onMediaError?.(mediaElement.error)
749
+ );
750
+ if (onFullscreenChange) {
751
+ document.removeEventListener(
752
+ "fullscreenchange",
753
+ () => onFullscreenChange?.(!!document.fullscreenElement)
754
+ );
755
+ }
756
+ if (volumeIndicatorTimeoutRef.current) {
757
+ clearTimeout(volumeIndicatorTimeoutRef.current);
758
+ }
759
+ if (hideControlsTimeoutRef.current) {
760
+ clearTimeout(hideControlsTimeoutRef.current);
761
+ }
762
+ };
763
+ }, [
764
+ onPlay,
765
+ onPause,
766
+ onEnded,
767
+ onTimeUpdate,
768
+ onVolumeChange,
769
+ onMuted,
770
+ onMediaError,
771
+ onFullscreenChange
772
+ ]);
773
+ const contextValue = React3.useMemo(
774
+ () => ({
775
+ mediaId,
776
+ labelId,
777
+ descriptionId,
778
+ dir,
779
+ rootRef,
780
+ mediaRef,
781
+ portalContainer,
782
+ tooltipDelayDuration,
783
+ tooltipSideOffset,
784
+ disabled,
785
+ isVideo,
786
+ withoutTooltip
787
+ }),
788
+ [
789
+ mediaId,
790
+ labelId,
791
+ descriptionId,
792
+ dir,
793
+ portalContainer,
794
+ tooltipDelayDuration,
795
+ tooltipSideOffset,
796
+ disabled,
797
+ isVideo,
798
+ withoutTooltip
799
+ ]
800
+ );
801
+ const RootPrimitive = asChild ? Slot : "div";
802
+ return /* @__PURE__ */ jsx(MediaPlayerContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
803
+ RootPrimitive,
804
+ {
805
+ "aria-labelledby": labelId,
806
+ "aria-describedby": descriptionId,
807
+ "aria-disabled": disabled,
808
+ "data-disabled": disabled ? "" : void 0,
809
+ "data-controls-visible": controlsVisible ? "" : void 0,
810
+ "data-slot": "media-player",
811
+ "data-state": isFullscreen ? "fullscreen" : "windowed",
812
+ dir,
813
+ tabIndex: disabled ? void 0 : 0,
814
+ ...rootImplProps,
815
+ ref: composedRef,
816
+ onMouseLeave,
817
+ onMouseMove,
818
+ onKeyDown,
819
+ onKeyUp,
820
+ className: cn(
821
+ "dark relative isolate flex flex-col overflow-hidden rounded-lg bg-background outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_video]:relative [&_video]:object-contain",
822
+ "in-[:fullscreen]:flex in-[:fullscreen]:h-full in-[:fullscreen]:max-h-screen in-[:fullscreen]:flex-col in-[:fullscreen]:justify-between data-[state=fullscreen]:[&_video]:size-full",
823
+ "**:data-slider:relative [&_[data-slider]::before]:absolute [&_[data-slider]::before]:inset-x-0 [&_[data-slider]::before]:-top-4 [&_[data-slider]::before]:-bottom-2 [&_[data-slider]::before]:z-10 [&_[data-slider]::before]:h-8 [&_[data-slider]::before]:cursor-pointer [&_[data-slider]::before]:content-[''] [&_[data-slot='media-player-seek']:not([data-hovering])::before]:cursor-default",
824
+ "[&_video::-webkit-media-text-track-display]:top-auto! [&_video::-webkit-media-text-track-display]:bottom-[4%]! [&_video::-webkit-media-text-track-display]:mb-0! data-[state=fullscreen]:data-controls-visible:[&_video::-webkit-media-text-track-display]:bottom-[9%]! data-[state=fullscreen]:[&_video::-webkit-media-text-track-display]:bottom-[7%]! data-controls-visible:[&_video::-webkit-media-text-track-display]:bottom-[13%]!",
825
+ className
826
+ ),
827
+ children: [
828
+ /* @__PURE__ */ jsx("span", { id: labelId, className: "sr-only", children: label ?? "Media player" }),
829
+ /* @__PURE__ */ jsx("span", { id: descriptionId, className: "sr-only", children: isVideo ? "Video player with custom controls for playback, volume, seeking, and more. Use space bar to play/pause, arrow keys (\u2190/\u2192) to seek, and arrow keys (\u2191/\u2193) to adjust volume." : "Audio player with custom controls for playback, volume, seeking, and more. Use space bar to play/pause, Shift + arrow keys (\u2190/\u2192) to seek, and arrow keys (\u2191/\u2193) to adjust volume." }),
830
+ children,
831
+ /* @__PURE__ */ jsx(MediaPlayerVolumeIndicator, {})
832
+ ]
833
+ }
834
+ ) });
835
+ }
836
+ function MediaPlayerVideo(props) {
837
+ const { asChild, ref, ...videoProps } = props;
838
+ const context = useMediaPlayerContext("MediaPlayerVideo");
839
+ const dispatch = useMediaDispatch();
840
+ const mediaRefCallback = useMediaRef();
841
+ const composedRef = useComposedRefs(ref, context.mediaRef, mediaRefCallback);
842
+ const onPlayToggle = React3.useCallback(
843
+ (event) => {
844
+ props.onClick?.(event);
845
+ if (event.defaultPrevented) return;
846
+ const mediaElement = event.currentTarget;
847
+ if (!mediaElement) return;
848
+ dispatch({
849
+ type: mediaElement.paused ? MediaActionTypes.MEDIA_PLAY_REQUEST : MediaActionTypes.MEDIA_PAUSE_REQUEST
850
+ });
851
+ },
852
+ [dispatch, props.onClick]
853
+ );
854
+ const VideoPrimitive = asChild ? Slot : "video";
855
+ return /* @__PURE__ */ jsx(
856
+ VideoPrimitive,
857
+ {
858
+ "aria-describedby": context.descriptionId,
859
+ "aria-labelledby": context.labelId,
860
+ "data-slot": "media-player-video",
861
+ ...videoProps,
862
+ id: context.mediaId,
863
+ ref: composedRef,
864
+ onClick: onPlayToggle
865
+ }
866
+ );
867
+ }
868
+ function MediaPlayerAudio(props) {
869
+ const { asChild, ref, ...audioProps } = props;
870
+ const context = useMediaPlayerContext("MediaPlayerAudio");
871
+ const mediaRefCallback = useMediaRef();
872
+ const composedRef = useComposedRefs(ref, context.mediaRef, mediaRefCallback);
873
+ const AudioPrimitive = asChild ? Slot : "audio";
874
+ return /* @__PURE__ */ jsx(
875
+ AudioPrimitive,
876
+ {
877
+ "aria-describedby": context.descriptionId,
878
+ "aria-labelledby": context.labelId,
879
+ "data-slot": "media-player-audio",
880
+ ...audioProps,
881
+ id: context.mediaId,
882
+ ref: composedRef
883
+ }
884
+ );
885
+ }
886
+ function MediaPlayerControls(props) {
887
+ const { asChild, className, ...controlsProps } = props;
888
+ const context = useMediaPlayerContext("MediaPlayerControls");
889
+ const isFullscreen = useMediaSelector(
890
+ (state) => state.mediaIsFullscreen ?? false
891
+ );
892
+ const controlsVisible = useStore((state) => state.controlsVisible);
893
+ const ControlsPrimitive = asChild ? Slot : "div";
894
+ return /* @__PURE__ */ jsx(
895
+ ControlsPrimitive,
896
+ {
897
+ "data-disabled": context.disabled ? "" : void 0,
898
+ "data-slot": "media-player-controls",
899
+ "data-state": isFullscreen ? "fullscreen" : "windowed",
900
+ "data-visible": controlsVisible ? "" : void 0,
901
+ dir: context.dir,
902
+ className: cn(
903
+ "dark pointer-events-none absolute right-0 bottom-0 left-0 z-50 flex items-center gap-2 in-[:fullscreen]:px-6 px-4 in-[:fullscreen]:py-4 py-3 opacity-0 transition-opacity duration-200 data-visible:pointer-events-auto data-visible:opacity-100",
904
+ className
905
+ ),
906
+ ...controlsProps
907
+ }
908
+ );
909
+ }
910
+ function MediaPlayerLoading(props) {
911
+ const {
912
+ delayMs = 500,
913
+ asChild,
914
+ className,
915
+ children,
916
+ ...loadingProps
917
+ } = props;
918
+ const isLoading = useMediaSelector((state) => state.mediaLoading ?? false);
919
+ const isPaused = useMediaSelector((state) => state.mediaPaused ?? true);
920
+ const hasPlayed = useMediaSelector((state) => state.mediaHasPlayed ?? false);
921
+ const shouldShowLoading = isLoading && !isPaused;
922
+ const shouldUseDelay = hasPlayed && shouldShowLoading;
923
+ const loadingDelayMs = shouldUseDelay ? delayMs : 0;
924
+ const [shouldRender, setShouldRender] = React3.useState(false);
925
+ const timeoutRef = React3.useRef(null);
926
+ React3.useEffect(() => {
927
+ if (timeoutRef.current) {
928
+ clearTimeout(timeoutRef.current);
929
+ timeoutRef.current = null;
930
+ }
931
+ if (shouldShowLoading) {
932
+ if (loadingDelayMs > 0) {
933
+ timeoutRef.current = setTimeout(() => {
934
+ setShouldRender(true);
935
+ timeoutRef.current = null;
936
+ }, loadingDelayMs);
937
+ } else {
938
+ setShouldRender(true);
939
+ }
940
+ } else {
941
+ setShouldRender(false);
942
+ }
943
+ return () => {
944
+ if (timeoutRef.current) {
945
+ clearTimeout(timeoutRef.current);
946
+ timeoutRef.current = null;
947
+ }
948
+ };
949
+ }, [shouldShowLoading, loadingDelayMs]);
950
+ if (!shouldRender) return null;
951
+ const LoadingPrimitive = asChild ? Slot : "div";
952
+ return /* @__PURE__ */ jsx(
953
+ LoadingPrimitive,
954
+ {
955
+ role: "status",
956
+ "aria-live": "polite",
957
+ "data-slot": "media-player-loading",
958
+ ...loadingProps,
959
+ className: cn(
960
+ "fade-in-0 zoom-in-95 pointer-events-none absolute inset-0 z-50 flex animate-in items-center justify-center duration-200",
961
+ className
962
+ ),
963
+ children: children ?? /* @__PURE__ */ jsx(Loader2Icon, { className: "size-20 animate-spin stroke-[.0938rem] text-primary" })
964
+ }
965
+ );
966
+ }
967
+ function MediaPlayerError(props) {
968
+ const {
969
+ error: errorProp,
970
+ label,
971
+ description,
972
+ onRetry: onRetryProp,
973
+ onReload: onReloadProp,
974
+ asChild,
975
+ className,
976
+ children,
977
+ ...errorProps
978
+ } = props;
979
+ const context = useMediaPlayerContext("MediaPlayerError");
980
+ const isFullscreen = useMediaSelector(
981
+ (state) => state.mediaIsFullscreen ?? false
982
+ );
983
+ const mediaError = useMediaSelector((state) => state.mediaError);
984
+ const error = errorProp ?? mediaError;
985
+ const labelId = React3.useId();
986
+ const descriptionId = React3.useId();
987
+ const [actionState, setActionState] = React3.useState({
988
+ retryPending: false,
989
+ reloadPending: false
990
+ });
991
+ const onRetry = React3.useCallback(() => {
992
+ setActionState((prev) => ({ ...prev, retryPending: true }));
993
+ requestAnimationFrame(() => {
994
+ const mediaElement = context.mediaRef.current;
995
+ if (!mediaElement) {
996
+ setActionState((prev) => ({ ...prev, retryPending: false }));
997
+ return;
998
+ }
999
+ if (onRetryProp) {
1000
+ onRetryProp();
1001
+ } else {
1002
+ const currentSrc = mediaElement.currentSrc ?? mediaElement.src;
1003
+ if (currentSrc) {
1004
+ mediaElement.load();
1005
+ }
1006
+ }
1007
+ setActionState((prev) => ({ ...prev, retryPending: false }));
1008
+ });
1009
+ }, [context.mediaRef, onRetryProp]);
1010
+ const onReload = React3.useCallback(() => {
1011
+ setActionState((prev) => ({ ...prev, reloadPending: true }));
1012
+ requestAnimationFrame(() => {
1013
+ if (onReloadProp) {
1014
+ onReloadProp();
1015
+ } else {
1016
+ window.location.reload();
1017
+ }
1018
+ });
1019
+ }, [onReloadProp]);
1020
+ const errorLabel = React3.useMemo(() => {
1021
+ if (label) return label;
1022
+ if (!error) return "Playback Error";
1023
+ const labelMap = {
1024
+ [MediaError.MEDIA_ERR_ABORTED]: "Playback Interrupted",
1025
+ [MediaError.MEDIA_ERR_NETWORK]: "Connection Problem",
1026
+ [MediaError.MEDIA_ERR_DECODE]: "Media Error",
1027
+ [MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED]: "Unsupported Format"
1028
+ };
1029
+ return labelMap[error.code] ?? "Playback Error";
1030
+ }, [label, error]);
1031
+ const errorDescription = React3.useMemo(() => {
1032
+ if (description) return description;
1033
+ if (!error) return "An unknown error occurred";
1034
+ const descriptionMap = {
1035
+ [MediaError.MEDIA_ERR_ABORTED]: "Media playback was aborted",
1036
+ [MediaError.MEDIA_ERR_NETWORK]: "A network error occurred while loading the media",
1037
+ [MediaError.MEDIA_ERR_DECODE]: "An error occurred while decoding the media",
1038
+ [MediaError.MEDIA_ERR_SRC_NOT_SUPPORTED]: "The media format is not supported"
1039
+ };
1040
+ return descriptionMap[error.code] ?? "An unknown error occurred";
1041
+ }, [description, error]);
1042
+ if (!error) return null;
1043
+ const ErrorPrimitive = asChild ? Slot : "div";
1044
+ return /* @__PURE__ */ jsx(
1045
+ ErrorPrimitive,
1046
+ {
1047
+ role: "alert",
1048
+ "aria-describedby": descriptionId,
1049
+ "aria-labelledby": labelId,
1050
+ "aria-live": "assertive",
1051
+ "data-slot": "media-player-error",
1052
+ "data-state": isFullscreen ? "fullscreen" : "windowed",
1053
+ ...errorProps,
1054
+ className: cn(
1055
+ "pointer-events-auto absolute inset-0 z-50 flex flex-col items-center justify-center bg-black/80 text-white backdrop-blur-sm",
1056
+ className
1057
+ ),
1058
+ children: children ?? /* @__PURE__ */ jsxs("div", { className: "flex max-w-md flex-col items-center gap-4 px-6 py-8 text-center", children: [
1059
+ /* @__PURE__ */ jsx(AlertTriangleIcon, { className: "size-12 text-destructive" }),
1060
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-px text-center", children: [
1061
+ /* @__PURE__ */ jsx("h3", { className: "font-semibold text-xl tracking-tight", children: errorLabel }),
1062
+ /* @__PURE__ */ jsx("p", { className: "text-balance text-muted-foreground text-sm leading-relaxed", children: errorDescription })
1063
+ ] }),
1064
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1065
+ /* @__PURE__ */ jsxs(
1066
+ Button,
1067
+ {
1068
+ variant: "secondary",
1069
+ size: "sm",
1070
+ onClick: onRetry,
1071
+ disabled: actionState.retryPending,
1072
+ children: [
1073
+ actionState.retryPending ? /* @__PURE__ */ jsx(Loader2Icon, { className: "animate-spin" }) : /* @__PURE__ */ jsx(RefreshCcwIcon, {}),
1074
+ "Try again"
1075
+ ]
1076
+ }
1077
+ ),
1078
+ /* @__PURE__ */ jsxs(
1079
+ Button,
1080
+ {
1081
+ variant: "outline",
1082
+ size: "sm",
1083
+ onClick: onReload,
1084
+ disabled: actionState.reloadPending,
1085
+ children: [
1086
+ actionState.reloadPending ? /* @__PURE__ */ jsx(Loader2Icon, { className: "animate-spin" }) : /* @__PURE__ */ jsx(RotateCcwIcon, {}),
1087
+ "Reload page"
1088
+ ]
1089
+ }
1090
+ )
1091
+ ] })
1092
+ ] })
1093
+ }
1094
+ );
1095
+ }
1096
+ function MediaPlayerVolumeIndicator(props) {
1097
+ const { asChild, className, ...indicatorProps } = props;
1098
+ const mediaVolume = useMediaSelector((state) => state.mediaVolume ?? 1);
1099
+ const mediaMuted = useMediaSelector((state) => state.mediaMuted ?? false);
1100
+ const mediaVolumeLevel = useMediaSelector(
1101
+ (state) => state.mediaVolumeLevel ?? "high"
1102
+ );
1103
+ const volumeIndicatorVisible = useStore(
1104
+ (state) => state.volumeIndicatorVisible
1105
+ );
1106
+ if (!volumeIndicatorVisible) return null;
1107
+ const effectiveVolume = mediaMuted ? 0 : mediaVolume;
1108
+ const volumePercentage = Math.round(effectiveVolume * 100);
1109
+ const barCount = 10;
1110
+ const activeBarCount = Math.ceil(effectiveVolume * barCount);
1111
+ const VolumeIndicatorPrimitive = asChild ? Slot : "div";
1112
+ return /* @__PURE__ */ jsx(
1113
+ VolumeIndicatorPrimitive,
1114
+ {
1115
+ role: "status",
1116
+ "aria-live": "polite",
1117
+ "aria-label": `Volume ${mediaMuted ? "muted" : `${volumePercentage}%`}`,
1118
+ "data-slot": "media-player-volume-indicator",
1119
+ ...indicatorProps,
1120
+ className: cn(
1121
+ "pointer-events-none absolute inset-0 z-50 flex items-center justify-center",
1122
+ className
1123
+ ),
1124
+ children: /* @__PURE__ */ jsxs("div", { className: "fade-in-0 zoom-in-95 flex animate-in flex-col items-center gap-3 rounded-lg bg-black/30 px-6 py-4 text-white backdrop-blur-xs duration-200", children: [
1125
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1126
+ mediaVolumeLevel === "off" || mediaMuted ? /* @__PURE__ */ jsx(VolumeXIcon, { className: "size-6" }) : mediaVolumeLevel === "high" ? /* @__PURE__ */ jsx(Volume2Icon, { className: "size-6" }) : /* @__PURE__ */ jsx(Volume1Icon, { className: "size-6" }),
1127
+ /* @__PURE__ */ jsx("span", { className: "font-medium text-sm tabular-nums", children: mediaMuted ? "Muted" : `${volumePercentage}%` })
1128
+ ] }),
1129
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: Array.from({ length: barCount }, (_, index) => /* @__PURE__ */ jsx(
1130
+ "div",
1131
+ {
1132
+ className: cn(
1133
+ "w-1.5 rounded-full transition-all duration-150",
1134
+ index < activeBarCount && !mediaMuted ? "scale-100 bg-white" : "scale-90 bg-white/30"
1135
+ ),
1136
+ style: {
1137
+ height: `${12 + index * 2}px`,
1138
+ animationDelay: `${index * 50}ms`
1139
+ }
1140
+ },
1141
+ index
1142
+ )) })
1143
+ ] })
1144
+ }
1145
+ );
1146
+ }
1147
+ function MediaPlayerControlsOverlay(props) {
1148
+ const { asChild, className, ...overlayProps } = props;
1149
+ const isFullscreen = useMediaSelector(
1150
+ (state) => state.mediaIsFullscreen ?? false
1151
+ );
1152
+ const controlsVisible = useStore((state) => state.controlsVisible);
1153
+ const OverlayPrimitive = asChild ? Slot : "div";
1154
+ return /* @__PURE__ */ jsx(
1155
+ OverlayPrimitive,
1156
+ {
1157
+ "data-slot": "media-player-controls-overlay",
1158
+ "data-state": isFullscreen ? "fullscreen" : "windowed",
1159
+ "data-visible": controlsVisible ? "" : void 0,
1160
+ ...overlayProps,
1161
+ className: cn(
1162
+ "pointer-events-none absolute inset-0 -z-10 bg-linear-to-t from-black/80 to-transparent opacity-0 transition-opacity duration-200 data-visible:opacity-100",
1163
+ className
1164
+ )
1165
+ }
1166
+ );
1167
+ }
1168
+ function MediaPlayerPlay(props) {
1169
+ const { children, className, disabled, ...playButtonProps } = props;
1170
+ const context = useMediaPlayerContext("MediaPlayerPlay");
1171
+ const dispatch = useMediaDispatch();
1172
+ const mediaPaused = useMediaSelector((state) => state.mediaPaused ?? true);
1173
+ const isDisabled = disabled || context.disabled;
1174
+ const onPlayToggle = React3.useCallback(
1175
+ (event) => {
1176
+ props.onClick?.(event);
1177
+ if (event.defaultPrevented) return;
1178
+ dispatch({
1179
+ type: mediaPaused ? MediaActionTypes.MEDIA_PLAY_REQUEST : MediaActionTypes.MEDIA_PAUSE_REQUEST
1180
+ });
1181
+ },
1182
+ [dispatch, props.onClick, mediaPaused]
1183
+ );
1184
+ return /* @__PURE__ */ jsx(
1185
+ MediaPlayerTooltip,
1186
+ {
1187
+ tooltip: mediaPaused ? "Play" : "Pause",
1188
+ shortcut: "Space",
1189
+ children: /* @__PURE__ */ jsx(
1190
+ Button,
1191
+ {
1192
+ type: "button",
1193
+ "aria-controls": context.mediaId,
1194
+ "aria-label": mediaPaused ? "Play" : "Pause",
1195
+ "aria-pressed": !mediaPaused,
1196
+ "data-disabled": isDisabled ? "" : void 0,
1197
+ "data-slot": "media-player-play-button",
1198
+ "data-state": mediaPaused ? "off" : "on",
1199
+ disabled: isDisabled,
1200
+ ...playButtonProps,
1201
+ variant: "ghost",
1202
+ size: "icon",
1203
+ className: cn(
1204
+ "size-8 [&_svg:not([class*='fill-'])]:fill-current",
1205
+ className
1206
+ ),
1207
+ onClick: onPlayToggle,
1208
+ children: children ?? (mediaPaused ? /* @__PURE__ */ jsx(PlayIcon, {}) : /* @__PURE__ */ jsx(PauseIcon, {}))
1209
+ }
1210
+ )
1211
+ }
1212
+ );
1213
+ }
1214
+ function MediaPlayerSeekBackward(props) {
1215
+ const {
1216
+ seconds = SEEK_STEP_SHORT,
1217
+ children,
1218
+ className,
1219
+ disabled,
1220
+ ...seekBackwardProps
1221
+ } = props;
1222
+ const context = useMediaPlayerContext("MediaPlayerSeekBackward");
1223
+ const dispatch = useMediaDispatch();
1224
+ const mediaCurrentTime = useMediaSelector(
1225
+ (state) => state.mediaCurrentTime ?? 0
1226
+ );
1227
+ const isDisabled = disabled || context.disabled;
1228
+ const onSeekBackward = React3.useCallback(
1229
+ (event) => {
1230
+ props.onClick?.(event);
1231
+ if (event.defaultPrevented) return;
1232
+ dispatch({
1233
+ type: MediaActionTypes.MEDIA_SEEK_REQUEST,
1234
+ detail: Math.max(0, mediaCurrentTime - seconds)
1235
+ });
1236
+ },
1237
+ [dispatch, props.onClick, mediaCurrentTime, seconds]
1238
+ );
1239
+ return /* @__PURE__ */ jsx(
1240
+ MediaPlayerTooltip,
1241
+ {
1242
+ tooltip: `Back ${seconds}s`,
1243
+ shortcut: context.isVideo ? ["\u2190"] : ["Shift \u2190"],
1244
+ children: /* @__PURE__ */ jsx(
1245
+ Button,
1246
+ {
1247
+ type: "button",
1248
+ "aria-controls": context.mediaId,
1249
+ "aria-label": `Back ${seconds} seconds`,
1250
+ "data-disabled": isDisabled ? "" : void 0,
1251
+ "data-slot": "media-player-seek-backward",
1252
+ disabled: isDisabled,
1253
+ ...seekBackwardProps,
1254
+ variant: "ghost",
1255
+ size: "icon",
1256
+ className: cn("size-8", className),
1257
+ onClick: onSeekBackward,
1258
+ children: children ?? /* @__PURE__ */ jsx(RewindIcon, {})
1259
+ }
1260
+ )
1261
+ }
1262
+ );
1263
+ }
1264
+ function MediaPlayerSeekForward(props) {
1265
+ const {
1266
+ seconds = SEEK_STEP_LONG,
1267
+ children,
1268
+ className,
1269
+ disabled,
1270
+ ...seekForwardProps
1271
+ } = props;
1272
+ const context = useMediaPlayerContext("MediaPlayerSeekForward");
1273
+ const dispatch = useMediaDispatch();
1274
+ const mediaCurrentTime = useMediaSelector(
1275
+ (state) => state.mediaCurrentTime ?? 0
1276
+ );
1277
+ const [, seekableEnd] = useMediaSelector(
1278
+ (state) => state.mediaSeekable ?? [0, 0]
1279
+ );
1280
+ const isDisabled = disabled || context.disabled;
1281
+ const onSeekForward = React3.useCallback(
1282
+ (event) => {
1283
+ props.onClick?.(event);
1284
+ if (event.defaultPrevented) return;
1285
+ dispatch({
1286
+ type: MediaActionTypes.MEDIA_SEEK_REQUEST,
1287
+ detail: Math.min(
1288
+ seekableEnd ?? Number.POSITIVE_INFINITY,
1289
+ mediaCurrentTime + seconds
1290
+ )
1291
+ });
1292
+ },
1293
+ [dispatch, props.onClick, mediaCurrentTime, seekableEnd, seconds]
1294
+ );
1295
+ return /* @__PURE__ */ jsx(
1296
+ MediaPlayerTooltip,
1297
+ {
1298
+ tooltip: `Forward ${seconds}s`,
1299
+ shortcut: context.isVideo ? ["\u2192"] : ["Shift \u2192"],
1300
+ children: /* @__PURE__ */ jsx(
1301
+ Button,
1302
+ {
1303
+ type: "button",
1304
+ "aria-controls": context.mediaId,
1305
+ "aria-label": `Forward ${seconds} seconds`,
1306
+ "data-disabled": isDisabled ? "" : void 0,
1307
+ "data-slot": "media-player-seek-forward",
1308
+ disabled: isDisabled,
1309
+ ...seekForwardProps,
1310
+ variant: "ghost",
1311
+ size: "icon",
1312
+ className: cn("size-8", className),
1313
+ onClick: onSeekForward,
1314
+ children: children ?? /* @__PURE__ */ jsx(FastForwardIcon, {})
1315
+ }
1316
+ )
1317
+ }
1318
+ );
1319
+ }
1320
+ function MediaPlayerSeek(props) {
1321
+ const {
1322
+ withTime = false,
1323
+ withoutChapter = false,
1324
+ withoutTooltip = false,
1325
+ tooltipTimeVariant = "current",
1326
+ tooltipThumbnailSrc,
1327
+ tooltipSideOffset,
1328
+ tooltipCollisionPadding = SEEK_COLLISION_PADDING,
1329
+ tooltipCollisionBoundary,
1330
+ className,
1331
+ disabled,
1332
+ ...seekProps
1333
+ } = props;
1334
+ const context = useMediaPlayerContext(SEEK_NAME);
1335
+ const store = useStoreContext(SEEK_NAME);
1336
+ const dispatch = useMediaDispatch();
1337
+ const mediaCurrentTime = useMediaSelector(
1338
+ (state) => state.mediaCurrentTime ?? 0
1339
+ );
1340
+ const [seekableStart = 0, seekableEnd = 0] = useMediaSelector(
1341
+ (state) => state.mediaSeekable ?? [0, 0]
1342
+ );
1343
+ const mediaBuffered = useMediaSelector((state) => state.mediaBuffered ?? []);
1344
+ const mediaEnded = useMediaSelector((state) => state.mediaEnded ?? false);
1345
+ const chapterCues = useMediaSelector(
1346
+ (state) => state.mediaChaptersCues ?? []
1347
+ );
1348
+ const mediaPreviewTime = useMediaSelector((state) => state.mediaPreviewTime);
1349
+ const mediaPreviewImage = useMediaSelector(
1350
+ (state) => state.mediaPreviewImage
1351
+ );
1352
+ const mediaPreviewCoords = useMediaSelector(
1353
+ (state) => state.mediaPreviewCoords
1354
+ );
1355
+ const seekRef = React3.useRef(null);
1356
+ const tooltipRef = React3.useRef(null);
1357
+ const justCommittedRef = React3.useRef(false);
1358
+ const hoverTimeRef = React3.useRef(0);
1359
+ const tooltipXRef = React3.useRef(0);
1360
+ const tooltipYRef = React3.useRef(0);
1361
+ const seekRectRef = React3.useRef(null);
1362
+ const collisionDataRef = React3.useRef(null);
1363
+ const [seekState, setSeekState] = React3.useState({
1364
+ isHovering: false,
1365
+ pendingSeekTime: null,
1366
+ hasInitialPosition: false
1367
+ });
1368
+ const rafIdRef = React3.useRef(null);
1369
+ const seekThrottleRef = React3.useRef(null);
1370
+ const hoverTimeoutRef = React3.useRef(null);
1371
+ const lastPointerXRef = React3.useRef(0);
1372
+ const lastPointerYRef = React3.useRef(0);
1373
+ const previewDebounceRef = React3.useRef(null);
1374
+ const pointerEnterTimeRef = React3.useRef(0);
1375
+ const horizontalMovementRef = React3.useRef(0);
1376
+ const verticalMovementRef = React3.useRef(0);
1377
+ const lastSeekCommitTimeRef = React3.useRef(0);
1378
+ const timeCache = React3.useRef(/* @__PURE__ */ new Map());
1379
+ const displayValue = seekState.pendingSeekTime ?? mediaCurrentTime;
1380
+ const isDisabled = disabled || context.disabled;
1381
+ const tooltipDisabled = withoutTooltip || context.withoutTooltip || store.getState().menuOpen;
1382
+ const currentTooltipSideOffset = tooltipSideOffset ?? context.tooltipSideOffset;
1383
+ const getCachedTime = React3.useCallback((time, duration2) => {
1384
+ const roundedTime = Math.floor(time);
1385
+ const key = roundedTime + duration2 * 1e4;
1386
+ if (timeCache.current.has(key)) {
1387
+ return timeCache.current.get(key);
1388
+ }
1389
+ const formatted = timeUtils.formatTime(time, duration2);
1390
+ timeCache.current.set(key, formatted);
1391
+ if (timeCache.current.size > 100) {
1392
+ timeCache.current.clear();
1393
+ }
1394
+ return formatted;
1395
+ }, []);
1396
+ const currentTime = getCachedTime(displayValue, seekableEnd);
1397
+ const duration = getCachedTime(seekableEnd, seekableEnd);
1398
+ const remainingTime = getCachedTime(seekableEnd - displayValue, seekableEnd);
1399
+ const onCollisionDataUpdate = React3.useCallback(() => {
1400
+ if (collisionDataRef.current) return collisionDataRef.current;
1401
+ const padding = typeof tooltipCollisionPadding === "number" ? {
1402
+ top: tooltipCollisionPadding,
1403
+ right: tooltipCollisionPadding,
1404
+ bottom: tooltipCollisionPadding,
1405
+ left: tooltipCollisionPadding
1406
+ } : { top: 0, right: 0, bottom: 0, left: 0, ...tooltipCollisionPadding };
1407
+ const boundaries = tooltipCollisionBoundary ? Array.isArray(tooltipCollisionBoundary) ? tooltipCollisionBoundary : [tooltipCollisionBoundary] : [context.rootRef.current].filter(Boolean);
1408
+ collisionDataRef.current = { padding, boundaries };
1409
+ return collisionDataRef.current;
1410
+ }, [tooltipCollisionPadding, tooltipCollisionBoundary, context.rootRef]);
1411
+ const getCurrentChapterCue = React3.useCallback(
1412
+ (time) => {
1413
+ if (withoutChapter || chapterCues.length === 0) return null;
1414
+ return chapterCues.find((c) => time >= c.startTime && time < c.endTime);
1415
+ },
1416
+ [chapterCues, withoutChapter]
1417
+ );
1418
+ const getThumbnail = React3.useCallback(
1419
+ (time) => {
1420
+ if (tooltipDisabled) return null;
1421
+ if (tooltipThumbnailSrc) {
1422
+ const src = typeof tooltipThumbnailSrc === "function" ? tooltipThumbnailSrc(time) : tooltipThumbnailSrc;
1423
+ return { src, coords: null };
1424
+ }
1425
+ if (mediaPreviewTime !== void 0 && Math.abs(time - mediaPreviewTime) < 0.1 && mediaPreviewImage) {
1426
+ return {
1427
+ src: mediaPreviewImage,
1428
+ coords: mediaPreviewCoords ?? null
1429
+ };
1430
+ }
1431
+ return null;
1432
+ },
1433
+ [
1434
+ tooltipThumbnailSrc,
1435
+ mediaPreviewTime,
1436
+ mediaPreviewImage,
1437
+ mediaPreviewCoords,
1438
+ tooltipDisabled
1439
+ ]
1440
+ );
1441
+ const onPreviewUpdate = React3.useCallback(
1442
+ (time) => {
1443
+ if (tooltipDisabled) return;
1444
+ if (previewDebounceRef.current) {
1445
+ cancelAnimationFrame(previewDebounceRef.current);
1446
+ }
1447
+ previewDebounceRef.current = requestAnimationFrame(() => {
1448
+ dispatch({
1449
+ type: MediaActionTypes.MEDIA_PREVIEW_REQUEST,
1450
+ detail: time
1451
+ });
1452
+ previewDebounceRef.current = null;
1453
+ });
1454
+ },
1455
+ [dispatch, tooltipDisabled]
1456
+ );
1457
+ const onTooltipPositionUpdate = React3.useCallback(
1458
+ (clientX) => {
1459
+ if (!seekRef.current) return;
1460
+ const tooltipWidth = tooltipRef.current?.offsetWidth ?? SEEK_TOOLTIP_WIDTH_FALLBACK;
1461
+ let x = clientX;
1462
+ const y = seekRectRef.current?.top ?? 0;
1463
+ const collisionData = onCollisionDataUpdate();
1464
+ const halfTooltipWidth = tooltipWidth / 2;
1465
+ let minLeft = 0;
1466
+ let maxRight = window.innerWidth;
1467
+ for (const boundary of collisionData.boundaries) {
1468
+ const boundaryRect = boundary.getBoundingClientRect();
1469
+ minLeft = Math.max(
1470
+ minLeft,
1471
+ boundaryRect.left + collisionData.padding.left
1472
+ );
1473
+ maxRight = Math.min(
1474
+ maxRight,
1475
+ boundaryRect.right - collisionData.padding.right
1476
+ );
1477
+ }
1478
+ if (x - halfTooltipWidth < minLeft) {
1479
+ x = minLeft + halfTooltipWidth;
1480
+ } else if (x + halfTooltipWidth > maxRight) {
1481
+ x = maxRight - halfTooltipWidth;
1482
+ }
1483
+ const viewportPadding = SEEK_COLLISION_PADDING;
1484
+ if (x - halfTooltipWidth < viewportPadding) {
1485
+ x = viewportPadding + halfTooltipWidth;
1486
+ } else if (x + halfTooltipWidth > window.innerWidth - viewportPadding) {
1487
+ x = window.innerWidth - viewportPadding - halfTooltipWidth;
1488
+ }
1489
+ tooltipXRef.current = x;
1490
+ tooltipYRef.current = y;
1491
+ if (tooltipRef.current) {
1492
+ tooltipRef.current.style.setProperty(SEEK_TOOLTIP_X, `${x}px`);
1493
+ tooltipRef.current.style.setProperty(SEEK_TOOLTIP_Y, `${y}px`);
1494
+ }
1495
+ if (!seekState.hasInitialPosition) {
1496
+ setSeekState((prev) => ({ ...prev, hasInitialPosition: true }));
1497
+ }
1498
+ },
1499
+ [onCollisionDataUpdate, seekState.hasInitialPosition]
1500
+ );
1501
+ const onHoverProgressUpdate = React3.useCallback(() => {
1502
+ if (!seekRef.current || seekableEnd <= 0) return;
1503
+ const hoverPercent = Math.min(
1504
+ 100,
1505
+ hoverTimeRef.current / seekableEnd * 100
1506
+ );
1507
+ seekRef.current.style.setProperty(
1508
+ SEEK_HOVER_PERCENT,
1509
+ `${hoverPercent.toFixed(4)}%`
1510
+ );
1511
+ }, [seekableEnd]);
1512
+ React3.useEffect(() => {
1513
+ if (seekState.pendingSeekTime !== null) {
1514
+ const diff = Math.abs(mediaCurrentTime - seekState.pendingSeekTime);
1515
+ if (diff < 0.5) {
1516
+ setSeekState((prev) => ({ ...prev, pendingSeekTime: null }));
1517
+ }
1518
+ }
1519
+ }, [mediaCurrentTime, seekState.pendingSeekTime]);
1520
+ React3.useEffect(() => {
1521
+ if (!seekState.isHovering || tooltipDisabled) return;
1522
+ function onScroll() {
1523
+ setSeekState((prev) => ({
1524
+ ...prev,
1525
+ isHovering: false,
1526
+ hasInitialPosition: false
1527
+ }));
1528
+ dispatch({
1529
+ type: MediaActionTypes.MEDIA_PREVIEW_REQUEST,
1530
+ detail: void 0
1531
+ });
1532
+ }
1533
+ document.addEventListener("scroll", onScroll, { passive: true });
1534
+ return () => {
1535
+ document.removeEventListener("scroll", onScroll);
1536
+ };
1537
+ }, [dispatch, seekState.isHovering, tooltipDisabled]);
1538
+ const bufferedProgress = React3.useMemo(() => {
1539
+ if (mediaBuffered.length === 0 || seekableEnd <= 0) return 0;
1540
+ if (mediaEnded) return 1;
1541
+ const containingRange = mediaBuffered.find(
1542
+ ([start, end]) => start <= mediaCurrentTime && mediaCurrentTime <= end
1543
+ );
1544
+ if (containingRange) {
1545
+ return Math.min(1, containingRange[1] / seekableEnd);
1546
+ }
1547
+ return Math.min(1, seekableStart / seekableEnd);
1548
+ }, [mediaBuffered, mediaCurrentTime, seekableEnd, mediaEnded, seekableStart]);
1549
+ const onPointerEnter = React3.useCallback(() => {
1550
+ if (seekRef.current) {
1551
+ seekRectRef.current = seekRef.current.getBoundingClientRect();
1552
+ }
1553
+ collisionDataRef.current = null;
1554
+ pointerEnterTimeRef.current = Date.now();
1555
+ horizontalMovementRef.current = 0;
1556
+ verticalMovementRef.current = 0;
1557
+ if (seekableEnd > 0) {
1558
+ if (hoverTimeoutRef.current) {
1559
+ clearTimeout(hoverTimeoutRef.current);
1560
+ }
1561
+ if (!tooltipDisabled) {
1562
+ if (lastPointerXRef.current && seekRectRef.current) {
1563
+ const clientX = Math.max(
1564
+ seekRectRef.current.left,
1565
+ Math.min(lastPointerXRef.current, seekRectRef.current.right)
1566
+ );
1567
+ onTooltipPositionUpdate(clientX);
1568
+ }
1569
+ }
1570
+ }
1571
+ }, [seekableEnd, onTooltipPositionUpdate, tooltipDisabled]);
1572
+ const onPointerLeave = React3.useCallback(() => {
1573
+ if (hoverTimeoutRef.current) {
1574
+ clearTimeout(hoverTimeoutRef.current);
1575
+ hoverTimeoutRef.current = null;
1576
+ }
1577
+ if (rafIdRef.current) {
1578
+ cancelAnimationFrame(rafIdRef.current);
1579
+ rafIdRef.current = null;
1580
+ }
1581
+ if (previewDebounceRef.current) {
1582
+ cancelAnimationFrame(previewDebounceRef.current);
1583
+ previewDebounceRef.current = null;
1584
+ }
1585
+ setSeekState((prev) => ({
1586
+ ...prev,
1587
+ isHovering: false,
1588
+ hasInitialPosition: false
1589
+ }));
1590
+ justCommittedRef.current = false;
1591
+ seekRectRef.current = null;
1592
+ collisionDataRef.current = null;
1593
+ pointerEnterTimeRef.current = 0;
1594
+ horizontalMovementRef.current = 0;
1595
+ verticalMovementRef.current = 0;
1596
+ lastPointerXRef.current = 0;
1597
+ lastPointerYRef.current = 0;
1598
+ lastSeekCommitTimeRef.current = 0;
1599
+ if (!tooltipDisabled) {
1600
+ dispatch({
1601
+ type: MediaActionTypes.MEDIA_PREVIEW_REQUEST,
1602
+ detail: void 0
1603
+ });
1604
+ }
1605
+ }, [dispatch, tooltipDisabled]);
1606
+ const onPointerMove = React3.useCallback(
1607
+ (event) => {
1608
+ if (seekableEnd <= 0) return;
1609
+ if (!seekRectRef.current && seekRef.current) {
1610
+ seekRectRef.current = seekRef.current.getBoundingClientRect();
1611
+ }
1612
+ if (!seekRectRef.current) return;
1613
+ const currentX = event.clientX;
1614
+ const currentY = event.clientY;
1615
+ if (lastPointerXRef.current !== 0 && lastPointerYRef.current !== 0) {
1616
+ const deltaX = Math.abs(currentX - lastPointerXRef.current);
1617
+ const deltaY = Math.abs(currentY - lastPointerYRef.current);
1618
+ horizontalMovementRef.current += deltaX;
1619
+ verticalMovementRef.current += deltaY;
1620
+ }
1621
+ lastPointerXRef.current = currentX;
1622
+ lastPointerYRef.current = currentY;
1623
+ if (rafIdRef.current) {
1624
+ cancelAnimationFrame(rafIdRef.current);
1625
+ }
1626
+ rafIdRef.current = requestAnimationFrame(() => {
1627
+ const wasJustCommitted = justCommittedRef.current;
1628
+ if (wasJustCommitted) {
1629
+ justCommittedRef.current = false;
1630
+ }
1631
+ const seekRect = seekRectRef.current;
1632
+ if (!seekRect) {
1633
+ rafIdRef.current = null;
1634
+ return;
1635
+ }
1636
+ const clientX = lastPointerXRef.current;
1637
+ const offsetXOnSeekBar = Math.max(
1638
+ 0,
1639
+ Math.min(clientX - seekRect.left, seekRect.width)
1640
+ );
1641
+ const relativeX = offsetXOnSeekBar / seekRect.width;
1642
+ const calculatedHoverTime = relativeX * seekableEnd;
1643
+ hoverTimeRef.current = calculatedHoverTime;
1644
+ onHoverProgressUpdate();
1645
+ const wasHovering = seekState.isHovering;
1646
+ const isCurrentlyHovering = clientX >= seekRect.left && clientX <= seekRect.right;
1647
+ const timeHovering = Date.now() - pointerEnterTimeRef.current;
1648
+ const totalMovement = horizontalMovementRef.current + verticalMovementRef.current;
1649
+ const horizontalRatio = totalMovement > 0 ? horizontalMovementRef.current / totalMovement : 0;
1650
+ const timeSinceSeekCommit = Date.now() - lastSeekCommitTimeRef.current;
1651
+ const isInSeekCooldown = timeSinceSeekCommit < 300;
1652
+ const shouldShowTooltip = !wasJustCommitted && !isInSeekCooldown && (timeHovering > 150 || horizontalRatio > 0.6 || totalMovement < 10 && timeHovering > 50);
1653
+ if (!wasHovering && isCurrentlyHovering && shouldShowTooltip && !tooltipDisabled) {
1654
+ setSeekState((prev) => ({ ...prev, isHovering: true }));
1655
+ }
1656
+ if (!tooltipDisabled) {
1657
+ onPreviewUpdate(calculatedHoverTime);
1658
+ if (isCurrentlyHovering && (wasHovering || shouldShowTooltip)) {
1659
+ onTooltipPositionUpdate(clientX);
1660
+ }
1661
+ }
1662
+ rafIdRef.current = null;
1663
+ });
1664
+ },
1665
+ [
1666
+ onPreviewUpdate,
1667
+ onTooltipPositionUpdate,
1668
+ onHoverProgressUpdate,
1669
+ seekableEnd,
1670
+ seekState.isHovering,
1671
+ tooltipDisabled
1672
+ ]
1673
+ );
1674
+ const onSeek = React3.useCallback(
1675
+ (value) => {
1676
+ const time = value[0] ?? 0;
1677
+ setSeekState((prev) => ({ ...prev, pendingSeekTime: time }));
1678
+ if (!store.getState().dragging) {
1679
+ store.setState("dragging", true);
1680
+ }
1681
+ if (seekThrottleRef.current) {
1682
+ cancelAnimationFrame(seekThrottleRef.current);
1683
+ }
1684
+ seekThrottleRef.current = requestAnimationFrame(() => {
1685
+ dispatch({
1686
+ type: MediaActionTypes.MEDIA_SEEK_REQUEST,
1687
+ detail: time
1688
+ });
1689
+ seekThrottleRef.current = null;
1690
+ });
1691
+ },
1692
+ [dispatch, store.getState, store.setState]
1693
+ );
1694
+ const onSeekCommit = React3.useCallback(
1695
+ (value) => {
1696
+ const time = value[0] ?? 0;
1697
+ if (seekThrottleRef.current) {
1698
+ cancelAnimationFrame(seekThrottleRef.current);
1699
+ seekThrottleRef.current = null;
1700
+ }
1701
+ if (hoverTimeoutRef.current) {
1702
+ clearTimeout(hoverTimeoutRef.current);
1703
+ hoverTimeoutRef.current = null;
1704
+ }
1705
+ if (rafIdRef.current) {
1706
+ cancelAnimationFrame(rafIdRef.current);
1707
+ rafIdRef.current = null;
1708
+ }
1709
+ if (previewDebounceRef.current) {
1710
+ cancelAnimationFrame(previewDebounceRef.current);
1711
+ previewDebounceRef.current = null;
1712
+ }
1713
+ setSeekState((prev) => ({
1714
+ ...prev,
1715
+ pendingSeekTime: time,
1716
+ isHovering: false,
1717
+ hasInitialPosition: false
1718
+ }));
1719
+ justCommittedRef.current = true;
1720
+ collisionDataRef.current = null;
1721
+ lastSeekCommitTimeRef.current = Date.now();
1722
+ pointerEnterTimeRef.current = Date.now();
1723
+ horizontalMovementRef.current = 0;
1724
+ verticalMovementRef.current = 0;
1725
+ if (store.getState().dragging) {
1726
+ store.setState("dragging", false);
1727
+ }
1728
+ dispatch({
1729
+ type: MediaActionTypes.MEDIA_SEEK_REQUEST,
1730
+ detail: time
1731
+ });
1732
+ dispatch({
1733
+ type: MediaActionTypes.MEDIA_PREVIEW_REQUEST,
1734
+ detail: void 0
1735
+ });
1736
+ },
1737
+ [dispatch, store.getState, store.setState]
1738
+ );
1739
+ React3.useEffect(() => {
1740
+ return () => {
1741
+ if (seekThrottleRef.current) {
1742
+ cancelAnimationFrame(seekThrottleRef.current);
1743
+ }
1744
+ if (hoverTimeoutRef.current) {
1745
+ clearTimeout(hoverTimeoutRef.current);
1746
+ }
1747
+ if (rafIdRef.current) {
1748
+ cancelAnimationFrame(rafIdRef.current);
1749
+ }
1750
+ if (previewDebounceRef.current) {
1751
+ cancelAnimationFrame(previewDebounceRef.current);
1752
+ }
1753
+ };
1754
+ }, []);
1755
+ const currentChapterCue = getCurrentChapterCue(hoverTimeRef.current);
1756
+ const thumbnail = getThumbnail(hoverTimeRef.current);
1757
+ const hoverTime = getCachedTime(hoverTimeRef.current, seekableEnd);
1758
+ const chapterSeparators = React3.useMemo(() => {
1759
+ if (withoutChapter || chapterCues.length <= 1 || seekableEnd <= 0) {
1760
+ return null;
1761
+ }
1762
+ return chapterCues.slice(1).map((chapterCue, index) => {
1763
+ const position = chapterCue.startTime / seekableEnd * 100;
1764
+ return /* @__PURE__ */ jsx(
1765
+ "div",
1766
+ {
1767
+ role: "presentation",
1768
+ "aria-hidden": "true",
1769
+ "data-slot": "media-player-seek-chapter-separator",
1770
+ className: "absolute top-0 h-full bg-zinc-50 dark:bg-zinc-950",
1771
+ style: {
1772
+ width: ".1563rem",
1773
+ left: `${position}%`,
1774
+ transform: "translateX(-50%)"
1775
+ }
1776
+ },
1777
+ `chapter-${index}-${chapterCue.startTime}`
1778
+ );
1779
+ });
1780
+ }, [chapterCues, seekableEnd, withoutChapter]);
1781
+ const spriteStyle = React3.useMemo(() => {
1782
+ if (!thumbnail?.coords || !thumbnail?.src) {
1783
+ return {};
1784
+ }
1785
+ const coordX = thumbnail.coords[0];
1786
+ const coordY = thumbnail.coords[1];
1787
+ const spriteWidth = Number.parseFloat(thumbnail.coords[2] ?? "0");
1788
+ const spriteHeight = Number.parseFloat(thumbnail.coords[3] ?? "0");
1789
+ const scaleX = spriteWidth > 0 ? SPRITE_CONTAINER_WIDTH / spriteWidth : 1;
1790
+ const scaleY = spriteHeight > 0 ? SPRITE_CONTAINER_HEIGHT / spriteHeight : 1;
1791
+ const scale = Math.min(scaleX, scaleY);
1792
+ return {
1793
+ width: `${spriteWidth}px`,
1794
+ height: `${spriteHeight}px`,
1795
+ backgroundImage: `url(${thumbnail.src})`,
1796
+ backgroundPosition: `-${coordX}px -${coordY}px`,
1797
+ backgroundRepeat: "no-repeat",
1798
+ transform: `scale(${scale})`,
1799
+ transformOrigin: "top left"
1800
+ };
1801
+ }, [thumbnail?.coords, thumbnail?.src]);
1802
+ const SeekSlider = /* @__PURE__ */ jsxs("div", { "data-slot": "media-player-seek-container", className: "relative w-full", children: [
1803
+ /* @__PURE__ */ jsxs(
1804
+ SliderPrimitive.Root,
1805
+ {
1806
+ "aria-controls": context.mediaId,
1807
+ "aria-valuetext": `${currentTime} of ${duration}`,
1808
+ "data-hovering": seekState.isHovering ? "" : void 0,
1809
+ "data-slider": "",
1810
+ "data-slot": "media-player-seek",
1811
+ disabled: isDisabled,
1812
+ ...seekProps,
1813
+ ref: seekRef,
1814
+ min: seekableStart,
1815
+ max: seekableEnd,
1816
+ step: 0.01,
1817
+ className: cn(
1818
+ "relative flex w-full touch-none select-none items-center data-disabled:pointer-events-none data-disabled:opacity-50",
1819
+ className
1820
+ ),
1821
+ value: [displayValue],
1822
+ onValueChange: onSeek,
1823
+ onValueCommit: onSeekCommit,
1824
+ onPointerEnter,
1825
+ onPointerLeave,
1826
+ onPointerMove,
1827
+ children: [
1828
+ /* @__PURE__ */ jsxs(SliderPrimitive.Track, { className: "relative h-1 w-full grow overflow-hidden rounded-full bg-primary/40", children: [
1829
+ /* @__PURE__ */ jsx(
1830
+ "div",
1831
+ {
1832
+ "data-slot": "media-player-seek-buffered",
1833
+ className: "absolute h-full bg-primary/70 will-change-[width]",
1834
+ style: {
1835
+ width: `${bufferedProgress * 100}%`
1836
+ }
1837
+ }
1838
+ ),
1839
+ /* @__PURE__ */ jsx(SliderPrimitive.Range, { className: "absolute h-full bg-primary will-change-[width]" }),
1840
+ seekState.isHovering && seekableEnd > 0 && /* @__PURE__ */ jsx(
1841
+ "div",
1842
+ {
1843
+ "data-slot": "media-player-seek-hover-range",
1844
+ className: "absolute h-full bg-primary/70 will-change-[width,opacity]",
1845
+ style: {
1846
+ width: `var(${SEEK_HOVER_PERCENT}, 0%)`,
1847
+ transition: "opacity 150ms ease-out"
1848
+ }
1849
+ }
1850
+ ),
1851
+ chapterSeparators
1852
+ ] }),
1853
+ /* @__PURE__ */ jsx(SliderPrimitive.Thumb, { className: "relative z-10 block size-2.5 shrink-0 rounded-full bg-primary shadow-sm ring-ring/50 transition-[color,box-shadow] will-change-transform hover:ring-4 focus-visible:outline-hidden focus-visible:ring-4 disabled:pointer-events-none disabled:opacity-50" })
1854
+ ]
1855
+ }
1856
+ ),
1857
+ !withoutTooltip && !context.withoutTooltip && seekState.isHovering && seekableEnd > 0 && /* @__PURE__ */ jsx(MediaPlayerPortal, { children: /* @__PURE__ */ jsx(
1858
+ "div",
1859
+ {
1860
+ ref: tooltipRef,
1861
+ className: "backface-hidden contain-[layout_style] pointer-events-none z-50 [transition:opacity_150ms_ease-in-out]",
1862
+ style: {
1863
+ position: "fixed",
1864
+ left: `var(${SEEK_TOOLTIP_X}, 0rem)`,
1865
+ top: `var(${SEEK_TOOLTIP_Y}, 0rem)`,
1866
+ transform: `translateX(-50%) translateY(calc(-100% - ${currentTooltipSideOffset}px))`,
1867
+ visibility: seekState.hasInitialPosition ? "visible" : "hidden",
1868
+ opacity: seekState.hasInitialPosition ? 1 : 0
1869
+ },
1870
+ children: /* @__PURE__ */ jsxs(
1871
+ "div",
1872
+ {
1873
+ className: cn(
1874
+ "flex flex-col items-center gap-1.5 rounded-md border bg-background text-foreground shadow-sm dark:bg-zinc-900",
1875
+ thumbnail && "min-h-10",
1876
+ !thumbnail && currentChapterCue && "px-3 py-1.5"
1877
+ ),
1878
+ children: [
1879
+ thumbnail?.src && /* @__PURE__ */ jsx(
1880
+ "div",
1881
+ {
1882
+ "data-slot": "media-player-seek-thumbnail",
1883
+ className: "overflow-hidden rounded-md rounded-b-none",
1884
+ style: {
1885
+ width: `${SPRITE_CONTAINER_WIDTH}px`,
1886
+ height: `${SPRITE_CONTAINER_HEIGHT}px`
1887
+ },
1888
+ children: thumbnail.coords ? /* @__PURE__ */ jsx("div", { style: spriteStyle }) : (
1889
+ // biome-ignore lint/performance/noImgElement: dynamic thumbnail URLs from media don't work well with Next.js Image optimization
1890
+ /* @__PURE__ */ jsx(
1891
+ "img",
1892
+ {
1893
+ src: thumbnail.src,
1894
+ alt: `Preview at ${hoverTime}`,
1895
+ className: "size-full object-cover"
1896
+ }
1897
+ )
1898
+ )
1899
+ }
1900
+ ),
1901
+ currentChapterCue && /* @__PURE__ */ jsx(
1902
+ "div",
1903
+ {
1904
+ "data-slot": "media-player-seek-chapter-title",
1905
+ className: "line-clamp-2 max-w-48 text-balance text-center text-xs",
1906
+ children: currentChapterCue.text
1907
+ }
1908
+ ),
1909
+ /* @__PURE__ */ jsx(
1910
+ "div",
1911
+ {
1912
+ "data-slot": "media-player-seek-time",
1913
+ className: cn(
1914
+ "whitespace-nowrap text-center text-xs tabular-nums",
1915
+ thumbnail && "pb-1.5",
1916
+ !(thumbnail || currentChapterCue) && "px-2.5 py-1"
1917
+ ),
1918
+ children: tooltipTimeVariant === "progress" ? `${hoverTime} / ${duration}` : hoverTime
1919
+ }
1920
+ )
1921
+ ]
1922
+ }
1923
+ )
1924
+ }
1925
+ ) })
1926
+ ] });
1927
+ if (withTime) {
1928
+ return /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center gap-2", children: [
1929
+ /* @__PURE__ */ jsx("span", { className: "text-sm tabular-nums", children: currentTime }),
1930
+ SeekSlider,
1931
+ /* @__PURE__ */ jsx("span", { className: "text-sm tabular-nums", children: remainingTime })
1932
+ ] });
1933
+ }
1934
+ return SeekSlider;
1935
+ }
1936
+ function MediaPlayerVolume(props) {
1937
+ const { expandable = false, className, disabled, ...volumeProps } = props;
1938
+ const context = useMediaPlayerContext(VOLUME_NAME);
1939
+ const store = useStoreContext(VOLUME_NAME);
1940
+ const dispatch = useMediaDispatch();
1941
+ const mediaVolume = useMediaSelector((state) => state.mediaVolume ?? 1);
1942
+ const mediaMuted = useMediaSelector((state) => state.mediaMuted ?? false);
1943
+ const mediaVolumeLevel = useMediaSelector(
1944
+ (state) => state.mediaVolumeLevel ?? "high"
1945
+ );
1946
+ const sliderId = React3.useId();
1947
+ const volumeTriggerId = React3.useId();
1948
+ const isDisabled = disabled || context.disabled;
1949
+ const onMute = React3.useCallback(() => {
1950
+ dispatch({
1951
+ type: mediaMuted ? MediaActionTypes.MEDIA_UNMUTE_REQUEST : MediaActionTypes.MEDIA_MUTE_REQUEST
1952
+ });
1953
+ }, [dispatch, mediaMuted]);
1954
+ const onVolumeChange = React3.useCallback(
1955
+ (value) => {
1956
+ const volume = value[0] ?? 0;
1957
+ if (!store.getState().dragging) {
1958
+ store.setState("dragging", true);
1959
+ }
1960
+ dispatch({
1961
+ type: MediaActionTypes.MEDIA_VOLUME_REQUEST,
1962
+ detail: volume
1963
+ });
1964
+ },
1965
+ [dispatch, store.getState, store.setState]
1966
+ );
1967
+ const onVolumeCommit = React3.useCallback(
1968
+ (value) => {
1969
+ const volume = value[0] ?? 0;
1970
+ if (store.getState().dragging) {
1971
+ store.setState("dragging", false);
1972
+ }
1973
+ dispatch({
1974
+ type: MediaActionTypes.MEDIA_VOLUME_REQUEST,
1975
+ detail: volume
1976
+ });
1977
+ },
1978
+ [dispatch, store]
1979
+ );
1980
+ const effectiveVolume = mediaMuted ? 0 : mediaVolume;
1981
+ return /* @__PURE__ */ jsxs(
1982
+ "div",
1983
+ {
1984
+ "data-disabled": isDisabled ? "" : void 0,
1985
+ "data-slot": "media-player-volume-container",
1986
+ className: cn(
1987
+ "group flex items-center",
1988
+ expandable ? "gap-0 group-focus-within:gap-2 group-hover:gap-1.5" : "gap-1.5",
1989
+ className
1990
+ ),
1991
+ children: [
1992
+ /* @__PURE__ */ jsx(MediaPlayerTooltip, { tooltip: "Volume", shortcut: "M", children: /* @__PURE__ */ jsx(
1993
+ Button,
1994
+ {
1995
+ id: volumeTriggerId,
1996
+ type: "button",
1997
+ "aria-controls": `${context.mediaId} ${sliderId}`,
1998
+ "aria-label": mediaMuted ? "Unmute" : "Mute",
1999
+ "aria-pressed": mediaMuted,
2000
+ "data-slot": "media-player-volume-trigger",
2001
+ "data-state": mediaMuted ? "on" : "off",
2002
+ variant: "ghost",
2003
+ size: "icon",
2004
+ className: "size-8",
2005
+ disabled: isDisabled,
2006
+ onClick: onMute,
2007
+ children: mediaVolumeLevel === "off" || mediaMuted ? /* @__PURE__ */ jsx(VolumeXIcon, {}) : mediaVolumeLevel === "high" ? /* @__PURE__ */ jsx(Volume2Icon, {}) : /* @__PURE__ */ jsx(Volume1Icon, {})
2008
+ }
2009
+ ) }),
2010
+ /* @__PURE__ */ jsxs(
2011
+ SliderPrimitive.Root,
2012
+ {
2013
+ id: sliderId,
2014
+ "aria-controls": context.mediaId,
2015
+ "aria-valuetext": `${Math.round(effectiveVolume * 100)}% volume`,
2016
+ "data-slider": "",
2017
+ "data-slot": "media-player-volume",
2018
+ ...volumeProps,
2019
+ min: 0,
2020
+ max: 1,
2021
+ step: 0.1,
2022
+ className: cn(
2023
+ "relative flex touch-none select-none items-center",
2024
+ expandable ? "w-0 opacity-0 transition-[width,opacity] duration-200 ease-in-out group-focus-within:w-16 group-focus-within:opacity-100 group-hover:w-16 group-hover:opacity-100" : "w-16",
2025
+ className
2026
+ ),
2027
+ disabled: isDisabled,
2028
+ value: [effectiveVolume],
2029
+ onValueChange: onVolumeChange,
2030
+ onValueCommit: onVolumeCommit,
2031
+ children: [
2032
+ /* @__PURE__ */ jsx(SliderPrimitive.Track, { className: "relative h-1 w-full grow overflow-hidden rounded-full bg-zinc-500", children: /* @__PURE__ */ jsx(SliderPrimitive.Range, { className: "absolute h-full bg-primary will-change-[width]" }) }),
2033
+ /* @__PURE__ */ jsx(SliderPrimitive.Thumb, { className: "block size-2.5 shrink-0 rounded-full bg-primary shadow-sm ring-ring/50 transition-[color,box-shadow] will-change-transform hover:ring-4 focus-visible:outline-hidden focus-visible:ring-4 disabled:pointer-events-none disabled:opacity-50" })
2034
+ ]
2035
+ }
2036
+ )
2037
+ ]
2038
+ }
2039
+ );
2040
+ }
2041
+ function MediaPlayerTime(props) {
2042
+ const { variant = "progress", asChild, className, ...timeProps } = props;
2043
+ const context = useMediaPlayerContext("MediaPlayerTime");
2044
+ const mediaCurrentTime = useMediaSelector(
2045
+ (state) => state.mediaCurrentTime ?? 0
2046
+ );
2047
+ const [, seekableEnd = 0] = useMediaSelector(
2048
+ (state) => state.mediaSeekable ?? [0, 0]
2049
+ );
2050
+ const times = React3.useMemo(() => {
2051
+ if (variant === "remaining") {
2052
+ return {
2053
+ remaining: timeUtils.formatTime(
2054
+ seekableEnd - mediaCurrentTime,
2055
+ seekableEnd
2056
+ )
2057
+ };
2058
+ }
2059
+ if (variant === "duration") {
2060
+ return {
2061
+ duration: timeUtils.formatTime(seekableEnd, seekableEnd)
2062
+ };
2063
+ }
2064
+ return {
2065
+ current: timeUtils.formatTime(mediaCurrentTime, seekableEnd),
2066
+ duration: timeUtils.formatTime(seekableEnd, seekableEnd)
2067
+ };
2068
+ }, [variant, mediaCurrentTime, seekableEnd]);
2069
+ const TimePrimitive = asChild ? Slot : "div";
2070
+ if (variant === "remaining" || variant === "duration") {
2071
+ return /* @__PURE__ */ jsx(
2072
+ TimePrimitive,
2073
+ {
2074
+ "data-slot": "media-player-time",
2075
+ "data-variant": variant,
2076
+ dir: context.dir,
2077
+ ...timeProps,
2078
+ className: cn("text-foreground/80 text-sm tabular-nums", className),
2079
+ children: times[variant]
2080
+ }
2081
+ );
2082
+ }
2083
+ return /* @__PURE__ */ jsxs(
2084
+ TimePrimitive,
2085
+ {
2086
+ "data-slot": "media-player-time",
2087
+ "data-variant": variant,
2088
+ dir: context.dir,
2089
+ ...timeProps,
2090
+ className: cn(
2091
+ "flex items-center gap-1 text-foreground/80 text-sm",
2092
+ className
2093
+ ),
2094
+ children: [
2095
+ /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: times.current }),
2096
+ /* @__PURE__ */ jsx("span", { role: "separator", "aria-hidden": "true", "aria-valuenow": 0, tabIndex: -1, children: "/" }),
2097
+ /* @__PURE__ */ jsx("span", { className: "tabular-nums", children: times.duration })
2098
+ ]
2099
+ }
2100
+ );
2101
+ }
2102
+ function MediaPlayerPlaybackSpeed(props) {
2103
+ const {
2104
+ open,
2105
+ defaultOpen,
2106
+ onOpenChange: onOpenChangeProp,
2107
+ sideOffset = FLOATING_MENU_SIDE_OFFSET,
2108
+ speeds = SPEEDS,
2109
+ modal = false,
2110
+ className,
2111
+ disabled,
2112
+ ...playbackSpeedProps
2113
+ } = props;
2114
+ const context = useMediaPlayerContext(PLAYBACK_SPEED_NAME);
2115
+ const store = useStoreContext(PLAYBACK_SPEED_NAME);
2116
+ const dispatch = useMediaDispatch();
2117
+ const mediaPlaybackRate = useMediaSelector(
2118
+ (state) => state.mediaPlaybackRate ?? 1
2119
+ );
2120
+ const isDisabled = disabled || context.disabled;
2121
+ const onPlaybackRateChange = React3.useCallback(
2122
+ (rate) => {
2123
+ dispatch({
2124
+ type: MediaActionTypes.MEDIA_PLAYBACK_RATE_REQUEST,
2125
+ detail: rate
2126
+ });
2127
+ },
2128
+ [dispatch]
2129
+ );
2130
+ const onOpenChange = React3.useCallback(
2131
+ (open2) => {
2132
+ store.setState("menuOpen", open2);
2133
+ onOpenChangeProp?.(open2);
2134
+ },
2135
+ [store.setState, onOpenChangeProp]
2136
+ );
2137
+ return /* @__PURE__ */ jsxs(
2138
+ DropdownMenu,
2139
+ {
2140
+ modal,
2141
+ open,
2142
+ defaultOpen,
2143
+ onOpenChange,
2144
+ children: [
2145
+ /* @__PURE__ */ jsx(MediaPlayerTooltip, { tooltip: "Playback speed", shortcut: ["<", ">"], children: /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
2146
+ Button,
2147
+ {
2148
+ type: "button",
2149
+ "aria-controls": context.mediaId,
2150
+ disabled: isDisabled,
2151
+ ...playbackSpeedProps,
2152
+ variant: "ghost",
2153
+ size: "icon",
2154
+ className: cn("h-8 w-16 aria-expanded:bg-accent/50", className),
2155
+ children: [
2156
+ mediaPlaybackRate,
2157
+ "x"
2158
+ ]
2159
+ }
2160
+ ) }) }),
2161
+ /* @__PURE__ */ jsx(
2162
+ DropdownMenuContent,
2163
+ {
2164
+ sideOffset,
2165
+ align: "center",
2166
+ className: "min-w-(--radix-dropdown-menu-trigger-width) data-[side=top]:mb-3.5",
2167
+ children: speeds.map((speed) => /* @__PURE__ */ jsxs(
2168
+ DropdownMenuItem,
2169
+ {
2170
+ className: "justify-between",
2171
+ onSelect: () => onPlaybackRateChange(speed),
2172
+ children: [
2173
+ speed,
2174
+ "x",
2175
+ mediaPlaybackRate === speed && /* @__PURE__ */ jsx(CheckIcon, {})
2176
+ ]
2177
+ },
2178
+ speed
2179
+ ))
2180
+ }
2181
+ )
2182
+ ]
2183
+ }
2184
+ );
2185
+ }
2186
+ function MediaPlayerLoop(props) {
2187
+ const { children, className, disabled, ...loopProps } = props;
2188
+ const context = useMediaPlayerContext("MediaPlayerLoop");
2189
+ const isDisabled = disabled || context.disabled;
2190
+ const [isLooping, setIsLooping] = React3.useState(() => {
2191
+ const mediaElement = context.mediaRef.current;
2192
+ return mediaElement?.loop ?? false;
2193
+ });
2194
+ React3.useEffect(() => {
2195
+ const mediaElement = context.mediaRef.current;
2196
+ if (!mediaElement) return;
2197
+ setIsLooping(mediaElement.loop);
2198
+ const checkLoop = () => setIsLooping(mediaElement.loop);
2199
+ const observer = new MutationObserver(checkLoop);
2200
+ observer.observe(mediaElement, {
2201
+ attributes: true,
2202
+ attributeFilter: ["loop"]
2203
+ });
2204
+ return () => observer.disconnect();
2205
+ }, [context.mediaRef]);
2206
+ const onLoopToggle = React3.useCallback(
2207
+ (event) => {
2208
+ props.onClick?.(event);
2209
+ if (event.defaultPrevented) return;
2210
+ const mediaElement = context.mediaRef.current;
2211
+ if (mediaElement) {
2212
+ const newLoopState = !mediaElement.loop;
2213
+ mediaElement.loop = newLoopState;
2214
+ setIsLooping(newLoopState);
2215
+ }
2216
+ },
2217
+ [context.mediaRef, props.onClick]
2218
+ );
2219
+ return /* @__PURE__ */ jsx(
2220
+ MediaPlayerTooltip,
2221
+ {
2222
+ tooltip: isLooping ? "Disable loop" : "Enable loop",
2223
+ shortcut: "R",
2224
+ children: /* @__PURE__ */ jsx(
2225
+ Button,
2226
+ {
2227
+ type: "button",
2228
+ "aria-controls": context.mediaId,
2229
+ "aria-label": isLooping ? "Disable loop" : "Enable loop",
2230
+ "aria-pressed": isLooping,
2231
+ "data-disabled": isDisabled ? "" : void 0,
2232
+ "data-slot": "media-player-loop",
2233
+ "data-state": isLooping ? "on" : "off",
2234
+ disabled: isDisabled,
2235
+ ...loopProps,
2236
+ variant: "ghost",
2237
+ size: "icon",
2238
+ className: cn("size-8", className),
2239
+ onClick: onLoopToggle,
2240
+ children: children ?? (isLooping ? /* @__PURE__ */ jsx(RepeatIcon, { className: "text-muted-foreground" }) : /* @__PURE__ */ jsx(RepeatIcon, {}))
2241
+ }
2242
+ )
2243
+ }
2244
+ );
2245
+ }
2246
+ function MediaPlayerFullscreen(props) {
2247
+ const { children, className, disabled, ...fullscreenProps } = props;
2248
+ const context = useMediaPlayerContext("MediaPlayerFullscreen");
2249
+ const dispatch = useMediaDispatch();
2250
+ const isFullscreen = useMediaSelector(
2251
+ (state) => state.mediaIsFullscreen ?? false
2252
+ );
2253
+ const isDisabled = disabled || context.disabled;
2254
+ const onFullscreen = React3.useCallback(
2255
+ (event) => {
2256
+ props.onClick?.(event);
2257
+ if (event.defaultPrevented) return;
2258
+ dispatch({
2259
+ type: isFullscreen ? MediaActionTypes.MEDIA_EXIT_FULLSCREEN_REQUEST : MediaActionTypes.MEDIA_ENTER_FULLSCREEN_REQUEST
2260
+ });
2261
+ },
2262
+ [dispatch, props.onClick, isFullscreen]
2263
+ );
2264
+ return /* @__PURE__ */ jsx(MediaPlayerTooltip, { tooltip: "Fullscreen", shortcut: "F", children: /* @__PURE__ */ jsx(
2265
+ Button,
2266
+ {
2267
+ type: "button",
2268
+ "aria-label": isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
2269
+ "data-disabled": isDisabled ? "" : void 0,
2270
+ "data-slot": "media-player-fullscreen",
2271
+ "data-state": isFullscreen ? "on" : "off",
2272
+ disabled: isDisabled,
2273
+ ...fullscreenProps,
2274
+ variant: "ghost",
2275
+ size: "icon",
2276
+ className: cn("size-8", className),
2277
+ onClick: onFullscreen,
2278
+ children: children ?? (isFullscreen ? /* @__PURE__ */ jsx(Minimize2Icon, {}) : /* @__PURE__ */ jsx(Maximize2Icon, {}))
2279
+ }
2280
+ ) });
2281
+ }
2282
+ function MediaPlayerPiP(props) {
2283
+ const { children, className, onPipError, disabled, ...pipButtonProps } = props;
2284
+ const context = useMediaPlayerContext("MediaPlayerPiP");
2285
+ const dispatch = useMediaDispatch();
2286
+ const isPictureInPicture = useMediaSelector(
2287
+ (state) => state.mediaIsPip ?? false
2288
+ );
2289
+ const isDisabled = disabled || context.disabled;
2290
+ const onPictureInPicture = React3.useCallback(
2291
+ (event) => {
2292
+ props.onClick?.(event);
2293
+ if (event.defaultPrevented) return;
2294
+ dispatch({
2295
+ type: isPictureInPicture ? MediaActionTypes.MEDIA_EXIT_PIP_REQUEST : MediaActionTypes.MEDIA_ENTER_PIP_REQUEST
2296
+ });
2297
+ const mediaElement = context.mediaRef.current;
2298
+ if (mediaElement instanceof HTMLVideoElement) {
2299
+ if (isPictureInPicture) {
2300
+ document.exitPictureInPicture().catch((error) => {
2301
+ onPipError?.(error, "exit");
2302
+ });
2303
+ } else {
2304
+ mediaElement.requestPictureInPicture().catch((error) => {
2305
+ onPipError?.(error, "enter");
2306
+ });
2307
+ }
2308
+ }
2309
+ },
2310
+ [dispatch, props.onClick, isPictureInPicture, onPipError, context.mediaRef]
2311
+ );
2312
+ return /* @__PURE__ */ jsx(MediaPlayerTooltip, { tooltip: "Picture in picture", shortcut: "P", children: /* @__PURE__ */ jsx(
2313
+ Button,
2314
+ {
2315
+ type: "button",
2316
+ "aria-controls": context.mediaId,
2317
+ "aria-label": isPictureInPicture ? "Exit pip" : "Enter pip",
2318
+ "data-disabled": isDisabled ? "" : void 0,
2319
+ "data-slot": "media-player-pip",
2320
+ "data-state": isPictureInPicture ? "on" : "off",
2321
+ disabled: isDisabled,
2322
+ ...pipButtonProps,
2323
+ variant: "ghost",
2324
+ size: "icon",
2325
+ className: cn("size-8", className),
2326
+ onClick: onPictureInPicture,
2327
+ children: typeof children === "function" ? children(isPictureInPicture) : children ?? (isPictureInPicture ? /* @__PURE__ */ jsx(PictureInPicture2Icon, {}) : /* @__PURE__ */ jsx(PictureInPictureIcon, {}))
2328
+ }
2329
+ ) });
2330
+ }
2331
+ function MediaPlayerCaptions(props) {
2332
+ const { children, className, disabled, ...captionsProps } = props;
2333
+ const context = useMediaPlayerContext("MediaPlayerCaptions");
2334
+ const dispatch = useMediaDispatch();
2335
+ const isSubtitlesActive = useMediaSelector(
2336
+ (state) => (state.mediaSubtitlesShowing ?? []).length > 0
2337
+ );
2338
+ const isDisabled = disabled || context.disabled;
2339
+ const onCaptionsToggle = React3.useCallback(
2340
+ (event) => {
2341
+ props.onClick?.(event);
2342
+ if (event.defaultPrevented) return;
2343
+ dispatch({
2344
+ type: MediaActionTypes.MEDIA_TOGGLE_SUBTITLES_REQUEST
2345
+ });
2346
+ },
2347
+ [dispatch, props.onClick]
2348
+ );
2349
+ return /* @__PURE__ */ jsx(MediaPlayerTooltip, { tooltip: "Captions", shortcut: "C", children: /* @__PURE__ */ jsx(
2350
+ Button,
2351
+ {
2352
+ type: "button",
2353
+ "aria-controls": context.mediaId,
2354
+ "aria-label": isSubtitlesActive ? "Disable captions" : "Enable captions",
2355
+ "aria-pressed": isSubtitlesActive,
2356
+ "data-disabled": isDisabled ? "" : void 0,
2357
+ "data-slot": "media-player-captions",
2358
+ "data-state": isSubtitlesActive ? "on" : "off",
2359
+ disabled: isDisabled,
2360
+ ...captionsProps,
2361
+ variant: "ghost",
2362
+ size: "icon",
2363
+ className: cn("size-8", className),
2364
+ onClick: onCaptionsToggle,
2365
+ children: children ?? (isSubtitlesActive ? /* @__PURE__ */ jsx(SubtitlesIcon, {}) : /* @__PURE__ */ jsx(CaptionsOffIcon, {}))
2366
+ }
2367
+ ) });
2368
+ }
2369
+ function MediaPlayerDownload(props) {
2370
+ const { children, className, disabled, ...downloadProps } = props;
2371
+ const context = useMediaPlayerContext("MediaPlayerDownload");
2372
+ const isDisabled = disabled || context.disabled;
2373
+ const onDownload = React3.useCallback(
2374
+ (event) => {
2375
+ props.onClick?.(event);
2376
+ if (event.defaultPrevented) return;
2377
+ const mediaElement = context.mediaRef.current;
2378
+ if (!mediaElement || !mediaElement.currentSrc) return;
2379
+ const link = document.createElement("a");
2380
+ link.href = mediaElement.currentSrc;
2381
+ link.download = "";
2382
+ document.body.appendChild(link);
2383
+ link.click();
2384
+ document.body.removeChild(link);
2385
+ },
2386
+ [context.mediaRef, props.onClick]
2387
+ );
2388
+ return /* @__PURE__ */ jsx(MediaPlayerTooltip, { tooltip: "Download", shortcut: "D", children: /* @__PURE__ */ jsx(
2389
+ Button,
2390
+ {
2391
+ type: "button",
2392
+ "aria-controls": context.mediaId,
2393
+ "aria-label": "Download",
2394
+ "data-disabled": isDisabled ? "" : void 0,
2395
+ "data-slot": "media-player-download",
2396
+ disabled: isDisabled,
2397
+ ...downloadProps,
2398
+ variant: "ghost",
2399
+ size: "icon",
2400
+ className: cn("size-8", className),
2401
+ onClick: onDownload,
2402
+ children: children ?? /* @__PURE__ */ jsx(DownloadIcon, {})
2403
+ }
2404
+ ) });
2405
+ }
2406
+ function MediaPlayerSettings(props) {
2407
+ const {
2408
+ open,
2409
+ defaultOpen,
2410
+ onOpenChange: onOpenChangeProp,
2411
+ sideOffset = FLOATING_MENU_SIDE_OFFSET,
2412
+ speeds = SPEEDS,
2413
+ modal = false,
2414
+ className,
2415
+ disabled,
2416
+ ...settingsProps
2417
+ } = props;
2418
+ const context = useMediaPlayerContext(SETTINGS_NAME);
2419
+ const store = useStoreContext(SETTINGS_NAME);
2420
+ const dispatch = useMediaDispatch();
2421
+ const mediaPlaybackRate = useMediaSelector(
2422
+ (state) => state.mediaPlaybackRate ?? 1
2423
+ );
2424
+ const mediaSubtitlesList = useMediaSelector(
2425
+ (state) => state.mediaSubtitlesList ?? []
2426
+ );
2427
+ const mediaSubtitlesShowing = useMediaSelector(
2428
+ (state) => state.mediaSubtitlesShowing ?? []
2429
+ );
2430
+ const mediaRenditionList = useMediaSelector(
2431
+ (state) => state.mediaRenditionList ?? []
2432
+ );
2433
+ const selectedRenditionId = useMediaSelector(
2434
+ (state) => state.mediaRenditionSelected
2435
+ );
2436
+ const isDisabled = disabled || context.disabled;
2437
+ const isSubtitlesActive = mediaSubtitlesShowing.length > 0;
2438
+ const onPlaybackRateChange = React3.useCallback(
2439
+ (rate) => {
2440
+ dispatch({
2441
+ type: MediaActionTypes.MEDIA_PLAYBACK_RATE_REQUEST,
2442
+ detail: rate
2443
+ });
2444
+ },
2445
+ [dispatch]
2446
+ );
2447
+ const onRenditionChange = React3.useCallback(
2448
+ (renditionId) => {
2449
+ dispatch({
2450
+ type: MediaActionTypes.MEDIA_RENDITION_REQUEST,
2451
+ detail: renditionId === "auto" ? void 0 : renditionId
2452
+ });
2453
+ },
2454
+ [dispatch]
2455
+ );
2456
+ const onSubtitlesToggle = React3.useCallback(() => {
2457
+ dispatch({
2458
+ type: MediaActionTypes.MEDIA_TOGGLE_SUBTITLES_REQUEST,
2459
+ detail: false
2460
+ });
2461
+ }, [dispatch]);
2462
+ const onShowSubtitleTrack = React3.useCallback(
2463
+ (subtitleTrack) => {
2464
+ dispatch({
2465
+ type: MediaActionTypes.MEDIA_TOGGLE_SUBTITLES_REQUEST,
2466
+ detail: false
2467
+ });
2468
+ dispatch({
2469
+ type: MediaActionTypes.MEDIA_SHOW_SUBTITLES_REQUEST,
2470
+ detail: subtitleTrack
2471
+ });
2472
+ },
2473
+ [dispatch]
2474
+ );
2475
+ const selectedSubtitleLabel = React3.useMemo(() => {
2476
+ if (!isSubtitlesActive) return "Off";
2477
+ if (mediaSubtitlesShowing.length > 0) {
2478
+ return mediaSubtitlesShowing[0]?.label ?? "On";
2479
+ }
2480
+ return "Off";
2481
+ }, [isSubtitlesActive, mediaSubtitlesShowing]);
2482
+ const selectedRenditionLabel = React3.useMemo(() => {
2483
+ if (!selectedRenditionId) return "Auto";
2484
+ const currentRendition = mediaRenditionList?.find(
2485
+ (rendition) => rendition.id === selectedRenditionId
2486
+ );
2487
+ if (!currentRendition) return "Auto";
2488
+ if (currentRendition.height) return `${currentRendition.height}p`;
2489
+ if (currentRendition.width) return `${currentRendition.width}p`;
2490
+ return currentRendition.id ?? "Auto";
2491
+ }, [selectedRenditionId, mediaRenditionList]);
2492
+ const onOpenChange = React3.useCallback(
2493
+ (open2) => {
2494
+ store.setState("menuOpen", open2);
2495
+ onOpenChangeProp?.(open2);
2496
+ },
2497
+ [store.setState, onOpenChangeProp]
2498
+ );
2499
+ return /* @__PURE__ */ jsxs(
2500
+ DropdownMenu,
2501
+ {
2502
+ modal,
2503
+ open,
2504
+ defaultOpen,
2505
+ onOpenChange,
2506
+ children: [
2507
+ /* @__PURE__ */ jsx(MediaPlayerTooltip, { tooltip: "Settings", children: /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
2508
+ Button,
2509
+ {
2510
+ type: "button",
2511
+ "aria-controls": context.mediaId,
2512
+ "aria-label": "Settings",
2513
+ "data-disabled": isDisabled ? "" : void 0,
2514
+ "data-slot": "media-player-settings",
2515
+ disabled: isDisabled,
2516
+ ...settingsProps,
2517
+ variant: "ghost",
2518
+ size: "icon",
2519
+ className: cn("size-8 aria-expanded:bg-accent/50", className),
2520
+ children: /* @__PURE__ */ jsx(SettingsIcon, {})
2521
+ }
2522
+ ) }) }),
2523
+ /* @__PURE__ */ jsxs(
2524
+ DropdownMenuContent,
2525
+ {
2526
+ align: "end",
2527
+ side: "top",
2528
+ sideOffset,
2529
+ className: "w-56 data-[side=top]:mb-3.5",
2530
+ children: [
2531
+ /* @__PURE__ */ jsx(DropdownMenuLabel, { className: "sr-only", children: "Settings" }),
2532
+ /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [
2533
+ /* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [
2534
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: "Speed" }),
2535
+ /* @__PURE__ */ jsxs(Badge, { variant: "outline", className: "rounded-sm", children: [
2536
+ mediaPlaybackRate,
2537
+ "x"
2538
+ ] })
2539
+ ] }),
2540
+ /* @__PURE__ */ jsx(DropdownMenuSubContent, { children: speeds.map((speed) => /* @__PURE__ */ jsxs(
2541
+ DropdownMenuItem,
2542
+ {
2543
+ className: "justify-between",
2544
+ onSelect: () => onPlaybackRateChange(speed),
2545
+ children: [
2546
+ speed,
2547
+ "x",
2548
+ mediaPlaybackRate === speed && /* @__PURE__ */ jsx(CheckIcon, {})
2549
+ ]
2550
+ },
2551
+ speed
2552
+ )) })
2553
+ ] }),
2554
+ context.isVideo && mediaRenditionList.length > 0 && /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [
2555
+ /* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [
2556
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: "Quality" }),
2557
+ /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "rounded-sm", children: selectedRenditionLabel })
2558
+ ] }),
2559
+ /* @__PURE__ */ jsxs(DropdownMenuSubContent, { children: [
2560
+ /* @__PURE__ */ jsxs(
2561
+ DropdownMenuItem,
2562
+ {
2563
+ className: "justify-between",
2564
+ onSelect: () => onRenditionChange("auto"),
2565
+ children: [
2566
+ "Auto",
2567
+ !selectedRenditionId && /* @__PURE__ */ jsx(CheckIcon, {})
2568
+ ]
2569
+ }
2570
+ ),
2571
+ mediaRenditionList.slice().sort((a, b) => {
2572
+ const aHeight = a.height ?? 0;
2573
+ const bHeight = b.height ?? 0;
2574
+ return bHeight - aHeight;
2575
+ }).map((rendition) => {
2576
+ const label = rendition.height ? `${rendition.height}p` : rendition.width ? `${rendition.width}p` : rendition.id ?? "Unknown";
2577
+ const selected = rendition.id === selectedRenditionId;
2578
+ return /* @__PURE__ */ jsxs(
2579
+ DropdownMenuItem,
2580
+ {
2581
+ className: "justify-between",
2582
+ onSelect: () => onRenditionChange(rendition.id ?? ""),
2583
+ children: [
2584
+ label,
2585
+ selected && /* @__PURE__ */ jsx(CheckIcon, {})
2586
+ ]
2587
+ },
2588
+ rendition.id
2589
+ );
2590
+ })
2591
+ ] })
2592
+ ] }),
2593
+ /* @__PURE__ */ jsxs(DropdownMenuSub, { children: [
2594
+ /* @__PURE__ */ jsxs(DropdownMenuSubTrigger, { children: [
2595
+ /* @__PURE__ */ jsx("span", { className: "flex-1", children: "Captions" }),
2596
+ /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "rounded-sm", children: selectedSubtitleLabel })
2597
+ ] }),
2598
+ /* @__PURE__ */ jsxs(DropdownMenuSubContent, { children: [
2599
+ /* @__PURE__ */ jsxs(
2600
+ DropdownMenuItem,
2601
+ {
2602
+ className: "justify-between",
2603
+ onSelect: onSubtitlesToggle,
2604
+ children: [
2605
+ "Off",
2606
+ !isSubtitlesActive && /* @__PURE__ */ jsx(CheckIcon, {})
2607
+ ]
2608
+ }
2609
+ ),
2610
+ mediaSubtitlesList.map((subtitleTrack) => {
2611
+ const isSelected = mediaSubtitlesShowing.some(
2612
+ (showingSubtitle) => showingSubtitle.label === subtitleTrack.label
2613
+ );
2614
+ return /* @__PURE__ */ jsxs(
2615
+ DropdownMenuItem,
2616
+ {
2617
+ className: "justify-between",
2618
+ onSelect: () => onShowSubtitleTrack(subtitleTrack),
2619
+ children: [
2620
+ subtitleTrack.label,
2621
+ isSelected && /* @__PURE__ */ jsx(CheckIcon, {})
2622
+ ]
2623
+ },
2624
+ `${subtitleTrack.kind}-${subtitleTrack.label}-${subtitleTrack.language}`
2625
+ );
2626
+ }),
2627
+ mediaSubtitlesList.length === 0 && /* @__PURE__ */ jsx(DropdownMenuItem, { disabled: true, children: "No captions available" })
2628
+ ] })
2629
+ ] })
2630
+ ]
2631
+ }
2632
+ )
2633
+ ]
2634
+ }
2635
+ );
2636
+ }
2637
+ function MediaPlayerPortal(props) {
2638
+ const { container: containerProp, children } = props;
2639
+ const context = useMediaPlayerContext("MediaPlayerPortal");
2640
+ const container = containerProp ?? context.portalContainer;
2641
+ if (!container) return null;
2642
+ return ReactDOM.createPortal(children, container);
2643
+ }
2644
+ function MediaPlayerTooltip(props) {
2645
+ const {
2646
+ tooltip,
2647
+ shortcut,
2648
+ delayDuration,
2649
+ sideOffset,
2650
+ children,
2651
+ ...tooltipProps
2652
+ } = props;
2653
+ const context = useMediaPlayerContext("MediaPlayerTooltip");
2654
+ const tooltipDelayDuration = delayDuration ?? context.tooltipDelayDuration;
2655
+ const tooltipSideOffset = sideOffset ?? context.tooltipSideOffset;
2656
+ if (!tooltip && !shortcut || context.withoutTooltip) return /* @__PURE__ */ jsx(Fragment, { children });
2657
+ return /* @__PURE__ */ jsxs(Tooltip, { ...tooltipProps, delayDuration: tooltipDelayDuration, children: [
2658
+ /* @__PURE__ */ jsx(
2659
+ TooltipTrigger,
2660
+ {
2661
+ className: "text-foreground focus-visible:ring-ring/50",
2662
+ asChild: true,
2663
+ children
2664
+ }
2665
+ ),
2666
+ /* @__PURE__ */ jsxs(
2667
+ TooltipContent,
2668
+ {
2669
+ sideOffset: tooltipSideOffset,
2670
+ className: "flex items-center gap-2 border bg-accent px-2 py-1 font-medium text-foreground data-[side=top]:mb-3.5 dark:bg-zinc-900 [&>span]:hidden",
2671
+ children: [
2672
+ /* @__PURE__ */ jsx("p", { children: tooltip }),
2673
+ Array.isArray(shortcut) ? /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1", children: shortcut.map((shortcutKey) => /* @__PURE__ */ jsx(
2674
+ "kbd",
2675
+ {
2676
+ className: "select-none rounded border bg-secondary px-1.5 py-0.5 font-mono text-[11.2px] text-foreground shadow-xs",
2677
+ children: /* @__PURE__ */ jsx("abbr", { title: shortcutKey, className: "no-underline", children: shortcutKey })
2678
+ },
2679
+ shortcutKey
2680
+ )) }) : shortcut && /* @__PURE__ */ jsx(
2681
+ "kbd",
2682
+ {
2683
+ className: "select-none rounded border bg-secondary px-1.5 py-px font-mono text-[11.2px] text-foreground shadow-xs",
2684
+ children: /* @__PURE__ */ jsx("abbr", { title: shortcut, className: "no-underline", children: shortcut })
2685
+ },
2686
+ shortcut
2687
+ )
2688
+ ]
2689
+ }
2690
+ )
2691
+ ] });
2692
+ }
2693
+
2694
+ export { MediaPlayer, MediaPlayerAudio, MediaPlayerCaptions, MediaPlayerControls, MediaPlayerControlsOverlay, MediaPlayerDownload, MediaPlayerError, MediaPlayerFullscreen, MediaPlayerLoading, MediaPlayerLoop, MediaPlayerPiP, MediaPlayerPlay, MediaPlayerPlaybackSpeed, MediaPlayerPortal, MediaPlayerSeek, MediaPlayerSeekBackward, MediaPlayerSeekForward, MediaPlayerSettings, MediaPlayerTime, MediaPlayerTooltip, MediaPlayerVideo, MediaPlayerVolume, MediaPlayerVolumeIndicator, useStore as useMediaPlayerStore };
2695
+ //# sourceMappingURL=media-player.js.map
2696
+ //# sourceMappingURL=media-player.js.map