diff --git a/client/components/MarkdownText.js b/client/components/MarkdownText.js
deleted file mode 100644
index 76e724a659cb7..0000000000000
--- a/client/components/MarkdownText.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import { Box } from '@rocket.chat/fuselage';
-import React, { useMemo } from 'react';
-import marked from 'marked';
-import dompurify from 'dompurify';
-
-const renderer = new marked.Renderer();
-
-marked.InlineLexer.rules.gfm.strong = /^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/;
-marked.InlineLexer.rules.gfm.em = /^__(?=\S)([\s\S]*?\S)__(?!_)|^_(?=\S)([\s\S]*?\S)_(?!_)/;
-
-const linkRenderer = renderer.link;
-renderer.link = function(href, title, text) {
- const html = linkRenderer.call(renderer, href, title, text);
- return html.replace(/^ {
- const html = content && typeof content === 'string' && marked(content, options);
- return preserveHtml ? html : html && sanitizer(html, { ADD_ATTR: ['target'] });
- }, [content, preserveHtml, sanitizer]);
- return __html ? : null;
-}
-
-export default MarkdownText;
diff --git a/client/components/MarkdownText.tsx b/client/components/MarkdownText.tsx
new file mode 100644
index 0000000000000..0308b2d37261c
--- /dev/null
+++ b/client/components/MarkdownText.tsx
@@ -0,0 +1,96 @@
+import { Box } from '@rocket.chat/fuselage';
+import React, { FC, useMemo } from 'react';
+import marked from 'marked';
+import dompurify from 'dompurify';
+
+type MarkdownTextParams = {
+ content: string;
+ variant: 'inline' | 'inlineWithoutBreaks' | 'document';
+ preserveHtml: boolean;
+ withTruncatedText: boolean;
+};
+
+const documentRenderer = new marked.Renderer();
+const inlineRenderer = new marked.Renderer();
+const inlineWithoutBreaks = new marked.Renderer();
+
+marked.InlineLexer.rules.gfm = {
+ ...marked.InlineLexer.rules.gfm,
+ strong: /^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,
+ em: /^__(?=\S)([\s\S]*?\S)__(?!_)|^_(?=\S)([\s\S]*?\S)_(?!_)/,
+};
+
+const linkMarked = (href: string | null, _title: string | null, text: string): string =>
+ `${ text } `;
+const paragraphMarked = (text: string): string => text;
+const brMarked = (): string => ' ';
+const listItemMarked = (text: string): string => {
+ const cleanText = text.replace(/
|<\/p>/ig, '');
+ return `${ cleanText }`;
+};
+
+documentRenderer.link = linkMarked;
+documentRenderer.listitem = listItemMarked;
+
+inlineRenderer.link = linkMarked;
+inlineRenderer.paragraph = paragraphMarked;
+inlineRenderer.listitem = listItemMarked;
+
+inlineWithoutBreaks.link = linkMarked;
+inlineWithoutBreaks.paragraph = paragraphMarked;
+inlineWithoutBreaks.br = brMarked;
+inlineWithoutBreaks.listitem = listItemMarked;
+
+const defaultOptions = {
+ gfm: true,
+ headerIds: false,
+};
+
+const options = {
+ ...defaultOptions,
+ renderer: documentRenderer,
+};
+
+const inlineOptions = {
+ ...defaultOptions,
+ renderer: inlineRenderer,
+};
+
+const inlineWithoutBreaksOptions = {
+ ...defaultOptions,
+ renderer: inlineWithoutBreaks,
+};
+
+const MarkdownText: FC> = ({
+ content,
+ variant = 'document',
+ withTruncatedText = false,
+ preserveHtml = false,
+ ...props
+}) => {
+ const sanitizer = dompurify.sanitize;
+
+ let markedOptions: {};
+
+ const withRichContent = variant;
+ switch (variant) {
+ case 'inline':
+ markedOptions = inlineOptions;
+ break;
+ case 'inlineWithoutBreaks':
+ markedOptions = inlineWithoutBreaksOptions;
+ break;
+ case 'document':
+ default:
+ markedOptions = options;
+ }
+
+ const __html = useMemo(() => {
+ const html = content && typeof content === 'string' && marked(content, markedOptions);
+ return preserveHtml ? html : html && sanitizer(html, { ADD_ATTR: ['target'] });
+ }, [content, preserveHtml, sanitizer, markedOptions]);
+
+ return __html ? : null;
+};
+
+export default MarkdownText;
diff --git a/client/components/Message/Attachments/DefaultAttachment.tsx b/client/components/Message/Attachments/DefaultAttachment.tsx
index 0584770f7a6a1..fa3fb03a3d97c 100644
--- a/client/components/Message/Attachments/DefaultAttachment.tsx
+++ b/client/components/Message/Attachments/DefaultAttachment.tsx
@@ -42,7 +42,7 @@ export type DefaultAttachmentProps = {
const isActionAttachment = (attachment: AttachmentProps): attachment is ActionAttachmentProps => 'actions' in attachment;
-const applyMarkdownIfRequires = (list: DefaultAttachmentProps['mrkdwn_in'] = ['text', 'pretext']) => (key: MarkdownFields, text: string): JSX.Element | string => (list?.includes(key) ? : text);
+const applyMarkdownIfRequires = (list: DefaultAttachmentProps['mrkdwn_in'] = ['text', 'pretext']) => (key: MarkdownFields, text: string): JSX.Element | string => (list?.includes(key) ? : text);
export const DefaultAttachment: FC = (attachment) => {
const applyMardownFor = applyMarkdownIfRequires(attachment.mrkdwn_in);
@@ -57,7 +57,7 @@ export const DefaultAttachment: FC = (attachment) => {
{!collapsed && <>
{attachment.text && {applyMardownFor('text', attachment.text)}}
{/* {attachment.fields && ({ ...rest, value: })) : attachment.fields} />} */}
- {attachment.fields && ({ ...rest, value: }))} />}
+ {attachment.fields && ({ ...rest, value: }))} />}
{attachment.image_url && }
{/* DEPRECATED */}
{isActionAttachment(attachment) && }
diff --git a/client/components/Message/Attachments/Files/GenericFileAttachment.tsx b/client/components/Message/Attachments/Files/GenericFileAttachment.tsx
index 77636b0fd6fbb..7c6a336ac77f1 100644
--- a/client/components/Message/Attachments/Files/GenericFileAttachment.tsx
+++ b/client/components/Message/Attachments/Files/GenericFileAttachment.tsx
@@ -24,7 +24,7 @@ export const GenericFileAttachment: FC = ({
// const [collapsed, collapse] = useCollapse(collapsedDefault);
const getURL = useMediaUrl();
return
- { description && }
+ { description && }
{ hasDownload && link ? : {title} }
{size && }
diff --git a/client/components/Message/Attachments/Files/ImageAttachment.tsx b/client/components/Message/Attachments/Files/ImageAttachment.tsx
index 911e9800d34ff..b71366e36bc75 100644
--- a/client/components/Message/Attachments/Files/ImageAttachment.tsx
+++ b/client/components/Message/Attachments/Files/ImageAttachment.tsx
@@ -35,7 +35,7 @@ export const ImageAttachment: FC = ({
const [collapsed, collapse] = useCollapse(collapsedDefault);
const getURL = useMediaUrl();
return
-
+
{title}
{size && }
diff --git a/client/components/Message/Attachments/Files/PDFAttachment.tsx b/client/components/Message/Attachments/Files/PDFAttachment.tsx
index 6dd877b1ac36a..d10480c75ea95 100644
--- a/client/components/Message/Attachments/Files/PDFAttachment.tsx
+++ b/client/components/Message/Attachments/Files/PDFAttachment.tsx
@@ -20,7 +20,7 @@ export const PDFAttachment: FC = ({
const t = useTranslation();
const [collapsed, collapse] = useCollapse(collapsedDefault);
return
-
+
{t('PDF')}
{collapse}
diff --git a/client/components/Message/Attachments/QuoteAttachment.tsx b/client/components/Message/Attachments/QuoteAttachment.tsx
index 09c7585aec8f7..26a7c139870e6 100644
--- a/client/components/Message/Attachments/QuoteAttachment.tsx
+++ b/client/components/Message/Attachments/QuoteAttachment.tsx
@@ -39,7 +39,7 @@ export const QuoteAttachment: FC = ({ author_icon: url, au
{name}
{format(ts)}
-
+
{attachments && }
diff --git a/client/components/UserCard.js b/client/components/UserCard.js
index bc7c2006b27e6..81d7fa5abefef 100644
--- a/client/components/UserCard.js
+++ b/client/components/UserCard.js
@@ -78,7 +78,7 @@ const UserCard = forwardRef(({
{nickname && ({ nickname })}
- { customStatus && {typeof customStatus === 'string' ? : customStatus} }
+ { customStatus && {typeof customStatus === 'string' ? : customStatus} }
{roles}
{localTime}
{ bio && {typeof bio === 'string' ? : bio} }
diff --git a/client/sidebar/header/UserDropdown.js b/client/sidebar/header/UserDropdown.js
index d62ad00bf0741..6d48457e3f9a8 100644
--- a/client/sidebar/header/UserDropdown.js
+++ b/client/sidebar/header/UserDropdown.js
@@ -114,7 +114,7 @@ const UserDropdown = ({ user, onClose }) => {
-
+
diff --git a/client/types/fuselage.d.ts b/client/types/fuselage.d.ts
index 9265b0385189c..ca7c6f6a28b70 100644
--- a/client/types/fuselage.d.ts
+++ b/client/types/fuselage.d.ts
@@ -151,7 +151,7 @@ declare module '@rocket.chat/fuselage' {
elevation?: '0' | '1' | '2';
invisible?: boolean;
- withRichContent?: boolean;
+ withRichContent?: boolean | string;
withTruncatedText?: boolean;
size?: CSSProperties['blockSize'];
minSize?: CSSProperties['blockSize'];
diff --git a/client/views/admin/cloud/CopyStep.tsx b/client/views/admin/cloud/CopyStep.tsx
index b8c07e95a01b1..1382a0a3c7d0f 100644
--- a/client/views/admin/cloud/CopyStep.tsx
+++ b/client/views/admin/cloud/CopyStep.tsx
@@ -74,7 +74,7 @@ const CopyStep: FC = ({ onNextButtonClick }) => {
{t('Copy')}
-
+
diff --git a/client/views/directory/ChannelsTab.js b/client/views/directory/ChannelsTab.js
index 07ed3e447865d..053c5d109e02c 100644
--- a/client/views/directory/ChannelsTab.js
+++ b/client/views/directory/ChannelsTab.js
@@ -78,7 +78,7 @@ function ChannelsTable() {
{fname || name}
- {topic && }
+ {topic && }
diff --git a/client/views/room/Announcement/Announcement.js b/client/views/room/Announcement/Announcement.tsx
similarity index 61%
rename from client/views/room/Announcement/Announcement.js
rename to client/views/room/Announcement/Announcement.tsx
index 7b0acded3f107..7d9ad98cac766 100644
--- a/client/views/room/Announcement/Announcement.js
+++ b/client/views/room/Announcement/Announcement.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { FC } from 'react';
import { Box } from '@rocket.chat/fuselage';
import { css } from '@rocket.chat/css-in-js';
import colors from '@rocket.chat/fuselage-tokens/colors';
@@ -8,7 +8,17 @@ import AnnouncementModal from './AnnouncementModal';
import { useSetModal } from '../../../contexts/ModalContext';
import MarkdownText from '../../../components/MarkdownText';
-export const Announcement = ({ children, onClickOpen }) => {
+type AnnouncementComponentParams = {
+ children: JSX.Element;
+ onClickOpen: (e: React.MouseEvent) => void;
+};
+
+type AnnouncementParams = {
+ announcement: string;
+ announcementDetails: () => void;
+}
+
+export const AnnouncementComponent: FC = ({ children, onClickOpen }) => {
const announcementBar = css`
background-color: ${ colors.b200 };
background-color: var(--rc-color-announcement-background, ${ colors.b200 });
@@ -35,21 +45,22 @@ export const Announcement = ({ children, onClickOpen }) => {
return {children};
};
-export default ({ announcement, announcementDetails }) => {
+const Announcement: FC = ({ announcement, announcementDetails }) => {
const setModal = useSetModal();
- const closeModal = useMutableCallback(() => setModal());
- const handleClick = (e) => {
- if (e.target.href) {
+ const closeModal = useMutableCallback(() => setModal(null));
+ const handleClick = (e: React.MouseEvent): void => {
+ if ((e.target as HTMLAnchorElement).href) {
return;
}
- if (window.getSelection().toString() !== '') {
+ if (window?.getSelection()?.toString() !== '') {
return;
}
announcementDetails ? announcementDetails() : setModal({announcement});
};
- const announcementWithoutBreaks = announcement && announcement.replace(/(\r\n|\n|\r)/gm, ' ');
- return announcementWithoutBreaks ? : false;
+ return announcement ? ): void => handleClick(e)}> : null;
};
+
+export default Announcement;
diff --git a/client/views/room/Announcement/AnnouncementModal.js b/client/views/room/Announcement/AnnouncementModal.tsx
similarity index 69%
rename from client/views/room/Announcement/AnnouncementModal.js
rename to client/views/room/Announcement/AnnouncementModal.tsx
index 596d28804a3e0..98b3a8896d6d8 100644
--- a/client/views/room/Announcement/AnnouncementModal.js
+++ b/client/views/room/Announcement/AnnouncementModal.tsx
@@ -1,10 +1,16 @@
-import React from 'react';
+import React, { FC } from 'react';
import { Button, ButtonGroup, Box, Modal } from '@rocket.chat/fuselage';
import { useTranslation } from '../../../contexts/TranslationContext';
import MarkdownText from '../../../components/MarkdownText';
-export default ({
+type AnnouncementModalParams = {
+ onClose: () => void;
+ confirmLabel?: string;
+ children?: string;
+}
+
+const AnnouncementModal: FC = ({
onClose,
confirmLabel = 'Close',
children,
@@ -19,7 +25,7 @@ export default ({
-
+
@@ -29,3 +35,5 @@ export default ({
);
};
+
+export default AnnouncementModal;
diff --git a/client/views/room/Announcement/index.js b/client/views/room/Announcement/index.tsx
similarity index 100%
rename from client/views/room/Announcement/index.js
rename to client/views/room/Announcement/index.tsx
diff --git a/client/views/room/Header/Header.js b/client/views/room/Header/Header.js
index 9506c239c08d8..f10b67b9fdea7 100644
--- a/client/views/room/Header/Header.js
+++ b/client/views/room/Header/Header.js
@@ -78,7 +78,7 @@ const RoomHeader = ({ room, topic }) => {
- {topic && }
+ {topic && }
diff --git a/client/views/room/contextualBar/UserInfo/index.js b/client/views/room/contextualBar/UserInfo/index.js
index 9a601f4a682ca..0f9645112e234 100644
--- a/client/views/room/contextualBar/UserInfo/index.js
+++ b/client/views/room/contextualBar/UserInfo/index.js
@@ -96,7 +96,7 @@ export const UserInfo = React.memo(function UserInfo({
{bio && <>
-
+
>}
{phone && <>
diff --git a/package-lock.json b/package-lock.json
index e8cea7ac43183..8d37a6a35db52 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5950,12 +5950,13 @@
}
},
"@rocket.chat/fuselage": {
- "version": "0.6.3-dev.179",
- "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage/-/fuselage-0.6.3-dev.179.tgz",
- "integrity": "sha512-z4Wgk8J34NfriXuh00cJ+J3M7h1fxFtG9ily3cKhYIVNPHyhUR4o3h2MbvPKKE+mBPzuLsOV2kbcb49y4gm76g==",
+ "version": "0.6.3-dev.188",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/fuselage/-/fuselage-0.6.3-dev.188.tgz",
+ "integrity": "sha512-a0XGJ4uayUUsdk7r5aAEdaXa5CmT+Wsx5B3rv4GJqOYGq5NEFzGHxssWaRd9PPVWDd/USYALMlOKqJSxKViSlw==",
"requires": {
"@rocket.chat/css-in-js": "^0.21.0",
"@rocket.chat/fuselage-tokens": "^0.21.0",
+ "@rocket.chat/memo": "^0.6.3-dev.180",
"invariant": "^2.2.4",
"react-keyed-flatten-children": "^1.2.0"
},
@@ -6088,6 +6089,11 @@
}
}
},
+ "@rocket.chat/memo": {
+ "version": "0.6.3-dev.180",
+ "resolved": "https://registry.npmjs.org/@rocket.chat/memo/-/memo-0.6.3-dev.180.tgz",
+ "integrity": "sha512-3+zoOZW/f2/cwmjDAh8yXvGQvskopSR/QCAUmatqSAiMztFvkBljlVbSx1YUiq4y5t41dzM5m+MKYRZAEgAtLQ=="
+ },
"@rocket.chat/mp3-encoder": {
"version": "0.6.3-dev.178",
"resolved": "https://registry.npmjs.org/@rocket.chat/mp3-encoder/-/mp3-encoder-0.6.3-dev.178.tgz",
@@ -10580,6 +10586,14 @@
"integrity": "sha512-EGlKlgMhnLt/cM4DbUSafFdrkeJoC9Mvnj0PUCU7tFmTjMjNRT957kXCx0wYm3JuEq4o4ZsS5vG+NlkM2DMd2A==",
"dev": true
},
+ "@types/dompurify": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-2.2.1.tgz",
+ "integrity": "sha512-3JwbEeRVQ3n6+JgBW/hCdkydRk9/vWT+UEglcXEJqLJEcUganDH37zlfLznxPKTZZfDqA9K229l1qN458ubcOQ==",
+ "requires": {
+ "@types/trusted-types": "*"
+ }
+ },
"@types/ejson": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@types/ejson/-/ejson-2.1.2.tgz",
@@ -10813,6 +10827,11 @@
"@types/react": "*"
}
},
+ "@types/marked": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@types/marked/-/marked-1.2.2.tgz",
+ "integrity": "sha512-wLfw1hnuuDYrFz97IzJja0pdVsC0oedtS4QsKH1/inyW9qkLQbXgMUqEQT0MVtUBx3twjWeInUfjQbhBVLECXw=="
+ },
"@types/md5-file": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/md5-file/-/md5-file-4.0.2.tgz",
@@ -11169,6 +11188,11 @@
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz",
"integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A=="
},
+ "@types/trusted-types": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.0.tgz",
+ "integrity": "sha512-I8MnZqNXsOLHsU111oHbn3khtvKMi5Bn4qVFsIWSJcCP1KKDiXX5AEw8UPk0nSopeC+Hvxt6yAy1/a5PailFqg=="
+ },
"@types/uglify-js": {
"version": "3.11.1",
"resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.11.1.tgz",
diff --git a/package.json b/package.json
index d9707cfc8744c..ec4a328e90ca8 100644
--- a/package.json
+++ b/package.json
@@ -137,7 +137,7 @@
"@rocket.chat/apps-engine": "1.23.0-alpha.4655",
"@rocket.chat/css-in-js": "^0.6.3-dev.178",
"@rocket.chat/emitter": "^0.6.3-dev.178",
- "@rocket.chat/fuselage": "^0.6.3-dev.179",
+ "@rocket.chat/fuselage": "^0.6.3-dev.188",
"@rocket.chat/fuselage-hooks": "^0.6.3-dev.178",
"@rocket.chat/fuselage-polyfills": "^0.6.3-dev.181",
"@rocket.chat/fuselage-tokens": "^0.21.0",
@@ -146,9 +146,11 @@
"@rocket.chat/mp3-encoder": "^0.6.3-dev.178",
"@rocket.chat/ui-kit": "^0.6.3-dev.178",
"@slack/client": "^4.12.0",
+ "@types/dompurify": "^2.2.1",
"@types/fibers": "^3.1.0",
"@types/imap": "^0.8.33",
"@types/mailparser": "^3.0.0",
+ "@types/marked": "^1.2.2",
"@types/mkdirp": "^1.0.1",
"@types/nodemailer": "^6.4.0",
"@types/string-strip-html": "^5.0.0",