xom-stream-chat-react
Version:
React components to create chat conversations or livestream style chat
1,428 lines (1,212 loc) • 473 kB
JavaScript
'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", {
/*