@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,639 @@
|
|
|
1
|
+
import CoreText
|
|
2
|
+
import UIKit
|
|
3
|
+
|
|
4
|
+
/// Mapping/reference overhead only. Decoded image allocations are owned and
|
|
5
|
+
/// accounted for by the shared native image cache.
|
|
6
|
+
internal enum PreparedProseImagePixelMapAccounting {
|
|
7
|
+
static let mapRetainedBytes = 48
|
|
8
|
+
static let entryRetainedBytes = 48
|
|
9
|
+
|
|
10
|
+
static func retainedBytes(entryCount: Int) -> Int {
|
|
11
|
+
guard entryCount > 0 else { return 0 }
|
|
12
|
+
return saturatingAdd(
|
|
13
|
+
mapRetainedBytes,
|
|
14
|
+
saturatingMultiply(entryCount, entryRetainedBytes)
|
|
15
|
+
)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
private static func saturatingAdd(_ left: Int, _ right: Int) -> Int {
|
|
19
|
+
guard left <= Int.max - right else { return Int.max }
|
|
20
|
+
return left + right
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private static func saturatingMultiply(_ left: Int, _ right: Int) -> Int {
|
|
24
|
+
guard left > 0, right > 0 else { return 0 }
|
|
25
|
+
guard left <= Int.max / right else { return Int.max }
|
|
26
|
+
return left * right
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@objc public protocol PreparedProseDrawingViewInteractionDelegate: AnyObject {
|
|
31
|
+
func preparedProseDrawingView(_ view: PreparedProseDrawingView, didActivateLink href: String, text: String) -> Bool
|
|
32
|
+
func preparedProseDrawingView(_ view: PreparedProseDrawingView, didActivateMention docPos: UInt32, label: String, attrsJSON: String) -> Bool
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// A rendering-only view: it consumes already prepared Core Text lines.
|
|
36
|
+
@objc(PREPPreparedProseDrawingView)
|
|
37
|
+
public final class PreparedProseDrawingView: UIView {
|
|
38
|
+
let codeHighlightingSession = NativeCodeHighlightingSession()
|
|
39
|
+
var onCodeHighlightingResolved: ((String) -> Void)?
|
|
40
|
+
var onCodeHighlightingFailure: ((Error) -> Void)?
|
|
41
|
+
@objc public static let codeHighlightingDidResolve = Notification.Name("com.apollohg.editor.viewer.codeHighlightingDidResolve")
|
|
42
|
+
@objc public static let codeHighlightingDidFail = Notification.Name("com.apollohg.editor.viewer.codeHighlightingDidFail")
|
|
43
|
+
|
|
44
|
+
deinit { codeHighlightingSession.cancel() }
|
|
45
|
+
|
|
46
|
+
var imagePixels: [String: UIImage] = [:] {
|
|
47
|
+
didSet {
|
|
48
|
+
PreparedProseInstrumentation.retained(.image, scope: "drawing-\(ObjectIdentifier(self))", bytes: retainedImagePixelsBytesForTesting)
|
|
49
|
+
setNeedsDisplay()
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/// This map owns only mapping/reference overhead. The shared native image
|
|
53
|
+
/// cache is the sole owner charged for a decoded CGImage allocation.
|
|
54
|
+
internal var retainedImagePixelsBytesForTesting: Int {
|
|
55
|
+
PreparedProseImagePixelMapAccounting.retainedBytes(entryCount: imagePixels.count)
|
|
56
|
+
}
|
|
57
|
+
internal var preparedSurfaceRetainedBytesForTesting: Int {
|
|
58
|
+
Self.saturatingAdd(
|
|
59
|
+
Self.saturatingAdd(layout?.retainedBytes ?? 0, imageRevisions.retainedPublicationBytesForTesting),
|
|
60
|
+
retainedImagePixelsBytesForTesting
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
@objc public static let imageMetadataDidResolve = Notification.Name("com.apollohg.editor.viewer.imageMetadataDidResolve")
|
|
64
|
+
@objc public static let imageResourceDidFail = Notification.Name("com.apollohg.editor.viewer.imageResourceDidFail")
|
|
65
|
+
private lazy var imagePipeline = ViewerImagePipeline(policy: .default)
|
|
66
|
+
private var imageRevisions = ViewerAttachmentRevisionState()
|
|
67
|
+
private var imageGeneration = ""
|
|
68
|
+
private var imageConfiguration: (enabled: Bool, policy: ImageLoadingPolicy) = (false, .default)
|
|
69
|
+
private var scrollObservations: [NSKeyValueObservation] = []
|
|
70
|
+
private var observedScrollViewIDs: [ObjectIdentifier] = []
|
|
71
|
+
var layout: PreparedProseLayout? {
|
|
72
|
+
didSet {
|
|
73
|
+
guard oldValue !== layout else { return }
|
|
74
|
+
PreparedProseInstrumentation.retained(.sidecars, scope: "drawing-\(ObjectIdentifier(self))", bytes: imageRevisions.retainedPublicationBytesForTesting)
|
|
75
|
+
invalidateAccessibilityNodes()
|
|
76
|
+
setNeedsDisplay()
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@objc public func install(layout: PreparedProseLayout?) {
|
|
81
|
+
guard self.layout !== layout else { return }
|
|
82
|
+
self.layout = layout
|
|
83
|
+
scheduleCodeHighlighting()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@objc(configureImagesWithGeneration:imagesEnabled:policyJSON:)
|
|
87
|
+
public func configureImages(generation: String, imagesEnabled: Bool, policyJSON: String?) {
|
|
88
|
+
imageGeneration = generation
|
|
89
|
+
imageConfiguration = (imagesEnabled, ImageLoadingPolicy.from(json: policyJSON))
|
|
90
|
+
imagePipeline.onPixels = { [weak self] attachment, image in self?.imagePixels[attachment.id] = image }
|
|
91
|
+
imagePipeline.onIntrinsicMetadata = { [weak self] attachment, size in
|
|
92
|
+
guard let self,
|
|
93
|
+
self.imagePipeline.acceptsCompletion(generation: generation),
|
|
94
|
+
self.imageRevisions.recordIntrinsicSize(size, for: attachment.id, ordinal: attachment.ordinal, declaredSize: attachment.declaredSize)
|
|
95
|
+
else { return }
|
|
96
|
+
NotificationCenter.default.post(
|
|
97
|
+
name: Self.imageMetadataDidResolve,
|
|
98
|
+
object: self,
|
|
99
|
+
userInfo: ["generation": generation, "revision": self.imageRevisions.revision]
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
imagePipeline.onResourceFailure = { [weak self] attachment in
|
|
103
|
+
guard let self,
|
|
104
|
+
self.imagePipeline.acceptsCompletion(generation: generation),
|
|
105
|
+
self.imageRevisions.recordResourceFailure(for: attachment.ordinal)
|
|
106
|
+
else { return }
|
|
107
|
+
NotificationCenter.default.post(
|
|
108
|
+
name: Self.imageResourceDidFail,
|
|
109
|
+
object: self,
|
|
110
|
+
userInfo: ["generation": generation, "attachment": attachment.id]
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
imagePipeline.begin(
|
|
114
|
+
generation: imageGeneration,
|
|
115
|
+
imagesEnabled: imageConfiguration.enabled,
|
|
116
|
+
policy: imageConfiguration.policy
|
|
117
|
+
)
|
|
118
|
+
imageRevisions.admit(attachmentCount: layout?.imageAttachments.count ?? 0)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/// Phase one of Fabric setup: semantic props/state have been accepted but
|
|
122
|
+
/// no mounted artifact exists yet. This clears active intrinsic fallback
|
|
123
|
+
/// before measurement/preparation and phase two only binds ordinals.
|
|
124
|
+
@objc(beginSemanticImageGeneration:)
|
|
125
|
+
public func beginSemanticImageGeneration(_ generation: String) {
|
|
126
|
+
guard imageRevisions.beginSemanticGeneration(generation) else { return }
|
|
127
|
+
imageGeneration = ""
|
|
128
|
+
imagePipeline.cancel()
|
|
129
|
+
imagePixels = [:]
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/// Fabric has already reset this sidecar during Yoga preparation. Mount
|
|
133
|
+
/// only transfers the stable surface owner; it must not reopen metadata or
|
|
134
|
+
/// error publication by resetting a second time.
|
|
135
|
+
@objc(bindFabricAttachmentStateSurfaceId:componentTag:leaseHandle:)
|
|
136
|
+
public func bindFabricAttachmentState(surfaceId: Int64, componentTag: Int64, leaseHandle: UInt64) {
|
|
137
|
+
guard let state = FabricAttachmentSidecars.state(
|
|
138
|
+
for: .init(surfaceId: surfaceId, componentTag: componentTag),
|
|
139
|
+
leaseHandle: leaseHandle
|
|
140
|
+
) else { return }
|
|
141
|
+
imageRevisions = state
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
@objc public func updateConfiguredImagesForVisibleWindow() {
|
|
145
|
+
refreshScrollObservations()
|
|
146
|
+
guard let layout, let visible = configuredVisibleRect() else {
|
|
147
|
+
imagePipeline.leaveViewport()
|
|
148
|
+
if !imagePixels.isEmpty { imagePixels = [:] }
|
|
149
|
+
onVisibleRectChange?(nil)
|
|
150
|
+
return
|
|
151
|
+
}
|
|
152
|
+
let retainedIDs = imagePipeline.updateVisibleRect(visible, attachments: layout.imageAttachments)
|
|
153
|
+
onVisibleRectChange?(visible)
|
|
154
|
+
guard imagePixels.keys.contains(where: { !retainedIDs.contains($0) }) else { return }
|
|
155
|
+
imagePixels = imagePixels.filter { retainedIDs.contains($0.key) }
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
@objc public func cancelConfiguredImages() {
|
|
159
|
+
imageGeneration = ""
|
|
160
|
+
imagePipeline.cancel()
|
|
161
|
+
imagePixels = [:]
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/// A semantic prop replacement starts a new source-qualified publication
|
|
165
|
+
/// generation. Attachment-revision replacements deliberately do not call
|
|
166
|
+
/// this: they are the one reflow being deduplicated.
|
|
167
|
+
@objc public func resetIntrinsicImagePublication() {
|
|
168
|
+
imageRevisions.reset()
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
@objc public var errorDomain: String? { layout?.error?.domain }
|
|
172
|
+
@objc public var errorCode: String? { layout?.error?.code }
|
|
173
|
+
@objc public var errorMessage: String? { layout?.error?.message }
|
|
174
|
+
|
|
175
|
+
@objc public func atomLayoutsJSON(origin: CGPoint) -> String {
|
|
176
|
+
let atoms: [[String: Any]] = layout?.blocks.compactMap { block in
|
|
177
|
+
guard let atom = block.atomSlot else { return nil }
|
|
178
|
+
return [
|
|
179
|
+
"nodeType": atom.nodeType,
|
|
180
|
+
"docPos": atom.docPos,
|
|
181
|
+
"attrsJson": atom.attrsJSON,
|
|
182
|
+
"x": atom.bounds.minX + origin.x,
|
|
183
|
+
"y": atom.bounds.minY + origin.y,
|
|
184
|
+
"width": atom.bounds.width,
|
|
185
|
+
"height": atom.bounds.height
|
|
186
|
+
]
|
|
187
|
+
} ?? []
|
|
188
|
+
guard let data = try? JSONSerialization.data(withJSONObject: atoms) else { return "[]" }
|
|
189
|
+
return String(data: data, encoding: .utf8) ?? "[]"
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/// The owner chooses its delivery channel (UIKit delegate or Fabric event).
|
|
193
|
+
var onActivateInteraction: ((PreparedProseInteraction) -> Bool)?
|
|
194
|
+
var onVisibleRectChange: ((CGRect?) -> Void)?
|
|
195
|
+
@objc public weak var interactionDelegate: PreparedProseDrawingViewInteractionDelegate?
|
|
196
|
+
@objc public var linkInteractionsEnabled = true {
|
|
197
|
+
didSet {
|
|
198
|
+
guard oldValue != linkInteractionsEnabled else { return }
|
|
199
|
+
invalidateAccessibilityNodes()
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
private var accessibilityElementsByIndex: [Int: PreparedProseDrawingAccessibilityElement] = [:]
|
|
203
|
+
internal var materializedAccessibilityElementCountForTesting: Int { accessibilityElementsByIndex.count }
|
|
204
|
+
|
|
205
|
+
private lazy var tapRecognizer: UITapGestureRecognizer = {
|
|
206
|
+
let recognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
|
|
207
|
+
recognizer.cancelsTouchesInView = false
|
|
208
|
+
return recognizer
|
|
209
|
+
}()
|
|
210
|
+
|
|
211
|
+
public override init(frame: CGRect) {
|
|
212
|
+
super.init(frame: frame)
|
|
213
|
+
isAccessibilityElement = false
|
|
214
|
+
addGestureRecognizer(tapRecognizer)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
public override func didMoveToSuperview() {
|
|
218
|
+
super.didMoveToSuperview()
|
|
219
|
+
updateConfiguredImagesForVisibleWindow()
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
public override func didMoveToWindow() {
|
|
223
|
+
super.didMoveToWindow()
|
|
224
|
+
if window == nil { codeHighlightingSession.cancel() } else { scheduleCodeHighlighting() }
|
|
225
|
+
updateConfiguredImagesForVisibleWindow()
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
@available(*, unavailable)
|
|
229
|
+
required init?(coder: NSCoder) { fatalError("PreparedProseDrawingView does not support NSCoder") }
|
|
230
|
+
|
|
231
|
+
internal static func pixelAllocationBytes(for image: UIImage) -> Int {
|
|
232
|
+
if let cgImage = image.cgImage {
|
|
233
|
+
return saturatingMultiply(cgImage.bytesPerRow, cgImage.height)
|
|
234
|
+
}
|
|
235
|
+
let width = image.size.width * image.scale
|
|
236
|
+
let height = image.size.height * image.scale
|
|
237
|
+
guard width.isFinite, height.isFinite, width > 0, height > 0 else { return 0 }
|
|
238
|
+
let pixels = min(Double(Int.max), width.rounded(.up) * height.rounded(.up))
|
|
239
|
+
return saturatingMultiply(Int(pixels), 4)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
internal static func saturatingAdd(_ left: Int, _ right: Int) -> Int {
|
|
243
|
+
guard left <= Int.max - right else { return Int.max }
|
|
244
|
+
return left + right
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
internal static func saturatingMultiply(_ left: Int, _ right: Int) -> Int {
|
|
248
|
+
guard left > 0, right > 0 else { return 0 }
|
|
249
|
+
guard left <= Int.max / right else { return Int.max }
|
|
250
|
+
return left * right
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
private func configuredVisibleRect() -> CGRect? {
|
|
254
|
+
guard let window, !isHidden, alpha > 0 else { return nil }
|
|
255
|
+
var visible = convert(window.bounds, from: window).intersection(bounds)
|
|
256
|
+
var ancestor = superview
|
|
257
|
+
while let view = ancestor, view !== window {
|
|
258
|
+
guard !view.isHidden, view.alpha > 0 else { return nil }
|
|
259
|
+
if view.clipsToBounds {
|
|
260
|
+
visible = visible.intersection(convert(view.bounds, from: view))
|
|
261
|
+
}
|
|
262
|
+
ancestor = view.superview
|
|
263
|
+
}
|
|
264
|
+
guard visible.origin.x.isFinite, visible.origin.y.isFinite,
|
|
265
|
+
visible.size.width.isFinite, visible.size.height.isFinite,
|
|
266
|
+
!visible.isNull, !visible.isEmpty else { return nil }
|
|
267
|
+
return visible
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
private func refreshScrollObservations() {
|
|
271
|
+
var scrollViews: [UIScrollView] = []
|
|
272
|
+
var ancestor = superview
|
|
273
|
+
while let view = ancestor {
|
|
274
|
+
if let scrollView = view as? UIScrollView { scrollViews.append(scrollView) }
|
|
275
|
+
ancestor = view.superview
|
|
276
|
+
}
|
|
277
|
+
let activeScrollViews = window == nil ? [] : scrollViews
|
|
278
|
+
let nextIDs = activeScrollViews.map(ObjectIdentifier.init)
|
|
279
|
+
guard nextIDs != observedScrollViewIDs else { return }
|
|
280
|
+
scrollObservations.removeAll()
|
|
281
|
+
observedScrollViewIDs = nextIDs
|
|
282
|
+
scrollObservations = activeScrollViews.map { scrollView in
|
|
283
|
+
scrollView.observe(\.contentOffset, options: [.new]) { [weak self] _, _ in
|
|
284
|
+
self?.updateConfiguredImagesForVisibleWindow()
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
func interaction(at point: CGPoint) -> PreparedProseInteraction? {
|
|
290
|
+
guard let layout else { return nil }
|
|
291
|
+
return layout.interactions.first { interaction in
|
|
292
|
+
(linkInteractionsEnabled || interaction.kind != .link) && interaction.rects.contains { $0.contains(point) }
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
@objc private func handleTap(_ recognizer: UITapGestureRecognizer) {
|
|
297
|
+
guard recognizer.state == .ended,
|
|
298
|
+
let interaction = interaction(at: recognizer.location(in: self))
|
|
299
|
+
else { return }
|
|
300
|
+
_ = activate(interaction)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
@discardableResult
|
|
304
|
+
private func activate(_ interaction: PreparedProseInteraction) -> Bool {
|
|
305
|
+
if let onActivateInteraction { return onActivateInteraction(interaction) }
|
|
306
|
+
switch interaction.kind {
|
|
307
|
+
case .link:
|
|
308
|
+
guard linkInteractionsEnabled, let href = interaction.href else { return false }
|
|
309
|
+
return interactionDelegate?.preparedProseDrawingView(self, didActivateLink: href, text: interaction.visibleText) ?? false
|
|
310
|
+
case .mention:
|
|
311
|
+
guard let docPos = interaction.docPos, let attrsJSON = interaction.attrsJSON else { return false }
|
|
312
|
+
return interactionDelegate?.preparedProseDrawingView(
|
|
313
|
+
self,
|
|
314
|
+
didActivateMention: docPos,
|
|
315
|
+
label: interaction.label,
|
|
316
|
+
attrsJSON: attrsJSON
|
|
317
|
+
) ?? false
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
public override func accessibilityElementCount() -> Int { accessibilityNodes.count }
|
|
322
|
+
|
|
323
|
+
public override func accessibilityElement(at index: Int) -> Any? {
|
|
324
|
+
let nodes = accessibilityNodes
|
|
325
|
+
guard nodes.indices.contains(index), let layout else { return nil }
|
|
326
|
+
if let existing = accessibilityElementsByIndex[index] { return existing }
|
|
327
|
+
let element = PreparedProseDrawingAccessibilityElement(
|
|
328
|
+
container: self,
|
|
329
|
+
index: index,
|
|
330
|
+
node: nodes[index],
|
|
331
|
+
layout: layout
|
|
332
|
+
)
|
|
333
|
+
accessibilityElementsByIndex[index] = element
|
|
334
|
+
return element
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
public override func index(ofAccessibilityElement element: Any) -> Int {
|
|
338
|
+
guard let element = element as? PreparedProseDrawingAccessibilityElement,
|
|
339
|
+
element.drawingView === self,
|
|
340
|
+
element.belongs(to: layout)
|
|
341
|
+
else { return NSNotFound }
|
|
342
|
+
return element.index
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
private var accessibilityNodes: [PreparedProseAccessibilityNode] {
|
|
346
|
+
layout?.accessibilityNodes.map { node in
|
|
347
|
+
guard !linkInteractionsEnabled, node.role == .link else { return node }
|
|
348
|
+
return PreparedProseAccessibilityNode(
|
|
349
|
+
interactionIndex: nil,
|
|
350
|
+
role: .text,
|
|
351
|
+
label: node.label,
|
|
352
|
+
rects: node.rects
|
|
353
|
+
)
|
|
354
|
+
} ?? []
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
fileprivate func accessibilityFrame(
|
|
358
|
+
for node: PreparedProseAccessibilityNode,
|
|
359
|
+
layout: PreparedProseLayout
|
|
360
|
+
) -> CGRect {
|
|
361
|
+
guard self.layout === layout else { return .zero }
|
|
362
|
+
return UIAccessibility.convertToScreenCoordinates(node.bounds, in: self)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
fileprivate func accessibilityPath(
|
|
366
|
+
for node: PreparedProseAccessibilityNode,
|
|
367
|
+
layout: PreparedProseLayout
|
|
368
|
+
) -> UIBezierPath? {
|
|
369
|
+
guard self.layout === layout, !node.rects.isEmpty else { return nil }
|
|
370
|
+
let path = UIBezierPath()
|
|
371
|
+
for rect in node.rects {
|
|
372
|
+
path.append(UIBezierPath(rect: rect))
|
|
373
|
+
}
|
|
374
|
+
return UIAccessibility.convertToScreenCoordinates(path, in: self)
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
fileprivate func activateAccessibilityNode(
|
|
378
|
+
_ node: PreparedProseAccessibilityNode,
|
|
379
|
+
layout: PreparedProseLayout
|
|
380
|
+
) -> Bool {
|
|
381
|
+
guard self.layout === layout,
|
|
382
|
+
let interactionIndex = node.interactionIndex,
|
|
383
|
+
let interaction = layout.interactions[safe: interactionIndex]
|
|
384
|
+
else { return false }
|
|
385
|
+
return activate(interaction)
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
private func invalidateAccessibilityNodes() {
|
|
389
|
+
accessibilityElementsByIndex.removeAll(keepingCapacity: true)
|
|
390
|
+
UIAccessibility.post(notification: .layoutChanged, argument: nil)
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/// Converts an artifact-top baseline to the flipped Core Graphics coordinate system.
|
|
394
|
+
/// The view bounds, not the intrinsic artifact height, defines the flip origin.
|
|
395
|
+
static func textPosition(
|
|
396
|
+
baselineFromArtifactTop: CGFloat,
|
|
397
|
+
in bounds: CGRect,
|
|
398
|
+
artifactHeight _: CGFloat
|
|
399
|
+
) -> CGPoint {
|
|
400
|
+
CGPoint(x: 0, y: bounds.height - baselineFromArtifactTop)
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
public override func draw(_ rect: CGRect) {
|
|
404
|
+
let drawStarted = PreparedProseInstrumentation.now()
|
|
405
|
+
guard let layout, let context = UIGraphicsGetCurrentContext(), !layout.blocks.isEmpty else { return }
|
|
406
|
+
let blocks = layout.blocks
|
|
407
|
+
var lower = 0
|
|
408
|
+
var upper = blocks.count
|
|
409
|
+
while layout.hasMonotonicBlockBounds && lower < upper {
|
|
410
|
+
let middle = (lower + upper) / 2
|
|
411
|
+
if blocks[middle].bounds.maxY < rect.minY { lower = middle + 1 } else { upper = middle }
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
context.saveGState()
|
|
415
|
+
defer { context.restoreGState() }
|
|
416
|
+
if let content = layout.decorations.first, let box = content.styleBox {
|
|
417
|
+
context.addPath(box.path(in: content.bounds).cgPath)
|
|
418
|
+
context.clip()
|
|
419
|
+
}
|
|
420
|
+
for fragment in layout.decorations where fragment.bounds.intersects(rect) {
|
|
421
|
+
fragment.styleBox?.draw(in: fragment.bounds, context: context)
|
|
422
|
+
}
|
|
423
|
+
context.saveGState()
|
|
424
|
+
context.translateBy(x: 0, y: bounds.height)
|
|
425
|
+
context.scaleBy(x: 1, y: -1)
|
|
426
|
+
let scale = CGFloat(Double(bitPattern: layout.key.displayScaleBits))
|
|
427
|
+
var visibleFragments: [PreparedProseFragment] = []
|
|
428
|
+
var visibleBlockCount = 0
|
|
429
|
+
for index in lower..<blocks.count {
|
|
430
|
+
let block = blocks[index]
|
|
431
|
+
if layout.hasMonotonicBlockBounds && block.bounds.minY > rect.maxY { break }
|
|
432
|
+
guard block.bounds.intersects(rect) else { continue }
|
|
433
|
+
visibleFragments.append(contentsOf: block.fragments)
|
|
434
|
+
visibleBlockCount += 1
|
|
435
|
+
}
|
|
436
|
+
// Keep paint phases global across the visible range: a nested code
|
|
437
|
+
// background must never cover a quote border from an adjacent block.
|
|
438
|
+
for fragment in visibleFragments { drawBackground(fragment, in: context) }
|
|
439
|
+
for fragment in visibleFragments { drawBorderOrRule(fragment, in: context, scale: scale) }
|
|
440
|
+
for fragment in visibleFragments { drawForeground(fragment, in: context) }
|
|
441
|
+
context.restoreGState()
|
|
442
|
+
PreparedProseInstrumentation.drew(drawStarted, visibleBlocks: visibleBlockCount)
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
private func drawingRect(for fragment: PreparedProseFragment) -> CGRect {
|
|
446
|
+
CGRect(
|
|
447
|
+
x: fragment.bounds.minX,
|
|
448
|
+
y: bounds.height - fragment.bounds.maxY,
|
|
449
|
+
width: fragment.bounds.width,
|
|
450
|
+
height: fragment.bounds.height
|
|
451
|
+
)
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
private func drawBackground(_ fragment: PreparedProseFragment, in context: CGContext) {
|
|
455
|
+
guard fragment.kind == .background || fragment.kind == .atom || fragment.kind == .image else { return }
|
|
456
|
+
let rect = drawingRect(for: fragment)
|
|
457
|
+
if let box = fragment.styleBox {
|
|
458
|
+
context.saveGState()
|
|
459
|
+
context.translateBy(x: 0, y: bounds.height)
|
|
460
|
+
context.scaleBy(x: 1, y: -1)
|
|
461
|
+
box.draw(in: fragment.bounds, context: context)
|
|
462
|
+
context.restoreGState()
|
|
463
|
+
return
|
|
464
|
+
}
|
|
465
|
+
context.setFillColor(fragment.color ?? UIColor.clear.cgColor)
|
|
466
|
+
context.addPath(UIBezierPath(roundedRect: rect, cornerRadius: fragment.cornerRadius).cgPath)
|
|
467
|
+
context.drawPath(using: .fill)
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
private func drawBorderOrRule(_ fragment: PreparedProseFragment, in context: CGContext, scale: CGFloat) {
|
|
471
|
+
let rect = drawingRect(for: fragment)
|
|
472
|
+
switch fragment.kind {
|
|
473
|
+
case .border:
|
|
474
|
+
context.setFillColor(fragment.color ?? UIColor.clear.cgColor)
|
|
475
|
+
context.fill(rect)
|
|
476
|
+
case .rule:
|
|
477
|
+
let unit = scale.isFinite && scale > 0 ? 1 / scale : 1
|
|
478
|
+
let alignedY = (rect.minY / unit).rounded() * unit
|
|
479
|
+
context.setFillColor(fragment.color ?? UIColor.clear.cgColor)
|
|
480
|
+
context.fill(CGRect(x: rect.minX, y: alignedY, width: rect.width, height: max(unit, rect.height)))
|
|
481
|
+
case .atom where fragment.strokeWidth > 0:
|
|
482
|
+
context.setStrokeColor(fragment.borderColor ?? fragment.color ?? UIColor.clear.cgColor)
|
|
483
|
+
context.setLineWidth(fragment.strokeWidth)
|
|
484
|
+
let inset = fragment.strokeWidth / 2
|
|
485
|
+
context.addPath(
|
|
486
|
+
UIBezierPath(
|
|
487
|
+
roundedRect: rect.insetBy(dx: inset, dy: inset),
|
|
488
|
+
cornerRadius: max(0, fragment.cornerRadius - inset)
|
|
489
|
+
).cgPath
|
|
490
|
+
)
|
|
491
|
+
context.drawPath(using: .stroke)
|
|
492
|
+
default:
|
|
493
|
+
break
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
private func drawForeground(_ fragment: PreparedProseFragment, in context: CGContext) {
|
|
498
|
+
let rect = CGRect(
|
|
499
|
+
x: fragment.bounds.minX,
|
|
500
|
+
y: bounds.height - fragment.bounds.maxY,
|
|
501
|
+
width: fragment.bounds.width,
|
|
502
|
+
height: fragment.bounds.height
|
|
503
|
+
)
|
|
504
|
+
switch fragment.kind {
|
|
505
|
+
case .text:
|
|
506
|
+
guard let line = fragment.line else { return }
|
|
507
|
+
context.textPosition = CGPoint(x: fragment.origin.x, y: bounds.height - fragment.origin.y)
|
|
508
|
+
CTLineDraw(line, context)
|
|
509
|
+
case .atom:
|
|
510
|
+
guard let line = fragment.line else { return }
|
|
511
|
+
context.textPosition = CGPoint(x: fragment.origin.x, y: bounds.height - fragment.origin.y)
|
|
512
|
+
CTLineDraw(line, context)
|
|
513
|
+
case .image:
|
|
514
|
+
guard let layout,
|
|
515
|
+
let attachment = layout.imageAttachments.first(where: { $0.bounds == fragment.bounds }),
|
|
516
|
+
let image = imagePixels[attachment.id] else { return }
|
|
517
|
+
context.saveGState()
|
|
518
|
+
context.translateBy(x: rect.minX, y: rect.maxY)
|
|
519
|
+
context.scaleBy(x: 1, y: -1)
|
|
520
|
+
let localBounds = CGRect(origin: .zero, size: rect.size)
|
|
521
|
+
if let box = fragment.styleBox {
|
|
522
|
+
context.addPath(box.path(in: localBounds, inner: true).cgPath)
|
|
523
|
+
context.clip()
|
|
524
|
+
context.clip(to: localBounds.inset(by: box.inset))
|
|
525
|
+
image.draw(in: box.imageRect(image.size, in: localBounds))
|
|
526
|
+
} else { image.draw(in: localBounds) }
|
|
527
|
+
context.restoreGState()
|
|
528
|
+
case .marker:
|
|
529
|
+
if fragment.label == "•", fragment.line == nil {
|
|
530
|
+
context.setFillColor(fragment.color ?? UIColor.label.cgColor)
|
|
531
|
+
context.fillEllipse(in: rect)
|
|
532
|
+
} else if let line = fragment.line {
|
|
533
|
+
context.textPosition = CGPoint(x: fragment.origin.x, y: bounds.height - fragment.origin.y)
|
|
534
|
+
CTLineDraw(line, context)
|
|
535
|
+
} else if let box = fragment.styleBox {
|
|
536
|
+
context.saveGState()
|
|
537
|
+
context.translateBy(x: 0, y: bounds.height)
|
|
538
|
+
context.scaleBy(x: 1, y: -1)
|
|
539
|
+
EditorStyleSheet.drawCheckbox(box, in: fragment.bounds, checked: fragment.checked, context: context)
|
|
540
|
+
context.restoreGState()
|
|
541
|
+
} else {
|
|
542
|
+
drawTaskMarker(in: rect, checked: fragment.checked, color: UIColor(cgColor: fragment.color ?? UIColor.label.cgColor))
|
|
543
|
+
}
|
|
544
|
+
case .strike:
|
|
545
|
+
context.setFillColor(fragment.color ?? UIColor.clear.cgColor)
|
|
546
|
+
context.addPath(UIBezierPath(roundedRect: rect, cornerRadius: fragment.cornerRadius).cgPath)
|
|
547
|
+
context.fillPath()
|
|
548
|
+
case .background, .border, .rule:
|
|
549
|
+
break
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
private func drawTaskMarker(in rect: CGRect, checked: Bool, color: UIColor) {
|
|
554
|
+
let inset = max(1, rect.height * 0.2)
|
|
555
|
+
let box = CGRect(x: rect.minX + inset, y: rect.minY + inset, width: rect.height - inset * 2, height: rect.height - inset * 2)
|
|
556
|
+
let path = UIBezierPath(roundedRect: box, cornerRadius: box.width * 0.2)
|
|
557
|
+
color.setStroke()
|
|
558
|
+
path.lineWidth = max(1, box.width * 0.1)
|
|
559
|
+
path.stroke()
|
|
560
|
+
guard checked else { return }
|
|
561
|
+
let check = UIBezierPath()
|
|
562
|
+
check.move(to: CGPoint(x: box.minX + box.width * 0.2, y: box.midY))
|
|
563
|
+
check.addLine(to: CGPoint(x: box.minX + box.width * 0.43, y: box.maxY - box.height * 0.2))
|
|
564
|
+
check.addLine(to: CGPoint(x: box.maxX - box.width * 0.16, y: box.minY + box.height * 0.2))
|
|
565
|
+
check.lineCapStyle = .round
|
|
566
|
+
check.lineJoinStyle = .round
|
|
567
|
+
check.lineWidth = max(1.4, box.width * 0.12)
|
|
568
|
+
color.setStroke()
|
|
569
|
+
check.stroke()
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
private final class PreparedProseDrawingAccessibilityElement: UIAccessibilityElement {
|
|
574
|
+
weak var drawingView: PreparedProseDrawingView?
|
|
575
|
+
weak var layout: PreparedProseLayout?
|
|
576
|
+
let index: Int
|
|
577
|
+
let node: PreparedProseAccessibilityNode
|
|
578
|
+
|
|
579
|
+
init(
|
|
580
|
+
container: PreparedProseDrawingView,
|
|
581
|
+
index: Int,
|
|
582
|
+
node: PreparedProseAccessibilityNode,
|
|
583
|
+
layout: PreparedProseLayout
|
|
584
|
+
) {
|
|
585
|
+
drawingView = container
|
|
586
|
+
self.index = index
|
|
587
|
+
self.node = node
|
|
588
|
+
self.layout = layout
|
|
589
|
+
super.init(accessibilityContainer: container)
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
func belongs(to layout: PreparedProseLayout?) -> Bool {
|
|
593
|
+
self.layout === layout
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
override var accessibilityLabel: String? {
|
|
597
|
+
get { node.label }
|
|
598
|
+
set { }
|
|
599
|
+
}
|
|
600
|
+
override var accessibilityTraits: UIAccessibilityTraits {
|
|
601
|
+
get {
|
|
602
|
+
switch node.role {
|
|
603
|
+
case .text, .separator:
|
|
604
|
+
return .staticText
|
|
605
|
+
case .heading:
|
|
606
|
+
return [.staticText, .header]
|
|
607
|
+
case .link:
|
|
608
|
+
return .link
|
|
609
|
+
case .mention:
|
|
610
|
+
return .button
|
|
611
|
+
case .image:
|
|
612
|
+
return .image
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
set { }
|
|
616
|
+
}
|
|
617
|
+
override var accessibilityFrame: CGRect {
|
|
618
|
+
get {
|
|
619
|
+
guard let drawingView, let layout else { return .zero }
|
|
620
|
+
return drawingView.accessibilityFrame(for: node, layout: layout)
|
|
621
|
+
}
|
|
622
|
+
set { }
|
|
623
|
+
}
|
|
624
|
+
override var accessibilityPath: UIBezierPath? {
|
|
625
|
+
get {
|
|
626
|
+
guard let drawingView, let layout else { return nil }
|
|
627
|
+
return drawingView.accessibilityPath(for: node, layout: layout)
|
|
628
|
+
}
|
|
629
|
+
set { }
|
|
630
|
+
}
|
|
631
|
+
override func accessibilityActivate() -> Bool {
|
|
632
|
+
guard let drawingView, let layout else { return false }
|
|
633
|
+
return drawingView.activateAccessibilityNode(node, layout: layout)
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
private extension Array {
|
|
638
|
+
subscript(safe index: Int) -> Element? { indices.contains(index) ? self[index] : nil }
|
|
639
|
+
}
|