@mathers101/react-native-render-rich-text 0.0.0-stage → 0.1.9

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 (358) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +140 -3
  3. package/ReactNativeRenderRichText.podspec +23 -0
  4. package/android/build.gradle +86 -0
  5. package/android/consumer-rules.pro +3 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/cpp/jni-adapter.cpp +191 -0
  8. package/android/src/main/java/com/renderrichtext/EnrichedTiptapText.kt +673 -0
  9. package/android/src/main/java/com/renderrichtext/EnrichedTiptapTextLayoutManager.kt +24 -0
  10. package/android/src/main/java/com/renderrichtext/EnrichedTiptapTextManager.kt +405 -0
  11. package/android/src/main/java/com/renderrichtext/EnrichedTiptapTextPackage.kt +13 -0
  12. package/android/src/main/java/com/renderrichtext/MeasurementStore.kt +644 -0
  13. package/android/src/main/java/com/renderrichtext/accessibility/AccessibilityLabels.kt +17 -0
  14. package/android/src/main/java/com/renderrichtext/accessibility/AccessibleTiptapTextView.kt +112 -0
  15. package/android/src/main/java/com/renderrichtext/accessibility/TiptapAccessibilityHelper.kt +576 -0
  16. package/android/src/main/java/com/renderrichtext/events/CodeBlockPressEvent.kt +24 -0
  17. package/android/src/main/java/com/renderrichtext/events/ContextMenuItemPressEvent.kt +28 -0
  18. package/android/src/main/java/com/renderrichtext/events/CopyPressEvent.kt +24 -0
  19. package/android/src/main/java/com/renderrichtext/events/FactoidPressEvent.kt +23 -0
  20. package/android/src/main/java/com/renderrichtext/events/ImagePressEvent.kt +25 -0
  21. package/android/src/main/java/com/renderrichtext/events/LatexErrorEvent.kt +29 -0
  22. package/android/src/main/java/com/renderrichtext/events/LinkLongPressEvent.kt +23 -0
  23. package/android/src/main/java/com/renderrichtext/events/LinkPressEvent.kt +23 -0
  24. package/android/src/main/java/com/renderrichtext/events/MentionLongPressEvent.kt +25 -0
  25. package/android/src/main/java/com/renderrichtext/events/MentionPressEvent.kt +25 -0
  26. package/android/src/main/java/com/renderrichtext/events/TaskListItemPressEvent.kt +26 -0
  27. package/android/src/main/java/com/renderrichtext/math/LatexErrorReporter.kt +9 -0
  28. package/android/src/main/java/com/renderrichtext/parser/Parser.kt +59 -0
  29. package/android/src/main/java/com/renderrichtext/parser/TextLinkMatching.kt +35 -0
  30. package/android/src/main/java/com/renderrichtext/parser/TiptapASTNode.kt +69 -0
  31. package/android/src/main/java/com/renderrichtext/renderer/BaselineShiftRenderer.kt +45 -0
  32. package/android/src/main/java/com/renderrichtext/renderer/BlankLineRenderer.kt +39 -0
  33. package/android/src/main/java/com/renderrichtext/renderer/BlockStyleContext.kt +181 -0
  34. package/android/src/main/java/com/renderrichtext/renderer/BlockquoteRenderer.kt +243 -0
  35. package/android/src/main/java/com/renderrichtext/renderer/BlockquoteTextRenderer.kt +56 -0
  36. package/android/src/main/java/com/renderrichtext/renderer/CodeBlockRenderer.kt +135 -0
  37. package/android/src/main/java/com/renderrichtext/renderer/CodeRenderer.kt +37 -0
  38. package/android/src/main/java/com/renderrichtext/renderer/EmphasisRenderer.kt +28 -0
  39. package/android/src/main/java/com/renderrichtext/renderer/FactoidRenderer.kt +97 -0
  40. package/android/src/main/java/com/renderrichtext/renderer/HeadingRenderer.kt +81 -0
  41. package/android/src/main/java/com/renderrichtext/renderer/HighlightRenderer.kt +26 -0
  42. package/android/src/main/java/com/renderrichtext/renderer/LineBreakRenderer.kt +17 -0
  43. package/android/src/main/java/com/renderrichtext/renderer/LinkRenderer.kt +90 -0
  44. package/android/src/main/java/com/renderrichtext/renderer/ListContextManager.kt +109 -0
  45. package/android/src/main/java/com/renderrichtext/renderer/ListItemRenderer.kt +211 -0
  46. package/android/src/main/java/com/renderrichtext/renderer/ListRenderer.kt +133 -0
  47. package/android/src/main/java/com/renderrichtext/renderer/MentionRenderer.kt +85 -0
  48. package/android/src/main/java/com/renderrichtext/renderer/NodeRenderer.kt +207 -0
  49. package/android/src/main/java/com/renderrichtext/renderer/ParagraphRenderer.kt +91 -0
  50. package/android/src/main/java/com/renderrichtext/renderer/Renderer.kt +148 -0
  51. package/android/src/main/java/com/renderrichtext/renderer/SoftBreakRenderer.kt +17 -0
  52. package/android/src/main/java/com/renderrichtext/renderer/SpanStyleCache.kt +143 -0
  53. package/android/src/main/java/com/renderrichtext/renderer/StrikethroughRenderer.kt +28 -0
  54. package/android/src/main/java/com/renderrichtext/renderer/StrongRenderer.kt +28 -0
  55. package/android/src/main/java/com/renderrichtext/renderer/TextRenderer.kt +31 -0
  56. package/android/src/main/java/com/renderrichtext/renderer/ThematicBreakRenderer.kt +46 -0
  57. package/android/src/main/java/com/renderrichtext/renderer/UnderlineRenderer.kt +28 -0
  58. package/android/src/main/java/com/renderrichtext/spans/BaseListSpan.kt +164 -0
  59. package/android/src/main/java/com/renderrichtext/spans/BaselineShiftSpan.kt +27 -0
  60. package/android/src/main/java/com/renderrichtext/spans/BlockquoteSpan.kt +302 -0
  61. package/android/src/main/java/com/renderrichtext/spans/CodeBackgroundSpan.kt +205 -0
  62. package/android/src/main/java/com/renderrichtext/spans/CodeBlockSpan.kt +216 -0
  63. package/android/src/main/java/com/renderrichtext/spans/CodeSpan.kt +32 -0
  64. package/android/src/main/java/com/renderrichtext/spans/EmphasisSpan.kt +42 -0
  65. package/android/src/main/java/com/renderrichtext/spans/FactoidBackgroundSpan.kt +265 -0
  66. package/android/src/main/java/com/renderrichtext/spans/FactoidPaddingSpan.kt +258 -0
  67. package/android/src/main/java/com/renderrichtext/spans/FactoidSpan.kt +32 -0
  68. package/android/src/main/java/com/renderrichtext/spans/FadeInSpan.kt +29 -0
  69. package/android/src/main/java/com/renderrichtext/spans/HeadingSpan.kt +38 -0
  70. package/android/src/main/java/com/renderrichtext/spans/HighlightSpan.kt +80 -0
  71. package/android/src/main/java/com/renderrichtext/spans/ImageSpan.kt +481 -0
  72. package/android/src/main/java/com/renderrichtext/spans/InlineBackgroundGeometry.kt +42 -0
  73. package/android/src/main/java/com/renderrichtext/spans/LineHeightSpan.kt +39 -0
  74. package/android/src/main/java/com/renderrichtext/spans/LinkPillIconCache.kt +154 -0
  75. package/android/src/main/java/com/renderrichtext/spans/LinkPillSpan.kt +381 -0
  76. package/android/src/main/java/com/renderrichtext/spans/LinkSpan.kt +68 -0
  77. package/android/src/main/java/com/renderrichtext/spans/ListItemSpacingSpan.kt +33 -0
  78. package/android/src/main/java/com/renderrichtext/spans/ListMarkerAnchorSpan.kt +38 -0
  79. package/android/src/main/java/com/renderrichtext/spans/MarginBottomSpan.kt +76 -0
  80. package/android/src/main/java/com/renderrichtext/spans/MentionChipSpan.kt +132 -0
  81. package/android/src/main/java/com/renderrichtext/spans/MentionSpan.kt +46 -0
  82. package/android/src/main/java/com/renderrichtext/spans/OrderedListSpan.kt +127 -0
  83. package/android/src/main/java/com/renderrichtext/spans/SpoilerSpan.kt +33 -0
  84. package/android/src/main/java/com/renderrichtext/spans/StrikethroughSpan.kt +12 -0
  85. package/android/src/main/java/com/renderrichtext/spans/StrongSpan.kt +39 -0
  86. package/android/src/main/java/com/renderrichtext/spans/TaskListSpan.kt +143 -0
  87. package/android/src/main/java/com/renderrichtext/spans/TextSpan.kt +26 -0
  88. package/android/src/main/java/com/renderrichtext/spans/ThematicBreakSpan.kt +69 -0
  89. package/android/src/main/java/com/renderrichtext/spans/UnorderedListSpan.kt +96 -0
  90. package/android/src/main/java/com/renderrichtext/spoiler/SpoilerStubs.kt +46 -0
  91. package/android/src/main/java/com/renderrichtext/styles/BaseBlockStyle.kt +11 -0
  92. package/android/src/main/java/com/renderrichtext/styles/BlockquoteStyle.kt +83 -0
  93. package/android/src/main/java/com/renderrichtext/styles/CodeBlockStyle.kt +80 -0
  94. package/android/src/main/java/com/renderrichtext/styles/CodeStyle.kt +26 -0
  95. package/android/src/main/java/com/renderrichtext/styles/EmphasisStyle.kt +21 -0
  96. package/android/src/main/java/com/renderrichtext/styles/FactoidStyle.kt +21 -0
  97. package/android/src/main/java/com/renderrichtext/styles/HeadingStyle.kt +33 -0
  98. package/android/src/main/java/com/renderrichtext/styles/HighlightStyle.kt +19 -0
  99. package/android/src/main/java/com/renderrichtext/styles/ImageStyle.kt +29 -0
  100. package/android/src/main/java/com/renderrichtext/styles/InlineImageStyle.kt +17 -0
  101. package/android/src/main/java/com/renderrichtext/styles/InlineMathStyle.kt +17 -0
  102. package/android/src/main/java/com/renderrichtext/styles/LinkPillContent.kt +36 -0
  103. package/android/src/main/java/com/renderrichtext/styles/LinkPillStyle.kt +44 -0
  104. package/android/src/main/java/com/renderrichtext/styles/LinkStyle.kt +23 -0
  105. package/android/src/main/java/com/renderrichtext/styles/LinkVariantEntry.kt +34 -0
  106. package/android/src/main/java/com/renderrichtext/styles/ListStyle.kt +65 -0
  107. package/android/src/main/java/com/renderrichtext/styles/MathStyle.kt +29 -0
  108. package/android/src/main/java/com/renderrichtext/styles/MentionStyle.kt +19 -0
  109. package/android/src/main/java/com/renderrichtext/styles/ParagraphStyle.kt +33 -0
  110. package/android/src/main/java/com/renderrichtext/styles/SpoilerStyle.kt +27 -0
  111. package/android/src/main/java/com/renderrichtext/styles/StrikethroughStyle.kt +17 -0
  112. package/android/src/main/java/com/renderrichtext/styles/StrongStyle.kt +21 -0
  113. package/android/src/main/java/com/renderrichtext/styles/StyleConfig.kt +411 -0
  114. package/android/src/main/java/com/renderrichtext/styles/StyleParser.kt +92 -0
  115. package/android/src/main/java/com/renderrichtext/styles/SubscriptStyle.kt +16 -0
  116. package/android/src/main/java/com/renderrichtext/styles/SuperscriptStyle.kt +16 -0
  117. package/android/src/main/java/com/renderrichtext/styles/TableStyle.kt +75 -0
  118. package/android/src/main/java/com/renderrichtext/styles/TaskListStyle.kt +29 -0
  119. package/android/src/main/java/com/renderrichtext/styles/TextAlignment.kt +32 -0
  120. package/android/src/main/java/com/renderrichtext/styles/ThematicBreakStyle.kt +23 -0
  121. package/android/src/main/java/com/renderrichtext/styles/UnderlineStyle.kt +17 -0
  122. package/android/src/main/java/com/renderrichtext/styles/VideoStyle.kt +31 -0
  123. package/android/src/main/java/com/renderrichtext/utils/common/BorderStyleUtils.kt +86 -0
  124. package/android/src/main/java/com/renderrichtext/utils/common/BreakStrategyUtils.kt +32 -0
  125. package/android/src/main/java/com/renderrichtext/utils/common/CodeBlockHighlighter.kt +36 -0
  126. package/android/src/main/java/com/renderrichtext/utils/common/CodeBlockNode.kt +42 -0
  127. package/android/src/main/java/com/renderrichtext/utils/common/EllipsizeUtils.kt +27 -0
  128. package/android/src/main/java/com/renderrichtext/utils/common/EnrichedTiptapAncestorUtils.kt +10 -0
  129. package/android/src/main/java/com/renderrichtext/utils/common/FeatureFlags.kt +9 -0
  130. package/android/src/main/java/com/renderrichtext/utils/common/LinkRecognitionProps.kt +31 -0
  131. package/android/src/main/java/com/renderrichtext/utils/common/LinkRegexConfig.kt +56 -0
  132. package/android/src/main/java/com/renderrichtext/utils/common/MotionPreferences.kt +18 -0
  133. package/android/src/main/java/com/renderrichtext/utils/common/ReadableMapExtensions.kt +28 -0
  134. package/android/src/main/java/com/renderrichtext/utils/common/TiptapViewManagerUtils.kt +242 -0
  135. package/android/src/main/java/com/renderrichtext/utils/common/layout/RTLUtils.kt +6 -0
  136. package/android/src/main/java/com/renderrichtext/utils/common/serialization/TiptapASTSerializer.kt +368 -0
  137. package/android/src/main/java/com/renderrichtext/utils/text/ImageCache.kt +88 -0
  138. package/android/src/main/java/com/renderrichtext/utils/text/ImageDownloader.kt +203 -0
  139. package/android/src/main/java/com/renderrichtext/utils/text/LocalImageLoader.kt +167 -0
  140. package/android/src/main/java/com/renderrichtext/utils/text/TailFadeInAnimator.kt +84 -0
  141. package/android/src/main/java/com/renderrichtext/utils/text/conversion/HTMLGenerator.kt +1105 -0
  142. package/android/src/main/java/com/renderrichtext/utils/text/conversion/TiptapExtractor.kt +423 -0
  143. package/android/src/main/java/com/renderrichtext/utils/text/extensions/ParagraphUtils.kt +9 -0
  144. package/android/src/main/java/com/renderrichtext/utils/text/extensions/SpannableExtensions.kt +9 -0
  145. package/android/src/main/java/com/renderrichtext/utils/text/extensions/TextPaintExtensions.kt +76 -0
  146. package/android/src/main/java/com/renderrichtext/utils/text/interaction/CheckboxTouchHelper.kt +61 -0
  147. package/android/src/main/java/com/renderrichtext/utils/text/interaction/TaskListTapUtils.kt +286 -0
  148. package/android/src/main/java/com/renderrichtext/utils/text/span/ApplyLineHeight.kt +39 -0
  149. package/android/src/main/java/com/renderrichtext/utils/text/span/BlockSpacing.kt +142 -0
  150. package/android/src/main/java/com/renderrichtext/utils/text/span/SpanFlags.kt +43 -0
  151. package/android/src/main/java/com/renderrichtext/utils/text/span/WidthAwareSpans.kt +30 -0
  152. package/android/src/main/java/com/renderrichtext/utils/text/view/CodeBlockPressHost.kt +15 -0
  153. package/android/src/main/java/com/renderrichtext/utils/text/view/ImagePressHost.kt +19 -0
  154. package/android/src/main/java/com/renderrichtext/utils/text/view/LinkEvents.kt +88 -0
  155. package/android/src/main/java/com/renderrichtext/utils/text/view/LinkLongPressMovementMethod.kt +449 -0
  156. package/android/src/main/java/com/renderrichtext/utils/text/view/SelectionActionMode.kt +235 -0
  157. package/android/src/main/java/com/renderrichtext/utils/text/view/TextSelectionColors.kt +48 -0
  158. package/android/src/main/java/com/renderrichtext/utils/text/view/TextViewSetup.kt +119 -0
  159. package/android/src/main/java/com/renderrichtext/views/ContextMenuPopup.kt +217 -0
  160. package/android/src/main/java/com/renderrichtext/views/CopyGlyph.kt +101 -0
  161. package/android/src/main/java/com/renderrichtext/views/WrapGlyph.kt +40 -0
  162. package/android/src/main/jni/CMakeLists.txt +52 -0
  163. package/android/src/main/jni/react/renderer/components/RichTextSpec/ComponentDescriptors.h +30 -0
  164. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextComponentDescriptor.h +29 -0
  165. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextMeasurementManager.cpp +45 -0
  166. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextMeasurementManager.h +21 -0
  167. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextShadowNode.cpp +38 -0
  168. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextShadowNode.h +53 -0
  169. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextState.cpp +9 -0
  170. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextState.h +24 -0
  171. package/android/src/main/jni/react/renderer/components/RichTextSpec/conversions.h +40 -0
  172. package/cpp/parser/TiptapASTNode.hpp +68 -0
  173. package/cpp/parser/TiptapParser.cpp +233 -0
  174. package/cpp/parser/TiptapParser.hpp +13 -0
  175. package/cpp/vendor/nlohmann/json.hpp +24765 -0
  176. package/ios/EnrichedTiptapText.h +27 -0
  177. package/ios/EnrichedTiptapText.mm +1222 -0
  178. package/ios/attachments/ENRMImageAttachment.h +51 -0
  179. package/ios/attachments/ENRMImageAttachment.m +398 -0
  180. package/ios/attachments/ENRMLinkPillAttachment.h +47 -0
  181. package/ios/attachments/ENRMLinkPillAttachment.m +324 -0
  182. package/ios/attachments/ENRMLinkPillIconCache.h +28 -0
  183. package/ios/attachments/ENRMLinkPillIconCache.m +181 -0
  184. package/ios/attachments/ENRMLinkPillText.h +27 -0
  185. package/ios/attachments/ENRMLinkPillText.m +118 -0
  186. package/ios/attachments/ENRMMathInlineAttachment.h +7 -0
  187. package/ios/attachments/ENRMMathInlineAttachment.m +4 -0
  188. package/ios/attachments/ThematicBreakAttachment.h +15 -0
  189. package/ios/attachments/ThematicBreakAttachment.m +33 -0
  190. package/ios/internals/ENRMViewFreeMeasurement.h +208 -0
  191. package/ios/internals/EnrichedTiptapTextComponentDescriptor.h +19 -0
  192. package/ios/internals/EnrichedTiptapTextShadowNode.h +43 -0
  193. package/ios/internals/EnrichedTiptapTextShadowNode.mm +69 -0
  194. package/ios/internals/EnrichedTiptapTextState.h +24 -0
  195. package/ios/internals/MeasurementCache.h +308 -0
  196. package/ios/internals/ShadowMeasurementUtils.h +145 -0
  197. package/ios/parser/ENRMTextLinkAttributes.h +7 -0
  198. package/ios/parser/ENRMTiptapParser.h +33 -0
  199. package/ios/parser/ENRMTiptapParser.mm +73 -0
  200. package/ios/parser/TiptapASTNode.h +57 -0
  201. package/ios/parser/TiptapASTNode.m +52 -0
  202. package/ios/parser/TiptapParserBridge.mm +179 -0
  203. package/ios/renderer/AttributedRenderer.h +23 -0
  204. package/ios/renderer/AttributedRenderer.m +229 -0
  205. package/ios/renderer/BaseRenderer.h +33 -0
  206. package/ios/renderer/BaseRenderer.m +46 -0
  207. package/ios/renderer/BaselineShiftTextAttributes.h +10 -0
  208. package/ios/renderer/BaselineShiftTextAttributes.m +26 -0
  209. package/ios/renderer/BlankLineRenderer.h +4 -0
  210. package/ios/renderer/BlankLineRenderer.m +51 -0
  211. package/ios/renderer/BlockquoteRenderer.h +6 -0
  212. package/ios/renderer/BlockquoteRenderer.m +258 -0
  213. package/ios/renderer/CodeBlockRenderer.h +9 -0
  214. package/ios/renderer/CodeBlockRenderer.m +99 -0
  215. package/ios/renderer/CodeRenderer.h +9 -0
  216. package/ios/renderer/CodeRenderer.m +69 -0
  217. package/ios/renderer/ENRMBlockquoteTextRenderer.h +25 -0
  218. package/ios/renderer/ENRMBlockquoteTextRenderer.m +48 -0
  219. package/ios/renderer/EmphasisRenderer.h +5 -0
  220. package/ios/renderer/EmphasisRenderer.m +100 -0
  221. package/ios/renderer/FactoidRenderer.h +9 -0
  222. package/ios/renderer/FactoidRenderer.m +130 -0
  223. package/ios/renderer/HeadingRenderer.h +6 -0
  224. package/ios/renderer/HeadingRenderer.m +103 -0
  225. package/ios/renderer/HighlightRenderer.h +7 -0
  226. package/ios/renderer/HighlightRenderer.m +33 -0
  227. package/ios/renderer/LinkRenderer.h +6 -0
  228. package/ios/renderer/LinkRenderer.m +158 -0
  229. package/ios/renderer/ListItemRenderer.h +24 -0
  230. package/ios/renderer/ListItemRenderer.m +283 -0
  231. package/ios/renderer/ListRenderer.h +13 -0
  232. package/ios/renderer/ListRenderer.m +126 -0
  233. package/ios/renderer/MentionRenderer.h +9 -0
  234. package/ios/renderer/MentionRenderer.m +96 -0
  235. package/ios/renderer/NodeRenderer.h +8 -0
  236. package/ios/renderer/ParagraphRenderer.h +6 -0
  237. package/ios/renderer/ParagraphRenderer.m +85 -0
  238. package/ios/renderer/RenderContext.h +145 -0
  239. package/ios/renderer/RenderContext.m +403 -0
  240. package/ios/renderer/RendererFactory.h +12 -0
  241. package/ios/renderer/RendererFactory.m +158 -0
  242. package/ios/renderer/StrikethroughRenderer.h +5 -0
  243. package/ios/renderer/StrikethroughRenderer.m +30 -0
  244. package/ios/renderer/StrongRenderer.h +5 -0
  245. package/ios/renderer/StrongRenderer.m +88 -0
  246. package/ios/renderer/TextRenderer.h +6 -0
  247. package/ios/renderer/TextRenderer.m +18 -0
  248. package/ios/renderer/ThematicBreakRenderer.h +4 -0
  249. package/ios/renderer/ThematicBreakRenderer.m +42 -0
  250. package/ios/renderer/UnderlineRenderer.h +4 -0
  251. package/ios/renderer/UnderlineRenderer.m +41 -0
  252. package/ios/styles/ENRMFontSlot.h +12 -0
  253. package/ios/styles/ENRMFontSlot.m +24 -0
  254. package/ios/styles/StyleConfig.h +488 -0
  255. package/ios/styles/StyleConfig.mm +2820 -0
  256. package/ios/utils/AccessibilityInfo.h +35 -0
  257. package/ios/utils/AccessibilityInfo.m +24 -0
  258. package/ios/utils/BlockquoteBorder.h +26 -0
  259. package/ios/utils/BlockquoteBorder.m +294 -0
  260. package/ios/utils/CodeBackground.h +19 -0
  261. package/ios/utils/CodeBackground.m +197 -0
  262. package/ios/utils/CodeBlockBackground.h +17 -0
  263. package/ios/utils/CodeBlockBackground.m +103 -0
  264. package/ios/utils/ContextMenuUtils.h +76 -0
  265. package/ios/utils/ContextMenuUtils.mm +75 -0
  266. package/ios/utils/ENRMAccessibilityLabels.h +40 -0
  267. package/ios/utils/ENRMAccessibilityLabels.m +5 -0
  268. package/ios/utils/ENRMAsyncRenderCoordinator.h +24 -0
  269. package/ios/utils/ENRMAsyncRenderCoordinator.m +37 -0
  270. package/ios/utils/ENRMAtomicSize.h +65 -0
  271. package/ios/utils/ENRMCodeBlockContent.h +37 -0
  272. package/ios/utils/ENRMCodeBlockContent.mm +89 -0
  273. package/ios/utils/ENRMFeatureFlags.h +25 -0
  274. package/ios/utils/ENRMImageDownloader.h +30 -0
  275. package/ios/utils/ENRMImageDownloader.m +168 -0
  276. package/ios/utils/ENRMLatexErrorCoordinator.h +27 -0
  277. package/ios/utils/ENRMLatexErrorCoordinator.mm +75 -0
  278. package/ios/utils/ENRMLatexErrorReporting.h +13 -0
  279. package/ios/utils/ENRMLinkContextMenus.h +93 -0
  280. package/ios/utils/ENRMLinkContextMenus.m +178 -0
  281. package/ios/utils/ENRMLinkRegexConfig.h +30 -0
  282. package/ios/utils/ENRMLinkRegexConfig.mm +104 -0
  283. package/ios/utils/ENRMLinkRegexProps.h +23 -0
  284. package/ios/utils/ENRMLocalImageLoader.h +35 -0
  285. package/ios/utils/ENRMLocalImageLoader.m +111 -0
  286. package/ios/utils/ENRMMenuAction.h +27 -0
  287. package/ios/utils/ENRMMenuAction.m +33 -0
  288. package/ios/utils/ENRMSpoilerOverlayManager.h +15 -0
  289. package/ios/utils/ENRMSpoilerOverlayManager.m +19 -0
  290. package/ios/utils/ENRMSpoilerTapUtils.h +6 -0
  291. package/ios/utils/ENRMSpoilerTapUtils.m +11 -0
  292. package/ios/utils/ENRMTailFadeInAnimator.h +16 -0
  293. package/ios/utils/ENRMTailFadeInAnimator.m +161 -0
  294. package/ios/utils/ENRMTextHitTest.h +23 -0
  295. package/ios/utils/ENRMTextHitTest.m +20 -0
  296. package/ios/utils/ENRMTextInteractionUtils.h +20 -0
  297. package/ios/utils/ENRMTextInteractionUtils.m +15 -0
  298. package/ios/utils/ENRMTextRenderer.h +38 -0
  299. package/ios/utils/ENRMTextRenderer.m +54 -0
  300. package/ios/utils/ENRMTextViewSetup.h +132 -0
  301. package/ios/utils/ENRMUIKit.h +429 -0
  302. package/ios/utils/EditMenuUtils.h +105 -0
  303. package/ios/utils/EditMenuUtils.m +143 -0
  304. package/ios/utils/FactoidBackground.h +20 -0
  305. package/ios/utils/FactoidBackground.m +161 -0
  306. package/ios/utils/FontScaleObserver.h +10 -0
  307. package/ios/utils/FontScaleObserver.m +55 -0
  308. package/ios/utils/FontUtils.h +31 -0
  309. package/ios/utils/FontUtils.m +63 -0
  310. package/ios/utils/HTMLGenerator.h +25 -0
  311. package/ios/utils/HTMLGenerator.m +1041 -0
  312. package/ios/utils/HeightUpdateUtils.h +25 -0
  313. package/ios/utils/ImageRequestHeaderUtils.h +35 -0
  314. package/ios/utils/LastElementUtils.h +97 -0
  315. package/ios/utils/LinkContextMenuUtils.h +55 -0
  316. package/ios/utils/LinkPillContentUtils.h +46 -0
  317. package/ios/utils/LinkTapUtils.h +56 -0
  318. package/ios/utils/LinkTapUtils.m +139 -0
  319. package/ios/utils/ListMarkerDrawer.h +15 -0
  320. package/ios/utils/ListMarkerDrawer.m +239 -0
  321. package/ios/utils/MentionBackground.h +26 -0
  322. package/ios/utils/MentionBackground.m +86 -0
  323. package/ios/utils/ParagraphStyleUtils.h +87 -0
  324. package/ios/utils/ParagraphStyleUtils.m +484 -0
  325. package/ios/utils/PasteboardUtils.h +48 -0
  326. package/ios/utils/PasteboardUtils.m +166 -0
  327. package/ios/utils/RTFExportUtils.h +24 -0
  328. package/ios/utils/RTFExportUtils.m +299 -0
  329. package/ios/utils/RuntimeKeys.h +44 -0
  330. package/ios/utils/RuntimeKeys.m +13 -0
  331. package/ios/utils/SelectionColorUtils.h +14 -0
  332. package/ios/utils/StylePropsUtils.h +1340 -0
  333. package/ios/utils/TaskListTapUtils.h +6 -0
  334. package/ios/utils/TaskListTapUtils.m +14 -0
  335. package/ios/utils/TextViewLayoutManager.h +14 -0
  336. package/ios/utils/TextViewLayoutManager.mm +198 -0
  337. package/ios/utils/TiptapAccessibilityElementBuilder.h +43 -0
  338. package/ios/utils/TiptapAccessibilityElementBuilder.m +432 -0
  339. package/ios/utils/TiptapExtractor.h +17 -0
  340. package/ios/utils/TiptapExtractor.m +367 -0
  341. package/ios/views/ENRMTiptapTextView.h +25 -0
  342. package/ios/views/ENRMTiptapTextView.m +247 -0
  343. package/package.json +70 -6
  344. package/react-native.config.js +10 -0
  345. package/src/EnrichedTiptapTextNativeComponent.ts +739 -0
  346. package/src/RichText.tsx +164 -0
  347. package/src/admonitionDefaults.ts +58 -0
  348. package/src/darkModeTextStyle.ts +99 -0
  349. package/src/headingDefaults.ts +21 -0
  350. package/src/index.tsx +4 -0
  351. package/src/linkVariantUtils.ts +120 -0
  352. package/src/normalizeTiptapStyle.ts +397 -0
  353. package/src/rn-globals.d.ts +1 -0
  354. package/src/styleUtils.ts +107 -0
  355. package/src/types/TiptapStyle.ts +532 -0
  356. package/src/types/TiptapStyleInternal.ts +299 -0
  357. package/src/types/linkPill.ts +9 -0
  358. package/src/utils/isDev.ts +4 -0
@@ -0,0 +1,51 @@
1
+ #pragma once
2
+ #import "ENRMUIKit.h"
3
+
4
+ @class StyleConfig;
5
+
6
+ NS_ASSUME_NONNULL_BEGIN
7
+
8
+ /**
9
+ * Adopted by component views that host tiptap text. Notified when a block
10
+ * image resolves its box height after loading (maxHeight/aspectRatio sizing),
11
+ * so the view can drop stale cached measurements and request a height update.
12
+ */
13
+ @protocol ENRMImageLayoutObserver
14
+ - (void)imageAttachmentDidResolveLayout;
15
+ @end
16
+
17
+ @interface RCTUIView (ENRMImageLayoutObserver)
18
+ /**
19
+ * Nearest ancestor (self included) adopting ENRMImageLayoutObserver, walking up
20
+ * the superview chain. Returns nil when none is found.
21
+ */
22
+ - (nullable id<ENRMImageLayoutObserver>)enrm_imageLayoutObserver;
23
+ @end
24
+
25
+ /**
26
+ * Custom NSTextAttachment for rendering tiptap images.
27
+ * Images are loaded asynchronously and scaled dynamically based on text container width.
28
+ * Supports inline and block images with custom height and border radius from config.
29
+ */
30
+ @interface ENRMImageAttachment : NSTextAttachment
31
+
32
+ @property (nonatomic, readonly) NSString *imageURL;
33
+ @property (nonatomic, readonly) BOOL isInline;
34
+
35
+ /**
36
+ * Invoked on the main thread whenever the image finishes loading/processing.
37
+ * Used by self-drawing hosts (e.g. a table grid) that rasterize the attributed
38
+ * string via -drawWithRect: and therefore never get a live text view for the
39
+ * attachment's normal -refreshDisplay invalidation to reach. Such hosts set this
40
+ * to trigger their own redraw (e.g. -setNeedsDisplay).
41
+ */
42
+ @property (nonatomic, copy, nullable) void (^onImageLoaded)(void);
43
+
44
+ + (instancetype)attachmentForURL:(NSString *)imageURL config:(StyleConfig *)config isInline:(BOOL)isInline;
45
+
46
+ + (NSCache<NSString *, RCTUIImage *> *)originalImageCache;
47
+ + (NSCache<NSString *, RCTUIImage *> *)processedImageCache;
48
+
49
+ @end
50
+
51
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,398 @@
1
+ #import "ENRMImageAttachment.h"
2
+ #import "ENRMImageDownloader.h"
3
+ #import "ENRMUIKit.h"
4
+ #import "RuntimeKeys.h"
5
+ #import "StyleConfig.h"
6
+ #import <objc/runtime.h>
7
+
8
+ #define CACHE_KEY_PROCESSED(url, w, h, r, m) [NSString stringWithFormat:@"%@_w%.1f_h%.1f_r%.1f_m%@", url, w, h, r, m]
9
+
10
+ static NSCache<NSString *, RCTUIImage *> *_originalImageCache;
11
+ static NSCache<NSString *, RCTUIImage *> *_processedImageCache;
12
+
13
+ @implementation RCTUIView (ENRMImageLayoutObserver)
14
+
15
+ - (id<ENRMImageLayoutObserver>)enrm_imageLayoutObserver
16
+ {
17
+ RCTUIView *view = self;
18
+ while (view && ![view conformsToProtocol:@protocol(ENRMImageLayoutObserver)]) {
19
+ view = view.superview;
20
+ }
21
+ return (id<ENRMImageLayoutObserver>)view;
22
+ }
23
+
24
+ @end
25
+
26
+ @interface ENRMImageAttachment ()
27
+
28
+ @property (nonatomic, copy) NSString *imageURL;
29
+ @property (nonatomic, copy, nullable) NSDictionary<NSString *, NSString *> *requestHeaders;
30
+ @property (nonatomic, copy) NSString *cacheKey;
31
+ @property (nonatomic, assign) BOOL isInline;
32
+ @property (nonatomic, assign) CGFloat cachedHeight;
33
+ @property (nonatomic, assign) CGFloat cachedMaxHeight;
34
+ @property (nonatomic, assign) CGFloat cachedAspectRatio;
35
+ @property (nonatomic, copy) NSString *cachedResizeMode;
36
+ @property (nonatomic, assign) CGFloat cachedBorderRadius;
37
+ @property (nonatomic, weak) NSTextContainer *textContainer;
38
+ @property (nonatomic, weak) ENRMPlatformTextView *textView;
39
+ @property (nonatomic, strong) RCTUIImage *originalImage;
40
+ @property (nonatomic, strong) RCTUIImage *loadedImage;
41
+ @property (nonatomic, strong) RCTUIImage *placeholderImage;
42
+ @property (nonatomic, copy) NSString *lastProcessedKey;
43
+
44
+ @end
45
+
46
+ @implementation ENRMImageAttachment
47
+
48
+ + (NSCache<NSString *, RCTUIImage *> *)originalImageCache
49
+ {
50
+ static dispatch_once_t onceToken;
51
+ dispatch_once(&onceToken, ^{
52
+ _originalImageCache = [[NSCache alloc] init];
53
+ _originalImageCache.countLimit = 50;
54
+ _originalImageCache.totalCostLimit = 1024 * 1024 * 20; // 20 MB
55
+ });
56
+ return _originalImageCache;
57
+ }
58
+
59
+ + (NSCache<NSString *, RCTUIImage *> *)processedImageCache
60
+ {
61
+ static dispatch_once_t onceToken;
62
+ dispatch_once(&onceToken, ^{
63
+ _processedImageCache = [[NSCache alloc] init];
64
+ _processedImageCache.countLimit = 100;
65
+ _processedImageCache.totalCostLimit = 1024 * 1024 * 30; // 30 MB
66
+ });
67
+ return _processedImageCache;
68
+ }
69
+
70
+ + (instancetype)attachmentForURL:(NSString *)imageURL config:(StyleConfig *)config isInline:(BOOL)isInline
71
+ {
72
+ // Always a fresh instance, never shared across positions: the table renderer can draw
73
+ // the same image URL at a different width than a copy outside the table, and a shared
74
+ // NSTextAttachment would thrash its single last-processed width into a redraw loop. The
75
+ // image caches keep fresh instances cheap (no re-fetch or re-scale).
76
+ return [[self alloc] initWithImageURL:imageURL config:config isInline:isInline];
77
+ }
78
+
79
+ - (instancetype)initWithImageURL:(NSString *)imageURL config:(StyleConfig *)config isInline:(BOOL)isInline
80
+ {
81
+ self = [super init];
82
+ if (self) {
83
+ _imageURL = imageURL;
84
+ _requestHeaders = [[config imageRequestHeaders] copy];
85
+ _cacheKey = ENRMImageCacheKey(imageURL, _requestHeaders);
86
+ _isInline = isInline;
87
+
88
+ _cachedHeight = isInline ? [config inlineImageSize] : [config imageHeight];
89
+ _cachedMaxHeight = [config imageMaxHeight];
90
+ _cachedAspectRatio = [config imageAspectRatio];
91
+ _cachedResizeMode = [config imageResizeMode];
92
+ _cachedBorderRadius = [config imageBorderRadius];
93
+
94
+ [self setupPlaceholder];
95
+ [self startDownloadingImage];
96
+ }
97
+ return self;
98
+ }
99
+
100
+ - (CGFloat)resolvedBoxHeightForWidth:(CGFloat)width
101
+ {
102
+ if (self.cachedAspectRatio > 0 && width > 0) {
103
+ return width / self.cachedAspectRatio;
104
+ }
105
+
106
+ if (self.cachedMaxHeight > 0) {
107
+ RCTUIImage *source = self.originalImage;
108
+ if (source && width > 0 && source.size.width > 0 && source.size.height > 0) {
109
+ CGFloat fitted = width * source.size.height / source.size.width;
110
+ return MIN(self.cachedMaxHeight, fitted);
111
+ }
112
+ // Intrinsic size not known yet — fall back to the full max height; the box
113
+ // shrinks once the image loads and layout is invalidated.
114
+ return self.cachedMaxHeight;
115
+ }
116
+
117
+ return self.cachedHeight;
118
+ }
119
+
120
+ // True when resizeMode is unset ('') - legacy always implies a fixed height box.
121
+
122
+ - (BOOL)isLegacyBlockSizing
123
+ {
124
+ return !self.isInline && self.cachedResizeMode.length == 0;
125
+ }
126
+
127
+ - (CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer
128
+ proposedLineFragment:(CGRect)lineFragment
129
+ glyphPosition:(CGPoint)position
130
+ characterIndex:(NSUInteger)characterIndex
131
+ {
132
+ CGFloat height = self.cachedHeight;
133
+ CGFloat width = self.isInline ? height : (lineFragment.size.width > 0 ? lineFragment.size.width : height);
134
+
135
+ if (!self.isInline) {
136
+ height = [self resolvedBoxHeightForWidth:width];
137
+ return CGRectMake(0, 0, width, height);
138
+ }
139
+
140
+ UIFont *appliedFont = nil;
141
+ NSLayoutManager *layoutManager = textContainer.layoutManager;
142
+ NSTextStorage *textStorage = layoutManager.textStorage;
143
+
144
+ if (textStorage && characterIndex < textStorage.length) {
145
+ appliedFont = [textStorage attribute:NSFontAttributeName atIndex:characterIndex effectiveRange:NULL];
146
+ }
147
+
148
+ CGFloat verticalOffset;
149
+ if (appliedFont) {
150
+ verticalOffset = (appliedFont.capHeight - height) / 2.0;
151
+ } else {
152
+ verticalOffset = (lineFragment.size.height - height) / 2.0;
153
+ }
154
+
155
+ return CGRectMake(0, verticalOffset, width, height);
156
+ }
157
+
158
+ - (RCTUIImage *)imageForBounds:(CGRect)imageBounds
159
+ textContainer:(NSTextContainer *)textContainer
160
+ characterIndex:(NSUInteger)characterIndex
161
+ {
162
+ self.textContainer = textContainer;
163
+
164
+ if (self.originalImage && imageBounds.size.width > 0) {
165
+ self.bounds = imageBounds;
166
+ [self processAndApplyImage:self.originalImage withTargetWidth:imageBounds.size.width];
167
+ }
168
+
169
+ return self.loadedImage ?: self.placeholderImage;
170
+ }
171
+
172
+ - (void)handleLoadedImage:(RCTUIImage *)image
173
+ {
174
+ if (!image)
175
+ return;
176
+
177
+ // The downloader completes synchronously on cache hits, which can happen on the render queue
178
+ if (!NSThread.isMainThread) {
179
+ dispatch_async(dispatch_get_main_queue(), ^{ [self handleLoadedImage:image]; });
180
+ return;
181
+ }
182
+
183
+ self.originalImage = image;
184
+ // UIKit reads the plain image property for save/drag/copy — it must hold the original
185
+ self.image = image;
186
+ CGFloat targetWidth = self.isInline ? self.cachedHeight : self.bounds.size.width;
187
+
188
+ // Defer processing if we don't have valid bounds yet (common for non-inline block images)
189
+ if (!self.isInline && targetWidth <= 0) {
190
+ return;
191
+ }
192
+
193
+ [self processAndApplyImage:image withTargetWidth:targetWidth];
194
+ }
195
+
196
+ - (void)processAndApplyImage:(RCTUIImage *)image withTargetWidth:(CGFloat)targetWidth
197
+ {
198
+ if (targetWidth <= 0)
199
+ return;
200
+
201
+ CGFloat boxHeight = self.isInline ? self.cachedHeight : [self resolvedBoxHeightForWidth:targetWidth];
202
+
203
+ NSString *processedKey =
204
+ CACHE_KEY_PROCESSED(self.cacheKey, targetWidth, boxHeight, self.cachedBorderRadius, self.cachedResizeMode);
205
+
206
+ if ([processedKey isEqualToString:self.lastProcessedKey])
207
+ return;
208
+ self.lastProcessedKey = processedKey;
209
+
210
+ RCTUIImage *cachedProcessed = [[ENRMImageAttachment processedImageCache] objectForKey:processedKey];
211
+
212
+ if (cachedProcessed) {
213
+ self.loadedImage = cachedProcessed;
214
+ [self refreshDisplay];
215
+ return;
216
+ }
217
+
218
+ __weak typeof(self) weakSelf = self;
219
+ dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
220
+ __strong typeof(weakSelf) strongSelf = weakSelf;
221
+ if (!strongSelf)
222
+ return;
223
+
224
+ RCTUIImage *processedImage = [strongSelf createScaledImage:image
225
+ toWidth:targetWidth
226
+ height:boxHeight
227
+ borderRadius:strongSelf.cachedBorderRadius];
228
+
229
+ if (processedImage) {
230
+ [[ENRMImageAttachment processedImageCache] setObject:processedImage
231
+ forKey:processedKey
232
+ cost:ENRMImageByteCost(processedImage)];
233
+ }
234
+
235
+ dispatch_async(dispatch_get_main_queue(), ^{
236
+ strongSelf.loadedImage = processedImage;
237
+ if (strongSelf.isInline) {
238
+ strongSelf.bounds = CGRectMake(0, 0, strongSelf.cachedHeight, strongSelf.cachedHeight);
239
+ }
240
+ [strongSelf refreshDisplay];
241
+ });
242
+ });
243
+ }
244
+
245
+ - (RCTUIImage *)createScaledImage:(RCTUIImage *)image
246
+ toWidth:(CGFloat)targetWidth
247
+ height:(CGFloat)targetHeight
248
+ borderRadius:(CGFloat)radius
249
+ {
250
+ CGFloat sourceWidth = image.size.width;
251
+ CGFloat sourceHeight = image.size.height;
252
+ if (sourceWidth <= 0 || sourceHeight <= 0)
253
+ return nil;
254
+
255
+ CGSize source = CGSizeMake(sourceWidth, sourceHeight);
256
+ CGSize box = CGSizeMake(targetWidth, targetHeight);
257
+ BOOL legacy = [self isLegacyBlockSizing];
258
+
259
+ CGRect drawingRect;
260
+ if (self.isInline || legacy) {
261
+ CGFloat drawingWidth, drawingHeight;
262
+ if (!self.isInline) {
263
+ CGFloat aspectRatioScale = targetWidth / sourceWidth;
264
+ drawingWidth = targetWidth;
265
+ drawingHeight = sourceHeight * aspectRatioScale;
266
+ } else {
267
+ drawingWidth = targetWidth;
268
+ drawingHeight = targetHeight;
269
+ }
270
+ drawingRect = CGRectMake((targetWidth - drawingWidth) / 2.0, (targetHeight - drawingHeight) / 2.0, drawingWidth,
271
+ drawingHeight);
272
+ } else {
273
+ drawingRect = [self drawingRectForResizeMode:self.cachedResizeMode source:source box:box];
274
+ }
275
+
276
+ RCTUIGraphicsImageRenderer *renderer = ImageRendererForSize(box);
277
+
278
+ return [renderer imageWithActions:^(RCTUIGraphicsImageRendererContext *context) {
279
+ if (radius > 0) {
280
+ CGRect clipRect = CGRectIntersection(CGRectMake(0, 0, targetWidth, targetHeight), drawingRect);
281
+ UIBezierPath *path = UIBezierPathWithRoundedRect(clipRect, radius);
282
+ [path addClip];
283
+ }
284
+ [image drawInRect:drawingRect];
285
+ }];
286
+ }
287
+
288
+ - (CGRect)drawingRectForResizeMode:(NSString *)mode source:(CGSize)source box:(CGSize)box
289
+ {
290
+ if ([mode isEqualToString:@"stretch"]) {
291
+ return CGRectMake(0, 0, box.width, box.height);
292
+ }
293
+
294
+ CGFloat widthScale = box.width / source.width;
295
+ CGFloat heightScale = box.height / source.height;
296
+
297
+ CGFloat scale;
298
+ if ([mode isEqualToString:@"contain"]) {
299
+ scale = MIN(widthScale, heightScale);
300
+ } else if ([mode isEqualToString:@"center"]) {
301
+ scale = MIN(1.0, MIN(widthScale, heightScale));
302
+ } else if ([mode isEqualToString:@"none"]) {
303
+ scale = 1.0;
304
+ } else { // cover (default)
305
+ scale = MAX(widthScale, heightScale);
306
+ }
307
+
308
+ CGFloat drawingWidth = source.width * scale;
309
+ CGFloat drawingHeight = source.height * scale;
310
+ return CGRectMake((box.width - drawingWidth) / 2.0, (box.height - drawingHeight) / 2.0, drawingWidth, drawingHeight);
311
+ }
312
+
313
+ - (void)startDownloadingImage
314
+ {
315
+ if (self.imageURL.length == 0)
316
+ return;
317
+
318
+ __weak typeof(self) weakSelf = self;
319
+ [[ENRMImageDownloader shared] downloadURL:self.imageURL
320
+ headers:self.requestHeaders
321
+ completion:^(RCTUIImage *image) { [weakSelf handleLoadedImage:image]; }];
322
+ }
323
+
324
+ - (void)refreshDisplay
325
+ {
326
+ // Notify self-drawing hosts (e.g. a table grid) that rasterize us via
327
+ // -drawWithRect: and have no live text view for the invalidation below to reach.
328
+ if (self.onImageLoaded) {
329
+ self.onImageLoaded();
330
+ }
331
+
332
+ UITextView *textView = [self fetchAssociatedTextView];
333
+ if (!textView)
334
+ return;
335
+
336
+ NSRange range = [self findAttachmentRangeInText:textView.textStorage];
337
+ if (range.location != NSNotFound) {
338
+ [textView.layoutManager invalidateDisplayForCharacterRange:range];
339
+ if (!self.isInline) {
340
+ [textView.layoutManager invalidateLayoutForCharacterRange:range actualCharacterRange:NULL];
341
+ [self notifyImageLayoutObserver:textView];
342
+ }
343
+ }
344
+ }
345
+
346
+ // With maxHeight/aspectRatio sizing the box height can settle after the image
347
+ // loads, while the component was measured (and its size cached) with the
348
+ // pre-load fallback. Notify the hosting component so it can re-measure.
349
+ // Dispatched async: refreshDisplay can run mid-layout (imageForBounds) and
350
+ // re-measuring would re-enter the layout manager.
351
+ - (void)notifyImageLayoutObserver:(UITextView *)textView
352
+ {
353
+ // Only maxHeight/aspectRatio boxes can change height after load; a fixed
354
+ // height box (legacy or explicit resizeMode) never needs a re-measure.
355
+ if (self.cachedMaxHeight <= 0 && self.cachedAspectRatio <= 0)
356
+ return;
357
+
358
+ id<ENRMImageLayoutObserver> observer = [textView enrm_imageLayoutObserver];
359
+ if (!observer)
360
+ return;
361
+
362
+ dispatch_async(dispatch_get_main_queue(), ^{ [observer imageAttachmentDidResolveLayout]; });
363
+ }
364
+
365
+ - (ENRMPlatformTextView *)fetchAssociatedTextView
366
+ {
367
+ if (self.textView)
368
+ return self.textView;
369
+ if (!self.textContainer)
370
+ return nil;
371
+ self.textView = objc_getAssociatedObject(self.textContainer, kTextViewKey);
372
+ return self.textView;
373
+ }
374
+
375
+ - (void)setupPlaceholder
376
+ {
377
+ CGFloat size = self.cachedHeight;
378
+ self.bounds = CGRectMake(0, 0, size, size);
379
+ RCTUIGraphicsImageRenderer *renderer = [[RCTUIGraphicsImageRenderer alloc] initWithSize:CGSizeMake(1, 1)];
380
+ self.placeholderImage = [renderer imageWithActions:^(RCTUIGraphicsImageRendererContext *ctx){}];
381
+ }
382
+
383
+ - (NSRange)findAttachmentRangeInText:(NSAttributedString *)attributedString
384
+ {
385
+ __block NSRange foundRange = NSMakeRange(NSNotFound, 0);
386
+ [attributedString enumerateAttribute:NSAttachmentAttributeName
387
+ inRange:NSMakeRange(0, attributedString.length)
388
+ options:0
389
+ usingBlock:^(id value, NSRange range, BOOL *stop) {
390
+ if (value == self) {
391
+ foundRange = range;
392
+ *stop = YES;
393
+ }
394
+ }];
395
+ return foundRange;
396
+ }
397
+
398
+ @end
@@ -0,0 +1,47 @@
1
+ #pragma once
2
+ #import "ENRMUIKit.h"
3
+
4
+ #if !TARGET_OS_OSX
5
+ @class LinkVariantConfig;
6
+
7
+ NS_ASSUME_NONNULL_BEGIN
8
+
9
+ /**
10
+ * A link presented as a pill. Like image and inline-math attachments it is a
11
+ * single U+FFFC in text storage, laid out and drawn by TextKit natively.
12
+ * The link's own rendered text is kept here; ENRMLinkPillText.h puts it back
13
+ * wherever text leaves the view (copy, export, accessibility).
14
+ */
15
+ @interface ENRMLinkPillAttachment : NSTextAttachment
16
+ @property (nonatomic, readonly) CGFloat boxHeight;
17
+ /// The minimum line height the pill asks of the block that holds it (`pill.lineHeight`); 0 for none.
18
+ @property (nonatomic, assign) CGFloat lineHeight;
19
+ /// The text the pill shows.
20
+ @property (nonatomic, readonly) NSString *label;
21
+ /// Visible label, followed by the original link text when they differ.
22
+ @property (nonatomic, readonly) NSString *linkAccessibilityLabel;
23
+ @property (nonatomic, readonly) NSAttributedString *originalText;
24
+ /// The radius the pill's corners are drawn with.
25
+ @property (nonatomic, readonly) CGFloat cornerRadius;
26
+ /// Draws nothing while set. The text view sets it while the pill is lifted for its menu,
27
+ /// so that the lifted copy is the only one on screen.
28
+ @property (nonatomic, assign) BOOL lifted;
29
+ /// Called on the main thread when an asynchronously loaded icon settles. For hosts that draw the
30
+ /// string themselves (the table grid) and have no text view for the attachment to invalidate.
31
+ @property (nonatomic, copy, nullable) void (^onIconLoaded)(void);
32
+
33
+ /// `variant.pill` must be non-nil. `label`, `iconUri` and `iconTintColor` are already resolved (per-link content,
34
+ /// then variant default).
35
+ - (instancetype)initWithOriginalText:(NSAttributedString *)originalText
36
+ variant:(LinkVariantConfig *)variant
37
+ label:(nullable NSString *)label
38
+ iconUri:(nullable NSString *)iconUri
39
+ iconTintColor:(nullable UIColor *)iconTintColor
40
+ font:(nullable UIFont *)font
41
+ requestHeaders:(nullable NSDictionary<NSString *, NSString *> *)requestHeaders;
42
+
43
+ - (void)adoptFont:(nullable UIFont *)font;
44
+ @end
45
+
46
+ NS_ASSUME_NONNULL_END
47
+ #endif