react-native-enriched-markdown 0.1.0 → 0.2.0

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 (226) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +551 -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 +54 -0
  6. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +26 -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 +33 -0
  10. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +31 -0
  11. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +82 -0
  12. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +1388 -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 +220 -0
  21. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +270 -0
  22. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextLayoutManager.kt +15 -0
  23. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +173 -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 +385 -0
  26. package/android/src/main/java/com/swmansion/enriched/markdown/accessibility/MarkdownAccessibilityHelper.kt +279 -0
  27. package/android/src/main/java/com/swmansion/enriched/markdown/events/LinkLongPressEvent.kt +23 -0
  28. package/android/src/main/java/com/swmansion/enriched/markdown/events/LinkPressEvent.kt +23 -0
  29. package/android/src/main/java/com/swmansion/enriched/markdown/parser/MarkdownASTNode.kt +31 -0
  30. package/android/src/main/java/com/swmansion/enriched/markdown/parser/Parser.kt +62 -0
  31. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockStyleContext.kt +166 -0
  32. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt +84 -0
  33. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeBlockRenderer.kt +104 -0
  34. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeRenderer.kt +36 -0
  35. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/DocumentRenderer.kt +16 -0
  36. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/EmphasisRenderer.kt +27 -0
  37. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +70 -0
  38. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ImageRenderer.kt +68 -0
  39. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LineBreakRenderer.kt +16 -0
  40. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LinkRenderer.kt +29 -0
  41. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListContextManager.kt +105 -0
  42. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListItemRenderer.kt +59 -0
  43. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListRenderer.kt +76 -0
  44. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/NodeRenderer.kt +103 -0
  45. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ParagraphRenderer.kt +80 -0
  46. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/Renderer.kt +109 -0
  47. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +86 -0
  48. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/StrikethroughRenderer.kt +27 -0
  49. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/StrongRenderer.kt +27 -0
  50. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/TextRenderer.kt +30 -0
  51. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ThematicBreakRenderer.kt +45 -0
  52. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/UnderlineRenderer.kt +27 -0
  53. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BaseListSpan.kt +136 -0
  54. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt +135 -0
  55. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBackgroundSpan.kt +180 -0
  56. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBlockSpan.kt +196 -0
  57. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeSpan.kt +27 -0
  58. package/android/src/main/java/com/swmansion/enriched/markdown/spans/EmphasisSpan.kt +34 -0
  59. package/android/src/main/java/com/swmansion/enriched/markdown/spans/HeadingSpan.kt +38 -0
  60. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ImageSpan.kt +321 -0
  61. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LineHeightSpan.kt +27 -0
  62. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LinkSpan.kt +51 -0
  63. package/android/src/main/java/com/swmansion/enriched/markdown/spans/MarginBottomSpan.kt +76 -0
  64. package/android/src/main/java/com/swmansion/enriched/markdown/spans/OrderedListSpan.kt +87 -0
  65. package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrikethroughSpan.kt +12 -0
  66. package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrongSpan.kt +37 -0
  67. package/android/src/main/java/com/swmansion/enriched/markdown/spans/TextSpan.kt +26 -0
  68. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ThematicBreakSpan.kt +69 -0
  69. package/android/src/main/java/com/swmansion/enriched/markdown/spans/UnorderedListSpan.kt +69 -0
  70. package/android/src/main/java/com/swmansion/enriched/markdown/styles/BaseBlockStyle.kt +11 -0
  71. package/android/src/main/java/com/swmansion/enriched/markdown/styles/BlockquoteStyle.kt +51 -0
  72. package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeBlockStyle.kt +54 -0
  73. package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeStyle.kt +21 -0
  74. package/android/src/main/java/com/swmansion/enriched/markdown/styles/EmphasisStyle.kt +17 -0
  75. package/android/src/main/java/com/swmansion/enriched/markdown/styles/HeadingStyle.kt +33 -0
  76. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ImageStyle.kt +23 -0
  77. package/android/src/main/java/com/swmansion/enriched/markdown/styles/InlineImageStyle.kt +17 -0
  78. package/android/src/main/java/com/swmansion/enriched/markdown/styles/LinkStyle.kt +19 -0
  79. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ListStyle.kt +57 -0
  80. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ParagraphStyle.kt +33 -0
  81. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StrikethroughStyle.kt +17 -0
  82. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StrongStyle.kt +17 -0
  83. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt +211 -0
  84. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleParser.kt +92 -0
  85. package/android/src/main/java/com/swmansion/enriched/markdown/styles/TextAlignment.kt +32 -0
  86. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ThematicBreakStyle.kt +23 -0
  87. package/android/src/main/java/com/swmansion/enriched/markdown/styles/UnderlineStyle.kt +17 -0
  88. package/android/src/main/java/com/swmansion/enriched/markdown/utils/AsyncDrawable.kt +91 -0
  89. package/android/src/main/java/com/swmansion/enriched/markdown/utils/HTMLGenerator.kt +827 -0
  90. package/android/src/main/java/com/swmansion/enriched/markdown/utils/LinkLongPressMovementMethod.kt +121 -0
  91. package/android/src/main/java/com/swmansion/enriched/markdown/utils/MarkdownExtractor.kt +375 -0
  92. package/android/src/main/java/com/swmansion/enriched/markdown/utils/SelectionActionMode.kt +139 -0
  93. package/android/src/main/java/com/swmansion/enriched/markdown/utils/Utils.kt +183 -0
  94. package/android/src/main/jni/CMakeLists.txt +70 -0
  95. package/android/src/main/jni/EnrichedMarkdownTextSpec.cpp +21 -0
  96. package/android/src/main/jni/EnrichedMarkdownTextSpec.h +25 -0
  97. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextComponentDescriptor.h +29 -0
  98. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextMeasurementManager.cpp +45 -0
  99. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextMeasurementManager.h +21 -0
  100. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.cpp +20 -0
  101. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.h +37 -0
  102. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/conversions.h +22 -0
  103. package/cpp/md4c/md4c.c +6492 -0
  104. package/cpp/md4c/md4c.h +402 -0
  105. package/cpp/parser/MD4CParser.cpp +327 -0
  106. package/cpp/parser/MD4CParser.hpp +27 -0
  107. package/cpp/parser/MarkdownASTNode.hpp +51 -0
  108. package/ios/EnrichedMarkdownText.h +18 -0
  109. package/ios/EnrichedMarkdownText.mm +1401 -0
  110. package/ios/attachments/EnrichedMarkdownImageAttachment.h +23 -0
  111. package/ios/attachments/EnrichedMarkdownImageAttachment.m +185 -0
  112. package/ios/attachments/ThematicBreakAttachment.h +15 -0
  113. package/ios/attachments/ThematicBreakAttachment.m +33 -0
  114. package/ios/generated/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp +22 -0
  115. package/ios/generated/EnrichedMarkdownTextSpec/ComponentDescriptors.h +24 -0
  116. package/ios/generated/EnrichedMarkdownTextSpec/EventEmitters.cpp +33 -0
  117. package/ios/generated/EnrichedMarkdownTextSpec/EventEmitters.h +31 -0
  118. package/ios/generated/EnrichedMarkdownTextSpec/Props.cpp +82 -0
  119. package/ios/generated/EnrichedMarkdownTextSpec/Props.h +1388 -0
  120. package/ios/generated/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +20 -0
  121. package/ios/generated/EnrichedMarkdownTextSpec/ShadowNodes.cpp +17 -0
  122. package/ios/generated/EnrichedMarkdownTextSpec/ShadowNodes.h +32 -0
  123. package/ios/generated/EnrichedMarkdownTextSpec/States.cpp +16 -0
  124. package/ios/generated/EnrichedMarkdownTextSpec/States.h +20 -0
  125. package/ios/internals/EnrichedMarkdownTextComponentDescriptor.h +19 -0
  126. package/ios/internals/EnrichedMarkdownTextShadowNode.h +43 -0
  127. package/ios/internals/EnrichedMarkdownTextShadowNode.mm +85 -0
  128. package/ios/internals/EnrichedMarkdownTextState.h +24 -0
  129. package/ios/parser/MarkdownASTNode.h +35 -0
  130. package/ios/parser/MarkdownASTNode.m +32 -0
  131. package/ios/parser/MarkdownParser.h +17 -0
  132. package/ios/parser/MarkdownParser.mm +42 -0
  133. package/ios/parser/MarkdownParserBridge.mm +120 -0
  134. package/ios/renderer/AttributedRenderer.h +11 -0
  135. package/ios/renderer/AttributedRenderer.m +152 -0
  136. package/ios/renderer/BlockquoteRenderer.h +7 -0
  137. package/ios/renderer/BlockquoteRenderer.m +160 -0
  138. package/ios/renderer/CodeBlockRenderer.h +10 -0
  139. package/ios/renderer/CodeBlockRenderer.m +90 -0
  140. package/ios/renderer/CodeRenderer.h +10 -0
  141. package/ios/renderer/CodeRenderer.m +60 -0
  142. package/ios/renderer/EmphasisRenderer.h +6 -0
  143. package/ios/renderer/EmphasisRenderer.m +96 -0
  144. package/ios/renderer/HeadingRenderer.h +7 -0
  145. package/ios/renderer/HeadingRenderer.m +105 -0
  146. package/ios/renderer/ImageRenderer.h +12 -0
  147. package/ios/renderer/ImageRenderer.m +83 -0
  148. package/ios/renderer/LinkRenderer.h +7 -0
  149. package/ios/renderer/LinkRenderer.m +69 -0
  150. package/ios/renderer/ListItemRenderer.h +16 -0
  151. package/ios/renderer/ListItemRenderer.m +103 -0
  152. package/ios/renderer/ListRenderer.h +13 -0
  153. package/ios/renderer/ListRenderer.m +70 -0
  154. package/ios/renderer/NodeRenderer.h +8 -0
  155. package/ios/renderer/ParagraphRenderer.h +7 -0
  156. package/ios/renderer/ParagraphRenderer.m +80 -0
  157. package/ios/renderer/RenderContext.h +105 -0
  158. package/ios/renderer/RenderContext.m +312 -0
  159. package/ios/renderer/RendererFactory.h +12 -0
  160. package/ios/renderer/RendererFactory.m +116 -0
  161. package/ios/renderer/StrikethroughRenderer.h +6 -0
  162. package/ios/renderer/StrikethroughRenderer.m +40 -0
  163. package/ios/renderer/StrongRenderer.h +6 -0
  164. package/ios/renderer/StrongRenderer.m +83 -0
  165. package/ios/renderer/TextRenderer.h +6 -0
  166. package/ios/renderer/TextRenderer.m +16 -0
  167. package/ios/renderer/ThematicBreakRenderer.h +5 -0
  168. package/ios/renderer/ThematicBreakRenderer.m +53 -0
  169. package/ios/renderer/UnderlineRenderer.h +6 -0
  170. package/ios/renderer/UnderlineRenderer.m +39 -0
  171. package/ios/styles/StyleConfig.h +274 -0
  172. package/ios/styles/StyleConfig.mm +1806 -0
  173. package/ios/utils/AccessibilityInfo.h +35 -0
  174. package/ios/utils/AccessibilityInfo.m +24 -0
  175. package/ios/utils/BlockquoteBorder.h +20 -0
  176. package/ios/utils/BlockquoteBorder.m +92 -0
  177. package/ios/utils/CodeBackground.h +19 -0
  178. package/ios/utils/CodeBackground.m +191 -0
  179. package/ios/utils/CodeBlockBackground.h +17 -0
  180. package/ios/utils/CodeBlockBackground.m +82 -0
  181. package/ios/utils/EditMenuUtils.h +22 -0
  182. package/ios/utils/EditMenuUtils.m +118 -0
  183. package/ios/utils/FontUtils.h +25 -0
  184. package/ios/utils/FontUtils.m +27 -0
  185. package/ios/utils/HTMLGenerator.h +20 -0
  186. package/ios/utils/HTMLGenerator.m +793 -0
  187. package/ios/utils/LastElementUtils.h +53 -0
  188. package/ios/utils/ListMarkerDrawer.h +15 -0
  189. package/ios/utils/ListMarkerDrawer.m +127 -0
  190. package/ios/utils/MarkdownAccessibilityElementBuilder.h +45 -0
  191. package/ios/utils/MarkdownAccessibilityElementBuilder.m +323 -0
  192. package/ios/utils/MarkdownExtractor.h +17 -0
  193. package/ios/utils/MarkdownExtractor.m +308 -0
  194. package/ios/utils/ParagraphStyleUtils.h +21 -0
  195. package/ios/utils/ParagraphStyleUtils.m +111 -0
  196. package/ios/utils/PasteboardUtils.h +36 -0
  197. package/ios/utils/PasteboardUtils.m +134 -0
  198. package/ios/utils/RTFExportUtils.h +24 -0
  199. package/ios/utils/RTFExportUtils.m +297 -0
  200. package/ios/utils/RuntimeKeys.h +38 -0
  201. package/ios/utils/RuntimeKeys.m +11 -0
  202. package/ios/utils/TextViewLayoutManager.h +14 -0
  203. package/ios/utils/TextViewLayoutManager.mm +113 -0
  204. package/lib/module/EnrichedMarkdownText.js +65 -0
  205. package/lib/module/EnrichedMarkdownText.js.map +1 -0
  206. package/lib/module/EnrichedMarkdownTextNativeComponent.ts +210 -0
  207. package/lib/module/index.js +4 -0
  208. package/lib/module/index.js.map +1 -0
  209. package/lib/module/normalizeMarkdownStyle.js +384 -0
  210. package/lib/module/normalizeMarkdownStyle.js.map +1 -0
  211. package/lib/module/package.json +1 -0
  212. package/lib/typescript/package.json +1 -0
  213. package/lib/typescript/src/EnrichedMarkdownText.d.ts +183 -0
  214. package/lib/typescript/src/EnrichedMarkdownText.d.ts.map +1 -0
  215. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +185 -0
  216. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -0
  217. package/lib/typescript/src/index.d.ts +4 -0
  218. package/lib/typescript/src/index.d.ts.map +1 -0
  219. package/lib/typescript/src/normalizeMarkdownStyle.d.ts +6 -0
  220. package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -0
  221. package/package.json +186 -1
  222. package/react-native.config.js +13 -0
  223. package/src/EnrichedMarkdownText.tsx +280 -0
  224. package/src/EnrichedMarkdownTextNativeComponent.ts +210 -0
  225. package/src/index.tsx +10 -0
  226. package/src/normalizeMarkdownStyle.ts +423 -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,551 @@
1
+ <img src="https://github.com/user-attachments/assets/922e57b6-98b7-4ad4-a270-838c7341d102" 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
+ - 🗣️ Accessibility support (VoiceOver & TalkBack)
18
+
19
+ 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.
20
+ We can help you build your next dream product –
21
+ [Hire us](https://swmansion.com/contact/projects?utm_source=react-native-enriched-markdown&utm_medium=readme).
22
+
23
+ ## Table of Contents
24
+
25
+ - [Prerequisites](#prerequisites)
26
+ - [Installation](#installation)
27
+ - [Usage](#usage)
28
+ - [Supported Markdown Elements](#supported-markdown-elements)
29
+ - [Link Handling](#link-handling)
30
+ - [Copy Options](#copy-options)
31
+ - [Accessibility](#accessibility)
32
+ - [Styling Architecture](#styling-architecture)
33
+ - [Customizing Styles](#customizing-styles)
34
+ - [API Reference](#api-reference)
35
+ - [Contributing](#contributing)
36
+ - [License](#license)
37
+
38
+ ## Prerequisites
39
+
40
+ - `react-native-enriched-markdown` currently supports only Android and iOS platforms
41
+ - 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`, `0.83` and `0.84`
42
+
43
+ ## Installation
44
+
45
+ ### Bare React Native app
46
+
47
+ #### 1. Install the library
48
+
49
+ ```sh
50
+ yarn add react-native-enriched-markdown
51
+ ```
52
+
53
+ #### 2. Install iOS dependencies
54
+
55
+ The library includes native code so you will need to re-build the native app.
56
+
57
+ ```sh
58
+ cd ios && bundle install && bundle exec pod install
59
+ ```
60
+
61
+ ### Expo app
62
+
63
+ #### 1. Install the library
64
+
65
+ ```sh
66
+ npx expo install react-native-enriched-markdown
67
+ ```
68
+
69
+ #### 2. Run prebuild
70
+
71
+ The library includes native code so you will need to re-build the native app.
72
+
73
+ ```sh
74
+ npx expo prebuild
75
+ ```
76
+
77
+ > [!NOTE]
78
+ > The library won't work in Expo Go as it needs native changes.
79
+
80
+ > [!IMPORTANT]
81
+ > **iOS: Save to Camera Roll**
82
+ >
83
+ > If your Markdown content includes images and you want users to save them to their photo library, add the following to your `Info.plist`:
84
+ > ```xml
85
+ > <key>NSPhotoLibraryAddUsageDescription</key>
86
+ > <string>This app needs access to your photo library to save images.</string>
87
+ > ```
88
+
89
+ ## Usage
90
+
91
+ Here's a simple example of rendering Markdown content:
92
+
93
+ ```tsx
94
+ import { EnrichedMarkdownText } from 'react-native-enriched-markdown';
95
+ import { Linking } from 'react-native';
96
+
97
+ const markdown = `
98
+ # Welcome to Markdown!
99
+
100
+ This is a paragraph with **bold**, *italic*, and [links](https://reactnative.dev).
101
+
102
+ - List item one
103
+ - List item two
104
+ - Nested item
105
+
106
+ \`\`\`javascript
107
+ const greeting = 'Hello, World!';
108
+ console.log(greeting);
109
+ \`\`\`
110
+ `;
111
+
112
+ export default function App() {
113
+ const handleLinkPress = (event: { nativeEvent: { url: string } }) => {
114
+ Linking.openURL(event.nativeEvent.url);
115
+ };
116
+
117
+ return (
118
+ <EnrichedMarkdownText
119
+ markdown={markdown}
120
+ onLinkPress={handleLinkPress}
121
+ />
122
+ );
123
+ }
124
+ ```
125
+
126
+ ## Supported Markdown Elements
127
+
128
+ `react-native-enriched-markdown` supports a comprehensive set of Markdown elements:
129
+
130
+ ### Block Elements
131
+
132
+ | Element | Syntax | Description |
133
+ |---------|--------|-------------|
134
+ | Headings | `# H1` to `###### H6` | Six levels of headings |
135
+ | Paragraphs | Plain text | Regular text paragraphs |
136
+ | Blockquotes | `> Quote` | Quoted text with unlimited nesting |
137
+ | Code Blocks | ` ``` code ``` ` | Multi-line code blocks |
138
+ | Unordered Lists | `- Item`, `* Item`, or `+ Item` | Bullet lists with unlimited nesting |
139
+ | Ordered Lists | `1. Item` | Numbered lists with unlimited nesting |
140
+ | Thematic Break | `---`, `***`, or `___` | Visual separator line |
141
+ | Images | `![alt](url)` | Block-level images |
142
+
143
+ ### Inline Elements
144
+
145
+ | Element | Syntax | Description |
146
+ |---------|--------|-------------|
147
+ | Bold | `**text**` or `__text__` | Strong emphasis |
148
+ | Italic | `*text*` or `_text_` | Emphasis |
149
+ | Underline | `_text_` | Underlined text (requires `md4cFlags`) |
150
+ | Strikethrough | `~~text~~` | Strikethrough text |
151
+ | Bold + Italic | `***text***`, `___text___`, etc. | Combined emphasis |
152
+ | Links | `[text](url)` | Clickable links |
153
+ | Inline Code | `` `code` `` | Inline code snippets |
154
+ | Inline Images | `![alt](url)` | Images within text flow |
155
+
156
+ > **Note:** Underscore syntax (`__text__`, `_text_`) works for bold/italic by default. Enable underline via `md4cFlags={{ underline: true }}` to treat `_text_` as underline instead of emphasis.
157
+
158
+ ### Nested Lists Example
159
+
160
+ ```markdown
161
+ - First level
162
+ - Second level
163
+ - Third level
164
+ - Fourth level (unlimited depth!)
165
+
166
+ 1. First item
167
+ 1. Nested numbered
168
+ 1. Deep nested
169
+ 2. Another nested
170
+ 2. Second item
171
+ ```
172
+
173
+ ### Nested Blockquotes Example
174
+
175
+ ```markdown
176
+ > Level 1 quote
177
+ > > Level 2 nested
178
+ > > > Level 3 nested (unlimited depth!)
179
+ ```
180
+
181
+ ## Link Handling
182
+
183
+ Links in Markdown are interactive and can be handled with the `onLinkPress` and `onLinkLongPress` callbacks:
184
+
185
+ ```tsx
186
+ <EnrichedMarkdownText
187
+ markdown="Check out [React Native](https://reactnative.dev)!"
188
+ onLinkPress={({ url }) => {
189
+ Alert.alert('Link pressed', url);
190
+ Linking.openURL(url);
191
+ }}
192
+ onLinkLongPress={({ url }) => {
193
+ Alert.alert('Link long pressed', url);
194
+ }}
195
+ />
196
+ ```
197
+
198
+ ### Link Preview (iOS)
199
+
200
+ By default, long-pressing a link on iOS shows the native system link preview. When you provide `onLinkLongPress`, the system preview is automatically disabled so your handler can fire instead.
201
+
202
+ You can also control this behavior explicitly with the `enableLinkPreview` prop:
203
+
204
+ ```tsx
205
+ // Disable system link preview without providing a handler
206
+ <EnrichedMarkdownText
207
+ markdown={content}
208
+ enableLinkPreview={false}
209
+ />
210
+ ```
211
+
212
+ ## Copy Options
213
+
214
+ When text is selected, `react-native-enriched-markdown` provides enhanced copy functionality through the context menu on both platforms.
215
+
216
+ ### Smart Copy
217
+
218
+ The default **Copy** action copies the selected text with rich formatting support:
219
+
220
+ #### iOS
221
+
222
+ Copies in multiple formats simultaneously — receiving apps pick the richest format they support:
223
+
224
+ | Format | Description |
225
+ |--------|-------------|
226
+ | **Plain Text** | Basic text without formatting |
227
+ | **Markdown** | Original Markdown syntax preserved |
228
+ | **HTML** | Rich HTML representation |
229
+ | **RTF** | Rich Text Format for apps like Notes, Pages |
230
+ | **RTFD** | RTF with embedded images |
231
+
232
+ #### Android
233
+
234
+ Copies as both **Plain Text** and **HTML** — apps that support rich text (like Gmail, Google Docs) will preserve formatting.
235
+
236
+ ### Copy as Markdown
237
+
238
+ 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.
239
+
240
+ ### Copy Image URL
241
+
242
+ 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).
243
+
244
+ ## Accessibility
245
+
246
+ `react-native-enriched-markdown` provides accessibility support for screen readers on both platforms — VoiceOver on iOS and TalkBack on Android.
247
+
248
+ ### Supported Elements
249
+
250
+ | Element | VoiceOver (iOS) | TalkBack (Android) |
251
+ |---------|-----------------|---------------------|
252
+ | **Headings (h1-h6)** | Rotor navigation | Reading controls navigation |
253
+ | **Links** | Rotor navigation, activatable | Reading controls navigation, activatable |
254
+ | **Images** | Alt text announced, rotor navigation | Alt text announced |
255
+ | **List items** | Position announced (e.g., "bullet point", "list item 1") | Position announced |
256
+ | **Nested lists** | Proper depth handling | "Nested" prefix for deeper items |
257
+
258
+ ## Styling Architecture
259
+
260
+ Understanding how `react-native-enriched-markdown` handles styling helps you create consistent, well-designed Markdown content.
261
+
262
+ ### Block vs Inline Elements
263
+
264
+ Markdown elements are divided into two categories:
265
+
266
+ #### Block Elements
267
+
268
+ Block elements are structural containers that define the layout. Each block has its own typography settings (`fontSize`, `fontFamily`, `fontWeight`, `color`, `lineHeight`, `marginTop`, `marginBottom`).
269
+
270
+ | Block Type | Description |
271
+ |------------|-------------|
272
+ | `paragraph` | Default text container |
273
+ | `h1` - `h6` | Heading levels |
274
+ | `blockquote` | Quoted content with accent bar |
275
+ | `list` | Ordered and unordered lists |
276
+ | `codeBlock` | Multi-line code containers |
277
+
278
+ #### Inline Elements
279
+
280
+ Inline elements modify text within blocks. They inherit the parent block's base typography and apply additional styling.
281
+
282
+ | Inline Type | Inherits From | Adds |
283
+ |-------------|---------------|------|
284
+ | `strong` | Parent block | Bold weight, optional color |
285
+ | `em` | Parent block | Italic style, optional color |
286
+ | `strikethrough` | Parent block | Strike line with custom color (iOS only) |
287
+ | `underline` | Parent block | Underline with custom color (iOS only) |
288
+ | `code` | Parent block | Monospace font, background |
289
+ | `link` | Parent block | Color, underline |
290
+
291
+ ### Style Inheritance
292
+
293
+ Inline styles automatically inherit from their containing block:
294
+
295
+ ```
296
+ Heading (h2: fontSize 24, color blue)
297
+ └── Strong text inherits → fontSize 24, color blue + bold weight
298
+ └── Link inherits → fontSize 24 + link color + underline
299
+
300
+ List item (list: fontSize 16, color gray)
301
+ └── Emphasis inherits → fontSize 16, color gray + italic style
302
+ └── Inline code inherits → fontSize 16 + code background
303
+ ```
304
+
305
+ ### Nested Elements
306
+
307
+ Some elements support unlimited nesting depth with automatic indentation:
308
+
309
+ - **Blockquotes**: Each level adds a new accent bar
310
+ - **Unordered Lists**: Each level indents with `marginLeft`
311
+ - **Ordered Lists**: Each level indents and maintains separate numbering
312
+
313
+ ```markdown
314
+ > Level 1
315
+ > > Level 2 (inherits L1 styles + additional indent)
316
+ > > > Level 3 (inherits L2 styles + additional indent)
317
+ ```
318
+
319
+ ### Platform Defaults
320
+
321
+ The library provides sensible defaults optimized for each platform:
322
+
323
+ | Property | iOS | Android |
324
+ |----------|-----|---------|
325
+ | System Font | SF Pro | Roboto |
326
+ | Monospace Font | Menlo | monospace |
327
+ | Line Height | Tighter (0.75x multiplier) | Standard |
328
+
329
+ ## Customizing Styles
330
+
331
+ 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:
332
+
333
+ ```tsx
334
+ <EnrichedMarkdownText
335
+ markdown={content}
336
+ markdownStyle={{
337
+ paragraph: {
338
+ fontSize: 16,
339
+ color: '#333',
340
+ lineHeight: 24,
341
+ },
342
+ h1: {
343
+ fontSize: 32,
344
+ fontWeight: 'bold',
345
+ color: '#000',
346
+ marginBottom: 16,
347
+ textAlign: 'center',
348
+ },
349
+ h2: {
350
+ fontSize: 24,
351
+ fontWeight: '600',
352
+ marginBottom: 12,
353
+ textAlign: 'left',
354
+ },
355
+ strong: {
356
+ color: '#000',
357
+ },
358
+ em: {
359
+ color: '#666',
360
+ },
361
+ strikethrough: {
362
+ color: '#999',
363
+ },
364
+ underline: {
365
+ color: '#333',
366
+ },
367
+ link: {
368
+ color: '#007AFF',
369
+ underline: true,
370
+ },
371
+ code: {
372
+ color: '#E91E63',
373
+ backgroundColor: '#F5F5F5',
374
+ borderColor: '#E0E0E0',
375
+ },
376
+ codeBlock: {
377
+ fontSize: 14,
378
+ fontFamily: 'monospace',
379
+ backgroundColor: '#1E1E1E',
380
+ color: '#D4D4D4',
381
+ padding: 16,
382
+ borderRadius: 8,
383
+ marginBottom: 16,
384
+ },
385
+ blockquote: {
386
+ borderColor: '#007AFF',
387
+ borderWidth: 3,
388
+ backgroundColor: '#F0F8FF',
389
+ marginBottom: 12,
390
+ },
391
+ list: {
392
+ fontSize: 16,
393
+ bulletColor: '#007AFF',
394
+ bulletSize: 6,
395
+ markerColor: '#007AFF',
396
+ gapWidth: 8,
397
+ marginLeft: 20,
398
+ },
399
+ image: {
400
+ borderRadius: 8,
401
+ marginBottom: 12,
402
+ },
403
+ inlineImage: {
404
+ size: 20,
405
+ },
406
+ }}
407
+ />
408
+ ```
409
+
410
+ > [!NOTE]
411
+ > **Performance:** Memoize the `markdownStyle` prop with `useMemo` to avoid unnecessary re-renders:
412
+ > ```tsx
413
+ > import type { MarkdownStyle } from 'react-native-enriched-markdown';
414
+ >
415
+ > const markdownStyle: MarkdownStyle = useMemo(() => ({
416
+ > paragraph: { fontSize: 16 },
417
+ > h1: { fontSize: 32 },
418
+ > }), []);
419
+ > ```
420
+
421
+ ### Style Properties Reference
422
+
423
+ #### Block Styles (paragraph, h1-h6, blockquote, list, codeBlock)
424
+
425
+ | Property | Type | Description |
426
+ |----------|------|-------------|
427
+ | `fontSize` | `number` | Font size in points |
428
+ | `fontFamily` | `string` | Font family name |
429
+ | `fontWeight` | `string` | Font weight |
430
+ | `color` | `string` | Text color |
431
+ | `marginTop` | `number` | Top margin |
432
+ | `marginBottom` | `number` | Bottom margin |
433
+ | `lineHeight` | `number` | Line height |
434
+
435
+ #### Paragraph and Heading-specific (paragraph, h1-h6)
436
+
437
+ | Property | Type | Description |
438
+ |----------|------|-------------|
439
+ | `textAlign` | `'auto' \| 'left' \| 'right' \| 'center' \| 'justify'` | Text alignment (default: `'left'`) |
440
+
441
+ #### Blockquote-specific
442
+
443
+ | Property | Type | Description |
444
+ |----------|------|-------------|
445
+ | `borderColor` | `string` | Left border color |
446
+ | `borderWidth` | `number` | Left border width |
447
+ | `gapWidth` | `number` | Gap between border and text |
448
+ | `backgroundColor` | `string` | Background color |
449
+
450
+ #### List-specific
451
+
452
+ | Property | Type | Description |
453
+ |----------|------|-------------|
454
+ | `bulletColor` | `string` | Bullet point color |
455
+ | `bulletSize` | `number` | Bullet point size |
456
+ | `markerColor` | `string` | Number marker color |
457
+ | `markerFontWeight` | `string` | Number marker font weight |
458
+ | `gapWidth` | `number` | Gap between marker and text |
459
+ | `marginLeft` | `number` | Left margin for nesting |
460
+
461
+ #### Code Block-specific
462
+
463
+ | Property | Type | Description |
464
+ |----------|------|-------------|
465
+ | `backgroundColor` | `string` | Background color |
466
+ | `borderColor` | `string` | Border color |
467
+ | `borderRadius` | `number` | Corner radius |
468
+ | `borderWidth` | `number` | Border width |
469
+ | `padding` | `number` | Inner padding |
470
+
471
+ #### Inline Code-specific
472
+
473
+ | Property | Type | Description |
474
+ |----------|------|-------------|
475
+ | `color` | `string` | Text color |
476
+ | `backgroundColor` | `string` | Background color |
477
+ | `borderColor` | `string` | Border color |
478
+
479
+ #### Link-specific
480
+
481
+ | Property | Type | Description |
482
+ |----------|------|-------------|
483
+ | `color` | `string` | Link text color |
484
+ | `underline` | `boolean` | Show underline |
485
+
486
+ #### Strikethrough-specific
487
+
488
+ | Property | Type | Description |
489
+ |----------|------|-------------|
490
+ | `color` | `string` | Strikethrough line color (iOS only) |
491
+
492
+ #### Underline-specific
493
+
494
+ | Property | Type | Description |
495
+ |----------|------|-------------|
496
+ | `color` | `string` | Underline color (iOS only) |
497
+
498
+ #### Image-specific
499
+
500
+ | Property | Type | Description |
501
+ |----------|------|-------------|
502
+ | `height` | `number` | Image height |
503
+ | `borderRadius` | `number` | Corner radius |
504
+ | `marginTop` | `number` | Top margin |
505
+ | `marginBottom` | `number` | Bottom margin |
506
+
507
+ #### Inline Image-specific
508
+
509
+ | Property | Type | Description |
510
+ |----------|------|-------------|
511
+ | `size` | `number` | Image size (square) |
512
+
513
+ #### Thematic Break (Horizontal Rule)-specific
514
+
515
+ | Property | Type | Description |
516
+ |----------|------|-------------|
517
+ | `color` | `string` | Line color |
518
+ | `height` | `number` | Line thickness |
519
+ | `marginTop` | `number` | Top margin |
520
+ | `marginBottom` | `number` | Bottom margin |
521
+
522
+ ## API Reference
523
+
524
+ ### Props
525
+
526
+ | Prop | Type | Default | Description |
527
+ |------|------|---------|-------------|
528
+ | `markdown` | `string` | Required | The Markdown content to render |
529
+ | `markdownStyle` | `MarkdownStyle` | `{}` | Style configuration for Markdown elements |
530
+ | `containerStyle` | `ViewStyle` | - | Style for the container view |
531
+ | `onLinkPress` | `(event: LinkPressEvent) => void` | - | Callback when a link is pressed. Access URL via `event.url` |
532
+ | `onLinkLongPress` | `(event: LinkLongPressEvent) => void` | - | Callback when a link is long pressed. Access URL via `event.url`. On iOS, automatically disables the system link preview |
533
+ | `enableLinkPreview` | `boolean` | `true` | Controls the native link preview on long press (iOS only). Automatically set to `false` when `onLinkLongPress` is provided |
534
+ | `selectable` | `boolean` | `true` | Whether text can be selected |
535
+ | `md4cFlags` | `Md4cFlags` | `{ underline: false }` | Configuration for md4c parser extension flags |
536
+ | `allowFontScaling` | `boolean` | `true` | Whether fonts should scale to respect Text Size accessibility settings |
537
+ | `maxFontSizeMultiplier` | `number` | `undefined` | Maximum font scale multiplier when `allowFontScaling` is enabled |
538
+ | `allowTrailingMargin` | `boolean` | `false` | Whether to preserve the bottom margin of the last block element |
539
+
540
+ ## Contributing
541
+
542
+ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
543
+
544
+ ## License
545
+
546
+ `react-native-enriched-markdown` library is licensed under [The MIT License](./LICENSE).
547
+
548
+ ---
549
+ Built by [Software Mansion](https://swmansion.com/).
550
+
551
+ [<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
+ }