Skip to content

Instantly share code, notes, and snippets.

@yleflour
Created October 2, 2018 10:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yleflour/0f76a0b793e6c5516bb404d035a8326c to your computer and use it in GitHub Desktop.
Save yleflour/0f76a0b793e6c5516bb404d035a8326c to your computer and use it in GitHub Desktop.
import React from 'react';
import { Image, Text, View } from 'react-native';
function renderImage(node: any, output: any, state: any, styles: any) {
const { imageWrapper: wrapperStyle, image: imageStyle } = styles;
/**
* Prevent Native crash (View in Text) from occuring
*/
if (state.inline) {
// @TODO send a sentry bug report
console.warn('Trying to insert an image within text');
return null;
}
return (
<View
key={state.key}
style={
node.width || node.height
? [wrapperStyle, paddedSize(node, wrapperStyle)]
: wrapperStyle
}
>
<Image source={{ uri: node.target }} style={imageStyle} />
</View>
);
}
function paragraphRenderer() {
const renderText = textContentRenderer('paragraph');
return (node: any, output: any, state: any, styles: any) => {
if (
node.content instanceof Array &&
node.content.length === 1 &&
node.content[0].type === 'image'
) {
const imageNode = node.content[0];
return renderImage(imageNode, output, state, styles);
} else {
return renderText(node, output, state, styles);
}
};
}
function textContentRenderer(styleName: any, styleName2?: any) {
return (node: any, output: any, state: any, styles: any) => (
<Text
key={state.key}
style={
styleName2 ? [styles[styleName], styles[styleName2]] : styles[styleName]
}
>
{typeof node.content === 'string'
? node.content
: output(node.content, { ...state, inline: true })}
</Text>
);
}
function paddedSize(size: any, style: any) {
function either(a: any, b: any) {
return a === undefined ? b : a;
}
const {
padding = 0,
paddingLeft,
paddingRight,
paddingTop,
paddingBottom,
} = style;
return {
width:
size.width + either(paddingLeft, padding) + either(paddingRight, padding),
height:
size.height +
either(paddingTop, padding) +
either(paddingBottom, padding),
};
}
function renderListBullet(index: any, node: any, styles: any) {
return node.ordered ? (
<Text style={styles.listItemNumber}>{`${index + 1}.`}</Text>
) : (
<Text style={styles.listItemBullet}>
{styles.listItemBullet && styles.listItemBullet.content
? styles.listItemBullet.content
: '\u2022'}
</Text>
);
}
export const markdownRenderers = Object.freeze({
blockQuote: textContentRenderer('blockQuote'),
br: (node: any, output: any, state: any, styles: any) => (
<Text key={state.key} style={styles.br}>
{'\n\n'}
</Text>
),
codeBlock: textContentRenderer('codeBlock'),
del: textContentRenderer('del'),
em: textContentRenderer('em'),
heading: (node: any, output: any, state: any, styles: any) =>
textContentRenderer('heading', 'heading' + node.level)(
node,
output,
state,
styles
),
hr: (node: any, output: any, state: any, styles: any) => (
<View key={state.key} style={styles.hr} />
),
image: renderImage,
inlineCode: textContentRenderer('inlineCode'),
link: (node: any, output: any, state: any, styles: any) => {
const onPress = state.onLinkPress;
return (
<Text
key={state.key}
style={styles.link}
onPress={onPress ? () => onPress(node.target) : () => null}
>
{typeof node.content === 'string'
? node.content
: output(node.content, { ...state, inline: true })}
</Text>
);
},
list: (node: any, output: any, state: any, styles: any) => {
/**
* Prevent View in Text crash by checking if the render tree is
* already in a Text (inline) node
*/
if (state.inline) {
// @TODO send a sentry bug report
console.warn('Trying to insert a list within text');
return (
<Text>
{node.items.map((item: any, i: number) => (
<Text key={i}>
{renderListBullet(i, node, styles)}
<Text
style={
node.ordered
? styles.listItemOrderedContent
: styles.listItemUnorderedContent
}
>
{output(item, { ...state, inline: true })}
</Text>
</Text>
))}
</Text>
);
}
/**
* Render the list at root level
*/
return (
<View key={state.key} style={styles.list}>
{node.items.map((item: any, i: number) => (
<View key={i} style={styles.listItem}>
{renderListBullet(i, node, styles)}
<Text
style={
node.ordered
? styles.listItemOrderedContent
: styles.listItemUnorderedContent
}
>
{output(item, { ...state, inline: true })}
</Text>
</View>
))}
</View>
);
},
newline: (node: any, output: any, state: any, styles: any) => (
<Text key={state.key} style={styles.newline}>
{'\n'}
</Text>
),
paragraph: paragraphRenderer(),
strong: textContentRenderer('strong'),
text: textContentRenderer('text'),
u: textContentRenderer('u'),
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment