stream-chat-react 12.0.0-rc.1 → 12.0.0-rc.11
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/README.md +11 -1
- package/dist/components/Attachment/components/WaveProgressBar.d.ts +3 -1
- package/dist/components/Attachment/components/WaveProgressBar.js +44 -9
- package/dist/components/Avatar/Avatar.js +5 -1
- package/dist/components/Channel/Channel.d.ts +3 -4
- package/dist/components/Channel/Channel.js +95 -56
- package/dist/components/Channel/channelState.js +1 -0
- package/dist/components/Channel/hooks/useCreateChannelStateContext.js +1 -1
- package/dist/components/ChannelList/ChannelList.js +1 -1
- package/dist/components/Chat/Chat.d.ts +1 -1
- package/dist/components/Chat/hooks/useChat.d.ts +2 -2
- package/dist/components/Chat/hooks/useChat.js +11 -8
- package/dist/components/Chat/hooks/useCreateChatClient.d.ts +4 -2
- package/dist/components/Chat/hooks/useCreateChatClient.js +5 -4
- package/dist/components/ChatView/ChatView.d.ts +18 -0
- package/dist/components/ChatView/ChatView.js +100 -0
- package/dist/components/ChatView/index.d.ts +1 -0
- package/dist/components/ChatView/index.js +1 -0
- package/dist/components/DateSeparator/DateSeparator.d.ts +1 -1
- package/dist/components/DateSeparator/DateSeparator.js +1 -1
- package/dist/components/EventComponent/EventComponent.d.ts +1 -1
- package/dist/components/EventComponent/EventComponent.js +1 -1
- package/dist/components/InfiniteScrollPaginator/InfiniteScroll.js +9 -3
- package/dist/components/MediaRecorder/AudioRecorder/AudioRecordingInProgress.js +3 -0
- package/dist/components/MediaRecorder/classes/MediaRecorderController.d.ts +6 -7
- package/dist/components/MediaRecorder/classes/MediaRecorderController.js +0 -5
- package/dist/components/MediaRecorder/hooks/index.d.ts +1 -1
- package/dist/components/MediaRecorder/hooks/useMediaRecorder.d.ts +1 -2
- package/dist/components/MediaRecorder/hooks/useMediaRecorder.js +1 -1
- package/dist/components/MediaRecorder/index.d.ts +1 -0
- package/dist/components/MediaRecorder/transcode/index.d.ts +6 -5
- package/dist/components/MediaRecorder/transcode/index.js +5 -15
- package/dist/components/Message/Message.js +2 -1
- package/dist/components/Message/MessageOptions.js +3 -4
- package/dist/components/Message/MessageSimple.js +3 -2
- package/dist/components/Message/MessageStatus.js +3 -2
- package/dist/components/Message/MessageTimestamp.d.ts +1 -2
- package/dist/components/Message/MessageTimestamp.js +0 -1
- package/dist/components/Message/QuotedMessage.js +2 -1
- package/dist/components/Message/Timestamp.d.ts +1 -2
- package/dist/components/Message/Timestamp.js +4 -5
- package/dist/components/Message/hooks/useReactionHandler.js +7 -0
- package/dist/components/Message/renderText/rehypePlugins/mentionsMarkdownPlugin.d.ts +1 -1
- package/dist/components/Message/renderText/remarkPlugins/htmlToTextPlugin.d.ts +1 -1
- package/dist/components/Message/renderText/remarkPlugins/keepLineBreaksPlugin.d.ts +1 -1
- package/dist/components/Message/renderText/remarkPlugins/keepLineBreaksPlugin.js +2 -6
- package/dist/components/Message/renderText/renderText.d.ts +2 -2
- package/dist/components/Message/renderText/renderText.js +8 -6
- package/dist/components/Message/utils.d.ts +10 -1
- package/dist/components/Message/utils.js +18 -7
- package/dist/components/MessageActions/MessageActions.js +14 -9
- package/dist/components/MessageInput/AttachmentPreviewList/AttachmentPreviewList.js +23 -27
- package/dist/components/MessageInput/AttachmentPreviewList/FileAttachmentPreview.d.ts +1 -0
- package/dist/components/MessageInput/AttachmentPreviewList/FileAttachmentPreview.js +1 -1
- package/dist/components/MessageInput/AttachmentPreviewList/ImageAttachmentPreview.js +2 -1
- package/dist/components/MessageInput/MessageInput.d.ts +4 -6
- package/dist/components/MessageInput/MessageInputFlat.js +5 -8
- package/dist/components/MessageInput/QuotedMessagePreview.js +2 -1
- package/dist/components/MessageInput/hooks/useAttachments.d.ts +1 -5
- package/dist/components/MessageInput/hooks/useAttachments.js +65 -52
- package/dist/components/MessageInput/hooks/useCreateMessageInputContext.js +2 -19
- package/dist/components/MessageInput/hooks/useMessageInputState.d.ts +2 -35
- package/dist/components/MessageInput/hooks/useMessageInputState.js +2 -107
- package/dist/components/MessageInput/hooks/usePasteHandler.js +1 -3
- package/dist/components/MessageInput/hooks/useSubmitHandler.js +19 -71
- package/dist/components/MessageInput/hooks/useTimeElapsed.js +5 -4
- package/dist/components/MessageInput/hooks/utils.d.ts +1 -2
- package/dist/components/MessageInput/icons.d.ts +0 -1
- package/dist/components/MessageInput/icons.js +0 -3
- package/dist/components/MessageInput/types.d.ts +3 -30
- package/dist/components/MessageList/MessageList.d.ts +3 -1
- package/dist/components/MessageList/MessageList.js +3 -4
- package/dist/components/MessageList/VirtualizedMessageList.d.ts +5 -2
- package/dist/components/MessageList/VirtualizedMessageList.js +8 -5
- package/dist/components/MessageList/VirtualizedMessageListComponents.d.ts +1 -1
- package/dist/components/MessageList/VirtualizedMessageListComponents.js +7 -6
- package/dist/components/MessageList/hooks/MessageList/useEnrichedMessages.d.ts +2 -1
- package/dist/components/MessageList/hooks/MessageList/useEnrichedMessages.js +3 -3
- package/dist/components/MessageList/renderMessages.d.ts +2 -2
- package/dist/components/MessageList/renderMessages.js +4 -1
- package/dist/components/MessageList/utils.d.ts +1 -1
- package/dist/components/MessageList/utils.js +17 -7
- package/dist/components/ReactFileUtilities/types.d.ts +0 -29
- package/dist/components/ReactFileUtilities/utils.d.ts +2 -0
- package/dist/components/ReactFileUtilities/utils.js +2 -0
- package/dist/components/Reactions/ReactionSelector.d.ts +5 -2
- package/dist/components/Reactions/ReactionSelector.js +2 -1
- package/dist/components/Reactions/ReactionsList.d.ts +4 -1
- package/dist/components/Reactions/hooks/useProcessReactions.js +2 -1
- package/dist/components/Thread/Thread.d.ts +0 -2
- package/dist/components/Thread/Thread.js +38 -12
- package/dist/components/Threads/ThreadContext.d.ts +9 -0
- package/dist/components/Threads/ThreadContext.js +9 -0
- package/dist/components/Threads/ThreadList/ThreadList.d.ts +9 -0
- package/dist/components/Threads/ThreadList/ThreadList.js +41 -0
- package/dist/components/Threads/ThreadList/ThreadListEmptyPlaceholder.d.ts +2 -0
- package/dist/components/Threads/ThreadList/ThreadListEmptyPlaceholder.js +5 -0
- package/dist/components/Threads/ThreadList/ThreadListItem.d.ts +9 -0
- package/dist/components/Threads/ThreadList/ThreadListItem.js +52 -0
- package/dist/components/Threads/ThreadList/ThreadListItemUI.d.ts +18 -0
- package/dist/components/Threads/ThreadList/ThreadListItemUI.js +76 -0
- package/dist/components/Threads/ThreadList/ThreadListLoadingIndicator.d.ts +2 -0
- package/dist/components/Threads/ThreadList/ThreadListLoadingIndicator.js +14 -0
- package/dist/components/Threads/ThreadList/ThreadListUnseenThreadsBanner.d.ts +2 -0
- package/dist/components/Threads/ThreadList/ThreadListUnseenThreadsBanner.js +16 -0
- package/dist/components/Threads/ThreadList/index.d.ts +3 -0
- package/dist/components/Threads/ThreadList/index.js +3 -0
- package/dist/components/Threads/UnreadCountBadge.d.ts +6 -0
- package/dist/components/Threads/UnreadCountBadge.js +5 -0
- package/dist/components/Threads/hooks/useStateStore.d.ts +3 -0
- package/dist/components/Threads/hooks/useStateStore.js +15 -0
- package/dist/components/Threads/hooks/useThreadManagerState.d.ts +2 -0
- package/dist/components/Threads/hooks/useThreadManagerState.js +6 -0
- package/dist/components/Threads/hooks/useThreadState.d.ts +5 -0
- package/dist/components/Threads/hooks/useThreadState.js +11 -0
- package/dist/components/Threads/icons.d.ts +8 -0
- package/dist/components/Threads/icons.js +13 -0
- package/dist/components/Threads/index.d.ts +3 -0
- package/dist/components/Threads/index.js +3 -0
- package/dist/components/UtilityComponents/ErrorBoundary.d.ts +16 -0
- package/dist/components/UtilityComponents/ErrorBoundary.js +19 -0
- package/dist/components/UtilityComponents/index.d.ts +1 -0
- package/dist/components/UtilityComponents/index.js +1 -0
- package/dist/components/Window/Window.d.ts +1 -3
- package/dist/components/Window/Window.js +2 -2
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +2 -0
- package/dist/context/ChannelActionContext.d.ts +2 -2
- package/dist/context/ComponentContext.d.ts +15 -40
- package/dist/context/ComponentContext.js +7 -9
- package/dist/context/MessageContext.d.ts +1 -1
- package/dist/context/MessageContext.js +3 -2
- package/dist/context/MessageInputContext.d.ts +1 -5
- package/dist/context/TranslationContext.d.ts +1 -11
- package/dist/context/TranslationContext.js +1 -9
- package/dist/context/WithComponents.d.ts +5 -0
- package/dist/context/WithComponents.js +7 -0
- package/dist/context/index.d.ts +1 -0
- package/dist/context/index.js +1 -0
- package/dist/css/v2/emoji-replacement.css +1 -1
- package/dist/css/v2/index.css +2 -2
- package/dist/css/v2/index.layout.css +2 -2
- package/dist/i18n/Streami18n.d.ts +3 -3
- package/dist/i18n/Streami18n.js +1 -2
- package/dist/i18n/de.json +3 -1
- package/dist/i18n/en.json +3 -1
- package/dist/i18n/es.json +3 -1
- package/dist/i18n/fr.json +3 -1
- package/dist/i18n/hi.json +3 -1
- package/dist/i18n/index.d.ts +2 -1
- package/dist/i18n/index.js +2 -0
- package/dist/i18n/it.json +3 -1
- package/dist/i18n/ja.json +3 -1
- package/dist/i18n/ko.json +3 -1
- package/dist/i18n/nl.json +3 -1
- package/dist/i18n/pt.json +3 -1
- package/dist/i18n/ru.json +3 -1
- package/dist/i18n/tr.json +3 -1
- package/dist/i18n/types.d.ts +26 -0
- package/dist/i18n/types.js +1 -0
- package/dist/i18n/utils.d.ts +9 -20
- package/dist/i18n/utils.js +10 -1
- package/dist/index.browser.cjs +47726 -0
- package/dist/index.browser.cjs.map +7 -0
- package/dist/{index.cjs.js → index.node.cjs} +21289 -32183
- package/dist/index.node.cjs.map +7 -0
- package/dist/{components → plugins}/Emojis/EmojiPicker.js +1 -1
- package/dist/plugins/Emojis/icons.d.ts +2 -0
- package/dist/plugins/Emojis/icons.js +4 -0
- package/dist/plugins/Emojis/index.browser.cjs +167 -0
- package/dist/plugins/Emojis/index.browser.cjs.map +7 -0
- package/dist/plugins/Emojis/index.d.ts +2 -0
- package/dist/plugins/Emojis/index.js +2 -0
- package/dist/{components/Emojis/index.cjs.js → plugins/Emojis/index.node.cjs} +31 -192
- package/dist/plugins/Emojis/index.node.cjs.map +7 -0
- package/dist/plugins/encoders/mp3.browser.cjs +105 -0
- package/dist/plugins/encoders/mp3.browser.cjs.map +7 -0
- package/dist/{components/MediaRecorder/transcode → plugins/encoders}/mp3.js +3 -3
- package/dist/plugins/encoders/mp3.node.cjs +109 -0
- package/dist/plugins/encoders/mp3.node.cjs.map +7 -0
- package/dist/scss/v2/Autocomplete/Autocomplete-layout.scss +1 -1
- package/dist/scss/v2/Autocomplete/Autocomplete-theme.scss +4 -2
- package/dist/scss/v2/Avatar/Avatar-layout.scss +38 -22
- package/dist/scss/v2/Avatar/Avatar-theme.scss +5 -0
- package/dist/scss/v2/Channel/Channel-layout.scss +0 -4
- package/dist/scss/v2/ChannelList/ChannelList-layout.scss +0 -5
- package/dist/scss/v2/ChannelSearch/ChannelSearch-layout.scss +1 -0
- package/dist/scss/v2/ChatView/ChatView-layout.scss +43 -0
- package/dist/scss/v2/ChatView/ChatView-theme.scss +31 -0
- package/dist/scss/v2/EditMessageForm/EditMessageForm-theme.scss +9 -9
- package/dist/scss/v2/LoadingIndicator/LoadingIndicator-layout.scss +16 -0
- package/dist/scss/v2/Message/Message-layout.scss +39 -6
- package/dist/scss/v2/MessageList/MessageList-layout.scss +0 -6
- package/dist/scss/v2/MessageList/VirtualizedMessageList-layout.scss +0 -12
- package/dist/scss/v2/MessageReactions/MessageReactionsSelector-layout.scss +18 -0
- package/dist/scss/v2/MessageReactions/MessageReactionsSelector-theme.scss +5 -0
- package/dist/scss/v2/Thread/Thread-layout.scss +13 -4
- package/dist/scss/v2/ThreadList/ThreadList-layout.scss +149 -0
- package/dist/scss/v2/ThreadList/ThreadList-theme.scss +73 -0
- package/dist/scss/v2/UnreadCountBadge/UnreadCountBadge-layout.scss +49 -0
- package/dist/scss/v2/UnreadCountBadge/UnreadCountBadge-theme.scss +10 -0
- package/dist/scss/v2/_base.scss +1 -0
- package/dist/scss/v2/_emoji-replacement.scss +4 -2
- package/dist/scss/v2/index.layout.scss +3 -0
- package/dist/scss/v2/index.scss +3 -0
- package/package.json +51 -19
- package/dist/components/Emojis/index.cjs.js.map +0 -7
- package/dist/components/Emojis/index.d.ts +0 -1
- package/dist/components/Emojis/index.js +0 -1
- package/dist/components/MessageInput/AttachmentPreviewList/UploadPreviewItem.d.ts +0 -11
- package/dist/components/MessageInput/AttachmentPreviewList/UploadPreviewItem.js +0 -51
- package/dist/components/MessageInput/hooks/useFileUploads.d.ts +0 -7
- package/dist/components/MessageInput/hooks/useFileUploads.js +0 -85
- package/dist/components/MessageInput/hooks/useImageUploads.d.ts +0 -8
- package/dist/components/MessageInput/hooks/useImageUploads.js +0 -94
- package/dist/index.cjs.js.map +0 -7
- /package/dist/{components → plugins}/Emojis/EmojiPicker.d.ts +0 -0
- /package/dist/{components/MediaRecorder/transcode → plugins/encoders}/mp3.d.ts +0 -0
package/README.md
CHANGED
|
@@ -90,7 +90,7 @@ For components that implement significant logic, it's helpful to split the compo
|
|
|
90
90
|
|
|
91
91
|
### Customizing Styles
|
|
92
92
|
|
|
93
|
-
The preferred method for overriding the pre-defined styles in the library is to two
|
|
93
|
+
The preferred method for overriding the pre-defined styles in the library is to two-step process. First, import our bundled CSS into the file where you instantiate your chat application. Second, locate any Stream styles you want to override using either the browser inspector or by viewing the library code. You can then add selectors to your local CSS file to override our defaults. For example:
|
|
94
94
|
|
|
95
95
|
```js
|
|
96
96
|
import 'stream-chat-react/dist/css/v2/index.css';
|
|
@@ -110,3 +110,13 @@ We recently closed a [$38 million Series B funding round](https://techcrunch.com
|
|
|
110
110
|
Our APIs are used by more than a billion end-users, and by working at Stream, you have the chance to make a huge impact on a team of very strong engineers.
|
|
111
111
|
|
|
112
112
|
Check out our current openings and apply via [Stream's website](https://getstream.io/team/#jobs).
|
|
113
|
+
|
|
114
|
+
## Acknowledgements
|
|
115
|
+
|
|
116
|
+
### Lamejs
|
|
117
|
+
|
|
118
|
+
This project uses `lamejs` library under the LGPL license to convert the recorded audio to mp3 format.
|
|
119
|
+
The library source code is dynamically imported and used only if audio recording is enabled.
|
|
120
|
+
|
|
121
|
+
You can obtain the source code for `lamejs` from the [lamejs repository](https://github.com/gideonstele/lamejs) that is a fork of [the original JS library](https://github.com/zhuker/lamejs).
|
|
122
|
+
You can find the source code for LAME at https://lame.sourceforge.net and its license at: https://lame.sourceforge.net/license.txt
|
|
@@ -9,6 +9,8 @@ type WaveProgressBarProps = {
|
|
|
9
9
|
amplitudesCount?: number;
|
|
10
10
|
/** Progress expressed in fractional number value btw 0 and 100. */
|
|
11
11
|
progress?: number;
|
|
12
|
+
relativeAmplitudeBarWidth?: number;
|
|
13
|
+
relativeAmplitudeGap?: number;
|
|
12
14
|
};
|
|
13
|
-
export declare const WaveProgressBar: ({ amplitudesCount, progress, seek, waveformData, }: WaveProgressBarProps) => React.JSX.Element | null;
|
|
15
|
+
export declare const WaveProgressBar: ({ amplitudesCount, progress, relativeAmplitudeBarWidth, relativeAmplitudeGap, seek, waveformData, }: WaveProgressBarProps) => React.JSX.Element | null;
|
|
14
16
|
export {};
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import throttle from 'lodash.throttle';
|
|
2
|
+
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react';
|
|
2
3
|
import clsx from 'clsx';
|
|
3
4
|
import { resampleWaveformData } from '../audioSampling';
|
|
4
|
-
export const WaveProgressBar = ({ amplitudesCount = 40, progress = 0, seek, waveformData, }) => {
|
|
5
|
+
export const WaveProgressBar = ({ amplitudesCount = 40, progress = 0, relativeAmplitudeBarWidth = 2, relativeAmplitudeGap = 1, seek, waveformData, }) => {
|
|
5
6
|
const [progressIndicator, setProgressIndicator] = useState(null);
|
|
6
7
|
const isDragging = useRef(false);
|
|
7
|
-
const
|
|
8
|
+
const [root, setRoot] = useState(null);
|
|
9
|
+
const [trackAxisX, setTrackAxisX] = useState();
|
|
10
|
+
const lastRootWidth = useRef();
|
|
8
11
|
const handleDragStart = (e) => {
|
|
9
12
|
e.preventDefault();
|
|
10
13
|
if (!progressIndicator)
|
|
@@ -25,22 +28,54 @@ export const WaveProgressBar = ({ amplitudesCount = 40, progress = 0, seek, wave
|
|
|
25
28
|
isDragging.current = false;
|
|
26
29
|
progressIndicator.style.removeProperty('cursor');
|
|
27
30
|
}, [progressIndicator]);
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
const getTrackAxisX = useMemo(() => throttle((rootWidth) => {
|
|
32
|
+
if (rootWidth === lastRootWidth.current)
|
|
33
|
+
return;
|
|
34
|
+
lastRootWidth.current = rootWidth;
|
|
35
|
+
const possibleAmpCount = Math.floor(rootWidth / (relativeAmplitudeGap + relativeAmplitudeBarWidth));
|
|
36
|
+
const tooManyAmplitudesToRender = possibleAmpCount < amplitudesCount;
|
|
37
|
+
const barCount = tooManyAmplitudesToRender ? possibleAmpCount : amplitudesCount;
|
|
38
|
+
const amplitudeBarWidthToGapRatio = relativeAmplitudeBarWidth / (relativeAmplitudeBarWidth + relativeAmplitudeGap);
|
|
39
|
+
const barWidth = barCount && (rootWidth / barCount) * amplitudeBarWidthToGapRatio;
|
|
40
|
+
setTrackAxisX({
|
|
41
|
+
barCount,
|
|
42
|
+
barWidth,
|
|
43
|
+
gap: barWidth * (relativeAmplitudeGap / relativeAmplitudeBarWidth),
|
|
44
|
+
});
|
|
45
|
+
}, 1), [relativeAmplitudeBarWidth, relativeAmplitudeGap, amplitudesCount]);
|
|
46
|
+
const resampledWaveformData = useMemo(() => (trackAxisX ? resampleWaveformData(waveformData, trackAxisX.barCount) : []), [trackAxisX, waveformData]);
|
|
32
47
|
useEffect(() => {
|
|
33
48
|
document.addEventListener('pointerup', handleDragStop);
|
|
34
49
|
return () => {
|
|
35
50
|
document.removeEventListener('pointerup', handleDragStop);
|
|
36
51
|
};
|
|
37
52
|
}, [handleDragStop]);
|
|
38
|
-
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!root || typeof ResizeObserver === 'undefined')
|
|
55
|
+
return;
|
|
56
|
+
const observer = new ResizeObserver(([entry]) => {
|
|
57
|
+
getTrackAxisX(entry.contentRect.width);
|
|
58
|
+
});
|
|
59
|
+
observer.observe(root);
|
|
60
|
+
return () => {
|
|
61
|
+
observer.disconnect();
|
|
62
|
+
};
|
|
63
|
+
}, [getTrackAxisX, root]);
|
|
64
|
+
useLayoutEffect(() => {
|
|
65
|
+
if (!root)
|
|
66
|
+
return;
|
|
67
|
+
const { width: rootWidth } = root.getBoundingClientRect();
|
|
68
|
+
getTrackAxisX(rootWidth);
|
|
69
|
+
}, [getTrackAxisX, root]);
|
|
70
|
+
if (!waveformData.length || trackAxisX?.barCount === 0)
|
|
39
71
|
return null;
|
|
40
|
-
return (React.createElement("div", { className: 'str-chat__wave-progress-bar__track', "data-testid": 'wave-progress-bar-track', onClick: seek, onPointerDown: handleDragStart, onPointerMove: handleDrag, onPointerUp: handleDragStop, ref:
|
|
72
|
+
return (React.createElement("div", { className: 'str-chat__wave-progress-bar__track', "data-testid": 'wave-progress-bar-track', onClick: seek, onPointerDown: handleDragStart, onPointerMove: handleDrag, onPointerUp: handleDragStop, ref: setRoot, role: 'progressbar', style: {
|
|
73
|
+
'--str-chat__voice-recording-amplitude-bar-gap-width': trackAxisX?.gap + 'px',
|
|
74
|
+
} },
|
|
41
75
|
resampledWaveformData.map((amplitude, i) => (React.createElement("div", { className: clsx('str-chat__wave-progress-bar__amplitude-bar', {
|
|
42
76
|
['str-chat__wave-progress-bar__amplitude-bar--active']: progress > (i / resampledWaveformData.length) * 100,
|
|
43
77
|
}), "data-testid": 'amplitude-bar', key: `amplitude-${i}`, style: {
|
|
78
|
+
'--str-chat__voice-recording-amplitude-bar-width': trackAxisX?.barWidth + 'px',
|
|
44
79
|
'--str-chat__wave-progress-bar__amplitude-bar-height': amplitude
|
|
45
80
|
? amplitude * 100 + '%'
|
|
46
81
|
: '0%',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import clsx from 'clsx';
|
|
2
2
|
import React, { useEffect, useState } from 'react';
|
|
3
|
+
import { Icon } from '../Threads/icons';
|
|
3
4
|
import { getWholeChar } from '../../utils';
|
|
4
5
|
/**
|
|
5
6
|
* A round avatar image with fallback to username's first letter
|
|
@@ -15,6 +16,9 @@ export const Avatar = (props) => {
|
|
|
15
16
|
const showImage = image && !error;
|
|
16
17
|
return (React.createElement("div", { className: clsx(`str-chat__avatar str-chat__message-sender-avatar`, className, {
|
|
17
18
|
['str-chat__avatar--multiple-letters']: initials.length > 1,
|
|
19
|
+
['str-chat__avatar--no-letters']: !initials.length,
|
|
18
20
|
['str-chat__avatar--one-letter']: initials.length === 1,
|
|
19
|
-
}), "data-testid": 'avatar', onClick: onClick, onMouseOver: onMouseOver, title: name }, showImage ? (React.createElement("img", { alt: initials, className:
|
|
21
|
+
}), "data-testid": 'avatar', onClick: onClick, onMouseOver: onMouseOver, role: 'button', title: name }, showImage ? (React.createElement("img", { alt: initials, className: 'str-chat__avatar-image', "data-testid": 'avatar-img', onError: () => setError(true), src: image })) : (React.createElement(React.Fragment, null,
|
|
22
|
+
!!initials.length && (React.createElement("div", { className: clsx('str-chat__avatar-fallback'), "data-testid": 'avatar-fallback' }, initials)),
|
|
23
|
+
!initials.length && React.createElement(Icon.User, null)))));
|
|
20
24
|
};
|
|
@@ -2,11 +2,10 @@ import React, { PropsWithChildren } from 'react';
|
|
|
2
2
|
import { ChannelQueryOptions, EventAPIResponse, Message, MessageResponse, Channel as StreamChannel, StreamChat, UpdatedMessage } from 'stream-chat';
|
|
3
3
|
import { OnMentionAction } from './hooks/useMentionsHandlers';
|
|
4
4
|
import { LoadingErrorIndicatorProps } from '../Loading';
|
|
5
|
-
import { StreamMessage } from '../../context
|
|
6
|
-
import { ComponentContextValue } from '../../context/ComponentContext';
|
|
5
|
+
import { ComponentContextValue, StreamMessage } from '../../context';
|
|
7
6
|
import type { UnreadMessagesNotificationProps } from '../MessageList';
|
|
8
|
-
import type { MessageProps } from '../Message
|
|
9
|
-
import type { MessageInputProps } from '../MessageInput
|
|
7
|
+
import type { MessageProps } from '../Message';
|
|
8
|
+
import type { MessageInputProps } from '../MessageInput';
|
|
10
9
|
import type { ChannelUnreadUiState, CustomTrigger, DefaultStreamChatGenerics, GiphyVersions, ImageAttachmentSizeHandler, SendMessageOptions, UpdateMessageOptions, VideoAttachmentSizeHandler } from '../../types/types';
|
|
11
10
|
import type { URLEnrichmentConfig } from '../MessageInput/hooks/useLinkPreviews';
|
|
12
11
|
import { ReactionOptions } from '../Reactions';
|
|
@@ -10,26 +10,17 @@ import { useCreateTypingContext } from './hooks/useCreateTypingContext';
|
|
|
10
10
|
import { useEditMessageHandler } from './hooks/useEditMessageHandler';
|
|
11
11
|
import { useIsMounted } from './hooks/useIsMounted';
|
|
12
12
|
import { useMentionsHandlers } from './hooks/useMentionsHandlers';
|
|
13
|
-
import { Attachment as DefaultAttachment } from '../Attachment/Attachment';
|
|
14
13
|
import { LoadingErrorIndicator as DefaultLoadingErrorIndicator, } from '../Loading';
|
|
15
14
|
import { LoadingChannel as DefaultLoadingIndicator } from './LoadingChannel';
|
|
16
|
-
import { MessageSimple } from '../Message/MessageSimple';
|
|
17
15
|
import { DropzoneProvider } from '../MessageInput/DropzoneProvider';
|
|
18
|
-
import { ChannelActionProvider, } from '../../context
|
|
19
|
-
import { ChannelStateProvider, } from '../../context/ChannelStateContext';
|
|
20
|
-
import { ComponentProvider } from '../../context/ComponentContext';
|
|
21
|
-
import { useChatContext } from '../../context/ChatContext';
|
|
22
|
-
import { useTranslationContext } from '../../context/TranslationContext';
|
|
23
|
-
import { TypingProvider } from '../../context/TypingContext';
|
|
16
|
+
import { ChannelActionProvider, ChannelStateProvider, TypingProvider, useChatContext, useTranslationContext, WithComponents, } from '../../context';
|
|
24
17
|
import { DEFAULT_HIGHLIGHT_DURATION, DEFAULT_INITIAL_CHANNEL_PAGE_SIZE, DEFAULT_JUMP_TO_PAGE_SIZE, DEFAULT_NEXT_CHANNEL_PAGE_SIZE, DEFAULT_THREAD_PAGE_SIZE, } from '../../constants/limits';
|
|
25
|
-
import { hasMoreMessagesProbably
|
|
18
|
+
import { hasMoreMessagesProbably } from '../MessageList';
|
|
26
19
|
import { useChannelContainerClasses } from './hooks/useChannelContainerClasses';
|
|
27
20
|
import { findInMsgSetByDate, findInMsgSetById, makeAddNotifications } from './utils';
|
|
28
21
|
import { getChannel } from '../../utils';
|
|
29
22
|
import { getImageAttachmentConfiguration, getVideoAttachmentConfiguration, } from '../Attachment/attachment-sizing';
|
|
30
|
-
import {
|
|
31
|
-
import { EventComponent } from '../EventComponent';
|
|
32
|
-
import { DateSeparator } from '../DateSeparator';
|
|
23
|
+
import { useThreadContext } from '../Threads';
|
|
33
24
|
const isUserResponseArray = (output) => output[0]?.id != null;
|
|
34
25
|
const UnMemoizedChannel = (props) => {
|
|
35
26
|
const { channel: propsChannel, EmptyPlaceholder = null, LoadingErrorIndicator, LoadingIndicator = DefaultLoadingIndicator, } = props;
|
|
@@ -60,6 +51,7 @@ const ChannelInner = (props) => {
|
|
|
60
51
|
const { client, customClasses, latestMessageDatesByChannels, mutes, theme, } = useChatContext('Channel');
|
|
61
52
|
const { t } = useTranslationContext('Channel');
|
|
62
53
|
const { channelClass, chatClass, chatContainerClass, windowsEmojiClass, } = useChannelContainerClasses({ customClasses });
|
|
54
|
+
const thread = useThreadContext();
|
|
63
55
|
const [channelConfig, setChannelConfig] = useState(channel.getConfig());
|
|
64
56
|
const [notifications, setNotifications] = useState([]);
|
|
65
57
|
const [quotedMessage, setQuotedMessage] = useState();
|
|
@@ -68,7 +60,11 @@ const ChannelInner = (props) => {
|
|
|
68
60
|
const [state, dispatch] = useReducer(channelReducer,
|
|
69
61
|
// channel.initialized === false if client.channel().query() was not called, e.g. ChannelList is not used
|
|
70
62
|
// => Channel will call channel.watch() in useLayoutEffect => state.loading is used to signal the watch() call state
|
|
71
|
-
{
|
|
63
|
+
{
|
|
64
|
+
...initialState,
|
|
65
|
+
hasMore: channel.state.messagePagination.hasPrev,
|
|
66
|
+
loading: !channel.initialized,
|
|
67
|
+
});
|
|
72
68
|
const isMounted = useIsMounted();
|
|
73
69
|
const originalTitle = useRef('');
|
|
74
70
|
const lastRead = useRef();
|
|
@@ -184,7 +180,6 @@ const ChannelInner = (props) => {
|
|
|
184
180
|
useLayoutEffect(() => {
|
|
185
181
|
let errored = false;
|
|
186
182
|
let done = false;
|
|
187
|
-
let channelInitializedExternally = true;
|
|
188
183
|
(async () => {
|
|
189
184
|
if (!channel.initialized && initializeOnMount) {
|
|
190
185
|
try {
|
|
@@ -210,7 +205,6 @@ const ChannelInner = (props) => {
|
|
|
210
205
|
await getChannel({ channel, client, members, options: channelQueryOptions });
|
|
211
206
|
const config = channel.getConfig();
|
|
212
207
|
setChannelConfig(config);
|
|
213
|
-
channelInitializedExternally = false;
|
|
214
208
|
}
|
|
215
209
|
catch (e) {
|
|
216
210
|
dispatch({ error: e, type: 'setError' });
|
|
@@ -222,8 +216,7 @@ const ChannelInner = (props) => {
|
|
|
222
216
|
if (!errored) {
|
|
223
217
|
dispatch({
|
|
224
218
|
channel,
|
|
225
|
-
hasMore:
|
|
226
|
-
hasMoreMessagesProbably(channel.state.messages.length, channelQueryOptions.messages.limit),
|
|
219
|
+
hasMore: channel.state.messagePagination.hasPrev,
|
|
227
220
|
type: 'initStateFromChannel',
|
|
228
221
|
});
|
|
229
222
|
if (client.user?.id && channel.state.read[client.user.id]) {
|
|
@@ -283,7 +276,7 @@ const ChannelInner = (props) => {
|
|
|
283
276
|
dispatch({ hasMore, messages, type: 'loadMoreFinished' });
|
|
284
277
|
}, 2000, { leading: true, trailing: true }), []);
|
|
285
278
|
const loadMore = async (limit = DEFAULT_NEXT_CHANNEL_PAGE_SIZE) => {
|
|
286
|
-
if (!online.current || !window.navigator.onLine || !state.
|
|
279
|
+
if (!online.current || !window.navigator.onLine || !channel.state.messagePagination.hasPrev)
|
|
287
280
|
return 0;
|
|
288
281
|
// prevent duplicate loading events...
|
|
289
282
|
const oldestMessage = state?.messages?.[0];
|
|
@@ -305,12 +298,11 @@ const ChannelInner = (props) => {
|
|
|
305
298
|
dispatch({ loadingMore: false, type: 'setLoadingMore' });
|
|
306
299
|
return 0;
|
|
307
300
|
}
|
|
308
|
-
|
|
309
|
-
loadMoreFinished(hasMoreMessages, channel.state.messages);
|
|
301
|
+
loadMoreFinished(channel.state.messagePagination.hasPrev, channel.state.messages);
|
|
310
302
|
return queryResponse.messages.length;
|
|
311
303
|
};
|
|
312
304
|
const loadMoreNewer = async (limit = DEFAULT_NEXT_CHANNEL_PAGE_SIZE) => {
|
|
313
|
-
if (!online.current || !window.navigator.onLine || !state.
|
|
305
|
+
if (!online.current || !window.navigator.onLine || !channel.state.messagePagination.hasNext)
|
|
314
306
|
return 0;
|
|
315
307
|
const newestMessage = state?.messages?.[state?.messages?.length - 1];
|
|
316
308
|
if (state.loadingMore || state.loadingMoreNewer)
|
|
@@ -330,9 +322,8 @@ const ChannelInner = (props) => {
|
|
|
330
322
|
dispatch({ loadingMoreNewer: false, type: 'setLoadingMoreNewer' });
|
|
331
323
|
return 0;
|
|
332
324
|
}
|
|
333
|
-
const hasMoreNewerMessages = channel.state.messages !== channel.state.latestMessages;
|
|
334
325
|
dispatch({
|
|
335
|
-
hasMoreNewer:
|
|
326
|
+
hasMoreNewer: channel.state.messagePagination.hasNext,
|
|
336
327
|
messages: channel.state.messages,
|
|
337
328
|
type: 'loadMoreNewerFinished',
|
|
338
329
|
});
|
|
@@ -342,15 +333,9 @@ const ChannelInner = (props) => {
|
|
|
342
333
|
const jumpToMessage = useCallback(async (messageId, messageLimit = DEFAULT_JUMP_TO_PAGE_SIZE, highlightDuration = DEFAULT_HIGHLIGHT_DURATION) => {
|
|
343
334
|
dispatch({ loadingMore: true, type: 'setLoadingMore' });
|
|
344
335
|
await channel.state.loadMessageIntoState(messageId, undefined, messageLimit);
|
|
345
|
-
|
|
346
|
-
* if the message we are jumping to has less than half of the page size older messages,
|
|
347
|
-
* we have jumped to the beginning of the channel.
|
|
348
|
-
*/
|
|
349
|
-
const indexOfMessage = channel.state.messages.findIndex((message) => message.id === messageId);
|
|
350
|
-
const hasMoreMessages = indexOfMessage >= Math.floor(messageLimit / 2);
|
|
351
|
-
loadMoreFinished(hasMoreMessages, channel.state.messages);
|
|
336
|
+
loadMoreFinished(channel.state.messagePagination.hasPrev, channel.state.messages);
|
|
352
337
|
dispatch({
|
|
353
|
-
hasMoreNewer: channel.state.
|
|
338
|
+
hasMoreNewer: channel.state.messagePagination.hasNext,
|
|
354
339
|
highlightedMessageId: messageId,
|
|
355
340
|
type: 'jumpToMessageFinished',
|
|
356
341
|
});
|
|
@@ -364,9 +349,7 @@ const ChannelInner = (props) => {
|
|
|
364
349
|
}, [channel, loadMoreFinished]);
|
|
365
350
|
const jumpToLatestMessage = useCallback(async () => {
|
|
366
351
|
await channel.state.loadMessageIntoState('latest');
|
|
367
|
-
|
|
368
|
-
const hasMoreOlder = channel.state.messages.length >= 25;
|
|
369
|
-
loadMoreFinished(hasMoreOlder, channel.state.messages);
|
|
352
|
+
loadMoreFinished(channel.state.messagePagination.hasPrev, channel.state.messages);
|
|
370
353
|
dispatch({
|
|
371
354
|
type: 'jumpToLatestMessage',
|
|
372
355
|
});
|
|
@@ -377,7 +360,6 @@ const ChannelInner = (props) => {
|
|
|
377
360
|
let lastReadMessageId = channelUnreadUiState?.last_read_message_id;
|
|
378
361
|
let firstUnreadMessageId = channelUnreadUiState?.first_unread_message_id;
|
|
379
362
|
let isInCurrentMessageSet = false;
|
|
380
|
-
let hasMoreMessages = true;
|
|
381
363
|
if (firstUnreadMessageId) {
|
|
382
364
|
const result = findInMsgSetById(firstUnreadMessageId, channel.state.messages);
|
|
383
365
|
isInCurrentMessageSet = result.index !== -1;
|
|
@@ -409,27 +391,25 @@ const ChannelInner = (props) => {
|
|
|
409
391
|
}
|
|
410
392
|
catch (e) {
|
|
411
393
|
addNotification(t('Failed to jump to the first unread message'), 'error');
|
|
412
|
-
loadMoreFinished(
|
|
394
|
+
loadMoreFinished(channel.state.messagePagination.hasPrev, channel.state.messages);
|
|
413
395
|
return;
|
|
414
396
|
}
|
|
415
397
|
const firstMessageWithCreationDate = messages.find((msg) => msg.created_at);
|
|
416
398
|
if (!firstMessageWithCreationDate) {
|
|
417
399
|
addNotification(t('Failed to jump to the first unread message'), 'error');
|
|
418
|
-
loadMoreFinished(
|
|
400
|
+
loadMoreFinished(channel.state.messagePagination.hasPrev, channel.state.messages);
|
|
419
401
|
return;
|
|
420
402
|
}
|
|
421
403
|
const firstMessageTimestamp = new Date(firstMessageWithCreationDate.created_at).getTime();
|
|
422
404
|
if (lastReadTimestamp < firstMessageTimestamp) {
|
|
423
405
|
// whole channel is unread
|
|
424
406
|
firstUnreadMessageId = firstMessageWithCreationDate.id;
|
|
425
|
-
hasMoreMessages = false;
|
|
426
407
|
}
|
|
427
408
|
else {
|
|
428
409
|
const result = findInMsgSetByDate(channelUnreadUiState.last_read, messages);
|
|
429
410
|
lastReadMessageId = result.target?.id;
|
|
430
|
-
hasMoreMessages = result.index >= Math.floor(queryMessageLimit / 2);
|
|
431
411
|
}
|
|
432
|
-
loadMoreFinished(
|
|
412
|
+
loadMoreFinished(channel.state.messagePagination.hasPrev, channel.state.messages);
|
|
433
413
|
}
|
|
434
414
|
}
|
|
435
415
|
if (!firstUnreadMessageId && !lastReadMessageId) {
|
|
@@ -446,14 +426,13 @@ const ChannelInner = (props) => {
|
|
|
446
426
|
* we have arrived to the oldest page of the channel
|
|
447
427
|
*/
|
|
448
428
|
const indexOfTarget = channel.state.messages.findIndex((message) => message.id === targetId);
|
|
449
|
-
|
|
450
|
-
loadMoreFinished(hasMoreMessages, channel.state.messages);
|
|
429
|
+
loadMoreFinished(channel.state.messagePagination.hasPrev, channel.state.messages);
|
|
451
430
|
firstUnreadMessageId =
|
|
452
431
|
firstUnreadMessageId ?? channel.state.messages[indexOfTarget + 1]?.id;
|
|
453
432
|
}
|
|
454
433
|
catch (e) {
|
|
455
434
|
addNotification(t('Failed to jump to the first unread message'), 'error');
|
|
456
|
-
loadMoreFinished(
|
|
435
|
+
loadMoreFinished(channel.state.messagePagination.hasPrev, channel.state.messages);
|
|
457
436
|
return;
|
|
458
437
|
}
|
|
459
438
|
}
|
|
@@ -468,7 +447,7 @@ const ChannelInner = (props) => {
|
|
|
468
447
|
last_read_message_id: lastReadMessageId,
|
|
469
448
|
});
|
|
470
449
|
dispatch({
|
|
471
|
-
hasMoreNewer: channel.state.
|
|
450
|
+
hasMoreNewer: channel.state.messagePagination.hasNext,
|
|
472
451
|
highlightedMessageId: firstUnreadMessageId,
|
|
473
452
|
type: 'jumpToMessageFinished',
|
|
474
453
|
});
|
|
@@ -578,25 +557,37 @@ const ChannelInner = (props) => {
|
|
|
578
557
|
errorStatusCode: parsedError.status || undefined,
|
|
579
558
|
status: 'failed',
|
|
580
559
|
});
|
|
560
|
+
thread?.upsertReplyLocally({
|
|
561
|
+
// @ts-expect-error
|
|
562
|
+
message: {
|
|
563
|
+
...message,
|
|
564
|
+
error: parsedError,
|
|
565
|
+
errorStatusCode: parsedError.status || undefined,
|
|
566
|
+
status: 'failed',
|
|
567
|
+
},
|
|
568
|
+
});
|
|
581
569
|
}
|
|
582
570
|
}
|
|
583
571
|
};
|
|
584
572
|
const sendMessage = async ({ attachments = [], mentioned_users = [], parent, text = '', }, customMessageData, options) => {
|
|
585
573
|
channel.state.filterErrorMessages();
|
|
586
574
|
const messagePreview = {
|
|
587
|
-
__html: text,
|
|
588
575
|
attachments,
|
|
589
576
|
created_at: new Date(),
|
|
590
577
|
html: text,
|
|
591
578
|
id: customMessageData?.id ?? `${client.userID}-${nanoid()}`,
|
|
592
579
|
mentioned_users,
|
|
580
|
+
parent_id: parent?.id,
|
|
593
581
|
reactions: [],
|
|
594
582
|
status: 'sending',
|
|
595
583
|
text,
|
|
596
584
|
type: 'regular',
|
|
597
585
|
user: client.user,
|
|
598
|
-
...(parent?.id ? { parent_id: parent.id } : null),
|
|
599
586
|
};
|
|
587
|
+
thread?.upsertReplyLocally({
|
|
588
|
+
// @ts-expect-error
|
|
589
|
+
message: messagePreview,
|
|
590
|
+
});
|
|
600
591
|
updateMessage(messagePreview);
|
|
601
592
|
await doSendMessage(messagePreview, customMessageData, options);
|
|
602
593
|
};
|
|
@@ -735,8 +726,9 @@ const ChannelInner = (props) => {
|
|
|
735
726
|
jumpToLatestMessage,
|
|
736
727
|
setChannelUnreadUiState,
|
|
737
728
|
]);
|
|
729
|
+
// @ts-expect-error
|
|
738
730
|
const componentContextValue = useMemo(() => ({
|
|
739
|
-
Attachment: props.Attachment
|
|
731
|
+
Attachment: props.Attachment,
|
|
740
732
|
AttachmentPreviewList: props.AttachmentPreviewList,
|
|
741
733
|
AudioRecorder: props.AudioRecorder,
|
|
742
734
|
AutocompleteSuggestionItem: props.AutocompleteSuggestionItem,
|
|
@@ -745,7 +737,7 @@ const ChannelInner = (props) => {
|
|
|
745
737
|
BaseImage: props.BaseImage,
|
|
746
738
|
CooldownTimer: props.CooldownTimer,
|
|
747
739
|
CustomMessageActionsList: props.CustomMessageActionsList,
|
|
748
|
-
DateSeparator: props.DateSeparator
|
|
740
|
+
DateSeparator: props.DateSeparator,
|
|
749
741
|
EditMessageInput: props.EditMessageInput,
|
|
750
742
|
EmojiPicker: props.EmojiPicker,
|
|
751
743
|
emojiSearchIndex: props.emojiSearchIndex,
|
|
@@ -756,7 +748,7 @@ const ChannelInner = (props) => {
|
|
|
756
748
|
Input: props.Input,
|
|
757
749
|
LinkPreviewList: props.LinkPreviewList,
|
|
758
750
|
LoadingIndicator: props.LoadingIndicator,
|
|
759
|
-
Message: props.Message
|
|
751
|
+
Message: props.Message,
|
|
760
752
|
MessageBouncePrompt: props.MessageBouncePrompt,
|
|
761
753
|
MessageDeleted: props.MessageDeleted,
|
|
762
754
|
MessageListNotifications: props.MessageListNotifications,
|
|
@@ -764,13 +756,13 @@ const ChannelInner = (props) => {
|
|
|
764
756
|
MessageOptions: props.MessageOptions,
|
|
765
757
|
MessageRepliesCountButton: props.MessageRepliesCountButton,
|
|
766
758
|
MessageStatus: props.MessageStatus,
|
|
767
|
-
MessageSystem: props.MessageSystem
|
|
759
|
+
MessageSystem: props.MessageSystem,
|
|
768
760
|
MessageTimestamp: props.MessageTimestamp,
|
|
769
761
|
ModalGallery: props.ModalGallery,
|
|
770
762
|
PinIndicator: props.PinIndicator,
|
|
771
763
|
QuotedMessage: props.QuotedMessage,
|
|
772
764
|
QuotedMessagePreview: props.QuotedMessagePreview,
|
|
773
|
-
reactionOptions: props.reactionOptions
|
|
765
|
+
reactionOptions: props.reactionOptions,
|
|
774
766
|
ReactionSelector: props.ReactionSelector,
|
|
775
767
|
ReactionsList: props.ReactionsList,
|
|
776
768
|
SendButton: props.SendButton,
|
|
@@ -782,11 +774,58 @@ const ChannelInner = (props) => {
|
|
|
782
774
|
TriggerProvider: props.TriggerProvider,
|
|
783
775
|
TypingIndicator: props.TypingIndicator,
|
|
784
776
|
UnreadMessagesNotification: props.UnreadMessagesNotification,
|
|
785
|
-
UnreadMessagesSeparator: props.UnreadMessagesSeparator
|
|
777
|
+
UnreadMessagesSeparator: props.UnreadMessagesSeparator,
|
|
786
778
|
VirtualMessage: props.VirtualMessage,
|
|
787
|
-
}),
|
|
788
|
-
|
|
789
|
-
|
|
779
|
+
}), [
|
|
780
|
+
props.Attachment,
|
|
781
|
+
props.AttachmentPreviewList,
|
|
782
|
+
props.AudioRecorder,
|
|
783
|
+
props.AutocompleteSuggestionItem,
|
|
784
|
+
props.AutocompleteSuggestionList,
|
|
785
|
+
props.Avatar,
|
|
786
|
+
props.BaseImage,
|
|
787
|
+
props.CooldownTimer,
|
|
788
|
+
props.CustomMessageActionsList,
|
|
789
|
+
props.DateSeparator,
|
|
790
|
+
props.EditMessageInput,
|
|
791
|
+
props.EmojiPicker,
|
|
792
|
+
props.EmptyStateIndicator,
|
|
793
|
+
props.FileUploadIcon,
|
|
794
|
+
props.GiphyPreviewMessage,
|
|
795
|
+
props.HeaderComponent,
|
|
796
|
+
props.Input,
|
|
797
|
+
props.LinkPreviewList,
|
|
798
|
+
props.LoadingIndicator,
|
|
799
|
+
props.Message,
|
|
800
|
+
props.MessageBouncePrompt,
|
|
801
|
+
props.MessageDeleted,
|
|
802
|
+
props.MessageListNotifications,
|
|
803
|
+
props.MessageNotification,
|
|
804
|
+
props.MessageOptions,
|
|
805
|
+
props.MessageRepliesCountButton,
|
|
806
|
+
props.MessageStatus,
|
|
807
|
+
props.MessageSystem,
|
|
808
|
+
props.MessageTimestamp,
|
|
809
|
+
props.ModalGallery,
|
|
810
|
+
props.PinIndicator,
|
|
811
|
+
props.QuotedMessage,
|
|
812
|
+
props.QuotedMessagePreview,
|
|
813
|
+
props.ReactionSelector,
|
|
814
|
+
props.ReactionsList,
|
|
815
|
+
props.SendButton,
|
|
816
|
+
props.StartRecordingAudioButton,
|
|
817
|
+
props.ThreadHead,
|
|
818
|
+
props.ThreadHeader,
|
|
819
|
+
props.ThreadStart,
|
|
820
|
+
props.Timestamp,
|
|
821
|
+
props.TriggerProvider,
|
|
822
|
+
props.TypingIndicator,
|
|
823
|
+
props.UnreadMessagesNotification,
|
|
824
|
+
props.UnreadMessagesSeparator,
|
|
825
|
+
props.VirtualMessage,
|
|
826
|
+
props.emojiSearchIndex,
|
|
827
|
+
props.reactionOptions,
|
|
828
|
+
]);
|
|
790
829
|
const typingContextValue = useCreateTypingContext({
|
|
791
830
|
typing,
|
|
792
831
|
});
|
|
@@ -806,7 +845,7 @@ const ChannelInner = (props) => {
|
|
|
806
845
|
return (React.createElement("div", { className: clsx(className, windowsEmojiClass) },
|
|
807
846
|
React.createElement(ChannelStateProvider, { value: channelStateContextValue },
|
|
808
847
|
React.createElement(ChannelActionProvider, { value: channelActionContextValue },
|
|
809
|
-
React.createElement(
|
|
848
|
+
React.createElement(WithComponents, { overrides: componentContextValue },
|
|
810
849
|
React.createElement(TypingProvider, { value: typingContextValue },
|
|
811
850
|
React.createElement("div", { className: `${chatContainerClass}` },
|
|
812
851
|
dragAndDropWindow && (React.createElement(DropzoneProvider, { ...optionalMessageInputProps }, children)),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
|
-
import { isDate, isDayOrMoment } from '../../../
|
|
2
|
+
import { isDate, isDayOrMoment } from '../../../i18n';
|
|
3
3
|
export const useCreateChannelStateContext = (value) => {
|
|
4
4
|
const { acceptedFiles, channel, channelCapabilitiesArray = [], channelConfig, debounceURLEnrichmentMs, dragAndDropWindow, enrichURLForPreview, giphyVersion, error, findURLFn, hasMore, hasMoreNewer, imageAttachmentSizeHandler, suppressAutoscroll, highlightedMessageId, loading, loadingMore, maxNumberOfFiles, members, messages = [], multipleUploads, mutes, notifications, onLinkPreviewDismissed, pinnedMessages, quotedMessage, read = {}, shouldGenerateVideoThumbnail, skipMessageDataMemoization, thread, threadHasMore, threadLoadingMore, threadMessages = [], channelUnreadUiState, videoAttachmentSizeHandler, watcherCount, watcher_count, watchers, } = value;
|
|
5
5
|
const channelId = channel.cid;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { PropsWithChildren } from 'react';
|
|
2
2
|
import { CustomClasses } from '../../context/ChatContext';
|
|
3
|
-
import { SupportedTranslations } from '../../context/TranslationContext';
|
|
4
3
|
import type { StreamChat } from 'stream-chat';
|
|
4
|
+
import type { SupportedTranslations } from '../../i18n/types';
|
|
5
5
|
import type { Streami18n } from '../../i18n/Streami18n';
|
|
6
6
|
import type { DefaultStreamChatGenerics } from '../../types/types';
|
|
7
7
|
export type ChatProps<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> = {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Streami18n } from '../../../i18n';
|
|
1
|
+
import { TranslationContextValue } from '../../../context/TranslationContext';
|
|
2
|
+
import { Streami18n, SupportedTranslations } from '../../../i18n';
|
|
3
3
|
import type { AppSettingsAPIResponse, Channel, Mute, StreamChat } from 'stream-chat';
|
|
4
4
|
import type { DefaultStreamChatGenerics } from '../../../types/types';
|
|
5
5
|
export type UseChatParams<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> = {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
-
import { defaultDateTimeParser, isLanguageSupported, } from '../../../
|
|
3
|
-
import { Streami18n } from '../../../i18n';
|
|
2
|
+
import { defaultDateTimeParser, isLanguageSupported, Streami18n, } from '../../../i18n';
|
|
4
3
|
import { version } from '../../../version';
|
|
5
4
|
export const useChat = ({ client, defaultLanguage = 'en', i18nInstance, initialNavOpen, }) => {
|
|
6
5
|
const [translators, setTranslators] = useState({
|
|
@@ -24,13 +23,17 @@ export const useChat = ({ client, defaultLanguage = 'en', i18nInstance, initialN
|
|
|
24
23
|
return appSettings.current;
|
|
25
24
|
};
|
|
26
25
|
useEffect(() => {
|
|
27
|
-
if (client)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
26
|
+
if (!client)
|
|
27
|
+
return;
|
|
28
|
+
const userAgent = client.getUserAgent();
|
|
29
|
+
if (!userAgent.includes('stream-chat-react')) {
|
|
30
|
+
// result looks like: 'stream-chat-react-2.3.2-stream-chat-javascript-client-browser-2.2.2'
|
|
31
|
+
client.setUserAgent(`stream-chat-react-${version}-${userAgent}`);
|
|
33
32
|
}
|
|
33
|
+
client.threads.registerSubscriptions();
|
|
34
|
+
return () => {
|
|
35
|
+
client.threads.unregisterSubscriptions();
|
|
36
|
+
};
|
|
34
37
|
}, [client]);
|
|
35
38
|
useEffect(() => {
|
|
36
39
|
setMutes(clientMutes);
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { StreamChat } from 'stream-chat';
|
|
2
|
+
import type { DefaultGenerics, ExtendableGenerics, OwnUserResponse, StreamChatOptions, TokenOrProvider, UserResponse } from 'stream-chat';
|
|
2
3
|
/**
|
|
3
4
|
* React hook to create, connect and return `StreamChat` client.
|
|
4
5
|
*/
|
|
5
|
-
export declare const useCreateChatClient: <SCG extends ExtendableGenerics = DefaultGenerics>({ apiKey, tokenOrProvider, userData, }: {
|
|
6
|
+
export declare const useCreateChatClient: <SCG extends ExtendableGenerics = DefaultGenerics>({ apiKey, options, tokenOrProvider, userData, }: {
|
|
6
7
|
apiKey: string;
|
|
7
8
|
tokenOrProvider: TokenOrProvider;
|
|
8
9
|
userData: OwnUserResponse<SCG> | UserResponse<SCG>;
|
|
10
|
+
options?: StreamChatOptions;
|
|
9
11
|
}) => StreamChat<SCG> | null;
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { useEffect, useState } from 'react';
|
|
2
|
-
import { StreamChat
|
|
2
|
+
import { StreamChat } from 'stream-chat';
|
|
3
3
|
/**
|
|
4
4
|
* React hook to create, connect and return `StreamChat` client.
|
|
5
5
|
*/
|
|
6
|
-
export const useCreateChatClient = ({ apiKey, tokenOrProvider, userData, }) => {
|
|
6
|
+
export const useCreateChatClient = ({ apiKey, options, tokenOrProvider, userData, }) => {
|
|
7
7
|
const [chatClient, setChatClient] = useState(null);
|
|
8
8
|
const [cachedUserData, setCachedUserData] = useState(userData);
|
|
9
9
|
if (userData.id !== cachedUserData.id) {
|
|
10
10
|
setCachedUserData(userData);
|
|
11
11
|
}
|
|
12
|
+
const [cachedOptions] = useState(options);
|
|
12
13
|
useEffect(() => {
|
|
13
|
-
const client = new StreamChat(apiKey);
|
|
14
|
+
const client = new StreamChat(apiKey, undefined, cachedOptions);
|
|
14
15
|
let didUserConnectInterrupt = false;
|
|
15
16
|
const connectionPromise = client.connectUser(cachedUserData, tokenOrProvider).then(() => {
|
|
16
17
|
if (!didUserConnectInterrupt)
|
|
@@ -25,6 +26,6 @@ export const useCreateChatClient = ({ apiKey, tokenOrProvider, userData, }) => {
|
|
|
25
26
|
console.log(`Connection for user "${cachedUserData.id}" has been closed`);
|
|
26
27
|
});
|
|
27
28
|
};
|
|
28
|
-
}, [apiKey, cachedUserData, tokenOrProvider]);
|
|
29
|
+
}, [apiKey, cachedUserData, cachedOptions, tokenOrProvider]);
|
|
29
30
|
return chatClient;
|
|
30
31
|
};
|