@therealtinhtute/baroiplayer 1.2.0 → 2.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (305) hide show
  1. package/README.md +91 -73
  2. package/dist/components/icons/index.d.ts +36 -0
  3. package/dist/components/icons/index.d.ts.map +1 -0
  4. package/dist/components/icons/svg-icons/ArrowLeftIcon.d.ts +4 -0
  5. package/dist/components/icons/svg-icons/ArrowLeftIcon.d.ts.map +1 -0
  6. package/dist/components/icons/svg-icons/ArrowRightIcon.d.ts +5 -0
  7. package/dist/components/icons/svg-icons/ArrowRightIcon.d.ts.map +1 -0
  8. package/dist/components/icons/svg-icons/AudioIcon.d.ts +5 -0
  9. package/dist/components/icons/svg-icons/AudioIcon.d.ts.map +1 -0
  10. package/dist/components/icons/svg-icons/BackwardIcon.d.ts +5 -0
  11. package/dist/components/icons/svg-icons/BackwardIcon.d.ts.map +1 -0
  12. package/dist/components/icons/svg-icons/CameraIcon.d.ts +5 -0
  13. package/dist/components/icons/svg-icons/CameraIcon.d.ts.map +1 -0
  14. package/dist/components/icons/svg-icons/CheckIcon.d.ts +5 -0
  15. package/dist/components/icons/svg-icons/CheckIcon.d.ts.map +1 -0
  16. package/dist/components/icons/svg-icons/EnablePiPIcon.d.ts +4 -0
  17. package/dist/components/icons/svg-icons/EnablePiPIcon.d.ts.map +1 -0
  18. package/dist/components/icons/svg-icons/ForwardIcon.d.ts +5 -0
  19. package/dist/components/icons/svg-icons/ForwardIcon.d.ts.map +1 -0
  20. package/dist/components/icons/svg-icons/FullscreenEnterIcon.d.ts +5 -0
  21. package/dist/components/icons/svg-icons/FullscreenEnterIcon.d.ts.map +1 -0
  22. package/dist/components/icons/svg-icons/FullscreenExitIcon.d.ts +5 -0
  23. package/dist/components/icons/svg-icons/FullscreenExitIcon.d.ts.map +1 -0
  24. package/dist/components/icons/svg-icons/LoadingIcon.d.ts +5 -0
  25. package/dist/components/icons/svg-icons/LoadingIcon.d.ts.map +1 -0
  26. package/dist/components/icons/svg-icons/PauseIcon.d.ts +5 -0
  27. package/dist/components/icons/svg-icons/PauseIcon.d.ts.map +1 -0
  28. package/dist/components/icons/svg-icons/PlayIcon.d.ts +5 -0
  29. package/dist/components/icons/svg-icons/PlayIcon.d.ts.map +1 -0
  30. package/dist/components/icons/svg-icons/PlaybackSpeedIcon.d.ts +5 -0
  31. package/dist/components/icons/svg-icons/PlaybackSpeedIcon.d.ts.map +1 -0
  32. package/dist/components/icons/svg-icons/QualityIcon.d.ts +5 -0
  33. package/dist/components/icons/svg-icons/QualityIcon.d.ts.map +1 -0
  34. package/dist/components/icons/svg-icons/SettingsIcon.d.ts +5 -0
  35. package/dist/components/icons/svg-icons/SettingsIcon.d.ts.map +1 -0
  36. package/dist/components/icons/svg-icons/SliderIcon.d.ts +5 -0
  37. package/dist/components/icons/svg-icons/SliderIcon.d.ts.map +1 -0
  38. package/dist/components/icons/svg-icons/SubtitleIcon.d.ts +5 -0
  39. package/dist/components/icons/svg-icons/SubtitleIcon.d.ts.map +1 -0
  40. package/dist/components/icons/svg-icons/SubtitleOffIcon.d.ts +5 -0
  41. package/dist/components/icons/svg-icons/SubtitleOffIcon.d.ts.map +1 -0
  42. package/dist/components/icons/svg-icons/UnPiPIcon.d.ts +4 -0
  43. package/dist/components/icons/svg-icons/UnPiPIcon.d.ts.map +1 -0
  44. package/dist/components/icons/svg-icons/VolumeMutedIcon.d.ts +5 -0
  45. package/dist/components/icons/svg-icons/VolumeMutedIcon.d.ts.map +1 -0
  46. package/dist/components/icons/svg-icons/VolumeOneIcon.d.ts +5 -0
  47. package/dist/components/icons/svg-icons/VolumeOneIcon.d.ts.map +1 -0
  48. package/dist/components/icons/svg-icons/VolumeThreeIcon.d.ts +5 -0
  49. package/dist/components/icons/svg-icons/VolumeThreeIcon.d.ts.map +1 -0
  50. package/dist/components/icons/svg-icons/VolumeTwoIcon.d.ts +5 -0
  51. package/dist/components/icons/svg-icons/VolumeTwoIcon.d.ts.map +1 -0
  52. package/dist/components/variants/gradient/gradient-audio.d.ts +13 -0
  53. package/dist/components/variants/gradient/gradient-audio.d.ts.map +1 -0
  54. package/dist/components/variants/gradient/gradient-controls.d.ts +4 -0
  55. package/dist/components/variants/gradient/gradient-controls.d.ts.map +1 -0
  56. package/dist/components/variants/gradient/gradient-glyphs.d.ts +30 -0
  57. package/dist/components/variants/gradient/gradient-glyphs.d.ts.map +1 -0
  58. package/dist/components/variants/gradient/gradient-video.d.ts +16 -0
  59. package/dist/components/variants/gradient/gradient-video.d.ts.map +1 -0
  60. package/dist/index.css +1 -1
  61. package/dist/index.d.ts +5 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +2 -112
  64. package/dist/index.js.map +1 -1
  65. package/dist/index.mjs +786 -6271
  66. package/dist/index.mjs.map +1 -1
  67. package/dist/package.json +3 -0
  68. package/package.json +110 -108
  69. package/src/components/variants/gradient/gradient-audio.tsx +47 -0
  70. package/src/components/variants/gradient/gradient-controls.tsx +254 -0
  71. package/src/components/variants/gradient/gradient-glyphs.test.tsx +69 -0
  72. package/src/components/variants/gradient/gradient-glyphs.tsx +129 -0
  73. package/src/components/variants/gradient/gradient-skin.css +211 -0
  74. package/src/components/variants/gradient/gradient-video.tsx +70 -0
  75. package/src/index.ts +5 -198
  76. package/src/test/accessibility-utils.ts +0 -59
  77. package/dist/context/media.js +0 -2
  78. package/dist/context/media.js.map +0 -1
  79. package/dist/context/media.mjs +0 -15
  80. package/dist/context/media.mjs.map +0 -1
  81. package/dist/context/store.js +0 -2
  82. package/dist/context/store.js.map +0 -1
  83. package/dist/context/store.mjs +0 -5
  84. package/dist/context/store.mjs.map +0 -1
  85. package/dist/context-BYwDoSRX.js +0 -1172
  86. package/dist/context-BYwDoSRX.js.map +0 -1
  87. package/dist/context-eNS62_ac.cjs +0 -23
  88. package/dist/context-eNS62_ac.cjs.map +0 -1
  89. package/dist/core-events-B1iM2F46.cjs +0 -2
  90. package/dist/core-events-B1iM2F46.cjs.map +0 -1
  91. package/dist/core-events-DunPHKRE.js +0 -484
  92. package/dist/core-events-DunPHKRE.js.map +0 -1
  93. package/dist/core-plugins-By-4-kGs.cjs +0 -2
  94. package/dist/core-plugins-By-4-kGs.cjs.map +0 -1
  95. package/dist/core-plugins-DSBWcTuX.js +0 -821
  96. package/dist/core-plugins-DSBWcTuX.js.map +0 -1
  97. package/dist/core.js +0 -37
  98. package/dist/core.js.map +0 -1
  99. package/dist/core.mjs +0 -1233
  100. package/dist/core.mjs.map +0 -1
  101. package/dist/enhanced-components-B_l3cist.js +0 -1142
  102. package/dist/enhanced-components-B_l3cist.js.map +0 -1
  103. package/dist/enhanced-components-BspFs9OO.cjs +0 -2
  104. package/dist/enhanced-components-BspFs9OO.cjs.map +0 -1
  105. package/dist/hooks-BXwI8QG6.cjs +0 -4
  106. package/dist/hooks-BXwI8QG6.cjs.map +0 -1
  107. package/dist/hooks-Bpi-jDiO.js +0 -1816
  108. package/dist/hooks-Bpi-jDiO.js.map +0 -1
  109. package/dist/minimal-components-C4z900Ro.js +0 -1926
  110. package/dist/minimal-components-C4z900Ro.js.map +0 -1
  111. package/dist/minimal-components-v4qBp6jv.cjs +0 -2
  112. package/dist/minimal-components-v4qBp6jv.cjs.map +0 -1
  113. package/dist/minimal-components.css +0 -1
  114. package/dist/mona-loading.gif +0 -0
  115. package/dist/performance-monitor-C5k6FDXw.js +0 -301
  116. package/dist/performance-monitor-C5k6FDXw.js.map +0 -1
  117. package/dist/performance-monitor-lJmuUjQQ.cjs +0 -2
  118. package/dist/performance-monitor-lJmuUjQQ.cjs.map +0 -1
  119. package/dist/utils-CFOue_9K.cjs +0 -9
  120. package/dist/utils-CFOue_9K.cjs.map +0 -1
  121. package/dist/utils-Dzpl2ArK.js +0 -2844
  122. package/dist/utils-Dzpl2ArK.js.map +0 -1
  123. package/dist/utils.js +0 -2
  124. package/dist/utils.js.map +0 -1
  125. package/dist/utils.mjs +0 -11
  126. package/dist/utils.mjs.map +0 -1
  127. package/src/adapters/videojs-adapter.tsx +0 -470
  128. package/src/assets/mona-loading.gif +0 -0
  129. package/src/components/AnimateLoading.tsx +0 -107
  130. package/src/components/LoadingState.tsx +0 -239
  131. package/src/components/__tests__/media-player-accessibility.test.tsx +0 -510
  132. package/src/components/__tests__/media-player-react19.test.tsx +0 -457
  133. package/src/components/accessibility/keyboard-help-overlay.tsx +0 -207
  134. package/src/components/audio-player.tsx +0 -85
  135. package/src/components/basic/index.ts +0 -37
  136. package/src/components/enhanced/advanced-features.tsx +0 -311
  137. package/src/components/enhanced/debug-panel.tsx +0 -448
  138. package/src/components/enhanced/enhanced-controls.tsx +0 -597
  139. package/src/components/enhanced/enhanced-media-player.tsx +0 -566
  140. package/src/components/enhanced/error-handling.tsx +0 -338
  141. package/src/components/enhanced/index.ts +0 -39
  142. package/src/components/enhanced/media-player-enhanced.tsx +0 -383
  143. package/src/components/examples/basic-video-player.tsx +0 -50
  144. package/src/components/examples/custom-controls-example.tsx +0 -63
  145. package/src/components/examples/enhanced-controls-example.tsx +0 -100
  146. package/src/components/examples/enhanced-media-player-example.tsx +0 -302
  147. package/src/components/examples/loading-states-demo.tsx +0 -142
  148. package/src/components/examples/react-19-demo.tsx +0 -353
  149. package/src/components/examples/volume-orientation-demo.tsx +0 -106
  150. package/src/components/icon-demo.tsx +0 -196
  151. package/src/components/legacy.tsx +0 -87
  152. package/src/components/media-metadata-display.tsx +0 -99
  153. package/src/components/media-player-audio.tsx +0 -39
  154. package/src/components/media-player-controls.tsx +0 -223
  155. package/src/components/media-player-error.tsx +0 -163
  156. package/src/components/media-player-fullscreen.tsx +0 -109
  157. package/src/components/media-player-hls.tsx +0 -111
  158. package/src/components/media-player-loading.tsx +0 -76
  159. package/src/components/media-player-play.tsx +0 -75
  160. package/src/components/media-player-root.tsx +0 -338
  161. package/src/components/media-player-seek.tsx +0 -168
  162. package/src/components/media-player-time.tsx +0 -99
  163. package/src/components/media-player-tooltip.tsx +0 -58
  164. package/src/components/media-player-video.tsx +0 -54
  165. package/src/components/media-player-volume.tsx +0 -155
  166. package/src/components/media-player.tsx +0 -292
  167. package/src/components/media-suspense.tsx +0 -344
  168. package/src/components/player-settings-form.tsx +0 -158
  169. package/src/components/react-player-wrapper.tsx +0 -651
  170. package/src/components/simple-video-player.tsx +0 -62
  171. package/src/components/ui/blur-poster.tsx +0 -93
  172. package/src/components/ui/empty-state.tsx +0 -91
  173. package/src/components/ui/enhanced-seek-bar.tsx +0 -254
  174. package/src/components/ui/error-state.tsx +0 -124
  175. package/src/components/ui/fullscreen-button.tsx +0 -81
  176. package/src/components/ui/loading-skeleton.tsx +0 -107
  177. package/src/components/ui/media-resource-preloader.tsx +0 -458
  178. package/src/components/ui/offline-message.tsx +0 -98
  179. package/src/components/ui/play-button.tsx +0 -99
  180. package/src/components/ui/seek-bar.tsx +0 -191
  181. package/src/components/ui/time-display.tsx +0 -61
  182. package/src/components/ui/volume-control.tsx +0 -190
  183. package/src/components/unified/base-media-player.tsx +0 -252
  184. package/src/components/unified/media-player.tsx +0 -75
  185. package/src/components/variants/minimal/AccessibleMinimalPlayer.tsx +0 -587
  186. package/src/components/variants/minimal/EnhancedMinimalMediaPlayer.tsx +0 -573
  187. package/src/components/variants/minimal/MinimalControls.tsx +0 -124
  188. package/src/components/variants/minimal/MinimalLoading.tsx +0 -28
  189. package/src/components/variants/minimal/MinimalMediaPlayer.tsx +0 -318
  190. package/src/components/variants/minimal/MinimalOverlay.tsx +0 -58
  191. package/src/components/variants/minimal/MinimalPlayButton.tsx +0 -56
  192. package/src/components/variants/minimal/MinimalSeekBar.tsx +0 -140
  193. package/src/components/variants/minimal/MinimalVolumeControl.tsx +0 -75
  194. package/src/components/variants/minimal/SimpleMinimalPlayer.tsx +0 -206
  195. package/src/components/variants/minimal/components/CenterPlayButton.tsx +0 -22
  196. package/src/components/variants/minimal/components/ControlBar.tsx +0 -142
  197. package/src/components/variants/minimal/components/EnhancedSettingsMenu.tsx +0 -412
  198. package/src/components/variants/minimal/components/PlaybackControls.tsx +0 -46
  199. package/src/components/variants/minimal/components/RightControls.tsx +0 -164
  200. package/src/components/variants/minimal/components/SeekBar.tsx +0 -127
  201. package/src/components/variants/minimal/components/SettingsDropdown.tsx +0 -68
  202. package/src/components/variants/minimal/components/SubtitleDisplay.tsx +0 -21
  203. package/src/components/variants/minimal/components/TimeDisplay.tsx +0 -15
  204. package/src/components/variants/minimal/components/VideoElement.tsx +0 -33
  205. package/src/components/variants/minimal/components/VolumeControl.tsx +0 -220
  206. package/src/components/variants/minimal/index.ts +0 -23
  207. package/src/components/video-player.tsx +0 -100
  208. package/src/context/__tests__/media-store.test.ts +0 -509
  209. package/src/context/error-handling.ts +0 -398
  210. package/src/context/media-context.tsx +0 -254
  211. package/src/context/media-provider.tsx +0 -264
  212. package/src/context/media-store.ts +0 -387
  213. package/src/context/persistence.ts +0 -462
  214. package/src/core/events/event-system.ts +0 -448
  215. package/src/core/events/hooks.ts +0 -325
  216. package/src/core/events/index.ts +0 -22
  217. package/src/core/events/middleware.ts +0 -286
  218. package/src/core/index.ts +0 -22
  219. package/src/core/optimization/bundle-optimizer.tsx +0 -312
  220. package/src/core/performance/cicd.ts +0 -98
  221. package/src/core/performance/index.ts +0 -38
  222. package/src/core/performance/media-loading-optimizer.ts +0 -544
  223. package/src/core/performance/performance-budgets.ts +0 -437
  224. package/src/core/performance/performance-monitor.tsx +0 -488
  225. package/src/core/performance/performance-testing.ts +0 -461
  226. package/src/core/plugins/__tests__/registry.test.ts +0 -595
  227. package/src/core/plugins/base-plugin.ts +0 -225
  228. package/src/core/plugins/enhanced-plugin-system.ts +0 -435
  229. package/src/core/plugins/examples/analytics-plugin.ts +0 -241
  230. package/src/core/plugins/index.ts +0 -39
  231. package/src/core/plugins/registry.ts +0 -546
  232. package/src/core/plugins/types.ts +0 -169
  233. package/src/core/plugins/utils.ts +0 -317
  234. package/src/core/progressive-loading.tsx +0 -331
  235. package/src/core/providers/enhanced-hls-provider.ts +0 -307
  236. package/src/core/providers/lazy-provider.tsx +0 -14
  237. package/src/core/providers/service-provider.tsx +0 -164
  238. package/src/core/utils.tsx +0 -34
  239. package/src/features/media-session/media-session-manager.ts +0 -411
  240. package/src/features/picture-in-picture/pip-manager.ts +0 -428
  241. package/src/features/playlist/playlist-manager.ts +0 -626
  242. package/src/features/subtitles/subtitle-manager.ts +0 -435
  243. package/src/features/subtitles/subtitle-parser.ts +0 -284
  244. package/src/features/thumbnails/thumbnail-generator.ts +0 -528
  245. package/src/hooks/__tests__/currentTime-fix.test.ts +0 -149
  246. package/src/hooks/__tests__/use-media-player.test.ts +0 -712
  247. package/src/hooks/__tests__/use-media-state.test.tsx +0 -316
  248. package/src/hooks/accessibility/index.ts +0 -27
  249. package/src/hooks/accessibility/use-accessibility-preferences.ts +0 -190
  250. package/src/hooks/accessibility/use-focus-management.ts +0 -183
  251. package/src/hooks/accessibility/use-keyboard-shortcuts.ts +0 -152
  252. package/src/hooks/accessibility/use-screen-reader.ts +0 -212
  253. package/src/hooks/core/index.ts +0 -47
  254. package/src/hooks/legacy.ts +0 -21
  255. package/src/hooks/use-buffer-health.ts +0 -218
  256. package/src/hooks/use-enhanced-media-player.ts +0 -575
  257. package/src/hooks/use-focus-trap.tsx +0 -162
  258. package/src/hooks/use-intelligent-preloading.ts +0 -387
  259. package/src/hooks/use-keyboard-controls.ts +0 -115
  260. package/src/hooks/use-keyboard-shortcuts.ts +0 -255
  261. package/src/hooks/use-media-actions.ts +0 -184
  262. package/src/hooks/use-media-metadata.ts +0 -91
  263. package/src/hooks/use-media-optimistic.ts +0 -264
  264. package/src/hooks/use-media-player.ts +0 -343
  265. package/src/hooks/use-media-state.ts +0 -194
  266. package/src/hooks/use-memory-optimization.ts +0 -360
  267. package/src/hooks/use-network-status.ts +0 -124
  268. package/src/hooks/use-optimistic-controls.ts +0 -95
  269. package/src/hooks/use-optimized-media.ts +0 -283
  270. package/src/hooks/use-smart-preload.ts +0 -229
  271. package/src/hooks/use-touch-gestures.ts +0 -461
  272. package/src/hooks/useEnhancedSubtitles.ts +0 -258
  273. package/src/hooks/useKeyboardShortcuts.ts +0 -106
  274. package/src/hooks/useMediaControls.ts +0 -52
  275. package/src/hooks/useScreenshot.ts +0 -61
  276. package/src/hooks/useSubtitles.ts +0 -91
  277. package/src/hooks/useVideoPlayer.ts +0 -278
  278. package/src/icons/components/FullscreenIcon.tsx +0 -36
  279. package/src/icons/components/SettingsIcon.tsx +0 -37
  280. package/src/icons/components/animated/LoadingIcon.tsx +0 -27
  281. package/src/icons/components/animated/PlayPauseIcon.tsx +0 -42
  282. package/src/icons/components/media/PauseIcon.tsx +0 -38
  283. package/src/icons/components/media/PlayIcon.tsx +0 -37
  284. package/src/icons/components/volume/VolumeIcon.tsx +0 -38
  285. package/src/icons/components/volume/VolumeOffIcon.tsx +0 -38
  286. package/src/icons/index.ts +0 -56
  287. package/src/icons/provider.tsx +0 -58
  288. package/src/icons/types.ts +0 -60
  289. package/src/index-enhanced.ts +0 -35
  290. package/src/index-legacy.ts +0 -324
  291. package/src/index.css +0 -102
  292. package/src/lib/__tests__/async-utils.test.ts +0 -291
  293. package/src/lib/async-utils.ts +0 -194
  294. package/src/lib/deprecation.ts +0 -51
  295. package/src/lib/format-time.ts +0 -37
  296. package/src/lib/index.ts +0 -4
  297. package/src/lib/utils.ts +0 -6
  298. package/src/styles/globals.css +0 -462
  299. package/src/styles/minimal-player.css +0 -621
  300. package/src/styles/pixel-art.css +0 -41
  301. package/src/styles/videojs.css +0 -100
  302. package/src/types/events.ts +0 -47
  303. package/src/types/formats.ts +0 -79
  304. package/src/types/index.ts +0 -203
  305. package/src/types/videojs-plugins.d.ts +0 -14
@@ -1,107 +0,0 @@
1
- import { memo } from "react"
2
- import { cn } from "../../lib/utils"
3
-
4
- interface LoadingSkeletonProps {
5
- className?: string
6
- variant?: "text" | "circular" | "rectangular" | "rounded"
7
- animation?: "pulse" | "wave" | "none"
8
- width?: number | string
9
- height?: number | string
10
- }
11
-
12
- const variantStyles = {
13
- text: "rounded",
14
- circular: "rounded-full",
15
- rectangular: "rounded-none",
16
- rounded: "rounded-lg"
17
- }
18
-
19
- const animationStyles = {
20
- pulse: "animate-pulse",
21
- wave: "animate-pulse",
22
- none: ""
23
- }
24
-
25
- const LoadingSkeletonComponent = memo(function LoadingSkeleton({
26
- className,
27
- variant = "text",
28
- animation = "pulse",
29
- width,
30
- height
31
- }: LoadingSkeletonProps) {
32
- return (
33
- <div
34
- className={cn(
35
- "bg-[color:var(--media-skeleton)]",
36
- variantStyles[variant],
37
- animation === "wave" &&
38
- "bg-[length:200%_100%] bg-gradient-to-r from-[color:var(--media-skeleton)] via-[color:var(--media-skeleton-light)] to-[color:var(--media-skeleton)]",
39
- animationStyles[animation],
40
- className
41
- )}
42
- style={{ width, height }}
43
- role="status"
44
- aria-label="Loading content"
45
- />
46
- )
47
- })
48
-
49
- interface LoadingSkeletonListProps {
50
- count?: number
51
- className?: string
52
- itemClassName?: string
53
- }
54
-
55
- export const LoadingSkeletonList = memo(function LoadingSkeletonList({
56
- count = 3,
57
- className,
58
- itemClassName
59
- }: LoadingSkeletonListProps) {
60
- return (
61
- <div className={cn("space-y-4", className)}>
62
- {Array.from({ length: count }).map((_, i) => (
63
- <LoadingSkeletonComponent
64
- key={i}
65
- variant="rounded"
66
- width="100%"
67
- height={60}
68
- className={itemClassName}
69
- />
70
- ))}
71
- </div>
72
- )
73
- })
74
-
75
- interface LoadingPlayerSkeletonProps {
76
- className?: string
77
- showTimeDisplay?: boolean
78
- showControls?: boolean
79
- }
80
-
81
- export const LoadingPlayerSkeleton = memo(function LoadingPlayerSkeleton({
82
- className,
83
- showTimeDisplay = true,
84
- showControls = true
85
- }: LoadingPlayerSkeletonProps) {
86
- return (
87
- <div className={cn("relative overflow-hidden rounded-lg bg-black", className)}>
88
- <LoadingSkeletonComponent
89
- variant="rectangular"
90
- width="100%"
91
- height="100%"
92
- className="aspect-video"
93
- />
94
- <div className="absolute right-0 bottom-0 left-0 p-4">
95
- {showTimeDisplay && (
96
- <div className="mb-2 flex justify-between">
97
- <LoadingSkeletonComponent variant="text" width={60} height={16} />
98
- <LoadingSkeletonComponent variant="text" width={60} height={16} />
99
- </div>
100
- )}
101
- {showControls && <LoadingSkeletonComponent variant="rounded" width="100%" height={8} />}
102
- </div>
103
- </div>
104
- )
105
- })
106
-
107
- export { LoadingSkeletonComponent as LoadingSkeleton }
@@ -1,458 +0,0 @@
1
- /**
2
- * Media Resource Preloader using React 19's resource preloading APIs
3
- * Implements intelligent preloading strategies based on user behavior and network conditions
4
- */
5
-
6
- import React, { useEffect, useRef, useMemo } from "react"
7
- import { preconnect, prefetchDNS, preinit, preload } from "react-dom"
8
- import { MediaSource } from "../../types"
9
-
10
- interface MediaResourcePreloaderProps {
11
- /** Media sources to preload */
12
- sources: MediaSource[]
13
- /** Enable intelligent preloading based on user behavior */
14
- enableIntelligentPreloading?: boolean
15
- /** Network-aware preloading */
16
- adaptToNetworkConditions?: boolean
17
- /** Preload priority level */
18
- priority?: "high" | "low" | "auto"
19
- /** Custom preloading strategy */
20
- strategy?: "conservative" | "aggressive" | "adaptive"
21
- }
22
-
23
- interface PreloadingConfig {
24
- dnsPrefetch: string[]
25
- preconnect: string[]
26
- preload: Array<{ url: string; type: string }>
27
- preinit: Array<{ url: string; type: string }>
28
- }
29
-
30
- export const MediaResourcePreloader: React.FC<MediaResourcePreloaderProps> = ({
31
- sources,
32
- enableIntelligentPreloading = true,
33
- adaptToNetworkConditions = true,
34
- priority = "auto",
35
- strategy = "adaptive"
36
- }) => {
37
- const networkInfoRef = useRef<any>(null)
38
- const userBehaviorRef = useRef<UserBehaviorTracker | null>(null)
39
- const preloadingHistoryRef = useRef<Map<string, number>>(new Map())
40
-
41
- // Helper functions (must be declared before use)
42
- function shouldUseCrossOrigin(url: string): boolean {
43
- return !url.includes(window.location.origin)
44
- }
45
-
46
- function getAssetIntegrity(url: string): string | undefined {
47
- // Return integrity hash if available for the asset
48
- // This would typically come from a build process or asset manifest
49
- return undefined
50
- }
51
-
52
- function preloadLikelyContent(sources: string[]): void {
53
- sources.forEach((url) => {
54
- // Mark as preloaded
55
- preloadingHistoryRef.current.set(url, Date.now())
56
-
57
- // Preload the content
58
- preload(url, {
59
- as: "fetch" as any,
60
- crossOrigin: "anonymous"
61
- } as any)
62
- })
63
- }
64
-
65
- function adjustPreloadingStrategy(): void {
66
- // Adjust preloading based on network conditions
67
- if (!networkInfoRef.current) return
68
-
69
- const { effectiveType, downlink } = networkInfoRef.current
70
-
71
- // This would update the preloading configuration
72
- // Implementation depends on specific requirements
73
- }
74
-
75
- // Analyze sources and determine preloading configuration
76
- const preloadingConfig = useMemo((): PreloadingConfig => {
77
- const config: PreloadingConfig = {
78
- dnsPrefetch: [],
79
- preconnect: [],
80
- preload: [],
81
- preinit: []
82
- }
83
-
84
- sources.forEach((source) => {
85
- const url = new URL(source.src)
86
- const domain = url.origin
87
-
88
- // DNS prefetch for CDN domains
89
- if (isCDNDomain(domain)) {
90
- config.dnsPrefetch.push(domain)
91
- }
92
-
93
- // Preconnect to media domains
94
- if (shouldPreconnect(source.type || "", strategy)) {
95
- config.preconnect.push(domain)
96
- }
97
-
98
- // Preload media files based on strategy (basic check without refs)
99
- if (shouldPreloadBasic(source, priority, strategy)) {
100
- config.preload.push({
101
- url: source.src,
102
- type: getPreloadType(source.type || "")
103
- })
104
- }
105
-
106
- // Preinit critical resources
107
- if (shouldPreinit(source, strategy)) {
108
- config.preinit.push({
109
- url: source.src,
110
- type: "script"
111
- })
112
- }
113
- })
114
-
115
- return config
116
- }, [sources, priority, strategy])
117
-
118
- // Store the filtered preloading config
119
- const [filteredPreloadingConfig, setFilteredPreloadingConfig] = React.useState(preloadingConfig)
120
-
121
- // Update filtered config when preloading config or refs change (safe ref access in effect)
122
- React.useEffect(() => {
123
- const filtered = { ...preloadingConfig }
124
- filtered.preload = preloadingConfig.preload.filter(({ url }) => {
125
- const source = sources.find((s) => s.src === url)
126
- if (!source) return false
127
-
128
- // Inline the full shouldPreload logic to avoid function hoisting issues
129
- // Check if already preloaded recently
130
- const lastPreload = preloadingHistoryRef.current.get(source.src)
131
- if (lastPreload && Date.now() - lastPreload < 300000) return false // 5 minutes
132
-
133
- // Strategy-based decision
134
- if (strategy === "conservative") {
135
- return priority === "high" && (source.type as string) === "hls"
136
- }
137
-
138
- if (strategy === "aggressive") {
139
- return true
140
- }
141
-
142
- // Adaptive strategy (simplified version)
143
- if (networkInfoRef.current) {
144
- const { effectiveType, saveData } = networkInfoRef.current
145
-
146
- if (saveData) return false
147
- if (effectiveType === "slow-2g" || effectiveType === "2g") {
148
- return priority === "high" && (source.type as string) === "hls"
149
- }
150
- if (effectiveType === "3g") {
151
- return ["hls", "m3u8"].includes(source.type || "")
152
- }
153
- }
154
-
155
- return priority !== "low"
156
- })
157
-
158
- setFilteredPreloadingConfig(filtered)
159
- }, [preloadingConfig, sources, priority, strategy])
160
-
161
- // Initialize network monitoring
162
- useEffect(() => {
163
- if (adaptToNetworkConditions && "connection" in navigator) {
164
- networkInfoRef.current = (navigator as any).connection
165
-
166
- const handleNetworkChange = () => {
167
- adjustPreloadingStrategy()
168
- }
169
-
170
- networkInfoRef.current.addEventListener("change", handleNetworkChange)
171
-
172
- return () => {
173
- networkInfoRef.current?.removeEventListener("change", handleNetworkChange)
174
- }
175
- }
176
- }, [adaptToNetworkConditions])
177
-
178
- // Initialize user behavior tracking
179
- useEffect(() => {
180
- if (enableIntelligentPreloading) {
181
- userBehaviorRef.current = new UserBehaviorTracker()
182
- userBehaviorRef.current.startTracking()
183
-
184
- return () => {
185
- userBehaviorRef.current?.stopTracking()
186
- }
187
- }
188
- }, [enableIntelligentPreloading])
189
-
190
- // Apply DNS prefetching
191
- useEffect(() => {
192
- filteredPreloadingConfig.dnsPrefetch.forEach((domain) => {
193
- prefetchDNS(domain)
194
- })
195
- }, [filteredPreloadingConfig.dnsPrefetch])
196
-
197
- // Apply preconnections
198
- useEffect(() => {
199
- filteredPreloadingConfig.preconnect.forEach((origin) => {
200
- preconnect(origin, { crossOrigin: "anonymous" })
201
- })
202
- }, [filteredPreloadingConfig.preconnect])
203
-
204
- // Apply preloading
205
- useEffect(() => {
206
- filteredPreloadingConfig.preload.forEach(({ url, type }) => {
207
- const crossOrigin = shouldUseCrossOrigin(url) ? "anonymous" : undefined
208
-
209
- preload(url, {
210
- as: type as any,
211
- crossOrigin,
212
- integrity: getAssetIntegrity(url)
213
- } as any)
214
- })
215
- }, [filteredPreloadingConfig.preload, priority])
216
-
217
- // Apply preinit for critical resources
218
- useEffect(() => {
219
- filteredPreloadingConfig.preinit.forEach(({ url, type }) => {
220
- const crossOrigin = shouldUseCrossOrigin(url) ? "anonymous" : undefined
221
-
222
- preinit(url, {
223
- as: type as any,
224
- crossOrigin
225
- } as any)
226
- })
227
- }, [filteredPreloadingConfig.preinit])
228
-
229
- // Intelligent preloading based on user behavior
230
- useEffect(() => {
231
- if (!enableIntelligentPreloading || !userBehaviorRef.current) return
232
-
233
- const handleUserBehavior = (behavior: UserBehaviorData) => {
234
- if (behavior.isLikelyToInteract) {
235
- preloadLikelyContent(behavior.predictedSources)
236
- }
237
- }
238
-
239
- userBehaviorRef.current.onBehaviorChange(handleUserBehavior)
240
- }, [enableIntelligentPreloading])
241
-
242
- // Helper functions
243
- function isCDNDomain(domain: string): boolean {
244
- const cdnDomains = [
245
- "cdn.jsdelivr.net",
246
- "cdnjs.cloudflare.com",
247
- "unpkg.com",
248
- "cloudflare.com",
249
- "fastly.net",
250
- "akamaized.net"
251
- ]
252
-
253
- return cdnDomains.some((cdn) => domain.includes(cdn))
254
- }
255
-
256
- function shouldPreconnect(mediaType: string, strategy: string): boolean {
257
- if (strategy === "aggressive") return true
258
- if (strategy === "conservative") return ["hls", "m3u8"].includes(mediaType)
259
- return ["hls", "m3u8", "mp4"].includes(mediaType)
260
- }
261
-
262
- function shouldPreloadBasic(source: MediaSource, priority: string, strategy: string): boolean {
263
- // Basic strategy-based decision without ref access
264
- if (strategy === "conservative") {
265
- return priority === "high" && (source.type as string) === "hls"
266
- }
267
-
268
- if (strategy === "aggressive") {
269
- return true
270
- }
271
-
272
- // Adaptive strategy (basic version)
273
- return priority !== "low"
274
- }
275
-
276
- function shouldPreload(
277
- source: MediaSource,
278
- priority: string,
279
- strategy: string,
280
- preloadingHistory: Map<string, number>,
281
- networkInfo: any
282
- ): boolean {
283
- // Check if already preloaded recently
284
- const lastPreload = preloadingHistory.get(source.src)
285
- if (lastPreload && Date.now() - lastPreload < 300000) return false // 5 minutes
286
-
287
- // Strategy-based decision
288
- if (strategy === "conservative") {
289
- return priority === "high" && (source.type as string) === "hls"
290
- }
291
-
292
- if (strategy === "aggressive") {
293
- return true
294
- }
295
-
296
- // Adaptive strategy
297
- return shouldAdaptivePreload(source, priority, networkInfo)
298
- }
299
-
300
- function shouldAdaptivePreload(
301
- source: MediaSource,
302
- priority: string,
303
- networkInfo: any
304
- ): boolean {
305
- // Consider network conditions
306
- if (networkInfo) {
307
- const { effectiveType, saveData } = networkInfo
308
-
309
- if (saveData) return false
310
- if (effectiveType === "slow-2g" || effectiveType === "2g") {
311
- return priority === "high" && (source.type as string) === "hls"
312
- }
313
- if (effectiveType === "3g") {
314
- return ["hls", "m3u8"].includes(source.type || "")
315
- }
316
- }
317
-
318
- // Consider user behavior
319
- if (userBehaviorRef.current) {
320
- const behavior = userBehaviorRef.current.getCurrentBehavior()
321
- if (behavior.engagementScore > 0.7) {
322
- return true
323
- }
324
- }
325
-
326
- return priority !== "low"
327
- }
328
-
329
- function shouldPreinit(source: MediaSource, strategy: string): boolean {
330
- return strategy === "aggressive" && (source.type as string) === "hls"
331
- }
332
-
333
- function getPreloadType(mediaType: string): string {
334
- switch (mediaType) {
335
- case "hls":
336
- case "m3u8":
337
- return "fetch"
338
- case "mp4":
339
- case "webm":
340
- return "video"
341
- case "mp3":
342
- case "wav":
343
- return "audio"
344
- default:
345
- return "fetch"
346
- }
347
- }
348
-
349
- // This component doesn't render anything visible
350
- return null
351
- }
352
-
353
- /**
354
- * User behavior tracker for intelligent preloading
355
- */
356
- class UserBehaviorTracker {
357
- private behaviorData: UserBehaviorData = {
358
- isLikelyToInteract: false,
359
- engagementScore: 0,
360
- predictedSources: [],
361
- interactionHistory: []
362
- }
363
-
364
- private listeners: ((behavior: UserBehaviorData) => void)[] = []
365
- private mouseMoveTimer: number | null = null
366
-
367
- public startTracking(): void {
368
- // Track mouse movements as interaction indicators
369
- document.addEventListener("mousemove", this.handleMouseMove)
370
- document.addEventListener("scroll", this.handleScroll)
371
- document.addEventListener("keydown", this.handleKeydown)
372
-
373
- // Track focus events
374
- document.addEventListener("focusin", this.handleFocus)
375
- document.addEventListener("visibilitychange", this.handleVisibilityChange)
376
- }
377
-
378
- public stopTracking(): void {
379
- document.removeEventListener("mousemove", this.handleMouseMove)
380
- document.removeEventListener("scroll", this.handleScroll)
381
- document.removeEventListener("keydown", this.handleKeydown)
382
- document.removeEventListener("focusin", this.handleFocus)
383
- document.removeEventListener("visibilitychange", this.handleVisibilityChange)
384
-
385
- if (this.mouseMoveTimer) {
386
- clearTimeout(this.mouseMoveTimer)
387
- }
388
- }
389
-
390
- public onBehaviorChange(listener: (behavior: UserBehaviorData) => void): void {
391
- this.listeners.push(listener)
392
- }
393
-
394
- public getCurrentBehavior(): UserBehaviorData {
395
- return this.behaviorData
396
- }
397
-
398
- private handleMouseMove = (): void => {
399
- if (this.mouseMoveTimer) return
400
-
401
- this.mouseMoveTimer = window.setTimeout(() => {
402
- this.updateEngagementScore(0.1)
403
- this.mouseMoveTimer = null
404
- }, 100)
405
- }
406
-
407
- private handleScroll = (): void => {
408
- this.updateEngagementScore(0.2)
409
- }
410
-
411
- private handleKeydown = (): void => {
412
- this.updateEngagementScore(0.3)
413
- this.behaviorData.isLikelyToInteract = true
414
- }
415
-
416
- private handleFocus = (): void => {
417
- this.updateEngagementScore(0.4)
418
- this.behaviorData.isLikelyToInteract = true
419
- }
420
-
421
- private handleVisibilityChange = (): void => {
422
- if (!document.hidden) {
423
- this.updateEngagementScore(0.5)
424
- this.behaviorData.isLikelyToInteract = true
425
- }
426
- }
427
-
428
- private updateEngagementScore(increment: number): void {
429
- this.behaviorData.engagementScore = Math.min(1, this.behaviorData.engagementScore + increment)
430
-
431
- // Decay engagement score over time
432
- setTimeout(() => {
433
- this.behaviorData.engagementScore = Math.max(
434
- 0,
435
- this.behaviorData.engagementScore - increment * 0.5
436
- )
437
- this.notifyListeners()
438
- }, 30000) // 30 seconds decay
439
-
440
- this.notifyListeners()
441
- }
442
-
443
- private notifyListeners(): void {
444
- this.listeners.forEach((listener) => listener(this.behaviorData))
445
- }
446
- }
447
-
448
- interface UserBehaviorData {
449
- isLikelyToInteract: boolean
450
- engagementScore: number
451
- predictedSources: string[]
452
- interactionHistory: Array<{
453
- type: string
454
- timestamp: number
455
- }>
456
- }
457
-
458
- export default MediaResourcePreloader
@@ -1,98 +0,0 @@
1
- import { RefreshCw, WifiOff } from "lucide-react"
2
- import { memo, useCallback } from "react"
3
- import { cn } from "../../lib/utils"
4
-
5
- interface OfflineMessageProps {
6
- className?: string
7
- title?: string
8
- message?: string
9
- onRetry?: () => void
10
- retryLabel?: string
11
- showRetry?: boolean
12
- }
13
-
14
- const OfflineMessageComponent = memo(function OfflineMessage({
15
- className,
16
- title = "You're offline",
17
- message = "Check your internet connection and try again.",
18
- onRetry,
19
- retryLabel = "Retry",
20
- showRetry = true
21
- }: OfflineMessageProps) {
22
- const handleRetry = useCallback(() => {
23
- onRetry?.()
24
- }, [onRetry])
25
-
26
- return (
27
- <div
28
- className={cn(
29
- "flex flex-col items-center justify-center p-8 text-center",
30
- "rounded-lg bg-[color:var(--media-bg)]",
31
- className
32
- )}
33
- role="alert"
34
- aria-live="polite">
35
- <div className="mb-4 rounded-full bg-[color:var(--media-control-bg)] p-4" aria-hidden="true">
36
- <WifiOff size={48} className="text-[color:var(--media-text-secondary)]" />
37
- </div>
38
- <h3 className="mb-2 font-semibold text-[color:var(--media-text)] text-lg">{title}</h3>
39
- <p className="mb-4 max-w-sm text-[color:var(--media-text-secondary)] text-sm">{message}</p>
40
- {showRetry && onRetry && (
41
- <button
42
- onClick={handleRetry}
43
- className={cn(
44
- "inline-flex items-center gap-2 rounded-lg px-4 py-2",
45
- "bg-[color:var(--media-primary)] text-white",
46
- "transition-opacity hover:opacity-90",
47
- "focus:outline-none focus:ring-2 focus:ring-[color:var(--media-primary)] focus:ring-offset-2"
48
- )}
49
- aria-label={retryLabel}>
50
- <RefreshCw size={16} />
51
- {retryLabel}
52
- </button>
53
- )}
54
- </div>
55
- )
56
- })
57
-
58
- interface OfflineBannerProps {
59
- className?: string
60
- onRetry?: () => void
61
- }
62
-
63
- export const OfflineBanner = memo(function OfflineBanner({
64
- className,
65
- onRetry
66
- }: OfflineBannerProps) {
67
- return (
68
- <div
69
- className={cn(
70
- "flex items-center justify-between gap-4 p-3 px-4",
71
- "rounded-lg border border-amber-500/20 bg-amber-500/10",
72
- className
73
- )}
74
- role="alert"
75
- aria-live="polite">
76
- <div className="flex items-center gap-3">
77
- <WifiOff size={20} className="text-amber-500" aria-hidden="true" />
78
- <span className="text-amber-500 text-sm">
79
- You're offline. Some features may be limited.
80
- </span>
81
- </div>
82
- {onRetry && (
83
- <button
84
- onClick={onRetry}
85
- className={cn(
86
- "rounded px-3 py-1 text-sm",
87
- "bg-amber-500/20 text-amber-500",
88
- "transition-colors hover:bg-amber-500/30"
89
- )}
90
- aria-label="Retry connection check">
91
- Retry
92
- </button>
93
- )}
94
- </div>
95
- )
96
- })
97
-
98
- export { OfflineMessageComponent as OfflineMessage }