react-native-enriched 0.3.0 → 0.4.1

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 (202) hide show
  1. package/README.md +6 -4
  2. package/android/build.gradle +3 -3
  3. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerDelegate.java +3 -0
  4. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerInterface.java +1 -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/{ios/generated/RNEnrichedTextInputViewSpec → android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec}/EventEmitters.cpp +31 -29
  8. package/{ios/generated/RNEnrichedTextInputViewSpec → android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec}/EventEmitters.h +22 -25
  9. package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/Props.h +57 -0
  10. package/android/gradle.properties +5 -5
  11. package/android/src/main/java/com/swmansion/enriched/{EnrichedTextInputViewPackage.kt → ReactNativeEnrichedPackage.kt} +3 -2
  12. package/android/src/main/java/com/swmansion/enriched/{utils → common}/AsyncDrawable.kt +40 -8
  13. package/android/src/main/java/com/swmansion/enriched/common/CheckboxDrawable.kt +81 -0
  14. package/android/src/main/java/com/swmansion/enriched/{utils → common}/EnrichedConstants.kt +1 -1
  15. package/android/src/main/java/com/swmansion/enriched/common/EnrichedStyle.kt +57 -0
  16. package/android/src/main/java/com/swmansion/enriched/{spans/utils → common}/ForceRedrawSpan.kt +1 -1
  17. package/android/src/main/java/com/swmansion/enriched/common/MentionStyle.kt +7 -0
  18. package/android/src/main/java/com/swmansion/enriched/{utils → common}/ResourceManager.kt +1 -1
  19. package/android/src/main/java/com/swmansion/enriched/{utils → common/parser}/EnrichedParser.java +126 -99
  20. package/android/src/main/java/com/swmansion/enriched/common/parser/EnrichedSpanFactory.kt +79 -0
  21. package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/EnrichedBlockQuoteSpan.kt +9 -13
  22. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedBoldSpan.kt +12 -0
  23. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedCheckboxListSpan.kt +91 -0
  24. package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/EnrichedCodeBlockSpan.kt +8 -12
  25. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH1Span.kt +20 -0
  26. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH2Span.kt +20 -0
  27. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH3Span.kt +20 -0
  28. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH4Span.kt +21 -0
  29. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH5Span.kt +20 -0
  30. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH6Span.kt +20 -0
  31. package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/EnrichedImageSpan.kt +43 -38
  32. package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/EnrichedInlineCodeSpan.kt +7 -11
  33. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedItalicSpan.kt +12 -0
  34. package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/EnrichedLinkSpan.kt +7 -11
  35. package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/EnrichedMentionSpan.kt +6 -10
  36. package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/EnrichedOrderedListSpan.kt +12 -21
  37. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedStrikeThroughSpan.kt +11 -0
  38. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedUnderlineSpan.kt +11 -0
  39. package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/EnrichedUnorderedListSpan.kt +9 -13
  40. package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/interfaces/EnrichedBlockSpan.kt +1 -1
  41. package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/interfaces/EnrichedHeadingSpan.kt +1 -1
  42. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedInlineSpan.kt +3 -0
  43. package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/interfaces/EnrichedParagraphSpan.kt +1 -1
  44. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedSpan.kt +3 -0
  45. package/android/src/main/java/com/swmansion/enriched/{spans → common/spans}/interfaces/EnrichedZeroWidthSpaceSpan.kt +1 -1
  46. package/android/src/main/java/com/swmansion/enriched/{EnrichedTextInputConnectionWrapper.kt → textinput/EnrichedTextInputConnectionWrapper.kt} +2 -2
  47. package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputSpannableFactory.kt +83 -0
  48. package/android/src/main/java/com/swmansion/enriched/{EnrichedTextInputView.kt → textinput/EnrichedTextInputView.kt} +87 -51
  49. package/android/src/main/java/com/swmansion/enriched/{EnrichedTextInputViewLayoutManager.kt → textinput/EnrichedTextInputViewLayoutManager.kt} +1 -1
  50. package/android/src/main/java/com/swmansion/enriched/{EnrichedTextInputViewManager.kt → textinput/EnrichedTextInputViewManager.kt} +24 -17
  51. package/android/src/main/java/com/swmansion/enriched/{MeasurementStore.kt → textinput/MeasurementStore.kt} +5 -4
  52. package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/MentionHandler.kt +2 -2
  53. package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnChangeHtmlEvent.kt +1 -1
  54. package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnChangeSelectionEvent.kt +1 -1
  55. package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnChangeStateEvent.kt +1 -1
  56. package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnChangeTextEvent.kt +2 -2
  57. package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnInputBlurEvent.kt +1 -1
  58. package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnInputFocusEvent.kt +1 -1
  59. package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnInputKeyPressEvent.kt +1 -1
  60. package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnLinkDetectedEvent.kt +1 -1
  61. package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnMentionDetectedEvent.kt +1 -1
  62. package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnMentionEvent.kt +1 -1
  63. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnPasteImagesEvent.kt +47 -0
  64. package/android/src/main/java/com/swmansion/enriched/{events → textinput/events}/OnRequestHtmlResultEvent.kt +1 -1
  65. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputBlockQuoteSpan.kt +14 -0
  66. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputBoldSpan.kt +14 -0
  67. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputCheckboxListSpan.kt +15 -0
  68. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputCodeBlockSpan.kt +14 -0
  69. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH1Span.kt +14 -0
  70. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH2Span.kt +14 -0
  71. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH3Span.kt +14 -0
  72. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH4Span.kt +14 -0
  73. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH5Span.kt +14 -0
  74. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH6Span.kt +14 -0
  75. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputImageSpan.kt +36 -0
  76. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputInlineCodeSpan.kt +14 -0
  77. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputItalicSpan.kt +14 -0
  78. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputLinkSpan.kt +15 -0
  79. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputMentionSpan.kt +18 -0
  80. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputOrderedListSpan.kt +21 -0
  81. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputStrikeThroughSpan.kt +14 -0
  82. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputUnderlineSpan.kt +14 -0
  83. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputUnorderedListSpan.kt +14 -0
  84. package/android/src/main/java/com/swmansion/enriched/{spans → textinput/spans}/EnrichedSpans.kt +39 -30
  85. package/android/src/main/java/com/swmansion/enriched/textinput/spans/interfaces/EnrichedInputSpan.kt +10 -0
  86. package/android/src/main/java/com/swmansion/enriched/{styles → textinput/styles}/HtmlStyle.kt +58 -43
  87. package/android/src/main/java/com/swmansion/enriched/{styles → textinput/styles}/InlineStyles.kt +4 -4
  88. package/android/src/main/java/com/swmansion/enriched/{styles → textinput/styles}/ListStyles.kt +77 -26
  89. package/android/src/main/java/com/swmansion/enriched/{styles → textinput/styles}/ParagraphStyles.kt +30 -25
  90. package/android/src/main/java/com/swmansion/enriched/{styles → textinput/styles}/ParametrizedStyles.kt +19 -19
  91. package/android/src/main/java/com/swmansion/enriched/{utils → textinput/utils}/EnrichedEditableFactory.kt +2 -2
  92. package/android/src/main/java/com/swmansion/enriched/{utils → textinput/utils}/EnrichedSelection.kt +15 -14
  93. package/android/src/main/java/com/swmansion/enriched/{utils → textinput/utils}/EnrichedSpanState.kt +15 -50
  94. package/android/src/main/java/com/swmansion/enriched/{utils → textinput/utils}/EnrichedSpannable.kt +3 -3
  95. package/android/src/main/java/com/swmansion/enriched/{utils → textinput/utils}/EnrichedSpannableStringBuilder.kt +2 -1
  96. package/android/src/main/java/com/swmansion/enriched/textinput/utils/RichContentReceiver.kt +127 -0
  97. package/android/src/main/java/com/swmansion/enriched/textinput/utils/Utils.kt +106 -0
  98. package/android/src/main/java/com/swmansion/enriched/{watchers → textinput/watchers}/EnrichedSpanWatcher.kt +10 -10
  99. package/android/src/main/java/com/swmansion/enriched/{watchers → textinput/watchers}/EnrichedTextWatcher.kt +3 -3
  100. package/android/src/main/new_arch/CMakeLists.txt +1 -1
  101. package/android/src/main/new_arch/ReactNativeEnrichedSpec.cpp +11 -0
  102. package/android/src/main/new_arch/ReactNativeEnrichedSpec.h +15 -0
  103. package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputMeasurementManager.h +1 -1
  104. package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputShadowNode.h +2 -2
  105. package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/conversions.h +1 -1
  106. package/ios/EnrichedTextInputView.h +1 -0
  107. package/ios/EnrichedTextInputView.mm +274 -55
  108. package/ios/config/InputConfig.h +10 -0
  109. package/ios/config/InputConfig.mm +119 -0
  110. package/ios/extensions/ImageExtension.h +35 -0
  111. package/ios/extensions/ImageExtension.mm +156 -0
  112. package/ios/extensions/LayoutManagerExtension.mm +115 -95
  113. package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ComponentDescriptors.cpp +1 -1
  114. package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ComponentDescriptors.h +1 -1
  115. package/{android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec → ios/generated/ReactNativeEnrichedSpec}/EventEmitters.cpp +31 -29
  116. package/{android/generated/jni/react/renderer/components/RNEnrichedTextInputViewSpec → ios/generated/ReactNativeEnrichedSpec}/EventEmitters.h +22 -25
  117. package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/Props.h +57 -0
  118. package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/RCTComponentViewHelpers.h +21 -0
  119. package/ios/inputParser/InputParser.mm +135 -8
  120. package/ios/inputTextView/InputTextView.mm +118 -0
  121. package/ios/interfaces/ImageAttachment.h +1 -0
  122. package/ios/interfaces/ImageAttachment.mm +43 -4
  123. package/ios/interfaces/StyleHeaders.h +13 -2
  124. package/ios/interfaces/StyleTypeEnum.h +1 -0
  125. package/ios/internals/EnrichedTextInputViewState.cpp +6 -6
  126. package/ios/styles/CheckboxListStyle.mm +321 -0
  127. package/ios/styles/H1Style.mm +3 -0
  128. package/ios/styles/H2Style.mm +3 -0
  129. package/ios/styles/H3Style.mm +3 -0
  130. package/ios/styles/H4Style.mm +3 -0
  131. package/ios/styles/H5Style.mm +3 -0
  132. package/ios/styles/H6Style.mm +3 -0
  133. package/ios/styles/HeadingStyleBase.mm +150 -78
  134. package/ios/utils/CheckboxHitTestUtils.h +10 -0
  135. package/ios/utils/CheckboxHitTestUtils.mm +123 -0
  136. package/ios/utils/ParagraphAttributesUtils.mm +83 -53
  137. package/ios/utils/TextBlockTapGestureRecognizer.h +17 -0
  138. package/ios/utils/TextBlockTapGestureRecognizer.mm +56 -0
  139. package/ios/utils/ZeroWidthSpaceUtils.mm +14 -3
  140. package/lib/module/EnrichedTextInput.js +36 -11
  141. package/lib/module/EnrichedTextInput.js.map +1 -1
  142. package/lib/module/{EnrichedTextInputNativeComponent.ts → spec/EnrichedTextInputNativeComponent.ts} +40 -9
  143. package/lib/module/types.js +4 -0
  144. package/lib/module/types.js.map +1 -0
  145. package/lib/module/utils/normalizeHtmlStyle.js +6 -0
  146. package/lib/module/utils/normalizeHtmlStyle.js.map +1 -1
  147. package/lib/module/utils/nullthrows.js +9 -0
  148. package/lib/module/utils/nullthrows.js.map +1 -0
  149. package/lib/typescript/src/EnrichedTextInput.d.ts +9 -49
  150. package/lib/typescript/src/EnrichedTextInput.d.ts.map +1 -1
  151. package/lib/typescript/src/index.d.ts +2 -1
  152. package/lib/typescript/src/index.d.ts.map +1 -1
  153. package/lib/typescript/src/{EnrichedTextInputNativeComponent.d.ts → spec/EnrichedTextInputNativeComponent.d.ts} +33 -8
  154. package/lib/typescript/src/spec/EnrichedTextInputNativeComponent.d.ts.map +1 -0
  155. package/lib/typescript/src/types.d.ts +58 -0
  156. package/lib/typescript/src/types.d.ts.map +1 -0
  157. package/lib/typescript/src/utils/normalizeHtmlStyle.d.ts +2 -2
  158. package/lib/typescript/src/utils/normalizeHtmlStyle.d.ts.map +1 -1
  159. package/lib/typescript/src/utils/nullthrows.d.ts +2 -0
  160. package/lib/typescript/src/utils/nullthrows.d.ts.map +1 -0
  161. package/lib/typescript/src/utils/regexParser.d.ts +1 -1
  162. package/lib/typescript/src/utils/regexParser.d.ts.map +1 -1
  163. package/package.json +4 -4
  164. package/src/EnrichedTextInput.tsx +49 -62
  165. package/src/index.tsx +3 -1
  166. package/src/{EnrichedTextInputNativeComponent.ts → spec/EnrichedTextInputNativeComponent.ts} +40 -9
  167. package/src/types.ts +59 -0
  168. package/src/utils/normalizeHtmlStyle.ts +8 -5
  169. package/src/utils/nullthrows.ts +7 -0
  170. package/src/utils/regexParser.ts +1 -1
  171. package/android/src/main/java/com/swmansion/enriched/events/OnChangeStateDeprecatedEvent.kt +0 -21
  172. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedBoldSpan.kt +0 -17
  173. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH1Span.kt +0 -24
  174. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH2Span.kt +0 -24
  175. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH3Span.kt +0 -24
  176. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH4Span.kt +0 -24
  177. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH5Span.kt +0 -24
  178. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedH6Span.kt +0 -24
  179. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedItalicSpan.kt +0 -16
  180. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedStrikeThroughSpan.kt +0 -15
  181. package/android/src/main/java/com/swmansion/enriched/spans/EnrichedUnderlineSpan.kt +0 -15
  182. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedInlineSpan.kt +0 -3
  183. package/android/src/main/java/com/swmansion/enriched/spans/interfaces/EnrichedSpan.kt +0 -9
  184. package/android/src/main/java/com/swmansion/enriched/utils/Utils.kt +0 -21
  185. package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.cpp +0 -22
  186. package/android/src/main/new_arch/RNEnrichedTextInputViewSpec.h +0 -26
  187. package/lib/typescript/src/EnrichedTextInputNativeComponent.d.ts.map +0 -1
  188. /package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/Props.cpp +0 -0
  189. /package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ShadowNodes.cpp +0 -0
  190. /package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ShadowNodes.h +0 -0
  191. /package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/States.cpp +0 -0
  192. /package/android/generated/jni/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/States.h +0 -0
  193. /package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputComponentDescriptor.h +0 -0
  194. /package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputMeasurementManager.cpp +0 -0
  195. /package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputShadowNode.cpp +0 -0
  196. /package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputState.cpp +0 -0
  197. /package/android/src/main/new_arch/react/renderer/components/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/EnrichedTextInputState.h +0 -0
  198. /package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/Props.cpp +0 -0
  199. /package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ShadowNodes.cpp +0 -0
  200. /package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/ShadowNodes.h +0 -0
  201. /package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/States.cpp +0 -0
  202. /package/ios/generated/{RNEnrichedTextInputViewSpec → ReactNativeEnrichedSpec}/States.h +0 -0
@@ -528,6 +528,57 @@ static inline folly::dynamic toDynamic(const EnrichedTextInputViewHtmlStyleUlStr
528
528
  }
529
529
  #endif
530
530
 
531
+ struct EnrichedTextInputViewHtmlStyleUlCheckboxStruct {
532
+ Float gapWidth{0.0};
533
+ Float boxSize{0.0};
534
+ Float marginLeft{0.0};
535
+ SharedColor boxColor{};
536
+
537
+ #ifdef RN_SERIALIZABLE_STATE
538
+ bool operator==(const EnrichedTextInputViewHtmlStyleUlCheckboxStruct&) const = default;
539
+
540
+ folly::dynamic toDynamic() const {
541
+ folly::dynamic result = folly::dynamic::object();
542
+ result["gapWidth"] = gapWidth;
543
+ result["boxSize"] = boxSize;
544
+ result["marginLeft"] = marginLeft;
545
+ result["boxColor"] = ::facebook::react::toDynamic(boxColor);
546
+ return result;
547
+ }
548
+ #endif
549
+ };
550
+
551
+ static inline void fromRawValue(const PropsParserContext& context, const RawValue &value, EnrichedTextInputViewHtmlStyleUlCheckboxStruct &result) {
552
+ auto map = (std::unordered_map<std::string, RawValue>)value;
553
+
554
+ auto tmp_gapWidth = map.find("gapWidth");
555
+ if (tmp_gapWidth != map.end()) {
556
+ fromRawValue(context, tmp_gapWidth->second, result.gapWidth);
557
+ }
558
+ auto tmp_boxSize = map.find("boxSize");
559
+ if (tmp_boxSize != map.end()) {
560
+ fromRawValue(context, tmp_boxSize->second, result.boxSize);
561
+ }
562
+ auto tmp_marginLeft = map.find("marginLeft");
563
+ if (tmp_marginLeft != map.end()) {
564
+ fromRawValue(context, tmp_marginLeft->second, result.marginLeft);
565
+ }
566
+ auto tmp_boxColor = map.find("boxColor");
567
+ if (tmp_boxColor != map.end()) {
568
+ fromRawValue(context, tmp_boxColor->second, result.boxColor);
569
+ }
570
+ }
571
+
572
+ static inline std::string toString(const EnrichedTextInputViewHtmlStyleUlCheckboxStruct &value) {
573
+ return "[Object EnrichedTextInputViewHtmlStyleUlCheckboxStruct]";
574
+ }
575
+
576
+ #ifdef RN_SERIALIZABLE_STATE
577
+ static inline folly::dynamic toDynamic(const EnrichedTextInputViewHtmlStyleUlCheckboxStruct &value) {
578
+ return value.toDynamic();
579
+ }
580
+ #endif
581
+
531
582
  struct EnrichedTextInputViewHtmlStyleStruct {
532
583
  EnrichedTextInputViewHtmlStyleH1Struct h1{};
533
584
  EnrichedTextInputViewHtmlStyleH2Struct h2{};
@@ -542,6 +593,7 @@ struct EnrichedTextInputViewHtmlStyleStruct {
542
593
  folly::dynamic mention{};
543
594
  EnrichedTextInputViewHtmlStyleOlStruct ol{};
544
595
  EnrichedTextInputViewHtmlStyleUlStruct ul{};
596
+ EnrichedTextInputViewHtmlStyleUlCheckboxStruct ulCheckbox{};
545
597
 
546
598
  #ifdef RN_SERIALIZABLE_STATE
547
599
  bool operator==(const EnrichedTextInputViewHtmlStyleStruct&) const = default;
@@ -561,6 +613,7 @@ struct EnrichedTextInputViewHtmlStyleStruct {
561
613
  result["mention"] = mention;
562
614
  result["ol"] = ::facebook::react::toDynamic(ol);
563
615
  result["ul"] = ::facebook::react::toDynamic(ul);
616
+ result["ulCheckbox"] = ::facebook::react::toDynamic(ulCheckbox);
564
617
  return result;
565
618
  }
566
619
  #endif
@@ -621,6 +674,10 @@ static inline void fromRawValue(const PropsParserContext& context, const RawValu
621
674
  if (tmp_ul != map.end()) {
622
675
  fromRawValue(context, tmp_ul->second, result.ul);
623
676
  }
677
+ auto tmp_ulCheckbox = map.find("ulCheckbox");
678
+ if (tmp_ulCheckbox != map.end()) {
679
+ fromRawValue(context, tmp_ulCheckbox->second, result.ulCheckbox);
680
+ }
624
681
  }
625
682
 
626
683
  static inline std::string toString(const EnrichedTextInputViewHtmlStyleStruct &value) {
@@ -33,6 +33,7 @@ NS_ASSUME_NONNULL_BEGIN
33
33
  - (void)toggleBlockQuote;
34
34
  - (void)toggleOrderedList;
35
35
  - (void)toggleUnorderedList;
36
+ - (void)toggleCheckboxList:(BOOL)checked;
36
37
  - (void)addLink:(NSInteger)start end:(NSInteger)end text:(NSString *)text url:(NSString *)url;
37
38
  - (void)addImage:(NSString *)uri width:(float)width height:(float)height;
38
39
  - (void)startMention:(NSString *)indicator;
@@ -331,6 +332,26 @@ if ([commandName isEqualToString:@"toggleUnorderedList"]) {
331
332
  return;
332
333
  }
333
334
 
335
+ if ([commandName isEqualToString:@"toggleCheckboxList"]) {
336
+ #if RCT_DEBUG
337
+ if ([args count] != 1) {
338
+ RCTLogError(@"%@ command %@ received %d arguments, expected %d.", @"EnrichedTextInputView", commandName, (int)[args count], 1);
339
+ return;
340
+ }
341
+ #endif
342
+
343
+ NSObject *arg0 = args[0];
344
+ #if RCT_DEBUG
345
+ if (!RCTValidateTypeOfViewCommandArgument(arg0, [NSNumber class], @"boolean", @"EnrichedTextInputView", commandName, @"1st")) {
346
+ return;
347
+ }
348
+ #endif
349
+ BOOL checked = [(NSNumber *)arg0 boolValue];
350
+
351
+ [componentView toggleCheckboxList:checked];
352
+ return;
353
+ }
354
+
334
355
  if ([commandName isEqualToString:@"addLink"]) {
335
356
  #if RCT_DEBUG
336
357
  if ([args count] != 4) {
@@ -33,6 +33,7 @@
33
33
  BOOL inOrderedList = NO;
34
34
  BOOL inBlockQuote = NO;
35
35
  BOOL inCodeBlock = NO;
36
+ BOOL inCheckboxList = NO;
36
37
  unichar lastCharacter = 0;
37
38
 
38
39
  for (int i = 0; i < text.length; i++) {
@@ -107,6 +108,21 @@
107
108
  [result appendString:@"\n</codeblock>\n<br>"];
108
109
  inCodeBlock = NO;
109
110
  }
111
+ } else if (inCheckboxList) {
112
+ CheckboxListStyle *cbLStyle = _input->stylesDict[@(CheckboxList)];
113
+ BOOL detected =
114
+ [cbLStyle detectStyle:NSMakeRange(currentRange.location, 0)];
115
+ if (detected) {
116
+ BOOL checked = [cbLStyle getCheckboxStateAt:currentRange.location];
117
+ if (checked) {
118
+ [result appendString:@"\n<li checked></li>"];
119
+ } else {
120
+ [result appendString:@"\n<li></li>"];
121
+ }
122
+ } else {
123
+ [result appendString:@"\n</ul>\n<br>"];
124
+ inCheckboxList = NO;
125
+ }
110
126
  } else {
111
127
  [result appendString:@"\n<br>"];
112
128
  }
@@ -145,7 +161,9 @@
145
161
  [previousActiveStyles
146
162
  containsObject:@([BlockQuoteStyle getStyleType])] ||
147
163
  [previousActiveStyles
148
- containsObject:@([CodeBlockStyle getStyleType])]) {
164
+ containsObject:@([CodeBlockStyle getStyleType])] ||
165
+ [previousActiveStyles
166
+ containsObject:@([CheckboxListStyle getStyleType])]) {
149
167
  // do nothing, proper closing paragraph tags have been already
150
168
  // appended
151
169
  } else {
@@ -191,6 +209,13 @@
191
209
  inCodeBlock = NO;
192
210
  [result appendString:@"\n</codeblock>"];
193
211
  }
212
+ // handle ending checkbox list
213
+ if (inCheckboxList &&
214
+ ![currentActiveStyles
215
+ containsObject:@([CheckboxListStyle getStyleType])]) {
216
+ inCheckboxList = NO;
217
+ [result appendString:@"\n</ul>"];
218
+ }
194
219
 
195
220
  // handle starting unordered list
196
221
  if (!inUnorderedList &&
@@ -220,6 +245,13 @@
220
245
  inCodeBlock = YES;
221
246
  [result appendString:@"\n<codeblock>"];
222
247
  }
248
+ // handle starting checkbox list
249
+ if (!inCheckboxList &&
250
+ [currentActiveStyles
251
+ containsObject:@([CheckboxListStyle getStyleType])]) {
252
+ inCheckboxList = YES;
253
+ [result appendString:@"\n<ul data-type=\"checkbox\">"];
254
+ }
223
255
 
224
256
  // don't add the <p> tag if some paragraph styles are present
225
257
  if ([currentActiveStyles
@@ -235,7 +267,9 @@
235
267
  [currentActiveStyles
236
268
  containsObject:@([BlockQuoteStyle getStyleType])] ||
237
269
  [currentActiveStyles
238
- containsObject:@([CodeBlockStyle getStyleType])]) {
270
+ containsObject:@([CodeBlockStyle getStyleType])] ||
271
+ [currentActiveStyles
272
+ containsObject:@([CheckboxListStyle getStyleType])]) {
239
273
  [result appendString:@"\n"];
240
274
  } else {
241
275
  [result appendString:@"\n<p>"];
@@ -381,6 +415,9 @@
381
415
  } else if ([previousActiveStyles
382
416
  containsObject:@([CodeBlockStyle getStyleType])]) {
383
417
  [result appendString:@"\n</codeblock>"];
418
+ } else if ([previousActiveStyles
419
+ containsObject:@([CheckboxListStyle getStyleType])]) {
420
+ [result appendString:@"\n</ul>"];
384
421
  } else if ([previousActiveStyles
385
422
  containsObject:@([H1Style getStyleType])] ||
386
423
  [previousActiveStyles
@@ -415,6 +452,10 @@
415
452
  inCodeBlock = NO;
416
453
  [result appendString:@"\n</codeblock>"];
417
454
  }
455
+ if (inCheckboxList) {
456
+ inCheckboxList = NO;
457
+ [result appendString:@"\n</ul>"];
458
+ }
418
459
  }
419
460
 
420
461
  [result appendString:@"\n</html>"];
@@ -536,6 +577,20 @@
536
577
  } else if ([style isEqualToNumber:@([UnorderedListStyle getStyleType])] ||
537
578
  [style isEqualToNumber:@([OrderedListStyle getStyleType])]) {
538
579
  return @"li";
580
+ } else if ([style isEqualToNumber:@([CheckboxListStyle getStyleType])]) {
581
+ if (openingTag) {
582
+ CheckboxListStyle *checkboxListStyleClass =
583
+ (CheckboxListStyle *)
584
+ _input->stylesDict[@([CheckboxListStyle getStyleType])];
585
+ BOOL checked = [checkboxListStyleClass getCheckboxStateAt:location];
586
+
587
+ if (checked) {
588
+ return @"li checked";
589
+ }
590
+ return @"li";
591
+ } else {
592
+ return @"li";
593
+ }
539
594
  } else if ([style isEqualToNumber:@([BlockQuoteStyle getStyleType])] ||
540
595
  [style isEqualToNumber:@([CodeBlockStyle getStyleType])]) {
541
596
  // blockquotes and codeblock use <p> tags the same way lists use <li>
@@ -634,6 +689,28 @@
634
689
  [((ImageStyle *)baseStyle) addImageAtRange:styleRange
635
690
  imageData:imgData
636
691
  withSelection:NO];
692
+ } else if ([styleType
693
+ isEqualToNumber:@([CheckboxListStyle getStyleType])]) {
694
+ NSDictionary *checkboxStates = (NSDictionary *)stylePair.styleValue;
695
+ CheckboxListStyle *cbLStyle = (CheckboxListStyle *)baseStyle;
696
+
697
+ // First apply the checkbox list style to the entire range with
698
+ // unchecked value
699
+ BOOL shouldAddTypingAttr =
700
+ styleRange.location + styleRange.length == plainTextLength;
701
+ [cbLStyle addAttributes:styleRange withTypingAttr:shouldAddTypingAttr];
702
+
703
+ if (!checkboxStates && checkboxStates.count == 0) {
704
+ continue;
705
+ }
706
+ // Then toggle checked checkboxes
707
+ for (NSNumber *key in checkboxStates) {
708
+ NSUInteger checkboxPosition = offset + [key unsignedIntegerValue];
709
+ BOOL isChecked = [checkboxStates[key] boolValue];
710
+ if (isChecked) {
711
+ [cbLStyle toggleCheckedAt:checkboxPosition];
712
+ }
713
+ }
637
714
  } else {
638
715
  BOOL shouldAddTypingAttr =
639
716
  styleRange.location + styleRange.length == plainTextLength;
@@ -752,6 +829,10 @@
752
829
  inString:fixedHtml
753
830
  leading:YES
754
831
  trailing:NO];
832
+ fixedHtml = [self stringByAddingNewlinesToTag:@"<li checked>"
833
+ inString:fixedHtml
834
+ leading:YES
835
+ trailing:NO];
755
836
  fixedHtml = [self stringByAddingNewlinesToTag:@"<h1>"
756
837
  inString:fixedHtml
757
838
  leading:YES
@@ -983,6 +1064,8 @@
983
1064
  NSMutableString *plainText = [[NSMutableString alloc] initWithString:@""];
984
1065
  NSMutableDictionary *ongoingTags = [[NSMutableDictionary alloc] init];
985
1066
  NSMutableArray *initiallyProcessedTags = [[NSMutableArray alloc] init];
1067
+ NSMutableDictionary *checkboxStates = [[NSMutableDictionary alloc] init];
1068
+ BOOL insideCheckboxList = NO;
986
1069
  _precedingImageCount = 0;
987
1070
  BOOL insideTag = NO;
988
1071
  BOOL gettingTagName = NO;
@@ -1023,9 +1106,14 @@
1023
1106
  }
1024
1107
 
1025
1108
  if ([currentTagName isEqualToString:@"p"] ||
1026
- [currentTagName isEqualToString:@"br"] ||
1027
- [currentTagName isEqualToString:@"li"]) {
1109
+ [currentTagName isEqualToString:@"br"]) {
1028
1110
  // do nothing, we don't include these tags in styles
1111
+ } else if ([currentTagName isEqualToString:@"li"]) {
1112
+ // Only track checkbox state if we're inside a checkbox list
1113
+ if (insideCheckboxList && !closingTag) {
1114
+ BOOL isChecked = [currentTagParams containsString:@"checked"];
1115
+ checkboxStates[@(plainText.length)] = @(isChecked);
1116
+ }
1029
1117
  } else if (!closingTag) {
1030
1118
  // we finish opening tag - get its location and optionally params and
1031
1119
  // put them under tag name key in ongoingTags
@@ -1036,6 +1124,12 @@
1036
1124
  }
1037
1125
  ongoingTags[currentTagName] = tagArr;
1038
1126
 
1127
+ // Check if this is a checkbox list
1128
+ if ([currentTagName isEqualToString:@"ul"] &&
1129
+ [self isUlCheckboxList:currentTagParams]) {
1130
+ insideCheckboxList = YES;
1131
+ }
1132
+
1039
1133
  // skip one newline after opening tags that are in separate lines
1040
1134
  // intentionally
1041
1135
  if ([currentTagName isEqualToString:@"ul"] ||
@@ -1055,6 +1149,12 @@
1055
1149
  // we finish closing tags - pack tag name, tag range and optionally tag
1056
1150
  // params into an entry that goes inside initiallyProcessedTags
1057
1151
 
1152
+ // Check if we're closing a checkbox list by looking at the params
1153
+ if ([currentTagName isEqualToString:@"ul"] &&
1154
+ [self isUlCheckboxList:currentTagParams]) {
1155
+ insideCheckboxList = NO;
1156
+ }
1157
+
1058
1158
  // skip one newline that was added before some closing tags that are in
1059
1159
  // separate lines
1060
1160
  if ([currentTagName isEqualToString:@"ul"] ||
@@ -1215,7 +1315,7 @@
1215
1315
  [styleArr addObject:@([MentionStyle getStyleType])];
1216
1316
  // extract html expression into dict using some regex
1217
1317
  NSMutableDictionary *paramsDict = [[NSMutableDictionary alloc] init];
1218
- NSString *pattern = @"(\\w+)=\"([^\"]*)\"";
1318
+ NSString *pattern = @"(\\w+)=(['\"])(.*?)\\2";
1219
1319
  NSRegularExpression *regex =
1220
1320
  [NSRegularExpression regularExpressionWithPattern:pattern
1221
1321
  options:0
@@ -1227,11 +1327,11 @@
1227
1327
  usingBlock:^(NSTextCheckingResult *_Nullable result,
1228
1328
  NSMatchingFlags flags,
1229
1329
  BOOL *_Nonnull stop) {
1230
- if (result.numberOfRanges == 3) {
1330
+ if (result.numberOfRanges == 4) {
1231
1331
  NSString *key = [params
1232
1332
  substringWithRange:[result rangeAtIndex:1]];
1233
1333
  NSString *value = [params
1234
- substringWithRange:[result rangeAtIndex:2]];
1334
+ substringWithRange:[result rangeAtIndex:3]];
1235
1335
  paramsDict[key] = value;
1236
1336
  }
1237
1337
  }];
@@ -1267,7 +1367,14 @@
1267
1367
  [styleArr addObject:@([H6Style getStyleType])];
1268
1368
  }
1269
1369
  } else if ([tagName isEqualToString:@"ul"]) {
1270
- [styleArr addObject:@([UnorderedListStyle getStyleType])];
1370
+ if ([self isUlCheckboxList:params]) {
1371
+ [styleArr addObject:@([CheckboxListStyle getStyleType])];
1372
+ stylePair.styleValue =
1373
+ [self prepareCheckboxListStyleValue:tagRangeValue
1374
+ checkboxStates:checkboxStates];
1375
+ } else {
1376
+ [styleArr addObject:@([UnorderedListStyle getStyleType])];
1377
+ }
1271
1378
  } else if ([tagName isEqualToString:@"ol"]) {
1272
1379
  [styleArr addObject:@([OrderedListStyle getStyleType])];
1273
1380
  } else if ([tagName isEqualToString:@"blockquote"]) {
@@ -1288,4 +1395,24 @@
1288
1395
  return @[ plainText, processedStyles ];
1289
1396
  }
1290
1397
 
1398
+ - (BOOL)isUlCheckboxList:(NSString *)params {
1399
+ return ([params containsString:@"data-type=\"checkbox\""] ||
1400
+ [params containsString:@"data-type='checkbox'"]);
1401
+ }
1402
+
1403
+ - (NSDictionary *)prepareCheckboxListStyleValue:(NSValue *)rangeValue
1404
+ checkboxStates:(NSDictionary *)checkboxStates {
1405
+ NSRange range = [rangeValue rangeValue];
1406
+ NSMutableDictionary *statesInRange = [[NSMutableDictionary alloc] init];
1407
+
1408
+ for (NSNumber *key in checkboxStates) {
1409
+ NSUInteger pos = [key unsignedIntegerValue];
1410
+ if (pos >= range.location && pos < range.location + range.length) {
1411
+ [statesInRange setObject:checkboxStates[key] forKey:key];
1412
+ }
1413
+ }
1414
+
1415
+ return statesInRange;
1416
+ }
1417
+
1291
1418
  @end
@@ -55,6 +55,67 @@
55
55
  NSArray<NSString *> *pasteboardTypes = pasteboard.pasteboardTypes;
56
56
  NSRange currentRange = typedInput->textView.selectedRange;
57
57
 
58
+ // Check the pasteboard for supported image formats. If found, save them to
59
+ // temporary storage then emit the 'onPasteImages' event and stop processing
60
+ // further (ignoring any HTML/Text).
61
+ NSMutableArray<NSDictionary *> *foundImages = [NSMutableArray new];
62
+
63
+ for (NSDictionary<NSString *, id> *item in pasteboard.items) {
64
+ NSData *imageData = nil;
65
+ BOOL added = NO;
66
+ NSString *ext = nil;
67
+ NSString *mimeType = nil;
68
+
69
+ for (int j = 0; j < item.allKeys.count; j++) {
70
+ if (added) {
71
+ break;
72
+ }
73
+
74
+ NSString *type = item.allKeys[j];
75
+ if ([type isEqual:UTTypeJPEG.identifier] ||
76
+ [type isEqual:UTTypePNG.identifier] ||
77
+ [type isEqual:UTTypeWebP.identifier] ||
78
+ [type isEqual:UTTypeHEIC.identifier] ||
79
+ [type isEqual:UTTypeTIFF.identifier]) {
80
+ imageData = [self getDataForImageItem:item[type] type:type];
81
+ } else if ([type isEqual:UTTypeGIF.identifier]) {
82
+ // gifs
83
+ imageData = [pasteboard dataForPasteboardType:type];
84
+ }
85
+ if (!imageData) {
86
+ continue;
87
+ }
88
+
89
+ NSDictionary *info = [self detectImageFormat:type];
90
+ if (!info) {
91
+ continue;
92
+ }
93
+ ext = info[@"ext"];
94
+ mimeType = info[@"mime"];
95
+
96
+ UIImage *imageInfo = [UIImage imageWithData:imageData];
97
+
98
+ if (imageInfo) {
99
+ NSString *path = [self saveToTempFile:imageData extension:ext];
100
+
101
+ if (path) {
102
+ added = YES;
103
+ [foundImages addObject:@{
104
+ @"uri" : path,
105
+ @"type" : mimeType,
106
+ @"width" : @(imageInfo.size.width),
107
+ @"height" : @(imageInfo.size.height)
108
+ }];
109
+ }
110
+ }
111
+ }
112
+ }
113
+
114
+ if (foundImages.count > 0) {
115
+ [typedInput emitOnPasteImagesEvent:foundImages];
116
+ return;
117
+ }
118
+
58
119
  if ([pasteboardTypes containsObject:UTTypeHTML.identifier]) {
59
120
  // we try processing the html contents
60
121
 
@@ -94,6 +155,52 @@
94
155
  [typedInput anyTextMayHaveBeenModified];
95
156
  }
96
157
 
158
+ - (NSDictionary *)detectImageFormat:(NSString *)type {
159
+ if ([type isEqual:UTTypeJPEG.identifier]) {
160
+ return @{@"ext" : @"jpg", @"mime" : @"image/jpeg"};
161
+ } else if ([type isEqual:UTTypePNG.identifier]) {
162
+ return @{@"ext" : @"png", @"mime" : @"image/png"};
163
+ } else if ([type isEqual:UTTypeGIF.identifier]) {
164
+ return @{@"ext" : @"gif", @"mime" : @"image/gif"};
165
+ } else if ([type isEqual:UTTypeHEIC.identifier]) {
166
+ return @{@"ext" : @"heic", @"mime" : @"image/heic"};
167
+ } else if ([type isEqual:UTTypeWebP.identifier]) {
168
+ return @{@"ext" : @"webp", @"mime" : @"image/webp"};
169
+ } else if ([type isEqual:UTTypeTIFF.identifier]) {
170
+ return @{@"ext" : @"tiff", @"mime" : @"image/tiff"};
171
+ } else {
172
+ return nil;
173
+ }
174
+ }
175
+
176
+ - (NSData *)getDataForImageItem:(NSData *)imageData type:(NSString *)type {
177
+ UIImage *image = (UIImage *)imageData;
178
+
179
+ if ([type isEqual:UTTypePNG.identifier]) {
180
+ return UIImagePNGRepresentation(image);
181
+ } else if ([type isEqual:UTTypeHEIC.identifier]) {
182
+ return UIImageHEICRepresentation(image);
183
+ } else {
184
+ return UIImageJPEGRepresentation(image, 1.0);
185
+ }
186
+ }
187
+
188
+ - (NSString *)saveToTempFile:(NSData *)data extension:(NSString *)ext {
189
+ if (!data)
190
+ return nil;
191
+ NSString *fileName =
192
+ [NSString stringWithFormat:@"%@.%@", [NSUUID UUID].UUIDString, ext];
193
+
194
+ NSString *filePath =
195
+ [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];
196
+
197
+ if ([data writeToFile:filePath atomically:YES]) {
198
+ return [NSURL fileURLWithPath:filePath].absoluteString;
199
+ }
200
+
201
+ return nil;
202
+ }
203
+
97
204
  - (void)tryHandlingPlainTextItemsIn:(UIPasteboard *)pasteboard
98
205
  range:(NSRange)range
99
206
  input:(EnrichedTextInputView *)input {
@@ -153,4 +260,15 @@
153
260
  [typedInput anyTextMayHaveBeenModified];
154
261
  }
155
262
 
263
+ - (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
264
+ if (action == @selector(paste:)) {
265
+ UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
266
+ // Enable Paste if clipboard has Text OR Images
267
+ if (pasteboard.hasStrings || pasteboard.hasImages) {
268
+ return YES;
269
+ }
270
+ }
271
+ return [super canPerformAction:action withSender:sender];
272
+ }
273
+
156
274
  @end
@@ -4,6 +4,7 @@
4
4
  @interface ImageAttachment : MediaAttachment
5
5
 
6
6
  @property(nonatomic, strong) ImageData *imageData;
7
+ @property(nonatomic, strong) UIImage *storedAnimatedImage;
7
8
 
8
9
  - (instancetype)initWithImageData:(ImageData *)data;
9
10
 
@@ -1,4 +1,5 @@
1
1
  #import "ImageAttachment.h"
2
+ #import "ImageExtension.h"
2
3
 
3
4
  @implementation ImageAttachment
4
5
 
@@ -8,26 +9,64 @@
8
9
  return nil;
9
10
 
10
11
  _imageData = data;
12
+
13
+ // Assign an empty image to reserve layout space within the text system.
14
+ // The actual image is not drawn here; it is rendered and overlaid by a
15
+ // separate ImageView.
11
16
  self.image = [UIImage new];
12
17
 
13
18
  [self loadAsync];
14
19
  return self;
15
20
  }
16
21
 
22
+ - (CGRect)attachmentBoundsForTextContainer:(NSTextContainer *)textContainer
23
+ proposedLineFragment:(CGRect)lineFrag
24
+ glyphPosition:(CGPoint)position
25
+ characterIndex:(NSUInteger)charIndex {
26
+ CGRect baseBounds = self.bounds;
27
+
28
+ if (!textContainer.layoutManager.textStorage ||
29
+ charIndex >= textContainer.layoutManager.textStorage.length) {
30
+ return baseBounds;
31
+ }
32
+
33
+ UIFont *font =
34
+ [textContainer.layoutManager.textStorage attribute:NSFontAttributeName
35
+ atIndex:charIndex
36
+ effectiveRange:NULL];
37
+ if (!font) {
38
+ return baseBounds;
39
+ }
40
+
41
+ // Extend the layout bounds below the baseline by the font's descender.
42
+ // Without this, a line containing only the attachment has no descender space
43
+ // below the baseline, but adding a text character introduces it — causing
44
+ // the line height to jump. By reserving descender space upfront the line
45
+ // height stays consistent regardless of whether text is present.
46
+ CGFloat descender = font.descender;
47
+ return CGRectMake(baseBounds.origin.x, descender, baseBounds.size.width,
48
+ baseBounds.size.height - descender);
49
+ }
50
+
17
51
  - (void)loadAsync {
18
52
  NSURL *url = [NSURL URLWithString:self.uri];
19
53
  if (!url) {
20
- self.image = [UIImage systemImageNamed:@"file"];
54
+ self.storedAnimatedImage = [UIImage systemImageNamed:@"photo"];
21
55
  return;
22
56
  }
23
57
 
24
58
  dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
25
59
  NSData *bytes = [NSData dataWithContentsOfURL:url];
26
- UIImage *img = bytes ? [UIImage imageWithData:bytes]
27
- : [UIImage systemImageNamed:@"file"];
60
+
61
+ // We pass all image data (including static formats like PNG or JPEG)
62
+ // through the GIF parser. It safely acts as a universal parser, returning
63
+ // a single-frame UIImage for static formats and an animated UIImage for
64
+ // GIFs.
65
+ UIImage *img = bytes ? [UIImage animatedImageWithAnimatedGIFData:bytes]
66
+ : [UIImage systemImageNamed:@"photo"];
28
67
 
29
68
  dispatch_async(dispatch_get_main_queue(), ^{
30
- self.image = img;
69
+ self.storedAnimatedImage = img;
31
70
  [self notifyUpdate];
32
71
  });
33
72
  });
@@ -55,10 +55,10 @@
55
55
  id input;
56
56
  }
57
57
  - (CGFloat)getHeadingFontSize;
58
+ - (NSString *)getHeadingLevelString;
58
59
  - (BOOL)isHeadingBold;
59
60
  - (BOOL)handleNewlinesInRange:(NSRange)range replacementText:(NSString *)text;
60
- - (void)handleImproperHeadings;
61
- @property(nonatomic, assign) CGFloat lastAppliedFontSize;
61
+ - (BOOL)handleBackspaceInRange:(NSRange)range replacementText:(NSString *)text;
62
62
  @end
63
63
 
64
64
  @interface H1Style : HeadingStyleBase
@@ -91,6 +91,17 @@
91
91
  replacementText:(NSString *)text;
92
92
  @end
93
93
 
94
+ @interface CheckboxListStyle : NSObject <BaseStyleProtocol>
95
+ - (void)applyStyleWithCheckedValue:(BOOL)checked inRange:(NSRange)range;
96
+ - (BOOL)handleBackspaceInRange:(NSRange)range replacementText:(NSString *)text;
97
+ - (BOOL)getCheckboxStateAt:(NSUInteger)location;
98
+ - (void)toggleCheckedAt:(NSUInteger)location;
99
+ - (BOOL)handleNewlinesInRange:(NSRange)range replacementText:(NSString *)text;
100
+ - (void)addAttributesWithCheckedValue:(BOOL)checked
101
+ inRange:(NSRange)range
102
+ withTypingAttr:(BOOL)withTypingAttr;
103
+ @end
104
+
94
105
  @interface BlockQuoteStyle : NSObject <BaseStyleProtocol>
95
106
  - (BOOL)handleBackspaceInRange:(NSRange)range replacementText:(NSString *)text;
96
107
  - (void)manageBlockquoteColor;
@@ -7,6 +7,7 @@ typedef NS_ENUM(NSInteger, StyleType) {
7
7
  CodeBlock,
8
8
  UnorderedList,
9
9
  OrderedList,
10
+ CheckboxList,
10
11
  H1,
11
12
  H2,
12
13
  H3,
@@ -1,10 +1,10 @@
1
1
  #include "EnrichedTextInputViewState.h"
2
2
 
3
3
  namespace facebook::react {
4
- int EnrichedTextInputViewState::getForceHeightRecalculationCounter() const {
5
- return forceHeightRecalculationCounter_;
6
- }
7
- std::shared_ptr<void> EnrichedTextInputViewState::getComponentViewRef() const {
8
- return componentViewRef_;
9
- }
4
+ int EnrichedTextInputViewState::getForceHeightRecalculationCounter() const {
5
+ return forceHeightRecalculationCounter_;
6
+ }
7
+ std::shared_ptr<void> EnrichedTextInputViewState::getComponentViewRef() const {
8
+ return componentViewRef_;
9
+ }
10
10
  } // namespace facebook::react