@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,639 @@
1
+ import CoreText
2
+ import UIKit
3
+
4
+ /// Mapping/reference overhead only. Decoded image allocations are owned and
5
+ /// accounted for by the shared native image cache.
6
+ internal enum PreparedProseImagePixelMapAccounting {
7
+ static let mapRetainedBytes = 48
8
+ static let entryRetainedBytes = 48
9
+
10
+ static func retainedBytes(entryCount: Int) -> Int {
11
+ guard entryCount > 0 else { return 0 }
12
+ return saturatingAdd(
13
+ mapRetainedBytes,
14
+ saturatingMultiply(entryCount, entryRetainedBytes)
15
+ )
16
+ }
17
+
18
+ private static func saturatingAdd(_ left: Int, _ right: Int) -> Int {
19
+ guard left <= Int.max - right else { return Int.max }
20
+ return left + right
21
+ }
22
+
23
+ private static func saturatingMultiply(_ left: Int, _ right: Int) -> Int {
24
+ guard left > 0, right > 0 else { return 0 }
25
+ guard left <= Int.max / right else { return Int.max }
26
+ return left * right
27
+ }
28
+ }
29
+
30
+ @objc public protocol PreparedProseDrawingViewInteractionDelegate: AnyObject {
31
+ func preparedProseDrawingView(_ view: PreparedProseDrawingView, didActivateLink href: String, text: String) -> Bool
32
+ func preparedProseDrawingView(_ view: PreparedProseDrawingView, didActivateMention docPos: UInt32, label: String, attrsJSON: String) -> Bool
33
+ }
34
+
35
+ /// A rendering-only view: it consumes already prepared Core Text lines.
36
+ @objc(PREPPreparedProseDrawingView)
37
+ public final class PreparedProseDrawingView: UIView {
38
+ let codeHighlightingSession = NativeCodeHighlightingSession()
39
+ var onCodeHighlightingResolved: ((String) -> Void)?
40
+ var onCodeHighlightingFailure: ((Error) -> Void)?
41
+ @objc public static let codeHighlightingDidResolve = Notification.Name("com.apollohg.editor.viewer.codeHighlightingDidResolve")
42
+ @objc public static let codeHighlightingDidFail = Notification.Name("com.apollohg.editor.viewer.codeHighlightingDidFail")
43
+
44
+ deinit { codeHighlightingSession.cancel() }
45
+
46
+ var imagePixels: [String: UIImage] = [:] {
47
+ didSet {
48
+ PreparedProseInstrumentation.retained(.image, scope: "drawing-\(ObjectIdentifier(self))", bytes: retainedImagePixelsBytesForTesting)
49
+ setNeedsDisplay()
50
+ }
51
+ }
52
+ /// This map owns only mapping/reference overhead. The shared native image
53
+ /// cache is the sole owner charged for a decoded CGImage allocation.
54
+ internal var retainedImagePixelsBytesForTesting: Int {
55
+ PreparedProseImagePixelMapAccounting.retainedBytes(entryCount: imagePixels.count)
56
+ }
57
+ internal var preparedSurfaceRetainedBytesForTesting: Int {
58
+ Self.saturatingAdd(
59
+ Self.saturatingAdd(layout?.retainedBytes ?? 0, imageRevisions.retainedPublicationBytesForTesting),
60
+ retainedImagePixelsBytesForTesting
61
+ )
62
+ }
63
+ @objc public static let imageMetadataDidResolve = Notification.Name("com.apollohg.editor.viewer.imageMetadataDidResolve")
64
+ @objc public static let imageResourceDidFail = Notification.Name("com.apollohg.editor.viewer.imageResourceDidFail")
65
+ private lazy var imagePipeline = ViewerImagePipeline(policy: .default)
66
+ private var imageRevisions = ViewerAttachmentRevisionState()
67
+ private var imageGeneration = ""
68
+ private var imageConfiguration: (enabled: Bool, policy: ImageLoadingPolicy) = (false, .default)
69
+ private var scrollObservations: [NSKeyValueObservation] = []
70
+ private var observedScrollViewIDs: [ObjectIdentifier] = []
71
+ var layout: PreparedProseLayout? {
72
+ didSet {
73
+ guard oldValue !== layout else { return }
74
+ PreparedProseInstrumentation.retained(.sidecars, scope: "drawing-\(ObjectIdentifier(self))", bytes: imageRevisions.retainedPublicationBytesForTesting)
75
+ invalidateAccessibilityNodes()
76
+ setNeedsDisplay()
77
+ }
78
+ }
79
+
80
+ @objc public func install(layout: PreparedProseLayout?) {
81
+ guard self.layout !== layout else { return }
82
+ self.layout = layout
83
+ scheduleCodeHighlighting()
84
+ }
85
+
86
+ @objc(configureImagesWithGeneration:imagesEnabled:policyJSON:)
87
+ public func configureImages(generation: String, imagesEnabled: Bool, policyJSON: String?) {
88
+ imageGeneration = generation
89
+ imageConfiguration = (imagesEnabled, ImageLoadingPolicy.from(json: policyJSON))
90
+ imagePipeline.onPixels = { [weak self] attachment, image in self?.imagePixels[attachment.id] = image }
91
+ imagePipeline.onIntrinsicMetadata = { [weak self] attachment, size in
92
+ guard let self,
93
+ self.imagePipeline.acceptsCompletion(generation: generation),
94
+ self.imageRevisions.recordIntrinsicSize(size, for: attachment.id, ordinal: attachment.ordinal, declaredSize: attachment.declaredSize)
95
+ else { return }
96
+ NotificationCenter.default.post(
97
+ name: Self.imageMetadataDidResolve,
98
+ object: self,
99
+ userInfo: ["generation": generation, "revision": self.imageRevisions.revision]
100
+ )
101
+ }
102
+ imagePipeline.onResourceFailure = { [weak self] attachment in
103
+ guard let self,
104
+ self.imagePipeline.acceptsCompletion(generation: generation),
105
+ self.imageRevisions.recordResourceFailure(for: attachment.ordinal)
106
+ else { return }
107
+ NotificationCenter.default.post(
108
+ name: Self.imageResourceDidFail,
109
+ object: self,
110
+ userInfo: ["generation": generation, "attachment": attachment.id]
111
+ )
112
+ }
113
+ imagePipeline.begin(
114
+ generation: imageGeneration,
115
+ imagesEnabled: imageConfiguration.enabled,
116
+ policy: imageConfiguration.policy
117
+ )
118
+ imageRevisions.admit(attachmentCount: layout?.imageAttachments.count ?? 0)
119
+ }
120
+
121
+ /// Phase one of Fabric setup: semantic props/state have been accepted but
122
+ /// no mounted artifact exists yet. This clears active intrinsic fallback
123
+ /// before measurement/preparation and phase two only binds ordinals.
124
+ @objc(beginSemanticImageGeneration:)
125
+ public func beginSemanticImageGeneration(_ generation: String) {
126
+ guard imageRevisions.beginSemanticGeneration(generation) else { return }
127
+ imageGeneration = ""
128
+ imagePipeline.cancel()
129
+ imagePixels = [:]
130
+ }
131
+
132
+ /// Fabric has already reset this sidecar during Yoga preparation. Mount
133
+ /// only transfers the stable surface owner; it must not reopen metadata or
134
+ /// error publication by resetting a second time.
135
+ @objc(bindFabricAttachmentStateSurfaceId:componentTag:leaseHandle:)
136
+ public func bindFabricAttachmentState(surfaceId: Int64, componentTag: Int64, leaseHandle: UInt64) {
137
+ guard let state = FabricAttachmentSidecars.state(
138
+ for: .init(surfaceId: surfaceId, componentTag: componentTag),
139
+ leaseHandle: leaseHandle
140
+ ) else { return }
141
+ imageRevisions = state
142
+ }
143
+
144
+ @objc public func updateConfiguredImagesForVisibleWindow() {
145
+ refreshScrollObservations()
146
+ guard let layout, let visible = configuredVisibleRect() else {
147
+ imagePipeline.leaveViewport()
148
+ if !imagePixels.isEmpty { imagePixels = [:] }
149
+ onVisibleRectChange?(nil)
150
+ return
151
+ }
152
+ let retainedIDs = imagePipeline.updateVisibleRect(visible, attachments: layout.imageAttachments)
153
+ onVisibleRectChange?(visible)
154
+ guard imagePixels.keys.contains(where: { !retainedIDs.contains($0) }) else { return }
155
+ imagePixels = imagePixels.filter { retainedIDs.contains($0.key) }
156
+ }
157
+
158
+ @objc public func cancelConfiguredImages() {
159
+ imageGeneration = ""
160
+ imagePipeline.cancel()
161
+ imagePixels = [:]
162
+ }
163
+
164
+ /// A semantic prop replacement starts a new source-qualified publication
165
+ /// generation. Attachment-revision replacements deliberately do not call
166
+ /// this: they are the one reflow being deduplicated.
167
+ @objc public func resetIntrinsicImagePublication() {
168
+ imageRevisions.reset()
169
+ }
170
+
171
+ @objc public var errorDomain: String? { layout?.error?.domain }
172
+ @objc public var errorCode: String? { layout?.error?.code }
173
+ @objc public var errorMessage: String? { layout?.error?.message }
174
+
175
+ @objc public func atomLayoutsJSON(origin: CGPoint) -> String {
176
+ let atoms: [[String: Any]] = layout?.blocks.compactMap { block in
177
+ guard let atom = block.atomSlot else { return nil }
178
+ return [
179
+ "nodeType": atom.nodeType,
180
+ "docPos": atom.docPos,
181
+ "attrsJson": atom.attrsJSON,
182
+ "x": atom.bounds.minX + origin.x,
183
+ "y": atom.bounds.minY + origin.y,
184
+ "width": atom.bounds.width,
185
+ "height": atom.bounds.height
186
+ ]
187
+ } ?? []
188
+ guard let data = try? JSONSerialization.data(withJSONObject: atoms) else { return "[]" }
189
+ return String(data: data, encoding: .utf8) ?? "[]"
190
+ }
191
+
192
+ /// The owner chooses its delivery channel (UIKit delegate or Fabric event).
193
+ var onActivateInteraction: ((PreparedProseInteraction) -> Bool)?
194
+ var onVisibleRectChange: ((CGRect?) -> Void)?
195
+ @objc public weak var interactionDelegate: PreparedProseDrawingViewInteractionDelegate?
196
+ @objc public var linkInteractionsEnabled = true {
197
+ didSet {
198
+ guard oldValue != linkInteractionsEnabled else { return }
199
+ invalidateAccessibilityNodes()
200
+ }
201
+ }
202
+ private var accessibilityElementsByIndex: [Int: PreparedProseDrawingAccessibilityElement] = [:]
203
+ internal var materializedAccessibilityElementCountForTesting: Int { accessibilityElementsByIndex.count }
204
+
205
+ private lazy var tapRecognizer: UITapGestureRecognizer = {
206
+ let recognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
207
+ recognizer.cancelsTouchesInView = false
208
+ return recognizer
209
+ }()
210
+
211
+ public override init(frame: CGRect) {
212
+ super.init(frame: frame)
213
+ isAccessibilityElement = false
214
+ addGestureRecognizer(tapRecognizer)
215
+ }
216
+
217
+ public override func didMoveToSuperview() {
218
+ super.didMoveToSuperview()
219
+ updateConfiguredImagesForVisibleWindow()
220
+ }
221
+
222
+ public override func didMoveToWindow() {
223
+ super.didMoveToWindow()
224
+ if window == nil { codeHighlightingSession.cancel() } else { scheduleCodeHighlighting() }
225
+ updateConfiguredImagesForVisibleWindow()
226
+ }
227
+
228
+ @available(*, unavailable)
229
+ required init?(coder: NSCoder) { fatalError("PreparedProseDrawingView does not support NSCoder") }
230
+
231
+ internal static func pixelAllocationBytes(for image: UIImage) -> Int {
232
+ if let cgImage = image.cgImage {
233
+ return saturatingMultiply(cgImage.bytesPerRow, cgImage.height)
234
+ }
235
+ let width = image.size.width * image.scale
236
+ let height = image.size.height * image.scale
237
+ guard width.isFinite, height.isFinite, width > 0, height > 0 else { return 0 }
238
+ let pixels = min(Double(Int.max), width.rounded(.up) * height.rounded(.up))
239
+ return saturatingMultiply(Int(pixels), 4)
240
+ }
241
+
242
+ internal static func saturatingAdd(_ left: Int, _ right: Int) -> Int {
243
+ guard left <= Int.max - right else { return Int.max }
244
+ return left + right
245
+ }
246
+
247
+ internal static func saturatingMultiply(_ left: Int, _ right: Int) -> Int {
248
+ guard left > 0, right > 0 else { return 0 }
249
+ guard left <= Int.max / right else { return Int.max }
250
+ return left * right
251
+ }
252
+
253
+ private func configuredVisibleRect() -> CGRect? {
254
+ guard let window, !isHidden, alpha > 0 else { return nil }
255
+ var visible = convert(window.bounds, from: window).intersection(bounds)
256
+ var ancestor = superview
257
+ while let view = ancestor, view !== window {
258
+ guard !view.isHidden, view.alpha > 0 else { return nil }
259
+ if view.clipsToBounds {
260
+ visible = visible.intersection(convert(view.bounds, from: view))
261
+ }
262
+ ancestor = view.superview
263
+ }
264
+ guard visible.origin.x.isFinite, visible.origin.y.isFinite,
265
+ visible.size.width.isFinite, visible.size.height.isFinite,
266
+ !visible.isNull, !visible.isEmpty else { return nil }
267
+ return visible
268
+ }
269
+
270
+ private func refreshScrollObservations() {
271
+ var scrollViews: [UIScrollView] = []
272
+ var ancestor = superview
273
+ while let view = ancestor {
274
+ if let scrollView = view as? UIScrollView { scrollViews.append(scrollView) }
275
+ ancestor = view.superview
276
+ }
277
+ let activeScrollViews = window == nil ? [] : scrollViews
278
+ let nextIDs = activeScrollViews.map(ObjectIdentifier.init)
279
+ guard nextIDs != observedScrollViewIDs else { return }
280
+ scrollObservations.removeAll()
281
+ observedScrollViewIDs = nextIDs
282
+ scrollObservations = activeScrollViews.map { scrollView in
283
+ scrollView.observe(\.contentOffset, options: [.new]) { [weak self] _, _ in
284
+ self?.updateConfiguredImagesForVisibleWindow()
285
+ }
286
+ }
287
+ }
288
+
289
+ func interaction(at point: CGPoint) -> PreparedProseInteraction? {
290
+ guard let layout else { return nil }
291
+ return layout.interactions.first { interaction in
292
+ (linkInteractionsEnabled || interaction.kind != .link) && interaction.rects.contains { $0.contains(point) }
293
+ }
294
+ }
295
+
296
+ @objc private func handleTap(_ recognizer: UITapGestureRecognizer) {
297
+ guard recognizer.state == .ended,
298
+ let interaction = interaction(at: recognizer.location(in: self))
299
+ else { return }
300
+ _ = activate(interaction)
301
+ }
302
+
303
+ @discardableResult
304
+ private func activate(_ interaction: PreparedProseInteraction) -> Bool {
305
+ if let onActivateInteraction { return onActivateInteraction(interaction) }
306
+ switch interaction.kind {
307
+ case .link:
308
+ guard linkInteractionsEnabled, let href = interaction.href else { return false }
309
+ return interactionDelegate?.preparedProseDrawingView(self, didActivateLink: href, text: interaction.visibleText) ?? false
310
+ case .mention:
311
+ guard let docPos = interaction.docPos, let attrsJSON = interaction.attrsJSON else { return false }
312
+ return interactionDelegate?.preparedProseDrawingView(
313
+ self,
314
+ didActivateMention: docPos,
315
+ label: interaction.label,
316
+ attrsJSON: attrsJSON
317
+ ) ?? false
318
+ }
319
+ }
320
+
321
+ public override func accessibilityElementCount() -> Int { accessibilityNodes.count }
322
+
323
+ public override func accessibilityElement(at index: Int) -> Any? {
324
+ let nodes = accessibilityNodes
325
+ guard nodes.indices.contains(index), let layout else { return nil }
326
+ if let existing = accessibilityElementsByIndex[index] { return existing }
327
+ let element = PreparedProseDrawingAccessibilityElement(
328
+ container: self,
329
+ index: index,
330
+ node: nodes[index],
331
+ layout: layout
332
+ )
333
+ accessibilityElementsByIndex[index] = element
334
+ return element
335
+ }
336
+
337
+ public override func index(ofAccessibilityElement element: Any) -> Int {
338
+ guard let element = element as? PreparedProseDrawingAccessibilityElement,
339
+ element.drawingView === self,
340
+ element.belongs(to: layout)
341
+ else { return NSNotFound }
342
+ return element.index
343
+ }
344
+
345
+ private var accessibilityNodes: [PreparedProseAccessibilityNode] {
346
+ layout?.accessibilityNodes.map { node in
347
+ guard !linkInteractionsEnabled, node.role == .link else { return node }
348
+ return PreparedProseAccessibilityNode(
349
+ interactionIndex: nil,
350
+ role: .text,
351
+ label: node.label,
352
+ rects: node.rects
353
+ )
354
+ } ?? []
355
+ }
356
+
357
+ fileprivate func accessibilityFrame(
358
+ for node: PreparedProseAccessibilityNode,
359
+ layout: PreparedProseLayout
360
+ ) -> CGRect {
361
+ guard self.layout === layout else { return .zero }
362
+ return UIAccessibility.convertToScreenCoordinates(node.bounds, in: self)
363
+ }
364
+
365
+ fileprivate func accessibilityPath(
366
+ for node: PreparedProseAccessibilityNode,
367
+ layout: PreparedProseLayout
368
+ ) -> UIBezierPath? {
369
+ guard self.layout === layout, !node.rects.isEmpty else { return nil }
370
+ let path = UIBezierPath()
371
+ for rect in node.rects {
372
+ path.append(UIBezierPath(rect: rect))
373
+ }
374
+ return UIAccessibility.convertToScreenCoordinates(path, in: self)
375
+ }
376
+
377
+ fileprivate func activateAccessibilityNode(
378
+ _ node: PreparedProseAccessibilityNode,
379
+ layout: PreparedProseLayout
380
+ ) -> Bool {
381
+ guard self.layout === layout,
382
+ let interactionIndex = node.interactionIndex,
383
+ let interaction = layout.interactions[safe: interactionIndex]
384
+ else { return false }
385
+ return activate(interaction)
386
+ }
387
+
388
+ private func invalidateAccessibilityNodes() {
389
+ accessibilityElementsByIndex.removeAll(keepingCapacity: true)
390
+ UIAccessibility.post(notification: .layoutChanged, argument: nil)
391
+ }
392
+
393
+ /// Converts an artifact-top baseline to the flipped Core Graphics coordinate system.
394
+ /// The view bounds, not the intrinsic artifact height, defines the flip origin.
395
+ static func textPosition(
396
+ baselineFromArtifactTop: CGFloat,
397
+ in bounds: CGRect,
398
+ artifactHeight _: CGFloat
399
+ ) -> CGPoint {
400
+ CGPoint(x: 0, y: bounds.height - baselineFromArtifactTop)
401
+ }
402
+
403
+ public override func draw(_ rect: CGRect) {
404
+ let drawStarted = PreparedProseInstrumentation.now()
405
+ guard let layout, let context = UIGraphicsGetCurrentContext(), !layout.blocks.isEmpty else { return }
406
+ let blocks = layout.blocks
407
+ var lower = 0
408
+ var upper = blocks.count
409
+ while layout.hasMonotonicBlockBounds && lower < upper {
410
+ let middle = (lower + upper) / 2
411
+ if blocks[middle].bounds.maxY < rect.minY { lower = middle + 1 } else { upper = middle }
412
+ }
413
+
414
+ context.saveGState()
415
+ defer { context.restoreGState() }
416
+ if let content = layout.decorations.first, let box = content.styleBox {
417
+ context.addPath(box.path(in: content.bounds).cgPath)
418
+ context.clip()
419
+ }
420
+ for fragment in layout.decorations where fragment.bounds.intersects(rect) {
421
+ fragment.styleBox?.draw(in: fragment.bounds, context: context)
422
+ }
423
+ context.saveGState()
424
+ context.translateBy(x: 0, y: bounds.height)
425
+ context.scaleBy(x: 1, y: -1)
426
+ let scale = CGFloat(Double(bitPattern: layout.key.displayScaleBits))
427
+ var visibleFragments: [PreparedProseFragment] = []
428
+ var visibleBlockCount = 0
429
+ for index in lower..<blocks.count {
430
+ let block = blocks[index]
431
+ if layout.hasMonotonicBlockBounds && block.bounds.minY > rect.maxY { break }
432
+ guard block.bounds.intersects(rect) else { continue }
433
+ visibleFragments.append(contentsOf: block.fragments)
434
+ visibleBlockCount += 1
435
+ }
436
+ // Keep paint phases global across the visible range: a nested code
437
+ // background must never cover a quote border from an adjacent block.
438
+ for fragment in visibleFragments { drawBackground(fragment, in: context) }
439
+ for fragment in visibleFragments { drawBorderOrRule(fragment, in: context, scale: scale) }
440
+ for fragment in visibleFragments { drawForeground(fragment, in: context) }
441
+ context.restoreGState()
442
+ PreparedProseInstrumentation.drew(drawStarted, visibleBlocks: visibleBlockCount)
443
+ }
444
+
445
+ private func drawingRect(for fragment: PreparedProseFragment) -> CGRect {
446
+ CGRect(
447
+ x: fragment.bounds.minX,
448
+ y: bounds.height - fragment.bounds.maxY,
449
+ width: fragment.bounds.width,
450
+ height: fragment.bounds.height
451
+ )
452
+ }
453
+
454
+ private func drawBackground(_ fragment: PreparedProseFragment, in context: CGContext) {
455
+ guard fragment.kind == .background || fragment.kind == .atom || fragment.kind == .image else { return }
456
+ let rect = drawingRect(for: fragment)
457
+ if let box = fragment.styleBox {
458
+ context.saveGState()
459
+ context.translateBy(x: 0, y: bounds.height)
460
+ context.scaleBy(x: 1, y: -1)
461
+ box.draw(in: fragment.bounds, context: context)
462
+ context.restoreGState()
463
+ return
464
+ }
465
+ context.setFillColor(fragment.color ?? UIColor.clear.cgColor)
466
+ context.addPath(UIBezierPath(roundedRect: rect, cornerRadius: fragment.cornerRadius).cgPath)
467
+ context.drawPath(using: .fill)
468
+ }
469
+
470
+ private func drawBorderOrRule(_ fragment: PreparedProseFragment, in context: CGContext, scale: CGFloat) {
471
+ let rect = drawingRect(for: fragment)
472
+ switch fragment.kind {
473
+ case .border:
474
+ context.setFillColor(fragment.color ?? UIColor.clear.cgColor)
475
+ context.fill(rect)
476
+ case .rule:
477
+ let unit = scale.isFinite && scale > 0 ? 1 / scale : 1
478
+ let alignedY = (rect.minY / unit).rounded() * unit
479
+ context.setFillColor(fragment.color ?? UIColor.clear.cgColor)
480
+ context.fill(CGRect(x: rect.minX, y: alignedY, width: rect.width, height: max(unit, rect.height)))
481
+ case .atom where fragment.strokeWidth > 0:
482
+ context.setStrokeColor(fragment.borderColor ?? fragment.color ?? UIColor.clear.cgColor)
483
+ context.setLineWidth(fragment.strokeWidth)
484
+ let inset = fragment.strokeWidth / 2
485
+ context.addPath(
486
+ UIBezierPath(
487
+ roundedRect: rect.insetBy(dx: inset, dy: inset),
488
+ cornerRadius: max(0, fragment.cornerRadius - inset)
489
+ ).cgPath
490
+ )
491
+ context.drawPath(using: .stroke)
492
+ default:
493
+ break
494
+ }
495
+ }
496
+
497
+ private func drawForeground(_ fragment: PreparedProseFragment, in context: CGContext) {
498
+ let rect = CGRect(
499
+ x: fragment.bounds.minX,
500
+ y: bounds.height - fragment.bounds.maxY,
501
+ width: fragment.bounds.width,
502
+ height: fragment.bounds.height
503
+ )
504
+ switch fragment.kind {
505
+ case .text:
506
+ guard let line = fragment.line else { return }
507
+ context.textPosition = CGPoint(x: fragment.origin.x, y: bounds.height - fragment.origin.y)
508
+ CTLineDraw(line, context)
509
+ case .atom:
510
+ guard let line = fragment.line else { return }
511
+ context.textPosition = CGPoint(x: fragment.origin.x, y: bounds.height - fragment.origin.y)
512
+ CTLineDraw(line, context)
513
+ case .image:
514
+ guard let layout,
515
+ let attachment = layout.imageAttachments.first(where: { $0.bounds == fragment.bounds }),
516
+ let image = imagePixels[attachment.id] else { return }
517
+ context.saveGState()
518
+ context.translateBy(x: rect.minX, y: rect.maxY)
519
+ context.scaleBy(x: 1, y: -1)
520
+ let localBounds = CGRect(origin: .zero, size: rect.size)
521
+ if let box = fragment.styleBox {
522
+ context.addPath(box.path(in: localBounds, inner: true).cgPath)
523
+ context.clip()
524
+ context.clip(to: localBounds.inset(by: box.inset))
525
+ image.draw(in: box.imageRect(image.size, in: localBounds))
526
+ } else { image.draw(in: localBounds) }
527
+ context.restoreGState()
528
+ case .marker:
529
+ if fragment.label == "•", fragment.line == nil {
530
+ context.setFillColor(fragment.color ?? UIColor.label.cgColor)
531
+ context.fillEllipse(in: rect)
532
+ } else if let line = fragment.line {
533
+ context.textPosition = CGPoint(x: fragment.origin.x, y: bounds.height - fragment.origin.y)
534
+ CTLineDraw(line, context)
535
+ } else if let box = fragment.styleBox {
536
+ context.saveGState()
537
+ context.translateBy(x: 0, y: bounds.height)
538
+ context.scaleBy(x: 1, y: -1)
539
+ EditorStyleSheet.drawCheckbox(box, in: fragment.bounds, checked: fragment.checked, context: context)
540
+ context.restoreGState()
541
+ } else {
542
+ drawTaskMarker(in: rect, checked: fragment.checked, color: UIColor(cgColor: fragment.color ?? UIColor.label.cgColor))
543
+ }
544
+ case .strike:
545
+ context.setFillColor(fragment.color ?? UIColor.clear.cgColor)
546
+ context.addPath(UIBezierPath(roundedRect: rect, cornerRadius: fragment.cornerRadius).cgPath)
547
+ context.fillPath()
548
+ case .background, .border, .rule:
549
+ break
550
+ }
551
+ }
552
+
553
+ private func drawTaskMarker(in rect: CGRect, checked: Bool, color: UIColor) {
554
+ let inset = max(1, rect.height * 0.2)
555
+ let box = CGRect(x: rect.minX + inset, y: rect.minY + inset, width: rect.height - inset * 2, height: rect.height - inset * 2)
556
+ let path = UIBezierPath(roundedRect: box, cornerRadius: box.width * 0.2)
557
+ color.setStroke()
558
+ path.lineWidth = max(1, box.width * 0.1)
559
+ path.stroke()
560
+ guard checked else { return }
561
+ let check = UIBezierPath()
562
+ check.move(to: CGPoint(x: box.minX + box.width * 0.2, y: box.midY))
563
+ check.addLine(to: CGPoint(x: box.minX + box.width * 0.43, y: box.maxY - box.height * 0.2))
564
+ check.addLine(to: CGPoint(x: box.maxX - box.width * 0.16, y: box.minY + box.height * 0.2))
565
+ check.lineCapStyle = .round
566
+ check.lineJoinStyle = .round
567
+ check.lineWidth = max(1.4, box.width * 0.12)
568
+ color.setStroke()
569
+ check.stroke()
570
+ }
571
+ }
572
+
573
+ private final class PreparedProseDrawingAccessibilityElement: UIAccessibilityElement {
574
+ weak var drawingView: PreparedProseDrawingView?
575
+ weak var layout: PreparedProseLayout?
576
+ let index: Int
577
+ let node: PreparedProseAccessibilityNode
578
+
579
+ init(
580
+ container: PreparedProseDrawingView,
581
+ index: Int,
582
+ node: PreparedProseAccessibilityNode,
583
+ layout: PreparedProseLayout
584
+ ) {
585
+ drawingView = container
586
+ self.index = index
587
+ self.node = node
588
+ self.layout = layout
589
+ super.init(accessibilityContainer: container)
590
+ }
591
+
592
+ func belongs(to layout: PreparedProseLayout?) -> Bool {
593
+ self.layout === layout
594
+ }
595
+
596
+ override var accessibilityLabel: String? {
597
+ get { node.label }
598
+ set { }
599
+ }
600
+ override var accessibilityTraits: UIAccessibilityTraits {
601
+ get {
602
+ switch node.role {
603
+ case .text, .separator:
604
+ return .staticText
605
+ case .heading:
606
+ return [.staticText, .header]
607
+ case .link:
608
+ return .link
609
+ case .mention:
610
+ return .button
611
+ case .image:
612
+ return .image
613
+ }
614
+ }
615
+ set { }
616
+ }
617
+ override var accessibilityFrame: CGRect {
618
+ get {
619
+ guard let drawingView, let layout else { return .zero }
620
+ return drawingView.accessibilityFrame(for: node, layout: layout)
621
+ }
622
+ set { }
623
+ }
624
+ override var accessibilityPath: UIBezierPath? {
625
+ get {
626
+ guard let drawingView, let layout else { return nil }
627
+ return drawingView.accessibilityPath(for: node, layout: layout)
628
+ }
629
+ set { }
630
+ }
631
+ override func accessibilityActivate() -> Bool {
632
+ guard let drawingView, let layout else { return false }
633
+ return drawingView.activateAccessibilityNode(node, layout: layout)
634
+ }
635
+ }
636
+
637
+ private extension Array {
638
+ subscript(safe index: Int) -> Element? { indices.contains(index) ? self[index] : nil }
639
+ }