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
@@ -1,10 +1,12 @@
1
1
  #import "EnrichedTextInputView.h"
2
2
  #import "CoreText/CoreText.h"
3
+ #import "ImageAttachment.h"
3
4
  #import "LayoutManagerExtension.h"
4
5
  #import "ParagraphAttributesUtils.h"
5
6
  #import "RCTFabricComponentsPlugins.h"
6
7
  #import "StringExtension.h"
7
8
  #import "StyleHeaders.h"
9
+ #import "TextBlockTapGestureRecognizer.h"
8
10
  #import "UIView+React.h"
9
11
  #import "WordsUtils.h"
10
12
  #import "ZeroWidthSpaceUtils.h"
@@ -16,10 +18,18 @@
16
18
  #import <folly/dynamic.h>
17
19
  #import <react/utils/ManagedObjectWrapper.h>
18
20
 
21
+ #define GET_STYLE_STATE(TYPE_ENUM) \
22
+ { \
23
+ .isActive = [self isStyleActive:TYPE_ENUM], \
24
+ .isBlocking = [self isStyle:TYPE_ENUM activeInMap:blockingStyles], \
25
+ .isConflicting = [self isStyle:TYPE_ENUM activeInMap:conflictingStyles] \
26
+ }
27
+
19
28
  using namespace facebook::react;
20
29
 
21
30
  @interface EnrichedTextInputView () <RCTEnrichedTextInputViewViewProtocol,
22
- UITextViewDelegate, NSObject>
31
+ UITextViewDelegate,
32
+ UIGestureRecognizerDelegate, NSObject>
23
33
 
24
34
  @end
25
35
 
@@ -27,6 +37,7 @@ using namespace facebook::react;
27
37
  EnrichedTextInputViewShadowNode::ConcreteState::Shared _state;
28
38
  int _componentViewHeightUpdateCounter;
29
39
  NSMutableSet<NSNumber *> *_activeStyles;
40
+ NSMutableSet<NSNumber *> *_blockedStyles;
30
41
  LinkData *_recentlyActiveLinkData;
31
42
  NSRange _recentlyActiveLinkRange;
32
43
  NSString *_recentInputString;
@@ -37,6 +48,8 @@ using namespace facebook::react;
37
48
  UILabel *_placeholderLabel;
38
49
  UIColor *_placeholderColor;
39
50
  BOOL _emitFocusBlur;
51
+ BOOL _emitTextChange;
52
+ NSMutableDictionary<NSValue *, UIImageView *> *_attachmentViews;
40
53
  }
41
54
 
42
55
  // MARK: - Component utils
@@ -72,6 +85,7 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
72
85
  - (void)setDefaults {
73
86
  _componentViewHeightUpdateCounter = 0;
74
87
  _activeStyles = [[NSMutableSet alloc] init];
88
+ _blockedStyles = [[NSMutableSet alloc] init];
75
89
  _recentlyActiveLinkRange = NSMakeRange(0, 0);
76
90
  _recentlyActiveMentionRange = NSMakeRange(0, 0);
77
91
  recentlyChangedRange = NSMakeRange(0, 0);
@@ -80,6 +94,7 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
80
94
  _emitHtml = NO;
81
95
  blockEmitting = NO;
82
96
  _emitFocusBlur = YES;
97
+ _emitTextChange = NO;
83
98
 
84
99
  defaultTypingAttributes =
85
100
  [[NSMutableDictionary<NSAttributedStringKey, id> alloc] init];
@@ -98,10 +113,15 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
98
113
  @([H1Style getStyleType]) : [[H1Style alloc] initWithInput:self],
99
114
  @([H2Style getStyleType]) : [[H2Style alloc] initWithInput:self],
100
115
  @([H3Style getStyleType]) : [[H3Style alloc] initWithInput:self],
116
+ @([H4Style getStyleType]) : [[H4Style alloc] initWithInput:self],
117
+ @([H5Style getStyleType]) : [[H5Style alloc] initWithInput:self],
118
+ @([H6Style getStyleType]) : [[H6Style alloc] initWithInput:self],
101
119
  @([UnorderedListStyle getStyleType]) :
102
120
  [[UnorderedListStyle alloc] initWithInput:self],
103
121
  @([OrderedListStyle getStyleType]) :
104
122
  [[OrderedListStyle alloc] initWithInput:self],
123
+ @([CheckboxListStyle getStyleType]) :
124
+ [[CheckboxListStyle alloc] initWithInput:self],
105
125
  @([BlockQuoteStyle getStyleType]) :
106
126
  [[BlockQuoteStyle alloc] initWithInput:self],
107
127
  @([CodeBlockStyle getStyleType]) :
@@ -124,48 +144,90 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
124
144
  @[ @([InlineCodeStyle getStyleType]), @([LinkStyle getStyleType]) ],
125
145
  @([H1Style getStyleType]) : @[
126
146
  @([H2Style getStyleType]), @([H3Style getStyleType]),
127
- @([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]),
128
- @([BlockQuoteStyle getStyleType]), @([CodeBlockStyle getStyleType])
147
+ @([H4Style getStyleType]), @([H5Style getStyleType]),
148
+ @([H6Style getStyleType]), @([UnorderedListStyle getStyleType]),
149
+ @([OrderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType]),
150
+ @([CodeBlockStyle getStyleType]), @([CheckboxListStyle getStyleType])
129
151
  ],
130
152
  @([H2Style getStyleType]) : @[
131
153
  @([H1Style getStyleType]), @([H3Style getStyleType]),
132
- @([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]),
133
- @([BlockQuoteStyle getStyleType]), @([CodeBlockStyle getStyleType])
154
+ @([H4Style getStyleType]), @([H5Style getStyleType]),
155
+ @([H6Style getStyleType]), @([UnorderedListStyle getStyleType]),
156
+ @([OrderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType]),
157
+ @([CodeBlockStyle getStyleType]), @([CheckboxListStyle getStyleType])
134
158
  ],
135
159
  @([H3Style getStyleType]) : @[
136
160
  @([H1Style getStyleType]), @([H2Style getStyleType]),
137
- @([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]),
138
- @([BlockQuoteStyle getStyleType]), @([CodeBlockStyle getStyleType])
161
+ @([H4Style getStyleType]), @([H5Style getStyleType]),
162
+ @([H6Style getStyleType]), @([UnorderedListStyle getStyleType]),
163
+ @([OrderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType]),
164
+ @([CodeBlockStyle getStyleType]), @([CheckboxListStyle getStyleType])
165
+ ],
166
+ @([H4Style getStyleType]) : @[
167
+ @([H1Style getStyleType]), @([H2Style getStyleType]),
168
+ @([H3Style getStyleType]), @([H5Style getStyleType]),
169
+ @([H6Style getStyleType]), @([UnorderedListStyle getStyleType]),
170
+ @([OrderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType]),
171
+ @([CodeBlockStyle getStyleType]), @([CheckboxListStyle getStyleType])
172
+ ],
173
+ @([H5Style getStyleType]) : @[
174
+ @([H1Style getStyleType]), @([H2Style getStyleType]),
175
+ @([H3Style getStyleType]), @([H4Style getStyleType]),
176
+ @([H6Style getStyleType]), @([UnorderedListStyle getStyleType]),
177
+ @([OrderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType]),
178
+ @([CodeBlockStyle getStyleType]), @([CheckboxListStyle getStyleType])
179
+ ],
180
+ @([H6Style getStyleType]) : @[
181
+ @([H1Style getStyleType]), @([H2Style getStyleType]),
182
+ @([H3Style getStyleType]), @([H4Style getStyleType]),
183
+ @([H5Style getStyleType]), @([UnorderedListStyle getStyleType]),
184
+ @([OrderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType]),
185
+ @([CodeBlockStyle getStyleType]), @([CheckboxListStyle getStyleType])
139
186
  ],
140
187
  @([UnorderedListStyle getStyleType]) : @[
141
188
  @([H1Style getStyleType]), @([H2Style getStyleType]),
142
- @([H3Style getStyleType]), @([OrderedListStyle getStyleType]),
143
- @([BlockQuoteStyle getStyleType]), @([CodeBlockStyle getStyleType])
189
+ @([H3Style getStyleType]), @([H4Style getStyleType]),
190
+ @([H5Style getStyleType]), @([H6Style getStyleType]),
191
+ @([OrderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType]),
192
+ @([CodeBlockStyle getStyleType]), @([CheckboxListStyle getStyleType])
144
193
  ],
145
194
  @([OrderedListStyle getStyleType]) : @[
146
195
  @([H1Style getStyleType]), @([H2Style getStyleType]),
147
- @([H3Style getStyleType]), @([UnorderedListStyle getStyleType]),
196
+ @([H3Style getStyleType]), @([H4Style getStyleType]),
197
+ @([H5Style getStyleType]), @([H6Style getStyleType]),
198
+ @([UnorderedListStyle getStyleType]), @([BlockQuoteStyle getStyleType]),
199
+ @([CodeBlockStyle getStyleType]), @([CheckboxListStyle getStyleType])
200
+ ],
201
+ @([CheckboxListStyle getStyleType]) : @[
202
+ @([H1Style getStyleType]), @([H2Style getStyleType]),
203
+ @([H3Style getStyleType]), @([H4Style getStyleType]),
204
+ @([H5Style getStyleType]), @([H6Style getStyleType]),
205
+ @([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]),
148
206
  @([BlockQuoteStyle getStyleType]), @([CodeBlockStyle getStyleType])
149
207
  ],
150
208
  @([BlockQuoteStyle getStyleType]) : @[
151
209
  @([H1Style getStyleType]), @([H2Style getStyleType]),
152
- @([H3Style getStyleType]), @([UnorderedListStyle getStyleType]),
153
- @([OrderedListStyle getStyleType]), @([CodeBlockStyle getStyleType])
210
+ @([H3Style getStyleType]), @([H4Style getStyleType]),
211
+ @([H5Style getStyleType]), @([H6Style getStyleType]),
212
+ @([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]),
213
+ @([CodeBlockStyle getStyleType]), @([CheckboxListStyle getStyleType])
154
214
  ],
155
215
  @([CodeBlockStyle getStyleType]) : @[
156
216
  @([H1Style getStyleType]), @([H2Style getStyleType]),
157
- @([H3Style getStyleType]), @([BoldStyle getStyleType]),
158
- @([ItalicStyle getStyleType]), @([UnderlineStyle getStyleType]),
159
- @([StrikethroughStyle getStyleType]),
217
+ @([H3Style getStyleType]), @([H4Style getStyleType]),
218
+ @([H5Style getStyleType]), @([H6Style getStyleType]),
219
+ @([BoldStyle getStyleType]), @([ItalicStyle getStyleType]),
220
+ @([UnderlineStyle getStyleType]), @([StrikethroughStyle getStyleType]),
160
221
  @([UnorderedListStyle getStyleType]), @([OrderedListStyle getStyleType]),
161
222
  @([BlockQuoteStyle getStyleType]), @([InlineCodeStyle getStyleType]),
162
- @([MentionStyle getStyleType]), @([LinkStyle getStyleType])
223
+ @([MentionStyle getStyleType]), @([LinkStyle getStyleType]),
224
+ @([CheckboxListStyle getStyleType])
163
225
  ],
164
226
  @([ImageStyle getStyleType]) :
165
227
  @[ @([LinkStyle getStyleType]), @([MentionStyle getStyleType]) ]
166
228
  };
167
229
 
168
- blockingStyles = @{
230
+ blockingStyles = [@{
169
231
  @([BoldStyle getStyleType]) : @[ @([CodeBlockStyle getStyleType]) ],
170
232
  @([ItalicStyle getStyleType]) : @[ @([CodeBlockStyle getStyleType]) ],
171
233
  @([UnderlineStyle getStyleType]) : @[ @([CodeBlockStyle getStyleType]) ],
@@ -180,14 +242,19 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
180
242
  @([H1Style getStyleType]) : @[],
181
243
  @([H2Style getStyleType]) : @[],
182
244
  @([H3Style getStyleType]) : @[],
245
+ @([H4Style getStyleType]) : @[],
246
+ @([H5Style getStyleType]) : @[],
247
+ @([H6Style getStyleType]) : @[],
183
248
  @([UnorderedListStyle getStyleType]) : @[],
184
249
  @([OrderedListStyle getStyleType]) : @[],
250
+ @([CheckboxListStyle getStyleType]) : @[],
185
251
  @([BlockQuoteStyle getStyleType]) : @[],
186
252
  @([CodeBlockStyle getStyleType]) : @[],
187
253
  @([ImageStyle getStyleType]) : @[ @([InlineCodeStyle getStyleType]) ]
188
- };
254
+ } mutableCopy];
189
255
 
190
256
  parser = [[InputParser alloc] initWithInput:self];
257
+ _attachmentViews = [[NSMutableDictionary alloc] init];
191
258
  }
192
259
 
193
260
  - (void)setupTextView {
@@ -198,6 +265,10 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
198
265
  textView.delegate = self;
199
266
  textView.input = self;
200
267
  textView.layoutManager.input = self;
268
+ textView.adjustsFontForContentSizeCategory = YES;
269
+ [textView addGestureRecognizer:[[TextBlockTapGestureRecognizer alloc]
270
+ initWithInput:self
271
+ action:@selector(onTextBlockTap:)]];
201
272
  }
202
273
 
203
274
  - (void)setupPlaceholderLabel {
@@ -216,6 +287,7 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
216
287
  _placeholderLabel.lineBreakMode = NSLineBreakByTruncatingTail;
217
288
  _placeholderLabel.text = @"";
218
289
  _placeholderLabel.hidden = YES;
290
+ _placeholderLabel.adjustsFontForContentSizeCategory = YES;
219
291
  }
220
292
 
221
293
  // MARK: - Props
@@ -292,6 +364,11 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
292
364
 
293
365
  if (newViewProps.htmlStyle.h1.bold != oldViewProps.htmlStyle.h1.bold) {
294
366
  [newConfig setH1Bold:newViewProps.htmlStyle.h1.bold];
367
+
368
+ // Update style blocks for bold
369
+ newViewProps.htmlStyle.h1.bold ? [self addStyleBlock:H1 to:Bold]
370
+ : [self removeStyleBlock:H1 from:Bold];
371
+
295
372
  stylePropChanged = YES;
296
373
  }
297
374
 
@@ -303,6 +380,11 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
303
380
 
304
381
  if (newViewProps.htmlStyle.h2.bold != oldViewProps.htmlStyle.h2.bold) {
305
382
  [newConfig setH2Bold:newViewProps.htmlStyle.h2.bold];
383
+
384
+ // Update style blocks for bold
385
+ newViewProps.htmlStyle.h2.bold ? [self addStyleBlock:H2 to:Bold]
386
+ : [self removeStyleBlock:H2 from:Bold];
387
+
306
388
  stylePropChanged = YES;
307
389
  }
308
390
 
@@ -314,6 +396,59 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
314
396
 
315
397
  if (newViewProps.htmlStyle.h3.bold != oldViewProps.htmlStyle.h3.bold) {
316
398
  [newConfig setH3Bold:newViewProps.htmlStyle.h3.bold];
399
+
400
+ // Update style blocks for bold
401
+ newViewProps.htmlStyle.h3.bold ? [self addStyleBlock:H3 to:Bold]
402
+ : [self removeStyleBlock:H3 from:Bold];
403
+
404
+ stylePropChanged = YES;
405
+ }
406
+
407
+ if (newViewProps.htmlStyle.h4.fontSize !=
408
+ oldViewProps.htmlStyle.h4.fontSize) {
409
+ [newConfig setH4FontSize:newViewProps.htmlStyle.h4.fontSize];
410
+ stylePropChanged = YES;
411
+ }
412
+
413
+ if (newViewProps.htmlStyle.h4.bold != oldViewProps.htmlStyle.h4.bold) {
414
+ [newConfig setH4Bold:newViewProps.htmlStyle.h4.bold];
415
+
416
+ // Update style blocks for bold
417
+ newViewProps.htmlStyle.h4.bold ? [self addStyleBlock:H4 to:Bold]
418
+ : [self removeStyleBlock:H4 from:Bold];
419
+
420
+ stylePropChanged = YES;
421
+ }
422
+
423
+ if (newViewProps.htmlStyle.h5.fontSize !=
424
+ oldViewProps.htmlStyle.h5.fontSize) {
425
+ [newConfig setH5FontSize:newViewProps.htmlStyle.h5.fontSize];
426
+ stylePropChanged = YES;
427
+ }
428
+
429
+ if (newViewProps.htmlStyle.h5.bold != oldViewProps.htmlStyle.h5.bold) {
430
+ [newConfig setH5Bold:newViewProps.htmlStyle.h5.bold];
431
+
432
+ // Update style blocks for bold
433
+ newViewProps.htmlStyle.h5.bold ? [self addStyleBlock:H5 to:Bold]
434
+ : [self removeStyleBlock:H5 from:Bold];
435
+
436
+ stylePropChanged = YES;
437
+ }
438
+
439
+ if (newViewProps.htmlStyle.h6.fontSize !=
440
+ oldViewProps.htmlStyle.h6.fontSize) {
441
+ [newConfig setH6FontSize:newViewProps.htmlStyle.h6.fontSize];
442
+ stylePropChanged = YES;
443
+ }
444
+
445
+ if (newViewProps.htmlStyle.h6.bold != oldViewProps.htmlStyle.h6.bold) {
446
+ [newConfig setH6Bold:newViewProps.htmlStyle.h6.bold];
447
+
448
+ // Update style blocks for bold
449
+ newViewProps.htmlStyle.h6.bold ? [self addStyleBlock:H6 to:Bold]
450
+ : [self removeStyleBlock:H6 from:Bold];
451
+
317
452
  stylePropChanged = YES;
318
453
  }
319
454
 
@@ -480,6 +615,37 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
480
615
  stylePropChanged = YES;
481
616
  }
482
617
 
618
+ if (newViewProps.htmlStyle.ulCheckbox.boxSize !=
619
+ oldViewProps.htmlStyle.ulCheckbox.boxSize) {
620
+ [newConfig
621
+ setCheckboxListBoxSize:newViewProps.htmlStyle.ulCheckbox.boxSize];
622
+ stylePropChanged = YES;
623
+ }
624
+
625
+ if (newViewProps.htmlStyle.ulCheckbox.gapWidth !=
626
+ oldViewProps.htmlStyle.ulCheckbox.gapWidth) {
627
+ [newConfig
628
+ setCheckboxListGapWidth:newViewProps.htmlStyle.ulCheckbox.gapWidth];
629
+ stylePropChanged = YES;
630
+ }
631
+
632
+ if (newViewProps.htmlStyle.ulCheckbox.marginLeft !=
633
+ oldViewProps.htmlStyle.ulCheckbox.marginLeft) {
634
+ [newConfig
635
+ setCheckboxListMarginLeft:newViewProps.htmlStyle.ulCheckbox.marginLeft];
636
+ stylePropChanged = YES;
637
+ }
638
+
639
+ if (newViewProps.htmlStyle.ulCheckbox.boxColor !=
640
+ oldViewProps.htmlStyle.ulCheckbox.boxColor) {
641
+ if (isColorMeaningful(newViewProps.htmlStyle.ulCheckbox.boxColor)) {
642
+ [newConfig setCheckboxListBoxColor:RCTUIColorFromSharedColor(
643
+ newViewProps.htmlStyle.ulCheckbox
644
+ .boxColor)];
645
+ stylePropChanged = YES;
646
+ }
647
+ }
648
+
483
649
  if (newViewProps.htmlStyle.a.textDecorationLine !=
484
650
  oldViewProps.htmlStyle.a.textDecorationLine) {
485
651
  NSString *objcString =
@@ -539,6 +705,8 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
539
705
  NSString *currentHtml = [parser
540
706
  parseToHtmlFromRange:NSMakeRange(0,
541
707
  textView.textStorage.string.length)];
708
+ // we want to preserve the selection between props changes
709
+ NSRange prevSelectedRange = textView.selectedRange;
542
710
 
543
711
  // now set the new config
544
712
  config = newConfig;
@@ -566,6 +734,7 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
566
734
  defaultTypingAttributes[NSParagraphStyleAttributeName] =
567
735
  [[NSParagraphStyle alloc] init];
568
736
  textView.typingAttributes = defaultTypingAttributes;
737
+ textView.selectedRange = prevSelectedRange;
569
738
 
570
739
  // update the placeholder as well
571
740
  [self refreshPlaceholderLabelStyles];
@@ -591,6 +760,7 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
591
760
  // we've got some seemingly proper html
592
761
  [parser replaceWholeFromHtml:initiallyProcessedHtml];
593
762
  }
763
+ textView.selectedRange = NSRange(textView.textStorage.string.length, 0);
594
764
  }
595
765
 
596
766
  // placeholderTextColor
@@ -631,6 +801,15 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
631
801
  [config setMentionIndicators:newIndicators];
632
802
  }
633
803
 
804
+ // linkRegex
805
+ LinkRegexConfig *oldRegexConfig =
806
+ [[LinkRegexConfig alloc] initWithLinkRegexProp:oldViewProps.linkRegex];
807
+ LinkRegexConfig *newRegexConfig =
808
+ [[LinkRegexConfig alloc] initWithLinkRegexProp:newViewProps.linkRegex];
809
+ if (![newRegexConfig isEqualToConfig:oldRegexConfig]) {
810
+ [config setLinkRegexConfig:newRegexConfig];
811
+ }
812
+
634
813
  // selection color sets both selection and cursor on iOS (just as in RN)
635
814
  if (newViewProps.selectionColor != oldViewProps.selectionColor) {
636
815
  if (isColorMeaningful(newViewProps.selectionColor)) {
@@ -668,6 +847,9 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
668
847
  // isOnChangeHtmlSet
669
848
  _emitHtml = newViewProps.isOnChangeHtmlSet;
670
849
 
850
+ // isOnChangeTextSet
851
+ _emitTextChange = newViewProps.isOnChangeTextSet;
852
+
671
853
  [super updateProps:props oldProps:oldProps];
672
854
  // run the changes callback
673
855
  [self anyTextMayHaveBeenModified];
@@ -782,6 +964,11 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
782
964
  // emitted
783
965
  NSMutableSet *newActiveStyles = [_activeStyles mutableCopy];
784
966
 
967
+ // currently blocked styles are subject to change (e.g. bold being blocked by
968
+ // headings might change in reaction to prop change) so they also are kept
969
+ // separately
970
+ NSMutableSet *newBlockedStyles = [_blockedStyles mutableCopy];
971
+
785
972
  // data for onLinkDetected event
786
973
  LinkData *detectedLinkData;
787
974
  NSRange detectedLinkRange = NSMakeRange(0, 0);
@@ -792,8 +979,14 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
792
979
 
793
980
  for (NSNumber *type in stylesDict) {
794
981
  id<BaseStyleProtocol> style = stylesDict[type];
982
+
795
983
  BOOL wasActive = [newActiveStyles containsObject:type];
796
984
  BOOL isActive = [style detectStyle:textView.selectedRange];
985
+
986
+ BOOL wasBlocked = [newBlockedStyles containsObject:type];
987
+ BOOL isBlocked = [self isStyle:(StyleType)[type integerValue]
988
+ activeInMap:blockingStyles];
989
+
797
990
  if (wasActive != isActive) {
798
991
  updateNeeded = YES;
799
992
  if (isActive) {
@@ -803,6 +996,16 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
803
996
  }
804
997
  }
805
998
 
999
+ // blocked state change for a style also needs an update
1000
+ if (wasBlocked != isBlocked) {
1001
+ updateNeeded = YES;
1002
+ if (isBlocked) {
1003
+ [newBlockedStyles addObject:type];
1004
+ } else {
1005
+ [newBlockedStyles removeObject:type];
1006
+ }
1007
+ }
1008
+
806
1009
  // onLinkDetected event
807
1010
  if (isActive && [type intValue] == [LinkStyle getStyleType]) {
808
1011
  // get the link data
@@ -867,35 +1070,30 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
867
1070
  if (updateNeeded) {
868
1071
  auto emitter = [self getEventEmitter];
869
1072
  if (emitter != nullptr) {
870
- // update activeStyles only if emitter is available
1073
+ // update activeStyles and blockedStyles only if emitter is available
871
1074
  _activeStyles = newActiveStyles;
872
-
873
- emitter->onChangeState({
874
- .isBold = [_activeStyles containsObject:@([BoldStyle getStyleType])],
875
- .isItalic =
876
- [_activeStyles containsObject:@([ItalicStyle getStyleType])],
877
- .isUnderline =
878
- [_activeStyles containsObject:@([UnderlineStyle getStyleType])],
879
- .isStrikeThrough =
880
- [_activeStyles containsObject:@([StrikethroughStyle getStyleType])],
881
- .isInlineCode =
882
- [_activeStyles containsObject:@([InlineCodeStyle getStyleType])],
883
- .isLink = [_activeStyles containsObject:@([LinkStyle getStyleType])],
884
- .isMention =
885
- [_activeStyles containsObject:@([MentionStyle getStyleType])],
886
- .isH1 = [_activeStyles containsObject:@([H1Style getStyleType])],
887
- .isH2 = [_activeStyles containsObject:@([H2Style getStyleType])],
888
- .isH3 = [_activeStyles containsObject:@([H3Style getStyleType])],
889
- .isUnorderedList =
890
- [_activeStyles containsObject:@([UnorderedListStyle getStyleType])],
891
- .isOrderedList =
892
- [_activeStyles containsObject:@([OrderedListStyle getStyleType])],
893
- .isBlockQuote =
894
- [_activeStyles containsObject:@([BlockQuoteStyle getStyleType])],
895
- .isCodeBlock =
896
- [_activeStyles containsObject:@([CodeBlockStyle getStyleType])],
897
- .isImage = [_activeStyles containsObject:@([ImageStyle getStyleType])],
898
- });
1075
+ _blockedStyles = newBlockedStyles;
1076
+
1077
+ emitter->onChangeState(
1078
+ {.bold = GET_STYLE_STATE([BoldStyle getStyleType]),
1079
+ .italic = GET_STYLE_STATE([ItalicStyle getStyleType]),
1080
+ .underline = GET_STYLE_STATE([UnderlineStyle getStyleType]),
1081
+ .strikeThrough = GET_STYLE_STATE([StrikethroughStyle getStyleType]),
1082
+ .inlineCode = GET_STYLE_STATE([InlineCodeStyle getStyleType]),
1083
+ .link = GET_STYLE_STATE([LinkStyle getStyleType]),
1084
+ .mention = GET_STYLE_STATE([MentionStyle getStyleType]),
1085
+ .h1 = GET_STYLE_STATE([H1Style getStyleType]),
1086
+ .h2 = GET_STYLE_STATE([H2Style getStyleType]),
1087
+ .h3 = GET_STYLE_STATE([H3Style getStyleType]),
1088
+ .h4 = GET_STYLE_STATE([H4Style getStyleType]),
1089
+ .h5 = GET_STYLE_STATE([H5Style getStyleType]),
1090
+ .h6 = GET_STYLE_STATE([H6Style getStyleType]),
1091
+ .unorderedList = GET_STYLE_STATE([UnorderedListStyle getStyleType]),
1092
+ .orderedList = GET_STYLE_STATE([OrderedListStyle getStyleType]),
1093
+ .blockQuote = GET_STYLE_STATE([BlockQuoteStyle getStyleType]),
1094
+ .codeBlock = GET_STYLE_STATE([CodeBlockStyle getStyleType]),
1095
+ .image = GET_STYLE_STATE([ImageStyle getStyleType]),
1096
+ .checkboxList = GET_STYLE_STATE([CheckboxListStyle getStyleType])});
899
1097
  }
900
1098
  }
901
1099
 
@@ -920,6 +1118,42 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
920
1118
  [self tryEmittingOnChangeHtmlEvent];
921
1119
  }
922
1120
 
1121
+ - (bool)isStyleActive:(StyleType)type {
1122
+ return [_activeStyles containsObject:@(type)];
1123
+ }
1124
+
1125
+ - (bool)isStyle:(StyleType)type activeInMap:(NSDictionary *)styleMap {
1126
+ NSArray *relatedStyles = styleMap[@(type)];
1127
+
1128
+ if (!relatedStyles) {
1129
+ return false;
1130
+ }
1131
+
1132
+ for (NSNumber *style in relatedStyles) {
1133
+ if ([_activeStyles containsObject:style]) {
1134
+ return true;
1135
+ }
1136
+ }
1137
+
1138
+ return false;
1139
+ }
1140
+
1141
+ - (void)addStyleBlock:(StyleType)blocking to:(StyleType)blocked {
1142
+ NSMutableArray *blocksArr = [blockingStyles[@(blocked)] mutableCopy];
1143
+ if (![blocksArr containsObject:@(blocking)]) {
1144
+ [blocksArr addObject:@(blocking)];
1145
+ blockingStyles[@(blocked)] = blocksArr;
1146
+ }
1147
+ }
1148
+
1149
+ - (void)removeStyleBlock:(StyleType)blocking from:(StyleType)blocked {
1150
+ NSMutableArray *blocksArr = [blockingStyles[@(blocked)] mutableCopy];
1151
+ if ([blocksArr containsObject:@(blocking)]) {
1152
+ [blocksArr removeObject:@(blocking)];
1153
+ blockingStyles[@(blocked)] = blocksArr;
1154
+ }
1155
+ }
1156
+
923
1157
  // MARK: - Native commands and events
924
1158
 
925
1159
  - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args {
@@ -960,10 +1194,19 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
960
1194
  [self toggleParagraphStyle:[H2Style getStyleType]];
961
1195
  } else if ([commandName isEqualToString:@"toggleH3"]) {
962
1196
  [self toggleParagraphStyle:[H3Style getStyleType]];
1197
+ } else if ([commandName isEqualToString:@"toggleH4"]) {
1198
+ [self toggleParagraphStyle:[H4Style getStyleType]];
1199
+ } else if ([commandName isEqualToString:@"toggleH5"]) {
1200
+ [self toggleParagraphStyle:[H5Style getStyleType]];
1201
+ } else if ([commandName isEqualToString:@"toggleH6"]) {
1202
+ [self toggleParagraphStyle:[H6Style getStyleType]];
963
1203
  } else if ([commandName isEqualToString:@"toggleUnorderedList"]) {
964
1204
  [self toggleParagraphStyle:[UnorderedListStyle getStyleType]];
965
1205
  } else if ([commandName isEqualToString:@"toggleOrderedList"]) {
966
1206
  [self toggleParagraphStyle:[OrderedListStyle getStyleType]];
1207
+ } else if ([commandName isEqualToString:@"toggleCheckboxList"]) {
1208
+ BOOL checked = [args[0] boolValue];
1209
+ [self toggleCheckboxList:checked];
967
1210
  } else if ([commandName isEqualToString:@"toggleBlockQuote"]) {
968
1211
  [self toggleParagraphStyle:[BlockQuoteStyle getStyleType]];
969
1212
  } else if ([commandName isEqualToString:@"toggleCodeBlock"]) {
@@ -974,6 +1217,10 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
974
1217
  CGFloat imgHeight = [(NSNumber *)args[2] floatValue];
975
1218
 
976
1219
  [self addImage:uri width:imgWidth height:imgHeight];
1220
+ } else if ([commandName isEqualToString:@"setSelection"]) {
1221
+ NSInteger start = [((NSNumber *)args[0]) integerValue];
1222
+ NSInteger end = [((NSNumber *)args[1]) integerValue];
1223
+ [self setCustomSelection:start end:end];
977
1224
  } else if ([commandName isEqualToString:@"requestHTML"]) {
978
1225
  NSInteger requestId = [((NSNumber *)args[0]) integerValue];
979
1226
  [self requestHTML:requestId];
@@ -1010,9 +1257,42 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
1010
1257
 
1011
1258
  // set recentlyChangedRange and check for changes
1012
1259
  recentlyChangedRange = NSMakeRange(0, textView.textStorage.string.length);
1260
+ textView.selectedRange = NSRange(textView.textStorage.string.length, 0);
1013
1261
  [self anyTextMayHaveBeenModified];
1014
1262
  }
1015
1263
 
1264
+ - (void)setCustomSelection:(NSInteger)visibleStart end:(NSInteger)visibleEnd {
1265
+ NSString *text = textView.textStorage.string;
1266
+
1267
+ NSUInteger actualStart = [self getActualIndex:visibleStart text:text];
1268
+ NSUInteger actualEnd = [self getActualIndex:visibleEnd text:text];
1269
+
1270
+ textView.selectedRange = NSMakeRange(actualStart, actualEnd - actualStart);
1271
+ }
1272
+
1273
+ // Helper: Walks through the string skipping ZWSPs to find the Nth visible
1274
+ // character
1275
+ - (NSUInteger)getActualIndex:(NSInteger)visibleIndex text:(NSString *)text {
1276
+ NSUInteger currentVisibleCount = 0;
1277
+ NSUInteger actualIndex = 0;
1278
+
1279
+ while (actualIndex < text.length) {
1280
+ if (currentVisibleCount == visibleIndex) {
1281
+ return actualIndex;
1282
+ }
1283
+
1284
+ // If the current char is not a hidden space, it counts towards our visible
1285
+ // index.
1286
+ if ([text characterAtIndex:actualIndex] != 0x200B) {
1287
+ currentVisibleCount++;
1288
+ }
1289
+
1290
+ actualIndex++;
1291
+ }
1292
+
1293
+ return actualIndex;
1294
+ }
1295
+
1016
1296
  - (void)emitOnLinkDetectedEvent:(NSString *)text
1017
1297
  url:(NSString *)url
1018
1298
  range:(NSRange)range {
@@ -1034,6 +1314,32 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
1034
1314
  }
1035
1315
  }
1036
1316
 
1317
+ - (void)emitOnPasteImagesEvent:(NSArray<NSDictionary *> *)images {
1318
+ auto emitter = [self getEventEmitter];
1319
+ if (emitter != nullptr) {
1320
+ std::vector<EnrichedTextInputViewEventEmitter::OnPasteImagesImages>
1321
+ imagesVector;
1322
+ imagesVector.reserve(images.count);
1323
+
1324
+ for (NSDictionary *img in images) {
1325
+ NSString *uri = img[@"uri"];
1326
+ NSString *type = img[@"type"];
1327
+ double width = [img[@"width"] doubleValue];
1328
+ double height = [img[@"height"] doubleValue];
1329
+
1330
+ EnrichedTextInputViewEventEmitter::OnPasteImagesImages imageStruct = {
1331
+ .uri = [uri toCppString],
1332
+ .type = [type toCppString],
1333
+ .width = width,
1334
+ .height = height};
1335
+
1336
+ imagesVector.push_back(imageStruct);
1337
+ }
1338
+
1339
+ emitter->onPasteImages({.images = imagesVector});
1340
+ }
1341
+ }
1342
+
1037
1343
  - (void)emitOnMentionDetectedEvent:(NSString *)text
1038
1344
  indicator:(NSString *)indicator
1039
1345
  attributes:(NSString *)attributes {
@@ -1091,6 +1397,13 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
1091
1397
  }
1092
1398
  }
1093
1399
 
1400
+ - (void)emitOnKeyPressEvent:(NSString *)key {
1401
+ auto emitter = [self getEventEmitter];
1402
+ if (emitter != nullptr) {
1403
+ emitter->onInputKeyPress({.key = [key toCppString]});
1404
+ }
1405
+ }
1406
+
1094
1407
  // MARK: - Styles manipulation
1095
1408
 
1096
1409
  - (void)toggleRegularStyle:(StyleType)type {
@@ -1114,6 +1427,24 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
1114
1427
  }
1115
1428
  }
1116
1429
 
1430
+ - (void)toggleCheckboxList:(BOOL)checked {
1431
+ CheckboxListStyle *checkboxListStyleClass =
1432
+ (CheckboxListStyle *)stylesDict[@([CheckboxListStyle getStyleType])];
1433
+ if (checkboxListStyleClass == nullptr) {
1434
+ return;
1435
+ }
1436
+ // we always pass whole paragraph/s range to these styles
1437
+ NSRange paragraphRange = [textView.textStorage.string
1438
+ paragraphRangeForRange:textView.selectedRange];
1439
+
1440
+ if ([self handleStyleBlocksAndConflicts:[CheckboxListStyle getStyleType]
1441
+ range:paragraphRange]) {
1442
+ [checkboxListStyleClass applyStyleWithCheckedValue:checked
1443
+ inRange:paragraphRange];
1444
+ [self anyTextMayHaveBeenModified];
1445
+ }
1446
+ }
1447
+
1117
1448
  - (void)addLinkAt:(NSInteger)start
1118
1449
  end:(NSInteger)end
1119
1450
  text:(NSString *)text
@@ -1247,6 +1578,7 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
1247
1578
  if (linkStyleClass != nullptr) {
1248
1579
  [linkStyleClass manageLinkTypingAttributes];
1249
1580
  }
1581
+ NSString *currentString = [textView.textStorage.string copy];
1250
1582
 
1251
1583
  // mention typing attribtues fix and active editing
1252
1584
  MentionStyle *mentionStyleClass =
@@ -1257,14 +1589,12 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
1257
1589
  // mention editing runs if only a selection was done (no text change)
1258
1590
  // otherwise we would double-emit with a second call in the
1259
1591
  // anyTextMayHaveBeenModified method
1260
- if ([_recentInputString
1261
- isEqualToString:[textView.textStorage.string copy]]) {
1592
+ if ([_recentInputString isEqualToString:currentString]) {
1262
1593
  [mentionStyleClass manageMentionEditing];
1263
1594
  }
1264
1595
  }
1265
1596
 
1266
1597
  // typing attributes for empty lines selection reset
1267
- NSString *currentString = [textView.textStorage.string copy];
1268
1598
  if (textView.selectedRange.length == 0 &&
1269
1599
  [_recentInputString isEqualToString:currentString]) {
1270
1600
  // no string change means only a selection changed with no character changes
@@ -1333,16 +1663,6 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
1333
1663
  [codeBlockStyle manageCodeBlockFontAndColor];
1334
1664
  }
1335
1665
 
1336
- // improper headings fix
1337
- H1Style *h1Style = stylesDict[@([H1Style getStyleType])];
1338
- H2Style *h2Style = stylesDict[@([H2Style getStyleType])];
1339
- H3Style *h3Style = stylesDict[@([H3Style getStyleType])];
1340
- if (h1Style != nullptr && h2Style != nullptr && h3Style != nullptr) {
1341
- [h1Style handleImproperHeadings];
1342
- [h2Style handleImproperHeadings];
1343
- [h3Style handleImproperHeadings];
1344
- }
1345
-
1346
1666
  // mentions management: removal and editing
1347
1667
  MentionStyle *mentionStyleClass =
1348
1668
  (MentionStyle *)stylesDict[@([MentionStyle getStyleType])];
@@ -1380,7 +1700,7 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
1380
1700
 
1381
1701
  // emit onChangeText event
1382
1702
  auto emitter = [self getEventEmitter];
1383
- if (emitter != nullptr) {
1703
+ if (emitter != nullptr && _emitTextChange) {
1384
1704
  // set the recent input string only if the emitter is defined
1385
1705
  _recentInputString = [textView.textStorage.string copy];
1386
1706
 
@@ -1397,6 +1717,7 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
1397
1717
  [self tryUpdatingHeight];
1398
1718
  // update active styles as well
1399
1719
  [self tryUpdatingActiveStyles];
1720
+ [self layoutAttachments];
1400
1721
  // update drawing - schedule debounced relayout
1401
1722
  [self scheduleRelayoutIfNeeded];
1402
1723
  }
@@ -1477,13 +1798,33 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
1477
1798
  }
1478
1799
  }
1479
1800
 
1801
+ - (void)handleKeyPressInRange:(NSString *)text range:(NSRange)range {
1802
+ NSString *key = nil;
1803
+
1804
+ if (text.length == 0 && range.length > 0) {
1805
+ key = @"Backspace";
1806
+ } else if ([text isEqualToString:@"\n"]) {
1807
+ key = @"Enter";
1808
+ } else if ([text isEqualToString:@"\t"]) {
1809
+ key = @"Tab";
1810
+ } else if (text.length == 1) {
1811
+ key = text;
1812
+ }
1813
+
1814
+ if (key != nil) {
1815
+ [self emitOnKeyPressEvent:key];
1816
+ }
1817
+ }
1818
+
1480
1819
  - (bool)textView:(UITextView *)textView
1481
1820
  shouldChangeTextInRange:(NSRange)range
1482
1821
  replacementText:(NSString *)text {
1483
1822
  recentlyChangedRange = NSMakeRange(range.location, text.length);
1823
+ [self handleKeyPressInRange:text range:range];
1484
1824
 
1485
1825
  UnorderedListStyle *uStyle = stylesDict[@([UnorderedListStyle getStyleType])];
1486
1826
  OrderedListStyle *oStyle = stylesDict[@([OrderedListStyle getStyleType])];
1827
+ CheckboxListStyle *cbLStyle = stylesDict[@([CheckboxListStyle getStyleType])];
1487
1828
  BlockQuoteStyle *bqStyle = stylesDict[@([BlockQuoteStyle getStyleType])];
1488
1829
  CodeBlockStyle *cbStyle = stylesDict[@([CodeBlockStyle getStyleType])];
1489
1830
  LinkStyle *linkStyle = stylesDict[@([LinkStyle getStyleType])];
@@ -1491,6 +1832,9 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
1491
1832
  H1Style *h1Style = stylesDict[@([H1Style getStyleType])];
1492
1833
  H2Style *h2Style = stylesDict[@([H2Style getStyleType])];
1493
1834
  H3Style *h3Style = stylesDict[@([H3Style getStyleType])];
1835
+ H4Style *h4Style = stylesDict[@([H4Style getStyleType])];
1836
+ H5Style *h5Style = stylesDict[@([H5Style getStyleType])];
1837
+ H6Style *h6Style = stylesDict[@([H6Style getStyleType])];
1494
1838
 
1495
1839
  // some of the changes these checks do could interfere with later checks and
1496
1840
  // cause a crash so here I rely on short circuiting evaluation of the logical
@@ -1500,6 +1844,8 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
1500
1844
  [uStyle tryHandlingListShorcutInRange:range replacementText:text] ||
1501
1845
  [oStyle handleBackspaceInRange:range replacementText:text] ||
1502
1846
  [oStyle tryHandlingListShorcutInRange:range replacementText:text] ||
1847
+ [cbLStyle handleBackspaceInRange:range replacementText:text] ||
1848
+ [cbLStyle handleNewlinesInRange:range replacementText:text] ||
1503
1849
  [bqStyle handleBackspaceInRange:range replacementText:text] ||
1504
1850
  [cbStyle handleBackspaceInRange:range replacementText:text] ||
1505
1851
  [linkStyle handleLeadingLinkReplacement:range replacementText:text] ||
@@ -1508,12 +1854,24 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
1508
1854
  [h1Style handleNewlinesInRange:range replacementText:text] ||
1509
1855
  [h2Style handleNewlinesInRange:range replacementText:text] ||
1510
1856
  [h3Style handleNewlinesInRange:range replacementText:text] ||
1857
+ [h4Style handleNewlinesInRange:range replacementText:text] ||
1858
+ [h5Style handleNewlinesInRange:range replacementText:text] ||
1859
+ [h6Style handleNewlinesInRange:range replacementText:text] ||
1860
+ [h1Style handleBackspaceInRange:range replacementText:text] ||
1861
+ [h2Style handleBackspaceInRange:range replacementText:text] ||
1862
+ [h3Style handleBackspaceInRange:range replacementText:text] ||
1863
+ [h4Style handleBackspaceInRange:range replacementText:text] ||
1864
+ [h5Style handleBackspaceInRange:range replacementText:text] ||
1865
+ [h6Style handleBackspaceInRange:range replacementText:text] ||
1511
1866
  [ZeroWidthSpaceUtils handleBackspaceInRange:range
1512
1867
  replacementText:text
1513
1868
  input:self] ||
1514
1869
  [ParagraphAttributesUtils handleBackspaceInRange:range
1515
1870
  replacementText:text
1516
1871
  input:self] ||
1872
+ [ParagraphAttributesUtils handleResetTypingAttributesOnBackspace:range
1873
+ replacementText:text
1874
+ input:self] ||
1517
1875
  // CRITICAL: This callback HAS TO be always evaluated last.
1518
1876
  //
1519
1877
  // This function is the "Generic Fallback": if no specific style claims
@@ -1558,6 +1916,90 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
1558
1916
  [self anyTextMayHaveBeenModified];
1559
1917
  }
1560
1918
 
1919
+ /**
1920
+ * Handles iOS Dynamic Type changes (User changing font size in System
1921
+ * Settings).
1922
+ *
1923
+ * Unlike Android, iOS Views do not automatically rescale existing
1924
+ * NSAttributedStrings when the system font size changes. The text attributes
1925
+ * are static once drawn.
1926
+ *
1927
+ * This method detects the change and performs a "Hard Refresh" of the content.
1928
+ */
1929
+ - (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
1930
+ [super traitCollectionDidChange:previousTraitCollection];
1931
+
1932
+ if (previousTraitCollection.preferredContentSizeCategory !=
1933
+ self.traitCollection.preferredContentSizeCategory) {
1934
+ [config invalidateFonts];
1935
+
1936
+ NSMutableDictionary *newTypingAttrs = [defaultTypingAttributes mutableCopy];
1937
+ newTypingAttrs[NSFontAttributeName] = [config primaryFont];
1938
+
1939
+ defaultTypingAttributes = newTypingAttrs;
1940
+ textView.typingAttributes = defaultTypingAttributes;
1941
+
1942
+ [self refreshPlaceholderLabelStyles];
1943
+
1944
+ NSRange prevSelectedRange = textView.selectedRange;
1945
+
1946
+ NSString *currentHtml = [parser
1947
+ parseToHtmlFromRange:NSMakeRange(0,
1948
+ textView.textStorage.string.length)];
1949
+ NSString *initiallyProcessedHtml =
1950
+ [parser initiallyProcessHtml:currentHtml];
1951
+ [parser replaceWholeFromHtml:initiallyProcessedHtml];
1952
+
1953
+ textView.selectedRange = prevSelectedRange;
1954
+ [self anyTextMayHaveBeenModified];
1955
+ }
1956
+ }
1957
+
1958
+ - (void)onTextBlockTap:(TextBlockTapGestureRecognizer *)gr {
1959
+ if (gr.state != UIGestureRecognizerStateEnded)
1960
+ return;
1961
+ if (![self->textView isFirstResponder]) {
1962
+ [self->textView becomeFirstResponder];
1963
+ }
1964
+
1965
+ switch (gr.tapKind) {
1966
+
1967
+ case TextBlockTapKindCheckbox: {
1968
+ CheckboxListStyle *checkboxStyle =
1969
+ (CheckboxListStyle *)stylesDict[@([CheckboxListStyle getStyleType])];
1970
+
1971
+ if (checkboxStyle) {
1972
+ NSUInteger charIndex = (NSUInteger)gr.characterIndex;
1973
+ [checkboxStyle toggleCheckedAt:charIndex];
1974
+ [self anyTextMayHaveBeenModified];
1975
+
1976
+ NSString *fullText = textView.textStorage.string;
1977
+ NSRange paragraphRange =
1978
+ [fullText paragraphRangeForRange:NSMakeRange(charIndex, 0)];
1979
+ NSUInteger endOfLineIndex = NSMaxRange(paragraphRange);
1980
+
1981
+ // If the paragraph ends with a newline, step back by 1 so the cursor
1982
+ // stays on the current line instead of jumping to the next one.
1983
+ if (endOfLineIndex > 0 && endOfLineIndex <= fullText.length) {
1984
+ unichar lastChar = [fullText characterAtIndex:endOfLineIndex - 1];
1985
+ if ([[NSCharacterSet newlineCharacterSet] characterIsMember:lastChar]) {
1986
+ endOfLineIndex--;
1987
+ }
1988
+ }
1989
+
1990
+ // Move the cursor to the end of the currently tapped checkbox line.
1991
+ // Without this, the cursor may remain at its previous position,
1992
+ // potentially inside a different checkbox line.
1993
+ textView.selectedRange = NSMakeRange(endOfLineIndex, 0);
1994
+ }
1995
+ break;
1996
+ }
1997
+
1998
+ default:
1999
+ break;
2000
+ }
2001
+ }
2002
+
1561
2003
  // MARK: - Media attachments delegate
1562
2004
 
1563
2005
  - (void)mediaAttachmentDidUpdate:(NSTextAttachment *)attachment {
@@ -1583,6 +2025,107 @@ Class<RCTComponentViewProtocol> EnrichedTextInputViewCls(void) {
1583
2025
  [storage edited:NSTextStorageEditedAttributes
1584
2026
  range:foundRange
1585
2027
  changeInLength:0];
2028
+
2029
+ dispatch_async(dispatch_get_main_queue(), ^{
2030
+ [self layoutAttachments];
2031
+ });
1586
2032
  }
1587
2033
 
2034
+ // MARK: - Image/GIF Overlay Management
2035
+
2036
+ - (void)layoutAttachments {
2037
+ NSTextStorage *storage = textView.textStorage;
2038
+ NSMutableDictionary<NSValue *, UIImageView *> *activeAttachmentViews =
2039
+ [NSMutableDictionary dictionary];
2040
+
2041
+ // Iterate over the entire text to find ImageAttachments
2042
+ [storage enumerateAttribute:NSAttachmentAttributeName
2043
+ inRange:NSMakeRange(0, storage.length)
2044
+ options:0
2045
+ usingBlock:^(id value, NSRange range, BOOL *stop) {
2046
+ if ([value isKindOfClass:[ImageAttachment class]]) {
2047
+ ImageAttachment *attachment = (ImageAttachment *)value;
2048
+
2049
+ CGRect rect = [self frameForAttachment:attachment
2050
+ atRange:range];
2051
+
2052
+ // Get or Create the UIImageView for this specific
2053
+ // attachment key
2054
+ NSValue *key =
2055
+ [NSValue valueWithNonretainedObject:attachment];
2056
+ UIImageView *imgView = _attachmentViews[key];
2057
+
2058
+ if (!imgView) {
2059
+ // It doesn't exist yet, create it
2060
+ imgView = [[UIImageView alloc] initWithFrame:rect];
2061
+ imgView.contentMode = UIViewContentModeScaleAspectFit;
2062
+ imgView.tintColor = [UIColor labelColor];
2063
+
2064
+ // Add it directly to the TextView
2065
+ [textView addSubview:imgView];
2066
+ }
2067
+
2068
+ // Update position (in case text moved/scrolled)
2069
+ if (!CGRectEqualToRect(imgView.frame, rect)) {
2070
+ imgView.frame = rect;
2071
+ }
2072
+ UIImage *targetImage =
2073
+ attachment.storedAnimatedImage ?: attachment.image;
2074
+
2075
+ // Only set if different to avoid resetting the animation
2076
+ // loop
2077
+ if (imgView.image != targetImage) {
2078
+ imgView.image = targetImage;
2079
+ }
2080
+
2081
+ // Ensure it is visible on top
2082
+ imgView.hidden = NO;
2083
+ [textView bringSubviewToFront:imgView];
2084
+
2085
+ activeAttachmentViews[key] = imgView;
2086
+ // Remove from the old map so we know it has been claimed
2087
+ [_attachmentViews removeObjectForKey:key];
2088
+ }
2089
+ }];
2090
+
2091
+ // Everything remaining in _attachmentViews is dead or off-screen
2092
+ for (UIImageView *danglingView in _attachmentViews.allValues) {
2093
+ [danglingView removeFromSuperview];
2094
+ }
2095
+ _attachmentViews = activeAttachmentViews;
2096
+ }
2097
+
2098
+ - (CGRect)frameForAttachment:(ImageAttachment *)attachment
2099
+ atRange:(NSRange)range {
2100
+ NSLayoutManager *layoutManager = textView.layoutManager;
2101
+ NSTextContainer *textContainer = textView.textContainer;
2102
+ NSTextStorage *storage = textView.textStorage;
2103
+
2104
+ NSRange glyphRange = [layoutManager glyphRangeForCharacterRange:range
2105
+ actualCharacterRange:NULL];
2106
+ CGRect glyphRect = [layoutManager boundingRectForGlyphRange:glyphRange
2107
+ inTextContainer:textContainer];
2108
+
2109
+ CGRect lineRect =
2110
+ [layoutManager lineFragmentRectForGlyphAtIndex:glyphRange.location
2111
+ effectiveRange:NULL];
2112
+ CGSize attachmentSize = attachment.bounds.size;
2113
+
2114
+ UIFont *font = [storage attribute:NSFontAttributeName
2115
+ atIndex:range.location
2116
+ effectiveRange:NULL];
2117
+ if (!font) {
2118
+ font = [config primaryFont];
2119
+ }
2120
+
2121
+ // Calculate (Baseline Alignment)
2122
+ CGFloat targetY =
2123
+ CGRectGetMaxY(lineRect) + font.descender - attachmentSize.height;
2124
+ CGRect rect =
2125
+ CGRectMake(glyphRect.origin.x + textView.textContainerInset.left,
2126
+ targetY + textView.textContainerInset.top,
2127
+ attachmentSize.width, attachmentSize.height);
2128
+
2129
+ return CGRectIntegral(rect);
2130
+ }
1588
2131
  @end