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
@@ -0,0 +1,17 @@
1
+
2
+ /**
3
+ * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
4
+ *
5
+ * Do not edit this file as changes may cause incorrect behavior and will be lost
6
+ * once the code is regenerated.
7
+ *
8
+ * @generated by codegen project: GenerateShadowNodeCpp.js
9
+ */
10
+
11
+ #include "ShadowNodes.h"
12
+
13
+ namespace facebook::react {
14
+
15
+ extern const char EnrichedMarkdownTextComponentName[] = "EnrichedMarkdownText";
16
+
17
+ } // namespace facebook::react
@@ -0,0 +1,32 @@
1
+
2
+ /**
3
+ * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
4
+ *
5
+ * Do not edit this file as changes may cause incorrect behavior and will be lost
6
+ * once the code is regenerated.
7
+ *
8
+ * @generated by codegen project: GenerateShadowNodeH.js
9
+ */
10
+
11
+ #pragma once
12
+
13
+ #include "EventEmitters.h"
14
+ #include "Props.h"
15
+ #include "States.h"
16
+ #include <react/renderer/components/view/ConcreteViewShadowNode.h>
17
+ #include <jsi/jsi.h>
18
+
19
+ namespace facebook::react {
20
+
21
+ JSI_EXPORT extern const char EnrichedMarkdownTextComponentName[];
22
+
23
+ /*
24
+ * `ShadowNode` for <EnrichedMarkdownText> component.
25
+ */
26
+ using EnrichedMarkdownTextShadowNode = ConcreteViewShadowNode<
27
+ EnrichedMarkdownTextComponentName,
28
+ EnrichedMarkdownTextProps,
29
+ EnrichedMarkdownTextEventEmitter,
30
+ EnrichedMarkdownTextState>;
31
+
32
+ } // namespace facebook::react
@@ -0,0 +1,16 @@
1
+
2
+ /**
3
+ * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
4
+ *
5
+ * Do not edit this file as changes may cause incorrect behavior and will be lost
6
+ * once the code is regenerated.
7
+ *
8
+ * @generated by codegen project: GenerateStateCpp.js
9
+ */
10
+ #include "States.h"
11
+
12
+ namespace facebook::react {
13
+
14
+
15
+
16
+ } // namespace facebook::react
@@ -0,0 +1,20 @@
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: GenerateStateH.js
8
+ */
9
+ #pragma once
10
+
11
+ #include <react/renderer/core/StateData.h>
12
+ #ifdef RN_SERIALIZABLE_STATE
13
+ #include <folly/dynamic.h>
14
+ #endif
15
+
16
+ namespace facebook::react {
17
+
18
+ using EnrichedMarkdownTextState = StateData;
19
+
20
+ } // namespace facebook::react
@@ -0,0 +1,5 @@
1
+ EnrichedMarkdown_kotlinVersion=2.0.21
2
+ EnrichedMarkdown_minSdkVersion=24
3
+ EnrichedMarkdown_targetSdkVersion=34
4
+ EnrichedMarkdown_compileSdkVersion=35
5
+ EnrichedMarkdown_ndkVersion=27.1.12297006
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,65 @@
1
+ # Baseline Profile for react-native-enriched-markdown
2
+ # These classes will be AOT compiled during app install
3
+ # to improve cold start performance.
4
+
5
+ # Core View and Rendering
6
+ Lcom/swmansion/enriched/markdown/EnrichedMarkdownText;
7
+ Lcom/swmansion/enriched/markdown/EnrichedMarkdownTextManager;
8
+ Lcom/swmansion/enriched/markdown/EnrichedMarkdownTextLayoutManager;
9
+
10
+ # Renderer Classes
11
+ Lcom/swmansion/enriched/markdown/renderer/Renderer;
12
+ Lcom/swmansion/enriched/markdown/renderer/RendererFactory;
13
+ Lcom/swmansion/enriched/markdown/renderer/RendererConfig;
14
+ Lcom/swmansion/enriched/markdown/renderer/BlockStyleContext;
15
+ Lcom/swmansion/enriched/markdown/renderer/BlockStyle;
16
+ Lcom/swmansion/enriched/markdown/renderer/SpanStyleCache;
17
+ Lcom/swmansion/enriched/markdown/renderer/NodeRenderer;
18
+ Lcom/swmansion/enriched/markdown/renderer/TextRenderer;
19
+ Lcom/swmansion/enriched/markdown/renderer/ParagraphRenderer;
20
+ Lcom/swmansion/enriched/markdown/renderer/HeadingRenderer;
21
+ Lcom/swmansion/enriched/markdown/renderer/StrongRenderer;
22
+ Lcom/swmansion/enriched/markdown/renderer/EmphasisRenderer;
23
+ Lcom/swmansion/enriched/markdown/renderer/LinkRenderer;
24
+ Lcom/swmansion/enriched/markdown/renderer/ListRenderer;
25
+ Lcom/swmansion/enriched/markdown/renderer/ListItemRenderer;
26
+ Lcom/swmansion/enriched/markdown/renderer/BlockquoteRenderer;
27
+ Lcom/swmansion/enriched/markdown/renderer/CodeBlockRenderer;
28
+ Lcom/swmansion/enriched/markdown/renderer/CodeRenderer;
29
+ Lcom/swmansion/enriched/markdown/renderer/ImageRenderer;
30
+ Lcom/swmansion/enriched/markdown/renderer/LineBreakRenderer;
31
+ Lcom/swmansion/enriched/markdown/renderer/DocumentRenderer;
32
+
33
+ # Spans
34
+ Lcom/swmansion/enriched/markdown/spans/StrongSpan;
35
+ Lcom/swmansion/enriched/markdown/spans/EmphasisSpan;
36
+ Lcom/swmansion/enriched/markdown/spans/CodeSpan;
37
+ Lcom/swmansion/enriched/markdown/spans/TextSpan;
38
+ Lcom/swmansion/enriched/markdown/spans/HeadingSpan;
39
+ Lcom/swmansion/enriched/markdown/spans/LinkSpan;
40
+ Lcom/swmansion/enriched/markdown/spans/LineHeightSpan;
41
+ Lcom/swmansion/enriched/markdown/spans/MarginBottomSpan;
42
+ Lcom/swmansion/enriched/markdown/spans/BaseListSpan;
43
+ Lcom/swmansion/enriched/markdown/spans/UnorderedListSpan;
44
+ Lcom/swmansion/enriched/markdown/spans/OrderedListSpan;
45
+ Lcom/swmansion/enriched/markdown/spans/BlockquoteSpan;
46
+ Lcom/swmansion/enriched/markdown/spans/CodeBlockSpan;
47
+ Lcom/swmansion/enriched/markdown/spans/CodeBackgroundSpan;
48
+ Lcom/swmansion/enriched/markdown/spans/ImageSpan;
49
+
50
+ # Style Configuration
51
+ Lcom/swmansion/enriched/markdown/styles/StyleConfig;
52
+ Lcom/swmansion/enriched/markdown/styles/ParagraphStyle;
53
+ Lcom/swmansion/enriched/markdown/styles/HeadingStyle;
54
+ Lcom/swmansion/enriched/markdown/styles/ListStyle;
55
+ Lcom/swmansion/enriched/markdown/styles/BlockquoteStyle;
56
+ Lcom/swmansion/enriched/markdown/styles/CodeBlockStyle;
57
+ Lcom/swmansion/enriched/markdown/styles/CodeStyle;
58
+
59
+ # Parser
60
+ Lcom/swmansion/enriched/markdown/parser/Parser;
61
+ Lcom/swmansion/enriched/markdown/parser/MarkdownASTNode;
62
+ Lcom/swmansion/enriched/markdown/parser/MarkdownASTNode$NodeType;
63
+
64
+ # Utilities
65
+ Lcom/swmansion/enriched/markdown/utils/UtilsKt;
@@ -0,0 +1,203 @@
1
+ #include "MD4CParser.hpp"
2
+ #include <android/log.h>
3
+ #include <jni.h>
4
+ #include <string>
5
+
6
+ using namespace Markdown;
7
+
8
+ #define ENRICHEDMARKDOWN_LOG_TAG "EnrichedMarkdownJNI"
9
+ #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, ENRICHEDMARKDOWN_LOG_TAG, __VA_ARGS__)
10
+ #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, ENRICHEDMARKDOWN_LOG_TAG, __VA_ARGS__)
11
+
12
+ // Helper function to convert C++ NodeType to Kotlin enum ordinal
13
+ static jint nodeTypeToJavaOrdinal(NodeType type) {
14
+ switch (type) {
15
+ case NodeType::Document:
16
+ return 0;
17
+ case NodeType::Paragraph:
18
+ return 1;
19
+ case NodeType::Text:
20
+ return 2;
21
+ case NodeType::Link:
22
+ return 3;
23
+ case NodeType::Heading:
24
+ return 4;
25
+ case NodeType::LineBreak:
26
+ return 5;
27
+ case NodeType::Strong:
28
+ return 6;
29
+ case NodeType::Emphasis:
30
+ return 7;
31
+ case NodeType::Code:
32
+ return 8;
33
+ case NodeType::Image:
34
+ return 9;
35
+ case NodeType::Blockquote:
36
+ return 10;
37
+ case NodeType::UnorderedList:
38
+ return 11;
39
+ case NodeType::OrderedList:
40
+ return 12;
41
+ case NodeType::ListItem:
42
+ return 13;
43
+ case NodeType::CodeBlock:
44
+ return 14;
45
+ case NodeType::ThematicBreak:
46
+ return 15;
47
+ default:
48
+ return 0;
49
+ }
50
+ }
51
+
52
+ // Helper function to create a Kotlin MarkdownASTNode object from C++ AST node
53
+ static jobject createJavaNode(JNIEnv *env, std::shared_ptr<MarkdownASTNode> node) {
54
+ if (!node) {
55
+ return nullptr;
56
+ }
57
+
58
+ // Find the MarkdownASTNode class
59
+ jclass nodeClass = env->FindClass("com/swmansion/enriched/markdown/parser/MarkdownASTNode");
60
+ if (!nodeClass) {
61
+ LOGE("Failed to find MarkdownASTNode class");
62
+ return nullptr;
63
+ }
64
+
65
+ // Find the NodeType enum class
66
+ jclass nodeTypeClass = env->FindClass("com/swmansion/enriched/markdown/parser/MarkdownASTNode$NodeType");
67
+ if (!nodeTypeClass) {
68
+ LOGE("Failed to find NodeType enum class");
69
+ return nullptr;
70
+ }
71
+
72
+ // Get the enum values array
73
+ jmethodID valuesMethod = env->GetStaticMethodID(
74
+ nodeTypeClass, "values", "()[Lcom/swmansion/enriched/markdown/parser/MarkdownASTNode$NodeType;");
75
+ if (!valuesMethod) {
76
+ LOGE("Failed to find NodeType.values() method");
77
+ return nullptr;
78
+ }
79
+
80
+ jobjectArray enumValues = (jobjectArray)env->CallStaticObjectMethod(nodeTypeClass, valuesMethod);
81
+ if (!enumValues) {
82
+ LOGE("Failed to get NodeType enum values");
83
+ return nullptr;
84
+ }
85
+
86
+ // Get the enum value for this node type
87
+ jint ordinal = nodeTypeToJavaOrdinal(node->type);
88
+ jobject nodeTypeEnum = env->GetObjectArrayElement(enumValues, ordinal);
89
+ if (!nodeTypeEnum) {
90
+ LOGE("Failed to get NodeType enum value at index %d", ordinal);
91
+ return nullptr;
92
+ }
93
+
94
+ // Create content string
95
+ jstring contentStr = env->NewStringUTF(node->content.c_str());
96
+ if (!contentStr && !node->content.empty()) {
97
+ LOGE("Failed to create content string");
98
+ return nullptr;
99
+ }
100
+
101
+ // Create attributes HashMap
102
+ jclass mapClass = env->FindClass("java/util/HashMap");
103
+ jmethodID mapInit = env->GetMethodID(mapClass, "<init>", "(I)V");
104
+ jmethodID mapPut = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
105
+
106
+ jobject attributesMap = env->NewObject(mapClass, mapInit, static_cast<jint>(node->attributes.size()));
107
+
108
+ for (const auto &pair : node->attributes) {
109
+ jstring key = env->NewStringUTF(pair.first.c_str());
110
+ jstring value = env->NewStringUTF(pair.second.c_str());
111
+ env->CallObjectMethod(attributesMap, mapPut, key, value);
112
+ env->DeleteLocalRef(key);
113
+ env->DeleteLocalRef(value);
114
+ }
115
+
116
+ // Create children ArrayList
117
+ jclass listClass = env->FindClass("java/util/ArrayList");
118
+ jmethodID listInit = env->GetMethodID(listClass, "<init>", "(I)V");
119
+ jmethodID listAdd = env->GetMethodID(listClass, "add", "(Ljava/lang/Object;)Z");
120
+
121
+ jobject childrenList = env->NewObject(listClass, listInit, static_cast<jint>(node->children.size()));
122
+
123
+ for (const auto &child : node->children) {
124
+ jobject childObj = createJavaNode(env, child);
125
+ if (childObj) {
126
+ env->CallBooleanMethod(childrenList, listAdd, childObj);
127
+ env->DeleteLocalRef(childObj);
128
+ }
129
+ }
130
+
131
+ // Find the MarkdownASTNode constructor
132
+ // Constructor signature: (Lcom/swmansion/enriched/markdown/parser/MarkdownASTNode$NodeType;Ljava/lang/String;Ljava/util/Map;Ljava/util/List;)V
133
+ jmethodID constructor = env->GetMethodID(nodeClass, "<init>",
134
+ "(Lcom/swmansion/enriched/markdown/parser/MarkdownASTNode$NodeType;Ljava/"
135
+ "lang/String;Ljava/util/Map;Ljava/util/List;)V");
136
+ if (!constructor) {
137
+ LOGE("Failed to find MarkdownASTNode constructor");
138
+ return nullptr;
139
+ }
140
+
141
+ // Create the Kotlin MarkdownASTNode object
142
+ jobject javaNode = env->NewObject(nodeClass, constructor, nodeTypeEnum, contentStr, attributesMap, childrenList);
143
+
144
+ // Clean up local references
145
+ env->DeleteLocalRef(nodeTypeClass);
146
+ env->DeleteLocalRef(enumValues);
147
+ env->DeleteLocalRef(nodeTypeEnum);
148
+ if (contentStr)
149
+ env->DeleteLocalRef(contentStr);
150
+ env->DeleteLocalRef(attributesMap);
151
+ env->DeleteLocalRef(childrenList);
152
+
153
+ return javaNode;
154
+ }
155
+
156
+ extern "C" {
157
+
158
+ JNIEXPORT jobject JNICALL Java_com_swmansion_enriched_markdown_parser_Parser_nativeParseMarkdown(JNIEnv *env,
159
+ jobject /* this */,
160
+ jstring markdown) {
161
+ if (!markdown) {
162
+ LOGE("Markdown string is null");
163
+ return nullptr;
164
+ }
165
+
166
+ const char *markdownStr = env->GetStringUTFChars(markdown, nullptr);
167
+ if (!markdownStr) {
168
+ LOGE("Failed to get UTF-8 chars from markdown string");
169
+ return nullptr;
170
+ }
171
+
172
+ try {
173
+ // Parse markdown using C++ MD4CParser
174
+ MD4CParser parser;
175
+ auto ast = parser.parse(std::string(markdownStr));
176
+
177
+ env->ReleaseStringUTFChars(markdown, markdownStr);
178
+
179
+ if (!ast) {
180
+ LOGE("Parser returned null AST");
181
+ return nullptr;
182
+ }
183
+
184
+ // Convert C++ AST to Kotlin MarkdownASTNode object
185
+ jobject javaNode = createJavaNode(env, ast);
186
+
187
+ if (!javaNode) {
188
+ LOGE("Failed to create Java node from AST");
189
+ }
190
+
191
+ return javaNode;
192
+ } catch (const std::exception &e) {
193
+ env->ReleaseStringUTFChars(markdown, markdownStr);
194
+ LOGE("Exception during parsing: %s", e.what());
195
+ return nullptr;
196
+ } catch (...) {
197
+ env->ReleaseStringUTFChars(markdown, markdownStr);
198
+ LOGE("Unknown exception during parsing");
199
+ return nullptr;
200
+ }
201
+ }
202
+
203
+ } // extern "C"
@@ -0,0 +1,153 @@
1
+ package com.swmansion.enriched.markdown
2
+
3
+ import android.content.Context
4
+ import android.graphics.Color
5
+ import android.os.Handler
6
+ import android.os.Looper
7
+ import android.text.method.LinkMovementMethod
8
+ import android.util.AttributeSet
9
+ import android.util.Log
10
+ import androidx.appcompat.widget.AppCompatTextView
11
+ import com.facebook.react.bridge.ReadableMap
12
+ import com.facebook.react.uimanager.UIManagerHelper
13
+ import com.swmansion.enriched.markdown.events.LinkPressEvent
14
+ import com.swmansion.enriched.markdown.parser.Parser
15
+ import com.swmansion.enriched.markdown.renderer.Renderer
16
+ import com.swmansion.enriched.markdown.styles.StyleConfig
17
+ import com.swmansion.enriched.markdown.utils.createSelectionActionModeCallback
18
+ import java.util.concurrent.Executors
19
+
20
+ /**
21
+ * EnrichedMarkdownText that handles Markdown parsing and rendering on a background thread.
22
+ * Utilizes PrecomputedText for smoother UI updates on supported Android versions.
23
+ */
24
+ class EnrichedMarkdownText
25
+ @JvmOverloads
26
+ constructor(
27
+ context: Context,
28
+ attrs: AttributeSet? = null,
29
+ defStyleAttr: Int = 0,
30
+ ) : AppCompatTextView(context, attrs, defStyleAttr) {
31
+ private val parser = Parser.shared
32
+ private val renderer = Renderer()
33
+ private var onLinkPressCallback: ((String) -> Unit)? = null
34
+
35
+ // Background processing tools
36
+ private val mainHandler = Handler(Looper.getMainLooper())
37
+ private val executor = Executors.newSingleThreadExecutor()
38
+ private var currentRenderId = 0L
39
+
40
+ val layoutManager = EnrichedMarkdownTextLayoutManager(this)
41
+
42
+ var markdownStyle: StyleConfig? = null
43
+ private set
44
+
45
+ var currentMarkdown: String = ""
46
+ private set
47
+
48
+ init {
49
+ setBackgroundColor(Color.TRANSPARENT)
50
+ includeFontPadding = false // Must match setIncludePad(false) in MeasurementStore
51
+ movementMethod = LinkMovementMethod.getInstance()
52
+ setTextIsSelectable(true)
53
+ customSelectionActionModeCallback = createSelectionActionModeCallback(this)
54
+ }
55
+
56
+ fun setMarkdownContent(markdown: String) {
57
+ if (currentMarkdown == markdown) return
58
+ currentMarkdown = markdown
59
+ scheduleRender()
60
+ }
61
+
62
+ fun setMarkdownStyle(style: ReadableMap?) {
63
+ val newStyle = style?.let { StyleConfig(it, context) }
64
+ if (markdownStyle == newStyle) return
65
+
66
+ markdownStyle = newStyle
67
+ scheduleRender()
68
+ }
69
+
70
+ private fun scheduleRender() {
71
+ val style = markdownStyle ?: return
72
+ val markdown = currentMarkdown
73
+ val renderId = ++currentRenderId
74
+ val scheduleStart = System.currentTimeMillis()
75
+
76
+ executor.execute {
77
+ try {
78
+ // 1. Parse Markdown → AST (C++ md4c parser)
79
+ val parseStart = System.currentTimeMillis()
80
+ val ast =
81
+ parser.parseMarkdown(markdown) ?: run {
82
+ mainHandler.post { if (renderId == currentRenderId) text = "" }
83
+ return@execute
84
+ }
85
+ val parseTime = System.currentTimeMillis() - parseStart
86
+
87
+ // 2. Render AST → Spannable
88
+ val renderStart = System.currentTimeMillis()
89
+ renderer.configure(style, context)
90
+ val styledText = renderer.renderDocument(ast, onLinkPressCallback)
91
+ val renderTime = System.currentTimeMillis() - renderStart
92
+
93
+ Log.i(TAG, "┌──────────────────────────────────────────────")
94
+ Log.i(TAG, "│ 📝 Input: ${markdown.length} chars of Markdown")
95
+ Log.i(TAG, "│ ⚡ md4c (C++ native): ${parseTime}ms → ${ast.children.size} AST nodes")
96
+ Log.i(TAG, "│ 🎨 Spannable render: ${renderTime}ms → ${styledText.length} styled chars")
97
+ Log.i(TAG, "└──────────────────────────────────────────────")
98
+
99
+ mainHandler.post {
100
+ if (renderId == currentRenderId) {
101
+ applyRenderedText(styledText)
102
+ Log.i(TAG, "✅ Total time to display: ${System.currentTimeMillis() - scheduleStart}ms")
103
+ }
104
+ }
105
+ } catch (e: Exception) {
106
+ Log.e(TAG, "❌ Render failed: ${e.message}", e)
107
+ mainHandler.post { if (renderId == currentRenderId) text = "" }
108
+ }
109
+ }
110
+ }
111
+
112
+ private fun applyRenderedText(styledText: CharSequence) {
113
+ // Sets the text. If it's PrecomputedText, the UI thread skips the measure pass.
114
+ text = styledText
115
+
116
+ // LinkMovementMethod check (setText can sometimes reset it)
117
+ if (movementMethod !is LinkMovementMethod) {
118
+ movementMethod = LinkMovementMethod.getInstance()
119
+ }
120
+
121
+ // Register ImageSpans from the collector
122
+ renderer.getCollectedImageSpans().forEach { span ->
123
+ span.registerTextView(this)
124
+ }
125
+
126
+ layoutManager.invalidateLayout()
127
+ }
128
+
129
+ fun setIsSelectable(selectable: Boolean) {
130
+ if (isTextSelectable == selectable) return
131
+ setTextIsSelectable(selectable)
132
+ movementMethod = LinkMovementMethod.getInstance()
133
+ if (!selectable && !isClickable) isClickable = true
134
+ }
135
+
136
+ fun emitOnLinkPress(url: String) {
137
+ val reactContext = context as? com.facebook.react.bridge.ReactContext ?: return
138
+ val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
139
+ val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id)
140
+
141
+ dispatcher?.dispatchEvent(
142
+ LinkPressEvent(surfaceId, id, url),
143
+ )
144
+ }
145
+
146
+ fun setOnLinkPressCallback(callback: (String) -> Unit) {
147
+ onLinkPressCallback = callback
148
+ }
149
+
150
+ companion object {
151
+ private const val TAG = "EnrichedMarkdownMeasure"
152
+ }
153
+ }
@@ -0,0 +1,30 @@
1
+ package com.swmansion.enriched.markdown
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.uimanager.StateWrapper
5
+
6
+ class EnrichedMarkdownTextLayoutManager(
7
+ private val view: EnrichedMarkdownText,
8
+ ) {
9
+ private var forceHeightRecalculationCounter: Int = 0
10
+
11
+ var stateWrapper: StateWrapper? = null
12
+
13
+ fun invalidateLayout() {
14
+ val text = view.text
15
+ val paint = view.paint
16
+
17
+ val needUpdate = MeasurementStore.store(view.id, text, paint)
18
+ if (!needUpdate) return
19
+
20
+ val counter = forceHeightRecalculationCounter
21
+ forceHeightRecalculationCounter++
22
+ val state = Arguments.createMap()
23
+ state.putInt("forceHeightRecalculationCounter", counter)
24
+ stateWrapper?.updateState(state)
25
+ }
26
+
27
+ fun releaseMeasurementStore() {
28
+ MeasurementStore.release(view.id)
29
+ }
30
+ }
@@ -0,0 +1,119 @@
1
+ package com.swmansion.enriched.markdown
2
+
3
+ import android.content.Context
4
+ import com.facebook.react.bridge.ReadableMap
5
+ import com.facebook.react.module.annotations.ReactModule
6
+ import com.facebook.react.uimanager.ReactStylesDiffMap
7
+ import com.facebook.react.uimanager.SimpleViewManager
8
+ import com.facebook.react.uimanager.StateWrapper
9
+ import com.facebook.react.uimanager.ThemedReactContext
10
+ import com.facebook.react.uimanager.UIManagerHelper
11
+ import com.facebook.react.uimanager.ViewManagerDelegate
12
+ import com.facebook.react.uimanager.annotations.ReactProp
13
+ import com.facebook.react.viewmanagers.EnrichedMarkdownTextManagerDelegate
14
+ import com.facebook.react.viewmanagers.EnrichedMarkdownTextManagerInterface
15
+ import com.facebook.yoga.YogaMeasureMode
16
+ import com.swmansion.enriched.markdown.events.LinkPressEvent
17
+
18
+ @ReactModule(name = EnrichedMarkdownTextManager.NAME)
19
+ class EnrichedMarkdownTextManager :
20
+ SimpleViewManager<EnrichedMarkdownText>(),
21
+ EnrichedMarkdownTextManagerInterface<EnrichedMarkdownText> {
22
+ private val mDelegate: ViewManagerDelegate<EnrichedMarkdownText> = EnrichedMarkdownTextManagerDelegate(this)
23
+
24
+ override fun getDelegate(): ViewManagerDelegate<EnrichedMarkdownText>? = mDelegate
25
+
26
+ override fun getName(): String = NAME
27
+
28
+ override fun createViewInstance(reactContext: ThemedReactContext): EnrichedMarkdownText = EnrichedMarkdownText(reactContext)
29
+
30
+ override fun onDropViewInstance(view: EnrichedMarkdownText) {
31
+ super.onDropViewInstance(view)
32
+ view.layoutManager.releaseMeasurementStore()
33
+ }
34
+
35
+ override fun updateState(
36
+ view: EnrichedMarkdownText,
37
+ props: ReactStylesDiffMap?,
38
+ stateWrapper: StateWrapper?,
39
+ ): Any? {
40
+ view.layoutManager.stateWrapper = stateWrapper
41
+ return super.updateState(view, props, stateWrapper)
42
+ }
43
+
44
+ override fun getExportedCustomDirectEventTypeConstants(): MutableMap<String, Any> {
45
+ val map = mutableMapOf<String, Any>()
46
+ map.put(LinkPressEvent.EVENT_NAME, mapOf("registrationName" to LinkPressEvent.EVENT_NAME))
47
+ return map
48
+ }
49
+
50
+ @ReactProp(name = "markdown")
51
+ override fun setMarkdown(
52
+ view: EnrichedMarkdownText?,
53
+ markdown: String?,
54
+ ) {
55
+ view?.setOnLinkPressCallback { url ->
56
+ emitOnLinkPress(view, url)
57
+ }
58
+
59
+ view?.setMarkdownContent(markdown ?: "No markdown content")
60
+ }
61
+
62
+ @ReactProp(name = "markdownStyle")
63
+ override fun setMarkdownStyle(
64
+ view: EnrichedMarkdownText?,
65
+ style: com.facebook.react.bridge.ReadableMap?,
66
+ ) {
67
+ view?.setMarkdownStyle(style)
68
+ }
69
+
70
+ @ReactProp(name = "isSelectable", defaultBoolean = true)
71
+ override fun setIsSelectable(
72
+ view: EnrichedMarkdownText?,
73
+ selectable: Boolean,
74
+ ) {
75
+ view?.setIsSelectable(selectable)
76
+ }
77
+
78
+ override fun setPadding(
79
+ view: EnrichedMarkdownText,
80
+ left: Int,
81
+ top: Int,
82
+ right: Int,
83
+ bottom: Int,
84
+ ) {
85
+ super.setPadding(view, left, top, right, bottom)
86
+ view.setPadding(left, top, right, bottom)
87
+ }
88
+
89
+ private fun emitOnLinkPress(
90
+ view: EnrichedMarkdownText,
91
+ url: String,
92
+ ) {
93
+ val context = view.context as com.facebook.react.bridge.ReactContext
94
+ val surfaceId = UIManagerHelper.getSurfaceId(context)
95
+ val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, view.id)
96
+ val event = LinkPressEvent(surfaceId, view.id, url)
97
+
98
+ eventDispatcher?.dispatchEvent(event)
99
+ }
100
+
101
+ override fun measure(
102
+ context: Context,
103
+ localData: ReadableMap?,
104
+ props: ReadableMap?,
105
+ state: ReadableMap?,
106
+ width: Float,
107
+ widthMode: YogaMeasureMode?,
108
+ height: Float,
109
+ heightMode: YogaMeasureMode?,
110
+ attachmentsPositions: FloatArray?,
111
+ ): Long {
112
+ val id = localData?.getInt("viewTag")
113
+ return MeasurementStore.getMeasureById(context, id, width, height, heightMode, props)
114
+ }
115
+
116
+ companion object {
117
+ const val NAME = "EnrichedMarkdownText"
118
+ }
119
+ }