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
@@ -0,0 +1,414 @@
1
+ package com.swmansion.enriched.markdown.views
2
+
3
+ import android.content.ClipData
4
+ import android.content.ClipboardManager
5
+ import android.content.Context
6
+ import android.graphics.Canvas
7
+ import android.graphics.ColorFilter
8
+ import android.graphics.Paint
9
+ import android.graphics.PixelFormat
10
+ import android.graphics.Typeface
11
+ import android.graphics.drawable.Drawable
12
+ import android.graphics.drawable.GradientDrawable
13
+ import android.os.Build
14
+ import android.text.Layout
15
+ import android.text.SpannableString
16
+ import android.text.StaticLayout
17
+ import android.text.TextPaint
18
+ import android.text.TextUtils
19
+ import android.util.TypedValue
20
+ import android.view.View
21
+ import android.widget.FrameLayout
22
+ import android.widget.HorizontalScrollView
23
+ import android.widget.ImageView
24
+ import androidx.appcompat.widget.AppCompatImageButton
25
+ import androidx.appcompat.widget.AppCompatTextView
26
+ import com.swmansion.enriched.markdown.parser.MarkdownASTNode
27
+ import com.swmansion.enriched.markdown.spans.LineHeightSpan
28
+ import com.swmansion.enriched.markdown.styles.CodeBlockStyle
29
+ import com.swmansion.enriched.markdown.styles.StyleConfig
30
+ import com.swmansion.enriched.markdown.utils.common.CodeBlockHighlighter
31
+ import com.swmansion.enriched.markdown.utils.common.CodeBlockNode
32
+ import com.swmansion.enriched.markdown.utils.text.extensions.applyCodeBlockTextStyle
33
+ import com.swmansion.enriched.markdown.utils.text.span.SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE
34
+ import kotlin.math.ceil
35
+
36
+ /**
37
+ * Block segment view for fenced code blocks (see splitASTIntoSegments):
38
+ * a fixed header bar (language name, copy button) above a horizontally
39
+ * scrolling, non-wrapping code pane. Syntax coloring comes from the
40
+ * CodeBlockHighlighter seam and falls back to plain text. The box visuals
41
+ * must stay in sync with the commonmark flavor's CodeBlockSpan.
42
+ *
43
+ * measureCodeBlockNodeHeight must stay in sync with the view: it builds the
44
+ * same styled text, paint, and header metrics, so the height reported to
45
+ * Yoga matches the laid-out height. Since lines never wrap, the height is
46
+ * independent of the available width.
47
+ */
48
+ class CodeBlockContainerView(
49
+ context: Context,
50
+ styleConfig: StyleConfig,
51
+ ) : FrameLayout(context),
52
+ BlockSegmentView {
53
+ private val codeBlockStyle: CodeBlockStyle = styleConfig.codeBlockStyle
54
+
55
+ private val inset = contentInset(codeBlockStyle)
56
+ private val borderW = borderPx(codeBlockStyle)
57
+ private val headerH = headerHeight(codeBlockStyle)
58
+
59
+ override val segmentMarginTop: Int get() = codeBlockStyle.marginTop.toInt()
60
+ override val segmentMarginBottom: Int get() = codeBlockStyle.marginBottom.toInt()
61
+
62
+ var copyLabel: String = ""
63
+ set(value) {
64
+ field = value
65
+ copyButton.contentDescription = value
66
+ }
67
+ var copyAsMarkdownLabel: String = ""
68
+
69
+ // Hides the long-press copy menu only; the header copy button is a visible
70
+ // control, not a context menu, and stays.
71
+ var contextMenuHidden: Boolean = false
72
+
73
+ // Called instead of the menu on long press while contextMenuHidden is on, so
74
+ // the owner can report the block (onSelectionChange) and show its own UI.
75
+ var onMenuSuppressed: ((markdown: String, text: String) -> Unit)? = null
76
+
77
+ // Copy / Copy as Markdown visibility, Copy format and the header copy button.
78
+ // The header button always copies the raw code.
79
+ var menuOptions: BlockMenuOptions = BlockMenuOptions()
80
+ set(value) {
81
+ field = value
82
+ // Hiding the button leaves the header (and its height) untouched.
83
+ copyButton.visibility = if (value.copyButtonHidden) View.GONE else View.VISIBLE
84
+ }
85
+
86
+ var onCopyPress: ((code: String, language: String) -> Unit)? = null
87
+
88
+ private var code: String = ""
89
+ private var language: String? = null
90
+ private var fenceChar: String = "`"
91
+
92
+ // True until the closing fence arrives: highlighting is deferred and copying
93
+ // is disabled, while the header stays visible.
94
+ var pending: Boolean = false
95
+ set(value) {
96
+ if (field == value) return
97
+ field = value
98
+ copyButton.isEnabled = !value
99
+ // The reconciler can reuse an unchanged block without re-applying the
100
+ // node, so re-derive here to pick up highlighting once the block closes.
101
+ rebuildCodeText()
102
+ }
103
+
104
+ private val textView =
105
+ AppCompatTextView(context).apply {
106
+ includeFontPadding = false
107
+ setLineSpacing(0f, 1f)
108
+ breakStrategy = Layout.BREAK_STRATEGY_SIMPLE
109
+ hyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE
110
+ layoutDirection = View.LAYOUT_DIRECTION_LTR
111
+ textDirection = View.TEXT_DIRECTION_LTR
112
+ setTextSize(TypedValue.COMPLEX_UNIT_PX, codeBlockStyle.fontSize)
113
+ typeface = createCodePaint(codeBlockStyle, context).typeface
114
+ setTextColor(codeBlockStyle.color)
115
+ val horizontalPad = (inset - borderW).coerceAtLeast(0)
116
+ setPadding(horizontalPad, inset, horizontalPad, inset)
117
+ setOnLongClickListener { view -> showContextMenu(view) }
118
+ }
119
+
120
+ private val scrollView =
121
+ HorizontalScrollView(context).apply {
122
+ isHorizontalScrollBarEnabled = true
123
+ overScrollMode = View.OVER_SCROLL_NEVER
124
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
125
+ horizontalScrollbarThumbDrawable =
126
+ GradientDrawable().apply {
127
+ setColor(secondaryColor(codeBlockStyle.color))
128
+ cornerRadius = context.resources.displayMetrics.density * 2
129
+ }
130
+ }
131
+ addView(textView, LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT))
132
+ }
133
+
134
+ private val languageView =
135
+ AppCompatTextView(context).apply {
136
+ includeFontPadding = false
137
+ maxLines = 1
138
+ ellipsize = TextUtils.TruncateAt.END
139
+ setTextSize(TypedValue.COMPLEX_UNIT_PX, codeBlockStyle.fontSize * HEADER_LABEL_SCALE)
140
+ typeface = headerTypeface
141
+ setTextColor(secondaryColor(codeBlockStyle.color))
142
+ }
143
+
144
+ private val copyButton =
145
+ AppCompatImageButton(context).apply {
146
+ background = null
147
+ scaleType = ImageView.ScaleType.CENTER
148
+ setImageDrawable(
149
+ CopyIconDrawable(
150
+ secondaryColor(codeBlockStyle.color),
151
+ ceil(codeBlockStyle.fontSize * HEADER_ICON_SCALE).toInt(),
152
+ ),
153
+ )
154
+ setOnClickListener { copyCode() }
155
+ }
156
+
157
+ private val dividerPaint =
158
+ Paint(Paint.ANTI_ALIAS_FLAG).apply {
159
+ color = dividerColor(codeBlockStyle.color)
160
+ strokeWidth = context.resources.displayMetrics.density
161
+ }
162
+
163
+ init {
164
+ setWillNotDraw(false)
165
+ background =
166
+ GradientDrawable().apply {
167
+ setColor(codeBlockStyle.backgroundColor)
168
+ cornerRadius = codeBlockStyle.borderRadius
169
+ if (codeBlockStyle.borderWidth > 0f) {
170
+ setStroke(ceil(codeBlockStyle.borderWidth).toInt(), codeBlockStyle.borderColor)
171
+ }
172
+ }
173
+ isLongClickable = true
174
+ setOnLongClickListener { view -> showContextMenu(view) }
175
+ addView(scrollView, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT))
176
+ addView(languageView, LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT))
177
+ addView(copyButton, LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT))
178
+ }
179
+
180
+ fun applyCodeBlockNode(node: MarkdownASTNode) {
181
+ code = CodeBlockNode.extractCode(node)
182
+ fenceChar = CodeBlockNode.fenceChar(node)
183
+
184
+ val newLanguage = CodeBlockNode.language(node)
185
+ if (newLanguage != language) {
186
+ language = newLanguage
187
+ languageView.text = CodeBlockNode.displayLanguageName(newLanguage)
188
+ }
189
+
190
+ rebuildCodeText()
191
+ }
192
+
193
+ // Highlighting is deferred while pending, applied once the block closes.
194
+ private fun rebuildCodeText() {
195
+ val plainCode = buildCodeText(code, codeBlockStyle)
196
+ if (!pending) {
197
+ CodeBlockHighlighter.highlight(plainCode, code, language, codeBlockStyle)
198
+ }
199
+ textView.text = plainCode
200
+ }
201
+
202
+ override fun onMeasure(
203
+ widthSpec: Int,
204
+ heightSpec: Int,
205
+ ) {
206
+ val measuredWidth = MeasureSpec.getSize(widthSpec)
207
+ scrollView.measure(
208
+ MeasureSpec.makeMeasureSpec((measuredWidth - borderW * 2).coerceAtLeast(0), MeasureSpec.EXACTLY),
209
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
210
+ )
211
+ copyButton.measure(
212
+ MeasureSpec.makeMeasureSpec(headerH, MeasureSpec.EXACTLY),
213
+ MeasureSpec.makeMeasureSpec(headerH, MeasureSpec.EXACTLY),
214
+ )
215
+ val labelMaxWidth = (measuredWidth - inset * 2 - headerH).coerceAtLeast(0)
216
+ languageView.measure(
217
+ MeasureSpec.makeMeasureSpec(labelMaxWidth, MeasureSpec.AT_MOST),
218
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
219
+ )
220
+ setMeasuredDimension(measuredWidth, headerH + scrollView.measuredHeight)
221
+ }
222
+
223
+ override fun onLayout(
224
+ changed: Boolean,
225
+ left: Int,
226
+ top: Int,
227
+ right: Int,
228
+ bottom: Int,
229
+ ) {
230
+ val width = right - left
231
+ val labelTop = headerH - languageView.measuredHeight
232
+ languageView.layout(
233
+ inset,
234
+ labelTop,
235
+ inset + languageView.measuredWidth,
236
+ labelTop + languageView.measuredHeight,
237
+ )
238
+
239
+ val iconWidth = copyButton.drawable?.intrinsicWidth ?: copyButton.measuredWidth
240
+ val iconSlack = ((copyButton.measuredWidth - iconWidth) / 2).coerceAtLeast(0)
241
+ val buttonLeft = (width - inset - copyButton.measuredWidth + iconSlack).coerceAtLeast(0)
242
+ val buttonTop = (headerH - languageView.measuredHeight / 2 - copyButton.measuredHeight / 2).coerceAtLeast(0)
243
+ copyButton.layout(
244
+ buttonLeft,
245
+ buttonTop,
246
+ buttonLeft + copyButton.measuredWidth,
247
+ buttonTop + copyButton.measuredHeight,
248
+ )
249
+
250
+ scrollView.layout(borderW, headerH, width - borderW, bottom - top - borderW)
251
+ }
252
+
253
+ // Divider between the header and the code, centered in the gap the code
254
+ // text's top inset creates, so it adds no height of its own.
255
+ override fun onDraw(canvas: Canvas) {
256
+ super.onDraw(canvas)
257
+ val borderWidth = borderW.toFloat()
258
+ val y = headerH + inset / 2f
259
+ canvas.drawLine(borderWidth, y, width - borderWidth, y, dividerPaint)
260
+ }
261
+
262
+ // Returns whether a menu was shown, so the long-press listener only consumes
263
+ // the event when there is one (a pending block has no menu yet, and a hidden
264
+ // one never does).
265
+ private fun showContextMenu(anchor: View): Boolean {
266
+ if (pending) return false
267
+ if (contextMenuHidden) {
268
+ val onSuppressed = onMenuSuppressed ?: return false
269
+ onSuppressed(CodeBlockNode.fencedMarkdown(code, language, fenceChar), code)
270
+ return true
271
+ }
272
+ if (!menuOptions.hasItems) return false
273
+ ContextMenuPopup.show(anchor, this) {
274
+ blockCopyItems(
275
+ menuOptions,
276
+ copyLabel,
277
+ copyAsMarkdownLabel,
278
+ markdown = { CodeBlockNode.fencedMarkdown(code, language, fenceChar) },
279
+ rawText = { code },
280
+ copyRaw = ::copyCode,
281
+ copyMarkdown = ::copyFencedMarkdown,
282
+ )
283
+ }
284
+ return true
285
+ }
286
+
287
+ private fun copyCode() {
288
+ if (pending || code.isEmpty()) return
289
+ copyToClipboard(code)
290
+ onCopyPress?.invoke(code, language ?: "")
291
+ }
292
+
293
+ private fun copyFencedMarkdown() {
294
+ if (code.isEmpty()) return
295
+ copyToClipboard(CodeBlockNode.fencedMarkdown(code, language, fenceChar))
296
+ }
297
+
298
+ private fun copyToClipboard(text: String) {
299
+ val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
300
+ clipboard.setPrimaryClip(ClipData.newPlainText("Code", text))
301
+ }
302
+
303
+ private class CopyIconDrawable(
304
+ color: Int,
305
+ private val size: Int,
306
+ ) : Drawable() {
307
+ private val paint =
308
+ Paint(Paint.ANTI_ALIAS_FLAG).apply {
309
+ style = Paint.Style.STROKE
310
+ strokeWidth = size / 20f
311
+ strokeJoin = Paint.Join.ROUND
312
+ strokeCap = Paint.Cap.ROUND
313
+ this.color = color
314
+ }
315
+
316
+ private val glyph = CopyGlyph()
317
+
318
+ override fun draw(canvas: Canvas) {
319
+ glyph.draw(canvas, bounds.width().toFloat(), paint)
320
+ }
321
+
322
+ override fun getIntrinsicWidth() = size
323
+
324
+ override fun getIntrinsicHeight() = size
325
+
326
+ override fun setAlpha(alpha: Int) {
327
+ paint.alpha = alpha
328
+ }
329
+
330
+ override fun setColorFilter(colorFilter: ColorFilter?) {
331
+ paint.colorFilter = colorFilter
332
+ }
333
+
334
+ @Deprecated("Deprecated in Java")
335
+ override fun getOpacity() = PixelFormat.TRANSLUCENT
336
+ }
337
+
338
+ companion object {
339
+ private const val HEADER_LABEL_SCALE = 0.85f
340
+
341
+ // Drawable box for the copy glyph, as a multiple of the code font size.
342
+ // iOS sizes the SF Symbol by point size (kENRMHeaderIconScale = 0.72) but
343
+ // the symbol renders roughly half again as tall as its point size; this box
344
+ // is scaled up to land the drawn glyph at the same on-screen size.
345
+ private const val HEADER_ICON_SCALE = 1.08f
346
+
347
+ private val headerTypeface: Typeface = Typeface.create("sans-serif-medium", Typeface.NORMAL)
348
+
349
+ private fun secondaryColor(color: Int): Int = (color and 0x00FFFFFF) or (0x99 shl 24)
350
+
351
+ private fun dividerColor(color: Int): Int = (color and 0x00FFFFFF) or (0x33 shl 24)
352
+
353
+ private fun contentInset(style: CodeBlockStyle): Int = ceil(style.padding + style.borderWidth).toInt()
354
+
355
+ private fun borderPx(style: CodeBlockStyle): Int = ceil(style.borderWidth).toInt()
356
+
357
+ // Header is the top content inset plus one label line; the code text
358
+ // view's own top inset then forms the single gap below the label.
359
+ private fun headerHeight(style: CodeBlockStyle): Int {
360
+ val paint =
361
+ TextPaint(Paint.ANTI_ALIAS_FLAG).apply {
362
+ textSize = style.fontSize * HEADER_LABEL_SCALE
363
+ typeface = headerTypeface
364
+ }
365
+ val metrics = paint.fontMetrics
366
+ return contentInset(style) + ceil(metrics.descent - metrics.ascent).toInt()
367
+ }
368
+
369
+ private fun createCodePaint(
370
+ style: CodeBlockStyle,
371
+ context: Context,
372
+ ): TextPaint =
373
+ TextPaint(Paint.ANTI_ALIAS_FLAG).apply {
374
+ applyCodeBlockTextStyle(style, context)
375
+ }
376
+
377
+ private fun buildCodeText(
378
+ code: String,
379
+ style: CodeBlockStyle,
380
+ ): SpannableString =
381
+ SpannableString(code).apply {
382
+ if (style.lineHeight > 0f && isNotEmpty()) {
383
+ setSpan(LineHeightSpan(style.lineHeight), 0, length, SPAN_FLAGS_EXCLUSIVE_EXCLUSIVE)
384
+ }
385
+ }
386
+
387
+ // Lines never wrap (the code pane scrolls horizontally), so the layout is
388
+ // built at the text's desired width and the result is independent of the
389
+ // available width.
390
+ fun measureCodeBlockNodeHeight(
391
+ node: MarkdownASTNode,
392
+ config: StyleConfig,
393
+ context: Context,
394
+ @Suppress("unused") width: Float,
395
+ ): Float {
396
+ val style = config.codeBlockStyle
397
+ val inset = contentInset(style)
398
+ val headerH = headerHeight(style)
399
+ val text = buildCodeText(CodeBlockNode.extractCode(node), style)
400
+ if (text.isEmpty()) return headerH + inset * 2f
401
+ val paint = createCodePaint(style, context)
402
+ val contentWidth = ceil(Layout.getDesiredWidth(text, paint)).toInt().coerceAtLeast(1)
403
+ val layout =
404
+ StaticLayout.Builder
405
+ .obtain(text, 0, text.length, paint, contentWidth)
406
+ .setIncludePad(false)
407
+ .setLineSpacing(0f, 1f)
408
+ .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
409
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
410
+ .build()
411
+ return layout.height.toFloat() + inset * 2 + headerH
412
+ }
413
+ }
414
+ }
@@ -183,16 +183,19 @@ object ContextMenuPopup {
183
183
  color = Color.parseColor("#333333")
184
184
  }
185
185
 
186
+ private val copyGlyph = CopyGlyph()
187
+
188
+ // COPY mirrors SF Symbol doc.on.doc, DOCUMENT mirrors doc.text; the copy
189
+ // glyph is shared with the header button in CodeBlockContainerView.
186
190
  override fun draw(canvas: Canvas) {
187
191
  val u = bounds.width() / 24f
188
192
  if (icon == Icon.COPY) {
189
- canvas.drawRoundRect(RectF(8 * u, 2 * u, 22 * u, 16 * u), 2 * u, 2 * u, paint)
190
- canvas.drawRoundRect(RectF(2 * u, 8 * u, 16 * u, 22 * u), 2 * u, 2 * u, paint)
193
+ copyGlyph.draw(canvas, bounds.width().toFloat(), paint)
191
194
  } else {
192
- canvas.drawRoundRect(RectF(4 * u, 2 * u, 20 * u, 22 * u), 2 * u, 2 * u, paint)
193
- canvas.drawLine(8 * u, 8 * u, 16 * u, 8 * u, paint)
194
- canvas.drawLine(8 * u, 12 * u, 16 * u, 12 * u, paint)
195
- canvas.drawLine(8 * u, 16 * u, 13 * u, 16 * u, paint)
195
+ canvas.drawRoundRect(RectF(5 * u, 3 * u, 19 * u, 21 * u), 2.5f * u, 2.5f * u, paint)
196
+ canvas.drawLine(8.5f * u, 9 * u, 15.5f * u, 9 * u, paint)
197
+ canvas.drawLine(8.5f * u, 12.5f * u, 15.5f * u, 12.5f * u, paint)
198
+ canvas.drawLine(8.5f * u, 16 * u, 13 * u, 16 * u, paint)
196
199
  }
197
200
  }
198
201
 
@@ -0,0 +1,101 @@
1
+ package com.swmansion.enriched.markdown.views
2
+
3
+ import android.graphics.Canvas
4
+ import android.graphics.Paint
5
+ import android.graphics.Path
6
+ import android.graphics.PorterDuff
7
+ import android.graphics.PorterDuffXfermode
8
+
9
+ /**
10
+ * Draws the copy glyph so Android matches the SF Symbol doc.on.doc rendered on
11
+ * iOS: two portrait document pages with a folded (dog-eared) top-right corner,
12
+ * a front page in the lower-left laid over a back page in the upper-right.
13
+ *
14
+ * The back page is punched out where the front page (plus a hairline of
15
+ * clearance) covers it, so the front reads as sitting on top exactly as the SF
16
+ * Symbol does, instead of both outlines crossing. The clear is done inside an
17
+ * offscreen layer so the punched region reveals whatever background the drawable
18
+ * sits on, without the glyph needing to know that color.
19
+ *
20
+ * One instance is held per drawable rather than shared: the paths and clear
21
+ * paint are reused across draws to keep draw() allocation-free, and two drawables
22
+ * of different sizes must not share those buffers. All coordinates use a 24-unit
23
+ * grid scaled to the drawable width, matching the grid the iOS symbol is authored
24
+ * on.
25
+ */
26
+ internal class CopyGlyph {
27
+ private val back = Path()
28
+ private val front = Path()
29
+ private val backFold = Path()
30
+ private val frontFold = Path()
31
+
32
+ // Color and colorFilter are irrelevant under PorterDuff.CLEAR; only the
33
+ // widened stroke (set per draw) matters, so this is configured once.
34
+ private val clearPaint =
35
+ Paint(Paint.ANTI_ALIAS_FLAG).apply {
36
+ style = Paint.Style.FILL_AND_STROKE
37
+ strokeJoin = Paint.Join.ROUND
38
+ strokeCap = Paint.Cap.ROUND
39
+ xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
40
+ }
41
+
42
+ fun draw(
43
+ canvas: Canvas,
44
+ width: Float,
45
+ stroke: Paint,
46
+ ) {
47
+ val u = width / 24f
48
+ val fold = 4f * u
49
+ val corner = 2f * u
50
+
51
+ buildPage(back, 9 * u, 1 * u, 20 * u, 17 * u, fold, corner)
52
+ buildPage(front, 3 * u, 7 * u, 14 * u, 23 * u, fold, corner)
53
+ buildFold(backFold, 20 * u, 1 * u, fold)
54
+ buildFold(frontFold, 14 * u, 7 * u, fold)
55
+ clearPaint.strokeWidth = stroke.strokeWidth * 3f
56
+
57
+ val saved = canvas.saveLayer(0f, 0f, width, width, null)
58
+ canvas.drawPath(back, stroke)
59
+ canvas.drawPath(backFold, stroke)
60
+ canvas.drawPath(front, clearPaint)
61
+ canvas.drawPath(front, stroke)
62
+ canvas.drawPath(frontFold, stroke)
63
+ canvas.restoreToCount(saved)
64
+ }
65
+
66
+ // A page outline whose top-right corner is cut back by fold, with the other
67
+ // three corners rounded by corner.
68
+ private fun buildPage(
69
+ path: Path,
70
+ l: Float,
71
+ t: Float,
72
+ r: Float,
73
+ b: Float,
74
+ fold: Float,
75
+ corner: Float,
76
+ ) {
77
+ path.rewind()
78
+ path.moveTo(l, t + corner)
79
+ path.quadTo(l, t, l + corner, t)
80
+ path.lineTo(r - fold, t)
81
+ path.lineTo(r, t + fold)
82
+ path.lineTo(r, b - corner)
83
+ path.quadTo(r, b, r - corner, b)
84
+ path.lineTo(l + corner, b)
85
+ path.quadTo(l, b, l, b - corner)
86
+ path.close()
87
+ }
88
+
89
+ // The two inner edges of the folded-over corner, at the page's top-right.
90
+ private fun buildFold(
91
+ path: Path,
92
+ r: Float,
93
+ t: Float,
94
+ fold: Float,
95
+ ) {
96
+ path.rewind()
97
+ path.moveTo(r - fold, t)
98
+ path.lineTo(r - fold, t + fold)
99
+ path.lineTo(r, t + fold)
100
+ }
101
+ }
@@ -24,6 +24,7 @@ import com.swmansion.enriched.markdown.accessibility.AccessibilityLabels
24
24
  import com.swmansion.enriched.markdown.parser.MarkdownASTNode
25
25
  import com.swmansion.enriched.markdown.parser.MarkdownASTNode.NodeType
26
26
  import com.swmansion.enriched.markdown.renderer.Renderer
27
+ import com.swmansion.enriched.markdown.spans.LinkChipBackgroundSpan
27
28
  import com.swmansion.enriched.markdown.styles.StyleConfig
28
29
  import com.swmansion.enriched.markdown.styles.TableStyle
29
30
  import com.swmansion.enriched.markdown.utils.common.layout.isLayoutRTL
@@ -43,7 +44,7 @@ class TableContainerView(
43
44
  private val styleConfig: StyleConfig,
44
45
  ) : FrameLayout(context),
45
46
  BlockSegmentView {
46
- private val tableStyle: TableStyle = styleConfig.tableStyle
47
+ internal val tableStyle: TableStyle = styleConfig.tableStyle
47
48
 
48
49
  override val segmentMarginTop: Int get() = tableStyle.marginTop.toInt()
49
50
  override val segmentMarginBottom: Int get() = tableStyle.marginBottom.toInt()
@@ -63,6 +64,12 @@ class TableContainerView(
63
64
 
64
65
  var copyLabel: String = ""
65
66
  var copyAsMarkdownLabel: String = ""
67
+ var contextMenuHidden: Boolean = false
68
+ var menuOptions: BlockMenuOptions = BlockMenuOptions()
69
+
70
+ // Called instead of the menu on long press while contextMenuHidden is on, so
71
+ // the owner can report the block (onSelectionChange) and show its own UI.
72
+ var onMenuSuppressed: ((markdown: String, text: String) -> Unit)? = null
66
73
 
67
74
  private val scrollView =
68
75
  HorizontalScrollView(context).apply {
@@ -79,6 +86,19 @@ class TableContainerView(
79
86
 
80
87
  val rowCount: Int get() = rows.size
81
88
 
89
+ /**
90
+ * Number of links across all cells. Tables are not reported by `onLinkLayout`, but their links
91
+ * still count so later link indices stay in document order.
92
+ */
93
+ val linkCount: Int
94
+ get() =
95
+ rows.sumOf { row ->
96
+ row.sumOf { cell ->
97
+ // LinkRenderer attaches one LinkChipBackgroundSpan per link.
98
+ cell.attributedText.getSpans(0, cell.attributedText.length, LinkChipBackgroundSpan::class.java).size
99
+ }
100
+ }
101
+
82
102
  fun animateNewRows(
83
103
  previousRowCount: Int,
84
104
  durationMs: Long,
@@ -327,20 +347,49 @@ class TableContainerView(
327
347
  right: Int,
328
348
  bottom: Int,
329
349
  ) {
330
- scrollView.layout(0, 0, right - left, bottom - top)
331
350
  val viewWidth = right - left
332
- scrollView.isHorizontalScrollBarEnabled = totalTableWidth > viewWidth
351
+ val overhang = max(ceil(tableStyle.horizontalOverflow.toDouble()).toInt(), 0)
352
+ val contentWidth = viewWidth - overhang * 2
353
+ val tableOverflows = totalTableWidth > contentWidth
354
+
355
+ scrollView.setPadding(overhang, 0, overhang, 0)
356
+ scrollView.clipToPadding = !tableOverflows
357
+ scrollView.isHorizontalScrollBarEnabled = tableOverflows
358
+
359
+ scrollView.layout(0, 0, viewWidth, bottom - top)
360
+
361
+ gridContainer.translationX =
362
+ if (tableStyle.align.isNotEmpty() && !tableOverflows) {
363
+ val freeSpace = max(contentWidth - totalTableWidth, 0f)
364
+ val desiredLeft =
365
+ overhang +
366
+ when (tableStyle.align) {
367
+ "center" -> freeSpace / 2f
368
+ "right" -> freeSpace
369
+ else -> 0f
370
+ }
371
+ desiredLeft - gridContainer.left
372
+ } else {
373
+ 0f
374
+ }
333
375
 
334
- if (isRtl && totalTableWidth > viewWidth) {
335
- scrollView.scrollTo((totalTableWidth - viewWidth).toInt(), 0)
376
+ if (isRtl) {
377
+ val effectiveWidth = if (tableOverflows) contentWidth.toFloat() else viewWidth.toFloat()
378
+ if (totalTableWidth > effectiveWidth) {
379
+ scrollView.scrollTo((totalTableWidth - effectiveWidth).toInt(), 0)
380
+ }
336
381
  }
337
382
  }
338
383
 
339
384
  private fun showContextMenu(anchor: View) {
385
+ if (contextMenuHidden) {
386
+ onMenuSuppressed?.invoke(tableMarkdown, buildPlainText())
387
+ return
388
+ }
340
389
  val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
341
390
  ContextMenuPopup.show(anchor, this) {
342
- item(ContextMenuPopup.Icon.COPY, copyLabel) {
343
- val plainText = rows.joinToString("\n") { row -> row.joinToString("\t") { it.plainText } }
391
+ blockCopyItems(menuOptions, copyLabel, copyAsMarkdownLabel, markdown = { tableMarkdown }, rawText = ::buildPlainText, copyRaw = {
392
+ val plainText = buildPlainText()
344
393
  if (plainText.isNotEmpty()) {
345
394
  val displayMetrics = context.resources.displayMetrics
346
395
  val tableRows =
@@ -350,13 +399,14 @@ class TableContainerView(
350
399
  val html = HTMLGenerator.generateTableHTML(tableRows, styleConfig, displayMetrics.scaledDensity, displayMetrics.density)
351
400
  clipboard.setPrimaryClip(ClipData.newHtmlText("Table", plainText, html))
352
401
  }
353
- }
354
- item(ContextMenuPopup.Icon.DOCUMENT, copyAsMarkdownLabel) {
402
+ }, copyMarkdown = {
355
403
  if (tableMarkdown.isNotEmpty()) clipboard.setPrimaryClip(ClipData.newPlainText("Table", tableMarkdown))
356
- }
404
+ })
357
405
  }
358
406
  }
359
407
 
408
+ private fun buildPlainText(): String = rows.joinToString("\n") { row -> row.joinToString("\t") { it.plainText } }
409
+
360
410
  private fun buildMarkdownFromRows(): String =
361
411
  rows.joinToString("") { row ->
362
412
  val line = "| ${row.joinToString(" | ") { it.markdownText }} |\n"
@@ -456,7 +506,7 @@ class TableContainerView(
456
506
  .apply { configure(config, context) }
457
507
  .renderDocument(MarkdownASTNode(NodeType.Document, children = listOf(paragraph)), null, null)
458
508
  }
459
- styledText.replaceMathSpansWithPlaceholders(context, config.inlineMathStyle.paddingVertical)
509
+ styledText.replaceMathSpansWithPlaceholders(context, config.inlineMathStyle.boxPaddingVertical)
460
510
  if (isHeader && styledText.isNotEmpty()) {
461
511
  styledText.setSpan(HeaderTypefaceSpan(headerTypeface), 0, styledText.length, 33)
462
512
  }