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
@@ -14,12 +14,15 @@ import com.swmansion.enriched.markdown.input.events.OnContextMenuItemPressEvent
14
14
  import com.swmansion.enriched.markdown.input.events.OnEndMentionEvent
15
15
  import com.swmansion.enriched.markdown.input.events.OnInputBlurEvent
16
16
  import com.swmansion.enriched.markdown.input.events.OnInputFocusEvent
17
+ import com.swmansion.enriched.markdown.input.events.OnInputKeyPressEvent
17
18
  import com.swmansion.enriched.markdown.input.events.OnLinkDetectedEvent
18
19
  import com.swmansion.enriched.markdown.input.events.OnMathPressEvent
20
+ import com.swmansion.enriched.markdown.input.events.OnPasteEvent
19
21
  import com.swmansion.enriched.markdown.input.events.OnRequestCaretRectResultEvent
20
22
  import com.swmansion.enriched.markdown.input.events.OnRequestMarkdownResultEvent
21
23
  import com.swmansion.enriched.markdown.input.events.OnStartMentionEvent
22
24
  import com.swmansion.enriched.markdown.input.formatting.MarkdownSerializer
25
+ import com.swmansion.enriched.markdown.input.model.BlockType
23
26
  import com.swmansion.enriched.markdown.input.model.CaretRect
24
27
  import com.swmansion.enriched.markdown.input.model.StyleType
25
28
 
@@ -27,10 +30,25 @@ class InputEventEmitter(
27
30
  private val view: EnrichedMarkdownTextInputView,
28
31
  ) {
29
32
  private var prevState: Map<StyleType, Boolean> = emptyMap()
33
+ private var prevHeadingLevel: Int = 0
34
+ private var prevUnorderedList: Pair<Boolean, Int> = false to 0
35
+ private var prevOrderedList: Pair<Boolean, Int> = false to 0
30
36
  private var prevCaretRect: CaretRect? = null
31
37
 
32
38
  fun emitChangeText() {
33
- val plainText = view.text?.toString() ?: ""
39
+ // The empty-list-line ZWSP anchor is an internal editing detail — never leak
40
+ // it to JS. Both output paths (plain text here, markdown) funnel through the
41
+ // same MarkdownSerializer.stripZwsp choke point.
42
+ //
43
+ // A math chip's U+FFFC placeholder is deliberately NOT stripped, and expanding it
44
+ // to `$latex$` here would be worse. This string has to stay index-compatible with
45
+ // the buffer: onChangeSelection, onChangeCaretRect and insertMath/updateMath/
46
+ // removeMath all speak buffer offsets, where a chip is exactly one character.
47
+ // Strip or expand it and every offset JS holds points at the wrong place. iOS
48
+ // lands in the same spot for free (an NSTextAttachment *is* U+FFFC in the string),
49
+ // so keeping it is also what makes the two platforms agree. Documented in
50
+ // docs/API_REFERENCE.md under onChangeText.
51
+ val plainText = MarkdownSerializer.stripZwsp(view.text?.toString() ?: "")
34
52
  dispatch(OnChangeTextEvent(surfaceId(), view.id, plainText))
35
53
  }
36
54
 
@@ -51,9 +69,19 @@ class InputEventEmitter(
51
69
  StyleType.entries.associateWith { style ->
52
70
  isStyleEffectivelyActive(style, pos)
53
71
  }
72
+ val headingLevel = view.headingLevelAtCursor()
73
+ val unorderedList = view.listStateAtCursor(BlockType.UNORDERED_LIST_ITEM)
74
+ val orderedList = view.listStateAtCursor(BlockType.ORDERED_LIST_ITEM)
54
75
 
55
- if (current == prevState) return
76
+ if (current == prevState && headingLevel == prevHeadingLevel && unorderedList == prevUnorderedList &&
77
+ orderedList == prevOrderedList
78
+ ) {
79
+ return
80
+ }
56
81
  prevState = current
82
+ prevHeadingLevel = headingLevel
83
+ prevUnorderedList = unorderedList
84
+ prevOrderedList = orderedList
57
85
 
58
86
  dispatch(
59
87
  OnChangeStateEvent(
@@ -65,10 +93,19 @@ class InputEventEmitter(
65
93
  current[StyleType.STRIKETHROUGH] ?: false,
66
94
  current[StyleType.SPOILER] ?: false,
67
95
  current[StyleType.LINK] ?: false,
96
+ headingLevel,
97
+ unorderedList.first,
98
+ unorderedList.second,
99
+ orderedList.first,
100
+ orderedList.second,
68
101
  ),
69
102
  )
70
103
  }
71
104
 
105
+ fun emitKeyPress(key: String) {
106
+ dispatch(OnInputKeyPressEvent(surfaceId(), view.id, key))
107
+ }
108
+
72
109
  fun emitFocus() {
73
110
  dispatch(OnInputFocusEvent(surfaceId(), view.id))
74
111
  }
@@ -99,6 +136,13 @@ class InputEventEmitter(
99
136
  dispatch(OnMathPressEvent(surfaceId(), view.id, latex, start, end, displayMode, x, y, width, height))
100
137
  }
101
138
 
139
+ fun emitPaste(
140
+ text: String,
141
+ markdown: String,
142
+ ) {
143
+ dispatch(OnPasteEvent(surfaceId(), view.id, text, markdown))
144
+ }
145
+
102
146
  fun emitStartMention(indicator: String) {
103
147
  dispatch(OnStartMentionEvent(surfaceId(), view.id, indicator))
104
148
  }
@@ -169,6 +213,8 @@ class InputEventEmitter(
169
213
  isStyleEffectivelyActive(type, selectionStart)
170
214
  }
171
215
 
216
+ val contextMenuListState = view.listStateAtCursor(BlockType.UNORDERED_LIST_ITEM)
217
+ val contextMenuOrderedState = view.listStateAtCursor(BlockType.ORDERED_LIST_ITEM)
172
218
  dispatch(
173
219
  OnContextMenuItemPressEvent(
174
220
  surfaceId(),
@@ -183,6 +229,11 @@ class InputEventEmitter(
183
229
  isStrikethrough = isActive(StyleType.STRIKETHROUGH),
184
230
  isSpoiler = isActive(StyleType.SPOILER),
185
231
  isLink = isActive(StyleType.LINK),
232
+ headingLevel = view.headingLevelAtCursor(),
233
+ isUnorderedList = contextMenuListState.first,
234
+ unorderedListDepth = contextMenuListState.second,
235
+ isOrderedList = contextMenuOrderedState.first,
236
+ orderedListDepth = contextMenuOrderedState.second,
186
237
  ),
187
238
  )
188
239
  }
@@ -198,8 +249,18 @@ class InputEventEmitter(
198
249
  )
199
250
 
200
251
  private fun serializeToMarkdown(): String {
201
- val editable = view.text ?: return ""
202
- return MarkdownSerializer.serialize(editable, view.allFormattingRangesForSerialization(), view.mathChipController)
252
+ val plainText = view.text?.toString() ?: ""
253
+ // Each block resolves its markdown line prefix through its registered handler.
254
+ // With no block handlers registered the provider returns "" for every block
255
+ // and output equals the inline-only serialization.
256
+ return MarkdownSerializer.serialize(
257
+ plainText,
258
+ view.mathChipsForSerialization(),
259
+ view.allFormattingRangesForSerialization(),
260
+ view.blockStore.allRanges,
261
+ ) { blockRange ->
262
+ view.formatter.handlerForBlock(blockRange.type)?.markdownLinePrefix(blockRange) ?: ""
263
+ }
203
264
  }
204
265
 
205
266
  private fun surfaceId(): Int {
@@ -208,7 +269,7 @@ class InputEventEmitter(
208
269
  }
209
270
 
210
271
  private fun dispatch(event: Event<*>) {
211
- if (view.blockEmitting) return
272
+ if (view.editSession.shouldSuppressEvents) return
212
273
  val reactContext = view.context as? ReactContext ?: return
213
274
  val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id)
214
275
  dispatcher?.dispatchEvent(event)
@@ -10,6 +10,8 @@ import com.facebook.react.uimanager.PixelUtil
10
10
  import com.facebook.yoga.YogaMeasureMode
11
11
  import com.facebook.yoga.YogaMeasureOutput
12
12
  import com.swmansion.enriched.markdown.input.formatting.InputParser
13
+ import com.swmansion.enriched.markdown.utils.common.getBooleanOrDefault
14
+ import com.swmansion.enriched.markdown.utils.common.getFloatOrDefault
13
15
  import java.util.concurrent.ConcurrentHashMap
14
16
 
15
17
  object InputMeasurementStore {
@@ -101,9 +103,9 @@ object InputMeasurementStore {
101
103
  val markdown = props?.getString("defaultValue") ?: props?.getString("placeholder") ?: "I"
102
104
  // Must read the same flag the view parses with, or the measured height and the
103
105
  // rendered height disagree: `blockSyntax = false` keeps list markers and `#` as text.
104
- val blockSyntax = if (props?.hasKey("blockSyntax") == true) props.getBoolean("blockSyntax") else true
106
+ val blockSyntax = props.getBooleanOrDefault("blockSyntax", true)
105
107
  val text = InputParser.parseToPlainTextAndRanges(markdown, blockSyntax).plainText
106
- val fontSize = props?.getDouble("fontSize")?.toFloat() ?: 16f
108
+ val fontSize = props.getFloatOrDefault("fontSize", 16f)
107
109
  val spSize = kotlin.math.ceil(PixelUtil.toPixelFromSP(fontSize).toDouble()).toFloat()
108
110
 
109
111
  val defaultView = AppCompatEditText(context)
@@ -0,0 +1,27 @@
1
+ package com.swmansion.enriched.markdown.input.model
2
+
3
+ /**
4
+ * A block-level element occupying a paragraph/line range. Mirrors [FormattingRange]
5
+ * but for block scope: the range always covers whole lines.
6
+ *
7
+ * Deliberately NOT a data class: [start]/[end] mutate as edits shift ranges, so
8
+ * value-based equals/hashCode would silently break set/map lookups. Identity
9
+ * semantics are the safe default for a mutable model.
10
+ *
11
+ * @property type the block kind (PARAGRAPH is the implicit default).
12
+ * @property start inclusive start offset, in plain-text characters.
13
+ * @property end exclusive end offset, in plain-text characters.
14
+ * @property level generic integer payload, 0 by default. Headings use it for the
15
+ * H-level (1-6); list items use it for nesting depth.
16
+ * @property ordinal 1-based position of an ordered list item among its adjacent
17
+ * siblings at the same depth; recomputed by the store's list-metadata pass.
18
+ */
19
+ class BlockRange(
20
+ val type: BlockType,
21
+ override var start: Int,
22
+ override var end: Int,
23
+ var level: Int = 0,
24
+ var ordinal: Int = 1,
25
+ ) : MutableRangeBounds {
26
+ val length: Int get() = end - start
27
+ }
@@ -0,0 +1,48 @@
1
+ package com.swmansion.enriched.markdown.input.model
2
+
3
+ /**
4
+ * Block-level (paragraph-scoped) element types. A block covers whole lines,
5
+ * unlike inline styles ([StyleType]) which cover character ranges.
6
+ *
7
+ * PARAGRAPH is the default: every line is a paragraph until a block handler
8
+ * claims it. Concrete block types (headings, list items, etc.) are appended
9
+ * here as their handlers are added — each new case must have a matching
10
+ * [com.swmansion.enriched.markdown.input.styles.BlockHandler] registered in
11
+ * [com.swmansion.enriched.markdown.input.formatting.InputFormatter].
12
+ */
13
+ enum class BlockType {
14
+ PARAGRAPH,
15
+ HEADING_1,
16
+ HEADING_2,
17
+ HEADING_3,
18
+ HEADING_4,
19
+ HEADING_5,
20
+ HEADING_6,
21
+ UNORDERED_LIST_ITEM,
22
+ ORDERED_LIST_ITEM,
23
+ ;
24
+
25
+ companion object {
26
+ /** The six heading block types, indexable by level via [forHeadingLevel]. */
27
+ val HEADINGS: List<BlockType> =
28
+ listOf(HEADING_1, HEADING_2, HEADING_3, HEADING_4, HEADING_5, HEADING_6)
29
+
30
+ /** List-item block types; nesting depth rides in the range's level payload. */
31
+ val LIST_ITEMS: Set<BlockType> = setOf(UNORDERED_LIST_ITEM, ORDERED_LIST_ITEM)
32
+
33
+ /**
34
+ * Block types whose emptied line persists as a zero-length anchor (an emptied
35
+ * heading stays a heading, an emptied list item keeps its marker) until toggled off.
36
+ */
37
+ val ANCHORED: Set<BlockType> = HEADINGS.toSet() + LIST_ITEMS
38
+
39
+ /**
40
+ * Maps an H-level (1-6) to its [BlockType], or null when out of range. Used by
41
+ * the parser to turn an AST heading node's `level` attribute into a block type.
42
+ */
43
+ fun forHeadingLevel(level: Int): BlockType? = HEADINGS.getOrNull(level - 1)
44
+ }
45
+ }
46
+
47
+ /** Maximum bullet-list nesting depth (0-based), so indent can't run away unbounded. */
48
+ const val MAX_LIST_DEPTH = 5
@@ -1,10 +1,15 @@
1
1
  package com.swmansion.enriched.markdown.input.model
2
2
 
3
- data class FormattingRange(
3
+ /**
4
+ * Deliberately NOT a data class: [start]/[end] mutate as edits shift ranges, so
5
+ * value-based equals/hashCode would silently break set/map lookups. Identity
6
+ * semantics are the safe default for a mutable model.
7
+ */
8
+ class FormattingRange(
4
9
  val type: StyleType,
5
- var start: Int,
6
- var end: Int,
10
+ override var start: Int,
11
+ override var end: Int,
7
12
  var url: String? = null,
8
- ) {
13
+ ) : MutableRangeBounds {
9
14
  val length: Int get() = end - start
10
15
  }
@@ -9,8 +9,45 @@ data class InputFormatterStyle(
9
9
  val linkVariants: List<InputLinkVariantStyle>,
10
10
  val spoilerColor: Int,
11
11
  val spoilerBackgroundColor: Int,
12
- val math: MathChipStyle,
13
- val mathBlock: MathChipStyle,
12
+ /**
13
+ * Inline chip style (`markdownStyle.inlineMath`). NOTE for anyone porting
14
+ * pre-rename fork code: this used to be called `math`. The field now named
15
+ * `math` is the **block** style — the two swapped meaning, and both are
16
+ * chip styles, so a stale read compiles clean and styles the wrong chip.
17
+ */
18
+ val inlineMath: MathChipStyle,
19
+ /** Block chip style (`markdownStyle.math`). Narrowed to [MathBlockStyle] so
20
+ * passing the inline style where block fields are needed is a compile error. */
21
+ val math: MathBlockStyle,
22
+ /** Per-level heading styling, indexed 0..5 for H1..H6. Always length 6. */
23
+ val headings: List<InputHeadingStyle>,
24
+ /**
25
+ * Extra vertical spacing (dp) above each list item, from `markdownStyle.list.itemSpacing`.
26
+ * Kept in dp (not px) so this stays a pure style value; the list block handlers convert
27
+ * to px with the display density they hold.
28
+ */
29
+ val listItemSpacing: Float = 0f,
30
+ ) {
31
+ /**
32
+ * Resolves the heading style for an H-level (1-6), clamping out-of-range levels
33
+ * to the nearest valid level so a malformed parse can never crash the formatter.
34
+ */
35
+ fun headingStyle(level: Int): InputHeadingStyle = headings[(level - 1).coerceIn(0, headings.size - 1)]
36
+ }
37
+
38
+ /**
39
+ * Resolved per-level heading style for the input editor.
40
+ *
41
+ * @property fontSizePx font size in pixels (already converted from the SP prop),
42
+ * or null to leave the base text size unchanged.
43
+ * @property fontWeight parsed font weight (e.g. [android.graphics.Typeface.BOLD]),
44
+ * or [com.facebook.react.common.ReactConstants.UNSET] when unspecified.
45
+ * @property color text color, or null to keep the editor's default color.
46
+ */
47
+ data class InputHeadingStyle(
48
+ val fontSizePx: Float?,
49
+ val fontWeight: Int,
50
+ val color: Int?,
14
51
  )
15
52
 
16
53
  data class InputLinkVariantStyle(
@@ -1,5 +1,25 @@
1
1
  package com.swmansion.enriched.markdown.input.model
2
2
 
3
+ /**
4
+ * U+FFFC OBJECT REPLACEMENT CHARACTER — the one character a math chip occupies in
5
+ * the editor's plain text. Everything about a formula (its LaTeX, its display mode)
6
+ * lives on the span, never in the buffer, so the chip stays atomic for the caret,
7
+ * the IME and every range in the stores.
8
+ *
9
+ * Single source of truth on purpose: the parser writes it, the serializer expands
10
+ * it back to `$…$`, and the view inserts it. A second copy of this literal is a
11
+ * silent round-trip break waiting to happen.
12
+ */
13
+ const val OBJECT_REPLACEMENT: Char = ''
14
+
15
+ /**
16
+ * A math formula parsed out of markdown, ready to be turned into a chip span.
17
+ *
18
+ * @property position offset of the [OBJECT_REPLACEMENT] placeholder in the parsed
19
+ * plain text.
20
+ * @property latex the formula source, without its `$`/`$$` delimiters.
21
+ * @property displayMode true for `$$…$$` (block chip), false for `$…$` (inline chip).
22
+ */
3
23
  data class MathAtom(
4
24
  val position: Int,
5
25
  val latex: String,
@@ -32,7 +32,7 @@ class MathBlockStyle(
32
32
  fontWeight: String = "normal",
33
33
  val marginTop: Float,
34
34
  val marginBottom: Float,
35
- val alignment: Layout.Alignment,
35
+ val textAlign: Layout.Alignment,
36
36
  ) : MathChipStyle(
37
37
  color,
38
38
  fontSize,
@@ -0,0 +1,11 @@
1
+ package com.swmansion.enriched.markdown.input.model
2
+
3
+ /**
4
+ * Mutable `[start, end)` character bounds shared by the stored range models so
5
+ * [com.swmansion.enriched.markdown.input.formatting.RangeEditAdjustment] can
6
+ * shift/clip any range kind after a text edit.
7
+ */
8
+ interface MutableRangeBounds {
9
+ var start: Int
10
+ var end: Int
11
+ }
@@ -0,0 +1,82 @@
1
+ package com.swmansion.enriched.markdown.input.spans
2
+
3
+ import android.graphics.Canvas
4
+ import android.graphics.Paint
5
+ import android.text.Layout
6
+ import android.text.Spanned
7
+ import android.text.style.LeadingMarginSpan
8
+ import com.swmansion.enriched.markdown.input.formatting.MarkdownSpan
9
+
10
+ /**
11
+ * Bullet list item span: reserves a per-depth leading margin and draws the marker
12
+ * glyph (dot / ring / square, capped at square for depth 2+) on the item's first line.
13
+ * Mirrors the readonly renderer's bullet. Tagged [MarkdownSpan] for formatter
14
+ * cleanup.
15
+ */
16
+ class InputBulletSpan(
17
+ val depth: Int,
18
+ density: Float,
19
+ ) : LeadingMarginSpan,
20
+ MarkdownSpan {
21
+ private val indentPerDepth = INDENT_PER_DEPTH_DP * density
22
+ private val markerWidth = MARKER_WIDTH_DP * density
23
+
24
+ override fun getLeadingMargin(first: Boolean): Int = (depth * indentPerDepth + markerWidth).toInt()
25
+
26
+ override fun drawLeadingMargin(
27
+ canvas: Canvas,
28
+ paint: Paint,
29
+ x: Int,
30
+ dir: Int,
31
+ top: Int,
32
+ baseline: Int,
33
+ bottom: Int,
34
+ text: CharSequence?,
35
+ start: Int,
36
+ end: Int,
37
+ first: Boolean,
38
+ layout: Layout?,
39
+ ) {
40
+ if (!first) return
41
+ // Wrapped continuation lines also report first=true; draw only on the visual
42
+ // line where this span actually begins.
43
+ if (text is Spanned && text.getSpanStart(this) != start) return
44
+
45
+ // Bullet size tracks the text size (~30%), with a small floor so it stays visible.
46
+ val size = (paint.textSize * BULLET_SIZE_RATIO).coerceAtLeast(MIN_BULLET_PX)
47
+ val radius = size / 2f
48
+ val centerX = x + (depth * indentPerDepth + markerWidth * 0.5f) * dir
49
+ val fm = paint.fontMetrics
50
+ val centerY = baseline + (fm.ascent + fm.descent) / 2f
51
+
52
+ val originalStyle = paint.style
53
+ val originalStrokeWidth = paint.strokeWidth
54
+ when (if (depth >= 2) 2 else depth) {
55
+ 0 -> {
56
+ paint.style = Paint.Style.FILL
57
+ canvas.drawCircle(centerX, centerY, radius, paint)
58
+ }
59
+
60
+ 1 -> {
61
+ paint.style = Paint.Style.STROKE
62
+ paint.strokeWidth = (size * RING_STROKE_RATIO).coerceAtLeast(1f)
63
+ canvas.drawCircle(centerX, centerY, radius - paint.strokeWidth / 2f, paint)
64
+ }
65
+
66
+ else -> {
67
+ paint.style = Paint.Style.FILL
68
+ canvas.drawRect(centerX - radius, centerY - radius, centerX + radius, centerY + radius, paint)
69
+ }
70
+ }
71
+ paint.style = originalStyle
72
+ paint.strokeWidth = originalStrokeWidth
73
+ }
74
+
75
+ companion object {
76
+ private const val INDENT_PER_DEPTH_DP = 18f
77
+ private const val MARKER_WIDTH_DP = 18f
78
+ private const val BULLET_SIZE_RATIO = 0.3f
79
+ private const val MIN_BULLET_PX = 4f
80
+ private const val RING_STROKE_RATIO = 0.15f
81
+ }
82
+ }
@@ -0,0 +1,58 @@
1
+ package com.swmansion.enriched.markdown.input.spans
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.graphics.Typeface
5
+ import android.text.TextPaint
6
+ import android.text.style.MetricAffectingSpan
7
+ import com.facebook.react.common.ReactConstants
8
+ import com.swmansion.enriched.markdown.input.formatting.MarkdownSpan
9
+ import com.swmansion.enriched.markdown.input.model.InputFormatterStyle
10
+
11
+ /**
12
+ * Sizes and optionally weights/colors a heading line per [InputFormatterStyle.headingStyle].
13
+ * Preserves inline bold/italic via [BOLD_ITALIC_MASK] so emphasis composes with heading weight.
14
+ * Tagged [MarkdownSpan] for formatter cleanup.
15
+ */
16
+ class InputHeadingSpan(
17
+ val level: Int,
18
+ style: InputFormatterStyle,
19
+ ) : MetricAffectingSpan(),
20
+ MarkdownSpan {
21
+ private val resolved = style.headingStyle(level)
22
+
23
+ override fun updateDrawState(tp: TextPaint) {
24
+ applyHeadingStyle(tp)
25
+ resolved.color?.let { tp.color = it }
26
+ }
27
+
28
+ override fun updateMeasureState(tp: TextPaint) {
29
+ applyHeadingStyle(tp)
30
+ }
31
+
32
+ @SuppressLint("WrongConstant") // Result of mask is always valid: 0, 1, 2, or 3
33
+ private fun applyHeadingStyle(tp: TextPaint) {
34
+ resolved.fontSizePx?.let { tp.textSize = it }
35
+
36
+ if (resolved.fontWeight != ReactConstants.UNSET) {
37
+ // Fold the configured heading weight into whatever bold/italic an inline span
38
+ // already applied, so heading weight and inline emphasis compose instead of
39
+ // one clobbering the other.
40
+ val inlineStyle = (tp.typeface?.style ?: 0) and BOLD_ITALIC_MASK
41
+ val headingBold = if (resolved.fontWeight >= BOLD_WEIGHT_THRESHOLD) Typeface.BOLD else 0
42
+ val combined = inlineStyle or headingBold
43
+ tp.typeface =
44
+ if (combined != 0) {
45
+ Typeface.create(tp.typeface, combined)
46
+ } else {
47
+ tp.typeface
48
+ }
49
+ }
50
+ }
51
+
52
+ companion object {
53
+ private const val BOLD_ITALIC_MASK = Typeface.BOLD or Typeface.ITALIC
54
+
55
+ // React Native treats weights >= 700 as bold.
56
+ private const val BOLD_WEIGHT_THRESHOLD = 700
57
+ }
58
+ }
@@ -0,0 +1,37 @@
1
+ package com.swmansion.enriched.markdown.input.spans
2
+
3
+ import android.graphics.Paint
4
+ import android.text.Spanned
5
+ import android.text.style.LineHeightSpan
6
+ import com.swmansion.enriched.markdown.input.formatting.MarkdownSpan
7
+
8
+ /**
9
+ * Adds [spacingPx] of vertical space above a bullet item (counterpart to iOS
10
+ * `paragraphSpacingBefore`). Tagged [MarkdownSpan] for formatter cleanup.
11
+ *
12
+ * StaticLayout treats a LineHeightSpan as paragraph-scoped: [chooseHeight] runs
13
+ * for every wrapped line of the item regardless of the span's character range,
14
+ * and the FontMetricsInt is reused across those calls, so an unguarded relative
15
+ * adjustment compounds line after line (progressively growing gaps). Guard to
16
+ * the single line that contains the span start so only the item's first visual
17
+ * line is spaced, exactly once.
18
+ */
19
+ class InputListItemSpacingSpan(
20
+ val spacingPx: Int,
21
+ ) : LineHeightSpan,
22
+ MarkdownSpan {
23
+ override fun chooseHeight(
24
+ text: CharSequence?,
25
+ start: Int,
26
+ end: Int,
27
+ spanstartv: Int,
28
+ lineHeight: Int,
29
+ fm: Paint.FontMetricsInt?,
30
+ ) {
31
+ if (fm == null || spacingPx <= 0 || text !is Spanned) return
32
+ val spanStart = text.getSpanStart(this)
33
+ if (spanStart < start || spanStart >= end) return
34
+ fm.ascent -= spacingPx
35
+ fm.top -= spacingPx
36
+ }
37
+ }
@@ -0,0 +1,63 @@
1
+ package com.swmansion.enriched.markdown.input.spans
2
+
3
+ import android.graphics.Canvas
4
+ import android.graphics.Paint
5
+ import android.text.Layout
6
+ import android.text.Spanned
7
+ import android.text.style.LeadingMarginSpan
8
+ import com.swmansion.enriched.markdown.input.formatting.MarkdownSpan
9
+
10
+ /**
11
+ * Ordered list item span: reserves the same per-depth leading margin as
12
+ * [InputBulletSpan] and draws the item's number ("3.") right-aligned before the
13
+ * text column. The ordinal comes from the block store's list-metadata pass.
14
+ * Tagged [MarkdownSpan] for formatter cleanup.
15
+ */
16
+ class InputOrderedListMarkerSpan(
17
+ val depth: Int,
18
+ private val ordinal: Int,
19
+ density: Float,
20
+ ) : LeadingMarginSpan,
21
+ MarkdownSpan {
22
+ private val indentPerDepth = INDENT_PER_DEPTH_DP * density
23
+ private val markerWidth = MARKER_WIDTH_DP * density
24
+ private val markerGap = MARKER_GAP_DP * density
25
+
26
+ override fun getLeadingMargin(first: Boolean): Int = (depth * indentPerDepth + markerWidth).toInt()
27
+
28
+ override fun drawLeadingMargin(
29
+ canvas: Canvas,
30
+ paint: Paint,
31
+ x: Int,
32
+ dir: Int,
33
+ top: Int,
34
+ baseline: Int,
35
+ bottom: Int,
36
+ text: CharSequence?,
37
+ start: Int,
38
+ end: Int,
39
+ first: Boolean,
40
+ layout: Layout?,
41
+ ) {
42
+ if (!first) return
43
+ // Wrapped continuation lines also report first=true; draw only on the visual
44
+ // line where this span actually begins.
45
+ if (text is Spanned && text.getSpanStart(this) != start) return
46
+
47
+ // RTL (dir < 0) mirrors the marker to the trailing side and flips the label
48
+ // to ".3", matching the readonly renderer's OrderedListSpan.
49
+ val label = if (dir < 0) ".$ordinal" else "$ordinal."
50
+ val originalAlign = paint.textAlign
51
+ paint.textAlign = if (dir < 0) Paint.Align.LEFT else Paint.Align.RIGHT
52
+ val markerEdge = x + (depth * indentPerDepth + markerWidth - markerGap) * dir
53
+ canvas.drawText(label, markerEdge, baseline.toFloat(), paint)
54
+ paint.textAlign = originalAlign
55
+ }
56
+
57
+ companion object {
58
+ // Geometry mirrors InputBulletSpan so ordered and bullet items align.
59
+ private const val INDENT_PER_DEPTH_DP = 18f
60
+ private const val MARKER_WIDTH_DP = 18f
61
+ private const val MARKER_GAP_DP = 4f
62
+ }
63
+ }
@@ -0,0 +1,54 @@
1
+ package com.swmansion.enriched.markdown.input.styles
2
+
3
+ import com.swmansion.enriched.markdown.input.model.BlockRange
4
+ import com.swmansion.enriched.markdown.input.model.BlockType
5
+ import com.swmansion.enriched.markdown.input.model.InputFormatterStyle
6
+
7
+ /**
8
+ * A block handler owns how its [BlockType] styles its paragraph and how it
9
+ * serializes to a markdown line prefix. Mirrors [StyleHandler] for the inline
10
+ * pipeline. Parser recognition is NOT handler-driven: it lives in
11
+ * [com.swmansion.enriched.markdown.input.formatting.InputParser]'s central
12
+ * `nodeTypeToBlockType` map, exactly as `nodeTypeToStyleType` does for inline
13
+ * styles — a new block type adds one entry there plus one handler here.
14
+ *
15
+ * Block spans are paragraph-scoped and applied over the block's whole line range
16
+ * by [com.swmansion.enriched.markdown.input.formatting.InputFormatter]. Unlike
17
+ * inline [StyleHandler.createSpans] (which returns `CharacterStyle`), a block
18
+ * handler returns `List<Any>` so it can mix character spans (a heading's
19
+ * metric/size span) with paragraph spans (a list item's `LeadingMarginSpan` and
20
+ * line-spacing span).
21
+ *
22
+ * These signatures are designed to cover headings AND list items.
23
+ */
24
+ interface BlockHandler {
25
+ val blockType: BlockType
26
+
27
+ /**
28
+ * Whether Enter continues the block onto the next line (a list item) rather
29
+ * than ending it (a heading). Keeps Enter behavior handler-driven.
30
+ */
31
+ val continuesOnNewline: Boolean
32
+ get() = false
33
+
34
+ /**
35
+ * Spans to apply over the block's line range. Returned spans are tagged with
36
+ * [com.swmansion.enriched.markdown.input.formatting.MarkdownSpan] so the
37
+ * formatter can clean up only spans it created. A heading raises the font
38
+ * size; a list item sets a leading margin and a marker. May be empty.
39
+ */
40
+ fun createSpans(
41
+ blockRange: BlockRange,
42
+ style: InputFormatterStyle,
43
+ ): List<Any>
44
+
45
+ /** Span classes this handler produces, for cleanup/identity (mirrors [StyleHandler.spanClasses]). */
46
+ fun spanClasses(): List<Class<*>>
47
+
48
+ /**
49
+ * Markdown prefix prepended to each line of the block during serialization,
50
+ * e.g. `"# "` for an H1 or `"- "` for a bullet. Returns `""` when the block
51
+ * needs no prefix. Owning the marker here replaces a central serializer switch.
52
+ */
53
+ fun markdownLinePrefix(blockRange: BlockRange): String
54
+ }