@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.
- package/LICENSE +21 -0
- package/README.md +384 -0
- package/dist/context/media.js +2 -0
- package/dist/context/media.js.map +1 -0
- package/dist/context/media.mjs +15 -0
- package/dist/context/media.mjs.map +1 -0
- package/dist/context/store.js +2 -0
- package/dist/context/store.js.map +1 -0
- package/dist/context/store.mjs +5 -0
- package/dist/context/store.mjs.map +1 -0
- package/dist/context-BMteAJDN.js +1140 -0
- package/dist/context-BMteAJDN.js.map +1 -0
- package/dist/context-DCJ_scmO.cjs +23 -0
- package/dist/context-DCJ_scmO.cjs.map +1 -0
- package/dist/core-events-B5W_j8yU.js +480 -0
- package/dist/core-events-B5W_j8yU.js.map +1 -0
- package/dist/core-events-CN0-Vhhq.cjs +2 -0
- package/dist/core-events-CN0-Vhhq.cjs.map +1 -0
- package/dist/core-plugins-Bq9KLany.js +696 -0
- package/dist/core-plugins-Bq9KLany.js.map +1 -0
- package/dist/core-plugins-CPDSHMiQ.cjs +2 -0
- package/dist/core-plugins-CPDSHMiQ.cjs.map +1 -0
- package/dist/core.js +37 -0
- package/dist/core.js.map +1 -0
- package/dist/core.mjs +1217 -0
- package/dist/core.mjs.map +1 -0
- package/dist/enhanced-components-DHv0MFvG.js +1073 -0
- package/dist/enhanced-components-DHv0MFvG.js.map +1 -0
- package/dist/enhanced-components-DTIObgB7.cjs +2 -0
- package/dist/enhanced-components-DTIObgB7.cjs.map +1 -0
- package/dist/hooks-C_r8wexn.cjs +4 -0
- package/dist/hooks-C_r8wexn.cjs.map +1 -0
- package/dist/hooks-Da2wVXlF.js +1630 -0
- package/dist/hooks-Da2wVXlF.js.map +1 -0
- package/dist/index.css +1 -0
- package/dist/index.js +112 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +6126 -0
- package/dist/index.mjs.map +1 -0
- package/dist/minimal-components-DSq5sQpy.js +2002 -0
- package/dist/minimal-components-DSq5sQpy.js.map +1 -0
- package/dist/minimal-components-DflWiihN.cjs +2 -0
- package/dist/minimal-components-DflWiihN.cjs.map +1 -0
- package/dist/minimal-components.css +1 -0
- package/dist/mona-loading.gif +0 -0
- package/dist/performance-monitor-CUW6f5ll.cjs +2 -0
- package/dist/performance-monitor-CUW6f5ll.cjs.map +1 -0
- package/dist/performance-monitor-rMW1RgV3.js +302 -0
- package/dist/performance-monitor-rMW1RgV3.js.map +1 -0
- package/dist/utils-BnscpYYd.js +2798 -0
- package/dist/utils-BnscpYYd.js.map +1 -0
- package/dist/utils-D_czS_0K.cjs +9 -0
- package/dist/utils-D_czS_0K.cjs.map +1 -0
- package/dist/utils.js +2 -0
- package/dist/utils.js.map +1 -0
- package/dist/utils.mjs +7 -0
- package/dist/utils.mjs.map +1 -0
- package/package.json +114 -0
- package/src/adapters/videojs-adapter.tsx +470 -0
- package/src/assets/mona-loading.gif +0 -0
- package/src/components/AnimateLoading.tsx +115 -0
- package/src/components/LoadingState.tsx +248 -0
- package/src/components/accessibility/keyboard-help-overlay.tsx +213 -0
- package/src/components/audio-player.tsx +85 -0
- package/src/components/basic/index.ts +37 -0
- package/src/components/enhanced/advanced-features.tsx +316 -0
- package/src/components/enhanced/debug-panel.tsx +422 -0
- package/src/components/enhanced/enhanced-controls.tsx +600 -0
- package/src/components/enhanced/enhanced-media-player.tsx +509 -0
- package/src/components/enhanced/error-handling.tsx +345 -0
- package/src/components/enhanced/index.ts +39 -0
- package/src/components/enhanced/media-player-enhanced.tsx +349 -0
- package/src/components/examples/basic-video-player.tsx +55 -0
- package/src/components/examples/custom-controls-example.tsx +63 -0
- package/src/components/examples/enhanced-controls-example.tsx +114 -0
- package/src/components/examples/enhanced-media-player-example.tsx +293 -0
- package/src/components/examples/loading-states-demo.tsx +142 -0
- package/src/components/examples/react-19-demo.tsx +381 -0
- package/src/components/examples/volume-orientation-demo.tsx +114 -0
- package/src/components/icon-demo.tsx +209 -0
- package/src/components/icons/index.tsx +166 -0
- package/src/components/icons/svg-icons/ArrowLeftIcon.tsx +18 -0
- package/src/components/icons/svg-icons/ArrowRightIcon.tsx +18 -0
- package/src/components/icons/svg-icons/AudioIcon.tsx +22 -0
- package/src/components/icons/svg-icons/BackwardIcon.tsx +12 -0
- package/src/components/icons/svg-icons/CameraIcon.tsx +19 -0
- package/src/components/icons/svg-icons/CheckIcon.tsx +19 -0
- package/src/components/icons/svg-icons/EnablePiPIcon.tsx +17 -0
- package/src/components/icons/svg-icons/ForwardIcon.tsx +12 -0
- package/src/components/icons/svg-icons/FullscreenEnterIcon.tsx +23 -0
- package/src/components/icons/svg-icons/FullscreenExitIcon.tsx +23 -0
- package/src/components/icons/svg-icons/LoadingIcon.tsx +32 -0
- package/src/components/icons/svg-icons/PauseIcon.tsx +23 -0
- package/src/components/icons/svg-icons/PlayIcon.tsx +21 -0
- package/src/components/icons/svg-icons/PlaybackSpeedIcon.tsx +23 -0
- package/src/components/icons/svg-icons/QualityIcon.tsx +21 -0
- package/src/components/icons/svg-icons/SettingsIcon.tsx +12 -0
- package/src/components/icons/svg-icons/SliderIcon.tsx +21 -0
- package/src/components/icons/svg-icons/SubtitleIcon.tsx +21 -0
- package/src/components/icons/svg-icons/SubtitleOffIcon.tsx +25 -0
- package/src/components/icons/svg-icons/UnPiPIcon.tsx +17 -0
- package/src/components/icons/svg-icons/VolumeMutedIcon.tsx +16 -0
- package/src/components/icons/svg-icons/VolumeOneIcon.tsx +22 -0
- package/src/components/icons/svg-icons/VolumeThreeIcon.tsx +16 -0
- package/src/components/icons/svg-icons/VolumeTwoIcon.tsx +16 -0
- package/src/components/legacy.tsx +93 -0
- package/src/components/media-metadata-display.tsx +100 -0
- package/src/components/media-player-audio.tsx +39 -0
- package/src/components/media-player-controls.tsx +226 -0
- package/src/components/media-player-error.tsx +163 -0
- package/src/components/media-player-fullscreen.tsx +109 -0
- package/src/components/media-player-hls.tsx +111 -0
- package/src/components/media-player-loading.tsx +76 -0
- package/src/components/media-player-play.tsx +75 -0
- package/src/components/media-player-root.tsx +340 -0
- package/src/components/media-player-seek.tsx +168 -0
- package/src/components/media-player-time.tsx +99 -0
- package/src/components/media-player-tooltip.tsx +58 -0
- package/src/components/media-player-video.tsx +39 -0
- package/src/components/media-player-volume.tsx +155 -0
- package/src/components/media-player.tsx +257 -0
- package/src/components/media-suspense.tsx +362 -0
- package/src/components/player-settings-form.tsx +163 -0
- package/src/components/react-player-wrapper.tsx +651 -0
- package/src/components/simple-video-player.tsx +60 -0
- package/src/components/ui/enhanced-seek-bar.tsx +235 -0
- package/src/components/ui/fullscreen-button.tsx +60 -0
- package/src/components/ui/media-resource-preloader.tsx +395 -0
- package/src/components/ui/play-button.tsx +107 -0
- package/src/components/ui/seek-bar.tsx +161 -0
- package/src/components/ui/time-display.tsx +40 -0
- package/src/components/ui/volume-control.tsx +143 -0
- package/src/components/unified/base-media-player.tsx +246 -0
- package/src/components/unified/media-player.tsx +75 -0
- package/src/components/variants/minimal/AccessibleMinimalPlayer.tsx +561 -0
- package/src/components/variants/minimal/EnhancedMinimalMediaPlayer.tsx +552 -0
- package/src/components/variants/minimal/MinimalControls.tsx +142 -0
- package/src/components/variants/minimal/MinimalLoading.tsx +32 -0
- package/src/components/variants/minimal/MinimalMediaPlayer.tsx +315 -0
- package/src/components/variants/minimal/MinimalOverlay.tsx +64 -0
- package/src/components/variants/minimal/MinimalPlayButton.tsx +65 -0
- package/src/components/variants/minimal/MinimalSeekBar.tsx +150 -0
- package/src/components/variants/minimal/MinimalVolumeControl.tsx +80 -0
- package/src/components/variants/minimal/SimpleMinimalPlayer.tsx +210 -0
- package/src/components/variants/minimal/components/CenterPlayButton.tsx +22 -0
- package/src/components/variants/minimal/components/ControlBar.tsx +146 -0
- package/src/components/variants/minimal/components/EnhancedSettingsMenu.tsx +361 -0
- package/src/components/variants/minimal/components/PlaybackControls.tsx +51 -0
- package/src/components/variants/minimal/components/RightControls.tsx +173 -0
- package/src/components/variants/minimal/components/SeekBar.tsx +131 -0
- package/src/components/variants/minimal/components/SettingsDropdown.tsx +70 -0
- package/src/components/variants/minimal/components/SubtitleDisplay.tsx +21 -0
- package/src/components/variants/minimal/components/TimeDisplay.tsx +18 -0
- package/src/components/variants/minimal/components/VideoElement.tsx +40 -0
- package/src/components/variants/minimal/components/VolumeControl.tsx +217 -0
- package/src/components/variants/minimal/index.ts +23 -0
- package/src/components/video-player.tsx +100 -0
- package/src/context/error-handling.ts +394 -0
- package/src/context/media-context.tsx +208 -0
- package/src/context/media-provider.tsx +265 -0
- package/src/context/media-store.ts +379 -0
- package/src/context/persistence.ts +453 -0
- package/src/core/events/event-system.ts +442 -0
- package/src/core/events/hooks.ts +302 -0
- package/src/core/events/index.ts +22 -0
- package/src/core/events/middleware.ts +269 -0
- package/src/core/index.ts +22 -0
- package/src/core/optimization/bundle-optimizer.tsx +308 -0
- package/src/core/performance/cicd.ts +96 -0
- package/src/core/performance/index.ts +38 -0
- package/src/core/performance/media-loading-optimizer.ts +538 -0
- package/src/core/performance/performance-budgets.ts +432 -0
- package/src/core/performance/performance-monitor.tsx +476 -0
- package/src/core/performance/performance-testing.ts +459 -0
- package/src/core/plugins/base-plugin.ts +224 -0
- package/src/core/plugins/enhanced-plugin-system.ts +411 -0
- package/src/core/plugins/examples/analytics-plugin.ts +242 -0
- package/src/core/plugins/index.ts +39 -0
- package/src/core/plugins/registry.ts +327 -0
- package/src/core/plugins/types.ts +159 -0
- package/src/core/plugins/utils.ts +316 -0
- package/src/core/progressive-loading.tsx +322 -0
- package/src/core/providers/enhanced-hls-provider.ts +339 -0
- package/src/core/providers/service-provider.tsx +168 -0
- package/src/core/utils.tsx +38 -0
- package/src/features/media-session/media-session-manager.ts +429 -0
- package/src/features/picture-in-picture/pip-manager.ts +429 -0
- package/src/features/playlist/playlist-manager.ts +606 -0
- package/src/features/subtitles/subtitle-manager.ts +441 -0
- package/src/features/subtitles/subtitle-parser.ts +280 -0
- package/src/features/thumbnails/thumbnail-generator.ts +519 -0
- package/src/hooks/accessibility/index.ts +27 -0
- package/src/hooks/accessibility/use-accessibility-preferences.ts +188 -0
- package/src/hooks/accessibility/use-focus-management.ts +176 -0
- package/src/hooks/accessibility/use-keyboard-shortcuts.ts +144 -0
- package/src/hooks/accessibility/use-screen-reader.ts +182 -0
- package/src/hooks/core/index.ts +47 -0
- package/src/hooks/legacy.ts +27 -0
- package/src/hooks/use-enhanced-media-player.ts +468 -0
- package/src/hooks/use-intelligent-preloading.ts +358 -0
- package/src/hooks/use-keyboard-controls.ts +115 -0
- package/src/hooks/use-media-actions.ts +175 -0
- package/src/hooks/use-media-metadata.ts +89 -0
- package/src/hooks/use-media-optimistic.ts +270 -0
- package/src/hooks/use-media-player.ts +312 -0
- package/src/hooks/use-media-state.ts +190 -0
- package/src/hooks/use-memory-optimization.ts +358 -0
- package/src/hooks/use-optimistic-controls.ts +92 -0
- package/src/hooks/use-optimized-media.ts +263 -0
- package/src/hooks/use-touch-gestures.ts +417 -0
- package/src/hooks/useEnhancedSubtitles.ts +258 -0
- package/src/hooks/useKeyboardShortcuts.ts +74 -0
- package/src/hooks/useMediaControls.ts +52 -0
- package/src/hooks/useScreenshot.ts +57 -0
- package/src/hooks/useSubtitles.ts +91 -0
- package/src/hooks/useVideoPlayer.ts +232 -0
- package/src/icons/components/FullscreenIcon.tsx +37 -0
- package/src/icons/components/SettingsIcon.tsx +38 -0
- package/src/icons/components/animated/LoadingIcon.tsx +43 -0
- package/src/icons/components/animated/PlayPauseIcon.tsx +50 -0
- package/src/icons/components/media/PauseIcon.tsx +39 -0
- package/src/icons/components/media/PlayIcon.tsx +38 -0
- package/src/icons/components/volume/VolumeIcon.tsx +39 -0
- package/src/icons/components/volume/VolumeOffIcon.tsx +39 -0
- package/src/icons/index.ts +56 -0
- package/src/icons/provider.tsx +64 -0
- package/src/icons/types.ts +40 -0
- package/src/index-enhanced.ts +35 -0
- package/src/index-legacy.ts +326 -0
- package/src/index.css +102 -0
- package/src/index.ts +216 -0
- package/src/lib/deprecation.ts +51 -0
- package/src/lib/format-time.ts +37 -0
- package/src/lib/index.ts +3 -0
- package/src/lib/utils.ts +6 -0
- package/src/styles/globals.css +462 -0
- package/src/styles/minimal-player.css +589 -0
- package/src/styles/pixel-art.css +46 -0
- package/src/styles/videojs.css +100 -0
- package/src/test/setup.ts +79 -0
- package/src/types/events.ts +47 -0
- package/src/types/formats.ts +95 -0
- package/src/types/index.ts +190 -0
- 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
|
+
}
|