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
@@ -77,6 +77,51 @@ Callback when a task list checkbox is tapped. Receives `index` (0-based), `check
77
77
  | ----------------------------------------------- | ------------- | -------- |
78
78
  | `(event: TaskListItemPressEvent) => void` | - | Both |
79
79
 
80
+ ### `enableTaskListItemToggle`
81
+
82
+ Controls whether tapping a task list checkbox toggles its checked state.
83
+
84
+ When `false`, the checkbox renders its markdown state read-only and the tap is **fully inert** — there is no visual toggle and `onTaskListItemPress` does not fire. Text selection and links in the same row are unaffected.
85
+
86
+ | Type | Default Value | Platform |
87
+ | --------- | ------------- | ----------------- |
88
+ | `boolean` | `true` | Both, Web |
89
+
90
+ **Example:**
91
+
92
+ ```tsx
93
+ // Render checkboxes that reflect the markdown but cannot be toggled by the user
94
+ <EnrichedMarkdownText
95
+ markdown={content}
96
+ flavor="github"
97
+ enableTaskListItemToggle={false}
98
+ />
99
+ ```
100
+
101
+ > **Note:** On web the checkbox keeps its normal appearance and is marked `readOnly` / `aria-disabled` rather than `disabled`, so it stays visually consistent with iOS and Android. It is also made pointer-inert (`pointer-events: none`), so the browser paints no hover or active state on a checkbox that cannot be toggled.
102
+
103
+ ### `onCopyPress`
104
+
105
+ Callback when code is copied from a fenced code block, via the header copy button, the long-press context-menu **Copy** action, or the VoiceOver copy action. Receives `code` (the copied code) and `language` (the fence language, or `""` if none). Does not fire for **Copy as Markdown**.
106
+
107
+ Only fires when `flavor="github"` — the copy button is part of the GitHub flavor's code block renderer.
108
+
109
+ | Type | Default Value | Platform |
110
+ | ------------------------------------- | ------------- | ---------------- |
111
+ | `(event: CopyPressEvent) => void` | - | Both, macOS |
112
+
113
+ **Example:**
114
+
115
+ ```tsx
116
+ <EnrichedMarkdownText
117
+ flavor="github"
118
+ markdown={"```ts\nconst x = 1;\n```"}
119
+ onCopyPress={({ code, language }) => {
120
+ console.log(`Copied ${language} code:`, code);
121
+ }}
122
+ />
123
+ ```
124
+
80
125
  ### `enableLinkPreview`
81
126
 
82
127
  Controls the native link preview on long press (iOS only). Automatically set to `false` when `onLinkLongPress` is provided.
@@ -105,6 +150,37 @@ Whether text can be selected.
105
150
  | --------- | ------------- | -------- |
106
151
  | `boolean` | `true` | Both |
107
152
 
153
+ ### `contextMenuHidden`
154
+
155
+ Hides the text selection context menu. Text stays selectable — only the menu is
156
+ suppressed. This is deliberately different from `selectable={false}`, which
157
+ disables selection altogether and, on Android, also removes the text from the
158
+ TalkBack focus order.
159
+
160
+ | Type | Default Value | Platform |
161
+ | --------- | ------------- | ----------- |
162
+ | `boolean` | `false` | Both, macOS |
163
+
164
+ ```tsx
165
+ // Text can still be selected, but long-press shows no menu
166
+ <EnrichedMarkdownText markdown={content} contextMenuHidden />
167
+ ```
168
+
169
+ Notes:
170
+
171
+ - It hides the **whole** menu. The custom items from `contextMenuItems` and the
172
+ built-in items from `selectionMenuConfig` share that same menu, so they are
173
+ hidden too. To drop individual items instead, use `selectionMenuConfig`.
174
+ - It also covers the separate copy menus on table, code and math blocks (which
175
+ appear with `flavor="github"`), not just the text selection menu. The copy
176
+ button in a code block's header is a visible control, not a menu, and stays.
177
+ - It does **not** suppress the system "Save to Camera Roll / Copy" sheet that
178
+ UIKit shows when long-pressing an image — that sheet is owned by UIKit.
179
+ - On macOS the menu opens on click-with-selection rather than long-press; the
180
+ prop suppresses it the same way.
181
+ - Applies to `EnrichedMarkdownText` only — it does not affect
182
+ `EnrichedMarkdownTextInput`.
183
+
108
184
  ### `selectionColor`
109
185
 
110
186
  Color of the text selection highlight. On iOS, this also affects the caret and selection handle colors (they share a single tint). On macOS, only the selection background is affected. On Android, use `selectionHandleColor` to override the handle color independently.
@@ -127,7 +203,7 @@ Configuration for md4c parser extension flags.
127
203
 
128
204
  | Type | Default Value | Platform |
129
205
  | ------------- | ------------------------ | -------- |
130
- | `Md4cFlags` | `{ underline: false, superscript: false, subscript: false, highlight: false, latexMath: true }` | Both |
206
+ | `Md4cFlags` | `{ underline: false, superscript: false, subscript: false, highlight: false, latexMath: true, hardSoftBreaks: false }` | Both |
131
207
 
132
208
  **Properties:**
133
209
 
@@ -136,6 +212,7 @@ Configuration for md4c parser extension flags.
136
212
  - **`subscript`**: When `true`, parses `~text~` as subscript. When disabled, single and double tildes remain strikethrough markers. Visual appearance can be tuned with the `subscript` style prop — see [Subscript-specific](./STYLES.md#subscript-specific).
137
213
  - **`highlight`**: When `true`, parses `==text==` as highlighted spans. When disabled, double equals signs are treated as plain text. Visual appearance can be tuned with the `highlight` style prop — see [Highlight-specific](./STYLES.md#highlight-specific).
138
214
  - **`latexMath`**: When `true`, parses `$...$` and `$$...$$` as LaTeX math spans.
215
+ - **`hardSoftBreaks`**: When `true`, treats single newlines (soft breaks) as hard breaks, rendering them as visible line breaks instead of collapsing them to spaces. Useful when displaying content authored in `EnrichedMarkdownTextInput`, where pressing Enter produces a single newline. See [Line Breaks](./ELEMENTS_STRUCTURE.md#line-breaks) for details.
139
216
 
140
217
  **Example:**
141
218
 
@@ -150,6 +227,12 @@ Configuration for md4c parser extension flags.
150
227
  markdown="This is _underlined_ and *italic* text"
151
228
  md4cFlags={{ underline: true }}
152
229
  />
230
+
231
+ // Preserve single newlines as visible line breaks
232
+ <EnrichedMarkdownText
233
+ markdown={markdownFromInput}
234
+ md4cFlags={{ hardSoftBreaks: true }}
235
+ />
153
236
  ```
154
237
 
155
238
  ### `allowFontScaling`
@@ -233,7 +316,7 @@ Code blocks are always rendered left-to-right regardless of this prop. Per-parag
233
316
 
234
317
  ### `flavor`
235
318
 
236
- Markdown flavor. Set to `'github'` to enable GitHub Flavored Markdown table support.
319
+ Markdown flavor. Set to `'github'` to enable GitHub Flavored Markdown features: tables and block-style code blocks.
237
320
 
238
321
  | Type | Default Value | Platform |
239
322
  | --------------------------------- | --------------- | -------- |
@@ -241,7 +324,9 @@ Markdown flavor. Set to `'github'` to enable GitHub Flavored Markdown table supp
241
324
 
242
325
  > **Note:**
243
326
  > - **`'commonmark'`**: All Markdown content is rendered as a single TextView. Selecting text will select all content in the view.
244
- > - **`'github'`**: The Markdown AST is split into segments. Consecutive text blocks (paragraphs, headings, lists, etc.) are grouped into separate TextView segments, while tables are rendered as separate table views. This allows for granular text selection within each segment and enables interactive table features (horizontal scrolling, context menus). Text selection cannot span across segments.
327
+ > - **`'github'`**: The Markdown AST is split into segments. Consecutive text blocks (paragraphs, headings, lists, etc.) are grouped into separate TextView segments, while tables, fenced code blocks, and math blocks are rendered as separate block views. This allows for granular text selection within each segment and enables interactive block features (horizontal table scrolling, context menus, the code block header). Text selection cannot span across segments.
328
+ >
329
+ > With `'github'`, a fenced code block renders as a dedicated component: a header bar with the language display name (` ```python ` shows "Python") and a copy-code button, a divider, and the code below. Long lines do not wrap — the code pane scrolls horizontally while the header stays fixed. Long-pressing the block opens the Copy / Copy as Markdown menu. With `'commonmark'`, code blocks stay inside the single TextView, styled via spans, and long lines wrap.
245
330
 
246
331
  ### `streamingAnimation`
247
332
 
@@ -253,11 +338,11 @@ When `true`, newly appended content fades in during streaming updates. Only the
253
338
 
254
339
  ### `streamingConfig`
255
340
 
256
- Configuration for streaming behavior. Currently controls how incomplete tables are handled during streaming with `flavor="github"`.
341
+ Configuration for streaming behavior. Controls how incomplete tables and fenced code blocks are handled during streaming with `flavor="github"`.
257
342
 
258
- | Type | Default Value | Platform |
259
- | ----------------------- | ------------------------ | -------- |
260
- | `{ tableMode: string }` | `{ tableMode: 'progressive' }` | Both |
343
+ | Type | Default Value | Platform |
344
+ | ------------------------------------------- | ------------------------------------------------------ | -------- |
345
+ | `{ tableMode?: string, codeBlockMode?: string }` | `{ tableMode: 'progressive', codeBlockMode: 'progressive' }` | Both |
261
346
 
262
347
  #### `tableMode`
263
348
 
@@ -275,6 +360,15 @@ Controls how incomplete (still-streaming) tables are rendered:
275
360
  />
276
361
  ```
277
362
 
363
+ #### `codeBlockMode`
364
+
365
+ Controls how a fenced code block whose closing fence has not arrived yet is rendered:
366
+
367
+ - **`'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 until the closing fence arrives, so it applies once instead of flickering on every token.
368
+ - **`'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).
369
+
370
+ Both modes only take effect when `streamingAnimation` is `true`.
371
+
278
372
  ### `spoilerOverlay`
279
373
 
280
374
  Controls how spoiler text (`||hidden text||`) is displayed before being revealed.
@@ -288,6 +382,29 @@ Controls how spoiler text (`||hidden text||`) is displayed before being revealed
288
382
 
289
383
  Both modes support tap-to-reveal.
290
384
 
385
+ ### `imageRequestHeaders`
386
+
387
+ HTTP headers attached to remote image requests, e.g. a `Referer` required by CDN hotlink protection or an `Authorization` token.
388
+
389
+ | Type | Default Value | Platform |
390
+ | ------------------------ | ------------- | -------- |
391
+ | `Record<string, string>` | - | Both |
392
+
393
+ Headers participate in image cache identity, so the same URL requested with different headers is fetched and cached separately — see [Image Caching](./IMAGE_CACHING.md).
394
+
395
+ > **Web**: Not supported — browsers don't allow custom headers on `<img>` requests.
396
+
397
+ **Example:**
398
+
399
+ ```tsx
400
+ <EnrichedMarkdownText
401
+ markdown={markdown}
402
+ imageRequestHeaders={{
403
+ Referer: 'https://example.com',
404
+ }}
405
+ />
406
+ ```
407
+
291
408
  ### `contextMenuItems`
292
409
 
293
410
  Custom items to add to the text selection context menu. Items appear before the system actions (Copy, etc.). Items with `visible: false` are hidden from the menu.
@@ -352,7 +469,7 @@ Controls built-in actions added to the native text selection menu. Custom app-pr
352
469
  | -------------------- | ---------------------------------------------- | -------- |
353
470
  | `SelectionMenuConfig` | `{}` (see shape below for per-field defaults) | iOS, Android, macOS |
354
471
 
355
- Each item takes an object: `{ enabled }` toggles visibility (the system `copy` item can't be hidden — only relabeled) and `label` overrides the English default. The labels apply to the main text selection menu as well as the table and math block copy menus.
472
+ Each item takes an object: `{ enabled }` toggles visibility and `label` overrides the English default. Items and labels apply to the main text selection menu as well as the table, math and code block copy menus. `copy.enabled`, `copy.format` and `systemItems` are ignored on macOS.
356
473
 
357
474
  > **Deprecation:** the previous boolean shape (`copyAsMarkdown: false`) is still accepted at runtime for backward compatibility but logs a one-time warning. It will be removed in 0.8 — migrate to `{ enabled: false }`.
358
475
 
@@ -360,9 +477,13 @@ Each item takes an object: `{ enabled }` toggles visibility (the system `copy` i
360
477
 
361
478
  ```ts
362
479
  interface SelectionMenuConfig {
363
- /** System "Copy" item — can't be hidden, only relabeled. @default { label: "Copy" } */
364
- copy?: { label?: string };
365
- /** "Copy as Markdown" action. @default { enabled: true, label: "Copy as Markdown" } */
480
+ /**
481
+ * "Copy" item. `format: 'markdown'` copies Markdown as plain text instead of
482
+ * rich text (text selections) or the raw content (blocks).
483
+ * @default { enabled: true, label: "Copy", format: "rich" }
484
+ */
485
+ copy?: { enabled?: boolean; label?: string; format?: 'rich' | 'markdown' };
486
+ /** "Copy as Markdown" action, in the text and block menus. @default { enabled: true, label: "Copy as Markdown" } */
366
487
  copyAsMarkdown?: { enabled?: boolean; label?: string };
367
488
  /** "Copy Image URL" action, shown when the selection contains images. */
368
489
  copyImageUrl?: {
@@ -372,6 +493,10 @@ interface SelectionMenuConfig {
372
493
  /** Forms for multiple images, chosen with Intl.PluralRules. @default { other: "Copy {count} Image URLs" } */
373
494
  pluralLabels?: SelectionMenuPluralLabels;
374
495
  };
496
+ /** `'none'` drops every system item (Select All, Look Up, Share, Translate…). @default 'default' */
497
+ systemItems?: 'default' | 'none';
498
+ /** Copy button in the code block header. @default { enabled: true } */
499
+ codeBlockCopyButton?: { enabled?: boolean };
375
500
  }
376
501
 
377
502
  interface SelectionMenuPluralLabels {
@@ -532,6 +657,18 @@ Auto-capitalization behavior.
532
657
  | -------- | -------------- | -------- |
533
658
  | `string` | `'sentences'` | Both |
534
659
 
660
+ ### `interceptPaste`
661
+
662
+ Reports pastes through [`onPaste`](#onpaste) instead of inserting them. Only takes effect when `onPaste` is also set — otherwise native would swallow every paste with nobody left to resolve it, so the library keeps the prop off.
663
+
664
+ See [Intercepting paste](./INPUT.md#intercepting-paste).
665
+
666
+ | Type | Default Value | Platform |
667
+ | --------- | ------------- | ------------- |
668
+ | `boolean` | `false` | iOS, Android |
669
+
670
+ macOS ignores this prop and always pastes inline.
671
+
535
672
  ### `multiline`
536
673
 
537
674
  Whether the input supports multiple lines.
@@ -574,6 +711,8 @@ Style configuration for formatted text in the input.
574
711
  - `linkVariants` — per-URL-pattern style overrides. Each key is a regex tested against the link URL. See [Mentions — Link Variants](MENTIONS.md#link-variants-mention-styling).
575
712
  - `spoiler.color` — text color for spoiler text.
576
713
  - `spoiler.backgroundColor` — background color for spoiler text.
714
+ - `h1`–`h6` — per-level heading styling, each accepting `fontSize`, `fontWeight`, and `color`. Defaults match the read-only renderer (sizes `30/24/20/18/16/14`, bold).
715
+ - `list.itemSpacing` — vertical spacing (points) added above each list item (bullet and numbered alike) so items read as separate rows; defaults to `0`. iOS applies it via `paragraphSpacingBefore`; Android via a `LineHeightSpan`.
577
716
 
578
717
  ### `mentionIndicators`
579
718
 
@@ -601,6 +740,15 @@ Fires when the plain text content changes. Returns the text without Markdown syn
601
740
  | ------------------------------- | ------------- | -------- |
602
741
  | `(text: string) => void` | - | Both |
603
742
 
743
+ > [!NOTE]
744
+ > A LaTeX formula appears in this string as a single `U+FFFC` (object replacement
745
+ > character), not as its source. That keeps the string index-compatible with
746
+ > [`onChangeSelection`](#onchangeselection), [`onCaretRectChange`](#oncaretrectchange)
747
+ > and the `insertMath` / `updateMath` / `removeMath` methods, which all address the
748
+ > buffer by offset and count a formula as one character. Use
749
+ > [`onChangeMarkdown`](#onchangemarkdown) when you need the `$...$` source.
750
+ > See [LaTeX math](LATEX_MATH.md).
751
+
604
752
  ### `onChangeMarkdown`
605
753
 
606
754
  Fires when the Markdown representation changes. Returns the full Markdown string. Only active when the callback is provided — omitting it skips the serialization for better performance.
@@ -619,7 +767,7 @@ Fires when the text selection changes.
619
767
 
620
768
  ### `onChangeState`
621
769
 
622
- Fires when the active style state changes. The payload provides a nested object for each style with an `isActive` property.
770
+ Fires when the active style state changes. The payload provides a nested object for each style with an `isActive` property; `heading` additionally carries the cursor paragraph's `level` (`0` when it is not a heading) and `unorderedList` / `orderedList` their 0-based nesting `depth`.
623
771
 
624
772
  | Type | Default Value | Platform |
625
773
  | --------------------------------- | ------------- | -------- |
@@ -635,9 +783,35 @@ interface StyleState {
635
783
  strikethrough: { isActive: boolean };
636
784
  spoiler: { isActive: boolean };
637
785
  link: { isActive: boolean };
786
+ // Heading level of the cursor's paragraph: 0 = none, 1-6 = H1-H6.
787
+ heading: { isActive: boolean; level: number };
788
+ // `depth` is the 0-based nesting level while `isActive` is true, and is
789
+ // always `0` when `isActive` is false (i.e. the cursor is not in a list).
790
+ // This differs from `heading.level`, where `0` is itself a meaningful value
791
+ // (no heading); read `depth` only when `isActive` is true.
792
+ unorderedList: { isActive: boolean; depth: number };
793
+ orderedList: { isActive: boolean; depth: number };
638
794
  }
639
795
  ```
640
796
 
797
+ ### `onKeyPress`
798
+
799
+ Fires on every keystroke, before the change is applied to the input content — mirroring React Native TextInput's `onKeyPress`. `nativeEvent.key` is the pressed character, or a named key: `Backspace`, `Enter`, `Tab` (iOS additionally reports `Escape`). On Android the key reported for soft keyboard input may lag actual typing when autocomplete suggestions are involved. Paste operations do not fire the event.
800
+
801
+ | Type | Default Value | Platform |
802
+ | ------------------------------------------------------------- | ------------- | -------- |
803
+ | `(e: NativeSyntheticEvent<{ key: string }>) => void` | - | Both |
804
+
805
+ **Example:**
806
+
807
+ ```tsx
808
+ <EnrichedMarkdownTextInput
809
+ onKeyPress={({ nativeEvent: { key } }) => {
810
+ console.log('Pressed key:', key);
811
+ }}
812
+ />
813
+ ```
814
+
641
815
  ### `onCaretRectChange`
642
816
 
643
817
  Fires when the caret's pixel position changes (typing, selection change, content reflow). The rect is relative to the input's top-left corner, in density-independent pixels. The native side diffs the rect before emitting, so redundant events are suppressed.
@@ -686,6 +860,8 @@ Fires when the input loses focus.
686
860
  | -------------- | ------------- | -------- |
687
861
  | `() => void` | - | Both |
688
862
 
863
+ The input participates in React Native's text-input focus tracking (`TextInput.State`), so blur also happens through the platform's standard keyboard-dismiss paths: taps outside the input inside a `ScrollView` (per its `keyboardShouldPersistTaps` setting) and `Keyboard.dismiss()`. See [Keyboard Dismissal](INPUT.md#keyboard-dismissal).
864
+
689
865
  ### `onStartMention`
690
866
 
691
867
  Fires when a new mention flow starts. See [Mentions](MENTIONS.md#events).
@@ -710,6 +886,18 @@ Fires when the active mention flow ends.
710
886
  | ---- | ------------- | -------- |
711
887
  | `(event: { indicator: string }) => void` | - | Both |
712
888
 
889
+ ### `onPaste`
890
+
891
+ Fires instead of the insert when [`interceptPaste`](#interceptpaste) is on. Native reads the clipboard and leaves the buffer untouched, so the handler owns the paste from that point: it must call [`resolvePaste`](#resolvepastetext-string-markdown-string) exactly once, on every path including failures, or the paste is silently dropped.
892
+
893
+ | Type | Default Value | Platform |
894
+ | ---- | ------------- | -------- |
895
+ | `(event: { text: string; markdown: string }) => void` | - | iOS, Android |
896
+
897
+ `markdown` is non-empty only on iOS, when the copy source was an `EnrichedMarkdownTextInput`. Android always reports `''` and `resolvePaste` there inserts `text` verbatim.
898
+
899
+ See [Intercepting paste](./INPUT.md#intercepting-paste).
900
+
713
901
  ### `writingDirection`
714
902
 
715
903
  Paragraph writing direction in the input. iOS only — Android's `EditText` already resolves direction per paragraph via `TEXT_DIRECTION_FIRST_STRONG` and is unaffected by this prop.
@@ -924,6 +1112,26 @@ Toggles strikethrough on the current selection or cursor.
924
1112
 
925
1113
  Toggles spoiler on the current selection or cursor.
926
1114
 
1115
+ ### `toggleHeading(level: number)`
1116
+
1117
+ Toggles a heading of the given level (`1`–`6`) on the cursor's paragraph. Calling it with the level already applied turns the paragraph back into regular text. Unlike the inline `toggle*` methods, this operates on the whole paragraph, not a character range.
1118
+
1119
+ ### `toggleUnorderedList()`
1120
+
1121
+ Turns the cursor's paragraph(s) into bullet list items, or back into regular paragraphs if they already are. Operates on the whole paragraph. List items are single-line — each item is exactly one paragraph, and Markdown imported with multi-paragraph (loose) items keeps only each item's first line as a list item.
1122
+
1123
+ ### `toggleOrderedList()`
1124
+
1125
+ Turns the cursor's paragraph(s) into numbered list items, or back into regular paragraphs if they already are. Numbering derives from an item's position among its adjacent same-depth siblings. Toggling one list type on a line carrying the other replaces it, keeping the item's nesting depth.
1126
+
1127
+ ### `indentList()`
1128
+
1129
+ Nests the current list item one level deeper (up to a maximum depth). Called on a non-list paragraph, it starts a bullet list at depth 0. Equivalent to pressing **Tab** with a hardware keyboard.
1130
+
1131
+ ### `outdentList()`
1132
+
1133
+ Lifts the current list item out one nesting level. Outdenting a depth-0 item removes the bullet, turning it back into a regular paragraph. Equivalent to **Shift+Tab**.
1134
+
927
1135
  ### `setLink(url: string)`
928
1136
 
929
1137
  Applies a link URL to the currently selected text.
@@ -936,12 +1144,26 @@ Inserts a link with the given text and URL at the current cursor position. Usefu
936
1144
 
937
1145
  Removes the link from the current selection.
938
1146
 
1147
+ ### `insertText(text: string)`
1148
+
1149
+ Parses the given string as Markdown and inserts it literally at the current cursor position, replacing the selection if there is one. Leading and trailing newlines are preserved, so wrap block content (lists, headings) in newlines to keep it on its own lines when inserting mid-paragraph — `insertText('\n- item\n')` in the middle of `test` yields `te`, a `- item` bullet, and `st` on separate lines. Calling it with an empty string is a no-op.
1150
+
939
1151
  ### `copyToClipboard()`
940
1152
 
941
1153
  Copies the input's full content to the system clipboard, matching the result of selecting all text and pressing the context menu's copy action. The selection is left unchanged, and calling it on an empty input is a no-op.
942
1154
 
943
1155
  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.
944
1156
 
1157
+ ### `resolvePaste(text: string, markdown?: string)`
1158
+
1159
+ Completes a paste reported through [`onPaste`](#onpaste). Call it exactly once per event:
1160
+
1161
+ - `resolvePaste(text, markdown)` — inserts, restoring the copied formatting when `markdown` is non-empty.
1162
+ - `resolvePaste(text)` — inserts `text` verbatim.
1163
+ - `resolvePaste('', '')` — drops the clipboard content, replacing the current selection. With an empty selection this is a no-op that still emits `onChangeText` with unchanged content.
1164
+
1165
+ Anything that replaces a selection replaces it here too, so a paste over selected text behaves the same on every branch.
1166
+
945
1167
  ### `startMention(indicator: string)`
946
1168
 
947
1169
  Programmatically triggers a mention flow by inserting the indicator character at the current cursor position. The indicator must be listed in the `mentionIndicators` prop. Useful for toolbar buttons.
@@ -0,0 +1,129 @@
1
+ # Breaking changes
2
+
3
+ This file tracks breaking changes and how to migrate for each. Entries are newest first. Deprecations
4
+ (things that still work but are slated for removal) are noted alongside the change that introduces them.
5
+
6
+ ## Unreleased
7
+
8
+ ### `EnrichedMarkdownTextInput` math style keys renamed to match the renderer
9
+
10
+ The editor's `markdownStyle` used `math` for the **inline** chip and `mathBlock` for the **block**
11
+ chip — the exact opposite of `EnrichedMarkdownText`, where `math` is the block style and `inlineMath`
12
+ the inline one. The same key name meant two different things depending on which component you were
13
+ styling. The editor now follows the renderer.
14
+
15
+ **Migrate:**
16
+
17
+ | Before (input) | After (input) | Renderer equivalent |
18
+ |---|---|---|
19
+ | `markdownStyle.math` | `markdownStyle.inlineMath` | `markdownStyle.inlineMath` |
20
+ | `markdownStyle.mathBlock` | `markdownStyle.math` | `markdownStyle.math` |
21
+ | `markdownStyle.mathBlock.alignment` | `markdownStyle.math.textAlign` | `markdownStyle.math.textAlign` |
22
+
23
+ ```diff
24
+ <EnrichedMarkdownTextInput
25
+ markdownStyle={{
26
+ - math: { color: '#0F172A', backgroundColor: '#EEF2FF' },
27
+ - mathBlock: { fontSize: 22, alignment: 'center' },
28
+ + inlineMath: { color: '#0F172A', backgroundColor: '#EEF2FF' },
29
+ + math: { fontSize: 22, textAlign: 'center' },
30
+ }}
31
+ />
32
+ ```
33
+
34
+ `markdownStyle.math` additionally accepts `padding` as a shorthand for both axes, matching the
35
+ renderer's `math.padding`; `paddingHorizontal` / `paddingVertical` still override it per axis.
36
+
37
+ The accompanying types are exported for the first time under names that say which surface they belong
38
+ to: `InputInlineMathStyle` and `InputMathStyle` (the renderer's own math style types stay internal to
39
+ `MarkdownStyle`).
40
+
41
+
42
+ ## v1.0.2
43
+
44
+ ### The Expo config plugin was removed
45
+
46
+ The built-in Expo config plugin (`app.plugin.js` and the `plugin/` folder) has been removed. Feature
47
+ configuration now lives entirely in your app's `package.json`, read directly by the native build and by
48
+ `postinstall` — the same approach `react-native-worklets` uses for its static feature flags.
49
+
50
+ Why: the plugin only wrote the (now deprecated) Podfile `ENV` / `gradle.properties` channels, it could
51
+ never influence the install-time asset download (it runs during `expo prebuild`, _after_ `npm install`),
52
+ and its option shape diverged from the `package.json` block. The `package.json` block supersedes it for
53
+ both the download and the build, and it survives `expo prebuild`.
54
+
55
+ **Migrate:** remove the plugin entry from `app.json` / `app.config.js` and move the options into the
56
+ `enriched-markdown` block of your `package.json`.
57
+
58
+ Before (`app.json`):
59
+
60
+ ```json
61
+ {
62
+ "expo": {
63
+ "plugins": [
64
+ [
65
+ "react-native-enriched-markdown-scaffold",
66
+ {
67
+ "enableMath": false,
68
+ "codeHighlight": {
69
+ "enabled": true,
70
+ "languages": ["javascript", "tsx"]
71
+ }
72
+ }
73
+ ]
74
+ ]
75
+ }
76
+ }
77
+ ```
78
+
79
+ After (`package.json`):
80
+
81
+ ```json
82
+ {
83
+ "enriched-markdown": {
84
+ "enableMath": false,
85
+ "enableCodeHighlight": true,
86
+ "codeHighlightLanguages": ["javascript", "tsx"]
87
+ }
88
+ }
89
+ ```
90
+
91
+ Note the key renames: the plugin's `codeHighlight.enabled` / `codeHighlight.languages` become
92
+ `enableCodeHighlight` / `codeHighlightLanguages`. Then run `pod install` (iOS) or rebuild (Android).
93
+ These are compile/link-time settings, so they apply only in builds you compile yourself (a custom dev
94
+ client or `expo prebuild`) — they cannot be changed in Expo Go, which ships a fixed prebuilt binary.
95
+
96
+ The `@expo/config-plugins` peer dependency was dropped as part of this removal.
97
+
98
+ ### Feature config moved to `package.json`; ENV vars and gradle properties are deprecated
99
+
100
+ The `enriched-markdown` block in your app's `package.json` is now the single source of truth for
101
+ `enableMath`, `enableCodeHighlight`, and `codeHighlightLanguages` on both platforms — the native build
102
+ reads it directly at `pod install` / Gradle configuration time. The previous build flags still work as a
103
+ fallback but are deprecated, print a warning, and are ignored when the matching `package.json` key is set:
104
+
105
+ | Deprecated flag | Replaced by (`package.json` `enriched-markdown`) |
106
+ | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
107
+ | Podfile `ENV['ENRICHED_MARKDOWN_ENABLE_MATH']` / gradle `enrichedMarkdown.enableMath` | `enableMath` |
108
+ | Podfile `ENV['ENRICHED_MARKDOWN_ENABLE_CODE_HIGHLIGHT']` / gradle `enrichedMarkdown.enableCodeHighlight` | `enableCodeHighlight` |
109
+ | Podfile `ENV['ENRICHED_MARKDOWN_CODE_HIGHLIGHT_LANGUAGES']` / gradle `enrichedMarkdown.codeHighlightLanguages` | `codeHighlightLanguages` |
110
+
111
+ In a monorepo the _build_ flag is read from the app's `package.json` (the one beside `ios/`/`android/`),
112
+ so each app configures independently. The _download_ opt-out is read where the install runs — usually the
113
+ workspace root — so put it in the root `package.json` to skip a download for the whole repo. See
114
+ [Native assets](./NATIVE_ASSETS.md).
115
+
116
+ ### Explicitly enabling a feature whose assets are missing now fails the build
117
+
118
+ Previously, a missing native asset (the RaTeX XCFramework, or the tree-sitter grammars) always silently
119
+ disabled the feature. Now, if you **explicitly** set `enableMath: true` or `enableCodeHighlight: true` but
120
+ the asset was not downloaded (for example an install with `--ignore-scripts`, or a monorepo root opt-out
121
+ that an app overrides), the build fails with an actionable error instead of degrading. Features left on by
122
+ default still degrade to a clean build. To fix, restore the assets:
123
+
124
+ ```sh
125
+ node node_modules/react-native-enriched-markdown-scaffold/postinstall.mjs
126
+ # or: npm rebuild react-native-enriched-markdown-scaffold
127
+ ```
128
+
129
+ then re-run `pod install` (iOS) / rebuild (Android).
@@ -0,0 +1,133 @@
1
+ # Code-block syntax highlighting
2
+
3
+ Fenced code blocks are syntax-highlighted natively via [tree-sitter](https://tree-sitter.github.io/).
4
+ Highlighting is **foreground-only** (it recolors tokens and never changes text metrics), so a code
5
+ block's measured height always matches its drawn height. It is enabled by default on iOS and Android
6
+ with a curated set of languages, and can be trimmed or disabled to reduce binary size.
7
+
8
+ ## Usage
9
+
10
+ Highlighting activates automatically for a fenced block whose info string names a supported language:
11
+
12
+ ````tsx
13
+ <EnrichedMarkdownText
14
+ flavor="github"
15
+ markdown={String.raw`
16
+ \`\`\`python
17
+ def greet(name: str) -> str:
18
+ return f"Hello, {name}!" # a comment
19
+ \`\`\`
20
+ `}
21
+ markdownStyle={{
22
+ codeBlock: {
23
+ syntaxColors: {
24
+ keyword: '#C678DD',
25
+ string: '#98C379',
26
+ number: '#D19A66',
27
+ comment: '#7F848E',
28
+ function: '#61AFEF',
29
+ type: '#E5C07B',
30
+ // ...any of the 14 token types
31
+ },
32
+ },
33
+ }}
34
+ />
35
+ ````
36
+
37
+ Token colors are set through `codeBlock.syntaxColors`. The 14 token types are: `keyword`,
38
+ `operator`, `punctuation`, `string`, `number`, `constant`, `comment`, `function`, `type`,
39
+ `variable`, `property`, `tag`, `attribute`, `embedded`. Any type left unset is drawn in the normal
40
+ code color.
41
+
42
+ ## Copy button
43
+
44
+ With `flavor="github"`, each code block's header shows a copy button (and a long-press context
45
+ menu with **Copy** / **Copy as Markdown**). The CommonMark flavor renders code blocks inline with
46
+ no header, so it has no copy button. To observe when a user copies code, pass
47
+ [`onCopyPress`](./API_REFERENCE.md#oncopypress) — it fires with the copied `code` and its
48
+ `language` for the header button, the context-menu **Copy** action, and the VoiceOver copy action.
49
+ The copy label shown to assistive technologies is configurable via
50
+ [`selectionMenuConfig`](./COPY_OPTIONS.md).
51
+
52
+ ## Supported languages
53
+
54
+ Fence info strings map to a grammar (for example `js` and `jsx` both select JavaScript). The **curated default
55
+ set** is compiled in unless you override it. It is defined by `default:true` in
56
+ `vendor/grammar-versions.json` (the single source of truth the iOS podspec and Android build both
57
+ derive from), so the table below tracks that manifest:
58
+
59
+ | Default (on) | Opt-in (heavier) |
60
+ |---|---|
61
+ | json, html, css, markdown, yaml, go, java, javascript, python, c, rust, bash, typescript, tsx | cpp, swift, php, ruby, c-sharp |
62
+
63
+ The default set is the smaller-footprint tier (~32 MB of grammar C source across the whole set).
64
+ The opt-in grammars are larger (17-29 MB each) and are only compiled when you list them explicitly.
65
+ A block whose language is not compiled in simply renders as plain (uncolored) code.
66
+
67
+ ## Choosing languages / reducing binary size
68
+
69
+ Only the grammars you compile end up in your binary, so trimming the list is the main size lever.
70
+ The seam degrades to plain code whenever a grammar is absent, so nothing breaks when you remove one.
71
+
72
+ Configure everything through the `enriched-markdown` block of your app's `package.json` — it is the
73
+ single source of truth for both platforms and both the install-time download and the build:
74
+
75
+ ```json
76
+ {
77
+ "enriched-markdown": {
78
+ "enableCodeHighlight": true,
79
+ "codeHighlightLanguages": ["javascript", "tsx", "json", "bash"]
80
+ }
81
+ }
82
+ ```
83
+
84
+ How the two keys interact:
85
+
86
+ - **`enableCodeHighlight`** (default `true`) is the master switch. When `false`, the grammar download is
87
+ skipped **and** the tree-sitter runtime is excluded from the native build. In that state
88
+ **`codeHighlightLanguages` is ignored — it is a no-op**, because there is no highlighter compiled in for
89
+ languages to feed.
90
+ - **`codeHighlightLanguages`** selects which grammars to compile *when highlighting is enabled*. Omit it
91
+ for the curated default set, or pass a subset to shrink the binary. An empty array (`[]`) compiles no
92
+ grammars, which disables highlighting entirely — equivalent to `enableCodeHighlight: false`.
93
+
94
+ Re-run `pod install` (iOS) / rebuild (Android) after changing these. The same block works with Expo —
95
+ `node_modules` survives `npx expo prebuild`, so no config plugin is needed (highlighting is compiled in,
96
+ so it can't be changed in **Expo Go**; use a dev client or `expo prebuild`). See
97
+ [Skipping the download](./NATIVE_ASSETS.md#skipping-the-download-opt-out).
98
+
99
+ > [!NOTE]
100
+ > **Deprecated:** the `ENV['ENRICHED_MARKDOWN_*']` Podfile variables and the `enrichedMarkdown.*` gradle
101
+ > properties still work as a fallback but are deprecated and print a warning; they are ignored when the
102
+ > corresponding `package.json` key is set. The Expo config plugin was removed — see
103
+ > [Breaking changes](./BREAKING_CHANGES.md). Prefer the `package.json` block above.
104
+
105
+ ## How it works
106
+
107
+ Grammars are **vendored** into `packages/core/cpp/highlight/vendor/` (only each grammar's
108
+ `parser.c`/`scanner.c` + `highlights.scm`, never whole npm packages), so the native build itself is
109
+ fully offline and deterministic. The stable tree-sitter runtime is vendored the same way and compiled
110
+ with WebAssembly support left out. A build-time codegen emits a registry for exactly the selected
111
+ languages, so the binary and link step only ever reference compiled grammars.
112
+
113
+ The entire `vendor/` tree is **gitignored** to keep the repo and PRs small — nothing generated lives
114
+ in git. `vendor/vendor-grammars.mjs` restores all of it from the pins in `vendor/grammar-versions.json`:
115
+ the tree-sitter runtime (`vendor/tree-sitter/`) is fetched and sha256-verified from the pinned GitHub
116
+ release tarball, the ~178 MB of grammar `parser.c` tables (`vendor/grammars/`) are copied from the
117
+ pinned grammar devDependencies, and the default registry (`vendor/generated/`) is codegen'd from them.
118
+ It is wired into the package `prepare` script (so a plain `yarn install` restores everything, with
119
+ `.stamp` guards making repeats a no-op).
120
+
121
+ The published npm tarball ships only the small default registry, **not** the heavy grammar/runtime
122
+ source — that would bloat every install to ~230 MB. Instead a `postinstall` script downloads the
123
+ grammar sources (from the npm registry) and the tree-sitter runtime (from the pinned GitHub release)
124
+ into the installed package, sha256-verified and idempotent. See [Native assets](./NATIVE_ASSETS.md)
125
+ for the install-time behavior, network requirements, and how to recover an offline/pnpm install.
126
+
127
+ Highlighting runs synchronously when a code block is applied and is cached per block, with a size cap
128
+ (~50 KB / ~2000 lines) that falls back to plain rendering for pathological inputs. Maintainers re-pin
129
+ by editing `vendor/grammar-versions.json` (for a runtime bump, also update `runtime.sha256` — a full
130
+ `node vendor/vendor-grammars.mjs --force` run prints the correct digest on mismatch) and re-running
131
+ the script; there is nothing generated to commit. To vendor the runtime from a local tree-sitter
132
+ checkout instead of the network, pass `--runtime-src <path to tree-sitter/lib>` (or set
133
+ `TREE_SITTER_SRC`).