trix-ui 0.2.3 → 0.2.4
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.
package/package.json
CHANGED
|
@@ -164,11 +164,12 @@ const MusicPlayerCardBase = React.forwardRef<HTMLDivElement, MusicPlayerCardProp
|
|
|
164
164
|
const [trackIndex, setTrackIndex] = React.useState(
|
|
165
165
|
clamp(initialTrackIndex, 0, Math.max((tracks?.length ?? 1) - 1, 0))
|
|
166
166
|
);
|
|
167
|
-
const [uploadedFile, setUploadedFile] = React.useState<File | null>(null);
|
|
168
|
-
const [currentTimeSec, setCurrentTimeSec] = React.useState(0);
|
|
169
|
-
const [durationSec, setDurationSec] = React.useState(0);
|
|
170
|
-
const
|
|
171
|
-
const
|
|
167
|
+
const [uploadedFile, setUploadedFile] = React.useState<File | null>(null);
|
|
168
|
+
const [currentTimeSec, setCurrentTimeSec] = React.useState(0);
|
|
169
|
+
const [durationSec, setDurationSec] = React.useState(0);
|
|
170
|
+
const [playbackError, setPlaybackError] = React.useState<string | null>(null);
|
|
171
|
+
const audioRef = React.useRef<HTMLAudioElement | null>(null);
|
|
172
|
+
const shuffleHistoryRef = React.useRef<number[]>([]);
|
|
172
173
|
|
|
173
174
|
const isShuffle = isShuffleOn ?? internalShuffle;
|
|
174
175
|
const isRepeat = isRepeatOn ?? internalRepeat;
|
|
@@ -186,16 +187,24 @@ const MusicPlayerCardBase = React.forwardRef<HTMLDivElement, MusicPlayerCardProp
|
|
|
186
187
|
? playlist[clamp(trackIndex, 0, playlist.length - 1)]
|
|
187
188
|
: fallbackTrack;
|
|
188
189
|
|
|
189
|
-
const propFileUrl = useObjectUrl(audioFile);
|
|
190
|
-
const uploadedFileUrl = useObjectUrl(uploadedFile ?? undefined);
|
|
191
|
-
const resolvedSrc = propFileUrl ?? uploadedFileUrl ?? activeTrack.src;
|
|
192
|
-
const isPlayable = Boolean(resolvedSrc);
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const
|
|
190
|
+
const propFileUrl = useObjectUrl(audioFile);
|
|
191
|
+
const uploadedFileUrl = useObjectUrl(uploadedFile ?? undefined);
|
|
192
|
+
const resolvedSrc = propFileUrl ?? uploadedFileUrl ?? activeTrack.src;
|
|
193
|
+
const isPlayable = Boolean(resolvedSrc);
|
|
194
|
+
const hasExplicitSource =
|
|
195
|
+
Boolean(audioSrc) ||
|
|
196
|
+
Boolean(audioFile) ||
|
|
197
|
+
Boolean(uploadedFile) ||
|
|
198
|
+
Boolean(playlist.length && activeTrack.src);
|
|
199
|
+
const missingSourceMessage =
|
|
200
|
+
!resolvedSrc && hasExplicitSource ? "Audio file not found." : null;
|
|
201
|
+
|
|
202
|
+
const derivedProgress =
|
|
203
|
+
durationSec > 0 ? clamp((currentTimeSec / durationSec) * 100, 0, 100) : 0;
|
|
204
|
+
const pct = clamp(progress ?? derivedProgress, 0, 100);
|
|
205
|
+
const resolvedCurrentTime = currentTime ?? formatTime(currentTimeSec);
|
|
206
|
+
const resolvedTotalTime = totalTime ?? formatTime(durationSec);
|
|
207
|
+
const errorMessage = playbackError ?? missingSourceMessage;
|
|
199
208
|
|
|
200
209
|
const requestPlay = React.useCallback(
|
|
201
210
|
async (nextPlaying: boolean): Promise<void> => {
|
|
@@ -210,16 +219,21 @@ const MusicPlayerCardBase = React.forwardRef<HTMLDivElement, MusicPlayerCardProp
|
|
|
210
219
|
} else {
|
|
211
220
|
audio.pause();
|
|
212
221
|
}
|
|
213
|
-
} catch {
|
|
214
|
-
if (isPlaying === undefined) {
|
|
215
|
-
setInternalPlaying(false);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
222
|
+
} catch {
|
|
223
|
+
if (isPlaying === undefined) {
|
|
224
|
+
setInternalPlaying(false);
|
|
225
|
+
}
|
|
226
|
+
setPlaybackError("Audio file is not playable.");
|
|
227
|
+
onPlayStateChange?.(false);
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
[isPlaying, onPlayStateChange, resolvedSrc]
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
React.useEffect(() => {
|
|
234
|
+
setPlaybackError(null);
|
|
235
|
+
}, [resolvedSrc]);
|
|
236
|
+
|
|
223
237
|
React.useEffect(() => {
|
|
224
238
|
const audio = audioRef.current;
|
|
225
239
|
if (!audio) return;
|
|
@@ -420,19 +434,27 @@ const MusicPlayerCardBase = React.forwardRef<HTMLDivElement, MusicPlayerCardProp
|
|
|
420
434
|
)}
|
|
421
435
|
{...props}
|
|
422
436
|
>
|
|
423
|
-
<audio
|
|
424
|
-
ref={audioRef}
|
|
425
|
-
preload="metadata"
|
|
426
|
-
onTimeUpdate={(event) => {
|
|
427
|
-
const audio = event.currentTarget;
|
|
428
|
-
setCurrentTimeSec(audio.currentTime);
|
|
429
|
-
}}
|
|
430
|
-
onLoadedMetadata={(event) => {
|
|
431
|
-
const audio = event.currentTarget;
|
|
432
|
-
setDurationSec(audio.duration || 0);
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
437
|
+
<audio
|
|
438
|
+
ref={audioRef}
|
|
439
|
+
preload="metadata"
|
|
440
|
+
onTimeUpdate={(event) => {
|
|
441
|
+
const audio = event.currentTarget;
|
|
442
|
+
setCurrentTimeSec(audio.currentTime);
|
|
443
|
+
}}
|
|
444
|
+
onLoadedMetadata={(event) => {
|
|
445
|
+
const audio = event.currentTarget;
|
|
446
|
+
setDurationSec(audio.duration || 0);
|
|
447
|
+
setPlaybackError(null);
|
|
448
|
+
}}
|
|
449
|
+
onError={() => {
|
|
450
|
+
setPlaybackError("Audio file is not playable.");
|
|
451
|
+
if (isPlaying === undefined) {
|
|
452
|
+
setInternalPlaying(false);
|
|
453
|
+
}
|
|
454
|
+
onPlayStateChange?.(false);
|
|
455
|
+
}}
|
|
456
|
+
onEnded={handleEnded}
|
|
457
|
+
/>
|
|
436
458
|
{/* Album Art */}
|
|
437
459
|
<div
|
|
438
460
|
className={cn(
|
|
@@ -498,10 +520,13 @@ const MusicPlayerCardBase = React.forwardRef<HTMLDivElement, MusicPlayerCardProp
|
|
|
498
520
|
/>
|
|
499
521
|
</div>
|
|
500
522
|
|
|
501
|
-
<div className="flex justify-between text-[10px] text-stone-400 font-mono mb-4">
|
|
502
|
-
<span>{resolvedCurrentTime}</span>
|
|
503
|
-
<span>{resolvedTotalTime}</span>
|
|
504
|
-
</div>
|
|
523
|
+
<div className="flex justify-between text-[10px] text-stone-400 font-mono mb-4">
|
|
524
|
+
<span>{resolvedCurrentTime}</span>
|
|
525
|
+
<span>{resolvedTotalTime}</span>
|
|
526
|
+
</div>
|
|
527
|
+
{errorMessage ? (
|
|
528
|
+
<p className="mb-3 text-xs text-rose-500">{errorMessage}</p>
|
|
529
|
+
) : null}
|
|
505
530
|
|
|
506
531
|
{/* Controls */}
|
|
507
532
|
<div className={cn("flex justify-between items-center mt-auto px-2", controlsClassName)}>
|