@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,697 @@
1
+ import UIKit
2
+
3
+ struct RemoteSelectionDecoration {
4
+ let clientId: String
5
+ let anchor: UInt32
6
+ let head: UInt32
7
+ let color: UIColor
8
+ let name: String?
9
+ let isFocused: Bool
10
+
11
+ static func from(json: String?) -> [RemoteSelectionDecoration] {
12
+ guard let json,
13
+ let data = json.data(using: .utf8),
14
+ let raw = try? JSONSerialization.jsonObject(with: data) as? [[String: Any]]
15
+ else {
16
+ return []
17
+ }
18
+
19
+ return raw.compactMap { item in
20
+ guard let clientId = item["clientId"] as? String,
21
+ !clientId.isEmpty,
22
+ clientId.allSatisfy({ $0 >= "0" && $0 <= "9" }),
23
+ clientId == "0" || clientId.first != "0",
24
+ UInt64(clientId) != nil,
25
+ let anchor = v2ExactUInt32(item["anchor"] as? NSNumber),
26
+ let head = v2ExactUInt32(item["head"] as? NSNumber),
27
+ let colorRaw = item["color"] as? String,
28
+ let color = colorFromString(colorRaw)
29
+ else {
30
+ return nil
31
+ }
32
+
33
+ return RemoteSelectionDecoration(
34
+ clientId: clientId,
35
+ anchor: anchor,
36
+ head: head,
37
+ color: color,
38
+ name: item["name"] as? String,
39
+ isFocused: (item["isFocused"] as? Bool) ?? false
40
+ )
41
+ }
42
+ }
43
+
44
+ private static func colorFromString(_ raw: String) -> UIColor? {
45
+ let value = raw.trimmingCharacters(in: .whitespacesAndNewlines)
46
+ guard value.hasPrefix("#") else { return nil }
47
+ let hex = String(value.dropFirst())
48
+
49
+ switch hex.count {
50
+ case 3:
51
+ let chars = Array(hex)
52
+ return UIColor(
53
+ red: component(String(repeating: String(chars[0]), count: 2)),
54
+ green: component(String(repeating: String(chars[1]), count: 2)),
55
+ blue: component(String(repeating: String(chars[2]), count: 2)),
56
+ alpha: 1
57
+ )
58
+ case 4:
59
+ let chars = Array(hex)
60
+ return UIColor(
61
+ red: component(String(repeating: String(chars[0]), count: 2)),
62
+ green: component(String(repeating: String(chars[1]), count: 2)),
63
+ blue: component(String(repeating: String(chars[2]), count: 2)),
64
+ alpha: component(String(repeating: String(chars[3]), count: 2))
65
+ )
66
+ case 6:
67
+ return UIColor(
68
+ red: component(String(hex.prefix(2))),
69
+ green: component(String(hex.dropFirst(2).prefix(2))),
70
+ blue: component(String(hex.dropFirst(4).prefix(2))),
71
+ alpha: 1
72
+ )
73
+ case 8:
74
+ return UIColor(
75
+ red: component(String(hex.prefix(2))),
76
+ green: component(String(hex.dropFirst(2).prefix(2))),
77
+ blue: component(String(hex.dropFirst(4).prefix(2))),
78
+ alpha: component(String(hex.dropFirst(6).prefix(2)))
79
+ )
80
+ default:
81
+ return nil
82
+ }
83
+ }
84
+
85
+ private static func component(_ hex: String) -> CGFloat {
86
+ CGFloat(Int(hex, radix: 16) ?? 0) / 255
87
+ }
88
+ }
89
+
90
+ private final class RemoteSelectionBadgeLabel: UILabel {
91
+ override func drawText(in rect: CGRect) {
92
+ super.drawText(in: rect.inset(by: UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 8)))
93
+ }
94
+
95
+ override var intrinsicContentSize: CGSize {
96
+ let size = super.intrinsicContentSize
97
+ return CGSize(width: size.width + 16, height: max(size.height + 8, 22))
98
+ }
99
+ }
100
+
101
+ final class RemoteSelectionOverlayView: UIView {
102
+ private struct ColoredRect {
103
+ let frame: CGRect
104
+ let color: UIColor
105
+ }
106
+
107
+ weak var textView: EditorTextView?
108
+ private var editorId: UInt64 = 0
109
+ private var selections: [RemoteSelectionDecoration] = []
110
+ private var selectionViews: [UIView] = []
111
+ private var caretViews: [UIView] = []
112
+
113
+ override init(frame: CGRect) {
114
+ super.init(frame: frame)
115
+ backgroundColor = .clear
116
+ isUserInteractionEnabled = false
117
+ clipsToBounds = true
118
+ }
119
+
120
+ required init?(coder: NSCoder) {
121
+ return nil
122
+ }
123
+
124
+ func bind(textView: EditorTextView) {
125
+ self.textView = textView
126
+ }
127
+
128
+ func update(selections: [RemoteSelectionDecoration], editorId: UInt64) {
129
+ self.selections = selections
130
+ self.editorId = editorId
131
+ refresh()
132
+ }
133
+
134
+ func refresh() {
135
+ guard editorId != 0,
136
+ let textView
137
+ else {
138
+ syncSelectionViews(with: [])
139
+ syncCaretViews(with: [])
140
+ return
141
+ }
142
+
143
+ var selectionRects: [ColoredRect] = []
144
+ var caretRects: [ColoredRect] = []
145
+
146
+ for selection in selections {
147
+ let geometry = geometry(for: selection, in: textView)
148
+ for rect in geometry.selectionRects {
149
+ selectionRects.append(
150
+ ColoredRect(
151
+ frame: rect.integral,
152
+ color: selection.color.withAlphaComponent(0.18)
153
+ )
154
+ )
155
+ }
156
+
157
+ guard selection.isFocused,
158
+ let caretRect = geometry.caretRect
159
+ else {
160
+ continue
161
+ }
162
+
163
+ caretRects.append(
164
+ ColoredRect(
165
+ frame: CGRect(
166
+ x: round(caretRect.minX),
167
+ y: round(caretRect.minY),
168
+ width: max(2, round(caretRect.width)),
169
+ height: round(caretRect.height)
170
+ ),
171
+ color: selection.color
172
+ )
173
+ )
174
+ }
175
+
176
+ syncSelectionViews(with: selectionRects)
177
+ syncCaretViews(with: caretRects)
178
+ }
179
+
180
+ var hasVisibleDecorations: Bool {
181
+ selectionViews.contains { !$0.isHidden } || caretViews.contains { !$0.isHidden }
182
+ }
183
+
184
+ var hasSelectionsOrVisibleDecorations: Bool {
185
+ !selections.isEmpty || hasVisibleDecorations
186
+ }
187
+
188
+ private func geometry(
189
+ for selection: RemoteSelectionDecoration,
190
+ in textView: EditorTextView
191
+ ) -> (selectionRects: [CGRect], caretRect: CGRect?) {
192
+ let startScalar = EditorV2Shadow.docToScalar(
193
+ id: editorId,
194
+ docPos: min(selection.anchor, selection.head)
195
+ )
196
+ let endScalar = EditorV2Shadow.docToScalar(
197
+ id: editorId,
198
+ docPos: max(selection.anchor, selection.head)
199
+ )
200
+
201
+ let startPosition = PositionBridge.scalarToTextView(startScalar, in: textView)
202
+ let endPosition = PositionBridge.scalarToTextView(endScalar, in: textView)
203
+ let caretRect = resolvedCaretRect(
204
+ for: endPosition,
205
+ in: textView
206
+ )
207
+
208
+ if startScalar == endScalar {
209
+ return ([], caretRect)
210
+ }
211
+
212
+ guard let range = textView.textRange(from: startPosition, to: endPosition) else {
213
+ return ([], caretRect)
214
+ }
215
+
216
+ let selectionRects = textView.selectionRects(for: range)
217
+ .map(\.rect)
218
+ .filter { !$0.isEmpty && $0.width > 0 && $0.height > 0 }
219
+ .map { textView.convert($0, to: self) }
220
+
221
+ return (selectionRects, caretRect)
222
+ }
223
+
224
+ private func resolvedCaretRect(
225
+ for position: UITextPosition,
226
+ in textView: EditorTextView
227
+ ) -> CGRect? {
228
+ let directRect = textView.convert(textView.caretRect(for: position), to: self)
229
+ if directRect.height > 0, directRect.width >= 0 {
230
+ return directRect
231
+ }
232
+
233
+ if let previousPosition = textView.position(from: position, offset: -1),
234
+ let previousRange = textView.textRange(from: previousPosition, to: position),
235
+ let previousRect = textView.selectionRects(for: previousRange)
236
+ .map(\.rect)
237
+ .last(where: { !$0.isEmpty && $0.height > 0 }) {
238
+ let rect = textView.convert(previousRect, to: self)
239
+ return CGRect(x: rect.maxX, y: rect.minY, width: 2, height: rect.height)
240
+ }
241
+
242
+ if let nextPosition = textView.position(from: position, offset: 1),
243
+ let nextRange = textView.textRange(from: position, to: nextPosition),
244
+ let nextRect = textView.selectionRects(for: nextRange)
245
+ .map(\.rect)
246
+ .first(where: { !$0.isEmpty && $0.height > 0 }) {
247
+ let rect = textView.convert(nextRect, to: self)
248
+ return CGRect(x: rect.minX, y: rect.minY, width: 2, height: rect.height)
249
+ }
250
+
251
+ if directRect.isEmpty {
252
+ return nil
253
+ }
254
+
255
+ return directRect
256
+ }
257
+
258
+ private func syncSelectionViews(with rects: [ColoredRect]) {
259
+ syncViews(rects, existingViews: &selectionViews) { view, rect in
260
+ view.frame = rect.frame
261
+ view.backgroundColor = rect.color
262
+ view.layer.cornerRadius = 3
263
+ }
264
+ }
265
+
266
+ private func syncCaretViews(with rects: [ColoredRect]) {
267
+ syncViews(rects, existingViews: &caretViews) { view, rect in
268
+ view.frame = rect.frame
269
+ view.backgroundColor = rect.color
270
+ view.layer.cornerRadius = view.bounds.width / 2
271
+ bringSubviewToFront(view)
272
+ }
273
+ }
274
+
275
+ private func syncViews(
276
+ _ rects: [ColoredRect],
277
+ existingViews: inout [UIView],
278
+ configure: (UIView, ColoredRect) -> Void
279
+ ) {
280
+ while existingViews.count < rects.count {
281
+ let view = UIView(frame: .zero)
282
+ view.isUserInteractionEnabled = false
283
+ addSubview(view)
284
+ existingViews.append(view)
285
+ }
286
+
287
+ for (index, rect) in rects.enumerated() {
288
+ let view = existingViews[index]
289
+ view.isHidden = false
290
+ configure(view, rect)
291
+ }
292
+
293
+ if existingViews.count > rects.count {
294
+ for view in existingViews[rects.count...] {
295
+ view.isHidden = true
296
+ view.frame = .zero
297
+ }
298
+ }
299
+ }
300
+ }
301
+
302
+ final class ImageTapOverlayView: UIView {
303
+ private weak var editorView: RichTextEditorView?
304
+
305
+ override init(frame: CGRect) {
306
+ super.init(frame: frame)
307
+ backgroundColor = .clear
308
+ }
309
+
310
+ required init?(coder: NSCoder) {
311
+ return nil
312
+ }
313
+
314
+ func bind(editorView: RichTextEditorView) {
315
+ self.editorView = editorView
316
+ }
317
+
318
+ override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
319
+ guard let editorView else { return false }
320
+ let pointInTextView = convert(point, to: editorView.textView)
321
+ return editorView.textView.hasImageAttachment(at: pointInTextView)
322
+ }
323
+
324
+ func interceptsPointForTesting(_ point: CGPoint) -> Bool {
325
+ self.point(inside: point, with: nil)
326
+ }
327
+
328
+ @discardableResult
329
+ func handleTapForTesting(_ point: CGPoint) -> Bool {
330
+ guard let editorView else { return false }
331
+ let pointInTextView = convert(point, to: editorView.textView)
332
+ return editorView.textView.selectImageAttachment(at: pointInTextView)
333
+ }
334
+ }
335
+
336
+ final class TaskListMarkerTapOverlayView: UIView {
337
+ private weak var editorView: RichTextEditorView?
338
+ private lazy var tapRecognizer: UITapGestureRecognizer = {
339
+ let recognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
340
+ recognizer.cancelsTouchesInView = true
341
+ return recognizer
342
+ }()
343
+
344
+ override init(frame: CGRect) {
345
+ super.init(frame: frame)
346
+ backgroundColor = .clear
347
+ addGestureRecognizer(tapRecognizer)
348
+ }
349
+
350
+ required init?(coder: NSCoder) {
351
+ return nil
352
+ }
353
+
354
+ func bind(editorView: RichTextEditorView) {
355
+ self.editorView = editorView
356
+ }
357
+
358
+ override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
359
+ guard let editorView else { return false }
360
+ let pointInTextView = convert(point, to: editorView.textView)
361
+ return editorView.textView.hasTaskListMarker(at: pointInTextView)
362
+ }
363
+
364
+ @objc
365
+ private func handleTap(_ recognizer: UITapGestureRecognizer) {
366
+ guard recognizer.state == .ended, let editorView else { return }
367
+ let pointInTextView = convert(recognizer.location(in: self), to: editorView.textView)
368
+ _ = editorView.textView.toggleTaskListMarker(at: pointInTextView)
369
+ }
370
+
371
+ func interceptsPointForTesting(_ point: CGPoint) -> Bool {
372
+ self.point(inside: point, with: nil)
373
+ }
374
+
375
+ @discardableResult
376
+ func handleTapForTesting(_ point: CGPoint) -> Bool {
377
+ guard let editorView else { return false }
378
+ let pointInTextView = convert(point, to: editorView.textView)
379
+ return editorView.textView.toggleTaskListMarker(at: pointInTextView)
380
+ }
381
+ }
382
+
383
+ private final class ImageResizeHandleView: UIView {
384
+ let corner: ImageResizeOverlayView.Corner
385
+
386
+ init(corner: ImageResizeOverlayView.Corner) {
387
+ self.corner = corner
388
+ super.init(frame: .zero)
389
+ isUserInteractionEnabled = true
390
+ backgroundColor = .systemBackground
391
+ layer.borderColor = UIColor.systemBlue.cgColor
392
+ layer.borderWidth = 2
393
+ layer.cornerRadius = 10
394
+ }
395
+
396
+ required init?(coder: NSCoder) {
397
+ return nil
398
+ }
399
+ }
400
+
401
+ final class ImageResizeOverlayView: UIView {
402
+ enum Corner: CaseIterable {
403
+ case topLeft
404
+ case topRight
405
+ case bottomLeft
406
+ case bottomRight
407
+ }
408
+
409
+ private struct DragState {
410
+ let corner: Corner
411
+ let originalRect: CGRect
412
+ let docPos: UInt32
413
+ let maximumWidth: CGFloat
414
+ }
415
+
416
+ private weak var editorView: RichTextEditorView?
417
+ private let selectionLayer = CAShapeLayer()
418
+ private let previewBackdropView = UIView()
419
+ private let previewImageView = UIImageView()
420
+ private var handleViews: [Corner: ImageResizeHandleView] = [:]
421
+ private var currentRect: CGRect?
422
+ private var currentDocPos: UInt32?
423
+ private var dragState: DragState?
424
+ private let handleSize: CGFloat = 20
425
+ private let minimumImageSize: CGFloat = 48
426
+
427
+ override init(frame: CGRect) {
428
+ super.init(frame: frame)
429
+ backgroundColor = .clear
430
+ clipsToBounds = true
431
+
432
+ previewBackdropView.isUserInteractionEnabled = false
433
+ previewBackdropView.isHidden = true
434
+ previewBackdropView.layer.zPosition = 1
435
+ addSubview(previewBackdropView)
436
+
437
+ previewImageView.isUserInteractionEnabled = false
438
+ previewImageView.isHidden = true
439
+ previewImageView.contentMode = .scaleToFill
440
+ previewImageView.layer.zPosition = 2
441
+ addSubview(previewImageView)
442
+
443
+ selectionLayer.strokeColor = UIColor.systemBlue.cgColor
444
+ selectionLayer.fillColor = UIColor.clear.cgColor
445
+ selectionLayer.lineWidth = 2
446
+ selectionLayer.zPosition = 10
447
+ layer.addSublayer(selectionLayer)
448
+
449
+ for corner in Corner.allCases {
450
+ let handleView = ImageResizeHandleView(corner: corner)
451
+ let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
452
+ handleView.addGestureRecognizer(panGesture)
453
+ handleView.layer.zPosition = 20
454
+ addSubview(handleView)
455
+ handleViews[corner] = handleView
456
+ }
457
+
458
+ isHidden = true
459
+ }
460
+
461
+ required init?(coder: NSCoder) {
462
+ return nil
463
+ }
464
+
465
+ func bind(editorView: RichTextEditorView) {
466
+ self.editorView = editorView
467
+ }
468
+
469
+ func refresh() {
470
+ if dragState != nil {
471
+ return
472
+ }
473
+
474
+ guard let editorView,
475
+ let geometry = editorView.selectedImageGeometry()
476
+ else {
477
+ hideOverlay()
478
+ return
479
+ }
480
+
481
+ hidePreviewLayers()
482
+ applyGeometry(rect: geometry.rect, docPos: geometry.docPos)
483
+ }
484
+
485
+ func simulateResizeForTesting(width: CGFloat, height: CGFloat) {
486
+ guard let docPos = currentDocPos else { return }
487
+ editorView?.resizeImage(docPos: docPos, size: CGSize(width: width, height: height))
488
+ }
489
+
490
+ func simulatePreviewResizeForTesting(width: CGFloat, height: CGFloat) {
491
+ guard beginPreviewResize(from: .bottomRight) else { return }
492
+ let nextRect = CGRect(
493
+ origin: dragState?.originalRect.origin ?? .zero,
494
+ size: editorView?.clampedImageSize(
495
+ CGSize(width: width, height: height),
496
+ maximumWidth: dragState?.maximumWidth
497
+ ) ?? CGSize(width: width, height: height)
498
+ )
499
+ updatePreviewRect(nextRect)
500
+ }
501
+
502
+ func commitPreviewResizeForTesting() {
503
+ finishPreviewResize(commit: true)
504
+ }
505
+
506
+ var visibleRectForTesting: CGRect? {
507
+ isHidden ? nil : currentRect
508
+ }
509
+
510
+ var isOverlayVisible: Bool {
511
+ !isHidden
512
+ }
513
+
514
+ var previewHasImageForTesting: Bool {
515
+ !previewImageView.isHidden && previewImageView.image != nil
516
+ }
517
+
518
+ func interceptsPointForTesting(_ location: CGPoint) -> Bool {
519
+ self.point(inside: location, with: nil)
520
+ }
521
+
522
+ override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
523
+ guard !isHidden else { return false }
524
+ for handleView in handleViews.values where !handleView.isHidden {
525
+ if handleView.frame.insetBy(dx: -12, dy: -12).contains(point) {
526
+ return true
527
+ }
528
+ }
529
+ return false
530
+ }
531
+
532
+ private func hideOverlay() {
533
+ hidePreviewLayers()
534
+ dragState = nil
535
+ currentRect = nil
536
+ currentDocPos = nil
537
+ selectionLayer.path = nil
538
+ isHidden = true
539
+ }
540
+
541
+ private func applyGeometry(rect: CGRect, docPos: UInt32) {
542
+ let integralRect = rect.integral
543
+ currentRect = integralRect
544
+ currentDocPos = docPos
545
+ selectionLayer.path = UIBezierPath(roundedRect: integralRect, cornerRadius: 8).cgPath
546
+ isHidden = false
547
+ layoutHandleViews(for: integralRect)
548
+ }
549
+
550
+ private func hidePreviewLayers() {
551
+ previewBackdropView.isHidden = true
552
+ previewImageView.isHidden = true
553
+ previewImageView.image = nil
554
+ }
555
+
556
+ private func showPreview(docPos: UInt32, originalRect: CGRect) {
557
+ previewBackdropView.backgroundColor = editorView?.imageResizePreviewBackgroundColor() ?? .systemBackground
558
+ previewBackdropView.frame = originalRect
559
+ previewBackdropView.isHidden = false
560
+
561
+ previewImageView.image = editorView?.imagePreviewForResize(docPos: docPos)
562
+ previewImageView.frame = originalRect
563
+ previewImageView.isHidden = previewImageView.image == nil
564
+ }
565
+
566
+ @discardableResult
567
+ private func beginPreviewResize(from corner: Corner) -> Bool {
568
+ guard let currentRect, let currentDocPos else { return false }
569
+ editorView?.setImageResizePreviewActive(true)
570
+ let maximumWidth = editorView?.maximumImageWidthForResizeGesture() ?? currentRect.width
571
+ dragState = DragState(
572
+ corner: corner,
573
+ originalRect: currentRect,
574
+ docPos: currentDocPos,
575
+ maximumWidth: maximumWidth
576
+ )
577
+ showPreview(docPos: currentDocPos, originalRect: currentRect)
578
+ return true
579
+ }
580
+
581
+ private func updatePreviewRect(_ rect: CGRect) {
582
+ guard let currentDocPos else { return }
583
+ applyGeometry(rect: rect, docPos: currentDocPos)
584
+ previewImageView.frame = currentRect ?? rect.integral
585
+ }
586
+
587
+ private func finishPreviewResize(commit: Bool) {
588
+ guard let dragState else { return }
589
+ let finalSize = currentRect?.size ?? dragState.originalRect.size
590
+ self.dragState = nil
591
+ editorView?.setImageResizePreviewActive(false)
592
+ if commit {
593
+ editorView?.resizeImage(docPos: dragState.docPos, size: finalSize)
594
+ } else {
595
+ hidePreviewLayers()
596
+ }
597
+ DispatchQueue.main.async { [weak self] in
598
+ self?.refresh()
599
+ }
600
+ }
601
+
602
+ private func layoutHandleViews(for rect: CGRect) {
603
+ for (corner, handleView) in handleViews {
604
+ let center = handleCenter(for: corner, in: rect)
605
+ handleView.frame = CGRect(
606
+ x: center.x - (handleSize / 2),
607
+ y: center.y - (handleSize / 2),
608
+ width: handleSize,
609
+ height: handleSize
610
+ )
611
+ }
612
+ }
613
+
614
+ private func handleCenter(for corner: Corner, in rect: CGRect) -> CGPoint {
615
+ switch corner {
616
+ case .topLeft:
617
+ return CGPoint(x: rect.minX, y: rect.minY)
618
+ case .topRight:
619
+ return CGPoint(x: rect.maxX, y: rect.minY)
620
+ case .bottomLeft:
621
+ return CGPoint(x: rect.minX, y: rect.maxY)
622
+ case .bottomRight:
623
+ return CGPoint(x: rect.maxX, y: rect.maxY)
624
+ }
625
+ }
626
+
627
+ private func anchorPoint(for corner: Corner, in rect: CGRect) -> CGPoint {
628
+ switch corner {
629
+ case .topLeft:
630
+ return CGPoint(x: rect.maxX, y: rect.maxY)
631
+ case .topRight:
632
+ return CGPoint(x: rect.minX, y: rect.maxY)
633
+ case .bottomLeft:
634
+ return CGPoint(x: rect.maxX, y: rect.minY)
635
+ case .bottomRight:
636
+ return CGPoint(x: rect.minX, y: rect.minY)
637
+ }
638
+ }
639
+
640
+ private func resizedRect(
641
+ from originalRect: CGRect,
642
+ corner: Corner,
643
+ translation: CGPoint,
644
+ maximumWidth: CGFloat?
645
+ ) -> CGRect {
646
+ let aspectRatio = max(originalRect.width / max(originalRect.height, 1), 0.1)
647
+ let signedDx = (corner == .topRight || corner == .bottomRight) ? translation.x : -translation.x
648
+ let signedDy = (corner == .bottomLeft || corner == .bottomRight) ? translation.y : -translation.y
649
+ let widthScale = (originalRect.width + signedDx) / max(originalRect.width, 1)
650
+ let heightScale = (originalRect.height + signedDy) / max(originalRect.height, 1)
651
+ let scale = max(minimumImageSize / max(originalRect.width, 1), widthScale, heightScale)
652
+ let unclampedSize = CGSize(
653
+ width: max(minimumImageSize, originalRect.width * scale),
654
+ height: max(minimumImageSize / aspectRatio, (max(minimumImageSize, originalRect.width * scale) / aspectRatio))
655
+ )
656
+ let clampedSize = editorView?.clampedImageSize(unclampedSize, maximumWidth: maximumWidth) ?? unclampedSize
657
+ let width = clampedSize.width
658
+ let height = clampedSize.height
659
+ let anchor = anchorPoint(for: corner, in: originalRect)
660
+
661
+ switch corner {
662
+ case .topLeft:
663
+ return CGRect(x: anchor.x - width, y: anchor.y - height, width: width, height: height)
664
+ case .topRight:
665
+ return CGRect(x: anchor.x, y: anchor.y - height, width: width, height: height)
666
+ case .bottomLeft:
667
+ return CGRect(x: anchor.x - width, y: anchor.y, width: width, height: height)
668
+ case .bottomRight:
669
+ return CGRect(x: anchor.x, y: anchor.y, width: width, height: height)
670
+ }
671
+ }
672
+
673
+ @objc
674
+ private func handlePan(_ gesture: UIPanGestureRecognizer) {
675
+ guard let handleView = gesture.view as? ImageResizeHandleView else { return }
676
+
677
+ switch gesture.state {
678
+ case .began:
679
+ _ = beginPreviewResize(from: handleView.corner)
680
+ case .changed:
681
+ guard let dragState else { return }
682
+ let nextRect = resizedRect(
683
+ from: dragState.originalRect,
684
+ corner: dragState.corner,
685
+ translation: gesture.translation(in: self),
686
+ maximumWidth: dragState.maximumWidth
687
+ )
688
+ updatePreviewRect(nextRect)
689
+ case .ended:
690
+ finishPreviewResize(commit: true)
691
+ case .cancelled, .failed:
692
+ finishPreviewResize(commit: false)
693
+ default:
694
+ finishPreviewResize(commit: false)
695
+ }
696
+ }
697
+ }