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
@@ -30,26 +30,32 @@ static inline void ENRMDetachLayoutManager(ENRMPlatformTextView *textView)
30
30
  }
31
31
  }
32
32
 
33
- static inline CGSize ENRMMeasureMarkdownText(ENRMPlatformTextView *textView, CGFloat maxWidth, StyleConfig *config,
34
- BOOL allowTrailingMargin, CGFloat lastElementMarginBottom)
33
+ /// Turns a raw TextKit layout pass into the final measured size. Shared by
34
+ /// the view-backed path (`ENRMMeasureMarkdownText`) and the view-free path
35
+ /// (`ENRMMeasureMarkdownViewFree`) so both measure with one algorithm.
36
+ ///
37
+ /// Steps, in order:
38
+ /// - Multiline pin: if the first line fragment doesn't span all glyphs the
39
+ /// text wrapped, and returning the tight usedRect width would let flexShrink
40
+ /// narrow the view below maxWidth, re-wrapping at the narrower width and
41
+ /// mismatching the measured height — so multiline content reports maxWidth,
42
+ /// while single-line content keeps its tight width for shrink-to-fit.
43
+ /// - Subtract the extra line fragment (iOS counts a trailing newline's empty
44
+ /// line fragment into usedRect).
45
+ /// - Add code-block padding when the last element is a code block, and the
46
+ /// trailing margin when enabled.
47
+ /// - Round up to the pixel grid of `scale` (pass `RCTScreenScale()` on main;
48
+ /// off-main callers must pass `LayoutContext::pointScaleFactor` instead —
49
+ /// `RCTScreenScale()` dispatch_syncs to main on first use, which the
50
+ /// measure path must never do, see issue #550).
51
+ static inline CGSize ENRMFinalizeMeasuredTextSize(ENRMTextLayoutResult layout, NSLayoutManager *layoutManager,
52
+ NSAttributedString *text, CGFloat maxWidth, StyleConfig *config,
53
+ BOOL allowTrailingMargin, CGFloat lastElementMarginBottom,
54
+ CGFloat scale)
35
55
  {
36
- NSAttributedString *text = ENRMGetAttributedText(textView);
37
- if (text.length == 0) {
38
- return CGSizeZero;
39
- }
40
-
41
- ENRMTextLayoutResult layout = ENRMMeasureTextLayout(textView, maxWidth);
42
-
43
56
  CGFloat measuredWidth = layout.usedRect.size.width;
44
57
  CGFloat measuredHeight = layout.usedRect.size.height;
45
58
 
46
- // Detect multiline content by checking if the layout produced more than one
47
- // line fragment. When text wraps, returning the tight usedRect width lets
48
- // flexShrink narrow the view below maxWidth, causing re-wrap at the narrower
49
- // width and a height mismatch. Pin to maxWidth for multiline content so Yoga
50
- // assigns the width the text was actually measured at. Single-line content
51
- // keeps its tight width for shrink-to-fit behavior.
52
- NSLayoutManager *layoutManager = textView.layoutManager;
53
59
  NSUInteger glyphCount = [layoutManager numberOfGlyphs];
54
60
  if (glyphCount > 0) {
55
61
  NSRange firstLineRange;
@@ -71,8 +77,20 @@ static inline CGSize ENRMMeasureMarkdownText(ENRMPlatformTextView *textView, CGF
71
77
  measuredHeight += lastElementMarginBottom;
72
78
  }
73
79
 
74
- CGFloat scale = RCTScreenScale();
75
80
  return CGSizeMake(ceil(measuredWidth * scale) / scale, ceil(measuredHeight * scale) / scale);
76
81
  }
77
82
 
83
+ static inline CGSize ENRMMeasureMarkdownText(ENRMPlatformTextView *textView, CGFloat maxWidth, StyleConfig *config,
84
+ BOOL allowTrailingMargin, CGFloat lastElementMarginBottom)
85
+ {
86
+ NSAttributedString *text = ENRMGetAttributedText(textView);
87
+ if (text.length == 0) {
88
+ return CGSizeZero;
89
+ }
90
+
91
+ ENRMTextLayoutResult layout = ENRMMeasureTextLayout(textView, maxWidth);
92
+ return ENRMFinalizeMeasuredTextSize(layout, textView.layoutManager, text, maxWidth, config, allowTrailingMargin,
93
+ lastElementMarginBottom, RCTScreenScale());
94
+ }
95
+
78
96
  NS_ASSUME_NONNULL_END
@@ -9,6 +9,12 @@ NS_ASSUME_NONNULL_BEGIN
9
9
  typedef struct {
10
10
  BOOL copyAsMarkdown;
11
11
  BOOL copyImageURL;
12
+ BOOL copyEnabled;
13
+ // Copy writes Markdown as plain text instead of rich text.
14
+ BOOL copyFormatMarkdown;
15
+ // Drop every system-provided item from the text selection menu.
16
+ BOOL systemItemsNone;
17
+ BOOL codeBlockCopyButton;
12
18
  // The owner must keep these strings alive for the duration of the call (the
13
19
  // view holds them in strong ivars).
14
20
  __unsafe_unretained NSString *_Nullable copyLabel;
@@ -36,6 +42,13 @@ static inline NSString *ENRMResolveImageURLsTitle(ENRMSelectionMenuConfig config
36
42
  return [titleTemplate stringByReplacingOccurrencesOfString:@"{count}" withString:[@(count) stringValue]];
37
43
  }
38
44
 
45
+ /// Defaults matching the JS-side defaults, used until the first props update.
46
+ static inline ENRMSelectionMenuConfig ENRMDefaultSelectionMenuConfig(void)
47
+ {
48
+ return (ENRMSelectionMenuConfig){
49
+ .copyAsMarkdown = YES, .copyImageURL = YES, .copyEnabled = YES, .codeBlockCopyButton = YES};
50
+ }
51
+
39
52
  #ifdef __cplusplus
40
53
 
41
54
  /// Strong owners for the label strings in ENRMSelectionMenuConfig.
@@ -63,13 +76,17 @@ template <typename T> static inline ENRMSelectionMenuLabels ENRMParseSelectionMe
63
76
  };
64
77
  }
65
78
 
66
- /// Builds an ENRMSelectionMenuConfig from pre-parsed labels and boolean flags.
67
- static inline ENRMSelectionMenuConfig ENRMBuildSelectionMenuConfig(const ENRMSelectionMenuLabels &labels,
68
- bool copyAsMarkdown, bool copyImageUrl)
79
+ /// Builds an ENRMSelectionMenuConfig from pre-parsed labels and the codegen struct's flags.
80
+ template <typename T>
81
+ static inline ENRMSelectionMenuConfig ENRMBuildSelectionMenuConfig(const ENRMSelectionMenuLabels &labels, const T &src)
69
82
  {
70
83
  return (ENRMSelectionMenuConfig){
71
- .copyAsMarkdown = copyAsMarkdown,
72
- .copyImageURL = copyImageUrl,
84
+ .copyAsMarkdown = src.copyAsMarkdown,
85
+ .copyImageURL = src.copyImageUrl,
86
+ .copyEnabled = src.copyEnabled,
87
+ .copyFormatMarkdown = src.copyFormatMarkdown,
88
+ .systemItemsNone = src.systemItemsNone,
89
+ .codeBlockCopyButton = src.codeBlockCopyButton,
73
90
  .copyLabel = labels.copyLabel,
74
91
  .copyAsMarkdownLabel = labels.copyAsMarkdownLabel,
75
92
  .copyImageUrlLabel = labels.copyImageUrlLabel,
@@ -10,14 +10,24 @@ static NSString *const kActionIdentifierCopy = @"com.swmansion.enriched.markdown
10
10
  static NSString *const kActionIdentifierCopyMarkdown = @"com.swmansion.enriched.markdown.copyMarkdown";
11
11
  static NSString *const kActionIdentifierCopyImageURL = @"com.swmansion.enriched.markdown.copyImageURL";
12
12
 
13
- static UIAction *createCopyAction(NSAttributedString *selectedText, NSString *markdown, StyleConfig *styleConfig,
14
- NSString *copyLabel)
13
+ static UIAction *_Nullable createCopyAction(NSAttributedString *selectedText, NSString *markdown,
14
+ StyleConfig *styleConfig, ENRMSelectionMenuConfig selectionMenuConfig)
15
15
  {
16
- return [UIAction actionWithTitle:copyLabel
16
+ if (!selectionMenuConfig.copyEnabled)
17
+ return nil;
18
+
19
+ BOOL writesMarkdown = selectionMenuConfig.copyFormatMarkdown;
20
+ return [UIAction actionWithTitle:selectionMenuConfig.copyLabel
17
21
  image:[RCTUIImage systemImageNamed:@"doc.on.doc"]
18
22
  identifier:kActionIdentifierCopy
19
23
  handler:^(__kindof UIAction *action) {
20
- copyAttributedStringToPasteboard(selectedText, markdown, styleConfig);
24
+ if (!writesMarkdown) {
25
+ copyAttributedStringToPasteboard(selectedText, markdown, styleConfig);
26
+ } else {
27
+ // Plain text only: with HTML/RTF alongside, rich-paste targets
28
+ // would take those and drop the Markdown.
29
+ copyStringToPasteboard(markdown.length > 0 ? markdown : selectedText.string);
30
+ }
21
31
  }];
22
32
  }
23
33
 
@@ -47,13 +57,37 @@ static UIAction *_Nullable createCopyImageURLAction(NSArray<NSString *> *imageUR
47
57
  handler:^(__kindof UIAction *action) { copyStringToPasteboard(urlsToCopy); }];
48
58
  }
49
59
 
50
- static UIMenu *createEnhancedStandardEditMenu(UIMenu *originalMenu, UIAction *copyAction)
60
+ /// Rebuilds the standard-edit menu with the system Copy swapped for the enhanced
61
+ /// copy action, or dropped when `copyAction` is nil (Copy disabled). All other
62
+ /// system items are kept — dropping them would remove Select All, which on
63
+ /// iOS 16+ is the only way to start a selection from the long-press menu of a
64
+ /// non-editable text view.
65
+ static UIMenu *createEnhancedStandardEditMenu(UIMenu *originalMenu, UIAction *_Nullable copyAction)
51
66
  {
67
+ NSMutableArray<UIMenuElement *> *children = [NSMutableArray arrayWithCapacity:originalMenu.children.count];
68
+ BOOL replacedCopy = NO;
69
+
70
+ for (UIMenuElement *element in originalMenu.children) {
71
+ if (!replacedCopy && [element isKindOfClass:[UICommand class]] &&
72
+ ((UICommand *)element).action == @selector(copy:)) {
73
+ if (copyAction) {
74
+ [children addObject:copyAction];
75
+ }
76
+ replacedCopy = YES;
77
+ continue;
78
+ }
79
+ [children addObject:element];
80
+ }
81
+
82
+ if (!replacedCopy && copyAction) {
83
+ [children insertObject:copyAction atIndex:0];
84
+ }
85
+
52
86
  return [UIMenu menuWithTitle:originalMenu.title
53
87
  image:originalMenu.image
54
88
  identifier:originalMenu.identifier
55
89
  options:originalMenu.options
56
- children:@[ copyAction ]];
90
+ children:children];
57
91
  }
58
92
 
59
93
  static void addOptionalAction(NSMutableArray<UIMenuElement *> *array, UIAction *_Nullable action)
@@ -80,7 +114,7 @@ UIMenu *buildEditMenuForSelection(NSAttributedString *attributedText, NSRange ra
80
114
  NSString *markdown = markdownForRange(attributedText, range, cachedMarkdown);
81
115
  NSArray<NSString *> *imageURLs = imageURLsInRange(attributedText, range);
82
116
 
83
- UIAction *copyAction = createCopyAction(selectedText, markdown, styleConfig, selectionMenuConfig.copyLabel);
117
+ UIAction *copyAction = createCopyAction(selectedText, markdown, styleConfig, selectionMenuConfig);
84
118
  UIAction *copyMarkdownAction = selectionMenuConfig.copyAsMarkdown
85
119
  ? createCopyMarkdownAction(markdown, selectionMenuConfig.copyAsMarkdownLabel)
86
120
  : nil;
@@ -88,6 +122,16 @@ UIMenu *buildEditMenuForSelection(NSAttributedString *attributedText, NSRange ra
88
122
  selectionMenuConfig.copyImageURL ? createCopyImageURLAction(imageURLs, selectionMenuConfig) : nil;
89
123
 
90
124
  NSMutableArray<UIMenuElement *> *result = [NSMutableArray array];
125
+
126
+ if (selectionMenuConfig.systemItemsNone) {
127
+ // Skip suggestedActions entirely. An empty result still yields an (empty)
128
+ // menu: returning nil would make UIKit present its default menu.
129
+ addOptionalAction(result, copyAction);
130
+ addOptionalAction(result, copyMarkdownAction);
131
+ addOptionalAction(result, copyImageURLAction);
132
+ return [UIMenu menuWithChildren:[(customActions ?: @[]) arrayByAddingObjectsFromArray:result]];
133
+ }
134
+
91
135
  BOOL foundStandardEditMenu = NO;
92
136
 
93
137
  for (UIMenuElement *element in suggestedActions) {
@@ -107,8 +151,8 @@ UIMenu *buildEditMenuForSelection(NSAttributedString *attributedText, NSRange ra
107
151
  }
108
152
 
109
153
  if (!foundStandardEditMenu) {
110
- [result insertObject:copyAction atIndex:0];
111
- insertOptionalAction(result, copyMarkdownAction, 1);
154
+ insertOptionalAction(result, copyMarkdownAction, 0);
155
+ insertOptionalAction(result, copyAction, 0);
112
156
  addOptionalAction(result, copyImageURLAction);
113
157
  }
114
158
 
@@ -0,0 +1,35 @@
1
+ #pragma once
2
+
3
+ #import <Foundation/Foundation.h>
4
+
5
+ #ifdef __cplusplus
6
+ #include <vector>
7
+
8
+ template <typename T>
9
+ static bool ENRMImageRequestHeadersChanged(const std::vector<T> &oldHeaders, const std::vector<T> &newHeaders)
10
+ {
11
+ if (newHeaders.size() != oldHeaders.size()) {
12
+ return true;
13
+ }
14
+ for (size_t i = 0; i < newHeaders.size(); i++) {
15
+ if (newHeaders[i].name != oldHeaders[i].name || newHeaders[i].value != oldHeaders[i].value) {
16
+ return true;
17
+ }
18
+ }
19
+ return false;
20
+ }
21
+
22
+ template <typename T>
23
+ static NSDictionary<NSString *, NSString *> *_Nullable ENRMImageRequestHeadersFromProps(const std::vector<T> &headers)
24
+ {
25
+ if (headers.empty()) {
26
+ return nil;
27
+ }
28
+ NSMutableDictionary<NSString *, NSString *> *result = [NSMutableDictionary dictionaryWithCapacity:headers.size()];
29
+ for (const auto &header : headers) {
30
+ result[@(header.name.c_str())] = @(header.value.c_str());
31
+ }
32
+ return [result copy];
33
+ }
34
+
35
+ #endif
@@ -4,6 +4,7 @@
4
4
  NS_ASSUME_NONNULL_BEGIN
5
5
 
6
6
  static NSString *const CodeBlockAttributeName = @"CodeBlock";
7
+ static NSString *const CodeBlockIndentAttributeName = @"CodeBlockIndent";
7
8
 
8
9
  /**
9
10
  * Returns YES when the last semantic block in the storage is a code block, ignoring any
@@ -5,11 +5,7 @@
5
5
  #import "RenderContext.h"
6
6
  #import "StyleConfig.h"
7
7
 
8
- extern NSString *const ListDepthAttribute;
9
- extern NSString *const ListTypeAttribute;
10
- extern NSString *const ListItemNumberAttribute;
11
- extern NSString *const TaskItemAttribute;
12
- extern NSString *const TaskCheckedAttribute;
8
+ extern NSString *const ListItemMarkerStartAttribute;
13
9
 
14
10
  @implementation ListMarkerDrawer {
15
11
  StyleConfig *_config;
@@ -44,13 +40,13 @@ extern NSString *const TaskCheckedAttribute;
44
40
  if (charRange.location == NSNotFound)
45
41
  return;
46
42
 
47
- // 1. Fetch all attributes at once for efficiency
48
43
  NSDictionary *attrs = [storage attributesAtIndex:charRange.location
49
44
  effectiveRange:NULL];
50
- if (!attrs[ListDepthAttribute])
45
+ NSArray *markers = attrs[ListItemMarkerStartAttribute];
46
+ if (![markers isKindOfClass:[NSArray class]] || markers.count == 0)
51
47
  return;
52
48
 
53
- // 2. Identify the start of the paragraph
49
+ // Identify the start of the paragraph
54
50
  NSRange paraRange = [storage.string paragraphRangeForRange:charRange];
55
51
  if (charRange.location != paraRange.location ||
56
52
  [drawnParagraphs containsObject:@(paraRange.location)])
@@ -61,30 +57,28 @@ extern NSString *const TaskCheckedAttribute;
61
57
 
62
58
  CGPoint glyphLoc = [layoutManager locationForGlyphAtIndex:glyphRange.location];
63
59
  CGFloat baselineY = origin.y + rect.origin.y + glyphLoc.y;
64
- CGFloat markerX;
65
- if (isRTL) {
66
- markerX = origin.x + usedRect.origin.x + usedRect.size.width + gap;
67
- } else {
68
- markerX = origin.x + usedRect.origin.x - gap;
69
- }
70
-
71
- // 4. Draw marker based on type
72
- if ([attrs[TaskItemAttribute] boolValue]) {
73
- UIFont *font = attrs[NSFontAttributeName] ?: [self defaultFont];
74
- BOOL checked = [attrs[TaskCheckedAttribute] boolValue];
75
- const CGFloat size = [_config taskListCheckboxSize];
76
- CGFloat checkboxX = isRTL ? markerX + size / 2.0 : markerX - size / 2.0;
77
- [self drawCheckboxAtX:checkboxX
78
- centerY:baselineY - (font.capHeight / 2.0)
79
- checked:checked];
80
- } else if ([attrs[ListTypeAttribute] integerValue] == ListTypeUnordered) {
81
- UIFont *font = attrs[NSFontAttributeName] ?: [self defaultFont];
82
- NSInteger depth = [attrs[ListDepthAttribute] integerValue];
83
- [self drawBulletAtX:markerX
84
- centerY:baselineY - (font.xHeight + font.capHeight) / 4.0
85
- depth:depth];
86
- } else {
87
- [self drawOrderedMarkerAtX:markerX attrs:attrs baselineY:baselineY isRTL:isRTL];
60
+ UIFont *font = attrs[NSFontAttributeName] ?: [self defaultFont];
61
+
62
+ for (ENRMListMarkerDescriptor *marker in markers) {
63
+ CGFloat markerX = isRTL ? origin.x + container.size.width - marker.indent + gap
64
+ : origin.x + marker.indent - gap;
65
+
66
+ if (marker.isTask) {
67
+ const CGFloat size = [_config taskListCheckboxSize];
68
+ CGFloat checkboxX = isRTL ? markerX + size / 2.0 : markerX - size / 2.0;
69
+ [self drawCheckboxAtX:checkboxX
70
+ centerY:baselineY - (font.capHeight / 2.0)
71
+ checked:marker.isChecked];
72
+ } else if (marker.listType == ListTypeUnordered) {
73
+ [self drawBulletAtX:markerX
74
+ centerY:baselineY - (font.xHeight + font.capHeight) / 4.0
75
+ depth:marker.depth];
76
+ } else {
77
+ [self drawOrderedMarkerAtX:markerX
78
+ number:marker.number
79
+ baselineY:baselineY
80
+ isRTL:isRTL];
81
+ }
88
82
  }
89
83
  }];
90
84
  }
@@ -167,17 +161,10 @@ extern NSString *const TaskCheckedAttribute;
167
161
  y:y];
168
162
  }
169
163
 
170
- - (void)drawOrderedMarkerAtX:(CGFloat)boundaryX
171
- attrs:(NSDictionary *)attrs
172
- baselineY:(CGFloat)baselineY
173
- isRTL:(BOOL)isRTL
164
+ - (void)drawOrderedMarkerAtX:(CGFloat)boundaryX number:(NSInteger)number baselineY:(CGFloat)baselineY isRTL:(BOOL)isRTL
174
165
  {
175
- NSNumber *num = attrs[ListItemNumberAttribute];
176
- if (!num)
177
- return;
178
-
179
- NSString *text = isRTL ? [NSString stringWithFormat:@".%ld", (long)num.integerValue]
180
- : [NSString stringWithFormat:@"%ld.", (long)num.integerValue];
166
+ NSString *text =
167
+ isRTL ? [NSString stringWithFormat:@".%ld", (long)number] : [NSString stringWithFormat:@"%ld.", (long)number];
181
168
  UIFont *font = [_config listMarkerFont] ?: [self defaultFont];
182
169
 
183
170
  NSDictionary *mAttrs = @{NSFontAttributeName : font, NSForegroundColorAttributeName : [_config listStyleMarkerColor]};
@@ -22,6 +22,10 @@ static void serializeNode(MarkdownASTNode *node, NSMutableString *buffer)
22
22
  break;
23
23
 
24
24
  case MarkdownNodeTypeLineBreak:
25
+ [buffer appendString:@"\\\n"];
26
+ break;
27
+
28
+ case MarkdownNodeTypeSoftBreak:
25
29
  [buffer appendString:@"\n"];
26
30
  break;
27
31
 
@@ -45,6 +45,11 @@ NSUInteger applyBlockSpacingBefore(NSMutableAttributedString *output, NSUInteger
45
45
  void applyBlockSpacingAfter(NSMutableAttributedString *output, CGFloat marginBottom);
46
46
  void applyLineHeight(NSMutableAttributedString *output, NSRange range, CGFloat lineHeight);
47
47
  void applyBaselineOffset(NSMutableAttributedString *output, NSRange range);
48
+
49
+ /// True when the range contains a block (non-inline) image attachment. Lines holding
50
+ /// such attachments must not be clamped by maximumLineHeight or the image box
51
+ /// overflows the line and paints over surrounding content.
52
+ BOOL ENRMRangeContainsBlockImage(NSAttributedString *output, NSRange range);
48
53
  void applyTextAlignment(NSMutableAttributedString *output, NSRange range, NSTextAlignment textAlign);
49
54
  NSTextAlignment textAlignmentFromString(NSString *textAlign);
50
55
 
@@ -1,5 +1,6 @@
1
1
  #import "ParagraphStyleUtils.h"
2
2
  #import "ENRMFeatureFlags.h"
3
+ #import "ENRMImageAttachment.h"
3
4
  #import "LastElementUtils.h"
4
5
  #import <React/RCTI18nUtil.h>
5
6
 
@@ -246,6 +247,21 @@ void applyBlockSpacingAfter(NSMutableAttributedString *output, CGFloat marginBot
246
247
  [output addAttribute:NSParagraphStyleAttributeName value:spacerStyle range:NSMakeRange(spacerLocation, 1)];
247
248
  }
248
249
 
250
+ BOOL ENRMRangeContainsBlockImage(NSAttributedString *output, NSRange range)
251
+ {
252
+ __block BOOL found = NO;
253
+ [output enumerateAttribute:NSAttachmentAttributeName
254
+ inRange:range
255
+ options:0
256
+ usingBlock:^(id value, __unused NSRange attrRange, BOOL *stop) {
257
+ if ([value isKindOfClass:[ENRMImageAttachment class]] && !((ENRMImageAttachment *)value).isInline) {
258
+ found = YES;
259
+ *stop = YES;
260
+ }
261
+ }];
262
+ return found;
263
+ }
264
+
249
265
  void applyLineHeight(NSMutableAttributedString *output, NSRange range, CGFloat lineHeight)
250
266
  {
251
267
  if (lineHeight <= 0) {
@@ -266,10 +282,12 @@ void applyLineHeight(NSMutableAttributedString *output, NSRange range, CGFloat l
266
282
  }];
267
283
  #endif
268
284
 
285
+ BOOL hasBlockImage = ENRMRangeContainsBlockImage(output, range);
286
+
269
287
  NSMutableParagraphStyle *style = getOrCreateParagraphStyle(output, range.location);
270
288
 
271
289
  style.minimumLineHeight = lineHeight;
272
- style.maximumLineHeight = hasMath ? 0 : lineHeight;
290
+ style.maximumLineHeight = (hasMath || hasBlockImage) ? 0 : lineHeight;
273
291
 
274
292
  [output addAttribute:NSParagraphStyleAttributeName value:style range:range];
275
293
  }
@@ -284,7 +302,8 @@ void applyBaselineOffset(NSMutableAttributedString *output, NSRange range)
284
302
  return;
285
303
  }
286
304
 
287
- __block CGFloat maximumLineHeight = 0;
305
+ // Math paragraphs leave maximumLineHeight at 0, so fall back to minimumLineHeight.
306
+ __block CGFloat targetLineHeight = 0;
288
307
  [output enumerateAttribute:NSParagraphStyleAttributeName
289
308
  inRange:range
290
309
  options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
@@ -292,29 +311,59 @@ void applyBaselineOffset(NSMutableAttributedString *output, NSRange range)
292
311
  if (!paragraphStyle) {
293
312
  return;
294
313
  }
295
- maximumLineHeight = MAX(paragraphStyle.maximumLineHeight, maximumLineHeight);
314
+ CGFloat clamp = MAX(paragraphStyle.maximumLineHeight, paragraphStyle.minimumLineHeight);
315
+ targetLineHeight = MAX(clamp, targetLineHeight);
296
316
  }];
297
317
 
298
- if (maximumLineHeight <= 0) {
318
+ if (targetLineHeight <= 0) {
299
319
  return;
300
320
  }
301
321
 
302
- __block CGFloat maximumFontLineHeight = 0;
303
- [output enumerateAttribute:NSFontAttributeName
304
- inRange:range
305
- options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
306
- usingBlock:^(UIFont *font, __unused NSRange subrange, __unused BOOL *stop) {
307
- if (!font) {
308
- return;
309
- }
310
- maximumFontLineHeight = MAX(UIFontLineHeight(font), maximumFontLineHeight);
311
- }];
322
+ // Center on real text; on a math-only line center the math box instead of its font.
323
+ __block CGFloat textLineHeight = 0;
324
+ #if ENRICHED_MARKDOWN_MATH
325
+ __block BOOL hasMath = NO;
326
+ #endif
327
+ [output enumerateAttributesInRange:range
328
+ options:0
329
+ usingBlock:^(NSDictionary<NSAttributedStringKey, id> *attrs, __unused NSRange subrange,
330
+ __unused BOOL *stop) {
331
+ #if ENRICHED_MARKDOWN_MATH
332
+ if ([attrs[NSAttachmentAttributeName] isKindOfClass:[ENRMMathInlineAttachment class]]) {
333
+ hasMath = YES;
334
+ return;
335
+ }
336
+ #endif
337
+ UIFont *font = attrs[NSFontAttributeName];
338
+ if (font) {
339
+ textLineHeight = MAX(UIFontLineHeight(font), textLineHeight);
340
+ }
341
+ }];
342
+
343
+ CGFloat contentLineHeight = textLineHeight;
344
+
345
+ #if ENRICHED_MARKDOWN_MATH
346
+ // Math only grows the content height, so measure it (parsing LaTeX) only when text
347
+ // alone wouldn't already fill the line.
348
+ if (hasMath && targetLineHeight > textLineHeight) {
349
+ __block CGFloat mathBoxHeight = 0;
350
+ [output enumerateAttribute:NSAttachmentAttributeName
351
+ inRange:range
352
+ options:0
353
+ usingBlock:^(id value, __unused NSRange subrange, __unused BOOL *stop) {
354
+ if ([value isKindOfClass:[ENRMMathInlineAttachment class]]) {
355
+ mathBoxHeight = MAX(((ENRMMathInlineAttachment *)value).boxHeight, mathBoxHeight);
356
+ }
357
+ }];
358
+ contentLineHeight = MAX(textLineHeight, mathBoxHeight);
359
+ }
360
+ #endif
312
361
 
313
- if (maximumFontLineHeight <= 0 || maximumLineHeight < maximumFontLineHeight) {
362
+ if (contentLineHeight <= 0 || targetLineHeight <= contentLineHeight) {
314
363
  return;
315
364
  }
316
365
 
317
- CGFloat baseLineOffset = (maximumLineHeight - maximumFontLineHeight) / 2.0;
366
+ CGFloat baseLineOffset = (targetLineHeight - contentLineHeight) / 2.0;
318
367
 
319
368
  [output enumerateAttribute:NSBaselineOffsetAttributeName
320
369
  inRange:range
@@ -323,7 +372,18 @@ void applyBaselineOffset(NSMutableAttributedString *output, NSRange range)
323
372
  if (existingOffset != nil) {
324
373
  return;
325
374
  }
326
- [output addAttribute:NSBaselineOffsetAttributeName value:@(baseLineOffset) range:subrange];
375
+ [output enumerateAttribute:NSAttachmentAttributeName
376
+ inRange:subrange
377
+ options:0
378
+ usingBlock:^(id attachment, NSRange attachmentRange, BOOL *innerStop) {
379
+ if ([attachment isKindOfClass:[ENRMImageAttachment class]] &&
380
+ !((ENRMImageAttachment *)attachment).isInline) {
381
+ return;
382
+ }
383
+ [output addAttribute:NSBaselineOffsetAttributeName
384
+ value:@(baseLineOffset)
385
+ range:attachmentRange];
386
+ }];
327
387
  }];
328
388
  }
329
389
 
@@ -7,7 +7,12 @@
7
7
 
8
8
  NS_ASSUME_NONNULL_BEGIN
9
9
 
10
- typedef NS_ENUM(NSInteger, ENRMSegmentKind) { ENRMSegmentKindText, ENRMSegmentKindTable, ENRMSegmentKindMath };
10
+ typedef NS_ENUM(NSInteger, ENRMSegmentKind) {
11
+ ENRMSegmentKindText,
12
+ ENRMSegmentKindTable,
13
+ ENRMSegmentKindMath,
14
+ ENRMSegmentKindCodeBlock
15
+ };
11
16
 
12
17
  @interface ENRMTextSegment : NSObject
13
18
  @property (nonatomic, strong) NSArray<MarkdownASTNode *> *nodes;
@@ -24,15 +29,22 @@ typedef NS_ENUM(NSInteger, ENRMSegmentKind) { ENRMSegmentKindText, ENRMSegmentKi
24
29
  + (instancetype)segmentWithLatex:(NSString *)latex;
25
30
  @end
26
31
 
32
+ @interface ENRMCodeBlockSegment : NSObject
33
+ @property (nonatomic, strong) MarkdownASTNode *codeBlockNode;
34
+ + (instancetype)segmentWithCodeBlockNode:(MarkdownASTNode *)node;
35
+ @end
36
+
27
37
  @interface ENRMRenderedSegment : NSObject
28
38
  @property (nonatomic, assign) ENRMSegmentKind kind;
29
39
  @property (nonatomic, assign) uint64_t signature;
30
40
  @property (nonatomic, strong, nullable) ENRMRenderResult *textResult;
31
41
  @property (nonatomic, strong, nullable) ENRMTableSegment *tableSegment;
32
42
  @property (nonatomic, strong, nullable) ENRMMathSegment *mathSegment;
43
+ @property (nonatomic, strong, nullable) ENRMCodeBlockSegment *codeBlockSegment;
33
44
  + (instancetype)textSegmentWithResult:(ENRMRenderResult *)result signature:(uint64_t)signature;
34
45
  + (instancetype)tableSegmentWithSegment:(ENRMTableSegment *)segment signature:(uint64_t)signature;
35
46
  + (instancetype)mathSegmentWithSegment:(ENRMMathSegment *)segment signature:(uint64_t)signature;
47
+ + (instancetype)codeBlockSegmentWithSegment:(ENRMCodeBlockSegment *)segment signature:(uint64_t)signature;
36
48
  @end
37
49
 
38
50
  #ifdef __cplusplus
@@ -31,6 +31,16 @@
31
31
  }
32
32
  @end
33
33
 
34
+ @implementation ENRMCodeBlockSegment
35
+ + (instancetype)segmentWithCodeBlockNode:(MarkdownASTNode *)node
36
+ {
37
+ NSParameterAssert(node != nil);
38
+ ENRMCodeBlockSegment *segment = [[ENRMCodeBlockSegment alloc] init];
39
+ segment.codeBlockNode = node;
40
+ return segment;
41
+ }
42
+ @end
43
+
34
44
  @implementation ENRMRenderedSegment
35
45
  + (instancetype)textSegmentWithResult:(ENRMRenderResult *)result signature:(uint64_t)signature
36
46
  {
@@ -61,6 +71,16 @@
61
71
  segment.signature = signature;
62
72
  return segment;
63
73
  }
74
+
75
+ + (instancetype)codeBlockSegmentWithSegment:(ENRMCodeBlockSegment *)codeBlockSegment signature:(uint64_t)signature
76
+ {
77
+ NSParameterAssert(codeBlockSegment != nil);
78
+ ENRMRenderedSegment *segment = [[ENRMRenderedSegment alloc] init];
79
+ segment.kind = ENRMSegmentKindCodeBlock;
80
+ segment.codeBlockSegment = codeBlockSegment;
81
+ segment.signature = signature;
82
+ return segment;
83
+ }
64
84
  @end
65
85
 
66
86
  // FNV-1a 64-bit hash for segment signatures. Collisions are theoretically