stream-chat-react 12.6.2 → 12.7.1
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/AIStateIndicator/AIStateIndicator.d.ts +7 -0
- package/dist/components/AIStateIndicator/AIStateIndicator.js +15 -0
- package/dist/components/AIStateIndicator/hooks/useAIState.d.ts +17 -0
- package/dist/components/AIStateIndicator/hooks/useAIState.js +39 -0
- package/dist/components/AIStateIndicator/index.d.ts +2 -0
- package/dist/components/AIStateIndicator/index.js +2 -0
- package/dist/components/Channel/Channel.d.ts +1 -1
- package/dist/components/Channel/Channel.js +4 -0
- package/dist/components/ChannelList/ChannelList.d.ts +2 -1
- package/dist/components/ChannelPreview/ChannelPreview.js +2 -2
- package/dist/components/ChannelPreview/utils.d.ts +2 -1
- package/dist/components/ChannelPreview/utils.js +4 -2
- package/dist/components/Chat/Chat.d.ts +2 -1
- package/dist/components/Chat/Chat.js +2 -1
- package/dist/components/Chat/hooks/useChat.js +1 -1
- package/dist/components/Chat/hooks/useCreateChatContext.js +3 -1
- package/dist/components/Message/Message.js +2 -1
- package/dist/components/Message/MessageSimple.js +10 -5
- package/dist/components/Message/StreamedMessageText.d.ts +8 -0
- package/dist/components/Message/StreamedMessageText.js +16 -0
- package/dist/components/Message/hooks/index.d.ts +1 -0
- package/dist/components/Message/hooks/index.js +1 -0
- package/dist/components/Message/hooks/useMessageTextStreaming.d.ts +16 -0
- package/dist/components/Message/hooks/useMessageTextStreaming.js +31 -0
- package/dist/components/Message/index.d.ts +1 -0
- package/dist/components/Message/index.js +1 -0
- package/dist/components/Message/renderText/renderText.js +7 -0
- package/dist/components/MessageInput/MessageInputFlat.js +16 -3
- package/dist/components/MessageInput/StopAIGenerationButton.d.ts +3 -0
- package/dist/components/MessageInput/StopAIGenerationButton.js +6 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +1 -0
- package/dist/context/ChatContext.d.ts +1 -1
- package/dist/context/ComponentContext.d.ts +4 -1
- package/dist/context/MessageContext.d.ts +4 -0
- package/dist/css/v2/index.css +2 -2
- package/dist/css/v2/index.layout.css +2 -2
- package/dist/experimental/index.browser.cjs.map +2 -2
- package/dist/experimental/index.node.cjs.map +2 -2
- package/dist/i18n/Streami18n.d.ts +3 -0
- package/dist/i18n/de.json +3 -0
- package/dist/i18n/en.json +3 -0
- package/dist/i18n/es.json +3 -0
- package/dist/i18n/fr.json +3 -0
- package/dist/i18n/hi.json +3 -0
- package/dist/i18n/it.json +3 -0
- package/dist/i18n/ja.json +3 -0
- package/dist/i18n/ko.json +3 -0
- package/dist/i18n/nl.json +3 -0
- package/dist/i18n/pt.json +3 -0
- package/dist/i18n/ru.json +3 -0
- package/dist/i18n/tr.json +3 -0
- package/dist/index.browser.cjs +1291 -1088
- package/dist/index.browser.cjs.map +4 -4
- package/dist/index.node.cjs +1209 -1001
- package/dist/index.node.cjs.map +4 -4
- package/dist/scss/v2/AIStateIndicator/AIStateIndicator-layout.scss +3 -0
- package/dist/scss/v2/AIStateIndicator/AIStateIndicator-theme.scss +7 -0
- package/dist/scss/v2/MessageInput/MessageInput-layout.scss +7 -1
- package/dist/scss/v2/MessageInput/MessageInput-theme.scss +9 -3
- package/dist/scss/v2/_icons.scss +1 -0
- package/dist/scss/v2/index.layout.scss +1 -0
- package/dist/scss/v2/index.scss +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Channel } from 'stream-chat';
|
|
3
|
+
import type { DefaultStreamChatGenerics } from '../../types/types';
|
|
4
|
+
export type AIStateIndicatorProps<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> = {
|
|
5
|
+
channel?: Channel<StreamChatGenerics>;
|
|
6
|
+
};
|
|
7
|
+
export declare const AIStateIndicator: <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>({ channel: channelFromProps, }: AIStateIndicatorProps<StreamChatGenerics>) => React.JSX.Element | null;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { AIStates, useAIState } from './hooks/useAIState';
|
|
3
|
+
import { useChannelStateContext, useTranslationContext } from '../../context';
|
|
4
|
+
export const AIStateIndicator = ({ channel: channelFromProps, }) => {
|
|
5
|
+
const { t } = useTranslationContext();
|
|
6
|
+
const { channel: channelFromContext } = useChannelStateContext('AIStateIndicator');
|
|
7
|
+
const channel = channelFromProps || channelFromContext;
|
|
8
|
+
const { aiState } = useAIState(channel);
|
|
9
|
+
const allowedStates = {
|
|
10
|
+
[AIStates.Thinking]: t('Thinking...'),
|
|
11
|
+
[AIStates.Generating]: t('Generating...'),
|
|
12
|
+
};
|
|
13
|
+
return aiState in allowedStates ? (React.createElement("div", { className: 'str-chat__ai-state-indicator-container' },
|
|
14
|
+
React.createElement("p", { className: 'str-chat__ai-state-indicator-text' }, allowedStates[aiState]))) : null;
|
|
15
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AIState, Channel } from 'stream-chat';
|
|
2
|
+
import type { DefaultStreamChatGenerics } from '../../../types/types';
|
|
3
|
+
export declare const AIStates: {
|
|
4
|
+
Error: string;
|
|
5
|
+
ExternalSources: string;
|
|
6
|
+
Generating: string;
|
|
7
|
+
Idle: string;
|
|
8
|
+
Thinking: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* A hook that returns the current state of the AI.
|
|
12
|
+
* @param {Channel} channel - The channel for which we want to know the AI state.
|
|
13
|
+
* @returns {{ aiState: AIState }} The current AI state for the given channel.
|
|
14
|
+
*/
|
|
15
|
+
export declare const useAIState: <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>(channel?: Channel<StreamChatGenerics>) => {
|
|
16
|
+
aiState: AIState;
|
|
17
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
export const AIStates = {
|
|
3
|
+
Error: 'AI_STATE_ERROR',
|
|
4
|
+
ExternalSources: 'AI_STATE_EXTERNAL_SOURCES',
|
|
5
|
+
Generating: 'AI_STATE_GENERATING',
|
|
6
|
+
Idle: 'AI_STATE_IDLE',
|
|
7
|
+
Thinking: 'AI_STATE_THINKING',
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* A hook that returns the current state of the AI.
|
|
11
|
+
* @param {Channel} channel - The channel for which we want to know the AI state.
|
|
12
|
+
* @returns {{ aiState: AIState }} The current AI state for the given channel.
|
|
13
|
+
*/
|
|
14
|
+
export const useAIState = (channel) => {
|
|
15
|
+
const [aiState, setAiState] = useState(AIStates.Idle);
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (!channel) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const indicatorChangedListener = channel.on('ai_indicator.update', (event) => {
|
|
21
|
+
const { cid } = event;
|
|
22
|
+
const state = event.ai_state;
|
|
23
|
+
if (channel.cid === cid) {
|
|
24
|
+
setAiState(state);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
const indicatorClearedListener = channel.on('ai_indicator.clear', (event) => {
|
|
28
|
+
const { cid } = event;
|
|
29
|
+
if (channel.cid === cid) {
|
|
30
|
+
setAiState(AIStates.Idle);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return () => {
|
|
34
|
+
indicatorChangedListener.unsubscribe();
|
|
35
|
+
indicatorClearedListener.unsubscribe();
|
|
36
|
+
};
|
|
37
|
+
}, [channel]);
|
|
38
|
+
return { aiState };
|
|
39
|
+
};
|
|
@@ -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'>;
|
|
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'>;
|
|
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[];
|
|
@@ -782,6 +782,8 @@ const ChannelInner = (props) => {
|
|
|
782
782
|
ReactionsList: props.ReactionsList,
|
|
783
783
|
SendButton: props.SendButton,
|
|
784
784
|
StartRecordingAudioButton: props.StartRecordingAudioButton,
|
|
785
|
+
StopAIGenerationButton: props.StopAIGenerationButton,
|
|
786
|
+
StreamedMessageText: props.StreamedMessageText,
|
|
785
787
|
ThreadHead: props.ThreadHead,
|
|
786
788
|
ThreadHeader: props.ThreadHeader,
|
|
787
789
|
ThreadStart: props.ThreadStart,
|
|
@@ -847,6 +849,8 @@ const ChannelInner = (props) => {
|
|
|
847
849
|
props.UnreadMessagesNotification,
|
|
848
850
|
props.UnreadMessagesSeparator,
|
|
849
851
|
props.VirtualMessage,
|
|
852
|
+
props.StopAIGenerationButton,
|
|
853
|
+
props.StreamedMessageText,
|
|
850
854
|
props.emojiSearchIndex,
|
|
851
855
|
props.reactionOptions,
|
|
852
856
|
]);
|
|
@@ -5,6 +5,7 @@ import { ChannelPreviewUIComponentProps } from '../ChannelPreview/ChannelPreview
|
|
|
5
5
|
import { ChannelSearchProps } from '../ChannelSearch/ChannelSearch';
|
|
6
6
|
import { EmptyStateIndicatorProps } from '../EmptyStateIndicator';
|
|
7
7
|
import { LoadMorePaginatorProps } from '../LoadMore/LoadMorePaginator';
|
|
8
|
+
import { ChatContextValue } from '../../context';
|
|
8
9
|
import type { Channel, ChannelFilters, ChannelOptions, ChannelSort, Event } from 'stream-chat';
|
|
9
10
|
import type { ChannelAvatarProps } from '../Avatar';
|
|
10
11
|
import type { TranslationContextValue } from '../../context/TranslationContext';
|
|
@@ -34,7 +35,7 @@ export type ChannelListProps<StreamChatGenerics extends DefaultStreamChatGeneric
|
|
|
34
35
|
/** An object containing channel query filters */
|
|
35
36
|
filters?: ChannelFilters<StreamChatGenerics>;
|
|
36
37
|
/** Custom function that generates the message preview in ChannelPreview component */
|
|
37
|
-
getLatestMessagePreview?: (channel: Channel<StreamChatGenerics>, t: TranslationContextValue['t'], userLanguage: TranslationContextValue['userLanguage']) => string | JSX.Element;
|
|
38
|
+
getLatestMessagePreview?: (channel: Channel<StreamChatGenerics>, t: TranslationContextValue['t'], userLanguage: TranslationContextValue['userLanguage'], isMessageAIGenerated?: ChatContextValue['isMessageAIGenerated']) => string | JSX.Element;
|
|
38
39
|
/** Custom UI component to display the container for the queried channels, defaults to and accepts same props as: [ChannelListMessenger](https://github.com/GetStream/stream-chat-react/blob/master/src/components/ChannelList/ChannelListMessenger.tsx) */
|
|
39
40
|
List?: React.ComponentType<ChannelListMessengerProps<StreamChatGenerics>>;
|
|
40
41
|
/** Custom UI component to display the loading error indicator, defaults to component that renders null */
|
|
@@ -9,7 +9,7 @@ import { useTranslationContext } from '../../context/TranslationContext';
|
|
|
9
9
|
import { useMessageDeliveryStatus } from './hooks/useMessageDeliveryStatus';
|
|
10
10
|
export const ChannelPreview = (props) => {
|
|
11
11
|
const { channel, Preview = ChannelPreviewMessenger, channelUpdateCount, getLatestMessagePreview = defaultGetLatestMessagePreview, } = props;
|
|
12
|
-
const { channel: activeChannel, client, setActiveChannel } = useChatContext('ChannelPreview');
|
|
12
|
+
const { channel: activeChannel, client, isMessageAIGenerated, setActiveChannel, } = useChatContext('ChannelPreview');
|
|
13
13
|
const { t, userLanguage } = useTranslationContext('ChannelPreview');
|
|
14
14
|
const { displayImage, displayTitle, groupChannelDisplayInfo } = useChannelPreviewInfo({
|
|
15
15
|
channel,
|
|
@@ -75,6 +75,6 @@ export const ChannelPreview = (props) => {
|
|
|
75
75
|
}, [channel, refreshUnreadCount, channelUpdateCount]);
|
|
76
76
|
if (!Preview)
|
|
77
77
|
return null;
|
|
78
|
-
const latestMessagePreview = getLatestMessagePreview(channel, t, userLanguage);
|
|
78
|
+
const latestMessagePreview = getLatestMessagePreview(channel, t, userLanguage, isMessageAIGenerated);
|
|
79
79
|
return (React.createElement(Preview, { ...props, active: isActive, displayImage: displayImage, displayTitle: displayTitle, groupChannelDisplayInfo: groupChannelDisplayInfo, lastMessage: lastMessage, latestMessage: latestMessagePreview, latestMessagePreview: latestMessagePreview, messageDeliveryStatus: messageDeliveryStatus, setActiveChannel: setActiveChannel, unread: unread }));
|
|
80
80
|
};
|
|
@@ -2,8 +2,9 @@ import React from 'react';
|
|
|
2
2
|
import type { Channel, UserResponse } from 'stream-chat';
|
|
3
3
|
import type { TranslationContextValue } from '../../context/TranslationContext';
|
|
4
4
|
import type { DefaultStreamChatGenerics } from '../../types/types';
|
|
5
|
+
import { ChatContextValue } from '../../context';
|
|
5
6
|
export declare const renderPreviewText: (text: string) => React.JSX.Element;
|
|
6
|
-
export declare const getLatestMessagePreview: <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>(channel: Channel<StreamChatGenerics>, t: TranslationContextValue['t'], userLanguage?: TranslationContextValue['userLanguage']) => string | JSX.Element;
|
|
7
|
+
export declare const getLatestMessagePreview: <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>(channel: Channel<StreamChatGenerics>, t: TranslationContextValue['t'], userLanguage?: TranslationContextValue['userLanguage'], isMessageAIGenerated?: ChatContextValue<StreamChatGenerics>['isMessageAIGenerated']) => string | JSX.Element;
|
|
7
8
|
export type GroupChannelDisplayInfo = {
|
|
8
9
|
image?: string;
|
|
9
10
|
name?: string;
|
|
@@ -12,7 +12,7 @@ const getLatestPollVote = (latestVotesByOption) => {
|
|
|
12
12
|
}
|
|
13
13
|
return latestVote;
|
|
14
14
|
};
|
|
15
|
-
export const getLatestMessagePreview = (channel, t, userLanguage = 'en') => {
|
|
15
|
+
export const getLatestMessagePreview = (channel, t, userLanguage = 'en', isMessageAIGenerated) => {
|
|
16
16
|
const latestMessage = channel.state.latestMessages[channel.state.latestMessages.length - 1];
|
|
17
17
|
const previewTextToRender = latestMessage?.i18n?.[`${userLanguage}_text`] ||
|
|
18
18
|
latestMessage?.text;
|
|
@@ -47,7 +47,9 @@ export const getLatestMessagePreview = (channel, t, userLanguage = 'en') => {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
if (previewTextToRender) {
|
|
50
|
-
return
|
|
50
|
+
return isMessageAIGenerated?.(latestMessage)
|
|
51
|
+
? previewTextToRender
|
|
52
|
+
: renderPreviewText(previewTextToRender);
|
|
51
53
|
}
|
|
52
54
|
if (latestMessage.command) {
|
|
53
55
|
return `/${latestMessage.command}`;
|
|
@@ -4,6 +4,7 @@ import type { StreamChat } from 'stream-chat';
|
|
|
4
4
|
import type { SupportedTranslations } from '../../i18n/types';
|
|
5
5
|
import type { Streami18n } from '../../i18n/Streami18n';
|
|
6
6
|
import type { DefaultStreamChatGenerics } from '../../types/types';
|
|
7
|
+
import type { MessageContextValue } from '../../context';
|
|
7
8
|
export type ChatProps<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> = {
|
|
8
9
|
/** The StreamChat client object */
|
|
9
10
|
client: StreamChat<StreamChatGenerics>;
|
|
@@ -25,7 +26,7 @@ export type ChatProps<StreamChatGenerics extends DefaultStreamChatGenerics = Def
|
|
|
25
26
|
* Note: requires importing `stream-chat-react/css/v2/emoji-replacement.css` style sheet
|
|
26
27
|
*/
|
|
27
28
|
useImageFlagEmojisOnWindows?: boolean;
|
|
28
|
-
}
|
|
29
|
+
} & Partial<Pick<MessageContextValue<StreamChatGenerics>, 'isMessageAIGenerated'>>;
|
|
29
30
|
/**
|
|
30
31
|
* Wrapper component for a StreamChat application. Chat needs to be placed around any other chat components
|
|
31
32
|
* as it provides the ChatContext.
|
|
@@ -9,7 +9,7 @@ import { TranslationProvider } from '../../context/TranslationContext';
|
|
|
9
9
|
* as it provides the ChatContext.
|
|
10
10
|
*/
|
|
11
11
|
export const Chat = (props) => {
|
|
12
|
-
const { children, client, customClasses, defaultLanguage, i18nInstance, initialNavOpen = true, theme = 'messaging light', useImageFlagEmojisOnWindows = false, } = props;
|
|
12
|
+
const { children, client, customClasses, defaultLanguage, i18nInstance, initialNavOpen = true, isMessageAIGenerated, theme = 'messaging light', useImageFlagEmojisOnWindows = false, } = props;
|
|
13
13
|
const { channel, closeMobileNav, getAppSettings, latestMessageDatesByChannels, mutes, navOpen, openMobileNav, setActiveChannel, translators, } = useChat({ client, defaultLanguage, i18nInstance, initialNavOpen });
|
|
14
14
|
const channelsQueryState = useChannelsQueryState();
|
|
15
15
|
const chatContextValue = useCreateChatContext({
|
|
@@ -19,6 +19,7 @@ export const Chat = (props) => {
|
|
|
19
19
|
closeMobileNav,
|
|
20
20
|
customClasses,
|
|
21
21
|
getAppSettings,
|
|
22
|
+
isMessageAIGenerated,
|
|
22
23
|
latestMessageDatesByChannels,
|
|
23
24
|
mutes,
|
|
24
25
|
navOpen,
|
|
@@ -28,7 +28,7 @@ export const useChat = ({ client, defaultLanguage = 'en', i18nInstance, initialN
|
|
|
28
28
|
if (!userAgent.includes('stream-chat-react')) {
|
|
29
29
|
// result looks like: 'stream-chat-react-2.3.2-stream-chat-javascript-client-browser-2.2.2'
|
|
30
30
|
// the upper-case text between double underscores is replaced with the actual semantic version of the library
|
|
31
|
-
client.setUserAgent(`stream-chat-react-12.
|
|
31
|
+
client.setUserAgent(`stream-chat-react-12.7.1-${userAgent}`);
|
|
32
32
|
}
|
|
33
33
|
client.threads.registerSubscriptions();
|
|
34
34
|
client.polls.registerSubscriptions();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
2
|
export const useCreateChatContext = (value) => {
|
|
3
|
-
const { channel, channelsQueryState, client, closeMobileNav, customClasses, getAppSettings, latestMessageDatesByChannels, mutes, navOpen, openMobileNav, setActiveChannel, theme, useImageFlagEmojisOnWindows, } = value;
|
|
3
|
+
const { channel, channelsQueryState, client, closeMobileNav, customClasses, getAppSettings, isMessageAIGenerated, latestMessageDatesByChannels, mutes, navOpen, openMobileNav, setActiveChannel, theme, useImageFlagEmojisOnWindows, } = value;
|
|
4
4
|
const channelCid = channel?.cid;
|
|
5
5
|
const channelsQueryError = channelsQueryState.error;
|
|
6
6
|
const channelsQueryInProgress = channelsQueryState.queryInProgress;
|
|
@@ -14,6 +14,7 @@ export const useCreateChatContext = (value) => {
|
|
|
14
14
|
closeMobileNav,
|
|
15
15
|
customClasses,
|
|
16
16
|
getAppSettings,
|
|
17
|
+
isMessageAIGenerated,
|
|
17
18
|
latestMessageDatesByChannels,
|
|
18
19
|
mutes,
|
|
19
20
|
navOpen,
|
|
@@ -31,6 +32,7 @@ export const useCreateChatContext = (value) => {
|
|
|
31
32
|
getAppSettings,
|
|
32
33
|
mutedUsersLength,
|
|
33
34
|
navOpen,
|
|
35
|
+
isMessageAIGenerated,
|
|
34
36
|
]);
|
|
35
37
|
return chatContext;
|
|
36
38
|
};
|
|
@@ -5,7 +5,7 @@ import { MessageProvider, useChannelActionContext, useChannelStateContext, useCh
|
|
|
5
5
|
import { MessageSimple as DefaultMessage } from './MessageSimple';
|
|
6
6
|
const MessageWithContext = (props) => {
|
|
7
7
|
const { canPin, groupedByUser, Message: propMessage, message, messageActions = Object.keys(MESSAGE_ACTIONS), onUserClick: propOnUserClick, onUserHover: propOnUserHover, userRoles, } = props;
|
|
8
|
-
const { client } = useChatContext('Message');
|
|
8
|
+
const { client, isMessageAIGenerated } = useChatContext('Message');
|
|
9
9
|
const { read } = useChannelStateContext('Message');
|
|
10
10
|
const { Message: contextMessage } = useComponentContext('Message');
|
|
11
11
|
const actionsEnabled = message.type === 'regular' && message.status === 'received';
|
|
@@ -58,6 +58,7 @@ const MessageWithContext = (props) => {
|
|
|
58
58
|
editing,
|
|
59
59
|
getMessageActions: messageActionsHandler,
|
|
60
60
|
handleEdit: setEdit,
|
|
61
|
+
isMessageAIGenerated,
|
|
61
62
|
isMyMessage: () => isMyMessage,
|
|
62
63
|
messageIsUnread,
|
|
63
64
|
onUserClick,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
1
|
+
import React, { useMemo, useState } from 'react';
|
|
2
2
|
import clsx from 'clsx';
|
|
3
3
|
import { MessageErrorIcon } from './icons';
|
|
4
4
|
import { MessageBouncePrompt as DefaultMessageBouncePrompt } from '../MessageBounce';
|
|
@@ -22,8 +22,9 @@ import { useComponentContext } from '../../context/ComponentContext';
|
|
|
22
22
|
import { useMessageContext } from '../../context/MessageContext';
|
|
23
23
|
import { useChatContext, useTranslationContext } from '../../context';
|
|
24
24
|
import { MessageEditedTimestamp } from './MessageEditedTimestamp';
|
|
25
|
+
import { StreamedMessageText as DefaultStreamedMessageText } from './StreamedMessageText';
|
|
25
26
|
const MessageSimpleWithContext = (props) => {
|
|
26
|
-
const { additionalMessageInputProps, clearEditingState, editing, endOfGroup, firstOfGroup, groupedByUser, handleAction, handleOpenThread, handleRetry, highlighted, isMyMessage, message, onUserClick, onUserHover, renderText, threadList, } = props;
|
|
27
|
+
const { additionalMessageInputProps, clearEditingState, editing, endOfGroup, firstOfGroup, groupedByUser, handleAction, handleOpenThread, handleRetry, highlighted, isMessageAIGenerated, isMyMessage, message, onUserClick, onUserHover, renderText, threadList, } = props;
|
|
27
28
|
const { client } = useChatContext('MessageSimple');
|
|
28
29
|
const { t } = useTranslationContext('MessageSimple');
|
|
29
30
|
const [isBounceDialogOpen, setIsBounceDialogOpen] = useState(false);
|
|
@@ -31,9 +32,13 @@ const MessageSimpleWithContext = (props) => {
|
|
|
31
32
|
const { Attachment = DefaultAttachment, Avatar = DefaultAvatar, EditMessageInput = DefaultEditMessageForm, MessageOptions = DefaultMessageOptions,
|
|
32
33
|
// TODO: remove this "passthrough" in the next
|
|
33
34
|
// major release and use the new default instead
|
|
34
|
-
MessageActions = MessageOptions, MessageDeleted = DefaultMessageDeleted, MessageBouncePrompt = DefaultMessageBouncePrompt, MessageRepliesCountButton = DefaultMessageRepliesCountButton, MessageStatus = DefaultMessageStatus, MessageTimestamp = DefaultMessageTimestamp, ReactionsList = DefaultReactionList, PinIndicator, } = useComponentContext('MessageSimple');
|
|
35
|
+
MessageActions = MessageOptions, MessageDeleted = DefaultMessageDeleted, MessageBouncePrompt = DefaultMessageBouncePrompt, MessageRepliesCountButton = DefaultMessageRepliesCountButton, MessageStatus = DefaultMessageStatus, MessageTimestamp = DefaultMessageTimestamp, ReactionsList = DefaultReactionList, StreamedMessageText = DefaultStreamedMessageText, PinIndicator, } = useComponentContext('MessageSimple');
|
|
35
36
|
const hasAttachment = messageHasAttachments(message);
|
|
36
37
|
const hasReactions = messageHasReactions(message);
|
|
38
|
+
const isAIGenerated = useMemo(() => isMessageAIGenerated?.(message), [
|
|
39
|
+
isMessageAIGenerated,
|
|
40
|
+
message,
|
|
41
|
+
]);
|
|
37
42
|
if (message.customType === CUSTOM_MESSAGE_TYPE.date) {
|
|
38
43
|
return null;
|
|
39
44
|
}
|
|
@@ -44,7 +49,7 @@ const MessageSimpleWithContext = (props) => {
|
|
|
44
49
|
const showReplyCountButton = !threadList && !!message.reply_count;
|
|
45
50
|
const allowRetry = message.status === 'failed' && message.errorStatusCode !== 403;
|
|
46
51
|
const isBounced = isMessageBounced(message);
|
|
47
|
-
const isEdited = isMessageEdited(message);
|
|
52
|
+
const isEdited = isMessageEdited(message) && !isAIGenerated;
|
|
48
53
|
let handleClick = undefined;
|
|
49
54
|
if (allowRetry) {
|
|
50
55
|
handleClick = () => handleRetry(message);
|
|
@@ -84,7 +89,7 @@ const MessageSimpleWithContext = (props) => {
|
|
|
84
89
|
React.createElement("div", { className: 'str-chat__message-bubble' },
|
|
85
90
|
poll && React.createElement(Poll, { poll: poll }),
|
|
86
91
|
message.attachments?.length && !message.quoted_message ? (React.createElement(Attachment, { actionHandler: handleAction, attachments: message.attachments })) : null,
|
|
87
|
-
React.createElement(MessageText, { message: message, renderText: renderText }),
|
|
92
|
+
isAIGenerated ? (React.createElement(StreamedMessageText, { message: message, renderText: renderText })) : (React.createElement(MessageText, { message: message, renderText: renderText })),
|
|
88
93
|
message.mml && (React.createElement(MML, { actionHandler: handleAction, align: isMyMessage() ? 'right' : 'left', source: message.mml })),
|
|
89
94
|
React.createElement(MessageErrorIcon, null))),
|
|
90
95
|
showReplyCountButton && (React.createElement(MessageRepliesCountButton, { onClick: handleOpenThread, reply_count: message.reply_count })),
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { MessageTextProps } from './MessageText';
|
|
3
|
+
import type { DefaultStreamChatGenerics } from '../../types/types';
|
|
4
|
+
export type StreamedMessageTextProps<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> = Pick<MessageTextProps<StreamChatGenerics>, 'message' | 'renderText'> & {
|
|
5
|
+
renderingLetterCount?: number;
|
|
6
|
+
streamingLetterIntervalMs?: number;
|
|
7
|
+
};
|
|
8
|
+
export declare const StreamedMessageText: <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>(props: StreamedMessageTextProps<StreamChatGenerics>) => React.JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { MessageText } from './MessageText';
|
|
3
|
+
import { useMessageContext } from '../../context';
|
|
4
|
+
import { useMessageTextStreaming } from './hooks';
|
|
5
|
+
export const StreamedMessageText = (props) => {
|
|
6
|
+
const { message: messageFromProps, renderingLetterCount, renderText, streamingLetterIntervalMs, } = props;
|
|
7
|
+
const { message: messageFromContext } = useMessageContext('StreamedMessageText');
|
|
8
|
+
const message = messageFromProps || messageFromContext;
|
|
9
|
+
const { text = '' } = message;
|
|
10
|
+
const { streamedMessageText } = useMessageTextStreaming({
|
|
11
|
+
renderingLetterCount,
|
|
12
|
+
streamingLetterIntervalMs,
|
|
13
|
+
text,
|
|
14
|
+
});
|
|
15
|
+
return (React.createElement(MessageText, { message: { ...message, text: streamedMessageText }, renderText: renderText }));
|
|
16
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DefaultStreamChatGenerics } from '../../../types/types';
|
|
2
|
+
import type { StreamedMessageTextProps } from '../StreamedMessageText';
|
|
3
|
+
export type UseMessageTextStreamingProps<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics> = Pick<StreamedMessageTextProps<StreamChatGenerics>, 'streamingLetterIntervalMs' | 'renderingLetterCount'> & {
|
|
4
|
+
text: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* A hook that returns text in a streamed, typewriter fashion. The speed of streaming is
|
|
8
|
+
* configurable.
|
|
9
|
+
* @param {number} [streamingLetterIntervalMs=30] - The timeout between each typing animation in milliseconds.
|
|
10
|
+
* @param {number} [renderingLetterCount=2] - The number of letters to be rendered each time we update.
|
|
11
|
+
* @param {string} text - The text that we want to render in a typewriter fashion.
|
|
12
|
+
* @returns {{ streamedMessageText: string }} - A substring of the text property, up until we've finished rendering the typewriter animation.
|
|
13
|
+
*/
|
|
14
|
+
export declare const useMessageTextStreaming: <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>({ streamingLetterIntervalMs, renderingLetterCount, text, }: UseMessageTextStreamingProps<StreamChatGenerics>) => {
|
|
15
|
+
streamedMessageText: string;
|
|
16
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
const DEFAULT_LETTER_INTERVAL = 30;
|
|
3
|
+
const DEFAULT_RENDERING_LETTER_COUNT = 2;
|
|
4
|
+
/**
|
|
5
|
+
* A hook that returns text in a streamed, typewriter fashion. The speed of streaming is
|
|
6
|
+
* configurable.
|
|
7
|
+
* @param {number} [streamingLetterIntervalMs=30] - The timeout between each typing animation in milliseconds.
|
|
8
|
+
* @param {number} [renderingLetterCount=2] - The number of letters to be rendered each time we update.
|
|
9
|
+
* @param {string} text - The text that we want to render in a typewriter fashion.
|
|
10
|
+
* @returns {{ streamedMessageText: string }} - A substring of the text property, up until we've finished rendering the typewriter animation.
|
|
11
|
+
*/
|
|
12
|
+
export const useMessageTextStreaming = ({ streamingLetterIntervalMs = DEFAULT_LETTER_INTERVAL, renderingLetterCount = DEFAULT_RENDERING_LETTER_COUNT, text, }) => {
|
|
13
|
+
const [streamedMessageText, setStreamedMessageText] = useState(text);
|
|
14
|
+
const textCursor = useRef(text.length);
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const textLength = text.length;
|
|
17
|
+
const interval = setInterval(() => {
|
|
18
|
+
if (!text || textCursor.current >= textLength) {
|
|
19
|
+
clearInterval(interval);
|
|
20
|
+
}
|
|
21
|
+
const newCursorValue = textCursor.current + renderingLetterCount;
|
|
22
|
+
const newText = text.substring(0, newCursorValue);
|
|
23
|
+
textCursor.current += newText.length - textCursor.current;
|
|
24
|
+
setStreamedMessageText(newText);
|
|
25
|
+
}, streamingLetterIntervalMs);
|
|
26
|
+
return () => {
|
|
27
|
+
clearInterval(interval);
|
|
28
|
+
};
|
|
29
|
+
}, [streamingLetterIntervalMs, renderingLetterCount, text]);
|
|
30
|
+
return { streamedMessageText };
|
|
31
|
+
};
|
|
@@ -5,6 +5,7 @@ import { AttachmentSelector as DefaultAttachmentSelector, SimpleAttachmentSelect
|
|
|
5
5
|
import { AttachmentPreviewList as DefaultAttachmentPreviewList } from './AttachmentPreviewList';
|
|
6
6
|
import { CooldownTimer as DefaultCooldownTimer } from './CooldownTimer';
|
|
7
7
|
import { SendButton as DefaultSendButton } from './SendButton';
|
|
8
|
+
import { StopAIGenerationButton as DefaultStopAIGenerationButton } from './StopAIGenerationButton';
|
|
8
9
|
import { AudioRecorder as DefaultAudioRecorder, RecordingPermissionDeniedNotification as DefaultRecordingPermissionDeniedNotification, StartRecordingAudioButton as DefaultStartRecordingAudioButton, RecordingPermission, } from '../MediaRecorder';
|
|
9
10
|
import { QuotedMessagePreview as DefaultQuotedMessagePreview, QuotedMessagePreviewHeader, } from './QuotedMessagePreview';
|
|
10
11
|
import { LinkPreviewList as DefaultLinkPreviewList } from './LinkPreviewList';
|
|
@@ -16,13 +17,16 @@ import { useChannelStateContext } from '../../context/ChannelStateContext';
|
|
|
16
17
|
import { useTranslationContext } from '../../context/TranslationContext';
|
|
17
18
|
import { useMessageInputContext } from '../../context/MessageInputContext';
|
|
18
19
|
import { useComponentContext } from '../../context/ComponentContext';
|
|
20
|
+
import { AIStates, useAIState } from '../AIStateIndicator';
|
|
19
21
|
export const MessageInputFlat = () => {
|
|
20
22
|
const { t } = useTranslationContext('MessageInputFlat');
|
|
21
23
|
const { asyncMessagesMultiSendEnabled, attachments, cooldownRemaining, findAndEnqueueURLsToEnrich, handleSubmit, hideSendButton, isUploadEnabled, linkPreviews, maxFilesLeft, message, numberOfUploads, parent, recordingController, setCooldownRemaining, text, uploadNewFiles, } = useMessageInputContext('MessageInputFlat');
|
|
22
|
-
const { AudioRecorder = DefaultAudioRecorder, AttachmentPreviewList = DefaultAttachmentPreviewList, AttachmentSelector = message ? SimpleAttachmentSelector : DefaultAttachmentSelector, CooldownTimer = DefaultCooldownTimer, LinkPreviewList = DefaultLinkPreviewList, QuotedMessagePreview = DefaultQuotedMessagePreview, RecordingPermissionDeniedNotification = DefaultRecordingPermissionDeniedNotification, SendButton = DefaultSendButton, StartRecordingAudioButton = DefaultStartRecordingAudioButton, EmojiPicker, } = useComponentContext('MessageInputFlat');
|
|
24
|
+
const { AudioRecorder = DefaultAudioRecorder, AttachmentPreviewList = DefaultAttachmentPreviewList, AttachmentSelector = message ? SimpleAttachmentSelector : DefaultAttachmentSelector, CooldownTimer = DefaultCooldownTimer, LinkPreviewList = DefaultLinkPreviewList, QuotedMessagePreview = DefaultQuotedMessagePreview, RecordingPermissionDeniedNotification = DefaultRecordingPermissionDeniedNotification, SendButton = DefaultSendButton, StartRecordingAudioButton = DefaultStartRecordingAudioButton, StopAIGenerationButton: StopAIGenerationButtonOverride, EmojiPicker, } = useComponentContext('MessageInputFlat');
|
|
23
25
|
const { acceptedFiles = [], multipleUploads, quotedMessage, } = useChannelStateContext('MessageInputFlat');
|
|
24
26
|
const { setQuotedMessage } = useChannelActionContext('MessageInputFlat');
|
|
25
27
|
const { channel } = useChatContext('MessageInputFlat');
|
|
28
|
+
const { aiState } = useAIState(channel);
|
|
29
|
+
const stopGenerating = useCallback(() => channel?.stopAIResponse(), [channel]);
|
|
26
30
|
const [showRecordingPermissionDeniedNotification, setShowRecordingPermissionDeniedNotification,] = useState(false);
|
|
27
31
|
const closePermissionDeniedNotification = useCallback(() => {
|
|
28
32
|
setShowRecordingPermissionDeniedNotification(false);
|
|
@@ -64,6 +68,15 @@ export const MessageInputFlat = () => {
|
|
|
64
68
|
const displayQuotedMessage = !message && quotedMessage && quotedMessage.parent_id === parent?.id;
|
|
65
69
|
const recordingEnabled = !!(recordingController.recorder && navigator.mediaDevices); // account for requirement on iOS as per this bug report: https://bugs.webkit.org/show_bug.cgi?id=252303
|
|
66
70
|
const isRecording = !!recordingController.recordingState;
|
|
71
|
+
/* This bit here is needed to make sure that we can get rid of the default behaviour
|
|
72
|
+
* if need be. Essentially this allows us to pass StopAIGenerationButton={null} and
|
|
73
|
+
* completely circumvent the default logic if it's not what we want. We need it as a
|
|
74
|
+
* prop because there is no other trivial way to override the SendMessage button otherwise.
|
|
75
|
+
*/
|
|
76
|
+
const StopAIGenerationButton = StopAIGenerationButtonOverride === undefined
|
|
77
|
+
? DefaultStopAIGenerationButton
|
|
78
|
+
: StopAIGenerationButtonOverride;
|
|
79
|
+
const shouldDisplayStopAIGeneration = [AIStates.Thinking, AIStates.Generating].includes(aiState) && !!StopAIGenerationButton;
|
|
67
80
|
return (React.createElement(React.Fragment, null,
|
|
68
81
|
React.createElement("div", { ...getRootProps({ className: 'str-chat__message-input' }) },
|
|
69
82
|
recordingEnabled &&
|
|
@@ -85,7 +98,7 @@ export const MessageInputFlat = () => {
|
|
|
85
98
|
React.createElement("div", { className: 'str-chat__message-textarea-with-emoji-picker' },
|
|
86
99
|
React.createElement(ChatAutoComplete, null),
|
|
87
100
|
EmojiPicker && React.createElement(EmojiPicker, null))),
|
|
88
|
-
!hideSendButton && (React.createElement(React.Fragment, null, cooldownRemaining ? (React.createElement(CooldownTimer, { cooldownInterval: cooldownRemaining, setCooldownRemaining: setCooldownRemaining })) : (React.createElement(React.Fragment, null,
|
|
101
|
+
shouldDisplayStopAIGeneration ? (React.createElement(StopAIGenerationButton, { onClick: stopGenerating })) : (!hideSendButton && (React.createElement(React.Fragment, null, cooldownRemaining ? (React.createElement(CooldownTimer, { cooldownInterval: cooldownRemaining, setCooldownRemaining: setCooldownRemaining })) : (React.createElement(React.Fragment, null,
|
|
89
102
|
React.createElement(SendButton, { disabled: !numberOfUploads &&
|
|
90
103
|
!text.length &&
|
|
91
104
|
attachments.length - failedUploadsCount === 0, sendMessage: handleSubmit }),
|
|
@@ -94,5 +107,5 @@ export const MessageInputFlat = () => {
|
|
|
94
107
|
attachments.some((a) => a.type === RecordingAttachmentType.VOICE_RECORDING)), onClick: () => {
|
|
95
108
|
recordingController.recorder?.start();
|
|
96
109
|
setShowRecordingPermissionDeniedNotification(true);
|
|
97
|
-
} }))))))))));
|
|
110
|
+
} })))))))))));
|
|
98
111
|
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useTranslationContext } from '../../context';
|
|
3
|
+
export const StopAIGenerationButton = ({ onClick, ...restProps }) => {
|
|
4
|
+
const { t } = useTranslationContext();
|
|
5
|
+
return (React.createElement("button", { "aria-label": t('aria/Stop AI Generation'), className: 'str-chat__stop-ai-generation-button', "data-testid": 'stop-ai-generation-button', onClick: onClick, ...restProps }));
|
|
6
|
+
};
|
|
@@ -36,5 +36,6 @@ export * from './UserItem';
|
|
|
36
36
|
export * from './Window';
|
|
37
37
|
export * from './Threads';
|
|
38
38
|
export * from './ChatView';
|
|
39
|
+
export * from './AIStateIndicator';
|
|
39
40
|
export { UploadButton } from './ReactFileUtilities';
|
|
40
41
|
export type { UploadButtonProps } from './ReactFileUtilities';
|
package/dist/components/index.js
CHANGED
|
@@ -36,7 +36,7 @@ export type ChatContextValue<StreamChatGenerics extends DefaultStreamChatGeneric
|
|
|
36
36
|
*/
|
|
37
37
|
customClasses?: CustomClasses;
|
|
38
38
|
navOpen?: boolean;
|
|
39
|
-
} & Required<Pick<ChatProps<StreamChatGenerics>, 'theme' | 'client'>>;
|
|
39
|
+
} & Partial<Pick<ChatProps<StreamChatGenerics>, 'isMessageAIGenerated'>> & Required<Pick<ChatProps<StreamChatGenerics>, 'theme' | 'client'>>;
|
|
40
40
|
export declare const ChatContext: React.Context<ChatContextValue<DefaultStreamChatGenerics> | undefined>;
|
|
41
41
|
export declare const ChatProvider: <StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics>({ children, value, }: PropsWithChildren<{
|
|
42
42
|
value: ChatContextValue<StreamChatGenerics>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { PropsWithChildren } from 'react';
|
|
2
|
-
import { AttachmentPreviewListProps, AttachmentProps, AvatarProps, BaseImageProps, CooldownTimerProps, CustomMessageActionsListProps, DateSeparatorProps, EmojiSearchIndex, EmptyStateIndicatorProps, EventComponentProps, FixedHeightMessageProps, GiphyPreviewMessageProps, LinkPreviewListProps, LoadingIndicatorProps, MessageBouncePromptProps, MessageDeletedProps, MessageInputProps, MessageListNotificationsProps, MessageNotificationProps, MessageOptionsProps, MessageProps, MessageRepliesCountButtonProps, MessageStatusProps, MessageTimestampProps, MessageUIComponentProps, ModalGalleryProps, PinIndicatorProps, PollCreationDialogProps, PollOptionSelectorProps, QuotedMessagePreviewProps, ReactionOptions, ReactionSelectorProps, ReactionsListProps, RecordingPermissionDeniedNotificationProps, SendButtonProps, StartRecordingAudioButtonProps, SuggestionItemProps, SuggestionListProps, ThreadHeaderProps, ThreadListItemProps, ThreadListItemUIProps, TimestampProps, TypingIndicatorProps, UnreadMessagesNotificationProps, UnreadMessagesSeparatorProps } from '../components';
|
|
2
|
+
import { AttachmentPreviewListProps, AttachmentProps, AvatarProps, BaseImageProps, CooldownTimerProps, CustomMessageActionsListProps, DateSeparatorProps, EmojiSearchIndex, EmptyStateIndicatorProps, EventComponentProps, FixedHeightMessageProps, GiphyPreviewMessageProps, LinkPreviewListProps, LoadingIndicatorProps, MessageBouncePromptProps, MessageDeletedProps, MessageInputProps, MessageListNotificationsProps, MessageNotificationProps, MessageOptionsProps, MessageProps, MessageRepliesCountButtonProps, MessageStatusProps, MessageTimestampProps, MessageUIComponentProps, ModalGalleryProps, PinIndicatorProps, PollCreationDialogProps, PollOptionSelectorProps, QuotedMessagePreviewProps, ReactionOptions, ReactionSelectorProps, ReactionsListProps, RecordingPermissionDeniedNotificationProps, SendButtonProps, StartRecordingAudioButtonProps, StreamedMessageTextProps, SuggestionItemProps, SuggestionListProps, ThreadHeaderProps, ThreadListItemProps, ThreadListItemUIProps, TimestampProps, TypingIndicatorProps, UnreadMessagesNotificationProps, UnreadMessagesSeparatorProps } from '../components';
|
|
3
3
|
import type { CustomTrigger, DefaultStreamChatGenerics, PropsWithChildrenOnly, UnknownType } from '../types/types';
|
|
4
|
+
import type { StopAIGenerationButtonProps } from '../components/MessageInput/StopAIGenerationButton';
|
|
4
5
|
export type ComponentContextValue<StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics, V extends CustomTrigger = CustomTrigger> = {
|
|
5
6
|
/** Custom UI component to display a message attachment, defaults to and accepts same props as: [Attachment](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Attachment/Attachment.tsx) */
|
|
6
7
|
Attachment?: React.ComponentType<AttachmentProps<StreamChatGenerics>>;
|
|
@@ -107,6 +108,8 @@ export type ComponentContextValue<StreamChatGenerics extends DefaultStreamChatGe
|
|
|
107
108
|
SendButton?: React.ComponentType<SendButtonProps<StreamChatGenerics>>;
|
|
108
109
|
/** Custom UI component button for initiating audio recording, defaults to and accepts same props as: [StartRecordingAudioButton](https://github.com/GetStream/stream-chat-react/blob/master/src/components/MediaRecorder/AudioRecorder/AudioRecordingButtons.tsx) */
|
|
109
110
|
StartRecordingAudioButton?: React.ComponentType<StartRecordingAudioButtonProps>;
|
|
111
|
+
StopAIGenerationButton?: React.ComponentType<StopAIGenerationButtonProps> | null;
|
|
112
|
+
StreamedMessageText?: React.ComponentType<StreamedMessageTextProps>;
|
|
110
113
|
/** Custom UI component that displays thread's parent or other message at the top of the `MessageList`, defaults to and accepts same props as [MessageSimple](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Message/MessageSimple.tsx) */
|
|
111
114
|
ThreadHead?: React.ComponentType<MessageProps<StreamChatGenerics>>;
|
|
112
115
|
/** Custom UI component to display the header of a `Thread`, defaults to and accepts same props as: [DefaultThreadHeader](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Thread/Thread.tsx) */
|
|
@@ -86,6 +86,10 @@ export type MessageContextValue<StreamChatGenerics extends DefaultStreamChatGene
|
|
|
86
86
|
highlighted?: boolean;
|
|
87
87
|
/** Whether the threaded message is the first in the thread list */
|
|
88
88
|
initialMessage?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* A factory function that determines whether a message is AI generated or not.
|
|
91
|
+
*/
|
|
92
|
+
isMessageAIGenerated?: (message: StreamMessage<StreamChatGenerics>) => boolean;
|
|
89
93
|
/** Latest message id on current channel */
|
|
90
94
|
lastReceivedId?: string | null;
|
|
91
95
|
/** DOMRect object for parent MessageList component */
|