@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,80 @@
1
+ package com.apollohg.editor.viewer
2
+
3
+ /**
4
+ * Yoga prepares Fabric artifacts before a View exists. Keep its publication
5
+ * sidecar by exact state incarnation so a new semantic identity is cleared before intrinsic
6
+ * fallback lookup, then mount binds the same state without a second reset.
7
+ */
8
+ internal object FabricAttachmentSidecars {
9
+ private val lock = Any()
10
+ private val states = mutableMapOf<FabricGenerationToken, ViewerAttachmentRevisionState>()
11
+ private val measurementState = ThreadLocal<ViewerAttachmentRevisionState>()
12
+
13
+ /** Only preparation's explicitly bound owner may satisfy an LRU miss. */
14
+ val currentMeasurementState: ViewerAttachmentRevisionState?
15
+ get() = measurementState.get()
16
+
17
+ fun beginIfActive(
18
+ generation: FabricGenerationToken,
19
+ semanticIdentity: String,
20
+ isActive: () -> Boolean
21
+ ): ViewerAttachmentRevisionState? = synchronized(lock) {
22
+ if (!isActive()) return@synchronized null
23
+ states.getOrPut(generation, ::ViewerAttachmentRevisionState).also {
24
+ it.beginSemanticGeneration(semanticIdentity)
25
+ }
26
+ }
27
+
28
+ fun begin(
29
+ generation: FabricGenerationToken,
30
+ semanticIdentity: String
31
+ ): ViewerAttachmentRevisionState = beginIfActive(generation, semanticIdentity) { true }
32
+ ?: error("Unconditionally active sidecar unexpectedly rejected.")
33
+
34
+ fun state(generation: FabricGenerationToken): ViewerAttachmentRevisionState? =
35
+ synchronized(lock) {
36
+ states[generation]
37
+ }
38
+
39
+ /** Nestable and exception-safe: Yoga workers may reuse the same thread. */
40
+ fun <T> withMeasurementState(state: ViewerAttachmentRevisionState, body: () -> T): T {
41
+ val previous = measurementState.get()
42
+ measurementState.set(state)
43
+ return try {
44
+ body()
45
+ } finally {
46
+ if (previous == null) measurementState.remove() else measurementState.set(previous)
47
+ }
48
+ }
49
+
50
+ fun remove(generation: FabricGenerationToken) = synchronized(lock) {
51
+ states.remove(generation)?.reset()
52
+ }
53
+
54
+ fun remove(surface: FabricSurfaceToken) = synchronized(lock) {
55
+ states.keys.filter { it.surface == surface }.forEach { states.remove(it)?.reset() }
56
+ }
57
+
58
+ fun removeSurface(surfaceId: Int) = synchronized(lock) {
59
+ states.keys.filter {
60
+ it.surface.surfaceId == surfaceId
61
+ }.forEach { token -> states.remove(token)?.reset() }
62
+ }
63
+
64
+ fun remove(owner: FabricLeaseOwner) = synchronized(lock) {
65
+ states.keys
66
+ .filter { it.surface == owner.surface && it.leaseHandle == owner.leaseHandle }
67
+ .forEach { states.remove(it)?.reset() }
68
+ }
69
+
70
+ /** Commit keeps the incoming generation's in-flight sidecar but drops every stale revision for this family. */
71
+ fun removeOtherGenerations(owner: FabricLeaseOwner, keeping: FabricGenerationToken) =
72
+ synchronized(lock) {
73
+ states.keys
74
+ .filter {
75
+ it.surface == owner.surface && it.leaseHandle == owner.leaseHandle &&
76
+ it != keeping
77
+ }
78
+ .forEach { states.remove(it)?.reset() }
79
+ }
80
+ }
@@ -0,0 +1,59 @@
1
+ package com.apollohg.editor.viewer
2
+
3
+ /** JNI-only handoff; handles never pass through `ReadableMap.getDouble()`. */
4
+ internal object FabricLeaseHandleBridge {
5
+ private val current = ThreadLocal<Long>()
6
+ internal data class FinalLayout(
7
+ val leaseHandle: Long,
8
+ val contentOriginXPx: Int,
9
+ val contentOriginYPx: Int
10
+ )
11
+ private val finalLayout = ThreadLocal<FinalLayout>()
12
+
13
+ @JvmStatic fun beginNativeMeasure(leaseHandle: Long) {
14
+ finalLayout.remove()
15
+ if (leaseHandle > 0) current.set(leaseHandle) else current.remove()
16
+ }
17
+
18
+ @JvmStatic
19
+ fun beginNativeFinalLayout(leaseHandle: Long, contentOriginXPx: Int, contentOriginYPx: Int) {
20
+ if (leaseHandle <= 0) {
21
+ current.remove()
22
+ finalLayout.remove()
23
+ return
24
+ }
25
+ current.set(leaseHandle)
26
+ finalLayout.set(FinalLayout(leaseHandle, contentOriginXPx, contentOriginYPx))
27
+ }
28
+
29
+ @JvmStatic fun endNativeMeasure() {
30
+ current.remove()
31
+ finalLayout.remove()
32
+ }
33
+
34
+ fun currentHandle(): Long = current.get() ?: 0L
35
+
36
+ fun currentFinalLayout(): FinalLayout? = finalLayout.get()
37
+
38
+ /**
39
+ * The C++ state lifecycle registers before its first Yoga pass and invokes
40
+ * the matching release from its final shared-state destructor. These are
41
+ * static calls only: no View, Context, or manager is retained across JNI.
42
+ */
43
+ @JvmStatic fun registerNativeLease(surfaceId: Int, componentTag: Int, leaseHandle: Long) {
44
+ if (surfaceId <= 0 || componentTag <= 0 || leaseHandle <= 0) return
45
+ PreparedProseLayoutRegistry.shared.registerFabricLease(
46
+ FabricSurfaceToken(surfaceId, componentTag),
47
+ leaseHandle
48
+ )
49
+ }
50
+
51
+ /** Invoked only from the C++ state-family's final destructor callback. */
52
+ @JvmStatic fun finalizeNativeLease(surfaceId: Int, componentTag: Int, leaseHandle: Long) {
53
+ if (surfaceId <= 0 || componentTag <= 0 || leaseHandle <= 0) return
54
+ PreparedProseLayoutRegistry.shared.finalizeFabricLease(
55
+ FabricSurfaceToken(surfaceId, componentTag),
56
+ leaseHandle
57
+ )
58
+ }
59
+ }
@@ -0,0 +1,450 @@
1
+ package com.apollohg.editor.viewer
2
+
3
+ import android.graphics.Color
4
+ import android.graphics.Paint
5
+ import android.graphics.Path
6
+ import android.graphics.PathMeasure
7
+ import android.graphics.Rect
8
+ import android.graphics.RectF
9
+ import android.graphics.Typeface
10
+ import android.text.Layout
11
+ import android.text.SpannableString
12
+ import android.text.Spanned
13
+ import android.text.StaticLayout
14
+ import android.text.TextPaint
15
+ import android.text.style.BackgroundColorSpan
16
+ import android.text.style.ForegroundColorSpan
17
+ import android.text.style.LineHeightSpan
18
+ import android.text.style.MetricAffectingSpan
19
+ import android.text.style.ReplacementSpan
20
+ import android.text.style.StrikethroughSpan
21
+ import android.text.style.UnderlineSpan
22
+ import com.apollohg.editor.EditorLinkTheme
23
+ import com.apollohg.editor.EditorMentionTheme
24
+ import com.apollohg.editor.EditorOrderedListMarkerTheme
25
+ import com.apollohg.editor.EditorTextStyle
26
+ import com.apollohg.editor.EditorTheme
27
+ import com.apollohg.editor.OrderedListMarkerFormatter
28
+ import com.apollohg.editor.ProseViewerError
29
+ import java.text.Bidi
30
+ import kotlin.math.abs
31
+ import kotlin.math.ceil
32
+ import kotlin.math.max
33
+ import kotlin.math.min
34
+
35
+ /**
36
+ * StaticLayout can split one visual selection run into edge-touching contours.
37
+ * Android [Rect.right] is exclusive, so only overlapping or edge-touching
38
+ * contours with compatible vertical bounds belong to one hit region.
39
+ */
40
+ internal fun mergeAdjacentSameLineSelectionFragments(fragments: List<Rect>): List<Rect> {
41
+ val ordered = fragments.sortedWith(compareBy<Rect> { it.top }.thenBy { it.left })
42
+ val merged = mutableListOf<Rect>()
43
+ ordered.forEach { fragment ->
44
+ val previous = merged.lastOrNull()
45
+ if (
46
+ previous != null &&
47
+ abs(previous.top - fragment.top) <= SELECTION_FRAGMENT_PIXEL_TOLERANCE_PX &&
48
+ abs(previous.bottom - fragment.bottom) <= SELECTION_FRAGMENT_PIXEL_TOLERANCE_PX &&
49
+ fragment.left <= previous.right
50
+ ) {
51
+ merged[merged.lastIndex] = Rect(
52
+ min(previous.left, fragment.left),
53
+ min(previous.top, fragment.top),
54
+ max(previous.right, fragment.right),
55
+ max(previous.bottom, fragment.bottom)
56
+ )
57
+ } else {
58
+ merged += Rect(fragment)
59
+ }
60
+ }
61
+ return merged
62
+ }
63
+
64
+ private const val SELECTION_FRAGMENT_PIXEL_TOLERANCE_PX = 1
65
+
66
+ internal enum class FallbackVisualEdge { LEFT, RIGHT }
67
+
68
+ /**
69
+ * Java [Bidi]'s run accessors are indexed in logical order. Keep that source
70
+ * identity immutable, then explicitly project it into visual order before any
71
+ * geometry asks about neighbours or line-edge ownership.
72
+ */
73
+ internal data class FallbackLogicalBidiRun(
74
+ val logicalIndex: Int,
75
+ val documentStart: Int,
76
+ val documentEnd: Int,
77
+ val level: Byte
78
+ ) {
79
+ val isRtl: Boolean get() = (level.toInt() and 1) == 1
80
+ }
81
+
82
+ internal data class FallbackVisualBidiRun(
83
+ val visualIndex: Int,
84
+ val logicalRun: FallbackLogicalBidiRun
85
+ ) {
86
+ val documentStart: Int get() = logicalRun.documentStart
87
+ val documentEnd: Int get() = logicalRun.documentEnd
88
+ val isRtl: Boolean get() = logicalRun.isRtl
89
+
90
+ fun offsetAt(edge: FallbackVisualEdge): Int = when (edge) {
91
+ FallbackVisualEdge.LEFT -> if (isRtl) documentEnd else documentStart
92
+ FallbackVisualEdge.RIGHT -> if (isRtl) documentStart else documentEnd
93
+ }
94
+
95
+ fun edgeForLogicalEnd(): FallbackVisualEdge =
96
+ if (isRtl) FallbackVisualEdge.LEFT else FallbackVisualEdge.RIGHT
97
+ }
98
+
99
+ /**
100
+ * [Bidi.getRunStart], [Bidi.getRunLimit], and [Bidi.getRunLevel] take a
101
+ * logical run index. [Bidi.reorderVisually] is the public Unicode Bidi API
102
+ * that turns those immutable logical records into left-to-right visual order.
103
+ */
104
+ internal fun visualBidiRuns(
105
+ logicalRuns: List<FallbackLogicalBidiRun>
106
+ ): List<FallbackVisualBidiRun> {
107
+ if (logicalRuns.isEmpty()) return emptyList()
108
+
109
+ val levels = ByteArray(logicalRuns.size) { logicalRuns[it].level }
110
+ val reordered: Array<Any> = Array(logicalRuns.size) { logicalRuns[it] }
111
+ Bidi.reorderVisually(levels, 0, reordered, 0, reordered.size)
112
+ return reordered.mapIndexed { visualIndex, value ->
113
+ FallbackVisualBidiRun(visualIndex, value as FallbackLogicalBidiRun)
114
+ }
115
+ }
116
+
117
+ private fun fallbackHorizontalAtVisualEdge(
118
+ layout: StaticLayout,
119
+ offset: Int,
120
+ edge: FallbackVisualEdge
121
+ ): Float {
122
+ val primary = layout.getPrimaryHorizontal(offset)
123
+ val secondary = layout.getSecondaryHorizontal(offset)
124
+ return if (edge ==
125
+ FallbackVisualEdge.RIGHT
126
+ ) {
127
+ max(primary, secondary)
128
+ } else {
129
+ min(primary, secondary)
130
+ }
131
+ }
132
+
133
+ /**
134
+ * The logical side of a cursor position. This mirrors Layout's internal
135
+ * `getHorizontal(offset, trailing, ...)` calls: a selection starts at the
136
+ * leading edge of its next logical character and ends at the trailing edge of
137
+ * its previous logical character. It is deliberately not a visual left/right
138
+ * concept.
139
+ */
140
+ internal enum class FallbackLogicalCaretAffinity { LEADING_NEXT, TRAILING_PREVIOUS }
141
+
142
+ internal fun FallbackVisualBidiRun.affinityAt(
143
+ edge: FallbackVisualEdge
144
+ ): FallbackLogicalCaretAffinity = if (offsetAt(edge) == documentStart) {
145
+ FallbackLogicalCaretAffinity.LEADING_NEXT
146
+ } else {
147
+ FallbackLogicalCaretAffinity.TRAILING_PREVIOUS
148
+ }
149
+
150
+ /**
151
+ * Mirrors Layout's primary-caret decision from the adjacent logical embedding
152
+ * levels. At a directional boundary the same offset has two valid positions;
153
+ * which one is primary is determined by the transition, not by the current
154
+ * run's direction or by the paragraph's base direction alone.
155
+ */
156
+ internal fun primaryIsTrailingPrevious(offset: Int, geometry: FallbackLineGeometry): Boolean {
157
+ val paragraphLevel = if (geometry.paragraphDirection == Layout.DIR_RIGHT_TO_LEFT) 1 else 0
158
+ val current = geometry.logicalRuns.firstOrNull {
159
+ offset in it.documentStart until it.documentEnd
160
+ }
161
+ // Inside a logical run the public primary cursor is the leading-next
162
+ // position. Only a run boundary needs the preceding-level comparison.
163
+ if (current != null && offset > current.documentStart) return false
164
+
165
+ val levelAt = current?.level?.toInt() ?: paragraphLevel
166
+ val levelBefore = when {
167
+ offset == geometry.lineStart -> paragraphLevel
168
+
169
+ else -> geometry.logicalRuns.firstOrNull {
170
+ offset - 1 in it.documentStart until it.documentEnd
171
+ }?.level?.toInt() ?: paragraphLevel
172
+ }
173
+ return levelBefore < levelAt
174
+ }
175
+
176
+ /** Resolves one public horizontal API result using Layout-equivalent affinity. */
177
+ internal fun fallbackHorizontalForLogicalCaret(
178
+ geometry: FallbackLineGeometry,
179
+ offset: Int,
180
+ affinity: FallbackLogicalCaretAffinity
181
+ ): Float {
182
+ val desiredTrailing = affinity == FallbackLogicalCaretAffinity.TRAILING_PREVIOUS
183
+ return if (desiredTrailing == primaryIsTrailingPrevious(offset, geometry)) {
184
+ geometry.primaryHorizontal(offset)
185
+ } else {
186
+ geometry.secondaryHorizontal(offset)
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Emulates Layout's private current-line trailing lookup at a soft-wrap end.
192
+ * The public horizontal APIs resolve that shared offset as the next line's
193
+ * start, so an internal terminal run instead borrows the same visual boundary
194
+ * from its adjacent run. Only a run which owns the outer visual edge may use
195
+ * the current line's left/right extent.
196
+ */
197
+ private fun softWrapTerminalBoundary(
198
+ terminalRun: FallbackVisualBidiRun,
199
+ visualRuns: List<FallbackVisualBidiRun>,
200
+ softWrapLineEnd: Int,
201
+ outerLineBoundary: (FallbackVisualEdge) -> Float,
202
+ logicalCaretHorizontal: (offset: Int, affinity: FallbackLogicalCaretAffinity) -> Float
203
+ ): Float? {
204
+ val terminalEdge = terminalRun.edgeForLogicalEnd()
205
+ val isOuter = when (terminalEdge) {
206
+ FallbackVisualEdge.LEFT -> terminalRun.visualIndex == 0
207
+ FallbackVisualEdge.RIGHT -> terminalRun.visualIndex == visualRuns.lastIndex
208
+ }
209
+ if (isOuter) {
210
+ return outerLineBoundary(terminalEdge)
211
+ }
212
+
213
+ val neighbor = when (terminalEdge) {
214
+ FallbackVisualEdge.LEFT -> visualRuns.getOrNull(terminalRun.visualIndex - 1)
215
+ FallbackVisualEdge.RIGHT -> visualRuns.getOrNull(terminalRun.visualIndex + 1)
216
+ } ?: return null
217
+ val neighborEdge = if (terminalEdge == FallbackVisualEdge.LEFT) {
218
+ FallbackVisualEdge.RIGHT
219
+ } else {
220
+ FallbackVisualEdge.LEFT
221
+ }
222
+ val neighborOffset = neighbor.offsetAt(neighborEdge)
223
+ // A distinct visual run cannot own the terminal line-end offset. Refuse a
224
+ // malformed/unexpected Bidi result rather than resolving that offset on
225
+ // the next line and expanding this hit rectangle across adjacent content.
226
+ if (neighborOffset == softWrapLineEnd) return null
227
+ return logicalCaretHorizontal(neighborOffset, neighbor.affinityAt(neighborEdge))
228
+ }
229
+
230
+ /**
231
+ * Test support for direct visual-edge fixtures. Production selection uses
232
+ * [fallbackSelectionRectsForLine], which resolves both endpoints by logical
233
+ * caret affinity instead of collapsing them to physical left/right extremes.
234
+ */
235
+ internal fun fallbackSelectionRectForVisualRun(
236
+ layout: StaticLayout,
237
+ runStart: Int,
238
+ runEnd: Int,
239
+ runIsRtl: Boolean,
240
+ line: Int,
241
+ width: Int,
242
+ softWrapLineEnd: Int? = null,
243
+ softWrapTerminalBoundary: Float? = null
244
+ ): Rect? {
245
+ if (runStart >= runEnd) return null
246
+
247
+ fun visualBoundary(offset: Int, logicalRunStart: Boolean): Float {
248
+ val visualRightEdge = if (runIsRtl) logicalRunStart else !logicalRunStart
249
+ // A soft-wrap terminal offset is also the following line's start.
250
+ // Layout's horizontal lookup therefore resolves it on that following
251
+ // line. The current line's matching visual extreme is the exact
252
+ // trailing boundary for this Bidi run. Keep ordinary primary/secondary
253
+ // affinity lookup for a current-line start and for the final document
254
+ // boundary, neither of which has this ambiguous line ownership.
255
+ if (!logicalRunStart && offset == softWrapLineEnd) {
256
+ softWrapTerminalBoundary?.let { return it }
257
+ return if (visualRightEdge) layout.getLineRight(line) else layout.getLineLeft(line)
258
+ }
259
+ return fallbackHorizontalAtVisualEdge(
260
+ layout,
261
+ offset,
262
+ if (visualRightEdge) FallbackVisualEdge.RIGHT else FallbackVisualEdge.LEFT
263
+ )
264
+ }
265
+
266
+ val start = visualBoundary(runStart, logicalRunStart = true)
267
+ val end = visualBoundary(runEnd, logicalRunStart = false)
268
+ val left = kotlin.math.floor(min(start, end)).toInt().coerceIn(0, width)
269
+ val right = ceil(max(start, end)).toInt().coerceIn(0, width)
270
+ return Rect(left, layout.getLineTop(line), right, layout.getLineBottom(line)).takeIf {
271
+ !it.isEmpty
272
+ }
273
+ }
274
+
275
+ /**
276
+ * The line-level input required by the Bidi fallback. Keeping it separate
277
+ * from [StaticLayout] makes the cursor-affinity algorithm deterministic while
278
+ * leaving layout extraction at the production adapter boundary.
279
+ */
280
+ internal data class FallbackLineGeometry(
281
+ val text: CharSequence,
282
+ val lineStart: Int,
283
+ val rawLineEnd: Int,
284
+ val nextLineStart: Int?,
285
+ val paragraphDirection: Int,
286
+ val top: Int,
287
+ val bottom: Int,
288
+ val width: Int,
289
+ /** Full drawable-line runs in logical order, including embedding levels. */
290
+ val logicalRuns: List<FallbackLogicalBidiRun>,
291
+ val outerLineBoundary: (FallbackVisualEdge) -> Float,
292
+ val primaryHorizontal: (Int) -> Float,
293
+ val secondaryHorizontal: (Int) -> Float
294
+ )
295
+
296
+ /**
297
+ * Derives fallback selection geometry from one already-resolved visual line.
298
+ *
299
+ * The [StaticLayout] adapter below supplies this geometry in production. The
300
+ * algorithm intentionally owns the soft-wrap, selection-intersection, Bidi
301
+ * ordering, and terminal-neighbour checks so those invariants do not depend
302
+ * on host text shaping.
303
+ */
304
+ internal fun fallbackSelectionRectsForGeometry(
305
+ geometry: FallbackLineGeometry,
306
+ start: Int,
307
+ end: Int
308
+ ): List<Rect> {
309
+ val lineStart = geometry.lineStart
310
+ val rawLineEnd = geometry.rawLineEnd
311
+ // A hard-break line includes its terminator in StaticLayout's end offset.
312
+ // It has no drawable/cursor run, so exclude it before constructing Bidi.
313
+ val lineEnd = if (
314
+ rawLineEnd > lineStart &&
315
+ rawLineEnd <= geometry.text.length &&
316
+ geometry.text[rawLineEnd - 1] == '\n'
317
+ ) {
318
+ rawLineEnd - 1
319
+ } else {
320
+ rawLineEnd
321
+ }
322
+ val softWrapLineEnd = rawLineEnd.takeIf {
323
+ lineEnd == rawLineEnd &&
324
+ rawLineEnd < geometry.text.length &&
325
+ geometry.nextLineStart == rawLineEnd
326
+ }
327
+ val selectedStart = maxOf(start, lineStart).coerceAtMost(lineEnd)
328
+ val selectedEnd = minOf(end, lineEnd).coerceAtLeast(lineStart)
329
+ if (selectedStart >= selectedEnd || lineStart >= lineEnd) return emptyList()
330
+
331
+ val visualRuns = visualBidiRuns(geometry.logicalRuns)
332
+ val fragments = mutableListOf<Rect>()
333
+ for (visualRun in visualRuns) {
334
+ val intersectedStart = maxOf(selectedStart, visualRun.documentStart)
335
+ val intersectedEnd = minOf(selectedEnd, visualRun.documentEnd)
336
+ val resolvesSoftWrapTerminal = softWrapLineEnd != null &&
337
+ visualRun.documentEnd == softWrapLineEnd &&
338
+ intersectedEnd == softWrapLineEnd
339
+ val terminalBoundary = if (resolvesSoftWrapTerminal) {
340
+ softWrapTerminalBoundary(
341
+ terminalRun = visualRun,
342
+ visualRuns = visualRuns,
343
+ softWrapLineEnd = softWrapLineEnd!!,
344
+ outerLineBoundary = geometry.outerLineBoundary,
345
+ logicalCaretHorizontal = { offset, affinity ->
346
+ fallbackHorizontalForLogicalCaret(geometry, offset, affinity)
347
+ }
348
+ )
349
+ } else {
350
+ null
351
+ }
352
+ // Do not allow an internal terminal boundary to fall through to the
353
+ // generic whole-line shortcut: that would over-expand the rectangle.
354
+ if (resolvesSoftWrapTerminal && terminalBoundary == null) continue
355
+ if (intersectedStart >= intersectedEnd) continue
356
+ fun visualBoundary(offset: Int, logicalRunStart: Boolean): Float {
357
+ val visualRightEdge = if (visualRun.isRtl) logicalRunStart else !logicalRunStart
358
+ val edge = if (visualRightEdge) FallbackVisualEdge.RIGHT else FallbackVisualEdge.LEFT
359
+ if (!logicalRunStart && offset == softWrapLineEnd) {
360
+ return terminalBoundary ?: geometry.outerLineBoundary(edge)
361
+ }
362
+ return fallbackHorizontalForLogicalCaret(
363
+ geometry,
364
+ offset,
365
+ if (logicalRunStart) {
366
+ FallbackLogicalCaretAffinity.LEADING_NEXT
367
+ } else {
368
+ FallbackLogicalCaretAffinity.TRAILING_PREVIOUS
369
+ }
370
+ )
371
+ }
372
+ val startBoundary = visualBoundary(intersectedStart, logicalRunStart = true)
373
+ val endBoundary = visualBoundary(intersectedEnd, logicalRunStart = false)
374
+ Rect(
375
+ kotlin.math.floor(min(startBoundary, endBoundary)).toInt().coerceIn(0, geometry.width),
376
+ geometry.top,
377
+ ceil(max(startBoundary, endBoundary)).toInt().coerceIn(0, geometry.width),
378
+ geometry.bottom
379
+ ).takeIf { !it.isEmpty }?.let(fragments::add)
380
+ }
381
+ return fragments
382
+ }
383
+
384
+ /**
385
+ * Derives fallback selection geometry from the complete [StaticLayout] line.
386
+ *
387
+ * The line's Bidi resolution must use the same paragraph direction as the
388
+ * layout that supplied its cursor positions. Resolving only the selected
389
+ * substring can give neutral characters and embedded runs a different level.
390
+ */
391
+ internal fun fallbackSelectionRectsForLine(
392
+ layout: StaticLayout,
393
+ start: Int,
394
+ end: Int,
395
+ line: Int,
396
+ width: Int
397
+ ): List<Rect> = fallbackSelectionRectsForGeometry(
398
+ FallbackLineGeometry(
399
+ text = layout.text,
400
+ lineStart = layout.getLineStart(line),
401
+ rawLineEnd = layout.getLineEnd(line),
402
+ nextLineStart = if (line + 1 < layout.lineCount) layout.getLineStart(line + 1) else null,
403
+ paragraphDirection = layout.getParagraphDirection(line),
404
+ top = layout.getLineTop(line),
405
+ bottom = layout.getLineBottom(line),
406
+ width = width,
407
+ logicalRuns = fallbackLogicalBidiRunsForLine(layout, line),
408
+ outerLineBoundary = { edge ->
409
+ if (edge ==
410
+ FallbackVisualEdge.LEFT
411
+ ) {
412
+ layout.getLineLeft(line)
413
+ } else {
414
+ layout.getLineRight(line)
415
+ }
416
+ },
417
+ primaryHorizontal = layout::getPrimaryHorizontal,
418
+ secondaryHorizontal = layout::getSecondaryHorizontal
419
+ ),
420
+ start,
421
+ end
422
+ )
423
+
424
+ private fun fallbackLogicalBidiRunsForLine(
425
+ layout: StaticLayout,
426
+ line: Int
427
+ ): List<FallbackLogicalBidiRun> {
428
+ val lineStart = layout.getLineStart(line)
429
+ val rawLineEnd = layout.getLineEnd(line)
430
+ val lineEnd = if (rawLineEnd > lineStart && layout.text[rawLineEnd - 1] == '\n') {
431
+ rawLineEnd - 1
432
+ } else {
433
+ rawLineEnd
434
+ }
435
+ if (lineStart >= lineEnd) return emptyList()
436
+ val direction = if (layout.getParagraphDirection(line) == Layout.DIR_RIGHT_TO_LEFT) {
437
+ Bidi.DIRECTION_RIGHT_TO_LEFT
438
+ } else {
439
+ Bidi.DIRECTION_LEFT_TO_RIGHT
440
+ }
441
+ val bidi = Bidi(layout.text.subSequence(lineStart, lineEnd).toString(), direction)
442
+ return List(bidi.runCount) { logicalIndex ->
443
+ FallbackLogicalBidiRun(
444
+ logicalIndex = logicalIndex,
445
+ documentStart = lineStart + bidi.getRunStart(logicalIndex),
446
+ documentEnd = lineStart + bidi.getRunLimit(logicalIndex),
447
+ level = bidi.getRunLevel(logicalIndex).toByte()
448
+ )
449
+ }
450
+ }