@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,308 @@
1
+ "use client"
2
+
3
+ import React, { Suspense, lazy, useMemo } from "react"
4
+ import { MediaLoading } from "../../components/media-suspense"
5
+
6
+ // Lazy loaded components for bundle splitting
7
+ const LazyAdvancedControls = lazy(() =>
8
+ import("../../components/advanced-controls").then(module => ({
9
+ default: module.AdvancedControls
10
+ }))
11
+ )
12
+
13
+ const LazyPlaylist = lazy(() =>
14
+ import("../../features/playlist/Playlist").then(module => ({
15
+ default: module.Playlist
16
+ }))
17
+ )
18
+
19
+ const LazySubtitles = lazy(() =>
20
+ import("../../features/subtitles/SubtitleDisplay").then(module => ({
21
+ default: module.SubtitleDisplay
22
+ }))
23
+ )
24
+
25
+ const LazyAnalytics = lazy(() =>
26
+ import("../../core/plugins/examples/analytics-plugin").then(module => ({
27
+ default: module.AnalyticsPlugin
28
+ }))
29
+ )
30
+
31
+ // Component types for dynamic loading
32
+ export interface LazyComponentConfig {
33
+ component: string
34
+ fallback?: React.ReactNode
35
+ preload?: boolean
36
+ priority?: "high" | "normal" | "low"
37
+ }
38
+
39
+ // Bundle optimization component
40
+ export function BundleOptimizer({
41
+ children,
42
+ lazyComponents = [],
43
+ preloadStrategy = "viewport"
44
+ }: {
45
+ children: React.ReactNode
46
+ lazyComponents?: LazyComponentConfig[]
47
+ preloadStrategy?: "viewport" | "hover" | "immediate" | "never"
48
+ }) {
49
+ // Memoize component mapping for performance
50
+ const componentMap = useMemo(() => ({
51
+ 'advanced-controls': LazyAdvancedControls,
52
+ 'playlist': LazyPlaylist,
53
+ 'subtitles': LazySubtitles,
54
+ 'analytics': LazyAnalytics
55
+ }), [])
56
+
57
+ // Preload components based on strategy
58
+ React.useEffect(() => {
59
+ if (preloadStrategy === "immediate") {
60
+ // Preload all components immediately
61
+ lazyComponents.forEach(({ component }) => {
62
+ const Component = componentMap[component as keyof typeof componentMap]
63
+ if (Component) {
64
+ // Trigger dynamic import
65
+ Component.preload?.()
66
+ }
67
+ })
68
+ } else if (preloadStrategy === "viewport") {
69
+ // Preload when component is likely to enter viewport
70
+ const observer = new IntersectionObserver(
71
+ (entries) => {
72
+ entries.forEach((entry) => {
73
+ if (entry.isIntersecting) {
74
+ const componentName = entry.target.getAttribute('data-component')
75
+ if (componentName) {
76
+ const Component = componentMap[componentName as keyof typeof componentMap]
77
+ if (Component) {
78
+ Component.preload?.()
79
+ }
80
+ }
81
+ observer.unobserve(entry.target)
82
+ }
83
+ })
84
+ },
85
+ { threshold: 0.1, rootMargin: '50px' }
86
+ )
87
+
88
+ // Observe lazy component containers
89
+ lazyComponents.forEach(({ component, priority }) => {
90
+ if (priority === "high") {
91
+ const element = document.querySelector(`[data-component="${component}"]`)
92
+ if (element) {
93
+ observer.observe(element)
94
+ }
95
+ }
96
+ })
97
+
98
+ return () => observer.disconnect()
99
+ }
100
+ }, [preloadStrategy, lazyComponents, componentMap])
101
+
102
+ // Render lazy components with suspense boundaries
103
+ const renderLazyComponent = (config: LazyComponentConfig) => {
104
+ const Component = componentMap[config.component as keyof typeof componentMap]
105
+ if (!Component) return null
106
+
107
+ const LazyComponent = Component as React.ComponentType<any>
108
+
109
+ return (
110
+ <Suspense
111
+ key={config.component}
112
+ fallback={config.fallback || <MediaLoading size="sm" />}>
113
+ <div
114
+ data-component={config.component}
115
+ data-priority={config.priority}>
116
+ <LazyComponent />
117
+ </div>
118
+ </Suspense>
119
+ )
120
+ }
121
+
122
+ return (
123
+ <>
124
+ {children}
125
+ {lazyComponents.map(renderLazyComponent)}
126
+ </>
127
+ )
128
+ }
129
+
130
+ // Progressive loading hook
131
+ export function useProgressiveLoading() {
132
+ const [loadedComponents, setLoadedComponents] = React.useState<Set<string>>(new Set())
133
+
134
+ const loadComponent = React.useCallback(async (componentName: string) => {
135
+ if (loadedComponents.has(componentName)) return
136
+
137
+ try {
138
+ // Dynamic import based on component name
139
+ const imports: Record<string, () => Promise<any>> = {
140
+ 'advanced-controls': () => import("../../components/advanced-controls"),
141
+ 'playlist': () => import("../../features/playlist/Playlist"),
142
+ 'subtitles': () => import("../../features/subtitles/SubtitleDisplay"),
143
+ 'analytics': () => import("../../core/plugins/examples/analytics-plugin")
144
+ }
145
+
146
+ const importFn = imports[componentName]
147
+ if (importFn) {
148
+ await importFn()
149
+ setLoadedComponents(prev => new Set([...prev, componentName]))
150
+ }
151
+ } catch (error) {
152
+ console.warn(`Failed to load component ${componentName}:`, error)
153
+ }
154
+ }, [loadedComponents])
155
+
156
+ const preloadComponents = React.useCallback((componentNames: string[]) => {
157
+ componentNames.forEach(loadComponent)
158
+ }, [loadComponent])
159
+
160
+ return {
161
+ loadedComponents,
162
+ loadComponent,
163
+ preloadComponents,
164
+ isComponentLoaded: (componentName: string) => loadedComponents.has(componentName)
165
+ }
166
+ }
167
+
168
+ // Tree shaking utilities
169
+ export function createLazyComponent<T extends React.ComponentType<any>>(
170
+ importFn: () => Promise<{ default: T }>,
171
+ componentName: string
172
+ ) {
173
+ const LazyComponent = React.lazy(importFn)
174
+
175
+ // Add preload method for manual preloading
176
+ (LazyComponent as any).preload = importFn
177
+
178
+ // Add display name for debugging
179
+ LazyComponent.displayName = `Lazy${componentName}`
180
+
181
+ return LazyComponent
182
+ }
183
+
184
+ // Bundle analyzer utilities
185
+ export interface BundleMetrics {
186
+ totalSize: number
187
+ chunkSizes: Record<string, number>
188
+ loadedChunks: Set<string>
189
+ pendingChunks: Set<string>
190
+ compressionRatio: number
191
+ }
192
+
193
+ export function useBundleMetrics() {
194
+ const [metrics, setMetrics] = React.useState<BundleMetrics>({
195
+ totalSize: 0,
196
+ chunkSizes: {},
197
+ loadedChunks: new Set(),
198
+ pendingChunks: new Set(),
199
+ compressionRatio: 1
200
+ })
201
+
202
+ React.useEffect(() => {
203
+ // Monitor bundle loading if performance observer is available
204
+ if (typeof window !== 'undefined' && 'PerformanceObserver' in window) {
205
+ const observer = new PerformanceObserver((list) => {
206
+ for (const entry of list.getEntries()) {
207
+ if (entry.entryType === 'resource' && entry.name.includes('.js')) {
208
+ const chunkName = entry.name.split('/').pop() || 'unknown'
209
+
210
+ setMetrics(prev => ({
211
+ ...prev,
212
+ chunkSizes: {
213
+ ...prev.chunkSizes,
214
+ [chunkName]: entry.transferSize || 0
215
+ },
216
+ loadedChunks: new Set([...prev.loadedChunks, chunkName]),
217
+ totalSize: prev.totalSize + (entry.transferSize || 0)
218
+ }))
219
+ }
220
+ }
221
+ })
222
+
223
+ observer.observe({ entryTypes: ['resource'] })
224
+
225
+ return () => observer.disconnect()
226
+ }
227
+ }, [])
228
+
229
+ const getLargestChunk = React.useCallback(() => {
230
+ const entries = Object.entries(metrics.chunkSizes)
231
+ if (entries.length === 0) return null
232
+
233
+ return entries.reduce((a, b) => a[1] > b[1] ? a : b)
234
+ }, [metrics.chunkSizes])
235
+
236
+ const formatBytes = React.useCallback((bytes: number) => {
237
+ if (bytes === 0) return '0 Bytes'
238
+ const k = 1024
239
+ const sizes = ['Bytes', 'KB', 'MB', 'GB']
240
+ const i = Math.floor(Math.log(bytes) / Math.log(k))
241
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
242
+ }, [])
243
+
244
+ return {
245
+ ...metrics,
246
+ largestChunk: getLargestChunk(),
247
+ formatBytes,
248
+ totalSizeFormatted: formatBytes(metrics.totalSize)
249
+ }
250
+ }
251
+
252
+ // Preloading strategies
253
+ export const PreloadStrategies = {
254
+ // Preload when user hovers over trigger element
255
+ onHover: (element: HTMLElement, importFn: () => Promise<any>) => {
256
+ let timeoutId: NodeJS.Timeout
257
+
258
+ const handleMouseEnter = () => {
259
+ timeoutId = setTimeout(importFn, 200) // 200ms delay
260
+ }
261
+
262
+ const handleMouseLeave = () => {
263
+ if (timeoutId) {
264
+ clearTimeout(timeoutId)
265
+ }
266
+ }
267
+
268
+ element.addEventListener('mouseenter', handleMouseEnter)
269
+ element.addEventListener('mouseleave', handleMouseLeave)
270
+
271
+ return () => {
272
+ element.removeEventListener('mouseenter', handleMouseEnter)
273
+ element.removeEventListener('mouseleave', handleMouseLeave)
274
+ if (timeoutId) {
275
+ clearTimeout(timeoutId)
276
+ }
277
+ }
278
+ },
279
+
280
+ // Preload when component enters viewport
281
+ onViewport: (element: HTMLElement, importFn: () => Promise<any>) => {
282
+ const observer = new IntersectionObserver(
283
+ (entries) => {
284
+ entries.forEach((entry) => {
285
+ if (entry.isIntersecting) {
286
+ importFn()
287
+ observer.unobserve(entry.target)
288
+ }
289
+ })
290
+ },
291
+ { threshold: 0.1, rootMargin: '50px' }
292
+ )
293
+
294
+ observer.observe(element)
295
+ return () => observer.disconnect()
296
+ },
297
+
298
+ // Preload after idle time
299
+ onIdle: (importFn: () => Promise<any>, delay = 1000) => {
300
+ if ('requestIdleCallback' in window) {
301
+ return (window as any).requestIdleCallback(() => {
302
+ setTimeout(importFn, delay)
303
+ })
304
+ } else {
305
+ return setTimeout(importFn, delay)
306
+ }
307
+ }
308
+ }
@@ -0,0 +1,96 @@
1
+ // CI/CD integration utilities - Node.js only
2
+ import { performanceBudgetMonitor, type BudgetViolation } from './performance-budgets';
3
+
4
+ export const cicdIntegration = {
5
+ // Check if running in CI environment
6
+ isCI(): boolean {
7
+ return !!(
8
+ process.env.CI ||
9
+ process.env.CONTINUOUS_INTEGRATION ||
10
+ process.env.BUILD_NUMBER ||
11
+ process.env.GITHUB_ACTIONS ||
12
+ process.env.GITLAB_CI ||
13
+ process.env.CIRCLE_CI
14
+ );
15
+ },
16
+
17
+ // Exit with error code if budget violations found
18
+ async enforcebudgets(distPath: string): Promise<void> {
19
+ const violations = await performanceBudgetMonitor.checkBundleSizes(distPath);
20
+ const errorViolations = violations.filter(v => v.budget.severity === 'error');
21
+
22
+ if (errorViolations.length > 0) {
23
+ console.error(`❌ Performance budget violations detected: ${errorViolations.length} errors`);
24
+ errorViolations.forEach(violation => {
25
+ console.error(` - ${violation.budget.name}: ${this.formatValue(violation.actualValue, violation.budget.unit)} (limit: ${this.formatValue(violation.budget.limit, violation.budget.unit)})`);
26
+ });
27
+
28
+ if (this.isCI()) {
29
+ process.exit(1);
30
+ }
31
+ } else {
32
+ console.log('✅ All performance budgets passed');
33
+ }
34
+ },
35
+
36
+ // Generate budget report for CI
37
+ generateCIReport(): string {
38
+ const summary = performanceBudgetMonitor.getViolationSummary();
39
+ const violations = performanceBudgetMonitor.getViolations();
40
+
41
+ let report = '## Performance Budget Report\n\n';
42
+
43
+ if (summary.total === 0) {
44
+ report += '✅ **All performance budgets passed!**\n\n';
45
+ } else {
46
+ report += `❌ **${summary.total} budget violations detected**\n\n`;
47
+
48
+ report += '### Violations by Category\n';
49
+ Object.entries(summary.byCategory).forEach(([category, count]) => {
50
+ report += `- ${category}: ${count}\n`;
51
+ });
52
+
53
+ report += '\n### Violations by Severity\n';
54
+ Object.entries(summary.bySeverity).forEach(([severity, count]) => {
55
+ const emoji = severity === 'error' ? '🔴' : severity === 'warning' ? '🟡' : '🔵';
56
+ report += `- ${emoji} ${severity}: ${count}\n`;
57
+ });
58
+
59
+ report += '\n### Detailed Violations\n';
60
+ violations.forEach(violation => {
61
+ const emoji = violation.budget.severity === 'error' ? '🔴' : '🟡';
62
+ report += `${emoji} **${violation.budget.name}**\n`;
63
+ report += `- Limit: ${this.formatValue(violation.budget.limit, violation.budget.unit)}\n`;
64
+ report += `- Actual: ${this.formatValue(violation.actualValue, violation.budget.unit)}\n`;
65
+ report += `- Overage: +${violation.overagePercentage.toFixed(1)}%\n\n`;
66
+ });
67
+ }
68
+
69
+ return report;
70
+ },
71
+
72
+ formatValue(value: number, unit: 'bytes' | 'ms' | 'score' | 'percent'): string {
73
+ switch (unit) {
74
+ case 'bytes':
75
+ return this.formatBytes(value);
76
+ case 'ms':
77
+ return `${value.toFixed(2)}ms`;
78
+ case 'score':
79
+ return value.toFixed(3);
80
+ case 'percent':
81
+ return `${value.toFixed(1)}%`;
82
+ default:
83
+ return value.toString();
84
+ }
85
+ },
86
+
87
+ formatBytes(bytes: number): string {
88
+ if (bytes >= 1024 * 1024) {
89
+ return `${(bytes / 1024 / 1024).toFixed(2)}MB`;
90
+ }
91
+ if (bytes >= 1024) {
92
+ return `${(bytes / 1024).toFixed(2)}KB`;
93
+ }
94
+ return `${bytes}B`;
95
+ }
96
+ };
@@ -0,0 +1,38 @@
1
+ // Performance Monitoring
2
+ export * from './performance-monitor';
3
+ export { default as PerformanceMonitor } from './performance-monitor';
4
+
5
+ // Performance Testing
6
+ export * from './performance-testing';
7
+
8
+ // Performance Budgets and CI/CD
9
+ export * from './performance-budgets';
10
+
11
+ // Media Loading Optimization
12
+ export * from './media-loading-optimizer';
13
+
14
+ // Re-export key classes and utilities for convenience
15
+ export {
16
+ performanceMonitor,
17
+ PerformanceDashboard,
18
+ usePerformanceMonitor,
19
+ withPerformanceMonitoring
20
+ } from './performance-monitor';
21
+
22
+ export {
23
+ performanceBenchmark,
24
+ performanceTestUtils,
25
+ performanceTestFramework
26
+ } from './performance-testing';
27
+
28
+ export {
29
+ performanceBudgetMonitor,
30
+ defaultPerformanceBudgets
31
+ } from './performance-budgets';
32
+
33
+ export {
34
+ mediaLoadingOptimizer,
35
+ useMediaLoadingOptimizer,
36
+ NetworkMonitor,
37
+ MediaLoadingOptimizer
38
+ } from './media-loading-optimizer';