@sendbird/uikit-react
Version:
Sendbird UIKit for React: A feature-rich and customizable chat UI kit with messaging, channel management, and user authentication.
341 lines (338 loc) • 20.8 kB
JavaScript
import { a as __awaiter, c as __generator, e as __spreadArray } from '../../chunks/bundle-Bpofr334.js';
import React__default, { useRef, useState, useCallback, useEffect } from 'react';
import { u as useTypingLifecycle } from '../../chunks/bundle-AsQ1wnFm.js';
import { MutedState } from '@sendbird/chat/groupChannel';
import { u as useMediaQueryContext } from '../../chunks/bundle-C2ARCMSL.js';
import { u as useLocalization } from '../../chunks/bundle-Cdqsdoa8.js';
import { useGlobalModalContext } from '../../hooks/useModal.js';
import { c as checkIfFileUploadEnabled, M as MessageInput } from '../../chunks/bundle-BCjR1Qiq.js';
import { a as usePendingFiles, u as useDragAndDrop } from '../../chunks/bundle-ExNQo0Ly.js';
import { i as isChannelTypeSupportsMultipleFilesMessage } from '../../chunks/bundle-C5-D2BAP.js';
import { M as MessageInputKeys } from '../../chunks/bundle-BEPoP7sp.js';
import { S as SuggestedMentionList } from '../../chunks/bundle-DFWI31lg.js';
import { V as VoiceMessageInputWrapper } from '../../chunks/bundle-CwMNZmx9.js';
import '../../chunks/bundle-B56O1y8C.js';
import '../../chunks/bundle-CFc2hy8g.js';
import { u as useSendbird } from '../../chunks/bundle-4clodtJA.js';
import '../../chunks/bundle-BLMU9f-F.js';
import '../../chunks/bundle-lqEjT2ED.js';
import '@sendbird/chat/message';
import '../../chunks/bundle-YDriVB8K.js';
import { R as Role } from '../../chunks/bundle-DVdeXT-4.js';
import { useDirtyGetMentions } from '../../Message/hooks/useDirtyGetMentions.js';
import { b as isDisabledBecauseFrozen, c as isDisabledBecauseMuted } from '../../chunks/bundle-ChLik1Zs.js';
import { c as classnames } from '../../chunks/bundle-DX6fRIJl.js';
import { u as useThread } from '../../chunks/bundle-Gpc6ZS8v.js';
import { c as compressImages } from '../../chunks/bundle-BfgSx7DM.js';
import '../../chunks/bundle-oM0Fxt9G.js';
import '../../chunks/bundle-DmnXeBdU.js';
import '../../chunks/bundle-C4anRHWY.js';
import 'react-dom';
import '../../ui/IconButton.js';
import '../../ui/Button.js';
import '../../chunks/bundle-Cdplrrlw.js';
import '../../ui/Icon.js';
import '../../chunks/bundle-LLA95Pqf.js';
import '../../chunks/bundle-JhKiWlXT.js';
import '@sendbird/chat';
import '@sendbird/chat/openChannel';
import '../../chunks/bundle-BZSLsKkw.js';
import '../../utils/message/getOutgoingMessageState.js';
import '../../chunks/bundle-CglqREVl.js';
import '../../chunks/bundle-BqKoZDqX.js';
import '../../chunks/bundle-EKFQIahk.js';
import '../../chunks/bundle-B5xkbY4c.js';
import 'dompurify';
import '../../chunks/bundle-6I0gJidJ.js';
import '../../chunks/bundle-B40pTdZv.js';
import '../../chunks/bundle-iPLJ9a5J.js';
import '../../chunks/bundle-CnFrQOtC.js';
import '../../chunks/bundle-BJShQs4P.js';
import '../../ui/ImageRenderer.js';
import '../../chunks/bundle-F_R9C4cW.js';
import '../../chunks/bundle-DiO7lolz.js';
import '../../GroupChannel/components/SuggestedMentionList.js';
import '../../ui/QuoteMessageInput.js';
import '../../chunks/bundle-CD4RzjMA.js';
import '../../VoicePlayer/useVoicePlayer.js';
import '../../chunks/bundle-DWURNKdQ.js';
import '../../VoiceRecorder/context.js';
import '../../VoiceRecorder/useVoiceRecorder.js';
import '../../chunks/bundle-DzB_38co.js';
import '../../ui/PlaybackTime.js';
import '../../ui/ProgressBar.js';
import '../../ui/TextButton.js';
import '../../chunks/bundle-C1npFBfj.js';
import '@sendbird/uikit-tools';
import '../../chunks/bundle-B5LKcMN_.js';
import '../../chunks/bundle-CAshTR7h.js';
import '../../chunks/bundle-BRJdb8OX.js';
import '../../chunks/bundle-BdprN8pt.js';
import '../../chunks/bundle-BsY2Dawk.js';
import '../../chunks/bundle-XzHJwv9S.js';
import '../../chunks/bundle-DpOgiF9r.js';
import '../context/types.js';
var ThreadMessageInput = function (props, ref) {
var _a;
var className = props.className, renderFileUploadIcon = props.renderFileUploadIcon, renderVoiceMessageIcon = props.renderVoiceMessageIcon, renderSendMessageIcon = props.renderSendMessageIcon, acceptableMimeTypes = props.acceptableMimeTypes;
var config = useSendbird().state.config;
var isMobile = useMediaQueryContext().isMobile;
var stringSet = useLocalization().stringSet;
var isOnline = config.isOnline, userMention = config.userMention, logger = config.logger, groupChannel = config.groupChannel, imageCompression = config.imageCompression;
var threadContext = useThread();
var _b = threadContext.state, currentChannel = _b.currentChannel, parentMessage = _b.parentMessage, isMuted = _b.isMuted, isChannelFrozen = _b.isChannelFrozen, allThreadMessages = _b.allThreadMessages, _c = threadContext.actions, sendMessage = _c.sendMessage, sendFileMessage = _c.sendFileMessage, sendVoiceMessage = _c.sendVoiceMessage, sendMultipleFilesMessage = _c.sendMultipleFilesMessage;
var messageInputRef = useRef();
var isMentionEnabled = groupChannel.enableMention;
var isVoiceMessageEnabled = groupChannel.enableVoiceMessage;
var isMultipleFilesMessageEnabled = (_a = threadContext.state.isMultipleFilesMessageEnabled) !== null && _a !== void 0 ? _a : config.isMultipleFilesMessageEnabled;
var threadInputDisabled = props.disabled
|| !isOnline
|| isMuted
|| (!((currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.myRole) === Role.OPERATOR) && isChannelFrozen) || parentMessage === null;
// mention
var _d = useState(''), mentionNickname = _d[0], setMentionNickname = _d[1];
var _e = useState([]), mentionedUsers = _e[0], setMentionedUsers = _e[1];
var _f = useState([]), mentionedUserIds = _f[0], setMentionedUserIds = _f[1];
var _g = useState(null), selectedUser = _g[0], setSelectedUser = _g[1];
var _h = useState([]), mentionSuggestedUsers = _h[0], setMentionSuggestedUsers = _h[1];
var _j = useState(null), messageInputEvent = _j[0], setMessageInputEvent = _j[1];
var _k = useState(false), showVoiceMessageInput = _k[0], setShowVoiceMessageInput = _k[1];
// Composer staging
var openModal = useGlobalModalContext().openModal;
var uikitUploadSizeLimit = config.uikitUploadSizeLimit, uikitMultipleFilesMessageLimit = config.uikitMultipleFilesMessageLimit;
var allowMultipleFiles = Boolean(isMultipleFilesMessageEnabled)
&& Boolean(currentChannel)
&& isChannelTypeSupportsMultipleFilesMessage(currentChannel);
var effectiveMultiLimit = allowMultipleFiles ? uikitMultipleFilesMessageLimit : 1;
var _l = usePendingFiles({
uikitUploadSizeLimit: uikitUploadSizeLimit,
uikitMultipleFilesMessageLimit: effectiveMultiLimit,
acceptableMimeTypes: acceptableMimeTypes,
openModal: openModal,
stringSet: stringSet,
logger: logger,
}), pendingFiles = _l.pendingFiles, addFiles = _l.addFiles, removeFile = _l.removeFile, clearPendingFiles = _l.clear;
// Window-level drop target — only consume drops that land inside the
// thread panel (.sendbird-thread-ui). Drops elsewhere are picked up by the
// main channel composer's hook instance.
var isFileUploadEnabled = checkIfFileUploadEnabled({ channel: currentChannel !== null && currentChannel !== void 0 ? currentChannel : undefined, config: config });
useDragAndDrop({
onAddFiles: addFiles,
disabled: isMobile || threadInputDisabled || showVoiceMessageInput || !isFileUploadEnabled,
shouldAccept: function (event) {
var target = event.target;
if (!(target instanceof Element))
return false;
return Boolean(target.closest('.sendbird-thread-ui'));
},
});
var _m = useTypingLifecycle(currentChannel), startTyping = _m.startTyping, stopTyping = _m.stopTyping;
// Submit handler. Files and body text do not coexist: when files are
// present, the composer's text is suppressed at the UI level and again
// here. parentMessage is always the thread parent so each send threads
// correctly. The caption read path is preserved elsewhere for historical
// file messages that still carry a body.
var isSubmittingFilesRef = useRef(false);
var handleSubmit = useCallback(function (_a) { return __awaiter(void 0, [_a], void 0, function (_b) {
var trimmed, rawImageFiles, otherFiles, compressedImageFiles_1, tasks_1, useMFMBatch;
var message = _b.message, mentionTemplate = _b.mentionTemplate, files = _b.files;
return __generator(this, function (_c) {
switch (_c.label) {
case 0:
trimmed = message.trim();
if (files.length === 0) {
if (trimmed.length === 0)
return [2 /*return*/];
sendMessage({
message: message,
mentionedUsers: mentionedUsers,
mentionTemplate: mentionTemplate,
quoteMessage: parentMessage,
});
setMentionNickname('');
setMentionedUsers([]);
stopTyping();
return [2 /*return*/];
}
if (isSubmittingFilesRef.current)
return [2 /*return*/];
isSubmittingFilesRef.current = true;
setMentionNickname('');
setMentionedUsers([]);
stopTyping();
clearPendingFiles();
_c.label = 1;
case 1:
_c.trys.push([1, , 3, 4]);
rawImageFiles = files.filter(function (entry) { return entry.isImage; }).map(function (entry) { return entry.file; });
otherFiles = files.filter(function (entry) { return !entry.isImage; }).map(function (entry) { return entry.file; });
return [4 /*yield*/, compressImages({
files: rawImageFiles,
imageCompression: imageCompression,
logger: logger,
})];
case 2:
compressedImageFiles_1 = (_c.sent()).compressedFiles;
tasks_1 = [];
useMFMBatch = isMultipleFilesMessageEnabled && compressedImageFiles_1.length > 1;
if (useMFMBatch) {
tasks_1.push(function () { return sendMultipleFilesMessage(compressedImageFiles_1, parentMessage !== null && parentMessage !== void 0 ? parentMessage : undefined); });
}
else if (compressedImageFiles_1.length === 1) {
tasks_1.push(function () { return sendFileMessage(compressedImageFiles_1[0], parentMessage !== null && parentMessage !== void 0 ? parentMessage : undefined); });
}
else if (compressedImageFiles_1.length > 1) {
compressedImageFiles_1.forEach(function (file) {
tasks_1.push(function () { return sendFileMessage(file, parentMessage !== null && parentMessage !== void 0 ? parentMessage : undefined); });
});
}
otherFiles.forEach(function (file) {
tasks_1.push(function () { return sendFileMessage(file, parentMessage !== null && parentMessage !== void 0 ? parentMessage : undefined); });
});
// Sequential dispatch with per-task error isolation.
(function () { return __awaiter(void 0, void 0, void 0, function () {
var _i, tasks_2, task, error_1;
var _a;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_i = 0, tasks_2 = tasks_1;
_b.label = 1;
case 1:
if (!(_i < tasks_2.length)) return [3 /*break*/, 6];
task = tasks_2[_i];
_b.label = 2;
case 2:
_b.trys.push([2, 4, , 5]);
return [4 /*yield*/, task()];
case 3:
_b.sent();
return [3 /*break*/, 5];
case 4:
error_1 = _b.sent();
(_a = logger.warning) === null || _a === void 0 ? void 0 : _a.call(logger, 'Thread|composer: file send failed', error_1);
return [3 /*break*/, 5];
case 5:
_i++;
return [3 /*break*/, 1];
case 6: return [2 /*return*/];
}
});
}); })();
return [3 /*break*/, 4];
case 3:
isSubmittingFilesRef.current = false;
return [7 /*endfinally*/];
case 4: return [2 /*return*/];
}
});
}); }, [
sendMessage,
sendFileMessage,
sendMultipleFilesMessage,
mentionedUsers,
parentMessage,
currentChannel,
stopTyping,
clearPendingFiles,
isMultipleFilesMessageEnabled,
imageCompression,
logger,
]);
var displaySuggestedMentionList = isOnline
&& isMentionEnabled
&& mentionNickname.length > 0
&& !isDisabledBecauseFrozen(currentChannel)
&& !isDisabledBecauseMuted(currentChannel)
&& !(currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.isBroadcast);
var stashedMentionedUsersRef = useRef(null);
var prevHasPendingFilesRef = useRef(false);
var hasPendingFilesInWrapper = pendingFiles.length > 0;
useEffect(function () {
if (hasPendingFilesInWrapper && !prevHasPendingFilesRef.current) {
if (mentionedUsers.length > 0) {
stashedMentionedUsersRef.current = mentionedUsers;
}
setMentionNickname('');
}
else if (!hasPendingFilesInWrapper && prevHasPendingFilesRef.current) {
if (stashedMentionedUsersRef.current) {
setMentionedUsers(stashedMentionedUsersRef.current);
stashedMentionedUsersRef.current = null;
}
}
prevHasPendingFilesRef.current = hasPendingFilesInWrapper;
}, [hasPendingFilesInWrapper]);
// Reset when changing channel
useEffect(function () {
setShowVoiceMessageInput(false);
clearPendingFiles();
stashedMentionedUsersRef.current = null;
}, [currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.url]);
var mentionNodes = useDirtyGetMentions({ ref: ref || messageInputRef }, { logger: logger });
var ableMention = (mentionNodes === null || mentionNodes === void 0 ? void 0 : mentionNodes.length) < (userMention === null || userMention === void 0 ? void 0 : userMention.maxMentionCount);
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]);
if ((currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.isBroadcast) && (currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.myRole) !== Role.OPERATOR) {
return React__default.createElement(React__default.Fragment, null);
}
return (React__default.createElement("div", { className: classnames(showVoiceMessageInput ? 'sendbird-thread-message-input--voice-message' : 'sendbird-thread-message-input', className) },
displaySuggestedMentionList && (React__default.createElement(SuggestedMentionList, { 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: userMention === null || userMention === void 0 ? void 0 : userMention.maxMentionCount, maxSuggestionCount: userMention === null || userMention === void 0 ? void 0 : userMention.maxSuggestionCount })),
showVoiceMessageInput
? (React__default.createElement(VoiceMessageInputWrapper, { channel: currentChannel, onSubmitClick: function (recordedFile, duration) {
sendVoiceMessage(recordedFile, duration, parentMessage);
setShowVoiceMessageInput(false);
}, onCancelClick: function () {
setShowVoiceMessageInput(false);
} }))
: (React__default.createElement(MessageInput, { className: "sendbird-thread-message-input__message-input", messageFieldId: "sendbird-message-input-text-field--thread", channel: currentChannel, channelUrl: currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.url, isMobile: isMobile, disabled: threadInputDisabled, acceptableMimeTypes: acceptableMimeTypes, setMentionedUsers: setMentionedUsers, mentionSelectedUser: selectedUser, isMentionEnabled: isMentionEnabled, isVoiceMessageEnabled: isVoiceMessageEnabled, isSelectingMultipleFilesEnabled: isMultipleFilesMessageEnabled, onVoiceMessageIconClick: function () {
setShowVoiceMessageInput(true);
}, renderFileUploadIcon: renderFileUploadIcon, renderVoiceMessageIcon: renderVoiceMessageIcon, renderSendMessageIcon: renderSendMessageIcon, ref: ref || messageInputRef, placeholder: ((currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.isFrozen) && !((currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.myRole) === Role.OPERATOR) && stringSet.MESSAGE_INPUT__PLACE_HOLDER__DISABLED)
|| ((currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.myMutedState) === MutedState.MUTED && stringSet.MESSAGE_INPUT__PLACE_HOLDER__MUTED_SHORT)
|| (allThreadMessages.length > 0
? stringSet.THREAD__INPUT__REPLY_TO_THREAD
: stringSet.THREAD__INPUT__REPLY_IN_THREAD), onStartTyping: startTyping, onStopTyping: stopTyping, pendingFiles: pendingFiles, onAddFiles: addFiles, onRemoveFile: removeFile, onSubmit: handleSubmit, 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;
} }))));
};
var ThreadMessageInput$1 = React__default.forwardRef(ThreadMessageInput);
export { ThreadMessageInput$1 as default };
//# sourceMappingURL=ThreadMessageInput.js.map