@uimkit/uikit-react
Version:
<img style="width:64px" src="https://mgmt.uimkit.chat/media/img/avatar.png"/>
243 lines (236 loc) • 16.8 kB
JavaScript
;
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