@mathers101/react-native-render-rich-text 0.1.10 → 0.1.14

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 (327) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +140 -140
  3. package/ReactNativeRenderRichText.podspec +23 -23
  4. package/android/build.gradle +86 -86
  5. package/android/consumer-rules.pro +3 -3
  6. package/android/src/main/AndroidManifest.xml +2 -2
  7. package/android/src/main/java/com/renderrichtext/EnrichedTiptapTextLayoutManager.kt +24 -24
  8. package/android/src/main/java/com/renderrichtext/EnrichedTiptapTextPackage.kt +13 -13
  9. package/android/src/main/java/com/renderrichtext/MeasurementStore.kt +644 -644
  10. package/android/src/main/java/com/renderrichtext/accessibility/AccessibilityLabels.kt +17 -17
  11. package/android/src/main/java/com/renderrichtext/accessibility/AccessibleTiptapTextView.kt +112 -112
  12. package/android/src/main/java/com/renderrichtext/accessibility/TiptapAccessibilityHelper.kt +576 -576
  13. package/android/src/main/java/com/renderrichtext/events/CodeBlockPressEvent.kt +24 -24
  14. package/android/src/main/java/com/renderrichtext/events/ContextMenuItemPressEvent.kt +28 -28
  15. package/android/src/main/java/com/renderrichtext/events/CopyPressEvent.kt +24 -24
  16. package/android/src/main/java/com/renderrichtext/events/ImagePressEvent.kt +25 -25
  17. package/android/src/main/java/com/renderrichtext/events/LatexErrorEvent.kt +29 -29
  18. package/android/src/main/java/com/renderrichtext/events/LinkLongPressEvent.kt +23 -23
  19. package/android/src/main/java/com/renderrichtext/events/LinkPressEvent.kt +23 -23
  20. package/android/src/main/java/com/renderrichtext/events/MentionLongPressEvent.kt +25 -25
  21. package/android/src/main/java/com/renderrichtext/events/MentionPressEvent.kt +25 -25
  22. package/android/src/main/java/com/renderrichtext/events/TaskListItemPressEvent.kt +26 -26
  23. package/android/src/main/java/com/renderrichtext/math/LatexErrorReporter.kt +9 -9
  24. package/android/src/main/java/com/renderrichtext/parser/Parser.kt +59 -59
  25. package/android/src/main/java/com/renderrichtext/parser/TextLinkMatching.kt +35 -35
  26. package/android/src/main/java/com/renderrichtext/renderer/BaselineShiftRenderer.kt +45 -45
  27. package/android/src/main/java/com/renderrichtext/renderer/BlankLineRenderer.kt +39 -39
  28. package/android/src/main/java/com/renderrichtext/renderer/BlockquoteRenderer.kt +243 -243
  29. package/android/src/main/java/com/renderrichtext/renderer/BlockquoteTextRenderer.kt +56 -56
  30. package/android/src/main/java/com/renderrichtext/renderer/CodeBlockRenderer.kt +135 -135
  31. package/android/src/main/java/com/renderrichtext/renderer/CodeRenderer.kt +37 -37
  32. package/android/src/main/java/com/renderrichtext/renderer/EmphasisRenderer.kt +28 -28
  33. package/android/src/main/java/com/renderrichtext/renderer/HeadingRenderer.kt +81 -81
  34. package/android/src/main/java/com/renderrichtext/renderer/HighlightRenderer.kt +26 -26
  35. package/android/src/main/java/com/renderrichtext/renderer/LineBreakRenderer.kt +17 -17
  36. package/android/src/main/java/com/renderrichtext/renderer/LinkRenderer.kt +90 -90
  37. package/android/src/main/java/com/renderrichtext/renderer/ListContextManager.kt +109 -109
  38. package/android/src/main/java/com/renderrichtext/renderer/ListItemRenderer.kt +211 -211
  39. package/android/src/main/java/com/renderrichtext/renderer/ListRenderer.kt +133 -133
  40. package/android/src/main/java/com/renderrichtext/renderer/MentionRenderer.kt +85 -85
  41. package/android/src/main/java/com/renderrichtext/renderer/ParagraphRenderer.kt +91 -91
  42. package/android/src/main/java/com/renderrichtext/renderer/Renderer.kt +148 -148
  43. package/android/src/main/java/com/renderrichtext/renderer/SoftBreakRenderer.kt +17 -17
  44. package/android/src/main/java/com/renderrichtext/renderer/SpanStyleCache.kt +143 -143
  45. package/android/src/main/java/com/renderrichtext/renderer/StrikethroughRenderer.kt +28 -28
  46. package/android/src/main/java/com/renderrichtext/renderer/StrongRenderer.kt +28 -28
  47. package/android/src/main/java/com/renderrichtext/renderer/TextRenderer.kt +31 -31
  48. package/android/src/main/java/com/renderrichtext/renderer/ThematicBreakRenderer.kt +46 -46
  49. package/android/src/main/java/com/renderrichtext/renderer/UnderlineRenderer.kt +28 -28
  50. package/android/src/main/java/com/renderrichtext/spans/BaseListSpan.kt +164 -164
  51. package/android/src/main/java/com/renderrichtext/spans/BaselineShiftSpan.kt +27 -27
  52. package/android/src/main/java/com/renderrichtext/spans/BlockquoteSpan.kt +302 -302
  53. package/android/src/main/java/com/renderrichtext/spans/CodeBackgroundSpan.kt +205 -205
  54. package/android/src/main/java/com/renderrichtext/spans/CodeBlockSpan.kt +216 -216
  55. package/android/src/main/java/com/renderrichtext/spans/CodeSpan.kt +32 -32
  56. package/android/src/main/java/com/renderrichtext/spans/EmphasisSpan.kt +42 -42
  57. package/android/src/main/java/com/renderrichtext/spans/FadeInSpan.kt +29 -29
  58. package/android/src/main/java/com/renderrichtext/spans/HeadingSpan.kt +38 -38
  59. package/android/src/main/java/com/renderrichtext/spans/HighlightSpan.kt +80 -80
  60. package/android/src/main/java/com/renderrichtext/spans/ImageSpan.kt +481 -481
  61. package/android/src/main/java/com/renderrichtext/spans/InlineBackgroundGeometry.kt +42 -42
  62. package/android/src/main/java/com/renderrichtext/spans/LineHeightSpan.kt +39 -39
  63. package/android/src/main/java/com/renderrichtext/spans/LinkPillIconCache.kt +154 -154
  64. package/android/src/main/java/com/renderrichtext/spans/LinkPillSpan.kt +381 -381
  65. package/android/src/main/java/com/renderrichtext/spans/LinkSpan.kt +68 -68
  66. package/android/src/main/java/com/renderrichtext/spans/ListItemSpacingSpan.kt +33 -33
  67. package/android/src/main/java/com/renderrichtext/spans/ListMarkerAnchorSpan.kt +38 -38
  68. package/android/src/main/java/com/renderrichtext/spans/MarginBottomSpan.kt +76 -76
  69. package/android/src/main/java/com/renderrichtext/spans/MentionChipSpan.kt +132 -132
  70. package/android/src/main/java/com/renderrichtext/spans/MentionSpan.kt +46 -46
  71. package/android/src/main/java/com/renderrichtext/spans/OrderedListSpan.kt +127 -127
  72. package/android/src/main/java/com/renderrichtext/spans/SpoilerSpan.kt +33 -33
  73. package/android/src/main/java/com/renderrichtext/spans/StrikethroughSpan.kt +12 -12
  74. package/android/src/main/java/com/renderrichtext/spans/StrongSpan.kt +39 -39
  75. package/android/src/main/java/com/renderrichtext/spans/TaskListSpan.kt +143 -143
  76. package/android/src/main/java/com/renderrichtext/spans/TextSpan.kt +26 -26
  77. package/android/src/main/java/com/renderrichtext/spans/ThematicBreakSpan.kt +69 -69
  78. package/android/src/main/java/com/renderrichtext/spans/UnorderedListSpan.kt +96 -96
  79. package/android/src/main/java/com/renderrichtext/spoiler/SpoilerStubs.kt +46 -46
  80. package/android/src/main/java/com/renderrichtext/styles/BaseBlockStyle.kt +11 -11
  81. package/android/src/main/java/com/renderrichtext/styles/BlockquoteStyle.kt +83 -83
  82. package/android/src/main/java/com/renderrichtext/styles/CodeBlockStyle.kt +80 -80
  83. package/android/src/main/java/com/renderrichtext/styles/CodeStyle.kt +26 -26
  84. package/android/src/main/java/com/renderrichtext/styles/EmphasisStyle.kt +21 -21
  85. package/android/src/main/java/com/renderrichtext/styles/FactoidStyle.kt +21 -21
  86. package/android/src/main/java/com/renderrichtext/styles/HeadingStyle.kt +33 -33
  87. package/android/src/main/java/com/renderrichtext/styles/HighlightStyle.kt +19 -19
  88. package/android/src/main/java/com/renderrichtext/styles/ImageStyle.kt +29 -29
  89. package/android/src/main/java/com/renderrichtext/styles/InlineImageStyle.kt +17 -17
  90. package/android/src/main/java/com/renderrichtext/styles/InlineMathStyle.kt +17 -17
  91. package/android/src/main/java/com/renderrichtext/styles/LinkPillContent.kt +36 -36
  92. package/android/src/main/java/com/renderrichtext/styles/LinkPillStyle.kt +44 -44
  93. package/android/src/main/java/com/renderrichtext/styles/LinkStyle.kt +23 -23
  94. package/android/src/main/java/com/renderrichtext/styles/LinkVariantEntry.kt +34 -34
  95. package/android/src/main/java/com/renderrichtext/styles/ListStyle.kt +65 -65
  96. package/android/src/main/java/com/renderrichtext/styles/MathStyle.kt +29 -29
  97. package/android/src/main/java/com/renderrichtext/styles/MentionStyle.kt +19 -19
  98. package/android/src/main/java/com/renderrichtext/styles/ParagraphStyle.kt +33 -33
  99. package/android/src/main/java/com/renderrichtext/styles/SpoilerStyle.kt +27 -27
  100. package/android/src/main/java/com/renderrichtext/styles/StrikethroughStyle.kt +17 -17
  101. package/android/src/main/java/com/renderrichtext/styles/StrongStyle.kt +21 -21
  102. package/android/src/main/java/com/renderrichtext/styles/StyleConfig.kt +411 -411
  103. package/android/src/main/java/com/renderrichtext/styles/StyleParser.kt +92 -92
  104. package/android/src/main/java/com/renderrichtext/styles/SubscriptStyle.kt +16 -16
  105. package/android/src/main/java/com/renderrichtext/styles/SuperscriptStyle.kt +16 -16
  106. package/android/src/main/java/com/renderrichtext/styles/TableStyle.kt +75 -75
  107. package/android/src/main/java/com/renderrichtext/styles/TaskListStyle.kt +29 -29
  108. package/android/src/main/java/com/renderrichtext/styles/TextAlignment.kt +32 -32
  109. package/android/src/main/java/com/renderrichtext/styles/ThematicBreakStyle.kt +23 -23
  110. package/android/src/main/java/com/renderrichtext/styles/UnderlineStyle.kt +17 -17
  111. package/android/src/main/java/com/renderrichtext/styles/VideoStyle.kt +31 -31
  112. package/android/src/main/java/com/renderrichtext/utils/common/BorderStyleUtils.kt +86 -86
  113. package/android/src/main/java/com/renderrichtext/utils/common/BreakStrategyUtils.kt +32 -32
  114. package/android/src/main/java/com/renderrichtext/utils/common/CodeBlockHighlighter.kt +36 -36
  115. package/android/src/main/java/com/renderrichtext/utils/common/CodeBlockNode.kt +42 -42
  116. package/android/src/main/java/com/renderrichtext/utils/common/EllipsizeUtils.kt +27 -27
  117. package/android/src/main/java/com/renderrichtext/utils/common/EnrichedTiptapAncestorUtils.kt +10 -10
  118. package/android/src/main/java/com/renderrichtext/utils/common/FeatureFlags.kt +9 -9
  119. package/android/src/main/java/com/renderrichtext/utils/common/LinkRecognitionProps.kt +31 -31
  120. package/android/src/main/java/com/renderrichtext/utils/common/LinkRegexConfig.kt +56 -56
  121. package/android/src/main/java/com/renderrichtext/utils/common/MotionPreferences.kt +18 -18
  122. package/android/src/main/java/com/renderrichtext/utils/common/ReadableMapExtensions.kt +28 -28
  123. package/android/src/main/java/com/renderrichtext/utils/common/layout/RTLUtils.kt +6 -6
  124. package/android/src/main/java/com/renderrichtext/utils/common/serialization/TiptapASTSerializer.kt +368 -368
  125. package/android/src/main/java/com/renderrichtext/utils/text/ImageCache.kt +88 -88
  126. package/android/src/main/java/com/renderrichtext/utils/text/ImageDownloader.kt +203 -203
  127. package/android/src/main/java/com/renderrichtext/utils/text/LocalImageLoader.kt +167 -167
  128. package/android/src/main/java/com/renderrichtext/utils/text/TailFadeInAnimator.kt +84 -84
  129. package/android/src/main/java/com/renderrichtext/utils/text/conversion/HTMLGenerator.kt +1105 -1105
  130. package/android/src/main/java/com/renderrichtext/utils/text/conversion/TiptapExtractor.kt +423 -423
  131. package/android/src/main/java/com/renderrichtext/utils/text/extensions/ParagraphUtils.kt +9 -9
  132. package/android/src/main/java/com/renderrichtext/utils/text/extensions/SpannableExtensions.kt +9 -9
  133. package/android/src/main/java/com/renderrichtext/utils/text/extensions/TextPaintExtensions.kt +76 -76
  134. package/android/src/main/java/com/renderrichtext/utils/text/interaction/CheckboxTouchHelper.kt +61 -61
  135. package/android/src/main/java/com/renderrichtext/utils/text/interaction/TaskListTapUtils.kt +286 -286
  136. package/android/src/main/java/com/renderrichtext/utils/text/span/ApplyLineHeight.kt +39 -39
  137. package/android/src/main/java/com/renderrichtext/utils/text/span/BlockSpacing.kt +142 -142
  138. package/android/src/main/java/com/renderrichtext/utils/text/span/SpanFlags.kt +43 -43
  139. package/android/src/main/java/com/renderrichtext/utils/text/span/WidthAwareSpans.kt +30 -30
  140. package/android/src/main/java/com/renderrichtext/utils/text/view/CodeBlockPressHost.kt +15 -15
  141. package/android/src/main/java/com/renderrichtext/utils/text/view/ImagePressHost.kt +19 -19
  142. package/android/src/main/java/com/renderrichtext/utils/text/view/SelectionActionMode.kt +235 -235
  143. package/android/src/main/java/com/renderrichtext/utils/text/view/TextSelectionColors.kt +48 -48
  144. package/android/src/main/java/com/renderrichtext/utils/text/view/TextViewSetup.kt +119 -119
  145. package/android/src/main/java/com/renderrichtext/views/ContextMenuPopup.kt +217 -217
  146. package/android/src/main/java/com/renderrichtext/views/CopyGlyph.kt +101 -101
  147. package/android/src/main/java/com/renderrichtext/views/WrapGlyph.kt +40 -40
  148. package/android/src/main/jni/CMakeLists.txt +52 -52
  149. package/android/src/main/jni/react/renderer/components/RichTextSpec/ComponentDescriptors.h +30 -30
  150. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextComponentDescriptor.h +29 -29
  151. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextMeasurementManager.cpp +45 -45
  152. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextMeasurementManager.h +21 -21
  153. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextShadowNode.cpp +38 -38
  154. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextShadowNode.h +53 -53
  155. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextState.cpp +9 -9
  156. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextState.h +24 -24
  157. package/android/src/main/jni/react/renderer/components/RichTextSpec/conversions.h +40 -40
  158. package/cpp/parser/TiptapParser.hpp +13 -13
  159. package/cpp/vendor/nlohmann/json.hpp +24765 -24765
  160. package/ios/EnrichedTiptapText.h +27 -27
  161. package/ios/attachments/ENRMImageAttachment.h +51 -51
  162. package/ios/attachments/ENRMImageAttachment.m +398 -398
  163. package/ios/attachments/ENRMLinkPillAttachment.h +47 -47
  164. package/ios/attachments/ENRMLinkPillAttachment.m +324 -324
  165. package/ios/attachments/ENRMLinkPillIconCache.h +28 -28
  166. package/ios/attachments/ENRMLinkPillIconCache.m +181 -181
  167. package/ios/attachments/ENRMLinkPillText.h +27 -27
  168. package/ios/attachments/ENRMLinkPillText.m +118 -118
  169. package/ios/attachments/ENRMMathInlineAttachment.h +7 -7
  170. package/ios/attachments/ENRMMathInlineAttachment.m +4 -4
  171. package/ios/attachments/ThematicBreakAttachment.h +15 -15
  172. package/ios/attachments/ThematicBreakAttachment.m +33 -33
  173. package/ios/internals/ENRMViewFreeMeasurement.h +208 -208
  174. package/ios/internals/EnrichedTiptapTextComponentDescriptor.h +19 -19
  175. package/ios/internals/EnrichedTiptapTextShadowNode.h +43 -43
  176. package/ios/internals/EnrichedTiptapTextShadowNode.mm +69 -69
  177. package/ios/internals/EnrichedTiptapTextState.h +24 -24
  178. package/ios/internals/MeasurementCache.h +308 -308
  179. package/ios/internals/ShadowMeasurementUtils.h +145 -145
  180. package/ios/parser/ENRMTextLinkAttributes.h +7 -7
  181. package/ios/parser/ENRMTiptapParser.h +33 -33
  182. package/ios/parser/ENRMTiptapParser.mm +73 -73
  183. package/ios/parser/TiptapASTNode.m +52 -52
  184. package/ios/renderer/AttributedRenderer.h +23 -23
  185. package/ios/renderer/AttributedRenderer.m +229 -229
  186. package/ios/renderer/BaseRenderer.h +33 -33
  187. package/ios/renderer/BaseRenderer.m +46 -46
  188. package/ios/renderer/BaselineShiftTextAttributes.h +10 -10
  189. package/ios/renderer/BaselineShiftTextAttributes.m +26 -26
  190. package/ios/renderer/BlankLineRenderer.h +4 -4
  191. package/ios/renderer/BlankLineRenderer.m +51 -51
  192. package/ios/renderer/BlockquoteRenderer.h +6 -6
  193. package/ios/renderer/BlockquoteRenderer.m +258 -258
  194. package/ios/renderer/CodeBlockRenderer.h +9 -9
  195. package/ios/renderer/CodeBlockRenderer.m +99 -99
  196. package/ios/renderer/CodeRenderer.h +9 -9
  197. package/ios/renderer/CodeRenderer.m +69 -69
  198. package/ios/renderer/ENRMBlockquoteTextRenderer.h +25 -25
  199. package/ios/renderer/ENRMBlockquoteTextRenderer.m +48 -48
  200. package/ios/renderer/EmphasisRenderer.h +5 -5
  201. package/ios/renderer/EmphasisRenderer.m +99 -99
  202. package/ios/renderer/HeadingRenderer.h +6 -6
  203. package/ios/renderer/HeadingRenderer.m +102 -102
  204. package/ios/renderer/HighlightRenderer.h +7 -7
  205. package/ios/renderer/HighlightRenderer.m +33 -33
  206. package/ios/renderer/LinkRenderer.h +6 -6
  207. package/ios/renderer/LinkRenderer.m +157 -157
  208. package/ios/renderer/ListItemRenderer.h +24 -24
  209. package/ios/renderer/ListItemRenderer.m +283 -283
  210. package/ios/renderer/ListRenderer.h +13 -13
  211. package/ios/renderer/ListRenderer.m +126 -126
  212. package/ios/renderer/MentionRenderer.h +9 -9
  213. package/ios/renderer/MentionRenderer.m +96 -96
  214. package/ios/renderer/NodeRenderer.h +8 -8
  215. package/ios/renderer/ParagraphRenderer.h +6 -6
  216. package/ios/renderer/ParagraphRenderer.m +85 -85
  217. package/ios/renderer/RenderContext.h +145 -145
  218. package/ios/renderer/RenderContext.m +402 -402
  219. package/ios/renderer/RendererFactory.h +12 -12
  220. package/ios/renderer/StrikethroughRenderer.h +5 -5
  221. package/ios/renderer/StrikethroughRenderer.m +30 -30
  222. package/ios/renderer/StrongRenderer.h +5 -5
  223. package/ios/renderer/StrongRenderer.m +87 -87
  224. package/ios/renderer/TextRenderer.h +6 -6
  225. package/ios/renderer/TextRenderer.m +18 -18
  226. package/ios/renderer/ThematicBreakRenderer.h +4 -4
  227. package/ios/renderer/ThematicBreakRenderer.m +41 -41
  228. package/ios/renderer/UnderlineRenderer.h +4 -4
  229. package/ios/renderer/UnderlineRenderer.m +41 -41
  230. package/ios/styles/ENRMFontSlot.h +12 -12
  231. package/ios/styles/ENRMFontSlot.m +24 -24
  232. package/ios/styles/StyleConfig.h +488 -488
  233. package/ios/styles/StyleConfig.mm +2820 -2820
  234. package/ios/utils/AccessibilityInfo.h +35 -35
  235. package/ios/utils/AccessibilityInfo.m +24 -24
  236. package/ios/utils/BlockquoteBorder.h +26 -26
  237. package/ios/utils/BlockquoteBorder.m +294 -294
  238. package/ios/utils/CodeBackground.h +19 -19
  239. package/ios/utils/CodeBackground.m +196 -196
  240. package/ios/utils/CodeBlockBackground.h +17 -17
  241. package/ios/utils/CodeBlockBackground.m +102 -102
  242. package/ios/utils/ContextMenuUtils.h +76 -76
  243. package/ios/utils/ContextMenuUtils.mm +75 -75
  244. package/ios/utils/ENRMAccessibilityLabels.h +40 -40
  245. package/ios/utils/ENRMAccessibilityLabels.m +5 -5
  246. package/ios/utils/ENRMAsyncRenderCoordinator.h +24 -24
  247. package/ios/utils/ENRMAsyncRenderCoordinator.m +37 -37
  248. package/ios/utils/ENRMAtomicSize.h +65 -65
  249. package/ios/utils/ENRMCodeBlockContent.h +37 -37
  250. package/ios/utils/ENRMCodeBlockContent.mm +89 -89
  251. package/ios/utils/ENRMFeatureFlags.h +25 -25
  252. package/ios/utils/ENRMImageDownloader.h +30 -30
  253. package/ios/utils/ENRMImageDownloader.m +168 -168
  254. package/ios/utils/ENRMLatexErrorCoordinator.h +27 -27
  255. package/ios/utils/ENRMLatexErrorCoordinator.mm +75 -75
  256. package/ios/utils/ENRMLatexErrorReporting.h +13 -13
  257. package/ios/utils/ENRMLinkContextMenus.h +93 -93
  258. package/ios/utils/ENRMLinkContextMenus.m +178 -178
  259. package/ios/utils/ENRMLinkRegexConfig.h +30 -30
  260. package/ios/utils/ENRMLinkRegexConfig.mm +104 -104
  261. package/ios/utils/ENRMLinkRegexProps.h +23 -23
  262. package/ios/utils/ENRMLocalImageLoader.h +35 -35
  263. package/ios/utils/ENRMLocalImageLoader.m +111 -111
  264. package/ios/utils/ENRMMenuAction.h +27 -27
  265. package/ios/utils/ENRMMenuAction.m +33 -33
  266. package/ios/utils/ENRMSpoilerOverlayManager.h +15 -15
  267. package/ios/utils/ENRMSpoilerOverlayManager.m +19 -19
  268. package/ios/utils/ENRMSpoilerTapUtils.h +6 -6
  269. package/ios/utils/ENRMSpoilerTapUtils.m +11 -11
  270. package/ios/utils/ENRMTailFadeInAnimator.h +16 -16
  271. package/ios/utils/ENRMTailFadeInAnimator.m +161 -161
  272. package/ios/utils/ENRMTextHitTest.h +23 -23
  273. package/ios/utils/ENRMTextHitTest.m +20 -20
  274. package/ios/utils/ENRMTextInteractionUtils.h +20 -20
  275. package/ios/utils/ENRMTextInteractionUtils.m +15 -15
  276. package/ios/utils/ENRMTextRenderer.h +38 -38
  277. package/ios/utils/ENRMTextRenderer.m +54 -54
  278. package/ios/utils/ENRMTextViewSetup.h +132 -132
  279. package/ios/utils/ENRMUIKit.h +429 -429
  280. package/ios/utils/EditMenuUtils.h +105 -105
  281. package/ios/utils/EditMenuUtils.m +143 -143
  282. package/ios/utils/FontScaleObserver.h +10 -10
  283. package/ios/utils/FontScaleObserver.m +55 -55
  284. package/ios/utils/FontUtils.h +31 -31
  285. package/ios/utils/FontUtils.m +63 -63
  286. package/ios/utils/HTMLGenerator.h +25 -25
  287. package/ios/utils/HTMLGenerator.m +1041 -1041
  288. package/ios/utils/HeightUpdateUtils.h +25 -25
  289. package/ios/utils/ImageRequestHeaderUtils.h +35 -35
  290. package/ios/utils/LastElementUtils.h +97 -97
  291. package/ios/utils/LinkContextMenuUtils.h +55 -55
  292. package/ios/utils/LinkPillContentUtils.h +46 -46
  293. package/ios/utils/ListMarkerDrawer.h +15 -15
  294. package/ios/utils/ListMarkerDrawer.m +239 -239
  295. package/ios/utils/MentionBackground.h +26 -26
  296. package/ios/utils/MentionBackground.m +86 -86
  297. package/ios/utils/ParagraphStyleUtils.h +87 -87
  298. package/ios/utils/ParagraphStyleUtils.m +484 -484
  299. package/ios/utils/PasteboardUtils.h +48 -48
  300. package/ios/utils/PasteboardUtils.m +166 -166
  301. package/ios/utils/RTFExportUtils.h +24 -24
  302. package/ios/utils/RTFExportUtils.m +299 -299
  303. package/ios/utils/SelectionColorUtils.h +14 -14
  304. package/ios/utils/StylePropsUtils.h +1340 -1340
  305. package/ios/utils/TaskListTapUtils.h +6 -6
  306. package/ios/utils/TaskListTapUtils.m +14 -14
  307. package/ios/utils/TextViewLayoutManager.h +14 -14
  308. package/ios/utils/TiptapAccessibilityElementBuilder.h +43 -43
  309. package/ios/utils/TiptapAccessibilityElementBuilder.m +432 -432
  310. package/ios/utils/TiptapExtractor.h +17 -17
  311. package/ios/utils/TiptapExtractor.m +367 -367
  312. package/ios/views/ENRMTiptapTextView.h +25 -25
  313. package/ios/views/ENRMTiptapTextView.m +247 -247
  314. package/package.json +65 -70
  315. package/react-native.config.js +10 -10
  316. package/src/admonitionDefaults.ts +58 -58
  317. package/src/darkModeTextStyle.ts +99 -99
  318. package/src/headingDefaults.ts +21 -21
  319. package/src/index.tsx +4 -4
  320. package/src/linkVariantUtils.ts +120 -120
  321. package/src/normalizeTiptapStyle.ts +397 -397
  322. package/src/rn-globals.d.ts +1 -1
  323. package/src/styleUtils.ts +107 -107
  324. package/src/types/TiptapStyle.ts +532 -532
  325. package/src/types/TiptapStyleInternal.ts +299 -299
  326. package/src/types/linkPill.ts +9 -9
  327. package/src/utils/isDev.ts +4 -4
@@ -1,484 +1,484 @@
1
- #import "ParagraphStyleUtils.h"
2
- #import "ENRMFeatureFlags.h"
3
- #import "ENRMImageAttachment.h"
4
- #import "ENRMLinkPillAttachment.h"
5
- #import "LastElementUtils.h"
6
- #import <React/RCTI18nUtil.h>
7
-
8
- #if ENRICHED_TIPTAP_MATH
9
- #import "ENRMMathInlineAttachment.h"
10
- #endif
11
-
12
- NSAttributedString *kNewlineAttributedString;
13
- static NSParagraphStyle *kBlockSpacerTemplate;
14
-
15
- NSLineBreakStrategy ENRMResolveLineBreakStrategy(NSString *strategy)
16
- {
17
- if ([strategy isEqualToString:@"standard"]) {
18
- return NSLineBreakStrategyStandard;
19
- } else if ([strategy isEqualToString:@"hangul-word"]) {
20
- return NSLineBreakStrategyHangulWordPriority;
21
- } else if ([strategy isEqualToString:@"push-out"]) {
22
- return NSLineBreakStrategyPushOut;
23
- }
24
- return NSLineBreakStrategyNone;
25
- }
26
-
27
- NSLineBreakMode ENRMResolveEllipsizeLineBreakMode(NSString *mode)
28
- {
29
- if ([mode isEqualToString:@"head"]) {
30
- return NSLineBreakByTruncatingHead;
31
- } else if ([mode isEqualToString:@"middle"]) {
32
- return NSLineBreakByTruncatingMiddle;
33
- } else if ([mode isEqualToString:@"clip"]) {
34
- return NSLineBreakByClipping;
35
- }
36
- return NSLineBreakByTruncatingTail;
37
- }
38
-
39
- __attribute__((constructor)) static void initParagraphStyleUtils(void)
40
- {
41
- kNewlineAttributedString = [[NSAttributedString alloc] initWithString:@"\n"];
42
-
43
- NSMutableParagraphStyle *template = [[NSMutableParagraphStyle alloc] init];
44
- template.minimumLineHeight = 1;
45
- template.maximumLineHeight = 1;
46
- kBlockSpacerTemplate = [template copy];
47
- }
48
-
49
- ENRMWritingDirectionMode ENRMResolveWritingDirectionMode(NSString *value)
50
- {
51
- if ([value isEqualToString:@"ltr"]) {
52
- return ENRMWritingDirectionModeLTR;
53
- }
54
- if ([value isEqualToString:@"rtl"]) {
55
- return ENRMWritingDirectionModeRTL;
56
- }
57
- if ([value isEqualToString:@"auto"]) {
58
- return ENRMWritingDirectionModeAuto;
59
- }
60
- return ENRMWritingDirectionModeFirstStrong;
61
- }
62
-
63
- static BOOL ENRMIsStrongRTLChar(unichar c)
64
- {
65
- return (c >= 0x0590 && c <= 0x08FF) || (c >= 0xFB1D && c <= 0xFDFF) || (c >= 0xFE70 && c <= 0xFEFF);
66
- }
67
-
68
- NSWritingDirection ENRMFirstStrongDirection(NSString *text)
69
- {
70
- NSCharacterSet *letters = [NSCharacterSet letterCharacterSet];
71
- NSUInteger length = text.length;
72
- for (NSUInteger i = 0; i < length; i++) {
73
- unichar c = [text characterAtIndex:i];
74
- if (![letters characterIsMember:c]) {
75
- continue;
76
- }
77
- return ENRMIsStrongRTLChar(c) ? NSWritingDirectionRightToLeft : NSWritingDirectionLeftToRight;
78
- }
79
- return NSWritingDirectionNatural;
80
- }
81
-
82
- BOOL ENRMParagraphIsRTL(NSParagraphStyle *style)
83
- {
84
- if (style && style.baseWritingDirection != NSWritingDirectionNatural) {
85
- return style.baseWritingDirection == NSWritingDirectionRightToLeft;
86
- }
87
- return [[RCTI18nUtil sharedInstance] isRTL];
88
- }
89
-
90
- void ENRMApplyWritingDirectionMode(NSMutableAttributedString *output, ENRMWritingDirectionMode mode,
91
- NSWritingDirection layoutDirection)
92
- {
93
- switch (mode) {
94
- case ENRMWritingDirectionModeAuto:
95
- ENRMApplyWritingDirectionToParagraphStyles(output, NSWritingDirectionNatural);
96
- break;
97
- case ENRMWritingDirectionModeLTR:
98
- ENRMApplyWritingDirectionToParagraphStyles(output, NSWritingDirectionLeftToRight);
99
- break;
100
- case ENRMWritingDirectionModeRTL:
101
- ENRMApplyWritingDirectionToParagraphStyles(output, NSWritingDirectionRightToLeft);
102
- break;
103
- case ENRMWritingDirectionModeFirstStrong:
104
- ENRMApplyFirstStrongParagraphDirections(output, layoutDirection);
105
- break;
106
- }
107
- }
108
-
109
- void ENRMApplyFirstStrongParagraphDirections(NSMutableAttributedString *output, NSWritingDirection fallback)
110
- {
111
- if (output.length == 0) {
112
- return;
113
- }
114
- NSString *string = output.string;
115
- NSUInteger length = string.length;
116
- NSUInteger position = 0;
117
- while (position < length) {
118
- NSRange paragraphRange = [string paragraphRangeForRange:NSMakeRange(position, 0)];
119
- if (NSMaxRange(paragraphRange) <= position) {
120
- break;
121
- }
122
- position = NSMaxRange(paragraphRange);
123
-
124
- NSNumber *isCodeBlock = [output attribute:CodeBlockAttributeName
125
- atIndex:paragraphRange.location
126
- effectiveRange:nil];
127
- if (isCodeBlock.boolValue) {
128
- continue;
129
- }
130
-
131
- NSWritingDirection direction = ENRMFirstStrongDirection([string substringWithRange:paragraphRange]);
132
- if (direction == NSWritingDirectionNatural) {
133
- direction = fallback;
134
- }
135
- if (direction == NSWritingDirectionNatural) {
136
- continue;
137
- }
138
-
139
- [output enumerateAttribute:NSParagraphStyleAttributeName
140
- inRange:paragraphRange
141
- options:0
142
- usingBlock:^(NSParagraphStyle *style, NSRange range, BOOL *stop) {
143
- if (style != nil && style.baseWritingDirection == direction) {
144
- return;
145
- }
146
- NSMutableParagraphStyle *updated =
147
- style ? [style mutableCopy] : [[NSMutableParagraphStyle alloc] init];
148
- updated.baseWritingDirection = direction;
149
- [output addAttribute:NSParagraphStyleAttributeName value:updated range:range];
150
- }];
151
- }
152
- }
153
-
154
- void ENRMApplyWritingDirectionToParagraphStyles(NSMutableAttributedString *output, NSWritingDirection writingDirection)
155
- {
156
- if (output.length == 0) {
157
- return;
158
- }
159
- [output enumerateAttribute:NSParagraphStyleAttributeName
160
- inRange:NSMakeRange(0, output.length)
161
- options:0
162
- usingBlock:^(NSParagraphStyle *style, NSRange range, BOOL *stop) {
163
- if (!style) {
164
- return;
165
- }
166
- // Skip runs already in the target direction (issue #739),
167
- // mirroring ENRMApplyFirstStrongParagraphDirections.
168
- if (style.baseWritingDirection == writingDirection) {
169
- return;
170
- }
171
- NSNumber *isCodeBlock = [output attribute:CodeBlockAttributeName
172
- atIndex:range.location
173
- effectiveRange:nil];
174
- if (isCodeBlock.boolValue) {
175
- return;
176
- }
177
- NSMutableParagraphStyle *mutable = [style mutableCopy];
178
- mutable.baseWritingDirection = writingDirection;
179
- [output addAttribute:NSParagraphStyleAttributeName value:mutable range:range];
180
- }];
181
- }
182
-
183
- NSMutableParagraphStyle *getOrCreateParagraphStyle(NSMutableAttributedString *output, NSUInteger index)
184
- {
185
- NSParagraphStyle *existing = [output attribute:NSParagraphStyleAttributeName atIndex:index effectiveRange:NULL];
186
- NSMutableParagraphStyle *style = existing ? [existing mutableCopy] : [[NSMutableParagraphStyle alloc] init];
187
- return style;
188
- }
189
-
190
- void applyParagraphSpacingAfter(NSMutableAttributedString *output, NSUInteger start, CGFloat marginBottom)
191
- {
192
- [output appendAttributedString:kNewlineAttributedString];
193
-
194
- NSMutableParagraphStyle *style = getOrCreateParagraphStyle(output, start);
195
- style.paragraphSpacing = marginBottom;
196
-
197
- NSRange range = NSMakeRange(start, output.length - start);
198
- [output addAttribute:NSParagraphStyleAttributeName value:style range:range];
199
- }
200
-
201
- NSUInteger applyParagraphSpacingBefore(NSMutableAttributedString *output, NSRange range, CGFloat marginTop)
202
- {
203
- if (marginTop <= 0 || range.location == 0)
204
- return 0;
205
-
206
- NSUInteger prevIdx = range.location - 1;
207
- if ([output.string characterAtIndex:prevIdx] != '\n')
208
- return 0;
209
-
210
- NSParagraphStyle *prevStyle = [output attribute:NSParagraphStyleAttributeName atIndex:prevIdx effectiveRange:NULL];
211
-
212
- CGFloat prevMarginBottom = prevStyle.paragraphSpacing;
213
- if (prevMarginBottom >= marginTop)
214
- return 0;
215
-
216
- CGFloat extraGap = marginTop - prevMarginBottom;
217
-
218
- NSMutableParagraphStyle *spacerStyle = [kBlockSpacerTemplate mutableCopy];
219
- spacerStyle.paragraphSpacing = MAX(0, extraGap - 1.0);
220
-
221
- NSDictionary *attrs = @{NSParagraphStyleAttributeName : spacerStyle};
222
- NSAttributedString *spacer = [[NSAttributedString alloc] initWithString:@"\n" attributes:attrs];
223
-
224
- [output insertAttributedString:spacer atIndex:range.location];
225
- return 1;
226
- }
227
-
228
- NSUInteger applyBlockSpacingBefore(NSMutableAttributedString *output, NSUInteger insertionPoint, CGFloat marginTop)
229
- {
230
- if (marginTop <= 0) {
231
- return 0;
232
- }
233
-
234
- CGFloat spacing = marginTop;
235
-
236
- // At index 0 the spacer \n produces a 1pt line fragment (minimumLineHeight=1)
237
- // on top of paragraphSpacing. Subtract it so the total equals the desired margin.
238
- // For non-zero positions the 1pt is intentional inter-block spacing.
239
- if (insertionPoint == 0) {
240
- spacing = MAX(0, marginTop - 1.0);
241
- }
242
-
243
- NSMutableParagraphStyle *spacerStyle = [kBlockSpacerTemplate mutableCopy];
244
- spacerStyle.paragraphSpacing = spacing;
245
-
246
- NSAttributedString *spacer =
247
- [[NSAttributedString alloc] initWithString:@"\n" attributes:@{NSParagraphStyleAttributeName : spacerStyle}];
248
-
249
- [output insertAttributedString:spacer atIndex:insertionPoint];
250
- return 1;
251
- }
252
-
253
- void applyBlockSpacingAfter(NSMutableAttributedString *output, CGFloat marginBottom)
254
- {
255
- if (marginBottom <= 0) {
256
- return;
257
- }
258
-
259
- NSUInteger spacerLocation = output.length;
260
- [output appendAttributedString:kNewlineAttributedString];
261
-
262
- NSMutableParagraphStyle *spacerStyle = [kBlockSpacerTemplate mutableCopy];
263
- spacerStyle.paragraphSpacing = marginBottom;
264
-
265
- [output addAttribute:NSParagraphStyleAttributeName value:spacerStyle range:NSMakeRange(spacerLocation, 1)];
266
- }
267
-
268
- CGFloat ENRMLineHeightWithLinkPills(NSAttributedString *text, NSRange range, CGFloat lineHeight)
269
- {
270
- #if !TARGET_OS_OSX
271
- __block CGFloat fitting = lineHeight;
272
- [text enumerateAttribute:NSAttachmentAttributeName
273
- inRange:range
274
- options:0
275
- usingBlock:^(id value, __unused NSRange subrange, __unused BOOL *stop) {
276
- if ([value isKindOfClass:ENRMLinkPillAttachment.class])
277
- fitting = MAX(fitting, ((ENRMLinkPillAttachment *)value).lineHeight);
278
- }];
279
- return fitting;
280
- #else
281
- return lineHeight;
282
- #endif
283
- }
284
-
285
- // UIKit's own key for the pre-substitution font. Not exported by any SDK header, so it is spelled out
286
- // here; it is the same string UIKit writes into a UITextView's storage when it substitutes a font.
287
- static NSString *const ENRMOriginalFontAttributeName = @"NSOriginalFont";
288
-
289
- void ENRMPinLineMetricsToStyledFonts(NSMutableAttributedString *output, NSRange range)
290
- {
291
- if (range.length == 0 || NSMaxRange(range) > output.length) {
292
- return;
293
- }
294
-
295
- [output enumerateAttribute:NSFontAttributeName
296
- inRange:range
297
- options:0
298
- usingBlock:^(UIFont *font, NSRange fontRange, __unused BOOL *stop) {
299
- if (font) {
300
- [output addAttribute:ENRMOriginalFontAttributeName value:font range:fontRange];
301
- }
302
- }];
303
- }
304
-
305
- // Floor, not clamp: minimumLineHeight keeps short lines at lineHeight, while maximumLineHeight = 0 lets
306
- // a line grow to fit a taller run (large inline code, math, images) instead of clipping it.
307
- // We can diverge from RN's clamp because we measure the real laid-out height, so grown lines are reserved.
308
- void ENRMApplyLineHeightToParagraphStyle(NSMutableParagraphStyle *style, CGFloat lineHeight)
309
- {
310
- if (lineHeight <= 0) {
311
- return;
312
- }
313
-
314
- style.minimumLineHeight = lineHeight;
315
- style.maximumLineHeight = 0;
316
- }
317
-
318
- void applyLineHeight(NSMutableAttributedString *output, NSRange range, CGFloat lineHeight)
319
- {
320
- lineHeight = ENRMLineHeightWithLinkPills(output, range, lineHeight);
321
- if (lineHeight <= 0) {
322
- return;
323
- }
324
-
325
- NSMutableParagraphStyle *style = getOrCreateParagraphStyle(output, range.location);
326
- ENRMApplyLineHeightToParagraphStyle(style, lineHeight);
327
-
328
- [output addAttribute:NSParagraphStyleAttributeName value:style range:range];
329
- }
330
-
331
- // Calculates the offset needed to center the text within the line height. Returns 0
332
- // when the range has no minimum line height or its content already fills the line.
333
- CGFloat calculateBaselineOffset(NSAttributedString *output, NSRange range)
334
- {
335
- if (range.length == 0) {
336
- return 0;
337
- }
338
-
339
- // applyLineHeight floors lines with minimumLineHeight (maximumLineHeight is 0 for grown lines,
340
- // or equal to the minimum for re-clamped code blocks), so the target is the minimum line height.
341
- __block CGFloat targetLineHeight = 0;
342
- [output enumerateAttribute:NSParagraphStyleAttributeName
343
- inRange:range
344
- options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
345
- usingBlock:^(NSParagraphStyle *paragraphStyle, __unused NSRange subrange, __unused BOOL *stop) {
346
- if (!paragraphStyle) {
347
- return;
348
- }
349
- targetLineHeight = MAX(paragraphStyle.minimumLineHeight, targetLineHeight);
350
- }];
351
-
352
- if (targetLineHeight <= 0) {
353
- return 0;
354
- }
355
-
356
- // Center on real text; on a math-only line center the math box instead of its font.
357
- __block CGFloat textLineHeight = 0;
358
- #if ENRICHED_TIPTAP_MATH
359
- __block BOOL hasMath = NO;
360
- #endif
361
- [output enumerateAttributesInRange:range
362
- options:0
363
- usingBlock:^(NSDictionary<NSAttributedStringKey, id> *attrs, __unused NSRange subrange,
364
- __unused BOOL *stop) {
365
- #if ENRICHED_TIPTAP_MATH
366
- if ([attrs[NSAttachmentAttributeName] isKindOfClass:[ENRMMathInlineAttachment class]]) {
367
- hasMath = YES;
368
- return;
369
- }
370
- #endif
371
- UIFont *font = attrs[NSFontAttributeName];
372
- if (font) {
373
- textLineHeight = MAX(UIFontLineHeight(font), textLineHeight);
374
- }
375
- }];
376
-
377
- CGFloat contentLineHeight = textLineHeight;
378
- #if !TARGET_OS_OSX
379
- __block CGFloat pillBoxHeight = 0;
380
- [output enumerateAttribute:NSAttachmentAttributeName
381
- inRange:range
382
- options:0
383
- usingBlock:^(id value, NSRange subrange, BOOL *stop) {
384
- if ([value isKindOfClass:ENRMLinkPillAttachment.class])
385
- pillBoxHeight = MAX(pillBoxHeight, ((ENRMLinkPillAttachment *)value).boxHeight);
386
- }];
387
- contentLineHeight = MAX(contentLineHeight, pillBoxHeight);
388
- #endif
389
-
390
- #if ENRICHED_TIPTAP_MATH
391
- // Math only grows the content height, so measure it (parsing LaTeX) only when text
392
- // alone wouldn't already fill the line.
393
- if (hasMath && targetLineHeight > textLineHeight) {
394
- __block CGFloat mathBoxHeight = 0;
395
- [output enumerateAttribute:NSAttachmentAttributeName
396
- inRange:range
397
- options:0
398
- usingBlock:^(id value, __unused NSRange subrange, __unused BOOL *stop) {
399
- if ([value isKindOfClass:[ENRMMathInlineAttachment class]]) {
400
- mathBoxHeight = MAX(((ENRMMathInlineAttachment *)value).boxHeight, mathBoxHeight);
401
- }
402
- }];
403
- contentLineHeight = MAX(contentLineHeight, mathBoxHeight);
404
- }
405
- #endif
406
-
407
- if (contentLineHeight <= 0 || targetLineHeight <= contentLineHeight) {
408
- return 0;
409
- }
410
-
411
- return (targetLineHeight - contentLineHeight) / 2.0;
412
- }
413
-
414
- // Centers text within its line height (see calculateBaselineOffset). Called per block over its
415
- // own range so blocks can keep different line heights. Ranges that already carry a baseline offset
416
- // are left untouched, keeping nesting (e.g. a blockquote wrapping list items) idempotent.
417
- void applyBaselineOffset(NSMutableAttributedString *output, NSRange range)
418
- {
419
- CGFloat baseLineOffset = calculateBaselineOffset(output, range);
420
- if (baseLineOffset <= 0) {
421
- return;
422
- }
423
-
424
- [output enumerateAttribute:NSBaselineOffsetAttributeName
425
- inRange:range
426
- options:0
427
- usingBlock:^(NSNumber *existingOffset, NSRange subrange, BOOL *stop) {
428
- if (existingOffset != nil) {
429
- return;
430
- }
431
- [output enumerateAttribute:NSAttachmentAttributeName
432
- inRange:subrange
433
- options:0
434
- usingBlock:^(id attachment, NSRange attachmentRange, BOOL *innerStop) {
435
- if ([attachment isKindOfClass:[ENRMImageAttachment class]] &&
436
- !((ENRMImageAttachment *)attachment).isInline) {
437
- return;
438
- }
439
- [output addAttribute:NSBaselineOffsetAttributeName
440
- value:@(baseLineOffset)
441
- range:attachmentRange];
442
- }];
443
- }];
444
- }
445
-
446
- void applyTextAlignment(NSMutableAttributedString *output, NSRange range, NSTextAlignment textAlign)
447
- {
448
- NSMutableParagraphStyle *style = getOrCreateParagraphStyle(output, range.location);
449
- style.alignment = textAlign;
450
- [output addAttribute:NSParagraphStyleAttributeName value:style range:range];
451
- }
452
-
453
- void ENRMApplyLineBreakStrategyToParagraphStyles(NSMutableAttributedString *output,
454
- NSLineBreakStrategy lineBreakStrategy)
455
- {
456
- if (output.length == 0) {
457
- return;
458
- }
459
- [output enumerateAttribute:NSParagraphStyleAttributeName
460
- inRange:NSMakeRange(0, output.length)
461
- options:0
462
- usingBlock:^(NSParagraphStyle *value, NSRange range, BOOL *stop) {
463
- if (!value) {
464
- return;
465
- }
466
- NSMutableParagraphStyle *mutable = [value mutableCopy];
467
- mutable.lineBreakStrategy = lineBreakStrategy;
468
- [output addAttribute:NSParagraphStyleAttributeName value:mutable range:range];
469
- }];
470
- }
471
-
472
- NSTextAlignment textAlignmentFromString(NSString *textAlign)
473
- {
474
- if ([textAlign isEqualToString:@"left"]) {
475
- return NSTextAlignmentLeft;
476
- } else if ([textAlign isEqualToString:@"center"]) {
477
- return NSTextAlignmentCenter;
478
- } else if ([textAlign isEqualToString:@"right"]) {
479
- return NSTextAlignmentRight;
480
- } else if ([textAlign isEqualToString:@"justify"]) {
481
- return NSTextAlignmentJustified;
482
- }
483
- return NSTextAlignmentNatural;
484
- }
1
+ #import "ParagraphStyleUtils.h"
2
+ #import "ENRMFeatureFlags.h"
3
+ #import "ENRMImageAttachment.h"
4
+ #import "ENRMLinkPillAttachment.h"
5
+ #import "LastElementUtils.h"
6
+ #import <React/RCTI18nUtil.h>
7
+
8
+ #if ENRICHED_TIPTAP_MATH
9
+ #import "ENRMMathInlineAttachment.h"
10
+ #endif
11
+
12
+ NSAttributedString *kNewlineAttributedString;
13
+ static NSParagraphStyle *kBlockSpacerTemplate;
14
+
15
+ NSLineBreakStrategy ENRMResolveLineBreakStrategy(NSString *strategy)
16
+ {
17
+ if ([strategy isEqualToString:@"standard"]) {
18
+ return NSLineBreakStrategyStandard;
19
+ } else if ([strategy isEqualToString:@"hangul-word"]) {
20
+ return NSLineBreakStrategyHangulWordPriority;
21
+ } else if ([strategy isEqualToString:@"push-out"]) {
22
+ return NSLineBreakStrategyPushOut;
23
+ }
24
+ return NSLineBreakStrategyNone;
25
+ }
26
+
27
+ NSLineBreakMode ENRMResolveEllipsizeLineBreakMode(NSString *mode)
28
+ {
29
+ if ([mode isEqualToString:@"head"]) {
30
+ return NSLineBreakByTruncatingHead;
31
+ } else if ([mode isEqualToString:@"middle"]) {
32
+ return NSLineBreakByTruncatingMiddle;
33
+ } else if ([mode isEqualToString:@"clip"]) {
34
+ return NSLineBreakByClipping;
35
+ }
36
+ return NSLineBreakByTruncatingTail;
37
+ }
38
+
39
+ __attribute__((constructor)) static void initParagraphStyleUtils(void)
40
+ {
41
+ kNewlineAttributedString = [[NSAttributedString alloc] initWithString:@"\n"];
42
+
43
+ NSMutableParagraphStyle *template = [[NSMutableParagraphStyle alloc] init];
44
+ template.minimumLineHeight = 1;
45
+ template.maximumLineHeight = 1;
46
+ kBlockSpacerTemplate = [template copy];
47
+ }
48
+
49
+ ENRMWritingDirectionMode ENRMResolveWritingDirectionMode(NSString *value)
50
+ {
51
+ if ([value isEqualToString:@"ltr"]) {
52
+ return ENRMWritingDirectionModeLTR;
53
+ }
54
+ if ([value isEqualToString:@"rtl"]) {
55
+ return ENRMWritingDirectionModeRTL;
56
+ }
57
+ if ([value isEqualToString:@"auto"]) {
58
+ return ENRMWritingDirectionModeAuto;
59
+ }
60
+ return ENRMWritingDirectionModeFirstStrong;
61
+ }
62
+
63
+ static BOOL ENRMIsStrongRTLChar(unichar c)
64
+ {
65
+ return (c >= 0x0590 && c <= 0x08FF) || (c >= 0xFB1D && c <= 0xFDFF) || (c >= 0xFE70 && c <= 0xFEFF);
66
+ }
67
+
68
+ NSWritingDirection ENRMFirstStrongDirection(NSString *text)
69
+ {
70
+ NSCharacterSet *letters = [NSCharacterSet letterCharacterSet];
71
+ NSUInteger length = text.length;
72
+ for (NSUInteger i = 0; i < length; i++) {
73
+ unichar c = [text characterAtIndex:i];
74
+ if (![letters characterIsMember:c]) {
75
+ continue;
76
+ }
77
+ return ENRMIsStrongRTLChar(c) ? NSWritingDirectionRightToLeft : NSWritingDirectionLeftToRight;
78
+ }
79
+ return NSWritingDirectionNatural;
80
+ }
81
+
82
+ BOOL ENRMParagraphIsRTL(NSParagraphStyle *style)
83
+ {
84
+ if (style && style.baseWritingDirection != NSWritingDirectionNatural) {
85
+ return style.baseWritingDirection == NSWritingDirectionRightToLeft;
86
+ }
87
+ return [[RCTI18nUtil sharedInstance] isRTL];
88
+ }
89
+
90
+ void ENRMApplyWritingDirectionMode(NSMutableAttributedString *output, ENRMWritingDirectionMode mode,
91
+ NSWritingDirection layoutDirection)
92
+ {
93
+ switch (mode) {
94
+ case ENRMWritingDirectionModeAuto:
95
+ ENRMApplyWritingDirectionToParagraphStyles(output, NSWritingDirectionNatural);
96
+ break;
97
+ case ENRMWritingDirectionModeLTR:
98
+ ENRMApplyWritingDirectionToParagraphStyles(output, NSWritingDirectionLeftToRight);
99
+ break;
100
+ case ENRMWritingDirectionModeRTL:
101
+ ENRMApplyWritingDirectionToParagraphStyles(output, NSWritingDirectionRightToLeft);
102
+ break;
103
+ case ENRMWritingDirectionModeFirstStrong:
104
+ ENRMApplyFirstStrongParagraphDirections(output, layoutDirection);
105
+ break;
106
+ }
107
+ }
108
+
109
+ void ENRMApplyFirstStrongParagraphDirections(NSMutableAttributedString *output, NSWritingDirection fallback)
110
+ {
111
+ if (output.length == 0) {
112
+ return;
113
+ }
114
+ NSString *string = output.string;
115
+ NSUInteger length = string.length;
116
+ NSUInteger position = 0;
117
+ while (position < length) {
118
+ NSRange paragraphRange = [string paragraphRangeForRange:NSMakeRange(position, 0)];
119
+ if (NSMaxRange(paragraphRange) <= position) {
120
+ break;
121
+ }
122
+ position = NSMaxRange(paragraphRange);
123
+
124
+ NSNumber *isCodeBlock = [output attribute:CodeBlockAttributeName
125
+ atIndex:paragraphRange.location
126
+ effectiveRange:nil];
127
+ if (isCodeBlock.boolValue) {
128
+ continue;
129
+ }
130
+
131
+ NSWritingDirection direction = ENRMFirstStrongDirection([string substringWithRange:paragraphRange]);
132
+ if (direction == NSWritingDirectionNatural) {
133
+ direction = fallback;
134
+ }
135
+ if (direction == NSWritingDirectionNatural) {
136
+ continue;
137
+ }
138
+
139
+ [output enumerateAttribute:NSParagraphStyleAttributeName
140
+ inRange:paragraphRange
141
+ options:0
142
+ usingBlock:^(NSParagraphStyle *style, NSRange range, BOOL *stop) {
143
+ if (style != nil && style.baseWritingDirection == direction) {
144
+ return;
145
+ }
146
+ NSMutableParagraphStyle *updated =
147
+ style ? [style mutableCopy] : [[NSMutableParagraphStyle alloc] init];
148
+ updated.baseWritingDirection = direction;
149
+ [output addAttribute:NSParagraphStyleAttributeName value:updated range:range];
150
+ }];
151
+ }
152
+ }
153
+
154
+ void ENRMApplyWritingDirectionToParagraphStyles(NSMutableAttributedString *output, NSWritingDirection writingDirection)
155
+ {
156
+ if (output.length == 0) {
157
+ return;
158
+ }
159
+ [output enumerateAttribute:NSParagraphStyleAttributeName
160
+ inRange:NSMakeRange(0, output.length)
161
+ options:0
162
+ usingBlock:^(NSParagraphStyle *style, NSRange range, BOOL *stop) {
163
+ if (!style) {
164
+ return;
165
+ }
166
+ // Skip runs already in the target direction (issue #739),
167
+ // mirroring ENRMApplyFirstStrongParagraphDirections.
168
+ if (style.baseWritingDirection == writingDirection) {
169
+ return;
170
+ }
171
+ NSNumber *isCodeBlock = [output attribute:CodeBlockAttributeName
172
+ atIndex:range.location
173
+ effectiveRange:nil];
174
+ if (isCodeBlock.boolValue) {
175
+ return;
176
+ }
177
+ NSMutableParagraphStyle *mutable = [style mutableCopy];
178
+ mutable.baseWritingDirection = writingDirection;
179
+ [output addAttribute:NSParagraphStyleAttributeName value:mutable range:range];
180
+ }];
181
+ }
182
+
183
+ NSMutableParagraphStyle *getOrCreateParagraphStyle(NSMutableAttributedString *output, NSUInteger index)
184
+ {
185
+ NSParagraphStyle *existing = [output attribute:NSParagraphStyleAttributeName atIndex:index effectiveRange:NULL];
186
+ NSMutableParagraphStyle *style = existing ? [existing mutableCopy] : [[NSMutableParagraphStyle alloc] init];
187
+ return style;
188
+ }
189
+
190
+ void applyParagraphSpacingAfter(NSMutableAttributedString *output, NSUInteger start, CGFloat marginBottom)
191
+ {
192
+ [output appendAttributedString:kNewlineAttributedString];
193
+
194
+ NSMutableParagraphStyle *style = getOrCreateParagraphStyle(output, start);
195
+ style.paragraphSpacing = marginBottom;
196
+
197
+ NSRange range = NSMakeRange(start, output.length - start);
198
+ [output addAttribute:NSParagraphStyleAttributeName value:style range:range];
199
+ }
200
+
201
+ NSUInteger applyParagraphSpacingBefore(NSMutableAttributedString *output, NSRange range, CGFloat marginTop)
202
+ {
203
+ if (marginTop <= 0 || range.location == 0)
204
+ return 0;
205
+
206
+ NSUInteger prevIdx = range.location - 1;
207
+ if ([output.string characterAtIndex:prevIdx] != '\n')
208
+ return 0;
209
+
210
+ NSParagraphStyle *prevStyle = [output attribute:NSParagraphStyleAttributeName atIndex:prevIdx effectiveRange:NULL];
211
+
212
+ CGFloat prevMarginBottom = prevStyle.paragraphSpacing;
213
+ if (prevMarginBottom >= marginTop)
214
+ return 0;
215
+
216
+ CGFloat extraGap = marginTop - prevMarginBottom;
217
+
218
+ NSMutableParagraphStyle *spacerStyle = [kBlockSpacerTemplate mutableCopy];
219
+ spacerStyle.paragraphSpacing = MAX(0, extraGap - 1.0);
220
+
221
+ NSDictionary *attrs = @{NSParagraphStyleAttributeName : spacerStyle};
222
+ NSAttributedString *spacer = [[NSAttributedString alloc] initWithString:@"\n" attributes:attrs];
223
+
224
+ [output insertAttributedString:spacer atIndex:range.location];
225
+ return 1;
226
+ }
227
+
228
+ NSUInteger applyBlockSpacingBefore(NSMutableAttributedString *output, NSUInteger insertionPoint, CGFloat marginTop)
229
+ {
230
+ if (marginTop <= 0) {
231
+ return 0;
232
+ }
233
+
234
+ CGFloat spacing = marginTop;
235
+
236
+ // At index 0 the spacer \n produces a 1pt line fragment (minimumLineHeight=1)
237
+ // on top of paragraphSpacing. Subtract it so the total equals the desired margin.
238
+ // For non-zero positions the 1pt is intentional inter-block spacing.
239
+ if (insertionPoint == 0) {
240
+ spacing = MAX(0, marginTop - 1.0);
241
+ }
242
+
243
+ NSMutableParagraphStyle *spacerStyle = [kBlockSpacerTemplate mutableCopy];
244
+ spacerStyle.paragraphSpacing = spacing;
245
+
246
+ NSAttributedString *spacer =
247
+ [[NSAttributedString alloc] initWithString:@"\n" attributes:@{NSParagraphStyleAttributeName : spacerStyle}];
248
+
249
+ [output insertAttributedString:spacer atIndex:insertionPoint];
250
+ return 1;
251
+ }
252
+
253
+ void applyBlockSpacingAfter(NSMutableAttributedString *output, CGFloat marginBottom)
254
+ {
255
+ if (marginBottom <= 0) {
256
+ return;
257
+ }
258
+
259
+ NSUInteger spacerLocation = output.length;
260
+ [output appendAttributedString:kNewlineAttributedString];
261
+
262
+ NSMutableParagraphStyle *spacerStyle = [kBlockSpacerTemplate mutableCopy];
263
+ spacerStyle.paragraphSpacing = marginBottom;
264
+
265
+ [output addAttribute:NSParagraphStyleAttributeName value:spacerStyle range:NSMakeRange(spacerLocation, 1)];
266
+ }
267
+
268
+ CGFloat ENRMLineHeightWithLinkPills(NSAttributedString *text, NSRange range, CGFloat lineHeight)
269
+ {
270
+ #if !TARGET_OS_OSX
271
+ __block CGFloat fitting = lineHeight;
272
+ [text enumerateAttribute:NSAttachmentAttributeName
273
+ inRange:range
274
+ options:0
275
+ usingBlock:^(id value, __unused NSRange subrange, __unused BOOL *stop) {
276
+ if ([value isKindOfClass:ENRMLinkPillAttachment.class])
277
+ fitting = MAX(fitting, ((ENRMLinkPillAttachment *)value).lineHeight);
278
+ }];
279
+ return fitting;
280
+ #else
281
+ return lineHeight;
282
+ #endif
283
+ }
284
+
285
+ // UIKit's own key for the pre-substitution font. Not exported by any SDK header, so it is spelled out
286
+ // here; it is the same string UIKit writes into a UITextView's storage when it substitutes a font.
287
+ static NSString *const ENRMOriginalFontAttributeName = @"NSOriginalFont";
288
+
289
+ void ENRMPinLineMetricsToStyledFonts(NSMutableAttributedString *output, NSRange range)
290
+ {
291
+ if (range.length == 0 || NSMaxRange(range) > output.length) {
292
+ return;
293
+ }
294
+
295
+ [output enumerateAttribute:NSFontAttributeName
296
+ inRange:range
297
+ options:0
298
+ usingBlock:^(UIFont *font, NSRange fontRange, __unused BOOL *stop) {
299
+ if (font) {
300
+ [output addAttribute:ENRMOriginalFontAttributeName value:font range:fontRange];
301
+ }
302
+ }];
303
+ }
304
+
305
+ // Floor, not clamp: minimumLineHeight keeps short lines at lineHeight, while maximumLineHeight = 0 lets
306
+ // a line grow to fit a taller run (large inline code, math, images) instead of clipping it.
307
+ // We can diverge from RN's clamp because we measure the real laid-out height, so grown lines are reserved.
308
+ void ENRMApplyLineHeightToParagraphStyle(NSMutableParagraphStyle *style, CGFloat lineHeight)
309
+ {
310
+ if (lineHeight <= 0) {
311
+ return;
312
+ }
313
+
314
+ style.minimumLineHeight = lineHeight;
315
+ style.maximumLineHeight = 0;
316
+ }
317
+
318
+ void applyLineHeight(NSMutableAttributedString *output, NSRange range, CGFloat lineHeight)
319
+ {
320
+ lineHeight = ENRMLineHeightWithLinkPills(output, range, lineHeight);
321
+ if (lineHeight <= 0) {
322
+ return;
323
+ }
324
+
325
+ NSMutableParagraphStyle *style = getOrCreateParagraphStyle(output, range.location);
326
+ ENRMApplyLineHeightToParagraphStyle(style, lineHeight);
327
+
328
+ [output addAttribute:NSParagraphStyleAttributeName value:style range:range];
329
+ }
330
+
331
+ // Calculates the offset needed to center the text within the line height. Returns 0
332
+ // when the range has no minimum line height or its content already fills the line.
333
+ CGFloat calculateBaselineOffset(NSAttributedString *output, NSRange range)
334
+ {
335
+ if (range.length == 0) {
336
+ return 0;
337
+ }
338
+
339
+ // applyLineHeight floors lines with minimumLineHeight (maximumLineHeight is 0 for grown lines,
340
+ // or equal to the minimum for re-clamped code blocks), so the target is the minimum line height.
341
+ __block CGFloat targetLineHeight = 0;
342
+ [output enumerateAttribute:NSParagraphStyleAttributeName
343
+ inRange:range
344
+ options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired
345
+ usingBlock:^(NSParagraphStyle *paragraphStyle, __unused NSRange subrange, __unused BOOL *stop) {
346
+ if (!paragraphStyle) {
347
+ return;
348
+ }
349
+ targetLineHeight = MAX(paragraphStyle.minimumLineHeight, targetLineHeight);
350
+ }];
351
+
352
+ if (targetLineHeight <= 0) {
353
+ return 0;
354
+ }
355
+
356
+ // Center on real text; on a math-only line center the math box instead of its font.
357
+ __block CGFloat textLineHeight = 0;
358
+ #if ENRICHED_TIPTAP_MATH
359
+ __block BOOL hasMath = NO;
360
+ #endif
361
+ [output enumerateAttributesInRange:range
362
+ options:0
363
+ usingBlock:^(NSDictionary<NSAttributedStringKey, id> *attrs, __unused NSRange subrange,
364
+ __unused BOOL *stop) {
365
+ #if ENRICHED_TIPTAP_MATH
366
+ if ([attrs[NSAttachmentAttributeName] isKindOfClass:[ENRMMathInlineAttachment class]]) {
367
+ hasMath = YES;
368
+ return;
369
+ }
370
+ #endif
371
+ UIFont *font = attrs[NSFontAttributeName];
372
+ if (font) {
373
+ textLineHeight = MAX(UIFontLineHeight(font), textLineHeight);
374
+ }
375
+ }];
376
+
377
+ CGFloat contentLineHeight = textLineHeight;
378
+ #if !TARGET_OS_OSX
379
+ __block CGFloat pillBoxHeight = 0;
380
+ [output enumerateAttribute:NSAttachmentAttributeName
381
+ inRange:range
382
+ options:0
383
+ usingBlock:^(id value, NSRange subrange, BOOL *stop) {
384
+ if ([value isKindOfClass:ENRMLinkPillAttachment.class])
385
+ pillBoxHeight = MAX(pillBoxHeight, ((ENRMLinkPillAttachment *)value).boxHeight);
386
+ }];
387
+ contentLineHeight = MAX(contentLineHeight, pillBoxHeight);
388
+ #endif
389
+
390
+ #if ENRICHED_TIPTAP_MATH
391
+ // Math only grows the content height, so measure it (parsing LaTeX) only when text
392
+ // alone wouldn't already fill the line.
393
+ if (hasMath && targetLineHeight > textLineHeight) {
394
+ __block CGFloat mathBoxHeight = 0;
395
+ [output enumerateAttribute:NSAttachmentAttributeName
396
+ inRange:range
397
+ options:0
398
+ usingBlock:^(id value, __unused NSRange subrange, __unused BOOL *stop) {
399
+ if ([value isKindOfClass:[ENRMMathInlineAttachment class]]) {
400
+ mathBoxHeight = MAX(((ENRMMathInlineAttachment *)value).boxHeight, mathBoxHeight);
401
+ }
402
+ }];
403
+ contentLineHeight = MAX(contentLineHeight, mathBoxHeight);
404
+ }
405
+ #endif
406
+
407
+ if (contentLineHeight <= 0 || targetLineHeight <= contentLineHeight) {
408
+ return 0;
409
+ }
410
+
411
+ return (targetLineHeight - contentLineHeight) / 2.0;
412
+ }
413
+
414
+ // Centers text within its line height (see calculateBaselineOffset). Called per block over its
415
+ // own range so blocks can keep different line heights. Ranges that already carry a baseline offset
416
+ // are left untouched, keeping nesting (e.g. a blockquote wrapping list items) idempotent.
417
+ void applyBaselineOffset(NSMutableAttributedString *output, NSRange range)
418
+ {
419
+ CGFloat baseLineOffset = calculateBaselineOffset(output, range);
420
+ if (baseLineOffset <= 0) {
421
+ return;
422
+ }
423
+
424
+ [output enumerateAttribute:NSBaselineOffsetAttributeName
425
+ inRange:range
426
+ options:0
427
+ usingBlock:^(NSNumber *existingOffset, NSRange subrange, BOOL *stop) {
428
+ if (existingOffset != nil) {
429
+ return;
430
+ }
431
+ [output enumerateAttribute:NSAttachmentAttributeName
432
+ inRange:subrange
433
+ options:0
434
+ usingBlock:^(id attachment, NSRange attachmentRange, BOOL *innerStop) {
435
+ if ([attachment isKindOfClass:[ENRMImageAttachment class]] &&
436
+ !((ENRMImageAttachment *)attachment).isInline) {
437
+ return;
438
+ }
439
+ [output addAttribute:NSBaselineOffsetAttributeName
440
+ value:@(baseLineOffset)
441
+ range:attachmentRange];
442
+ }];
443
+ }];
444
+ }
445
+
446
+ void applyTextAlignment(NSMutableAttributedString *output, NSRange range, NSTextAlignment textAlign)
447
+ {
448
+ NSMutableParagraphStyle *style = getOrCreateParagraphStyle(output, range.location);
449
+ style.alignment = textAlign;
450
+ [output addAttribute:NSParagraphStyleAttributeName value:style range:range];
451
+ }
452
+
453
+ void ENRMApplyLineBreakStrategyToParagraphStyles(NSMutableAttributedString *output,
454
+ NSLineBreakStrategy lineBreakStrategy)
455
+ {
456
+ if (output.length == 0) {
457
+ return;
458
+ }
459
+ [output enumerateAttribute:NSParagraphStyleAttributeName
460
+ inRange:NSMakeRange(0, output.length)
461
+ options:0
462
+ usingBlock:^(NSParagraphStyle *value, NSRange range, BOOL *stop) {
463
+ if (!value) {
464
+ return;
465
+ }
466
+ NSMutableParagraphStyle *mutable = [value mutableCopy];
467
+ mutable.lineBreakStrategy = lineBreakStrategy;
468
+ [output addAttribute:NSParagraphStyleAttributeName value:mutable range:range];
469
+ }];
470
+ }
471
+
472
+ NSTextAlignment textAlignmentFromString(NSString *textAlign)
473
+ {
474
+ if ([textAlign isEqualToString:@"left"]) {
475
+ return NSTextAlignmentLeft;
476
+ } else if ([textAlign isEqualToString:@"center"]) {
477
+ return NSTextAlignmentCenter;
478
+ } else if ([textAlign isEqualToString:@"right"]) {
479
+ return NSTextAlignmentRight;
480
+ } else if ([textAlign isEqualToString:@"justify"]) {
481
+ return NSTextAlignmentJustified;
482
+ }
483
+ return NSTextAlignmentNatural;
484
+ }