react-native-enriched-markdown-scaffold 0.6.0-scaffold.4

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 (678) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +53 -0
  3. package/ReactNativeEnrichedMarkdown.podspec +67 -0
  4. package/android/build.gradle +94 -0
  5. package/android/consumer-rules.pro +19 -0
  6. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerDelegate.java +87 -0
  7. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownManagerInterface.java +37 -0
  8. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerDelegate.java +159 -0
  9. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextInputManagerInterface.java +59 -0
  10. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerDelegate.java +87 -0
  11. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedMarkdownTextManagerInterface.java +37 -0
  12. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp +22 -0
  13. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.h +24 -0
  14. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.cpp +318 -0
  15. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/EventEmitters.h +259 -0
  16. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.cpp +375 -0
  17. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/Props.h +5174 -0
  18. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ShadowNodes.cpp +17 -0
  19. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/ShadowNodes.h +23 -0
  20. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/States.cpp +16 -0
  21. package/android/generated/jni/react/renderer/components/EnrichedMarkdownTextSpec/States.h +20 -0
  22. package/android/gradle.properties +5 -0
  23. package/android/src/main/AndroidManifest.xml +2 -0
  24. package/android/src/main/baseline-prof.txt +254 -0
  25. package/android/src/main/cpp/jni-adapter.cpp +264 -0
  26. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdown.kt +554 -0
  27. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownInternalText.kt +122 -0
  28. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownManager.kt +255 -0
  29. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownText.kt +363 -0
  30. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextLayoutManager.kt +15 -0
  31. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextManager.kt +253 -0
  32. package/android/src/main/java/com/swmansion/enriched/markdown/EnrichedMarkdownTextPackage.kt +20 -0
  33. package/android/src/main/java/com/swmansion/enriched/markdown/MeasurementStore.kt +653 -0
  34. package/android/src/main/java/com/swmansion/enriched/markdown/accessibility/AccessibleMarkdownTextView.kt +33 -0
  35. package/android/src/main/java/com/swmansion/enriched/markdown/accessibility/MarkdownAccessibilityHelper.kt +482 -0
  36. package/android/src/main/java/com/swmansion/enriched/markdown/events/ContextMenuItemPressEvent.kt +28 -0
  37. package/android/src/main/java/com/swmansion/enriched/markdown/events/LinkLongPressEvent.kt +23 -0
  38. package/android/src/main/java/com/swmansion/enriched/markdown/events/LinkPressEvent.kt +23 -0
  39. package/android/src/main/java/com/swmansion/enriched/markdown/events/TaskListItemPressEvent.kt +26 -0
  40. package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputManager.kt +465 -0
  41. package/android/src/main/java/com/swmansion/enriched/markdown/input/EnrichedMarkdownTextInputView.kt +1066 -0
  42. package/android/src/main/java/com/swmansion/enriched/markdown/input/autolink/AutoDetectedLinkSpan.kt +29 -0
  43. package/android/src/main/java/com/swmansion/enriched/markdown/input/autolink/AutoLinkDetector.kt +188 -0
  44. package/android/src/main/java/com/swmansion/enriched/markdown/input/autolink/LinkRegexConfig.kt +9 -0
  45. package/android/src/main/java/com/swmansion/enriched/markdown/input/detection/DetectorPipeline.kt +40 -0
  46. package/android/src/main/java/com/swmansion/enriched/markdown/input/detection/TextDetector.kt +27 -0
  47. package/android/src/main/java/com/swmansion/enriched/markdown/input/detection/WordResult.kt +7 -0
  48. package/android/src/main/java/com/swmansion/enriched/markdown/input/detection/WordsUtils.kt +65 -0
  49. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/InputConnectionWrapper.kt +69 -0
  50. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/MarkdownEditableFactory.kt +15 -0
  51. package/android/src/main/java/com/swmansion/enriched/markdown/input/editing/MarkdownTextWatcher.kt +41 -0
  52. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnCaretRectChangeEvent.kt +20 -0
  53. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnChangeMarkdownEvent.kt +22 -0
  54. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnChangeMentionEvent.kt +24 -0
  55. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnChangeSelectionEvent.kt +24 -0
  56. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnChangeStateEvent.kt +50 -0
  57. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnChangeTextEvent.kt +22 -0
  58. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnContextMenuItemPressEvent.kt +48 -0
  59. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnEndMentionEvent.kt +22 -0
  60. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnInputBlurEvent.kt +18 -0
  61. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnInputFocusEvent.kt +18 -0
  62. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnLinkDetectedEvent.kt +28 -0
  63. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnMathPressEvent.kt +36 -0
  64. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnRequestCaretRectResultEvent.kt +25 -0
  65. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnRequestMarkdownResultEvent.kt +24 -0
  66. package/android/src/main/java/com/swmansion/enriched/markdown/input/events/OnStartMentionEvent.kt +22 -0
  67. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/FormattingStore.kt +192 -0
  68. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputFormatter.kt +117 -0
  69. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputParser.kt +117 -0
  70. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/InputRemend.kt +120 -0
  71. package/android/src/main/java/com/swmansion/enriched/markdown/input/formatting/MarkdownSerializer.kt +176 -0
  72. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputEventEmitter.kt +216 -0
  73. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputLayoutManager.kt +28 -0
  74. package/android/src/main/java/com/swmansion/enriched/markdown/input/layout/InputMeasurementStore.kt +137 -0
  75. package/android/src/main/java/com/swmansion/enriched/markdown/input/math/MathChipController.kt +113 -0
  76. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/CaretRect.kt +17 -0
  77. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/FormattingRange.kt +10 -0
  78. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/InputFormatterStyle.kt +28 -0
  79. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathAtom.kt +7 -0
  80. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/MathChipStyle.kt +47 -0
  81. package/android/src/main/java/com/swmansion/enriched/markdown/input/model/StyleType.kt +10 -0
  82. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/BoldStyleHandler.kt +35 -0
  83. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/ItalicStyleHandler.kt +35 -0
  84. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/LinkStyleHandler.kt +75 -0
  85. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/SpoilerStyleHandler.kt +36 -0
  86. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/StrikethroughStyleHandler.kt +24 -0
  87. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/StyleHandler.kt +18 -0
  88. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/StyleMergingConfig.kt +10 -0
  89. package/android/src/main/java/com/swmansion/enriched/markdown/input/styles/UnderlineStyleHandler.kt +24 -0
  90. package/android/src/main/java/com/swmansion/enriched/markdown/input/toolbar/InputContextMenu.kt +181 -0
  91. package/android/src/main/java/com/swmansion/enriched/markdown/parser/MarkdownASTNode.kt +43 -0
  92. package/android/src/main/java/com/swmansion/enriched/markdown/parser/Parser.kt +68 -0
  93. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BaselineShiftRenderer.kt +44 -0
  94. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockStyleContext.kt +152 -0
  95. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/BlockquoteRenderer.kt +87 -0
  96. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeBlockRenderer.kt +104 -0
  97. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/CodeRenderer.kt +36 -0
  98. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/DocumentRenderer.kt +16 -0
  99. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/EmphasisRenderer.kt +27 -0
  100. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HeadingRenderer.kt +71 -0
  101. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/HighlightRenderer.kt +25 -0
  102. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ImageRenderer.kt +61 -0
  103. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LineBreakRenderer.kt +16 -0
  104. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/LinkRenderer.kt +29 -0
  105. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListContextManager.kt +89 -0
  106. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListItemRenderer.kt +127 -0
  107. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ListRenderer.kt +74 -0
  108. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/NodeRenderer.kt +161 -0
  109. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ParagraphRenderer.kt +75 -0
  110. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/Renderer.kt +113 -0
  111. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpanStyleCache.kt +134 -0
  112. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SpoilerRenderer.kt +25 -0
  113. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/StrikethroughRenderer.kt +27 -0
  114. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/StrongRenderer.kt +27 -0
  115. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SubscriptRenderer.kt +11 -0
  116. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/SuperscriptRenderer.kt +11 -0
  117. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/TextRenderer.kt +30 -0
  118. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/ThematicBreakRenderer.kt +45 -0
  119. package/android/src/main/java/com/swmansion/enriched/markdown/renderer/UnderlineRenderer.kt +27 -0
  120. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BaseListSpan.kt +127 -0
  121. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BaselineShiftSpan.kt +27 -0
  122. package/android/src/main/java/com/swmansion/enriched/markdown/spans/BlockquoteSpan.kt +152 -0
  123. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBackgroundSpan.kt +180 -0
  124. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeBlockSpan.kt +196 -0
  125. package/android/src/main/java/com/swmansion/enriched/markdown/spans/CodeSpan.kt +32 -0
  126. package/android/src/main/java/com/swmansion/enriched/markdown/spans/EmphasisSpan.kt +42 -0
  127. package/android/src/main/java/com/swmansion/enriched/markdown/spans/FadeInSpan.kt +25 -0
  128. package/android/src/main/java/com/swmansion/enriched/markdown/spans/HeadingSpan.kt +38 -0
  129. package/android/src/main/java/com/swmansion/enriched/markdown/spans/HighlightSpan.kt +26 -0
  130. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ImageSpan.kt +335 -0
  131. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LineHeightSpan.kt +27 -0
  132. package/android/src/main/java/com/swmansion/enriched/markdown/spans/LinkSpan.kt +66 -0
  133. package/android/src/main/java/com/swmansion/enriched/markdown/spans/MarginBottomSpan.kt +76 -0
  134. package/android/src/main/java/com/swmansion/enriched/markdown/spans/MathModels.kt +18 -0
  135. package/android/src/main/java/com/swmansion/enriched/markdown/spans/OrderedListSpan.kt +85 -0
  136. package/android/src/main/java/com/swmansion/enriched/markdown/spans/SpoilerSpan.kt +33 -0
  137. package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrikethroughSpan.kt +12 -0
  138. package/android/src/main/java/com/swmansion/enriched/markdown/spans/StrongSpan.kt +39 -0
  139. package/android/src/main/java/com/swmansion/enriched/markdown/spans/TaskListSpan.kt +134 -0
  140. package/android/src/main/java/com/swmansion/enriched/markdown/spans/TextSpan.kt +26 -0
  141. package/android/src/main/java/com/swmansion/enriched/markdown/spans/ThematicBreakSpan.kt +69 -0
  142. package/android/src/main/java/com/swmansion/enriched/markdown/spans/UnorderedListSpan.kt +92 -0
  143. package/android/src/main/java/com/swmansion/enriched/markdown/spoiler/ParticleStrategy.kt +68 -0
  144. package/android/src/main/java/com/swmansion/enriched/markdown/spoiler/SegmentKey.kt +13 -0
  145. package/android/src/main/java/com/swmansion/enriched/markdown/spoiler/SolidStrategy.kt +95 -0
  146. package/android/src/main/java/com/swmansion/enriched/markdown/spoiler/SpoilerAnimator.kt +89 -0
  147. package/android/src/main/java/com/swmansion/enriched/markdown/spoiler/SpoilerCapable.kt +5 -0
  148. package/android/src/main/java/com/swmansion/enriched/markdown/spoiler/SpoilerConstants.kt +3 -0
  149. package/android/src/main/java/com/swmansion/enriched/markdown/spoiler/SpoilerDrawContext.kt +33 -0
  150. package/android/src/main/java/com/swmansion/enriched/markdown/spoiler/SpoilerDrawUtils.kt +40 -0
  151. package/android/src/main/java/com/swmansion/enriched/markdown/spoiler/SpoilerOverlay.kt +17 -0
  152. package/android/src/main/java/com/swmansion/enriched/markdown/spoiler/SpoilerOverlayDrawer.kt +152 -0
  153. package/android/src/main/java/com/swmansion/enriched/markdown/spoiler/SpoilerParticleDrawable.kt +237 -0
  154. package/android/src/main/java/com/swmansion/enriched/markdown/spoiler/SpoilerStrategy.kt +53 -0
  155. package/android/src/main/java/com/swmansion/enriched/markdown/styles/BaseBlockStyle.kt +11 -0
  156. package/android/src/main/java/com/swmansion/enriched/markdown/styles/BlockquoteStyle.kt +51 -0
  157. package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeBlockStyle.kt +54 -0
  158. package/android/src/main/java/com/swmansion/enriched/markdown/styles/CodeStyle.kt +26 -0
  159. package/android/src/main/java/com/swmansion/enriched/markdown/styles/EmphasisStyle.kt +21 -0
  160. package/android/src/main/java/com/swmansion/enriched/markdown/styles/HeadingStyle.kt +33 -0
  161. package/android/src/main/java/com/swmansion/enriched/markdown/styles/HighlightStyle.kt +19 -0
  162. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ImageStyle.kt +23 -0
  163. package/android/src/main/java/com/swmansion/enriched/markdown/styles/InlineImageStyle.kt +17 -0
  164. package/android/src/main/java/com/swmansion/enriched/markdown/styles/InlineMathStyle.kt +17 -0
  165. package/android/src/main/java/com/swmansion/enriched/markdown/styles/LinkStyle.kt +23 -0
  166. package/android/src/main/java/com/swmansion/enriched/markdown/styles/LinkVariantEntry.kt +29 -0
  167. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ListStyle.kt +62 -0
  168. package/android/src/main/java/com/swmansion/enriched/markdown/styles/MathStyle.kt +29 -0
  169. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ParagraphStyle.kt +33 -0
  170. package/android/src/main/java/com/swmansion/enriched/markdown/styles/SpoilerStyle.kt +27 -0
  171. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StrikethroughStyle.kt +17 -0
  172. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StrongStyle.kt +21 -0
  173. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleConfig.kt +364 -0
  174. package/android/src/main/java/com/swmansion/enriched/markdown/styles/StyleParser.kt +92 -0
  175. package/android/src/main/java/com/swmansion/enriched/markdown/styles/SubscriptStyle.kt +16 -0
  176. package/android/src/main/java/com/swmansion/enriched/markdown/styles/SuperscriptStyle.kt +16 -0
  177. package/android/src/main/java/com/swmansion/enriched/markdown/styles/TableStyle.kt +69 -0
  178. package/android/src/main/java/com/swmansion/enriched/markdown/styles/TaskListStyle.kt +29 -0
  179. package/android/src/main/java/com/swmansion/enriched/markdown/styles/TextAlignment.kt +32 -0
  180. package/android/src/main/java/com/swmansion/enriched/markdown/styles/ThematicBreakStyle.kt +23 -0
  181. package/android/src/main/java/com/swmansion/enriched/markdown/styles/UnderlineStyle.kt +17 -0
  182. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/BreakStrategyUtils.kt +32 -0
  183. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/FeatureFlags.kt +7 -0
  184. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownSegment.kt +56 -0
  185. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MarkdownViewManagerUtils.kt +100 -0
  186. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/MotionPreferences.kt +18 -0
  187. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/ReadableMapExtensions.kt +20 -0
  188. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/RenderedSegment.kt +78 -0
  189. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/SegmentReconciler.kt +118 -0
  190. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/SegmentSignature.kt +78 -0
  191. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/StreamingMarkdownFilter.kt +142 -0
  192. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/layout/RTLUtils.kt +6 -0
  193. package/android/src/main/java/com/swmansion/enriched/markdown/utils/common/serialization/MarkdownASTSerializer.kt +115 -0
  194. package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/AutoCapitalizeUtils.kt +27 -0
  195. package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/BorderPropsApplicator.kt +77 -0
  196. package/android/src/main/java/com/swmansion/enriched/markdown/utils/input/MarkdownStyleParser.kt +184 -0
  197. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/ImageCache.kt +53 -0
  198. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/ImageDownloader.kt +156 -0
  199. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/TailFadeInAnimator.kt +84 -0
  200. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/conversion/HTMLGenerator.kt +1067 -0
  201. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/conversion/MarkdownExtractor.kt +419 -0
  202. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/extensions/ParagraphUtils.kt +9 -0
  203. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/extensions/SpannableExtensions.kt +65 -0
  204. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/extensions/TextPaintExtensions.kt +53 -0
  205. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/interaction/CheckboxTouchHelper.kt +54 -0
  206. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/interaction/TaskListTapUtils.kt +249 -0
  207. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/span/BlockSpacing.kt +89 -0
  208. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/span/SpanFlags.kt +17 -0
  209. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkEvents.kt +43 -0
  210. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/LinkLongPressMovementMethod.kt +187 -0
  211. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/SelectionActionMode.kt +205 -0
  212. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/TextSelectionColors.kt +48 -0
  213. package/android/src/main/java/com/swmansion/enriched/markdown/utils/text/view/TextViewSetup.kt +40 -0
  214. package/android/src/main/java/com/swmansion/enriched/markdown/views/BlockSegmentView.kt +10 -0
  215. package/android/src/main/java/com/swmansion/enriched/markdown/views/ContextMenuPopup.kt +214 -0
  216. package/android/src/main/java/com/swmansion/enriched/markdown/views/TableContainerView.kt +501 -0
  217. package/android/src/main/jni/CMakeLists.txt +70 -0
  218. package/android/src/main/jni/EnrichedMarkdownTextSpec.cpp +21 -0
  219. package/android/src/main/jni/EnrichedMarkdownTextSpec.h +15 -0
  220. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/ComponentDescriptors.h +67 -0
  221. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownContainerComponentDescriptor.h +26 -0
  222. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownContainerMeasurementManager.cpp +45 -0
  223. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownContainerMeasurementManager.h +21 -0
  224. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownContainerShadowNode.cpp +20 -0
  225. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownContainerShadowNode.h +34 -0
  226. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextComponentDescriptor.h +29 -0
  227. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextInputMeasurementManager.cpp +44 -0
  228. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextInputMeasurementManager.h +21 -0
  229. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextInputShadowNode.cpp +30 -0
  230. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextInputShadowNode.h +43 -0
  231. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextInputState.cpp +9 -0
  232. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextInputState.h +24 -0
  233. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextMeasurementManager.cpp +45 -0
  234. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextMeasurementManager.h +21 -0
  235. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.cpp +20 -0
  236. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/MarkdownTextShadowNode.h +37 -0
  237. package/android/src/main/jni/react/renderer/components/EnrichedMarkdownTextSpec/conversions.h +45 -0
  238. package/android/src/math/java/com/swmansion/enriched/markdown/input/math/MathChipControllerImpl.kt +217 -0
  239. package/android/src/math/java/com/swmansion/enriched/markdown/renderer/MathInlineRenderer.kt +47 -0
  240. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathChipSpan.kt +208 -0
  241. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathInlinePlaceholderSpan.kt +41 -0
  242. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathInlineSpan.kt +92 -0
  243. package/android/src/math/java/com/swmansion/enriched/markdown/spans/MathMeasureHelper.kt +57 -0
  244. package/android/src/math/java/com/swmansion/enriched/markdown/views/MathContainerView.kt +148 -0
  245. package/app.plugin.js +1 -0
  246. package/cpp/md4c/md4c.c +7235 -0
  247. package/cpp/md4c/md4c.h +475 -0
  248. package/cpp/parser/MD4CParser.cpp +539 -0
  249. package/cpp/parser/MD4CParser.hpp +32 -0
  250. package/cpp/parser/MarkdownASTNode.hpp +63 -0
  251. package/cpp/wasm/ASTSerializer.cpp +158 -0
  252. package/cpp/wasm/ASTSerializer.hpp +17 -0
  253. package/cpp/wasm/build.sh +58 -0
  254. package/cpp/wasm/md4c_wasm.cpp +43 -0
  255. package/ios/EnrichedMarkdown.h +20 -0
  256. package/ios/EnrichedMarkdown.mm +1121 -0
  257. package/ios/EnrichedMarkdownText.h +20 -0
  258. package/ios/EnrichedMarkdownText.mm +802 -0
  259. package/ios/attachments/ENRMImageAttachment.h +27 -0
  260. package/ios/attachments/ENRMImageAttachment.m +305 -0
  261. package/ios/attachments/ENRMMathInlineAttachment+macOS.m +60 -0
  262. package/ios/attachments/ENRMMathInlineAttachment.h +47 -0
  263. package/ios/attachments/ENRMMathInlineAttachment.m +142 -0
  264. package/ios/attachments/ENRMMathInlineAttachmentShared.h +17 -0
  265. package/ios/attachments/ThematicBreakAttachment.h +15 -0
  266. package/ios/attachments/ThematicBreakAttachment.m +33 -0
  267. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/ComponentDescriptors.cpp +22 -0
  268. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/ComponentDescriptors.h +24 -0
  269. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.cpp +318 -0
  270. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/EventEmitters.h +259 -0
  271. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.cpp +375 -0
  272. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/Props.h +5174 -0
  273. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/RCTComponentViewHelpers.h +436 -0
  274. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/ShadowNodes.cpp +17 -0
  275. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/ShadowNodes.h +23 -0
  276. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/States.cpp +16 -0
  277. package/ios/generated/ReactCodegen/EnrichedMarkdownTextSpec/States.h +20 -0
  278. package/ios/input/ENRMAutoLinkDetector.h +32 -0
  279. package/ios/input/ENRMAutoLinkDetector.mm +211 -0
  280. package/ios/input/ENRMDetectorPipeline.h +28 -0
  281. package/ios/input/ENRMDetectorPipeline.mm +53 -0
  282. package/ios/input/ENRMFormattingRange.h +19 -0
  283. package/ios/input/ENRMFormattingRange.mm +28 -0
  284. package/ios/input/ENRMFormattingStore.h +29 -0
  285. package/ios/input/ENRMFormattingStore.mm +278 -0
  286. package/ios/input/ENRMInputFormatter.h +84 -0
  287. package/ios/input/ENRMInputFormatter.mm +222 -0
  288. package/ios/input/ENRMInputLayoutManager.h +11 -0
  289. package/ios/input/ENRMInputLayoutManager.mm +5 -0
  290. package/ios/input/ENRMInputLinkPrompt.h +9 -0
  291. package/ios/input/ENRMInputLinkPrompt.mm +71 -0
  292. package/ios/input/ENRMInputMentionCandidate.h +21 -0
  293. package/ios/input/ENRMInputMentionCandidate.mm +18 -0
  294. package/ios/input/ENRMInputParser.h +27 -0
  295. package/ios/input/ENRMInputParser.mm +556 -0
  296. package/ios/input/ENRMInputRemend.h +9 -0
  297. package/ios/input/ENRMInputRemend.mm +136 -0
  298. package/ios/input/ENRMInputStyledRange.h +29 -0
  299. package/ios/input/ENRMInputStyledRange.mm +4 -0
  300. package/ios/input/ENRMInputTextView.h +13 -0
  301. package/ios/input/ENRMInputTextView.mm +175 -0
  302. package/ios/input/ENRMLinkRegexConfig.h +26 -0
  303. package/ios/input/ENRMLinkRegexConfig.mm +60 -0
  304. package/ios/input/ENRMMarkdownSerializer.h +19 -0
  305. package/ios/input/ENRMMarkdownSerializer.mm +283 -0
  306. package/ios/input/ENRMTextDetector.h +30 -0
  307. package/ios/input/ENRMWordsUtils.h +28 -0
  308. package/ios/input/ENRMWordsUtils.mm +88 -0
  309. package/ios/input/EnrichedMarkdownTextInput+ContextMenu.mm +157 -0
  310. package/ios/input/EnrichedMarkdownTextInput+Internal.h +30 -0
  311. package/ios/input/EnrichedMarkdownTextInput.h +20 -0
  312. package/ios/input/EnrichedMarkdownTextInput.mm +2008 -0
  313. package/ios/input/InputStylePropsUtils.h +261 -0
  314. package/ios/input/internals/EnrichedMarkdownTextInputComponentDescriptor.h +19 -0
  315. package/ios/input/internals/EnrichedMarkdownTextInputShadowNode.h +40 -0
  316. package/ios/input/internals/EnrichedMarkdownTextInputShadowNode.mm +83 -0
  317. package/ios/input/internals/EnrichedMarkdownTextInputState.h +23 -0
  318. package/ios/input/styles/ENRMBoldStyleHandler.h +10 -0
  319. package/ios/input/styles/ENRMBoldStyleHandler.mm +29 -0
  320. package/ios/input/styles/ENRMItalicStyleHandler.h +10 -0
  321. package/ios/input/styles/ENRMItalicStyleHandler.mm +29 -0
  322. package/ios/input/styles/ENRMLinkStyleHandler.h +10 -0
  323. package/ios/input/styles/ENRMLinkStyleHandler.mm +52 -0
  324. package/ios/input/styles/ENRMSpoilerStyleHandler.h +10 -0
  325. package/ios/input/styles/ENRMSpoilerStyleHandler.mm +33 -0
  326. package/ios/input/styles/ENRMStrikethroughStyleHandler.h +10 -0
  327. package/ios/input/styles/ENRMStrikethroughStyleHandler.mm +28 -0
  328. package/ios/input/styles/ENRMStyleHandler.h +26 -0
  329. package/ios/input/styles/ENRMStyleMergingConfig.h +26 -0
  330. package/ios/input/styles/ENRMStyleMergingConfig.mm +21 -0
  331. package/ios/input/styles/ENRMUnderlineStyleHandler.h +10 -0
  332. package/ios/input/styles/ENRMUnderlineStyleHandler.mm +28 -0
  333. package/ios/internals/EnrichedMarkdownComponentDescriptor.h +18 -0
  334. package/ios/internals/EnrichedMarkdownShadowNode.h +43 -0
  335. package/ios/internals/EnrichedMarkdownShadowNode.mm +73 -0
  336. package/ios/internals/EnrichedMarkdownState.h +23 -0
  337. package/ios/internals/EnrichedMarkdownTextComponentDescriptor.h +19 -0
  338. package/ios/internals/EnrichedMarkdownTextShadowNode.h +45 -0
  339. package/ios/internals/EnrichedMarkdownTextShadowNode.mm +74 -0
  340. package/ios/internals/EnrichedMarkdownTextState.h +24 -0
  341. package/ios/internals/MeasurementCache.h +223 -0
  342. package/ios/internals/ShadowMeasurementUtils.h +135 -0
  343. package/ios/math/ENRMRaTeXBridge.swift +58 -0
  344. package/ios/parser/ENRMMarkdownParser.h +21 -0
  345. package/ios/parser/ENRMMarkdownParser.mm +50 -0
  346. package/ios/parser/MarkdownASTNode.h +47 -0
  347. package/ios/parser/MarkdownASTNode.m +32 -0
  348. package/ios/parser/MarkdownParserBridge.mm +161 -0
  349. package/ios/renderer/AttributedRenderer.h +11 -0
  350. package/ios/renderer/AttributedRenderer.m +153 -0
  351. package/ios/renderer/BaseRenderer.h +18 -0
  352. package/ios/renderer/BaseRenderer.m +16 -0
  353. package/ios/renderer/BaselineShiftTextAttributes.h +6 -0
  354. package/ios/renderer/BaselineShiftTextAttributes.m +22 -0
  355. package/ios/renderer/BlockquoteRenderer.h +6 -0
  356. package/ios/renderer/BlockquoteRenderer.m +148 -0
  357. package/ios/renderer/CodeBlockRenderer.h +9 -0
  358. package/ios/renderer/CodeBlockRenderer.m +90 -0
  359. package/ios/renderer/CodeRenderer.h +9 -0
  360. package/ios/renderer/CodeRenderer.m +64 -0
  361. package/ios/renderer/ENRMImageRenderer.h +9 -0
  362. package/ios/renderer/ENRMImageRenderer.m +65 -0
  363. package/ios/renderer/ENRMMathInlineRenderer.h +9 -0
  364. package/ios/renderer/ENRMMathInlineRenderer.m +56 -0
  365. package/ios/renderer/ENRMSpoilerRenderer.h +5 -0
  366. package/ios/renderer/ENRMSpoilerRenderer.m +32 -0
  367. package/ios/renderer/EmphasisRenderer.h +5 -0
  368. package/ios/renderer/EmphasisRenderer.m +98 -0
  369. package/ios/renderer/HeadingRenderer.h +6 -0
  370. package/ios/renderer/HeadingRenderer.m +94 -0
  371. package/ios/renderer/HighlightRenderer.h +7 -0
  372. package/ios/renderer/HighlightRenderer.m +31 -0
  373. package/ios/renderer/LinkRenderer.h +6 -0
  374. package/ios/renderer/LinkRenderer.m +82 -0
  375. package/ios/renderer/ListItemRenderer.h +12 -0
  376. package/ios/renderer/ListItemRenderer.m +175 -0
  377. package/ios/renderer/ListRenderer.h +13 -0
  378. package/ios/renderer/ListRenderer.m +70 -0
  379. package/ios/renderer/NodeRenderer.h +8 -0
  380. package/ios/renderer/ParagraphRenderer.h +6 -0
  381. package/ios/renderer/ParagraphRenderer.m +70 -0
  382. package/ios/renderer/RenderContext.h +118 -0
  383. package/ios/renderer/RenderContext.m +337 -0
  384. package/ios/renderer/RendererFactory.h +12 -0
  385. package/ios/renderer/RendererFactory.m +147 -0
  386. package/ios/renderer/StrikethroughRenderer.h +5 -0
  387. package/ios/renderer/StrikethroughRenderer.m +28 -0
  388. package/ios/renderer/StrongRenderer.h +5 -0
  389. package/ios/renderer/StrongRenderer.m +86 -0
  390. package/ios/renderer/SubscriptRenderer.h +5 -0
  391. package/ios/renderer/SubscriptRenderer.m +22 -0
  392. package/ios/renderer/SuperscriptRenderer.h +5 -0
  393. package/ios/renderer/SuperscriptRenderer.m +22 -0
  394. package/ios/renderer/TextRenderer.h +6 -0
  395. package/ios/renderer/TextRenderer.m +16 -0
  396. package/ios/renderer/ThematicBreakRenderer.h +4 -0
  397. package/ios/renderer/ThematicBreakRenderer.m +40 -0
  398. package/ios/renderer/UnderlineRenderer.h +4 -0
  399. package/ios/renderer/UnderlineRenderer.m +27 -0
  400. package/ios/styles/ENRMFontSlot.h +12 -0
  401. package/ios/styles/ENRMFontSlot.m +24 -0
  402. package/ios/styles/StyleConfig.h +407 -0
  403. package/ios/styles/StyleConfig.mm +2515 -0
  404. package/ios/utils/AccessibilityInfo.h +35 -0
  405. package/ios/utils/AccessibilityInfo.m +24 -0
  406. package/ios/utils/BlockquoteBorder.h +20 -0
  407. package/ios/utils/BlockquoteBorder.m +97 -0
  408. package/ios/utils/CodeBackground.h +19 -0
  409. package/ios/utils/CodeBackground.m +197 -0
  410. package/ios/utils/CodeBlockBackground.h +17 -0
  411. package/ios/utils/CodeBlockBackground.m +89 -0
  412. package/ios/utils/ContextMenuUtils.h +76 -0
  413. package/ios/utils/ContextMenuUtils.mm +73 -0
  414. package/ios/utils/ENRMAsyncRenderCoordinator.h +24 -0
  415. package/ios/utils/ENRMAsyncRenderCoordinator.m +37 -0
  416. package/ios/utils/ENRMFeatureFlags.h +12 -0
  417. package/ios/utils/ENRMImageDownloader.h +16 -0
  418. package/ios/utils/ENRMImageDownloader.m +108 -0
  419. package/ios/utils/ENRMMenuAction.h +27 -0
  420. package/ios/utils/ENRMMenuAction.m +33 -0
  421. package/ios/utils/ENRMParticleOverlayView.h +12 -0
  422. package/ios/utils/ENRMParticleOverlayView.m +159 -0
  423. package/ios/utils/ENRMSolidOverlayView.h +12 -0
  424. package/ios/utils/ENRMSolidOverlayView.m +25 -0
  425. package/ios/utils/ENRMSpoilerCapable.h +15 -0
  426. package/ios/utils/ENRMSpoilerOverlayManager.h +21 -0
  427. package/ios/utils/ENRMSpoilerOverlayManager.m +181 -0
  428. package/ios/utils/ENRMSpoilerOverlayView.h +49 -0
  429. package/ios/utils/ENRMSpoilerOverlayView.m +144 -0
  430. package/ios/utils/ENRMSpoilerTapUtils.h +25 -0
  431. package/ios/utils/ENRMSpoilerTapUtils.m +68 -0
  432. package/ios/utils/ENRMTailFadeInAnimator.h +16 -0
  433. package/ios/utils/ENRMTailFadeInAnimator.m +161 -0
  434. package/ios/utils/ENRMTextHitTest.h +23 -0
  435. package/ios/utils/ENRMTextHitTest.m +20 -0
  436. package/ios/utils/ENRMTextInteractionUtils.h +20 -0
  437. package/ios/utils/ENRMTextInteractionUtils.m +15 -0
  438. package/ios/utils/ENRMTextRenderer.h +30 -0
  439. package/ios/utils/ENRMTextRenderer.m +38 -0
  440. package/ios/utils/ENRMTextViewSetup.h +78 -0
  441. package/ios/utils/ENRMUIKit.h +418 -0
  442. package/ios/utils/EditMenuUtils+macOS.m +60 -0
  443. package/ios/utils/EditMenuUtils.h +35 -0
  444. package/ios/utils/EditMenuUtils.m +119 -0
  445. package/ios/utils/FontScaleObserver.h +10 -0
  446. package/ios/utils/FontScaleObserver.m +55 -0
  447. package/ios/utils/FontUtils.h +30 -0
  448. package/ios/utils/FontUtils.m +47 -0
  449. package/ios/utils/HTMLGenerator.h +25 -0
  450. package/ios/utils/HTMLGenerator.m +1019 -0
  451. package/ios/utils/HeightUpdateUtils.h +25 -0
  452. package/ios/utils/LastElementUtils.h +53 -0
  453. package/ios/utils/LinkTapUtils.h +24 -0
  454. package/ios/utils/LinkTapUtils.m +32 -0
  455. package/ios/utils/ListMarkerDrawer.h +15 -0
  456. package/ios/utils/ListMarkerDrawer.m +212 -0
  457. package/ios/utils/MarkdownASTSerializer.h +24 -0
  458. package/ios/utils/MarkdownASTSerializer.m +114 -0
  459. package/ios/utils/MarkdownAccessibilityElementBuilder.h +41 -0
  460. package/ios/utils/MarkdownAccessibilityElementBuilder.m +450 -0
  461. package/ios/utils/MarkdownExtractor.h +17 -0
  462. package/ios/utils/MarkdownExtractor.m +355 -0
  463. package/ios/utils/ParagraphStyleUtils.h +53 -0
  464. package/ios/utils/ParagraphStyleUtils.m +349 -0
  465. package/ios/utils/PasteboardUtils.h +48 -0
  466. package/ios/utils/PasteboardUtils.m +162 -0
  467. package/ios/utils/RTFExportUtils.h +24 -0
  468. package/ios/utils/RTFExportUtils.m +297 -0
  469. package/ios/utils/RenderedMarkdownSegment.h +49 -0
  470. package/ios/utils/RenderedMarkdownSegment.m +130 -0
  471. package/ios/utils/RuntimeKeys.h +38 -0
  472. package/ios/utils/RuntimeKeys.m +11 -0
  473. package/ios/utils/SegmentReconciler.h +32 -0
  474. package/ios/utils/SegmentReconciler.m +118 -0
  475. package/ios/utils/SegmentRenderer.h +24 -0
  476. package/ios/utils/SegmentRenderer.m +88 -0
  477. package/ios/utils/SegmentViewRegistry.h +36 -0
  478. package/ios/utils/SegmentViewRegistry.m +67 -0
  479. package/ios/utils/SelectionColorUtils.h +14 -0
  480. package/ios/utils/StreamingMarkdownFilter.h +22 -0
  481. package/ios/utils/StreamingMarkdownFilter.m +165 -0
  482. package/ios/utils/StylePropsUtils.h +1146 -0
  483. package/ios/utils/TaskListTapUtils.h +43 -0
  484. package/ios/utils/TaskListTapUtils.m +227 -0
  485. package/ios/utils/TextViewLayoutManager.h +14 -0
  486. package/ios/utils/TextViewLayoutManager.mm +113 -0
  487. package/ios/views/ENRMContextMenuTextView+macOS.h +17 -0
  488. package/ios/views/ENRMContextMenuTextView+macOS.m +97 -0
  489. package/ios/views/ENRMMathContainerView.h +20 -0
  490. package/ios/views/ENRMMathContainerView.m +227 -0
  491. package/ios/views/ENRMTableGridView.h +36 -0
  492. package/ios/views/ENRMTableGridView.m +98 -0
  493. package/ios/views/EnrichedMarkdownInternalText.h +42 -0
  494. package/ios/views/EnrichedMarkdownInternalText.m +161 -0
  495. package/ios/views/TableContainerView.h +39 -0
  496. package/ios/views/TableContainerView.m +686 -0
  497. package/lib/module/EnrichedMarkdownNativeComponent.ts +429 -0
  498. package/lib/module/EnrichedMarkdownTextInput.js +310 -0
  499. package/lib/module/EnrichedMarkdownTextInput.js.map +1 -0
  500. package/lib/module/EnrichedMarkdownTextInputNativeComponent.ts +364 -0
  501. package/lib/module/EnrichedMarkdownTextNativeComponent.ts +428 -0
  502. package/lib/module/index.js +5 -0
  503. package/lib/module/index.js.map +1 -0
  504. package/lib/module/index.web.js +4 -0
  505. package/lib/module/index.web.js.map +1 -0
  506. package/lib/module/linkVariantUtils.js +28 -0
  507. package/lib/module/linkVariantUtils.js.map +1 -0
  508. package/lib/module/native/EnrichedMarkdownText.js +158 -0
  509. package/lib/module/native/EnrichedMarkdownText.js.map +1 -0
  510. package/lib/module/normalizeMarkdownStyle.js +337 -0
  511. package/lib/module/normalizeMarkdownStyle.js.map +1 -0
  512. package/lib/module/normalizeMarkdownStyle.web.js +264 -0
  513. package/lib/module/normalizeMarkdownStyle.web.js.map +1 -0
  514. package/lib/module/normalizeMarkdownTextInputStyle.js +146 -0
  515. package/lib/module/normalizeMarkdownTextInputStyle.js.map +1 -0
  516. package/lib/module/package.json +1 -0
  517. package/lib/module/plugin/withAndroidMath.js +20 -0
  518. package/lib/module/plugin/withAndroidMath.js.map +1 -0
  519. package/lib/module/plugin/withIosMath.js +23 -0
  520. package/lib/module/plugin/withIosMath.js.map +1 -0
  521. package/lib/module/plugin/withReactNativeEnrichedMarkdown.js +16 -0
  522. package/lib/module/plugin/withReactNativeEnrichedMarkdown.js.map +1 -0
  523. package/lib/module/styleUtils.js +64 -0
  524. package/lib/module/styleUtils.js.map +1 -0
  525. package/lib/module/types/MarkdownStyle.js +2 -0
  526. package/lib/module/types/MarkdownStyle.js.map +1 -0
  527. package/lib/module/types/MarkdownStyleInternal.js +2 -0
  528. package/lib/module/types/MarkdownStyleInternal.js.map +1 -0
  529. package/lib/module/types/MarkdownTextProps.js +4 -0
  530. package/lib/module/types/MarkdownTextProps.js.map +1 -0
  531. package/lib/module/types/MarkdownTextProps.web.js +4 -0
  532. package/lib/module/types/MarkdownTextProps.web.js.map +1 -0
  533. package/lib/module/types/events.js +2 -0
  534. package/lib/module/types/events.js.map +1 -0
  535. package/lib/module/utils/regexParser.js +43 -0
  536. package/lib/module/utils/regexParser.js.map +1 -0
  537. package/lib/module/web/EnrichedMarkdownText.js +120 -0
  538. package/lib/module/web/EnrichedMarkdownText.js.map +1 -0
  539. package/lib/module/web/globalStyles.js +10 -0
  540. package/lib/module/web/globalStyles.js.map +1 -0
  541. package/lib/module/web/injectStyle.js +20 -0
  542. package/lib/module/web/injectStyle.js.map +1 -0
  543. package/lib/module/web/katex.js +22 -0
  544. package/lib/module/web/katex.js.map +1 -0
  545. package/lib/module/web/parseMarkdown.js +35 -0
  546. package/lib/module/web/parseMarkdown.js.map +1 -0
  547. package/lib/module/web/renderers/BlockRenderers.js +115 -0
  548. package/lib/module/web/renderers/BlockRenderers.js.map +1 -0
  549. package/lib/module/web/renderers/InlineRenderers.js +160 -0
  550. package/lib/module/web/renderers/InlineRenderers.js.map +1 -0
  551. package/lib/module/web/renderers/KaTeXRenderer.js +43 -0
  552. package/lib/module/web/renderers/KaTeXRenderer.js.map +1 -0
  553. package/lib/module/web/renderers/ListRenderers.js +92 -0
  554. package/lib/module/web/renderers/ListRenderers.js.map +1 -0
  555. package/lib/module/web/renderers/TableRenderers.js +77 -0
  556. package/lib/module/web/renderers/TableRenderers.js.map +1 -0
  557. package/lib/module/web/renderers/index.js +49 -0
  558. package/lib/module/web/renderers/index.js.map +1 -0
  559. package/lib/module/web/styles.js +454 -0
  560. package/lib/module/web/styles.js.map +1 -0
  561. package/lib/module/web/types.js +4 -0
  562. package/lib/module/web/types.js.map +1 -0
  563. package/lib/module/web/utils.js +56 -0
  564. package/lib/module/web/utils.js.map +1 -0
  565. package/lib/module/web/wasm/md4c.d.js +4 -0
  566. package/lib/module/web/wasm/md4c.d.js.map +1 -0
  567. package/lib/module/web/wasm/md4c.js +0 -0
  568. package/lib/module/web/wasm/md4c.js.map +1 -0
  569. package/lib/typescript/package.json +1 -0
  570. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts +384 -0
  571. package/lib/typescript/src/EnrichedMarkdownNativeComponent.d.ts.map +1 -0
  572. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts +173 -0
  573. package/lib/typescript/src/EnrichedMarkdownTextInput.d.ts.map +1 -0
  574. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts +285 -0
  575. package/lib/typescript/src/EnrichedMarkdownTextInputNativeComponent.d.ts.map +1 -0
  576. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts +384 -0
  577. package/lib/typescript/src/EnrichedMarkdownTextNativeComponent.d.ts.map +1 -0
  578. package/lib/typescript/src/index.d.ts +6 -0
  579. package/lib/typescript/src/index.d.ts.map +1 -0
  580. package/lib/typescript/src/index.web.d.ts +5 -0
  581. package/lib/typescript/src/index.web.d.ts.map +1 -0
  582. package/lib/typescript/src/linkVariantUtils.d.ts +5 -0
  583. package/lib/typescript/src/linkVariantUtils.d.ts.map +1 -0
  584. package/lib/typescript/src/native/EnrichedMarkdownText.d.ts +9 -0
  585. package/lib/typescript/src/native/EnrichedMarkdownText.d.ts.map +1 -0
  586. package/lib/typescript/src/normalizeMarkdownStyle.d.ts +4 -0
  587. package/lib/typescript/src/normalizeMarkdownStyle.d.ts.map +1 -0
  588. package/lib/typescript/src/normalizeMarkdownStyle.web.d.ts +4 -0
  589. package/lib/typescript/src/normalizeMarkdownStyle.web.d.ts.map +1 -0
  590. package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts +48 -0
  591. package/lib/typescript/src/normalizeMarkdownTextInputStyle.d.ts.map +1 -0
  592. package/lib/typescript/src/plugin/withAndroidMath.d.ts +5 -0
  593. package/lib/typescript/src/plugin/withAndroidMath.d.ts.map +1 -0
  594. package/lib/typescript/src/plugin/withIosMath.d.ts +5 -0
  595. package/lib/typescript/src/plugin/withIosMath.d.ts.map +1 -0
  596. package/lib/typescript/src/plugin/withReactNativeEnrichedMarkdown.d.ts +6 -0
  597. package/lib/typescript/src/plugin/withReactNativeEnrichedMarkdown.d.ts.map +1 -0
  598. package/lib/typescript/src/styleUtils.d.ts +6 -0
  599. package/lib/typescript/src/styleUtils.d.ts.map +1 -0
  600. package/lib/typescript/src/types/MarkdownStyle.d.ts +300 -0
  601. package/lib/typescript/src/types/MarkdownStyle.d.ts.map +1 -0
  602. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts +178 -0
  603. package/lib/typescript/src/types/MarkdownStyleInternal.d.ts.map +1 -0
  604. package/lib/typescript/src/types/MarkdownTextProps.d.ts +249 -0
  605. package/lib/typescript/src/types/MarkdownTextProps.d.ts.map +1 -0
  606. package/lib/typescript/src/types/MarkdownTextProps.web.d.ts +83 -0
  607. package/lib/typescript/src/types/MarkdownTextProps.web.d.ts.map +1 -0
  608. package/lib/typescript/src/types/events.d.ts +29 -0
  609. package/lib/typescript/src/types/events.d.ts.map +1 -0
  610. package/lib/typescript/src/utils/regexParser.d.ts +3 -0
  611. package/lib/typescript/src/utils/regexParser.d.ts.map +1 -0
  612. package/lib/typescript/src/web/EnrichedMarkdownText.d.ts +4 -0
  613. package/lib/typescript/src/web/EnrichedMarkdownText.d.ts.map +1 -0
  614. package/lib/typescript/src/web/globalStyles.d.ts +3 -0
  615. package/lib/typescript/src/web/globalStyles.d.ts.map +1 -0
  616. package/lib/typescript/src/web/injectStyle.d.ts +9 -0
  617. package/lib/typescript/src/web/injectStyle.d.ts.map +1 -0
  618. package/lib/typescript/src/web/katex.d.ts +11 -0
  619. package/lib/typescript/src/web/katex.d.ts.map +1 -0
  620. package/lib/typescript/src/web/parseMarkdown.d.ts +4 -0
  621. package/lib/typescript/src/web/parseMarkdown.d.ts.map +1 -0
  622. package/lib/typescript/src/web/renderers/BlockRenderers.d.ts +3 -0
  623. package/lib/typescript/src/web/renderers/BlockRenderers.d.ts.map +1 -0
  624. package/lib/typescript/src/web/renderers/InlineRenderers.d.ts +3 -0
  625. package/lib/typescript/src/web/renderers/InlineRenderers.d.ts.map +1 -0
  626. package/lib/typescript/src/web/renderers/KaTeXRenderer.d.ts +11 -0
  627. package/lib/typescript/src/web/renderers/KaTeXRenderer.d.ts.map +1 -0
  628. package/lib/typescript/src/web/renderers/ListRenderers.d.ts +3 -0
  629. package/lib/typescript/src/web/renderers/ListRenderers.d.ts.map +1 -0
  630. package/lib/typescript/src/web/renderers/TableRenderers.d.ts +3 -0
  631. package/lib/typescript/src/web/renderers/TableRenderers.d.ts.map +1 -0
  632. package/lib/typescript/src/web/renderers/index.d.ts +14 -0
  633. package/lib/typescript/src/web/renderers/index.d.ts.map +1 -0
  634. package/lib/typescript/src/web/styles.d.ts +49 -0
  635. package/lib/typescript/src/web/styles.d.ts.map +1 -0
  636. package/lib/typescript/src/web/types.d.ts +51 -0
  637. package/lib/typescript/src/web/types.d.ts.map +1 -0
  638. package/lib/typescript/src/web/utils.d.ts +21 -0
  639. package/lib/typescript/src/web/utils.d.ts.map +1 -0
  640. package/package.json +125 -0
  641. package/react-native.config.js +17 -0
  642. package/src/EnrichedMarkdownNativeComponent.ts +429 -0
  643. package/src/EnrichedMarkdownTextInput.tsx +547 -0
  644. package/src/EnrichedMarkdownTextInputNativeComponent.ts +364 -0
  645. package/src/EnrichedMarkdownTextNativeComponent.ts +428 -0
  646. package/src/index.tsx +28 -0
  647. package/src/index.web.tsx +8 -0
  648. package/src/linkVariantUtils.ts +42 -0
  649. package/src/native/EnrichedMarkdownText.tsx +187 -0
  650. package/src/normalizeMarkdownStyle.ts +310 -0
  651. package/src/normalizeMarkdownStyle.web.ts +281 -0
  652. package/src/normalizeMarkdownTextInputStyle.ts +242 -0
  653. package/src/plugin/withAndroidMath.ts +24 -0
  654. package/src/plugin/withIosMath.ts +35 -0
  655. package/src/plugin/withReactNativeEnrichedMarkdown.ts +17 -0
  656. package/src/styleUtils.ts +98 -0
  657. package/src/types/MarkdownStyle.ts +326 -0
  658. package/src/types/MarkdownStyleInternal.ts +208 -0
  659. package/src/types/MarkdownTextProps.ts +253 -0
  660. package/src/types/MarkdownTextProps.web.ts +90 -0
  661. package/src/types/events.ts +32 -0
  662. package/src/utils/regexParser.ts +54 -0
  663. package/src/web/EnrichedMarkdownText.tsx +154 -0
  664. package/src/web/globalStyles.ts +15 -0
  665. package/src/web/injectStyle.ts +17 -0
  666. package/src/web/katex.ts +31 -0
  667. package/src/web/parseMarkdown.ts +78 -0
  668. package/src/web/renderers/BlockRenderers.tsx +90 -0
  669. package/src/web/renderers/InlineRenderers.tsx +121 -0
  670. package/src/web/renderers/KaTeXRenderer.tsx +49 -0
  671. package/src/web/renderers/ListRenderers.tsx +110 -0
  672. package/src/web/renderers/TableRenderers.tsx +61 -0
  673. package/src/web/renderers/index.tsx +75 -0
  674. package/src/web/styles.ts +549 -0
  675. package/src/web/types.ts +92 -0
  676. package/src/web/utils.ts +52 -0
  677. package/src/web/wasm/md4c.d.ts +21 -0
  678. package/src/web/wasm/md4c.js +0 -0
@@ -0,0 +1,2008 @@
1
+ #import "EnrichedMarkdownTextInput.h"
2
+ #import "ContextMenuUtils.h"
3
+ #import "ENRMAutoLinkDetector.h"
4
+ #import "ENRMDetectorPipeline.h"
5
+ #import "ENRMFeatureFlags.h"
6
+ #import "ENRMFormattingRange.h"
7
+ #import "ENRMFormattingStore.h"
8
+ #import "ENRMInputFormatter.h"
9
+ #import "ENRMInputLayoutManager.h"
10
+ #import "ENRMInputLinkPrompt.h"
11
+ #import "ENRMInputMentionCandidate.h"
12
+ #import "ENRMInputParser.h"
13
+ #import "ENRMInputTextView.h"
14
+ #import "ENRMLinkRegexConfig.h"
15
+ #import "ENRMMarkdownSerializer.h"
16
+ #if ENRICHED_MARKDOWN_MATH
17
+ #import "ENRMMathInlineAttachment.h"
18
+ #endif
19
+ #import "ENRMStyleHandler.h"
20
+ #import "ENRMStyleMergingConfig.h"
21
+ #import "ENRMUIKit.h"
22
+ #import "ENRMWordsUtils.h"
23
+ #import "InputStylePropsUtils.h"
24
+ #import "ParagraphStyleUtils.h"
25
+ #import "SelectionColorUtils.h"
26
+ #import <React/RCTI18nUtil.h>
27
+ #if TARGET_OS_OSX
28
+ #import <React/RCTBackedTextInputDelegate.h>
29
+ #endif
30
+
31
+ #import <ReactNativeEnrichedMarkdown/EnrichedMarkdownTextInputComponentDescriptor.h>
32
+ #import <ReactNativeEnrichedMarkdown/EventEmitters.h>
33
+ #import <ReactNativeEnrichedMarkdown/Props.h>
34
+ #import <ReactNativeEnrichedMarkdown/RCTComponentViewHelpers.h>
35
+
36
+ #import "EnrichedMarkdownTextInputShadowNode.h"
37
+ #import "HeightUpdateUtils.h"
38
+ #import "RCTFabricComponentsPlugins.h"
39
+ #import <React/RCTConversions.h>
40
+
41
+ using namespace facebook::react;
42
+
43
+ #if !TARGET_OS_OSX
44
+ @interface EnrichedMarkdownTextInput () <RCTEnrichedMarkdownTextInputViewProtocol, UITextViewDelegate>
45
+ #else
46
+ @interface EnrichedMarkdownTextInput () <RCTEnrichedMarkdownTextInputViewProtocol, RCTBackedTextInputDelegate>
47
+ #endif
48
+ - (void)setupTextView;
49
+ - (void)applyFormatting;
50
+ - (void)toggleInlineStyle:(ENRMInputStyleType)styleType;
51
+ - (void)resetBaseTypingAttributes;
52
+ @end
53
+
54
+ @implementation EnrichedMarkdownTextInput {
55
+ ENRMPlatformTextView *_textView;
56
+ ENRMInputLayoutManager *_layoutManager;
57
+ EnrichedMarkdownTextInputShadowNode::ConcreteState::Shared _state;
58
+ int _heightUpdateCounter;
59
+ ENRMInputFormatter *_formatter;
60
+ ENRMInputFormatterStyle *_formatterStyle;
61
+ ENRMFormattingStore *_formattingStore;
62
+ NSMutableSet<NSNumber *> *_pendingStyles;
63
+ NSMutableSet<NSNumber *> *_pendingStyleRemovals;
64
+ BOOL _isApplyingFormatting;
65
+ BOOL _isTextChanging;
66
+ BOOL _emitMarkdown;
67
+
68
+ ENRMPlaceholderLabel *_placeholderLabel;
69
+
70
+ NSUInteger _lastTextLength;
71
+ NSRange _lastSelectedRange;
72
+ NSRange _preEditSelectedRange;
73
+
74
+ struct {
75
+ BOOL bold, italic, underline, strikethrough, spoiler, link, initialized;
76
+ } _prevState;
77
+
78
+ std::optional<CGRect> _prevCaretRect;
79
+
80
+ #if TARGET_OS_OSX
81
+ NSScrollView *_scrollView;
82
+ #endif
83
+
84
+ NSArray<NSString *> *_contextMenuItemTexts;
85
+ NSArray<NSString *> *_contextMenuItemIcons;
86
+ NSArray<NSString *> *_mentionIndicators;
87
+ NSString *_activeMentionIndicator;
88
+ NSRange _activeMentionRange;
89
+ NSString *_activeMentionText;
90
+
91
+ ENRMAutoLinkDetector *_autoLinkDetector;
92
+ ENRMDetectorPipeline *_detectorPipeline;
93
+
94
+ ENRMWritingDirectionMode _writingDirectionMode;
95
+ NSWritingDirection _resolvedLayoutDirection;
96
+
97
+ /// One-shot guard: when YES, the next textViewDidChangeSelection skips
98
+ /// clearing math chip selections. Set by handleTapForMathChip right before
99
+ /// it moves the caret to the chip, so the caret update doesn't immediately
100
+ /// wipe the chip we just selected.
101
+ BOOL _suppressMathChipClearOnce;
102
+ /// Character index of the currently selected math chip, or NSNotFound.
103
+ NSUInteger _activeMathChipIndex;
104
+ }
105
+
106
+ #pragma mark - Fabric lifecycle
107
+
108
+ + (ComponentDescriptorProvider)componentDescriptorProvider
109
+ {
110
+ return concreteComponentDescriptorProvider<EnrichedMarkdownTextInputComponentDescriptor>();
111
+ }
112
+
113
+ + (BOOL)shouldBeRecycled
114
+ {
115
+ return NO;
116
+ }
117
+
118
+ - (instancetype)initWithFrame:(CGRect)frame
119
+ {
120
+ if (self = [super initWithFrame:frame]) {
121
+ static const auto defaultProps = std::make_shared<const EnrichedMarkdownTextInputProps>();
122
+ _props = defaultProps;
123
+
124
+ self.backgroundColor = [RCTUIColor clearColor];
125
+ _blockEmitting = NO;
126
+ _heightUpdateCounter = 0;
127
+ _formatter = [[ENRMInputFormatter alloc] init];
128
+ _formatterStyle = [[ENRMInputFormatterStyle alloc] init];
129
+ _formattingStore = [[ENRMFormattingStore alloc] init];
130
+ _pendingStyles = [NSMutableSet set];
131
+ _pendingStyleRemovals = [NSMutableSet set];
132
+ _lastTextLength = 0;
133
+ _lastSelectedRange = NSMakeRange(0, 0);
134
+ _mentionIndicators = @[];
135
+ _activeMentionRange = NSMakeRange(NSNotFound, 0);
136
+ _activeMentionText = @"";
137
+
138
+ _writingDirectionMode = ENRMWritingDirectionModeFirstStrong;
139
+ _resolvedLayoutDirection =
140
+ [[RCTI18nUtil sharedInstance] isRTL] ? NSWritingDirectionRightToLeft : NSWritingDirectionLeftToRight;
141
+
142
+ _suppressMathChipClearOnce = NO;
143
+ _activeMathChipIndex = NSNotFound;
144
+
145
+ [self setupTextView];
146
+
147
+ [self setupDetectorPipeline];
148
+ }
149
+ return self;
150
+ }
151
+
152
+ - (void)setupDetectorPipeline
153
+ {
154
+ _autoLinkDetector = [[ENRMAutoLinkDetector alloc] initWithTextStorage:_textView.textStorage
155
+ formattingStore:_formattingStore
156
+ style:_formatterStyle];
157
+
158
+ __weak EnrichedMarkdownTextInput *weakSelf = self;
159
+ _autoLinkDetector.onLinkDetected = ^(NSString *text, NSString *url, NSRange range) {
160
+ [weakSelf emitOnLinkDetectedWithText:text url:url range:range];
161
+ };
162
+
163
+ _detectorPipeline = [[ENRMDetectorPipeline alloc] init];
164
+ [_detectorPipeline addDetector:_autoLinkDetector];
165
+ }
166
+
167
+ - (void)setupTextView
168
+ {
169
+ #if !TARGET_OS_OSX
170
+ _layoutManager = [[ENRMInputLayoutManager alloc] init];
171
+ NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:CGSizeMake(0, CGFLOAT_MAX)];
172
+ textContainer.widthTracksTextView = YES;
173
+ [_layoutManager addTextContainer:textContainer];
174
+
175
+ NSTextStorage *textStorage = [[NSTextStorage alloc] init];
176
+ [textStorage addLayoutManager:_layoutManager];
177
+
178
+ ENRMInputTextView *inputTextView = [[ENRMInputTextView alloc] initWithFrame:CGRectZero textContainer:textContainer];
179
+ #else
180
+ ENRMInputTextView *inputTextView = [[ENRMInputTextView alloc] initWithFrame:CGRectZero];
181
+ #endif
182
+ inputTextView.markdownTextInput = self;
183
+ _textView = inputTextView;
184
+ ENRMConfigureMarkdownTextInputTextView(_textView);
185
+ #if !TARGET_OS_OSX
186
+ _textView.adjustsFontForContentSizeCategory = YES;
187
+ _textView.delegate = self;
188
+ #else
189
+ _textView.textInputDelegate = self;
190
+ #endif
191
+
192
+ #if !TARGET_OS_OSX
193
+ self.contentView = _textView;
194
+ #else
195
+ _textView.selectable = YES;
196
+
197
+ _scrollView = [[NSScrollView alloc] initWithFrame:CGRectZero];
198
+ _scrollView.backgroundColor = [RCTUIColor clearColor];
199
+ _scrollView.drawsBackground = NO;
200
+ _scrollView.borderType = NSNoBorder;
201
+ _scrollView.hasHorizontalRuler = NO;
202
+ _scrollView.hasVerticalRuler = NO;
203
+ _scrollView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
204
+
205
+ _textView.verticallyResizable = YES;
206
+ _textView.horizontallyResizable = YES;
207
+ _textView.textContainer.containerSize = NSMakeSize(CGFLOAT_MAX, CGFLOAT_MAX);
208
+ _textView.textContainer.widthTracksTextView = YES;
209
+
210
+ _scrollView.documentView = _textView;
211
+ self.contentView = _scrollView;
212
+ #endif
213
+
214
+ _placeholderLabel = ENRMCreatePlaceholderLabel(_textView, _formatterStyle.baseFont);
215
+ #if !TARGET_OS_OSX
216
+ _placeholderLabel.adjustsFontForContentSizeCategory = YES;
217
+ #endif
218
+
219
+ [self resetBaseTypingAttributes];
220
+
221
+ #if ENRICHED_MARKDOWN_MATH && !TARGET_OS_OSX
222
+ UITapGestureRecognizer *mathTap = [[UITapGestureRecognizer alloc] initWithTarget:self
223
+ action:@selector(handleTapForMathChip:)];
224
+ mathTap.cancelsTouchesInView = NO;
225
+ [_textView addGestureRecognizer:mathTap];
226
+ #endif
227
+ }
228
+
229
+ #if ENRICHED_MARKDOWN_MATH && !TARGET_OS_OSX
230
+
231
+ - (void)handleTapForMathChip:(UITapGestureRecognizer *)gesture
232
+ {
233
+ if (gesture.state != UIGestureRecognizerStateRecognized)
234
+ return;
235
+ CGPoint loc = [gesture locationInView:_textView];
236
+ UITextPosition *pos = [_textView closestPositionToPoint:loc];
237
+ if (!pos)
238
+ return;
239
+ NSInteger idx = [_textView offsetFromPosition:_textView.beginningOfDocument toPosition:pos];
240
+ if (idx < 0)
241
+ return;
242
+ NSTextStorage *storage = _textView.textStorage;
243
+ // The closest position can land just past the chip; probe both `idx` and `idx-1`.
244
+ ENRMMathInlineAttachment *att = nil;
245
+ NSUInteger chipIdx = NSNotFound;
246
+ if ((NSUInteger)idx < storage.length) {
247
+ id v = [storage attribute:NSAttachmentAttributeName atIndex:(NSUInteger)idx effectiveRange:NULL];
248
+ if ([v isKindOfClass:[ENRMMathInlineAttachment class]]) {
249
+ att = v;
250
+ chipIdx = (NSUInteger)idx;
251
+ }
252
+ }
253
+ if (!att && idx > 0) {
254
+ NSUInteger probe = (NSUInteger)idx - 1;
255
+ id v = [storage attribute:NSAttachmentAttributeName atIndex:probe effectiveRange:NULL];
256
+ if ([v isKindOfClass:[ENRMMathInlineAttachment class]]) {
257
+ att = v;
258
+ chipIdx = probe;
259
+ }
260
+ }
261
+ if (!att)
262
+ return;
263
+
264
+ NSRange chipRange = NSMakeRange(chipIdx, 1);
265
+ [self clearMathChipSelectionsExcept:chipRange];
266
+ att.isSelected = YES;
267
+ [att invalidateRender];
268
+ NSLayoutManager *lm = storage.layoutManagers.firstObject;
269
+ if (lm) {
270
+ [lm invalidateLayoutForCharacterRange:chipRange actualCharacterRange:NULL];
271
+ [lm ensureLayoutForCharacterRange:chipRange];
272
+ }
273
+ ENRMSetNeedsDisplay(_textView);
274
+ // Place caret right after the chip (length 0) instead of selecting the chip
275
+ // — a length-1 selection would make UITextView draw its blue range handles
276
+ // on top of our custom selected-chip background.
277
+ NSUInteger caretIndex = chipIdx + 1;
278
+ if (caretIndex > storage.length)
279
+ caretIndex = storage.length;
280
+ _activeMathChipIndex = chipIdx;
281
+ _suppressMathChipClearOnce = YES;
282
+ _textView.selectedRange = NSMakeRange(caretIndex, 0);
283
+
284
+ NSRange glyphRange = [lm glyphRangeForCharacterRange:chipRange actualCharacterRange:NULL];
285
+ CGRect glyphRect = [lm boundingRectForGlyphRange:glyphRange inTextContainer:_textView.textContainer];
286
+ glyphRect.origin.x += _textView.textContainerInset.left;
287
+ glyphRect.origin.y += _textView.textContainerInset.top;
288
+ CGRect rectInSelf = [self.contentView convertRect:glyphRect fromView:_textView];
289
+
290
+ [self emitOnMathPressWithLatex:att.latex start:chipIdx end:chipIdx + 1 displayMode:att.displayMode rect:rectInSelf];
291
+ }
292
+
293
+ - (void)emitOnMathPressWithLatex:(NSString *)latex
294
+ start:(NSUInteger)start
295
+ end:(NSUInteger)end
296
+ displayMode:(BOOL)displayMode
297
+ rect:(CGRect)rect
298
+ {
299
+ auto emitter = [self getEventEmitter];
300
+ if (emitter == nullptr)
301
+ return;
302
+ emitter->onMathPress({
303
+ .latex = std::string([latex UTF8String] ?: ""),
304
+ .start = static_cast<int>(start),
305
+ .end = static_cast<int>(end),
306
+ .displayMode = displayMode ? true : false,
307
+ .x = rect.origin.x,
308
+ .y = rect.origin.y,
309
+ .width = rect.size.width,
310
+ .height = rect.size.height,
311
+ });
312
+ }
313
+
314
+ #endif
315
+
316
+ #pragma mark - State
317
+
318
+ - (void)updateState:(const facebook::react::State::Shared &)state
319
+ oldState:(const facebook::react::State::Shared &)oldState
320
+ {
321
+ _state = std::static_pointer_cast<const EnrichedMarkdownTextInputShadowNode::ConcreteState>(state);
322
+
323
+ if (oldState == nullptr) {
324
+ [self requestHeightUpdate];
325
+ }
326
+ }
327
+
328
+ - (void)requestHeightUpdate
329
+ {
330
+ ENRMRequestHeightUpdate<EnrichedMarkdownTextInputState>(_state, _heightUpdateCounter, self);
331
+ }
332
+
333
+ /// Yoga-resolved direction inherited from any ancestor `direction` style.
334
+ /// In FirstStrong mode this feeds the neutral-paragraph fallback, so a change
335
+ /// requires re-resolving per-paragraph directions over the current text.
336
+ - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics
337
+ oldLayoutMetrics:(const LayoutMetrics &)oldLayoutMetrics
338
+ {
339
+ [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:oldLayoutMetrics];
340
+
341
+ NSWritingDirection resolved = _resolvedLayoutDirection;
342
+ if (layoutMetrics.layoutDirection == LayoutDirection::RightToLeft) {
343
+ resolved = NSWritingDirectionRightToLeft;
344
+ } else if (layoutMetrics.layoutDirection == LayoutDirection::LeftToRight) {
345
+ resolved = NSWritingDirectionLeftToRight;
346
+ }
347
+
348
+ if (resolved != _resolvedLayoutDirection) {
349
+ _resolvedLayoutDirection = resolved;
350
+ if (_writingDirectionMode == ENRMWritingDirectionModeFirstStrong && _textView.textStorage.length > 0) {
351
+ [self applyFormatting];
352
+ }
353
+ }
354
+ }
355
+
356
+ #pragma mark - Measurement
357
+
358
+ - (CGSize)measureSize:(CGFloat)maxWidth
359
+ {
360
+ NSMutableAttributedString *measuredText =
361
+ [[NSMutableAttributedString alloc] initWithAttributedString:ENRMGetAttributedText(_textView)];
362
+
363
+ // Empty input should still be the height of a single line.
364
+ // Use typingAttributes so the measurement matches the actual configured font.
365
+ if (measuredText.length == 0) {
366
+ [measuredText appendAttributedString:[[NSAttributedString alloc] initWithString:@"I"
367
+ attributes:_textView.typingAttributes]];
368
+ }
369
+
370
+ // Trailing newlines are not counted by boundingRectWithSize — append
371
+ // a mock character so the extra line is included in the height.
372
+ if (measuredText.length > 0) {
373
+ unichar lastChar = [measuredText.string characterAtIndex:measuredText.length - 1];
374
+ if ([[NSCharacterSet newlineCharacterSet] characterIsMember:lastChar]) {
375
+ [measuredText appendAttributedString:[[NSAttributedString alloc] initWithString:@"I"
376
+ attributes:_textView.typingAttributes]];
377
+ }
378
+ }
379
+
380
+ CGRect boundingBox =
381
+ [measuredText boundingRectWithSize:CGSizeMake(maxWidth, CGFLOAT_MAX)
382
+ options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
383
+ context:nil];
384
+
385
+ return CGSizeMake(maxWidth, ceil(boundingBox.size.height));
386
+ }
387
+
388
+ #pragma mark - Props
389
+
390
+ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
391
+ {
392
+ const auto &oldViewProps = *std::static_pointer_cast<EnrichedMarkdownTextInputProps const>(_props);
393
+ const auto &newViewProps = *std::static_pointer_cast<EnrichedMarkdownTextInputProps const>(props);
394
+
395
+ if (newViewProps.editable != oldViewProps.editable) {
396
+ _textView.editable = newViewProps.editable;
397
+ }
398
+
399
+ #if !TARGET_OS_OSX
400
+ if (newViewProps.scrollEnabled != oldViewProps.scrollEnabled) {
401
+ _textView.scrollEnabled = newViewProps.scrollEnabled;
402
+ }
403
+
404
+ if (newViewProps.autoCapitalize != oldViewProps.autoCapitalize) {
405
+ NSString *value = [NSString stringWithUTF8String:newViewProps.autoCapitalize.c_str()];
406
+ _textView.autocapitalizationType = ENRMAutocapitalizationTypeFromString(value);
407
+ if ([_textView isFirstResponder]) {
408
+ [_textView resignFirstResponder];
409
+ [_textView becomeFirstResponder];
410
+ }
411
+ }
412
+
413
+ if (newViewProps.multiline != oldViewProps.multiline) {
414
+ _textView.textContainer.maximumNumberOfLines = newViewProps.multiline ? 0 : 1;
415
+ _textView.textContainer.lineBreakMode =
416
+ newViewProps.multiline ? NSLineBreakByWordWrapping : NSLineBreakByTruncatingTail;
417
+ }
418
+ #endif
419
+
420
+ if (newViewProps.placeholder != oldViewProps.placeholder) {
421
+ ENRMSetPlaceholderText(_placeholderLabel, [NSString stringWithUTF8String:newViewProps.placeholder.c_str()]);
422
+ }
423
+
424
+ if (newViewProps.placeholderTextColor != oldViewProps.placeholderTextColor) {
425
+ if (isColorMeaningful(newViewProps.placeholderTextColor)) {
426
+ _placeholderLabel.textColor = RCTUIColorFromSharedColor(newViewProps.placeholderTextColor);
427
+ }
428
+ }
429
+
430
+ if (newViewProps.cursorColor != oldViewProps.cursorColor) {
431
+ if (isColorMeaningful(newViewProps.cursorColor)) {
432
+ ENRMSetCursorColor(_textView, RCTUIColorFromSharedColor(newViewProps.cursorColor));
433
+ }
434
+ }
435
+
436
+ if (newViewProps.selectionColor != oldViewProps.selectionColor) {
437
+ ENRMApplySelectionColor(_textView, newViewProps.selectionColor);
438
+ }
439
+
440
+ _emitMarkdown = newViewProps.isOnChangeMarkdownSet;
441
+
442
+ {
443
+ auto configFromProp = [](const auto &prop) {
444
+ return [[ENRMLinkRegexConfig alloc] initWithPattern:[NSString stringWithUTF8String:prop.pattern.c_str()]
445
+ caseInsensitive:prop.caseInsensitive
446
+ dotAll:prop.dotAll
447
+ isDisabled:prop.isDisabled
448
+ isDefault:prop.isDefault];
449
+ };
450
+ ENRMLinkRegexConfig *oldRegexConfig = configFromProp(oldViewProps.linkRegex);
451
+ ENRMLinkRegexConfig *newRegexConfig = configFromProp(newViewProps.linkRegex);
452
+ if (![newRegexConfig isEqualToConfig:oldRegexConfig]) {
453
+ [_autoLinkDetector setRegexConfig:newRegexConfig];
454
+ }
455
+ }
456
+
457
+ if (ENRMContextMenuItemsChanged(oldViewProps.contextMenuItems, newViewProps.contextMenuItems)) {
458
+ _contextMenuItemTexts = ENRMContextMenuTextsFromItems(newViewProps.contextMenuItems);
459
+ _contextMenuItemIcons = ENRMContextMenuIconsFromItems(newViewProps.contextMenuItems);
460
+ }
461
+
462
+ if (newViewProps.mentionIndicators != oldViewProps.mentionIndicators) {
463
+ NSMutableArray<NSString *> *indicators = [NSMutableArray array];
464
+ for (const auto &indicator : newViewProps.mentionIndicators) {
465
+ NSString *value = [NSString stringWithUTF8String:indicator.c_str()];
466
+ if (value.length > 0) {
467
+ [indicators addObject:value];
468
+ }
469
+ }
470
+ _mentionIndicators = [indicators copy];
471
+ if (_activeMentionIndicator != nil && ![_mentionIndicators containsObject:_activeMentionIndicator]) {
472
+ [self clearActiveMention:_activeMentionIndicator];
473
+ }
474
+ [self updateActiveMention];
475
+ }
476
+
477
+ BOOL styleChanged = applyInputStyleProps(_formatterStyle, newViewProps, oldViewProps);
478
+
479
+ BOOL writingDirectionChanged = NO;
480
+ if (newViewProps.writingDirection != oldViewProps.writingDirection) {
481
+ NSString *value = [[NSString alloc] initWithUTF8String:newViewProps.writingDirection.c_str()];
482
+ _writingDirectionMode = ENRMResolveWritingDirectionMode(value);
483
+ writingDirectionChanged = YES;
484
+ }
485
+
486
+ if (newViewProps.defaultValue != oldViewProps.defaultValue) {
487
+ if (!newViewProps.defaultValue.empty() && oldViewProps.defaultValue.empty()) {
488
+ NSString *markdown = [NSString stringWithUTF8String:newViewProps.defaultValue.c_str()];
489
+ [self importMarkdown:markdown];
490
+ }
491
+ }
492
+
493
+ if (styleChanged) {
494
+ _placeholderLabel.font = _formatterStyle.baseFont;
495
+
496
+ [self resetBaseTypingAttributes];
497
+
498
+ if (_formattingStore.allRanges.count > 0) {
499
+ [self applyFormatting];
500
+ }
501
+
502
+ #if ENRICHED_MARKDOWN_MATH && !TARGET_OS_OSX
503
+ [self refreshAllMathChips];
504
+ #endif
505
+
506
+ [self requestHeightUpdate];
507
+ } else if (writingDirectionChanged && _textView.textStorage.length > 0) {
508
+ [self applyFormatting];
509
+ }
510
+
511
+ [super updateProps:props oldProps:oldProps];
512
+ }
513
+
514
+ #pragma mark - Relayout
515
+
516
+ - (void)scheduleRelayoutIfNeeded
517
+ {
518
+ [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_performRelayout) object:nil];
519
+ [self performSelector:@selector(_performRelayout) withObject:nil afterDelay:0];
520
+ }
521
+
522
+ - (void)_performRelayout
523
+ {
524
+ if (!_textView) {
525
+ return;
526
+ }
527
+
528
+ dispatch_async(dispatch_get_main_queue(), ^{
529
+ NSUInteger textLength = self->_textView.textStorage.length;
530
+ if (textLength == 0) {
531
+ return;
532
+ }
533
+ NSRange wholeRange = NSMakeRange(0, textLength);
534
+ NSRange actualRange = NSMakeRange(0, 0);
535
+ [self->_textView.layoutManager invalidateLayoutForCharacterRange:wholeRange actualCharacterRange:&actualRange];
536
+ [self->_textView.layoutManager ensureLayoutForCharacterRange:actualRange];
537
+ [self->_textView.layoutManager invalidateDisplayForCharacterRange:wholeRange];
538
+
539
+ CGSize measuredSize = [self measureSize:self->_textView.frame.size.width];
540
+ ENRMSetContentSize(self->_textView, measuredSize);
541
+ });
542
+ }
543
+
544
+ #pragma mark - Window attachment
545
+
546
+ - (void)didMoveToWindow
547
+ {
548
+ [super didMoveToWindow];
549
+
550
+ if (self.window) {
551
+ // Don't override the contentView frame set by RCTViewComponentView.
552
+ ENRMRefreshTextViewLayout(_textView);
553
+
554
+ [self applyFormatting];
555
+ [self updatePlaceholderVisibility];
556
+ [self requestHeightUpdate];
557
+
558
+ const auto &viewProps = *std::static_pointer_cast<EnrichedMarkdownTextInputProps const>(_props);
559
+ if (viewProps.autoFocus) {
560
+ ENRMFocusTextView(_textView);
561
+ }
562
+ }
563
+ }
564
+
565
+ #if TARGET_OS_OSX
566
+
567
+ #pragma mark - macOS responder chain
568
+
569
+ - (BOOL)acceptsFirstResponder
570
+ {
571
+ return _textView.acceptsFirstResponder;
572
+ }
573
+
574
+ - (BOOL)becomeFirstResponder
575
+ {
576
+ return [self.window makeFirstResponder:_textView];
577
+ }
578
+
579
+ - (BOOL)needsPanelToBecomeKey
580
+ {
581
+ return YES;
582
+ }
583
+
584
+ - (BOOL)mouseDownCanMoveWindow
585
+ {
586
+ return NO;
587
+ }
588
+
589
+ - (void)mouseDown:(NSEvent *)event
590
+ {
591
+ [self.window makeFirstResponder:_textView];
592
+ [_textView mouseDown:event];
593
+ }
594
+
595
+ #endif
596
+
597
+ #if !TARGET_OS_OSX
598
+ - (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection
599
+ {
600
+ [super traitCollectionDidChange:previousTraitCollection];
601
+
602
+ if (previousTraitCollection.preferredContentSizeCategory != self.traitCollection.preferredContentSizeCategory) {
603
+ [_formatterStyle invalidateFontCache];
604
+
605
+ [self resetBaseTypingAttributes];
606
+
607
+ _placeholderLabel.font = _formatterStyle.baseFont;
608
+
609
+ [self applyFormatting];
610
+ [self requestHeightUpdate];
611
+ }
612
+ }
613
+ #endif
614
+
615
+ #pragma mark - Placeholder
616
+
617
+ - (void)updatePlaceholderVisibility
618
+ {
619
+ _placeholderLabel.hidden = (ENRMGetPlainText(_textView).length > 0);
620
+ }
621
+
622
+ #pragma mark - Markdown import
623
+
624
+ - (void)importMarkdown:(NSString *)markdown
625
+ {
626
+ ENRMInputParser *parser = [[ENRMInputParser alloc] init];
627
+ ENRMParseResult *parsed = [parser parseToPlainTextAndRanges:markdown];
628
+
629
+ _blockEmitting = YES;
630
+
631
+ _isApplyingFormatting = YES;
632
+ ENRMSetPlainText(_textView, parsed.plainText);
633
+
634
+ #if ENRICHED_MARKDOWN_MATH && !TARGET_OS_OSX
635
+ if (parsed.mathAtoms.count > 0) {
636
+ NSTextStorage *storage = _textView.textStorage;
637
+ [storage beginEditing];
638
+ for (ENRMMathAtom *atom in parsed.mathAtoms) {
639
+ if (atom.position >= storage.length)
640
+ continue;
641
+ unichar c = [storage.string characterAtIndex:atom.position];
642
+ if (c != (unichar)0xFFFC)
643
+ continue;
644
+ ENRMMathInlineAttachment *att = [self createMathAttachmentWithLatex:atom.latex displayMode:atom.displayMode];
645
+ NSAttributedString *replacement = [NSAttributedString attributedStringWithAttachment:att];
646
+ [storage replaceCharactersInRange:NSMakeRange(atom.position, 1) withAttributedString:replacement];
647
+ if (atom.displayMode && _formatterStyle.mathBlockAlignment != NSTextAlignmentNatural) {
648
+ NSMutableParagraphStyle *ps = [[NSMutableParagraphStyle alloc] init];
649
+ ps.alignment = _formatterStyle.mathBlockAlignment;
650
+ [storage addAttribute:NSParagraphStyleAttributeName value:ps range:NSMakeRange(atom.position, 1)];
651
+ }
652
+ }
653
+ [storage endEditing];
654
+ }
655
+ #endif
656
+
657
+ _isApplyingFormatting = NO;
658
+
659
+ [_formattingStore setRanges:parsed.formattingRanges];
660
+ _lastTextLength = parsed.plainText.length;
661
+ _lastSelectedRange = _textView.selectedRange;
662
+ [self applyFormatting];
663
+ [self updatePlaceholderVisibility];
664
+
665
+ _blockEmitting = NO;
666
+ }
667
+
668
+ #if ENRICHED_MARKDOWN_MATH && !TARGET_OS_OSX
669
+
670
+ - (void)applyMathStyleToAttachment:(ENRMMathInlineAttachment *)att
671
+ {
672
+ if (att.displayMode) {
673
+ att.fontSize = _formatterStyle.mathBlockFontSize > 0 ? _formatterStyle.mathBlockFontSize : 20.0;
674
+ att.mathTextColor = _formatterStyle.mathBlockColor ?: _formatterStyle.baseTextColor;
675
+ att.containerBackgroundColor = _formatterStyle.mathBlockBackgroundColor;
676
+ att.containerBorderColor = _formatterStyle.mathBlockBorderColor;
677
+ att.containerBorderWidth = _formatterStyle.mathBlockBorderWidth;
678
+ att.containerBorderRadius = _formatterStyle.mathBlockBorderRadius;
679
+ att.containerPaddingHorizontal = _formatterStyle.mathBlockPaddingHorizontal;
680
+ att.containerPaddingVertical = _formatterStyle.mathBlockPaddingVertical;
681
+ att.blockMarginTop = _formatterStyle.mathBlockMarginTop;
682
+ att.blockMarginBottom = _formatterStyle.mathBlockMarginBottom;
683
+ att.blockAlignment = _formatterStyle.mathBlockAlignment;
684
+ att.selectedBackgroundColor = _formatterStyle.mathBlockSelectedBackgroundColor;
685
+ att.selectedBorderColor = _formatterStyle.mathBlockSelectedBorderColor;
686
+ } else {
687
+ att.fontSize = _formatterStyle.mathFontSize > 0 ? _formatterStyle.mathFontSize : 16.0;
688
+ att.mathTextColor = _formatterStyle.mathColor ?: _formatterStyle.baseTextColor;
689
+ att.containerBackgroundColor = _formatterStyle.mathBackgroundColor;
690
+ att.containerBorderColor = _formatterStyle.mathBorderColor;
691
+ att.containerBorderWidth = _formatterStyle.mathBorderWidth;
692
+ att.containerBorderRadius = _formatterStyle.mathBorderRadius;
693
+ att.containerPaddingHorizontal = _formatterStyle.mathPaddingHorizontal;
694
+ att.containerPaddingVertical = _formatterStyle.mathPaddingVertical;
695
+ att.blockMarginTop = 0;
696
+ att.blockMarginBottom = 0;
697
+ att.blockAlignment = NSTextAlignmentNatural;
698
+ att.selectedBackgroundColor = _formatterStyle.mathSelectedBackgroundColor;
699
+ att.selectedBorderColor = _formatterStyle.mathSelectedBorderColor;
700
+ }
701
+ }
702
+
703
+ - (ENRMMathInlineAttachment *)createMathAttachmentWithLatex:(NSString *)latex displayMode:(BOOL)displayMode
704
+ {
705
+ ENRMMathInlineAttachment *att = [[ENRMMathInlineAttachment alloc] init];
706
+ att.latex = latex ?: @"";
707
+ att.displayMode = displayMode;
708
+ [self applyMathStyleToAttachment:att];
709
+ return att;
710
+ }
711
+
712
+ - (void)refreshAllMathChips
713
+ {
714
+ NSTextStorage *storage = _textView.textStorage;
715
+ if (storage.length == 0)
716
+ return;
717
+ __weak EnrichedMarkdownTextInput *weakSelf = self;
718
+ [storage beginEditing];
719
+ [storage enumerateAttribute:NSAttachmentAttributeName
720
+ inRange:NSMakeRange(0, storage.length)
721
+ options:0
722
+ usingBlock:^(id value, NSRange range, BOOL *stop) {
723
+ EnrichedMarkdownTextInput *strongSelf = weakSelf;
724
+ if (!strongSelf)
725
+ return;
726
+ if ([value isKindOfClass:[ENRMMathInlineAttachment class]]) {
727
+ ENRMMathInlineAttachment *att = value;
728
+ [strongSelf applyMathStyleToAttachment:att];
729
+ [att invalidateRender];
730
+ }
731
+ }];
732
+ [storage endEditing];
733
+
734
+ NSLayoutManager *lm = storage.layoutManagers.firstObject;
735
+ if (lm) {
736
+ NSRange fullRange = NSMakeRange(0, storage.length);
737
+ [lm invalidateLayoutForCharacterRange:fullRange actualCharacterRange:NULL];
738
+ [lm ensureLayoutForCharacterRange:fullRange];
739
+ }
740
+ ENRMSetNeedsDisplay(_textView);
741
+ }
742
+
743
+ #endif
744
+
745
+ - (void)replaceTextInRange:(NSRange)selection
746
+ withText:(NSString *)text
747
+ formattingRanges:(NSArray<ENRMFormattingRange *> *)ranges
748
+ {
749
+ NSUInteger editLocation = selection.location;
750
+
751
+ _isApplyingFormatting = YES;
752
+ ENRMReplaceTextInRange(_textView, text, selection);
753
+ _isApplyingFormatting = NO;
754
+
755
+ [_formattingStore adjustForEditAtLocation:editLocation deletedLength:selection.length insertedLength:text.length];
756
+
757
+ for (ENRMFormattingRange *range in ranges) {
758
+ NSRange shifted = NSMakeRange(range.range.location + editLocation, range.range.length);
759
+ [_formattingStore addRange:[ENRMFormattingRange rangeWithType:range.type range:shifted url:range.url]];
760
+ }
761
+
762
+ _lastTextLength = ENRMGetPlainText(_textView).length;
763
+ _lastSelectedRange = _textView.selectedRange;
764
+
765
+ [self applyFormatting];
766
+
767
+ [_detectorPipeline processTextChange:ENRMGetPlainText(_textView)
768
+ modificationRange:NSMakeRange(editLocation, text.length)];
769
+
770
+ [self updatePlaceholderVisibility];
771
+ [self emitOnChangeText];
772
+ [self emitOnChangeSelection];
773
+ [self emitFormattingChanged];
774
+ [self requestHeightUpdate];
775
+ [self scheduleRelayoutIfNeeded];
776
+ }
777
+
778
+ - (void)replaceSelectedTextWith:(NSString *)text formattingRanges:(NSArray<ENRMFormattingRange *> *)ranges
779
+ {
780
+ [self replaceTextInRange:_textView.selectedRange withText:text formattingRanges:ranges];
781
+ }
782
+
783
+ - (void)pasteMarkdown:(NSString *)markdown
784
+ {
785
+ ENRMInputParser *parser = [[ENRMInputParser alloc] init];
786
+ ENRMParseResult *parsed = [parser parseToPlainTextAndRanges:markdown];
787
+ [self replaceSelectedTextWith:parsed.plainText formattingRanges:parsed.formattingRanges];
788
+ }
789
+
790
+ #pragma mark - Formatting
791
+
792
+ - (void)resetBaseTypingAttributes
793
+ {
794
+ ENRMSetDefaultTypingAttributes(_textView, @{
795
+ NSFontAttributeName : _formatterStyle.baseFont,
796
+ NSForegroundColorAttributeName : _formatterStyle.baseTextColor,
797
+ });
798
+ }
799
+
800
+ - (void)applyFormatting
801
+ {
802
+ if (_isApplyingFormatting) {
803
+ return;
804
+ }
805
+ if (ENRMHasMarkedText(_textView)) {
806
+ return;
807
+ }
808
+ _isApplyingFormatting = YES;
809
+
810
+ NSRange savedSelection = _textView.selectedRange;
811
+
812
+ [_formatter applyFormattingRanges:_formattingStore.allRanges toTextView:_textView style:_formatterStyle];
813
+ [_detectorPipeline refreshAllStyling];
814
+ [self applyWritingDirection];
815
+
816
+ NSUInteger textLen = ENRMGetPlainText(_textView).length;
817
+ if (savedSelection.location + savedSelection.length <= textLen) {
818
+ _textView.selectedRange = savedSelection;
819
+ }
820
+
821
+ _isApplyingFormatting = NO;
822
+ }
823
+
824
+ - (void)applyWritingDirection
825
+ {
826
+ NSTextStorage *textStorage = _textView.textStorage;
827
+ if (textStorage.length == 0) {
828
+ return;
829
+ }
830
+ [textStorage beginEditing];
831
+ ENRMApplyWritingDirectionMode(textStorage, _writingDirectionMode, _resolvedLayoutDirection);
832
+ [textStorage endEditing];
833
+ }
834
+
835
+ #pragma mark - Commands
836
+
837
+ - (void)focus
838
+ {
839
+ ENRMFocusTextView(_textView);
840
+ }
841
+
842
+ - (void)blur
843
+ {
844
+ ENRMBlurTextView(_textView);
845
+ }
846
+
847
+ - (void)setValue:(NSString *)markdown
848
+ {
849
+ [self importMarkdown:markdown];
850
+ _lastSelectedRange = _textView.selectedRange;
851
+ [self emitOnChangeText];
852
+ [self emitOnChangeSelection];
853
+ [self emitOnChangeState];
854
+ [self requestHeightUpdate];
855
+ }
856
+
857
+ - (void)setSelection:(NSInteger)start end:(NSInteger)end
858
+ {
859
+ NSInteger textLen = (NSInteger)ENRMGetPlainText(_textView).length;
860
+ NSInteger clampedStart = MIN(MAX(start, 0), textLen);
861
+ NSInteger clampedEnd = MIN(MAX(end, clampedStart), textLen);
862
+ _textView.selectedRange = NSMakeRange((NSUInteger)clampedStart, (NSUInteger)(clampedEnd - clampedStart));
863
+ [self emitOnChangeSelection];
864
+ [self emitOnChangeState];
865
+ }
866
+
867
+ - (void)toggleBold
868
+ {
869
+ [self toggleInlineStyle:ENRMInputStyleTypeStrong];
870
+ }
871
+
872
+ - (void)toggleItalic
873
+ {
874
+ [self toggleInlineStyle:ENRMInputStyleTypeEmphasis];
875
+ }
876
+
877
+ - (void)toggleUnderline
878
+ {
879
+ [self toggleInlineStyle:ENRMInputStyleTypeUnderline];
880
+ }
881
+
882
+ - (void)toggleStrikethrough
883
+ {
884
+ [self toggleInlineStyle:ENRMInputStyleTypeStrikethrough];
885
+ }
886
+
887
+ - (void)toggleSpoiler
888
+ {
889
+ [self toggleInlineStyle:ENRMInputStyleTypeSpoiler];
890
+ }
891
+
892
+ - (void)toggleInlineStyle:(ENRMInputStyleType)styleType
893
+ {
894
+ id<ENRMStyleHandler> handler = [_formatter handlerForStyleType:styleType];
895
+ if (!handler) {
896
+ return;
897
+ }
898
+ ENRMStyleMergingConfig *mergingConfig = handler.mergingConfig;
899
+
900
+ NSRange selection = _textView.selectedRange;
901
+ NSUInteger cursor = selection.location;
902
+ NSNumber *key = @(styleType);
903
+
904
+ // Check blocking rules: if any blocking style is active, refuse to toggle on.
905
+ if (mergingConfig.blockingStyles.count > 0) {
906
+ BOOL isCurrentlyActive = [_formattingStore isStyleActive:styleType atPosition:cursor];
907
+ if (!isCurrentlyActive) {
908
+ for (NSNumber *blockerNum in mergingConfig.blockingStyles) {
909
+ if ([_formattingStore isStyleActive:(ENRMInputStyleType)blockerNum.integerValue atPosition:cursor]) {
910
+ return;
911
+ }
912
+ }
913
+ }
914
+ }
915
+
916
+ if (selection.length > 0) {
917
+ BOOL fullyStyled = YES;
918
+ NSUInteger pos = selection.location;
919
+ NSUInteger selEnd = NSMaxRange(selection);
920
+ while (pos < selEnd) {
921
+ ENRMFormattingRange *match = [_formattingStore rangeOfType:styleType containingPosition:pos];
922
+ if (match == nil) {
923
+ fullyStyled = NO;
924
+ break;
925
+ }
926
+ pos = NSMaxRange(match.range);
927
+ }
928
+ if (fullyStyled) {
929
+ [_formattingStore removeType:styleType inRange:selection];
930
+ } else {
931
+ // Remove conflicting styles from the range before applying.
932
+ for (NSNumber *conflictNum in mergingConfig.conflictingStyles) {
933
+ [_formattingStore removeType:(ENRMInputStyleType)conflictNum.integerValue inRange:selection];
934
+ }
935
+ ENRMFormattingRange *newRange = [ENRMFormattingRange rangeWithType:styleType range:selection];
936
+ [_formattingStore addRange:newRange];
937
+ }
938
+ [_pendingStyles removeObject:key];
939
+ [_pendingStyleRemovals removeObject:key];
940
+ } else {
941
+ BOOL isInsideRange = [_formattingStore isStyleActive:styleType atPosition:cursor];
942
+
943
+ if ([_pendingStyleRemovals containsObject:key]) {
944
+ [_pendingStyleRemovals removeObject:key];
945
+ } else if ([_pendingStyles containsObject:key]) {
946
+ [_pendingStyles removeObject:key];
947
+ } else if (isInsideRange) {
948
+ [_pendingStyleRemovals addObject:key];
949
+ } else {
950
+ [_pendingStyles addObject:key];
951
+ }
952
+ }
953
+
954
+ [self applyFormatting];
955
+ [self emitFormattingChanged];
956
+ }
957
+
958
+ - (void)setLink:(NSString *)url
959
+ {
960
+ NSRange selection = _textView.selectedRange;
961
+ NSUInteger cursor = selection.location;
962
+
963
+ ENRMFormattingRange *activeLink = [_formattingStore rangeOfType:ENRMInputStyleTypeLink containingPosition:cursor];
964
+
965
+ if (activeLink != nil) {
966
+ activeLink.url = url;
967
+ [_autoLinkDetector clearAutoLinkInRange:activeLink.range];
968
+ } else if (selection.length > 0) {
969
+ ENRMFormattingRange *linkRange = [ENRMFormattingRange rangeWithType:ENRMInputStyleTypeLink range:selection url:url];
970
+ [_formattingStore addRange:linkRange];
971
+ [_autoLinkDetector clearAutoLinkInRange:selection];
972
+ } else {
973
+ return;
974
+ }
975
+
976
+ [self applyFormatting];
977
+ [self emitFormattingChanged];
978
+ }
979
+
980
+ - (void)insertLink:(NSString *)text url:(NSString *)url
981
+ {
982
+ NSString *displayText = text.length > 0 ? text : url;
983
+ NSRange linkRange = NSMakeRange(0, displayText.length);
984
+ ENRMFormattingRange *range = [ENRMFormattingRange rangeWithType:ENRMInputStyleTypeLink
985
+ range:linkRange
986
+ url:[self sanitizeLinkURL:url]];
987
+ [self replaceSelectedTextWith:displayText formattingRanges:@[ range ]];
988
+ }
989
+
990
+ - (NSString *)sanitizeLinkURL:(NSString *)url
991
+ {
992
+ NSString *result = [url stringByReplacingOccurrencesOfString:@"(" withString:@"%28"];
993
+ return [result stringByReplacingOccurrencesOfString:@")" withString:@"%29"];
994
+ }
995
+
996
+ - (void)startMention:(NSString *)indicator
997
+ {
998
+ if (indicator.length == 0 || ![_mentionIndicators containsObject:indicator]) {
999
+ return;
1000
+ }
1001
+
1002
+ [self replaceSelectedTextWith:indicator formattingRanges:@[]];
1003
+ [self updateActiveMention];
1004
+ }
1005
+
1006
+ - (void)insertMention:(NSString *)displayText url:(NSString *)url
1007
+ {
1008
+ if (displayText.length == 0 || _activeMentionIndicator == nil || _activeMentionRange.location == NSNotFound) {
1009
+ return;
1010
+ }
1011
+
1012
+ NSString *plainText = ENRMGetPlainText(_textView);
1013
+ NSUInteger rangeEnd = NSMaxRange(_activeMentionRange);
1014
+ if (rangeEnd > plainText.length) {
1015
+ return;
1016
+ }
1017
+ BOOL nextCharIsWhitespace = rangeEnd < plainText.length && [[NSCharacterSet whitespaceAndNewlineCharacterSet]
1018
+ characterIsMember:[plainText
1019
+ characterAtIndex:rangeEnd]];
1020
+ NSString *replacement = nextCharIsWhitespace ? displayText : [displayText stringByAppendingString:@" "];
1021
+ ENRMFormattingRange *linkRange = [ENRMFormattingRange rangeWithType:ENRMInputStyleTypeLink
1022
+ range:NSMakeRange(0, displayText.length)
1023
+ url:[self sanitizeLinkURL:url]];
1024
+ NSString *indicator = _activeMentionIndicator;
1025
+ NSRange mentionRange = _activeMentionRange;
1026
+
1027
+ [self clearActiveMention:indicator];
1028
+ [self replaceTextInRange:mentionRange withText:replacement formattingRanges:@[ linkRange ]];
1029
+ _textView.selectedRange = NSMakeRange(mentionRange.location + replacement.length, 0);
1030
+ [self emitOnChangeSelection];
1031
+ }
1032
+
1033
+ - (void)removeLink
1034
+ {
1035
+ NSUInteger cursor = _textView.selectedRange.location;
1036
+ ENRMFormattingRange *activeLink = [_formattingStore rangeOfType:ENRMInputStyleTypeLink containingPosition:cursor];
1037
+ if (activeLink == nil) {
1038
+ return;
1039
+ }
1040
+
1041
+ [_formattingStore removeRange:activeLink];
1042
+ [self applyFormatting];
1043
+ [self emitFormattingChanged];
1044
+ }
1045
+
1046
+ #pragma mark - Math chip commands
1047
+
1048
+ - (void)insertMath:(NSString *)latex displayMode:(BOOL)displayMode
1049
+ {
1050
+ #if ENRICHED_MARKDOWN_MATH && !TARGET_OS_OSX
1051
+ if (latex.length == 0)
1052
+ return;
1053
+ NSTextStorage *storage = _textView.textStorage;
1054
+ NSRange selection = _textView.selectedRange;
1055
+ NSString *plainText = ENRMGetPlainText(_textView);
1056
+
1057
+ NSMutableString *prefix = [NSMutableString string];
1058
+ NSMutableString *suffix = [NSMutableString string];
1059
+ if (displayMode) {
1060
+ BOOL atLineStart = (selection.location == 0) || [plainText characterAtIndex:selection.location - 1] == '\n';
1061
+ NSUInteger afterSel = selection.location + selection.length;
1062
+ BOOL atLineEnd = (afterSel >= plainText.length) || [plainText characterAtIndex:afterSel] == '\n';
1063
+ if (!atLineStart)
1064
+ [prefix appendString:@"\n"];
1065
+ if (!atLineEnd)
1066
+ [suffix appendString:@"\n"];
1067
+ }
1068
+
1069
+ ENRMMathInlineAttachment *att = [self createMathAttachmentWithLatex:latex displayMode:displayMode];
1070
+ NSMutableAttributedString *replacement = [[NSMutableAttributedString alloc] init];
1071
+ if (prefix.length) {
1072
+ [replacement appendAttributedString:[[NSAttributedString alloc] initWithString:prefix]];
1073
+ }
1074
+ [replacement appendAttributedString:[NSAttributedString attributedStringWithAttachment:att]];
1075
+ if (suffix.length) {
1076
+ [replacement appendAttributedString:[[NSAttributedString alloc] initWithString:suffix]];
1077
+ }
1078
+
1079
+ if (displayMode && att.blockAlignment != NSTextAlignmentNatural) {
1080
+ NSMutableParagraphStyle *ps = [[NSMutableParagraphStyle alloc] init];
1081
+ ps.alignment = att.blockAlignment;
1082
+ NSRange chipRange = NSMakeRange(prefix.length, 1);
1083
+ [replacement addAttribute:NSParagraphStyleAttributeName value:ps range:chipRange];
1084
+ }
1085
+
1086
+ _isApplyingFormatting = YES;
1087
+ [storage replaceCharactersInRange:selection withAttributedString:replacement];
1088
+ _isApplyingFormatting = NO;
1089
+
1090
+ NSUInteger insertedLength = replacement.length;
1091
+ [_formattingStore adjustForEditAtLocation:selection.location
1092
+ deletedLength:selection.length
1093
+ insertedLength:insertedLength];
1094
+
1095
+ NSUInteger newCursor = selection.location + insertedLength;
1096
+ _textView.selectedRange = NSMakeRange(newCursor, 0);
1097
+ _lastTextLength = ENRMGetPlainText(_textView).length;
1098
+ _lastSelectedRange = _textView.selectedRange;
1099
+
1100
+ [self applyFormatting];
1101
+ [self updatePlaceholderVisibility];
1102
+ [self emitOnChangeText];
1103
+ [self emitOnChangeSelection];
1104
+ [self emitFormattingChanged];
1105
+ [self requestHeightUpdate];
1106
+ [self scheduleRelayoutIfNeeded];
1107
+ #endif
1108
+ }
1109
+
1110
+ - (void)updateMath:(NSInteger)start latex:(NSString *)latex displayMode:(BOOL)displayMode
1111
+ {
1112
+ #if ENRICHED_MARKDOWN_MATH && !TARGET_OS_OSX
1113
+ NSTextStorage *storage = _textView.textStorage;
1114
+ if (start < 0 || (NSUInteger)start >= storage.length)
1115
+ return;
1116
+ id value = [storage attribute:NSAttachmentAttributeName atIndex:(NSUInteger)start effectiveRange:NULL];
1117
+ if (![value isKindOfClass:[ENRMMathInlineAttachment class]])
1118
+ return;
1119
+
1120
+ ENRMMathInlineAttachment *att = value;
1121
+ BOOL modeChanged = (att.displayMode != displayMode);
1122
+ att.latex = latex ?: @"";
1123
+ att.displayMode = displayMode;
1124
+ [self applyMathStyleToAttachment:att];
1125
+ [att invalidateRender];
1126
+
1127
+ NSRange chipRange = NSMakeRange((NSUInteger)start, 1);
1128
+ if (modeChanged) {
1129
+ [storage beginEditing];
1130
+ if (displayMode && att.blockAlignment != NSTextAlignmentNatural) {
1131
+ NSMutableParagraphStyle *ps = [[NSMutableParagraphStyle alloc] init];
1132
+ ps.alignment = att.blockAlignment;
1133
+ [storage addAttribute:NSParagraphStyleAttributeName value:ps range:chipRange];
1134
+ } else {
1135
+ [storage removeAttribute:NSParagraphStyleAttributeName range:chipRange];
1136
+ }
1137
+ [storage endEditing];
1138
+ }
1139
+
1140
+ NSLayoutManager *lm = storage.layoutManagers.firstObject;
1141
+ if (lm) {
1142
+ [lm invalidateLayoutForCharacterRange:chipRange actualCharacterRange:NULL];
1143
+ [lm ensureLayoutForCharacterRange:chipRange];
1144
+ }
1145
+ ENRMSetNeedsDisplay(_textView);
1146
+
1147
+ if (_emitMarkdown) {
1148
+ [self emitOnChangeMarkdown];
1149
+ }
1150
+ [self requestHeightUpdate];
1151
+ [self scheduleRelayoutIfNeeded];
1152
+ #endif
1153
+ }
1154
+
1155
+ - (void)removeMath:(NSInteger)start
1156
+ {
1157
+ #if ENRICHED_MARKDOWN_MATH && !TARGET_OS_OSX
1158
+ NSTextStorage *storage = _textView.textStorage;
1159
+ if (start < 0 || (NSUInteger)start >= storage.length)
1160
+ return;
1161
+ id value = [storage attribute:NSAttachmentAttributeName atIndex:(NSUInteger)start effectiveRange:NULL];
1162
+ if (![value isKindOfClass:[ENRMMathInlineAttachment class]])
1163
+ return;
1164
+
1165
+ [self replaceTextInRange:NSMakeRange((NSUInteger)start, 1) withText:@"" formattingRanges:@[]];
1166
+ #endif
1167
+ }
1168
+
1169
+ - (void)showLinkPrompt
1170
+ {
1171
+ NSUInteger cursor = _textView.selectedRange.location;
1172
+ ENRMFormattingRange *activeLink = [_formattingStore rangeOfType:ENRMInputStyleTypeLink containingPosition:cursor];
1173
+ NSString *existingURL = activeLink != nil ? activeLink.url : nil;
1174
+
1175
+ __weak EnrichedMarkdownTextInput *weakSelf = self;
1176
+ ENRMShowLinkPrompt(self, existingURL, ^(NSString *url) { [weakSelf setLink:url]; });
1177
+ }
1178
+
1179
+ - (nullable NSString *)markdownForSelectedRange
1180
+ {
1181
+ NSRange selection = _textView.selectedRange;
1182
+ if (selection.length == 0) {
1183
+ return nil;
1184
+ }
1185
+
1186
+ NSAttributedString *full = _textView.textStorage;
1187
+ if (NSMaxRange(selection) > full.length) {
1188
+ return nil;
1189
+ }
1190
+ NSAttributedString *selectedAttr = [full attributedSubstringFromRange:selection];
1191
+ NSUInteger selEnd = NSMaxRange(selection);
1192
+
1193
+ NSMutableArray<ENRMFormattingRange *> *clippedRanges = [NSMutableArray array];
1194
+ for (ENRMFormattingRange *range in [self allRangesIncludingTransient]) {
1195
+ NSUInteger rangeStart = range.range.location;
1196
+ NSUInteger rangeEnd = NSMaxRange(range.range);
1197
+
1198
+ if (rangeEnd <= selection.location || rangeStart >= selEnd) {
1199
+ continue;
1200
+ }
1201
+
1202
+ NSUInteger clippedStart = MAX(rangeStart, selection.location);
1203
+ NSUInteger clippedEnd = MIN(rangeEnd, selEnd);
1204
+ NSRange shifted = NSMakeRange(clippedStart - selection.location, clippedEnd - clippedStart);
1205
+
1206
+ [clippedRanges addObject:[ENRMFormattingRange rangeWithType:range.type range:shifted url:range.url]];
1207
+ }
1208
+
1209
+ return [ENRMMarkdownSerializer serializeAttributedString:selectedAttr ranges:clippedRanges];
1210
+ }
1211
+
1212
+ - (void)requestMarkdown:(NSInteger)requestId
1213
+ {
1214
+ auto emitter = [self getEventEmitter];
1215
+ if (emitter == nullptr) {
1216
+ return;
1217
+ }
1218
+ NSString *markdown = [ENRMMarkdownSerializer serializeAttributedString:_textView.textStorage
1219
+ ranges:[self allRangesIncludingTransient]];
1220
+ emitter->onRequestMarkdownResult({
1221
+ .requestId = static_cast<int>(requestId),
1222
+ .markdown = std::string([markdown UTF8String] ?: ""),
1223
+ });
1224
+ }
1225
+
1226
+ - (CGRect)computeCaretRect
1227
+ {
1228
+ CGRect caretRect = CGRectZero;
1229
+ #if !TARGET_OS_OSX
1230
+ UITextRange *selectedRange = _textView.selectedTextRange;
1231
+ if (selectedRange != nil) {
1232
+ caretRect = [_textView caretRectForPosition:selectedRange.start];
1233
+ }
1234
+ #else
1235
+ NSRange selection = _textView.selectedRange;
1236
+ if (selection.location != NSNotFound) {
1237
+ NSRange glyphRange = [_textView.layoutManager glyphRangeForCharacterRange:NSMakeRange(selection.location, 0)
1238
+ actualCharacterRange:NULL];
1239
+ caretRect = [_textView.layoutManager boundingRectForGlyphRange:glyphRange inTextContainer:_textView.textContainer];
1240
+ caretRect.origin.x += _textView.textContainerInset.left;
1241
+ caretRect.origin.y += _textView.textContainerInset.top;
1242
+ }
1243
+ #endif
1244
+ return caretRect;
1245
+ }
1246
+
1247
+ - (void)requestCaretRect:(NSInteger)requestId
1248
+ {
1249
+ auto emitter = [self getEventEmitter];
1250
+ if (emitter == nullptr) {
1251
+ return;
1252
+ }
1253
+
1254
+ CGRect caretRect = [self computeCaretRect];
1255
+ emitter->onRequestCaretRectResult({
1256
+ .requestId = static_cast<int>(requestId),
1257
+ .x = caretRect.origin.x,
1258
+ .y = caretRect.origin.y,
1259
+ .width = caretRect.size.width,
1260
+ .height = caretRect.size.height,
1261
+ });
1262
+ }
1263
+
1264
+ - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
1265
+ {
1266
+ RCTEnrichedMarkdownTextInputHandleCommand(self, commandName, args);
1267
+ }
1268
+
1269
+ #pragma mark - Style state query
1270
+
1271
+ - (BOOL)isEffectiveStyleActive:(ENRMInputStyleType)type atPosition:(NSUInteger)position
1272
+ {
1273
+ BOOL inRange = [_formattingStore isStyleActive:type atPosition:position];
1274
+ NSNumber *key = @(type);
1275
+ if ([_pendingStyleRemovals containsObject:key]) {
1276
+ return NO;
1277
+ }
1278
+ if ([_pendingStyles containsObject:key]) {
1279
+ return YES;
1280
+ }
1281
+ return inRange;
1282
+ }
1283
+
1284
+ #pragma mark - Event emitters
1285
+
1286
+ - (void)emitFormattingChanged
1287
+ {
1288
+ [self emitOnChangeState];
1289
+ if (_emitMarkdown) {
1290
+ [self emitOnChangeMarkdown];
1291
+ }
1292
+ }
1293
+
1294
+ - (std::shared_ptr<EnrichedMarkdownTextInputEventEmitter const>)getEventEmitter
1295
+ {
1296
+ if (_eventEmitter == nullptr || _blockEmitting) {
1297
+ return nullptr;
1298
+ }
1299
+ return std::static_pointer_cast<EnrichedMarkdownTextInputEventEmitter const>(_eventEmitter);
1300
+ }
1301
+
1302
+ - (NSArray<ENRMFormattingRange *> *)allRangesIncludingTransient
1303
+ {
1304
+ NSArray<ENRMFormattingRange *> *transient = [_detectorPipeline allTransientFormattingRanges];
1305
+ if (transient.count == 0) {
1306
+ return _formattingStore.allRanges;
1307
+ }
1308
+ NSMutableArray<ENRMFormattingRange *> *merged = [_formattingStore.allRanges mutableCopy];
1309
+ [merged addObjectsFromArray:transient];
1310
+ return merged;
1311
+ }
1312
+
1313
+ - (void)clearActiveMention:(nullable NSString *)indicatorOverride
1314
+ {
1315
+ NSString *indicator = indicatorOverride ?: _activeMentionIndicator;
1316
+ _activeMentionIndicator = nil;
1317
+ _activeMentionRange = NSMakeRange(NSNotFound, 0);
1318
+ _activeMentionText = @"";
1319
+
1320
+ if (indicator.length > 0) {
1321
+ [self emitOnEndMention:indicator];
1322
+ }
1323
+ }
1324
+
1325
+ - (nullable ENRMInputMentionCandidate *)mentionCandidateAtCursor
1326
+ {
1327
+ NSRange selectedRange = _textView.selectedRange;
1328
+ if (_mentionIndicators.count == 0 || selectedRange.length != 0) {
1329
+ return nil;
1330
+ }
1331
+
1332
+ NSString *plainText = ENRMGetPlainText(_textView);
1333
+ NSUInteger cursor = selectedRange.location;
1334
+ if (cursor > plainText.length) {
1335
+ return nil;
1336
+ }
1337
+
1338
+ NSUInteger start = [ENRMWordsUtils tokenStartInText:plainText beforePosition:cursor];
1339
+ NSString *token = [plainText substringWithRange:NSMakeRange(start, cursor - start)];
1340
+ NSString *matchedIndicator = nil;
1341
+ for (NSString *indicator in _mentionIndicators) {
1342
+ if ([token hasPrefix:indicator]) {
1343
+ matchedIndicator = indicator;
1344
+ break;
1345
+ }
1346
+ }
1347
+ if (matchedIndicator == nil) {
1348
+ return nil;
1349
+ }
1350
+
1351
+ if ([_formattingStore rangeOfType:ENRMInputStyleTypeLink containingPosition:start] != nil) {
1352
+ return nil;
1353
+ }
1354
+
1355
+ return [ENRMInputMentionCandidate candidateWithIndicator:matchedIndicator
1356
+ start:start
1357
+ end:cursor
1358
+ text:[token substringFromIndex:matchedIndicator.length]];
1359
+ }
1360
+
1361
+ - (void)updateActiveMention
1362
+ {
1363
+ ENRMInputMentionCandidate *candidate = [self mentionCandidateAtCursor];
1364
+ if (candidate == nil) {
1365
+ [self clearActiveMention:nil];
1366
+ return;
1367
+ }
1368
+
1369
+ NSString *indicator = candidate.indicator;
1370
+ NSUInteger start = candidate.start;
1371
+ NSUInteger end = candidate.end;
1372
+ NSString *query = candidate.text;
1373
+
1374
+ if (_activeMentionIndicator == nil || ![_activeMentionIndicator isEqualToString:indicator] ||
1375
+ _activeMentionRange.location != start) {
1376
+ if (_activeMentionIndicator != nil) {
1377
+ [self emitOnEndMention:_activeMentionIndicator];
1378
+ }
1379
+ _activeMentionIndicator = indicator;
1380
+ [self emitOnStartMention:indicator];
1381
+ }
1382
+ _activeMentionRange = NSMakeRange(start, end - start);
1383
+
1384
+ if (![_activeMentionText isEqualToString:query]) {
1385
+ _activeMentionText = query;
1386
+ [self emitOnChangeMentionWithIndicator:indicator text:query];
1387
+ }
1388
+ }
1389
+
1390
+ - (BOOL)deleteLinkForReplacementRange:(NSRange)range replacementText:(NSString *)text
1391
+ {
1392
+ if (text.length > 0) {
1393
+ return NO;
1394
+ }
1395
+
1396
+ NSUInteger lookupPosition;
1397
+ if (range.length > 0) {
1398
+ lookupPosition = range.location;
1399
+ } else if (range.location > 0) {
1400
+ lookupPosition = range.location - 1;
1401
+ } else {
1402
+ return NO;
1403
+ }
1404
+
1405
+ ENRMFormattingRange *linkRange = [_formattingStore rangeOfType:ENRMInputStyleTypeLink
1406
+ containingPosition:lookupPosition];
1407
+ if (linkRange == nil) {
1408
+ return NO;
1409
+ }
1410
+
1411
+ [self replaceTextInRange:linkRange.range withText:@"" formattingRanges:@[]];
1412
+ [self clearActiveMention:nil];
1413
+ return YES;
1414
+ }
1415
+
1416
+ - (void)emitOnChangeText
1417
+ {
1418
+ auto emitter = [self getEventEmitter];
1419
+ if (emitter == nullptr) {
1420
+ return;
1421
+ }
1422
+ NSString *plainText = ENRMGetPlainText(_textView);
1423
+ emitter->onChangeText({.value = std::string([plainText UTF8String] ?: "")});
1424
+ }
1425
+
1426
+ - (void)emitOnChangeMarkdown
1427
+ {
1428
+ auto emitter = [self getEventEmitter];
1429
+ if (emitter == nullptr) {
1430
+ return;
1431
+ }
1432
+ NSString *markdown = [ENRMMarkdownSerializer serializeAttributedString:_textView.textStorage
1433
+ ranges:[self allRangesIncludingTransient]];
1434
+ emitter->onChangeMarkdown({.value = std::string([markdown UTF8String] ?: "")});
1435
+ }
1436
+
1437
+ - (void)emitOnChangeSelection
1438
+ {
1439
+ auto emitter = [self getEventEmitter];
1440
+ if (emitter == nullptr) {
1441
+ return;
1442
+ }
1443
+ NSRange selection = _textView.selectedRange;
1444
+ emitter->onChangeSelection({
1445
+ .start = static_cast<int>(selection.location),
1446
+ .end = static_cast<int>(NSMaxRange(selection)),
1447
+ });
1448
+ }
1449
+
1450
+ - (void)emitOnChangeState
1451
+ {
1452
+ auto emitter = [self getEventEmitter];
1453
+ if (emitter == nullptr) {
1454
+ return;
1455
+ }
1456
+
1457
+ NSUInteger cursor = _textView.selectedRange.location;
1458
+ BOOL boldActive = [self isEffectiveStyleActive:ENRMInputStyleTypeStrong atPosition:cursor];
1459
+ BOOL italicActive = [self isEffectiveStyleActive:ENRMInputStyleTypeEmphasis atPosition:cursor];
1460
+ BOOL underlineActive = [self isEffectiveStyleActive:ENRMInputStyleTypeUnderline atPosition:cursor];
1461
+ BOOL strikethroughActive = [self isEffectiveStyleActive:ENRMInputStyleTypeStrikethrough atPosition:cursor];
1462
+ BOOL spoilerActive = [self isEffectiveStyleActive:ENRMInputStyleTypeSpoiler atPosition:cursor];
1463
+ BOOL linkActive = [self isEffectiveStyleActive:ENRMInputStyleTypeLink atPosition:cursor];
1464
+
1465
+ if (_prevState.initialized && _prevState.bold == boldActive && _prevState.italic == italicActive &&
1466
+ _prevState.underline == underlineActive && _prevState.strikethrough == strikethroughActive &&
1467
+ _prevState.spoiler == spoilerActive && _prevState.link == linkActive) {
1468
+ return;
1469
+ }
1470
+
1471
+ _prevState.bold = boldActive;
1472
+ _prevState.italic = italicActive;
1473
+ _prevState.underline = underlineActive;
1474
+ _prevState.strikethrough = strikethroughActive;
1475
+ _prevState.spoiler = spoilerActive;
1476
+ _prevState.link = linkActive;
1477
+ _prevState.initialized = YES;
1478
+
1479
+ emitter->onChangeState({
1480
+ .bold = {.isActive = boldActive},
1481
+ .italic = {.isActive = italicActive},
1482
+ .underline = {.isActive = underlineActive},
1483
+ .strikethrough = {.isActive = strikethroughActive},
1484
+ .spoiler = {.isActive = spoilerActive},
1485
+ .link = {.isActive = linkActive},
1486
+ });
1487
+ }
1488
+
1489
+ - (void)emitCaretRectChangeIfNeeded
1490
+ {
1491
+ auto emitter = [self getEventEmitter];
1492
+ if (emitter == nullptr) {
1493
+ return;
1494
+ }
1495
+
1496
+ CGRect caretRect = [self computeCaretRect];
1497
+
1498
+ if (_prevCaretRect.has_value() && CGRectEqualToRect(_prevCaretRect.value(), caretRect)) {
1499
+ return;
1500
+ }
1501
+
1502
+ _prevCaretRect = caretRect;
1503
+
1504
+ emitter->onCaretRectChange({
1505
+ .x = caretRect.origin.x,
1506
+ .y = caretRect.origin.y,
1507
+ .width = caretRect.size.width,
1508
+ .height = caretRect.size.height,
1509
+ });
1510
+ }
1511
+
1512
+ - (NSArray<NSString *> *)contextMenuItemTexts
1513
+ {
1514
+ return _contextMenuItemTexts ?: @[];
1515
+ }
1516
+
1517
+ - (NSArray<NSString *> *)contextMenuItemIcons
1518
+ {
1519
+ return _contextMenuItemIcons ?: @[];
1520
+ }
1521
+
1522
+ - (void)emitContextMenuItemPress:(NSString *)itemText
1523
+ {
1524
+ auto eventEmitter = [self getEventEmitter];
1525
+ if (eventEmitter == nullptr) {
1526
+ return;
1527
+ }
1528
+
1529
+ NSRange selectedRange = _textView.selectedRange;
1530
+ NSString *selectedText =
1531
+ selectedRange.length > 0 ? [_textView.textStorage.string substringWithRange:selectedRange] : @"";
1532
+
1533
+ auto isActive = [&](ENRMInputStyleType type) -> BOOL {
1534
+ if (selectedRange.length > 0) {
1535
+ return [_formattingStore isStyleActive:type inRange:selectedRange];
1536
+ }
1537
+ return [self isEffectiveStyleActive:type atPosition:selectedRange.location];
1538
+ };
1539
+
1540
+ BOOL boldActive = isActive(ENRMInputStyleTypeStrong);
1541
+ BOOL italicActive = isActive(ENRMInputStyleTypeEmphasis);
1542
+ BOOL underlineActive = isActive(ENRMInputStyleTypeUnderline);
1543
+ BOOL strikethroughActive = isActive(ENRMInputStyleTypeStrikethrough);
1544
+ BOOL spoilerActive = isActive(ENRMInputStyleTypeSpoiler);
1545
+ BOOL linkActive = isActive(ENRMInputStyleTypeLink);
1546
+
1547
+ eventEmitter->onContextMenuItemPress({
1548
+ .itemText = std::string(itemText.UTF8String),
1549
+ .selectedText = std::string(selectedText.UTF8String),
1550
+ .selectionStart = static_cast<int>(selectedRange.location),
1551
+ .selectionEnd = static_cast<int>(NSMaxRange(selectedRange)),
1552
+ .styleState =
1553
+ {
1554
+ .bold = {.isActive = boldActive},
1555
+ .italic = {.isActive = italicActive},
1556
+ .underline = {.isActive = underlineActive},
1557
+ .strikethrough = {.isActive = strikethroughActive},
1558
+ .spoiler = {.isActive = spoilerActive},
1559
+ .link = {.isActive = linkActive},
1560
+ },
1561
+ });
1562
+ }
1563
+
1564
+ - (void)emitOnFocus
1565
+ {
1566
+ auto emitter = [self getEventEmitter];
1567
+ if (emitter == nullptr) {
1568
+ return;
1569
+ }
1570
+ emitter->onInputFocus({});
1571
+ }
1572
+
1573
+ - (void)emitOnBlur
1574
+ {
1575
+ auto emitter = [self getEventEmitter];
1576
+ if (emitter == nullptr) {
1577
+ return;
1578
+ }
1579
+ emitter->onInputBlur({});
1580
+ }
1581
+
1582
+ - (void)emitOnLinkDetectedWithText:(NSString *)text url:(NSString *)url range:(NSRange)range
1583
+ {
1584
+ auto emitter = [self getEventEmitter];
1585
+ if (emitter == nullptr) {
1586
+ return;
1587
+ }
1588
+ emitter->onLinkDetected({
1589
+ .text = std::string([text UTF8String] ?: ""),
1590
+ .url = std::string([url UTF8String] ?: ""),
1591
+ .start = static_cast<int>(range.location),
1592
+ .end = static_cast<int>(range.location + range.length),
1593
+ });
1594
+ }
1595
+
1596
+ - (void)emitOnStartMention:(NSString *)indicator
1597
+ {
1598
+ auto emitter = [self getEventEmitter];
1599
+ if (emitter == nullptr) {
1600
+ return;
1601
+ }
1602
+ emitter->onStartMention({.indicator = std::string([indicator UTF8String] ?: "")});
1603
+ }
1604
+
1605
+ - (void)emitOnChangeMentionWithIndicator:(NSString *)indicator text:(NSString *)text
1606
+ {
1607
+ auto emitter = [self getEventEmitter];
1608
+ if (emitter == nullptr) {
1609
+ return;
1610
+ }
1611
+ emitter->onChangeMention({
1612
+ .indicator = std::string([indicator UTF8String] ?: ""),
1613
+ .text = std::string([text UTF8String] ?: ""),
1614
+ });
1615
+ }
1616
+
1617
+ - (void)emitOnEndMention:(NSString *)indicator
1618
+ {
1619
+ auto emitter = [self getEventEmitter];
1620
+ if (emitter == nullptr) {
1621
+ return;
1622
+ }
1623
+ emitter->onEndMention({.indicator = std::string([indicator UTF8String] ?: "")});
1624
+ }
1625
+
1626
+ #pragma mark - Text edit tracking
1627
+
1628
+ - (void)handleTextChanged
1629
+ {
1630
+ if (ENRMHasMarkedText(_textView)) {
1631
+ return;
1632
+ }
1633
+
1634
+ NSUInteger newLength = ENRMGetPlainText(_textView).length;
1635
+ NSRange selection = _textView.selectedRange;
1636
+
1637
+ NSRange preEditSelection = _preEditSelectedRange;
1638
+ NSUInteger editLocation = preEditSelection.location;
1639
+ NSUInteger deletedLength = 0;
1640
+ NSUInteger insertedLength = 0;
1641
+
1642
+ if (newLength >= _lastTextLength) {
1643
+ NSUInteger netInserted = newLength - _lastTextLength;
1644
+ deletedLength = preEditSelection.length;
1645
+ insertedLength = deletedLength + netInserted;
1646
+ } else {
1647
+ NSUInteger netDeleted = _lastTextLength - newLength;
1648
+ if (preEditSelection.length > 0) {
1649
+ deletedLength = preEditSelection.length;
1650
+ insertedLength = deletedLength > netDeleted ? deletedLength - netDeleted : 0;
1651
+ } else {
1652
+ deletedLength = netDeleted;
1653
+ insertedLength = 0;
1654
+ if (selection.location < editLocation) {
1655
+ editLocation = selection.location;
1656
+ }
1657
+ }
1658
+ }
1659
+
1660
+ [_formattingStore adjustForEditAtLocation:editLocation deletedLength:deletedLength insertedLength:insertedLength];
1661
+
1662
+ if (insertedLength > 0) {
1663
+ NSRange insertedRange = NSMakeRange(editLocation, insertedLength);
1664
+
1665
+ for (NSNumber *styleNum in _pendingStyles) {
1666
+ ENRMFormattingRange *newRange = [ENRMFormattingRange rangeWithType:(ENRMInputStyleType)styleNum.integerValue
1667
+ range:insertedRange];
1668
+ [_formattingStore addRange:newRange];
1669
+ }
1670
+
1671
+ // adjustForEditAtLocation may have expanded an existing range to cover
1672
+ // the insertion — carve out the inserted portion for removed styles.
1673
+ for (NSNumber *styleNum in _pendingStyleRemovals) {
1674
+ [_formattingStore removeType:(ENRMInputStyleType)styleNum.integerValue inRange:insertedRange];
1675
+ }
1676
+ }
1677
+
1678
+ _lastTextLength = newLength;
1679
+
1680
+ #if !TARGET_OS_OSX
1681
+ if (newLength == 0) {
1682
+ [self resetBaseTypingAttributes];
1683
+ }
1684
+ #endif
1685
+
1686
+ [self applyFormatting];
1687
+
1688
+ NSUInteger clampedEditLocation = MIN(editLocation, newLength);
1689
+ NSUInteger clampedInsertedLength = MIN(insertedLength, newLength - clampedEditLocation);
1690
+ [_detectorPipeline processTextChange:ENRMGetPlainText(_textView)
1691
+ modificationRange:NSMakeRange(clampedEditLocation, clampedInsertedLength)];
1692
+
1693
+ [self updatePlaceholderVisibility];
1694
+ [self emitOnChangeText];
1695
+ [self emitOnChangeSelection];
1696
+ [self emitFormattingChanged];
1697
+ [self updateActiveMention];
1698
+ [self emitCaretRectChangeIfNeeded];
1699
+ [self requestHeightUpdate];
1700
+ [self scheduleRelayoutIfNeeded];
1701
+ }
1702
+
1703
+ #pragma mark - Text view delegate
1704
+
1705
+ #if !TARGET_OS_OSX
1706
+
1707
+ - (void)stripLinkTypingAttributes
1708
+ {
1709
+ NSMutableDictionary *attrs = [_textView.typingAttributes mutableCopy];
1710
+ BOOL changed = NO;
1711
+
1712
+ UIColor *linkColor = _formatterStyle.linkColor;
1713
+ UIColor *currentColor = attrs[NSForegroundColorAttributeName];
1714
+ if (currentColor != nil && linkColor != nil && [currentColor isEqual:linkColor]) {
1715
+ attrs[NSForegroundColorAttributeName] = _formatterStyle.baseTextColor;
1716
+ changed = YES;
1717
+ }
1718
+
1719
+ if (attrs[NSUnderlineStyleAttributeName] != nil) {
1720
+ [attrs removeObjectForKey:NSUnderlineStyleAttributeName];
1721
+ changed = YES;
1722
+ }
1723
+
1724
+ if (attrs[NSLinkAttributeName] != nil) {
1725
+ [attrs removeObjectForKey:NSLinkAttributeName];
1726
+ changed = YES;
1727
+ }
1728
+
1729
+ if (changed) {
1730
+ _textView.typingAttributes = attrs;
1731
+ }
1732
+ }
1733
+
1734
+ - (void)manageSelectionBasedChanges
1735
+ {
1736
+ [self stripLinkTypingAttributes];
1737
+
1738
+ if (_textView.selectedRange.length == 0 && !_isTextChanging) {
1739
+ NSString *text = ENRMGetPlainText(_textView);
1740
+ if (text.length > 0) {
1741
+ NSRange paragraphRange = [text paragraphRangeForRange:_textView.selectedRange];
1742
+ NSString *paragraphText = [text substringWithRange:paragraphRange];
1743
+ BOOL isEmpty = paragraphText.length == 0 || [paragraphText isEqualToString:@"\n"];
1744
+ if (isEmpty) {
1745
+ NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
1746
+ attrs[NSFontAttributeName] = _formatterStyle.baseFont;
1747
+ attrs[NSForegroundColorAttributeName] = _formatterStyle.baseTextColor;
1748
+ _textView.typingAttributes = attrs;
1749
+ }
1750
+ }
1751
+ }
1752
+ }
1753
+
1754
+ - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
1755
+ {
1756
+ if ([self deleteLinkForReplacementRange:range replacementText:text]) {
1757
+ return NO;
1758
+ }
1759
+ _preEditSelectedRange = _lastSelectedRange;
1760
+ _isTextChanging = YES;
1761
+ [self stripLinkTypingAttributes];
1762
+ return YES;
1763
+ }
1764
+
1765
+ - (void)textViewDidChange:(UITextView *)textView
1766
+ {
1767
+ if (_isApplyingFormatting) {
1768
+ return;
1769
+ }
1770
+ [self handleTextChanged];
1771
+ _isTextChanging = NO;
1772
+ _lastSelectedRange = textView.selectedRange;
1773
+ }
1774
+
1775
+ - (void)textViewDidBeginEditing:(UITextView *)textView
1776
+ {
1777
+ [self emitOnFocus];
1778
+ }
1779
+
1780
+ - (void)textViewDidEndEditing:(UITextView *)textView
1781
+ {
1782
+ [self clearActiveMention:nil];
1783
+ [self emitOnBlur];
1784
+ }
1785
+
1786
+ - (void)textViewDidChangeSelection:(UITextView *)textView
1787
+ {
1788
+ NSRange newSelection = textView.selectedRange;
1789
+ NSRange previousSelection = _lastSelectedRange;
1790
+ _lastSelectedRange = newSelection;
1791
+
1792
+ if (_isApplyingFormatting || _isTextChanging) {
1793
+ return;
1794
+ }
1795
+
1796
+ #if ENRICHED_MARKDOWN_MATH
1797
+ if (_suppressMathChipClearOnce) {
1798
+ // Caret update was triggered by handleTapForMathChip — keep that chip
1799
+ // selected; consume the suppression flag.
1800
+ _suppressMathChipClearOnce = NO;
1801
+ } else {
1802
+ [self clearMathChipSelectionsExcept:NSMakeRange(NSNotFound, 0)];
1803
+ _activeMathChipIndex = NSNotFound;
1804
+ }
1805
+ #endif
1806
+
1807
+ BOOL selectionMoved =
1808
+ newSelection.location != previousSelection.location || newSelection.length != previousSelection.length;
1809
+
1810
+ if (selectionMoved) {
1811
+ [_pendingStyles removeAllObjects];
1812
+ [_pendingStyleRemovals removeAllObjects];
1813
+ }
1814
+
1815
+ [self manageSelectionBasedChanges];
1816
+
1817
+ [self emitOnChangeSelection];
1818
+ [self updateActiveMention];
1819
+ [self emitOnChangeState];
1820
+ [self emitCaretRectChangeIfNeeded];
1821
+ }
1822
+
1823
+ #if ENRICHED_MARKDOWN_MATH && !TARGET_OS_OSX
1824
+ - (void)clearMathChipSelectionsExcept:(NSRange)keepRange
1825
+ {
1826
+ NSTextStorage *storage = _textView.textStorage;
1827
+ if (storage.length == 0)
1828
+ return;
1829
+ __block BOOL anyChanged = NO;
1830
+ __block NSMutableArray<NSValue *> *invalidationRanges = [NSMutableArray array];
1831
+ [storage enumerateAttribute:NSAttachmentAttributeName
1832
+ inRange:NSMakeRange(0, storage.length)
1833
+ options:0
1834
+ usingBlock:^(id value, NSRange range, BOOL *stop) {
1835
+ if (![value isKindOfClass:[ENRMMathInlineAttachment class]])
1836
+ return;
1837
+ ENRMMathInlineAttachment *att = value;
1838
+ BOOL keep = NSEqualRanges(range, keepRange);
1839
+ if (att.isSelected && !keep) {
1840
+ att.isSelected = NO;
1841
+ [att invalidateRender];
1842
+ [invalidationRanges addObject:[NSValue valueWithRange:range]];
1843
+ anyChanged = YES;
1844
+ }
1845
+ }];
1846
+ if (anyChanged) {
1847
+ NSLayoutManager *lm = storage.layoutManagers.firstObject;
1848
+ for (NSValue *v in invalidationRanges) {
1849
+ NSRange r = v.rangeValue;
1850
+ [lm invalidateLayoutForCharacterRange:r actualCharacterRange:NULL];
1851
+ }
1852
+ ENRMSetNeedsDisplay(_textView);
1853
+ }
1854
+ }
1855
+ #else
1856
+ - (void)clearMathChipSelectionsExcept:(NSRange)keepRange
1857
+ {
1858
+ (void)keepRange;
1859
+ }
1860
+ #endif
1861
+
1862
+ #else
1863
+
1864
+ #pragma mark - RCTBackedTextInputDelegate (macOS)
1865
+
1866
+ - (BOOL)textInputShouldBeginEditing
1867
+ {
1868
+ return YES;
1869
+ }
1870
+
1871
+ - (void)textInputDidBeginEditing
1872
+ {
1873
+ [self emitOnFocus];
1874
+ }
1875
+
1876
+ - (BOOL)textInputShouldEndEditing
1877
+ {
1878
+ return YES;
1879
+ }
1880
+
1881
+ - (void)textInputDidEndEditing
1882
+ {
1883
+ [self clearActiveMention:nil];
1884
+ [self emitOnBlur];
1885
+ }
1886
+
1887
+ - (BOOL)textInputShouldReturn
1888
+ {
1889
+ return NO;
1890
+ }
1891
+
1892
+ - (void)textInputDidReturn
1893
+ {
1894
+ }
1895
+
1896
+ - (BOOL)textInputShouldSubmitOnReturn
1897
+ {
1898
+ return NO;
1899
+ }
1900
+
1901
+ - (nullable NSString *)textInputShouldChangeText:(NSString *)text inRange:(NSRange)range
1902
+ {
1903
+ if ([self deleteLinkForReplacementRange:range replacementText:text]) {
1904
+ return nil;
1905
+ }
1906
+ _preEditSelectedRange = _lastSelectedRange;
1907
+ _isTextChanging = YES;
1908
+ return text;
1909
+ }
1910
+
1911
+ - (void)textInputDidChange
1912
+ {
1913
+ if (_isApplyingFormatting) {
1914
+ _isTextChanging = NO;
1915
+ return;
1916
+ }
1917
+ [self handleTextChanged];
1918
+ _isTextChanging = NO;
1919
+ _lastSelectedRange = _textView.selectedRange;
1920
+ }
1921
+
1922
+ - (void)textInputDidChangeSelection
1923
+ {
1924
+ _lastSelectedRange = _textView.selectedRange;
1925
+
1926
+ if (_isApplyingFormatting || _isTextChanging) {
1927
+ return;
1928
+ }
1929
+
1930
+ [_pendingStyles removeAllObjects];
1931
+ [_pendingStyleRemovals removeAllObjects];
1932
+
1933
+ [self emitOnChangeSelection];
1934
+ [self updateActiveMention];
1935
+ [self emitOnChangeState];
1936
+ [self emitCaretRectChangeIfNeeded];
1937
+ }
1938
+
1939
+ // @required stubs for RCTBackedTextInputDelegate — RCTUITextView's internal adapter
1940
+ // calls these via textInputDelegate; omitting any causes silent failures or crashes.
1941
+
1942
+ - (BOOL)textInputShouldHandleDeleteBackward:(id<RCTBackedTextInputViewProtocol>)sender
1943
+ {
1944
+ return YES;
1945
+ }
1946
+
1947
+ - (BOOL)textInputShouldHandleDeleteForward:(id<RCTBackedTextInputViewProtocol>)sender
1948
+ {
1949
+ return YES;
1950
+ }
1951
+
1952
+ - (BOOL)textInputShouldHandleKeyEvent:(NSEvent *)event
1953
+ {
1954
+ return YES;
1955
+ }
1956
+
1957
+ - (BOOL)hasKeyDownEventOrKeyUpEvent:(NSString *)key
1958
+ {
1959
+ return NO;
1960
+ }
1961
+
1962
+ - (NSDragOperation)textInputDraggingEntered:(id<NSDraggingInfo>)draggingInfo
1963
+ {
1964
+ return NSDragOperationNone;
1965
+ }
1966
+
1967
+ - (void)textInputDraggingExited:(id<NSDraggingInfo>)draggingInfo
1968
+ {
1969
+ }
1970
+
1971
+ - (BOOL)textInputShouldHandleDragOperation:(id<NSDraggingInfo>)draggingInfo
1972
+ {
1973
+ return YES;
1974
+ }
1975
+
1976
+ - (void)textInputDidCancel
1977
+ {
1978
+ }
1979
+
1980
+ - (BOOL)textInputShouldHandlePaste:(id<RCTBackedTextInputViewProtocol>)sender
1981
+ {
1982
+ return YES;
1983
+ }
1984
+
1985
+ - (void)automaticSpellingCorrectionDidChange:(BOOL)enabled
1986
+ {
1987
+ }
1988
+
1989
+ - (void)continuousSpellCheckingDidChange:(BOOL)enabled
1990
+ {
1991
+ }
1992
+
1993
+ - (void)grammarCheckingDidChange:(BOOL)enabled
1994
+ {
1995
+ }
1996
+
1997
+ - (void)submitOnKeyDownIfNeeded:(NSEvent *)event
1998
+ {
1999
+ }
2000
+
2001
+ #endif
2002
+
2003
+ @end
2004
+
2005
+ Class<RCTComponentViewProtocol> EnrichedMarkdownTextInputCls(void)
2006
+ {
2007
+ return EnrichedMarkdownTextInput.class;
2008
+ }