communication-react-19
Version:
React library for building modern communication user experiences utilizing Azure Communication Services (React 19 compatible fork)
84 lines • 5.36 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { Text, mergeStyles } from '@fluentui/react';
import { ChatMessage as FluentChatMessage } from '@fluentui-contrib/react-chat';
import React, { useCallback, useMemo } from 'react';
import { chatMessageDateStyle, chatMessageAuthorStyle, chatMessageDateFailedStyle } from '../../styles/ChatMessageComponent.styles';
import { useIdentifiers } from '../../../identifiers/IdentifierProvider';
import { useTheme } from '../../../theming';
import { useLocale } from '../../../localization';
import { createStyleFromV8Style } from '../../styles/v8StyleShim';
import { mergeClasses } from '@fluentui/react-components';
import { useChatMessageStyles, useChatMessageCommonStyles } from '../../styles/MessageThread.styles';
import { generateCustomizedTimestamp, generateDefaultTimestamp, getMessageBubbleContent, getMessageEditedDetails } from '../../utils/ChatMessageComponentUtils';
/* @conditional-compile-remove(file-sharing-acs) */
import { doesMessageContainMultipleAttachments } from '../../utils/ChatMessageComponentAsEditBoxUtils';
/** @private */
const MessageBubble = (props) => {
const ids = useIdentifiers();
const theme = useTheme();
const locale = useLocale();
const { userId, message, showDate, messageContainerStyle, strings, onRenderAttachmentDownloads, inlineImageOptions, shouldOverlapAvatarAndMessage, actionsForAttachment,
/* @conditional-compile-remove(mention) */
mentionDisplayOptions, onDisplayDateTimeString } = props;
const formattedTimestamp = useMemo(() => {
const defaultTimeStamp = message.createdOn
? generateDefaultTimestamp(message.createdOn, showDate, strings)
: undefined;
const customTimestamp = message.createdOn
? generateCustomizedTimestamp(message.createdOn, locale, onDisplayDateTimeString)
: '';
return customTimestamp || defaultTimeStamp;
}, [locale, message.createdOn, onDisplayDateTimeString, showDate, strings]);
const getMessageDetails = useCallback(() => {
return getMessageEditedDetails(message, theme, strings.editedTag);
}, [strings.editedTag, theme, message]);
const getContent = useCallback(() => {
return getMessageBubbleContent(message, strings, userId, inlineImageOptions,
/* @conditional-compile-remove(mention) */
mentionDisplayOptions, onRenderAttachmentDownloads, actionsForAttachment);
}, [
actionsForAttachment,
inlineImageOptions,
/* @conditional-compile-remove(mention) */ mentionDisplayOptions,
message,
onRenderAttachmentDownloads,
strings,
userId
]);
const isBlockedMessage =
// eslint-disable-next-line no-constant-binary-expression
false || /* @conditional-compile-remove(data-loss-prevention) */ message.messageType === 'blocked';
const chatMessageCommonStyles = useChatMessageCommonStyles();
/* @conditional-compile-remove(file-sharing-acs) */
const hasMultipleAttachments = useMemo(() => {
return doesMessageContainMultipleAttachments(message);
}, [message]);
const chatMessageStyles = useChatMessageStyles();
const chatItemMessageContainerClassName = mergeClasses(chatMessageCommonStyles.body, chatMessageStyles.body,
// disable placeholder functionality for GA releases as it might confuse users
chatMessageCommonStyles.bodyWithPlaceholderImage, isBlockedMessage
? chatMessageCommonStyles.blocked
: props.message.status === 'failed'
? chatMessageCommonStyles.failed
: undefined, shouldOverlapAvatarAndMessage ? chatMessageStyles.avatarOverlap : chatMessageStyles.avatarNoOverlap,
/* @conditional-compile-remove(file-sharing-acs) */
hasMultipleAttachments ? chatMessageStyles.multipleAttachments : undefined, message.attached === 'top' || message.attached === false
? chatMessageStyles.bodyWithAvatar
: chatMessageStyles.bodyWithoutAvatar,
// messageContainerStyle used in className and style prop as style prop can't handle CSS selectors
mergeStyles(messageContainerStyle));
const attached = message.attached === true ? 'center' : message.attached === 'bottom' ? 'bottom' : 'top';
const chatMessage = (React.createElement(React.Fragment, null,
React.createElement("div", { key: props.message.messageId },
React.createElement(FluentChatMessage, { attached: attached, key: props.message.messageId, root: {
className: chatMessageStyles.root
}, author: React.createElement(Text, { className: chatMessageAuthorStyle }, message.senderDisplayName), body: {
className: chatItemMessageContainerClassName,
style: Object.assign({}, createStyleFromV8Style(messageContainerStyle))
}, "data-testid": "chat-composite-message", timestamp: React.createElement(Text, { className: props.message.status === 'failed' ? chatMessageDateFailedStyle(theme) : chatMessageDateStyle(theme), "data-testid": ids.messageTimestamp }, formattedTimestamp), details: getMessageDetails() }, getContent()))));
return chatMessage;
};
/** @private */
export const ChatMessageComponentAsMessageBubble = React.memo(MessageBubble);
//# sourceMappingURL=ChatMessageComponentAsMessageBubble.js.map