@mathers101/react-native-render-rich-text 0.0.0-stage → 0.1.10

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 (358) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +140 -3
  3. package/ReactNativeRenderRichText.podspec +23 -0
  4. package/android/build.gradle +86 -0
  5. package/android/consumer-rules.pro +3 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/cpp/jni-adapter.cpp +191 -0
  8. package/android/src/main/java/com/renderrichtext/EnrichedTiptapText.kt +673 -0
  9. package/android/src/main/java/com/renderrichtext/EnrichedTiptapTextLayoutManager.kt +24 -0
  10. package/android/src/main/java/com/renderrichtext/EnrichedTiptapTextManager.kt +405 -0
  11. package/android/src/main/java/com/renderrichtext/EnrichedTiptapTextPackage.kt +13 -0
  12. package/android/src/main/java/com/renderrichtext/MeasurementStore.kt +644 -0
  13. package/android/src/main/java/com/renderrichtext/accessibility/AccessibilityLabels.kt +17 -0
  14. package/android/src/main/java/com/renderrichtext/accessibility/AccessibleTiptapTextView.kt +112 -0
  15. package/android/src/main/java/com/renderrichtext/accessibility/TiptapAccessibilityHelper.kt +576 -0
  16. package/android/src/main/java/com/renderrichtext/events/CodeBlockPressEvent.kt +24 -0
  17. package/android/src/main/java/com/renderrichtext/events/ContextMenuItemPressEvent.kt +28 -0
  18. package/android/src/main/java/com/renderrichtext/events/CopyPressEvent.kt +24 -0
  19. package/android/src/main/java/com/renderrichtext/events/FactoidPressEvent.kt +23 -0
  20. package/android/src/main/java/com/renderrichtext/events/ImagePressEvent.kt +25 -0
  21. package/android/src/main/java/com/renderrichtext/events/LatexErrorEvent.kt +29 -0
  22. package/android/src/main/java/com/renderrichtext/events/LinkLongPressEvent.kt +23 -0
  23. package/android/src/main/java/com/renderrichtext/events/LinkPressEvent.kt +23 -0
  24. package/android/src/main/java/com/renderrichtext/events/MentionLongPressEvent.kt +25 -0
  25. package/android/src/main/java/com/renderrichtext/events/MentionPressEvent.kt +25 -0
  26. package/android/src/main/java/com/renderrichtext/events/TaskListItemPressEvent.kt +26 -0
  27. package/android/src/main/java/com/renderrichtext/math/LatexErrorReporter.kt +9 -0
  28. package/android/src/main/java/com/renderrichtext/parser/Parser.kt +59 -0
  29. package/android/src/main/java/com/renderrichtext/parser/TextLinkMatching.kt +35 -0
  30. package/android/src/main/java/com/renderrichtext/parser/TiptapASTNode.kt +69 -0
  31. package/android/src/main/java/com/renderrichtext/renderer/BaselineShiftRenderer.kt +45 -0
  32. package/android/src/main/java/com/renderrichtext/renderer/BlankLineRenderer.kt +39 -0
  33. package/android/src/main/java/com/renderrichtext/renderer/BlockStyleContext.kt +181 -0
  34. package/android/src/main/java/com/renderrichtext/renderer/BlockquoteRenderer.kt +243 -0
  35. package/android/src/main/java/com/renderrichtext/renderer/BlockquoteTextRenderer.kt +56 -0
  36. package/android/src/main/java/com/renderrichtext/renderer/CodeBlockRenderer.kt +135 -0
  37. package/android/src/main/java/com/renderrichtext/renderer/CodeRenderer.kt +37 -0
  38. package/android/src/main/java/com/renderrichtext/renderer/EmphasisRenderer.kt +28 -0
  39. package/android/src/main/java/com/renderrichtext/renderer/FactoidRenderer.kt +97 -0
  40. package/android/src/main/java/com/renderrichtext/renderer/HeadingRenderer.kt +81 -0
  41. package/android/src/main/java/com/renderrichtext/renderer/HighlightRenderer.kt +26 -0
  42. package/android/src/main/java/com/renderrichtext/renderer/LineBreakRenderer.kt +17 -0
  43. package/android/src/main/java/com/renderrichtext/renderer/LinkRenderer.kt +90 -0
  44. package/android/src/main/java/com/renderrichtext/renderer/ListContextManager.kt +109 -0
  45. package/android/src/main/java/com/renderrichtext/renderer/ListItemRenderer.kt +211 -0
  46. package/android/src/main/java/com/renderrichtext/renderer/ListRenderer.kt +133 -0
  47. package/android/src/main/java/com/renderrichtext/renderer/MentionRenderer.kt +85 -0
  48. package/android/src/main/java/com/renderrichtext/renderer/NodeRenderer.kt +207 -0
  49. package/android/src/main/java/com/renderrichtext/renderer/ParagraphRenderer.kt +91 -0
  50. package/android/src/main/java/com/renderrichtext/renderer/Renderer.kt +148 -0
  51. package/android/src/main/java/com/renderrichtext/renderer/SoftBreakRenderer.kt +17 -0
  52. package/android/src/main/java/com/renderrichtext/renderer/SpanStyleCache.kt +143 -0
  53. package/android/src/main/java/com/renderrichtext/renderer/StrikethroughRenderer.kt +28 -0
  54. package/android/src/main/java/com/renderrichtext/renderer/StrongRenderer.kt +28 -0
  55. package/android/src/main/java/com/renderrichtext/renderer/TextRenderer.kt +31 -0
  56. package/android/src/main/java/com/renderrichtext/renderer/ThematicBreakRenderer.kt +46 -0
  57. package/android/src/main/java/com/renderrichtext/renderer/UnderlineRenderer.kt +28 -0
  58. package/android/src/main/java/com/renderrichtext/spans/BaseListSpan.kt +164 -0
  59. package/android/src/main/java/com/renderrichtext/spans/BaselineShiftSpan.kt +27 -0
  60. package/android/src/main/java/com/renderrichtext/spans/BlockquoteSpan.kt +302 -0
  61. package/android/src/main/java/com/renderrichtext/spans/CodeBackgroundSpan.kt +205 -0
  62. package/android/src/main/java/com/renderrichtext/spans/CodeBlockSpan.kt +216 -0
  63. package/android/src/main/java/com/renderrichtext/spans/CodeSpan.kt +32 -0
  64. package/android/src/main/java/com/renderrichtext/spans/EmphasisSpan.kt +42 -0
  65. package/android/src/main/java/com/renderrichtext/spans/FactoidBackgroundSpan.kt +265 -0
  66. package/android/src/main/java/com/renderrichtext/spans/FactoidPaddingSpan.kt +258 -0
  67. package/android/src/main/java/com/renderrichtext/spans/FactoidSpan.kt +32 -0
  68. package/android/src/main/java/com/renderrichtext/spans/FadeInSpan.kt +29 -0
  69. package/android/src/main/java/com/renderrichtext/spans/HeadingSpan.kt +38 -0
  70. package/android/src/main/java/com/renderrichtext/spans/HighlightSpan.kt +80 -0
  71. package/android/src/main/java/com/renderrichtext/spans/ImageSpan.kt +481 -0
  72. package/android/src/main/java/com/renderrichtext/spans/InlineBackgroundGeometry.kt +42 -0
  73. package/android/src/main/java/com/renderrichtext/spans/LineHeightSpan.kt +39 -0
  74. package/android/src/main/java/com/renderrichtext/spans/LinkPillIconCache.kt +154 -0
  75. package/android/src/main/java/com/renderrichtext/spans/LinkPillSpan.kt +381 -0
  76. package/android/src/main/java/com/renderrichtext/spans/LinkSpan.kt +68 -0
  77. package/android/src/main/java/com/renderrichtext/spans/ListItemSpacingSpan.kt +33 -0
  78. package/android/src/main/java/com/renderrichtext/spans/ListMarkerAnchorSpan.kt +38 -0
  79. package/android/src/main/java/com/renderrichtext/spans/MarginBottomSpan.kt +76 -0
  80. package/android/src/main/java/com/renderrichtext/spans/MentionChipSpan.kt +132 -0
  81. package/android/src/main/java/com/renderrichtext/spans/MentionSpan.kt +46 -0
  82. package/android/src/main/java/com/renderrichtext/spans/OrderedListSpan.kt +127 -0
  83. package/android/src/main/java/com/renderrichtext/spans/SpoilerSpan.kt +33 -0
  84. package/android/src/main/java/com/renderrichtext/spans/StrikethroughSpan.kt +12 -0
  85. package/android/src/main/java/com/renderrichtext/spans/StrongSpan.kt +39 -0
  86. package/android/src/main/java/com/renderrichtext/spans/TaskListSpan.kt +143 -0
  87. package/android/src/main/java/com/renderrichtext/spans/TextSpan.kt +26 -0
  88. package/android/src/main/java/com/renderrichtext/spans/ThematicBreakSpan.kt +69 -0
  89. package/android/src/main/java/com/renderrichtext/spans/UnorderedListSpan.kt +96 -0
  90. package/android/src/main/java/com/renderrichtext/spoiler/SpoilerStubs.kt +46 -0
  91. package/android/src/main/java/com/renderrichtext/styles/BaseBlockStyle.kt +11 -0
  92. package/android/src/main/java/com/renderrichtext/styles/BlockquoteStyle.kt +83 -0
  93. package/android/src/main/java/com/renderrichtext/styles/CodeBlockStyle.kt +80 -0
  94. package/android/src/main/java/com/renderrichtext/styles/CodeStyle.kt +26 -0
  95. package/android/src/main/java/com/renderrichtext/styles/EmphasisStyle.kt +21 -0
  96. package/android/src/main/java/com/renderrichtext/styles/FactoidStyle.kt +21 -0
  97. package/android/src/main/java/com/renderrichtext/styles/HeadingStyle.kt +33 -0
  98. package/android/src/main/java/com/renderrichtext/styles/HighlightStyle.kt +19 -0
  99. package/android/src/main/java/com/renderrichtext/styles/ImageStyle.kt +29 -0
  100. package/android/src/main/java/com/renderrichtext/styles/InlineImageStyle.kt +17 -0
  101. package/android/src/main/java/com/renderrichtext/styles/InlineMathStyle.kt +17 -0
  102. package/android/src/main/java/com/renderrichtext/styles/LinkPillContent.kt +36 -0
  103. package/android/src/main/java/com/renderrichtext/styles/LinkPillStyle.kt +44 -0
  104. package/android/src/main/java/com/renderrichtext/styles/LinkStyle.kt +23 -0
  105. package/android/src/main/java/com/renderrichtext/styles/LinkVariantEntry.kt +34 -0
  106. package/android/src/main/java/com/renderrichtext/styles/ListStyle.kt +65 -0
  107. package/android/src/main/java/com/renderrichtext/styles/MathStyle.kt +29 -0
  108. package/android/src/main/java/com/renderrichtext/styles/MentionStyle.kt +19 -0
  109. package/android/src/main/java/com/renderrichtext/styles/ParagraphStyle.kt +33 -0
  110. package/android/src/main/java/com/renderrichtext/styles/SpoilerStyle.kt +27 -0
  111. package/android/src/main/java/com/renderrichtext/styles/StrikethroughStyle.kt +17 -0
  112. package/android/src/main/java/com/renderrichtext/styles/StrongStyle.kt +21 -0
  113. package/android/src/main/java/com/renderrichtext/styles/StyleConfig.kt +411 -0
  114. package/android/src/main/java/com/renderrichtext/styles/StyleParser.kt +92 -0
  115. package/android/src/main/java/com/renderrichtext/styles/SubscriptStyle.kt +16 -0
  116. package/android/src/main/java/com/renderrichtext/styles/SuperscriptStyle.kt +16 -0
  117. package/android/src/main/java/com/renderrichtext/styles/TableStyle.kt +75 -0
  118. package/android/src/main/java/com/renderrichtext/styles/TaskListStyle.kt +29 -0
  119. package/android/src/main/java/com/renderrichtext/styles/TextAlignment.kt +32 -0
  120. package/android/src/main/java/com/renderrichtext/styles/ThematicBreakStyle.kt +23 -0
  121. package/android/src/main/java/com/renderrichtext/styles/UnderlineStyle.kt +17 -0
  122. package/android/src/main/java/com/renderrichtext/styles/VideoStyle.kt +31 -0
  123. package/android/src/main/java/com/renderrichtext/utils/common/BorderStyleUtils.kt +86 -0
  124. package/android/src/main/java/com/renderrichtext/utils/common/BreakStrategyUtils.kt +32 -0
  125. package/android/src/main/java/com/renderrichtext/utils/common/CodeBlockHighlighter.kt +36 -0
  126. package/android/src/main/java/com/renderrichtext/utils/common/CodeBlockNode.kt +42 -0
  127. package/android/src/main/java/com/renderrichtext/utils/common/EllipsizeUtils.kt +27 -0
  128. package/android/src/main/java/com/renderrichtext/utils/common/EnrichedTiptapAncestorUtils.kt +10 -0
  129. package/android/src/main/java/com/renderrichtext/utils/common/FeatureFlags.kt +9 -0
  130. package/android/src/main/java/com/renderrichtext/utils/common/LinkRecognitionProps.kt +31 -0
  131. package/android/src/main/java/com/renderrichtext/utils/common/LinkRegexConfig.kt +56 -0
  132. package/android/src/main/java/com/renderrichtext/utils/common/MotionPreferences.kt +18 -0
  133. package/android/src/main/java/com/renderrichtext/utils/common/ReadableMapExtensions.kt +28 -0
  134. package/android/src/main/java/com/renderrichtext/utils/common/TiptapViewManagerUtils.kt +242 -0
  135. package/android/src/main/java/com/renderrichtext/utils/common/layout/RTLUtils.kt +6 -0
  136. package/android/src/main/java/com/renderrichtext/utils/common/serialization/TiptapASTSerializer.kt +368 -0
  137. package/android/src/main/java/com/renderrichtext/utils/text/ImageCache.kt +88 -0
  138. package/android/src/main/java/com/renderrichtext/utils/text/ImageDownloader.kt +203 -0
  139. package/android/src/main/java/com/renderrichtext/utils/text/LocalImageLoader.kt +167 -0
  140. package/android/src/main/java/com/renderrichtext/utils/text/TailFadeInAnimator.kt +84 -0
  141. package/android/src/main/java/com/renderrichtext/utils/text/conversion/HTMLGenerator.kt +1105 -0
  142. package/android/src/main/java/com/renderrichtext/utils/text/conversion/TiptapExtractor.kt +423 -0
  143. package/android/src/main/java/com/renderrichtext/utils/text/extensions/ParagraphUtils.kt +9 -0
  144. package/android/src/main/java/com/renderrichtext/utils/text/extensions/SpannableExtensions.kt +9 -0
  145. package/android/src/main/java/com/renderrichtext/utils/text/extensions/TextPaintExtensions.kt +76 -0
  146. package/android/src/main/java/com/renderrichtext/utils/text/interaction/CheckboxTouchHelper.kt +61 -0
  147. package/android/src/main/java/com/renderrichtext/utils/text/interaction/TaskListTapUtils.kt +286 -0
  148. package/android/src/main/java/com/renderrichtext/utils/text/span/ApplyLineHeight.kt +39 -0
  149. package/android/src/main/java/com/renderrichtext/utils/text/span/BlockSpacing.kt +142 -0
  150. package/android/src/main/java/com/renderrichtext/utils/text/span/SpanFlags.kt +43 -0
  151. package/android/src/main/java/com/renderrichtext/utils/text/span/WidthAwareSpans.kt +30 -0
  152. package/android/src/main/java/com/renderrichtext/utils/text/view/CodeBlockPressHost.kt +15 -0
  153. package/android/src/main/java/com/renderrichtext/utils/text/view/ImagePressHost.kt +19 -0
  154. package/android/src/main/java/com/renderrichtext/utils/text/view/LinkEvents.kt +88 -0
  155. package/android/src/main/java/com/renderrichtext/utils/text/view/LinkLongPressMovementMethod.kt +449 -0
  156. package/android/src/main/java/com/renderrichtext/utils/text/view/SelectionActionMode.kt +235 -0
  157. package/android/src/main/java/com/renderrichtext/utils/text/view/TextSelectionColors.kt +48 -0
  158. package/android/src/main/java/com/renderrichtext/utils/text/view/TextViewSetup.kt +119 -0
  159. package/android/src/main/java/com/renderrichtext/views/ContextMenuPopup.kt +217 -0
  160. package/android/src/main/java/com/renderrichtext/views/CopyGlyph.kt +101 -0
  161. package/android/src/main/java/com/renderrichtext/views/WrapGlyph.kt +40 -0
  162. package/android/src/main/jni/CMakeLists.txt +52 -0
  163. package/android/src/main/jni/react/renderer/components/RichTextSpec/ComponentDescriptors.h +30 -0
  164. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextComponentDescriptor.h +29 -0
  165. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextMeasurementManager.cpp +45 -0
  166. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextMeasurementManager.h +21 -0
  167. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextShadowNode.cpp +38 -0
  168. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextShadowNode.h +53 -0
  169. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextState.cpp +9 -0
  170. package/android/src/main/jni/react/renderer/components/RichTextSpec/TiptapTextState.h +24 -0
  171. package/android/src/main/jni/react/renderer/components/RichTextSpec/conversions.h +40 -0
  172. package/cpp/parser/TiptapASTNode.hpp +68 -0
  173. package/cpp/parser/TiptapParser.cpp +233 -0
  174. package/cpp/parser/TiptapParser.hpp +13 -0
  175. package/cpp/vendor/nlohmann/json.hpp +24765 -0
  176. package/ios/EnrichedTiptapText.h +27 -0
  177. package/ios/EnrichedTiptapText.mm +1222 -0
  178. package/ios/attachments/ENRMImageAttachment.h +51 -0
  179. package/ios/attachments/ENRMImageAttachment.m +398 -0
  180. package/ios/attachments/ENRMLinkPillAttachment.h +47 -0
  181. package/ios/attachments/ENRMLinkPillAttachment.m +324 -0
  182. package/ios/attachments/ENRMLinkPillIconCache.h +28 -0
  183. package/ios/attachments/ENRMLinkPillIconCache.m +181 -0
  184. package/ios/attachments/ENRMLinkPillText.h +27 -0
  185. package/ios/attachments/ENRMLinkPillText.m +118 -0
  186. package/ios/attachments/ENRMMathInlineAttachment.h +7 -0
  187. package/ios/attachments/ENRMMathInlineAttachment.m +4 -0
  188. package/ios/attachments/ThematicBreakAttachment.h +15 -0
  189. package/ios/attachments/ThematicBreakAttachment.m +33 -0
  190. package/ios/internals/ENRMViewFreeMeasurement.h +208 -0
  191. package/ios/internals/EnrichedTiptapTextComponentDescriptor.h +19 -0
  192. package/ios/internals/EnrichedTiptapTextShadowNode.h +43 -0
  193. package/ios/internals/EnrichedTiptapTextShadowNode.mm +69 -0
  194. package/ios/internals/EnrichedTiptapTextState.h +24 -0
  195. package/ios/internals/MeasurementCache.h +308 -0
  196. package/ios/internals/ShadowMeasurementUtils.h +145 -0
  197. package/ios/parser/ENRMTextLinkAttributes.h +7 -0
  198. package/ios/parser/ENRMTiptapParser.h +33 -0
  199. package/ios/parser/ENRMTiptapParser.mm +73 -0
  200. package/ios/parser/TiptapASTNode.h +57 -0
  201. package/ios/parser/TiptapASTNode.m +52 -0
  202. package/ios/parser/TiptapParserBridge.mm +179 -0
  203. package/ios/renderer/AttributedRenderer.h +23 -0
  204. package/ios/renderer/AttributedRenderer.m +229 -0
  205. package/ios/renderer/BaseRenderer.h +33 -0
  206. package/ios/renderer/BaseRenderer.m +46 -0
  207. package/ios/renderer/BaselineShiftTextAttributes.h +10 -0
  208. package/ios/renderer/BaselineShiftTextAttributes.m +26 -0
  209. package/ios/renderer/BlankLineRenderer.h +4 -0
  210. package/ios/renderer/BlankLineRenderer.m +51 -0
  211. package/ios/renderer/BlockquoteRenderer.h +6 -0
  212. package/ios/renderer/BlockquoteRenderer.m +258 -0
  213. package/ios/renderer/CodeBlockRenderer.h +9 -0
  214. package/ios/renderer/CodeBlockRenderer.m +99 -0
  215. package/ios/renderer/CodeRenderer.h +9 -0
  216. package/ios/renderer/CodeRenderer.m +69 -0
  217. package/ios/renderer/ENRMBlockquoteTextRenderer.h +25 -0
  218. package/ios/renderer/ENRMBlockquoteTextRenderer.m +48 -0
  219. package/ios/renderer/EmphasisRenderer.h +5 -0
  220. package/ios/renderer/EmphasisRenderer.m +100 -0
  221. package/ios/renderer/FactoidRenderer.h +9 -0
  222. package/ios/renderer/FactoidRenderer.m +130 -0
  223. package/ios/renderer/HeadingRenderer.h +6 -0
  224. package/ios/renderer/HeadingRenderer.m +103 -0
  225. package/ios/renderer/HighlightRenderer.h +7 -0
  226. package/ios/renderer/HighlightRenderer.m +33 -0
  227. package/ios/renderer/LinkRenderer.h +6 -0
  228. package/ios/renderer/LinkRenderer.m +158 -0
  229. package/ios/renderer/ListItemRenderer.h +24 -0
  230. package/ios/renderer/ListItemRenderer.m +283 -0
  231. package/ios/renderer/ListRenderer.h +13 -0
  232. package/ios/renderer/ListRenderer.m +126 -0
  233. package/ios/renderer/MentionRenderer.h +9 -0
  234. package/ios/renderer/MentionRenderer.m +96 -0
  235. package/ios/renderer/NodeRenderer.h +8 -0
  236. package/ios/renderer/ParagraphRenderer.h +6 -0
  237. package/ios/renderer/ParagraphRenderer.m +85 -0
  238. package/ios/renderer/RenderContext.h +145 -0
  239. package/ios/renderer/RenderContext.m +403 -0
  240. package/ios/renderer/RendererFactory.h +12 -0
  241. package/ios/renderer/RendererFactory.m +158 -0
  242. package/ios/renderer/StrikethroughRenderer.h +5 -0
  243. package/ios/renderer/StrikethroughRenderer.m +30 -0
  244. package/ios/renderer/StrongRenderer.h +5 -0
  245. package/ios/renderer/StrongRenderer.m +88 -0
  246. package/ios/renderer/TextRenderer.h +6 -0
  247. package/ios/renderer/TextRenderer.m +18 -0
  248. package/ios/renderer/ThematicBreakRenderer.h +4 -0
  249. package/ios/renderer/ThematicBreakRenderer.m +42 -0
  250. package/ios/renderer/UnderlineRenderer.h +4 -0
  251. package/ios/renderer/UnderlineRenderer.m +41 -0
  252. package/ios/styles/ENRMFontSlot.h +12 -0
  253. package/ios/styles/ENRMFontSlot.m +24 -0
  254. package/ios/styles/StyleConfig.h +488 -0
  255. package/ios/styles/StyleConfig.mm +2820 -0
  256. package/ios/utils/AccessibilityInfo.h +35 -0
  257. package/ios/utils/AccessibilityInfo.m +24 -0
  258. package/ios/utils/BlockquoteBorder.h +26 -0
  259. package/ios/utils/BlockquoteBorder.m +294 -0
  260. package/ios/utils/CodeBackground.h +19 -0
  261. package/ios/utils/CodeBackground.m +197 -0
  262. package/ios/utils/CodeBlockBackground.h +17 -0
  263. package/ios/utils/CodeBlockBackground.m +103 -0
  264. package/ios/utils/ContextMenuUtils.h +76 -0
  265. package/ios/utils/ContextMenuUtils.mm +75 -0
  266. package/ios/utils/ENRMAccessibilityLabels.h +40 -0
  267. package/ios/utils/ENRMAccessibilityLabels.m +5 -0
  268. package/ios/utils/ENRMAsyncRenderCoordinator.h +24 -0
  269. package/ios/utils/ENRMAsyncRenderCoordinator.m +37 -0
  270. package/ios/utils/ENRMAtomicSize.h +65 -0
  271. package/ios/utils/ENRMCodeBlockContent.h +37 -0
  272. package/ios/utils/ENRMCodeBlockContent.mm +89 -0
  273. package/ios/utils/ENRMFeatureFlags.h +25 -0
  274. package/ios/utils/ENRMImageDownloader.h +30 -0
  275. package/ios/utils/ENRMImageDownloader.m +168 -0
  276. package/ios/utils/ENRMLatexErrorCoordinator.h +27 -0
  277. package/ios/utils/ENRMLatexErrorCoordinator.mm +75 -0
  278. package/ios/utils/ENRMLatexErrorReporting.h +13 -0
  279. package/ios/utils/ENRMLinkContextMenus.h +93 -0
  280. package/ios/utils/ENRMLinkContextMenus.m +178 -0
  281. package/ios/utils/ENRMLinkRegexConfig.h +30 -0
  282. package/ios/utils/ENRMLinkRegexConfig.mm +104 -0
  283. package/ios/utils/ENRMLinkRegexProps.h +23 -0
  284. package/ios/utils/ENRMLocalImageLoader.h +35 -0
  285. package/ios/utils/ENRMLocalImageLoader.m +111 -0
  286. package/ios/utils/ENRMMenuAction.h +27 -0
  287. package/ios/utils/ENRMMenuAction.m +33 -0
  288. package/ios/utils/ENRMSpoilerOverlayManager.h +15 -0
  289. package/ios/utils/ENRMSpoilerOverlayManager.m +19 -0
  290. package/ios/utils/ENRMSpoilerTapUtils.h +6 -0
  291. package/ios/utils/ENRMSpoilerTapUtils.m +11 -0
  292. package/ios/utils/ENRMTailFadeInAnimator.h +16 -0
  293. package/ios/utils/ENRMTailFadeInAnimator.m +161 -0
  294. package/ios/utils/ENRMTextHitTest.h +23 -0
  295. package/ios/utils/ENRMTextHitTest.m +20 -0
  296. package/ios/utils/ENRMTextInteractionUtils.h +20 -0
  297. package/ios/utils/ENRMTextInteractionUtils.m +15 -0
  298. package/ios/utils/ENRMTextRenderer.h +38 -0
  299. package/ios/utils/ENRMTextRenderer.m +54 -0
  300. package/ios/utils/ENRMTextViewSetup.h +132 -0
  301. package/ios/utils/ENRMUIKit.h +429 -0
  302. package/ios/utils/EditMenuUtils.h +105 -0
  303. package/ios/utils/EditMenuUtils.m +143 -0
  304. package/ios/utils/FactoidBackground.h +20 -0
  305. package/ios/utils/FactoidBackground.m +161 -0
  306. package/ios/utils/FontScaleObserver.h +10 -0
  307. package/ios/utils/FontScaleObserver.m +55 -0
  308. package/ios/utils/FontUtils.h +31 -0
  309. package/ios/utils/FontUtils.m +63 -0
  310. package/ios/utils/HTMLGenerator.h +25 -0
  311. package/ios/utils/HTMLGenerator.m +1041 -0
  312. package/ios/utils/HeightUpdateUtils.h +25 -0
  313. package/ios/utils/ImageRequestHeaderUtils.h +35 -0
  314. package/ios/utils/LastElementUtils.h +97 -0
  315. package/ios/utils/LinkContextMenuUtils.h +55 -0
  316. package/ios/utils/LinkPillContentUtils.h +46 -0
  317. package/ios/utils/LinkTapUtils.h +56 -0
  318. package/ios/utils/LinkTapUtils.m +139 -0
  319. package/ios/utils/ListMarkerDrawer.h +15 -0
  320. package/ios/utils/ListMarkerDrawer.m +239 -0
  321. package/ios/utils/MentionBackground.h +26 -0
  322. package/ios/utils/MentionBackground.m +86 -0
  323. package/ios/utils/ParagraphStyleUtils.h +87 -0
  324. package/ios/utils/ParagraphStyleUtils.m +484 -0
  325. package/ios/utils/PasteboardUtils.h +48 -0
  326. package/ios/utils/PasteboardUtils.m +166 -0
  327. package/ios/utils/RTFExportUtils.h +24 -0
  328. package/ios/utils/RTFExportUtils.m +299 -0
  329. package/ios/utils/RuntimeKeys.h +44 -0
  330. package/ios/utils/RuntimeKeys.m +13 -0
  331. package/ios/utils/SelectionColorUtils.h +14 -0
  332. package/ios/utils/StylePropsUtils.h +1340 -0
  333. package/ios/utils/TaskListTapUtils.h +6 -0
  334. package/ios/utils/TaskListTapUtils.m +14 -0
  335. package/ios/utils/TextViewLayoutManager.h +14 -0
  336. package/ios/utils/TextViewLayoutManager.mm +198 -0
  337. package/ios/utils/TiptapAccessibilityElementBuilder.h +43 -0
  338. package/ios/utils/TiptapAccessibilityElementBuilder.m +432 -0
  339. package/ios/utils/TiptapExtractor.h +17 -0
  340. package/ios/utils/TiptapExtractor.m +367 -0
  341. package/ios/views/ENRMTiptapTextView.h +25 -0
  342. package/ios/views/ENRMTiptapTextView.m +247 -0
  343. package/package.json +70 -6
  344. package/react-native.config.js +10 -0
  345. package/src/EnrichedTiptapTextNativeComponent.ts +739 -0
  346. package/src/RichText.tsx +164 -0
  347. package/src/admonitionDefaults.ts +58 -0
  348. package/src/darkModeTextStyle.ts +99 -0
  349. package/src/headingDefaults.ts +21 -0
  350. package/src/index.tsx +4 -0
  351. package/src/linkVariantUtils.ts +120 -0
  352. package/src/normalizeTiptapStyle.ts +397 -0
  353. package/src/rn-globals.d.ts +1 -0
  354. package/src/styleUtils.ts +107 -0
  355. package/src/types/TiptapStyle.ts +532 -0
  356. package/src/types/TiptapStyleInternal.ts +299 -0
  357. package/src/types/linkPill.ts +9 -0
  358. package/src/utils/isDev.ts +4 -0
@@ -0,0 +1,164 @@
1
+ import { useMemo } from 'react';
2
+ import { type NativeSyntheticEvent, type StyleProp, type ViewStyle } from 'react-native';
3
+ import NativeRichText, {
4
+ type FactoidPressEvent,
5
+ type LinkPressEvent,
6
+ type MentionPressEvent,
7
+ type Md4cFlagsInternal,
8
+ type SelectionMenuConfig,
9
+ type AccessibilityLabelsProps,
10
+ } from './EnrichedTiptapTextNativeComponent';
11
+ import { normalizeTiptapStyle } from './normalizeTiptapStyle';
12
+ import type { TiptapStyle } from './types/TiptapStyle';
13
+
14
+ export type TiptapMark = {
15
+ type: string;
16
+ attrs?: Record<string, unknown>;
17
+ };
18
+
19
+ export type TiptapNode = {
20
+ type: string;
21
+ text?: string;
22
+ attrs?: Record<string, unknown>;
23
+ marks?: TiptapMark[];
24
+ content?: TiptapNode[];
25
+ };
26
+
27
+ const IGNORED_PARSER_FLAGS: Md4cFlagsInternal = {
28
+ underline: false,
29
+ superscript: false,
30
+ subscript: false,
31
+ latexMath: false,
32
+ highlight: false,
33
+ hardSoftBreaks: false,
34
+ preserveBlankLines: false,
35
+ admonitions: false,
36
+ };
37
+
38
+ const SELECTION_MENU: SelectionMenuConfig = {
39
+ copyAsTiptap: false,
40
+ copyImageUrl: false,
41
+ copyLabel: 'Copy',
42
+ copyAsTiptapLabel: 'Copy as Tiptap',
43
+ copyImageUrlLabel: 'Copy Image URL',
44
+ copyImageUrlsLabel: 'Copy {count} Image URLs',
45
+ copyImageUrlPluralTemplates: [],
46
+ };
47
+
48
+ const ACCESSIBILITY_LABELS: AccessibilityLabelsProps = {
49
+ list: {
50
+ bulletPoint: 'bullet',
51
+ nestedBulletPoint: 'nested bullet',
52
+ orderedItem: 'item {index}',
53
+ nestedOrderedItem: 'nested item {index}',
54
+ },
55
+ blockquote: {
56
+ quote: 'quote',
57
+ nestedQuote: 'nested quote',
58
+ },
59
+ table: { row: 'row' },
60
+ math: { equation: 'equation' },
61
+ codeBlock: { wrap: 'wrap', unwrap: 'unwrap' },
62
+ rotor: { headings: 'headings', links: 'links', images: 'images' },
63
+ };
64
+
65
+ export type MentionTarget = {
66
+ id: string;
67
+ label: string;
68
+ };
69
+
70
+ export type RichTextProps = {
71
+ /** Tiptap document, or the same document already encoded as JSON. */
72
+ document: TiptapNode | string;
73
+ /** Partial style for the nodes this library renders. Missing keys use defaults. */
74
+ textStyle?: TiptapStyle;
75
+ onLinkPress?: (url: string) => void;
76
+ /** Called with the factoid's `id`. A factoid that contains a link emits `onLinkPress` instead. */
77
+ onFactoidPress?: (factoidId: string) => void;
78
+ /** Called with the mention node's `id` and `label`. */
79
+ onMentionPress?: (mention: MentionTarget) => void;
80
+ /** Called with the mention node's `id` and `label`. */
81
+ onMentionLongPress?: (mention: MentionTarget) => void;
82
+ selectable?: boolean;
83
+ allowFontScaling?: boolean;
84
+ maxFontSizeMultiplier?: number;
85
+ numberOfLines?: number;
86
+ ellipsizeMode?: 'head' | 'middle' | 'tail' | 'clip';
87
+ style?: StyleProp<ViewStyle>;
88
+ };
89
+
90
+ export function RichText({
91
+ document,
92
+ textStyle,
93
+ onLinkPress,
94
+ selectable = true,
95
+ allowFontScaling = true,
96
+ onFactoidPress,
97
+ onMentionPress,
98
+ onMentionLongPress,
99
+ maxFontSizeMultiplier,
100
+ numberOfLines,
101
+ ellipsizeMode,
102
+ style,
103
+ }: RichTextProps) {
104
+ const documentJson = typeof document === 'string' ? document : JSON.stringify(document);
105
+ const tiptapStyle = useMemo(() => normalizeTiptapStyle(textStyle ?? {}), [textStyle]);
106
+ const handleLinkPress = useMemo(() => {
107
+ if (!onLinkPress) {
108
+ return undefined;
109
+ }
110
+ return (event: NativeSyntheticEvent<LinkPressEvent>) => {
111
+ onLinkPress(event.nativeEvent.url);
112
+ };
113
+ }, [onLinkPress]);
114
+ const handleFactoidPress = useMemo(() => {
115
+ if (!onFactoidPress) {
116
+ return undefined;
117
+ }
118
+ return (event: NativeSyntheticEvent<FactoidPressEvent>) => {
119
+ onFactoidPress(event.nativeEvent.factoidId);
120
+ };
121
+ }, [onFactoidPress]);
122
+ const handleMentionPress = useMemo(() => {
123
+ if (!onMentionPress) {
124
+ return undefined;
125
+ }
126
+ return (event: NativeSyntheticEvent<MentionPressEvent>) => {
127
+ onMentionPress({
128
+ id: event.nativeEvent.mentionId,
129
+ label: event.nativeEvent.label,
130
+ });
131
+ };
132
+ }, [onMentionPress]);
133
+ const handleMentionLongPress = useMemo(() => {
134
+ if (!onMentionLongPress) {
135
+ return undefined;
136
+ }
137
+ return (event: NativeSyntheticEvent<MentionPressEvent>) => {
138
+ onMentionLongPress({
139
+ id: event.nativeEvent.mentionId,
140
+ label: event.nativeEvent.label,
141
+ });
142
+ };
143
+ }, [onMentionLongPress]);
144
+
145
+ return (
146
+ <NativeRichText
147
+ document={documentJson}
148
+ tiptapStyle={tiptapStyle}
149
+ md4cFlags={IGNORED_PARSER_FLAGS}
150
+ selectionMenuConfig={SELECTION_MENU}
151
+ accessibilityLabels={ACCESSIBILITY_LABELS}
152
+ onLinkPress={handleLinkPress}
153
+ selectable={selectable}
154
+ allowFontScaling={allowFontScaling}
155
+ onFactoidPress={handleFactoidPress}
156
+ onMentionPress={handleMentionPress}
157
+ onMentionLongPress={handleMentionLongPress}
158
+ maxFontSizeMultiplier={maxFontSizeMultiplier}
159
+ numberOfLines={numberOfLines}
160
+ ellipsizeMode={ellipsizeMode}
161
+ style={style}
162
+ />
163
+ );
164
+ }
@@ -0,0 +1,58 @@
1
+ import { normalizeColor } from './styleUtils';
2
+ import type { AdmonitionsStyle } from './types/TiptapStyle';
3
+
4
+ // The five GitHub-flavored admonition/alert types, in the order md4c reports
5
+ // them (see MD_ADMONITION_TAGS). The `admonitionType` attribute emitted by the
6
+ // parser is always one of these lowercase strings.
7
+ export const ADMONITION_TYPES = [
8
+ 'note',
9
+ 'tip',
10
+ 'important',
11
+ 'warning',
12
+ 'caution',
13
+ ] as const;
14
+
15
+ export type AdmonitionType = (typeof ADMONITION_TYPES)[number];
16
+
17
+ // GitHub alert palette. Each `color` tints the left accent bar, the title label
18
+ // and the icon for that type. Backgrounds default to transparent (no fill) per
19
+ // the issue; users opt into a tint via tiptapStyle.blockquote.admonitions.
20
+ const ADMONITION_COLOR_DEFAULTS: Record<AdmonitionType, string> = {
21
+ note: '#0969DA',
22
+ tip: '#1A7F37',
23
+ important: '#8250DF',
24
+ warning: '#9A6700',
25
+ caution: '#CF222E',
26
+ };
27
+
28
+ export interface ResolvedAdmonitionColors {
29
+ color: string;
30
+ backgroundColor: string;
31
+ }
32
+
33
+ export type ResolvedAdmonitions = Record<
34
+ AdmonitionType,
35
+ ResolvedAdmonitionColors
36
+ >;
37
+
38
+ // Merge user overrides over the GitHub defaults and normalize every color, so
39
+ // native/web receive a complete, concrete per-type palette. Mirrors the
40
+ // linkVariants resolution: `color` falls back to the type default, and an empty
41
+ // or omitted `backgroundColor` resolves to transparent (drawn as no fill).
42
+ export function resolveAdmonitionColors(
43
+ user: AdmonitionsStyle | undefined
44
+ ): ResolvedAdmonitions {
45
+ const transparent = normalizeColor('transparent')! as string;
46
+ const result = {} as ResolvedAdmonitions;
47
+ for (const type of ADMONITION_TYPES) {
48
+ const override = user?.[type];
49
+ result[type] = {
50
+ color: ((override?.color ? normalizeColor(override.color) : undefined) ??
51
+ normalizeColor(ADMONITION_COLOR_DEFAULTS[type])!) as string,
52
+ backgroundColor: (override?.backgroundColor
53
+ ? (normalizeColor(override.backgroundColor) ?? transparent)
54
+ : transparent) as string,
55
+ };
56
+ }
57
+ return result;
58
+ }
@@ -0,0 +1,99 @@
1
+ import type { TiptapStyle } from './types/TiptapStyle';
2
+
3
+ const text = '#E6EDF3';
4
+ const textStrong = '#F0F6FC';
5
+ const textMuted = '#C9D1D9';
6
+ const textFaint = '#8B949E';
7
+ const border = '#30363D';
8
+ const surface = '#161B22';
9
+ const canvas = '#0D1117';
10
+
11
+ /**
12
+ * Optional dark palette for `RichText`'s `textStyle`.
13
+ * Colors only: font sizes, spacing, and other geometry stay on the built-in defaults.
14
+ * Bold and italic are omitted so they keep inheriting the surrounding text color.
15
+ */
16
+ export const darkModeTextStyle: TiptapStyle = {
17
+ paragraph: { color: text },
18
+ h1: { color: textStrong },
19
+ h2: { color: textStrong },
20
+ h3: { color: textStrong },
21
+ h4: { color: textStrong },
22
+ h5: { color: text },
23
+ h6: { color: textMuted },
24
+ blockquote: {
25
+ color: textMuted,
26
+ borderColor: border,
27
+ backgroundColor: surface,
28
+ admonitions: {
29
+ note: { color: '#58A6FF', backgroundColor: '#0D1C2E' },
30
+ tip: { color: '#3FB950', backgroundColor: '#0F2419' },
31
+ important: { color: '#AB7DF8', backgroundColor: '#1C1428' },
32
+ warning: { color: '#D29922', backgroundColor: '#2A2108' },
33
+ caution: { color: '#F85149', backgroundColor: '#2D1214' },
34
+ },
35
+ },
36
+ list: {
37
+ color: text,
38
+ bulletColor: textFaint,
39
+ markerColor: textFaint,
40
+ },
41
+ codeBlock: {
42
+ color: text,
43
+ backgroundColor: canvas,
44
+ borderColor: border,
45
+ syntaxColors: {
46
+ keyword: '#FF7B72',
47
+ operator: text,
48
+ punctuation: text,
49
+ string: '#A5D6FF',
50
+ number: '#79C0FF',
51
+ constant: '#79C0FF',
52
+ comment: textFaint,
53
+ function: '#D2A8FF',
54
+ type: '#FFA657',
55
+ variable: text,
56
+ property: '#79C0FF',
57
+ tag: '#7EE787',
58
+ attribute: '#79C0FF',
59
+ embedded: text,
60
+ },
61
+ },
62
+ link: { color: '#58A6FF', backgroundColor: 'transparent' },
63
+ strikethrough: { color: textFaint },
64
+ underline: { color: text },
65
+ code: {
66
+ color: '#FF7B72',
67
+ backgroundColor: '#3D1F24',
68
+ borderColor: '#6E3036',
69
+ },
70
+ mention: {
71
+ color: '#93C5FD',
72
+ backgroundColor: '#1E3A5F',
73
+ },
74
+ factoid: {
75
+ color: '#9BFC6E',
76
+ backgroundColor: '#132E0F',
77
+ borderColor: '#3FB950',
78
+ },
79
+ video: { backgroundColor: '#000000' },
80
+ thematicBreak: { color: border },
81
+ table: {
82
+ color: text,
83
+ headerBackgroundColor: surface,
84
+ headerTextColor: textStrong,
85
+ rowEvenBackgroundColor: canvas,
86
+ rowOddBackgroundColor: surface,
87
+ borderColor: border,
88
+ },
89
+ taskList: {
90
+ checkedColor: '#58A6FF',
91
+ borderColor: '#6E7681',
92
+ checkmarkColor: '#FFFFFF',
93
+ checkedTextColor: textFaint,
94
+ },
95
+ math: { color: text, backgroundColor: surface },
96
+ inlineMath: { color: text },
97
+ spoiler: { color: '#6E7681' },
98
+ highlight: { color: '#1C1917', backgroundColor: '#FACC15' },
99
+ };
@@ -0,0 +1,21 @@
1
+ // Single source of truth for default heading appearance, shared by the
2
+ // read-only renderer and the editable input so headings match across views.
3
+
4
+ export type HeadingLevelKey = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
5
+
6
+ export interface HeadingDefault {
7
+ fontSize: number;
8
+ color: string;
9
+ }
10
+
11
+ /** Default font weight applied to every heading level. */
12
+ export const DEFAULT_HEADING_FONT_WEIGHT = 'bold';
13
+
14
+ export const HEADING_DEFAULTS: Record<HeadingLevelKey, HeadingDefault> = {
15
+ h1: { fontSize: 30, color: '#111827' },
16
+ h2: { fontSize: 24, color: '#111827' },
17
+ h3: { fontSize: 20, color: '#111827' },
18
+ h4: { fontSize: 18, color: '#111827' },
19
+ h5: { fontSize: 16, color: '#374151' },
20
+ h6: { fontSize: 14, color: '#4B5563' },
21
+ };
package/src/index.tsx ADDED
@@ -0,0 +1,4 @@
1
+ export { RichText } from './RichText';
2
+ export { darkModeTextStyle } from './darkModeTextStyle';
3
+ export type { MentionTarget, RichTextProps, TiptapMark, TiptapNode } from './RichText';
4
+ export type { TiptapStyle } from './types/TiptapStyle';
@@ -0,0 +1,120 @@
1
+ import type { LinkPillContentInternal } from './EnrichedTiptapTextNativeComponent';
2
+ import type { LinkVariantStyle } from './types/TiptapStyle';
3
+ import type { LinkPillContent } from './types/linkPill';
4
+ import { normalizeColor } from './styleUtils';
5
+ import { isDev } from './utils/isDev';
6
+
7
+ type LinkPatternEntry<T> = [pattern: string, value: T];
8
+
9
+ // Lookbehind assertions (?<=...) and (?<!...) are not supported by
10
+ // NSRegularExpression on iOS. Warn early so the issue surfaces in JS tests
11
+ // before it silently misfires on device.
12
+ const UNSAFE_LOOKBEHIND_RE = /\(\?<[=!]/;
13
+
14
+ function warnAboutUnsafePattern(owner: string, pattern: string): void {
15
+ if (UNSAFE_LOOKBEHIND_RE.test(pattern)) {
16
+ console.warn(
17
+ `${owner} pattern "${pattern}" contains a lookbehind assertion (?<= or ?<!). ` +
18
+ 'Lookbehinds are not supported by NSRegularExpression on iOS and will never match. ' +
19
+ 'Use a lookahead or restructure the pattern to avoid them.'
20
+ );
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Orders URL patterns the way native tries them: longest first, so the most
26
+ * specific pattern wins. Patterns that are not valid regexes are dropped.
27
+ * `owner` names the prop in warnings.
28
+ */
29
+ export function normalizeLinkPatternEntries<T>(
30
+ entries: Record<string, T> | undefined,
31
+ owner: string
32
+ ): LinkPatternEntry<T>[] {
33
+ return Object.entries(entries ?? {})
34
+ .sort(([a], [b]) => b.length - a.length)
35
+ .filter(([pattern]) => {
36
+ try {
37
+ RegExp(pattern);
38
+ } catch {
39
+ if (isDev) {
40
+ console.warn(
41
+ `${owner} pattern "${pattern}" is not a valid regex and will be ignored.`
42
+ );
43
+ }
44
+ return false;
45
+ }
46
+
47
+ if (isDev) {
48
+ warnAboutUnsafePattern(owner, pattern);
49
+ }
50
+ return true;
51
+ });
52
+ }
53
+
54
+ export function normalizeLinkVariantEntries(
55
+ linkVariants?: Record<string, LinkVariantStyle>
56
+ ): LinkPatternEntry<LinkVariantStyle>[] {
57
+ return normalizeLinkPatternEntries(
58
+ linkVariants,
59
+ '[TiptapStyle] linkVariants'
60
+ );
61
+ }
62
+
63
+ /** Native pill geometry is finite and nonnegative before crossing codegen. */
64
+ export function normalizeLinkPillStyle(style: LinkVariantStyle) {
65
+ const hasConfig = typeof style.pill === 'object' && style.pill !== null;
66
+ const config =
67
+ typeof style.pill === 'object' && style.pill !== null ? style.pill : {};
68
+ const dimension = (value: number | undefined, fallback: number) =>
69
+ value === undefined || !Number.isFinite(value)
70
+ ? fallback
71
+ : Math.max(0, value);
72
+ return {
73
+ enabled: style.pill === true || hasConfig,
74
+ borderColor: config.borderColor ?? 'transparent',
75
+ label: config.label ?? '',
76
+ iconUri: config.iconUri ?? '',
77
+ iconTintColor: config.iconTintColor,
78
+ borderRadius: dimension(config.borderRadius, 8),
79
+ paddingHorizontal: dimension(config.paddingHorizontal, 6),
80
+ paddingVertical: dimension(config.paddingVertical, 2),
81
+ lineHeight: dimension(config.lineHeight, 0),
82
+ borderWidth: dimension(config.borderWidth, 0),
83
+ maxWidth: dimension(config.maxWidth, 0),
84
+ };
85
+ }
86
+
87
+ /** Flattens `linkPillContent` for native; sorted so equal maps produce the same array. */
88
+ export function normalizeLinkPillContent(
89
+ content: Record<string, LinkPillContent> | undefined
90
+ ): LinkPillContentInternal[] | undefined {
91
+ if (!content) return undefined;
92
+ return Object.entries(content)
93
+ .map(([url, { label, iconUri, iconTintColor }]) => ({
94
+ url,
95
+ label: label ?? '',
96
+ iconUri: iconUri ?? '',
97
+ iconTintColor: normalizeColor(iconTintColor),
98
+ }))
99
+ .sort((a, b) => (a.url < b.url ? -1 : a.url > b.url ? 1 : 0));
100
+ }
101
+
102
+ type NativeLinkPillContent = ReturnType<typeof normalizeLinkPillContent>;
103
+
104
+ /** Whether two flattened `linkPillContent` arrays hold the same entries. */
105
+ export function isLinkPillContentEqual(
106
+ a: NativeLinkPillContent,
107
+ b: NativeLinkPillContent
108
+ ): boolean {
109
+ if (a === b) return true;
110
+ if (!a || !b || a.length !== b.length) return false;
111
+ return a.every((entry, index) => {
112
+ const other = b[index]!;
113
+ return (
114
+ entry.url === other.url &&
115
+ entry.label === other.label &&
116
+ entry.iconUri === other.iconUri &&
117
+ entry.iconTintColor === other.iconTintColor
118
+ );
119
+ });
120
+ }