react-native-enriched-html 0.0.0 → 1.1.0-nightly-20260617-3dfd09072

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (666) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +402 -0
  3. package/ReactNativeEnrichedHtml.podspec +31 -0
  4. package/android/build.gradle +106 -0
  5. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerDelegate.java +203 -0
  6. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextInputViewManagerInterface.java +74 -0
  7. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextViewManagerDelegate.java +70 -0
  8. package/android/generated/java/com/facebook/react/viewmanagers/EnrichedTextViewManagerInterface.java +31 -0
  9. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/ComponentDescriptors.cpp +22 -0
  10. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/ComponentDescriptors.h +24 -0
  11. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/EventEmitters.cpp +456 -0
  12. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/EventEmitters.h +410 -0
  13. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/Props.cpp +272 -0
  14. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/Props.h +1595 -0
  15. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/ShadowNodes.cpp +17 -0
  16. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/ShadowNodes.h +23 -0
  17. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/States.cpp +16 -0
  18. package/android/generated/jni/react/renderer/components/ReactNativeEnrichedSpec/States.h +20 -0
  19. package/android/gradle.properties +5 -0
  20. package/android/lint.gradle +70 -0
  21. package/android/src/main/AndroidManifest.xml +3 -0
  22. package/android/src/main/AndroidManifestNew.xml +2 -0
  23. package/android/src/main/java/com/swmansion/enriched/ReactNativeEnrichedPackage.kt +22 -0
  24. package/android/src/main/java/com/swmansion/enriched/common/AllowFontScaling.kt +36 -0
  25. package/android/src/main/java/com/swmansion/enriched/common/AsyncDrawable.kt +126 -0
  26. package/android/src/main/java/com/swmansion/enriched/common/CheckboxDrawable.kt +81 -0
  27. package/android/src/main/java/com/swmansion/enriched/common/EnrichedConstants.kt +16 -0
  28. package/android/src/main/java/com/swmansion/enriched/common/EnrichedStyle.kt +57 -0
  29. package/android/src/main/java/com/swmansion/enriched/common/ForceRedrawSpan.kt +14 -0
  30. package/android/src/main/java/com/swmansion/enriched/common/GumboNormalizer.kt +5 -0
  31. package/android/src/main/java/com/swmansion/enriched/common/MentionStyle.kt +9 -0
  32. package/android/src/main/java/com/swmansion/enriched/common/ResourceManager.kt +26 -0
  33. package/android/src/main/java/com/swmansion/enriched/common/parser/EnrichedParser.java +1034 -0
  34. package/android/src/main/java/com/swmansion/enriched/common/parser/EnrichedSpanFactory.kt +82 -0
  35. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedAlignmentSpan.kt +19 -0
  36. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedBlockQuoteSpan.kt +53 -0
  37. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedBoldSpan.kt +12 -0
  38. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedCheckboxListSpan.kt +92 -0
  39. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedCodeBlockSpan.kt +81 -0
  40. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH1Span.kt +20 -0
  41. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH2Span.kt +20 -0
  42. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH3Span.kt +20 -0
  43. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH4Span.kt +21 -0
  44. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH5Span.kt +20 -0
  45. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedH6Span.kt +20 -0
  46. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedImageSpan.kt +185 -0
  47. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedInlineCodeSpan.kt +24 -0
  48. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedItalicSpan.kt +12 -0
  49. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedLinkSpan.kt +29 -0
  50. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedMentionSpan.kt +35 -0
  51. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedOrderedListSpan.kt +79 -0
  52. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedStrikeThroughSpan.kt +11 -0
  53. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedUnderlineSpan.kt +11 -0
  54. package/android/src/main/java/com/swmansion/enriched/common/spans/EnrichedUnorderedListSpan.kt +62 -0
  55. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedBlockSpan.kt +5 -0
  56. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedHeadingSpan.kt +3 -0
  57. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedInlineSpan.kt +3 -0
  58. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedParagraphSpan.kt +5 -0
  59. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedSpan.kt +3 -0
  60. package/android/src/main/java/com/swmansion/enriched/common/spans/interfaces/EnrichedZeroWidthSpaceSpan.kt +4 -0
  61. package/android/src/main/java/com/swmansion/enriched/text/EnrichedTextMovementMethod.kt +75 -0
  62. package/android/src/main/java/com/swmansion/enriched/text/EnrichedTextSpanFactory.kt +83 -0
  63. package/android/src/main/java/com/swmansion/enriched/text/EnrichedTextStyle.kt +202 -0
  64. package/android/src/main/java/com/swmansion/enriched/text/EnrichedTextView.kt +361 -0
  65. package/android/src/main/java/com/swmansion/enriched/text/EnrichedTextViewManager.kt +157 -0
  66. package/android/src/main/java/com/swmansion/enriched/text/MeasurementStore.kt +170 -0
  67. package/android/src/main/java/com/swmansion/enriched/text/events/OnLinkPressEvent.kt +23 -0
  68. package/android/src/main/java/com/swmansion/enriched/text/events/OnMentionPressEvent.kt +32 -0
  69. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextAlignmentSpan.kt +14 -0
  70. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextBlockQuoteSpan.kt +14 -0
  71. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextBoldSpan.kt +14 -0
  72. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextCheckboxListSpan.kt +15 -0
  73. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextCodeBlockSpan.kt +14 -0
  74. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextH1Span.kt +14 -0
  75. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextH2Span.kt +14 -0
  76. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextH3Span.kt +15 -0
  77. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextH4Span.kt +15 -0
  78. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextH5Span.kt +14 -0
  79. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextH6Span.kt +14 -0
  80. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextImageSpan.kt +57 -0
  81. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextInlineCodeSpan.kt +14 -0
  82. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextItalicSpan.kt +14 -0
  83. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextLinkSpan.kt +41 -0
  84. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextMentionSpan.kt +63 -0
  85. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextOrderedListSpan.kt +16 -0
  86. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextStrikeThroughSpan.kt +15 -0
  87. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextUnderlineSpan.kt +15 -0
  88. package/android/src/main/java/com/swmansion/enriched/text/spans/EnrichedTextUnorderedListSpan.kt +15 -0
  89. package/android/src/main/java/com/swmansion/enriched/text/spans/interfaces/EnrichedTextClickableSpan.kt +9 -0
  90. package/android/src/main/java/com/swmansion/enriched/text/spans/interfaces/EnrichedTextSpan.kt +10 -0
  91. package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputConnectionWrapper.kt +140 -0
  92. package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputSpannableFactory.kt +85 -0
  93. package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputView.kt +1141 -0
  94. package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputViewLayoutManager.kt +27 -0
  95. package/android/src/main/java/com/swmansion/enriched/textinput/EnrichedTextInputViewManager.kt +500 -0
  96. package/android/src/main/java/com/swmansion/enriched/textinput/MeasurementStore.kt +230 -0
  97. package/android/src/main/java/com/swmansion/enriched/textinput/events/MentionHandler.kt +55 -0
  98. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnChangeHtmlEvent.kt +27 -0
  99. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnChangeSelectionEvent.kt +30 -0
  100. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnChangeStateEvent.kt +21 -0
  101. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnChangeTextEvent.kt +30 -0
  102. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnContextMenuItemPressEvent.kt +35 -0
  103. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnInputBlurEvent.kt +25 -0
  104. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnInputFocusEvent.kt +25 -0
  105. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnInputKeyPressEvent.kt +27 -0
  106. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnLinkDetectedEvent.kt +32 -0
  107. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnMentionDetectedEvent.kt +30 -0
  108. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnMentionEvent.kt +34 -0
  109. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnPasteImagesEvent.kt +47 -0
  110. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnRequestHtmlResultEvent.kt +32 -0
  111. package/android/src/main/java/com/swmansion/enriched/textinput/events/OnSubmitEditingEvent.kt +29 -0
  112. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputAlignmentSpan.kt +14 -0
  113. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputBlockQuoteSpan.kt +14 -0
  114. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputBoldSpan.kt +14 -0
  115. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputCheckboxListSpan.kt +15 -0
  116. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputCodeBlockSpan.kt +14 -0
  117. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH1Span.kt +14 -0
  118. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH2Span.kt +14 -0
  119. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH3Span.kt +14 -0
  120. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH4Span.kt +14 -0
  121. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH5Span.kt +14 -0
  122. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputH6Span.kt +14 -0
  123. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputImageSpan.kt +36 -0
  124. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputInlineCodeSpan.kt +14 -0
  125. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputItalicSpan.kt +14 -0
  126. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputLinkSpan.kt +16 -0
  127. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputMentionSpan.kt +18 -0
  128. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputOrderedListSpan.kt +21 -0
  129. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputStrikeThroughSpan.kt +14 -0
  130. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputUnderlineSpan.kt +14 -0
  131. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedInputUnorderedListSpan.kt +14 -0
  132. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedLineHeightSpan.kt +45 -0
  133. package/android/src/main/java/com/swmansion/enriched/textinput/spans/EnrichedSpans.kt +240 -0
  134. package/android/src/main/java/com/swmansion/enriched/textinput/spans/interfaces/EnrichedInputSpan.kt +10 -0
  135. package/android/src/main/java/com/swmansion/enriched/textinput/styles/AlignmentStyles.kt +367 -0
  136. package/android/src/main/java/com/swmansion/enriched/textinput/styles/HtmlStyle.kt +371 -0
  137. package/android/src/main/java/com/swmansion/enriched/textinput/styles/InlineStyles.kt +232 -0
  138. package/android/src/main/java/com/swmansion/enriched/textinput/styles/ListStyles.kt +260 -0
  139. package/android/src/main/java/com/swmansion/enriched/textinput/styles/ParagraphStyles.kt +439 -0
  140. package/android/src/main/java/com/swmansion/enriched/textinput/styles/ParametrizedStyles.kt +408 -0
  141. package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedEditableFactory.kt +17 -0
  142. package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSelection.kt +340 -0
  143. package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpanState.kt +318 -0
  144. package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpannable.kt +156 -0
  145. package/android/src/main/java/com/swmansion/enriched/textinput/utils/EnrichedSpannableStringBuilder.kt +59 -0
  146. package/android/src/main/java/com/swmansion/enriched/textinput/utils/RichContentReceiver.kt +127 -0
  147. package/android/src/main/java/com/swmansion/enriched/textinput/utils/ShortcutsHandler.kt +150 -0
  148. package/android/src/main/java/com/swmansion/enriched/textinput/utils/StyleUtils.kt +51 -0
  149. package/android/src/main/java/com/swmansion/enriched/textinput/utils/Utils.kt +106 -0
  150. package/android/src/main/java/com/swmansion/enriched/textinput/watchers/EnrichedSpanWatcher.kt +109 -0
  151. package/android/src/main/java/com/swmansion/enriched/textinput/watchers/EnrichedTextWatcher.kt +106 -0
  152. package/android/src/main/new_arch/CMakeLists.txt +62 -0
  153. package/android/src/main/new_arch/GumboNormalizerJni.cpp +14 -0
  154. package/android/src/main/new_arch/ReactNativeEnrichedSpec.cpp +11 -0
  155. package/android/src/main/new_arch/ReactNativeEnrichedSpec.h +16 -0
  156. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextComponentDescriptor.h +32 -0
  157. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputComponentDescriptor.h +35 -0
  158. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputMeasurementManager.cpp +53 -0
  159. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputMeasurementManager.h +25 -0
  160. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputShadowNode.cpp +35 -0
  161. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputShadowNode.h +53 -0
  162. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputState.cpp +9 -0
  163. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextInputState.h +24 -0
  164. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextMeasurementManager.cpp +45 -0
  165. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextMeasurementManager.h +25 -0
  166. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextShadowNode.cpp +21 -0
  167. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/EnrichedTextShadowNode.h +39 -0
  168. package/android/src/main/new_arch/react/renderer/components/ReactNativeEnrichedSpec/conversions.h +44 -0
  169. package/android/src/main/res/drawable/broken_image.xml +10 -0
  170. package/cpp/CMakeLists.txt +50 -0
  171. package/cpp/GumboParser/GumboParser.h +34043 -0
  172. package/cpp/README.md +59 -0
  173. package/cpp/parser/GumboNormalizer.c +915 -0
  174. package/cpp/parser/GumboParser.cpp +16 -0
  175. package/cpp/parser/GumboParser.hpp +23 -0
  176. package/cpp/tests/GumboParserTest.cpp +457 -0
  177. package/ios/EnrichedTextInputView.h +54 -0
  178. package/ios/EnrichedTextInputView.mm +2170 -0
  179. package/ios/EnrichedTextInputViewManager.mm +13 -0
  180. package/ios/EnrichedTextView.h +35 -0
  181. package/ios/EnrichedTextView.mm +806 -0
  182. package/ios/EnrichedTextViewManager.mm +13 -0
  183. package/ios/config/EnrichedConfig.h +114 -0
  184. package/ios/config/EnrichedConfig.mm +727 -0
  185. package/ios/enrichedInputTextView/EnrichedInputTextView.h +6 -0
  186. package/ios/enrichedInputTextView/EnrichedInputTextView.mm +334 -0
  187. package/ios/enrichedTextTextView/EnrichedTextTextView.h +16 -0
  188. package/ios/enrichedTextTextView/EnrichedTextTextView.mm +71 -0
  189. package/ios/extensions/ColorExtension.h +8 -0
  190. package/ios/extensions/ColorExtension.mm +48 -0
  191. package/ios/extensions/FontExtension.h +11 -0
  192. package/ios/extensions/FontExtension.mm +72 -0
  193. package/ios/extensions/ImageExtension.h +33 -0
  194. package/ios/extensions/ImageExtension.mm +176 -0
  195. package/ios/extensions/LayoutManagerExtension.h +6 -0
  196. package/ios/extensions/LayoutManagerExtension.mm +454 -0
  197. package/ios/extensions/StringExtension.h +15 -0
  198. package/ios/extensions/StringExtension.mm +69 -0
  199. package/ios/generated/ReactNativeEnrichedSpec/ComponentDescriptors.cpp +22 -0
  200. package/ios/generated/ReactNativeEnrichedSpec/ComponentDescriptors.h +24 -0
  201. package/ios/generated/ReactNativeEnrichedSpec/EventEmitters.cpp +456 -0
  202. package/ios/generated/ReactNativeEnrichedSpec/EventEmitters.h +410 -0
  203. package/ios/generated/ReactNativeEnrichedSpec/Props.cpp +272 -0
  204. package/ios/generated/ReactNativeEnrichedSpec/Props.h +1595 -0
  205. package/ios/generated/ReactNativeEnrichedSpec/RCTComponentViewHelpers.h +570 -0
  206. package/ios/generated/ReactNativeEnrichedSpec/ShadowNodes.cpp +17 -0
  207. package/ios/generated/ReactNativeEnrichedSpec/ShadowNodes.h +23 -0
  208. package/ios/generated/ReactNativeEnrichedSpec/States.cpp +16 -0
  209. package/ios/generated/ReactNativeEnrichedSpec/States.h +20 -0
  210. package/ios/htmlParser/HtmlParser.h +11 -0
  211. package/ios/htmlParser/HtmlParser.mm +1468 -0
  212. package/ios/inputAttributesManager/InputAttributesManager.h +18 -0
  213. package/ios/inputAttributesManager/InputAttributesManager.mm +222 -0
  214. package/ios/inputHtmlParser/InputHtmlParser.h +10 -0
  215. package/ios/inputHtmlParser/InputHtmlParser.mm +225 -0
  216. package/ios/interfaces/AlignmentEntry.h +9 -0
  217. package/ios/interfaces/AlignmentEntry.mm +4 -0
  218. package/ios/interfaces/AttributeEntry.h +9 -0
  219. package/ios/interfaces/AttributeEntry.mm +4 -0
  220. package/ios/interfaces/BaseStyleProtocol.h +17 -0
  221. package/ios/interfaces/EnrichedTextStyleHeaders.h +62 -0
  222. package/ios/interfaces/EnrichedViewHost.h +26 -0
  223. package/ios/interfaces/ImageAttachment.h +11 -0
  224. package/ios/interfaces/ImageAttachment.mm +107 -0
  225. package/ios/interfaces/ImageData.h +10 -0
  226. package/ios/interfaces/ImageData.mm +4 -0
  227. package/ios/interfaces/LinkData.h +11 -0
  228. package/ios/interfaces/LinkData.mm +43 -0
  229. package/ios/interfaces/LinkRegexConfig.h +19 -0
  230. package/ios/interfaces/LinkRegexConfig.mm +37 -0
  231. package/ios/interfaces/MediaAttachment.h +23 -0
  232. package/ios/interfaces/MediaAttachment.mm +31 -0
  233. package/ios/interfaces/MentionParams.h +8 -0
  234. package/ios/interfaces/MentionParams.mm +4 -0
  235. package/ios/interfaces/MentionStyleProps.h +17 -0
  236. package/ios/interfaces/MentionStyleProps.mm +80 -0
  237. package/ios/interfaces/StyleBase.h +38 -0
  238. package/ios/interfaces/StyleBase.mm +279 -0
  239. package/ios/interfaces/StyleHeaders.h +110 -0
  240. package/ios/interfaces/StylePair.h +9 -0
  241. package/ios/interfaces/StylePair.mm +4 -0
  242. package/ios/interfaces/StyleTypeEnum.h +27 -0
  243. package/ios/interfaces/TextDecorationLineEnum.h +6 -0
  244. package/ios/interfaces/TextDecorationLineEnum.mm +4 -0
  245. package/ios/internals/EnrichedTextComponentDescriptor.h +19 -0
  246. package/ios/internals/EnrichedTextInputViewComponentDescriptor.h +19 -0
  247. package/ios/internals/EnrichedTextInputViewShadowNode.h +44 -0
  248. package/ios/internals/EnrichedTextInputViewShadowNode.mm +103 -0
  249. package/ios/internals/EnrichedTextInputViewState.cpp +10 -0
  250. package/ios/internals/EnrichedTextInputViewState.h +22 -0
  251. package/ios/internals/EnrichedTextViewShadowNode.h +34 -0
  252. package/ios/internals/EnrichedTextViewShadowNode.mm +72 -0
  253. package/ios/internals/EnrichedTextViewState.cpp +7 -0
  254. package/ios/internals/EnrichedTextViewState.h +18 -0
  255. package/ios/styles/AlignmentStyle.mm +203 -0
  256. package/ios/styles/BlockQuoteStyle.mm +54 -0
  257. package/ios/styles/BoldStyle.mm +37 -0
  258. package/ios/styles/CheckboxListStyle.mm +154 -0
  259. package/ios/styles/CodeBlockStyle.mm +49 -0
  260. package/ios/styles/EnrichedTextStyles.mm +61 -0
  261. package/ios/styles/H1Style.mm +20 -0
  262. package/ios/styles/H2Style.mm +20 -0
  263. package/ios/styles/H3Style.mm +20 -0
  264. package/ios/styles/H4Style.mm +20 -0
  265. package/ios/styles/H5Style.mm +20 -0
  266. package/ios/styles/H6Style.mm +20 -0
  267. package/ios/styles/HeadingStyleBase.mm +96 -0
  268. package/ios/styles/ImageStyle.mm +150 -0
  269. package/ios/styles/InlineCodeStyle.mm +65 -0
  270. package/ios/styles/ItalicStyle.mm +37 -0
  271. package/ios/styles/LinkStyle.mm +532 -0
  272. package/ios/styles/MentionStyle.mm +541 -0
  273. package/ios/styles/OrderedListStyle.mm +48 -0
  274. package/ios/styles/StrikethroughStyle.mm +25 -0
  275. package/ios/styles/UnderlineStyle.mm +24 -0
  276. package/ios/styles/UnorderedListStyle.mm +48 -0
  277. package/ios/textHtmlParser/TextHtmlParser.h +10 -0
  278. package/ios/textHtmlParser/TextHtmlParser.mm +181 -0
  279. package/ios/utils/AlignmentUtils.h +20 -0
  280. package/ios/utils/AlignmentUtils.mm +111 -0
  281. package/ios/utils/AttachmentLayoutUtils.h +24 -0
  282. package/ios/utils/AttachmentLayoutUtils.mm +144 -0
  283. package/ios/utils/CheckboxHitTestUtils.h +10 -0
  284. package/ios/utils/CheckboxHitTestUtils.mm +122 -0
  285. package/ios/utils/DotReplacementUtils.h +10 -0
  286. package/ios/utils/DotReplacementUtils.mm +68 -0
  287. package/ios/utils/EnrichedTextTouchHandler.h +14 -0
  288. package/ios/utils/EnrichedTextTouchHandler.mm +152 -0
  289. package/ios/utils/KeyboardUtils.h +7 -0
  290. package/ios/utils/KeyboardUtils.mm +30 -0
  291. package/ios/utils/OccurenceUtils.h +44 -0
  292. package/ios/utils/OccurenceUtils.mm +185 -0
  293. package/ios/utils/ParagraphAttributesUtils.h +18 -0
  294. package/ios/utils/ParagraphAttributesUtils.mm +289 -0
  295. package/ios/utils/RangeUtils.h +12 -0
  296. package/ios/utils/RangeUtils.mm +183 -0
  297. package/ios/utils/ShortcutsUtils.h +21 -0
  298. package/ios/utils/ShortcutsUtils.mm +486 -0
  299. package/ios/utils/StyleUtils.h +33 -0
  300. package/ios/utils/StyleUtils.mm +290 -0
  301. package/ios/utils/TextBlockTapGestureRecognizer.h +17 -0
  302. package/ios/utils/TextBlockTapGestureRecognizer.mm +56 -0
  303. package/ios/utils/TextInsertionUtils.h +17 -0
  304. package/ios/utils/TextInsertionUtils.mm +60 -0
  305. package/ios/utils/TextListsUtils.h +40 -0
  306. package/ios/utils/TextListsUtils.mm +93 -0
  307. package/ios/utils/WeakBox.h +3 -0
  308. package/ios/utils/WeakBox.m +4 -0
  309. package/ios/utils/WordsUtils.h +7 -0
  310. package/ios/utils/WordsUtils.mm +98 -0
  311. package/ios/utils/ZeroWidthSpaceUtils.h +14 -0
  312. package/ios/utils/ZeroWidthSpaceUtils.mm +310 -0
  313. package/lib/module/index.js +4 -0
  314. package/lib/module/index.js.map +1 -0
  315. package/lib/module/index.native.js +7 -0
  316. package/lib/module/index.native.js.map +1 -0
  317. package/lib/module/native/EnrichedText.js +76 -0
  318. package/lib/module/native/EnrichedText.js.map +1 -0
  319. package/lib/module/native/EnrichedTextInput.js +306 -0
  320. package/lib/module/native/EnrichedTextInput.js.map +1 -0
  321. package/lib/module/package.json +1 -0
  322. package/lib/module/spec/EnrichedTextInputNativeComponent.ts +524 -0
  323. package/lib/module/spec/EnrichedTextNativeComponent.ts +110 -0
  324. package/lib/module/types.js +4 -0
  325. package/lib/module/types.js.map +1 -0
  326. package/lib/module/utils/EnrichedTextInputDefaultProps.js +20 -0
  327. package/lib/module/utils/EnrichedTextInputDefaultProps.js.map +1 -0
  328. package/lib/module/utils/defaultHtmlStyle.js +83 -0
  329. package/lib/module/utils/defaultHtmlStyle.js.map +1 -0
  330. package/lib/module/utils/expandMentionStylesForIndicators.js +15 -0
  331. package/lib/module/utils/expandMentionStylesForIndicators.js.map +1 -0
  332. package/lib/module/utils/isMentionStyleRecord.js +10 -0
  333. package/lib/module/utils/isMentionStyleRecord.js.map +1 -0
  334. package/lib/module/utils/normalizeHtmlStyle.js +126 -0
  335. package/lib/module/utils/normalizeHtmlStyle.js.map +1 -0
  336. package/lib/module/utils/nullthrows.js +9 -0
  337. package/lib/module/utils/nullthrows.js.map +1 -0
  338. package/lib/module/utils/regexParser.js +46 -0
  339. package/lib/module/utils/regexParser.js.map +1 -0
  340. package/lib/module/web/EnrichedTextInput.css +201 -0
  341. package/lib/module/web/EnrichedTextInput.js +314 -0
  342. package/lib/module/web/EnrichedTextInput.js.map +1 -0
  343. package/lib/module/web/adaptWebToNativeEvent.js +34 -0
  344. package/lib/module/web/adaptWebToNativeEvent.js.map +1 -0
  345. package/lib/module/web/checkboxHtmlNormalizer.js +54 -0
  346. package/lib/module/web/checkboxHtmlNormalizer.js.map +1 -0
  347. package/lib/module/web/formats/EnrichedBlockquote.js +32 -0
  348. package/lib/module/web/formats/EnrichedBlockquote.js.map +1 -0
  349. package/lib/module/web/formats/EnrichedBold.js +22 -0
  350. package/lib/module/web/formats/EnrichedBold.js.map +1 -0
  351. package/lib/module/web/formats/EnrichedCheckboxItem.js +32 -0
  352. package/lib/module/web/formats/EnrichedCheckboxItem.js.map +1 -0
  353. package/lib/module/web/formats/EnrichedCheckboxList.js +35 -0
  354. package/lib/module/web/formats/EnrichedCheckboxList.js.map +1 -0
  355. package/lib/module/web/formats/EnrichedCode.js +15 -0
  356. package/lib/module/web/formats/EnrichedCode.js.map +1 -0
  357. package/lib/module/web/formats/EnrichedCodeBlock.js +43 -0
  358. package/lib/module/web/formats/EnrichedCodeBlock.js.map +1 -0
  359. package/lib/module/web/formats/EnrichedHeading.js +27 -0
  360. package/lib/module/web/formats/EnrichedHeading.js.map +1 -0
  361. package/lib/module/web/formats/EnrichedImage.js +57 -0
  362. package/lib/module/web/formats/EnrichedImage.js.map +1 -0
  363. package/lib/module/web/formats/EnrichedImageNodeView.js +90 -0
  364. package/lib/module/web/formats/EnrichedImageNodeView.js.map +1 -0
  365. package/lib/module/web/formats/EnrichedItalic.js +22 -0
  366. package/lib/module/web/formats/EnrichedItalic.js.map +1 -0
  367. package/lib/module/web/formats/EnrichedLink.js +140 -0
  368. package/lib/module/web/formats/EnrichedLink.js.map +1 -0
  369. package/lib/module/web/formats/EnrichedListItem.js +19 -0
  370. package/lib/module/web/formats/EnrichedListItem.js.map +1 -0
  371. package/lib/module/web/formats/EnrichedMention.js +50 -0
  372. package/lib/module/web/formats/EnrichedMention.js.map +1 -0
  373. package/lib/module/web/formats/EnrichedOrderedList.js +32 -0
  374. package/lib/module/web/formats/EnrichedOrderedList.js.map +1 -0
  375. package/lib/module/web/formats/EnrichedStrike.js +22 -0
  376. package/lib/module/web/formats/EnrichedStrike.js.map +1 -0
  377. package/lib/module/web/formats/EnrichedUnderline.js +22 -0
  378. package/lib/module/web/formats/EnrichedUnderline.js.map +1 -0
  379. package/lib/module/web/formats/EnrichedUnorderedList.js +33 -0
  380. package/lib/module/web/formats/EnrichedUnorderedList.js.map +1 -0
  381. package/lib/module/web/formats/applyWrappingListToSelection.js +63 -0
  382. package/lib/module/web/formats/applyWrappingListToSelection.js.map +1 -0
  383. package/lib/module/web/formats/formatRules.js +48 -0
  384. package/lib/module/web/formats/formatRules.js.map +1 -0
  385. package/lib/module/web/formats/listKeyboard.js +50 -0
  386. package/lib/module/web/formats/listKeyboard.js.map +1 -0
  387. package/lib/module/web/formats/wrappedBlockKeyboard.js +58 -0
  388. package/lib/module/web/formats/wrappedBlockKeyboard.js.map +1 -0
  389. package/lib/module/web/pasteImages.js +78 -0
  390. package/lib/module/web/pasteImages.js.map +1 -0
  391. package/lib/module/web/pastedImageDimensions.js +49 -0
  392. package/lib/module/web/pastedImageDimensions.js.map +1 -0
  393. package/lib/module/web/pmPlugins/MentionPlugin/index.js +36 -0
  394. package/lib/module/web/pmPlugins/MentionPlugin/index.js.map +1 -0
  395. package/lib/module/web/pmPlugins/MentionPlugin/isCaretInBlockedContext.js +11 -0
  396. package/lib/module/web/pmPlugins/MentionPlugin/isCaretInBlockedContext.js.map +1 -0
  397. package/lib/module/web/pmPlugins/MentionPlugin/makeMentionPluginState.js +67 -0
  398. package/lib/module/web/pmPlugins/MentionPlugin/makeMentionPluginState.js.map +1 -0
  399. package/lib/module/web/pmPlugins/MentionPlugin/mentionPluginKey.js +5 -0
  400. package/lib/module/web/pmPlugins/MentionPlugin/mentionPluginKey.js.map +1 -0
  401. package/lib/module/web/pmPlugins/MentionPlugin/removeMentionMarksIfSpansResized.js +56 -0
  402. package/lib/module/web/pmPlugins/MentionPlugin/removeMentionMarksIfSpansResized.js.map +1 -0
  403. package/lib/module/web/pmPlugins/MentionPlugin/setMention.js +58 -0
  404. package/lib/module/web/pmPlugins/MentionPlugin/setMention.js.map +1 -0
  405. package/lib/module/web/pmPlugins/MentionPlugin/startMention.js +9 -0
  406. package/lib/module/web/pmPlugins/MentionPlugin/startMention.js.map +1 -0
  407. package/lib/module/web/pmPlugins/MentionPlugin/stripPartialMentionMarks.js +9 -0
  408. package/lib/module/web/pmPlugins/MentionPlugin/stripPartialMentionMarks.js.map +1 -0
  409. package/lib/module/web/pmPlugins/MentionPlugin/subscribeMentionEvents.js +100 -0
  410. package/lib/module/web/pmPlugins/MentionPlugin/subscribeMentionEvents.js.map +1 -0
  411. package/lib/module/web/pmPlugins/MentionPlugin/types.js +4 -0
  412. package/lib/module/web/pmPlugins/MentionPlugin/types.js.map +1 -0
  413. package/lib/module/web/pmPlugins/MergeAdjacentSameKindBlocksPlugin.js +42 -0
  414. package/lib/module/web/pmPlugins/MergeAdjacentSameKindBlocksPlugin.js.map +1 -0
  415. package/lib/module/web/pmPlugins/ShortcutPlugin.js +123 -0
  416. package/lib/module/web/pmPlugins/ShortcutPlugin.js.map +1 -0
  417. package/lib/module/web/pmPlugins/StrictMarksPlugin.js +98 -0
  418. package/lib/module/web/pmPlugins/StrictMarksPlugin.js.map +1 -0
  419. package/lib/module/web/pmPlugins/StripBoldInStyledHeadingsPlugin.js +56 -0
  420. package/lib/module/web/pmPlugins/StripBoldInStyledHeadingsPlugin.js.map +1 -0
  421. package/lib/module/web/pmPlugins/StripMarksInCodeBlockPlugin.js +28 -0
  422. package/lib/module/web/pmPlugins/StripMarksInCodeBlockPlugin.js.map +1 -0
  423. package/lib/module/web/pmPlugins/StripMarksOnImagePlugin.js +29 -0
  424. package/lib/module/web/pmPlugins/StripMarksOnImagePlugin.js.map +1 -0
  425. package/lib/module/web/positionMapping.js +76 -0
  426. package/lib/module/web/positionMapping.js.map +1 -0
  427. package/lib/module/web/returnKeyTypeToEnterKeyHint.js +20 -0
  428. package/lib/module/web/returnKeyTypeToEnterKeyHint.js.map +1 -0
  429. package/lib/module/web/styleConversion/buildMentionRulesCSS.js +33 -0
  430. package/lib/module/web/styleConversion/buildMentionRulesCSS.js.map +1 -0
  431. package/lib/module/web/styleConversion/enrichedInputStyleToCSSProperties.js +159 -0
  432. package/lib/module/web/styleConversion/enrichedInputStyleToCSSProperties.js.map +1 -0
  433. package/lib/module/web/styleConversion/enrichedInputThemingToCSSProperties.js +18 -0
  434. package/lib/module/web/styleConversion/enrichedInputThemingToCSSProperties.js.map +1 -0
  435. package/lib/module/web/styleConversion/htmlStyleToCSSVariables.js +145 -0
  436. package/lib/module/web/styleConversion/htmlStyleToCSSVariables.js.map +1 -0
  437. package/lib/module/web/styleConversion/mentionIndicatorCssKey.js +15 -0
  438. package/lib/module/web/styleConversion/mentionIndicatorCssKey.js.map +1 -0
  439. package/lib/module/web/styleConversion/toColor.js +18 -0
  440. package/lib/module/web/styleConversion/toColor.js.map +1 -0
  441. package/lib/module/web/tiptapHtmlNormalizer.js +30 -0
  442. package/lib/module/web/tiptapHtmlNormalizer.js.map +1 -0
  443. package/lib/module/web/useOnChangeHtml.js +8 -0
  444. package/lib/module/web/useOnChangeHtml.js.map +1 -0
  445. package/lib/module/web/useOnChangeState.js +88 -0
  446. package/lib/module/web/useOnChangeState.js.map +1 -0
  447. package/lib/module/web/useOnChangeText.js +11 -0
  448. package/lib/module/web/useOnChangeText.js.map +1 -0
  449. package/lib/module/web/useOnEditorChange.js +25 -0
  450. package/lib/module/web/useOnEditorChange.js.map +1 -0
  451. package/lib/module/web/useOnLinkDetected.js +68 -0
  452. package/lib/module/web/useOnLinkDetected.js.map +1 -0
  453. package/lib/typescript/package.json +1 -0
  454. package/lib/typescript/src/index.d.ts +3 -0
  455. package/lib/typescript/src/index.d.ts.map +1 -0
  456. package/lib/typescript/src/index.native.d.ts +5 -0
  457. package/lib/typescript/src/index.native.d.ts.map +1 -0
  458. package/lib/typescript/src/native/EnrichedText.d.ts +3 -0
  459. package/lib/typescript/src/native/EnrichedText.d.ts.map +1 -0
  460. package/lib/typescript/src/native/EnrichedTextInput.d.ts +3 -0
  461. package/lib/typescript/src/native/EnrichedTextInput.d.ts.map +1 -0
  462. package/lib/typescript/src/spec/EnrichedTextInputNativeComponent.d.ts +405 -0
  463. package/lib/typescript/src/spec/EnrichedTextInputNativeComponent.d.ts.map +1 -0
  464. package/lib/typescript/src/spec/EnrichedTextNativeComponent.d.ts +88 -0
  465. package/lib/typescript/src/spec/EnrichedTextNativeComponent.d.ts.map +1 -0
  466. package/lib/typescript/src/types.d.ts +721 -0
  467. package/lib/typescript/src/types.d.ts.map +1 -0
  468. package/lib/typescript/src/utils/EnrichedTextInputDefaultProps.d.ts +13 -0
  469. package/lib/typescript/src/utils/EnrichedTextInputDefaultProps.d.ts.map +1 -0
  470. package/lib/typescript/src/utils/defaultHtmlStyle.d.ts +4 -0
  471. package/lib/typescript/src/utils/defaultHtmlStyle.d.ts.map +1 -0
  472. package/lib/typescript/src/utils/expandMentionStylesForIndicators.d.ts +3 -0
  473. package/lib/typescript/src/utils/expandMentionStylesForIndicators.d.ts.map +1 -0
  474. package/lib/typescript/src/utils/isMentionStyleRecord.d.ts +3 -0
  475. package/lib/typescript/src/utils/isMentionStyleRecord.d.ts.map +1 -0
  476. package/lib/typescript/src/utils/normalizeHtmlStyle.d.ts +6 -0
  477. package/lib/typescript/src/utils/normalizeHtmlStyle.d.ts.map +1 -0
  478. package/lib/typescript/src/utils/nullthrows.d.ts +2 -0
  479. package/lib/typescript/src/utils/nullthrows.d.ts.map +1 -0
  480. package/lib/typescript/src/utils/regexParser.d.ts +3 -0
  481. package/lib/typescript/src/utils/regexParser.d.ts.map +1 -0
  482. package/lib/typescript/src/web/EnrichedTextInput.d.ts +4 -0
  483. package/lib/typescript/src/web/EnrichedTextInput.d.ts.map +1 -0
  484. package/lib/typescript/src/web/adaptWebToNativeEvent.d.ts +3 -0
  485. package/lib/typescript/src/web/adaptWebToNativeEvent.d.ts.map +1 -0
  486. package/lib/typescript/src/web/checkboxHtmlNormalizer.d.ts +3 -0
  487. package/lib/typescript/src/web/checkboxHtmlNormalizer.d.ts.map +1 -0
  488. package/lib/typescript/src/web/formats/EnrichedBlockquote.d.ts +2 -0
  489. package/lib/typescript/src/web/formats/EnrichedBlockquote.d.ts.map +1 -0
  490. package/lib/typescript/src/web/formats/EnrichedBold.d.ts +2 -0
  491. package/lib/typescript/src/web/formats/EnrichedBold.d.ts.map +1 -0
  492. package/lib/typescript/src/web/formats/EnrichedCheckboxItem.d.ts +2 -0
  493. package/lib/typescript/src/web/formats/EnrichedCheckboxItem.d.ts.map +1 -0
  494. package/lib/typescript/src/web/formats/EnrichedCheckboxList.d.ts +9 -0
  495. package/lib/typescript/src/web/formats/EnrichedCheckboxList.d.ts.map +1 -0
  496. package/lib/typescript/src/web/formats/EnrichedCode.d.ts +2 -0
  497. package/lib/typescript/src/web/formats/EnrichedCode.d.ts.map +1 -0
  498. package/lib/typescript/src/web/formats/EnrichedCodeBlock.d.ts +9 -0
  499. package/lib/typescript/src/web/formats/EnrichedCodeBlock.d.ts.map +1 -0
  500. package/lib/typescript/src/web/formats/EnrichedHeading.d.ts +5 -0
  501. package/lib/typescript/src/web/formats/EnrichedHeading.d.ts.map +1 -0
  502. package/lib/typescript/src/web/formats/EnrichedImage.d.ts +2 -0
  503. package/lib/typescript/src/web/formats/EnrichedImage.d.ts.map +1 -0
  504. package/lib/typescript/src/web/formats/EnrichedImageNodeView.d.ts +3 -0
  505. package/lib/typescript/src/web/formats/EnrichedImageNodeView.d.ts.map +1 -0
  506. package/lib/typescript/src/web/formats/EnrichedItalic.d.ts +2 -0
  507. package/lib/typescript/src/web/formats/EnrichedItalic.d.ts.map +1 -0
  508. package/lib/typescript/src/web/formats/EnrichedLink.d.ts +5 -0
  509. package/lib/typescript/src/web/formats/EnrichedLink.d.ts.map +1 -0
  510. package/lib/typescript/src/web/formats/EnrichedListItem.d.ts +2 -0
  511. package/lib/typescript/src/web/formats/EnrichedListItem.d.ts.map +1 -0
  512. package/lib/typescript/src/web/formats/EnrichedMention.d.ts +4 -0
  513. package/lib/typescript/src/web/formats/EnrichedMention.d.ts.map +1 -0
  514. package/lib/typescript/src/web/formats/EnrichedOrderedList.d.ts +2 -0
  515. package/lib/typescript/src/web/formats/EnrichedOrderedList.d.ts.map +1 -0
  516. package/lib/typescript/src/web/formats/EnrichedStrike.d.ts +2 -0
  517. package/lib/typescript/src/web/formats/EnrichedStrike.d.ts.map +1 -0
  518. package/lib/typescript/src/web/formats/EnrichedUnderline.d.ts +2 -0
  519. package/lib/typescript/src/web/formats/EnrichedUnderline.d.ts.map +1 -0
  520. package/lib/typescript/src/web/formats/EnrichedUnorderedList.d.ts +9 -0
  521. package/lib/typescript/src/web/formats/EnrichedUnorderedList.d.ts.map +1 -0
  522. package/lib/typescript/src/web/formats/applyWrappingListToSelection.d.ts +18 -0
  523. package/lib/typescript/src/web/formats/applyWrappingListToSelection.d.ts.map +1 -0
  524. package/lib/typescript/src/web/formats/formatRules.d.ts +10 -0
  525. package/lib/typescript/src/web/formats/formatRules.d.ts.map +1 -0
  526. package/lib/typescript/src/web/formats/listKeyboard.d.ts +4 -0
  527. package/lib/typescript/src/web/formats/listKeyboard.d.ts.map +1 -0
  528. package/lib/typescript/src/web/formats/wrappedBlockKeyboard.d.ts +12 -0
  529. package/lib/typescript/src/web/formats/wrappedBlockKeyboard.d.ts.map +1 -0
  530. package/lib/typescript/src/web/pasteImages.d.ts +10 -0
  531. package/lib/typescript/src/web/pasteImages.d.ts.map +1 -0
  532. package/lib/typescript/src/web/pastedImageDimensions.d.ts +9 -0
  533. package/lib/typescript/src/web/pastedImageDimensions.d.ts.map +1 -0
  534. package/lib/typescript/src/web/pmPlugins/MentionPlugin/index.d.ts +9 -0
  535. package/lib/typescript/src/web/pmPlugins/MentionPlugin/index.d.ts.map +1 -0
  536. package/lib/typescript/src/web/pmPlugins/MentionPlugin/isCaretInBlockedContext.d.ts +3 -0
  537. package/lib/typescript/src/web/pmPlugins/MentionPlugin/isCaretInBlockedContext.d.ts.map +1 -0
  538. package/lib/typescript/src/web/pmPlugins/MentionPlugin/makeMentionPluginState.d.ts +4 -0
  539. package/lib/typescript/src/web/pmPlugins/MentionPlugin/makeMentionPluginState.d.ts.map +1 -0
  540. package/lib/typescript/src/web/pmPlugins/MentionPlugin/mentionPluginKey.d.ts +4 -0
  541. package/lib/typescript/src/web/pmPlugins/MentionPlugin/mentionPluginKey.d.ts.map +1 -0
  542. package/lib/typescript/src/web/pmPlugins/MentionPlugin/removeMentionMarksIfSpansResized.d.ts +9 -0
  543. package/lib/typescript/src/web/pmPlugins/MentionPlugin/removeMentionMarksIfSpansResized.d.ts.map +1 -0
  544. package/lib/typescript/src/web/pmPlugins/MentionPlugin/setMention.d.ts +3 -0
  545. package/lib/typescript/src/web/pmPlugins/MentionPlugin/setMention.d.ts.map +1 -0
  546. package/lib/typescript/src/web/pmPlugins/MentionPlugin/startMention.d.ts +3 -0
  547. package/lib/typescript/src/web/pmPlugins/MentionPlugin/startMention.d.ts.map +1 -0
  548. package/lib/typescript/src/web/pmPlugins/MentionPlugin/stripPartialMentionMarks.d.ts +3 -0
  549. package/lib/typescript/src/web/pmPlugins/MentionPlugin/stripPartialMentionMarks.d.ts.map +1 -0
  550. package/lib/typescript/src/web/pmPlugins/MentionPlugin/subscribeMentionEvents.d.ts +4 -0
  551. package/lib/typescript/src/web/pmPlugins/MentionPlugin/subscribeMentionEvents.d.ts.map +1 -0
  552. package/lib/typescript/src/web/pmPlugins/MentionPlugin/types.d.ts +20 -0
  553. package/lib/typescript/src/web/pmPlugins/MentionPlugin/types.d.ts.map +1 -0
  554. package/lib/typescript/src/web/pmPlugins/MergeAdjacentSameKindBlocksPlugin.d.ts +3 -0
  555. package/lib/typescript/src/web/pmPlugins/MergeAdjacentSameKindBlocksPlugin.d.ts.map +1 -0
  556. package/lib/typescript/src/web/pmPlugins/ShortcutPlugin.d.ts +7 -0
  557. package/lib/typescript/src/web/pmPlugins/ShortcutPlugin.d.ts.map +1 -0
  558. package/lib/typescript/src/web/pmPlugins/StrictMarksPlugin.d.ts +3 -0
  559. package/lib/typescript/src/web/pmPlugins/StrictMarksPlugin.d.ts.map +1 -0
  560. package/lib/typescript/src/web/pmPlugins/StripBoldInStyledHeadingsPlugin.d.ts +10 -0
  561. package/lib/typescript/src/web/pmPlugins/StripBoldInStyledHeadingsPlugin.d.ts.map +1 -0
  562. package/lib/typescript/src/web/pmPlugins/StripMarksInCodeBlockPlugin.d.ts +3 -0
  563. package/lib/typescript/src/web/pmPlugins/StripMarksInCodeBlockPlugin.d.ts.map +1 -0
  564. package/lib/typescript/src/web/pmPlugins/StripMarksOnImagePlugin.d.ts +3 -0
  565. package/lib/typescript/src/web/pmPlugins/StripMarksOnImagePlugin.d.ts.map +1 -0
  566. package/lib/typescript/src/web/positionMapping.d.ts +39 -0
  567. package/lib/typescript/src/web/positionMapping.d.ts.map +1 -0
  568. package/lib/typescript/src/web/returnKeyTypeToEnterKeyHint.d.ts +4 -0
  569. package/lib/typescript/src/web/returnKeyTypeToEnterKeyHint.d.ts.map +1 -0
  570. package/lib/typescript/src/web/styleConversion/buildMentionRulesCSS.d.ts +3 -0
  571. package/lib/typescript/src/web/styleConversion/buildMentionRulesCSS.d.ts.map +1 -0
  572. package/lib/typescript/src/web/styleConversion/enrichedInputStyleToCSSProperties.d.ts +8 -0
  573. package/lib/typescript/src/web/styleConversion/enrichedInputStyleToCSSProperties.d.ts.map +1 -0
  574. package/lib/typescript/src/web/styleConversion/enrichedInputThemingToCSSProperties.d.ts +9 -0
  575. package/lib/typescript/src/web/styleConversion/enrichedInputThemingToCSSProperties.d.ts.map +1 -0
  576. package/lib/typescript/src/web/styleConversion/htmlStyleToCSSVariables.d.ts +10 -0
  577. package/lib/typescript/src/web/styleConversion/htmlStyleToCSSVariables.d.ts.map +1 -0
  578. package/lib/typescript/src/web/styleConversion/mentionIndicatorCssKey.d.ts +3 -0
  579. package/lib/typescript/src/web/styleConversion/mentionIndicatorCssKey.d.ts.map +1 -0
  580. package/lib/typescript/src/web/styleConversion/toColor.d.ts +3 -0
  581. package/lib/typescript/src/web/styleConversion/toColor.d.ts.map +1 -0
  582. package/lib/typescript/src/web/tiptapHtmlNormalizer.d.ts +3 -0
  583. package/lib/typescript/src/web/tiptapHtmlNormalizer.d.ts.map +1 -0
  584. package/lib/typescript/src/web/useOnChangeHtml.d.ts +5 -0
  585. package/lib/typescript/src/web/useOnChangeHtml.d.ts.map +1 -0
  586. package/lib/typescript/src/web/useOnChangeState.d.ts +6 -0
  587. package/lib/typescript/src/web/useOnChangeState.d.ts.map +1 -0
  588. package/lib/typescript/src/web/useOnChangeText.d.ts +5 -0
  589. package/lib/typescript/src/web/useOnChangeText.d.ts.map +1 -0
  590. package/lib/typescript/src/web/useOnEditorChange.d.ts +6 -0
  591. package/lib/typescript/src/web/useOnEditorChange.d.ts.map +1 -0
  592. package/lib/typescript/src/web/useOnLinkDetected.d.ts +4 -0
  593. package/lib/typescript/src/web/useOnLinkDetected.d.ts.map +1 -0
  594. package/package.json +232 -1
  595. package/react-native.config.js +16 -0
  596. package/src/index.native.tsx +34 -0
  597. package/src/index.tsx +24 -0
  598. package/src/native/EnrichedText.tsx +115 -0
  599. package/src/native/EnrichedTextInput.tsx +374 -0
  600. package/src/spec/EnrichedTextInputNativeComponent.ts +524 -0
  601. package/src/spec/EnrichedTextNativeComponent.ts +110 -0
  602. package/src/types.ts +864 -0
  603. package/src/utils/EnrichedTextInputDefaultProps.ts +16 -0
  604. package/src/utils/defaultHtmlStyle.ts +83 -0
  605. package/src/utils/expandMentionStylesForIndicators.ts +19 -0
  606. package/src/utils/isMentionStyleRecord.ts +22 -0
  607. package/src/utils/normalizeHtmlStyle.ts +181 -0
  608. package/src/utils/nullthrows.ts +7 -0
  609. package/src/utils/regexParser.ts +56 -0
  610. package/src/web/EnrichedTextInput.css +201 -0
  611. package/src/web/EnrichedTextInput.tsx +403 -0
  612. package/src/web/adaptWebToNativeEvent.ts +37 -0
  613. package/src/web/checkboxHtmlNormalizer.ts +62 -0
  614. package/src/web/formats/EnrichedBlockquote.ts +36 -0
  615. package/src/web/formats/EnrichedBold.ts +16 -0
  616. package/src/web/formats/EnrichedCheckboxItem.ts +35 -0
  617. package/src/web/formats/EnrichedCheckboxList.ts +47 -0
  618. package/src/web/formats/EnrichedCode.ts +13 -0
  619. package/src/web/formats/EnrichedCodeBlock.ts +53 -0
  620. package/src/web/formats/EnrichedHeading.ts +36 -0
  621. package/src/web/formats/EnrichedImage.ts +59 -0
  622. package/src/web/formats/EnrichedImageNodeView.tsx +89 -0
  623. package/src/web/formats/EnrichedItalic.ts +16 -0
  624. package/src/web/formats/EnrichedLink.ts +149 -0
  625. package/src/web/formats/EnrichedListItem.ts +17 -0
  626. package/src/web/formats/EnrichedMention.ts +55 -0
  627. package/src/web/formats/EnrichedOrderedList.ts +40 -0
  628. package/src/web/formats/EnrichedStrike.ts +16 -0
  629. package/src/web/formats/EnrichedUnderline.ts +16 -0
  630. package/src/web/formats/EnrichedUnorderedList.ts +50 -0
  631. package/src/web/formats/applyWrappingListToSelection.ts +76 -0
  632. package/src/web/formats/formatRules.ts +84 -0
  633. package/src/web/formats/listKeyboard.ts +58 -0
  634. package/src/web/formats/wrappedBlockKeyboard.ts +76 -0
  635. package/src/web/pasteImages.ts +96 -0
  636. package/src/web/pastedImageDimensions.ts +40 -0
  637. package/src/web/pmPlugins/MentionPlugin/index.ts +45 -0
  638. package/src/web/pmPlugins/MentionPlugin/isCaretInBlockedContext.ts +17 -0
  639. package/src/web/pmPlugins/MentionPlugin/makeMentionPluginState.ts +75 -0
  640. package/src/web/pmPlugins/MentionPlugin/mentionPluginKey.ts +4 -0
  641. package/src/web/pmPlugins/MentionPlugin/removeMentionMarksIfSpansResized.ts +68 -0
  642. package/src/web/pmPlugins/MentionPlugin/setMention.ts +83 -0
  643. package/src/web/pmPlugins/MentionPlugin/startMention.ts +14 -0
  644. package/src/web/pmPlugins/MentionPlugin/stripPartialMentionMarks.ts +20 -0
  645. package/src/web/pmPlugins/MentionPlugin/subscribeMentionEvents.ts +105 -0
  646. package/src/web/pmPlugins/MentionPlugin/types.ts +22 -0
  647. package/src/web/pmPlugins/MergeAdjacentSameKindBlocksPlugin.ts +57 -0
  648. package/src/web/pmPlugins/ShortcutPlugin.ts +98 -0
  649. package/src/web/pmPlugins/StrictMarksPlugin.ts +131 -0
  650. package/src/web/pmPlugins/StripBoldInStyledHeadingsPlugin.ts +79 -0
  651. package/src/web/pmPlugins/StripMarksInCodeBlockPlugin.ts +34 -0
  652. package/src/web/pmPlugins/StripMarksOnImagePlugin.ts +33 -0
  653. package/src/web/positionMapping.ts +81 -0
  654. package/src/web/returnKeyTypeToEnterKeyHint.ts +29 -0
  655. package/src/web/styleConversion/buildMentionRulesCSS.ts +42 -0
  656. package/src/web/styleConversion/enrichedInputStyleToCSSProperties.ts +224 -0
  657. package/src/web/styleConversion/enrichedInputThemingToCSSProperties.ts +34 -0
  658. package/src/web/styleConversion/htmlStyleToCSSVariables.ts +226 -0
  659. package/src/web/styleConversion/mentionIndicatorCssKey.ts +14 -0
  660. package/src/web/styleConversion/toColor.ts +17 -0
  661. package/src/web/tiptapHtmlNormalizer.ts +33 -0
  662. package/src/web/useOnChangeHtml.ts +14 -0
  663. package/src/web/useOnChangeState.ts +125 -0
  664. package/src/web/useOnChangeText.ts +15 -0
  665. package/src/web/useOnEditorChange.ts +33 -0
  666. package/src/web/useOnLinkDetected.ts +82 -0
@@ -0,0 +1,1468 @@
1
+ #import "HtmlParser.h"
2
+ #import "AlignmentEntry.h"
3
+ #import "AlignmentUtils.h"
4
+ #import "ImageData.h"
5
+ #import "LinkData.h"
6
+ #import "MentionParams.h"
7
+ #import "StringExtension.h"
8
+ #import "StyleHeaders.h"
9
+ #import "StylePair.h"
10
+
11
+ #include "GumboParser.hpp"
12
+
13
+ @implementation HtmlParser
14
+
15
+ + (BOOL)isBlockTag:(NSString *)tagName {
16
+ return [tagName isEqualToString:@"ul"] || [tagName isEqualToString:@"ol"] ||
17
+ [tagName isEqualToString:@"blockquote"] ||
18
+ [tagName isEqualToString:@"codeblock"];
19
+ }
20
+
21
+ /**
22
+ * Prepares HTML for the parser by stripping extraneous whitespace and newlines
23
+ * from structural tags, while preserving them within text content.
24
+ *
25
+ * APPROACH:
26
+ * This function treats the HTML as having two distinct states:
27
+ * 1. Structure Mode (Depth == 0): We are inside or between container tags (like
28
+ * blockquote, ul, codeblock). In this mode whitespace and newlines are
29
+ * considered layout artifacts and are REMOVED to prevent the parser from
30
+ * creating unwanted spaces.
31
+ * 2. Content Mode (Depth > 0): We are inside a text-containing tag (like p,
32
+ * b, li). In this mode, all whitespace is PRESERVED exactly as is, ensuring
33
+ * that sentences and inline formatting remain readable.
34
+ *
35
+ * The function iterates character-by-character, using a depth counter to track
36
+ * nesting levels of the specific tags defined in `textTags`.
37
+ *
38
+ * IMPORTANT:
39
+ * The `textTags` set acts as a whitelist for "Content Mode". If you add support
40
+ * for a new HTML tag that contains visible text (e.g., h4, h5, h6),
41
+ * you MUST add it to the `textTags` set below.
42
+ */
43
+ + (NSString *)stripExtraWhiteSpacesAndNewlines:(NSString *)html {
44
+ NSSet *textTags = [NSSet setWithObjects:@"p", @"h1", @"h2", @"h3", @"h4",
45
+ @"h5", @"h6", @"li", @"b", @"a", @"s",
46
+ @"mention", @"code", @"u", @"i", nil];
47
+
48
+ NSMutableString *output = [NSMutableString stringWithCapacity:html.length];
49
+ NSMutableString *currentTagBuffer = [NSMutableString string];
50
+ NSCharacterSet *whitespaceAndNewlineSet =
51
+ [NSCharacterSet whitespaceAndNewlineCharacterSet];
52
+
53
+ BOOL isReadingTag = NO;
54
+ NSInteger textDepth = 0;
55
+
56
+ for (NSUInteger i = 0; i < html.length; i++) {
57
+ unichar c = [html characterAtIndex:i];
58
+
59
+ if (c == '<') {
60
+ isReadingTag = YES;
61
+ [currentTagBuffer setString:@""];
62
+ [output appendString:@"<"];
63
+ } else if (c == '>') {
64
+ isReadingTag = NO;
65
+ [output appendString:@">"];
66
+
67
+ NSString *fullTag = [currentTagBuffer lowercaseString];
68
+
69
+ NSString *cleanName = [fullTag
70
+ stringByTrimmingCharactersInSet:
71
+ [NSCharacterSet characterSetWithCharactersInString:@"/"]];
72
+ NSArray *parts =
73
+ [cleanName componentsSeparatedByCharactersInSet:
74
+ [NSCharacterSet whitespaceAndNewlineCharacterSet]];
75
+ NSString *tagName = parts.firstObject;
76
+
77
+ if (![textTags containsObject:tagName]) {
78
+ continue;
79
+ }
80
+
81
+ if ([fullTag hasPrefix:@"/"]) {
82
+ textDepth--;
83
+ if (textDepth < 0)
84
+ textDepth = 0;
85
+ } else {
86
+ // Opening tag (e.g. <h1>) -> Enter Text Mode
87
+ // (Ignore self-closing tags like <img/> if they happen to be in the
88
+ // list)
89
+ if (![fullTag hasSuffix:@"/"]) {
90
+ textDepth++;
91
+ }
92
+ }
93
+ } else {
94
+ if (isReadingTag) {
95
+ [currentTagBuffer appendFormat:@"%C", c];
96
+ [output appendFormat:@"%C", c];
97
+ continue;
98
+ }
99
+
100
+ if (textDepth > 0) {
101
+ [output appendFormat:@"%C", c];
102
+ } else {
103
+ if (![whitespaceAndNewlineSet characterIsMember:c]) {
104
+ [output appendFormat:@"%C", c];
105
+ }
106
+ }
107
+ }
108
+ }
109
+
110
+ return output;
111
+ }
112
+
113
+ + (NSString *)stringByAddingNewlinesToTag:(NSString *)tag
114
+ inString:(NSString *)html
115
+ leading:(BOOL)leading
116
+ trailing:(BOOL)trailing {
117
+ NSString *str = [html copy];
118
+ if (leading) {
119
+ NSString *formattedTag = [NSString stringWithFormat:@">%@", tag];
120
+ NSString *formattedNewTag = [NSString stringWithFormat:@">\n%@", tag];
121
+ str = [str stringByReplacingOccurrencesOfString:formattedTag
122
+ withString:formattedNewTag];
123
+ }
124
+ if (trailing) {
125
+ NSString *formattedTag = [NSString stringWithFormat:@"%@<", tag];
126
+ NSString *formattedNewTag = [NSString stringWithFormat:@"%@\n<", tag];
127
+ str = [str stringByReplacingOccurrencesOfString:formattedTag
128
+ withString:formattedNewTag];
129
+ }
130
+ return str;
131
+ }
132
+
133
+ #pragma mark - External HTML normalization
134
+
135
+ /**
136
+ * Normalizes external HTML (from Google Docs, Word, web pages, etc.) into our
137
+ * canonical tag subset using the Gumbo-based C++ normalizer.
138
+ *
139
+ * Converts: strong → b, em → i, span style="font-weight:bold" → b,
140
+ * strips unknown tags while preserving text
141
+ */
142
+ + (NSString *_Nullable)normalizeExternalHtml:(NSString *_Nonnull)html {
143
+ std::string result =
144
+ GumboParser::normalizeHtml(std::string([html UTF8String]));
145
+ if (result.empty())
146
+ return nil;
147
+ return [NSString stringWithUTF8String:result.c_str()];
148
+ }
149
+
150
+ + (void)finalizeTagEntry:(NSMutableString *)tagName
151
+ ongoingTags:(NSMutableDictionary *)ongoingTags
152
+ initiallyProcessedTags:(NSMutableArray *)processedTags
153
+ plainText:(NSMutableString *)plainText
154
+ precedingImageCount:(NSInteger *)precedingImageCount {
155
+ NSMutableArray *tagEntry = [[NSMutableArray alloc] init];
156
+
157
+ NSArray *tagData = ongoingTags[tagName];
158
+ if (tagData == nil) {
159
+ return;
160
+ }
161
+ NSInteger tagLocation = [((NSNumber *)tagData[0]) intValue];
162
+ NSInteger openImageCount = [((NSNumber *)tagData[1]) intValue];
163
+ NSInteger currentImageCount = *precedingImageCount;
164
+
165
+ // 'plainText' doesn't contain image placeholders yet, but the final
166
+ // NSTextStorage will, so each image adds one character that ranges here
167
+ // must account for. 'openImageCount' (captured when the tag opened) shifts
168
+ // the start past images finalized BEFORE this tag, while the diff against
169
+ // 'currentImageCount' extends the length to cover images finalized INSIDE
170
+ // it.
171
+ NSRange tagRange = NSMakeRange(tagLocation + openImageCount,
172
+ (plainText.length - tagLocation) +
173
+ (currentImageCount - openImageCount));
174
+
175
+ [tagEntry addObject:[tagName copy]];
176
+ [tagEntry addObject:[NSValue valueWithRange:tagRange]];
177
+ if (tagData.count > 2) {
178
+ [tagEntry addObject:[(NSString *)tagData[2] copy]];
179
+ }
180
+
181
+ [processedTags addObject:tagEntry];
182
+ [ongoingTags removeObjectForKey:tagName];
183
+
184
+ if ([tagName isEqualToString:@"img"]) {
185
+ (*precedingImageCount)++;
186
+ }
187
+ }
188
+
189
+ + (BOOL)isUlCheckboxList:(NSString *)params {
190
+ return ([params containsString:@"data-type=\"checkbox\""] ||
191
+ [params containsString:@"data-type='checkbox'"]);
192
+ }
193
+
194
+ + (NSDictionary *)prepareCheckboxListStyleValue:(NSValue *)rangeValue
195
+ checkboxStates:(NSDictionary *)checkboxStates {
196
+ NSRange range = [rangeValue rangeValue];
197
+ NSMutableDictionary *statesInRange = [[NSMutableDictionary alloc] init];
198
+
199
+ for (NSNumber *key in checkboxStates) {
200
+ NSUInteger pos = [key unsignedIntegerValue];
201
+ if (pos >= range.location && pos < range.location + range.length) {
202
+ [statesInRange setObject:checkboxStates[key] forKey:key];
203
+ }
204
+ }
205
+
206
+ return statesInRange;
207
+ }
208
+
209
+ + (NSString *_Nullable)initiallyProcessHtml:(NSString *_Nonnull)html
210
+ useHtmlNormalizer:(BOOL)useHtmlNormalizer {
211
+ NSString *htmlWithoutSpaces = [self stripExtraWhiteSpacesAndNewlines:html];
212
+ NSString *fixedHtml = nullptr;
213
+
214
+ if (htmlWithoutSpaces.length >= 13) {
215
+ NSString *firstSix =
216
+ [htmlWithoutSpaces substringWithRange:NSMakeRange(0, 6)];
217
+ NSString *lastSeven = [htmlWithoutSpaces
218
+ substringWithRange:NSMakeRange(htmlWithoutSpaces.length - 7, 7)];
219
+
220
+ if ([firstSix isEqualToString:@"<html>"] &&
221
+ [lastSeven isEqualToString:@"</html>"]) {
222
+ // remove html tags, might be with newlines or without them
223
+ fixedHtml = [htmlWithoutSpaces copy];
224
+ // firstly remove newlined html tags if any:
225
+ fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<html>\n"
226
+ withString:@""];
227
+ fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"\n</html>"
228
+ withString:@""];
229
+ // fallback; remove html tags without their newlines
230
+ fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<html>"
231
+ withString:@""];
232
+ fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"</html>"
233
+ withString:@""];
234
+ } else if (useHtmlNormalizer) {
235
+ // External HTML (from Google Docs, Word, web pages, etc.)
236
+ // Run through the Gumbo-based normalizer to convert arbitrary HTML
237
+ // into our canonical tag subset.
238
+ NSString *normalized = [self normalizeExternalHtml:html];
239
+ if (normalized != nil) {
240
+ fixedHtml = normalized;
241
+ }
242
+ }
243
+
244
+ // Additionally, try getting the content from between body tags if there are
245
+ // some:
246
+
247
+ // Firstly make sure there are no newlines between them.
248
+ fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<body>\n"
249
+ withString:@"<body>"];
250
+ fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"\n</body>"
251
+ withString:@"</body>"];
252
+ // Then, if there actually are body tags, use the content between them.
253
+ NSRange openingBodyRange = [htmlWithoutSpaces rangeOfString:@"<body>"];
254
+ NSRange closingBodyRange = [htmlWithoutSpaces rangeOfString:@"</body>"];
255
+ if (openingBodyRange.length != 0 && closingBodyRange.length != 0) {
256
+ NSInteger newStart = openingBodyRange.location + 6;
257
+ NSInteger newEnd = closingBodyRange.location - 1;
258
+ fixedHtml = [htmlWithoutSpaces
259
+ substringWithRange:NSMakeRange(newStart, newEnd - newStart + 1)];
260
+ }
261
+ }
262
+
263
+ // second processing - try fixing htmls with wrong newlines' setup
264
+ if (fixedHtml != nullptr) {
265
+ // add <br> tag wherever needed
266
+ fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<p></p>"
267
+ withString:@"<br>"];
268
+
269
+ // remove <p> tags inside of <li>
270
+ fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<li><p>"
271
+ withString:@"<li>"];
272
+ fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"</p></li>"
273
+ withString:@"</li>"];
274
+
275
+ // change <br/> to <br>
276
+ fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<br/>"
277
+ withString:@"<br>"];
278
+
279
+ // remove <p> tags around <br>
280
+ fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<p><br>"
281
+ withString:@"<br>"];
282
+ fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<br></p>"
283
+ withString:@"<br>"];
284
+
285
+ // add <br> tags inside empty blockquote and codeblock tags
286
+ fixedHtml = [fixedHtml
287
+ stringByReplacingOccurrencesOfString:@"<blockquote></blockquote>"
288
+ withString:@"<blockquote><br></"
289
+ @"blockquote>"];
290
+ fixedHtml = [fixedHtml
291
+ stringByReplacingOccurrencesOfString:@"<codeblock></codeblock>"
292
+ withString:@"<codeblock><br></codeblock>"];
293
+
294
+ // remove empty ul and ol tags
295
+ fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<ul></ul>"
296
+ withString:@""];
297
+ fixedHtml = [fixedHtml
298
+ stringByReplacingOccurrencesOfString:@"<ul data-type=\"checkbox\"></ul>"
299
+ withString:@""];
300
+ fixedHtml = [fixedHtml stringByReplacingOccurrencesOfString:@"<ol></ol>"
301
+ withString:@""];
302
+
303
+ // tags that have to be in separate lines
304
+ fixedHtml = [self stringByAddingNewlinesToTag:@"<br>"
305
+ inString:fixedHtml
306
+ leading:YES
307
+ trailing:YES];
308
+ fixedHtml = [self stringByAddingNewlinesToTag:@"<ul>"
309
+ inString:fixedHtml
310
+ leading:YES
311
+ trailing:YES];
312
+ fixedHtml = [self stringByAddingNewlinesToTag:@"</ul>"
313
+ inString:fixedHtml
314
+ leading:YES
315
+ trailing:YES];
316
+ fixedHtml = [self stringByAddingNewlinesToTag:@"<ol>"
317
+ inString:fixedHtml
318
+ leading:YES
319
+ trailing:YES];
320
+ fixedHtml = [self stringByAddingNewlinesToTag:@"</ol>"
321
+ inString:fixedHtml
322
+ leading:YES
323
+ trailing:YES];
324
+ fixedHtml = [self stringByAddingNewlinesToTag:@"<blockquote>"
325
+ inString:fixedHtml
326
+ leading:YES
327
+ trailing:YES];
328
+ fixedHtml = [self stringByAddingNewlinesToTag:@"</blockquote>"
329
+ inString:fixedHtml
330
+ leading:YES
331
+ trailing:YES];
332
+ fixedHtml = [self stringByAddingNewlinesToTag:@"<codeblock>"
333
+ inString:fixedHtml
334
+ leading:YES
335
+ trailing:YES];
336
+ fixedHtml = [self stringByAddingNewlinesToTag:@"</codeblock>"
337
+ inString:fixedHtml
338
+ leading:YES
339
+ trailing:YES];
340
+
341
+ // line opening tags
342
+ fixedHtml = [self stringByAddingNewlinesToTag:@"<p>"
343
+ inString:fixedHtml
344
+ leading:YES
345
+ trailing:NO];
346
+ fixedHtml = [self stringByAddingNewlinesToTag:@"<li>"
347
+ inString:fixedHtml
348
+ leading:YES
349
+ trailing:NO];
350
+ fixedHtml = [self stringByAddingNewlinesToTag:@"<li checked>"
351
+ inString:fixedHtml
352
+ leading:YES
353
+ trailing:NO];
354
+ fixedHtml = [self stringByAddingNewlinesToTag:@"<h1>"
355
+ inString:fixedHtml
356
+ leading:YES
357
+ trailing:NO];
358
+ fixedHtml = [self stringByAddingNewlinesToTag:@"<h2>"
359
+ inString:fixedHtml
360
+ leading:YES
361
+ trailing:NO];
362
+ fixedHtml = [self stringByAddingNewlinesToTag:@"<h3>"
363
+ inString:fixedHtml
364
+ leading:YES
365
+ trailing:NO];
366
+ fixedHtml = [self stringByAddingNewlinesToTag:@"<h4>"
367
+ inString:fixedHtml
368
+ leading:YES
369
+ trailing:NO];
370
+ fixedHtml = [self stringByAddingNewlinesToTag:@"<h5>"
371
+ inString:fixedHtml
372
+ leading:YES
373
+ trailing:NO];
374
+ fixedHtml = [self stringByAddingNewlinesToTag:@"<h6>"
375
+ inString:fixedHtml
376
+ leading:YES
377
+ trailing:NO];
378
+
379
+ // line closing tags
380
+ fixedHtml = [self stringByAddingNewlinesToTag:@"</p>"
381
+ inString:fixedHtml
382
+ leading:NO
383
+ trailing:YES];
384
+ fixedHtml = [self stringByAddingNewlinesToTag:@"</li>"
385
+ inString:fixedHtml
386
+ leading:NO
387
+ trailing:YES];
388
+ fixedHtml = [self stringByAddingNewlinesToTag:@"</h1>"
389
+ inString:fixedHtml
390
+ leading:NO
391
+ trailing:YES];
392
+ fixedHtml = [self stringByAddingNewlinesToTag:@"</h2>"
393
+ inString:fixedHtml
394
+ leading:NO
395
+ trailing:YES];
396
+ fixedHtml = [self stringByAddingNewlinesToTag:@"</h3>"
397
+ inString:fixedHtml
398
+ leading:NO
399
+ trailing:YES];
400
+ fixedHtml = [self stringByAddingNewlinesToTag:@"</h4>"
401
+ inString:fixedHtml
402
+ leading:NO
403
+ trailing:YES];
404
+ fixedHtml = [self stringByAddingNewlinesToTag:@"</h5>"
405
+ inString:fixedHtml
406
+ leading:NO
407
+ trailing:YES];
408
+ fixedHtml = [self stringByAddingNewlinesToTag:@"</h6>"
409
+ inString:fixedHtml
410
+ leading:NO
411
+ trailing:YES];
412
+ }
413
+
414
+ return fixedHtml;
415
+ }
416
+
417
+ + (NSArray *_Nonnull)getTextAndStylesFromHtml:(NSString *_Nonnull)fixedHtml {
418
+ NSMutableString *plainText = [[NSMutableString alloc] initWithString:@""];
419
+ NSMutableDictionary *ongoingTags = [[NSMutableDictionary alloc] init];
420
+ NSMutableArray *initiallyProcessedTags = [[NSMutableArray alloc] init];
421
+ NSMutableDictionary *checkboxStates = [[NSMutableDictionary alloc] init];
422
+ NSMutableArray<AlignmentEntry *> *foundAlignments =
423
+ [[NSMutableArray alloc] init];
424
+ BOOL insideCheckboxList = NO;
425
+ NSInteger precedingImageCount = 0;
426
+ BOOL insideTag = NO;
427
+ BOOL gettingTagName = NO;
428
+ BOOL gettingTagParams = NO;
429
+ BOOL closingTag = NO;
430
+ BOOL lastTagWasBr = NO;
431
+ NSMutableString *currentTagName =
432
+ [[NSMutableString alloc] initWithString:@""];
433
+ NSMutableString *currentTagParams =
434
+ [[NSMutableString alloc] initWithString:@""];
435
+ NSDictionary *htmlEntitiesDict =
436
+ [NSString getEscapedCharactersInfoFrom:fixedHtml];
437
+
438
+ // firstly, extract text and initially processed tags
439
+ for (int i = 0; i < fixedHtml.length; i++) {
440
+ NSString *currentCharacterStr =
441
+ [fixedHtml substringWithRange:NSMakeRange(i, 1)];
442
+ unichar currentCharacterChar = [fixedHtml characterAtIndex:i];
443
+
444
+ if (currentCharacterChar == '<') {
445
+ // opening the tag, mark that we are inside and getting its name
446
+ insideTag = YES;
447
+ gettingTagName = YES;
448
+ } else if (currentCharacterChar == '>') {
449
+ // finishing some tag, no longer marked as inside or getting its
450
+ // name/params
451
+ insideTag = NO;
452
+ gettingTagName = NO;
453
+ gettingTagParams = NO;
454
+
455
+ BOOL isSelfClosing = NO;
456
+
457
+ // Check if params ended with '/' (e.g. <img src="" />)
458
+ if ([currentTagParams hasSuffix:@"/"]) {
459
+ [currentTagParams
460
+ deleteCharactersInRange:NSMakeRange(currentTagParams.length - 1,
461
+ 1)];
462
+ isSelfClosing = YES;
463
+ }
464
+
465
+ if ([currentTagName isEqualToString:@"br"]) {
466
+ lastTagWasBr = YES;
467
+ // do nothing, we don't include these tags in styles
468
+ } else if ([currentTagName isEqualToString:@"li"]) {
469
+ if (!closingTag) {
470
+ // Opening tag <li>
471
+ // Track checkbox state if we're inside a checkbox list
472
+ if (insideCheckboxList) {
473
+ BOOL isChecked = [currentTagParams containsString:@"checked"];
474
+ checkboxStates[@(plainText.length)] = @(isChecked);
475
+ }
476
+ // Record the start location so we can check if it's empty when
477
+ // closing
478
+ ongoingTags[@"li"] = @[ @(plainText.length) ];
479
+ } else {
480
+ // Closing tag </li>
481
+ NSArray *tagData = ongoingTags[@"li"];
482
+ if (tagData != nil) {
483
+ NSInteger tagLocation = [((NSNumber *)tagData[0]) intValue];
484
+ NSString *innerContent = [plainText substringFromIndex:tagLocation];
485
+
486
+ // If the li is completely empty (or just contains layout newlines),
487
+ // inject ZWS
488
+ if ([innerContent
489
+ stringByTrimmingCharactersInSet:[NSCharacterSet
490
+ newlineCharacterSet]]
491
+ .length == 0) {
492
+ [plainText appendString:@"\u200B"];
493
+ }
494
+ [ongoingTags removeObjectForKey:@"li"];
495
+ }
496
+ }
497
+ } else if (!closingTag) {
498
+ BOOL isPlainParagraph = [currentTagName isEqualToString:@"p"] &&
499
+ currentTagParams.length == 0;
500
+
501
+ if (!isPlainParagraph) {
502
+ // we finish opening tag - get its location, the current
503
+ // precedingImageCount and optionally params and put them under tag
504
+ // name key in ongoingTags. Storing the open-time image count lets
505
+ // finalizeTagEntry: correctly shift the start and extend the length
506
+ // so the range covers any images finalized between open and close.
507
+ NSMutableArray *tagArr = [[NSMutableArray alloc] init];
508
+ [tagArr addObject:[NSNumber numberWithInteger:plainText.length]];
509
+ [tagArr addObject:[NSNumber numberWithInteger:precedingImageCount]];
510
+ if (currentTagParams.length > 0) {
511
+ [tagArr addObject:[currentTagParams copy]];
512
+ }
513
+ ongoingTags[currentTagName] = tagArr;
514
+
515
+ // Check if this is a checkbox list
516
+ if ([currentTagName isEqualToString:@"ul"] &&
517
+ [self isUlCheckboxList:currentTagParams]) {
518
+ insideCheckboxList = YES;
519
+ }
520
+
521
+ // skip one newline if it was added after opening tags that are in
522
+ // separate lines
523
+ if ([self isBlockTag:currentTagName] && i + 1 < fixedHtml.length &&
524
+ [[NSCharacterSet newlineCharacterSet]
525
+ characterIsMember:[fixedHtml characterAtIndex:i + 1]]) {
526
+ i += 1;
527
+ }
528
+
529
+ if ([currentTagName isEqualToString:@"img"]) {
530
+ // Images have no inner text, so we manually break the <br> streak
531
+ // here.
532
+ lastTagWasBr = NO;
533
+ }
534
+
535
+ if (isSelfClosing) {
536
+ [self finalizeTagEntry:currentTagName
537
+ ongoingTags:ongoingTags
538
+ initiallyProcessedTags:initiallyProcessedTags
539
+ plainText:plainText
540
+ precedingImageCount:&precedingImageCount];
541
+ }
542
+ }
543
+ } else {
544
+ // we finish closing tags - pack tag name, tag range and optionally tag
545
+ // params into an entry that goes inside initiallyProcessedTags
546
+
547
+ // Check if we're closing a checkbox list by looking at the params
548
+ if ([currentTagName isEqualToString:@"ul"] &&
549
+ [self isUlCheckboxList:currentTagParams]) {
550
+ insideCheckboxList = NO;
551
+ }
552
+
553
+ BOOL isBlockTag = [self isBlockTag:currentTagName];
554
+
555
+ // ZWS logic for blockquote and codeblock
556
+ BOOL needsZWS = [currentTagName isEqualToString:@"blockquote"] ||
557
+ [currentTagName isEqualToString:@"codeblock"];
558
+ BOOL isEmptyBlock = NO;
559
+ if (needsZWS) {
560
+ NSArray *tagData = ongoingTags[currentTagName];
561
+ if (tagData != nil) {
562
+ NSInteger tagLoc = [tagData[0] intValue];
563
+ NSString *inner = [plainText substringFromIndex:tagLoc];
564
+ if ([inner stringByTrimmingCharactersInSet:[NSCharacterSet
565
+ newlineCharacterSet]]
566
+ .length == 0) {
567
+ isEmptyBlock = YES;
568
+ }
569
+ }
570
+ }
571
+
572
+ // skip one newline if it was added before some closing tags that are
573
+ // in separate lines
574
+ if (isBlockTag && plainText.length > 0 &&
575
+ [[NSCharacterSet newlineCharacterSet]
576
+ characterIsMember:[plainText
577
+ characterAtIndex:plainText.length - 1]]) {
578
+
579
+ // If the last thing processed was a <br>, or the block is totally
580
+ // empty, inject a \u200B before trimming the trailing newline to save
581
+ // the empty line.
582
+ if (lastTagWasBr || isEmptyBlock) {
583
+ [plainText insertString:@"\u200B" atIndex:plainText.length - 1];
584
+ }
585
+ plainText = [[plainText
586
+ substringWithRange:NSMakeRange(0, plainText.length - 1)]
587
+ mutableCopy];
588
+ }
589
+
590
+ [self checkForAlignments:ongoingTags[currentTagName]
591
+ plainText:plainText
592
+ foundAlignments:foundAlignments
593
+ precedingImageCount:precedingImageCount];
594
+ [self finalizeTagEntry:currentTagName
595
+ ongoingTags:ongoingTags
596
+ initiallyProcessedTags:initiallyProcessedTags
597
+ plainText:plainText
598
+ precedingImageCount:&precedingImageCount];
599
+ }
600
+ // post-tag cleanup
601
+ closingTag = NO;
602
+ currentTagName = [[NSMutableString alloc] initWithString:@""];
603
+ currentTagParams = [[NSMutableString alloc] initWithString:@""];
604
+ } else {
605
+ if (!insideTag) {
606
+ // no tags logic - just append the right text
607
+
608
+ // html entity on the index; use unescaped character and forward
609
+ // iterator accordingly
610
+ NSArray *entityInfo = htmlEntitiesDict[@(i)];
611
+ if (entityInfo != nullptr) {
612
+ NSString *escaped = entityInfo[0];
613
+ NSString *unescaped = entityInfo[1];
614
+ [plainText appendString:unescaped];
615
+ // the iterator will forward by 1 itself
616
+ i += escaped.length - 1;
617
+ } else {
618
+ [plainText appendString:currentCharacterStr];
619
+ // Any typed character that isn't a newline breaks the <br> streak
620
+ if (![[NSCharacterSet newlineCharacterSet]
621
+ characterIsMember:currentCharacterChar]) {
622
+ lastTagWasBr = NO;
623
+ }
624
+ }
625
+ } else {
626
+ if (gettingTagName) {
627
+ if (currentCharacterChar == ' ') {
628
+ // no longer getting tag name - switch to params
629
+ gettingTagName = NO;
630
+ gettingTagParams = YES;
631
+ } else if (currentCharacterChar == '/') {
632
+ // mark that the tag is closing
633
+ closingTag = YES;
634
+ } else {
635
+ // append next tag char
636
+ [currentTagName appendString:currentCharacterStr];
637
+ }
638
+ } else if (gettingTagParams) {
639
+ // append next tag params char
640
+ [currentTagParams appendString:currentCharacterStr];
641
+ }
642
+ }
643
+ }
644
+ }
645
+
646
+ // process tags into proper StyleType + StylePair values
647
+ NSMutableArray *processedStyles = [[NSMutableArray alloc] init];
648
+
649
+ for (NSArray *arr in initiallyProcessedTags) {
650
+ NSString *tagName = (NSString *)arr[0];
651
+ NSValue *tagRangeValue = (NSValue *)arr[1];
652
+ NSMutableString *params = [[NSMutableString alloc] initWithString:@""];
653
+ if (arr.count > 2) {
654
+ [params appendString:(NSString *)arr[2]];
655
+ }
656
+
657
+ NSMutableArray *styleArr = [[NSMutableArray alloc] init];
658
+ StylePair *stylePair = [[StylePair alloc] init];
659
+
660
+ if ([tagName isEqualToString:@"b"]) {
661
+ [styleArr addObject:@([BoldStyle getType])];
662
+ } else if ([tagName isEqualToString:@"i"]) {
663
+ [styleArr addObject:@([ItalicStyle getType])];
664
+ } else if ([tagName isEqualToString:@"img"]) {
665
+ NSRegularExpression *srcRegex =
666
+ [NSRegularExpression regularExpressionWithPattern:@"src=\"([^\"]+)\""
667
+ options:0
668
+ error:nullptr];
669
+ NSTextCheckingResult *match =
670
+ [srcRegex firstMatchInString:params
671
+ options:0
672
+ range:NSMakeRange(0, params.length)];
673
+
674
+ if (match == nullptr) {
675
+ continue;
676
+ }
677
+
678
+ NSRange srcRange = match.range;
679
+ [styleArr addObject:@([ImageStyle getType])];
680
+ // cut only the uri from the src="..." string
681
+ NSString *uri =
682
+ [params substringWithRange:NSMakeRange(srcRange.location + 5,
683
+ srcRange.length - 6)];
684
+ ImageData *imageData = [[ImageData alloc] init];
685
+ imageData.uri = uri;
686
+
687
+ NSRegularExpression *widthRegex = [NSRegularExpression
688
+ regularExpressionWithPattern:@"width=\"([0-9.]+)\""
689
+ options:0
690
+ error:nil];
691
+ NSTextCheckingResult *widthMatch =
692
+ [widthRegex firstMatchInString:params
693
+ options:0
694
+ range:NSMakeRange(0, params.length)];
695
+
696
+ if (widthMatch) {
697
+ NSString *widthString =
698
+ [params substringWithRange:[widthMatch rangeAtIndex:1]];
699
+ imageData.width = [widthString floatValue];
700
+ }
701
+
702
+ NSRegularExpression *heightRegex = [NSRegularExpression
703
+ regularExpressionWithPattern:@"height=\"([0-9.]+)\""
704
+ options:0
705
+ error:nil];
706
+ NSTextCheckingResult *heightMatch =
707
+ [heightRegex firstMatchInString:params
708
+ options:0
709
+ range:NSMakeRange(0, params.length)];
710
+
711
+ if (heightMatch) {
712
+ NSString *heightString =
713
+ [params substringWithRange:[heightMatch rangeAtIndex:1]];
714
+ imageData.height = [heightString floatValue];
715
+ }
716
+
717
+ stylePair.styleValue = imageData;
718
+ } else if ([tagName isEqualToString:@"u"]) {
719
+ [styleArr addObject:@([UnderlineStyle getType])];
720
+ } else if ([tagName isEqualToString:@"s"]) {
721
+ [styleArr addObject:@([StrikethroughStyle getType])];
722
+ } else if ([tagName isEqualToString:@"code"]) {
723
+ [styleArr addObject:@([InlineCodeStyle getType])];
724
+ } else if ([tagName isEqualToString:@"a"]) {
725
+ NSRegularExpression *hrefRegex =
726
+ [NSRegularExpression regularExpressionWithPattern:@"href=\".+\""
727
+ options:0
728
+ error:nullptr];
729
+ NSTextCheckingResult *match =
730
+ [hrefRegex firstMatchInString:params
731
+ options:0
732
+ range:NSMakeRange(0, params.length)];
733
+
734
+ if (match == nullptr) {
735
+ // same as on Android, no href (or empty href) equals no link style
736
+ continue;
737
+ }
738
+
739
+ NSRange hrefRange = match.range;
740
+ [styleArr addObject:@([LinkStyle getType])];
741
+ // cut only the url from the href="..." string
742
+ NSString *url =
743
+ [params substringWithRange:NSMakeRange(hrefRange.location + 6,
744
+ hrefRange.length - 7)];
745
+ NSString *text = [plainText substringWithRange:tagRangeValue.rangeValue];
746
+
747
+ LinkData *linkData = [[LinkData alloc] init];
748
+ linkData.url = url;
749
+ linkData.text = text;
750
+ linkData.isManual = ![text isEqualToString:url];
751
+
752
+ stylePair.styleValue = linkData;
753
+ } else if ([tagName isEqualToString:@"mention"]) {
754
+ [styleArr addObject:@([MentionStyle getType])];
755
+ // extract html expression into dict using some regex
756
+ NSMutableDictionary *paramsDict = [[NSMutableDictionary alloc] init];
757
+ NSString *pattern = @"(\\w+)=(['\"])(.*?)\\2";
758
+ NSRegularExpression *regex =
759
+ [NSRegularExpression regularExpressionWithPattern:pattern
760
+ options:0
761
+ error:nil];
762
+
763
+ [regex enumerateMatchesInString:params
764
+ options:0
765
+ range:NSMakeRange(0, params.length)
766
+ usingBlock:^(NSTextCheckingResult *_Nullable result,
767
+ NSMatchingFlags flags,
768
+ BOOL *_Nonnull stop) {
769
+ if (result.numberOfRanges == 4) {
770
+ NSString *key = [params
771
+ substringWithRange:[result rangeAtIndex:1]];
772
+ NSString *value = [params
773
+ substringWithRange:[result rangeAtIndex:3]];
774
+ paramsDict[key] = value;
775
+ }
776
+ }];
777
+
778
+ MentionParams *mentionParams = [[MentionParams alloc] init];
779
+ mentionParams.text = paramsDict[@"text"];
780
+ mentionParams.indicator = paramsDict[@"indicator"];
781
+
782
+ [paramsDict removeObjectsForKeys:@[ @"text", @"indicator" ]];
783
+ NSError *error;
784
+ NSData *attrsData = [NSJSONSerialization dataWithJSONObject:paramsDict
785
+ options:0
786
+ error:&error];
787
+ NSString *formattedAttrsString =
788
+ [[NSString alloc] initWithData:attrsData
789
+ encoding:NSUTF8StringEncoding];
790
+ mentionParams.attributes = formattedAttrsString;
791
+
792
+ stylePair.styleValue = mentionParams;
793
+ } else if ([tagName isEqualToString:@"h1"]) {
794
+ [styleArr addObject:@([H1Style getType])];
795
+ } else if ([tagName isEqualToString:@"h2"]) {
796
+ [styleArr addObject:@([H2Style getType])];
797
+ } else if ([tagName isEqualToString:@"h3"]) {
798
+ [styleArr addObject:@([H3Style getType])];
799
+ } else if ([tagName isEqualToString:@"h4"]) {
800
+ [styleArr addObject:@([H4Style getType])];
801
+ } else if ([tagName isEqualToString:@"h5"]) {
802
+ [styleArr addObject:@([H5Style getType])];
803
+ } else if ([tagName isEqualToString:@"h6"]) {
804
+ [styleArr addObject:@([H6Style getType])];
805
+ } else if ([tagName isEqualToString:@"ul"]) {
806
+ if ([self isUlCheckboxList:params]) {
807
+ [styleArr addObject:@([CheckboxListStyle getType])];
808
+ stylePair.styleValue =
809
+ [self prepareCheckboxListStyleValue:tagRangeValue
810
+ checkboxStates:checkboxStates];
811
+ } else {
812
+ [styleArr addObject:@([UnorderedListStyle getType])];
813
+ }
814
+ } else if ([tagName isEqualToString:@"ol"]) {
815
+ [styleArr addObject:@([OrderedListStyle getType])];
816
+ } else if ([tagName isEqualToString:@"blockquote"]) {
817
+ [styleArr addObject:@([BlockQuoteStyle getType])];
818
+ } else if ([tagName isEqualToString:@"codeblock"]) {
819
+ [styleArr addObject:@([CodeBlockStyle getType])];
820
+ } else {
821
+ // some other external tags like span just don't get put into the
822
+ // processed styles
823
+ continue;
824
+ }
825
+
826
+ stylePair.rangeValue = tagRangeValue;
827
+ [styleArr addObject:stylePair];
828
+ [processedStyles addObject:styleArr];
829
+ }
830
+
831
+ return @[ plainText, processedStyles, foundAlignments ];
832
+ }
833
+
834
+ + (NSString *)parseToHtmlFromRange:(NSRange)range
835
+ host:(id<EnrichedViewHost>)host {
836
+ NSInteger offset = range.location;
837
+ NSString *text = [host.textView.textStorage.string substringWithRange:range];
838
+
839
+ if (text.length == 0) {
840
+ return @"<html>\n<p></p>\n</html>";
841
+ }
842
+
843
+ NSMutableString *result = [[NSMutableString alloc] initWithString:@"<html>"];
844
+ NSSet<NSNumber *> *previousActiveStyles = [[NSSet<NSNumber *> alloc] init];
845
+ BOOL newLine = YES;
846
+ BOOL inUnorderedList = NO;
847
+ BOOL inOrderedList = NO;
848
+ BOOL inBlockQuote = NO;
849
+ BOOL inCodeBlock = NO;
850
+ BOOL inCheckboxList = NO;
851
+ unichar lastCharacter = 0;
852
+
853
+ for (int i = 0; i < text.length; i++) {
854
+ NSRange currentRange = NSMakeRange(offset + i, 1);
855
+ NSMutableSet<NSNumber *> *currentActiveStyles =
856
+ [[NSMutableSet<NSNumber *> alloc] init];
857
+ NSMutableDictionary *currentActiveStylesBeginning =
858
+ [[NSMutableDictionary alloc] init];
859
+
860
+ // check each existing style existence
861
+ for (NSNumber *type in host.stylesDict) {
862
+ StyleBase *style = host.stylesDict[type];
863
+ // we do not want to add <></> tags for alignment
864
+ if ([style isKindOfClass:[AlignmentStyle class]]) {
865
+ continue;
866
+ }
867
+ if ([style detect:currentRange]) {
868
+ [currentActiveStyles addObject:type];
869
+
870
+ if (![previousActiveStyles member:type]) {
871
+ currentActiveStylesBeginning[type] = [NSNumber numberWithInt:i];
872
+ }
873
+ } else if ([previousActiveStyles member:type]) {
874
+ [currentActiveStylesBeginning removeObjectForKey:type];
875
+ }
876
+ }
877
+
878
+ NSString *currentCharacterStr =
879
+ [host.textView.textStorage.string substringWithRange:currentRange];
880
+ unichar currentCharacterChar = [host.textView.textStorage.string
881
+ characterAtIndex:currentRange.location];
882
+
883
+ if ([[NSCharacterSet newlineCharacterSet]
884
+ characterIsMember:currentCharacterChar]) {
885
+ if (newLine) {
886
+ // we can either have an empty list item OR need to close the list and
887
+ // put a BR in such a situation the existence of the list must be
888
+ // checked on 0 length range, not on the newline character
889
+ if (inOrderedList) {
890
+ OrderedListStyle *oStyle = host.stylesDict[@(OrderedList)];
891
+ BOOL detected = [oStyle detect:NSMakeRange(currentRange.location, 0)];
892
+ if (detected) {
893
+ [result appendString:@"\n<li></li>"];
894
+ } else {
895
+ [result appendString:@"\n</ol>\n<br>"];
896
+ inOrderedList = NO;
897
+ }
898
+ } else if (inUnorderedList) {
899
+ UnorderedListStyle *uStyle = host.stylesDict[@(UnorderedList)];
900
+ BOOL detected = [uStyle detect:NSMakeRange(currentRange.location, 0)];
901
+ if (detected) {
902
+ [result appendString:@"\n<li></li>"];
903
+ } else {
904
+ [result appendString:@"\n</ul>\n<br>"];
905
+ inUnorderedList = NO;
906
+ }
907
+ } else if (inBlockQuote) {
908
+ BlockQuoteStyle *bqStyle = host.stylesDict[@(BlockQuote)];
909
+ BOOL detected =
910
+ [bqStyle detect:NSMakeRange(currentRange.location, 0)];
911
+ if (detected) {
912
+ [result appendString:@"\n<br>"];
913
+ } else {
914
+ [result appendString:@"\n</blockquote>\n<br>"];
915
+ inBlockQuote = NO;
916
+ }
917
+ } else if (inCodeBlock) {
918
+ CodeBlockStyle *cbStyle = host.stylesDict[@(CodeBlock)];
919
+ BOOL detected =
920
+ [cbStyle detect:NSMakeRange(currentRange.location, 0)];
921
+ if (detected) {
922
+ [result appendString:@"\n<br>"];
923
+ } else {
924
+ [result appendString:@"\n</codeblock>\n<br>"];
925
+ inCodeBlock = NO;
926
+ }
927
+ } else if (inCheckboxList) {
928
+ CheckboxListStyle *cbLStyle = host.stylesDict[@(CheckboxList)];
929
+ BOOL detected =
930
+ [cbLStyle detect:NSMakeRange(currentRange.location, 0)];
931
+ if (detected) {
932
+ BOOL checked = [cbLStyle getCheckboxStateAt:currentRange.location];
933
+ if (checked) {
934
+ [result appendString:@"\n<li checked></li>"];
935
+ } else {
936
+ [result appendString:@"\n<li></li>"];
937
+ }
938
+ } else {
939
+ [result appendString:@"\n</ul>\n<br>"];
940
+ inCheckboxList = NO;
941
+ }
942
+ } else {
943
+ [result appendString:@"\n<br>"];
944
+ }
945
+ } else {
946
+ // newline finishes a paragraph and all style tags need to be closed
947
+ // we use previous styles
948
+ NSArray<NSNumber *> *sortedEndedStyles = [previousActiveStyles
949
+ sortedArrayUsingDescriptors:@[ [NSSortDescriptor
950
+ sortDescriptorWithKey:@"intValue"
951
+ ascending:NO] ]];
952
+
953
+ // append closing tags
954
+ for (NSNumber *style in sortedEndedStyles) {
955
+ if ([style isEqualToNumber:@([ImageStyle getType])]) {
956
+ continue;
957
+ }
958
+ NSString *tagContent = [self tagContentForStyle:style
959
+ openingTag:NO
960
+ location:currentRange.location
961
+ host:host];
962
+ [result
963
+ appendString:[NSString stringWithFormat:@"</%@>", tagContent]];
964
+ }
965
+
966
+ // append closing paragraph tag
967
+ if ([previousActiveStyles
968
+ containsObject:@([UnorderedListStyle getType])] ||
969
+ [previousActiveStyles
970
+ containsObject:@([OrderedListStyle getType])] ||
971
+ [previousActiveStyles containsObject:@([H1Style getType])] ||
972
+ [previousActiveStyles containsObject:@([H2Style getType])] ||
973
+ [previousActiveStyles containsObject:@([H3Style getType])] ||
974
+ [previousActiveStyles containsObject:@([H4Style getType])] ||
975
+ [previousActiveStyles containsObject:@([H5Style getType])] ||
976
+ [previousActiveStyles containsObject:@([H6Style getType])] ||
977
+ [previousActiveStyles
978
+ containsObject:@([BlockQuoteStyle getType])] ||
979
+ [previousActiveStyles containsObject:@([CodeBlockStyle getType])] ||
980
+ [previousActiveStyles
981
+ containsObject:@([CheckboxListStyle getType])]) {
982
+ // do nothing, proper closing paragraph tags have been already
983
+ // appended
984
+ } else {
985
+ [result appendString:@"</p>"];
986
+ }
987
+ }
988
+
989
+ // clear the previous styles
990
+ previousActiveStyles = [[NSSet<NSNumber *> alloc] init];
991
+
992
+ // next character opens new paragraph
993
+ newLine = YES;
994
+ } else {
995
+ // new line - open the paragraph
996
+ if (newLine) {
997
+ newLine = NO;
998
+
999
+ // handle ending unordered list
1000
+ if (inUnorderedList &&
1001
+ ![currentActiveStyles
1002
+ containsObject:@([UnorderedListStyle getType])]) {
1003
+ inUnorderedList = NO;
1004
+ [result appendString:@"\n</ul>"];
1005
+ }
1006
+ // handle ending ordered list
1007
+ if (inOrderedList &&
1008
+ ![currentActiveStyles
1009
+ containsObject:@([OrderedListStyle getType])]) {
1010
+ inOrderedList = NO;
1011
+ [result appendString:@"\n</ol>"];
1012
+ }
1013
+ // handle ending blockquotes
1014
+ if (inBlockQuote && ![currentActiveStyles
1015
+ containsObject:@([BlockQuoteStyle getType])]) {
1016
+ inBlockQuote = NO;
1017
+ [result appendString:@"\n</blockquote>"];
1018
+ }
1019
+ // handle ending codeblock
1020
+ if (inCodeBlock &&
1021
+ ![currentActiveStyles containsObject:@([CodeBlockStyle getType])]) {
1022
+ inCodeBlock = NO;
1023
+ [result appendString:@"\n</codeblock>"];
1024
+ }
1025
+ // handle ending checkbox list
1026
+ if (inCheckboxList &&
1027
+ ![currentActiveStyles
1028
+ containsObject:@([CheckboxListStyle getType])]) {
1029
+ inCheckboxList = NO;
1030
+ [result appendString:@"\n</ul>"];
1031
+ }
1032
+
1033
+ NSString *cssStyleString =
1034
+ [self prepareCssStyleString:currentRange.location
1035
+ isOpeningTag:YES
1036
+ host:host];
1037
+
1038
+ // handle starting unordered list
1039
+ if (!inUnorderedList &&
1040
+ [currentActiveStyles
1041
+ containsObject:@([UnorderedListStyle getType])]) {
1042
+ inUnorderedList = YES;
1043
+ [result appendString:[NSString stringWithFormat:@"\n<ul%@>",
1044
+ cssStyleString]];
1045
+ }
1046
+ // handle starting ordered list
1047
+ if (!inOrderedList &&
1048
+ [currentActiveStyles
1049
+ containsObject:@([OrderedListStyle getType])]) {
1050
+ inOrderedList = YES;
1051
+ [result appendString:[NSString stringWithFormat:@"\n<ol%@>",
1052
+ cssStyleString]];
1053
+ }
1054
+ // handle starting blockquotes
1055
+ if (!inBlockQuote &&
1056
+ [currentActiveStyles containsObject:@([BlockQuoteStyle getType])]) {
1057
+ inBlockQuote = YES;
1058
+ [result appendString:@"\n<blockquote>"];
1059
+ }
1060
+ // handle starting codeblock
1061
+ if (!inCodeBlock &&
1062
+ [currentActiveStyles containsObject:@([CodeBlockStyle getType])]) {
1063
+ inCodeBlock = YES;
1064
+ [result appendString:@"\n<codeblock>"];
1065
+ }
1066
+ // handle starting checkbox list
1067
+ if (!inCheckboxList &&
1068
+ [currentActiveStyles
1069
+ containsObject:@([CheckboxListStyle getType])]) {
1070
+ inCheckboxList = YES;
1071
+ [result appendString:[NSString stringWithFormat:
1072
+ @"\n<ul data-type=\"checkbox\"%@>",
1073
+ cssStyleString]];
1074
+ }
1075
+
1076
+ // don't add the <p> tag if some paragraph styles are present
1077
+ if ([currentActiveStyles
1078
+ containsObject:@([UnorderedListStyle getType])] ||
1079
+ [currentActiveStyles
1080
+ containsObject:@([OrderedListStyle getType])] ||
1081
+ [currentActiveStyles containsObject:@([H1Style getType])] ||
1082
+ [currentActiveStyles containsObject:@([H2Style getType])] ||
1083
+ [currentActiveStyles containsObject:@([H3Style getType])] ||
1084
+ [currentActiveStyles containsObject:@([H4Style getType])] ||
1085
+ [currentActiveStyles containsObject:@([H5Style getType])] ||
1086
+ [currentActiveStyles containsObject:@([H6Style getType])] ||
1087
+ [currentActiveStyles containsObject:@([BlockQuoteStyle getType])] ||
1088
+ [currentActiveStyles containsObject:@([CodeBlockStyle getType])] ||
1089
+ [currentActiveStyles
1090
+ containsObject:@([CheckboxListStyle getType])]) {
1091
+ [result appendString:@"\n"];
1092
+ } else {
1093
+ [result appendString:[NSString stringWithFormat:@"\n<p%@>",
1094
+ cssStyleString]];
1095
+ }
1096
+ }
1097
+
1098
+ // get styles that have ended
1099
+ NSMutableSet<NSNumber *> *endedStyles =
1100
+ [previousActiveStyles mutableCopy];
1101
+ [endedStyles minusSet:currentActiveStyles];
1102
+
1103
+ // also finish styles that should be ended becasue they are nested in a
1104
+ // style that ended
1105
+ NSMutableSet *fixedEndedStyles = [endedStyles mutableCopy];
1106
+ NSMutableSet *stylesToBeReAdded = [[NSMutableSet alloc] init];
1107
+
1108
+ for (NSNumber *style in endedStyles) {
1109
+ NSInteger styleBeginning =
1110
+ [currentActiveStylesBeginning[style] integerValue];
1111
+
1112
+ for (NSNumber *activeStyle in currentActiveStyles) {
1113
+ NSInteger activeStyleBeginning =
1114
+ [currentActiveStylesBeginning[activeStyle] integerValue];
1115
+
1116
+ // we end the styles that began after the currently ended style but
1117
+ // not at the "i" (cause the old style ended at exactly "i-1" also the
1118
+ // ones that began in the exact same place but are "inner" in relation
1119
+ // to them due to StyleTypeEnum integer values
1120
+
1121
+ if ((activeStyleBeginning > styleBeginning &&
1122
+ activeStyleBeginning < i) ||
1123
+ (activeStyleBeginning == styleBeginning &&
1124
+ activeStyleBeginning<
1125
+ i && [activeStyle integerValue]>[style integerValue])) {
1126
+ [fixedEndedStyles addObject:activeStyle];
1127
+ [stylesToBeReAdded addObject:activeStyle];
1128
+ }
1129
+ }
1130
+ }
1131
+
1132
+ // if a style begins but there is a style inner to it that is (and was
1133
+ // previously) active, it also should be closed and readded
1134
+
1135
+ // newly added styles
1136
+ NSMutableSet *newStyles = [currentActiveStyles mutableCopy];
1137
+ [newStyles minusSet:previousActiveStyles];
1138
+ // styles that were and still are active
1139
+ NSMutableSet *stillActiveStyles = [previousActiveStyles mutableCopy];
1140
+ [stillActiveStyles intersectSet:currentActiveStyles];
1141
+
1142
+ for (NSNumber *style in newStyles) {
1143
+ for (NSNumber *ongoingStyle in stillActiveStyles) {
1144
+ if ([ongoingStyle integerValue] > [style integerValue]) {
1145
+ // the prev style is inner; needs to be closed and re-added later
1146
+ [fixedEndedStyles addObject:ongoingStyle];
1147
+ [stylesToBeReAdded addObject:ongoingStyle];
1148
+ }
1149
+ }
1150
+ }
1151
+
1152
+ // they are sorted in a descending order
1153
+ NSArray<NSNumber *> *sortedEndedStyles = [fixedEndedStyles
1154
+ sortedArrayUsingDescriptors:@[ [NSSortDescriptor
1155
+ sortDescriptorWithKey:@"intValue"
1156
+ ascending:NO] ]];
1157
+
1158
+ // append closing tags
1159
+ for (NSNumber *style in sortedEndedStyles) {
1160
+ if ([style isEqualToNumber:@([ImageStyle getType])]) {
1161
+ continue;
1162
+ }
1163
+ NSString *tagContent = [self tagContentForStyle:style
1164
+ openingTag:NO
1165
+ location:currentRange.location
1166
+ host:host];
1167
+ [result appendString:[NSString stringWithFormat:@"</%@>", tagContent]];
1168
+ }
1169
+
1170
+ // all styles that have begun: new styles + the ones that need to be
1171
+ // re-added they are sorted in a ascending manner to properly keep tags'
1172
+ // FILO order
1173
+ [newStyles unionSet:stylesToBeReAdded];
1174
+ NSArray<NSNumber *> *sortedNewStyles = [newStyles
1175
+ sortedArrayUsingDescriptors:@[ [NSSortDescriptor
1176
+ sortDescriptorWithKey:@"intValue"
1177
+ ascending:YES] ]];
1178
+
1179
+ // append opening tags
1180
+ for (NSNumber *style in sortedNewStyles) {
1181
+ NSString *tagContent = [self tagContentForStyle:style
1182
+ openingTag:YES
1183
+ location:currentRange.location
1184
+ host:host];
1185
+ if ([style isEqualToNumber:@([ImageStyle getType])]) {
1186
+ [result
1187
+ appendString:[NSString stringWithFormat:@"<%@/>", tagContent]];
1188
+ [currentActiveStyles removeObject:@([ImageStyle getType])];
1189
+ } else {
1190
+ [result appendString:[NSString stringWithFormat:@"<%@>", tagContent]];
1191
+ }
1192
+ }
1193
+
1194
+ // append the letter and escape it if needed
1195
+ [result appendString:[NSString stringByEscapingHtml:currentCharacterStr]];
1196
+
1197
+ // save current styles for next character's checks
1198
+ previousActiveStyles = currentActiveStyles;
1199
+ }
1200
+
1201
+ // set last character
1202
+ lastCharacter = currentCharacterChar;
1203
+ }
1204
+
1205
+ if (![[NSCharacterSet newlineCharacterSet] characterIsMember:lastCharacter]) {
1206
+ // not-newline character was last - finish the paragraph
1207
+ // close all pending tags
1208
+ NSArray<NSNumber *> *sortedEndedStyles = [previousActiveStyles
1209
+ sortedArrayUsingDescriptors:@[ [NSSortDescriptor
1210
+ sortDescriptorWithKey:@"intValue"
1211
+ ascending:NO] ]];
1212
+
1213
+ // append closing tags
1214
+ for (NSNumber *style in sortedEndedStyles) {
1215
+ if ([style isEqualToNumber:@([ImageStyle getType])]) {
1216
+ continue;
1217
+ }
1218
+ NSString *tagContent =
1219
+ [self tagContentForStyle:style
1220
+ openingTag:NO
1221
+ location:host.textView.textStorage.string.length - 1
1222
+ host:host];
1223
+ [result appendString:[NSString stringWithFormat:@"</%@>", tagContent]];
1224
+ }
1225
+
1226
+ // finish the paragraph
1227
+ // handle ending of some paragraph styles
1228
+ if ([previousActiveStyles containsObject:@([UnorderedListStyle getType])]) {
1229
+ [result appendString:@"\n</ul>"];
1230
+ } else if ([previousActiveStyles
1231
+ containsObject:@([OrderedListStyle getType])]) {
1232
+ [result appendString:@"\n</ol>"];
1233
+ } else if ([previousActiveStyles
1234
+ containsObject:@([BlockQuoteStyle getType])]) {
1235
+ [result appendString:@"\n</blockquote>"];
1236
+ } else if ([previousActiveStyles
1237
+ containsObject:@([CodeBlockStyle getType])]) {
1238
+ [result appendString:@"\n</codeblock>"];
1239
+ } else if ([previousActiveStyles
1240
+ containsObject:@([CheckboxListStyle getType])]) {
1241
+ [result appendString:@"\n</ul>"];
1242
+ } else if ([previousActiveStyles containsObject:@([H1Style getType])] ||
1243
+ [previousActiveStyles containsObject:@([H2Style getType])] ||
1244
+ [previousActiveStyles containsObject:@([H3Style getType])] ||
1245
+ [previousActiveStyles containsObject:@([H4Style getType])] ||
1246
+ [previousActiveStyles containsObject:@([H5Style getType])] ||
1247
+ [previousActiveStyles containsObject:@([H6Style getType])]) {
1248
+ // do nothing, heading closing tag has already been appended
1249
+ } else {
1250
+ [result appendString:@"</p>"];
1251
+ }
1252
+ } else {
1253
+ // newline character was last - some paragraph styles need to be closed
1254
+ if (inUnorderedList) {
1255
+ inUnorderedList = NO;
1256
+ [result appendString:@"\n</ul>"];
1257
+ }
1258
+ if (inOrderedList) {
1259
+ inOrderedList = NO;
1260
+ [result appendString:@"\n</ol>"];
1261
+ }
1262
+ if (inBlockQuote) {
1263
+ inBlockQuote = NO;
1264
+ [result appendString:@"\n</blockquote>"];
1265
+ }
1266
+ if (inCodeBlock) {
1267
+ inCodeBlock = NO;
1268
+ [result appendString:@"\n</codeblock>"];
1269
+ }
1270
+ if (inCheckboxList) {
1271
+ inCheckboxList = NO;
1272
+ [result appendString:@"\n</ul>"];
1273
+ }
1274
+ }
1275
+
1276
+ [result appendString:@"\n</html>"];
1277
+
1278
+ // remove Object Replacement Characters in the very end
1279
+ [result replaceOccurrencesOfString:@"\uFFFC"
1280
+ withString:@""
1281
+ options:0
1282
+ range:NSMakeRange(0, result.length)];
1283
+
1284
+ // remove zero width spaces in the very end
1285
+ [result replaceOccurrencesOfString:@"\u200B"
1286
+ withString:@""
1287
+ options:0
1288
+ range:NSMakeRange(0, result.length)];
1289
+
1290
+ // replace empty <p></p> into <br> in the very end
1291
+ [result replaceOccurrencesOfString:@"<p></p>"
1292
+ withString:@"<br>"
1293
+ options:0
1294
+ range:NSMakeRange(0, result.length)];
1295
+
1296
+ return result;
1297
+ }
1298
+
1299
+ + (NSString *)tagContentForStyle:(NSNumber *)style
1300
+ openingTag:(BOOL)openingTag
1301
+ location:(NSInteger)location
1302
+ host:(id<EnrichedViewHost>)host {
1303
+ NSString *cssStyleString = [self prepareCssStyleString:location
1304
+ isOpeningTag:openingTag
1305
+ host:host];
1306
+ if ([style isEqualToNumber:@([BoldStyle getType])]) {
1307
+ return @"b";
1308
+ } else if ([style isEqualToNumber:@([ItalicStyle getType])]) {
1309
+ return @"i";
1310
+ } else if ([style isEqualToNumber:@([ImageStyle getType])]) {
1311
+ if (openingTag) {
1312
+ ImageStyle *imageStyle =
1313
+ (ImageStyle *)host.stylesDict[@([ImageStyle getType])];
1314
+ if (imageStyle != nullptr) {
1315
+ ImageData *data = [imageStyle getImageDataAt:location];
1316
+ if (data != nullptr && data.uri != nullptr) {
1317
+ return [NSString
1318
+ stringWithFormat:@"img src=\"%@\" width=\"%f\" height=\"%f\"",
1319
+ data.uri, data.width, data.height];
1320
+ }
1321
+ }
1322
+ return @"img";
1323
+ } else {
1324
+ return @"";
1325
+ }
1326
+ } else if ([style isEqualToNumber:@([UnderlineStyle getType])]) {
1327
+ return @"u";
1328
+ } else if ([style isEqualToNumber:@([StrikethroughStyle getType])]) {
1329
+ return @"s";
1330
+ } else if ([style isEqualToNumber:@([InlineCodeStyle getType])]) {
1331
+ return @"code";
1332
+ } else if ([style isEqualToNumber:@([LinkStyle getType])]) {
1333
+ if (openingTag) {
1334
+ LinkStyle *linkStyle =
1335
+ (LinkStyle *)host.stylesDict[@([LinkStyle getType])];
1336
+ if (linkStyle != nullptr) {
1337
+ LinkData *data = [linkStyle getLinkDataAt:location];
1338
+ if (data != nullptr && data.url != nullptr) {
1339
+ return [NSString stringWithFormat:@"a href=\"%@\"", data.url];
1340
+ }
1341
+ }
1342
+ return @"a";
1343
+ } else {
1344
+ return @"a";
1345
+ }
1346
+ } else if ([style isEqualToNumber:@([MentionStyle getType])]) {
1347
+ if (openingTag) {
1348
+ MentionStyle *mentionStyle =
1349
+ (MentionStyle *)host.stylesDict[@([MentionStyle getType])];
1350
+ if (mentionStyle != nullptr) {
1351
+ MentionParams *params = [mentionStyle getMentionParamsAt:location];
1352
+ // attributes can theoretically be nullptr
1353
+ if (params != nullptr && params.indicator != nullptr &&
1354
+ params.text != nullptr) {
1355
+ NSMutableString *attrsStr =
1356
+ [[NSMutableString alloc] initWithString:@""];
1357
+ if (params.attributes != nullptr) {
1358
+ // turn attributes to Data and then into dict
1359
+ NSData *attrsData =
1360
+ [params.attributes dataUsingEncoding:NSUTF8StringEncoding];
1361
+ NSError *jsonError;
1362
+ NSDictionary *json =
1363
+ [NSJSONSerialization JSONObjectWithData:attrsData
1364
+ options:0
1365
+ error:&jsonError];
1366
+ // format dict keys and values into string
1367
+ [json enumerateKeysAndObjectsUsingBlock:^(
1368
+ id _Nonnull key, id _Nonnull obj, BOOL *_Nonnull stop) {
1369
+ [attrsStr
1370
+ appendString:[NSString stringWithFormat:@" %@=\"%@\"",
1371
+ (NSString *)key,
1372
+ (NSString *)obj]];
1373
+ }];
1374
+ }
1375
+ return [NSString
1376
+ stringWithFormat:@"mention text=\"%@\" indicator=\"%@\"%@",
1377
+ params.text, params.indicator, attrsStr];
1378
+ }
1379
+ }
1380
+ return @"mention";
1381
+ } else {
1382
+ return @"mention";
1383
+ }
1384
+ } else if ([style isEqualToNumber:@([H1Style getType])]) {
1385
+ return [NSString stringWithFormat:@"h1%@", cssStyleString];
1386
+ } else if ([style isEqualToNumber:@([H2Style getType])]) {
1387
+ return [NSString stringWithFormat:@"h2%@", cssStyleString];
1388
+ } else if ([style isEqualToNumber:@([H3Style getType])]) {
1389
+ return [NSString stringWithFormat:@"h3%@", cssStyleString];
1390
+ } else if ([style isEqualToNumber:@([H4Style getType])]) {
1391
+ return [NSString stringWithFormat:@"h4%@", cssStyleString];
1392
+ } else if ([style isEqualToNumber:@([H5Style getType])]) {
1393
+ return [NSString stringWithFormat:@"h5%@", cssStyleString];
1394
+ } else if ([style isEqualToNumber:@([H6Style getType])]) {
1395
+ return [NSString stringWithFormat:@"h6%@", cssStyleString];
1396
+ } else if ([style isEqualToNumber:@([UnorderedListStyle getType])] ||
1397
+ [style isEqualToNumber:@([OrderedListStyle getType])]) {
1398
+ return @"li";
1399
+ } else if ([style isEqualToNumber:@([CheckboxListStyle getType])]) {
1400
+ if (openingTag) {
1401
+ CheckboxListStyle *checkboxListStyleClass =
1402
+ (CheckboxListStyle *)host.stylesDict[@([CheckboxListStyle getType])];
1403
+ BOOL checked = [checkboxListStyleClass getCheckboxStateAt:location];
1404
+
1405
+ if (checked) {
1406
+ return @"li checked";
1407
+ }
1408
+ return @"li";
1409
+ } else {
1410
+ return @"li";
1411
+ }
1412
+ } else if ([style isEqualToNumber:@([BlockQuoteStyle getType])] ||
1413
+ [style isEqualToNumber:@([CodeBlockStyle getType])]) {
1414
+ // blockquotes and codeblock use <p> tags the same way lists use <li>
1415
+ return [NSString stringWithFormat:@"p%@", cssStyleString];
1416
+ }
1417
+ return @"";
1418
+ }
1419
+
1420
+ + (NSString *)prepareCssStyleString:(NSInteger)location
1421
+ isOpeningTag:(BOOL)isOpeningTag
1422
+ host:(id<EnrichedViewHost>)host {
1423
+ if (!isOpeningTag) {
1424
+ return @"";
1425
+ }
1426
+
1427
+ NSParagraphStyle *pStyle =
1428
+ [host.textView.textStorage attribute:NSParagraphStyleAttributeName
1429
+ atIndex:location
1430
+ effectiveRange:nil];
1431
+ NSString *alignStr = [AlignmentUtils cssValueForAlignment:pStyle.alignment];
1432
+
1433
+ if (alignStr) {
1434
+ return [NSString stringWithFormat:@" style=\"text-align: %@\"", alignStr];
1435
+ }
1436
+
1437
+ return @"";
1438
+ }
1439
+
1440
+ + (void)checkForAlignments:(NSArray *)tagData
1441
+ plainText:(NSString *)plainText
1442
+ foundAlignments:(NSMutableArray<AlignmentEntry *> *)foundAlignments
1443
+ precedingImageCount:(NSInteger)precedingImageCount {
1444
+ if (tagData == nil) {
1445
+ return;
1446
+ }
1447
+
1448
+ // We look at the params stored in ongoingTags
1449
+ NSString *storedParams = (tagData.count > 2) ? tagData[2] : nil;
1450
+ NSTextAlignment align =
1451
+ [AlignmentUtils alignmentFromStyleParams:storedParams];
1452
+
1453
+ if (align != NSTextAlignmentNatural) {
1454
+ NSInteger startLoc = [tagData[0] integerValue];
1455
+ // Calculate range relative to plainText
1456
+ NSInteger actualStart = startLoc + precedingImageCount;
1457
+ NSInteger length = plainText.length - startLoc;
1458
+
1459
+ if (length > 0) {
1460
+ AlignmentEntry *entry = [[AlignmentEntry alloc] init];
1461
+ entry.alignment = align;
1462
+ entry.range = NSMakeRange(actualStart, length);
1463
+ [foundAlignments addObject:entry];
1464
+ }
1465
+ }
1466
+ }
1467
+
1468
+ @end