// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Icon, mergeStyles, PrimaryButton } from '@fluentui/react';
import { Chat } from '@fluentui-contrib/react-chat';
import { mergeClasses, useArrowNavigationGroup } from '@fluentui/react-components';
import { DownIconStyle, newMessageButtonContainerStyle, messageThreadContainerStyle, messageThreadWrapperContainerStyle, useChatStyles, buttonWithIconStyles, newMessageButtonStyle } from './styles/MessageThread.styles';
import { delay } from './utils/delay';
import { memoizeFnAll } from "../../../acs-ui-common/src";
import { useLocale } from '../localization/LocalizationProvider';
import { isNarrowWidth, _useContainerWidth } from './utils/responsive';
import getParticipantsWhoHaveReadMessage from './utils/getParticipantsWhoHaveReadMessage';
import { useTheme } from '../theming';
import { FluentV9ThemeProvider } from './../theming/FluentV9ThemeProvider';
import LiveAnnouncer from './Announcer/LiveAnnouncer';
import { createStyleFromV8Style } from './styles/v8StyleShim';
import { ChatMessageComponentWrapper } from './ChatMessage/ChatMessageComponentWrapper';
import { MessageStatusIndicatorInternal } from './MessageStatusIndicatorInternal';
import { Announcer } from './Announcer';
const isMessageSame = (first, second) => {
    return first.messageId === second.messageId && first.content === second.content && first.contentType === second.contentType && JSON.stringify(first.createdOn) === JSON.stringify(second.createdOn) && first.senderId === second.senderId && first.senderDisplayName === second.senderDisplayName && JSON.stringify(first.editedOn) === JSON.stringify(second.editedOn);
};
/**
 * Get the latest message from the message array.
 *
 * @param messages
 */
const getLatestChatMessage = (messages) => {
    for (let i = messages.length - 1; i >= 0; i--) {
        const message = messages[i];
        if ((message === null || message === void 0 ? void 0 : message.messageType) === 'chat' && !!message.createdOn) {
            return message;
        }
    }
    return undefined;
};
/**
 * Compare latestMessageFromPreviousMessages & latestMessageFromNewMessages to see if the new message is not from
 * current user.
 */
const isThereNewMessageNotFromCurrentUser = (userId, latestMessageFromPreviousMessages, latestMessageFromNewMessages) => {
    if (latestMessageFromNewMessages === undefined) {
        return false;
    }
    if (latestMessageFromPreviousMessages === undefined) {
        return latestMessageFromNewMessages.senderId !== userId;
    }
    return !isMessageSame(latestMessageFromNewMessages, latestMessageFromPreviousMessages) && latestMessageFromNewMessages.senderId !== userId;
};
/**
 * Returns true if the current user sent the latest message and false otherwise. It will ignore messages that have no
 * sender, messages that have failed to send, and messages from the current user that is marked as SEEN. This is meant
 * as an indirect way to detect if user is at bottom of the chat when the component updates with new messages. If we
 * updated this component due to current user sending a message we want to then call scrollToBottom.
 */
const didUserSendTheLatestMessage = (userId, latestMessageFromPreviousMessages, latestMessageFromNewMessages) => {
    if (latestMessageFromNewMessages === undefined) {
        return false;
    }
    if (latestMessageFromPreviousMessages === undefined) {
        return latestMessageFromNewMessages.senderId === userId;
    }
    return !isMessageSame(latestMessageFromNewMessages, latestMessageFromPreviousMessages) && latestMessageFromNewMessages.senderId === userId;
};
const DefaultJumpToNewMessageButton = (props) => {
    const { text, onClick } = props;
    return React.createElement(PrimaryButton, { className: newMessageButtonStyle, styles: buttonWithIconStyles, text: text, onClick: onClick, onRenderIcon: () => React.createElement(Icon, { iconName: "Down", className: DownIconStyle }) });
};
const memoizeAllMessages = memoizeFnAll((message, showMessageDate, showMessageStatus, strings, index, onUpdateMessage, onCancelEditMessage, onDeleteMessage, onSendMessage, disableEditing, lastSeenChatMessage, lastSendingChatMessage, lastDeliveredChatMessage) => {
    let key = message.messageId;
    let statusToRender = undefined;
    if (message.messageType === 'chat') {
        if ((!message.messageId || message.messageId === '') && 'clientMessageId' in message) {
            key = message.clientMessageId;
        }
        if (showMessageStatus && message.mine) {
            switch (message.messageId) {
                case lastSeenChatMessage:
                    {
                        statusToRender = 'seen';
                        break;
                    }
                case lastSendingChatMessage:
                    {
                        statusToRender = 'sending';
                        break;
                    }
                case lastDeliveredChatMessage:
                    {
                        statusToRender = 'delivered';
                        break;
                    }
            }
        }
        if (message.mine && message.status === 'failed') {
            statusToRender = 'failed';
        }
    }
    return {
        key: key !== null && key !== void 0 ? key : 'id_' + index,
        statusToRender,
        message,
        strings,
        showDate: showMessageDate,
        onUpdateMessage,
        onCancelEditMessage,
        onDeleteMessage,
        onSendMessage,
        disableEditing,
        showMessageStatus
    };
});
const getLastChatMessageIdWithStatus = (messages, status) => {
    for (let i = messages.length - 1; i >= 0; i--) {
        const message = messages[i];
        if ((message === null || message === void 0 ? void 0 : message.messageType) === 'chat' && message.status === status && message.mine) {
            return message.messageId;
        }
    }
    return undefined;
};
const getLastChatMessageForCurrentUser = (messages) => {
    for (let i = messages.length - 1; i >= 0; i--) {
        const message = messages[i];
        if ((message === null || message === void 0 ? void 0 : message.messageType) === 'chat' && message.mine) {
            return message;
        }
    }
    return undefined;
};
/**
 * `MessageThread` allows you to easily create a component for rendering chat messages, handling scrolling behavior of new/old messages and customizing icons & controls inside the chat thread.
 * @param props - of type MessageThreadProps
 *
 * Users will need to provide at least chat messages and userId to render the `MessageThread` component.
 * Users can also customize `MessageThread` by passing in their own Avatar, `MessageStatusIndicator` icon, `JumpToNewMessageButton`, `LoadPreviousMessagesButton` and the behavior of these controls.
 *
 * `MessageThread` internally uses the `Chat` component from `@fluentui-contrib/chat`. You can checkout the details about these components [here](https://microsoft.github.io/fluentui-contrib/react-chat/).
 *
 * @public
 */
export const MessageThread = (props) => {
    var _a;
    const theme = useTheme();
    const chatBody = useMemo(() => {
        return React.createElement(FluentV9ThemeProvider, { v8Theme: theme },
            React.createElement(MessageThreadWrapper, Object.assign({}, props)));
    }, [theme, props]);
    return React.createElement("div", { className: mergeStyles(messageThreadContainerStyle, (_a = props.styles) === null || _a === void 0 ? void 0 : _a.root) }, chatBody);
};
/**
 * @private
 */
export const MessageThreadWrapper = (props) => {
    var _a;
    const { messages: newMessages, userId, participantCount, readReceiptsBySenderId, styles, disableJumpToNewMessageButton = false, showMessageDate = false, showMessageStatus = false, numberOfChatMessagesToReload = 5, onMessageSeen, onRenderMessageStatus, onRenderAvatar, onLoadPreviousChatMessages, onRenderJumpToNewMessageButton, onRenderMessage, onUpdateMessage, onCancelEditMessage, onDeleteMessage, onSendMessage, inlineImageOptions } = props;
    // We need this state to wait for one tick and scroll to bottom after messages have been initialized.
    // Otherwise chatScrollDivRef.current.clientHeight is wrong if we scroll to bottom before messages are initialized.
    const [chatMessagesInitialized, setChatMessagesInitialized] = useState(false);
    const [isAtBottomOfScroll, setIsAtBottomOfScroll] = useState(true);
    const [forceUpdate, setForceUpdate] = useState(0);
    // Used to decide if should auto scroll to bottom or show "new message" button
    const [latestPreviousChatMessage, setLatestPreviousChatMessage] = useState(undefined);
    const [latestCurrentChatMessage, setLatestCurrentChatMessage] = useState(undefined);
    const [existsNewChatMessage, setExistsNewChatMessage] = useState(false);
    const [lastSeenChatMessage, setLastSeenChatMessage] = useState(undefined);
    const [lastDeliveredChatMessage, setLastDeliveredChatMessage] = useState(undefined);
    const [lastSendingChatMessage, setLastSendingChatMessage] = useState(undefined);
    // readCount and participantCount will only need to be updated on-fly when user hover on an indicator
    const [readCountForHoveredIndicator, setReadCountForHoveredIndicator] = useState(undefined);
    const localeStrings = useLocale().strings.messageThread;
    const strings = useMemo(() => (Object.assign(Object.assign({}, localeStrings), props.strings)), [localeStrings, props.strings]);
    // it is required to use useState for messages
    // as the scrolling logic requires re - render at a specific point in time
    const [messages, setMessages] = useState([]);
    // id for the latest deleted message
    const [latestDeletedMessageId, setLatestDeletedMessageId] = useState(undefined);
    // this value is used to check if a message is deleted for the previous value of messages array
    const previousMessagesRef = useRef([]);
    // an aria label for Narrator to notify when a message is deleted
    const [deletedMessageAriaLabel, setDeletedMessageAriaLabel] = useState(undefined);
    const onDeleteMessageCallback = useCallback((messageId) => __awaiter(void 0, void 0, void 0, function* () {
        if (!onDeleteMessage) {
            return;
        }
        try {
            // reset deleted message label in case if there was a value already (messages are deleted 1 after another)
            setDeletedMessageAriaLabel(undefined);
            setLatestDeletedMessageId(messageId);
            lastChatMessageStatus.current = 'deleted';
            // we should set up latestDeletedMessageId before the onDeleteMessage call
            // as otherwise in very rare cases the messages array can be updated before latestDeletedMessageId
            yield onDeleteMessage(messageId);
        }
        catch (e) {
            console.log('onDeleteMessage failed: messageId', messageId, 'error', e);
        }
    }), [onDeleteMessage]);
    const isAllChatMessagesLoadedRef = useRef(false);
    // isAllChatMessagesLoadedRef needs to be updated every time when a new adapter is set in order to display correct data
    // onLoadPreviousChatMessages is updated when a new adapter is set
    useEffect(() => {
        if (onLoadPreviousChatMessages) {
            isAllChatMessagesLoadedRef.current = false;
        }
    }, [onLoadPreviousChatMessages]);
    const previousTopRef = useRef(-1);
    const previousHeightRef = useRef(-1);
    const messageIdSeenByMeRef = useRef('');
    const chatScrollDivRef = useRef(null);
    const isLoadingChatMessagesRef = useRef(false);
    useEffect(() => {
        if (latestDeletedMessageId === undefined) {
            setDeletedMessageAriaLabel(undefined);
        }
        else {
            if (!previousMessagesRef.current.find(message => message.messageId === latestDeletedMessageId)) {
                // the message is deleted in previousMessagesRef
                // no need to update deletedMessageAriaLabel
                setDeletedMessageAriaLabel(undefined);
            }
            else if (!messages.find(message => message.messageId === latestDeletedMessageId)) {
                // the message is deleted in messages array but still exists in previousMessagesRef
                // update deletedMessageAriaLabel
                setDeletedMessageAriaLabel(strings.messageDeletedAnnouncementAriaLabel);
            }
            else {
                // the message exists in both arrays
                // no need to update deletedMessageAriaLabel
                setDeletedMessageAriaLabel(undefined);
            }
        }
        previousMessagesRef.current = messages;
    }, [latestDeletedMessageId, messages, strings.messageDeletedAnnouncementAriaLabel]);
    const messagesRef = useRef(messages);
    const setMessagesRef = (messagesWithAttachedValue) => {
        messagesRef.current = messagesWithAttachedValue;
        setMessages(messagesWithAttachedValue);
    };
    const isAtBottomOfScrollRef = useRef(isAtBottomOfScroll);
    const setIsAtBottomOfScrollRef = (isAtBottomOfScrollValue) => {
        isAtBottomOfScrollRef.current = isAtBottomOfScrollValue;
        setIsAtBottomOfScroll(isAtBottomOfScrollValue);
    };
    const chatMessagesInitializedRef = useRef(chatMessagesInitialized);
    const setChatMessagesInitializedRef = (chatMessagesInitialized) => {
        chatMessagesInitializedRef.current = chatMessagesInitialized;
        setChatMessagesInitialized(chatMessagesInitialized);
    };
    const chatThreadRef = useRef(null);
    // When the chat thread is narrow, we perform space optimizations such as overlapping
    // the avatar on top of the chat message and moving the chat accept/reject edit buttons
    // to a new line
    const chatThreadWidth = _useContainerWidth(chatThreadRef);
    const isNarrow = chatThreadWidth ? isNarrowWidth(chatThreadWidth) : false;
    /**
     * ClientHeight controls the number of messages to render. However ClientHeight will not be initialized after the
     * first render (not sure but I guess Fluent is updating it in hook which is after render maybe?) so we need to
     * trigger a re-render until ClientHeight is initialized. This force re-render should only happen once.
     */
    const clientHeight = (_a = chatThreadRef.current) === null || _a === void 0 ? void 0 : _a.clientHeight;
    // we try to only send those message status if user is scrolled to the bottom.
    const sendMessageStatusIfAtBottom = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
        if (!isAtBottomOfScrollRef.current || !document.hasFocus() || !messagesRef.current || messagesRef.current.length === 0 || !showMessageStatus) {
            return;
        }
        const messagesWithId = messagesRef.current.filter(message => {
            return message.messageType === 'chat' && !message.mine && !!message.messageId;
        });
        if (messagesWithId.length === 0) {
            return;
        }
        const lastMessage = messagesWithId[messagesWithId.length - 1];
        try {
            if (onMessageSeen && lastMessage && lastMessage.messageId && lastMessage.messageId !== messageIdSeenByMeRef.current) {
                yield onMessageSeen(lastMessage.messageId);
                messageIdSeenByMeRef.current = lastMessage.messageId;
            }
        }
        catch (e) {
            console.log('onMessageSeen Error', lastMessage, e);
        }
    }), [showMessageStatus, onMessageSeen]);
    const scrollToBottom = useCallback(() => {
        if (chatScrollDivRef.current) {
            chatScrollDivRef.current.scrollTop = chatScrollDivRef.current.scrollHeight;
        }
        setExistsNewChatMessage(false);
        setIsAtBottomOfScrollRef(true);
        sendMessageStatusIfAtBottom();
    }, [sendMessageStatusIfAtBottom]);
    const handleScrollToTheBottom = useCallback(() => {
        if (!chatScrollDivRef.current) {
            return;
        }
        const atBottom = Math.ceil(chatScrollDivRef.current.scrollTop) >= chatScrollDivRef.current.scrollHeight - chatScrollDivRef.current.clientHeight;
        if (atBottom) {
            sendMessageStatusIfAtBottom();
            if (!isAtBottomOfScrollRef.current) {
                scrollToBottom();
            }
        }
        setIsAtBottomOfScrollRef(atBottom);
    }, [scrollToBottom, sendMessageStatusIfAtBottom]);
    // Infinite scrolling + threadInitialize function
    const fetchNewMessageWhenAtTop = useCallback(() => __awaiter(void 0, void 0, void 0, function* () {
        if (!isLoadingChatMessagesRef.current) {
            if (onLoadPreviousChatMessages) {
                isLoadingChatMessagesRef.current = true;
                try {
                    // Fetch message until scrollTop reach the threshold for fetching new message
                    while (!isAllChatMessagesLoadedRef.current && chatScrollDivRef.current && chatScrollDivRef.current.scrollTop <= 500) {
                        isAllChatMessagesLoadedRef.current = yield onLoadPreviousChatMessages(numberOfChatMessagesToReload);
                        yield delay(200);
                    }
                }
                finally {
                    // Set isLoadingChatMessagesRef to false after messages are fetched
                    isLoadingChatMessagesRef.current = false;
                }
            }
        }
    }), [numberOfChatMessagesToReload, onLoadPreviousChatMessages]);
    // The below 2 of useEffects are design for fixing infinite scrolling problem
    // Scrolling element will behave differently when scrollTop = 0(it sticks at the top)
    // we need to get previousTop before it prepend contents
    // Execute order [newMessage useEffect] => get previousTop => dom update => [messages useEffect]
    useEffect(() => {
        if (!chatScrollDivRef.current) {
            return;
        }
        previousTopRef.current = chatScrollDivRef.current.scrollTop;
        previousHeightRef.current = chatScrollDivRef.current.scrollHeight;
    }, [newMessages]);
    useEffect(() => {
        if (!chatScrollDivRef.current) {
            return;
        }
        chatScrollDivRef.current.scrollTop = chatScrollDivRef.current.scrollHeight - (previousHeightRef.current - previousTopRef.current);
    }, [messages]);
    // Fetch more messages to make the scroll bar appear, infinity scroll is then handled in the handleScroll function.
    useEffect(() => {
        fetchNewMessageWhenAtTop();
    }, [fetchNewMessageWhenAtTop]);
    /**
     * One time run useEffects. Sets up listeners when component is mounted and tears down listeners when component
     * unmounts unless these function changed
     */
    useEffect(() => {
        window && window.addEventListener('click', sendMessageStatusIfAtBottom);
        window && window.addEventListener('focus', sendMessageStatusIfAtBottom);
        return () => {
            window && window.removeEventListener('click', sendMessageStatusIfAtBottom);
            window && window.removeEventListener('focus', sendMessageStatusIfAtBottom);
        };
    }, [sendMessageStatusIfAtBottom]);
    useEffect(() => {
        const chatScrollDiv = chatScrollDivRef.current;
        chatScrollDiv === null || chatScrollDiv === void 0 ? void 0 : chatScrollDiv.addEventListener('scroll', handleScrollToTheBottom);
        chatScrollDiv === null || chatScrollDiv === void 0 ? void 0 : chatScrollDiv.addEventListener('scroll', fetchNewMessageWhenAtTop);
        return () => {
            chatScrollDiv === null || chatScrollDiv === void 0 ? void 0 : chatScrollDiv.removeEventListener('scroll', handleScrollToTheBottom);
            chatScrollDiv === null || chatScrollDiv === void 0 ? void 0 : chatScrollDiv.removeEventListener('scroll', fetchNewMessageWhenAtTop);
        };
    }, [fetchNewMessageWhenAtTop, handleScrollToTheBottom]);
    useEffect(() => {
        if (clientHeight === undefined) {
            setForceUpdate(forceUpdate + 1);
            return;
        }
        // Only scroll to bottom if isAtBottomOfScrollRef is true
        isAtBottomOfScrollRef.current && scrollToBottom();
    }, [clientHeight, forceUpdate, scrollToBottom, chatMessagesInitialized]);
    useEffect(() => {
        var _a;
        const newStatus = (_a = getLastChatMessageForCurrentUser(newMessages)) === null || _a === void 0 ? void 0 : _a.status;
        if (newStatus !== undefined) {
            if (lastChatMessageStatus.current === 'deleted' && newStatus === 'sending') {
                // enforce message life cycle
                // message status should always be [ sending -> delivered -> seen (optional) -> deleted ] or [sending -> failed -> deleted]
                // not any other way around
                // therefore, if current message status is deleted, we should only update it if newStatus is sending
                lastChatMessageStatus.current = newStatus;
            }
            else if (lastChatMessageStatus.current !== 'deleted') {
                lastChatMessageStatus.current = newStatus;
            }
        }
        // The hook should depend on newMessages not on messages as otherwise it will skip the sending status for a first message
    }, [newMessages]);
    /**
     * This needs to run to update latestPreviousChatMessage & latestCurrentChatMessage.
     * These two states are used to manipulate scrollbar
     */
    useEffect(() => {
        setLatestPreviousChatMessage(getLatestChatMessage(messagesRef.current));
        setLatestCurrentChatMessage(getLatestChatMessage(newMessages));
        setMessagesRef(newMessages);
        !chatMessagesInitializedRef.current && setChatMessagesInitializedRef(true);
        setLastDeliveredChatMessage(getLastChatMessageIdWithStatus(newMessages, 'delivered'));
        setLastSeenChatMessage(getLastChatMessageIdWithStatus(newMessages, 'seen'));
        setLastSendingChatMessage(getLastChatMessageIdWithStatus(newMessages, 'sending'));
    }, [newMessages]);
    /**
     * This needs to run after messages are rendered so we can manipulate the scroll bar.
     */
    useEffect(() => {
        // If user just sent the latest message then we assume we can move user to bottom of scroll.
        if (isThereNewMessageNotFromCurrentUser(userId, latestPreviousChatMessage, latestCurrentChatMessage) && !isAtBottomOfScrollRef.current) {
            setExistsNewChatMessage(true);
        }
        else if (didUserSendTheLatestMessage(userId, latestPreviousChatMessage, latestCurrentChatMessage) || isAtBottomOfScrollRef.current) {
            scrollToBottom();
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [messages]);
    const lastChatMessageStatus = useRef(undefined);
    const participantCountRef = useRef(participantCount);
    const readReceiptsBySenderIdRef = useRef(readReceiptsBySenderId);
    participantCountRef.current = participantCount;
    readReceiptsBySenderIdRef.current = readReceiptsBySenderId;
    const onActionButtonClickMemo = useCallback((message, setMessageReadBy) => {
        if (participantCountRef.current && participantCountRef.current - 1 > 1 && readReceiptsBySenderIdRef.current) {
            setMessageReadBy(getParticipantsWhoHaveReadMessage(message, readReceiptsBySenderIdRef.current));
        }
    }, []);
    const defaultStatusRenderer = useCallback((message, participantCount, readCount, status) => {
        // we should only announce label if the message status isn't deleted
        // because after message is deleted, we now need to render statusIndicator for previous messages
        // and their status has been announced already and we should not announce them again
        const shouldAnnounce = lastChatMessageStatus.current !== 'deleted';
        const onToggleToolTip = (isToggled) => {
            if (isToggled && readReceiptsBySenderIdRef.current) {
                setReadCountForHoveredIndicator(getParticipantsWhoHaveReadMessage(message, readReceiptsBySenderIdRef.current).length);
            }
            else {
                setReadCountForHoveredIndicator(undefined);
            }
        };
        return React.createElement(MessageStatusIndicatorInternal, { status: status, readCount: readCount, onToggleToolTip: onToggleToolTip, 
            // -1 because participant count does not include myself
            remoteParticipantsCount: participantCount ? participantCount - 1 : 0, shouldAnnounce: shouldAnnounce });
    }, []);
    const theme = useTheme();
    const messagesToDisplay = useMemo(() => {
        return memoizeAllMessages(memoizedMessageFn => {
            return messages.map((message, index) => {
                return memoizedMessageFn(message, showMessageDate, showMessageStatus, strings, index, onUpdateMessage, onCancelEditMessage, onDeleteMessageCallback, onSendMessage, props.disableEditing, lastDeliveredChatMessage, lastSeenChatMessage, lastSendingChatMessage);
            });
        });
    }, [lastDeliveredChatMessage, lastSeenChatMessage, lastSendingChatMessage, messages, onCancelEditMessage, onDeleteMessageCallback, onSendMessage, onUpdateMessage, props.disableEditing, showMessageDate, showMessageStatus, strings]);
    const classes = useChatStyles();
    const chatArrowNavigationAttributes = useArrowNavigationGroup({
        axis: 'vertical',
        memorizeCurrent: false
    });
    return React.createElement("div", { className: mergeStyles(messageThreadWrapperContainerStyle), ref: chatThreadRef },
        existsNewChatMessage && !disableJumpToNewMessageButton && React.createElement("div", { className: mergeStyles(newMessageButtonContainerStyle, styles === null || styles === void 0 ? void 0 : styles.newMessageButtonContainer) }, onRenderJumpToNewMessageButton ? onRenderJumpToNewMessageButton({
            text: strings.newMessagesIndicator,
            onClick: scrollToBottom
        }) : React.createElement(DefaultJumpToNewMessageButton, { text: strings.newMessagesIndicator, onClick: scrollToBottom })),
        React.createElement(LiveAnnouncer, null,
            React.createElement(FluentV9ThemeProvider, { v8Theme: theme },
                React.createElement(Chat
                // styles?.chatContainer used in className and style prop as style prop can't handle CSS selectors
                , Object.assign({ 
                    // styles?.chatContainer used in className and style prop as style prop can't handle CSS selectors
                    className: mergeClasses(classes.root, mergeStyles(styles === null || styles === void 0 ? void 0 : styles.chatContainer)), ref: chatScrollDivRef, style: Object.assign({}, createStyleFromV8Style(styles === null || styles === void 0 ? void 0 : styles.chatContainer)) }, chatArrowNavigationAttributes),
                    latestDeletedMessageId && React.createElement(Announcer, { key: latestDeletedMessageId, announcementString: deletedMessageAriaLabel, ariaLive: 'polite' }),
                    messagesToDisplay.map((message) => {
                        return React.createElement(MemoChatMessageComponentWrapper, Object.assign({}, message, { userId: userId, key: message.key, styles: styles, shouldOverlapAvatarAndMessage: isNarrow, strings: strings, onRenderAvatar: onRenderAvatar, onRenderMessage: onRenderMessage, onRenderMessageStatus: onRenderMessageStatus, defaultStatusRenderer: defaultStatusRenderer, onActionButtonClick: onActionButtonClickMemo, readCount: readCountForHoveredIndicator, participantCount: participantCount, inlineImageOptions: inlineImageOptions }));
                    })))));
};
const MemoChatMessageComponentWrapper = React.memo((obj) => {
    return React.createElement(ChatMessageComponentWrapper, Object.assign({}, obj));
});
//# sourceMappingURL=MessageThread.js.map