react-native-enriched-markdown-scaffold 0.7.4-scaffold.8 → 1.0.2-scaffold.1

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 +191 -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 +27 -0
  8. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerInterface.java +9 -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 +40 -0
  14. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +839 -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 +175 -11
  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 +62 -4
  26. package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputView.kt +911 -460
  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/BlockSyntaxSentinel.kt +69 -0
  43. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/FormattingStore.kt +80 -87
  44. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputFormatter.kt +109 -1
  45. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputParser.kt +180 -27
  46. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/MarkdownSerializer.kt +167 -38
  47. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/RangeEditAdjustment.kt +149 -0
  48. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputEventEmitter.kt +66 -5
  49. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputMeasurementStore.kt +7 -2
  50. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/BlockRange.kt +27 -0
  51. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/BlockType.kt +48 -0
  52. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/FormattingRange.kt +9 -4
  53. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/InputFormatterStyle.kt +39 -2
  54. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathAtom.kt +20 -0
  55. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathChipStyle.kt +1 -1
  56. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MutableRangeBounds.kt +11 -0
  57. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputBulletSpan.kt +82 -0
  58. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputHeadingSpan.kt +58 -0
  59. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputListItemSpacingSpan.kt +37 -0
  60. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputOrderedListMarkerSpan.kt +63 -0
  61. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/BlockHandler.kt +54 -0
  62. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/HeadingBlockHandler.kt +27 -0
  63. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/OrderedListBlockHandler.kt +38 -0
  64. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/UnorderedListBlockHandler.kt +37 -0
  65. package/android/src/main/java/com/swmansion/enriched/markdown/input/toolbar/InputContextMenu.kt +8 -26
  66. package/android/src/main/java/com/swmansion/enriched/markdown/parser/MarkdownASTNode.kt +1 -0
  67. package/android/src/main/java/com/swmansion/enriched/markdown/parser/Parser.kt +1 -0
  68. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockStyleContext.kt +9 -2
  69. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt +100 -12
  70. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeBlockRenderer.kt +16 -1
  71. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +4 -0
  72. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListContextManager.kt +2 -1
  73. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListItemRenderer.kt +74 -18
  74. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListRenderer.kt +43 -4
  75. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/NodeRenderer.kt +9 -1
  76. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SoftBreakRenderer.kt +16 -0
  77. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +30 -27
  78. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BaseListSpan.kt +24 -0
  79. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt +174 -24
  80. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBackgroundSpan.kt +27 -3
  81. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBlockSpan.kt +13 -16
  82. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeSpan.kt +1 -1
  83. package/android/src/main/java/com/swmansion/enriched/markdown/spans/EmphasisSpan.kt +1 -1
  84. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ImageSpan.kt +182 -46
  85. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ListItemSpacingSpan.kt +33 -0
  86. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ListMarkerAnchorSpan.kt +38 -0
  87. package/android/src/main/java/com/swmansion/enriched/markdown/spans/OrderedListSpan.kt +2 -0
  88. package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrongSpan.kt +1 -1
  89. package/android/src/main/java/com/swmansion/enriched/markdown/spans/TaskListSpan.kt +3 -2
  90. package/android/src/main/java/com/swmansion/enriched/markdown/spans/UnorderedListSpan.kt +3 -2
  91. package/android/src/main/java/com/swmansion/enriched/markdown/styles/BlockquoteStyle.kt +6 -0
  92. package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeBlockStyle.kt +26 -0
  93. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ImageStyle.kt +7 -1
  94. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ListStyle.kt +4 -1
  95. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt +13 -4
  96. package/android/src/main/java/com/swmansion/enriched/markdown/styles/TableStyle.kt +6 -0
  97. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/CodeBlockHighlighter.kt +90 -0
  98. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/CodeBlockNode.kt +57 -0
  99. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/FeatureFlags.kt +1 -0
  100. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownSegment.kt +9 -0
  101. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt +33 -7
  102. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/ReadableMapExtensions.kt +3 -0
  103. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/RenderedSegment.kt +10 -0
  104. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/SegmentSignature.kt +1 -0
  105. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/StreamingMarkdownFilter.kt +83 -5
  106. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/serialization/MarkdownASTSerializer.kt +4 -0
  107. package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/MarkdownStyleParser.kt +74 -44
  108. package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/PasteTextUtils.kt +20 -0
  109. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/ImageCache.kt +26 -3
  110. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/ImageDownloader.kt +22 -9
  111. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/LocalImageLoader.kt +161 -0
  112. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/extensions/TextPaintExtensions.kt +23 -0
  113. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/interaction/CheckboxTouchHelper.kt +7 -0
  114. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/interaction/TaskListTapUtils.kt +41 -21
  115. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/span/BlockSpacing.kt +15 -8
  116. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkLongPressMovementMethod.kt +58 -27
  117. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionActionMode.kt +19 -2
  118. package/android/src/main/java/com/swmansion/enriched/markdown/views/CodeBlockContainerView.kt +388 -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 +32 -5
  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 +2 -0
  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 +231 -8
  152. package/docs/BREAKING_CHANGES.md +129 -0
  153. package/docs/CODE_HIGHLIGHT.md +133 -0
  154. package/docs/COPY_OPTIONS.md +21 -3
  155. package/docs/ELEMENTS_STRUCTURE.md +52 -4
  156. package/docs/IMAGE_CACHING.md +30 -0
  157. package/docs/INPUT.md +146 -5
  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 +262 -67
  169. package/ios/EnrichedMarkdownText.h +7 -0
  170. package/ios/EnrichedMarkdownText.mm +97 -68
  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 +40 -0
  179. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +839 -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/ENRMBlockSyntaxSentinel.h +25 -0
  190. package/ios/input/ENRMBlockSyntaxSentinel.mm +80 -0
  191. package/ios/input/ENRMClipboardCoordinator.h +45 -0
  192. package/ios/input/ENRMClipboardCoordinator.mm +120 -0
  193. package/ios/input/ENRMDetectorPipeline.h +2 -1
  194. package/ios/input/ENRMEditPipeline.h +76 -0
  195. package/ios/input/ENRMEditPipeline.mm +228 -0
  196. package/ios/input/ENRMEditSession.h +36 -0
  197. package/ios/input/ENRMEditSession.mm +63 -0
  198. package/ios/input/ENRMFormattingStore.h +17 -0
  199. package/ios/input/ENRMFormattingStore.mm +95 -105
  200. package/ios/input/ENRMInputBlockType.h +91 -0
  201. package/ios/input/ENRMInputBlockType.mm +5 -0
  202. package/ios/input/ENRMInputDecorationDrawer.h +18 -0
  203. package/ios/input/ENRMInputEventEmitter.h +56 -0
  204. package/ios/input/ENRMInputEventEmitter.mm +308 -0
  205. package/ios/input/ENRMInputFormatter.h +29 -69
  206. package/ios/input/ENRMInputFormatter.mm +216 -124
  207. package/ios/input/ENRMInputFormatterStyle.h +99 -0
  208. package/ios/input/ENRMInputFormatterStyle.mm +188 -0
  209. package/ios/input/ENRMInputLayoutManager.h +9 -0
  210. package/ios/input/ENRMInputLayoutManager.mm +30 -0
  211. package/ios/input/ENRMInputListMarkerDrawer.h +32 -0
  212. package/ios/input/ENRMInputListMarkerDrawer.mm +426 -0
  213. package/ios/input/ENRMInputParser.h +10 -6
  214. package/ios/input/ENRMInputParser.mm +527 -171
  215. package/ios/input/ENRMInputRemend.mm +2 -2
  216. package/ios/input/ENRMInputStyleStateBuilder.h +40 -0
  217. package/ios/input/ENRMInputStyleStateBuilder.mm +60 -0
  218. package/ios/input/ENRMInputTextView.mm +103 -8
  219. package/ios/input/ENRMInputTypingAttributesController.h +42 -0
  220. package/ios/input/ENRMInputTypingAttributesController.mm +203 -0
  221. package/ios/input/ENRMLinkCoordinator.h +41 -0
  222. package/ios/input/ENRMLinkCoordinator.mm +89 -0
  223. package/ios/input/ENRMMarkdownSerializer.h +29 -5
  224. package/ios/input/ENRMMarkdownSerializer.mm +170 -48
  225. package/ios/input/ENRMMathAtom.h +26 -0
  226. package/ios/input/ENRMMathAtom.mm +12 -0
  227. package/ios/input/ENRMMentionCoordinator.h +45 -0
  228. package/ios/input/ENRMMentionCoordinator.mm +167 -0
  229. package/ios/input/ENRMRangeEditAdjustment.h +38 -0
  230. package/ios/input/ENRMRangeEditAdjustment.mm +91 -0
  231. package/ios/input/ENRMRangeStoreUtils.h +39 -0
  232. package/ios/input/EnrichedMarkdownTextInput+ContextMenu.mm +6 -6
  233. package/ios/input/EnrichedMarkdownTextInput+Internal.h +11 -3
  234. package/ios/input/EnrichedMarkdownTextInput.h +7 -1
  235. package/ios/input/EnrichedMarkdownTextInput.mm +1104 -1024
  236. package/ios/input/InputStylePropsUtils.h +109 -68
  237. package/ios/input/internals/EnrichedMarkdownTextInputShadowNode.mm +2 -1
  238. package/ios/input/styles/ENRMBlockHandler.h +46 -0
  239. package/ios/input/styles/ENRMHeadingBlockHandler.h +15 -0
  240. package/ios/input/styles/ENRMHeadingBlockHandler.mm +38 -0
  241. package/ios/input/styles/ENRMOrderedListBlockHandler.h +14 -0
  242. package/ios/input/styles/ENRMOrderedListBlockHandler.mm +48 -0
  243. package/ios/input/styles/ENRMUnorderedListBlockHandler.h +15 -0
  244. package/ios/input/styles/ENRMUnorderedListBlockHandler.mm +51 -0
  245. package/ios/internals/ENRMViewFreeMeasurement.h +331 -0
  246. package/ios/internals/EnrichedMarkdownShadowNode.h +1 -3
  247. package/ios/internals/EnrichedMarkdownShadowNode.mm +16 -20
  248. package/ios/internals/EnrichedMarkdownTextShadowNode.h +1 -3
  249. package/ios/internals/EnrichedMarkdownTextShadowNode.mm +15 -20
  250. package/ios/internals/MeasurementCache.h +33 -7
  251. package/ios/internals/ShadowMeasurementUtils.h +63 -58
  252. package/ios/math/ENRMMathChipController.h +74 -0
  253. package/ios/math/ENRMMathChipController.mm +476 -0
  254. package/ios/math/ENRMRaTeXBridge.swift +4 -1
  255. package/ios/parser/ENRMMarkdownParser.h +1 -8
  256. package/ios/parser/ENRMMarkdownParser.mm +2 -11
  257. package/ios/parser/MarkdownASTNode.h +2 -1
  258. package/ios/parser/MarkdownParserBridge.mm +4 -0
  259. package/ios/renderer/AttributedRenderer.m +20 -2
  260. package/ios/renderer/BaseRenderer.h +17 -2
  261. package/ios/renderer/BaseRenderer.m +30 -0
  262. package/ios/renderer/BlockquoteRenderer.h +1 -1
  263. package/ios/renderer/BlockquoteRenderer.m +144 -35
  264. package/ios/renderer/CodeBlockRenderer.h +1 -1
  265. package/ios/renderer/CodeBlockRenderer.m +27 -23
  266. package/ios/renderer/CodeRenderer.h +1 -1
  267. package/ios/renderer/CodeRenderer.m +3 -1
  268. package/ios/renderer/ENRMImageRenderer.h +1 -1
  269. package/ios/renderer/ENRMImageRenderer.m +5 -1
  270. package/ios/renderer/ENRMMathInlineRenderer.h +1 -1
  271. package/ios/renderer/ENRMMathInlineRenderer.m +5 -1
  272. package/ios/renderer/ENRMSpoilerRenderer.h +1 -1
  273. package/ios/renderer/ENRMSpoilerRenderer.m +3 -1
  274. package/ios/renderer/EmphasisRenderer.h +1 -1
  275. package/ios/renderer/EmphasisRenderer.m +3 -1
  276. package/ios/renderer/HeadingRenderer.h +1 -1
  277. package/ios/renderer/HeadingRenderer.m +13 -6
  278. package/ios/renderer/HighlightRenderer.h +1 -1
  279. package/ios/renderer/HighlightRenderer.m +3 -1
  280. package/ios/renderer/LinkRenderer.h +1 -1
  281. package/ios/renderer/LinkRenderer.m +3 -1
  282. package/ios/renderer/ListItemRenderer.h +13 -1
  283. package/ios/renderer/ListItemRenderer.m +102 -44
  284. package/ios/renderer/ListRenderer.h +2 -2
  285. package/ios/renderer/ListRenderer.m +63 -25
  286. package/ios/renderer/ParagraphRenderer.h +1 -1
  287. package/ios/renderer/ParagraphRenderer.m +16 -8
  288. package/ios/renderer/RenderContext.h +10 -0
  289. package/ios/renderer/RenderContext.m +44 -0
  290. package/ios/renderer/RendererFactory.m +14 -0
  291. package/ios/renderer/StrikethroughRenderer.h +1 -1
  292. package/ios/renderer/StrikethroughRenderer.m +3 -1
  293. package/ios/renderer/StrongRenderer.h +1 -1
  294. package/ios/renderer/StrongRenderer.m +3 -1
  295. package/ios/renderer/SubscriptRenderer.h +1 -1
  296. package/ios/renderer/SubscriptRenderer.m +3 -1
  297. package/ios/renderer/SuperscriptRenderer.h +1 -1
  298. package/ios/renderer/SuperscriptRenderer.m +3 -1
  299. package/ios/renderer/TextRenderer.h +2 -2
  300. package/ios/renderer/TextRenderer.m +3 -1
  301. package/ios/renderer/ThematicBreakRenderer.h +1 -1
  302. package/ios/renderer/ThematicBreakRenderer.m +3 -1
  303. package/ios/renderer/UnderlineRenderer.h +1 -1
  304. package/ios/renderer/UnderlineRenderer.m +3 -1
  305. package/ios/styles/StyleConfig.h +22 -0
  306. package/ios/styles/StyleConfig.mm +132 -0
  307. package/ios/utils/BlockquoteBorder.h +6 -0
  308. package/ios/utils/BlockquoteBorder.m +249 -52
  309. package/ios/utils/CodeBlockBackground.m +16 -2
  310. package/ios/utils/ENRMAtomicSize.h +65 -0
  311. package/ios/utils/ENRMCodeBlockContent.h +37 -0
  312. package/ios/utils/ENRMCodeBlockContent.mm +79 -0
  313. package/ios/utils/ENRMCodeBlockHighlighter.h +37 -0
  314. package/ios/utils/ENRMCodeBlockHighlighter.mm +51 -0
  315. package/ios/utils/ENRMFeatureFlags.h +7 -0
  316. package/ios/utils/ENRMImageDownloader.h +11 -1
  317. package/ios/utils/ENRMImageDownloader.m +60 -16
  318. package/ios/utils/ENRMLocalImageLoader.h +31 -0
  319. package/ios/utils/ENRMLocalImageLoader.m +68 -0
  320. package/ios/utils/ENRMMathFallback.h +26 -0
  321. package/ios/utils/ENRMMathFallback.m +18 -0
  322. package/ios/utils/ENRMTextViewSetup.h +35 -17
  323. package/ios/utils/EditMenuUtils.m +22 -1
  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 +46 -0
  338. package/ios/views/ENRMCodeBlockContainerView.m +566 -0
  339. package/ios/views/ENRMMathContainerView.h +12 -0
  340. package/ios/views/ENRMMathContainerView.m +71 -1
  341. package/ios/views/TableContainerView.h +18 -0
  342. package/ios/views/TableContainerView.m +259 -159
  343. package/jest.d.ts +1 -0
  344. package/jest.js +5 -0
  345. package/lib/module/EnrichedMarkdownNativeComponent.ts +65 -0
  346. package/lib/module/EnrichedMarkdownTextInput.js +86 -5
  347. package/lib/module/EnrichedMarkdownTextInput.js.map +1 -1
  348. package/lib/module/EnrichedMarkdownTextInputNativeComponent.ts +89 -5
  349. package/lib/module/EnrichedMarkdownTextNativeComponent.ts +66 -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 +30 -4
  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 +62 -0
  383. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -1
  384. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts +95 -9
  385. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts.map +1 -1
  386. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts +80 -5
  387. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts.map +1 -1
  388. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +62 -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 +65 -1
  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 +65 -0
  433. package/src/EnrichedMarkdownTextInput.tsx +162 -8
  434. package/src/EnrichedMarkdownTextInputNativeComponent.ts +89 -5
  435. package/src/EnrichedMarkdownTextNativeComponent.ts +66 -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 +40 -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 +65 -0
  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
@@ -27,8 +27,14 @@ NS_ASSUME_NONNULL_BEGIN
27
27
  - (void)toggleUnderline;
28
28
  - (void)toggleStrikethrough;
29
29
  - (void)toggleSpoiler;
30
+ - (void)toggleHeading:(NSInteger)level;
31
+ - (void)toggleUnorderedList;
32
+ - (void)toggleOrderedList;
33
+ - (void)indentList;
34
+ - (void)outdentList;
30
35
  - (void)setLink:(NSString *)url;
31
36
  - (void)insertLink:(NSString *)text url:(NSString *)url;
37
+ - (void)insertText:(NSString *)text;
32
38
  - (void)insertMention:(NSString *)displayText url:(NSString *)url;
33
39
  - (void)startMention:(NSString *)indicator;
34
40
  - (void)removeLink;
@@ -36,6 +42,7 @@ NS_ASSUME_NONNULL_BEGIN
36
42
  - (void)updateMath:(NSInteger)start latex:(NSString *)latex displayMode:(BOOL)displayMode;
37
43
  - (void)removeMath:(NSInteger)start;
38
44
  - (void)copyToClipboard;
45
+ - (void)resolvePaste:(NSString *)text markdown:(NSString *)markdown;
39
46
  - (void)requestMarkdown:(NSInteger)requestId;
40
47
  - (void)requestCaretRect:(NSInteger)requestId;
41
48
  @end
@@ -191,6 +198,82 @@ if ([commandName isEqualToString:@"toggleSpoiler"]) {
191
198
  return;
192
199
  }
193
200
 
201
+ if ([commandName isEqualToString:@"toggleHeading"]) {
202
+ #if RCT_DEBUG
203
+ if ([args count] != 1) {
204
+ RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 1);
205
+ return;
206
+ }
207
+ #endif
208
+
209
+ NSObject *arg0 = args[0];
210
+ #if RCT_DEBUG
211
+ if (!RCTValidateTypeOfViewCommandArgument(arg0, [NSNumber class], @"number", @"EnrichedMarkdownTextInput", commandName, @"1st")) {
212
+ return;
213
+ }
214
+ #endif
215
+ NSInteger level = [(NSNumber *)arg0 intValue];
216
+
217
+ [componentView toggleHeading:level];
218
+ return;
219
+ }
220
+
221
+ if ([commandName isEqualToString:@"toggleUnorderedList"]) {
222
+ #if RCT_DEBUG
223
+ if ([args count] != 0) {
224
+ RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 0);
225
+ return;
226
+ }
227
+ #endif
228
+
229
+
230
+
231
+ [componentView toggleUnorderedList];
232
+ return;
233
+ }
234
+
235
+ if ([commandName isEqualToString:@"toggleOrderedList"]) {
236
+ #if RCT_DEBUG
237
+ if ([args count] != 0) {
238
+ RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 0);
239
+ return;
240
+ }
241
+ #endif
242
+
243
+
244
+
245
+ [componentView toggleOrderedList];
246
+ return;
247
+ }
248
+
249
+ if ([commandName isEqualToString:@"indentList"]) {
250
+ #if RCT_DEBUG
251
+ if ([args count] != 0) {
252
+ RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 0);
253
+ return;
254
+ }
255
+ #endif
256
+
257
+
258
+
259
+ [componentView indentList];
260
+ return;
261
+ }
262
+
263
+ if ([commandName isEqualToString:@"outdentList"]) {
264
+ #if RCT_DEBUG
265
+ if ([args count] != 0) {
266
+ RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 0);
267
+ return;
268
+ }
269
+ #endif
270
+
271
+
272
+
273
+ [componentView outdentList];
274
+ return;
275
+ }
276
+
194
277
  if ([commandName isEqualToString:@"setLink"]) {
195
278
  #if RCT_DEBUG
196
279
  if ([args count] != 1) {
@@ -239,6 +322,26 @@ NSObject *arg1 = args[1];
239
322
  return;
240
323
  }
241
324
 
325
+ if ([commandName isEqualToString:@"insertText"]) {
326
+ #if RCT_DEBUG
327
+ if ([args count] != 1) {
328
+ RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 1);
329
+ return;
330
+ }
331
+ #endif
332
+
333
+ NSObject *arg0 = args[0];
334
+ #if RCT_DEBUG
335
+ if (!RCTValidateTypeOfViewCommandArgument(arg0, [NSString class], @"string", @"EnrichedMarkdownTextInput", commandName, @"1st")) {
336
+ return;
337
+ }
338
+ #endif
339
+ NSString * text = (NSString *)arg0;
340
+
341
+ [componentView insertText:text];
342
+ return;
343
+ }
344
+
242
345
  if ([commandName isEqualToString:@"insertMention"]) {
243
346
  #if RCT_DEBUG
244
347
  if ([args count] != 2) {
@@ -399,6 +502,34 @@ if ([commandName isEqualToString:@"copyToClipboard"]) {
399
502
  return;
400
503
  }
401
504
 
505
+ if ([commandName isEqualToString:@"resolvePaste"]) {
506
+ #if RCT_DEBUG
507
+ if ([args count] != 2) {
508
+ RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedMarkdownTextInput", commandName, (int)[args count], 2);
509
+ return;
510
+ }
511
+ #endif
512
+
513
+ NSObject *arg0 = args[0];
514
+ #if RCT_DEBUG
515
+ if (!RCTValidateTypeOfViewCommandArgument(arg0, [NSString class], @"string", @"EnrichedMarkdownTextInput", commandName, @"1st")) {
516
+ return;
517
+ }
518
+ #endif
519
+ NSString * text = (NSString *)arg0;
520
+
521
+ NSObject *arg1 = args[1];
522
+ #if RCT_DEBUG
523
+ if (!RCTValidateTypeOfViewCommandArgument(arg1, [NSString class], @"string", @"EnrichedMarkdownTextInput", commandName, @"2nd")) {
524
+ return;
525
+ }
526
+ #endif
527
+ NSString * markdown = (NSString *)arg1;
528
+
529
+ [componentView resolvePaste:text markdown:markdown];
530
+ return;
531
+ }
532
+
402
533
  if ([commandName isEqualToString:@"requestMarkdown"]) {
403
534
  #if RCT_DEBUG
404
535
  if ([args count] != 1) {
@@ -1,6 +1,7 @@
1
1
  #pragma once
2
2
 
3
3
  #import "ENRMFormattingStore.h"
4
+ #import "ENRMLinkCoordinator.h"
4
5
  #import "ENRMLinkRegexConfig.h"
5
6
  #import "ENRMTextDetector.h"
6
7
  #import <Foundation/Foundation.h>
@@ -11,7 +12,7 @@ NS_ASSUME_NONNULL_BEGIN
11
12
 
12
13
  typedef void (^ENRMAutoLinkCallback)(NSString *text, NSString *url, NSRange range);
13
14
 
14
- @interface ENRMAutoLinkDetector : NSObject <ENRMTextDetector>
15
+ @interface ENRMAutoLinkDetector : NSObject <ENRMTextDetector, ENRMAutoLinkDetecting>
15
16
 
16
17
  - (instancetype)initWithTextStorage:(NSTextStorage *)textStorage
17
18
  formattingStore:(ENRMFormattingStore *)store
@@ -34,9 +34,19 @@ static NSAttributedStringKey const ENRMAutomaticLinkAttributeName = @"ENRMAutoma
34
34
 
35
35
  - (void)processWord:(ENRMWordResult *)wordResult
36
36
  {
37
- NSString *detectedUrl = [self detectNewLinkAtRange:wordResult.range inText:wordResult.word];
37
+ NSRange matchedRange = NSMakeRange(NSNotFound, 0);
38
+ NSString *detectedUrl = [self detectNewLinkAtRange:wordResult.range
39
+ inText:wordResult.word
40
+ matchedRange:&matchedRange];
38
41
  if (detectedUrl != nil && _onLinkDetected != nil) {
39
- _onLinkDetected(wordResult.word, detectedUrl, wordResult.range);
42
+ // Emit the actual linked slice, not the whole whitespace token — surrounding
43
+ // punctuation is not part of the link.
44
+ BOOL hasSlice = matchedRange.location != NSNotFound;
45
+ NSString *matchedText = hasSlice ? [wordResult.word substringWithRange:matchedRange] : wordResult.word;
46
+ NSRange absoluteRange = hasSlice
47
+ ? NSMakeRange(wordResult.range.location + matchedRange.location, matchedRange.length)
48
+ : wordResult.range;
49
+ _onLinkDetected(matchedText, detectedUrl, absoluteRange);
40
50
  }
41
51
  }
42
52
 
@@ -92,8 +102,14 @@ static NSAttributedStringKey const ENRMAutomaticLinkAttributeName = @"ENRMAutoma
92
102
 
93
103
  #pragma mark - Link matching
94
104
 
95
- - (nullable NSString *)detectNewLinkAtRange:(NSRange)wordRange inText:(NSString *)word
105
+ - (nullable NSString *)detectNewLinkAtRange:(NSRange)wordRange
106
+ inText:(NSString *)word
107
+ matchedRange:(NSRange *)outMatchedRange
96
108
  {
109
+ if (outMatchedRange != NULL) {
110
+ *outMatchedRange = NSMakeRange(NSNotFound, 0);
111
+ }
112
+
97
113
  if (_regexConfig != nil && _regexConfig.isDisabled) {
98
114
  return nil;
99
115
  }
@@ -107,61 +123,83 @@ static NSAttributedStringKey const ENRMAutomaticLinkAttributeName = @"ENRMAutoma
107
123
  return nil;
108
124
  }
109
125
 
126
+ // Tokens carrying markdown link syntax (e.g. "[label](url)") belong to the
127
+ // parser, not the auto-linker. Auto-linking them re-wraps the destination and
128
+ // yields a corrupted URL like "https://[label](url)" on serialize.
129
+ if ([word hasPrefix:@"["] || [word rangeOfString:@"]("].location != NSNotFound) {
130
+ [self clearAutoLinkInRange:wordRange];
131
+ return nil;
132
+ }
133
+
134
+ NSRange localMatch = NSMakeRange(NSNotFound, 0);
135
+ NSString *matchedUrl = [self tryMatchWord:word matchedRange:&localMatch];
136
+
137
+ if (matchedUrl == nil || localMatch.location == NSNotFound) {
138
+ [self clearAutoLinkInRange:wordRange];
139
+ return nil;
140
+ }
141
+
142
+ NSRange matchRange = NSMakeRange(wordRange.location + localMatch.location, localMatch.length);
143
+
144
+ // A manual link overlapping the matched slice takes precedence — test the
145
+ // whole slice, not just its first character.
110
146
  ENRMFormattingStore *store = _formattingStore;
111
- if (store != nil) {
112
- ENRMFormattingRange *manualLink = [store rangeOfType:ENRMInputStyleTypeLink containingPosition:wordRange.location];
113
- if (manualLink != nil) {
114
- return nil;
115
- }
116
- }
117
-
118
- NSString *matchedUrl = [self tryMatchWord:word];
119
-
120
- if (matchedUrl != nil) {
121
- NSRange effectiveRange;
122
- id existing = [textStorage attribute:ENRMAutomaticLinkAttributeName
123
- atIndex:wordRange.location
124
- effectiveRange:&effectiveRange];
125
- BOOL alreadyApplied = [matchedUrl isEqual:existing] && NSEqualRanges(effectiveRange, wordRange);
126
-
127
- if (!alreadyApplied) {
128
- [textStorage beginEditing];
129
- [textStorage addAttribute:ENRMAutomaticLinkAttributeName value:matchedUrl range:wordRange];
130
- [self applyVisualStylingToRange:wordRange];
131
- [textStorage endEditing];
132
- }
133
- } else {
134
- id existing = [textStorage attribute:ENRMAutomaticLinkAttributeName atIndex:wordRange.location effectiveRange:nil];
135
- if (existing != nil) {
136
- [textStorage beginEditing];
137
- [textStorage removeAttribute:ENRMAutomaticLinkAttributeName range:wordRange];
138
- [textStorage endEditing];
139
- }
147
+ if (store != nil && [store isStyleActive:ENRMInputStyleTypeLink inRange:matchRange]) {
148
+ [self clearAutoLinkInRange:wordRange];
149
+ return nil;
140
150
  }
141
151
 
152
+ NSRange effectiveRange;
153
+ id existing = [textStorage attribute:ENRMAutomaticLinkAttributeName
154
+ atIndex:matchRange.location
155
+ effectiveRange:&effectiveRange];
156
+ BOOL alreadyApplied = [matchedUrl isEqual:existing] && NSEqualRanges(effectiveRange, matchRange);
157
+
158
+ if (!alreadyApplied) {
159
+ [textStorage beginEditing];
160
+ [textStorage removeAttribute:ENRMAutomaticLinkAttributeName range:wordRange];
161
+ [textStorage addAttribute:ENRMAutomaticLinkAttributeName value:matchedUrl range:matchRange];
162
+ [self applyVisualStylingToRange:matchRange];
163
+ [textStorage endEditing];
164
+ }
165
+
166
+ if (outMatchedRange != NULL) {
167
+ *outMatchedRange = localMatch;
168
+ }
142
169
  return matchedUrl;
143
170
  }
144
171
 
145
- - (nullable NSString *)tryMatchWord:(NSString *)word
172
+ - (nullable NSString *)tryMatchWord:(NSString *)word matchedRange:(NSRange *)outRange
146
173
  {
174
+ if (outRange != NULL) {
175
+ *outRange = NSMakeRange(NSNotFound, 0);
176
+ }
177
+
147
178
  if (word.length == 0) {
148
179
  return nil;
149
180
  }
150
181
 
151
- NSRange matchRange = NSMakeRange(0, word.length);
182
+ NSRange fullRange = NSMakeRange(0, word.length);
152
183
 
153
- if (_regexConfig != nil && !_regexConfig.isDefault && _regexConfig.parsedRegex != nil) {
154
- if ([_regexConfig.parsedRegex numberOfMatchesInString:word options:0 range:matchRange]) {
155
- return [ENRMAutoLinkDetector normalizeUrl:word];
156
- }
184
+ // A custom regex describes the whole-token contract, so keep whole-word
185
+ // semantics for it. The default detector extracts just the matched URL slice
186
+ // so surrounding punctuation isn't swallowed into the link.
187
+ BOOL customExact = _regexConfig != nil && !_regexConfig.isDefault && _regexConfig.parsedRegex != nil;
188
+ NSRegularExpression *regex = customExact ? _regexConfig.parsedRegex : [ENRMAutoLinkDetector defaultRegex];
189
+ if (regex == nil) {
157
190
  return nil;
158
191
  }
159
192
 
160
- if ([[ENRMAutoLinkDetector defaultRegex] numberOfMatchesInString:word options:0 range:matchRange]) {
161
- return [ENRMAutoLinkDetector normalizeUrl:word];
193
+ NSTextCheckingResult *match = [regex firstMatchInString:word options:0 range:fullRange];
194
+ if (match == nil || match.range.location == NSNotFound) {
195
+ return nil;
162
196
  }
163
197
 
164
- return nil;
198
+ NSRange matchRange = customExact ? fullRange : match.range;
199
+ if (outRange != NULL) {
200
+ *outRange = matchRange;
201
+ }
202
+ return [ENRMAutoLinkDetector normalizeUrl:[word substringWithRange:matchRange]];
165
203
  }
166
204
 
167
205
  + (NSString *)normalizeUrl:(NSString *)url
@@ -0,0 +1,71 @@
1
+ #pragma once
2
+
3
+ #import "ENRMInputBlockType.h"
4
+ #import <Foundation/Foundation.h>
5
+
6
+ @class ENRMBlockStore;
7
+ @class ENRMBlockRange;
8
+
9
+ NS_ASSUME_NONNULL_BEGIN
10
+
11
+ /// Result of a depth-change operation.
12
+ typedef NS_ENUM(NSInteger, ENRMDepthChangeResult) {
13
+ ENRMDepthChangeResultChanged,
14
+ ENRMDepthChangeResultStartedList,
15
+ ENRMDepthChangeResultExitedList,
16
+ ENRMDepthChangeResultNoOp,
17
+ };
18
+
19
+ /// Encapsulates block-editing operations: toggling block types, adjusting list
20
+ /// depth, and querying the block at a given position. The view delegates here
21
+ /// and applies UI-level consequences (formatting, anchor sync, typing
22
+ /// attributes) based on the returned result.
23
+ ///
24
+ /// All mutating methods normalize stores to line bounds before returning, so the
25
+ /// caller can re-stamp block spans immediately.
26
+ @interface ENRMBlockEditCoordinator : NSObject
27
+
28
+ - (instancetype)initWithBlockStore:(ENRMBlockStore *)blockStore;
29
+
30
+ // ── Queries ──────────────────────────────────────────────────────────
31
+
32
+ /// The block owning the paragraph at `position`, or nil.
33
+ - (nullable ENRMBlockRange *)blockAtPosition:(NSUInteger)position inText:(NSString *)text;
34
+
35
+ /// The list-item block at `position`, or nil if the paragraph is not a list item.
36
+ - (nullable ENRMBlockRange *)listBlockAtPosition:(NSUInteger)position inText:(NSString *)text;
37
+
38
+ /// Heading level (1-6) at `position`, or 0 for non-heading paragraphs.
39
+ - (NSInteger)headingLevelAtPosition:(NSUInteger)position inText:(NSString *)text;
40
+
41
+ /// Whether the paragraph at `position` is a list item of `type`, and its depth.
42
+ - (BOOL)listStateOfType:(ENRMInputBlockType)type
43
+ atPosition:(NSUInteger)position
44
+ inText:(NSString *)text
45
+ depth:(nullable NSInteger *)outDepth;
46
+
47
+ // ── Mutations ────────────────────────────────────────────────────────
48
+
49
+ /// Toggles `type` at `level` on the paragraphs the selection touches.
50
+ /// Returns YES when the block was already active (i.e. it was turned off).
51
+ - (BOOL)toggleBlockType:(ENRMInputBlockType)type
52
+ level:(NSInteger)level
53
+ selectionRange:(NSRange)selection
54
+ inText:(NSString *)text;
55
+
56
+ /// Toggles a list of `type` on the selection.
57
+ /// Returns YES when the list was turned off.
58
+ - (BOOL)toggleListType:(ENRMInputBlockType)type
59
+ cursorPosition:(NSUInteger)cursorPos
60
+ selectionRange:(NSRange)selection
61
+ inText:(NSString *)text;
62
+
63
+ /// Adjusts list depth by `delta` on the selected lines.
64
+ - (ENRMDepthChangeResult)changeDepthBy:(NSInteger)delta
65
+ cursorPosition:(NSUInteger)cursorPos
66
+ selectionRange:(NSRange)selection
67
+ inText:(NSString *)text;
68
+
69
+ @end
70
+
71
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,195 @@
1
+ #import "ENRMBlockEditCoordinator.h"
2
+ #import "ENRMBlockRange.h"
3
+ #import "ENRMBlockStore.h"
4
+
5
+ @implementation ENRMBlockEditCoordinator {
6
+ ENRMBlockStore *_blockStore;
7
+ }
8
+
9
+ - (instancetype)initWithBlockStore:(ENRMBlockStore *)blockStore
10
+ {
11
+ self = [super init];
12
+ if (self) {
13
+ _blockStore = blockStore;
14
+ }
15
+ return self;
16
+ }
17
+
18
+ // ── Queries ──────────────────────────────────────────────────────────
19
+
20
+ - (nullable ENRMBlockRange *)blockAtPosition:(NSUInteger)position inText:(NSString *)text
21
+ {
22
+ if (position > text.length) {
23
+ return nil;
24
+ }
25
+ NSRange paragraph = [text paragraphRangeForRange:NSMakeRange(position, 0)];
26
+ return [_blockStore blockStartingAtLocation:paragraph.location];
27
+ }
28
+
29
+ - (nullable ENRMBlockRange *)listBlockAtPosition:(NSUInteger)position inText:(NSString *)text
30
+ {
31
+ ENRMBlockRange *block = [self blockAtPosition:position inText:text];
32
+ return (block != nil && ENRMBlockTypeIsListItem(block.type)) ? block : nil;
33
+ }
34
+
35
+ - (NSInteger)headingLevelAtPosition:(NSUInteger)position inText:(NSString *)text
36
+ {
37
+ ENRMBlockRange *block = [self blockAtPosition:position inText:text];
38
+ return block != nil ? ENRMHeadingLevelForBlockType(block.type) : 0;
39
+ }
40
+
41
+ - (BOOL)listStateOfType:(ENRMInputBlockType)type
42
+ atPosition:(NSUInteger)position
43
+ inText:(NSString *)text
44
+ depth:(nullable NSInteger *)outDepth
45
+ {
46
+ ENRMBlockRange *block = [self listBlockAtPosition:position inText:text];
47
+ BOOL match = block != nil && block.type == type;
48
+ if (outDepth) {
49
+ *outDepth = match ? block.level : 0;
50
+ }
51
+ return match;
52
+ }
53
+
54
+ // ── Mutations ────────────────────────────────────────────────────────
55
+
56
+ - (BOOL)toggleBlockType:(ENRMInputBlockType)type
57
+ level:(NSInteger)level
58
+ selectionRange:(NSRange)selection
59
+ inText:(NSString *)text
60
+ {
61
+ NSRange paragraphRange = [text paragraphRangeForRange:selection];
62
+
63
+ ENRMBlockRange *current = [_blockStore blockStartingAtLocation:paragraphRange.location];
64
+ BOOL alreadyActive = current != nil && current.type == type;
65
+
66
+ if (alreadyActive) {
67
+ [_blockStore removeBlockInParagraphRange:paragraphRange inText:text];
68
+ } else if (paragraphRange.length == 0) {
69
+ NSInteger resolvedLevel = level;
70
+ if (ENRMBlockTypeIsListItem(type) && current != nil && ENRMBlockTypeIsListItem(current.type)) {
71
+ resolvedLevel = current.level;
72
+ }
73
+ [_blockStore setBlockType:type level:resolvedLevel forParagraphRange:paragraphRange inText:text];
74
+ } else {
75
+ [text
76
+ enumerateSubstringsInRange:paragraphRange
77
+ options:NSStringEnumerationByParagraphs | NSStringEnumerationSubstringNotRequired
78
+ usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
79
+ NSInteger paragraphLevel = level;
80
+ if (ENRMBlockTypeIsListItem(type)) {
81
+ ENRMBlockRange *existing = [self listBlockAtPosition:substringRange.location inText:text];
82
+ if (existing != nil) {
83
+ paragraphLevel = existing.level;
84
+ }
85
+ }
86
+ [self->_blockStore setBlockType:type
87
+ level:paragraphLevel
88
+ forParagraphRange:substringRange
89
+ inText:text];
90
+ }];
91
+ }
92
+
93
+ [_blockStore normalizeToLineBoundsInText:text];
94
+ return alreadyActive;
95
+ }
96
+
97
+ - (BOOL)toggleListType:(ENRMInputBlockType)type
98
+ cursorPosition:(NSUInteger)cursorPos
99
+ selectionRange:(NSRange)selection
100
+ inText:(NSString *)text
101
+ {
102
+ ENRMBlockRange *cursorBlock = [self listBlockAtPosition:cursorPos inText:text];
103
+ BOOL turningOff = cursorBlock != nil && cursorBlock.type == type;
104
+ NSRange paragraphRange = [text paragraphRangeForRange:selection];
105
+
106
+ if (turningOff) {
107
+ if (paragraphRange.length == 0) {
108
+ [_blockStore removeBlockInParagraphRange:paragraphRange inText:text];
109
+ } else {
110
+ [text enumerateSubstringsInRange:paragraphRange
111
+ options:NSStringEnumerationByParagraphs | NSStringEnumerationSubstringNotRequired
112
+ usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange,
113
+ BOOL *stop) {
114
+ [self->_blockStore removeBlockInParagraphRange:substringRange inText:text];
115
+ }];
116
+ }
117
+ } else {
118
+ if (paragraphRange.length == 0) {
119
+ NSInteger existingLevel = 0;
120
+ ENRMBlockRange *existing = [self listBlockAtPosition:paragraphRange.location inText:text];
121
+ if (existing != nil) {
122
+ existingLevel = existing.level;
123
+ }
124
+ [_blockStore setBlockType:type level:existingLevel forParagraphRange:paragraphRange inText:text];
125
+ } else {
126
+ [text enumerateSubstringsInRange:paragraphRange
127
+ options:NSStringEnumerationByParagraphs | NSStringEnumerationSubstringNotRequired
128
+ usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange,
129
+ BOOL *stop) {
130
+ NSInteger existingLevel = 0;
131
+ ENRMBlockRange *existing = [self listBlockAtPosition:substringRange.location inText:text];
132
+ if (existing != nil) {
133
+ existingLevel = existing.level;
134
+ }
135
+ [self->_blockStore setBlockType:type
136
+ level:existingLevel
137
+ forParagraphRange:substringRange
138
+ inText:text];
139
+ }];
140
+ }
141
+ }
142
+
143
+ [_blockStore normalizeToLineBoundsInText:text];
144
+ return turningOff;
145
+ }
146
+
147
+ - (ENRMDepthChangeResult)changeDepthBy:(NSInteger)delta
148
+ cursorPosition:(NSUInteger)cursorPos
149
+ selectionRange:(NSRange)selection
150
+ inText:(NSString *)text
151
+ {
152
+ ENRMBlockRange *cursorBlock = [self listBlockAtPosition:cursorPos inText:text];
153
+ if (cursorBlock == nil) {
154
+ if (delta > 0 && [self headingLevelAtPosition:cursorPos inText:text] == 0) {
155
+ [self toggleListType:ENRMInputBlockTypeUnorderedListItem
156
+ cursorPosition:cursorPos
157
+ selectionRange:selection
158
+ inText:text];
159
+ return ENRMDepthChangeResultStartedList;
160
+ }
161
+ return ENRMDepthChangeResultNoOp;
162
+ }
163
+
164
+ if (delta < 0 && cursorBlock.level == 0) {
165
+ [self toggleListType:cursorBlock.type cursorPosition:cursorPos selectionRange:selection inText:text];
166
+ return ENRMDepthChangeResultExitedList;
167
+ }
168
+
169
+ NSRange paragraphRange = [text paragraphRangeForRange:selection];
170
+
171
+ if (paragraphRange.length == 0) {
172
+ NSInteger newDepth = MIN(MAX(cursorBlock.level + delta, (NSInteger)0), kENRMMaxListDepth);
173
+ [_blockStore setBlockType:cursorBlock.type level:newDepth forParagraphRange:paragraphRange inText:text];
174
+ } else {
175
+ [text
176
+ enumerateSubstringsInRange:paragraphRange
177
+ options:NSStringEnumerationByParagraphs | NSStringEnumerationSubstringNotRequired
178
+ usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
179
+ ENRMBlockRange *block = [self listBlockAtPosition:substringRange.location inText:text];
180
+ if (block == nil) {
181
+ return;
182
+ }
183
+ NSInteger newDepth = MIN(MAX(block.level + delta, (NSInteger)0), kENRMMaxListDepth);
184
+ [self->_blockStore setBlockType:block.type
185
+ level:newDepth
186
+ forParagraphRange:substringRange
187
+ inText:text];
188
+ }];
189
+ }
190
+
191
+ [_blockStore normalizeToLineBoundsInText:text];
192
+ return ENRMDepthChangeResultChanged;
193
+ }
194
+
195
+ @end
@@ -0,0 +1,28 @@
1
+ #pragma once
2
+
3
+ #import "ENRMInputBlockType.h"
4
+ #import <Foundation/Foundation.h>
5
+
6
+ NS_ASSUME_NONNULL_BEGIN
7
+
8
+ /// A block-level element occupying a paragraph/line range. Mirrors
9
+ /// ENRMFormattingRange but for block scope: the range always covers whole lines.
10
+ @interface ENRMBlockRange : NSObject <NSCopying>
11
+
12
+ @property (nonatomic, assign) ENRMInputBlockType type;
13
+ @property (nonatomic, assign) NSRange range;
14
+
15
+ /// Generic integer payload for the block. 0 by default. Headings use it for the
16
+ /// H-level (1-6); list items use it for nesting depth.
17
+ @property (nonatomic, assign) NSInteger level;
18
+
19
+ /// 1-based position of an ordered item among its adjacent same-depth siblings;
20
+ /// recomputed by the block store's list-metadata pass.
21
+ @property (nonatomic, assign) NSInteger ordinal;
22
+
23
+ + (instancetype)rangeWithType:(ENRMInputBlockType)type range:(NSRange)range;
24
+ + (instancetype)rangeWithType:(ENRMInputBlockType)type range:(NSRange)range level:(NSInteger)level;
25
+
26
+ @end
27
+
28
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,30 @@
1
+ #import "ENRMBlockRange.h"
2
+
3
+ @implementation ENRMBlockRange
4
+
5
+ + (instancetype)rangeWithType:(ENRMInputBlockType)type range:(NSRange)range
6
+ {
7
+ return [self rangeWithType:type range:range level:0];
8
+ }
9
+
10
+ + (instancetype)rangeWithType:(ENRMInputBlockType)type range:(NSRange)range level:(NSInteger)level
11
+ {
12
+ ENRMBlockRange *blockRange = [[ENRMBlockRange alloc] init];
13
+ blockRange.type = type;
14
+ blockRange.range = range;
15
+ blockRange.level = level;
16
+ blockRange.ordinal = 1;
17
+ return blockRange;
18
+ }
19
+
20
+ - (id)copyWithZone:(NSZone *)zone
21
+ {
22
+ ENRMBlockRange *copy = [[ENRMBlockRange allocWithZone:zone] init];
23
+ copy.type = _type;
24
+ copy.range = _range;
25
+ copy.level = _level;
26
+ copy.ordinal = _ordinal;
27
+ return copy;
28
+ }
29
+
30
+ @end