react-native-enriched-html 0.0.0 → 1.0.0

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 (666) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +402 -0
  3. package/ReactNativeEnrichedHtml.podspec +31 -0
  4. package/android/build.gradle +106 -0
  5. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerDelegate.java +203 -0
  6. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerInterface.java +74 -0
  7. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextViewManagerDelegate.java +70 -0
  8. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextViewManagerInterface.java +31 -0
  9. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/ComponentDescriptors.cpp +22 -0
  10. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/ComponentDescriptors.h +24 -0
  11. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/EventEmitters.cpp +456 -0
  12. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/EventEmitters.h +410 -0
  13. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/Props.cpp +272 -0
  14. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/Props.h +1595 -0
  15. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/ShadowNodes.cpp +17 -0
  16. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/ShadowNodes.h +23 -0
  17. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/States.cpp +16 -0
  18. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/States.h +20 -0
  19. package/android/gradle.properties +5 -0
  20. package/android/lint.gradle +70 -0
  21. package/android/src/main/AndroidManifest.xml +3 -0
  22. package/android/src/main/AndroidManifestNew.xml +2 -0
  23. package/android/src/main/java/com/swmansion/enriched/ReactNativeEnrichedPackage.kt +22 -0
  24. package/android/src/main/java/com/swmansion/enriched/common/AllowFontScaling.kt +36 -0
  25. package/android/src/main/java/com/swmansion/enriched/common/AsyncDrawable.kt +126 -0
  26. package/android/src/main/java/com/swmansion/enriched/common/CheckboxDrawable.kt +81 -0
  27. package/android/src/main/java/com/swmansion/enriched/common/EnrichedConstants.kt +16 -0
  28. package/android/src/main/java/com/swmansion/enriched/common/EnrichedStyle.kt +57 -0
  29. package/android/src/main/java/com/swmansion/enriched/common/ForceRedrawSpan.kt +14 -0
  30. package/android/src/main/java/com/swmansion/enriched/common/GumboNormalizer.kt +5 -0
  31. package/android/src/main/java/com/swmansion/enriched/common/MentionStyle.kt +9 -0
  32. package/android/src/main/java/com/swmansion/enriched/common/ResourceManager.kt +26 -0
  33. package/android/src/main/java/com/swmansion/enriched/common/parser/EnrichedParser.java +1034 -0
  34. package/android/src/main/java/com/swmansion/enriched/common/parser/EnrichedSpanFactory.kt +82 -0
  35. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedAlignmentSpan.kt +19 -0
  36. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedBlockQuoteSpan.kt +53 -0
  37. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedBoldSpan.kt +12 -0
  38. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedCheckboxListSpan.kt +92 -0
  39. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedCodeBlockSpan.kt +81 -0
  40. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH1Span.kt +20 -0
  41. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH2Span.kt +20 -0
  42. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH3Span.kt +20 -0
  43. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH4Span.kt +21 -0
  44. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH5Span.kt +20 -0
  45. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH6Span.kt +20 -0
  46. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedImageSpan.kt +185 -0
  47. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedInlineCodeSpan.kt +24 -0
  48. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedItalicSpan.kt +12 -0
  49. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedLinkSpan.kt +29 -0
  50. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedMentionSpan.kt +35 -0
  51. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedOrderedListSpan.kt +79 -0
  52. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedStrikeThroughSpan.kt +11 -0
  53. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedUnderlineSpan.kt +11 -0
  54. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedUnorderedListSpan.kt +62 -0
  55. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedBlockSpan.kt +5 -0
  56. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedHeadingSpan.kt +3 -0
  57. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedInlineSpan.kt +3 -0
  58. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedParagraphSpan.kt +5 -0
  59. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedSpan.kt +3 -0
  60. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedZeroWidthSpaceSpan.kt +4 -0
  61. package/android/src/main/java/com/swmansion/enriched/text/EnrichedTextMovementMethod.kt +75 -0
  62. package/android/src/main/java/com/swmansion/enriched/text/EnrichedTextSpanFactory.kt +83 -0
  63. package/android/src/main/java/com/swmansion/enriched/text/EnrichedTextStyle.kt +202 -0
  64. package/android/src/main/java/com/swmansion/enriched/text/EnrichedTextView.kt +361 -0
  65. package/android/src/main/java/com/swmansion/enriched/text/EnrichedTextViewManager.kt +157 -0
  66. package/android/src/main/java/com/swmansion/enriched/text/MeasurementStore.kt +170 -0
  67. package/android/src/main/java/com/swmansion/enriched/text/events/OnLinkPressEvent.kt +23 -0
  68. package/android/src/main/java/com/swmansion/enriched/text/events/OnMentionPressEvent.kt +32 -0
  69. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextAlignmentSpan.kt +14 -0
  70. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextBlockQuoteSpan.kt +14 -0
  71. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextBoldSpan.kt +14 -0
  72. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextCheckboxListSpan.kt +15 -0
  73. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextCodeBlockSpan.kt +14 -0
  74. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextH1Span.kt +14 -0
  75. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextH2Span.kt +14 -0
  76. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextH3Span.kt +15 -0
  77. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextH4Span.kt +15 -0
  78. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextH5Span.kt +14 -0
  79. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextH6Span.kt +14 -0
  80. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextImageSpan.kt +57 -0
  81. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextInlineCodeSpan.kt +14 -0
  82. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextItalicSpan.kt +14 -0
  83. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextLinkSpan.kt +41 -0
  84. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextMentionSpan.kt +63 -0
  85. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextOrderedListSpan.kt +16 -0
  86. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextStrikeThroughSpan.kt +15 -0
  87. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextUnderlineSpan.kt +15 -0
  88. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextUnorderedListSpan.kt +15 -0
  89. package/android/src/main/java/com/swmansion/enriched/text/spans/interfaces/EnrichedTextClickableSpan.kt +9 -0
  90. package/android/src/main/java/com/swmansion/enriched/text/spans/interfaces/EnrichedTextSpan.kt +10 -0
  91. package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputConnectionWrapper.kt +140 -0
  92. package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputSpannableFactory.kt +85 -0
  93. package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputView.kt +1141 -0
  94. package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputViewLayoutManager.kt +27 -0
  95. package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputViewManager.kt +500 -0
  96. package/android/src/main/java/com/swmansion/enriched/textinput/MeasurementStore.kt +230 -0
  97. package/android/src/main/java/com/swmansion/enriched/textinput/events/MentionHandler.kt +55 -0
  98. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnChangeHtmlEvent.kt +27 -0
  99. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnChangeSelectionEvent.kt +30 -0
  100. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnChangeStateEvent.kt +21 -0
  101. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnChangeTextEvent.kt +30 -0
  102. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnContextMenuItemPressEvent.kt +35 -0
  103. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnInputBlurEvent.kt +25 -0
  104. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnInputFocusEvent.kt +25 -0
  105. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnInputKeyPressEvent.kt +27 -0
  106. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnLinkDetectedEvent.kt +32 -0
  107. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnMentionDetectedEvent.kt +30 -0
  108. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnMentionEvent.kt +34 -0
  109. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnPasteImagesEvent.kt +47 -0
  110. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnRequestHtmlResultEvent.kt +32 -0
  111. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnSubmitEditingEvent.kt +29 -0
  112. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputAlignmentSpan.kt +14 -0
  113. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputBlockQuoteSpan.kt +14 -0
  114. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputBoldSpan.kt +14 -0
  115. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputCheckboxListSpan.kt +15 -0
  116. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputCodeBlockSpan.kt +14 -0
  117. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH1Span.kt +14 -0
  118. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH2Span.kt +14 -0
  119. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH3Span.kt +14 -0
  120. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH4Span.kt +14 -0
  121. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH5Span.kt +14 -0
  122. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH6Span.kt +14 -0
  123. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputImageSpan.kt +36 -0
  124. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputInlineCodeSpan.kt +14 -0
  125. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputItalicSpan.kt +14 -0
  126. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputLinkSpan.kt +16 -0
  127. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputMentionSpan.kt +18 -0
  128. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputOrderedListSpan.kt +21 -0
  129. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputStrikeThroughSpan.kt +14 -0
  130. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputUnderlineSpan.kt +14 -0
  131. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputUnorderedListSpan.kt +14 -0
  132. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedLineHeightSpan.kt +45 -0
  133. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedSpans.kt +240 -0
  134. package/android/src/main/java/com/swmansion/enriched/textinput/spans/interfaces/EnrichedInputSpan.kt +10 -0
  135. package/android/src/main/java/com/swmansion/enriched/textinput/styles/AlignmentStyles.kt +367 -0
  136. package/android/src/main/java/com/swmansion/enriched/textinput/styles/HtmlStyle.kt +371 -0
  137. package/android/src/main/java/com/swmansion/enriched/textinput/styles/InlineStyles.kt +232 -0
  138. package/android/src/main/java/com/swmansion/enriched/textinput/styles/ListStyles.kt +260 -0
  139. package/android/src/main/java/com/swmansion/enriched/textinput/styles/ParagraphStyles.kt +439 -0
  140. package/android/src/main/java/com/swmansion/enriched/textinput/styles/ParametrizedStyles.kt +408 -0
  141. package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedEditableFactory.kt +17 -0
  142. package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSelection.kt +340 -0
  143. package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpanState.kt +318 -0
  144. package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpannable.kt +156 -0
  145. package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpannableStringBuilder.kt +59 -0
  146. package/android/src/main/java/com/swmansion/enriched/textinput/utils/RichContentReceiver.kt +127 -0
  147. package/android/src/main/java/com/swmansion/enriched/textinput/utils/ShortcutsHandler.kt +150 -0
  148. package/android/src/main/java/com/swmansion/enriched/textinput/utils/StyleUtils.kt +51 -0
  149. package/android/src/main/java/com/swmansion/enriched/textinput/utils/Utils.kt +106 -0
  150. package/android/src/main/java/com/swmansion/enriched/textinput/watchers/EnrichedSpanWatcher.kt +109 -0
  151. package/android/src/main/java/com/swmansion/enriched/textinput/watchers/EnrichedTextWatcher.kt +106 -0
  152. package/android/src/main/new_arch/CMakeLists.txt +62 -0
  153. package/android/src/main/new_arch/GumboNormalizerJni.cpp +14 -0
  154. package/android/src/main/new_arch/ReactNativeEnrichedSpec.cpp +11 -0
  155. package/android/src/main/new_arch/ReactNativeEnrichedSpec.h +16 -0
  156. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextComponentDescriptor.h +32 -0
  157. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputComponentDescriptor.h +35 -0
  158. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputMeasurementManager.cpp +53 -0
  159. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputMeasurementManager.h +25 -0
  160. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputShadowNode.cpp +35 -0
  161. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputShadowNode.h +53 -0
  162. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputState.cpp +9 -0
  163. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputState.h +24 -0
  164. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextMeasurementManager.cpp +45 -0
  165. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextMeasurementManager.h +25 -0
  166. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextShadowNode.cpp +21 -0
  167. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextShadowNode.h +39 -0
  168. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/conversions.h +44 -0
  169. package/android/src/main/res/drawable/broken_image.xml +10 -0
  170. package/cpp/CMakeLists.txt +50 -0
  171. package/cpp/GumboParser/GumboParser.h +34043 -0
  172. package/cpp/README.md +59 -0
  173. package/cpp/parser/GumboNormalizer.c +915 -0
  174. package/cpp/parser/GumboParser.cpp +16 -0
  175. package/cpp/parser/GumboParser.hpp +23 -0
  176. package/cpp/tests/GumboParserTest.cpp +457 -0
  177. package/ios/EnrichedTextInputView.h +54 -0
  178. package/ios/EnrichedTextInputView.mm +2170 -0
  179. package/ios/EnrichedTextInputViewManager.mm +13 -0
  180. package/ios/EnrichedTextView.h +35 -0
  181. package/ios/EnrichedTextView.mm +806 -0
  182. package/ios/EnrichedTextViewManager.mm +13 -0
  183. package/ios/config/EnrichedConfig.h +114 -0
  184. package/ios/config/EnrichedConfig.mm +727 -0
  185. package/ios/enrichedInputTextView/EnrichedInputTextView.h +6 -0
  186. package/ios/enrichedInputTextView/EnrichedInputTextView.mm +334 -0
  187. package/ios/enrichedTextTextView/EnrichedTextTextView.h +16 -0
  188. package/ios/enrichedTextTextView/EnrichedTextTextView.mm +71 -0
  189. package/ios/extensions/ColorExtension.h +8 -0
  190. package/ios/extensions/ColorExtension.mm +48 -0
  191. package/ios/extensions/FontExtension.h +11 -0
  192. package/ios/extensions/FontExtension.mm +72 -0
  193. package/ios/extensions/ImageExtension.h +33 -0
  194. package/ios/extensions/ImageExtension.mm +176 -0
  195. package/ios/extensions/LayoutManagerExtension.h +6 -0
  196. package/ios/extensions/LayoutManagerExtension.mm +454 -0
  197. package/ios/extensions/StringExtension.h +15 -0
  198. package/ios/extensions/StringExtension.mm +69 -0
  199. package/ios/generated/ReactNativeEnrichedSpec/ComponentDescriptors.cpp +22 -0
  200. package/ios/generated/ReactNativeEnrichedSpec/ComponentDescriptors.h +24 -0
  201. package/ios/generated/ReactNativeEnrichedSpec/EventEmitters.cpp +456 -0
  202. package/ios/generated/ReactNativeEnrichedSpec/EventEmitters.h +410 -0
  203. package/ios/generated/ReactNativeEnrichedSpec/Props.cpp +272 -0
  204. package/ios/generated/ReactNativeEnrichedSpec/Props.h +1595 -0
  205. package/ios/generated/ReactNativeEnrichedSpec/RCTComponentViewHelpers.h +570 -0
  206. package/ios/generated/ReactNativeEnrichedSpec/ShadowNodes.cpp +17 -0
  207. package/ios/generated/ReactNativeEnrichedSpec/ShadowNodes.h +23 -0
  208. package/ios/generated/ReactNativeEnrichedSpec/States.cpp +16 -0
  209. package/ios/generated/ReactNativeEnrichedSpec/States.h +20 -0
  210. package/ios/htmlParser/HtmlParser.h +11 -0
  211. package/ios/htmlParser/HtmlParser.mm +1468 -0
  212. package/ios/inputAttributesManager/InputAttributesManager.h +18 -0
  213. package/ios/inputAttributesManager/InputAttributesManager.mm +222 -0
  214. package/ios/inputHtmlParser/InputHtmlParser.h +10 -0
  215. package/ios/inputHtmlParser/InputHtmlParser.mm +225 -0
  216. package/ios/interfaces/AlignmentEntry.h +9 -0
  217. package/ios/interfaces/AlignmentEntry.mm +4 -0
  218. package/ios/interfaces/AttributeEntry.h +9 -0
  219. package/ios/interfaces/AttributeEntry.mm +4 -0
  220. package/ios/interfaces/BaseStyleProtocol.h +17 -0
  221. package/ios/interfaces/EnrichedTextStyleHeaders.h +62 -0
  222. package/ios/interfaces/EnrichedViewHost.h +26 -0
  223. package/ios/interfaces/ImageAttachment.h +11 -0
  224. package/ios/interfaces/ImageAttachment.mm +107 -0
  225. package/ios/interfaces/ImageData.h +10 -0
  226. package/ios/interfaces/ImageData.mm +4 -0
  227. package/ios/interfaces/LinkData.h +11 -0
  228. package/ios/interfaces/LinkData.mm +43 -0
  229. package/ios/interfaces/LinkRegexConfig.h +19 -0
  230. package/ios/interfaces/LinkRegexConfig.mm +37 -0
  231. package/ios/interfaces/MediaAttachment.h +23 -0
  232. package/ios/interfaces/MediaAttachment.mm +31 -0
  233. package/ios/interfaces/MentionParams.h +8 -0
  234. package/ios/interfaces/MentionParams.mm +4 -0
  235. package/ios/interfaces/MentionStyleProps.h +17 -0
  236. package/ios/interfaces/MentionStyleProps.mm +80 -0
  237. package/ios/interfaces/StyleBase.h +38 -0
  238. package/ios/interfaces/StyleBase.mm +279 -0
  239. package/ios/interfaces/StyleHeaders.h +110 -0
  240. package/ios/interfaces/StylePair.h +9 -0
  241. package/ios/interfaces/StylePair.mm +4 -0
  242. package/ios/interfaces/StyleTypeEnum.h +27 -0
  243. package/ios/interfaces/TextDecorationLineEnum.h +6 -0
  244. package/ios/interfaces/TextDecorationLineEnum.mm +4 -0
  245. package/ios/internals/EnrichedTextComponentDescriptor.h +19 -0
  246. package/ios/internals/EnrichedTextInputViewComponentDescriptor.h +19 -0
  247. package/ios/internals/EnrichedTextInputViewShadowNode.h +44 -0
  248. package/ios/internals/EnrichedTextInputViewShadowNode.mm +103 -0
  249. package/ios/internals/EnrichedTextInputViewState.cpp +10 -0
  250. package/ios/internals/EnrichedTextInputViewState.h +22 -0
  251. package/ios/internals/EnrichedTextViewShadowNode.h +34 -0
  252. package/ios/internals/EnrichedTextViewShadowNode.mm +72 -0
  253. package/ios/internals/EnrichedTextViewState.cpp +7 -0
  254. package/ios/internals/EnrichedTextViewState.h +18 -0
  255. package/ios/styles/AlignmentStyle.mm +203 -0
  256. package/ios/styles/BlockQuoteStyle.mm +54 -0
  257. package/ios/styles/BoldStyle.mm +37 -0
  258. package/ios/styles/CheckboxListStyle.mm +154 -0
  259. package/ios/styles/CodeBlockStyle.mm +49 -0
  260. package/ios/styles/EnrichedTextStyles.mm +61 -0
  261. package/ios/styles/H1Style.mm +20 -0
  262. package/ios/styles/H2Style.mm +20 -0
  263. package/ios/styles/H3Style.mm +20 -0
  264. package/ios/styles/H4Style.mm +20 -0
  265. package/ios/styles/H5Style.mm +20 -0
  266. package/ios/styles/H6Style.mm +20 -0
  267. package/ios/styles/HeadingStyleBase.mm +96 -0
  268. package/ios/styles/ImageStyle.mm +150 -0
  269. package/ios/styles/InlineCodeStyle.mm +65 -0
  270. package/ios/styles/ItalicStyle.mm +37 -0
  271. package/ios/styles/LinkStyle.mm +532 -0
  272. package/ios/styles/MentionStyle.mm +541 -0
  273. package/ios/styles/OrderedListStyle.mm +48 -0
  274. package/ios/styles/StrikethroughStyle.mm +25 -0
  275. package/ios/styles/UnderlineStyle.mm +24 -0
  276. package/ios/styles/UnorderedListStyle.mm +48 -0
  277. package/ios/textHtmlParser/TextHtmlParser.h +10 -0
  278. package/ios/textHtmlParser/TextHtmlParser.mm +181 -0
  279. package/ios/utils/AlignmentUtils.h +20 -0
  280. package/ios/utils/AlignmentUtils.mm +111 -0
  281. package/ios/utils/AttachmentLayoutUtils.h +24 -0
  282. package/ios/utils/AttachmentLayoutUtils.mm +144 -0
  283. package/ios/utils/CheckboxHitTestUtils.h +10 -0
  284. package/ios/utils/CheckboxHitTestUtils.mm +122 -0
  285. package/ios/utils/DotReplacementUtils.h +10 -0
  286. package/ios/utils/DotReplacementUtils.mm +68 -0
  287. package/ios/utils/EnrichedTextTouchHandler.h +14 -0
  288. package/ios/utils/EnrichedTextTouchHandler.mm +152 -0
  289. package/ios/utils/KeyboardUtils.h +7 -0
  290. package/ios/utils/KeyboardUtils.mm +30 -0
  291. package/ios/utils/OccurenceUtils.h +44 -0
  292. package/ios/utils/OccurenceUtils.mm +185 -0
  293. package/ios/utils/ParagraphAttributesUtils.h +18 -0
  294. package/ios/utils/ParagraphAttributesUtils.mm +289 -0
  295. package/ios/utils/RangeUtils.h +12 -0
  296. package/ios/utils/RangeUtils.mm +183 -0
  297. package/ios/utils/ShortcutsUtils.h +21 -0
  298. package/ios/utils/ShortcutsUtils.mm +486 -0
  299. package/ios/utils/StyleUtils.h +33 -0
  300. package/ios/utils/StyleUtils.mm +290 -0
  301. package/ios/utils/TextBlockTapGestureRecognizer.h +17 -0
  302. package/ios/utils/TextBlockTapGestureRecognizer.mm +56 -0
  303. package/ios/utils/TextInsertionUtils.h +17 -0
  304. package/ios/utils/TextInsertionUtils.mm +60 -0
  305. package/ios/utils/TextListsUtils.h +40 -0
  306. package/ios/utils/TextListsUtils.mm +93 -0
  307. package/ios/utils/WeakBox.h +3 -0
  308. package/ios/utils/WeakBox.m +4 -0
  309. package/ios/utils/WordsUtils.h +7 -0
  310. package/ios/utils/WordsUtils.mm +98 -0
  311. package/ios/utils/ZeroWidthSpaceUtils.h +14 -0
  312. package/ios/utils/ZeroWidthSpaceUtils.mm +310 -0
  313. package/lib/module/index.js +4 -0
  314. package/lib/module/index.js.map +1 -0
  315. package/lib/module/index.native.js +7 -0
  316. package/lib/module/index.native.js.map +1 -0
  317. package/lib/module/native/EnrichedText.js +76 -0
  318. package/lib/module/native/EnrichedText.js.map +1 -0
  319. package/lib/module/native/EnrichedTextInput.js +306 -0
  320. package/lib/module/native/EnrichedTextInput.js.map +1 -0
  321. package/lib/module/package.json +1 -0
  322. package/lib/module/spec/EnrichedTextInputNativeComponent.ts +524 -0
  323. package/lib/module/spec/EnrichedTextNativeComponent.ts +110 -0
  324. package/lib/module/types.js +4 -0
  325. package/lib/module/types.js.map +1 -0
  326. package/lib/module/utils/EnrichedTextInputDefaultProps.js +20 -0
  327. package/lib/module/utils/EnrichedTextInputDefaultProps.js.map +1 -0
  328. package/lib/module/utils/defaultHtmlStyle.js +83 -0
  329. package/lib/module/utils/defaultHtmlStyle.js.map +1 -0
  330. package/lib/module/utils/expandMentionStylesForIndicators.js +15 -0
  331. package/lib/module/utils/expandMentionStylesForIndicators.js.map +1 -0
  332. package/lib/module/utils/isMentionStyleRecord.js +10 -0
  333. package/lib/module/utils/isMentionStyleRecord.js.map +1 -0
  334. package/lib/module/utils/normalizeHtmlStyle.js +126 -0
  335. package/lib/module/utils/normalizeHtmlStyle.js.map +1 -0
  336. package/lib/module/utils/nullthrows.js +9 -0
  337. package/lib/module/utils/nullthrows.js.map +1 -0
  338. package/lib/module/utils/regexParser.js +46 -0
  339. package/lib/module/utils/regexParser.js.map +1 -0
  340. package/lib/module/web/EnrichedTextInput.css +201 -0
  341. package/lib/module/web/EnrichedTextInput.js +314 -0
  342. package/lib/module/web/EnrichedTextInput.js.map +1 -0
  343. package/lib/module/web/adaptWebToNativeEvent.js +34 -0
  344. package/lib/module/web/adaptWebToNativeEvent.js.map +1 -0
  345. package/lib/module/web/checkboxHtmlNormalizer.js +54 -0
  346. package/lib/module/web/checkboxHtmlNormalizer.js.map +1 -0
  347. package/lib/module/web/formats/EnrichedBlockquote.js +32 -0
  348. package/lib/module/web/formats/EnrichedBlockquote.js.map +1 -0
  349. package/lib/module/web/formats/EnrichedBold.js +22 -0
  350. package/lib/module/web/formats/EnrichedBold.js.map +1 -0
  351. package/lib/module/web/formats/EnrichedCheckboxItem.js +32 -0
  352. package/lib/module/web/formats/EnrichedCheckboxItem.js.map +1 -0
  353. package/lib/module/web/formats/EnrichedCheckboxList.js +35 -0
  354. package/lib/module/web/formats/EnrichedCheckboxList.js.map +1 -0
  355. package/lib/module/web/formats/EnrichedCode.js +15 -0
  356. package/lib/module/web/formats/EnrichedCode.js.map +1 -0
  357. package/lib/module/web/formats/EnrichedCodeBlock.js +43 -0
  358. package/lib/module/web/formats/EnrichedCodeBlock.js.map +1 -0
  359. package/lib/module/web/formats/EnrichedHeading.js +27 -0
  360. package/lib/module/web/formats/EnrichedHeading.js.map +1 -0
  361. package/lib/module/web/formats/EnrichedImage.js +57 -0
  362. package/lib/module/web/formats/EnrichedImage.js.map +1 -0
  363. package/lib/module/web/formats/EnrichedImageNodeView.js +90 -0
  364. package/lib/module/web/formats/EnrichedImageNodeView.js.map +1 -0
  365. package/lib/module/web/formats/EnrichedItalic.js +22 -0
  366. package/lib/module/web/formats/EnrichedItalic.js.map +1 -0
  367. package/lib/module/web/formats/EnrichedLink.js +140 -0
  368. package/lib/module/web/formats/EnrichedLink.js.map +1 -0
  369. package/lib/module/web/formats/EnrichedListItem.js +19 -0
  370. package/lib/module/web/formats/EnrichedListItem.js.map +1 -0
  371. package/lib/module/web/formats/EnrichedMention.js +50 -0
  372. package/lib/module/web/formats/EnrichedMention.js.map +1 -0
  373. package/lib/module/web/formats/EnrichedOrderedList.js +32 -0
  374. package/lib/module/web/formats/EnrichedOrderedList.js.map +1 -0
  375. package/lib/module/web/formats/EnrichedStrike.js +22 -0
  376. package/lib/module/web/formats/EnrichedStrike.js.map +1 -0
  377. package/lib/module/web/formats/EnrichedUnderline.js +22 -0
  378. package/lib/module/web/formats/EnrichedUnderline.js.map +1 -0
  379. package/lib/module/web/formats/EnrichedUnorderedList.js +33 -0
  380. package/lib/module/web/formats/EnrichedUnorderedList.js.map +1 -0
  381. package/lib/module/web/formats/applyWrappingListToSelection.js +63 -0
  382. package/lib/module/web/formats/applyWrappingListToSelection.js.map +1 -0
  383. package/lib/module/web/formats/formatRules.js +48 -0
  384. package/lib/module/web/formats/formatRules.js.map +1 -0
  385. package/lib/module/web/formats/listKeyboard.js +50 -0
  386. package/lib/module/web/formats/listKeyboard.js.map +1 -0
  387. package/lib/module/web/formats/wrappedBlockKeyboard.js +58 -0
  388. package/lib/module/web/formats/wrappedBlockKeyboard.js.map +1 -0
  389. package/lib/module/web/pasteImages.js +78 -0
  390. package/lib/module/web/pasteImages.js.map +1 -0
  391. package/lib/module/web/pastedImageDimensions.js +49 -0
  392. package/lib/module/web/pastedImageDimensions.js.map +1 -0
  393. package/lib/module/web/pmPlugins/MentionPlugin/index.js +36 -0
  394. package/lib/module/web/pmPlugins/MentionPlugin/index.js.map +1 -0
  395. package/lib/module/web/pmPlugins/MentionPlugin/isCaretInBlockedContext.js +11 -0
  396. package/lib/module/web/pmPlugins/MentionPlugin/isCaretInBlockedContext.js.map +1 -0
  397. package/lib/module/web/pmPlugins/MentionPlugin/makeMentionPluginState.js +67 -0
  398. package/lib/module/web/pmPlugins/MentionPlugin/makeMentionPluginState.js.map +1 -0
  399. package/lib/module/web/pmPlugins/MentionPlugin/mentionPluginKey.js +5 -0
  400. package/lib/module/web/pmPlugins/MentionPlugin/mentionPluginKey.js.map +1 -0
  401. package/lib/module/web/pmPlugins/MentionPlugin/removeMentionMarksIfSpansResized.js +56 -0
  402. package/lib/module/web/pmPlugins/MentionPlugin/removeMentionMarksIfSpansResized.js.map +1 -0
  403. package/lib/module/web/pmPlugins/MentionPlugin/setMention.js +58 -0
  404. package/lib/module/web/pmPlugins/MentionPlugin/setMention.js.map +1 -0
  405. package/lib/module/web/pmPlugins/MentionPlugin/startMention.js +9 -0
  406. package/lib/module/web/pmPlugins/MentionPlugin/startMention.js.map +1 -0
  407. package/lib/module/web/pmPlugins/MentionPlugin/stripPartialMentionMarks.js +9 -0
  408. package/lib/module/web/pmPlugins/MentionPlugin/stripPartialMentionMarks.js.map +1 -0
  409. package/lib/module/web/pmPlugins/MentionPlugin/subscribeMentionEvents.js +100 -0
  410. package/lib/module/web/pmPlugins/MentionPlugin/subscribeMentionEvents.js.map +1 -0
  411. package/lib/module/web/pmPlugins/MentionPlugin/types.js +4 -0
  412. package/lib/module/web/pmPlugins/MentionPlugin/types.js.map +1 -0
  413. package/lib/module/web/pmPlugins/MergeAdjacentSameKindBlocksPlugin.js +42 -0
  414. package/lib/module/web/pmPlugins/MergeAdjacentSameKindBlocksPlugin.js.map +1 -0
  415. package/lib/module/web/pmPlugins/ShortcutPlugin.js +123 -0
  416. package/lib/module/web/pmPlugins/ShortcutPlugin.js.map +1 -0
  417. package/lib/module/web/pmPlugins/StrictMarksPlugin.js +98 -0
  418. package/lib/module/web/pmPlugins/StrictMarksPlugin.js.map +1 -0
  419. package/lib/module/web/pmPlugins/StripBoldInStyledHeadingsPlugin.js +56 -0
  420. package/lib/module/web/pmPlugins/StripBoldInStyledHeadingsPlugin.js.map +1 -0
  421. package/lib/module/web/pmPlugins/StripMarksInCodeBlockPlugin.js +28 -0
  422. package/lib/module/web/pmPlugins/StripMarksInCodeBlockPlugin.js.map +1 -0
  423. package/lib/module/web/pmPlugins/StripMarksOnImagePlugin.js +29 -0
  424. package/lib/module/web/pmPlugins/StripMarksOnImagePlugin.js.map +1 -0
  425. package/lib/module/web/positionMapping.js +76 -0
  426. package/lib/module/web/positionMapping.js.map +1 -0
  427. package/lib/module/web/returnKeyTypeToEnterKeyHint.js +20 -0
  428. package/lib/module/web/returnKeyTypeToEnterKeyHint.js.map +1 -0
  429. package/lib/module/web/styleConversion/buildMentionRulesCSS.js +33 -0
  430. package/lib/module/web/styleConversion/buildMentionRulesCSS.js.map +1 -0
  431. package/lib/module/web/styleConversion/enrichedInputStyleToCSSProperties.js +159 -0
  432. package/lib/module/web/styleConversion/enrichedInputStyleToCSSProperties.js.map +1 -0
  433. package/lib/module/web/styleConversion/enrichedInputThemingToCSSProperties.js +18 -0
  434. package/lib/module/web/styleConversion/enrichedInputThemingToCSSProperties.js.map +1 -0
  435. package/lib/module/web/styleConversion/htmlStyleToCSSVariables.js +145 -0
  436. package/lib/module/web/styleConversion/htmlStyleToCSSVariables.js.map +1 -0
  437. package/lib/module/web/styleConversion/mentionIndicatorCssKey.js +15 -0
  438. package/lib/module/web/styleConversion/mentionIndicatorCssKey.js.map +1 -0
  439. package/lib/module/web/styleConversion/toColor.js +18 -0
  440. package/lib/module/web/styleConversion/toColor.js.map +1 -0
  441. package/lib/module/web/tiptapHtmlNormalizer.js +30 -0
  442. package/lib/module/web/tiptapHtmlNormalizer.js.map +1 -0
  443. package/lib/module/web/useOnChangeHtml.js +8 -0
  444. package/lib/module/web/useOnChangeHtml.js.map +1 -0
  445. package/lib/module/web/useOnChangeState.js +88 -0
  446. package/lib/module/web/useOnChangeState.js.map +1 -0
  447. package/lib/module/web/useOnChangeText.js +11 -0
  448. package/lib/module/web/useOnChangeText.js.map +1 -0
  449. package/lib/module/web/useOnEditorChange.js +25 -0
  450. package/lib/module/web/useOnEditorChange.js.map +1 -0
  451. package/lib/module/web/useOnLinkDetected.js +68 -0
  452. package/lib/module/web/useOnLinkDetected.js.map +1 -0
  453. package/lib/typescript/package.json +1 -0
  454. package/lib/typescript/src/index.d.ts +3 -0
  455. package/lib/typescript/src/index.d.ts.map +1 -0
  456. package/lib/typescript/src/index.native.d.ts +5 -0
  457. package/lib/typescript/src/index.native.d.ts.map +1 -0
  458. package/lib/typescript/src/native/EnrichedText.d.ts +3 -0
  459. package/lib/typescript/src/native/EnrichedText.d.ts.map +1 -0
  460. package/lib/typescript/src/native/EnrichedTextInput.d.ts +3 -0
  461. package/lib/typescript/src/native/EnrichedTextInput.d.ts.map +1 -0
  462. package/lib/typescript/src/spec/EnrichedTextInputNativeComponent.d.ts +405 -0
  463. package/lib/typescript/src/spec/EnrichedTextInputNativeComponent.d.ts.map +1 -0
  464. package/lib/typescript/src/spec/EnrichedTextNativeComponent.d.ts +88 -0
  465. package/lib/typescript/src/spec/EnrichedTextNativeComponent.d.ts.map +1 -0
  466. package/lib/typescript/src/types.d.ts +721 -0
  467. package/lib/typescript/src/types.d.ts.map +1 -0
  468. package/lib/typescript/src/utils/EnrichedTextInputDefaultProps.d.ts +13 -0
  469. package/lib/typescript/src/utils/EnrichedTextInputDefaultProps.d.ts.map +1 -0
  470. package/lib/typescript/src/utils/defaultHtmlStyle.d.ts +4 -0
  471. package/lib/typescript/src/utils/defaultHtmlStyle.d.ts.map +1 -0
  472. package/lib/typescript/src/utils/expandMentionStylesForIndicators.d.ts +3 -0
  473. package/lib/typescript/src/utils/expandMentionStylesForIndicators.d.ts.map +1 -0
  474. package/lib/typescript/src/utils/isMentionStyleRecord.d.ts +3 -0
  475. package/lib/typescript/src/utils/isMentionStyleRecord.d.ts.map +1 -0
  476. package/lib/typescript/src/utils/normalizeHtmlStyle.d.ts +6 -0
  477. package/lib/typescript/src/utils/normalizeHtmlStyle.d.ts.map +1 -0
  478. package/lib/typescript/src/utils/nullthrows.d.ts +2 -0
  479. package/lib/typescript/src/utils/nullthrows.d.ts.map +1 -0
  480. package/lib/typescript/src/utils/regexParser.d.ts +3 -0
  481. package/lib/typescript/src/utils/regexParser.d.ts.map +1 -0
  482. package/lib/typescript/src/web/EnrichedTextInput.d.ts +4 -0
  483. package/lib/typescript/src/web/EnrichedTextInput.d.ts.map +1 -0
  484. package/lib/typescript/src/web/adaptWebToNativeEvent.d.ts +3 -0
  485. package/lib/typescript/src/web/adaptWebToNativeEvent.d.ts.map +1 -0
  486. package/lib/typescript/src/web/checkboxHtmlNormalizer.d.ts +3 -0
  487. package/lib/typescript/src/web/checkboxHtmlNormalizer.d.ts.map +1 -0
  488. package/lib/typescript/src/web/formats/EnrichedBlockquote.d.ts +2 -0
  489. package/lib/typescript/src/web/formats/EnrichedBlockquote.d.ts.map +1 -0
  490. package/lib/typescript/src/web/formats/EnrichedBold.d.ts +2 -0
  491. package/lib/typescript/src/web/formats/EnrichedBold.d.ts.map +1 -0
  492. package/lib/typescript/src/web/formats/EnrichedCheckboxItem.d.ts +2 -0
  493. package/lib/typescript/src/web/formats/EnrichedCheckboxItem.d.ts.map +1 -0
  494. package/lib/typescript/src/web/formats/EnrichedCheckboxList.d.ts +9 -0
  495. package/lib/typescript/src/web/formats/EnrichedCheckboxList.d.ts.map +1 -0
  496. package/lib/typescript/src/web/formats/EnrichedCode.d.ts +2 -0
  497. package/lib/typescript/src/web/formats/EnrichedCode.d.ts.map +1 -0
  498. package/lib/typescript/src/web/formats/EnrichedCodeBlock.d.ts +9 -0
  499. package/lib/typescript/src/web/formats/EnrichedCodeBlock.d.ts.map +1 -0
  500. package/lib/typescript/src/web/formats/EnrichedHeading.d.ts +5 -0
  501. package/lib/typescript/src/web/formats/EnrichedHeading.d.ts.map +1 -0
  502. package/lib/typescript/src/web/formats/EnrichedImage.d.ts +2 -0
  503. package/lib/typescript/src/web/formats/EnrichedImage.d.ts.map +1 -0
  504. package/lib/typescript/src/web/formats/EnrichedImageNodeView.d.ts +3 -0
  505. package/lib/typescript/src/web/formats/EnrichedImageNodeView.d.ts.map +1 -0
  506. package/lib/typescript/src/web/formats/EnrichedItalic.d.ts +2 -0
  507. package/lib/typescript/src/web/formats/EnrichedItalic.d.ts.map +1 -0
  508. package/lib/typescript/src/web/formats/EnrichedLink.d.ts +5 -0
  509. package/lib/typescript/src/web/formats/EnrichedLink.d.ts.map +1 -0
  510. package/lib/typescript/src/web/formats/EnrichedListItem.d.ts +2 -0
  511. package/lib/typescript/src/web/formats/EnrichedListItem.d.ts.map +1 -0
  512. package/lib/typescript/src/web/formats/EnrichedMention.d.ts +4 -0
  513. package/lib/typescript/src/web/formats/EnrichedMention.d.ts.map +1 -0
  514. package/lib/typescript/src/web/formats/EnrichedOrderedList.d.ts +2 -0
  515. package/lib/typescript/src/web/formats/EnrichedOrderedList.d.ts.map +1 -0
  516. package/lib/typescript/src/web/formats/EnrichedStrike.d.ts +2 -0
  517. package/lib/typescript/src/web/formats/EnrichedStrike.d.ts.map +1 -0
  518. package/lib/typescript/src/web/formats/EnrichedUnderline.d.ts +2 -0
  519. package/lib/typescript/src/web/formats/EnrichedUnderline.d.ts.map +1 -0
  520. package/lib/typescript/src/web/formats/EnrichedUnorderedList.d.ts +9 -0
  521. package/lib/typescript/src/web/formats/EnrichedUnorderedList.d.ts.map +1 -0
  522. package/lib/typescript/src/web/formats/applyWrappingListToSelection.d.ts +18 -0
  523. package/lib/typescript/src/web/formats/applyWrappingListToSelection.d.ts.map +1 -0
  524. package/lib/typescript/src/web/formats/formatRules.d.ts +10 -0
  525. package/lib/typescript/src/web/formats/formatRules.d.ts.map +1 -0
  526. package/lib/typescript/src/web/formats/listKeyboard.d.ts +4 -0
  527. package/lib/typescript/src/web/formats/listKeyboard.d.ts.map +1 -0
  528. package/lib/typescript/src/web/formats/wrappedBlockKeyboard.d.ts +12 -0
  529. package/lib/typescript/src/web/formats/wrappedBlockKeyboard.d.ts.map +1 -0
  530. package/lib/typescript/src/web/pasteImages.d.ts +10 -0
  531. package/lib/typescript/src/web/pasteImages.d.ts.map +1 -0
  532. package/lib/typescript/src/web/pastedImageDimensions.d.ts +9 -0
  533. package/lib/typescript/src/web/pastedImageDimensions.d.ts.map +1 -0
  534. package/lib/typescript/src/web/pmPlugins/MentionPlugin/index.d.ts +9 -0
  535. package/lib/typescript/src/web/pmPlugins/MentionPlugin/index.d.ts.map +1 -0
  536. package/lib/typescript/src/web/pmPlugins/MentionPlugin/isCaretInBlockedContext.d.ts +3 -0
  537. package/lib/typescript/src/web/pmPlugins/MentionPlugin/isCaretInBlockedContext.d.ts.map +1 -0
  538. package/lib/typescript/src/web/pmPlugins/MentionPlugin/makeMentionPluginState.d.ts +4 -0
  539. package/lib/typescript/src/web/pmPlugins/MentionPlugin/makeMentionPluginState.d.ts.map +1 -0
  540. package/lib/typescript/src/web/pmPlugins/MentionPlugin/mentionPluginKey.d.ts +4 -0
  541. package/lib/typescript/src/web/pmPlugins/MentionPlugin/mentionPluginKey.d.ts.map +1 -0
  542. package/lib/typescript/src/web/pmPlugins/MentionPlugin/removeMentionMarksIfSpansResized.d.ts +9 -0
  543. package/lib/typescript/src/web/pmPlugins/MentionPlugin/removeMentionMarksIfSpansResized.d.ts.map +1 -0
  544. package/lib/typescript/src/web/pmPlugins/MentionPlugin/setMention.d.ts +3 -0
  545. package/lib/typescript/src/web/pmPlugins/MentionPlugin/setMention.d.ts.map +1 -0
  546. package/lib/typescript/src/web/pmPlugins/MentionPlugin/startMention.d.ts +3 -0
  547. package/lib/typescript/src/web/pmPlugins/MentionPlugin/startMention.d.ts.map +1 -0
  548. package/lib/typescript/src/web/pmPlugins/MentionPlugin/stripPartialMentionMarks.d.ts +3 -0
  549. package/lib/typescript/src/web/pmPlugins/MentionPlugin/stripPartialMentionMarks.d.ts.map +1 -0
  550. package/lib/typescript/src/web/pmPlugins/MentionPlugin/subscribeMentionEvents.d.ts +4 -0
  551. package/lib/typescript/src/web/pmPlugins/MentionPlugin/subscribeMentionEvents.d.ts.map +1 -0
  552. package/lib/typescript/src/web/pmPlugins/MentionPlugin/types.d.ts +20 -0
  553. package/lib/typescript/src/web/pmPlugins/MentionPlugin/types.d.ts.map +1 -0
  554. package/lib/typescript/src/web/pmPlugins/MergeAdjacentSameKindBlocksPlugin.d.ts +3 -0
  555. package/lib/typescript/src/web/pmPlugins/MergeAdjacentSameKindBlocksPlugin.d.ts.map +1 -0
  556. package/lib/typescript/src/web/pmPlugins/ShortcutPlugin.d.ts +7 -0
  557. package/lib/typescript/src/web/pmPlugins/ShortcutPlugin.d.ts.map +1 -0
  558. package/lib/typescript/src/web/pmPlugins/StrictMarksPlugin.d.ts +3 -0
  559. package/lib/typescript/src/web/pmPlugins/StrictMarksPlugin.d.ts.map +1 -0
  560. package/lib/typescript/src/web/pmPlugins/StripBoldInStyledHeadingsPlugin.d.ts +10 -0
  561. package/lib/typescript/src/web/pmPlugins/StripBoldInStyledHeadingsPlugin.d.ts.map +1 -0
  562. package/lib/typescript/src/web/pmPlugins/StripMarksInCodeBlockPlugin.d.ts +3 -0
  563. package/lib/typescript/src/web/pmPlugins/StripMarksInCodeBlockPlugin.d.ts.map +1 -0
  564. package/lib/typescript/src/web/pmPlugins/StripMarksOnImagePlugin.d.ts +3 -0
  565. package/lib/typescript/src/web/pmPlugins/StripMarksOnImagePlugin.d.ts.map +1 -0
  566. package/lib/typescript/src/web/positionMapping.d.ts +39 -0
  567. package/lib/typescript/src/web/positionMapping.d.ts.map +1 -0
  568. package/lib/typescript/src/web/returnKeyTypeToEnterKeyHint.d.ts +4 -0
  569. package/lib/typescript/src/web/returnKeyTypeToEnterKeyHint.d.ts.map +1 -0
  570. package/lib/typescript/src/web/styleConversion/buildMentionRulesCSS.d.ts +3 -0
  571. package/lib/typescript/src/web/styleConversion/buildMentionRulesCSS.d.ts.map +1 -0
  572. package/lib/typescript/src/web/styleConversion/enrichedInputStyleToCSSProperties.d.ts +8 -0
  573. package/lib/typescript/src/web/styleConversion/enrichedInputStyleToCSSProperties.d.ts.map +1 -0
  574. package/lib/typescript/src/web/styleConversion/enrichedInputThemingToCSSProperties.d.ts +9 -0
  575. package/lib/typescript/src/web/styleConversion/enrichedInputThemingToCSSProperties.d.ts.map +1 -0
  576. package/lib/typescript/src/web/styleConversion/htmlStyleToCSSVariables.d.ts +10 -0
  577. package/lib/typescript/src/web/styleConversion/htmlStyleToCSSVariables.d.ts.map +1 -0
  578. package/lib/typescript/src/web/styleConversion/mentionIndicatorCssKey.d.ts +3 -0
  579. package/lib/typescript/src/web/styleConversion/mentionIndicatorCssKey.d.ts.map +1 -0
  580. package/lib/typescript/src/web/styleConversion/toColor.d.ts +3 -0
  581. package/lib/typescript/src/web/styleConversion/toColor.d.ts.map +1 -0
  582. package/lib/typescript/src/web/tiptapHtmlNormalizer.d.ts +3 -0
  583. package/lib/typescript/src/web/tiptapHtmlNormalizer.d.ts.map +1 -0
  584. package/lib/typescript/src/web/useOnChangeHtml.d.ts +5 -0
  585. package/lib/typescript/src/web/useOnChangeHtml.d.ts.map +1 -0
  586. package/lib/typescript/src/web/useOnChangeState.d.ts +6 -0
  587. package/lib/typescript/src/web/useOnChangeState.d.ts.map +1 -0
  588. package/lib/typescript/src/web/useOnChangeText.d.ts +5 -0
  589. package/lib/typescript/src/web/useOnChangeText.d.ts.map +1 -0
  590. package/lib/typescript/src/web/useOnEditorChange.d.ts +6 -0
  591. package/lib/typescript/src/web/useOnEditorChange.d.ts.map +1 -0
  592. package/lib/typescript/src/web/useOnLinkDetected.d.ts +4 -0
  593. package/lib/typescript/src/web/useOnLinkDetected.d.ts.map +1 -0
  594. package/package.json +232 -1
  595. package/react-native.config.js +16 -0
  596. package/src/index.native.tsx +34 -0
  597. package/src/index.tsx +24 -0
  598. package/src/native/EnrichedText.tsx +115 -0
  599. package/src/native/EnrichedTextInput.tsx +374 -0
  600. package/src/spec/EnrichedTextInputNativeComponent.ts +524 -0
  601. package/src/spec/EnrichedTextNativeComponent.ts +110 -0
  602. package/src/types.ts +864 -0
  603. package/src/utils/EnrichedTextInputDefaultProps.ts +16 -0
  604. package/src/utils/defaultHtmlStyle.ts +83 -0
  605. package/src/utils/expandMentionStylesForIndicators.ts +19 -0
  606. package/src/utils/isMentionStyleRecord.ts +22 -0
  607. package/src/utils/normalizeHtmlStyle.ts +181 -0
  608. package/src/utils/nullthrows.ts +7 -0
  609. package/src/utils/regexParser.ts +56 -0
  610. package/src/web/EnrichedTextInput.css +201 -0
  611. package/src/web/EnrichedTextInput.tsx +403 -0
  612. package/src/web/adaptWebToNativeEvent.ts +37 -0
  613. package/src/web/checkboxHtmlNormalizer.ts +62 -0
  614. package/src/web/formats/EnrichedBlockquote.ts +36 -0
  615. package/src/web/formats/EnrichedBold.ts +16 -0
  616. package/src/web/formats/EnrichedCheckboxItem.ts +35 -0
  617. package/src/web/formats/EnrichedCheckboxList.ts +47 -0
  618. package/src/web/formats/EnrichedCode.ts +13 -0
  619. package/src/web/formats/EnrichedCodeBlock.ts +53 -0
  620. package/src/web/formats/EnrichedHeading.ts +36 -0
  621. package/src/web/formats/EnrichedImage.ts +59 -0
  622. package/src/web/formats/EnrichedImageNodeView.tsx +89 -0
  623. package/src/web/formats/EnrichedItalic.ts +16 -0
  624. package/src/web/formats/EnrichedLink.ts +149 -0
  625. package/src/web/formats/EnrichedListItem.ts +17 -0
  626. package/src/web/formats/EnrichedMention.ts +55 -0
  627. package/src/web/formats/EnrichedOrderedList.ts +40 -0
  628. package/src/web/formats/EnrichedStrike.ts +16 -0
  629. package/src/web/formats/EnrichedUnderline.ts +16 -0
  630. package/src/web/formats/EnrichedUnorderedList.ts +50 -0
  631. package/src/web/formats/applyWrappingListToSelection.ts +76 -0
  632. package/src/web/formats/formatRules.ts +84 -0
  633. package/src/web/formats/listKeyboard.ts +58 -0
  634. package/src/web/formats/wrappedBlockKeyboard.ts +76 -0
  635. package/src/web/pasteImages.ts +96 -0
  636. package/src/web/pastedImageDimensions.ts +40 -0
  637. package/src/web/pmPlugins/MentionPlugin/index.ts +45 -0
  638. package/src/web/pmPlugins/MentionPlugin/isCaretInBlockedContext.ts +17 -0
  639. package/src/web/pmPlugins/MentionPlugin/makeMentionPluginState.ts +75 -0
  640. package/src/web/pmPlugins/MentionPlugin/mentionPluginKey.ts +4 -0
  641. package/src/web/pmPlugins/MentionPlugin/removeMentionMarksIfSpansResized.ts +68 -0
  642. package/src/web/pmPlugins/MentionPlugin/setMention.ts +83 -0
  643. package/src/web/pmPlugins/MentionPlugin/startMention.ts +14 -0
  644. package/src/web/pmPlugins/MentionPlugin/stripPartialMentionMarks.ts +20 -0
  645. package/src/web/pmPlugins/MentionPlugin/subscribeMentionEvents.ts +105 -0
  646. package/src/web/pmPlugins/MentionPlugin/types.ts +22 -0
  647. package/src/web/pmPlugins/MergeAdjacentSameKindBlocksPlugin.ts +57 -0
  648. package/src/web/pmPlugins/ShortcutPlugin.ts +98 -0
  649. package/src/web/pmPlugins/StrictMarksPlugin.ts +131 -0
  650. package/src/web/pmPlugins/StripBoldInStyledHeadingsPlugin.ts +79 -0
  651. package/src/web/pmPlugins/StripMarksInCodeBlockPlugin.ts +34 -0
  652. package/src/web/pmPlugins/StripMarksOnImagePlugin.ts +33 -0
  653. package/src/web/positionMapping.ts +81 -0
  654. package/src/web/returnKeyTypeToEnterKeyHint.ts +29 -0
  655. package/src/web/styleConversion/buildMentionRulesCSS.ts +42 -0
  656. package/src/web/styleConversion/enrichedInputStyleToCSSProperties.ts +224 -0
  657. package/src/web/styleConversion/enrichedInputThemingToCSSProperties.ts +34 -0
  658. package/src/web/styleConversion/htmlStyleToCSSVariables.ts +226 -0
  659. package/src/web/styleConversion/mentionIndicatorCssKey.ts +14 -0
  660. package/src/web/styleConversion/toColor.ts +17 -0
  661. package/src/web/tiptapHtmlNormalizer.ts +33 -0
  662. package/src/web/useOnChangeHtml.ts +14 -0
  663. package/src/web/useOnChangeState.ts +125 -0
  664. package/src/web/useOnChangeText.ts +15 -0
  665. package/src/web/useOnEditorChange.ts +33 -0
  666. package/src/web/useOnLinkDetected.ts +82 -0
@@ -0,0 +1,1141 @@
1
+ package com.swmansion.enriched.textinput
2
+
3
+ import android.content.ClipData
4
+ import android.content.ClipboardManager
5
+ import android.content.Context
6
+ import android.graphics.BlendMode
7
+ import android.graphics.BlendModeColorFilter
8
+ import android.graphics.Color
9
+ import android.graphics.Rect
10
+ import android.graphics.text.LineBreaker
11
+ import android.os.Build
12
+ import android.text.InputType
13
+ import android.text.Spannable
14
+ import android.text.SpannableString
15
+ import android.util.AttributeSet
16
+ import android.util.Log
17
+ import android.util.Patterns
18
+ import android.util.TypedValue
19
+ import android.view.ActionMode
20
+ import android.view.Gravity
21
+ import android.view.KeyEvent
22
+ import android.view.Menu
23
+ import android.view.MenuItem
24
+ import android.view.MotionEvent
25
+ import android.view.inputmethod.EditorInfo
26
+ import android.view.inputmethod.InputConnection
27
+ import android.view.inputmethod.InputMethodManager
28
+ import android.widget.TextView
29
+ import androidx.appcompat.widget.AppCompatEditText
30
+ import androidx.core.view.ViewCompat
31
+ import com.facebook.react.bridge.ReactContext
32
+ import com.facebook.react.bridge.ReadableArray
33
+ import com.facebook.react.bridge.ReadableMap
34
+ import com.facebook.react.common.ReactConstants
35
+ import com.facebook.react.uimanager.StateWrapper
36
+ import com.facebook.react.uimanager.UIManagerHelper
37
+ import com.facebook.react.views.text.ReactTypefaceUtils.applyStyles
38
+ import com.facebook.react.views.text.ReactTypefaceUtils.parseFontStyle
39
+ import com.facebook.react.views.text.ReactTypefaceUtils.parseFontWeight
40
+ import com.swmansion.enriched.common.EnrichedConstants
41
+ import com.swmansion.enriched.common.GumboNormalizer
42
+ import com.swmansion.enriched.common.parser.EnrichedParser
43
+ import com.swmansion.enriched.common.pixelFromSpOrDp
44
+ import com.swmansion.enriched.textinput.events.MentionHandler
45
+ import com.swmansion.enriched.textinput.events.OnContextMenuItemPressEvent
46
+ import com.swmansion.enriched.textinput.events.OnInputBlurEvent
47
+ import com.swmansion.enriched.textinput.events.OnInputFocusEvent
48
+ import com.swmansion.enriched.textinput.events.OnRequestHtmlResultEvent
49
+ import com.swmansion.enriched.textinput.events.OnSubmitEditingEvent
50
+ import com.swmansion.enriched.textinput.spans.EnrichedInputH1Span
51
+ import com.swmansion.enriched.textinput.spans.EnrichedInputH2Span
52
+ import com.swmansion.enriched.textinput.spans.EnrichedInputH3Span
53
+ import com.swmansion.enriched.textinput.spans.EnrichedInputH4Span
54
+ import com.swmansion.enriched.textinput.spans.EnrichedInputH5Span
55
+ import com.swmansion.enriched.textinput.spans.EnrichedInputH6Span
56
+ import com.swmansion.enriched.textinput.spans.EnrichedInputImageSpan
57
+ import com.swmansion.enriched.textinput.spans.EnrichedLineHeightSpan
58
+ import com.swmansion.enriched.textinput.spans.EnrichedSpans
59
+ import com.swmansion.enriched.textinput.spans.interfaces.EnrichedInputSpan
60
+ import com.swmansion.enriched.textinput.styles.AlignmentStyles
61
+ import com.swmansion.enriched.textinput.styles.HtmlStyle
62
+ import com.swmansion.enriched.textinput.styles.InlineStyles
63
+ import com.swmansion.enriched.textinput.styles.ListStyles
64
+ import com.swmansion.enriched.textinput.styles.ParagraphStyles
65
+ import com.swmansion.enriched.textinput.styles.ParametrizedStyles
66
+ import com.swmansion.enriched.textinput.utils.EnrichedEditableFactory
67
+ import com.swmansion.enriched.textinput.utils.EnrichedSelection
68
+ import com.swmansion.enriched.textinput.utils.EnrichedSpanState
69
+ import com.swmansion.enriched.textinput.utils.RichContentReceiver
70
+ import com.swmansion.enriched.textinput.utils.ShortcutsHandler
71
+ import com.swmansion.enriched.textinput.utils.mergeSpannables
72
+ import com.swmansion.enriched.textinput.utils.setCheckboxClickListener
73
+ import com.swmansion.enriched.textinput.utils.zwsCountBefore
74
+ import com.swmansion.enriched.textinput.watchers.EnrichedSpanWatcher
75
+ import com.swmansion.enriched.textinput.watchers.EnrichedTextWatcher
76
+ import java.util.regex.Pattern
77
+ import java.util.regex.PatternSyntaxException
78
+ import kotlin.math.ceil
79
+
80
+ class EnrichedTextInputView :
81
+ AppCompatEditText,
82
+ TextView.OnEditorActionListener {
83
+ var stateWrapper: StateWrapper? = null
84
+ val selection: EnrichedSelection? = EnrichedSelection(this)
85
+ val spanState: EnrichedSpanState? = EnrichedSpanState(this)
86
+ val inlineStyles: InlineStyles? = InlineStyles(this)
87
+ val paragraphStyles: ParagraphStyles? = ParagraphStyles(this)
88
+ val listStyles: ListStyles? = ListStyles(this)
89
+ val shortcutsHandler: ShortcutsHandler? = ShortcutsHandler(this)
90
+ val parametrizedStyles: ParametrizedStyles? = ParametrizedStyles(this)
91
+ val alignmentStyles: AlignmentStyles? = AlignmentStyles(this)
92
+ var isDuringTransaction: Boolean = false
93
+ var isRemovingMany: Boolean = false
94
+ var scrollEnabled: Boolean = true
95
+ var allowFontScaling: Boolean = EnrichedConstants.ALLOW_FONT_SCALING_DEFAULT
96
+ set(value) {
97
+ if (field != value) {
98
+ field = value
99
+ val raw = fontSizeRaw
100
+ if (raw != null) {
101
+ setFontSize(raw) // re-invokes invalidateStyles internally
102
+ } else {
103
+ htmlStyle.invalidateStyles()
104
+ }
105
+ applyLineSpacing()
106
+ reApplyHtmlStyleForSpans(htmlStyle, htmlStyle) // force re-apply
107
+ }
108
+ }
109
+
110
+ val mentionHandler: MentionHandler? = MentionHandler(this)
111
+ var htmlStyle: HtmlStyle = HtmlStyle(this, null)
112
+ set(value) {
113
+ if (field != value) {
114
+ val prev = field
115
+ field = value
116
+ reApplyHtmlStyleForSpans(prev, value)
117
+ }
118
+ }
119
+
120
+ var linkRegex: Pattern? = Patterns.WEB_URL
121
+ var spanWatcher: EnrichedSpanWatcher? = null
122
+ var layoutManager: EnrichedTextInputViewLayoutManager = EnrichedTextInputViewLayoutManager(this)
123
+
124
+ var shouldEmitHtml: Boolean = false
125
+ var shouldEmitOnChangeText: Boolean = false
126
+ var experimentalSynchronousEvents: Boolean = false
127
+ var useHtmlNormalizer: Boolean = false
128
+
129
+ // Pair: (trigger, style)
130
+ var textShortcuts: List<Pair<String, String>> = emptyList()
131
+
132
+ private var fontSizeRaw: Float? = null
133
+ var fontSize: Float? = null
134
+ private var lineHeight: Float? = null
135
+ var submitBehavior: String? = null
136
+ private var autoFocus = false
137
+ private var typefaceDirty = false
138
+ private var didAttachToWindow = false
139
+ private var detectScrollMovement = false
140
+ private var fontFamily: String? = null
141
+ private var fontStyle: Int = ReactConstants.UNSET
142
+ private var fontWeight: Int = ReactConstants.UNSET
143
+ private var defaultValue: CharSequence? = null
144
+ private var defaultValueDirty: Boolean = false
145
+
146
+ private var inputMethodManager: InputMethodManager? = null
147
+ private val spannableFactory = EnrichedTextInputSpannableFactory()
148
+ private var contextMenuItems: List<Pair<Int, String>> = emptyList()
149
+
150
+ constructor(context: Context) : super(context) {
151
+ prepareComponent()
152
+ }
153
+
154
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
155
+ prepareComponent()
156
+ }
157
+
158
+ constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
159
+ context,
160
+ attrs,
161
+ defStyleAttr,
162
+ ) {
163
+ prepareComponent()
164
+ }
165
+
166
+ override fun scrollTo(
167
+ x: Int,
168
+ y: Int,
169
+ ) {
170
+ // Android's internal cursor tracker gets confused by ALIGN_CENTER + LeadingMarginSpan
171
+ // and attempts to scroll the text horizontally.
172
+ // We lock the horizontal scroll to 0 to prevent the view from shifting.
173
+ super.scrollTo(0, y)
174
+ }
175
+
176
+ override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection? {
177
+ var inputConnection = super.onCreateInputConnection(outAttrs)
178
+
179
+ if (shouldSubmitOnReturn()) {
180
+ // Remove the "No Enter Action" flag if it exists
181
+ outAttrs.imeOptions = outAttrs.imeOptions and EditorInfo.IME_FLAG_NO_ENTER_ACTION.inv()
182
+
183
+ // Force the key to be "Done" (or whatever label you set) instead of "Return"
184
+ // This ensures onEditorAction gets called instead of just inserting \n
185
+ if (outAttrs.imeOptions and EditorInfo.IME_MASK_ACTION == EditorInfo.IME_ACTION_UNSPECIFIED) {
186
+ outAttrs.imeOptions = outAttrs.imeOptions or EditorInfo.IME_ACTION_DONE
187
+ }
188
+ }
189
+
190
+ if (inputConnection != null) {
191
+ inputConnection =
192
+ EnrichedTextInputConnectionWrapper(
193
+ inputConnection,
194
+ context as ReactContext,
195
+ this,
196
+ experimentalSynchronousEvents,
197
+ )
198
+ }
199
+
200
+ return inputConnection
201
+ }
202
+
203
+ init {
204
+ inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
205
+ ViewCompat.setOnReceiveContentListener(
206
+ this,
207
+ RichContentReceiver.MIME_TYPES,
208
+ RichContentReceiver(this, context as ReactContext),
209
+ )
210
+ }
211
+
212
+ private fun prepareComponent() {
213
+ isSingleLine = false
214
+ isHorizontalScrollBarEnabled = false
215
+ isVerticalScrollBarEnabled = true
216
+ gravity = Gravity.TOP or Gravity.START
217
+ inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE
218
+
219
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
220
+ breakStrategy = LineBreaker.BREAK_STRATEGY_HIGH_QUALITY
221
+ }
222
+
223
+ setPadding(0, 0, 0, 0)
224
+ setBackgroundColor(Color.TRANSPARENT)
225
+
226
+ // Ensure that every time new editable is created, it has EnrichedSpanWatcher attached
227
+ val spanWatcher = EnrichedSpanWatcher(this)
228
+ this.spanWatcher = spanWatcher
229
+
230
+ setEditableFactory(EnrichedEditableFactory(spanWatcher))
231
+ addTextChangedListener(EnrichedTextWatcher(this))
232
+
233
+ // Handle checkbox list item clicks
234
+ this.setCheckboxClickListener()
235
+
236
+ setOnEditorActionListener(this)
237
+ setReturnKeyLabel(DEFAULT_IME_ACTION_LABEL)
238
+ }
239
+
240
+ // Similar implementation to: https://github.com/facebook/react-native/blob/c1f5445f4a59d0035389725e47da58eb3d2c267c/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.kt#L940
241
+ override fun onEditorAction(
242
+ v: TextView?,
243
+ actionId: Int,
244
+ event: KeyEvent?,
245
+ ): Boolean {
246
+ // Check if it's a valid keyboard action (Done, Next, etc.) or the Enter key (IME_NULL)
247
+ val isAction = (actionId and EditorInfo.IME_MASK_ACTION) != 0 || actionId == EditorInfo.IME_NULL
248
+
249
+ if (isAction) {
250
+ val shouldSubmit = shouldSubmitOnReturn()
251
+ val shouldBlur = shouldBlurOnReturn()
252
+
253
+ if (shouldSubmit) {
254
+ emitSubmitEditing()
255
+ }
256
+
257
+ if (shouldBlur) {
258
+ clearFocus()
259
+ }
260
+
261
+ if (shouldSubmit || shouldBlur) {
262
+ return true
263
+ }
264
+ }
265
+
266
+ // Return false to let the system handle default behavior (like inserting \n)
267
+ return false
268
+ }
269
+
270
+ private fun emitSubmitEditing() {
271
+ val context = context as ReactContext
272
+ val surfaceId = UIManagerHelper.getSurfaceId(context)
273
+ val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, id)
274
+ dispatcher?.dispatchEvent(
275
+ OnSubmitEditingEvent(
276
+ surfaceId,
277
+ id,
278
+ text,
279
+ experimentalSynchronousEvents,
280
+ ),
281
+ )
282
+ }
283
+
284
+ // https://github.com/facebook/react-native/blob/36df97f500aa0aa8031098caf7526db358b6ddc1/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt#L295C1-L296C1
285
+ override fun onTouchEvent(ev: MotionEvent): Boolean {
286
+ when (ev.action) {
287
+ MotionEvent.ACTION_DOWN -> {
288
+ detectScrollMovement = true
289
+ // Disallow parent views to intercept touch events, until we can detect if we should be
290
+ // capturing these touches or not.
291
+ this.parent.requestDisallowInterceptTouchEvent(true)
292
+ }
293
+
294
+ MotionEvent.ACTION_MOVE -> {
295
+ if (detectScrollMovement) {
296
+ if (!canScrollVertically(-1) &&
297
+ !canScrollVertically(1) &&
298
+ !canScrollHorizontally(-1) &&
299
+ !canScrollHorizontally(1)
300
+ ) {
301
+ // We cannot scroll, let parent views take care of these touches.
302
+ this.parent.requestDisallowInterceptTouchEvent(false)
303
+ }
304
+ detectScrollMovement = false
305
+ }
306
+ }
307
+ }
308
+
309
+ return super.onTouchEvent(ev)
310
+ }
311
+
312
+ override fun canScrollVertically(direction: Int): Boolean = scrollEnabled
313
+
314
+ override fun canScrollHorizontally(direction: Int): Boolean = scrollEnabled
315
+
316
+ override fun onSelectionChanged(
317
+ selStart: Int,
318
+ selEnd: Int,
319
+ ) {
320
+ super.onSelectionChanged(selStart, selEnd)
321
+ selection?.onSelection(selStart, selEnd)
322
+ }
323
+
324
+ override fun clearFocus() {
325
+ super.clearFocus()
326
+ inputMethodManager?.hideSoftInputFromWindow(windowToken, 0)
327
+ }
328
+
329
+ override fun onFocusChanged(
330
+ focused: Boolean,
331
+ direction: Int,
332
+ previouslyFocusedRect: Rect?,
333
+ ) {
334
+ super.onFocusChanged(focused, direction, previouslyFocusedRect)
335
+ val context = context as ReactContext
336
+ val surfaceId = UIManagerHelper.getSurfaceId(context)
337
+ val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, id)
338
+
339
+ if (focused) {
340
+ dispatcher?.dispatchEvent(OnInputFocusEvent(surfaceId, id, experimentalSynchronousEvents))
341
+ } else {
342
+ dispatcher?.dispatchEvent(OnInputBlurEvent(surfaceId, id, experimentalSynchronousEvents))
343
+ }
344
+ }
345
+
346
+ override fun onTextContextMenuItem(id: Int): Boolean {
347
+ when (id) {
348
+ android.R.id.copy -> {
349
+ handleCustomCopy()
350
+ return true
351
+ }
352
+ }
353
+ return super.onTextContextMenuItem(id)
354
+ }
355
+
356
+ private fun handleCustomCopy() {
357
+ val start = selectionStart
358
+ val end = selectionEnd
359
+ val spannable = text as Spannable
360
+
361
+ if (start < end) {
362
+ val selectedText = spannable.subSequence(start, end) as Spannable
363
+ val selectedHtml = EnrichedParser.toHtml(selectedText)
364
+
365
+ val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
366
+ val clip = ClipData.newHtmlText(EnrichedConstants.CLIPBOARD_TAG, selectedText, selectedHtml)
367
+ clipboard.setPrimaryClip(clip)
368
+ }
369
+ }
370
+
371
+ fun handleTextPaste(item: ClipData.Item) {
372
+ val currentText = text as Spannable
373
+ val start = selectionStart.coerceAtLeast(0)
374
+ val end = selectionEnd.coerceAtLeast(0)
375
+ val lengthBefore = currentText.length
376
+
377
+ val pastedSpannable: Spannable =
378
+ when {
379
+ item.htmlText != null -> {
380
+ val parsed = parseText(item.htmlText)
381
+ (parsed as? Spannable) ?: return
382
+ }
383
+
384
+ item.text != null -> {
385
+ SpannableString(item.text.toString())
386
+ }
387
+
388
+ else -> {
389
+ return
390
+ }
391
+ }
392
+
393
+ val finalText = currentText.mergeSpannables(start, end, pastedSpannable, htmlStyle)
394
+ setValue(finalText, false)
395
+
396
+ // replacement-safe: oldLength - removed + inserted
397
+ val insertedLength = finalText.length - (lengthBefore - (end - start))
398
+ val pasteEnd = (start + insertedLength).coerceIn(0, finalText.length)
399
+ setSelection(pasteEnd)
400
+
401
+ // Detect links in the newly pasted range
402
+ parametrizedStyles?.detectLinksInRange(finalText, start.coerceAtMost(pasteEnd), pasteEnd)
403
+ }
404
+
405
+ fun requestFocusProgrammatically() {
406
+ requestFocus()
407
+ inputMethodManager?.showSoftInput(this, 0)
408
+ setSelection(selection?.start ?: text?.length ?: 0)
409
+ }
410
+
411
+ private fun normalizeHtmlIfNeeded(text: CharSequence): CharSequence {
412
+ if (!useHtmlNormalizer) return text
413
+ val normalized = GumboNormalizer.normalizeHtml(text.toString()) ?: return text
414
+
415
+ return try {
416
+ val parsed = EnrichedParser.fromHtml(normalized, htmlStyle, spannableFactory)
417
+ parsed.trimEnd('\n')
418
+ } catch (e: Exception) {
419
+ Log.e(TAG, "Error parsing normalized HTML: ${e.message}")
420
+ text
421
+ }
422
+ }
423
+
424
+ private fun parseText(text: CharSequence): CharSequence {
425
+ val isInternalHtml = text.startsWith("<html>") && text.endsWith("</html>")
426
+
427
+ if (isInternalHtml) {
428
+ try {
429
+ val parsed = EnrichedParser.fromHtml(text.toString(), htmlStyle, spannableFactory)
430
+ return parsed.trimEnd('\n')
431
+ } catch (e: Exception) {
432
+ Log.e(TAG, "Error parsing HTML: ${e.message}")
433
+ return normalizeHtmlIfNeeded(text)
434
+ }
435
+ }
436
+
437
+ return normalizeHtmlIfNeeded(text)
438
+ }
439
+
440
+ fun setValue(
441
+ value: CharSequence?,
442
+ shouldParseHtml: Boolean = true,
443
+ ) {
444
+ if (value == null) return
445
+
446
+ runAsATransaction {
447
+ val newText = if (shouldParseHtml) parseText(value) else value
448
+ setText(newText)
449
+ applyLineSpacing()
450
+
451
+ observeAsyncImages()
452
+
453
+ // Scroll to the last line of text
454
+ setSelection(text?.length ?: 0)
455
+ }
456
+ layoutManager.invalidateLayout()
457
+ }
458
+
459
+ fun setCustomSelection(
460
+ visibleStart: Int,
461
+ visibleEnd: Int,
462
+ ) {
463
+ val actualStart = getActualIndex(visibleStart)
464
+ val actualEnd = getActualIndex(visibleEnd)
465
+
466
+ setSelection(actualStart, actualEnd)
467
+ }
468
+
469
+ // Helper: Walks through the string skipping ZWSPs to find the Nth visible character
470
+ private fun getActualIndex(visibleIndex: Int): Int {
471
+ val currentText = text as Spannable
472
+ var currentVisibleCount = 0
473
+ var actualIndex = 0
474
+
475
+ while (actualIndex < currentText.length) {
476
+ if (currentVisibleCount == visibleIndex) {
477
+ return actualIndex
478
+ }
479
+
480
+ // If the current char is not a hidden space, it counts towards our visible index
481
+ if (currentText[actualIndex] != EnrichedConstants.ZWS) {
482
+ currentVisibleCount++
483
+ }
484
+ actualIndex++
485
+ }
486
+
487
+ return actualIndex
488
+ }
489
+
490
+ /**
491
+ * Finds all async images in the current text and sets up listeners
492
+ * to redraw the text layout when they finish downloading.
493
+ */
494
+ private fun observeAsyncImages() {
495
+ val liveText = text ?: return
496
+
497
+ val spans = liveText.getSpans(0, liveText.length, EnrichedInputImageSpan::class.java)
498
+
499
+ for (span in spans) {
500
+ span.observeAsyncDrawableLoaded(liveText)
501
+ }
502
+ }
503
+
504
+ fun setAutoFocus(autoFocus: Boolean) {
505
+ this.autoFocus = autoFocus
506
+ }
507
+
508
+ fun setPlaceholder(placeholder: String?) {
509
+ if (placeholder == null) return
510
+
511
+ hint = placeholder
512
+ }
513
+
514
+ fun setPlaceholderTextColor(colorInt: Int?) {
515
+ if (colorInt == null) return
516
+
517
+ setHintTextColor(colorInt)
518
+ }
519
+
520
+ fun setSelectionColor(colorInt: Int?) {
521
+ if (colorInt == null) return
522
+
523
+ highlightColor = colorInt
524
+ }
525
+
526
+ fun setCursorColor(colorInt: Int?) {
527
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
528
+ val cursorDrawable = textCursorDrawable ?: return
529
+
530
+ if (colorInt != null) {
531
+ cursorDrawable.colorFilter = BlendModeColorFilter(colorInt, BlendMode.SRC_IN)
532
+ } else {
533
+ cursorDrawable.clearColorFilter()
534
+ }
535
+
536
+ textCursorDrawable = cursorDrawable
537
+ }
538
+ }
539
+
540
+ fun setReturnKeyLabel(returnKeyLabel: String?) {
541
+ setImeActionLabel(returnKeyLabel, EditorInfo.IME_ACTION_UNSPECIFIED)
542
+ }
543
+
544
+ fun setColor(colorInt: Int?) {
545
+ if (colorInt == null) {
546
+ setTextColor(Color.BLACK)
547
+ return
548
+ }
549
+
550
+ setTextColor(colorInt)
551
+ }
552
+
553
+ fun setFontSize(size: Float) {
554
+ if (size == 0f) return
555
+ fontSizeRaw = size
556
+
557
+ val sizeInt = ceil(pixelFromSpOrDp(size, allowFontScaling))
558
+ fontSize = sizeInt
559
+ setTextSize(TypedValue.COMPLEX_UNIT_PX, sizeInt)
560
+
561
+ // This ensured that newly created spans will take the new font size into account
562
+ htmlStyle.invalidateStyles()
563
+ layoutManager.invalidateLayout()
564
+ forceScrollToSelection()
565
+ }
566
+
567
+ fun setLineHeight(height: Float) {
568
+ lineHeight = if (height == 0f) null else height
569
+ applyLineSpacing()
570
+ layoutManager.invalidateLayout()
571
+ forceScrollToSelection()
572
+ }
573
+
574
+ private fun applyLineSpacing() {
575
+ val spannable = text as? Spannable ?: return
576
+ spannable
577
+ .getSpans(0, spannable.length, EnrichedLineHeightSpan::class.java)
578
+ .forEach { spannable.removeSpan(it) }
579
+
580
+ val lh = lineHeight ?: return
581
+ spannable.setSpan(
582
+ EnrichedLineHeightSpan(lh, allowFontScaling),
583
+ 0,
584
+ spannable.length,
585
+ Spannable.SPAN_INCLUSIVE_INCLUSIVE,
586
+ )
587
+ }
588
+
589
+ fun setFontFamily(family: String?) {
590
+ if (family != fontFamily) {
591
+ fontFamily = family
592
+ typefaceDirty = true
593
+ }
594
+ }
595
+
596
+ fun setFontWeight(weight: String?) {
597
+ val fontWeight = parseFontWeight(weight)
598
+
599
+ if (fontWeight != fontStyle) {
600
+ this.fontWeight = fontWeight
601
+ typefaceDirty = true
602
+ }
603
+ }
604
+
605
+ fun setFontStyle(style: String?) {
606
+ val fontStyle = parseFontStyle(style)
607
+
608
+ if (fontStyle != this.fontStyle) {
609
+ this.fontStyle = fontStyle
610
+ typefaceDirty = true
611
+ }
612
+ }
613
+
614
+ fun setAutoCapitalize(flagName: String?) {
615
+ val flag =
616
+ when (flagName) {
617
+ "none" -> InputType.TYPE_NULL
618
+ "sentences" -> InputType.TYPE_TEXT_FLAG_CAP_SENTENCES
619
+ "words" -> InputType.TYPE_TEXT_FLAG_CAP_WORDS
620
+ "characters" -> InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS
621
+ else -> InputType.TYPE_NULL
622
+ }
623
+
624
+ inputType = (
625
+ inputType and
626
+ InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS.inv() and
627
+ InputType.TYPE_TEXT_FLAG_CAP_WORDS.inv() and
628
+ InputType.TYPE_TEXT_FLAG_CAP_SENTENCES.inv()
629
+ ) or if (flag == InputType.TYPE_NULL) 0 else flag
630
+ }
631
+
632
+ fun setLinkRegex(config: ReadableMap?) {
633
+ val patternStr = config?.getString("pattern")
634
+ if (patternStr == null) {
635
+ linkRegex = Patterns.WEB_URL
636
+ return
637
+ }
638
+
639
+ if (config.getBoolean("isDefault")) {
640
+ linkRegex = Patterns.WEB_URL
641
+ return
642
+ }
643
+
644
+ if (config.getBoolean("isDisabled")) {
645
+ linkRegex = null
646
+ return
647
+ }
648
+
649
+ var flags = 0
650
+ if (config.getBoolean("caseInsensitive")) flags = flags or Pattern.CASE_INSENSITIVE
651
+ if (config.getBoolean("dotAll")) flags = flags or Pattern.DOTALL
652
+
653
+ try {
654
+ linkRegex = Pattern.compile("(?s).*?($patternStr).*", flags)
655
+ } catch (_: PatternSyntaxException) {
656
+ Log.w(TAG, "Invalid link regex pattern: $patternStr")
657
+ linkRegex = Patterns.WEB_URL
658
+ }
659
+ }
660
+
661
+ fun setContextMenuItems(items: ReadableArray?) {
662
+ if (items == null) {
663
+ contextMenuItems = emptyList()
664
+ return
665
+ }
666
+
667
+ val result = mutableListOf<Pair<Int, String>>()
668
+ for (i in 0 until items.size()) {
669
+ val item = items.getMap(i) ?: continue
670
+ val text = item.getString("text") ?: continue
671
+ result.add(Pair(i, text))
672
+ }
673
+
674
+ contextMenuItems = result
675
+ }
676
+
677
+ override fun startActionMode(
678
+ callback: ActionMode.Callback?,
679
+ type: Int,
680
+ ): ActionMode? {
681
+ if (contextMenuItems.isEmpty()) {
682
+ return super.startActionMode(callback, type)
683
+ }
684
+
685
+ val wrappedCallback =
686
+ object : ActionMode.Callback2() {
687
+ override fun onCreateActionMode(
688
+ mode: ActionMode,
689
+ menu: Menu,
690
+ ): Boolean {
691
+ val result = callback?.onCreateActionMode(mode, menu) ?: false
692
+ for ((index, text) in contextMenuItems) {
693
+ menu.add(Menu.NONE, CONTEXT_MENU_ITEM_ID + index, Menu.NONE, text)
694
+ }
695
+
696
+ return result
697
+ }
698
+
699
+ override fun onPrepareActionMode(
700
+ mode: ActionMode,
701
+ menu: Menu,
702
+ ) = callback?.onPrepareActionMode(mode, menu) ?: false
703
+
704
+ override fun onActionItemClicked(
705
+ mode: ActionMode,
706
+ menuItem: MenuItem,
707
+ ): Boolean {
708
+ val itemId = menuItem.itemId
709
+ if (itemId < CONTEXT_MENU_ITEM_ID) {
710
+ return callback?.onActionItemClicked(mode, menuItem) ?: false
711
+ }
712
+
713
+ val selStart = selection?.start ?: 0
714
+ val selEnd = selection?.end ?: 0
715
+ val itemText = contextMenuItems.getOrNull(itemId - CONTEXT_MENU_ITEM_ID)?.second ?: return false
716
+ emitContextMenuItemPressEvent(itemText)
717
+ mode.finish()
718
+ post {
719
+ // Ensures selection is not lost after the action mode is finished
720
+ if (selStart in 0..selEnd) {
721
+ setSelection(selStart, selEnd)
722
+ }
723
+ }
724
+ return true
725
+ }
726
+
727
+ override fun onDestroyActionMode(mode: ActionMode) {
728
+ callback?.onDestroyActionMode(mode)
729
+ }
730
+ }
731
+
732
+ return super.startActionMode(wrappedCallback, type)
733
+ }
734
+
735
+ private fun emitContextMenuItemPressEvent(itemText: String) {
736
+ val start = selection?.start ?: return
737
+ val end = selection.end
738
+ val styleState = spanState?.getStyleStatePayload() ?: return
739
+ val currentText = text ?: return
740
+ val selectedText = currentText.subSequence(start, end).toString().replace(EnrichedConstants.ZWS_STRING, "")
741
+
742
+ val visibleStart = start - currentText.zwsCountBefore(start)
743
+ val visibleEnd = end - currentText.zwsCountBefore(end)
744
+
745
+ val reactContext = context as ReactContext
746
+ val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
747
+ val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id)
748
+ dispatcher?.dispatchEvent(
749
+ OnContextMenuItemPressEvent(
750
+ surfaceId,
751
+ id,
752
+ itemText,
753
+ selectedText,
754
+ visibleStart,
755
+ visibleEnd,
756
+ styleState,
757
+ experimentalSynchronousEvents,
758
+ ),
759
+ )
760
+ }
761
+
762
+ // https://github.com/facebook/react-native/blob/36df97f500aa0aa8031098caf7526db358b6ddc1/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt#L283C2-L284C1
763
+ // After the text changes inside an EditText, TextView checks if a layout() has been requested.
764
+ // If it has, it will not scroll the text to the end of the new text inserted, but wait for the
765
+ // next layout() to be called. However, we do not perform a layout() after a requestLayout(), so
766
+ // we need to override isLayoutRequested to force EditText to scroll to the end of the new text
767
+ // immediately.
768
+ override fun isLayoutRequested(): Boolean = false
769
+
770
+ fun afterUpdateTransaction() {
771
+ updateTypeface()
772
+ updateDefaultValue()
773
+ }
774
+
775
+ fun setDefaultValue(value: CharSequence?) {
776
+ defaultValue = value
777
+ defaultValueDirty = true
778
+ }
779
+
780
+ fun shouldBlurOnReturn(): Boolean = submitBehavior == "blurAndSubmit"
781
+
782
+ fun shouldSubmitOnReturn(): Boolean = submitBehavior == "submit" || submitBehavior == "blurAndSubmit"
783
+
784
+ private fun updateDefaultValue() {
785
+ if (!defaultValueDirty) return
786
+
787
+ defaultValueDirty = false
788
+ setValue(defaultValue ?: "")
789
+ }
790
+
791
+ private fun updateTypeface() {
792
+ if (!typefaceDirty) return
793
+ typefaceDirty = false
794
+
795
+ val newTypeface = applyStyles(typeface, fontStyle, fontWeight, fontFamily, context.assets)
796
+ typeface = newTypeface
797
+ paint.typeface = newTypeface
798
+
799
+ layoutManager.invalidateLayout()
800
+ }
801
+
802
+ internal fun toggleStyle(name: String) {
803
+ when (name) {
804
+ EnrichedSpans.BOLD -> inlineStyles?.toggleStyle(EnrichedSpans.BOLD)
805
+ EnrichedSpans.ITALIC -> inlineStyles?.toggleStyle(EnrichedSpans.ITALIC)
806
+ EnrichedSpans.UNDERLINE -> inlineStyles?.toggleStyle(EnrichedSpans.UNDERLINE)
807
+ EnrichedSpans.STRIKETHROUGH -> inlineStyles?.toggleStyle(EnrichedSpans.STRIKETHROUGH)
808
+ EnrichedSpans.INLINE_CODE -> inlineStyles?.toggleStyle(EnrichedSpans.INLINE_CODE)
809
+ EnrichedSpans.H1 -> paragraphStyles?.toggleStyle(EnrichedSpans.H1)
810
+ EnrichedSpans.H2 -> paragraphStyles?.toggleStyle(EnrichedSpans.H2)
811
+ EnrichedSpans.H3 -> paragraphStyles?.toggleStyle(EnrichedSpans.H3)
812
+ EnrichedSpans.H4 -> paragraphStyles?.toggleStyle(EnrichedSpans.H4)
813
+ EnrichedSpans.H5 -> paragraphStyles?.toggleStyle(EnrichedSpans.H5)
814
+ EnrichedSpans.H6 -> paragraphStyles?.toggleStyle(EnrichedSpans.H6)
815
+ EnrichedSpans.CODE_BLOCK -> paragraphStyles?.toggleStyle(EnrichedSpans.CODE_BLOCK)
816
+ EnrichedSpans.BLOCK_QUOTE -> paragraphStyles?.toggleStyle(EnrichedSpans.BLOCK_QUOTE)
817
+ EnrichedSpans.ORDERED_LIST -> listStyles?.toggleStyle(EnrichedSpans.ORDERED_LIST)
818
+ EnrichedSpans.UNORDERED_LIST -> listStyles?.toggleStyle(EnrichedSpans.UNORDERED_LIST)
819
+ EnrichedSpans.CHECKBOX_LIST -> listStyles?.toggleStyle(EnrichedSpans.CHECKBOX_LIST)
820
+ else -> Log.w(TAG, "Unknown style: $name")
821
+ }
822
+
823
+ layoutManager.invalidateLayout()
824
+ }
825
+
826
+ private fun removeStyle(
827
+ name: String,
828
+ start: Int,
829
+ end: Int,
830
+ ): Boolean {
831
+ val removed =
832
+ when (name) {
833
+ EnrichedSpans.BOLD -> inlineStyles?.removeStyle(EnrichedSpans.BOLD, start, end)
834
+ EnrichedSpans.ITALIC -> inlineStyles?.removeStyle(EnrichedSpans.ITALIC, start, end)
835
+ EnrichedSpans.UNDERLINE -> inlineStyles?.removeStyle(EnrichedSpans.UNDERLINE, start, end)
836
+ EnrichedSpans.STRIKETHROUGH -> inlineStyles?.removeStyle(EnrichedSpans.STRIKETHROUGH, start, end)
837
+ EnrichedSpans.INLINE_CODE -> inlineStyles?.removeStyle(EnrichedSpans.INLINE_CODE, start, end)
838
+ EnrichedSpans.H1 -> paragraphStyles?.removeStyle(EnrichedSpans.H1, start, end)
839
+ EnrichedSpans.H2 -> paragraphStyles?.removeStyle(EnrichedSpans.H2, start, end)
840
+ EnrichedSpans.H3 -> paragraphStyles?.removeStyle(EnrichedSpans.H3, start, end)
841
+ EnrichedSpans.H4 -> paragraphStyles?.removeStyle(EnrichedSpans.H4, start, end)
842
+ EnrichedSpans.H5 -> paragraphStyles?.removeStyle(EnrichedSpans.H5, start, end)
843
+ EnrichedSpans.H6 -> paragraphStyles?.removeStyle(EnrichedSpans.H6, start, end)
844
+ EnrichedSpans.CODE_BLOCK -> paragraphStyles?.removeStyle(EnrichedSpans.CODE_BLOCK, start, end)
845
+ EnrichedSpans.BLOCK_QUOTE -> paragraphStyles?.removeStyle(EnrichedSpans.BLOCK_QUOTE, start, end)
846
+ EnrichedSpans.ORDERED_LIST -> listStyles?.removeStyle(EnrichedSpans.ORDERED_LIST, start, end)
847
+ EnrichedSpans.UNORDERED_LIST -> listStyles?.removeStyle(EnrichedSpans.UNORDERED_LIST, start, end)
848
+ EnrichedSpans.CHECKBOX_LIST -> listStyles?.removeStyle(EnrichedSpans.CHECKBOX_LIST, start, end)
849
+ EnrichedSpans.LINK -> parametrizedStyles?.removeStyle(EnrichedSpans.LINK, start, end)
850
+ EnrichedSpans.IMAGE -> parametrizedStyles?.removeStyle(EnrichedSpans.IMAGE, start, end)
851
+ EnrichedSpans.MENTION -> parametrizedStyles?.removeStyle(EnrichedSpans.MENTION, start, end)
852
+ else -> false
853
+ }
854
+
855
+ return removed == true
856
+ }
857
+
858
+ private fun getTargetRange(name: String): Pair<Int, Int> {
859
+ val result =
860
+ when (name) {
861
+ EnrichedSpans.BOLD -> inlineStyles?.getStyleRange()
862
+ EnrichedSpans.ITALIC -> inlineStyles?.getStyleRange()
863
+ EnrichedSpans.UNDERLINE -> inlineStyles?.getStyleRange()
864
+ EnrichedSpans.STRIKETHROUGH -> inlineStyles?.getStyleRange()
865
+ EnrichedSpans.INLINE_CODE -> inlineStyles?.getStyleRange()
866
+ EnrichedSpans.H1 -> paragraphStyles?.getStyleRange()
867
+ EnrichedSpans.H2 -> paragraphStyles?.getStyleRange()
868
+ EnrichedSpans.H3 -> paragraphStyles?.getStyleRange()
869
+ EnrichedSpans.H4 -> paragraphStyles?.getStyleRange()
870
+ EnrichedSpans.H5 -> paragraphStyles?.getStyleRange()
871
+ EnrichedSpans.H6 -> paragraphStyles?.getStyleRange()
872
+ EnrichedSpans.CODE_BLOCK -> paragraphStyles?.getStyleRange()
873
+ EnrichedSpans.BLOCK_QUOTE -> paragraphStyles?.getStyleRange()
874
+ EnrichedSpans.ORDERED_LIST -> listStyles?.getStyleRange()
875
+ EnrichedSpans.UNORDERED_LIST -> listStyles?.getStyleRange()
876
+ EnrichedSpans.CHECKBOX_LIST -> listStyles?.getStyleRange()
877
+ EnrichedSpans.LINK -> parametrizedStyles?.getStyleRange()
878
+ EnrichedSpans.IMAGE -> parametrizedStyles?.getStyleRange()
879
+ EnrichedSpans.MENTION -> parametrizedStyles?.getStyleRange()
880
+ else -> Pair(0, 0)
881
+ }
882
+
883
+ return result ?: Pair(0, 0)
884
+ }
885
+
886
+ private fun verifyStyle(name: String): Boolean {
887
+ val mergingConfig = EnrichedSpans.getMergingConfigForStyle(name, htmlStyle) ?: return true
888
+ val conflictingStyles = mergingConfig.conflictingStyles
889
+ val blockingStyles = mergingConfig.blockingStyles
890
+ val isEnabling = spanState?.getStart(name) == null
891
+ if (!isEnabling) return true
892
+
893
+ for (style in blockingStyles) {
894
+ if (spanState?.getStart(style) != null) {
895
+ spanState.setStart(name, null)
896
+ return false
897
+ }
898
+ }
899
+
900
+ for (style in conflictingStyles) {
901
+ val start = selection?.start ?: 0
902
+ val end = selection?.end ?: 0
903
+ val lengthBefore = text?.length ?: 0
904
+
905
+ runAsATransaction {
906
+ val targetRange = getTargetRange(name)
907
+ val removed = removeStyle(style, targetRange.first, targetRange.second)
908
+ if (removed) {
909
+ spanState?.setStart(style, null)
910
+ }
911
+ }
912
+
913
+ val lengthAfter = text?.length ?: 0
914
+ val charactersRemoved = lengthBefore - lengthAfter
915
+ val finalEnd =
916
+ if (charactersRemoved > 0) {
917
+ (end - charactersRemoved).coerceAtLeast(0)
918
+ } else {
919
+ end
920
+ }
921
+
922
+ val finalStart = start.coerceAtLeast(0).coerceAtMost(finalEnd)
923
+ selection?.onSelection(finalStart, finalEnd)
924
+ }
925
+
926
+ return true
927
+ }
928
+
929
+ fun verifyAndToggleStyle(name: String) {
930
+ val isValid = verifyStyle(name)
931
+ if (!isValid) return
932
+
933
+ val (rangeStart, rangeEnd) = getTargetRange(name)
934
+
935
+ runAsATransaction {
936
+ toggleStyle(name)
937
+ }
938
+
939
+ parametrizedStyles?.onStyleToggled(name, rangeStart, rangeEnd)
940
+ }
941
+
942
+ fun toggleCheckboxListItem(checked: Boolean) {
943
+ val isValid = verifyStyle(EnrichedSpans.CHECKBOX_LIST)
944
+ if (!isValid) return
945
+
946
+ listStyles?.toggleCheckboxListStyle(checked)
947
+ }
948
+
949
+ fun addLink(
950
+ start: Int,
951
+ end: Int,
952
+ text: String,
953
+ url: String,
954
+ ) {
955
+ val isValid = verifyStyle(EnrichedSpans.LINK)
956
+ if (!isValid) return
957
+
958
+ parametrizedStyles?.setLinkSpan(getActualIndex(start), getActualIndex(end), text, url)
959
+ }
960
+
961
+ fun removeLink(
962
+ start: Int,
963
+ end: Int,
964
+ ) {
965
+ parametrizedStyles?.removeLinkSpans(getActualIndex(start), getActualIndex(end))
966
+ }
967
+
968
+ fun addImage(
969
+ src: String,
970
+ width: Float,
971
+ height: Float,
972
+ ) {
973
+ val isValid = verifyStyle(EnrichedSpans.IMAGE)
974
+ if (!isValid) return
975
+
976
+ parametrizedStyles?.setImageSpan(src, width, height)
977
+ layoutManager.invalidateLayout()
978
+ }
979
+
980
+ fun startMention(indicator: String) {
981
+ val isValid = verifyStyle(EnrichedSpans.MENTION)
982
+ if (!isValid) return
983
+
984
+ parametrizedStyles?.startMention(indicator)
985
+ }
986
+
987
+ fun addMention(
988
+ indicator: String,
989
+ text: String,
990
+ attributes: Map<String, String>,
991
+ ) {
992
+ val isValid = verifyStyle(EnrichedSpans.MENTION)
993
+ if (!isValid) return
994
+
995
+ parametrizedStyles?.setMentionSpan(text, indicator, attributes)
996
+ }
997
+
998
+ fun setTextAlignment(alignment: String) {
999
+ runAsATransaction {
1000
+ alignmentStyles?.setAlignment(alignment)
1001
+ }
1002
+ selection?.validateStyles()
1003
+ }
1004
+
1005
+ fun requestHTML(requestId: Int) {
1006
+ val html =
1007
+ try {
1008
+ EnrichedParser.toHtmlWithDefault(text)
1009
+ } catch (_: Exception) {
1010
+ null
1011
+ }
1012
+
1013
+ val reactContext = context as ReactContext
1014
+ val surfaceId = UIManagerHelper.getSurfaceId(reactContext)
1015
+ val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id)
1016
+ dispatcher?.dispatchEvent(OnRequestHtmlResultEvent(surfaceId, id, requestId, html, experimentalSynchronousEvents))
1017
+ }
1018
+
1019
+ // Sometimes setting up style triggers many changes in sequence
1020
+ // Eg. removing conflicting styles -> changing text -> applying spans
1021
+ // In such scenario we want to prevent from handling side effects (eg. onTextChanged)
1022
+ fun runAsATransaction(block: () -> Unit) {
1023
+ try {
1024
+ isDuringTransaction = true
1025
+ block()
1026
+ } finally {
1027
+ isDuringTransaction = false
1028
+ }
1029
+ }
1030
+
1031
+ private fun forceScrollToSelection() {
1032
+ val textLayout = layout ?: return
1033
+ val cursorOffset = selectionStart
1034
+ if (cursorOffset <= 0) return
1035
+
1036
+ val selectedLineIndex = textLayout.getLineForOffset(cursorOffset)
1037
+ val selectedLineTop = textLayout.getLineTop(selectedLineIndex)
1038
+ val selectedLineBottom = textLayout.getLineBottom(selectedLineIndex)
1039
+ val visibleTextHeight = height - paddingTop - paddingBottom
1040
+
1041
+ if (visibleTextHeight <= 0) return
1042
+
1043
+ val visibleTop = scrollY
1044
+ val visibleBottom = scrollY + visibleTextHeight
1045
+ var targetScrollY = scrollY
1046
+
1047
+ if (selectedLineTop < visibleTop) {
1048
+ targetScrollY = selectedLineTop
1049
+ } else if (selectedLineBottom > visibleBottom) {
1050
+ targetScrollY = selectedLineBottom - visibleTextHeight
1051
+ }
1052
+
1053
+ val maxScrollY = (textLayout.height - visibleTextHeight).coerceAtLeast(0)
1054
+ targetScrollY = targetScrollY.coerceIn(0, maxScrollY)
1055
+ scrollTo(scrollX, targetScrollY)
1056
+ }
1057
+
1058
+ private fun isHeadingBold(
1059
+ style: HtmlStyle,
1060
+ span: EnrichedInputSpan,
1061
+ ): Boolean =
1062
+ when (span) {
1063
+ is EnrichedInputH1Span -> style.h1Bold
1064
+ is EnrichedInputH2Span -> style.h2Bold
1065
+ is EnrichedInputH3Span -> style.h3Bold
1066
+ is EnrichedInputH4Span -> style.h4Bold
1067
+ is EnrichedInputH5Span -> style.h5Bold
1068
+ is EnrichedInputH6Span -> style.h6Bold
1069
+ else -> false
1070
+ }
1071
+
1072
+ private fun shouldRemoveBoldFromHeading(
1073
+ span: EnrichedInputSpan,
1074
+ prevStyle: HtmlStyle,
1075
+ nextStyle: HtmlStyle,
1076
+ ): Boolean {
1077
+ val wasBold = isHeadingBold(prevStyle, span)
1078
+ val isNowBold = isHeadingBold(nextStyle, span)
1079
+
1080
+ return !wasBold && isNowBold
1081
+ }
1082
+
1083
+ private fun reApplyHtmlStyleForSpans(
1084
+ previousHtmlStyle: HtmlStyle,
1085
+ nextHtmlStyle: HtmlStyle,
1086
+ ) {
1087
+ val spannable = text as? Spannable ?: return
1088
+ if (spannable.isEmpty()) return
1089
+
1090
+ var shouldEmitStateChange = false
1091
+
1092
+ runAsATransaction {
1093
+ val spans = spannable.getSpans(0, spannable.length, EnrichedInputSpan::class.java)
1094
+ for (span in spans) {
1095
+ if (!span.dependsOnHtmlStyle) continue
1096
+
1097
+ val start = spannable.getSpanStart(span)
1098
+ val end = spannable.getSpanEnd(span)
1099
+ val flags = spannable.getSpanFlags(span)
1100
+
1101
+ if (start == -1 || end == -1) continue
1102
+
1103
+ // Check if we need to remove explicit bold spans
1104
+ if (shouldRemoveBoldFromHeading(span, previousHtmlStyle, nextHtmlStyle)) {
1105
+ val isRemoved = removeStyle(EnrichedSpans.BOLD, start, end)
1106
+ if (isRemoved) shouldEmitStateChange = true
1107
+ }
1108
+
1109
+ spannable.removeSpan(span)
1110
+ val newSpan = span.rebuildWithStyle(htmlStyle)
1111
+ spannable.setSpan(newSpan, start, end, flags)
1112
+ }
1113
+
1114
+ if (shouldEmitStateChange) {
1115
+ selection?.validateStyles()
1116
+ }
1117
+ }
1118
+ layoutManager.invalidateLayout()
1119
+ forceScrollToSelection()
1120
+ }
1121
+
1122
+ override fun onAttachedToWindow() {
1123
+ super.onAttachedToWindow()
1124
+
1125
+ // https://github.com/facebook/react-native/blob/36df97f500aa0aa8031098caf7526db358b6ddc1/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt#L946
1126
+ // setTextIsSelectable internally calls setText(), which fires afterTextChanged that should be marked as a transaction to avoid unwanted side effects
1127
+ runAsATransaction { super.setTextIsSelectable(true) }
1128
+
1129
+ if (autoFocus && !didAttachToWindow) {
1130
+ requestFocusProgrammatically()
1131
+ }
1132
+
1133
+ didAttachToWindow = true
1134
+ }
1135
+
1136
+ companion object {
1137
+ const val TAG = "EnrichedTextInputView"
1138
+ private const val CONTEXT_MENU_ITEM_ID = 10000
1139
+ const val DEFAULT_IME_ACTION_LABEL = "DONE"
1140
+ }
1141
+ }