@djangocfg/ui-tools 2.1.110 → 2.1.112

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 (159) hide show
  1. package/README.md +242 -49
  2. package/dist/JsonSchemaForm-65NLLK56.mjs +4 -0
  3. package/dist/JsonSchemaForm-65NLLK56.mjs.map +1 -0
  4. package/dist/JsonSchemaForm-PY6DH3HE.cjs +13 -0
  5. package/dist/JsonSchemaForm-PY6DH3HE.cjs.map +1 -0
  6. package/dist/JsonTree-6RYAOPSS.mjs +4 -0
  7. package/dist/JsonTree-6RYAOPSS.mjs.map +1 -0
  8. package/dist/JsonTree-7OH6CIHT.cjs +10 -0
  9. package/dist/JsonTree-7OH6CIHT.cjs.map +1 -0
  10. package/dist/MapContainer-GXQLP5WY.mjs +214 -0
  11. package/dist/MapContainer-GXQLP5WY.mjs.map +1 -0
  12. package/dist/MapContainer-RYG4HPH4.cjs +221 -0
  13. package/dist/MapContainer-RYG4HPH4.cjs.map +1 -0
  14. package/dist/{Mermaid.client-4OCKJ6QD.mjs → Mermaid.client-OKACITCW.mjs} +16 -7
  15. package/dist/Mermaid.client-OKACITCW.mjs.map +1 -0
  16. package/dist/{Mermaid.client-ZP6OE46Z.cjs → Mermaid.client-PNXEC6YL.cjs} +16 -7
  17. package/dist/Mermaid.client-PNXEC6YL.cjs.map +1 -0
  18. package/dist/{PlaygroundLayout-XXVBU4WZ.cjs → PlaygroundLayout-SYMEAG3J.cjs} +25 -24
  19. package/dist/PlaygroundLayout-SYMEAG3J.cjs.map +1 -0
  20. package/dist/{PlaygroundLayout-LMQTVXSP.mjs → PlaygroundLayout-UQRBU5RH.mjs} +4 -3
  21. package/dist/PlaygroundLayout-UQRBU5RH.mjs.map +1 -0
  22. package/dist/{PrettyCode.client-2CLSV2VD.cjs → PrettyCode.client-DANYYQYO.cjs} +11 -4
  23. package/dist/PrettyCode.client-DANYYQYO.cjs.map +1 -0
  24. package/dist/{PrettyCode.client-Y2BVON7R.mjs → PrettyCode.client-RS5ZTNBT.mjs} +11 -4
  25. package/dist/PrettyCode.client-RS5ZTNBT.mjs.map +1 -0
  26. package/dist/chunk-2DSR7V2L.mjs +561 -0
  27. package/dist/chunk-2DSR7V2L.mjs.map +1 -0
  28. package/dist/chunk-47T5ECYV.cjs +1357 -0
  29. package/dist/chunk-47T5ECYV.cjs.map +1 -0
  30. package/dist/chunk-5QT3QYFZ.cjs +189 -0
  31. package/dist/chunk-5QT3QYFZ.cjs.map +1 -0
  32. package/dist/chunk-7IIRYG4S.mjs +1057 -0
  33. package/dist/chunk-7IIRYG4S.mjs.map +1 -0
  34. package/dist/{chunk-FB5QBSI3.cjs → chunk-DI3HUXHK.cjs} +15 -195
  35. package/dist/chunk-DI3HUXHK.cjs.map +1 -0
  36. package/dist/chunk-EVGWYASL.cjs +1528 -0
  37. package/dist/chunk-EVGWYASL.cjs.map +1 -0
  38. package/dist/chunk-F2N7P5XU.cjs +30 -0
  39. package/dist/chunk-F2N7P5XU.cjs.map +1 -0
  40. package/dist/{chunk-L6UHASYQ.mjs → chunk-G6PRZP5I.mjs} +7 -186
  41. package/dist/chunk-G6PRZP5I.mjs.map +1 -0
  42. package/dist/chunk-JWB2EWQO.mjs +5 -0
  43. package/dist/chunk-JWB2EWQO.mjs.map +1 -0
  44. package/dist/chunk-LTJX2JXE.mjs +338 -0
  45. package/dist/chunk-LTJX2JXE.mjs.map +1 -0
  46. package/dist/chunk-OVNC4KW6.mjs +1494 -0
  47. package/dist/chunk-OVNC4KW6.mjs.map +1 -0
  48. package/dist/chunk-PNZSJN6T.cjs +1086 -0
  49. package/dist/chunk-PNZSJN6T.cjs.map +1 -0
  50. package/dist/chunk-TEFRA7GW.cjs +565 -0
  51. package/dist/chunk-TEFRA7GW.cjs.map +1 -0
  52. package/dist/chunk-UOMPPIED.mjs +1343 -0
  53. package/dist/chunk-UOMPPIED.mjs.map +1 -0
  54. package/dist/chunk-W6YHQI4F.mjs +187 -0
  55. package/dist/chunk-W6YHQI4F.mjs.map +1 -0
  56. package/dist/chunk-XTBRWVIV.cjs +346 -0
  57. package/dist/chunk-XTBRWVIV.cjs.map +1 -0
  58. package/dist/components-C7ZL7OMY.mjs +5 -0
  59. package/dist/components-C7ZL7OMY.mjs.map +1 -0
  60. package/dist/components-CJ2IB65O.cjs +27 -0
  61. package/dist/components-CJ2IB65O.cjs.map +1 -0
  62. package/dist/components-EASJYK45.mjs +6 -0
  63. package/dist/components-EASJYK45.mjs.map +1 -0
  64. package/dist/components-LDRFDV4A.cjs +22 -0
  65. package/dist/components-LDRFDV4A.cjs.map +1 -0
  66. package/dist/components-VZKUTDJK.mjs +5 -0
  67. package/dist/components-VZKUTDJK.mjs.map +1 -0
  68. package/dist/components-Y64GTIMQ.cjs +42 -0
  69. package/dist/components-Y64GTIMQ.cjs.map +1 -0
  70. package/dist/index.cjs +701 -4813
  71. package/dist/index.cjs.map +1 -1
  72. package/dist/index.d.cts +1274 -1026
  73. package/dist/index.d.ts +1274 -1026
  74. package/dist/index.mjs +358 -4730
  75. package/dist/index.mjs.map +1 -1
  76. package/package.json +27 -4
  77. package/src/components/index.ts +17 -0
  78. package/src/components/lazy-wrapper.tsx +281 -0
  79. package/src/index.ts +92 -7
  80. package/src/tools/AudioPlayer/components/HybridAudioPlayer.tsx +14 -5
  81. package/src/tools/AudioPlayer/lazy.tsx +85 -0
  82. package/src/tools/Gallery/components/Gallery.tsx +182 -0
  83. package/src/tools/Gallery/components/GalleryCarousel.tsx +251 -0
  84. package/src/tools/Gallery/components/GalleryCompact.tsx +173 -0
  85. package/src/tools/Gallery/components/GalleryGrid.tsx +493 -0
  86. package/src/tools/Gallery/components/GalleryImage.tsx +66 -0
  87. package/src/tools/Gallery/components/GalleryLightbox.tsx +331 -0
  88. package/src/tools/Gallery/components/GalleryMedia.tsx +66 -0
  89. package/src/tools/Gallery/components/GalleryThumbnails.tsx +173 -0
  90. package/src/tools/Gallery/components/GalleryThumbnailsVirtual.tsx +138 -0
  91. package/src/tools/Gallery/components/GalleryVideo.tsx +222 -0
  92. package/src/tools/Gallery/components/index.ts +13 -0
  93. package/src/tools/Gallery/hooks/index.ts +23 -0
  94. package/src/tools/Gallery/hooks/useGallery.ts +137 -0
  95. package/src/tools/Gallery/hooks/useImageDimensions.ts +223 -0
  96. package/src/tools/Gallery/hooks/usePinchZoom.ts +234 -0
  97. package/src/tools/Gallery/hooks/usePreloadImages.ts +71 -0
  98. package/src/tools/Gallery/hooks/useSwipe.ts +86 -0
  99. package/src/tools/Gallery/hooks/useVirtualList.ts +129 -0
  100. package/src/tools/Gallery/hooks/useZoom.ts +316 -0
  101. package/src/tools/Gallery/index.ts +66 -0
  102. package/src/tools/Gallery/types.ts +183 -0
  103. package/src/tools/Gallery/utils/imageAnalysis.ts +52 -0
  104. package/src/tools/Gallery/utils/index.ts +11 -0
  105. package/src/tools/ImageViewer/components/ImageToolbar.tsx +20 -8
  106. package/src/tools/ImageViewer/components/ImageViewer.tsx +12 -4
  107. package/src/tools/ImageViewer/lazy.tsx +37 -0
  108. package/src/tools/JsonForm/lazy.tsx +43 -0
  109. package/src/tools/JsonForm/widgets/ColorWidget.tsx +4 -1
  110. package/src/tools/JsonTree/lazy.tsx +45 -0
  111. package/src/tools/LottiePlayer/lazy.tsx +57 -0
  112. package/src/tools/Map/components/CustomOverlay.tsx +54 -0
  113. package/src/tools/Map/components/DrawControl.tsx +36 -0
  114. package/src/tools/Map/components/GeocoderControl.tsx +70 -0
  115. package/src/tools/Map/components/LayerSwitcher.tsx +225 -0
  116. package/src/tools/Map/components/MapCluster.tsx +273 -0
  117. package/src/tools/Map/components/MapContainer.tsx +191 -0
  118. package/src/tools/Map/components/MapControls.tsx +44 -0
  119. package/src/tools/Map/components/MapLegend.tsx +161 -0
  120. package/src/tools/Map/components/MapMarker.tsx +102 -0
  121. package/src/tools/Map/components/MapPopup.tsx +46 -0
  122. package/src/tools/Map/components/MapSource.tsx +30 -0
  123. package/src/tools/Map/components/index.ts +20 -0
  124. package/src/tools/Map/context/MapContext.tsx +89 -0
  125. package/src/tools/Map/context/index.ts +2 -0
  126. package/src/tools/Map/hooks/index.ts +9 -0
  127. package/src/tools/Map/hooks/useMap.ts +11 -0
  128. package/src/tools/Map/hooks/useMapControl.ts +99 -0
  129. package/src/tools/Map/hooks/useMapEvents.ts +147 -0
  130. package/src/tools/Map/hooks/useMapLayers.ts +83 -0
  131. package/src/tools/Map/hooks/useMapViewport.ts +62 -0
  132. package/src/tools/Map/hooks/useMarkers.ts +85 -0
  133. package/src/tools/Map/index.ts +116 -0
  134. package/src/tools/Map/layers/cluster.ts +94 -0
  135. package/src/tools/Map/layers/index.ts +15 -0
  136. package/src/tools/Map/layers/line.ts +93 -0
  137. package/src/tools/Map/layers/point.ts +61 -0
  138. package/src/tools/Map/layers/polygon.ts +73 -0
  139. package/src/tools/Map/lazy.tsx +56 -0
  140. package/src/tools/Map/styles/index.ts +15 -0
  141. package/src/tools/Map/types.ts +259 -0
  142. package/src/tools/Map/utils/geo.ts +88 -0
  143. package/src/tools/Map/utils/index.ts +16 -0
  144. package/src/tools/Map/utils/transform.ts +107 -0
  145. package/src/tools/Mermaid/Mermaid.client.tsx +12 -4
  146. package/src/tools/Mermaid/components/MermaidFullscreenModal.tsx +6 -2
  147. package/src/tools/Mermaid/lazy.tsx +46 -0
  148. package/src/tools/OpenapiViewer/lazy.tsx +72 -0
  149. package/src/tools/PrettyCode/PrettyCode.client.tsx +10 -3
  150. package/src/tools/PrettyCode/lazy.tsx +64 -0
  151. package/src/tools/VideoPlayer/lazy.tsx +63 -0
  152. package/dist/Mermaid.client-4OCKJ6QD.mjs.map +0 -1
  153. package/dist/Mermaid.client-ZP6OE46Z.cjs.map +0 -1
  154. package/dist/PlaygroundLayout-LMQTVXSP.mjs.map +0 -1
  155. package/dist/PlaygroundLayout-XXVBU4WZ.cjs.map +0 -1
  156. package/dist/PrettyCode.client-2CLSV2VD.cjs.map +0 -1
  157. package/dist/PrettyCode.client-Y2BVON7R.mjs.map +0 -1
  158. package/dist/chunk-FB5QBSI3.cjs.map +0 -1
  159. package/dist/chunk-L6UHASYQ.mjs.map +0 -1
@@ -0,0 +1,1343 @@
1
+ import { cn as cn$1, Button, DownloadButton } from './chunk-JWB2EWQO.mjs';
2
+ import { useVideoCache, useMediaCacheStore, generateContentKey, useVideoPlayerSettings } from './chunk-LTJX2JXE.mjs';
3
+ import { __name } from './chunk-CGILA3WO.mjs';
4
+ import { forwardRef, useRef, useState, useMemo, useEffect, useCallback, useImperativeHandle, createContext, useContext } from 'react';
5
+ import '@vidstack/react/player/styles/base.css';
6
+ import '@vidstack/react/player/styles/default/theme.css';
7
+ import '@vidstack/react/player/styles/default/layouts/video.css';
8
+ import { createMediaLogger, generateOgImageUrl, cn } from '@djangocfg/ui-core/lib';
9
+ import { MediaPlayer, MediaProvider, Poster, useMediaStore, useMediaRemote } from '@vidstack/react';
10
+ import { DefaultVideoLayout, defaultLayoutIcons } from '@vidstack/react/player/layouts/default';
11
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
12
+ import { Preloader, AspectRatio } from '@djangocfg/ui-core';
13
+ import { Play, Pause, VolumeX, Volume2, Minimize, Maximize, FileVideo, RefreshCw } from 'lucide-react';
14
+
15
+ var videoDebug = createMediaLogger("VideoPlayer");
16
+ function getVidstackSrc(source) {
17
+ switch (source.type) {
18
+ case "youtube":
19
+ return `youtube/${source.id}`;
20
+ case "vimeo":
21
+ return `vimeo/${source.id}`;
22
+ case "hls":
23
+ return { src: source.url, type: "application/x-mpegurl" };
24
+ case "dash":
25
+ return { src: source.url, type: "application/dash+xml" };
26
+ case "url":
27
+ return source.url;
28
+ default:
29
+ return "";
30
+ }
31
+ }
32
+ __name(getVidstackSrc, "getVidstackSrc");
33
+ function DefaultErrorFallback({ error }) {
34
+ return /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 flex flex-col items-center justify-center gap-4 text-white bg-black", children: [
35
+ /* @__PURE__ */ jsx(
36
+ "svg",
37
+ {
38
+ className: "w-16 h-16 text-muted-foreground",
39
+ fill: "none",
40
+ stroke: "currentColor",
41
+ viewBox: "0 0 24 24",
42
+ children: /* @__PURE__ */ jsx(
43
+ "path",
44
+ {
45
+ strokeLinecap: "round",
46
+ strokeLinejoin: "round",
47
+ strokeWidth: 2,
48
+ d: "M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z"
49
+ }
50
+ )
51
+ }
52
+ ),
53
+ /* @__PURE__ */ jsx("p", { className: "text-lg", children: error || "Video cannot be played" })
54
+ ] });
55
+ }
56
+ __name(DefaultErrorFallback, "DefaultErrorFallback");
57
+ var VidstackProvider = forwardRef(
58
+ ({
59
+ source,
60
+ aspectRatio = 16 / 9,
61
+ autoPlay = false,
62
+ muted = false,
63
+ loop = false,
64
+ playsInline = true,
65
+ controls = true,
66
+ className,
67
+ showInfo = false,
68
+ theme = "default",
69
+ errorFallback,
70
+ onPlay,
71
+ onPause,
72
+ onEnded,
73
+ onError,
74
+ onLoadStart,
75
+ onCanPlay,
76
+ onTimeUpdate
77
+ }, ref) => {
78
+ const playerRef = useRef(null);
79
+ const [hasError, setHasError] = useState(false);
80
+ const [errorMessage, setErrorMessage] = useState("Video cannot be played");
81
+ const lastSavedTimeRef = useRef(0);
82
+ const hasRestoredPositionRef = useRef(false);
83
+ const {
84
+ getPosterUrl,
85
+ cachePosterUrl,
86
+ saveVideoPosition,
87
+ getVideoPosition
88
+ } = useVideoCache();
89
+ const sourceKey = useMemo(() => {
90
+ switch (source.type) {
91
+ case "youtube":
92
+ return `youtube:${source.id}`;
93
+ case "vimeo":
94
+ return `vimeo:${source.id}`;
95
+ case "hls":
96
+ case "dash":
97
+ case "url":
98
+ return `url:${source.url}`;
99
+ default:
100
+ return null;
101
+ }
102
+ }, [source]);
103
+ const posterUrl = useMemo(() => {
104
+ if (source.poster) return source.poster;
105
+ if (!source.title) return void 0;
106
+ const cached = getPosterUrl(source.title);
107
+ if (cached) return cached;
108
+ const url = generateOgImageUrl({ title: source.title });
109
+ cachePosterUrl(source.title, url);
110
+ return url;
111
+ }, [source.poster, source.title, getPosterUrl, cachePosterUrl]);
112
+ const vidstackSrc = useMemo(() => getVidstackSrc(source), [source]);
113
+ useEffect(() => {
114
+ const srcString = typeof vidstackSrc === "string" ? vidstackSrc : vidstackSrc.src;
115
+ videoDebug.load(srcString, source.type);
116
+ }, [vidstackSrc, source.type]);
117
+ const retry = useCallback(() => {
118
+ setHasError(false);
119
+ setErrorMessage("Video cannot be played");
120
+ const player = playerRef.current;
121
+ if (player) {
122
+ player.currentTime = 0;
123
+ player.play();
124
+ }
125
+ }, []);
126
+ useImperativeHandle(
127
+ ref,
128
+ () => {
129
+ const player = playerRef.current;
130
+ return {
131
+ play: /* @__PURE__ */ __name(() => player?.play(), "play"),
132
+ pause: /* @__PURE__ */ __name(() => player?.pause(), "pause"),
133
+ togglePlay: /* @__PURE__ */ __name(() => {
134
+ if (player) {
135
+ player.paused ? player.play() : player.pause();
136
+ }
137
+ }, "togglePlay"),
138
+ seekTo: /* @__PURE__ */ __name((time) => {
139
+ if (player) player.currentTime = time;
140
+ }, "seekTo"),
141
+ setVolume: /* @__PURE__ */ __name((volume) => {
142
+ if (player) player.volume = Math.max(0, Math.min(1, volume));
143
+ }, "setVolume"),
144
+ toggleMute: /* @__PURE__ */ __name(() => {
145
+ if (player) player.muted = !player.muted;
146
+ }, "toggleMute"),
147
+ enterFullscreen: /* @__PURE__ */ __name(() => player?.enterFullscreen(), "enterFullscreen"),
148
+ exitFullscreen: /* @__PURE__ */ __name(() => player?.exitFullscreen(), "exitFullscreen"),
149
+ get currentTime() {
150
+ return player?.currentTime ?? 0;
151
+ },
152
+ get duration() {
153
+ return player?.duration ?? 0;
154
+ },
155
+ get paused() {
156
+ return player?.paused ?? true;
157
+ }
158
+ };
159
+ },
160
+ []
161
+ );
162
+ const handlePlay = /* @__PURE__ */ __name(() => onPlay?.(), "handlePlay");
163
+ const handlePause = useCallback(() => {
164
+ const player = playerRef.current;
165
+ if (sourceKey && player && player.currentTime > 0) {
166
+ saveVideoPosition(sourceKey, player.currentTime);
167
+ lastSavedTimeRef.current = player.currentTime;
168
+ }
169
+ onPause?.();
170
+ }, [sourceKey, saveVideoPosition, onPause]);
171
+ const handleEnded = /* @__PURE__ */ __name(() => onEnded?.(), "handleEnded");
172
+ const handleError = /* @__PURE__ */ __name((detail) => {
173
+ const error = detail;
174
+ const msg = error?.message || "Video playback error";
175
+ videoDebug.error("Vidstack error", { message: msg });
176
+ setHasError(true);
177
+ setErrorMessage(msg);
178
+ onError?.(msg);
179
+ }, "handleError");
180
+ const handleLoadStart = /* @__PURE__ */ __name(() => onLoadStart?.(), "handleLoadStart");
181
+ const handleCanPlay = useCallback(() => {
182
+ const player = playerRef.current;
183
+ if (player) {
184
+ videoDebug.state("canplay", { duration: player.duration });
185
+ const mediaEl = player.provider?.media;
186
+ if (mediaEl?.buffered) {
187
+ videoDebug.buffer(mediaEl.buffered, player.duration);
188
+ }
189
+ }
190
+ setHasError(false);
191
+ if (sourceKey && player && !hasRestoredPositionRef.current) {
192
+ const cachedPosition = getVideoPosition(sourceKey);
193
+ if (cachedPosition && cachedPosition > 0) {
194
+ const duration = player.duration;
195
+ if (cachedPosition < duration - 1) {
196
+ videoDebug.debug(`Restoring position: ${cachedPosition}s`);
197
+ player.currentTime = cachedPosition;
198
+ }
199
+ }
200
+ hasRestoredPositionRef.current = true;
201
+ }
202
+ onCanPlay?.();
203
+ }, [sourceKey, getVideoPosition, onCanPlay]);
204
+ const handleTimeUpdate = useCallback(() => {
205
+ const player = playerRef.current;
206
+ if (!player) return;
207
+ if (sourceKey && player.currentTime > 0) {
208
+ const timeSinceLastSave = player.currentTime - lastSavedTimeRef.current;
209
+ if (timeSinceLastSave >= 5 || timeSinceLastSave < 0) {
210
+ saveVideoPosition(sourceKey, player.currentTime);
211
+ lastSavedTimeRef.current = player.currentTime;
212
+ }
213
+ }
214
+ onTimeUpdate?.(player.currentTime, player.duration);
215
+ }, [sourceKey, saveVideoPosition, onTimeUpdate]);
216
+ useEffect(() => {
217
+ hasRestoredPositionRef.current = false;
218
+ lastSavedTimeRef.current = 0;
219
+ }, [sourceKey]);
220
+ useEffect(() => {
221
+ const player = playerRef.current;
222
+ if (!player) return;
223
+ const handleSeeking = /* @__PURE__ */ __name(() => {
224
+ videoDebug.event("seeking", { currentTime: player.currentTime });
225
+ }, "handleSeeking");
226
+ const handleSeeked = /* @__PURE__ */ __name(() => {
227
+ videoDebug.event("seeked", { currentTime: player.currentTime });
228
+ const mediaEl = player.provider?.media;
229
+ if (mediaEl?.buffered) {
230
+ videoDebug.buffer(mediaEl.buffered, player.duration);
231
+ }
232
+ }, "handleSeeked");
233
+ const handleWaiting = /* @__PURE__ */ __name(() => {
234
+ videoDebug.warn("WAITING - buffering...");
235
+ const mediaEl = player.provider?.media;
236
+ if (mediaEl?.buffered) {
237
+ videoDebug.buffer(mediaEl.buffered, player.duration);
238
+ }
239
+ }, "handleWaiting");
240
+ const handleStalled = /* @__PURE__ */ __name(() => {
241
+ videoDebug.warn("STALLED - network issue");
242
+ const mediaEl = player.provider?.media;
243
+ if (mediaEl?.buffered) {
244
+ videoDebug.buffer(mediaEl.buffered, player.duration);
245
+ }
246
+ }, "handleStalled");
247
+ player.addEventListener("seeking", handleSeeking);
248
+ player.addEventListener("seeked", handleSeeked);
249
+ player.addEventListener("waiting", handleWaiting);
250
+ player.addEventListener("stalled", handleStalled);
251
+ return () => {
252
+ player.removeEventListener("seeking", handleSeeking);
253
+ player.removeEventListener("seeked", handleSeeked);
254
+ player.removeEventListener("waiting", handleWaiting);
255
+ player.removeEventListener("stalled", handleStalled);
256
+ };
257
+ }, [vidstackSrc]);
258
+ const isFillMode = aspectRatio === "fill";
259
+ const computedAspectRatio = aspectRatio === "auto" || aspectRatio === "fill" ? void 0 : aspectRatio;
260
+ const renderErrorFallback = /* @__PURE__ */ __name(() => {
261
+ const fallbackProps = { error: errorMessage, retry };
262
+ if (typeof errorFallback === "function") {
263
+ return errorFallback(fallbackProps);
264
+ }
265
+ if (errorFallback) {
266
+ return errorFallback;
267
+ }
268
+ return /* @__PURE__ */ jsx(DefaultErrorFallback, { ...fallbackProps });
269
+ }, "renderErrorFallback");
270
+ const containerStyles = isFillMode ? { width: "100%", height: "100%" } : { aspectRatio: computedAspectRatio };
271
+ return /* @__PURE__ */ jsxs("div", { className: cn(isFillMode ? "w-full h-full" : "w-full", className), children: [
272
+ /* @__PURE__ */ jsx(
273
+ "div",
274
+ {
275
+ className: cn(
276
+ "relative w-full rounded-sm bg-black overflow-hidden",
277
+ isFillMode && "h-full",
278
+ theme === "minimal" && "rounded-none",
279
+ theme === "modern" && "rounded-xl shadow-2xl"
280
+ ),
281
+ style: containerStyles,
282
+ children: hasError ? renderErrorFallback() : /* @__PURE__ */ jsxs(
283
+ MediaPlayer,
284
+ {
285
+ ref: playerRef,
286
+ title: source.title || "Video",
287
+ src: vidstackSrc,
288
+ autoPlay,
289
+ muted,
290
+ loop,
291
+ playsInline,
292
+ onPlay: handlePlay,
293
+ onPause: handlePause,
294
+ onEnded: handleEnded,
295
+ onError: handleError,
296
+ onLoadStart: handleLoadStart,
297
+ onCanPlay: handleCanPlay,
298
+ onTimeUpdate: handleTimeUpdate,
299
+ className: "w-full h-full",
300
+ children: [
301
+ /* @__PURE__ */ jsx(MediaProvider, {}),
302
+ posterUrl && /* @__PURE__ */ jsx(
303
+ Poster,
304
+ {
305
+ className: "vds-poster",
306
+ src: posterUrl,
307
+ alt: source.title || "Video poster",
308
+ style: { objectFit: "cover" }
309
+ }
310
+ ),
311
+ controls && /* @__PURE__ */ jsx(DefaultVideoLayout, { icons: defaultLayoutIcons, thumbnails: posterUrl })
312
+ ]
313
+ }
314
+ )
315
+ }
316
+ ),
317
+ showInfo && source.title && /* @__PURE__ */ jsx("div", { className: "mt-4 space-y-2", children: /* @__PURE__ */ jsx("h3", { className: "text-xl font-semibold text-foreground", children: source.title }) })
318
+ ] });
319
+ }
320
+ );
321
+ VidstackProvider.displayName = "VidstackProvider";
322
+ function useVideoPlayerSettings2() {
323
+ const { settings, saveSettings } = useVideoPlayerSettings();
324
+ const updateVolume = useCallback(
325
+ (volume) => {
326
+ saveSettings({ volume: Math.max(0, Math.min(1, volume)) });
327
+ },
328
+ [saveSettings]
329
+ );
330
+ const updateLoop = useCallback(
331
+ (isLooping) => {
332
+ saveSettings({ isLooping });
333
+ },
334
+ [saveSettings]
335
+ );
336
+ const updateSettings = useCallback(
337
+ (newSettings) => {
338
+ saveSettings(newSettings);
339
+ },
340
+ [saveSettings]
341
+ );
342
+ return {
343
+ settings,
344
+ updateVolume,
345
+ updateLoop,
346
+ updateSettings
347
+ };
348
+ }
349
+ __name(useVideoPlayerSettings2, "useVideoPlayerSettings");
350
+ function getVideoUrl(source) {
351
+ switch (source.type) {
352
+ case "url":
353
+ return source.url;
354
+ case "data-url":
355
+ return source.data;
356
+ default:
357
+ return "";
358
+ }
359
+ }
360
+ __name(getVideoUrl, "getVideoUrl");
361
+ var NativeProvider = forwardRef(
362
+ ({
363
+ source,
364
+ aspectRatio = 16 / 9,
365
+ autoPlay = true,
366
+ muted = true,
367
+ loop = true,
368
+ playsInline = true,
369
+ preload = "auto",
370
+ controls = false,
371
+ disableContextMenu = true,
372
+ showPreloader = true,
373
+ preloaderTimeout = 5e3,
374
+ className,
375
+ videoClassName,
376
+ onPlay,
377
+ onPause,
378
+ onEnded,
379
+ onError,
380
+ onLoadStart,
381
+ onCanPlay,
382
+ onTimeUpdate
383
+ }, ref) => {
384
+ const [isLoading, setIsLoading] = useState(showPreloader);
385
+ const videoRef = useRef(null);
386
+ const { settings: savedSettings, updateVolume } = useVideoPlayerSettings2();
387
+ const videoUrl = getVideoUrl(source);
388
+ useEffect(() => {
389
+ videoDebug.load(videoUrl, source.type);
390
+ }, [videoUrl, source.type]);
391
+ useImperativeHandle(
392
+ ref,
393
+ () => ({
394
+ play: /* @__PURE__ */ __name(() => videoRef.current?.play(), "play"),
395
+ pause: /* @__PURE__ */ __name(() => videoRef.current?.pause(), "pause"),
396
+ togglePlay: /* @__PURE__ */ __name(() => {
397
+ const video = videoRef.current;
398
+ if (video) {
399
+ video.paused ? video.play() : video.pause();
400
+ }
401
+ }, "togglePlay"),
402
+ seekTo: /* @__PURE__ */ __name((time) => {
403
+ if (videoRef.current) videoRef.current.currentTime = time;
404
+ }, "seekTo"),
405
+ setVolume: /* @__PURE__ */ __name((volume) => {
406
+ if (videoRef.current) videoRef.current.volume = Math.max(0, Math.min(1, volume));
407
+ }, "setVolume"),
408
+ toggleMute: /* @__PURE__ */ __name(() => {
409
+ if (videoRef.current) videoRef.current.muted = !videoRef.current.muted;
410
+ }, "toggleMute"),
411
+ enterFullscreen: /* @__PURE__ */ __name(() => videoRef.current?.requestFullscreen(), "enterFullscreen"),
412
+ exitFullscreen: /* @__PURE__ */ __name(() => document.exitFullscreen(), "exitFullscreen"),
413
+ get currentTime() {
414
+ return videoRef.current?.currentTime ?? 0;
415
+ },
416
+ get duration() {
417
+ return videoRef.current?.duration ?? 0;
418
+ },
419
+ get paused() {
420
+ return videoRef.current?.paused ?? true;
421
+ }
422
+ }),
423
+ []
424
+ );
425
+ useEffect(() => {
426
+ if (!showPreloader) return;
427
+ const video = videoRef.current;
428
+ if (!video) return;
429
+ if (video.readyState >= 3) {
430
+ setIsLoading(false);
431
+ return;
432
+ }
433
+ const hideLoader = /* @__PURE__ */ __name(() => setIsLoading(false), "hideLoader");
434
+ video.addEventListener("canplay", hideLoader);
435
+ video.addEventListener("loadeddata", hideLoader);
436
+ video.addEventListener("playing", hideLoader);
437
+ const timeout = setTimeout(hideLoader, preloaderTimeout);
438
+ return () => {
439
+ video.removeEventListener("canplay", hideLoader);
440
+ video.removeEventListener("loadeddata", hideLoader);
441
+ video.removeEventListener("playing", hideLoader);
442
+ clearTimeout(timeout);
443
+ };
444
+ }, [showPreloader, preloaderTimeout]);
445
+ useEffect(() => {
446
+ const video = videoRef.current;
447
+ if (!video) return;
448
+ const handleLoadedMetadata = /* @__PURE__ */ __name(() => {
449
+ videoDebug.state("loadedmetadata", { duration: video.duration });
450
+ }, "handleLoadedMetadata");
451
+ const handleCanPlayDebug = /* @__PURE__ */ __name(() => {
452
+ videoDebug.state("canplay", { duration: video.duration, buffered: video.buffered.length });
453
+ videoDebug.buffer(video.buffered, video.duration);
454
+ video.volume = savedSettings.volume;
455
+ }, "handleCanPlayDebug");
456
+ const handleSeeking = /* @__PURE__ */ __name(() => {
457
+ videoDebug.event("seeking", { currentTime: video.currentTime });
458
+ }, "handleSeeking");
459
+ const handleSeeked = /* @__PURE__ */ __name(() => {
460
+ videoDebug.event("seeked", { currentTime: video.currentTime });
461
+ videoDebug.buffer(video.buffered, video.duration);
462
+ }, "handleSeeked");
463
+ const handleWaiting = /* @__PURE__ */ __name(() => {
464
+ videoDebug.warn("WAITING - buffering...");
465
+ videoDebug.buffer(video.buffered, video.duration);
466
+ }, "handleWaiting");
467
+ const handleStalled = /* @__PURE__ */ __name(() => {
468
+ videoDebug.warn("STALLED - network issue");
469
+ videoDebug.buffer(video.buffered, video.duration);
470
+ }, "handleStalled");
471
+ video.addEventListener("loadedmetadata", handleLoadedMetadata);
472
+ video.addEventListener("canplay", handleCanPlayDebug);
473
+ video.addEventListener("seeking", handleSeeking);
474
+ video.addEventListener("seeked", handleSeeked);
475
+ video.addEventListener("waiting", handleWaiting);
476
+ video.addEventListener("stalled", handleStalled);
477
+ return () => {
478
+ video.removeEventListener("loadedmetadata", handleLoadedMetadata);
479
+ video.removeEventListener("canplay", handleCanPlayDebug);
480
+ video.removeEventListener("seeking", handleSeeking);
481
+ video.removeEventListener("seeked", handleSeeked);
482
+ video.removeEventListener("waiting", handleWaiting);
483
+ video.removeEventListener("stalled", handleStalled);
484
+ };
485
+ }, [savedSettings.volume]);
486
+ useEffect(() => {
487
+ const video = videoRef.current;
488
+ if (!video) return;
489
+ const handleVolumeChange = /* @__PURE__ */ __name(() => {
490
+ updateVolume(video.volume);
491
+ }, "handleVolumeChange");
492
+ video.addEventListener("volumechange", handleVolumeChange);
493
+ return () => video.removeEventListener("volumechange", handleVolumeChange);
494
+ }, [updateVolume]);
495
+ const handleContextMenu = /* @__PURE__ */ __name((e) => {
496
+ if (disableContextMenu) {
497
+ e.preventDefault();
498
+ }
499
+ }, "handleContextMenu");
500
+ const handleError = /* @__PURE__ */ __name((e) => {
501
+ const video = e.currentTarget;
502
+ const errorMsg = video.error?.message || "Video playback error";
503
+ videoDebug.error("Video error", { code: video.error?.code, message: errorMsg });
504
+ setIsLoading(false);
505
+ onError?.(errorMsg);
506
+ }, "handleError");
507
+ const handleTimeUpdate = /* @__PURE__ */ __name(() => {
508
+ const video = videoRef.current;
509
+ if (video && onTimeUpdate) {
510
+ onTimeUpdate(video.currentTime, video.duration);
511
+ }
512
+ }, "handleTimeUpdate");
513
+ const isFillMode = aspectRatio === "fill";
514
+ const computedAspectRatio = aspectRatio === "auto" || aspectRatio === "fill" ? void 0 : aspectRatio;
515
+ const videoContent = /* @__PURE__ */ jsxs(Fragment, { children: [
516
+ showPreloader && isLoading && /* @__PURE__ */ jsx(
517
+ "div",
518
+ {
519
+ className: cn(
520
+ "absolute inset-0 flex items-center justify-center bg-muted/30 backdrop-blur-sm z-10"
521
+ ),
522
+ children: /* @__PURE__ */ jsx(Preloader, { size: "lg", spinnerClassName: "text-white" })
523
+ }
524
+ ),
525
+ /* @__PURE__ */ jsx(
526
+ "video",
527
+ {
528
+ ref: videoRef,
529
+ className: cn("w-full h-full object-cover", videoClassName),
530
+ src: videoUrl,
531
+ autoPlay,
532
+ muted,
533
+ loop,
534
+ playsInline,
535
+ preload,
536
+ controls,
537
+ poster: source.poster,
538
+ onContextMenu: handleContextMenu,
539
+ onLoadStart,
540
+ onCanPlay,
541
+ onPlay,
542
+ onPause,
543
+ onPlaying: () => setIsLoading(false),
544
+ onEnded,
545
+ onError: handleError,
546
+ onTimeUpdate: handleTimeUpdate
547
+ }
548
+ )
549
+ ] });
550
+ if (isFillMode) {
551
+ return /* @__PURE__ */ jsx("div", { className: cn("relative w-full h-full overflow-hidden", className), children: videoContent });
552
+ }
553
+ return /* @__PURE__ */ jsx("div", { className: cn("relative overflow-hidden", className), children: /* @__PURE__ */ jsx(AspectRatio, { ratio: computedAspectRatio, children: videoContent }) });
554
+ }
555
+ );
556
+ NativeProvider.displayName = "NativeProvider";
557
+ function DefaultErrorFallback2({ error }) {
558
+ return /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 flex flex-col items-center justify-center gap-4 text-white", children: [
559
+ /* @__PURE__ */ jsx(
560
+ "svg",
561
+ {
562
+ className: "w-16 h-16 text-muted-foreground",
563
+ fill: "none",
564
+ stroke: "currentColor",
565
+ viewBox: "0 0 24 24",
566
+ children: /* @__PURE__ */ jsx(
567
+ "path",
568
+ {
569
+ strokeLinecap: "round",
570
+ strokeLinejoin: "round",
571
+ strokeWidth: 2,
572
+ d: "M15 10l4.553-2.276A1 1 0 0121 8.618v6.764a1 1 0 01-1.447.894L15 14M5 18h8a2 2 0 002-2V8a2 2 0 00-2-2H5a2 2 0 00-2 2v8a2 2 0 002 2z"
573
+ }
574
+ )
575
+ }
576
+ ),
577
+ /* @__PURE__ */ jsx("p", { className: "text-lg", children: error || "Video cannot be previewed" })
578
+ ] });
579
+ }
580
+ __name(DefaultErrorFallback2, "DefaultErrorFallback");
581
+ var StreamProvider = forwardRef(
582
+ ({
583
+ source,
584
+ aspectRatio = 16 / 9,
585
+ autoPlay = false,
586
+ muted = false,
587
+ loop = false,
588
+ playsInline = true,
589
+ preload = "metadata",
590
+ controls = true,
591
+ disableContextMenu = false,
592
+ showPreloader = true,
593
+ preloaderTimeout = 1e4,
594
+ className,
595
+ videoClassName,
596
+ errorFallback,
597
+ onPlay,
598
+ onPause,
599
+ onEnded,
600
+ onError,
601
+ onLoadStart,
602
+ onCanPlay,
603
+ onTimeUpdate,
604
+ onBufferProgress
605
+ }, ref) => {
606
+ const [videoUrl, setVideoUrl] = useState(null);
607
+ const [isLoading, setIsLoading] = useState(true);
608
+ const [hasError, setHasError] = useState(false);
609
+ const [errorMessage, setErrorMessage] = useState("Video cannot be previewed");
610
+ const videoRef = useRef(null);
611
+ const contentKeyRef = useRef(null);
612
+ const lastSavedTimeRef = useRef(0);
613
+ const getOrCreateBlobUrl = useMediaCacheStore.getState().getOrCreateBlobUrl;
614
+ const releaseBlobUrl = useMediaCacheStore.getState().releaseBlobUrl;
615
+ const getOrCreateStreamUrl = useMediaCacheStore.getState().getOrCreateStreamUrl;
616
+ const saveVideoPosition = useMediaCacheStore.getState().saveVideoPosition;
617
+ const getVideoPosition = useMediaCacheStore.getState().getVideoPosition;
618
+ const { settings: savedSettings, updateVolume } = useVideoPlayerSettings2();
619
+ const retry = useCallback(() => {
620
+ setHasError(false);
621
+ setIsLoading(true);
622
+ if (source.type === "stream") {
623
+ const streamSource = source;
624
+ const freshUrl = streamSource.getStreamUrl(streamSource.sessionId, streamSource.path);
625
+ setVideoUrl(freshUrl);
626
+ return;
627
+ }
628
+ const video = videoRef.current;
629
+ if (video && videoUrl) {
630
+ video.load();
631
+ }
632
+ }, [source, videoUrl]);
633
+ useImperativeHandle(
634
+ ref,
635
+ () => ({
636
+ play: /* @__PURE__ */ __name(() => videoRef.current?.play(), "play"),
637
+ pause: /* @__PURE__ */ __name(() => videoRef.current?.pause(), "pause"),
638
+ togglePlay: /* @__PURE__ */ __name(() => {
639
+ const video = videoRef.current;
640
+ if (video) {
641
+ video.paused ? video.play() : video.pause();
642
+ }
643
+ }, "togglePlay"),
644
+ seekTo: /* @__PURE__ */ __name((time) => {
645
+ if (videoRef.current) videoRef.current.currentTime = time;
646
+ }, "seekTo"),
647
+ setVolume: /* @__PURE__ */ __name((volume) => {
648
+ if (videoRef.current) videoRef.current.volume = Math.max(0, Math.min(1, volume));
649
+ }, "setVolume"),
650
+ toggleMute: /* @__PURE__ */ __name(() => {
651
+ if (videoRef.current) videoRef.current.muted = !videoRef.current.muted;
652
+ }, "toggleMute"),
653
+ enterFullscreen: /* @__PURE__ */ __name(() => videoRef.current?.requestFullscreen(), "enterFullscreen"),
654
+ exitFullscreen: /* @__PURE__ */ __name(() => document.exitFullscreen(), "exitFullscreen"),
655
+ get currentTime() {
656
+ return videoRef.current?.currentTime ?? 0;
657
+ },
658
+ get duration() {
659
+ return videoRef.current?.duration ?? 0;
660
+ },
661
+ get paused() {
662
+ return videoRef.current?.paused ?? true;
663
+ }
664
+ }),
665
+ []
666
+ );
667
+ const isMountedRef = useRef(true);
668
+ useEffect(() => {
669
+ isMountedRef.current = true;
670
+ return () => {
671
+ isMountedRef.current = false;
672
+ if (contentKeyRef.current) {
673
+ useMediaCacheStore.getState().releaseBlobUrl(contentKeyRef.current);
674
+ contentKeyRef.current = null;
675
+ }
676
+ };
677
+ }, []);
678
+ useEffect(() => {
679
+ if (contentKeyRef.current) {
680
+ const newKey = source.type === "blob" ? generateContentKey(source.data) : null;
681
+ if (newKey !== contentKeyRef.current) {
682
+ releaseBlobUrl(contentKeyRef.current);
683
+ contentKeyRef.current = null;
684
+ }
685
+ }
686
+ setHasError(false);
687
+ setIsLoading(true);
688
+ switch (source.type) {
689
+ case "stream": {
690
+ const streamSource = source;
691
+ const url = getOrCreateStreamUrl(
692
+ streamSource.sessionId,
693
+ streamSource.path,
694
+ streamSource.getStreamUrl
695
+ );
696
+ videoDebug.load(url, "stream");
697
+ setVideoUrl(url);
698
+ break;
699
+ }
700
+ case "blob": {
701
+ const blobSource = source;
702
+ const contentKey = generateContentKey(blobSource.data);
703
+ contentKeyRef.current = contentKey;
704
+ const url = getOrCreateBlobUrl(
705
+ contentKey,
706
+ blobSource.data,
707
+ blobSource.mimeType || "video/mp4"
708
+ );
709
+ videoDebug.load(url, "blob");
710
+ setVideoUrl(url);
711
+ break;
712
+ }
713
+ case "data-url": {
714
+ const dataUrlSource = source;
715
+ videoDebug.load(dataUrlSource.data.slice(0, 50) + "...", "data-url");
716
+ setVideoUrl(dataUrlSource.data);
717
+ break;
718
+ }
719
+ default:
720
+ videoDebug.error("Invalid video source type", { type: source.type });
721
+ setVideoUrl(null);
722
+ setHasError(true);
723
+ setErrorMessage("Invalid video source");
724
+ }
725
+ }, [source]);
726
+ const getSourceKey = useCallback(() => {
727
+ switch (source.type) {
728
+ case "stream":
729
+ return `stream:${source.sessionId}:${source.path}`;
730
+ case "blob":
731
+ return contentKeyRef.current ? `blob:${contentKeyRef.current}` : null;
732
+ case "data-url":
733
+ return `data:${source.data.slice(0, 50)}`;
734
+ default:
735
+ return null;
736
+ }
737
+ }, [source]);
738
+ const handleCanPlay = useCallback(() => {
739
+ const video = videoRef.current;
740
+ if (video) {
741
+ videoDebug.state("canplay", { duration: video.duration, buffered: video.buffered.length });
742
+ videoDebug.buffer(video.buffered, video.duration);
743
+ video.volume = savedSettings.volume;
744
+ }
745
+ setIsLoading(false);
746
+ const sourceKey = getSourceKey();
747
+ if (sourceKey && video) {
748
+ const cachedPosition = getVideoPosition(sourceKey);
749
+ if (cachedPosition && cachedPosition > 0) {
750
+ const duration = video.duration;
751
+ if (cachedPosition < duration - 1) {
752
+ videoDebug.debug(`Restoring position: ${cachedPosition}s`);
753
+ video.currentTime = cachedPosition;
754
+ }
755
+ }
756
+ }
757
+ onCanPlay?.();
758
+ }, [getSourceKey, onCanPlay, savedSettings.volume]);
759
+ const handleTimeUpdate = useCallback(() => {
760
+ const video = videoRef.current;
761
+ if (!video) return;
762
+ const sourceKey = getSourceKey();
763
+ if (sourceKey && video.currentTime > 0) {
764
+ const timeSinceLastSave = video.currentTime - lastSavedTimeRef.current;
765
+ if (timeSinceLastSave >= 5 || timeSinceLastSave < 0) {
766
+ saveVideoPosition(sourceKey, video.currentTime);
767
+ lastSavedTimeRef.current = video.currentTime;
768
+ }
769
+ }
770
+ onTimeUpdate?.(video.currentTime, video.duration);
771
+ }, [getSourceKey, onTimeUpdate]);
772
+ const handlePause = useCallback(() => {
773
+ const video = videoRef.current;
774
+ const sourceKey = getSourceKey();
775
+ if (sourceKey && video && video.currentTime > 0) {
776
+ saveVideoPosition(sourceKey, video.currentTime);
777
+ lastSavedTimeRef.current = video.currentTime;
778
+ }
779
+ onPause?.();
780
+ }, [getSourceKey, onPause]);
781
+ const handleProgress = useCallback(() => {
782
+ const video = videoRef.current;
783
+ if (!video || !onBufferProgress) return;
784
+ if (video.buffered.length > 0) {
785
+ const bufferedEnd = video.buffered.end(video.buffered.length - 1);
786
+ const duration = video.duration;
787
+ if (duration > 0 && !isNaN(bufferedEnd)) {
788
+ onBufferProgress(bufferedEnd, duration);
789
+ }
790
+ }
791
+ }, [onBufferProgress]);
792
+ useEffect(() => {
793
+ if (!showPreloader || !isLoading) return;
794
+ const timeout = setTimeout(() => {
795
+ setIsLoading(false);
796
+ }, preloaderTimeout);
797
+ return () => clearTimeout(timeout);
798
+ }, [showPreloader, isLoading, preloaderTimeout]);
799
+ const handleContextMenu = /* @__PURE__ */ __name((e) => {
800
+ if (disableContextMenu) {
801
+ e.preventDefault();
802
+ }
803
+ }, "handleContextMenu");
804
+ const handleLoadedData = /* @__PURE__ */ __name(() => {
805
+ setIsLoading(false);
806
+ }, "handleLoadedData");
807
+ const handleError = /* @__PURE__ */ __name(() => {
808
+ const video = videoRef.current;
809
+ if (video) {
810
+ videoDebug.error("Video error", { code: video.error?.code, message: video.error?.message });
811
+ }
812
+ setIsLoading(false);
813
+ setHasError(true);
814
+ setErrorMessage("Failed to load video");
815
+ onError?.("Video playback error");
816
+ }, "handleError");
817
+ useEffect(() => {
818
+ const video = videoRef.current;
819
+ if (!video) return;
820
+ const handleLoadedMetadata = /* @__PURE__ */ __name(() => {
821
+ videoDebug.state("loadedmetadata", { duration: video.duration });
822
+ }, "handleLoadedMetadata");
823
+ const handleSeeking = /* @__PURE__ */ __name(() => {
824
+ videoDebug.event("seeking", { currentTime: video.currentTime });
825
+ }, "handleSeeking");
826
+ const handleSeeked = /* @__PURE__ */ __name(() => {
827
+ videoDebug.event("seeked", { currentTime: video.currentTime });
828
+ videoDebug.buffer(video.buffered, video.duration);
829
+ }, "handleSeeked");
830
+ const handleWaiting = /* @__PURE__ */ __name(() => {
831
+ videoDebug.warn("WAITING - buffering...");
832
+ videoDebug.buffer(video.buffered, video.duration);
833
+ }, "handleWaiting");
834
+ const handleStalled = /* @__PURE__ */ __name(() => {
835
+ videoDebug.warn("STALLED - network issue");
836
+ videoDebug.buffer(video.buffered, video.duration);
837
+ }, "handleStalled");
838
+ video.addEventListener("loadedmetadata", handleLoadedMetadata);
839
+ video.addEventListener("seeking", handleSeeking);
840
+ video.addEventListener("seeked", handleSeeked);
841
+ video.addEventListener("waiting", handleWaiting);
842
+ video.addEventListener("stalled", handleStalled);
843
+ return () => {
844
+ video.removeEventListener("loadedmetadata", handleLoadedMetadata);
845
+ video.removeEventListener("seeking", handleSeeking);
846
+ video.removeEventListener("seeked", handleSeeked);
847
+ video.removeEventListener("waiting", handleWaiting);
848
+ video.removeEventListener("stalled", handleStalled);
849
+ };
850
+ }, [videoUrl]);
851
+ useEffect(() => {
852
+ const video = videoRef.current;
853
+ if (!video) return;
854
+ const handleVolumeChange = /* @__PURE__ */ __name(() => {
855
+ updateVolume(video.volume);
856
+ }, "handleVolumeChange");
857
+ video.addEventListener("volumechange", handleVolumeChange);
858
+ return () => video.removeEventListener("volumechange", handleVolumeChange);
859
+ }, [videoUrl, updateVolume]);
860
+ const isFillMode = aspectRatio === "fill";
861
+ const computedAspectRatio = aspectRatio === "auto" || aspectRatio === "fill" ? void 0 : aspectRatio;
862
+ const renderErrorFallback = /* @__PURE__ */ __name(() => {
863
+ const fallbackProps = { error: errorMessage, retry };
864
+ if (typeof errorFallback === "function") {
865
+ return errorFallback(fallbackProps);
866
+ }
867
+ if (errorFallback) {
868
+ return errorFallback;
869
+ }
870
+ return /* @__PURE__ */ jsx(DefaultErrorFallback2, { ...fallbackProps });
871
+ }, "renderErrorFallback");
872
+ if (!videoUrl || hasError) {
873
+ if (isFillMode) {
874
+ return /* @__PURE__ */ jsx("div", { className: cn("relative w-full h-full overflow-hidden bg-black", className), children: renderErrorFallback() });
875
+ }
876
+ return /* @__PURE__ */ jsx("div", { className: cn("relative overflow-hidden bg-black", className), children: /* @__PURE__ */ jsx(AspectRatio, { ratio: computedAspectRatio, children: renderErrorFallback() }) });
877
+ }
878
+ const videoContent = /* @__PURE__ */ jsxs(Fragment, { children: [
879
+ showPreloader && isLoading && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center bg-black/50 z-10", children: /* @__PURE__ */ jsx(Preloader, { size: "lg", spinnerClassName: "text-white" }) }),
880
+ /* @__PURE__ */ jsx(
881
+ "video",
882
+ {
883
+ ref: videoRef,
884
+ src: videoUrl,
885
+ className: cn(
886
+ "w-full h-full object-contain",
887
+ isLoading && "opacity-0",
888
+ videoClassName
889
+ ),
890
+ autoPlay,
891
+ muted,
892
+ loop,
893
+ playsInline,
894
+ preload,
895
+ controls,
896
+ crossOrigin: "anonymous",
897
+ poster: source.poster,
898
+ onContextMenu: handleContextMenu,
899
+ onLoadStart,
900
+ onCanPlay: handleCanPlay,
901
+ onLoadedData: handleLoadedData,
902
+ onPlay,
903
+ onPause: handlePause,
904
+ onEnded,
905
+ onError: handleError,
906
+ onTimeUpdate: handleTimeUpdate,
907
+ onProgress: handleProgress
908
+ }
909
+ )
910
+ ] });
911
+ if (isFillMode) {
912
+ return /* @__PURE__ */ jsx("div", { className: cn("relative w-full h-full overflow-hidden bg-black", className), children: videoContent });
913
+ }
914
+ return /* @__PURE__ */ jsx("div", { className: cn("relative overflow-hidden bg-black", className), children: /* @__PURE__ */ jsx(AspectRatio, { ratio: computedAspectRatio, children: videoContent }) });
915
+ }
916
+ );
917
+ StreamProvider.displayName = "StreamProvider";
918
+ var VideoPlayerContext = createContext(null);
919
+ function VideoPlayerProvider({
920
+ children,
921
+ getStreamUrl,
922
+ sessionId
923
+ }) {
924
+ const value = useMemo(
925
+ () => ({ getStreamUrl, sessionId }),
926
+ [getStreamUrl, sessionId]
927
+ );
928
+ return /* @__PURE__ */ jsx(VideoPlayerContext.Provider, { value, children });
929
+ }
930
+ __name(VideoPlayerProvider, "VideoPlayerProvider");
931
+ function useVideoPlayerContext() {
932
+ return useContext(VideoPlayerContext);
933
+ }
934
+ __name(useVideoPlayerContext, "useVideoPlayerContext");
935
+
936
+ // src/tools/VideoPlayer/utils/resolvers.ts
937
+ function resolvePlayerMode(source, mode = "auto") {
938
+ if (mode !== "auto") {
939
+ return mode;
940
+ }
941
+ switch (source.type) {
942
+ case "youtube":
943
+ case "vimeo":
944
+ case "hls":
945
+ case "dash":
946
+ return "vidstack";
947
+ case "stream":
948
+ case "blob":
949
+ return "streaming";
950
+ case "data-url":
951
+ case "url":
952
+ default:
953
+ return "native";
954
+ }
955
+ }
956
+ __name(resolvePlayerMode, "resolvePlayerMode");
957
+ function isSimpleStreamSource(source) {
958
+ return source.type === "stream" && !("getStreamUrl" in source);
959
+ }
960
+ __name(isSimpleStreamSource, "isSimpleStreamSource");
961
+ function resolveStreamSource(source, context) {
962
+ if (!context?.getStreamUrl) {
963
+ console.warn(
964
+ "VideoPlayer: Stream source requires getStreamUrl. Either provide it in source or wrap with VideoPlayerProvider."
965
+ );
966
+ return null;
967
+ }
968
+ const sessionId = source.sessionId || context.sessionId;
969
+ if (!sessionId) {
970
+ console.warn("VideoPlayer: Stream source requires sessionId.");
971
+ return null;
972
+ }
973
+ return {
974
+ type: "stream",
975
+ sessionId,
976
+ path: source.path,
977
+ getStreamUrl: context.getStreamUrl,
978
+ mimeType: source.mimeType,
979
+ title: source.title,
980
+ poster: source.poster
981
+ };
982
+ }
983
+ __name(resolveStreamSource, "resolveStreamSource");
984
+
985
+ // src/tools/VideoPlayer/utils/fileSource.ts
986
+ function resolveFileSource(options) {
987
+ const {
988
+ content,
989
+ path,
990
+ mimeType,
991
+ sessionId,
992
+ loadMethod,
993
+ getStreamUrl,
994
+ title,
995
+ poster
996
+ } = options;
997
+ const contentSize = content ? typeof content === "string" ? content.length : content.byteLength : 0;
998
+ const hasContent = contentSize > 0;
999
+ if (loadMethod === "http_stream" && !hasContent && sessionId && getStreamUrl) {
1000
+ return {
1001
+ type: "stream",
1002
+ sessionId,
1003
+ path,
1004
+ getStreamUrl,
1005
+ mimeType,
1006
+ title,
1007
+ poster
1008
+ };
1009
+ }
1010
+ if (typeof content === "string" && hasContent) {
1011
+ return {
1012
+ type: "data-url",
1013
+ data: content,
1014
+ title,
1015
+ poster
1016
+ };
1017
+ }
1018
+ if (content instanceof ArrayBuffer && hasContent) {
1019
+ return {
1020
+ type: "blob",
1021
+ data: content,
1022
+ mimeType: mimeType || "video/mp4",
1023
+ title,
1024
+ poster
1025
+ };
1026
+ }
1027
+ return null;
1028
+ }
1029
+ __name(resolveFileSource, "resolveFileSource");
1030
+ var VideoPlayer = forwardRef(
1031
+ ({
1032
+ source: rawSource,
1033
+ mode = "auto",
1034
+ aspectRatio = 16 / 9,
1035
+ autoPlay = false,
1036
+ muted = false,
1037
+ loop = false,
1038
+ playsInline = true,
1039
+ controls = true,
1040
+ preload = "metadata",
1041
+ theme = "default",
1042
+ showInfo = false,
1043
+ className,
1044
+ videoClassName,
1045
+ disableContextMenu = false,
1046
+ showPreloader = true,
1047
+ preloaderTimeout = 5e3,
1048
+ errorFallback,
1049
+ onPlay,
1050
+ onPause,
1051
+ onEnded,
1052
+ onError,
1053
+ onLoadStart,
1054
+ onCanPlay,
1055
+ onTimeUpdate
1056
+ }, ref) => {
1057
+ const context = useVideoPlayerContext();
1058
+ const source = useMemo(() => {
1059
+ if (isSimpleStreamSource(rawSource)) {
1060
+ const resolved = resolveStreamSource(rawSource, context);
1061
+ if (!resolved) {
1062
+ return null;
1063
+ }
1064
+ return resolved;
1065
+ }
1066
+ return rawSource;
1067
+ }, [rawSource, context]);
1068
+ if (!source) {
1069
+ const errorMessage = "Stream source requires VideoPlayerProvider with getStreamUrl and sessionId";
1070
+ if (typeof errorFallback === "function") {
1071
+ return /* @__PURE__ */ jsx("div", { className, style: { aspectRatio: aspectRatio === "fill" ? void 0 : aspectRatio }, children: errorFallback({ error: errorMessage }) });
1072
+ }
1073
+ if (errorFallback) {
1074
+ return /* @__PURE__ */ jsx("div", { className, style: { aspectRatio: aspectRatio === "fill" ? void 0 : aspectRatio }, children: errorFallback });
1075
+ }
1076
+ return /* @__PURE__ */ jsx(
1077
+ "div",
1078
+ {
1079
+ className,
1080
+ style: {
1081
+ aspectRatio: aspectRatio === "fill" ? void 0 : aspectRatio,
1082
+ display: "flex",
1083
+ alignItems: "center",
1084
+ justifyContent: "center",
1085
+ backgroundColor: "black",
1086
+ color: "white"
1087
+ },
1088
+ children: /* @__PURE__ */ jsx("p", { children: errorMessage })
1089
+ }
1090
+ );
1091
+ }
1092
+ const resolvedMode = resolvePlayerMode(source, mode);
1093
+ const commonProps = {
1094
+ aspectRatio,
1095
+ autoPlay,
1096
+ muted,
1097
+ loop,
1098
+ playsInline,
1099
+ controls,
1100
+ preload,
1101
+ className,
1102
+ onPlay,
1103
+ onPause,
1104
+ onEnded,
1105
+ onError,
1106
+ onLoadStart,
1107
+ onCanPlay,
1108
+ onTimeUpdate
1109
+ };
1110
+ switch (resolvedMode) {
1111
+ case "vidstack":
1112
+ return /* @__PURE__ */ jsx(
1113
+ VidstackProvider,
1114
+ {
1115
+ ref,
1116
+ source,
1117
+ theme,
1118
+ showInfo,
1119
+ errorFallback,
1120
+ ...commonProps
1121
+ }
1122
+ );
1123
+ case "streaming":
1124
+ return /* @__PURE__ */ jsx(
1125
+ StreamProvider,
1126
+ {
1127
+ ref,
1128
+ source,
1129
+ videoClassName,
1130
+ disableContextMenu,
1131
+ showPreloader,
1132
+ preloaderTimeout,
1133
+ errorFallback,
1134
+ ...commonProps
1135
+ }
1136
+ );
1137
+ case "native":
1138
+ default:
1139
+ return /* @__PURE__ */ jsx(
1140
+ NativeProvider,
1141
+ {
1142
+ ref,
1143
+ source,
1144
+ videoClassName,
1145
+ disableContextMenu,
1146
+ showPreloader,
1147
+ preloaderTimeout,
1148
+ ...commonProps
1149
+ }
1150
+ );
1151
+ }
1152
+ }
1153
+ );
1154
+ VideoPlayer.displayName = "VideoPlayer";
1155
+ function VideoControls({ player, className }) {
1156
+ const store = useMediaStore(player);
1157
+ const remote = useMediaRemote();
1158
+ const isPaused = store.paused;
1159
+ const isMuted = store.muted;
1160
+ const isFullscreen = store.fullscreen;
1161
+ const currentTime = store.currentTime;
1162
+ const duration = store.duration;
1163
+ const volume = store.volume;
1164
+ const formatTime = /* @__PURE__ */ __name((seconds) => {
1165
+ if (!seconds || seconds < 0) return "0:00";
1166
+ const minutes = Math.floor(seconds / 60);
1167
+ const secs = Math.floor(seconds % 60);
1168
+ return `${minutes}:${secs.toString().padStart(2, "0")}`;
1169
+ }, "formatTime");
1170
+ const handleProgressClick = /* @__PURE__ */ __name((e) => {
1171
+ if (!duration) return;
1172
+ const rect = e.currentTarget.getBoundingClientRect();
1173
+ const clickX = e.clientX - rect.left;
1174
+ const percentage = clickX / rect.width;
1175
+ const newTime = percentage * duration;
1176
+ remote.seek(newTime);
1177
+ }, "handleProgressClick");
1178
+ const handleVolumeChange = /* @__PURE__ */ __name((e) => {
1179
+ const rect = e.currentTarget.getBoundingClientRect();
1180
+ const clickX = e.clientX - rect.left;
1181
+ const percentage = Math.max(0, Math.min(1, clickX / rect.width));
1182
+ remote.changeVolume(percentage);
1183
+ if (percentage > 0 && isMuted) {
1184
+ remote.toggleMuted();
1185
+ }
1186
+ }, "handleVolumeChange");
1187
+ const progress = duration > 0 ? currentTime / duration * 100 : 0;
1188
+ return /* @__PURE__ */ jsxs(
1189
+ "div",
1190
+ {
1191
+ className: cn(
1192
+ "absolute inset-0 flex flex-col justify-end transition-opacity duration-300",
1193
+ "bg-gradient-to-t from-black/80 via-black/20 to-transparent",
1194
+ "opacity-0 group-hover:opacity-100 focus-within:opacity-100",
1195
+ "pointer-events-none group-hover:pointer-events-auto",
1196
+ className
1197
+ ),
1198
+ children: [
1199
+ /* @__PURE__ */ jsx("div", { className: "px-4 pb-2 pointer-events-auto", children: /* @__PURE__ */ jsx(
1200
+ "div",
1201
+ {
1202
+ className: "h-1.5 bg-white/20 rounded-full cursor-pointer hover:h-2 transition-all group",
1203
+ onClick: handleProgressClick,
1204
+ children: /* @__PURE__ */ jsx(
1205
+ "div",
1206
+ {
1207
+ className: "h-full bg-primary rounded-full transition-all relative group-hover:bg-primary/90",
1208
+ style: { width: `${progress}%` },
1209
+ children: /* @__PURE__ */ jsx("div", { className: "absolute right-0 top-1/2 -translate-y-1/2 w-3 h-3 bg-white rounded-full opacity-0 group-hover:opacity-100 transition-opacity" })
1210
+ }
1211
+ )
1212
+ }
1213
+ ) }),
1214
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 px-4 pb-4 pointer-events-auto", children: [
1215
+ /* @__PURE__ */ jsx(
1216
+ "button",
1217
+ {
1218
+ onClick: () => remote.togglePaused(),
1219
+ className: "text-white hover:text-primary transition-colors p-1.5 hover:bg-white/10 rounded-full",
1220
+ children: isPaused ? /* @__PURE__ */ jsx(Play, { className: "h-6 w-6" }) : /* @__PURE__ */ jsx(Pause, { className: "h-6 w-6" })
1221
+ }
1222
+ ),
1223
+ /* @__PURE__ */ jsxs("div", { className: "text-white text-sm font-medium", children: [
1224
+ formatTime(currentTime),
1225
+ " / ",
1226
+ formatTime(duration)
1227
+ ] }),
1228
+ /* @__PURE__ */ jsx("div", { className: "flex-1" }),
1229
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 group/volume", children: [
1230
+ /* @__PURE__ */ jsx(
1231
+ "button",
1232
+ {
1233
+ onClick: () => remote.toggleMuted(),
1234
+ className: "text-white hover:text-primary transition-colors p-1.5 hover:bg-white/10 rounded-full",
1235
+ children: isMuted || volume === 0 ? /* @__PURE__ */ jsx(VolumeX, { className: "h-5 w-5" }) : /* @__PURE__ */ jsx(Volume2, { className: "h-5 w-5" })
1236
+ }
1237
+ ),
1238
+ /* @__PURE__ */ jsx(
1239
+ "div",
1240
+ {
1241
+ className: "w-0 group-hover/volume:w-20 transition-all overflow-hidden",
1242
+ children: /* @__PURE__ */ jsx(
1243
+ "div",
1244
+ {
1245
+ className: "h-1.5 bg-white/20 rounded-full cursor-pointer hover:h-2 transition-all",
1246
+ onClick: handleVolumeChange,
1247
+ children: /* @__PURE__ */ jsx(
1248
+ "div",
1249
+ {
1250
+ className: "h-full bg-white rounded-full transition-all",
1251
+ style: { width: `${volume * 100}%` }
1252
+ }
1253
+ )
1254
+ }
1255
+ )
1256
+ }
1257
+ )
1258
+ ] }),
1259
+ /* @__PURE__ */ jsx(
1260
+ "button",
1261
+ {
1262
+ onClick: () => isFullscreen ? remote.exitFullscreen() : remote.enterFullscreen(),
1263
+ className: "text-white hover:text-primary transition-colors p-1.5 hover:bg-white/10 rounded-full",
1264
+ children: isFullscreen ? /* @__PURE__ */ jsx(Minimize, { className: "h-5 w-5" }) : /* @__PURE__ */ jsx(Maximize, { className: "h-5 w-5" })
1265
+ }
1266
+ )
1267
+ ] })
1268
+ ]
1269
+ }
1270
+ );
1271
+ }
1272
+ __name(VideoControls, "VideoControls");
1273
+ function VideoErrorFallback({
1274
+ error,
1275
+ retry,
1276
+ downloadUrl,
1277
+ downloadFilename,
1278
+ fileSize,
1279
+ showRetry = true,
1280
+ className,
1281
+ icon,
1282
+ title,
1283
+ description
1284
+ }) {
1285
+ const displayTitle = title || error || "Video cannot be previewed";
1286
+ return /* @__PURE__ */ jsxs(
1287
+ "div",
1288
+ {
1289
+ className: cn$1(
1290
+ "absolute inset-0 flex flex-col items-center justify-center gap-4 bg-black/90 text-white p-6",
1291
+ className
1292
+ ),
1293
+ children: [
1294
+ icon || /* @__PURE__ */ jsx(FileVideo, { className: "w-16 h-16 text-muted-foreground" }),
1295
+ /* @__PURE__ */ jsx("p", { className: "text-lg font-medium text-center", children: displayTitle }),
1296
+ (description || fileSize) && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground text-center", children: description || fileSize }),
1297
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mt-2", children: [
1298
+ showRetry && retry && /* @__PURE__ */ jsxs(
1299
+ Button,
1300
+ {
1301
+ variant: "outline",
1302
+ size: "sm",
1303
+ onClick: retry,
1304
+ className: "gap-2",
1305
+ children: [
1306
+ /* @__PURE__ */ jsx(RefreshCw, { className: "w-4 h-4" }),
1307
+ "Retry"
1308
+ ]
1309
+ }
1310
+ ),
1311
+ downloadUrl && /* @__PURE__ */ jsx(
1312
+ DownloadButton,
1313
+ {
1314
+ url: downloadUrl,
1315
+ filename: downloadFilename,
1316
+ variant: "default",
1317
+ size: "sm",
1318
+ children: "Download to view"
1319
+ }
1320
+ )
1321
+ ] })
1322
+ ]
1323
+ }
1324
+ );
1325
+ }
1326
+ __name(VideoErrorFallback, "VideoErrorFallback");
1327
+ function createVideoErrorFallback(options) {
1328
+ return (props, source) => /* @__PURE__ */ jsx(
1329
+ VideoErrorFallback,
1330
+ {
1331
+ ...props,
1332
+ downloadUrl: options.getDownloadUrl?.(source),
1333
+ downloadFilename: options.getFilename?.(source),
1334
+ fileSize: options.getFileSize?.(source),
1335
+ showRetry: options.showRetry
1336
+ }
1337
+ );
1338
+ }
1339
+ __name(createVideoErrorFallback, "createVideoErrorFallback");
1340
+
1341
+ export { NativeProvider, StreamProvider, VideoControls, VideoErrorFallback, VideoPlayer, VideoPlayerProvider, VidstackProvider, createVideoErrorFallback, isSimpleStreamSource, resolveFileSource, resolvePlayerMode, resolveStreamSource, useVideoPlayerContext };
1342
+ //# sourceMappingURL=chunk-UOMPPIED.mjs.map
1343
+ //# sourceMappingURL=chunk-UOMPPIED.mjs.map