diff --git a/app/containers/markdown/Hashtag.js b/app/containers/markdown/Hashtag.js index 8d9672e40..d66896169 100644 --- a/app/containers/markdown/Hashtag.js +++ b/app/containers/markdown/Hashtag.js @@ -3,12 +3,14 @@ import React from 'react'; import { Text } from 'react-native'; import { themes } from '../../constants/colors'; +import { useTheme } from '../../theme'; import styles from './styles'; const Hashtag = React.memo(({ - hashtag, channels, navToRoomInfo, style = [], theme + hashtag, channels, navToRoomInfo, style = [] }) => { + const { theme } = useTheme(); const handlePress = () => { const index = channels.findIndex(channel => channel.name === hashtag); const navParam = { @@ -44,7 +46,6 @@ Hashtag.propTypes = { hashtag: PropTypes.string, navToRoomInfo: PropTypes.func, style: PropTypes.array, - theme: PropTypes.string, channels: PropTypes.oneOfType([PropTypes.array, PropTypes.object]) }; diff --git a/app/containers/markdown/MessageBody/BigEmoji.js b/app/containers/markdown/MessageBody/BigEmoji.js index 02f92020d..ce671f89c 100644 --- a/app/containers/markdown/MessageBody/BigEmoji.js +++ b/app/containers/markdown/MessageBody/BigEmoji.js @@ -1,14 +1,15 @@ /* eslint-disable react/no-array-index-key */ import React from 'react'; +import { View } from 'react-native'; import PropTypes from 'prop-types'; import Emoji from './Emoji'; const BigEmoji = ({ value }) => ( - <> + {value.map((block, index) => )} - + ); BigEmoji.propTypes = { diff --git a/app/containers/markdown/MessageBody/Bold.js b/app/containers/markdown/MessageBody/Bold.js index d0d7a1d82..ed827eff8 100644 --- a/app/containers/markdown/MessageBody/Bold.js +++ b/app/containers/markdown/MessageBody/Bold.js @@ -2,9 +2,10 @@ import React from 'react'; import { StyleSheet, Text } from 'react-native'; import PropTypes from 'prop-types'; -import Plain from './Plain'; + import Strike from './Strike'; import Italic from './Italic'; +import Plain from './Plain'; const styles = StyleSheet.create({ text: { @@ -17,7 +18,7 @@ const Bold = ({ value }) => ( {value.map((block, index) => { switch (block.type) { case 'PLAIN_TEXT': - return ; + return ; case 'STRIKE': return ; case 'ITALIC': diff --git a/app/containers/markdown/MessageBody/Code.js b/app/containers/markdown/MessageBody/Code.js index 2d93c429c..d11532954 100644 --- a/app/containers/markdown/MessageBody/Code.js +++ b/app/containers/markdown/MessageBody/Code.js @@ -21,7 +21,7 @@ const Code = ({ ...styles.codeBlock, color: themes[theme].bodyText, backgroundColor: themes[theme].bannerBackground, - borderColor: themes[theme].bannerBackground + borderColor: themes[theme].borderColor }, ...style ]} diff --git a/app/containers/markdown/MessageBody/Inline.js b/app/containers/markdown/MessageBody/Inline.js index ade8eb2a1..d1ab4400a 100644 --- a/app/containers/markdown/MessageBody/Inline.js +++ b/app/containers/markdown/MessageBody/Inline.js @@ -10,9 +10,11 @@ import Italic from './Italic'; import Emoji from './Emoji'; import Mention from './Mention'; import InlineCode from './InlineCode'; +import Hashtag from '../Hashtag'; + const Inline = ({ - value, mentions, navToRoomInfo, style + value, mentions, channels, navToRoomInfo, style }) => ( {value.map((block) => { @@ -33,8 +35,7 @@ const Inline = ({ case 'EMOJI': return ; case 'MENTION_CHANNEL': - // case 'COLOR': - return ; + return ; case 'INLINE_CODE': return ; default: @@ -47,6 +48,7 @@ const Inline = ({ Inline.propTypes = { value: PropTypes.object, mentions: PropTypes.array, + channels: PropTypes.array, navToRoomInfo: PropTypes.func, style: PropTypes.oneOfType([PropTypes.array, PropTypes.object]) }; diff --git a/app/containers/markdown/MessageBody/InlineCode.js b/app/containers/markdown/MessageBody/InlineCode.js index 913eb45a0..d9e8d940a 100644 --- a/app/containers/markdown/MessageBody/InlineCode.js +++ b/app/containers/markdown/MessageBody/InlineCode.js @@ -1,33 +1,26 @@ import React from 'react'; import { Text } from 'react-native'; import PropTypes from 'prop-types'; -import { useTheme } from '@react-navigation/native'; import styles from '../styles'; import { themes } from '../../../constants/colors'; +import { useTheme } from '../../../theme'; const InlineCode = ({ value, style }) => { const { theme } = useTheme(); - + console.log({ value: value.value }); return ( - {((block) => { - switch (block.type) { - case 'PLAIN_TEXT': - return block.value; - default: - return null; - } - })(value)} + {value.type === 'PLAIN_TEXT' && value.value} ); }; diff --git a/app/containers/markdown/MessageBody/Italic.js b/app/containers/markdown/MessageBody/Italic.js index 24cb082e2..f4f24dea6 100644 --- a/app/containers/markdown/MessageBody/Italic.js +++ b/app/containers/markdown/MessageBody/Italic.js @@ -3,9 +3,9 @@ import React from 'react'; import { StyleSheet, Text } from 'react-native'; import PropTypes from 'prop-types'; -import Plain from './Plain'; import Strike from './Strike'; import Bold from './Bold'; +import Plain from './Plain'; const styles = StyleSheet.create({ text: { diff --git a/app/containers/markdown/MessageBody/OrderedList.js b/app/containers/markdown/MessageBody/OrderedList.js new file mode 100644 index 000000000..f5a4f19d3 --- /dev/null +++ b/app/containers/markdown/MessageBody/OrderedList.js @@ -0,0 +1,23 @@ +/* eslint-disable react/no-array-index-key */ +import React from 'react'; +import { View, Text } from 'react-native'; +import PropTypes from 'prop-types'; + +import Inline from './Inline'; + +const OrderedList = React.memo(({ value }) => ( + <> + {value.map((item, index) => ( + + {index + 1}. + + + ))} + +)); + +OrderedList.propTypes = { + value: PropTypes.array +}; + +export default OrderedList; diff --git a/app/containers/markdown/MessageBody/Paragraph.js b/app/containers/markdown/MessageBody/Paragraph.js index 2d43c696e..51d0a38f7 100644 --- a/app/containers/markdown/MessageBody/Paragraph.js +++ b/app/containers/markdown/MessageBody/Paragraph.js @@ -4,12 +4,13 @@ import PropTypes from 'prop-types'; import Inline from './Inline'; const Paragraph = ({ - value, mentions, navToRoomInfo, style -}) => ; + value, mentions, channels, navToRoomInfo, style +}) => ; Paragraph.propTypes = { value: PropTypes.string, - mentions: PropTypes.string, + mentions: PropTypes.array, + channels: PropTypes.array, navToRoomInfo: PropTypes.func, style: PropTypes.oneOfType([PropTypes.array, PropTypes.object]) }; diff --git a/app/containers/markdown/MessageBody/Quote.js b/app/containers/markdown/MessageBody/Quote.js index 934c63625..6c75de1b7 100644 --- a/app/containers/markdown/MessageBody/Quote.js +++ b/app/containers/markdown/MessageBody/Quote.js @@ -1,9 +1,11 @@ +/* eslint-disable react/no-array-index-key */ import React from 'react'; import { View } from 'react-native'; import PropTypes from 'prop-types'; import { themes } from '../../../constants/colors'; import { useTheme } from '../../../theme'; import styles from '../styles'; +import Paragraph from './Paragraph'; const Quote = ({ value }) => { const { theme } = useTheme(); @@ -12,7 +14,9 @@ const Quote = ({ value }) => { - {value} + {value.map((item, index) => ( + + ))} diff --git a/app/containers/markdown/MessageBody/Strike.js b/app/containers/markdown/MessageBody/Strike.js index f33c5b104..0c6984214 100644 --- a/app/containers/markdown/MessageBody/Strike.js +++ b/app/containers/markdown/MessageBody/Strike.js @@ -3,9 +3,9 @@ import React from 'react'; import { StyleSheet, Text } from 'react-native'; import PropTypes from 'prop-types'; -import Plain from './Plain'; import Bold from './Bold'; import Italic from './Italic'; +import Plain from './Plain'; const styles = StyleSheet.create({ text: { diff --git a/app/containers/markdown/MessageBody/UnorderedList.js b/app/containers/markdown/MessageBody/UnorderedList.js new file mode 100644 index 000000000..c5c0fd3d2 --- /dev/null +++ b/app/containers/markdown/MessageBody/UnorderedList.js @@ -0,0 +1,18 @@ +/* eslint-disable react/no-array-index-key */ +import React from 'react'; +import PropTypes from 'prop-types'; +import Inline from './Inline'; + +const UnorderedList = React.memo(({ value }) => ( + <> + {value.map((item, index) => ( + + ))} + +)); + +UnorderedList.propTypes = { + value: PropTypes.array +}; + +export default UnorderedList; diff --git a/app/containers/markdown/MessageBody/index.js b/app/containers/markdown/MessageBody/index.js index 7880bd30f..a3ca0d29d 100644 --- a/app/containers/markdown/MessageBody/index.js +++ b/app/containers/markdown/MessageBody/index.js @@ -2,18 +2,19 @@ import React from 'react'; import PropTypes from 'prop-types'; -import List from './List'; import Quote from './Quote'; import Paragraph from './Paragraph'; import Heading from './Heading'; import Code from './Code'; import Link from './Link'; import BigEmoji from './BigEmoji'; +import OrderedList from './OrderedList'; +import UnorderedList from './UnorderedList'; const isBigEmoji = tokens => tokens.length === 1 && tokens[0].type === 'BIG_EMOJI'; const Body = ({ - tokens, mentions, navToRoomInfo, style + tokens, mentions, channels, navToRoomInfo, style }) => { if (isBigEmoji(tokens)) { return ; @@ -24,15 +25,25 @@ const Body = ({ {tokens.map((block, index) => { switch (block.type) { case 'UNORDERED_LIST': - return ; + return ; case 'ORDERED_LIST': - return ; + return ; case 'TASK': - return ; + return ; case 'QUOTE': + console.log({ block }); return ; case 'PARAGRAPH': - return ; + return ( + + ); case 'CODE': return ; case 'LINK': @@ -51,6 +62,7 @@ const Body = ({ Body.propTypes = { tokens: PropTypes.array, mentions: PropTypes.array, + channels: PropTypes.array, navToRoomInfo: PropTypes.func, style: PropTypes.oneOfType([PropTypes.array, PropTypes.object]) }; diff --git a/app/containers/markdown/index.js b/app/containers/markdown/index.js index c4dd54d1b..fa1a8739e 100644 --- a/app/containers/markdown/index.js +++ b/app/containers/markdown/index.js @@ -238,14 +238,13 @@ class Markdown extends PureComponent { renderHashtag = ({ hashtag }) => { const { - channels, navToRoomInfo, style, theme + channels, navToRoomInfo, style } = this.props; return ( ); @@ -376,7 +375,7 @@ class Markdown extends PureComponent { render() { const { - msg, md, numberOfLines, preview = false, theme, style = [], testID, user, mentions, navToRoomInfo + msg, md, numberOfLines, preview = false, theme, style = [], testID, user, mentions, channels, navToRoomInfo } = this.props; if (!msg) { @@ -384,7 +383,7 @@ class Markdown extends PureComponent { } if (user.enableMessageParserEarlyAdoption && md) { - return ; + return ; } let m = formatText(msg); diff --git a/app/containers/markdown/styles.js b/app/containers/markdown/styles.js index f78ad3c3a..6a6770e1b 100644 --- a/app/containers/markdown/styles.js +++ b/app/containers/markdown/styles.js @@ -73,7 +73,9 @@ export default StyleSheet.create({ ...sharedStyles.textRegular, ...codeFontFamily, borderWidth: 1, - borderRadius: 4 + borderRadius: 4, + paddingLeft: 2, + paddingTop: 2 }, codeBlock: { ...sharedStyles.textRegular, diff --git a/index.js b/index.js index bbd7a5786..02a59df2c 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,13 @@ -import 'react-native-gesture-handler'; -import 'react-native-console-time-polyfill'; -import { AppRegistry } from 'react-native'; -import { name as appName, share as shareName } from './app.json'; +// import 'react-native-gesture-handler'; +// import 'react-native-console-time-polyfill'; +// import { AppRegistry } from 'react-native'; +// import { name as appName, share as shareName } from './app.json'; + +// AppRegistry.registerComponent(appName, () => require('./app/index').default); +// AppRegistry.registerComponent(shareName, () => require('./app/share').default); + +// For storybook, comment everything above and uncomment below +import './storybook'; if (__DEV__) { require('./app/ReactotronConfig'); @@ -16,9 +22,3 @@ if (__DEV__) { console.error = () => {}; console.info = () => {}; } - -AppRegistry.registerComponent(appName, () => require('./app/index').default); -AppRegistry.registerComponent(shareName, () => require('./app/share').default); - -// For storybook, comment everything above and uncomment below -// import './storybook'; diff --git a/storybook/stories/Markdown.js b/storybook/stories/Markdown.js index bffd5a2aa..7c5187045 100644 --- a/storybook/stories/Markdown.js +++ b/storybook/stories/Markdown.js @@ -152,7 +152,6 @@ stories.add('Hashtag', () => ( diff --git a/storybook/stories/MessageBody.js b/storybook/stories/MessageBody.js new file mode 100644 index 000000000..23c247c87 --- /dev/null +++ b/storybook/stories/MessageBody.js @@ -0,0 +1,536 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import React from 'react'; +import { StyleSheet, View } from 'react-native'; +import { storiesOf } from '@storybook/react-native'; + +import MessageBody from '../../app/containers/markdown/MessageBody'; +import { themes } from '../../app/constants/colors'; + +const stories = storiesOf('MessageBody', module); + +const theme = 'light'; + +const styles = StyleSheet.create({ + container: { + marginHorizontal: 15, + backgroundColor: themes[theme].backgroundColor, + marginVertical: 50 + }, + separator: { + marginHorizontal: 10, + marginVertical: 10 + } +}); + +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: 'PLAIN_TEXT', + value: 'Strong emphasis, aka bold, with ' + }, + { + type: 'BOLD', + value: [{ + type: 'PLAIN_TEXT', + value: 'asterisks' + }] + }, + { + type: 'PLAIN_TEXT', + value: ' or ' + }, + { + type: 'ITALIC', + value: [{ + type: 'PLAIN_TEXT', + value: 'underscore' + }] + } + ] + } +]; + +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={[]} /> + +)); + +const channelTokens = [ + { + type: 'PARAGRAPH', + value: [{ + type: 'MENTION_CHANNEL', + value: { + type: 'PLAIN_TEXT', + value: 'text_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' + } + } + ] +}]; + +const multipleBigEmojiTokens = [{ + 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' + } + } + ] +}]; + +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 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 b695d49d6..53eeb0d55 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 './MessageBody'; import '../../app/containers/BackgroundContainer/index.stories.js'; import '../../app/containers/RoomHeader/RoomHeader.stories.js'; import '../../app/views/RoomView/LoadMore/LoadMore.stories';