@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,226 @@
1
+ import UIKit
2
+
3
+ enum NativeEditorDestroyReservationResult: Equatable {
4
+ case reserved
5
+ case alreadyInProgress
6
+ case unavailable
7
+ }
8
+
9
+ final class NativeEditorViewRegistry {
10
+ static let shared = NativeEditorViewRegistry()
11
+
12
+ private final class RegisteredView {
13
+ weak var view: NativeEditorExpoView?
14
+ let order: UInt64
15
+
16
+ init(view: NativeEditorExpoView, order: UInt64) {
17
+ self.view = view
18
+ self.order = order
19
+ }
20
+ }
21
+
22
+ private var viewsByEditorId: [UInt64: [RegisteredView]] = [:]
23
+ private var nextRegistrationOrder: UInt64 = 0
24
+ private var activeEditorIds: Set<UInt64> = []
25
+ private var destroyingEditorIds: Set<UInt64> = []
26
+ var onFinalizeDestroyForTesting: ((UInt64) throws -> Void)?
27
+
28
+ private init() {}
29
+
30
+ func markEditorCreated(editorId: UInt64) {
31
+ guard editorId != 0 else { return }
32
+ _ = performOnMain {
33
+ activeEditorIds.insert(editorId)
34
+ }
35
+ }
36
+
37
+ func rebaseAfterRemoteCommit(editorId: UInt64) {
38
+ guard editorId != 0 else { return }
39
+ DispatchQueue.main.async { [weak self] in
40
+ self?.applyRemoteCommitRefresh(editorId: editorId)
41
+ }
42
+ }
43
+
44
+ func applyRemoteCommitRefresh(editorId: UInt64) {
45
+ dispatchPrecondition(condition: .onQueue(.main))
46
+ liveRegisteredViews(editorId: editorId).forEach { $0.view?.applyRemoteCommitRefresh() }
47
+ }
48
+
49
+ func isDestroyed(editorId: UInt64) -> Bool {
50
+ guard editorId != 0 else { return false }
51
+ return performOnMain {
52
+ if destroyingEditorIds.contains(editorId) { return true }
53
+ if activeEditorIds.contains(editorId) {
54
+ return false
55
+ }
56
+ return EditorV2Registry.adapter(forLegacyId: editorId) == nil
57
+ }
58
+ }
59
+
60
+ @discardableResult
61
+ func register(editorId: UInt64, view: NativeEditorExpoView) -> Bool {
62
+ guard editorId != 0 else { return false }
63
+ return performOnMain {
64
+ guard !destroyingEditorIds.contains(editorId) else { return false }
65
+ if !activeEditorIds.contains(editorId) {
66
+ guard EditorV2Registry.adapter(forLegacyId: editorId) != nil else {
67
+ return false
68
+ }
69
+ activeEditorIds.insert(editorId)
70
+ }
71
+ var views = liveRegisteredViews(editorId: editorId)
72
+ guard !views.contains(where: { $0.view === view }) else { return true }
73
+ nextRegistrationOrder &+= 1
74
+ views.append(RegisteredView(view: view, order: nextRegistrationOrder))
75
+ viewsByEditorId[editorId] = views
76
+ return true
77
+ }
78
+ }
79
+
80
+ func unregister(editorId: UInt64, view: NativeEditorExpoView) {
81
+ guard editorId != 0 else { return }
82
+ performOnMain {
83
+ let views = liveRegisteredViews(editorId: editorId).filter { $0.view !== view }
84
+ if views.isEmpty {
85
+ viewsByEditorId.removeValue(forKey: editorId)
86
+ } else {
87
+ viewsByEditorId[editorId] = views
88
+ }
89
+ }
90
+ }
91
+
92
+ func nativeOwnerReleased(editorId: UInt64, by view: NativeEditorExpoView) {
93
+ guard editorId != 0 else { return }
94
+ performOnMain {
95
+ guard !destroyingEditorIds.contains(editorId) else { return }
96
+ let survivor = liveRegisteredViews(editorId: editorId)
97
+ .reversed()
98
+ .compactMap(\.view)
99
+ .first { $0 !== view && $0.window != nil }
100
+ survivor?.claimNativeOwnershipAndCatchUp(editorId: editorId)
101
+ }
102
+ }
103
+
104
+ func invalidateDestroyedEditor(editorId: UInt64) {
105
+ guard reserveDestroy(editorId: editorId) else { return }
106
+ finalizeDestroy(editorId: editorId)
107
+ }
108
+
109
+ /// Install the reversible, in-flight destroy gate before crossing the
110
+ /// FFI boundary. The active view state remains intact until finalization
111
+ /// so a retryable destroy can roll back without reconstructing bindings.
112
+ func acquireDestroyReservation(editorId: UInt64) -> NativeEditorDestroyReservationResult {
113
+ guard editorId != 0 else { return .unavailable }
114
+ return performOnMain {
115
+ guard !destroyingEditorIds.contains(editorId) else { return .alreadyInProgress }
116
+ guard activeEditorIds.contains(editorId)
117
+ || EditorV2Registry.adapter(forLegacyId: editorId) != nil
118
+ else {
119
+ return .unavailable
120
+ }
121
+ destroyingEditorIds.insert(editorId)
122
+ return .reserved
123
+ }
124
+ }
125
+
126
+ @discardableResult
127
+ func reserveDestroy(editorId: UInt64) -> Bool {
128
+ acquireDestroyReservation(editorId: editorId) == .reserved
129
+ }
130
+
131
+ func rollbackDestroy(editorId: UInt64) {
132
+ guard editorId != 0 else { return }
133
+ _ = performOnMain {
134
+ destroyingEditorIds.remove(editorId)
135
+ }
136
+ }
137
+
138
+ func isDestroyReserved(editorId: UInt64) -> Bool {
139
+ guard editorId != 0 else { return false }
140
+ return performOnMain {
141
+ destroyingEditorIds.contains(editorId)
142
+ }
143
+ }
144
+
145
+ func finalizeDestroy(editorId: UInt64) {
146
+ guard editorId != 0 else { return }
147
+ performOnMain {
148
+ guard destroyingEditorIds.contains(editorId) else { return }
149
+ invokeDestroyTestingHook(onFinalizeDestroyForTesting, editorId: editorId)
150
+ activeEditorIds.remove(editorId)
151
+ let views = viewsByEditorId.removeValue(forKey: editorId)?.compactMap(\.view) ?? []
152
+ views.forEach { $0.handleEditorDestroyed(editorId) }
153
+ destroyingEditorIds.remove(editorId)
154
+ }
155
+ }
156
+
157
+ func destroy(editorId: UInt64, operation: () -> Void) {
158
+ guard reserveDestroy(editorId: editorId) else { return }
159
+ operation()
160
+ finalizeDestroy(editorId: editorId)
161
+ }
162
+
163
+ func prepareForCommandJSON(editorId: UInt64) -> String {
164
+ let prepare = { () -> String in
165
+ if self.destroyingEditorIds.contains(editorId) {
166
+ return Self.commandPreparationJSON(ready: false, blockedReason: "destroying")
167
+ }
168
+ if !self.activeEditorIds.contains(editorId),
169
+ EditorV2Registry.adapter(forLegacyId: editorId) == nil {
170
+ return Self.commandPreparationJSON(ready: false, blockedReason: "destroyed")
171
+ }
172
+ let views = self.liveRegisteredViews(editorId: editorId).compactMap(\.view)
173
+ guard let view = views.reversed().first(where: {
174
+ $0.ownsNativeBinding(editorId: editorId)
175
+ }) ?? views.last else {
176
+ self.viewsByEditorId.removeValue(forKey: editorId)
177
+ return Self.commandPreparationJSON(ready: true)
178
+ }
179
+ return view.prepareForEditorCommandJSON()
180
+ }
181
+
182
+ return performOnMain(prepare)
183
+ }
184
+
185
+ private func liveRegisteredViews(editorId: UInt64) -> [RegisteredView] {
186
+ let views = viewsByEditorId[editorId]?.filter { $0.view != nil } ?? []
187
+ if views.isEmpty {
188
+ viewsByEditorId.removeValue(forKey: editorId)
189
+ } else {
190
+ viewsByEditorId[editorId] = views
191
+ }
192
+ return views.sorted { $0.order < $1.order }
193
+ }
194
+
195
+ static func commandPreparationJSON(
196
+ ready: Bool,
197
+ updateJSON: String? = nil,
198
+ blockedReason: String? = nil
199
+ ) -> String {
200
+ var payload: [String: Any] = ["ready": ready]
201
+ if let updateJSON {
202
+ payload["updateJSON"] = updateJSON
203
+ }
204
+ if let blockedReason {
205
+ payload["blockedReason"] = blockedReason
206
+ }
207
+ guard let data = try? JSONSerialization.data(withJSONObject: payload),
208
+ let json = String(data: data, encoding: .utf8)
209
+ else {
210
+ if let blockedReason {
211
+ return ready
212
+ ? "{\"ready\":true,\"blockedReason\":\"\(blockedReason)\"}"
213
+ : "{\"ready\":false,\"blockedReason\":\"\(blockedReason)\"}"
214
+ }
215
+ return ready ? "{\"ready\":true}" : "{\"ready\":false}"
216
+ }
217
+ return json
218
+ }
219
+
220
+ private func performOnMain<T>(_ work: () -> T) -> T {
221
+ if Thread.isMainThread {
222
+ return work()
223
+ }
224
+ return DispatchQueue.main.sync(execute: work)
225
+ }
226
+ }
@@ -0,0 +1,214 @@
1
+ import UIKit
2
+
3
+ extension EditorAccessoryToolbarView {
4
+ func buttonState(
5
+ for item: NativeToolbarItem,
6
+ state: NativeToolbarState
7
+ ) -> (enabled: Bool, active: Bool) {
8
+ switch item.type {
9
+ case .mark:
10
+ let mark = item.mark ?? ""
11
+ return (
12
+ enabled: state.allowedMarks.contains(mark),
13
+ active: state.marks[mark] == true
14
+ )
15
+ case .heading:
16
+ let level = item.headingLevel ?? 0
17
+ let headingType = "h\(level)"
18
+ return (
19
+ enabled: state.commands["toggleHeading\(level)"] == true,
20
+ active: state.nodes[headingType] == true
21
+ )
22
+ case .blockquote:
23
+ return (
24
+ enabled: state.commands["toggleBlockquote"] == true,
25
+ active: state.nodes["blockquote"] == true
26
+ )
27
+ case .list:
28
+ switch item.listType {
29
+ case .bulletList, .legacyBulletList:
30
+ return (
31
+ enabled: state.commands["wrapBulletList"] == true,
32
+ active: state.nodes[item.listType?.rawValue ?? ""] == true
33
+ )
34
+ case .orderedList, .legacyOrderedList:
35
+ return (
36
+ enabled: state.commands["wrapOrderedList"] == true,
37
+ active: state.nodes[item.listType?.rawValue ?? ""] == true
38
+ )
39
+ case .none:
40
+ return (enabled: false, active: false)
41
+ }
42
+ case .command:
43
+ switch item.command {
44
+ case .indentList:
45
+ return (
46
+ enabled: state.commands["indentList"] == true,
47
+ active: false
48
+ )
49
+ case .outdentList:
50
+ return (
51
+ enabled: state.commands["outdentList"] == true,
52
+ active: false
53
+ )
54
+ case .undo:
55
+ return (enabled: state.canUndo, active: false)
56
+ case .redo:
57
+ return (enabled: state.canRedo, active: false)
58
+ case .none:
59
+ return (enabled: false, active: false)
60
+ }
61
+ case .node:
62
+ let nodeType = item.nodeType ?? ""
63
+ return (
64
+ enabled: state.insertableNodes.contains(nodeType),
65
+ active: state.nodes[nodeType] == true
66
+ )
67
+ case .action:
68
+ return (
69
+ enabled: !item.isDisabled,
70
+ active: item.isActive
71
+ )
72
+ case .group:
73
+ let childStates = item.items.map { buttonState(for: $0, state: state) }
74
+ return (
75
+ enabled: childStates.contains { $0.enabled },
76
+ active: childStates.contains { $0.active } ||
77
+ (
78
+ (item.presentation ?? .expand) == .expand &&
79
+ expandedGroupKey == item.key
80
+ )
81
+ )
82
+ case .separator:
83
+ return (enabled: false, active: false)
84
+ }
85
+ }
86
+
87
+ func updateButtonAppearance(
88
+ _ button: UIButton,
89
+ item: NativeToolbarItem,
90
+ enabled: Bool,
91
+ active: Bool
92
+ ) {
93
+ let buttonStyle = item.buttonStyle
94
+ let tintColor: UIColor
95
+ if !enabled {
96
+ tintColor = buttonStyle?.disabledColor
97
+ ?? theme?.buttonDisabledColor
98
+ ?? (resolvedAppearance == .native
99
+ ? UIColor.label.withAlphaComponent(Self.nativeDisabledButtonOpacity)
100
+ : .tertiaryLabel)
101
+ } else if active {
102
+ tintColor = buttonStyle?.activeColor
103
+ ?? theme?.buttonActiveColor
104
+ ?? (resolvedAppearance == .native ? self.tintColor : .systemBlue)
105
+ } else {
106
+ tintColor = buttonStyle?.color
107
+ ?? theme?.buttonColor
108
+ ?? (resolvedAppearance == .native ? self.tintColor : .secondaryLabel)
109
+ }
110
+
111
+ button.tintColor = tintColor
112
+ button.setTitleColor(tintColor, for: .normal)
113
+ button.setTitleColor(tintColor, for: .disabled)
114
+ button.tintAdjustmentMode = enabled ? .automatic : .normal
115
+ button.alpha = enabled || resolvedAppearance == .native ? 1 : 0.7
116
+ let inactiveBackgroundColor = buttonStyle?.backgroundColor
117
+ ?? theme?.buttonBackgroundColor
118
+ ?? .clear
119
+ let activeBackgroundColor = buttonStyle?.activeBackgroundColor
120
+ ?? theme?.buttonActiveBackgroundColor
121
+ ?? (resolvedAppearance == .native
122
+ ? UIColor.white.withAlphaComponent(0.18)
123
+ : UIColor.systemBlue.withAlphaComponent(0.12))
124
+ let disabledBackgroundColor = buttonStyle?.disabledBackgroundColor
125
+ ?? theme?.buttonDisabledBackgroundColor
126
+ ?? (active ? activeBackgroundColor : inactiveBackgroundColor)
127
+ let backgroundColor: UIColor
128
+ if !enabled {
129
+ backgroundColor = disabledBackgroundColor
130
+ } else if active {
131
+ backgroundColor = activeBackgroundColor
132
+ } else {
133
+ backgroundColor = inactiveBackgroundColor
134
+ }
135
+ let cornerRadius = resolvedButtonBorderRadius(for: item)
136
+ button.layer.cornerRadius = cornerRadius
137
+ applyButtonBackground(
138
+ to: button,
139
+ color: backgroundColor,
140
+ cornerRadius: cornerRadius
141
+ )
142
+ applyButtonIconStyle(to: button, item: item)
143
+ }
144
+
145
+ /// Own the configured background to avoid stacking it with UIButton state fills.
146
+ private func applyButtonBackground(
147
+ to button: UIButton,
148
+ color: UIColor,
149
+ cornerRadius: CGFloat
150
+ ) {
151
+ guard #available(iOS 15.0, *), var configuration = button.configuration else {
152
+ button.backgroundColor = color
153
+ return
154
+ }
155
+ var background = UIBackgroundConfiguration.clear()
156
+ background.backgroundColor = color
157
+ background.cornerRadius = cornerRadius
158
+ configuration.background = background
159
+ button.configuration = configuration
160
+ button.backgroundColor = .clear
161
+ }
162
+
163
+ func resolvedButtonBorderRadius(for item: NativeToolbarItem) -> CGFloat {
164
+ guard let radius = item.buttonStyle?.borderRadius, radius.isFinite else {
165
+ return max(0, resolvedButtonBorderRadius)
166
+ }
167
+ return max(0, radius)
168
+ }
169
+
170
+ private func resolvedButtonIconSize(for item: NativeToolbarItem) -> CGFloat {
171
+ let requestedSize = item.buttonStyle?.iconSize ?? theme?.buttonIconSize
172
+ guard let requestedSize, requestedSize.isFinite, requestedSize > 0 else {
173
+ return 16
174
+ }
175
+ return min(requestedSize, resolvedButtonSize)
176
+ }
177
+
178
+ private func applyButtonIconStyle(to button: UIButton, item: NativeToolbarItem) {
179
+ let iconSize = resolvedButtonIconSize(for: item)
180
+ let font = UIFont.systemFont(ofSize: iconSize, weight: .semibold)
181
+ if #available(iOS 15.0, *), var configuration = button.configuration {
182
+ configuration.titleTextAttributesTransformer = UIConfigurationTextAttributesTransformer { incoming in
183
+ var outgoing = incoming
184
+ outgoing.font = font
185
+ return outgoing
186
+ }
187
+ button.configuration = configuration
188
+ button.updateConfiguration()
189
+ }
190
+ button.titleLabel?.font = font
191
+ if button.image(for: .normal) != nil {
192
+ button.setPreferredSymbolConfiguration(
193
+ UIImage.SymbolConfiguration(pointSize: iconSize, weight: .semibold),
194
+ forImageIn: .normal
195
+ )
196
+ }
197
+ }
198
+
199
+ func resolvedBlurEffect() -> UIVisualEffect {
200
+ #if compiler(>=6.2)
201
+ if #available(iOS 26.0, *) {
202
+ let effect = UIGlassEffect(style: .regular)
203
+ effect.isInteractive = true
204
+ effect.tintColor = resolvedGlassEffectTintColor
205
+ return effect
206
+ }
207
+ #endif
208
+ if #available(iOS 13.0, *) {
209
+ return UIBlurEffect(style: .systemUltraThinMaterial)
210
+ }
211
+ return UIBlurEffect(style: .extraLight)
212
+ }
213
+
214
+ }
@@ -0,0 +1,228 @@
1
+ import UIKit
2
+
3
+ extension EditorAccessoryToolbarView {
4
+ func rebuildButtons() {
5
+ if #available(iOS 16.0, *) {
6
+ (editMenuPresenter as? ToolbarEditMenuPresenter)?.dismiss()
7
+ }
8
+ buttonBindings.removeAll()
9
+ separators.removeAll()
10
+ for arrangedSubview in startPinnedStackView.arrangedSubviews {
11
+ startPinnedStackView.removeArrangedSubview(arrangedSubview)
12
+ arrangedSubview.removeFromSuperview()
13
+ }
14
+ for arrangedSubview in stackView.arrangedSubviews {
15
+ stackView.removeArrangedSubview(arrangedSubview)
16
+ arrangedSubview.removeFromSuperview()
17
+ }
18
+ for arrangedSubview in endPinnedStackView.arrangedSubviews {
19
+ endPinnedStackView.removeArrangedSubview(arrangedSubview)
20
+ arrangedSubview.removeFromSuperview()
21
+ }
22
+
23
+ let visibleItems = visibleToolbarItemsByPlacement()
24
+ rebuildButtons(items: visibleItems.start, in: startPinnedStackView)
25
+ rebuildButtons(items: visibleItems.scroll, in: stackView)
26
+ rebuildButtons(items: visibleItems.end, in: endPinnedStackView)
27
+ updatePinnedStackParticipation()
28
+ apply(theme: theme)
29
+ apply(state: currentState)
30
+ }
31
+
32
+ /// Exclude an empty pinned stack from `bodyStackView` entirely.
33
+ ///
34
+ /// Horizontal hugging cannot hold an empty `UIStackView` at zero width:
35
+ /// hugging only resists growing beyond an *intrinsic* size, and an empty
36
+ /// stack has none. With nothing to hug to, `bodyStackView`'s fill
37
+ /// distribution is free to hand the whole row to an empty pinned stack,
38
+ /// collapsing the scrolling middle that holds every button. Hiding an
39
+ /// arranged subview removes it from the distribution outright, which is
40
+ /// the only unambiguous way to say "this edge takes no space".
41
+ private func updatePinnedStackParticipation() {
42
+ startPinnedStackView.isHidden = startPinnedStackView.arrangedSubviews.isEmpty
43
+ endPinnedStackView.isHidden = endPinnedStackView.arrangedSubviews.isEmpty
44
+ }
45
+
46
+ func rebuildButtons(items: [NativeToolbarItem], in container: UIStackView) {
47
+ for item in items {
48
+ if item.type == .separator {
49
+ container.addArrangedSubview(makeSeparator())
50
+ continue
51
+ }
52
+
53
+ container.addArrangedSubview(makeButton(item: item))
54
+ }
55
+ }
56
+
57
+ private func compactToolbarItems(_ items: [NativeToolbarItem]) -> [NativeToolbarItem] {
58
+ items.enumerated().filter { index, item in
59
+ guard item.type == .separator else { return true }
60
+ guard index > 0, index < items.count - 1 else { return false }
61
+ return items[index - 1].type != .separator && items[index + 1].type != .separator
62
+ }.map(\.element)
63
+ }
64
+
65
+ private func visibleToolbarItems() -> [NativeToolbarItem] {
66
+ var visible: [NativeToolbarItem] = []
67
+ for item in compactToolbarItems(items) {
68
+ visible.append(item)
69
+ if item.type == .group,
70
+ (item.presentation ?? .expand) == .expand,
71
+ expandedGroupKey == item.key {
72
+ visible.append(contentsOf: item.items.map {
73
+ $0.with(parentGroupKey: item.key, inheritedPlacement: item.placement)
74
+ })
75
+ }
76
+ }
77
+ return compactToolbarItems(visible)
78
+ }
79
+
80
+ private func visibleToolbarItemsByPlacement() -> VisibleToolbarItemsByPlacement {
81
+ var start: [NativeToolbarItem] = []
82
+ var scroll: [NativeToolbarItem] = []
83
+ var end: [NativeToolbarItem] = []
84
+
85
+ for item in visibleToolbarItems() {
86
+ switch item.placement ?? .scroll {
87
+ case .start:
88
+ start.append(item)
89
+ case .scroll:
90
+ scroll.append(item)
91
+ case .end:
92
+ end.append(item)
93
+ }
94
+ }
95
+
96
+ return VisibleToolbarItemsByPlacement(
97
+ start: compactToolbarItems(start),
98
+ scroll: compactToolbarItems(scroll),
99
+ end: compactToolbarItems(end)
100
+ )
101
+ }
102
+
103
+ private func handleToolbarButtonPress(_ item: NativeToolbarItem) {
104
+ switch item.type {
105
+ case .group:
106
+ handleGroupPress(item)
107
+ default:
108
+ onPressItem?(item.with(parentGroupKey: nil))
109
+ if let parentGroupKey = item.parentGroupKey,
110
+ expandedGroupKey == parentGroupKey {
111
+ expandedGroupKey = nil
112
+ rebuildButtons()
113
+ }
114
+ }
115
+ }
116
+
117
+ private func handleGroupPress(_ item: NativeToolbarItem) {
118
+ guard item.type == .group, !item.items.isEmpty else { return }
119
+ switch item.presentation ?? .expand {
120
+ case .expand:
121
+ expandedGroupKey = expandedGroupKey == item.key ? nil : item.key
122
+ rebuildButtons()
123
+ case .menu:
124
+ break
125
+ }
126
+ }
127
+
128
+ private func presentGroupMenu(_ item: NativeToolbarItem, from sourceButton: UIButton) {
129
+ guard #available(iOS 16.0, *),
130
+ let presenter = editMenuPresenter as? ToolbarEditMenuPresenter
131
+ else {
132
+ return
133
+ }
134
+ presenter.toggle(from: sourceButton) { [weak self] in
135
+ self?.makeGroupMenu(item: item)
136
+ }
137
+ }
138
+
139
+ private func makeGroupMenu(item: NativeToolbarItem) -> UIMenu? {
140
+ guard item.type == .group else { return nil }
141
+ let actions = item.items.compactMap { child -> UIAction? in
142
+ let state = buttonState(for: child, state: currentState)
143
+ let image = child.icon?.resolvedSFSymbolName().flatMap { UIImage(systemName: $0) }
144
+ let title = child.label ?? child.icon?.resolvedGlyphText() ?? "Item"
145
+ return UIAction(
146
+ title: title,
147
+ image: image,
148
+ identifier: nil,
149
+ discoverabilityTitle: child.label,
150
+ attributes: state.enabled ? [] : [.disabled],
151
+ state: state.active ? .on : .off
152
+ ) { [weak self] _ in
153
+ self?.handleToolbarButtonPress(child)
154
+ }
155
+ }
156
+ guard !actions.isEmpty else { return nil }
157
+ let menu = UIMenu(title: item.label ?? "", children: actions)
158
+ menu.preferredElementSize = .large
159
+ return menu
160
+ }
161
+
162
+ private func makeButton(item: NativeToolbarItem) -> UIButton {
163
+ let button = UIButton(type: .system)
164
+ button.translatesAutoresizingMaskIntoConstraints = false
165
+ button.accessibilityLabel = item.label
166
+ button.layer.cornerRadius = resolvedButtonBorderRadius(for: item)
167
+ button.clipsToBounds = true
168
+ if #available(iOS 15.0, *) {
169
+ var configuration = UIButton.Configuration.plain()
170
+ configuration.contentInsets = NSDirectionalEdgeInsets(
171
+ top: 8,
172
+ leading: 10,
173
+ bottom: 8,
174
+ trailing: 10
175
+ )
176
+ button.configuration = configuration
177
+ } else {
178
+ button.contentEdgeInsets = UIEdgeInsets(top: 8, left: 10, bottom: 8, right: 10)
179
+ }
180
+ if let symbolName = item.icon?.resolvedSFSymbolName(),
181
+ let symbolImage = UIImage(systemName: symbolName) {
182
+ button.setImage(symbolImage, for: .normal)
183
+ button.setTitle(nil, for: .normal)
184
+ } else {
185
+ button.setImage(nil, for: .normal)
186
+ button.setTitle(item.icon?.resolvedGlyphText() ?? "?", for: .normal)
187
+ }
188
+ let buttonSize = resolvedButtonSize
189
+ let widthConstraint = button.widthAnchor.constraint(greaterThanOrEqualToConstant: buttonSize)
190
+ let heightConstraint = button.heightAnchor.constraint(equalToConstant: buttonSize)
191
+ widthConstraint.isActive = true
192
+ heightConstraint.isActive = true
193
+ if item.type == .group,
194
+ (item.presentation ?? .expand) == .menu,
195
+ #available(iOS 16.0, *) {
196
+ button.accessibilityHint = "Shows menu"
197
+ button.addAction(UIAction { [weak self, weak button] _ in
198
+ guard let button else { return }
199
+ self?.presentGroupMenu(item, from: button)
200
+ }, for: .touchUpInside)
201
+ } else {
202
+ button.addAction(UIAction { [weak self] _ in
203
+ self?.handleToolbarButtonPress(item)
204
+ }, for: .touchUpInside)
205
+ }
206
+ updateButtonAppearance(button, item: item, enabled: true, active: false)
207
+ buttonBindings.append(
208
+ ButtonBinding(
209
+ item: item,
210
+ button: button,
211
+ widthConstraint: widthConstraint,
212
+ heightConstraint: heightConstraint
213
+ )
214
+ )
215
+ return button
216
+ }
217
+
218
+ private func makeSeparator() -> UIView {
219
+ let separator = UIView()
220
+ separator.translatesAutoresizingMaskIntoConstraints = false
221
+ separator.backgroundColor = .separator
222
+ separator.widthAnchor.constraint(equalToConstant: 1 / UIScreen.main.scale).isActive = true
223
+ separator.heightAnchor.constraint(equalToConstant: 22).isActive = true
224
+ separators.append(separator)
225
+ return separator
226
+ }
227
+
228
+ }