react-native-enriched-markdown-scaffold 0.7.4-scaffold.9 → 1.0.2-scaffold.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 (505) hide show
  1. package/README.md +54 -8
  2. package/ReactNativeEnrichedMarkdown.podspec +82 -73
  3. package/android/build.gradle +188 -1
  4. package/android/consumer-rules.pro +1 -1
  5. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerDelegate.java +27 -0
  6. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java +7 -0
  7. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerDelegate.java +24 -0
  8. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerInterface.java +8 -0
  9. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +27 -0
  10. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +7 -0
  11. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +223 -0
  12. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +183 -0
  13. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +65 -0
  14. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +1086 -61
  15. package/android/src/main/baseline-prof.txt +1 -1
  16. package/android/src/main/cpp/jni-adapter.cpp +74 -0
  17. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdown.kt +351 -13
  18. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt +62 -0
  19. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownManager.kt +85 -0
  20. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +160 -1
  21. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextLayoutManager.kt +10 -1
  22. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +76 -0
  23. package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +126 -10
  24. package/android/src/main/java/com/swmansion/enriched/markdown/events/CopyPressEvent.kt +24 -0
  25. package/android/src/main/java/com/swmansion/enriched/markdown/events/CopyRequestEvent.kt +28 -0
  26. package/android/src/main/java/com/swmansion/enriched/markdown/events/LinkLayoutEvent.kt +36 -0
  27. package/android/src/main/java/com/swmansion/enriched/markdown/events/SelectionChangeEvent.kt +43 -0
  28. package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt +54 -4
  29. package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputView.kt +923 -462
  30. package/android/src/main/java/com/swmansion/enriched/markdown/input/MarkdownClipboard.kt +42 -0
  31. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/BlockEditCoordinator.kt +196 -0
  32. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/ClipboardCoordinator.kt +73 -0
  33. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/EditContext.kt +19 -0
  34. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/EditPipeline.kt +248 -0
  35. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/EditSession.kt +52 -0
  36. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/InputConnectionWrapper.kt +108 -7
  37. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/LinkCoordinator.kt +69 -0
  38. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/MarkdownTextWatcher.kt +3 -3
  39. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/MentionCoordinator.kt +118 -0
  40. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnChangeStateEvent.kt +26 -0
  41. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnContextMenuItemPressEvent.kt +26 -0
  42. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnInputKeyPressEvent.kt +24 -0
  43. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnPasteEvent.kt +24 -0
  44. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/BlockStore.kt +254 -0
  45. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/FormattingStore.kt +80 -87
  46. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputFormatter.kt +109 -1
  47. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputParser.kt +116 -22
  48. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/MarkdownSerializer.kt +167 -38
  49. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/RangeEditAdjustment.kt +149 -0
  50. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputEventEmitter.kt +66 -5
  51. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputMeasurementStore.kt +4 -2
  52. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/BlockRange.kt +27 -0
  53. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/BlockType.kt +48 -0
  54. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/FormattingRange.kt +9 -4
  55. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/InputFormatterStyle.kt +39 -2
  56. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathAtom.kt +20 -0
  57. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathChipStyle.kt +1 -1
  58. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MutableRangeBounds.kt +11 -0
  59. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputBulletSpan.kt +82 -0
  60. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputHeadingSpan.kt +58 -0
  61. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputListItemSpacingSpan.kt +37 -0
  62. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputOrderedListMarkerSpan.kt +63 -0
  63. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/BlockHandler.kt +54 -0
  64. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/HeadingBlockHandler.kt +27 -0
  65. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/OrderedListBlockHandler.kt +38 -0
  66. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/UnorderedListBlockHandler.kt +37 -0
  67. package/android/src/main/java/com/swmansion/enriched/markdown/input/toolbar/InputContextMenu.kt +8 -26
  68. package/android/src/main/java/com/swmansion/enriched/markdown/parser/MarkdownASTNode.kt +1 -0
  69. package/android/src/main/java/com/swmansion/enriched/markdown/parser/Parser.kt +1 -0
  70. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockStyleContext.kt +9 -2
  71. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt +100 -12
  72. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeBlockRenderer.kt +16 -1
  73. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +4 -0
  74. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LinkRenderer.kt +37 -7
  75. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListContextManager.kt +2 -1
  76. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListItemRenderer.kt +74 -18
  77. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListRenderer.kt +43 -4
  78. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/NodeRenderer.kt +9 -1
  79. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SoftBreakRenderer.kt +16 -0
  80. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +35 -28
  81. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BaseListSpan.kt +24 -0
  82. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt +174 -24
  83. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBackgroundSpan.kt +20 -82
  84. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBlockSpan.kt +13 -16
  85. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeSpan.kt +1 -1
  86. package/android/src/main/java/com/swmansion/enriched/markdown/spans/EmphasisSpan.kt +1 -1
  87. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ImageSpan.kt +182 -46
  88. package/android/src/main/java/com/swmansion/enriched/markdown/spans/InlineChipPainter.kt +140 -0
  89. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LinkChipSpans.kt +177 -0
  90. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LinkSpan.kt +1 -6
  91. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ListItemSpacingSpan.kt +33 -0
  92. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ListMarkerAnchorSpan.kt +38 -0
  93. package/android/src/main/java/com/swmansion/enriched/markdown/spans/OrderedListSpan.kt +2 -0
  94. package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrongSpan.kt +1 -1
  95. package/android/src/main/java/com/swmansion/enriched/markdown/spans/TaskListSpan.kt +3 -2
  96. package/android/src/main/java/com/swmansion/enriched/markdown/spans/UnorderedListSpan.kt +3 -2
  97. package/android/src/main/java/com/swmansion/enriched/markdown/styles/BlockquoteStyle.kt +6 -0
  98. package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeBlockStyle.kt +26 -0
  99. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ImageStyle.kt +7 -1
  100. package/android/src/main/java/com/swmansion/enriched/markdown/styles/InlineMathStyle.kt +16 -1
  101. package/android/src/main/java/com/swmansion/enriched/markdown/styles/LinkStyle.kt +36 -1
  102. package/android/src/main/java/com/swmansion/enriched/markdown/styles/LinkVariantEntry.kt +7 -3
  103. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ListStyle.kt +4 -1
  104. package/android/src/main/java/com/swmansion/enriched/markdown/styles/MathStyle.kt +3 -0
  105. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt +13 -4
  106. package/android/src/main/java/com/swmansion/enriched/markdown/styles/TableStyle.kt +6 -0
  107. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/CodeBlockHighlighter.kt +90 -0
  108. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/CodeBlockNode.kt +57 -0
  109. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/FeatureFlags.kt +1 -0
  110. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownSegment.kt +9 -0
  111. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt +84 -7
  112. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/ReadableMapExtensions.kt +3 -0
  113. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/RenderedSegment.kt +10 -0
  114. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/SegmentSignature.kt +1 -0
  115. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/StreamingMarkdownFilter.kt +83 -5
  116. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/serialization/MarkdownASTSerializer.kt +4 -0
  117. package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/MarkdownStyleParser.kt +74 -44
  118. package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/PasteTextUtils.kt +52 -0
  119. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/ImageCache.kt +26 -3
  120. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/ImageDownloader.kt +22 -9
  121. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/LocalImageLoader.kt +161 -0
  122. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/conversion/HTMLGenerator.kt +2 -1
  123. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/conversion/MarkdownExtractor.kt +6 -0
  124. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/extensions/TextPaintExtensions.kt +23 -0
  125. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/interaction/CheckboxTouchHelper.kt +7 -0
  126. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/interaction/TaskListTapUtils.kt +41 -21
  127. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/span/BlockSpacing.kt +15 -8
  128. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/HeadlessActionMode.kt +88 -0
  129. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkLayoutCollector.kt +100 -0
  130. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkLongPressMovementMethod.kt +58 -27
  131. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionActionMode.kt +72 -16
  132. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionChangeReporter.kt +232 -0
  133. package/android/src/main/java/com/swmansion/enriched/markdown/views/BlockMenuOptions.kt +64 -0
  134. package/android/src/main/java/com/swmansion/enriched/markdown/views/CodeBlockContainerView.kt +414 -0
  135. package/android/src/main/java/com/swmansion/enriched/markdown/views/ContextMenuPopup.kt +9 -6
  136. package/android/src/main/java/com/swmansion/enriched/markdown/views/CopyGlyph.kt +101 -0
  137. package/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt +61 -11
  138. package/android/src/main/jni/CMakeLists.txt +53 -0
  139. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownContainerShadowNode.cpp +10 -0
  140. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownContainerShadowNode.h +11 -2
  141. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.cpp +10 -0
  142. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.h +12 -2
  143. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextState.cpp +9 -0
  144. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextState.h +24 -0
  145. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/conversions.h +16 -0
  146. package/android/src/math/java/com/swmansion/enriched/markdown/input/math/MathChipControllerImpl.kt +21 -4
  147. package/android/src/math/java/com/swmansion/enriched/markdown/renderer/MathInlineRenderer.kt +8 -2
  148. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathChipSpan.kt +1 -1
  149. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathInlineSpan.kt +13 -6
  150. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathMeasureHelper.kt +2 -1
  151. package/android/src/math/java/com/swmansion/enriched/markdown/views/MathContainerView.kt +26 -8
  152. package/cpp/highlight/CodeBlockHighlighter.cpp +284 -0
  153. package/cpp/highlight/CodeBlockHighlighter.hpp +66 -0
  154. package/cpp/highlight/CodeBlockLanguages.cpp +138 -0
  155. package/cpp/highlight/CodeBlockLanguages.hpp +25 -0
  156. package/cpp/highlight/HighlightGrammars.hpp +28 -0
  157. package/cpp/highlight/code_highlight_podspec.rb +211 -0
  158. package/cpp/highlight/gen-registry.mjs +155 -0
  159. package/cpp/highlight/grammar-versions.json +159 -0
  160. package/cpp/highlight/vendor/generated/generated_queries.h +1665 -0
  161. package/cpp/highlight/vendor/generated/generated_registry.cpp +59 -0
  162. package/cpp/parser/MD4CParser.cpp +173 -61
  163. package/cpp/parser/MD4CParser.hpp +1 -0
  164. package/cpp/parser/MarkdownASTNode.hpp +2 -1
  165. package/cpp/wasm/ASTSerializer.cpp +2 -0
  166. package/cpp/wasm/build.sh +1 -0
  167. package/cpp/wasm/md4c_wasm.cpp +3 -1
  168. package/docs/ACCESSIBILITY.md +14 -2
  169. package/docs/API_REFERENCE.md +405 -12
  170. package/docs/BREAKING_CHANGES.md +129 -0
  171. package/docs/CODE_HIGHLIGHT.md +133 -0
  172. package/docs/COPY_OPTIONS.md +61 -3
  173. package/docs/ELEMENTS_STRUCTURE.md +52 -4
  174. package/docs/IMAGE_CACHING.md +30 -0
  175. package/docs/INPUT.md +110 -11
  176. package/docs/LATEX_MATH.md +87 -45
  177. package/docs/MACOS.md +1 -1
  178. package/docs/MARKDOWN_STREAMING.md +27 -1
  179. package/docs/MENTIONS.md +8 -1
  180. package/docs/NATIVE_ASSETS.md +127 -0
  181. package/docs/RTL.md +1 -1
  182. package/docs/STYLES.md +73 -6
  183. package/docs/TESTING.md +112 -0
  184. package/docs/TEXT.md +18 -6
  185. package/docs/WEB.md +4 -1
  186. package/ios/EnrichedMarkdown.h +7 -0
  187. package/ios/EnrichedMarkdown.mm +583 -76
  188. package/ios/EnrichedMarkdownText.h +7 -0
  189. package/ios/EnrichedMarkdownText.mm +299 -73
  190. package/ios/attachments/ENRMImageAttachment.h +9 -0
  191. package/ios/attachments/ENRMImageAttachment.m +143 -40
  192. package/ios/attachments/ENRMMathInlineAttachment+macOS.m +2 -1
  193. package/ios/attachments/ENRMMathInlineAttachment.h +5 -0
  194. package/ios/attachments/ENRMMathInlineAttachment.m +50 -82
  195. package/ios/attachments/ENRMMathInlineAttachmentShared.h +2 -0
  196. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.cpp +223 -0
  197. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.h +183 -0
  198. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp +65 -0
  199. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +1086 -61
  200. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +181 -2
  201. package/ios/input/ENRMAutoLinkDetector.h +2 -1
  202. package/ios/input/ENRMAutoLinkDetector.mm +79 -41
  203. package/ios/input/ENRMBlockEditCoordinator.h +71 -0
  204. package/ios/input/ENRMBlockEditCoordinator.mm +195 -0
  205. package/ios/input/ENRMBlockRange.h +28 -0
  206. package/ios/input/ENRMBlockRange.mm +30 -0
  207. package/ios/input/ENRMBlockStore.h +56 -0
  208. package/ios/input/ENRMBlockStore.mm +275 -0
  209. package/ios/input/ENRMClipboardCoordinator.h +45 -0
  210. package/ios/input/ENRMClipboardCoordinator.mm +120 -0
  211. package/ios/input/ENRMDetectorPipeline.h +2 -1
  212. package/ios/input/ENRMEditPipeline.h +76 -0
  213. package/ios/input/ENRMEditPipeline.mm +228 -0
  214. package/ios/input/ENRMEditSession.h +36 -0
  215. package/ios/input/ENRMEditSession.mm +63 -0
  216. package/ios/input/ENRMFormattingStore.h +17 -0
  217. package/ios/input/ENRMFormattingStore.mm +95 -105
  218. package/ios/input/ENRMInputBlockType.h +91 -0
  219. package/ios/input/ENRMInputBlockType.mm +5 -0
  220. package/ios/input/ENRMInputDecorationDrawer.h +18 -0
  221. package/ios/input/ENRMInputEventEmitter.h +56 -0
  222. package/ios/input/ENRMInputEventEmitter.mm +308 -0
  223. package/ios/input/ENRMInputFormatter.h +29 -69
  224. package/ios/input/ENRMInputFormatter.mm +216 -124
  225. package/ios/input/ENRMInputFormatterStyle.h +99 -0
  226. package/ios/input/ENRMInputFormatterStyle.mm +188 -0
  227. package/ios/input/ENRMInputLayoutManager.h +9 -0
  228. package/ios/input/ENRMInputLayoutManager.mm +30 -0
  229. package/ios/input/ENRMInputListMarkerDrawer.h +32 -0
  230. package/ios/input/ENRMInputListMarkerDrawer.mm +426 -0
  231. package/ios/input/ENRMInputParser.h +5 -6
  232. package/ios/input/ENRMInputParser.mm +461 -178
  233. package/ios/input/ENRMInputRemend.mm +2 -2
  234. package/ios/input/ENRMInputStyleStateBuilder.h +40 -0
  235. package/ios/input/ENRMInputStyleStateBuilder.mm +60 -0
  236. package/ios/input/ENRMInputTextView.mm +103 -8
  237. package/ios/input/ENRMInputTypingAttributesController.h +42 -0
  238. package/ios/input/ENRMInputTypingAttributesController.mm +203 -0
  239. package/ios/input/ENRMLinkCoordinator.h +41 -0
  240. package/ios/input/ENRMLinkCoordinator.mm +89 -0
  241. package/ios/input/ENRMMarkdownSerializer.h +29 -5
  242. package/ios/input/ENRMMarkdownSerializer.mm +170 -48
  243. package/ios/input/ENRMMathAtom.h +26 -0
  244. package/ios/input/ENRMMathAtom.mm +12 -0
  245. package/ios/input/ENRMMentionCoordinator.h +45 -0
  246. package/ios/input/ENRMMentionCoordinator.mm +167 -0
  247. package/ios/input/ENRMRangeEditAdjustment.h +38 -0
  248. package/ios/input/ENRMRangeEditAdjustment.mm +91 -0
  249. package/ios/input/ENRMRangeStoreUtils.h +39 -0
  250. package/ios/input/EnrichedMarkdownTextInput+ContextMenu.mm +6 -6
  251. package/ios/input/EnrichedMarkdownTextInput+Internal.h +11 -3
  252. package/ios/input/EnrichedMarkdownTextInput.h +7 -1
  253. package/ios/input/EnrichedMarkdownTextInput.mm +1089 -1023
  254. package/ios/input/InputStylePropsUtils.h +109 -68
  255. package/ios/input/internals/EnrichedMarkdownTextInputShadowNode.mm +2 -1
  256. package/ios/input/styles/ENRMBlockHandler.h +46 -0
  257. package/ios/input/styles/ENRMHeadingBlockHandler.h +15 -0
  258. package/ios/input/styles/ENRMHeadingBlockHandler.mm +38 -0
  259. package/ios/input/styles/ENRMOrderedListBlockHandler.h +14 -0
  260. package/ios/input/styles/ENRMOrderedListBlockHandler.mm +48 -0
  261. package/ios/input/styles/ENRMUnorderedListBlockHandler.h +15 -0
  262. package/ios/input/styles/ENRMUnorderedListBlockHandler.mm +51 -0
  263. package/ios/internals/ENRMViewFreeMeasurement.h +331 -0
  264. package/ios/internals/EnrichedMarkdownShadowNode.h +1 -3
  265. package/ios/internals/EnrichedMarkdownShadowNode.mm +16 -20
  266. package/ios/internals/EnrichedMarkdownTextShadowNode.h +1 -3
  267. package/ios/internals/EnrichedMarkdownTextShadowNode.mm +15 -20
  268. package/ios/internals/MeasurementCache.h +41 -9
  269. package/ios/internals/ShadowMeasurementUtils.h +63 -58
  270. package/ios/math/ENRMMathChipController.h +74 -0
  271. package/ios/math/ENRMMathChipController.mm +476 -0
  272. package/ios/math/ENRMRaTeXBridge.swift +27 -6
  273. package/ios/parser/ENRMMarkdownParser.h +1 -8
  274. package/ios/parser/ENRMMarkdownParser.mm +2 -11
  275. package/ios/parser/MarkdownASTNode.h +2 -1
  276. package/ios/parser/MarkdownParserBridge.mm +4 -0
  277. package/ios/renderer/AttributedRenderer.m +20 -2
  278. package/ios/renderer/BaseRenderer.h +17 -2
  279. package/ios/renderer/BaseRenderer.m +30 -0
  280. package/ios/renderer/BlockquoteRenderer.h +1 -1
  281. package/ios/renderer/BlockquoteRenderer.m +144 -35
  282. package/ios/renderer/CodeBlockRenderer.h +1 -1
  283. package/ios/renderer/CodeBlockRenderer.m +27 -23
  284. package/ios/renderer/CodeRenderer.h +1 -1
  285. package/ios/renderer/CodeRenderer.m +3 -1
  286. package/ios/renderer/ENRMImageRenderer.h +1 -1
  287. package/ios/renderer/ENRMImageRenderer.m +5 -1
  288. package/ios/renderer/ENRMMathInlineRenderer.h +1 -1
  289. package/ios/renderer/ENRMMathInlineRenderer.m +6 -1
  290. package/ios/renderer/ENRMSpoilerRenderer.h +1 -1
  291. package/ios/renderer/ENRMSpoilerRenderer.m +3 -1
  292. package/ios/renderer/EmphasisRenderer.h +1 -1
  293. package/ios/renderer/EmphasisRenderer.m +3 -1
  294. package/ios/renderer/HeadingRenderer.h +1 -1
  295. package/ios/renderer/HeadingRenderer.m +13 -6
  296. package/ios/renderer/HighlightRenderer.h +1 -1
  297. package/ios/renderer/HighlightRenderer.m +3 -1
  298. package/ios/renderer/LinkRenderer.h +1 -1
  299. package/ios/renderer/LinkRenderer.m +50 -16
  300. package/ios/renderer/ListItemRenderer.h +13 -1
  301. package/ios/renderer/ListItemRenderer.m +102 -44
  302. package/ios/renderer/ListRenderer.h +2 -2
  303. package/ios/renderer/ListRenderer.m +63 -25
  304. package/ios/renderer/ParagraphRenderer.h +1 -1
  305. package/ios/renderer/ParagraphRenderer.m +16 -8
  306. package/ios/renderer/RenderContext.h +10 -0
  307. package/ios/renderer/RenderContext.m +44 -0
  308. package/ios/renderer/RendererFactory.m +14 -0
  309. package/ios/renderer/StrikethroughRenderer.h +1 -1
  310. package/ios/renderer/StrikethroughRenderer.m +3 -1
  311. package/ios/renderer/StrongRenderer.h +1 -1
  312. package/ios/renderer/StrongRenderer.m +3 -1
  313. package/ios/renderer/SubscriptRenderer.h +1 -1
  314. package/ios/renderer/SubscriptRenderer.m +3 -1
  315. package/ios/renderer/SuperscriptRenderer.h +1 -1
  316. package/ios/renderer/SuperscriptRenderer.m +3 -1
  317. package/ios/renderer/TextRenderer.h +2 -2
  318. package/ios/renderer/TextRenderer.m +3 -1
  319. package/ios/renderer/ThematicBreakRenderer.h +1 -1
  320. package/ios/renderer/ThematicBreakRenderer.m +3 -1
  321. package/ios/renderer/UnderlineRenderer.h +1 -1
  322. package/ios/renderer/UnderlineRenderer.m +3 -1
  323. package/ios/styles/StyleConfig.h +42 -0
  324. package/ios/styles/StyleConfig.mm +216 -0
  325. package/ios/utils/BlockquoteBorder.h +6 -0
  326. package/ios/utils/BlockquoteBorder.m +249 -52
  327. package/ios/utils/CodeBackground.m +3 -65
  328. package/ios/utils/CodeBlockBackground.m +16 -2
  329. package/ios/utils/ENRMAtomicSize.h +65 -0
  330. package/ios/utils/ENRMBlockMenu.h +66 -0
  331. package/ios/utils/ENRMChipDrawing.h +24 -0
  332. package/ios/utils/ENRMChipDrawing.m +83 -0
  333. package/ios/utils/ENRMCodeBlockContent.h +37 -0
  334. package/ios/utils/ENRMCodeBlockContent.mm +79 -0
  335. package/ios/utils/ENRMCodeBlockHighlighter.h +37 -0
  336. package/ios/utils/ENRMCodeBlockHighlighter.mm +51 -0
  337. package/ios/utils/ENRMFeatureFlags.h +7 -0
  338. package/ios/utils/ENRMImageDownloader.h +11 -1
  339. package/ios/utils/ENRMImageDownloader.m +60 -16
  340. package/ios/utils/ENRMLinkChip.h +70 -0
  341. package/ios/utils/ENRMLinkChip.m +213 -0
  342. package/ios/utils/ENRMLinkLayout.h +50 -0
  343. package/ios/utils/ENRMLinkLayout.m +45 -0
  344. package/ios/utils/ENRMLocalImageLoader.h +31 -0
  345. package/ios/utils/ENRMLocalImageLoader.m +68 -0
  346. package/ios/utils/ENRMMathFallback.h +26 -0
  347. package/ios/utils/ENRMMathFallback.m +18 -0
  348. package/ios/utils/ENRMSelectionChange.h +120 -0
  349. package/ios/utils/ENRMSelectionChange.m +282 -0
  350. package/ios/utils/ENRMTextViewSetup.h +35 -17
  351. package/ios/utils/EditMenuUtils+macOS.m +4 -1
  352. package/ios/utils/EditMenuUtils.h +35 -6
  353. package/ios/utils/EditMenuUtils.m +188 -11
  354. package/ios/utils/HTMLGenerator.m +2 -1
  355. package/ios/utils/ImageRequestHeaderUtils.h +35 -0
  356. package/ios/utils/LastElementUtils.h +1 -0
  357. package/ios/utils/ListMarkerDrawer.m +29 -42
  358. package/ios/utils/MarkdownASTSerializer.m +4 -0
  359. package/ios/utils/MarkdownAccessibilityElementBuilder.m +3 -1
  360. package/ios/utils/MarkdownExtractor.m +2 -1
  361. package/ios/utils/ParagraphStyleUtils.h +5 -0
  362. package/ios/utils/ParagraphStyleUtils.m +77 -17
  363. package/ios/utils/RTFExportUtils.m +2 -0
  364. package/ios/utils/RenderedMarkdownSegment.h +13 -1
  365. package/ios/utils/RenderedMarkdownSegment.m +20 -0
  366. package/ios/utils/SegmentRenderer.m +17 -4
  367. package/ios/utils/StreamingMarkdownFilter.h +11 -1
  368. package/ios/utils/StreamingMarkdownFilter.m +98 -2
  369. package/ios/utils/StylePropsUtils.h +110 -1
  370. package/ios/utils/TaskListTapUtils.m +24 -0
  371. package/ios/utils/TextViewLayoutManager.mm +3 -0
  372. package/ios/views/ENRMCodeBlockContainerView.h +60 -0
  373. package/ios/views/ENRMCodeBlockContainerView.m +569 -0
  374. package/ios/views/ENRMMathContainerView.h +23 -0
  375. package/ios/views/ENRMMathContainerView.m +87 -20
  376. package/ios/views/TableContainerView.h +32 -0
  377. package/ios/views/TableContainerView.m +291 -175
  378. package/jest.d.ts +1 -0
  379. package/jest.js +5 -0
  380. package/lib/module/EnrichedMarkdownNativeComponent.ts +203 -1
  381. package/lib/module/EnrichedMarkdownTextInput.js +84 -5
  382. package/lib/module/EnrichedMarkdownTextInput.js.map +1 -1
  383. package/lib/module/EnrichedMarkdownTextInputNativeComponent.ts +78 -5
  384. package/lib/module/EnrichedMarkdownTextNativeComponent.ts +204 -1
  385. package/lib/module/headingDefaults.js +34 -0
  386. package/lib/module/headingDefaults.js.map +1 -0
  387. package/lib/module/index.js.map +1 -1
  388. package/lib/module/jest/index.js +205 -0
  389. package/lib/module/jest/index.js.map +1 -0
  390. package/lib/module/native/EnrichedMarkdownText.js +199 -15
  391. package/lib/module/native/EnrichedMarkdownText.js.map +1 -1
  392. package/lib/module/normalizeMarkdownStyle.js +98 -23
  393. package/lib/module/normalizeMarkdownStyle.js.map +1 -1
  394. package/lib/module/normalizeMarkdownStyle.web.js +73 -22
  395. package/lib/module/normalizeMarkdownStyle.web.js.map +1 -1
  396. package/lib/module/normalizeMarkdownTextInputStyle.js +62 -15
  397. package/lib/module/normalizeMarkdownTextInputStyle.js.map +1 -1
  398. package/lib/module/normalizeMenuItem.js +1 -1
  399. package/lib/module/utils/textInputState.js +26 -0
  400. package/lib/module/utils/textInputState.js.map +1 -0
  401. package/lib/module/web/EnrichedMarkdownText.js +15 -8
  402. package/lib/module/web/EnrichedMarkdownText.js.map +1 -1
  403. package/lib/module/web/parseMarkdown.js +4 -3
  404. package/lib/module/web/parseMarkdown.js.map +1 -1
  405. package/lib/module/web/renderers/InlineRenderers.js +102 -3
  406. package/lib/module/web/renderers/InlineRenderers.js.map +1 -1
  407. package/lib/module/web/renderers/ListRenderers.js +7 -2
  408. package/lib/module/web/renderers/ListRenderers.js.map +1 -1
  409. package/lib/module/web/renderers/index.js +7 -4
  410. package/lib/module/web/renderers/index.js.map +1 -1
  411. package/lib/module/web/styles.js +101 -6
  412. package/lib/module/web/styles.js.map +1 -1
  413. package/lib/module/web/utils.js +14 -0
  414. package/lib/module/web/utils.js.map +1 -1
  415. package/lib/module/web/wasm/md4c.js +0 -0
  416. package/lib/module/web/wasm/md4c.js.map +1 -1
  417. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts +185 -2
  418. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -1
  419. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts +94 -9
  420. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts.map +1 -1
  421. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts +69 -5
  422. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts.map +1 -1
  423. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +185 -2
  424. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -1
  425. package/lib/typescript/src/headingDefaults.d.ts +9 -0
  426. package/lib/typescript/src/headingDefaults.d.ts.map +1 -0
  427. package/lib/typescript/src/index.d.ts +3 -3
  428. package/lib/typescript/src/index.d.ts.map +1 -1
  429. package/lib/typescript/src/index.web.d.ts +2 -2
  430. package/lib/typescript/src/index.web.d.ts.map +1 -1
  431. package/lib/typescript/src/jest/index.d.ts +6 -0
  432. package/lib/typescript/src/jest/index.d.ts.map +1 -0
  433. package/lib/typescript/src/native/EnrichedMarkdownText.d.ts +5 -5
  434. package/lib/typescript/src/native/EnrichedMarkdownText.d.ts.map +1 -1
  435. package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -1
  436. package/lib/typescript/src/normalizeMarkdownStyle.web.d.ts.map +1 -1
  437. package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts +19 -5
  438. package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts.map +1 -1
  439. package/lib/typescript/src/types/MarkdownStyle.d.ts +122 -5
  440. package/lib/typescript/src/types/MarkdownStyle.d.ts.map +1 -1
  441. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts +39 -0
  442. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts.map +1 -1
  443. package/lib/typescript/src/types/MarkdownTextProps.d.ts +207 -10
  444. package/lib/typescript/src/types/MarkdownTextProps.d.ts.map +1 -1
  445. package/lib/typescript/src/types/MarkdownTextProps.web.d.ts +60 -1
  446. package/lib/typescript/src/types/MarkdownTextProps.web.d.ts.map +1 -1
  447. package/lib/typescript/src/types/events.d.ts +85 -0
  448. package/lib/typescript/src/types/events.d.ts.map +1 -1
  449. package/lib/typescript/src/utils/textInputState.d.ts +24 -0
  450. package/lib/typescript/src/utils/textInputState.d.ts.map +1 -0
  451. package/lib/typescript/src/web/EnrichedMarkdownText.d.ts +1 -1
  452. package/lib/typescript/src/web/EnrichedMarkdownText.d.ts.map +1 -1
  453. package/lib/typescript/src/web/parseMarkdown.d.ts +1 -1
  454. package/lib/typescript/src/web/parseMarkdown.d.ts.map +1 -1
  455. package/lib/typescript/src/web/renderers/InlineRenderers.d.ts.map +1 -1
  456. package/lib/typescript/src/web/renderers/ListRenderers.d.ts.map +1 -1
  457. package/lib/typescript/src/web/renderers/index.d.ts +2 -1
  458. package/lib/typescript/src/web/renderers/index.d.ts.map +1 -1
  459. package/lib/typescript/src/web/styles.d.ts +2 -1
  460. package/lib/typescript/src/web/styles.d.ts.map +1 -1
  461. package/lib/typescript/src/web/types.d.ts +10 -2
  462. package/lib/typescript/src/web/types.d.ts.map +1 -1
  463. package/lib/typescript/src/web/utils.d.ts +4 -0
  464. package/lib/typescript/src/web/utils.d.ts.map +1 -1
  465. package/package.json +36 -9
  466. package/postinstall.mjs +131 -0
  467. package/ratex-version.json +21 -0
  468. package/src/EnrichedMarkdownNativeComponent.ts +203 -1
  469. package/src/EnrichedMarkdownTextInput.tsx +159 -8
  470. package/src/EnrichedMarkdownTextInputNativeComponent.ts +78 -5
  471. package/src/EnrichedMarkdownTextNativeComponent.ts +204 -1
  472. package/src/headingDefaults.ts +21 -0
  473. package/src/index.tsx +15 -0
  474. package/src/index.web.tsx +6 -1
  475. package/src/jest/index.tsx +236 -0
  476. package/src/native/EnrichedMarkdownText.tsx +260 -11
  477. package/src/normalizeMarkdownStyle.ts +117 -16
  478. package/src/normalizeMarkdownStyle.web.ts +76 -15
  479. package/src/normalizeMarkdownTextInputStyle.ts +110 -35
  480. package/src/normalizeMenuItem.ts +1 -1
  481. package/src/types/MarkdownStyle.ts +125 -5
  482. package/src/types/MarkdownStyleInternal.ts +51 -0
  483. package/src/types/MarkdownTextProps.ts +215 -10
  484. package/src/types/MarkdownTextProps.web.ts +62 -1
  485. package/src/types/events.ts +90 -0
  486. package/src/utils/textInputState.ts +35 -0
  487. package/src/web/EnrichedMarkdownText.tsx +26 -5
  488. package/src/web/parseMarkdown.ts +6 -2
  489. package/src/web/renderers/InlineRenderers.tsx +116 -3
  490. package/src/web/renderers/ListRenderers.tsx +14 -2
  491. package/src/web/renderers/index.tsx +6 -2
  492. package/src/web/styles.ts +114 -5
  493. package/src/web/types.ts +10 -1
  494. package/src/web/utils.ts +9 -0
  495. package/src/web/wasm/md4c.js +0 -0
  496. package/vendor-grammars.mjs +511 -0
  497. package/vendor-ratex.mjs +173 -0
  498. package/app.plugin.js +0 -2
  499. package/plugin/build/withAndroidMath.js +0 -19
  500. package/plugin/build/withIosMath.js +0 -28
  501. package/plugin/build/withReactNativeEnrichedMarkdown.js +0 -11
  502. package/plugin/src/withAndroidMath.ts +0 -24
  503. package/plugin/src/withIosMath.ts +0 -35
  504. package/plugin/src/withReactNativeEnrichedMarkdown.ts +0 -17
  505. package/plugin/tsconfig.build.json +0 -16
@@ -12,27 +12,25 @@ import android.text.style.LeadingMarginSpan
12
12
  import android.text.style.LineBackgroundSpan
13
13
  import android.text.style.MetricAffectingSpan
14
14
  import androidx.core.graphics.withSave
15
- import com.swmansion.enriched.markdown.renderer.BlockStyle
16
15
  import com.swmansion.enriched.markdown.renderer.SpanStyleCache
17
16
  import com.swmansion.enriched.markdown.styles.CodeBlockStyle
18
- import com.swmansion.enriched.markdown.utils.text.extensions.applyBlockStyleFont
17
+ import com.swmansion.enriched.markdown.utils.text.extensions.applyCodeBlockTextStyle
19
18
  import com.swmansion.enriched.markdown.utils.text.extensions.applyColorPreserving
20
19
 
20
+ /**
21
+ * Draws the commonmark-flavor code block box as per-line strips. The visual
22
+ * conventions (half-stroke border inset, radius reduced by that inset) must
23
+ * stay in sync with the whole-rect box the github flavor draws in
24
+ * CodeBlockContainerView.
25
+ */
21
26
  class CodeBlockSpan(
22
27
  private val codeBlockStyle: CodeBlockStyle,
23
28
  private val context: Context,
24
29
  private val styleCache: SpanStyleCache,
30
+ private val leadingIndent: Int = 0,
25
31
  ) : MetricAffectingSpan(),
26
32
  LineBackgroundSpan,
27
33
  LeadingMarginSpan {
28
- private val blockStyle =
29
- BlockStyle(
30
- fontSize = codeBlockStyle.fontSize,
31
- fontFamily = codeBlockStyle.fontFamily,
32
- fontWeight = codeBlockStyle.fontWeight,
33
- color = codeBlockStyle.color,
34
- )
35
-
36
34
  private val path = Path()
37
35
  private val rect = RectF()
38
36
  private val arcRect = RectF()
@@ -59,7 +57,7 @@ class CodeBlockSpan(
59
57
  color = codeBlockStyle.borderColor
60
58
  }
61
59
 
62
- override fun getLeadingMargin(first: Boolean): Int = codeBlockStyle.padding.toInt()
60
+ override fun getLeadingMargin(first: Boolean): Int = codeBlockStyle.padding.toInt() + leadingIndent
63
61
 
64
62
  override fun drawLeadingMargin(
65
63
  c: Canvas?,
@@ -105,11 +103,12 @@ class CodeBlockSpan(
105
103
  val inset = codeBlockStyle.borderWidth / 2f
106
104
 
107
105
  rect.set(
108
- left.toFloat() + inset,
106
+ left.toFloat() + leadingIndent + inset,
109
107
  top.toFloat() + (if (isFirstLine) inset else 0f),
110
108
  right.toFloat() - inset,
111
109
  bottom.toFloat() - (if (isLastLine) inset else 0f),
112
110
  )
111
+ if (rect.left >= rect.right) return
113
112
 
114
113
  val radius = codeBlockStyle.borderRadius
115
114
  val adjRadius = if (radius > inset) radius - inset else radius
@@ -187,10 +186,8 @@ class CodeBlockSpan(
187
186
  }
188
187
 
189
188
  private fun applyTextStyle(tp: TextPaint) {
190
- tp.textSize = blockStyle.fontSize
191
-
192
- tp.applyBlockStyleFont(blockStyle, context)
189
+ tp.applyCodeBlockTextStyle(codeBlockStyle, context)
193
190
 
194
- tp.applyColorPreserving(blockStyle.color, *styleCache.colorsToPreserve)
191
+ tp.applyColorPreserving(codeBlockStyle.color, *styleCache.colorsToPreserve)
195
192
  }
196
193
  }
@@ -24,7 +24,7 @@ class CodeSpan(
24
24
  val preservedStyle = (paint.typeface?.style ?: 0) and (Typeface.BOLD or Typeface.ITALIC)
25
25
  paint.typeface =
26
26
  if (styleCache.codeFontFamily.isNotEmpty()) {
27
- SpanStyleCache.getTypeface(styleCache.codeFontFamily, preservedStyle)
27
+ styleCache.getTypeface(styleCache.codeFontFamily, preservedStyle)
28
28
  } else {
29
29
  SpanStyleCache.getMonospaceTypeface(preservedStyle)
30
30
  }
@@ -27,7 +27,7 @@ class EmphasisSpan(
27
27
  tp.typeface =
28
28
  if (styleCache.emphasisFontFamily.isNotEmpty()) {
29
29
  val resolvedStyle = if (styleCache.emphasisFontStyle == "normal") Typeface.NORMAL else style
30
- SpanStyleCache.getTypeface(styleCache.emphasisFontFamily, resolvedStyle)
30
+ styleCache.getTypeface(styleCache.emphasisFontFamily, resolvedStyle)
31
31
  } else if (styleCache.emphasisFontStyle == "normal") {
32
32
  currentTypeface
33
33
  } else {
@@ -7,6 +7,7 @@ import android.graphics.Color
7
7
  import android.graphics.Paint
8
8
  import android.graphics.Path
9
9
  import android.graphics.drawable.Drawable
10
+ import android.net.Uri
10
11
  import android.os.Build
11
12
  import android.text.Spannable
12
13
  import android.text.Spanned
@@ -17,9 +18,12 @@ import androidx.core.graphics.createBitmap
17
18
  import androidx.core.graphics.drawable.toDrawable
18
19
  import androidx.core.graphics.withClip
19
20
  import androidx.core.graphics.withSave
21
+ import com.swmansion.enriched.markdown.EnrichedMarkdown
22
+ import com.swmansion.enriched.markdown.EnrichedMarkdownText
20
23
  import com.swmansion.enriched.markdown.styles.StyleConfig
21
24
  import com.swmansion.enriched.markdown.utils.text.ImageCache
22
25
  import com.swmansion.enriched.markdown.utils.text.ImageDownloader
26
+ import com.swmansion.enriched.markdown.utils.text.LocalImageLoader
23
27
  import java.lang.ref.WeakReference
24
28
  import java.util.concurrent.Executors
25
29
  import android.text.style.ImageSpan as AndroidImageSpan
@@ -39,36 +43,84 @@ class ImageSpan(
39
43
  AndroidLineHeightSpan {
40
44
  private var loadedDrawable: Drawable? = null
41
45
  private val height: Int = if (isInline) styleConfig.inlineImageStyle.size.toInt() else styleConfig.imageStyle.height.toInt()
42
- private val borderRadiusPx: Int = (styleConfig.imageStyle.borderRadius * context.resources.displayMetrics.density).toInt()
46
+
47
+ private val borderRadiusPx: Int = styleConfig.imageStyle.borderRadius.toInt()
48
+ private val maxHeightPx: Int = if (isInline) 0 else styleConfig.imageStyle.maxHeight.toInt()
49
+ private val aspectRatio: Float = if (isInline) 0f else styleConfig.imageStyle.aspectRatio
50
+ private val resizeMode: String = if (isInline) "" else styleConfig.imageStyle.resizeMode
51
+
52
+ // so legacy always implies a fixed height box.
53
+ private val legacySizing: Boolean = resizeMode.isEmpty()
54
+
55
+ private val dynamicBoxHeight: Boolean = !isInline && (maxHeightPx > 0 || aspectRatio > 0f)
56
+
57
+ private var boxHeight: Int =
58
+ when {
59
+ isInline -> height
60
+ maxHeightPx > 0 -> maxHeightPx
61
+ else -> height
62
+ }
63
+
64
+ private val requestHeaders: Map<String, String> = styleConfig.imageRequestHeaders
65
+ private val requestKey: String = ImageCache.requestKey(imageUrl, requestHeaders)
43
66
 
44
67
  private var cachedWidth: Int = 0
45
68
  private var viewRef: WeakReference<TextView>? = null
46
69
  private var sourceDrawable: Drawable? = null
47
70
 
71
+ private fun intrinsicImageSize(): Pair<Int, Int> {
72
+ sourceDrawable?.let { return it.intrinsicWidth to it.intrinsicHeight }
73
+ val cached = ImageCache.getOriginal(imageUrl) ?: return 0 to 0
74
+ return cached.width to cached.height
75
+ }
76
+
77
+ // Sizing precedence: aspectRatio > maxHeight > height. Returns the legacy fixed
78
+ // height when no new knob is set.
79
+ private fun resolveBoxHeight(targetWidth: Int): Int {
80
+ if (isInline) return height
81
+ if (aspectRatio > 0f && targetWidth > 0) {
82
+ return (targetWidth / aspectRatio).toInt().coerceAtLeast(1)
83
+ }
84
+ if (maxHeightPx > 0) {
85
+ val (intrinsicWidth, intrinsicHeight) = intrinsicImageSize()
86
+ if (targetWidth > 0 && intrinsicWidth > 0 && intrinsicHeight > 0) {
87
+ val fitted = targetWidth.toFloat() * intrinsicHeight / intrinsicWidth
88
+ return minOf(maxHeightPx.toFloat(), fitted).toInt().coerceAtLeast(1)
89
+ }
90
+ return maxHeightPx
91
+ }
92
+ return height
93
+ }
94
+
95
+ fun prepareForMeasurement(
96
+ text: Spanned,
97
+ widthPx: Int,
98
+ ) {
99
+ if (!dynamicBoxHeight || widthPx <= 0) return
100
+ val available = availableWidthIn(text, widthPx)
101
+ if (available > 0) boxHeight = resolveBoxHeight(available)
102
+ }
103
+
48
104
  init {
49
105
  loadImage()
50
106
  }
51
107
 
52
108
  private fun loadImage() {
53
- if (imageUrl.startsWith("http")) {
54
- ImageDownloader.download(context, imageUrl) { bitmap ->
109
+ val scheme = Uri.parse(imageUrl).scheme?.lowercase()
110
+ if (scheme == "http" || scheme == "https") {
111
+ ImageDownloader.download(context, imageUrl, requestHeaders) { bitmap ->
55
112
  if (bitmap != null) {
56
113
  sourceDrawable = bitmap.toDrawable(context.resources)
57
114
  wrapAndAssignDrawable()
58
115
  }
59
116
  }
60
117
  } else {
61
- val path = imageUrl.removePrefix("file://")
62
- try {
63
- val cached = ImageCache.getOriginal(imageUrl)
64
- val bitmap = cached ?: ImageDownloader.decodeFileDownsampled(context, path)
65
- if (bitmap != null) {
66
- if (cached == null) ImageCache.putOriginal(imageUrl, bitmap)
67
- sourceDrawable = bitmap.toDrawable(context.resources)
68
- wrapAndAssignDrawable()
69
- }
70
- } catch (e: Exception) {
71
- Log.w(TAG, "Failed to load local image: $path", e)
118
+ val cached = ImageCache.getOriginal(imageUrl)
119
+ val bitmap = cached ?: LocalImageLoader.load(context, imageUrl)
120
+ if (bitmap != null) {
121
+ if (cached == null) ImageCache.putOriginal(imageUrl, bitmap)
122
+ sourceDrawable = bitmap.toDrawable(context.resources)
123
+ wrapAndAssignDrawable()
72
124
  }
73
125
  }
74
126
  }
@@ -83,21 +135,26 @@ class ImageSpan(
83
135
  available.coerceAtLeast(0)
84
136
  }
85
137
 
86
- val cachedBitmap = ImageCache.getProcessed(imageUrl, targetWidth, height, borderRadiusPx)
138
+ boxHeight = resolveBoxHeight(targetWidth)
139
+
140
+ val cachedBitmap = ImageCache.getProcessed(requestKey, targetWidth, boxHeight, borderRadiusPx, resizeMode)
141
+
87
142
  if (cachedBitmap != null) {
88
143
  loadedDrawable =
89
144
  cachedBitmap.toDrawable(context.resources).apply {
90
- setBounds(0, 0, targetWidth, height)
145
+ setBounds(0, 0, targetWidth, boxHeight)
91
146
  }
92
147
  } else {
93
148
  loadedDrawable =
94
149
  ScaledImageDrawable(
95
150
  imageDrawable = base,
96
151
  targetWidth = targetWidth,
97
- targetHeight = height,
152
+ targetHeight = boxHeight,
98
153
  borderRadius = borderRadiusPx,
99
154
  isBlockImage = !isInline,
100
- cacheKey = CacheKey(imageUrl, targetWidth, height, borderRadiusPx),
155
+ resizeMode = resizeMode,
156
+ legacySizing = legacySizing,
157
+ cacheKey = CacheKey(requestKey, targetWidth, boxHeight, borderRadiusPx, resizeMode),
101
158
  )
102
159
  }
103
160
  requestReflow()
@@ -116,6 +173,22 @@ class ImageSpan(
116
173
  view.invalidate()
117
174
  view.requestLayout()
118
175
  }
176
+ notifyBoxHeightMayHaveChanged(view)
177
+ }
178
+
179
+ // With maxHeight/aspectRatio the box height can change after the image loads
180
+ // (maxHeight fitted, aspectRatio at a late width). The React container height
181
+ // was measured with the pre-load value, so ask the owning component to
182
+ // re-measure; it only propagates when the stored height actually changed.
183
+ private fun notifyBoxHeightMayHaveChanged(view: TextView) {
184
+ if (!dynamicBoxHeight) return
185
+ if (view is EnrichedMarkdownText) {
186
+ view.layoutManager.invalidateLayout()
187
+ return
188
+ }
189
+ var parent = view.parent
190
+ while (parent != null && parent !is EnrichedMarkdown) parent = parent.parent
191
+ parent?.onImageLayoutChanged()
119
192
  }
120
193
 
121
194
  fun registerTextView(view: TextView) {
@@ -137,12 +210,27 @@ class ImageSpan(
137
210
  cachedWidth = newWidth
138
211
  if (sourceDrawable != null) {
139
212
  wrapAndAssignDrawable()
213
+ return
214
+ }
215
+ if (dynamicBoxHeight) {
216
+ val newBoxHeight = resolveBoxHeight(newWidth)
217
+ if (newBoxHeight != boxHeight) {
218
+ boxHeight = newBoxHeight
219
+ requestReflow()
220
+ }
140
221
  }
141
222
  }
142
223
 
143
224
  private fun getAvailableWidth(view: TextView): Int {
144
225
  val baseWidth = (view.layout?.width ?: view.width).coerceAtLeast(0)
145
226
  val text = view.text as? Spanned ?: return baseWidth
227
+ return availableWidthIn(text, baseWidth)
228
+ }
229
+
230
+ private fun availableWidthIn(
231
+ text: Spanned,
232
+ baseWidth: Int,
233
+ ): Int {
146
234
  val start = text.getSpanStart(this).takeIf { it >= 0 } ?: return baseWidth
147
235
  val end = text.getSpanEnd(this).coerceAtLeast(start)
148
236
  // Subtract leading margins (list bullet/indent, blockquote bar) that consume
@@ -159,7 +247,7 @@ class ImageSpan(
159
247
  val drawable = loadedDrawable ?: transparentDrawable
160
248
  if (drawable !is ScaledImageDrawable) {
161
249
  val drawableWidth = if (isInline) height else cachedWidth.takeIf { it > 0 } ?: drawable.intrinsicWidth
162
- drawable.setBounds(0, 0, drawableWidth.coerceAtLeast(0), height.coerceAtLeast(0))
250
+ drawable.setBounds(0, 0, drawableWidth.coerceAtLeast(0), boxHeight.coerceAtLeast(0))
163
251
  }
164
252
  return drawable
165
253
  }
@@ -182,8 +270,8 @@ class ImageSpan(
182
270
  ) {
183
271
  if (fm == null || isInline) return
184
272
  val currentLineHeight = fm.descent - fm.ascent
185
- if (height > currentLineHeight) {
186
- val extraHeight = height - currentLineHeight
273
+ if (boxHeight > currentLineHeight) {
274
+ val extraHeight = boxHeight - currentLineHeight
187
275
  fm.descent += extraHeight
188
276
  fm.bottom += extraHeight
189
277
  }
@@ -217,6 +305,7 @@ class ImageSpan(
217
305
  val width: Int,
218
306
  val height: Int,
219
307
  val borderRadius: Int,
308
+ val resizeMode: String,
220
309
  )
221
310
 
222
311
  private class ScaledImageDrawable(
@@ -225,6 +314,8 @@ class ImageSpan(
225
314
  private val targetHeight: Int,
226
315
  private val borderRadius: Int,
227
316
  isBlockImage: Boolean,
317
+ private val resizeMode: String = "",
318
+ private val legacySizing: Boolean = true,
228
319
  private val cacheKey: CacheKey? = null,
229
320
  ) : Drawable() {
230
321
  private val clipPath: Path?
@@ -235,14 +326,26 @@ class ImageSpan(
235
326
  val intrinsicWidth = imageDrawable.intrinsicWidth
236
327
  val intrinsicHeight = imageDrawable.intrinsicHeight
237
328
 
329
+ // New sizing needs a clip to the box so cropping
330
+ // modes don't spill over neighbouring lines.
331
+ val clipToBox = isBlockImage && !legacySizing
332
+
238
333
  val (scaledWidth, scaledHeight) =
239
334
  if (intrinsicWidth > 0 && intrinsicHeight > 0) {
240
- if (isBlockImage) {
241
- val scale = targetWidth.toFloat() / intrinsicWidth
242
- targetWidth to (intrinsicHeight * scale).toInt()
243
- } else {
244
- val scale = minOf(targetWidth.toFloat() / intrinsicWidth, targetHeight.toFloat() / intrinsicHeight)
245
- (intrinsicWidth * scale).toInt() to (intrinsicHeight * scale).toInt()
335
+ when {
336
+ !isBlockImage -> {
337
+ val scale = minOf(targetWidth.toFloat() / intrinsicWidth, targetHeight.toFloat() / intrinsicHeight)
338
+ (intrinsicWidth * scale).toInt() to (intrinsicHeight * scale).toInt()
339
+ }
340
+
341
+ legacySizing -> {
342
+ val scale = targetWidth.toFloat() / intrinsicWidth
343
+ targetWidth to (intrinsicHeight * scale).toInt()
344
+ }
345
+
346
+ else -> {
347
+ resizeModeSize(intrinsicWidth, intrinsicHeight)
348
+ }
246
349
  }
247
350
  } else {
248
351
  targetWidth to targetHeight
@@ -252,26 +355,53 @@ class ImageSpan(
252
355
  val top = (targetHeight - scaledHeight) / 2
253
356
  imageDrawable.setBounds(left, top, left + scaledWidth, top + scaledHeight)
254
357
 
358
+ val clipLeft = maxOf(0, left).toFloat()
359
+ val clipTop = maxOf(0, top).toFloat()
360
+ val clipRight = minOf(targetWidth, left + scaledWidth).toFloat()
361
+ val clipBottom = minOf(targetHeight, top + scaledHeight).toFloat()
255
362
  clipPath =
256
- if (borderRadius > 0) {
257
- val clipLeft = maxOf(0, left).toFloat()
258
- val clipTop = maxOf(0, top).toFloat()
259
- val clipRight = minOf(targetWidth, left + scaledWidth).toFloat()
260
- val clipBottom = minOf(targetHeight, top + scaledHeight).toFloat()
261
- Path().apply {
262
- addRoundRect(
263
- clipLeft,
264
- clipTop,
265
- clipRight,
266
- clipBottom,
267
- borderRadius.toFloat(),
268
- borderRadius.toFloat(),
269
- Path.Direction.CW,
270
- )
363
+ when {
364
+ borderRadius > 0 -> {
365
+ Path().apply {
366
+ addRoundRect(
367
+ clipLeft,
368
+ clipTop,
369
+ clipRight,
370
+ clipBottom,
371
+ borderRadius.toFloat(),
372
+ borderRadius.toFloat(),
373
+ Path.Direction.CW,
374
+ )
375
+ }
271
376
  }
272
- } else {
273
- null
377
+
378
+ clipToBox -> {
379
+ Path().apply {
380
+ addRect(clipLeft, clipTop, clipRight, clipBottom, Path.Direction.CW)
381
+ }
382
+ }
383
+
384
+ else -> {
385
+ null
386
+ }
387
+ }
388
+ }
389
+
390
+ private fun resizeModeSize(
391
+ intrinsicWidth: Int,
392
+ intrinsicHeight: Int,
393
+ ): Pair<Int, Int> {
394
+ if (resizeMode == "stretch") return targetWidth to targetHeight
395
+ val widthScale = targetWidth.toFloat() / intrinsicWidth
396
+ val heightScale = targetHeight.toFloat() / intrinsicHeight
397
+ val scale =
398
+ when (resizeMode) {
399
+ "contain" -> minOf(widthScale, heightScale)
400
+ "center" -> minOf(1f, minOf(widthScale, heightScale))
401
+ "none" -> 1f
402
+ else -> maxOf(widthScale, heightScale) // cover (default)
274
403
  }
404
+ return (intrinsicWidth * scale).toInt() to (intrinsicHeight * scale).toInt()
275
405
  }
276
406
 
277
407
  override fun draw(canvas: Canvas) {
@@ -303,7 +433,14 @@ class ImageSpan(
303
433
  } else {
304
434
  source.draw(offscreen)
305
435
  }
306
- ImageCache.putProcessed(cachedKey.url, cachedKey.width, cachedKey.height, cachedKey.borderRadius, bitmap)
436
+ ImageCache.putProcessed(
437
+ cachedKey.url,
438
+ cachedKey.width,
439
+ cachedKey.height,
440
+ cachedKey.borderRadius,
441
+ cachedKey.resizeMode,
442
+ bitmap,
443
+ )
307
444
  } catch (_: OutOfMemoryError) {
308
445
  Log.e("ScaledImageDrawable", "OOM caching bitmap ${width}x$height")
309
446
  }
@@ -328,7 +465,6 @@ class ImageSpan(
328
465
  }
329
466
 
330
467
  companion object {
331
- private const val TAG = "ImageSpan"
332
468
  private val transparentDrawable by lazy { Color.TRANSPARENT.toDrawable() }
333
469
  private val cacheExecutor = Executors.newSingleThreadExecutor()
334
470
  }
@@ -0,0 +1,140 @@
1
+ package com.swmansion.enriched.markdown.spans
2
+
3
+ import android.graphics.Canvas
4
+ import android.graphics.Paint
5
+ import android.graphics.Path
6
+ import android.graphics.RectF
7
+ import android.text.Spanned
8
+ import android.text.StaticLayout
9
+ import android.text.TextPaint
10
+ import android.text.style.LeadingMarginSpan
11
+
12
+ /**
13
+ * Shared geometry and drawing for inline "chips" painted from a [android.text.style.LineBackgroundSpan]
14
+ * (inline code, link chips). For a chip that wraps, only the outer ends are rounded and the border
15
+ * stays open where a fragment is cut.
16
+ */
17
+ internal object InlineChipPainter {
18
+ /**
19
+ * Returns the x position of [index] relative to the line's left edge, including any
20
+ * leading margin. The measuring StaticLayout is built from a subSequence that keeps
21
+ * all spans, so LeadingMarginSpans (lists, blockquotes) are already applied to
22
+ * getPrimaryHorizontal; adding the margin again on top would shift the background
23
+ * right by the indent. The margin is only added explicitly in the early-return case,
24
+ * where no layout is built.
25
+ */
26
+ fun horizontalOffset(
27
+ text: CharSequence,
28
+ lineStart: Int,
29
+ lineEnd: Int,
30
+ index: Int,
31
+ paint: Paint,
32
+ leadingMargin: Int,
33
+ ): Float {
34
+ if (index <= lineStart) return leadingMargin.toFloat()
35
+ val lineText = text.subSequence(lineStart, lineEnd)
36
+ val textPaint = paint as? TextPaint ?: TextPaint(paint)
37
+ val layout = StaticLayout.Builder.obtain(lineText, 0, lineText.length, textPaint, 10000).build()
38
+ return layout.getPrimaryHorizontal(index - lineStart)
39
+ }
40
+
41
+ fun leadingMarginAt(
42
+ text: Spanned,
43
+ lineStart: Int,
44
+ ): Int {
45
+ if (lineStart >= text.length) return 0
46
+ val spans = text.getSpans(lineStart, lineStart + 1, LeadingMarginSpan::class.java)
47
+ var margin = 0
48
+ for (span in spans) {
49
+ margin += span.getLeadingMargin(false)
50
+ }
51
+ return margin
52
+ }
53
+
54
+ /**
55
+ * Fills [rect] and strokes its border. [strokeInset] keeps a closed border inside [rect]
56
+ * (link chips); otherwise it is centered on the edge (inline code, kept for pixel parity).
57
+ * [path] is caller-owned scratch space to avoid per-draw allocations.
58
+ */
59
+ fun draw(
60
+ canvas: Canvas,
61
+ rect: RectF,
62
+ path: Path,
63
+ cornerRadius: Float,
64
+ backgroundPaint: Paint?,
65
+ borderPaint: Paint?,
66
+ isFirst: Boolean,
67
+ isLast: Boolean,
68
+ strokeInset: Boolean,
69
+ ) {
70
+ val r = minOf(maxOf(cornerRadius, 0f), minOf(rect.width(), rect.height()) / 2f)
71
+
72
+ if (backgroundPaint != null) {
73
+ path.reset()
74
+ path.addRoundRect(rect, radii(r, isFirst, isLast), Path.Direction.CW)
75
+ canvas.drawPath(path, backgroundPaint)
76
+ }
77
+
78
+ if (borderPaint == null || borderPaint.strokeWidth <= 0f) return
79
+
80
+ path.reset()
81
+ if (isFirst && isLast) {
82
+ if (strokeInset) {
83
+ val inset = borderPaint.strokeWidth / 2f
84
+ val insetRect = RectF(rect.left + inset, rect.top + inset, rect.right - inset, rect.bottom - inset)
85
+ path.addRoundRect(insetRect, radii(maxOf(r - inset, 0f), true, true), Path.Direction.CW)
86
+ } else {
87
+ path.addRoundRect(rect, radii(r, true, true), Path.Direction.CW)
88
+ }
89
+ } else {
90
+ val inset = if (strokeInset) borderPaint.strokeWidth / 2f else 0f
91
+ addOpenBorder(path, rect, r, inset, isFirst, isLast)
92
+ }
93
+ canvas.drawPath(path, borderPaint)
94
+ }
95
+
96
+ private fun addOpenBorder(
97
+ path: Path,
98
+ rect: RectF,
99
+ r: Float,
100
+ inset: Float,
101
+ isFirst: Boolean,
102
+ isLast: Boolean,
103
+ ) {
104
+ val left = rect.left + inset
105
+ val top = rect.top + inset
106
+ val right = rect.right - inset
107
+ val bottom = rect.bottom - inset
108
+
109
+ if (isFirst) {
110
+ path.moveTo(rect.right, top)
111
+ path.lineTo(left + r, top)
112
+ path.quadTo(left, top, left, top + r)
113
+ path.lineTo(left, bottom - r)
114
+ path.quadTo(left, bottom, left + r, bottom)
115
+ path.lineTo(rect.right, bottom)
116
+ } else if (isLast) {
117
+ path.moveTo(rect.left, top)
118
+ path.lineTo(right - r, top)
119
+ path.quadTo(right, top, right, top + r)
120
+ path.lineTo(right, bottom - r)
121
+ path.quadTo(right, bottom, right - r, bottom)
122
+ path.lineTo(rect.left, bottom)
123
+ } else {
124
+ path.moveTo(rect.left, top)
125
+ path.lineTo(rect.right, top)
126
+ path.moveTo(rect.left, bottom)
127
+ path.lineTo(rect.right, bottom)
128
+ }
129
+ }
130
+
131
+ private fun radii(
132
+ r: Float,
133
+ isFirst: Boolean,
134
+ isLast: Boolean,
135
+ ): FloatArray {
136
+ val left = if (isFirst) r else 0f
137
+ val right = if (isLast) r else 0f
138
+ return floatArrayOf(left, left, right, right, right, right, left, left)
139
+ }
140
+ }