react-native-markdown-renderer
react-native-markdown-renderer copied to clipboard
Q: How can i use Syntax highlighting in React Native?
I can't find any examples for syntax highlighting in react native? How can i convert https://github.com/markdown-it/markdown-it#syntax-highlighting this example to react native?
I dont know what highlightjs is returning as a syntax. i need some time to delf in to this.
Thanks, @mientjan. I am also looking into that. I will tell if I figure it out.
@syedabuthahirm any news?
This is example code @mientjan. I changed syntax highlight rules to get the correct design.
import React, { Component } from 'react';
import {
Platform,
StyleSheet,
Image,
Text,
View,
ScrollView
} from 'react-native';
import Tip from "./tip";
import Markdown, {getUniqueID} from 'react-native-markdown-renderer'
import NativeSyntaxHighlighter from "./Higlighter"
import FitImage from 'react-native-fit-image'
const a = require('./2.gif')
const rules = {
fence: (node, children, parent, styles) =>
<View style={{ margin:5 }} key={getUniqueID()}>
<NativeSyntaxHighlighter
language="python"
customStyle={{ marginHorizontal:5, padding:7, borderRadius: 5 }}
highlighter="prism">
{node.content}
</NativeSyntaxHighlighter>
</View>,
image: (node, children, parent, styles) => {
return <Image style={{width: '50%', height: 250, borderColor: 'red', borderWidth: 4}} resizeMode="contain" key={getUniqueID()} source={node.attributes.src}/>
}
}
export default class App extends Component{
render() {
return (
<ScrollView>
<Markdown rules={rules}>{Tip}</Markdown>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
});
This is our core package file but I modified some imports statements to load the highlight content faster.
import React from 'react';
import { Text, ScrollView, Platform, View } from 'react-native';
import SyntaxHighlighterPrism, { registerLanguage } from "react-syntax-highlighter/prism-light";
import { createStyleObject } from 'react-syntax-highlighter/create-element';
import python from 'react-syntax-highlighter/languages/prism/python';
import dark from 'react-syntax-highlighter/styles/prism/tomorrow';
const styleCache = new Map();
registerLanguage('python', python);
const topLevelPropertiesToRemove = [
"Opacity",
"color",
"textShadow",
"textAlign",
"whiteSpace",
"wordSpacing",
"wordBreak",
"wordWrap",
"lineHeight",
"MozTabSize",
"OTabSize",
"tabSize",
"WebkitHyphens",
"MozHyphens",
"msHyphens",
"hyphens",
"fontFamily",
];
function generateNewStylesheet({ stylesheet, highlighter }) {
if (styleCache.has(stylesheet)) {
return styleCache.get(stylesheet);
}
const transformedStyle = Object.entries(stylesheet).reduce((newStylesheet, [className, style]) => {
newStylesheet[className] = Object.entries(style).reduce((newStyle, [key, value]) => {
if (key === 'overflowX' || key === "overflow") {
newStyle.overflow = value === 'auto' ? 'scroll' : value;
}
else if (value.includes('em')) {
const [num] = value.split('em');
newStyle[key] = Number(num) * 16;
}
else if (key === 'background') {
newStyle.backgroundColor = value;
}
else if (key === 'display') {
return newStyle;
}
else {
newStyle[key] = value;
}
return newStyle;
}, {});
return newStylesheet;
}, {});
const topLevel = highlighter === "prism" ? transformedStyle['pre[class*=\"language-\"]'] : transformedStyle.hljs;
const defaultColor = topLevel && topLevel.color || "#000";
topLevelPropertiesToRemove.forEach(property => {
if (topLevel[property]) {
delete topLevel[property];
}
});
if (topLevel.backgroundColor === "none") {
delete topLevel.backgroundColor;
}
const codeLevel = transformedStyle['code[class*=\"language-\"]'];
if (highlighter === "prism" && !!codeLevel) {
topLevelPropertiesToRemove.forEach(property => {
if (codeLevel[property]) {
delete codeLevel[property];
}
});
if (codeLevel.backgroundColor === "none") {
delete codeLevel.backgroundColor;
}
}
styleCache.set(stylesheet, { transformedStyle, defaultColor });
return { transformedStyle, defaultColor };
}
function createChildren({ stylesheet, fontSize, fontFamily }) {
let childrenCount = 0;
return (children, defaultColor) => {
childrenCount += 1;
return children.map((child, i) => createNativeElement({
node: child,
stylesheet,
key:`code-segment-${childrenCount}-${i}`,
defaultColor,
fontSize,
fontFamily
}));
}
}
function createNativeElement({ node, stylesheet, key, defaultColor, fontFamily, fontSize = 12 }) {
const { properties, type, tagName: TagName, value } = node;
const startingStyle = { fontFamily, fontSize, height: fontSize + 5 };
if (type === 'text') {
return (
<Text
key={key}
style={Object.assign({ color: defaultColor }, startingStyle)}
>
{value}
</Text>
);
} else if (TagName) {
const childrenCreator = createChildren({ stylesheet, fontSize, fontFamily });
const style = createStyleObject(
properties.className,
Object.assign(
{ color: defaultColor },
properties.style,
startingStyle
),
stylesheet
);
const children = childrenCreator(node.children, style.color || defaultColor);
return <Text key={key} style={style}>{children}</Text>;
}
}
function nativeRenderer({ defaultColor, fontFamily, fontSize }) {
return ({ rows, stylesheet }) => rows.map((node, i) => createNativeElement({
node,
stylesheet,
key: `code-segment-${i}`,
defaultColor,
fontFamily,
fontSize
}))
}
function NativeSyntaxHighlighter({
fontFamily,
fontSize,
children,
highlighter = "highlightjs",
style = dark,
...rest
}) {
const { transformedStyle, defaultColor } = generateNewStylesheet({
stylesheet: style,
highlighter
});
const Highlighter = (
highlighter === "prism"
?
SyntaxHighlighterPrism
:
SyntaxHighlighter
);
return (
<Highlighter
{...rest}
style={transformedStyle}
horizontal={true}
renderer={(nativeRenderer({
defaultColor,
fontFamily,
fontSize
}))}
>
{children}
</Highlighter>
);
}
NativeSyntaxHighlighter.defaultProps = {
fontFamily: Platform.OS === 'ios' ? 'Menlo-Regular' : 'monospace',
fontSize: 12,
PreTag: ScrollView,
CodeTag: View
};
export default NativeSyntaxHighlighter;