Giter VIP home page Giter VIP logo

react-native-markdown-display's Introduction

React Native Markdown Display npm version Known Vulnerabilities

It a 100% compatible CommonMark renderer, a react-native markdown renderer done right. This is not a web-view markdown renderer but a renderer that uses native components for all its elements. These components can be overwritten and styled as needed.

Compatibility with react-native-markdown-renderer

This is intended to be a replacement for react-native-markdown-renderer, with a variety of bug fixes and enhancements - Due to how the new style rules work, there may be some tweaking needed, see how to style stuff section below

Install

Yarn

yarn add react-native-markdown-display

NPM

npm install -S react-native-markdown-display

Get Started

import React from 'react';
import { SafeAreaView, ScrollView, StatusBar } from 'react-native';

import Markdown from 'react-native-markdown-display';

const copy = `# h1 Heading 8-)

**This is some bold text!**

This is normal text
`;

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}
        >
          <Markdown>
            {copy}
          </Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

Props and Functions

The <Markdown> object takes the following common props:

Property Default Required Description
children N/A true The markdown string to render, or the pre-processed tree
style source false An object to override the styling for the various rules, see style section below for more info
mergeStyle true false If true, when a style is supplied, the individual items are merged with the default styles instead of overwriting them
rules source false An object of rules that specify how to render each markdown item, see rules section below for more info
onLinkPress import { Linking } from 'react-native'; and Linking.openURL(url); false A handler function to change click behaviour, see handling links section below for more info
debugPrintTree false false Will print the AST tree to the console to help you see what the markdown is being translated to

And some additional, less used options:

Property Default Required Description
renderer instanceOf(AstRenderer) false Used to specify a custom renderer, you can not use the rules or styles props with a custom renderer.
markdownit instanceOf(MarkdownIt) false A custom markdownit instance with your configuration, default is MarkdownIt({typographer: true})
maxTopLevelChildren null false If defined as a number will only render out first n many top level children, then will try to render out topLevelMaxExceededItem
topLevelMaxExceededItem <Text key="dotdotdot">...</Text> false Will render when maxTopLevelChildren is hit. Make sure to give it a key!
allowedImageHandlers ['data:image/png;base64', 'data:image/gif;base64', 'data:image/jpeg;base64', 'https://', 'http://'] false Any image that does not start with one of these will have the defaultImageHandler value prepended to it (unless defaultImageHandler is null in which case it won't try to render anything)
defaultImageHandler http:// false Will be prepended to an image url if it does not start with something in the allowedImageHandlers array, if this is set to null, it won't try to recover but will just not render anything instead.

Syntax Support

Headings

  # h1 Heading 8-)
  ## h2 Heading
  ### h3 Heading
  #### h4 Heading
  ##### h5 Heading
  ###### h6 Heading
iOS Android

Horizontal Rules

  Some text above
  ___

  Some text in the middle

  ---

  Some text below
iOS Android

Emphasis

  **This is bold text**

  __This is bold text__

  *This is italic text*

  _This is italic text_

  ~~Strikethrough~~
iOS Android

Blockquotes

  > Blockquotes can also be nested...
  >> ...by using additional greater-than signs right next to each other...
  > > > ...or with spaces between arrows.
iOS Android

Lists

  Unordered

  + Create a list by starting a line with `+`, `-`, or `*`
  + Sub-lists are made by indenting 2 spaces:
    - Marker character change forces new list start:
      * Ac tristique libero volutpat at
      + Facilisis in pretium nisl aliquet. This is a very long list item that will surely wrap onto the next line.
      - Nulla volutpat aliquam velit
  + Very easy!

  Ordered

  1. Lorem ipsum dolor sit amet
  2. Consectetur adipiscing elit. This is a very long list item that will surely wrap onto the next line.
  3. Integer molestie lorem at massa

  Start numbering with offset:

  57. foo
  58. bar
iOS Android

Code

  Inline \`code\`

  Indented code

      // Some comments
      line 1 of code
      line 2 of code
      line 3 of code


  Block code "fences"

  \`\`\`
  Sample text here...
  \`\`\`

  Syntax highlighting

  \`\`\` js
  var foo = function (bar) {
    return bar++;
  };

  console.log(foo(5));
  \`\`\`
iOS Android

Tables

  | Option | Description |
  | ------ | ----------- |
  | data   | path to data files to supply the data that will be passed into templates. |
  | engine | engine to be used for processing templates. Handlebars is the default. |
  | ext    | extension to be used for dest files. |

  Right aligned columns

  | Option | Description |
  | ------:| -----------:|
  | data   | path to data files to supply the data that will be passed into templates. |
  | engine | engine to be used for processing templates. Handlebars is the default. |
  | ext    | extension to be used for dest files. |
iOS Android

Links

  [link text](https://www.google.com)

  [link with title](https://www.google.com "title text!")

  Autoconverted link https://www.google.com (enable linkify to see)
iOS Android

Images

  ![Minion](https://octodex.github.com/images/minion.png)
  ![Stormtroopocat](https://octodex.github.com/images/stormtroopocat.jpg "The Stormtroopocat")

  Like links, Images also have a footnote style syntax

  ![Alt text][id]

  With a reference later in the document defining the URL location:

  [id]: https://octodex.github.com/images/dojocat.jpg  "The Dojocat"
iOS Android

Typographic Replacements

  Enable typographer option to see result.

  (c) (C) (r) (R) (tm) (TM) (p) (P) +-

  test.. test... test..... test?..... test!....

  !!!!!! ???? ,,  -- ---

  "Smartypants, double quotes" and 'single quotes'
iOS Android

Plugins and Extensions

Plugins for extra syntax support can be added using any markdown-it compatible plugins - see plugins for documentation from markdown-it. An example for integration follows:

Step 1

Identify the new components and integrate the plugin with a rendered component. We can use the debugPrintTree property to see what rules we are rendering:

import React from 'react';
import { SafeAreaView, ScrollView, StatusBar } from 'react-native';

import Markdown, { MarkdownIt } from 'react-native-markdown-display';
import blockEmbedPlugin from 'markdown-it-block-embed';

const markdownItInstance = 
    MarkdownIt({typographer: true})
      .use(blockEmbedPlugin, {
        containerClassName: "video-embed"
      });

const copy = `
# Some header

@[youtube](lJIrF4YjHfQ)
`;

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}
        >
            <Markdown
              debugPrintTree
              markdownit={markdownItInstance}
            >
              {copy}
            </Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

In the console, we will see the following rendered tree:

body
-heading1
--textgroup
---text
-video

With the following error message:

Warning, unknown render rule encountered: video. 'unknown' render rule used (by default, returns null - nothing rendered) 

Step 2

We need to create the render rules and styles to handle this new 'video' component

import React from 'react';
import { SafeAreaView, ScrollView, StatusBar } from 'react-native';

import Markdown, { MarkdownIt } from 'react-native-markdown-display';
import blockEmbedPlugin from 'markdown-it-block-embed';

const markdownItInstance = 
    MarkdownIt({typographer: true})
      .use(blockEmbedPlugin, {
        containerClassName: "video-embed"
      });

const copy = `
# Some header

@[youtube](lJIrF4YjHfQ)
`;

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}
        >
            <Markdown
              debugPrintTree
              markdownit={markdownItInstance}
              style={{
                  video: {
                    color: 'red',
                  }
                }}
              rules={{
                  video: (node, children, parent, styles) =>{
                    // examine the node properties to see what video we need to render
                    console.log(node); // expected output of this is in readme.md below this code snip

                    return (<Text key={node.key} style={styles.video}>
                      Return a video component instead of this text component!
                    </Text>);
                  }
                   
                }}
            >
              {copy}
            </Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

And all of the video properties needed to render something meaningful are on the node, like this:

{type: "video", sourceType: "video", sourceInfo: {…}, sourceMeta: null, block: true, …}
  attributes: {}
  block: true
  children: []
  content: ""
  index: 1
  key: "rnmr_1720a98f540_video"
  markup: "@[youtube](lJIrF4YjHfQ)"
  sourceInfo:
    service: YouTubeService
      env: PluginEnvironment {md: MarkdownIt, options: {…}, services: {…}}
      name: "youtube"
      options:
        height: 390
        width: 640
      serviceName: "youtube"
      videoID: "lJIrF4YjHfQ"
      videoReference: "lJIrF4YjHfQ"
  sourceMeta: null
  sourceType: "video"
  tokenIndex: 5
  type: "video"

Other Debugging

You can do some additional debugging of what the markdown instance is spitting out like this:

import Markdown, { MarkdownIt } from 'react-native-markdown-display';
import blockEmbedPlugin from 'markdown-it-block-embed';

const markdownItInstance = 
    MarkdownIt({typographer: true})
      .use(blockEmbedPlugin, {
        containerClassName: "video-embed"
      });

const copy = `
# Some header

@[youtube](lJIrF4YjHfQ)
`;

// this shows you the tree that is used by the react-native-markdown-display
const astTree = markdownItInstance.parse(copy, {});
console.log(astTree);

//this contains the html that would be generated - not used by react-native-markdown-display but useful for reference
const html = markdownItInstance.render(copy);
console.log(html);

The above code will output something like this:

astTree:

(4) [Token, Token, Token, Token]

0: Token {type: "heading_open", tag: "h1", attrs: null, map: Array(2), nesting: 1, …}
1: Token {type: "inline", tag: "", attrs: null, map: Array(2), nesting: 0, …}
2: Token {type: "heading_close", tag: "h1", attrs: null, map: null, nesting: -1, …}
3: Token {type: "video", tag: "div", attrs: null, map: Array(2), nesting: 0, …}

length: 4
html:


<h1>Some header</h1>
<div class="video-embed block-embed-service-youtube"><iframe type="text/html" src="//www.youtube.com/embed/lJIrF4YjHfQ" frameborder="0" width="640" height="390" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>

All Markdown for Testing

This is all of the markdown in one place for testing that your applied styles work in all cases

Headings

  # h1 Heading 8-)
  ## h2 Heading
  ### h3 Heading
  #### h4 Heading
  ##### h5 Heading
  ###### h6 Heading


Horizontal Rules

  Some text above
  ___

  Some text in the middle

  ---

  Some text below


Emphasis

  **This is bold text**

  __This is bold text__

  *This is italic text*

  _This is italic text_

  ~~Strikethrough~~


Blockquotes

  > Blockquotes can also be nested...
  >> ...by using additional greater-than signs right next to each other...
  > > > ...or with spaces between arrows.


Lists

  Unordered

  + Create a list by starting a line with `+`, `-`, or `*`
  + Sub-lists are made by indenting 2 spaces:
    - Marker character change forces new list start:
      * Ac tristique libero volutpat at
      + Facilisis in pretium nisl aliquet. This is a very long list item that will surely wrap onto the next line.
      - Nulla volutpat aliquam velit
  + Very easy!

  Ordered

  1. Lorem ipsum dolor sit amet
  2. Consectetur adipiscing elit. This is a very long list item that will surely wrap onto the next line.
  3. Integer molestie lorem at massa

  Start numbering with offset:

  57. foo
  58. bar


Code

  Inline \`code\`

  Indented code

      // Some comments
      line 1 of code
      line 2 of code
      line 3 of code


  Block code "fences"

  \`\`\`
  Sample text here...
  \`\`\`

  Syntax highlighting

  \`\`\` js
  var foo = function (bar) {
    return bar++;
  };

  console.log(foo(5));
  \`\`\`


Tables

  | Option | Description |
  | ------ | ----------- |
  | data   | path to data files to supply the data that will be passed into templates. |
  | engine | engine to be used for processing templates. Handlebars is the default. |
  | ext    | extension to be used for dest files. |

  Right aligned columns

  | Option | Description |
  | ------:| -----------:|
  | data   | path to data files to supply the data that will be passed into templates. |
  | engine | engine to be used for processing templates. Handlebars is the default. |
  | ext    | extension to be used for dest files. |


Links

  [link text](https://www.google.com)

  [link with title](https://www.google.com "title text!")

  Autoconverted link https://www.google.com (enable linkify to see)


Images

  ![Minion](https://octodex.github.com/images/minion.png)
  ![Stormtroopocat](https://octodex.github.com/images/stormtroopocat.jpg "The Stormtroopocat")

  Like links, Images also have a footnote style syntax

  ![Alt text][id]

  With a reference later in the document defining the URL location:

  [id]: https://octodex.github.com/images/dojocat.jpg  "The Dojocat"


Typographic Replacements

  Enable typographer option to see result.

  (c) (C) (r) (R) (tm) (TM) (p) (P) +-

  test.. test... test..... test?..... test!....

  !!!!!! ???? ,,  -- ---

  "Smartypants, double quotes" and 'single quotes'

Rules and Styles

How to style stuff

Text styles are applied in a way that makes it much more convenient to manage changes to global styles while also allowing fine tuning of individual elements.

Think of the implementation like applying styles in CSS. changes to the body effect everything, but can be overwritten further down the style / component tree.

Be careful when styling 'text': the text rule is not applied to all rendered text, most notably list bullet points. If you want to, for instance, color all text, change the body style.

Example

import React from 'react';
import { SafeAreaView, ScrollView, StatusBar } from 'react-native';

import Markdown from 'react-native-markdown-display';

const copy = `
This is some text which is red because of the body style, which is also really small!

\`\`\`
//This is a code block woooo

const cool = () => {
  console.log('????');
};
\`\`\`

and some more small text

# This is a h1
## this is a h2
### this is a h3
`;

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}
        >
            <Markdown
              style={{
                body: {color: 'red', fontSize: 10},
                heading1: {color: 'purple'},
                code_block: {color: 'black', fontSize: 14}
              }}
            >
              {copy}
            </Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

Styles

Styles are used to override how certain rules are styled. The existing implementation is here

NOTE: By default styles are merged with the existing implementation, to change this, see the mergeStyle prop

Example Implementation

import React from 'react';
import { SafeAreaView, ScrollView, StatusBar, StyleSheet } from 'react-native';

import Markdown from 'react-native-markdown-display';

const styles = StyleSheet.create({
  heading1: {
    fontSize: 32,
    backgroundColor: '#000000',
    color: '#FFFFFF',
  },
  heading2: {
    fontSize: 24,
  },
  heading3: {
    fontSize: 18,
  },
  heading4: {
    fontSize: 16,
  },
  heading5: {
    fontSize: 13,
  },
  heading6: {
    fontSize: 11,
  }
});

const copy = `
# h1 Heading 8-)
## h2 Heading 8-)
### h3 Heading 8-)

| Option | Description |
| ------ | ----------- |
| data   | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext    | extension to be used for dest files. |
`;

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}
        >
            <Markdown
              style={styles}
            >
              {copy}
            </Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

Rules

Rules are used to specify how you want certain elements to be displayed. The existing implementation is here

Example Implementation

import React from 'react';
import { SafeAreaView, ScrollView, StatusBar, Text } from 'react-native';

import Markdown from 'react-native-markdown-display';

const rules = {
    heading1: (node, children, parent, styles) =>
      <Text key={node.key} style={[styles.heading, styles.heading1]}>
        >> H1 TEXT HERE >> "{children}"
      </Text>,
    heading2: (node, children, parent, styles) =>
      <Text key={node.key} style={[styles.heading, styles.heading2]}>
        >> H2 TEXT HERE >> "{children}"
      </Text>,
    heading3: (node, children, parent, styles) =>
      <Text key={node.key} style={[styles.heading, styles.heading3]}>
        >> H3 TEXT HERE >> "{children}"
      </Text>,
};

const copy = `
# h1 Heading 8-)
## h2 Heading 8-)
### h3 Heading 8-)

| Option | Description |
| ------ | ----------- |
| data   | path to data files to supply the data that will be passed into templates. |
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext    | extension to be used for dest files. |
`;

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}
        >
            <Markdown
              rules={rules}
            >
              {copy}
            </Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

All rules and their associated styles:

Render Rule Style(s)
body body
heading1 heading1
heading2 heading2
heading3 heading3
heading4 heading4
heading5 heading5
heading6 heading6
hr hr
strong strong
em em
s s
blockquote blockquote
bullet_list bullet_list
ordered_list ordered_list
list_item list_item - This is a special case that contains a set of pseudo classes that don't align to the render rule: ordered_list_icon, ordered_list_content, bullet_list_icon, bullet_list_content
code_inline code_inline
code_block code_block
fence fence
table table
thead thead
tbody tbody
th th
tr tr
td td
link link
blocklink blocklink
image image
text text
textgroup textgroup
paragraph paragraph
hardbreak hardbreak
softbreak softbreak
pre pre
inline inline
span span

Handling Links

Links, by default, will be handled with the import { Linking } from 'react-native'; import and Linking.openURL(url); call.

It is possible to overwrite this behaviour in one of two ways:

onLinkPress Callback

import React from 'react';
import { SafeAreaView, ScrollView, StatusBar } from 'react-native';

import Markdown from 'react-native-markdown-display';

const copy = `[This is a link!](https://github.com/iamacup/react-native-markdown-display/)`;

const onLinkPress = (url) => {
    if (url) {
      // some custom logic
      return false;
    }
    
    // return true to open with `Linking.openURL
    // return false to handle it yourself
    return true
  }

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}
        >
          <Markdown
             onLinkPress={onLinkPress}
          >
            {copy}
          </Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

Using a Custom Rule

You will need to overwrite one or both of link and blocklink, the original defenitions can be found here

Something like this with yourCustomHandlerFunctionOrLogicHere:

import React from 'react';
import { SafeAreaView, ScrollView, StatusBar, Text } from 'react-native';

import Markdown from 'react-native-markdown-display';

const copy = `[This is a link!](https://github.com/iamacup/react-native-markdown-display/)`;

const rules = {
  link: (node, children, parent, styles) => {
    return (
      <Text key={node.key} style={styles.link} onPress={() => yourCustomHandlerFunctionOrLogicHere(node.attributes.href) }>
        {children}
      </Text>
    );
  },
};

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}
        >
          <Markdown
             rules={rules}
          >
            {copy}
          </Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

Disabling Specific Types of Markdown

You can dissable any type of markdown you want, which is very useful in a mobile environment, by passing the markdownit property like below. Note that for convenience we also export the MarkdownIt instance so you don't have to include it as a project dependency directly just to remove some types of markdown.

This example will stop images and links.

import React from 'react';
import { SafeAreaView, ScrollView, StatusBar, Text } from 'react-native';

import Markdown, { MarkdownIt } from 'react-native-markdown-display';

const copy = `
# This heading will show with formatting

[but this link will just](be displayed as this text)
`;

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}
        >
            <Markdown
              markdownit={
                MarkdownIt({typographer: true}).disable([ 'link', 'image' ])
              }
            >
              {copy}
            </Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

A full list of things you can turn off is here

Pre Processing

It is possible to need to pre-process the data outside of this library (related discussion here). As a result, you can pass an AST tree directly as the children like this:

import React from 'react';
import { SafeAreaView, ScrollView, StatusBar, Text } from 'react-native';

import Markdown, { MarkdownIt, tokensToAST, stringToTokens } from 'react-native-markdown-display';

const markdownItInstance = MarkdownIt({typographer: true});

const copy = `
# Hello this is a title

This is some text with **BOLD!**
`;

const ast = tokensToAST(stringToTokens(copy, markdownItInstance))

const App: () => React$Node = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
      <SafeAreaView>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={{height: '100%'}}
        >
            <Markdown
            >
              {ast}
            </Markdown>
        </ScrollView>
      </SafeAreaView>
    </>
  );
};

export default App;

Other Notes

This is a fork of react-native-markdown-renderer, a library that unfortunately has not been updated for some time so i took all of the outstanding pull requests from that library and tested + merged as necessary.

react-native-markdown-display's People

Contributors

abirchall avatar aekaisato avatar agazso avatar benadamstyles avatar braincore avatar diakonos avatar doomsower avatar fiznool avatar gchallen avatar geastwood avatar iamacup avatar janrop avatar l-yeiser avatar lukeramsden avatar maxkomarychev avatar mientjan avatar milanbarande avatar pke avatar rajivshah3 avatar sebacampos avatar snyk-bot avatar trajano avatar tvrqvoise avatar vinayvenu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

react-native-markdown-display's Issues

6.1.x things

  1. We need to fix up the way list styles work in conjunction with the way paragraph / text styles are handled

#63
#61
#52

  1. Fix for multiple line breaks

#49

Is it possible to render markdown under <Text> </Text> tag ?

Hello people,
Can someone guide me that is it possible to use the code like above:

   <Text>
      <Markdown
        onLinkPress={() => alert('Link Clicked')}
        style={{ link: { color: 'blue' } }}
      >
        {body}
      </Markdown>
    </Text>

As i need to use this markdown functionality with native text component
@iamacup

How can I make the text fit the viewport?

With the following content variable:

const content = `voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture voiture`;

Using <Text />:

<Text>{content}</Text>

image

Using <Markdown />:

<Markdown>{content}</Markdown>

image

Local images don't render - not even alt text shown

The following markdown of a local image won't render anything, not even the provided alt text:

![MyImage](${require('./myImage.png')})

Images from urls do work for me, e.g.

![MyImage](https://octodex.github.com/images/minion.png)

Versions:

react-native-markdown-display: 6.1.1
react-native: 0.61.5

Tested on an iPhone 11 simulator with iOS 13.3

Are local image files supported? How to include them? Thanks!

Emojis

Hey!

I use markdown-it-emoji it creates a type called emoji so I create custom rule, example:

emoji: (node, children, parent) => {
			return (
				<Text key={node.key} style={styles.emoji} numberOfLines={numberOfLines}>
					{node.content}
				</Text>
			)
		},

What I wanted to apply is a unique style for emojis when there is only emoji (and other non-strings).

Example:
;) ;) ;) -> Only Emoji
;) -> Only Emoji
;) lorem -> Paragraph
;) ipsum -> Paragraph
🔢 -> only Emoji
🔢 lorem -> Paragraph

There is another case that I pass in the markdown is that the emoji already formatted can arrive and I would like it to pass the right rule (type: emoji) and not the paragraph.

I have this:

const renderOnlyEmoji = (key, text) => (
		<Text key={key} style={styles.emoji} numberOfLines={numberOfLines}>
			{text}
		</Text>
	)

	const rules = {
		emoji: (node, children, parent) => {
			if (this.isOnlyEmoji(node.content)) { // <- if I could get the formatted emoji here, it will work
				return renderOnlyEmoji(node.key, node.content)
			}

			return (
				<Text key={node.key} style={styles.text} numberOfLines={numberOfLines}>
					{node.content}
				</Text>
			)
		},
		paragraph: (node, children, parent) => {
			if (this.isOnlyEmoji(message.txt)) {
				return renderOnlyEmoji(node.key, message.txt)
			}

			return (
				<Text key={node.key} style={styles.text} numberOfLines={numberOfLines}>
					{children}
				</Text>
			)
		}
}

...

<Markdown
					rules={rules}
					style={styles}
					mergeStyle={true}
					markdownit={...}
				>
					{message.txt}
				</Markdown>

Upgrade 6.1 Build Error - Unable to resolve module ./lib/plugin/PluginContainer

Just upgraded from 6.01 to 6.1. Getting the following error:
error: Error: Unable to resolve module ./lib/plugin/PluginContainer from node_modules\react-native-markdown-display\src\index.js:

Platform:
Android
RN: 62.0
RN-Markdown-display: 6.1

Specific Language is very straightforward...getting content from Strapi and diplaying markdown content. Worked great prior to 6.1
import Markdown from 'react-native-markdown-display';
{item.content}

Steps taken:
Cleared Android Cache
Uninstall
Reinstall
Same error

Multiple new lines / line breaks are ignored

using following:

const copy = `
# h1 Heading 8-)
## h2 Heading 8-)
### h3 Heading 8-)

Just some randome text fto read here

\n\n\n

* one
* twoo
* threee
`;

const bodyStyles = StyleSheet.create({
  // eslint-disable-next-line react-native/no-unused-styles
   paragraph: {
     color: 'white',
     fontSize: 14,
     borderWidth: 1,
     borderColor: 'black',
     margin: 0,
     marginTop: 0,
     marginBottom: 0,
  },
  // eslint-disable-next-line react-native/no-unused-styles
  listUnorderedItemIcon: {
    color: 'white',
    fontSize: 14,
    lineHeight: 14,
    borderWidth: 1,
    borderColor: 'black',
    textAlign: 'center',
    alignSelf: 'center',
  },
  listItem: {
     borderColor: 'blue',
    borderWidth: 1,
  },
  listUnordered: {
    borderColor: 'yellow',
    borderWidth: 1,
  },
  listUnorderedItem: {
    borderColor: 'cyan',
    borderWidth: 1,
  }
});

There is no space between text and list during rendering.

Invalid prop `markdownit` of type `MarkdownIt`

On the web, ios and android (all together):

<MarkdownDisplay
  rules={rules}
  markdownit={MarkdownIt({
    linkify: true,
    typographer: true
  })}
  {...rest}
/>

This cause:

index.js:1 Warning: Failed prop type: Invalid prop `markdownit` of type `MarkdownIt` supplied to `<<anonymous>>`, expected instance of `MarkdownIt`.

Successive LineBreaks

@iamacup Thankyou for ur response!

const rules = {
  body: (node, children, parent, styles) => children,
  paragraph: (node, children, parent, styles) => children,
};

export const MarkdownText = ({ body, onLinkPress }) => (
  <Markdown
    markdownit={
      MarkdownIt({ typographer: true, linkify: true,breaks: true,
      }).disable(['blockquote', 'list', 'code'])
    }
    onLinkPress={(url) => onLinkPress(url)}
    style={{ link: { color: '#007BC7' } }}
    rules={rules}
  >
    {body}
  </Markdown>
);

This is the code block.
I want to handle multiple successive linebreaks in this scenario. Kindly guide me how can i achieve this.
Markdown is not displaying multiple linebreaks and ignoring multiple linebreaks during rendering

Originally posted by @MuhammadMattiullah in #49 (comment)

Setting allowFontScaling prop on <Text>

Hi! First off, thank you for this package.

I'm playing around with it in a React Native (Expo) app and I'm having trouble with font size. I'd like to disable font scaling but it doesn't seem like it's possible. I had a quick look through the code and in React Native itself and it seems like it could be related to a few things.

For example, the following code, unrelated to your package, will result in "Test" being rendered at a fixed size, regardless of your device's font size. That is, the disabling of the font scaling is working. If, however, I put the allowFontScaling on the inner <Text> only, it doesn't work.

<Text allowFontScaling={false}>
  <Text>Test</Text>
</Text>

So, I tried the following:

<Markdown
  rules={{
    text: (node, children, parent, styles, inheritedStyles = {}) => (
      <Text
        allowFontScaling={false}
        key={node.key}
        style={[inheritedStyles, styles.text]}
      >
        {node.content}
      </Text>
    ),
  }}
  style={markdownStyles}
>
  {content}
</Markdown>

As this doesn't work, I can only imagine it's related to the issue I mentioned above (the nested <Text> components). Hopefully I'm missing something here, though, and that there's an easy solution to disable all font scaling in my rendered markdown. If there's not, I think it'd be a great prop for the Markdown component itself, setting the property on all rendered <Text> components.

Anyway, I hope that was clear enough. Have a nice day. ✌️

Allow handing in pre-parsed AST

For my component I'd like to extract all the text links from the markdown to build an action sheet out of the links.

So I would like to pre-parse the markdown using markdown-it for all links and then hand in that AST to the component instead of a markdown-it prop.

I want to prevent thet parsing of the markdown twice, once in my component and second in yours.

Do you think that would be a possible addition?

Touchables and View within Link custom rule not working

Hi everyone! I found this library awesome and very useful so thanks for that!

I'm facing an issue when trying to override the default link rule with my custom Link component which basically renders the following:

<TouchableOpacity onPress={onLinkPressed}>
   <Text>{props.text}</Text>
</TouchableOpacity>

But I am not able to see anything being rendered
image

I'm overriding the default link rule like this:
link: (node: any): JSX.Element => <Link key={node.key} href={node.attributes.href} text={node.children[0].content} />,

I'm sure that props.text is defined and it has text content, the same code is working perfectly on the web (using react-native-web). Also, if I change the TouchableOpacity to a View component, it does not work either, the only way I was able to make it work is by just returning the inner <Text>{props.text}</Text>.

Thank you very much!

textAlign doesn't work

const markdownStyle = StyleSheet.create({
  body: {
    textAlign: 'justify',
    borderWidth: 1,
    borderColor: 'red'
  }
})

...

<Markdown style={markdownStyle}>{termsAndConditions}</Markdown>

No problem with the red border, although textAlign doesn't make any difference. I tried on other elements like text or heading, heading1 and I have the same behavior.
Any solution to this?

Links don't work

When there is no customCallback, links do not automatically work.

Sample test

<Markdown >{`[This is a link!](https://github.com/iamacup/react-native-markdown-display/)`}</Markdown>

Workaround

Add LInking.openURL to the callback.

<Markdown **onLinkPress={(url) => Linking.openURL(url)}** >{`[This is a link!](https://github.com/iamacup/react-native-markdown-display/)`}</MTMarkdown>

We look for existence of customCallBack in openURL.js, but the component definition already provides a default. This makes the else condition unreachable.

Text renderRule is not accepting textBreakStrategy prop

Since Android 10, textBreakStrategy="simple" is necessary for the text not to break in a way that can hide the last word of the text. Apparently, only the prop mentioned above solves this issue.

I tried adding this prop to the text renderRule like:

text: (node, children, parent, styles) => {
    return <Text key={node.key} textBreakStrategy="simple">{node.content}</Text>;
  },

But the prop is not being applied appropriately, or, at least, the text is still breaking. I have two questions:

  1. Am I missing something about how this is supposed to work?
  2. Is there a way to make sure this textBreakStrategy="simple" is applied?

Can I have markdown as a list?

I am concern about performance.

Will this package renders the marked texts as a loop or it parse from string ??

because if there the marked text renders as loop then may affect on performance, please someone help me and sure how this package works.

Images disappear when scrolling

The issue

When the markdown is rendered within a ScrollView, images within the markdown disappear as it scrolls. In versions prior to these changes, the images render consistently.

The reason

It looks like the commit made on November 6, 2019 where the deprecated lifecycle methods are removed is the culprit, but I'm not sure where the bug occurs. Any ideas?

Can't specify link color

I can change all other styles on a link like textDecorationLine and backgroundColor but the color property doesn't do anything.

On web (react-native-web) styles are ignored

Some of our content has headings.

I just noticed this now, but headings font size is not changed for headings when using React-native-web

This only happens in react-native-web, in react-native this seems to work.

In react native web, I see a warning generated.


Warning: Failed prop type: Invalid props.style key `fontSize` supplied to `View`.
Bad object: {
  "flexDirection": "row",
  "fontSize": 32
}

in View (at renderRules.js:88)

I am trying to follow that code, but
The comment in renderRules.js says:
// applying styles.heading and styles.headingX to the view is fine here because of style rollup we do in the AstRenderer.js file for text display items

I am only guessing, but AstRender looks for styles in a <View>, and it seems like in react-native, the View component allows (at least for now), to pass through unknown style directives, but in RNW -- this way of passing custom style directives does not work. Which is, perhaps, why styling is not work on the web now (it used to work before the fork).

The flexDirection and fontSize seem to be 'defaults' for Heading1 type.

Newlines in table columns via <br> not possible

In traditional Markdown html can be sprinkled here and there to get some behavior which isn't available with Markdown commands.

A thing I recently needed was the ability to force line-breaks inside table columns. This SO article suggests to use <br>. This also works in Markdown but does not in this library.

Property 'mergeStyle' does not exist on type 'IntrinsicAttributes & MarkdownProps & { children?: ReactNode; }'.

When using the mergeStyle prop using Markdown as in this example,

          <Markdown style={stylesMd} mergeStyle={true}>
                  {itemState.content}
          </Markdown>

a linting error is displayed claiming that
Property 'mergeStyle' does not exist on type 'IntrinsicAttributes & MarkdownProps & { children?: ReactNode; }'.

The program itself works fine, but it may be helpful to prevent this from showing.
I'm using VSCode.

How to apply style to main view?

Is there a way to apply style on the main view or is it impossible?

I am trying to do that:

<Markdown
  style={{
    marginVertical: 30,
    marginHorizontal: 10,
  }}
  {...rest}
/>

Styles from text seem to override styles for Headers

I tested this on both, Android and Web, and behavior seems to be the same.

If I specify a style , say, color: 'red' for ext, and color: 'green' for Header 1, everything is 'red' (including headers).
Same for fontSize.

Perhaps, I am mistaken, but I am thinking, that styles for 'text' should not override styles for other sections.


  render() {
    console.log('App::render');

    const localStyle={
      text: {color: 'red'}, //text should be red
      heading1: {fontSize:52, color: 'green'},//headings should be green
      
    }
    return (
      <ScrollView>
      <View>
        <Text> Mark Down with react-native-markdown-display </Text>
        <View style={{ flex: 1, margin:5,  borderWidth: 2 }}>
          <Markdown style={localStyle} markdownit={md}>
            {MD_TEST_DATA2}
          </Markdown>
        </View>
      </View>
      </ScrollView>
    );
  }

listUnorderedItem and other list styles do not work

tried applying following:

const bodyStyles = StyleSheet.create({
  listUnorderedItem:{
    color: 'yellow'
  },
  listUnordered: {
    color: 'green'
  },
  listItem: {
    color: 'white'
  },
});

But it has no effect.
The list item text still shows in black.

Other styles like paragraph, text, heading1, etc work fine.

Can't give a code_block custom style

I'm able to override the code_block with the following code.

rules = {
    code_block: (node, children, parent, style) => {
        return <Text>I am a code_block</Text>;
    }
}

<Markdown rules={rules}>
    {myString}
</Markdown>

However, I can't give code_block a custom style (for example, a different text color) with similar code, even though I can modify the style of other components.

style = {
    root: { color: "red" }, // works on its own
    code_block: { color: "red" } // doesn't work on its own
}

<Markdown style={style}>
    {myString}
</Markdown>

Any thoughts?
I'm doing this because I'm setting the "root" text color to be white, but the background color of the code_block is close to white, so it's impossible to read. I'd like to either change the text color or the background color of the code_block, but I can't seem to do it.

Remove the platform enum

It is really annoying to overwrite render rules if you have to include a platform enum that is not exported!

Need a way of turning off components

Because this is for mobile, we need a way of specifying - 'i don't want to support images' etc. - esp if this is library that prints out user content.

Plugins

How can add a plugin?
I want to embed a video in the markdown file. Which is currently not available in the package.

works on Web with react-native web

Thank you for taking the initiative to fork this.

Just wanted to report that your work, also works with react-native-web (so works on web across all modern browsers).

How to reduce line spacing in bullet list

Hi,

I have list:

- item 1
- item 2
- item 3

I need some help with styles:
I want reduce line spacing in bullet list

I try to modify styles bullet_list and bullet_list_content
I can’t change the distance between the lines...

how to I can change spacing in bullet list?

thank you!

Have issue with lib in expo app

Hi,
I am using expo v35 and trying to use this lib to display markdown elements but I got an error

ENOENT: no such file or directory, scandir 'project-root\node_modules\markdown-it\lib\common\node_modules\entities\lib\maps'

My component

import React, {Component} from 'react';
import {ScrollView} from 'react-native';
import Markdown from 'react-native-markdown-display';

export default class TermsAndConditions extends Component {
  state = {
    text: '',
  };


  constructor(props) {
    super(props);
    this.state.text = props.tc;
  }

  componentDidMount() {
  }

  render() {
    return (
      <ScrollView>
        <Markdown>{this.state.text}</Markdown>
      </ScrollView>
    )
  }
}

Can you help me with it?

Numbering in lists is wierd

By the spec, and with this example below, you can see the numbering always continues even though perhaps it should not

  Unordered

  + Create a list by starting a line with `+`, `-`, or `*`
  + Sub-lists are made by indenting 2 spaces:
    - Marker character change forces new list start:
      * Ac tristique libero volutpat at
      + Facilisis in pretium nisl aliquet
      - Nulla volutpat aliquam velit
  + Very easy!

  Ordered

  1. Lorem ipsum dolor sit amet
  2. Consectetur adipiscing elit
  3. Integer molestie lorem at massa


  1. You can use sequential numbers...
  1. ...or keep all the numbers as `1.`

  Start numbering with offset:

  57. foo
  1. bar
iOS Android

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.