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
@@ -13,6 +13,13 @@ NS_ASSUME_NONNULL_BEGIN
13
13
  - (void)renderMarkdownSynchronously:(NSString *)markdownString;
14
14
  - (BOOL)hasRenderedMarkdown:(NSString *)markdown;
15
15
  - (BOOL)hasRenderedWithStyleFingerprint:(size_t)fingerprint;
16
+
17
+ /// Size last committed by Fabric via `updateLayoutMetrics:`, readable from
18
+ /// any thread without blocking (issue #550: the shadow-node measure path must
19
+ /// never wait on the main thread, and reading `bounds` off-main is unsafe).
20
+ /// Backed by a single lock-free atomic, so the pair can't tear. Returns
21
+ /// CGSizeZero until the first layout is committed.
22
+ - (CGSize)lastCommittedLayoutSize;
16
23
  @end
17
24
 
18
25
  NS_ASSUME_NONNULL_END
@@ -3,9 +3,12 @@
3
3
  #import "ContextMenuUtils.h"
4
4
  #import "ENRMAccessibilityLabels.h"
5
5
  #import "ENRMAsyncRenderCoordinator.h"
6
+ #import "ENRMAtomicSize.h"
6
7
  #import "ENRMContextMenuTextView+macOS.h"
7
8
  #import "ENRMImageAttachment.h"
9
+ #import "ENRMLinkLayout.h"
8
10
  #import "ENRMMarkdownParser.h"
11
+ #import "ENRMSelectionChange.h"
9
12
  #import "ENRMSpoilerOverlayManager.h"
10
13
  #import "ENRMSpoilerTapUtils.h"
11
14
  #import "ENRMTailFadeInAnimator.h"
@@ -17,12 +20,14 @@
17
20
  #import "FontScaleObserver.h"
18
21
  #import "FontUtils.h"
19
22
  #import "HeightUpdateUtils.h"
23
+ #import "ImageRequestHeaderUtils.h"
20
24
  #import "LinkTapUtils.h"
21
25
  #import "MarkdownASTNode.h"
22
26
  #import "MarkdownAccessibilityElementBuilder.h"
23
27
  #import "MarkdownExtractor.h"
24
28
  #import "MeasurementCache.h"
25
29
  #import "ParagraphStyleUtils.h"
30
+ #import "PasteboardUtils.h"
26
31
  #import "RuntimeKeys.h"
27
32
  #import "SelectionColorUtils.h"
28
33
  #import "StylePropsUtils.h"
@@ -45,8 +50,8 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
45
50
  ENRMDirtyRender = 1 << 0,
46
51
  };
47
52
 
48
- @interface EnrichedMarkdownText () <RCTEnrichedMarkdownTextViewProtocol, UITextViewDelegate>
49
- - (void)resetPropDerivedState;
53
+ @interface EnrichedMarkdownText () <RCTEnrichedMarkdownTextViewProtocol, UITextViewDelegate, ENRMImageLayoutObserver>
54
+ + (ENRMMd4cFlags *)flagsFromProps:(const EnrichedMarkdownTextMd4cFlagsStruct &)props;
50
55
  - (void)setupTextView;
51
56
  - (void)renderMarkdownContent:(NSString *)markdownString;
52
57
  - (void)applyRenderedText:(NSMutableAttributedString *)attributedText;
@@ -54,11 +59,13 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
54
59
  - (void)setupLayoutManager;
55
60
  - (void)emitLinkPress:(NSString *)url;
56
61
  - (void)emitLinkLongPress:(NSString *)url;
62
+ - (void)emitLinkLayoutIfNeeded;
57
63
  - (void)emitTaskListItemPress:(NSInteger)index checked:(BOOL)checked text:(NSString *)text;
58
64
  - (void)emitContextMenuItemPress:(NSString *)itemText
59
65
  selectedText:(NSString *)selectedText
60
66
  selectionStart:(NSUInteger)selectionStart
61
67
  selectionEnd:(NSUInteger)selectionEnd;
68
+ - (void)emitCopyRequest:(NSString *)source markdown:(NSString *)markdown text:(NSString *)text whole:(BOOL)whole;
62
69
  @end
63
70
 
64
71
  @implementation EnrichedMarkdownText {
@@ -80,6 +87,9 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
80
87
  CGFloat _lastElementMarginBottom;
81
88
  BOOL _allowTrailingMargin;
82
89
  BOOL _enableLinkPreview;
90
+ BOOL _linkLongPressSelects;
91
+ BOOL _enableTaskListItemToggle;
92
+ BOOL _contextMenuHidden;
83
93
  BOOL _streamingAnimation;
84
94
  BOOL _forceHeightUpdateOnNextRender;
85
95
 
@@ -105,12 +115,22 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
105
115
 
106
116
  ENRMSpoilerOverlayManager *_spoilerManager;
107
117
 
118
+ BOOL _emitLinkLayout;
119
+ NSArray<NSDictionary *> *_lastLinkLayout;
120
+
121
+ ENRMSelectionChangeReporter *_selectionReporter;
122
+ #if !TARGET_OS_OSX
123
+ ENRMSelectionGestureTracker *_selectionGestures;
124
+ #endif
125
+
108
126
  NSLineBreakStrategy _lineBreakStrategy;
109
127
 
110
128
  ENRMWritingDirectionMode _writingDirectionMode;
111
129
  NSWritingDirection _resolvedLayoutDirection;
112
130
 
113
131
  ENRMDirtyFlags _dirtyFlags;
132
+
133
+ ENRMAtomicSize _lastCommittedSize;
114
134
  }
115
135
 
116
136
  + (ComponentDescriptorProvider)componentDescriptorProvider
@@ -118,6 +138,18 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
118
138
  return concreteComponentDescriptorProvider<EnrichedMarkdownTextComponentDescriptor>();
119
139
  }
120
140
 
141
+ + (ENRMMd4cFlags *)flagsFromProps:(const EnrichedMarkdownTextMd4cFlagsStruct &)props
142
+ {
143
+ ENRMMd4cFlags *flags = [ENRMMd4cFlags defaultFlags];
144
+ flags.underline = props.underline;
145
+ flags.superscript = props.superscript;
146
+ flags.subscript = props.subscript;
147
+ flags.latexMath = props.latexMath;
148
+ flags.highlight = props.highlight;
149
+ flags.hardSoftBreaks = props.hardSoftBreaks;
150
+ return flags;
151
+ }
152
+
121
153
  #pragma mark - Measuring and State
122
154
 
123
155
  - (CGSize)measureSize:(CGFloat)maxWidth
@@ -130,6 +162,11 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
130
162
  return size;
131
163
  }
132
164
 
165
+ - (CGSize)lastCommittedLayoutSize
166
+ {
167
+ return _lastCommittedSize.load();
168
+ }
169
+
133
170
  - (BOOL)hasRenderedMarkdown:(NSString *)markdown
134
171
  {
135
172
  return _renderedMarkdown != nil && [_renderedMarkdown isEqualToString:markdown];
@@ -158,6 +195,11 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
158
195
  {
159
196
  [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
160
197
 
198
+ _lastCommittedSize.store(CGSizeMake(layoutMetrics.frame.size.width, layoutMetrics.frame.size.height));
199
+ #if TARGET_OS_OSX
200
+ [self emitLinkLayoutIfNeeded];
201
+ #endif
202
+
161
203
  NSWritingDirection resolved = _resolvedLayoutDirection;
162
204
  if (layoutMetrics.layoutDirection == LayoutDirection::RightToLeft) {
163
205
  resolved = NSWritingDirectionRightToLeft;
@@ -178,44 +220,22 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
178
220
  ENRMRequestHeightUpdate<EnrichedMarkdownTextState>(_state, _heightUpdateCounter, self);
179
221
  }
180
222
 
181
- /// Clears every piece of state that `updateProps` derives from props, back to the
182
- /// values the default-constructed `EnrichedMarkdownTextProps` describes.
183
- ///
184
- /// `updateProps` applies most props as a per-field diff against `_props`, so this
185
- /// state is only correct while it stays in phase with the `_props` baseline it was
186
- /// diffed from. `prepareForRecycle` resets `_props`, so it must reset this too —
187
- /// otherwise every field the next consumer leaves at its default silently inherits
188
- /// the previous consumer's value. Called from `initWithFrame:` as well, so the two
189
- /// baselines cannot drift apart.
190
- ///
191
- /// Requires `_fontScaleObserver` to already exist.
192
- - (void)resetPropDerivedState
193
- {
194
- // Discarded rather than cleared field-by-field: the style diff can only clear a
195
- // field when new and old differ, which never holds against a reset baseline.
196
- _config = nil;
197
- _spoilerManager = nil;
198
-
199
- _md4cFlags = [ENRMMd4cFlags propsDefaultFlags];
200
- _maxFontSizeMultiplier = 0;
201
- _allowTrailingMargin = NO;
202
- _fontScaleObserver.allowFontScaling = YES;
203
- _streamingAnimation = NO;
204
- _lineBreakStrategy = NSLineBreakStrategyNone;
205
- _writingDirectionMode = ENRMWritingDirectionModeFirstStrong;
206
- _contextMenuItemTexts = nil;
207
- _contextMenuItemIcons = nil;
208
- _accessibilityLabels = nil;
209
-
210
- // Written only once a render completes, so stale until the next one lands.
211
- _renderedStyleFingerprint = 0;
212
- _pendingStyleFingerprint = 0;
213
- _lastElementMarginBottom = 0;
223
+ // A block image resolved its box height after loading (maxHeight/aspectRatio
224
+ // sizing). The shadow node measured — and cached — this markdown with the
225
+ // pre-load fallback height, so drop those entries and re-measure.
226
+ - (void)imageAttachmentDidResolveLayout
227
+ {
228
+ if (_renderedMarkdown.length > 0) {
229
+ facebook::react::MeasurementCache::shared().removeMatchingMarkdown(std::string(_renderedMarkdown.UTF8String));
230
+ }
214
231
 
215
- _dirtyFlags = ENRMDirtyNone;
216
- _forceHeightUpdateOnNextRender = NO;
217
- _heightUpdateCounter = 0;
218
- _state = nullptr;
232
+ if (self.bounds.size.width > 0) {
233
+ CGSize measured = [self measureSize:self.bounds.size.width];
234
+ if (needsHeightUpdate(measured, self.bounds)) {
235
+ [self requestHeightUpdate];
236
+ }
237
+ [self emitLinkLayoutIfNeeded];
238
+ }
219
239
  }
220
240
 
221
241
  - (instancetype)initWithFrame:(CGRect)frame
@@ -226,18 +246,25 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
226
246
 
227
247
  self.backgroundColor = [RCTUIColor clearColor];
228
248
  _parser = [[ENRMMarkdownParser alloc] init];
249
+ _md4cFlags = [EnrichedMarkdownText flagsFromProps:defaultProps->md4cFlags];
229
250
 
230
251
  _renderCoordinator =
231
252
  [[ENRMAsyncRenderCoordinator alloc] initWithQueueLabel:"com.swmansion.enriched.markdown.render"];
232
253
 
254
+ _maxFontSizeMultiplier = 0;
255
+ _allowTrailingMargin = NO;
233
256
  _enableLinkPreview = YES;
234
- _selectionMenuConfig = (ENRMSelectionMenuConfig){.copyAsMarkdown = YES, .copyImageURL = YES};
257
+ _enableTaskListItemToggle = YES;
258
+ _forceHeightUpdateOnNextRender = NO;
259
+ _contextMenuHidden = NO;
260
+ _selectionMenuConfig = ENRMDefaultSelectionMenuConfig();
261
+ _lineBreakStrategy = NSLineBreakStrategyNone;
262
+ _writingDirectionMode = ENRMWritingDirectionModeFirstStrong;
235
263
  _resolvedLayoutDirection =
236
264
  [[RCTI18nUtil sharedInstance] isRTL] ? NSWritingDirectionRightToLeft : NSWritingDirectionLeftToRight;
265
+ _dirtyFlags = ENRMDirtyNone;
237
266
 
238
267
  _fontScaleObserver = [[FontScaleObserver alloc] init];
239
- [self resetPropDerivedState];
240
-
241
268
  __weak EnrichedMarkdownText *weakSelf = self;
242
269
  _fontScaleObserver.onChange = ^{
243
270
  EnrichedMarkdownText *strongSelf = weakSelf;
@@ -253,11 +280,82 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
253
280
  };
254
281
 
255
282
  [self setupTextView];
283
+ [self setupSelectionReporter];
256
284
  }
257
285
 
258
286
  return self;
259
287
  }
260
288
 
289
+ - (void)setupSelectionReporter
290
+ {
291
+ __weak EnrichedMarkdownText *weakSelf = self;
292
+ _selectionReporter = [[ENRMSelectionChangeReporter alloc]
293
+ initWithSnapshot:^NSDictionary * {
294
+ EnrichedMarkdownText *strongSelf = weakSelf;
295
+ return strongSelf ? [strongSelf selectionPayload] : ENRMInactiveSelectionPayload();
296
+ }
297
+ emit:^(NSDictionary *payload) {
298
+ EnrichedMarkdownText *strongSelf = weakSelf;
299
+ if (!strongSelf)
300
+ return;
301
+ auto emitter = std::static_pointer_cast<EnrichedMarkdownTextEventEmitter const>(strongSelf->_eventEmitter);
302
+ if (emitter)
303
+ emitter->onSelectionChange(
304
+ ENRMSelectionChangeEventFromPayload<EnrichedMarkdownTextEventEmitter::OnSelectionChange>(payload));
305
+ }];
306
+ #if !TARGET_OS_OSX
307
+ // A handle drag starting or ending is reported right away, even when the
308
+ // selection itself is unchanged.
309
+ _selectionGestures = [[ENRMSelectionGestureTracker alloc] initWithChange:^{
310
+ EnrichedMarkdownText *strongSelf = weakSelf;
311
+ if (!strongSelf)
312
+ return;
313
+ [strongSelf->_selectionGestures trackTextView:strongSelf->_textView];
314
+ [strongSelf->_selectionReporter forgetLastReported];
315
+ [strongSelf->_selectionReporter flushNow];
316
+ }];
317
+ [_selectionGestures trackTextView:_textView];
318
+ #endif
319
+ }
320
+
321
+ /// The current selection as an `onSelectionChange` payload. Markdown and
322
+ /// `whole` follow the same rules as the intercepted Copy (`onCopyRequest`).
323
+ - (NSDictionary *)selectionPayload
324
+ {
325
+ #if !TARGET_OS_OSX
326
+ NSDictionary *selection = ENRMTextSelectionInTextView(_textView, self);
327
+ if (!selection)
328
+ return ENRMInactiveSelectionPayload();
329
+
330
+ NSString *text = selection[ENRMSelectionTextKey];
331
+ NSString *markdown = markdownForRange(_textView.attributedText, _textView.selectedRange, _cachedMarkdown);
332
+ NSMutableDictionary *payload = [selection mutableCopy];
333
+ [payload removeObjectForKey:ENRMSelectionFullKey];
334
+ payload[ENRMSelectionActiveKey] = @YES;
335
+ payload[ENRMSelectionSourceKey] = @"selection";
336
+ payload[ENRMSelectionMarkdownKey] = markdown.length > 0 ? markdown : text;
337
+ payload[ENRMSelectionWholeKey] = @([selection[ENRMSelectionFullKey] boolValue] && _cachedMarkdown.length > 0);
338
+ payload[ENRMSelectionAdjustingKey] = @(_selectionGestures.adjusting);
339
+ return payload;
340
+ #else
341
+ return ENRMInactiveSelectionPayload();
342
+ #endif
343
+ }
344
+
345
+ - (void)clearSelection
346
+ {
347
+ #if !TARGET_OS_OSX
348
+ _textView.selectedRange = NSMakeRange(0, 0);
349
+ [_textView resignFirstResponder];
350
+ #endif
351
+ [_selectionReporter flushNow];
352
+ }
353
+
354
+ - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
355
+ {
356
+ RCTEnrichedMarkdownTextHandleCommand(self, commandName, args);
357
+ }
358
+
261
359
  - (void)setupTextView
262
360
  {
263
361
  #if !TARGET_OS_OSX
@@ -280,6 +378,9 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
280
378
  if (!strongSelf) {
281
379
  return baseMenu;
282
380
  }
381
+ if (strongSelf->_contextMenuHidden) {
382
+ return nil;
383
+ }
283
384
  NSArray<NSMenuItem *> *customItems = ENRMBuildContextMenuItems(
284
385
  strongSelf->_contextMenuItemTexts, strongSelf->_contextMenuItemIcons, textView,
285
386
  ^(NSString *itemText, NSString *selectedText, NSUInteger selectionStart, NSUInteger selectionEnd) {
@@ -451,8 +552,13 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
451
552
  if (forceHeightUpdate || needsHeightUpdate(measured, self.bounds)) {
452
553
  [self requestHeightUpdate];
453
554
  }
555
+
556
+ [self emitLinkLayoutIfNeeded];
454
557
  }
455
558
 
559
+ // New text drops the selection; setting attributedText doesn't call the delegate.
560
+ [_selectionReporter schedule];
561
+
456
562
  if (_textView.hidden) {
457
563
  dispatch_async(dispatch_get_main_queue(), ^{ self->_textView.hidden = NO; });
458
564
  }
@@ -471,6 +577,7 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
471
577
  {
472
578
  [super layoutSubviews];
473
579
  [_spoilerManager updateIfNeeded];
580
+ [self emitLinkLayoutIfNeeded];
474
581
  }
475
582
  #endif
476
583
 
@@ -495,6 +602,11 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
495
602
  _dirtyFlags |= ENRMDirtyRender;
496
603
  }
497
604
 
605
+ if (ENRMImageRequestHeadersChanged(oldViewProps.imageRequestHeaders, newViewProps.imageRequestHeaders)) {
606
+ [_config setImageRequestHeaders:ENRMImageRequestHeadersFromProps(newViewProps.imageRequestHeaders)];
607
+ _dirtyFlags |= ENRMDirtyRender;
608
+ }
609
+
498
610
  NSLayoutManager *layoutManager = _textView.layoutManager;
499
611
  if ([layoutManager isKindOfClass:[TextViewLayoutManager class]]) {
500
612
  StyleConfig *currentConfig = [layoutManager valueForKey:@"config"];
@@ -503,6 +615,14 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
503
615
  }
504
616
  }
505
617
 
618
+ if (newViewProps.emitLinkLayout != _emitLinkLayout) {
619
+ _emitLinkLayout = newViewProps.emitLinkLayout;
620
+ _lastLinkLayout = nil;
621
+ [self emitLinkLayoutIfNeeded];
622
+ }
623
+
624
+ _selectionReporter.enabled = newViewProps.emitSelectionChange;
625
+
506
626
  if (_textView.selectable != newViewProps.selectable) {
507
627
  _textView.selectable = newViewProps.selectable;
508
628
  }
@@ -539,33 +659,21 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
539
659
  _dirtyFlags |= ENRMDirtyRender;
540
660
  }
541
661
 
542
- if (newViewProps.md4cFlags.underline != oldViewProps.md4cFlags.underline) {
543
- _md4cFlags.underline = newViewProps.md4cFlags.underline;
544
- _forceHeightUpdateOnNextRender = YES;
545
- _dirtyFlags |= ENRMDirtyRender;
546
- }
547
- if (newViewProps.md4cFlags.superscript != oldViewProps.md4cFlags.superscript) {
548
- _md4cFlags.superscript = newViewProps.md4cFlags.superscript;
549
- _forceHeightUpdateOnNextRender = YES;
550
- _dirtyFlags |= ENRMDirtyRender;
551
- }
552
- if (newViewProps.md4cFlags.subscript != oldViewProps.md4cFlags.subscript) {
553
- _md4cFlags.subscript = newViewProps.md4cFlags.subscript;
554
- _forceHeightUpdateOnNextRender = YES;
555
- _dirtyFlags |= ENRMDirtyRender;
556
- }
557
- if (newViewProps.md4cFlags.latexMath != oldViewProps.md4cFlags.latexMath) {
558
- _md4cFlags.latexMath = newViewProps.md4cFlags.latexMath;
559
- _forceHeightUpdateOnNextRender = YES;
560
- _dirtyFlags |= ENRMDirtyRender;
561
- }
562
- if (newViewProps.md4cFlags.highlight != oldViewProps.md4cFlags.highlight) {
563
- _md4cFlags.highlight = newViewProps.md4cFlags.highlight;
662
+ if (newViewProps.md4cFlags.underline != oldViewProps.md4cFlags.underline ||
663
+ newViewProps.md4cFlags.superscript != oldViewProps.md4cFlags.superscript ||
664
+ newViewProps.md4cFlags.subscript != oldViewProps.md4cFlags.subscript ||
665
+ newViewProps.md4cFlags.latexMath != oldViewProps.md4cFlags.latexMath ||
666
+ newViewProps.md4cFlags.highlight != oldViewProps.md4cFlags.highlight ||
667
+ newViewProps.md4cFlags.hardSoftBreaks != oldViewProps.md4cFlags.hardSoftBreaks) {
668
+ _md4cFlags = [EnrichedMarkdownText flagsFromProps:newViewProps.md4cFlags];
564
669
  _forceHeightUpdateOnNextRender = YES;
565
670
  _dirtyFlags |= ENRMDirtyRender;
566
671
  }
567
672
 
568
673
  _enableLinkPreview = newViewProps.enableLinkPreview;
674
+ _linkLongPressSelects = newViewProps.linkLongPressSelects;
675
+ _enableTaskListItemToggle = newViewProps.enableTaskListItemToggle;
676
+ _contextMenuHidden = newViewProps.contextMenuHidden;
569
677
 
570
678
  if (ENRMContextMenuItemsChanged(oldViewProps.contextMenuItems, newViewProps.contextMenuItems)) {
571
679
  _contextMenuItemTexts = ENRMContextMenuTextsFromItems(newViewProps.contextMenuItems);
@@ -573,9 +681,7 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
573
681
  }
574
682
 
575
683
  _selectionMenuLabels = ENRMParseSelectionMenuLabels(newViewProps.selectionMenuConfig);
576
- _selectionMenuConfig =
577
- ENRMBuildSelectionMenuConfig(_selectionMenuLabels, newViewProps.selectionMenuConfig.copyAsMarkdown,
578
- newViewProps.selectionMenuConfig.copyImageUrl);
684
+ _selectionMenuConfig = ENRMBuildSelectionMenuConfig(_selectionMenuLabels, newViewProps.selectionMenuConfig);
579
685
 
580
686
  if (ENRMAccessibilityLabelsChanged(oldViewProps.accessibilityLabels, newViewProps.accessibilityLabels)) {
581
687
  _accessibilityLabels = [[ENRMAccessibilityLabels alloc] init];
@@ -665,26 +771,52 @@ typedef NS_OPTIONS(NSUInteger, ENRMDirtyFlags) {
665
771
 
666
772
  - (void)prepareForRecycle
667
773
  {
668
- _props = std::make_shared<const EnrichedMarkdownTextProps>();
774
+ const auto resetProps = std::make_shared<const EnrichedMarkdownTextProps>();
775
+ _props = resetProps;
669
776
  [_renderCoordinator invalidate];
670
777
 
671
778
  [_fadeAnimator cancel];
672
779
  _fadeAnimator = nil;
673
780
  _previousTextLength = 0;
781
+ _streamingAnimation = NO;
782
+ _forceHeightUpdateOnNextRender = NO;
674
783
  _cachedMarkdown = nil;
675
784
  _renderedMarkdown = nil;
785
+ _config = nil;
786
+ _md4cFlags = [EnrichedMarkdownText flagsFromProps:resetProps->md4cFlags];
787
+ _maxFontSizeMultiplier = 0;
788
+ _lastElementMarginBottom = 0;
789
+ _allowTrailingMargin = NO;
790
+ _lineBreakStrategy = NSLineBreakStrategyNone;
791
+ _writingDirectionMode = ENRMWritingDirectionModeFirstStrong;
792
+ _renderedStyleFingerprint = 0;
793
+ _pendingStyleFingerprint = 0;
794
+ _contextMenuItemTexts = nil;
795
+ _contextMenuItemIcons = nil;
796
+ _fontScaleObserver.allowFontScaling = resetProps->allowFontScaling;
797
+ _accessibilityLabels = nil;
676
798
  _accessibilityElements = nil;
677
799
  _accessibilityInfo = nil;
678
800
  _accessibilityNeedsRebuild = NO;
679
801
  [_spoilerManager removeAllOverlays];
680
-
681
- [self resetPropDerivedState];
682
-
802
+ _spoilerManager = nil;
803
+ _emitLinkLayout = NO;
804
+ _lastLinkLayout = nil;
805
+ _selectionReporter.enabled = NO;
806
+ #if !TARGET_OS_OSX
807
+ [_selectionGestures reset];
808
+ #endif
683
809
  if (_textView != nil) {
684
810
  ENRMSetAttributedText(_textView, [[NSAttributedString alloc] initWithString:@""]);
685
811
  _textView.hidden = YES;
686
812
  }
687
813
 
814
+ // Ported from the fork's resetPropDerivedState: upstream's prepareForRecycle covers every
815
+ // other prop-derived ivar but leaves these two, so a recycled view keeps the previous
816
+ // consumer's height-update counter and a dangling shadow-node state handle.
817
+ _heightUpdateCounter = 0;
818
+ _state = nullptr;
819
+
688
820
  [super prepareForRecycle];
689
821
  }
690
822
 
@@ -719,6 +851,25 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
719
851
  emitter->onLinkLongPress({.url = std::string(url.UTF8String)});
720
852
  }
721
853
 
854
+ /// Reports link rects to JS (for `renderLinkDecoration`). Called after every
855
+ /// render and layout change; deduplicated so an unchanged layout — the common
856
+ /// case during streaming — sends nothing.
857
+ - (void)emitLinkLayoutIfNeeded
858
+ {
859
+ if (!_emitLinkLayout || _renderedMarkdown == nil || self.bounds.size.width <= 0)
860
+ return;
861
+
862
+ auto emitter = std::static_pointer_cast<EnrichedMarkdownTextEventEmitter const>(_eventEmitter);
863
+ if (!emitter)
864
+ return;
865
+
866
+ NSArray<NSDictionary *> *fragments = ENRMCollectLinkLayoutFragments(_textView, CGPointZero, 0, NULL);
867
+ if (_lastLinkLayout != nil && [fragments isEqualToArray:_lastLinkLayout])
868
+ return;
869
+ _lastLinkLayout = fragments;
870
+ emitter->onLinkLayout(ENRMLinkLayoutEventFromFragments<EnrichedMarkdownTextEventEmitter::OnLinkLayout>(fragments));
871
+ }
872
+
722
873
  - (void)emitTaskListItemPress:(NSInteger)index checked:(BOOL)checked text:(NSString *)text
723
874
  {
724
875
  auto emitter = std::static_pointer_cast<EnrichedMarkdownTextEventEmitter const>(_eventEmitter);
@@ -726,6 +877,18 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
726
877
  emitter->onTaskListItemPress({.index = (int)index, .checked = checked, .text = std::string(text.UTF8String ?: "")});
727
878
  }
728
879
 
880
+ - (void)emitCopyRequest:(NSString *)source markdown:(NSString *)markdown text:(NSString *)text whole:(BOOL)whole
881
+ {
882
+ auto emitter = std::static_pointer_cast<EnrichedMarkdownTextEventEmitter const>(_eventEmitter);
883
+ if (emitter)
884
+ emitter->onCopyRequest({
885
+ .source = std::string(source.UTF8String),
886
+ .markdown = std::string(markdown.UTF8String ?: ""),
887
+ .text = std::string(text.UTF8String ?: ""),
888
+ .whole = (bool)whole,
889
+ });
890
+ }
891
+
729
892
  - (void)emitContextMenuItemPress:(NSString *)itemText
730
893
  selectedText:(NSString *)selectedText
731
894
  selectionStart:(NSUInteger)selectionStart
@@ -745,7 +908,8 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
745
908
  {
746
909
  ENRMPlatformTextView *textView = (ENRMPlatformTextView *)recognizer.view;
747
910
 
748
- if (handleTaskListTapWithSharedLogic(
911
+ if (_enableTaskListItemToggle &&
912
+ handleTaskListTapWithSharedLogic(
749
913
  textView, recognizer, &self->_cachedMarkdown, self->_config,
750
914
  ^(NSInteger index, BOOL checked, NSString *itemText) {
751
915
  [self emitTaskListItemPress:index checked:checked text:itemText];
@@ -764,6 +928,31 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
764
928
  #pragma mark - UITextViewDelegate (Link Interaction)
765
929
 
766
930
  #if !TARGET_OS_OSX
931
+ // Attachments other than images (inline math) are text, not items: without
932
+ // this a long press on one in an unfocused text view starts UIKit's text item
933
+ // interaction, which presents nothing and leaves the view unable to select.
934
+ - (BOOL)textView:(UITextView *)textView
935
+ shouldInteractWithTextAttachment:(NSTextAttachment *)textAttachment
936
+ inRange:(NSRange)characterRange
937
+ interaction:(UITextItemInteraction)interaction
938
+ {
939
+ if ([textAttachment isKindOfClass:[ENRMImageAttachment class]]) {
940
+ return YES;
941
+ }
942
+ // A long press selects the attachment like a word, as it does once the view is focused.
943
+ if (interaction == UITextItemInteractionPresentActions) {
944
+ __weak UITextView *weakTextView = textView;
945
+ dispatch_async(dispatch_get_main_queue(), ^{
946
+ UITextView *strongTextView = weakTextView;
947
+ if (!strongTextView || NSMaxRange(characterRange) > strongTextView.attributedText.length) {
948
+ return;
949
+ }
950
+ ENRMSelectRangeAndPresentEditMenu(strongTextView, characterRange);
951
+ });
952
+ }
953
+ return NO;
954
+ }
955
+
767
956
  - (BOOL)textView:(ENRMPlatformTextView *)textView
768
957
  shouldInteractWithURL:(NSURL *)URL
769
958
  inRange:(NSRange)characterRange
@@ -775,6 +964,18 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
775
964
 
776
965
  NSString *urlString = linkURLAtRange(textView, characterRange);
777
966
 
967
+ if (urlString && _linkLongPressSelects) {
968
+ __weak UITextView *weakTextView = textView;
969
+ dispatch_async(dispatch_get_main_queue(), ^{
970
+ UITextView *strongTextView = weakTextView;
971
+ if (!strongTextView || NSMaxRange(characterRange) > strongTextView.attributedText.length) {
972
+ return;
973
+ }
974
+ ENRMSelectRangeAndPresentEditMenu(strongTextView, characterRange);
975
+ });
976
+ return NO;
977
+ }
978
+
778
979
  if (!urlString || _enableLinkPreview) {
779
980
  return YES;
780
981
  }
@@ -783,6 +984,15 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
783
984
  return NO;
784
985
  }
785
986
 
987
+ #pragma mark - UITextViewDelegate (Selection)
988
+
989
+ - (void)textViewDidChangeSelection:(UITextView *)textView
990
+ {
991
+ [_selectionGestures trackTextView:textView];
992
+ ENRMDismissSelectionEditMenuIfMoved(textView);
993
+ [_selectionReporter selectionChanged:textView.selectedRange.length > 0];
994
+ }
995
+
786
996
  #pragma mark - UITextViewDelegate (Edit Menu)
787
997
 
788
998
  // TODO: Remove API_AVAILABLE(ios(16.0)) guard when the minimum iOS deployment target in RN is bumped to 16.
@@ -790,6 +1000,12 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
790
1000
  editMenuForTextInRange:(NSRange)range
791
1001
  suggestedActions:(NSArray<UIMenuElement *> *)suggestedActions API_AVAILABLE(ios(16.0))
792
1002
  {
1003
+ // An empty menu presents nothing; nil would make UIKit show its default menu
1004
+ // (the selection and handles stay either way).
1005
+ if (_contextMenuHidden) {
1006
+ return [UIMenu menuWithChildren:@[]];
1007
+ }
1008
+
793
1009
  __weak EnrichedMarkdownText *weakSelf = self;
794
1010
  ENRMContextMenuPressHandler handler =
795
1011
  ^(NSString *itemText, NSString *selectedText, NSUInteger selectionStart, NSUInteger selectionEnd) {
@@ -803,8 +1019,18 @@ Class<RCTComponentViewProtocol> EnrichedMarkdownTextCls(void)
803
1019
  NSMutableArray<UIAction *> *customActions =
804
1020
  ENRMBuildContextMenuActions(_contextMenuItemTexts, _contextMenuItemIcons, textView, range, handler);
805
1021
 
1022
+ // A full selection already carries the cached (original) markdown.
1023
+ ENRMCopyRequestHandler onCopyRequest = ^(NSString *markdown, NSString *text, BOOL fullSelection) {
1024
+ EnrichedMarkdownText *strongSelf = weakSelf;
1025
+ if (strongSelf)
1026
+ [strongSelf emitCopyRequest:@"selection"
1027
+ markdown:markdown
1028
+ text:text
1029
+ whole:fullSelection && strongSelf->_cachedMarkdown.length > 0];
1030
+ };
1031
+
806
1032
  return buildEditMenuForSelection(textView.attributedText, range, _cachedMarkdown, _config, suggestedActions,
807
- customActions, _selectionMenuConfig);
1033
+ customActions, _selectionMenuConfig, onCopyRequest);
808
1034
  }
809
1035
  #endif
810
1036
 
@@ -5,6 +5,15 @@
5
5
 
6
6
  NS_ASSUME_NONNULL_BEGIN
7
7
 
8
+ /**
9
+ * Adopted by component views that host markdown text. Notified when a block
10
+ * image resolves its box height after loading (maxHeight/aspectRatio sizing),
11
+ * so the view can drop stale cached measurements and request a height update.
12
+ */
13
+ @protocol ENRMImageLayoutObserver
14
+ - (void)imageAttachmentDidResolveLayout;
15
+ @end
16
+
8
17
  /**
9
18
  * Custom NSTextAttachment for rendering markdown images.
10
19
  * Images are loaded asynchronously and scaled dynamically based on text container width.