@sendbird/uikit-react
Version:
Sendbird UIKit for React: A feature-rich and customizable chat UI kit with messaging, channel management, and user authentication.
268 lines (263 loc) • 18.2 kB
JavaScript
import { c as __spreadArray, _ as __assign } from './bundle-CzBQNSmE.js';
import React__default, { useState, useEffect, useRef, useCallback, useLayoutEffect, useMemo } from 'react';
import { f as format } from './bundle-Bq-Lo_oj.js';
import { u as useLocalization } from './bundle-BiqO1upP.js';
import { M as MAX_USER_MENTION_COUNT, b as MAX_USER_SUGGESTION_COUNT } from './bundle-DfThYlSD.js';
import { i as isDisabledBecauseFrozen, a as isDisabledBecauseMuted } from './bundle-fjYZUavu.js';
import { useDirtyGetMentions } from '../Message/hooks/useDirtyGetMentions.js';
import { g as getSuggestedReplies } from './bundle-BtrLIwe9.js';
import DateSeparator from '../ui/DateSeparator.js';
import { L as Label, a as LabelTypography, b as LabelColors } from './bundle-LBf6CphS.js';
import MessageInput from '../ui/MessageInput.js';
import { M as MessageInputKeys } from './bundle-Cu1scdm7.js';
import { MessageContent } from '../ui/MessageContent.js';
import SuggestedReplies from '../GroupChannel/components/SuggestedReplies.js';
import { S as SuggestedMentionListView } from './bundle-D2cr3zBl.js';
import { d as deleteNullish, c as classnames } from './bundle-DO80aKFO.js';
import { u as useSendbird } from './bundle-DMcf5OHL.js';
import { C as Colors, c as changeColorToClassName } from './bundle-CY7euRvz.js';
var useDidMountEffect = function (func, deps) {
var _a = useState(false), didMount = _a[0], setDidMount = _a[1];
useEffect(function () {
if (didMount) {
func();
}
else {
setDidMount(true);
}
}, deps);
};
var NewMessageIndicator = function (_a) {
var _b = _a.children, children = _b === void 0 ? undefined : _b, _c = _a.className, className = _c === void 0 ? '' : _c, onVisibilityChange = _a.onVisibilityChange, _d = _a.separatorColor, separatorColor = _d === void 0 ? Colors.PRIMARY : _d;
var separatorRef = useRef(null);
var handleVisibilityChange = useCallback(function (isVisible) {
onVisibilityChange === null || onVisibilityChange === void 0 ? void 0 : onVisibilityChange(isVisible);
}, [onVisibilityChange]);
useLayoutEffect(function () {
var element = separatorRef.current;
if (!element || !onVisibilityChange)
return;
var observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
var visible = entry.isIntersecting;
handleVisibilityChange(visible);
});
}, {
threshold: 1.0,
rootMargin: '0px',
root: null,
});
observer.observe(element);
return function () {
observer.disconnect();
};
}, [handleVisibilityChange, onVisibilityChange]);
return (React__default.createElement("div", { ref: separatorRef, className: __spreadArray(__spreadArray([], (Array.isArray(className) ? className : [className]), true), [
'sendbird-separator',
], false).join(' ') },
React__default.createElement("div", { className: ['sendbird-separator__left', "".concat(changeColorToClassName(separatorColor), "--background-color")].join(' ') }),
React__default.createElement("div", { className: "sendbird-separator__text" }, children
|| (React__default.createElement(Label, { type: LabelTypography.CAPTION_2, color: LabelColors.PRIMARY }, "New Messages"))),
React__default.createElement("div", { className: ['sendbird-separator__right', "".concat(changeColorToClassName(separatorColor), "--background-color")].join(' ') })));
};
// TODO: Refactor this component, is too complex now
var MessageView = function (props) {
var _a, _b;
var
// MessageProps
message = props.message, children = props.children, hasSeparator = props.hasSeparator, hasNewMessageSeparator = props.hasNewMessageSeparator, chainTop = props.chainTop, chainBottom = props.chainBottom, handleScroll = props.handleScroll, onNewMessageSeparatorVisibilityChange = props.onNewMessageSeparatorVisibilityChange,
// MessageViewProps
channel = props.channel, emojiContainer = props.emojiContainer, editInputDisabled = props.editInputDisabled, shouldRenderSuggestedReplies = props.shouldRenderSuggestedReplies, isReactionEnabled = props.isReactionEnabled, replyType = props.replyType, threadReplySelectType = props.threadReplySelectType, nicknamesMap = props.nicknamesMap, scrollToMessage = props.scrollToMessage, toggleReaction = props.toggleReaction, setQuoteMessage = props.setQuoteMessage, onQuoteMessageClick = props.onQuoteMessageClick, onReplyInThreadClick = props.onReplyInThreadClick, onBeforeDownloadFileMessage = props.onBeforeDownloadFileMessage, sendUserMessage = props.sendUserMessage, updateUserMessage = props.updateUserMessage, resendMessage = props.resendMessage, deleteMessage = props.deleteMessage, markAsUnread = props.markAsUnread, setAnimatedMessageId = props.setAnimatedMessageId, animatedMessageId = props.animatedMessageId, onMessageAnimated = props.onMessageAnimated, _c = props.usedInLegacy, usedInLegacy = _c === void 0 ? true : _c;
var _d = deleteNullish(props), renderUserMentionItem = _d.renderUserMentionItem, renderMessage = _d.renderMessage, _e = _d.renderMessageContent, renderMessageContent = _e === void 0 ? function (props) { return React__default.createElement(MessageContent, __assign({}, props)); } : _e, _f = _d.renderSuggestedReplies, renderSuggestedReplies = _f === void 0 ? function (props) { return React__default.createElement(SuggestedReplies, __assign({}, props)); } : _f, renderCustomSeparator = _d.renderCustomSeparator, renderEditInput = _d.renderEditInput, renderFileViewer = _d.renderFileViewer, renderRemoveMessageModal = _d.renderRemoveMessageModal, filterEmojiCategoryIds = _d.filterEmojiCategoryIds;
var _g = useLocalization(), dateLocale = _g.dateLocale, stringSet = _g.stringSet;
var state = useSendbird().state;
var _h = state.config, userId = _h.userId, isOnline = _h.isOnline, userMention = _h.userMention, logger = _h.logger, groupChannel = _h.groupChannel;
var maxUserMentionCount = (userMention === null || userMention === void 0 ? void 0 : userMention.maxMentionCount) || MAX_USER_MENTION_COUNT;
var maxUserSuggestionCount = (userMention === null || userMention === void 0 ? void 0 : userMention.maxSuggestionCount) || MAX_USER_SUGGESTION_COUNT;
var _j = useState(false), showEdit = _j[0], setShowEdit = _j[1];
var _k = useState(false), showRemove = _k[0], setShowRemove = _k[1];
var _l = useState(false), showFileViewer = _l[0], setShowFileViewer = _l[1];
var _m = useState(false), isAnimated = _m[0], setIsAnimated = _m[1];
var _o = useState(''), mentionNickname = _o[0], setMentionNickname = _o[1];
var _p = useState([]), mentionedUsers = _p[0], setMentionedUsers = _p[1];
var _q = useState([]), mentionedUserIds = _q[0], setMentionedUserIds = _q[1];
var _r = useState(null), messageInputEvent = _r[0], setMessageInputEvent = _r[1];
var _s = useState(null), selectedUser = _s[0], setSelectedUser = _s[1];
var _t = useState([]), mentionSuggestedUsers = _t[0], setMentionSuggestedUsers = _t[1];
var editMessageInputRef = useRef(null);
var messageScrollRef = useRef(null);
var displaySuggestedMentionList = isOnline
&& groupChannel.enableMention && mentionNickname.length > 0
&& !isDisabledBecauseFrozen(channel)
&& !isDisabledBecauseMuted(channel);
var mentionNodes = useDirtyGetMentions({ ref: editMessageInputRef }, { logger: logger });
var ableMention = (mentionNodes === null || mentionNodes === void 0 ? void 0 : mentionNodes.length) < maxUserMentionCount;
useEffect(function () {
setMentionedUsers(mentionedUsers.filter(function (_a) {
var userId = _a.userId;
var i = mentionedUserIds.indexOf(userId);
if (i < 0) {
return false;
}
else {
mentionedUserIds.splice(i, 1);
return true;
}
}));
}, [mentionedUserIds]);
// Side effect: scroll position update when showEdit is toggled or reactions updated
useDidMountEffect(function () {
handleScroll === null || handleScroll === void 0 ? void 0 : handleScroll();
}, [showEdit, (_a = message === null || message === void 0 ? void 0 : message.reactions) === null || _a === void 0 ? void 0 : _a.length]);
// Side effect: scroll position update when message updated
useDidMountEffect(function () {
handleScroll === null || handleScroll === void 0 ? void 0 : handleScroll(true);
}, [message === null || message === void 0 ? void 0 : message.updatedAt, message === null || message === void 0 ? void 0 : message.message]);
// Side effect: scroll position update when suggested replies are rendered or hidden
var prevShouldRenderSuggestedReplies = useRef(shouldRenderSuggestedReplies);
useEffect(function () {
if (prevShouldRenderSuggestedReplies.current !== shouldRenderSuggestedReplies) {
handleScroll === null || handleScroll === void 0 ? void 0 : handleScroll();
}
else {
prevShouldRenderSuggestedReplies.current = shouldRenderSuggestedReplies;
}
}, [shouldRenderSuggestedReplies]);
useLayoutEffect(function () {
// Keep the scrollBottom value after fetching new message list (but GroupChannel module is not needed.)
if (usedInLegacy)
handleScroll === null || handleScroll === void 0 ? void 0 : handleScroll(true);
}, []);
useLayoutEffect(function () {
var timeouts = [];
if (animatedMessageId === message.messageId && (messageScrollRef === null || messageScrollRef === void 0 ? void 0 : messageScrollRef.current)) {
timeouts.push(setTimeout(function () {
setIsAnimated(true);
}, 500));
timeouts.push(setTimeout(function () {
setAnimatedMessageId(null);
onMessageAnimated === null || onMessageAnimated === void 0 ? void 0 : onMessageAnimated();
}, 1600));
}
else {
setIsAnimated(false);
}
return function () {
timeouts.forEach(function (it) { return clearTimeout(it); });
};
}, [animatedMessageId, messageScrollRef.current, message.messageId]);
var renderedCustomSeparator = useMemo(function () { var _a; return (_a = renderCustomSeparator === null || renderCustomSeparator === void 0 ? void 0 : renderCustomSeparator({ message: message })) !== null && _a !== void 0 ? _a : null; }, [message, renderCustomSeparator]);
var renderChildren = function () {
if (children) {
return children;
}
if (renderMessage) {
var messageProps = __assign(__assign({}, props), { renderMessage: undefined });
return renderMessage(messageProps);
}
return (React__default.createElement(React__default.Fragment, null,
renderMessageContent({
className: 'sendbird-message-hoc__message-content',
userId: userId,
scrollToMessage: scrollToMessage,
channel: channel,
message: message,
disabled: !isOnline,
chainTop: chainTop,
chainBottom: chainBottom,
isReactionEnabled: isReactionEnabled,
replyType: replyType,
threadReplySelectType: threadReplySelectType,
nicknamesMap: nicknamesMap,
emojiContainer: emojiContainer,
showEdit: setShowEdit,
showRemove: setShowRemove,
showFileViewer: setShowFileViewer,
resendMessage: resendMessage,
deleteMessage: deleteMessage,
toggleReaction: toggleReaction,
setQuoteMessage: setQuoteMessage,
onReplyInThread: onReplyInThreadClick,
onQuoteMessageClick: onQuoteMessageClick,
onMessageHeightChange: handleScroll,
onBeforeDownloadFileMessage: onBeforeDownloadFileMessage,
filterEmojiCategoryIds: filterEmojiCategoryIds,
markAsUnread: markAsUnread,
}),
shouldRenderSuggestedReplies && renderSuggestedReplies({
replyOptions: getSuggestedReplies(message),
onSendMessage: sendUserMessage,
type: groupChannel === null || groupChannel === void 0 ? void 0 : groupChannel.suggestedRepliesDirection,
}),
showRemove && (renderRemoveMessageModal === null || renderRemoveMessageModal === void 0 ? void 0 : renderRemoveMessageModal({ message: message, onCancel: function () { return setShowRemove(false); } })),
showFileViewer && renderFileViewer({ message: message, onCancel: function () { return setShowFileViewer(false); } })));
};
if (showEdit && ((_b = message === null || message === void 0 ? void 0 : message.isUserMessage) === null || _b === void 0 ? void 0 : _b.call(message))) {
return ((renderEditInput === null || renderEditInput === void 0 ? void 0 : renderEditInput()) || (React__default.createElement(React__default.Fragment, null,
displaySuggestedMentionList && (React__default.createElement(SuggestedMentionListView, { currentChannel: channel, targetNickname: mentionNickname, inputEvent: messageInputEvent !== null && messageInputEvent !== void 0 ? messageInputEvent : undefined, renderUserMentionItem: renderUserMentionItem, onUserItemClick: function (user) {
if (user) {
setMentionedUsers(__spreadArray(__spreadArray([], mentionedUsers, true), [user], false));
}
setMentionNickname('');
setSelectedUser(user);
setMessageInputEvent(null);
}, onFocusItemChange: function () {
setMessageInputEvent(null);
}, onFetchUsers: function (users) {
setMentionSuggestedUsers(users);
}, ableAddMention: ableMention, maxMentionCount: maxUserMentionCount, maxSuggestionCount: maxUserSuggestionCount })),
React__default.createElement(MessageInput, { isEdit: true, channel: channel, disabled: editInputDisabled, ref: editMessageInputRef, mentionSelectedUser: selectedUser, isMentionEnabled: groupChannel.enableMention, message: message, onStartTyping: function () {
var _a;
(_a = channel === null || channel === void 0 ? void 0 : channel.startTyping) === null || _a === void 0 ? void 0 : _a.call(channel);
}, onUpdateMessage: function (_a) {
var _b;
var messageId = _a.messageId, message = _a.message, mentionTemplate = _a.mentionTemplate;
updateUserMessage(messageId, {
message: message,
mentionedUsers: mentionedUsers,
mentionedMessageTemplate: mentionTemplate,
});
setShowEdit(false);
(_b = channel === null || channel === void 0 ? void 0 : channel.endTyping) === null || _b === void 0 ? void 0 : _b.call(channel);
}, onCancelEdit: function () {
var _a;
setMentionNickname('');
setMentionedUsers([]);
setMentionedUserIds([]);
setMentionSuggestedUsers([]);
setShowEdit(false);
(_a = channel === null || channel === void 0 ? void 0 : channel.endTyping) === null || _a === void 0 ? void 0 : _a.call(channel);
}, onUserMentioned: function (user) {
if ((selectedUser === null || selectedUser === void 0 ? void 0 : selectedUser.userId) === (user === null || user === void 0 ? void 0 : user.userId)) {
setSelectedUser(null);
setMentionNickname('');
}
}, onMentionStringChange: function (mentionText) {
setMentionNickname(mentionText);
}, onMentionedUserIdsUpdated: function (userIds) {
setMentionedUserIds(userIds);
}, onKeyDown: function (e) {
if (displaySuggestedMentionList
&& (mentionSuggestedUsers === null || mentionSuggestedUsers === void 0 ? void 0 : mentionSuggestedUsers.length) > 0
&& ((e.key === MessageInputKeys.Enter && ableMention)
|| e.key === MessageInputKeys.ArrowUp
|| e.key === MessageInputKeys.ArrowDown)) {
setMessageInputEvent(e);
return true;
}
return false;
} }))));
}
return (React__default.createElement("div", { className: classnames('sendbird-msg-hoc sendbird-msg--scroll-ref', isAnimated && 'sendbird-msg-hoc__animated'), "data-testid": "sendbird-message-view", style: children || renderMessage ? undefined : { marginBottom: '2px' }, "data-sb-message-id": message.messageId, "data-sb-created-at": message.createdAt, ref: messageScrollRef },
hasSeparator
&& (renderedCustomSeparator || (React__default.createElement(DateSeparator, null,
React__default.createElement(Label, { type: LabelTypography.CAPTION_2, color: LabelColors.ONBACKGROUND_2 }, format(message.createdAt, stringSet.DATE_FORMAT__MESSAGE_LIST__DATE_SEPARATOR, {
locale: dateLocale,
}))))),
hasNewMessageSeparator
&& (React__default.createElement(NewMessageIndicator, { onVisibilityChange: onNewMessageSeparatorVisibilityChange },
React__default.createElement(Label, { type: LabelTypography.CAPTION_2, color: LabelColors.PRIMARY }, "New Messages"))),
renderChildren()));
};
export { MessageView as M };
//# sourceMappingURL=bundle-DD2MMoZ3.js.map