communication-react-19
Version:
React library for building modern communication user experiences utilizing Azure Communication Services (React 19 compatible fork)
125 lines • 8.71 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { concatStyleSets, mergeStyles, Stack } from '@fluentui/react';
import { ChatMyMessage } from '@fluentui-contrib/react-chat';
import { mergeClasses } from '@fluentui/react-components';
import { useTheme } from '../../../theming/FluentThemeProvider';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
/* @conditional-compile-remove(file-sharing-acs) */
import { useReducer } from 'react';
import { editBoxStyle, editingButtonStyle, editBoxStyleSet, inputBoxIcon } from '../../styles/EditBox.styles';
import { InputBoxComponent } from '../../InputBoxComponent';
import { InputBoxButton } from '../../InputBoxButton';
import { useChatMyMessageStyles } from '../../styles/MessageThread.styles';
/* @conditional-compile-remove(file-sharing-acs) */
import { _AttachmentUploadCards } from '../../Attachment/AttachmentUploadCards';
import { chatMessageFailedTagStyle, editChatMessageFailedTagStyle, chatMessageFailedTagStackItemStyle, editChatMessageButtonsStackStyle, useChatMessageEditContainerStyles } from '../../styles/ChatMessageComponent.styles';
import { MAXIMUM_LENGTH_OF_MESSAGE } from '../../utils/SendBoxUtils';
/* @conditional-compile-remove(file-sharing-acs) */
import { attachmentMetadataReducer, doesMessageContainMultipleAttachments } from '../../utils/ChatMessageComponentAsEditBoxUtils';
import { getMessageState, onRenderCancelIcon, onRenderSubmitIcon, getTextValidationErrorMessage } from '../../utils/ChatMessageComponentAsEditBoxUtils';
/* @conditional-compile-remove(file-sharing-acs) */
import { getMessageWithAttachmentMetadata } from '../../utils/ChatMessageComponentAsEditBoxUtils';
/**
* @private
*/
export const ChatMessageComponentAsEditBox = (props) => {
var _a;
const { onCancel, onSubmit, strings, message } = props;
/* @conditional-compile-remove(mention) */
const { mentionLookupOptions } = props;
const [textValue, setTextValue] = useState(message.content || '');
/* @conditional-compile-remove(file-sharing-acs) */
const [attachmentMetadata, handleAttachmentAction] = useReducer(attachmentMetadataReducer, (_a = getMessageWithAttachmentMetadata(message)) !== null && _a !== void 0 ? _a : []);
const editTextFieldRef = React.useRef(null);
const theme = useTheme();
const messageState = getMessageState(textValue,
/* @conditional-compile-remove(file-sharing-acs) */ attachmentMetadata !== null && attachmentMetadata !== void 0 ? attachmentMetadata : []);
const submitEnabled = messageState === 'OK';
const editContainerStyles = useChatMessageEditContainerStyles();
const chatMyMessageStyles = useChatMyMessageStyles();
useEffect(() => {
var _a;
(_a = editTextFieldRef.current) === null || _a === void 0 ? void 0 : _a.focus();
}, []);
const setText = (event, newValue) => {
setTextValue(newValue !== null && newValue !== void 0 ? newValue : '');
};
const textValidationErrorMessage = useMemo(() => {
return getTextValidationErrorMessage(messageState, strings.editBoxTextLimit, strings.editBoxEmptyWarningText);
}, [
messageState,
strings.editBoxTextLimit,
strings.editBoxEmptyWarningText,
]);
const iconClassName = useCallback((isHover) => {
const color = isHover ? theme.palette.accent : theme.palette.neutralSecondary;
return mergeStyles(inputBoxIcon, { color });
}, [theme.palette.accent, theme.palette.neutralSecondary]);
const onRenderThemedCancelIcon = useCallback((isHover) => {
return onRenderCancelIcon(iconClassName(isHover));
}, [iconClassName]);
const onRenderThemedSubmitIcon = useCallback((isHover) => {
return onRenderSubmitIcon(iconClassName(isHover));
}, [iconClassName]);
/* @conditional-compile-remove(file-sharing-acs) */
const hasMultipleAttachments = useMemo(() => {
return doesMessageContainMultipleAttachments(message);
}, [message]);
const editBoxStyles = useMemo(() => {
return concatStyleSets(editBoxStyleSet, { textField: { borderColor: theme.palette.themePrimary } });
}, [theme.palette.themePrimary]);
/* @conditional-compile-remove(file-sharing-acs) */
const onRenderAttachmentUploads = useCallback(() => {
return (!!attachmentMetadata &&
attachmentMetadata.length > 0 && (React.createElement("div", { style: { margin: '0.25rem' } },
React.createElement(_AttachmentUploadCards, { attachments: attachmentMetadata, onCancelAttachmentUpload: (id) => {
// edit box only capable of removing attachments
// we need to expand attachment actions
// if we want to support more actions e.g. add
handleAttachmentAction({ type: 'remove', id });
} }))));
}, [attachmentMetadata]);
const getContent = () => {
return (React.createElement(React.Fragment, null,
React.createElement(InputBoxComponent, { "data-ui-id": "edit-box", textFieldRef: editTextFieldRef, inputClassName: editBoxStyle, placeholderText: strings.editBoxPlaceholderText, textValue: textValue, onChange: setText, onKeyDown: (ev) => {
if (ev.key === 'ArrowUp' || ev.key === 'ArrowDown') {
ev.stopPropagation();
}
}, onEnterKeyDown: () => {
submitEnabled &&
onSubmit(textValue,
/* @conditional-compile-remove(file-sharing-acs) */
attachmentMetadata);
}, supportNewline: false, maxLength: MAXIMUM_LENGTH_OF_MESSAGE, errorMessage: textValidationErrorMessage, styles: editBoxStyles,
/* @conditional-compile-remove(mention) */
mentionLookupOptions: mentionLookupOptions }),
React.createElement(Stack, { horizontal: true, horizontalAlign: "end", className: editChatMessageButtonsStackStyle, tokens: { childrenGap: '0.25rem' } },
message.failureReason && (React.createElement(Stack.Item, { grow: true, align: "stretch", className: chatMessageFailedTagStackItemStyle },
React.createElement("div", { className: mergeStyles(chatMessageFailedTagStyle(theme), editChatMessageFailedTagStyle) }, message.failureReason))),
React.createElement(Stack.Item, { align: "end" },
React.createElement(InputBoxButton, { className: editingButtonStyle, ariaLabel: strings.editBoxCancelButton, tooltipContent: strings.editBoxCancelButton, onRenderIcon: onRenderThemedCancelIcon, onClick: () => {
onCancel && onCancel(message.messageId);
}, id: 'dismissIconWrapper', "data-testId": "chat-message-edit-box-cancel-button" })),
React.createElement(Stack.Item, { align: "end" },
React.createElement(InputBoxButton, { className: editingButtonStyle, ariaLabel: strings.editBoxSubmitButton, tooltipContent: strings.editBoxSubmitButton, onRenderIcon: onRenderThemedSubmitIcon, onClick: (e) => {
// it's very important to pass an empty attachment here
// so when user remvoes all attachments, UI can reflect it instantly
// if you set it to undefined, the attachments pre-edited would still be there
// until edit message event is received
submitEnabled &&
onSubmit(textValue, /* @conditional-compile-remove(file-sharing-acs) */ attachmentMetadata);
e.stopPropagation();
}, id: 'submitIconWrapper', "data-testId": "chat-message-edit-box-submit-button" }))), /* @conditional-compile-remove(file-sharing-acs) */
onRenderAttachmentUploads()));
};
const attached = message.attached === true ? 'center' : message.attached === 'bottom' ? 'bottom' : 'top';
return (React.createElement(ChatMyMessage, { attached: attached, root: {
className: mergeClasses(chatMyMessageStyles.root,
/* @conditional-compile-remove(file-sharing-acs) */
hasMultipleAttachments ? chatMyMessageStyles.multipleAttachmentsInEditing : undefined)
}, body: {
className: mergeClasses(editContainerStyles.body, message.failureReason !== undefined ? editContainerStyles.bodyError : editContainerStyles.bodyDefault, attached !== 'top' ? editContainerStyles.bodyAttached : undefined)
} }, getContent()));
};
//# sourceMappingURL=ChatMessageComponentAsEditBox.js.map