/
MessageText.tsx
103 lines (88 loc) · 3.66 KB
/
MessageText.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import React, { useMemo } from 'react';
import { QuotedMessage as DefaultQuotedMessage } from './QuotedMessage';
import { isOnlyEmojis, messageHasAttachments } from './utils';
import { useComponentContext, useMessageContext, useTranslationContext } from '../../context';
import { renderText as defaultRenderText } from './renderText';
import { MessageErrorText } from './MessageErrorText';
import type { TranslationLanguages } from 'stream-chat';
import type { MessageContextValue, StreamMessage } from '../../context';
import type { DefaultStreamChatGenerics } from '../../types/types';
export type MessageTextProps<
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics
> = {
/* Replaces the CSS class name placed on the component's inner `div` container */
customInnerClass?: string;
/* Adds a CSS class name to the component's outer `div` container */
customWrapperClass?: string;
/* The `StreamChat` message object, which provides necessary data to the underlying UI components (overrides the value stored in `MessageContext`) */
message?: StreamMessage<StreamChatGenerics>;
/* Theme string to be added to CSS class names */
theme?: string;
} & Pick<MessageContextValue<StreamChatGenerics>, 'renderText'>;
const UnMemoizedMessageTextComponent = <
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics
>(
props: MessageTextProps<StreamChatGenerics>,
) => {
const {
customInnerClass,
customWrapperClass = '',
message: propMessage,
renderText: propsRenderText,
theme = 'simple',
} = props;
const { QuotedMessage = DefaultQuotedMessage } = useComponentContext<StreamChatGenerics>(
'MessageText',
);
const {
message: contextMessage,
onMentionsClickMessage,
onMentionsHoverMessage,
renderText: contextRenderText,
unsafeHTML,
} = useMessageContext<StreamChatGenerics>('MessageText');
const renderText = propsRenderText ?? contextRenderText ?? defaultRenderText;
const { userLanguage } = useTranslationContext('MessageText');
const message = propMessage || contextMessage;
const hasAttachment = messageHasAttachments(message);
const messageTextToRender =
message.i18n?.[`${userLanguage}_text` as `${TranslationLanguages}_text`] || message.text;
// eslint-disable-next-line react-hooks/exhaustive-deps
const messageText = useMemo(() => renderText(messageTextToRender, message.mentioned_users), [
message.mentioned_users,
messageTextToRender,
]);
const wrapperClass = customWrapperClass || 'str-chat__message-text';
const innerClass =
customInnerClass || `str-chat__message-text-inner str-chat__message-${theme}-text-inner`;
if (!messageTextToRender && !message.quoted_message) return null;
return (
<div className={wrapperClass} tabIndex={0}>
<div
className={`
${innerClass}
${hasAttachment ? ` str-chat__message-${theme}-text-inner--has-attachment` : ''}
${
isOnlyEmojis(message.text) && !message.quoted_message
? ` str-chat__message-${theme}-text-inner--is-emoji`
: ''
}
`.trim()}
data-testid='message-text-inner-wrapper'
onClick={onMentionsClickMessage}
onMouseOver={onMentionsHoverMessage}
>
{message.quoted_message && <QuotedMessage />}
<MessageErrorText message={message} theme={theme} />
{unsafeHTML && message.html ? (
<div dangerouslySetInnerHTML={{ __html: message.html }} />
) : (
<div>{messageText}</div>
)}
</div>
</div>
);
};
export const MessageText = React.memo(
UnMemoizedMessageTextComponent,
) as typeof UnMemoizedMessageTextComponent;