@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,179 @@
1
+ #import "ENRMTiptapParser.h"
2
+ #include "TiptapParser.hpp"
3
+ #import "TiptapASTNode.h"
4
+ #include "TiptapASTNode.hpp"
5
+ #import <React/RCTLog.h>
6
+
7
+ // Convert C++ AST node to Objective-C AST node
8
+ static TiptapASTNode *convertCppASTToObjC(std::shared_ptr<Tiptap::TiptapASTNode> cppNode)
9
+ {
10
+ if (!cppNode) {
11
+ return [[TiptapASTNode alloc] initWithType:TiptapNodeTypeDocument];
12
+ }
13
+
14
+ // Convert C++ NodeType enum to Objective-C TiptapNodeType
15
+ TiptapNodeType objcType;
16
+ switch (cppNode->type) {
17
+ case Tiptap::NodeType::Document:
18
+ objcType = TiptapNodeTypeDocument;
19
+ break;
20
+ case Tiptap::NodeType::Paragraph:
21
+ objcType = TiptapNodeTypeParagraph;
22
+ break;
23
+ case Tiptap::NodeType::Text:
24
+ objcType = TiptapNodeTypeText;
25
+ break;
26
+ case Tiptap::NodeType::Link:
27
+ objcType = TiptapNodeTypeLink;
28
+ break;
29
+ case Tiptap::NodeType::Heading:
30
+ objcType = TiptapNodeTypeHeading;
31
+ break;
32
+ case Tiptap::NodeType::LineBreak:
33
+ objcType = TiptapNodeTypeLineBreak;
34
+ break;
35
+ case Tiptap::NodeType::Strong:
36
+ objcType = TiptapNodeTypeStrong;
37
+ break;
38
+ case Tiptap::NodeType::Emphasis:
39
+ objcType = TiptapNodeTypeEmphasis;
40
+ break;
41
+ case Tiptap::NodeType::Strikethrough:
42
+ objcType = TiptapNodeTypeStrikethrough;
43
+ break;
44
+ case Tiptap::NodeType::Underline:
45
+ objcType = TiptapNodeTypeUnderline;
46
+ break;
47
+ case Tiptap::NodeType::Code:
48
+ objcType = TiptapNodeTypeCode;
49
+ break;
50
+ case Tiptap::NodeType::Image:
51
+ objcType = TiptapNodeTypeImage;
52
+ break;
53
+ case Tiptap::NodeType::Blockquote:
54
+ objcType = TiptapNodeTypeBlockquote;
55
+ break;
56
+ case Tiptap::NodeType::UnorderedList:
57
+ objcType = TiptapNodeTypeUnorderedList;
58
+ break;
59
+ case Tiptap::NodeType::OrderedList:
60
+ objcType = TiptapNodeTypeOrderedList;
61
+ break;
62
+ case Tiptap::NodeType::ListItem:
63
+ objcType = TiptapNodeTypeListItem;
64
+ break;
65
+ case Tiptap::NodeType::CodeBlock:
66
+ objcType = TiptapNodeTypeCodeBlock;
67
+ break;
68
+ case Tiptap::NodeType::ThematicBreak:
69
+ objcType = TiptapNodeTypeThematicBreak;
70
+ break;
71
+ case Tiptap::NodeType::Table:
72
+ objcType = TiptapNodeTypeTable;
73
+ break;
74
+ case Tiptap::NodeType::TableHead:
75
+ objcType = TiptapNodeTypeTableHead;
76
+ break;
77
+ case Tiptap::NodeType::TableBody:
78
+ objcType = TiptapNodeTypeTableBody;
79
+ break;
80
+ case Tiptap::NodeType::TableRow:
81
+ objcType = TiptapNodeTypeTableRow;
82
+ break;
83
+ case Tiptap::NodeType::TableHeaderCell:
84
+ objcType = TiptapNodeTypeTableHeaderCell;
85
+ break;
86
+ case Tiptap::NodeType::TableCell:
87
+ objcType = TiptapNodeTypeTableCell;
88
+ break;
89
+ case Tiptap::NodeType::LatexMathInline:
90
+ objcType = TiptapNodeTypeLatexMathInline;
91
+ break;
92
+ case Tiptap::NodeType::LatexMathDisplay:
93
+ objcType = TiptapNodeTypeLatexMathDisplay;
94
+ break;
95
+ case Tiptap::NodeType::Spoiler:
96
+ objcType = TiptapNodeTypeSpoiler;
97
+ break;
98
+ case Tiptap::NodeType::Superscript:
99
+ objcType = TiptapNodeTypeSuperscript;
100
+ break;
101
+ case Tiptap::NodeType::Subscript:
102
+ objcType = TiptapNodeTypeSubscript;
103
+ break;
104
+ case Tiptap::NodeType::Highlight:
105
+ objcType = TiptapNodeTypeHighlight;
106
+ break;
107
+ case Tiptap::NodeType::SoftBreak:
108
+ objcType = TiptapNodeTypeSoftBreak;
109
+ break;
110
+ case Tiptap::NodeType::BlankLine:
111
+ objcType = TiptapNodeTypeBlankLine;
112
+ break;
113
+ case Tiptap::NodeType::Admonition:
114
+ objcType = TiptapNodeTypeAdmonition;
115
+ break;
116
+ case Tiptap::NodeType::Video:
117
+ objcType = TiptapNodeTypeVideo;
118
+ break;
119
+ case Tiptap::NodeType::Factoid:
120
+ objcType = TiptapNodeTypeFactoid;
121
+ break;
122
+ case Tiptap::NodeType::Mention:
123
+ objcType = TiptapNodeTypeMention;
124
+ break;
125
+ }
126
+
127
+ TiptapASTNode *objcNode = [[TiptapASTNode alloc] initWithType:objcType];
128
+
129
+ // Convert content
130
+ if (!cppNode->content.empty()) {
131
+ objcNode.content = [NSString stringWithUTF8String:cppNode->content.c_str()];
132
+ }
133
+
134
+ // Convert attributes
135
+ for (const auto &[key, value] : cppNode->attributes) {
136
+ NSString *objcKey = [NSString stringWithUTF8String:key.c_str()];
137
+ NSString *objcValue = [NSString stringWithUTF8String:value.c_str()];
138
+ [objcNode setAttribute:objcKey value:objcValue];
139
+ }
140
+
141
+ // Convert children recursively
142
+ for (const auto &child : cppNode->children) {
143
+ TiptapASTNode *objcChild = convertCppASTToObjC(child);
144
+ [objcNode addChild:objcChild];
145
+ }
146
+
147
+ return objcNode;
148
+ }
149
+
150
+ TiptapASTNode *parseTiptapWithCppParser(NSString *document, ENRMMd4cFlags *flags, BOOL isGFM,
151
+ ENRMLinkRegexConfig *textRegex, ENRMLinkRegexConfig *codeRegex);
152
+
153
+ TiptapASTNode *parseTiptapWithCppParser(NSString *document, ENRMMd4cFlags *flags, BOOL isGFM)
154
+ {
155
+ return parseTiptapWithCppParser(document, flags, isGFM, nil, nil);
156
+ }
157
+
158
+ // Flags and link-regex arguments are ignored. The string is a Tiptap document.
159
+ TiptapASTNode *parseTiptapWithCppParser(NSString *document, ENRMMd4cFlags *flags, BOOL isGFM,
160
+ ENRMLinkRegexConfig *textRegex, ENRMLinkRegexConfig *codeRegex)
161
+ {
162
+ (void)flags;
163
+ (void)isGFM;
164
+ (void)textRegex;
165
+ (void)codeRegex;
166
+
167
+ if (document.length == 0) {
168
+ return [[TiptapASTNode alloc] initWithType:TiptapNodeTypeDocument];
169
+ }
170
+
171
+ const char *utf8String = [document UTF8String];
172
+ if (!utf8String) {
173
+ RCTLogError(@"TiptapParserBridge: Failed to convert document to UTF-8");
174
+ return [[TiptapASTNode alloc] initWithType:TiptapNodeTypeDocument];
175
+ }
176
+
177
+ auto cppAST = Tiptap::parseTiptapDocument(std::string(utf8String));
178
+ return convertCppASTToObjC(cppAST);
179
+ }
@@ -0,0 +1,23 @@
1
+ #import <Foundation/Foundation.h>
2
+
3
+ @class ENRMBlockquoteTextRenderer;
4
+ @class TiptapASTNode;
5
+ @class RenderContext;
6
+
7
+ NS_ASSUME_NONNULL_BEGIN
8
+
9
+ @interface AttributedRenderer : NSObject
10
+ - (instancetype)initWithConfig:(id)config;
11
+ // Renders a flat list of sibling nodes into an attributed string: sets the baseline block style,
12
+ // walks each node, and trims the trailing block margin. Pass a non-nil block to render the nodes as
13
+ // a blockquote's own content (blockquote baseline + the quote's line height applied over the run);
14
+ // it draws no box - the ENRMBlockquoteContainerView draws the border/background/padding. See
15
+ // ENRMBlockquoteTextRenderer.
16
+ - (NSMutableAttributedString *)renderNodes:(NSArray<TiptapASTNode *> *)nodes
17
+ context:(RenderContext *)context
18
+ block:(nullable ENRMBlockquoteTextRenderer *)block;
19
+ - (CGFloat)getLastElementMarginBottom;
20
+ - (void)setAllowTrailingMargin:(BOOL)allow;
21
+ @end
22
+
23
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,229 @@
1
+ #import "AttributedRenderer.h"
2
+ #import "BlockquoteBorder.h"
3
+ #import "CodeBlockBackground.h"
4
+ #import "ENRMBlockquoteTextRenderer.h"
5
+ #import "ENRMLinkPillText.h"
6
+ #import "LastElementUtils.h"
7
+ #import "TiptapASTNode.h"
8
+ #import "NodeRenderer.h"
9
+ #import "ParagraphStyleUtils.h"
10
+ #import "RenderContext.h"
11
+ #import "RendererFactory.h"
12
+ #import "StyleConfig.h"
13
+
14
+ @implementation AttributedRenderer {
15
+ StyleConfig *_config;
16
+ RendererFactory *_rendererFactory;
17
+ CGFloat _lastElementMarginBottom;
18
+ BOOL _allowTrailingMargin;
19
+ }
20
+
21
+ - (instancetype)initWithConfig:(StyleConfig *)config
22
+ {
23
+ self = [super init];
24
+ if (self) {
25
+ _config = config;
26
+ _rendererFactory = [[RendererFactory alloc] initWithConfig:config];
27
+ _lastElementMarginBottom = 0.0;
28
+ _allowTrailingMargin = NO;
29
+ }
30
+ return self;
31
+ }
32
+
33
+ /**
34
+ * Entry point for rendering a flat list of sibling nodes (e.g. a document's or a block segment's
35
+ * children). Sets the baseline block style, runs the recursive traversal, and trims the trailing
36
+ * block margin. An optional [block] decorates the pass - it enters a block baseline before the nodes
37
+ * render and post-processes the finished string - letting a caller render content as e.g. blockquote
38
+ * text without this class knowing anything block-specific. See ENRMBlockquoteTextRenderer.
39
+ */
40
+ - (NSMutableAttributedString *)renderNodes:(NSArray<TiptapASTNode *> *)nodes
41
+ context:(RenderContext *)context
42
+ block:(ENRMBlockquoteTextRenderer *)block
43
+ {
44
+ // 1. Establish the baseline block style. This ensures leaf nodes (like Text) have valid
45
+ // attributes if they appear at the top level. A decorator overrides the default paragraph
46
+ // baseline (e.g. the blockquote baseline so paragraphs render tight and pick up the quote's
47
+ // font/color).
48
+ if (block) {
49
+ [block pushOnContext:context];
50
+ } else {
51
+ [context setBlockStyle:BlockTypeParagraph font:_config.paragraphFont color:_config.paragraphColor headingLevel:0];
52
+ }
53
+
54
+ NSMutableAttributedString *output = [[NSMutableAttributedString alloc] init];
55
+
56
+ // 2. Iterate through the sibling nodes.
57
+ for (TiptapASTNode *node in nodes) {
58
+ [self renderNodeRecursive:node into:output context:context];
59
+ }
60
+
61
+ // 3. Remove trailing paragraph spacing from last block element
62
+ // Reset lastElementMarginBottom before processing
63
+ _lastElementMarginBottom = 0.0;
64
+ [self removeTrailingSpacing:output];
65
+
66
+ // 4. Let the decorator post-process the finished string (e.g. stamp the quote's line height).
67
+ [block postProcess:output];
68
+ ENRMLinkPillsAdoptPlaceholderFonts(output);
69
+
70
+ // 5. Cleanup global state to prevent side effects in subsequent renders.
71
+ [context clearBlockStyle];
72
+
73
+ return output;
74
+ }
75
+
76
+ /**
77
+ * Trims trailing newlines after the last rendered block, with special handling for code blocks.
78
+ *
79
+ * For non-code-block tail elements: deletes all trailing newlines after the last non-newline
80
+ * character and zeroes the last element's paragraph spacing so it doesn't render a margin past
81
+ * the content.
82
+ *
83
+ * For code blocks (`isLastBlockACodeBlock` == YES): keeps the bottom padding spacer in place
84
+ * AND preserves a single trailing newline immediately after it (typically the
85
+ * codeBlockMarginBottom spacer that CodeBlockRenderer already appended; if none exists, one is
86
+ * synthesized here). That extra newline matters because of an iOS layout quirk:
87
+ *
88
+ * - iOS treats the trailing `\n` of the storage as a paragraph terminator and reports the
89
+ * line fragment for the paragraph after it via `extraLineFragmentRect`.
90
+ * - `boundingRectForGlyphRange:` excludes that extra line, and the graphics-context clip
91
+ * passed to `drawBackgroundForGlyphRange:` is tiled to the laid-out content area (rounded
92
+ * up to 128pt boundaries) which also excludes it.
93
+ * - If the bottom padding spacer were the trailing `\n`, its 16/19pt line fragment would
94
+ * fall into that excluded zone — the background rect would have to be manually extended
95
+ * past the clip and the bottom rounded corner would get sliced off at the tile boundary
96
+ * (the original visual bug in #354).
97
+ *
98
+ * By keeping a 1pt-tall tail newline beyond the bottom padding spacer, iOS lays the spacer
99
+ * out as a normal interior line fragment included in usedRect/boundingRect and inside the
100
+ * drawing tiles, so the corner renders intact and no rect extension is needed.
101
+ */
102
+ - (void)removeTrailingSpacing:(NSMutableAttributedString *)output
103
+ {
104
+ if (output.length == 0)
105
+ return;
106
+
107
+ // Find the last non-newline character
108
+ NSRange lastContent = [output.string rangeOfCharacterFromSet:[NSCharacterSet.newlineCharacterSet invertedSet]
109
+ options:NSBackwardsSearch];
110
+ if (lastContent.location == NSNotFound)
111
+ return;
112
+
113
+ // 1. Capture the Margin Bottom (Scanning from last content to end)
114
+ _lastElementMarginBottom = 0.0;
115
+ for (NSUInteger i = lastContent.location; i < output.length;) {
116
+ NSRange attrRange;
117
+ NSParagraphStyle *style = [output attribute:NSParagraphStyleAttributeName atIndex:i effectiveRange:&attrRange];
118
+ if (style) {
119
+ _lastElementMarginBottom = MAX(_lastElementMarginBottom, style.paragraphSpacing);
120
+ }
121
+ i = NSMaxRange(attrRange);
122
+ }
123
+
124
+ // 2. Trim trailing characters
125
+ NSUInteger logicalEnd = NSMaxRange(lastContent);
126
+ BOOL isCodeBlock = isLastBlockACodeBlock(output);
127
+ BOOL isPaddedBlockquote = !isCodeBlock && [_config blockquotePadding] > 0 &&
128
+ [output attribute:BlockquoteDepthAttributeName
129
+ atIndex:lastContent.location
130
+ effectiveRange:NULL] != nil;
131
+ NSRange codeRange = NSMakeRange(0, 0);
132
+ if (isCodeBlock) {
133
+ [output attribute:CodeBlockAttributeName
134
+ atIndex:lastContent.location
135
+ longestEffectiveRange:&codeRange
136
+ inRange:NSMakeRange(0, output.length)];
137
+ NSUInteger codeEnd = NSMaxRange(codeRange);
138
+ if (codeEnd >= output.length) {
139
+ [output appendAttributedString:kNewlineAttributedString];
140
+ }
141
+ logicalEnd = codeEnd + 1;
142
+ } else if (isPaddedBlockquote) {
143
+ NSUInteger blockquoteEnd = NSMaxRange(lastContent);
144
+ while (blockquoteEnd < output.length && [output attribute:BlockquoteDepthAttributeName
145
+ atIndex:blockquoteEnd
146
+ effectiveRange:NULL] != nil) {
147
+ blockquoteEnd++;
148
+ }
149
+ if (blockquoteEnd >= output.length) {
150
+ [output appendAttributedString:kNewlineAttributedString];
151
+ }
152
+ logicalEnd = blockquoteEnd + 1;
153
+ }
154
+
155
+ if (logicalEnd < output.length) {
156
+ [output deleteCharactersInRange:NSMakeRange(logicalEnd, output.length - logicalEnd)];
157
+ }
158
+
159
+ if ((isCodeBlock && NSMaxRange(codeRange) < output.length) || isPaddedBlockquote) {
160
+ NSUInteger tailIdx = isCodeBlock ? NSMaxRange(codeRange) : logicalEnd - 1;
161
+ [output removeAttribute:CodeBlockAttributeName range:NSMakeRange(tailIdx, 1)];
162
+ [output removeAttribute:BlockquoteDepthAttributeName range:NSMakeRange(tailIdx, 1)];
163
+ [output removeAttribute:BlockquoteBackgroundColorAttributeName range:NSMakeRange(tailIdx, 1)];
164
+ NSParagraphStyle *style = [output attribute:NSParagraphStyleAttributeName atIndex:tailIdx effectiveRange:NULL];
165
+ NSMutableParagraphStyle *mutableStyle = style ? [style mutableCopy] : [[NSMutableParagraphStyle alloc] init];
166
+ mutableStyle.paragraphSpacing = 0;
167
+ mutableStyle.paragraphSpacingBefore = 0;
168
+ mutableStyle.minimumLineHeight = 1;
169
+ mutableStyle.maximumLineHeight = 1;
170
+ [output addAttribute:NSParagraphStyleAttributeName value:mutableStyle range:NSMakeRange(tailIdx, 1)];
171
+ }
172
+
173
+ // 3. Zero out internal spacing for the last element (if not a code block)
174
+ if (!isCodeBlock) {
175
+ NSRange styleRange;
176
+ NSParagraphStyle *style = [output attribute:NSParagraphStyleAttributeName
177
+ atIndex:lastContent.location
178
+ effectiveRange:&styleRange];
179
+
180
+ if (style) {
181
+ NSMutableParagraphStyle *mutableStyle = [style mutableCopy];
182
+ mutableStyle.paragraphSpacing = 0;
183
+ mutableStyle.paragraphSpacingBefore = 0;
184
+
185
+ if (isLastElementImage(output)) {
186
+ mutableStyle.lineSpacing = 0;
187
+ }
188
+
189
+ NSRange safeRange = NSIntersectionRange(styleRange, NSMakeRange(0, output.length));
190
+ [output addAttribute:NSParagraphStyleAttributeName value:mutableStyle range:safeRange];
191
+ }
192
+ }
193
+ }
194
+
195
+ - (void)setAllowTrailingMargin:(BOOL)allow
196
+ {
197
+ _allowTrailingMargin = allow;
198
+ }
199
+
200
+ - (CGFloat)getLastElementMarginBottom
201
+ {
202
+ return _lastElementMarginBottom;
203
+ }
204
+
205
+ /**
206
+ * Orchestrates the recursive traversal of the AST.
207
+ * If a specialized renderer exists for a node type, it takes full control.
208
+ */
209
+ - (void)renderNodeRecursive:(TiptapASTNode *)node
210
+ into:(NSMutableAttributedString *)out
211
+ context:(RenderContext *)context
212
+ {
213
+ if (!node)
214
+ return;
215
+
216
+ id<NodeRenderer> renderer = [_rendererFactory rendererForNodeType:node.type];
217
+
218
+ if (renderer) {
219
+ // Specialized renderers (e.g., Strong, Link, Heading) handle their own sub-trees.
220
+ [renderer renderNode:node into:out context:context];
221
+ } else {
222
+ // Fallback: Default to deep-first traversal for unhandled container nodes.
223
+ for (TiptapASTNode *child in node.children) {
224
+ [self renderNodeRecursive:child into:out context:context];
225
+ }
226
+ }
227
+ }
228
+
229
+ @end
@@ -0,0 +1,33 @@
1
+ #pragma once
2
+ #import "NodeRenderer.h"
3
+
4
+ @class RendererFactory;
5
+ @class StyleConfig;
6
+ @class RenderContext;
7
+ @class TiptapASTNode;
8
+
9
+ /// Shared base for all node renderers — provides `_rendererFactory` and `_config`
10
+ /// as protected ivars and the common designated initializer.
11
+ /// `renderNode:into:context:` is a template method: take context snapshot ->
12
+ /// `renderNodeContent:into:context:` -> restore snapshot. Subclasses implement
13
+ /// `renderNodeContent:into:context:` and, when they mutate scoped context state,
14
+ /// override `takeContextSnapshot:` to return `[context snapshotScope]`.
15
+ @interface BaseRenderer : NSObject <NodeRenderer> {
16
+ @protected
17
+ __weak RendererFactory *_rendererFactory;
18
+ StyleConfig *_config;
19
+ }
20
+
21
+ - (instancetype)initWithRendererFactory:(id)rendererFactory config:(id)config;
22
+
23
+ - (void)renderNodeContent:(TiptapASTNode *)node
24
+ into:(NSMutableAttributedString *)output
25
+ context:(RenderContext *)context;
26
+
27
+ /// Default returns nil.
28
+ - (nullable id)takeContextSnapshot:(RenderContext *)context;
29
+
30
+ /// Default restores a scope frame when snapshot is non-nil, no-op otherwise.
31
+ - (void)restoreContextSnapshot:(nullable id)snapshot context:(RenderContext *)context;
32
+
33
+ @end
@@ -0,0 +1,46 @@
1
+ #import "BaseRenderer.h"
2
+ #import "RenderContext.h"
3
+ #import "RendererFactory.h"
4
+ #import "StyleConfig.h"
5
+
6
+ @implementation BaseRenderer
7
+
8
+ - (instancetype)initWithRendererFactory:(id)rendererFactory config:(id)config
9
+ {
10
+ if (self = [super init]) {
11
+ _rendererFactory = rendererFactory;
12
+ _config = (StyleConfig *)config;
13
+ }
14
+ return self;
15
+ }
16
+
17
+ - (void)renderNode:(TiptapASTNode *)node into:(NSMutableAttributedString *)output context:(RenderContext *)context
18
+ {
19
+ id snapshot = [self takeContextSnapshot:context];
20
+ @try {
21
+ [self renderNodeContent:node into:output context:context];
22
+ } @finally {
23
+ [self restoreContextSnapshot:snapshot context:context];
24
+ }
25
+ }
26
+
27
+ - (void)renderNodeContent:(TiptapASTNode *)node
28
+ into:(NSMutableAttributedString *)output
29
+ context:(RenderContext *)context
30
+ {
31
+ [self doesNotRecognizeSelector:_cmd];
32
+ }
33
+
34
+ - (id)takeContextSnapshot:(RenderContext *)context
35
+ {
36
+ return nil;
37
+ }
38
+
39
+ - (void)restoreContextSnapshot:(id)snapshot context:(RenderContext *)context
40
+ {
41
+ if (snapshot) {
42
+ [context restoreScope:snapshot];
43
+ }
44
+ }
45
+
46
+ @end
@@ -0,0 +1,10 @@
1
+ #pragma once
2
+ #import "ENRMUIKit.h"
3
+ #import <Foundation/Foundation.h>
4
+
5
+ extern NSString *const ENRMScriptAttributeName;
6
+ extern NSString *const ENRMScriptValueSuperscript;
7
+ extern NSString *const ENRMScriptValueSubscript;
8
+
9
+ void ENRMApplyBaselineShift(NSMutableAttributedString *output, NSRange range, CGFloat fontScale,
10
+ CGFloat baselineOffsetScale);
@@ -0,0 +1,26 @@
1
+ #import "BaselineShiftTextAttributes.h"
2
+
3
+ NSString *const ENRMScriptAttributeName = @"ENRMScript";
4
+ NSString *const ENRMScriptValueSuperscript = @"superscript";
5
+ NSString *const ENRMScriptValueSubscript = @"subscript";
6
+
7
+ void ENRMApplyBaselineShift(NSMutableAttributedString *output, NSRange range, CGFloat fontScale,
8
+ CGFloat baselineOffsetScale)
9
+ {
10
+ [output enumerateAttribute:NSFontAttributeName
11
+ inRange:range
12
+ options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
13
+ usingBlock:^(UIFont *font, NSRange fontRange, BOOL *stop) {
14
+ (void)stop;
15
+ if (![font isKindOfClass:UIFont.class]) {
16
+ return;
17
+ }
18
+
19
+ UIFont *scaledFont = [UIFont fontWithDescriptor:font.fontDescriptor
20
+ size:font.pointSize * fontScale];
21
+ [output addAttribute:NSFontAttributeName value:scaledFont range:fontRange];
22
+ [output addAttribute:NSBaselineOffsetAttributeName
23
+ value:@(font.pointSize * baselineOffsetScale)
24
+ range:fontRange];
25
+ }];
26
+ }
@@ -0,0 +1,4 @@
1
+ #import "BaseRenderer.h"
2
+
3
+ @interface BlankLineRenderer : BaseRenderer
4
+ @end
@@ -0,0 +1,51 @@
1
+ #import "BlankLineRenderer.h"
2
+ #import "TiptapASTNode.h"
3
+ #import "ParagraphStyleUtils.h"
4
+ #import "StyleConfig.h"
5
+
6
+ #pragma mark - Renderer Implementation
7
+
8
+ // Renders a run of consecutive blank lines emitted by the parser when the
9
+ // preserveBlankLines flag is enabled. Each blank line in the source is drawn as
10
+ // one empty line, so the rendered text keeps the exact line count that was typed
11
+ // (e.g. in EnrichedTiptapTextInput). The empty lines use the paragraph font
12
+ // and line height so their vertical rhythm matches the surrounding paragraphs;
13
+ // any extra block spacing is left to the caller to configure via tiptapStyle.
14
+ @implementation BlankLineRenderer
15
+
16
+ - (void)renderNodeContent:(TiptapASTNode *)node
17
+ into:(NSMutableAttributedString *)output
18
+ context:(RenderContext *)context
19
+ {
20
+ NSInteger count = [node.attributes[@"count"] integerValue];
21
+ if (count <= 0) {
22
+ return;
23
+ }
24
+
25
+ [self ensureStartingNewline:output];
26
+
27
+ NSDictionary *attributes = @{NSFontAttributeName : _config.paragraphFont};
28
+
29
+ NSMutableString *blanks = [NSMutableString stringWithCapacity:(NSUInteger)count];
30
+ for (NSInteger i = 0; i < count; i++) {
31
+ [blanks appendString:@"\n"];
32
+ }
33
+
34
+ NSUInteger start = output.length;
35
+ [output appendAttributedString:[[NSAttributedString alloc] initWithString:blanks attributes:attributes]];
36
+
37
+ NSRange range = NSMakeRange(start, output.length - start);
38
+ applyLineHeight(output, range, _config.paragraphLineHeight);
39
+ applyTextAlignment(output, range, _config.paragraphTextAlign);
40
+ }
41
+
42
+ #pragma mark - Private Utilities
43
+
44
+ - (void)ensureStartingNewline:(NSMutableAttributedString *)output
45
+ {
46
+ if (output.length > 0 && ![output.string hasSuffix:@"\n"]) {
47
+ [output appendAttributedString:[[NSAttributedString alloc] initWithString:@"\n"]];
48
+ }
49
+ }
50
+
51
+ @end
@@ -0,0 +1,6 @@
1
+ #import "BaseRenderer.h"
2
+ #import "TiptapASTNode.h"
3
+ #import "RenderContext.h"
4
+
5
+ @interface BlockquoteRenderer : BaseRenderer
6
+ @end