@wavv/ui 2.4.14 → 2.4.15-alpha.2

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.
@@ -13,6 +13,9 @@ const Audio = ({ src, title, width, infoPosition, centerAlignContent, small, tin
13
13
  const [displayCurrent, setDisplayCurrent] = useState('');
14
14
  const [displayDuration, setDisplayDuration] = useState('0:00');
15
15
  const audioRef = useRef(null);
16
+ const isSeekingRef = useRef(false);
17
+ const seekedTimeoutRef = useRef(null);
18
+ const END_EPSILON_SECONDS = 0.75;
16
19
  const { height = 30, showHoverTime = false, playedColor, unplayedColor } = 'object' == typeof waveform ? waveform : {};
17
20
  const play = ()=>{
18
21
  const { current: audio } = audioRef;
@@ -32,9 +35,20 @@ const Audio = ({ src, title, width, infoPosition, centerAlignContent, small, tin
32
35
  const { current: audio } = audioRef;
33
36
  return audio ? !audio.paused : false;
34
37
  };
38
+ const isNearEnd = (sec)=>totalDuration > 0 && totalDuration - sec <= END_EPSILON_SECONDS;
35
39
  const togglePlayPause = ()=>{
36
40
  if (isPlaying) pause();
37
- else play();
41
+ else {
42
+ if (isNearEnd(progress)) {
43
+ setProgress(0);
44
+ setDisplayCurrent('0:00');
45
+ const { current: audio } = audioRef;
46
+ if (audio) try {
47
+ audio.currentTime = 0;
48
+ } catch (_e) {}
49
+ }
50
+ play();
51
+ }
38
52
  };
39
53
  useImperativeHandle(ref, ()=>({
40
54
  play,
@@ -56,6 +70,16 @@ const Audio = ({ src, title, width, infoPosition, centerAlignContent, small, tin
56
70
  const handleAudioStop = (event)=>{
57
71
  setIsPlaying(false);
58
72
  setIsCleared(true);
73
+ setProgress(0);
74
+ setDisplayCurrent('0:00');
75
+ const { current: audio } = audioRef;
76
+ if (audio) try {
77
+ audio.currentTime = 0;
78
+ window.setTimeout(()=>{
79
+ const ct = audio.currentTime ?? 0;
80
+ if (ct > 0.5) audio.currentTime = 0;
81
+ }, 120);
82
+ } catch (_e) {}
59
83
  if (onStop) onStop(event);
60
84
  };
61
85
  const handleAudioError = ()=>{
@@ -88,6 +112,9 @@ const Audio = ({ src, title, width, infoPosition, centerAlignContent, small, tin
88
112
  src,
89
113
  fallbackDuration
90
114
  ]);
115
+ useEffect(()=>()=>{
116
+ if (seekedTimeoutRef.current) clearTimeout(seekedTimeoutRef.current);
117
+ }, []);
91
118
  const formatTime = (time)=>{
92
119
  if (!Number.isFinite(time) || time < 0) return '0:00';
93
120
  const mins = Math.floor(time / 60);
@@ -95,6 +122,7 @@ const Audio = ({ src, title, width, infoPosition, centerAlignContent, small, tin
95
122
  return `${mins}:${secs.toString().padStart(2, '0')}`;
96
123
  };
97
124
  const updateProgress = ()=>{
125
+ if (isSeekingRef.current) return;
98
126
  const { current: audio } = audioRef;
99
127
  if (audio) {
100
128
  const { currentTime } = audio;
@@ -128,9 +156,27 @@ const Audio = ({ src, title, width, infoPosition, centerAlignContent, small, tin
128
156
  }, 100);
129
157
  }
130
158
  };
159
+ const handleSeeked = ()=>{
160
+ isSeekingRef.current = false;
161
+ if (seekedTimeoutRef.current) {
162
+ clearTimeout(seekedTimeoutRef.current);
163
+ seekedTimeoutRef.current = null;
164
+ }
165
+ };
131
166
  const handleControlGrab = (value)=>{
132
167
  const sliderPosition = Array.isArray(value) ? value[0] : value;
133
- if (audioRef?.current && Number.isFinite(sliderPosition) && Number.isFinite(totalDuration) && totalDuration > 0) audioRef.current.currentTime = Math.max(0, Math.min(sliderPosition, totalDuration));
168
+ if (!audioRef?.current || !Number.isFinite(sliderPosition) || !Number.isFinite(totalDuration) || totalDuration <= 0) return;
169
+ const maxSeekTarget = Math.max(0, totalDuration - END_EPSILON_SECONDS);
170
+ const clamped = Math.min(Math.max(sliderPosition, 0), maxSeekTarget);
171
+ isSeekingRef.current = true;
172
+ if (seekedTimeoutRef.current) clearTimeout(seekedTimeoutRef.current);
173
+ seekedTimeoutRef.current = setTimeout(()=>{
174
+ isSeekingRef.current = false;
175
+ seekedTimeoutRef.current = null;
176
+ }, 300);
177
+ setProgress(clamped);
178
+ setDisplayCurrent(formatTime(clamped));
179
+ audioRef.current.currentTime = clamped;
134
180
  };
135
181
  const hideSlider = isCleared && hideSliderOnStop;
136
182
  const hideTime = isCleared && hideTimeOnStop;
@@ -199,6 +245,7 @@ const Audio = ({ src, title, width, infoPosition, centerAlignContent, small, tin
199
245
  onEmptied: handleAudioStop,
200
246
  onEnded: handleAudioStop,
201
247
  onTimeUpdate: updateProgress,
248
+ onSeeked: handleSeeked,
202
249
  onDurationChange: handleLoad,
203
250
  onLoadedMetadata: handleLoad,
204
251
  onLoadedData: handleLoad,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wavv/ui",
3
- "version": "2.4.14",
3
+ "version": "2.4.15-alpha.2",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": {