import React, { useRef } from 'react'; import PropTypes from 'prop-types'; import './Message.scss'; import Linkify from 'linkifyjs/react'; import ReactMarkdown from 'react-markdown'; import gfm from 'remark-gfm'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { coy } from 'react-syntax-highlighter/dist/esm/styles/prism'; import parse from 'html-react-parser'; import twemoji from 'twemoji'; import { getUsername } from '../../../util/matrixUtil'; import Text from '../../atoms/text/Text'; import RawIcon from '../../atoms/system-icons/RawIcon'; import Button from '../../atoms/button/Button'; import Tooltip from '../../atoms/tooltip/Tooltip'; import Input from '../../atoms/input/Input'; import ReplyArrowIC from '../../../../public/res/ic/outlined/reply-arrow.svg'; const components = { code({ // eslint-disable-next-line react/prop-types inline, className, children, }) { const match = /language-(\w+)/.exec(className || ''); return !inline && match ? ( {String(children).replace(/\n$/, '')} ) : ( {String(children)} ); }, }; function linkifyContent(content) { return {content}; } function genMarkdown(content) { return {content}; } function PlaceholderMessage() { return (
); } function MessageHeader({ userId, name, color, time, }) { return (
{name} {userId}
{time}
); } MessageHeader.propTypes = { userId: PropTypes.string.isRequired, name: PropTypes.string.isRequired, color: PropTypes.string.isRequired, time: PropTypes.string.isRequired, }; function MessageReply({ name, color, content }) { return (
{name} <>{` ${content}`}
); } MessageReply.propTypes = { name: PropTypes.string.isRequired, color: PropTypes.string.isRequired, content: PropTypes.string.isRequired, }; function MessageContent({ content, isMarkdown, isEdited }) { return (
{ isMarkdown ? genMarkdown(content) : linkifyContent(content) }
{ isEdited && (edited)}
); } MessageContent.defaultProps = { isMarkdown: false, isEdited: false, }; MessageContent.propTypes = { content: PropTypes.node.isRequired, isMarkdown: PropTypes.bool, isEdited: PropTypes.bool, }; function MessageEdit({ content, onSave, onCancel }) { const editInputRef = useRef(null); return (
{ e.preventDefault(); onSave(editInputRef.current.value); }}>
); } MessageEdit.propTypes = { content: PropTypes.string.isRequired, onSave: PropTypes.func.isRequired, onCancel: PropTypes.func.isRequired, }; function MessageReactionGroup({ children }) { return (
{ children }
); } MessageReactionGroup.propTypes = { children: PropTypes.node.isRequired, }; function genReactionMsg(userIds, reaction) { const genLessContText = (text) => {text}; let msg = <>; userIds.forEach((userId, index) => { if (index === 0) msg = <>{getUsername(userId)}; // eslint-disable-next-line react/jsx-one-expression-per-line else if (index === userIds.length - 1) msg = <>{msg}{genLessContText(' and ')}{getUsername(userId)}; // eslint-disable-next-line react/jsx-one-expression-per-line else msg = <>{msg}{genLessContText(', ')}{getUsername(userId)}; }); return ( <> {msg} {genLessContText(' reacted with')} {parse(twemoji.parse(reaction))} ); } function MessageReaction({ reaction, users, isActive, onClick, }) { return ( {genReactionMsg(users, reaction)}} > ); } MessageReaction.propTypes = { reaction: PropTypes.node.isRequired, users: PropTypes.arrayOf(PropTypes.string).isRequired, isActive: PropTypes.bool.isRequired, onClick: PropTypes.func.isRequired, }; function MessageOptions({ children }) { return (
{children}
); } MessageOptions.propTypes = { children: PropTypes.node.isRequired, }; function Message({ avatar, header, reply, content, editContent, reactions, options, }) { const msgClass = header === null ? ' message--content-only' : ' message--full'; return (
{avatar !== null && avatar}
{header !== null && header} {reply !== null && reply} {content !== null && content} {editContent !== null && editContent} {reactions !== null && reactions} {options !== null && options}
); } Message.defaultProps = { avatar: null, header: null, reply: null, content: null, editContent: null, reactions: null, options: null, }; Message.propTypes = { avatar: PropTypes.node, header: PropTypes.node, reply: PropTypes.node, content: PropTypes.node, editContent: PropTypes.node, reactions: PropTypes.node, options: PropTypes.node, }; export { Message, MessageHeader, MessageReply, MessageContent, MessageEdit, MessageReactionGroup, MessageReaction, MessageOptions, PlaceholderMessage, };