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
@@ -1,6 +1,6 @@
1
1
  # Copy Options
2
2
 
3
- When text is selected, `react-native-enriched-markdown` provides enhanced copy functionality through the context menu on both platforms.
3
+ When text is selected, `react-native-enriched-markdown-scaffold` provides enhanced copy functionality through the context menu on both platforms.
4
4
 
5
5
  ## Smart Copy
6
6
 
@@ -44,6 +44,19 @@ Use `selectionMenuConfig` to hide built-in selection menu actions while keeping
44
44
  />
45
45
  ```
46
46
 
47
+ To turn the menu off entirely rather than item by item, use `contextMenuHidden`:
48
+
49
+ ```tsx
50
+ // No selection menu at all — text is still selectable
51
+ <EnrichedMarkdownText markdown={content} contextMenuHidden />
52
+ ```
53
+
54
+ The two are complementary: `selectionMenuConfig` prunes individual built-in
55
+ items and leaves the menu in place, while `contextMenuHidden` suppresses the
56
+ menu as a whole — including `contextMenuItems` and the copy menus on table,
57
+ code and math blocks. Note that `contextMenuHidden` applies to `EnrichedMarkdownText`
58
+ only; it does not affect `EnrichedMarkdownTextInput`.
59
+
47
60
  `EnrichedMarkdownTextInput` supports the same `{ enabled, label }` shape. In addition to `copyAsMarkdown`, the input's `selectionMenuConfig` exposes the built-in **Format** submenu, and `formatMenuConfig` controls the items inside it:
48
61
 
49
62
  ```tsx
@@ -93,8 +106,13 @@ Notes:
93
106
  plural category (`zero`, `one`, `two`, `few`, `many`, `other`). Only `other` is
94
107
  required; any category left `undefined` falls back to it. The `{count}` token
95
108
  is replaced by the number of selected images.
96
- - The labels apply to the main text selection menu as well as the table and math
97
- block copy menus.
109
+ - The labels apply to the main text selection menu as well as the table, math,
110
+ and code block copy menus. With `flavor="github"`, the code block header's copy
111
+ button also reuses the copy label for assistive technologies (the CommonMark
112
+ flavor renders code inline with no header button): it is the button's
113
+ contentDescription on Android, and on iOS it names the VoiceOver custom
114
+ action that triggers the copy. To be notified when code is copied from a code
115
+ block, use the [`onCopyPress`](./API_REFERENCE.md#oncopypress) callback.
98
116
  - OS-provided actions (Look Up, Translate…) and the system **Cut / Paste /
99
117
  Select All** items are localized by the platform and are not affected by this
100
118
  config.
@@ -1,10 +1,10 @@
1
1
  # Element Structure
2
2
 
3
- Markdown elements in `react-native-enriched-markdown` are organized into block and inline categories, each with distinct rendering behaviors.
3
+ Markdown elements in `react-native-enriched-markdown-scaffold` are organized into block and inline categories, each with distinct rendering behaviors.
4
4
 
5
5
  ## Supported Markdown Elements
6
6
 
7
- `react-native-enriched-markdown` supports a comprehensive set of Markdown elements:
7
+ `react-native-enriched-markdown-scaffold` supports a comprehensive set of Markdown elements:
8
8
 
9
9
  ### Block Elements
10
10
 
@@ -13,7 +13,7 @@ Markdown elements in `react-native-enriched-markdown` are organized into block a
13
13
  | Headings | `# H1` to `###### H6` | `h1` - `h6` | Six levels of headings |
14
14
  | Paragraphs | Plain text | `paragraph` | Default text container |
15
15
  | Blockquotes | `> Quote` | `blockquote` | Quoted content with accent bar, unlimited nesting |
16
- | Code Blocks | ` ``` code ``` ` | `codeBlock` | Multi-line code containers |
16
+ | Code Blocks | ` ``` code ``` ` | `codeBlock` | Multi-line code containers; with `flavor="github"` rendered as a block component with a language header and copy-code button |
17
17
  | Unordered Lists | `- Item`, `* Item`, or `+ Item` | `list` | Bullet lists with unlimited nesting |
18
18
  | Ordered Lists | `1. Item` | `list` | Numbered lists with unlimited nesting |
19
19
  | Task Lists | `- [x] Done`, `- [ ] Todo` | `taskList` | Interactive checkboxes (requires `flavor="github"`) |
@@ -60,6 +60,22 @@ Markdown elements in `react-native-enriched-markdown` are organized into block a
60
60
  2. Second item
61
61
  ```
62
62
 
63
+ ### Lists with Block Content Example
64
+
65
+ List items can contain block elements — fenced code blocks, nested lists, and multiple paragraphs:
66
+
67
+ ````markdown
68
+ 1. Install via npm:
69
+
70
+ ```
71
+ npm install
72
+ ```
73
+
74
+ 2. Verify the connection.
75
+ ````
76
+
77
+ Code blocks indent to the item's content column, and the marker is drawn next to the first line even when a code block or nested list is the item's first child.
78
+
63
79
  ### Nested Blockquotes Example
64
80
 
65
81
  ```markdown
@@ -94,6 +110,38 @@ Block elements are structural containers that define the layout and establish th
94
110
 
95
111
  Inline elements modify text within blocks and apply additional styling on top of the block's typography.
96
112
 
113
+ ## Line Breaks
114
+
115
+ Newlines follow standard CommonMark semantics by default:
116
+
117
+ - **Blank line**: Starts a new paragraph.
118
+ - **Single newline (soft break)**: Renders as a space — consecutive lines flow together into one wrapped paragraph, matching how GitHub and other CommonMark renderers display Markdown.
119
+ - **Hard break**: Ends a line with two spaces or a backslash to force a line break within the paragraph.
120
+
121
+ ```markdown
122
+ This line and
123
+ this line render as one continuous sentence.
124
+
125
+ A blank line starts a new paragraph.
126
+
127
+ Two trailing spaces
128
+ or a trailing backslash\
129
+ force a line break within the paragraph.
130
+ ```
131
+
132
+ ### Preserving single newlines
133
+
134
+ When displaying content authored in `EnrichedMarkdownTextInput`, pressing Enter produces a single newline in the serialized markdown. By default, `EnrichedMarkdownText` collapses these to spaces (per CommonMark). To preserve them as visible line breaks, enable the `hardSoftBreaks` flag:
135
+
136
+ ```tsx
137
+ <EnrichedMarkdownText
138
+ markdown={markdownFromInput}
139
+ md4cFlags={{ hardSoftBreaks: true }}
140
+ />
141
+ ```
142
+
143
+ This forces the parser to treat every soft break as a hard break, so single newlines render as line breaks on all platforms.
144
+
97
145
  ## Images: Block vs Inline
98
146
 
99
147
  Images are automatically detected as block or inline based on context:
@@ -101,7 +149,7 @@ Images are automatically detected as block or inline based on context:
101
149
  - **Block images**: When an image is the only content in a paragraph (standalone), it's treated as a block image and uses block-level spacing
102
150
  - **Inline images**: When an image appears alongside other text content, it's treated as inline and aligns with the text baseline
103
151
 
104
- You don't need to specify which type—the renderer automatically determines this based on the image's position in the content.
152
+ You don't need to specify which type—the renderer automatically determines this based on the image's position in the content. Note that a single newline doesn't split a paragraph, so an image on its own source line directly below text is still inline; separate it with a blank line to make it a block image.
105
153
 
106
154
  ## Nested Elements
107
155
 
@@ -2,6 +2,30 @@
2
2
 
3
3
  Images in Markdown content are loaded, cached, and reused automatically — no configuration required.
4
4
 
5
+ ## Supported Image Sources
6
+
7
+ Markdown image URLs are strings, so bundled assets must be resolved to a URI before being interpolated into the markdown:
8
+
9
+ ```tsx
10
+ import { Image } from 'react-native';
11
+
12
+ const logoUri = Image.resolveAssetSource(require('./assets/logo.png')).uri;
13
+ const markdown = `![Logo](${logoUri})`;
14
+ ```
15
+
16
+ This works in every environment: in dev the URI is a Metro dev-server URL, while in a release build it resolves to a drawable resource name on Android and a bundle `file://` URL on iOS — all of which are supported. URIs from `expo-asset` (`asset.uri` / `asset.localUri`) work the same way.
17
+
18
+ | Source | Android | iOS / macOS |
19
+ |---|---|---|
20
+ | `http://`, `https://` | Yes | Yes |
21
+ | `file://` (including percent-encoded paths) | Yes | Yes |
22
+ | Bare asset name (release builds, expo-asset `localUri`) | Yes (drawable/raw resource) | Yes (bundle resource) |
23
+ | `file:///android_res/…`, `file:///android_asset/…` | Yes | No |
24
+ | `asset://`, `res://`, `content://` | Yes | No |
25
+ | `data:` (base64) | Yes | Yes |
26
+
27
+ Local sources skip the HTTP layers below (disk cache, request headers, deduplication) but still use both memory cache tiers.
28
+
5
29
  ## Cache Layers
6
30
 
7
31
  The library uses a three-tier caching strategy on both platforms:
@@ -16,6 +40,12 @@ The library uses a three-tier caching strategy on both platforms:
16
40
  - **Processed cache** stores scaled and clipped variants keyed by URL + dimensions + border radius, so repeated layouts with the same geometry skip all image processing.
17
41
  - **Disk cache** persists raw HTTP responses across app launches, respecting standard HTTP cache headers.
18
42
 
43
+ ## Request Headers
44
+
45
+ When `imageRequestHeaders` is set, the headers become part of the cache identity for both memory tiers and for request deduplication: the same URL requested with different headers is fetched and cached separately, and changing the prop re-fetches the images.
46
+
47
+ One caveat: the disk cache is managed by the HTTP stack (OkHttp / `NSURLCache`) and keys responses by URL alone. A response fetched with one set of headers can be served from disk for a request with different headers, subject to standard HTTP caching semantics (`Cache-Control`, `Vary`).
48
+
19
49
  ## Request Deduplication
20
50
 
21
51
  When multiple components request the same image URL simultaneously (e.g. during a re-render), only one network request is made. All pending callbacks are coalesced and dispatched together once the download completes.
package/docs/INPUT.md CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  EnrichedMarkdownTextInput,
14
14
  type EnrichedMarkdownTextInputInstance,
15
15
  type StyleState,
16
- } from 'react-native-enriched-markdown';
16
+ } from 'react-native-enriched-markdown-scaffold';
17
17
 
18
18
  export default function App() {
19
19
  const ref = useRef<EnrichedMarkdownTextInputInstance>(null);
@@ -66,6 +66,48 @@ Each call toggles the style within the current text selection. They are being to
66
66
 
67
67
  Styles are also available through the built-in native format bar that appears on text selection, and through the system context menu.
68
68
 
69
+ ## Headings
70
+
71
+ Supported heading levels: H1–H6.
72
+
73
+ Headings are block-level: a heading applies to the whole paragraph the cursor (or selection) touches, unlike [inline styles](#inline-styles) which apply to a character range. Toggle a heading by calling `toggleHeading(level)` on the component ref with a level from `1` to `6`:
74
+
75
+ ```tsx
76
+ <Button title="H1" onPress={() => ref.current?.toggleHeading(1)} />
77
+ ```
78
+
79
+ Calling `toggleHeading` with the level already applied to the cursor's paragraph turns the heading back into a regular paragraph. The cursor's current heading level is reported through the [`onChangeState`](API_REFERENCE.md#onchangestate) payload as `heading: { isActive, level }` (`level` is `0` when the paragraph is not a heading), so you can highlight the active level in your toolbar.
80
+
81
+ Behavior notes:
82
+
83
+ - An emptied heading line stays a heading until you toggle it off, so characters you type next continue at the heading size.
84
+ - Pressing Enter at the end of a heading starts a regular paragraph on the next line (headings do not continue like list items).
85
+
86
+ Heading font sizes, weights, and colors are configurable per level — see [Customizing Styles](#customizing-enrichedmarkdowntextinput--styles).
87
+
88
+ ## Lists
89
+
90
+ `EnrichedMarkdownTextInput` supports nested unordered (bullet) and ordered (numbered) lists, serialized to Markdown as `- ` / `1. ` with three spaces of indentation per nesting level. Ordered items are numbered by their position among adjacent same-depth siblings, so numbering stays correct as items are added, removed, or reordered. Like headings, list items are block-level — they apply to whole paragraphs. Manage them through the component ref:
91
+
92
+ - [`toggleUnorderedList()`](API_REFERENCE.md#toggleunorderedlist) — turns the cursor's paragraph(s) into bullet items, or back into regular paragraphs if they already are.
93
+ - [`toggleOrderedList()`](API_REFERENCE.md#toggleorderedlist) — same for numbered items; toggling one list type on the other replaces it.
94
+ - [`indentList()`](API_REFERENCE.md#indentlist) — nests the current item one level deeper. On a non-list paragraph it starts a bullet list.
95
+ - [`outdentList()`](API_REFERENCE.md#outdentlist) — lifts the current item out one level. Outdenting a top-level (depth 0) item removes the bullet.
96
+
97
+ On a hardware keyboard, **Tab** and **Shift+Tab** indent and outdent the current item.
98
+
99
+ Behavior notes:
100
+
101
+ - **Return continues the list** — pressing Return inside an item starts a new bullet at the same depth on the next line. Pressing Return on an empty item exits the list (the line becomes a regular paragraph).
102
+ - **Backspace at the start of an item** outdents it; at depth 0 it removes the bullet.
103
+ - An emptied list line stays a list item (its bullet keeps showing) until you toggle it off or Backspace out of it, so text you type next continues in the list.
104
+ - The bullet marker exists only in the serialized Markdown and the rendered glyph — it is never part of the editor's text, so it won't collide with `-`-prefixed text such as mentions.
105
+ - **List items are single-line.** Each item is exactly one paragraph. Importing or pasting Markdown with *loose* list items (an item containing multiple paragraphs) keeps only the item's first line as a list item — continuation paragraphs become regular paragraphs, not list-styled blocks.
106
+
107
+ Whether the cursor's paragraph is a list item, and its nesting depth, are reported through the [`onChangeState`](API_REFERENCE.md#onchangestate) payload as `unorderedList` / `orderedList` (`{ isActive, depth }`), so you can highlight the list buttons in your toolbar.
108
+
109
+ Use [`markdownStyle.list.itemSpacing`](API_REFERENCE.md#markdownstyle) to add vertical spacing between list items (bullet and numbered alike) so they read as separate rows.
110
+
69
111
  ## Links
70
112
 
71
113
  Links are a piece of text with a URL attributed to it. They can be managed by calling methods on the input ref:
@@ -122,6 +164,52 @@ The callback fires only for newly detected links — not for links that were alr
122
164
 
123
165
  When a manual link is applied (via `setLink` or `insertLink`) over an auto-detected link, the auto-detected link is replaced by the manual one. Auto-link detection skips ranges that already contain a manual link.
124
166
 
167
+ ## Preserving block syntax
168
+
169
+ By default the input interprets block-level Markdown: a line starting with `1) `, `- `,
170
+ `# ` or `> ` is consumed as list, heading or quote *structure*, and the marker itself is
171
+ not part of the text. Headings and lists are written back on save, but in the editor's
172
+ own form rather than the source's: `1) ` comes back as `1. ` and `* ` as `- `. Other block
173
+ syntax — blockquotes, code blocks, tables, thematic breaks, setext headings — is not
174
+ modeled by the editor and is not guaranteed to survive: depending on the platform its
175
+ marker is either dropped or left in the text.
176
+
177
+ Set `blockSyntax={false}` when the text must survive the round trip unchanged:
178
+
179
+ ```tsx
180
+ <EnrichedMarkdownTextInput
181
+ blockSyntax={false}
182
+ defaultValue={markdown}
183
+ onChangeMarkdown={setMarkdown}
184
+ />
185
+ ```
186
+
187
+ In this mode the parser never sees block structure, so markers stay in the text verbatim
188
+ and `onChangeMarkdown` returns what was loaded, byte for byte. Inline syntax is unaffected:
189
+ `**bold**`, `*italic*`, `~~strike~~`, `||spoiler||`, links and `$math$` all still parse and
190
+ style as usual.
191
+
192
+ What changes:
193
+
194
+ - **Loaded or pasted markers stay text**: `3) ` or `# ` coming in through `defaultValue`,
195
+ `setValue` or a paste is not turned into a list or heading. Blocks applied explicitly
196
+ through the toolbar commands still work, and are written back with their markers.
197
+ - The text is displayed with its markers showing, so an editor with `blockSyntax={false}`
198
+ and a `EnrichedMarkdownText` rendering the same source look different, even though the
199
+ stored string is identical.
200
+ - `\r\n` and `\r` are normalized to `\n`, and `U+000B` (vertical tab) is stripped from the
201
+ input. `U+000B` is used internally to hide line structure from the Markdown parser, so it
202
+ cannot be carried through as content.
203
+
204
+ Three inline constructs are still lossy in this mode, exactly as they are with
205
+ `blockSyntax={true}` — they are not regressions introduced by the flag:
206
+
207
+ | Input | Saved as | Why |
208
+ | --- | --- | --- |
209
+ | `` gõ `x` vào `` | `gõ x vào` | The editor has no inline code style, so the backticks have nothing to round-trip through |
210
+ | `Giá 5\$` | `Giá 5$` | The serializer does not re-escape `\$`, which can leave an unpaired `$` |
211
+ | `A &amp;amp; B` | `A B` | HTML entity nodes are dropped. A raw `&` is safe |
212
+
125
213
  ## Caret Position Tracking
126
214
 
127
215
  `EnrichedMarkdownTextInput` can report the caret's pixel position relative to the input, which is useful when the input is embedded in a scrollable container with `scrollEnabled={false}` and you need to keep the caret visible.
@@ -161,6 +249,45 @@ The input's content can be copied to the system clipboard from a ref, without re
161
249
 
162
250
  On iOS and macOS the clipboard receives both plain text and a private Markdown pasteboard type, so pasting back into an `EnrichedMarkdownTextInput` restores the formatting; external apps receive plain text only. On Android the clipboard receives plain text only — inline styles are not preserved for any paste target.
163
251
 
252
+ ## Intercepting paste
253
+
254
+ By default a paste goes straight into the buffer. Set [`interceptPaste`](API_REFERENCE.md#interceptpaste) together with [`onPaste`](API_REFERENCE.md#onpaste) to decide what a paste means before any text lands — turning a long paste into an attachment chip, stripping it, or inserting it unchanged.
255
+
256
+ ```tsx
257
+ const inputRef = useRef<EnrichedMarkdownTextInputInstance>(null);
258
+
259
+ <EnrichedMarkdownTextInput
260
+ ref={inputRef}
261
+ interceptPaste
262
+ onPaste={({ text, markdown }) => {
263
+ if (text.length > 2000) {
264
+ attachAsFile(text);
265
+ inputRef.current?.resolvePaste('', ''); // drops it, and replaces the selection
266
+ return;
267
+ }
268
+ inputRef.current?.resolvePaste(text, markdown);
269
+ }}
270
+ />
271
+ ```
272
+
273
+ Native reads the clipboard and **does not touch the buffer**. That makes the handler the only thing that can complete the paste, so the contract is strict:
274
+
275
+ - Call [`resolvePaste`](API_REFERENCE.md#resolvepastetext-string-markdown-string) **exactly once per event, on every path including failures**. A handler that throws before resolving leaves the paste dropped — the user sees nothing happen.
276
+ - Pass `markdown` back through when inserting. It is the copied formatting; dropping it turns a copy-then-paste inside your app into flat text.
277
+ - `interceptPaste` is ignored unless `onPaste` is set, so switching the prop on alone cannot make the input swallow pastes.
278
+
279
+ Because nothing is written until you resolve, an async decision is safe: the selection is still there, and the user sees an unchanged input rather than text that vanished.
280
+
281
+ ### Platform behavior
282
+
283
+ | | Behavior |
284
+ | --- | --- |
285
+ | **iOS** | Context menu and hardware ⌘V. `markdown` is set when the copy source was an `EnrichedMarkdownTextInput`. |
286
+ | **Android** | Context menu, hardware Ctrl+V and `KEYCODE_PASTE`. `markdown` is always `''`, and `resolvePaste` inserts `text` verbatim — so an intercepted copy-then-paste inside the app lands as plain text, even though the un-intercepted paste restores the formatting. |
287
+ | **macOS** | `interceptPaste` is ignored, `onPaste` never fires, and pastes insert inline as usual. |
288
+
289
+ Only clipboard content is intercepted. Drag-and-drop, autofill and IME content insertion bypass `onPaste` on both platforms and insert normally — on Android they are filtered out explicitly, so an autofill never arrives looking like a paste.
290
+
164
291
  ## Style Detection
165
292
 
166
293
  All of the above styles can be detected with the use of [onChangeState](API_REFERENCE.md#onchangestate) callback payload.
@@ -176,6 +303,17 @@ You can find some examples in the [usage section](#usage) or in the example app.
176
303
  - [onChangeText](API_REFERENCE.md#onchangetext) - returns the input's plain text (without Markdown syntax) anytime it changes.
177
304
  - [onChangeMarkdown](API_REFERENCE.md#onchangemarkdown) - returns the Markdown string parsed from current input text and styles anytime it would change. As parsing the Markdown on each input change can be expensive, not assigning the event's callback will skip the serialization for better performance.
178
305
  - [onChangeSelection](API_REFERENCE.md#onchangeselection) - returns `{ start, end }` of the current selection, useful for working with [links](#links).
306
+ - [onKeyPress](API_REFERENCE.md#onkeypress) - returns `{ nativeEvent: { key } }` for every keystroke before it is applied to the content, mirroring React Native TextInput's `onKeyPress`.
307
+
308
+ ## Keyboard Dismissal
309
+
310
+ `EnrichedMarkdownTextInput` registers with React Native's text-input focus tracking (`TextInput.State`), so scroll containers treat it exactly like the built-in `TextInput`. No props on the input are involved — the behavior is controlled by the surrounding `ScrollView` / `FlatList`:
311
+
312
+ - With the soft keyboard open, tapping outside the focused input blurs it and dismisses the keyboard, following the scroll container's [`keyboardShouldPersistTaps`](https://reactnative.dev/docs/scrollview#keyboardshouldpersisttaps) setting. In the default `'never'` mode the dismissing tap is consumed (the classic first-tap-dismisses, second-tap-presses behavior); `'handled'` dismisses only on taps no child handles; `'always'` never auto-dismisses.
313
+ - Scrolling does not dismiss the keyboard unless the container sets [`keyboardDismissMode`](https://reactnative.dev/docs/scrollview#keyboarddismissmode).
314
+ - [`Keyboard.dismiss()`](https://reactnative.dev/docs/keyboard#dismiss) blurs the input when it is the focused field.
315
+
316
+ Matching `TextInput`, none of this applies while a hardware keyboard is in use (for example the iOS Simulator with **Connect Hardware Keyboard** enabled): with no soft keyboard on screen there is nothing to dismiss, so outside taps intentionally leave the input focused.
179
317
 
180
318
  ## RTL Support
181
319
 
@@ -205,7 +343,7 @@ No setup is required. Both platforms autodetect direction per paragraph out of t
205
343
 
206
344
  - **Placeholder** follows the host view's layout direction, not the prop. If you need an RTL placeholder, wrap the input in `<View style={{ direction: 'rtl' }}>` or set `I18nManager.forceRTL(true)`.
207
345
  - **Mixed paragraphs while typing** — newly inserted characters in an empty paragraph briefly inherit the previous paragraph's direction; the first-strong pass corrects this on the next input event.
208
- - **Code blocks, tables, blockquotes, lists** are not supported in the input (it's a flat inline-formatting surface). For those, use [`EnrichedMarkdownText`](TEXT.md).
346
+ - **Code blocks, tables, blockquotes** are not supported in the input. Headings and bullet lists are; other block elements require [`EnrichedMarkdownText`](TEXT.md).
209
347
 
210
348
  See [RTL Support](RTL.md) for the full per-element behavior on the rendered output side.
211
349
 
@@ -219,6 +357,7 @@ See [RTL Support](RTL.md) for the full per-element behavior on the rendered outp
219
357
  strong: { color: '#1D4ED8' },
220
358
  em: { color: '#7C3AED' },
221
359
  link: { color: '#2563EB', underline: true },
360
+ h1: { fontSize: 28, fontWeight: 'bold', color: '#111827' },
222
361
  }}
223
362
  />
224
363
  ```
@@ -231,7 +370,9 @@ Available style properties:
231
370
  - `link.underline` — whether links are underlined (defaults to `true`).
232
371
  - `spoiler.color` — text color for spoiler text.
233
372
  - `spoiler.backgroundColor` — background color for spoiler text.
234
- - `math.fontWeight` — `'bold'` | `'normal'` (default `'normal'`); typesets inline formula chips
373
+ - `h1`–`h6` — per-level heading styling, each accepting `fontSize`, `fontWeight`, and `color`. Defaults match the read-only `EnrichedMarkdownText` renderer (sizes `30/24/20/18/16/14`, bold) so headings look the same in the editor and a rendered preview. Omitted levels (or fields) fall back to those defaults.
374
+ - `inlineMath` / `math` — chip styling for inline (`$...$`) and block (`$$...$$`) LaTeX. Same key names and shared field names as the read-only renderer's `markdownStyle`, so one palette drives both. See [LaTeX Math](LATEX_MATH.md#styling-math-in-the-editor).
375
+ - `inlineMath.fontWeight` — `'bold'` | `'normal'` (default `'normal'`); typesets inline formula chips
235
376
  (`$...$`) at bold weight. See [LATEX_MATH.md](./LATEX_MATH.md#bold-formulas).
236
- - `mathBlock.fontWeight` — same for block formula chips (`$$...$$`); inherits from
237
- `math.fontWeight` when unset.
377
+ - `math.fontWeight` — same for block formula chips (`$$...$$`); inherits from
378
+ `inlineMath.fontWeight` when unset.
@@ -47,6 +47,39 @@ what pushes those lines apart. It affects only lines that actually contain inlin
47
47
  the line height they had. Set it to `0` to get the old flush behaviour back. Block math (`$$...$$`) has its own
48
48
  `math.padding` instead.
49
49
 
50
+ ### Styling math in the editor
51
+
52
+ `EnrichedMarkdownTextInput` renders each formula as a chip and takes its style
53
+ under the **same two keys**, with the same meaning: `markdownStyle.inlineMath`
54
+ for `$...$` and `markdownStyle.math` for `$$...$$`.
55
+
56
+ ```tsx
57
+ <EnrichedMarkdownTextInput
58
+ markdownStyle={{
59
+ inlineMath: { color: '#0F172A', backgroundColor: '#EEF2FF' },
60
+ math: { fontSize: 22, padding: 12, textAlign: 'center' },
61
+ }}
62
+ />
63
+ ```
64
+
65
+ Fields shared with the renderer (`color`, `fontSize`, `backgroundColor`,
66
+ `padding`, `marginTop`, `marginBottom`, `textAlign`) mean the same thing on both
67
+ surfaces, so one palette can drive an editor and its preview. The chip adds
68
+ `borderColor`, `borderWidth`, `borderRadius`, `selectedBackgroundColor` and
69
+ `selectedBorderColor`, which the read-only renderer has no counterpart for, and
70
+ it splits `padding` into `paddingHorizontal` / `paddingVertical` — either of
71
+ which overrides the `padding` shorthand for its axis.
72
+
73
+ `math` inherits the chip look (colors, border, selection) from `inlineMath`, so
74
+ setting `inlineMath` alone styles both; `math` then overrides what differs.
75
+
76
+ A formula is **atomic** in the editor: it occupies one character (`U+FFFC`) in the
77
+ buffer, and the LaTeX lives on the chip rather than in the text. That is what makes
78
+ the caret, selection and IME step over a formula in one move — and it is why
79
+ `onChangeText` reports a `U+FFFC` where the formula is, while `onChangeMarkdown`
80
+ reports the `$...$` source. Offsets in `onChangeSelection`, `onCaretRectChange` and
81
+ `updateMath` / `removeMath` count a formula as that one character.
82
+
50
83
  ### Bold formulas
51
84
 
52
85
  `math.fontWeight` / `inlineMath.fontWeight` (`'normal'` | `'bold'`, default `'normal'`) typeset a
@@ -74,15 +107,16 @@ bold face, so the browser synthesizes one there too. Treat web as synthetic as w
74
107
  reference for how heavy bold "should" look.
75
108
 
76
109
  `EnrichedMarkdownTextInput` honours the same prop for the formula chips typed into the editor, under
77
- its own style keys — `math.fontWeight` for inline chips (`$...$`) and `mathBlock.fontWeight` for
78
- block chips (`$$...$$`). `mathBlock` inherits the weight from `math` when it does not set one of its
79
- own, the way it already inherits `color` and the border props:
110
+ the same two keys as the rest of [Styling math in the editor](#styling-math-in-the-editor) —
111
+ `inlineMath.fontWeight` for inline chips (`$...$`) and `math.fontWeight` for block chips
112
+ (`$$...$$`). `math` inherits the weight from `inlineMath` when it does not set one of its own, the
113
+ way it already inherits `color` and the border props:
80
114
 
81
115
  ```tsx
82
116
  <EnrichedMarkdownTextInput
83
117
  markdownStyle={{
84
- math: { fontWeight: 'bold' }, // inline chips bold…
85
- mathBlock: { fontWeight: 'normal' }, // …block chips opt back out
118
+ inlineMath: { fontWeight: 'bold' }, // inline chips bold…
119
+ math: { fontWeight: 'normal' }, // …block chips opt back out
86
120
  }}
87
121
  />
88
122
  ```
@@ -142,57 +176,65 @@ Set `latexMath: false` in `md4cFlags` so the parser treats `$` as plain text:
142
176
 
143
177
  This alone prevents math rendering without any native changes. The steps below go further by removing the native math libraries from your binary entirely.
144
178
 
145
- ### 2. Remove the native iOS dependency
179
+ ### 2. Remove the native dependency
146
180
 
147
- Add the following to your Podfile and re-run `pod install`:
181
+ Set `enableMath` to `false` in the `enriched-markdown` block of your app's `package.json`:
148
182
 
149
- ```ruby
150
- ENV['ENRICHED_MARKDOWN_ENABLE_MATH'] = '0'
183
+ ```json
184
+ {
185
+ "enriched-markdown": {
186
+ "enableMath": false
187
+ }
188
+ }
151
189
  ```
152
190
 
153
- This excludes **RaTeX** from the build. Rebuild the app after running `pod install`.
191
+ This is the single source of truth for both platforms: `postinstall` skips the install-time RaTeX
192
+ download, and the native build reads the same block directly to exclude **RaTeX** from the binary — no
193
+ Podfile or `gradle.properties` edit needed. Re-run `pod install` (iOS) / rebuild (Android) after
194
+ changing it. See [Skipping the download](./NATIVE_ASSETS.md#skipping-the-download-opt-out).
154
195
 
155
196
  > [!NOTE]
156
- > When math is **enabled** (the default), your Podfile must use dynamic frameworks:
157
- > ```ruby
158
- > use_frameworks! :linkage => :dynamic
159
- > ```
160
- > This is required for CocoaPods to resolve the RaTeX Swift Package dependency.
197
+ > **Deprecated:** the `ENV['ENRICHED_MARKDOWN_ENABLE_MATH']` Podfile variable and the
198
+ > `enrichedMarkdown.enableMath` gradle property still work as a fallback but are deprecated and print a
199
+ > warning; they are ignored when the `package.json` block sets `enableMath`.
161
200
 
162
201
  > [!NOTE]
163
- > **macOS**: LaTeX math is currently not supported on macOS because `react-native-macos` does not support `use_frameworks!` ([microsoft/react-native-macos#1969](https://github.com/microsoft/react-native-macos/issues/1969)). Math is automatically disabled in the macOS example app.
164
-
165
- ### 3. Remove the native Android dependency
166
-
167
- Add the following to your project's `gradle.properties`:
168
-
169
- ```properties
170
- enrichedMarkdown.enableMath=false
171
- ```
172
-
173
- This excludes **RaTeX** from the Android build. Rebuild the app after changing this property.
202
+ > When math is **enabled** (the default), no special Podfile configuration is required.
203
+ > RaTeX ships as a prebuilt static XCFramework vendored into the pod, so it links under
204
+ > CocoaPods default static linkage — you do **not** need `use_frameworks!`. (Earlier
205
+ > versions required `use_frameworks! :linkage => :dynamic` to resolve RaTeX as a Swift
206
+ > Package; that is no longer the case.)
174
207
 
175
- ### 4. Expo config plugin
208
+ > [!NOTE]
209
+ > The RaTeX XCFramework is **not** bundled in the npm tarball — it is downloaded at install time by
210
+ > a `postinstall` script (see [Native assets](./NATIVE_ASSETS.md)). If `ios/vendor/RaTeX.xcframework`
211
+ > is missing (offline install, `--ignore-scripts`, pnpm, or a `package.json` opt-out) and math is only
212
+ > on by default, `pod install` auto-disables math and prints a warning instead of failing. If you
213
+ > **explicitly** set `"enableMath": true`, a missing framework is a hard error instead. Either way, run
214
+ > `node node_modules/react-native-enriched-markdown-scaffold/postinstall.mjs` and re-run `pod install` to restore it.
176
215
 
177
- If you are using Expo, you can use the built-in config plugin to disable LaTeX math rendering on both platforms at once.
216
+ > [!IMPORTANT]
217
+ > **Upgrading from a version that used `use_frameworks! :linkage => :dynamic` for math?**
218
+ > The pod changed from a dynamic framework to a static library. After `pod install`,
219
+ > do a one-time clean build (Xcode: Product > Clean Build Folder, or delete the app's
220
+ > DerivedData) — a stale build folder otherwise fails with
221
+ > `ReactNativeEnrichedMarkdown.framework/Modules/module.modulemap not found`. Fresh
222
+ > installs are unaffected.
178
223
 
179
- Add the following to your `app.json` or `app.config.js`:
224
+ > [!NOTE]
225
+ > **macOS**: LaTeX math is not yet enabled on macOS and remains off in the macOS example
226
+ > app. The previous blocker (`use_frameworks!` was required for the RaTeX Swift Package)
227
+ > no longer applies now that RaTeX is a vendored XCFramework with a macOS slice, so macOS
228
+ > support is a possible future follow-up.
180
229
 
181
- ```json
182
- {
183
- "expo": {
184
- "plugins": [
185
- [
186
- "react-native-enriched-markdown",
187
- {
188
- "enableMath": false
189
- }
190
- ]
191
- ]
192
- }
193
- }
194
- ```
230
+ ### 3. Expo
195
231
 
196
- This will automatically apply both the [iOS](#2-remove-the-native-ios-dependency) and [Android](#3-remove-the-native-android-dependency) native changes listed above during `npx expo prebuild`.
232
+ The `package.json` block above works with Expo too — `node_modules` (and the resolved config) survive
233
+ `npx expo prebuild`, so no config plugin is needed. Set `"enriched-markdown": { "enableMath": false }` in
234
+ your app's `package.json` and rebuild.
197
235
 
198
- If you later re-enable math (e.g. remove the plugin or set `enableMath: true`), run `npx expo prebuild --clean` so native projects are regenerated without the disable flags, then rebuild.
236
+ > [!NOTE]
237
+ > Because `enableMath` is a compile/link-time decision, it only applies in builds you compile yourself
238
+ > (a custom dev client or `expo prebuild`). It **cannot** be changed in **Expo Go**, which ships a fixed
239
+ > prebuilt binary. A dedicated config plugin was removed in favor of the `package.json` block — see
240
+ > [Breaking changes](./BREAKING_CHANGES.md).
package/docs/MACOS.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # macOS Support
2
2
 
3
- `react-native-enriched-markdown` supports macOS via [react-native-macos](https://github.com/microsoft/react-native-macos). The native layer shares code with iOS through a platform abstraction header (`ENRMUIKit.h`), with macOS-specific implementations for context menus, text selection, and clipboard handling.
3
+ `react-native-enriched-markdown-scaffold` supports macOS via [react-native-macos](https://github.com/microsoft/react-native-macos). The native layer shares code with iOS through a platform abstraction header (`ENRMUIKit.h`), with macOS-specific implementations for context menus, text selection, and clipboard handling.
4
4
 
5
5
  The macOS implementation supports the same rendering elements as iOS — CommonMark, GitHub Flavored Markdown (tables, task lists, strikethrough), images, code blocks, blockquotes, and all other supported elements. `EnrichedMarkdownTextInput` is also available on macOS with full support for inline styles, links, and the native context menu.
6
6
 
@@ -1,6 +1,6 @@
1
1
  # Markdown Streaming
2
2
 
3
- If you need to render markdown that streams token-by-token from an LLM, check out [react-native-streamdown](https://github.com/software-mansion-labs/react-native-streamdown) — a streaming-ready markdown component built on top of `react-native-enriched-markdown`.
3
+ If you need to render markdown that streams token-by-token from an LLM, check out [react-native-streamdown](https://github.com/software-mansion-labs/react-native-streamdown) — a streaming-ready markdown component built on top of `react-native-enriched-markdown-scaffold`.
4
4
 
5
5
  It combines [remend](https://www.npmjs.com/package/remend) for fixing incomplete markdown on the fly with [react-native-worklets](https://docs.swmansion.com/react-native-worklets/) **Bundle Mode** to run all processing off the JS thread, keeping your UI responsive while tokens arrive.
6
6
 
@@ -34,3 +34,29 @@ The `streamingConfig` prop controls this behavior:
34
34
  | `'progressive'` (default) | Renders the table row-by-row as content arrives. New rows fade in when `streamingAnimation` is enabled. Incomplete trailing rows are automatically trimmed. |
35
35
  | `'hidden'` | The table is completely hidden until it is followed by a blank line, indicating the table is complete. Prevents visual jank from partially formed tables. |
36
36
 
37
+ ## Code Block Streaming (GFM)
38
+
39
+ Fenced code blocks are also block-level elements. While a block's closing fence
40
+ (```` ``` ````) has not arrived, its content is still changing, which would
41
+ otherwise make syntax highlighting flicker on every token.
42
+
43
+ The `codeBlockMode` field of `streamingConfig` controls this:
44
+
45
+ ```tsx
46
+ <EnrichedMarkdownText
47
+ markdown={streamingMarkdown}
48
+ flavor="github"
49
+ streamingAnimation
50
+ streamingConfig={{ codeBlockMode: 'progressive' }}
51
+ />
52
+ ```
53
+
54
+ ### Code Block Modes
55
+
56
+ | Mode | Behavior |
57
+ |---|---|
58
+ | `'progressive'` (default) | The code streams in line-by-line with its header (language label + copy button) visible but non-interactive — copying is disabled until the block completes. Syntax highlighting is deferred so it applies once when the closing fence arrives instead of flickering per token. |
59
+ | `'hidden'` | The entire code block is hidden until its closing fence arrives, then it appears complete (the same all-or-nothing behavior block math uses). |
60
+
61
+ Both modes only take effect when `streamingAnimation` is `true`.
62
+