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,23 @@
1
+ #pragma once
2
+ #import <UIKit/UIKit.h>
3
+
4
+ @class StyleConfig;
5
+ @class UITextView;
6
+
7
+ NS_ASSUME_NONNULL_BEGIN
8
+
9
+ /**
10
+ * Custom NSTextAttachment for rendering markdown images.
11
+ * Images are loaded asynchronously and scaled dynamically based on text container width.
12
+ * Supports inline and block images with custom height and border radius from config.
13
+ */
14
+ @interface EnrichedMarkdownImageAttachment : NSTextAttachment
15
+
16
+ @property (nonatomic, readonly) NSString *imageURL;
17
+ @property (nonatomic, readonly) BOOL isInline;
18
+
19
+ - (instancetype)initWithImageURL:(NSString *)imageURL config:(StyleConfig *)config isInline:(BOOL)isInline;
20
+
21
+ @end
22
+
23
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,185 @@
1
+ #import "EnrichedMarkdownImageAttachment.h"
2
+ #import "RuntimeKeys.h"
3
+ #import "StyleConfig.h"
4
+ #import <React/RCTLog.h>
5
+ #import <objc/runtime.h>
6
+
7
+ @interface EnrichedMarkdownImageAttachment ()
8
+ @property (nonatomic, readwrite) NSString *imageURL;
9
+ @property (nonatomic, weak) StyleConfig *config;
10
+ @property (nonatomic, assign) BOOL isInline;
11
+ @property (nonatomic, assign) CGFloat cachedHeight;
12
+ @property (nonatomic, assign) CGFloat cachedBorderRadius;
13
+ @property (nonatomic, weak) NSTextContainer *textContainer;
14
+ @property (nonatomic, weak) UITextView *textView;
15
+ @property (nonatomic, strong) UIImage *originalImage;
16
+ @property (nonatomic, strong) UIImage *loadedImage;
17
+ @property (nonatomic, strong) NSURLSessionDataTask *loadingTask;
18
+ @end
19
+
20
+ @implementation EnrichedMarkdownImageAttachment
21
+
22
+ - (instancetype)initWithImageURL:(NSString *)imageURL config:(StyleConfig *)config isInline:(BOOL)isInline
23
+ {
24
+ if (self = [super init]) {
25
+ _imageURL = imageURL;
26
+ _config = config;
27
+ _isInline = isInline;
28
+ _cachedHeight = isInline ? [config inlineImageSize] : [config imageHeight];
29
+ _cachedBorderRadius = [config imageBorderRadius];
30
+
31
+ [self setupPlaceholder];
32
+ [self loadImage];
33
+ }
34
+ return self;
35
+ }
36
+
37
+ - (CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer
38
+ proposedLineFragment:(CGRect)lineFrag
39
+ glyphPosition:(CGPoint)position
40
+ characterIndex:(NSUInteger)charIndex
41
+ {
42
+ CGFloat height = self.cachedHeight;
43
+ CGFloat width = self.isInline ? height : (lineFrag.size.width > 0 ? lineFrag.size.width : height);
44
+ return CGRectMake(0, 0, width, height);
45
+ }
46
+
47
+ - (UIImage *)imageForBounds:(CGRect)imageBounds
48
+ textContainer:(NSTextContainer *)textContainer
49
+ characterIndex:(NSUInteger)charIndex
50
+ {
51
+ self.textContainer = textContainer;
52
+
53
+ // If width is now known but we haven't scaled yet, trigger it
54
+ if (self.originalImage && !self.loadedImage && imageBounds.size.width > 0) {
55
+ self.bounds = imageBounds;
56
+ [self handleLoadedImage:self.originalImage];
57
+ }
58
+
59
+ return self.loadedImage ?: self.image;
60
+ }
61
+
62
+ - (void)handleLoadedImage:(UIImage *)image
63
+ {
64
+ if (!image)
65
+ return;
66
+ self.originalImage = image;
67
+
68
+ __weak typeof(self) weakSelf = self;
69
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
70
+ __strong typeof(weakSelf) strongSelf = weakSelf;
71
+ if (!strongSelf)
72
+ return;
73
+
74
+ CGFloat targetWidth = strongSelf.isInline ? strongSelf.cachedHeight : strongSelf.bounds.size.width;
75
+ if (targetWidth <= 0)
76
+ return;
77
+
78
+ UIImage *scaled = [strongSelf scaleImage:image
79
+ toWidth:targetWidth
80
+ height:strongSelf.cachedHeight
81
+ borderRadius:strongSelf.cachedBorderRadius];
82
+
83
+ dispatch_async(dispatch_get_main_queue(), ^{
84
+ strongSelf.loadedImage = scaled;
85
+
86
+ if (strongSelf.isInline) {
87
+ // Use scaled image for RTF export (RTF uses self.image dimensions)
88
+ strongSelf.image = scaled;
89
+ strongSelf.bounds = CGRectMake(0, 0, strongSelf.cachedHeight, strongSelf.cachedHeight);
90
+ } else {
91
+ // Use original for "Save to Camera Roll" (no baked-in rounded corners)
92
+ strongSelf.image = image;
93
+ }
94
+
95
+ [strongSelf updateUI];
96
+ });
97
+ });
98
+ }
99
+
100
+ - (void)updateUI
101
+ {
102
+ UITextView *textView = [self getTextView];
103
+ if (!textView)
104
+ return;
105
+
106
+ NSRange range = [self findAttachmentRangeInText:textView.attributedText];
107
+ if (range.location == NSNotFound)
108
+ return;
109
+
110
+ [textView.layoutManager invalidateDisplayForCharacterRange:range];
111
+ if (!self.isInline) {
112
+ [textView.layoutManager invalidateLayoutForCharacterRange:range actualCharacterRange:NULL];
113
+ }
114
+ }
115
+
116
+ - (UITextView *)getTextView
117
+ {
118
+ if (self.textView)
119
+ return self.textView;
120
+ if (!self.textContainer)
121
+ return nil;
122
+ self.textView = objc_getAssociatedObject(self.textContainer, kTextViewKey);
123
+ return self.textView;
124
+ }
125
+
126
+ - (void)setupPlaceholder
127
+ {
128
+ CGFloat size = self.cachedHeight;
129
+ self.bounds = CGRectMake(0, 0, size, size);
130
+ UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:CGSizeMake(size, size)];
131
+ self.image = [renderer imageWithActions:^(UIGraphicsImageRendererContext *ctx){}];
132
+ }
133
+
134
+ - (void)loadImage
135
+ {
136
+ if (self.imageURL.length == 0)
137
+ return;
138
+ NSURL *url = [NSURL URLWithString:self.imageURL];
139
+ if (!url)
140
+ return;
141
+
142
+ __weak typeof(self) weakSelf = self;
143
+ self.loadingTask =
144
+ [[NSURLSession sharedSession] dataTaskWithURL:url
145
+ completionHandler:^(NSData *data, NSURLResponse *res, NSError *err) {
146
+ if (data) {
147
+ UIImage *img = [UIImage imageWithData:data];
148
+ dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf handleLoadedImage:img]; });
149
+ }
150
+ }];
151
+ [self.loadingTask resume];
152
+ }
153
+
154
+ - (UIImage *)scaleImage:(UIImage *)image toWidth:(CGFloat)w height:(CGFloat)h borderRadius:(CGFloat)r
155
+ {
156
+ UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:CGSizeMake(w, h)];
157
+ return [renderer imageWithActions:^(UIGraphicsImageRendererContext *ctx) {
158
+ if (r > 0) {
159
+ [[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, w, h) cornerRadius:r] addClip];
160
+ }
161
+ [image drawInRect:CGRectMake(0, 0, w, h)];
162
+ }];
163
+ }
164
+
165
+ - (NSRange)findAttachmentRangeInText:(NSAttributedString *)text
166
+ {
167
+ __block NSRange found = NSMakeRange(NSNotFound, 0);
168
+ [text enumerateAttribute:NSAttachmentAttributeName
169
+ inRange:NSMakeRange(0, text.length)
170
+ options:0
171
+ usingBlock:^(id val, NSRange range, BOOL *stop) {
172
+ if (val == self) {
173
+ found = range;
174
+ *stop = YES;
175
+ }
176
+ }];
177
+ return found;
178
+ }
179
+
180
+ - (void)dealloc
181
+ {
182
+ [_loadingTask cancel];
183
+ }
184
+
185
+ @end
@@ -0,0 +1,15 @@
1
+ #pragma once
2
+ #import <UIKit/UIKit.h>
3
+
4
+ NS_ASSUME_NONNULL_BEGIN
5
+
6
+ @interface ThematicBreakAttachment : NSTextAttachment
7
+
8
+ @property (nonatomic, strong) UIColor *lineColor;
9
+ @property (nonatomic, assign) CGFloat lineHeight;
10
+ @property (nonatomic, assign) CGFloat marginTop;
11
+ @property (nonatomic, assign) CGFloat marginBottom;
12
+
13
+ @end
14
+
15
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,33 @@
1
+ #import "ThematicBreakAttachment.h"
2
+
3
+ @implementation ThematicBreakAttachment
4
+
5
+ - (CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer
6
+ proposedLineFragment:(CGRect)lineFrag
7
+ glyphPosition:(CGPoint)position
8
+ characterIndex:(NSUInteger)charIndex
9
+ {
10
+ CGFloat totalHeight = self.marginTop + self.lineHeight + self.marginBottom;
11
+ return CGRectMake(0, 0, CGRectGetWidth(lineFrag), totalHeight);
12
+ }
13
+
14
+ - (UIImage *)imageForBounds:(CGRect)imageBounds
15
+ textContainer:(NSTextContainer *)textContainer
16
+ characterIndex:(NSUInteger)charIndex
17
+ {
18
+ UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:imageBounds.size];
19
+
20
+ return [renderer imageWithActions:^(UIGraphicsImageRendererContext *_Nonnull rendererContext) {
21
+ CGContextRef ctx = rendererContext.CGContext;
22
+
23
+ CGFloat lineY = self.marginTop + (self.lineHeight / 2.0);
24
+
25
+ [self.lineColor setStroke];
26
+ CGContextSetLineWidth(ctx, self.lineHeight);
27
+ CGContextMoveToPoint(ctx, 0, lineY);
28
+ CGContextAddLineToPoint(ctx, imageBounds.size.width, lineY);
29
+ CGContextStrokePath(ctx);
30
+ }];
31
+ }
32
+
33
+ @end
@@ -0,0 +1,22 @@
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: GenerateComponentDescriptorCpp.js
9
+ */
10
+
11
+ #include "ComponentDescriptors.h"
12
+ #include <react/renderer/core/ConcreteComponentDescriptor.h>
13
+ #include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
14
+
15
+ namespace facebook::react {
16
+
17
+ void EnrichedMarkdownTextSpec_registerComponentDescriptorsFromCodegen(
18
+ std::shared_ptr<const ComponentDescriptorProviderRegistry> registry) {
19
+ registry->add(concreteComponentDescriptorProvider<EnrichedMarkdownTextComponentDescriptor>());
20
+ }
21
+
22
+ } // namespace facebook::react
@@ -0,0 +1,24 @@
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: GenerateComponentDescriptorH.js
9
+ */
10
+
11
+ #pragma once
12
+
13
+ #include "ShadowNodes.h"
14
+ #include <react/renderer/core/ConcreteComponentDescriptor.h>
15
+ #include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
16
+
17
+ namespace facebook::react {
18
+
19
+ using EnrichedMarkdownTextComponentDescriptor = ConcreteComponentDescriptor<EnrichedMarkdownTextShadowNode>;
20
+
21
+ void EnrichedMarkdownTextSpec_registerComponentDescriptorsFromCodegen(
22
+ std::shared_ptr<const ComponentDescriptorProviderRegistry> registry);
23
+
24
+ } // namespace facebook::react
@@ -0,0 +1,33 @@
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: GenerateEventEmitterCpp.js
9
+ */
10
+
11
+ #include "EventEmitters.h"
12
+
13
+
14
+ namespace facebook::react {
15
+
16
+ void EnrichedMarkdownTextEventEmitter::onLinkPress(OnLinkPress event) const {
17
+ dispatchEvent("linkPress", [event=std::move(event)](jsi::Runtime &runtime) {
18
+ auto payload = jsi::Object(runtime);
19
+ payload.setProperty(runtime, "url", event.url);
20
+ return payload;
21
+ });
22
+ }
23
+
24
+
25
+ void EnrichedMarkdownTextEventEmitter::onLinkLongPress(OnLinkLongPress event) const {
26
+ dispatchEvent("linkLongPress", [event=std::move(event)](jsi::Runtime &runtime) {
27
+ auto payload = jsi::Object(runtime);
28
+ payload.setProperty(runtime, "url", event.url);
29
+ return payload;
30
+ });
31
+ }
32
+
33
+ } // namespace facebook::react
@@ -0,0 +1,31 @@
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: GenerateEventEmitterH.js
9
+ */
10
+ #pragma once
11
+
12
+ #include <react/renderer/components/view/ViewEventEmitter.h>
13
+
14
+
15
+ namespace facebook::react {
16
+ class EnrichedMarkdownTextEventEmitter : public ViewEventEmitter {
17
+ public:
18
+ using ViewEventEmitter::ViewEventEmitter;
19
+
20
+ struct OnLinkPress {
21
+ std::string url;
22
+ };
23
+
24
+ struct OnLinkLongPress {
25
+ std::string url;
26
+ };
27
+ void onLinkPress(OnLinkPress value) const;
28
+
29
+ void onLinkLongPress(OnLinkLongPress value) const;
30
+ };
31
+ } // namespace facebook::react
@@ -0,0 +1,82 @@
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: GeneratePropsCpp.js
9
+ */
10
+
11
+ #include "Props.h"
12
+ #include <react/renderer/core/PropsParserContext.h>
13
+ #include <react/renderer/core/propsConversions.h>
14
+
15
+ namespace facebook::react {
16
+
17
+ EnrichedMarkdownTextProps::EnrichedMarkdownTextProps(
18
+ const PropsParserContext &context,
19
+ const EnrichedMarkdownTextProps &sourceProps,
20
+ const RawProps &rawProps): ViewProps(context, sourceProps, rawProps),
21
+
22
+ markdown(convertRawProp(context, rawProps, "markdown", sourceProps.markdown, {})),
23
+ markdownStyle(convertRawProp(context, rawProps, "markdownStyle", sourceProps.markdownStyle, {})),
24
+ enableLinkPreview(convertRawProp(context, rawProps, "enableLinkPreview", sourceProps.enableLinkPreview, {true})),
25
+ selectable(convertRawProp(context, rawProps, "selectable", sourceProps.selectable, {false})),
26
+ md4cFlags(convertRawProp(context, rawProps, "md4cFlags", sourceProps.md4cFlags, {})),
27
+ allowFontScaling(convertRawProp(context, rawProps, "allowFontScaling", sourceProps.allowFontScaling, {true})),
28
+ maxFontSizeMultiplier(convertRawProp(context, rawProps, "maxFontSizeMultiplier", sourceProps.maxFontSizeMultiplier, {0.0})),
29
+ allowTrailingMargin(convertRawProp(context, rawProps, "allowTrailingMargin", sourceProps.allowTrailingMargin, {false})) {}
30
+
31
+ #ifdef RN_SERIALIZABLE_STATE
32
+ ComponentName EnrichedMarkdownTextProps::getDiffPropsImplementationTarget() const {
33
+ return "EnrichedMarkdownText";
34
+ }
35
+
36
+ folly::dynamic EnrichedMarkdownTextProps::getDiffProps(
37
+ const Props* prevProps) const {
38
+ static const auto defaultProps = EnrichedMarkdownTextProps();
39
+ const EnrichedMarkdownTextProps* oldProps = prevProps == nullptr
40
+ ? &defaultProps
41
+ : static_cast<const EnrichedMarkdownTextProps*>(prevProps);
42
+ if (this == oldProps) {
43
+ return folly::dynamic::object();
44
+ }
45
+ folly::dynamic result = HostPlatformViewProps::getDiffProps(prevProps);
46
+
47
+ if (markdown != oldProps->markdown) {
48
+ result["markdown"] = markdown;
49
+ }
50
+
51
+ if (markdownStyle != oldProps->markdownStyle) {
52
+ result["markdownStyle"] = toDynamic(markdownStyle);
53
+ }
54
+
55
+ if (enableLinkPreview != oldProps->enableLinkPreview) {
56
+ result["enableLinkPreview"] = enableLinkPreview;
57
+ }
58
+
59
+ if (selectable != oldProps->selectable) {
60
+ result["selectable"] = selectable;
61
+ }
62
+
63
+ if (md4cFlags != oldProps->md4cFlags) {
64
+ result["md4cFlags"] = toDynamic(md4cFlags);
65
+ }
66
+
67
+ if (allowFontScaling != oldProps->allowFontScaling) {
68
+ result["allowFontScaling"] = allowFontScaling;
69
+ }
70
+
71
+ if ((maxFontSizeMultiplier != oldProps->maxFontSizeMultiplier) && !(std::isnan(maxFontSizeMultiplier) && std::isnan(oldProps->maxFontSizeMultiplier))) {
72
+ result["maxFontSizeMultiplier"] = maxFontSizeMultiplier;
73
+ }
74
+
75
+ if (allowTrailingMargin != oldProps->allowTrailingMargin) {
76
+ result["allowTrailingMargin"] = allowTrailingMargin;
77
+ }
78
+ return result;
79
+ }
80
+ #endif
81
+
82
+ } // namespace facebook::react