UNPKG

xom-stream-chat-react

Version:

React components to create chat conversations or livestream style chat

1,428 lines (1,212 loc) 473 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var _extends = _interopDefault(require('@babel/runtime/helpers/extends')); var _classCallCheck = _interopDefault(require('@babel/runtime/helpers/classCallCheck')); var _createClass = _interopDefault(require('@babel/runtime/helpers/createClass')); var _possibleConstructorReturn = _interopDefault(require('@babel/runtime/helpers/possibleConstructorReturn')); var _getPrototypeOf = _interopDefault(require('@babel/runtime/helpers/getPrototypeOf')); var _assertThisInitialized = _interopDefault(require('@babel/runtime/helpers/assertThisInitialized')); var _inherits = _interopDefault(require('@babel/runtime/helpers/inherits')); var _defineProperty = _interopDefault(require('@babel/runtime/helpers/defineProperty')); var React = require('react'); var React__default = _interopDefault(React); var ReactPlayer = _interopDefault(require('react-player')); var PropTypes = _interopDefault(require('prop-types')); var sanitizeUrl = require('@braintree/sanitize-url'); var Carousel = require('react-images'); var Carousel__default = _interopDefault(Carousel); var reactFileUtils = require('react-file-utils'); var prettybytes = _interopDefault(require('pretty-bytes')); var _toConsumableArray = _interopDefault(require('@babel/runtime/helpers/toConsumableArray')); var _regeneratorRuntime = _interopDefault(require('@babel/runtime/regenerator')); var _asyncToGenerator = _interopDefault(require('@babel/runtime/helpers/asyncToGenerator')); var uuidv4 = _interopDefault(require('uuid/v4')); var Immutable = _interopDefault(require('seamless-immutable')); var Visibility = _interopDefault(require('visibilityjs')); var streamChat = require('stream-chat'); var anchorme = _interopDefault(require('anchorme')); var emojiRegex = _interopDefault(require('emoji-regex')); var ReactMarkdown = _interopDefault(require('react-markdown/with-html')); var truncate = _interopDefault(require('lodash/truncate')); var data = _interopDefault(require('emoji-mart/data/all.json')); var emojiMart = require('emoji-mart'); var _typeof = _interopDefault(require('@babel/runtime/helpers/typeof')); var _slicedToArray = _interopDefault(require('@babel/runtime/helpers/slicedToArray')); var getCaretCoordinates = _interopDefault(require('textarea-caret')); var CustomEvent = _interopDefault(require('custom-event')); var Textarea = _interopDefault(require('react-textarea-autosize')); var uniq = _interopDefault(require('lodash/uniq')); var moment = _interopDefault(require('moment')); var debounce = _interopDefault(require('lodash/debounce')); var throttle = _interopDefault(require('lodash/throttle')); var uniqBy = _interopDefault(require('lodash.uniqby')); var deepequal = _interopDefault(require('deep-equal')); var _objectWithoutProperties = _interopDefault(require('@babel/runtime/helpers/objectWithoutProperties')); /** * SafeAnchor - In all ways similar to a regular anchor tag. * The difference is that it sanitizes the href value and prevents XSS * @extends PureComponent */ var SafeAnchor = /*#__PURE__*/ function (_React$PureComponent) { _inherits(SafeAnchor, _React$PureComponent); function SafeAnchor() { _classCallCheck(this, SafeAnchor); return _possibleConstructorReturn(this, _getPrototypeOf(SafeAnchor).apply(this, arguments)); } _createClass(SafeAnchor, [{ key: "render", value: function render() { var href = sanitizeUrl.sanitizeUrl(this.props.href); return React__default.createElement("a", _extends({}, this.props, { href: href }), this.props.children); } }]); return SafeAnchor; }(React__default.PureComponent); var giphyLogo = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAAAkCAYAAAB/up84AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABVhJREFUeNrsW6GS20AMdToGBgEGAQYBBgEBBQYFgQcP5hMO9jP6CYWFBwsPBgYUGBQEFAQUGAQYBBgYGHjmutt5O6NupbXXcZJrx5rJXGyv11o96Ukr52avr6/BJG9HZmMBMpvNYnxt1JzNZNoRAYFxM2Z8rT6FuueMcaH6s1KfhBn3U42r1Jg1rrfq+Bt5xgf1Z64+uQFQndNzLc1Ydfwg6F2p6wd1PVXfU+b6Gc9vHGuh8+jrsXVN61Sq64XggNw95tlH9XmP6y3W2OI+qvN3db6mN7/zBFAb8L2aNMJxRsDQC6jIuEyN039LnAvV8QJKRRijZUHmT8iiLpEFDHKJaB1TGN732WuAokEIDQCwhwGjsMEIMNgp6qY9JlsTgyXquCFG1d54IsbOsKAVPLDBcQJjUxB0RJwAltGntNQ46GhzqPnb0y0954RG/1iLQ7SRCkR+guiPtW6GFRg5gAlCrFvbJEZ0ngDAUn0/Y77fDCJFXuiB/AmGDC3PLg0YWLRW5CcJWWPglNxDKS6C59AcZBs/sYxbOQBqHHkuZYCsGCds4SQJDDx3RK3RjUb9EfMUcLQ57BHS64MAIYtYkvEt+d4wCzqr++ipkoTtkihOI2chREfA5KiC0GOAaMig05zoWJPjgMk39jxcPphDR0mSDrtq438g51iq8omQlEnYJfHoiAFxYQGko6bCPSmZ5wS+TRx0Zc5R4CtmHbEVJT+0p1uOYdNE1SMfOKNO0zXWEmItptApsfYa1LV0UZUPIHSCmlRYJhfokNWhX5IcsmIWbEAMCQWerWirhZK57MghNQyzgke3QuQWPUv4EAac9wCuJjmkNmvUNEwiobX+DgdEWoQGgNDPGtTWWhRRWONX5JlnePCZhP1JUCOzPN1O0C2MohP7xuiko8Qy9INUDBg2YPJMlzP8pRv0qYeUdu+Cy+RAKIYmtVqojM5kkS0DwkXlLuY0ICzgAEOlAd8fPe+rYJdppz61TiZ5G4AgcScWz05RcUtAkOwyJMtI4FzNt3suCWKfwLUhdqRC0yA/enB1CZ4vBZ2fhIptJ4x/5PYVavyzQ39N0V8ddnsQ+m3sfX02hjo3bIVJ7d5PhqojZxYdC3NEdv9oQMQWFFjHHqpLEsc9BZyF23c9cG0ZOJjUIN15V1mY8OOAhW0E77yWaP2eoO9VBFG/d6yX6/xuHT2z3AsQ5ImnjrZBF6XcUiKAEl0RlJzZ7ZtnbxmqSgRqfxmyD9k6wNDGzuExecB3Z1/ukBOjQH73MZbspChFp9nQ/EYY9+LaaIYOqlo7JjwISX+LcBwbjAOz2ZKS7BpOcq0o0R2HvZAbHpHPJGc+dm00paQuedmOA4O0WD5fyQ4V08Ip4ATxhYl8CCh76/0QLVyehlBVFyCpYJTcKmPjHoY8XNE2VQ8dbIkdr4Z95npBwcNVahKzNEMBSYSyz46iLm8sLunreG5O+xYTsaMUHYu6bMn79sRCT2+8l6SMV2cCT5e3UspBXbbd9n3nDIN/Q1KP3JDfWLcd8kZwCVX12hjeOlmOIMe+L6FGjJLC4QS5rz6hg/tThjZiU0Pr/g7D65/uCUafKgaUJu0lHjvox/XsjXA+GAOQUogIXV8/v7GoKOGJfYuHxvHjt7t3rEMHD2+E5PoR+5GCLCS+8g6Z2xgGt6anuwGC99MSKAl6RrfUs/ofje+b1PcjlJBlMMk4gKBUe77AqKVP/T1Jj30IQPmCTdkm6NeKb5BkJzCGdCA8XuFGZIOWCBEh/mwGiZ/rFZXk3xHEdkjHb6MknVOhypJe+Sac03XlL4fe3r81mH518q9GyCS3kV8CDADlsrVaJhTLAgAAAABJRU5ErkJggg=="; /** * Card - Simple Card Layout * * @example ./docs/Card.md * @extends PureComponent */ var Card = /*#__PURE__*/ function (_React$PureComponent) { _inherits(Card, _React$PureComponent); function Card() { var _getPrototypeOf2; var _this; _classCallCheck(this, Card); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(Card)).call.apply(_getPrototypeOf2, [this].concat(args))); _defineProperty(_assertThisInitialized(_this), "trimUrl", function (url) { var trimmedUrl; if (url !== undefined && url !== null) { trimmedUrl = url.replace(/^(?:https?:\/\/)?(?:www\.)?/i, '').split('/')[0]; } return trimmedUrl; }); return _this; } _createClass(Card, [{ key: "render", value: function render() { var _this$props = this.props, title = _this$props.title, title_link = _this$props.title_link, text = _this$props.text, type = _this$props.type, image_url = _this$props.image_url, thumb_url = _this$props.thumb_url, og_scrape_url = _this$props.og_scrape_url; var image = thumb_url || image_url; if (!title && !title_link && !image) { return React__default.createElement("div", { className: "str-chat__message-attachment-card str-chat__message-attachment-card--".concat(type) }, React__default.createElement("div", { className: "str-chat__message-attachment-card--content" }, React__default.createElement("div", { className: "str-chat__message-attachment-card--text" }, "this content could not be displayed"))); } if (!title_link && !og_scrape_url) { return null; } return React__default.createElement("div", { className: "str-chat__message-attachment-card str-chat__message-attachment-card--".concat(type) }, image && React__default.createElement("div", { className: "str-chat__message-attachment-card--header" }, React__default.createElement("img", { src: image, alt: image })), React__default.createElement("div", { className: "str-chat__message-attachment-card--content" }, React__default.createElement("div", { className: "str-chat__message-attachment-card--flex" }, title && React__default.createElement("div", { className: "str-chat__message-attachment-card--title" }, title), text && React__default.createElement("div", { className: "str-chat__message-attachment-card--text" }, text), (title_link || og_scrape_url) && React__default.createElement(SafeAnchor, { href: title_link || og_scrape_url, target: "_blank", rel: "noopener noreferrer", className: "str-chat__message-attachment-card--url" }, this.trimUrl(title_link || og_scrape_url))), type === 'giphy' && React__default.createElement("img", { className: "str-chat__message-attachment-card__giphy-logo", src: giphyLogo, alt: "giphy logo" }))); } }]); return Card; }(React__default.PureComponent); _defineProperty(Card, "propTypes", { /** Title returned by the OG scraper */ title: PropTypes.string, /** Link returned by the OG scraper */ title_link: PropTypes.string, /** The scraped url, used as a fallback if the OG-data doesn't include a link */ og_scrape_url: PropTypes.string, /** The url of the full sized image */ image_url: PropTypes.string, /** The url for thumbnail sized image*/ thumb_url: PropTypes.string, /** Description returned by the OG scraper */ text: PropTypes.string }); /** * Image - Small wrapper around an image tag, supports thumbnails * * @example ./docs/Image.md * @extends PureComponent */ var Image = /*#__PURE__*/ function (_React$PureComponent) { _inherits(Image, _React$PureComponent); function Image() { var _getPrototypeOf2; var _this; _classCallCheck(this, Image); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(Image)).call.apply(_getPrototypeOf2, [this].concat(args))); _defineProperty(_assertThisInitialized(_this), "state", { modalIsOpen: false, currentIndex: 0 }); _defineProperty(_assertThisInitialized(_this), "toggleModal", function () { _this.setState(function (state) { return { modalIsOpen: !state.modalIsOpen }; }); }); return _this; } _createClass(Image, [{ key: "render", value: function render() { var _this$props = this.props, image_url = _this$props.image_url, thumb_url = _this$props.thumb_url, fallback = _this$props.fallback; var formattedArray = [{ src: image_url || thumb_url }]; return React__default.createElement(React__default.Fragment, null, React__default.createElement("img", { className: "str-chat__message-attachment--img", onClick: this.toggleModal, src: thumb_url || image_url, alt: fallback }), React__default.createElement(Carousel.ModalGateway, null, this.state.modalIsOpen ? React__default.createElement(Carousel.Modal, { onClose: this.toggleModal }, React__default.createElement(Carousel__default, { views: formattedArray })) : null)); } }]); return Image; }(React__default.PureComponent); _defineProperty(Image, "propTypes", { /** The full size image url */ image_url: PropTypes.string, /** The thumb url */ thumb_url: PropTypes.string, /** The text fallback for the image */ fallback: PropTypes.string }); /** * AttachmentActions - The actions you can take on an attachment * * @example ./docs/AttachmentActions.md * @extends PureComponent */ var AttachmentActions = /*#__PURE__*/ function (_React$PureComponent) { _inherits(AttachmentActions, _React$PureComponent); function AttachmentActions() { _classCallCheck(this, AttachmentActions); return _possibleConstructorReturn(this, _getPrototypeOf(AttachmentActions).apply(this, arguments)); } _createClass(AttachmentActions, [{ key: "render", value: function render() { var _this = this; var _this$props = this.props, text = _this$props.text, id = _this$props.id, actions = _this$props.actions, actionHandler = _this$props.actionHandler; return React__default.createElement("div", { className: "str-chat__message-attachment-actions" }, React__default.createElement("form", { className: "str-chat__message-attachment-actions-form" }, React__default.createElement("span", { key: 0 }, text), actions.map(function (action) { return React__default.createElement("button", { className: "str-chat__message-attachment-actions-button str-chat__message-attachment-actions-button--".concat(action.style), key: "".concat(id, "-").concat(action.value), "data-value": action.value, onClick: actionHandler.bind(_this, action.name, action.value) }, action.text); }))); } }]); return AttachmentActions; }(React__default.PureComponent); _defineProperty(AttachmentActions, "propTypes", { /** Unique id for action button key. Key is generated by concatenating this id with action value - {`${id}-${action.value}`} */ id: PropTypes.string.isRequired, /** The text for the form input */ text: PropTypes.string, /** A list of actions */ actions: PropTypes.array.isRequired, /** * * Handler for actions. Actions in combination with attachments can be used to build [commands](https://getstream.io/chat/docs/#channel_commands). * * @param name {string} Name of action * @param value {string} Value of action * @param event Dom event that triggered this handler */ actionHandler: PropTypes.func.isRequired }); var Audio = /*#__PURE__*/ function (_React$Component) { _inherits(Audio, _React$Component); function Audio(props) { var _this; _classCallCheck(this, Audio); _this = _possibleConstructorReturn(this, _getPrototypeOf(Audio).call(this, props)); _defineProperty(_assertThisInitialized(_this), "playAudio", function () { if (_this.audioRef.current !== null) { _this.audioRef.current.pause(); _this.updateProgress(); _this.setState({ playing: true, updateProgress: setInterval(_this.updateProgress, 500) }); //$FlowFixMe _this.audioRef.current.play(); } }); _defineProperty(_assertThisInitialized(_this), "pauseAudio", function () { if (_this.audioRef.current !== null) { _this.audioRef.current.pause(); } _this.setState({ playing: false }); window.clearInterval(_this.state.updateProgress); }); _defineProperty(_assertThisInitialized(_this), "updateProgress", function () { if (_this.audioRef.current !== null) { var position = _this.audioRef.current.currentTime; var duration = _this.audioRef.current.duration; var progress = 100 / duration * position; _this.setState({ progress: progress }); if (position === duration) { _this.pauseAudio(); } } }); _this.state = { open: false, playing: false, progress: 0, updateProgress: null }; _this.audioRef = React.createRef(); return _this; } _createClass(Audio, [{ key: "componentWillUnmount", value: function componentWillUnmount() { window.clearInterval(this.state.updateProgress); } }, { key: "render", value: function render() { var _this2 = this; var og = this.props.og; var url = og.asset_url; var image = og.image_url; return React.createElement("div", { className: "str-chat__audio" }, React.createElement("div", { className: "str-chat__audio__wrapper" }, React.createElement("audio", { ref: this.audioRef }, React.createElement("source", { src: url, type: "audio/mp3" })), React.createElement("div", { className: "str-chat__audio__image" }, React.createElement("div", { className: "str-chat__audio__image--overlay" }, !this.state.playing ? React.createElement("div", { onClick: function onClick() { return _this2.playAudio(); }, className: "str-chat__audio__image--button" }, React.createElement("svg", { width: "40", height: "40", viewBox: "0 0 64 64", xmlns: "http://www.w3.org/2000/svg" }, React.createElement("path", { d: "M32 58c14.36 0 26-11.64 26-26S46.36 6 32 6 6 17.64 6 32s11.64 26 26 26zm0 6C14.327 64 0 49.673 0 32 0 14.327 14.327 0 32 0c17.673 0 32 14.327 32 32 0 17.673-14.327 32-32 32zm13.237-28.412L26.135 45.625a3.27 3.27 0 0 1-4.426-1.4 3.319 3.319 0 0 1-.372-1.47L21 23.36c-.032-1.823 1.41-3.327 3.222-3.358a3.263 3.263 0 0 1 1.473.322l19.438 9.36a3.311 3.311 0 0 1 .103 5.905z", fillRule: "nonzero" }))) : React.createElement("div", { onClick: function onClick() { return _this2.pauseAudio(); }, className: "str-chat__audio__image--button" }, React.createElement("svg", { width: "40", height: "40", viewBox: "0 0 64 64", xmlns: "http://www.w3.org/2000/svg" }, React.createElement("path", { d: "M32 58.215c14.478 0 26.215-11.737 26.215-26.215S46.478 5.785 32 5.785 5.785 17.522 5.785 32 17.522 58.215 32 58.215zM32 64C14.327 64 0 49.673 0 32 0 14.327 14.327 0 32 0c17.673 0 32 14.327 32 32 0 17.673-14.327 32-32 32zm-7.412-45.56h2.892a2.17 2.17 0 0 1 2.17 2.17v23.865a2.17 2.17 0 0 1-2.17 2.17h-2.892a2.17 2.17 0 0 1-2.17-2.17V20.61a2.17 2.17 0 0 1 2.17-2.17zm12.293 0h2.893a2.17 2.17 0 0 1 2.17 2.17v23.865a2.17 2.17 0 0 1-2.17 2.17h-2.893a2.17 2.17 0 0 1-2.17-2.17V20.61a2.17 2.17 0 0 1 2.17-2.17z", fillRule: "nonzero" })))), React.createElement("img", { src: image, alt: "".concat(og.description) })), React.createElement("div", { className: "str-chat__audio__content" }, React.createElement("span", { className: "str-chat__audio__content--title" }, React.createElement("strong", null, og.title)), React.createElement("span", { className: "str-chat__audio__content--subtitle" }, og.text), React.createElement("div", { className: "str-chat__audio__content--progress" }, React.createElement("div", { style: { width: "".concat(this.state.progress, "%") } }))))); } }]); return Audio; }(React.Component); _defineProperty(Audio, "propTypes", { /** Attachment object of audio type */ og: PropTypes.object }); /** * Attachment - The message attachment * * @example ./docs/Attachment.md * @extends PureComponent */ var Attachment = /*#__PURE__*/ function (_PureComponent) { _inherits(Attachment, _PureComponent); function Attachment() { var _getPrototypeOf2; var _this; _classCallCheck(this, Attachment); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(Attachment)).call.apply(_getPrototypeOf2, [this].concat(args))); _defineProperty(_assertThisInitialized(_this), "attachmentRef", React__default.createRef()); _defineProperty(_assertThisInitialized(_this), "renderAttachmentActions", function (a) { return React__default.createElement(AttachmentActions, _extends({ key: 'key-actions-' + a.id }, a, { actionHandler: _this.props.actionHandler })); }); _defineProperty(_assertThisInitialized(_this), "renderAttachment", function (a) { return React__default.createElement("div", { className: "str-chat__attachment", key: "key-image-".concat(a.id) }, React__default.createElement(Card, _extends({}, a, { key: "key-card-".concat(a.id) })), _this.renderAttachmentActions(a)); }); return _this; } _createClass(Attachment, [{ key: "attachmentType", value: function attachmentType(a) { var type, extra; if (a.actions && a.actions.length > 0) { extra = 'actions'; } if (a.type === 'giphy' || a.type === 'imgur') { type = 'card'; } else if (a.type === 'image' && (a.title_link || a.og_scrape_url)) { type = 'card'; } else if (a.type === 'image') { type = 'image'; } else if (a.type === 'file') { type = 'file'; } else if (a.type === 'audio') { type = 'audio'; } else if (a.type === 'video') { type = 'media'; } else { type = 'card'; extra = 'no-image'; } return { type: type, extra: extra }; } }, { key: "render", value: function render() { var a = this.props.attachment; if (!a) { return null; } var _this$attachmentType = this.attachmentType(a), type = _this$attachmentType.type, extra = _this$attachmentType.extra; if (type === 'card' && !a.title_link && !a.og_scrape_url) { return null; } var results = []; if (type === 'image') { if (a.actions && a.actions.length) { results.push(React__default.createElement("div", { className: "str-chat__attachment", key: "key-image-".concat(a.id) }, React__default.createElement(Image, a), this.renderAttachmentActions(a))); } else { results.push(React__default.createElement(Image, _extends({}, a, { key: "key-image-".concat(a.id) }))); } } else if (type === 'file') { a.asset_url && results.push(React__default.createElement("div", { className: "str-chat__message-attachment-file--item", key: "key-file-".concat(a.id) }, React__default.createElement(reactFileUtils.FileIcon, { mimeType: a.mime_type, filename: a.title, big: true, size: 30 }), React__default.createElement("div", { className: "str-chat__message-attachment-file--item-text" }, React__default.createElement(SafeAnchor, { href: a.asset_url, download: true }, a.title), a.file_size && React__default.createElement("span", null, prettybytes(a.file_size))))); } else if (type === 'audio') { results.push(React__default.createElement("div", { className: "str-chat__attachment", key: "key-video-".concat(a.id) }, React__default.createElement(Audio, { og: a }))); } else if (type === 'media') { if (a.actions && a.actions.length) { results.push(React__default.createElement("div", { className: "str-chat__attachment", key: "key-video-".concat(a.id) }, React__default.createElement("div", { className: "str-chat__player-wrapper" }, React__default.createElement(ReactPlayer, { className: "react-player", url: a.asset_url, width: "100%", height: "100%", controls: true })), this.renderAttachmentActions(a))); } else { results.push(React__default.createElement("div", { className: "str-chat__player-wrapper", key: "key-video-".concat(a.id) }, React__default.createElement(ReactPlayer, { className: "react-player", url: a.asset_url, width: "100%", height: "100%", controls: true }))); } } else { if (a.actions && a.actions.length) { results.push(this.renderAttachment(a)); } else { results.push(React__default.createElement(Card, _extends({}, a, { key: "key-card-".concat(a.id) }))); } } if (results.length === 0) return null; return React__default.createElement("div", { className: "str-chat__message-attachment str-chat__message-attachment--".concat(type, " str-chat__message-attachment--").concat(a.type, " str-chat__message-attachment--").concat(type, "--").concat(extra), ref: this.attachmentRef }, results); } }]); return Attachment; }(React.PureComponent); _defineProperty(Attachment, "propTypes", { /** * The attachment to render * @see See [Attachment structure](https://getstream.io/chat/docs/#message_format) * * */ attachment: PropTypes.object.isRequired, /** * * Handler for actions. Actions in combination with attachments can be used to build [commands](https://getstream.io/chat/docs/#channel_commands). * * @param name {string} Name of action * @param value {string} Value of action * @param event Dom event that triggered this handler */ actionHandler: PropTypes.func.isRequired }); Attachment.propTypes = {}; /** * Avatar - A round avatar image with fallback to username's first letter * * @example ./docs/Avatar.md * @extends PureComponent */ var Avatar = /*#__PURE__*/ function (_React$PureComponent) { _inherits(Avatar, _React$PureComponent); function Avatar() { var _getPrototypeOf2; var _this; _classCallCheck(this, Avatar); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(Avatar)).call.apply(_getPrototypeOf2, [this].concat(args))); _defineProperty(_assertThisInitialized(_this), "state", { errored: false, loaded: false }); _defineProperty(_assertThisInitialized(_this), "getInitials", function (name) { return name ? name.split(' ').slice(0, 1).map(function (name) { return name.charAt(0); }) : null; }); _defineProperty(_assertThisInitialized(_this), "onLoad", function () { _this.setState({ loaded: true }); }); _defineProperty(_assertThisInitialized(_this), "onError", function () { _this.setState({ errored: true }); }); return _this; } _createClass(Avatar, [{ key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { if (prevProps.image !== this.props.image) { this.setState({ loaded: false, errored: false }); } } }, { key: "render", value: function render() { var _this$props = this.props, size = _this$props.size, name = _this$props.name, shape = _this$props.shape, image = _this$props.image; var initials = this.getInitials(name); return React__default.createElement("div", { className: "str-chat__avatar str-chat__avatar--".concat(shape), title: name, style: { width: size, height: size, flexBasis: size, lineHeight: size + 'px', fontSize: size / 2 } }, image && !this.state.errored ? React__default.createElement("img", { src: image, alt: initials, className: 'str-chat__avatar-image' + (this.state.loaded ? ' str-chat__avatar-image--loaded' : ''), style: { width: size, height: size, flexBasis: size, objectFit: 'cover' }, onLoad: this.onLoad, onError: this.onError }) : React__default.createElement("div", { className: "str-chat__avatar-fallback" }, initials)); } }]); return Avatar; }(React__default.PureComponent); _defineProperty(Avatar, "propTypes", { /** image url */ image: PropTypes.string, /** name of the picture, used for title tag fallback */ name: PropTypes.string, /** shape of the avatar, circle, rounded or square */ shape: PropTypes.oneOf(['circle', 'rounded', 'square']), /** size in pixels */ size: PropTypes.number }); _defineProperty(Avatar, "defaultProps", { size: 32, shape: 'circle' }); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } var ChatContext = React__default.createContext({ client: null }); function withChatContext(OriginalComponent) { var ContextAwareComponent = function ContextComponent(props) { return React__default.createElement(ChatContext.Consumer, null, function (context) { var mergedProps = _objectSpread({}, context, {}, props); return React__default.createElement(OriginalComponent, mergedProps); }); }; ContextAwareComponent.displayName = OriginalComponent.displayName || OriginalComponent.name || 'Component'; ContextAwareComponent.displayName = ContextAwareComponent.displayName.replace('Base', ''); return ContextAwareComponent; } var ChannelContext = React__default.createContext({}); function withChannelContext(OriginalComponent) { var ContextAwareComponent = function ContextComponent(props) { return React__default.createElement(ChannelContext.Consumer, null, function (channelContext) { return React__default.createElement(OriginalComponent, _extends({}, channelContext, props)); }); }; ContextAwareComponent.displayName = OriginalComponent.displayName || OriginalComponent.name || 'Component'; ContextAwareComponent.displayName = ContextAwareComponent.displayName.replace('Base', ''); return ContextAwareComponent; } /** * LoadingIndicator - Just a simple loading spinner.. * * @example ./docs/LoadingIndicator.md * @extends PureComponent */ var LoadingIndicator = /*#__PURE__*/ function (_React$PureComponent) { _inherits(LoadingIndicator, _React$PureComponent); function LoadingIndicator() { var _getPrototypeOf2; var _this; _classCallCheck(this, LoadingIndicator); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(LoadingIndicator)).call.apply(_getPrototypeOf2, [this].concat(args))); _defineProperty(_assertThisInitialized(_this), "stopRef", React__default.createRef()); return _this; } _createClass(LoadingIndicator, [{ key: "render", value: function render() { var _this$props = this.props, size = _this$props.size, color = _this$props.color; return React__default.createElement("div", { className: 'str-chat__loading-indicator ' + color, style: { width: size, height: size } }, React__default.createElement("svg", { width: size, height: size, viewBox: "0 0 30 30", xmlns: "http://www.w3.org/2000/svg" }, React__default.createElement("defs", null, React__default.createElement("linearGradient", { x1: "50%", y1: "0%", x2: "50%", y2: "100%", id: "a" }, React__default.createElement("stop", { stopColor: "#FFF", stopOpacity: "0", offset: "0%" }), React__default.createElement("stop", { ref: this.stopRef, offset: "100%", stopColor: color, stopOpacity: "1", style: { stopColor: color } }))), React__default.createElement("path", { d: "M2.518 23.321l1.664-1.11A12.988 12.988 0 0 0 15 28c7.18 0 13-5.82 13-13S22.18 2 15 2V0c8.284 0 15 6.716 15 15 0 8.284-6.716 15-15 15-5.206 0-9.792-2.652-12.482-6.679z", fill: "url(#a)", fillRule: "evenodd" }))); } }]); return LoadingIndicator; }(React__default.PureComponent); _defineProperty(LoadingIndicator, "propTypes", { /** The size of the loading icon */ size: PropTypes.number, /** Set the color of the LoadingIndicator */ color: PropTypes.string }); _defineProperty(LoadingIndicator, "defaultProps", { size: 15, color: '#006CFF' }); /** * LoadingErrorIndicator - UI component for error indicator in Channel. * * @example ./docs/LoadingErrorIndicator.md * @extends PureComponent */ var LoadingErrorIndicator = /*#__PURE__*/ function (_React$PureComponent) { _inherits(LoadingErrorIndicator, _React$PureComponent); function LoadingErrorIndicator() { _classCallCheck(this, LoadingErrorIndicator); return _possibleConstructorReturn(this, _getPrototypeOf(LoadingErrorIndicator).apply(this, arguments)); } _createClass(LoadingErrorIndicator, [{ key: "render", value: function render() { if (!this.props.error) return null; return React__default.createElement("div", null, "Error: ", this.props.error.message); } }]); return LoadingErrorIndicator; }(React__default.PureComponent); _defineProperty(LoadingErrorIndicator, "propTypes", { /** Error object */ error: PropTypes.oneOfType([PropTypes.shape({ message: PropTypes.string }), PropTypes.bool]) }); _defineProperty(LoadingErrorIndicator, "defaultProps", { error: false }); function ownKeys$1(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$1(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$1(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } var emojiSetDef = { spriteUrl: 'https://getstream.imgix.net/images/emoji-sprite.png', size: 20, sheetColumns: 2, sheetRows: 3, sheetSize: 64 }; var commonEmoji = { emoticons: [], short_names: [], custom: true }; var defaultMinimalEmojis = [_objectSpread$1({ id: 'like', name: 'like', colons: ':+1:', sheet_x: 0, sheet_y: 0 }, commonEmoji, {}, emojiSetDef), _objectSpread$1({ id: 'love', name: 'love', colons: ':heart:', sheet_x: 1, sheet_y: 2 }, commonEmoji, {}, emojiSetDef), _objectSpread$1({ id: 'haha', name: 'haha', colons: ':joy:', sheet_x: 1, sheet_y: 0 }, commonEmoji, {}, emojiSetDef), _objectSpread$1({ id: 'wow', name: 'wow', colons: ':astonished:', sheet_x: 0, sheet_y: 2 }, commonEmoji, {}, emojiSetDef), _objectSpread$1({ id: 'sad', name: 'sad', colons: ':pensive:', sheet_x: 0, sheet_y: 1 }, commonEmoji, {}, emojiSetDef), _objectSpread$1({ id: 'angry', name: 'angry', colons: ':angry:', sheet_x: 1, sheet_y: 1 }, commonEmoji, {}, emojiSetDef)]; var d = Object.assign({}, data); d.emojis = {}; // use this only for small lists like in ReactionSelector var emojiData = d; var isOnlyEmojis = function isOnlyEmojis(text) { if (!text) return false; var noEmojis = text.replace(emojiRegex(), ''); var noSpace = noEmojis.replace(/[\s\n]/gm, ''); return !noSpace; }; var isPromise = function isPromise(thing) { return thing && typeof thing.then === 'function'; }; var byDate = function byDate(a, b) { return a.created_at - b.created_at; }; // https://stackoverflow.com/a/29234240/7625485 var formatArray = function formatArray(dict) { var arr2 = Object.keys(dict); var arr3 = []; arr2.forEach(function (item, i) { return arr3.push(dict[arr2[i]].user.name || dict[arr2[i]].user.id); }); var outStr = ''; if (arr3.length === 1) { outStr = arr3[0] + ' is typing...'; } else if (arr3.length === 2) { //joins all with "and" but =no commas //example: "bob and sam" outStr = arr3.join(' and ') + ' are typing...'; } else if (arr3.length > 2) { //joins all with commas, but last one gets ", and" (oxford comma!) //example: "bob, joe, and sam" outStr = arr3.slice(0, -1).join(', ') + ', and ' + arr3.slice(-1) + ' are typing...'; } return outStr; }; var renderText = function renderText(message) { // take the @ mentions and turn them into markdown? // translate links var text = message.text; var mentioned_users = message.mentioned_users; if (!text) { return; } var allowed = ['html', 'root', 'text', 'break', 'paragraph', 'emphasis', 'strong', 'link', 'list', 'listItem', 'code', 'inlineCode', 'blockquote']; var urls = anchorme(text, { list: true }); var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = urls[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var urlInfo = _step.value; var displayLink = truncate(urlInfo.encoded.replace(/^(www\.)/, ''), { length: 20, omission: '...' }); var _mkdown = "[".concat(displayLink, "](").concat(urlInfo.protocol).concat(urlInfo.encoded, ")"); text = text.replace(urlInfo.raw, _mkdown); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return != null) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } var newText = text; if (mentioned_users && mentioned_users.length) { for (var i = 0; i < mentioned_users.length; i++) { var username = mentioned_users[i].name || mentioned_users[i].id; var mkdown = "**@".concat(username, "**"); var re = new RegExp("@".concat(username), 'g'); newText = newText.replace(re, mkdown); } } return React__default.createElement(ReactMarkdown, { allowedTypes: allowed, source: newText, linkTarget: "_blank", plugins: [], escapeHtml: true, skipHtml: false }); }; // https://stackoverflow.com/a/6860916/2570866 function generateRandomId() { // prettier-ignore return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4(); } function S4() { return ((1 + Math.random()) * 0x10000 | 0).toString(16).substring(1); } var smartRender = function smartRender(ElementOrComponentOrLiteral, props, fallback) { if (ElementOrComponentOrLiteral === undefined) { ElementOrComponentOrLiteral = fallback; } if (React__default.isValidElement(ElementOrComponentOrLiteral)) { // Flow cast through any, to make flow believe it's a React.Element var element = ElementOrComponentOrLiteral; // eslint-disable-line return element; } // Flow cast through any to remove React.Element after previous check var ComponentOrLiteral = ElementOrComponentOrLiteral; if (typeof ComponentOrLiteral === 'string' || typeof ComponentOrLiteral === 'number' || typeof ComponentOrLiteral === 'boolean' || ComponentOrLiteral == null) { return ComponentOrLiteral; } return React__default.createElement(ComponentOrLiteral, props); }; var MESSAGE_ACTIONS = { edit: 'edit', delete: 'delete', flag: 'flag', mute: 'mute' }; /** * MessageActionsBox - A component for taking action on a message * * @example ./docs/MessageActionsBox.md * @extends PureComponent */ var MessageActionsBox = /*#__PURE__*/ function (_React$Component) { _inherits(MessageActionsBox, _React$Component); function MessageActionsBox() { var _getPrototypeOf2; var _this; _classCallCheck(this, MessageActionsBox); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(MessageActionsBox)).call.apply(_getPrototypeOf2, [this].concat(args))); _defineProperty(_assertThisInitialized(_this), "actionsBoxRef", React__default.createRef()); _defineProperty(_assertThisInitialized(_this), "state", { reverse: false, rect: null }); return _this; } _createClass(MessageActionsBox, [{ key: "componentDidMount", value: function componentDidMount() {} }, { key: "componentDidUpdate", value: function () { var _componentDidUpdate = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee(prevProps) { var ml; return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: if (!(!prevProps.open && this.props.open)) { _context.next = 6; break; } if (!(this.state.rect === null)) { _context.next = 4; break; } _context.next = 4; return this.setState({ rect: this.actionsBoxRef.current.getBoundingClientRect() }); case 4: ml = this.props.messageListRect; if (this.props.mine) { this.setState({ reverse: this.state.rect.left < ml.left ? true : false }); } else if (!this.props.mine) { this.setState({ reverse: this.state.rect.right + 5 > ml.right ? true : false }); } case 6: case "end": return _context.stop(); } } }, _callee, this); })); function componentDidUpdate(_x) { return _componentDidUpdate.apply(this, arguments); } return componentDidUpdate; }() }, { key: "render", value: function render() { var _this$props = this.props, handleFlag = _this$props.handleFlag, handleMute = _this$props.handleMute, handleEdit = _this$props.handleEdit, handleDelete = _this$props.handleDelete, getMessageActions = _this$props.getMessageActions; var messageActions = getMessageActions(); return React__default.createElement("div", { className: "str-chat__message-actions-box\n ".concat(this.props.open ? 'str-chat__message-actions-box--open' : '', "\n ").concat(this.props.mine ? 'str-chat__message-actions-box--mine' : '', "\n ").concat(this.state.reverse ? 'str-chat__message-actions-box--reverse' : '', "\n "), ref: this.actionsBoxRef }, React__default.createElement("ul", { className: "str-chat__message-actions-list" }, messageActions.indexOf(MESSAGE_ACTIONS.flag) > -1 && React__default.createElement("button", { onClick: handleFlag }, React__default.createElement("li", { className: "str-chat__message-actions-list-item" }, "Flag")), messageActions.indexOf(MESSAGE_ACTIONS.mute) > -1 && React__default.createElement("button", { onClick: handleMute }, React__default.createElement("li", { className: "str-chat__message-actions-list-item" }, "Mute")), messageActions.indexOf(MESSAGE_ACTIONS.edit) > -1 && React__default.createElement("button", { onClick: handleEdit }, React__default.createElement("li", { className: "str-chat__message-actions-list-item" }, "Edit Message")), messageActions.indexOf(MESSAGE_ACTIONS.delete) > -1 && React__default.createElement("button", { onClick: handleDelete }, React__default.createElement("li", { className: "str-chat__message-actions-list-item" }, "Delete")))); } }]); return MessageActionsBox; }(React__default.Component); _defineProperty(MessageActionsBox, "propTypes", { /** If the message actions box should be open or not */ open: PropTypes.bool.isRequired, /** * @deprecated * * The message component, most logic is delegated to this component and MessageActionsBox uses the following functions explicitly: * `handleFlag`, `handleMute`, `handleEdit`, `handleDelete`, `canDeleteMessage`, `canEditMessage`, `isMyMessage`, `isAdmin` */ Message: PropTypes.oneOfType([PropTypes.node, PropTypes.func, PropTypes.object]).isRequired, /** If message belongs to current user. */ mine: PropTypes.bool, /** DOMRect object for parent MessageList component */ messageListRect: PropTypes.object, /** * Handler for flaging a current message * * @param event React's MouseEventHandler event * @returns void * */ handleFlag: PropTypes.func, /** * Handler for muting a current message * * @param event React's MouseEventHandler event * @returns void * */ handleMute: PropTypes.func, /** * Handler for editing a current message * * @param event React's MouseEventHandler event * @returns void * */ handleEdit: PropTypes.func, /** * Handler for deleting a current message * * @param event React's MouseEventHandler event * @returns void * */ handleDelete: PropTypes.func, /** * Returns array of avalable message actions for current message. * Please check [Message](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Message.js) component for default implementation. */ getMessageActions: PropTypes.func }); _defineProperty(MessageActionsBox, "defaultProps", { open: false }); function ownKeys$2(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread$2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys$2(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys$2(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } var ReactionsList = /*#__PURE__*/ function (_React$Component) { _inherits(ReactionsList, _React$Component); function ReactionsList(props) { var _this; _classCallCheck(this, ReactionsList); _this = _possibleConstructorReturn(this, _getPrototypeOf(ReactionsList).call(this, props)); _defineProperty(_assertThisInitialized(_this), "_renderReactions", function (reactions) { var reactionsByType = {}; reactions.map(function (item) { if (reactions[item.type] === undefined) { return reactionsByType[item.type] = [item]; } else { return reactionsByType[item.type] = [].concat(_toConsumableArray(reactionsByType[item.type]), [item]); } }); var reactionsEmojis = _this.props.reactionOptions.reduce(function (acc, cur) { return _objectSpread$2({}, acc, _defineProperty({}, cur.id, cur)); }, {}); return Object.keys(reactionsByType).map(function (type) { return reactionsEmojis[type] ? React__default.createElement("li", { key: reactionsEmojis[type].id }, React__default.createElement(emojiMart.NimbleEmoji, _extends({ emoji: reactionsEmojis[type] }, emojiSetDef, { size: 16, data: emojiData })), ' ', "\xA0") : null; }); }); _defineProperty(_assertThisInitialized(_this), "_getReactionCount", function () { var reaction_counts = _this.props.reaction_counts; var count = null; if (reaction_counts !== null && reaction_counts !== undefined && Object.keys(reaction_counts).length > 0) { count = 0; Object.keys(reaction_counts).map(function (key) { return count += reaction_counts[key]; }); } return count; }); return _this; } _createClass(ReactionsList, [{ key: "render", value: function render() { return React__default.createElement("div", { className: "str-chat__reaction-list ".concat(this.props.reverse ? 'str-chat__reaction-list--reverse' : ''), onClick: this.props.onClick, ref: this.reactionList }, React__default.createElement("ul", null, this._renderReactions(this.props.reactions), React__default.createElement("li", null, React__default.createElement("span", { className: "str-chat__reaction-list--counter" }, this._getReactionCount())))); } }]); return ReactionsList; }(React__default.Component); _defineProperty(ReactionsList, "propTypes", { /*