@djangocfg/ui-tools 2.1.110 → 2.1.111

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,1494 @@
1
+ import { cn as cn$1, Button, Slider, useLocalStorage } from './chunk-JWB2EWQO.mjs';
2
+ import { __name } from './chunk-CGILA3WO.mjs';
3
+ import { createContext, memo, useRef, useCallback, useEffect, useMemo, useState, useContext } from 'react';
4
+ import { Loader2, RotateCcw, SkipBack, Pause, Play, SkipForward, VolumeX, Volume2, Repeat, Music } from 'lucide-react';
5
+ import { useTypedT } from '@djangocfg/i18n';
6
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
+ import { cn, createMediaLogger } from '@djangocfg/ui-core/lib';
8
+ import { cn as cn$2 } from '@djangocfg/ui-core';
9
+
10
+ function useHybridAudio(options) {
11
+ const {
12
+ src,
13
+ autoPlay = false,
14
+ initialVolume = 1,
15
+ loop = false,
16
+ crossOrigin = "anonymous",
17
+ onPlay,
18
+ onPause,
19
+ onEnded,
20
+ onTimeUpdate,
21
+ onError,
22
+ onReady
23
+ } = options;
24
+ const audioRef = useRef(null);
25
+ const audioContextRef = useRef(null);
26
+ const sourceNodeRef = useRef(null);
27
+ const analyserRef = useRef(null);
28
+ const connectedElementRef = useRef(null);
29
+ const [state, setState] = useState({
30
+ isReady: false,
31
+ isPlaying: false,
32
+ currentTime: 0,
33
+ duration: 0,
34
+ volume: initialVolume,
35
+ isMuted: false,
36
+ isLooping: loop,
37
+ buffered: null,
38
+ error: null
39
+ });
40
+ const initWebAudio = useCallback(() => {
41
+ const audio = audioRef.current;
42
+ if (!audio) return;
43
+ if (connectedElementRef.current === audio && audioContextRef.current) {
44
+ return;
45
+ }
46
+ try {
47
+ if (!audioContextRef.current) {
48
+ const AudioContextClass = window.AudioContext || window.webkitAudioContext;
49
+ audioContextRef.current = new AudioContextClass();
50
+ }
51
+ const ctx = audioContextRef.current;
52
+ if (sourceNodeRef.current) {
53
+ try {
54
+ sourceNodeRef.current.disconnect();
55
+ } catch {
56
+ }
57
+ }
58
+ const source = ctx.createMediaElementSource(audio);
59
+ sourceNodeRef.current = source;
60
+ const analyser = ctx.createAnalyser();
61
+ analyser.fftSize = 256;
62
+ analyser.smoothingTimeConstant = 0.85;
63
+ analyserRef.current = analyser;
64
+ source.connect(ctx.destination);
65
+ source.connect(analyser);
66
+ connectedElementRef.current = audio;
67
+ } catch (error) {
68
+ console.warn("[useHybridAudio] Web Audio init failed:", error);
69
+ }
70
+ }, []);
71
+ const resumeAudioContext = useCallback(async () => {
72
+ const ctx = audioContextRef.current;
73
+ if (ctx && ctx.state === "suspended") {
74
+ await ctx.resume();
75
+ }
76
+ }, []);
77
+ const play = useCallback(async () => {
78
+ const audio = audioRef.current;
79
+ if (!audio) return;
80
+ try {
81
+ initWebAudio();
82
+ await resumeAudioContext();
83
+ await audio.play();
84
+ } catch (error) {
85
+ console.error("[useHybridAudio] Play failed:", error);
86
+ onError?.(error);
87
+ }
88
+ }, [initWebAudio, resumeAudioContext, onError]);
89
+ const pause = useCallback(() => {
90
+ audioRef.current?.pause();
91
+ }, []);
92
+ const togglePlay = useCallback(() => {
93
+ if (state.isPlaying) {
94
+ pause();
95
+ } else {
96
+ play();
97
+ }
98
+ }, [state.isPlaying, play, pause]);
99
+ const seek = useCallback(
100
+ (time) => {
101
+ const audio = audioRef.current;
102
+ if (audio && isFinite(time)) {
103
+ audio.currentTime = Math.max(0, Math.min(time, state.duration || audio.duration || 0));
104
+ }
105
+ },
106
+ [state.duration]
107
+ );
108
+ const seekTo = useCallback(
109
+ (progress) => {
110
+ const duration = state.duration || audioRef.current?.duration || 0;
111
+ seek(duration * Math.max(0, Math.min(1, progress)));
112
+ },
113
+ [state.duration, seek]
114
+ );
115
+ const skip = useCallback(
116
+ (seconds) => {
117
+ seek(state.currentTime + seconds);
118
+ },
119
+ [state.currentTime, seek]
120
+ );
121
+ const setVolume = useCallback((vol) => {
122
+ const audio = audioRef.current;
123
+ if (audio) {
124
+ const clampedVol = Math.max(0, Math.min(1, vol));
125
+ audio.volume = clampedVol;
126
+ setState((prev) => ({ ...prev, volume: clampedVol }));
127
+ }
128
+ }, []);
129
+ const toggleMute = useCallback(() => {
130
+ const audio = audioRef.current;
131
+ if (audio) {
132
+ audio.muted = !audio.muted;
133
+ setState((prev) => ({ ...prev, isMuted: audio.muted }));
134
+ }
135
+ }, []);
136
+ const toggleLoop = useCallback(() => {
137
+ const audio = audioRef.current;
138
+ if (audio) {
139
+ audio.loop = !audio.loop;
140
+ setState((prev) => ({ ...prev, isLooping: audio.loop }));
141
+ }
142
+ }, []);
143
+ const setLoop = useCallback((enabled) => {
144
+ const audio = audioRef.current;
145
+ if (audio) {
146
+ audio.loop = enabled;
147
+ setState((prev) => ({ ...prev, isLooping: enabled }));
148
+ }
149
+ }, []);
150
+ const restart = useCallback(() => {
151
+ seek(0);
152
+ play();
153
+ }, [seek, play]);
154
+ const controls = {
155
+ play,
156
+ pause,
157
+ togglePlay,
158
+ seek,
159
+ seekTo,
160
+ skip,
161
+ setVolume,
162
+ toggleMute,
163
+ toggleLoop,
164
+ setLoop,
165
+ restart
166
+ };
167
+ useEffect(() => {
168
+ const audio = document.createElement("audio");
169
+ audio.preload = "metadata";
170
+ audio.crossOrigin = crossOrigin;
171
+ audio.volume = initialVolume;
172
+ audio.loop = loop;
173
+ audioRef.current = audio;
174
+ return () => {
175
+ audio.pause();
176
+ audio.src = "";
177
+ if (audioContextRef.current) {
178
+ audioContextRef.current.close().catch(() => {
179
+ });
180
+ }
181
+ };
182
+ }, []);
183
+ useEffect(() => {
184
+ const audio = audioRef.current;
185
+ if (!audio) return;
186
+ const handlers = {
187
+ loadedmetadata: /* @__PURE__ */ __name(() => {
188
+ setState((prev) => ({
189
+ ...prev,
190
+ duration: audio.duration,
191
+ isReady: true
192
+ }));
193
+ onReady?.();
194
+ }, "loadedmetadata"),
195
+ canplay: /* @__PURE__ */ __name(() => {
196
+ setState((prev) => ({ ...prev, isReady: true }));
197
+ if (autoPlay) {
198
+ play();
199
+ }
200
+ }, "canplay"),
201
+ play: /* @__PURE__ */ __name(() => {
202
+ setState((prev) => ({ ...prev, isPlaying: true }));
203
+ onPlay?.();
204
+ }, "play"),
205
+ pause: /* @__PURE__ */ __name(() => {
206
+ setState((prev) => ({ ...prev, isPlaying: false }));
207
+ onPause?.();
208
+ }, "pause"),
209
+ ended: /* @__PURE__ */ __name(() => {
210
+ setState((prev) => ({ ...prev, isPlaying: false }));
211
+ onEnded?.();
212
+ }, "ended"),
213
+ timeupdate: /* @__PURE__ */ __name(() => {
214
+ setState((prev) => ({ ...prev, currentTime: audio.currentTime }));
215
+ onTimeUpdate?.(audio.currentTime);
216
+ }, "timeupdate"),
217
+ progress: /* @__PURE__ */ __name(() => {
218
+ setState((prev) => ({ ...prev, buffered: audio.buffered }));
219
+ }, "progress"),
220
+ error: /* @__PURE__ */ __name(() => {
221
+ const error = new Error(audio.error?.message || "Audio error");
222
+ setState((prev) => ({ ...prev, error }));
223
+ onError?.(error);
224
+ }, "error"),
225
+ volumechange: /* @__PURE__ */ __name(() => {
226
+ setState((prev) => ({
227
+ ...prev,
228
+ volume: audio.volume,
229
+ isMuted: audio.muted
230
+ }));
231
+ }, "volumechange")
232
+ };
233
+ Object.entries(handlers).forEach(([event, handler]) => {
234
+ audio.addEventListener(event, handler);
235
+ });
236
+ return () => {
237
+ Object.entries(handlers).forEach(([event, handler]) => {
238
+ audio.removeEventListener(event, handler);
239
+ });
240
+ };
241
+ }, [autoPlay, onPlay, onPause, onEnded, onTimeUpdate, onError, onReady, play]);
242
+ useEffect(() => {
243
+ const audio = audioRef.current;
244
+ if (!audio || !src) return;
245
+ setState((prev) => ({
246
+ ...prev,
247
+ isReady: false,
248
+ currentTime: 0,
249
+ duration: 0,
250
+ error: null
251
+ }));
252
+ audio.src = src;
253
+ audio.load();
254
+ }, [src]);
255
+ return {
256
+ audioRef,
257
+ state,
258
+ controls,
259
+ webAudio: {
260
+ context: audioContextRef.current,
261
+ analyser: analyserRef.current,
262
+ sourceNode: sourceNodeRef.current
263
+ }
264
+ };
265
+ }
266
+ __name(useHybridAudio, "useHybridAudio");
267
+ function useHybridAudioAnalysis(analyser, isPlaying) {
268
+ const [levels, setLevels] = useState({ bass: 0, mid: 0, high: 0, overall: 0 });
269
+ const animationRef = useRef(null);
270
+ const dataArrayRef = useRef(null);
271
+ const cleanup = useCallback(() => {
272
+ if (animationRef.current) {
273
+ cancelAnimationFrame(animationRef.current);
274
+ animationRef.current = null;
275
+ }
276
+ }, []);
277
+ useEffect(() => {
278
+ if (analyser && !dataArrayRef.current) {
279
+ dataArrayRef.current = new Uint8Array(analyser.frequencyBinCount);
280
+ }
281
+ }, [analyser]);
282
+ useEffect(() => {
283
+ if (!isPlaying || !analyser || !dataArrayRef.current) {
284
+ cleanup();
285
+ setLevels((prev) => ({
286
+ bass: prev.bass * 0.95 < 0.01 ? 0 : prev.bass * 0.95,
287
+ mid: prev.mid * 0.95 < 0.01 ? 0 : prev.mid * 0.95,
288
+ high: prev.high * 0.95 < 0.01 ? 0 : prev.high * 0.95,
289
+ overall: prev.overall * 0.95 < 0.01 ? 0 : prev.overall * 0.95
290
+ }));
291
+ return;
292
+ }
293
+ const dataArray = dataArrayRef.current;
294
+ const animate = /* @__PURE__ */ __name(() => {
295
+ analyser.getByteFrequencyData(dataArray);
296
+ const binCount = dataArray.length;
297
+ const bassEnd = Math.floor(binCount * 0.15);
298
+ let bassSum = 0;
299
+ for (let i = 0; i < bassEnd; i++) bassSum += dataArray[i];
300
+ const bass = bassSum / bassEnd / 255;
301
+ const midStart = bassEnd;
302
+ const midEnd = Math.floor(binCount * 0.5);
303
+ let midSum = 0;
304
+ for (let i = midStart; i < midEnd; i++) midSum += dataArray[i];
305
+ const mid = midSum / (midEnd - midStart) / 255;
306
+ const highStart = midEnd;
307
+ let highSum = 0;
308
+ for (let i = highStart; i < binCount; i++) highSum += dataArray[i];
309
+ const high = highSum / (binCount - highStart) / 255;
310
+ let totalSum = 0;
311
+ for (let i = 0; i < binCount; i++) totalSum += dataArray[i];
312
+ const overall = totalSum / binCount / 255;
313
+ setLevels((prev) => ({
314
+ bass: prev.bass * 0.7 + bass * 0.3,
315
+ mid: prev.mid * 0.7 + mid * 0.3,
316
+ high: prev.high * 0.7 + high * 0.3,
317
+ overall: prev.overall * 0.7 + overall * 0.3
318
+ }));
319
+ animationRef.current = requestAnimationFrame(animate);
320
+ }, "animate");
321
+ animationRef.current = requestAnimationFrame(animate);
322
+ return cleanup;
323
+ }, [analyser, isPlaying, cleanup]);
324
+ return levels;
325
+ }
326
+ __name(useHybridAudioAnalysis, "useHybridAudioAnalysis");
327
+ var STORAGE_KEY = "audio-player-settings";
328
+ var DEFAULT_SETTINGS = {
329
+ enabled: true,
330
+ variant: "spotlight",
331
+ intensity: "medium",
332
+ colorScheme: "primary",
333
+ volume: 1,
334
+ isLooping: false
335
+ };
336
+ var VARIANTS = ["spotlight", "glow", "orbs", "mesh", "none"];
337
+ var INTENSITIES = ["subtle", "medium", "strong"];
338
+ var COLOR_SCHEMES = ["primary", "vibrant", "cool", "warm"];
339
+ var VisualizationContext = createContext(null);
340
+ function VisualizationProvider({ children }) {
341
+ const value = useVisualizationState();
342
+ return /* @__PURE__ */ jsx(VisualizationContext.Provider, { value, children });
343
+ }
344
+ __name(VisualizationProvider, "VisualizationProvider");
345
+ function useVisualizationState() {
346
+ const [settings, setSettings] = useLocalStorage(
347
+ STORAGE_KEY,
348
+ DEFAULT_SETTINGS
349
+ );
350
+ const toggle = useCallback(() => {
351
+ setSettings((prev) => ({ ...prev, enabled: !prev.enabled }));
352
+ }, [setSettings]);
353
+ const setSetting = useCallback(
354
+ (key, value) => {
355
+ setSettings((prev) => ({ ...prev, [key]: value }));
356
+ },
357
+ [setSettings]
358
+ );
359
+ const nextVariant = useCallback(() => {
360
+ setSettings((prev) => {
361
+ const currentIndex = VARIANTS.indexOf(prev.variant);
362
+ const nextIndex = (currentIndex + 1) % VARIANTS.length;
363
+ return { ...prev, variant: VARIANTS[nextIndex] };
364
+ });
365
+ }, [setSettings]);
366
+ const nextIntensity = useCallback(() => {
367
+ setSettings((prev) => {
368
+ const currentIndex = INTENSITIES.indexOf(prev.intensity);
369
+ const nextIndex = (currentIndex + 1) % INTENSITIES.length;
370
+ return { ...prev, intensity: INTENSITIES[nextIndex] };
371
+ });
372
+ }, [setSettings]);
373
+ const nextColorScheme = useCallback(() => {
374
+ setSettings((prev) => {
375
+ const currentIndex = COLOR_SCHEMES.indexOf(prev.colorScheme);
376
+ const nextIndex = (currentIndex + 1) % COLOR_SCHEMES.length;
377
+ return { ...prev, colorScheme: COLOR_SCHEMES[nextIndex] };
378
+ });
379
+ }, [setSettings]);
380
+ const reset = useCallback(() => {
381
+ setSettings(DEFAULT_SETTINGS);
382
+ }, [setSettings]);
383
+ return useMemo(
384
+ () => ({
385
+ settings,
386
+ toggle,
387
+ setSetting,
388
+ nextVariant,
389
+ nextIntensity,
390
+ nextColorScheme,
391
+ reset
392
+ }),
393
+ [settings, toggle, setSetting, nextVariant, nextIntensity, nextColorScheme, reset]
394
+ );
395
+ }
396
+ __name(useVisualizationState, "useVisualizationState");
397
+ function useVisualization() {
398
+ const context = useContext(VisualizationContext);
399
+ const fallbackState = useVisualizationState();
400
+ return context ?? fallbackState;
401
+ }
402
+ __name(useVisualization, "useVisualization");
403
+ var useAudioVisualization = useVisualization;
404
+ var VARIANT_INFO = {
405
+ spotlight: { label: "Spotlight", icon: "\u{1F4AB}" },
406
+ glow: { label: "Glow", icon: "\u2728" },
407
+ orbs: { label: "Orbs", icon: "\u{1F52E}" },
408
+ mesh: { label: "Mesh", icon: "\u{1F308}" },
409
+ none: { label: "Off", icon: "\u2B55" }
410
+ };
411
+ var INTENSITY_INFO = {
412
+ subtle: { label: "Subtle" },
413
+ medium: { label: "Medium" },
414
+ strong: { label: "Strong" }
415
+ };
416
+ var COLOR_SCHEME_INFO = {
417
+ primary: { label: "Primary", preview: "\u{1F535}" },
418
+ vibrant: { label: "Vibrant", preview: "\u{1F308}" },
419
+ cool: { label: "Cool", preview: "\u{1F499}" },
420
+ warm: { label: "Warm", preview: "\u{1F525}" }
421
+ };
422
+ var HybridAudioContext = createContext(null);
423
+ function HybridAudioProvider({ children, ...options }) {
424
+ const { settings: savedSettings, setSetting } = useVisualization();
425
+ const effectiveOptions = {
426
+ ...options,
427
+ initialVolume: savedSettings.volume,
428
+ loop: savedSettings.isLooping
429
+ };
430
+ const { audioRef, state, controls, webAudio } = useHybridAudio(effectiveOptions);
431
+ const hasAppliedInitialSettings = useRef(false);
432
+ useEffect(() => {
433
+ if (!state.isReady || hasAppliedInitialSettings.current) return;
434
+ hasAppliedInitialSettings.current = true;
435
+ controls.setVolume(savedSettings.volume);
436
+ controls.setLoop(savedSettings.isLooping);
437
+ }, [state.isReady, savedSettings, controls]);
438
+ useEffect(() => {
439
+ if (!state.isReady) return;
440
+ if (state.volume !== savedSettings.volume) {
441
+ setSetting("volume", state.volume);
442
+ }
443
+ if (state.isLooping !== savedSettings.isLooping) {
444
+ setSetting("isLooping", state.isLooping);
445
+ }
446
+ }, [state.isReady, state.volume, state.isLooping, savedSettings, setSetting]);
447
+ const audioLevels = useHybridAudioAnalysis(webAudio.analyser, state.isPlaying);
448
+ const value = useMemo(
449
+ () => ({
450
+ state,
451
+ controls,
452
+ webAudio,
453
+ audioLevels,
454
+ audioRef
455
+ }),
456
+ [state, controls, webAudio, audioLevels, audioRef]
457
+ );
458
+ return /* @__PURE__ */ jsx(HybridAudioContext.Provider, { value, children });
459
+ }
460
+ __name(HybridAudioProvider, "HybridAudioProvider");
461
+ function useHybridAudioContext() {
462
+ const context = useContext(HybridAudioContext);
463
+ if (!context) {
464
+ throw new Error("useHybridAudioContext must be used within HybridAudioProvider");
465
+ }
466
+ return context;
467
+ }
468
+ __name(useHybridAudioContext, "useHybridAudioContext");
469
+ function useHybridAudioState() {
470
+ const { state } = useHybridAudioContext();
471
+ return state;
472
+ }
473
+ __name(useHybridAudioState, "useHybridAudioState");
474
+ function useHybridAudioControls() {
475
+ const { controls } = useHybridAudioContext();
476
+ return controls;
477
+ }
478
+ __name(useHybridAudioControls, "useHybridAudioControls");
479
+ function useHybridAudioLevels() {
480
+ const { audioLevels } = useHybridAudioContext();
481
+ return audioLevels;
482
+ }
483
+ __name(useHybridAudioLevels, "useHybridAudioLevels");
484
+ function useHybridWebAudio() {
485
+ const { webAudio } = useHybridAudioContext();
486
+ return webAudio;
487
+ }
488
+ __name(useHybridWebAudio, "useHybridWebAudio");
489
+ var HybridWaveform = memo(/* @__PURE__ */ __name(function HybridWaveform2({
490
+ mode = "frequency",
491
+ height = 64,
492
+ barWidth = 3,
493
+ barGap = 2,
494
+ barRadius = 2,
495
+ progressColor = "hsl(217 91% 60%)",
496
+ waveColor = "hsl(217 91% 60% / 0.3)",
497
+ bufferedColor = "hsl(217 91% 60% / 0.15)",
498
+ className,
499
+ onSeek
500
+ }) {
501
+ const canvasRef = useRef(null);
502
+ const containerRef = useRef(null);
503
+ const animationRef = useRef(null);
504
+ const { state, controls, webAudio } = useHybridAudioContext();
505
+ const handleClick = useCallback(
506
+ (e) => {
507
+ const canvas = canvasRef.current;
508
+ if (!canvas || !state.duration) return;
509
+ const rect = canvas.getBoundingClientRect();
510
+ const x = e.clientX - rect.left;
511
+ const progress = x / rect.width;
512
+ const time = state.duration * progress;
513
+ controls.seek(time);
514
+ onSeek?.(time);
515
+ },
516
+ [state.duration, controls, onSeek]
517
+ );
518
+ const renderFrequency = useCallback(() => {
519
+ const canvas = canvasRef.current;
520
+ const analyser = webAudio.analyser;
521
+ if (!canvas) return;
522
+ const ctx = canvas.getContext("2d");
523
+ if (!ctx) return;
524
+ const { width, height: canvasHeight } = canvas;
525
+ const dpr = window.devicePixelRatio || 1;
526
+ const displayWidth = width / dpr;
527
+ let dataArray = null;
528
+ if (analyser) {
529
+ dataArray = new Uint8Array(analyser.frequencyBinCount);
530
+ analyser.getByteFrequencyData(dataArray);
531
+ }
532
+ ctx.clearRect(0, 0, width, canvasHeight);
533
+ if (state.buffered && state.duration > 0) {
534
+ ctx.fillStyle = bufferedColor;
535
+ for (let i = 0; i < state.buffered.length; i++) {
536
+ const start = state.buffered.start(i) / state.duration * width;
537
+ const end = state.buffered.end(i) / state.duration * width;
538
+ ctx.fillRect(start, canvasHeight - 3 * dpr, end - start, 3 * dpr);
539
+ }
540
+ }
541
+ const barCount = Math.floor(displayWidth / (barWidth + barGap));
542
+ const progress = state.duration > 0 ? state.currentTime / state.duration : 0;
543
+ const progressX = width * progress;
544
+ for (let i = 0; i < barCount; i++) {
545
+ let barHeight;
546
+ if (dataArray && state.isPlaying) {
547
+ const step = Math.floor(dataArray.length / barCount);
548
+ const value = dataArray[i * step] / 255;
549
+ barHeight = Math.max(4 * dpr, value * (canvasHeight - 6 * dpr) * 0.9);
550
+ } else {
551
+ barHeight = 8 * dpr;
552
+ }
553
+ const x = i * (barWidth + barGap) * dpr;
554
+ const y = (canvasHeight - barHeight) / 2;
555
+ ctx.fillStyle = x < progressX ? progressColor : waveColor;
556
+ const radius = barRadius * dpr;
557
+ const rectWidth = barWidth * dpr;
558
+ ctx.beginPath();
559
+ ctx.roundRect(x, y, rectWidth, barHeight, radius);
560
+ ctx.fill();
561
+ }
562
+ if (state.isPlaying) {
563
+ animationRef.current = requestAnimationFrame(renderFrequency);
564
+ }
565
+ }, [
566
+ webAudio.analyser,
567
+ state.buffered,
568
+ state.duration,
569
+ state.currentTime,
570
+ state.isPlaying,
571
+ barWidth,
572
+ barGap,
573
+ barRadius,
574
+ progressColor,
575
+ waveColor,
576
+ bufferedColor
577
+ ]);
578
+ const renderStatic = useCallback(() => {
579
+ const canvas = canvasRef.current;
580
+ if (!canvas) return;
581
+ const ctx = canvas.getContext("2d");
582
+ if (!ctx) return;
583
+ const { width, height: canvasHeight } = canvas;
584
+ const dpr = window.devicePixelRatio || 1;
585
+ ctx.clearRect(0, 0, width, canvasHeight);
586
+ if (state.buffered && state.duration > 0) {
587
+ ctx.fillStyle = bufferedColor;
588
+ for (let i = 0; i < state.buffered.length; i++) {
589
+ const start = state.buffered.start(i) / state.duration * width;
590
+ const end = state.buffered.end(i) / state.duration * width;
591
+ ctx.fillRect(start, 0, end - start, canvasHeight);
592
+ }
593
+ }
594
+ const progress = state.duration > 0 ? state.currentTime / state.duration : 0;
595
+ const progressWidth = width * progress;
596
+ ctx.fillStyle = waveColor;
597
+ ctx.fillRect(0, canvasHeight / 2 - 2 * dpr, width, 4 * dpr);
598
+ ctx.fillStyle = progressColor;
599
+ ctx.fillRect(0, canvasHeight / 2 - 2 * dpr, progressWidth, 4 * dpr);
600
+ if (progress > 0) {
601
+ ctx.beginPath();
602
+ ctx.arc(progressWidth, canvasHeight / 2, 6 * dpr, 0, Math.PI * 2);
603
+ ctx.fill();
604
+ }
605
+ }, [state.buffered, state.duration, state.currentTime, progressColor, waveColor, bufferedColor]);
606
+ useEffect(() => {
607
+ const container = containerRef.current;
608
+ const canvas = canvasRef.current;
609
+ if (!container || !canvas) return;
610
+ const resizeObserver = new ResizeObserver((entries) => {
611
+ const entry = entries[0];
612
+ if (!entry) return;
613
+ const dpr = window.devicePixelRatio || 1;
614
+ const displayWidth = entry.contentRect.width;
615
+ const displayHeight = height;
616
+ canvas.width = displayWidth * dpr;
617
+ canvas.height = displayHeight * dpr;
618
+ canvas.style.width = `${displayWidth}px`;
619
+ canvas.style.height = `${displayHeight}px`;
620
+ if (mode === "frequency") {
621
+ renderFrequency();
622
+ } else {
623
+ renderStatic();
624
+ }
625
+ });
626
+ resizeObserver.observe(container);
627
+ return () => resizeObserver.disconnect();
628
+ }, [height, mode, renderFrequency, renderStatic]);
629
+ useEffect(() => {
630
+ if (mode === "frequency") {
631
+ renderFrequency();
632
+ }
633
+ return () => {
634
+ if (animationRef.current) {
635
+ cancelAnimationFrame(animationRef.current);
636
+ }
637
+ };
638
+ }, [mode, renderFrequency]);
639
+ useEffect(() => {
640
+ if (mode === "static") {
641
+ renderStatic();
642
+ }
643
+ }, [mode, state.currentTime, renderStatic]);
644
+ useEffect(() => {
645
+ if (mode === "frequency" && !state.isPlaying) {
646
+ renderFrequency();
647
+ }
648
+ }, [mode, state.isPlaying, renderFrequency]);
649
+ return /* @__PURE__ */ jsx("div", { ref: containerRef, className: cn("w-full", className), children: /* @__PURE__ */ jsx(
650
+ "canvas",
651
+ {
652
+ ref: canvasRef,
653
+ onClick: handleClick,
654
+ className: "cursor-pointer",
655
+ style: { width: "100%", height }
656
+ }
657
+ ) });
658
+ }, "HybridWaveform"));
659
+
660
+ // src/tools/AudioPlayer/utils/formatTime.ts
661
+ function formatTime(seconds) {
662
+ if (!seconds || !isFinite(seconds) || seconds < 0) return "0:00";
663
+ const mins = Math.floor(seconds / 60);
664
+ const secs = Math.floor(seconds % 60);
665
+ return `${mins}:${secs.toString().padStart(2, "0")}`;
666
+ }
667
+ __name(formatTime, "formatTime");
668
+ createMediaLogger("AudioPlayer");
669
+ var HybridAudioPlayer = memo(/* @__PURE__ */ __name(function HybridAudioPlayer2({
670
+ showControls = true,
671
+ showWaveform = true,
672
+ waveformMode = "frequency",
673
+ waveformHeight = 64,
674
+ showTimer = true,
675
+ showVolume = true,
676
+ showLoop = true,
677
+ className,
678
+ style
679
+ }) {
680
+ const t = useTypedT();
681
+ const { state, controls } = useHybridAudioContext();
682
+ const labels = useMemo(() => ({
683
+ restart: t("tools.audio.restart"),
684
+ back: t("tools.audio.back"),
685
+ forward: t("tools.audio.forward"),
686
+ volume: t("tools.audio.volume")
687
+ }), [t]);
688
+ const isLoading = !state.isReady;
689
+ const handleVolumeChange = /* @__PURE__ */ __name((value) => {
690
+ controls.setVolume(value[0] / 100);
691
+ }, "handleVolumeChange");
692
+ return /* @__PURE__ */ jsxs(
693
+ "div",
694
+ {
695
+ className: cn$1("flex flex-col gap-3 p-4 rounded-lg bg-card border", className),
696
+ style,
697
+ children: [
698
+ showWaveform && /* @__PURE__ */ jsxs("div", { className: "relative", children: [
699
+ /* @__PURE__ */ jsx(
700
+ HybridWaveform,
701
+ {
702
+ mode: waveformMode,
703
+ height: waveformHeight,
704
+ className: cn$1(isLoading && "opacity-50")
705
+ }
706
+ ),
707
+ isLoading && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 flex items-center justify-center", children: /* @__PURE__ */ jsx(Loader2, { className: "h-6 w-6 animate-spin text-primary" }) })
708
+ ] }),
709
+ showTimer && /* @__PURE__ */ jsxs("div", { className: "flex justify-between text-xs text-muted-foreground tabular-nums px-1", children: [
710
+ /* @__PURE__ */ jsx("span", { children: formatTime(state.currentTime) }),
711
+ /* @__PURE__ */ jsx("span", { children: formatTime(state.duration) })
712
+ ] }),
713
+ showControls && /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-center gap-1", children: [
714
+ /* @__PURE__ */ jsx(
715
+ Button,
716
+ {
717
+ variant: "ghost",
718
+ size: "icon",
719
+ className: "h-9 w-9",
720
+ onClick: controls.restart,
721
+ disabled: !state.isReady,
722
+ title: labels.restart,
723
+ children: /* @__PURE__ */ jsx(RotateCcw, { className: "h-4 w-4" })
724
+ }
725
+ ),
726
+ /* @__PURE__ */ jsx(
727
+ Button,
728
+ {
729
+ variant: "ghost",
730
+ size: "icon",
731
+ className: "h-9 w-9",
732
+ onClick: () => controls.skip(-5),
733
+ disabled: !state.isReady,
734
+ title: labels.back,
735
+ children: /* @__PURE__ */ jsx(SkipBack, { className: "h-4 w-4" })
736
+ }
737
+ ),
738
+ /* @__PURE__ */ jsx(
739
+ Button,
740
+ {
741
+ variant: "default",
742
+ size: "icon",
743
+ className: "h-12 w-12 rounded-full",
744
+ onClick: controls.togglePlay,
745
+ disabled: !state.isReady && !isLoading,
746
+ title: state.isPlaying ? "Pause" : "Play",
747
+ children: isLoading ? /* @__PURE__ */ jsx(Loader2, { className: "h-5 w-5 animate-spin" }) : state.isPlaying ? /* @__PURE__ */ jsx(Pause, { className: "h-5 w-5" }) : /* @__PURE__ */ jsx(Play, { className: "h-5 w-5 ml-0.5" })
748
+ }
749
+ ),
750
+ /* @__PURE__ */ jsx(
751
+ Button,
752
+ {
753
+ variant: "ghost",
754
+ size: "icon",
755
+ className: "h-9 w-9",
756
+ onClick: () => controls.skip(5),
757
+ disabled: !state.isReady,
758
+ title: labels.forward,
759
+ children: /* @__PURE__ */ jsx(SkipForward, { className: "h-4 w-4" })
760
+ }
761
+ ),
762
+ showVolume && /* @__PURE__ */ jsxs(Fragment, { children: [
763
+ /* @__PURE__ */ jsx(
764
+ Button,
765
+ {
766
+ variant: "ghost",
767
+ size: "icon",
768
+ className: "h-9 w-9",
769
+ onClick: controls.toggleMute,
770
+ title: state.isMuted ? "Unmute" : "Mute",
771
+ children: state.isMuted || state.volume === 0 ? /* @__PURE__ */ jsx(VolumeX, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(Volume2, { className: "h-4 w-4" })
772
+ }
773
+ ),
774
+ /* @__PURE__ */ jsx(
775
+ Slider,
776
+ {
777
+ value: [state.isMuted ? 0 : state.volume * 100],
778
+ max: 100,
779
+ step: 1,
780
+ onValueChange: handleVolumeChange,
781
+ className: "w-20",
782
+ "aria-label": labels.volume
783
+ }
784
+ )
785
+ ] }),
786
+ showLoop && /* @__PURE__ */ jsx(
787
+ Button,
788
+ {
789
+ variant: "ghost",
790
+ size: "icon",
791
+ className: cn$1("h-9 w-9", state.isLooping && "text-primary"),
792
+ onClick: controls.toggleLoop,
793
+ disabled: !state.isReady,
794
+ title: state.isLooping ? "Disable loop" : "Enable loop",
795
+ children: /* @__PURE__ */ jsx(Repeat, { className: "h-4 w-4" })
796
+ }
797
+ )
798
+ ] })
799
+ ]
800
+ }
801
+ );
802
+ }, "HybridAudioPlayer"));
803
+
804
+ // src/tools/AudioPlayer/effects/index.ts
805
+ var INTENSITY_CONFIG = {
806
+ subtle: { opacity: 0.3, scale: 0.02, blur: "blur-2xl" },
807
+ medium: { opacity: 0.5, scale: 0.04, blur: "blur-xl" },
808
+ strong: { opacity: 0.7, scale: 0.06, blur: "blur-lg" }
809
+ };
810
+ var COLOR_SCHEMES2 = {
811
+ primary: ["217 91% 60%"],
812
+ vibrant: ["217 91% 60%", "142 76% 36%", "262 83% 58%", "25 95% 53%"],
813
+ cool: ["217 91% 60%", "262 83% 58%", "199 89% 48%"],
814
+ warm: ["25 95% 53%", "0 84% 60%", "38 92% 50%"]
815
+ };
816
+ var DEFAULT_GLOW_COLORS = [
817
+ "217 91% 60%",
818
+ // Blue
819
+ "262 83% 58%",
820
+ // Purple
821
+ "330 81% 60%",
822
+ // Pink
823
+ "25 95% 53%"
824
+ // Orange
825
+ ];
826
+ function getEffectConfig(intensity) {
827
+ return INTENSITY_CONFIG[intensity];
828
+ }
829
+ __name(getEffectConfig, "getEffectConfig");
830
+ function getColors(colorScheme) {
831
+ return COLOR_SCHEMES2[colorScheme];
832
+ }
833
+ __name(getColors, "getColors");
834
+ function prepareEffectColors(colorScheme, levels) {
835
+ const baseColors = COLOR_SCHEMES2[colorScheme];
836
+ const colors = baseColors.length > 1 ? baseColors : DEFAULT_GLOW_COLORS;
837
+ const hueShift = Math.floor(
838
+ levels.bass * 30 + levels.mid * 20 + levels.high * 10
839
+ );
840
+ return { colors, hueShift };
841
+ }
842
+ __name(prepareEffectColors, "prepareEffectColors");
843
+ function calculateGlowLayers(levels, config, colors) {
844
+ const { bass, mid, high } = levels;
845
+ return [
846
+ // Layer 1: Bass glow - bottom
847
+ {
848
+ inset: 60 + bass * 90,
849
+ opacity: 1,
850
+ scale: 1 + bass * 0.5,
851
+ background: `radial-gradient(ellipse 80% 60% at 50% 100%, hsl(${colors[0]} / ${0.4 + bass * 0.4}) 0%, transparent 70%)`,
852
+ blur: "blur-3xl"
853
+ },
854
+ // Layer 2: Mid glow - top
855
+ {
856
+ inset: 45 + mid * 75,
857
+ opacity: 1,
858
+ scale: 1 + mid * 0.4,
859
+ background: `radial-gradient(ellipse 70% 50% at 50% 0%, hsl(${colors[1] || colors[0]} / ${0.3 + mid * 0.5}) 0%, transparent 70%)`,
860
+ blur: "blur-2xl"
861
+ },
862
+ // Layer 3: High glow - left
863
+ {
864
+ inset: 30 + high * 60,
865
+ opacity: 1,
866
+ scale: 1 + high * 0.3,
867
+ background: `radial-gradient(ellipse 50% 80% at 0% 50%, hsl(${colors[2] || colors[0]} / ${0.3 + high * 0.4}) 0%, transparent 60%)`,
868
+ blur: "blur-2xl"
869
+ },
870
+ // Layer 4: High glow - right
871
+ {
872
+ inset: 30 + high * 60,
873
+ opacity: 1,
874
+ scale: 1 + high * 0.3,
875
+ background: `radial-gradient(ellipse 50% 80% at 100% 50%, hsl(${colors[3] || colors[0]} / ${0.3 + high * 0.4}) 0%, transparent 60%)`,
876
+ blur: "blur-2xl"
877
+ },
878
+ // Layer 5: Center pulsing glow
879
+ {
880
+ inset: 24 + bass * 45,
881
+ opacity: 1,
882
+ scale: 1 + bass * 0.2,
883
+ background: `radial-gradient(circle at 50% 50%, hsl(${colors[0]} / ${0.2 + bass * 0.3}) 0%, hsl(${colors[1] || colors[0]} / ${0.1 + mid * 0.2}) 40%, transparent 70%)`,
884
+ blur: "blur-xl",
885
+ animation: "glow-breathe 2s ease-in-out infinite"
886
+ }
887
+ ];
888
+ }
889
+ __name(calculateGlowLayers, "calculateGlowLayers");
890
+ function calculateOrbs(levels, config, colors, baseSize = 50) {
891
+ const { bass, mid, high, overall } = levels;
892
+ const size = baseSize * 3;
893
+ const bassMove = bass * 30;
894
+ const midMove = mid * 25;
895
+ const highMove = high * 20;
896
+ return [
897
+ // Bass orb - top left, big pulses
898
+ {
899
+ x: -40 + bassMove,
900
+ y: -40 - bassMove * 0.5,
901
+ size: size * (1 + bass * 1.2),
902
+ color: colors[0],
903
+ opacity: 0.5 + bass * 0.5,
904
+ scale: 1 + bass * 0.6
905
+ },
906
+ // Mid orb - top right
907
+ {
908
+ x: 130 - midMove * 0.5,
909
+ y: -30 + midMove,
910
+ size: size * (0.9 + mid * 1),
911
+ color: colors[1] || colors[0],
912
+ opacity: 0.5 + mid * 0.5,
913
+ scale: 1 + mid * 0.5
914
+ },
915
+ // High orb - bottom right
916
+ {
917
+ x: 140 + highMove * 0.3,
918
+ y: 120 - highMove,
919
+ size: size * (0.8 + high * 0.8),
920
+ color: colors[2] || colors[0],
921
+ opacity: 0.4 + high * 0.6,
922
+ scale: 1 + high * 0.45
923
+ },
924
+ // Mid orb 2 - bottom left
925
+ {
926
+ x: -30 - midMove * 0.4,
927
+ y: 130 + midMove * 0.3,
928
+ size: size * (0.9 + mid * 0.9),
929
+ color: colors[3] || colors[0],
930
+ opacity: 0.45 + mid * 0.55,
931
+ scale: 1 + mid * 0.5
932
+ },
933
+ // Center overall orb
934
+ {
935
+ x: 50,
936
+ y: 50,
937
+ size: size * (0.6 + overall * 1.5),
938
+ color: colors[0],
939
+ opacity: 0.3 + overall * 0.5,
940
+ scale: 1 + overall * 0.7
941
+ }
942
+ ];
943
+ }
944
+ __name(calculateOrbs, "calculateOrbs");
945
+ function calculateMeshGradients(levels, config, colors) {
946
+ const { bass, mid, high, overall } = levels;
947
+ const bassOffset = bass * 40;
948
+ const midOffset = mid * 30;
949
+ const highOffset = high * 25;
950
+ return [
951
+ // Large bass blob - top right, pulses hard
952
+ {
953
+ width: `${200 + bass * 150}%`,
954
+ height: `${200 + bass * 150}%`,
955
+ top: `${ -80 + bassOffset}%`,
956
+ right: `${ -80 - bassOffset}%`,
957
+ color: colors[0],
958
+ opacity: 0.4 + bass * 0.6,
959
+ scale: 1 + bass * 0.5,
960
+ rotation: bass * 45,
961
+ blur: "blur-2xl"
962
+ },
963
+ // Mid blob - bottom left
964
+ {
965
+ width: `${180 + mid * 120}%`,
966
+ height: `${180 + mid * 120}%`,
967
+ bottom: `${ -60 + midOffset}%`,
968
+ left: `${ -60 - midOffset}%`,
969
+ color: colors[1] || colors[0],
970
+ opacity: 0.4 + mid * 0.6,
971
+ scale: 1 + mid * 0.4,
972
+ rotation: -mid * 40,
973
+ blur: "blur-2xl"
974
+ },
975
+ // High blob - bottom right
976
+ {
977
+ width: `${140 + high * 100}%`,
978
+ height: `${140 + high * 100}%`,
979
+ top: `${70 - highOffset}%`,
980
+ right: `${ -50 + highOffset}%`,
981
+ color: colors[2] || colors[0],
982
+ opacity: 0.35 + high * 0.65,
983
+ scale: 1 + high * 0.35,
984
+ rotation: high * 35,
985
+ blur: "blur-xl"
986
+ },
987
+ // Extra bass reactive blob - top left
988
+ {
989
+ width: `${160 + bass * 140}%`,
990
+ height: `${160 + bass * 140}%`,
991
+ top: `${ -60 - bassOffset * 0.8}%`,
992
+ left: `${ -60 + bassOffset * 0.8}%`,
993
+ color: colors[3] || colors[1] || colors[0],
994
+ opacity: 0.35 + bass * 0.65,
995
+ scale: 1 + bass * 0.55,
996
+ rotation: -bass * 50,
997
+ blur: "blur-2xl"
998
+ },
999
+ // Center glow - pulses with overall
1000
+ {
1001
+ width: `${80 + overall * 150}%`,
1002
+ height: `${80 + overall * 150}%`,
1003
+ top: "50%",
1004
+ left: "50%",
1005
+ color: colors[0],
1006
+ opacity: 0.3 + overall * 0.5,
1007
+ scale: 1 + overall * 0.4,
1008
+ rotation: 0,
1009
+ isCenter: true,
1010
+ blur: "blur-3xl"
1011
+ }
1012
+ ];
1013
+ }
1014
+ __name(calculateMeshGradients, "calculateMeshGradients");
1015
+ function calculateSpotlight(levels, config, colors, rotation) {
1016
+ const { bass, mid, high, overall } = levels;
1017
+ return {
1018
+ // Rotation speed increases with mid frequencies
1019
+ rotation: rotation + mid * 180,
1020
+ // Border expands with bass
1021
+ inset: 12 + bass * 30,
1022
+ // Color intensities react to different frequencies
1023
+ colors: colors.map((c, i) => ({
1024
+ color: c,
1025
+ opacity: i === 0 ? 0.3 + bass * 0.7 : i === 1 ? 0.3 + mid * 0.7 : 0.3 + high * 0.7
1026
+ })),
1027
+ // Pulse glow - big and reactive
1028
+ pulseInset: 24 + bass * 50,
1029
+ pulseOpacity: 0.3 + bass * 0.7,
1030
+ pulseScale: 1 + bass * 0.4,
1031
+ // Extra glow ring
1032
+ ringOpacity: 0.2 + overall * 0.6,
1033
+ ringScale: 1 + overall * 0.3
1034
+ };
1035
+ }
1036
+ __name(calculateSpotlight, "calculateSpotlight");
1037
+ var EFFECT_ANIMATIONS = `
1038
+ @keyframes spotlight-spin {
1039
+ 0% { transform: rotate(0deg); }
1040
+ 100% { transform: rotate(360deg); }
1041
+ }
1042
+
1043
+ @keyframes orb-float-1 {
1044
+ 0%, 100% { transform: translate(-50%, -50%) translateY(0); }
1045
+ 50% { transform: translate(-50%, -50%) translateY(-15px); }
1046
+ }
1047
+
1048
+ @keyframes orb-float-2 {
1049
+ 0%, 100% { transform: translate(-50%, -50%) translateX(0); }
1050
+ 50% { transform: translate(-50%, -50%) translateX(15px); }
1051
+ }
1052
+
1053
+ @keyframes orb-float-3 {
1054
+ 0%, 100% { transform: translate(-50%, -50%) translate(0, 0); }
1055
+ 33% { transform: translate(-50%, -50%) translate(10px, -10px); }
1056
+ 66% { transform: translate(-50%, -50%) translate(-10px, 10px); }
1057
+ }
1058
+
1059
+ @keyframes orb-float-4 {
1060
+ 0%, 100% { transform: translate(-50%, -50%) translate(0, 0); }
1061
+ 50% { transform: translate(-50%, -50%) translate(-15px, -10px); }
1062
+ }
1063
+
1064
+ @keyframes mesh-float-1 {
1065
+ 0%, 100% { transform: translate(0, 0) scale(1); }
1066
+ 25% { transform: translate(-5%, 10%) scale(1.05); }
1067
+ 50% { transform: translate(5%, 5%) scale(0.95); }
1068
+ 75% { transform: translate(-3%, -5%) scale(1.02); }
1069
+ }
1070
+
1071
+ @keyframes mesh-float-2 {
1072
+ 0%, 100% { transform: translate(0, 0) scale(1); }
1073
+ 33% { transform: translate(8%, -8%) scale(1.08); }
1074
+ 66% { transform: translate(-6%, 6%) scale(0.92); }
1075
+ }
1076
+
1077
+ @keyframes mesh-float-3 {
1078
+ 0%, 100% { transform: translate(0, 0) scale(1); }
1079
+ 50% { transform: translate(10%, 10%) scale(1.1); }
1080
+ }
1081
+
1082
+ @keyframes mesh-float-4 {
1083
+ 0%, 100% { transform: translate(0, 0) scale(1) rotate(0deg); }
1084
+ 25% { transform: translate(10%, -5%) scale(1.1) rotate(5deg); }
1085
+ 50% { transform: translate(-5%, 10%) scale(0.95) rotate(-5deg); }
1086
+ 75% { transform: translate(-10%, -10%) scale(1.05) rotate(3deg); }
1087
+ }
1088
+
1089
+ @keyframes mesh-pulse {
1090
+ 0%, 100% { transform: translate(-50%, -50%) scale(1); opacity: 0.3; }
1091
+ 50% { transform: translate(-50%, -50%) scale(1.2); opacity: 0.5; }
1092
+ }
1093
+
1094
+ @keyframes glow-breathe {
1095
+ 0%, 100% { opacity: 0.6; transform: scale(1); }
1096
+ 50% { opacity: 1; transform: scale(1.05); }
1097
+ }
1098
+
1099
+ @keyframes glow-rotate {
1100
+ 0% { transform: rotate(0deg); }
1101
+ 100% { transform: rotate(360deg); }
1102
+ }
1103
+
1104
+ @keyframes sparkle-move {
1105
+ 0% { opacity: 0; transform: scale(0.8); }
1106
+ 50% { opacity: 1; }
1107
+ 100% { opacity: 0; transform: scale(1.2); }
1108
+ }
1109
+ `;
1110
+ function GlowEffect({ data, colors, isPlaying }) {
1111
+ const { layers, hueShift, showPulseRings, showSparkle } = data;
1112
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1113
+ layers.map((layer, i) => /* @__PURE__ */ jsx(
1114
+ "div",
1115
+ {
1116
+ className: cn$1("absolute rounded-2xl -z-10", layer.blur),
1117
+ style: {
1118
+ inset: `-${layer.inset}px`,
1119
+ background: layer.background,
1120
+ opacity: isPlaying ? layer.opacity : 0,
1121
+ transform: i < 2 ? `scaleY(${layer.scale})` : `scale(${layer.scale})`,
1122
+ animation: isPlaying && layer.animation ? layer.animation : "none",
1123
+ transition: "opacity 0.3s"
1124
+ }
1125
+ },
1126
+ i
1127
+ )),
1128
+ /* @__PURE__ */ jsx(
1129
+ "div",
1130
+ {
1131
+ className: "absolute rounded-2xl blur-xl overflow-hidden -z-10",
1132
+ style: {
1133
+ inset: "-75px",
1134
+ opacity: isPlaying ? 0.6 : 0,
1135
+ transition: "opacity 0.5s"
1136
+ },
1137
+ children: /* @__PURE__ */ jsx(
1138
+ "div",
1139
+ {
1140
+ className: "absolute inset-0",
1141
+ style: {
1142
+ background: `conic-gradient(
1143
+ from ${hueShift}deg at 50% 50%,
1144
+ hsl(${colors[0]} / 0.4) 0deg,
1145
+ hsl(${colors[1] || colors[0]} / 0.3) 90deg,
1146
+ hsl(${colors[2] || colors[0]} / 0.3) 180deg,
1147
+ hsl(${colors[3] || colors[0]} / 0.3) 270deg,
1148
+ hsl(${colors[0]} / 0.4) 360deg
1149
+ )`,
1150
+ animation: isPlaying ? "glow-rotate 6s linear infinite" : "none"
1151
+ }
1152
+ }
1153
+ )
1154
+ }
1155
+ ),
1156
+ showPulseRings && /* @__PURE__ */ jsxs(Fragment, { children: [
1157
+ /* @__PURE__ */ jsx(
1158
+ "div",
1159
+ {
1160
+ className: "absolute -inset-6 rounded-xl border-2 animate-ping -z-10",
1161
+ style: {
1162
+ borderColor: `hsl(${colors[0]} / 0.4)`,
1163
+ animationDuration: "1s"
1164
+ }
1165
+ }
1166
+ ),
1167
+ /* @__PURE__ */ jsx(
1168
+ "div",
1169
+ {
1170
+ className: "absolute -inset-12 rounded-2xl border animate-ping -z-10",
1171
+ style: {
1172
+ borderColor: `hsl(${colors[1] || colors[0]} / 0.3)`,
1173
+ animationDuration: "1.5s",
1174
+ animationDelay: "0.2s"
1175
+ }
1176
+ }
1177
+ )
1178
+ ] }),
1179
+ showSparkle && /* @__PURE__ */ jsx(
1180
+ "div",
1181
+ {
1182
+ className: "absolute -inset-18 rounded-3xl -z-10",
1183
+ style: {
1184
+ background: `radial-gradient(circle at 50% 30%, hsl(${colors[2] || colors[0]} / 0.5) 0%, transparent 30%)`,
1185
+ animation: "sparkle-move 0.5s ease-out"
1186
+ }
1187
+ }
1188
+ )
1189
+ ] });
1190
+ }
1191
+ __name(GlowEffect, "GlowEffect");
1192
+ function OrbsEffect({ orbs, blur, isPlaying }) {
1193
+ return /* @__PURE__ */ jsx(Fragment, { children: orbs.map((orb, i) => /* @__PURE__ */ jsx(
1194
+ "div",
1195
+ {
1196
+ className: cn$1("absolute rounded-full -z-10", blur),
1197
+ style: {
1198
+ width: orb.size,
1199
+ height: orb.size,
1200
+ left: `${orb.x}%`,
1201
+ top: `${orb.y}%`,
1202
+ background: `radial-gradient(circle at 30% 30%, hsl(${orb.color}) 0%, hsl(${orb.color} / 0.5) 40%, transparent 70%)`,
1203
+ opacity: isPlaying ? orb.opacity : 0,
1204
+ transform: `translate(-50%, -50%) scale(${orb.scale})`,
1205
+ transition: "all 0.08s ease-out"
1206
+ }
1207
+ },
1208
+ i
1209
+ )) });
1210
+ }
1211
+ __name(OrbsEffect, "OrbsEffect");
1212
+ function SpotlightEffect({ data, colors, blur, isPlaying }) {
1213
+ const inset = "inset" in data ? data.inset : 12;
1214
+ const pulseInset = "pulseInset" in data ? data.pulseInset : 24;
1215
+ const ringOpacity = "ringOpacity" in data ? data.ringOpacity : 0.3;
1216
+ const ringScale = "ringScale" in data ? data.ringScale : 1;
1217
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1218
+ /* @__PURE__ */ jsx(
1219
+ "div",
1220
+ {
1221
+ className: cn$1("absolute rounded-xl -z-10", blur),
1222
+ style: {
1223
+ inset: `-${inset}px`,
1224
+ background: `conic-gradient(
1225
+ from ${data.rotation}deg,
1226
+ hsl(${colors[0]} / ${data.colors[0]?.opacity || 0.5}),
1227
+ hsl(${colors[1] || colors[0]} / ${data.colors[1]?.opacity || 0.7}),
1228
+ hsl(${colors[2] || colors[0]} / ${data.colors[2]?.opacity || 0.5}),
1229
+ hsl(${colors[0]} / ${data.colors[1]?.opacity || 0.7}),
1230
+ hsl(${colors[0]} / ${data.colors[0]?.opacity || 0.5})
1231
+ )`,
1232
+ opacity: isPlaying ? 1 : 0,
1233
+ transition: "all 0.08s ease-out"
1234
+ }
1235
+ }
1236
+ ),
1237
+ /* @__PURE__ */ jsx(
1238
+ "div",
1239
+ {
1240
+ className: "absolute -inset-1 rounded-lg bg-background -z-10",
1241
+ style: { opacity: isPlaying ? 1 : 0, transition: "opacity 0.1s" }
1242
+ }
1243
+ ),
1244
+ /* @__PURE__ */ jsx(
1245
+ "div",
1246
+ {
1247
+ className: cn$1("absolute rounded-2xl -z-10", blur),
1248
+ style: {
1249
+ inset: `-${pulseInset}px`,
1250
+ background: `radial-gradient(circle, hsl(${colors[0]} / 0.7) 0%, hsl(${colors[0]} / 0.3) 50%, transparent 70%)`,
1251
+ opacity: isPlaying ? data.pulseOpacity : 0,
1252
+ transform: `scale(${data.pulseScale})`,
1253
+ transition: "all 0.08s ease-out"
1254
+ }
1255
+ }
1256
+ ),
1257
+ /* @__PURE__ */ jsx(
1258
+ "div",
1259
+ {
1260
+ className: "absolute rounded-3xl -z-10 blur-2xl",
1261
+ style: {
1262
+ inset: `-${pulseInset + 30}px`,
1263
+ background: `radial-gradient(circle, hsl(${colors[1] || colors[0]} / 0.4) 0%, transparent 60%)`,
1264
+ opacity: isPlaying ? ringOpacity : 0,
1265
+ transform: `scale(${ringScale})`,
1266
+ transition: "all 0.08s ease-out"
1267
+ }
1268
+ }
1269
+ )
1270
+ ] });
1271
+ }
1272
+ __name(SpotlightEffect, "SpotlightEffect");
1273
+ function MeshEffect({ gradients, isPlaying }) {
1274
+ return /* @__PURE__ */ jsx(Fragment, { children: gradients.map((g, i) => {
1275
+ const isCenter = "isCenter" in g && g.isCenter;
1276
+ const scale = "scale" in g ? g.scale : 1;
1277
+ const rotation = "rotation" in g ? g.rotation : 0;
1278
+ const itemBlur = "blur" in g ? g.blur : "blur-2xl";
1279
+ return /* @__PURE__ */ jsx(
1280
+ "div",
1281
+ {
1282
+ className: cn$1("absolute rounded-full -z-10", itemBlur),
1283
+ style: {
1284
+ width: g.width,
1285
+ height: g.height,
1286
+ top: "top" in g ? g.top : void 0,
1287
+ bottom: "bottom" in g ? g.bottom : void 0,
1288
+ left: "left" in g ? g.left : void 0,
1289
+ right: "right" in g ? g.right : void 0,
1290
+ background: isCenter ? `radial-gradient(circle, hsl(${g.color} / 0.6) 0%, hsl(${g.color} / 0.3) 30%, transparent 60%)` : `radial-gradient(circle, hsl(${g.color}) 0%, hsl(${g.color} / 0.5) 30%, transparent 65%)`,
1291
+ opacity: isPlaying ? g.opacity : 0,
1292
+ transform: isCenter ? `translate(-50%, -50%) scale(${scale})` : `scale(${scale}) rotate(${rotation}deg)`,
1293
+ transition: "all 0.08s ease-out"
1294
+ }
1295
+ },
1296
+ i
1297
+ );
1298
+ }) });
1299
+ }
1300
+ __name(MeshEffect, "MeshEffect");
1301
+ var SIZES = {
1302
+ sm: { container: "w-32 h-32", orbBase: 40 },
1303
+ md: { container: "w-40 h-40", orbBase: 50 },
1304
+ lg: { container: "w-48 h-48", orbBase: 60 }
1305
+ };
1306
+ function AudioReactiveCover({
1307
+ children,
1308
+ size = "lg",
1309
+ variant = "spotlight",
1310
+ intensity = "medium",
1311
+ colorScheme = "primary",
1312
+ onClick,
1313
+ className
1314
+ }) {
1315
+ const { isPlaying } = useHybridAudioState();
1316
+ const levels = useHybridAudioLevels();
1317
+ const sizeConfig = SIZES[size];
1318
+ const effectConfig = getEffectConfig(intensity);
1319
+ const { colors, hueShift } = prepareEffectColors(colorScheme, levels);
1320
+ const containerScale = 1 + levels.overall * effectConfig.scale;
1321
+ const glowData = variant === "glow" ? {
1322
+ layers: calculateGlowLayers(levels, effectConfig, colors),
1323
+ hueShift,
1324
+ showPulseRings: levels.bass > 0.5,
1325
+ showSparkle: levels.high > 0.4
1326
+ } : null;
1327
+ const orbsData = variant === "orbs" ? calculateOrbs(levels, effectConfig, colors, sizeConfig.orbBase) : null;
1328
+ const meshData = variant === "mesh" ? calculateMeshGradients(levels, effectConfig, colors) : null;
1329
+ const spotlightData = variant === "spotlight" ? calculateSpotlight(levels, effectConfig, colors, levels.mid * 360) : null;
1330
+ return /* @__PURE__ */ jsxs(
1331
+ "div",
1332
+ {
1333
+ className: cn$1("relative", sizeConfig.container, className),
1334
+ style: {
1335
+ transform: `scale(${containerScale})`,
1336
+ transition: "transform 0.1s ease-out"
1337
+ },
1338
+ children: [
1339
+ /* @__PURE__ */ jsxs("div", { className: "absolute inset-0 z-0 pointer-events-none overflow-visible", children: [
1340
+ glowData && /* @__PURE__ */ jsx(GlowEffect, { data: glowData, colors, isPlaying }),
1341
+ orbsData && /* @__PURE__ */ jsx(OrbsEffect, { orbs: orbsData, blur: effectConfig.blur, isPlaying }),
1342
+ spotlightData && /* @__PURE__ */ jsx(SpotlightEffect, { data: spotlightData, colors, blur: effectConfig.blur, isPlaying }),
1343
+ meshData && /* @__PURE__ */ jsx(MeshEffect, { gradients: meshData, blur: effectConfig.blur, isPlaying })
1344
+ ] }),
1345
+ /* @__PURE__ */ jsx(
1346
+ "div",
1347
+ {
1348
+ className: "relative w-full h-full rounded-lg overflow-hidden shadow-2xl z-10 bg-background cursor-pointer",
1349
+ onClick,
1350
+ role: onClick ? "button" : void 0,
1351
+ tabIndex: onClick ? 0 : void 0,
1352
+ onKeyDown: onClick ? (e) => e.key === "Enter" && onClick() : void 0,
1353
+ children
1354
+ }
1355
+ ),
1356
+ /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: EFFECT_ANIMATIONS } })
1357
+ ]
1358
+ }
1359
+ );
1360
+ }
1361
+ __name(AudioReactiveCover, "AudioReactiveCover");
1362
+ var COVER_SIZES = {
1363
+ sm: "w-24 h-24",
1364
+ md: "w-32 h-32",
1365
+ lg: "w-48 h-48"
1366
+ };
1367
+ function HybridSimplePlayer(props) {
1368
+ return /* @__PURE__ */ jsx(VisualizationProvider, { children: /* @__PURE__ */ jsx(HybridSimplePlayerContent, { ...props }) });
1369
+ }
1370
+ __name(HybridSimplePlayer, "HybridSimplePlayer");
1371
+ function HybridSimplePlayerContent({
1372
+ src,
1373
+ title,
1374
+ artist,
1375
+ coverArt,
1376
+ coverSize = "md",
1377
+ showWaveform = true,
1378
+ waveformMode = "frequency",
1379
+ waveformHeight = 64,
1380
+ showTimer = true,
1381
+ showVolume = true,
1382
+ showLoop = true,
1383
+ reactiveCover = true,
1384
+ variant,
1385
+ intensity,
1386
+ colorScheme,
1387
+ autoPlay = false,
1388
+ loop = false,
1389
+ initialVolume = 1,
1390
+ layout = "vertical",
1391
+ className,
1392
+ onPlay,
1393
+ onPause,
1394
+ onEnded,
1395
+ onError
1396
+ }) {
1397
+ const { settings: vizSettings, nextVariant } = useVisualization();
1398
+ const effectiveVariant = variant ?? (vizSettings.variant !== "none" ? vizSettings.variant : "spotlight");
1399
+ const effectiveIntensity = intensity ?? vizSettings.intensity;
1400
+ const effectiveColorScheme = colorScheme ?? vizSettings.colorScheme;
1401
+ const showReactiveCover = reactiveCover && effectiveVariant !== "none";
1402
+ const renderCoverContent = /* @__PURE__ */ __name(() => {
1403
+ if (typeof coverArt === "string") {
1404
+ return /* @__PURE__ */ jsx("img", { src: coverArt, alt: title || "Album cover", className: "w-full h-full object-cover" });
1405
+ }
1406
+ if (coverArt) {
1407
+ return coverArt;
1408
+ }
1409
+ return /* @__PURE__ */ jsx("div", { className: "w-full h-full bg-muted/30 flex items-center justify-center", children: /* @__PURE__ */ jsx(Music, { className: "w-1/3 h-1/3 text-muted-foreground/50" }) });
1410
+ }, "renderCoverContent");
1411
+ const isHorizontal = layout === "horizontal";
1412
+ return /* @__PURE__ */ jsx(
1413
+ HybridAudioProvider,
1414
+ {
1415
+ src,
1416
+ autoPlay,
1417
+ loop,
1418
+ initialVolume,
1419
+ onPlay,
1420
+ onPause,
1421
+ onEnded,
1422
+ onError,
1423
+ children: /* @__PURE__ */ jsxs(
1424
+ "div",
1425
+ {
1426
+ className: cn$2(
1427
+ "flex gap-4",
1428
+ isHorizontal ? "flex-row items-center" : "flex-col items-center",
1429
+ className
1430
+ ),
1431
+ children: [
1432
+ (coverArt || reactiveCover) && /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-2 shrink-0", children: [
1433
+ showReactiveCover ? /* @__PURE__ */ jsx(
1434
+ AudioReactiveCover,
1435
+ {
1436
+ size: coverSize,
1437
+ variant: effectiveVariant,
1438
+ intensity: effectiveIntensity,
1439
+ colorScheme: effectiveColorScheme,
1440
+ onClick: nextVariant,
1441
+ children: /* @__PURE__ */ jsx("div", { className: cn$2("rounded-lg overflow-hidden", COVER_SIZES[coverSize]), children: renderCoverContent() })
1442
+ }
1443
+ ) : /* @__PURE__ */ jsx(
1444
+ "div",
1445
+ {
1446
+ className: cn$2(
1447
+ "rounded-lg overflow-hidden shadow-lg cursor-pointer",
1448
+ COVER_SIZES[coverSize]
1449
+ ),
1450
+ onClick: nextVariant,
1451
+ role: "button",
1452
+ tabIndex: 0,
1453
+ onKeyDown: (e) => e.key === "Enter" && nextVariant(),
1454
+ children: renderCoverContent()
1455
+ }
1456
+ ),
1457
+ reactiveCover && /* @__PURE__ */ jsx("span", { className: "text-[10px] uppercase tracking-wider text-muted-foreground/50 select-none", children: vizSettings.variant === "none" ? "off" : vizSettings.variant })
1458
+ ] }),
1459
+ /* @__PURE__ */ jsxs(
1460
+ "div",
1461
+ {
1462
+ className: cn$2("flex flex-col gap-3", isHorizontal ? "flex-1 min-w-0" : "w-full max-w-md"),
1463
+ children: [
1464
+ (title || artist) && /* @__PURE__ */ jsxs("div", { className: cn$2("text-center", isHorizontal && "text-left"), children: [
1465
+ title && /* @__PURE__ */ jsx("h3", { className: "text-base font-medium text-foreground truncate", children: title }),
1466
+ artist && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground truncate", children: artist })
1467
+ ] }),
1468
+ /* @__PURE__ */ jsx(
1469
+ HybridAudioPlayer,
1470
+ {
1471
+ showControls: true,
1472
+ showWaveform,
1473
+ waveformMode,
1474
+ waveformHeight,
1475
+ showTimer,
1476
+ showVolume,
1477
+ showLoop,
1478
+ className: "border-0 bg-transparent"
1479
+ }
1480
+ )
1481
+ ]
1482
+ }
1483
+ )
1484
+ ]
1485
+ }
1486
+ )
1487
+ }
1488
+ );
1489
+ }
1490
+ __name(HybridSimplePlayerContent, "HybridSimplePlayerContent");
1491
+
1492
+ export { AudioReactiveCover, COLOR_SCHEMES2 as COLOR_SCHEMES, COLOR_SCHEME_INFO, EFFECT_ANIMATIONS, GlowEffect, HybridAudioPlayer, HybridAudioProvider, HybridSimplePlayer, HybridWaveform, INTENSITY_CONFIG, INTENSITY_INFO, MeshEffect, OrbsEffect, SpotlightEffect, VARIANT_INFO, VisualizationProvider, calculateGlowLayers, calculateMeshGradients, calculateOrbs, calculateSpotlight, formatTime, getColors, getEffectConfig, prepareEffectColors, useAudioVisualization, useHybridAudio, useHybridAudioAnalysis, useHybridAudioContext, useHybridAudioControls, useHybridAudioLevels, useHybridAudioState, useHybridWebAudio, useVisualization };
1493
+ //# sourceMappingURL=chunk-OVNC4KW6.mjs.map
1494
+ //# sourceMappingURL=chunk-OVNC4KW6.mjs.map