stream-chat-react 13.11.0 → 13.13.0

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 (51) hide show
  1. package/dist/components/Attachment/Audio.js +38 -15
  2. package/dist/components/Attachment/Card.js +33 -11
  3. package/dist/components/Attachment/Geolocation.js +1 -1
  4. package/dist/components/Attachment/VoiceRecording.js +45 -20
  5. package/dist/components/Attachment/components/PlayButton.js +1 -1
  6. package/dist/components/Attachment/components/PlaybackRateButton.js +1 -1
  7. package/dist/components/Attachment/hooks/useAudioController.d.ts +1 -0
  8. package/dist/components/Attachment/hooks/useAudioController.js +1 -0
  9. package/dist/components/Attachment/index.d.ts +1 -0
  10. package/dist/components/Attachment/index.js +1 -0
  11. package/dist/components/AudioPlayback/AudioPlayer.d.ts +116 -0
  12. package/dist/components/AudioPlayback/AudioPlayer.js +456 -0
  13. package/dist/components/AudioPlayback/AudioPlayerPool.d.ts +49 -0
  14. package/dist/components/AudioPlayback/AudioPlayerPool.js +156 -0
  15. package/dist/components/AudioPlayback/WithAudioPlayback.d.ts +24 -0
  16. package/dist/components/AudioPlayback/WithAudioPlayback.js +57 -0
  17. package/dist/components/AudioPlayback/index.d.ts +3 -0
  18. package/dist/components/AudioPlayback/index.js +3 -0
  19. package/dist/components/AudioPlayback/plugins/AudioPlayerNotificationsPlugin.d.ts +7 -0
  20. package/dist/components/AudioPlayback/plugins/AudioPlayerNotificationsPlugin.js +25 -0
  21. package/dist/components/AudioPlayback/plugins/AudioPlayerPlugin.d.ts +10 -0
  22. package/dist/components/AudioPlayback/plugins/AudioPlayerPlugin.js +1 -0
  23. package/dist/components/AudioPlayback/plugins/index.d.ts +1 -0
  24. package/dist/components/AudioPlayback/plugins/index.js +1 -0
  25. package/dist/components/Channel/Channel.d.ts +2 -0
  26. package/dist/components/Channel/Channel.js +4 -2
  27. package/dist/components/Chat/hooks/useChat.js +1 -1
  28. package/dist/components/MediaRecorder/AudioRecorder/AudioRecordingPreview.d.ts +3 -2
  29. package/dist/components/MediaRecorder/AudioRecorder/AudioRecordingPreview.js +23 -8
  30. package/dist/components/MessageInput/AttachmentPreviewList/FileAttachmentPreview.js +1 -1
  31. package/dist/components/MessageInput/AttachmentPreviewList/GeolocationPreview.js +1 -1
  32. package/dist/components/MessageInput/AttachmentPreviewList/ImageAttachmentPreview.js +1 -1
  33. package/dist/components/MessageInput/AttachmentPreviewList/UnsupportedAttachmentPreview.js +1 -1
  34. package/dist/components/MessageInput/AttachmentPreviewList/VoiceRecordingPreview.d.ts +1 -1
  35. package/dist/components/MessageInput/AttachmentPreviewList/VoiceRecordingPreview.js +20 -7
  36. package/dist/components/MessageList/MessageList.js +8 -5
  37. package/dist/components/MessageList/renderMessages.js +6 -6
  38. package/dist/components/index.d.ts +2 -1
  39. package/dist/components/index.js +2 -1
  40. package/dist/context/ComponentContext.d.ts +4 -0
  41. package/dist/context/MessageListContext.d.ts +3 -0
  42. package/dist/experimental/index.browser.cjs.map +2 -2
  43. package/dist/experimental/index.node.cjs.map +2 -2
  44. package/dist/i18n/TranslationBuilder/notifications/NotificationTranslationTopic.js +2 -0
  45. package/dist/i18n/TranslationBuilder/notifications/browserAudioPlaybackError.d.ts +3 -0
  46. package/dist/i18n/TranslationBuilder/notifications/browserAudioPlaybackError.js +1 -0
  47. package/dist/index.browser.cjs +2833 -2089
  48. package/dist/index.browser.cjs.map +4 -4
  49. package/dist/index.node.cjs +2842 -2089
  50. package/dist/index.node.cjs.map +4 -4
  51. package/package.json +1 -1
@@ -1,27 +1,50 @@
1
1
  import React from 'react';
2
2
  import { DownloadButton, FileSizeIndicator, PlayButton, ProgressBar } from './components';
3
- import { useAudioController } from './hooks/useAudioController';
4
- const UnMemoizedAudio = (props) => {
5
- const { og: { asset_url, file_size, mime_type, title }, } = props;
6
- const { audioRef, isPlaying, progress, seek, togglePlay } = useAudioController({
7
- mimeType: mime_type,
8
- });
9
- if (!asset_url)
10
- return null;
3
+ import { useAudioPlayer } from '../AudioPlayback';
4
+ import { useStateStore } from '../../store';
5
+ import { useMessageContext } from '../../context';
6
+ // todo: finish creating a BaseAudioPlayer derived from VoiceRecordingPlayerUI and AudioAttachmentUI
7
+ const AudioAttachmentUI = ({ audioPlayer }) => {
11
8
  const dataTestId = 'audio-widget';
12
9
  const rootClassName = 'str-chat__message-attachment-audio-widget';
10
+ const { isPlaying, progress } = useStateStore(audioPlayer?.state, audioPlayerStateSelector) ?? {};
13
11
  return (React.createElement("div", { className: rootClassName, "data-testid": dataTestId },
14
- React.createElement("audio", { ref: audioRef },
15
- React.createElement("source", { "data-testid": 'audio-source', src: asset_url, type: 'audio/mp3' })),
16
12
  React.createElement("div", { className: 'str-chat__message-attachment-audio-widget--play-controls' },
17
- React.createElement(PlayButton, { isPlaying: isPlaying, onClick: togglePlay })),
13
+ React.createElement(PlayButton, { isPlaying: !!isPlaying, onClick: audioPlayer.togglePlay })),
18
14
  React.createElement("div", { className: 'str-chat__message-attachment-audio-widget--text' },
19
15
  React.createElement("div", { className: 'str-chat__message-attachment-audio-widget--text-first-row' },
20
- React.createElement("div", { className: 'str-chat__message-attachment-audio-widget--title' }, title),
21
- React.createElement(DownloadButton, { assetUrl: asset_url })),
16
+ React.createElement("div", { className: 'str-chat__message-attachment-audio-widget--title' }, audioPlayer.title),
17
+ React.createElement(DownloadButton, { assetUrl: audioPlayer.src })),
22
18
  React.createElement("div", { className: 'str-chat__message-attachment-audio-widget--text-second-row' },
23
- React.createElement(FileSizeIndicator, { fileSize: file_size }),
24
- React.createElement(ProgressBar, { onClick: seek, progress: progress })))));
19
+ React.createElement(FileSizeIndicator, { fileSize: audioPlayer.fileSize }),
20
+ React.createElement(ProgressBar, { onClick: audioPlayer.seek, progress: progress ?? 0 })))));
21
+ };
22
+ const audioPlayerStateSelector = (state) => ({
23
+ isPlaying: state.isPlaying,
24
+ progress: state.progressPercent,
25
+ });
26
+ const UnMemoizedAudio = (props) => {
27
+ const { og: { asset_url, file_size, mime_type, title }, } = props;
28
+ /**
29
+ * Introducing message context. This could be breaking change, therefore the fallback to {} is provided.
30
+ * If this component is used outside the message context, then there will be no audio player namespacing
31
+ * => scrolling away from the message in virtualized ML would create a new AudioPlayer instance.
32
+ *
33
+ * Edge case: the requester (message) has multiple attachments with the same assetURL - does not happen
34
+ * with the default SDK components, but can be done with custom API calls.In this case all the Audio
35
+ * widgets will share the state.
36
+ */
37
+ const { message, threadList } = useMessageContext() ?? {};
38
+ const audioPlayer = useAudioPlayer({
39
+ fileSize: file_size,
40
+ mimeType: mime_type,
41
+ requester: message?.id &&
42
+ `${threadList ? (message.parent_id ?? message.id) : ''}${message.id}`,
43
+ src: asset_url,
44
+ title,
45
+ waveformData: props.og.waveform_data,
46
+ });
47
+ return audioPlayer ? React.createElement(AudioAttachmentUI, { audioPlayer: audioPlayer }) : null;
25
48
  };
26
49
  /**
27
50
  * Audio attachment with play/pause button and progress bar
@@ -4,9 +4,11 @@ import ReactPlayer from 'react-player';
4
4
  import { ImageComponent } from '../Gallery';
5
5
  import { SafeAnchor } from '../SafeAnchor';
6
6
  import { PlayButton, ProgressBar } from './components';
7
- import { useAudioController } from './hooks/useAudioController';
8
7
  import { useChannelStateContext } from '../../context/ChannelStateContext';
9
8
  import { useTranslationContext } from '../../context/TranslationContext';
9
+ import { useAudioPlayer } from '../AudioPlayback';
10
+ import { useStateStore } from '../../store';
11
+ import { useMessageContext } from '../../context';
10
12
  const getHostFromURL = (url) => {
11
13
  if (url !== undefined && url !== null) {
12
14
  const [trimmedUrl] = url.replace(/^(?:https?:\/\/)?(?:www\.)?/i, '').split('/');
@@ -43,21 +45,41 @@ const CardContent = (props) => {
43
45
  title && (React.createElement("div", { className: 'str-chat__message-attachment-card--title' }, title)),
44
46
  text && React.createElement("div", { className: 'str-chat__message-attachment-card--text' }, text)))));
45
47
  };
46
- export const CardAudio = ({ og: { asset_url, author_name, mime_type, og_scrape_url, text, title, title_link }, }) => {
47
- const { audioRef, isPlaying, progress, seek, togglePlay } = useAudioController({
48
- mimeType: mime_type,
48
+ const audioPlayerStateSelector = (state) => ({
49
+ isPlaying: state.isPlaying,
50
+ progress: state.progressPercent,
51
+ });
52
+ const AudioWidget = ({ mimeType, src }) => {
53
+ /**
54
+ * Introducing message context. This could be breaking change, therefore the fallback to {} is provided.
55
+ * If this component is used outside the message context, then there will be no audio player namespacing
56
+ * => scrolling away from the message in virtualized ML would create a new AudioPlayer instance.
57
+ *
58
+ * Edge case: the requester (message) has multiple attachments with the same assetURL - does not happen
59
+ * with the default SDK components, but can be done with custom API calls.In this case all the Audio
60
+ * widgets will share the state.
61
+ */
62
+ const { message, threadList } = useMessageContext() ?? {};
63
+ const audioPlayer = useAudioPlayer({
64
+ mimeType,
65
+ requester: message?.id &&
66
+ `${threadList ? (message.parent_id ?? message.id) : ''}${message.id}`,
67
+ src,
49
68
  });
69
+ const { isPlaying, progress } = useStateStore(audioPlayer?.state, audioPlayerStateSelector) ?? {};
70
+ if (!audioPlayer)
71
+ return;
72
+ return (React.createElement("div", { className: 'str-chat__message-attachment-card-audio-widget--first-row' },
73
+ React.createElement("div", { className: 'str-chat__message-attachment-audio-widget--play-controls' },
74
+ React.createElement(PlayButton, { isPlaying: !!isPlaying, onClick: audioPlayer.togglePlay })),
75
+ React.createElement(ProgressBar, { onClick: audioPlayer.seek, progress: progress ?? 0 })));
76
+ };
77
+ export const CardAudio = ({ og: { asset_url, author_name, mime_type, og_scrape_url, text, title, title_link }, }) => {
50
78
  const url = title_link || og_scrape_url;
51
79
  const dataTestId = 'card-audio-widget';
52
80
  const rootClassName = 'str-chat__message-attachment-card-audio-widget';
53
81
  return (React.createElement("div", { className: rootClassName, "data-testid": dataTestId },
54
- asset_url && (React.createElement(React.Fragment, null,
55
- React.createElement("audio", { ref: audioRef },
56
- React.createElement("source", { "data-testid": 'audio-source', src: asset_url, type: 'audio/mp3' })),
57
- React.createElement("div", { className: 'str-chat__message-attachment-card-audio-widget--first-row' },
58
- React.createElement("div", { className: 'str-chat__message-attachment-audio-widget--play-controls' },
59
- React.createElement(PlayButton, { isPlaying: isPlaying, onClick: togglePlay })),
60
- React.createElement(ProgressBar, { onClick: seek, progress: progress })))),
82
+ asset_url && React.createElement(AudioWidget, { mimeType: mime_type, src: asset_url }),
61
83
  React.createElement("div", { className: 'str-chat__message-attachment-audio-widget--second-row' },
62
84
  url && React.createElement(SourceLink, { author_name: author_name, url: url }),
63
85
  title && (React.createElement("div", { className: 'str-chat__message-attachment-audio-widget--title' }, title)),
@@ -19,7 +19,7 @@ export const Geolocation = ({ GeolocationAttachmentMapPlaceholder = DefaultGeolo
19
19
  return (React.createElement("div", { className: 'str-chat__message-attachment-geolocation', "data-testid": 'attachment-geolocation' },
20
20
  React.createElement("div", { className: 'str-chat__message-attachment-geolocation__location-preview' }, GeolocationMap ? (React.createElement(GeolocationMap, { latitude: location.latitude, longitude: location.longitude })) : (React.createElement(GeolocationAttachmentMapPlaceholder, { location: location }))),
21
21
  React.createElement("div", { className: 'str-chat__message-attachment-geolocation__status' }, isLiveLocation ? (stoppedSharing ? (t('Location sharing ended')) : isMyLocation ? (React.createElement("div", { className: 'str-chat__message-attachment-geolocation__status--active' },
22
- React.createElement("button", { className: 'str-chat__message-attachment-geolocation__stop-sharing-button', onClick: () => channel?.stopLiveLocationSharing(location) }, t('Stop sharing')),
22
+ React.createElement("button", { className: 'str-chat__message-attachment-geolocation__stop-sharing-button', onClick: () => channel?.stopLiveLocationSharing(location), type: 'button' }, t('Stop sharing')),
23
23
  React.createElement("div", { className: 'str-chat__message-attachment-geolocation__status--active-until' }, t('Live until {{ timestamp }}', {
24
24
  timestamp: t('timestamp/LiveLocation', { timestamp: location.end_at }),
25
25
  })))) : (React.createElement("div", { className: 'str-chat__message-attachment-geolocation__status--active' },
@@ -1,33 +1,58 @@
1
1
  import React from 'react';
2
2
  import { FileSizeIndicator, PlaybackRateButton, PlayButton, WaveProgressBar, } from './components';
3
- import { useAudioController } from './hooks/useAudioController';
4
3
  import { displayDuration } from './utils';
5
4
  import { FileIcon } from '../ReactFileUtilities';
6
- import { useTranslationContext } from '../../context';
5
+ import { useMessageContext, useTranslationContext } from '../../context';
6
+ import { useAudioPlayer } from '../AudioPlayback/';
7
+ import { useStateStore } from '../../store';
7
8
  const rootClassName = 'str-chat__message-attachment__voice-recording-widget';
9
+ const audioPlayerStateSelector = (state) => ({
10
+ canPlayRecord: state.canPlayRecord,
11
+ isPlaying: state.isPlaying,
12
+ playbackRate: state.currentPlaybackRate,
13
+ progress: state.progressPercent,
14
+ secondsElapsed: state.secondsElapsed,
15
+ });
16
+ // todo: finish creating a BaseAudioPlayer derived from VoiceRecordingPlayerUI and AudioAttachmentUI
17
+ const VoiceRecordingPlayerUI = ({ audioPlayer }) => {
18
+ const { canPlayRecord, isPlaying, playbackRate, progress, secondsElapsed } = useStateStore(audioPlayer?.state, audioPlayerStateSelector) ?? {};
19
+ const displayedDuration = secondsElapsed || audioPlayer.durationSeconds;
20
+ return (React.createElement("div", { className: rootClassName, "data-testid": 'voice-recording-widget' },
21
+ React.createElement(PlayButton, { isPlaying: !!isPlaying, onClick: audioPlayer.togglePlay }),
22
+ React.createElement("div", { className: 'str-chat__message-attachment__voice-recording-widget__metadata' },
23
+ React.createElement("div", { className: 'str-chat__message-attachment__voice-recording-widget__title', "data-testid": 'voice-recording-title', title: audioPlayer.title }, audioPlayer.title),
24
+ React.createElement("div", { className: 'str-chat__message-attachment__voice-recording-widget__audio-state' },
25
+ React.createElement("div", { className: 'str-chat__message-attachment__voice-recording-widget__timer' }, audioPlayer.durationSeconds ? (displayDuration(displayedDuration)) : (React.createElement(FileSizeIndicator, { fileSize: audioPlayer.fileSize, maximumFractionDigits: 0 }))),
26
+ React.createElement(WaveProgressBar, { progress: progress, seek: audioPlayer.seek, waveformData: audioPlayer.waveformData || [] }))),
27
+ React.createElement("div", { className: 'str-chat__message-attachment__voice-recording-widget__right-section' }, isPlaying ? (React.createElement(PlaybackRateButton, { disabled: !canPlayRecord, onClick: audioPlayer.increasePlaybackRate },
28
+ playbackRate?.toFixed(1),
29
+ "x")) : (React.createElement(FileIcon, { big: true, mimeType: audioPlayer.mimeType, size: 40 })))));
30
+ };
8
31
  export const VoiceRecordingPlayer = ({ attachment, playbackRates, }) => {
9
- const { t } = useTranslationContext('VoiceRecordingPlayer');
10
- const { asset_url, duration = 0, mime_type, title = t('Voice message'), waveform_data, } = attachment;
11
- const { audioRef, increasePlaybackRate, isPlaying, playbackRate, progress, secondsElapsed, seek, togglePlay, } = useAudioController({
32
+ const { t } = useTranslationContext();
33
+ const { asset_url, duration = 0, file_size, mime_type, title = t('Voice message'), waveform_data, } = attachment;
34
+ /**
35
+ * Introducing message context. This could be breaking change, therefore the fallback to {} is provided.
36
+ * If this component is used outside the message context, then there will be no audio player namespacing
37
+ * => scrolling away from the message in virtualized ML would create a new AudioPlayer instance.
38
+ *
39
+ * Edge case: the requester (message) has multiple attachments with the same assetURL - does not happen
40
+ * with the default SDK components, but can be done with custom API calls.In this case all the Audio
41
+ * widgets will share the state.
42
+ */
43
+ const { message, threadList } = useMessageContext() ?? {};
44
+ const audioPlayer = useAudioPlayer({
12
45
  durationSeconds: duration ?? 0,
46
+ fileSize: file_size,
13
47
  mimeType: mime_type,
14
48
  playbackRates,
49
+ requester: message?.id &&
50
+ `${threadList ? (message.parent_id ?? message.id) : ''}${message.id}`,
51
+ src: asset_url,
52
+ title,
53
+ waveformData: waveform_data,
15
54
  });
16
- if (!asset_url)
17
- return null;
18
- const displayedDuration = secondsElapsed || duration;
19
- return (React.createElement("div", { className: rootClassName, "data-testid": 'voice-recording-widget' },
20
- React.createElement("audio", { ref: audioRef },
21
- React.createElement("source", { "data-testid": 'audio-source', src: asset_url, type: mime_type })),
22
- React.createElement(PlayButton, { isPlaying: isPlaying, onClick: togglePlay }),
23
- React.createElement("div", { className: 'str-chat__message-attachment__voice-recording-widget__metadata' },
24
- React.createElement("div", { className: 'str-chat__message-attachment__voice-recording-widget__title', "data-testid": 'voice-recording-title', title: title }, title),
25
- React.createElement("div", { className: 'str-chat__message-attachment__voice-recording-widget__audio-state' },
26
- React.createElement("div", { className: 'str-chat__message-attachment__voice-recording-widget__timer' }, attachment.duration ? (displayDuration(displayedDuration)) : (React.createElement(FileSizeIndicator, { fileSize: attachment.file_size, maximumFractionDigits: 0 }))),
27
- React.createElement(WaveProgressBar, { progress: progress, seek: seek, waveformData: waveform_data || [] }))),
28
- React.createElement("div", { className: 'str-chat__message-attachment__voice-recording-widget__right-section' }, isPlaying ? (React.createElement(PlaybackRateButton, { disabled: !audioRef.current, onClick: increasePlaybackRate },
29
- playbackRate.toFixed(1),
30
- "x")) : (React.createElement(FileIcon, { big: true, mimeType: mime_type, size: 40 })))));
55
+ return audioPlayer ? React.createElement(VoiceRecordingPlayerUI, { audioPlayer: audioPlayer }) : null;
31
56
  };
32
57
  export const QuotedVoiceRecording = ({ attachment }) => {
33
58
  const { t } = useTranslationContext();
@@ -1,3 +1,3 @@
1
1
  import React from 'react';
2
2
  import { PauseIcon, PlayTriangleIcon } from '../icons';
3
- export const PlayButton = ({ isPlaying, onClick }) => (React.createElement("button", { className: 'str-chat__message-attachment-audio-widget--play-button', "data-testid": isPlaying ? 'pause-audio' : 'play-audio', onClick: onClick }, isPlaying ? React.createElement(PauseIcon, null) : React.createElement(PlayTriangleIcon, null)));
3
+ export const PlayButton = ({ isPlaying, onClick }) => (React.createElement("button", { className: 'str-chat__message-attachment-audio-widget--play-button', "data-testid": isPlaying ? 'pause-audio' : 'play-audio', onClick: onClick, type: 'button' }, isPlaying ? React.createElement(PauseIcon, null) : React.createElement(PlayTriangleIcon, null)));
@@ -1,2 +1,2 @@
1
1
  import React from 'react';
2
- export const PlaybackRateButton = ({ children, onClick }) => (React.createElement("button", { className: 'str-chat__message_attachment__playback-rate-button', "data-testid": 'playback-rate-button', onClick: onClick }, children));
2
+ export const PlaybackRateButton = ({ children, onClick }) => (React.createElement("button", { className: 'str-chat__message_attachment__playback-rate-button', "data-testid": 'playback-rate-button', onClick: onClick, type: 'button' }, children));
@@ -12,6 +12,7 @@ type AudioControllerParams = {
12
12
  /** An array of fractional numeric values of playback speed to override the defaults (1.0, 1.5, 2.0) */
13
13
  playbackRates?: number[];
14
14
  };
15
+ /** @deprecated use useAudioPlayer instead */
15
16
  export declare const useAudioController: ({ durationSeconds, mimeType, playbackRates, }?: AudioControllerParams) => {
16
17
  audioRef: import("react").RefObject<HTMLAudioElement | null>;
17
18
  canPlayRecord: boolean;
@@ -5,6 +5,7 @@ const isSeekable = (audioElement) => !(audioElement.duration === Infinity || isN
5
5
  export const elementIsPlaying = (audioElement) => audioElement && !(audioElement.paused || audioElement.ended);
6
6
  const logError = (e) => console.error('[AUDIO PLAYER]', e);
7
7
  const DEFAULT_PLAYBACK_RATES = [1.0, 1.5, 2.0];
8
+ /** @deprecated use useAudioPlayer instead */
8
9
  export const useAudioController = ({ durationSeconds, mimeType, playbackRates = DEFAULT_PLAYBACK_RATES, } = {}) => {
9
10
  const { addNotification } = useChannelActionContext('useAudioController');
10
11
  const { t } = useTranslationContext('useAudioController');
@@ -9,5 +9,6 @@ export * from './FileAttachment';
9
9
  export * from './Geolocation';
10
10
  export * from './UnsupportedAttachment';
11
11
  export * from './utils';
12
+ export * from './VoiceRecording';
12
13
  export { useAudioController } from './hooks/useAudioController';
13
14
  export * from '../Location/hooks/useLiveLocationSharingManager';
@@ -9,5 +9,6 @@ export * from './FileAttachment';
9
9
  export * from './Geolocation';
10
10
  export * from './UnsupportedAttachment';
11
11
  export * from './utils';
12
+ export * from './VoiceRecording';
12
13
  export { useAudioController } from './hooks/useAudioController';
13
14
  export * from '../Location/hooks/useLiveLocationSharingManager';
@@ -0,0 +1,116 @@
1
+ /// <reference types="lodash" />
2
+ import { StateStore } from 'stream-chat';
3
+ import type { AudioPlayerPlugin } from './plugins';
4
+ import type { AudioPlayerPool } from './AudioPlayerPool';
5
+ export type AudioPlayerErrorCode = 'failed-to-start' | 'not-playable' | 'seek-not-supported' | (string & {});
6
+ export type RegisterAudioPlayerErrorParams = {
7
+ error?: Error;
8
+ errCode?: AudioPlayerErrorCode;
9
+ };
10
+ export type AudioPlayerDescriptor = {
11
+ id: string;
12
+ src: string;
13
+ /** Audio duration in seconds. */
14
+ durationSeconds?: number;
15
+ fileSize?: number | string;
16
+ mimeType?: string;
17
+ title?: string;
18
+ waveformData?: number[];
19
+ };
20
+ export type AudioPlayerPlayAudioParams = {
21
+ currentPlaybackRate?: number;
22
+ playbackRates?: number[];
23
+ };
24
+ export type AudioPlayerState = {
25
+ /** Signals whether the browser can play the record. */
26
+ canPlayRecord: boolean;
27
+ /** Current playback speed. Initiated with the first item of the playbackRates array. */
28
+ currentPlaybackRate: number;
29
+ /** The audio element ref */
30
+ elementRef: HTMLAudioElement | null;
31
+ /** Signals whether the playback is in progress. */
32
+ isPlaying: boolean;
33
+ /** Keeps the latest playback error reference. */
34
+ playbackError: Error | null;
35
+ /** An array of fractional numeric values of playback speed to override the defaults (1.0, 1.5, 2.0) */
36
+ playbackRates: number[];
37
+ /** Playback progress expressed in percent. */
38
+ progressPercent: number;
39
+ /** Playback progress expressed in seconds. */
40
+ secondsElapsed: number;
41
+ };
42
+ export type AudioPlayerOptions = AudioPlayerDescriptor & {
43
+ /** An array of fractional numeric values of playback speed to override the defaults (1.0, 1.5, 2.0) */
44
+ playbackRates?: number[];
45
+ plugins?: AudioPlayerPlugin[];
46
+ pool: AudioPlayerPool;
47
+ };
48
+ export declare const defaultRegisterAudioPlayerError: ({ error, }?: RegisterAudioPlayerErrorParams) => void;
49
+ export declare const elementIsPlaying: (audioElement: HTMLAudioElement | null) => boolean | null;
50
+ export type SeekFn = (params: {
51
+ clientX: number;
52
+ currentTarget: HTMLDivElement;
53
+ }) => Promise<void>;
54
+ export declare class AudioPlayer {
55
+ state: StateStore<AudioPlayerState>;
56
+ /** The audio MIME type that is checked before the audio is played. If the type is not supported the controller registers error in playbackError. */
57
+ private _data;
58
+ private _plugins;
59
+ private playTimeout;
60
+ private unsubscribeEventListeners;
61
+ private _pool;
62
+ private _disposed;
63
+ private _pendingLoadedMeta?;
64
+ private _elementIsReadyPromise?;
65
+ private _restoringPosition;
66
+ private _removalTimeout;
67
+ constructor({ durationSeconds, fileSize, id, mimeType, playbackRates: customPlaybackRates, plugins, pool, src, title, waveformData, }: AudioPlayerOptions);
68
+ private get plugins();
69
+ get canPlayRecord(): boolean;
70
+ get elementRef(): HTMLAudioElement | null;
71
+ get isPlaying(): boolean;
72
+ get currentPlaybackRate(): number;
73
+ get playbackRates(): number[];
74
+ get durationSeconds(): number | undefined;
75
+ get fileSize(): string | number | undefined;
76
+ get id(): string;
77
+ get src(): string;
78
+ get mimeType(): string | undefined;
79
+ get title(): string | undefined;
80
+ get waveformData(): number[] | undefined;
81
+ get secondsElapsed(): number;
82
+ get progressPercent(): number;
83
+ get disposed(): boolean;
84
+ private ensureElementRef;
85
+ private setPlaybackStartSafetyTimeout;
86
+ private clearPlaybackStartSafetyTimeout;
87
+ private clearPendingLoadedMeta;
88
+ private restoreSavedPosition;
89
+ setDescriptor(descriptor: AudioPlayerDescriptor): void;
90
+ private releaseElement;
91
+ private elementIsReady;
92
+ private setRef;
93
+ setSecondsElapsed: (secondsElapsed: number) => void;
94
+ setPlugins(setter: (currentPlugins: AudioPlayerPlugin[]) => AudioPlayerPlugin[]): void;
95
+ canPlayMimeType: (mimeType: string) => boolean;
96
+ play: (params?: AudioPlayerPlayAudioParams) => Promise<void>;
97
+ pause: () => void;
98
+ stop: () => void;
99
+ togglePlay: () => Promise<void>;
100
+ increasePlaybackRate: () => void;
101
+ seek: import("lodash").DebouncedFunc<SeekFn>;
102
+ registerError: (params: RegisterAudioPlayerErrorParams) => void;
103
+ /**
104
+ * Removes the audio element reference, event listeners and audio player from the player pool.
105
+ * Helpful when only a single AudioPlayer instance is to be removed from the AudioPlayerPool.
106
+ */
107
+ requestRemoval: () => void;
108
+ cancelScheduledRemoval: () => void;
109
+ scheduleRemoval: (ms?: number) => void;
110
+ /**
111
+ * Releases only the underlying element back to the pool without disposing the player instance.
112
+ * Used by the pool to hand off the shared element in single-playback mode.
113
+ */
114
+ releaseElementForHandoff: () => void;
115
+ registerSubscriptions: () => void;
116
+ }