@djangocfg/ui-tools 2.1.404 → 2.1.407

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 (52) hide show
  1. package/README.md +2 -1
  2. package/package.json +11 -9
  3. package/src/tools/AudioPlayer/lazy.tsx +13 -27
  4. package/src/tools/ImageViewer/components/ImageViewer.tsx +10 -2
  5. package/src/tools/VideoPlayer/README.md +87 -230
  6. package/src/tools/VideoPlayer/VideoPlayer.tsx +82 -0
  7. package/src/tools/VideoPlayer/canvas/canvas-dispatcher.tsx +34 -0
  8. package/src/tools/VideoPlayer/canvas/hls-canvas.tsx +38 -0
  9. package/src/tools/VideoPlayer/canvas/iframe-canvas.tsx +33 -0
  10. package/src/tools/VideoPlayer/canvas/index.ts +12 -0
  11. package/src/tools/VideoPlayer/canvas/jsx.d.ts +54 -0
  12. package/src/tools/VideoPlayer/canvas/native-canvas.tsx +38 -0
  13. package/src/tools/VideoPlayer/canvas/vimeo-canvas.tsx +39 -0
  14. package/src/tools/VideoPlayer/canvas/youtube-canvas.tsx +77 -0
  15. package/src/tools/VideoPlayer/index.ts +51 -65
  16. package/src/tools/VideoPlayer/lazy.tsx +11 -54
  17. package/src/tools/VideoPlayer/parts/controls-bar.tsx +35 -0
  18. package/src/tools/VideoPlayer/parts/fullscreen.tsx +19 -0
  19. package/src/tools/VideoPlayer/parts/index.ts +15 -0
  20. package/src/tools/VideoPlayer/parts/pip.tsx +19 -0
  21. package/src/tools/VideoPlayer/parts/play-button.tsx +19 -0
  22. package/src/tools/VideoPlayer/parts/playback-rate.tsx +31 -0
  23. package/src/tools/VideoPlayer/parts/poster.tsx +3 -0
  24. package/src/tools/VideoPlayer/parts/seek-bar.tsx +26 -0
  25. package/src/tools/VideoPlayer/parts/volume.tsx +32 -0
  26. package/src/tools/VideoPlayer/styles/video-player.css +141 -0
  27. package/src/tools/VideoPlayer/types.ts +82 -0
  28. package/src/tools/VideoPlayer/utils/parse-embed-url.ts +70 -0
  29. package/src/tools/VideoPlayer/utils/vimeo-id.ts +24 -0
  30. package/src/tools/VideoPlayer/utils/youtube-id.ts +64 -0
  31. package/src/tools/index.ts +35 -28
  32. package/src/tools/VideoPlayer/components/VideoControls.tsx +0 -138
  33. package/src/tools/VideoPlayer/components/VideoErrorFallback.tsx +0 -172
  34. package/src/tools/VideoPlayer/components/VideoPlayer.tsx +0 -201
  35. package/src/tools/VideoPlayer/components/index.ts +0 -14
  36. package/src/tools/VideoPlayer/context/VideoPlayerContext.tsx +0 -52
  37. package/src/tools/VideoPlayer/context/index.ts +0 -8
  38. package/src/tools/VideoPlayer/hooks/index.ts +0 -12
  39. package/src/tools/VideoPlayer/hooks/useVideoPlayerSettings.ts +0 -71
  40. package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +0 -117
  41. package/src/tools/VideoPlayer/providers/NativeProvider.tsx +0 -284
  42. package/src/tools/VideoPlayer/providers/StreamProvider.tsx +0 -505
  43. package/src/tools/VideoPlayer/providers/VidstackProvider.tsx +0 -397
  44. package/src/tools/VideoPlayer/providers/index.ts +0 -8
  45. package/src/tools/VideoPlayer/types/index.ts +0 -38
  46. package/src/tools/VideoPlayer/types/player.ts +0 -116
  47. package/src/tools/VideoPlayer/types/provider.ts +0 -93
  48. package/src/tools/VideoPlayer/types/sources.ts +0 -97
  49. package/src/tools/VideoPlayer/utils/debug.ts +0 -14
  50. package/src/tools/VideoPlayer/utils/fileSource.ts +0 -78
  51. package/src/tools/VideoPlayer/utils/index.ts +0 -12
  52. package/src/tools/VideoPlayer/utils/resolvers.ts +0 -75
@@ -1,284 +0,0 @@
1
- /**
2
- * NativeProvider - Lightweight native HTML5 video player
3
- * For demo videos, background videos, autoplay loop muted scenarios
4
- */
5
-
6
- 'use client';
7
-
8
- import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
9
-
10
- import { cn } from '@djangocfg/ui-core/lib';
11
- import { Preloader, AspectRatio } from '@djangocfg/ui-core';
12
- import { useVideoPlayerSettings } from '../hooks/useVideoPlayerSettings';
13
-
14
- import type { NativeProviderProps, VideoPlayerRef } from '../types';
15
- import { videoDebug } from '../utils/debug';
16
-
17
- /**
18
- * Get video URL from source
19
- */
20
- function getVideoUrl(source: NativeProviderProps['source']): string {
21
- switch (source.type) {
22
- case 'url':
23
- return source.url;
24
- case 'data-url':
25
- return source.data;
26
- default:
27
- return '';
28
- }
29
- }
30
-
31
- export const NativeProvider = forwardRef<VideoPlayerRef, NativeProviderProps>(
32
- (
33
- {
34
- source,
35
- aspectRatio = 16 / 9,
36
- autoPlay = true,
37
- muted = true,
38
- loop = true,
39
- playsInline = true,
40
- preload = 'auto',
41
- controls = false,
42
- disableContextMenu = true,
43
- showPreloader = true,
44
- preloaderTimeout = 5000,
45
- className,
46
- videoClassName,
47
- onPlay,
48
- onPause,
49
- onEnded,
50
- onError,
51
- onLoadStart,
52
- onCanPlay,
53
- onTimeUpdate,
54
- },
55
- ref
56
- ) => {
57
- const [isLoading, setIsLoading] = useState(showPreloader);
58
- const videoRef = useRef<HTMLVideoElement>(null);
59
-
60
- // Persisted player settings
61
- const { settings: savedSettings, updateVolume } = useVideoPlayerSettings();
62
-
63
- const videoUrl = getVideoUrl(source);
64
-
65
- // Debug: Log video source
66
- useEffect(() => {
67
- videoDebug.load(videoUrl, source.type);
68
- }, [videoUrl, source.type]);
69
-
70
- // Expose video element methods via ref
71
- useImperativeHandle(
72
- ref,
73
- () => ({
74
- play: () => videoRef.current?.play(),
75
- pause: () => videoRef.current?.pause(),
76
- togglePlay: () => {
77
- const video = videoRef.current;
78
- if (video) {
79
- video.paused ? video.play() : video.pause();
80
- }
81
- },
82
- seekTo: (time: number) => {
83
- if (videoRef.current) videoRef.current.currentTime = time;
84
- },
85
- setVolume: (volume: number) => {
86
- if (videoRef.current) videoRef.current.volume = Math.max(0, Math.min(1, volume));
87
- },
88
- toggleMute: () => {
89
- if (videoRef.current) videoRef.current.muted = !videoRef.current.muted;
90
- },
91
- enterFullscreen: () => videoRef.current?.requestFullscreen(),
92
- exitFullscreen: () => document.exitFullscreen(),
93
- get currentTime() {
94
- return videoRef.current?.currentTime ?? 0;
95
- },
96
- get duration() {
97
- return videoRef.current?.duration ?? 0;
98
- },
99
- get paused() {
100
- return videoRef.current?.paused ?? true;
101
- },
102
- }),
103
- []
104
- );
105
-
106
- useEffect(() => {
107
- if (!showPreloader) return;
108
-
109
- const video = videoRef.current;
110
- if (!video) return;
111
-
112
- // Check if video is already loaded
113
- if (video.readyState >= 3) {
114
- setIsLoading(false);
115
- return;
116
- }
117
-
118
- const hideLoader = () => setIsLoading(false);
119
-
120
- video.addEventListener('canplay', hideLoader);
121
- video.addEventListener('loadeddata', hideLoader);
122
- video.addEventListener('playing', hideLoader);
123
-
124
- // Fallback: hide loader after timeout
125
- const timeout = setTimeout(hideLoader, preloaderTimeout);
126
-
127
- return () => {
128
- video.removeEventListener('canplay', hideLoader);
129
- video.removeEventListener('loadeddata', hideLoader);
130
- video.removeEventListener('playing', hideLoader);
131
- clearTimeout(timeout);
132
- };
133
- }, [showPreloader, preloaderTimeout]);
134
-
135
- // Debug: Log video events
136
- useEffect(() => {
137
- const video = videoRef.current;
138
- if (!video) return;
139
-
140
- const handleLoadedMetadata = () => {
141
- videoDebug.state('loadedmetadata', { duration: video.duration });
142
- };
143
-
144
- const handleCanPlayDebug = () => {
145
- videoDebug.state('canplay', { duration: video.duration, buffered: video.buffered.length });
146
- videoDebug.buffer(video.buffered, video.duration);
147
- // Apply saved volume
148
- video.volume = savedSettings.volume;
149
- };
150
-
151
- const handleSeeking = () => {
152
- videoDebug.event('seeking', { currentTime: video.currentTime });
153
- };
154
-
155
- const handleSeeked = () => {
156
- videoDebug.event('seeked', { currentTime: video.currentTime });
157
- videoDebug.buffer(video.buffered, video.duration);
158
- };
159
-
160
- const handleWaiting = () => {
161
- videoDebug.warn('WAITING - buffering...');
162
- videoDebug.buffer(video.buffered, video.duration);
163
- };
164
-
165
- const handleStalled = () => {
166
- videoDebug.warn('STALLED - network issue');
167
- videoDebug.buffer(video.buffered, video.duration);
168
- };
169
-
170
- video.addEventListener('loadedmetadata', handleLoadedMetadata);
171
- video.addEventListener('canplay', handleCanPlayDebug);
172
- video.addEventListener('seeking', handleSeeking);
173
- video.addEventListener('seeked', handleSeeked);
174
- video.addEventListener('waiting', handleWaiting);
175
- video.addEventListener('stalled', handleStalled);
176
-
177
- return () => {
178
- video.removeEventListener('loadedmetadata', handleLoadedMetadata);
179
- video.removeEventListener('canplay', handleCanPlayDebug);
180
- video.removeEventListener('seeking', handleSeeking);
181
- video.removeEventListener('seeked', handleSeeked);
182
- video.removeEventListener('waiting', handleWaiting);
183
- video.removeEventListener('stalled', handleStalled);
184
- };
185
- }, [savedSettings.volume]);
186
-
187
- // Persist volume when user changes it via native controls
188
- useEffect(() => {
189
- const video = videoRef.current;
190
- if (!video) return;
191
-
192
- const handleVolumeChange = () => {
193
- updateVolume(video.volume);
194
- };
195
-
196
- video.addEventListener('volumechange', handleVolumeChange);
197
- return () => video.removeEventListener('volumechange', handleVolumeChange);
198
- }, [updateVolume]);
199
-
200
- const handleContextMenu = (e: React.MouseEvent) => {
201
- if (disableContextMenu) {
202
- e.preventDefault();
203
- }
204
- };
205
-
206
- const handleError = (e: React.SyntheticEvent<HTMLVideoElement>) => {
207
- const video = e.currentTarget;
208
- const errorMsg = video.error?.message || 'Video playback error';
209
- videoDebug.error('Video error', { code: video.error?.code, message: errorMsg });
210
- setIsLoading(false);
211
- onError?.(errorMsg);
212
- };
213
-
214
- const handleTimeUpdate = () => {
215
- const video = videoRef.current;
216
- if (video && onTimeUpdate) {
217
- onTimeUpdate(video.currentTime, video.duration);
218
- }
219
- };
220
-
221
- // Determine if we should use AspectRatio wrapper or fill mode
222
- const isFillMode = aspectRatio === 'fill';
223
- const computedAspectRatio = aspectRatio === 'auto' || aspectRatio === 'fill' ? undefined : aspectRatio;
224
-
225
- // Video content
226
- const videoContent = (
227
- <>
228
- {/* Preloader */}
229
- {showPreloader && isLoading && (
230
- <div
231
- className={cn(
232
- 'absolute inset-0 flex items-center justify-center bg-muted/30 backdrop-blur-sm z-10'
233
- )}
234
- >
235
- <Preloader size="lg" spinnerClassName="text-white" />
236
- </div>
237
- )}
238
-
239
- {/* Video */}
240
- <video
241
- ref={videoRef}
242
- className={cn('w-full h-full object-cover', videoClassName)}
243
- src={videoUrl}
244
- autoPlay={autoPlay}
245
- muted={muted}
246
- loop={loop}
247
- playsInline={playsInline}
248
- preload={preload}
249
- controls={controls}
250
- poster={source.poster}
251
- onContextMenu={handleContextMenu}
252
- onLoadStart={onLoadStart}
253
- onCanPlay={onCanPlay}
254
- onPlay={onPlay}
255
- onPause={onPause}
256
- onPlaying={() => setIsLoading(false)}
257
- onEnded={onEnded}
258
- onError={handleError}
259
- onTimeUpdate={handleTimeUpdate}
260
- />
261
- </>
262
- );
263
-
264
- // Fill mode - no AspectRatio wrapper
265
- if (isFillMode) {
266
- return (
267
- <div className={cn('relative w-full h-full overflow-hidden', className)}>
268
- {videoContent}
269
- </div>
270
- );
271
- }
272
-
273
- // Normal mode with AspectRatio
274
- return (
275
- <div className={cn('relative overflow-hidden', className)}>
276
- <AspectRatio ratio={computedAspectRatio}>
277
- {videoContent}
278
- </AspectRatio>
279
- </div>
280
- );
281
- }
282
- );
283
-
284
- NativeProvider.displayName = 'NativeProvider';