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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (469) hide show
  1. package/README.md +54 -8
  2. package/ReactNativeEnrichedMarkdown.podspec +82 -73
  3. package/android/build.gradle +186 -1
  4. package/android/consumer-rules.pro +1 -1
  5. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerDelegate.java +9 -0
  6. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java +3 -0
  7. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerDelegate.java +24 -0
  8. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerInterface.java +8 -0
  9. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +9 -0
  10. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +3 -0
  11. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +75 -0
  12. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +63 -0
  13. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +35 -0
  14. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +886 -23
  15. package/android/src/main/baseline-prof.txt +1 -1
  16. package/android/src/main/cpp/jni-adapter.cpp +74 -0
  17. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdown.kt +189 -13
  18. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt +17 -0
  19. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownManager.kt +50 -0
  20. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +48 -1
  21. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextLayoutManager.kt +10 -1
  22. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +42 -0
  23. package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +82 -4
  24. package/android/src/main/java/com/swmansion/enriched/markdown/events/CopyPressEvent.kt +24 -0
  25. package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt +54 -4
  26. package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputView.kt +901 -462
  27. package/android/src/main/java/com/swmansion/enriched/markdown/input/MarkdownClipboard.kt +42 -0
  28. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/BlockEditCoordinator.kt +196 -0
  29. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/ClipboardCoordinator.kt +73 -0
  30. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/EditContext.kt +19 -0
  31. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/EditPipeline.kt +248 -0
  32. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/EditSession.kt +52 -0
  33. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/InputConnectionWrapper.kt +101 -7
  34. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/LinkCoordinator.kt +69 -0
  35. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/MarkdownTextWatcher.kt +3 -3
  36. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/MentionCoordinator.kt +118 -0
  37. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnChangeStateEvent.kt +26 -0
  38. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnContextMenuItemPressEvent.kt +26 -0
  39. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnInputKeyPressEvent.kt +24 -0
  40. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnPasteEvent.kt +24 -0
  41. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/BlockStore.kt +254 -0
  42. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/FormattingStore.kt +80 -87
  43. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputFormatter.kt +109 -1
  44. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputParser.kt +116 -22
  45. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/MarkdownSerializer.kt +167 -38
  46. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/RangeEditAdjustment.kt +149 -0
  47. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputEventEmitter.kt +66 -5
  48. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputMeasurementStore.kt +4 -2
  49. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/BlockRange.kt +27 -0
  50. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/BlockType.kt +48 -0
  51. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/FormattingRange.kt +9 -4
  52. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/InputFormatterStyle.kt +39 -2
  53. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathAtom.kt +20 -0
  54. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathChipStyle.kt +1 -1
  55. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MutableRangeBounds.kt +11 -0
  56. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputBulletSpan.kt +82 -0
  57. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputHeadingSpan.kt +58 -0
  58. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputListItemSpacingSpan.kt +37 -0
  59. package/android/src/main/java/com/swmansion/enriched/markdown/input/spans/InputOrderedListMarkerSpan.kt +63 -0
  60. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/BlockHandler.kt +54 -0
  61. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/HeadingBlockHandler.kt +27 -0
  62. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/OrderedListBlockHandler.kt +38 -0
  63. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/UnorderedListBlockHandler.kt +37 -0
  64. package/android/src/main/java/com/swmansion/enriched/markdown/input/toolbar/InputContextMenu.kt +8 -26
  65. package/android/src/main/java/com/swmansion/enriched/markdown/parser/MarkdownASTNode.kt +1 -0
  66. package/android/src/main/java/com/swmansion/enriched/markdown/parser/Parser.kt +1 -0
  67. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockStyleContext.kt +9 -2
  68. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt +100 -12
  69. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeBlockRenderer.kt +16 -1
  70. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +4 -0
  71. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListContextManager.kt +2 -1
  72. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListItemRenderer.kt +74 -18
  73. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListRenderer.kt +43 -4
  74. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/NodeRenderer.kt +9 -1
  75. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SoftBreakRenderer.kt +16 -0
  76. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +30 -27
  77. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BaseListSpan.kt +24 -0
  78. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt +174 -24
  79. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBackgroundSpan.kt +27 -3
  80. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBlockSpan.kt +13 -16
  81. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeSpan.kt +1 -1
  82. package/android/src/main/java/com/swmansion/enriched/markdown/spans/EmphasisSpan.kt +1 -1
  83. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ImageSpan.kt +182 -46
  84. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ListItemSpacingSpan.kt +33 -0
  85. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ListMarkerAnchorSpan.kt +38 -0
  86. package/android/src/main/java/com/swmansion/enriched/markdown/spans/OrderedListSpan.kt +2 -0
  87. package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrongSpan.kt +1 -1
  88. package/android/src/main/java/com/swmansion/enriched/markdown/spans/TaskListSpan.kt +3 -2
  89. package/android/src/main/java/com/swmansion/enriched/markdown/spans/UnorderedListSpan.kt +3 -2
  90. package/android/src/main/java/com/swmansion/enriched/markdown/styles/BlockquoteStyle.kt +6 -0
  91. package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeBlockStyle.kt +26 -0
  92. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ImageStyle.kt +7 -1
  93. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ListStyle.kt +4 -1
  94. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt +13 -4
  95. package/android/src/main/java/com/swmansion/enriched/markdown/styles/TableStyle.kt +6 -0
  96. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/CodeBlockHighlighter.kt +90 -0
  97. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/CodeBlockNode.kt +57 -0
  98. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/FeatureFlags.kt +1 -0
  99. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownSegment.kt +9 -0
  100. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt +37 -7
  101. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/ReadableMapExtensions.kt +3 -0
  102. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/RenderedSegment.kt +10 -0
  103. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/SegmentSignature.kt +1 -0
  104. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/StreamingMarkdownFilter.kt +83 -5
  105. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/serialization/MarkdownASTSerializer.kt +4 -0
  106. package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/MarkdownStyleParser.kt +74 -44
  107. package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/PasteTextUtils.kt +20 -0
  108. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/ImageCache.kt +26 -3
  109. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/ImageDownloader.kt +22 -9
  110. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/LocalImageLoader.kt +161 -0
  111. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/extensions/TextPaintExtensions.kt +23 -0
  112. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/interaction/CheckboxTouchHelper.kt +7 -0
  113. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/interaction/TaskListTapUtils.kt +41 -21
  114. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/span/BlockSpacing.kt +15 -8
  115. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkLongPressMovementMethod.kt +58 -27
  116. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionActionMode.kt +49 -15
  117. package/android/src/main/java/com/swmansion/enriched/markdown/views/BlockMenuOptions.kt +45 -0
  118. package/android/src/main/java/com/swmansion/enriched/markdown/views/CodeBlockContainerView.kt +396 -0
  119. package/android/src/main/java/com/swmansion/enriched/markdown/views/ContextMenuPopup.kt +9 -6
  120. package/android/src/main/java/com/swmansion/enriched/markdown/views/CopyGlyph.kt +101 -0
  121. package/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt +36 -9
  122. package/android/src/main/jni/CMakeLists.txt +53 -0
  123. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownContainerShadowNode.cpp +10 -0
  124. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownContainerShadowNode.h +11 -2
  125. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.cpp +10 -0
  126. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.h +12 -2
  127. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextState.cpp +9 -0
  128. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextState.h +24 -0
  129. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/conversions.h +16 -0
  130. package/android/src/math/java/com/swmansion/enriched/markdown/input/math/MathChipControllerImpl.kt +21 -4
  131. package/android/src/math/java/com/swmansion/enriched/markdown/renderer/MathInlineRenderer.kt +7 -2
  132. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathChipSpan.kt +1 -1
  133. package/android/src/math/java/com/swmansion/enriched/markdown/views/MathContainerView.kt +6 -4
  134. package/cpp/highlight/CodeBlockHighlighter.cpp +284 -0
  135. package/cpp/highlight/CodeBlockHighlighter.hpp +66 -0
  136. package/cpp/highlight/CodeBlockLanguages.cpp +138 -0
  137. package/cpp/highlight/CodeBlockLanguages.hpp +25 -0
  138. package/cpp/highlight/HighlightGrammars.hpp +28 -0
  139. package/cpp/highlight/code_highlight_podspec.rb +211 -0
  140. package/cpp/highlight/gen-registry.mjs +155 -0
  141. package/cpp/highlight/grammar-versions.json +159 -0
  142. package/cpp/highlight/vendor/generated/generated_queries.h +1665 -0
  143. package/cpp/highlight/vendor/generated/generated_registry.cpp +59 -0
  144. package/cpp/parser/MD4CParser.cpp +173 -61
  145. package/cpp/parser/MD4CParser.hpp +1 -0
  146. package/cpp/parser/MarkdownASTNode.hpp +2 -1
  147. package/cpp/wasm/ASTSerializer.cpp +2 -0
  148. package/cpp/wasm/build.sh +1 -0
  149. package/cpp/wasm/md4c_wasm.cpp +3 -1
  150. package/docs/ACCESSIBILITY.md +14 -2
  151. package/docs/API_REFERENCE.md +234 -12
  152. package/docs/BREAKING_CHANGES.md +129 -0
  153. package/docs/CODE_HIGHLIGHT.md +133 -0
  154. package/docs/COPY_OPTIONS.md +47 -3
  155. package/docs/ELEMENTS_STRUCTURE.md +52 -4
  156. package/docs/IMAGE_CACHING.md +30 -0
  157. package/docs/INPUT.md +108 -11
  158. package/docs/LATEX_MATH.md +87 -45
  159. package/docs/MACOS.md +1 -1
  160. package/docs/MARKDOWN_STREAMING.md +27 -1
  161. package/docs/NATIVE_ASSETS.md +127 -0
  162. package/docs/RTL.md +1 -1
  163. package/docs/STYLES.md +46 -6
  164. package/docs/TESTING.md +112 -0
  165. package/docs/TEXT.md +16 -6
  166. package/docs/WEB.md +3 -1
  167. package/ios/EnrichedMarkdown.h +7 -0
  168. package/ios/EnrichedMarkdown.mm +284 -75
  169. package/ios/EnrichedMarkdownText.h +7 -0
  170. package/ios/EnrichedMarkdownText.mm +101 -73
  171. package/ios/attachments/ENRMImageAttachment.h +9 -0
  172. package/ios/attachments/ENRMImageAttachment.m +143 -40
  173. package/ios/attachments/ENRMMathInlineAttachment.h +2 -0
  174. package/ios/attachments/ENRMMathInlineAttachment.m +48 -81
  175. package/ios/attachments/ENRMMathInlineAttachmentShared.h +2 -0
  176. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.cpp +75 -0
  177. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.h +63 -0
  178. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp +35 -0
  179. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +886 -23
  180. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +131 -0
  181. package/ios/input/ENRMAutoLinkDetector.h +2 -1
  182. package/ios/input/ENRMAutoLinkDetector.mm +79 -41
  183. package/ios/input/ENRMBlockEditCoordinator.h +71 -0
  184. package/ios/input/ENRMBlockEditCoordinator.mm +195 -0
  185. package/ios/input/ENRMBlockRange.h +28 -0
  186. package/ios/input/ENRMBlockRange.mm +30 -0
  187. package/ios/input/ENRMBlockStore.h +56 -0
  188. package/ios/input/ENRMBlockStore.mm +275 -0
  189. package/ios/input/ENRMClipboardCoordinator.h +45 -0
  190. package/ios/input/ENRMClipboardCoordinator.mm +120 -0
  191. package/ios/input/ENRMDetectorPipeline.h +2 -1
  192. package/ios/input/ENRMEditPipeline.h +76 -0
  193. package/ios/input/ENRMEditPipeline.mm +228 -0
  194. package/ios/input/ENRMEditSession.h +36 -0
  195. package/ios/input/ENRMEditSession.mm +63 -0
  196. package/ios/input/ENRMFormattingStore.h +17 -0
  197. package/ios/input/ENRMFormattingStore.mm +95 -105
  198. package/ios/input/ENRMInputBlockType.h +91 -0
  199. package/ios/input/ENRMInputBlockType.mm +5 -0
  200. package/ios/input/ENRMInputDecorationDrawer.h +18 -0
  201. package/ios/input/ENRMInputEventEmitter.h +56 -0
  202. package/ios/input/ENRMInputEventEmitter.mm +308 -0
  203. package/ios/input/ENRMInputFormatter.h +29 -69
  204. package/ios/input/ENRMInputFormatter.mm +216 -124
  205. package/ios/input/ENRMInputFormatterStyle.h +99 -0
  206. package/ios/input/ENRMInputFormatterStyle.mm +188 -0
  207. package/ios/input/ENRMInputLayoutManager.h +9 -0
  208. package/ios/input/ENRMInputLayoutManager.mm +30 -0
  209. package/ios/input/ENRMInputListMarkerDrawer.h +32 -0
  210. package/ios/input/ENRMInputListMarkerDrawer.mm +426 -0
  211. package/ios/input/ENRMInputParser.h +5 -6
  212. package/ios/input/ENRMInputParser.mm +461 -178
  213. package/ios/input/ENRMInputRemend.mm +2 -2
  214. package/ios/input/ENRMInputStyleStateBuilder.h +40 -0
  215. package/ios/input/ENRMInputStyleStateBuilder.mm +60 -0
  216. package/ios/input/ENRMInputTextView.mm +103 -8
  217. package/ios/input/ENRMInputTypingAttributesController.h +42 -0
  218. package/ios/input/ENRMInputTypingAttributesController.mm +203 -0
  219. package/ios/input/ENRMLinkCoordinator.h +41 -0
  220. package/ios/input/ENRMLinkCoordinator.mm +89 -0
  221. package/ios/input/ENRMMarkdownSerializer.h +29 -5
  222. package/ios/input/ENRMMarkdownSerializer.mm +170 -48
  223. package/ios/input/ENRMMathAtom.h +26 -0
  224. package/ios/input/ENRMMathAtom.mm +12 -0
  225. package/ios/input/ENRMMentionCoordinator.h +45 -0
  226. package/ios/input/ENRMMentionCoordinator.mm +167 -0
  227. package/ios/input/ENRMRangeEditAdjustment.h +38 -0
  228. package/ios/input/ENRMRangeEditAdjustment.mm +91 -0
  229. package/ios/input/ENRMRangeStoreUtils.h +39 -0
  230. package/ios/input/EnrichedMarkdownTextInput+ContextMenu.mm +6 -6
  231. package/ios/input/EnrichedMarkdownTextInput+Internal.h +11 -3
  232. package/ios/input/EnrichedMarkdownTextInput.h +7 -1
  233. package/ios/input/EnrichedMarkdownTextInput.mm +1089 -1023
  234. package/ios/input/InputStylePropsUtils.h +109 -68
  235. package/ios/input/internals/EnrichedMarkdownTextInputShadowNode.mm +2 -1
  236. package/ios/input/styles/ENRMBlockHandler.h +46 -0
  237. package/ios/input/styles/ENRMHeadingBlockHandler.h +15 -0
  238. package/ios/input/styles/ENRMHeadingBlockHandler.mm +38 -0
  239. package/ios/input/styles/ENRMOrderedListBlockHandler.h +14 -0
  240. package/ios/input/styles/ENRMOrderedListBlockHandler.mm +48 -0
  241. package/ios/input/styles/ENRMUnorderedListBlockHandler.h +15 -0
  242. package/ios/input/styles/ENRMUnorderedListBlockHandler.mm +51 -0
  243. package/ios/internals/ENRMViewFreeMeasurement.h +331 -0
  244. package/ios/internals/EnrichedMarkdownShadowNode.h +1 -3
  245. package/ios/internals/EnrichedMarkdownShadowNode.mm +16 -20
  246. package/ios/internals/EnrichedMarkdownTextShadowNode.h +1 -3
  247. package/ios/internals/EnrichedMarkdownTextShadowNode.mm +15 -20
  248. package/ios/internals/MeasurementCache.h +33 -7
  249. package/ios/internals/ShadowMeasurementUtils.h +63 -58
  250. package/ios/math/ENRMMathChipController.h +74 -0
  251. package/ios/math/ENRMMathChipController.mm +476 -0
  252. package/ios/math/ENRMRaTeXBridge.swift +4 -1
  253. package/ios/parser/ENRMMarkdownParser.h +1 -8
  254. package/ios/parser/ENRMMarkdownParser.mm +2 -11
  255. package/ios/parser/MarkdownASTNode.h +2 -1
  256. package/ios/parser/MarkdownParserBridge.mm +4 -0
  257. package/ios/renderer/AttributedRenderer.m +20 -2
  258. package/ios/renderer/BaseRenderer.h +17 -2
  259. package/ios/renderer/BaseRenderer.m +30 -0
  260. package/ios/renderer/BlockquoteRenderer.h +1 -1
  261. package/ios/renderer/BlockquoteRenderer.m +144 -35
  262. package/ios/renderer/CodeBlockRenderer.h +1 -1
  263. package/ios/renderer/CodeBlockRenderer.m +27 -23
  264. package/ios/renderer/CodeRenderer.h +1 -1
  265. package/ios/renderer/CodeRenderer.m +3 -1
  266. package/ios/renderer/ENRMImageRenderer.h +1 -1
  267. package/ios/renderer/ENRMImageRenderer.m +5 -1
  268. package/ios/renderer/ENRMMathInlineRenderer.h +1 -1
  269. package/ios/renderer/ENRMMathInlineRenderer.m +5 -1
  270. package/ios/renderer/ENRMSpoilerRenderer.h +1 -1
  271. package/ios/renderer/ENRMSpoilerRenderer.m +3 -1
  272. package/ios/renderer/EmphasisRenderer.h +1 -1
  273. package/ios/renderer/EmphasisRenderer.m +3 -1
  274. package/ios/renderer/HeadingRenderer.h +1 -1
  275. package/ios/renderer/HeadingRenderer.m +13 -6
  276. package/ios/renderer/HighlightRenderer.h +1 -1
  277. package/ios/renderer/HighlightRenderer.m +3 -1
  278. package/ios/renderer/LinkRenderer.h +1 -1
  279. package/ios/renderer/LinkRenderer.m +3 -1
  280. package/ios/renderer/ListItemRenderer.h +13 -1
  281. package/ios/renderer/ListItemRenderer.m +102 -44
  282. package/ios/renderer/ListRenderer.h +2 -2
  283. package/ios/renderer/ListRenderer.m +63 -25
  284. package/ios/renderer/ParagraphRenderer.h +1 -1
  285. package/ios/renderer/ParagraphRenderer.m +16 -8
  286. package/ios/renderer/RenderContext.h +10 -0
  287. package/ios/renderer/RenderContext.m +44 -0
  288. package/ios/renderer/RendererFactory.m +14 -0
  289. package/ios/renderer/StrikethroughRenderer.h +1 -1
  290. package/ios/renderer/StrikethroughRenderer.m +3 -1
  291. package/ios/renderer/StrongRenderer.h +1 -1
  292. package/ios/renderer/StrongRenderer.m +3 -1
  293. package/ios/renderer/SubscriptRenderer.h +1 -1
  294. package/ios/renderer/SubscriptRenderer.m +3 -1
  295. package/ios/renderer/SuperscriptRenderer.h +1 -1
  296. package/ios/renderer/SuperscriptRenderer.m +3 -1
  297. package/ios/renderer/TextRenderer.h +2 -2
  298. package/ios/renderer/TextRenderer.m +3 -1
  299. package/ios/renderer/ThematicBreakRenderer.h +1 -1
  300. package/ios/renderer/ThematicBreakRenderer.m +3 -1
  301. package/ios/renderer/UnderlineRenderer.h +1 -1
  302. package/ios/renderer/UnderlineRenderer.m +3 -1
  303. package/ios/styles/StyleConfig.h +22 -0
  304. package/ios/styles/StyleConfig.mm +132 -0
  305. package/ios/utils/BlockquoteBorder.h +6 -0
  306. package/ios/utils/BlockquoteBorder.m +249 -52
  307. package/ios/utils/CodeBlockBackground.m +16 -2
  308. package/ios/utils/ENRMAtomicSize.h +65 -0
  309. package/ios/utils/ENRMBlockMenu.h +57 -0
  310. package/ios/utils/ENRMCodeBlockContent.h +37 -0
  311. package/ios/utils/ENRMCodeBlockContent.mm +79 -0
  312. package/ios/utils/ENRMCodeBlockHighlighter.h +37 -0
  313. package/ios/utils/ENRMCodeBlockHighlighter.mm +51 -0
  314. package/ios/utils/ENRMFeatureFlags.h +7 -0
  315. package/ios/utils/ENRMImageDownloader.h +11 -1
  316. package/ios/utils/ENRMImageDownloader.m +60 -16
  317. package/ios/utils/ENRMLocalImageLoader.h +31 -0
  318. package/ios/utils/ENRMLocalImageLoader.m +68 -0
  319. package/ios/utils/ENRMMathFallback.h +26 -0
  320. package/ios/utils/ENRMMathFallback.m +18 -0
  321. package/ios/utils/ENRMTextViewSetup.h +35 -17
  322. package/ios/utils/EditMenuUtils.h +22 -5
  323. package/ios/utils/EditMenuUtils.m +53 -9
  324. package/ios/utils/ImageRequestHeaderUtils.h +35 -0
  325. package/ios/utils/LastElementUtils.h +1 -0
  326. package/ios/utils/ListMarkerDrawer.m +29 -42
  327. package/ios/utils/MarkdownASTSerializer.m +4 -0
  328. package/ios/utils/ParagraphStyleUtils.h +5 -0
  329. package/ios/utils/ParagraphStyleUtils.m +77 -17
  330. package/ios/utils/RenderedMarkdownSegment.h +13 -1
  331. package/ios/utils/RenderedMarkdownSegment.m +20 -0
  332. package/ios/utils/SegmentRenderer.m +17 -4
  333. package/ios/utils/StreamingMarkdownFilter.h +11 -1
  334. package/ios/utils/StreamingMarkdownFilter.m +98 -2
  335. package/ios/utils/StylePropsUtils.h +63 -0
  336. package/ios/utils/TaskListTapUtils.m +24 -0
  337. package/ios/views/ENRMCodeBlockContainerView.h +53 -0
  338. package/ios/views/ENRMCodeBlockContainerView.m +559 -0
  339. package/ios/views/ENRMMathContainerView.h +16 -0
  340. package/ios/views/ENRMMathContainerView.m +74 -19
  341. package/ios/views/TableContainerView.h +22 -0
  342. package/ios/views/TableContainerView.m +261 -175
  343. package/jest.d.ts +1 -0
  344. package/jest.js +5 -0
  345. package/lib/module/EnrichedMarkdownNativeComponent.ts +73 -0
  346. package/lib/module/EnrichedMarkdownTextInput.js +84 -5
  347. package/lib/module/EnrichedMarkdownTextInput.js.map +1 -1
  348. package/lib/module/EnrichedMarkdownTextInputNativeComponent.ts +78 -5
  349. package/lib/module/EnrichedMarkdownTextNativeComponent.ts +74 -0
  350. package/lib/module/headingDefaults.js +34 -0
  351. package/lib/module/headingDefaults.js.map +1 -0
  352. package/lib/module/index.js.map +1 -1
  353. package/lib/module/jest/index.js +191 -0
  354. package/lib/module/jest/index.js.map +1 -0
  355. package/lib/module/native/EnrichedMarkdownText.js +37 -5
  356. package/lib/module/native/EnrichedMarkdownText.js.map +1 -1
  357. package/lib/module/normalizeMarkdownStyle.js +81 -19
  358. package/lib/module/normalizeMarkdownStyle.js.map +1 -1
  359. package/lib/module/normalizeMarkdownStyle.web.js +56 -18
  360. package/lib/module/normalizeMarkdownStyle.web.js.map +1 -1
  361. package/lib/module/normalizeMarkdownTextInputStyle.js +62 -15
  362. package/lib/module/normalizeMarkdownTextInputStyle.js.map +1 -1
  363. package/lib/module/normalizeMenuItem.js +1 -1
  364. package/lib/module/utils/textInputState.js +26 -0
  365. package/lib/module/utils/textInputState.js.map +1 -0
  366. package/lib/module/web/EnrichedMarkdownText.js +9 -5
  367. package/lib/module/web/EnrichedMarkdownText.js.map +1 -1
  368. package/lib/module/web/parseMarkdown.js +4 -3
  369. package/lib/module/web/parseMarkdown.js.map +1 -1
  370. package/lib/module/web/renderers/InlineRenderers.js +6 -0
  371. package/lib/module/web/renderers/InlineRenderers.js.map +1 -1
  372. package/lib/module/web/renderers/ListRenderers.js +7 -2
  373. package/lib/module/web/renderers/ListRenderers.js.map +1 -1
  374. package/lib/module/web/renderers/index.js +7 -4
  375. package/lib/module/web/renderers/index.js.map +1 -1
  376. package/lib/module/web/styles.js +83 -6
  377. package/lib/module/web/styles.js.map +1 -1
  378. package/lib/module/web/utils.js +1 -0
  379. package/lib/module/web/utils.js.map +1 -1
  380. package/lib/module/web/wasm/md4c.js +0 -0
  381. package/lib/module/web/wasm/md4c.js.map +1 -1
  382. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts +66 -0
  383. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -1
  384. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts +94 -9
  385. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts.map +1 -1
  386. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts +69 -5
  387. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts.map +1 -1
  388. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +66 -0
  389. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -1
  390. package/lib/typescript/src/headingDefaults.d.ts +9 -0
  391. package/lib/typescript/src/headingDefaults.d.ts.map +1 -0
  392. package/lib/typescript/src/index.d.ts +2 -2
  393. package/lib/typescript/src/index.d.ts.map +1 -1
  394. package/lib/typescript/src/index.web.d.ts +1 -1
  395. package/lib/typescript/src/index.web.d.ts.map +1 -1
  396. package/lib/typescript/src/jest/index.d.ts +6 -0
  397. package/lib/typescript/src/jest/index.d.ts.map +1 -0
  398. package/lib/typescript/src/native/EnrichedMarkdownText.d.ts +3 -3
  399. package/lib/typescript/src/native/EnrichedMarkdownText.d.ts.map +1 -1
  400. package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -1
  401. package/lib/typescript/src/normalizeMarkdownStyle.web.d.ts.map +1 -1
  402. package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts +19 -5
  403. package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts.map +1 -1
  404. package/lib/typescript/src/types/MarkdownStyle.d.ts +72 -0
  405. package/lib/typescript/src/types/MarkdownStyle.d.ts.map +1 -1
  406. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts +27 -0
  407. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts.map +1 -1
  408. package/lib/typescript/src/types/MarkdownTextProps.d.ts +104 -9
  409. package/lib/typescript/src/types/MarkdownTextProps.d.ts.map +1 -1
  410. package/lib/typescript/src/types/MarkdownTextProps.web.d.ts +19 -0
  411. package/lib/typescript/src/types/MarkdownTextProps.web.d.ts.map +1 -1
  412. package/lib/typescript/src/types/events.d.ts +19 -0
  413. package/lib/typescript/src/types/events.d.ts.map +1 -1
  414. package/lib/typescript/src/utils/textInputState.d.ts +24 -0
  415. package/lib/typescript/src/utils/textInputState.d.ts.map +1 -0
  416. package/lib/typescript/src/web/EnrichedMarkdownText.d.ts +1 -1
  417. package/lib/typescript/src/web/EnrichedMarkdownText.d.ts.map +1 -1
  418. package/lib/typescript/src/web/parseMarkdown.d.ts +1 -1
  419. package/lib/typescript/src/web/parseMarkdown.d.ts.map +1 -1
  420. package/lib/typescript/src/web/renderers/InlineRenderers.d.ts.map +1 -1
  421. package/lib/typescript/src/web/renderers/ListRenderers.d.ts.map +1 -1
  422. package/lib/typescript/src/web/renderers/index.d.ts +2 -1
  423. package/lib/typescript/src/web/renderers/index.d.ts.map +1 -1
  424. package/lib/typescript/src/web/styles.d.ts +2 -1
  425. package/lib/typescript/src/web/styles.d.ts.map +1 -1
  426. package/lib/typescript/src/web/types.d.ts +6 -2
  427. package/lib/typescript/src/web/types.d.ts.map +1 -1
  428. package/lib/typescript/src/web/utils.d.ts.map +1 -1
  429. package/package.json +36 -9
  430. package/postinstall.mjs +131 -0
  431. package/ratex-version.json +21 -0
  432. package/src/EnrichedMarkdownNativeComponent.ts +73 -0
  433. package/src/EnrichedMarkdownTextInput.tsx +159 -8
  434. package/src/EnrichedMarkdownTextInputNativeComponent.ts +78 -5
  435. package/src/EnrichedMarkdownTextNativeComponent.ts +74 -0
  436. package/src/headingDefaults.ts +21 -0
  437. package/src/index.tsx +9 -0
  438. package/src/index.web.tsx +1 -0
  439. package/src/jest/index.tsx +215 -0
  440. package/src/native/EnrichedMarkdownText.tsx +53 -2
  441. package/src/normalizeMarkdownStyle.ts +102 -16
  442. package/src/normalizeMarkdownStyle.web.ts +63 -15
  443. package/src/normalizeMarkdownTextInputStyle.ts +110 -35
  444. package/src/normalizeMenuItem.ts +1 -1
  445. package/src/types/MarkdownStyle.ts +74 -0
  446. package/src/types/MarkdownStyleInternal.ts +39 -0
  447. package/src/types/MarkdownTextProps.ts +101 -9
  448. package/src/types/MarkdownTextProps.web.ts +19 -0
  449. package/src/types/events.ts +21 -0
  450. package/src/utils/textInputState.ts +35 -0
  451. package/src/web/EnrichedMarkdownText.tsx +16 -2
  452. package/src/web/parseMarkdown.ts +6 -2
  453. package/src/web/renderers/InlineRenderers.tsx +5 -0
  454. package/src/web/renderers/ListRenderers.tsx +14 -2
  455. package/src/web/renderers/index.tsx +6 -2
  456. package/src/web/styles.ts +89 -5
  457. package/src/web/types.ts +6 -1
  458. package/src/web/utils.ts +1 -0
  459. package/src/web/wasm/md4c.js +0 -0
  460. package/vendor-grammars.mjs +511 -0
  461. package/vendor-ratex.mjs +173 -0
  462. package/app.plugin.js +0 -2
  463. package/plugin/build/withAndroidMath.js +0 -19
  464. package/plugin/build/withIosMath.js +0 -28
  465. package/plugin/build/withReactNativeEnrichedMarkdown.js +0 -11
  466. package/plugin/src/withAndroidMath.ts +0 -24
  467. package/plugin/src/withIosMath.ts +0 -35
  468. package/plugin/src/withReactNativeEnrichedMarkdown.ts +0 -17
  469. package/plugin/tsconfig.build.json +0 -16
@@ -1,4 +1,5 @@
1
1
  #import "ListItemRenderer.h"
2
+ #import "BlockquoteBorder.h"
2
3
  #import "ENRMUIKit.h"
3
4
  #import "LastElementUtils.h"
4
5
  #import "MarkdownASTNode.h"
@@ -10,10 +11,14 @@
10
11
  NSString *const ListDepthAttribute = @"ListDepth";
11
12
  NSString *const ListTypeAttribute = @"ListType";
12
13
  NSString *const ListItemNumberAttribute = @"ListItemNumber";
14
+ NSString *const ListItemMarkerStartAttribute = @"ListItemMarkerStart";
13
15
  NSString *const TaskItemAttribute = @"TaskItem";
14
16
  NSString *const TaskCheckedAttribute = @"TaskChecked";
15
17
  NSString *const TaskIndexAttribute = @"TaskIndex";
16
18
 
19
+ @implementation ENRMListMarkerDescriptor
20
+ @end
21
+
17
22
  @interface ListItemRenderer ()
18
23
  - (void)applyCheckedDecorationsTo:(NSMutableAttributedString *)output
19
24
  range:(NSRange)range
@@ -22,7 +27,9 @@ NSString *const TaskIndexAttribute = @"TaskIndex";
22
27
 
23
28
  @implementation ListItemRenderer
24
29
 
25
- - (void)renderNode:(MarkdownASTNode *)node into:(NSMutableAttributedString *)output context:(RenderContext *)context
30
+ - (void)renderNodeContent:(MarkdownASTNode *)node
31
+ into:(NSMutableAttributedString *)output
32
+ context:(RenderContext *)context
26
33
  {
27
34
  if (!context)
28
35
  return;
@@ -39,10 +46,28 @@ NSString *const TaskIndexAttribute = @"TaskIndex";
39
46
  context.taskItemCount++;
40
47
  }
41
48
 
49
+ // currentDepth - 1 handles the horizontal offset for nested lists
50
+ const NSInteger nestingLevel = currentDepth - 1;
51
+ const CGFloat baseMarkerWidth = isTask ? [_config effectiveListMarginLeftForTask]
52
+ : (context.listType == ListTypeOrdered) ? [_config effectiveListMarginLeftForNumber]
53
+ : [_config effectiveListMarginLeftForBullet];
54
+
55
+ const CGFloat blockquoteIndent =
56
+ blockquoteIndentForDepth(context.blockquoteDepth, [_config blockquoteBorderWidth] + [_config blockquoteGapWidth]);
57
+
58
+ const CGFloat totalIndent = blockquoteIndent + baseMarkerWidth + [_config effectiveListGapWidth] +
59
+ (nestingLevel * [_config listStyleMarginLeft]);
60
+
42
61
  const NSUInteger startLocation = output.length;
43
62
 
44
- // Render the actual content of the list item (text, bolding, etc.)
45
- [_rendererFactory renderChildrenOfNode:node into:output context:context];
63
+ // Manual save/restore — a scope snapshot would also roll back the listItemNumber increment
64
+ const CGFloat prevIndent = context.accumulatedIndent;
65
+ context.accumulatedIndent = totalIndent;
66
+ @try {
67
+ [_rendererFactory renderChildrenOfNode:node into:output context:context];
68
+ } @finally {
69
+ context.accumulatedIndent = prevIndent;
70
+ }
46
71
 
47
72
  // Ensure every list item ends with a newline to prevent paragraph merging
48
73
  if (output.length > startLocation && ![output.string hasSuffix:@"\n"]) {
@@ -59,15 +84,6 @@ NSString *const TaskIndexAttribute = @"TaskIndex";
59
84
  depth:currentDepth
60
85
  isOrdered:(context.listType == ListTypeOrdered)];
61
86
 
62
- // currentDepth - 1 handles the horizontal offset for nested lists
63
- const NSInteger nestingLevel = currentDepth - 1;
64
- const CGFloat baseMarkerWidth = isTask ? [_config effectiveListMarginLeftForTask]
65
- : (context.listType == ListTypeOrdered) ? [_config effectiveListMarginLeftForNumber]
66
- : [_config effectiveListMarginLeftForBullet];
67
-
68
- const CGFloat totalIndent =
69
- baseMarkerWidth + [_config effectiveListGapWidth] + (nestingLevel * [_config listStyleMarginLeft]);
70
-
71
87
  const CGFloat lineHeightConfig = [_config listStyleLineHeight];
72
88
 
73
89
  // Boxing metadata for attributed string storage
@@ -83,45 +99,87 @@ NSString *const TaskIndexAttribute = @"TaskIndex";
83
99
  metadata[TaskIndexAttribute] = @(taskIndex);
84
100
  }
85
101
 
86
- // We enumerate to ensure we don't overwrite styles of nested sub-lists
87
- // or code blocks that may have already been rendered inside this item.
102
+ // Preserve styles of nested sub-lists and code blocks by applying the list
103
+ // paragraph style only to the surviving gaps between them.
104
+ NSMutableArray<NSValue *> *skipRanges = [NSMutableArray array];
105
+ [output enumerateAttribute:CodeBlockAttributeName
106
+ inRange:itemRange
107
+ options:0
108
+ usingBlock:^(id value, NSRange range, BOOL *stop) {
109
+ if ([value boolValue]) {
110
+ [skipRanges addObject:[NSValue valueWithRange:range]];
111
+ }
112
+ }];
88
113
  [output enumerateAttribute:ListDepthAttribute
89
114
  inRange:itemRange
90
115
  options:0
91
116
  usingBlock:^(id depthAttr, NSRange range, BOOL *stop) {
92
- // If a segment already has a Depth attribute higher than our current level,
93
- // it belongs to a nested list and we should skip it to preserve its styling.
94
117
  if (depthAttr && [depthAttr integerValue] > nestingLevel) {
95
- return;
96
- }
97
-
98
- // Skip code block ranges — CodeBlockRenderer already applied its own
99
- // paragraph style (padding, LTR indent). Overwriting would add list
100
- // markers ("2.") inside the code block.
101
- NSNumber *isCodeBlock = [output attribute:CodeBlockAttributeName
102
- atIndex:range.location
103
- effectiveRange:nil];
104
- if ([isCodeBlock boolValue]) {
105
- return;
118
+ [skipRanges addObject:[NSValue valueWithRange:range]];
106
119
  }
120
+ }];
121
+ [skipRanges sortUsingComparator:^NSComparisonResult(NSValue *a, NSValue *b) {
122
+ NSUInteger la = [a rangeValue].location;
123
+ NSUInteger lb = [b rangeValue].location;
124
+ return la < lb ? NSOrderedAscending : (la > lb ? NSOrderedDescending : NSOrderedSame);
125
+ }];
126
+
127
+ void (^applyStyleToRange)(NSRange) = ^(NSRange range) {
128
+ if (range.length == 0)
129
+ return;
130
+ NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
131
+ style.firstLineHeadIndent = totalIndent;
132
+ style.headIndent = totalIndent;
133
+ NSMutableDictionary *attributesToApply = [metadata mutableCopy];
134
+ attributesToApply[NSParagraphStyleAttributeName] = style;
135
+ [output addAttributes:attributesToApply range:range];
136
+ // Line height goes through the shared helper so list items get the same carve-out as
137
+ // paragraphs — inline math AND block images. Clamping maximumLineHeight here directly
138
+ // would push the line fragment below the height an inline math attachment draws at, and
139
+ // the overflow paints over the neighbouring lines. applyLineHeight reads the paragraph
140
+ // style back via getOrCreateParagraphStyle, so it must run AFTER addAttributes: for the
141
+ // indents above to survive; it early-returns on a non-positive line height.
142
+ applyLineHeight(output, range, lineHeightConfig);
143
+ };
144
+
145
+ NSUInteger pos = itemRange.location;
146
+ const NSUInteger itemEnd = NSMaxRange(itemRange);
147
+ for (NSValue *val in skipRanges) {
148
+ NSRange skip = [val rangeValue];
149
+ if (pos < skip.location) {
150
+ applyStyleToRange(NSMakeRange(pos, skip.location - pos));
151
+ }
152
+ pos = MAX(pos, NSMaxRange(skip));
153
+ }
154
+ if (pos < itemEnd) {
155
+ applyStyleToRange(NSMakeRange(pos, itemEnd - pos));
156
+ }
107
157
 
108
- NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
109
- style.firstLineHeadIndent = totalIndent;
110
- style.headIndent = totalIndent;
111
-
112
- NSMutableDictionary *attributesToApply = [metadata mutableCopy];
113
- attributesToApply[NSParagraphStyleAttributeName] = style;
114
-
115
- [output addAttributes:attributesToApply range:range];
158
+ ENRMListMarkerDescriptor *marker = [[ENRMListMarkerDescriptor alloc] init];
159
+ marker.isTask = isTask;
160
+ marker.isChecked = isChecked;
161
+ marker.taskIndex = taskIndex;
162
+ marker.listType = context.listType;
163
+ marker.number = currentPosition;
164
+ marker.depth = nestingLevel;
165
+ marker.indent = totalIndent;
166
+
167
+ // Anchor on the first content character so items that open with a code block
168
+ // or nested sublist still get their marker; fall back to startLocation for
169
+ // whitespace-only items.
170
+ NSUInteger anchorLocation = startLocation;
171
+ NSString *string = output.string;
172
+ for (NSUInteger i = startLocation; i < itemEnd; i++) {
173
+ if ([string characterAtIndex:i] != '\n') {
174
+ anchorLocation = i;
175
+ break;
176
+ }
177
+ }
116
178
 
117
- // Line height goes through the shared helper so list items get the same math
118
- // carve-out as paragraphs. Setting maximumLineHeight here directly would clamp
119
- // the line fragment below the height an inline math attachment draws at, and the
120
- // overflow paints over the neighbouring lines. applyLineHeight reads back the
121
- // paragraph style we just applied, so the indents above survive, and it
122
- // early-returns on a non-positive line height like the old guard did.
123
- applyLineHeight(output, range, lineHeightConfig);
124
- }];
179
+ NSArray *existingMarkers = [output attribute:ListItemMarkerStartAttribute atIndex:anchorLocation effectiveRange:NULL];
180
+ NSArray *markers =
181
+ [existingMarkers isKindOfClass:[NSArray class]] ? [existingMarkers arrayByAddingObject:marker] : @[ marker ];
182
+ [output addAttribute:ListItemMarkerStartAttribute value:markers range:NSMakeRange(anchorLocation, 1)];
125
183
 
126
184
  if (isTask && isChecked) {
127
185
  [self applyCheckedDecorationsTo:output range:itemRange nestingLevel:nestingLevel];
@@ -175,4 +233,4 @@ NSString *const TaskIndexAttribute = @"TaskIndex";
175
233
  }];
176
234
  }
177
235
 
178
- @end
236
+ @end
@@ -1,10 +1,10 @@
1
- #import "NodeRenderer.h"
1
+ #import "BaseRenderer.h"
2
2
 
3
3
  @class RendererFactory;
4
4
  @class StyleConfig;
5
5
  @class RenderContext;
6
6
 
7
- @interface ListRenderer : NSObject <NodeRenderer>
7
+ @interface ListRenderer : BaseRenderer
8
8
 
9
9
  - (instancetype)initWithRendererFactory:(RendererFactory *)rendererFactory
10
10
  config:(StyleConfig *)config
@@ -6,37 +6,75 @@
6
6
  #import "RendererFactory.h"
7
7
  #import "StyleConfig.h"
8
8
 
9
+ // Inserts the configured vertical gap between consecutive list items (including
10
+ // nested ones) by raising paragraphSpacing on the paragraph preceding each item
11
+ // start. The first item of the root list gets no spacing above it.
12
+ static void applyListItemSpacing(NSMutableAttributedString *output, RenderContext *context, NSUInteger listStart,
13
+ CGFloat itemSpacing)
14
+ {
15
+ if (itemSpacing <= 0)
16
+ return;
17
+
18
+ NSMutableIndexSet *itemStarts = [NSMutableIndexSet indexSet];
19
+ for (NSValue *value in context.listItemRanges) {
20
+ NSUInteger location = [value rangeValue].location;
21
+ if (location >= listStart && location < output.length) {
22
+ [itemStarts addIndex:location];
23
+ }
24
+ }
25
+ if (itemStarts.count < 2)
26
+ return;
27
+
28
+ NSString *string = output.string;
29
+ const NSUInteger firstStart = itemStarts.firstIndex;
30
+ [itemStarts enumerateIndexesUsingBlock:^(NSUInteger itemStart, BOOL *stop) {
31
+ if (itemStart == firstStart)
32
+ return;
33
+ NSRange prevParagraph = [string paragraphRangeForRange:NSMakeRange(itemStart - 1, 0)];
34
+ [output enumerateAttribute:NSParagraphStyleAttributeName
35
+ inRange:prevParagraph
36
+ options:0
37
+ usingBlock:^(NSParagraphStyle *style, NSRange range, BOOL *innerStop) {
38
+ if (style.paragraphSpacing >= itemSpacing)
39
+ return;
40
+ NSMutableParagraphStyle *updated =
41
+ style ? [style mutableCopy] : [[NSMutableParagraphStyle alloc] init];
42
+ updated.paragraphSpacing = itemSpacing;
43
+ [output addAttribute:NSParagraphStyleAttributeName value:updated range:range];
44
+ }];
45
+ }];
46
+ }
47
+
9
48
  @implementation ListRenderer {
10
- __weak RendererFactory *_rendererFactory;
11
- StyleConfig *_config;
12
49
  BOOL _isOrdered;
13
50
  }
14
51
 
15
52
  - (instancetype)initWithRendererFactory:(RendererFactory *)factory config:(StyleConfig *)config isOrdered:(BOOL)ordered
16
53
  {
17
- if (self = [super init]) {
18
- _rendererFactory = factory;
19
- _config = config;
54
+ if (self = [super initWithRendererFactory:factory config:config]) {
20
55
  _isOrdered = ordered;
21
56
  }
22
57
  return self;
23
58
  }
24
59
 
25
- - (void)renderNode:(MarkdownASTNode *)node into:(NSMutableAttributedString *)output context:(RenderContext *)context
60
+ - (id)takeContextSnapshot:(RenderContext *)context
61
+ {
62
+ return [context snapshotScope];
63
+ }
64
+
65
+ - (void)renderNodeContent:(MarkdownASTNode *)node
66
+ into:(NSMutableAttributedString *)output
67
+ context:(RenderContext *)context
26
68
  {
27
69
  if (!context)
28
70
  return;
29
71
 
30
72
  const NSInteger prevDepth = context.listDepth;
31
- const ListType prevType = context.listType;
32
- const NSInteger prevNum = context.listItemNumber;
33
-
34
73
  const NSUInteger startLocation = output.length;
35
- NSUInteger contentStart = startLocation;
36
74
 
37
75
  if (prevDepth == 0) {
38
76
  // Apply top margin for root-level list
39
- contentStart += applyBlockSpacingBefore(output, startLocation, _config.listStyleMarginTop);
77
+ applyBlockSpacingBefore(output, startLocation, _config.listStyleMarginTop);
40
78
  } else if (output.length > 0 && ![output.string hasSuffix:@"\n"]) {
41
79
  // Ensure nested lists start on a new line
42
80
  [output appendAttributedString:kNewlineAttributedString];
@@ -44,27 +82,27 @@
44
82
 
45
83
  context.listDepth = prevDepth + 1;
46
84
  context.listType = _isOrdered ? ListTypeOrdered : ListTypeUnordered;
47
- context.listItemNumber = 0; // Reset counter for this specific list level
85
+ NSInteger startNumber = 1;
86
+ NSString *startAttr = node.attributes[@"start"];
87
+ if (_isOrdered && startAttr != nil) {
88
+ startNumber = MAX((NSInteger)0, (NSInteger)startAttr.integerValue);
89
+ }
90
+ // ListItemRenderer pre-increments, so the counter starts one below the
91
+ // first rendered number.
92
+ context.listItemNumber = startNumber - 1;
48
93
 
49
94
  [context setBlockStyle:_isOrdered ? BlockTypeOrderedList : BlockTypeUnorderedList
50
95
  font:_config.listStyleFont
51
96
  color:_config.listStyleColor
52
97
  headingLevel:0];
53
98
 
54
- @try {
55
- [_rendererFactory renderChildrenOfNode:node into:output context:context];
56
- } @finally {
57
- context.listDepth = prevDepth;
58
- context.listType = prevType;
59
- context.listItemNumber = prevNum;
60
-
61
- if (prevDepth == 0) {
62
- [context clearBlockStyle];
99
+ [_rendererFactory renderChildrenOfNode:node into:output context:context];
63
100
 
64
- // Apply bottom margin for root-level list
65
- applyBlockSpacingAfter(output, _config.listStyleMarginBottom);
66
- }
101
+ if (prevDepth == 0) {
102
+ applyListItemSpacing(output, context, startLocation, [_config listStyleItemSpacing]);
103
+ // Apply bottom margin for root-level list
104
+ applyBlockSpacingAfter(output, _config.listStyleMarginBottom);
67
105
  }
68
106
  }
69
107
 
70
- @end
108
+ @end
@@ -2,5 +2,5 @@
2
2
  #import "MarkdownASTNode.h"
3
3
  #import "RenderContext.h"
4
4
 
5
- @interface ParagraphRenderer : BaseRenderer <NodeRenderer>
5
+ @interface ParagraphRenderer : BaseRenderer
6
6
  @end
@@ -7,8 +7,22 @@
7
7
 
8
8
  @implementation ParagraphRenderer
9
9
 
10
- - (void)renderNode:(MarkdownASTNode *)node into:(NSMutableAttributedString *)output context:(RenderContext *)context
10
+ - (id)takeContextSnapshot:(RenderContext *)context
11
11
  {
12
+ return [context snapshotScope];
13
+ }
14
+
15
+ - (void)renderNodeContent:(MarkdownASTNode *)node
16
+ into:(NSMutableAttributedString *)output
17
+ context:(RenderContext *)context
18
+ {
19
+ // Synthetic wrapper around tight list item inlines (see wrapListItemInlineRuns
20
+ // in MD4CParser) — render transparently, the list owns spacing and layout.
21
+ if ([node.attributes[@"tight"] boolValue]) {
22
+ [_rendererFactory renderChildrenOfNode:node into:output context:context];
23
+ return;
24
+ }
25
+
12
26
  // Only set block style if a parent element (e.g. List, Blockquote) hasn't already established one
13
27
  BOOL isTopLevel = (context.currentBlockType == BlockTypeNone);
14
28
 
@@ -33,13 +47,7 @@
33
47
  start += offset;
34
48
  }
35
49
 
36
- @try {
37
- [_rendererFactory renderChildrenOfNode:node into:output context:context];
38
- } @finally {
39
- if (isTopLevel) {
40
- [context clearBlockStyle];
41
- }
42
- }
50
+ [_rendererFactory renderChildrenOfNode:node into:output context:context];
43
51
 
44
52
  if (output.length <= start)
45
53
  return;
@@ -41,6 +41,7 @@ typedef NS_ENUM(NSInteger, ListType) { ListTypeUnordered, ListTypeOrdered };
41
41
  @property (nonatomic, assign) NSInteger listDepth;
42
42
  @property (nonatomic, assign) ListType listType;
43
43
  @property (nonatomic, assign) NSInteger listItemNumber;
44
+ @property (nonatomic, assign) CGFloat accumulatedIndent;
44
45
  @property (nonatomic, assign) BOOL allowFontScaling;
45
46
  @property (nonatomic, assign) CGFloat maxFontSizeMultiplier;
46
47
  @property (nonatomic, assign) NSInteger taskItemCount;
@@ -79,6 +80,15 @@ typedef NS_ENUM(NSInteger, ListType) { ListTypeUnordered, ListTypeOrdered };
79
80
  - (NSDictionary *)getTextAttributes;
80
81
  - (void)clearBlockStyle;
81
82
 
83
+ /**
84
+ * Captures/restores the scoped context state: block style, block type, heading level,
85
+ * blockquote/list depths, list type, list item counter and accumulated indent.
86
+ * Accumulators (range registries, taskItemCount) are excluded on purpose — they
87
+ * must survive restores.
88
+ */
89
+ - (id)snapshotScope;
90
+ - (void)restoreScope:(id)snapshot;
91
+
82
92
  /**
83
93
  * Checks if colors should be preserved based on existing attributes.
84
94
  * Returns YES if the text is inside a link or inline code, which means
@@ -6,6 +6,30 @@
6
6
  @implementation BlockStyle
7
7
  @end
8
8
 
9
+ static NSArray<NSString *> *ENRMScopedKeyPaths(void)
10
+ {
11
+ static NSArray<NSString *> *keyPaths;
12
+ static dispatch_once_t onceToken;
13
+ dispatch_once(&onceToken, ^{
14
+ keyPaths = @[
15
+ @"currentBlockType",
16
+ @"currentHeadingLevel",
17
+ @"currentBlockStyle.fontSize",
18
+ @"currentBlockStyle.fontFamily",
19
+ @"currentBlockStyle.fontWeight",
20
+ @"currentBlockStyle.color",
21
+ @"currentBlockStyle.cachedFont",
22
+ @"currentBlockStyle.cachedTextAttributes",
23
+ @"blockquoteDepth",
24
+ @"listDepth",
25
+ @"listType",
26
+ @"listItemNumber",
27
+ @"accumulatedIndent",
28
+ ];
29
+ });
30
+ return keyPaths;
31
+ }
32
+
9
33
  @implementation RenderContext {
10
34
  NSMutableDictionary<NSString *, UIFont *> *_fontCache;
11
35
  NSParagraphStyle *_baseSpacerTemplate;
@@ -235,6 +259,25 @@
235
259
  _currentBlockStyle.cachedTextAttributes = nil;
236
260
  }
237
261
 
262
+ - (id)snapshotScope
263
+ {
264
+ NSArray<NSString *> *keyPaths = ENRMScopedKeyPaths();
265
+ NSMutableDictionary *snapshot = [NSMutableDictionary dictionaryWithCapacity:keyPaths.count];
266
+ for (NSString *keyPath in keyPaths) {
267
+ snapshot[keyPath] = [self valueForKeyPath:keyPath] ?: [NSNull null];
268
+ }
269
+ return snapshot;
270
+ }
271
+
272
+ - (void)restoreScope:(id)snapshot
273
+ {
274
+ NSDictionary *frame = snapshot;
275
+ for (NSString *keyPath in ENRMScopedKeyPaths()) {
276
+ id value = frame[keyPath];
277
+ [self setValue:(value == [NSNull null] ? nil : value) forKeyPath:keyPath];
278
+ }
279
+ }
280
+
238
281
  #pragma mark - Reset
239
282
 
240
283
  - (void)reset
@@ -256,6 +299,7 @@
256
299
  _listDepth = 0;
257
300
  _listType = ListTypeUnordered;
258
301
  _listItemNumber = 0;
302
+ _accumulatedIndent = 0;
259
303
  _taskItemCount = 0;
260
304
 
261
305
  // Revert shared style object to baseline defaults
@@ -112,6 +112,14 @@
112
112
  #if ENRICHED_MARKDOWN_MATH
113
113
  case MarkdownNodeTypeLatexMathInline:
114
114
  return [[ENRMMathInlineRenderer alloc] initWithRendererFactory:self config:_config];
115
+ case MarkdownNodeTypeLatexMathDisplay:
116
+ // Display math INSIDE a paragraph (mid-paragraph / softbreak-adjacent
117
+ // `$$…$$`) previously fell through to the nil-renderer child dump —
118
+ // the body leaked as plain text with its delimiters silently dropped.
119
+ // Typeset it as an inline attachment instead; block-level display math
120
+ // is unaffected (SegmentRenderer intercepts root-level display nodes
121
+ // before this factory is consulted).
122
+ return [[ENRMMathInlineRenderer alloc] initWithRendererFactory:self config:_config];
115
123
  #endif
116
124
  case MarkdownNodeTypeSpoiler:
117
125
  return [[ENRMSpoilerRenderer alloc] initWithRendererFactory:self config:_config];
@@ -135,6 +143,12 @@
135
143
  [output appendAttributedString:lineBreak];
136
144
  continue;
137
145
  }
146
+ if (child.type == MarkdownNodeTypeSoftBreak) {
147
+ NSAttributedString *softBreak = [[NSAttributedString alloc] initWithString:@" "
148
+ attributes:[context getTextAttributes]];
149
+ [output appendAttributedString:softBreak];
150
+ continue;
151
+ }
138
152
  id<NodeRenderer> renderer = [self rendererForNodeType:child.type];
139
153
  if (renderer) {
140
154
  [renderer renderNode:child into:output context:context];
@@ -1,5 +1,5 @@
1
1
  #pragma once
2
2
  #import "BaseRenderer.h"
3
3
 
4
- @interface StrikethroughRenderer : BaseRenderer <NodeRenderer>
4
+ @interface StrikethroughRenderer : BaseRenderer
5
5
  @end
@@ -8,7 +8,9 @@
8
8
 
9
9
  #pragma mark - Rendering
10
10
 
11
- - (void)renderNode:(MarkdownASTNode *)node into:(NSMutableAttributedString *)output context:(RenderContext *)context
11
+ - (void)renderNodeContent:(MarkdownASTNode *)node
12
+ into:(NSMutableAttributedString *)output
13
+ context:(RenderContext *)context
12
14
  {
13
15
  NSUInteger start = output.length;
14
16
  [_rendererFactory renderChildrenOfNode:node into:output context:context];
@@ -1,5 +1,5 @@
1
1
  #pragma once
2
2
  #import "BaseRenderer.h"
3
3
 
4
- @interface StrongRenderer : BaseRenderer <NodeRenderer>
4
+ @interface StrongRenderer : BaseRenderer
5
5
  @end
@@ -10,7 +10,9 @@
10
10
 
11
11
  #pragma mark - Rendering
12
12
 
13
- - (void)renderNode:(MarkdownASTNode *)node into:(NSMutableAttributedString *)output context:(RenderContext *)context
13
+ - (void)renderNodeContent:(MarkdownASTNode *)node
14
+ into:(NSMutableAttributedString *)output
15
+ context:(RenderContext *)context
14
16
  {
15
17
  NSUInteger start = output.length;
16
18
  [_rendererFactory renderChildrenOfNode:node into:output context:context];
@@ -1,5 +1,5 @@
1
1
  #pragma once
2
2
  #import "BaseRenderer.h"
3
3
 
4
- @interface SubscriptRenderer : BaseRenderer <NodeRenderer>
4
+ @interface SubscriptRenderer : BaseRenderer
5
5
  @end
@@ -7,7 +7,9 @@
7
7
 
8
8
  @implementation SubscriptRenderer
9
9
 
10
- - (void)renderNode:(MarkdownASTNode *)node into:(NSMutableAttributedString *)output context:(RenderContext *)context
10
+ - (void)renderNodeContent:(MarkdownASTNode *)node
11
+ into:(NSMutableAttributedString *)output
12
+ context:(RenderContext *)context
11
13
  {
12
14
  NSUInteger start = output.length;
13
15
  [_rendererFactory renderChildrenOfNode:node into:output context:context];
@@ -1,5 +1,5 @@
1
1
  #pragma once
2
2
  #import "BaseRenderer.h"
3
3
 
4
- @interface SuperscriptRenderer : BaseRenderer <NodeRenderer>
4
+ @interface SuperscriptRenderer : BaseRenderer
5
5
  @end
@@ -7,7 +7,9 @@
7
7
 
8
8
  @implementation SuperscriptRenderer
9
9
 
10
- - (void)renderNode:(MarkdownASTNode *)node into:(NSMutableAttributedString *)output context:(RenderContext *)context
10
+ - (void)renderNodeContent:(MarkdownASTNode *)node
11
+ into:(NSMutableAttributedString *)output
12
+ context:(RenderContext *)context
11
13
  {
12
14
  NSUInteger start = output.length;
13
15
  [_rendererFactory renderChildrenOfNode:node into:output context:context];
@@ -1,6 +1,6 @@
1
+ #import "BaseRenderer.h"
1
2
  #import "MarkdownASTNode.h"
2
- #import "NodeRenderer.h"
3
3
  #import "RenderContext.h"
4
4
 
5
- @interface TextRenderer : NSObject <NodeRenderer>
5
+ @interface TextRenderer : BaseRenderer
6
6
  @end
@@ -3,7 +3,9 @@
3
3
 
4
4
  @implementation TextRenderer
5
5
 
6
- - (void)renderNode:(MarkdownASTNode *)node into:(NSMutableAttributedString *)output context:(RenderContext *)context
6
+ - (void)renderNodeContent:(MarkdownASTNode *)node
7
+ into:(NSMutableAttributedString *)output
8
+ context:(RenderContext *)context
7
9
  {
8
10
  if (!node.content)
9
11
  return;
@@ -1,4 +1,4 @@
1
1
  #import "BaseRenderer.h"
2
2
 
3
- @interface ThematicBreakRenderer : BaseRenderer <NodeRenderer>
3
+ @interface ThematicBreakRenderer : BaseRenderer
4
4
  @end
@@ -7,7 +7,9 @@
7
7
 
8
8
  @implementation ThematicBreakRenderer
9
9
 
10
- - (void)renderNode:(MarkdownASTNode *)node into:(NSMutableAttributedString *)output context:(RenderContext *)context
10
+ - (void)renderNodeContent:(MarkdownASTNode *)node
11
+ into:(NSMutableAttributedString *)output
12
+ context:(RenderContext *)context
11
13
  {
12
14
  [self ensureStartingNewline:output];
13
15
 
@@ -1,4 +1,4 @@
1
1
  #import "BaseRenderer.h"
2
2
 
3
- @interface UnderlineRenderer : BaseRenderer <NodeRenderer>
3
+ @interface UnderlineRenderer : BaseRenderer
4
4
  @end
@@ -8,7 +8,9 @@
8
8
 
9
9
  #pragma mark - Rendering
10
10
 
11
- - (void)renderNode:(MarkdownASTNode *)node into:(NSMutableAttributedString *)output context:(RenderContext *)context
11
+ - (void)renderNodeContent:(MarkdownASTNode *)node
12
+ into:(NSMutableAttributedString *)output
13
+ context:(RenderContext *)context
12
14
  {
13
15
  NSUInteger start = output.length;
14
16
  [_rendererFactory renderChildrenOfNode:node into:output context:context];