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

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,308 @@
1
+ #pragma once
2
+
3
+ #include <CoreGraphics/CGBase.h>
4
+ #include <React/RCTUtils.h>
5
+ #include <list>
6
+ #include <mutex>
7
+ #include <react/renderer/graphics/Float.h>
8
+ #include <string>
9
+ #include <tuple>
10
+ #include <unordered_map>
11
+
12
+ namespace facebook::react {
13
+
14
+ struct HashUtils {
15
+
16
+ static inline size_t combine(size_t h, size_t v)
17
+ {
18
+ return h ^ (v + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2));
19
+ }
20
+
21
+ template <typename T> static inline void hash_one(size_t &seed, const T &v)
22
+ {
23
+ seed = combine(seed, std::hash<T>{}(v));
24
+ }
25
+ };
26
+
27
+ enum class TiptapFlavor : uint8_t {
28
+ CommonMark = 0,
29
+ GitHub = 1,
30
+ };
31
+
32
+ struct MeasurementCacheKey {
33
+ std::string tiptap;
34
+ CGFloat maxWidth;
35
+ bool allowTrailingMargin;
36
+ bool allowFontScaling;
37
+ double maxFontSizeMultiplier;
38
+ bool md4cFlagsUnderline;
39
+ bool md4cFlagsSuperscript;
40
+ bool md4cFlagsSubscript;
41
+ bool md4cFlagsHighlight;
42
+ bool md4cFlagsLatexMath;
43
+ bool md4cFlagsHardSoftBreaks;
44
+ bool md4cFlagsPreserveBlankLines;
45
+ bool md4cFlagsAdmonitions;
46
+ size_t styleFingerprint;
47
+ size_t linkPillContentFingerprint;
48
+ // Code blocks the user wrapped (view state, not props); 0 when none.
49
+ size_t wrappedCodeBlocksFingerprint;
50
+ CGFloat fontScale;
51
+ TiptapFlavor flavor;
52
+ std::string lineBreakStrategyIOS;
53
+ std::string writingDirection;
54
+ int numberOfLines;
55
+ std::string ellipsizeMode;
56
+ std::string linkRegexKey;
57
+ std::string inlineCodeLinkRegexKey;
58
+
59
+ bool operator==(const MeasurementCacheKey &other) const
60
+ {
61
+ return std::tie(tiptap, maxWidth, allowTrailingMargin, allowFontScaling, maxFontSizeMultiplier,
62
+ md4cFlagsUnderline, md4cFlagsSuperscript, md4cFlagsSubscript, md4cFlagsHighlight,
63
+ md4cFlagsLatexMath, md4cFlagsHardSoftBreaks, md4cFlagsPreserveBlankLines, md4cFlagsAdmonitions,
64
+ styleFingerprint, linkPillContentFingerprint, wrappedCodeBlocksFingerprint, fontScale, flavor,
65
+ lineBreakStrategyIOS, writingDirection, numberOfLines, ellipsizeMode, linkRegexKey,
66
+ inlineCodeLinkRegexKey) ==
67
+ std::tie(other.tiptap, other.maxWidth, other.allowTrailingMargin, other.allowFontScaling,
68
+ other.maxFontSizeMultiplier, other.md4cFlagsUnderline, other.md4cFlagsSuperscript,
69
+ other.md4cFlagsSubscript, other.md4cFlagsHighlight, other.md4cFlagsLatexMath,
70
+ other.md4cFlagsHardSoftBreaks, other.md4cFlagsPreserveBlankLines, other.md4cFlagsAdmonitions,
71
+ other.styleFingerprint, other.linkPillContentFingerprint, other.wrappedCodeBlocksFingerprint,
72
+ other.fontScale, other.flavor, other.lineBreakStrategyIOS, other.writingDirection,
73
+ other.numberOfLines, other.ellipsizeMode, other.linkRegexKey, other.inlineCodeLinkRegexKey);
74
+ }
75
+ };
76
+
77
+ struct MeasurementCacheKeyHash {
78
+ size_t operator()(const MeasurementCacheKey &key) const
79
+ {
80
+ size_t h = 0;
81
+ HashUtils::hash_one(h, key.tiptap);
82
+ HashUtils::hash_one(h, key.maxWidth);
83
+ HashUtils::hash_one(h, key.allowTrailingMargin);
84
+ HashUtils::hash_one(h, key.allowFontScaling);
85
+ HashUtils::hash_one(h, key.maxFontSizeMultiplier);
86
+ HashUtils::hash_one(h, key.md4cFlagsUnderline);
87
+ HashUtils::hash_one(h, key.md4cFlagsSuperscript);
88
+ HashUtils::hash_one(h, key.md4cFlagsSubscript);
89
+ HashUtils::hash_one(h, key.md4cFlagsHighlight);
90
+ HashUtils::hash_one(h, key.md4cFlagsLatexMath);
91
+ HashUtils::hash_one(h, key.md4cFlagsHardSoftBreaks);
92
+ HashUtils::hash_one(h, key.md4cFlagsPreserveBlankLines);
93
+ HashUtils::hash_one(h, key.md4cFlagsAdmonitions);
94
+ HashUtils::hash_one(h, key.styleFingerprint);
95
+ HashUtils::hash_one(h, key.linkPillContentFingerprint);
96
+ HashUtils::hash_one(h, key.wrappedCodeBlocksFingerprint);
97
+ HashUtils::hash_one(h, key.fontScale);
98
+ HashUtils::hash_one(h, static_cast<uint8_t>(key.flavor));
99
+ HashUtils::hash_one(h, key.lineBreakStrategyIOS);
100
+ HashUtils::hash_one(h, key.writingDirection);
101
+ HashUtils::hash_one(h, key.numberOfLines);
102
+ HashUtils::hash_one(h, key.ellipsizeMode);
103
+ HashUtils::hash_one(h, key.linkRegexKey);
104
+ HashUtils::hash_one(h, key.inlineCodeLinkRegexKey);
105
+ return h;
106
+ }
107
+ };
108
+
109
+ struct CachedSize {
110
+ CGFloat width;
111
+ CGFloat height;
112
+ };
113
+
114
+ template <typename StyleStruct> inline size_t computeStyleFingerprint(const StyleStruct &s)
115
+ {
116
+ size_t h = 0;
117
+ auto hashFields = [&](auto... args) { (HashUtils::hash_one(h, args), ...); };
118
+
119
+ auto hashTextLayout = [&](const auto &item) {
120
+ hashFields(item.fontFamily, item.fontSize, item.fontWeight, item.marginTop, item.marginBottom, item.lineHeight);
121
+ };
122
+
123
+ // Block Elements
124
+ hashTextLayout(s.paragraph);
125
+ hashFields(s.paragraph.textAlign);
126
+ hashTextLayout(s.h1);
127
+ hashFields(s.h1.textAlign);
128
+ hashTextLayout(s.h2);
129
+ hashFields(s.h2.textAlign);
130
+ hashTextLayout(s.h3);
131
+ hashFields(s.h3.textAlign);
132
+ hashTextLayout(s.h4);
133
+ hashFields(s.h4.textAlign);
134
+ hashTextLayout(s.h5);
135
+ hashFields(s.h5.textAlign);
136
+ hashTextLayout(s.h6);
137
+ hashFields(s.h6.textAlign);
138
+
139
+ hashTextLayout(s.blockquote);
140
+ hashFields(s.blockquote.borderWidth, s.blockquote.gapWidth, s.blockquote.padding, s.blockquote.borderRadius);
141
+
142
+ hashTextLayout(s.list);
143
+ hashFields(s.list.bulletSize, s.list.markerMinWidth, s.list.markerFontWeight, s.list.gapWidth, s.list.marginLeft,
144
+ s.list.itemSpacing);
145
+
146
+ // Code & Inlines
147
+ hashFields(s.codeBlock.fontFamily, s.codeBlock.fontSize, s.codeBlock.fontWeight, s.codeBlock.marginTop,
148
+ s.codeBlock.marginBottom, s.codeBlock.lineHeight, s.codeBlock.padding, s.codeBlock.borderRadius,
149
+ s.codeBlock.borderWidth);
150
+ hashFields(s.code.fontFamily, s.code.fontSize);
151
+ hashFields(s.link.fontFamily, s.strong.fontFamily, s.strong.fontWeight, s.em.fontFamily, s.em.fontStyle);
152
+ // Variants change link metrics: a font family, or a pill box around the label.
153
+ for (const auto &variant : s.linkVariants) {
154
+ hashFields(variant.pattern, variant.fontFamily, variant.pill.enabled, variant.pill.label, variant.pill.iconUri,
155
+ variant.pill.paddingHorizontal, variant.pill.paddingVertical, variant.pill.lineHeight,
156
+ variant.pill.borderWidth, variant.pill.maxWidth);
157
+ }
158
+ hashFields(s.highlight.backgroundColor, s.highlight.color);
159
+
160
+ // Visual/Spacing Elements
161
+ hashFields(s.image.height, s.image.maxHeight, s.image.aspectRatio, s.image.marginTop, s.image.marginBottom);
162
+ hashFields(s.video.marginTop, s.video.marginBottom, s.video.borderRadius, s.video.aspectRatio,
163
+ s.video.backgroundColor);
164
+ hashFields(s.inlineImage.size);
165
+ hashFields(s.thematicBreak.height, s.thematicBreak.marginTop, s.thematicBreak.marginBottom);
166
+
167
+ // Complex Components
168
+ hashTextLayout(s.table);
169
+ hashFields(s.table.headerFontFamily, s.table.cellPaddingHorizontal, s.table.cellPaddingVertical, s.table.borderWidth,
170
+ s.table.borderRadius, s.table.horizontalOverflow);
171
+ hashFields(s.math.fontSize, s.math.padding, s.math.marginTop, s.math.marginBottom, s.math.textAlign);
172
+ hashFields(s.taskList.checkboxSize, s.taskList.checkboxBorderRadius);
173
+
174
+ return h;
175
+ }
176
+
177
+ // Pill labels and icons (the `linkPillContent` prop) change link widths.
178
+ template <typename ContentVector> inline size_t computeLinkPillContentFingerprint(const ContentVector &content)
179
+ {
180
+ size_t h = 0;
181
+ for (const auto &entry : content) {
182
+ HashUtils::hash_one(h, entry.url);
183
+ HashUtils::hash_one(h, entry.label);
184
+ HashUtils::hash_one(h, entry.iconUri);
185
+ }
186
+ return h;
187
+ }
188
+
189
+ template <typename RegexProps> inline std::string buildLinkRecognitionCacheKey(const RegexProps &props)
190
+ {
191
+ std::string key;
192
+ key += props.caseInsensitive ? '1' : '0';
193
+ key += props.dotAll ? '1' : '0';
194
+ key += props.isDisabled ? '1' : '0';
195
+ key += props.isDefault ? '1' : '0';
196
+ return key + props.pattern;
197
+ }
198
+
199
+ template <typename PropsType>
200
+ inline MeasurementCacheKey buildMeasurementCacheKey(const PropsType &props, CGFloat maxWidth, CGFloat fontScale,
201
+ TiptapFlavor flavor, size_t wrappedCodeBlocksFingerprint = 0)
202
+ {
203
+ return MeasurementCacheKey{
204
+ .tiptap = props.document,
205
+ .maxWidth = maxWidth,
206
+ .allowTrailingMargin = props.allowTrailingMargin,
207
+ .allowFontScaling = props.allowFontScaling,
208
+ .maxFontSizeMultiplier = props.maxFontSizeMultiplier,
209
+ .md4cFlagsUnderline = props.md4cFlags.underline,
210
+ .md4cFlagsSuperscript = props.md4cFlags.superscript,
211
+ .md4cFlagsSubscript = props.md4cFlags.subscript,
212
+ .md4cFlagsHighlight = props.md4cFlags.highlight,
213
+ .md4cFlagsLatexMath = props.md4cFlags.latexMath,
214
+ .md4cFlagsHardSoftBreaks = props.md4cFlags.hardSoftBreaks,
215
+ .md4cFlagsPreserveBlankLines = props.md4cFlags.preserveBlankLines,
216
+ .md4cFlagsAdmonitions = props.md4cFlags.admonitions,
217
+ .styleFingerprint = computeStyleFingerprint(props.tiptapStyle),
218
+ .linkPillContentFingerprint = computeLinkPillContentFingerprint(props.linkPillContent),
219
+ .wrappedCodeBlocksFingerprint = wrappedCodeBlocksFingerprint,
220
+ .fontScale = fontScale,
221
+ .flavor = flavor,
222
+ .lineBreakStrategyIOS = props.lineBreakStrategyIOS,
223
+ .writingDirection = props.writingDirection,
224
+ .numberOfLines = props.numberOfLines,
225
+ .ellipsizeMode = props.ellipsizeMode,
226
+ .linkRegexKey = buildLinkRecognitionCacheKey(props.linkRecognition.text),
227
+ .inlineCodeLinkRegexKey = buildLinkRecognitionCacheKey(props.linkRecognition.inlineCode),
228
+ };
229
+ }
230
+
231
+ /**
232
+ * Thread-safe global measurement cache using an LRU (Least Recently Used) strategy.
233
+ * This ensures O(1) lookups while automatically discarding the oldest entries.
234
+ */
235
+ class MeasurementCache {
236
+ public:
237
+ struct CacheEntry {
238
+ MeasurementCacheKey key;
239
+ CachedSize size;
240
+ };
241
+
242
+ static MeasurementCache &shared()
243
+ {
244
+ static MeasurementCache instance;
245
+ return instance;
246
+ }
247
+
248
+ bool get(const MeasurementCacheKey &key, CachedSize &outSize)
249
+ {
250
+ std::lock_guard<std::mutex> lock(mutex_);
251
+
252
+ auto it = map_.find(key);
253
+ if (it == map_.end()) {
254
+ return false;
255
+ }
256
+
257
+ list_.splice(list_.begin(), list_, it->second);
258
+
259
+ outSize = it->second->size;
260
+ return true;
261
+ }
262
+
263
+ void set(const MeasurementCacheKey &key, CachedSize size)
264
+ {
265
+ std::lock_guard<std::mutex> lock(mutex_);
266
+
267
+ auto it = map_.find(key);
268
+ if (it != map_.end()) {
269
+ it->second->size = size;
270
+ list_.splice(list_.begin(), list_, it->second);
271
+ return;
272
+ }
273
+
274
+ list_.push_front({key, size});
275
+ map_[key] = list_.begin();
276
+
277
+ if (map_.size() > kMaxEntries) {
278
+ auto &lastEntry = list_.back();
279
+ map_.erase(lastEntry.key);
280
+ list_.pop_back();
281
+ }
282
+ }
283
+
284
+ void removeMatchingTiptap(const std::string &tiptap)
285
+ {
286
+ std::lock_guard<std::mutex> lock(mutex_);
287
+
288
+ for (auto it = list_.begin(); it != list_.end();) {
289
+ if (it->key.tiptap == tiptap) {
290
+ map_.erase(it->key);
291
+ it = list_.erase(it);
292
+ } else {
293
+ ++it;
294
+ }
295
+ }
296
+ }
297
+
298
+ private:
299
+ MeasurementCache() = default;
300
+
301
+ static constexpr size_t kMaxEntries = 512;
302
+ mutable std::mutex mutex_;
303
+
304
+ std::list<CacheEntry> list_;
305
+ std::unordered_map<MeasurementCacheKey, std::list<CacheEntry>::iterator, MeasurementCacheKeyHash> map_;
306
+ };
307
+
308
+ } // namespace facebook::react
@@ -0,0 +1,145 @@
1
+ #pragma once
2
+
3
+ #include "MeasurementCache.h"
4
+ #import <Foundation/Foundation.h>
5
+ #import <React/RCTUtils.h>
6
+ #include <algorithm>
7
+ #include <cmath>
8
+ #include <react/renderer/core/LayoutConstraints.h>
9
+ #include <react/renderer/core/LayoutContext.h>
10
+ #include <react/utils/ManagedObjectWrapper.h>
11
+
12
+ namespace facebook::react {
13
+
14
+ // Threading contract (issue #550): measureContent may run on any thread while
15
+ // RN holds commit locks that main-thread committers (e.g. Reanimated) also
16
+ // acquire — with `preventShadowTreeCommitExhaustion`, the JS thread re-runs
17
+ // layout under `revisionMutexRecursive_` after 3 failed optimistic commits.
18
+ // Any dispatch_sync to main from this path can therefore deadlock: JS waits
19
+ // for main, main waits for the mutex JS holds (watchdog kill 0x8BADF00D).
20
+ // Nothing in the measurement path may wait on the main thread.
21
+ // EnrichedTiptapText and EnrichedTiptap both measure view-free
22
+ // (ENRMViewFreeMeasurement.h) and comply fully. The one known remaining
23
+ // violation is the text input's own measureContent
24
+ // (EnrichedTiptapTextInputShadowNode.mm), which measures live editable
25
+ // UITextView state and needs its own strategy.
26
+
27
+ /**
28
+ * Font scale (Dynamic Type multiplier) for measurement, without touching the
29
+ * main thread.
30
+ *
31
+ * Reads `LayoutContext::fontSizeMultiplier` instead of calling
32
+ * `RCTFontSizeMultiplier()` (a UIKit read that previously forced a
33
+ * dispatch_sync to main on every measure — a deadlock window under the locked
34
+ * commit fallback, see the contract above). RN maintains the multiplier for
35
+ * us: `RCTFabricSurface::_updateLayoutContext` sets it on main from
36
+ * `RCTFontSizeMultiplier()` and re-runs `constraintLayout` whenever
37
+ * `UIContentSizeCategoryDidChangeNotification` fires, so every Dynamic Type
38
+ * change re-measures with the fresh value. This is the same source
39
+ * `ParagraphShadowNode` uses for core text. A measure racing a Dynamic Type
40
+ * change at worst caches under the outgoing scale, which is never read again
41
+ * once the re-layout lands.
42
+ */
43
+ static inline CGFloat ENRMFontScaleForMeasurement(bool allowFontScaling, const LayoutContext &layoutContext)
44
+ {
45
+ return allowFontScaling ? layoutContext.fontSizeMultiplier : 1.0;
46
+ }
47
+
48
+ static inline Size ENRMClampMeasuredSize(CGSize size, const LayoutConstraints &layoutConstraints)
49
+ {
50
+ Float clampedWidth = std::max((Float)size.width, layoutConstraints.minimumSize.width);
51
+ clampedWidth = std::min(clampedWidth, layoutConstraints.maximumSize.width);
52
+ Float clampedHeight = std::max((Float)size.height, layoutConstraints.minimumSize.height);
53
+ if (std::isfinite(layoutConstraints.maximumSize.height)) {
54
+ clampedHeight = std::min(clampedHeight, layoutConstraints.maximumSize.height);
55
+ }
56
+ return {clampedWidth, clampedHeight};
57
+ }
58
+
59
+ template <typename PropsT>
60
+ static inline bool ENRMPropsNeedExactStreamingMeasurement(const PropsT &oldProps, const PropsT &newProps)
61
+ {
62
+ return oldProps.streamingAnimation != newProps.streamingAnimation ||
63
+ oldProps.allowFontScaling != newProps.allowFontScaling ||
64
+ oldProps.maxFontSizeMultiplier != newProps.maxFontSizeMultiplier ||
65
+ oldProps.allowTrailingMargin != newProps.allowTrailingMargin ||
66
+ oldProps.md4cFlags.underline != newProps.md4cFlags.underline ||
67
+ oldProps.md4cFlags.superscript != newProps.md4cFlags.superscript ||
68
+ oldProps.md4cFlags.subscript != newProps.md4cFlags.subscript ||
69
+ oldProps.md4cFlags.latexMath != newProps.md4cFlags.latexMath ||
70
+ oldProps.md4cFlags.highlight != newProps.md4cFlags.highlight ||
71
+ oldProps.md4cFlags.hardSoftBreaks != newProps.md4cFlags.hardSoftBreaks ||
72
+ oldProps.md4cFlags.preserveBlankLines != newProps.md4cFlags.preserveBlankLines ||
73
+ oldProps.isGFM != newProps.isGFM || oldProps.md4cFlags.admonitions != newProps.md4cFlags.admonitions ||
74
+ computeStyleFingerprint(oldProps.tiptapStyle) != computeStyleFingerprint(newProps.tiptapStyle);
75
+ }
76
+
77
+ /**
78
+ * Shared measureContent implementation for the tiptap component views.
79
+ *
80
+ * Owns the thread-safe layers — the streaming fast path (lock-free
81
+ * `ENRMAtomicSize` mailbox published by `updateLayoutMetrics:`), the
82
+ * LRU measurement cache, and the `layoutContext`-sourced font scale — then
83
+ * delegates cache misses to `measureUncached`, through which both components
84
+ * plug their view-free pipeline (`ENRMMeasureTiptapViewFree` /
85
+ * `ENRMMeasureSegmentedTiptapViewFree`); the resolved view is still handed
86
+ * to the block for strategies that can use it. `fontScale` handed to the
87
+ * block is the real multiplier even when streaming skips the cache —
88
+ * rendering must always use it. `wrappedCodeBlocksFingerprint` folds view
89
+ * state outside the props that changes the size (code blocks the user wrapped)
90
+ * into the cache key.
91
+ */
92
+ template <typename PropsT, typename ViewT>
93
+ static inline Size
94
+ ENRMMeasureTiptapContent(const PropsT &typedProps, const std::shared_ptr<void> &componentViewRef, int receivedCounter,
95
+ int &lastExactMeasurementCounter, CGSize &lastExactMeasurementSize, TiptapFlavor flavor,
96
+ const LayoutContext &layoutContext, const LayoutConstraints &layoutConstraints,
97
+ CGSize (^measureUncached)(ViewT *view, CGFloat maxWidth, CGFloat fontScale),
98
+ size_t wrappedCodeBlocksFingerprint = 0)
99
+ {
100
+ CGFloat maxWidth = layoutConstraints.maximumSize.width;
101
+
102
+ RCTInternalGenericWeakWrapper *weakWrapper = (RCTInternalGenericWeakWrapper *)unwrapManagedObject(componentViewRef);
103
+ ViewT *view = weakWrapper ? (ViewT *)weakWrapper.object : nil;
104
+
105
+ // Streaming fast path. Yoga re-measures several times per pass; the first call
106
+ // bumps lastExactMeasurementCounter, the rest land here. Return the freshly
107
+ // measured size, not the view's mailbox — mid-pass the frame isn't committed,
108
+ // so the mailbox is a generation stale and would freeze the height.
109
+ if (typedProps.streamingAnimation && view && receivedCounter <= lastExactMeasurementCounter) {
110
+ if (lastExactMeasurementSize.width > 0 && lastExactMeasurementSize.height > 0) {
111
+ return ENRMClampMeasuredSize(lastExactMeasurementSize, layoutConstraints);
112
+ }
113
+ CGSize currentSize = [view lastCommittedLayoutSize];
114
+ if (currentSize.width > 0 && currentSize.height > 0) {
115
+ return ENRMClampMeasuredSize(currentSize, layoutConstraints);
116
+ }
117
+ }
118
+
119
+ const bool shouldUseMeasurementCache = !typedProps.streamingAnimation;
120
+ CGFloat fontScale = ENRMFontScaleForMeasurement(typedProps.allowFontScaling, layoutContext);
121
+
122
+ if (shouldUseMeasurementCache && !typedProps.document.empty()) {
123
+ auto cacheKey = buildMeasurementCacheKey(typedProps, maxWidth, fontScale, flavor, wrappedCodeBlocksFingerprint);
124
+ CachedSize cached;
125
+ if (MeasurementCache::shared().get(cacheKey, cached)) {
126
+ return ENRMClampMeasuredSize(CGSizeMake(cached.width, cached.height), layoutConstraints);
127
+ }
128
+ }
129
+
130
+ CGSize size = measureUncached(view, maxWidth, fontScale);
131
+
132
+ if (shouldUseMeasurementCache && !typedProps.document.empty()) {
133
+ auto cacheKey = buildMeasurementCacheKey(typedProps, maxWidth, fontScale, flavor, wrappedCodeBlocksFingerprint);
134
+ MeasurementCache::shared().set(cacheKey, {size.width, size.height});
135
+ }
136
+
137
+ if (typedProps.streamingAnimation) {
138
+ lastExactMeasurementCounter = receivedCounter;
139
+ lastExactMeasurementSize = size;
140
+ }
141
+
142
+ return ENRMClampMeasuredSize(size, layoutConstraints);
143
+ }
144
+
145
+ } // namespace facebook::react
@@ -0,0 +1,7 @@
1
+ #pragma once
2
+
3
+ #import <Foundation/Foundation.h>
4
+
5
+ // Rendering metadata only. Copy reconstruction retains the source semantics.
6
+ static NSString *const ENRMRecognizedLinkAttributeName = @"ENRMRecognizedLink";
7
+ static NSString *const ENRMRecognizedLinkOriginalUnderlineAttributeName = @"ENRMRecognizedLinkOriginalUnderline";
@@ -0,0 +1,33 @@
1
+ #import "TiptapASTNode.h"
2
+ #import <Foundation/Foundation.h>
3
+
4
+ @interface ENRMMd4cFlags : NSObject <NSCopying>
5
+
6
+ @property (nonatomic, assign) BOOL underline;
7
+ @property (nonatomic, assign) BOOL latexMath;
8
+ @property (nonatomic, assign) BOOL superscript;
9
+ @property (nonatomic, assign) BOOL subscript;
10
+ @property (nonatomic, assign) BOOL highlight;
11
+ @property (nonatomic, assign) BOOL hardSoftBreaks;
12
+ @property (nonatomic, assign) BOOL preserveBlankLines;
13
+ @property (nonatomic, assign) BOOL admonitions;
14
+
15
+ + (instancetype)defaultFlags;
16
+
17
+ @end
18
+
19
+ @class ENRMLinkRegexConfig;
20
+
21
+ @interface ENRMTiptapParser : NSObject
22
+
23
+ - (TiptapASTNode *)parseTiptap:(NSString *)tiptap;
24
+ - (TiptapASTNode *)parseTiptap:(NSString *)tiptap flags:(ENRMMd4cFlags *)flags;
25
+ - (TiptapASTNode *)parseTiptap:(NSString *)tiptap flags:(ENRMMd4cFlags *)flags isGFM:(BOOL)isGFM;
26
+ // Recognition runs before returning the AST to renderers and measurement.
27
+ - (TiptapASTNode *)parseTiptap:(NSString *)tiptap
28
+ flags:(ENRMMd4cFlags *)flags
29
+ isGFM:(BOOL)isGFM
30
+ linkRegex:(ENRMLinkRegexConfig *)linkRegex
31
+ inlineCodeLinkRegex:(ENRMLinkRegexConfig *)inlineCodeLinkRegex;
32
+
33
+ @end
@@ -0,0 +1,73 @@
1
+ #import "ENRMTiptapParser.h"
2
+ #import "ENRMLinkRegexConfig.h"
3
+ #import "TiptapASTNode.h"
4
+
5
+ extern TiptapASTNode *parseTiptapWithCppParser(NSString *tiptap, ENRMMd4cFlags *flags, BOOL isGFM);
6
+ extern TiptapASTNode *parseTiptapWithCppParser(NSString *tiptap, ENRMMd4cFlags *flags, BOOL isGFM,
7
+ ENRMLinkRegexConfig *textRegex, ENRMLinkRegexConfig *codeRegex);
8
+
9
+ @implementation ENRMMd4cFlags
10
+
11
+ - (instancetype)init
12
+ {
13
+ if (self = [super init]) {
14
+ _underline = NO;
15
+ _latexMath = YES;
16
+ _superscript = NO;
17
+ _subscript = NO;
18
+ _highlight = NO;
19
+ _hardSoftBreaks = NO;
20
+ _preserveBlankLines = NO;
21
+ _admonitions = YES;
22
+ }
23
+ return self;
24
+ }
25
+
26
+ + (instancetype)defaultFlags
27
+ {
28
+ return [[ENRMMd4cFlags alloc] init];
29
+ }
30
+
31
+ - (id)copyWithZone:(NSZone *)zone
32
+ {
33
+ ENRMMd4cFlags *copy = [[ENRMMd4cFlags allocWithZone:zone] init];
34
+ copy.underline = self.underline;
35
+ copy.latexMath = self.latexMath;
36
+ copy.superscript = self.superscript;
37
+ copy.subscript = self.subscript;
38
+ copy.highlight = self.highlight;
39
+ copy.hardSoftBreaks = self.hardSoftBreaks;
40
+ copy.preserveBlankLines = self.preserveBlankLines;
41
+ copy.admonitions = self.admonitions;
42
+ return copy;
43
+ }
44
+
45
+ @end
46
+
47
+ @implementation ENRMTiptapParser
48
+
49
+ - (TiptapASTNode *)parseTiptap:(NSString *)tiptap
50
+ {
51
+ return [self parseTiptap:tiptap flags:[ENRMMd4cFlags defaultFlags]];
52
+ }
53
+
54
+ - (TiptapASTNode *)parseTiptap:(NSString *)tiptap flags:(ENRMMd4cFlags *)flags
55
+ {
56
+ return [self parseTiptap:tiptap flags:flags isGFM:YES];
57
+ }
58
+
59
+ - (TiptapASTNode *)parseTiptap:(NSString *)tiptap flags:(ENRMMd4cFlags *)flags isGFM:(BOOL)isGFM
60
+ {
61
+ return parseTiptapWithCppParser(tiptap, flags, isGFM);
62
+ }
63
+
64
+ - (TiptapASTNode *)parseTiptap:(NSString *)tiptap
65
+ flags:(ENRMMd4cFlags *)flags
66
+ isGFM:(BOOL)isGFM
67
+ linkRegex:(ENRMLinkRegexConfig *)linkRegex
68
+ inlineCodeLinkRegex:(ENRMLinkRegexConfig *)inlineCodeLinkRegex
69
+ {
70
+ return parseTiptapWithCppParser(tiptap, flags, isGFM, linkRegex, inlineCodeLinkRegex);
71
+ }
72
+
73
+ @end
@@ -0,0 +1,57 @@
1
+ #import <Foundation/Foundation.h>
2
+
3
+ typedef NS_ENUM(NSInteger, TiptapNodeType) {
4
+ TiptapNodeTypeDocument,
5
+ TiptapNodeTypeParagraph,
6
+ TiptapNodeTypeText,
7
+ TiptapNodeTypeLink,
8
+ TiptapNodeTypeHeading,
9
+ TiptapNodeTypeLineBreak,
10
+ TiptapNodeTypeStrong,
11
+ TiptapNodeTypeEmphasis,
12
+ TiptapNodeTypeStrikethrough,
13
+ TiptapNodeTypeUnderline,
14
+ TiptapNodeTypeCode,
15
+ TiptapNodeTypeImage,
16
+ TiptapNodeTypeBlockquote,
17
+ TiptapNodeTypeUnorderedList,
18
+ TiptapNodeTypeOrderedList,
19
+ TiptapNodeTypeListItem,
20
+ TiptapNodeTypeCodeBlock,
21
+ TiptapNodeTypeThematicBreak,
22
+ TiptapNodeTypeTable,
23
+ TiptapNodeTypeTableHead,
24
+ TiptapNodeTypeTableBody,
25
+ TiptapNodeTypeTableRow,
26
+ TiptapNodeTypeTableHeaderCell,
27
+ TiptapNodeTypeTableCell,
28
+ TiptapNodeTypeLatexMathInline,
29
+ TiptapNodeTypeLatexMathDisplay,
30
+ TiptapNodeTypeSpoiler,
31
+ TiptapNodeTypeSuperscript,
32
+ TiptapNodeTypeSubscript,
33
+ TiptapNodeTypeHighlight,
34
+ TiptapNodeTypeSoftBreak,
35
+ TiptapNodeTypeBlankLine,
36
+ TiptapNodeTypeAdmonition,
37
+ TiptapNodeTypeVideo,
38
+ TiptapNodeTypeFactoid,
39
+ TiptapNodeTypeMention
40
+ };
41
+
42
+ @interface TiptapASTNode : NSObject
43
+
44
+ @property (nonatomic, assign) TiptapNodeType type;
45
+ @property (nonatomic, strong) NSString *content;
46
+ @property (nonatomic, strong) NSMutableDictionary *attributes;
47
+ @property (nonatomic, strong) NSMutableArray<TiptapASTNode *> *children;
48
+
49
+ - (instancetype)initWithType:(TiptapNodeType)type;
50
+ - (void)addChild:(TiptapASTNode *)child;
51
+ - (void)setAttribute:(NSString *)key value:(NSString *)value;
52
+
53
+ @end
54
+
55
+ /// A node type that md4c emits as a standalone block stacked vertically,
56
+ /// as opposed to an inline span.
57
+ BOOL ENRMIsTopLevelBlockType(TiptapNodeType type);
@@ -0,0 +1,52 @@
1
+ #import "TiptapASTNode.h"
2
+
3
+ @implementation TiptapASTNode
4
+
5
+ - (instancetype)initWithType:(TiptapNodeType)type
6
+ {
7
+ if (self = [super init]) {
8
+ _type = type;
9
+ _content = nil;
10
+ _attributes = [[NSMutableDictionary alloc] init];
11
+ _children = [[NSMutableArray alloc] init];
12
+ }
13
+ return self;
14
+ }
15
+
16
+ - (void)addChild:(TiptapASTNode *)child
17
+ {
18
+ [_children addObject:child];
19
+ }
20
+
21
+ - (void)setAttribute:(NSString *)key value:(NSString *)value
22
+ {
23
+ _attributes[key] = value;
24
+ }
25
+
26
+ - (NSString *)description
27
+ {
28
+ return [NSString stringWithFormat:@"TiptapASTNode(type=%ld, content=%@, children=%lu)", (long)_type, _content,
29
+ (unsigned long)_children.count];
30
+ }
31
+
32
+ @end
33
+
34
+ BOOL ENRMIsTopLevelBlockType(TiptapNodeType type)
35
+ {
36
+ switch (type) {
37
+ case TiptapNodeTypeParagraph:
38
+ case TiptapNodeTypeHeading:
39
+ case TiptapNodeTypeCodeBlock:
40
+ case TiptapNodeTypeBlockquote:
41
+ case TiptapNodeTypeAdmonition:
42
+ case TiptapNodeTypeTable:
43
+ case TiptapNodeTypeUnorderedList:
44
+ case TiptapNodeTypeOrderedList:
45
+ case TiptapNodeTypeThematicBreak:
46
+ case TiptapNodeTypeBlankLine:
47
+ case TiptapNodeTypeLatexMathDisplay:
48
+ return YES;
49
+ default:
50
+ return NO;
51
+ }
52
+ }