@djangocfg/ui-nextjs 2.1.66 → 2.1.68

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 (90) hide show
  1. package/package.json +8 -6
  2. package/src/stores/index.ts +8 -0
  3. package/src/stores/mediaCache.ts +474 -0
  4. package/src/tools/AudioPlayer/@refactoring/00-PLAN.md +148 -0
  5. package/src/tools/AudioPlayer/@refactoring/01-TYPES.md +301 -0
  6. package/src/tools/AudioPlayer/@refactoring/02-HOOKS.md +281 -0
  7. package/src/tools/AudioPlayer/@refactoring/03-CONTEXT.md +328 -0
  8. package/src/tools/AudioPlayer/@refactoring/04-COMPONENTS.md +251 -0
  9. package/src/tools/AudioPlayer/@refactoring/05-EFFECTS.md +427 -0
  10. package/src/tools/AudioPlayer/@refactoring/06-UTILS-AND-INDEX.md +193 -0
  11. package/src/tools/AudioPlayer/@refactoring/07-EXECUTION-CHECKLIST.md +146 -0
  12. package/src/tools/AudioPlayer/README.md +35 -11
  13. package/src/tools/AudioPlayer/{AudioEqualizer.tsx → components/AudioEqualizer.tsx} +29 -64
  14. package/src/tools/AudioPlayer/{AudioPlayer.tsx → components/AudioPlayer.tsx} +22 -14
  15. package/src/tools/AudioPlayer/{AudioShortcutsPopover.tsx → components/AudioShortcutsPopover.tsx} +6 -2
  16. package/src/tools/AudioPlayer/components/ReactiveCover/AudioReactiveCover.tsx +147 -0
  17. package/src/tools/AudioPlayer/components/ReactiveCover/effects/GlowEffect.tsx +110 -0
  18. package/src/tools/AudioPlayer/components/ReactiveCover/effects/MeshEffect.tsx +58 -0
  19. package/src/tools/AudioPlayer/components/ReactiveCover/effects/OrbsEffect.tsx +45 -0
  20. package/src/tools/AudioPlayer/components/ReactiveCover/effects/SpotlightEffect.tsx +82 -0
  21. package/src/tools/AudioPlayer/components/ReactiveCover/effects/index.ts +8 -0
  22. package/src/tools/AudioPlayer/components/ReactiveCover/index.ts +6 -0
  23. package/src/tools/AudioPlayer/{SimpleAudioPlayer.tsx → components/SimpleAudioPlayer.tsx} +12 -7
  24. package/src/tools/AudioPlayer/{VisualizationToggle.tsx → components/VisualizationToggle.tsx} +2 -6
  25. package/src/tools/AudioPlayer/components/index.ts +21 -0
  26. package/src/tools/AudioPlayer/context/AudioProvider.tsx +292 -0
  27. package/src/tools/AudioPlayer/context/index.ts +11 -0
  28. package/src/tools/AudioPlayer/context/selectors.ts +96 -0
  29. package/src/tools/AudioPlayer/hooks/index.ts +29 -0
  30. package/src/tools/AudioPlayer/hooks/useAudioAnalysis.ts +110 -0
  31. package/src/tools/AudioPlayer/{useAudioHotkeys.ts → hooks/useAudioHotkeys.ts} +11 -4
  32. package/src/tools/AudioPlayer/hooks/useSharedWebAudio.ts +106 -0
  33. package/src/tools/AudioPlayer/{useAudioVisualization.tsx → hooks/useVisualization.tsx} +11 -5
  34. package/src/tools/AudioPlayer/index.ts +104 -49
  35. package/src/tools/AudioPlayer/types/audio.ts +107 -0
  36. package/src/tools/AudioPlayer/{types.ts → types/components.ts} +20 -84
  37. package/src/tools/AudioPlayer/types/effects.ts +73 -0
  38. package/src/tools/AudioPlayer/types/index.ts +35 -0
  39. package/src/tools/AudioPlayer/utils/formatTime.ts +10 -0
  40. package/src/tools/AudioPlayer/utils/index.ts +5 -0
  41. package/src/tools/ImageViewer/@refactoring/00-PLAN.md +71 -0
  42. package/src/tools/ImageViewer/@refactoring/01-TYPES.md +121 -0
  43. package/src/tools/ImageViewer/@refactoring/02-UTILS.md +143 -0
  44. package/src/tools/ImageViewer/@refactoring/03-HOOKS.md +261 -0
  45. package/src/tools/ImageViewer/@refactoring/04-COMPONENTS.md +427 -0
  46. package/src/tools/ImageViewer/@refactoring/05-EXECUTION-CHECKLIST.md +126 -0
  47. package/src/tools/ImageViewer/README.md +16 -3
  48. package/src/tools/ImageViewer/components/ImageInfo.tsx +44 -0
  49. package/src/tools/ImageViewer/components/ImageToolbar.tsx +150 -0
  50. package/src/tools/ImageViewer/components/ImageViewer.tsx +235 -0
  51. package/src/tools/ImageViewer/components/index.ts +7 -0
  52. package/src/tools/ImageViewer/hooks/index.ts +9 -0
  53. package/src/tools/ImageViewer/hooks/useImageLoading.ts +153 -0
  54. package/src/tools/ImageViewer/hooks/useImageTransform.ts +101 -0
  55. package/src/tools/ImageViewer/index.ts +47 -3
  56. package/src/tools/ImageViewer/types.ts +75 -0
  57. package/src/tools/ImageViewer/utils/constants.ts +59 -0
  58. package/src/tools/ImageViewer/utils/index.ts +16 -0
  59. package/src/tools/ImageViewer/utils/lqip.ts +47 -0
  60. package/src/tools/VideoPlayer/@refactoring/00-PLAN.md +91 -0
  61. package/src/tools/VideoPlayer/@refactoring/01-TYPES.md +284 -0
  62. package/src/tools/VideoPlayer/@refactoring/02-UTILS.md +141 -0
  63. package/src/tools/VideoPlayer/@refactoring/03-HOOKS.md +178 -0
  64. package/src/tools/VideoPlayer/@refactoring/04-COMPONENTS.md +95 -0
  65. package/src/tools/VideoPlayer/@refactoring/05-EXECUTION-CHECKLIST.md +139 -0
  66. package/src/tools/VideoPlayer/README.md +26 -10
  67. package/src/tools/VideoPlayer/{VideoControls.tsx → components/VideoControls.tsx} +8 -9
  68. package/src/tools/VideoPlayer/{VideoErrorFallback.tsx → components/VideoErrorFallback.tsx} +2 -2
  69. package/src/tools/VideoPlayer/{VideoPlayer.tsx → components/VideoPlayer.tsx} +4 -5
  70. package/src/tools/VideoPlayer/components/index.ts +14 -0
  71. package/src/tools/VideoPlayer/context/VideoPlayerContext.tsx +52 -0
  72. package/src/tools/VideoPlayer/context/index.ts +8 -0
  73. package/src/tools/VideoPlayer/hooks/index.ts +9 -0
  74. package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +109 -0
  75. package/src/tools/VideoPlayer/index.ts +29 -20
  76. package/src/tools/VideoPlayer/providers/StreamProvider.tsx +118 -28
  77. package/src/tools/VideoPlayer/providers/VidstackProvider.tsx +89 -11
  78. package/src/tools/VideoPlayer/types/index.ts +38 -0
  79. package/src/tools/VideoPlayer/types/player.ts +116 -0
  80. package/src/tools/VideoPlayer/types/provider.ts +93 -0
  81. package/src/tools/VideoPlayer/types/sources.ts +97 -0
  82. package/src/tools/VideoPlayer/utils/fileSource.ts +78 -0
  83. package/src/tools/VideoPlayer/utils/index.ts +11 -0
  84. package/src/tools/VideoPlayer/utils/resolvers.ts +75 -0
  85. package/src/tools/index.ts +10 -0
  86. package/src/tools/AudioPlayer/AudioReactiveCover.tsx +0 -389
  87. package/src/tools/AudioPlayer/context.tsx +0 -426
  88. package/src/tools/ImageViewer/ImageViewer.tsx +0 -416
  89. package/src/tools/VideoPlayer/VideoPlayerContext.tsx +0 -125
  90. package/src/tools/VideoPlayer/types.ts +0 -367
@@ -0,0 +1,141 @@
1
+ # Phase 2: Utils Extraction
2
+
3
+ ## Goal
4
+
5
+ Extract helper functions from types.ts into dedicated utils files.
6
+
7
+ ## Files to Create
8
+
9
+ ### utils/resolvers.ts
10
+
11
+ Player mode and source resolution:
12
+
13
+ ```typescript
14
+ /**
15
+ * Video source and player mode resolvers
16
+ */
17
+
18
+ import type { VideoSourceUnion, PlayerMode, SimpleStreamSource, StreamSource } from '../types';
19
+
20
+ /**
21
+ * Determine the appropriate player mode for a given source
22
+ */
23
+ export function resolvePlayerMode(source: VideoSourceUnion): PlayerMode {
24
+ switch (source.type) {
25
+ case 'youtube':
26
+ case 'vimeo':
27
+ case 'hls':
28
+ case 'dash':
29
+ return 'vidstack';
30
+ case 'stream':
31
+ case 'blob':
32
+ case 'data-url':
33
+ return 'streaming';
34
+ case 'url':
35
+ default:
36
+ return 'native';
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Check if source is a simple stream (needs context resolution)
42
+ */
43
+ export function isSimpleStreamSource(
44
+ source: VideoSourceUnion
45
+ ): source is SimpleStreamSource {
46
+ return (
47
+ source.type === 'stream' &&
48
+ !('getStreamUrl' in source)
49
+ );
50
+ }
51
+
52
+ /**
53
+ * Resolve simple stream source with context getStreamUrl
54
+ */
55
+ export function resolveStreamSource(
56
+ source: SimpleStreamSource,
57
+ getStreamUrl: (streamKey: string) => Promise<string>
58
+ ): StreamSource {
59
+ return {
60
+ ...source,
61
+ getStreamUrl,
62
+ };
63
+ }
64
+ ```
65
+
66
+ ### utils/fileSource.ts
67
+
68
+ File content to source conversion:
69
+
70
+ ```typescript
71
+ /**
72
+ * File source resolution utilities
73
+ */
74
+
75
+ import type { VideoSourceUnion, ResolveFileSourceOptions } from '../types';
76
+
77
+ /**
78
+ * Convert file content to appropriate VideoSource
79
+ */
80
+ export function resolveFileSource(options: ResolveFileSourceOptions): VideoSourceUnion {
81
+ const { fileName, content, mimeType } = options;
82
+
83
+ // Data URL string
84
+ if (typeof content === 'string' && content.startsWith('data:')) {
85
+ return {
86
+ type: 'data-url',
87
+ dataUrl: content,
88
+ mimeType,
89
+ };
90
+ }
91
+
92
+ // Regular URL string
93
+ if (typeof content === 'string') {
94
+ return {
95
+ type: 'url',
96
+ url: content,
97
+ mimeType,
98
+ };
99
+ }
100
+
101
+ // ArrayBuffer -> Blob source
102
+ return {
103
+ type: 'blob',
104
+ data: content,
105
+ mimeType: mimeType || guessMimeType(fileName),
106
+ fileName,
107
+ };
108
+ }
109
+
110
+ /**
111
+ * Guess MIME type from file extension
112
+ */
113
+ function guessMimeType(fileName: string): string {
114
+ const ext = fileName.split('.').pop()?.toLowerCase();
115
+ const mimeTypes: Record<string, string> = {
116
+ mp4: 'video/mp4',
117
+ webm: 'video/webm',
118
+ ogg: 'video/ogg',
119
+ mov: 'video/quicktime',
120
+ avi: 'video/x-msvideo',
121
+ mkv: 'video/x-matroska',
122
+ };
123
+ return mimeTypes[ext || ''] || 'video/mp4';
124
+ }
125
+ ```
126
+
127
+ ### utils/index.ts
128
+
129
+ ```typescript
130
+ /**
131
+ * VideoPlayer utilities - Public API
132
+ */
133
+
134
+ export {
135
+ resolvePlayerMode,
136
+ isSimpleStreamSource,
137
+ resolveStreamSource,
138
+ } from './resolvers';
139
+
140
+ export { resolveFileSource } from './fileSource';
141
+ ```
@@ -0,0 +1,178 @@
1
+ # Phase 3: Hooks Extraction
2
+
3
+ ## Goal
4
+
5
+ Extract duplicated video position caching logic into a reusable hook.
6
+
7
+ ## Current Duplication
8
+
9
+ The position caching pattern is duplicated in:
10
+ 1. `VidstackProvider.tsx` (lines ~180-220)
11
+ 2. `StreamProvider.tsx` (lines ~200-240)
12
+
13
+ Both implement:
14
+ - Save position every 5 seconds during playback
15
+ - Restore position when video loads (canPlay)
16
+ - Clear position when video ends
17
+
18
+ ## File to Create
19
+
20
+ ### hooks/useVideoPositionCache.ts
21
+
22
+ ```typescript
23
+ 'use client';
24
+
25
+ /**
26
+ * useVideoPositionCache - Manages video playback position caching
27
+ *
28
+ * Saves position periodically during playback and restores on load.
29
+ */
30
+
31
+ import { useRef, useEffect, useCallback } from 'react';
32
+ import { useVideoCache } from '../../../stores/mediaCache';
33
+
34
+ // =============================================================================
35
+ // TYPES
36
+ // =============================================================================
37
+
38
+ export interface UseVideoPositionCacheOptions {
39
+ /** Unique key for caching (e.g., video URL or stream key) */
40
+ cacheKey: string;
41
+ /** Current playback time in seconds */
42
+ currentTime: number;
43
+ /** Video duration in seconds */
44
+ duration: number;
45
+ /** Whether video is currently playing */
46
+ isPlaying: boolean;
47
+ /** Whether video is ready to play */
48
+ isReady: boolean;
49
+ /** Callback to seek to a specific time */
50
+ onSeek: (time: number) => void;
51
+ }
52
+
53
+ export interface UseVideoPositionCacheReturn {
54
+ /** Manually save current position */
55
+ savePosition: () => void;
56
+ /** Clear saved position */
57
+ clearPosition: () => void;
58
+ }
59
+
60
+ // =============================================================================
61
+ // CONSTANTS
62
+ // =============================================================================
63
+
64
+ /** Save interval in seconds */
65
+ const SAVE_INTERVAL = 5;
66
+
67
+ /** Minimum position to restore (avoid 0 or near-end) */
68
+ const MIN_RESTORE_POSITION = 1;
69
+
70
+ // =============================================================================
71
+ // HOOK
72
+ // =============================================================================
73
+
74
+ export function useVideoPositionCache(
75
+ options: UseVideoPositionCacheOptions
76
+ ): UseVideoPositionCacheReturn {
77
+ const { cacheKey, currentTime, duration, isPlaying, isReady, onSeek } = options;
78
+
79
+ const { saveVideoPosition, getVideoPosition } = useVideoCache();
80
+ const lastSavedTimeRef = useRef<number>(0);
81
+ const hasRestoredRef = useRef<boolean>(false);
82
+
83
+ // Restore position when ready
84
+ useEffect(() => {
85
+ if (!isReady || !cacheKey || hasRestoredRef.current) return;
86
+
87
+ const savedPosition = getVideoPosition(cacheKey);
88
+ if (savedPosition && savedPosition > MIN_RESTORE_POSITION && savedPosition < duration - 1) {
89
+ onSeek(savedPosition);
90
+ }
91
+ hasRestoredRef.current = true;
92
+ }, [isReady, cacheKey, duration, getVideoPosition, onSeek]);
93
+
94
+ // Reset restored flag when cache key changes
95
+ useEffect(() => {
96
+ hasRestoredRef.current = false;
97
+ lastSavedTimeRef.current = 0;
98
+ }, [cacheKey]);
99
+
100
+ // Save position periodically during playback
101
+ useEffect(() => {
102
+ if (!cacheKey || !isPlaying || currentTime <= 0) return;
103
+
104
+ const timeSinceLastSave = currentTime - lastSavedTimeRef.current;
105
+ if (timeSinceLastSave >= SAVE_INTERVAL || timeSinceLastSave < 0) {
106
+ saveVideoPosition(cacheKey, currentTime);
107
+ lastSavedTimeRef.current = currentTime;
108
+ }
109
+ }, [cacheKey, isPlaying, currentTime, saveVideoPosition]);
110
+
111
+ // Save position on pause
112
+ useEffect(() => {
113
+ if (!cacheKey || isPlaying || currentTime <= 0) return;
114
+
115
+ saveVideoPosition(cacheKey, currentTime);
116
+ lastSavedTimeRef.current = currentTime;
117
+ }, [cacheKey, isPlaying, currentTime, saveVideoPosition]);
118
+
119
+ const savePosition = useCallback(() => {
120
+ if (cacheKey && currentTime > 0) {
121
+ saveVideoPosition(cacheKey, currentTime);
122
+ }
123
+ }, [cacheKey, currentTime, saveVideoPosition]);
124
+
125
+ const clearPosition = useCallback(() => {
126
+ if (cacheKey) {
127
+ saveVideoPosition(cacheKey, 0);
128
+ }
129
+ }, [cacheKey, saveVideoPosition]);
130
+
131
+ return {
132
+ savePosition,
133
+ clearPosition,
134
+ };
135
+ }
136
+ ```
137
+
138
+ ### hooks/index.ts
139
+
140
+ ```typescript
141
+ /**
142
+ * VideoPlayer hooks - Public API
143
+ */
144
+
145
+ export { useVideoPositionCache } from './useVideoPositionCache';
146
+ export type {
147
+ UseVideoPositionCacheOptions,
148
+ UseVideoPositionCacheReturn,
149
+ } from './useVideoPositionCache';
150
+ ```
151
+
152
+ ## Usage in Providers
153
+
154
+ After extraction, providers can use:
155
+
156
+ ```typescript
157
+ // In VidstackProvider.tsx
158
+ const { clearPosition } = useVideoPositionCache({
159
+ cacheKey: sourceKey,
160
+ currentTime: player?.currentTime ?? 0,
161
+ duration: player?.duration ?? 0,
162
+ isPlaying: !paused,
163
+ isReady: canPlay,
164
+ onSeek: (time) => player?.currentTime = time,
165
+ });
166
+
167
+ // Clear on video end
168
+ useEffect(() => {
169
+ if (ended) clearPosition();
170
+ }, [ended, clearPosition]);
171
+ ```
172
+
173
+ ## Benefits
174
+
175
+ 1. **DRY** - Single source of truth for position caching logic
176
+ 2. **Testable** - Hook can be unit tested independently
177
+ 3. **Reusable** - Can be used in future video components
178
+ 4. **Maintainable** - Changes only need to be made in one place
@@ -0,0 +1,95 @@
1
+ # Phase 4: Components Organization
2
+
3
+ ## Goal
4
+
5
+ Move standalone components to a dedicated `components/` folder for consistency.
6
+
7
+ ## Current Location
8
+
9
+ ```
10
+ VideoPlayer/
11
+ ├── VideoPlayer.tsx # Main orchestrator
12
+ ├── VideoControls.tsx # Vidstack controls
13
+ ├── VideoErrorFallback.tsx # Error UI
14
+ └── providers/ # Provider implementations
15
+ ```
16
+
17
+ ## Target Location
18
+
19
+ ```
20
+ VideoPlayer/
21
+ ├── components/
22
+ │ ├── index.ts
23
+ │ ├── VideoPlayer.tsx
24
+ │ ├── VideoControls.tsx
25
+ │ └── VideoErrorFallback.tsx
26
+ └── providers/ # Unchanged
27
+ ```
28
+
29
+ ## Files to Create
30
+
31
+ ### components/index.ts
32
+
33
+ ```typescript
34
+ /**
35
+ * VideoPlayer components - Public API
36
+ */
37
+
38
+ export { VideoPlayer } from './VideoPlayer';
39
+ export { VideoControls } from './VideoControls';
40
+ export {
41
+ VideoErrorFallback,
42
+ createVideoErrorFallback,
43
+ } from './VideoErrorFallback';
44
+ ```
45
+
46
+ ## Component Updates
47
+
48
+ ### VideoPlayer.tsx
49
+
50
+ Update imports to use new paths:
51
+
52
+ ```typescript
53
+ // Before
54
+ import { VidstackProvider } from './providers';
55
+ import { NativeProvider } from './providers';
56
+ import { StreamProvider } from './providers';
57
+ import { resolvePlayerMode, isSimpleStreamSource, resolveStreamSource } from './types';
58
+ import { useVideoPlayerContext } from './VideoPlayerContext';
59
+
60
+ // After
61
+ import { VidstackProvider, NativeProvider, StreamProvider } from '../providers';
62
+ import { resolvePlayerMode, isSimpleStreamSource, resolveStreamSource } from '../utils';
63
+ import { useVideoPlayerContext } from '../context';
64
+ ```
65
+
66
+ ### VideoControls.tsx
67
+
68
+ Update imports:
69
+
70
+ ```typescript
71
+ // Before
72
+ import type { ... } from './types';
73
+
74
+ // After
75
+ import type { ... } from '../types';
76
+ ```
77
+
78
+ ### VideoErrorFallback.tsx
79
+
80
+ Update imports:
81
+
82
+ ```typescript
83
+ // Before
84
+ import type { ErrorFallbackProps } from './types';
85
+
86
+ // After
87
+ import type { ErrorFallbackProps } from '../types';
88
+ ```
89
+
90
+ ## Notes
91
+
92
+ - VideoPlayer.tsx is the main entry point, moved to components/
93
+ - Providers stay in their own folder (already well-organized)
94
+ - Context moves to context/ folder
95
+ - All imports updated to reflect new structure
@@ -0,0 +1,139 @@
1
+ # Execution Checklist
2
+
3
+ ## Pre-flight
4
+
5
+ - [ ] Read all current files
6
+ - [ ] Backup or rename original files
7
+ - [ ] Create folder structure
8
+
9
+ ## Phase 1: Folder Structure
10
+
11
+ ```bash
12
+ cd src/tools/VideoPlayer
13
+ mkdir -p types hooks utils components context
14
+ ```
15
+
16
+ - [ ] Create `types/` directory
17
+ - [ ] Create `hooks/` directory
18
+ - [ ] Create `utils/` directory
19
+ - [ ] Create `components/` directory
20
+ - [ ] Create `context/` directory
21
+
22
+ ## Phase 2: Types
23
+
24
+ - [ ] Create `types/sources.ts` - Source type definitions
25
+ - [ ] Create `types/player.ts` - Player config and main types
26
+ - [ ] Create `types/provider.ts` - Provider-specific types
27
+ - [ ] Create `types/index.ts` - Re-exports
28
+ - [ ] Run `pnpm check`
29
+
30
+ ## Phase 3: Utils
31
+
32
+ - [ ] Create `utils/resolvers.ts` - resolvePlayerMode, isSimpleStreamSource
33
+ - [ ] Create `utils/fileSource.ts` - resolveFileSource
34
+ - [ ] Create `utils/index.ts` - Re-exports
35
+ - [ ] Run `pnpm check`
36
+
37
+ ## Phase 4: Hooks
38
+
39
+ - [ ] Create `hooks/useVideoPositionCache.ts` - Position caching logic
40
+ - [ ] Create `hooks/index.ts` - Re-exports
41
+ - [ ] Run `pnpm check`
42
+
43
+ ## Phase 5: Components
44
+
45
+ - [ ] Move `VideoPlayer.tsx` to `components/`
46
+ - [ ] Move `VideoControls.tsx` to `components/`
47
+ - [ ] Move `VideoErrorFallback.tsx` to `components/`
48
+ - [ ] Create `components/index.ts`
49
+ - [ ] Update imports in all moved files
50
+ - [ ] Run `pnpm check`
51
+
52
+ ## Phase 6: Context
53
+
54
+ - [ ] Move `VideoPlayerContext.tsx` to `context/`
55
+ - [ ] Create `context/index.ts`
56
+ - [ ] Update imports
57
+ - [ ] Run `pnpm check`
58
+
59
+ ## Phase 7: Update Providers
60
+
61
+ - [ ] Update imports in `VidstackProvider.tsx`
62
+ - [ ] Update imports in `NativeProvider.tsx`
63
+ - [ ] Update imports in `StreamProvider.tsx`
64
+ - [ ] Optionally integrate `useVideoPositionCache` hook
65
+ - [ ] Run `pnpm check`
66
+
67
+ ## Phase 8: Main Index
68
+
69
+ - [ ] Update `index.ts` with new imports
70
+ - [ ] Verify all exports work
71
+ - [ ] Run `pnpm check`
72
+
73
+ ## Phase 9: Cleanup
74
+
75
+ - [ ] Delete old `types.ts`
76
+ - [ ] Delete old `VideoPlayer.tsx`
77
+ - [ ] Delete old `VideoControls.tsx`
78
+ - [ ] Delete old `VideoErrorFallback.tsx`
79
+ - [ ] Delete old `VideoPlayerContext.tsx`
80
+ - [ ] Run `pnpm check`
81
+ - [ ] Run `pnpm build` (optional)
82
+
83
+ ## Post-flight
84
+
85
+ - [ ] Test video playback (URL source)
86
+ - [ ] Test YouTube embed
87
+ - [ ] Test stream playback
88
+ - [ ] Test error fallback
89
+ - [ ] Verify position caching works
90
+
91
+ ## Final Structure
92
+
93
+ ```
94
+ VideoPlayer/
95
+ ├── index.ts
96
+ ├── README.md
97
+ ├── types/
98
+ │ ├── index.ts
99
+ │ ├── sources.ts
100
+ │ ├── player.ts
101
+ │ └── provider.ts
102
+ ├── hooks/
103
+ │ ├── index.ts
104
+ │ └── useVideoPositionCache.ts
105
+ ├── utils/
106
+ │ ├── index.ts
107
+ │ ├── resolvers.ts
108
+ │ └── fileSource.ts
109
+ ├── components/
110
+ │ ├── index.ts
111
+ │ ├── VideoPlayer.tsx
112
+ │ ├── VideoControls.tsx
113
+ │ └── VideoErrorFallback.tsx
114
+ ├── context/
115
+ │ ├── index.ts
116
+ │ └── VideoPlayerContext.tsx
117
+ └── providers/
118
+ ├── index.ts
119
+ ├── VidstackProvider.tsx
120
+ ├── NativeProvider.tsx
121
+ └── StreamProvider.tsx
122
+ ```
123
+
124
+ ## Metrics
125
+
126
+ | Metric | Before | After |
127
+ |--------|--------|-------|
128
+ | types.ts | 369 lines | Split into 3 files (~100 each) |
129
+ | Total files | 10 | 18 |
130
+ | Hooks | 0 | 1 (useVideoPositionCache) |
131
+ | Utils | 0 (in types.ts) | 2 |
132
+ | Duplicated code | Position caching x2 | Extracted to hook |
133
+
134
+ ## Optional Improvements
135
+
136
+ After main refactoring, consider:
137
+ 1. Integrate `useVideoPositionCache` into providers
138
+ 2. Extract more shared logic from StreamProvider
139
+ 3. Add unit tests for utils and hooks
@@ -218,16 +218,32 @@ type VideoSourceUnion =
218
218
 
219
219
  ```
220
220
  VideoPlayer/
221
- ├── VideoPlayer.tsx # Main orchestrator
222
- ├── VideoPlayerContext.tsx # Context for streaming config
223
- ├── VideoErrorFallback.tsx # Pre-built error UI
224
- ├── VideoControls.tsx # Standalone controls (Vidstack)
225
- ├── types.ts # Type definitions
226
- ├── providers/
227
- ├── VidstackProvider.tsx # YouTube, Vimeo, HLS, DASH
228
- │ ├── NativeProvider.tsx # HTML5 <video>
229
- │ └── StreamProvider.tsx # HTTP Range, Blob
230
- └── index.ts # Exports
221
+ ├── index.ts # Public API exports
222
+ ├── types/
223
+ ├── index.ts # Type re-exports
224
+ ├── sources.ts # Source types (Url, YouTube, HLS, etc.)
225
+ ├── player.ts # Player props, ref, events
226
+ │ └── provider.ts # Provider & context types
227
+ ├── hooks/
228
+ │ ├── index.ts
229
+ │ └── useVideoPositionCache.ts # Playback position caching
230
+ ├── utils/
231
+ │ ├── index.ts
232
+ │ ├── resolvers.ts # resolvePlayerMode, isSimpleStreamSource
233
+ │ └── fileSource.ts # resolveFileSource helper
234
+ ├── components/
235
+ │ ├── index.ts
236
+ │ ├── VideoPlayer.tsx # Main orchestrator
237
+ │ ├── VideoControls.tsx # Standalone Vidstack controls
238
+ │ └── VideoErrorFallback.tsx # Pre-built error UI
239
+ ├── context/
240
+ │ ├── index.ts
241
+ │ └── VideoPlayerContext.tsx # Streaming config provider
242
+ └── providers/
243
+ ├── index.ts
244
+ ├── VidstackProvider.tsx # YouTube, Vimeo, HLS, DASH
245
+ ├── NativeProvider.tsx # HTML5 <video>
246
+ └── StreamProvider.tsx # HTTP Range, Blob
231
247
  ```
232
248
 
233
249
  ## Accessibility
@@ -19,7 +19,7 @@ interface VideoControlsProps {
19
19
  export function VideoControls({ player, className }: VideoControlsProps) {
20
20
  const store = useMediaStore(player);
21
21
  const remote = useMediaRemote();
22
-
22
+
23
23
  const isPaused = store.paused;
24
24
  const isMuted = store.muted;
25
25
  const isFullscreen = store.fullscreen;
@@ -56,7 +56,7 @@ export function VideoControls({ player, className }: VideoControlsProps) {
56
56
  const progress = duration > 0 ? (currentTime / duration) * 100 : 0;
57
57
 
58
58
  return (
59
- <div
59
+ <div
60
60
  className={cn(
61
61
  "absolute inset-0 flex flex-col justify-end transition-opacity duration-300",
62
62
  "bg-gradient-to-t from-black/80 via-black/20 to-transparent",
@@ -67,11 +67,11 @@ export function VideoControls({ player, className }: VideoControlsProps) {
67
67
  >
68
68
  {/* Progress Bar */}
69
69
  <div className="px-4 pb-2 pointer-events-auto">
70
- <div
70
+ <div
71
71
  className="h-1.5 bg-white/20 rounded-full cursor-pointer hover:h-2 transition-all group"
72
72
  onClick={handleProgressClick}
73
73
  >
74
- <div
74
+ <div
75
75
  className="h-full bg-primary rounded-full transition-all relative group-hover:bg-primary/90"
76
76
  style={{ width: `${progress}%` }}
77
77
  >
@@ -109,15 +109,15 @@ export function VideoControls({ player, className }: VideoControlsProps) {
109
109
  <Volume2 className="h-5 w-5" />
110
110
  )}
111
111
  </button>
112
-
113
- <div
112
+
113
+ <div
114
114
  className="w-0 group-hover/volume:w-20 transition-all overflow-hidden"
115
115
  >
116
- <div
116
+ <div
117
117
  className="h-1.5 bg-white/20 rounded-full cursor-pointer hover:h-2 transition-all"
118
118
  onClick={handleVolumeChange}
119
119
  >
120
- <div
120
+ <div
121
121
  className="h-full bg-white rounded-full transition-all"
122
122
  style={{ width: `${volume * 100}%` }}
123
123
  />
@@ -136,4 +136,3 @@ export function VideoControls({ player, className }: VideoControlsProps) {
136
136
  </div>
137
137
  );
138
138
  }
139
-
@@ -10,9 +10,9 @@ import { FileVideo, RefreshCw } from 'lucide-react';
10
10
 
11
11
  import { cn } from '@djangocfg/ui-core/lib';
12
12
  import { Button } from '@djangocfg/ui-core/components';
13
- import { DownloadButton } from '../../components/button-download';
13
+ import { DownloadButton } from '../../../components/button-download';
14
14
 
15
- import type { ErrorFallbackProps } from './types';
15
+ import type { ErrorFallbackProps } from '../types';
16
16
 
17
17
  // ============================================================================
18
18
  // Types
@@ -40,12 +40,11 @@
40
40
 
41
41
  import React, { forwardRef, useMemo } from 'react';
42
42
 
43
- import { VidstackProvider, NativeProvider, StreamProvider } from './providers';
44
- import { useVideoPlayerContext, isSimpleStreamSource, resolveStreamSource } from './VideoPlayerContext';
45
- import { resolvePlayerMode } from './types';
43
+ import { VidstackProvider, NativeProvider, StreamProvider } from '../providers';
44
+ import { useVideoPlayerContext } from '../context';
45
+ import { resolvePlayerMode, isSimpleStreamSource, resolveStreamSource } from '../utils';
46
46
 
47
- import type { VideoPlayerProps, VideoPlayerRef, VideoSourceUnion, VidstackProviderProps, NativeProviderProps, StreamProviderProps } from './types';
48
- import type { SimpleStreamSource } from './VideoPlayerContext';
47
+ import type { VideoPlayerProps, VideoPlayerRef, VideoSourceUnion, VidstackProviderProps, NativeProviderProps, StreamProviderProps, SimpleStreamSource } from '../types';
49
48
 
50
49
  export const VideoPlayer = forwardRef<VideoPlayerRef, VideoPlayerProps & { source: VideoSourceUnion | SimpleStreamSource }>(
51
50
  (
@@ -0,0 +1,14 @@
1
+ /**
2
+ * VideoPlayer components - Public API
3
+ */
4
+
5
+ export { VideoPlayer } from './VideoPlayer';
6
+ export { VideoControls } from './VideoControls';
7
+ export {
8
+ VideoErrorFallback,
9
+ createVideoErrorFallback,
10
+ } from './VideoErrorFallback';
11
+ export type {
12
+ VideoErrorFallbackProps,
13
+ CreateVideoErrorFallbackOptions,
14
+ } from './VideoErrorFallback';