@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,471 @@
1
+ import os
2
+ import UIKit
3
+
4
+ extension EditorTextView {
5
+ struct NativeTextMutation {
6
+ let from: UInt32
7
+ let to: UInt32
8
+ /// The replaced span as UTF-16 in the authorized storage. Kept so a
9
+ /// caret can be converted against that storage patched with this
10
+ /// replacement, which is the only ruler that still carries the
11
+ /// document's structural attributes.
12
+ let authorizedReplacementUtf16Range: NSRange
13
+ let replacementText: String
14
+ let resultingText: String
15
+ let authorizedText: String
16
+ let selectionAnchor: UInt32?
17
+ let selectionHead: UInt32?
18
+ let authorizedSelectionUtf16Range: NSRange?
19
+ let rawSelectionUtf16Range: NSRange?
20
+ let acceptedSpaceCaretUtf16Offset: Int?
21
+ let selectionRevision: UInt64
22
+ let capturedWhileFirstResponder: Bool
23
+ let capturedWhileEditable: Bool
24
+ let capturedAfterBlur: Bool
25
+ let inputGeneration: UInt64
26
+ }
27
+
28
+ /// The last Rust-authorized storage with one native replacement applied.
29
+ ///
30
+ /// A caret inside a natively mutated document cannot be converted against
31
+ /// the live text view. A keyboard correction replaces the word with an
32
+ /// unattributed string, which strips the structural attributes the
33
+ /// utf16→scalar conversion reads to count a list's block openings, so the
34
+ /// live view maps the caret as though the line were never wrapped. The
35
+ /// authorized storage still carries those attributes; patching its text
36
+ /// with the same replacement gives a ruler that matches the new text
37
+ /// while keeping the structure. Falls back to the unpatched storage when
38
+ /// the range no longer addresses it.
39
+ private func authorizedStorageApplying(
40
+ _ replacementText: String,
41
+ inUtf16Range range: NSRange
42
+ ) -> NSAttributedString {
43
+ guard range.location >= 0,
44
+ range.length >= 0,
45
+ NSMaxRange(range) <= lastAuthorizedAttributedTextStorage.length
46
+ else {
47
+ return lastAuthorizedAttributedTextStorage
48
+ }
49
+ let patched = NSMutableAttributedString(
50
+ attributedString: lastAuthorizedAttributedTextStorage
51
+ )
52
+ // The string overload inherits the replaced run's attributes, which is
53
+ // exactly what keeps the structure the keyboard's replacement dropped.
54
+ patched.replaceCharacters(in: range, with: replacementText)
55
+ return patched
56
+ }
57
+
58
+ func nativeTextMutationFromAuthorizedDiff(
59
+ currentText: String
60
+ ) -> NativeTextMutation? {
61
+ let authorizedText = lastAuthorizedText
62
+ guard currentText != authorizedText else { return nil }
63
+
64
+ let authorized = authorizedText as NSString
65
+ let current = currentText as NSString
66
+ let sharedLength = min(authorized.length, current.length)
67
+ var prefix = 0
68
+ while prefix < sharedLength,
69
+ authorized.character(at: prefix) == current.character(at: prefix) {
70
+ prefix += 1
71
+ }
72
+ prefix = sharedUtf16ScalarBoundary(atOrBefore: prefix, in: authorizedText, and: currentText)
73
+
74
+ var authorizedEnd = authorized.length
75
+ var currentEnd = current.length
76
+ while authorizedEnd > prefix,
77
+ currentEnd > prefix,
78
+ authorized.character(at: authorizedEnd - 1) == current.character(at: currentEnd - 1) {
79
+ authorizedEnd -= 1
80
+ currentEnd -= 1
81
+ }
82
+ authorizedEnd = utf16ScalarBoundary(atOrAfter: authorizedEnd, in: authorizedText)
83
+ currentEnd = utf16ScalarBoundary(atOrAfter: currentEnd, in: currentText)
84
+
85
+ let replacementLength = currentEnd - prefix
86
+ guard replacementLength >= 0 else { return nil }
87
+ let rawReplacementText = current.substring(
88
+ with: NSRange(location: prefix, length: replacementLength)
89
+ )
90
+
91
+ let rawSelectionUtf16Range = selectedUtf16Range()
92
+ let authorizedSelectionUtf16Range = lastAuthorizedSelectedUtf16Range
93
+ let preservesAcceptedSpace = shouldPreserveAcceptedAutocorrectSpace(
94
+ authorizedText: authorized,
95
+ replacementStartUtf16: prefix,
96
+ authorizedEndUtf16: authorizedEnd,
97
+ replacementText: rawReplacementText,
98
+ rawSelectionUtf16Range: rawSelectionUtf16Range,
99
+ authorizedSelectionUtf16Range: authorizedSelectionUtf16Range,
100
+ acceptedCaretUtf16Offset: currentEnd
101
+ )
102
+ let replacementText = preservesAcceptedSpace
103
+ ? rawReplacementText + " "
104
+ : rawReplacementText
105
+ let selectionRangeForMapping = preservesAcceptedSpace
106
+ ? NSRange(location: currentEnd + 1, length: 0)
107
+ : rawSelectionUtf16Range
108
+ let targetSelectionUtf16Range = targetSelectionUtf16RangeForNativeTextMutation(
109
+ rawSelectionUtf16Range: selectionRangeForMapping,
110
+ authorizedSelectionUtf16Range: authorizedSelectionUtf16Range,
111
+ replacementStartUtf16: prefix,
112
+ authorizedEndUtf16: authorizedEnd,
113
+ currentEndUtf16: currentEnd + (preservesAcceptedSpace ? 1 : 0),
114
+ currentTextUtf16Length: current.length + (preservesAcceptedSpace ? 1 : 0)
115
+ )
116
+ let mappedAuthorizedSelectionUtf16Range = targetSelectionUtf16RangeForNativeTextMutation(
117
+ rawSelectionUtf16Range: authorizedSelectionUtf16Range,
118
+ authorizedSelectionUtf16Range: authorizedSelectionUtf16Range,
119
+ replacementStartUtf16: prefix,
120
+ authorizedEndUtf16: authorizedEnd,
121
+ currentEndUtf16: currentEnd + (preservesAcceptedSpace ? 1 : 0),
122
+ currentTextUtf16Length: current.length + (preservesAcceptedSpace ? 1 : 0)
123
+ )
124
+ let authorizedReplacementUtf16Range = NSRange(
125
+ location: prefix,
126
+ length: authorizedEnd - prefix
127
+ )
128
+ let selectedScalarRange = targetSelectionUtf16Range.map { range in
129
+ scalarRange(
130
+ forUtf16Range: range,
131
+ in: authorizedStorageApplying(
132
+ replacementText,
133
+ inUtf16Range: authorizedReplacementUtf16Range
134
+ )
135
+ )
136
+ }
137
+ let preservesAuthorizedSelectionDirection = lastAuthorizedSelectionIsBackward
138
+ && targetSelectionUtf16Range.map { targetSelection in
139
+ mappedAuthorizedSelectionUtf16Range.map {
140
+ NSEqualRanges(targetSelection, $0)
141
+ } ?? false
142
+ } == true
143
+ let capturedAfterBlur = canAdoptNativeTextMutationAfterBlur()
144
+
145
+ return NativeTextMutation(
146
+ from: PositionBridge.utf16OffsetToScalar(prefix, in: lastAuthorizedAttributedTextStorage),
147
+ to: PositionBridge.utf16OffsetToScalar(authorizedEnd, in: lastAuthorizedAttributedTextStorage),
148
+ authorizedReplacementUtf16Range: authorizedReplacementUtf16Range,
149
+ replacementText: replacementText,
150
+ resultingText: currentText,
151
+ authorizedText: authorizedText,
152
+ selectionAnchor: preservesAuthorizedSelectionDirection
153
+ ? selectedScalarRange?.to
154
+ : selectedScalarRange?.from,
155
+ selectionHead: preservesAuthorizedSelectionDirection
156
+ ? selectedScalarRange?.from
157
+ : selectedScalarRange?.to,
158
+ authorizedSelectionUtf16Range: authorizedSelectionUtf16Range,
159
+ rawSelectionUtf16Range: rawSelectionUtf16Range,
160
+ acceptedSpaceCaretUtf16Offset: preservesAcceptedSpace ? currentEnd : nil,
161
+ selectionRevision: selectionRevision,
162
+ capturedWhileFirstResponder: isFirstResponder || capturedAfterBlur,
163
+ capturedWhileEditable: isEditable,
164
+ capturedAfterBlur: capturedAfterBlur,
165
+ inputGeneration: nativeTextMutationGeneration
166
+ )
167
+ }
168
+
169
+ func shouldPreserveAcceptedAutocorrectSpace(
170
+ authorizedText: NSString,
171
+ replacementStartUtf16: Int,
172
+ authorizedEndUtf16: Int,
173
+ replacementText: String,
174
+ rawSelectionUtf16Range: NSRange?,
175
+ authorizedSelectionUtf16Range: NSRange?,
176
+ acceptedCaretUtf16Offset: Int
177
+ ) -> Bool {
178
+ guard replacementStartUtf16 >= 0,
179
+ authorizedEndUtf16 > replacementStartUtf16,
180
+ authorizedEndUtf16 <= authorizedText.length,
181
+ authorizedText.character(at: authorizedEndUtf16 - 1) == 0x20,
182
+ !replacementText.isEmpty,
183
+ let replacementLastCharacter = replacementText.last,
184
+ replacementLastCharacter.isLetter || replacementLastCharacter.isNumber,
185
+ let rawSelectionUtf16Range,
186
+ rawSelectionUtf16Range.length == 0,
187
+ rawSelectionUtf16Range.location == acceptedCaretUtf16Offset,
188
+ let authorizedSelectionUtf16Range,
189
+ authorizedSelectionUtf16Range.length == 0,
190
+ authorizedSelectionUtf16Range.location == authorizedEndUtf16
191
+ else {
192
+ return false
193
+ }
194
+
195
+ let correctedText = authorizedText.substring(
196
+ with: NSRange(
197
+ location: replacementStartUtf16,
198
+ length: authorizedEndUtf16 - replacementStartUtf16 - 1
199
+ )
200
+ )
201
+ guard !correctedText.isEmpty,
202
+ correctedText != replacementText,
203
+ let correctedLastCharacter = correctedText.last
204
+ else {
205
+ return false
206
+ }
207
+ return correctedLastCharacter.isLetter || correctedLastCharacter.isNumber
208
+ }
209
+
210
+ func nativeTextMutationWithCurrentSelection(
211
+ _ mutation: NativeTextMutation
212
+ ) -> NativeTextMutation {
213
+ let currentSelectionUtf16Range = selectedUtf16Range()
214
+ let didSelectionChangeAfterCapture = selectionRevision != mutation.selectionRevision
215
+ let didCurrentRangeMoveAfterCapture: Bool
216
+ if let currentSelectionUtf16Range,
217
+ let rawSelectionUtf16Range = mutation.rawSelectionUtf16Range {
218
+ didCurrentRangeMoveAfterCapture = !NSEqualRanges(
219
+ currentSelectionUtf16Range,
220
+ rawSelectionUtf16Range
221
+ )
222
+ } else {
223
+ didCurrentRangeMoveAfterCapture = false
224
+ }
225
+ let currentSelectionDiffersFromAuthorized: Bool
226
+ if let currentSelectionUtf16Range,
227
+ let authorizedSelectionUtf16Range = mutation.authorizedSelectionUtf16Range {
228
+ currentSelectionDiffersFromAuthorized = !NSEqualRanges(
229
+ currentSelectionUtf16Range,
230
+ authorizedSelectionUtf16Range
231
+ )
232
+ } else {
233
+ currentSelectionDiffersFromAuthorized = currentSelectionUtf16Range != nil
234
+ }
235
+ let repeatsCapturedTransientBeginningSelection: Bool
236
+ if let currentSelectionUtf16Range,
237
+ let rawSelectionUtf16Range = mutation.rawSelectionUtf16Range,
238
+ let authorizedSelectionUtf16Range = mutation.authorizedSelectionUtf16Range,
239
+ NSEqualRanges(currentSelectionUtf16Range, rawSelectionUtf16Range) {
240
+ repeatsCapturedTransientBeginningSelection =
241
+ isTransientBeginningSelectionDuringNativeReplacement(
242
+ currentSelectionUtf16Range,
243
+ authorizedSelection: authorizedSelectionUtf16Range,
244
+ replacementStartUtf16: mutation.authorizedReplacementUtf16Range.location,
245
+ authorizedEndUtf16: NSMaxRange(mutation.authorizedReplacementUtf16Range),
246
+ currentEndUtf16: mutation.authorizedReplacementUtf16Range.location
247
+ + mutation.replacementText.utf16.count
248
+ )
249
+ } else {
250
+ repeatsCapturedTransientBeginningSelection = false
251
+ }
252
+ let shouldUseCurrentSelection = currentSelectionUtf16Range != nil
253
+ && !repeatsCapturedTransientBeginningSelection
254
+ && (
255
+ (didSelectionChangeAfterCapture && currentSelectionDiffersFromAuthorized)
256
+ || didCurrentRangeMoveAfterCapture
257
+ || mutation.rawSelectionUtf16Range == nil
258
+ )
259
+ // Same ruler as the capture path: the live view has lost the
260
+ // structural attributes wherever the keyboard replaced a run, so a
261
+ // caret converted against it maps as though the block were never
262
+ // wrapped.
263
+ let selectionConversionStorage = authorizedStorageApplying(
264
+ mutation.replacementText,
265
+ inUtf16Range: mutation.authorizedReplacementUtf16Range
266
+ )
267
+ let selectionRangeForConversion: NSRange?
268
+ if let currentSelectionUtf16Range,
269
+ currentSelectionUtf16Range.length == 0,
270
+ currentSelectionUtf16Range.location == mutation.acceptedSpaceCaretUtf16Offset {
271
+ selectionRangeForConversion = NSRange(
272
+ location: currentSelectionUtf16Range.location + 1,
273
+ length: 0
274
+ )
275
+ } else {
276
+ selectionRangeForConversion = currentSelectionUtf16Range
277
+ }
278
+ let selectedScalarRange = shouldUseCurrentSelection
279
+ ? selectionRangeForConversion.map {
280
+ scalarRange(forUtf16Range: $0, in: selectionConversionStorage)
281
+ }
282
+ : nil
283
+ let preservesCapturedSelectionDirection = selectedScalarRange.map { selectedRange in
284
+ guard let anchor = mutation.selectionAnchor,
285
+ let head = mutation.selectionHead,
286
+ anchor > head
287
+ else {
288
+ return false
289
+ }
290
+ return selectedRange.from == head && selectedRange.to == anchor
291
+ } ?? false
292
+ return NativeTextMutation(
293
+ from: mutation.from,
294
+ to: mutation.to,
295
+ authorizedReplacementUtf16Range: mutation.authorizedReplacementUtf16Range,
296
+ replacementText: mutation.replacementText,
297
+ resultingText: mutation.resultingText,
298
+ authorizedText: mutation.authorizedText,
299
+ selectionAnchor: preservesCapturedSelectionDirection
300
+ ? selectedScalarRange?.to
301
+ : selectedScalarRange?.from ?? mutation.selectionAnchor,
302
+ selectionHead: preservesCapturedSelectionDirection
303
+ ? selectedScalarRange?.from
304
+ : selectedScalarRange?.to ?? mutation.selectionHead,
305
+ authorizedSelectionUtf16Range: mutation.authorizedSelectionUtf16Range,
306
+ rawSelectionUtf16Range: shouldUseCurrentSelection
307
+ ? currentSelectionUtf16Range
308
+ : mutation.rawSelectionUtf16Range,
309
+ acceptedSpaceCaretUtf16Offset: mutation.acceptedSpaceCaretUtf16Offset,
310
+ selectionRevision: shouldUseCurrentSelection
311
+ ? selectionRevision
312
+ : mutation.selectionRevision,
313
+ capturedWhileFirstResponder: mutation.capturedWhileFirstResponder,
314
+ capturedWhileEditable: mutation.capturedWhileEditable,
315
+ capturedAfterBlur: mutation.capturedAfterBlur,
316
+ inputGeneration: mutation.inputGeneration
317
+ )
318
+ }
319
+
320
+ private func targetSelectionUtf16RangeForNativeTextMutation(
321
+ rawSelectionUtf16Range: NSRange?,
322
+ authorizedSelectionUtf16Range: NSRange?,
323
+ replacementStartUtf16: Int,
324
+ authorizedEndUtf16: Int,
325
+ currentEndUtf16: Int,
326
+ currentTextUtf16Length: Int
327
+ ) -> NSRange? {
328
+ guard let authorizedSelection = authorizedSelectionUtf16Range else {
329
+ return clampedUtf16Range(rawSelectionUtf16Range, length: currentTextUtf16Length)
330
+ }
331
+ guard authorizedSelection.location != NSNotFound else {
332
+ return clampedUtf16Range(rawSelectionUtf16Range, length: currentTextUtf16Length)
333
+ }
334
+
335
+ if let rawSelection = rawSelectionUtf16Range,
336
+ rawSelection.location != NSNotFound,
337
+ !isTransientBeginningSelectionDuringNativeReplacement(
338
+ rawSelection,
339
+ authorizedSelection: authorizedSelection,
340
+ replacementStartUtf16: replacementStartUtf16,
341
+ authorizedEndUtf16: authorizedEndUtf16,
342
+ currentEndUtf16: currentEndUtf16
343
+ ),
344
+ !NSEqualRanges(rawSelection, authorizedSelection) {
345
+ return clampedUtf16Range(rawSelection, length: currentTextUtf16Length)
346
+ }
347
+
348
+ if authorizedSelection.length == 0 {
349
+ let mappedOffset = mapCollapsedAuthorizedSelectionOffsetThroughNativeTextMutation(
350
+ authorizedSelection.location,
351
+ replacementStartUtf16: replacementStartUtf16,
352
+ authorizedEndUtf16: authorizedEndUtf16,
353
+ currentEndUtf16: currentEndUtf16
354
+ )
355
+ let clampedOffset = min(max(mappedOffset, 0), currentTextUtf16Length)
356
+ return NSRange(location: clampedOffset, length: 0)
357
+ }
358
+
359
+ let mappedStart = mapAuthorizedSelectionOffsetThroughNativeTextMutation(
360
+ authorizedSelection.location,
361
+ replacementStartUtf16: replacementStartUtf16,
362
+ authorizedEndUtf16: authorizedEndUtf16,
363
+ currentEndUtf16: currentEndUtf16,
364
+ isRangeStart: true
365
+ )
366
+ let mappedEnd = mapAuthorizedSelectionOffsetThroughNativeTextMutation(
367
+ NSMaxRange(authorizedSelection),
368
+ replacementStartUtf16: replacementStartUtf16,
369
+ authorizedEndUtf16: authorizedEndUtf16,
370
+ currentEndUtf16: currentEndUtf16,
371
+ isRangeStart: false
372
+ )
373
+ let start = min(mappedStart, mappedEnd)
374
+ let end = max(mappedStart, mappedEnd)
375
+ let clampedStart = min(max(start, 0), currentTextUtf16Length)
376
+ let clampedEnd = min(max(end, 0), currentTextUtf16Length)
377
+ return NSRange(location: clampedStart, length: max(0, clampedEnd - clampedStart))
378
+ }
379
+
380
+ private func isTransientBeginningSelectionDuringNativeReplacement(
381
+ _ rawSelection: NSRange,
382
+ authorizedSelection: NSRange,
383
+ replacementStartUtf16: Int,
384
+ authorizedEndUtf16: Int,
385
+ currentEndUtf16: Int
386
+ ) -> Bool {
387
+ rawSelection.location == 0
388
+ && rawSelection.length == 0
389
+ && authorizedSelection.location > 0
390
+ && authorizedSelection.length == 0
391
+ && authorizedEndUtf16 > replacementStartUtf16
392
+ && currentEndUtf16 > replacementStartUtf16
393
+ }
394
+
395
+ private func clampedUtf16Range(_ range: NSRange?, length: Int) -> NSRange? {
396
+ guard let range, range.location != NSNotFound else { return nil }
397
+ let start = min(max(range.location, 0), length)
398
+ let end = min(max(NSMaxRange(range), 0), length)
399
+ return NSRange(location: min(start, end), length: abs(end - start))
400
+ }
401
+
402
+ private func mapCollapsedAuthorizedSelectionOffsetThroughNativeTextMutation(
403
+ _ offset: Int,
404
+ replacementStartUtf16: Int,
405
+ authorizedEndUtf16: Int,
406
+ currentEndUtf16: Int
407
+ ) -> Int {
408
+ // UIKit can leave a stale caret at the insertion point during autocomplete.
409
+ // A collapsed authorized caret should stay collapsed after the inserted text.
410
+ if replacementStartUtf16 == authorizedEndUtf16,
411
+ offset == replacementStartUtf16,
412
+ currentEndUtf16 > replacementStartUtf16 {
413
+ return currentEndUtf16
414
+ }
415
+ if offset <= replacementStartUtf16 {
416
+ return offset
417
+ }
418
+ if offset < authorizedEndUtf16 {
419
+ return currentEndUtf16
420
+ }
421
+ return offset + currentEndUtf16 - authorizedEndUtf16
422
+ }
423
+
424
+ private func mapAuthorizedSelectionOffsetThroughNativeTextMutation(
425
+ _ offset: Int,
426
+ replacementStartUtf16: Int,
427
+ authorizedEndUtf16: Int,
428
+ currentEndUtf16: Int,
429
+ isRangeStart: Bool
430
+ ) -> Int {
431
+ if offset <= replacementStartUtf16 {
432
+ return offset
433
+ }
434
+ if offset >= authorizedEndUtf16 {
435
+ return offset + currentEndUtf16 - authorizedEndUtf16
436
+ }
437
+ return isRangeStart ? replacementStartUtf16 : currentEndUtf16
438
+ }
439
+
440
+ func isUtf16ScalarBoundary(_ offset: Int, in text: String) -> Bool {
441
+ guard offset >= 0, offset <= text.utf16.count else { return false }
442
+ let utf16Index = text.utf16.index(text.utf16.startIndex, offsetBy: offset)
443
+ return String.Index(utf16Index, within: text) != nil
444
+ }
445
+
446
+ private func utf16ScalarBoundary(atOrBefore offset: Int, in text: String) -> Int {
447
+ var candidate = min(max(offset, 0), text.utf16.count)
448
+ while candidate > 0, !isUtf16ScalarBoundary(candidate, in: text) {
449
+ candidate -= 1
450
+ }
451
+ return candidate
452
+ }
453
+
454
+ private func utf16ScalarBoundary(atOrAfter offset: Int, in text: String) -> Int {
455
+ var candidate = min(max(offset, 0), text.utf16.count)
456
+ while candidate < text.utf16.count, !isUtf16ScalarBoundary(candidate, in: text) {
457
+ candidate += 1
458
+ }
459
+ return candidate
460
+ }
461
+
462
+ func sharedUtf16ScalarBoundary(atOrBefore offset: Int, in lhs: String, and rhs: String) -> Int {
463
+ var candidate = min(max(offset, 0), lhs.utf16.count, rhs.utf16.count)
464
+ while candidate > 0,
465
+ !isUtf16ScalarBoundary(candidate, in: lhs) || !isUtf16ScalarBoundary(candidate, in: rhs) {
466
+ candidate -= 1
467
+ }
468
+ return candidate
469
+ }
470
+
471
+ }
@@ -0,0 +1,97 @@
1
+ import UIKit
2
+
3
+ // MARK: - EditorTextView + NSTextStorageDelegate (Reconciliation Fallback)
4
+
5
+ extension EditorTextView: NSTextStorageDelegate {
6
+
7
+ /// Detect unauthorized text storage mutations after UIKit finishes
8
+ /// processing an editing operation. If the text storage diverges from
9
+ /// the last Rust-authorized content and the change was NOT initiated by
10
+ /// our Rust apply path, re-render from Rust ("Rust wins").
11
+ func textStorage(
12
+ _ textStorage: NSTextStorage,
13
+ didProcessEditing editedMask: NSTextStorage.EditActions,
14
+ range editedRange: NSRange,
15
+ changeInLength delta: Int
16
+ ) {
17
+ guard editedMask.contains(.editedCharacters) else { return }
18
+ // Skip if this change came from our own Rust apply path, transient IME
19
+ // composition, or an inline prediction. iOS inline predictions (iOS 17+)
20
+ // mutate textStorage directly and set markedTextRange without calling
21
+ // setMarkedText, so isComposing remains false — check markedTextRange too.
22
+ guard !isApplyingRustState, !isComposing, markedTextRange == nil else { return }
23
+
24
+ if case let .awaitingUIKitCleanup(_, _, cleanupRanges) = localTextDragState,
25
+ delta < 0,
26
+ cleanupRanges.contains(where: {
27
+ $0.location == editedRange.location && $0.length == -delta
28
+ }) {
29
+ pendingNativeTextMutation = nil
30
+ nativeTextMutationCommitScheduled = false
31
+ restoreAfterLocalTextDragCleanup()
32
+ return
33
+ }
34
+
35
+ guard editorId != 0 else { return }
36
+
37
+ PositionBridge.invalidateCache(for: self)
38
+
39
+ let currentText = textStorage.string
40
+ guard currentText != lastAuthorizedText else { return }
41
+ currentTopLevelChildMetadata = nil
42
+
43
+ let allowAfterBlur = canAdoptNativeTextMutationAfterBlur()
44
+ if let mutation = nativeTextMutationFromAuthorizedDiff(currentText: currentText),
45
+ isInterceptingInput
46
+ || shouldAdoptNativeTextStorageMutation(
47
+ mutation,
48
+ allowAfterBlur: allowAfterBlur
49
+ ) {
50
+ scheduleNativeTextMutationCommit(mutation)
51
+ return
52
+ }
53
+
54
+ let authorizedPreview = preview(lastAuthorizedText)
55
+ let storagePreview = preview(currentText)
56
+
57
+ reconciliationCount += 1
58
+
59
+ Self.reconciliationLog.warning(
60
+ """
61
+ [NativeEditor:reconciliation] Text storage diverged from Rust state \
62
+ (count: \(self.reconciliationCount), \
63
+ delta: \(delta), \
64
+ editedRange: \(editedRange.location)..<\(editedRange.location + editedRange.length), \
65
+ authorizedLen: \(self.lastAuthorizedText.count), \
66
+ storageLen: \(currentText.count), \
67
+ selection: \(self.selectionSummary(), privacy: .public), \
68
+ interceptedDepth: \(self.interceptedInputDepth), \
69
+ composing: \(self.isComposing), \
70
+ authorizedPreview: \(authorizedPreview, privacy: .public), \
71
+ storagePreview: \(storagePreview, privacy: .public))
72
+ """
73
+ )
74
+
75
+ scheduleReconciliationFromRust()
76
+ }
77
+
78
+ func scheduleReconciliationFromRust() {
79
+ guard !reconciliationWorkScheduled else { return }
80
+ reconciliationWorkScheduled = true
81
+
82
+ DispatchQueue.main.async { [weak self] in
83
+ guard let self else { return }
84
+ self.reconciliationWorkScheduled = false
85
+
86
+ guard !self.isApplyingRustState, !self.isInterceptingInput, !self.isComposing else { return }
87
+ guard self.editorId != 0 else { return }
88
+ guard self.textStorage.string != self.lastAuthorizedText else { return }
89
+
90
+ // Reconcile by pulling the current editor state without rebuilding
91
+ // the Rust backend or clearing history. This must run after the
92
+ // current NSTextStorage edit transaction has finished.
93
+ let stateJSON = EditorV2Shadow.getCurrentState(id: self.editorId)
94
+ self.applyUpdateJSON(stateJSON)
95
+ }
96
+ }
97
+ }