@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,381 @@
1
+ "use client"
2
+
3
+ import React from "react"
4
+ import { MediaProvider } from "../../context/media-provider"
5
+ import { MediaPlayerRoot } from "../media-player-root"
6
+ import { MediaPlayerVideo } from "../media-player-video"
7
+ import { MediaPlayerControls } from "../media-player-controls"
8
+ import { MediaPlayerPlay } from "../media-player-play"
9
+ import { MediaPlayerVolume } from "../media-player-volume"
10
+ import { MediaPlayerTime } from "../media-player-time"
11
+ import { MediaPlayerSeek } from "../media-player-seek"
12
+ import { MediaPlayerFullscreen } from "../media-player-fullscreen"
13
+ import {
14
+ EnhancedMediaWrapper,
15
+ MediaLoading,
16
+ useMediaConcurrent,
17
+ useMediaPerformance
18
+ } from "../media-suspense"
19
+ import {
20
+ useEnhancedMediaState
21
+ } from "../../hooks/use-media-state"
22
+ import {
23
+ useMediaActions
24
+ } from "../../hooks/use-media-actions"
25
+ import {
26
+ useMediaOptimistic
27
+ } from "../../hooks/use-media-optimistic"
28
+ import { useMediaErrorHandler } from "../../context/error-handling"
29
+ import { useAutoMediaPersistence } from "../../context/persistence"
30
+ import { useOptimisticMediaSelector } from "../../context/media-context"
31
+ import { cn } from "../../lib/utils"
32
+
33
+ // Demo component showcasing React 19 features
34
+ interface React19MediaPlayerDemoProps {
35
+ src: string
36
+ poster?: string
37
+ className?: string
38
+ mediaId?: string
39
+ }
40
+
41
+ export function React19MediaPlayerDemo({
42
+ src,
43
+ poster,
44
+ className,
45
+ mediaId = "react-19-demo"
46
+ }: React19MediaPlayerDemoProps) {
47
+ return (
48
+ <EnhancedMediaWrapper
49
+ className={className}
50
+ priority="high"
51
+ loadingFallback={<MediaLoading variant="skeleton" size="lg" />}
52
+ errorFallback={ErrorFallback}
53
+ >
54
+ <MediaProvider
55
+ mediaId={mediaId}
56
+ useEnhancedStore={true}
57
+ enableOptimisticUpdates={true}
58
+ enableErrorRecovery={true}
59
+ persistenceConfig={{
60
+ userPreferences: true,
61
+ sessionState: true,
62
+ debounceMs: 300
63
+ }}
64
+ retryConfig={{
65
+ maxRetries: 3,
66
+ exponentialBackoff: true
67
+ }}
68
+ >
69
+ <MediaPlayerContent src={src} poster={poster} />
70
+ </MediaProvider>
71
+ </EnhancedMediaWrapper>
72
+ )
73
+ }
74
+
75
+ // Internal content component with React 19 hooks
76
+ function MediaPlayerContent({ src, poster }: { src: string; poster?: string }) {
77
+ // React 19 enhanced state management
78
+ const mediaState = useEnhancedMediaState()
79
+ const { isLoading: actionLoading, errorMessage, ...actions } = useMediaActions(
80
+ mediaState.state as any // Type assertion for store
81
+ )
82
+
83
+ // React 19 optimistic updates
84
+ const optimisticState = useMediaOptimistic(mediaState.state as any)
85
+
86
+ // React 19 concurrent features
87
+ const { isPending, updateWithTransition } = useMediaConcurrent()
88
+
89
+ // Performance monitoring
90
+ const { metrics, recordRenderTime } = useMediaPerformance()
91
+
92
+ // Error handling
93
+ const { errors, clearError } = useMediaErrorHandler()
94
+
95
+ // Record render performance
96
+ React.useEffect(() => {
97
+ const start = performance.now()
98
+ return () => recordRenderTime(start)
99
+ }, [recordRenderTime])
100
+
101
+ // Optimistic selectors for immediate UI feedback
102
+ const isPlaying = useOptimisticMediaSelector(state => state.isPlaying)
103
+ const volume = useOptimisticMediaSelector(state => state.volume)
104
+ const currentTime = useOptimisticMediaSelector(state => state.currentTime)
105
+ const duration = useOptimisticMediaSelector(state => state.duration)
106
+ const isFullscreen = useOptimisticMediaSelector(state => state.isFullscreen)
107
+
108
+ // Enhanced action handlers with React 19 features
109
+ const handlePlayPause = async () => {
110
+ await updateWithTransition(async () => {
111
+ await optimisticState.togglePlayPause()
112
+ })
113
+ }
114
+
115
+ const handleVolumeChange = async (newVolume: number) => {
116
+ await optimisticState.setVolumeOptimistic(newVolume)
117
+ }
118
+
119
+ const handleSeek = async (time: number) => {
120
+ await optimisticState.seekOptimistic(time)
121
+ }
122
+
123
+ const handleFullscreenToggle = async () => {
124
+ await optimisticState.toggleFullscreenOptimistic()
125
+ }
126
+
127
+ return (
128
+ <MediaPlayerRoot
129
+ className={cn(
130
+ "group relative overflow-hidden rounded-lg",
131
+ "border border-border bg-black shadow-lg",
132
+ "transition-all duration-200",
133
+ isPending && "opacity-75", // Visual feedback for pending transitions
134
+ actionLoading && "pointer-events-none"
135
+ )}
136
+ enableGestures={true}
137
+ enableMobileOptimizations={true}
138
+ >
139
+ {/* Video Element */}
140
+ <MediaPlayerVideo
141
+ src={src}
142
+ poster={poster}
143
+ className="aspect-video w-full object-contain"
144
+ />
145
+
146
+ {/* Enhanced Loading State */}
147
+ {(actionLoading || isPending) && (
148
+ <div className="absolute inset-0 flex items-center justify-center bg-black/20">
149
+ <MediaLoading variant="spinner" size="lg">
150
+ {actionLoading ? "Processing..." : "Updating..."}
151
+ </MediaLoading>
152
+ </div>
153
+ )}
154
+
155
+ {/* Controls with React 19 optimizations */}
156
+ <MediaPlayerControls className="absolute right-0 bottom-0 left-0">
157
+ <div className="flex items-center gap-4 bg-gradient-to-t from-black/80 to-transparent p-4">
158
+ {/* Play/Pause with optimistic updates */}
159
+ <MediaPlayerPlay
160
+ className="text-white transition-colors hover:text-white/80"
161
+ />
162
+
163
+ {/* Volume with immediate feedback */}
164
+ <MediaPlayerVolume
165
+ className="text-white"
166
+ />
167
+
168
+ {/* Time Display with optimistic values */}
169
+ <MediaPlayerTime
170
+ className="min-w-[120px] font-mono text-sm text-white"
171
+ />
172
+
173
+ {/* Seek Bar with optimistic scrubbing */}
174
+ <div className="flex-1">
175
+ <MediaPlayerSeek
176
+ className="w-full"
177
+ />
178
+ </div>
179
+
180
+ {/* Fullscreen with optimistic updates */}
181
+ <MediaPlayerFullscreen
182
+ className="text-white transition-colors hover:text-white/80"
183
+ />
184
+ </div>
185
+ </MediaPlayerControls>
186
+
187
+ {/* Error Display */}
188
+ {(errorMessage || errors.length > 0) && (
189
+ <div className="absolute top-4 right-4 rounded-lg bg-destructive/90 px-3 py-2 text-destructive-foreground text-sm">
190
+ {errorMessage || errors[0]?.message}
191
+ <button
192
+ onClick={() => clearError(errors[0] ? `${errors[0].action?.type}-${errors[0].timestamp}` : '')}
193
+ className="ml-2 underline hover:no-underline"
194
+ >
195
+ Dismiss
196
+ </button>
197
+ </div>
198
+ )}
199
+
200
+ {/* Performance Debug Info (Development only) */}
201
+ {process.env.NODE_ENV === 'development' && (
202
+ <PerformanceDebugPanel
203
+ metrics={metrics}
204
+ optimisticState={optimisticState}
205
+ errors={errors}
206
+ />
207
+ )}
208
+ </MediaPlayerRoot>
209
+ )
210
+ }
211
+
212
+ // Error fallback component
213
+ function ErrorFallback({
214
+ error,
215
+ resetError
216
+ }: {
217
+ error: Error
218
+ resetError: () => void
219
+ }) {
220
+ return (
221
+ <div className="flex min-h-[300px] flex-col items-center justify-center rounded-lg border border-destructive/20 bg-destructive/10 p-8">
222
+ <div className="mb-2 font-semibold text-destructive text-xl">
223
+ React 19 Media Player Error
224
+ </div>
225
+ <div className="mb-4 max-w-md text-center text-muted-foreground">
226
+ {error.message}
227
+ </div>
228
+ <button
229
+ onClick={resetError}
230
+ className="rounded-lg bg-primary px-4 py-2 text-primary-foreground transition-colors hover:bg-primary/90"
231
+ >
232
+ Retry Player
233
+ </button>
234
+ </div>
235
+ )
236
+ }
237
+
238
+ // Performance debug panel (development only)
239
+ function PerformanceDebugPanel({
240
+ metrics,
241
+ optimisticState,
242
+ errors
243
+ }: {
244
+ metrics: any
245
+ optimisticState: any
246
+ errors: any[]
247
+ }) {
248
+ const [isExpanded, setIsExpanded] = React.useState(false)
249
+
250
+ if (!isExpanded) {
251
+ return (
252
+ <button
253
+ onClick={() => setIsExpanded(true)}
254
+ className="absolute top-4 left-4 rounded bg-blue-600 px-2 py-1 text-white text-xs"
255
+ >
256
+ Debug
257
+ </button>
258
+ )
259
+ }
260
+
261
+ return (
262
+ <div className="absolute top-4 left-4 max-w-sm rounded-lg bg-black/90 p-4 font-mono text-white text-xs">
263
+ <div className="mb-2 flex items-center justify-between">
264
+ <span className="font-bold">React 19 Debug</span>
265
+ <button
266
+ onClick={() => setIsExpanded(false)}
267
+ className="text-white/60 hover:text-white"
268
+ >
269
+ ×
270
+ </button>
271
+ </div>
272
+
273
+ <div className="space-y-1">
274
+ <div>Render Time: {metrics.renderTime}ms</div>
275
+ <div>Suspense Count: {metrics.suspenseCount}</div>
276
+ <div>Error Count: {metrics.errorCount}</div>
277
+ <div>Transition Count: {metrics.transitionCount}</div>
278
+ <div>Has Optimistic: {optimisticState.hasOptimisticUpdates ? 'Yes' : 'No'}</div>
279
+ <div>Active Errors: {errors.length}</div>
280
+ </div>
281
+
282
+ {optimisticState.differences?.length > 0 && (
283
+ <div className="mt-2 border-white/20 border-t pt-2">
284
+ <div className="mb-1 font-bold">Optimistic Diffs:</div>
285
+ {optimisticState.differences.map((diff: any, i: number) => (
286
+ <div key={i} className="text-yellow-400">
287
+ {diff.key}: {JSON.stringify(diff.optimistic)}
288
+ (was: {JSON.stringify(diff.actual)})
289
+ </div>
290
+ ))}
291
+ </div>
292
+ )}
293
+ </div>
294
+ )
295
+ }
296
+
297
+ // Example usage component
298
+ export function React19DemoExample() {
299
+ const [currentSrc, setCurrentSrc] = React.useState(
300
+ "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
301
+ )
302
+
303
+ const videoSources = [
304
+ {
305
+ src: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
306
+ title: "Big Buck Bunny",
307
+ poster: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/images/BigBuckBunny.jpg"
308
+ },
309
+ {
310
+ src: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4",
311
+ title: "Elephants Dream",
312
+ poster: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/images/ElephantsDream.jpg"
313
+ }
314
+ ]
315
+
316
+ const currentVideo = videoSources.find(v => v.src === currentSrc)!
317
+
318
+ return (
319
+ <div className="mx-auto max-w-4xl space-y-6 p-6">
320
+ <div>
321
+ <h1 className="mb-2 font-bold text-3xl">
322
+ React 19 Enhanced Media Player
323
+ </h1>
324
+ <p className="text-muted-foreground">
325
+ Featuring useOptimistic, useActionState, Suspense, concurrent features,
326
+ error handling, state persistence, and performance optimizations.
327
+ </p>
328
+ </div>
329
+
330
+ {/* Video Source Selector */}
331
+ <div className="flex gap-4">
332
+ {videoSources.map((video) => (
333
+ <button
334
+ key={video.src}
335
+ onClick={() => setCurrentSrc(video.src)}
336
+ className={cn(
337
+ "rounded-lg border px-4 py-2 transition-colors",
338
+ currentSrc === video.src
339
+ ? "border-primary bg-primary text-primary-foreground"
340
+ : "border-border bg-background hover:border-primary/50"
341
+ )}
342
+ >
343
+ {video.title}
344
+ </button>
345
+ ))}
346
+ </div>
347
+
348
+ {/* Enhanced Media Player */}
349
+ <React19MediaPlayerDemo
350
+ src={currentSrc}
351
+ poster={currentVideo.poster}
352
+ mediaId={`demo-${currentSrc}`}
353
+ className="w-full"
354
+ />
355
+
356
+ {/* Feature List */}
357
+ <div className="grid grid-cols-1 gap-4 text-sm md:grid-cols-2">
358
+ <div className="space-y-2">
359
+ <h3 className="font-semibold">React 19 Features</h3>
360
+ <ul className="space-y-1 text-muted-foreground">
361
+ <li>✅ useOptimistic for immediate UI feedback</li>
362
+ <li>✅ useActionState for form-like actions</li>
363
+ <li>✅ Automatic memoization via React compiler</li>
364
+ <li>✅ Concurrent features with Suspense</li>
365
+ <li>✅ Enhanced error boundaries</li>
366
+ </ul>
367
+ </div>
368
+ <div className="space-y-2">
369
+ <h3 className="font-semibold">Media Features</h3>
370
+ <ul className="space-y-1 text-muted-foreground">
371
+ <li>✅ Optimistic play/pause/seek/volume</li>
372
+ <li>✅ Automatic state persistence</li>
373
+ <li>✅ Error recovery with retries</li>
374
+ <li>✅ Touch gestures & mobile optimization</li>
375
+ <li>✅ Performance monitoring</li>
376
+ </ul>
377
+ </div>
378
+ </div>
379
+ </div>
380
+ )
381
+ }
@@ -0,0 +1,114 @@
1
+ "use client"
2
+
3
+ import { useState } from "react"
4
+ import { SimpleMinimalPlayer } from "../variants/minimal/SimpleMinimalPlayer"
5
+
6
+ export function VolumeOrientationDemo() {
7
+ const [orientation, setOrientation] = useState<"horizontal" | "vertical">("horizontal")
8
+
9
+ return (
10
+ <div className="min-h-screen bg-gray-950 p-8">
11
+ <div className="mx-auto max-w-5xl space-y-8">
12
+ <div className="text-center">
13
+ <h1 className="mb-4 font-bold text-3xl text-white">
14
+ Enhanced Volume Control Demo
15
+ </h1>
16
+ <p className="mb-6 text-gray-400">
17
+ Small gradient volume slider with horizontal/vertical orientation
18
+ </p>
19
+
20
+ {/* Orientation toggle */}
21
+ <div className="mb-8 flex justify-center gap-4">
22
+ <button
23
+ onClick={() => setOrientation("horizontal")}
24
+ className={`rounded-lg px-4 py-2 transition-colors ${
25
+ orientation === "horizontal"
26
+ ? "bg-cyan-600 text-white"
27
+ : "bg-gray-800 text-gray-400 hover:bg-gray-700"
28
+ }`}
29
+ >
30
+ Horizontal (Default)
31
+ </button>
32
+ <button
33
+ onClick={() => setOrientation("vertical")}
34
+ className={`rounded-lg px-4 py-2 transition-colors ${
35
+ orientation === "vertical"
36
+ ? "bg-cyan-600 text-white"
37
+ : "bg-gray-800 text-gray-400 hover:bg-gray-700"
38
+ }`}
39
+ >
40
+ Vertical
41
+ </button>
42
+ </div>
43
+ </div>
44
+
45
+ {/* Demo Player */}
46
+ <div className="aspect-video overflow-hidden rounded-lg bg-black">
47
+ <SimpleMinimalPlayer
48
+ src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
49
+ poster="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/images/BigBuckBunny.jpg"
50
+ crossOrigin="anonymous"
51
+ className="h-full w-full"
52
+ volumeOrientation={orientation}
53
+ />
54
+ </div>
55
+
56
+ {/* Features list */}
57
+ <div className="mt-8 grid gap-6 md:grid-cols-2">
58
+ <div className="rounded-lg bg-gray-900 p-6">
59
+ <h3 className="mb-3 font-semibold text-lg text-white">
60
+ Horizontal Mode (Default)
61
+ </h3>
62
+ <ul className="space-y-2 text-gray-400 text-sm">
63
+ <li>• Slider appears beside the volume button</li>
64
+ <li>• Expands horizontally on hover</li>
65
+ <li>• Cyan to blue gradient (4px height)</li>
66
+ <li>• Smooth 300ms transition</li>
67
+ <li>• White thumb appears on hover</li>
68
+ </ul>
69
+ </div>
70
+
71
+ <div className="rounded-lg bg-gray-900 p-6">
72
+ <h3 className="mb-3 font-semibold text-lg text-white">
73
+ Vertical Mode
74
+ </h3>
75
+ <ul className="space-y-2 text-gray-400 text-sm">
76
+ <li>• Slider appears above the volume button</li>
77
+ <li>• Expands vertically on hover</li>
78
+ <li>• Same gradient rotated 90°</li>
79
+ <li>• Shows percentage value</li>
80
+ <li>• Dark backdrop for visibility</li>
81
+ </ul>
82
+ </div>
83
+ </div>
84
+
85
+ {/* Code example */}
86
+ <div className="rounded-lg bg-gray-900 p-6">
87
+ <h3 className="mb-3 font-semibold text-lg text-white">Usage Example</h3>
88
+ <pre className="overflow-x-auto text-gray-300 text-sm">
89
+ <code>{`// Default horizontal orientation
90
+ <VolumeControl
91
+ volume={volume}
92
+ isMuted={isMuted}
93
+ showVolumeSlider={showSlider}
94
+ onToggleMute={handleMute}
95
+ onVolumeChange={handleVolumeChange}
96
+ onShowVolumeSlider={setShowSlider}
97
+ />
98
+
99
+ // Vertical orientation
100
+ <VolumeControl
101
+ volume={volume}
102
+ isMuted={isMuted}
103
+ showVolumeSlider={showSlider}
104
+ onToggleMute={handleMute}
105
+ onVolumeChange={handleVolumeChange}
106
+ onShowVolumeSlider={setShowSlider}
107
+ orientation="vertical"
108
+ />`}</code>
109
+ </pre>
110
+ </div>
111
+ </div>
112
+ </div>
113
+ )
114
+ }