@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.
- package/LICENSE +160 -0
- package/README.md +259 -0
- package/RUST-STANDARD-LIBRARY-NOTICES.html +8266 -0
- package/ReactNativeProseEditor.podspec +59 -0
- package/THIRD_PARTY_NOTICES.md +31155 -0
- package/android/build.gradle +188 -0
- package/android/consumer-rules.pro +18 -0
- package/android/expo/build.gradle +17 -0
- package/android/src/debug/java/com/apollohg/editor/viewer/PreparedProseDrawInstrumentation.kt +7 -0
- package/android/src/main/assets/editor-icons/MaterialIcons.json +2236 -0
- package/android/src/main/assets/editor-icons/MaterialIcons.ttf +0 -0
- package/android/src/main/java/com/apollohg/editor/AndroidApiCompat.kt +19 -0
- package/android/src/main/java/com/apollohg/editor/AndroidCollaborationTransport.kt +860 -0
- package/android/src/main/java/com/apollohg/editor/CaretGeometry.kt +91 -0
- package/android/src/main/java/com/apollohg/editor/CodeHighlighting.kt +141 -0
- package/android/src/main/java/com/apollohg/editor/DecodedBitmapBudget.kt +250 -0
- package/android/src/main/java/com/apollohg/editor/EditorAddons.kt +133 -0
- package/android/src/main/java/com/apollohg/editor/EditorBlockSpacing.kt +51 -0
- package/android/src/main/java/com/apollohg/editor/EditorBoxDrawable.kt +16 -0
- package/android/src/main/java/com/apollohg/editor/EditorBoxDrawing.kt +234 -0
- package/android/src/main/java/com/apollohg/editor/EditorCheckboxSpan.kt +87 -0
- package/android/src/main/java/com/apollohg/editor/EditorCodeHighlighting.kt +120 -0
- package/android/src/main/java/com/apollohg/editor/EditorDecorationLayer.java +18 -0
- package/android/src/main/java/com/apollohg/editor/EditorDocumentLayout.kt +626 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditText.kt +1042 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextAnnotations.kt +191 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextCaret.kt +100 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextClipboard.kt +101 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextComposition.kt +220 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextConfiguration.kt +316 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextCorrection.kt +303 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextDeferredUpdates.kt +327 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextDeletion.kt +258 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextDiagnostics.kt +83 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextDragDrop.kt +67 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextExternalComposition.kt +357 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextHardwareInput.kt +277 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextImages.kt +280 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextInputLifecycle.kt +183 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextInputPreparation.kt +79 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextInputTraits.kt +384 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextLayout.kt +100 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextNativeMutation.kt +243 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextPlaceholder.kt +154 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextRenderPatch.kt +347 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextRendering.kt +313 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextRustCommands.kt +281 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextSelection.kt +352 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextState.kt +113 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextTaskMarkers.kt +92 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextTextCommit.kt +327 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextToolbar.kt +84 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextUpdates.kt +245 -0
- package/android/src/main/java/com/apollohg/editor/EditorGlyphHeightCursorDrawable.kt +42 -0
- package/android/src/main/java/com/apollohg/editor/EditorHeightBehavior.kt +13 -0
- package/android/src/main/java/com/apollohg/editor/EditorInputConnection.kt +923 -0
- package/android/src/main/java/com/apollohg/editor/EditorInputCoordinates.kt +191 -0
- package/android/src/main/java/com/apollohg/editor/EditorInputCorrection.kt +107 -0
- package/android/src/main/java/com/apollohg/editor/EditorInputCursorGeometry.kt +128 -0
- package/android/src/main/java/com/apollohg/editor/EditorInputSnapshots.kt +134 -0
- package/android/src/main/java/com/apollohg/editor/EditorInputSurroundingDeletion.kt +321 -0
- package/android/src/main/java/com/apollohg/editor/EditorKeyboardToolbarView.kt +851 -0
- package/android/src/main/java/com/apollohg/editor/EditorMentionStyle.kt +192 -0
- package/android/src/main/java/com/apollohg/editor/EditorReconciliationWatcher.kt +46 -0
- package/android/src/main/java/com/apollohg/editor/EditorStyleSheet.kt +303 -0
- package/android/src/main/java/com/apollohg/editor/EditorStyleSheetSpans.kt +253 -0
- package/android/src/main/java/com/apollohg/editor/EditorSurfaceInputConnection.kt +67 -0
- package/android/src/main/java/com/apollohg/editor/EditorTextDecorationDrawing.kt +143 -0
- package/android/src/main/java/com/apollohg/editor/EditorTextSurface.kt +712 -0
- package/android/src/main/java/com/apollohg/editor/EditorTextSurfaceDragDrop.kt +94 -0
- package/android/src/main/java/com/apollohg/editor/EditorTextSurfaceInteraction.kt +708 -0
- package/android/src/main/java/com/apollohg/editor/EditorTheme.kt +650 -0
- package/android/src/main/java/com/apollohg/editor/EditorV2Adapter.kt +912 -0
- package/android/src/main/java/com/apollohg/editor/EditorV2AdapterMutations.kt +402 -0
- package/android/src/main/java/com/apollohg/editor/EditorV2AdapterRendering.kt +123 -0
- package/android/src/main/java/com/apollohg/editor/EditorV2AdapterSelection.kt +203 -0
- package/android/src/main/java/com/apollohg/editor/EditorV2Backend.kt +120 -0
- package/android/src/main/java/com/apollohg/editor/EditorV2Driver.kt +87 -0
- package/android/src/main/java/com/apollohg/editor/EditorV2Registry.kt +97 -0
- package/android/src/main/java/com/apollohg/editor/EditorV2RenderValidation.kt +409 -0
- package/android/src/main/java/com/apollohg/editor/ExpoAutoGrowStyleSizePublisher.kt +34 -0
- package/android/src/main/java/com/apollohg/editor/ImageResizeOverlayView.kt +266 -0
- package/android/src/main/java/com/apollohg/editor/ImeTextCoordinateMapper.kt +102 -0
- package/android/src/main/java/com/apollohg/editor/KeyboardToolbarImeAnimationController.kt +101 -0
- package/android/src/main/java/com/apollohg/editor/MentionSuggestionChipView.kt +234 -0
- package/android/src/main/java/com/apollohg/editor/NativeCollaborationTransportRegistry.kt +493 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoView.kt +813 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewAtoms.kt +68 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewBinding.kt +126 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewDiagnostics.kt +208 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewErrors.kt +146 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewEvents.kt +150 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewExternalComposition.kt +39 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewFocus.kt +176 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewLifecycle.kt +302 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewMentions.kt +259 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewNativeActions.kt +179 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewOutsideTap.kt +214 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewPendingUpdates.kt +376 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewProperties.kt +234 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewPropertyRetries.kt +197 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewToolbar.kt +285 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewTypes.kt +28 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoViewUpdates.kt +271 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorModule.kt +687 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorOutsideTapDispatcher.kt +380 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorV2Numbers.kt +45 -0
- package/android/src/main/java/com/apollohg/editor/NativeEditorViewRegistry.kt +372 -0
- package/android/src/main/java/com/apollohg/editor/NativeImagePipeline.kt +22 -0
- package/android/src/main/java/com/apollohg/editor/NativeToolbar.kt +193 -0
- package/android/src/main/java/com/apollohg/editor/NativeToolbarIcons.kt +177 -0
- package/android/src/main/java/com/apollohg/editor/NativeToolbarItem.kt +274 -0
- package/android/src/main/java/com/apollohg/editor/OkHttpCollaborationSocket.kt +102 -0
- package/android/src/main/java/com/apollohg/editor/OrderedListMarkerFormatter.kt +130 -0
- package/android/src/main/java/com/apollohg/editor/PointerTransparentView.java +18 -0
- package/android/src/main/java/com/apollohg/editor/PositionBridge.kt +128 -0
- package/android/src/main/java/com/apollohg/editor/ProseViewerView.kt +854 -0
- package/android/src/main/java/com/apollohg/editor/RemoteSelectionOverlayView.kt +314 -0
- package/android/src/main/java/com/apollohg/editor/RenderBlockSpans.kt +314 -0
- package/android/src/main/java/com/apollohg/editor/RenderBridge.kt +224 -0
- package/android/src/main/java/com/apollohg/editor/RenderBridgeBlockStyles.kt +407 -0
- package/android/src/main/java/com/apollohg/editor/RenderBridgeElements.kt +544 -0
- package/android/src/main/java/com/apollohg/editor/RenderBridgeInlineAndAtoms.kt +631 -0
- package/android/src/main/java/com/apollohg/editor/RenderBridgeParagraphs.kt +215 -0
- package/android/src/main/java/com/apollohg/editor/RenderImageDecoder.kt +748 -0
- package/android/src/main/java/com/apollohg/editor/RenderImageLoader.kt +900 -0
- package/android/src/main/java/com/apollohg/editor/RenderLayoutConstants.kt +117 -0
- package/android/src/main/java/com/apollohg/editor/RenderMediaSpans.kt +337 -0
- package/android/src/main/java/com/apollohg/editor/RenderParagraphSpans.kt +182 -0
- package/android/src/main/java/com/apollohg/editor/RichTextEditorView.kt +951 -0
- package/android/src/main/java/com/apollohg/editor/SharedNativeImagePipeline.kt +78 -0
- package/android/src/main/java/com/apollohg/editor/UniffiEditorV2Backend.kt +261 -0
- package/android/src/main/java/com/apollohg/editor/viewer/AndroidProseLayoutEngine.kt +1656 -0
- package/android/src/main/java/com/apollohg/editor/viewer/FabricAttachmentSidecars.kt +80 -0
- package/android/src/main/java/com/apollohg/editor/viewer/FabricLeaseHandleBridge.kt +59 -0
- package/android/src/main/java/com/apollohg/editor/viewer/FallbackSelectionGeometry.kt +450 -0
- package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseDrawingView.kt +678 -0
- package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseInstrumentation.kt +608 -0
- package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseLayout.kt +186 -0
- package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseLayoutCache.kt +393 -0
- package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseLayoutRegistry.kt +828 -0
- package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseTheme.kt +316 -0
- package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseViewerManager.kt +900 -0
- package/android/src/main/java/com/apollohg/editor/viewer/PreparedProseViewerPackage.kt +16 -0
- package/android/src/main/java/com/apollohg/editor/viewer/PreparedViewerAtoms.kt +89 -0
- package/android/src/main/java/com/apollohg/editor/viewer/ViewerCodeHighlighting.kt +91 -0
- package/android/src/main/java/com/apollohg/editor/viewer/ViewerDocument.kt +453 -0
- package/android/src/main/java/com/apollohg/editor/viewer/ViewerFontEnvironment.kt +282 -0
- package/android/src/main/java/com/apollohg/editor/viewer/ViewerImagePipeline.kt +460 -0
- package/android/src/main/jni/CMakeLists.txt +85 -0
- package/android/src/main/jni/PreparedProseViewerMeasurementsManager.cpp +334 -0
- package/android/src/main/jni/ReactNativeProseEditorSpec.h +17 -0
- package/android/src/main/jni/reactnativeproseeditor.h +6 -0
- package/android/src/main/res/values/attrs.xml +6 -0
- package/android/src/release/java/com/apollohg/editor/viewer/PreparedProseDrawInstrumentation.kt +9 -0
- package/app.plugin.js +62 -0
- package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseMeasurementsManager.h +62 -0
- package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseViewerComponentDescriptor.h +30 -0
- package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseViewerShadowNode.cpp +192 -0
- package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseViewerShadowNode.h +46 -0
- package/common/cpp/react/renderer/components/PreparedProseViewer/PreparedProseViewerState.h +145 -0
- package/dist/AtomHost.d.ts +17 -0
- package/dist/AtomHost.js +135 -0
- package/dist/DefaultAtomChip.d.ts +2 -0
- package/dist/DefaultAtomChip.js +22 -0
- package/dist/EditorAddon.d.ts +32 -0
- package/dist/EditorAddon.js +29 -0
- package/dist/EditorAddonNormalization.d.ts +6 -0
- package/dist/EditorAddonNormalization.js +48 -0
- package/dist/EditorMentionThemeNormalization.d.ts +8 -0
- package/dist/EditorMentionThemeNormalization.js +22 -0
- package/dist/EditorMentionThemeValidation.d.ts +12 -0
- package/dist/EditorMentionThemeValidation.js +95 -0
- package/dist/EditorStyleSheet.d.ts +4 -0
- package/dist/EditorStyleSheet.js +10 -0
- package/dist/EditorStyleSheetNormalization.d.ts +3 -0
- package/dist/EditorStyleSheetNormalization.js +226 -0
- package/dist/EditorStyleSheetTypes.d.ts +151 -0
- package/dist/EditorStyleSheetTypes.js +2 -0
- package/dist/EditorTheme.d.ts +117 -0
- package/dist/EditorTheme.js +41 -0
- package/dist/EditorToolbar.d.ts +4 -0
- package/dist/EditorToolbar.js +17 -0
- package/dist/EditorToolbarComponent.d.ts +13 -0
- package/dist/EditorToolbarComponent.js +24 -0
- package/dist/EditorToolbarItems.d.ts +9 -0
- package/dist/EditorToolbarItems.js +58 -0
- package/dist/EditorToolbarRegistry.d.ts +59 -0
- package/dist/EditorToolbarRegistry.js +175 -0
- package/dist/EditorToolbarTypes.d.ts +273 -0
- package/dist/EditorToolbarTypes.js +2 -0
- package/dist/EditorToolbarVisuals.d.ts +154 -0
- package/dist/EditorToolbarVisuals.js +228 -0
- package/dist/EditorUpdateRevision.d.ts +8 -0
- package/dist/EditorUpdateRevision.js +22 -0
- package/dist/ExternalTextComposition.d.ts +45 -0
- package/dist/ExternalTextComposition.js +537 -0
- package/dist/ImageLoadingPolicy.d.ts +54 -0
- package/dist/ImageLoadingPolicy.js +60 -0
- package/dist/NativeEditorBoundaryError.d.ts +111 -0
- package/dist/NativeEditorBoundaryError.js +268 -0
- package/dist/NativeEditorBridge.d.ts +9 -0
- package/dist/NativeEditorBridge.js +37 -0
- package/dist/NativeEditorCollaborationTransport.d.ts +154 -0
- package/dist/NativeEditorCollaborationTransport.js +275 -0
- package/dist/NativeEditorCreateConfig.d.ts +16 -0
- package/dist/NativeEditorCreateConfig.js +249 -0
- package/dist/NativeEditorCreateJson.d.ts +76 -0
- package/dist/NativeEditorCreateJson.js +474 -0
- package/dist/NativeEditorCreateValidation.d.ts +32 -0
- package/dist/NativeEditorCreateValidation.js +150 -0
- package/dist/NativeEditorDocumentBridge.d.ts +72 -0
- package/dist/NativeEditorDocumentBridge.js +305 -0
- package/dist/NativeEditorDocumentHandle.d.ts +70 -0
- package/dist/NativeEditorDocumentHandle.js +89 -0
- package/dist/NativeEditorLocalAwareness.d.ts +34 -0
- package/dist/NativeEditorLocalAwareness.js +153 -0
- package/dist/NativeEditorNativeModule.d.ts +48 -0
- package/dist/NativeEditorNativeModule.js +34 -0
- package/dist/NativeEditorRenderNormalization.d.ts +22 -0
- package/dist/NativeEditorRenderNormalization.js +274 -0
- package/dist/NativeEditorResultNormalization.d.ts +108 -0
- package/dist/NativeEditorResultNormalization.js +400 -0
- package/dist/NativeEditorTypes.d.ts +318 -0
- package/dist/NativeEditorTypes.js +15 -0
- package/dist/NativeEditorV2Decimal.d.ts +5 -0
- package/dist/NativeEditorV2Decimal.js +18 -0
- package/dist/NativeProseViewer.d.ts +122 -0
- package/dist/NativeProseViewer.js +130 -0
- package/dist/NativeRichTextEditor.d.ts +3 -0
- package/dist/NativeRichTextEditor.js +6 -0
- package/dist/ResourceLimits.d.ts +100 -0
- package/dist/ResourceLimits.js +80 -0
- package/dist/RichTextEditor.d.ts +4 -0
- package/dist/RichTextEditor.js +25 -0
- package/dist/RichTextEditorNativeTypes.d.ts +122 -0
- package/dist/RichTextEditorNativeTypes.js +2 -0
- package/dist/RichTextEditorNativeView.d.ts +12 -0
- package/dist/RichTextEditorNativeView.js +15 -0
- package/dist/RichTextEditorSerialization.d.ts +53 -0
- package/dist/RichTextEditorSerialization.js +283 -0
- package/dist/RichTextEditorTypes.d.ts +281 -0
- package/dist/RichTextEditorTypes.js +2 -0
- package/dist/ViewerConfiguration.d.ts +22 -0
- package/dist/ViewerConfiguration.js +6 -0
- package/dist/YjsCollaboration.d.ts +146 -0
- package/dist/YjsCollaboration.js +496 -0
- package/dist/addons.d.ts +193 -0
- package/dist/addons.js +122 -0
- package/dist/atomConstants.d.ts +3 -0
- package/dist/atomConstants.js +6 -0
- package/dist/atomInstances.d.ts +35 -0
- package/dist/atomInstances.js +79 -0
- package/dist/atomPolicy.d.ts +4 -0
- package/dist/atomPolicy.js +47 -0
- package/dist/atomUpdates.d.ts +2 -0
- package/dist/atomUpdates.js +38 -0
- package/dist/atoms.d.ts +92 -0
- package/dist/atoms.js +222 -0
- package/dist/attributeValidation.d.ts +4 -0
- package/dist/attributeValidation.js +97 -0
- package/dist/contentExpression.d.ts +6 -0
- package/dist/contentExpression.js +335 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +78 -0
- package/dist/listMarkers.d.ts +15 -0
- package/dist/listMarkers.js +21 -0
- package/dist/schemaDefinition.d.ts +143 -0
- package/dist/schemaDefinition.js +206 -0
- package/dist/schemaDocument.d.ts +17 -0
- package/dist/schemaDocument.js +69 -0
- package/dist/schemaDocumentConstruction.d.ts +5 -0
- package/dist/schemaDocumentConstruction.js +125 -0
- package/dist/schemaNormalization.d.ts +29 -0
- package/dist/schemaNormalization.js +313 -0
- package/dist/schemaPresets.d.ts +68 -0
- package/dist/schemaPresets.js +198 -0
- package/dist/schemaResolution.d.ts +9 -0
- package/dist/schemaResolution.js +211 -0
- package/dist/schemas.d.ts +5 -0
- package/dist/schemas.js +28 -0
- package/dist/specs/PreparedProseViewerNativeComponent.d.ts +37 -0
- package/dist/specs/PreparedProseViewerNativeComponent.js +6 -0
- package/dist/useEditorToolbarInteractions.d.ts +12 -0
- package/dist/useEditorToolbarInteractions.js +218 -0
- package/dist/useEditorToolbarItems.d.ts +8 -0
- package/dist/useEditorToolbarItems.js +280 -0
- package/dist/useEditorToolbarPresentation.d.ts +4 -0
- package/dist/useEditorToolbarPresentation.js +203 -0
- package/dist/useEditorToolbarState.d.ts +63 -0
- package/dist/useEditorToolbarState.js +108 -0
- package/dist/useFocusPreservingFrames.d.ts +17 -0
- package/dist/useFocusPreservingFrames.js +108 -0
- package/dist/useNativeEditor.d.ts +66 -0
- package/dist/useNativeEditor.js +370 -0
- package/dist/useRichTextEditorCommands.d.ts +21 -0
- package/dist/useRichTextEditorCommands.js +299 -0
- package/dist/useRichTextEditorEvents.d.ts +18 -0
- package/dist/useRichTextEditorEvents.js +216 -0
- package/dist/useRichTextEditorMentions.d.ts +11 -0
- package/dist/useRichTextEditorMentions.js +316 -0
- package/dist/useRichTextEditorPresentation.d.ts +5 -0
- package/dist/useRichTextEditorPresentation.js +178 -0
- package/dist/useRichTextEditorState.d.ts +180 -0
- package/dist/useRichTextEditorState.js +405 -0
- package/dist/useRichTextEditorUpdates.d.ts +10 -0
- package/dist/useRichTextEditorUpdates.js +308 -0
- package/dist/useViewerAtoms.d.ts +38 -0
- package/dist/useViewerAtoms.js +288 -0
- package/expo-module.config.json +13 -0
- package/ios/EditorAddons.swift +354 -0
- package/ios/EditorCodeHighlighting.swift +184 -0
- package/ios/EditorCore.xcframework/Info.plist +44 -0
- package/ios/EditorCore.xcframework/ios-arm64/libeditor_core.a +0 -0
- package/ios/EditorCore.xcframework/ios-arm64_x86_64-simulator/libeditor_core.a +0 -0
- package/ios/EditorInteractionOverlays.swift +697 -0
- package/ios/EditorLayoutManager.swift +971 -0
- package/ios/EditorNodeTypes.swift +37 -0
- package/ios/EditorStyleSheet.swift +461 -0
- package/ios/EditorTextView+AttributedPatch.swift +305 -0
- package/ios/EditorTextView+Binding.swift +61 -0
- package/ios/EditorTextView+Caret.swift +333 -0
- package/ios/EditorTextView+Commands.swift +203 -0
- package/ios/EditorTextView+Delegate.swift +65 -0
- package/ios/EditorTextView+Diagnostics.swift +225 -0
- package/ios/EditorTextView+DragDrop.swift +290 -0
- package/ios/EditorTextView+ExternalComposition.swift +364 -0
- package/ios/EditorTextView+Images.swift +354 -0
- package/ios/EditorTextView+InputTraits.swift +200 -0
- package/ios/EditorTextView+KeyboardInput.swift +318 -0
- package/ios/EditorTextView+Layout.swift +245 -0
- package/ios/EditorTextView+MarkedText.swift +267 -0
- package/ios/EditorTextView+NativeInputLifecycle.swift +372 -0
- package/ios/EditorTextView+NativeMutation.swift +471 -0
- package/ios/EditorTextView+Reconciliation.swift +97 -0
- package/ios/EditorTextView+RenderPatch.swift +573 -0
- package/ios/EditorTextView+Rendering.swift +539 -0
- package/ios/EditorTextView+Selection.swift +542 -0
- package/ios/EditorTextView.swift +953 -0
- package/ios/EditorTheme.swift +626 -0
- package/ios/EditorV2Adapter+Commands.swift +204 -0
- package/ios/EditorV2Adapter+Envelope.swift +238 -0
- package/ios/EditorV2Adapter+Mutation.swift +392 -0
- package/ios/EditorV2Adapter+Registry.swift +185 -0
- package/ios/EditorV2Adapter+RenderState.swift +360 -0
- package/ios/EditorV2Adapter+RenderValidation.swift +420 -0
- package/ios/EditorV2Adapter+Selection.swift +329 -0
- package/ios/EditorV2Adapter+TextCommands.swift +430 -0
- package/ios/EditorV2Adapter.swift +376 -0
- package/ios/EditorV2Shadow.swift +353 -0
- package/ios/Generated_editor_core.swift +2378 -0
- package/ios/NativeCodeHighlighting.swift +159 -0
- package/ios/NativeCollaborationSocket.swift +144 -0
- package/ios/NativeCollaborationTransport+Protocol.swift +258 -0
- package/ios/NativeCollaborationTransport+Socket.swift +379 -0
- package/ios/NativeCollaborationTransport+Validation.swift +103 -0
- package/ios/NativeCollaborationTransport.swift +322 -0
- package/ios/NativeCollaborationTransportRegistry.swift +521 -0
- package/ios/NativeEditorExpoView+AccessoryRetry.swift +219 -0
- package/ios/NativeEditorExpoView+Binding.swift +268 -0
- package/ios/NativeEditorExpoView+Diagnostics.swift +66 -0
- package/ios/NativeEditorExpoView+Events.swift +131 -0
- package/ios/NativeEditorExpoView+Focus.swift +169 -0
- package/ios/NativeEditorExpoView+MentionRetry.swift +288 -0
- package/ios/NativeEditorExpoView+Mentions.swift +288 -0
- package/ios/NativeEditorExpoView+Properties.swift +300 -0
- package/ios/NativeEditorExpoView+Toolbar.swift +86 -0
- package/ios/NativeEditorExpoView+Updates.swift +312 -0
- package/ios/NativeEditorExpoView.swift +349 -0
- package/ios/NativeEditorModule.swift +856 -0
- package/ios/NativeEditorViewRegistry.swift +226 -0
- package/ios/NativeToolbar+ButtonStyle.swift +214 -0
- package/ios/NativeToolbar+Buttons.swift +228 -0
- package/ios/NativeToolbar+Diagnostics.swift +114 -0
- package/ios/NativeToolbar+Menu.swift +101 -0
- package/ios/NativeToolbar+Models.swift +519 -0
- package/ios/NativeToolbar+Placeholder.swift +39 -0
- package/ios/NativeToolbar.swift +612 -0
- package/ios/OrderedListMarkerFormatter.swift +103 -0
- package/ios/PositionBridge.swift +596 -0
- package/ios/ProseViewerView.swift +462 -0
- package/ios/RenderBridge+Atoms.swift +288 -0
- package/ios/RenderBridge+Attachments.swift +246 -0
- package/ios/RenderBridge+BlockBoundaries.swift +313 -0
- package/ios/RenderBridge+Style.swift +343 -0
- package/ios/RenderBridge.swift +704 -0
- package/ios/RichTextEditorView.swift +930 -0
- package/ios/SharedNativeImagePipeline+Cache.swift +189 -0
- package/ios/SharedNativeImagePipeline+Transport.swift +328 -0
- package/ios/SharedNativeImagePipeline.swift +533 -0
- package/ios/Viewer/CoreTextProseLayoutEngine+AttributedText.swift +436 -0
- package/ios/Viewer/CoreTextProseLayoutEngine+Models.swift +322 -0
- package/ios/Viewer/CoreTextProseLayoutEngine.swift +635 -0
- package/ios/Viewer/Fabric/PREPPreparedProseViewerComponentView.h +4 -0
- package/ios/Viewer/Fabric/PREPPreparedProseViewerComponentView.mm +767 -0
- package/ios/Viewer/Fabric/PreparedProseMeasurementsManager.mm +118 -0
- package/ios/Viewer/NativeSVGImageDecoder.h +9 -0
- package/ios/Viewer/NativeSVGImageDecoder.mm +106 -0
- package/ios/Viewer/NativeSVGPreflight.h +11 -0
- package/ios/Viewer/NativeSVGPreflight.mm +219 -0
- package/ios/Viewer/PreparedProseDrawingView.swift +639 -0
- package/ios/Viewer/PreparedProseInstrumentation.swift +387 -0
- package/ios/Viewer/PreparedProseLayout.swift +326 -0
- package/ios/Viewer/PreparedProseLayoutCache.swift +766 -0
- package/ios/Viewer/PreparedProseLayoutRegistry+Artifacts.swift +377 -0
- package/ios/Viewer/PreparedProseLayoutRegistry+Fabric.swift +582 -0
- package/ios/Viewer/PreparedProseLayoutRegistry+FabricOwnership.swift +128 -0
- package/ios/Viewer/PreparedProseLayoutRegistry.swift +381 -0
- package/ios/Viewer/ViewerDocument.swift +575 -0
- package/ios/Viewer/ViewerFontEnvironment.swift +283 -0
- package/ios/Viewer/ViewerImagePipeline.swift +478 -0
- package/ios/editor_coreFFI/editor_coreFFI.h +1023 -0
- package/ios/editor_coreFFI/module.modulemap +7 -0
- package/package.json +151 -0
- package/react-native.config.js +17 -0
- package/rust/android/arm64-v8a/libeditor_core.so +0 -0
- package/rust/android/armeabi-v7a/libeditor_core.so +0 -0
- package/rust/android/x86/libeditor_core.so +0 -0
- package/rust/android/x86_64/libeditor_core.so +0 -0
- package/rust/bindings/kotlin/uniffi/editor_core/editor_core.kt +3146 -0
- package/src/AtomHost.tsx +180 -0
- package/src/DefaultAtomChip.tsx +27 -0
- package/src/EditorAddon.ts +65 -0
- package/src/EditorAddonNormalization.ts +49 -0
- package/src/EditorMentionThemeNormalization.ts +25 -0
- package/src/EditorMentionThemeValidation.ts +133 -0
- package/src/EditorStyleSheet.ts +9 -0
- package/src/EditorStyleSheetNormalization.ts +219 -0
- package/src/EditorStyleSheetTypes.ts +189 -0
- package/src/EditorTheme.ts +196 -0
- package/src/EditorToolbar.tsx +31 -0
- package/src/EditorToolbarComponent.tsx +23 -0
- package/src/EditorToolbarItems.tsx +64 -0
- package/src/EditorToolbarRegistry.tsx +254 -0
- package/src/EditorToolbarTypes.tsx +322 -0
- package/src/EditorToolbarVisuals.tsx +270 -0
- package/src/EditorUpdateRevision.ts +26 -0
- package/src/ExternalTextComposition.ts +658 -0
- package/src/ImageLoadingPolicy.ts +125 -0
- package/src/NativeEditorBoundaryError.ts +345 -0
- package/src/NativeEditorBridge.ts +93 -0
- package/src/NativeEditorCollaborationTransport.ts +493 -0
- package/src/NativeEditorCreateConfig.ts +326 -0
- package/src/NativeEditorCreateJson.ts +579 -0
- package/src/NativeEditorCreateValidation.ts +178 -0
- package/src/NativeEditorDocumentBridge.ts +485 -0
- package/src/NativeEditorDocumentHandle.ts +168 -0
- package/src/NativeEditorLocalAwareness.ts +168 -0
- package/src/NativeEditorNativeModule.ts +97 -0
- package/src/NativeEditorRenderNormalization.ts +320 -0
- package/src/NativeEditorResultNormalization.ts +469 -0
- package/src/NativeEditorTypes.ts +366 -0
- package/src/NativeEditorV2Decimal.ts +13 -0
- package/src/NativeProseViewer.tsx +356 -0
- package/src/NativeRichTextEditor.tsx +33 -0
- package/src/ResourceLimits.ts +187 -0
- package/src/RichTextEditor.tsx +27 -0
- package/src/RichTextEditorNativeTypes.tsx +144 -0
- package/src/RichTextEditorNativeView.tsx +21 -0
- package/src/RichTextEditorSerialization.tsx +381 -0
- package/src/RichTextEditorTypes.tsx +327 -0
- package/src/ViewerConfiguration.ts +23 -0
- package/src/YjsCollaboration.ts +692 -0
- package/src/addons.ts +311 -0
- package/src/atomConstants.ts +3 -0
- package/src/atomInstances.ts +123 -0
- package/src/atomPolicy.ts +47 -0
- package/src/atomUpdates.ts +52 -0
- package/src/atoms.ts +379 -0
- package/src/attributeValidation.ts +116 -0
- package/src/contentExpression.ts +338 -0
- package/src/index.ts +295 -0
- package/src/listMarkers.ts +18 -0
- package/src/schemaDefinition.ts +395 -0
- package/src/schemaDocument.ts +92 -0
- package/src/schemaDocumentConstruction.ts +148 -0
- package/src/schemaNormalization.ts +367 -0
- package/src/schemaPresets.ts +250 -0
- package/src/schemaResolution.ts +242 -0
- package/src/schemas.ts +43 -0
- package/src/specs/PreparedProseViewerNativeComponent.ts +40 -0
- package/src/useEditorToolbarInteractions.tsx +329 -0
- package/src/useEditorToolbarItems.tsx +390 -0
- package/src/useEditorToolbarPresentation.tsx +483 -0
- package/src/useEditorToolbarState.tsx +172 -0
- package/src/useFocusPreservingFrames.ts +171 -0
- package/src/useNativeEditor.ts +534 -0
- package/src/useRichTextEditorCommands.tsx +478 -0
- package/src/useRichTextEditorEvents.tsx +342 -0
- package/src/useRichTextEditorMentions.tsx +441 -0
- package/src/useRichTextEditorPresentation.tsx +563 -0
- package/src/useRichTextEditorState.tsx +620 -0
- package/src/useRichTextEditorUpdates.tsx +403 -0
- package/src/useViewerAtoms.tsx +427 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import UIKit
|
|
3
|
+
|
|
4
|
+
extension EditorTextView {
|
|
5
|
+
func shouldUseSmallPatchTextMutation(
|
|
6
|
+
for attributedString: NSAttributedString,
|
|
7
|
+
replaceRange: NSRange?
|
|
8
|
+
) -> Bool {
|
|
9
|
+
attributedString.length > 0
|
|
10
|
+
&& attributedString.length <= 512
|
|
11
|
+
&& (replaceRange?.length ?? 0) <= 512
|
|
12
|
+
&& !attributedStringContainsAttachment(attributedString)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
private func attributesEqualForPatchTrimming(
|
|
16
|
+
_ lhs: [NSAttributedString.Key: Any],
|
|
17
|
+
_ rhs: [NSAttributedString.Key: Any]
|
|
18
|
+
) -> Bool {
|
|
19
|
+
// `docPos` and `topLevelChildIndex` are positional metadata consumed
|
|
20
|
+
// by atom actions and future patch-range resolution. Trimming across
|
|
21
|
+
// either change would preserve stale attributed metadata.
|
|
22
|
+
NSDictionary(dictionary: lhs).isEqual(to: rhs)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func applyAttributes(from attributedString: NSAttributedString, to destinationRange: NSRange) {
|
|
26
|
+
guard attributedString.length == destinationRange.length else { return }
|
|
27
|
+
if let uniformAttributes = uniformAttributes(in: attributedString) {
|
|
28
|
+
textStorage.setAttributes(uniformAttributes, range: destinationRange)
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
let sourceRange = NSRange(location: 0, length: attributedString.length)
|
|
32
|
+
attributedString.enumerateAttributes(
|
|
33
|
+
in: sourceRange,
|
|
34
|
+
options: [.longestEffectiveRangeNotRequired]
|
|
35
|
+
) { attrs, range, _ in
|
|
36
|
+
let targetRange = NSRange(location: destinationRange.location + range.location, length: range.length)
|
|
37
|
+
textStorage.setAttributes(attrs, range: targetRange)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private func uniformAttributes(in attributedString: NSAttributedString) -> [NSAttributedString.Key: Any]? {
|
|
42
|
+
guard attributedString.length > 0 else { return [:] }
|
|
43
|
+
let firstAttributes = attributedString.attributes(at: 0, effectiveRange: nil)
|
|
44
|
+
var isUniform = true
|
|
45
|
+
attributedString.enumerateAttributes(
|
|
46
|
+
in: NSRange(location: 0, length: attributedString.length),
|
|
47
|
+
options: [.longestEffectiveRangeNotRequired]
|
|
48
|
+
) { attrs, _, stop in
|
|
49
|
+
guard (attrs as NSDictionary).isEqual(firstAttributes) else {
|
|
50
|
+
isUniform = false
|
|
51
|
+
stop.pointee = true
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return isUniform ? firstAttributes : nil
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
func attributedStringContainsAttachment(_ attributedString: NSAttributedString) -> Bool {
|
|
59
|
+
guard attributedString.length > 0 else { return false }
|
|
60
|
+
var hasAttachment = false
|
|
61
|
+
attributedString.enumerateAttribute(
|
|
62
|
+
.attachment,
|
|
63
|
+
in: NSRange(location: 0, length: attributedString.length),
|
|
64
|
+
options: [.longestEffectiveRangeNotRequired]
|
|
65
|
+
) { value, _, stop in
|
|
66
|
+
if value != nil {
|
|
67
|
+
hasAttachment = true
|
|
68
|
+
stop.pointee = true
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return hasAttachment
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
func attributedStringContainsPositionAdjustments(_ attributedString: NSAttributedString) -> Bool {
|
|
75
|
+
guard attributedString.length > 0 else { return false }
|
|
76
|
+
var hasAdjustments = false
|
|
77
|
+
attributedString.enumerateAttributes(
|
|
78
|
+
in: NSRange(location: 0, length: attributedString.length),
|
|
79
|
+
options: [.longestEffectiveRangeNotRequired]
|
|
80
|
+
) { attrs, _, stop in
|
|
81
|
+
if attrs[RenderBridgeAttributes.syntheticPlaceholder] as? Bool == true
|
|
82
|
+
|| attrs[RenderBridgeAttributes.listMarkerContext] != nil {
|
|
83
|
+
hasAdjustments = true
|
|
84
|
+
stop.pointee = true
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return hasAdjustments
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
func attributedStringContainsListMarkerContext(_ attributedString: NSAttributedString) -> Bool {
|
|
91
|
+
guard attributedString.length > 0 else { return false }
|
|
92
|
+
var hasListMarkerContext = false
|
|
93
|
+
attributedString.enumerateAttribute(
|
|
94
|
+
RenderBridgeAttributes.listMarkerContext,
|
|
95
|
+
in: NSRange(location: 0, length: attributedString.length),
|
|
96
|
+
options: [.longestEffectiveRangeNotRequired]
|
|
97
|
+
) { value, _, stop in
|
|
98
|
+
if value != nil {
|
|
99
|
+
hasListMarkerContext = true
|
|
100
|
+
stop.pointee = true
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return hasListMarkerContext
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
func textStorageRangeContainsPositionAdjustments(_ range: NSRange) -> Bool {
|
|
107
|
+
guard range.length > 0,
|
|
108
|
+
range.location >= 0,
|
|
109
|
+
range.location + range.length <= textStorage.length
|
|
110
|
+
else {
|
|
111
|
+
return false
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
var hasAdjustments = false
|
|
115
|
+
textStorage.enumerateAttributes(
|
|
116
|
+
in: range,
|
|
117
|
+
options: [.longestEffectiveRangeNotRequired]
|
|
118
|
+
) { attrs, _, stop in
|
|
119
|
+
if attrs[RenderBridgeAttributes.syntheticPlaceholder] as? Bool == true
|
|
120
|
+
|| attrs[RenderBridgeAttributes.listMarkerContext] != nil {
|
|
121
|
+
hasAdjustments = true
|
|
122
|
+
stop.pointee = true
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return hasAdjustments
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
func textStorageRangeContainsListMarkerContext(_ range: NSRange) -> Bool {
|
|
129
|
+
guard range.length > 0,
|
|
130
|
+
range.location >= 0,
|
|
131
|
+
range.location + range.length <= textStorage.length
|
|
132
|
+
else {
|
|
133
|
+
return false
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
var hasListMarkerContext = false
|
|
137
|
+
textStorage.enumerateAttribute(
|
|
138
|
+
RenderBridgeAttributes.listMarkerContext,
|
|
139
|
+
in: range,
|
|
140
|
+
options: [.longestEffectiveRangeNotRequired]
|
|
141
|
+
) { value, _, stop in
|
|
142
|
+
if value != nil {
|
|
143
|
+
hasListMarkerContext = true
|
|
144
|
+
stop.pointee = true
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return hasListMarkerContext
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
func textStorageRangeContainsAttachment(_ range: NSRange) -> Bool {
|
|
151
|
+
guard range.length > 0,
|
|
152
|
+
range.location >= 0,
|
|
153
|
+
range.location + range.length <= textStorage.length
|
|
154
|
+
else {
|
|
155
|
+
return false
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
var hasAttachment = false
|
|
159
|
+
textStorage.enumerateAttribute(
|
|
160
|
+
.attachment,
|
|
161
|
+
in: range,
|
|
162
|
+
options: [.longestEffectiveRangeNotRequired]
|
|
163
|
+
) { value, _, stop in
|
|
164
|
+
if value != nil {
|
|
165
|
+
hasAttachment = true
|
|
166
|
+
stop.pointee = true
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return hasAttachment
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
func topLevelChildrenContainAttachment(
|
|
173
|
+
startIndex: Int,
|
|
174
|
+
deleteCount: Int
|
|
175
|
+
) -> Bool {
|
|
176
|
+
guard deleteCount > 0,
|
|
177
|
+
let currentTopLevelChildMetadata,
|
|
178
|
+
startIndex >= 0,
|
|
179
|
+
startIndex + deleteCount <= currentTopLevelChildMetadata.count
|
|
180
|
+
else {
|
|
181
|
+
return false
|
|
182
|
+
}
|
|
183
|
+
return currentTopLevelChildMetadata[startIndex..<(startIndex + deleteCount)]
|
|
184
|
+
.contains(where: \.containsAttachment)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
func topLevelChildrenContainPositionAdjustments(
|
|
188
|
+
startIndex: Int,
|
|
189
|
+
deleteCount: Int
|
|
190
|
+
) -> Bool {
|
|
191
|
+
guard deleteCount > 0,
|
|
192
|
+
let currentTopLevelChildMetadata,
|
|
193
|
+
startIndex >= 0,
|
|
194
|
+
startIndex + deleteCount <= currentTopLevelChildMetadata.count
|
|
195
|
+
else {
|
|
196
|
+
return false
|
|
197
|
+
}
|
|
198
|
+
return currentTopLevelChildMetadata[startIndex..<(startIndex + deleteCount)]
|
|
199
|
+
.contains(where: \.containsPositionAdjustments)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
func trimmedAttributedPatch(
|
|
203
|
+
replacing fullReplaceRange: NSRange,
|
|
204
|
+
with replacement: NSAttributedString
|
|
205
|
+
) -> (replaceRange: NSRange, replacement: NSAttributedString) {
|
|
206
|
+
guard fullReplaceRange.length > 0 else {
|
|
207
|
+
return (fullReplaceRange, replacement)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
let existing = textStorage.attributedSubstring(from: fullReplaceRange)
|
|
211
|
+
let existingRawString = existing.string
|
|
212
|
+
let replacementRawString = replacement.string
|
|
213
|
+
let existingString = existingRawString as NSString
|
|
214
|
+
let replacementString = replacementRawString as NSString
|
|
215
|
+
let sharedLength = min(existing.length, replacement.length)
|
|
216
|
+
|
|
217
|
+
var prefix = 0
|
|
218
|
+
while prefix < sharedLength {
|
|
219
|
+
var existingRange = NSRange()
|
|
220
|
+
let existingAttrs = existing.attributes(
|
|
221
|
+
at: prefix,
|
|
222
|
+
longestEffectiveRange: &existingRange,
|
|
223
|
+
in: NSRange(location: prefix, length: sharedLength - prefix)
|
|
224
|
+
)
|
|
225
|
+
var replacementRange = NSRange()
|
|
226
|
+
let replacementAttrs = replacement.attributes(
|
|
227
|
+
at: prefix,
|
|
228
|
+
longestEffectiveRange: &replacementRange,
|
|
229
|
+
in: NSRange(location: prefix, length: sharedLength - prefix)
|
|
230
|
+
)
|
|
231
|
+
guard attributesEqualForPatchTrimming(existingAttrs, replacementAttrs) else { break }
|
|
232
|
+
let runEnd = min(NSMaxRange(existingRange), NSMaxRange(replacementRange), sharedLength)
|
|
233
|
+
while prefix < runEnd,
|
|
234
|
+
existingString.character(at: prefix) == replacementString.character(at: prefix) {
|
|
235
|
+
prefix += 1
|
|
236
|
+
}
|
|
237
|
+
if prefix < runEnd {
|
|
238
|
+
break
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
var suffix = 0
|
|
243
|
+
while suffix < (sharedLength - prefix) {
|
|
244
|
+
let existingIndex = existing.length - suffix - 1
|
|
245
|
+
let replacementIndex = replacement.length - suffix - 1
|
|
246
|
+
var existingRange = NSRange()
|
|
247
|
+
let existingAttrs = existing.attributes(
|
|
248
|
+
at: existingIndex,
|
|
249
|
+
longestEffectiveRange: &existingRange,
|
|
250
|
+
in: NSRange(location: prefix, length: existingIndex - prefix + 1)
|
|
251
|
+
)
|
|
252
|
+
var replacementRange = NSRange()
|
|
253
|
+
let replacementAttrs = replacement.attributes(
|
|
254
|
+
at: replacementIndex,
|
|
255
|
+
longestEffectiveRange: &replacementRange,
|
|
256
|
+
in: NSRange(location: prefix, length: replacementIndex - prefix + 1)
|
|
257
|
+
)
|
|
258
|
+
guard attributesEqualForPatchTrimming(existingAttrs, replacementAttrs) else { break }
|
|
259
|
+
let maxComparableLength = min(
|
|
260
|
+
existingIndex - max(existingRange.location, prefix) + 1,
|
|
261
|
+
replacementIndex - max(replacementRange.location, prefix) + 1,
|
|
262
|
+
sharedLength - prefix - suffix
|
|
263
|
+
)
|
|
264
|
+
var matchedLength = 0
|
|
265
|
+
while matchedLength < maxComparableLength,
|
|
266
|
+
existingString.character(at: existingIndex - matchedLength)
|
|
267
|
+
== replacementString.character(at: replacementIndex - matchedLength) {
|
|
268
|
+
matchedLength += 1
|
|
269
|
+
}
|
|
270
|
+
suffix += matchedLength
|
|
271
|
+
if matchedLength < maxComparableLength {
|
|
272
|
+
break
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
prefix = sharedUtf16ScalarBoundary(atOrBefore: prefix, in: existingRawString, and: replacementRawString)
|
|
276
|
+
while suffix > 0 {
|
|
277
|
+
let existingSuffixStart = existing.length - suffix
|
|
278
|
+
let replacementSuffixStart = replacement.length - suffix
|
|
279
|
+
if suffix <= sharedLength - prefix,
|
|
280
|
+
isUtf16ScalarBoundary(existingSuffixStart, in: existingRawString),
|
|
281
|
+
isUtf16ScalarBoundary(replacementSuffixStart, in: replacementRawString) {
|
|
282
|
+
break
|
|
283
|
+
}
|
|
284
|
+
suffix -= 1
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
guard prefix > 0 || suffix > 0 else {
|
|
288
|
+
return (fullReplaceRange, replacement)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
let trimmedReplaceRange = NSRange(
|
|
292
|
+
location: fullReplaceRange.location + prefix,
|
|
293
|
+
length: fullReplaceRange.length - prefix - suffix
|
|
294
|
+
)
|
|
295
|
+
let trimmedReplacementRange = NSRange(
|
|
296
|
+
location: prefix,
|
|
297
|
+
length: replacement.length - prefix - suffix
|
|
298
|
+
)
|
|
299
|
+
return (
|
|
300
|
+
trimmedReplaceRange,
|
|
301
|
+
replacement.attributedSubstring(from: trimmedReplacementRange)
|
|
302
|
+
)
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import UIKit
|
|
3
|
+
|
|
4
|
+
extension EditorTextView {
|
|
5
|
+
func ownsNativeBinding(_ adapter: EditorV2Adapter) -> Bool {
|
|
6
|
+
adapter.isNativeBindingOwner(token: nativeBindingToken)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/// Bind this text view to a Rust editor instance and apply initial content.
|
|
10
|
+
///
|
|
11
|
+
/// - Parameters:
|
|
12
|
+
/// - id: The editor ID from `editor_create()`.
|
|
13
|
+
/// - initialHTML: Optional HTML to set as initial content.
|
|
14
|
+
func bindEditor(
|
|
15
|
+
id: UInt64,
|
|
16
|
+
initialHTML: String? = nil,
|
|
17
|
+
initialUpdateJSON: String? = nil
|
|
18
|
+
) {
|
|
19
|
+
ensureInternalTextViewDelegate()
|
|
20
|
+
if editorId == id, initialHTML == nil {
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
localTextDragState = .idle
|
|
24
|
+
if editorId != id {
|
|
25
|
+
EditorV2Registry.adapter(forLegacyId: editorId)?
|
|
26
|
+
.releaseNativeBindingOwner(token: nativeBindingToken)
|
|
27
|
+
discardTransientNativeInputForEditorRebind()
|
|
28
|
+
invalidateCurrentRenderBlocks()
|
|
29
|
+
}
|
|
30
|
+
editorId = id
|
|
31
|
+
EditorV2Registry.adapter(forLegacyId: id)?
|
|
32
|
+
.claimNativeBindingIfUnowned(token: nativeBindingToken)
|
|
33
|
+
|
|
34
|
+
if let initialUpdateJSON {
|
|
35
|
+
applyUpdateJSON(initialUpdateJSON, notifyDelegate: false)
|
|
36
|
+
} else if let html = initialHTML, !html.isEmpty {
|
|
37
|
+
let updateJSON = EditorV2Shadow.setHtml(id: editorId, html: html)
|
|
38
|
+
if !applyUpdateJSON(updateJSON, notifyDelegate: false) {
|
|
39
|
+
let stateJSON = EditorV2Shadow.getCurrentState(id: editorId)
|
|
40
|
+
applyUpdateJSON(stateJSON, notifyDelegate: false)
|
|
41
|
+
}
|
|
42
|
+
} else {
|
|
43
|
+
// Pull current state from Rust (content may already be loaded via bridge).
|
|
44
|
+
let stateJSON = EditorV2Shadow.getCurrentState(id: editorId)
|
|
45
|
+
applyUpdateJSON(stateJSON, notifyDelegate: false)
|
|
46
|
+
}
|
|
47
|
+
replayDesiredInputTraitsIfNeeded()
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/// Unbind from the current editor instance.
|
|
51
|
+
func unbindEditor() {
|
|
52
|
+
codeHighlightingSession.cancel()
|
|
53
|
+
restoreCodeHighlighting()
|
|
54
|
+
discardTransientNativeInputForEditorRebind()
|
|
55
|
+
EditorV2Registry.adapter(forLegacyId: editorId)?
|
|
56
|
+
.releaseNativeBindingOwner(token: nativeBindingToken)
|
|
57
|
+
invalidateCurrentRenderBlocks()
|
|
58
|
+
editorId = 0
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
}
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import UIKit
|
|
3
|
+
|
|
4
|
+
extension EditorTextView {
|
|
5
|
+
func resolvedCaretReferenceRect(for position: UITextPosition) -> CGRect {
|
|
6
|
+
let directRect = super.caretRect(for: position)
|
|
7
|
+
if let horizontalRuleRect = resolvedHorizontalRuleAdjacentCaretRect(
|
|
8
|
+
for: position,
|
|
9
|
+
directRect: directRect
|
|
10
|
+
) {
|
|
11
|
+
return horizontalRuleRect
|
|
12
|
+
}
|
|
13
|
+
guard directRect.height <= 0 || directRect.isEmpty else {
|
|
14
|
+
return directRect
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let caretWidth = max(directRect.width, 2)
|
|
18
|
+
|
|
19
|
+
if let nextPosition = self.position(from: position, offset: 1),
|
|
20
|
+
let nextRange = textRange(from: position, to: nextPosition),
|
|
21
|
+
let nextRect = selectionRects(for: nextRange)
|
|
22
|
+
.map(\.rect)
|
|
23
|
+
.first(where: { !$0.isEmpty && $0.width > 0 && $0.height > 0 }) {
|
|
24
|
+
return CGRect(
|
|
25
|
+
x: nextRect.minX,
|
|
26
|
+
y: nextRect.minY,
|
|
27
|
+
width: caretWidth,
|
|
28
|
+
height: max(directRect.height, nextRect.height)
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if let previousPosition = self.position(from: position, offset: -1),
|
|
33
|
+
let previousRange = textRange(from: previousPosition, to: position),
|
|
34
|
+
let previousRect = selectionRects(for: previousRange)
|
|
35
|
+
.map(\.rect)
|
|
36
|
+
.last(where: { !$0.isEmpty && $0.width > 0 && $0.height > 0 }) {
|
|
37
|
+
return CGRect(
|
|
38
|
+
x: previousRect.maxX,
|
|
39
|
+
y: previousRect.minY,
|
|
40
|
+
width: caretWidth,
|
|
41
|
+
height: max(directRect.height, previousRect.height)
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return directRect
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private func resolvedHorizontalRuleAdjacentCaretRect(
|
|
49
|
+
for position: UITextPosition,
|
|
50
|
+
directRect: CGRect
|
|
51
|
+
) -> CGRect? {
|
|
52
|
+
guard textStorage.length > 0 else { return nil }
|
|
53
|
+
|
|
54
|
+
let utf16Offset = offset(from: beginningOfDocument, to: position)
|
|
55
|
+
let caretWidth = max(directRect.width, 2)
|
|
56
|
+
|
|
57
|
+
if isHorizontalRuleAttachment(at: utf16Offset),
|
|
58
|
+
let previousCharacterIndex = nearestVisibleCharacterIndex(
|
|
59
|
+
from: utf16Offset - 1,
|
|
60
|
+
direction: -1
|
|
61
|
+
),
|
|
62
|
+
let previousRect = visibleSelectionRect(forCharacterAt: previousCharacterIndex) {
|
|
63
|
+
return CGRect(
|
|
64
|
+
x: previousRect.maxX,
|
|
65
|
+
y: previousRect.minY,
|
|
66
|
+
width: caretWidth,
|
|
67
|
+
height: max(directRect.height, previousRect.height)
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if isHorizontalRuleAttachment(at: utf16Offset - 1),
|
|
72
|
+
let nextCharacterIndex = nearestVisibleCharacterIndex(
|
|
73
|
+
from: utf16Offset,
|
|
74
|
+
direction: 1
|
|
75
|
+
),
|
|
76
|
+
let nextRect = visibleSelectionRect(forCharacterAt: nextCharacterIndex) {
|
|
77
|
+
return CGRect(
|
|
78
|
+
x: nextRect.minX,
|
|
79
|
+
y: nextRect.minY,
|
|
80
|
+
width: caretWidth,
|
|
81
|
+
height: max(directRect.height, nextRect.height)
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return nil
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static func adjustedCaretRect(
|
|
89
|
+
from rect: CGRect,
|
|
90
|
+
targetHeight: CGFloat,
|
|
91
|
+
screenScale: CGFloat
|
|
92
|
+
) -> CGRect {
|
|
93
|
+
guard rect.height > 0, targetHeight > 0, targetHeight < rect.height else {
|
|
94
|
+
return rect
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let scale = max(screenScale, 1)
|
|
98
|
+
let alignedHeight = ceil(targetHeight * scale) / scale
|
|
99
|
+
let centeredY = rect.minY + ((rect.height - alignedHeight) / 2.0)
|
|
100
|
+
let alignedY = (centeredY * scale).rounded() / scale
|
|
101
|
+
|
|
102
|
+
var adjusted = rect
|
|
103
|
+
adjusted.origin.y = alignedY
|
|
104
|
+
adjusted.size.height = alignedHeight
|
|
105
|
+
return adjusted
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
static func adjustedCaretRect(
|
|
109
|
+
from rect: CGRect,
|
|
110
|
+
font: UIFont,
|
|
111
|
+
screenScale: CGFloat
|
|
112
|
+
) -> CGRect {
|
|
113
|
+
let scale = max(screenScale, 1)
|
|
114
|
+
let lineHeight = max(font.lineHeight, 0)
|
|
115
|
+
let alignedHeight = ceil(lineHeight * scale) / scale
|
|
116
|
+
let alignedY = ((rect.maxY - alignedHeight) * scale).rounded() / scale
|
|
117
|
+
|
|
118
|
+
var adjusted = rect
|
|
119
|
+
adjusted.origin.y = alignedY
|
|
120
|
+
adjusted.size.height = alignedHeight
|
|
121
|
+
return adjusted
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
static func adjustedCaretRect(
|
|
125
|
+
from rect: CGRect,
|
|
126
|
+
baselineY: CGFloat,
|
|
127
|
+
font: UIFont,
|
|
128
|
+
screenScale: CGFloat
|
|
129
|
+
) -> CGRect {
|
|
130
|
+
let scale = max(screenScale, 1)
|
|
131
|
+
let lineHeight = max(font.lineHeight, 0)
|
|
132
|
+
let alignedHeight = ceil(lineHeight * scale) / scale
|
|
133
|
+
let typographicHeight = font.ascender - font.descender
|
|
134
|
+
let leading = max(lineHeight - typographicHeight, 0)
|
|
135
|
+
let topY = baselineY - font.ascender - (leading / 2.0)
|
|
136
|
+
let alignedY = (topY * scale).rounded() / scale
|
|
137
|
+
|
|
138
|
+
var adjusted = rect
|
|
139
|
+
adjusted.origin.y = alignedY
|
|
140
|
+
adjusted.size.height = alignedHeight
|
|
141
|
+
return adjusted
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
func caretBaselineY(for position: UITextPosition, referenceRect: CGRect) -> CGFloat? {
|
|
145
|
+
guard textStorage.length > 0 else { return nil }
|
|
146
|
+
|
|
147
|
+
let rawOffset = offset(from: beginningOfDocument, to: position)
|
|
148
|
+
let clampedOffset = min(max(rawOffset, 0), textStorage.length)
|
|
149
|
+
|
|
150
|
+
if let horizontalRuleBaselineY = horizontalRuleAdjacentBaselineY(at: clampedOffset) {
|
|
151
|
+
return horizontalRuleBaselineY
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if let hardBreakBaselineY = hardBreakBaselineY(after: clampedOffset) {
|
|
155
|
+
return hardBreakBaselineY
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
var candidateCharacters = Set<Int>()
|
|
159
|
+
|
|
160
|
+
if clampedOffset < textStorage.length {
|
|
161
|
+
candidateCharacters.insert(clampedOffset)
|
|
162
|
+
}
|
|
163
|
+
if clampedOffset > 0 {
|
|
164
|
+
candidateCharacters.insert(clampedOffset - 1)
|
|
165
|
+
}
|
|
166
|
+
if clampedOffset + 1 < textStorage.length {
|
|
167
|
+
candidateCharacters.insert(clampedOffset + 1)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
guard !candidateCharacters.isEmpty else { return nil }
|
|
171
|
+
|
|
172
|
+
let referenceMidY = referenceRect.midY
|
|
173
|
+
let referenceMinY = referenceRect.minY
|
|
174
|
+
var bestMatch: (score: CGFloat, baselineY: CGFloat)?
|
|
175
|
+
|
|
176
|
+
for characterIndex in candidateCharacters.sorted() {
|
|
177
|
+
let glyphIndex = layoutManager.glyphIndexForCharacter(at: characterIndex)
|
|
178
|
+
guard glyphIndex < layoutManager.numberOfGlyphs else { continue }
|
|
179
|
+
|
|
180
|
+
let lineFragmentRect = layoutManager.lineFragmentRect(
|
|
181
|
+
forGlyphAt: glyphIndex,
|
|
182
|
+
effectiveRange: nil
|
|
183
|
+
)
|
|
184
|
+
let lineRectInView = lineFragmentRect.offsetBy(dx: 0, dy: textContainerInset.top)
|
|
185
|
+
let score = abs(lineRectInView.midY - referenceMidY) * 10
|
|
186
|
+
+ abs(lineRectInView.minY - referenceMinY)
|
|
187
|
+
let glyphLocation = layoutManager.location(forGlyphAt: glyphIndex)
|
|
188
|
+
let baselineY = textContainerInset.top + lineFragmentRect.minY + glyphLocation.y
|
|
189
|
+
|
|
190
|
+
if let currentBest = bestMatch, currentBest.score <= score {
|
|
191
|
+
continue
|
|
192
|
+
}
|
|
193
|
+
bestMatch = (score, baselineY)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return bestMatch?.baselineY
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private func horizontalRuleAdjacentBaselineY(at utf16Offset: Int) -> CGFloat? {
|
|
200
|
+
guard textStorage.length > 0 else { return nil }
|
|
201
|
+
|
|
202
|
+
if isHorizontalRuleAttachment(at: utf16Offset),
|
|
203
|
+
let previousCharacterIndex = nearestVisibleCharacterIndex(
|
|
204
|
+
from: utf16Offset - 1,
|
|
205
|
+
direction: -1
|
|
206
|
+
) {
|
|
207
|
+
return baselineY(forCharacterAt: previousCharacterIndex)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if isHorizontalRuleAttachment(at: utf16Offset - 1),
|
|
211
|
+
let nextCharacterIndex = nearestVisibleCharacterIndex(
|
|
212
|
+
from: utf16Offset,
|
|
213
|
+
direction: 1
|
|
214
|
+
) {
|
|
215
|
+
return baselineY(forCharacterAt: nextCharacterIndex)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return nil
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
func baselineY(forCharacterAt characterIndex: Int) -> CGFloat? {
|
|
222
|
+
guard characterIndex >= 0, characterIndex < textStorage.length else { return nil }
|
|
223
|
+
|
|
224
|
+
let glyphIndex = layoutManager.glyphIndexForCharacter(at: characterIndex)
|
|
225
|
+
guard glyphIndex < layoutManager.numberOfGlyphs else { return nil }
|
|
226
|
+
|
|
227
|
+
let lineFragmentRect = layoutManager.lineFragmentRect(
|
|
228
|
+
forGlyphAt: glyphIndex,
|
|
229
|
+
effectiveRange: nil
|
|
230
|
+
)
|
|
231
|
+
let glyphLocation = layoutManager.location(forGlyphAt: glyphIndex)
|
|
232
|
+
return textContainerInset.top + lineFragmentRect.minY + glyphLocation.y
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private func visibleSelectionRect(forCharacterAt characterIndex: Int) -> CGRect? {
|
|
236
|
+
guard characterIndex >= 0, characterIndex < textStorage.length else { return nil }
|
|
237
|
+
guard let start = position(from: beginningOfDocument, offset: characterIndex),
|
|
238
|
+
let end = position(from: start, offset: 1),
|
|
239
|
+
let range = textRange(from: start, to: end)
|
|
240
|
+
else {
|
|
241
|
+
return nil
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return selectionRects(for: range)
|
|
245
|
+
.map(\.rect)
|
|
246
|
+
.first(where: { !$0.isEmpty && $0.width > 0 && $0.height > 0 })
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
private func nearestVisibleCharacterIndex(from startIndex: Int, direction: Int) -> Int? {
|
|
250
|
+
guard direction == -1 || direction == 1 else { return nil }
|
|
251
|
+
guard textStorage.length > 0 else { return nil }
|
|
252
|
+
|
|
253
|
+
let text = textStorage.string as NSString
|
|
254
|
+
var index = startIndex
|
|
255
|
+
|
|
256
|
+
while index >= 0, index < text.length {
|
|
257
|
+
let attrs = textStorage.attributes(at: index, effectiveRange: nil)
|
|
258
|
+
let character = text.substring(with: NSRange(location: index, length: 1))
|
|
259
|
+
|
|
260
|
+
if attrs[.attachment] == nil,
|
|
261
|
+
character != "\n",
|
|
262
|
+
character != "\r",
|
|
263
|
+
visibleSelectionRect(forCharacterAt: index) != nil {
|
|
264
|
+
return index
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
index += direction
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return nil
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
private func isHorizontalRuleAttachment(at utf16Offset: Int) -> Bool {
|
|
274
|
+
guard utf16Offset >= 0, utf16Offset < textStorage.length else { return false }
|
|
275
|
+
|
|
276
|
+
let attrs = textStorage.attributes(at: utf16Offset, effectiveRange: nil)
|
|
277
|
+
return attrs[.attachment] is NSTextAttachment
|
|
278
|
+
&& EditorNodeTypes.isHorizontalRule(attrs[RenderBridgeAttributes.voidNodeType] as? String)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
private func hardBreakBaselineY(after utf16Offset: Int) -> CGFloat? {
|
|
282
|
+
guard utf16Offset > 0, utf16Offset <= textStorage.length else { return nil }
|
|
283
|
+
let previousVoidType = textStorage.attribute(
|
|
284
|
+
RenderBridgeAttributes.voidNodeType,
|
|
285
|
+
at: utf16Offset - 1,
|
|
286
|
+
effectiveRange: nil
|
|
287
|
+
) as? String
|
|
288
|
+
guard EditorNodeTypes.isHardBreak(previousVoidType) else { return nil }
|
|
289
|
+
|
|
290
|
+
let previousGlyphIndex = layoutManager.glyphIndexForCharacter(at: utf16Offset - 1)
|
|
291
|
+
guard previousGlyphIndex < layoutManager.numberOfGlyphs else { return nil }
|
|
292
|
+
|
|
293
|
+
let lineFragmentRect = layoutManager.lineFragmentRect(
|
|
294
|
+
forGlyphAt: previousGlyphIndex,
|
|
295
|
+
effectiveRange: nil
|
|
296
|
+
)
|
|
297
|
+
let glyphLocation = layoutManager.location(forGlyphAt: previousGlyphIndex)
|
|
298
|
+
let previousBaselineY = textContainerInset.top + lineFragmentRect.minY + glyphLocation.y
|
|
299
|
+
|
|
300
|
+
let paragraphStyle = textStorage.attribute(
|
|
301
|
+
.paragraphStyle,
|
|
302
|
+
at: utf16Offset - 1,
|
|
303
|
+
effectiveRange: nil
|
|
304
|
+
) as? NSParagraphStyle
|
|
305
|
+
let configuredLineHeight = max(
|
|
306
|
+
paragraphStyle?.minimumLineHeight ?? 0,
|
|
307
|
+
paragraphStyle?.maximumLineHeight ?? 0
|
|
308
|
+
)
|
|
309
|
+
let lineAdvance = configuredLineHeight > 0
|
|
310
|
+
? configuredLineHeight
|
|
311
|
+
: lineFragmentRect.height
|
|
312
|
+
|
|
313
|
+
return previousBaselineY + lineAdvance
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
func resolvedCaretFont(for position: UITextPosition) -> UIFont {
|
|
317
|
+
guard textStorage.length > 0 else { return resolvedDefaultFont() }
|
|
318
|
+
|
|
319
|
+
let offset = offset(from: beginningOfDocument, to: position)
|
|
320
|
+
let attributeIndex: Int
|
|
321
|
+
if offset <= 0 {
|
|
322
|
+
attributeIndex = 0
|
|
323
|
+
} else if offset < textStorage.length {
|
|
324
|
+
attributeIndex = offset
|
|
325
|
+
} else {
|
|
326
|
+
attributeIndex = textStorage.length - 1
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return (textStorage.attribute(.font, at: attributeIndex, effectiveRange: nil) as? UIFont)
|
|
330
|
+
?? resolvedDefaultFont()
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
}
|