stream-chat-react 12.9.0 → 12.11.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.
- package/dist/components/Attachment/Attachment.js +2 -1
- package/dist/components/Attachment/AttachmentContainer.d.ts +1 -1
- package/dist/components/Attachment/AttachmentContainer.js +2 -2
- package/dist/components/Attachment/Card.js +3 -3
- package/dist/components/Attachment/VoiceRecording.d.ts +1 -1
- package/dist/components/Attachment/VoiceRecording.js +2 -2
- package/dist/components/Attachment/attachment-sizing.js +2 -1
- package/dist/components/Attachment/components/FileSizeIndicator.d.ts +1 -1
- package/dist/components/Attachment/components/FileSizeIndicator.js +1 -1
- package/dist/components/Attachment/components/WaveProgressBar.js +1 -1
- package/dist/components/Attachment/hooks/useAudioController.d.ts +1 -1
- package/dist/components/Attachment/hooks/useAudioController.js +4 -2
- package/dist/components/Attachment/utils.d.ts +1 -1
- package/dist/components/Attachment/utils.js +12 -3
- package/dist/components/AutoCompleteTextarea/List.js +3 -2
- package/dist/components/AutoCompleteTextarea/Textarea.js +3 -7
- package/dist/components/AutoCompleteTextarea/utils.js +3 -7
- package/dist/components/Avatar/ChannelAvatar.js +1 -1
- package/dist/components/Channel/Channel.d.ts +1 -1
- package/dist/components/Channel/Channel.js +30 -14
- package/dist/components/Channel/channelState.d.ts +1 -3
- package/dist/components/Channel/channelState.js +10 -4
- package/dist/components/Channel/hooks/useCreateChannelStateContext.js +5 -3
- package/dist/components/Channel/hooks/useIsMounted.d.ts +1 -1
- package/dist/components/Channel/hooks/useMentionsHandlers.js +5 -2
- package/dist/components/Channel/utils.js +2 -1
- package/dist/components/ChannelHeader/ChannelHeader.js +1 -1
- package/dist/components/ChannelList/ChannelList.js +13 -8
- package/dist/components/ChannelList/hooks/useChannelListShape.d.ts +2 -2
- package/dist/components/ChannelList/hooks/useChannelListShape.js +46 -19
- package/dist/components/ChannelList/hooks/useChannelUpdatedListener.js +2 -1
- package/dist/components/ChannelList/hooks/useMessageNewListener.js +3 -1
- package/dist/components/ChannelList/hooks/useMobileNavigation.d.ts +1 -1
- package/dist/components/ChannelList/hooks/usePaginatedChannels.js +5 -3
- package/dist/components/ChannelList/hooks/useSelectedChannelState.js +1 -1
- package/dist/components/ChannelPreview/ChannelPreview.js +2 -2
- package/dist/components/ChannelPreview/ChannelPreviewMessenger.js +1 -1
- package/dist/components/ChannelPreview/icons.js +0 -1
- package/dist/components/ChannelPreview/utils.js +3 -3
- package/dist/components/ChannelSearch/ChannelSearch.js +5 -3
- package/dist/components/ChannelSearch/SearchBar.d.ts +1 -1
- package/dist/components/ChannelSearch/SearchInput.d.ts +1 -1
- package/dist/components/ChannelSearch/SearchResults.js +1 -1
- package/dist/components/ChannelSearch/hooks/useChannelSearch.d.ts +4 -2
- package/dist/components/ChannelSearch/hooks/useChannelSearch.js +61 -36
- package/dist/components/ChannelSearch/index.d.ts +1 -1
- package/dist/components/Chat/hooks/useChat.js +4 -2
- package/dist/components/Chat/hooks/useCreateChatClient.js +3 -1
- package/dist/components/ChatAutoComplete/ChatAutoComplete.js +1 -1
- package/dist/components/ChatView/ChatView.js +0 -1
- package/dist/components/Dialog/PromptDialog.d.ts +1 -1
- package/dist/components/Dialog/PromptDialog.js +1 -1
- package/dist/components/EventComponent/EventComponent.js +1 -1
- package/dist/components/Gallery/BaseImage.d.ts +1 -3
- package/dist/components/Gallery/Gallery.js +10 -2
- package/dist/components/Gallery/Image.js +1 -1
- package/dist/components/Gallery/ModalGallery.js +4 -4
- package/dist/components/InfiniteScrollPaginator/InfiniteScroll.js +9 -6
- package/dist/components/InfiniteScrollPaginator/InfiniteScrollPaginator.js +1 -1
- package/dist/components/LoadMore/LoadMorePaginator.js +1 -1
- package/dist/components/MML/MML.js +1 -0
- package/dist/components/MediaRecorder/transcode/wav.js +6 -3
- package/dist/components/Message/FixedHeightMessage.js +6 -8
- package/dist/components/Message/Message.js +2 -1
- package/dist/components/Message/MessageEditedTimestamp.js +1 -1
- package/dist/components/Message/MessageSimple.js +2 -5
- package/dist/components/Message/MessageStatus.js +1 -1
- package/dist/components/Message/MessageText.js +7 -7
- package/dist/components/Message/QuotedMessage.js +2 -2
- package/dist/components/Message/Timestamp.js +9 -1
- package/dist/components/Message/hooks/useActionHandler.js +1 -1
- package/dist/components/Message/hooks/useFlagHandler.js +2 -1
- package/dist/components/Message/hooks/useMarkUnreadHandler.js +2 -1
- package/dist/components/Message/hooks/useMessageTextStreaming.d.ts +1 -1
- package/dist/components/Message/hooks/useMessageTextStreaming.js +1 -1
- package/dist/components/Message/hooks/useMuteHandler.js +7 -4
- package/dist/components/Message/hooks/usePinHandler.js +1 -1
- package/dist/components/Message/hooks/useReactionHandler.js +10 -5
- package/dist/components/Message/hooks/useRetryHandler.js +1 -1
- package/dist/components/Message/hooks/useUserRole.js +1 -1
- package/dist/components/Message/renderText/renderText.js +2 -2
- package/dist/components/Message/utils.js +3 -3
- package/dist/components/MessageActions/MessageActionsBox.js +7 -3
- package/dist/components/MessageActions/hooks/useMessageActionsBoxPopper.d.ts +1 -1
- package/dist/components/MessageInput/AttachmentPreviewList/AttachmentPreviewList.js +1 -1
- package/dist/components/MessageInput/AttachmentPreviewList/FileAttachmentPreview.js +4 -2
- package/dist/components/MessageInput/AttachmentPreviewList/UnsupportedAttachmentPreview.js +4 -2
- package/dist/components/MessageInput/AttachmentSelector.js +1 -1
- package/dist/components/MessageInput/DefaultTriggerProvider.js +1 -1
- package/dist/components/MessageInput/DropzoneProvider.js +1 -1
- package/dist/components/MessageInput/MessageInput.js +1 -1
- package/dist/components/MessageInput/MessageInputFlat.js +4 -3
- package/dist/components/MessageInput/QuotedMessagePreview.js +1 -1
- package/dist/components/MessageInput/hooks/useAttachments.js +12 -4
- package/dist/components/MessageInput/hooks/useLinkPreviews.js +3 -1
- package/dist/components/MessageInput/hooks/useMessageInputState.js +4 -3
- package/dist/components/MessageInput/hooks/useMessageInputText.d.ts +1 -1
- package/dist/components/MessageInput/hooks/useMessageInputText.js +5 -3
- package/dist/components/MessageInput/hooks/useSubmitHandler.js +5 -3
- package/dist/components/MessageInput/hooks/useTimeElapsed.js +1 -1
- package/dist/components/MessageInput/hooks/useUserTrigger.js +2 -2
- package/dist/components/MessageInput/hooks/utils.js +6 -2
- package/dist/components/MessageList/ConnectionStatus.js +1 -1
- package/dist/components/MessageList/MessageList.js +5 -6
- package/dist/components/MessageList/MessageListNotifications.js +3 -1
- package/dist/components/MessageList/VirtualizedMessageList.d.ts +1 -1
- package/dist/components/MessageList/VirtualizedMessageList.js +19 -12
- package/dist/components/MessageList/VirtualizedMessageListComponents.js +2 -2
- package/dist/components/MessageList/hooks/MessageList/useMessageListElements.js +1 -3
- package/dist/components/MessageList/hooks/MessageList/useMessageListScrollManager.js +3 -2
- package/dist/components/MessageList/hooks/MessageList/useScrollLocationLogic.js +3 -2
- package/dist/components/MessageList/hooks/MessageList/useUnreadMessagesNotification.js +6 -2
- package/dist/components/MessageList/hooks/VirtualizedMessageList/useMessageSetKey.js +1 -1
- package/dist/components/MessageList/hooks/VirtualizedMessageList/useNewMessageNotification.d.ts +1 -1
- package/dist/components/MessageList/hooks/VirtualizedMessageList/usePrependMessagesCount.js +4 -3
- package/dist/components/MessageList/hooks/VirtualizedMessageList/useScrollToBottomOnNewMessage.js +1 -1
- package/dist/components/MessageList/hooks/VirtualizedMessageList/useUnreadMessagesNotificationVirtualized.js +7 -3
- package/dist/components/MessageList/hooks/useMarkRead.d.ts +2 -4
- package/dist/components/MessageList/hooks/useMarkRead.js +14 -16
- package/dist/components/MessageList/utils.js +28 -11
- package/dist/components/Modal/Modal.d.ts +1 -1
- package/dist/components/Modal/Modal.js +1 -1
- package/dist/components/Modal/ModalHeader.js +1 -1
- package/dist/components/Poll/Poll.js +1 -1
- package/dist/components/Poll/PollActions/PollActions.js +6 -4
- package/dist/components/Poll/PollActions/PollAnswerList.js +1 -1
- package/dist/components/Poll/PollActions/PollResults/PollOptionVotesList.js +1 -1
- package/dist/components/Poll/PollActions/PollResults/PollOptionWithLatestVotes.js +4 -2
- package/dist/components/Poll/PollActions/PollResults/PollResults.js +2 -1
- package/dist/components/Poll/PollContent.js +1 -1
- package/dist/components/Poll/PollCreationDialog/OptionFieldSet.d.ts +1 -1
- package/dist/components/Poll/PollCreationDialog/OptionFieldSet.js +11 -4
- package/dist/components/Poll/PollCreationDialog/PollCreationDialog.js +13 -4
- package/dist/components/Poll/PollCreationDialog/PollCreationDialogControls.js +6 -3
- package/dist/components/Poll/PollOptionList.js +1 -1
- package/dist/components/Poll/PollOptionSelector.js +12 -5
- package/dist/components/Poll/hooks/useManagePollVotesRealtime.js +9 -4
- package/dist/components/Poll/hooks/usePollAnswerPagination.js +8 -2
- package/dist/components/Poll/hooks/usePollOptionVotesPagination.js +8 -2
- package/dist/components/ReactFileUtilities/FileIcon/mimeTypes.d.ts +1 -1
- package/dist/components/ReactFileUtilities/ImageDropzone.js +3 -1
- package/dist/components/ReactFileUtilities/UploadButton.js +1 -1
- package/dist/components/ReactFileUtilities/utils.js +3 -1
- package/dist/components/Reactions/ReactionSelector.js +3 -1
- package/dist/components/Reactions/ReactionSelectorWithButton.js +1 -1
- package/dist/components/Reactions/ReactionsList.d.ts +2 -2
- package/dist/components/Reactions/ReactionsList.js +7 -4
- package/dist/components/Reactions/ReactionsListModal.d.ts +1 -2
- package/dist/components/Reactions/ReactionsListModal.js +1 -1
- package/dist/components/Reactions/SpriteImage.js +6 -2
- package/dist/components/Reactions/hooks/useFetchReactions.js +1 -1
- package/dist/components/Reactions/hooks/useProcessReactions.js +1 -1
- package/dist/components/Reactions/index.d.ts +1 -0
- package/dist/components/Reactions/index.js +1 -0
- package/dist/components/Reactions/reactionOptions.js +20 -5
- package/dist/components/Thread/Thread.js +4 -3
- package/dist/components/Threads/ThreadContext.d.ts +1 -1
- package/dist/components/Threads/ThreadContext.js +1 -1
- package/dist/components/Threads/ThreadList/ThreadList.js +1 -1
- package/dist/components/Threads/ThreadList/ThreadListItem.d.ts +1 -1
- package/dist/components/Threads/ThreadList/ThreadListItem.js +1 -1
- package/dist/components/Threads/ThreadList/ThreadListItemUI.js +5 -3
- package/dist/components/Threads/icons.js +0 -1
- package/dist/components/Tooltip/Tooltip.d.ts +1 -1
- package/dist/components/Tooltip/Tooltip.js +1 -1
- package/dist/context/ComponentContext.d.ts +3 -1
- package/dist/context/ComponentContext.js +1 -1
- package/dist/context/DialogManagerContext.d.ts +1 -1
- package/dist/context/DialogManagerContext.js +1 -1
- package/dist/context/MessageBounceContext.js +2 -2
- package/dist/context/MessageContext.js +1 -1
- package/dist/context/VirtualizedMessageListContext.d.ts +13 -0
- package/dist/context/VirtualizedMessageListContext.js +7 -0
- package/dist/context/WithComponents.js +1 -1
- package/dist/css/v2/index.css +2 -2
- package/dist/css/v2/index.layout.css +2 -2
- package/dist/experimental/MessageActions/MessageActions.js +0 -1
- package/dist/experimental/MessageActions/defaults.js +31 -7
- package/dist/experimental/index.browser.cjs +103 -37
- package/dist/experimental/index.browser.cjs.map +2 -2
- package/dist/experimental/index.node.cjs +103 -37
- package/dist/experimental/index.node.cjs.map +2 -2
- package/dist/i18n/Streami18n.js +11 -2
- package/dist/i18n/utils.js +14 -1
- package/dist/index.browser.cjs +2329 -1145
- package/dist/index.browser.cjs.map +4 -4
- package/dist/index.node.cjs +2594 -1164
- package/dist/index.node.cjs.map +4 -4
- package/dist/plugins/Emojis/EmojiPicker.js +0 -1
- package/dist/plugins/Emojis/index.browser.cjs +3 -1
- package/dist/plugins/Emojis/index.browser.cjs.map +2 -2
- package/dist/plugins/Emojis/index.node.cjs +3 -1
- package/dist/plugins/Emojis/index.node.cjs.map +2 -2
- package/dist/plugins/encoders/mp3.browser.cjs +7 -4
- package/dist/plugins/encoders/mp3.browser.cjs.map +2 -2
- package/dist/plugins/encoders/mp3.node.cjs +7 -4
- package/dist/plugins/encoders/mp3.node.cjs.map +2 -2
- package/dist/scss/v2/ChannelSearch/ChannelSearch-layout.scss +1 -0
- package/dist/scss/v2/Message/Message-layout.scss +12 -5
- package/dist/scss/v2/Poll/Poll-layout.scss +1 -1
- package/dist/scss/v2/Search/Search-layout.scss +148 -0
- package/dist/scss/v2/Search/Search-theme.scss +222 -0
- package/dist/scss/v2/_icons.scss +2 -0
- package/dist/scss/v2/index.layout.scss +1 -0
- package/dist/scss/v2/index.scss +1 -0
- package/dist/store/hooks/useStateStore.js +35 -11
- package/package.json +32 -47
|
@@ -24,8 +24,9 @@ export const ATTACHMENT_GROUPS_ORDER = [
|
|
|
24
24
|
*/
|
|
25
25
|
export const Attachment = (props) => {
|
|
26
26
|
const { attachments } = props;
|
|
27
|
+
const groupedAttachments = useMemo(() => renderGroupedAttachments(props),
|
|
27
28
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
28
|
-
|
|
29
|
+
[attachments]);
|
|
29
30
|
return (React.createElement("div", { className: 'str-chat__attachment-list' }, ATTACHMENT_GROUPS_ORDER.reduce((acc, groupName) => [...acc, ...groupedAttachments[groupName]], [])));
|
|
30
31
|
};
|
|
31
32
|
const renderGroupedAttachments = ({ attachments, ...rest }) => {
|
|
@@ -13,6 +13,6 @@ export declare const ImageContainer: <StreamChatGenerics extends DefaultStreamCh
|
|
|
13
13
|
export declare const CardContainer: <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>(props: RenderAttachmentProps<StreamChatGenerics>) => React.JSX.Element;
|
|
14
14
|
export declare const FileContainer: <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>({ attachment, File, }: RenderAttachmentProps<StreamChatGenerics>) => React.JSX.Element | null;
|
|
15
15
|
export declare const AudioContainer: <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>({ attachment, Audio, }: RenderAttachmentProps<StreamChatGenerics>) => React.JSX.Element;
|
|
16
|
-
export declare const VoiceRecordingContainer: <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>({ attachment,
|
|
16
|
+
export declare const VoiceRecordingContainer: <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>({ attachment, isQuoted, VoiceRecording, }: RenderAttachmentProps<StreamChatGenerics>) => React.JSX.Element;
|
|
17
17
|
export declare const MediaContainer: <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>(props: RenderAttachmentProps<StreamChatGenerics>) => React.JSX.Element;
|
|
18
18
|
export declare const UnsupportedAttachmentContainer: <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>({ attachment, UnsupportedAttachment, }: RenderAttachmentProps<StreamChatGenerics>) => React.JSX.Element;
|
|
@@ -123,7 +123,7 @@ export const FileContainer = ({ attachment, File = DefaultFile, }) => {
|
|
|
123
123
|
export const AudioContainer = ({ attachment, Audio = DefaultAudio, }) => (React.createElement(AttachmentWithinContainer, { attachment: attachment, componentType: 'audio' },
|
|
124
124
|
React.createElement("div", { className: 'str-chat__attachment' },
|
|
125
125
|
React.createElement(Audio, { og: attachment }))));
|
|
126
|
-
export const VoiceRecordingContainer = ({ attachment, VoiceRecording = DefaultVoiceRecording,
|
|
126
|
+
export const VoiceRecordingContainer = ({ attachment, isQuoted, VoiceRecording = DefaultVoiceRecording, }) => (React.createElement(AttachmentWithinContainer, { attachment: attachment, componentType: 'voiceRecording' },
|
|
127
127
|
React.createElement("div", { className: 'str-chat__attachment' },
|
|
128
128
|
React.createElement(VoiceRecording, { attachment: attachment, isQuoted: isQuoted }))));
|
|
129
129
|
export const MediaContainer = (props) => {
|
|
@@ -131,7 +131,7 @@ export const MediaContainer = (props) => {
|
|
|
131
131
|
const componentType = 'media';
|
|
132
132
|
const { shouldGenerateVideoThumbnail, videoAttachmentSizeHandler } = useChannelStateContext();
|
|
133
133
|
const videoElement = useRef(null);
|
|
134
|
-
const [attachmentConfiguration, setAttachmentConfiguration
|
|
134
|
+
const [attachmentConfiguration, setAttachmentConfiguration] = useState();
|
|
135
135
|
useLayoutEffect(() => {
|
|
136
136
|
if (videoElement.current && videoAttachmentSizeHandler) {
|
|
137
137
|
const config = videoAttachmentSizeHandler(attachment, videoElement.current, shouldGenerateVideoThumbnail);
|
|
@@ -22,7 +22,7 @@ const UnableToRenderCard = ({ type }) => {
|
|
|
22
22
|
React.createElement("div", { className: 'str-chat__message-attachment-card--content' },
|
|
23
23
|
React.createElement("div", { className: 'str-chat__message-attachment-card--text' }, t('this content could not be displayed')))));
|
|
24
24
|
};
|
|
25
|
-
const SourceLink = ({ author_name, url }) => (React.createElement("div", { className: 'str-chat__message-attachment-card--source-link', "data-testid": 'card-source-link' },
|
|
25
|
+
const SourceLink = ({ author_name, url, }) => (React.createElement("div", { className: 'str-chat__message-attachment-card--source-link', "data-testid": 'card-source-link' },
|
|
26
26
|
React.createElement(SafeAnchor, { className: 'str-chat__message-attachment-card--url', href: url, rel: 'noopener noreferrer', target: '_blank' }, author_name || getHostFromURL(url))));
|
|
27
27
|
const CardHeader = (props) => {
|
|
28
28
|
const { asset_url, dimensions, image, image_url, thumb_url, title, type } = props;
|
|
@@ -40,7 +40,7 @@ const CardContent = (props) => {
|
|
|
40
40
|
const url = title_link || og_scrape_url;
|
|
41
41
|
return (React.createElement("div", { className: 'str-chat__message-attachment-card--content' }, type === 'audio' ? (React.createElement(CardAudio, { og: props })) : (React.createElement("div", { className: 'str-chat__message-attachment-card--flex' },
|
|
42
42
|
url && React.createElement(SourceLink, { author_name: author_name, url: url }),
|
|
43
|
-
title && React.createElement("div", { className: 'str-chat__message-attachment-card--title' }, title),
|
|
43
|
+
title && (React.createElement("div", { className: 'str-chat__message-attachment-card--title' }, title)),
|
|
44
44
|
text && React.createElement("div", { className: 'str-chat__message-attachment-card--text' }, text)))));
|
|
45
45
|
};
|
|
46
46
|
export const CardAudio = ({ og: { asset_url, author_name, mime_type, og_scrape_url, text, title, title_link }, }) => {
|
|
@@ -60,7 +60,7 @@ export const CardAudio = ({ og: { asset_url, author_name, mime_type, og_scrape_u
|
|
|
60
60
|
React.createElement(ProgressBar, { onClick: seek, progress: progress })))),
|
|
61
61
|
React.createElement("div", { className: 'str-chat__message-attachment-audio-widget--second-row' },
|
|
62
62
|
url && React.createElement(SourceLink, { author_name: author_name, url: url }),
|
|
63
|
-
title && React.createElement("div", { className: 'str-chat__message-attachment-audio-widget--title' }, title),
|
|
63
|
+
title && (React.createElement("div", { className: 'str-chat__message-attachment-audio-widget--title' }, title)),
|
|
64
64
|
text && (React.createElement("div", { className: 'str-chat__message-attachment-audio-widget--description' }, text)))));
|
|
65
65
|
};
|
|
66
66
|
const UnMemoizedCard = (props) => {
|
|
@@ -5,7 +5,7 @@ export type VoiceRecordingPlayerProps<StreamChatGenerics extends DefaultStreamCh
|
|
|
5
5
|
/** An array of fractional numeric values of playback speed to override the defaults (1.0, 1.5, 2.0) */
|
|
6
6
|
playbackRates?: number[];
|
|
7
7
|
};
|
|
8
|
-
export declare const VoiceRecordingPlayer: ({ attachment, playbackRates }: VoiceRecordingPlayerProps) => React.JSX.Element | null;
|
|
8
|
+
export declare const VoiceRecordingPlayer: ({ attachment, playbackRates, }: VoiceRecordingPlayerProps) => React.JSX.Element | null;
|
|
9
9
|
export type QuotedVoiceRecordingProps<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> = Pick<VoiceRecordingProps<StreamChatGenerics>, 'attachment'>;
|
|
10
10
|
export declare const QuotedVoiceRecording: ({ attachment }: QuotedVoiceRecordingProps) => React.JSX.Element;
|
|
11
11
|
export type VoiceRecordingProps<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> = {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { FileSizeIndicator, PlaybackRateButton, PlayButton, WaveProgressBar } from './components';
|
|
2
|
+
import { FileSizeIndicator, PlaybackRateButton, PlayButton, WaveProgressBar, } from './components';
|
|
3
3
|
import { useAudioController } from './hooks/useAudioController';
|
|
4
4
|
import { displayDuration } from './utils';
|
|
5
5
|
import { FileIcon } from '../ReactFileUtilities';
|
|
6
6
|
import { useTranslationContext } from '../../context';
|
|
7
7
|
const rootClassName = 'str-chat__message-attachment__voice-recording-widget';
|
|
8
|
-
export const VoiceRecordingPlayer = ({ attachment, playbackRates }) => {
|
|
8
|
+
export const VoiceRecordingPlayer = ({ attachment, playbackRates, }) => {
|
|
9
9
|
const { t } = useTranslationContext('VoiceRecordingPlayer');
|
|
10
10
|
const { asset_url, duration = 0, mime_type, title = t('Voice message'), waveform_data, } = attachment;
|
|
11
11
|
const { audioRef, increasePlaybackRate, isPlaying, playbackRate, progress, secondsElapsed, seek, togglePlay, } = useAudioController({
|
|
@@ -43,7 +43,8 @@ const getSizingRestrictions = (url, htmlElement) => {
|
|
|
43
43
|
const originalWidth = Number(urlParams.get('ow')) || 1;
|
|
44
44
|
const cssSizeRestriction = getCSSSizeRestrictions(htmlElement);
|
|
45
45
|
let resizeDimensions;
|
|
46
|
-
if ((cssSizeRestriction.maxHeight || cssSizeRestriction.height) &&
|
|
46
|
+
if ((cssSizeRestriction.maxHeight || cssSizeRestriction.height) &&
|
|
47
|
+
cssSizeRestriction.maxWidth) {
|
|
47
48
|
resizeDimensions = getResizeDimensions(originalHeight, originalWidth,
|
|
48
49
|
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */
|
|
49
50
|
cssSizeRestriction.maxHeight || cssSizeRestriction.height, cssSizeRestriction.maxWidth);
|
|
@@ -8,5 +8,5 @@ type FileSizeIndicatorProps = {
|
|
|
8
8
|
*/
|
|
9
9
|
maximumFractionDigits?: number;
|
|
10
10
|
};
|
|
11
|
-
export declare const FileSizeIndicator: ({ fileSize, maximumFractionDigits }: FileSizeIndicatorProps) => React.JSX.Element | null;
|
|
11
|
+
export declare const FileSizeIndicator: ({ fileSize, maximumFractionDigits, }: FileSizeIndicatorProps) => React.JSX.Element | null;
|
|
12
12
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { prettifyFileSize } from '../../MessageInput/hooks/utils';
|
|
3
|
-
export const FileSizeIndicator = ({ fileSize, maximumFractionDigits }) => {
|
|
3
|
+
export const FileSizeIndicator = ({ fileSize, maximumFractionDigits, }) => {
|
|
4
4
|
if (!(fileSize && Number.isFinite(Number(fileSize))))
|
|
5
5
|
return null;
|
|
6
6
|
return (React.createElement("span", { className: 'str-chat__message-attachment-file--item-size', "data-testid": 'file-size-indicator' }, prettifyFileSize(fileSize, maximumFractionDigits)));
|
|
@@ -7,7 +7,7 @@ export const WaveProgressBar = ({ amplitudesCount = 40, progress = 0, relativeAm
|
|
|
7
7
|
const isDragging = useRef(false);
|
|
8
8
|
const [root, setRoot] = useState(null);
|
|
9
9
|
const [trackAxisX, setTrackAxisX] = useState();
|
|
10
|
-
const lastRootWidth = useRef();
|
|
10
|
+
const lastRootWidth = useRef(undefined);
|
|
11
11
|
const handleDragStart = (e) => {
|
|
12
12
|
e.preventDefault();
|
|
13
13
|
if (!progressIndicator)
|
|
@@ -13,7 +13,7 @@ type AudioControllerParams = {
|
|
|
13
13
|
playbackRates?: number[];
|
|
14
14
|
};
|
|
15
15
|
export declare const useAudioController: ({ durationSeconds, mimeType, playbackRates, }?: AudioControllerParams) => {
|
|
16
|
-
audioRef: import("react").
|
|
16
|
+
audioRef: import("react").RefObject<HTMLAudioElement | null>;
|
|
17
17
|
canPlayRecord: boolean;
|
|
18
18
|
increasePlaybackRate: () => void;
|
|
19
19
|
isPlaying: boolean;
|
|
@@ -13,7 +13,7 @@ export const useAudioController = ({ durationSeconds, mimeType, playbackRates =
|
|
|
13
13
|
const [canPlayRecord, setCanPlayRecord] = useState(true);
|
|
14
14
|
const [secondsElapsed, setSecondsElapsed] = useState(0);
|
|
15
15
|
const [playbackRateIndex, setPlaybackRateIndex] = useState(0);
|
|
16
|
-
const playTimeout = useRef();
|
|
16
|
+
const playTimeout = useRef(undefined);
|
|
17
17
|
const audioRef = useRef(null);
|
|
18
18
|
const registerError = useCallback((e) => {
|
|
19
19
|
logError(e);
|
|
@@ -116,7 +116,9 @@ export const useAudioController = ({ durationSeconds, mimeType, playbackRates =
|
|
|
116
116
|
isPlaying,
|
|
117
117
|
playbackError,
|
|
118
118
|
playbackRate: playbackRates[playbackRateIndex],
|
|
119
|
-
progress: audioRef.current && secondsElapsed
|
|
119
|
+
progress: audioRef.current && secondsElapsed
|
|
120
|
+
? (secondsElapsed / audioRef.current.duration) * 100
|
|
121
|
+
: 0,
|
|
120
122
|
secondsElapsed,
|
|
121
123
|
seek,
|
|
122
124
|
togglePlay,
|
|
@@ -4,7 +4,7 @@ import type { ATTACHMENT_GROUPS_ORDER, AttachmentProps } from './Attachment';
|
|
|
4
4
|
import type { DefaultStreamChatGenerics, UnknownType } from '../../types/types';
|
|
5
5
|
import type { LocalAttachment, LocalAudioAttachment, LocalFileAttachment, LocalImageAttachment, LocalVideoAttachment, LocalVoiceRecordingAttachment, VoiceRecordingAttachment } from '../MessageInput';
|
|
6
6
|
export declare const SUPPORTED_VIDEO_FORMATS: string[];
|
|
7
|
-
export type AttachmentComponentType = typeof ATTACHMENT_GROUPS_ORDER[number];
|
|
7
|
+
export type AttachmentComponentType = (typeof ATTACHMENT_GROUPS_ORDER)[number];
|
|
8
8
|
export type GroupedRenderedAttachment = Record<AttachmentComponentType, ReactNode[]>;
|
|
9
9
|
export type GalleryAttachment<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> = {
|
|
10
10
|
images: Attachment<StreamChatGenerics>[];
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
export const SUPPORTED_VIDEO_FORMATS = [
|
|
1
|
+
export const SUPPORTED_VIDEO_FORMATS = [
|
|
2
|
+
'video/mp4',
|
|
3
|
+
'video/ogg',
|
|
4
|
+
'video/webm',
|
|
5
|
+
'video/quicktime',
|
|
6
|
+
];
|
|
2
7
|
export const isLocalAttachment = (attachment) => !!attachment.localMetadata?.id;
|
|
3
8
|
export const isScrapedContent = (attachment) => attachment.og_scrape_url || attachment.title_link;
|
|
4
9
|
export const isUploadedImage = (attachment) => attachment.type === 'image' && !isScrapedContent(attachment);
|
|
@@ -13,14 +18,18 @@ export const isFileAttachment = (attachment) => attachment.type === 'file' ||
|
|
|
13
18
|
SUPPORTED_VIDEO_FORMATS.indexOf(attachment.mime_type) === -1 &&
|
|
14
19
|
attachment.type !== 'video');
|
|
15
20
|
export const isLocalFileAttachment = (attachment) => isFileAttachment(attachment) && isLocalAttachment(attachment);
|
|
16
|
-
export const isMediaAttachment = (attachment) => (attachment.mime_type &&
|
|
21
|
+
export const isMediaAttachment = (attachment) => (attachment.mime_type &&
|
|
22
|
+
SUPPORTED_VIDEO_FORMATS.indexOf(attachment.mime_type) !== -1) ||
|
|
17
23
|
attachment.type === 'video';
|
|
18
24
|
export const isLocalMediaAttachment = (attachment) => isMediaAttachment(attachment) && isLocalAttachment(attachment);
|
|
19
25
|
export const isSvgAttachment = (attachment) => {
|
|
20
26
|
const filename = attachment.fallback || '';
|
|
21
27
|
return filename.toLowerCase().endsWith('.svg');
|
|
22
28
|
};
|
|
23
|
-
export const divMod = (num, divisor) => [
|
|
29
|
+
export const divMod = (num, divisor) => [
|
|
30
|
+
Math.floor(num / divisor),
|
|
31
|
+
num % divisor,
|
|
32
|
+
];
|
|
24
33
|
export const displayDuration = (totalSeconds) => {
|
|
25
34
|
if (!totalSeconds || totalSeconds < 0)
|
|
26
35
|
return '00:00';
|
|
@@ -19,7 +19,7 @@ export const List = ({ className, component, currentTrigger, dropdownScroll, get
|
|
|
19
19
|
}
|
|
20
20
|
return item.key;
|
|
21
21
|
};
|
|
22
|
-
const findItemIndex = useCallback((item) => values.findIndex((value) =>
|
|
22
|
+
const findItemIndex = useCallback((item) => values.findIndex((value) => value.id ? value.id === item.id : value.name === item.name), [values]);
|
|
23
23
|
const modifyText = (value) => {
|
|
24
24
|
if (!value)
|
|
25
25
|
return;
|
|
@@ -57,7 +57,8 @@ export const List = ({ className, component, currentTrigger, dropdownScroll, get
|
|
|
57
57
|
return newIndex;
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
|
-
if ((event.key === 'Enter' || event.key === 'Tab') &&
|
|
60
|
+
if ((event.key === 'Enter' || event.key === 'Tab') &&
|
|
61
|
+
selectedItemIndex !== undefined) {
|
|
61
62
|
handleClick(event, values[selectedItemIndex]);
|
|
62
63
|
}
|
|
63
64
|
return null;
|
|
@@ -2,7 +2,6 @@ import React from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import Textarea from 'react-textarea-autosize';
|
|
4
4
|
import getCaretCoordinates from 'textarea-caret';
|
|
5
|
-
import { isValidElementType } from 'react-is';
|
|
6
5
|
import clsx from 'clsx';
|
|
7
6
|
import { List as DefaultSuggestionList } from './List';
|
|
8
7
|
import { DEFAULT_CARET_POSITION, defaultScrollToItem, errorMessage, triggerPropsCheck, } from './utils';
|
|
@@ -112,7 +111,7 @@ export class ReactTextareaAutocomplete extends React.Component {
|
|
|
112
111
|
};
|
|
113
112
|
this._onSelect = (newToken) => {
|
|
114
113
|
const { closeCommandsList, closeMentionsList, onChange, showCommandsList, showMentionsList, } = this.props;
|
|
115
|
-
const { currentTrigger: stateTrigger, selectionEnd, value: textareaValue } = this.state;
|
|
114
|
+
const { currentTrigger: stateTrigger, selectionEnd, value: textareaValue, } = this.state;
|
|
116
115
|
const currentTrigger = showCommandsList ? '/' : showMentionsList ? '@' : stateTrigger;
|
|
117
116
|
if (!currentTrigger)
|
|
118
117
|
return;
|
|
@@ -242,9 +241,6 @@ export class ReactTextareaAutocomplete extends React.Component {
|
|
|
242
241
|
if (!Array.isArray(data)) {
|
|
243
242
|
throw new Error('Trigger provider has to provide an array!');
|
|
244
243
|
}
|
|
245
|
-
if (!isValidElementType(component)) {
|
|
246
|
-
throw new Error('Component should be defined!');
|
|
247
|
-
}
|
|
248
244
|
// throw away if we resolved old trigger
|
|
249
245
|
if (currentTrigger !== this.state.currentTrigger)
|
|
250
246
|
return;
|
|
@@ -317,7 +313,6 @@ export class ReactTextareaAutocomplete extends React.Component {
|
|
|
317
313
|
'trigger',
|
|
318
314
|
'value',
|
|
319
315
|
];
|
|
320
|
-
// eslint-disable-next-line
|
|
321
316
|
for (const prop in props) {
|
|
322
317
|
if (notSafe.includes(prop))
|
|
323
318
|
delete props[prop];
|
|
@@ -354,7 +349,8 @@ export class ReactTextareaAutocomplete extends React.Component {
|
|
|
354
349
|
const regex = new RegExp(`(?!^|\\W)?[${triggerTokens}]${triggerNorWhitespace}\\s?${triggerNorWhitespace}$`, 'g');
|
|
355
350
|
const tokenMatch = value.slice(0, selectionEnd).match(regex);
|
|
356
351
|
lastToken = tokenMatch && tokenMatch[tokenMatch.length - 1].trim();
|
|
357
|
-
currentTrigger =
|
|
352
|
+
currentTrigger =
|
|
353
|
+
(lastToken && Object.keys(trigger).find((a) => a === lastToken[0])) || null;
|
|
358
354
|
}
|
|
359
355
|
/*
|
|
360
356
|
if we lost the trigger token or there is no following character we want to close
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { isValidElementType } from 'react-is';
|
|
2
1
|
export const DEFAULT_CARET_POSITION = 'next';
|
|
3
2
|
export function defaultScrollToItem(container, item) {
|
|
4
3
|
if (!item)
|
|
@@ -7,10 +6,10 @@ export function defaultScrollToItem(container, item) {
|
|
|
7
6
|
const containerHight = parseInt(getComputedStyle(container).getPropertyValue('height'), 10) - itemHeight;
|
|
8
7
|
const actualScrollTop = container.scrollTop;
|
|
9
8
|
const itemOffsetTop = item.offsetTop;
|
|
10
|
-
if (itemOffsetTop < actualScrollTop + containerHight &&
|
|
9
|
+
if (itemOffsetTop < actualScrollTop + containerHight &&
|
|
10
|
+
actualScrollTop < itemOffsetTop) {
|
|
11
11
|
return;
|
|
12
12
|
}
|
|
13
|
-
// eslint-disable-next-line
|
|
14
13
|
container.scrollTop = itemOffsetTop;
|
|
15
14
|
}
|
|
16
15
|
export const errorMessage = (message) => console.error(`RTA: dataProvider fails: ${message}
|
|
@@ -26,10 +25,7 @@ export const triggerPropsCheck = ({ trigger }) => {
|
|
|
26
25
|
}
|
|
27
26
|
// $FlowFixMe
|
|
28
27
|
const triggerSetting = settings;
|
|
29
|
-
const { callback,
|
|
30
|
-
if (!isValidElementType(component)) {
|
|
31
|
-
return Error('Invalid prop trigger: component should be defined.');
|
|
32
|
-
}
|
|
28
|
+
const { callback, dataProvider, output } = triggerSetting;
|
|
33
29
|
if (!dataProvider || typeof dataProvider !== 'function') {
|
|
34
30
|
return Error('Invalid prop trigger: dataProvider should be defined.');
|
|
35
31
|
}
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { Avatar, GroupAvatar } from './index';
|
|
3
3
|
export const ChannelAvatar = ({ groupChannelDisplayInfo, image, name, user, ...sharedProps }) => {
|
|
4
4
|
if (groupChannelDisplayInfo) {
|
|
5
|
-
return React.createElement(GroupAvatar, { groupChannelDisplayInfo: groupChannelDisplayInfo, ...sharedProps });
|
|
5
|
+
return (React.createElement(GroupAvatar, { groupChannelDisplayInfo: groupChannelDisplayInfo, ...sharedProps }));
|
|
6
6
|
}
|
|
7
7
|
return React.createElement(Avatar, { image: image, name: name, user: user, ...sharedProps });
|
|
8
8
|
};
|
|
@@ -6,7 +6,7 @@ import { ComponentContextValue, StreamMessage } from '../../context';
|
|
|
6
6
|
import type { MessageInputProps } from '../MessageInput';
|
|
7
7
|
import type { ChannelUnreadUiState, CustomTrigger, DefaultStreamChatGenerics, GiphyVersions, ImageAttachmentSizeHandler, SendMessageOptions, UpdateMessageOptions, VideoAttachmentSizeHandler } from '../../types/types';
|
|
8
8
|
import type { URLEnrichmentConfig } from '../MessageInput/hooks/useLinkPreviews';
|
|
9
|
-
type ChannelPropsForwardedToComponentContext<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> = Pick<ComponentContextValue<StreamChatGenerics>, 'Attachment' | 'AttachmentPreviewList' | 'AttachmentSelector' | 'AttachmentSelectorInitiationButtonContents' | 'AudioRecorder' | 'AutocompleteSuggestionItem' | 'AutocompleteSuggestionList' | 'Avatar' | 'BaseImage' | 'CooldownTimer' | 'CustomMessageActionsList' | 'DateSeparator' | 'EditMessageInput' | 'EmojiPicker' | 'emojiSearchIndex' | 'EmptyStateIndicator' | 'FileUploadIcon' | 'GiphyPreviewMessage' | 'HeaderComponent' | 'Input' | 'LinkPreviewList' | 'LoadingIndicator' | 'Message' | 'MessageActions' | 'MessageBouncePrompt' | 'MessageDeleted' | 'MessageListNotifications' | 'MessageListMainPanel' | 'MessageNotification' | 'MessageOptions' | 'MessageRepliesCountButton' | 'MessageStatus' | 'MessageSystem' | 'MessageTimestamp' | 'ModalGallery' | 'PinIndicator' | 'PollActions' | 'PollContent' | 'PollCreationDialog' | 'PollHeader' | 'PollOptionSelector' | 'QuotedMessage' | 'QuotedMessagePreview' | 'QuotedPoll' | 'reactionOptions' | 'ReactionSelector' | 'ReactionsList' | 'SendButton' | 'StartRecordingAudioButton' | 'ThreadHead' | 'ThreadHeader' | 'ThreadStart' | 'Timestamp' | 'TriggerProvider' | 'TypingIndicator' | 'UnreadMessagesNotification' | 'UnreadMessagesSeparator' | 'VirtualMessage' | 'StopAIGenerationButton' | 'StreamedMessageText'>;
|
|
9
|
+
type ChannelPropsForwardedToComponentContext<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> = Pick<ComponentContextValue<StreamChatGenerics>, 'Attachment' | 'AttachmentPreviewList' | 'AttachmentSelector' | 'AttachmentSelectorInitiationButtonContents' | 'AudioRecorder' | 'AutocompleteSuggestionItem' | 'AutocompleteSuggestionList' | 'Avatar' | 'BaseImage' | 'CooldownTimer' | 'CustomMessageActionsList' | 'DateSeparator' | 'EditMessageInput' | 'EmojiPicker' | 'emojiSearchIndex' | 'EmptyStateIndicator' | 'FileUploadIcon' | 'GiphyPreviewMessage' | 'HeaderComponent' | 'Input' | 'LinkPreviewList' | 'LoadingIndicator' | 'Message' | 'MessageActions' | 'MessageBouncePrompt' | 'MessageDeleted' | 'MessageListNotifications' | 'MessageListMainPanel' | 'MessageNotification' | 'MessageOptions' | 'MessageRepliesCountButton' | 'MessageStatus' | 'MessageSystem' | 'MessageTimestamp' | 'ModalGallery' | 'PinIndicator' | 'PollActions' | 'PollContent' | 'PollCreationDialog' | 'PollHeader' | 'PollOptionSelector' | 'QuotedMessage' | 'QuotedMessagePreview' | 'QuotedPoll' | 'reactionOptions' | 'ReactionSelector' | 'ReactionsList' | 'ReactionsListModal' | 'SendButton' | 'StartRecordingAudioButton' | 'ThreadHead' | 'ThreadHeader' | 'ThreadStart' | 'Timestamp' | 'TriggerProvider' | 'TypingIndicator' | 'UnreadMessagesNotification' | 'UnreadMessagesSeparator' | 'VirtualMessage' | 'StopAIGenerationButton' | 'StreamedMessageText'>;
|
|
10
10
|
export type ChannelProps<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics, V extends CustomTrigger = CustomTrigger> = ChannelPropsForwardedToComponentContext<StreamChatGenerics> & {
|
|
11
11
|
/** List of accepted file types */
|
|
12
12
|
acceptedFiles?: string[];
|
|
@@ -4,7 +4,7 @@ import defaultsDeep from 'lodash.defaultsdeep';
|
|
|
4
4
|
import throttle from 'lodash.throttle';
|
|
5
5
|
import { nanoid } from 'nanoid';
|
|
6
6
|
import clsx from 'clsx';
|
|
7
|
-
import {
|
|
7
|
+
import { initialState, makeChannelReducer } from './channelState';
|
|
8
8
|
import { useCreateChannelStateContext } from './hooks/useCreateChannelStateContext';
|
|
9
9
|
import { useCreateTypingContext } from './hooks/useCreateTypingContext';
|
|
10
10
|
import { useEditMessageHandler } from './hooks/useEditMessageHandler';
|
|
@@ -53,7 +53,7 @@ const ChannelInner = (props) => {
|
|
|
53
53
|
const channelQueryOptions = useMemo(() => defaultsDeep(propChannelQueryOptions, {
|
|
54
54
|
messages: { limit: DEFAULT_INITIAL_CHANNEL_PAGE_SIZE },
|
|
55
55
|
}), [propChannelQueryOptions]);
|
|
56
|
-
const { client, customClasses, latestMessageDatesByChannels, mutes
|
|
56
|
+
const { client, customClasses, latestMessageDatesByChannels, mutes } = useChatContext('Channel');
|
|
57
57
|
const { t } = useTranslationContext('Channel');
|
|
58
58
|
const chatContainerClass = getChatContainerClass(customClasses?.chatContainer);
|
|
59
59
|
const windowsEmojiClass = useImageFlagEmojisOnWindowsClass();
|
|
@@ -63,6 +63,7 @@ const ChannelInner = (props) => {
|
|
|
63
63
|
const [quotedMessage, setQuotedMessage] = useState();
|
|
64
64
|
const [channelUnreadUiState, _setChannelUnreadUiState] = useState();
|
|
65
65
|
const notificationTimeouts = useRef([]);
|
|
66
|
+
const channelReducer = useMemo(() => makeChannelReducer(), []);
|
|
66
67
|
const [state, dispatch] = useReducer(channelReducer,
|
|
67
68
|
// channel.initialized === false if client.channel().query() was not called, e.g. ChannelList is not used
|
|
68
69
|
// => Channel will call channel.watch() in useLayoutEffect => state.loading is used to signal the watch() call state
|
|
@@ -73,7 +74,7 @@ const ChannelInner = (props) => {
|
|
|
73
74
|
});
|
|
74
75
|
const isMounted = useIsMounted();
|
|
75
76
|
const originalTitle = useRef('');
|
|
76
|
-
const lastRead = useRef();
|
|
77
|
+
const lastRead = useRef(undefined);
|
|
77
78
|
const online = useRef(true);
|
|
78
79
|
const channelCapabilitiesArray = channel.data?.own_capabilities;
|
|
79
80
|
const throttledCopyStateFromChannel = throttle(() => dispatch({ channel, type: 'copyStateFromChannelOnEvent' }), 500, {
|
|
@@ -114,7 +115,14 @@ const ChannelInner = (props) => {
|
|
|
114
115
|
catch (e) {
|
|
115
116
|
console.error(t('Failed to mark channel as read'));
|
|
116
117
|
}
|
|
117
|
-
}, 500, { leading: true, trailing: false }), [
|
|
118
|
+
}, 500, { leading: true, trailing: false }), [
|
|
119
|
+
activeUnreadHandler,
|
|
120
|
+
channel,
|
|
121
|
+
channelConfig,
|
|
122
|
+
doMarkReadRequest,
|
|
123
|
+
setChannelUnreadUiState,
|
|
124
|
+
t,
|
|
125
|
+
]);
|
|
118
126
|
const handleEvent = async (event) => {
|
|
119
127
|
if (event.message) {
|
|
120
128
|
dispatch({
|
|
@@ -134,7 +142,9 @@ const ChannelInner = (props) => {
|
|
|
134
142
|
if (event.type === 'message.new') {
|
|
135
143
|
const mainChannelUpdated = !event.message?.parent_id || event.message?.show_in_channel;
|
|
136
144
|
if (mainChannelUpdated) {
|
|
137
|
-
if (document.hidden &&
|
|
145
|
+
if (document.hidden &&
|
|
146
|
+
channelConfig?.read_events &&
|
|
147
|
+
!channel.muteStatus().muted) {
|
|
138
148
|
const unread = channel.countUnread(lastRead.current);
|
|
139
149
|
if (activeUnreadHandler) {
|
|
140
150
|
activeUnreadHandler(unread, originalTitle.current);
|
|
@@ -282,11 +292,15 @@ const ChannelInner = (props) => {
|
|
|
282
292
|
dispatch({ hasMore, messages, type: 'loadMoreFinished' });
|
|
283
293
|
}, 2000, { leading: true, trailing: true }), []);
|
|
284
294
|
const loadMore = async (limit = DEFAULT_NEXT_CHANNEL_PAGE_SIZE) => {
|
|
285
|
-
if (!online.current ||
|
|
295
|
+
if (!online.current ||
|
|
296
|
+
!window.navigator.onLine ||
|
|
297
|
+
!channel.state.messagePagination.hasPrev)
|
|
286
298
|
return 0;
|
|
287
299
|
// prevent duplicate loading events...
|
|
288
300
|
const oldestMessage = state?.messages?.[0];
|
|
289
|
-
if (state.loadingMore ||
|
|
301
|
+
if (state.loadingMore ||
|
|
302
|
+
state.loadingMoreNewer ||
|
|
303
|
+
oldestMessage?.status !== 'received') {
|
|
290
304
|
return 0;
|
|
291
305
|
}
|
|
292
306
|
dispatch({ loadingMore: true, type: 'setLoadingMore' });
|
|
@@ -308,7 +322,9 @@ const ChannelInner = (props) => {
|
|
|
308
322
|
return queryResponse.messages.length;
|
|
309
323
|
};
|
|
310
324
|
const loadMoreNewer = async (limit = DEFAULT_NEXT_CHANNEL_PAGE_SIZE) => {
|
|
311
|
-
if (!online.current ||
|
|
325
|
+
if (!online.current ||
|
|
326
|
+
!window.navigator.onLine ||
|
|
327
|
+
!channel.state.messagePagination.hasNext)
|
|
312
328
|
return 0;
|
|
313
329
|
const newestMessage = state?.messages?.[state?.messages?.length - 1];
|
|
314
330
|
if (state.loadingMore || state.loadingMoreNewer)
|
|
@@ -538,9 +554,7 @@ const ChannelInner = (props) => {
|
|
|
538
554
|
catch (error) {
|
|
539
555
|
// error response isn't usable so needs to be stringified then parsed
|
|
540
556
|
const stringError = JSON.stringify(error);
|
|
541
|
-
const parsedError = (stringError
|
|
542
|
-
? JSON.parse(stringError)
|
|
543
|
-
: {});
|
|
557
|
+
const parsedError = (stringError ? JSON.parse(stringError) : {});
|
|
544
558
|
// Handle the case where the message already exists
|
|
545
559
|
// (typically, when retrying to send a message).
|
|
546
560
|
// If the message already exists, we can assume it was sent successfully,
|
|
@@ -564,7 +578,7 @@ const ChannelInner = (props) => {
|
|
|
564
578
|
status: 'failed',
|
|
565
579
|
});
|
|
566
580
|
thread?.upsertReplyLocally({
|
|
567
|
-
// @ts-expect-error
|
|
581
|
+
// @ts-expect-error message type mismatch
|
|
568
582
|
message: {
|
|
569
583
|
...message,
|
|
570
584
|
error: parsedError,
|
|
@@ -591,7 +605,7 @@ const ChannelInner = (props) => {
|
|
|
591
605
|
user: client.user,
|
|
592
606
|
};
|
|
593
607
|
thread?.upsertReplyLocally({
|
|
594
|
-
// @ts-expect-error
|
|
608
|
+
// @ts-expect-error message type mismatch
|
|
595
609
|
message: messagePreview,
|
|
596
610
|
});
|
|
597
611
|
updateMessage(messagePreview);
|
|
@@ -732,7 +746,7 @@ const ChannelInner = (props) => {
|
|
|
732
746
|
jumpToLatestMessage,
|
|
733
747
|
setChannelUnreadUiState,
|
|
734
748
|
]);
|
|
735
|
-
// @ts-expect-error
|
|
749
|
+
// @ts-expect-error message type mismatch
|
|
736
750
|
const componentContextValue = useMemo(() => ({
|
|
737
751
|
Attachment: props.Attachment,
|
|
738
752
|
AttachmentPreviewList: props.AttachmentPreviewList,
|
|
@@ -780,6 +794,7 @@ const ChannelInner = (props) => {
|
|
|
780
794
|
reactionOptions: props.reactionOptions,
|
|
781
795
|
ReactionSelector: props.ReactionSelector,
|
|
782
796
|
ReactionsList: props.ReactionsList,
|
|
797
|
+
ReactionsListModal: props.ReactionsListModal,
|
|
783
798
|
SendButton: props.SendButton,
|
|
784
799
|
StartRecordingAudioButton: props.StartRecordingAudioButton,
|
|
785
800
|
StopAIGenerationButton: props.StopAIGenerationButton,
|
|
@@ -838,6 +853,7 @@ const ChannelInner = (props) => {
|
|
|
838
853
|
props.QuotedPoll,
|
|
839
854
|
props.ReactionSelector,
|
|
840
855
|
props.ReactionsList,
|
|
856
|
+
props.ReactionsListModal,
|
|
841
857
|
props.SendButton,
|
|
842
858
|
props.StartRecordingAudioButton,
|
|
843
859
|
props.ThreadHead,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Reducer } from 'react';
|
|
2
1
|
import type { Channel, MessageResponse, ChannelState as StreamChannelState } from 'stream-chat';
|
|
3
2
|
import type { ChannelState, StreamMessage } from '../../context/ChannelStateContext';
|
|
4
3
|
import type { DefaultStreamChatGenerics } from '../../types/types';
|
|
@@ -61,8 +60,7 @@ export type ChannelStateReducerAction<StreamChatGenerics extends DefaultStreamCh
|
|
|
61
60
|
} | {
|
|
62
61
|
type: 'jumpToLatestMessage';
|
|
63
62
|
};
|
|
64
|
-
export
|
|
65
|
-
export declare const channelReducer: <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>(state: ChannelState<StreamChatGenerics>, action: ChannelStateReducerAction<StreamChatGenerics>) => ChannelState<StreamChatGenerics>;
|
|
63
|
+
export declare const makeChannelReducer: <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>() => (state: ChannelState<StreamChatGenerics>, action: ChannelStateReducerAction<StreamChatGenerics>) => ChannelState<StreamChatGenerics>;
|
|
66
64
|
export declare const initialState: {
|
|
67
65
|
error: null;
|
|
68
66
|
hasMore: boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const makeChannelReducer = () => (state, action) => {
|
|
2
2
|
switch (action.type) {
|
|
3
3
|
case 'closeThread': {
|
|
4
4
|
return {
|
|
@@ -103,7 +103,9 @@ export const channelReducer = (state, action) => {
|
|
|
103
103
|
...state,
|
|
104
104
|
thread: message,
|
|
105
105
|
threadHasMore: true,
|
|
106
|
-
threadMessages: message.id
|
|
106
|
+
threadMessages: message.id
|
|
107
|
+
? { ...channel.state.threads }[message.id] || []
|
|
108
|
+
: [],
|
|
107
109
|
threadSuppressAutoscroll: false,
|
|
108
110
|
};
|
|
109
111
|
}
|
|
@@ -144,8 +146,12 @@ export const channelReducer = (state, action) => {
|
|
|
144
146
|
return state;
|
|
145
147
|
return {
|
|
146
148
|
...state,
|
|
147
|
-
thread: message?.id === state.thread.id
|
|
148
|
-
|
|
149
|
+
thread: message?.id === state.thread.id
|
|
150
|
+
? channel.state.formatMessage(message)
|
|
151
|
+
: state.thread,
|
|
152
|
+
threadMessages: state.thread?.id
|
|
153
|
+
? { ...channel.state.threads }[state.thread.id] || []
|
|
154
|
+
: [],
|
|
149
155
|
};
|
|
150
156
|
}
|
|
151
157
|
default:
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
2
|
import { isDate, isDayOrMoment } from '../../../i18n';
|
|
3
3
|
export const useCreateChannelStateContext = (value) => {
|
|
4
|
-
const { acceptedFiles, channel, channelCapabilitiesArray = [], channelConfig, debounceURLEnrichmentMs, dragAndDropWindow, enrichURLForPreview,
|
|
4
|
+
const { acceptedFiles, channel, channelCapabilitiesArray = [], channelConfig, channelUnreadUiState, debounceURLEnrichmentMs, dragAndDropWindow, enrichURLForPreview, error, findURLFn, giphyVersion, hasMore, hasMoreNewer, highlightedMessageId, imageAttachmentSizeHandler, loading, loadingMore, maxNumberOfFiles, members, messages = [], multipleUploads, mutes, notifications, onLinkPreviewDismissed, pinnedMessages, quotedMessage, read = {}, shouldGenerateVideoThumbnail, skipMessageDataMemoization, suppressAutoscroll, thread, threadHasMore, threadLoadingMore, threadMessages = [], videoAttachmentSizeHandler, watcher_count, watcherCount, watchers, } = value;
|
|
5
5
|
const channelId = channel.cid;
|
|
6
6
|
const lastRead = channel.initialized && channel.lastRead()?.getTime();
|
|
7
7
|
const membersLength = Object.keys(members || []).length;
|
|
8
8
|
const notificationsLength = notifications.length;
|
|
9
9
|
const readUsers = Object.values(read);
|
|
10
10
|
const readUsersLength = readUsers.length;
|
|
11
|
-
const readUsersLastReads = readUsers
|
|
11
|
+
const readUsersLastReads = readUsers
|
|
12
|
+
.map(({ last_read }) => last_read.toISOString())
|
|
13
|
+
.join();
|
|
12
14
|
const threadMessagesLength = threadMessages?.length;
|
|
13
15
|
const channelCapabilities = {};
|
|
14
16
|
channelCapabilitiesArray.forEach((capability) => {
|
|
@@ -17,7 +19,7 @@ export const useCreateChannelStateContext = (value) => {
|
|
|
17
19
|
const memoizedMessageData = skipMessageDataMemoization
|
|
18
20
|
? messages
|
|
19
21
|
: messages
|
|
20
|
-
.map(({ deleted_at, latest_reactions, pinned, reply_count, status, updated_at, user }) => `${deleted_at}${latest_reactions ? latest_reactions.map(({ type }) => type).join() : ''}${pinned}${reply_count}${status}${updated_at && (isDayOrMoment(updated_at) || isDate(updated_at))
|
|
22
|
+
.map(({ deleted_at, latest_reactions, pinned, reply_count, status, updated_at, user, }) => `${deleted_at}${latest_reactions ? latest_reactions.map(({ type }) => type).join() : ''}${pinned}${reply_count}${status}${updated_at && (isDayOrMoment(updated_at) || isDate(updated_at))
|
|
21
23
|
? updated_at.toISOString()
|
|
22
24
|
: updated_at || ''}${user?.updated_at}`)
|
|
23
25
|
.join();
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
export declare const useIsMounted: () => import("react").
|
|
2
|
+
export declare const useIsMounted: () => import("react").RefObject<boolean>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
2
|
export const useMentionsHandlers = (onMentionsHover, onMentionsClick) => useCallback((event, mentioned_users) => {
|
|
3
|
-
if ((!onMentionsHover && !onMentionsClick) ||
|
|
3
|
+
if ((!onMentionsHover && !onMentionsClick) ||
|
|
4
|
+
!(event.target instanceof HTMLElement)) {
|
|
4
5
|
return;
|
|
5
6
|
}
|
|
6
7
|
const target = event.target;
|
|
@@ -13,7 +14,9 @@ export const useMentionsHandlers = (onMentionsHover, onMentionsClick) => useCall
|
|
|
13
14
|
event.type === 'mouseover') {
|
|
14
15
|
onMentionsHover(event, user);
|
|
15
16
|
}
|
|
16
|
-
if (onMentionsClick &&
|
|
17
|
+
if (onMentionsClick &&
|
|
18
|
+
event.type === 'click' &&
|
|
19
|
+
typeof onMentionsClick === 'function') {
|
|
17
20
|
onMentionsClick(event, user);
|
|
18
21
|
}
|
|
19
22
|
}
|
|
@@ -57,7 +57,8 @@ export const findInMsgSetByDate = (targetDate, msgSet, exact = false) => {
|
|
|
57
57
|
else
|
|
58
58
|
right = middle - 1;
|
|
59
59
|
}
|
|
60
|
-
if (!exact ||
|
|
60
|
+
if (!exact ||
|
|
61
|
+
new Date(msgSet[left].created_at).getTime() === targetTimestamp) {
|
|
61
62
|
return { index: left, target: msgSet[left] };
|
|
62
63
|
}
|
|
63
64
|
return { index: -1 };
|
|
@@ -9,7 +9,7 @@ import { useTranslationContext } from '../../context/TranslationContext';
|
|
|
9
9
|
* The ChannelHeader component renders some basic information about a Channel.
|
|
10
10
|
*/
|
|
11
11
|
export const ChannelHeader = (props) => {
|
|
12
|
-
const { Avatar = DefaultAvatar,
|
|
12
|
+
const { Avatar = DefaultAvatar, image: overrideImage, live, MenuIcon = DefaultMenuIcon, title: overrideTitle, } = props;
|
|
13
13
|
const { channel, watcher_count } = useChannelStateContext('ChannelHeader');
|
|
14
14
|
const { openMobileNav } = useChatContext('ChannelHeader');
|
|
15
15
|
const { t } = useTranslationContext('ChannelHeader');
|