From b62a683ada2f7e62609dde41364c00dc47af5d17 Mon Sep 17 00:00:00 2001 From: Terry Sahaidak Date: Thu, 6 Jul 2017 02:43:46 +0300 Subject: [PATCH] Add base markdown parsing --- app/components/Markdown/index.js | 124 ++++++++++++++++++++++++++++++ app/components/Markdown/styles.js | 59 ++++++++++++++ app/screens/Room/Message/index.js | 14 +++- package.json | 1 + 4 files changed, 194 insertions(+), 4 deletions(-) create mode 100644 app/components/Markdown/index.js create mode 100644 app/components/Markdown/styles.js diff --git a/app/components/Markdown/index.js b/app/components/Markdown/index.js new file mode 100644 index 0000000..4d8c205 --- /dev/null +++ b/app/components/Markdown/index.js @@ -0,0 +1,124 @@ +import React, {Component, createElement} from 'react' +import { + View, + Text, + ScrollView, + Image +} from 'react-native' +import styles from './styles' +import MarkdownView from 'react-native-markdown-view/MarkdownView' +import SimpleMarkdown from 'simple-markdown' + +class Markdown extends Component { + getRules() { + return { + fence: { + match: (source, state) => (null) + }, + codeBlock: { + match: SimpleMarkdown.blockRegex(/^`{3}([\S]+)?\n([\s\S]+)\n`{3}/), + parse: (capture, parse, state) => { + return { + lang: capture[1], + content: capture[2] + } + }, + render: (node, output, state) => { + // debugger + state.withinText = true + const codeElement = createElement(Text, { + key: state.key, + style: styles.codeBlock + }, node.content) + const scrollElement = createElement(ScrollView, { + horizontal: true, + key: state.key + }, codeElement) + return createElement(View, { + key: state.key, + style: styles.codeBlockContainer + }, scrollElement) + } + }, + inlineCode: { + match: (source, state) => { + const match = /^\`([^`]+)\`/.exec(source) + + if (!!match) { + const newLineMatch = /\n/.exec(match[0]) + if (!!newLineMatch) return null + } + + return match + }, + parse: (capture, parse, state) => { + // debugger + return { + content: capture[1] + } + }, + render: (node, output, state) => { + state.withinText = true + return createElement(Text, { + key: state.key, + style: styles.inlineCode + }, node.content) + } + }, + blockQuote: { + render: (node, output, state) => { + state.withinText = true + const blockBar = createElement(View, { + key: state.key, + style: [styles.blockQuoteSectionBar, styles.blockQuoteBar] + }) + const blockText = createElement(View, { + key: state.key + 1, + style: styles.blockQuoteText + }, output(node.content, state)) + return createElement(View, { key: state.key, style: [styles.blockQuoteSection, styles.blockQuote] }, [blockBar, blockText]) + } + }, + heading: { + match: (source, state) => { + return /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n *)/.exec(source) + }, + render: (node, output, parentState) => { + const state = {...parentState} + state.withinText = true + const stylesToApply = [styles.heading, styles['heading' + node.level]] + state.stylesToApply = stylesToApply + return createElement(Text, { + key: state.key, + style: stylesToApply + }, output(node.content, state)) + } + }, + // image: { + // render: (node, output, state) => { + // state.inline = false + // return createElement(Image, { + // key: state.key, + // resizeMode: styles.resizeMode ? styles.resizeMode : 'contain', + // source: { uri: node.target }, + // style: node.target.match(/youtu|vimeo/) ? styles.video : styles.image + // }) + // } + // }, + } + } + render() { + return ( + + {this.props.children} + + ) + } +} + +Markdown.propTypes = { + +} + +export default Markdown diff --git a/app/components/Markdown/styles.js b/app/components/Markdown/styles.js new file mode 100644 index 0000000..71e5a2e --- /dev/null +++ b/app/components/Markdown/styles.js @@ -0,0 +1,59 @@ +import {StyleSheet, Platform} from 'react-native' +const iOS = Platform.OS === 'ios' + +const styles = StyleSheet.create({ + codeBlock: { + fontFamily: iOS ? 'Courier' : 'monospace' + }, + codeBlockContainer: { + backgroundColor: '#eeeeee', + borderColor: '#dddddd', + borderRadius: 3, + borderWidth: 1, + padding: 4 + }, + inlineCode: { + backgroundColor: '#eeeeee', + borderColor: '#dddddd', + borderRadius: 3, + borderWidth: 1, + fontFamily: 'Courier', + fontWeight: 'bold' + }, + blockQuoteSection: { + flexDirection: 'row' + }, + blockQuoteSectionBar: { + width: 3, + height: null, + backgroundColor: '#DDDDDD', + marginRight: 15 + }, + heading: { + fontWeight: '500' + }, + heading1: { + fontSize: 32 + }, + heading2: { + fontSize: 24 + }, + heading3: { + fontSize: 18 + }, + heading4: { + fontSize: 16 + }, + heading5: { + fontSize: 13 + }, + heading6: { + fontSize: 11 + }, + image: { + width: '30%', + height: '30%', + }, +}) + +export default styles diff --git a/app/screens/Room/Message/index.js b/app/screens/Room/Message/index.js index 7b0495c..a1b8173 100644 --- a/app/screens/Room/Message/index.js +++ b/app/screens/Room/Message/index.js @@ -11,6 +11,7 @@ import ParsedText from '../../../components/ParsedText' import Avatar from '../../../components/Avatar' import StatusMessage from '../StatusMessage' import Button from '../../../components/Button' +import Markdown from '../../../components/Markdown' class Message extends Component { constructor(props) { @@ -75,11 +76,16 @@ class Message extends Component { ) } return ( - + + {text} + ) + // return ( + // + // ) } render() { diff --git a/package.json b/package.json index d65b8ec..2109fc7 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "react-native-drawer-layout": "^1.3.0", "react-native-fetch-blob": "^0.10.6", "react-native-invertible-scroll-view": "^1.0.0", + "react-native-markdown-view": "^1.0.0", "react-native-navigation": "^1.1.125", "react-native-parsed-text": "0.0.16", "react-native-scrollable-tab-view": "^0.6.7",