@therealtinhtute/baroiplayer 1.2.0 → 2.0.0-beta.1

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 (305) hide show
  1. package/README.md +91 -73
  2. package/dist/components/icons/index.d.ts +36 -0
  3. package/dist/components/icons/index.d.ts.map +1 -0
  4. package/dist/components/icons/svg-icons/ArrowLeftIcon.d.ts +4 -0
  5. package/dist/components/icons/svg-icons/ArrowLeftIcon.d.ts.map +1 -0
  6. package/dist/components/icons/svg-icons/ArrowRightIcon.d.ts +5 -0
  7. package/dist/components/icons/svg-icons/ArrowRightIcon.d.ts.map +1 -0
  8. package/dist/components/icons/svg-icons/AudioIcon.d.ts +5 -0
  9. package/dist/components/icons/svg-icons/AudioIcon.d.ts.map +1 -0
  10. package/dist/components/icons/svg-icons/BackwardIcon.d.ts +5 -0
  11. package/dist/components/icons/svg-icons/BackwardIcon.d.ts.map +1 -0
  12. package/dist/components/icons/svg-icons/CameraIcon.d.ts +5 -0
  13. package/dist/components/icons/svg-icons/CameraIcon.d.ts.map +1 -0
  14. package/dist/components/icons/svg-icons/CheckIcon.d.ts +5 -0
  15. package/dist/components/icons/svg-icons/CheckIcon.d.ts.map +1 -0
  16. package/dist/components/icons/svg-icons/EnablePiPIcon.d.ts +4 -0
  17. package/dist/components/icons/svg-icons/EnablePiPIcon.d.ts.map +1 -0
  18. package/dist/components/icons/svg-icons/ForwardIcon.d.ts +5 -0
  19. package/dist/components/icons/svg-icons/ForwardIcon.d.ts.map +1 -0
  20. package/dist/components/icons/svg-icons/FullscreenEnterIcon.d.ts +5 -0
  21. package/dist/components/icons/svg-icons/FullscreenEnterIcon.d.ts.map +1 -0
  22. package/dist/components/icons/svg-icons/FullscreenExitIcon.d.ts +5 -0
  23. package/dist/components/icons/svg-icons/FullscreenExitIcon.d.ts.map +1 -0
  24. package/dist/components/icons/svg-icons/LoadingIcon.d.ts +5 -0
  25. package/dist/components/icons/svg-icons/LoadingIcon.d.ts.map +1 -0
  26. package/dist/components/icons/svg-icons/PauseIcon.d.ts +5 -0
  27. package/dist/components/icons/svg-icons/PauseIcon.d.ts.map +1 -0
  28. package/dist/components/icons/svg-icons/PlayIcon.d.ts +5 -0
  29. package/dist/components/icons/svg-icons/PlayIcon.d.ts.map +1 -0
  30. package/dist/components/icons/svg-icons/PlaybackSpeedIcon.d.ts +5 -0
  31. package/dist/components/icons/svg-icons/PlaybackSpeedIcon.d.ts.map +1 -0
  32. package/dist/components/icons/svg-icons/QualityIcon.d.ts +5 -0
  33. package/dist/components/icons/svg-icons/QualityIcon.d.ts.map +1 -0
  34. package/dist/components/icons/svg-icons/SettingsIcon.d.ts +5 -0
  35. package/dist/components/icons/svg-icons/SettingsIcon.d.ts.map +1 -0
  36. package/dist/components/icons/svg-icons/SliderIcon.d.ts +5 -0
  37. package/dist/components/icons/svg-icons/SliderIcon.d.ts.map +1 -0
  38. package/dist/components/icons/svg-icons/SubtitleIcon.d.ts +5 -0
  39. package/dist/components/icons/svg-icons/SubtitleIcon.d.ts.map +1 -0
  40. package/dist/components/icons/svg-icons/SubtitleOffIcon.d.ts +5 -0
  41. package/dist/components/icons/svg-icons/SubtitleOffIcon.d.ts.map +1 -0
  42. package/dist/components/icons/svg-icons/UnPiPIcon.d.ts +4 -0
  43. package/dist/components/icons/svg-icons/UnPiPIcon.d.ts.map +1 -0
  44. package/dist/components/icons/svg-icons/VolumeMutedIcon.d.ts +5 -0
  45. package/dist/components/icons/svg-icons/VolumeMutedIcon.d.ts.map +1 -0
  46. package/dist/components/icons/svg-icons/VolumeOneIcon.d.ts +5 -0
  47. package/dist/components/icons/svg-icons/VolumeOneIcon.d.ts.map +1 -0
  48. package/dist/components/icons/svg-icons/VolumeThreeIcon.d.ts +5 -0
  49. package/dist/components/icons/svg-icons/VolumeThreeIcon.d.ts.map +1 -0
  50. package/dist/components/icons/svg-icons/VolumeTwoIcon.d.ts +5 -0
  51. package/dist/components/icons/svg-icons/VolumeTwoIcon.d.ts.map +1 -0
  52. package/dist/components/variants/gradient/gradient-audio.d.ts +13 -0
  53. package/dist/components/variants/gradient/gradient-audio.d.ts.map +1 -0
  54. package/dist/components/variants/gradient/gradient-controls.d.ts +4 -0
  55. package/dist/components/variants/gradient/gradient-controls.d.ts.map +1 -0
  56. package/dist/components/variants/gradient/gradient-glyphs.d.ts +30 -0
  57. package/dist/components/variants/gradient/gradient-glyphs.d.ts.map +1 -0
  58. package/dist/components/variants/gradient/gradient-video.d.ts +16 -0
  59. package/dist/components/variants/gradient/gradient-video.d.ts.map +1 -0
  60. package/dist/index.css +1 -1
  61. package/dist/index.d.ts +5 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +2 -112
  64. package/dist/index.js.map +1 -1
  65. package/dist/index.mjs +786 -6271
  66. package/dist/index.mjs.map +1 -1
  67. package/dist/package.json +3 -0
  68. package/package.json +110 -108
  69. package/src/components/variants/gradient/gradient-audio.tsx +47 -0
  70. package/src/components/variants/gradient/gradient-controls.tsx +254 -0
  71. package/src/components/variants/gradient/gradient-glyphs.test.tsx +69 -0
  72. package/src/components/variants/gradient/gradient-glyphs.tsx +129 -0
  73. package/src/components/variants/gradient/gradient-skin.css +211 -0
  74. package/src/components/variants/gradient/gradient-video.tsx +70 -0
  75. package/src/index.ts +5 -198
  76. package/src/test/accessibility-utils.ts +0 -59
  77. package/dist/context/media.js +0 -2
  78. package/dist/context/media.js.map +0 -1
  79. package/dist/context/media.mjs +0 -15
  80. package/dist/context/media.mjs.map +0 -1
  81. package/dist/context/store.js +0 -2
  82. package/dist/context/store.js.map +0 -1
  83. package/dist/context/store.mjs +0 -5
  84. package/dist/context/store.mjs.map +0 -1
  85. package/dist/context-BYwDoSRX.js +0 -1172
  86. package/dist/context-BYwDoSRX.js.map +0 -1
  87. package/dist/context-eNS62_ac.cjs +0 -23
  88. package/dist/context-eNS62_ac.cjs.map +0 -1
  89. package/dist/core-events-B1iM2F46.cjs +0 -2
  90. package/dist/core-events-B1iM2F46.cjs.map +0 -1
  91. package/dist/core-events-DunPHKRE.js +0 -484
  92. package/dist/core-events-DunPHKRE.js.map +0 -1
  93. package/dist/core-plugins-By-4-kGs.cjs +0 -2
  94. package/dist/core-plugins-By-4-kGs.cjs.map +0 -1
  95. package/dist/core-plugins-DSBWcTuX.js +0 -821
  96. package/dist/core-plugins-DSBWcTuX.js.map +0 -1
  97. package/dist/core.js +0 -37
  98. package/dist/core.js.map +0 -1
  99. package/dist/core.mjs +0 -1233
  100. package/dist/core.mjs.map +0 -1
  101. package/dist/enhanced-components-B_l3cist.js +0 -1142
  102. package/dist/enhanced-components-B_l3cist.js.map +0 -1
  103. package/dist/enhanced-components-BspFs9OO.cjs +0 -2
  104. package/dist/enhanced-components-BspFs9OO.cjs.map +0 -1
  105. package/dist/hooks-BXwI8QG6.cjs +0 -4
  106. package/dist/hooks-BXwI8QG6.cjs.map +0 -1
  107. package/dist/hooks-Bpi-jDiO.js +0 -1816
  108. package/dist/hooks-Bpi-jDiO.js.map +0 -1
  109. package/dist/minimal-components-C4z900Ro.js +0 -1926
  110. package/dist/minimal-components-C4z900Ro.js.map +0 -1
  111. package/dist/minimal-components-v4qBp6jv.cjs +0 -2
  112. package/dist/minimal-components-v4qBp6jv.cjs.map +0 -1
  113. package/dist/minimal-components.css +0 -1
  114. package/dist/mona-loading.gif +0 -0
  115. package/dist/performance-monitor-C5k6FDXw.js +0 -301
  116. package/dist/performance-monitor-C5k6FDXw.js.map +0 -1
  117. package/dist/performance-monitor-lJmuUjQQ.cjs +0 -2
  118. package/dist/performance-monitor-lJmuUjQQ.cjs.map +0 -1
  119. package/dist/utils-CFOue_9K.cjs +0 -9
  120. package/dist/utils-CFOue_9K.cjs.map +0 -1
  121. package/dist/utils-Dzpl2ArK.js +0 -2844
  122. package/dist/utils-Dzpl2ArK.js.map +0 -1
  123. package/dist/utils.js +0 -2
  124. package/dist/utils.js.map +0 -1
  125. package/dist/utils.mjs +0 -11
  126. package/dist/utils.mjs.map +0 -1
  127. package/src/adapters/videojs-adapter.tsx +0 -470
  128. package/src/assets/mona-loading.gif +0 -0
  129. package/src/components/AnimateLoading.tsx +0 -107
  130. package/src/components/LoadingState.tsx +0 -239
  131. package/src/components/__tests__/media-player-accessibility.test.tsx +0 -510
  132. package/src/components/__tests__/media-player-react19.test.tsx +0 -457
  133. package/src/components/accessibility/keyboard-help-overlay.tsx +0 -207
  134. package/src/components/audio-player.tsx +0 -85
  135. package/src/components/basic/index.ts +0 -37
  136. package/src/components/enhanced/advanced-features.tsx +0 -311
  137. package/src/components/enhanced/debug-panel.tsx +0 -448
  138. package/src/components/enhanced/enhanced-controls.tsx +0 -597
  139. package/src/components/enhanced/enhanced-media-player.tsx +0 -566
  140. package/src/components/enhanced/error-handling.tsx +0 -338
  141. package/src/components/enhanced/index.ts +0 -39
  142. package/src/components/enhanced/media-player-enhanced.tsx +0 -383
  143. package/src/components/examples/basic-video-player.tsx +0 -50
  144. package/src/components/examples/custom-controls-example.tsx +0 -63
  145. package/src/components/examples/enhanced-controls-example.tsx +0 -100
  146. package/src/components/examples/enhanced-media-player-example.tsx +0 -302
  147. package/src/components/examples/loading-states-demo.tsx +0 -142
  148. package/src/components/examples/react-19-demo.tsx +0 -353
  149. package/src/components/examples/volume-orientation-demo.tsx +0 -106
  150. package/src/components/icon-demo.tsx +0 -196
  151. package/src/components/legacy.tsx +0 -87
  152. package/src/components/media-metadata-display.tsx +0 -99
  153. package/src/components/media-player-audio.tsx +0 -39
  154. package/src/components/media-player-controls.tsx +0 -223
  155. package/src/components/media-player-error.tsx +0 -163
  156. package/src/components/media-player-fullscreen.tsx +0 -109
  157. package/src/components/media-player-hls.tsx +0 -111
  158. package/src/components/media-player-loading.tsx +0 -76
  159. package/src/components/media-player-play.tsx +0 -75
  160. package/src/components/media-player-root.tsx +0 -338
  161. package/src/components/media-player-seek.tsx +0 -168
  162. package/src/components/media-player-time.tsx +0 -99
  163. package/src/components/media-player-tooltip.tsx +0 -58
  164. package/src/components/media-player-video.tsx +0 -54
  165. package/src/components/media-player-volume.tsx +0 -155
  166. package/src/components/media-player.tsx +0 -292
  167. package/src/components/media-suspense.tsx +0 -344
  168. package/src/components/player-settings-form.tsx +0 -158
  169. package/src/components/react-player-wrapper.tsx +0 -651
  170. package/src/components/simple-video-player.tsx +0 -62
  171. package/src/components/ui/blur-poster.tsx +0 -93
  172. package/src/components/ui/empty-state.tsx +0 -91
  173. package/src/components/ui/enhanced-seek-bar.tsx +0 -254
  174. package/src/components/ui/error-state.tsx +0 -124
  175. package/src/components/ui/fullscreen-button.tsx +0 -81
  176. package/src/components/ui/loading-skeleton.tsx +0 -107
  177. package/src/components/ui/media-resource-preloader.tsx +0 -458
  178. package/src/components/ui/offline-message.tsx +0 -98
  179. package/src/components/ui/play-button.tsx +0 -99
  180. package/src/components/ui/seek-bar.tsx +0 -191
  181. package/src/components/ui/time-display.tsx +0 -61
  182. package/src/components/ui/volume-control.tsx +0 -190
  183. package/src/components/unified/base-media-player.tsx +0 -252
  184. package/src/components/unified/media-player.tsx +0 -75
  185. package/src/components/variants/minimal/AccessibleMinimalPlayer.tsx +0 -587
  186. package/src/components/variants/minimal/EnhancedMinimalMediaPlayer.tsx +0 -573
  187. package/src/components/variants/minimal/MinimalControls.tsx +0 -124
  188. package/src/components/variants/minimal/MinimalLoading.tsx +0 -28
  189. package/src/components/variants/minimal/MinimalMediaPlayer.tsx +0 -318
  190. package/src/components/variants/minimal/MinimalOverlay.tsx +0 -58
  191. package/src/components/variants/minimal/MinimalPlayButton.tsx +0 -56
  192. package/src/components/variants/minimal/MinimalSeekBar.tsx +0 -140
  193. package/src/components/variants/minimal/MinimalVolumeControl.tsx +0 -75
  194. package/src/components/variants/minimal/SimpleMinimalPlayer.tsx +0 -206
  195. package/src/components/variants/minimal/components/CenterPlayButton.tsx +0 -22
  196. package/src/components/variants/minimal/components/ControlBar.tsx +0 -142
  197. package/src/components/variants/minimal/components/EnhancedSettingsMenu.tsx +0 -412
  198. package/src/components/variants/minimal/components/PlaybackControls.tsx +0 -46
  199. package/src/components/variants/minimal/components/RightControls.tsx +0 -164
  200. package/src/components/variants/minimal/components/SeekBar.tsx +0 -127
  201. package/src/components/variants/minimal/components/SettingsDropdown.tsx +0 -68
  202. package/src/components/variants/minimal/components/SubtitleDisplay.tsx +0 -21
  203. package/src/components/variants/minimal/components/TimeDisplay.tsx +0 -15
  204. package/src/components/variants/minimal/components/VideoElement.tsx +0 -33
  205. package/src/components/variants/minimal/components/VolumeControl.tsx +0 -220
  206. package/src/components/variants/minimal/index.ts +0 -23
  207. package/src/components/video-player.tsx +0 -100
  208. package/src/context/__tests__/media-store.test.ts +0 -509
  209. package/src/context/error-handling.ts +0 -398
  210. package/src/context/media-context.tsx +0 -254
  211. package/src/context/media-provider.tsx +0 -264
  212. package/src/context/media-store.ts +0 -387
  213. package/src/context/persistence.ts +0 -462
  214. package/src/core/events/event-system.ts +0 -448
  215. package/src/core/events/hooks.ts +0 -325
  216. package/src/core/events/index.ts +0 -22
  217. package/src/core/events/middleware.ts +0 -286
  218. package/src/core/index.ts +0 -22
  219. package/src/core/optimization/bundle-optimizer.tsx +0 -312
  220. package/src/core/performance/cicd.ts +0 -98
  221. package/src/core/performance/index.ts +0 -38
  222. package/src/core/performance/media-loading-optimizer.ts +0 -544
  223. package/src/core/performance/performance-budgets.ts +0 -437
  224. package/src/core/performance/performance-monitor.tsx +0 -488
  225. package/src/core/performance/performance-testing.ts +0 -461
  226. package/src/core/plugins/__tests__/registry.test.ts +0 -595
  227. package/src/core/plugins/base-plugin.ts +0 -225
  228. package/src/core/plugins/enhanced-plugin-system.ts +0 -435
  229. package/src/core/plugins/examples/analytics-plugin.ts +0 -241
  230. package/src/core/plugins/index.ts +0 -39
  231. package/src/core/plugins/registry.ts +0 -546
  232. package/src/core/plugins/types.ts +0 -169
  233. package/src/core/plugins/utils.ts +0 -317
  234. package/src/core/progressive-loading.tsx +0 -331
  235. package/src/core/providers/enhanced-hls-provider.ts +0 -307
  236. package/src/core/providers/lazy-provider.tsx +0 -14
  237. package/src/core/providers/service-provider.tsx +0 -164
  238. package/src/core/utils.tsx +0 -34
  239. package/src/features/media-session/media-session-manager.ts +0 -411
  240. package/src/features/picture-in-picture/pip-manager.ts +0 -428
  241. package/src/features/playlist/playlist-manager.ts +0 -626
  242. package/src/features/subtitles/subtitle-manager.ts +0 -435
  243. package/src/features/subtitles/subtitle-parser.ts +0 -284
  244. package/src/features/thumbnails/thumbnail-generator.ts +0 -528
  245. package/src/hooks/__tests__/currentTime-fix.test.ts +0 -149
  246. package/src/hooks/__tests__/use-media-player.test.ts +0 -712
  247. package/src/hooks/__tests__/use-media-state.test.tsx +0 -316
  248. package/src/hooks/accessibility/index.ts +0 -27
  249. package/src/hooks/accessibility/use-accessibility-preferences.ts +0 -190
  250. package/src/hooks/accessibility/use-focus-management.ts +0 -183
  251. package/src/hooks/accessibility/use-keyboard-shortcuts.ts +0 -152
  252. package/src/hooks/accessibility/use-screen-reader.ts +0 -212
  253. package/src/hooks/core/index.ts +0 -47
  254. package/src/hooks/legacy.ts +0 -21
  255. package/src/hooks/use-buffer-health.ts +0 -218
  256. package/src/hooks/use-enhanced-media-player.ts +0 -575
  257. package/src/hooks/use-focus-trap.tsx +0 -162
  258. package/src/hooks/use-intelligent-preloading.ts +0 -387
  259. package/src/hooks/use-keyboard-controls.ts +0 -115
  260. package/src/hooks/use-keyboard-shortcuts.ts +0 -255
  261. package/src/hooks/use-media-actions.ts +0 -184
  262. package/src/hooks/use-media-metadata.ts +0 -91
  263. package/src/hooks/use-media-optimistic.ts +0 -264
  264. package/src/hooks/use-media-player.ts +0 -343
  265. package/src/hooks/use-media-state.ts +0 -194
  266. package/src/hooks/use-memory-optimization.ts +0 -360
  267. package/src/hooks/use-network-status.ts +0 -124
  268. package/src/hooks/use-optimistic-controls.ts +0 -95
  269. package/src/hooks/use-optimized-media.ts +0 -283
  270. package/src/hooks/use-smart-preload.ts +0 -229
  271. package/src/hooks/use-touch-gestures.ts +0 -461
  272. package/src/hooks/useEnhancedSubtitles.ts +0 -258
  273. package/src/hooks/useKeyboardShortcuts.ts +0 -106
  274. package/src/hooks/useMediaControls.ts +0 -52
  275. package/src/hooks/useScreenshot.ts +0 -61
  276. package/src/hooks/useSubtitles.ts +0 -91
  277. package/src/hooks/useVideoPlayer.ts +0 -278
  278. package/src/icons/components/FullscreenIcon.tsx +0 -36
  279. package/src/icons/components/SettingsIcon.tsx +0 -37
  280. package/src/icons/components/animated/LoadingIcon.tsx +0 -27
  281. package/src/icons/components/animated/PlayPauseIcon.tsx +0 -42
  282. package/src/icons/components/media/PauseIcon.tsx +0 -38
  283. package/src/icons/components/media/PlayIcon.tsx +0 -37
  284. package/src/icons/components/volume/VolumeIcon.tsx +0 -38
  285. package/src/icons/components/volume/VolumeOffIcon.tsx +0 -38
  286. package/src/icons/index.ts +0 -56
  287. package/src/icons/provider.tsx +0 -58
  288. package/src/icons/types.ts +0 -60
  289. package/src/index-enhanced.ts +0 -35
  290. package/src/index-legacy.ts +0 -324
  291. package/src/index.css +0 -102
  292. package/src/lib/__tests__/async-utils.test.ts +0 -291
  293. package/src/lib/async-utils.ts +0 -194
  294. package/src/lib/deprecation.ts +0 -51
  295. package/src/lib/format-time.ts +0 -37
  296. package/src/lib/index.ts +0 -4
  297. package/src/lib/utils.ts +0 -6
  298. package/src/styles/globals.css +0 -462
  299. package/src/styles/minimal-player.css +0 -621
  300. package/src/styles/pixel-art.css +0 -41
  301. package/src/styles/videojs.css +0 -100
  302. package/src/types/events.ts +0 -47
  303. package/src/types/formats.ts +0 -79
  304. package/src/types/index.ts +0 -203
  305. package/src/types/videojs-plugins.d.ts +0 -14
@@ -1,109 +0,0 @@
1
- "use client"
2
-
3
- import { Button } from "@rp/ui/components/button"
4
- import { Maximize2Icon, Minimize2Icon } from "lucide-react"
5
- import React from "react"
6
- import {
7
- MediaActionTypes,
8
- useMediaContext,
9
- useMediaDispatch,
10
- useMediaSelector
11
- } from "../context/media-context"
12
- import { MediaPlayerTooltip } from "./media-player-tooltip"
13
-
14
- export interface MediaPlayerFullscreenProps {
15
- className?: string
16
- disabled?: boolean
17
- asChild?: boolean
18
- children?: React.ReactNode
19
- }
20
-
21
- export function MediaPlayerFullscreen({
22
- className,
23
- disabled = false,
24
- asChild = false,
25
- children,
26
- ...props
27
- }: MediaPlayerFullscreenProps) {
28
- const context = useMediaContext()
29
- const dispatch = useMediaDispatch()
30
- const isFullscreen = useMediaSelector((state) => state.isFullscreen)
31
- const isDisabled = disabled || useMediaSelector((state) => state.error !== null)
32
-
33
- const handleClick = React.useCallback(
34
- (event: React.MouseEvent) => {
35
- event.preventDefault()
36
-
37
- if (isDisabled) return
38
-
39
- dispatch({
40
- type: isFullscreen ? MediaActionTypes.EXIT_FULLSCREEN : MediaActionTypes.ENTER_FULLSCREEN
41
- })
42
- },
43
- [dispatch, isFullscreen, isDisabled]
44
- )
45
-
46
- // Set up fullscreen API event listeners
47
- React.useEffect(() => {
48
- const handleFullscreenChange = () => {
49
- const isCurrentlyFullscreen = !!document.fullscreenElement
50
- dispatch({
51
- type: isCurrentlyFullscreen
52
- ? MediaActionTypes.ENTER_FULLSCREEN
53
- : MediaActionTypes.EXIT_FULLSCREEN
54
- })
55
- }
56
-
57
- document.addEventListener("fullscreenchange", handleFullscreenChange)
58
- return () => {
59
- document.removeEventListener("fullscreenchange", handleFullscreenChange)
60
- }
61
- }, [dispatch])
62
-
63
- // Handle actual fullscreen API calls
64
- React.useEffect(() => {
65
- const rootElement = context.rootRef.current
66
- if (!rootElement) return
67
-
68
- if (isFullscreen && !document.fullscreenElement) {
69
- rootElement.requestFullscreen?.().catch(console.error)
70
- } else if (!isFullscreen && document.fullscreenElement) {
71
- document.exitFullscreen?.().catch(console.error)
72
- }
73
- }, [isFullscreen, context.rootRef])
74
-
75
- const buttonProps = {
76
- type: "button" as const,
77
- "aria-label": isFullscreen ? "Exit fullscreen" : "Enter fullscreen",
78
- "data-disabled": isDisabled ? "" : undefined,
79
- "data-slot": "media-player-fullscreen",
80
- "data-state": isFullscreen ? "fullscreen" : "inline",
81
- disabled: isDisabled,
82
- variant: "ghost" as const,
83
- size: "icon" as const,
84
- className: "size-8",
85
- onClick: handleClick,
86
- ...props
87
- }
88
-
89
- const content = isFullscreen ? (
90
- <Minimize2Icon className="size-4" />
91
- ) : (
92
- <Maximize2Icon className="size-4" />
93
- )
94
-
95
- if (asChild) {
96
- const child = React.Children.only(children) as React.ReactElement
97
- return React.cloneElement(child, buttonProps as any, content)
98
- }
99
-
100
- return (
101
- <MediaPlayerTooltip
102
- tooltip={isFullscreen ? "Exit fullscreen" : "Enter fullscreen"}
103
- shortcut="F">
104
- <Button {...buttonProps}>{content}</Button>
105
- </MediaPlayerTooltip>
106
- )
107
- }
108
-
109
- MediaPlayerFullscreen.displayName = "MediaPlayerFullscreen"
@@ -1,111 +0,0 @@
1
- "use client"
2
-
3
- import React from "react"
4
- import { TextTrack, VideoJSAdapter, VideoSource } from "../adapters/videojs-adapter"
5
- import { useMediaSelector } from "../context/media-context"
6
- import { cn } from "../lib/utils"
7
- import { MediaPlayerControls } from "./media-player-controls"
8
- import { MediaPlayerError } from "./media-player-error"
9
- import { MediaPlayerLoading } from "./media-player-loading"
10
- import { MediaPlayerRoot, MediaPlayerRootProps } from "./media-player-root"
11
- import "../styles/videojs.css" // Import Video.js styles
12
-
13
- export interface MediaPlayerHLSProps extends Omit<MediaPlayerRootProps, "children"> {
14
- sources: VideoSource[]
15
- poster?: string
16
- textTracks?: TextTrack[]
17
- showControls?: boolean
18
- customControls?: React.ReactNode
19
- hlsConfig?: any
20
- enableQualitySelector?: boolean
21
- enableSubtitles?: boolean
22
- containerClassName?: string
23
- videoClassName?: string
24
- onPlayerReady?: (player: any) => void
25
- onPlayerError?: (error: any) => void
26
- }
27
-
28
- function MediaPlayerHLSContent({
29
- sources,
30
- poster,
31
- textTracks = [],
32
- showControls = true,
33
- customControls,
34
- hlsConfig,
35
- enableQualitySelector = true,
36
- enableSubtitles = true,
37
- containerClassName,
38
- videoClassName,
39
- onPlayerReady,
40
- onPlayerError
41
- }: MediaPlayerHLSProps) {
42
- const isLoading = useMediaSelector((state) => state.isLoading)
43
- const isBuffering = useMediaSelector((state) => state.isBuffering)
44
- const error = useMediaSelector((state) => state.error)
45
-
46
- return (
47
- <div className={cn("relative h-full w-full", containerClassName)}>
48
- {/* Video.js Adapter */}
49
- <VideoJSAdapter
50
- sources={sources}
51
- poster={poster}
52
- textTracks={textTracks}
53
- controls={true} // Enable Video.js controls
54
- autoplay={false}
55
- muted={true} // Muted for autoplay policy
56
- preload="auto"
57
- className={videoClassName}
58
- hlsConfig={hlsConfig}
59
- enableQualitySelector={enableQualitySelector}
60
- enableSubtitles={enableSubtitles}
61
- onReady={onPlayerReady}
62
- onError={onPlayerError}
63
- />
64
-
65
- {/* Loading state */}
66
- {(isLoading || isBuffering) && <MediaPlayerLoading />}
67
-
68
- {/* Error state */}
69
- {error && <MediaPlayerError>{error}</MediaPlayerError>}
70
- </div>
71
- )
72
- }
73
-
74
- export function MediaPlayerHLS(props: MediaPlayerHLSProps) {
75
- const {
76
- sources,
77
- poster,
78
- textTracks,
79
- showControls,
80
- customControls,
81
- hlsConfig,
82
- enableQualitySelector,
83
- enableSubtitles,
84
- containerClassName,
85
- videoClassName,
86
- onPlayerReady,
87
- onPlayerError,
88
- ...rootProps
89
- } = props
90
-
91
- return (
92
- <MediaPlayerRoot {...rootProps}>
93
- <MediaPlayerHLSContent
94
- sources={sources}
95
- poster={poster}
96
- textTracks={textTracks}
97
- showControls={showControls}
98
- customControls={customControls}
99
- hlsConfig={hlsConfig}
100
- enableQualitySelector={enableQualitySelector}
101
- enableSubtitles={enableSubtitles}
102
- containerClassName={containerClassName}
103
- videoClassName={videoClassName}
104
- onPlayerReady={onPlayerReady}
105
- onPlayerError={onPlayerError}
106
- />
107
- </MediaPlayerRoot>
108
- )
109
- }
110
-
111
- MediaPlayerHLS.displayName = "MediaPlayerHLS"
@@ -1,76 +0,0 @@
1
- "use client"
2
-
3
- import { Loader2Icon } from "lucide-react"
4
- import React from "react"
5
- import { useMediaSelector } from "../context/media-context"
6
- import { cn } from "../lib/utils"
7
-
8
- export interface MediaPlayerLoadingProps {
9
- className?: string
10
- delayMs?: number
11
- asChild?: boolean
12
- children?: React.ReactNode
13
- }
14
-
15
- export function MediaPlayerLoading({
16
- className,
17
- delayMs = 300,
18
- asChild = false,
19
- children,
20
- ...props
21
- }: MediaPlayerLoadingProps) {
22
- const isLoading = useMediaSelector((state) => state.isLoading)
23
- const [shouldRender, setShouldRender] = React.useState(false)
24
- const timeoutRef = React.useRef<NodeJS.Timeout | undefined>(undefined)
25
-
26
- React.useEffect(() => {
27
- if (timeoutRef.current) {
28
- clearTimeout(timeoutRef.current)
29
- timeoutRef.current = undefined
30
- }
31
-
32
- if (isLoading) {
33
- if (delayMs > 0) {
34
- timeoutRef.current = setTimeout(() => {
35
- setShouldRender(true)
36
- timeoutRef.current = undefined
37
- }, delayMs)
38
- } else {
39
- setShouldRender(true)
40
- }
41
- } else {
42
- setShouldRender(false)
43
- }
44
-
45
- return () => {
46
- if (timeoutRef.current) {
47
- clearTimeout(timeoutRef.current)
48
- timeoutRef.current = undefined
49
- }
50
- }
51
- }, [isLoading, delayMs])
52
-
53
- if (!shouldRender) return null
54
-
55
- const loadingProps = {
56
- role: "status",
57
- "aria-live": "polite" as const,
58
- "data-slot": "media-player-loading",
59
- className: cn(
60
- "fade-in-0 zoom-in-95 pointer-events-none absolute inset-0 z-50 flex animate-in items-center justify-center duration-200",
61
- className
62
- ),
63
- ...props
64
- }
65
-
66
- const content = <Loader2Icon className="size-8 animate-spin text-white" />
67
-
68
- if (asChild) {
69
- const child = React.Children.only(children) as React.ReactElement
70
- return React.cloneElement(child, loadingProps as any, content)
71
- }
72
-
73
- return <div {...loadingProps}>{content}</div>
74
- }
75
-
76
- MediaPlayerLoading.displayName = "MediaPlayerLoading"
@@ -1,75 +0,0 @@
1
- "use client"
2
-
3
- import { Button } from "@rp/ui/components/button"
4
- import { PauseIcon, PlayIcon } from "lucide-react"
5
- import React from "react"
6
- import {
7
- MediaActionTypes,
8
- useMediaContext,
9
- useMediaDispatch,
10
- useMediaSelector
11
- } from "../context/media-context"
12
- import { MediaPlayerTooltip } from "./media-player-tooltip"
13
-
14
- export interface MediaPlayerPlayProps {
15
- className?: string
16
- asChild?: boolean
17
- children?: React.ReactNode
18
- }
19
-
20
- export function MediaPlayerPlay({
21
- className,
22
- asChild = false,
23
- children,
24
- ...props
25
- }: MediaPlayerPlayProps) {
26
- const context = useMediaContext()
27
- const dispatch = useMediaDispatch()
28
- const isPlaying = useMediaSelector((state) => state.isPlaying)
29
- const disabled = useMediaSelector((state) => state.error !== null)
30
-
31
- const handleClick = React.useCallback(
32
- (event: React.MouseEvent) => {
33
- event.preventDefault()
34
-
35
- const mediaElement = context.mediaRef.current
36
- if (!mediaElement || disabled) return
37
-
38
- dispatch({
39
- type: isPlaying ? MediaActionTypes.PAUSE : MediaActionTypes.PLAY
40
- })
41
- },
42
- [dispatch, context.mediaRef, isPlaying, disabled]
43
- )
44
-
45
- const buttonProps = {
46
- type: "button" as const,
47
- "aria-controls": context.mediaId,
48
- "aria-label": isPlaying ? "Pause" : "Play",
49
- "aria-pressed": isPlaying,
50
- "data-disabled": disabled ? "" : undefined,
51
- "data-slot": "media-player-play",
52
- "data-state": isPlaying ? "playing" : "paused",
53
- disabled,
54
- variant: "ghost" as const,
55
- size: "icon" as const,
56
- className: "size-8 [&_svg:not([class*='fill-'])]:fill-current",
57
- onClick: handleClick,
58
- ...props
59
- }
60
-
61
- const content = isPlaying ? <PauseIcon className="size-4" /> : <PlayIcon className="size-4" />
62
-
63
- if (asChild) {
64
- const child = React.Children.only(children) as React.ReactElement
65
- return React.cloneElement(child, buttonProps as any, content)
66
- }
67
-
68
- return (
69
- <MediaPlayerTooltip tooltip={isPlaying ? "Pause" : "Play"} shortcut="Space">
70
- <Button {...buttonProps}>{content}</Button>
71
- </MediaPlayerTooltip>
72
- )
73
- }
74
-
75
- MediaPlayerPlay.displayName = "MediaPlayerPlay"
@@ -1,338 +0,0 @@
1
- "use client"
2
-
3
- import { useDeviceInfo, useMobileOptimizations } from "@rp/ui/hooks/use-mobile"
4
- import React from "react"
5
- import {
6
- MediaActionTypes,
7
- useMediaContext,
8
- useMediaDispatch,
9
- useMediaSelector
10
- } from "../context/media-context"
11
- import { MediaProvider } from "../context/media-provider"
12
- import { useMediaGestures } from "../hooks/use-touch-gestures"
13
- import { cn } from "../lib/utils"
14
-
15
- // Utility function to compose refs
16
- function composeRefs<T>(...refs: Array<React.Ref<T> | undefined>) {
17
- return (node: T) => {
18
- refs.forEach((ref) => {
19
- if (typeof ref === "function") {
20
- ref(node)
21
- } else if (ref && typeof ref === "object") {
22
- ;(ref as React.MutableRefObject<T>).current = node
23
- }
24
- })
25
- }
26
- }
27
-
28
- // MediaPlayer root component props
29
- export interface MediaPlayerRootProps {
30
- children: React.ReactNode
31
- className?: string
32
- dir?: "ltr" | "rtl"
33
- disabled?: boolean
34
- asChild?: boolean
35
- autoHide?: boolean
36
- tooltipDelayDuration?: number
37
- tooltipSideOffset?: number
38
- withoutTooltip?: boolean
39
-
40
- // Mobile-first options
41
- enableGestures?: boolean
42
- enableMobileOptimizations?: boolean
43
-
44
- // Media event handlers
45
- onPlay?: () => void
46
- onPause?: () => void
47
- onEnded?: () => void
48
- onTimeUpdate?: (currentTime: number) => void
49
- onVolumeChange?: (volume: number) => void
50
- onMuted?: (muted: boolean) => void
51
- onMediaError?: (error: string) => void
52
- onPipError?: (error: Error) => void
53
- onFullscreenChange?: (isFullscreen: boolean) => void
54
- }
55
-
56
- // Internal MediaPlayer implementation
57
- function MediaPlayerImpl({
58
- children,
59
- className,
60
- dir = "ltr",
61
- disabled = false,
62
- asChild = false,
63
- autoHide = true,
64
- enableGestures = true,
65
- enableMobileOptimizations = true,
66
- onPlay,
67
- onPause,
68
- onEnded,
69
- onTimeUpdate,
70
- onVolumeChange,
71
- onMuted,
72
- onMediaError,
73
- onPipError,
74
- onFullscreenChange,
75
- ...props
76
- }: MediaPlayerRootProps) {
77
- const context = useMediaContext()
78
- const dispatch = useMediaDispatch()
79
- const { isTouchDevice } = useDeviceInfo()
80
-
81
- // Get state values
82
- const isPlaying = useMediaSelector((state) => state.isPlaying)
83
- const currentTime = useMediaSelector((state) => state.currentTime)
84
- const volume = useMediaSelector((state) => state.volume)
85
- const isMuted = useMediaSelector((state) => state.isMuted)
86
- const error = useMediaSelector((state) => state.error)
87
- const isFullscreen = useMediaSelector((state) => state.isFullscreen)
88
- const isPictureInPicture = useMediaSelector((state) => state.isPictureInPicture)
89
-
90
- // Enable mobile optimizations
91
- useMobileOptimizations()
92
-
93
- // Gesture handling actions - React 19 compiler will optimize this
94
- const gestureActions = {
95
- onPlayPause: () => {
96
- if (disabled) return
97
- dispatch({
98
- type: isPlaying ? MediaActionTypes.PAUSE : MediaActionTypes.PLAY
99
- })
100
- },
101
- onSeek: (direction: "forward" | "backward", amount: number) => {
102
- if (disabled || !context.isVideo) return
103
- const mediaElement = context.mediaRef.current
104
- if (!mediaElement) return
105
-
106
- const newTime =
107
- direction === "forward"
108
- ? Math.min(mediaElement.duration || 0, currentTime + amount)
109
- : Math.max(0, currentTime - amount)
110
-
111
- dispatch({
112
- type: MediaActionTypes.SEEK,
113
- detail: newTime
114
- })
115
- },
116
- onVolumeChange: (direction: "up" | "down", amount: number) => {
117
- if (disabled) return
118
- const newVolume =
119
- direction === "up" ? Math.min(1, volume + amount) : Math.max(0, volume - amount)
120
-
121
- dispatch({
122
- type: MediaActionTypes.SET_VOLUME,
123
- detail: newVolume
124
- })
125
- },
126
- onToggleFullscreen: () => {
127
- if (disabled || !context.isVideo) return
128
- dispatch({
129
- type: isFullscreen ? MediaActionTypes.EXIT_FULLSCREEN : MediaActionTypes.ENTER_FULLSCREEN
130
- })
131
- },
132
- onZoom: (scale: number) => {
133
- // Handle video zoom - this could be implemented with CSS transforms
134
- // For now, we'll just log it as a placeholder
135
- console.log("Zoom gesture detected:", scale)
136
- }
137
- }
138
-
139
- // Set up touch gestures for mobile devices
140
- const { isGestureEnabled } = useMediaGestures(
141
- context.rootRef as React.RefObject<HTMLElement>,
142
- enableGestures ? gestureActions : {}
143
- )
144
-
145
- // Keyboard event handler - React 19 compiler will optimize this
146
- const handleKeyDown = (event: React.KeyboardEvent) => {
147
- if (disabled) return
148
-
149
- const target = event.target as HTMLElement
150
- const isInputElement =
151
- target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable
152
-
153
- if (isInputElement) return
154
-
155
- const mediaElement = context.mediaRef.current
156
- if (!mediaElement) return
157
-
158
- switch (event.code) {
159
- case "Space":
160
- case "KeyK":
161
- event.preventDefault()
162
- dispatch({
163
- type: isPlaying ? MediaActionTypes.PAUSE : MediaActionTypes.PLAY
164
- })
165
- break
166
-
167
- case "KeyF":
168
- event.preventDefault()
169
- dispatch({
170
- type: isFullscreen ? MediaActionTypes.EXIT_FULLSCREEN : MediaActionTypes.ENTER_FULLSCREEN
171
- })
172
- break
173
-
174
- case "KeyM":
175
- event.preventDefault()
176
- dispatch({
177
- type: MediaActionTypes.TOGGLE_MUTE
178
- })
179
- break
180
-
181
- case "ArrowLeft":
182
- event.preventDefault()
183
- if (context.isVideo && mediaElement instanceof HTMLVideoElement) {
184
- dispatch({
185
- type: MediaActionTypes.SEEK,
186
- detail: Math.max(0, currentTime - 10)
187
- })
188
- }
189
- break
190
-
191
- case "ArrowRight":
192
- event.preventDefault()
193
- if (context.isVideo && mediaElement instanceof HTMLVideoElement) {
194
- dispatch({
195
- type: MediaActionTypes.SEEK,
196
- detail: Math.min(mediaElement.duration || 0, currentTime + 10)
197
- })
198
- }
199
- break
200
-
201
- case "ArrowUp":
202
- event.preventDefault()
203
- dispatch({
204
- type: MediaActionTypes.SET_VOLUME,
205
- detail: Math.min(1, volume + 0.1)
206
- })
207
- break
208
-
209
- case "ArrowDown":
210
- event.preventDefault()
211
- dispatch({
212
- type: MediaActionTypes.SET_VOLUME,
213
- detail: Math.max(0, volume - 0.1)
214
- })
215
- break
216
- }
217
- }
218
-
219
- // Set up media element event listeners
220
- React.useEffect(() => {
221
- const mediaElement = context.mediaRef.current
222
- if (!mediaElement) return
223
-
224
- const handlePlay = () => {
225
- dispatch({ type: MediaActionTypes.PLAY })
226
- onPlay?.()
227
- }
228
-
229
- const handlePause = () => {
230
- dispatch({ type: MediaActionTypes.PAUSE })
231
- onPause?.()
232
- }
233
-
234
- const handleEnded = () => {
235
- dispatch({ type: MediaActionTypes.PAUSE })
236
- onEnded?.()
237
- }
238
-
239
- const handleTimeUpdate = () => {
240
- const time = mediaElement.currentTime
241
- dispatch({ type: MediaActionTypes.SET_CURRENT_TIME, detail: time })
242
- onTimeUpdate?.(time)
243
- }
244
-
245
- const handleVolumeChange = () => {
246
- const vol = mediaElement.volume
247
- const muted = mediaElement.muted
248
- dispatch({ type: MediaActionTypes.SET_VOLUME, detail: vol })
249
- dispatch({ type: muted ? MediaActionTypes.MUTE : MediaActionTypes.UNMUTE })
250
- onVolumeChange?.(vol)
251
- onMuted?.(muted)
252
- }
253
-
254
- const handleLoadedMetadata = () => {
255
- dispatch({ type: MediaActionTypes.SET_DURATION, detail: mediaElement.duration })
256
- dispatch({ type: MediaActionTypes.SET_LOADING, detail: false })
257
- }
258
-
259
- const handleError = () => {
260
- const errorMessage = "An error occurred while loading the media"
261
- dispatch({ type: MediaActionTypes.SET_ERROR, detail: errorMessage })
262
- onMediaError?.(errorMessage)
263
- }
264
-
265
- const handleLoadStart = () => {
266
- dispatch({ type: MediaActionTypes.SET_LOADING, detail: true })
267
- }
268
-
269
- // Add event listeners
270
- mediaElement.addEventListener("play", handlePlay)
271
- mediaElement.addEventListener("pause", handlePause)
272
- mediaElement.addEventListener("ended", handleEnded)
273
- mediaElement.addEventListener("timeupdate", handleTimeUpdate)
274
- mediaElement.addEventListener("volumechange", handleVolumeChange)
275
- mediaElement.addEventListener("loadedmetadata", handleLoadedMetadata)
276
- mediaElement.addEventListener("error", handleError)
277
- mediaElement.addEventListener("loadstart", handleLoadStart)
278
-
279
- return () => {
280
- mediaElement.removeEventListener("play", handlePlay)
281
- mediaElement.removeEventListener("pause", handlePause)
282
- mediaElement.removeEventListener("ended", handleEnded)
283
- mediaElement.removeEventListener("timeupdate", handleTimeUpdate)
284
- mediaElement.removeEventListener("volumechange", handleVolumeChange)
285
- mediaElement.removeEventListener("loadedmetadata", handleLoadedMetadata)
286
- mediaElement.removeEventListener("error", handleError)
287
- mediaElement.removeEventListener("loadstart", handleLoadStart)
288
- }
289
- }, [dispatch, onPlay, onPause, onEnded, onTimeUpdate, onVolumeChange, onMuted, onMediaError])
290
-
291
- const rootProps = {
292
- "aria-labelledby": context.labelId,
293
- "aria-describedby": context.descriptionId,
294
- "aria-disabled": disabled,
295
- "data-disabled": disabled ? "" : undefined,
296
- "data-slot": "media-player",
297
- "data-state": isFullscreen ? "fullscreen" : "inline",
298
- dir,
299
- tabIndex: disabled ? -1 : 0,
300
- className: cn(
301
- "dark relative isolate flex flex-col overflow-hidden rounded-lg bg-background outline-none",
302
- "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50",
303
- "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
304
- "[&_video]:relative [&_video]:object-contain",
305
- "data-[state=fullscreen]:[&_video]:size-full",
306
- "[:fullscreen_&]:flex [:fullscreen_&]:h-full [:fullscreen_&]:max-h-screen [:fullscreen_&]:flex-col [:fullscreen_&]:justify-between",
307
- // Mobile-first optimizations
308
- isTouchDevice && [
309
- "touch-manipulation", // Improves touch responsiveness
310
- "select-none", // Prevents text selection during gestures
311
- "overscroll-contain" // Prevents scroll chaining
312
- ],
313
- // Enable hardware acceleration for smooth animations
314
- "will-change-transform",
315
- "transform-gpu",
316
- className
317
- ),
318
- onKeyDown: handleKeyDown,
319
- ...props
320
- }
321
-
322
- return (
323
- <div ref={composeRefs(context.rootRef)} {...rootProps}>
324
- {children}
325
- </div>
326
- )
327
- }
328
-
329
- // Main MediaPlayer component with provider
330
- export function MediaPlayerRoot(props: MediaPlayerRootProps) {
331
- return (
332
- <MediaProvider>
333
- <MediaPlayerImpl {...props} />
334
- </MediaProvider>
335
- )
336
- }
337
-
338
- MediaPlayerRoot.displayName = "MediaPlayerRoot"