@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.
- package/README.md +91 -73
- package/dist/components/icons/index.d.ts +36 -0
- package/dist/components/icons/index.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/ArrowLeftIcon.d.ts +4 -0
- package/dist/components/icons/svg-icons/ArrowLeftIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/ArrowRightIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/ArrowRightIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/AudioIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/AudioIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/BackwardIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/BackwardIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/CameraIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/CameraIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/CheckIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/CheckIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/EnablePiPIcon.d.ts +4 -0
- package/dist/components/icons/svg-icons/EnablePiPIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/ForwardIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/ForwardIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/FullscreenEnterIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/FullscreenEnterIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/FullscreenExitIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/FullscreenExitIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/LoadingIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/LoadingIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/PauseIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/PauseIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/PlayIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/PlayIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/PlaybackSpeedIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/PlaybackSpeedIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/QualityIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/QualityIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/SettingsIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/SettingsIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/SliderIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/SliderIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/SubtitleIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/SubtitleIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/SubtitleOffIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/SubtitleOffIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/UnPiPIcon.d.ts +4 -0
- package/dist/components/icons/svg-icons/UnPiPIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/VolumeMutedIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/VolumeMutedIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/VolumeOneIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/VolumeOneIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/VolumeThreeIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/VolumeThreeIcon.d.ts.map +1 -0
- package/dist/components/icons/svg-icons/VolumeTwoIcon.d.ts +5 -0
- package/dist/components/icons/svg-icons/VolumeTwoIcon.d.ts.map +1 -0
- package/dist/components/variants/gradient/gradient-audio.d.ts +13 -0
- package/dist/components/variants/gradient/gradient-audio.d.ts.map +1 -0
- package/dist/components/variants/gradient/gradient-controls.d.ts +4 -0
- package/dist/components/variants/gradient/gradient-controls.d.ts.map +1 -0
- package/dist/components/variants/gradient/gradient-glyphs.d.ts +30 -0
- package/dist/components/variants/gradient/gradient-glyphs.d.ts.map +1 -0
- package/dist/components/variants/gradient/gradient-video.d.ts +16 -0
- package/dist/components/variants/gradient/gradient-video.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -112
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +786 -6271
- package/dist/index.mjs.map +1 -1
- package/dist/package.json +3 -0
- package/package.json +110 -108
- package/src/components/variants/gradient/gradient-audio.tsx +47 -0
- package/src/components/variants/gradient/gradient-controls.tsx +254 -0
- package/src/components/variants/gradient/gradient-glyphs.test.tsx +69 -0
- package/src/components/variants/gradient/gradient-glyphs.tsx +129 -0
- package/src/components/variants/gradient/gradient-skin.css +211 -0
- package/src/components/variants/gradient/gradient-video.tsx +70 -0
- package/src/index.ts +5 -198
- package/src/test/accessibility-utils.ts +0 -59
- package/dist/context/media.js +0 -2
- package/dist/context/media.js.map +0 -1
- package/dist/context/media.mjs +0 -15
- package/dist/context/media.mjs.map +0 -1
- package/dist/context/store.js +0 -2
- package/dist/context/store.js.map +0 -1
- package/dist/context/store.mjs +0 -5
- package/dist/context/store.mjs.map +0 -1
- package/dist/context-BYwDoSRX.js +0 -1172
- package/dist/context-BYwDoSRX.js.map +0 -1
- package/dist/context-eNS62_ac.cjs +0 -23
- package/dist/context-eNS62_ac.cjs.map +0 -1
- package/dist/core-events-B1iM2F46.cjs +0 -2
- package/dist/core-events-B1iM2F46.cjs.map +0 -1
- package/dist/core-events-DunPHKRE.js +0 -484
- package/dist/core-events-DunPHKRE.js.map +0 -1
- package/dist/core-plugins-By-4-kGs.cjs +0 -2
- package/dist/core-plugins-By-4-kGs.cjs.map +0 -1
- package/dist/core-plugins-DSBWcTuX.js +0 -821
- package/dist/core-plugins-DSBWcTuX.js.map +0 -1
- package/dist/core.js +0 -37
- package/dist/core.js.map +0 -1
- package/dist/core.mjs +0 -1233
- package/dist/core.mjs.map +0 -1
- package/dist/enhanced-components-B_l3cist.js +0 -1142
- package/dist/enhanced-components-B_l3cist.js.map +0 -1
- package/dist/enhanced-components-BspFs9OO.cjs +0 -2
- package/dist/enhanced-components-BspFs9OO.cjs.map +0 -1
- package/dist/hooks-BXwI8QG6.cjs +0 -4
- package/dist/hooks-BXwI8QG6.cjs.map +0 -1
- package/dist/hooks-Bpi-jDiO.js +0 -1816
- package/dist/hooks-Bpi-jDiO.js.map +0 -1
- package/dist/minimal-components-C4z900Ro.js +0 -1926
- package/dist/minimal-components-C4z900Ro.js.map +0 -1
- package/dist/minimal-components-v4qBp6jv.cjs +0 -2
- package/dist/minimal-components-v4qBp6jv.cjs.map +0 -1
- package/dist/minimal-components.css +0 -1
- package/dist/mona-loading.gif +0 -0
- package/dist/performance-monitor-C5k6FDXw.js +0 -301
- package/dist/performance-monitor-C5k6FDXw.js.map +0 -1
- package/dist/performance-monitor-lJmuUjQQ.cjs +0 -2
- package/dist/performance-monitor-lJmuUjQQ.cjs.map +0 -1
- package/dist/utils-CFOue_9K.cjs +0 -9
- package/dist/utils-CFOue_9K.cjs.map +0 -1
- package/dist/utils-Dzpl2ArK.js +0 -2844
- package/dist/utils-Dzpl2ArK.js.map +0 -1
- package/dist/utils.js +0 -2
- package/dist/utils.js.map +0 -1
- package/dist/utils.mjs +0 -11
- package/dist/utils.mjs.map +0 -1
- package/src/adapters/videojs-adapter.tsx +0 -470
- package/src/assets/mona-loading.gif +0 -0
- package/src/components/AnimateLoading.tsx +0 -107
- package/src/components/LoadingState.tsx +0 -239
- package/src/components/__tests__/media-player-accessibility.test.tsx +0 -510
- package/src/components/__tests__/media-player-react19.test.tsx +0 -457
- package/src/components/accessibility/keyboard-help-overlay.tsx +0 -207
- package/src/components/audio-player.tsx +0 -85
- package/src/components/basic/index.ts +0 -37
- package/src/components/enhanced/advanced-features.tsx +0 -311
- package/src/components/enhanced/debug-panel.tsx +0 -448
- package/src/components/enhanced/enhanced-controls.tsx +0 -597
- package/src/components/enhanced/enhanced-media-player.tsx +0 -566
- package/src/components/enhanced/error-handling.tsx +0 -338
- package/src/components/enhanced/index.ts +0 -39
- package/src/components/enhanced/media-player-enhanced.tsx +0 -383
- package/src/components/examples/basic-video-player.tsx +0 -50
- package/src/components/examples/custom-controls-example.tsx +0 -63
- package/src/components/examples/enhanced-controls-example.tsx +0 -100
- package/src/components/examples/enhanced-media-player-example.tsx +0 -302
- package/src/components/examples/loading-states-demo.tsx +0 -142
- package/src/components/examples/react-19-demo.tsx +0 -353
- package/src/components/examples/volume-orientation-demo.tsx +0 -106
- package/src/components/icon-demo.tsx +0 -196
- package/src/components/legacy.tsx +0 -87
- package/src/components/media-metadata-display.tsx +0 -99
- package/src/components/media-player-audio.tsx +0 -39
- package/src/components/media-player-controls.tsx +0 -223
- package/src/components/media-player-error.tsx +0 -163
- package/src/components/media-player-fullscreen.tsx +0 -109
- package/src/components/media-player-hls.tsx +0 -111
- package/src/components/media-player-loading.tsx +0 -76
- package/src/components/media-player-play.tsx +0 -75
- package/src/components/media-player-root.tsx +0 -338
- package/src/components/media-player-seek.tsx +0 -168
- package/src/components/media-player-time.tsx +0 -99
- package/src/components/media-player-tooltip.tsx +0 -58
- package/src/components/media-player-video.tsx +0 -54
- package/src/components/media-player-volume.tsx +0 -155
- package/src/components/media-player.tsx +0 -292
- package/src/components/media-suspense.tsx +0 -344
- package/src/components/player-settings-form.tsx +0 -158
- package/src/components/react-player-wrapper.tsx +0 -651
- package/src/components/simple-video-player.tsx +0 -62
- package/src/components/ui/blur-poster.tsx +0 -93
- package/src/components/ui/empty-state.tsx +0 -91
- package/src/components/ui/enhanced-seek-bar.tsx +0 -254
- package/src/components/ui/error-state.tsx +0 -124
- package/src/components/ui/fullscreen-button.tsx +0 -81
- package/src/components/ui/loading-skeleton.tsx +0 -107
- package/src/components/ui/media-resource-preloader.tsx +0 -458
- package/src/components/ui/offline-message.tsx +0 -98
- package/src/components/ui/play-button.tsx +0 -99
- package/src/components/ui/seek-bar.tsx +0 -191
- package/src/components/ui/time-display.tsx +0 -61
- package/src/components/ui/volume-control.tsx +0 -190
- package/src/components/unified/base-media-player.tsx +0 -252
- package/src/components/unified/media-player.tsx +0 -75
- package/src/components/variants/minimal/AccessibleMinimalPlayer.tsx +0 -587
- package/src/components/variants/minimal/EnhancedMinimalMediaPlayer.tsx +0 -573
- package/src/components/variants/minimal/MinimalControls.tsx +0 -124
- package/src/components/variants/minimal/MinimalLoading.tsx +0 -28
- package/src/components/variants/minimal/MinimalMediaPlayer.tsx +0 -318
- package/src/components/variants/minimal/MinimalOverlay.tsx +0 -58
- package/src/components/variants/minimal/MinimalPlayButton.tsx +0 -56
- package/src/components/variants/minimal/MinimalSeekBar.tsx +0 -140
- package/src/components/variants/minimal/MinimalVolumeControl.tsx +0 -75
- package/src/components/variants/minimal/SimpleMinimalPlayer.tsx +0 -206
- package/src/components/variants/minimal/components/CenterPlayButton.tsx +0 -22
- package/src/components/variants/minimal/components/ControlBar.tsx +0 -142
- package/src/components/variants/minimal/components/EnhancedSettingsMenu.tsx +0 -412
- package/src/components/variants/minimal/components/PlaybackControls.tsx +0 -46
- package/src/components/variants/minimal/components/RightControls.tsx +0 -164
- package/src/components/variants/minimal/components/SeekBar.tsx +0 -127
- package/src/components/variants/minimal/components/SettingsDropdown.tsx +0 -68
- package/src/components/variants/minimal/components/SubtitleDisplay.tsx +0 -21
- package/src/components/variants/minimal/components/TimeDisplay.tsx +0 -15
- package/src/components/variants/minimal/components/VideoElement.tsx +0 -33
- package/src/components/variants/minimal/components/VolumeControl.tsx +0 -220
- package/src/components/variants/minimal/index.ts +0 -23
- package/src/components/video-player.tsx +0 -100
- package/src/context/__tests__/media-store.test.ts +0 -509
- package/src/context/error-handling.ts +0 -398
- package/src/context/media-context.tsx +0 -254
- package/src/context/media-provider.tsx +0 -264
- package/src/context/media-store.ts +0 -387
- package/src/context/persistence.ts +0 -462
- package/src/core/events/event-system.ts +0 -448
- package/src/core/events/hooks.ts +0 -325
- package/src/core/events/index.ts +0 -22
- package/src/core/events/middleware.ts +0 -286
- package/src/core/index.ts +0 -22
- package/src/core/optimization/bundle-optimizer.tsx +0 -312
- package/src/core/performance/cicd.ts +0 -98
- package/src/core/performance/index.ts +0 -38
- package/src/core/performance/media-loading-optimizer.ts +0 -544
- package/src/core/performance/performance-budgets.ts +0 -437
- package/src/core/performance/performance-monitor.tsx +0 -488
- package/src/core/performance/performance-testing.ts +0 -461
- package/src/core/plugins/__tests__/registry.test.ts +0 -595
- package/src/core/plugins/base-plugin.ts +0 -225
- package/src/core/plugins/enhanced-plugin-system.ts +0 -435
- package/src/core/plugins/examples/analytics-plugin.ts +0 -241
- package/src/core/plugins/index.ts +0 -39
- package/src/core/plugins/registry.ts +0 -546
- package/src/core/plugins/types.ts +0 -169
- package/src/core/plugins/utils.ts +0 -317
- package/src/core/progressive-loading.tsx +0 -331
- package/src/core/providers/enhanced-hls-provider.ts +0 -307
- package/src/core/providers/lazy-provider.tsx +0 -14
- package/src/core/providers/service-provider.tsx +0 -164
- package/src/core/utils.tsx +0 -34
- package/src/features/media-session/media-session-manager.ts +0 -411
- package/src/features/picture-in-picture/pip-manager.ts +0 -428
- package/src/features/playlist/playlist-manager.ts +0 -626
- package/src/features/subtitles/subtitle-manager.ts +0 -435
- package/src/features/subtitles/subtitle-parser.ts +0 -284
- package/src/features/thumbnails/thumbnail-generator.ts +0 -528
- package/src/hooks/__tests__/currentTime-fix.test.ts +0 -149
- package/src/hooks/__tests__/use-media-player.test.ts +0 -712
- package/src/hooks/__tests__/use-media-state.test.tsx +0 -316
- package/src/hooks/accessibility/index.ts +0 -27
- package/src/hooks/accessibility/use-accessibility-preferences.ts +0 -190
- package/src/hooks/accessibility/use-focus-management.ts +0 -183
- package/src/hooks/accessibility/use-keyboard-shortcuts.ts +0 -152
- package/src/hooks/accessibility/use-screen-reader.ts +0 -212
- package/src/hooks/core/index.ts +0 -47
- package/src/hooks/legacy.ts +0 -21
- package/src/hooks/use-buffer-health.ts +0 -218
- package/src/hooks/use-enhanced-media-player.ts +0 -575
- package/src/hooks/use-focus-trap.tsx +0 -162
- package/src/hooks/use-intelligent-preloading.ts +0 -387
- package/src/hooks/use-keyboard-controls.ts +0 -115
- package/src/hooks/use-keyboard-shortcuts.ts +0 -255
- package/src/hooks/use-media-actions.ts +0 -184
- package/src/hooks/use-media-metadata.ts +0 -91
- package/src/hooks/use-media-optimistic.ts +0 -264
- package/src/hooks/use-media-player.ts +0 -343
- package/src/hooks/use-media-state.ts +0 -194
- package/src/hooks/use-memory-optimization.ts +0 -360
- package/src/hooks/use-network-status.ts +0 -124
- package/src/hooks/use-optimistic-controls.ts +0 -95
- package/src/hooks/use-optimized-media.ts +0 -283
- package/src/hooks/use-smart-preload.ts +0 -229
- package/src/hooks/use-touch-gestures.ts +0 -461
- package/src/hooks/useEnhancedSubtitles.ts +0 -258
- package/src/hooks/useKeyboardShortcuts.ts +0 -106
- package/src/hooks/useMediaControls.ts +0 -52
- package/src/hooks/useScreenshot.ts +0 -61
- package/src/hooks/useSubtitles.ts +0 -91
- package/src/hooks/useVideoPlayer.ts +0 -278
- package/src/icons/components/FullscreenIcon.tsx +0 -36
- package/src/icons/components/SettingsIcon.tsx +0 -37
- package/src/icons/components/animated/LoadingIcon.tsx +0 -27
- package/src/icons/components/animated/PlayPauseIcon.tsx +0 -42
- package/src/icons/components/media/PauseIcon.tsx +0 -38
- package/src/icons/components/media/PlayIcon.tsx +0 -37
- package/src/icons/components/volume/VolumeIcon.tsx +0 -38
- package/src/icons/components/volume/VolumeOffIcon.tsx +0 -38
- package/src/icons/index.ts +0 -56
- package/src/icons/provider.tsx +0 -58
- package/src/icons/types.ts +0 -60
- package/src/index-enhanced.ts +0 -35
- package/src/index-legacy.ts +0 -324
- package/src/index.css +0 -102
- package/src/lib/__tests__/async-utils.test.ts +0 -291
- package/src/lib/async-utils.ts +0 -194
- package/src/lib/deprecation.ts +0 -51
- package/src/lib/format-time.ts +0 -37
- package/src/lib/index.ts +0 -4
- package/src/lib/utils.ts +0 -6
- package/src/styles/globals.css +0 -462
- package/src/styles/minimal-player.css +0 -621
- package/src/styles/pixel-art.css +0 -41
- package/src/styles/videojs.css +0 -100
- package/src/types/events.ts +0 -47
- package/src/types/formats.ts +0 -79
- package/src/types/index.ts +0 -203
- package/src/types/videojs-plugins.d.ts +0 -14
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
import type { Plugin, PluginConfig, PluginLogger } from "./types"
|
|
2
|
-
|
|
3
|
-
// Simple console logger implementation
|
|
4
|
-
export class ConsolePluginLogger implements PluginLogger {
|
|
5
|
-
private prefix: string
|
|
6
|
-
|
|
7
|
-
constructor(prefix = "[Plugin]") {
|
|
8
|
-
this.prefix = prefix
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
info(message: string, data?: any): void {
|
|
12
|
-
if (data) {
|
|
13
|
-
console.info(`${this.prefix} ${message}`, data)
|
|
14
|
-
} else {
|
|
15
|
-
console.info(`${this.prefix} ${message}`)
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
warn(message: string, data?: any): void {
|
|
20
|
-
if (data) {
|
|
21
|
-
console.warn(`${this.prefix} ${message}`, data)
|
|
22
|
-
} else {
|
|
23
|
-
console.warn(`${this.prefix} ${message}`)
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
error(message: string, data?: any): void {
|
|
28
|
-
if (data) {
|
|
29
|
-
console.error(`${this.prefix} ${message}`, data)
|
|
30
|
-
} else {
|
|
31
|
-
console.error(`${this.prefix} ${message}`)
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
debug(message: string, data?: any): void {
|
|
36
|
-
if (process.env.NODE_ENV === "development") {
|
|
37
|
-
if (data) {
|
|
38
|
-
console.debug(`${this.prefix} ${message}`, data)
|
|
39
|
-
} else {
|
|
40
|
-
console.debug(`${this.prefix} ${message}`)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Plugin validation utilities
|
|
47
|
-
export class PluginValidator {
|
|
48
|
-
static validateMetadata(plugin: Plugin): boolean {
|
|
49
|
-
const { metadata } = plugin
|
|
50
|
-
|
|
51
|
-
if (!metadata.name || typeof metadata.name !== "string") {
|
|
52
|
-
throw new Error("Plugin metadata must include a valid name")
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (!metadata.version || typeof metadata.version !== "string") {
|
|
56
|
-
throw new Error("Plugin metadata must include a valid version")
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (!metadata.description || typeof metadata.description !== "string") {
|
|
60
|
-
throw new Error("Plugin metadata must include a valid description")
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (!metadata.category) {
|
|
64
|
-
throw new Error("Plugin metadata must include a valid category")
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (!metadata.priority) {
|
|
68
|
-
throw new Error("Plugin metadata must include a valid priority")
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return true
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
static validateConfig(config: PluginConfig, schema?: Record<string, any>): boolean {
|
|
75
|
-
if (!schema) return true
|
|
76
|
-
|
|
77
|
-
// Simple schema validation - could be enhanced with a proper schema validator
|
|
78
|
-
for (const [key, rules] of Object.entries(schema)) {
|
|
79
|
-
const value = config[key]
|
|
80
|
-
|
|
81
|
-
if (rules.required && (value === undefined || value === null)) {
|
|
82
|
-
throw new Error(`Configuration property '${key}' is required`)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (value !== undefined && rules.type && typeof value !== rules.type) {
|
|
86
|
-
throw new Error(`Configuration property '${key}' must be of type '${rules.type}'`)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (rules.enum && !rules.enum.includes(value)) {
|
|
90
|
-
throw new Error(`Configuration property '${key}' must be one of: ${rules.enum.join(", ")}`)
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (rules.min !== undefined && typeof value === "number" && value < rules.min) {
|
|
94
|
-
throw new Error(`Configuration property '${key}' must be at least ${rules.min}`)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (rules.max !== undefined && typeof value === "number" && value > rules.max) {
|
|
98
|
-
throw new Error(`Configuration property '${key}' must be at most ${rules.max}`)
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return true
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Plugin performance monitoring
|
|
107
|
-
export class PluginPerformanceMonitor {
|
|
108
|
-
private metrics = new Map<
|
|
109
|
-
string,
|
|
110
|
-
{
|
|
111
|
-
calls: number
|
|
112
|
-
totalTime: number
|
|
113
|
-
averageTime: number
|
|
114
|
-
lastCall: number
|
|
115
|
-
}
|
|
116
|
-
>()
|
|
117
|
-
|
|
118
|
-
measure<T>(pluginName: string, operation: string, fn: () => T | Promise<T>): T | Promise<T> {
|
|
119
|
-
const key = `${pluginName}.${operation}`
|
|
120
|
-
const startTime = performance.now()
|
|
121
|
-
|
|
122
|
-
const updateMetrics = () => {
|
|
123
|
-
const endTime = performance.now()
|
|
124
|
-
const duration = endTime - startTime
|
|
125
|
-
|
|
126
|
-
const existing = this.metrics.get(key) || {
|
|
127
|
-
calls: 0,
|
|
128
|
-
totalTime: 0,
|
|
129
|
-
averageTime: 0,
|
|
130
|
-
lastCall: 0
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
existing.calls++
|
|
134
|
-
existing.totalTime += duration
|
|
135
|
-
existing.averageTime = existing.totalTime / existing.calls
|
|
136
|
-
existing.lastCall = endTime
|
|
137
|
-
|
|
138
|
-
this.metrics.set(key, existing)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const result = fn()
|
|
142
|
-
|
|
143
|
-
if (result instanceof Promise) {
|
|
144
|
-
return result.then(
|
|
145
|
-
(value) => {
|
|
146
|
-
updateMetrics()
|
|
147
|
-
return value
|
|
148
|
-
},
|
|
149
|
-
(error) => {
|
|
150
|
-
updateMetrics()
|
|
151
|
-
throw error
|
|
152
|
-
}
|
|
153
|
-
)
|
|
154
|
-
} else {
|
|
155
|
-
updateMetrics()
|
|
156
|
-
return result
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
getMetrics(pluginName?: string) {
|
|
161
|
-
if (pluginName) {
|
|
162
|
-
const pluginMetrics: Record<string, any> = {}
|
|
163
|
-
for (const [key, value] of this.metrics.entries()) {
|
|
164
|
-
if (key.startsWith(`${pluginName}.`)) {
|
|
165
|
-
const operation = key.substring(pluginName.length + 1)
|
|
166
|
-
pluginMetrics[operation] = value
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
return pluginMetrics
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
return Object.fromEntries(this.metrics.entries())
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
reset(pluginName?: string): void {
|
|
176
|
-
if (pluginName) {
|
|
177
|
-
for (const key of this.metrics.keys()) {
|
|
178
|
-
if (key.startsWith(`${pluginName}.`)) {
|
|
179
|
-
this.metrics.delete(key)
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
} else {
|
|
183
|
-
this.metrics.clear()
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Plugin development helpers
|
|
189
|
-
export const PluginDevelopmentHelpers = {
|
|
190
|
-
// Create a mock plugin context for testing
|
|
191
|
-
createMockContext(): any {
|
|
192
|
-
return {
|
|
193
|
-
state: {
|
|
194
|
-
isPlaying: false,
|
|
195
|
-
currentTime: 0,
|
|
196
|
-
duration: 0,
|
|
197
|
-
volume: 1,
|
|
198
|
-
isMuted: false,
|
|
199
|
-
isLoading: false,
|
|
200
|
-
error: null
|
|
201
|
-
},
|
|
202
|
-
controls: {
|
|
203
|
-
play: () => Promise.resolve(),
|
|
204
|
-
pause: () => Promise.resolve(),
|
|
205
|
-
seek: (time: number) => Promise.resolve(),
|
|
206
|
-
setVolume: (volume: number) => Promise.resolve(),
|
|
207
|
-
mute: () => Promise.resolve(),
|
|
208
|
-
unmute: () => Promise.resolve(),
|
|
209
|
-
toggleMute: () => Promise.resolve()
|
|
210
|
-
},
|
|
211
|
-
plugins: {
|
|
212
|
-
get: () => undefined,
|
|
213
|
-
getAll: () => [],
|
|
214
|
-
isEnabled: () => false
|
|
215
|
-
},
|
|
216
|
-
emit: () => {},
|
|
217
|
-
on: () => () => {},
|
|
218
|
-
element: null,
|
|
219
|
-
logger: new ConsolePluginLogger("[MockPlugin]")
|
|
220
|
-
}
|
|
221
|
-
},
|
|
222
|
-
|
|
223
|
-
// Create a test plugin for development
|
|
224
|
-
createTestPlugin(name: string, hooks: Partial<Plugin> = {}): Plugin {
|
|
225
|
-
return {
|
|
226
|
-
metadata: {
|
|
227
|
-
name,
|
|
228
|
-
version: "1.0.0",
|
|
229
|
-
description: `Test plugin: ${name}`,
|
|
230
|
-
category: "ui",
|
|
231
|
-
priority: "medium"
|
|
232
|
-
},
|
|
233
|
-
initialize: async () => {},
|
|
234
|
-
activate: async () => {},
|
|
235
|
-
deactivate: async () => {},
|
|
236
|
-
destroy: async () => {},
|
|
237
|
-
healthCheck: () => true,
|
|
238
|
-
...hooks
|
|
239
|
-
}
|
|
240
|
-
},
|
|
241
|
-
|
|
242
|
-
// Plugin timing utilities
|
|
243
|
-
time: {
|
|
244
|
-
async: async <T>(label: string, fn: () => Promise<T>): Promise<T> => {
|
|
245
|
-
console.time(label)
|
|
246
|
-
try {
|
|
247
|
-
const result = await fn()
|
|
248
|
-
console.timeEnd(label)
|
|
249
|
-
return result
|
|
250
|
-
} catch (error) {
|
|
251
|
-
console.timeEnd(label)
|
|
252
|
-
throw error
|
|
253
|
-
}
|
|
254
|
-
},
|
|
255
|
-
|
|
256
|
-
sync: <T>(label: string, fn: () => T): T => {
|
|
257
|
-
console.time(label)
|
|
258
|
-
try {
|
|
259
|
-
const result = fn()
|
|
260
|
-
console.timeEnd(label)
|
|
261
|
-
return result
|
|
262
|
-
} catch (error) {
|
|
263
|
-
console.timeEnd(label)
|
|
264
|
-
throw error
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Plugin storage utilities for persistent data
|
|
271
|
-
export class PluginStorage {
|
|
272
|
-
private prefix: string
|
|
273
|
-
|
|
274
|
-
constructor(pluginName: string) {
|
|
275
|
-
this.prefix = `baroi-plugin-${pluginName}`
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
get<T>(key: string, defaultValue?: T): T | undefined {
|
|
279
|
-
try {
|
|
280
|
-
const item = localStorage.getItem(`${this.prefix}-${key}`)
|
|
281
|
-
return item ? (JSON.parse(item) as T) : defaultValue
|
|
282
|
-
} catch {
|
|
283
|
-
return defaultValue
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
set<T>(key: string, value: T): void {
|
|
288
|
-
try {
|
|
289
|
-
localStorage.setItem(`${this.prefix}-${key}`, JSON.stringify(value))
|
|
290
|
-
} catch (error) {
|
|
291
|
-
console.warn(`Failed to store plugin data for key: ${key}`, error)
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
remove(key: string): void {
|
|
296
|
-
try {
|
|
297
|
-
localStorage.removeItem(`${this.prefix}-${key}`)
|
|
298
|
-
} catch (error) {
|
|
299
|
-
console.warn(`Failed to remove plugin data for key: ${key}`, error)
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
clear(): void {
|
|
304
|
-
try {
|
|
305
|
-
const keys = Object.keys(localStorage).filter((key) => key.startsWith(`${this.prefix}-`))
|
|
306
|
-
keys.forEach((key) => localStorage.removeItem(key))
|
|
307
|
-
} catch (error) {
|
|
308
|
-
console.warn("Failed to clear plugin data", error)
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// Export default logger instance
|
|
314
|
-
export const defaultPluginLogger = new ConsolePluginLogger()
|
|
315
|
-
|
|
316
|
-
// Export default performance monitor instance
|
|
317
|
-
export const defaultPerformanceMonitor = new PluginPerformanceMonitor()
|
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
import React, { lazy, Suspense } from "react"
|
|
2
|
-
|
|
3
|
-
// Feature flags for progressive loading
|
|
4
|
-
export const FEATURES = {
|
|
5
|
-
SUBTITLES: "subtitles",
|
|
6
|
-
PLAYLISTS: "playlists",
|
|
7
|
-
ADVANCED_CONTROLS: "advanced_controls",
|
|
8
|
-
ANALYTICS: "analytics",
|
|
9
|
-
PICTURE_IN_PICTURE: "picture_in_picture",
|
|
10
|
-
QUALITY_SELECTOR: "quality_selector",
|
|
11
|
-
PLAYBACK_SPEED: "playback_speed",
|
|
12
|
-
CHAPTERS: "chapters",
|
|
13
|
-
THUMBNAILS: "thumbnails",
|
|
14
|
-
KEYBOARD_SHORTCUTS: "keyboard_shortcuts"
|
|
15
|
-
} as const
|
|
16
|
-
|
|
17
|
-
export type FeatureType = (typeof FEATURES)[keyof typeof FEATURES]
|
|
18
|
-
|
|
19
|
-
// Progressive loading configuration
|
|
20
|
-
export interface ProgressiveLoadingConfig {
|
|
21
|
-
enabledFeatures: FeatureType[]
|
|
22
|
-
loadingStrategy: "lazy" | "preload" | "immediate"
|
|
23
|
-
fallbackTimeout: number
|
|
24
|
-
retryAttempts: number
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const defaultProgressiveConfig: ProgressiveLoadingConfig = {
|
|
28
|
-
enabledFeatures: [FEATURES.SUBTITLES, FEATURES.ADVANCED_CONTROLS, FEATURES.KEYBOARD_SHORTCUTS],
|
|
29
|
-
loadingStrategy: "lazy",
|
|
30
|
-
fallbackTimeout: 5000,
|
|
31
|
-
retryAttempts: 3
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Dynamic imports with error handling and retry logic
|
|
35
|
-
export const lazyComponents = {
|
|
36
|
-
// Subtitle system
|
|
37
|
-
SubtitleSelector: lazy(() =>
|
|
38
|
-
import("../components/enhanced/advanced-features").then((module) => ({
|
|
39
|
-
default: module.SubtitleSelector
|
|
40
|
-
}))
|
|
41
|
-
),
|
|
42
|
-
|
|
43
|
-
// Playlist functionality
|
|
44
|
-
PlaylistManager: lazy(
|
|
45
|
-
() =>
|
|
46
|
-
import("../components/enhanced/advanced-features").then((module) => ({
|
|
47
|
-
default: module.SubtitleSelector
|
|
48
|
-
})) // Use existing component as placeholder
|
|
49
|
-
),
|
|
50
|
-
|
|
51
|
-
// Advanced controls
|
|
52
|
-
QualitySelector: lazy(() =>
|
|
53
|
-
import("../components/enhanced/advanced-features").then((module) => ({
|
|
54
|
-
default: module.QualitySelector
|
|
55
|
-
}))
|
|
56
|
-
),
|
|
57
|
-
|
|
58
|
-
PlaybackSpeedSelector: lazy(() =>
|
|
59
|
-
import("../components/enhanced/advanced-features").then((module) => ({
|
|
60
|
-
default: module.PlaybackSpeedSelector
|
|
61
|
-
}))
|
|
62
|
-
),
|
|
63
|
-
|
|
64
|
-
ChaptersPanel: lazy(() =>
|
|
65
|
-
import("../components/enhanced/advanced-features").then((module) => ({
|
|
66
|
-
default: module.ChaptersPanel
|
|
67
|
-
}))
|
|
68
|
-
),
|
|
69
|
-
|
|
70
|
-
PictureInPictureButton: lazy(() =>
|
|
71
|
-
import("../components/enhanced/advanced-features").then((module) => ({
|
|
72
|
-
default: module.PictureInPictureButton
|
|
73
|
-
}))
|
|
74
|
-
),
|
|
75
|
-
|
|
76
|
-
// Analytics
|
|
77
|
-
AnalyticsTracker: lazy(
|
|
78
|
-
() =>
|
|
79
|
-
import("../components/enhanced/advanced-features").then((module) => ({
|
|
80
|
-
default: module.SubtitleSelector
|
|
81
|
-
})) // Use existing component as placeholder
|
|
82
|
-
)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Feature detection utilities
|
|
86
|
-
export class FeatureDetector {
|
|
87
|
-
private static cache = new Map<FeatureType, boolean>()
|
|
88
|
-
|
|
89
|
-
static async isSupported(feature: FeatureType): Promise<boolean> {
|
|
90
|
-
if (this.cache.has(feature)) {
|
|
91
|
-
return this.cache.get(feature)!
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const supported = await this.checkFeatureSupport(feature)
|
|
95
|
-
this.cache.set(feature, supported)
|
|
96
|
-
return supported
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
private static async checkFeatureSupport(feature: FeatureType): Promise<boolean> {
|
|
100
|
-
if (typeof window === "undefined" || typeof document === "undefined") {
|
|
101
|
-
// Server-side rendering - assume basic support
|
|
102
|
-
return true
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
switch (feature) {
|
|
106
|
-
case FEATURES.SUBTITLES:
|
|
107
|
-
return "TextTrack" in window
|
|
108
|
-
|
|
109
|
-
case FEATURES.PICTURE_IN_PICTURE:
|
|
110
|
-
return "pictureInPictureEnabled" in document
|
|
111
|
-
|
|
112
|
-
case FEATURES.ADVANCED_CONTROLS:
|
|
113
|
-
return true // Always supported
|
|
114
|
-
|
|
115
|
-
case FEATURES.PLAYLISTS:
|
|
116
|
-
return "MediaSession" in window
|
|
117
|
-
|
|
118
|
-
case FEATURES.ANALYTICS:
|
|
119
|
-
return "IntersectionObserver" in window
|
|
120
|
-
|
|
121
|
-
case FEATURES.QUALITY_SELECTOR:
|
|
122
|
-
return "MediaSource" in window
|
|
123
|
-
|
|
124
|
-
case FEATURES.PLAYBACK_SPEED:
|
|
125
|
-
return true // HTML5 video supports this
|
|
126
|
-
|
|
127
|
-
case FEATURES.CHAPTERS:
|
|
128
|
-
return "TextTrack" in window
|
|
129
|
-
|
|
130
|
-
case FEATURES.THUMBNAILS:
|
|
131
|
-
return "OffscreenCanvas" in window || "canvas" in document.createElement("canvas")
|
|
132
|
-
|
|
133
|
-
case FEATURES.KEYBOARD_SHORTCUTS:
|
|
134
|
-
return "KeyboardEvent" in window
|
|
135
|
-
|
|
136
|
-
default:
|
|
137
|
-
return false
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Progressive loading manager
|
|
143
|
-
export class ProgressiveLoader {
|
|
144
|
-
private config: ProgressiveLoadingConfig
|
|
145
|
-
private loadedFeatures = new Set<FeatureType>()
|
|
146
|
-
private loadingPromises = new Map<FeatureType, Promise<any>>()
|
|
147
|
-
|
|
148
|
-
constructor(config: Partial<ProgressiveLoadingConfig> = {}) {
|
|
149
|
-
this.config = { ...defaultProgressiveConfig, ...config }
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
async loadFeature<T = any>(feature: FeatureType): Promise<T | null> {
|
|
153
|
-
// Check if feature is enabled
|
|
154
|
-
if (!this.config.enabledFeatures.includes(feature)) {
|
|
155
|
-
return null
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Check if already loaded
|
|
159
|
-
if (this.loadedFeatures.has(feature)) {
|
|
160
|
-
return this.getLoadedFeature(feature)
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// Check if currently loading
|
|
164
|
-
if (this.loadingPromises.has(feature)) {
|
|
165
|
-
return this.loadingPromises.get(feature)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Check browser support
|
|
169
|
-
const isSupported = await FeatureDetector.isSupported(feature)
|
|
170
|
-
if (!isSupported) {
|
|
171
|
-
console.warn(`Feature ${feature} is not supported in this browser`)
|
|
172
|
-
return null
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Start loading with retry logic
|
|
176
|
-
const loadingPromise = this.loadWithRetry(feature)
|
|
177
|
-
this.loadingPromises.set(feature, loadingPromise)
|
|
178
|
-
|
|
179
|
-
try {
|
|
180
|
-
const result = await loadingPromise
|
|
181
|
-
this.loadedFeatures.add(feature)
|
|
182
|
-
return result as T
|
|
183
|
-
} catch (error) {
|
|
184
|
-
console.error(`Failed to load feature ${feature}:`, error)
|
|
185
|
-
this.loadingPromises.delete(feature)
|
|
186
|
-
return null
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
private async loadWithRetry<T>(feature: FeatureType, attempt = 1): Promise<T> {
|
|
191
|
-
try {
|
|
192
|
-
const result = await this.loadFeatureModule(feature)
|
|
193
|
-
return result as T
|
|
194
|
-
} catch (error) {
|
|
195
|
-
if (attempt < this.config.retryAttempts) {
|
|
196
|
-
console.warn(
|
|
197
|
-
`Loading feature ${feature} failed, retrying (${attempt}/${this.config.retryAttempts})`
|
|
198
|
-
)
|
|
199
|
-
await new Promise((resolve) => setTimeout(resolve, 1000 * attempt))
|
|
200
|
-
return this.loadWithRetry(feature, attempt + 1)
|
|
201
|
-
}
|
|
202
|
-
throw error
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
private async loadFeatureModule(feature: FeatureType) {
|
|
207
|
-
switch (feature) {
|
|
208
|
-
case FEATURES.SUBTITLES:
|
|
209
|
-
return import("../hooks/useEnhancedSubtitles")
|
|
210
|
-
|
|
211
|
-
case FEATURES.PLAYLISTS:
|
|
212
|
-
return import("../components/enhanced/advanced-features") // Use existing features
|
|
213
|
-
|
|
214
|
-
case FEATURES.ADVANCED_CONTROLS:
|
|
215
|
-
return import("../components/enhanced/advanced-features")
|
|
216
|
-
|
|
217
|
-
case FEATURES.ANALYTICS:
|
|
218
|
-
return import("../components/enhanced/advanced-features") // Use existing features
|
|
219
|
-
|
|
220
|
-
case FEATURES.PICTURE_IN_PICTURE:
|
|
221
|
-
return import("../components/enhanced/advanced-features") // Use existing features
|
|
222
|
-
|
|
223
|
-
case FEATURES.QUALITY_SELECTOR:
|
|
224
|
-
return import("../components/enhanced/advanced-features") // Use existing features
|
|
225
|
-
|
|
226
|
-
case FEATURES.PLAYBACK_SPEED:
|
|
227
|
-
return import("../components/enhanced/advanced-features") // Use existing features
|
|
228
|
-
|
|
229
|
-
case FEATURES.CHAPTERS:
|
|
230
|
-
return import("../components/enhanced/advanced-features") // Use existing features
|
|
231
|
-
|
|
232
|
-
case FEATURES.THUMBNAILS:
|
|
233
|
-
return import("../components/enhanced/advanced-features") // Use existing features
|
|
234
|
-
|
|
235
|
-
case FEATURES.KEYBOARD_SHORTCUTS:
|
|
236
|
-
return import("../hooks/use-keyboard-controls")
|
|
237
|
-
|
|
238
|
-
default:
|
|
239
|
-
throw new Error(`Unknown feature: ${feature}`)
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
private getLoadedFeature(feature: FeatureType) {
|
|
244
|
-
// Return cached feature instance
|
|
245
|
-
return this.loadingPromises.get(feature)
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// Preload features for faster access
|
|
249
|
-
async preloadFeatures(features: FeatureType[] = this.config.enabledFeatures) {
|
|
250
|
-
const preloadPromises = features.map((feature) => this.loadFeature(feature))
|
|
251
|
-
await Promise.allSettled(preloadPromises)
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// Get loading state
|
|
255
|
-
getLoadingState() {
|
|
256
|
-
return {
|
|
257
|
-
loaded: Array.from(this.loadedFeatures),
|
|
258
|
-
loading: Array.from(this.loadingPromises.keys()),
|
|
259
|
-
enabled: this.config.enabledFeatures
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Global progressive loader instance
|
|
265
|
-
export const progressiveLoader = new ProgressiveLoader()
|
|
266
|
-
|
|
267
|
-
// React hook for progressive loading
|
|
268
|
-
export function useProgressiveFeature<T = any>(
|
|
269
|
-
feature: FeatureType
|
|
270
|
-
): {
|
|
271
|
-
feature: T | null
|
|
272
|
-
loading: boolean
|
|
273
|
-
error: Error | null
|
|
274
|
-
load: () => Promise<void>
|
|
275
|
-
} {
|
|
276
|
-
const [featureModule, setFeatureModule] = React.useState<T | null>(null)
|
|
277
|
-
const [loading, setLoading] = React.useState(false)
|
|
278
|
-
const [error, setError] = React.useState<Error | null>(null)
|
|
279
|
-
|
|
280
|
-
const load = React.useCallback(async () => {
|
|
281
|
-
if (loading || featureModule) return
|
|
282
|
-
|
|
283
|
-
setLoading(true)
|
|
284
|
-
setError(null)
|
|
285
|
-
|
|
286
|
-
try {
|
|
287
|
-
const module = await progressiveLoader.loadFeature<T>(feature)
|
|
288
|
-
setFeatureModule(module)
|
|
289
|
-
} catch (err) {
|
|
290
|
-
setError(err as Error)
|
|
291
|
-
} finally {
|
|
292
|
-
setLoading(false)
|
|
293
|
-
}
|
|
294
|
-
}, [feature, loading, featureModule])
|
|
295
|
-
|
|
296
|
-
// Auto-load if strategy is immediate
|
|
297
|
-
React.useEffect(() => {
|
|
298
|
-
if (progressiveLoader["config"].loadingStrategy === "immediate") {
|
|
299
|
-
load()
|
|
300
|
-
}
|
|
301
|
-
}, [load])
|
|
302
|
-
|
|
303
|
-
return {
|
|
304
|
-
feature: featureModule,
|
|
305
|
-
loading,
|
|
306
|
-
error,
|
|
307
|
-
load
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// HOC for progressive feature loading
|
|
312
|
-
export function withProgressiveFeature<P extends object>(
|
|
313
|
-
WrappedComponent: React.ComponentType<P>,
|
|
314
|
-
feature: FeatureType,
|
|
315
|
-
fallback?: React.ComponentType<P>
|
|
316
|
-
) {
|
|
317
|
-
return function ProgressiveFeatureWrapper(props: P) {
|
|
318
|
-
const { feature: featureModule, loading, error } = useProgressiveFeature(feature)
|
|
319
|
-
|
|
320
|
-
if (loading) {
|
|
321
|
-
return <div className="h-8 animate-pulse rounded bg-gray-200" />
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (error || !featureModule) {
|
|
325
|
-
const Fallback = fallback
|
|
326
|
-
return Fallback ? <Fallback {...props} /> : null
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return <WrappedComponent {...props} />
|
|
330
|
-
}
|
|
331
|
-
}
|