UNPKG

@uimkit/uikit-react

Version:

<img style="width:64px" src="https://mgmt.uimkit.chat/media/img/avatar.png"/>

243 lines (236 loc) 16.8 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var tslib = require('tslib'); var React = require('react'); require('../../types/models.js'); require('../../types/events.js'); require('../../context/TranslationContext.js'); require('../../context/UIKitContext.js'); var ComponentContext = require('../../context/ComponentContext.js'); var ChatActionContext = require('../../context/ChatActionContext.js'); require('../../context/MessageInputContext.js'); require('../../context/UIMessageContext.js'); var ChatStateContext = require('../../context/ChatStateContext.js'); var EmptyStateIndicator = require('../EmptyStateIndicator/EmptyStateIndicator.js'); var MessageListNotifications = require('./MessageListNotifications.js'); require('../Loading/LoadingErrorIndicator.js'); var LoadingIndicator = require('../Loading/LoadingIndicator.js'); var MessageNotification = require('./MessageNotification.js'); var index = require('../../node_modules/.pnpm/react-virtuoso@4.1.0_biqbaboplfbrettd7655fr4n2y/node_modules/react-virtuoso/dist/index.mjs.js'); var DateSeparator = require('../DateSeparator/DateSeparator.js'); var useShouldForceScrollToBottom = require('./hooks/useShouldForceScrollToBottom.js'); var useNewMessageNotification = require('./hooks/useNewMessageNotification.js'); var usePrependedMessagesCount = require('./hooks/usePrependedMessagesCount.js'); var UIMessage = require('../UIMessage/UIMessage.js'); require('../UIMessage/MessagePlugins.js'); require('../UIMessage/MessageStatus.js'); require('../UIMessage/MessageProgress.js'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var React__default = /*#__PURE__*/_interopDefaultLegacy(React); var PREPEND_OFFSET = Math.pow(10, 7); function captureResizeObserverExceededError(e) { if (e.message === 'ResizeObserver loop completed with undelivered notifications.' || e.message === 'ResizeObserver loop limit exceeded') { e.stopImmediatePropagation(); } } function useCaptureResizeObserverExceededError() { React.useEffect(function () { window.addEventListener('error', captureResizeObserverExceededError); return function () { window.removeEventListener('error', captureResizeObserverExceededError); }; }, []); } function fractionalItemSize(element) { return element.getBoundingClientRect().height; } function findMessageIndex(messages, id) { return messages.findIndex(function (message) { return message.id === id; }); } function calculateInitialTopMostItemIndex(messages, highlightedMessageId) { if (highlightedMessageId) { var index = findMessageIndex(messages, highlightedMessageId); if (index !== -1) { console.log('calculateInitialTopMostItemIndex: ', index); return { align: 'center', index: index }; } } return messages.length - 1; } var VirtualizedMessageListWithContext = function (props) { var additionalVirtuosoProps = props.additionalVirtuosoProps, conversation = props.conversation, messages = props.messages, highlightedMessageId = props.highlightedMessageId, intervalsTimer = props.intervalsTimer, hasMore = props.hasMore, loadMore = props.loadMore, loadingMore = props.loadingMore, hasMoreNewer = props.hasMoreNewer, loadMoreNewer = props.loadMoreNewer, loadingMoreNewer = props.loadingMoreNewer, suppressAutoscroll = props.suppressAutoscroll, jumpToLatestMessage = props.jumpToLatestMessage, head = props.head, defaultItemHeight = props.defaultItemHeight, customMessageRenderer = props.customMessageRenderer, _a = props.stickToBottomScrollBehavior, stickToBottomScrollBehavior = _a === void 0 ? 'smooth' : _a, _b = props.overscan, overscan = _b === void 0 ? 0 : _b, scrollSeekPlaceHolder = props.scrollSeekPlaceHolder, _c = props.scrollToLatestMessageOnFocus, scrollToLatestMessageOnFocus = _c === void 0 ? false : _c, propMessage = props.UIMessage; useCaptureResizeObserverExceededError(); var _d = ComponentContext.useComponentContext('VirtualizedMessageList'), _e = _d.UIMessage, contextMessage = _e === void 0 ? UIMessage.UIMessage : _e, _f = _d.EmptyStateIndicator, EmptyStateIndicator$1 = _f === void 0 ? EmptyStateIndicator.EmptyStateIndicator : _f, _g = _d.LoadingIndicator, LoadingIndicator$1 = _g === void 0 ? LoadingIndicator.LoadingIndicator : _g, _h = _d.MessageListNotifications, MessageListNotifications$1 = _h === void 0 ? MessageListNotifications.MessageListNotifications : _h, _j = _d.MessageNotification, MessageNotification$1 = _j === void 0 ? MessageNotification.MessageNotification : _j; var MessageUIComponent = propMessage || contextMessage; var processedMessages = React.useMemo(function () { if (typeof messages === 'undefined') { return []; } return messages; }, [ messages, messages === null || messages === void 0 ? void 0 : messages.length, ]); var virtuoso = React.useRef(null); var _k = useNewMessageNotification.useNewMessageNotification(processedMessages, conversation.account, hasMoreNewer), atBottom = _k.atBottom, isMessageListScrolledToBottom = _k.isMessageListScrolledToBottom, newMessagesNotification = _k.newMessagesNotification, setIsMessageListScrolledToBottom = _k.setIsMessageListScrolledToBottom, setNewMessagesNotification = _k.setNewMessagesNotification; var scrollToBottom = React.useCallback(function () { return tslib.__awaiter(void 0, void 0, void 0, function () { return tslib.__generator(this, function (_a) { switch (_a.label) { case 0: if (!hasMoreNewer) return [3 /*break*/, 2]; return [4 /*yield*/, jumpToLatestMessage()]; case 1: _a.sent(); return [2 /*return*/]; case 2: if (virtuoso.current) { virtuoso.current.scrollToIndex(processedMessages.length - 1); } setNewMessagesNotification(false); return [2 /*return*/]; } }); }); }, [ virtuoso, processedMessages, setNewMessagesNotification, // processedMessages were incorrectly rebuilt with a new object identity at some point, hence the .length usage processedMessages.length, hasMoreNewer, jumpToLatestMessage, ]); var _l = React__default["default"].useState(false), newMessagesReceivedInBackground = _l[0], setNewMessagesReceivedInBackground = _l[1]; var resetNewMessagesReceivedInBackground = React.useCallback(function () { setNewMessagesReceivedInBackground(false); }, []); React.useEffect(function () { setNewMessagesReceivedInBackground(true); }, [messages]); var scrollToBottomIfConfigured = React.useCallback(function (event) { if (scrollToLatestMessageOnFocus && event.target === window) { if (newMessagesReceivedInBackground) { setTimeout(scrollToBottom, 100); } } }, [scrollToLatestMessageOnFocus, scrollToBottom, newMessagesReceivedInBackground]); React.useEffect(function () { if (typeof window !== 'undefined') { window.addEventListener('focus', scrollToBottomIfConfigured); window.addEventListener('blur', resetNewMessagesReceivedInBackground); } return function () { window.removeEventListener('focus', scrollToBottomIfConfigured); window.removeEventListener('blur', resetNewMessagesReceivedInBackground); }; }, [scrollToBottomIfConfigured]); // 在前面追加的消息数,也就是 loadMore 加载的消息总量 var numItemsPrepended = usePrependedMessagesCount.usePrependedMessagesCount(processedMessages); var _m = React.useState(+new Date()), messageSetKey = _m[0], setMessageSetKey = _m[1]; var firstMessageId = React.useRef(); React.useEffect(function () { var _a; var continuousSet = messages === null || messages === void 0 ? void 0 : messages.find(function (message) { return message.id === firstMessageId.current; }); if (!continuousSet) { setMessageSetKey(+new Date()); } firstMessageId.current = (_a = messages === null || messages === void 0 ? void 0 : messages[0]) === null || _a === void 0 ? void 0 : _a.id; }, [messages]); // 是否要强制滚动到最底部 var shouldForceScrollToBottom = useShouldForceScrollToBottom.useShouldForceScrollToBottom(processedMessages, conversation.account); // 列表 totalCount 改变时调用 var followOutput = function (isAtBottom) { if (hasMoreNewer || suppressAutoscroll) { return false; } if (shouldForceScrollToBottom()) { return isAtBottom ? stickToBottomScrollBehavior : 'auto'; } // a message from another user has been received - don't scroll to bottom unless already there return isAtBottom ? stickToBottomScrollBehavior : false; }; var messageRenderer = React.useCallback(function (messages, virtuosoIndex) { var _a, _b; var messageIndex = virtuosoIndex + numItemsPrepended - PREPEND_OFFSET; // use custom renderer supplied by client if present and skip the rest if (customMessageRenderer) { return customMessageRenderer(messages, messageIndex); } var message = messages[messageIndex]; var preMessageTimer = messageIndex > 0 ? (_a = messages[messageIndex - 1]) === null || _a === void 0 ? void 0 : _a.sent_at : -1; var currrentTimer = (_b = message === null || message === void 0 ? void 0 : message.sent_at) !== null && _b !== void 0 ? _b : 0; var isShowIntervalsTimer = preMessageTimer !== -1 ? (currrentTimer - preMessageTimer) >= intervalsTimer : false; if (!message) return React__default["default"].createElement("div", { style: { height: '1px' } }); // returning null or zero height breaks the virtuoso return (React__default["default"].createElement("li", { className: "message-list-item" }, isShowIntervalsTimer && React__default["default"].createElement(DateSeparator.DateSeparator, { date: currrentTimer ? new Date(currrentTimer) : null }), React__default["default"].createElement(MessageUIComponent, { message: message }))); }, [customMessageRenderer, numItemsPrepended]); var virtuosoComponents = React.useMemo(function () { var EmptyPlaceholder = function () { return (React__default["default"].createElement(React__default["default"].Fragment, null, EmptyStateIndicator$1 && (React__default["default"].createElement(EmptyStateIndicator$1, { listType: 'message' })))); }; var Header = function () { return loadingMore ? (React__default["default"].createElement("div", { className: 'uim__virtual-list__loading' }, React__default["default"].createElement(LoadingIndicator$1, { size: 20 }))) : (head || null); }; /* const Footer: Components['Footer'] = () => TypingIndicator ? <TypingIndicator avatarSize={24} /> : <></>; */ var Footer = function () { return React__default["default"].createElement(React__default["default"].Fragment, null); }; return { EmptyPlaceholder: EmptyPlaceholder, Footer: Footer, Header: Header, }; }, [loadingMore, head]); var atBottomStateChange = function (isAtBottom) { atBottom.current = isAtBottom; setIsMessageListScrolledToBottom(isAtBottom); if (isAtBottom && newMessagesNotification) { setNewMessagesNotification(false); } }; var startReached = function () { console.log('startReached hasMore: ', hasMore, !!loadMore); if (hasMore && loadMore) { loadMore(); } }; var endReached = function () { console.log('endReached hasMoreNewer: ', hasMoreNewer, !!loadMoreNewer); if (hasMoreNewer && loadMoreNewer) { loadMoreNewer(); } }; React.useEffect(function () { var _a; if (highlightedMessageId) { var index = findMessageIndex(processedMessages, highlightedMessageId); if (index !== -1) { (_a = virtuoso.current) === null || _a === void 0 ? void 0 : _a.scrollToIndex({ align: 'center', index: index }); } } }, [highlightedMessageId]); console.log("\n messages: ".concat(processedMessages.length, ",\n hasMore: ").concat(hasMore, ",\n hasMoreNewer: ").concat(hasMoreNewer, ",\n loadingMore: ").concat(loadingMore, ",\n loadingMoreNewer: ").concat(loadingMoreNewer, "\n ")); return (React__default["default"].createElement("div", { className: "uim-message-list" }, React__default["default"].createElement(index.Virtuoso, tslib.__assign({ atBottomStateChange: atBottomStateChange, atBottomThreshold: 200, className: 'uim__message-list-scroll', components: virtuosoComponents, computeItemKey: function (index) { return processedMessages[numItemsPrepended + index - PREPEND_OFFSET].id; }, endReached: endReached, firstItemIndex: PREPEND_OFFSET - numItemsPrepended, followOutput: followOutput, increaseViewportBy: { bottom: 200, top: 0 }, initialTopMostItemIndex: calculateInitialTopMostItemIndex(processedMessages, highlightedMessageId), itemContent: function (i) { return messageRenderer(processedMessages, i); }, itemSize: fractionalItemSize, key: messageSetKey, overscan: overscan, ref: virtuoso, startReached: startReached, style: { overflowX: 'hidden' }, totalCount: processedMessages.length }, additionalVirtuosoProps, (scrollSeekPlaceHolder ? { scrollSeek: scrollSeekPlaceHolder } : {}), (defaultItemHeight ? { defaultItemHeight: defaultItemHeight } : {}))), React__default["default"].createElement(MessageListNotifications$1, { hasNewMessages: newMessagesNotification, isMessageListScrolledToBottom: isMessageListScrolledToBottom, isNotAtLatestMessageSet: hasMoreNewer, MessageNotification: MessageNotification$1, scrollToBottom: scrollToBottom }))); }; var VirtualizedMessageList = function (props) { var propMessages = props.messages, propsIntervalsTimer = props.intervalsTimer, propHasMore = props.hasMore, propLoadMore = props.loadMore, propLoadingMore = props.loadingMore, propHasMoreNewer = props.hasMoreNewer; props.loadingMoreNewer; var propLoadMoreNewer = props.loadMoreNewer, rest = tslib.__rest(props, ["messages", "intervalsTimer", "hasMore", "loadMore", "loadingMore", "hasMoreNewer", "loadingMoreNewer", "loadMoreNewer"]); var _a = ChatActionContext.useChatActionContext('VirtualizedMessageList'), jumpToLatestMessage = _a.jumpToLatestMessage, contextLoadMore = _a.loadMore, contextLoadMoreNewer = _a.loadMoreNewer; var _b = ChatStateContext.useChatStateContext('VirtualizedMessageList'), conversation = _b.conversation, highlightedMessageId = _b.highlightedMessageId, suppressAutoscroll = _b.suppressAutoscroll, contextMessages = _b.messages, contextHasMore = _b.hasMore, contextLoadingMore = _b.loadingMore, contextHasMoreNewer = _b.hasMoreNewer, contextLoadingMoreNewer = _b.loadingMoreNewer; var hasMore = propHasMore !== null && propHasMore !== void 0 ? propHasMore : contextHasMore; var loadMore = propLoadMore !== null && propLoadMore !== void 0 ? propLoadMore : contextLoadMore; var loadingMore = propLoadingMore !== null && propLoadingMore !== void 0 ? propLoadingMore : contextLoadingMore; var hasMoreNewer = propHasMoreNewer !== null && propHasMoreNewer !== void 0 ? propHasMoreNewer : contextHasMoreNewer; var loadingMoreNewer = propHasMoreNewer !== null && propHasMoreNewer !== void 0 ? propHasMoreNewer : contextLoadingMoreNewer; var loadMoreNewer = propLoadMoreNewer !== null && propLoadMoreNewer !== void 0 ? propLoadMoreNewer : contextLoadMoreNewer; var intervalsTimer = (propsIntervalsTimer !== null && propsIntervalsTimer !== void 0 ? propsIntervalsTimer : 30) * 60; var messages = propMessages || contextMessages; return (React__default["default"].createElement(VirtualizedMessageListWithContext, tslib.__assign({ conversation: conversation, hasMore: !!hasMore, hasMoreNewer: !!hasMoreNewer, highlightedMessageId: highlightedMessageId, jumpToLatestMessage: jumpToLatestMessage, loadingMore: !!loadingMore, loadingMoreNewer: !!loadingMoreNewer, loadMore: loadMore, loadMoreNewer: loadMoreNewer, messages: messages, suppressAutoscroll: suppressAutoscroll, intervalsTimer: intervalsTimer }, rest))); }; exports.VirtualizedMessageList = VirtualizedMessageList; //# sourceMappingURL=VirtualizedMessageList.js.map