UNPKG

stream-chat-react

Version:

React components to create chat conversations or livestream style chat

141 lines (140 loc) 12.5 kB
var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; import React, { useEffect, useMemo, useState } from 'react'; import { FileUploadButton, ImageDropzone, UploadButton } from 'react-file-utils'; import clsx from 'clsx'; import { usePopper } from 'react-popper'; import { useDropzone } from 'react-dropzone'; import { nanoid } from 'nanoid'; import { EmojiPicker } from './EmojiPicker'; import { EmojiIconLarge as DefaultEmojiIcon, EmojiPickerIcon as DefaultEmojiPickerIcon, FileUploadIconFlat as DefaultFileUploadIcon, SendButton as DefaultSendButton, UploadIcon as DefaultUploadIcon, } from './icons'; import { QuotedMessagePreview as DefaultQuotedMessagePreview, QuotedMessagePreviewHeader, } from './QuotedMessagePreview'; import { AttachmentPreviewList } from './AttachmentPreviewList'; import { UploadsPreview } from './UploadsPreview'; import { ChatAutoComplete } from '../ChatAutoComplete/ChatAutoComplete'; import { Tooltip } from '../Tooltip/Tooltip'; import { useChatContext } from '../../context/ChatContext'; import { useChannelActionContext } from '../../context/ChannelActionContext'; import { useChannelStateContext } from '../../context/ChannelStateContext'; import { useTranslationContext } from '../../context/TranslationContext'; import { useMessageInputContext } from '../../context/MessageInputContext'; import { useComponentContext } from '../../context/ComponentContext'; import { CooldownTimer as DefaultCooldownTimer } from './CooldownTimer'; export var MessageInputFlat = function () { var quotedMessage = useChannelStateContext('MessageInputFlat').quotedMessage; var setQuotedMessage = useChannelActionContext('MessageInputFlat').setQuotedMessage; var _a = useChatContext('MessageInputFlat'), channel = _a.channel, themeVersion = _a.themeVersion; useEffect(function () { var handleQuotedMessageUpdate = function (e) { var _a; if (((_a = e.message) === null || _a === void 0 ? void 0 : _a.id) !== (quotedMessage === null || quotedMessage === void 0 ? void 0 : quotedMessage.id)) return; if (e.type === 'message.deleted') { setQuotedMessage(undefined); return; } setQuotedMessage(e.message); }; channel === null || channel === void 0 ? void 0 : channel.on('message.deleted', handleQuotedMessageUpdate); channel === null || channel === void 0 ? void 0 : channel.on('message.updated', handleQuotedMessageUpdate); return function () { channel === null || channel === void 0 ? void 0 : channel.off('message.deleted', handleQuotedMessageUpdate); channel === null || channel === void 0 ? void 0 : channel.off('message.updated', handleQuotedMessageUpdate); }; }, [channel, quotedMessage]); return themeVersion === '2' ? (React.createElement(MessageInputV2, null)) : (React.createElement(MessageInputV1, null)); }; var MessageInputV1 = function () { var _a = useChannelStateContext('MessageInputFlat'), acceptedFiles = _a.acceptedFiles, multipleUploads = _a.multipleUploads, quotedMessage = _a.quotedMessage; var t = useTranslationContext('MessageInputFlat').t; var _b = useMessageInputContext('MessageInputFlat'), closeEmojiPicker = _b.closeEmojiPicker, cooldownRemaining = _b.cooldownRemaining, emojiPickerIsOpen = _b.emojiPickerIsOpen, handleSubmit = _b.handleSubmit, isUploadEnabled = _b.isUploadEnabled, maxFilesLeft = _b.maxFilesLeft, numberOfUploads = _b.numberOfUploads, openEmojiPicker = _b.openEmojiPicker, setCooldownRemaining = _b.setCooldownRemaining, uploadNewFiles = _b.uploadNewFiles; var _c = useComponentContext('MessageInputFlat'), _d = _c.CooldownTimer, CooldownTimer = _d === void 0 ? DefaultCooldownTimer : _d, _e = _c.EmojiIcon, EmojiIcon = _e === void 0 ? DefaultEmojiIcon : _e, _f = _c.FileUploadIcon, FileUploadIcon = _f === void 0 ? DefaultFileUploadIcon : _f, _g = _c.QuotedMessagePreview, QuotedMessagePreview = _g === void 0 ? DefaultQuotedMessagePreview : _g, _h = _c.SendButton, SendButton = _h === void 0 ? DefaultSendButton : _h; return (React.createElement("div", { className: clsx('str-chat__input-flat', 'str-chat__message-input', { 'str-chat__input-flat--send-button-active': !!SendButton, 'str-chat__input-flat-has-attachments': numberOfUploads, 'str-chat__input-flat-quoted': quotedMessage && !quotedMessage.parent_id, }) }, React.createElement(ImageDropzone, { accept: acceptedFiles, disabled: !isUploadEnabled || maxFilesLeft === 0 || !!cooldownRemaining, handleFiles: uploadNewFiles, maxNumberOfFiles: maxFilesLeft, multiple: multipleUploads }, quotedMessage && !quotedMessage.parent_id && (React.createElement(QuotedMessagePreview, { quotedMessage: quotedMessage })), React.createElement("div", { className: 'str-chat__input-flat-wrapper' }, isUploadEnabled && React.createElement(UploadsPreview, null), React.createElement("div", { className: 'str-chat__input-flat--textarea-wrapper' }, React.createElement("div", { className: 'str-chat__emojiselect-wrapper' }, React.createElement(Tooltip, null, emojiPickerIsOpen ? t('Close emoji picker') : t('Open emoji picker')), React.createElement("button", { "aria-label": 'Emoji picker', className: 'str-chat__input-flat-emojiselect', onClick: emojiPickerIsOpen ? closeEmojiPicker : openEmojiPicker }, cooldownRemaining ? (React.createElement("div", { className: 'str-chat__input-flat-cooldown' }, React.createElement(CooldownTimer, { cooldownInterval: cooldownRemaining, setCooldownRemaining: setCooldownRemaining }))) : (React.createElement(EmojiIcon, null)))), React.createElement(EmojiPicker, null), React.createElement(ChatAutoComplete, null), isUploadEnabled && !cooldownRemaining && (React.createElement("div", { className: 'str-chat__fileupload-wrapper', "data-testid": 'fileinput' }, React.createElement(Tooltip, null, maxFilesLeft ? t('Attach files') : t("You've reached the maximum number of files")), React.createElement(FileUploadButton, { accepts: acceptedFiles, disabled: maxFilesLeft === 0, handleFiles: uploadNewFiles, multiple: multipleUploads }, React.createElement("span", { className: 'str-chat__input-flat-fileupload' }, React.createElement(FileUploadIcon, null)))))), !cooldownRemaining && React.createElement(SendButton, { sendMessage: handleSubmit }))))); }; var MessageInputV2 = function () { var _a = useChannelStateContext('MessageInputV2'), _b = _a.acceptedFiles, acceptedFiles = _b === void 0 ? [] : _b, multipleUploads = _a.multipleUploads, quotedMessage = _a.quotedMessage; var t = useTranslationContext('MessageInputV2').t; var _c = useMessageInputContext('MessageInputV2'), closeEmojiPicker = _c.closeEmojiPicker, cooldownRemaining = _c.cooldownRemaining, emojiPickerIsOpen = _c.emojiPickerIsOpen, handleSubmit = _c.handleSubmit, isUploadEnabled = _c.isUploadEnabled, maxFilesLeft = _c.maxFilesLeft, message = _c.message, numberOfUploads = _c.numberOfUploads, openEmojiPicker = _c.openEmojiPicker, setCooldownRemaining = _c.setCooldownRemaining, text = _c.text, uploadNewFiles = _c.uploadNewFiles; var _d = useComponentContext('MessageInputV2'), _e = _d.CooldownTimer, CooldownTimer = _e === void 0 ? DefaultCooldownTimer : _e, _f = _d.EmojiIcon, EmojiIcon = _f === void 0 ? DefaultEmojiPickerIcon : _f, _g = _d.FileUploadIcon, FileUploadIcon = _g === void 0 ? DefaultUploadIcon : _g, _h = _d.QuotedMessagePreview, QuotedMessagePreview = _h === void 0 ? DefaultQuotedMessagePreview : _h, _j = _d.SendButton, SendButton = _j === void 0 ? DefaultSendButton : _j; var _k = useState(null), referenceElement = _k[0], setReferenceElement = _k[1]; var _l = useState(null), popperElement = _l[0], setPopperElement = _l[1]; var _m = usePopper(referenceElement, popperElement, { placement: 'top-end', }), attributes = _m.attributes, styles = _m.styles; var id = useMemo(function () { return nanoid(); }, []); var accept = useMemo(function () { return acceptedFiles.reduce(function (mediaTypeMap, mediaType) { var _a; (_a = mediaTypeMap[mediaType]) !== null && _a !== void 0 ? _a : (mediaTypeMap[mediaType] = []); return mediaTypeMap; }, {}); }, [acceptedFiles]); var _o = useDropzone({ accept: accept, disabled: !isUploadEnabled || maxFilesLeft === 0, multiple: multipleUploads, noClick: true, onDrop: uploadNewFiles, }), getRootProps = _o.getRootProps, isDragActive = _o.isDragActive, isDragReject = _o.isDragReject; // TODO: "!message" condition is a temporary fix for shared // state when editing a message (fix shared state issue) var displayQuotedMessage = !message && quotedMessage && !quotedMessage.parent_id; return (React.createElement(React.Fragment, null, React.createElement("div", __assign({}, getRootProps({ className: 'str-chat__message-input' })), isDragActive && (React.createElement("div", { className: clsx('str-chat__dropzone-container', { 'str-chat__dropzone-container--not-accepted': isDragReject, }) }, !isDragReject && React.createElement("p", null, t('Drag your files here')), isDragReject && React.createElement("p", null, t('Some of the files will not be accepted')))), displayQuotedMessage && React.createElement(QuotedMessagePreviewHeader, null), React.createElement("div", { className: 'str-chat__message-input-inner' }, React.createElement("div", { className: 'str-chat__file-input-container', "data-testid": 'file-upload-button' }, React.createElement(UploadButton, { accept: acceptedFiles === null || acceptedFiles === void 0 ? void 0 : acceptedFiles.join(','), "aria-label": 'File upload', className: 'str-chat__file-input', "data-testid": 'file-input', disabled: !isUploadEnabled || maxFilesLeft === 0, id: id, multiple: multipleUploads, onFileChange: uploadNewFiles }), React.createElement("label", { className: 'str-chat__file-input-label', htmlFor: id }, React.createElement(FileUploadIcon, null))), React.createElement("div", { className: 'str-chat__message-textarea-container' }, displayQuotedMessage && React.createElement(QuotedMessagePreview, { quotedMessage: quotedMessage }), isUploadEnabled && !!numberOfUploads && React.createElement(AttachmentPreviewList, null), React.createElement("div", { className: 'str-chat__message-textarea-with-emoji-picker' }, React.createElement(ChatAutoComplete, null), React.createElement("div", { className: 'str-chat__message-textarea-emoji-picker' }, emojiPickerIsOpen && (React.createElement("div", __assign({ className: 'str-chat__message-textarea-emoji-picker-container', style: styles.popper }, attributes.popper, { ref: setPopperElement }), React.createElement(EmojiPicker, null))), React.createElement("button", { "aria-label": 'Emoji picker', className: 'str-chat__emoji-picker-button', onClick: emojiPickerIsOpen ? closeEmojiPicker : openEmojiPicker, ref: setReferenceElement, type: 'button' }, React.createElement(EmojiIcon, null))))), !message && (React.createElement(React.Fragment, null, cooldownRemaining ? (React.createElement(CooldownTimer, { cooldownInterval: cooldownRemaining, setCooldownRemaining: setCooldownRemaining })) : (React.createElement(SendButton, { disabled: !numberOfUploads && !text.length, sendMessage: handleSubmit })))))))); };