@exode-team/react-recorder 1.1.5 → 1.1.8
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/dist/components/AudioRecorder.d.ts +1 -1
- package/dist/components/AudioRecorder.d.ts.map +1 -1
- package/dist/components/RecordingShell/RecordingShell.d.ts +1 -0
- package/dist/components/RecordingShell/RecordingShell.d.ts.map +1 -1
- package/dist/components/RecordingShell/RecordingShell.styled.d.ts +0 -2
- package/dist/components/RecordingShell/RecordingShell.styled.d.ts.map +1 -1
- package/dist/components/WaveformBars/WaveformBars.d.ts +4 -0
- package/dist/components/WaveformBars/WaveformBars.d.ts.map +1 -1
- package/dist/components/WaveformBars/WaveformBars.styled.d.ts +3 -0
- package/dist/components/WaveformBars/WaveformBars.styled.d.ts.map +1 -0
- package/dist/hooks/useAudioRecorderHandlers.d.ts.map +1 -1
- package/dist/hooks/useMediaRecorder.d.ts.map +1 -1
- package/dist/hooks/useRecordingSender.d.ts +2 -1
- package/dist/hooks/useRecordingSender.d.ts.map +1 -1
- package/dist/hooks/useRecordingTiming.d.ts +2 -0
- package/dist/hooks/useRecordingTiming.d.ts.map +1 -1
- package/dist/hooks/useVoiceRecorder.d.ts.map +1 -1
- package/dist/hooks/useVoiceRecorderInput.d.ts +1 -1
- package/dist/hooks/useVoiceRecorderInput.d.ts.map +1 -1
- package/dist/index.cjs +116 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +116 -51
- package/dist/index.js.map +1 -1
- package/dist/platform/audio-blob-fetcher.d.ts.map +1 -1
- package/dist/types/recorder.d.ts +8 -1
- package/dist/types/recorder.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -178,7 +178,11 @@ const decodeAudioLevels = async (blob, barCount = AUDIO_LEVEL_BARS) => {
|
|
|
178
178
|
* @author: exode <hello@exode.ru>
|
|
179
179
|
*/
|
|
180
180
|
const fetchAudioBlob = async (url, signal) => {
|
|
181
|
-
const response = await fetch(url, {
|
|
181
|
+
const response = await fetch(url, {
|
|
182
|
+
signal,
|
|
183
|
+
mode: 'cors',
|
|
184
|
+
credentials: 'omit',
|
|
185
|
+
});
|
|
182
186
|
return response.blob();
|
|
183
187
|
};
|
|
184
188
|
|
|
@@ -270,6 +274,9 @@ const useMediaRecorder = (callbacks) => {
|
|
|
270
274
|
if (!mediaRecorderRef.current || !isRecording) {
|
|
271
275
|
return;
|
|
272
276
|
}
|
|
277
|
+
if (mediaRecorderRef.current.state === 'paused') {
|
|
278
|
+
mediaRecorderRef.current.resume();
|
|
279
|
+
}
|
|
273
280
|
mediaRecorderRef.current.stop();
|
|
274
281
|
}, [isRecording]);
|
|
275
282
|
const cancelRecording = useCallback(() => {
|
|
@@ -428,6 +435,7 @@ const useAudioPlayback = () => {
|
|
|
428
435
|
* @author: exode <hello@exode.ru>
|
|
429
436
|
*/
|
|
430
437
|
const useRecordingTiming = () => {
|
|
438
|
+
const [lastDuration, setLastDuration] = useState(0);
|
|
431
439
|
const [recordingTime, setRecordingTime] = useState(0);
|
|
432
440
|
const timerRef = useRef(null);
|
|
433
441
|
const recordingStartRef = useRef(null);
|
|
@@ -455,6 +463,7 @@ const useRecordingTiming = () => {
|
|
|
455
463
|
const startNewSession = useCallback(() => {
|
|
456
464
|
recordingAccumulatedRef.current = 0;
|
|
457
465
|
setRecordingTime(0);
|
|
466
|
+
setLastDuration(0);
|
|
458
467
|
recordingStartRef.current = performance.now();
|
|
459
468
|
startTicker();
|
|
460
469
|
}, [startTicker]);
|
|
@@ -472,7 +481,21 @@ const useRecordingTiming = () => {
|
|
|
472
481
|
setRecordingTime(roundTo(recordingAccumulatedRef.current));
|
|
473
482
|
stopTicker();
|
|
474
483
|
}, [stopTicker]);
|
|
484
|
+
const getElapsedMs = useCallback(() => {
|
|
485
|
+
const accumulated = recordingAccumulatedRef.current;
|
|
486
|
+
const elapsed = recordingStartRef.current !== null
|
|
487
|
+
? (performance.now() - recordingStartRef.current) / 1000 + accumulated
|
|
488
|
+
: accumulated;
|
|
489
|
+
return Math.round(elapsed * 1000);
|
|
490
|
+
}, []);
|
|
475
491
|
const resetSession = useCallback(() => {
|
|
492
|
+
const accumulated = recordingAccumulatedRef.current;
|
|
493
|
+
const elapsed = recordingStartRef.current !== null
|
|
494
|
+
? (performance.now() - recordingStartRef.current) / 1000 + accumulated
|
|
495
|
+
: accumulated;
|
|
496
|
+
if (elapsed > 0) {
|
|
497
|
+
setLastDuration(roundTo(elapsed));
|
|
498
|
+
}
|
|
476
499
|
stopTicker();
|
|
477
500
|
recordingStartRef.current = null;
|
|
478
501
|
recordingAccumulatedRef.current = 0;
|
|
@@ -484,6 +507,8 @@ const useRecordingTiming = () => {
|
|
|
484
507
|
};
|
|
485
508
|
}, [stopTicker]);
|
|
486
509
|
return {
|
|
510
|
+
lastDuration,
|
|
511
|
+
getElapsedMs,
|
|
487
512
|
pauseSession,
|
|
488
513
|
resetSession,
|
|
489
514
|
recordingTime,
|
|
@@ -585,7 +610,7 @@ const useRecorderVisualization = () => {
|
|
|
585
610
|
* @author: exode <hello@exode.ru>
|
|
586
611
|
*/
|
|
587
612
|
const useRecordingSender = (options) => {
|
|
588
|
-
const { uploader, fileName, mimeType, uploadId, audioBlob, onUploaded, onRecordingError, deleteRecording, autoResetAfterUpload, } = options;
|
|
613
|
+
const { uploader, fileName, mimeType, uploadId, audioBlob, onUploaded, getDurationMs, onRecordingError, deleteRecording, autoResetAfterUpload, } = options;
|
|
589
614
|
const sendRecording = useCallback(async () => {
|
|
590
615
|
if (!audioBlob) {
|
|
591
616
|
const error = new Error('Voice recording is not available');
|
|
@@ -598,11 +623,13 @@ const useRecordingSender = (options) => {
|
|
|
598
623
|
throw error;
|
|
599
624
|
}
|
|
600
625
|
try {
|
|
626
|
+
const durationMs = getDurationMs();
|
|
627
|
+
const durationSec = durationMs / 1000;
|
|
601
628
|
const file = new File([audioBlob], fileName, {
|
|
602
629
|
type: audioBlob.type || mimeType,
|
|
603
630
|
});
|
|
604
631
|
const uploaded = await uploader(file, { uploadId });
|
|
605
|
-
await onUploaded(uploaded);
|
|
632
|
+
await onUploaded(uploaded, durationSec);
|
|
606
633
|
if (autoResetAfterUpload) {
|
|
607
634
|
deleteRecording();
|
|
608
635
|
}
|
|
@@ -618,8 +645,9 @@ const useRecordingSender = (options) => {
|
|
|
618
645
|
audioBlob,
|
|
619
646
|
mimeType,
|
|
620
647
|
onUploaded,
|
|
621
|
-
|
|
648
|
+
getDurationMs,
|
|
622
649
|
deleteRecording,
|
|
650
|
+
onRecordingError,
|
|
623
651
|
autoResetAfterUpload,
|
|
624
652
|
]);
|
|
625
653
|
return { sendRecording };
|
|
@@ -635,7 +663,7 @@ function useVoiceRecorder(props) {
|
|
|
635
663
|
const [audioBlob, setAudioBlob] = useState(null);
|
|
636
664
|
const { audioURL, isPlaying, mountBlob, playbackTime, stopPlayback, resetPlayback, togglePlayback: _togglePlayback, playbackDuration, } = useAudioPlayback();
|
|
637
665
|
const { audioLevels, previewLevels, resetAudioLevels, stopVisualization, resetPreviewLevels, resumeVisualization, cleanupVisualization, generatePreviewLevels, initializeVisualization, } = useRecorderVisualization();
|
|
638
|
-
const { recordingTime, pauseSession, resetSession, resumeSession, startNewSession, } = useRecordingTiming();
|
|
666
|
+
const { lastDuration, getElapsedMs, recordingTime, pauseSession, resetSession, resumeSession, startNewSession, } = useRecordingTiming();
|
|
639
667
|
const resetCurrentRecording = useCallback((opts) => {
|
|
640
668
|
var _a;
|
|
641
669
|
setAudioBlob(null);
|
|
@@ -663,10 +691,11 @@ function useVoiceRecorder(props) {
|
|
|
663
691
|
mimeType,
|
|
664
692
|
uploadId,
|
|
665
693
|
uploader,
|
|
666
|
-
autoResetAfterUpload,
|
|
667
694
|
onUploaded,
|
|
668
|
-
onRecordingError,
|
|
669
695
|
deleteRecording,
|
|
696
|
+
onRecordingError,
|
|
697
|
+
autoResetAfterUpload,
|
|
698
|
+
getDurationMs: getElapsedMs,
|
|
670
699
|
});
|
|
671
700
|
const mountRecordingBlob = useCallback((blob) => {
|
|
672
701
|
setAudioBlob(blob);
|
|
@@ -749,6 +778,7 @@ function useVoiceRecorder(props) {
|
|
|
749
778
|
isPlaying,
|
|
750
779
|
isRecording,
|
|
751
780
|
audioLevels,
|
|
781
|
+
lastDuration,
|
|
752
782
|
playbackTime,
|
|
753
783
|
recordingTime,
|
|
754
784
|
previewLevels,
|
|
@@ -1095,9 +1125,6 @@ const useAudioRecorderHandlers = (options) => {
|
|
|
1095
1125
|
toggleRecordingPause,
|
|
1096
1126
|
]);
|
|
1097
1127
|
const handleSend = useCallback(async () => {
|
|
1098
|
-
if (isSending) {
|
|
1099
|
-
return;
|
|
1100
|
-
}
|
|
1101
1128
|
shouldSendAfterStopRef.current = false;
|
|
1102
1129
|
setIsSending(true);
|
|
1103
1130
|
try {
|
|
@@ -1114,7 +1141,6 @@ const useAudioRecorderHandlers = (options) => {
|
|
|
1114
1141
|
setIsSending(false);
|
|
1115
1142
|
}
|
|
1116
1143
|
}, [
|
|
1117
|
-
isSending,
|
|
1118
1144
|
stopPlayback,
|
|
1119
1145
|
onUploadError,
|
|
1120
1146
|
sendRecording,
|
|
@@ -1125,6 +1151,7 @@ const useAudioRecorderHandlers = (options) => {
|
|
|
1125
1151
|
return;
|
|
1126
1152
|
}
|
|
1127
1153
|
if (isRecording) {
|
|
1154
|
+
setIsSending(true);
|
|
1128
1155
|
shouldSendAfterStopRef.current = true;
|
|
1129
1156
|
stopRecording();
|
|
1130
1157
|
return;
|
|
@@ -1262,6 +1289,44 @@ const IdleControl = (props) => {
|
|
|
1262
1289
|
return (jsxs(IdleWrapper, { children: [jsxs(IdleButton, { type: "button", onClick: onClick, "aria-label": startAriaLabel, children: [jsx(IdleButtonOutline, { "aria-hidden": true }), jsx(IdleButtonGlow, { "aria-hidden": true }), jsx(Icon32Microphone, { height: 48, width: 48 })] }), jsx(IdleInstruction, { children: instruction })] }));
|
|
1263
1290
|
};
|
|
1264
1291
|
|
|
1292
|
+
const Bars = styled.div `
|
|
1293
|
+
position: absolute;
|
|
1294
|
+
inset: 0;
|
|
1295
|
+
display: flex;
|
|
1296
|
+
align-items: flex-end;
|
|
1297
|
+
gap: 3px;
|
|
1298
|
+
`;
|
|
1299
|
+
const Bar = styled.div `
|
|
1300
|
+
flex: 1;
|
|
1301
|
+
min-width: 2px;
|
|
1302
|
+
border-radius: 9999px;
|
|
1303
|
+
background: var(--white, #ffffff);
|
|
1304
|
+
opacity: 0.6;
|
|
1305
|
+
transition: height 120ms ease, opacity 120ms ease;
|
|
1306
|
+
`;
|
|
1307
|
+
|
|
1308
|
+
const WaveformBars = (props) => {
|
|
1309
|
+
const { values, progress, styleInterpolator, scale = 40, minHeight = 6, divider = 100, } = props;
|
|
1310
|
+
return (jsx(Bars, { children: values.map((value, index) => {
|
|
1311
|
+
const normalized = clampValue(value);
|
|
1312
|
+
const height = Math.max(minHeight, (normalized / divider) * scale);
|
|
1313
|
+
const barProgress = values.length > 1 ? index / (values.length - 1) : 0;
|
|
1314
|
+
const isPlayed = (progress !== null && progress !== void 0 ? progress : 0) > 0 && barProgress <= (progress !== null && progress !== void 0 ? progress : 0);
|
|
1315
|
+
const interpolated = styleInterpolator === null || styleInterpolator === void 0 ? void 0 : styleInterpolator({
|
|
1316
|
+
normalized,
|
|
1317
|
+
height,
|
|
1318
|
+
index,
|
|
1319
|
+
progress: progress !== null && progress !== void 0 ? progress : 0,
|
|
1320
|
+
barProgress,
|
|
1321
|
+
isPlayed,
|
|
1322
|
+
});
|
|
1323
|
+
return (jsx(Bar, { style: {
|
|
1324
|
+
height: `${height}px`,
|
|
1325
|
+
...interpolated,
|
|
1326
|
+
} }, index));
|
|
1327
|
+
}) }));
|
|
1328
|
+
};
|
|
1329
|
+
|
|
1265
1330
|
/**
|
|
1266
1331
|
* RecordingShell styles
|
|
1267
1332
|
*
|
|
@@ -1356,21 +1421,6 @@ const Waveform = styled.div `
|
|
|
1356
1421
|
align-items: center;
|
|
1357
1422
|
overflow: hidden;
|
|
1358
1423
|
`;
|
|
1359
|
-
const Bars = styled.div `
|
|
1360
|
-
position: absolute;
|
|
1361
|
-
inset: 0;
|
|
1362
|
-
display: flex;
|
|
1363
|
-
align-items: flex-end;
|
|
1364
|
-
gap: 3px;
|
|
1365
|
-
`;
|
|
1366
|
-
const Bar = styled.div `
|
|
1367
|
-
flex: 1;
|
|
1368
|
-
min-width: 2px;
|
|
1369
|
-
border-radius: 9999px;
|
|
1370
|
-
background: var(--white, #ffffff);
|
|
1371
|
-
opacity: 0.6;
|
|
1372
|
-
transition: height 120ms ease, opacity 120ms ease;
|
|
1373
|
-
`;
|
|
1374
1424
|
const Timer$1 = styled.span `
|
|
1375
1425
|
text-align: right;
|
|
1376
1426
|
font-size: 13px;
|
|
@@ -1432,31 +1482,33 @@ const Spinner = styled.span `
|
|
|
1432
1482
|
}
|
|
1433
1483
|
`;
|
|
1434
1484
|
|
|
1435
|
-
const WaveformBars = (props) => {
|
|
1436
|
-
const { values, styleInterpolator, scale = 40, minHeight = 6, divider = 100, } = props;
|
|
1437
|
-
return (jsx(Bars, { children: values.map((value, index) => {
|
|
1438
|
-
const normalized = clampValue(value);
|
|
1439
|
-
const height = Math.max(minHeight, (normalized / divider) * scale);
|
|
1440
|
-
const interpolated = styleInterpolator === null || styleInterpolator === void 0 ? void 0 : styleInterpolator({ normalized, height, index });
|
|
1441
|
-
return (jsx(Bar, { style: {
|
|
1442
|
-
height: `${height}px`,
|
|
1443
|
-
...interpolated,
|
|
1444
|
-
} }, index));
|
|
1445
|
-
}) }));
|
|
1446
|
-
};
|
|
1447
|
-
|
|
1448
1485
|
const RecordingShell = (props) => {
|
|
1449
1486
|
const { isPaused, isPlaying, isSending, isRecording, audioLevels, hasRecording, playbackTime, previewLevels, recordingTime, stopAriaLabel, playAriaLabel, sendAriaLabel, startAriaLabel, cancelAriaLabel, playbackDuration, pausePlaybackAriaLabel, pauseRecordingAriaLabel, resumeRecordingAriaLabel, onSend, onCancel, formatTime, onRecordToggle, onTogglePlayback, } = props;
|
|
1487
|
+
const { lastDuration } = props;
|
|
1488
|
+
const isPreview = !isRecording || isPaused;
|
|
1450
1489
|
const waveformValues = isRecording ? audioLevels : (hasRecording ? previewLevels : audioLevels);
|
|
1490
|
+
const effectiveDuration = recordingTime
|
|
1491
|
+
|| playbackDuration
|
|
1492
|
+
|| lastDuration
|
|
1493
|
+
|| 1;
|
|
1494
|
+
const progress = (isPreview && isPlaying)
|
|
1495
|
+
? Math.min(1, playbackTime / effectiveDuration)
|
|
1496
|
+
: 0;
|
|
1451
1497
|
const displayTime = useMemo(() => {
|
|
1452
|
-
if (
|
|
1498
|
+
if (isPlaying) {
|
|
1499
|
+
return formatTime(playbackTime);
|
|
1500
|
+
}
|
|
1501
|
+
if (isRecording && !isPaused) {
|
|
1502
|
+
return formatTime(recordingTime);
|
|
1503
|
+
}
|
|
1504
|
+
if (isRecording && isPaused) {
|
|
1453
1505
|
return formatTime(recordingTime);
|
|
1454
1506
|
}
|
|
1507
|
+
if (lastDuration > 0) {
|
|
1508
|
+
return formatTime(lastDuration);
|
|
1509
|
+
}
|
|
1455
1510
|
if (hasRecording) {
|
|
1456
|
-
if (
|
|
1457
|
-
return formatTime(playbackTime);
|
|
1458
|
-
}
|
|
1459
|
-
if (playbackDuration > 0) {
|
|
1511
|
+
if (playbackDuration > 0.5) {
|
|
1460
1512
|
return formatTime(playbackDuration);
|
|
1461
1513
|
}
|
|
1462
1514
|
if (recordingTime > 0) {
|
|
@@ -1464,7 +1516,17 @@ const RecordingShell = (props) => {
|
|
|
1464
1516
|
}
|
|
1465
1517
|
}
|
|
1466
1518
|
return formatTime(0);
|
|
1467
|
-
}, [
|
|
1519
|
+
}, [
|
|
1520
|
+
isPaused,
|
|
1521
|
+
isPlaying,
|
|
1522
|
+
formatTime,
|
|
1523
|
+
isRecording,
|
|
1524
|
+
lastDuration,
|
|
1525
|
+
hasRecording,
|
|
1526
|
+
playbackTime,
|
|
1527
|
+
recordingTime,
|
|
1528
|
+
playbackDuration,
|
|
1529
|
+
]);
|
|
1468
1530
|
const recordButtonDisabled = isSending;
|
|
1469
1531
|
const recordButtonIcon = !isRecording || isPaused
|
|
1470
1532
|
? jsx(Icon16Microphone, { width: 24, height: 24 })
|
|
@@ -1482,10 +1544,13 @@ const RecordingShell = (props) => {
|
|
|
1482
1544
|
: jsx(Icon16Play, { width: 24, height: 24 });
|
|
1483
1545
|
const playbackAria = isPlaying ? pausePlaybackAriaLabel : playAriaLabel;
|
|
1484
1546
|
const sendDisabled = isSending || (!hasRecording && !isRecording);
|
|
1485
|
-
return (jsxs(Wrapper$1, { children: [jsx(CancelButton$1, { type: "button", onClick: onCancel, "aria-label": cancelAriaLabel, children: jsx(Icon28DeleteOutlineAndroid, { fill: "var(--exode_red)", width: 24, height: 24, style: { minWidth: 24 } }) }), jsxs(Track, { children: [jsx(CircleButton, { type: "button", "$variant": recordButtonVariant, onClick: onRecordToggle, "aria-label": recordButtonAria, disabled: recordButtonDisabled, children: recordButtonIcon }), !canShowPlayback ? null : (jsx(CircleButton, { type: "button", "$variant": "play", onClick: onTogglePlayback, "aria-label": playbackAria, disabled: playbackDisabled, children: playbackIcon })), jsx(Waveform, { "$expanded": canShowPlayback, children: jsx(WaveformBars, {
|
|
1547
|
+
return (jsxs(Wrapper$1, { children: [jsx(CancelButton$1, { type: "button", onClick: onCancel, "aria-label": cancelAriaLabel, children: jsx(Icon28DeleteOutlineAndroid, { fill: "var(--exode_red)", width: 24, height: 24, style: { minWidth: 24 } }) }), jsxs(Track, { children: [jsx(CircleButton, { type: "button", "$variant": recordButtonVariant, onClick: onRecordToggle, "aria-label": recordButtonAria, disabled: recordButtonDisabled, children: recordButtonIcon }), !canShowPlayback ? null : (jsx(CircleButton, { type: "button", "$variant": "play", onClick: onTogglePlayback, "aria-label": playbackAria, disabled: playbackDisabled, children: playbackIcon })), jsx(Waveform, { "$expanded": canShowPlayback, children: jsx(WaveformBars, { scale: 42, minHeight: 6, divider: 100, progress: progress, values: waveformValues, styleInterpolator: ({ normalized, isPlayed, progress: p }) => ({
|
|
1486
1548
|
height: `${12 + normalized / 2}px`,
|
|
1487
1549
|
maxHeight: '34px',
|
|
1488
|
-
opacity:
|
|
1550
|
+
opacity: p > 0
|
|
1551
|
+
? (isPlayed ? 0.80 : 0.22)
|
|
1552
|
+
: 0.38 + Math.min(0.5, normalized / 120),
|
|
1553
|
+
transition: 'opacity 80ms ease',
|
|
1489
1554
|
}) }) }), jsx(Timer$1, { children: displayTime })] }), jsx(SendButton$1, { type: "button", onClick: onSend, disabled: sendDisabled, "aria-label": sendAriaLabel, children: isSending ? (jsx(SpinnerSlot, { children: jsx(Spinner, {}) })) : (jsx(Icon28SendOutline, { width: 24, height: 24 })) })] }));
|
|
1490
1555
|
};
|
|
1491
1556
|
|
|
@@ -1568,9 +1633,9 @@ const AudioRecorder = (props) => {
|
|
|
1568
1633
|
messages,
|
|
1569
1634
|
onUploadError,
|
|
1570
1635
|
});
|
|
1571
|
-
const { isPaused, isPlaying, formatTime, audioLevels, isRecording, playbackTime, hasRecording, previewLevels, recordingTime, playbackDuration, } = recorder;
|
|
1572
|
-
const showRecorderBar = isRecording || hasRecording;
|
|
1573
|
-
return (jsx(Container, { className: className, children: showRecorderBar ? (jsx(RecordingShell, { isPaused: isPaused, isSending: isSending, isPlaying: isPlaying, formatTime: formatTime, onCancel: handleCancel, isRecording: isRecording, audioLevels: audioLevels, onSend: handleSendRequest, playbackTime: playbackTime, hasRecording: hasRecording, previewLevels: previewLevels, recordingTime: recordingTime, playbackDuration: playbackDuration, onRecordToggle: handleRecordToggle, sendAriaLabel: messages.buttons.send, onTogglePlayback: handlePlaybackToggle, cancelAriaLabel: messages.buttons.cancel, playAriaLabel: messages.aria.playRecording, stopAriaLabel: messages.aria.stopRecording, startAriaLabel: messages.aria.startRecording, pauseRecordingAriaLabel: messages.aria.pauseRecording, resumeRecordingAriaLabel: messages.aria.resumeRecording, pausePlaybackAriaLabel: messages.aria.pausePlayback })) : (jsx(IdleControl, { onClick: handleRecordToggle, startAriaLabel: messages.aria.startRecording, instruction: messages.instruction })) }));
|
|
1636
|
+
const { isPaused, isPlaying, formatTime, audioLevels, isRecording, lastDuration, playbackTime, hasRecording, previewLevels, recordingTime, playbackDuration, } = recorder;
|
|
1637
|
+
const showRecorderBar = isRecording || hasRecording || isSending;
|
|
1638
|
+
return (jsx(Container, { className: className, children: showRecorderBar ? (jsx(RecordingShell, { isPaused: isPaused, isSending: isSending, isPlaying: isPlaying, formatTime: formatTime, onCancel: handleCancel, isRecording: isRecording, audioLevels: audioLevels, onSend: handleSendRequest, playbackTime: playbackTime, lastDuration: lastDuration, hasRecording: hasRecording, previewLevels: previewLevels, recordingTime: recordingTime, playbackDuration: playbackDuration, onRecordToggle: handleRecordToggle, sendAriaLabel: messages.buttons.send, onTogglePlayback: handlePlaybackToggle, cancelAriaLabel: messages.buttons.cancel, playAriaLabel: messages.aria.playRecording, stopAriaLabel: messages.aria.stopRecording, startAriaLabel: messages.aria.startRecording, pauseRecordingAriaLabel: messages.aria.pauseRecording, resumeRecordingAriaLabel: messages.aria.resumeRecording, pausePlaybackAriaLabel: messages.aria.pausePlayback })) : (jsx(IdleControl, { onClick: handleRecordToggle, startAriaLabel: messages.aria.startRecording, instruction: messages.instruction })) }));
|
|
1574
1639
|
};
|
|
1575
1640
|
|
|
1576
1641
|
/**
|
|
@@ -2209,7 +2274,7 @@ const VoiceMessagePlayer = React.forwardRef((props, ref) => {
|
|
|
2209
2274
|
observer.disconnect();
|
|
2210
2275
|
};
|
|
2211
2276
|
}, []);
|
|
2212
|
-
const displayTime = isPlaying
|
|
2277
|
+
const displayTime = (isPlaying || currentTime > 0)
|
|
2213
2278
|
? formatTime(currentTime)
|
|
2214
2279
|
: formatTime(resolvedDuration);
|
|
2215
2280
|
const handleTrackClick = useCallback((e) => {
|