stream-chat-react 12.10.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/hooks/useAudioController.js +3 -1
- 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 -3
- package/dist/components/AutoCompleteTextarea/utils.js +2 -2
- package/dist/components/Avatar/ChannelAvatar.js +1 -1
- package/dist/components/Channel/Channel.d.ts +1 -1
- package/dist/components/Channel/Channel.js +27 -12
- package/dist/components/Channel/channelState.js +9 -3
- package/dist/components/Channel/hooks/useCreateChannelStateContext.js +5 -3
- 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 +44 -17
- package/dist/components/ChannelList/hooks/useChannelUpdatedListener.js +2 -1
- package/dist/components/ChannelList/hooks/useMessageNewListener.js +3 -1
- package/dist/components/ChannelList/hooks/usePaginatedChannels.js +4 -2
- 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/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/Image.js +1 -1
- package/dist/components/Gallery/ModalGallery.js +1 -2
- package/dist/components/InfiniteScrollPaginator/InfiniteScroll.js +5 -2
- 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/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.js +3 -1
- package/dist/components/MessageInput/hooks/useSubmitHandler.js +5 -3
- 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 -5
- package/dist/components/MessageList/MessageListNotifications.js +3 -1
- package/dist/components/MessageList/VirtualizedMessageList.js +17 -10
- 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 +2 -1
- 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/usePrependMessagesCount.js +2 -1
- package/dist/components/MessageList/hooks/VirtualizedMessageList/useUnreadMessagesNotificationVirtualized.js +7 -3
- 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/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 +1771 -981
- package/dist/index.browser.cjs.map +4 -4
- package/dist/index.node.cjs +1772 -981
- 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 +21 -33
|
@@ -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)));
|
|
@@ -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;
|
|
@@ -111,7 +111,7 @@ export class ReactTextareaAutocomplete extends React.Component {
|
|
|
111
111
|
};
|
|
112
112
|
this._onSelect = (newToken) => {
|
|
113
113
|
const { closeCommandsList, closeMentionsList, onChange, showCommandsList, showMentionsList, } = this.props;
|
|
114
|
-
const { currentTrigger: stateTrigger, selectionEnd, value: textareaValue } = this.state;
|
|
114
|
+
const { currentTrigger: stateTrigger, selectionEnd, value: textareaValue, } = this.state;
|
|
115
115
|
const currentTrigger = showCommandsList ? '/' : showMentionsList ? '@' : stateTrigger;
|
|
116
116
|
if (!currentTrigger)
|
|
117
117
|
return;
|
|
@@ -313,7 +313,6 @@ export class ReactTextareaAutocomplete extends React.Component {
|
|
|
313
313
|
'trigger',
|
|
314
314
|
'value',
|
|
315
315
|
];
|
|
316
|
-
// eslint-disable-next-line
|
|
317
316
|
for (const prop in props) {
|
|
318
317
|
if (notSafe.includes(prop))
|
|
319
318
|
delete props[prop];
|
|
@@ -350,7 +349,8 @@ export class ReactTextareaAutocomplete extends React.Component {
|
|
|
350
349
|
const regex = new RegExp(`(?!^|\\W)?[${triggerTokens}]${triggerNorWhitespace}\\s?${triggerNorWhitespace}$`, 'g');
|
|
351
350
|
const tokenMatch = value.slice(0, selectionEnd).match(regex);
|
|
352
351
|
lastToken = tokenMatch && tokenMatch[tokenMatch.length - 1].trim();
|
|
353
|
-
currentTrigger =
|
|
352
|
+
currentTrigger =
|
|
353
|
+
(lastToken && Object.keys(trigger).find((a) => a === lastToken[0])) || null;
|
|
354
354
|
}
|
|
355
355
|
/*
|
|
356
356
|
if we lost the trigger token or there is no following character we want to close
|
|
@@ -6,10 +6,10 @@ export function defaultScrollToItem(container, item) {
|
|
|
6
6
|
const containerHight = parseInt(getComputedStyle(container).getPropertyValue('height'), 10) - itemHeight;
|
|
7
7
|
const actualScrollTop = container.scrollTop;
|
|
8
8
|
const itemOffsetTop = item.offsetTop;
|
|
9
|
-
if (itemOffsetTop < actualScrollTop + containerHight &&
|
|
9
|
+
if (itemOffsetTop < actualScrollTop + containerHight &&
|
|
10
|
+
actualScrollTop < itemOffsetTop) {
|
|
10
11
|
return;
|
|
11
12
|
}
|
|
12
|
-
// eslint-disable-next-line
|
|
13
13
|
container.scrollTop = itemOffsetTop;
|
|
14
14
|
}
|
|
15
15
|
export const errorMessage = (message) => console.error(`RTA: dataProvider fails: ${message}
|
|
@@ -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[];
|
|
@@ -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();
|
|
@@ -115,7 +115,14 @@ const ChannelInner = (props) => {
|
|
|
115
115
|
catch (e) {
|
|
116
116
|
console.error(t('Failed to mark channel as read'));
|
|
117
117
|
}
|
|
118
|
-
}, 500, { leading: true, trailing: false }), [
|
|
118
|
+
}, 500, { leading: true, trailing: false }), [
|
|
119
|
+
activeUnreadHandler,
|
|
120
|
+
channel,
|
|
121
|
+
channelConfig,
|
|
122
|
+
doMarkReadRequest,
|
|
123
|
+
setChannelUnreadUiState,
|
|
124
|
+
t,
|
|
125
|
+
]);
|
|
119
126
|
const handleEvent = async (event) => {
|
|
120
127
|
if (event.message) {
|
|
121
128
|
dispatch({
|
|
@@ -135,7 +142,9 @@ const ChannelInner = (props) => {
|
|
|
135
142
|
if (event.type === 'message.new') {
|
|
136
143
|
const mainChannelUpdated = !event.message?.parent_id || event.message?.show_in_channel;
|
|
137
144
|
if (mainChannelUpdated) {
|
|
138
|
-
if (document.hidden &&
|
|
145
|
+
if (document.hidden &&
|
|
146
|
+
channelConfig?.read_events &&
|
|
147
|
+
!channel.muteStatus().muted) {
|
|
139
148
|
const unread = channel.countUnread(lastRead.current);
|
|
140
149
|
if (activeUnreadHandler) {
|
|
141
150
|
activeUnreadHandler(unread, originalTitle.current);
|
|
@@ -283,11 +292,15 @@ const ChannelInner = (props) => {
|
|
|
283
292
|
dispatch({ hasMore, messages, type: 'loadMoreFinished' });
|
|
284
293
|
}, 2000, { leading: true, trailing: true }), []);
|
|
285
294
|
const loadMore = async (limit = DEFAULT_NEXT_CHANNEL_PAGE_SIZE) => {
|
|
286
|
-
if (!online.current ||
|
|
295
|
+
if (!online.current ||
|
|
296
|
+
!window.navigator.onLine ||
|
|
297
|
+
!channel.state.messagePagination.hasPrev)
|
|
287
298
|
return 0;
|
|
288
299
|
// prevent duplicate loading events...
|
|
289
300
|
const oldestMessage = state?.messages?.[0];
|
|
290
|
-
if (state.loadingMore ||
|
|
301
|
+
if (state.loadingMore ||
|
|
302
|
+
state.loadingMoreNewer ||
|
|
303
|
+
oldestMessage?.status !== 'received') {
|
|
291
304
|
return 0;
|
|
292
305
|
}
|
|
293
306
|
dispatch({ loadingMore: true, type: 'setLoadingMore' });
|
|
@@ -309,7 +322,9 @@ const ChannelInner = (props) => {
|
|
|
309
322
|
return queryResponse.messages.length;
|
|
310
323
|
};
|
|
311
324
|
const loadMoreNewer = async (limit = DEFAULT_NEXT_CHANNEL_PAGE_SIZE) => {
|
|
312
|
-
if (!online.current ||
|
|
325
|
+
if (!online.current ||
|
|
326
|
+
!window.navigator.onLine ||
|
|
327
|
+
!channel.state.messagePagination.hasNext)
|
|
313
328
|
return 0;
|
|
314
329
|
const newestMessage = state?.messages?.[state?.messages?.length - 1];
|
|
315
330
|
if (state.loadingMore || state.loadingMoreNewer)
|
|
@@ -539,9 +554,7 @@ const ChannelInner = (props) => {
|
|
|
539
554
|
catch (error) {
|
|
540
555
|
// error response isn't usable so needs to be stringified then parsed
|
|
541
556
|
const stringError = JSON.stringify(error);
|
|
542
|
-
const parsedError = (stringError
|
|
543
|
-
? JSON.parse(stringError)
|
|
544
|
-
: {});
|
|
557
|
+
const parsedError = (stringError ? JSON.parse(stringError) : {});
|
|
545
558
|
// Handle the case where the message already exists
|
|
546
559
|
// (typically, when retrying to send a message).
|
|
547
560
|
// If the message already exists, we can assume it was sent successfully,
|
|
@@ -565,7 +578,7 @@ const ChannelInner = (props) => {
|
|
|
565
578
|
status: 'failed',
|
|
566
579
|
});
|
|
567
580
|
thread?.upsertReplyLocally({
|
|
568
|
-
// @ts-expect-error
|
|
581
|
+
// @ts-expect-error message type mismatch
|
|
569
582
|
message: {
|
|
570
583
|
...message,
|
|
571
584
|
error: parsedError,
|
|
@@ -592,7 +605,7 @@ const ChannelInner = (props) => {
|
|
|
592
605
|
user: client.user,
|
|
593
606
|
};
|
|
594
607
|
thread?.upsertReplyLocally({
|
|
595
|
-
// @ts-expect-error
|
|
608
|
+
// @ts-expect-error message type mismatch
|
|
596
609
|
message: messagePreview,
|
|
597
610
|
});
|
|
598
611
|
updateMessage(messagePreview);
|
|
@@ -733,7 +746,7 @@ const ChannelInner = (props) => {
|
|
|
733
746
|
jumpToLatestMessage,
|
|
734
747
|
setChannelUnreadUiState,
|
|
735
748
|
]);
|
|
736
|
-
// @ts-expect-error
|
|
749
|
+
// @ts-expect-error message type mismatch
|
|
737
750
|
const componentContextValue = useMemo(() => ({
|
|
738
751
|
Attachment: props.Attachment,
|
|
739
752
|
AttachmentPreviewList: props.AttachmentPreviewList,
|
|
@@ -781,6 +794,7 @@ const ChannelInner = (props) => {
|
|
|
781
794
|
reactionOptions: props.reactionOptions,
|
|
782
795
|
ReactionSelector: props.ReactionSelector,
|
|
783
796
|
ReactionsList: props.ReactionsList,
|
|
797
|
+
ReactionsListModal: props.ReactionsListModal,
|
|
784
798
|
SendButton: props.SendButton,
|
|
785
799
|
StartRecordingAudioButton: props.StartRecordingAudioButton,
|
|
786
800
|
StopAIGenerationButton: props.StopAIGenerationButton,
|
|
@@ -839,6 +853,7 @@ const ChannelInner = (props) => {
|
|
|
839
853
|
props.QuotedPoll,
|
|
840
854
|
props.ReactionSelector,
|
|
841
855
|
props.ReactionsList,
|
|
856
|
+
props.ReactionsListModal,
|
|
842
857
|
props.SendButton,
|
|
843
858
|
props.StartRecordingAudioButton,
|
|
844
859
|
props.ThreadHead,
|
|
@@ -103,7 +103,9 @@ export const makeChannelReducer = () => (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 makeChannelReducer = () => (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,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');
|
|
@@ -3,10 +3,10 @@ import clsx from 'clsx';
|
|
|
3
3
|
import { ChannelListMessenger } from './ChannelListMessenger';
|
|
4
4
|
import { useConnectionRecoveredListener } from './hooks/useConnectionRecoveredListener';
|
|
5
5
|
import { useMobileNavigation } from './hooks/useMobileNavigation';
|
|
6
|
-
import { usePaginatedChannels } from './hooks/usePaginatedChannels';
|
|
6
|
+
import { usePaginatedChannels, } from './hooks/usePaginatedChannels';
|
|
7
7
|
import { MAX_QUERY_CHANNELS_LIMIT, moveChannelUpwards } from './utils';
|
|
8
8
|
import { Avatar as DefaultAvatar } from '../Avatar';
|
|
9
|
-
import { ChannelPreview } from '../ChannelPreview/ChannelPreview';
|
|
9
|
+
import { ChannelPreview, } from '../ChannelPreview/ChannelPreview';
|
|
10
10
|
import { ChannelSearch as DefaultChannelSearch, } from '../ChannelSearch/ChannelSearch';
|
|
11
11
|
import { EmptyStateIndicator as DefaultEmptyStateIndicator, } from '../EmptyStateIndicator';
|
|
12
12
|
import { LoadingChannels } from '../Loading/LoadingChannels';
|
|
@@ -14,12 +14,12 @@ import { LoadMorePaginator } from '../LoadMore/LoadMorePaginator';
|
|
|
14
14
|
import { NullComponent } from '../UtilityComponents';
|
|
15
15
|
import { ChannelListContextProvider } from '../../context';
|
|
16
16
|
import { useChatContext } from '../../context/ChatContext';
|
|
17
|
-
import { useChannelListShape, usePrepareShapeHandlers } from './hooks/useChannelListShape';
|
|
17
|
+
import { useChannelListShape, usePrepareShapeHandlers, } from './hooks/useChannelListShape';
|
|
18
18
|
const DEFAULT_FILTERS = {};
|
|
19
19
|
const DEFAULT_OPTIONS = {};
|
|
20
20
|
const DEFAULT_SORT = {};
|
|
21
21
|
const UnMemoizedChannelList = (props) => {
|
|
22
|
-
const { additionalChannelSearchProps,
|
|
22
|
+
const { additionalChannelSearchProps, allowNewMessagesFromUnfilteredChannels = true, Avatar = DefaultAvatar, channelRenderFilterFn, ChannelSearch = DefaultChannelSearch, customActiveChannel, customQueryChannels, EmptyStateIndicator = DefaultEmptyStateIndicator, filters = {}, getLatestMessagePreview, List = ChannelListMessenger, LoadingErrorIndicator = NullComponent, LoadingIndicator = LoadingChannels, lockChannelOrder = false, onAddedToChannel, onChannelDeleted, onChannelHidden, onChannelTruncated, onChannelUpdated, onChannelVisible, onMessageNew, onMessageNewHandler, onRemovedFromChannel, options, Paginator = LoadMorePaginator, Preview, recoveryThrottleIntervalMs, renderChannels, sendChannelsToList = false, setActiveChannelOnMount = true, showChannelSearch = false, sort = DEFAULT_SORT, watchers = {}, } = props;
|
|
23
23
|
const { channel, channelsQueryState, client, closeMobileNav, customClasses, navOpen = false, setActiveChannel, theme, useImageFlagEmojisOnWindows, } = useChatContext('ChannelList');
|
|
24
24
|
const channelListRef = useRef(null);
|
|
25
25
|
const [channelUpdateCount, setChannelUpdateCount] = useState(0);
|
|
@@ -29,15 +29,18 @@ const UnMemoizedChannelList = (props) => {
|
|
|
29
29
|
* If customActiveChannel prop is absent, then set the first channel in list as active channel.
|
|
30
30
|
*/
|
|
31
31
|
const activeChannelHandler = async (channels, setChannels) => {
|
|
32
|
-
if (!channels.length ||
|
|
32
|
+
if (!channels.length ||
|
|
33
|
+
channels.length > (options?.limit || MAX_QUERY_CHANNELS_LIMIT)) {
|
|
33
34
|
return;
|
|
34
35
|
}
|
|
35
36
|
if (customActiveChannel) {
|
|
36
37
|
// FIXME: this is wrong...
|
|
37
38
|
let customActiveChannelObject = channels.find((chan) => chan.id === customActiveChannel);
|
|
38
39
|
if (!customActiveChannelObject) {
|
|
39
|
-
//@ts-expect-error
|
|
40
|
-
[customActiveChannelObject] = await client.queryChannels({
|
|
40
|
+
//@ts-expect-error valid query
|
|
41
|
+
[customActiveChannelObject] = await client.queryChannels({
|
|
42
|
+
id: customActiveChannel,
|
|
43
|
+
});
|
|
41
44
|
}
|
|
42
45
|
if (customActiveChannelObject) {
|
|
43
46
|
setActiveChannel(customActiveChannelObject, watchers);
|
|
@@ -70,7 +73,9 @@ const UnMemoizedChannelList = (props) => {
|
|
|
70
73
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
71
74
|
}, []);
|
|
72
75
|
const { channels, hasNextPage, loadNextPage, setChannels } = usePaginatedChannels(client, filters || DEFAULT_FILTERS, sort || DEFAULT_SORT, options || DEFAULT_OPTIONS, activeChannelHandler, recoveryThrottleIntervalMs, customQueryChannels);
|
|
73
|
-
const loadedChannels = channelRenderFilterFn
|
|
76
|
+
const loadedChannels = channelRenderFilterFn
|
|
77
|
+
? channelRenderFilterFn(channels)
|
|
78
|
+
: channels;
|
|
74
79
|
useMobileNavigation(channelListRef, navOpen, closeMobileNav);
|
|
75
80
|
const { customHandler, defaultHandler } = usePrepareShapeHandlers({
|
|
76
81
|
allowNewMessagesFromUnfilteredChannels,
|
|
@@ -27,7 +27,7 @@ type HandleMemberUpdatedParameters<SCG extends ExtendableGenerics> = BaseParamet
|
|
|
27
27
|
} & Required<Pick<ChannelListProps<SCG>, 'sort' | 'filters'>>;
|
|
28
28
|
type HandleChannelDeletedParameters<SCG extends ExtendableGenerics> = BaseParameters<SCG> & RepeatedParameters<SCG>;
|
|
29
29
|
type HandleChannelHiddenParameters<SCG extends ExtendableGenerics> = BaseParameters<SCG> & RepeatedParameters<SCG>;
|
|
30
|
-
type HandleChannelVisibleParameters<SCG extends ExtendableGenerics> = BaseParameters<SCG> & RepeatedParameters<SCG
|
|
30
|
+
type HandleChannelVisibleParameters<SCG extends ExtendableGenerics> = BaseParameters<SCG> & RepeatedParameters<SCG> & Required<Pick<ChannelListProps<SCG>, 'sort' | 'filters'>>;
|
|
31
31
|
type HandleChannelTruncatedParameters<SCG extends ExtendableGenerics> = BaseParameters<SCG> & RepeatedParameters<SCG>;
|
|
32
32
|
type HandleChannelUpdatedParameters<SCG extends ExtendableGenerics> = BaseParameters<SCG> & RepeatedParameters<SCG>;
|
|
33
33
|
type HandleUserPresenceChangedParameters<SCG extends ExtendableGenerics> = BaseParameters<SCG>;
|
|
@@ -36,7 +36,7 @@ export declare const useChannelListShapeDefaults: <SCG extends ExtendableGeneric
|
|
|
36
36
|
handleChannelHidden: (p: HandleChannelHiddenParameters<SCG>) => void;
|
|
37
37
|
handleChannelTruncated: ({ customHandler, event, setChannels }: HandleChannelTruncatedParameters<SCG>) => void;
|
|
38
38
|
handleChannelUpdated: ({ customHandler, event, setChannels }: HandleChannelUpdatedParameters<SCG>) => void;
|
|
39
|
-
handleChannelVisible: ({ customHandler, event, setChannels }: HandleChannelVisibleParameters<SCG>) => Promise<void>;
|
|
39
|
+
handleChannelVisible: ({ customHandler, event, filters, setChannels, sort, }: HandleChannelVisibleParameters<SCG>) => Promise<void>;
|
|
40
40
|
handleMemberUpdated: ({ event, filters, lockChannelOrder, setChannels, sort, }: HandleMemberUpdatedParameters<SCG>) => void;
|
|
41
41
|
handleMessageNew: ({ allowNewMessagesFromUnfilteredChannels, customHandler, event, filters, lockChannelOrder, setChannels, sort, }: HandleMessageNewParameters<SCG>) => void;
|
|
42
42
|
handleNotificationAddedToChannel: ({ allowNewMessagesFromUnfilteredChannels, customHandler, event, setChannels, sort, }: HandleNotificationAddedToChannelParameters<SCG>) => Promise<void>;
|