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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (358) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +140 -3
  3. package/ReactNativeRenderRichText.podspec +23 -0
  4. package/android/build.gradle +86 -0
  5. package/android/consumer-rules.pro +3 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/cpp/jni-adapter.cpp +191 -0
  8. package/android/src/main/java/com/renderrichtext/EnrichedTiptapText.kt +673 -0
  9. package/android/src/main/java/com/renderrichtext/EnrichedTiptapTextLayoutManager.kt +24 -0
  10. package/android/src/main/java/com/renderrichtext/EnrichedTiptapTextManager.kt +405 -0
  11. package/android/src/main/java/com/renderrichtext/EnrichedTiptapTextPackage.kt +13 -0
  12. package/android/src/main/java/com/renderrichtext/MeasurementStore.kt +644 -0
  13. package/android/src/main/java/com/renderrichtext/accessibility/AccessibilityLabels.kt +17 -0
  14. package/android/src/main/java/com/renderrichtext/accessibility/AccessibleTiptapTextView.kt +112 -0
  15. package/android/src/main/java/com/renderrichtext/accessibility/TiptapAccessibilityHelper.kt +576 -0
  16. package/android/src/main/java/com/renderrichtext/events/CodeBlockPressEvent.kt +24 -0
  17. package/android/src/main/java/com/renderrichtext/events/ContextMenuItemPressEvent.kt +28 -0
  18. package/android/src/main/java/com/renderrichtext/events/CopyPressEvent.kt +24 -0
  19. package/android/src/main/java/com/renderrichtext/events/FactoidPressEvent.kt +23 -0
  20. package/android/src/main/java/com/renderrichtext/events/ImagePressEvent.kt +25 -0
  21. package/android/src/main/java/com/renderrichtext/events/LatexErrorEvent.kt +29 -0
  22. package/android/src/main/java/com/renderrichtext/events/LinkLongPressEvent.kt +23 -0
  23. package/android/src/main/java/com/renderrichtext/events/LinkPressEvent.kt +23 -0
  24. package/android/src/main/java/com/renderrichtext/events/MentionLongPressEvent.kt +25 -0
  25. package/android/src/main/java/com/renderrichtext/events/MentionPressEvent.kt +25 -0
  26. package/android/src/main/java/com/renderrichtext/events/TaskListItemPressEvent.kt +26 -0
  27. package/android/src/main/java/com/renderrichtext/math/LatexErrorReporter.kt +9 -0
  28. package/android/src/main/java/com/renderrichtext/parser/Parser.kt +59 -0
  29. package/android/src/main/java/com/renderrichtext/parser/TextLinkMatching.kt +35 -0
  30. package/android/src/main/java/com/renderrichtext/parser/TiptapASTNode.kt +69 -0
  31. package/android/src/main/java/com/renderrichtext/renderer/BaselineShiftRenderer.kt +45 -0
  32. package/android/src/main/java/com/renderrichtext/renderer/BlankLineRenderer.kt +39 -0
  33. package/android/src/main/java/com/renderrichtext/renderer/BlockStyleContext.kt +181 -0
  34. package/android/src/main/java/com/renderrichtext/renderer/BlockquoteRenderer.kt +243 -0
  35. package/android/src/main/java/com/renderrichtext/renderer/BlockquoteTextRenderer.kt +56 -0
  36. package/android/src/main/java/com/renderrichtext/renderer/CodeBlockRenderer.kt +135 -0
  37. package/android/src/main/java/com/renderrichtext/renderer/CodeRenderer.kt +37 -0
  38. package/android/src/main/java/com/renderrichtext/renderer/EmphasisRenderer.kt +28 -0
  39. package/android/src/main/java/com/renderrichtext/renderer/FactoidRenderer.kt +97 -0
  40. package/android/src/main/java/com/renderrichtext/renderer/HeadingRenderer.kt +81 -0
  41. package/android/src/main/java/com/renderrichtext/renderer/HighlightRenderer.kt +26 -0
  42. package/android/src/main/java/com/renderrichtext/renderer/LineBreakRenderer.kt +17 -0
  43. package/android/src/main/java/com/renderrichtext/renderer/LinkRenderer.kt +90 -0
  44. package/android/src/main/java/com/renderrichtext/renderer/ListContextManager.kt +109 -0
  45. package/android/src/main/java/com/renderrichtext/renderer/ListItemRenderer.kt +211 -0
  46. package/android/src/main/java/com/renderrichtext/renderer/ListRenderer.kt +133 -0
  47. package/android/src/main/java/com/renderrichtext/renderer/MentionRenderer.kt +85 -0
  48. package/android/src/main/java/com/renderrichtext/renderer/NodeRenderer.kt +207 -0
  49. package/android/src/main/java/com/renderrichtext/renderer/ParagraphRenderer.kt +91 -0
  50. package/android/src/main/java/com/renderrichtext/renderer/Renderer.kt +148 -0
  51. package/android/src/main/java/com/renderrichtext/renderer/SoftBreakRenderer.kt +17 -0
  52. package/android/src/main/java/com/renderrichtext/renderer/SpanStyleCache.kt +143 -0
  53. package/android/src/main/java/com/renderrichtext/renderer/StrikethroughRenderer.kt +28 -0
  54. package/android/src/main/java/com/renderrichtext/renderer/StrongRenderer.kt +28 -0
  55. package/android/src/main/java/com/renderrichtext/renderer/TextRenderer.kt +31 -0
  56. package/android/src/main/java/com/renderrichtext/renderer/ThematicBreakRenderer.kt +46 -0
  57. package/android/src/main/java/com/renderrichtext/renderer/UnderlineRenderer.kt +28 -0
  58. package/android/src/main/java/com/renderrichtext/spans/BaseListSpan.kt +164 -0
  59. package/android/src/main/java/com/renderrichtext/spans/BaselineShiftSpan.kt +27 -0
  60. package/android/src/main/java/com/renderrichtext/spans/BlockquoteSpan.kt +302 -0
  61. package/android/src/main/java/com/renderrichtext/spans/CodeBackgroundSpan.kt +205 -0
  62. package/android/src/main/java/com/renderrichtext/spans/CodeBlockSpan.kt +216 -0
  63. package/android/src/main/java/com/renderrichtext/spans/CodeSpan.kt +32 -0
  64. package/android/src/main/java/com/renderrichtext/spans/EmphasisSpan.kt +42 -0
  65. package/android/src/main/java/com/renderrichtext/spans/FactoidBackgroundSpan.kt +265 -0
  66. package/android/src/main/java/com/renderrichtext/spans/FactoidPaddingSpan.kt +258 -0
  67. package/android/src/main/java/com/renderrichtext/spans/FactoidSpan.kt +32 -0
  68. package/android/src/main/java/com/renderrichtext/spans/FadeInSpan.kt +29 -0
  69. package/android/src/main/java/com/renderrichtext/spans/HeadingSpan.kt +38 -0
  70. package/android/src/main/java/com/renderrichtext/spans/HighlightSpan.kt +80 -0
  71. package/android/src/main/java/com/renderrichtext/spans/ImageSpan.kt +481 -0
  72. package/android/src/main/java/com/renderrichtext/spans/InlineBackgroundGeometry.kt +42 -0
  73. package/android/src/main/java/com/renderrichtext/spans/LineHeightSpan.kt +39 -0
  74. package/android/src/main/java/com/renderrichtext/spans/LinkPillIconCache.kt +154 -0
  75. package/android/src/main/java/com/renderrichtext/spans/LinkPillSpan.kt +381 -0
  76. package/android/src/main/java/com/renderrichtext/spans/LinkSpan.kt +68 -0
  77. package/android/src/main/java/com/renderrichtext/spans/ListItemSpacingSpan.kt +33 -0
  78. package/android/src/main/java/com/renderrichtext/spans/ListMarkerAnchorSpan.kt +38 -0
  79. package/android/src/main/java/com/renderrichtext/spans/MarginBottomSpan.kt +76 -0
  80. package/android/src/main/java/com/renderrichtext/spans/MentionChipSpan.kt +132 -0
  81. package/android/src/main/java/com/renderrichtext/spans/MentionSpan.kt +46 -0
  82. package/android/src/main/java/com/renderrichtext/spans/OrderedListSpan.kt +127 -0
  83. package/android/src/main/java/com/renderrichtext/spans/SpoilerSpan.kt +33 -0
  84. package/android/src/main/java/com/renderrichtext/spans/StrikethroughSpan.kt +12 -0
  85. package/android/src/main/java/com/renderrichtext/spans/StrongSpan.kt +39 -0
  86. package/android/src/main/java/com/renderrichtext/spans/TaskListSpan.kt +143 -0
  87. package/android/src/main/java/com/renderrichtext/spans/TextSpan.kt +26 -0
  88. package/android/src/main/java/com/renderrichtext/spans/ThematicBreakSpan.kt +69 -0
  89. package/android/src/main/java/com/renderrichtext/spans/UnorderedListSpan.kt +96 -0
  90. package/android/src/main/java/com/renderrichtext/spoiler/SpoilerStubs.kt +46 -0
  91. package/android/src/main/java/com/renderrichtext/styles/BaseBlockStyle.kt +11 -0
  92. package/android/src/main/java/com/renderrichtext/styles/BlockquoteStyle.kt +83 -0
  93. package/android/src/main/java/com/renderrichtext/styles/CodeBlockStyle.kt +80 -0
  94. package/android/src/main/java/com/renderrichtext/styles/CodeStyle.kt +26 -0
  95. package/android/src/main/java/com/renderrichtext/styles/EmphasisStyle.kt +21 -0
  96. package/android/src/main/java/com/renderrichtext/styles/FactoidStyle.kt +21 -0
  97. package/android/src/main/java/com/renderrichtext/styles/HeadingStyle.kt +33 -0
  98. package/android/src/main/java/com/renderrichtext/styles/HighlightStyle.kt +19 -0
  99. package/android/src/main/java/com/renderrichtext/styles/ImageStyle.kt +29 -0
  100. package/android/src/main/java/com/renderrichtext/styles/InlineImageStyle.kt +17 -0
  101. package/android/src/main/java/com/renderrichtext/styles/InlineMathStyle.kt +17 -0
  102. package/android/src/main/java/com/renderrichtext/styles/LinkPillContent.kt +36 -0
  103. package/android/src/main/java/com/renderrichtext/styles/LinkPillStyle.kt +44 -0
  104. package/android/src/main/java/com/renderrichtext/styles/LinkStyle.kt +23 -0
  105. package/android/src/main/java/com/renderrichtext/styles/LinkVariantEntry.kt +34 -0
  106. package/android/src/main/java/com/renderrichtext/styles/ListStyle.kt +65 -0
  107. package/android/src/main/java/com/renderrichtext/styles/MathStyle.kt +29 -0
  108. package/android/src/main/java/com/renderrichtext/styles/MentionStyle.kt +19 -0
  109. package/android/src/main/java/com/renderrichtext/styles/ParagraphStyle.kt +33 -0
  110. package/android/src/main/java/com/renderrichtext/styles/SpoilerStyle.kt +27 -0
  111. package/android/src/main/java/com/renderrichtext/styles/StrikethroughStyle.kt +17 -0
  112. package/android/src/main/java/com/renderrichtext/styles/StrongStyle.kt +21 -0
  113. package/android/src/main/java/com/renderrichtext/styles/StyleConfig.kt +411 -0
  114. package/android/src/main/java/com/renderrichtext/styles/StyleParser.kt +92 -0
  115. package/android/src/main/java/com/renderrichtext/styles/SubscriptStyle.kt +16 -0
  116. package/android/src/main/java/com/renderrichtext/styles/SuperscriptStyle.kt +16 -0
  117. package/android/src/main/java/com/renderrichtext/styles/TableStyle.kt +75 -0
  118. package/android/src/main/java/com/renderrichtext/styles/TaskListStyle.kt +29 -0
  119. package/android/src/main/java/com/renderrichtext/styles/TextAlignment.kt +32 -0
  120. package/android/src/main/java/com/renderrichtext/styles/ThematicBreakStyle.kt +23 -0
  121. package/android/src/main/java/com/renderrichtext/styles/UnderlineStyle.kt +17 -0
  122. package/android/src/main/java/com/renderrichtext/styles/VideoStyle.kt +31 -0
  123. package/android/src/main/java/com/renderrichtext/utils/common/BorderStyleUtils.kt +86 -0
  124. package/android/src/main/java/com/renderrichtext/utils/common/BreakStrategyUtils.kt +32 -0
  125. package/android/src/main/java/com/renderrichtext/utils/common/CodeBlockHighlighter.kt +36 -0
  126. package/android/src/main/java/com/renderrichtext/utils/common/CodeBlockNode.kt +42 -0
  127. package/android/src/main/java/com/renderrichtext/utils/common/EllipsizeUtils.kt +27 -0
  128. package/android/src/main/java/com/renderrichtext/utils/common/EnrichedTiptapAncestorUtils.kt +10 -0
  129. package/android/src/main/java/com/renderrichtext/utils/common/FeatureFlags.kt +9 -0
  130. package/android/src/main/java/com/renderrichtext/utils/common/LinkRecognitionProps.kt +31 -0
  131. package/android/src/main/java/com/renderrichtext/utils/common/LinkRegexConfig.kt +56 -0
  132. package/android/src/main/java/com/renderrichtext/utils/common/MotionPreferences.kt +18 -0
  133. package/android/src/main/java/com/renderrichtext/utils/common/ReadableMapExtensions.kt +28 -0
  134. package/android/src/main/java/com/renderrichtext/utils/common/TiptapViewManagerUtils.kt +242 -0
  135. package/android/src/main/java/com/renderrichtext/utils/common/layout/RTLUtils.kt +6 -0
  136. package/android/src/main/java/com/renderrichtext/utils/common/serialization/TiptapASTSerializer.kt +368 -0
  137. package/android/src/main/java/com/renderrichtext/utils/text/ImageCache.kt +88 -0
  138. package/android/src/main/java/com/renderrichtext/utils/text/ImageDownloader.kt +203 -0
  139. package/android/src/main/java/com/renderrichtext/utils/text/LocalImageLoader.kt +167 -0
  140. package/android/src/main/java/com/renderrichtext/utils/text/TailFadeInAnimator.kt +84 -0
  141. package/android/src/main/java/com/renderrichtext/utils/text/conversion/HTMLGenerator.kt +1105 -0
  142. package/android/src/main/java/com/renderrichtext/utils/text/conversion/TiptapExtractor.kt +423 -0
  143. package/android/src/main/java/com/renderrichtext/utils/text/extensions/ParagraphUtils.kt +9 -0
  144. package/android/src/main/java/com/renderrichtext/utils/text/extensions/SpannableExtensions.kt +9 -0
  145. package/android/src/main/java/com/renderrichtext/utils/text/extensions/TextPaintExtensions.kt +76 -0
  146. package/android/src/main/java/com/renderrichtext/utils/text/interaction/CheckboxTouchHelper.kt +61 -0
  147. package/android/src/main/java/com/renderrichtext/utils/text/interaction/TaskListTapUtils.kt +286 -0
  148. package/android/src/main/java/com/renderrichtext/utils/text/span/ApplyLineHeight.kt +39 -0
  149. package/android/src/main/java/com/renderrichtext/utils/text/span/BlockSpacing.kt +142 -0
  150. package/android/src/main/java/com/renderrichtext/utils/text/span/SpanFlags.kt +43 -0
  151. package/android/src/main/java/com/renderrichtext/utils/text/span/WidthAwareSpans.kt +30 -0
  152. package/android/src/main/java/com/renderrichtext/utils/text/view/CodeBlockPressHost.kt +15 -0
  153. package/android/src/main/java/com/renderrichtext/utils/text/view/ImagePressHost.kt +19 -0
  154. package/android/src/main/java/com/renderrichtext/utils/text/view/LinkEvents.kt +88 -0
  155. package/android/src/main/java/com/renderrichtext/utils/text/view/LinkLongPressMovementMethod.kt +449 -0
  156. package/android/src/main/java/com/renderrichtext/utils/text/view/SelectionActionMode.kt +235 -0
  157. package/android/src/main/java/com/renderrichtext/utils/text/view/TextSelectionColors.kt +48 -0
  158. package/android/src/main/java/com/renderrichtext/utils/text/view/TextViewSetup.kt +119 -0
  159. package/android/src/main/java/com/renderrichtext/views/ContextMenuPopup.kt +217 -0
  160. package/android/src/main/java/com/renderrichtext/views/CopyGlyph.kt +101 -0
  161. package/android/src/main/java/com/renderrichtext/views/WrapGlyph.kt +40 -0
  162. package/android/src/main/jni/CMakeLists.txt +52 -0
  163. package/android/src/main/jni/react/renderer/components/RichTextSpec/ComponentDescriptors.h +30 -0
  164. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextComponentDescriptor.h +29 -0
  165. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextMeasurementManager.cpp +45 -0
  166. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextMeasurementManager.h +21 -0
  167. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextShadowNode.cpp +38 -0
  168. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextShadowNode.h +53 -0
  169. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextState.cpp +9 -0
  170. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextState.h +24 -0
  171. package/android/src/main/jni/react/renderer/components/RichTextSpec/conversions.h +40 -0
  172. package/cpp/parser/TiptapASTNode.hpp +68 -0
  173. package/cpp/parser/TiptapParser.cpp +233 -0
  174. package/cpp/parser/TiptapParser.hpp +13 -0
  175. package/cpp/vendor/nlohmann/json.hpp +24765 -0
  176. package/ios/EnrichedTiptapText.h +27 -0
  177. package/ios/EnrichedTiptapText.mm +1222 -0
  178. package/ios/attachments/ENRMImageAttachment.h +51 -0
  179. package/ios/attachments/ENRMImageAttachment.m +398 -0
  180. package/ios/attachments/ENRMLinkPillAttachment.h +47 -0
  181. package/ios/attachments/ENRMLinkPillAttachment.m +324 -0
  182. package/ios/attachments/ENRMLinkPillIconCache.h +28 -0
  183. package/ios/attachments/ENRMLinkPillIconCache.m +181 -0
  184. package/ios/attachments/ENRMLinkPillText.h +27 -0
  185. package/ios/attachments/ENRMLinkPillText.m +118 -0
  186. package/ios/attachments/ENRMMathInlineAttachment.h +7 -0
  187. package/ios/attachments/ENRMMathInlineAttachment.m +4 -0
  188. package/ios/attachments/ThematicBreakAttachment.h +15 -0
  189. package/ios/attachments/ThematicBreakAttachment.m +33 -0
  190. package/ios/internals/ENRMViewFreeMeasurement.h +208 -0
  191. package/ios/internals/EnrichedTiptapTextComponentDescriptor.h +19 -0
  192. package/ios/internals/EnrichedTiptapTextShadowNode.h +43 -0
  193. package/ios/internals/EnrichedTiptapTextShadowNode.mm +69 -0
  194. package/ios/internals/EnrichedTiptapTextState.h +24 -0
  195. package/ios/internals/MeasurementCache.h +308 -0
  196. package/ios/internals/ShadowMeasurementUtils.h +145 -0
  197. package/ios/parser/ENRMTextLinkAttributes.h +7 -0
  198. package/ios/parser/ENRMTiptapParser.h +33 -0
  199. package/ios/parser/ENRMTiptapParser.mm +73 -0
  200. package/ios/parser/TiptapASTNode.h +57 -0
  201. package/ios/parser/TiptapASTNode.m +52 -0
  202. package/ios/parser/TiptapParserBridge.mm +179 -0
  203. package/ios/renderer/AttributedRenderer.h +23 -0
  204. package/ios/renderer/AttributedRenderer.m +229 -0
  205. package/ios/renderer/BaseRenderer.h +33 -0
  206. package/ios/renderer/BaseRenderer.m +46 -0
  207. package/ios/renderer/BaselineShiftTextAttributes.h +10 -0
  208. package/ios/renderer/BaselineShiftTextAttributes.m +26 -0
  209. package/ios/renderer/BlankLineRenderer.h +4 -0
  210. package/ios/renderer/BlankLineRenderer.m +51 -0
  211. package/ios/renderer/BlockquoteRenderer.h +6 -0
  212. package/ios/renderer/BlockquoteRenderer.m +258 -0
  213. package/ios/renderer/CodeBlockRenderer.h +9 -0
  214. package/ios/renderer/CodeBlockRenderer.m +99 -0
  215. package/ios/renderer/CodeRenderer.h +9 -0
  216. package/ios/renderer/CodeRenderer.m +69 -0
  217. package/ios/renderer/ENRMBlockquoteTextRenderer.h +25 -0
  218. package/ios/renderer/ENRMBlockquoteTextRenderer.m +48 -0
  219. package/ios/renderer/EmphasisRenderer.h +5 -0
  220. package/ios/renderer/EmphasisRenderer.m +100 -0
  221. package/ios/renderer/FactoidRenderer.h +9 -0
  222. package/ios/renderer/FactoidRenderer.m +130 -0
  223. package/ios/renderer/HeadingRenderer.h +6 -0
  224. package/ios/renderer/HeadingRenderer.m +103 -0
  225. package/ios/renderer/HighlightRenderer.h +7 -0
  226. package/ios/renderer/HighlightRenderer.m +33 -0
  227. package/ios/renderer/LinkRenderer.h +6 -0
  228. package/ios/renderer/LinkRenderer.m +158 -0
  229. package/ios/renderer/ListItemRenderer.h +24 -0
  230. package/ios/renderer/ListItemRenderer.m +283 -0
  231. package/ios/renderer/ListRenderer.h +13 -0
  232. package/ios/renderer/ListRenderer.m +126 -0
  233. package/ios/renderer/MentionRenderer.h +9 -0
  234. package/ios/renderer/MentionRenderer.m +96 -0
  235. package/ios/renderer/NodeRenderer.h +8 -0
  236. package/ios/renderer/ParagraphRenderer.h +6 -0
  237. package/ios/renderer/ParagraphRenderer.m +85 -0
  238. package/ios/renderer/RenderContext.h +145 -0
  239. package/ios/renderer/RenderContext.m +403 -0
  240. package/ios/renderer/RendererFactory.h +12 -0
  241. package/ios/renderer/RendererFactory.m +158 -0
  242. package/ios/renderer/StrikethroughRenderer.h +5 -0
  243. package/ios/renderer/StrikethroughRenderer.m +30 -0
  244. package/ios/renderer/StrongRenderer.h +5 -0
  245. package/ios/renderer/StrongRenderer.m +88 -0
  246. package/ios/renderer/TextRenderer.h +6 -0
  247. package/ios/renderer/TextRenderer.m +18 -0
  248. package/ios/renderer/ThematicBreakRenderer.h +4 -0
  249. package/ios/renderer/ThematicBreakRenderer.m +42 -0
  250. package/ios/renderer/UnderlineRenderer.h +4 -0
  251. package/ios/renderer/UnderlineRenderer.m +41 -0
  252. package/ios/styles/ENRMFontSlot.h +12 -0
  253. package/ios/styles/ENRMFontSlot.m +24 -0
  254. package/ios/styles/StyleConfig.h +488 -0
  255. package/ios/styles/StyleConfig.mm +2820 -0
  256. package/ios/utils/AccessibilityInfo.h +35 -0
  257. package/ios/utils/AccessibilityInfo.m +24 -0
  258. package/ios/utils/BlockquoteBorder.h +26 -0
  259. package/ios/utils/BlockquoteBorder.m +294 -0
  260. package/ios/utils/CodeBackground.h +19 -0
  261. package/ios/utils/CodeBackground.m +197 -0
  262. package/ios/utils/CodeBlockBackground.h +17 -0
  263. package/ios/utils/CodeBlockBackground.m +103 -0
  264. package/ios/utils/ContextMenuUtils.h +76 -0
  265. package/ios/utils/ContextMenuUtils.mm +75 -0
  266. package/ios/utils/ENRMAccessibilityLabels.h +40 -0
  267. package/ios/utils/ENRMAccessibilityLabels.m +5 -0
  268. package/ios/utils/ENRMAsyncRenderCoordinator.h +24 -0
  269. package/ios/utils/ENRMAsyncRenderCoordinator.m +37 -0
  270. package/ios/utils/ENRMAtomicSize.h +65 -0
  271. package/ios/utils/ENRMCodeBlockContent.h +37 -0
  272. package/ios/utils/ENRMCodeBlockContent.mm +89 -0
  273. package/ios/utils/ENRMFeatureFlags.h +25 -0
  274. package/ios/utils/ENRMImageDownloader.h +30 -0
  275. package/ios/utils/ENRMImageDownloader.m +168 -0
  276. package/ios/utils/ENRMLatexErrorCoordinator.h +27 -0
  277. package/ios/utils/ENRMLatexErrorCoordinator.mm +75 -0
  278. package/ios/utils/ENRMLatexErrorReporting.h +13 -0
  279. package/ios/utils/ENRMLinkContextMenus.h +93 -0
  280. package/ios/utils/ENRMLinkContextMenus.m +178 -0
  281. package/ios/utils/ENRMLinkRegexConfig.h +30 -0
  282. package/ios/utils/ENRMLinkRegexConfig.mm +104 -0
  283. package/ios/utils/ENRMLinkRegexProps.h +23 -0
  284. package/ios/utils/ENRMLocalImageLoader.h +35 -0
  285. package/ios/utils/ENRMLocalImageLoader.m +111 -0
  286. package/ios/utils/ENRMMenuAction.h +27 -0
  287. package/ios/utils/ENRMMenuAction.m +33 -0
  288. package/ios/utils/ENRMSpoilerOverlayManager.h +15 -0
  289. package/ios/utils/ENRMSpoilerOverlayManager.m +19 -0
  290. package/ios/utils/ENRMSpoilerTapUtils.h +6 -0
  291. package/ios/utils/ENRMSpoilerTapUtils.m +11 -0
  292. package/ios/utils/ENRMTailFadeInAnimator.h +16 -0
  293. package/ios/utils/ENRMTailFadeInAnimator.m +161 -0
  294. package/ios/utils/ENRMTextHitTest.h +23 -0
  295. package/ios/utils/ENRMTextHitTest.m +20 -0
  296. package/ios/utils/ENRMTextInteractionUtils.h +20 -0
  297. package/ios/utils/ENRMTextInteractionUtils.m +15 -0
  298. package/ios/utils/ENRMTextRenderer.h +38 -0
  299. package/ios/utils/ENRMTextRenderer.m +54 -0
  300. package/ios/utils/ENRMTextViewSetup.h +132 -0
  301. package/ios/utils/ENRMUIKit.h +429 -0
  302. package/ios/utils/EditMenuUtils.h +105 -0
  303. package/ios/utils/EditMenuUtils.m +143 -0
  304. package/ios/utils/FactoidBackground.h +20 -0
  305. package/ios/utils/FactoidBackground.m +161 -0
  306. package/ios/utils/FontScaleObserver.h +10 -0
  307. package/ios/utils/FontScaleObserver.m +55 -0
  308. package/ios/utils/FontUtils.h +31 -0
  309. package/ios/utils/FontUtils.m +63 -0
  310. package/ios/utils/HTMLGenerator.h +25 -0
  311. package/ios/utils/HTMLGenerator.m +1041 -0
  312. package/ios/utils/HeightUpdateUtils.h +25 -0
  313. package/ios/utils/ImageRequestHeaderUtils.h +35 -0
  314. package/ios/utils/LastElementUtils.h +97 -0
  315. package/ios/utils/LinkContextMenuUtils.h +55 -0
  316. package/ios/utils/LinkPillContentUtils.h +46 -0
  317. package/ios/utils/LinkTapUtils.h +56 -0
  318. package/ios/utils/LinkTapUtils.m +139 -0
  319. package/ios/utils/ListMarkerDrawer.h +15 -0
  320. package/ios/utils/ListMarkerDrawer.m +239 -0
  321. package/ios/utils/MentionBackground.h +26 -0
  322. package/ios/utils/MentionBackground.m +86 -0
  323. package/ios/utils/ParagraphStyleUtils.h +87 -0
  324. package/ios/utils/ParagraphStyleUtils.m +484 -0
  325. package/ios/utils/PasteboardUtils.h +48 -0
  326. package/ios/utils/PasteboardUtils.m +166 -0
  327. package/ios/utils/RTFExportUtils.h +24 -0
  328. package/ios/utils/RTFExportUtils.m +299 -0
  329. package/ios/utils/RuntimeKeys.h +44 -0
  330. package/ios/utils/RuntimeKeys.m +13 -0
  331. package/ios/utils/SelectionColorUtils.h +14 -0
  332. package/ios/utils/StylePropsUtils.h +1340 -0
  333. package/ios/utils/TaskListTapUtils.h +6 -0
  334. package/ios/utils/TaskListTapUtils.m +14 -0
  335. package/ios/utils/TextViewLayoutManager.h +14 -0
  336. package/ios/utils/TextViewLayoutManager.mm +198 -0
  337. package/ios/utils/TiptapAccessibilityElementBuilder.h +43 -0
  338. package/ios/utils/TiptapAccessibilityElementBuilder.m +432 -0
  339. package/ios/utils/TiptapExtractor.h +17 -0
  340. package/ios/utils/TiptapExtractor.m +367 -0
  341. package/ios/views/ENRMTiptapTextView.h +25 -0
  342. package/ios/views/ENRMTiptapTextView.m +247 -0
  343. package/package.json +70 -6
  344. package/react-native.config.js +10 -0
  345. package/src/EnrichedTiptapTextNativeComponent.ts +739 -0
  346. package/src/RichText.tsx +164 -0
  347. package/src/admonitionDefaults.ts +58 -0
  348. package/src/darkModeTextStyle.ts +99 -0
  349. package/src/headingDefaults.ts +21 -0
  350. package/src/index.tsx +4 -0
  351. package/src/linkVariantUtils.ts +120 -0
  352. package/src/normalizeTiptapStyle.ts +397 -0
  353. package/src/rn-globals.d.ts +1 -0
  354. package/src/styleUtils.ts +107 -0
  355. package/src/types/TiptapStyle.ts +532 -0
  356. package/src/types/TiptapStyleInternal.ts +299 -0
  357. package/src/types/linkPill.ts +9 -0
  358. package/src/utils/isDev.ts +4 -0
@@ -0,0 +1,423 @@
1
+ package com.renderrichtext.utils.text.conversion
2
+
3
+ import android.text.Spannable
4
+ import android.text.style.UnderlineSpan
5
+ import android.widget.TextView
6
+ import com.renderrichtext.EnrichedTiptapText
7
+ import com.renderrichtext.spans.BaseListSpan
8
+ import com.renderrichtext.spans.BaselineShiftSpan
9
+ import com.renderrichtext.spans.BlockquoteSpan
10
+ import com.renderrichtext.spans.CodeBlockSpan
11
+ import com.renderrichtext.spans.CodeSpan
12
+ import com.renderrichtext.spans.EmphasisSpan
13
+ import com.renderrichtext.spans.FactoidPaddingSpan
14
+ import com.renderrichtext.spans.HeadingSpan
15
+ import com.renderrichtext.spans.HighlightSpan
16
+ import com.renderrichtext.spans.ImageSpan
17
+ import com.renderrichtext.spans.LinkSpan
18
+ import com.renderrichtext.spans.OrderedListSpan
19
+ import com.renderrichtext.spans.StrikethroughSpan
20
+ import com.renderrichtext.spans.StrongSpan
21
+ import com.renderrichtext.spans.TaskListSpan
22
+ import com.renderrichtext.spans.ThematicBreakSpan
23
+ import com.renderrichtext.spans.UnorderedListSpan
24
+
25
+ /** Extracts tiptap from styled text (Spannable). */
26
+ object TiptapExtractor {
27
+ /**
28
+ * Gets tiptap for the current text selection.
29
+ * Full selection returns original tiptap, partial reconstructs from spans.
30
+ */
31
+ fun getTiptapForSelection(textView: TextView): String? {
32
+ val start = textView.selectionStart
33
+ val end = textView.selectionEnd
34
+ if (start < 0 || end < 0 || start >= end) return null
35
+
36
+ val spannable = textView.text as? Spannable ?: return null
37
+
38
+ val isFullSelection = start == 0 && end >= textView.text.length - 1
39
+ if (isFullSelection && textView is EnrichedTiptapText) {
40
+ val original = textView.currentTiptap
41
+ if (original.isNotEmpty()) return original
42
+ }
43
+
44
+ return extractFromSpannable(spannable, start, end)
45
+ }
46
+
47
+ /** Extracts tiptap from a Spannable within a given range. */
48
+ fun extractFromSpannable(
49
+ spannable: Spannable,
50
+ start: Int,
51
+ end: Int,
52
+ ): String {
53
+ val result = StringBuilder()
54
+ val state = ExtractionState()
55
+ val headingAccumulator = HeadingAccumulator()
56
+
57
+ var i = start
58
+ while (i < end) {
59
+ val nextTransition = spannable.nextSpanTransition(i, end, Any::class.java)
60
+ val segmentText = spannable.subSequence(i, nextTransition).toString()
61
+
62
+ val handled =
63
+ processSegment(
64
+ spannable = spannable,
65
+ segmentText = segmentText,
66
+ segmentStart = i,
67
+ segmentEnd = nextTransition,
68
+ result = result,
69
+ state = state,
70
+ headingAccumulator = headingAccumulator,
71
+ )
72
+
73
+ if (!handled) {
74
+ // Regular text segment - apply inline formatting and block prefixes
75
+ appendFormattedSegment(spannable, segmentText, i, nextTransition, result, state)
76
+ }
77
+
78
+ i = nextTransition
79
+ }
80
+
81
+ headingAccumulator.flush(result, state)
82
+ return result.toString()
83
+ }
84
+
85
+ /** Returns true if segment was handled specially. */
86
+ private fun processSegment(
87
+ spannable: Spannable,
88
+ segmentText: String,
89
+ segmentStart: Int,
90
+ segmentEnd: Int,
91
+ result: StringBuilder,
92
+ state: ExtractionState,
93
+ headingAccumulator: HeadingAccumulator,
94
+ ): Boolean {
95
+ // Check for thematic breaks first (uses " \n" as placeholder)
96
+ val thematicBreakSpans = spannable.getSpans(segmentStart, segmentEnd, ThematicBreakSpan::class.java)
97
+ if (thematicBreakSpans.isNotEmpty()) {
98
+ appendThematicBreak(result, state)
99
+ return true
100
+ }
101
+
102
+ if (
103
+ segmentText.length == 1 &&
104
+ segmentText[0] == FactoidPaddingSpan.MARK &&
105
+ spannable.getSpans(segmentStart, segmentEnd, FactoidPaddingSpan::class.java).isNotEmpty()
106
+ ) {
107
+ return true
108
+ }
109
+
110
+ if (segmentText == "\uFFFC" || segmentText == "\u200B") {
111
+ val imageSpans = spannable.getSpans(segmentStart, segmentEnd, ImageSpan::class.java)
112
+ if (imageSpans.isNotEmpty()) {
113
+ appendImage(imageSpans[0], result, state)
114
+ return true
115
+ }
116
+
117
+ val mathLatex = extractMathLatex(spannable, segmentStart, segmentEnd)
118
+ if (mathLatex != null) {
119
+ result.append("$$mathLatex$")
120
+ return true
121
+ }
122
+ }
123
+
124
+ if (segmentText.isEmpty()) return true
125
+
126
+ if (segmentText == "\n" || segmentText == "\n\n") {
127
+ handleNewline(spannable, segmentStart, segmentEnd, result, state)
128
+ return true
129
+ }
130
+
131
+ val headingSpans = spannable.getSpans(segmentStart, segmentEnd, HeadingSpan::class.java)
132
+ if (headingSpans.isNotEmpty()) {
133
+ headingAccumulator.accumulate(headingSpans[0].level, segmentText, result, state)
134
+ return true
135
+ } else {
136
+ headingAccumulator.flush(result, state)
137
+ }
138
+
139
+ val codeBlockSpans = spannable.getSpans(segmentStart, segmentEnd, CodeBlockSpan::class.java)
140
+ if (codeBlockSpans.isNotEmpty()) {
141
+ appendCodeBlock(segmentText, result, state)
142
+ return true
143
+ }
144
+
145
+ return false
146
+ }
147
+
148
+ private fun appendFormattedSegment(
149
+ spannable: Spannable,
150
+ segmentText: String,
151
+ segmentStart: Int,
152
+ segmentEnd: Int,
153
+ result: StringBuilder,
154
+ state: ExtractionState,
155
+ ) {
156
+ val blockquotePrefix = detectBlockquote(spannable, segmentStart, segmentEnd, state)
157
+ val listPrefix = detectList(spannable, segmentStart, segmentEnd, state)
158
+ var segment = applyInlineFormatting(spannable, segmentText, segmentStart, segmentEnd)
159
+
160
+ if (result.isAtLineStart() && !segmentText.startsWith("\n")) {
161
+ segment = buildBlockPrefix(blockquotePrefix, listPrefix) + segment
162
+ }
163
+
164
+ if (state.needsBlankLine && result.isNotEmpty()) {
165
+ result.ensureBlankLine()
166
+ state.needsBlankLine = false
167
+ }
168
+
169
+ result.append(segment)
170
+ }
171
+
172
+ private fun appendImage(
173
+ img: ImageSpan,
174
+ result: StringBuilder,
175
+ state: ExtractionState,
176
+ ) {
177
+ if (img.isInline) {
178
+ result.append("![image](${img.imageUrl})")
179
+ } else {
180
+ result.ensureBlankLine()
181
+ result.append("![image](${img.imageUrl})\n")
182
+ state.needsBlankLine = true
183
+ state.blockquoteDepth = -1
184
+ state.listDepth = -1
185
+ }
186
+ }
187
+
188
+ private fun appendThematicBreak(
189
+ result: StringBuilder,
190
+ state: ExtractionState,
191
+ ) {
192
+ result.ensureBlankLine()
193
+ result.append("---\n")
194
+ state.needsBlankLine = true
195
+ state.blockquoteDepth = -1
196
+ state.listDepth = -1
197
+ }
198
+
199
+ private fun handleNewline(
200
+ spannable: Spannable,
201
+ start: Int,
202
+ end: Int,
203
+ result: StringBuilder,
204
+ state: ExtractionState,
205
+ ) {
206
+ val inBlockquote = spannable.getSpans(start, end, BlockquoteSpan::class.java).isNotEmpty()
207
+ val inList =
208
+ spannable.getSpans(start, end, OrderedListSpan::class.java).isNotEmpty() ||
209
+ spannable.getSpans(start, end, UnorderedListSpan::class.java).isNotEmpty() ||
210
+ spannable.getSpans(start, end, TaskListSpan::class.java).isNotEmpty()
211
+
212
+ when {
213
+ !inBlockquote && state.blockquoteDepth >= 0 -> {
214
+ result.ensureBlankLine()
215
+ state.blockquoteDepth = -1
216
+ }
217
+
218
+ !inList && state.listDepth >= 0 -> {
219
+ result.ensureBlankLine()
220
+ state.listDepth = -1
221
+ }
222
+
223
+ inBlockquote || inList -> {
224
+ if (!result.endsWith("\n")) result.append("\n")
225
+ }
226
+
227
+ else -> {
228
+ result.ensureBlankLine()
229
+ }
230
+ }
231
+ }
232
+
233
+ private fun appendCodeBlock(
234
+ text: String,
235
+ result: StringBuilder,
236
+ state: ExtractionState,
237
+ ) {
238
+ if (state.needsBlankLine) {
239
+ result.ensureBlankLine()
240
+ state.needsBlankLine = false
241
+ }
242
+
243
+ val needsFence = result.isEmpty() || result.endsWith("\n\n")
244
+ if (needsFence) result.append("```\n")
245
+
246
+ result.append(text)
247
+
248
+ if (text.endsWith("\n")) {
249
+ result.append("```\n")
250
+ state.needsBlankLine = true
251
+ }
252
+ }
253
+
254
+ private fun detectBlockquote(
255
+ spannable: Spannable,
256
+ start: Int,
257
+ end: Int,
258
+ state: ExtractionState,
259
+ ): String? {
260
+ val spans = spannable.getSpans(start, end, BlockquoteSpan::class.java)
261
+ val depth = spans.maxOfOrNull { it.depth } ?: -1
262
+
263
+ return if (depth >= 0) {
264
+ state.blockquoteDepth = depth
265
+ "> ".repeat(depth + 1)
266
+ } else {
267
+ if (state.blockquoteDepth >= 0) state.blockquoteDepth = -1
268
+ null
269
+ }
270
+ }
271
+
272
+ private fun detectList(
273
+ spannable: Spannable,
274
+ start: Int,
275
+ end: Int,
276
+ state: ExtractionState,
277
+ ): String? {
278
+ // A list item's span covers its nested children, so ancestors are returned here too. The
279
+ // innermost span is the item this segment actually belongs to.
280
+ val listSpan =
281
+ spannable.getSpans(start, end, BaseListSpan::class.java).maxByOrNull { it.depth }
282
+
283
+ if (listSpan == null) {
284
+ if (state.listDepth >= 0) state.listDepth = -1
285
+ return null
286
+ }
287
+
288
+ state.listDepth = listSpan.depth
289
+ val indent = " ".repeat(listSpan.depth)
290
+
291
+ return when (listSpan) {
292
+ is TaskListSpan -> "$indent- ${if (listSpan.isChecked) "[x]" else "[ ]"} "
293
+ is OrderedListSpan -> "$indent${listSpan.itemNumber}. "
294
+ else -> "$indent- "
295
+ }
296
+ }
297
+
298
+ private fun applyInlineFormatting(
299
+ spannable: Spannable,
300
+ text: String,
301
+ start: Int,
302
+ end: Int,
303
+ ): String {
304
+ val hasStrong = spannable.getSpans(start, end, StrongSpan::class.java).isNotEmpty()
305
+ val hasEmphasis = spannable.getSpans(start, end, EmphasisSpan::class.java).isNotEmpty()
306
+ val hasCode = spannable.getSpans(start, end, CodeSpan::class.java).isNotEmpty()
307
+ val hasStrikethrough = spannable.getSpans(start, end, StrikethroughSpan::class.java).isNotEmpty()
308
+ val hasUnderline = spannable.getSpans(start, end, UnderlineSpan::class.java).isNotEmpty()
309
+ val baselineShiftSpans = spannable.getSpans(start, end, BaselineShiftSpan::class.java)
310
+ val hasSuperscript = baselineShiftSpans.any { it.spanType == BaselineShiftSpan.SpanType.SUPERSCRIPT }
311
+ val hasSubscript = baselineShiftSpans.any { it.spanType == BaselineShiftSpan.SpanType.SUBSCRIPT }
312
+ val linkSpans = spannable.getSpans(start, end, LinkSpan::class.java).filterNot { it.recognizedLink }
313
+ val hasHighlight = spannable.getSpans(start, end, HighlightSpan::class.java).isNotEmpty()
314
+
315
+ var result = text
316
+
317
+ // Innermost first
318
+ if (hasCode && linkSpans.isEmpty()) {
319
+ result = "`$result`"
320
+ }
321
+ if (hasStrikethrough) {
322
+ result = "~~$result~~"
323
+ }
324
+ if (hasSubscript) {
325
+ result = "~$result~"
326
+ }
327
+ if (hasSuperscript) {
328
+ result = "^$result^"
329
+ }
330
+ if (hasUnderline && linkSpans.isEmpty()) {
331
+ result = "<u>$result</u>"
332
+ }
333
+ if (hasEmphasis) {
334
+ result = "*$result*"
335
+ }
336
+ if (hasStrong) {
337
+ result = "**$result**"
338
+ }
339
+ if (linkSpans.isNotEmpty()) {
340
+ result = "[$result](${linkSpans[0].url})"
341
+ }
342
+ if (hasHighlight) {
343
+ result = "==$result=="
344
+ }
345
+
346
+ return result
347
+ }
348
+
349
+ private fun buildBlockPrefix(
350
+ blockquotePrefix: String?,
351
+ listPrefix: String?,
352
+ ): String =
353
+ buildString {
354
+ blockquotePrefix?.let { append(it) }
355
+ listPrefix?.let { append(it) }
356
+ }
357
+
358
+ private data class ExtractionState(
359
+ var blockquoteDepth: Int = -1,
360
+ var listDepth: Int = -1,
361
+ var needsBlankLine: Boolean = false,
362
+ )
363
+
364
+ /** Accumulates heading content across multiple span segments. */
365
+ private class HeadingAccumulator {
366
+ private var level: Int? = null
367
+ private val content = StringBuilder()
368
+
369
+ fun accumulate(
370
+ newLevel: Int,
371
+ text: String,
372
+ result: StringBuilder,
373
+ state: ExtractionState,
374
+ ) {
375
+ if (level != newLevel) {
376
+ flush(result, state)
377
+ level = newLevel
378
+ }
379
+ content.append(text.trim('\n'))
380
+ }
381
+
382
+ fun flush(
383
+ result: StringBuilder,
384
+ state: ExtractionState,
385
+ ) {
386
+ val currentLevel = level ?: return
387
+ if (content.isEmpty()) return
388
+
389
+ result.ensureBlankLine()
390
+ result.append("#".repeat(currentLevel))
391
+ result.append(" ")
392
+ result.append(content.toString().trim())
393
+ result.append("\n")
394
+
395
+ level = null
396
+ content.clear()
397
+ state.needsBlankLine = true
398
+ }
399
+ }
400
+
401
+ private fun StringBuilder.ensureBlankLine() {
402
+ if (isEmpty() || endsWith("\n\n")) return
403
+ append(if (endsWith("\n")) "\n" else "\n\n")
404
+ }
405
+
406
+ private fun StringBuilder.isAtLineStart(): Boolean = isEmpty() || endsWith("\n")
407
+
408
+ private fun extractMathLatex(
409
+ spannable: Spannable,
410
+ start: Int,
411
+ end: Int,
412
+ ): String? {
413
+ return try {
414
+ val mathInlineSpanClass = Class.forName("com.renderrichtext.spans.MathInlineSpan")
415
+ val spans = spannable.getSpans(start, end, mathInlineSpanClass)
416
+ if (spans.isEmpty()) return null
417
+ val latexField = mathInlineSpanClass.getDeclaredField("latex").apply { isAccessible = true }
418
+ latexField.get(spans[0]) as? String
419
+ } catch (_: Exception) {
420
+ null
421
+ }
422
+ }
423
+ }
@@ -0,0 +1,9 @@
1
+ package com.renderrichtext.utils.text.extensions
2
+
3
+ import com.renderrichtext.parser.TiptapASTNode
4
+
5
+ fun TiptapASTNode.containsBlockImage(): Boolean {
6
+ if (type != TiptapASTNode.NodeType.Paragraph) return false
7
+ val firstChild = children.firstOrNull()
8
+ return firstChild != null && children.size == 1 && firstChild.type == TiptapASTNode.NodeType.Image
9
+ }
@@ -0,0 +1,9 @@
1
+ package com.renderrichtext.utils.text.extensions
2
+
3
+ import android.text.SpannableStringBuilder
4
+
5
+ fun SpannableStringBuilder.isInlineImage(): Boolean {
6
+ if (isEmpty()) return false
7
+ val lastChar = last()
8
+ return lastChar != '\n' && lastChar != '\u200B'
9
+ }
@@ -0,0 +1,76 @@
1
+ package com.renderrichtext.utils.text.extensions
2
+
3
+ import android.content.Context
4
+ import android.graphics.Typeface
5
+ import android.text.TextPaint
6
+ import com.facebook.react.common.ReactConstants
7
+ import com.facebook.react.views.text.ReactTypefaceUtils.applyStyles
8
+ import com.facebook.react.views.text.ReactTypefaceUtils.parseFontWeight
9
+ import com.renderrichtext.renderer.BlockStyle
10
+ import com.renderrichtext.styles.CodeBlockStyle
11
+
12
+ fun TextPaint.applyColorPreserving(
13
+ color: Int,
14
+ vararg preserveColors: Int,
15
+ ) {
16
+ if (this.color !in preserveColors) {
17
+ this.color = color
18
+ }
19
+ }
20
+
21
+ private val typefaceCache = mutableMapOf<String, Typeface>()
22
+ private val fontWeightCache = mutableMapOf<String?, Int>()
23
+
24
+ fun TextPaint.applyBlockStyleFont(
25
+ blockStyle: BlockStyle,
26
+ context: Context,
27
+ ) {
28
+ val cacheKey = "${blockStyle.fontFamily}|${blockStyle.fontWeight}"
29
+
30
+ val cachedTypeface = typefaceCache[cacheKey]
31
+ if (cachedTypeface != null) {
32
+ this.typeface = cachedTypeface
33
+ return
34
+ }
35
+
36
+ val fontWeight =
37
+ fontWeightCache.getOrPut(blockStyle.fontWeight) {
38
+ parseFontWeight(blockStyle.fontWeight)
39
+ }
40
+
41
+ // Pass null as base typeface - this matches React Native Text behavior
42
+ // applyStyles will use ReactFontManager to load custom fonts from assets
43
+ val newTypeface =
44
+ applyStyles(
45
+ null, // Let applyStyles handle font loading from assets
46
+ ReactConstants.UNSET,
47
+ fontWeight,
48
+ blockStyle.fontFamily.takeIf { it.isNotEmpty() },
49
+ context.assets,
50
+ )
51
+
52
+ typefaceCache[cacheKey] = newTypeface
53
+ this.typeface = newTypeface
54
+ }
55
+
56
+ /**
57
+ * Code block text sizing and font, shared by both flavors (CodeBlockSpan for
58
+ * commonmark, CodeBlockContainerView for github) so the code always renders
59
+ * and measures with the same paint. Color is applied by the callers: the span
60
+ * needs color preserving, the view colors via the text view.
61
+ */
62
+ fun TextPaint.applyCodeBlockTextStyle(
63
+ style: CodeBlockStyle,
64
+ context: Context,
65
+ ) {
66
+ textSize = style.fontSize
67
+ applyBlockStyleFont(
68
+ BlockStyle(
69
+ fontSize = style.fontSize,
70
+ fontFamily = style.fontFamily,
71
+ fontWeight = style.fontWeight,
72
+ color = style.color,
73
+ ),
74
+ context,
75
+ )
76
+ }
@@ -0,0 +1,61 @@
1
+ package com.renderrichtext.utils.text.interaction
2
+
3
+ import android.view.MotionEvent
4
+ import android.view.ViewConfiguration
5
+ import android.widget.TextView
6
+ import com.renderrichtext.utils.text.interaction.TaskListHitTestResult
7
+ import com.renderrichtext.utils.text.interaction.TaskListTapUtils
8
+ import kotlin.math.abs
9
+
10
+ class CheckboxTouchHelper(
11
+ private val textView: TextView,
12
+ ) {
13
+ var onCheckboxTap: ((taskIndex: Int, checked: Boolean, itemText: String) -> Unit)? = null
14
+
15
+ /**
16
+ * When false, checkbox taps are ignored: hit-testing is skipped and no
17
+ * gesture is consumed, so the tap falls through to the text view unchanged.
18
+ */
19
+ var isEnabled: Boolean = true
20
+
21
+ private var touchDownX = 0f
22
+ private var touchDownY = 0f
23
+ private var pendingHit: TaskListHitTestResult? = null
24
+ private val touchSlop: Int by lazy { ViewConfiguration.get(textView.context).scaledTouchSlop }
25
+
26
+ /** Returns `true` if the event was consumed by a checkbox gesture. */
27
+ fun onTouchEvent(event: MotionEvent): Boolean {
28
+ if (!isEnabled) return false
29
+ when (event.actionMasked) {
30
+ MotionEvent.ACTION_DOWN -> {
31
+ val hit = TaskListTapUtils.hitTest(textView, event.x, event.y) ?: return false
32
+ touchDownX = event.x
33
+ touchDownY = event.y
34
+ pendingHit = hit
35
+ return true
36
+ }
37
+
38
+ MotionEvent.ACTION_MOVE -> {
39
+ if (pendingHit != null && isExceedingSlop(event)) {
40
+ pendingHit = null
41
+ }
42
+ }
43
+
44
+ MotionEvent.ACTION_UP -> {
45
+ val hit = pendingHit ?: return false
46
+ pendingHit = null
47
+ if (!isExceedingSlop(event)) {
48
+ onCheckboxTap?.invoke(hit.taskIndex, hit.checked, hit.itemText)
49
+ }
50
+ return true
51
+ }
52
+
53
+ MotionEvent.ACTION_CANCEL -> {
54
+ pendingHit = null
55
+ }
56
+ }
57
+ return pendingHit != null
58
+ }
59
+
60
+ private fun isExceedingSlop(event: MotionEvent): Boolean = abs(event.x - touchDownX) > touchSlop || abs(event.y - touchDownY) > touchSlop
61
+ }