@djangocfg/ui-nextjs 2.1.81 → 2.1.83

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 (36) hide show
  1. package/package.json +4 -4
  2. package/src/tools/AudioPlayer/@refactoring3/00-IMPLEMENTATION-ROADMAP.md +1146 -0
  3. package/src/tools/AudioPlayer/@refactoring3/01-WAVESURFER-STREAMING-ANALYSIS.md +611 -0
  4. package/src/tools/AudioPlayer/@refactoring3/02-MEDIA-VIEWER-ANALYSIS.md +560 -0
  5. package/src/tools/AudioPlayer/@refactoring3/03-HYBRID-ARCHITECTURE-PROPOSAL.md +769 -0
  6. package/src/tools/AudioPlayer/@refactoring3/04-CRACKLING-ISSUE-DIAGNOSIS.md +373 -0
  7. package/src/tools/AudioPlayer/README.md +177 -205
  8. package/src/tools/AudioPlayer/components/AudioPlayer.tsx +9 -4
  9. package/src/tools/AudioPlayer/components/HybridAudioPlayer.tsx +251 -0
  10. package/src/tools/AudioPlayer/components/HybridSimplePlayer.tsx +291 -0
  11. package/src/tools/AudioPlayer/components/HybridWaveform.tsx +279 -0
  12. package/src/tools/AudioPlayer/components/SimpleAudioPlayer.tsx +16 -26
  13. package/src/tools/AudioPlayer/components/index.ts +6 -1
  14. package/src/tools/AudioPlayer/context/AudioProvider.tsx +16 -8
  15. package/src/tools/AudioPlayer/context/HybridAudioProvider.tsx +121 -0
  16. package/src/tools/AudioPlayer/context/index.ts +14 -2
  17. package/src/tools/AudioPlayer/hooks/index.ts +11 -0
  18. package/src/tools/AudioPlayer/hooks/useHybridAudio.ts +387 -0
  19. package/src/tools/AudioPlayer/hooks/useHybridAudioAnalysis.ts +95 -0
  20. package/src/tools/AudioPlayer/hooks/useSharedWebAudio.ts +6 -3
  21. package/src/tools/AudioPlayer/index.ts +31 -0
  22. package/src/tools/AudioPlayer/progressive/ProgressiveAudioPlayer.tsx +8 -0
  23. package/src/tools/ImageViewer/hooks/useImageLoading.ts +33 -9
  24. package/src/tools/VideoPlayer/hooks/useVideoPositionCache.ts +13 -6
  25. package/src/tools/VideoPlayer/providers/StreamProvider.tsx +38 -22
  26. package/src/tools/index.ts +22 -0
  27. package/src/tools/AudioPlayer/@refactoring/00-PLAN.md +0 -148
  28. package/src/tools/AudioPlayer/@refactoring/01-TYPES.md +0 -301
  29. package/src/tools/AudioPlayer/@refactoring/02-HOOKS.md +0 -281
  30. package/src/tools/AudioPlayer/@refactoring/03-CONTEXT.md +0 -328
  31. package/src/tools/AudioPlayer/@refactoring/04-COMPONENTS.md +0 -251
  32. package/src/tools/AudioPlayer/@refactoring/05-EFFECTS.md +0 -427
  33. package/src/tools/AudioPlayer/@refactoring/06-UTILS-AND-INDEX.md +0 -193
  34. package/src/tools/AudioPlayer/@refactoring/07-EXECUTION-CHECKLIST.md +0 -146
  35. package/src/tools/AudioPlayer/@refactoring2/ISSUE_ANALYSIS.md +0 -187
  36. package/src/tools/AudioPlayer/@refactoring2/PLAN.md +0 -372
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  import { useRef, useEffect, useCallback } from 'react';
10
- import { useVideoCache } from '../../../stores/mediaCache';
10
+ import { useMediaCacheStore } from '../../../stores/mediaCache';
11
11
 
12
12
  // =============================================================================
13
13
  // TYPES
@@ -54,7 +54,10 @@ export function useVideoPositionCache(
54
54
  ): UseVideoPositionCacheReturn {
55
55
  const { cacheKey, currentTime, duration, isPlaying, isReady, onSeek } = options;
56
56
 
57
- const { saveVideoPosition, getVideoPosition } = useVideoCache();
57
+ // Get stable function references from store
58
+ const saveVideoPosition = useMediaCacheStore.getState().saveVideoPosition;
59
+ const getVideoPosition = useMediaCacheStore.getState().getVideoPosition;
60
+
58
61
  const lastSavedTimeRef = useRef<number>(0);
59
62
  const hasRestoredRef = useRef<boolean>(false);
60
63
 
@@ -70,7 +73,8 @@ export function useVideoPositionCache(
70
73
  }
71
74
  }
72
75
  hasRestoredRef.current = true;
73
- }, [isReady, cacheKey, duration, getVideoPosition, onSeek]);
76
+ // eslint-disable-next-line react-hooks/exhaustive-deps
77
+ }, [isReady, cacheKey, duration, onSeek]);
74
78
 
75
79
  // Reset restored flag when cache key changes
76
80
  useEffect(() => {
@@ -87,20 +91,23 @@ export function useVideoPositionCache(
87
91
  saveVideoPosition(cacheKey, currentTime);
88
92
  lastSavedTimeRef.current = currentTime;
89
93
  }
90
- }, [cacheKey, isPlaying, currentTime, saveVideoPosition]);
94
+ // eslint-disable-next-line react-hooks/exhaustive-deps
95
+ }, [cacheKey, isPlaying, currentTime]);
91
96
 
92
97
  const savePosition = useCallback(() => {
93
98
  if (cacheKey && currentTime > 0) {
94
99
  saveVideoPosition(cacheKey, currentTime);
95
100
  lastSavedTimeRef.current = currentTime;
96
101
  }
97
- }, [cacheKey, currentTime, saveVideoPosition]);
102
+ // eslint-disable-next-line react-hooks/exhaustive-deps
103
+ }, [cacheKey, currentTime]);
98
104
 
99
105
  const clearPosition = useCallback(() => {
100
106
  if (cacheKey) {
101
107
  saveVideoPosition(cacheKey, 0);
102
108
  }
103
- }, [cacheKey, saveVideoPosition]);
109
+ // eslint-disable-next-line react-hooks/exhaustive-deps
110
+ }, [cacheKey]);
104
111
 
105
112
  return {
106
113
  savePosition,
@@ -14,7 +14,7 @@ import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useRef,
14
14
 
15
15
  import { cn } from '@djangocfg/ui-core/lib';
16
16
  import { Preloader, AspectRatio } from '@djangocfg/ui-core';
17
- import { useVideoCache, generateContentKey } from '../../../stores/mediaCache';
17
+ import { useMediaCacheStore, generateContentKey } from '../../../stores/mediaCache';
18
18
 
19
19
  import type { StreamProviderProps, VideoPlayerRef, StreamSource, BlobSource, DataUrlSource, ErrorFallbackProps } from '../types';
20
20
  import { videoDebug } from '../utils/debug';
@@ -77,14 +77,12 @@ export const StreamProvider = forwardRef<VideoPlayerRef, StreamProviderProps>(
77
77
  const contentKeyRef = useRef<string | null>(null);
78
78
  const lastSavedTimeRef = useRef<number>(0);
79
79
 
80
- // Cache hooks
81
- const {
82
- getOrCreateBlobUrl,
83
- releaseBlobUrl,
84
- getOrCreateStreamUrl,
85
- saveVideoPosition,
86
- getVideoPosition,
87
- } = useVideoCache();
80
+ // Get stable function references from store (not from hook to avoid re-renders)
81
+ const getOrCreateBlobUrl = useMediaCacheStore.getState().getOrCreateBlobUrl;
82
+ const releaseBlobUrl = useMediaCacheStore.getState().releaseBlobUrl;
83
+ const getOrCreateStreamUrl = useMediaCacheStore.getState().getOrCreateStreamUrl;
84
+ const saveVideoPosition = useMediaCacheStore.getState().saveVideoPosition;
85
+ const getVideoPosition = useMediaCacheStore.getState().getVideoPosition;
88
86
 
89
87
  // Retry function for error fallback
90
88
  // Regenerates URL for stream sources to get fresh token/session
@@ -143,12 +141,31 @@ export const StreamProvider = forwardRef<VideoPlayerRef, StreamProviderProps>(
143
141
  []
144
142
  );
145
143
 
144
+ // Track unmount for cleanup
145
+ const isMountedRef = useRef(true);
146
+ useEffect(() => {
147
+ isMountedRef.current = true;
148
+ return () => {
149
+ isMountedRef.current = false;
150
+ // Release blob URL only on actual unmount
151
+ if (contentKeyRef.current) {
152
+ useMediaCacheStore.getState().releaseBlobUrl(contentKeyRef.current);
153
+ contentKeyRef.current = null;
154
+ }
155
+ };
156
+ }, []);
157
+
146
158
  // Create video URL based on source type with caching
147
159
  useEffect(() => {
148
- // Cleanup previous blob URL from cache
160
+ // Release previous blob URL if source changed
149
161
  if (contentKeyRef.current) {
150
- releaseBlobUrl(contentKeyRef.current);
151
- contentKeyRef.current = null;
162
+ const newKey = source.type === 'blob'
163
+ ? generateContentKey((source as BlobSource).data)
164
+ : null;
165
+ if (newKey !== contentKeyRef.current) {
166
+ releaseBlobUrl(contentKeyRef.current);
167
+ contentKeyRef.current = null;
168
+ }
152
169
  }
153
170
 
154
171
  setHasError(false);
@@ -198,13 +215,9 @@ export const StreamProvider = forwardRef<VideoPlayerRef, StreamProviderProps>(
198
215
  setErrorMessage('Invalid video source');
199
216
  }
200
217
 
201
- return () => {
202
- if (contentKeyRef.current) {
203
- releaseBlobUrl(contentKeyRef.current);
204
- contentKeyRef.current = null;
205
- }
206
- };
207
- }, [source, getOrCreateBlobUrl, getOrCreateStreamUrl, releaseBlobUrl]);
218
+ // No cleanup here - cleanup happens in unmount effect above
219
+ // eslint-disable-next-line react-hooks/exhaustive-deps
220
+ }, [source]);
208
221
 
209
222
  // Get source key for position caching
210
223
  const getSourceKey = useCallback(() => {
@@ -244,7 +257,8 @@ export const StreamProvider = forwardRef<VideoPlayerRef, StreamProviderProps>(
244
257
  }
245
258
 
246
259
  onCanPlay?.();
247
- }, [getSourceKey, getVideoPosition, onCanPlay]);
260
+ // eslint-disable-next-line react-hooks/exhaustive-deps
261
+ }, [getSourceKey, onCanPlay]);
248
262
 
249
263
  // Save playback position periodically
250
264
  const handleTimeUpdate = useCallback(() => {
@@ -262,7 +276,8 @@ export const StreamProvider = forwardRef<VideoPlayerRef, StreamProviderProps>(
262
276
  }
263
277
 
264
278
  onTimeUpdate?.(video.currentTime, video.duration);
265
- }, [getSourceKey, saveVideoPosition, onTimeUpdate]);
279
+ // eslint-disable-next-line react-hooks/exhaustive-deps
280
+ }, [getSourceKey, onTimeUpdate]);
266
281
 
267
282
  // Save position on pause
268
283
  const handlePause = useCallback(() => {
@@ -273,7 +288,8 @@ export const StreamProvider = forwardRef<VideoPlayerRef, StreamProviderProps>(
273
288
  lastSavedTimeRef.current = video.currentTime;
274
289
  }
275
290
  onPause?.();
276
- }, [getSourceKey, saveVideoPosition, onPause]);
291
+ // eslint-disable-next-line react-hooks/exhaustive-deps
292
+ }, [getSourceKey, onPause]);
277
293
 
278
294
  // Handle buffer progress
279
295
  const handleProgress = useCallback(() => {
@@ -110,6 +110,18 @@ export {
110
110
  mergePeaks,
111
111
  resamplePeaks,
112
112
  smoothPeaks,
113
+ // Hybrid Audio Player (HTML5 audio + Web Audio visualization)
114
+ HybridSimplePlayer,
115
+ HybridAudioPlayer,
116
+ HybridWaveform,
117
+ HybridAudioProvider,
118
+ useHybridAudioContext,
119
+ useHybridAudioState,
120
+ useHybridAudioControls,
121
+ useHybridAudioLevels,
122
+ useHybridWebAudio,
123
+ useHybridAudio,
124
+ useHybridAudioAnalysis,
113
125
  } from './AudioPlayer';
114
126
  export type {
115
127
  SimpleAudioPlayerProps,
@@ -136,6 +148,16 @@ export type {
136
148
  LoadedRange,
137
149
  ProgressiveAudioState,
138
150
  ProgressiveAudioControls,
151
+ // Hybrid types
152
+ HybridSimplePlayerProps,
153
+ HybridAudioPlayerProps,
154
+ HybridWaveformProps,
155
+ HybridAudioProviderProps,
156
+ HybridAudioContextValue,
157
+ UseHybridAudioOptions,
158
+ HybridAudioState,
159
+ HybridAudioControls,
160
+ HybridWebAudioAPI,
139
161
  } from './AudioPlayer';
140
162
 
141
163
  // Export ImageViewer
@@ -1,148 +0,0 @@
1
- # AudioPlayer Refactoring Plan
2
-
3
- ## Goal
4
-
5
- Decompose the AudioPlayer module into a clean, maintainable folder structure with proper separation of concerns.
6
-
7
- ## Current Issues
8
-
9
- 1. **`context.tsx` is too large (574 lines)** - contains 4 different hooks and provider
10
- 2. **`types.ts` is monolithic (185 lines)** - mixes audio, component, and effect types
11
- 3. **`effects/index.ts` is overloaded (413 lines)** - types, constants, and calculations together
12
- 4. **`AudioReactiveCover.tsx` has inline effect components** - harder to maintain
13
-
14
- ## Target Structure
15
-
16
- ```
17
- AudioPlayer/
18
- ├── index.ts # Public API (re-exports)
19
-
20
- ├── types/
21
- │ ├── index.ts # Re-exports all types
22
- │ ├── audio.ts # Core audio types
23
- │ ├── components.ts # Component props
24
- │ └── effects.ts # Effect-related types
25
-
26
- ├── hooks/
27
- │ ├── index.ts # Re-exports all hooks
28
- │ ├── useSharedWebAudio.ts # Web Audio API management
29
- │ ├── useAudioAnalysis.ts # Frequency analysis
30
- │ ├── useAudioHotkeys.ts # Keyboard shortcuts (existing)
31
- │ └── useVisualization.tsx # Settings + Provider (renamed)
32
-
33
- ├── context/
34
- │ ├── index.ts # Re-exports
35
- │ ├── AudioProvider.tsx # Provider component only
36
- │ └── selectors.ts # useAudio, useAudioControls, useAudioState, useAudioElement
37
-
38
- ├── components/
39
- │ ├── index.ts # Re-exports
40
- │ ├── AudioPlayer.tsx # Main player UI
41
- │ ├── AudioEqualizer.tsx # Equalizer visualization
42
- │ ├── SimpleAudioPlayer.tsx # Easy-to-use wrapper
43
- │ ├── ShortcutsPopover.tsx # Keyboard shortcuts popover
44
- │ ├── VisualizationToggle.tsx # Effect toggle button
45
- │ └── ReactiveCover/ # Cover with effects
46
- │ ├── index.tsx # Main component
47
- │ ├── GlowEffect.tsx # Glow effect
48
- │ ├── OrbsEffect.tsx # Orbs effect
49
- │ ├── SpotlightEffect.tsx # Spotlight effect
50
- │ └── MeshEffect.tsx # Mesh gradient effect
51
-
52
- ├── effects/
53
- │ ├── index.ts # Re-exports
54
- │ ├── constants.ts # INTENSITY_CONFIG, COLOR_SCHEMES
55
- │ ├── calculations.ts # calculateGlowLayers, calculateOrbs, etc.
56
- │ └── animations.ts # EFFECT_ANIMATIONS CSS string
57
-
58
- └── utils/
59
- ├── index.ts # Re-exports
60
- └── formatTime.ts # Time formatting helper
61
- ```
62
-
63
- ## Migration Steps
64
-
65
- ### Phase 1: Create folder structure
66
- - [ ] Create `types/`, `hooks/`, `context/`, `components/`, `effects/`, `utils/` folders
67
-
68
- ### Phase 2: Split types
69
- - [ ] Create `types/audio.ts` - AudioSource, PlaybackStatus, SharedWebAudioContext, AudioContextState
70
- - [ ] Create `types/components.ts` - AudioPlayerProps, AudioEqualizerProps, etc.
71
- - [ ] Create `types/effects.ts` - EffectVariant, AudioLevels, EffectConfig, etc.
72
- - [ ] Create `types/index.ts` - re-export all
73
-
74
- ### Phase 3: Extract hooks from context.tsx
75
- - [ ] Create `hooks/useSharedWebAudio.ts` - extract from context.tsx
76
- - [ ] Create `hooks/useAudioAnalysis.ts` - extract from context.tsx
77
- - [ ] Move `useAudioHotkeys.ts` to `hooks/`
78
- - [ ] Move `useAudioVisualization.tsx` to `hooks/useVisualization.tsx`
79
- - [ ] Create `hooks/index.ts`
80
-
81
- ### Phase 4: Refactor context
82
- - [ ] Create `context/AudioProvider.tsx` - provider only
83
- - [ ] Create `context/selectors.ts` - useAudio, useAudioControls, useAudioState, useAudioElement
84
- - [ ] Create `context/index.ts`
85
-
86
- ### Phase 5: Reorganize components
87
- - [ ] Move `AudioPlayer.tsx` to `components/`
88
- - [ ] Move `AudioEqualizer.tsx` to `components/`
89
- - [ ] Move `SimpleAudioPlayer.tsx` to `components/`
90
- - [ ] Rename and move `AudioShortcutsPopover.tsx` to `components/ShortcutsPopover.tsx`
91
- - [ ] Move `VisualizationToggle.tsx` to `components/`
92
- - [ ] Split `AudioReactiveCover.tsx` into `components/ReactiveCover/`
93
-
94
- ### Phase 6: Refactor effects
95
- - [ ] Create `effects/constants.ts` - INTENSITY_CONFIG, COLOR_SCHEMES
96
- - [ ] Create `effects/calculations.ts` - all calculate* functions
97
- - [ ] Create `effects/animations.ts` - EFFECT_ANIMATIONS
98
- - [ ] Update `effects/index.ts`
99
-
100
- ### Phase 7: Create utils
101
- - [ ] Create `utils/formatTime.ts` - extract from AudioPlayer.tsx
102
- - [ ] Create `utils/index.ts`
103
-
104
- ### Phase 8: Update main index.ts
105
- - [ ] Update `index.ts` to re-export from new locations
106
- - [ ] Ensure backward compatibility of public API
107
-
108
- ### Phase 9: Cleanup
109
- - [ ] Delete old files
110
- - [ ] Run type check
111
- - [ ] Test imports
112
-
113
- ## File Size Targets
114
-
115
- | File | Current | Target |
116
- |------|---------|--------|
117
- | context.tsx | 574 lines | Split into 4 files (~100-150 each) |
118
- | types.ts | 185 lines | Split into 3 files (~60 each) |
119
- | effects/index.ts | 413 lines | Split into 3 files (~100-150 each) |
120
- | AudioReactiveCover.tsx | 390 lines | Split into 5 files (~80 each) |
121
-
122
- ## Public API (must remain unchanged)
123
-
124
- ```typescript
125
- // Components
126
- export { SimpleAudioPlayer } from './components';
127
- export { AudioPlayer } from './components';
128
- export { AudioEqualizer } from './components';
129
- export { AudioReactiveCover } from './components';
130
- export { AudioShortcutsPopover } from './components'; // alias for backward compat
131
-
132
- // Context & Hooks
133
- export { AudioProvider, useAudio, useAudioControls, useAudioState, useAudioElement } from './context';
134
- export { useAudioHotkeys, AUDIO_SHORTCUTS } from './hooks';
135
- export { useAudioVisualization, VisualizationProvider } from './hooks'; // alias
136
-
137
- // Effects utilities
138
- export { INTENSITY_CONFIG, COLOR_SCHEMES, ... } from './effects';
139
-
140
- // Types (all existing types)
141
- export type { AudioSource, PlaybackStatus, ... } from './types';
142
- ```
143
-
144
- ## Notes
145
-
146
- - Keep backward compatibility for all public exports
147
- - Internal imports will change but external API stays the same
148
- - Run `pnpm check` after each phase to catch issues early
@@ -1,301 +0,0 @@
1
- # Phase 2: Types Split
2
-
3
- ## Source: `types.ts` (185 lines)
4
-
5
- Split into 3 files by domain.
6
-
7
- ---
8
-
9
- ## `types/audio.ts`
10
-
11
- Core audio-related types.
12
-
13
- ```typescript
14
- import type WaveSurfer from 'wavesurfer.js';
15
- import type { AudioLevels } from '../effects';
16
-
17
- // =============================================================================
18
- // AUDIO SOURCE
19
- // =============================================================================
20
-
21
- export interface AudioSource {
22
- uri: string;
23
- }
24
-
25
- // =============================================================================
26
- // PLAYBACK STATE
27
- // =============================================================================
28
-
29
- export interface PlaybackStatus {
30
- isLoaded: boolean;
31
- isPlaying: boolean;
32
- duration: number;
33
- currentTime: number;
34
- volume: number;
35
- isMuted: boolean;
36
- }
37
-
38
- // =============================================================================
39
- // WAVEFORM OPTIONS
40
- // =============================================================================
41
-
42
- export interface WaveformOptions {
43
- waveColor?: string;
44
- progressColor?: string;
45
- height?: number;
46
- barWidth?: number;
47
- barRadius?: number;
48
- barGap?: number;
49
- cursorWidth?: number;
50
- cursorColor?: string;
51
- }
52
-
53
- // =============================================================================
54
- // EQUALIZER OPTIONS
55
- // =============================================================================
56
-
57
- export interface EqualizerOptions {
58
- barCount?: number;
59
- height?: number;
60
- gap?: number;
61
- showPeaks?: boolean;
62
- barColor?: string;
63
- peakColor?: string;
64
- }
65
-
66
- // =============================================================================
67
- // SHARED WEB AUDIO CONTEXT
68
- // =============================================================================
69
-
70
- export interface SharedWebAudioContext {
71
- audioContext: AudioContext | null;
72
- sourceNode: MediaElementAudioSourceNode | null;
73
- createAnalyser: (options?: { fftSize?: number; smoothing?: number }) => AnalyserNode | null;
74
- disconnectAnalyser: (analyser: AnalyserNode) => void;
75
- }
76
-
77
- // =============================================================================
78
- // AUDIO CONTEXT STATE
79
- // =============================================================================
80
-
81
- export interface AudioContextState {
82
- // Core instances
83
- wavesurfer: WaveSurfer | null;
84
- audioElement: HTMLMediaElement | null;
85
- sharedAudio: SharedWebAudioContext;
86
-
87
- // Playback state
88
- isReady: boolean;
89
- isPlaying: boolean;
90
- currentTime: number;
91
- duration: number;
92
- volume: number;
93
- isMuted: boolean;
94
- isLooping: boolean;
95
-
96
- // Audio analysis
97
- audioLevels: AudioLevels;
98
-
99
- // Actions
100
- play: () => Promise<void>;
101
- pause: () => void;
102
- togglePlay: () => void;
103
- seek: (time: number) => void;
104
- seekTo: (progress: number) => void;
105
- skip: (seconds: number) => void;
106
- setVolume: (volume: number) => void;
107
- toggleMute: () => void;
108
- toggleLoop: () => void;
109
- setLoop: (enabled: boolean) => void;
110
- restart: () => void;
111
- }
112
- ```
113
-
114
- ---
115
-
116
- ## `types/components.ts`
117
-
118
- Component props types.
119
-
120
- ```typescript
121
- import type { CSSProperties } from 'react';
122
- import type { WaveformOptions, EqualizerOptions, AudioSource, PlaybackStatus } from './audio';
123
-
124
- // =============================================================================
125
- // AUDIO PLAYER PROPS
126
- // =============================================================================
127
-
128
- export interface AudioPlayerProps {
129
- showControls?: boolean;
130
- showWaveform?: boolean;
131
- showEqualizer?: boolean;
132
- showTimer?: boolean;
133
- showVolume?: boolean;
134
- showLoop?: boolean;
135
- waveformOptions?: WaveformOptions;
136
- equalizerOptions?: EqualizerOptions;
137
- className?: string;
138
- style?: CSSProperties;
139
- }
140
-
141
- // =============================================================================
142
- // AUDIO EQUALIZER PROPS
143
- // =============================================================================
144
-
145
- export interface AudioEqualizerProps {
146
- barCount?: number;
147
- height?: number;
148
- gap?: number;
149
- showPeaks?: boolean;
150
- barColor?: string;
151
- peakColor?: string;
152
- className?: string;
153
- }
154
-
155
- // =============================================================================
156
- // AUDIO REACTIVE COVER PROPS
157
- // =============================================================================
158
-
159
- export interface AudioReactiveCoverProps {
160
- variant?: 'glow' | 'orbs' | 'spotlight' | 'mesh';
161
- intensity?: 'subtle' | 'medium' | 'strong';
162
- colorScheme?: 'primary' | 'vibrant' | 'cool' | 'warm';
163
- }
164
-
165
- // =============================================================================
166
- // AUDIO VIEWER PROPS (legacy)
167
- // =============================================================================
168
-
169
- export interface AudioViewerProps {
170
- source: AudioSource;
171
- autoPlay?: boolean;
172
- showControls?: boolean;
173
- showWaveform?: boolean;
174
- showEqualizer?: boolean;
175
- showTimer?: boolean;
176
- showVolume?: boolean;
177
- waveformOptions?: WaveformOptions;
178
- equalizerOptions?: EqualizerOptions;
179
- onPlaybackStatusUpdate?: (status: PlaybackStatus) => void;
180
- className?: string;
181
- style?: CSSProperties;
182
- }
183
- ```
184
-
185
- ---
186
-
187
- ## `types/effects.ts`
188
-
189
- Effect-related types (moved from effects/index.ts).
190
-
191
- ```typescript
192
- // =============================================================================
193
- // EFFECT TYPES
194
- // =============================================================================
195
-
196
- export type EffectVariant = 'glow' | 'orbs' | 'spotlight' | 'mesh';
197
- export type EffectIntensity = 'subtle' | 'medium' | 'strong';
198
- export type EffectColorScheme = 'primary' | 'vibrant' | 'cool' | 'warm';
199
-
200
- export interface AudioLevels {
201
- bass: number;
202
- mid: number;
203
- high: number;
204
- overall: number;
205
- }
206
-
207
- export interface EffectConfig {
208
- opacity: number;
209
- scale: number;
210
- blur: string;
211
- }
212
-
213
- export interface EffectColors {
214
- colors: string[];
215
- hueShift: number;
216
- }
217
-
218
- export interface EffectLayer {
219
- inset: number;
220
- opacity: number;
221
- scale: number;
222
- background: string;
223
- blur: string;
224
- animation?: string;
225
- }
226
-
227
- export interface Orb {
228
- x: number;
229
- y: number;
230
- size: number;
231
- color: string;
232
- opacity: number;
233
- scale: number;
234
- }
235
-
236
- export interface MeshGradient {
237
- width: string;
238
- height: string;
239
- top?: string;
240
- bottom?: string;
241
- left?: string;
242
- right?: string;
243
- color: string;
244
- opacity: number;
245
- scale: number;
246
- rotation: number;
247
- blur: string;
248
- isCenter?: boolean;
249
- }
250
-
251
- export interface SpotlightData {
252
- rotation: number;
253
- inset: number;
254
- colors: Array<{ color: string; opacity: number }>;
255
- pulseInset: number;
256
- pulseOpacity: number;
257
- pulseScale: number;
258
- ringOpacity: number;
259
- ringScale: number;
260
- }
261
- ```
262
-
263
- ---
264
-
265
- ## `types/index.ts`
266
-
267
- Re-export all types.
268
-
269
- ```typescript
270
- // Audio types
271
- export type {
272
- AudioSource,
273
- PlaybackStatus,
274
- WaveformOptions,
275
- EqualizerOptions,
276
- SharedWebAudioContext,
277
- AudioContextState,
278
- } from './audio';
279
-
280
- // Component props
281
- export type {
282
- AudioPlayerProps,
283
- AudioEqualizerProps,
284
- AudioReactiveCoverProps,
285
- AudioViewerProps,
286
- } from './components';
287
-
288
- // Effect types
289
- export type {
290
- EffectVariant,
291
- EffectIntensity,
292
- EffectColorScheme,
293
- AudioLevels,
294
- EffectConfig,
295
- EffectColors,
296
- EffectLayer,
297
- Orb,
298
- MeshGradient,
299
- SpotlightData,
300
- } from './effects';
301
- ```