@saiansh2525/react-native-nitro-markdown 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +468 -0
  3. package/android/CMakeLists.txt +40 -0
  4. package/android/build.gradle +92 -0
  5. package/android/gradle.properties +5 -0
  6. package/android/src/main/AndroidManifest.xml +4 -0
  7. package/android/src/main/cpp/cpp-adapter.cpp +7 -0
  8. package/android/src/main/java/com/margelo/nitro/com/nitromarkdown/HybridMarkdownSession.kt +61 -0
  9. package/android/src/main/java/com/nitromarkdown/NitroMarkdownPackage.kt +27 -0
  10. package/cpp/CMakeLists.txt +46 -0
  11. package/cpp/bindings/HybridMarkdownParser.cpp +114 -0
  12. package/cpp/bindings/HybridMarkdownParser.hpp +28 -0
  13. package/cpp/bindings/HybridMarkdownSession.cpp +0 -0
  14. package/cpp/core/MD4CParser.cpp +440 -0
  15. package/cpp/core/MD4CParser.hpp +21 -0
  16. package/cpp/core/MarkdownSessionCore.cpp +0 -0
  17. package/cpp/core/MarkdownTypes.hpp +124 -0
  18. package/cpp/md4c/md4c.c +6610 -0
  19. package/cpp/md4c/md4c.h +410 -0
  20. package/ios/HybridMarkdownSession.swift +64 -0
  21. package/lib/commonjs/Markdown.nitro.js +6 -0
  22. package/lib/commonjs/Markdown.nitro.js.map +1 -0
  23. package/lib/commonjs/MarkdownContext.js +17 -0
  24. package/lib/commonjs/MarkdownContext.js.map +1 -0
  25. package/lib/commonjs/MarkdownSession.js +11 -0
  26. package/lib/commonjs/MarkdownSession.js.map +1 -0
  27. package/lib/commonjs/default-markdown-renderer.js +217 -0
  28. package/lib/commonjs/default-markdown-renderer.js.map +1 -0
  29. package/lib/commonjs/headless.js +98 -0
  30. package/lib/commonjs/headless.js.map +1 -0
  31. package/lib/commonjs/index.js +226 -0
  32. package/lib/commonjs/index.js.map +1 -0
  33. package/lib/commonjs/markdown-stream.js +32 -0
  34. package/lib/commonjs/markdown-stream.js.map +1 -0
  35. package/lib/commonjs/markdown.js +385 -0
  36. package/lib/commonjs/markdown.js.map +1 -0
  37. package/lib/commonjs/package.json +1 -0
  38. package/lib/commonjs/renderers/blockquote.js +36 -0
  39. package/lib/commonjs/renderers/blockquote.js.map +1 -0
  40. package/lib/commonjs/renderers/code.js +99 -0
  41. package/lib/commonjs/renderers/code.js.map +1 -0
  42. package/lib/commonjs/renderers/heading.js +63 -0
  43. package/lib/commonjs/renderers/heading.js.map +1 -0
  44. package/lib/commonjs/renderers/horizontal-rule.js +29 -0
  45. package/lib/commonjs/renderers/horizontal-rule.js.map +1 -0
  46. package/lib/commonjs/renderers/image.js +184 -0
  47. package/lib/commonjs/renderers/image.js.map +1 -0
  48. package/lib/commonjs/renderers/link.js +35 -0
  49. package/lib/commonjs/renderers/link.js.map +1 -0
  50. package/lib/commonjs/renderers/list.js +114 -0
  51. package/lib/commonjs/renderers/list.js.map +1 -0
  52. package/lib/commonjs/renderers/math.js +137 -0
  53. package/lib/commonjs/renderers/math.js.map +1 -0
  54. package/lib/commonjs/renderers/paragraph.js +37 -0
  55. package/lib/commonjs/renderers/paragraph.js.map +1 -0
  56. package/lib/commonjs/renderers/table.js +290 -0
  57. package/lib/commonjs/renderers/table.js.map +1 -0
  58. package/lib/commonjs/specs/MarkdownSession.nitro.js +6 -0
  59. package/lib/commonjs/specs/MarkdownSession.nitro.js.map +1 -0
  60. package/lib/commonjs/theme.js +191 -0
  61. package/lib/commonjs/theme.js.map +1 -0
  62. package/lib/commonjs/use-markdown-stream.js +71 -0
  63. package/lib/commonjs/use-markdown-stream.js.map +1 -0
  64. package/lib/module/Markdown.nitro.js +4 -0
  65. package/lib/module/Markdown.nitro.js.map +1 -0
  66. package/lib/module/MarkdownContext.js +12 -0
  67. package/lib/module/MarkdownContext.js.map +1 -0
  68. package/lib/module/MarkdownSession.js +7 -0
  69. package/lib/module/MarkdownSession.js.map +1 -0
  70. package/lib/module/default-markdown-renderer.js +212 -0
  71. package/lib/module/default-markdown-renderer.js.map +1 -0
  72. package/lib/module/headless.js +90 -0
  73. package/lib/module/headless.js.map +1 -0
  74. package/lib/module/index.js +21 -0
  75. package/lib/module/index.js.map +1 -0
  76. package/lib/module/markdown-stream.js +27 -0
  77. package/lib/module/markdown-stream.js.map +1 -0
  78. package/lib/module/markdown.js +380 -0
  79. package/lib/module/markdown.js.map +1 -0
  80. package/lib/module/package.json +1 -0
  81. package/lib/module/renderers/blockquote.js +31 -0
  82. package/lib/module/renderers/blockquote.js.map +1 -0
  83. package/lib/module/renderers/code.js +93 -0
  84. package/lib/module/renderers/code.js.map +1 -0
  85. package/lib/module/renderers/heading.js +58 -0
  86. package/lib/module/renderers/heading.js.map +1 -0
  87. package/lib/module/renderers/horizontal-rule.js +24 -0
  88. package/lib/module/renderers/horizontal-rule.js.map +1 -0
  89. package/lib/module/renderers/image.js +179 -0
  90. package/lib/module/renderers/image.js.map +1 -0
  91. package/lib/module/renderers/link.js +30 -0
  92. package/lib/module/renderers/link.js.map +1 -0
  93. package/lib/module/renderers/list.js +107 -0
  94. package/lib/module/renderers/list.js.map +1 -0
  95. package/lib/module/renderers/math.js +131 -0
  96. package/lib/module/renderers/math.js.map +1 -0
  97. package/lib/module/renderers/paragraph.js +32 -0
  98. package/lib/module/renderers/paragraph.js.map +1 -0
  99. package/lib/module/renderers/table.js +285 -0
  100. package/lib/module/renderers/table.js.map +1 -0
  101. package/lib/module/specs/MarkdownSession.nitro.js +4 -0
  102. package/lib/module/specs/MarkdownSession.nitro.js.map +1 -0
  103. package/lib/module/theme.js +186 -0
  104. package/lib/module/theme.js.map +1 -0
  105. package/lib/module/use-markdown-stream.js +66 -0
  106. package/lib/module/use-markdown-stream.js.map +1 -0
  107. package/lib/typescript/commonjs/Markdown.nitro.d.ts +13 -0
  108. package/lib/typescript/commonjs/Markdown.nitro.d.ts.map +1 -0
  109. package/lib/typescript/commonjs/MarkdownContext.d.ts +65 -0
  110. package/lib/typescript/commonjs/MarkdownContext.d.ts.map +1 -0
  111. package/lib/typescript/commonjs/MarkdownSession.d.ts +4 -0
  112. package/lib/typescript/commonjs/MarkdownSession.d.ts.map +1 -0
  113. package/lib/typescript/commonjs/default-markdown-renderer.d.ts +10 -0
  114. package/lib/typescript/commonjs/default-markdown-renderer.d.ts.map +1 -0
  115. package/lib/typescript/commonjs/headless.d.ts +61 -0
  116. package/lib/typescript/commonjs/headless.d.ts.map +1 -0
  117. package/lib/typescript/commonjs/index.d.ts +22 -0
  118. package/lib/typescript/commonjs/index.d.ts.map +1 -0
  119. package/lib/typescript/commonjs/markdown-stream.d.ts +15 -0
  120. package/lib/typescript/commonjs/markdown-stream.d.ts.map +1 -0
  121. package/lib/typescript/commonjs/markdown.d.ts +60 -0
  122. package/lib/typescript/commonjs/markdown.d.ts.map +1 -0
  123. package/lib/typescript/commonjs/package.json +1 -0
  124. package/lib/typescript/commonjs/renderers/blockquote.d.ts +9 -0
  125. package/lib/typescript/commonjs/renderers/blockquote.d.ts.map +1 -0
  126. package/lib/typescript/commonjs/renderers/code.d.ts +19 -0
  127. package/lib/typescript/commonjs/renderers/code.d.ts.map +1 -0
  128. package/lib/typescript/commonjs/renderers/heading.d.ts +10 -0
  129. package/lib/typescript/commonjs/renderers/heading.d.ts.map +1 -0
  130. package/lib/typescript/commonjs/renderers/horizontal-rule.d.ts +8 -0
  131. package/lib/typescript/commonjs/renderers/horizontal-rule.d.ts.map +1 -0
  132. package/lib/typescript/commonjs/renderers/image.d.ts +13 -0
  133. package/lib/typescript/commonjs/renderers/image.d.ts.map +1 -0
  134. package/lib/typescript/commonjs/renderers/link.d.ts +10 -0
  135. package/lib/typescript/commonjs/renderers/link.d.ts.map +1 -0
  136. package/lib/typescript/commonjs/renderers/list.d.ts +26 -0
  137. package/lib/typescript/commonjs/renderers/list.d.ts.map +1 -0
  138. package/lib/typescript/commonjs/renderers/math.d.ts +14 -0
  139. package/lib/typescript/commonjs/renderers/math.d.ts.map +1 -0
  140. package/lib/typescript/commonjs/renderers/paragraph.d.ts +10 -0
  141. package/lib/typescript/commonjs/renderers/paragraph.d.ts.map +1 -0
  142. package/lib/typescript/commonjs/renderers/table.d.ts +12 -0
  143. package/lib/typescript/commonjs/renderers/table.d.ts.map +1 -0
  144. package/lib/typescript/commonjs/specs/MarkdownSession.nitro.d.ts +12 -0
  145. package/lib/typescript/commonjs/specs/MarkdownSession.nitro.d.ts.map +1 -0
  146. package/lib/typescript/commonjs/theme.d.ts +65 -0
  147. package/lib/typescript/commonjs/theme.d.ts.map +1 -0
  148. package/lib/typescript/commonjs/use-markdown-stream.d.ts +22 -0
  149. package/lib/typescript/commonjs/use-markdown-stream.d.ts.map +1 -0
  150. package/lib/typescript/module/Markdown.nitro.d.ts +13 -0
  151. package/lib/typescript/module/Markdown.nitro.d.ts.map +1 -0
  152. package/lib/typescript/module/MarkdownContext.d.ts +65 -0
  153. package/lib/typescript/module/MarkdownContext.d.ts.map +1 -0
  154. package/lib/typescript/module/MarkdownSession.d.ts +4 -0
  155. package/lib/typescript/module/MarkdownSession.d.ts.map +1 -0
  156. package/lib/typescript/module/default-markdown-renderer.d.ts +10 -0
  157. package/lib/typescript/module/default-markdown-renderer.d.ts.map +1 -0
  158. package/lib/typescript/module/headless.d.ts +61 -0
  159. package/lib/typescript/module/headless.d.ts.map +1 -0
  160. package/lib/typescript/module/index.d.ts +22 -0
  161. package/lib/typescript/module/index.d.ts.map +1 -0
  162. package/lib/typescript/module/markdown-stream.d.ts +15 -0
  163. package/lib/typescript/module/markdown-stream.d.ts.map +1 -0
  164. package/lib/typescript/module/markdown.d.ts +60 -0
  165. package/lib/typescript/module/markdown.d.ts.map +1 -0
  166. package/lib/typescript/module/package.json +1 -0
  167. package/lib/typescript/module/renderers/blockquote.d.ts +9 -0
  168. package/lib/typescript/module/renderers/blockquote.d.ts.map +1 -0
  169. package/lib/typescript/module/renderers/code.d.ts +19 -0
  170. package/lib/typescript/module/renderers/code.d.ts.map +1 -0
  171. package/lib/typescript/module/renderers/heading.d.ts +10 -0
  172. package/lib/typescript/module/renderers/heading.d.ts.map +1 -0
  173. package/lib/typescript/module/renderers/horizontal-rule.d.ts +8 -0
  174. package/lib/typescript/module/renderers/horizontal-rule.d.ts.map +1 -0
  175. package/lib/typescript/module/renderers/image.d.ts +13 -0
  176. package/lib/typescript/module/renderers/image.d.ts.map +1 -0
  177. package/lib/typescript/module/renderers/link.d.ts +10 -0
  178. package/lib/typescript/module/renderers/link.d.ts.map +1 -0
  179. package/lib/typescript/module/renderers/list.d.ts +26 -0
  180. package/lib/typescript/module/renderers/list.d.ts.map +1 -0
  181. package/lib/typescript/module/renderers/math.d.ts +14 -0
  182. package/lib/typescript/module/renderers/math.d.ts.map +1 -0
  183. package/lib/typescript/module/renderers/paragraph.d.ts +10 -0
  184. package/lib/typescript/module/renderers/paragraph.d.ts.map +1 -0
  185. package/lib/typescript/module/renderers/table.d.ts +12 -0
  186. package/lib/typescript/module/renderers/table.d.ts.map +1 -0
  187. package/lib/typescript/module/specs/MarkdownSession.nitro.d.ts +12 -0
  188. package/lib/typescript/module/specs/MarkdownSession.nitro.d.ts.map +1 -0
  189. package/lib/typescript/module/theme.d.ts +65 -0
  190. package/lib/typescript/module/theme.d.ts.map +1 -0
  191. package/lib/typescript/module/use-markdown-stream.d.ts +22 -0
  192. package/lib/typescript/module/use-markdown-stream.d.ts.map +1 -0
  193. package/nitro.json +19 -0
  194. package/nitrogen/generated/.gitattributes +1 -0
  195. package/nitrogen/generated/android/NitroMarkdown+autolinking.cmake +82 -0
  196. package/nitrogen/generated/android/NitroMarkdown+autolinking.gradle +27 -0
  197. package/nitrogen/generated/android/NitroMarkdownOnLoad.cpp +56 -0
  198. package/nitrogen/generated/android/NitroMarkdownOnLoad.hpp +25 -0
  199. package/nitrogen/generated/android/c++/JFunc_void.hpp +75 -0
  200. package/nitrogen/generated/android/c++/JHybridMarkdownSessionSpec.cpp +91 -0
  201. package/nitrogen/generated/android/c++/JHybridMarkdownSessionSpec.hpp +70 -0
  202. package/nitrogen/generated/android/kotlin/com/margelo/nitro/com/nitromarkdown/Func_void.kt +80 -0
  203. package/nitrogen/generated/android/kotlin/com/margelo/nitro/com/nitromarkdown/HybridMarkdownSessionSpec.kt +78 -0
  204. package/nitrogen/generated/android/kotlin/com/margelo/nitro/com/nitromarkdown/NitroMarkdownOnLoad.kt +35 -0
  205. package/nitrogen/generated/ios/NitroMarkdown+autolinking.rb +60 -0
  206. package/nitrogen/generated/ios/NitroMarkdown-Swift-Cxx-Bridge.cpp +41 -0
  207. package/nitrogen/generated/ios/NitroMarkdown-Swift-Cxx-Bridge.hpp +93 -0
  208. package/nitrogen/generated/ios/NitroMarkdown-Swift-Cxx-Umbrella.hpp +45 -0
  209. package/nitrogen/generated/ios/NitroMarkdownAutolinking.mm +43 -0
  210. package/nitrogen/generated/ios/NitroMarkdownAutolinking.swift +26 -0
  211. package/nitrogen/generated/ios/c++/HybridMarkdownSessionSpecSwift.cpp +11 -0
  212. package/nitrogen/generated/ios/c++/HybridMarkdownSessionSpecSwift.hpp +108 -0
  213. package/nitrogen/generated/ios/swift/Func_void.swift +47 -0
  214. package/nitrogen/generated/ios/swift/HybridMarkdownSessionSpec.swift +59 -0
  215. package/nitrogen/generated/ios/swift/HybridMarkdownSessionSpec_cxx.swift +190 -0
  216. package/nitrogen/generated/shared/c++/HybridMarkdownParserSpec.cpp +22 -0
  217. package/nitrogen/generated/shared/c++/HybridMarkdownParserSpec.hpp +65 -0
  218. package/nitrogen/generated/shared/c++/HybridMarkdownSessionSpec.cpp +26 -0
  219. package/nitrogen/generated/shared/c++/HybridMarkdownSessionSpec.hpp +67 -0
  220. package/nitrogen/generated/shared/c++/ParserOptions.hpp +87 -0
  221. package/package.json +134 -0
  222. package/react-native-nitro-markdown.podspec +42 -0
  223. package/src/Markdown.nitro.ts +12 -0
  224. package/src/MarkdownContext.ts +98 -0
  225. package/src/MarkdownSession.ts +8 -0
  226. package/src/default-markdown-renderer.tsx +261 -0
  227. package/src/headless.ts +171 -0
  228. package/src/index.ts +52 -0
  229. package/src/markdown-stream.tsx +32 -0
  230. package/src/markdown.tsx +521 -0
  231. package/src/renderers/blockquote.tsx +30 -0
  232. package/src/renderers/code.tsx +112 -0
  233. package/src/renderers/heading.tsx +66 -0
  234. package/src/renderers/horizontal-rule.tsx +23 -0
  235. package/src/renderers/image.tsx +204 -0
  236. package/src/renderers/link.tsx +33 -0
  237. package/src/renderers/list.tsx +123 -0
  238. package/src/renderers/math.tsx +147 -0
  239. package/src/renderers/paragraph.tsx +45 -0
  240. package/src/renderers/table.tsx +370 -0
  241. package/src/specs/MarkdownSession.nitro.ts +14 -0
  242. package/src/theme.ts +243 -0
  243. package/src/use-markdown-stream.ts +83 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-2026 João Paulo C. Marra
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,468 @@
1
+ <p align="center">
2
+ <img src="./readme/demo.gif" alt="react-native-nitro-markdown demo" width="300" />
3
+ <img src="./readme/stream-demo.gif" alt="react-native-nitro-markdown stream demo" width="300" />
4
+ </p>
5
+
6
+ # react-native-nitro-markdown 🚀
7
+
8
+ > The fastest Markdown parser for React Native. Period.
9
+
10
+ [![npm version](https://img.shields.io/npm/v/react-native-nitro-markdown?style=flat-square)](https://www.npmjs.com/package/react-native-nitro-markdown)
11
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square)](https://opensource.org/licenses/MIT)
12
+ [![Nitro Modules](https://img.shields.io/badge/Powered%20by-Nitro%20Modules-blueviolet?style=flat-square)](https://nitro.margelo.com)
13
+
14
+ **react-native-nitro-markdown** is a high-performance Markdown parser built on **[md4c](https://github.com/mity/md4c)** (C++) and **[Nitro Modules](https://nitro.margelo.com)**. It parses complex Markdown, GFM, and LaTeX Math into a structured AST **synchronously** via JSI, bypassing the React Native Bridge entirely.
15
+
16
+ ---
17
+
18
+ ## ⚡ Why Nitro? (Benchmarks)
19
+
20
+ We benchmarked this library against the most popular JavaScript parsers on a real mobile device (iPhone 15 Pro, Release Mode) using a heavy **237KB** Markdown document.
21
+
22
+ | Parser | Time (ms) | Speedup | Frame Drops (60fps) |
23
+ | :-------------------------- | :--------- | :---------------- | :-------------------- |
24
+ | **🚀 Nitro Markdown (C++)** | **~29 ms** | **1x (Baseline)** | **~1 frame** (Smooth) |
25
+ | 📋 CommonMark (JS) | ~82 ms | 2.8x slower | ~5 frames (Jank) |
26
+ | 🏗️ Markdown-It (JS) | ~118 ms | 4.0x slower | ~7 frames (Jank) |
27
+ | 💨 Marked (JS) | ~400 ms | 13.5x slower | ~24 frames (Freeze) |
28
+
29
+ > **Takeaway:** JavaScript parsers trigger Garbage Collection pauses. Nitro uses C++ to parse efficiently with zero-copy overhead, keeping your UI thread responsive.
30
+
31
+ ---
32
+
33
+ ## 📦 Installation
34
+
35
+ Choose your preferred package manager to install the package and its core dependency (`react-native-nitro-modules`).
36
+
37
+ ### **1. Install Dependencies**
38
+
39
+ **npm**
40
+
41
+ ```bash
42
+ npm install react-native-nitro-markdown react-native-nitro-modules
43
+ ```
44
+
45
+ > **Note:** If you want to use **Math** (LaTeX) or certain **Image** features, you should also install the optional peer dependencies:
46
+ > `npm install react-native-svg react-native-mathjax-svg`
47
+
48
+ **Yarn**
49
+
50
+ ```bash
51
+ yarn add react-native-nitro-markdown react-native-nitro-modules
52
+ ```
53
+
54
+ **Bun**
55
+
56
+ ```bash
57
+ bun add react-native-nitro-markdown react-native-nitro-modules
58
+ ```
59
+
60
+ **pnpm**
61
+
62
+ ```bash
63
+ pnpm add react-native-nitro-markdown react-native-nitro-modules
64
+ ```
65
+
66
+ ### **2. Install Native Pods (iOS)**
67
+
68
+ **Standard**
69
+
70
+ ```bash
71
+ cd ios && pod install
72
+ ```
73
+
74
+ ### **3. Expo Users**
75
+
76
+ If you are using Expo, you must run a **Prebuild** (Development Build) because this package contains native C++ code.
77
+
78
+ ```bash
79
+ bunx expo install react-native-nitro-markdown react-native-nitro-modules
80
+ bunx expo prebuild
81
+ ```
82
+
83
+ ---
84
+
85
+ ## 💻 Usage
86
+
87
+ ### Option 1: Batteries Included (Simplest)
88
+
89
+ Use the `Markdown` component with built-in premium dark-mode styling:
90
+
91
+ ```tsx
92
+ import { Markdown } from "react-native-nitro-markdown";
93
+
94
+ export function MyComponent() {
95
+ return (
96
+ <Markdown options={{ gfm: true }}>
97
+ {"# Hello World\nThis is **bold** text."}
98
+ </Markdown>
99
+ );
100
+ }
101
+ ```
102
+
103
+ ### Option 2: Light Theme / Theme Presets
104
+
105
+ The default theme is optimized for dark mode. For light backgrounds, use the provided `lightMarkdownTheme`:
106
+
107
+ ```tsx
108
+ import { Markdown, lightMarkdownTheme } from "react-native-nitro-markdown";
109
+
110
+ <Markdown theme={lightMarkdownTheme}>{"# Light Mode Markdown"}</Markdown>;
111
+ ```
112
+
113
+ Available presets:
114
+
115
+ - `defaultMarkdownTheme` / `darkMarkdownTheme` - Modern dark theme
116
+ - `lightMarkdownTheme` - Clean light theme
117
+ - `minimalMarkdownTheme` - Bare minimum styling for a clean slate
118
+
119
+ ### Option 3: Custom Theming
120
+
121
+ Customize the look and feel by passing a partial `theme` object:
122
+
123
+ ```tsx
124
+ import { Markdown } from "react-native-nitro-markdown";
125
+
126
+ const myTheme = {
127
+ colors: {
128
+ text: "#2D3748",
129
+ heading: "#1A202C",
130
+ link: "#3182CE",
131
+ },
132
+ fontFamilies: {
133
+ regular: "Inter",
134
+ heading: "Inter-Bold",
135
+ mono: "JetBrainsMono",
136
+ },
137
+ borderRadius: {
138
+ s: 4,
139
+ m: 8,
140
+ l: 16,
141
+ },
142
+ showCodeLanguage: true, // Toggle code language labels
143
+ };
144
+
145
+ <Markdown theme={myTheme}>{"# Custom Themed Markdown"}</Markdown>;
146
+ ```
147
+
148
+ **Theme Properties:**
149
+
150
+ - `colors` - All color tokens (text, heading, link, code, codeBackground, codeLanguage, etc.)
151
+ - `spacing` - Spacing tokens (xs, s, m, l, xl)
152
+ - `fontSizes` - Font sizes (xs, s, m, l, xl, h1-h6)
153
+ - `fontFamilies` - Font families for regular, heading, and mono text
154
+ - `borderRadius` - Border radius tokens (s, m, l)
155
+ - `showCodeLanguage` - Show/hide code block language labels
156
+
157
+ ### Option 4: Style Overrides per Node Type
158
+
159
+ Apply quick style overrides to specific node types without writing custom renderers:
160
+
161
+ ```tsx
162
+ <Markdown
163
+ styles={{
164
+ heading: { color: "red", fontWeight: "900" },
165
+ code_block: { backgroundColor: "#1a1a2e", borderRadius: 16 },
166
+ blockquote: { borderLeftColor: "#ff6b6b" },
167
+ }}
168
+ >
169
+ {markdown}
170
+ </Markdown>
171
+ ```
172
+
173
+ ### Option 5: Minimal Styling Strategy
174
+
175
+ Start with a clean slate using the `stylingStrategy` prop:
176
+
177
+ ```tsx
178
+ <Markdown stylingStrategy="minimal" theme={myLightTheme}>
179
+ {content}
180
+ </Markdown>
181
+ ```
182
+
183
+ This zeros out all spacing and removes opinionated colors, letting you build up from scratch.
184
+
185
+ ### Option 6: Custom Renderers
186
+
187
+ Override specific node types with full control. Custom renderers now receive **pre-mapped props** for common values:
188
+
189
+ ```tsx
190
+ import {
191
+ Markdown,
192
+ CodeBlock,
193
+ type HeadingRendererProps,
194
+ type CodeBlockRendererProps,
195
+ } from "react-native-nitro-markdown";
196
+
197
+ const renderers = {
198
+ // Pre-mapped `level` prop - no need for node.level!
199
+ heading: ({ level, children }: HeadingRendererProps) => (
200
+ <MyHeading level={level}>{children}</MyHeading>
201
+ ),
202
+
203
+ // Pre-mapped `content` and `language` - no getTextContent() needed!
204
+ code_block: ({ content, language }: CodeBlockRendererProps) => (
205
+ <CodeBlock
206
+ content={content}
207
+ language={language}
208
+ style={{ borderWidth: 2 }}
209
+ />
210
+ ),
211
+ };
212
+
213
+ <Markdown renderers={renderers} options={{ gfm: true }}>
214
+ {markdown}
215
+ </Markdown>;
216
+ ```
217
+
218
+ **Pre-mapped Props by Node Type:**
219
+
220
+ - `heading` → `level` (1-6)
221
+ - `link` → `href`, `title`
222
+ - `image` → `url`, `alt`, `title`
223
+ - `code_block` → `content`, `language`
224
+ - `code_inline` → `content`
225
+ - `list` → `ordered`, `start`
226
+ - `task_list_item` → `checked`
227
+
228
+ ### Option 7: Style Props on Individual Renderers
229
+
230
+ All built-in renderers accept a `style` prop for fine-grained overrides:
231
+
232
+ ```tsx
233
+ import { Heading, CodeBlock, InlineCode } from "react-native-nitro-markdown";
234
+
235
+ // Works in custom renderers
236
+ <Heading level={1} style={{ color: "hotpink" }}>Title</Heading>
237
+ <CodeBlock content={code} style={{ borderRadius: 0 }} />
238
+ <InlineCode style={{ backgroundColor: "#ff0" }}>code</InlineCode>
239
+ ```
240
+
241
+ ### Option 8: Auto Content Extraction for Code
242
+
243
+ The `CodeBlock` and `InlineCode` components now accept a `node` prop for automatic content extraction:
244
+
245
+ ```tsx
246
+ // Before: Manual extraction required
247
+ code_block: ({ node }) => (
248
+ <CodeBlock content={getTextContent(node)} language={node.language} />
249
+ );
250
+
251
+ // After: Just pass the node
252
+ code_block: ({ node }) => <CodeBlock node={node} />;
253
+
254
+ // Or use the pre-mapped content prop (recommended)
255
+ code_block: ({ content, language }) => (
256
+ <CodeBlock content={content} language={language} />
257
+ );
258
+ ```
259
+
260
+ ### Option 9: Headless (Minimal Bundle)
261
+
262
+ For maximum control, data processing, or minimal JS overhead:
263
+
264
+ ```tsx
265
+ import {
266
+ parseMarkdown,
267
+ getTextContent,
268
+ getFlattenedText,
269
+ } from "react-native-nitro-markdown/headless";
270
+
271
+ const ast = parseMarkdown("# Hello World");
272
+ const text = getTextContent(ast); // "Hello World"
273
+ const fullText = getFlattenedText(ast); // "Hello World\n\n" (Normalized with line breaks)
274
+ ```
275
+
276
+ ### Option 10: High-Performance Streaming (LLMs)
277
+
278
+ When streaming text token-by-token (e.g., from ChatGPT or Gemini):
279
+
280
+ ```tsx
281
+ import {
282
+ MarkdownStream,
283
+ useMarkdownSession,
284
+ } from "react-native-nitro-markdown";
285
+
286
+ export function AIResponseStream() {
287
+ const session = useMarkdownSession();
288
+
289
+ useEffect(() => {
290
+ session.getSession().append("Hello **Nitro**!");
291
+ return () => session.clear();
292
+ }, [session]);
293
+
294
+ return (
295
+ <MarkdownStream session={session.getSession()} options={{ gfm: true }} />
296
+ );
297
+ }
298
+ ```
299
+
300
+ ### Option 11: Extracting Plain Text
301
+
302
+ You can extract the plain text representation (with proper line breaks) using the `onParseComplete` callback. This is useful for "Copy All" buttons or TTS.
303
+
304
+ ```tsx
305
+ <Markdown
306
+ onParseComplete={(result) => {
307
+ console.log(result.text); // "Hello World\n\nThis is bold text."
308
+ console.log(result.ast); // Full AST
309
+ }}
310
+ >
311
+ {markdown}
312
+ </Markdown>
313
+ ```
314
+
315
+ ---
316
+
317
+ ## 🎨 Using Context in Custom Renderers
318
+
319
+ Access theme and context in custom renderers:
320
+
321
+ ```tsx
322
+ import {
323
+ useMarkdownContext,
324
+ MarkdownContext,
325
+ } from "react-native-nitro-markdown";
326
+
327
+ const MyCustomRenderer = ({ children }) => {
328
+ const { theme, stylingStrategy } = useMarkdownContext();
329
+
330
+ return <View style={{ padding: theme.spacing.m }}>{children}</View>;
331
+ };
332
+ ```
333
+
334
+ ---
335
+
336
+ ## 🛠️ Exported Utilities
337
+
338
+ ```tsx
339
+ // Parser and utilities
340
+ export {
341
+ parseMarkdown,
342
+ parseMarkdownWithOptions,
343
+ getTextContent,
344
+ getFlattenedText,
345
+ } from "./headless";
346
+
347
+ // Theme presets
348
+ export {
349
+ defaultMarkdownTheme,
350
+ lightMarkdownTheme,
351
+ darkMarkdownTheme,
352
+ minimalMarkdownTheme,
353
+ mergeThemes,
354
+ };
355
+
356
+ // Context
357
+ export { useMarkdownContext, MarkdownContext };
358
+
359
+ // Individual renderers
360
+ export {
361
+ Heading,
362
+ Paragraph,
363
+ Link,
364
+ Blockquote,
365
+ HorizontalRule,
366
+ CodeBlock,
367
+ InlineCode,
368
+ List,
369
+ ListItem,
370
+ TaskListItem,
371
+ TableRenderer,
372
+ Image,
373
+ MathInline,
374
+ MathBlock,
375
+ };
376
+ ```
377
+
378
+ ---
379
+
380
+ ## 🛠️ Headless vs. Non-Headless
381
+
382
+ | Feature | **Headless** (`/headless`) | **Non-Headless** (`default`) |
383
+ | :-------------- | :-------------------------- | :--------------------------------- |
384
+ | **Logic** | Raw C++ md4c Parser | Parser + Full UI Renderer |
385
+ | **Output** | JSON AST Tree | React Native Views |
386
+ | **Best For** | Search Indexing, Custom UIs | Fast Implementation, Documentation |
387
+ | **JS Overhead** | ~4 KB | ~60 KB |
388
+
389
+ ---
390
+
391
+ ### Basic Parsing API
392
+
393
+ The parsing is synchronous and instant. It returns a fully typed JSON AST:
394
+
395
+ ```typescript
396
+ import { parseMarkdown } from "react-native-nitro-markdown/headless";
397
+
398
+ const ast = parseMarkdown(`
399
+ # Hello World
400
+ This is **bold** text and a [link](https://github.com).
401
+ `);
402
+ ```
403
+
404
+ ### Options
405
+
406
+ | Option | Type | Default | Description |
407
+ | :----- | :-------- | :------ | :----------------------------------------------------------------------------- |
408
+ | `gfm` | `boolean` | `false` | Enable GitHub Flavored Markdown (Tables, Strikethrough, Autolinks, TaskLists). |
409
+ | `math` | `boolean` | `false` | Enable LaTeX Math support (`$` and `$$`). |
410
+
411
+ ---
412
+
413
+ ## 📐 AST Structure
414
+
415
+ The parser returns a `MarkdownNode` tree:
416
+
417
+ ```typescript
418
+ export interface MarkdownNode {
419
+ type: NodeType;
420
+ content?: string;
421
+ children?: MarkdownNode[];
422
+ level?: number;
423
+ href?: string;
424
+ checked?: boolean;
425
+ language?: string;
426
+ align?: "left" | "center" | "right";
427
+ isHeader?: boolean;
428
+ }
429
+ ```
430
+
431
+ ---
432
+
433
+ ## 🧮 LaTeX Math Support
434
+
435
+ We parse math delimiters (`$` and `$$`) natively using the `MD_FLAG_LATEXMATHSPANS` flag in `md4c`.
436
+
437
+ To render the math, use a library like `react-native-mathjax-svg`:
438
+
439
+ ```tsx
440
+ case 'math_inline':
441
+ return <MathView math={node.content} style={styles.math} />;
442
+ case 'math_block':
443
+ return <MathView math={node.content} style={styles.mathBlock} />;
444
+ ```
445
+
446
+ ---
447
+
448
+ ## 📊 Package Size
449
+
450
+ | Metric | Size |
451
+ | :------------------- | :------ |
452
+ | **Packed (tarball)** | ~75 kB |
453
+ | **Unpacked** | ~325 kB |
454
+ | **Total files** | 55 |
455
+
456
+ ---
457
+
458
+ ## 🤝 Contributing
459
+
460
+ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
461
+
462
+ ## 📄 License
463
+
464
+ MIT
465
+
466
+ ---
467
+
468
+ Built with ❤️ using [Nitro Modules](https://nitro.margelo.com) and [md4c](https://github.com/mity/md4c).
@@ -0,0 +1,40 @@
1
+ cmake_minimum_required(VERSION 3.22.1)
2
+ project(NitroMarkdown)
3
+
4
+ set(CMAKE_CXX_STANDARD 20)
5
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
6
+ set(CMAKE_C_STANDARD 11)
7
+ set(CMAKE_C_STANDARD_REQUIRED ON)
8
+
9
+ # Define the path to our C++ sources
10
+ set(CPP_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../cpp")
11
+
12
+ # Collect source files
13
+ file(GLOB MD4C_SOURCES "${CPP_ROOT}/md4c/*.c")
14
+ file(GLOB CORE_SOURCES "${CPP_ROOT}/core/*.cpp")
15
+ file(GLOB BINDING_SOURCES "${CPP_ROOT}/bindings/*.cpp")
16
+
17
+ # Create the shared library with our sources
18
+ add_library(${PROJECT_NAME} SHARED
19
+ ${MD4C_SOURCES}
20
+ ${CORE_SOURCES}
21
+ ${BINDING_SOURCES}
22
+ # JNI adapter
23
+ src/main/cpp/cpp-adapter.cpp
24
+ )
25
+
26
+ # Include directories
27
+ target_include_directories(${PROJECT_NAME} PRIVATE
28
+ "${CPP_ROOT}/md4c"
29
+ "${CPP_ROOT}/core"
30
+ "${CPP_ROOT}/bindings"
31
+ )
32
+
33
+ # Preprocessor definitions
34
+ target_compile_definitions(${PROJECT_NAME} PRIVATE
35
+ MD4C_USE_UTF8=1
36
+ )
37
+
38
+ # Include Nitro autolinking (adds nitrogen sources, definitions, and links)
39
+ include(${CMAKE_CURRENT_SOURCE_DIR}/../nitrogen/generated/android/NitroMarkdown+autolinking.cmake)
40
+
@@ -0,0 +1,92 @@
1
+ buildscript {
2
+ repositories {
3
+ google()
4
+ mavenCentral()
5
+ }
6
+
7
+ dependencies {
8
+ classpath "com.android.tools.build:gradle:8.10.1"
9
+ }
10
+ }
11
+
12
+ def reactNativeArchitectures() {
13
+ def value = rootProject.getProperties().get("reactNativeArchitectures")
14
+ return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
15
+ }
16
+
17
+ def isNewArchitectureEnabled() {
18
+ return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
19
+ }
20
+
21
+ apply plugin: "com.android.library"
22
+ apply plugin: 'org.jetbrains.kotlin.android'
23
+ apply from: '../nitrogen/generated/android/NitroMarkdown+autolinking.gradle'
24
+
25
+ if (isNewArchitectureEnabled()) {
26
+ apply plugin: "com.facebook.react"
27
+ }
28
+
29
+ def getExtOrDefault(name) {
30
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["NitroMarkdown_" + name]
31
+ }
32
+
33
+ def getExtOrIntegerDefault(name) {
34
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["NitroMarkdown_" + name]).toInteger()
35
+ }
36
+
37
+ android {
38
+ namespace "com.nitromarkdown"
39
+
40
+ ndkVersion getExtOrDefault("ndkVersion")
41
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
42
+
43
+ defaultConfig {
44
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
45
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
46
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
47
+
48
+ externalNativeBuild {
49
+ cmake {
50
+ cppFlags "-frtti -fexceptions -Wall -Wextra -fstack-protector-all"
51
+ arguments "-DANDROID_STL=c++_shared", "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
52
+ abiFilters (*reactNativeArchitectures())
53
+ }
54
+ }
55
+ }
56
+
57
+ externalNativeBuild {
58
+ cmake {
59
+ path "CMakeLists.txt"
60
+ }
61
+ }
62
+
63
+ buildFeatures {
64
+ buildConfig true
65
+ prefab true
66
+ }
67
+
68
+ compileOptions {
69
+ sourceCompatibility JavaVersion.VERSION_1_8
70
+ targetCompatibility JavaVersion.VERSION_1_8
71
+ }
72
+
73
+ sourceSets {
74
+ main {
75
+ java.srcDirs += ["src/main/java"]
76
+ if (isNewArchitectureEnabled()) {
77
+ java.srcDirs += ["${project.buildDir}/generated/source/codegen/java"]
78
+ }
79
+ }
80
+ }
81
+ }
82
+
83
+ repositories {
84
+ mavenCentral()
85
+ google()
86
+ }
87
+
88
+ dependencies {
89
+ //noinspection GradleDynamicVersion
90
+ implementation "com.facebook.react:react-native:+"
91
+ implementation project(":react-native-nitro-modules")
92
+ }
@@ -0,0 +1,5 @@
1
+ NitroMarkdown_compileSdkVersion=34
2
+ NitroMarkdown_minSdkVersion=24
3
+ NitroMarkdown_targetSdkVersion=34
4
+ NitroMarkdown_ndkVersion=27.1.12297006
5
+
@@ -0,0 +1,4 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="com.nitromarkdown">
3
+ </manifest>
4
+
@@ -0,0 +1,7 @@
1
+ #include <jni.h>
2
+ #include "NitroMarkdownOnLoad.hpp"
3
+
4
+ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*) {
5
+ return margelo::nitro::Markdown::initialize(vm);
6
+ }
7
+
@@ -0,0 +1,61 @@
1
+ package com.margelo.nitro.com.nitromarkdown
2
+
3
+ class HybridMarkdownSession : HybridMarkdownSessionSpec() {
4
+ private var buffer = StringBuilder()
5
+ private val listeners = mutableMapOf<Long, () -> Unit>()
6
+ private var nextListenerId = 0L
7
+ private val lock = Any()
8
+
9
+ override var highlightPosition: Double = 0.0
10
+ set(value) {
11
+ synchronized(lock) { field = value }
12
+ // No notify for highlighting to avoid flood
13
+ }
14
+
15
+
16
+
17
+ override val memorySize: Long
18
+ get() = buffer.length.toLong()
19
+
20
+ override fun append(chunk: String) {
21
+ synchronized(lock) {
22
+ buffer.append(chunk)
23
+ }
24
+ notifyListeners()
25
+ }
26
+
27
+ override fun clear() {
28
+ synchronized(lock) {
29
+ buffer.clear()
30
+ highlightPosition = 0.0
31
+ }
32
+ notifyListeners()
33
+ }
34
+
35
+ override fun getAllText(): String {
36
+ synchronized(lock) {
37
+ return buffer.toString()
38
+ }
39
+ }
40
+
41
+ override fun addListener(listener: () -> Unit): () -> Unit {
42
+ val id: Long
43
+ synchronized(lock) {
44
+ id = nextListenerId++
45
+ listeners[id] = listener
46
+ }
47
+ return {
48
+ synchronized(lock) {
49
+ listeners.remove(id)
50
+ }
51
+ }
52
+ }
53
+
54
+ private fun notifyListeners() {
55
+ val currentListeners: Collection<() -> Unit>
56
+ synchronized(lock) {
57
+ currentListeners = listeners.values.toList()
58
+ }
59
+ currentListeners.forEach { it() }
60
+ }
61
+ }