react-native-enriched 0.2.1 → 0.4.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 (263) hide show
  1. package/README.md +21 -16
  2. package/android/build.gradle +77 -72
  3. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerDelegate.java +21 -0
  4. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerInterface.java +7 -0
  5. package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ComponentDescriptors.cpp +1 -1
  6. package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ComponentDescriptors.h +1 -1
  7. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/EventEmitters.cpp +276 -0
  8. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/EventEmitters.h +239 -0
  9. package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/Props.cpp +10 -0
  10. package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/Props.h +251 -0
  11. package/android/gradle.properties +5 -5
  12. package/android/lint.gradle +70 -0
  13. package/android/src/main/java/com/swmansion/enriched/{EnrichedTextInputViewPackage.kt → ReactNativeEnrichedPackage.kt} +4 -5
  14. package/android/src/main/java/com/swmansion/enriched/{utils → common}/AsyncDrawable.kt +50 -15
  15. package/android/src/main/java/com/swmansion/enriched/common/CheckboxDrawable.kt +81 -0
  16. package/android/src/main/java/com/swmansion/enriched/common/EnrichedConstants.kt +11 -0
  17. package/android/src/main/java/com/swmansion/enriched/common/EnrichedStyle.kt +57 -0
  18. package/android/src/main/java/com/swmansion/enriched/{spans/utils → common}/ForceRedrawSpan.kt +3 -2
  19. package/android/src/main/java/com/swmansion/enriched/common/MentionStyle.kt +7 -0
  20. package/android/src/main/java/com/swmansion/enriched/{utils → common}/ResourceManager.kt +1 -1
  21. package/android/src/main/java/com/swmansion/enriched/{utils → common/parser}/EnrichedParser.java +228 -160
  22. package/android/src/main/java/com/swmansion/enriched/common/parser/EnrichedSpanFactory.kt +79 -0
  23. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedBlockQuoteSpan.kt +53 -0
  24. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedBoldSpan.kt +12 -0
  25. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedCheckboxListSpan.kt +91 -0
  26. package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/EnrichedCodeBlockSpan.kt +12 -14
  27. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH1Span.kt +20 -0
  28. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH2Span.kt +20 -0
  29. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH3Span.kt +20 -0
  30. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH4Span.kt +21 -0
  31. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH5Span.kt +20 -0
  32. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH6Span.kt +20 -0
  33. package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/EnrichedImageSpan.kt +68 -51
  34. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedInlineCodeSpan.kt +24 -0
  35. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedItalicSpan.kt +12 -0
  36. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedLinkSpan.kt +26 -0
  37. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedMentionSpan.kt +35 -0
  38. package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/EnrichedOrderedListSpan.kt +21 -29
  39. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedStrikeThroughSpan.kt +11 -0
  40. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedUnderlineSpan.kt +11 -0
  41. package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/EnrichedUnorderedListSpan.kt +13 -17
  42. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedBlockSpan.kt +5 -0
  43. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedHeadingSpan.kt +3 -0
  44. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedInlineSpan.kt +3 -0
  45. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedParagraphSpan.kt +5 -0
  46. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedSpan.kt +3 -0
  47. package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/interfaces/EnrichedZeroWidthSpaceSpan.kt +2 -3
  48. package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputConnectionWrapper.kt +140 -0
  49. package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputSpannableFactory.kt +83 -0
  50. package/android/src/main/java/com/swmansion/enriched/{EnrichedTextInputView.kt → textinput/EnrichedTextInputView.kt} +322 -157
  51. package/android/src/main/java/com/swmansion/enriched/{EnrichedTextInputViewLayoutManager.kt → textinput/EnrichedTextInputViewLayoutManager.kt} +4 -2
  52. package/android/src/main/java/com/swmansion/enriched/{EnrichedTextInputViewManager.kt → textinput/EnrichedTextInputViewManager.kt} +182 -66
  53. package/android/src/main/java/com/swmansion/enriched/{MeasurementStore.kt → textinput/MeasurementStore.kt} +75 -25
  54. package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/MentionHandler.kt +22 -12
  55. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnChangeHtmlEvent.kt +27 -0
  56. package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnChangeSelectionEvent.kt +11 -10
  57. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnChangeStateEvent.kt +21 -0
  58. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnChangeTextEvent.kt +30 -0
  59. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnInputBlurEvent.kt +25 -0
  60. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnInputFocusEvent.kt +25 -0
  61. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnInputKeyPressEvent.kt +27 -0
  62. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnLinkDetectedEvent.kt +32 -0
  63. package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnMentionDetectedEvent.kt +11 -10
  64. package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnMentionEvent.kt +10 -9
  65. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnPasteImagesEvent.kt +47 -0
  66. package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnRequestHtmlResultEvent.kt +2 -3
  67. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputBlockQuoteSpan.kt +14 -0
  68. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputBoldSpan.kt +14 -0
  69. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputCheckboxListSpan.kt +15 -0
  70. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputCodeBlockSpan.kt +14 -0
  71. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH1Span.kt +14 -0
  72. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH2Span.kt +14 -0
  73. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH3Span.kt +14 -0
  74. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH4Span.kt +14 -0
  75. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH5Span.kt +14 -0
  76. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH6Span.kt +14 -0
  77. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputImageSpan.kt +36 -0
  78. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputInlineCodeSpan.kt +14 -0
  79. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputItalicSpan.kt +14 -0
  80. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputLinkSpan.kt +15 -0
  81. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputMentionSpan.kt +18 -0
  82. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputOrderedListSpan.kt +21 -0
  83. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputStrikeThroughSpan.kt +14 -0
  84. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputUnderlineSpan.kt +14 -0
  85. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputUnorderedListSpan.kt +14 -0
  86. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedSpans.kt +241 -0
  87. package/android/src/main/java/com/swmansion/enriched/textinput/spans/interfaces/EnrichedInputSpan.kt +10 -0
  88. package/android/src/main/java/com/swmansion/enriched/{styles → textinput/styles}/HtmlStyle.kt +129 -57
  89. package/android/src/main/java/com/swmansion/enriched/{styles → textinput/styles}/InlineStyles.kt +30 -13
  90. package/android/src/main/java/com/swmansion/enriched/textinput/styles/ListStyles.kt +263 -0
  91. package/android/src/main/java/com/swmansion/enriched/{styles → textinput/styles}/ParagraphStyles.kt +94 -34
  92. package/android/src/main/java/com/swmansion/enriched/{styles → textinput/styles}/ParametrizedStyles.kt +143 -67
  93. package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedEditableFactory.kt +17 -0
  94. package/android/src/main/java/com/swmansion/enriched/{utils → textinput/utils}/EnrichedSelection.kt +84 -54
  95. package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpanState.kt +304 -0
  96. package/android/src/main/java/com/swmansion/enriched/{utils/Utils.kt → textinput/utils/EnrichedSpannable.kt} +22 -31
  97. package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpannableStringBuilder.kt +16 -0
  98. package/android/src/main/java/com/swmansion/enriched/textinput/utils/RichContentReceiver.kt +127 -0
  99. package/android/src/main/java/com/swmansion/enriched/textinput/utils/Utils.kt +106 -0
  100. package/android/src/main/java/com/swmansion/enriched/{watchers → textinput/watchers}/EnrichedSpanWatcher.kt +56 -24
  101. package/android/src/main/java/com/swmansion/enriched/{watchers → textinput/watchers}/EnrichedTextWatcher.kt +37 -14
  102. package/android/src/main/new_arch/CMakeLists.txt +7 -1
  103. package/android/src/main/new_arch/ReactNativeEnrichedSpec.cpp +11 -0
  104. package/android/src/main/new_arch/ReactNativeEnrichedSpec.h +15 -0
  105. package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputMeasurementManager.h +1 -1
  106. package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputShadowNode.h +2 -2
  107. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/conversions.h +46 -0
  108. package/ios/EnrichedTextInputView.h +2 -1
  109. package/ios/EnrichedTextInputView.mm +603 -60
  110. package/ios/config/InputConfig.h +28 -0
  111. package/ios/config/InputConfig.mm +237 -8
  112. package/ios/extensions/ImageExtension.h +35 -0
  113. package/ios/extensions/ImageExtension.mm +156 -0
  114. package/ios/{utils → extensions}/LayoutManagerExtension.mm +115 -95
  115. package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ComponentDescriptors.cpp +1 -1
  116. package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ComponentDescriptors.h +1 -1
  117. package/ios/generated/ReactNativeEnrichedSpec/EventEmitters.cpp +276 -0
  118. package/ios/generated/ReactNativeEnrichedSpec/EventEmitters.h +239 -0
  119. package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/Props.cpp +10 -0
  120. package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/Props.h +251 -0
  121. package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/RCTComponentViewHelpers.h +95 -0
  122. package/ios/inputParser/InputParser.mm +218 -18
  123. package/ios/inputTextView/InputTextView.mm +118 -0
  124. package/ios/{attachments → interfaces}/ImageAttachment.h +1 -0
  125. package/ios/interfaces/ImageAttachment.mm +46 -0
  126. package/ios/interfaces/LinkRegexConfig.h +19 -0
  127. package/ios/interfaces/LinkRegexConfig.mm +37 -0
  128. package/ios/{utils → interfaces}/MentionStyleProps.mm +2 -2
  129. package/ios/{utils → interfaces}/StyleHeaders.h +22 -1
  130. package/ios/{utils → interfaces}/StyleTypeEnum.h +4 -0
  131. package/ios/internals/EnrichedTextInputViewState.cpp +6 -6
  132. package/ios/styles/BlockQuoteStyle.mm +5 -5
  133. package/ios/styles/BoldStyle.mm +21 -6
  134. package/ios/styles/CheckboxListStyle.mm +321 -0
  135. package/ios/styles/CodeBlockStyle.mm +5 -5
  136. package/ios/styles/H1Style.mm +3 -0
  137. package/ios/styles/H2Style.mm +3 -0
  138. package/ios/styles/H3Style.mm +3 -0
  139. package/ios/styles/H4Style.mm +20 -0
  140. package/ios/styles/H5Style.mm +20 -0
  141. package/ios/styles/H6Style.mm +20 -0
  142. package/ios/styles/HeadingStyleBase.mm +161 -72
  143. package/ios/styles/ImageStyle.mm +5 -5
  144. package/ios/styles/InlineCodeStyle.mm +30 -19
  145. package/ios/styles/ItalicStyle.mm +5 -5
  146. package/ios/styles/LinkStyle.mm +98 -40
  147. package/ios/styles/MentionStyle.mm +4 -4
  148. package/ios/styles/OrderedListStyle.mm +5 -5
  149. package/ios/styles/StrikethroughStyle.mm +5 -5
  150. package/ios/styles/UnderlineStyle.mm +5 -5
  151. package/ios/styles/UnorderedListStyle.mm +5 -5
  152. package/ios/utils/CheckboxHitTestUtils.h +10 -0
  153. package/ios/utils/CheckboxHitTestUtils.mm +123 -0
  154. package/ios/utils/ParagraphAttributesUtils.h +4 -0
  155. package/ios/utils/ParagraphAttributesUtils.mm +142 -45
  156. package/ios/utils/ParagraphsUtils.mm +4 -4
  157. package/ios/utils/TextBlockTapGestureRecognizer.h +17 -0
  158. package/ios/utils/TextBlockTapGestureRecognizer.mm +56 -0
  159. package/ios/utils/ZeroWidthSpaceUtils.mm +14 -3
  160. package/lib/module/EnrichedTextInput.js +57 -11
  161. package/lib/module/EnrichedTextInput.js.map +1 -1
  162. package/lib/module/{EnrichedTextInputNativeComponent.ts → spec/EnrichedTextInputNativeComponent.ts} +175 -18
  163. package/lib/module/types.js +4 -0
  164. package/lib/module/types.js.map +1 -0
  165. package/lib/module/{normalizeHtmlStyle.js → utils/normalizeHtmlStyle.js} +18 -0
  166. package/lib/module/utils/normalizeHtmlStyle.js.map +1 -0
  167. package/lib/module/utils/nullthrows.js +9 -0
  168. package/lib/module/utils/nullthrows.js.map +1 -0
  169. package/lib/module/utils/regexParser.js +46 -0
  170. package/lib/module/utils/regexParser.js.map +1 -0
  171. package/lib/typescript/src/EnrichedTextInput.d.ts +20 -51
  172. package/lib/typescript/src/EnrichedTextInput.d.ts.map +1 -1
  173. package/lib/typescript/src/index.d.ts +2 -1
  174. package/lib/typescript/src/index.d.ts.map +1 -1
  175. package/lib/typescript/src/{EnrichedTextInputNativeComponent.d.ts → spec/EnrichedTextInputNativeComponent.d.ts} +154 -18
  176. package/lib/typescript/src/spec/EnrichedTextInputNativeComponent.d.ts.map +1 -0
  177. package/lib/typescript/src/types.d.ts +58 -0
  178. package/lib/typescript/src/types.d.ts.map +1 -0
  179. package/lib/typescript/src/utils/normalizeHtmlStyle.d.ts +4 -0
  180. package/lib/typescript/src/utils/normalizeHtmlStyle.d.ts.map +1 -0
  181. package/lib/typescript/src/utils/nullthrows.d.ts +2 -0
  182. package/lib/typescript/src/utils/nullthrows.d.ts.map +1 -0
  183. package/lib/typescript/src/utils/regexParser.d.ts +3 -0
  184. package/lib/typescript/src/utils/regexParser.d.ts.map +1 -0
  185. package/package.json +13 -9
  186. package/src/EnrichedTextInput.tsx +88 -63
  187. package/src/index.tsx +5 -1
  188. package/src/{EnrichedTextInputNativeComponent.ts → spec/EnrichedTextInputNativeComponent.ts} +175 -18
  189. package/src/types.ts +59 -0
  190. package/src/{normalizeHtmlStyle.ts → utils/normalizeHtmlStyle.ts} +20 -5
  191. package/src/utils/nullthrows.ts +7 -0
  192. package/src/utils/regexParser.ts +56 -0
  193. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.cpp +0 -128
  194. package/android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec/EventEmitters.h +0 -102
  195. package/android/src/main/java/com/swmansion/enriched/events/OnChangeHtmlEvent.kt +0 -28
  196. package/android/src/main/java/com/swmansion/enriched/events/OnChangeStateEvent.kt +0 -24
  197. package/android/src/main/java/com/swmansion/enriched/events/OnChangeTextEvent.kt +0 -30
  198. package/android/src/main/java/com/swmansion/enriched/events/OnInputBlurEvent.kt +0 -27
  199. package/android/src/main/java/com/swmansion/enriched/events/OnInputFocusEvent.kt +0 -27
  200. package/android/src/main/java/com/swmansion/enriched/events/OnLinkDetectedEvent.kt +0 -30
  201. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBlockQuoteSpan.kt +0 -44
  202. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBoldSpan.kt +0 -16
  203. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH1Span.kt +0 -23
  204. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH2Span.kt +0 -23
  205. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH3Span.kt +0 -23
  206. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedInlineCodeSpan.kt +0 -27
  207. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedItalicSpan.kt +0 -15
  208. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedLinkSpan.kt +0 -30
  209. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedMentionSpan.kt +0 -42
  210. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedSpans.kt +0 -136
  211. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedStrikeThroughSpan.kt +0 -14
  212. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnderlineSpan.kt +0 -14
  213. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedBlockSpan.kt +0 -4
  214. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedHeadingSpan.kt +0 -4
  215. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedInlineSpan.kt +0 -4
  216. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedParagraphSpan.kt +0 -4
  217. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedSpan.kt +0 -8
  218. package/android/src/main/java/com/swmansion/enriched/styles/ListStyles.kt +0 -172
  219. package/android/src/main/java/com/swmansion/enriched/utils/EnrichedSpanState.kt +0 -204
  220. package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.cpp +0 -22
  221. package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.h +0 -26
  222. package/android/src/main/new_arch/react/renderer/components/RNEnrichedTextInputViewSpec/conversions.h +0 -26
  223. package/ios/attachments/ImageAttachment.mm +0 -34
  224. package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.cpp +0 -128
  225. package/ios/generated/RNEnrichedTextInputViewSpec/EventEmitters.h +0 -102
  226. package/lib/module/normalizeHtmlStyle.js.map +0 -1
  227. package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts.map +0 -1
  228. package/lib/typescript/src/normalizeHtmlStyle.d.ts +0 -4
  229. package/lib/typescript/src/normalizeHtmlStyle.d.ts.map +0 -1
  230. /package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ShadowNodes.cpp +0 -0
  231. /package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ShadowNodes.h +0 -0
  232. /package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/States.cpp +0 -0
  233. /package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/States.h +0 -0
  234. /package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputComponentDescriptor.h +0 -0
  235. /package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputMeasurementManager.cpp +0 -0
  236. /package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputShadowNode.cpp +0 -0
  237. /package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputState.cpp +0 -0
  238. /package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputState.h +0 -0
  239. /package/ios/{utils → extensions}/ColorExtension.h +0 -0
  240. /package/ios/{utils → extensions}/ColorExtension.mm +0 -0
  241. /package/ios/{utils → extensions}/FontExtension.h +0 -0
  242. /package/ios/{utils → extensions}/FontExtension.mm +0 -0
  243. /package/ios/{utils → extensions}/LayoutManagerExtension.h +0 -0
  244. /package/ios/{utils → extensions}/StringExtension.h +0 -0
  245. /package/ios/{utils → extensions}/StringExtension.mm +0 -0
  246. /package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ShadowNodes.cpp +0 -0
  247. /package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ShadowNodes.h +0 -0
  248. /package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/States.cpp +0 -0
  249. /package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/States.h +0 -0
  250. /package/ios/{utils → interfaces}/BaseStyleProtocol.h +0 -0
  251. /package/ios/{utils → interfaces}/ImageData.h +0 -0
  252. /package/ios/{utils → interfaces}/ImageData.mm +0 -0
  253. /package/ios/{utils → interfaces}/LinkData.h +0 -0
  254. /package/ios/{utils → interfaces}/LinkData.mm +0 -0
  255. /package/ios/{attachments → interfaces}/MediaAttachment.h +0 -0
  256. /package/ios/{attachments → interfaces}/MediaAttachment.mm +0 -0
  257. /package/ios/{utils → interfaces}/MentionParams.h +0 -0
  258. /package/ios/{utils → interfaces}/MentionParams.mm +0 -0
  259. /package/ios/{utils → interfaces}/MentionStyleProps.h +0 -0
  260. /package/ios/{utils → interfaces}/StylePair.h +0 -0
  261. /package/ios/{utils → interfaces}/StylePair.mm +0 -0
  262. /package/ios/{utils → interfaces}/TextDecorationLineEnum.h +0 -0
  263. /package/ios/{utils → interfaces}/TextDecorationLineEnum.mm +0 -0
@@ -0,0 +1,304 @@
1
+ package com.swmansion.enriched.textinput.utils
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.ReactContext
5
+ import com.facebook.react.bridge.WritableMap
6
+ import com.facebook.react.uimanager.UIManagerHelper
7
+ import com.facebook.react.uimanager.events.EventDispatcher
8
+ import com.swmansion.enriched.textinput.EnrichedTextInputView
9
+ import com.swmansion.enriched.textinput.events.OnChangeStateEvent
10
+ import com.swmansion.enriched.textinput.spans.EnrichedSpans
11
+
12
+ class EnrichedSpanState(
13
+ private val view: EnrichedTextInputView,
14
+ ) {
15
+ private var previousPayload: WritableMap? = null
16
+
17
+ var boldStart: Int? = null
18
+ private set
19
+ var italicStart: Int? = null
20
+ private set
21
+ var underlineStart: Int? = null
22
+ private set
23
+ var strikethroughStart: Int? = null
24
+ private set
25
+ var inlineCodeStart: Int? = null
26
+ private set
27
+ var h1Start: Int? = null
28
+ private set
29
+ var h2Start: Int? = null
30
+ private set
31
+ var h3Start: Int? = null
32
+ private set
33
+ var h4Start: Int? = null
34
+ private set
35
+ var h5Start: Int? = null
36
+ private set
37
+ var h6Start: Int? = null
38
+ private set
39
+ var codeBlockStart: Int? = null
40
+ private set
41
+ var blockQuoteStart: Int? = null
42
+ private set
43
+ var orderedListStart: Int? = null
44
+ private set
45
+ var unorderedListStart: Int? = null
46
+ private set
47
+ var checkboxListStart: Int? = null
48
+ private set
49
+ var linkStart: Int? = null
50
+ private set
51
+ var imageStart: Int? = null
52
+ private set
53
+ var mentionStart: Int? = null
54
+ private set
55
+
56
+ fun setBoldStart(start: Int?) {
57
+ this.boldStart = start
58
+ emitStateChangeEvent()
59
+ }
60
+
61
+ fun setItalicStart(start: Int?) {
62
+ this.italicStart = start
63
+ emitStateChangeEvent()
64
+ }
65
+
66
+ fun setUnderlineStart(start: Int?) {
67
+ this.underlineStart = start
68
+ emitStateChangeEvent()
69
+ }
70
+
71
+ fun setStrikethroughStart(start: Int?) {
72
+ this.strikethroughStart = start
73
+ emitStateChangeEvent()
74
+ }
75
+
76
+ fun setInlineCodeStart(start: Int?) {
77
+ this.inlineCodeStart = start
78
+ emitStateChangeEvent()
79
+ }
80
+
81
+ fun setH1Start(start: Int?) {
82
+ this.h1Start = start
83
+ emitStateChangeEvent()
84
+ }
85
+
86
+ fun setH2Start(start: Int?) {
87
+ this.h2Start = start
88
+ emitStateChangeEvent()
89
+ }
90
+
91
+ fun setH3Start(start: Int?) {
92
+ this.h3Start = start
93
+ emitStateChangeEvent()
94
+ }
95
+
96
+ fun setH4Start(start: Int?) {
97
+ this.h4Start = start
98
+ emitStateChangeEvent()
99
+ }
100
+
101
+ fun setH5Start(start: Int?) {
102
+ this.h5Start = start
103
+ emitStateChangeEvent()
104
+ }
105
+
106
+ fun setH6Start(start: Int?) {
107
+ this.h6Start = start
108
+ emitStateChangeEvent()
109
+ }
110
+
111
+ fun setCodeBlockStart(start: Int?) {
112
+ this.codeBlockStart = start
113
+ emitStateChangeEvent()
114
+ }
115
+
116
+ fun setBlockQuoteStart(start: Int?) {
117
+ this.blockQuoteStart = start
118
+ emitStateChangeEvent()
119
+ }
120
+
121
+ fun setOrderedListStart(start: Int?) {
122
+ this.orderedListStart = start
123
+ emitStateChangeEvent()
124
+ }
125
+
126
+ fun setUnorderedListStart(start: Int?) {
127
+ this.unorderedListStart = start
128
+ emitStateChangeEvent()
129
+ }
130
+
131
+ fun setCheckboxListStart(start: Int?) {
132
+ this.checkboxListStart = start
133
+ emitStateChangeEvent()
134
+ }
135
+
136
+ fun setLinkStart(start: Int?) {
137
+ this.linkStart = start
138
+ emitStateChangeEvent()
139
+ }
140
+
141
+ fun setImageStart(start: Int?) {
142
+ this.imageStart = start
143
+ emitStateChangeEvent()
144
+ }
145
+
146
+ fun setMentionStart(start: Int?) {
147
+ this.mentionStart = start
148
+ emitStateChangeEvent()
149
+ }
150
+
151
+ fun getStart(name: String): Int? {
152
+ val start =
153
+ when (name) {
154
+ EnrichedSpans.BOLD -> boldStart
155
+ EnrichedSpans.ITALIC -> italicStart
156
+ EnrichedSpans.UNDERLINE -> underlineStart
157
+ EnrichedSpans.STRIKETHROUGH -> strikethroughStart
158
+ EnrichedSpans.INLINE_CODE -> inlineCodeStart
159
+ EnrichedSpans.H1 -> h1Start
160
+ EnrichedSpans.H2 -> h2Start
161
+ EnrichedSpans.H3 -> h3Start
162
+ EnrichedSpans.H4 -> h4Start
163
+ EnrichedSpans.H5 -> h5Start
164
+ EnrichedSpans.H6 -> h6Start
165
+ EnrichedSpans.CODE_BLOCK -> codeBlockStart
166
+ EnrichedSpans.BLOCK_QUOTE -> blockQuoteStart
167
+ EnrichedSpans.ORDERED_LIST -> orderedListStart
168
+ EnrichedSpans.UNORDERED_LIST -> unorderedListStart
169
+ EnrichedSpans.CHECKBOX_LIST -> checkboxListStart
170
+ EnrichedSpans.LINK -> linkStart
171
+ EnrichedSpans.IMAGE -> imageStart
172
+ EnrichedSpans.MENTION -> mentionStart
173
+ else -> null
174
+ }
175
+
176
+ return start
177
+ }
178
+
179
+ fun setStart(
180
+ name: String,
181
+ start: Int?,
182
+ ) {
183
+ when (name) {
184
+ EnrichedSpans.BOLD -> setBoldStart(start)
185
+ EnrichedSpans.ITALIC -> setItalicStart(start)
186
+ EnrichedSpans.UNDERLINE -> setUnderlineStart(start)
187
+ EnrichedSpans.STRIKETHROUGH -> setStrikethroughStart(start)
188
+ EnrichedSpans.INLINE_CODE -> setInlineCodeStart(start)
189
+ EnrichedSpans.H1 -> setH1Start(start)
190
+ EnrichedSpans.H2 -> setH2Start(start)
191
+ EnrichedSpans.H3 -> setH3Start(start)
192
+ EnrichedSpans.H4 -> setH4Start(start)
193
+ EnrichedSpans.H5 -> setH5Start(start)
194
+ EnrichedSpans.H6 -> setH6Start(start)
195
+ EnrichedSpans.CODE_BLOCK -> setCodeBlockStart(start)
196
+ EnrichedSpans.BLOCK_QUOTE -> setBlockQuoteStart(start)
197
+ EnrichedSpans.ORDERED_LIST -> setOrderedListStart(start)
198
+ EnrichedSpans.UNORDERED_LIST -> setUnorderedListStart(start)
199
+ EnrichedSpans.CHECKBOX_LIST -> setCheckboxListStart(start)
200
+ EnrichedSpans.LINK -> setLinkStart(start)
201
+ EnrichedSpans.IMAGE -> setImageStart(start)
202
+ EnrichedSpans.MENTION -> setMentionStart(start)
203
+ }
204
+ }
205
+
206
+ private fun emitStateChangeEvent() {
207
+ val context = view.context as ReactContext
208
+ val surfaceId = UIManagerHelper.getSurfaceId(context)
209
+ val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, view.id)
210
+
211
+ dispatchPayload(dispatcher, surfaceId)
212
+ }
213
+
214
+ private fun dispatchPayload(
215
+ dispatcher: EventDispatcher?,
216
+ surfaceId: Int,
217
+ ) {
218
+ val activeStyles =
219
+ listOfNotNull(
220
+ if (boldStart != null) EnrichedSpans.BOLD else null,
221
+ if (italicStart != null) EnrichedSpans.ITALIC else null,
222
+ if (underlineStart != null) EnrichedSpans.UNDERLINE else null,
223
+ if (strikethroughStart != null) EnrichedSpans.STRIKETHROUGH else null,
224
+ if (inlineCodeStart != null) EnrichedSpans.INLINE_CODE else null,
225
+ if (h1Start != null) EnrichedSpans.H1 else null,
226
+ if (h2Start != null) EnrichedSpans.H2 else null,
227
+ if (h3Start != null) EnrichedSpans.H3 else null,
228
+ if (h4Start != null) EnrichedSpans.H4 else null,
229
+ if (h5Start != null) EnrichedSpans.H5 else null,
230
+ if (h6Start != null) EnrichedSpans.H6 else null,
231
+ if (codeBlockStart != null) EnrichedSpans.CODE_BLOCK else null,
232
+ if (blockQuoteStart != null) EnrichedSpans.BLOCK_QUOTE else null,
233
+ if (orderedListStart != null) EnrichedSpans.ORDERED_LIST else null,
234
+ if (unorderedListStart != null) EnrichedSpans.UNORDERED_LIST else null,
235
+ if (checkboxListStart != null) EnrichedSpans.CHECKBOX_LIST else null,
236
+ if (linkStart != null) EnrichedSpans.LINK else null,
237
+ if (imageStart != null) EnrichedSpans.IMAGE else null,
238
+ if (mentionStart != null) EnrichedSpans.MENTION else null,
239
+ )
240
+ val payload = Arguments.createMap()
241
+ payload.putMap("bold", getStyleState(activeStyles, EnrichedSpans.BOLD))
242
+ payload.putMap("italic", getStyleState(activeStyles, EnrichedSpans.ITALIC))
243
+ payload.putMap("underline", getStyleState(activeStyles, EnrichedSpans.UNDERLINE))
244
+ payload.putMap("strikeThrough", getStyleState(activeStyles, EnrichedSpans.STRIKETHROUGH))
245
+ payload.putMap("inlineCode", getStyleState(activeStyles, EnrichedSpans.INLINE_CODE))
246
+ payload.putMap("h1", getStyleState(activeStyles, EnrichedSpans.H1))
247
+ payload.putMap("h2", getStyleState(activeStyles, EnrichedSpans.H2))
248
+ payload.putMap("h3", getStyleState(activeStyles, EnrichedSpans.H3))
249
+ payload.putMap("h4", getStyleState(activeStyles, EnrichedSpans.H4))
250
+ payload.putMap("h5", getStyleState(activeStyles, EnrichedSpans.H5))
251
+ payload.putMap("h6", getStyleState(activeStyles, EnrichedSpans.H6))
252
+ payload.putMap("codeBlock", getStyleState(activeStyles, EnrichedSpans.CODE_BLOCK))
253
+ payload.putMap("blockQuote", getStyleState(activeStyles, EnrichedSpans.BLOCK_QUOTE))
254
+ payload.putMap("orderedList", getStyleState(activeStyles, EnrichedSpans.ORDERED_LIST))
255
+ payload.putMap("unorderedList", getStyleState(activeStyles, EnrichedSpans.UNORDERED_LIST))
256
+ payload.putMap("link", getStyleState(activeStyles, EnrichedSpans.LINK))
257
+ payload.putMap("image", getStyleState(activeStyles, EnrichedSpans.IMAGE))
258
+ payload.putMap("mention", getStyleState(activeStyles, EnrichedSpans.MENTION))
259
+ payload.putMap("checkboxList", getStyleState(activeStyles, EnrichedSpans.CHECKBOX_LIST))
260
+
261
+ // Do not emit event if payload is the same
262
+ if (previousPayload == payload) {
263
+ return
264
+ }
265
+
266
+ previousPayload =
267
+ Arguments.createMap().apply {
268
+ merge(payload)
269
+ }
270
+ dispatcher?.dispatchEvent(
271
+ OnChangeStateEvent(
272
+ surfaceId,
273
+ view.id,
274
+ payload,
275
+ view.experimentalSynchronousEvents,
276
+ ),
277
+ )
278
+ }
279
+
280
+ private fun getStyleState(
281
+ activeStyles: List<String>,
282
+ type: String,
283
+ ): WritableMap {
284
+ val mergingConfig = EnrichedSpans.getMergingConfigForStyle(type, view.htmlStyle)
285
+ val blockingList = mergingConfig?.blockingStyles
286
+ val conflictingList = mergingConfig?.conflictingStyles
287
+
288
+ val state = Arguments.createMap()
289
+
290
+ state.putBoolean("isActive", activeStyles.contains(type))
291
+
292
+ val isBlocking = blockingList?.any { activeStyles.contains(it) } ?: false
293
+ state.putBoolean("isBlocking", isBlocking)
294
+
295
+ val isConflicting = conflictingList?.any { activeStyles.contains(it) } ?: false
296
+ state.putBoolean("isConflicting", isConflicting)
297
+
298
+ return state
299
+ }
300
+
301
+ companion object {
302
+ const val NAME = "ReactNativeEnrichedView"
303
+ }
304
+ }
@@ -1,38 +1,25 @@
1
- package com.swmansion.enriched.utils
1
+ package com.swmansion.enriched.textinput.utils
2
2
 
3
3
  import android.text.Spannable
4
4
  import android.text.SpannableString
5
5
  import android.text.SpannableStringBuilder
6
- import android.util.Log
7
- import com.swmansion.enriched.spans.interfaces.EnrichedBlockSpan
8
- import com.swmansion.enriched.spans.interfaces.EnrichedParagraphSpan
9
- import org.json.JSONObject
10
-
11
- fun jsonStringToStringMap(json: String): Map<String, String> {
12
- val result = mutableMapOf<String, String>()
13
- try {
14
- val jsonObject = JSONObject(json)
15
- for (key in jsonObject.keys()) {
16
- val value = jsonObject.opt(key)
17
- if (value is String) {
18
- result[key] = value
19
- }
20
- }
21
- } catch (e: Exception) {
22
- Log.w("ReactNativeEnrichedView", "Failed to parse JSON string to Map: $json", e)
23
- }
24
-
25
- return result
26
- }
6
+ import com.swmansion.enriched.common.spans.interfaces.EnrichedBlockSpan
7
+ import com.swmansion.enriched.common.spans.interfaces.EnrichedParagraphSpan
27
8
 
28
- fun Spannable.getSafeSpanBoundaries(start: Int, end: Int): Pair<Int, Int> {
9
+ fun Spannable.getSafeSpanBoundaries(
10
+ start: Int,
11
+ end: Int,
12
+ ): Pair<Int, Int> {
29
13
  val safeStart = start.coerceAtMost(end).coerceAtLeast(0)
30
14
  val safeEnd = end.coerceAtLeast(start).coerceAtMost(this.length)
31
15
 
32
16
  return Pair(safeStart, safeEnd)
33
17
  }
34
18
 
35
- fun Spannable.getParagraphBounds(start: Int, end: Int): Pair<Int, Int> {
19
+ fun Spannable.getParagraphBounds(
20
+ start: Int,
21
+ end: Int,
22
+ ): Pair<Int, Int> {
36
23
  var startPosition = start.coerceAtLeast(0).coerceAtMost(this.length)
37
24
  var endPosition = end.coerceAtLeast(0).coerceAtMost(this.length)
38
25
 
@@ -54,15 +41,19 @@ fun Spannable.getParagraphBounds(start: Int, end: Int): Pair<Int, Int> {
54
41
  return Pair(startPosition, endPosition)
55
42
  }
56
43
 
57
- fun Spannable.getParagraphBounds(index: Int): Pair<Int, Int> {
58
- return this.getParagraphBounds(index, index)
59
- }
44
+ fun Spannable.getParagraphBounds(index: Int): Pair<Int, Int> = this.getParagraphBounds(index, index)
60
45
 
61
- fun Spannable.mergeSpannables(start: Int, end: Int, string: String): Spannable {
62
- return this.mergeSpannables(start, end, SpannableString(string))
63
- }
46
+ fun Spannable.mergeSpannables(
47
+ start: Int,
48
+ end: Int,
49
+ string: String,
50
+ ): Spannable = this.mergeSpannables(start, end, SpannableString(string))
64
51
 
65
- fun Spannable.mergeSpannables(start: Int, end: Int, spannable: Spannable): Spannable {
52
+ fun Spannable.mergeSpannables(
53
+ start: Int,
54
+ end: Int,
55
+ spannable: Spannable,
56
+ ): Spannable {
66
57
  var finalStart = start
67
58
  var finalEnd = end
68
59
 
@@ -0,0 +1,16 @@
1
+ package com.swmansion.enriched.textinput.utils
2
+
3
+ import android.text.SpannableStringBuilder
4
+ import com.swmansion.enriched.common.EnrichedConstants
5
+
6
+ // Removes zero-width spaces from the given range in the SpannableStringBuilder without affecting spans
7
+ fun SpannableStringBuilder.removeZWS(
8
+ start: Int,
9
+ end: Int,
10
+ ) {
11
+ for (i in (end - 1) downTo start) {
12
+ if (this[i] == EnrichedConstants.ZWS) {
13
+ delete(i, i + 1)
14
+ }
15
+ }
16
+ }
@@ -0,0 +1,127 @@
1
+ package com.swmansion.enriched.textinput.utils
2
+
3
+ import android.content.ClipData
4
+ import android.content.Context
5
+ import android.graphics.BitmapFactory
6
+ import android.net.Uri
7
+ import android.os.Handler
8
+ import android.os.Looper
9
+ import android.util.Log
10
+ import android.view.View
11
+ import android.webkit.MimeTypeMap
12
+ import androidx.core.view.ContentInfoCompat
13
+ import androidx.core.view.OnReceiveContentListener
14
+ import com.facebook.react.bridge.ReactContext
15
+ import com.facebook.react.uimanager.UIManagerHelper
16
+ import com.swmansion.enriched.textinput.EnrichedTextInputView
17
+ import com.swmansion.enriched.textinput.events.OnPasteImagesEvent
18
+ import java.io.File
19
+ import java.io.FileOutputStream
20
+ import kotlin.io.copyTo
21
+
22
+ class RichContentReceiver(
23
+ private val view: EnrichedTextInputView,
24
+ private val context: ReactContext,
25
+ ) : OnReceiveContentListener {
26
+ override fun onReceiveContent(
27
+ view: View,
28
+ contentInfo: ContentInfoCompat,
29
+ ): ContentInfoCompat? {
30
+ val split = contentInfo.partition { item: ClipData.Item -> item.uri != null }
31
+ val uriContent = split.first
32
+ val remaining = split.second
33
+
34
+ if (uriContent != null) {
35
+ processClipDataInBackground(uriContent.clip)
36
+ }
37
+
38
+ if (remaining != null && remaining.clip.itemCount > 0) {
39
+ val item = remaining.clip.getItemAt(0)
40
+
41
+ this.view.handleTextPaste(item)
42
+ }
43
+
44
+ return null
45
+ }
46
+
47
+ private fun processClipDataInBackground(clip: ClipData) {
48
+ Thread {
49
+ val results = mutableListOf<OnPasteImagesEvent.Companion.PastedImage>()
50
+
51
+ for (i in 0 until clip.itemCount) {
52
+ val item = clip.getItemAt(i)
53
+ val uri = item.uri ?: continue
54
+ val mimeType = getMimeTypeFromUri(uri) ?: continue
55
+
56
+ if (mimeType.startsWith("image/")) {
57
+ val result = saveUriToTempFile(context, uri, mimeType)
58
+ if (result != null) {
59
+ results.add(result)
60
+ }
61
+ }
62
+ }
63
+
64
+ if (results.isNotEmpty()) {
65
+ Handler(Looper.getMainLooper()).post {
66
+ emitOnPasteImageEvent(results)
67
+ }
68
+ }
69
+ }.start()
70
+ }
71
+
72
+ private fun emitOnPasteImageEvent(images: List<OnPasteImagesEvent.Companion.PastedImage>) {
73
+ val surfaceId = UIManagerHelper.getSurfaceId(context)
74
+ val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, view.id)
75
+ dispatcher?.dispatchEvent(OnPasteImagesEvent(surfaceId, view.id, images, false))
76
+ }
77
+
78
+ private fun saveUriToTempFile(
79
+ context: Context,
80
+ uri: Uri,
81
+ mimeType: String,
82
+ ): OnPasteImagesEvent.Companion.PastedImage? {
83
+ return try {
84
+ val resolver = context.contentResolver
85
+ val ext = MimeTypeMap.getFileExtensionFromUrl(uri.toString())
86
+ val file = File.createTempFile("temp", ".$ext", context.cacheDir)
87
+
88
+ // Copy Stream
89
+ resolver.openInputStream(uri).use { input ->
90
+ if (input == null) return null
91
+ FileOutputStream(file).use { output ->
92
+ input.copyTo(output)
93
+ }
94
+ }
95
+
96
+ // Decode Dimensions
97
+ val options = BitmapFactory.Options().apply { inJustDecodeBounds = true }
98
+ BitmapFactory.decodeFile(file.absolutePath, options)
99
+
100
+ OnPasteImagesEvent.Companion.PastedImage(
101
+ uri = "file://${file.absolutePath}",
102
+ type = mimeType,
103
+ width = options.outWidth.toDouble(),
104
+ height = options.outHeight.toDouble(),
105
+ )
106
+ } catch (e: Exception) {
107
+ Log.e("RichContentReceiver", "Failed to save URI: $uri", e)
108
+ null
109
+ }
110
+ }
111
+
112
+ private fun getMimeTypeFromUri(uri: Uri): String? {
113
+ var mimeType = context.contentResolver.getType(uri)
114
+
115
+ if (mimeType == null) {
116
+ val extension = MimeTypeMap.getFileExtensionFromUrl(uri.toString())
117
+
118
+ mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
119
+ }
120
+
121
+ return mimeType
122
+ }
123
+
124
+ companion object {
125
+ val MIME_TYPES = arrayOf("image/*", "text/*")
126
+ }
127
+ }
@@ -0,0 +1,106 @@
1
+ package com.swmansion.enriched.textinput.utils
2
+
3
+ import android.annotation.SuppressLint
4
+ import android.text.Selection
5
+ import android.text.Spannable
6
+ import android.text.Spanned
7
+ import android.util.Log
8
+ import android.view.MotionEvent
9
+ import android.widget.TextView
10
+ import com.swmansion.enriched.textinput.spans.EnrichedInputCheckboxListSpan
11
+ import org.json.JSONObject
12
+
13
+ fun jsonStringToStringMap(json: String): Map<String, String> {
14
+ val result = mutableMapOf<String, String>()
15
+ try {
16
+ val jsonObject = JSONObject(json)
17
+ for (key in jsonObject.keys()) {
18
+ val value = jsonObject.opt(key)
19
+ if (value is String) {
20
+ result[key] = value
21
+ }
22
+ }
23
+ } catch (e: Exception) {
24
+ Log.w("ReactNativeEnrichedView", "Failed to parse JSON string to Map: $json", e)
25
+ }
26
+
27
+ return result
28
+ }
29
+
30
+ // Sets a touch listener on TextView which is responsible for detecting touches on checkbox icons
31
+ // We don't use ClickableSpan because it works fine only when LinkMovementMethod is set on TextView
32
+ // Which breaks text selection and other features
33
+ @SuppressLint("ClickableViewAccessibility")
34
+ fun TextView.setCheckboxClickListener() {
35
+ var isDownOnCheckbox = false
36
+
37
+ setOnTouchListener { v, event ->
38
+ val tv = v as TextView
39
+ val layout = tv.layout ?: return@setOnTouchListener false
40
+ val spannable = tv.text as? Spanned ?: return@setOnTouchListener false
41
+
42
+ // Get touch coordinates relative to the text content
43
+ val x = event.x.toInt() - tv.totalPaddingLeft + tv.scrollX
44
+ val y = event.y.toInt() - tv.totalPaddingTop + tv.scrollY
45
+
46
+ // Identify the line and whether it's the first line of the span
47
+ val line = layout.getLineForVertical(y)
48
+ val lineStart = layout.getLineStart(line)
49
+
50
+ // Find spans for specific line
51
+ val spans = spannable.getSpans(lineStart, lineStart, EnrichedInputCheckboxListSpan::class.java)
52
+ if (spans.isEmpty()) return@setOnTouchListener false
53
+
54
+ // There should be only one span per line as we don't support nested lists
55
+ val span = spans[0]
56
+ val isFirstLine = spannable.getSpanStart(span) == lineStart
57
+ val marginWidth = span.getLeadingMargin(true)
58
+
59
+ // Check if touch is on checkbox icon area (which is in the leading margin on the first line)
60
+ val isInHotZone = isFirstLine && x in 0..marginWidth
61
+
62
+ when (event.action) {
63
+ MotionEvent.ACTION_DOWN -> {
64
+ if (isInHotZone) {
65
+ isDownOnCheckbox = true
66
+ return@setOnTouchListener true
67
+ }
68
+ }
69
+
70
+ MotionEvent.ACTION_UP -> {
71
+ if (isDownOnCheckbox && isInHotZone) {
72
+ val spannable = tv.text as? Spannable
73
+ if (spannable != null) {
74
+ val start = spannable.getSpanStart(span)
75
+ val end = spannable.getSpanEnd(span)
76
+ val flags = spannable.getSpanFlags(span)
77
+ span.isChecked = !span.isChecked
78
+
79
+ // Reapply span so changes are visible without need to redraw entire TextView
80
+ spannable.removeSpan(span)
81
+ spannable.setSpan(span, start, end, flags)
82
+
83
+ // For focused input, ensure cursor is active for affected paragraph
84
+ if (tv.isFocused) {
85
+ val currentCursor = Selection.getSelectionEnd(spannable)
86
+ if (currentCursor < start || currentCursor > end) {
87
+ Selection.setSelection(spannable, end)
88
+ }
89
+ }
90
+ }
91
+
92
+ isDownOnCheckbox = false
93
+ return@setOnTouchListener true
94
+ }
95
+ isDownOnCheckbox = false
96
+ }
97
+
98
+ MotionEvent.ACTION_CANCEL -> {
99
+ isDownOnCheckbox = false
100
+ }
101
+ }
102
+
103
+ // Let TextView handle other touches (e.g., for selection)
104
+ false
105
+ }
106
+ }