Benjamin-Dobell / react-native-markdown-view

MarkdownView for React Native
MIT License
190 stars 77 forks source link

Cannot get rule to work - need examples - please! #12

Open adrianstrahan opened 6 years ago

adrianstrahan commented 6 years ago

Hi, I am trying to write a new rule to allow '[ ]' sequences to be parsed and replaced with a box character (using FontAwesome). I have the following in my code:

<MarkdownView
    styles={{
        untickedCheckbox: {
          fontFamily: 'FontAwesome'
        }
      }}
    rules={{
        untickedCheckbox: {
            match: function(source, state, lookbehind) {
                return /^\[([\s]+?)\](?!\])/.exec(source);
            },
            parse: function(capture, recurseParse, state) {
                return {
                    content: [],
                };
            },
            render: (node, output, state, styles) => {
                <Text style={{fontFamily: 'FontAwesome'}}>&#xf096;</Text>
            }
        },
    }}
>{value}</MarkdownView>

My parse function doesn't need to do anything since the whole of the matched sequence is replaced with a react-native component. This is my input markdown:

[ ] This is an empty checkbox

All I get back is:

This is an empty checkbox

How can I get the component to appear?

Any examples on how to add a rule would be most helpful - I've gone through the simple-markdown code but can't get this to work. In fact, any help would be most appreciated.

v3yr0n commented 6 years ago

@adrianstrahan did you manage to do this? I'm trying to override the render method of newline.. Any idea of how can I do that? @Benjamin-Dobell

wilkerlucio commented 6 years ago

Sample problem here, an example of how to write actual rules would be great.

zzorba commented 6 years ago

Okay, after what took way too long reverse engineering the library, I managed to get this to work with some custom rules.. Caveat: the tags I was trying to parse out are leaf tags, a node about how I believe output should be used is at the end, but I haven't tested it.

Here is a sample rule definition just as an example to read a bold/italic html tag. This worked for me, but who knows if its the 'best' way or not.

const BoldHtmlTagRule = {
  match: SimpleMarkdown.anyScopeRegex(new RegExp('^<b>(.+?)<\\/b>')),
  order: 1,
  quality: () => 100,
  parse: (capture, nestedParse, state) => {
    return { text: capture[1] };
  },
  render: (node, output, state) => {
    return (
      <Text key={state.key} style={styles.boldText}>
        { node.text }
      </Text>
    );
  },
};
const ItalicHtmlTagRule = {
  match: SimpleMarkdown.anyScopeRegex(new RegExp('^<i>(.+?)<\\/i>')),
  order: 1,
  quality: () => 100,
  parse: (capture, nestedParse, state) => {
    return { text: capture[1] };
  },
  render: (node, output, state) => {
    return (
      <Text key={state.key} style={styles.italicText}>
        { node.text }
      </Text>
    );
  },
};

And here is how I invoke the MarkdownView component.

<MarkdownView
  rules={{
    bTag: BoldHtmlTagRule,
    iTag: ItalicHtmlTagRule,
  }}
>
  { this.props.text }
</MarkdownView>

This works, with one caveat -- it produces a warning about the order key failing a propType match. Order controls when the rule gets applied, and the simple-markdown library seems to need it. Lower means it runs first, so by putting in 1 my rules run first (what I want, but maybe not what you want).

Without the undocumented order key it fails, but if you put it in it complains that its not a function. If you make it a function it fails. I can't pinpoint where the validation error comes from, so I just ignored it.

Now, if the custom rule you are trying to implement wraps nested content, you want to return a tag and then call output(node.nestedTextYouParsedOut, state) to ensure the tree keeps getting built. I didn't have to do this for my simple use case.

Hope this helps.

jiku commented 6 years ago

@adrianstrahan maybe you're just missing return for <Text/> in render, or FontAwesome isn't available? This works here

const untickedCheckbox = {
  match: (source, state, lookbehind) => /^\[([\s]+?)\](?!\])/.exec(source),
  parse: (capture, recurseParse, state) => ({ content: [] }),
  render: (node, output, state, styles) => <Text style={{fontSize: 30}}>&#xf096;</Text>
}

// ...

<MarkdownView rules={{ untickedCheckbox }}> // ...
mmckinley8 commented 1 year ago

I'm also having this issue, I can't even get any of the parameters to print in the render function