react-native-enriched-markdown-scaffold 0.7.4-scaffold.9 → 1.0.2-scaffold.2

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 (469) hide show
  1. package/README.md +54 -8
  2. package/ReactNativeEnrichedMarkdown.podspec +82 -73
  3. package/android/build.gradle +186 -1
  4. package/android/consumer-rules.pro +1 -1
  5. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerDelegate.java +9 -0
  6. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java +3 -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 +9 -0
  10. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +3 -0
  11. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +75 -0
  12. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +63 -0
  13. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +35 -0
  14. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +886 -23
  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 +189 -13
  18. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt +17 -0
  19. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownManager.kt +50 -0
  20. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +48 -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 +42 -0
  23. package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +82 -4
  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/input/EnrichedMarkdownTextInputManager.kt +54 -4
  26. package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputView.kt +901 -462
  27. package/android/src/main/java/com/swmansion/enriched/markdown/input/MarkdownClipboard.kt +42 -0
  28. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/BlockEditCoordinator.kt +196 -0
  29. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/ClipboardCoordinator.kt +73 -0
  30. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/EditContext.kt +19 -0
  31. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/EditPipeline.kt +248 -0
  32. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/EditSession.kt +52 -0
  33. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/InputConnectionWrapper.kt +101 -7
  34. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/LinkCoordinator.kt +69 -0
  35. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/MarkdownTextWatcher.kt +3 -3
  36. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/MentionCoordinator.kt +118 -0
  37. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnChangeStateEvent.kt +26 -0
  38. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnContextMenuItemPressEvent.kt +26 -0
  39. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnInputKeyPressEvent.kt +24 -0
  40. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnPasteEvent.kt +24 -0
  41. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/BlockStore.kt +254 -0
  42. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/FormattingStore.kt +80 -87
  43. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputFormatter.kt +109 -1
  44. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputParser.kt +116 -22
  45. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/MarkdownSerializer.kt +167 -38
  46. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/RangeEditAdjustment.kt +149 -0
  47. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputEventEmitter.kt +66 -5
  48. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputMeasurementStore.kt +4 -2
  49. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/BlockRange.kt +27 -0
  50. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/BlockType.kt +48 -0
  51. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/FormattingRange.kt +9 -4
  52. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/InputFormatterStyle.kt +39 -2
  53. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathAtom.kt +20 -0
  54. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathChipStyle.kt +1 -1
  55. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MutableRangeBounds.kt +11 -0
  56. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputBulletSpan.kt +82 -0
  57. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputHeadingSpan.kt +58 -0
  58. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputListItemSpacingSpan.kt +37 -0
  59. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputOrderedListMarkerSpan.kt +63 -0
  60. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/BlockHandler.kt +54 -0
  61. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/HeadingBlockHandler.kt +27 -0
  62. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/OrderedListBlockHandler.kt +38 -0
  63. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/UnorderedListBlockHandler.kt +37 -0
  64. package/android/src/main/java/com/swmansion/enriched/markdown/input/toolbar/InputContextMenu.kt +8 -26
  65. package/android/src/main/java/com/swmansion/enriched/markdown/parser/MarkdownASTNode.kt +1 -0
  66. package/android/src/main/java/com/swmansion/enriched/markdown/parser/Parser.kt +1 -0
  67. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockStyleContext.kt +9 -2
  68. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt +100 -12
  69. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeBlockRenderer.kt +16 -1
  70. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +4 -0
  71. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListContextManager.kt +2 -1
  72. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListItemRenderer.kt +74 -18
  73. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListRenderer.kt +43 -4
  74. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/NodeRenderer.kt +9 -1
  75. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SoftBreakRenderer.kt +16 -0
  76. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +30 -27
  77. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BaseListSpan.kt +24 -0
  78. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt +174 -24
  79. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBackgroundSpan.kt +27 -3
  80. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBlockSpan.kt +13 -16
  81. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeSpan.kt +1 -1
  82. package/android/src/main/java/com/swmansion/enriched/markdown/spans/EmphasisSpan.kt +1 -1
  83. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ImageSpan.kt +182 -46
  84. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ListItemSpacingSpan.kt +33 -0
  85. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ListMarkerAnchorSpan.kt +38 -0
  86. package/android/src/main/java/com/swmansion/enriched/markdown/spans/OrderedListSpan.kt +2 -0
  87. package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrongSpan.kt +1 -1
  88. package/android/src/main/java/com/swmansion/enriched/markdown/spans/TaskListSpan.kt +3 -2
  89. package/android/src/main/java/com/swmansion/enriched/markdown/spans/UnorderedListSpan.kt +3 -2
  90. package/android/src/main/java/com/swmansion/enriched/markdown/styles/BlockquoteStyle.kt +6 -0
  91. package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeBlockStyle.kt +26 -0
  92. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ImageStyle.kt +7 -1
  93. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ListStyle.kt +4 -1
  94. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt +13 -4
  95. package/android/src/main/java/com/swmansion/enriched/markdown/styles/TableStyle.kt +6 -0
  96. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/CodeBlockHighlighter.kt +90 -0
  97. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/CodeBlockNode.kt +57 -0
  98. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/FeatureFlags.kt +1 -0
  99. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownSegment.kt +9 -0
  100. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt +37 -7
  101. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/ReadableMapExtensions.kt +3 -0
  102. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/RenderedSegment.kt +10 -0
  103. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/SegmentSignature.kt +1 -0
  104. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/StreamingMarkdownFilter.kt +83 -5
  105. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/serialization/MarkdownASTSerializer.kt +4 -0
  106. package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/MarkdownStyleParser.kt +74 -44
  107. package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/PasteTextUtils.kt +20 -0
  108. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/ImageCache.kt +26 -3
  109. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/ImageDownloader.kt +22 -9
  110. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/LocalImageLoader.kt +161 -0
  111. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/extensions/TextPaintExtensions.kt +23 -0
  112. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/interaction/CheckboxTouchHelper.kt +7 -0
  113. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/interaction/TaskListTapUtils.kt +41 -21
  114. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/span/BlockSpacing.kt +15 -8
  115. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkLongPressMovementMethod.kt +58 -27
  116. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionActionMode.kt +49 -15
  117. package/android/src/main/java/com/swmansion/enriched/markdown/views/BlockMenuOptions.kt +45 -0
  118. package/android/src/main/java/com/swmansion/enriched/markdown/views/CodeBlockContainerView.kt +396 -0
  119. package/android/src/main/java/com/swmansion/enriched/markdown/views/ContextMenuPopup.kt +9 -6
  120. package/android/src/main/java/com/swmansion/enriched/markdown/views/CopyGlyph.kt +101 -0
  121. package/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt +36 -9
  122. package/android/src/main/jni/CMakeLists.txt +53 -0
  123. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownContainerShadowNode.cpp +10 -0
  124. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownContainerShadowNode.h +11 -2
  125. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.cpp +10 -0
  126. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.h +12 -2
  127. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextState.cpp +9 -0
  128. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextState.h +24 -0
  129. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/conversions.h +16 -0
  130. package/android/src/math/java/com/swmansion/enriched/markdown/input/math/MathChipControllerImpl.kt +21 -4
  131. package/android/src/math/java/com/swmansion/enriched/markdown/renderer/MathInlineRenderer.kt +7 -2
  132. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathChipSpan.kt +1 -1
  133. package/android/src/math/java/com/swmansion/enriched/markdown/views/MathContainerView.kt +6 -4
  134. package/cpp/highlight/CodeBlockHighlighter.cpp +284 -0
  135. package/cpp/highlight/CodeBlockHighlighter.hpp +66 -0
  136. package/cpp/highlight/CodeBlockLanguages.cpp +138 -0
  137. package/cpp/highlight/CodeBlockLanguages.hpp +25 -0
  138. package/cpp/highlight/HighlightGrammars.hpp +28 -0
  139. package/cpp/highlight/code_highlight_podspec.rb +211 -0
  140. package/cpp/highlight/gen-registry.mjs +155 -0
  141. package/cpp/highlight/grammar-versions.json +159 -0
  142. package/cpp/highlight/vendor/generated/generated_queries.h +1665 -0
  143. package/cpp/highlight/vendor/generated/generated_registry.cpp +59 -0
  144. package/cpp/parser/MD4CParser.cpp +173 -61
  145. package/cpp/parser/MD4CParser.hpp +1 -0
  146. package/cpp/parser/MarkdownASTNode.hpp +2 -1
  147. package/cpp/wasm/ASTSerializer.cpp +2 -0
  148. package/cpp/wasm/build.sh +1 -0
  149. package/cpp/wasm/md4c_wasm.cpp +3 -1
  150. package/docs/ACCESSIBILITY.md +14 -2
  151. package/docs/API_REFERENCE.md +234 -12
  152. package/docs/BREAKING_CHANGES.md +129 -0
  153. package/docs/CODE_HIGHLIGHT.md +133 -0
  154. package/docs/COPY_OPTIONS.md +47 -3
  155. package/docs/ELEMENTS_STRUCTURE.md +52 -4
  156. package/docs/IMAGE_CACHING.md +30 -0
  157. package/docs/INPUT.md +108 -11
  158. package/docs/LATEX_MATH.md +87 -45
  159. package/docs/MACOS.md +1 -1
  160. package/docs/MARKDOWN_STREAMING.md +27 -1
  161. package/docs/NATIVE_ASSETS.md +127 -0
  162. package/docs/RTL.md +1 -1
  163. package/docs/STYLES.md +46 -6
  164. package/docs/TESTING.md +112 -0
  165. package/docs/TEXT.md +16 -6
  166. package/docs/WEB.md +3 -1
  167. package/ios/EnrichedMarkdown.h +7 -0
  168. package/ios/EnrichedMarkdown.mm +284 -75
  169. package/ios/EnrichedMarkdownText.h +7 -0
  170. package/ios/EnrichedMarkdownText.mm +101 -73
  171. package/ios/attachments/ENRMImageAttachment.h +9 -0
  172. package/ios/attachments/ENRMImageAttachment.m +143 -40
  173. package/ios/attachments/ENRMMathInlineAttachment.h +2 -0
  174. package/ios/attachments/ENRMMathInlineAttachment.m +48 -81
  175. package/ios/attachments/ENRMMathInlineAttachmentShared.h +2 -0
  176. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.cpp +75 -0
  177. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.h +63 -0
  178. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp +35 -0
  179. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +886 -23
  180. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +131 -0
  181. package/ios/input/ENRMAutoLinkDetector.h +2 -1
  182. package/ios/input/ENRMAutoLinkDetector.mm +79 -41
  183. package/ios/input/ENRMBlockEditCoordinator.h +71 -0
  184. package/ios/input/ENRMBlockEditCoordinator.mm +195 -0
  185. package/ios/input/ENRMBlockRange.h +28 -0
  186. package/ios/input/ENRMBlockRange.mm +30 -0
  187. package/ios/input/ENRMBlockStore.h +56 -0
  188. package/ios/input/ENRMBlockStore.mm +275 -0
  189. package/ios/input/ENRMClipboardCoordinator.h +45 -0
  190. package/ios/input/ENRMClipboardCoordinator.mm +120 -0
  191. package/ios/input/ENRMDetectorPipeline.h +2 -1
  192. package/ios/input/ENRMEditPipeline.h +76 -0
  193. package/ios/input/ENRMEditPipeline.mm +228 -0
  194. package/ios/input/ENRMEditSession.h +36 -0
  195. package/ios/input/ENRMEditSession.mm +63 -0
  196. package/ios/input/ENRMFormattingStore.h +17 -0
  197. package/ios/input/ENRMFormattingStore.mm +95 -105
  198. package/ios/input/ENRMInputBlockType.h +91 -0
  199. package/ios/input/ENRMInputBlockType.mm +5 -0
  200. package/ios/input/ENRMInputDecorationDrawer.h +18 -0
  201. package/ios/input/ENRMInputEventEmitter.h +56 -0
  202. package/ios/input/ENRMInputEventEmitter.mm +308 -0
  203. package/ios/input/ENRMInputFormatter.h +29 -69
  204. package/ios/input/ENRMInputFormatter.mm +216 -124
  205. package/ios/input/ENRMInputFormatterStyle.h +99 -0
  206. package/ios/input/ENRMInputFormatterStyle.mm +188 -0
  207. package/ios/input/ENRMInputLayoutManager.h +9 -0
  208. package/ios/input/ENRMInputLayoutManager.mm +30 -0
  209. package/ios/input/ENRMInputListMarkerDrawer.h +32 -0
  210. package/ios/input/ENRMInputListMarkerDrawer.mm +426 -0
  211. package/ios/input/ENRMInputParser.h +5 -6
  212. package/ios/input/ENRMInputParser.mm +461 -178
  213. package/ios/input/ENRMInputRemend.mm +2 -2
  214. package/ios/input/ENRMInputStyleStateBuilder.h +40 -0
  215. package/ios/input/ENRMInputStyleStateBuilder.mm +60 -0
  216. package/ios/input/ENRMInputTextView.mm +103 -8
  217. package/ios/input/ENRMInputTypingAttributesController.h +42 -0
  218. package/ios/input/ENRMInputTypingAttributesController.mm +203 -0
  219. package/ios/input/ENRMLinkCoordinator.h +41 -0
  220. package/ios/input/ENRMLinkCoordinator.mm +89 -0
  221. package/ios/input/ENRMMarkdownSerializer.h +29 -5
  222. package/ios/input/ENRMMarkdownSerializer.mm +170 -48
  223. package/ios/input/ENRMMathAtom.h +26 -0
  224. package/ios/input/ENRMMathAtom.mm +12 -0
  225. package/ios/input/ENRMMentionCoordinator.h +45 -0
  226. package/ios/input/ENRMMentionCoordinator.mm +167 -0
  227. package/ios/input/ENRMRangeEditAdjustment.h +38 -0
  228. package/ios/input/ENRMRangeEditAdjustment.mm +91 -0
  229. package/ios/input/ENRMRangeStoreUtils.h +39 -0
  230. package/ios/input/EnrichedMarkdownTextInput+ContextMenu.mm +6 -6
  231. package/ios/input/EnrichedMarkdownTextInput+Internal.h +11 -3
  232. package/ios/input/EnrichedMarkdownTextInput.h +7 -1
  233. package/ios/input/EnrichedMarkdownTextInput.mm +1089 -1023
  234. package/ios/input/InputStylePropsUtils.h +109 -68
  235. package/ios/input/internals/EnrichedMarkdownTextInputShadowNode.mm +2 -1
  236. package/ios/input/styles/ENRMBlockHandler.h +46 -0
  237. package/ios/input/styles/ENRMHeadingBlockHandler.h +15 -0
  238. package/ios/input/styles/ENRMHeadingBlockHandler.mm +38 -0
  239. package/ios/input/styles/ENRMOrderedListBlockHandler.h +14 -0
  240. package/ios/input/styles/ENRMOrderedListBlockHandler.mm +48 -0
  241. package/ios/input/styles/ENRMUnorderedListBlockHandler.h +15 -0
  242. package/ios/input/styles/ENRMUnorderedListBlockHandler.mm +51 -0
  243. package/ios/internals/ENRMViewFreeMeasurement.h +331 -0
  244. package/ios/internals/EnrichedMarkdownShadowNode.h +1 -3
  245. package/ios/internals/EnrichedMarkdownShadowNode.mm +16 -20
  246. package/ios/internals/EnrichedMarkdownTextShadowNode.h +1 -3
  247. package/ios/internals/EnrichedMarkdownTextShadowNode.mm +15 -20
  248. package/ios/internals/MeasurementCache.h +33 -7
  249. package/ios/internals/ShadowMeasurementUtils.h +63 -58
  250. package/ios/math/ENRMMathChipController.h +74 -0
  251. package/ios/math/ENRMMathChipController.mm +476 -0
  252. package/ios/math/ENRMRaTeXBridge.swift +4 -1
  253. package/ios/parser/ENRMMarkdownParser.h +1 -8
  254. package/ios/parser/ENRMMarkdownParser.mm +2 -11
  255. package/ios/parser/MarkdownASTNode.h +2 -1
  256. package/ios/parser/MarkdownParserBridge.mm +4 -0
  257. package/ios/renderer/AttributedRenderer.m +20 -2
  258. package/ios/renderer/BaseRenderer.h +17 -2
  259. package/ios/renderer/BaseRenderer.m +30 -0
  260. package/ios/renderer/BlockquoteRenderer.h +1 -1
  261. package/ios/renderer/BlockquoteRenderer.m +144 -35
  262. package/ios/renderer/CodeBlockRenderer.h +1 -1
  263. package/ios/renderer/CodeBlockRenderer.m +27 -23
  264. package/ios/renderer/CodeRenderer.h +1 -1
  265. package/ios/renderer/CodeRenderer.m +3 -1
  266. package/ios/renderer/ENRMImageRenderer.h +1 -1
  267. package/ios/renderer/ENRMImageRenderer.m +5 -1
  268. package/ios/renderer/ENRMMathInlineRenderer.h +1 -1
  269. package/ios/renderer/ENRMMathInlineRenderer.m +5 -1
  270. package/ios/renderer/ENRMSpoilerRenderer.h +1 -1
  271. package/ios/renderer/ENRMSpoilerRenderer.m +3 -1
  272. package/ios/renderer/EmphasisRenderer.h +1 -1
  273. package/ios/renderer/EmphasisRenderer.m +3 -1
  274. package/ios/renderer/HeadingRenderer.h +1 -1
  275. package/ios/renderer/HeadingRenderer.m +13 -6
  276. package/ios/renderer/HighlightRenderer.h +1 -1
  277. package/ios/renderer/HighlightRenderer.m +3 -1
  278. package/ios/renderer/LinkRenderer.h +1 -1
  279. package/ios/renderer/LinkRenderer.m +3 -1
  280. package/ios/renderer/ListItemRenderer.h +13 -1
  281. package/ios/renderer/ListItemRenderer.m +102 -44
  282. package/ios/renderer/ListRenderer.h +2 -2
  283. package/ios/renderer/ListRenderer.m +63 -25
  284. package/ios/renderer/ParagraphRenderer.h +1 -1
  285. package/ios/renderer/ParagraphRenderer.m +16 -8
  286. package/ios/renderer/RenderContext.h +10 -0
  287. package/ios/renderer/RenderContext.m +44 -0
  288. package/ios/renderer/RendererFactory.m +14 -0
  289. package/ios/renderer/StrikethroughRenderer.h +1 -1
  290. package/ios/renderer/StrikethroughRenderer.m +3 -1
  291. package/ios/renderer/StrongRenderer.h +1 -1
  292. package/ios/renderer/StrongRenderer.m +3 -1
  293. package/ios/renderer/SubscriptRenderer.h +1 -1
  294. package/ios/renderer/SubscriptRenderer.m +3 -1
  295. package/ios/renderer/SuperscriptRenderer.h +1 -1
  296. package/ios/renderer/SuperscriptRenderer.m +3 -1
  297. package/ios/renderer/TextRenderer.h +2 -2
  298. package/ios/renderer/TextRenderer.m +3 -1
  299. package/ios/renderer/ThematicBreakRenderer.h +1 -1
  300. package/ios/renderer/ThematicBreakRenderer.m +3 -1
  301. package/ios/renderer/UnderlineRenderer.h +1 -1
  302. package/ios/renderer/UnderlineRenderer.m +3 -1
  303. package/ios/styles/StyleConfig.h +22 -0
  304. package/ios/styles/StyleConfig.mm +132 -0
  305. package/ios/utils/BlockquoteBorder.h +6 -0
  306. package/ios/utils/BlockquoteBorder.m +249 -52
  307. package/ios/utils/CodeBlockBackground.m +16 -2
  308. package/ios/utils/ENRMAtomicSize.h +65 -0
  309. package/ios/utils/ENRMBlockMenu.h +57 -0
  310. package/ios/utils/ENRMCodeBlockContent.h +37 -0
  311. package/ios/utils/ENRMCodeBlockContent.mm +79 -0
  312. package/ios/utils/ENRMCodeBlockHighlighter.h +37 -0
  313. package/ios/utils/ENRMCodeBlockHighlighter.mm +51 -0
  314. package/ios/utils/ENRMFeatureFlags.h +7 -0
  315. package/ios/utils/ENRMImageDownloader.h +11 -1
  316. package/ios/utils/ENRMImageDownloader.m +60 -16
  317. package/ios/utils/ENRMLocalImageLoader.h +31 -0
  318. package/ios/utils/ENRMLocalImageLoader.m +68 -0
  319. package/ios/utils/ENRMMathFallback.h +26 -0
  320. package/ios/utils/ENRMMathFallback.m +18 -0
  321. package/ios/utils/ENRMTextViewSetup.h +35 -17
  322. package/ios/utils/EditMenuUtils.h +22 -5
  323. package/ios/utils/EditMenuUtils.m +53 -9
  324. package/ios/utils/ImageRequestHeaderUtils.h +35 -0
  325. package/ios/utils/LastElementUtils.h +1 -0
  326. package/ios/utils/ListMarkerDrawer.m +29 -42
  327. package/ios/utils/MarkdownASTSerializer.m +4 -0
  328. package/ios/utils/ParagraphStyleUtils.h +5 -0
  329. package/ios/utils/ParagraphStyleUtils.m +77 -17
  330. package/ios/utils/RenderedMarkdownSegment.h +13 -1
  331. package/ios/utils/RenderedMarkdownSegment.m +20 -0
  332. package/ios/utils/SegmentRenderer.m +17 -4
  333. package/ios/utils/StreamingMarkdownFilter.h +11 -1
  334. package/ios/utils/StreamingMarkdownFilter.m +98 -2
  335. package/ios/utils/StylePropsUtils.h +63 -0
  336. package/ios/utils/TaskListTapUtils.m +24 -0
  337. package/ios/views/ENRMCodeBlockContainerView.h +53 -0
  338. package/ios/views/ENRMCodeBlockContainerView.m +559 -0
  339. package/ios/views/ENRMMathContainerView.h +16 -0
  340. package/ios/views/ENRMMathContainerView.m +74 -19
  341. package/ios/views/TableContainerView.h +22 -0
  342. package/ios/views/TableContainerView.m +261 -175
  343. package/jest.d.ts +1 -0
  344. package/jest.js +5 -0
  345. package/lib/module/EnrichedMarkdownNativeComponent.ts +73 -0
  346. package/lib/module/EnrichedMarkdownTextInput.js +84 -5
  347. package/lib/module/EnrichedMarkdownTextInput.js.map +1 -1
  348. package/lib/module/EnrichedMarkdownTextInputNativeComponent.ts +78 -5
  349. package/lib/module/EnrichedMarkdownTextNativeComponent.ts +74 -0
  350. package/lib/module/headingDefaults.js +34 -0
  351. package/lib/module/headingDefaults.js.map +1 -0
  352. package/lib/module/index.js.map +1 -1
  353. package/lib/module/jest/index.js +191 -0
  354. package/lib/module/jest/index.js.map +1 -0
  355. package/lib/module/native/EnrichedMarkdownText.js +37 -5
  356. package/lib/module/native/EnrichedMarkdownText.js.map +1 -1
  357. package/lib/module/normalizeMarkdownStyle.js +81 -19
  358. package/lib/module/normalizeMarkdownStyle.js.map +1 -1
  359. package/lib/module/normalizeMarkdownStyle.web.js +56 -18
  360. package/lib/module/normalizeMarkdownStyle.web.js.map +1 -1
  361. package/lib/module/normalizeMarkdownTextInputStyle.js +62 -15
  362. package/lib/module/normalizeMarkdownTextInputStyle.js.map +1 -1
  363. package/lib/module/normalizeMenuItem.js +1 -1
  364. package/lib/module/utils/textInputState.js +26 -0
  365. package/lib/module/utils/textInputState.js.map +1 -0
  366. package/lib/module/web/EnrichedMarkdownText.js +9 -5
  367. package/lib/module/web/EnrichedMarkdownText.js.map +1 -1
  368. package/lib/module/web/parseMarkdown.js +4 -3
  369. package/lib/module/web/parseMarkdown.js.map +1 -1
  370. package/lib/module/web/renderers/InlineRenderers.js +6 -0
  371. package/lib/module/web/renderers/InlineRenderers.js.map +1 -1
  372. package/lib/module/web/renderers/ListRenderers.js +7 -2
  373. package/lib/module/web/renderers/ListRenderers.js.map +1 -1
  374. package/lib/module/web/renderers/index.js +7 -4
  375. package/lib/module/web/renderers/index.js.map +1 -1
  376. package/lib/module/web/styles.js +83 -6
  377. package/lib/module/web/styles.js.map +1 -1
  378. package/lib/module/web/utils.js +1 -0
  379. package/lib/module/web/utils.js.map +1 -1
  380. package/lib/module/web/wasm/md4c.js +0 -0
  381. package/lib/module/web/wasm/md4c.js.map +1 -1
  382. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts +66 -0
  383. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -1
  384. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts +94 -9
  385. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts.map +1 -1
  386. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts +69 -5
  387. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts.map +1 -1
  388. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +66 -0
  389. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -1
  390. package/lib/typescript/src/headingDefaults.d.ts +9 -0
  391. package/lib/typescript/src/headingDefaults.d.ts.map +1 -0
  392. package/lib/typescript/src/index.d.ts +2 -2
  393. package/lib/typescript/src/index.d.ts.map +1 -1
  394. package/lib/typescript/src/index.web.d.ts +1 -1
  395. package/lib/typescript/src/index.web.d.ts.map +1 -1
  396. package/lib/typescript/src/jest/index.d.ts +6 -0
  397. package/lib/typescript/src/jest/index.d.ts.map +1 -0
  398. package/lib/typescript/src/native/EnrichedMarkdownText.d.ts +3 -3
  399. package/lib/typescript/src/native/EnrichedMarkdownText.d.ts.map +1 -1
  400. package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -1
  401. package/lib/typescript/src/normalizeMarkdownStyle.web.d.ts.map +1 -1
  402. package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts +19 -5
  403. package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts.map +1 -1
  404. package/lib/typescript/src/types/MarkdownStyle.d.ts +72 -0
  405. package/lib/typescript/src/types/MarkdownStyle.d.ts.map +1 -1
  406. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts +27 -0
  407. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts.map +1 -1
  408. package/lib/typescript/src/types/MarkdownTextProps.d.ts +104 -9
  409. package/lib/typescript/src/types/MarkdownTextProps.d.ts.map +1 -1
  410. package/lib/typescript/src/types/MarkdownTextProps.web.d.ts +19 -0
  411. package/lib/typescript/src/types/MarkdownTextProps.web.d.ts.map +1 -1
  412. package/lib/typescript/src/types/events.d.ts +19 -0
  413. package/lib/typescript/src/types/events.d.ts.map +1 -1
  414. package/lib/typescript/src/utils/textInputState.d.ts +24 -0
  415. package/lib/typescript/src/utils/textInputState.d.ts.map +1 -0
  416. package/lib/typescript/src/web/EnrichedMarkdownText.d.ts +1 -1
  417. package/lib/typescript/src/web/EnrichedMarkdownText.d.ts.map +1 -1
  418. package/lib/typescript/src/web/parseMarkdown.d.ts +1 -1
  419. package/lib/typescript/src/web/parseMarkdown.d.ts.map +1 -1
  420. package/lib/typescript/src/web/renderers/InlineRenderers.d.ts.map +1 -1
  421. package/lib/typescript/src/web/renderers/ListRenderers.d.ts.map +1 -1
  422. package/lib/typescript/src/web/renderers/index.d.ts +2 -1
  423. package/lib/typescript/src/web/renderers/index.d.ts.map +1 -1
  424. package/lib/typescript/src/web/styles.d.ts +2 -1
  425. package/lib/typescript/src/web/styles.d.ts.map +1 -1
  426. package/lib/typescript/src/web/types.d.ts +6 -2
  427. package/lib/typescript/src/web/types.d.ts.map +1 -1
  428. package/lib/typescript/src/web/utils.d.ts.map +1 -1
  429. package/package.json +36 -9
  430. package/postinstall.mjs +131 -0
  431. package/ratex-version.json +21 -0
  432. package/src/EnrichedMarkdownNativeComponent.ts +73 -0
  433. package/src/EnrichedMarkdownTextInput.tsx +159 -8
  434. package/src/EnrichedMarkdownTextInputNativeComponent.ts +78 -5
  435. package/src/EnrichedMarkdownTextNativeComponent.ts +74 -0
  436. package/src/headingDefaults.ts +21 -0
  437. package/src/index.tsx +9 -0
  438. package/src/index.web.tsx +1 -0
  439. package/src/jest/index.tsx +215 -0
  440. package/src/native/EnrichedMarkdownText.tsx +53 -2
  441. package/src/normalizeMarkdownStyle.ts +102 -16
  442. package/src/normalizeMarkdownStyle.web.ts +63 -15
  443. package/src/normalizeMarkdownTextInputStyle.ts +110 -35
  444. package/src/normalizeMenuItem.ts +1 -1
  445. package/src/types/MarkdownStyle.ts +74 -0
  446. package/src/types/MarkdownStyleInternal.ts +39 -0
  447. package/src/types/MarkdownTextProps.ts +101 -9
  448. package/src/types/MarkdownTextProps.web.ts +19 -0
  449. package/src/types/events.ts +21 -0
  450. package/src/utils/textInputState.ts +35 -0
  451. package/src/web/EnrichedMarkdownText.tsx +16 -2
  452. package/src/web/parseMarkdown.ts +6 -2
  453. package/src/web/renderers/InlineRenderers.tsx +5 -0
  454. package/src/web/renderers/ListRenderers.tsx +14 -2
  455. package/src/web/renderers/index.tsx +6 -2
  456. package/src/web/styles.ts +89 -5
  457. package/src/web/types.ts +6 -1
  458. package/src/web/utils.ts +1 -0
  459. package/src/web/wasm/md4c.js +0 -0
  460. package/vendor-grammars.mjs +511 -0
  461. package/vendor-ratex.mjs +173 -0
  462. package/app.plugin.js +0 -2
  463. package/plugin/build/withAndroidMath.js +0 -19
  464. package/plugin/build/withIosMath.js +0 -28
  465. package/plugin/build/withReactNativeEnrichedMarkdown.js +0 -11
  466. package/plugin/src/withAndroidMath.ts +0 -24
  467. package/plugin/src/withIosMath.ts +0 -35
  468. package/plugin/src/withReactNativeEnrichedMarkdown.ts +0 -17
  469. package/plugin/tsconfig.build.json +0 -16
@@ -3,8 +3,11 @@ package com.swmansion.enriched.markdown.utils.input
3
3
  import android.graphics.Color
4
4
  import android.text.Layout
5
5
  import com.facebook.react.bridge.ReadableMap
6
+ import com.facebook.react.common.ReactConstants
6
7
  import com.facebook.react.uimanager.PixelUtil
8
+ import com.facebook.react.views.text.ReactTypefaceUtils
7
9
  import com.swmansion.enriched.markdown.input.model.InputFormatterStyle
10
+ import com.swmansion.enriched.markdown.input.model.InputHeadingStyle
8
11
  import com.swmansion.enriched.markdown.input.model.InputLinkVariantStyle
9
12
  import com.swmansion.enriched.markdown.input.model.MathBlockStyle
10
13
  import com.swmansion.enriched.markdown.input.model.MathChipStyle
@@ -15,11 +18,12 @@ object MarkdownStyleParser {
15
18
  val emMap = map.getMap("em")
16
19
  val linkMap = map.getMap("link")
17
20
  val spoilerMap = map.getMap("spoiler")
18
- val mathMap = map.getMap("math")
19
- val mathBlockMap = map.getMap("mathBlock")
21
+ val inlineMathMap = map.getMap("inlineMath")
22
+ val blockMathMap = map.getMap("math")
20
23
 
21
- val math = parseMathStyle(mathMap)
22
- val mathBlock = parseMathBlockStyle(mathBlockMap, math)
24
+ val inlineMath = parseInlineMathStyle(inlineMathMap)
25
+ val math = parseBlockMathStyle(blockMathMap, inlineMath)
26
+ val listMap = map.getMap("list")
23
27
 
24
28
  return InputFormatterStyle(
25
29
  boldColor = if (strongMap?.hasKey("color") == true) strongMap.getInt("color") else null,
@@ -30,11 +34,37 @@ object MarkdownStyleParser {
30
34
  linkVariants = parseLinkVariants(map),
31
35
  spoilerColor = spoilerMap!!.getInt("color"),
32
36
  spoilerBackgroundColor = spoilerMap.getInt("backgroundColor"),
37
+ inlineMath = inlineMath,
33
38
  math = math,
34
- mathBlock = mathBlock,
39
+ headings = parseHeadings(map),
40
+ listItemSpacing =
41
+ if (listMap?.hasKey("itemSpacing") == true) listMap.getDouble("itemSpacing").toFloat() else 0f,
35
42
  )
36
43
  }
37
44
 
45
+ // Mirrors the readonly renderer's h1..h6 markdownStyle. fontSize arrives in SP
46
+ // (matching the JS prop) and is converted to px so the input span can size text
47
+ // identically to the read view.
48
+ private fun parseHeadings(map: ReadableMap): List<InputHeadingStyle> =
49
+ (1..6).map { level ->
50
+ val headingMap = map.getMap("h$level")
51
+ InputHeadingStyle(
52
+ fontSizePx =
53
+ if (headingMap?.hasKey("fontSize") == true) {
54
+ PixelUtil.toPixelFromSP(headingMap.getDouble("fontSize"))
55
+ } else {
56
+ null
57
+ },
58
+ fontWeight =
59
+ if (headingMap?.hasKey("fontWeight") == true) {
60
+ ReactTypefaceUtils.parseFontWeight(headingMap.getString("fontWeight"))
61
+ } else {
62
+ ReactConstants.UNSET
63
+ },
64
+ color = if (headingMap?.hasKey("color") == true) headingMap.getInt("color") else null,
65
+ )
66
+ }
67
+
38
68
  private fun parseLinkVariants(map: ReadableMap): List<InputLinkVariantStyle> {
39
69
  if (!map.hasKey("linkVariants")) return emptyList()
40
70
  val variants = map.getArray("linkVariants") ?: return emptyList()
@@ -49,35 +79,35 @@ object MarkdownStyleParser {
49
79
  }
50
80
  }
51
81
 
52
- private fun parseMathStyle(mathMap: ReadableMap?): MathChipStyle {
53
- val color = if (mathMap?.hasKey("color") == true) mathMap.getInt("color") else Color.BLACK
54
- val fontSizeSp = if (mathMap?.hasKey("fontSize") == true) mathMap.getDouble("fontSize").toFloat() else 16f
82
+ private fun parseInlineMathStyle(styleMap: ReadableMap?): MathChipStyle {
83
+ val color = if (styleMap?.hasKey("color") == true) styleMap.getInt("color") else Color.BLACK
84
+ val fontSizeSp = if (styleMap?.hasKey("fontSize") == true) styleMap.getDouble("fontSize").toFloat() else 16f
55
85
  val fontSize = PixelUtil.toPixelFromSP(fontSizeSp)
56
86
  val backgroundColor =
57
- if (mathMap?.hasKey("backgroundColor") == true) mathMap.getInt("backgroundColor") else null
58
- val borderColor = if (mathMap?.hasKey("borderColor") == true) mathMap.getInt("borderColor") else null
87
+ if (styleMap?.hasKey("backgroundColor") == true) styleMap.getInt("backgroundColor") else null
88
+ val borderColor = if (styleMap?.hasKey("borderColor") == true) styleMap.getInt("borderColor") else null
59
89
  val borderWidth =
60
90
  PixelUtil.toPixelFromDIP(
61
- if (mathMap?.hasKey("borderWidth") == true) mathMap.getDouble("borderWidth").toFloat() else 0f,
91
+ if (styleMap?.hasKey("borderWidth") == true) styleMap.getDouble("borderWidth").toFloat() else 0f,
62
92
  )
63
93
  val borderRadius =
64
94
  PixelUtil.toPixelFromDIP(
65
- if (mathMap?.hasKey("borderRadius") == true) mathMap.getDouble("borderRadius").toFloat() else 0f,
95
+ if (styleMap?.hasKey("borderRadius") == true) styleMap.getDouble("borderRadius").toFloat() else 0f,
66
96
  )
67
97
  val paddingHorizontal =
68
98
  PixelUtil.toPixelFromDIP(
69
- if (mathMap?.hasKey("paddingHorizontal") == true) mathMap.getDouble("paddingHorizontal").toFloat() else 0f,
99
+ if (styleMap?.hasKey("paddingHorizontal") == true) styleMap.getDouble("paddingHorizontal").toFloat() else 0f,
70
100
  )
71
101
  val paddingVertical =
72
102
  PixelUtil.toPixelFromDIP(
73
- if (mathMap?.hasKey("paddingVertical") == true) mathMap.getDouble("paddingVertical").toFloat() else 0f,
103
+ if (styleMap?.hasKey("paddingVertical") == true) styleMap.getDouble("paddingVertical").toFloat() else 0f,
74
104
  )
75
105
  val selectedBackgroundColor =
76
- if (mathMap?.hasKey("selectedBackgroundColor") == true) mathMap.getInt("selectedBackgroundColor") else null
106
+ if (styleMap?.hasKey("selectedBackgroundColor") == true) styleMap.getInt("selectedBackgroundColor") else null
77
107
  val selectedBorderColor =
78
- if (mathMap?.hasKey("selectedBorderColor") == true) mathMap.getInt("selectedBorderColor") else null
108
+ if (styleMap?.hasKey("selectedBorderColor") == true) styleMap.getInt("selectedBorderColor") else null
79
109
  val fontWeight =
80
- (if (mathMap?.hasKey("fontWeight") == true) mathMap.getString("fontWeight") else null) ?: "normal"
110
+ (if (styleMap?.hasKey("fontWeight") == true) styleMap.getString("fontWeight") else null) ?: "normal"
81
111
 
82
112
  return MathChipStyle(
83
113
  color = color,
@@ -94,75 +124,75 @@ object MarkdownStyleParser {
94
124
  )
95
125
  }
96
126
 
97
- private fun parseMathBlockStyle(
98
- mathBlockMap: ReadableMap?,
127
+ private fun parseBlockMathStyle(
128
+ styleMap: ReadableMap?,
99
129
  inlineFallback: MathChipStyle,
100
- ): MathChipStyle {
101
- val color = if (mathBlockMap?.hasKey("color") == true) mathBlockMap.getInt("color") else inlineFallback.color
130
+ ): MathBlockStyle {
131
+ val color = if (styleMap?.hasKey("color") == true) styleMap.getInt("color") else inlineFallback.color
102
132
  val fontSizeSp =
103
- if (mathBlockMap?.hasKey("fontSize") == true) mathBlockMap.getDouble("fontSize").toFloat() else 20f
133
+ if (styleMap?.hasKey("fontSize") == true) styleMap.getDouble("fontSize").toFloat() else 20f
104
134
  val fontSize = PixelUtil.toPixelFromSP(fontSizeSp)
105
135
  val backgroundColor =
106
- if (mathBlockMap?.hasKey("backgroundColor") == true) {
107
- mathBlockMap.getInt("backgroundColor")
136
+ if (styleMap?.hasKey("backgroundColor") == true) {
137
+ styleMap.getInt("backgroundColor")
108
138
  } else {
109
139
  inlineFallback.backgroundColor
110
140
  }
111
141
  val borderColor =
112
- if (mathBlockMap?.hasKey("borderColor") == true) {
113
- mathBlockMap.getInt("borderColor")
142
+ if (styleMap?.hasKey("borderColor") == true) {
143
+ styleMap.getInt("borderColor")
114
144
  } else {
115
145
  inlineFallback.borderColor
116
146
  }
117
147
  val borderWidth =
118
- if (mathBlockMap?.hasKey("borderWidth") == true) {
119
- PixelUtil.toPixelFromDIP(mathBlockMap.getDouble("borderWidth").toFloat())
148
+ if (styleMap?.hasKey("borderWidth") == true) {
149
+ PixelUtil.toPixelFromDIP(styleMap.getDouble("borderWidth").toFloat())
120
150
  } else {
121
151
  inlineFallback.borderWidth
122
152
  }
123
153
  val borderRadius =
124
- if (mathBlockMap?.hasKey("borderRadius") == true) {
125
- PixelUtil.toPixelFromDIP(mathBlockMap.getDouble("borderRadius").toFloat())
154
+ if (styleMap?.hasKey("borderRadius") == true) {
155
+ PixelUtil.toPixelFromDIP(styleMap.getDouble("borderRadius").toFloat())
126
156
  } else {
127
157
  inlineFallback.borderRadius
128
158
  }
129
159
  val paddingHorizontal =
130
160
  PixelUtil.toPixelFromDIP(
131
- if (mathBlockMap?.hasKey("paddingHorizontal") == true) mathBlockMap.getDouble("paddingHorizontal").toFloat() else 12f,
161
+ if (styleMap?.hasKey("paddingHorizontal") == true) styleMap.getDouble("paddingHorizontal").toFloat() else 12f,
132
162
  )
133
163
  val paddingVertical =
134
164
  PixelUtil.toPixelFromDIP(
135
- if (mathBlockMap?.hasKey("paddingVertical") == true) mathBlockMap.getDouble("paddingVertical").toFloat() else 8f,
165
+ if (styleMap?.hasKey("paddingVertical") == true) styleMap.getDouble("paddingVertical").toFloat() else 8f,
136
166
  )
137
167
  val selectedBackgroundColor =
138
- if (mathBlockMap?.hasKey("selectedBackgroundColor") == true) {
139
- mathBlockMap.getInt("selectedBackgroundColor")
168
+ if (styleMap?.hasKey("selectedBackgroundColor") == true) {
169
+ styleMap.getInt("selectedBackgroundColor")
140
170
  } else {
141
171
  inlineFallback.selectedBackgroundColor
142
172
  }
143
173
  val selectedBorderColor =
144
- if (mathBlockMap?.hasKey("selectedBorderColor") == true) {
145
- mathBlockMap.getInt("selectedBorderColor")
174
+ if (styleMap?.hasKey("selectedBorderColor") == true) {
175
+ styleMap.getInt("selectedBorderColor")
146
176
  } else {
147
177
  inlineFallback.selectedBorderColor
148
178
  }
149
179
  val fontWeight =
150
- if (mathBlockMap?.hasKey("fontWeight") == true) {
151
- mathBlockMap.getString("fontWeight") ?: "normal"
180
+ if (styleMap?.hasKey("fontWeight") == true) {
181
+ styleMap.getString("fontWeight") ?: "normal"
152
182
  } else {
153
183
  inlineFallback.fontWeight
154
184
  }
155
185
  val marginTop =
156
186
  PixelUtil.toPixelFromDIP(
157
- if (mathBlockMap?.hasKey("marginTop") == true) mathBlockMap.getDouble("marginTop").toFloat() else 8f,
187
+ if (styleMap?.hasKey("marginTop") == true) styleMap.getDouble("marginTop").toFloat() else 8f,
158
188
  )
159
189
  val marginBottom =
160
190
  PixelUtil.toPixelFromDIP(
161
- if (mathBlockMap?.hasKey("marginBottom") == true) mathBlockMap.getDouble("marginBottom").toFloat() else 8f,
191
+ if (styleMap?.hasKey("marginBottom") == true) styleMap.getDouble("marginBottom").toFloat() else 8f,
162
192
  )
163
- val alignmentRaw = if (mathBlockMap?.hasKey("alignment") == true) mathBlockMap.getString("alignment") else null
164
- val alignment =
165
- when (alignmentRaw) {
193
+ val textAlignRaw = if (styleMap?.hasKey("textAlign") == true) styleMap.getString("textAlign") else null
194
+ val textAlign =
195
+ when (textAlignRaw) {
166
196
  "left" -> Layout.Alignment.ALIGN_NORMAL
167
197
  "right" -> Layout.Alignment.ALIGN_OPPOSITE
168
198
  else -> Layout.Alignment.ALIGN_CENTER
@@ -182,7 +212,7 @@ object MarkdownStyleParser {
182
212
  fontWeight = fontWeight,
183
213
  marginTop = marginTop,
184
214
  marginBottom = marginBottom,
185
- alignment = alignment,
215
+ textAlign = textAlign,
186
216
  )
187
217
  }
188
218
 
@@ -0,0 +1,20 @@
1
+ package com.swmansion.enriched.markdown.utils.input
2
+
3
+ /**
4
+ * The pure half of the paste interception path. A `ClipData` cannot be built on
5
+ * the JVM, so the joining rule lives here where a unit test can reach it; the
6
+ * two call sites (context menu and `onReceiveContent`) only extract the items.
7
+ */
8
+ object PasteTextUtils {
9
+ /**
10
+ * Flattens a clip's items into one string. A clip regularly carries more than
11
+ * one item — reading only `getItemAt(0)` silently drops items 2..n. Items
12
+ * without text (a URI or intent) are skipped, and the rest join on newlines,
13
+ * which is what the platform's own paste does.
14
+ */
15
+ fun joinClipTexts(texts: List<CharSequence?>): String =
16
+ texts
17
+ .mapNotNull { it?.toString() }
18
+ .filter { it.isNotEmpty() }
19
+ .joinToString("\n")
20
+ }
@@ -2,6 +2,7 @@ package com.swmansion.enriched.markdown.utils.text
2
2
 
3
3
  import android.graphics.Bitmap
4
4
  import android.util.LruCache
5
+ import java.security.MessageDigest
5
6
 
6
7
  object ImageCache {
7
8
  private const val ORIGINAL_CACHE_SIZE = 20 * 1024 * 1024
@@ -10,6 +11,25 @@ object ImageCache {
10
11
  private val originalCache = bitmapLruCache(ORIGINAL_CACHE_SIZE)
11
12
  private val processedCache = bitmapLruCache(PROCESSED_CACHE_SIZE)
12
13
 
14
+ /**
15
+ * Cache identity for a remote image request. Returns the URL itself when no
16
+ * headers are set; otherwise appends a SHA-256 digest of the sorted header
17
+ * pairs, so the same URL fetched with different headers is cached and
18
+ * deduplicated separately without embedding header values in the key.
19
+ */
20
+ fun requestKey(
21
+ url: String,
22
+ headers: Map<String, String>,
23
+ ): String {
24
+ if (headers.isEmpty()) return url
25
+ val joined =
26
+ headers.entries
27
+ .sortedBy { it.key }
28
+ .joinToString(separator = "\n") { "${it.key}:${it.value}" }
29
+ val digest = MessageDigest.getInstance("SHA-256").digest(joined.toByteArray())
30
+ return url + "|" + digest.joinToString(separator = "") { "%02x".format(it) }
31
+ }
32
+
13
33
  fun getOriginal(url: String): Bitmap? = originalCache.get(url)
14
34
 
15
35
  fun putOriginal(
@@ -24,16 +44,18 @@ object ImageCache {
24
44
  width: Int,
25
45
  height: Int,
26
46
  borderRadius: Int,
27
- ): Bitmap? = processedCache.get(processedKey(url, width, height, borderRadius))
47
+ resizeMode: String,
48
+ ): Bitmap? = processedCache.get(processedKey(url, width, height, borderRadius, resizeMode))
28
49
 
29
50
  fun putProcessed(
30
51
  url: String,
31
52
  width: Int,
32
53
  height: Int,
33
54
  borderRadius: Int,
55
+ resizeMode: String,
34
56
  bitmap: Bitmap,
35
57
  ) {
36
- processedCache.put(processedKey(url, width, height, borderRadius), bitmap)
58
+ processedCache.put(processedKey(url, width, height, borderRadius, resizeMode), bitmap)
37
59
  }
38
60
 
39
61
  private fun processedKey(
@@ -41,7 +63,8 @@ object ImageCache {
41
63
  width: Int,
42
64
  height: Int,
43
65
  borderRadius: Int,
44
- ): String = "${url}_w${width}_h${height}_r$borderRadius"
66
+ resizeMode: String,
67
+ ): String = "${url}_w${width}_h${height}_r${borderRadius}_m$resizeMode"
45
68
 
46
69
  private fun bitmapLruCache(maxSize: Int): LruCache<String, Bitmap> =
47
70
  object : LruCache<String, Bitmap>(maxSize) {
@@ -50,23 +50,31 @@ object ImageDownloader {
50
50
  fun download(
51
51
  context: Context,
52
52
  url: String,
53
+ headers: Map<String, String> = emptyMap(),
53
54
  callback: (Bitmap?) -> Unit,
54
55
  ) {
55
- ImageCache.getOriginal(url)?.let {
56
+ val requestKey = ImageCache.requestKey(url, headers)
57
+
58
+ ImageCache.getOriginal(requestKey)?.let {
56
59
  callback(it)
57
60
  return
58
61
  }
59
62
 
60
63
  synchronized(inFlight) {
61
- val existing = inFlight[url]
64
+ val existing = inFlight[requestKey]
62
65
  if (existing != null) {
63
66
  existing.add(callback)
64
67
  return
65
68
  }
66
- inFlight[url] = mutableListOf(callback)
69
+ inFlight[requestKey] = mutableListOf(callback)
67
70
  }
68
71
 
69
- val request = Request.Builder().url(url).build()
72
+ val request =
73
+ Request
74
+ .Builder()
75
+ .url(url)
76
+ .apply { headers.forEach { (name, value) -> addHeader(name, value) } }
77
+ .build()
70
78
  getClient(context).newCall(request).enqueue(
71
79
  object : Callback {
72
80
  override fun onResponse(
@@ -87,8 +95,8 @@ object ImageDownloader {
87
95
  }
88
96
  }
89
97
 
90
- bitmap?.let { ImageCache.putOriginal(url, it) }
91
- dispatchCallbacks(url, bitmap)
98
+ bitmap?.let { ImageCache.putOriginal(requestKey, it) }
99
+ dispatchCallbacks(requestKey, bitmap)
92
100
  }
93
101
 
94
102
  override fun onFailure(
@@ -96,7 +104,7 @@ object ImageDownloader {
96
104
  e: IOException,
97
105
  ) {
98
106
  Log.e(TAG, "Failed to download image: $url", e)
99
- dispatchCallbacks(url, null)
107
+ dispatchCallbacks(requestKey, null)
100
108
  }
101
109
  },
102
110
  )
@@ -113,6 +121,11 @@ object ImageDownloader {
113
121
  }
114
122
  }
115
123
 
124
+ fun decodeBytesDownsampled(
125
+ context: Context,
126
+ bytes: ByteArray,
127
+ ): Bitmap? = decodeDownsampled(bytes, context.resources.displayMetrics.widthPixels)
128
+
116
129
  fun decodeFileDownsampled(
117
130
  context: Context,
118
131
  path: String,
@@ -145,10 +158,10 @@ object ImageDownloader {
145
158
  }
146
159
 
147
160
  private fun dispatchCallbacks(
148
- url: String,
161
+ requestKey: String,
149
162
  bitmap: Bitmap?,
150
163
  ) {
151
- val callbacks = synchronized(inFlight) { inFlight.remove(url) } ?: return
164
+ val callbacks = synchronized(inFlight) { inFlight.remove(requestKey) } ?: return
152
165
  mainHandler.post {
153
166
  callbacks.forEach { it(bitmap) }
154
167
  }
@@ -0,0 +1,161 @@
1
+ package com.swmansion.enriched.markdown.utils.text
2
+
3
+ import android.content.Context
4
+ import android.graphics.Bitmap
5
+ import android.net.Uri
6
+ import android.util.Base64
7
+ import android.util.Log
8
+ import java.io.FileNotFoundException
9
+ import java.io.InputStream
10
+
11
+ /**
12
+ * Loads markdown images from non-network sources (issue #377).
13
+ *
14
+ * React Native's asset system produces different URI shapes for the same
15
+ * `require('./img.png')` depending on environment, and none of them are plain
16
+ * file paths in a bundled app:
17
+ * - Metro dev server: `http://host:8081/assets/...` (handled by [ImageDownloader])
18
+ * - Release APK: a bare drawable resource name, e.g. `src_assets_logo`
19
+ * (RN's `AssetSourceResolver.resourceIdentifierWithoutScale`)
20
+ * - Sideloaded JS bundle: `file:///.../drawable-xhdpi/src_assets_logo.png`
21
+ * - expo-updates embedded assets: `file:///android_res/drawable/<name>.png`
22
+ * - expo-asset downloads: percent-encoded `file://` paths in the cache dir
23
+ *
24
+ * Resolution mirrors RN core: `ImageSource.computeUri` treats a scheme-less
25
+ * source as a resource name, and `ResourceDrawableIdHelper` normalizes names
26
+ * by lowercasing, replacing `-` with `_`, and accepting numeric resource ids. The
27
+ * `android_res`/`android_asset` and drawable/raw lookups follow expo-asset's
28
+ * `ResourceAsset.kt`. `content://`, `asset://`, `res://` and `data:` URIs are
29
+ * supported for parity with RN's Fresco pipeline. All decodes are downsampled
30
+ * to screen width like the network path.
31
+ */
32
+ object LocalImageLoader {
33
+ private const val TAG = "LocalImageLoader"
34
+ private const val ASSET_PATH_PREFIX = "/android_asset/"
35
+ private const val RES_PATH_PREFIX = "/android_res/"
36
+ private const val BASE64_MARKER = "base64,"
37
+
38
+ fun load(
39
+ context: Context,
40
+ source: String,
41
+ ): Bitmap? =
42
+ try {
43
+ val uri = Uri.parse(source)
44
+ when (uri.scheme?.lowercase()) {
45
+ null -> {
46
+ if (source.startsWith('/')) {
47
+ ImageDownloader.decodeFileDownsampled(context, source)
48
+ } else {
49
+ decodeResourceByName(context, source)
50
+ }
51
+ }
52
+
53
+ "file" -> {
54
+ loadFileUri(context, uri)
55
+ }
56
+
57
+ "asset" -> {
58
+ decodeStream(context) { context.assets.open(schemelessPath(uri)) }
59
+ }
60
+
61
+ "content" -> {
62
+ decodeStream(context) {
63
+ context.contentResolver.openInputStream(uri) ?: throw FileNotFoundException(source)
64
+ }
65
+ }
66
+
67
+ "res" -> {
68
+ decodeResourceByName(context, schemelessPath(uri))
69
+ }
70
+
71
+ "data" -> {
72
+ decodeDataUri(context, source)
73
+ }
74
+
75
+ else -> {
76
+ Log.w(TAG, "Unsupported image URI scheme: $source")
77
+ null
78
+ }
79
+ }
80
+ } catch (_: OutOfMemoryError) {
81
+ Log.e(TAG, "OOM loading local image: $source")
82
+ null
83
+ } catch (e: Exception) {
84
+ Log.w(TAG, "Failed to load local image: $source", e)
85
+ null
86
+ }
87
+
88
+ private fun loadFileUri(
89
+ context: Context,
90
+ uri: Uri,
91
+ ): Bitmap? {
92
+ val path = uri.path ?: return null
93
+ return when {
94
+ path.startsWith(ASSET_PATH_PREFIX) -> {
95
+ decodeStream(context) { context.assets.open(path.removePrefix(ASSET_PATH_PREFIX)) }
96
+ }
97
+
98
+ path.startsWith(RES_PATH_PREFIX) -> {
99
+ decodeAndroidRes(context, uri)
100
+ }
101
+
102
+ else -> {
103
+ ImageDownloader.decodeFileDownsampled(context, path)
104
+ }
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Resolves `file:///android_res/<dir>[-qualifier]/<file>[.<ext>]` by stripping
110
+ * density qualifiers and the file extension, then looking the resource up by name.
111
+ */
112
+ private fun decodeAndroidRes(
113
+ context: Context,
114
+ uri: Uri,
115
+ ): Bitmap? {
116
+ val segments = uri.pathSegments
117
+ if (segments.size < 3) return null
118
+ val directory = segments[1].substringBefore('-')
119
+ val name = segments[2].substringBeforeLast('.')
120
+ val resId = context.resources.getIdentifier(name, directory, context.packageName)
121
+ if (resId == 0) {
122
+ Log.w(TAG, "No $directory resource named: $name")
123
+ return null
124
+ }
125
+ return decodeStream(context) { context.resources.openRawResource(resId) }
126
+ }
127
+
128
+ private fun decodeResourceByName(
129
+ context: Context,
130
+ name: String,
131
+ ): Bitmap? {
132
+ if (name.isEmpty()) return null
133
+ val normalized = name.lowercase().replace('-', '_')
134
+ val resId =
135
+ normalized.toIntOrNull()
136
+ ?: context.resources.getIdentifier(normalized, "drawable", context.packageName).takeIf { it != 0 }
137
+ ?: context.resources.getIdentifier(normalized, "raw", context.packageName)
138
+ if (resId == 0) {
139
+ Log.w(TAG, "No drawable or raw resource named: $normalized")
140
+ return null
141
+ }
142
+ return decodeStream(context) { context.resources.openRawResource(resId) }
143
+ }
144
+
145
+ private fun decodeDataUri(
146
+ context: Context,
147
+ source: String,
148
+ ): Bitmap? {
149
+ val marker = source.indexOf(BASE64_MARKER)
150
+ if (marker == -1) return null
151
+ val bytes = Base64.decode(source.substring(marker + BASE64_MARKER.length), Base64.DEFAULT)
152
+ return ImageDownloader.decodeBytesDownsampled(context, bytes)
153
+ }
154
+
155
+ private inline fun decodeStream(
156
+ context: Context,
157
+ open: () -> InputStream,
158
+ ): Bitmap? = open().use { ImageDownloader.decodeBytesDownsampled(context, it.readBytes()) }
159
+
160
+ private fun schemelessPath(uri: Uri): String = (uri.host.orEmpty() + uri.path.orEmpty()).trimStart('/')
161
+ }
@@ -7,6 +7,7 @@ import com.facebook.react.common.ReactConstants
7
7
  import com.facebook.react.views.text.ReactTypefaceUtils.applyStyles
8
8
  import com.facebook.react.views.text.ReactTypefaceUtils.parseFontWeight
9
9
  import com.swmansion.enriched.markdown.renderer.BlockStyle
10
+ import com.swmansion.enriched.markdown.styles.CodeBlockStyle
10
11
 
11
12
  fun TextPaint.applyColorPreserving(
12
13
  color: Int,
@@ -51,3 +52,25 @@ fun TextPaint.applyBlockStyleFont(
51
52
  typefaceCache[cacheKey] = newTypeface
52
53
  this.typeface = newTypeface
53
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
+ }
@@ -12,6 +12,12 @@ class CheckboxTouchHelper(
12
12
  ) {
13
13
  var onCheckboxTap: ((taskIndex: Int, checked: Boolean, itemText: String) -> Unit)? = null
14
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
+
15
21
  private var touchDownX = 0f
16
22
  private var touchDownY = 0f
17
23
  private var pendingHit: TaskListHitTestResult? = null
@@ -19,6 +25,7 @@ class CheckboxTouchHelper(
19
25
 
20
26
  /** Returns `true` if the event was consumed by a checkbox gesture. */
21
27
  fun onTouchEvent(event: MotionEvent): Boolean {
28
+ if (!isEnabled) return false
22
29
  when (event.actionMasked) {
23
30
  MotionEvent.ACTION_DOWN -> {
24
31
  val hit = TaskListTapUtils.hitTest(textView, event.x, event.y) ?: return false