UNPKG

@sendbird/uikit-react

Version:

Sendbird UIKit for React: A feature-rich and customizable chat UI kit with messaging, channel management, and user authentication.

1,012 lines (930 loc) 637 kB
import { _ as __assign, a as __awaiter, b as __generator, c as __spreadArray } from './bundle-CzBQNSmE.js'; import React__default, { useCallback, useContext, useMemo, useEffect, useRef } from 'react'; import { s as scrollIntoLast, c as compareIds, u as useSendMultipleFilesMessage, g as getParentMessageFrom, a as getNicknamesMapFromMembers } from './bundle-Dpu4ZOmf.js'; import { U as UserProfileProvider } from './bundle-CS_zfDpT.js'; import { d as commonjsGlobal, s as shimExports, u as useStore, c as createStore } from './bundle-BRRgVYI5.js'; import { ChannelType } from '@sendbird/chat'; import { p as pubSubTopics, b as PublishingModuleType, a as shouldPubSubPublishToThread, P as PUBSUB_TOPICS } from './bundle-DAYo2mkS.js'; import { GroupChannelHandler } from '@sendbird/chat/groupChannel'; import { u as uuidv4 } from './bundle-CgQaz0Nj.js'; import { c as compareIds$1 } from './bundle-yd76uvgx.js'; import { ThreadListStateTypes, ParentMessageStateTypes, ChannelStateTypes } from '../Thread/context/types.js'; import { u as useSendbird } from './bundle-DMcf5OHL.js'; import { u as useDeepCompareEffect } from './bundle-CJemq6cX.js'; import { SendingStatus, MessageMetaArray, MessageType } from '@sendbird/chat/message'; import './bundle-BiqO1upP.js'; import { e as SCROLL_BOTTOM_DELAY_FOR_SEND, a as VOICE_MESSAGE_FILE_NAME, b as VOICE_MESSAGE_MIME_TYPE, i as META_ARRAY_VOICE_DURATION_KEY, j as META_ARRAY_MESSAGE_TYPE_KEY, k as META_ARRAY_MESSAGE_TYPE_VALUE__VOICE } from './bundle-DmYFHm_s.js'; var PREV_THREADS_FETCH_SIZE = 30; var NEXT_THREADS_FETCH_SIZE = 30; function useToggleReactionCallback(_a, _b) { var currentChannel = _a.currentChannel; var logger = _b.logger; return useCallback(function (message, key, isReacted) { var _a, _b; if (isReacted) { (_a = currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.deleteReaction) === null || _a === void 0 ? void 0 : _a.call(currentChannel, message, key).then(function (res) { logger.info('Thread | useToggleReactionsCallback: Delete reaction succeeded.', res); }).catch(function (err) { logger.warning('Thread | useToggleReactionsCallback: Delete reaction failed.', err); }); return; } (_b = currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.addReaction) === null || _b === void 0 ? void 0 : _b.call(currentChannel, message, key).then(function (res) { logger.info('Thread | useToggleReactionsCallback: Add reaction succeeded.', res); }).catch(function (err) { logger.warning('Thread | useToggleReactionsCallback: Add reaction failed.', err); }); }, [currentChannel]); } function useSendUserMessageCallback(_a, _b) { var isMentionEnabled = _a.isMentionEnabled, currentChannel = _a.currentChannel, onBeforeSendUserMessage = _a.onBeforeSendUserMessage, sendMessageStart = _a.sendMessageStart, sendMessageFailure = _a.sendMessageFailure; var logger = _b.logger, pubSub = _b.pubSub; var sendMessage = useCallback(function (props) { var _a; var message = props.message, quoteMessage = props.quoteMessage, mentionTemplate = props.mentionTemplate, mentionedUsers = props.mentionedUsers; var createDefaultParams = function () { var params = {}; params.message = message; var mentionedUsersLength = (mentionedUsers === null || mentionedUsers === void 0 ? void 0 : mentionedUsers.length) || 0; if (isMentionEnabled && mentionedUsersLength) { params.mentionedUsers = mentionedUsers; } if (isMentionEnabled && mentionTemplate && mentionedUsersLength) { params.mentionedMessageTemplate = mentionTemplate; } if (quoteMessage) { params.isReplyToChannel = true; params.parentMessageId = quoteMessage.messageId; } return params; }; var params = (_a = onBeforeSendUserMessage === null || onBeforeSendUserMessage === void 0 ? void 0 : onBeforeSendUserMessage(message, quoteMessage)) !== null && _a !== void 0 ? _a : createDefaultParams(); logger.info('Thread | useSendUserMessageCallback: Sending user message start.', params); if (currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.sendUserMessage) { currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.sendUserMessage(params).onPending(function (pendingMessage) { sendMessageStart(pendingMessage); }).onFailed(function (error, message) { logger.info('Thread | useSendUserMessageCallback: Sending user message failed.', { message: message, error: error }); sendMessageFailure(message); }).onSucceeded(function (message) { logger.info('Thread | useSendUserMessageCallback: Sending user message succeeded.', message); // because Thread doesn't subscribe SEND_USER_MESSAGE pubSub.publish(pubSubTopics.SEND_USER_MESSAGE, { channel: currentChannel, message: message, publishingModules: [PublishingModuleType.THREAD], }); }); } }, [ isMentionEnabled, currentChannel, onBeforeSendUserMessage, sendMessageStart, sendMessageFailure, ]); return sendMessage; } function useSendFileMessageCallback(_a, _b) { var currentChannel = _a.currentChannel, onBeforeSendFileMessage = _a.onBeforeSendFileMessage, sendMessageStart = _a.sendMessageStart, sendMessageFailure = _a.sendMessageFailure; var logger = _b.logger, pubSub = _b.pubSub; return useCallback(function (file, quoteMessage) { return new Promise(function (resolve, reject) { var _a; var createParamsDefault = function () { var params = {}; params.file = file; if (quoteMessage) { params.isReplyToChannel = true; params.parentMessageId = quoteMessage.messageId; } return params; }; var params = (_a = onBeforeSendFileMessage === null || onBeforeSendFileMessage === void 0 ? void 0 : onBeforeSendFileMessage(file, quoteMessage)) !== null && _a !== void 0 ? _a : createParamsDefault(); logger.info('Thread | useSendFileMessageCallback: Sending file message start.', params); if (currentChannel == null) { logger.warning('Thread | useSendFileMessageCallback: currentChannel is null. Skipping file message send.'); resolve(null); } else { currentChannel.sendFileMessage(params) .onPending(function (pendingMessage) { // @ts-ignore sendMessageStart(__assign(__assign({}, pendingMessage), { url: URL.createObjectURL(file), // pending thumbnail message seems to be failed sendingStatus: SendingStatus.PENDING, isUserMessage: pendingMessage.isUserMessage, isFileMessage: pendingMessage.isFileMessage, isAdminMessage: pendingMessage.isAdminMessage, isMultipleFilesMessage: pendingMessage.isMultipleFilesMessage })); setTimeout(function () { return scrollIntoLast(); }, SCROLL_BOTTOM_DELAY_FOR_SEND); }) .onFailed(function (error, message) { message.localUrl = URL.createObjectURL(file); message.file = file; logger.info('Thread | useSendFileMessageCallback: Sending file message failed.', { message: message, error: error }); sendMessageFailure(message); reject(error); }) .onSucceeded(function (message) { logger.info('Thread | useSendFileMessageCallback: Sending file message succeeded.', message); pubSub.publish(pubSubTopics.SEND_FILE_MESSAGE, { channel: currentChannel, message: message, publishingModules: [PublishingModuleType.THREAD], }); resolve(message); }); } }); }, [ currentChannel, onBeforeSendFileMessage, sendMessageStart, sendMessageFailure, ]); } var useSendVoiceMessageCallback = function (_a, _b) { var currentChannel = _a.currentChannel, onBeforeSendVoiceMessage = _a.onBeforeSendVoiceMessage, sendMessageStart = _a.sendMessageStart, sendMessageFailure = _a.sendMessageFailure; var logger = _b.logger, pubSub = _b.pubSub; var sendMessage = useCallback(function (file, duration, quoteMessage) { var messageParams = (onBeforeSendVoiceMessage && typeof onBeforeSendVoiceMessage === 'function') ? onBeforeSendVoiceMessage(file, quoteMessage) : { file: file, fileName: VOICE_MESSAGE_FILE_NAME, mimeType: VOICE_MESSAGE_MIME_TYPE, metaArrays: [ new MessageMetaArray({ key: META_ARRAY_VOICE_DURATION_KEY, value: ["".concat(duration)], }), new MessageMetaArray({ key: META_ARRAY_MESSAGE_TYPE_KEY, value: [META_ARRAY_MESSAGE_TYPE_VALUE__VOICE], }), ], }; if (quoteMessage) { messageParams.isReplyToChannel = true; messageParams.parentMessageId = quoteMessage.messageId; } logger.info('Thread | useSendVoiceMessageCallback: Start sending voice message', messageParams); currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.sendFileMessage(messageParams).onPending(function (pendingMessage) { // @ts-ignore sendMessageStart(__assign(__assign({}, pendingMessage), { url: URL.createObjectURL(file), // pending thumbnail message seems to be failed sendingStatus: SendingStatus.PENDING, isUserMessage: pendingMessage.isUserMessage, isFileMessage: pendingMessage.isFileMessage, isAdminMessage: pendingMessage.isAdminMessage, isMultipleFilesMessage: pendingMessage.isMultipleFilesMessage })); setTimeout(function () { return scrollIntoLast(); }, SCROLL_BOTTOM_DELAY_FOR_SEND); }).onFailed(function (error, message) { message.localUrl = URL.createObjectURL(file); message.file = file; logger.info('Thread | useSendVoiceMessageCallback: Sending voice message failed.', { message: message, error: error }); sendMessageFailure(message); }).onSucceeded(function (message) { logger.info('Thread | useSendVoiceMessageCallback: Sending voice message succeeded.', message); pubSub.publish(pubSubTopics.SEND_FILE_MESSAGE, { channel: currentChannel, message: message, publishingModules: [PublishingModuleType.THREAD], }); }); }, [ currentChannel, onBeforeSendVoiceMessage, sendMessageStart, sendMessageFailure, ]); return sendMessage; }; function useResendMessageCallback(_a, _b) { var currentChannel = _a.currentChannel, resendMessageStart = _a.resendMessageStart, sendMessageSuccess = _a.sendMessageSuccess, sendMessageFailure = _a.sendMessageFailure; var logger = _b.logger, pubSub = _b.pubSub; return useCallback(function (failedMessage) { var _a, _b, _c, _d, _e; if (!(failedMessage === null || failedMessage === void 0 ? void 0 : failedMessage.isResendable)) { logger.warning('Thread | useResendMessageCallback: Message is not resendable.', failedMessage); return; } logger.info('Thread | useResendMessageCallback: Resending failedMessage start.', failedMessage); if (((_a = failedMessage === null || failedMessage === void 0 ? void 0 : failedMessage.isUserMessage) === null || _a === void 0 ? void 0 : _a.call(failedMessage)) || (failedMessage === null || failedMessage === void 0 ? void 0 : failedMessage.messageType) === MessageType.USER) { try { currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.resendMessage(failedMessage).onPending(function (message) { logger.info('Thread | useResendMessageCallback: Resending user message started.', message); resendMessageStart(message); }).onSucceeded(function (message) { logger.info('Thread | useResendMessageCallback: Resending user message succeeded.', message); sendMessageSuccess(message); pubSub.publish(pubSubTopics.SEND_USER_MESSAGE, { channel: currentChannel, message: message, publishingModules: [PublishingModuleType.THREAD], }); }).onFailed(function (error) { logger.warning('Thread | useResendMessageCallback: Resending user message failed.', error); failedMessage.sendingStatus = SendingStatus.FAILED; sendMessageFailure(failedMessage); }); } catch (err) { logger.warning('Thread | useResendMessageCallback: Resending user message failed.', err); failedMessage.sendingStatus = SendingStatus.FAILED; sendMessageFailure(failedMessage); } } else if ((_b = failedMessage === null || failedMessage === void 0 ? void 0 : failedMessage.isFileMessage) === null || _b === void 0 ? void 0 : _b.call(failedMessage)) { try { (_c = currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.resendMessage) === null || _c === void 0 ? void 0 : _c.call(currentChannel, failedMessage).onPending(function (message) { logger.info('Thread | useResendMessageCallback: Resending file message started.', message); resendMessageStart(message); }).onSucceeded(function (message) { logger.info('Thread | useResendMessageCallback: Resending file message succeeded.', message); sendMessageSuccess(message); pubSub.publish(pubSubTopics.SEND_FILE_MESSAGE, { channel: currentChannel, message: failedMessage, publishingModules: [PublishingModuleType.THREAD], }); }).onFailed(function (error) { logger.warning('Thread | useResendMessageCallback: Resending file message failed.', error); failedMessage.sendingStatus = SendingStatus.FAILED; sendMessageFailure(failedMessage); }); } catch (err) { logger.warning('Thread | useResendMessageCallback: Resending file message failed.', err); failedMessage.sendingStatus = SendingStatus.FAILED; sendMessageFailure(failedMessage); } } else if ((_d = failedMessage === null || failedMessage === void 0 ? void 0 : failedMessage.isMultipleFilesMessage) === null || _d === void 0 ? void 0 : _d.call(failedMessage)) { try { (_e = currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.resendMessage) === null || _e === void 0 ? void 0 : _e.call(currentChannel, failedMessage).onPending(function (message) { logger.info('Thread | useResendMessageCallback: Resending multiple files message started.', message); resendMessageStart(message); }).onFileUploaded(function (requestId, index, uploadableFileInfo, error) { logger.info('Thread | useResendMessageCallback: onFileUploaded during resending multiple files message.', { requestId: requestId, index: index, error: error, uploadableFileInfo: uploadableFileInfo, }); pubSub.publish(pubSubTopics.ON_FILE_INFO_UPLOADED, { response: { channelUrl: currentChannel.url, requestId: requestId, index: index, uploadableFileInfo: uploadableFileInfo, error: error, }, publishingModules: [PublishingModuleType.THREAD], }); }).onSucceeded(function (message) { logger.info('Thread | useResendMessageCallback: Resending MFM succeeded.', message); sendMessageSuccess(message); pubSub.publish(pubSubTopics.SEND_FILE_MESSAGE, { channel: currentChannel, message: message, publishingModules: [PublishingModuleType.THREAD], }); }).onFailed(function (error, message) { logger.warning('Thread | useResendMessageCallback: Resending MFM failed.', error); sendMessageFailure(message); }); } catch (err) { logger.warning('Thread | useResendMessageCallback: Resending MFM failed.', err); sendMessageFailure(failedMessage); } } else { logger.warning('Thread | useResendMessageCallback: Message is not resendable.', failedMessage); failedMessage.sendingStatus = SendingStatus.FAILED; sendMessageFailure(failedMessage); } }, [ currentChannel, resendMessageStart, sendMessageSuccess, sendMessageFailure, ]); } function useUpdateMessageCallback(_a, _b) { var currentChannel = _a.currentChannel, isMentionEnabled = _a.isMentionEnabled, onMessageUpdated = _a.onMessageUpdated; var logger = _b.logger, pubSub = _b.pubSub; // TODO: add type return useCallback(function (props) { var _a; var messageId = props.messageId, message = props.message, mentionedUsers = props.mentionedUsers, mentionTemplate = props.mentionTemplate; var createParamsDefault = function () { var params = {}; params.message = message; if (isMentionEnabled && mentionedUsers && (mentionedUsers === null || mentionedUsers === void 0 ? void 0 : mentionedUsers.length) > 0) { params.mentionedUsers = mentionedUsers; } if (isMentionEnabled && mentionTemplate) { params.mentionedMessageTemplate = mentionTemplate; } else { params.mentionedMessageTemplate = message; } return params; }; var params = createParamsDefault(); logger.info('Thread | useUpdateMessageCallback: Message update start.', params); if (currentChannel == null) { logger.warning('Thread | useUpdateMessageCallback: currentChannel is null.'); return; } (_a = currentChannel.updateUserMessage) === null || _a === void 0 ? void 0 : _a.call(currentChannel, messageId, params).then(function (message) { logger.info('Thread | useUpdateMessageCallback: Message update succeeded.', message); onMessageUpdated(currentChannel, message); pubSub.publish(pubSubTopics.UPDATE_USER_MESSAGE, { fromSelector: true, channel: currentChannel, message: message, publishingModules: [PublishingModuleType.THREAD], }); }); }, [ currentChannel, isMentionEnabled, onMessageUpdated, ]); } function useDeleteMessageCallback(_a, _b) { var currentChannel = _a.currentChannel, onMessageDeletedByReqId = _a.onMessageDeletedByReqId, onMessageDeleted = _a.onMessageDeleted; var logger = _b.logger; return useCallback(function (message) { logger.info('Thread | useDeleteMessageCallback: Deleting message.', message); var sendingStatus = message.sendingStatus; return new Promise(function (resolve, reject) { var _a; logger.info('Thread | useDeleteMessageCallback: Deleting message requestState:', sendingStatus); // Message is only on local if (sendingStatus === 'failed' || sendingStatus === 'pending') { logger.info('Thread | useDeleteMessageCallback: Deleted message from local:', message); onMessageDeletedByReqId(message.reqId); resolve(); } if (currentChannel == null) { logger.info('Thread | useDeleteMessageCallback: No current channel'); resolve(); } logger.info('Thread | useDeleteMessageCallback: Deleting message from remote:', sendingStatus); (_a = currentChannel.deleteMessage) === null || _a === void 0 ? void 0 : _a.call(currentChannel, message).then(function () { logger.info('Thread | useDeleteMessageCallback: Deleting message success!', message); onMessageDeleted(currentChannel, message.messageId); resolve(); }).catch(function (err) { logger.warning('Thread | useDeleteMessageCallback: Deleting message failed!', err); reject(err); }); }); }, [ currentChannel, onMessageDeletedByReqId, onMessageDeleted, ]); } function getThreadMessageListParams(params) { return __assign({ prevResultSize: PREV_THREADS_FETCH_SIZE, nextResultSize: NEXT_THREADS_FETCH_SIZE, includeMetaArray: true, isInclusive: true }, params); } var useThreadFetchers = function (_a) { var isReactionEnabled = _a.isReactionEnabled, anchorMessage = _a.anchorMessage, staleParentMessage = _a.parentMessage, logger = _a.logger, oldestMessageTimeStamp = _a.oldestMessageTimeStamp, latestMessageTimeStamp = _a.latestMessageTimeStamp, threadListState = _a.threadListState, initializeThreadListStart = _a.initializeThreadListStart, initializeThreadListSuccess = _a.initializeThreadListSuccess, initializeThreadListFailure = _a.initializeThreadListFailure, getPrevMessagesStart = _a.getPrevMessagesStart, getPrevMessagesSuccess = _a.getPrevMessagesSuccess, getPrevMessagesFailure = _a.getPrevMessagesFailure, getNextMessagesStart = _a.getNextMessagesStart, getNextMessagesSuccess = _a.getNextMessagesSuccess, getNextMessagesFailure = _a.getNextMessagesFailure; var stores = useSendbird().state.stores; var timestamp = (anchorMessage === null || anchorMessage === void 0 ? void 0 : anchorMessage.createdAt) || 0; var initialize = useCallback(function (callback) { return __awaiter(void 0, void 0, void 0, function () { var params, _a, threadedMessages_1, parentMessage, error_1; return __generator(this, function (_b) { switch (_b.label) { case 0: if (!stores.sdkStore.initialized || !staleParentMessage) return [2 /*return*/]; initializeThreadListStart(); _b.label = 1; case 1: _b.trys.push([1, 3, , 4]); params = getThreadMessageListParams({ includeReactions: isReactionEnabled }); logger.info('Thread | useGetThreadList: Initialize thread list start.', { timestamp: timestamp, params: params }); return [4 /*yield*/, staleParentMessage.getThreadedMessagesByTimestamp(timestamp, params)]; case 2: _a = _b.sent(), threadedMessages_1 = _a.threadedMessages, parentMessage = _a.parentMessage; logger.info('Thread | useGetThreadList: Initialize thread list succeeded.', { staleParentMessage: staleParentMessage, threadedMessages: threadedMessages_1 }); initializeThreadListSuccess(parentMessage, anchorMessage, threadedMessages_1); setTimeout(function () { return callback === null || callback === void 0 ? void 0 : callback(threadedMessages_1); }); return [3 /*break*/, 4]; case 3: error_1 = _b.sent(); logger.info('Thread | useGetThreadList: Initialize thread list failed.', error_1); initializeThreadListFailure(); return [3 /*break*/, 4]; case 4: return [2 /*return*/]; } }); }); }, [ stores.sdkStore.initialized, staleParentMessage, anchorMessage, isReactionEnabled, initializeThreadListStart, initializeThreadListSuccess, initializeThreadListFailure, ]); var loadPrevious = useCallback(function (callback) { return __awaiter(void 0, void 0, void 0, function () { var params, _a, threadedMessages_2, parentMessage, error_2; return __generator(this, function (_b) { switch (_b.label) { case 0: if (threadListState !== ThreadListStateTypes.INITIALIZED || oldestMessageTimeStamp === 0 || !staleParentMessage) return [2 /*return*/]; getPrevMessagesStart(); _b.label = 1; case 1: _b.trys.push([1, 3, , 4]); params = getThreadMessageListParams({ nextResultSize: 0, includeReactions: isReactionEnabled }); return [4 /*yield*/, staleParentMessage.getThreadedMessagesByTimestamp(oldestMessageTimeStamp, params)]; case 2: _a = _b.sent(), threadedMessages_2 = _a.threadedMessages, parentMessage = _a.parentMessage; logger.info('Thread | useGetPrevThreadsCallback: Fetch prev threads succeeded.', { parentMessage: parentMessage, threadedMessages: threadedMessages_2 }); getPrevMessagesSuccess(threadedMessages_2); setTimeout(function () { return callback === null || callback === void 0 ? void 0 : callback(threadedMessages_2); }); return [3 /*break*/, 4]; case 3: error_2 = _b.sent(); logger.info('Thread | useGetPrevThreadsCallback: Fetch prev threads failed.', error_2); getPrevMessagesFailure(); return [3 /*break*/, 4]; case 4: return [2 /*return*/]; } }); }); }, [ threadListState, oldestMessageTimeStamp, isReactionEnabled, staleParentMessage, getPrevMessagesStart, getPrevMessagesSuccess, getPrevMessagesFailure, ]); var loadNext = useCallback(function (callback) { return __awaiter(void 0, void 0, void 0, function () { var params, _a, threadedMessages_3, parentMessage, error_3; return __generator(this, function (_b) { switch (_b.label) { case 0: if (threadListState !== ThreadListStateTypes.INITIALIZED || latestMessageTimeStamp === 0 || !staleParentMessage) return [2 /*return*/]; getNextMessagesStart(); _b.label = 1; case 1: _b.trys.push([1, 3, , 4]); params = getThreadMessageListParams({ prevResultSize: 0, includeReactions: isReactionEnabled }); return [4 /*yield*/, staleParentMessage.getThreadedMessagesByTimestamp(latestMessageTimeStamp, params)]; case 2: _a = _b.sent(), threadedMessages_3 = _a.threadedMessages, parentMessage = _a.parentMessage; logger.info('Thread | useGetNextThreadsCallback: Fetch next threads succeeded.', { parentMessage: parentMessage, threadedMessages: threadedMessages_3 }); getNextMessagesSuccess(threadedMessages_3); setTimeout(function () { return callback === null || callback === void 0 ? void 0 : callback(threadedMessages_3); }); return [3 /*break*/, 4]; case 3: error_3 = _b.sent(); logger.info('Thread | useGetNextThreadsCallback: Fetch next threads failed.', error_3); getNextMessagesFailure(); return [3 /*break*/, 4]; case 4: return [2 /*return*/]; } }); }); }, [ threadListState, latestMessageTimeStamp, isReactionEnabled, staleParentMessage, getNextMessagesStart, getNextMessagesSuccess, getNextMessagesFailure, ]); return { initializeThreadFetcher: initialize, fetchPrevThreads: loadPrevious, fetchNextThreads: loadNext, }; }; var lodash = {exports: {}}; /** * @license * Lodash <https://lodash.com/> * Copyright OpenJS Foundation and other contributors <https://openjsf.org/> * Released under MIT license <https://lodash.com/license> * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors */ lodash.exports; (function (module, exports) { (function() { /** Used as a safe reference for `undefined` in pre-ES5 environments. */ var undefined$1; /** Used as the semantic version number. */ var VERSION = '4.17.21'; /** Used as the size to enable large array optimizations. */ var LARGE_ARRAY_SIZE = 200; /** Error message constants. */ var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.', FUNC_ERROR_TEXT = 'Expected a function', INVALID_TEMPL_VAR_ERROR_TEXT = 'Invalid `variable` option passed into `_.template`'; /** Used to stand-in for `undefined` hash values. */ var HASH_UNDEFINED = '__lodash_hash_undefined__'; /** Used as the maximum memoize cache size. */ var MAX_MEMOIZE_SIZE = 500; /** Used as the internal argument placeholder. */ var PLACEHOLDER = '__lodash_placeholder__'; /** Used to compose bitmasks for cloning. */ var CLONE_DEEP_FLAG = 1, CLONE_FLAT_FLAG = 2, CLONE_SYMBOLS_FLAG = 4; /** Used to compose bitmasks for value comparisons. */ var COMPARE_PARTIAL_FLAG = 1, COMPARE_UNORDERED_FLAG = 2; /** Used to compose bitmasks for function metadata. */ var WRAP_BIND_FLAG = 1, WRAP_BIND_KEY_FLAG = 2, WRAP_CURRY_BOUND_FLAG = 4, WRAP_CURRY_FLAG = 8, WRAP_CURRY_RIGHT_FLAG = 16, WRAP_PARTIAL_FLAG = 32, WRAP_PARTIAL_RIGHT_FLAG = 64, WRAP_ARY_FLAG = 128, WRAP_REARG_FLAG = 256, WRAP_FLIP_FLAG = 512; /** Used as default options for `_.truncate`. */ var DEFAULT_TRUNC_LENGTH = 30, DEFAULT_TRUNC_OMISSION = '...'; /** Used to detect hot functions by number of calls within a span of milliseconds. */ var HOT_COUNT = 800, HOT_SPAN = 16; /** Used to indicate the type of lazy iteratees. */ var LAZY_FILTER_FLAG = 1, LAZY_MAP_FLAG = 2, LAZY_WHILE_FLAG = 3; /** Used as references for various `Number` constants. */ var INFINITY = 1 / 0, MAX_SAFE_INTEGER = 9007199254740991, MAX_INTEGER = 1.7976931348623157e+308, NAN = 0 / 0; /** Used as references for the maximum length and index of an array. */ var MAX_ARRAY_LENGTH = 4294967295, MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1, HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1; /** Used to associate wrap methods with their bit flags. */ var wrapFlags = [ ['ary', WRAP_ARY_FLAG], ['bind', WRAP_BIND_FLAG], ['bindKey', WRAP_BIND_KEY_FLAG], ['curry', WRAP_CURRY_FLAG], ['curryRight', WRAP_CURRY_RIGHT_FLAG], ['flip', WRAP_FLIP_FLAG], ['partial', WRAP_PARTIAL_FLAG], ['partialRight', WRAP_PARTIAL_RIGHT_FLAG], ['rearg', WRAP_REARG_FLAG] ]; /** `Object#toString` result references. */ var argsTag = '[object Arguments]', arrayTag = '[object Array]', asyncTag = '[object AsyncFunction]', boolTag = '[object Boolean]', dateTag = '[object Date]', domExcTag = '[object DOMException]', errorTag = '[object Error]', funcTag = '[object Function]', genTag = '[object GeneratorFunction]', mapTag = '[object Map]', numberTag = '[object Number]', nullTag = '[object Null]', objectTag = '[object Object]', promiseTag = '[object Promise]', proxyTag = '[object Proxy]', regexpTag = '[object RegExp]', setTag = '[object Set]', stringTag = '[object String]', symbolTag = '[object Symbol]', undefinedTag = '[object Undefined]', weakMapTag = '[object WeakMap]', weakSetTag = '[object WeakSet]'; var arrayBufferTag = '[object ArrayBuffer]', dataViewTag = '[object DataView]', float32Tag = '[object Float32Array]', float64Tag = '[object Float64Array]', int8Tag = '[object Int8Array]', int16Tag = '[object Int16Array]', int32Tag = '[object Int32Array]', uint8Tag = '[object Uint8Array]', uint8ClampedTag = '[object Uint8ClampedArray]', uint16Tag = '[object Uint16Array]', uint32Tag = '[object Uint32Array]'; /** Used to match empty string literals in compiled template source. */ var reEmptyStringLeading = /\b__p \+= '';/g, reEmptyStringMiddle = /\b(__p \+=) '' \+/g, reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; /** Used to match HTML entities and HTML characters. */ var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g, reUnescapedHtml = /[&<>"']/g, reHasEscapedHtml = RegExp(reEscapedHtml.source), reHasUnescapedHtml = RegExp(reUnescapedHtml.source); /** Used to match template delimiters. */ var reEscape = /<%-([\s\S]+?)%>/g, reEvaluate = /<%([\s\S]+?)%>/g, reInterpolate = /<%=([\s\S]+?)%>/g; /** Used to match property names within property paths. */ var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, reIsPlainProp = /^\w*$/, rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; /** * Used to match `RegExp` * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). */ var reRegExpChar = /[\\^$.*+?()[\]{}|]/g, reHasRegExpChar = RegExp(reRegExpChar.source); /** Used to match leading whitespace. */ var reTrimStart = /^\s+/; /** Used to match a single whitespace character. */ var reWhitespace = /\s/; /** Used to match wrap detail comments. */ var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/, reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/, reSplitDetails = /,? & /; /** Used to match words composed of alphanumeric characters. */ var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g; /** * Used to validate the `validate` option in `_.template` variable. * * Forbids characters which could potentially change the meaning of the function argument definition: * - "()," (modification of function parameters) * - "=" (default value) * - "[]{}" (destructuring of function parameters) * - "/" (beginning of a comment) * - whitespace */ var reForbiddenIdentifierChars = /[()=,{}\[\]\/\s]/; /** Used to match backslashes in property paths. */ var reEscapeChar = /\\(\\)?/g; /** * Used to match * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components). */ var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; /** Used to match `RegExp` flags from their coerced string values. */ var reFlags = /\w*$/; /** Used to detect bad signed hexadecimal string values. */ var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; /** Used to detect binary string values. */ var reIsBinary = /^0b[01]+$/i; /** Used to detect host constructors (Safari). */ var reIsHostCtor = /^\[object .+?Constructor\]$/; /** Used to detect octal string values. */ var reIsOctal = /^0o[0-7]+$/i; /** Used to detect unsigned integer values. */ var reIsUint = /^(?:0|[1-9]\d*)$/; /** Used to match Latin Unicode letters (excluding mathematical operators). */ var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g; /** Used to ensure capturing order of template delimiters. */ var reNoMatch = /($^)/; /** Used to match unescaped characters in compiled string literals. */ var reUnescapedString = /['\n\r\u2028\u2029\\]/g; /** Used to compose unicode character classes. */ var rsAstralRange = '\\ud800-\\udfff', rsComboMarksRange = '\\u0300-\\u036f', reComboHalfMarksRange = '\\ufe20-\\ufe2f', rsComboSymbolsRange = '\\u20d0-\\u20ff', rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange, rsDingbatRange = '\\u2700-\\u27bf', rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff', rsMathOpRange = '\\xac\\xb1\\xd7\\xf7', rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf', rsPunctuationRange = '\\u2000-\\u206f', rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000', rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde', rsVarRange = '\\ufe0e\\ufe0f', rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange; /** Used to compose unicode capture groups. */ var rsApos = "['\u2019]", rsAstral = '[' + rsAstralRange + ']', rsBreak = '[' + rsBreakRange + ']', rsCombo = '[' + rsComboRange + ']', rsDigits = '\\d+', rsDingbat = '[' + rsDingbatRange + ']', rsLower = '[' + rsLowerRange + ']', rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']', rsFitz = '\\ud83c[\\udffb-\\udfff]', rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', rsNonAstral = '[^' + rsAstralRange + ']', rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', rsUpper = '[' + rsUpperRange + ']', rsZWJ = '\\u200d'; /** Used to compose unicode regexes. */ var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')', rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')', rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?', rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?', reOptMod = rsModifier + '?', rsOptVar = '[' + rsVarRange + ']?', rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', rsOrdLower = '\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])', rsOrdUpper = '\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])', rsSeq = rsOptVar + reOptMod + rsOptJoin, rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq, rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; /** Used to match apostrophes. */ var reApos = RegExp(rsApos, 'g'); /** * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols). */ var reComboMark = RegExp(rsCombo, 'g'); /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); /** Used to match complex or compound words. */ var reUnicodeWord = RegExp([ rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')', rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')', rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower, rsUpper + '+' + rsOptContrUpper, rsOrdUpper, rsOrdLower, rsDigits, rsEmoji ].join('|'), 'g'); /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */ var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']'); /** Used to detect strings that need a more robust regexp to match words. */ var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/; /** Used to assign default `context` object properties. */ var contextProps = [ 'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array', 'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object', 'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array', 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap', '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout' ]; /** Used to make template sourceURLs easier to identify. */ var templateCounter = -1; /** Used to identify `toStringTag` values of typed arrays. */ var typedArrayTags = {}; typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = typedArrayTags[uint32Tag] = true; typedArrayTags[argsTag] = typedArrayTags[arrayTag] = typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = typedArrayTags[errorTag] = typedArrayTags[funcTag] = typedArrayTags[mapTag] = typedArrayTags[numberTag] = typedArrayTags[objectTag] = typedArrayTags[regexpTag] = typedArrayTags[setTag] = typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; /** Used to identify `toStringTag` values supported by `_.clone`. */ var cloneableTags = {}; cloneableTags[argsTag] = cloneableTags[arrayTag] = cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = cloneableTags[boolTag] = cloneableTags[dateTag] = cloneableTags[float32Tag] = cloneableTags[float64Tag] = cloneableTags[int8Tag] = cloneableTags[int16Tag] = cloneableTags[int32Tag] = cloneableTags[mapTag] = cloneableTags[numberTag] = cloneableTags[objectTag] = cloneableTags[regexpTag] = cloneableTags[setTag] = cloneableTags[stringTag] = cloneableTags[symbolTag] = cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; cloneableTags[errorTag] = cloneableTags[funcTag] = cloneableTags[weakMapTag] = false; /** Used to map Latin Unicode letters to basic Latin letters. */ var deburredLetters = { // Latin-1 Supplement block. '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A', '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a', '\xc7': 'C', '\xe7': 'c', '\xd0': 'D', '\xf0': 'd', '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E', '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e', '\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I', '\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i', '\xd1': 'N', '\xf1': 'n', '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O', '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o', '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U', '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u', '\xdd': 'Y', '\xfd': 'y', '\xff': 'y', '\xc6': 'Ae', '\xe6': 'ae', '\xde': 'Th', '\xfe': 'th', '\xdf': 'ss', // Latin Extended-A block. '\u0100': 'A', '\u0102': 'A', '\u0104': 'A', '\u0101': 'a', '\u0103': 'a', '\u0105': 'a', '\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C', '\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c', '\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd', '\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E', '\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e', '\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G', '\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g', '\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h', '\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I', '\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i', '\u0134': 'J', '\u0135': 'j', '\u0136': 'K', '\u0137': 'k', '\u0138': 'k', '\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L', '\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l', '\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N', '\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n', '\u014c': 'O', '\u014e': 'O', '\u0150': 'O', '\u014d': 'o', '\u014f': 'o', '\u0151': 'o', '\u0154': 'R', '\u0156': 'R', '\u0158': 'R', '\u0155': 'r', '\u0157': 'r', '\u0159': 'r', '\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S', '\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's', '\u0162': 'T', '\u0164': 'T', '\u0166': 'T', '\u0163': 't', '\u0165': 't', '\u0167': 't', '\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U', '\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u', '\u0174': 'W', '\u0175': 'w', '\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y', '\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z', '\u017a': 'z', '\u017c': 'z', '\u017e': 'z', '\u0132': 'IJ', '\u0133': 'ij', '\u0152': 'Oe', '\u0153': 'oe', '\u0149': "'n", '\u017f': 's' }; /** Used to map characters to HTML entities. */ var htmlEscapes = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }; /** Used to map HTML entities to characters. */ var htmlUnescapes = { '&amp;': '&', '&lt;': '<', '&gt;': '>', '&quot;': '"', '&#39;': "'" }; /** Used to escape characters for inclusion in compiled string literals. */ var stringEscapes = { '\\': '\\', "'": "'", '\n': 'n', '\r': 'r', '\u2028': 'u2028', '\u2029': 'u2029' }; /** Built-in method references without a dependency on `root`. */ var freeParseFloat = parseFloat, freeParseInt = parseInt; /** Detect free variable `global` from Node.js. */ var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal; /** Detect free variable `self`. */ var freeSelf = typeof self == 'object' && self && self.Object === Object && self; /** Used as a reference to the global object. */ var root = freeGlobal || freeSelf || Function('return this')(); /** Detect free variable `exports`. */ var freeExports = exports && !exports.nodeType && exports; /** Detect free variable `module`. */ var freeModule = freeExports && 'object' == 'object' && module && !module.nodeType && module; /** Detect the popular CommonJS extension `module.exports`. */ var moduleExports = freeModule && freeModule.exports === freeExports; /** Detect free variable `process` from Node.js. */ var freeProcess = moduleExports && freeGlobal.process; /** Used to access faster Node.js helpers. */ var nodeUtil = (function() { try { // Use `util.types` for Node.js 10+. var types = freeModule && freeModule.require && freeModule.require('util').types; if (types) { return types; } // Legacy `process.binding('util')` for Node.js < 10. return freeProcess && freeProcess.binding && freeProcess.binding('util'); } catch (e) {} }()); /* Node.js helper references. */ var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer, nodeIsDate = nodeUtil && nodeUtil.isDate, nodeIsMap = nodeUtil && nodeUtil.isMap, nodeIsRegExp = nodeUtil && nodeUtil.isRegExp, nodeIsSet = nodeUtil && nodeUtil.isSet, nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; /*--------------------------------------------------------------------------*/ /** * A faster alternative to `Function#apply`, this function invokes `func` * with the `this` binding of `thisArg` and the arguments of `args`. * * @private * @param {Function} func The function to invoke. * @param {*} thisArg The `this` binding of `func`. * @param {Array} args The arguments to invoke `func` with. * @returns {*} Returns the result of `func`. */ function apply(func, thisArg, args) { switch (args.length) { case 0: return func.call(thisArg); case 1: return func.call(thisArg, args[0]); case