diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap
index 8b5073224..ae596da06 100644
--- a/__tests__/__snapshots__/Storyshots.test.js.snap
+++ b/__tests__/__snapshots__/Storyshots.test.js.snap
@@ -15665,7 +15665,10 @@ exports[`Storyshots Markdown Code 1`] = `
"borderWidth": 1,
"color": "#2f343d",
"fontFamily": "Courier New",
+ "fontSize": 16,
"fontWeight": "400",
+ "paddingLeft": 2,
+ "paddingTop": 2,
"textAlign": "left",
},
]
@@ -15728,7 +15731,10 @@ exports[`Storyshots Markdown Code 1`] = `
"borderWidth": 1,
"color": "#2f343d",
"fontFamily": "Courier New",
+ "fontSize": 16,
"fontWeight": "400",
+ "paddingLeft": 2,
+ "paddingTop": 2,
"textAlign": "left",
},
]
@@ -15773,7 +15779,10 @@ exports[`Storyshots Markdown Code 1`] = `
"borderWidth": 1,
"color": "#2f343d",
"fontFamily": "Courier New",
+ "fontSize": 16,
"fontWeight": "400",
+ "paddingLeft": 2,
+ "paddingTop": 2,
"textAlign": "left",
},
]
@@ -15819,6 +15828,7 @@ exports[`Storyshots Markdown Code 1`] = `
"borderWidth": 1,
"color": "#2f343d",
"fontFamily": "Courier New",
+ "fontSize": 16,
"fontWeight": "400",
"padding": 4,
"textAlign": "left",
@@ -16881,7 +16891,10 @@ exports[`Storyshots Markdown Links 1`] = `
"borderWidth": 1,
"color": "#2f343d",
"fontFamily": "Courier New",
+ "fontSize": 16,
"fontWeight": "400",
+ "paddingLeft": 2,
+ "paddingTop": 2,
"textAlign": "left",
},
]
@@ -16993,7 +17006,10 @@ exports[`Storyshots Markdown Links 1`] = `
"borderWidth": 1,
"color": "#2f343d",
"fontFamily": "Courier New",
+ "fontSize": 16,
"fontWeight": "400",
+ "paddingLeft": 2,
+ "paddingTop": 2,
"textAlign": "left",
},
]
@@ -50287,6 +50303,1370 @@ exports[`Storyshots Message Without header 1`] = `
`;
+exports[`Storyshots NewMarkdown Block quote 1`] = `
+
+
+
+
+
+
+ Rocket.Chat to the moon
+
+
+
+
+
+`;
+
+exports[`Storyshots NewMarkdown Code 1`] = `
+
+
+
+
+ inline code
+
+
+
+
+
+ Multi line
+
+
+ Code
+
+
+
+`;
+
+exports[`Storyshots NewMarkdown Emoji 1`] = `
+
+
+
+ 💚
+
+
+ 😂
+
+
+ 😁
+
+
+
+
+ 🚀
+
+
+ 🤦
+
+
+
+
+
+
+
+
+
+`;
+
+exports[`Storyshots NewMarkdown Hashtag 1`] = `
+
+
+
+ #text_channel
+
+
+ and
+
+
+ #not_a_channel
+
+
+
+`;
+
+exports[`Storyshots NewMarkdown Headers 1`] = `
+
+
+ # Header 1
+
+
+ ## Header 2
+
+
+ ### Header 3
+
+
+ #### Header 4
+
+
+ ##### Header 5
+
+
+ ###### Header 6
+
+
+`;
+
+exports[`Storyshots NewMarkdown Links 1`] = `
+
+
+
+ https://rocket.chat
+
+
+
+
+ Markdown link
+
+
+
+`;
+
+exports[`Storyshots NewMarkdown Lists 1`] = `
+
+
+
+
+ -
+
+
+ Open Source
+
+
+
+
+ -
+
+
+ Rocket.Chat
+
+
+
+
+
+
+ 1
+ .
+
+
+ Open Source
+
+
+
+
+ 2
+ .
+
+
+ Rocket.Chat
+
+
+
+
+`;
+
+exports[`Storyshots NewMarkdown Mentions 1`] = `
+
+
+
+ rocket.cat
+
+
+
+
+ name
+
+
+
+
+
+ rocket.cat
+
+
+
+
+
+ here
+
+
+
+
+
+ all
+
+
+
+`;
+
+exports[`Storyshots NewMarkdown Text 1`] = `
+
+
+
+ This is Rocket.Chat
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+
+
+
+ a
+
+
+ b
+
+
+ c
+
+
+
+
+
+ d
+
+
+
+
+
+
+
+
+ e
+
+
+
+
+ a b c
+
+
+
+
+
+ This is bold
+
+
+
+ and
+
+
+
+ this is italic
+
+
+
+
+`;
+
exports[`Storyshots Room Item Alerts 1`] = `
{
+const AtMention = React.memo(({ mention, mentions, username, navToRoomInfo, style = [], useRealName }: IAtMention) => {
+ const { theme } = useTheme();
if (mention === 'all' || mention === 'here') {
return (
@@ -34,11 +35,11 @@ const AtMention = React.memo(({ mention, mentions, username, navToRoomInfo, styl
let mentionStyle = {};
if (mention === username) {
mentionStyle = {
- color: themes[theme].mentionMeColor
+ color: themes[theme!].mentionMeColor
};
} else {
mentionStyle = {
- color: themes[theme].mentionOtherColor
+ color: themes[theme!].mentionOtherColor
};
}
@@ -61,7 +62,7 @@ const AtMention = React.memo(({ mention, mentions, username, navToRoomInfo, styl
);
}
- return {`@${mention}`};
+ return {`@${mention}`};
});
export default AtMention;
diff --git a/app/containers/markdown/Hashtag.tsx b/app/containers/markdown/Hashtag.tsx
index 872b8782a..b20794de5 100644
--- a/app/containers/markdown/Hashtag.tsx
+++ b/app/containers/markdown/Hashtag.tsx
@@ -1,23 +1,26 @@
import React from 'react';
-import { Text } from 'react-native';
+import { Text, TextStyle } from 'react-native';
import { themes } from '../../constants/colors';
+import { useTheme } from '../../theme';
import styles from './styles';
interface IHashtag {
hashtag: string;
navToRoomInfo: Function;
- style: [];
- theme: string;
+ style?: TextStyle[];
channels: {
+ [index: number]: string | number;
name: string;
_id: number;
}[];
}
-const Hashtag = React.memo(({ hashtag, channels, navToRoomInfo, style = [], theme }: IHashtag) => {
+const Hashtag = React.memo(({ hashtag, channels, navToRoomInfo, style = [] }: IHashtag) => {
+ const { theme } = useTheme();
+
const handlePress = () => {
- const index = channels.findIndex(channel => channel.name === hashtag);
+ const index = channels?.findIndex(channel => channel.name === hashtag);
const navParam = {
t: 'c',
rid: channels[index]._id
@@ -31,7 +34,7 @@ const Hashtag = React.memo(({ hashtag, channels, navToRoomInfo, style = [], them
style={[
styles.mention,
{
- color: themes[theme].mentionOtherColor
+ color: themes[theme!].mentionOtherColor
},
...style
]}
@@ -40,7 +43,7 @@ const Hashtag = React.memo(({ hashtag, channels, navToRoomInfo, style = [], them
);
}
- return {`#${hashtag}`};
+ return {`#${hashtag}`};
});
export default Hashtag;
diff --git a/app/containers/markdown/index.tsx b/app/containers/markdown/index.tsx
index d3ce8453e..d84dc7dc8 100644
--- a/app/containers/markdown/index.tsx
+++ b/app/containers/markdown/index.tsx
@@ -3,6 +3,7 @@ import { Image, Text } from 'react-native';
import { Node, Parser } from 'commonmark';
import Renderer from 'commonmark-react-renderer';
import removeMarkdown from 'remove-markdown';
+import { MarkdownAST } from '@rocket.chat/message-parser';
import shortnameToUnicode from '../../utils/shortnameToUnicode';
import I18n from '../../i18n';
@@ -20,9 +21,20 @@ import MarkdownTableCell from './TableCell';
import mergeTextNodes from './mergeTextNodes';
import styles from './styles';
import { isValidURL } from '../../utils/url';
+import NewMarkdown from './new';
+
+interface IUser {
+ _id: string;
+ username: string;
+ name: string;
+}
+
+type UserMention = Pick;
interface IMarkdownProps {
msg: string;
+ md: MarkdownAST;
+ mentions: UserMention[];
getCustomEmoji: Function;
baseUrl: string;
username: string;
@@ -35,7 +47,7 @@ interface IMarkdownProps {
name: string;
_id: number;
}[];
- mentions: object[];
+ enableMessageParser: boolean;
navToRoomInfo: Function;
preview: boolean;
theme: string;
@@ -97,7 +109,9 @@ class Markdown extends PureComponent {
constructor(props: IMarkdownProps) {
super(props);
- this.renderer = this.createRenderer();
+ if (!this.isNewMarkdown) {
+ this.renderer = this.createRenderer();
+ }
}
createRenderer = () =>
@@ -139,6 +153,11 @@ class Markdown extends PureComponent {
renderParagraphsInLists: true
});
+ get isNewMarkdown(): boolean {
+ const { md, enableMessageParser } = this.props;
+ return enableMessageParser && !!md;
+ }
+
editedMessage = (ast: any) => {
const { isEdited } = this.props;
if (isEdited) {
@@ -227,12 +246,12 @@ class Markdown extends PureComponent {
};
renderHashtag = ({ hashtag }: { hashtag: string }) => {
- const { channels, navToRoomInfo, style, theme } = this.props;
- return ;
+ const { channels, navToRoomInfo, style } = this.props;
+ return ;
};
renderAtMention = ({ mentionName }: { mentionName: string }) => {
- const { username, mentions, navToRoomInfo, useRealName, style, theme } = this.props;
+ const { username, mentions, navToRoomInfo, useRealName, style } = this.props;
return (
{
useRealName={useRealName}
username={username}
navToRoomInfo={navToRoomInfo}
- theme={theme}
style={style}
/>
);
@@ -329,12 +347,44 @@ class Markdown extends PureComponent {
};
render() {
- const { msg, numberOfLines, preview = false, theme, style = [], testID } = this.props;
+ const {
+ msg,
+ md,
+ numberOfLines,
+ preview = false,
+ theme,
+ style = [],
+ testID,
+ mentions,
+ channels,
+ navToRoomInfo,
+ useRealName,
+ username,
+ getCustomEmoji,
+ baseUrl,
+ onLinkPress
+ } = this.props;
if (!msg) {
return null;
}
+ if (this.isNewMarkdown) {
+ return (
+
+ );
+ }
+
let m = formatText(msg);
// Ex: '[ ](https://open.rocket.chat/group/test?msg=abcdef) Test'
diff --git a/app/containers/markdown/new/BigEmoji.tsx b/app/containers/markdown/new/BigEmoji.tsx
new file mode 100644
index 000000000..c8f6a3beb
--- /dev/null
+++ b/app/containers/markdown/new/BigEmoji.tsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import { StyleSheet, View } from 'react-native';
+import { BigEmoji as BigEmojiProps } from '@rocket.chat/message-parser';
+
+import Emoji from './Emoji';
+
+interface IBigEmojiProps {
+ value: BigEmojiProps['value'];
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flexDirection: 'row'
+ }
+});
+
+const BigEmoji = ({ value }: IBigEmojiProps): JSX.Element => (
+
+ {value.map(block => (
+
+ ))}
+
+);
+
+export default BigEmoji;
diff --git a/app/containers/markdown/new/Bold.tsx b/app/containers/markdown/new/Bold.tsx
new file mode 100644
index 000000000..9cb1f4fdb
--- /dev/null
+++ b/app/containers/markdown/new/Bold.tsx
@@ -0,0 +1,40 @@
+import React from 'react';
+import { StyleSheet, Text } from 'react-native';
+import { Bold as BoldProps } from '@rocket.chat/message-parser';
+
+import sharedStyles from '../../../views/Styles';
+import Strike from './Strike';
+import Italic from './Italic';
+import Plain from './Plain';
+import Link from './Link';
+
+interface IBoldProps {
+ value: BoldProps['value'];
+}
+
+const styles = StyleSheet.create({
+ text: {
+ ...sharedStyles.textBold
+ }
+});
+
+const Bold = ({ value }: IBoldProps): JSX.Element => (
+
+ {value.map(block => {
+ switch (block.type) {
+ case 'LINK':
+ return ;
+ case 'PLAIN_TEXT':
+ return ;
+ case 'STRIKE':
+ return ;
+ case 'ITALIC':
+ return ;
+ default:
+ return null;
+ }
+ })}
+
+);
+
+export default Bold;
diff --git a/app/containers/markdown/new/Code.tsx b/app/containers/markdown/new/Code.tsx
new file mode 100644
index 000000000..d2a164367
--- /dev/null
+++ b/app/containers/markdown/new/Code.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import { Text } from 'react-native';
+import { Code as CodeProps } from '@rocket.chat/message-parser';
+
+import styles from '../styles';
+import { themes } from '../../../constants/colors';
+import { useTheme } from '../../../theme';
+import CodeLine from './CodeLine';
+
+interface ICodeProps {
+ value: CodeProps['value'];
+}
+
+const Code = ({ value }: ICodeProps): JSX.Element => {
+ const { theme } = useTheme();
+
+ return (
+
+ {value.map(block => {
+ switch (block.type) {
+ case 'CODE_LINE':
+ return ;
+ default:
+ return null;
+ }
+ })}
+
+ );
+};
+
+export default Code;
diff --git a/app/containers/markdown/new/CodeLine.tsx b/app/containers/markdown/new/CodeLine.tsx
new file mode 100644
index 000000000..c05066f9c
--- /dev/null
+++ b/app/containers/markdown/new/CodeLine.tsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import { Text } from 'react-native';
+import { CodeLine as CodeLineProps } from '@rocket.chat/message-parser';
+
+interface ICodeLineProps {
+ value: CodeLineProps['value'];
+}
+
+const CodeLine = ({ value }: ICodeLineProps): JSX.Element | null => {
+ if (value.type !== 'PLAIN_TEXT') {
+ return null;
+ }
+
+ return {value.value};
+};
+
+export default CodeLine;
diff --git a/app/containers/markdown/new/Emoji.tsx b/app/containers/markdown/new/Emoji.tsx
new file mode 100644
index 000000000..0800b8874
--- /dev/null
+++ b/app/containers/markdown/new/Emoji.tsx
@@ -0,0 +1,29 @@
+import React, { useContext } from 'react';
+import { Text } from 'react-native';
+import { Emoji as EmojiProps } from '@rocket.chat/message-parser';
+
+import shortnameToUnicode from '../../../utils/shortnameToUnicode';
+import { themes } from '../../../constants/colors';
+import { useTheme } from '../../../theme';
+import styles from '../styles';
+import CustomEmoji from '../../EmojiPicker/CustomEmoji';
+import MarkdownContext from './MarkdownContext';
+
+interface IEmojiProps {
+ value: EmojiProps['value'];
+ isBigEmoji?: boolean;
+}
+
+const Emoji = ({ value, isBigEmoji }: IEmojiProps): JSX.Element => {
+ const { theme } = useTheme();
+ const { baseUrl, getCustomEmoji } = useContext(MarkdownContext);
+ const emojiUnicode = shortnameToUnicode(`:${value.value}:`);
+ const emoji = getCustomEmoji?.(value.value);
+
+ if (emoji) {
+ return ;
+ }
+ return {emojiUnicode};
+};
+
+export default Emoji;
diff --git a/app/containers/markdown/new/Heading.tsx b/app/containers/markdown/new/Heading.tsx
new file mode 100644
index 000000000..2e810d376
--- /dev/null
+++ b/app/containers/markdown/new/Heading.tsx
@@ -0,0 +1,32 @@
+import React from 'react';
+import { Text } from 'react-native';
+import { Heading as HeadingProps } from '@rocket.chat/message-parser';
+
+import { themes } from '../../../constants/colors';
+import styles from '../styles';
+import { useTheme } from '../../../theme';
+
+interface IHeadingProps {
+ value: HeadingProps['value'];
+ level: HeadingProps['level'];
+}
+
+const Heading = ({ value, level }: IHeadingProps): JSX.Element => {
+ const { theme } = useTheme();
+ const textStyle = styles[`heading${level}`];
+
+ return (
+
+ {value.map(block => {
+ switch (block.type) {
+ case 'PLAIN_TEXT':
+ return block.value;
+ default:
+ return null;
+ }
+ })}
+
+ );
+};
+
+export default Heading;
diff --git a/app/containers/markdown/new/Image.tsx b/app/containers/markdown/new/Image.tsx
new file mode 100644
index 000000000..fb9f95d28
--- /dev/null
+++ b/app/containers/markdown/new/Image.tsx
@@ -0,0 +1,41 @@
+import React from 'react';
+import { Image as ImageProps } from '@rocket.chat/message-parser';
+import { createImageProgress } from 'react-native-image-progress';
+import * as Progress from 'react-native-progress';
+import FastImage from '@rocket.chat/react-native-fast-image';
+
+import { useTheme } from '../../../theme';
+import { themes } from '../../../constants/colors';
+import styles from '../../message/styles';
+
+interface IImageProps {
+ value: ImageProps['value'];
+}
+
+type TMessageImage = {
+ img: string;
+ theme: string;
+};
+
+const ImageProgress = createImageProgress(FastImage);
+
+const MessageImage = ({ img, theme }: TMessageImage) => (
+
+);
+
+const Image = ({ value }: IImageProps): JSX.Element => {
+ const { theme } = useTheme();
+ const { src } = value;
+
+ return ;
+};
+
+export default Image;
diff --git a/app/containers/markdown/new/Inline.tsx b/app/containers/markdown/new/Inline.tsx
new file mode 100644
index 000000000..08c4b1e5f
--- /dev/null
+++ b/app/containers/markdown/new/Inline.tsx
@@ -0,0 +1,62 @@
+import React, { useContext } from 'react';
+import { Paragraph as ParagraphProps } from '@rocket.chat/message-parser';
+
+import Hashtag from '../Hashtag';
+import AtMention from '../AtMention';
+import Link from './Link';
+import Plain from './Plain';
+import Bold from './Bold';
+import Strike from './Strike';
+import Italic from './Italic';
+import Emoji from './Emoji';
+import InlineCode from './InlineCode';
+import Image from './Image';
+import MarkdownContext from './MarkdownContext';
+
+interface IParagraphProps {
+ value: ParagraphProps['value'];
+}
+
+const Inline = ({ value }: IParagraphProps): JSX.Element => {
+ const { useRealName, username, navToRoomInfo, mentions, channels } = useContext(MarkdownContext);
+ return (
+ <>
+ {value.map(block => {
+ switch (block.type) {
+ case 'IMAGE':
+ return ;
+ case 'PLAIN_TEXT':
+ return ;
+ case 'BOLD':
+ return ;
+ case 'STRIKE':
+ return ;
+ case 'ITALIC':
+ return ;
+ case 'LINK':
+ return ;
+ case 'MENTION_USER':
+ return (
+
+ );
+ case 'EMOJI':
+ return ;
+ case 'MENTION_CHANNEL':
+ return ;
+ case 'INLINE_CODE':
+ return ;
+ default:
+ return null;
+ }
+ })}
+ >
+ );
+};
+
+export default Inline;
diff --git a/app/containers/markdown/new/InlineCode.tsx b/app/containers/markdown/new/InlineCode.tsx
new file mode 100644
index 000000000..cf90f2cb3
--- /dev/null
+++ b/app/containers/markdown/new/InlineCode.tsx
@@ -0,0 +1,38 @@
+import React from 'react';
+import { Text } from 'react-native';
+import { InlineCode as InlineCodeProps } from '@rocket.chat/message-parser';
+
+import styles from '../styles';
+import { themes } from '../../../constants/colors';
+import { useTheme } from '../../../theme';
+
+interface IInlineCodeProps {
+ value: InlineCodeProps['value'];
+}
+
+const InlineCode = ({ value }: IInlineCodeProps): JSX.Element => {
+ const { theme } = useTheme();
+
+ return (
+
+ {(block => {
+ switch (block.type) {
+ case 'PLAIN_TEXT':
+ return {block.value};
+ default:
+ return null;
+ }
+ })(value)}
+
+ );
+};
+
+export default InlineCode;
diff --git a/app/containers/markdown/new/Italic.tsx b/app/containers/markdown/new/Italic.tsx
new file mode 100644
index 000000000..fc1432e5a
--- /dev/null
+++ b/app/containers/markdown/new/Italic.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import { StyleSheet, Text } from 'react-native';
+import { Italic as ItalicProps } from '@rocket.chat/message-parser';
+
+import Strike from './Strike';
+import Bold from './Bold';
+import Plain from './Plain';
+import Link from './Link';
+
+interface IItalicProps {
+ value: ItalicProps['value'];
+}
+
+const styles = StyleSheet.create({
+ text: {
+ fontStyle: 'italic'
+ }
+});
+
+const Italic = ({ value }: IItalicProps): JSX.Element => (
+
+ {value.map(block => {
+ switch (block.type) {
+ case 'LINK':
+ return ;
+ case 'PLAIN_TEXT':
+ return ;
+ case 'STRIKE':
+ return ;
+ case 'BOLD':
+ return ;
+ default:
+ return null;
+ }
+ })}
+
+);
+
+export default Italic;
diff --git a/app/containers/markdown/new/Link.tsx b/app/containers/markdown/new/Link.tsx
new file mode 100644
index 000000000..e29c4f2c0
--- /dev/null
+++ b/app/containers/markdown/new/Link.tsx
@@ -0,0 +1,60 @@
+import React, { useContext } from 'react';
+import { Text, Clipboard } from 'react-native';
+import { Link as LinkProps } from '@rocket.chat/message-parser';
+
+import styles from '../styles';
+import I18n from '../../../i18n';
+import { LISTENER } from '../../Toast';
+import { useTheme } from '../../../theme';
+import openLink from '../../../utils/openLink';
+import EventEmitter from '../../../utils/events';
+import { themes } from '../../../constants/colors';
+import Strike from './Strike';
+import Italic from './Italic';
+import Bold from './Bold';
+import MarkdownContext from './MarkdownContext';
+
+interface ILinkProps {
+ value: LinkProps['value'];
+}
+
+const Link = ({ value }: ILinkProps): JSX.Element => {
+ const { theme } = useTheme();
+ const { onLinkPress } = useContext(MarkdownContext);
+ const { src, label } = value;
+ const handlePress = () => {
+ if (!src.value) {
+ return;
+ }
+ if (onLinkPress) {
+ return onLinkPress(src.value);
+ }
+ openLink(src.value, theme);
+ };
+
+ const onLongPress = () => {
+ Clipboard.setString(src.value);
+ EventEmitter.emit(LISTENER, { message: I18n.t('Copied_to_clipboard') });
+ };
+
+ return (
+
+ {(block => {
+ switch (block.type) {
+ case 'PLAIN_TEXT':
+ return block.value;
+ case 'STRIKE':
+ return ;
+ case 'ITALIC':
+ return ;
+ case 'BOLD':
+ return ;
+ default:
+ return null;
+ }
+ })(label)}
+
+ );
+};
+
+export default Link;
diff --git a/app/containers/markdown/new/MarkdownContext.ts b/app/containers/markdown/new/MarkdownContext.ts
new file mode 100644
index 000000000..b22f15614
--- /dev/null
+++ b/app/containers/markdown/new/MarkdownContext.ts
@@ -0,0 +1,29 @@
+import React from 'react';
+
+import { UserMention } from '../../message/interfaces';
+
+interface IMarkdownContext {
+ mentions: UserMention[];
+ channels: {
+ name: string;
+ _id: number;
+ }[];
+ useRealName: boolean;
+ username: string;
+ baseUrl: string;
+ navToRoomInfo: Function;
+ getCustomEmoji?: Function;
+ onLinkPress?: Function;
+}
+
+const defaultState = {
+ mentions: [],
+ channels: [],
+ useRealName: false,
+ username: '',
+ baseUrl: '',
+ navToRoomInfo: () => {}
+};
+
+const MarkdownContext = React.createContext(defaultState);
+export default MarkdownContext;
diff --git a/app/containers/markdown/new/OrderedList.tsx b/app/containers/markdown/new/OrderedList.tsx
new file mode 100644
index 000000000..c5ae25125
--- /dev/null
+++ b/app/containers/markdown/new/OrderedList.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import { View, Text } from 'react-native';
+import { OrderedList as OrderedListProps } from '@rocket.chat/message-parser';
+
+import Inline from './Inline';
+import styles from '../styles';
+import { themes } from '../../../constants/colors';
+import { useTheme } from '../../../theme';
+
+interface IOrderedListProps {
+ value: OrderedListProps['value'];
+}
+
+const OrderedList = ({ value }: IOrderedListProps): JSX.Element => {
+ const { theme } = useTheme();
+ return (
+
+ {value.map((item, index) => (
+
+ {index + 1}.
+
+
+ ))}
+
+ );
+};
+
+export default OrderedList;
diff --git a/app/containers/markdown/new/Paragraph.tsx b/app/containers/markdown/new/Paragraph.tsx
new file mode 100644
index 000000000..2f7649bb9
--- /dev/null
+++ b/app/containers/markdown/new/Paragraph.tsx
@@ -0,0 +1,23 @@
+import React from 'react';
+import { Text } from 'react-native';
+import { Paragraph as ParagraphProps } from '@rocket.chat/message-parser';
+
+import Inline from './Inline';
+import styles from '../styles';
+import { useTheme } from '../../../theme';
+import { themes } from '../../../constants/colors';
+
+interface IParagraphProps {
+ value: ParagraphProps['value'];
+}
+
+const Paragraph = ({ value }: IParagraphProps): JSX.Element => {
+ const { theme } = useTheme();
+ return (
+
+
+
+ );
+};
+
+export default Paragraph;
diff --git a/app/containers/markdown/new/Plain.tsx b/app/containers/markdown/new/Plain.tsx
new file mode 100644
index 000000000..9eca2e0c7
--- /dev/null
+++ b/app/containers/markdown/new/Plain.tsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import { Text } from 'react-native';
+import { Plain as PlainProps } from '@rocket.chat/message-parser';
+
+import styles from '../styles';
+import { useTheme } from '../../../theme';
+import { themes } from '../../../constants/colors';
+
+interface IPlainProps {
+ value: PlainProps['value'];
+}
+
+const Plain = ({ value }: IPlainProps): JSX.Element => {
+ const { theme } = useTheme();
+ return (
+
+ {value}
+
+ );
+};
+
+export default Plain;
diff --git a/app/containers/markdown/new/Quote.tsx b/app/containers/markdown/new/Quote.tsx
new file mode 100644
index 000000000..27d6a01d1
--- /dev/null
+++ b/app/containers/markdown/new/Quote.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import { View } from 'react-native';
+import { Quote as QuoteProps } from '@rocket.chat/message-parser';
+
+import { themes } from '../../../constants/colors';
+import { useTheme } from '../../../theme';
+import styles from '../styles';
+import Paragraph from './Paragraph';
+
+interface IQuoteProps {
+ value: QuoteProps['value'];
+}
+
+const Quote = ({ value }: IQuoteProps): JSX.Element => {
+ const { theme } = useTheme();
+ return (
+
+
+
+ {value.map(item => (
+
+ ))}
+
+
+ );
+};
+
+export default Quote;
diff --git a/app/containers/markdown/new/Strike.tsx b/app/containers/markdown/new/Strike.tsx
new file mode 100644
index 000000000..4d1cf5ea8
--- /dev/null
+++ b/app/containers/markdown/new/Strike.tsx
@@ -0,0 +1,39 @@
+import React from 'react';
+import { StyleSheet, Text } from 'react-native';
+import { Strike as StrikeProps } from '@rocket.chat/message-parser';
+
+import Bold from './Bold';
+import Italic from './Italic';
+import Plain from './Plain';
+import Link from './Link';
+
+interface IStrikeProps {
+ value: StrikeProps['value'];
+}
+
+const styles = StyleSheet.create({
+ text: {
+ textDecorationLine: 'line-through'
+ }
+});
+
+const Strike = ({ value }: IStrikeProps): JSX.Element => (
+
+ {value.map(block => {
+ switch (block.type) {
+ case 'LINK':
+ return ;
+ case 'PLAIN_TEXT':
+ return ;
+ case 'BOLD':
+ return ;
+ case 'ITALIC':
+ return ;
+ default:
+ return null;
+ }
+ })}
+
+);
+
+export default Strike;
diff --git a/app/containers/markdown/new/TaskList.tsx b/app/containers/markdown/new/TaskList.tsx
new file mode 100644
index 000000000..8f46af965
--- /dev/null
+++ b/app/containers/markdown/new/TaskList.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import { Text, View } from 'react-native';
+import { Tasks as TasksProps } from '@rocket.chat/message-parser';
+
+import Inline from './Inline';
+import styles from '../styles';
+import { themes } from '../../../constants/colors';
+import { useTheme } from '../../../theme';
+
+interface ITasksProps {
+ value: TasksProps['value'];
+}
+
+const TaskList = ({ value = [] }: ITasksProps): JSX.Element => {
+ const { theme } = useTheme();
+ return (
+
+ {value.map(item => (
+
+ {item.status ? '- [x] ' : '- [ ] '}
+
+
+ ))}
+
+ );
+};
+
+export default TaskList;
diff --git a/app/containers/markdown/new/UnorderedList.tsx b/app/containers/markdown/new/UnorderedList.tsx
new file mode 100644
index 000000000..51c9b2188
--- /dev/null
+++ b/app/containers/markdown/new/UnorderedList.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import { UnorderedList as UnorderedListProps } from '@rocket.chat/message-parser';
+import { View, Text } from 'react-native';
+
+import Inline from './Inline';
+import styles from '../styles';
+import { themes } from '../../../constants/colors';
+import { useTheme } from '../../../theme';
+
+interface IUnorderedListProps {
+ value: UnorderedListProps['value'];
+}
+
+const UnorderedList = ({ value }: IUnorderedListProps): JSX.Element => {
+ const { theme } = useTheme();
+ return (
+
+ {value.map(item => (
+
+ -
+
+
+ ))}
+
+ );
+};
+
+export default UnorderedList;
diff --git a/app/containers/markdown/new/index.tsx b/app/containers/markdown/new/index.tsx
new file mode 100644
index 000000000..a56b66f54
--- /dev/null
+++ b/app/containers/markdown/new/index.tsx
@@ -0,0 +1,77 @@
+import React from 'react';
+import { MarkdownAST } from '@rocket.chat/message-parser';
+
+import Quote from './Quote';
+import Paragraph from './Paragraph';
+import Heading from './Heading';
+import Code from './Code';
+import BigEmoji from './BigEmoji';
+import OrderedList from './OrderedList';
+import UnorderedList from './UnorderedList';
+import { UserMention } from '../../message/interfaces';
+import TaskList from './TaskList';
+import MarkdownContext from './MarkdownContext';
+
+interface IBodyProps {
+ tokens: MarkdownAST;
+ mentions: UserMention[];
+ channels: {
+ name: string;
+ _id: number;
+ }[];
+ getCustomEmoji?: Function;
+ onLinkPress?: Function;
+ navToRoomInfo: Function;
+ useRealName: boolean;
+ username: string;
+ baseUrl: string;
+}
+
+const Body = ({
+ tokens,
+ mentions,
+ channels,
+ useRealName,
+ username,
+ navToRoomInfo,
+ getCustomEmoji,
+ baseUrl,
+ onLinkPress
+}: IBodyProps): JSX.Element => (
+
+ {tokens.map(block => {
+ switch (block.type) {
+ case 'BIG_EMOJI':
+ return ;
+ case 'UNORDERED_LIST':
+ return ;
+ case 'ORDERED_LIST':
+ return ;
+ case 'TASKS':
+ return ;
+ case 'QUOTE':
+ return
;
+ case 'PARAGRAPH':
+ return ;
+ case 'CODE':
+ return
;
+ case 'HEADING':
+ return ;
+ default:
+ return null;
+ }
+ })}
+
+);
+
+export default Body;
diff --git a/app/containers/markdown/styles.ts b/app/containers/markdown/styles.ts
index d7eef0502..7a9cdebb5 100644
--- a/app/containers/markdown/styles.ts
+++ b/app/containers/markdown/styles.ts
@@ -30,6 +30,10 @@ export default StyleSheet.create({
del: {
textDecorationLine: 'line-through'
},
+ plainText: {
+ fontSize: 16,
+ flexShrink: 1
+ },
text: {
fontSize: 16,
...sharedStyles.textRegular
@@ -70,12 +74,16 @@ export default StyleSheet.create({
resizeMode: 'contain'
},
codeInline: {
+ fontSize: 16,
...sharedStyles.textRegular,
...codeFontFamily,
borderWidth: 1,
- borderRadius: 4
+ borderRadius: 4,
+ paddingLeft: 2,
+ paddingTop: 2
},
codeBlock: {
+ fontSize: 16,
...sharedStyles.textRegular,
...codeFontFamily,
borderWidth: 1,
diff --git a/app/containers/message/Content.tsx b/app/containers/message/Content.tsx
index ee3b8c931..b9aaf9620 100644
--- a/app/containers/message/Content.tsx
+++ b/app/containers/message/Content.tsx
@@ -51,8 +51,10 @@ const Content = React.memo(
// @ts-ignore
{
unread,
blocks,
autoTranslate: autoTranslateMessage,
- replies
+ replies,
+ md
} = item;
let message = msg;
@@ -391,6 +392,7 @@ class MessageContainer extends React.Component {
;
+
export interface IMessageContent {
isTemp: boolean;
isInfo: boolean;
tmid: string;
isThreadRoom: boolean;
msg: string;
+ md: MarkdownAST;
theme: string;
isEdited: boolean;
isEncrypted: boolean;
@@ -62,7 +73,7 @@ export interface IMessageContent {
name: string;
_id: number;
}[];
- mentions: object[];
+ mentions: UserMention[];
navToRoomInfo: Function;
useRealName: boolean;
isIgnored: boolean;
diff --git a/app/containers/message/styles.ts b/app/containers/message/styles.ts
index 3d4334f7c..49aa273eb 100644
--- a/app/containers/message/styles.ts
+++ b/app/containers/message/styles.ts
@@ -106,7 +106,6 @@ export default StyleSheet.create({
},
image: {
width: '100%',
- // maxWidth: 400,
minHeight: isTablet ? 300 : 200,
borderRadius: 4,
borderWidth: 1,
diff --git a/app/i18n/locales/en.json b/app/i18n/locales/en.json
index 7b76ef75b..0d66cc698 100644
--- a/app/i18n/locales/en.json
+++ b/app/i18n/locales/en.json
@@ -779,5 +779,6 @@
"Shortcut": "Shortcut",
"Content": "Content",
"Sharing": "Sharing",
- "No_canned_responses": "No canned responses"
+ "No_canned_responses": "No canned responses",
+ "Enable_Message_Parser": "Enable Message Parser"
}
diff --git a/app/lib/database/model/Message.js b/app/lib/database/model/Message.js
index a03902a26..20134733b 100644
--- a/app/lib/database/model/Message.js
+++ b/app/lib/database/model/Message.js
@@ -81,4 +81,6 @@ export default class Message extends Model {
@field('e2e') e2e;
@field('tshow') tshow;
+
+ @json('md', sanitizer) md;
}
diff --git a/app/lib/database/model/migrations.js b/app/lib/database/model/migrations.js
index fe32ec4f3..15c1331fe 100644
--- a/app/lib/database/model/migrations.js
+++ b/app/lib/database/model/migrations.js
@@ -190,6 +190,15 @@ export default schemaMigrations({
]
})
]
+ },
+ {
+ toVersion: 14,
+ steps: [
+ addColumns({
+ table: 'messages',
+ columns: [{ name: 'md', type: 'string', isOptional: true }]
+ })
+ ]
}
]
});
diff --git a/app/lib/database/model/servers/User.js b/app/lib/database/model/servers/User.js
index 6d78c27fa..30bd5f57d 100644
--- a/app/lib/database/model/servers/User.js
+++ b/app/lib/database/model/servers/User.js
@@ -25,4 +25,6 @@ export default class User extends Model {
@field('show_message_in_main_thread') showMessageInMainThread;
@field('is_from_webview') isFromWebView;
+
+ @field('enable_message_parser_early_adoption') enableMessageParserEarlyAdoption;
}
diff --git a/app/lib/database/model/servers/migrations.js b/app/lib/database/model/servers/migrations.js
index 51ec2b73b..d1f24f125 100644
--- a/app/lib/database/model/servers/migrations.js
+++ b/app/lib/database/model/servers/migrations.js
@@ -94,6 +94,15 @@ export default schemaMigrations({
columns: [{ name: 'is_from_webview', type: 'boolean', isOptional: true }]
})
]
+ },
+ {
+ toVersion: 12,
+ steps: [
+ addColumns({
+ table: 'users',
+ columns: [{ name: 'enable_message_parser_early_adoption', type: 'boolean', isOptional: true }]
+ })
+ ]
}
]
});
diff --git a/app/lib/database/schema/app.js b/app/lib/database/schema/app.js
index 33bde61de..043ddb8e9 100644
--- a/app/lib/database/schema/app.js
+++ b/app/lib/database/schema/app.js
@@ -1,7 +1,7 @@
import { appSchema, tableSchema } from '@nozbe/watermelondb';
export default appSchema({
- version: 13,
+ version: 14,
tables: [
tableSchema({
name: 'subscriptions',
@@ -115,7 +115,8 @@ export default appSchema({
{ name: 'tmsg', type: 'string', isOptional: true },
{ name: 'blocks', type: 'string', isOptional: true },
{ name: 'e2e', type: 'string', isOptional: true },
- { name: 'tshow', type: 'boolean', isOptional: true }
+ { name: 'tshow', type: 'boolean', isOptional: true },
+ { name: 'md', type: 'string', isOptional: true }
]
}),
tableSchema({
diff --git a/app/lib/database/schema/servers.js b/app/lib/database/schema/servers.js
index 1105cf165..1d849b874 100644
--- a/app/lib/database/schema/servers.js
+++ b/app/lib/database/schema/servers.js
@@ -1,7 +1,7 @@
import { appSchema, tableSchema } from '@nozbe/watermelondb';
export default appSchema({
- version: 11,
+ version: 12,
tables: [
tableSchema({
name: 'users',
@@ -16,7 +16,8 @@ export default appSchema({
{ name: 'login_email_password', type: 'boolean', isOptional: true },
{ name: 'show_message_in_main_thread', type: 'boolean', isOptional: true },
{ name: 'avatar_etag', type: 'string', isOptional: true },
- { name: 'is_from_webview', type: 'boolean', isOptional: true }
+ { name: 'is_from_webview', type: 'boolean', isOptional: true },
+ { name: 'enable_message_parser_early_adoption', type: 'boolean', isOptional: true }
]
}),
tableSchema({
diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js
index 40722348f..275cc1cf1 100644
--- a/app/lib/rocketchat.js
+++ b/app/lib/rocketchat.js
@@ -622,7 +622,8 @@ const RocketChat = {
roles: result.me.roles,
avatarETag: result.me.avatarETag,
isFromWebView,
- showMessageInMainThread: result.me.settings?.preferences?.showMessageInMainThread ?? true
+ showMessageInMainThread: result.me.settings?.preferences?.showMessageInMainThread ?? true,
+ enableMessageParserEarlyAdoption: result.me.settings?.preferences?.enableMessageParserEarlyAdoption ?? true
};
return user;
},
diff --git a/app/views/UserPreferencesView/index.js b/app/views/UserPreferencesView/index.js
index 573ab58f9..476c49a7d 100644
--- a/app/views/UserPreferencesView/index.js
+++ b/app/views/UserPreferencesView/index.js
@@ -1,46 +1,75 @@
-import React from 'react';
+import React, { useEffect, useState } from 'react';
+import { Switch } from 'react-native';
import PropTypes from 'prop-types';
+import { useSelector } from 'react-redux';
import I18n from '../../i18n';
-import { events, logEvent } from '../../utils/log';
+import log, { logEvent, events } from '../../utils/log';
import SafeAreaView from '../../containers/SafeAreaView';
import StatusBar from '../../containers/StatusBar';
import * as List from '../../containers/List';
+import { SWITCH_TRACK_COLOR } from '../../constants/colors';
+import { getUserSelector } from '../../selectors/login';
+import RocketChat from '../../lib/rocketchat';
-class UserPreferencesView extends React.Component {
- static navigationOptions = () => ({
- title: I18n.t('Preferences')
- });
+const UserPreferencesView = ({ navigation }) => {
+ const user = useSelector(state => getUserSelector(state));
+ const [enableParser, setEnableParser] = useState(user.enableMessageParserEarlyAdoption);
- static propTypes = {
- navigation: PropTypes.object
- };
+ useEffect(() => {
+ navigation.setOptions({
+ title: I18n.t('Preferences')
+ });
+ }, []);
- navigateToScreen = (screen, params) => {
+ const navigateToScreen = (screen, params) => {
logEvent(events[`SE_GO_${screen.replace('View', '').toUpperCase()}`]);
- const { navigation } = this.props;
navigation.navigate(screen, params);
};
- render() {
- return (
-
-
-
-
-
- this.navigateToScreen('UserNotificationPrefView')}
- showActionIndicator
- testID='preferences-view-notifications'
- />
-
-
-
-
- );
- }
-}
+ const toggleMessageParser = async value => {
+ try {
+ await RocketChat.saveUserPreferences({ id: user.id, enableMessageParserEarlyAdoption: value });
+ setEnableParser(value);
+ } catch (e) {
+ log(e);
+ }
+ };
+
+ const renderMessageParserSwitch = () => (
+
+ );
+
+ return (
+
+
+
+
+
+ navigateToScreen('UserNotificationPrefView')}
+ showActionIndicator
+ testID='preferences-view-notifications'
+ />
+
+
+
+
+ renderMessageParserSwitch()}
+ />
+
+
+
+
+ );
+};
+
+UserPreferencesView.propTypes = {
+ navigation: PropTypes.object
+};
export default UserPreferencesView;
diff --git a/package.json b/package.json
index 5786cd036..dcf82c98d 100644
--- a/package.json
+++ b/package.json
@@ -47,6 +47,7 @@
"@react-navigation/drawer": "5.12.5",
"@react-navigation/native": "5.9.4",
"@react-navigation/stack": "5.14.5",
+ "@rocket.chat/message-parser": "0.30.0",
"@rocket.chat/react-native-fast-image": "^8.2.0",
"@rocket.chat/sdk": "RocketChat/Rocket.Chat.js.SDK#mobile",
"@rocket.chat/ui-kit": "0.13.0",
diff --git a/storybook/stories/NewMarkdown.js b/storybook/stories/NewMarkdown.js
new file mode 100644
index 000000000..17684bb91
--- /dev/null
+++ b/storybook/stories/NewMarkdown.js
@@ -0,0 +1,627 @@
+/* eslint-disable import/no-extraneous-dependencies */
+import React from 'react';
+import { StyleSheet, View } from 'react-native';
+import { storiesOf } from '@storybook/react-native';
+
+import NewMarkdown from '../../app/containers/markdown/new';
+import { themes } from '../../app/constants/colors';
+
+const stories = storiesOf('NewMarkdown', module);
+
+const theme = 'light';
+
+const styles = StyleSheet.create({
+ container: {
+ marginHorizontal: 15,
+ backgroundColor: themes[theme].backgroundColor,
+ marginVertical: 50
+ },
+ separator: {
+ marginHorizontal: 10,
+ marginVertical: 10
+ }
+});
+
+const getCustomEmoji = content => {
+ const customEmoji = {
+ marioparty: { name: content, extension: 'gif' },
+ nyan_rocket: { name: content, extension: 'png' }
+ }[content];
+ return customEmoji;
+};
+const baseUrl = 'https://open.rocket.chat';
+
+const simpleTextMsg = [
+ {
+ type: 'PARAGRAPH',
+ value: [
+ {
+ type: 'PLAIN_TEXT',
+ value: 'This is Rocket.Chat'
+ }
+ ]
+ }
+];
+
+const longTextMsg = [
+ {
+ type: 'PARAGRAPH',
+ value: [
+ {
+ type: 'PLAIN_TEXT',
+ value:
+ 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
+ }
+ ]
+ }
+];
+
+const lineBreakMsg = [
+ {
+ type: 'PARAGRAPH',
+ value: [
+ {
+ type: 'PLAIN_TEXT',
+ value: 'a'
+ },
+ {
+ type: 'PLAIN_TEXT',
+ value: 'b'
+ },
+ {
+ type: 'PLAIN_TEXT',
+ value: 'c'
+ },
+ {
+ type: 'PLAIN_TEXT',
+ value: ''
+ },
+ {
+ type: 'PLAIN_TEXT',
+ value: 'd'
+ },
+ {
+ type: 'PLAIN_TEXT',
+ value: ''
+ },
+ {
+ type: 'PLAIN_TEXT',
+ value: ''
+ },
+ {
+ type: 'PLAIN_TEXT',
+ value: 'e'
+ }
+ ]
+ }
+];
+
+const sequentialEmptySpacesMsg = [
+ {
+ type: 'PARAGRAPH',
+ value: [
+ {
+ type: 'PLAIN_TEXT',
+ value: 'a b c'
+ }
+ ]
+ }
+];
+
+const boldOrUnderscoreMsg = [
+ {
+ type: 'PARAGRAPH',
+ value: [
+ {
+ type: 'BOLD',
+ value: [
+ {
+ type: 'PLAIN_TEXT',
+ value: 'This is bold'
+ }
+ ]
+ },
+ {
+ type: 'PLAIN_TEXT',
+ value: ' and '
+ },
+ {
+ type: 'ITALIC',
+ value: [
+ {
+ type: 'PLAIN_TEXT',
+ value: 'this is italic'
+ }
+ ]
+ }
+ ]
+ }
+];
+
+stories.add('Text', () => (
+
+
+
+
+
+
+
+));
+
+const allMentionTokens = [
+ {
+ type: 'PARAGRAPH',
+ value: [
+ {
+ type: 'MENTION_USER',
+ value: {
+ type: 'PLAIN_TEXT',
+ value: 'rocket.cat'
+ }
+ }
+ ]
+ }
+];
+
+const multipleMentionTokens = [
+ {
+ type: 'PARAGRAPH',
+ value: [
+ {
+ type: 'MENTION_USER',
+ value: {
+ type: 'PLAIN_TEXT',
+ value: 'name'
+ }
+ },
+ {
+ type: 'PLAIN_TEXT',
+ value: ' '
+ },
+ {
+ type: 'MENTION_USER',
+ value: {
+ type: 'PLAIN_TEXT',
+ value: 'rocket.cat'
+ }
+ },
+ {
+ type: 'PLAIN_TEXT',
+ value: ' '
+ },
+ {
+ type: 'MENTION_USER',
+ value: {
+ type: 'PLAIN_TEXT',
+ value: 'here'
+ }
+ },
+ {
+ type: 'PLAIN_TEXT',
+ value: ' '
+ },
+ {
+ type: 'MENTION_USER',
+ value: {
+ type: 'PLAIN_TEXT',
+ value: 'all'
+ }
+ }
+ ]
+ }
+];
+
+const allMentions = [
+ {
+ _id: 'rocket.cat',
+ username: 'rocket.cat'
+ }
+];
+
+const multipleMentions = [
+ {
+ _id: 'name',
+ username: 'name'
+ },
+ {
+ _id: 'rocket.cat',
+ username: 'rocket.cat'
+ },
+ {
+ _id: 'here',
+ username: 'here'
+ },
+ {
+ _id: 'all',
+ username: 'all'
+ }
+];
+
+stories.add('Mentions', () => (
+
+ {}} style={[]} />
+ {}}
+ style={[]}
+ username='rocket.cat'
+ />
+
+));
+
+const channelTokens = [
+ {
+ type: 'PARAGRAPH',
+ value: [
+ {
+ type: 'MENTION_CHANNEL',
+ value: {
+ type: 'PLAIN_TEXT',
+ value: 'text_channel'
+ }
+ },
+ {
+ type: 'PLAIN_TEXT',
+ value: ' and '
+ },
+ {
+ type: 'MENTION_CHANNEL',
+ value: {
+ type: 'PLAIN_TEXT',
+ value: 'not_a_channel'
+ }
+ }
+ ]
+ }
+];
+
+const channelMention = [
+ {
+ _id: 'text_channel',
+ name: 'text_channel'
+ }
+];
+
+stories.add('Hashtag', () => (
+
+ {}} />
+
+));
+
+const bigEmojiTokens = [
+ {
+ type: 'BIG_EMOJI',
+ value: [
+ {
+ type: 'EMOJI',
+ value: {
+ type: 'PLAIN_TEXT',
+ value: 'green_heart'
+ }
+ },
+ {
+ type: 'EMOJI',
+ value: {
+ type: 'PLAIN_TEXT',
+ value: 'joy'
+ }
+ },
+ {
+ type: 'EMOJI',
+ value: {
+ type: 'PLAIN_TEXT',
+ value: 'grin'
+ }
+ }
+ ]
+ }
+];
+
+const emojiTokens = [
+ {
+ type: 'PARAGRAPH',
+ value: [
+ {
+ type: 'EMOJI',
+ value: {
+ type: 'PLAIN_TEXT',
+ value: 'rocket'
+ }
+ },
+ {
+ type: 'EMOJI',
+ value: {
+ type: 'PLAIN_TEXT',
+ value: 'facepalm'
+ }
+ },
+ {
+ type: 'EMOJI',
+ value: {
+ type: 'PLAIN_TEXT',
+ value: 'nyan_rocket'
+ }
+ },
+ {
+ type: 'EMOJI',
+ value: {
+ type: 'PLAIN_TEXT',
+ value: 'marioparty'
+ }
+ }
+ ]
+ }
+];
+
+stories.add('Emoji', () => (
+
+
+
+
+));
+
+const blockQuoteTokens = [
+ {
+ type: 'QUOTE',
+ value: [
+ {
+ type: 'PARAGRAPH',
+ value: [
+ {
+ type: 'PLAIN_TEXT',
+ value: 'Rocket.Chat to the moon'
+ }
+ ]
+ }
+ ]
+ }
+];
+
+stories.add('Block quote', () => (
+
+
+
+));
+
+const rocketChatLink = [
+ {
+ type: 'PARAGRAPH',
+ value: [
+ {
+ type: 'LINK',
+ value: {
+ src: {
+ type: 'PLAIN_TEXT',
+ value: 'https://rocket.chat'
+ },
+ label: {
+ type: 'PLAIN_TEXT',
+ value: 'https://rocket.chat'
+ }
+ }
+ }
+ ]
+ }
+];
+
+const markdownLink = [
+ {
+ type: 'PARAGRAPH',
+ value: [
+ {
+ type: 'LINK',
+ value: {
+ src: {
+ type: 'PLAIN_TEXT',
+ value: 'https://rocket.chat'
+ },
+ label: {
+ type: 'PLAIN_TEXT',
+ value: 'Markdown link'
+ }
+ }
+ }
+ ]
+ }
+];
+
+stories.add('Links', () => (
+
+
+
+
+));
+
+stories.add('Headers', () => (
+
+
+
+
+
+
+
+
+));
+
+const inlineCodeToken = [
+ {
+ type: 'PARAGRAPH',
+ value: [
+ {
+ type: 'INLINE_CODE',
+ value: {
+ type: 'PLAIN_TEXT',
+ value: 'inline code'
+ }
+ }
+ ]
+ }
+];
+
+const multilineCodeToken = [
+ {
+ type: 'CODE',
+ language: 'none',
+ value: [
+ {
+ type: 'CODE_LINE',
+ value: {
+ type: 'PLAIN_TEXT',
+ value: 'Multi line '
+ }
+ },
+ {
+ type: 'CODE_LINE',
+ value: {
+ type: 'PLAIN_TEXT',
+ value: 'Code'
+ }
+ }
+ ]
+ }
+];
+
+stories.add('Code', () => (
+
+
+
+
+));
+
+const unorederedListToken = [
+ {
+ type: 'UNORDERED_LIST',
+ value: [
+ {
+ type: 'LIST_ITEM',
+ value: [
+ {
+ type: 'PLAIN_TEXT',
+ value: 'Open Source'
+ }
+ ]
+ },
+ {
+ type: 'LIST_ITEM',
+ value: [
+ {
+ type: 'PLAIN_TEXT',
+ value: 'Rocket.Chat'
+ }
+ ]
+ }
+ ]
+ }
+];
+
+const orderedListToken = [
+ {
+ type: 'ORDERED_LIST',
+ value: [
+ {
+ type: 'LIST_ITEM',
+ value: [
+ {
+ type: 'PLAIN_TEXT',
+ value: 'Open Source'
+ }
+ ]
+ },
+ {
+ type: 'LIST_ITEM',
+ value: [
+ {
+ type: 'PLAIN_TEXT',
+ value: 'Rocket.Chat'
+ }
+ ]
+ }
+ ]
+ }
+];
+
+stories.add('Lists', () => (
+
+
+
+
+));
diff --git a/storybook/stories/index.js b/storybook/stories/index.js
index 4ff6450b0..c8209d6f6 100644
--- a/storybook/stories/index.js
+++ b/storybook/stories/index.js
@@ -12,6 +12,7 @@ import './HeaderButtons';
import './UnreadBadge';
import '../../app/views/ThreadMessagesView/Item.stories.js';
import './Avatar';
+import './NewMarkdown';
import '../../app/containers/BackgroundContainer/index.stories.js';
import '../../app/containers/RoomHeader/RoomHeader.stories.js';
import '../../app/views/RoomView/LoadMore/LoadMore.stories';
diff --git a/yarn.lock b/yarn.lock
index 7352e3388..388162383 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3748,6 +3748,11 @@
dependencies:
eslint-plugin-import "^2.17.2"
+"@rocket.chat/message-parser@0.30.0":
+ version "0.30.0"
+ resolved "https://registry.yarnpkg.com/@rocket.chat/message-parser/-/message-parser-0.30.0.tgz#63a25aa7fa17724d55db80f95f7f8d6a99ae42ff"
+ integrity sha512-pI7ajaojv+GqhQBMnFiBOWerE7zIlJywWFaLzJlIC/wsJ9LgX6YaKY2wqc909nkr+E4qZY1luJ61ErXGGSF9Zw==
+
"@rocket.chat/react-native-fast-image@^8.2.0":
version "8.2.0"
resolved "https://registry.yarnpkg.com/@rocket.chat/react-native-fast-image/-/react-native-fast-image-8.2.0.tgz#4f48858f95f40afcb10b39cee9b1239c150d6c51"