@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,181 @@
1
+ package com.renderrichtext.renderer
2
+
3
+ import com.renderrichtext.styles.BaseBlockStyle
4
+ import com.renderrichtext.styles.BlockquoteStyle
5
+ import com.renderrichtext.styles.CodeBlockStyle
6
+ import com.renderrichtext.styles.HeadingStyle
7
+ import com.renderrichtext.styles.ListStyle
8
+ import com.renderrichtext.styles.ParagraphStyle
9
+
10
+ enum class BlockType {
11
+ NONE,
12
+ PARAGRAPH,
13
+ HEADING,
14
+ BLOCKQUOTE,
15
+ UNORDERED_LIST,
16
+ ORDERED_LIST,
17
+ CODE_BLOCK,
18
+ }
19
+
20
+ data class BlockStyle(
21
+ val fontSize: Float,
22
+ val fontFamily: String,
23
+ val fontWeight: String,
24
+ val color: Int,
25
+ )
26
+
27
+ private data class BlockStyleEntry(
28
+ val blockType: BlockType,
29
+ val blockStyle: BlockStyle,
30
+ val headingLevel: Int,
31
+ )
32
+
33
+ class BlockStyleContext {
34
+ var currentBlockType = BlockType.NONE
35
+ private set
36
+
37
+ private var currentHeadingLevel = 0
38
+ private val blockStyleStack = ArrayDeque<BlockStyleEntry>()
39
+
40
+ var blockquoteDepth = 0
41
+ var listDepth = 0
42
+ var listType: ListType? = null
43
+ var listItemNumber = 0
44
+ var listMarkerExtra = 0f
45
+ var ancestorMarkerOffset = 0f
46
+ var listItemMarkerExtra = 0f
47
+ var listItemMarkerWidth: Float? = null
48
+ var taskItemCount = 0
49
+ var accumulatedIndent = 0
50
+
51
+ val listItemStarts = mutableListOf<Int>()
52
+
53
+ private val orderedListItemNumbers = ArrayDeque<Int>()
54
+
55
+ enum class ListType { UNORDERED, ORDERED }
56
+
57
+ private fun pushBlockStyle(
58
+ type: BlockType,
59
+ style: BaseBlockStyle,
60
+ headingLevel: Int = 0,
61
+ ) {
62
+ val entry =
63
+ BlockStyleEntry(
64
+ blockType = type,
65
+ blockStyle = BlockStyle(style.fontSize, style.fontFamily, style.fontWeight, style.color),
66
+ headingLevel = headingLevel,
67
+ )
68
+
69
+ blockStyleStack.addLast(entry)
70
+ currentBlockType = type
71
+ currentHeadingLevel = headingLevel
72
+ }
73
+
74
+ fun popBlockStyle() {
75
+ if (blockStyleStack.isNotEmpty()) {
76
+ blockStyleStack.removeLast()
77
+ }
78
+
79
+ val parentStyle = blockStyleStack.lastOrNull()
80
+ if (parentStyle != null) {
81
+ currentBlockType = parentStyle.blockType
82
+ currentHeadingLevel = parentStyle.headingLevel
83
+ } else {
84
+ currentBlockType = BlockType.NONE
85
+ currentHeadingLevel = 0
86
+ }
87
+ }
88
+
89
+ fun setParagraphStyle(style: ParagraphStyle) = pushBlockStyle(BlockType.PARAGRAPH, style)
90
+
91
+ fun setHeadingStyle(
92
+ style: HeadingStyle,
93
+ level: Int,
94
+ ) = pushBlockStyle(BlockType.HEADING, style, level)
95
+
96
+ fun setBlockquoteStyle(style: BlockquoteStyle) = pushBlockStyle(BlockType.BLOCKQUOTE, style)
97
+
98
+ fun setUnorderedListStyle(style: ListStyle) {
99
+ listType = ListType.UNORDERED
100
+ pushBlockStyle(BlockType.UNORDERED_LIST, style)
101
+ }
102
+
103
+ fun setOrderedListStyle(style: ListStyle) {
104
+ listType = ListType.ORDERED
105
+ pushBlockStyle(BlockType.ORDERED_LIST, style)
106
+ }
107
+
108
+ fun setCodeBlockStyle(style: CodeBlockStyle) = pushBlockStyle(BlockType.CODE_BLOCK, style)
109
+
110
+ fun incrementListItemNumber() {
111
+ listItemNumber++
112
+ }
113
+
114
+ fun resetListItemNumber(startNumber: Int = 1) {
115
+ // ListItemRenderer pre-increments, so the counter starts one below the
116
+ // first rendered number.
117
+ listItemNumber = startNumber - 1
118
+ }
119
+
120
+ fun pushOrderedListItemNumber() {
121
+ orderedListItemNumbers.addLast(listItemNumber)
122
+ }
123
+
124
+ fun popOrderedListItemNumber() {
125
+ if (orderedListItemNumbers.isNotEmpty()) {
126
+ listItemNumber = orderedListItemNumbers.removeLast()
127
+ }
128
+ }
129
+
130
+ fun clearListStyle() {
131
+ popBlockStyle()
132
+
133
+ if (listDepth == 0) {
134
+ listType = null
135
+ listItemNumber = 0
136
+ orderedListItemNumbers.clear()
137
+ }
138
+ }
139
+
140
+ /** Same font as the current block, with [color] as the base text color for nested inline nodes. */
141
+ fun pushInlineColor(color: Int) {
142
+ val current =
143
+ blockStyleStack.lastOrNull()
144
+ ?: throw IllegalStateException(
145
+ "BlockStyle is null. Inline renderers must be used within a block context.",
146
+ )
147
+ blockStyleStack.addLast(current.copy(blockStyle = current.blockStyle.copy(color = color)))
148
+ }
149
+
150
+ fun popInlineColor() {
151
+ popBlockStyle()
152
+ }
153
+
154
+ fun requireBlockStyle(): BlockStyle {
155
+ val entry = blockStyleStack.lastOrNull()
156
+ return entry?.blockStyle
157
+ ?: throw IllegalStateException(
158
+ "BlockStyle is null. Inline renderers must be used within a block context.",
159
+ )
160
+ }
161
+
162
+ fun currentBlockStyleOrNull(): BlockStyle? = blockStyleStack.lastOrNull()?.blockStyle
163
+
164
+ fun resetForNewRender() {
165
+ blockStyleStack.clear()
166
+ currentBlockType = BlockType.NONE
167
+ currentHeadingLevel = 0
168
+ blockquoteDepth = 0
169
+ listDepth = 0
170
+ listType = null
171
+ listItemNumber = 0
172
+ listMarkerExtra = 0f
173
+ ancestorMarkerOffset = 0f
174
+ listItemMarkerExtra = 0f
175
+ listItemMarkerWidth = null
176
+ taskItemCount = 0
177
+ accumulatedIndent = 0
178
+ listItemStarts.clear()
179
+ orderedListItemNumbers.clear()
180
+ }
181
+ }
@@ -0,0 +1,243 @@
1
+ package com.renderrichtext.renderer
2
+
3
+ import android.graphics.Paint
4
+ import android.text.SpannableStringBuilder
5
+ import android.text.Spanned
6
+ import android.text.style.LineHeightSpan
7
+ import com.renderrichtext.parser.TiptapASTNode
8
+ import com.renderrichtext.spans.BlockquoteSpan
9
+ import com.renderrichtext.spans.MarginBottomSpan
10
+ import com.renderrichtext.utils.text.span.SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE
11
+ import com.renderrichtext.utils.text.span.SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE_PRIORITY
12
+ import com.renderrichtext.utils.text.span.SPAN_FLAGS_LINE_HEIGHT_PRIORITY
13
+ import com.renderrichtext.utils.text.span.applyLineHeightSkippingImages
14
+ import com.renderrichtext.utils.text.span.applyMarginBottom
15
+ import com.renderrichtext.utils.text.span.applyMarginTop
16
+
17
+ class BlockquoteRenderer(
18
+ private val config: RendererConfig,
19
+ ) : NodeRenderer {
20
+ override fun render(
21
+ node: TiptapASTNode,
22
+ builder: SpannableStringBuilder,
23
+ onLinkPress: ((String) -> Unit)?,
24
+ onLinkLongPress: ((String) -> Unit)?,
25
+ onFactoidPress: ((String) -> Unit)?,
26
+ factory: RendererFactory,
27
+ ) {
28
+ if (builder.isNotEmpty() && builder.last() != '\n') {
29
+ builder.append("\n")
30
+ }
31
+
32
+ val start = builder.length
33
+ val style = config.style.blockquoteStyle
34
+ val context = factory.blockStyleContext
35
+ val depth = context.blockquoteDepth
36
+
37
+ // Track depth to handle nested indentation levels
38
+ context.blockquoteDepth = depth + 1
39
+ context.setBlockquoteStyle(style)
40
+
41
+ try {
42
+ factory.renderChildren(node, builder, onLinkPress, onLinkLongPress, onFactoidPress)
43
+ } finally {
44
+ context.popBlockStyle()
45
+ context.blockquoteDepth = depth
46
+ }
47
+
48
+ if (builder.length == start) return
49
+ // The last child's margin sits on its terminating newline, so the extra
50
+ // descent is part of the last content line and the quote background paints
51
+ // it. That reads as a large gap under the text. Lift it off the box.
52
+ var end = detachTrailingContentMargin(builder, start, depth)
53
+ if (end == start) return
54
+ if (depth == 0 && end == builder.length && builder[end - 1] != '\n') {
55
+ builder.append('\n')
56
+ end = builder.length
57
+ }
58
+ val padding = style.padding.toInt()
59
+
60
+ var contentStart = start
61
+ if (padding > 0) {
62
+ builder.insert(start, "\n")
63
+ factory.shiftDeferredSpans(start, 1)
64
+ builder.setSpan(
65
+ BlockquotePaddingSpacerSpan(padding),
66
+ start,
67
+ start + 1,
68
+ SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
69
+ )
70
+ contentStart = start + 1
71
+ end += 1
72
+ }
73
+
74
+ // Find immediately nested quotes to exclude them from this level's line-height/margins
75
+ val nestedRanges =
76
+ builder
77
+ .getSpans(contentStart, end, BlockquoteSpan::class.java)
78
+ .filter { it.depth == depth + 1 }
79
+ .map { builder.getSpanStart(it) to builder.getSpanEnd(it) }
80
+ .sortedBy { it.first }
81
+
82
+ // The accent bar / background span covers the full box, incl. the top spacer.
83
+ // Top priority draws it first, so inline pill/chip backgrounds paint on top of its fill.
84
+ builder.setSpan(
85
+ BlockquoteSpan(style, depth, factory.context, factory.styleCache),
86
+ start,
87
+ end,
88
+ SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE_PRIORITY,
89
+ )
90
+
91
+ applyLineHeightExcludingNested(builder, nestedRanges, contentStart, end, style.lineHeight)
92
+
93
+ if (padding > 0) {
94
+ builder.setSpan(
95
+ BlockquoteBoundaryPaddingSpan(padding),
96
+ contentStart,
97
+ end,
98
+ SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
99
+ )
100
+ }
101
+
102
+ // Margins are only applied by the outermost (root) quote
103
+ if (depth == 0) {
104
+ applyMarginTop(builder, start, style.marginTop)
105
+ applyMarginBottom(builder, style.marginBottom)
106
+ }
107
+ }
108
+
109
+ /**
110
+ * The last block inside the quote ends with a [MarginBottomSpan] on its
111
+ * terminating newline. That span adds its margin to the content line's descent,
112
+ * and the quote background fills the whole line, so the margin shows up as
113
+ * extra space under the text.
114
+ *
115
+ * A root quote drops that margin and keeps a bare newline, so the quote's own
116
+ * margin (applied after the box) is a separate spacer line outside the
117
+ * background. A nested quote keeps the margin, but on a following spacer line
118
+ * the box does not cover, so the parent still gets a gap before the next sibling.
119
+ *
120
+ * Returns the exclusive end index the quote box should use.
121
+ */
122
+ private fun detachTrailingContentMargin(
123
+ builder: SpannableStringBuilder,
124
+ start: Int,
125
+ depth: Int,
126
+ ): Int {
127
+ val end = builder.length
128
+ if (end <= start || builder[end - 1] != '\n') return end
129
+
130
+ val newline = end - 1
131
+ val marginSpans =
132
+ builder.getSpans(newline, end, MarginBottomSpan::class.java).filter {
133
+ builder.getSpanStart(it) == newline && builder.getSpanEnd(it) == end
134
+ }
135
+ if (marginSpans.isEmpty()) return end
136
+
137
+ val margin = marginSpans.maxOf { it.marginBottom }
138
+ val spacerLine = newline == start || builder[newline - 1] == '\n'
139
+
140
+ if (spacerLine) {
141
+ if (depth == 0) {
142
+ marginSpans.forEach { builder.removeSpan(it) }
143
+ builder.delete(newline, end)
144
+ return newline
145
+ }
146
+ return newline
147
+ }
148
+
149
+ marginSpans.forEach { builder.removeSpan(it) }
150
+ if (depth > 0 && margin > 0f) {
151
+ val spacer = builder.length
152
+ builder.append('\n')
153
+ builder.setSpan(
154
+ MarginBottomSpan(margin),
155
+ spacer,
156
+ builder.length,
157
+ SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
158
+ )
159
+ return end
160
+ }
161
+ return builder.length
162
+ }
163
+
164
+ /**
165
+ * A blockquote's top padding, rendered as a standalone spacer line of exactly
166
+ * [padding] px.
167
+ *
168
+ * Top padding cannot be added by growing the first content line's ascent:
169
+ * StaticLayout reuses one FontMetricsInt across a paragraph's soft-wrapped lines,
170
+ * so the inflated first-line metrics leak into the wrapped continuation line, where
171
+ * the line-height clamp then skews them into overlapping baselines. A spacer sits in
172
+ * its own paragraph, and setting absolute metrics keeps it fixed regardless of that
173
+ * reuse.
174
+ */
175
+ private class BlockquotePaddingSpacerSpan(
176
+ private val padding: Int,
177
+ ) : LineHeightSpan {
178
+ override fun chooseHeight(
179
+ text: CharSequence,
180
+ startLine: Int,
181
+ endLine: Int,
182
+ spanstartv: Int,
183
+ v: Int,
184
+ fm: Paint.FontMetricsInt,
185
+ ) {
186
+ fm.top = 0
187
+ fm.ascent = 0
188
+ fm.descent = padding
189
+ fm.bottom = padding
190
+ }
191
+ }
192
+
193
+ /**
194
+ * A blockquote's bottom padding, grown onto the last content line's descent (safe
195
+ * because no later line inherits its metrics; top padding uses
196
+ * [BlockquotePaddingSpacerSpan]).
197
+ *
198
+ * The span range can include trailing '\n'(s) that form no visible line, so the last
199
+ * drawn line ends before getSpanEnd; the comparison uses the visible content end.
200
+ */
201
+ private class BlockquoteBoundaryPaddingSpan(
202
+ private val padding: Int,
203
+ ) : LineHeightSpan {
204
+ override fun chooseHeight(
205
+ text: CharSequence,
206
+ startLine: Int,
207
+ endLine: Int,
208
+ spanstartv: Int,
209
+ v: Int,
210
+ fm: Paint.FontMetricsInt,
211
+ ) {
212
+ if (text !is Spanned) return
213
+
214
+ var contentEnd = text.getSpanEnd(this)
215
+ while (contentEnd > 0 && text[contentEnd - 1] == '\n') {
216
+ contentEnd--
217
+ }
218
+ if (endLine >= contentEnd) {
219
+ fm.descent += padding
220
+ fm.bottom += padding
221
+ }
222
+ }
223
+ }
224
+
225
+ private fun applyLineHeightExcludingNested(
226
+ builder: SpannableStringBuilder,
227
+ nestedRanges: List<Pair<Int, Int>>,
228
+ start: Int,
229
+ end: Int,
230
+ lineHeight: Float,
231
+ ) {
232
+ var currentPos = start
233
+ for ((nestedStart, nestedEnd) in nestedRanges) {
234
+ if (currentPos < nestedStart) {
235
+ applyLineHeightSkippingImages(builder, currentPos, nestedStart, lineHeight, SPAN_FLAGS_LINE_HEIGHT_PRIORITY)
236
+ }
237
+ currentPos = nestedEnd
238
+ }
239
+ if (currentPos < end) {
240
+ applyLineHeightSkippingImages(builder, currentPos, end, lineHeight, SPAN_FLAGS_LINE_HEIGHT_PRIORITY)
241
+ }
242
+ }
243
+ }
@@ -0,0 +1,56 @@
1
+ package com.renderrichtext.renderer
2
+
3
+ import android.text.SpannableStringBuilder
4
+ import com.renderrichtext.parser.TiptapASTNode
5
+ import com.renderrichtext.styles.BlockquoteStyle
6
+ import com.renderrichtext.utils.text.span.SPAN_FLAGS_LINE_HEIGHT_PRIORITY
7
+ import com.renderrichtext.utils.text.span.applyLineHeightSkippingImages
8
+
9
+ /**
10
+ * Renders a GFM blockquote's own prose content - the nodes left after nested
11
+ * quotes, code blocks and other block segments have been split out - into a
12
+ * standalone buffer styled as blockquote text.
13
+ *
14
+ * It decorates a generic [Renderer.renderContent] pass rather than owning the
15
+ * render envelope itself: [push] enters the blockquote block style so text picks
16
+ * up the quote's font/color while still emitting block margins between children,
17
+ * matching the commonmark BlockquoteRenderer; [postProcess] applies the quote's
18
+ * line height once the builder is complete. It draws no border/background/padding
19
+ * - the BlockquoteContainerView draws the box.
20
+ */
21
+ class BlockquoteTextRenderer(
22
+ private val style: BlockquoteStyle,
23
+ ) {
24
+ fun render(
25
+ renderer: Renderer,
26
+ nodes: List<TiptapASTNode>,
27
+ onLinkPress: ((String) -> Unit)?,
28
+ onLinkLongPress: ((String) -> Unit)?,
29
+ onFactoidPress: ((String) -> Unit)?,
30
+ ): SpannableStringBuilder = renderer.renderContent(nodes, onLinkPress, onLinkLongPress, onFactoidPress, block = this)
31
+
32
+ fun push(context: BlockStyleContext) {
33
+ context.blockquoteDepth += 1
34
+ context.setBlockquoteStyle(style)
35
+ }
36
+
37
+ fun pop(context: BlockStyleContext) {
38
+ context.popBlockStyle()
39
+ context.blockquoteDepth -= 1
40
+ }
41
+
42
+ fun postProcess(builder: SpannableStringBuilder) {
43
+ if (builder.isNotEmpty()) {
44
+ // Priority flag so this block-wide line height iterates before the per-block
45
+ // MarginBottomSpans, which then add their gap on top instead of being
46
+ // normalized away (see SPAN_FLAGS_LINE_HEIGHT_PRIORITY).
47
+ applyLineHeightSkippingImages(
48
+ builder,
49
+ 0,
50
+ builder.length,
51
+ style.lineHeight,
52
+ SPAN_FLAGS_LINE_HEIGHT_PRIORITY,
53
+ )
54
+ }
55
+ }
56
+ }
@@ -0,0 +1,135 @@
1
+ package com.renderrichtext.renderer
2
+
3
+ import android.graphics.Paint
4
+ import android.text.SpannableStringBuilder
5
+ import android.text.Spanned
6
+ import android.text.style.LineHeightSpan
7
+ import com.renderrichtext.parser.TiptapASTNode
8
+ import com.renderrichtext.spans.CodeBlockSpan
9
+ import com.renderrichtext.spans.MarginBottomSpan
10
+ import com.renderrichtext.spans.isLastDrawnLine
11
+ import com.renderrichtext.utils.common.CodeBlockHighlighter
12
+ import com.renderrichtext.utils.common.CodeBlockNode
13
+ import com.renderrichtext.utils.text.span.SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE
14
+ import com.renderrichtext.utils.text.span.applyMarginTop
15
+
16
+ class CodeBlockRenderer(
17
+ private val config: RendererConfig,
18
+ ) : NodeRenderer {
19
+ override fun render(
20
+ node: TiptapASTNode,
21
+ builder: SpannableStringBuilder,
22
+ onLinkPress: ((String) -> Unit)?,
23
+ onLinkLongPress: ((String) -> Unit)?,
24
+ onFactoidPress: ((String) -> Unit)?,
25
+ factory: RendererFactory,
26
+ ) {
27
+ if (builder.isNotEmpty() && builder.last() != '\n') {
28
+ builder.append("\n")
29
+ }
30
+
31
+ val start = builder.length
32
+ val style = config.style.codeBlockStyle
33
+ val context = factory.blockStyleContext
34
+
35
+ applyMarginTop(builder, start, style.marginTop)
36
+
37
+ // Content starts after the potential 1-character marginTop spacer
38
+ val contentStart = start + (if (style.marginTop > 0) 1 else 0)
39
+
40
+ context.setCodeBlockStyle(style)
41
+
42
+ try {
43
+ factory.renderChildren(node, builder, onLinkPress, onLinkLongPress, onFactoidPress)
44
+ } finally {
45
+ context.popBlockStyle()
46
+ }
47
+
48
+ if (builder.length == contentStart) return
49
+
50
+ CodeBlockHighlighter.highlight(
51
+ builder,
52
+ CodeBlockNode.extractCode(node),
53
+ CodeBlockNode.language(node),
54
+ style,
55
+ contentStart,
56
+ )
57
+
58
+ // Terminate the content so the margin newline below is its own line. Sharing
59
+ // the last code line makes that line's descent grow by marginBottom, and the
60
+ // background paints the whole line — the bottom edge is then the margin, and
61
+ // it is not recognized as the last line, so the bottom corners stay square.
62
+ if (builder.last() != '\n') {
63
+ builder.append('\n')
64
+ }
65
+
66
+ val end = builder.length
67
+ val padding = style.padding.toInt()
68
+
69
+ // Apply background, borders, and horizontal padding to content only
70
+ builder.setSpan(
71
+ CodeBlockSpan(
72
+ style,
73
+ factory.context,
74
+ factory.styleCache,
75
+ context.accumulatedIndent,
76
+ CodeBlockNode.extractCode(node),
77
+ CodeBlockNode.language(node) ?: "",
78
+ ),
79
+ contentStart,
80
+ end,
81
+ SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
82
+ )
83
+
84
+ // Apply vertical padding via line height manipulation
85
+ builder.setSpan(
86
+ CodeBlockBoundaryPaddingSpan(padding),
87
+ contentStart,
88
+ end,
89
+ SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
90
+ )
91
+
92
+ val marginStart = builder.length
93
+ builder.append("\n")
94
+ builder.setSpan(
95
+ MarginBottomSpan(style.marginBottom),
96
+ marginStart,
97
+ builder.length,
98
+ SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
99
+ )
100
+ }
101
+
102
+ /**
103
+ * Internal span to handle top/bottom padding by modifying font metrics.
104
+ */
105
+ private class CodeBlockBoundaryPaddingSpan(
106
+ private val padding: Int,
107
+ ) : LineHeightSpan {
108
+ override fun chooseHeight(
109
+ text: CharSequence,
110
+ startLine: Int,
111
+ endLine: Int,
112
+ spanstartv: Int,
113
+ v: Int,
114
+ fm: Paint.FontMetricsInt,
115
+ ) {
116
+ if (text !is Spanned) return
117
+
118
+ val spanStart = text.getSpanStart(this)
119
+ val spanEnd = text.getSpanEnd(this)
120
+
121
+ // Adjust ascent/top for the first line to create internal top padding
122
+ if (startLine == spanStart) {
123
+ fm.ascent -= padding
124
+ fm.top -= padding
125
+ }
126
+
127
+ // Same last-line test as CodeBlockSpan, so the bottom padding lands on the
128
+ // line that draws the bottom corners.
129
+ if (isLastDrawnLine(text, endLine, spanEnd)) {
130
+ fm.descent += padding
131
+ fm.bottom += padding
132
+ }
133
+ }
134
+ }
135
+ }
@@ -0,0 +1,37 @@
1
+ package com.renderrichtext.renderer
2
+
3
+ import android.text.SpannableStringBuilder
4
+ import com.renderrichtext.parser.TiptapASTNode
5
+ import com.renderrichtext.spans.CodeBackgroundSpan
6
+ import com.renderrichtext.spans.CodeSpan
7
+ import com.renderrichtext.utils.text.span.SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE
8
+
9
+ class CodeRenderer(
10
+ private val config: RendererConfig,
11
+ ) : NodeRenderer {
12
+ override fun render(
13
+ node: TiptapASTNode,
14
+ builder: SpannableStringBuilder,
15
+ onLinkPress: ((String) -> Unit)?,
16
+ onLinkLongPress: ((String) -> Unit)?,
17
+ onFactoidPress: ((String) -> Unit)?,
18
+ factory: RendererFactory,
19
+ ) {
20
+ if (node.children.isEmpty() || node.children.all { it.content.isEmpty() }) return
21
+
22
+ factory.renderWithSpan(builder, { node.children.forEach { builder.append(it.content) } }) { start, end, blockStyle ->
23
+ builder.setSpan(
24
+ CodeSpan(factory.styleCache, blockStyle),
25
+ start,
26
+ end,
27
+ SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
28
+ )
29
+ builder.setSpan(
30
+ CodeBackgroundSpan(config.style),
31
+ start,
32
+ end,
33
+ SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
34
+ )
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,28 @@
1
+ package com.renderrichtext.renderer
2
+
3
+ import android.text.SpannableStringBuilder
4
+ import com.renderrichtext.parser.TiptapASTNode
5
+ import com.renderrichtext.spans.EmphasisSpan
6
+ import com.renderrichtext.utils.text.span.SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE
7
+
8
+ class EmphasisRenderer(
9
+ private val config: RendererConfig,
10
+ ) : NodeRenderer {
11
+ override fun render(
12
+ node: TiptapASTNode,
13
+ builder: SpannableStringBuilder,
14
+ onLinkPress: ((String) -> Unit)?,
15
+ onLinkLongPress: ((String) -> Unit)?,
16
+ onFactoidPress: ((String) -> Unit)?,
17
+ factory: RendererFactory,
18
+ ) {
19
+ factory.renderWithSpan(builder, { factory.renderChildren(node, builder, onLinkPress, onLinkLongPress, onFactoidPress) }) { start, end, blockStyle ->
20
+ builder.setSpan(
21
+ EmphasisSpan(factory.styleCache, blockStyle),
22
+ start,
23
+ end,
24
+ SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE,
25
+ )
26
+ }
27
+ }
28
+ }