react-native-enriched-markdown 0.1.0 → 0.1.1

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 (211) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +479 -0
  3. package/ReactNativeEnrichedMarkdown.podspec +27 -0
  4. package/android/build.gradle +101 -0
  5. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +39 -0
  6. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +21 -0
  7. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp +22 -0
  8. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.h +24 -0
  9. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +24 -0
  10. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +25 -0
  11. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +57 -0
  12. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +1164 -0
  13. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ShadowNodes.cpp +17 -0
  14. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ShadowNodes.h +32 -0
  15. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/States.cpp +16 -0
  16. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/States.h +20 -0
  17. package/android/gradle.properties +5 -0
  18. package/android/src/main/AndroidManifest.xml +2 -0
  19. package/android/src/main/baseline-prof.txt +65 -0
  20. package/android/src/main/cpp/jni-adapter.cpp +203 -0
  21. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +153 -0
  22. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextLayoutManager.kt +30 -0
  23. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +119 -0
  24. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextPackage.kt +17 -0
  25. package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +165 -0
  26. package/android/src/main/java/com/swmansion/enriched/markdown/events/LinkPressEvent.kt +23 -0
  27. package/android/src/main/java/com/swmansion/enriched/markdown/parser/MarkdownASTNode.kt +29 -0
  28. package/android/src/main/java/com/swmansion/enriched/markdown/parser/Parser.kt +48 -0
  29. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockStyleContext.kt +166 -0
  30. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt +89 -0
  31. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeBlockRenderer.kt +105 -0
  32. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeRenderer.kt +35 -0
  33. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/DocumentRenderer.kt +15 -0
  34. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/EmphasisRenderer.kt +26 -0
  35. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +54 -0
  36. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ImageRenderer.kt +52 -0
  37. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LineBreakRenderer.kt +15 -0
  38. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LinkRenderer.kt +28 -0
  39. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListContextManager.kt +105 -0
  40. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListItemRenderer.kt +58 -0
  41. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListRenderer.kt +69 -0
  42. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/NodeRenderer.kt +99 -0
  43. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ParagraphRenderer.kt +66 -0
  44. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/Renderer.kt +95 -0
  45. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +85 -0
  46. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/StrongRenderer.kt +26 -0
  47. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/TextRenderer.kt +29 -0
  48. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ThematicBreakRenderer.kt +44 -0
  49. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BaseListSpan.kt +136 -0
  50. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt +135 -0
  51. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBackgroundSpan.kt +180 -0
  52. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBlockSpan.kt +196 -0
  53. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeSpan.kt +27 -0
  54. package/android/src/main/java/com/swmansion/enriched/markdown/spans/EmphasisSpan.kt +34 -0
  55. package/android/src/main/java/com/swmansion/enriched/markdown/spans/HeadingSpan.kt +38 -0
  56. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ImageSpan.kt +320 -0
  57. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LineHeightSpan.kt +36 -0
  58. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LinkSpan.kt +37 -0
  59. package/android/src/main/java/com/swmansion/enriched/markdown/spans/MarginBottomSpan.kt +76 -0
  60. package/android/src/main/java/com/swmansion/enriched/markdown/spans/OrderedListSpan.kt +87 -0
  61. package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrongSpan.kt +37 -0
  62. package/android/src/main/java/com/swmansion/enriched/markdown/spans/TextSpan.kt +26 -0
  63. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ThematicBreakSpan.kt +69 -0
  64. package/android/src/main/java/com/swmansion/enriched/markdown/spans/UnorderedListSpan.kt +69 -0
  65. package/android/src/main/java/com/swmansion/enriched/markdown/styles/BaseBlockStyle.kt +10 -0
  66. package/android/src/main/java/com/swmansion/enriched/markdown/styles/BlockquoteStyle.kt +48 -0
  67. package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeBlockStyle.kt +51 -0
  68. package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeStyle.kt +21 -0
  69. package/android/src/main/java/com/swmansion/enriched/markdown/styles/EmphasisStyle.kt +17 -0
  70. package/android/src/main/java/com/swmansion/enriched/markdown/styles/HeadingStyle.kt +29 -0
  71. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ImageStyle.kt +21 -0
  72. package/android/src/main/java/com/swmansion/enriched/markdown/styles/InlineImageStyle.kt +17 -0
  73. package/android/src/main/java/com/swmansion/enriched/markdown/styles/LinkStyle.kt +19 -0
  74. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ListStyle.kt +54 -0
  75. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ParagraphStyle.kt +29 -0
  76. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StrongStyle.kt +17 -0
  77. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt +180 -0
  78. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleParser.kt +75 -0
  79. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ThematicBreakStyle.kt +23 -0
  80. package/android/src/main/java/com/swmansion/enriched/markdown/utils/AsyncDrawable.kt +91 -0
  81. package/android/src/main/java/com/swmansion/enriched/markdown/utils/HTMLGenerator.kt +809 -0
  82. package/android/src/main/java/com/swmansion/enriched/markdown/utils/MarkdownExtractor.kt +365 -0
  83. package/android/src/main/java/com/swmansion/enriched/markdown/utils/SelectionActionMode.kt +139 -0
  84. package/android/src/main/java/com/swmansion/enriched/markdown/utils/Utils.kt +181 -0
  85. package/android/src/main/jni/CMakeLists.txt +82 -0
  86. package/android/src/main/jni/EnrichedMarkdownTextSpec.cpp +21 -0
  87. package/android/src/main/jni/EnrichedMarkdownTextSpec.h +25 -0
  88. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextComponentDescriptor.h +29 -0
  89. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextMeasurementManager.cpp +45 -0
  90. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextMeasurementManager.h +21 -0
  91. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.cpp +33 -0
  92. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.h +49 -0
  93. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextState.cpp +9 -0
  94. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextState.h +25 -0
  95. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/conversions.h +19 -0
  96. package/cpp/md4c/md4c.c +6492 -0
  97. package/cpp/md4c/md4c.h +402 -0
  98. package/cpp/parser/MD4CParser.cpp +314 -0
  99. package/cpp/parser/MD4CParser.hpp +23 -0
  100. package/cpp/parser/MarkdownASTNode.hpp +49 -0
  101. package/ios/EnrichedMarkdownText.h +18 -0
  102. package/ios/EnrichedMarkdownText.mm +1074 -0
  103. package/ios/attachments/ImageAttachment.h +23 -0
  104. package/ios/attachments/ImageAttachment.m +185 -0
  105. package/ios/attachments/ThematicBreakAttachment.h +15 -0
  106. package/ios/attachments/ThematicBreakAttachment.m +33 -0
  107. package/ios/generated/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp +22 -0
  108. package/ios/generated/EnrichedMarkdownTextSpec/ComponentDescriptors.h +24 -0
  109. package/ios/generated/EnrichedMarkdownTextSpec/EventEmitters.cpp +24 -0
  110. package/ios/generated/EnrichedMarkdownTextSpec/EventEmitters.h +25 -0
  111. package/ios/generated/EnrichedMarkdownTextSpec/Props.cpp +57 -0
  112. package/ios/generated/EnrichedMarkdownTextSpec/Props.h +1164 -0
  113. package/ios/generated/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +20 -0
  114. package/ios/generated/EnrichedMarkdownTextSpec/ShadowNodes.cpp +17 -0
  115. package/ios/generated/EnrichedMarkdownTextSpec/ShadowNodes.h +32 -0
  116. package/ios/generated/EnrichedMarkdownTextSpec/States.cpp +16 -0
  117. package/ios/generated/EnrichedMarkdownTextSpec/States.h +20 -0
  118. package/ios/internals/EnrichedMarkdownTextComponentDescriptor.h +19 -0
  119. package/ios/internals/EnrichedMarkdownTextShadowNode.h +43 -0
  120. package/ios/internals/EnrichedMarkdownTextShadowNode.mm +85 -0
  121. package/ios/internals/EnrichedMarkdownTextState.h +24 -0
  122. package/ios/parser/MarkdownASTNode.h +33 -0
  123. package/ios/parser/MarkdownASTNode.m +32 -0
  124. package/ios/parser/MarkdownParser.h +8 -0
  125. package/ios/parser/MarkdownParser.mm +13 -0
  126. package/ios/parser/MarkdownParserBridge.mm +110 -0
  127. package/ios/renderer/AttributedRenderer.h +9 -0
  128. package/ios/renderer/AttributedRenderer.m +119 -0
  129. package/ios/renderer/BlockquoteRenderer.h +7 -0
  130. package/ios/renderer/BlockquoteRenderer.m +159 -0
  131. package/ios/renderer/CodeBlockRenderer.h +10 -0
  132. package/ios/renderer/CodeBlockRenderer.m +89 -0
  133. package/ios/renderer/CodeRenderer.h +10 -0
  134. package/ios/renderer/CodeRenderer.m +60 -0
  135. package/ios/renderer/EmphasisRenderer.h +6 -0
  136. package/ios/renderer/EmphasisRenderer.m +96 -0
  137. package/ios/renderer/HeadingRenderer.h +7 -0
  138. package/ios/renderer/HeadingRenderer.m +98 -0
  139. package/ios/renderer/ImageRenderer.h +12 -0
  140. package/ios/renderer/ImageRenderer.m +62 -0
  141. package/ios/renderer/LinkRenderer.h +7 -0
  142. package/ios/renderer/LinkRenderer.m +69 -0
  143. package/ios/renderer/ListItemRenderer.h +16 -0
  144. package/ios/renderer/ListItemRenderer.m +91 -0
  145. package/ios/renderer/ListRenderer.h +13 -0
  146. package/ios/renderer/ListRenderer.m +67 -0
  147. package/ios/renderer/NodeRenderer.h +8 -0
  148. package/ios/renderer/ParagraphRenderer.h +7 -0
  149. package/ios/renderer/ParagraphRenderer.m +69 -0
  150. package/ios/renderer/RenderContext.h +88 -0
  151. package/ios/renderer/RenderContext.m +248 -0
  152. package/ios/renderer/RendererFactory.h +12 -0
  153. package/ios/renderer/RendererFactory.m +110 -0
  154. package/ios/renderer/StrongRenderer.h +6 -0
  155. package/ios/renderer/StrongRenderer.m +83 -0
  156. package/ios/renderer/TextRenderer.h +6 -0
  157. package/ios/renderer/TextRenderer.m +16 -0
  158. package/ios/renderer/ThematicBreakRenderer.h +5 -0
  159. package/ios/renderer/ThematicBreakRenderer.m +53 -0
  160. package/ios/styles/StyleConfig.h +228 -0
  161. package/ios/styles/StyleConfig.mm +1467 -0
  162. package/ios/utils/BlockquoteBorder.h +20 -0
  163. package/ios/utils/BlockquoteBorder.m +92 -0
  164. package/ios/utils/CodeBackground.h +19 -0
  165. package/ios/utils/CodeBackground.m +191 -0
  166. package/ios/utils/CodeBlockBackground.h +17 -0
  167. package/ios/utils/CodeBlockBackground.m +87 -0
  168. package/ios/utils/EditMenuUtils.h +22 -0
  169. package/ios/utils/EditMenuUtils.m +118 -0
  170. package/ios/utils/FontUtils.h +20 -0
  171. package/ios/utils/FontUtils.m +13 -0
  172. package/ios/utils/HTMLGenerator.h +20 -0
  173. package/ios/utils/HTMLGenerator.m +779 -0
  174. package/ios/utils/LastElementUtils.h +53 -0
  175. package/ios/utils/ListMarkerDrawer.h +15 -0
  176. package/ios/utils/ListMarkerDrawer.m +127 -0
  177. package/ios/utils/MarkdownExtractor.h +17 -0
  178. package/ios/utils/MarkdownExtractor.m +295 -0
  179. package/ios/utils/ParagraphStyleUtils.h +13 -0
  180. package/ios/utils/ParagraphStyleUtils.m +56 -0
  181. package/ios/utils/PasteboardUtils.h +36 -0
  182. package/ios/utils/PasteboardUtils.m +134 -0
  183. package/ios/utils/RTFExportUtils.h +24 -0
  184. package/ios/utils/RTFExportUtils.m +297 -0
  185. package/ios/utils/RuntimeKeys.h +38 -0
  186. package/ios/utils/RuntimeKeys.m +11 -0
  187. package/ios/utils/TextViewLayoutManager.h +14 -0
  188. package/ios/utils/TextViewLayoutManager.mm +113 -0
  189. package/lib/module/EnrichedMarkdownText.js +34 -0
  190. package/lib/module/EnrichedMarkdownText.js.map +1 -0
  191. package/lib/module/EnrichedMarkdownTextNativeComponent.ts +130 -0
  192. package/lib/module/index.js +5 -0
  193. package/lib/module/index.js.map +1 -0
  194. package/lib/module/normalizeMarkdownStyle.js +340 -0
  195. package/lib/module/normalizeMarkdownStyle.js.map +1 -0
  196. package/lib/module/package.json +1 -0
  197. package/lib/typescript/package.json +1 -0
  198. package/lib/typescript/src/EnrichedMarkdownText.d.ts +101 -0
  199. package/lib/typescript/src/EnrichedMarkdownText.d.ts.map +1 -0
  200. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +111 -0
  201. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -0
  202. package/lib/typescript/src/index.d.ts +5 -0
  203. package/lib/typescript/src/index.d.ts.map +1 -0
  204. package/lib/typescript/src/normalizeMarkdownStyle.d.ts +6 -0
  205. package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -0
  206. package/package.json +186 -1
  207. package/react-native.config.js +13 -0
  208. package/src/EnrichedMarkdownText.tsx +152 -0
  209. package/src/EnrichedMarkdownTextNativeComponent.ts +130 -0
  210. package/src/index.tsx +7 -0
  211. package/src/normalizeMarkdownStyle.ts +377 -0
package/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Software Mansion
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,479 @@
1
+ <img src="https://github.com/user-attachments/assets/76e00153-6ae6-4a1a-bbbb-a8f7646aa1b5" alt="react-native-enriched-markdown by Software Mansion" width="100%">
2
+
3
+ # react-native-enriched-markdown
4
+
5
+ `react-native-enriched-markdown` is a powerful React Native library that renders Markdown content as native text:
6
+
7
+ - ⚡ Fully native text rendering (no WebView)
8
+ - 🎯 High-performance Markdown parsing with [md4c](https://github.com/mity/md4c)
9
+ - 📐 CommonMark standard compliant
10
+ - 🎨 Fully customizable styles for all elements
11
+ - 📱 iOS and Android support
12
+ - 🏛 Supports only the New Architecture (Fabric)
13
+ - ✨ Text selection and copy support
14
+ - 🔗 Interactive link handling
15
+ - 🖼️ Native image interactions (iOS: Copy, Save to Camera Roll)
16
+ - 🌐 Native platform features (Translate, Look Up, Search Web, Share)
17
+
18
+ Since 2012 [Software Mansion](https://swmansion.com) is a software agency with experience in building web and mobile apps. We are Core React Native Contributors and experts in dealing with all kinds of React Native issues.
19
+ We can help you build your next dream product –
20
+ [Hire us](https://swmansion.com/contact/projects?utm_source=react-native-enriched-markdown&utm_medium=readme).
21
+
22
+ ## Table of Contents
23
+
24
+ - [Prerequisites](#prerequisites)
25
+ - [Installation](#installation)
26
+ - [Usage](#usage)
27
+ - [Supported Markdown Elements](#supported-markdown-elements)
28
+ - [Link Handling](#link-handling)
29
+ - [Copy Options](#copy-options)
30
+ - [Styling Architecture](#styling-architecture)
31
+ - [Customizing Styles](#customizing-styles)
32
+ - [API Reference](#api-reference)
33
+ - [Contributing](#contributing)
34
+ - [License](#license)
35
+
36
+ ## Prerequisites
37
+
38
+ - `react-native-enriched-markdown` currently supports only Android and iOS platforms
39
+ - It works only with [the React Native New Architecture (Fabric)](https://reactnative.dev/architecture/landing-page) and supports following React Native releases: `0.81`, `0.82` and `0.83`
40
+
41
+ ## Installation
42
+
43
+ ### Bare React Native app
44
+
45
+ #### 1. Install the library
46
+
47
+ ```sh
48
+ yarn add react-native-enriched-markdown
49
+ ```
50
+
51
+ #### 2. Install iOS dependencies
52
+
53
+ The library includes native code so you will need to re-build the native app.
54
+
55
+ ```sh
56
+ cd ios && bundle install && bundle exec pod install
57
+ ```
58
+
59
+ ### Expo app
60
+
61
+ #### 1. Install the library
62
+
63
+ ```sh
64
+ npx expo install react-native-enriched-markdown
65
+ ```
66
+
67
+ #### 2. Run prebuild
68
+
69
+ The library includes native code so you will need to re-build the native app.
70
+
71
+ ```sh
72
+ npx expo prebuild
73
+ ```
74
+
75
+ > [!NOTE]
76
+ > The library won't work in Expo Go as it needs native changes.
77
+
78
+ > [!IMPORTANT]
79
+ > **iOS: Save to Camera Roll**
80
+ >
81
+ > If your Markdown content includes images and you want users to save them to their photo library, add the following to your `Info.plist`:
82
+ > ```xml
83
+ > <key>NSPhotoLibraryAddUsageDescription</key>
84
+ > <string>This app needs access to your photo library to save images.</string>
85
+ > ```
86
+
87
+ ## Usage
88
+
89
+ Here's a simple example of rendering Markdown content:
90
+
91
+ ```tsx
92
+ import { EnrichedMarkdownText } from 'react-native-enriched-markdown';
93
+ import { Linking } from 'react-native';
94
+
95
+ const markdown = `
96
+ # Welcome to Markdown!
97
+
98
+ This is a paragraph with **bold**, *italic*, and [links](https://reactnative.dev).
99
+
100
+ - List item one
101
+ - List item two
102
+ - Nested item
103
+
104
+ \`\`\`javascript
105
+ const greeting = 'Hello, World!';
106
+ console.log(greeting);
107
+ \`\`\`
108
+ `;
109
+
110
+ export default function App() {
111
+ const handleLinkPress = (event: { nativeEvent: { url: string } }) => {
112
+ Linking.openURL(event.nativeEvent.url);
113
+ };
114
+
115
+ return (
116
+ <EnrichedMarkdownText
117
+ markdown={markdown}
118
+ onLinkPress={handleLinkPress}
119
+ />
120
+ );
121
+ }
122
+ ```
123
+
124
+ ## Supported Markdown Elements
125
+
126
+ `react-native-enriched-markdown` supports a comprehensive set of Markdown elements:
127
+
128
+ ### Block Elements
129
+
130
+ | Element | Syntax | Description |
131
+ |---------|--------|-------------|
132
+ | Headings | `# H1` to `###### H6` | Six levels of headings |
133
+ | Paragraphs | Plain text | Regular text paragraphs |
134
+ | Blockquotes | `> Quote` | Quoted text with unlimited nesting |
135
+ | Code Blocks | ` ``` code ``` ` | Multi-line code blocks |
136
+ | Unordered Lists | `- Item`, `* Item`, or `+ Item` | Bullet lists with unlimited nesting |
137
+ | Ordered Lists | `1. Item` | Numbered lists with unlimited nesting |
138
+ | Thematic Break | `---`, `***`, or `___` | Visual separator line |
139
+ | Images | `![alt](url)` | Block-level images |
140
+
141
+ ### Inline Elements
142
+
143
+ | Element | Syntax | Description |
144
+ |---------|--------|-------------|
145
+ | Bold | `**text**` or `__text__` | Strong emphasis |
146
+ | Italic | `*text*` or `_text_` | Emphasis |
147
+ | Bold + Italic | `***text***`, `___text___`, `**_text_**`, `__*text*__`, `_**text**_`, `*__text__*` | Combined emphasis |
148
+ | Links | `[text](url)` | Clickable links |
149
+ | Inline Code | `` `code` `` | Inline code snippets |
150
+ | Inline Images | `![alt](url)` | Images within text flow |
151
+
152
+ ### Nested Lists Example
153
+
154
+ ```markdown
155
+ - First level
156
+ - Second level
157
+ - Third level
158
+ - Fourth level (unlimited depth!)
159
+
160
+ 1. First item
161
+ 1. Nested numbered
162
+ 1. Deep nested
163
+ 2. Another nested
164
+ 2. Second item
165
+ ```
166
+
167
+ ### Nested Blockquotes Example
168
+
169
+ ```markdown
170
+ > Level 1 quote
171
+ > > Level 2 nested
172
+ > > > Level 3 nested (unlimited depth!)
173
+ ```
174
+
175
+ ## Link Handling
176
+
177
+ Links in Markdown are interactive and can be handled with the `onLinkPress` callback:
178
+
179
+ ```tsx
180
+ <EnrichedMarkdownText
181
+ markdown="Check out [React Native](https://reactnative.dev)!"
182
+ onLinkPress={(event) => {
183
+ const { url } = event.nativeEvent;
184
+ Alert.alert('Link pressed', url);
185
+ Linking.openURL(url);
186
+ }}
187
+ />
188
+ ```
189
+
190
+ ## Copy Options
191
+
192
+ When text is selected, `react-native-enriched-markdown` provides enhanced copy functionality through the context menu on both platforms.
193
+
194
+ ### Smart Copy
195
+
196
+ The default **Copy** action copies the selected text with rich formatting support:
197
+
198
+ #### iOS
199
+
200
+ Copies in multiple formats simultaneously — receiving apps pick the richest format they support:
201
+
202
+ | Format | Description |
203
+ |--------|-------------|
204
+ | **Plain Text** | Basic text without formatting |
205
+ | **Markdown** | Original Markdown syntax preserved |
206
+ | **HTML** | Rich HTML representation |
207
+ | **RTF** | Rich Text Format for apps like Notes, Pages |
208
+ | **RTFD** | RTF with embedded images |
209
+
210
+ #### Android
211
+
212
+ Copies as both **Plain Text** and **HTML** — apps that support rich text (like Gmail, Google Docs) will preserve formatting.
213
+
214
+ ### Copy as Markdown
215
+
216
+ A dedicated **Copy as Markdown** option is available in the context menu on both platforms. This copies only the Markdown source text, useful when you want to preserve the original syntax.
217
+
218
+ ### Copy Image URL
219
+
220
+ When selecting text that contains images, a **Copy Image URL** option appears to copy the image's source URL. On Android, if multiple images are selected, all URLs are copied (one per line).
221
+
222
+ ## Styling Architecture
223
+
224
+ Understanding how `react-native-enriched-markdown` handles styling helps you create consistent, well-designed Markdown content.
225
+
226
+ ### Block vs Inline Elements
227
+
228
+ Markdown elements are divided into two categories:
229
+
230
+ #### Block Elements
231
+
232
+ Block elements are structural containers that define the layout. Each block has its own typography settings (`fontSize`, `fontFamily`, `fontWeight`, `color`, `lineHeight`, `marginBottom`).
233
+
234
+ | Block Type | Description |
235
+ |------------|-------------|
236
+ | `paragraph` | Default text container |
237
+ | `h1` - `h6` | Heading levels |
238
+ | `blockquote` | Quoted content with accent bar |
239
+ | `list` | Ordered and unordered lists |
240
+ | `codeBlock` | Multi-line code containers |
241
+
242
+ #### Inline Elements
243
+
244
+ Inline elements modify text within blocks. They inherit the parent block's base typography and apply additional styling.
245
+
246
+ | Inline Type | Inherits From | Adds |
247
+ |-------------|---------------|------|
248
+ | `strong` | Parent block | Bold weight, optional color |
249
+ | `em` | Parent block | Italic style, optional color |
250
+ | `code` | Parent block | Monospace font, background |
251
+ | `link` | Parent block | Color, underline |
252
+
253
+ ### Style Inheritance
254
+
255
+ Inline styles automatically inherit from their containing block:
256
+
257
+ ```
258
+ Heading (h2: fontSize 24, color blue)
259
+ └── Strong text inherits → fontSize 24, color blue + bold weight
260
+ └── Link inherits → fontSize 24 + link color + underline
261
+
262
+ List item (list: fontSize 16, color gray)
263
+ └── Emphasis inherits → fontSize 16, color gray + italic style
264
+ └── Inline code inherits → fontSize 16 + code background
265
+ ```
266
+
267
+ ### Nested Elements
268
+
269
+ Some elements support unlimited nesting depth with automatic indentation:
270
+
271
+ - **Blockquotes**: Each level adds a new accent bar
272
+ - **Unordered Lists**: Each level indents with `marginLeft`
273
+ - **Ordered Lists**: Each level indents and maintains separate numbering
274
+
275
+ ```markdown
276
+ > Level 1
277
+ > > Level 2 (inherits L1 styles + additional indent)
278
+ > > > Level 3 (inherits L2 styles + additional indent)
279
+ ```
280
+
281
+ ### Platform Defaults
282
+
283
+ The library provides sensible defaults optimized for each platform:
284
+
285
+ | Property | iOS | Android |
286
+ |----------|-----|---------|
287
+ | System Font | SF Pro | Roboto |
288
+ | Monospace Font | Menlo | monospace |
289
+ | Line Height | Tighter (0.75x multiplier) | Standard |
290
+
291
+ ## Customizing Styles
292
+
293
+ The library provides sensible default styles for all Markdown elements out of the box. You can override any of these defaults using the `markdownStyle` prop — only specify the properties you want to change:
294
+
295
+ ```tsx
296
+ <EnrichedMarkdownText
297
+ markdown={content}
298
+ markdownStyle={{
299
+ paragraph: {
300
+ fontSize: 16,
301
+ color: '#333',
302
+ lineHeight: 24,
303
+ },
304
+ h1: {
305
+ fontSize: 32,
306
+ fontWeight: 'bold',
307
+ color: '#000',
308
+ marginBottom: 16,
309
+ },
310
+ h2: {
311
+ fontSize: 24,
312
+ fontWeight: '600',
313
+ marginBottom: 12,
314
+ },
315
+ strong: {
316
+ color: '#000',
317
+ },
318
+ em: {
319
+ color: '#666',
320
+ },
321
+ link: {
322
+ color: '#007AFF',
323
+ underline: true,
324
+ },
325
+ code: {
326
+ color: '#E91E63',
327
+ backgroundColor: '#F5F5F5',
328
+ borderColor: '#E0E0E0',
329
+ },
330
+ codeBlock: {
331
+ fontSize: 14,
332
+ fontFamily: 'monospace',
333
+ backgroundColor: '#1E1E1E',
334
+ color: '#D4D4D4',
335
+ padding: 16,
336
+ borderRadius: 8,
337
+ marginBottom: 16,
338
+ },
339
+ blockquote: {
340
+ borderColor: '#007AFF',
341
+ borderWidth: 3,
342
+ backgroundColor: '#F0F8FF',
343
+ marginBottom: 12,
344
+ },
345
+ list: {
346
+ fontSize: 16,
347
+ bulletColor: '#007AFF',
348
+ bulletSize: 6,
349
+ markerColor: '#007AFF',
350
+ gapWidth: 8,
351
+ marginLeft: 20,
352
+ },
353
+ image: {
354
+ borderRadius: 8,
355
+ marginBottom: 12,
356
+ },
357
+ inlineImage: {
358
+ size: 20,
359
+ },
360
+ }}
361
+ />
362
+ ```
363
+
364
+ > [!NOTE]
365
+ > **Performance:** Memoize the `markdownStyle` prop with `useMemo` to avoid unnecessary re-renders:
366
+ > ```tsx
367
+ > import type { MarkdownStyle } from 'react-native-enriched-markdown';
368
+ >
369
+ > const markdownStyle: MarkdownStyle = useMemo(() => ({
370
+ > paragraph: { fontSize: 16 },
371
+ > h1: { fontSize: 32 },
372
+ > }), []);
373
+ > ```
374
+
375
+ ### Style Properties Reference
376
+
377
+ #### Block Styles (paragraph, h1-h6, blockquote, list, codeBlock)
378
+
379
+ | Property | Type | Description |
380
+ |----------|------|-------------|
381
+ | `fontSize` | `number` | Font size in points |
382
+ | `fontFamily` | `string` | Font family name |
383
+ | `fontWeight` | `string` | Font weight |
384
+ | `color` | `string` | Text color |
385
+ | `marginBottom` | `number` | Bottom margin |
386
+ | `lineHeight` | `number` | Line height |
387
+
388
+ #### Blockquote-specific
389
+
390
+ | Property | Type | Description |
391
+ |----------|------|-------------|
392
+ | `borderColor` | `string` | Left border color |
393
+ | `borderWidth` | `number` | Left border width |
394
+ | `gapWidth` | `number` | Gap between border and text |
395
+ | `backgroundColor` | `string` | Background color |
396
+
397
+ #### List-specific
398
+
399
+ | Property | Type | Description |
400
+ |----------|------|-------------|
401
+ | `bulletColor` | `string` | Bullet point color |
402
+ | `bulletSize` | `number` | Bullet point size |
403
+ | `markerColor` | `string` | Number marker color |
404
+ | `markerFontWeight` | `string` | Number marker font weight |
405
+ | `gapWidth` | `number` | Gap between marker and text |
406
+ | `marginLeft` | `number` | Left margin for nesting |
407
+
408
+ #### Code Block-specific
409
+
410
+ | Property | Type | Description |
411
+ |----------|------|-------------|
412
+ | `backgroundColor` | `string` | Background color |
413
+ | `borderColor` | `string` | Border color |
414
+ | `borderRadius` | `number` | Corner radius |
415
+ | `borderWidth` | `number` | Border width |
416
+ | `padding` | `number` | Inner padding |
417
+
418
+ #### Inline Code-specific
419
+
420
+ | Property | Type | Description |
421
+ |----------|------|-------------|
422
+ | `color` | `string` | Text color |
423
+ | `backgroundColor` | `string` | Background color |
424
+ | `borderColor` | `string` | Border color |
425
+
426
+ #### Link-specific
427
+
428
+ | Property | Type | Description |
429
+ |----------|------|-------------|
430
+ | `color` | `string` | Link text color |
431
+ | `underline` | `boolean` | Show underline |
432
+
433
+ #### Image-specific
434
+
435
+ | Property | Type | Description |
436
+ |----------|------|-------------|
437
+ | `height` | `number` | Image height |
438
+ | `borderRadius` | `number` | Corner radius |
439
+ | `marginBottom` | `number` | Bottom margin |
440
+
441
+ #### Inline Image-specific
442
+
443
+ | Property | Type | Description |
444
+ |----------|------|-------------|
445
+ | `size` | `number` | Image size (square) |
446
+
447
+ #### Thematic Break (Horizontal Rule)-specific
448
+
449
+ | Property | Type | Description |
450
+ |----------|------|-------------|
451
+ | `color` | `string` | Line color |
452
+ | `height` | `number` | Line thickness |
453
+ | `marginTop` | `number` | Top margin |
454
+ | `marginBottom` | `number` | Bottom margin |
455
+
456
+ ## API Reference
457
+
458
+ ### Props
459
+
460
+ | Prop | Type | Default | Description |
461
+ |------|------|---------|-------------|
462
+ | `markdown` | `string` | Required | The Markdown content to render |
463
+ | `markdownStyle` | `MarkdownStyle` | `{}` | Style configuration for Markdown elements |
464
+ | `containerStyle` | `ViewStyle` | - | Style for the container view |
465
+ | `onLinkPress` | `(event: LinkPressEvent) => void` | - | Callback when a link is pressed. Access URL via `event.url` |
466
+ | `isSelectable` | `boolean` | `true` | Whether text can be selected |
467
+
468
+ ## Contributing
469
+
470
+ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
471
+
472
+ ## License
473
+
474
+ `react-native-enriched-markdown` library is licensed under [The MIT License](./LICENSE).
475
+
476
+ ---
477
+ Built by [Software Mansion](https://swmansion.com/).
478
+
479
+ [<img width="128" height="69" alt="Software Mansion Logo" src="https://github.com/user-attachments/assets/f0e18471-a7aa-4e80-86ac-87686a86fe56" />](https://swmansion.com/)
@@ -0,0 +1,27 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = "ReactNativeEnrichedMarkdown"
7
+ s.version = package["version"]
8
+ s.summary = package["description"]
9
+ s.homepage = package["homepage"]
10
+ s.license = package["license"]
11
+ s.authors = package["author"]
12
+
13
+ s.platforms = { :ios => min_ios_version_supported }
14
+ s.source = { :git => "https://github.com/software-mansion-labs/react-native-enriched-markdown.git", :tag => "#{s.version}" }
15
+
16
+ s.source_files = "ios/**/*.{h,m,mm,cpp}", "cpp/md4c/*.{c,h}", "cpp/parser/*.{hpp,cpp}"
17
+ s.private_header_files = "ios/**/*.h"
18
+
19
+ # Set header search paths to cpp/md4c and cpp/parser, add preprocessor definitions
20
+ s.pod_target_xcconfig = {
21
+ 'HEADER_SEARCH_PATHS' => '"$(PODS_TARGET_SRCROOT)/cpp/md4c" "$(PODS_TARGET_SRCROOT)/cpp/parser" "$(PODS_TARGET_SRCROOT)/ios/internals"',
22
+ 'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) MD4C_USE_UTF8=1',
23
+ 'CLANG_CXX_LANGUAGE_STANDARD' => 'c++17'
24
+ }
25
+
26
+ install_modules_dependencies(s)
27
+ end
@@ -0,0 +1,101 @@
1
+ buildscript {
2
+ ext.getExtOrDefault = {name ->
3
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['EnrichedMarkdown_' + name]
4
+ }
5
+
6
+ repositories {
7
+ google()
8
+ mavenCentral()
9
+ }
10
+
11
+ dependencies {
12
+ classpath "com.android.tools.build:gradle:8.7.2"
13
+ // noinspection DifferentKotlinGradleVersion
14
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
15
+ }
16
+ }
17
+
18
+ plugins {
19
+ id "org.jlleitschuh.gradle.ktlint" version "14.0.1"
20
+ }
21
+
22
+ apply plugin: "com.android.library"
23
+ apply plugin: "kotlin-android"
24
+ apply plugin: "com.facebook.react"
25
+
26
+ def getExtOrIntegerDefault(name) {
27
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["EnrichedMarkdown_" + name]).toInteger()
28
+ }
29
+
30
+ android {
31
+ namespace "com.swmansion.enriched.markdown"
32
+
33
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
34
+
35
+ defaultConfig {
36
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
37
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
38
+ }
39
+
40
+ buildFeatures {
41
+ buildConfig true
42
+ }
43
+
44
+ buildTypes {
45
+ release {
46
+ minifyEnabled false
47
+ }
48
+ }
49
+
50
+ lintOptions {
51
+ disable "GradleCompatible"
52
+ }
53
+
54
+ compileOptions {
55
+ sourceCompatibility JavaVersion.VERSION_1_8
56
+ targetCompatibility JavaVersion.VERSION_1_8
57
+ }
58
+
59
+ sourceSets {
60
+ main {
61
+ java.srcDirs += [
62
+ "generated/java",
63
+ "generated/jni"
64
+ ]
65
+ }
66
+ }
67
+ }
68
+
69
+ repositories {
70
+ mavenCentral()
71
+ google()
72
+ }
73
+
74
+ def kotlin_version = getExtOrDefault("kotlinVersion")
75
+
76
+ dependencies {
77
+ implementation "com.facebook.react:react-android"
78
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
79
+ // Baseline Profile installer for AOT compilation hints
80
+ implementation "androidx.profileinstaller:profileinstaller:1.3.1"
81
+ }
82
+
83
+ ktlint {
84
+ version = "1.8.0"
85
+ debug = false
86
+ verbose = true
87
+ android = true
88
+ outputToConsole = true
89
+ ignoreFailures = false
90
+ enableExperimentalRules = false
91
+ filter {
92
+ exclude("**/build/**")
93
+ exclude("**/generated/**")
94
+ }
95
+ }
96
+
97
+ react {
98
+ jsRootDir = file("../src/")
99
+ libraryName = "EnrichedMarkdownText"
100
+ codegenJavaPackageName = "com.swmansion.enriched.markdown"
101
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
3
+ *
4
+ * Do not edit this file as changes may cause incorrect behavior and will be lost
5
+ * once the code is regenerated.
6
+ *
7
+ * @generated by codegen project: GeneratePropsJavaDelegate.js
8
+ */
9
+
10
+ package com.facebook.react.viewmanagers;
11
+
12
+ import android.view.View;
13
+ import androidx.annotation.Nullable;
14
+ import com.facebook.react.bridge.ReadableMap;
15
+ import com.facebook.react.uimanager.BaseViewManager;
16
+ import com.facebook.react.uimanager.BaseViewManagerDelegate;
17
+ import com.facebook.react.uimanager.LayoutShadowNode;
18
+
19
+ public class EnrichedMarkdownTextManagerDelegate<T extends View, U extends BaseViewManager<T, ? extends LayoutShadowNode> & EnrichedMarkdownTextManagerInterface<T>> extends BaseViewManagerDelegate<T, U> {
20
+ public EnrichedMarkdownTextManagerDelegate(U viewManager) {
21
+ super(viewManager);
22
+ }
23
+ @Override
24
+ public void setProperty(T view, String propName, @Nullable Object value) {
25
+ switch (propName) {
26
+ case "markdown":
27
+ mViewManager.setMarkdown(view, value == null ? null : (String) value);
28
+ break;
29
+ case "markdownStyle":
30
+ mViewManager.setMarkdownStyle(view, (ReadableMap) value);
31
+ break;
32
+ case "isSelectable":
33
+ mViewManager.setIsSelectable(view, value == null ? false : (boolean) value);
34
+ break;
35
+ default:
36
+ super.setProperty(view, propName, value);
37
+ }
38
+ }
39
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
3
+ *
4
+ * Do not edit this file as changes may cause incorrect behavior and will be lost
5
+ * once the code is regenerated.
6
+ *
7
+ * @generated by codegen project: GeneratePropsJavaInterface.js
8
+ */
9
+
10
+ package com.facebook.react.viewmanagers;
11
+
12
+ import android.view.View;
13
+ import androidx.annotation.Nullable;
14
+ import com.facebook.react.bridge.ReadableMap;
15
+ import com.facebook.react.uimanager.ViewManagerWithGeneratedInterface;
16
+
17
+ public interface EnrichedMarkdownTextManagerInterface<T extends View> extends ViewManagerWithGeneratedInterface {
18
+ void setMarkdown(T view, @Nullable String value);
19
+ void setMarkdownStyle(T view, @Nullable ReadableMap value);
20
+ void setIsSelectable(T view, boolean value);
21
+ }