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
@@ -0,0 +1,327 @@
1
+ #include "MD4CParser.hpp"
2
+ #include "../md4c/md4c.h"
3
+ #include <cstring>
4
+ #include <vector>
5
+
6
+ namespace Markdown {
7
+
8
+ class MD4CParser::Impl {
9
+ public:
10
+ std::shared_ptr<MarkdownASTNode> root;
11
+ std::vector<std::shared_ptr<MarkdownASTNode>> nodeStack;
12
+ std::string currentText;
13
+ const char *inputText = nullptr;
14
+
15
+ static const std::string ATTR_LEVEL;
16
+ static const std::string ATTR_URL;
17
+ static const std::string ATTR_TITLE;
18
+ static const std::string ATTR_FENCE_CHAR;
19
+ static const std::string ATTR_LANGUAGE;
20
+
21
+ void reset(size_t estimatedDepth) {
22
+ root = std::make_shared<MarkdownASTNode>(NodeType::Document);
23
+ nodeStack.clear();
24
+ // Reserve based on estimated depth, with reasonable bounds
25
+ // Typical markdown has 5-15 levels, but can go deeper with nested structures
26
+ // Cap at 128 to avoid excessive memory for extreme cases
27
+ nodeStack.reserve(std::min(estimatedDepth, static_cast<size_t>(128)));
28
+ nodeStack.push_back(root);
29
+ currentText.clear();
30
+ currentText.reserve(256);
31
+ }
32
+
33
+ void flushText() {
34
+ if (!currentText.empty() && !nodeStack.empty()) {
35
+ auto textNode = std::make_shared<MarkdownASTNode>(NodeType::Text);
36
+ textNode->content = std::move(currentText);
37
+ nodeStack.back()->addChild(std::move(textNode));
38
+ currentText.clear();
39
+ }
40
+ }
41
+
42
+ void pushNode(std::shared_ptr<MarkdownASTNode> node) {
43
+ flushText();
44
+ if (node && !nodeStack.empty()) {
45
+ nodeStack.back()->addChild(node);
46
+ nodeStack.push_back(std::move(node));
47
+ }
48
+ }
49
+
50
+ void popNode() {
51
+ flushText();
52
+ if (nodeStack.size() > 1) {
53
+ nodeStack.pop_back();
54
+ }
55
+ }
56
+
57
+ void addInlineNode(std::shared_ptr<MarkdownASTNode> node) {
58
+ if (node && !nodeStack.empty()) {
59
+ nodeStack.back()->addChild(node);
60
+ }
61
+ }
62
+
63
+ std::string getAttributeText(const MD_ATTRIBUTE *attr) {
64
+ if (!attr || attr->size == 0 || !attr->text)
65
+ return {};
66
+
67
+ // Use string constructor directly - let SSO handle small strings efficiently
68
+ // Empty return {} avoids allocating empty string object
69
+ return std::string(attr->text, attr->size);
70
+ }
71
+
72
+ static int enterBlock(MD_BLOCKTYPE type, void *detail, void *userdata) {
73
+ if (!userdata)
74
+ return 1;
75
+ auto *impl = static_cast<Impl *>(userdata);
76
+
77
+ switch (type) {
78
+ case MD_BLOCK_DOC:
79
+ // Document node already created in reset()
80
+ break;
81
+
82
+ case MD_BLOCK_P: {
83
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::Paragraph));
84
+ break;
85
+ }
86
+
87
+ case MD_BLOCK_H: {
88
+ auto node = std::make_shared<MarkdownASTNode>(NodeType::Heading);
89
+ if (detail) {
90
+ auto *h = static_cast<MD_BLOCK_H_DETAIL *>(detail);
91
+ int level = static_cast<int>(h->level);
92
+ // Clamp level to valid range (1-6)
93
+ level = (level < 1) ? 1 : (level > 6) ? 6 : level;
94
+ // Use char conversion for small integers (1-6)
95
+ // Avoids std::to_string() allocation overhead
96
+ char levelStr[2] = {static_cast<char>('0' + level), '\0'};
97
+ node->setAttribute(ATTR_LEVEL, levelStr);
98
+ }
99
+ impl->pushNode(node);
100
+ break;
101
+ }
102
+
103
+ case MD_BLOCK_QUOTE: {
104
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::Blockquote));
105
+ break;
106
+ }
107
+
108
+ case MD_BLOCK_UL: {
109
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::UnorderedList));
110
+ break;
111
+ }
112
+
113
+ case MD_BLOCK_OL: {
114
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::OrderedList));
115
+ break;
116
+ }
117
+
118
+ case MD_BLOCK_LI: {
119
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::ListItem));
120
+ break;
121
+ }
122
+
123
+ case MD_BLOCK_CODE: {
124
+ auto node = std::make_shared<MarkdownASTNode>(NodeType::CodeBlock);
125
+ if (detail) {
126
+ auto *codeDetail = static_cast<MD_BLOCK_CODE_DETAIL *>(detail);
127
+ // Extract fence character (if fenced code block)
128
+ if (codeDetail->fence_char != 0) {
129
+ char fenceStr[2] = {static_cast<char>(codeDetail->fence_char), '\0'};
130
+ node->setAttribute(ATTR_FENCE_CHAR, fenceStr);
131
+ }
132
+ // Extract language from lang attribute
133
+ std::string lang = impl->getAttributeText(&codeDetail->lang);
134
+ if (!lang.empty()) {
135
+ node->setAttribute(ATTR_LANGUAGE, lang);
136
+ }
137
+ }
138
+ impl->pushNode(node);
139
+ break;
140
+ }
141
+
142
+ case MD_BLOCK_HR: {
143
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::ThematicBreak));
144
+ break;
145
+ }
146
+
147
+ default:
148
+ // Other block types not yet implemented
149
+ break;
150
+ }
151
+
152
+ return 0;
153
+ }
154
+
155
+ static int leaveBlock(MD_BLOCKTYPE type, void *detail, void *userdata) {
156
+ (void)detail;
157
+ if (!userdata)
158
+ return 1;
159
+ auto *impl = static_cast<Impl *>(userdata);
160
+
161
+ if (type != MD_BLOCK_DOC && !impl->nodeStack.empty()) {
162
+ impl->popNode();
163
+ }
164
+
165
+ return 0;
166
+ }
167
+
168
+ static int enterSpan(MD_SPANTYPE type, void *detail, void *userdata) {
169
+ if (!userdata)
170
+ return 1;
171
+ auto *impl = static_cast<Impl *>(userdata);
172
+
173
+ switch (type) {
174
+ case MD_SPAN_A: {
175
+ auto node = std::make_shared<MarkdownASTNode>(NodeType::Link);
176
+ if (detail) {
177
+ auto *linkDetail = static_cast<MD_SPAN_A_DETAIL *>(detail);
178
+ std::string url = impl->getAttributeText(&linkDetail->href);
179
+ if (!url.empty()) {
180
+ node->setAttribute(ATTR_URL, url);
181
+ }
182
+ }
183
+ impl->pushNode(node);
184
+ break;
185
+ }
186
+
187
+ case MD_SPAN_STRONG: {
188
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::Strong));
189
+ break;
190
+ }
191
+
192
+ case MD_SPAN_EM: {
193
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::Emphasis));
194
+ break;
195
+ }
196
+
197
+ case MD_SPAN_U: {
198
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::Underline));
199
+ break;
200
+ }
201
+
202
+ case MD_SPAN_CODE: {
203
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::Code));
204
+ break;
205
+ }
206
+
207
+ case MD_SPAN_DEL: {
208
+ impl->pushNode(std::make_shared<MarkdownASTNode>(NodeType::Strikethrough));
209
+ break;
210
+ }
211
+
212
+ case MD_SPAN_IMG: {
213
+ auto node = std::make_shared<MarkdownASTNode>(NodeType::Image);
214
+ if (detail) {
215
+ auto *imgDetail = static_cast<MD_SPAN_IMG_DETAIL *>(detail);
216
+ std::string url = impl->getAttributeText(&imgDetail->src);
217
+ if (!url.empty()) {
218
+ node->setAttribute(ATTR_URL, url);
219
+ }
220
+ std::string title = impl->getAttributeText(&imgDetail->title);
221
+ if (!title.empty()) {
222
+ node->setAttribute(ATTR_TITLE, title);
223
+ }
224
+ }
225
+ impl->pushNode(node);
226
+ break;
227
+ }
228
+
229
+ default:
230
+ break;
231
+ }
232
+
233
+ return 0;
234
+ }
235
+
236
+ static int leaveSpan(MD_SPANTYPE type, void *detail, void *userdata) {
237
+ (void)detail;
238
+ if (!userdata)
239
+ return 1;
240
+ auto *impl = static_cast<Impl *>(userdata);
241
+
242
+ if (!impl->nodeStack.empty()) {
243
+ impl->popNode();
244
+ }
245
+
246
+ return 0;
247
+ }
248
+
249
+ static int text(MD_TEXTTYPE type, const MD_CHAR *text, MD_SIZE size, void *userdata) {
250
+ if (!userdata || !text || size == 0)
251
+ return 0;
252
+ auto *impl = static_cast<Impl *>(userdata);
253
+
254
+ // Handle soft/hard line breaks
255
+ if (type == MD_TEXT_SOFTBR || type == MD_TEXT_BR) {
256
+ auto brNode = std::make_shared<MarkdownASTNode>(NodeType::LineBreak);
257
+ impl->addInlineNode(brNode);
258
+ return 0;
259
+ }
260
+
261
+ // Handle text content (normal text, code text, etc.)
262
+ if (type == MD_TEXT_NORMAL || type == MD_TEXT_CODE) {
263
+ impl->currentText.append(text, size);
264
+ }
265
+
266
+ return 0;
267
+ }
268
+ };
269
+
270
+ MD4CParser::MD4CParser() : impl_(std::make_unique<Impl>()) {}
271
+
272
+ MD4CParser::~MD4CParser() = default;
273
+
274
+ std::shared_ptr<MarkdownASTNode> MD4CParser::parse(const std::string &markdown, const Md4cFlags &md4cFlags) {
275
+ if (markdown.empty()) {
276
+ return std::make_shared<MarkdownASTNode>(NodeType::Document);
277
+ }
278
+
279
+ // Estimate stack depth based on markdown size
280
+ // Heuristic: ~1 nesting level per 500-1000 characters for typical markdown
281
+ // This is a rough estimate - actual depth depends on structure, not just size
282
+ // Base depth of 12 covers typical nested structures (blockquotes, future lists)
283
+ size_t estimatedDepth = 12; // Base depth for small documents
284
+ if (markdown.size() > 1000) {
285
+ // Scale up for larger documents, but cap the growth
286
+ estimatedDepth = std::min(static_cast<size_t>(12 + (markdown.size() / 1000)), static_cast<size_t>(64));
287
+ }
288
+
289
+ impl_->reset(estimatedDepth);
290
+ impl_->inputText = markdown.c_str();
291
+
292
+ // MD_FLAG_NOHTML: Disable HTML parsing
293
+ // MD_FLAG_STRIKETHROUGH: Enable ~~strikethrough~~ syntax
294
+ // MD_FLAG_UNDERLINE: When enabled, __ creates underline; when disabled, __ creates emphasis
295
+ unsigned flags = MD_FLAG_NOHTML | MD_FLAG_STRIKETHROUGH;
296
+ if (md4cFlags.underline) {
297
+ flags |= MD_FLAG_UNDERLINE;
298
+ }
299
+
300
+ // Configure MD4C parser with callbacks
301
+ MD_PARSER parser = {
302
+ 0, // abi_version
303
+ flags, &Impl::enterBlock, &Impl::leaveBlock, &Impl::enterSpan, &Impl::leaveSpan, &Impl::text,
304
+ nullptr, // debug_log
305
+ nullptr // syntax
306
+ };
307
+
308
+ // Parse the markdown
309
+ int result = md_parse(markdown.c_str(), static_cast<MD_SIZE>(markdown.size()), &parser, impl_.get());
310
+
311
+ if (result != 0) {
312
+ // Parsing failed, return empty document
313
+ return std::make_shared<MarkdownASTNode>(NodeType::Document);
314
+ }
315
+
316
+ impl_->flushText();
317
+ return impl_->root ? impl_->root : std::make_shared<MarkdownASTNode>(NodeType::Document);
318
+ }
319
+
320
+ // Static member definitions
321
+ const std::string MD4CParser::Impl::ATTR_LEVEL = "level";
322
+ const std::string MD4CParser::Impl::ATTR_URL = "url";
323
+ const std::string MD4CParser::Impl::ATTR_TITLE = "title";
324
+ const std::string MD4CParser::Impl::ATTR_FENCE_CHAR = "fenceChar";
325
+ const std::string MD4CParser::Impl::ATTR_LANGUAGE = "language";
326
+
327
+ } // namespace Markdown
@@ -0,0 +1,27 @@
1
+ #pragma once
2
+
3
+ #include "MarkdownASTNode.hpp"
4
+ #include <string>
5
+ #include <memory>
6
+
7
+ namespace Markdown {
8
+
9
+ struct Md4cFlags {
10
+ bool underline = false;
11
+ };
12
+
13
+ class MD4CParser {
14
+ public:
15
+ MD4CParser();
16
+ ~MD4CParser();
17
+
18
+ // Parse markdown string and return AST root node
19
+ std::shared_ptr<MarkdownASTNode> parse(const std::string& markdown, const Md4cFlags& flags = Md4cFlags{});
20
+
21
+ private:
22
+ class Impl;
23
+ std::unique_ptr<Impl> impl_;
24
+ };
25
+
26
+ } // namespace Markdown
27
+
@@ -0,0 +1,51 @@
1
+ #pragma once
2
+
3
+ #include <string>
4
+ #include <memory>
5
+ #include <vector>
6
+ #include <unordered_map>
7
+
8
+ namespace Markdown {
9
+
10
+ enum class NodeType {
11
+ Document,
12
+ Paragraph,
13
+ Text,
14
+ Link,
15
+ Heading,
16
+ LineBreak,
17
+ Strong,
18
+ Emphasis,
19
+ Strikethrough,
20
+ Underline,
21
+ Code,
22
+ Image,
23
+ Blockquote,
24
+ UnorderedList,
25
+ OrderedList,
26
+ ListItem,
27
+ CodeBlock,
28
+ ThematicBreak
29
+ };
30
+
31
+ struct MarkdownASTNode {
32
+ NodeType type;
33
+ std::string content;
34
+ std::unordered_map<std::string, std::string> attributes;
35
+ std::vector<std::shared_ptr<MarkdownASTNode>> children;
36
+
37
+ explicit MarkdownASTNode(NodeType t) : type(t) {}
38
+
39
+ void addChild(std::shared_ptr<MarkdownASTNode> child) {
40
+ if (child) {
41
+ children.push_back(std::move(child));
42
+ }
43
+ }
44
+
45
+ void setAttribute(const std::string& key, const std::string& value) {
46
+ attributes[key] = value;
47
+ }
48
+ };
49
+
50
+ } // namespace Markdown
51
+
@@ -0,0 +1,18 @@
1
+ #import "StyleConfig.h"
2
+ #import <React/RCTViewComponentView.h>
3
+ #import <UIKit/UIKit.h>
4
+
5
+ #ifndef EnrichedMarkdownTextNativeComponent_h
6
+ #define EnrichedMarkdownTextNativeComponent_h
7
+
8
+ NS_ASSUME_NONNULL_BEGIN
9
+
10
+ @interface EnrichedMarkdownText : RCTViewComponentView
11
+ @property (nonatomic, strong) StyleConfig *config;
12
+ - (CGSize)measureSize:(CGFloat)maxWidth;
13
+ - (void)renderMarkdownSynchronously:(NSString *)markdownString;
14
+ @end
15
+
16
+ NS_ASSUME_NONNULL_END
17
+
18
+ #endif