stream-chat-react-native-core 5.43.3-beta.2 → 5.44.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/lib/commonjs/components/AITypingIndicatorView/AITypingIndicatorView.js +53 -0
- package/lib/commonjs/components/AITypingIndicatorView/AITypingIndicatorView.js.map +1 -0
- package/lib/commonjs/components/AITypingIndicatorView/hooks/useAIState.js +59 -0
- package/lib/commonjs/components/AITypingIndicatorView/hooks/useAIState.js.map +1 -0
- package/lib/commonjs/components/AITypingIndicatorView/index.js +26 -0
- package/lib/commonjs/components/AITypingIndicatorView/index.js.map +1 -0
- package/lib/commonjs/components/Channel/Channel.js +9 -1
- package/lib/commonjs/components/Channel/Channel.js.map +1 -1
- package/lib/commonjs/components/Channel/hooks/useCreateInputMessageInputContext.js +2 -0
- package/lib/commonjs/components/Channel/hooks/useCreateInputMessageInputContext.js.map +1 -1
- package/lib/commonjs/components/Channel/hooks/useCreateMessagesContext.js +2 -0
- package/lib/commonjs/components/Channel/hooks/useCreateMessagesContext.js.map +1 -1
- package/lib/commonjs/components/Message/Message.js +3 -1
- package/lib/commonjs/components/Message/Message.js.map +1 -1
- package/lib/commonjs/components/Message/MessageSimple/MessageContent.js +8 -3
- package/lib/commonjs/components/Message/MessageSimple/MessageContent.js.map +1 -1
- package/lib/commonjs/components/Message/MessageSimple/MessageFooter.js +5 -4
- package/lib/commonjs/components/Message/MessageSimple/MessageFooter.js.map +1 -1
- package/lib/commonjs/components/Message/MessageSimple/MessageSimple.js +1 -1
- package/lib/commonjs/components/Message/MessageSimple/MessageSimple.js.map +1 -1
- package/lib/commonjs/components/Message/MessageSimple/StreamingMessageView.js +36 -0
- package/lib/commonjs/components/Message/MessageSimple/StreamingMessageView.js.map +1 -0
- package/lib/commonjs/components/Message/MessageSimple/utils/generateMarkdownText.js +5 -1
- package/lib/commonjs/components/Message/MessageSimple/utils/generateMarkdownText.js.map +1 -1
- package/lib/commonjs/components/Message/MessageSimple/utils/renderText.js +209 -23
- package/lib/commonjs/components/Message/MessageSimple/utils/renderText.js.map +1 -1
- package/lib/commonjs/components/Message/hooks/useStreamingMessage.js +43 -0
- package/lib/commonjs/components/Message/hooks/useStreamingMessage.js.map +1 -0
- package/lib/commonjs/components/MessageInput/MessageInput.js +20 -6
- package/lib/commonjs/components/MessageInput/MessageInput.js.map +1 -1
- package/lib/commonjs/components/MessageInput/StopMessageStreamingButton.js +39 -0
- package/lib/commonjs/components/MessageInput/StopMessageStreamingButton.js.map +1 -0
- package/lib/commonjs/components/MessageOverlay/MessageOverlay.js +6 -1
- package/lib/commonjs/components/MessageOverlay/MessageOverlay.js.map +1 -1
- package/lib/commonjs/components/index.js +44 -0
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js +4 -2
- package/lib/commonjs/contexts/messageInputContext/MessageInputContext.js.map +1 -1
- package/lib/commonjs/contexts/messageInputContext/hooks/useCreateMessageInputContext.js +2 -0
- package/lib/commonjs/contexts/messageInputContext/hooks/useCreateMessageInputContext.js.map +1 -1
- package/lib/commonjs/contexts/messagesContext/MessagesContext.js.map +1 -1
- package/lib/commonjs/contexts/themeContext/utils/theme.js +7 -0
- package/lib/commonjs/contexts/themeContext/utils/theme.js.map +1 -1
- package/lib/commonjs/i18n/en.json +2 -0
- package/lib/commonjs/i18n/es.json +2 -0
- package/lib/commonjs/i18n/fr.json +2 -0
- package/lib/commonjs/i18n/he.json +2 -0
- package/lib/commonjs/i18n/hi.json +2 -0
- package/lib/commonjs/i18n/it.json +2 -0
- package/lib/commonjs/i18n/ja.json +2 -0
- package/lib/commonjs/i18n/ko.json +2 -0
- package/lib/commonjs/i18n/nl.json +2 -0
- package/lib/commonjs/i18n/pt-br.json +2 -0
- package/lib/commonjs/i18n/ru.json +2 -0
- package/lib/commonjs/i18n/tr.json +2 -0
- package/lib/commonjs/utils/utils.js +1 -1
- package/lib/commonjs/utils/utils.js.map +1 -1
- package/lib/commonjs/version.json +1 -1
- package/lib/module/components/AITypingIndicatorView/AITypingIndicatorView.js +53 -0
- package/lib/module/components/AITypingIndicatorView/AITypingIndicatorView.js.map +1 -0
- package/lib/module/components/AITypingIndicatorView/hooks/useAIState.js +59 -0
- package/lib/module/components/AITypingIndicatorView/hooks/useAIState.js.map +1 -0
- package/lib/module/components/AITypingIndicatorView/index.js +26 -0
- package/lib/module/components/AITypingIndicatorView/index.js.map +1 -0
- package/lib/module/components/Channel/Channel.js +9 -1
- package/lib/module/components/Channel/Channel.js.map +1 -1
- package/lib/module/components/Channel/hooks/useCreateInputMessageInputContext.js +2 -0
- package/lib/module/components/Channel/hooks/useCreateInputMessageInputContext.js.map +1 -1
- package/lib/module/components/Channel/hooks/useCreateMessagesContext.js +2 -0
- package/lib/module/components/Channel/hooks/useCreateMessagesContext.js.map +1 -1
- package/lib/module/components/Message/Message.js +3 -1
- package/lib/module/components/Message/Message.js.map +1 -1
- package/lib/module/components/Message/MessageSimple/MessageContent.js +8 -3
- package/lib/module/components/Message/MessageSimple/MessageContent.js.map +1 -1
- package/lib/module/components/Message/MessageSimple/MessageFooter.js +5 -4
- package/lib/module/components/Message/MessageSimple/MessageFooter.js.map +1 -1
- package/lib/module/components/Message/MessageSimple/MessageSimple.js +1 -1
- package/lib/module/components/Message/MessageSimple/MessageSimple.js.map +1 -1
- package/lib/module/components/Message/MessageSimple/StreamingMessageView.js +36 -0
- package/lib/module/components/Message/MessageSimple/StreamingMessageView.js.map +1 -0
- package/lib/module/components/Message/MessageSimple/utils/generateMarkdownText.js +5 -1
- package/lib/module/components/Message/MessageSimple/utils/generateMarkdownText.js.map +1 -1
- package/lib/module/components/Message/MessageSimple/utils/renderText.js +209 -23
- package/lib/module/components/Message/MessageSimple/utils/renderText.js.map +1 -1
- package/lib/module/components/Message/hooks/useStreamingMessage.js +43 -0
- package/lib/module/components/Message/hooks/useStreamingMessage.js.map +1 -0
- package/lib/module/components/MessageInput/MessageInput.js +20 -6
- package/lib/module/components/MessageInput/MessageInput.js.map +1 -1
- package/lib/module/components/MessageInput/StopMessageStreamingButton.js +39 -0
- package/lib/module/components/MessageInput/StopMessageStreamingButton.js.map +1 -0
- package/lib/module/components/MessageOverlay/MessageOverlay.js +6 -1
- package/lib/module/components/MessageOverlay/MessageOverlay.js.map +1 -1
- package/lib/module/components/index.js +44 -0
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/contexts/messageInputContext/MessageInputContext.js +4 -2
- package/lib/module/contexts/messageInputContext/MessageInputContext.js.map +1 -1
- package/lib/module/contexts/messageInputContext/hooks/useCreateMessageInputContext.js +2 -0
- package/lib/module/contexts/messageInputContext/hooks/useCreateMessageInputContext.js.map +1 -1
- package/lib/module/contexts/messagesContext/MessagesContext.js.map +1 -1
- package/lib/module/contexts/themeContext/utils/theme.js +7 -0
- package/lib/module/contexts/themeContext/utils/theme.js.map +1 -1
- package/lib/module/i18n/en.json +2 -0
- package/lib/module/i18n/es.json +2 -0
- package/lib/module/i18n/fr.json +2 -0
- package/lib/module/i18n/he.json +2 -0
- package/lib/module/i18n/hi.json +2 -0
- package/lib/module/i18n/it.json +2 -0
- package/lib/module/i18n/ja.json +2 -0
- package/lib/module/i18n/ko.json +2 -0
- package/lib/module/i18n/nl.json +2 -0
- package/lib/module/i18n/pt-br.json +2 -0
- package/lib/module/i18n/ru.json +2 -0
- package/lib/module/i18n/tr.json +2 -0
- package/lib/module/utils/utils.js +1 -1
- package/lib/module/utils/utils.js.map +1 -1
- package/lib/module/version.json +1 -1
- package/lib/typescript/components/AITypingIndicatorView/AITypingIndicatorView.d.ts +11 -0
- package/lib/typescript/components/AITypingIndicatorView/AITypingIndicatorView.d.ts.map +1 -0
- package/lib/typescript/components/AITypingIndicatorView/hooks/useAIState.d.ts +18 -0
- package/lib/typescript/components/AITypingIndicatorView/hooks/useAIState.d.ts.map +1 -0
- package/lib/typescript/components/AITypingIndicatorView/index.d.ts +3 -0
- package/lib/typescript/components/AITypingIndicatorView/index.d.ts.map +1 -0
- package/lib/typescript/components/Channel/Channel.d.ts +2 -2
- package/lib/typescript/components/Channel/Channel.d.ts.map +1 -1
- package/lib/typescript/components/Channel/hooks/useCreateInputMessageInputContext.d.ts +1 -1
- package/lib/typescript/components/Channel/hooks/useCreateInputMessageInputContext.d.ts.map +1 -1
- package/lib/typescript/components/Channel/hooks/useCreateMessagesContext.d.ts +1 -1
- package/lib/typescript/components/Channel/hooks/useCreateMessagesContext.d.ts.map +1 -1
- package/lib/typescript/components/Message/Message.d.ts.map +1 -1
- package/lib/typescript/components/Message/MessageSimple/MessageContent.d.ts +1 -1
- package/lib/typescript/components/Message/MessageSimple/MessageContent.d.ts.map +1 -1
- package/lib/typescript/components/Message/MessageSimple/MessageFooter.d.ts.map +1 -1
- package/lib/typescript/components/Message/MessageSimple/MessageSimple.d.ts.map +1 -1
- package/lib/typescript/components/Message/MessageSimple/StreamingMessageView.d.ts +12 -0
- package/lib/typescript/components/Message/MessageSimple/StreamingMessageView.d.ts.map +1 -0
- package/lib/typescript/components/Message/MessageSimple/utils/generateMarkdownText.d.ts.map +1 -1
- package/lib/typescript/components/Message/MessageSimple/utils/renderText.d.ts +16 -1
- package/lib/typescript/components/Message/MessageSimple/utils/renderText.d.ts.map +1 -1
- package/lib/typescript/components/Message/hooks/useStreamingMessage.d.ts +17 -0
- package/lib/typescript/components/Message/hooks/useStreamingMessage.d.ts.map +1 -0
- package/lib/typescript/components/MessageInput/MessageInput.d.ts +1 -1
- package/lib/typescript/components/MessageInput/MessageInput.d.ts.map +1 -1
- package/lib/typescript/components/MessageInput/StopMessageStreamingButton.d.ts +10 -0
- package/lib/typescript/components/MessageInput/StopMessageStreamingButton.d.ts.map +1 -0
- package/lib/typescript/components/MessageOverlay/MessageOverlay.d.ts.map +1 -1
- package/lib/typescript/components/index.d.ts +4 -0
- package/lib/typescript/components/index.d.ts.map +1 -1
- package/lib/typescript/contexts/messageInputContext/MessageInputContext.d.ts +3 -2
- package/lib/typescript/contexts/messageInputContext/MessageInputContext.d.ts.map +1 -1
- package/lib/typescript/contexts/messageInputContext/hooks/useCreateMessageInputContext.d.ts +1 -1
- package/lib/typescript/contexts/messageInputContext/hooks/useCreateMessageInputContext.d.ts.map +1 -1
- package/lib/typescript/contexts/messagesContext/MessagesContext.d.ts +6 -2
- package/lib/typescript/contexts/messagesContext/MessagesContext.d.ts.map +1 -1
- package/lib/typescript/contexts/themeContext/utils/theme.d.ts +8 -1
- package/lib/typescript/contexts/themeContext/utils/theme.d.ts.map +1 -1
- package/lib/typescript/i18n/en.json +2 -0
- package/lib/typescript/i18n/es.json +2 -0
- package/lib/typescript/i18n/fr.json +2 -0
- package/lib/typescript/i18n/he.json +2 -0
- package/lib/typescript/i18n/hi.json +2 -0
- package/lib/typescript/i18n/it.json +2 -0
- package/lib/typescript/i18n/ja.json +2 -0
- package/lib/typescript/i18n/ko.json +2 -0
- package/lib/typescript/i18n/nl.json +2 -0
- package/lib/typescript/i18n/pt-br.json +2 -0
- package/lib/typescript/i18n/ru.json +2 -0
- package/lib/typescript/i18n/tr.json +2 -0
- package/lib/typescript/utils/i18n/Streami18n.d.ts +2 -0
- package/lib/typescript/utils/i18n/Streami18n.d.ts.map +1 -1
- package/lib/typescript/utils/utils.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/components/AITypingIndicatorView/AITypingIndicatorView.tsx +50 -0
- package/src/components/AITypingIndicatorView/hooks/useAIState.ts +68 -0
- package/src/components/AITypingIndicatorView/index.ts +2 -0
- package/src/components/Channel/Channel.tsx +26 -2
- package/src/components/Channel/hooks/useCreateInputMessageInputContext.ts +2 -0
- package/src/components/Channel/hooks/useCreateMessagesContext.ts +2 -0
- package/src/components/Message/Message.tsx +4 -1
- package/src/components/Message/MessageSimple/MessageContent.tsx +14 -2
- package/src/components/Message/MessageSimple/MessageFooter.tsx +6 -4
- package/src/components/Message/MessageSimple/MessageSimple.tsx +3 -1
- package/src/components/Message/MessageSimple/StreamingMessageView.tsx +34 -0
- package/src/components/Message/MessageSimple/utils/generateMarkdownText.ts +9 -1
- package/src/components/Message/MessageSimple/utils/renderText.tsx +207 -3
- package/src/components/Message/hooks/useStreamingMessage.ts +54 -0
- package/src/components/MessageInput/MessageInput.tsx +19 -3
- package/src/components/MessageInput/StopMessageStreamingButton.tsx +34 -0
- package/src/components/MessageOverlay/MessageOverlay.tsx +10 -1
- package/src/components/index.ts +5 -0
- package/src/contexts/messageInputContext/MessageInputContext.tsx +5 -1
- package/src/contexts/messageInputContext/hooks/useCreateMessageInputContext.ts +2 -0
- package/src/contexts/messagesContext/MessagesContext.tsx +6 -1
- package/src/contexts/themeContext/utils/theme.ts +14 -1
- package/src/i18n/en.json +2 -0
- package/src/i18n/es.json +2 -0
- package/src/i18n/fr.json +2 -0
- package/src/i18n/he.json +2 -0
- package/src/i18n/hi.json +2 -0
- package/src/i18n/it.json +2 -0
- package/src/i18n/ja.json +2 -0
- package/src/i18n/ko.json +2 -0
- package/src/i18n/nl.json +2 -0
- package/src/i18n/pt-br.json +2 -0
- package/src/i18n/ru.json +2 -0
- package/src/i18n/tr.json +2 -0
- package/src/utils/utils.ts +1 -1
- package/src/version.json +1 -1
|
@@ -100,6 +100,7 @@ export type MessageContentPropsWithContext<
|
|
|
100
100
|
| 'myMessageTheme'
|
|
101
101
|
| 'onPressInMessage'
|
|
102
102
|
| 'Reply'
|
|
103
|
+
| 'StreamingMessageView'
|
|
103
104
|
> &
|
|
104
105
|
Pick<TranslationContextValue, 't'> & {
|
|
105
106
|
setMessageContentWidth: React.Dispatch<React.SetStateAction<number>>;
|
|
@@ -142,6 +143,7 @@ const MessageContentWithContext = <
|
|
|
142
143
|
Reply,
|
|
143
144
|
setMessageContentWidth,
|
|
144
145
|
showMessageStatus,
|
|
146
|
+
StreamingMessageView,
|
|
145
147
|
threadList,
|
|
146
148
|
} = props;
|
|
147
149
|
const { client } = useChatContext();
|
|
@@ -393,9 +395,16 @@ const MessageContentWithContext = <
|
|
|
393
395
|
/>
|
|
394
396
|
) : null;
|
|
395
397
|
}
|
|
398
|
+
case 'ai_text':
|
|
399
|
+
return message.ai_generated ? (
|
|
400
|
+
<StreamingMessageView
|
|
401
|
+
key={`ai_message_text_container_${messageContentOrderIndex}`}
|
|
402
|
+
/>
|
|
403
|
+
) : null;
|
|
396
404
|
case 'text':
|
|
397
405
|
default:
|
|
398
|
-
return otherAttachments.length && otherAttachments[0].actions
|
|
406
|
+
return (otherAttachments.length && otherAttachments[0].actions) ||
|
|
407
|
+
message.ai_generated ? null : (
|
|
399
408
|
<MessageTextContainer<StreamChatGenerics>
|
|
400
409
|
key={`message_text_container_${messageContentOrderIndex}`}
|
|
401
410
|
/>
|
|
@@ -484,7 +493,8 @@ const areEqual = <StreamChatGenerics extends DefaultStreamChatGenerics = Default
|
|
|
484
493
|
prevMessage.type === nextMessage.type &&
|
|
485
494
|
prevMessage.text === nextMessage.text &&
|
|
486
495
|
prevMessage.pinned === nextMessage.pinned &&
|
|
487
|
-
prevMessage.i18n === nextMessage.i18n
|
|
496
|
+
prevMessage.i18n === nextMessage.i18n &&
|
|
497
|
+
prevMessage.ai_generated === nextMessage.ai_generated;
|
|
488
498
|
if (!messageEqual) return false;
|
|
489
499
|
|
|
490
500
|
const isPrevQuotedMessageTypeDeleted = prevMessage.quoted_message?.type === 'deleted';
|
|
@@ -597,6 +607,7 @@ export const MessageContent = <
|
|
|
597
607
|
MessageStatus,
|
|
598
608
|
myMessageTheme,
|
|
599
609
|
Reply,
|
|
610
|
+
StreamingMessageView,
|
|
600
611
|
} = useMessagesContext<StreamChatGenerics>();
|
|
601
612
|
const { t } = useTranslationContext();
|
|
602
613
|
|
|
@@ -635,6 +646,7 @@ export const MessageContent = <
|
|
|
635
646
|
preventPress,
|
|
636
647
|
Reply,
|
|
637
648
|
showMessageStatus,
|
|
649
|
+
StreamingMessageView,
|
|
638
650
|
t,
|
|
639
651
|
threadList,
|
|
640
652
|
}}
|
|
@@ -129,6 +129,8 @@ const MessageFooterWithContext = <
|
|
|
129
129
|
return null;
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
const isEdited = isEditedMessage(message);
|
|
133
|
+
|
|
132
134
|
return (
|
|
133
135
|
<>
|
|
134
136
|
<View style={[styles.container, metaContainer]} testID='message-status-time'>
|
|
@@ -141,7 +143,7 @@ const MessageFooterWithContext = <
|
|
|
141
143
|
{showMessageStatus && <MessageStatus />}
|
|
142
144
|
<MessageTimestamp formattedDate={formattedDate} timestamp={date} />
|
|
143
145
|
|
|
144
|
-
{
|
|
146
|
+
{isEdited && !isEditedMessageOpen ? (
|
|
145
147
|
<>
|
|
146
148
|
<Text
|
|
147
149
|
style={[
|
|
@@ -159,11 +161,11 @@ const MessageFooterWithContext = <
|
|
|
159
161
|
{t<string>('Edited')}
|
|
160
162
|
</Text>
|
|
161
163
|
</>
|
|
162
|
-
)}
|
|
164
|
+
) : null}
|
|
163
165
|
</View>
|
|
164
|
-
{
|
|
166
|
+
{isEdited && isEditedMessageOpen ? (
|
|
165
167
|
<MessageEditedTimestamp message={message} MessageTimestamp={MessageTimestamp} />
|
|
166
|
-
)}
|
|
168
|
+
) : null}
|
|
167
169
|
</>
|
|
168
170
|
);
|
|
169
171
|
};
|
|
@@ -154,7 +154,9 @@ const areEqual = <StreamChatGenerics extends DefaultStreamChatGenerics = Default
|
|
|
154
154
|
prevMessage.status === nextMessage.status &&
|
|
155
155
|
prevMessage.type === nextMessage.type &&
|
|
156
156
|
prevMessage.text === nextMessage.text &&
|
|
157
|
-
prevMessage.i18n === nextMessage.i18n
|
|
157
|
+
prevMessage.i18n === nextMessage.i18n &&
|
|
158
|
+
prevMessage.pinned === nextMessage.pinned &&
|
|
159
|
+
prevMessage.ai_generated === nextMessage.ai_generated;
|
|
158
160
|
if (!messageEqual) return false;
|
|
159
161
|
|
|
160
162
|
const isPrevQuotedMessageTypeDeleted = prevMessage.quoted_message?.type === 'deleted';
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { MessageTextContainer, MessageTextContainerProps } from './MessageTextContainer';
|
|
4
|
+
|
|
5
|
+
import { useMessageContext } from '../../../contexts';
|
|
6
|
+
import type { DefaultStreamChatGenerics } from '../../../types/types';
|
|
7
|
+
import { useStreamingMessage } from '../hooks/useStreamingMessage';
|
|
8
|
+
|
|
9
|
+
export type StreamingMessageViewProps<
|
|
10
|
+
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
|
|
11
|
+
> = Pick<MessageTextContainerProps<StreamChatGenerics>, 'message'> & {
|
|
12
|
+
letterInterval?: number;
|
|
13
|
+
renderingLetterCount?: number;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const StreamingMessageView = <
|
|
17
|
+
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
|
|
18
|
+
>(
|
|
19
|
+
props: StreamingMessageViewProps<StreamChatGenerics>,
|
|
20
|
+
) => {
|
|
21
|
+
const { letterInterval, message: messageFromProps, renderingLetterCount } = props;
|
|
22
|
+
const { message: messageFromContext } = useMessageContext<StreamChatGenerics>();
|
|
23
|
+
const message = messageFromProps || messageFromContext;
|
|
24
|
+
const { text = '' } = message;
|
|
25
|
+
const { streamedMessageText } = useStreamingMessage({
|
|
26
|
+
letterInterval,
|
|
27
|
+
renderingLetterCount,
|
|
28
|
+
text,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return <MessageTextContainer message={{ ...message, text: streamedMessageText }} />;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
StreamingMessageView.displayName = 'StreamingMessageView{messageSimple{content}}';
|
|
@@ -33,7 +33,11 @@ export const generateMarkdownText = (text?: string) => {
|
|
|
33
33
|
resultText = resultText.replace(mentionsRegex, `@${displayLink}`);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
// Escape the " and ' characters, except in code blocks where we deem this allowed.
|
|
37
|
+
resultText = resultText.replace(/(```[\s\S]*?```|`.*?`)|[<"'>]/g, (match, code) => {
|
|
38
|
+
if (code) return code;
|
|
39
|
+
return `\\${match}`;
|
|
40
|
+
});
|
|
37
41
|
|
|
38
42
|
// Remove whitespaces that come directly after newlines except in code blocks where we deem this allowed.
|
|
39
43
|
resultText = resultText.replace(/(```[\s\S]*?```|`.*?`)|\n[ ]{2,}/g, (_, code) => {
|
|
@@ -41,5 +45,9 @@ export const generateMarkdownText = (text?: string) => {
|
|
|
41
45
|
return '\n';
|
|
42
46
|
});
|
|
43
47
|
|
|
48
|
+
// Always replace \n``` with \n\n``` to force the markdown state machine to treat it as a separate block. Otherwise, code blocks inside of list
|
|
49
|
+
// items for example were broken. We clean up the code block closing state within the rendering itself.
|
|
50
|
+
resultText = resultText.replace(/\n```/g, '\n\n```');
|
|
51
|
+
|
|
44
52
|
return resultText;
|
|
45
53
|
};
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
import React, { PropsWithChildren } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import React, { PropsWithChildren, ReactNode, useCallback, useMemo } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
GestureResponderEvent,
|
|
4
|
+
Linking,
|
|
5
|
+
Platform,
|
|
6
|
+
Text,
|
|
7
|
+
TextProps,
|
|
8
|
+
View,
|
|
9
|
+
ViewProps,
|
|
10
|
+
} from 'react-native';
|
|
11
|
+
|
|
12
|
+
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
|
|
4
13
|
// @ts-expect-error
|
|
5
14
|
import Markdown from 'react-native-markdown-package';
|
|
15
|
+
import Animated, { clamp, scrollTo, useAnimatedRef, useSharedValue } from 'react-native-reanimated';
|
|
6
16
|
|
|
7
17
|
import {
|
|
8
18
|
DefaultRules,
|
|
@@ -26,7 +36,64 @@ import type { DefaultStreamChatGenerics } from '../../../../types/types';
|
|
|
26
36
|
import { escapeRegExp } from '../../../../utils/utils';
|
|
27
37
|
import type { MessageType } from '../../../MessageList/hooks/useMessageList';
|
|
28
38
|
|
|
39
|
+
export const MarkdownReactiveScrollView = ({ children }: { children: ReactNode }) => {
|
|
40
|
+
const scrollViewRef = useAnimatedRef<Animated.ScrollView>();
|
|
41
|
+
const contentWidth = useSharedValue(0);
|
|
42
|
+
const visibleContentWidth = useSharedValue(0);
|
|
43
|
+
const offsetBeforeScroll = useSharedValue(0);
|
|
44
|
+
|
|
45
|
+
const panGesture = Gesture.Pan()
|
|
46
|
+
.activeOffsetX([-5, 5])
|
|
47
|
+
.onUpdate((event) => {
|
|
48
|
+
const { translationX } = event;
|
|
49
|
+
|
|
50
|
+
scrollTo(scrollViewRef, offsetBeforeScroll.value - translationX, 0, false);
|
|
51
|
+
})
|
|
52
|
+
.onEnd((event) => {
|
|
53
|
+
const { translationX } = event;
|
|
54
|
+
|
|
55
|
+
const velocityEffect = event.velocityX * 0.3;
|
|
56
|
+
|
|
57
|
+
const finalPosition = clamp(
|
|
58
|
+
offsetBeforeScroll.value - translationX - velocityEffect,
|
|
59
|
+
0,
|
|
60
|
+
contentWidth.value - visibleContentWidth.value,
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
offsetBeforeScroll.value = finalPosition;
|
|
64
|
+
|
|
65
|
+
scrollTo(scrollViewRef, finalPosition, 0, true);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<View style={{ width: '100%' }}>
|
|
70
|
+
<GestureDetector gesture={panGesture}>
|
|
71
|
+
<Animated.ScrollView
|
|
72
|
+
contentContainerStyle={{ flexGrow: 1 }}
|
|
73
|
+
horizontal
|
|
74
|
+
nestedScrollEnabled={true}
|
|
75
|
+
onContentSizeChange={(width) => {
|
|
76
|
+
contentWidth.value = width;
|
|
77
|
+
}}
|
|
78
|
+
onLayout={(e) => {
|
|
79
|
+
visibleContentWidth.value = e.nativeEvent.layout.width;
|
|
80
|
+
}}
|
|
81
|
+
ref={scrollViewRef}
|
|
82
|
+
scrollEnabled={false}
|
|
83
|
+
>
|
|
84
|
+
{children}
|
|
85
|
+
</Animated.ScrollView>
|
|
86
|
+
</GestureDetector>
|
|
87
|
+
</View>
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
|
|
29
91
|
const defaultMarkdownStyles: MarkdownStyle = {
|
|
92
|
+
codeBlock: {
|
|
93
|
+
fontFamily: Platform.OS === 'ios' ? 'Courier' : 'Monospace',
|
|
94
|
+
fontWeight: '500',
|
|
95
|
+
marginVertical: 8,
|
|
96
|
+
},
|
|
30
97
|
inlineCode: {
|
|
31
98
|
fontSize: 13,
|
|
32
99
|
padding: 3,
|
|
@@ -60,6 +127,26 @@ const defaultMarkdownStyles: MarkdownStyle = {
|
|
|
60
127
|
marginBottom: 8,
|
|
61
128
|
marginTop: 8,
|
|
62
129
|
},
|
|
130
|
+
table: {
|
|
131
|
+
borderRadius: 3,
|
|
132
|
+
borderWidth: 1,
|
|
133
|
+
flex: 1,
|
|
134
|
+
flexDirection: 'row',
|
|
135
|
+
},
|
|
136
|
+
tableHeader: {
|
|
137
|
+
flexDirection: 'row',
|
|
138
|
+
justifyContent: 'space-around',
|
|
139
|
+
},
|
|
140
|
+
tableHeaderCell: {
|
|
141
|
+
fontWeight: '500',
|
|
142
|
+
},
|
|
143
|
+
tableRow: {
|
|
144
|
+
alignItems: 'center',
|
|
145
|
+
justifyContent: 'space-around',
|
|
146
|
+
},
|
|
147
|
+
tableRowCell: {
|
|
148
|
+
flex: 1,
|
|
149
|
+
},
|
|
63
150
|
};
|
|
64
151
|
|
|
65
152
|
const mentionsParseFunction: ParseFunction = (capture, parse, state) => ({
|
|
@@ -113,6 +200,13 @@ export const renderText = <
|
|
|
113
200
|
color: colors.accent_blue,
|
|
114
201
|
...markdownStyles?.autolink,
|
|
115
202
|
},
|
|
203
|
+
codeBlock: {
|
|
204
|
+
...defaultMarkdownStyles.codeBlock,
|
|
205
|
+
backgroundColor: colors.code_block,
|
|
206
|
+
color: colors.black,
|
|
207
|
+
padding: 8,
|
|
208
|
+
...markdownStyles?.codeBlock,
|
|
209
|
+
},
|
|
116
210
|
inlineCode: {
|
|
117
211
|
...defaultMarkdownStyles.inlineCode,
|
|
118
212
|
backgroundColor: colors.white_smoke,
|
|
@@ -125,6 +219,35 @@ export const renderText = <
|
|
|
125
219
|
color: colors.accent_blue,
|
|
126
220
|
...markdownStyles?.mentions,
|
|
127
221
|
},
|
|
222
|
+
table: {
|
|
223
|
+
...defaultMarkdownStyles.table,
|
|
224
|
+
borderColor: colors.grey_dark,
|
|
225
|
+
marginVertical: 8,
|
|
226
|
+
...markdownStyles?.table,
|
|
227
|
+
},
|
|
228
|
+
tableHeader: {
|
|
229
|
+
...defaultMarkdownStyles.tableHeader,
|
|
230
|
+
backgroundColor: colors.grey,
|
|
231
|
+
...markdownStyles?.tableHeader,
|
|
232
|
+
},
|
|
233
|
+
tableHeaderCell: {
|
|
234
|
+
...defaultMarkdownStyles.tableHeaderCell,
|
|
235
|
+
padding: 5,
|
|
236
|
+
...markdownStyles?.tableHeaderCell,
|
|
237
|
+
},
|
|
238
|
+
tableRow: {
|
|
239
|
+
...defaultMarkdownStyles.tableRow,
|
|
240
|
+
...markdownStyles?.tableRow,
|
|
241
|
+
},
|
|
242
|
+
tableRowCell: {
|
|
243
|
+
...defaultMarkdownStyles.tableRowCell,
|
|
244
|
+
borderColor: colors.grey_dark,
|
|
245
|
+
padding: 5,
|
|
246
|
+
...markdownStyles?.tableRowCell,
|
|
247
|
+
},
|
|
248
|
+
tableRowLast: {
|
|
249
|
+
...markdownStyles?.tableRowLast,
|
|
250
|
+
},
|
|
128
251
|
text: {
|
|
129
252
|
...defaultMarkdownStyles.text,
|
|
130
253
|
color: colors.black,
|
|
@@ -263,6 +386,18 @@ export const renderText = <
|
|
|
263
386
|
/>
|
|
264
387
|
);
|
|
265
388
|
|
|
389
|
+
const codeBlockReact: ReactNodeOutput = (node, _, state) => (
|
|
390
|
+
<MarkdownReactiveScrollView key={state.key}>
|
|
391
|
+
<Text style={styles.codeBlock}>{node?.content?.trim()}</Text>
|
|
392
|
+
</MarkdownReactiveScrollView>
|
|
393
|
+
);
|
|
394
|
+
|
|
395
|
+
const tableReact: ReactNodeOutput = (node, output, state) => (
|
|
396
|
+
<MarkdownReactiveScrollView key={state.key}>
|
|
397
|
+
<MarkdownTable node={node} output={output} state={state} styles={styles} />
|
|
398
|
+
</MarkdownReactiveScrollView>
|
|
399
|
+
);
|
|
400
|
+
|
|
266
401
|
const customRules = {
|
|
267
402
|
// do not render images, we will scrape them out of the message and show on attachment card component
|
|
268
403
|
image: { match: () => null },
|
|
@@ -283,6 +418,8 @@ export const renderText = <
|
|
|
283
418
|
},
|
|
284
419
|
}
|
|
285
420
|
: {}),
|
|
421
|
+
codeBlock: { react: codeBlockReact },
|
|
422
|
+
table: { react: tableReact },
|
|
286
423
|
};
|
|
287
424
|
|
|
288
425
|
return (
|
|
@@ -373,3 +510,70 @@ const ListRow = ({ children, style }: PropsWithChildren<ViewProps>) => (
|
|
|
373
510
|
const ListItem = ({ children, style }: PropsWithChildren<TextProps>) => (
|
|
374
511
|
<Text style={style}>{children}</Text>
|
|
375
512
|
);
|
|
513
|
+
|
|
514
|
+
export type MarkdownTableProps = {
|
|
515
|
+
node: SingleASTNode;
|
|
516
|
+
output: ReactOutput;
|
|
517
|
+
state: State;
|
|
518
|
+
styles: Partial<MarkdownStyle>;
|
|
519
|
+
};
|
|
520
|
+
|
|
521
|
+
const transpose = (matrix: SingleASTNode[][]) =>
|
|
522
|
+
matrix[0].map((_, colIndex) => matrix.map((row) => row[colIndex]));
|
|
523
|
+
|
|
524
|
+
const MarkdownTable = ({ node, output, state, styles }: MarkdownTableProps) => {
|
|
525
|
+
const content = useMemo(() => {
|
|
526
|
+
const nodeContent = [node?.header, ...node?.cells];
|
|
527
|
+
return transpose(nodeContent);
|
|
528
|
+
}, [node?.cells, node?.header]);
|
|
529
|
+
const columns = content?.map((column, idx) => (
|
|
530
|
+
<MarkdownTableColumn
|
|
531
|
+
items={column}
|
|
532
|
+
key={`column-${idx}`}
|
|
533
|
+
output={output}
|
|
534
|
+
state={state}
|
|
535
|
+
styles={styles}
|
|
536
|
+
/>
|
|
537
|
+
));
|
|
538
|
+
|
|
539
|
+
return (
|
|
540
|
+
<View key={state.key} style={styles.table}>
|
|
541
|
+
{columns}
|
|
542
|
+
</View>
|
|
543
|
+
);
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
export type MarkdownTableRowProps = {
|
|
547
|
+
items: SingleASTNode[];
|
|
548
|
+
output: ReactOutput;
|
|
549
|
+
state: State;
|
|
550
|
+
styles: Partial<MarkdownStyle>;
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
const MarkdownTableColumn = ({ items, output, state, styles }: MarkdownTableRowProps) => {
|
|
554
|
+
const [headerCellContent, ...columnCellContents] = items;
|
|
555
|
+
|
|
556
|
+
const ColumnCell = useCallback(
|
|
557
|
+
({ content }: { content: SingleASTNode }) =>
|
|
558
|
+
content ? (
|
|
559
|
+
<View style={styles.tableRow}>
|
|
560
|
+
<View style={styles.tableRowCell}>{output(content, state)}</View>
|
|
561
|
+
</View>
|
|
562
|
+
) : null,
|
|
563
|
+
[output, state, styles],
|
|
564
|
+
);
|
|
565
|
+
|
|
566
|
+
return (
|
|
567
|
+
<View style={{ flex: 1, flexDirection: 'column' }}>
|
|
568
|
+
{headerCellContent ? (
|
|
569
|
+
<View key={-1} style={styles.tableHeader}>
|
|
570
|
+
<Text style={styles.tableHeaderCell}>{output(headerCellContent, state)}</Text>
|
|
571
|
+
</View>
|
|
572
|
+
) : null}
|
|
573
|
+
{columnCellContents &&
|
|
574
|
+
columnCellContents.map((content, idx) => (
|
|
575
|
+
<ColumnCell content={content} key={`cell-${idx}`} />
|
|
576
|
+
))}
|
|
577
|
+
</View>
|
|
578
|
+
);
|
|
579
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { DefaultStreamChatGenerics } from '../../../types/types';
|
|
4
|
+
import { StreamingMessageViewProps } from '../MessageSimple/StreamingMessageView';
|
|
5
|
+
|
|
6
|
+
export type UseStreamingMessageProps<
|
|
7
|
+
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
|
|
8
|
+
> = Pick<
|
|
9
|
+
StreamingMessageViewProps<StreamChatGenerics>,
|
|
10
|
+
'letterInterval' | 'renderingLetterCount'
|
|
11
|
+
> & { text: string };
|
|
12
|
+
|
|
13
|
+
const DEFAULT_LETTER_INTERVAL = 0;
|
|
14
|
+
const DEFAULT_RENDERING_LETTER_COUNT = 2;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* A hook that returns text in a streamed, typewriter fashion. The speed of streaming is
|
|
18
|
+
* configurable.
|
|
19
|
+
* @param {number} [letterInterval=0] - The timeout between each typing animation in milliseconds.
|
|
20
|
+
* @param {number} [renderingLetterCount=2] - The number of letters to be rendered each time we update.
|
|
21
|
+
* @param {string} text - The text that we want to render in a typewriter fashion.
|
|
22
|
+
* @returns {{ streamedMessageText: string }} - A substring of the text property, up until we've finished rendering the typewriter animation.
|
|
23
|
+
*/
|
|
24
|
+
export const useStreamingMessage = <
|
|
25
|
+
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
|
|
26
|
+
>({
|
|
27
|
+
letterInterval = DEFAULT_LETTER_INTERVAL,
|
|
28
|
+
renderingLetterCount = DEFAULT_RENDERING_LETTER_COUNT,
|
|
29
|
+
text,
|
|
30
|
+
}: UseStreamingMessageProps<StreamChatGenerics>): { streamedMessageText: string } => {
|
|
31
|
+
const [streamedMessageText, setStreamedMessageText] = useState<string>(text);
|
|
32
|
+
const textCursor = useRef<number>(text.length);
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
const textLength = text.length;
|
|
36
|
+
const interval = setInterval(() => {
|
|
37
|
+
if (!text || textCursor.current >= textLength) {
|
|
38
|
+
clearInterval(interval);
|
|
39
|
+
}
|
|
40
|
+
const newCursorValue = textCursor.current + renderingLetterCount;
|
|
41
|
+
const newText = text.substring(0, newCursorValue);
|
|
42
|
+
textCursor.current += newText.length - textCursor.current;
|
|
43
|
+
const codeBlockCounts = (newText.match(/```/g) || []).length;
|
|
44
|
+
const shouldOptimisticallyCloseCodeBlock = codeBlockCounts > 0 && codeBlockCounts % 2 > 0;
|
|
45
|
+
setStreamedMessageText(shouldOptimisticallyCloseCodeBlock ? newText + '```' : newText);
|
|
46
|
+
}, letterInterval);
|
|
47
|
+
|
|
48
|
+
return () => {
|
|
49
|
+
clearInterval(interval);
|
|
50
|
+
};
|
|
51
|
+
}, [letterInterval, renderingLetterCount, text]);
|
|
52
|
+
|
|
53
|
+
return { streamedMessageText };
|
|
54
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useEffect, useMemo, useState } from 'react';
|
|
1
|
+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
Modal,
|
|
4
4
|
NativeSyntheticEvent,
|
|
@@ -58,6 +58,7 @@ import {
|
|
|
58
58
|
|
|
59
59
|
import { isImageMediaLibraryAvailable, triggerHaptic } from '../../native';
|
|
60
60
|
import type { Asset, DefaultStreamChatGenerics } from '../../types/types';
|
|
61
|
+
import { AIStates, useAIState } from '../AITypingIndicatorView';
|
|
61
62
|
import { AutoCompleteInput } from '../AutoCompleteInput/AutoCompleteInput';
|
|
62
63
|
import { CreatePoll } from '../Poll/CreatePollContent';
|
|
63
64
|
|
|
@@ -159,6 +160,7 @@ type MessageInputPropsWithContext<
|
|
|
159
160
|
| 'showPollCreationDialog'
|
|
160
161
|
| 'sendMessage'
|
|
161
162
|
| 'CreatePollContent'
|
|
163
|
+
| 'StopMessageStreamingButton'
|
|
162
164
|
> &
|
|
163
165
|
Pick<MessagesContextValue<StreamChatGenerics>, 'Reply'> &
|
|
164
166
|
Pick<
|
|
@@ -228,6 +230,7 @@ const MessageInputWithContext = <
|
|
|
228
230
|
showPollCreationDialog,
|
|
229
231
|
ShowThreadMessageInChannelButton,
|
|
230
232
|
StartAudioRecordingButton,
|
|
233
|
+
StopMessageStreamingButton,
|
|
231
234
|
suggestions,
|
|
232
235
|
text,
|
|
233
236
|
thread,
|
|
@@ -728,6 +731,13 @@ const MessageInputWithContext = <
|
|
|
728
731
|
})),
|
|
729
732
|
};
|
|
730
733
|
|
|
734
|
+
const { channel } = useChannelContext<StreamChatGenerics>();
|
|
735
|
+
const { aiState } = useAIState(channel);
|
|
736
|
+
|
|
737
|
+
const stopGenerating = useCallback(() => channel?.stopAIResponse(), [channel]);
|
|
738
|
+
const shouldDisplayStopAIGeneration =
|
|
739
|
+
[AIStates.Thinking, AIStates.Generating].includes(aiState) && !!StopMessageStreamingButton;
|
|
740
|
+
|
|
731
741
|
return (
|
|
732
742
|
<>
|
|
733
743
|
<View
|
|
@@ -833,7 +843,10 @@ const MessageInputWithContext = <
|
|
|
833
843
|
</>
|
|
834
844
|
)}
|
|
835
845
|
|
|
836
|
-
{
|
|
846
|
+
{shouldDisplayStopAIGeneration ? (
|
|
847
|
+
<StopMessageStreamingButton onPress={stopGenerating} />
|
|
848
|
+
) : (
|
|
849
|
+
isSendingButtonVisible() &&
|
|
837
850
|
(cooldownRemainingSeconds ? (
|
|
838
851
|
<CooldownTimer seconds={cooldownRemainingSeconds} />
|
|
839
852
|
) : (
|
|
@@ -842,7 +855,8 @@ const MessageInputWithContext = <
|
|
|
842
855
|
disabled={sending.current || !isValidMessage() || (giphyActive && !isOnline)}
|
|
843
856
|
/>
|
|
844
857
|
</View>
|
|
845
|
-
))
|
|
858
|
+
))
|
|
859
|
+
)}
|
|
846
860
|
{audioRecordingEnabled && !micLocked && (
|
|
847
861
|
<GestureDetector gesture={panGestureMic}>
|
|
848
862
|
<Animated.View
|
|
@@ -1144,6 +1158,7 @@ export const MessageInput = <
|
|
|
1144
1158
|
showPollCreationDialog,
|
|
1145
1159
|
ShowThreadMessageInChannelButton,
|
|
1146
1160
|
StartAudioRecordingButton,
|
|
1161
|
+
StopMessageStreamingButton,
|
|
1147
1162
|
text,
|
|
1148
1163
|
uploadNewFile,
|
|
1149
1164
|
uploadNewImage,
|
|
@@ -1233,6 +1248,7 @@ export const MessageInput = <
|
|
|
1233
1248
|
showPollCreationDialog,
|
|
1234
1249
|
ShowThreadMessageInChannelButton,
|
|
1235
1250
|
StartAudioRecordingButton,
|
|
1251
|
+
StopMessageStreamingButton,
|
|
1236
1252
|
suggestions,
|
|
1237
1253
|
t,
|
|
1238
1254
|
text,
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Pressable } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import { useTheme } from '../../contexts/themeContext/ThemeContext';
|
|
5
|
+
import { CircleStop } from '../../icons';
|
|
6
|
+
|
|
7
|
+
export type StopMessageStreamingButtonProps = {
|
|
8
|
+
/** Function that opens attachment options bottom sheet */
|
|
9
|
+
onPress?: () => void;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const StopMessageStreamingButton = (props: StopMessageStreamingButtonProps) => {
|
|
13
|
+
const { onPress } = props;
|
|
14
|
+
|
|
15
|
+
const {
|
|
16
|
+
theme: {
|
|
17
|
+
colors: { accent_blue },
|
|
18
|
+
messageInput: { stopMessageStreamingButton, stopMessageStreamingIcon },
|
|
19
|
+
},
|
|
20
|
+
} = useTheme();
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Pressable
|
|
24
|
+
hitSlop={{ bottom: 15, left: 15, right: 15, top: 15 }}
|
|
25
|
+
onPress={onPress}
|
|
26
|
+
style={[stopMessageStreamingButton]}
|
|
27
|
+
testID='more-options-button'
|
|
28
|
+
>
|
|
29
|
+
<CircleStop fill={accent_blue} size={32} {...stopMessageStreamingIcon} />
|
|
30
|
+
</Pressable>
|
|
31
|
+
);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
StopMessageStreamingButton.displayName = 'StopMessageStreamingButton{messageInput}';
|
|
@@ -45,6 +45,7 @@ import { mergeThemes, ThemeProvider, useTheme } from '../../contexts/themeContex
|
|
|
45
45
|
import { useViewport } from '../../hooks/useViewport';
|
|
46
46
|
import type { DefaultStreamChatGenerics } from '../../types/types';
|
|
47
47
|
import { MessageTextContainer } from '../Message/MessageSimple/MessageTextContainer';
|
|
48
|
+
import { StreamingMessageView } from '../Message/MessageSimple/StreamingMessageView';
|
|
48
49
|
import { OverlayReactions as DefaultOverlayReactions } from '../MessageOverlay/OverlayReactions';
|
|
49
50
|
import type { ReplyProps } from '../Reply/Reply';
|
|
50
51
|
|
|
@@ -451,9 +452,17 @@ const MessageOverlayWithContext = <
|
|
|
451
452
|
</OwnCapabilitiesProvider>
|
|
452
453
|
) : null;
|
|
453
454
|
}
|
|
455
|
+
case 'ai_text':
|
|
456
|
+
return (
|
|
457
|
+
<StreamingMessageView
|
|
458
|
+
key={`ai_message_text_container_${messageContentOrderIndex}`}
|
|
459
|
+
message={message}
|
|
460
|
+
/>
|
|
461
|
+
);
|
|
454
462
|
case 'text':
|
|
455
463
|
default:
|
|
456
|
-
return otherAttachments?.length && otherAttachments[0].actions
|
|
464
|
+
return (otherAttachments?.length && otherAttachments[0].actions) ||
|
|
465
|
+
message.ai_generated ? null : (
|
|
457
466
|
<MessageTextContainer<StreamChatGenerics>
|
|
458
467
|
key={`message_text_container_${messageContentOrderIndex}`}
|
|
459
468
|
message={message}
|
package/src/components/index.ts
CHANGED
|
@@ -97,6 +97,7 @@ export * from './KeyboardCompatibleView/KeyboardCompatibleView';
|
|
|
97
97
|
export * from './Message/hooks/useCreateMessageContext';
|
|
98
98
|
export * from './Message/hooks/useMessageActions';
|
|
99
99
|
export * from './Message/hooks/useMessageActionHandlers';
|
|
100
|
+
export * from './Message/hooks/useStreamingMessage';
|
|
100
101
|
export * from './Message/Message';
|
|
101
102
|
export * from './Message/MessageSimple/MessageAvatar';
|
|
102
103
|
export * from './Message/MessageSimple/MessageBounce';
|
|
@@ -132,6 +133,7 @@ export * from './MessageInput/InputButtons';
|
|
|
132
133
|
export * from './MessageInput/MessageInput';
|
|
133
134
|
export * from './MessageInput/MoreOptionsButton';
|
|
134
135
|
export * from './MessageInput/SendButton';
|
|
136
|
+
export * from './MessageInput/StopMessageStreamingButton';
|
|
135
137
|
export * from './MessageInput/ShowThreadMessageInChannelButton';
|
|
136
138
|
export * from './MessageInput/UploadProgressIndicator';
|
|
137
139
|
|
|
@@ -172,3 +174,6 @@ export * from './Spinner/Spinner';
|
|
|
172
174
|
export * from './Thread/Thread';
|
|
173
175
|
export * from './Thread/components/ThreadFooterComponent';
|
|
174
176
|
export * from './ThreadList/ThreadList';
|
|
177
|
+
|
|
178
|
+
export * from './Message/MessageSimple/StreamingMessageView';
|
|
179
|
+
export * from './AITypingIndicatorView';
|
|
@@ -29,7 +29,7 @@ import { useMessageDetailsForState } from './hooks/useMessageDetailsForState';
|
|
|
29
29
|
|
|
30
30
|
import { isUploadAllowed, MAX_FILE_SIZE_TO_UPLOAD, prettifyFileSize } from './utils/utils';
|
|
31
31
|
|
|
32
|
-
import { PollContentProps } from '../../components';
|
|
32
|
+
import { PollContentProps, StopMessageStreamingButtonProps } from '../../components';
|
|
33
33
|
import { AudioAttachmentProps } from '../../components/Attachment/AudioAttachment';
|
|
34
34
|
import { parseLinksFromText } from '../../components/Message/MessageSimple/utils/parseLinks';
|
|
35
35
|
import type { AttachButtonProps } from '../../components/MessageInput/AttachButton';
|
|
@@ -385,6 +385,7 @@ export type InputMessageInputContextValue<
|
|
|
385
385
|
* Defaults to and accepts same props as: [AudioRecordingButton](https://github.com/GetStream/stream-chat-react-native/blob/main/package/src/components/MessageInput/components/AudioRecorder/AudioRecordingButton.tsx)
|
|
386
386
|
*/
|
|
387
387
|
StartAudioRecordingButton: React.ComponentType<AudioRecordingButtonProps<StreamChatGenerics>>;
|
|
388
|
+
StopMessageStreamingButton: React.ComponentType<StopMessageStreamingButtonProps>;
|
|
388
389
|
/**
|
|
389
390
|
* Custom UI component to render upload progress indicator on attachment preview.
|
|
390
391
|
*
|
|
@@ -586,7 +587,9 @@ export const MessageInputProvider = <
|
|
|
586
587
|
editing,
|
|
587
588
|
initialValue,
|
|
588
589
|
openPollCreationDialog: openPollCreationDialogFromContext,
|
|
590
|
+
StopMessageStreamingButton,
|
|
589
591
|
} = value;
|
|
592
|
+
|
|
590
593
|
const {
|
|
591
594
|
fileUploads,
|
|
592
595
|
imageUploads,
|
|
@@ -1481,6 +1484,7 @@ export const MessageInputProvider = <
|
|
|
1481
1484
|
openPollCreationDialog,
|
|
1482
1485
|
sendMessage, // overriding the originally passed in sendMessage
|
|
1483
1486
|
showPollCreationDialog,
|
|
1487
|
+
StopMessageStreamingButton,
|
|
1484
1488
|
});
|
|
1485
1489
|
return (
|
|
1486
1490
|
<MessageInputContext.Provider
|