Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export default defineConfig([
},
},
rules: {
"react/prop-types": "off",
"react/react-in-jsx-scope": "off",
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "error",
Expand Down
90 changes: 76 additions & 14 deletions example/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@ import {
ActionSheetProvider,
useActionSheet,
} from "@expo/react-native-action-sheet";
import { Markdown } from "@react-native-remark";
import { themes } from "@react-native-remark";
import {
Markdown,
defaultRenderers,
remarkParse,
themes,
} from "@react-native-remark";
import {
createStaticNavigation,
useNavigation,
} from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import { StatusBar } from "expo-status-bar";
import { useEffect, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import {
ActivityIndicator,
Alert,
Expand All @@ -19,8 +23,16 @@ import {
ScrollView,
useColorScheme,
} from "react-native";
import rehypeParse from "rehype-parse";
import rehypeRemark from "rehype-remark";
import { PluggableList } from "unified";

import Mermaid from "./components/Mermaid";
import { sampleHTML } from "./samples/html";
import { mermaidMarkdown } from "./samples/mermaid";

const { defaultTheme, githubTheme, serifTheme } = themes;
const { CodeRenderer } = defaultRenderers;

const BASE_URL =
"https://raw.githubusercontent.com/imwithye/react-native-remark/refs/heads/main/markdown";
Expand All @@ -30,10 +42,23 @@ const HomeScreen = () => {
const colorScheme = useColorScheme();
const navigation = useNavigation();
const { showActionSheetWithOptions } = useActionSheet();
const [url, setUrl] = useState(URL);
const [markdown, setMarkdown] = useState("");
const [theme, setTheme] = useState(defaultTheme);
const [loading, setLoading] = useState(false);
const [plugins, setPlugins] = useState<PluggableList>();

const loadMarkdown = useCallback((url: string) => {
setLoading(true);

const controller = new AbortController();

fetch(url, { signal: controller.signal })
.then((res) => res.text())
.then((text) => setMarkdown(text))
.finally(() => setTimeout(() => setLoading(false), 1000));

return controller;
}, []);

useEffect(() => {
navigation.setOptions({
Expand Down Expand Up @@ -103,7 +128,15 @@ const HomeScreen = () => {
url: `${BASE_URL}/04_pytorch.md`,
},
{
title: "5. Load from URL",
title: "5. HTML",
url: "html-sample",
},
{
title: "6. Mermaid",
url: "mermaid-markdown",
},
{
title: "7. Load from URL",
url: "",
},
];
Expand All @@ -115,28 +148,47 @@ const HomeScreen = () => {
},
(idx?: number) => {
if (!idx || idx === cancelButtonIndex) return;

if (options[idx].url === "html-sample") {
setMarkdown(sampleHTML);
setPlugins([rehypeParse, rehypeRemark]);
return;
}

if (options[idx].url === "mermaid-markdown") {
setMarkdown(mermaidMarkdown);
setPlugins([remarkParse]);
return;
}

if (idx === options.length - 1) {
Alert.prompt("Load Markdown from URL", "", (url) => {
setUrl(url);
loadMarkdown(url);
});
return;
}
setUrl(options[idx].url);

setPlugins(undefined);
loadMarkdown(options[idx].url);
},
);
}}
/>
),
});
}, [colorScheme, navigation, showActionSheetWithOptions, setTheme, setUrl]);
}, [
colorScheme,
navigation,
showActionSheetWithOptions,
setTheme,
loadMarkdown,
]);

useEffect(() => {
setLoading(true);
fetch(url)
.then((res) => res.text())
.then((text) => setMarkdown(text))
.finally(() => setTimeout(() => setLoading(false), 1000));
}, [url]);
const controller = loadMarkdown(URL);

return controller.abort;
}, [loadMarkdown]);

return (
<ScrollView
Expand All @@ -153,6 +205,16 @@ const HomeScreen = () => {
<Markdown
markdown={markdown}
theme={theme}
remarkPlugins={plugins}
customRenderers={{
CodeRenderer: (props) => {
if (props.node.lang === "mermaid") {
return <Mermaid value={props.node.value} />;
}

return CodeRenderer(props);
},
}}
onLinkPress={(url) => Linking.openURL(url)}
/>
)}
Expand Down
57 changes: 57 additions & 0 deletions example/components/Mermaid.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { WebView } from "react-native-webview";

export default function Mermaid({ value }: { value: string }) {
return (
<WebView
style={{ height: 300, width: "100%" }}
source={{
html: `
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<script src="https://cdn.jsdelivr.net/npm/mermaid@11.12.0/dist/mermaid.min.js"></script>
<style>
body {
margin: 0;
padding: 16px;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.mermaid {
width: 100%;
display: flex;
justify-content: center;
}
.mermaid svg {
max-width: 100%;
height: auto;
}
</style>
</head>
<body>
<div class="mermaid">
${value}
</div>
<script>
mermaid.initialize({
startOnLoad: true,
theme: 'default',
flowchart: {
useMaxWidth: false,
htmlLabels: true
},
sequence: {
useMaxWidth: false
}
});
</script>
</body>
</html>
`,
}}
/>
);
}
5 changes: 4 additions & 1 deletion example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@
"expo-status-bar": "~2.2.3",
"react": "19.0.0",
"react-native": "0.79.4",
"react-native-remark": "file:../"
"react-native-remark": "file:../",
"react-native-webview": "^13.16.0",
"rehype-parse": "^9.0.1",
"rehype-remark": "^10.0.1"
},
"devDependencies": {
"@babel/core": "^7.25.2",
Expand Down
Loading