@apollohg/react-native-rich-text-editor 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (494) hide show
  1. package/LICENSE +160 -0
  2. package/README.md +259 -0
  3. package/RUST-STANDARD-LIBRARY-NOTICES.html +8266 -0
  4. package/ReactNativeProseEditor.podspec +59 -0
  5. package/THIRD_PARTY_NOTICES.md +31155 -0
  6. package/android/build.gradle +188 -0
  7. package/android/consumer-rules.pro +18 -0
  8. package/android/expo/build.gradle +17 -0
  9. package/android/src/debug/java/com/apollohg/editor/viewer/PreparedProseDrawInstrumentation.kt +7 -0
  10. package/android/src/main/assets/editor-icons/MaterialIcons.json +2236 -0
  11. package/android/src/main/assets/editor-icons/MaterialIcons.ttf +0 -0
  12. package/android/src/main/java/com/apollohg/editor/AndroidApiCompat.kt +19 -0
  13. package/android/src/main/java/com/apollohg/editor/AndroidCollaborationTransport.kt +860 -0
  14. package/android/src/main/java/com/apollohg/editor/CaretGeometry.kt +91 -0
  15. package/android/src/main/java/com/apollohg/editor/CodeHighlighting.kt +141 -0
  16. package/android/src/main/java/com/apollohg/editor/DecodedBitmapBudget.kt +250 -0
  17. package/android/src/main/java/com/apollohg/editor/EditorAddons.kt +133 -0
  18. package/android/src/main/java/com/apollohg/editor/EditorBlockSpacing.kt +51 -0
  19. package/android/src/main/java/com/apollohg/editor/EditorBoxDrawable.kt +16 -0
  20. package/android/src/main/java/com/apollohg/editor/EditorBoxDrawing.kt +234 -0
  21. package/android/src/main/java/com/apollohg/editor/EditorCheckboxSpan.kt +87 -0
  22. package/android/src/main/java/com/apollohg/editor/EditorCodeHighlighting.kt +120 -0
  23. package/android/src/main/java/com/apollohg/editor/EditorDecorationLayer.java +18 -0
  24. package/android/src/main/java/com/apollohg/editor/EditorDocumentLayout.kt +626 -0
  25. package/android/src/main/java/com/apollohg/editor/EditorEditText.kt +1042 -0
  26. package/android/src/main/java/com/apollohg/editor/EditorEditTextAnnotations.kt +191 -0
  27. package/android/src/main/java/com/apollohg/editor/EditorEditTextCaret.kt +100 -0
  28. package/android/src/main/java/com/apollohg/editor/EditorEditTextClipboard.kt +101 -0
  29. package/android/src/main/java/com/apollohg/editor/EditorEditTextComposition.kt +220 -0
  30. package/android/src/main/java/com/apollohg/editor/EditorEditTextConfiguration.kt +316 -0
  31. package/android/src/main/java/com/apollohg/editor/EditorEditTextCorrection.kt +303 -0
  32. package/android/src/main/java/com/apollohg/editor/EditorEditTextDeferredUpdates.kt +327 -0
  33. package/android/src/main/java/com/apollohg/editor/EditorEditTextDeletion.kt +258 -0
  34. package/android/src/main/java/com/apollohg/editor/EditorEditTextDiagnostics.kt +83 -0
  35. package/android/src/main/java/com/apollohg/editor/EditorEditTextDragDrop.kt +67 -0
  36. package/android/src/main/java/com/apollohg/editor/EditorEditTextExternalComposition.kt +357 -0
  37. package/android/src/main/java/com/apollohg/editor/EditorEditTextHardwareInput.kt +277 -0
  38. package/android/src/main/java/com/apollohg/editor/EditorEditTextImages.kt +280 -0
  39. package/android/src/main/java/com/apollohg/editor/EditorEditTextInputLifecycle.kt +183 -0
  40. package/android/src/main/java/com/apollohg/editor/EditorEditTextInputPreparation.kt +79 -0
  41. package/android/src/main/java/com/apollohg/editor/EditorEditTextInputTraits.kt +384 -0
  42. package/android/src/main/java/com/apollohg/editor/EditorEditTextLayout.kt +100 -0
  43. package/android/src/main/java/com/apollohg/editor/EditorEditTextNativeMutation.kt +243 -0
  44. package/android/src/main/java/com/apollohg/editor/EditorEditTextPlaceholder.kt +154 -0
  45. package/android/src/main/java/com/apollohg/editor/EditorEditTextRenderPatch.kt +347 -0
  46. package/android/src/main/java/com/apollohg/editor/EditorEditTextRendering.kt +313 -0
  47. package/android/src/main/java/com/apollohg/editor/EditorEditTextRustCommands.kt +281 -0
  48. package/android/src/main/java/com/apollohg/editor/EditorEditTextSelection.kt +352 -0
  49. package/android/src/main/java/com/apollohg/editor/EditorEditTextState.kt +113 -0
  50. package/android/src/main/java/com/apollohg/editor/EditorEditTextTaskMarkers.kt +92 -0
  51. package/android/src/main/java/com/apollohg/editor/EditorEditTextTextCommit.kt +327 -0
  52. package/android/src/main/java/com/apollohg/editor/EditorEditTextToolbar.kt +84 -0
  53. package/android/src/main/java/com/apollohg/editor/EditorEditTextUpdates.kt +245 -0
  54. package/android/src/main/java/com/apollohg/editor/EditorGlyphHeightCursorDrawable.kt +42 -0
  55. package/android/src/main/java/com/apollohg/editor/EditorHeightBehavior.kt +13 -0
  56. package/android/src/main/java/com/apollohg/editor/EditorInputConnection.kt +923 -0
  57. package/android/src/main/java/com/apollohg/editor/EditorInputCoordinates.kt +191 -0
  58. package/android/src/main/java/com/apollohg/editor/EditorInputCorrection.kt +107 -0
  59. package/android/src/main/java/com/apollohg/editor/EditorInputCursorGeometry.kt +128 -0
  60. package/android/src/main/java/com/apollohg/editor/EditorInputSnapshots.kt +134 -0
  61. package/android/src/main/java/com/apollohg/editor/EditorInputSurroundingDeletion.kt +321 -0
  62. package/android/src/main/java/com/apollohg/editor/EditorKeyboardToolbarView.kt +851 -0
  63. package/android/src/main/java/com/apollohg/editor/EditorMentionStyle.kt +192 -0
  64. package/android/src/main/java/com/apollohg/editor/EditorReconciliationWatcher.kt +46 -0
  65. package/android/src/main/java/com/apollohg/editor/EditorStyleSheet.kt +303 -0
  66. package/android/src/main/java/com/apollohg/editor/EditorStyleSheetSpans.kt +253 -0
  67. package/android/src/main/java/com/apollohg/editor/EditorSurfaceInputConnection.kt +67 -0
  68. package/android/src/main/java/com/apollohg/editor/EditorTextDecorationDrawing.kt +143 -0
  69. package/android/src/main/java/com/apollohg/editor/EditorTextSurface.kt +712 -0
  70. package/android/src/main/java/com/apollohg/editor/EditorTextSurfaceDragDrop.kt +94 -0
  71. package/android/src/main/java/com/apollohg/editor/EditorTextSurfaceInteraction.kt +708 -0
  72. package/android/src/main/java/com/apollohg/editor/EditorTheme.kt +650 -0
  73. package/android/src/main/java/com/apollohg/editor/EditorV2Adapter.kt +912 -0
  74. package/android/src/main/java/com/apollohg/editor/EditorV2AdapterMutations.kt +402 -0
  75. package/android/src/main/java/com/apollohg/editor/EditorV2AdapterRendering.kt +123 -0
  76. package/android/src/main/java/com/apollohg/editor/EditorV2AdapterSelection.kt +203 -0
  77. package/android/src/main/java/com/apollohg/editor/EditorV2Backend.kt +120 -0
  78. package/android/src/main/java/com/apollohg/editor/EditorV2Driver.kt +87 -0
  79. package/android/src/main/java/com/apollohg/editor/EditorV2Registry.kt +97 -0
  80. package/android/src/main/java/com/apollohg/editor/EditorV2RenderValidation.kt +409 -0
  81. package/android/src/main/java/com/apollohg/editor/ExpoAutoGrowStyleSizePublisher.kt +34 -0
  82. package/android/src/main/java/com/apollohg/editor/ImageResizeOverlayView.kt +266 -0
  83. package/android/src/main/java/com/apollohg/editor/ImeTextCoordinateMapper.kt +102 -0
  84. package/android/src/main/java/com/apollohg/editor/KeyboardToolbarImeAnimationController.kt +101 -0
  85. package/android/src/main/java/com/apollohg/editor/MentionSuggestionChipView.kt +234 -0
  86. package/android/src/main/java/com/apollohg/editor/NativeCollaborationTransportRegistry.kt +493 -0
  87. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoView.kt +813 -0
  88. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewAtoms.kt +68 -0
  89. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewBinding.kt +126 -0
  90. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewDiagnostics.kt +208 -0
  91. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewErrors.kt +146 -0
  92. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewEvents.kt +150 -0
  93. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewExternalComposition.kt +39 -0
  94. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewFocus.kt +176 -0
  95. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewLifecycle.kt +302 -0
  96. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewMentions.kt +259 -0
  97. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewNativeActions.kt +179 -0
  98. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewOutsideTap.kt +214 -0
  99. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewPendingUpdates.kt +376 -0
  100. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewProperties.kt +234 -0
  101. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewPropertyRetries.kt +197 -0
  102. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewToolbar.kt +285 -0
  103. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewTypes.kt +28 -0
  104. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewUpdates.kt +271 -0
  105. package/android/src/main/java/com/apollohg/editor/NativeEditorModule.kt +687 -0
  106. package/android/src/main/java/com/apollohg/editor/NativeEditorOutsideTapDispatcher.kt +380 -0
  107. package/android/src/main/java/com/apollohg/editor/NativeEditorV2Numbers.kt +45 -0
  108. package/android/src/main/java/com/apollohg/editor/NativeEditorViewRegistry.kt +372 -0
  109. package/android/src/main/java/com/apollohg/editor/NativeImagePipeline.kt +22 -0
  110. package/android/src/main/java/com/apollohg/editor/NativeToolbar.kt +193 -0
  111. package/android/src/main/java/com/apollohg/editor/NativeToolbarIcons.kt +177 -0
  112. package/android/src/main/java/com/apollohg/editor/NativeToolbarItem.kt +274 -0
  113. package/android/src/main/java/com/apollohg/editor/OkHttpCollaborationSocket.kt +102 -0
  114. package/android/src/main/java/com/apollohg/editor/OrderedListMarkerFormatter.kt +130 -0
  115. package/android/src/main/java/com/apollohg/editor/PointerTransparentView.java +18 -0
  116. package/android/src/main/java/com/apollohg/editor/PositionBridge.kt +128 -0
  117. package/android/src/main/java/com/apollohg/editor/ProseViewerView.kt +854 -0
  118. package/android/src/main/java/com/apollohg/editor/RemoteSelectionOverlayView.kt +314 -0
  119. package/android/src/main/java/com/apollohg/editor/RenderBlockSpans.kt +314 -0
  120. package/android/src/main/java/com/apollohg/editor/RenderBridge.kt +224 -0
  121. package/android/src/main/java/com/apollohg/editor/RenderBridgeBlockStyles.kt +407 -0
  122. package/android/src/main/java/com/apollohg/editor/RenderBridgeElements.kt +544 -0
  123. package/android/src/main/java/com/apollohg/editor/RenderBridgeInlineAndAtoms.kt +631 -0
  124. package/android/src/main/java/com/apollohg/editor/RenderBridgeParagraphs.kt +215 -0
  125. package/android/src/main/java/com/apollohg/editor/RenderImageDecoder.kt +748 -0
  126. package/android/src/main/java/com/apollohg/editor/RenderImageLoader.kt +900 -0
  127. package/android/src/main/java/com/apollohg/editor/RenderLayoutConstants.kt +117 -0
  128. package/android/src/main/java/com/apollohg/editor/RenderMediaSpans.kt +337 -0
  129. package/android/src/main/java/com/apollohg/editor/RenderParagraphSpans.kt +182 -0
  130. package/android/src/main/java/com/apollohg/editor/RichTextEditorView.kt +951 -0
  131. package/android/src/main/java/com/apollohg/editor/SharedNativeImagePipeline.kt +78 -0
  132. package/android/src/main/java/com/apollohg/editor/UniffiEditorV2Backend.kt +261 -0
  133. package/android/src/main/java/com/apollohg/editor/viewer/AndroidProseLayoutEngine.kt +1656 -0
  134. package/android/src/main/java/com/apollohg/editor/viewer/FabricAttachmentSidecars.kt +80 -0
  135. package/android/src/main/java/com/apollohg/editor/viewer/FabricLeaseHandleBridge.kt +59 -0
  136. package/android/src/main/java/com/apollohg/editor/viewer/FallbackSelectionGeometry.kt +450 -0
  137. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseDrawingView.kt +678 -0
  138. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseInstrumentation.kt +608 -0
  139. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseLayout.kt +186 -0
  140. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseLayoutCache.kt +393 -0
  141. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseLayoutRegistry.kt +828 -0
  142. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseTheme.kt +316 -0
  143. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseViewerManager.kt +900 -0
  144. package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseViewerPackage.kt +16 -0
  145. package/android/src/main/java/com/apollohg/editor/viewer/PreparedViewerAtoms.kt +89 -0
  146. package/android/src/main/java/com/apollohg/editor/viewer/ViewerCodeHighlighting.kt +91 -0
  147. package/android/src/main/java/com/apollohg/editor/viewer/ViewerDocument.kt +453 -0
  148. package/android/src/main/java/com/apollohg/editor/viewer/ViewerFontEnvironment.kt +282 -0
  149. package/android/src/main/java/com/apollohg/editor/viewer/ViewerImagePipeline.kt +460 -0
  150. package/android/src/main/jni/CMakeLists.txt +85 -0
  151. package/android/src/main/jni/PreparedProseViewerMeasurementsManager.cpp +334 -0
  152. package/android/src/main/jni/ReactNativeProseEditorSpec.h +17 -0
  153. package/android/src/main/jni/reactnativeproseeditor.h +6 -0
  154. package/android/src/main/res/values/attrs.xml +6 -0
  155. package/android/src/release/java/com/apollohg/editor/viewer/PreparedProseDrawInstrumentation.kt +9 -0
  156. package/app.plugin.js +62 -0
  157. package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseMeasurementsManager.h +62 -0
  158. package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseViewerComponentDescriptor.h +30 -0
  159. package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseViewerShadowNode.cpp +192 -0
  160. package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseViewerShadowNode.h +46 -0
  161. package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseViewerState.h +145 -0
  162. package/dist/AtomHost.d.ts +17 -0
  163. package/dist/AtomHost.js +135 -0
  164. package/dist/DefaultAtomChip.d.ts +2 -0
  165. package/dist/DefaultAtomChip.js +22 -0
  166. package/dist/EditorAddon.d.ts +32 -0
  167. package/dist/EditorAddon.js +29 -0
  168. package/dist/EditorAddonNormalization.d.ts +6 -0
  169. package/dist/EditorAddonNormalization.js +48 -0
  170. package/dist/EditorMentionThemeNormalization.d.ts +8 -0
  171. package/dist/EditorMentionThemeNormalization.js +22 -0
  172. package/dist/EditorMentionThemeValidation.d.ts +12 -0
  173. package/dist/EditorMentionThemeValidation.js +95 -0
  174. package/dist/EditorStyleSheet.d.ts +4 -0
  175. package/dist/EditorStyleSheet.js +10 -0
  176. package/dist/EditorStyleSheetNormalization.d.ts +3 -0
  177. package/dist/EditorStyleSheetNormalization.js +226 -0
  178. package/dist/EditorStyleSheetTypes.d.ts +151 -0
  179. package/dist/EditorStyleSheetTypes.js +2 -0
  180. package/dist/EditorTheme.d.ts +117 -0
  181. package/dist/EditorTheme.js +41 -0
  182. package/dist/EditorToolbar.d.ts +4 -0
  183. package/dist/EditorToolbar.js +17 -0
  184. package/dist/EditorToolbarComponent.d.ts +13 -0
  185. package/dist/EditorToolbarComponent.js +24 -0
  186. package/dist/EditorToolbarItems.d.ts +9 -0
  187. package/dist/EditorToolbarItems.js +58 -0
  188. package/dist/EditorToolbarRegistry.d.ts +59 -0
  189. package/dist/EditorToolbarRegistry.js +175 -0
  190. package/dist/EditorToolbarTypes.d.ts +273 -0
  191. package/dist/EditorToolbarTypes.js +2 -0
  192. package/dist/EditorToolbarVisuals.d.ts +154 -0
  193. package/dist/EditorToolbarVisuals.js +228 -0
  194. package/dist/EditorUpdateRevision.d.ts +8 -0
  195. package/dist/EditorUpdateRevision.js +22 -0
  196. package/dist/ExternalTextComposition.d.ts +45 -0
  197. package/dist/ExternalTextComposition.js +537 -0
  198. package/dist/ImageLoadingPolicy.d.ts +54 -0
  199. package/dist/ImageLoadingPolicy.js +60 -0
  200. package/dist/NativeEditorBoundaryError.d.ts +111 -0
  201. package/dist/NativeEditorBoundaryError.js +268 -0
  202. package/dist/NativeEditorBridge.d.ts +9 -0
  203. package/dist/NativeEditorBridge.js +37 -0
  204. package/dist/NativeEditorCollaborationTransport.d.ts +154 -0
  205. package/dist/NativeEditorCollaborationTransport.js +275 -0
  206. package/dist/NativeEditorCreateConfig.d.ts +16 -0
  207. package/dist/NativeEditorCreateConfig.js +249 -0
  208. package/dist/NativeEditorCreateJson.d.ts +76 -0
  209. package/dist/NativeEditorCreateJson.js +474 -0
  210. package/dist/NativeEditorCreateValidation.d.ts +32 -0
  211. package/dist/NativeEditorCreateValidation.js +150 -0
  212. package/dist/NativeEditorDocumentBridge.d.ts +72 -0
  213. package/dist/NativeEditorDocumentBridge.js +305 -0
  214. package/dist/NativeEditorDocumentHandle.d.ts +70 -0
  215. package/dist/NativeEditorDocumentHandle.js +89 -0
  216. package/dist/NativeEditorLocalAwareness.d.ts +34 -0
  217. package/dist/NativeEditorLocalAwareness.js +153 -0
  218. package/dist/NativeEditorNativeModule.d.ts +48 -0
  219. package/dist/NativeEditorNativeModule.js +34 -0
  220. package/dist/NativeEditorRenderNormalization.d.ts +22 -0
  221. package/dist/NativeEditorRenderNormalization.js +274 -0
  222. package/dist/NativeEditorResultNormalization.d.ts +108 -0
  223. package/dist/NativeEditorResultNormalization.js +400 -0
  224. package/dist/NativeEditorTypes.d.ts +318 -0
  225. package/dist/NativeEditorTypes.js +15 -0
  226. package/dist/NativeEditorV2Decimal.d.ts +5 -0
  227. package/dist/NativeEditorV2Decimal.js +18 -0
  228. package/dist/NativeProseViewer.d.ts +122 -0
  229. package/dist/NativeProseViewer.js +130 -0
  230. package/dist/NativeRichTextEditor.d.ts +3 -0
  231. package/dist/NativeRichTextEditor.js +6 -0
  232. package/dist/ResourceLimits.d.ts +100 -0
  233. package/dist/ResourceLimits.js +80 -0
  234. package/dist/RichTextEditor.d.ts +4 -0
  235. package/dist/RichTextEditor.js +25 -0
  236. package/dist/RichTextEditorNativeTypes.d.ts +122 -0
  237. package/dist/RichTextEditorNativeTypes.js +2 -0
  238. package/dist/RichTextEditorNativeView.d.ts +12 -0
  239. package/dist/RichTextEditorNativeView.js +15 -0
  240. package/dist/RichTextEditorSerialization.d.ts +53 -0
  241. package/dist/RichTextEditorSerialization.js +283 -0
  242. package/dist/RichTextEditorTypes.d.ts +281 -0
  243. package/dist/RichTextEditorTypes.js +2 -0
  244. package/dist/ViewerConfiguration.d.ts +22 -0
  245. package/dist/ViewerConfiguration.js +6 -0
  246. package/dist/YjsCollaboration.d.ts +146 -0
  247. package/dist/YjsCollaboration.js +496 -0
  248. package/dist/addons.d.ts +193 -0
  249. package/dist/addons.js +122 -0
  250. package/dist/atomConstants.d.ts +3 -0
  251. package/dist/atomConstants.js +6 -0
  252. package/dist/atomInstances.d.ts +35 -0
  253. package/dist/atomInstances.js +79 -0
  254. package/dist/atomPolicy.d.ts +4 -0
  255. package/dist/atomPolicy.js +47 -0
  256. package/dist/atomUpdates.d.ts +2 -0
  257. package/dist/atomUpdates.js +38 -0
  258. package/dist/atoms.d.ts +92 -0
  259. package/dist/atoms.js +222 -0
  260. package/dist/attributeValidation.d.ts +4 -0
  261. package/dist/attributeValidation.js +97 -0
  262. package/dist/contentExpression.d.ts +6 -0
  263. package/dist/contentExpression.js +335 -0
  264. package/dist/index.d.ts +21 -0
  265. package/dist/index.js +78 -0
  266. package/dist/listMarkers.d.ts +15 -0
  267. package/dist/listMarkers.js +21 -0
  268. package/dist/schemaDefinition.d.ts +143 -0
  269. package/dist/schemaDefinition.js +206 -0
  270. package/dist/schemaDocument.d.ts +17 -0
  271. package/dist/schemaDocument.js +69 -0
  272. package/dist/schemaDocumentConstruction.d.ts +5 -0
  273. package/dist/schemaDocumentConstruction.js +125 -0
  274. package/dist/schemaNormalization.d.ts +29 -0
  275. package/dist/schemaNormalization.js +313 -0
  276. package/dist/schemaPresets.d.ts +68 -0
  277. package/dist/schemaPresets.js +198 -0
  278. package/dist/schemaResolution.d.ts +9 -0
  279. package/dist/schemaResolution.js +211 -0
  280. package/dist/schemas.d.ts +5 -0
  281. package/dist/schemas.js +28 -0
  282. package/dist/specs/PreparedProseViewerNativeComponent.d.ts +37 -0
  283. package/dist/specs/PreparedProseViewerNativeComponent.js +6 -0
  284. package/dist/useEditorToolbarInteractions.d.ts +12 -0
  285. package/dist/useEditorToolbarInteractions.js +218 -0
  286. package/dist/useEditorToolbarItems.d.ts +8 -0
  287. package/dist/useEditorToolbarItems.js +280 -0
  288. package/dist/useEditorToolbarPresentation.d.ts +4 -0
  289. package/dist/useEditorToolbarPresentation.js +203 -0
  290. package/dist/useEditorToolbarState.d.ts +63 -0
  291. package/dist/useEditorToolbarState.js +108 -0
  292. package/dist/useFocusPreservingFrames.d.ts +17 -0
  293. package/dist/useFocusPreservingFrames.js +108 -0
  294. package/dist/useNativeEditor.d.ts +66 -0
  295. package/dist/useNativeEditor.js +370 -0
  296. package/dist/useRichTextEditorCommands.d.ts +21 -0
  297. package/dist/useRichTextEditorCommands.js +299 -0
  298. package/dist/useRichTextEditorEvents.d.ts +18 -0
  299. package/dist/useRichTextEditorEvents.js +216 -0
  300. package/dist/useRichTextEditorMentions.d.ts +11 -0
  301. package/dist/useRichTextEditorMentions.js +316 -0
  302. package/dist/useRichTextEditorPresentation.d.ts +5 -0
  303. package/dist/useRichTextEditorPresentation.js +178 -0
  304. package/dist/useRichTextEditorState.d.ts +180 -0
  305. package/dist/useRichTextEditorState.js +405 -0
  306. package/dist/useRichTextEditorUpdates.d.ts +10 -0
  307. package/dist/useRichTextEditorUpdates.js +308 -0
  308. package/dist/useViewerAtoms.d.ts +38 -0
  309. package/dist/useViewerAtoms.js +288 -0
  310. package/expo-module.config.json +13 -0
  311. package/ios/EditorAddons.swift +354 -0
  312. package/ios/EditorCodeHighlighting.swift +184 -0
  313. package/ios/EditorCore.xcframework/Info.plist +44 -0
  314. package/ios/EditorCore.xcframework/ios-arm64/libeditor_core.a +0 -0
  315. package/ios/EditorCore.xcframework/ios-arm64_x86_64-simulator/libeditor_core.a +0 -0
  316. package/ios/EditorInteractionOverlays.swift +697 -0
  317. package/ios/EditorLayoutManager.swift +971 -0
  318. package/ios/EditorNodeTypes.swift +37 -0
  319. package/ios/EditorStyleSheet.swift +461 -0
  320. package/ios/EditorTextView+AttributedPatch.swift +305 -0
  321. package/ios/EditorTextView+Binding.swift +61 -0
  322. package/ios/EditorTextView+Caret.swift +333 -0
  323. package/ios/EditorTextView+Commands.swift +203 -0
  324. package/ios/EditorTextView+Delegate.swift +65 -0
  325. package/ios/EditorTextView+Diagnostics.swift +225 -0
  326. package/ios/EditorTextView+DragDrop.swift +290 -0
  327. package/ios/EditorTextView+ExternalComposition.swift +364 -0
  328. package/ios/EditorTextView+Images.swift +354 -0
  329. package/ios/EditorTextView+InputTraits.swift +200 -0
  330. package/ios/EditorTextView+KeyboardInput.swift +318 -0
  331. package/ios/EditorTextView+Layout.swift +245 -0
  332. package/ios/EditorTextView+MarkedText.swift +267 -0
  333. package/ios/EditorTextView+NativeInputLifecycle.swift +372 -0
  334. package/ios/EditorTextView+NativeMutation.swift +471 -0
  335. package/ios/EditorTextView+Reconciliation.swift +97 -0
  336. package/ios/EditorTextView+RenderPatch.swift +573 -0
  337. package/ios/EditorTextView+Rendering.swift +539 -0
  338. package/ios/EditorTextView+Selection.swift +542 -0
  339. package/ios/EditorTextView.swift +953 -0
  340. package/ios/EditorTheme.swift +626 -0
  341. package/ios/EditorV2Adapter+Commands.swift +204 -0
  342. package/ios/EditorV2Adapter+Envelope.swift +238 -0
  343. package/ios/EditorV2Adapter+Mutation.swift +392 -0
  344. package/ios/EditorV2Adapter+Registry.swift +185 -0
  345. package/ios/EditorV2Adapter+RenderState.swift +360 -0
  346. package/ios/EditorV2Adapter+RenderValidation.swift +420 -0
  347. package/ios/EditorV2Adapter+Selection.swift +329 -0
  348. package/ios/EditorV2Adapter+TextCommands.swift +430 -0
  349. package/ios/EditorV2Adapter.swift +376 -0
  350. package/ios/EditorV2Shadow.swift +353 -0
  351. package/ios/Generated_editor_core.swift +2378 -0
  352. package/ios/NativeCodeHighlighting.swift +159 -0
  353. package/ios/NativeCollaborationSocket.swift +144 -0
  354. package/ios/NativeCollaborationTransport+Protocol.swift +258 -0
  355. package/ios/NativeCollaborationTransport+Socket.swift +379 -0
  356. package/ios/NativeCollaborationTransport+Validation.swift +103 -0
  357. package/ios/NativeCollaborationTransport.swift +322 -0
  358. package/ios/NativeCollaborationTransportRegistry.swift +521 -0
  359. package/ios/NativeEditorExpoView+AccessoryRetry.swift +219 -0
  360. package/ios/NativeEditorExpoView+Binding.swift +268 -0
  361. package/ios/NativeEditorExpoView+Diagnostics.swift +66 -0
  362. package/ios/NativeEditorExpoView+Events.swift +131 -0
  363. package/ios/NativeEditorExpoView+Focus.swift +169 -0
  364. package/ios/NativeEditorExpoView+MentionRetry.swift +288 -0
  365. package/ios/NativeEditorExpoView+Mentions.swift +288 -0
  366. package/ios/NativeEditorExpoView+Properties.swift +300 -0
  367. package/ios/NativeEditorExpoView+Toolbar.swift +86 -0
  368. package/ios/NativeEditorExpoView+Updates.swift +312 -0
  369. package/ios/NativeEditorExpoView.swift +349 -0
  370. package/ios/NativeEditorModule.swift +856 -0
  371. package/ios/NativeEditorViewRegistry.swift +226 -0
  372. package/ios/NativeToolbar+ButtonStyle.swift +214 -0
  373. package/ios/NativeToolbar+Buttons.swift +228 -0
  374. package/ios/NativeToolbar+Diagnostics.swift +114 -0
  375. package/ios/NativeToolbar+Menu.swift +101 -0
  376. package/ios/NativeToolbar+Models.swift +519 -0
  377. package/ios/NativeToolbar+Placeholder.swift +39 -0
  378. package/ios/NativeToolbar.swift +612 -0
  379. package/ios/OrderedListMarkerFormatter.swift +103 -0
  380. package/ios/PositionBridge.swift +596 -0
  381. package/ios/ProseViewerView.swift +462 -0
  382. package/ios/RenderBridge+Atoms.swift +288 -0
  383. package/ios/RenderBridge+Attachments.swift +246 -0
  384. package/ios/RenderBridge+BlockBoundaries.swift +313 -0
  385. package/ios/RenderBridge+Style.swift +343 -0
  386. package/ios/RenderBridge.swift +704 -0
  387. package/ios/RichTextEditorView.swift +930 -0
  388. package/ios/SharedNativeImagePipeline+Cache.swift +189 -0
  389. package/ios/SharedNativeImagePipeline+Transport.swift +328 -0
  390. package/ios/SharedNativeImagePipeline.swift +533 -0
  391. package/ios/Viewer/CoreTextProseLayoutEngine+AttributedText.swift +436 -0
  392. package/ios/Viewer/CoreTextProseLayoutEngine+Models.swift +322 -0
  393. package/ios/Viewer/CoreTextProseLayoutEngine.swift +635 -0
  394. package/ios/Viewer/Fabric/PREPPreparedProseViewerComponentView.h +4 -0
  395. package/ios/Viewer/Fabric/PREPPreparedProseViewerComponentView.mm +767 -0
  396. package/ios/Viewer/Fabric/PreparedProseMeasurementsManager.mm +118 -0
  397. package/ios/Viewer/NativeSVGImageDecoder.h +9 -0
  398. package/ios/Viewer/NativeSVGImageDecoder.mm +106 -0
  399. package/ios/Viewer/NativeSVGPreflight.h +11 -0
  400. package/ios/Viewer/NativeSVGPreflight.mm +219 -0
  401. package/ios/Viewer/PreparedProseDrawingView.swift +639 -0
  402. package/ios/Viewer/PreparedProseInstrumentation.swift +387 -0
  403. package/ios/Viewer/PreparedProseLayout.swift +326 -0
  404. package/ios/Viewer/PreparedProseLayoutCache.swift +766 -0
  405. package/ios/Viewer/PreparedProseLayoutRegistry+Artifacts.swift +377 -0
  406. package/ios/Viewer/PreparedProseLayoutRegistry+Fabric.swift +582 -0
  407. package/ios/Viewer/PreparedProseLayoutRegistry+FabricOwnership.swift +128 -0
  408. package/ios/Viewer/PreparedProseLayoutRegistry.swift +381 -0
  409. package/ios/Viewer/ViewerDocument.swift +575 -0
  410. package/ios/Viewer/ViewerFontEnvironment.swift +283 -0
  411. package/ios/Viewer/ViewerImagePipeline.swift +478 -0
  412. package/ios/editor_coreFFI/editor_coreFFI.h +1023 -0
  413. package/ios/editor_coreFFI/module.modulemap +7 -0
  414. package/package.json +151 -0
  415. package/react-native.config.js +17 -0
  416. package/rust/android/arm64-v8a/libeditor_core.so +0 -0
  417. package/rust/android/armeabi-v7a/libeditor_core.so +0 -0
  418. package/rust/android/x86/libeditor_core.so +0 -0
  419. package/rust/android/x86_64/libeditor_core.so +0 -0
  420. package/rust/bindings/kotlin/uniffi/editor_core/editor_core.kt +3146 -0
  421. package/src/AtomHost.tsx +180 -0
  422. package/src/DefaultAtomChip.tsx +27 -0
  423. package/src/EditorAddon.ts +65 -0
  424. package/src/EditorAddonNormalization.ts +49 -0
  425. package/src/EditorMentionThemeNormalization.ts +25 -0
  426. package/src/EditorMentionThemeValidation.ts +133 -0
  427. package/src/EditorStyleSheet.ts +9 -0
  428. package/src/EditorStyleSheetNormalization.ts +219 -0
  429. package/src/EditorStyleSheetTypes.ts +189 -0
  430. package/src/EditorTheme.ts +196 -0
  431. package/src/EditorToolbar.tsx +31 -0
  432. package/src/EditorToolbarComponent.tsx +23 -0
  433. package/src/EditorToolbarItems.tsx +64 -0
  434. package/src/EditorToolbarRegistry.tsx +254 -0
  435. package/src/EditorToolbarTypes.tsx +322 -0
  436. package/src/EditorToolbarVisuals.tsx +270 -0
  437. package/src/EditorUpdateRevision.ts +26 -0
  438. package/src/ExternalTextComposition.ts +658 -0
  439. package/src/ImageLoadingPolicy.ts +125 -0
  440. package/src/NativeEditorBoundaryError.ts +345 -0
  441. package/src/NativeEditorBridge.ts +93 -0
  442. package/src/NativeEditorCollaborationTransport.ts +493 -0
  443. package/src/NativeEditorCreateConfig.ts +326 -0
  444. package/src/NativeEditorCreateJson.ts +579 -0
  445. package/src/NativeEditorCreateValidation.ts +178 -0
  446. package/src/NativeEditorDocumentBridge.ts +485 -0
  447. package/src/NativeEditorDocumentHandle.ts +168 -0
  448. package/src/NativeEditorLocalAwareness.ts +168 -0
  449. package/src/NativeEditorNativeModule.ts +97 -0
  450. package/src/NativeEditorRenderNormalization.ts +320 -0
  451. package/src/NativeEditorResultNormalization.ts +469 -0
  452. package/src/NativeEditorTypes.ts +366 -0
  453. package/src/NativeEditorV2Decimal.ts +13 -0
  454. package/src/NativeProseViewer.tsx +356 -0
  455. package/src/NativeRichTextEditor.tsx +33 -0
  456. package/src/ResourceLimits.ts +187 -0
  457. package/src/RichTextEditor.tsx +27 -0
  458. package/src/RichTextEditorNativeTypes.tsx +144 -0
  459. package/src/RichTextEditorNativeView.tsx +21 -0
  460. package/src/RichTextEditorSerialization.tsx +381 -0
  461. package/src/RichTextEditorTypes.tsx +327 -0
  462. package/src/ViewerConfiguration.ts +23 -0
  463. package/src/YjsCollaboration.ts +692 -0
  464. package/src/addons.ts +311 -0
  465. package/src/atomConstants.ts +3 -0
  466. package/src/atomInstances.ts +123 -0
  467. package/src/atomPolicy.ts +47 -0
  468. package/src/atomUpdates.ts +52 -0
  469. package/src/atoms.ts +379 -0
  470. package/src/attributeValidation.ts +116 -0
  471. package/src/contentExpression.ts +338 -0
  472. package/src/index.ts +295 -0
  473. package/src/listMarkers.ts +18 -0
  474. package/src/schemaDefinition.ts +395 -0
  475. package/src/schemaDocument.ts +92 -0
  476. package/src/schemaDocumentConstruction.ts +148 -0
  477. package/src/schemaNormalization.ts +367 -0
  478. package/src/schemaPresets.ts +250 -0
  479. package/src/schemaResolution.ts +242 -0
  480. package/src/schemas.ts +43 -0
  481. package/src/specs/PreparedProseViewerNativeComponent.ts +40 -0
  482. package/src/useEditorToolbarInteractions.tsx +329 -0
  483. package/src/useEditorToolbarItems.tsx +390 -0
  484. package/src/useEditorToolbarPresentation.tsx +483 -0
  485. package/src/useEditorToolbarState.tsx +172 -0
  486. package/src/useFocusPreservingFrames.ts +171 -0
  487. package/src/useNativeEditor.ts +534 -0
  488. package/src/useRichTextEditorCommands.tsx +478 -0
  489. package/src/useRichTextEditorEvents.tsx +342 -0
  490. package/src/useRichTextEditorMentions.tsx +441 -0
  491. package/src/useRichTextEditorPresentation.tsx +563 -0
  492. package/src/useRichTextEditorState.tsx +620 -0
  493. package/src/useRichTextEditorUpdates.tsx +403 -0
  494. package/src/useViewerAtoms.tsx +427 -0
@@ -0,0 +1,704 @@
1
+ import CryptoKit
2
+ import ImageIO
3
+ import UIKit
4
+ enum RenderBridgeAttributes {
5
+ /// Marks a character as a void element placeholder (hardBreak, horizontalRule).
6
+ /// The value is the node type string (e.g. "hardBreak", "horizontalRule").
7
+ static let voidNodeType = NSAttributedString.Key("com.apollohg.editor.voidNodeType")
8
+
9
+ /// Stores the Rust document position (UInt32) for void elements.
10
+ static let docPos = NSAttributedString.Key("com.apollohg.editor.docPos")
11
+
12
+ /// Marks a character as a block boundary (for block start/end tracking).
13
+ static let blockBoundary = NSAttributedString.Key("com.apollohg.editor.blockBoundary")
14
+
15
+ /// Stores the block node type (e.g. "paragraph", "listItem").
16
+ static let blockNodeType = NSAttributedString.Key("com.apollohg.editor.blockNodeType")
17
+
18
+ /// Stores the block depth (UInt8).
19
+ static let blockDepth = NSAttributedString.Key("com.apollohg.editor.blockDepth")
20
+
21
+ /// Stores list context info as a dictionary for list items.
22
+ static let listContext = NSAttributedString.Key("com.apollohg.editor.listContext")
23
+
24
+ /// Marks blocks that should render a visible list marker.
25
+ static let listMarkerContext = NSAttributedString.Key("com.apollohg.editor.listMarkerContext")
26
+
27
+ static let orderedListMarkerLabel = NSAttributedString.Key("com.apollohg.editor.orderedListMarkerLabel")
28
+
29
+ /// Stores the rendered list marker color for the paragraph marker.
30
+ static let listMarkerColor = NSAttributedString.Key("com.apollohg.editor.listMarkerColor")
31
+
32
+ /// Stores the rendered list marker scale for unordered bullets.
33
+ static let listMarkerScale = NSAttributedString.Key("com.apollohg.editor.listMarkerScale")
34
+ static let listMarkerGap = NSAttributedString.Key("com.apollohg.editor.listMarkerGap")
35
+
36
+ /// Stores the paragraph base font used to render the list marker.
37
+ static let listMarkerBaseFont = NSAttributedString.Key("com.apollohg.editor.listMarkerBaseFont")
38
+
39
+ /// Stores the reserved list marker gutter width.
40
+ static let listMarkerWidth = NSAttributedString.Key("com.apollohg.editor.listMarkerWidth")
41
+
42
+ /// Stores the rendered blockquote border color.
43
+ static let blockquoteBorderColor = NSAttributedString.Key("com.apollohg.editor.blockquoteBorderColor")
44
+
45
+ /// Stores the rendered blockquote border width.
46
+ static let blockquoteBorderWidth = NSAttributedString.Key("com.apollohg.editor.blockquoteBorderWidth")
47
+
48
+ /// Stores the rendered blockquote gap between border and text.
49
+ static let blockquoteMarkerGap = NSAttributedString.Key("com.apollohg.editor.blockquoteMarkerGap")
50
+
51
+ /// Marks code-block paragraphs for custom background drawing.
52
+ static let codeBlockBackgroundColor = NSAttributedString.Key("com.apollohg.editor.codeBlockBackgroundColor")
53
+ static let codeBlockBorderRadius = NSAttributedString.Key("com.apollohg.editor.codeBlockBorderRadius")
54
+ static let codeBlockPaddingHorizontal = NSAttributedString.Key("com.apollohg.editor.codeBlockPaddingHorizontal")
55
+ static let codeBlockPaddingVertical = NSAttributedString.Key("com.apollohg.editor.codeBlockPaddingVertical")
56
+
57
+ /// Marks synthetic zero-width placeholders used only for UIKit layout.
58
+ static let syntheticPlaceholder = NSAttributedString.Key("com.apollohg.editor.syntheticPlaceholder")
59
+
60
+ /// Stores the link href for visually styled link text without enabling UITextView's default link interaction.
61
+ static let linkHref = NSAttributedString.Key("com.apollohg.editor.linkHref")
62
+
63
+ /// Stores the owning top-level document child index for partial native patching.
64
+ static let topLevelChildIndex = NSAttributedString.Key("com.apollohg.editor.topLevelChildIndex")
65
+ }
66
+
67
+ /// Layout constants for paragraph styles.
68
+ enum LayoutConstants {
69
+ /// Spacing between paragraphs (points).
70
+ static let paragraphSpacing: CGFloat = 8.0
71
+
72
+ /// Base indentation per depth level (points).
73
+ static let indentPerDepth: CGFloat = 24.0
74
+
75
+ /// Width reserved for the list bullet/number (points).
76
+ static let listMarkerWidth: CGFloat = 36.0
77
+
78
+ /// Gap between the list marker and the text that follows (points).
79
+ static let listMarkerTextGap: CGFloat = 8.0
80
+
81
+ /// Height of the horizontal rule separator line (points).
82
+ static let horizontalRuleHeight: CGFloat = 1.0
83
+
84
+ /// Vertical padding above and below the horizontal rule (points).
85
+ static let horizontalRuleVerticalPadding: CGFloat = 8.0
86
+
87
+ /// Total leading inset reserved for each blockquote depth.
88
+ static let blockquoteIndent: CGFloat = 18.0
89
+
90
+ /// Width of the rendered blockquote border bar.
91
+ static let blockquoteBorderWidth: CGFloat = 3.0
92
+
93
+ /// Gap between the blockquote border bar and the text that follows.
94
+ static let blockquoteMarkerGap: CGFloat = 8.0
95
+
96
+ /// Bullet character for unordered list items.
97
+ static let unorderedListBullet = "\u{2022} "
98
+
99
+ /// Scale factor applied only to unordered list marker glyphs.
100
+ static let unorderedListMarkerFontScale: CGFloat = 2.0
101
+
102
+ /// Object replacement character used for void block elements.
103
+ static let objectReplacementCharacter = "\u{FFFC}"
104
+ }
105
+
106
+ struct AtomRenderConfiguration: Equatable {
107
+ let registeredNodeTypes: Set<String>
108
+ let estimatedHeights: [String: CGFloat]
109
+ let measuredHeights: [String: CGFloat]
110
+
111
+ func reservedHeight(atomKey: String, nodeType: String) -> CGFloat? {
112
+ measuredHeights[atomKey] ?? estimatedHeights[nodeType]
113
+ }
114
+
115
+ static func from(json: String?) -> AtomRenderConfiguration? {
116
+ guard let json,
117
+ let data = json.data(using: .utf8),
118
+ let raw = try? JSONSerialization.jsonObject(with: data) as? [String: Any]
119
+ else { return nil }
120
+
121
+ let nodeTypes = Set((raw["nodeTypes"] as? [Any] ?? []).compactMap { $0 as? String })
122
+ let rawHeights = raw["estimatedHeights"] as? [String: Any] ?? [:]
123
+ var estimatedHeights: [String: CGFloat] = [:]
124
+ for (nodeType, value) in rawHeights {
125
+ guard let number = value as? NSNumber else { continue }
126
+ let height = CGFloat(truncating: number)
127
+ guard height.isFinite, height >= 0 else { continue }
128
+ estimatedHeights[nodeType] = height
129
+ }
130
+ return AtomRenderConfiguration(
131
+ registeredNodeTypes: nodeTypes,
132
+ estimatedHeights: estimatedHeights,
133
+ measuredHeights: [:]
134
+ )
135
+ }
136
+ }
137
+
138
+ // MARK: - RenderBridge
139
+
140
+ /// Converts RenderElement JSON (emitted by Rust editor-core via UniFFI) into
141
+ /// NSAttributedString for display in a UITextView.
142
+ ///
143
+ /// The JSON format matches the output of `serialize_render_elements` in lib.rs:
144
+ /// ```json
145
+ /// [
146
+ /// {"type": "blockStart", "nodeType": "paragraph", "depth": 0},
147
+ /// {"type": "textRun", "text": "Hello ", "marks": []},
148
+ /// {"type": "textRun", "text": "world", "marks": ["bold"]},
149
+ /// {"type": "blockEnd"},
150
+ /// {"type": "voidInline", "nodeType": "hardBreak", "docPos": 12},
151
+ /// {"type": "voidBlock", "nodeType": "horizontalRule", "docPos": 15}
152
+ /// ]
153
+ /// ```
154
+ final class RenderBridge {
155
+
156
+ // MARK: - Public API
157
+
158
+ /// Convert a JSON array of RenderElements into an NSAttributedString.
159
+ ///
160
+ /// - Parameters:
161
+ /// - json: A JSON string representing an array of render elements.
162
+ /// - baseFont: The default font for unstyled text.
163
+ /// - textColor: The default text color.
164
+ /// - Returns: The rendered attributed string. Returns an empty attributed
165
+ /// string if the JSON is invalid.
166
+ static func renderElements(
167
+ fromJSON json: String,
168
+ baseFont: UIFont,
169
+ textColor: UIColor,
170
+ theme: EditorTheme? = nil,
171
+ atomConfiguration: AtomRenderConfiguration? = nil
172
+ ) -> NSAttributedString {
173
+ guard let data = json.data(using: .utf8),
174
+ let parsed = try? JSONSerialization.jsonObject(with: data) as? [[String: Any]]
175
+ else {
176
+ return NSAttributedString()
177
+ }
178
+
179
+ return renderElements(
180
+ fromArray: parsed,
181
+ baseFont: baseFont,
182
+ textColor: textColor,
183
+ theme: theme,
184
+ atomConfiguration: atomConfiguration
185
+ )
186
+ }
187
+
188
+ /// Convert a parsed array of RenderElement dictionaries into an NSAttributedString.
189
+ ///
190
+ /// This is the main rendering entry point. It processes elements in order,
191
+ /// maintaining a block context stack for proper paragraph styling.
192
+ ///
193
+ /// - Parameters:
194
+ /// - elements: Parsed JSON array where each element is a dictionary.
195
+ /// - baseFont: The default font for unstyled text.
196
+ /// - textColor: The default text color.
197
+ /// - Returns: The rendered attributed string.
198
+ static func renderElements(
199
+ fromArray elements: [[String: Any]],
200
+ baseFont: UIFont,
201
+ textColor: UIColor,
202
+ theme: EditorTheme? = nil,
203
+ atomConfiguration: AtomRenderConfiguration? = nil
204
+ ) -> NSAttributedString {
205
+ let result = NSMutableAttributedString()
206
+ var blockStack: [BlockContext] = []
207
+ var isFirstBlock = true
208
+ var pendingTrailingParagraphSpacing: CGFloat?
209
+ var atomOccurrences: [String: Int] = [:]
210
+
211
+ for (elementIndex, element) in elements.enumerated() {
212
+ guard let type = element["type"] as? String else { continue }
213
+ let topLevelChildIndex = jsonInt(element["topLevelChildIndex"])
214
+
215
+ switch type {
216
+ case "textRun":
217
+ let text = element["text"] as? String ?? ""
218
+ let marks = element["marks"] as? [Any] ?? []
219
+ let isCodeBlock = blockStack.last?.nodeType == "codeBlock"
220
+ let blockFont = resolvedFont(
221
+ for: blockStack,
222
+ baseFont: baseFont,
223
+ theme: theme
224
+ )
225
+ let blockColor = resolvedTextColor(
226
+ for: blockStack,
227
+ textColor: textColor,
228
+ theme: theme
229
+ )
230
+ var baseAttrs = attributesForMarks(
231
+ marks,
232
+ baseFont: blockFont,
233
+ textColor: blockColor,
234
+ theme: theme
235
+ )
236
+ if let sheet = theme?.styleSheet {
237
+ var base = defaultAttributes(baseFont: blockFont, textColor: blockColor)
238
+ EditorStyleSheet.applyText(sheet.textValues(blockStack.last?.nodeType ?? "paragraph", ancestors: blockStack.dropLast().map(\.nodeType)), to: &base)
239
+ baseAttrs = sheet.inlineAttributes(marks, base: base)
240
+ }
241
+ if isCodeBlock {
242
+ // blockFont already carries theme.codeBlock.text. Keep an
243
+ // explicit code-block family for ordinary marked text;
244
+ // otherwise use the shared monospace resolver. In either
245
+ // case, the resolver accepts a face only if it satisfies
246
+ // the complete bold/italic request.
247
+ let resolvedFont = baseAttrs[.font] as? UIFont ?? blockFont
248
+ let markTraits = resolvedFont.fontDescriptor.symbolicTraits
249
+ .intersection([.traitBold, .traitItalic])
250
+ let themedFamily = theme?.codeBlock?.text?.fontFamily != nil
251
+ baseAttrs[.font] = ViewerFontEnvironment.shared.resolveFont(
252
+ family: themedFamily ? nil : "monospace",
253
+ size: resolvedFont.pointSize,
254
+ fallback: resolvedFont,
255
+ additionalTraits: markTraits,
256
+ semanticGeneration: "legacy-editor-theme"
257
+ )
258
+ }
259
+ let attrs = applyBlockStyle(
260
+ to: baseAttrs,
261
+ blockStack: blockStack,
262
+ theme: theme,
263
+ blockBaseFont: blockFont
264
+ )
265
+ let attributedText = NSAttributedString(string: text, attributes: attrs)
266
+ result.append(
267
+ attributedStringApplyingLeadingTopLevelChildIndexIfNeeded(
268
+ attributedText,
269
+ topLevelChildIndex: topLevelChildIndex,
270
+ resultIsEmpty: result.length == 0
271
+ )
272
+ )
273
+
274
+ case "voidInline":
275
+ let nodeType = element["nodeType"] as? String ?? ""
276
+ guard let docPos = jsonUInt32(element["docPos"]) else { continue }
277
+ let attrs = element["attrs"] as? [String: Any] ?? [:]
278
+ if EditorNodeTypes.isHardBreak(nodeType) {
279
+ overrideTrailingParagraphSpacing(in: result, paragraphSpacing: 0)
280
+ }
281
+ let attrStr = attributedStringForVoidInline(
282
+ nodeType: nodeType,
283
+ docPos: docPos,
284
+ attrs: attrs,
285
+ baseFont: baseFont,
286
+ textColor: textColor,
287
+ blockStack: blockStack,
288
+ topLevelChildIndex: topLevelChildIndex,
289
+ theme: theme
290
+ )
291
+ result.append(
292
+ attributedStringApplyingLeadingTopLevelChildIndexIfNeeded(
293
+ attrStr,
294
+ topLevelChildIndex: topLevelChildIndex,
295
+ resultIsEmpty: result.length == 0
296
+ )
297
+ )
298
+
299
+ case "voidBlock":
300
+ let nodeType = element["nodeType"] as? String ?? ""
301
+ guard let docPos = jsonUInt32(element["docPos"]) else { continue }
302
+ let attrs = element["attrs"] as? [String: Any] ?? [:]
303
+ let occurrence = atomOccurrences[nodeType, default: 0]
304
+ atomOccurrences[nodeType] = occurrence + 1
305
+ let atomKey = (element["atomId"] as? String) ?? "\(nodeType):\(occurrence)"
306
+
307
+ if !isFirstBlock {
308
+ collapseTrailingSpacingBeforeHorizontalRuleIfNeeded(
309
+ in: result,
310
+ pendingParagraphSpacing: &pendingTrailingParagraphSpacing,
311
+ nodeType: nodeType,
312
+ theme: theme
313
+ )
314
+ applyPendingTrailingParagraphSpacing(
315
+ in: result,
316
+ pendingParagraphSpacing: &pendingTrailingParagraphSpacing
317
+ )
318
+ result.append(
319
+ interBlockNewline(
320
+ baseFont: baseFont,
321
+ textColor: textColor,
322
+ blockStack: [],
323
+ theme: theme,
324
+ topLevelChildIndex: topLevelChildIndex
325
+ )
326
+ )
327
+ }
328
+ isFirstBlock = false
329
+
330
+ let attrStr = attributedStringForVoidBlock(
331
+ nodeType: nodeType,
332
+ docPos: docPos,
333
+ elementAttrs: attrs,
334
+ baseFont: baseFont,
335
+ textColor: textColor,
336
+ topLevelChildIndex: topLevelChildIndex,
337
+ theme: theme,
338
+ atomKey: atomKey,
339
+ atomConfiguration: atomConfiguration
340
+ )
341
+ if let sheet = theme?.styleSheet {
342
+ let styled = NSMutableAttributedString(attributedString: attrStr)
343
+ styled.addAttribute(editorStyledContentAttribute, value: true, range: NSRange(location: 0, length: styled.length))
344
+ let context = BlockContext(nodeType: nodeType, depth: blockStack.last?.depth ?? 0, listContext: nil)
345
+ let style = paragraphStyleForBlock(context, blockStack: blockStack + [context], theme: theme, baseFont: baseFont)
346
+ let inset = sheet.box(nodeType).inset
347
+ style.headIndent -= inset.left
348
+ style.firstLineHeadIndent -= inset.left
349
+ style.tailIndent += inset.right
350
+ style.paragraphSpacingBefore = sheet.box(nodeType).margin.top
351
+ style.paragraphSpacing = sheet.box(nodeType).margin.bottom
352
+ styled.addAttribute(.paragraphStyle, value: style, range: NSRange(location: 0, length: styled.length))
353
+ styled.addAttribute(editorBlockSpacingBoxAttribute, value: EditorRenderedBox(box: sheet.box(nodeType), depth: blockStack.count, leading: 0, trailing: 0), range: NSRange(location: 0, length: styled.length))
354
+ result.append(styled)
355
+ } else { result.append(attrStr) }
356
+ pendingTrailingParagraphSpacing = theme?.effectiveTextStyle(
357
+ for: nodeType
358
+ ).spacingAfter
359
+
360
+ case "opaqueInlineAtom":
361
+ let nodeType = element["nodeType"] as? String ?? ""
362
+ let label = element["label"] as? String ?? "?"
363
+ guard let docPos = jsonUInt32(element["docPos"]) else { continue }
364
+ let mentionTheme = (element["mentionTheme"] as? [String: Any]).map(
365
+ EditorMentionTheme.init(dictionary:)
366
+ )
367
+ let attrStr = attributedStringForOpaqueInlineAtom(
368
+ nodeType: nodeType,
369
+ label: label,
370
+ docPos: docPos,
371
+ baseFont: baseFont,
372
+ textColor: textColor,
373
+ blockStack: blockStack,
374
+ topLevelChildIndex: topLevelChildIndex,
375
+ theme: theme,
376
+ mentionTheme: mentionTheme
377
+ )
378
+ result.append(
379
+ attributedStringApplyingLeadingTopLevelChildIndexIfNeeded(
380
+ attrStr,
381
+ topLevelChildIndex: topLevelChildIndex,
382
+ resultIsEmpty: result.length == 0
383
+ )
384
+ )
385
+
386
+ case "opaqueBlockAtom":
387
+ let nodeType = element["nodeType"] as? String ?? ""
388
+ let label = element["label"] as? String ?? "?"
389
+ guard let docPos = jsonUInt32(element["docPos"]) else { continue }
390
+
391
+ if !isFirstBlock {
392
+ applyPendingTrailingParagraphSpacing(
393
+ in: result,
394
+ pendingParagraphSpacing: &pendingTrailingParagraphSpacing
395
+ )
396
+ result.append(
397
+ interBlockNewline(
398
+ baseFont: baseFont,
399
+ textColor: textColor,
400
+ blockStack: [],
401
+ theme: theme,
402
+ topLevelChildIndex: topLevelChildIndex
403
+ )
404
+ )
405
+ }
406
+ isFirstBlock = false
407
+
408
+ let attrStr = attributedStringForOpaqueBlockAtom(
409
+ nodeType: nodeType,
410
+ label: label,
411
+ docPos: docPos,
412
+ baseFont: baseFont,
413
+ textColor: textColor,
414
+ topLevelChildIndex: topLevelChildIndex,
415
+ theme: theme
416
+ )
417
+ result.append(attrStr)
418
+
419
+ case "blockStart":
420
+ let nodeType = element["nodeType"] as? String ?? ""
421
+ let depth = jsonUInt8(element["depth"])
422
+ let listContext = element["listContext"] as? [String: Any]
423
+ let isListItemContainer = isListItemNodeType(nodeType) && listContext != nil
424
+ let isTransparentLayoutContainer = isTransparentContainer(nodeType)
425
+ var ctx = BlockContext(
426
+ nodeType: nodeType,
427
+ depth: depth,
428
+ listContext: listContext,
429
+ topLevelChildIndex: topLevelChildIndex,
430
+ markerPending: isListItemContainer,
431
+ language: element["language"] as? String
432
+ )
433
+ let nestedListItemContainer =
434
+ isListItemContainer && (theme?.list?.itemSpacing != nil)
435
+ && blockStack.contains(where: {
436
+ isListItemNodeType($0.nodeType) && $0.listContext != nil
437
+ })
438
+
439
+ if !isListItemContainer && !isTransparentLayoutContainer {
440
+ if !isFirstBlock {
441
+ applyPendingTrailingParagraphSpacing(
442
+ in: result,
443
+ pendingParagraphSpacing: &pendingTrailingParagraphSpacing
444
+ )
445
+ let newlineBlockStack: [BlockContext]
446
+ if ctx.nodeType == "codeBlock" {
447
+ newlineBlockStack = []
448
+ } else if blockquoteDepth(in: blockStack + [ctx]) > 0,
449
+ !trailingRenderedContentHasBlockquote(in: result) {
450
+ newlineBlockStack = []
451
+ } else {
452
+ newlineBlockStack = blockStack + [ctx]
453
+ }
454
+ let collapsedSeparatorSpacing = collapsedParagraphSpacingAfterHorizontalRule(
455
+ in: result,
456
+ separatorBlockStack: newlineBlockStack,
457
+ theme: theme,
458
+ baseFont: baseFont
459
+ )
460
+ result.append(
461
+ interBlockNewline(
462
+ baseFont: baseFont,
463
+ textColor: textColor,
464
+ blockStack: newlineBlockStack,
465
+ theme: theme,
466
+ paragraphSpacingOverride: collapsedSeparatorSpacing,
467
+ topLevelChildIndex: topLevelChildIndex
468
+ )
469
+ )
470
+ }
471
+ isFirstBlock = false
472
+ } else if applyPendingTrailingParagraphSpacing(
473
+ in: result,
474
+ pendingParagraphSpacing: &pendingTrailingParagraphSpacing
475
+ ) {
476
+ // Applied list item spacing queued when the previous item ended.
477
+ } else if nestedListItemContainer {
478
+ overrideTrailingParagraphSpacing(
479
+ in: result,
480
+ paragraphSpacing: CGFloat(theme?.list?.itemSpacing ?? 0)
481
+ )
482
+ }
483
+
484
+ if theme?.styleSheet != nil, isListItemContainer,
485
+ (listContext?["isFirst"] as? Bool) == true || (listContext?["index"] as? NSNumber)?.intValue == 1 {
486
+ let listName = (listContext?["kind"] as? String) == "task" ? "taskList" : ((listContext?["ordered"] as? Bool) == true ? "orderedList" : "bulletList")
487
+ blockStack.append(BlockContext(nodeType: listName, depth: depth, listContext: nil, styleStart: result.length))
488
+ }
489
+ ctx.styleStart = result.length
490
+
491
+ blockStack.append(ctx)
492
+
493
+ var markerListContext: [String: Any]?
494
+ if !isListItemContainer {
495
+ if let directListContext = listContext {
496
+ markerListContext = directListContext
497
+ } else {
498
+ markerListContext = consumePendingListMarker(from: &blockStack)
499
+ }
500
+ }
501
+
502
+ if markerListContext != nil {
503
+ if var currentBlock = blockStack.popLast() {
504
+ currentBlock.listMarkerContext = markerListContext
505
+ if currentBlock.listContext != nil {
506
+ currentBlock.listContext = markerListContext
507
+ }
508
+ blockStack.append(currentBlock)
509
+ }
510
+ // On iOS we draw list markers outside the editable text stream so
511
+ // UIKit still sees paragraph-start for native capitalization.
512
+ }
513
+
514
+ case "blockEnd":
515
+ if let endedBlock = blockStack.popLast() {
516
+ appendTrailingLineBreakPlaceholderIfNeeded(
517
+ in: result,
518
+ endedBlock: endedBlock,
519
+ remainingBlockStack: blockStack,
520
+ baseFont: baseFont,
521
+ textColor: textColor,
522
+ theme: theme
523
+ )
524
+ let omitBottomMargin = endedBlock.nodeType == "paragraph"
525
+ && blockStack.last?.nodeType == "blockquote"
526
+ && elements.indices.contains(elementIndex + 1)
527
+ && elements[elementIndex + 1]["type"] as? String == "blockEnd"
528
+ closeStyledBlock(endedBlock, ancestors: blockStack, in: result, theme: theme, baseFont: baseFont, textColor: textColor, omitBottomMargin: omitBottomMargin)
529
+ if EditorStyleSheet.element(endedBlock.nodeType) == "codeBlock", endedBlock.styleStart < result.length {
530
+ result.addAttribute(editorCodeBlockAttribute, value: EditorCodeBlockPresentation(language: endedBlock.language), range: NSRange(location: endedBlock.styleStart, length: result.length - endedBlock.styleStart))
531
+ }
532
+ if theme?.styleSheet != nil, endedBlock.listContext?["isLast"] as? Bool == true,
533
+ let container = blockStack.last,
534
+ ["bulletList", "orderedList", "taskList"].contains(container.nodeType) {
535
+ blockStack.removeLast()
536
+ closeStyledBlock(container, ancestors: blockStack, in: result, theme: theme, baseFont: baseFont, textColor: textColor)
537
+ }
538
+ if endedBlock.listContext != nil, theme?.styleSheet == nil {
539
+ let spacing = (endedBlock.listContext?["isLast"] as? Bool) == true
540
+ ? (theme?.list?.spacingAfter ?? theme?.list?.itemSpacing)
541
+ : theme?.list?.itemSpacing
542
+ if let spacing {
543
+ pendingTrailingParagraphSpacing = (pendingTrailingParagraphSpacing ?? 0) + spacing
544
+ }
545
+ }
546
+ }
547
+
548
+ default:
549
+ break
550
+ }
551
+ }
552
+
553
+ if theme?.styleSheet != nil, result.length > 1 {
554
+ collapseStyledSiblingMargins(in: result)
555
+ }
556
+ return result
557
+ }
558
+
559
+ static func renderBlocks(
560
+ fromArray blocks: [[[String: Any]]],
561
+ startIndex: Int = 0,
562
+ includeLeadingInterBlockSeparator: Bool = false,
563
+ includeTrailingInterBlockSeparator: Bool = false,
564
+ baseFont: UIFont,
565
+ textColor: UIColor,
566
+ theme: EditorTheme? = nil,
567
+ atomConfiguration: AtomRenderConfiguration? = nil
568
+ ) -> NSAttributedString {
569
+ var flattened: [[String: Any]] = []
570
+ flattened.reserveCapacity(blocks.reduce(0) { $0 + $1.count })
571
+
572
+ for (offset, block) in blocks.enumerated() {
573
+ let topLevelChildIndex = startIndex + offset
574
+ for element in block {
575
+ var tagged = element
576
+ tagged["topLevelChildIndex"] = topLevelChildIndex
577
+ flattened.append(tagged)
578
+ }
579
+ }
580
+
581
+ let renderedBlocks = renderElements(
582
+ fromArray: flattened,
583
+ baseFont: baseFont,
584
+ textColor: textColor,
585
+ theme: theme,
586
+ atomConfiguration: atomConfiguration
587
+ )
588
+ let needsLeadingInterBlockSeparator = includeLeadingInterBlockSeparator && startIndex > 0
589
+ guard !blocks.isEmpty,
590
+ needsLeadingInterBlockSeparator || includeTrailingInterBlockSeparator
591
+ else {
592
+ return renderedBlocks
593
+ }
594
+
595
+ let result = NSMutableAttributedString()
596
+ if needsLeadingInterBlockSeparator {
597
+ result.append(
598
+ interBlockNewline(
599
+ baseFont: baseFont,
600
+ textColor: textColor,
601
+ blockStack: [],
602
+ theme: theme,
603
+ topLevelChildIndex: startIndex
604
+ )
605
+ )
606
+ result.append(
607
+ removingLeadingTopLevelChildIndex(
608
+ from: renderedBlocks,
609
+ topLevelChildIndex: startIndex
610
+ )
611
+ )
612
+ } else {
613
+ result.append(renderedBlocks)
614
+ }
615
+ if includeTrailingInterBlockSeparator {
616
+ result.append(
617
+ interBlockNewline(
618
+ baseFont: baseFont,
619
+ textColor: textColor,
620
+ blockStack: [],
621
+ theme: theme,
622
+ topLevelChildIndex: startIndex + blocks.count
623
+ )
624
+ )
625
+ }
626
+ return result
627
+ }
628
+
629
+ // MARK: - Height Pre-Measurement
630
+
631
+ static func measureHeight(
632
+ forRenderJSON renderJSON: String,
633
+ themeJSON: String?,
634
+ width: CGFloat
635
+ ) -> CGFloat {
636
+ if !Thread.isMainThread {
637
+ return DispatchQueue.main.sync {
638
+ measureHeight(
639
+ forRenderJSON: renderJSON,
640
+ themeJSON: themeJSON,
641
+ width: width
642
+ )
643
+ }
644
+ }
645
+ guard width > 0 else { return 0 }
646
+
647
+ let theme = EditorTheme.from(json: themeJSON)
648
+ let baseFontSize = theme?.text?.fontSize ?? theme?.paragraph?.fontSize ?? 16
649
+ let baseFont = UIFont.systemFont(ofSize: baseFontSize)
650
+ let textColor = theme?.text?.color ?? UIColor.label
651
+
652
+ let attributedString = NativeImagePipeline.withoutLoading {
653
+ renderElements(
654
+ fromJSON: renderJSON,
655
+ baseFont: baseFont,
656
+ textColor: textColor,
657
+ theme: theme
658
+ )
659
+ }
660
+
661
+ guard attributedString.length > 0 else { return 0 }
662
+
663
+ let contentInsets = theme?.contentInsets
664
+ let topInset = contentInsets?.top ?? 0
665
+ let bottomInset = contentInsets?.bottom ?? 0
666
+ let leftInset = contentInsets?.left ?? 0
667
+ let rightInset = contentInsets?.right ?? 0
668
+
669
+ // When contentInsets are set, lineFragmentPadding is 0 (matches
670
+ // RichTextEditorView.theme didSet). Otherwise use the UITextView
671
+ // default of 5.
672
+ let lineFragmentPadding: CGFloat = contentInsets != nil ? 0 : 5
673
+
674
+ let textStorage = NSTextStorage(attributedString: attributedString)
675
+ let layoutManager = EditorLayoutManager()
676
+ let containerWidth = width - leftInset - rightInset - lineFragmentPadding * 2
677
+ let textContainer = NSTextContainer(
678
+ size: CGSize(width: max(containerWidth, 0), height: .greatestFiniteMagnitude)
679
+ )
680
+ textContainer.lineFragmentPadding = 0
681
+
682
+ layoutManager.addTextContainer(textContainer)
683
+ textStorage.addLayoutManager(layoutManager)
684
+
685
+ layoutManager.ensureLayout(for: textContainer)
686
+
687
+ var usedRect = layoutManager.usedRect(for: textContainer)
688
+ let extraLineFragmentRect = layoutManager.extraLineFragmentRect
689
+ if !extraLineFragmentRect.isEmpty {
690
+ usedRect = usedRect.union(extraLineFragmentRect)
691
+ }
692
+
693
+ let height = ceil(usedRect.height + topInset + bottomInset)
694
+ return height
695
+ }
696
+
697
+ // MARK: - Private Helpers
698
+
699
+ }
700
+
701
+ // MARK: - BlockContext
702
+
703
+ /// Transient context while rendering block elements. Pushed onto a stack
704
+ /// when a `blockStart` element is encountered and popped on `blockEnd`.