@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.
@@ -12,7 +12,7 @@ interface Props extends Partial<RecorderOptionOverrides> {
12
12
  uploadId?: string;
13
13
  className?: string;
14
14
  onUploadError?: (error: unknown) => void;
15
- onUploaded?: (file: Partial<StorageFileEntity>) => void | Promise<void>;
15
+ onUploaded?: (file: Partial<StorageFileEntity>, duration: number) => void | Promise<void>;
16
16
  }
17
17
  declare const AudioRecorder: (props: Props) => any;
18
18
  export { AudioRecorder };
@@ -1 +1 @@
1
- {"version":3,"file":"AudioRecorder.d.ts","sourceRoot":"","sources":["../../src/components/AudioRecorder.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH,OAAO,EAAiB,KAAK,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAErF,OAAO,EACH,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,uBAAuB,EAC/B,MAAM,UAAU,CAAC;AAGlB,KAAK,uBAAuB,GAAG,IAAI,CAC/B,uBAAuB,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,EACnD,UAAU,GAAG,YAAY,GAAG,UAAU,CACzC,CAAC;AAEF,UAAU,KAAM,SAAQ,OAAO,CAAC,uBAAuB,CAAC;IACpD,QAAQ,EAAE,cAAc,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,iBAAiB,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3E;AAGD,QAAA,MAAM,aAAa,GAAI,OAAO,KAAK,QAsHlC,CAAC;AAGF,OAAO,EAAE,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"AudioRecorder.d.ts","sourceRoot":"","sources":["../../src/components/AudioRecorder.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH,OAAO,EAAiB,KAAK,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAErF,OAAO,EACH,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,uBAAuB,EAC/B,MAAM,UAAU,CAAC;AAGlB,KAAK,uBAAuB,GAAG,IAAI,CAC/B,uBAAuB,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,EACnD,UAAU,GAAG,YAAY,GAAG,UAAU,CACzC,CAAC;AAEF,UAAU,KAAM,SAAQ,OAAO,CAAC,uBAAuB,CAAC;IACpD,QAAQ,EAAE,cAAc,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC;IACrD,QAAQ,CAAC,EAAE,qBAAqB,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7F;AAGD,QAAA,MAAM,aAAa,GAAI,OAAO,KAAK,QAwHlC,CAAC;AAGF,OAAO,EAAE,aAAa,EAAE,CAAC"}
@@ -8,6 +8,7 @@ interface Props {
8
8
  isPaused: boolean;
9
9
  hasRecording: boolean;
10
10
  isPlaying: boolean;
11
+ lastDuration: number;
11
12
  recordingTime: number;
12
13
  playbackTime: number;
13
14
  playbackDuration: number;
@@ -1 +1 @@
1
- {"version":3,"file":"RecordingShell.d.ts","sourceRoot":"","sources":["../../../src/components/RecordingShell/RecordingShell.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AA2BH,UAAU,KAAK;IACX,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,uBAAuB,EAAE,MAAM,CAAC;IAChC,wBAAwB,EAAE,MAAM,CAAC;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;CAC3C;AAGD,QAAA,MAAM,cAAc,GAAI,OAAO,KAAK,QA6HnC,CAAC;AAGF,OAAO,EAAE,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"RecordingShell.d.ts","sourceRoot":"","sources":["../../../src/components/RecordingShell/RecordingShell.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AA2BH,UAAU,KAAK;IACX,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,uBAAuB,EAAE,MAAM,CAAC;IAChC,wBAAwB,EAAE,MAAM,CAAC;IACjC,aAAa,EAAE,MAAM,CAAC;IACtB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;CAC3C;AAGD,QAAA,MAAM,cAAc,GAAI,OAAO,KAAK,QA+JnC,CAAC;AAGF,OAAO,EAAE,cAAc,EAAE,CAAC"}
@@ -8,8 +8,6 @@ export declare const CancelButton: any;
8
8
  export declare const Track: any;
9
9
  export declare const CircleButton: any;
10
10
  export declare const Waveform: any;
11
- export declare const Bars: any;
12
- export declare const Bar: any;
13
11
  export declare const Timer: any;
14
12
  export declare const SendButton: any;
15
13
  export declare const SpinnerSlot: any;
@@ -1 +1 @@
1
- {"version":3,"file":"RecordingShell.styled.d.ts","sourceRoot":"","sources":["../../../src/components/RecordingShell/RecordingShell.styled.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,eAAO,MAAM,OAAO,KAOnB,CAAC;AAEF,eAAO,MAAM,YAAY,KAqBxB,CAAC;AAEF,eAAO,MAAM,KAAK,KAQjB,CAAC;AAEF,eAAO,MAAM,YAAY,KA2CxB,CAAC;AAEF,eAAO,MAAM,QAAQ,KAOpB,CAAC;AAEF,eAAO,MAAM,IAAI,KAMhB,CAAC;AAEF,eAAO,MAAM,GAAG,KAOf,CAAC;AAEF,eAAO,MAAM,KAAK,KAKjB,CAAC;AAEF,eAAO,MAAM,UAAU,KAyBtB,CAAC;AAEF,eAAO,MAAM,WAAW,KAMvB,CAAC;AAEF,eAAO,MAAM,OAAO,KAoBnB,CAAC"}
1
+ {"version":3,"file":"RecordingShell.styled.d.ts","sourceRoot":"","sources":["../../../src/components/RecordingShell/RecordingShell.styled.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,eAAO,MAAM,OAAO,KAOnB,CAAC;AAEF,eAAO,MAAM,YAAY,KAqBxB,CAAC;AAEF,eAAO,MAAM,KAAK,KAQjB,CAAC;AAEF,eAAO,MAAM,YAAY,KA2CxB,CAAC;AAEF,eAAO,MAAM,QAAQ,KAOpB,CAAC;AAEF,eAAO,MAAM,KAAK,KAKjB,CAAC;AAEF,eAAO,MAAM,UAAU,KAyBtB,CAAC;AAEF,eAAO,MAAM,WAAW,KAMvB,CAAC;AAEF,eAAO,MAAM,OAAO,KAoBnB,CAAC"}
@@ -8,11 +8,15 @@ interface Props {
8
8
  scale?: number;
9
9
  divider?: number;
10
10
  values: number[];
11
+ progress?: number;
11
12
  minHeight?: number;
12
13
  styleInterpolator?: (context: {
13
14
  normalized: number;
14
15
  height: number;
15
16
  index: number;
17
+ progress: number;
18
+ barProgress: number;
19
+ isPlayed: boolean;
16
20
  }) => React.CSSProperties;
17
21
  }
18
22
  declare const WaveformBars: (props: Props) => any;
@@ -1 +1 @@
1
- {"version":3,"file":"WaveformBars.d.ts","sourceRoot":"","sources":["../../../src/components/WaveformBars/WaveformBars.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,UAAU,KAAK;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE;QAC1B,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACjB,KAAK,KAAK,CAAC,aAAa,CAAC;CAC7B;AAGD,QAAA,MAAM,YAAY,GAAI,OAAO,KAAK,QA0BjC,CAAC;AAGF,OAAO,EAAE,YAAY,EAAE,CAAC"}
1
+ {"version":3,"file":"WaveformBars.d.ts","sourceRoot":"","sources":["../../../src/components/WaveformBars/WaveformBars.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAO1B,UAAU,KAAK;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE;QAC1B,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,OAAO,CAAC;KACrB,KAAK,KAAK,CAAC,aAAa,CAAC;CAC7B;AAGD,QAAA,MAAM,YAAY,GAAI,OAAO,KAAK,QAoCjC,CAAC;AAGF,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare const Bars: any;
2
+ export declare const Bar: any;
3
+ //# sourceMappingURL=WaveformBars.styled.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WaveformBars.styled.d.ts","sourceRoot":"","sources":["../../../src/components/WaveformBars/WaveformBars.styled.tsx"],"names":[],"mappings":"AAGA,eAAO,MAAM,IAAI,KAMhB,CAAC;AAEF,eAAO,MAAM,GAAG,KAOf,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useAudioRecorderHandlers.d.ts","sourceRoot":"","sources":["../../src/hooks/useAudioRecorderHandlers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAG7E,UAAU,+BAA+B;IACrC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC;IAC9C,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,EAAE,sBAAsB,CAAC;IACjC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC5C;AAGD,QAAA,MAAM,wBAAwB,GAAI,SAAS,+BAA+B;;;;;;CA2KzE,CAAC;AAGF,OAAO,EAAE,wBAAwB,EAAE,CAAC"}
1
+ {"version":3,"file":"useAudioRecorderHandlers.d.ts","sourceRoot":"","sources":["../../src/hooks/useAudioRecorderHandlers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AAG7E,UAAU,+BAA+B;IACrC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,IAAI,CAAC;IAC9C,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,EAAE,sBAAsB,CAAC;IACjC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC5C;AAGD,QAAA,MAAM,wBAAwB,GAAI,SAAS,+BAA+B;;;;;;CAuKzE,CAAC;AAGF,OAAO,EAAE,wBAAwB,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useMediaRecorder.d.ts","sourceRoot":"","sources":["../../src/hooks/useMediaRecorder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAGvD,UAAU,sBAAsB;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,aAAa,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,QAAA,MAAM,gBAAgB,GAAI,WAAW,sBAAsB,KAAG,sBAkI7D,CAAC;AAGF,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"useMediaRecorder.d.ts","sourceRoot":"","sources":["../../src/hooks/useMediaRecorder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAGvD,UAAU,sBAAsB;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,cAAc,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,aAAa,EAAE,MAAM,IAAI,CAAC;CAC7B;AAED,QAAA,MAAM,gBAAgB,GAAI,WAAW,sBAAsB,KAAG,sBAsI7D,CAAC;AAGF,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -9,8 +9,9 @@ interface UseRecordingSenderOptions<TFile> {
9
9
  mimeType: string;
10
10
  audioBlob: Blob | null;
11
11
  uploadId: string;
12
+ getDurationMs: () => number;
12
13
  uploader?: UploadStrategy<TFile>;
13
- onUploaded: (file: TFile) => void | Promise<void>;
14
+ onUploaded: (file: TFile, duration: number) => void | Promise<void>;
14
15
  deleteRecording: () => void;
15
16
  autoResetAfterUpload: boolean;
16
17
  onRecordingError?: (error: unknown) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useRecordingSender.d.ts","sourceRoot":"","sources":["../../src/hooks/useRecordingSender.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG/C,UAAU,yBAAyB,CAAC,KAAK;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;IACjC,UAAU,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC/C;AAGD,QAAA,MAAM,kBAAkB,GAAI,KAAK,GAAG,OAAO,EAAE,SAAS,yBAAyB,CAAC,KAAK,CAAC;;CA0DrF,CAAC;AAGF,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"useRecordingSender.d.ts","sourceRoot":"","sources":["../../src/hooks/useRecordingSender.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG/C,UAAU,yBAAyB,CAAC,KAAK;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;IACjC,UAAU,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CAC/C;AAGD,QAAA,MAAM,kBAAkB,GAAI,KAAK,GAAG,OAAO,EAAE,SAAS,yBAAyB,CAAC,KAAK,CAAC;;CA+DrF,CAAC;AAGF,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
@@ -5,6 +5,8 @@
5
5
  */
6
6
  interface UseRecordingTimingResult {
7
7
  recordingTime: number;
8
+ lastDuration: number;
9
+ getElapsedMs: () => number;
8
10
  pauseSession: () => void;
9
11
  resetSession: () => void;
10
12
  resumeSession: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useRecordingTiming.d.ts","sourceRoot":"","sources":["../../src/hooks/useRecordingTiming.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,UAAU,wBAAwB;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,eAAe,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,QAAA,MAAM,kBAAkB,QAAO,wBAgF9B,CAAC;AAGF,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"useRecordingTiming.d.ts","sourceRoot":"","sources":["../../src/hooks/useRecordingTiming.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,UAAU,wBAAwB;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,eAAe,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,QAAA,MAAM,kBAAkB,QAAO,wBAwG9B,CAAC;AAGF,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useVoiceRecorder.d.ts","sourceRoot":"","sources":["../../src/hooks/useVoiceRecorder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH,OAAO,KAAK,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAGhF,iBAAS,gBAAgB,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,EAAE,uBAAuB,CAAC,KAAK,CAAC,GAAG,sBAAsB,CAuMxG;AAGD,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"useVoiceRecorder.d.ts","sourceRoot":"","sources":["../../src/hooks/useVoiceRecorder.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAWH,OAAO,KAAK,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAGhF,iBAAS,gBAAgB,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,EAAE,uBAAuB,CAAC,KAAK,CAAC,GAAG,sBAAsB,CA2MxG;AAGD,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -6,7 +6,7 @@
6
6
  import type { UploadStrategy } from '../types';
7
7
  interface UseVoiceRecorderInputOptions {
8
8
  uploader?: UploadStrategy<unknown>;
9
- onUploaded?: (file: unknown) => void | Promise<void>;
9
+ onUploaded?: (file: unknown, duration: number) => void | Promise<void>;
10
10
  onSend?: (file: File, duration: number) => void | Promise<void>;
11
11
  onError?: (error: unknown) => void;
12
12
  onCancel?: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useVoiceRecorderInput.d.ts","sourceRoot":"","sources":["../../src/hooks/useVoiceRecorderInput.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG/C,UAAU,4BAA4B;IAClC,QAAQ,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;IACnC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrD,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAGD,QAAA,MAAM,qBAAqB,GAAI,SAAS,4BAA4B;;;;;;;;;;CA6MnE,CAAC;AAGF,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
1
+ {"version":3,"file":"useVoiceRecorderInput.d.ts","sourceRoot":"","sources":["../../src/hooks/useVoiceRecorderInput.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG/C,UAAU,4BAA4B;IAClC,QAAQ,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;IACnC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAC9C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAGD,QAAA,MAAM,qBAAqB,GAAI,SAAS,4BAA4B;;;;;;;;;;CA6MnE,CAAC;AAGF,OAAO,EAAE,qBAAqB,EAAE,CAAC"}
package/dist/index.cjs CHANGED
@@ -180,7 +180,11 @@ const decodeAudioLevels = async (blob, barCount = AUDIO_LEVEL_BARS) => {
180
180
  * @author: exode <hello@exode.ru>
181
181
  */
182
182
  const fetchAudioBlob = async (url, signal) => {
183
- const response = await fetch(url, { signal });
183
+ const response = await fetch(url, {
184
+ signal,
185
+ mode: 'cors',
186
+ credentials: 'omit',
187
+ });
184
188
  return response.blob();
185
189
  };
186
190
 
@@ -272,6 +276,9 @@ const useMediaRecorder = (callbacks) => {
272
276
  if (!mediaRecorderRef.current || !isRecording) {
273
277
  return;
274
278
  }
279
+ if (mediaRecorderRef.current.state === 'paused') {
280
+ mediaRecorderRef.current.resume();
281
+ }
275
282
  mediaRecorderRef.current.stop();
276
283
  }, [isRecording]);
277
284
  const cancelRecording = React.useCallback(() => {
@@ -430,6 +437,7 @@ const useAudioPlayback = () => {
430
437
  * @author: exode <hello@exode.ru>
431
438
  */
432
439
  const useRecordingTiming = () => {
440
+ const [lastDuration, setLastDuration] = React.useState(0);
433
441
  const [recordingTime, setRecordingTime] = React.useState(0);
434
442
  const timerRef = React.useRef(null);
435
443
  const recordingStartRef = React.useRef(null);
@@ -457,6 +465,7 @@ const useRecordingTiming = () => {
457
465
  const startNewSession = React.useCallback(() => {
458
466
  recordingAccumulatedRef.current = 0;
459
467
  setRecordingTime(0);
468
+ setLastDuration(0);
460
469
  recordingStartRef.current = performance.now();
461
470
  startTicker();
462
471
  }, [startTicker]);
@@ -474,7 +483,21 @@ const useRecordingTiming = () => {
474
483
  setRecordingTime(roundTo(recordingAccumulatedRef.current));
475
484
  stopTicker();
476
485
  }, [stopTicker]);
486
+ const getElapsedMs = React.useCallback(() => {
487
+ const accumulated = recordingAccumulatedRef.current;
488
+ const elapsed = recordingStartRef.current !== null
489
+ ? (performance.now() - recordingStartRef.current) / 1000 + accumulated
490
+ : accumulated;
491
+ return Math.round(elapsed * 1000);
492
+ }, []);
477
493
  const resetSession = React.useCallback(() => {
494
+ const accumulated = recordingAccumulatedRef.current;
495
+ const elapsed = recordingStartRef.current !== null
496
+ ? (performance.now() - recordingStartRef.current) / 1000 + accumulated
497
+ : accumulated;
498
+ if (elapsed > 0) {
499
+ setLastDuration(roundTo(elapsed));
500
+ }
478
501
  stopTicker();
479
502
  recordingStartRef.current = null;
480
503
  recordingAccumulatedRef.current = 0;
@@ -486,6 +509,8 @@ const useRecordingTiming = () => {
486
509
  };
487
510
  }, [stopTicker]);
488
511
  return {
512
+ lastDuration,
513
+ getElapsedMs,
489
514
  pauseSession,
490
515
  resetSession,
491
516
  recordingTime,
@@ -587,7 +612,7 @@ const useRecorderVisualization = () => {
587
612
  * @author: exode <hello@exode.ru>
588
613
  */
589
614
  const useRecordingSender = (options) => {
590
- const { uploader, fileName, mimeType, uploadId, audioBlob, onUploaded, onRecordingError, deleteRecording, autoResetAfterUpload, } = options;
615
+ const { uploader, fileName, mimeType, uploadId, audioBlob, onUploaded, getDurationMs, onRecordingError, deleteRecording, autoResetAfterUpload, } = options;
591
616
  const sendRecording = React.useCallback(async () => {
592
617
  if (!audioBlob) {
593
618
  const error = new Error('Voice recording is not available');
@@ -600,11 +625,13 @@ const useRecordingSender = (options) => {
600
625
  throw error;
601
626
  }
602
627
  try {
628
+ const durationMs = getDurationMs();
629
+ const durationSec = durationMs / 1000;
603
630
  const file = new File([audioBlob], fileName, {
604
631
  type: audioBlob.type || mimeType,
605
632
  });
606
633
  const uploaded = await uploader(file, { uploadId });
607
- await onUploaded(uploaded);
634
+ await onUploaded(uploaded, durationSec);
608
635
  if (autoResetAfterUpload) {
609
636
  deleteRecording();
610
637
  }
@@ -620,8 +647,9 @@ const useRecordingSender = (options) => {
620
647
  audioBlob,
621
648
  mimeType,
622
649
  onUploaded,
623
- onRecordingError,
650
+ getDurationMs,
624
651
  deleteRecording,
652
+ onRecordingError,
625
653
  autoResetAfterUpload,
626
654
  ]);
627
655
  return { sendRecording };
@@ -637,7 +665,7 @@ function useVoiceRecorder(props) {
637
665
  const [audioBlob, setAudioBlob] = React.useState(null);
638
666
  const { audioURL, isPlaying, mountBlob, playbackTime, stopPlayback, resetPlayback, togglePlayback: _togglePlayback, playbackDuration, } = useAudioPlayback();
639
667
  const { audioLevels, previewLevels, resetAudioLevels, stopVisualization, resetPreviewLevels, resumeVisualization, cleanupVisualization, generatePreviewLevels, initializeVisualization, } = useRecorderVisualization();
640
- const { recordingTime, pauseSession, resetSession, resumeSession, startNewSession, } = useRecordingTiming();
668
+ const { lastDuration, getElapsedMs, recordingTime, pauseSession, resetSession, resumeSession, startNewSession, } = useRecordingTiming();
641
669
  const resetCurrentRecording = React.useCallback((opts) => {
642
670
  var _a;
643
671
  setAudioBlob(null);
@@ -665,10 +693,11 @@ function useVoiceRecorder(props) {
665
693
  mimeType,
666
694
  uploadId,
667
695
  uploader,
668
- autoResetAfterUpload,
669
696
  onUploaded,
670
- onRecordingError,
671
697
  deleteRecording,
698
+ onRecordingError,
699
+ autoResetAfterUpload,
700
+ getDurationMs: getElapsedMs,
672
701
  });
673
702
  const mountRecordingBlob = React.useCallback((blob) => {
674
703
  setAudioBlob(blob);
@@ -751,6 +780,7 @@ function useVoiceRecorder(props) {
751
780
  isPlaying,
752
781
  isRecording,
753
782
  audioLevels,
783
+ lastDuration,
754
784
  playbackTime,
755
785
  recordingTime,
756
786
  previewLevels,
@@ -1097,9 +1127,6 @@ const useAudioRecorderHandlers = (options) => {
1097
1127
  toggleRecordingPause,
1098
1128
  ]);
1099
1129
  const handleSend = React.useCallback(async () => {
1100
- if (isSending) {
1101
- return;
1102
- }
1103
1130
  shouldSendAfterStopRef.current = false;
1104
1131
  setIsSending(true);
1105
1132
  try {
@@ -1116,7 +1143,6 @@ const useAudioRecorderHandlers = (options) => {
1116
1143
  setIsSending(false);
1117
1144
  }
1118
1145
  }, [
1119
- isSending,
1120
1146
  stopPlayback,
1121
1147
  onUploadError,
1122
1148
  sendRecording,
@@ -1127,6 +1153,7 @@ const useAudioRecorderHandlers = (options) => {
1127
1153
  return;
1128
1154
  }
1129
1155
  if (isRecording) {
1156
+ setIsSending(true);
1130
1157
  shouldSendAfterStopRef.current = true;
1131
1158
  stopRecording();
1132
1159
  return;
@@ -1264,6 +1291,44 @@ const IdleControl = (props) => {
1264
1291
  return (jsxRuntime.jsxs(IdleWrapper, { children: [jsxRuntime.jsxs(IdleButton, { type: "button", onClick: onClick, "aria-label": startAriaLabel, children: [jsxRuntime.jsx(IdleButtonOutline, { "aria-hidden": true }), jsxRuntime.jsx(IdleButtonGlow, { "aria-hidden": true }), jsxRuntime.jsx(icons.Icon32Microphone, { height: 48, width: 48 })] }), jsxRuntime.jsx(IdleInstruction, { children: instruction })] }));
1265
1292
  };
1266
1293
 
1294
+ const Bars = styled.div `
1295
+ position: absolute;
1296
+ inset: 0;
1297
+ display: flex;
1298
+ align-items: flex-end;
1299
+ gap: 3px;
1300
+ `;
1301
+ const Bar = styled.div `
1302
+ flex: 1;
1303
+ min-width: 2px;
1304
+ border-radius: 9999px;
1305
+ background: var(--white, #ffffff);
1306
+ opacity: 0.6;
1307
+ transition: height 120ms ease, opacity 120ms ease;
1308
+ `;
1309
+
1310
+ const WaveformBars = (props) => {
1311
+ const { values, progress, styleInterpolator, scale = 40, minHeight = 6, divider = 100, } = props;
1312
+ return (jsxRuntime.jsx(Bars, { children: values.map((value, index) => {
1313
+ const normalized = clampValue(value);
1314
+ const height = Math.max(minHeight, (normalized / divider) * scale);
1315
+ const barProgress = values.length > 1 ? index / (values.length - 1) : 0;
1316
+ const isPlayed = (progress !== null && progress !== void 0 ? progress : 0) > 0 && barProgress <= (progress !== null && progress !== void 0 ? progress : 0);
1317
+ const interpolated = styleInterpolator === null || styleInterpolator === void 0 ? void 0 : styleInterpolator({
1318
+ normalized,
1319
+ height,
1320
+ index,
1321
+ progress: progress !== null && progress !== void 0 ? progress : 0,
1322
+ barProgress,
1323
+ isPlayed,
1324
+ });
1325
+ return (jsxRuntime.jsx(Bar, { style: {
1326
+ height: `${height}px`,
1327
+ ...interpolated,
1328
+ } }, index));
1329
+ }) }));
1330
+ };
1331
+
1267
1332
  /**
1268
1333
  * RecordingShell styles
1269
1334
  *
@@ -1358,21 +1423,6 @@ const Waveform = styled.div `
1358
1423
  align-items: center;
1359
1424
  overflow: hidden;
1360
1425
  `;
1361
- const Bars = styled.div `
1362
- position: absolute;
1363
- inset: 0;
1364
- display: flex;
1365
- align-items: flex-end;
1366
- gap: 3px;
1367
- `;
1368
- const Bar = styled.div `
1369
- flex: 1;
1370
- min-width: 2px;
1371
- border-radius: 9999px;
1372
- background: var(--white, #ffffff);
1373
- opacity: 0.6;
1374
- transition: height 120ms ease, opacity 120ms ease;
1375
- `;
1376
1426
  const Timer$1 = styled.span `
1377
1427
  text-align: right;
1378
1428
  font-size: 13px;
@@ -1434,31 +1484,33 @@ const Spinner = styled.span `
1434
1484
  }
1435
1485
  `;
1436
1486
 
1437
- const WaveformBars = (props) => {
1438
- const { values, styleInterpolator, scale = 40, minHeight = 6, divider = 100, } = props;
1439
- return (jsxRuntime.jsx(Bars, { children: values.map((value, index) => {
1440
- const normalized = clampValue(value);
1441
- const height = Math.max(minHeight, (normalized / divider) * scale);
1442
- const interpolated = styleInterpolator === null || styleInterpolator === void 0 ? void 0 : styleInterpolator({ normalized, height, index });
1443
- return (jsxRuntime.jsx(Bar, { style: {
1444
- height: `${height}px`,
1445
- ...interpolated,
1446
- } }, index));
1447
- }) }));
1448
- };
1449
-
1450
1487
  const RecordingShell = (props) => {
1451
1488
  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;
1489
+ const { lastDuration } = props;
1490
+ const isPreview = !isRecording || isPaused;
1452
1491
  const waveformValues = isRecording ? audioLevels : (hasRecording ? previewLevels : audioLevels);
1492
+ const effectiveDuration = recordingTime
1493
+ || playbackDuration
1494
+ || lastDuration
1495
+ || 1;
1496
+ const progress = (isPreview && isPlaying)
1497
+ ? Math.min(1, playbackTime / effectiveDuration)
1498
+ : 0;
1453
1499
  const displayTime = React.useMemo(() => {
1454
- if (isRecording) {
1500
+ if (isPlaying) {
1501
+ return formatTime(playbackTime);
1502
+ }
1503
+ if (isRecording && !isPaused) {
1504
+ return formatTime(recordingTime);
1505
+ }
1506
+ if (isRecording && isPaused) {
1455
1507
  return formatTime(recordingTime);
1456
1508
  }
1509
+ if (lastDuration > 0) {
1510
+ return formatTime(lastDuration);
1511
+ }
1457
1512
  if (hasRecording) {
1458
- if (isPlaying) {
1459
- return formatTime(playbackTime);
1460
- }
1461
- if (playbackDuration > 0) {
1513
+ if (playbackDuration > 0.5) {
1462
1514
  return formatTime(playbackDuration);
1463
1515
  }
1464
1516
  if (recordingTime > 0) {
@@ -1466,7 +1518,17 @@ const RecordingShell = (props) => {
1466
1518
  }
1467
1519
  }
1468
1520
  return formatTime(0);
1469
- }, [formatTime, hasRecording, isPlaying, playbackDuration, playbackTime, recordingTime]);
1521
+ }, [
1522
+ isPaused,
1523
+ isPlaying,
1524
+ formatTime,
1525
+ isRecording,
1526
+ lastDuration,
1527
+ hasRecording,
1528
+ playbackTime,
1529
+ recordingTime,
1530
+ playbackDuration,
1531
+ ]);
1470
1532
  const recordButtonDisabled = isSending;
1471
1533
  const recordButtonIcon = !isRecording || isPaused
1472
1534
  ? jsxRuntime.jsx(icons.Icon16Microphone, { width: 24, height: 24 })
@@ -1484,10 +1546,13 @@ const RecordingShell = (props) => {
1484
1546
  : jsxRuntime.jsx(icons.Icon16Play, { width: 24, height: 24 });
1485
1547
  const playbackAria = isPlaying ? pausePlaybackAriaLabel : playAriaLabel;
1486
1548
  const sendDisabled = isSending || (!hasRecording && !isRecording);
1487
- return (jsxRuntime.jsxs(Wrapper$1, { children: [jsxRuntime.jsx(CancelButton$1, { type: "button", onClick: onCancel, "aria-label": cancelAriaLabel, children: jsxRuntime.jsx(icons.Icon28DeleteOutlineAndroid, { fill: "var(--exode_red)", width: 24, height: 24, style: { minWidth: 24 } }) }), jsxRuntime.jsxs(Track, { children: [jsxRuntime.jsx(CircleButton, { type: "button", "$variant": recordButtonVariant, onClick: onRecordToggle, "aria-label": recordButtonAria, disabled: recordButtonDisabled, children: recordButtonIcon }), !canShowPlayback ? null : (jsxRuntime.jsx(CircleButton, { type: "button", "$variant": "play", onClick: onTogglePlayback, "aria-label": playbackAria, disabled: playbackDisabled, children: playbackIcon })), jsxRuntime.jsx(Waveform, { "$expanded": canShowPlayback, children: jsxRuntime.jsx(WaveformBars, { values: waveformValues, divider: 100, scale: 42, minHeight: 6, styleInterpolator: ({ normalized }) => ({
1549
+ return (jsxRuntime.jsxs(Wrapper$1, { children: [jsxRuntime.jsx(CancelButton$1, { type: "button", onClick: onCancel, "aria-label": cancelAriaLabel, children: jsxRuntime.jsx(icons.Icon28DeleteOutlineAndroid, { fill: "var(--exode_red)", width: 24, height: 24, style: { minWidth: 24 } }) }), jsxRuntime.jsxs(Track, { children: [jsxRuntime.jsx(CircleButton, { type: "button", "$variant": recordButtonVariant, onClick: onRecordToggle, "aria-label": recordButtonAria, disabled: recordButtonDisabled, children: recordButtonIcon }), !canShowPlayback ? null : (jsxRuntime.jsx(CircleButton, { type: "button", "$variant": "play", onClick: onTogglePlayback, "aria-label": playbackAria, disabled: playbackDisabled, children: playbackIcon })), jsxRuntime.jsx(Waveform, { "$expanded": canShowPlayback, children: jsxRuntime.jsx(WaveformBars, { scale: 42, minHeight: 6, divider: 100, progress: progress, values: waveformValues, styleInterpolator: ({ normalized, isPlayed, progress: p }) => ({
1488
1550
  height: `${12 + normalized / 2}px`,
1489
1551
  maxHeight: '34px',
1490
- opacity: 0.38 + Math.min(0.5, normalized / 120),
1552
+ opacity: p > 0
1553
+ ? (isPlayed ? 0.80 : 0.22)
1554
+ : 0.38 + Math.min(0.5, normalized / 120),
1555
+ transition: 'opacity 80ms ease',
1491
1556
  }) }) }), jsxRuntime.jsx(Timer$1, { children: displayTime })] }), jsxRuntime.jsx(SendButton$1, { type: "button", onClick: onSend, disabled: sendDisabled, "aria-label": sendAriaLabel, children: isSending ? (jsxRuntime.jsx(SpinnerSlot, { children: jsxRuntime.jsx(Spinner, {}) })) : (jsxRuntime.jsx(icons.Icon28SendOutline, { width: 24, height: 24 })) })] }));
1492
1557
  };
1493
1558
 
@@ -1570,9 +1635,9 @@ const AudioRecorder = (props) => {
1570
1635
  messages,
1571
1636
  onUploadError,
1572
1637
  });
1573
- const { isPaused, isPlaying, formatTime, audioLevels, isRecording, playbackTime, hasRecording, previewLevels, recordingTime, playbackDuration, } = recorder;
1574
- const showRecorderBar = isRecording || hasRecording;
1575
- return (jsxRuntime.jsx(Container, { className: className, children: showRecorderBar ? (jsxRuntime.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 })) : (jsxRuntime.jsx(IdleControl, { onClick: handleRecordToggle, startAriaLabel: messages.aria.startRecording, instruction: messages.instruction })) }));
1638
+ const { isPaused, isPlaying, formatTime, audioLevels, isRecording, lastDuration, playbackTime, hasRecording, previewLevels, recordingTime, playbackDuration, } = recorder;
1639
+ const showRecorderBar = isRecording || hasRecording || isSending;
1640
+ return (jsxRuntime.jsx(Container, { className: className, children: showRecorderBar ? (jsxRuntime.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 })) : (jsxRuntime.jsx(IdleControl, { onClick: handleRecordToggle, startAriaLabel: messages.aria.startRecording, instruction: messages.instruction })) }));
1576
1641
  };
1577
1642
 
1578
1643
  /**
@@ -2211,7 +2276,7 @@ const VoiceMessagePlayer = React.forwardRef((props, ref) => {
2211
2276
  observer.disconnect();
2212
2277
  };
2213
2278
  }, []);
2214
- const displayTime = isPlaying
2279
+ const displayTime = (isPlaying || currentTime > 0)
2215
2280
  ? formatTime(currentTime)
2216
2281
  : formatTime(resolvedDuration);
2217
2282
  const handleTrackClick = React.useCallback((e) => {