@therealtinhtute/baroiplayer 1.0.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 (244) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +384 -0
  3. package/dist/context/media.js +2 -0
  4. package/dist/context/media.js.map +1 -0
  5. package/dist/context/media.mjs +15 -0
  6. package/dist/context/media.mjs.map +1 -0
  7. package/dist/context/store.js +2 -0
  8. package/dist/context/store.js.map +1 -0
  9. package/dist/context/store.mjs +5 -0
  10. package/dist/context/store.mjs.map +1 -0
  11. package/dist/context-BMteAJDN.js +1140 -0
  12. package/dist/context-BMteAJDN.js.map +1 -0
  13. package/dist/context-DCJ_scmO.cjs +23 -0
  14. package/dist/context-DCJ_scmO.cjs.map +1 -0
  15. package/dist/core-events-B5W_j8yU.js +480 -0
  16. package/dist/core-events-B5W_j8yU.js.map +1 -0
  17. package/dist/core-events-CN0-Vhhq.cjs +2 -0
  18. package/dist/core-events-CN0-Vhhq.cjs.map +1 -0
  19. package/dist/core-plugins-Bq9KLany.js +696 -0
  20. package/dist/core-plugins-Bq9KLany.js.map +1 -0
  21. package/dist/core-plugins-CPDSHMiQ.cjs +2 -0
  22. package/dist/core-plugins-CPDSHMiQ.cjs.map +1 -0
  23. package/dist/core.js +37 -0
  24. package/dist/core.js.map +1 -0
  25. package/dist/core.mjs +1217 -0
  26. package/dist/core.mjs.map +1 -0
  27. package/dist/enhanced-components-DHv0MFvG.js +1073 -0
  28. package/dist/enhanced-components-DHv0MFvG.js.map +1 -0
  29. package/dist/enhanced-components-DTIObgB7.cjs +2 -0
  30. package/dist/enhanced-components-DTIObgB7.cjs.map +1 -0
  31. package/dist/hooks-C_r8wexn.cjs +4 -0
  32. package/dist/hooks-C_r8wexn.cjs.map +1 -0
  33. package/dist/hooks-Da2wVXlF.js +1630 -0
  34. package/dist/hooks-Da2wVXlF.js.map +1 -0
  35. package/dist/index.css +1 -0
  36. package/dist/index.js +112 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/index.mjs +6126 -0
  39. package/dist/index.mjs.map +1 -0
  40. package/dist/minimal-components-DSq5sQpy.js +2002 -0
  41. package/dist/minimal-components-DSq5sQpy.js.map +1 -0
  42. package/dist/minimal-components-DflWiihN.cjs +2 -0
  43. package/dist/minimal-components-DflWiihN.cjs.map +1 -0
  44. package/dist/minimal-components.css +1 -0
  45. package/dist/mona-loading.gif +0 -0
  46. package/dist/performance-monitor-CUW6f5ll.cjs +2 -0
  47. package/dist/performance-monitor-CUW6f5ll.cjs.map +1 -0
  48. package/dist/performance-monitor-rMW1RgV3.js +302 -0
  49. package/dist/performance-monitor-rMW1RgV3.js.map +1 -0
  50. package/dist/utils-BnscpYYd.js +2798 -0
  51. package/dist/utils-BnscpYYd.js.map +1 -0
  52. package/dist/utils-D_czS_0K.cjs +9 -0
  53. package/dist/utils-D_czS_0K.cjs.map +1 -0
  54. package/dist/utils.js +2 -0
  55. package/dist/utils.js.map +1 -0
  56. package/dist/utils.mjs +7 -0
  57. package/dist/utils.mjs.map +1 -0
  58. package/package.json +114 -0
  59. package/src/adapters/videojs-adapter.tsx +470 -0
  60. package/src/assets/mona-loading.gif +0 -0
  61. package/src/components/AnimateLoading.tsx +115 -0
  62. package/src/components/LoadingState.tsx +248 -0
  63. package/src/components/accessibility/keyboard-help-overlay.tsx +213 -0
  64. package/src/components/audio-player.tsx +85 -0
  65. package/src/components/basic/index.ts +37 -0
  66. package/src/components/enhanced/advanced-features.tsx +316 -0
  67. package/src/components/enhanced/debug-panel.tsx +422 -0
  68. package/src/components/enhanced/enhanced-controls.tsx +600 -0
  69. package/src/components/enhanced/enhanced-media-player.tsx +509 -0
  70. package/src/components/enhanced/error-handling.tsx +345 -0
  71. package/src/components/enhanced/index.ts +39 -0
  72. package/src/components/enhanced/media-player-enhanced.tsx +349 -0
  73. package/src/components/examples/basic-video-player.tsx +55 -0
  74. package/src/components/examples/custom-controls-example.tsx +63 -0
  75. package/src/components/examples/enhanced-controls-example.tsx +114 -0
  76. package/src/components/examples/enhanced-media-player-example.tsx +293 -0
  77. package/src/components/examples/loading-states-demo.tsx +142 -0
  78. package/src/components/examples/react-19-demo.tsx +381 -0
  79. package/src/components/examples/volume-orientation-demo.tsx +114 -0
  80. package/src/components/icon-demo.tsx +209 -0
  81. package/src/components/icons/index.tsx +166 -0
  82. package/src/components/icons/svg-icons/ArrowLeftIcon.tsx +18 -0
  83. package/src/components/icons/svg-icons/ArrowRightIcon.tsx +18 -0
  84. package/src/components/icons/svg-icons/AudioIcon.tsx +22 -0
  85. package/src/components/icons/svg-icons/BackwardIcon.tsx +12 -0
  86. package/src/components/icons/svg-icons/CameraIcon.tsx +19 -0
  87. package/src/components/icons/svg-icons/CheckIcon.tsx +19 -0
  88. package/src/components/icons/svg-icons/EnablePiPIcon.tsx +17 -0
  89. package/src/components/icons/svg-icons/ForwardIcon.tsx +12 -0
  90. package/src/components/icons/svg-icons/FullscreenEnterIcon.tsx +23 -0
  91. package/src/components/icons/svg-icons/FullscreenExitIcon.tsx +23 -0
  92. package/src/components/icons/svg-icons/LoadingIcon.tsx +32 -0
  93. package/src/components/icons/svg-icons/PauseIcon.tsx +23 -0
  94. package/src/components/icons/svg-icons/PlayIcon.tsx +21 -0
  95. package/src/components/icons/svg-icons/PlaybackSpeedIcon.tsx +23 -0
  96. package/src/components/icons/svg-icons/QualityIcon.tsx +21 -0
  97. package/src/components/icons/svg-icons/SettingsIcon.tsx +12 -0
  98. package/src/components/icons/svg-icons/SliderIcon.tsx +21 -0
  99. package/src/components/icons/svg-icons/SubtitleIcon.tsx +21 -0
  100. package/src/components/icons/svg-icons/SubtitleOffIcon.tsx +25 -0
  101. package/src/components/icons/svg-icons/UnPiPIcon.tsx +17 -0
  102. package/src/components/icons/svg-icons/VolumeMutedIcon.tsx +16 -0
  103. package/src/components/icons/svg-icons/VolumeOneIcon.tsx +22 -0
  104. package/src/components/icons/svg-icons/VolumeThreeIcon.tsx +16 -0
  105. package/src/components/icons/svg-icons/VolumeTwoIcon.tsx +16 -0
  106. package/src/components/legacy.tsx +93 -0
  107. package/src/components/media-metadata-display.tsx +100 -0
  108. package/src/components/media-player-audio.tsx +39 -0
  109. package/src/components/media-player-controls.tsx +226 -0
  110. package/src/components/media-player-error.tsx +163 -0
  111. package/src/components/media-player-fullscreen.tsx +109 -0
  112. package/src/components/media-player-hls.tsx +111 -0
  113. package/src/components/media-player-loading.tsx +76 -0
  114. package/src/components/media-player-play.tsx +75 -0
  115. package/src/components/media-player-root.tsx +340 -0
  116. package/src/components/media-player-seek.tsx +168 -0
  117. package/src/components/media-player-time.tsx +99 -0
  118. package/src/components/media-player-tooltip.tsx +58 -0
  119. package/src/components/media-player-video.tsx +39 -0
  120. package/src/components/media-player-volume.tsx +155 -0
  121. package/src/components/media-player.tsx +257 -0
  122. package/src/components/media-suspense.tsx +362 -0
  123. package/src/components/player-settings-form.tsx +163 -0
  124. package/src/components/react-player-wrapper.tsx +651 -0
  125. package/src/components/simple-video-player.tsx +60 -0
  126. package/src/components/ui/enhanced-seek-bar.tsx +235 -0
  127. package/src/components/ui/fullscreen-button.tsx +60 -0
  128. package/src/components/ui/media-resource-preloader.tsx +395 -0
  129. package/src/components/ui/play-button.tsx +107 -0
  130. package/src/components/ui/seek-bar.tsx +161 -0
  131. package/src/components/ui/time-display.tsx +40 -0
  132. package/src/components/ui/volume-control.tsx +143 -0
  133. package/src/components/unified/base-media-player.tsx +246 -0
  134. package/src/components/unified/media-player.tsx +75 -0
  135. package/src/components/variants/minimal/AccessibleMinimalPlayer.tsx +561 -0
  136. package/src/components/variants/minimal/EnhancedMinimalMediaPlayer.tsx +552 -0
  137. package/src/components/variants/minimal/MinimalControls.tsx +142 -0
  138. package/src/components/variants/minimal/MinimalLoading.tsx +32 -0
  139. package/src/components/variants/minimal/MinimalMediaPlayer.tsx +315 -0
  140. package/src/components/variants/minimal/MinimalOverlay.tsx +64 -0
  141. package/src/components/variants/minimal/MinimalPlayButton.tsx +65 -0
  142. package/src/components/variants/minimal/MinimalSeekBar.tsx +150 -0
  143. package/src/components/variants/minimal/MinimalVolumeControl.tsx +80 -0
  144. package/src/components/variants/minimal/SimpleMinimalPlayer.tsx +210 -0
  145. package/src/components/variants/minimal/components/CenterPlayButton.tsx +22 -0
  146. package/src/components/variants/minimal/components/ControlBar.tsx +146 -0
  147. package/src/components/variants/minimal/components/EnhancedSettingsMenu.tsx +361 -0
  148. package/src/components/variants/minimal/components/PlaybackControls.tsx +51 -0
  149. package/src/components/variants/minimal/components/RightControls.tsx +173 -0
  150. package/src/components/variants/minimal/components/SeekBar.tsx +131 -0
  151. package/src/components/variants/minimal/components/SettingsDropdown.tsx +70 -0
  152. package/src/components/variants/minimal/components/SubtitleDisplay.tsx +21 -0
  153. package/src/components/variants/minimal/components/TimeDisplay.tsx +18 -0
  154. package/src/components/variants/minimal/components/VideoElement.tsx +40 -0
  155. package/src/components/variants/minimal/components/VolumeControl.tsx +217 -0
  156. package/src/components/variants/minimal/index.ts +23 -0
  157. package/src/components/video-player.tsx +100 -0
  158. package/src/context/error-handling.ts +394 -0
  159. package/src/context/media-context.tsx +208 -0
  160. package/src/context/media-provider.tsx +265 -0
  161. package/src/context/media-store.ts +379 -0
  162. package/src/context/persistence.ts +453 -0
  163. package/src/core/events/event-system.ts +442 -0
  164. package/src/core/events/hooks.ts +302 -0
  165. package/src/core/events/index.ts +22 -0
  166. package/src/core/events/middleware.ts +269 -0
  167. package/src/core/index.ts +22 -0
  168. package/src/core/optimization/bundle-optimizer.tsx +308 -0
  169. package/src/core/performance/cicd.ts +96 -0
  170. package/src/core/performance/index.ts +38 -0
  171. package/src/core/performance/media-loading-optimizer.ts +538 -0
  172. package/src/core/performance/performance-budgets.ts +432 -0
  173. package/src/core/performance/performance-monitor.tsx +476 -0
  174. package/src/core/performance/performance-testing.ts +459 -0
  175. package/src/core/plugins/base-plugin.ts +224 -0
  176. package/src/core/plugins/enhanced-plugin-system.ts +411 -0
  177. package/src/core/plugins/examples/analytics-plugin.ts +242 -0
  178. package/src/core/plugins/index.ts +39 -0
  179. package/src/core/plugins/registry.ts +327 -0
  180. package/src/core/plugins/types.ts +159 -0
  181. package/src/core/plugins/utils.ts +316 -0
  182. package/src/core/progressive-loading.tsx +322 -0
  183. package/src/core/providers/enhanced-hls-provider.ts +339 -0
  184. package/src/core/providers/service-provider.tsx +168 -0
  185. package/src/core/utils.tsx +38 -0
  186. package/src/features/media-session/media-session-manager.ts +429 -0
  187. package/src/features/picture-in-picture/pip-manager.ts +429 -0
  188. package/src/features/playlist/playlist-manager.ts +606 -0
  189. package/src/features/subtitles/subtitle-manager.ts +441 -0
  190. package/src/features/subtitles/subtitle-parser.ts +280 -0
  191. package/src/features/thumbnails/thumbnail-generator.ts +519 -0
  192. package/src/hooks/accessibility/index.ts +27 -0
  193. package/src/hooks/accessibility/use-accessibility-preferences.ts +188 -0
  194. package/src/hooks/accessibility/use-focus-management.ts +176 -0
  195. package/src/hooks/accessibility/use-keyboard-shortcuts.ts +144 -0
  196. package/src/hooks/accessibility/use-screen-reader.ts +182 -0
  197. package/src/hooks/core/index.ts +47 -0
  198. package/src/hooks/legacy.ts +27 -0
  199. package/src/hooks/use-enhanced-media-player.ts +468 -0
  200. package/src/hooks/use-intelligent-preloading.ts +358 -0
  201. package/src/hooks/use-keyboard-controls.ts +115 -0
  202. package/src/hooks/use-media-actions.ts +175 -0
  203. package/src/hooks/use-media-metadata.ts +89 -0
  204. package/src/hooks/use-media-optimistic.ts +270 -0
  205. package/src/hooks/use-media-player.ts +312 -0
  206. package/src/hooks/use-media-state.ts +190 -0
  207. package/src/hooks/use-memory-optimization.ts +358 -0
  208. package/src/hooks/use-optimistic-controls.ts +92 -0
  209. package/src/hooks/use-optimized-media.ts +263 -0
  210. package/src/hooks/use-touch-gestures.ts +417 -0
  211. package/src/hooks/useEnhancedSubtitles.ts +258 -0
  212. package/src/hooks/useKeyboardShortcuts.ts +74 -0
  213. package/src/hooks/useMediaControls.ts +52 -0
  214. package/src/hooks/useScreenshot.ts +57 -0
  215. package/src/hooks/useSubtitles.ts +91 -0
  216. package/src/hooks/useVideoPlayer.ts +232 -0
  217. package/src/icons/components/FullscreenIcon.tsx +37 -0
  218. package/src/icons/components/SettingsIcon.tsx +38 -0
  219. package/src/icons/components/animated/LoadingIcon.tsx +43 -0
  220. package/src/icons/components/animated/PlayPauseIcon.tsx +50 -0
  221. package/src/icons/components/media/PauseIcon.tsx +39 -0
  222. package/src/icons/components/media/PlayIcon.tsx +38 -0
  223. package/src/icons/components/volume/VolumeIcon.tsx +39 -0
  224. package/src/icons/components/volume/VolumeOffIcon.tsx +39 -0
  225. package/src/icons/index.ts +56 -0
  226. package/src/icons/provider.tsx +64 -0
  227. package/src/icons/types.ts +40 -0
  228. package/src/index-enhanced.ts +35 -0
  229. package/src/index-legacy.ts +326 -0
  230. package/src/index.css +102 -0
  231. package/src/index.ts +216 -0
  232. package/src/lib/deprecation.ts +51 -0
  233. package/src/lib/format-time.ts +37 -0
  234. package/src/lib/index.ts +3 -0
  235. package/src/lib/utils.ts +6 -0
  236. package/src/styles/globals.css +462 -0
  237. package/src/styles/minimal-player.css +589 -0
  238. package/src/styles/pixel-art.css +46 -0
  239. package/src/styles/videojs.css +100 -0
  240. package/src/test/setup.ts +79 -0
  241. package/src/types/events.ts +47 -0
  242. package/src/types/formats.ts +95 -0
  243. package/src/types/index.ts +190 -0
  244. package/src/types/videojs-plugins.d.ts +14 -0
@@ -0,0 +1,47 @@
1
+ // Core Media Player Hooks
2
+ export { useKeyboardControls } from "../use-keyboard-controls";
3
+ export { useMediaPlayer } from "../use-media-player";
4
+
5
+ // Media State Hooks
6
+ export {
7
+ useAdaptiveMediaState,
8
+ useEnhancedMediaState,
9
+ useMediaState
10
+ } from "../use-media-state";
11
+
12
+ // React 19 Advanced Hooks
13
+ export {
14
+ useMediaActions,
15
+ useMediaActionState
16
+ } from "../use-media-actions";
17
+ export type { MediaActionPayloads } from "../use-media-actions";
18
+
19
+ export {
20
+ useMediaOptimistic,
21
+ useMediaStateComparison,
22
+ useOptimisticUpdates
23
+ } from "../use-media-optimistic";
24
+
25
+ // Mobile-First Touch Gestures
26
+ export {
27
+ useMediaGestures,
28
+ useTouchGestures
29
+ } from "../use-touch-gestures";
30
+ export type {
31
+ GestureConfig,
32
+ GestureEvent,
33
+ GestureType
34
+ } from "../use-touch-gestures";
35
+
36
+ // Refactored Hooks (React 19 optimized)
37
+ export { useVideoPlayer } from "../useVideoPlayer";
38
+ export { useSubtitles } from "../useSubtitles";
39
+ export { useEnhancedSubtitles } from "../useEnhancedSubtitles";
40
+ export type { SubtitleTrack, UseEnhancedSubtitlesOptions } from "../useEnhancedSubtitles";
41
+ export { useMediaControls } from "../useMediaControls";
42
+ export { useScreenshot } from "../useScreenshot";
43
+ export type { VideoState, VideoControls } from "../useVideoPlayer";
44
+
45
+ // Specialized hooks
46
+ export { useMediaMetadata } from "../use-media-metadata";
47
+ export { useOptimisticControls } from "../use-optimistic-controls";
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Legacy Hooks (Deprecated)
3
+ * These hooks are wrapped with deprecation warnings
4
+ */
5
+
6
+ import { showDeprecationWarning } from "../lib/deprecation"
7
+
8
+ // Import current hooks
9
+ import { useMediaPlayer } from "./use-media-player"
10
+ import { useSubtitles } from "./useSubtitles"
11
+
12
+ // Legacy hook wrappers with deprecation warnings
13
+ export function useVideoPlayer(props: any) {
14
+ showDeprecationWarning(
15
+ "useVideoPlayer",
16
+ "useMediaPlayer (the primary media player hook)"
17
+ )
18
+ return useMediaPlayer(props)
19
+ }
20
+
21
+ export function useEnhancedSubtitles(props: any) {
22
+ showDeprecationWarning(
23
+ "useEnhancedSubtitles",
24
+ "useSubtitles (the current subtitle hook)"
25
+ )
26
+ return useSubtitles(props)
27
+ }
@@ -0,0 +1,468 @@
1
+ "use client"
2
+
3
+ import React, {
4
+ useCallback,
5
+ useEffect,
6
+ useRef,
7
+ useMemo,
8
+ useTransition,
9
+ useOptimistic,
10
+ useActionState
11
+ } from "react"
12
+ import type { MediaPlayerControls, MediaPlayerState } from "../types/index"
13
+ import { useMediaStore, useMediaSelector } from "../context/media-context"
14
+ import { useMediaOptimistic } from "./use-media-optimistic"
15
+ import { useMediaActions } from "./use-media-actions"
16
+ import type { EnhancedMediaStore } from "../context/media-store"
17
+
18
+ interface UseEnhancedMediaPlayerOptions {
19
+ src: string | string[]
20
+ autoPlay?: boolean
21
+ loop?: boolean
22
+ muted?: boolean
23
+ volume?: number
24
+ preload?: "none" | "metadata" | "auto"
25
+ crossOrigin?: "anonymous" | "use-credentials"
26
+ playbackRates?: number[]
27
+ keyboardControls?: boolean
28
+ showControls?: boolean
29
+ customControls?: boolean
30
+ enablePerformanceMonitoring?: boolean
31
+ bufferingStrategy?: "aggressive" | "conservative" | "adaptive"
32
+ // Performance optimizations
33
+ enableTimeUpdateThrottling?: boolean
34
+ timeUpdateThrottleMs?: number
35
+ enableSeekPreview?: boolean
36
+ preloadStrategy?: "eager" | "lazy" | "progressive"
37
+ }
38
+
39
+ // Performance-optimized media player hook with React 19 features
40
+ export function useEnhancedMediaPlayer(options: UseEnhancedMediaPlayerOptions) {
41
+ const mediaRef = useRef<HTMLVideoElement | HTMLAudioElement>(null)
42
+ const containerRef = useRef<HTMLDivElement>(null)
43
+
44
+ // React 19 concurrent features
45
+ const [isPending, startTransition] = useTransition()
46
+ const [isSeeking, startSeekTransition] = useTransition()
47
+
48
+ // Performance monitoring
49
+ const renderStartTime = React.useRef<number>(0)
50
+ const frameCount = React.useRef<number>(0)
51
+ const lastFrameTime = React.useRef<number>(0)
52
+
53
+ // Throttled time update
54
+ const timeUpdateTimeoutRef = useRef<NodeJS.Timeout>()
55
+ const lastTimeUpdate = useRef<number>(0)
56
+
57
+ // Store integration
58
+ const store = useMediaStore()
59
+ const isEnhanced = 'getOptimisticState' in store
60
+
61
+ // Select only the state we need to minimize re-renders
62
+ const isPlaying = useMediaSelector(state => state.isPlaying)
63
+ const currentTime = useMediaSelector(state => state.currentTime)
64
+ const duration = useMediaSelector(state => state.duration)
65
+ const volume = useMediaSelector(state => state.volume)
66
+ const isMuted = useMediaSelector(state => state.isMuted)
67
+ const isLoading = useMediaSelector(state => state.isLoading)
68
+ const isBuffering = useMediaSelector(state => state.isBuffering)
69
+ const error = useMediaSelector(state => state.error)
70
+ const buffered = useMediaSelector(state => state.buffered)
71
+ const isFullscreen = useMediaSelector(state => state.isFullscreen)
72
+
73
+ // Enhanced features if available
74
+ const enhancedStore = store as unknown as EnhancedMediaStore
75
+ const optimisticState = isEnhanced ? useMediaOptimistic(enhancedStore) : null
76
+ const actions = isEnhanced ? useMediaActions(enhancedStore) : null
77
+
78
+ // Performance state
79
+ const [performanceMetrics, setPerformanceMetrics] = React.useState({
80
+ frameRate: 0,
81
+ averageRenderTime: 0,
82
+ droppedFrames: 0,
83
+ bufferHealth: 0
84
+ })
85
+
86
+ // Optimistic state updates for immediate UI feedback
87
+ const [optimisticVolume, setOptimisticVolume] = useOptimistic(volume, (state, newVolume: number) => {
88
+ return Math.max(0, Math.min(1, newVolume))
89
+ })
90
+
91
+ const [optimisticTime, setOptimisticTime] = useOptimistic(currentTime, (state, newTime: number) => {
92
+ return Math.max(0, Math.min(duration || 0, newTime))
93
+ })
94
+
95
+ // Initialize media element with performance optimizations
96
+ useEffect(() => {
97
+ const media = mediaRef.current
98
+ if (!media) return
99
+
100
+ // Set initial properties
101
+ const initProps = {
102
+ volume: options.volume,
103
+ muted: options.muted,
104
+ autoplay: options.autoPlay,
105
+ loop: options.loop,
106
+ preload: options.preload,
107
+ crossOrigin: options.crossOrigin
108
+ }
109
+
110
+ Object.entries(initProps).forEach(([key, value]) => {
111
+ if (value !== undefined) {
112
+ (media as any)[key] = value
113
+ }
114
+ })
115
+
116
+ // Performance optimizations
117
+ media.setAttribute('preload', options.preloadStrategy === 'eager' ? 'auto' : 'metadata')
118
+
119
+ if (options.bufferingStrategy === 'aggressive') {
120
+ media.setAttribute('buffered', 'auto')
121
+ }
122
+
123
+ // Hardware acceleration
124
+ if (media instanceof HTMLVideoElement) {
125
+ media.style.willChange = 'transform'
126
+ media.style.transform = 'translateZ(0)'
127
+ }
128
+ }, [
129
+ options.volume,
130
+ options.muted,
131
+ options.autoPlay,
132
+ options.loop,
133
+ options.preload,
134
+ options.crossOrigin,
135
+ options.preloadStrategy,
136
+ options.bufferingStrategy
137
+ ])
138
+
139
+ // Optimized event handlers with React 19 patterns
140
+ const handleTimeUpdate = useCallback(() => {
141
+ const media = mediaRef.current
142
+ if (!media) return
143
+
144
+ const now = performance.now()
145
+
146
+ // Throttle time updates for performance
147
+ if (options.enableTimeUpdateThrottling !== false) {
148
+ if (now - lastTimeUpdate.current < (options.timeUpdateThrottleMs || 100)) {
149
+ return
150
+ }
151
+ lastTimeUpdate.current = now
152
+ }
153
+
154
+ startTransition(() => {
155
+ if (isEnhanced && actions) {
156
+ actions.setCurrentTime(media.currentTime)
157
+ }
158
+ })
159
+ }, [options.enableTimeUpdateThrottling, options.timeUpdateThrottleMs, isEnhanced, actions])
160
+
161
+ const handlePlay = useCallback(() => {
162
+ startTransition(() => {
163
+ if (isEnhanced && actions) {
164
+ actions.play(true) // Optimistic update
165
+ }
166
+ })
167
+ options.onPlay?.()
168
+ }, [isEnhanced, actions, options.onPlay])
169
+
170
+ const handlePause = useCallback(() => {
171
+ startTransition(() => {
172
+ if (isEnhanced && actions) {
173
+ actions.pause(true) // Optimistic update
174
+ }
175
+ })
176
+ options.onPause?.()
177
+ }, [isEnhanced, actions, options.onPause])
178
+
179
+ const handleVolumeChange = useCallback(() => {
180
+ const media = mediaRef.current
181
+ if (!media) return
182
+
183
+ startTransition(() => {
184
+ if (isEnhanced && actions) {
185
+ actions.setVolume(media.volume, true) // Optimistic update
186
+ media.muted ? actions.mute(true) : actions.unmute(true)
187
+ }
188
+ })
189
+ }, [isEnhanced, actions])
190
+
191
+ const handleSeeking = useCallback(() => {
192
+ startSeekTransition(() => {
193
+ // Seek operations get their own transition
194
+ })
195
+ }, [])
196
+
197
+ const handleSeeked = useCallback(() => {
198
+ // Seek completed
199
+ }, [])
200
+
201
+ const handleProgress = useCallback(() => {
202
+ const media = mediaRef.current
203
+ if (!media) return
204
+
205
+ startTransition(() => {
206
+ if (isEnhanced && actions) {
207
+ actions.setBuffered(media.buffered)
208
+ }
209
+ })
210
+ }, [isEnhanced, actions])
211
+
212
+ // Performance monitoring
213
+ const measureRenderTime = useCallback(() => {
214
+ const now = performance.now()
215
+ const deltaTime = now - lastFrameTime.current
216
+
217
+ if (deltaTime > 0) {
218
+ frameCount.current++
219
+
220
+ // Calculate frame rate every second
221
+ if (frameCount.current >= 60) {
222
+ const fps = Math.round((frameCount.current * 1000) / (now - lastFrameTime.current))
223
+ setPerformanceMetrics(prev => ({
224
+ ...prev,
225
+ frameRate: fps,
226
+ droppedFrames: Math.max(0, 60 - fps)
227
+ }))
228
+ frameCount.current = 0
229
+ lastFrameTime.current = now
230
+ }
231
+ }
232
+ }, [])
233
+
234
+ // Attach event listeners with performance optimization
235
+ useEffect(() => {
236
+ const media = mediaRef.current
237
+ if (!media) return
238
+
239
+ // Use passive listeners where possible for better performance
240
+ const eventListeners = [
241
+ { event: "timeupdate", handler: handleTimeUpdate, passive: true },
242
+ { event: "play", handler: handlePlay },
243
+ { event: "pause", handler: handlePause },
244
+ { event: "volumechange", handler: handleVolumeChange },
245
+ { event: "seeking", handler: handleSeeking },
246
+ { event: "seeked", handler: handleSeeked },
247
+ { event: "progress", handler: handleProgress, passive: true },
248
+ { event: "loadedmetadata", handler: () => measureRenderTime() },
249
+ { event: "loadeddata", handler: () => measureRenderTime() }
250
+ ]
251
+
252
+ eventListeners.forEach(({ event, handler, passive }) => {
253
+ const options = passive ? { passive: true } : {}
254
+ media.addEventListener(event, handler, options)
255
+ })
256
+
257
+ // Performance monitoring frame loop
258
+ let rafId: number
259
+ const performanceLoop = () => {
260
+ measureRenderTime()
261
+ rafId = requestAnimationFrame(performanceLoop)
262
+ }
263
+
264
+ if (options.enablePerformanceMonitoring) {
265
+ performanceLoop()
266
+ }
267
+
268
+ return () => {
269
+ eventListeners.forEach(({ event, handler }) => {
270
+ media.removeEventListener(event, handler)
271
+ })
272
+ if (rafId) {
273
+ cancelAnimationFrame(rafId)
274
+ }
275
+ }
276
+ }, [
277
+ handleTimeUpdate,
278
+ handlePlay,
279
+ handlePause,
280
+ handleVolumeChange,
281
+ handleSeeking,
282
+ handleSeeked,
283
+ handleProgress,
284
+ measureRenderTime,
285
+ options.enablePerformanceMonitoring
286
+ ])
287
+
288
+ // Optimized control functions with React 19 features
289
+ const controls = useMemo(() => {
290
+ const play = async () => {
291
+ const media = mediaRef.current
292
+ if (!media) return
293
+
294
+ if (isEnhanced && actions) {
295
+ await actions.play(true) // Optimistic
296
+ } else {
297
+ try {
298
+ await media.play()
299
+ } catch (error) {
300
+ console.error("Failed to play media:", error)
301
+ }
302
+ }
303
+ }
304
+
305
+ const pause = () => {
306
+ const media = mediaRef.current
307
+ if (!media) return
308
+
309
+ if (isEnhanced && actions) {
310
+ actions.pause(true) // Optimistic
311
+ } else {
312
+ media.pause()
313
+ }
314
+ }
315
+
316
+ const toggle = () => {
317
+ if (isPlaying) {
318
+ pause()
319
+ } else {
320
+ play()
321
+ }
322
+ }
323
+
324
+ const seek = (time: number) => {
325
+ const media = mediaRef.current
326
+ if (!media) return
327
+
328
+ const clampedTime = Math.max(0, Math.min(time, duration || 0))
329
+
330
+ if (isEnhanced && actions) {
331
+ startSeekTransition(() => {
332
+ actions.seek(clampedTime, true) // Optimistic
333
+ })
334
+ } else {
335
+ media.currentTime = clampedTime
336
+ }
337
+ }
338
+
339
+ const setVolume = (volume: number) => {
340
+ const media = mediaRef.current
341
+ if (!media) return
342
+
343
+ const clampedVolume = Math.max(0, Math.min(1, volume))
344
+
345
+ if (isEnhanced && actions) {
346
+ setOptimisticVolume(clampedVolume)
347
+ startTransition(() => {
348
+ actions.setVolume(clampedVolume, true)
349
+ })
350
+ } else {
351
+ media.volume = clampedVolume
352
+ }
353
+ }
354
+
355
+ const toggleMute = () => {
356
+ const media = mediaRef.current
357
+ if (!media) return
358
+
359
+ if (isEnhanced && actions) {
360
+ actions.toggleMute(true) // Optimistic
361
+ } else {
362
+ media.muted = !media.muted
363
+ }
364
+ }
365
+
366
+ const enterFullscreen = async () => {
367
+ const container = containerRef.current
368
+ if (!container || !document.fullscreenEnabled) return
369
+
370
+ try {
371
+ await container.requestFullscreen()
372
+ if (isEnhanced && actions) {
373
+ actions.enterFullscreen(true)
374
+ }
375
+ } catch (error) {
376
+ console.error("Failed to enter fullscreen:", error)
377
+ }
378
+ }
379
+
380
+ const exitFullscreen = async () => {
381
+ if (!document.fullscreenElement) return
382
+
383
+ try {
384
+ await document.exitFullscreen()
385
+ if (isEnhanced && actions) {
386
+ actions.exitFullscreen(true)
387
+ }
388
+ } catch (error) {
389
+ console.error("Failed to exit fullscreen:", error)
390
+ }
391
+ }
392
+
393
+ return {
394
+ play,
395
+ pause,
396
+ toggle,
397
+ seek,
398
+ setVolume,
399
+ toggleMute,
400
+ enterFullscreen,
401
+ exitFullscreen
402
+ }
403
+ }, [
404
+ isPlaying,
405
+ duration,
406
+ isEnhanced,
407
+ actions,
408
+ startTransition,
409
+ startSeekTransition,
410
+ setOptimisticVolume
411
+ ])
412
+
413
+ // Computed state
414
+ const computedState = useMemo(() => ({
415
+ isPlaying: optimisticState?.isPlaying ?? isPlaying,
416
+ currentTime: optimisticState?.currentTime ?? currentTime,
417
+ duration: optimisticState?.duration ?? duration,
418
+ volume: optimisticState?.volume ?? optimisticVolume,
419
+ isMuted: optimisticState?.isMuted ?? isMuted,
420
+ isLoading: optimisticState?.isBuffering ?? isLoading,
421
+ isBuffering: optimisticState?.isBuffering ?? isBuffering,
422
+ error: optimisticState?.error ?? error,
423
+ buffered: optimisticState?.buffered ?? buffered,
424
+ isFullscreen: optimisticState?.isFullscreen ?? isFullscreen,
425
+ progress: duration > 0 ? currentTime / duration : 0,
426
+ isTransitioning: isPending || isSeeking,
427
+ canPlay: !isLoading && !isBuffering && !error
428
+ }), [
429
+ optimisticState,
430
+ isPlaying,
431
+ currentTime,
432
+ duration,
433
+ optimisticVolume,
434
+ isMuted,
435
+ isLoading,
436
+ isBuffering,
437
+ error,
438
+ buffered,
439
+ isFullscreen,
440
+ isPending,
441
+ isSeeking
442
+ ])
443
+
444
+ return {
445
+ // Refs
446
+ mediaRef,
447
+ containerRef,
448
+
449
+ // State
450
+ state: computedState,
451
+ actualState: optimisticState?.actualState,
452
+
453
+ // Controls
454
+ controls,
455
+
456
+ // Performance metrics
457
+ performanceMetrics,
458
+ isTransitioning: isPending || isSeeking,
459
+
460
+ // Enhanced features
461
+ actions: optimisticState?.actions,
462
+ actionState: optimisticState?.actionState,
463
+
464
+ // Optimistic features
465
+ optimisticState,
466
+ isEnhanced
467
+ }
468
+ }