@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,395 @@
|
|
|
1
|
+
import { withAtomsSchema, type AtomNodeDefinition } from './atoms';
|
|
2
|
+
import { RESERVED_WIRE_NODE_TYPES } from './atomPolicy';
|
|
3
|
+
|
|
4
|
+
/** Declaration of one node or mark attribute. */
|
|
5
|
+
export interface AttrSpec {
|
|
6
|
+
/** Value used when the attribute is absent. Omit to make the attribute required. */
|
|
7
|
+
default?: unknown;
|
|
8
|
+
type?: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
9
|
+
enum?: readonly unknown[];
|
|
10
|
+
min?: number;
|
|
11
|
+
max?: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Static DOM output supported by the native HTML serializer. */
|
|
15
|
+
export type DOMOutputSpec = readonly [tag: string] | readonly [tag: string, content: 0];
|
|
16
|
+
|
|
17
|
+
/** Declarative DOM rule supported by the native HTML parser. */
|
|
18
|
+
export interface ParseDOMRule {
|
|
19
|
+
tag: string;
|
|
20
|
+
attrs?: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Select a DOM output from one declared node attribute. */
|
|
24
|
+
export interface AttributeDOMOutputSpec {
|
|
25
|
+
switchOn: string;
|
|
26
|
+
cases: Readonly<Record<string, DOMOutputSpec>>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** JSON representation projected from one native node variant. */
|
|
30
|
+
export interface NodeJSONProjection {
|
|
31
|
+
type: string;
|
|
32
|
+
attrs?: Record<string, unknown>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Declarative HTML parsing and serialization rules for a void node. */
|
|
36
|
+
export interface NodeHtmlRules {
|
|
37
|
+
tag: string;
|
|
38
|
+
staticAttrs?: Record<string, string>;
|
|
39
|
+
attrMap?: Record<string, string>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Declaration of one node type in a {@link SchemaDefinition}. */
|
|
43
|
+
export interface NodeSpec {
|
|
44
|
+
/** Native node type name. `json` may expose a different public document type. */
|
|
45
|
+
name: string;
|
|
46
|
+
/** ProseMirror-style content expression, e.g. `'block+'`, `'inline*'`, or `''` for a leaf. */
|
|
47
|
+
content: string;
|
|
48
|
+
/** Content group this node belongs to, e.g. `'block'` or `'inline'`. */
|
|
49
|
+
group?: string;
|
|
50
|
+
/** Attributes this node declares. Undeclared attributes are filtered out on
|
|
51
|
+
* ingestion unless `allowUndeclaredAttrs` is set. */
|
|
52
|
+
attrs?: Record<string, AttrSpec>;
|
|
53
|
+
/**
|
|
54
|
+
* How the engine treats this node: `'doc'`, `'textBlock'`, `'list'`,
|
|
55
|
+
* `'listItem'`, `'text'`, `'hardBreak'`, `'inline'`, or `'block'`. Any
|
|
56
|
+
* unrecognized value is treated as `'block'`. Exactly one node must use
|
|
57
|
+
* `'doc'`. An ordered list is a `'list'` node whose name contains
|
|
58
|
+
* `ordered`.
|
|
59
|
+
*/
|
|
60
|
+
role: string;
|
|
61
|
+
/** Tag used when serializing this node to HTML. */
|
|
62
|
+
htmlTag?: string;
|
|
63
|
+
/** Declarative HTML rules used for lossless void-node round trips. */
|
|
64
|
+
html?: NodeHtmlRules;
|
|
65
|
+
/** Whether the node holds no content of its own (an image or rule, say). */
|
|
66
|
+
isVoid?: boolean;
|
|
67
|
+
/** Whether collapsed backspace may remove this void block from an adjacent caret. */
|
|
68
|
+
deletableOnBackspace?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Opt-in escape hatch: when `true`, JSON ingestion (`set_json` /
|
|
71
|
+
* `insert_content_json`) admits attrs on this node that are not declared
|
|
72
|
+
* in `attrs`, instead of filtering them out. Default `false`. Intended
|
|
73
|
+
* for node types with an intentional pass-through-metadata contract
|
|
74
|
+
* (e.g. the mention node — see `mentionNodeSpec()` in addons.ts).
|
|
75
|
+
*/
|
|
76
|
+
allowUndeclaredAttrs?: boolean;
|
|
77
|
+
/** Public JSON representation when it differs from the native node name. */
|
|
78
|
+
json?: NodeJSONProjection;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Declaration of one mark type in a {@link SchemaDefinition}. */
|
|
82
|
+
export interface MarkSpec {
|
|
83
|
+
/** Mark type name, as it appears in document JSON. */
|
|
84
|
+
name: string;
|
|
85
|
+
/** Attributes this mark declares. */
|
|
86
|
+
attrs?: Record<string, AttrSpec>;
|
|
87
|
+
/** Mark names that cannot coexist with this one on the same text range. */
|
|
88
|
+
excludes?: string;
|
|
89
|
+
/**
|
|
90
|
+
* Serializer tag for a custom mark. Native accepts only the inert allowlist:
|
|
91
|
+
* span, strong, em, u, s, code, a, sub, sup, mark.
|
|
92
|
+
*/
|
|
93
|
+
htmlTag?: 'span' | 'strong' | 'em' | 'u' | 's' | 'code' | 'a' | 'sub' | 'sup' | 'mark';
|
|
94
|
+
/**
|
|
95
|
+
* Opt-in escape hatch: when `true`, JSON ingestion (`set_json` /
|
|
96
|
+
* `insert_content_json`) admits attrs on this mark that are not declared
|
|
97
|
+
* in `attrs`, instead of filtering them out. Default `false`. Mirrors
|
|
98
|
+
* `NodeSpec.allowUndeclaredAttrs` for mark types with an intentional
|
|
99
|
+
* pass-through-metadata contract.
|
|
100
|
+
*/
|
|
101
|
+
allowUndeclaredAttrs?: boolean;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* The node and mark types a document may contain. Fixed when the document
|
|
106
|
+
* handle is created (`NativeEditorCreateConfig.schema`), or per render for
|
|
107
|
+
* `RichTextViewer`. Start from {@link defaultSchema},
|
|
108
|
+
* {@link prosemirrorSchema}, or {@link tiptapCompatibleSchema} rather than
|
|
109
|
+
* assembling one from scratch.
|
|
110
|
+
*/
|
|
111
|
+
export interface SchemaDefinition {
|
|
112
|
+
/** Node types. Exactly one must have `role: 'doc'`. */
|
|
113
|
+
nodes: NodeSpec[];
|
|
114
|
+
/** Mark types. */
|
|
115
|
+
marks: MarkSpec[];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Keyed node declaration accepted by {@link defineSchema}. */
|
|
119
|
+
export interface SchemaNodeSpec {
|
|
120
|
+
content?: string;
|
|
121
|
+
group?: string;
|
|
122
|
+
attrs?: Record<string, AttrSpec>;
|
|
123
|
+
/** Native semantic role. Common `doc`, `paragraph`, and `text` shapes are inferred. */
|
|
124
|
+
role?: NodeSpec['role'] | 'heading';
|
|
125
|
+
parseDOM?: readonly ParseDOMRule[];
|
|
126
|
+
toDOM?: DOMOutputSpec | AttributeDOMOutputSpec;
|
|
127
|
+
html?: NodeHtmlRules;
|
|
128
|
+
isVoid?: boolean;
|
|
129
|
+
deletableOnBackspace?: boolean;
|
|
130
|
+
allowUndeclaredAttrs?: boolean;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Keyed mark declaration accepted by {@link defineSchema}. */
|
|
134
|
+
export interface SchemaMarkSpec {
|
|
135
|
+
attrs?: Record<string, AttrSpec>;
|
|
136
|
+
excludes?: string;
|
|
137
|
+
parseDOM?: readonly ParseDOMRule[];
|
|
138
|
+
toDOM?: DOMOutputSpec;
|
|
139
|
+
allowUndeclaredAttrs?: boolean;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** ProseMirror-shaped authoring schema compiled for the native engine. */
|
|
143
|
+
export interface SchemaSpec {
|
|
144
|
+
nodes: Readonly<Record<string, SchemaNodeSpec>>;
|
|
145
|
+
marks?: Readonly<Record<string, SchemaMarkSpec>>;
|
|
146
|
+
atoms?: readonly AtomNodeDefinition<any>[];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export const ALLOWED_MARK_HTML_TAGS = new Set([
|
|
150
|
+
'span',
|
|
151
|
+
'strong',
|
|
152
|
+
'em',
|
|
153
|
+
'u',
|
|
154
|
+
's',
|
|
155
|
+
'code',
|
|
156
|
+
'a',
|
|
157
|
+
'sub',
|
|
158
|
+
'sup',
|
|
159
|
+
'mark',
|
|
160
|
+
]);
|
|
161
|
+
|
|
162
|
+
export function outputTag(spec: DOMOutputSpec): string {
|
|
163
|
+
return spec[0];
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function appendGroup(group: string | undefined, name: string): string {
|
|
167
|
+
const groups = group?.split(/\s+/).filter(Boolean) ?? [];
|
|
168
|
+
if (!groups.includes(name)) groups.push(name);
|
|
169
|
+
return groups.join(' ');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function schemaNodeRole(name: string, node: SchemaNodeSpec): string {
|
|
173
|
+
if (node.role != null) return node.role === 'heading' ? 'textBlock' : node.role;
|
|
174
|
+
if (name === 'doc') return 'doc';
|
|
175
|
+
if (name === 'text') return 'text';
|
|
176
|
+
if (node.content === 'inline*' && node.group?.split(/\s+/).includes('block')) {
|
|
177
|
+
return 'textBlock';
|
|
178
|
+
}
|
|
179
|
+
if (node.group?.split(/\s+/).includes('inline')) return 'inline';
|
|
180
|
+
return 'block';
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export function caseAttributeValue(
|
|
184
|
+
key: string,
|
|
185
|
+
attribute: string,
|
|
186
|
+
tag: string,
|
|
187
|
+
parseDOM: readonly ParseDOMRule[] | undefined,
|
|
188
|
+
defaultValue: unknown
|
|
189
|
+
): unknown {
|
|
190
|
+
const rule = parseDOM?.find(
|
|
191
|
+
(candidate) =>
|
|
192
|
+
candidate.tag === tag &&
|
|
193
|
+
candidate.attrs != null &&
|
|
194
|
+
String(candidate.attrs[attribute]) === key
|
|
195
|
+
);
|
|
196
|
+
if (rule?.attrs && Object.prototype.hasOwnProperty.call(rule.attrs, attribute)) {
|
|
197
|
+
return rule.attrs[attribute];
|
|
198
|
+
}
|
|
199
|
+
if (typeof defaultValue === 'number') return Number(key);
|
|
200
|
+
if (typeof defaultValue === 'boolean') return key === 'true';
|
|
201
|
+
return key;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function validateAttributeDOMRules(
|
|
205
|
+
name: string,
|
|
206
|
+
switched: AttributeDOMOutputSpec,
|
|
207
|
+
parseDOM: readonly ParseDOMRule[] | undefined,
|
|
208
|
+
defaultValue: unknown
|
|
209
|
+
): void {
|
|
210
|
+
const cases = Object.entries(switched.cases);
|
|
211
|
+
let discriminatorType =
|
|
212
|
+
typeof defaultValue === 'string' ||
|
|
213
|
+
typeof defaultValue === 'number' ||
|
|
214
|
+
typeof defaultValue === 'boolean'
|
|
215
|
+
? typeof defaultValue
|
|
216
|
+
: undefined;
|
|
217
|
+
if (discriminatorType == null && parseDOM != null) {
|
|
218
|
+
const parsedTypes = parseDOM.map((rule) => {
|
|
219
|
+
const value = rule.attrs?.[switched.switchOn];
|
|
220
|
+
return typeof value === 'string' ||
|
|
221
|
+
typeof value === 'number' ||
|
|
222
|
+
typeof value === 'boolean'
|
|
223
|
+
? typeof value
|
|
224
|
+
: undefined;
|
|
225
|
+
});
|
|
226
|
+
const firstType = parsedTypes[0];
|
|
227
|
+
if (firstType != null && parsedTypes.every((type) => type === firstType)) {
|
|
228
|
+
discriminatorType = firstType;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (discriminatorType == null) {
|
|
232
|
+
throw new Error(
|
|
233
|
+
`node '${name}' DOM discriminator '${switched.switchOn}' must have a scalar type`
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
if (parseDOM == null) {
|
|
237
|
+
const validCases = cases.every(([caseKey]) => {
|
|
238
|
+
if (discriminatorType === 'number') {
|
|
239
|
+
return /^-?(?:0|[1-9]\d*)(?:\.\d+)?$/.test(caseKey);
|
|
240
|
+
}
|
|
241
|
+
return discriminatorType !== 'boolean' || caseKey === 'true' || caseKey === 'false';
|
|
242
|
+
});
|
|
243
|
+
if (!validCases) {
|
|
244
|
+
throw new Error(
|
|
245
|
+
`node '${name}' DOM discriminator '${switched.switchOn}' must use ${discriminatorType} values`
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const matchesCase = ([caseKey, output]: [string, DOMOutputSpec]) =>
|
|
251
|
+
parseDOM.filter(
|
|
252
|
+
(rule) =>
|
|
253
|
+
rule.tag === outputTag(output) &&
|
|
254
|
+
rule.attrs != null &&
|
|
255
|
+
Object.prototype.hasOwnProperty.call(rule.attrs, switched.switchOn) &&
|
|
256
|
+
String(rule.attrs[switched.switchOn]) === caseKey
|
|
257
|
+
).length === 1;
|
|
258
|
+
if (parseDOM.length !== cases.length || !cases.every(matchesCase)) {
|
|
259
|
+
throw new Error(
|
|
260
|
+
`node '${name}' DOM parse rules must map one-to-one with '${switched.switchOn}' output cases`
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
if (
|
|
264
|
+
discriminatorType != null &&
|
|
265
|
+
parseDOM.some(
|
|
266
|
+
(rule) =>
|
|
267
|
+
rule.attrs != null && typeof rule.attrs[switched.switchOn] !== discriminatorType
|
|
268
|
+
)
|
|
269
|
+
) {
|
|
270
|
+
throw new Error(
|
|
271
|
+
`node '${name}' DOM discriminator '${switched.switchOn}' must use ${discriminatorType} values`
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export function staticDOMTag(
|
|
277
|
+
kind: 'node' | 'mark',
|
|
278
|
+
name: string,
|
|
279
|
+
parseDOM: readonly ParseDOMRule[] | undefined,
|
|
280
|
+
toDOM: DOMOutputSpec | undefined
|
|
281
|
+
): string | undefined {
|
|
282
|
+
if ((parseDOM?.length ?? 0) > 1) {
|
|
283
|
+
throw new Error(`${kind} '${name}' has multiple static DOM parse rules`);
|
|
284
|
+
}
|
|
285
|
+
const parsed = parseDOM?.[0]?.tag;
|
|
286
|
+
const serialized = toDOM == null ? undefined : outputTag(toDOM);
|
|
287
|
+
if (parsed != null && serialized != null && parsed !== serialized) {
|
|
288
|
+
throw new Error(`${kind} '${name}' parses '${parsed}' but serializes '${serialized}'`);
|
|
289
|
+
}
|
|
290
|
+
return serialized ?? parsed;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** Compile a keyed, ProseMirror-shaped schema into the serializable native form. */
|
|
294
|
+
export function defineSchema(spec: SchemaSpec): SchemaDefinition {
|
|
295
|
+
const nodes: NodeSpec[] = [];
|
|
296
|
+
const names = new Set<string>();
|
|
297
|
+
for (const [name, node] of Object.entries(spec.nodes)) {
|
|
298
|
+
const common = {
|
|
299
|
+
content: node.content ?? '',
|
|
300
|
+
...(node.group == null ? {} : { group: node.group }),
|
|
301
|
+
...(node.attrs == null ? {} : { attrs: node.attrs }),
|
|
302
|
+
role: schemaNodeRole(name, node),
|
|
303
|
+
...(node.html == null ? {} : { html: node.html }),
|
|
304
|
+
...(node.isVoid == null ? {} : { isVoid: node.isVoid }),
|
|
305
|
+
...(node.deletableOnBackspace == null
|
|
306
|
+
? {}
|
|
307
|
+
: { deletableOnBackspace: node.deletableOnBackspace }),
|
|
308
|
+
...(node.allowUndeclaredAttrs == null
|
|
309
|
+
? {}
|
|
310
|
+
: { allowUndeclaredAttrs: node.allowUndeclaredAttrs }),
|
|
311
|
+
};
|
|
312
|
+
if (node.toDOM != null && !Array.isArray(node.toDOM)) {
|
|
313
|
+
const switched = node.toDOM as AttributeDOMOutputSpec;
|
|
314
|
+
if (RESERVED_WIRE_NODE_TYPES.has(name)) {
|
|
315
|
+
throw new Error(`node '${name}' uses a reserved wire projection type`);
|
|
316
|
+
}
|
|
317
|
+
if (
|
|
318
|
+
node.attrs == null ||
|
|
319
|
+
!Object.prototype.hasOwnProperty.call(node.attrs, switched.switchOn)
|
|
320
|
+
) {
|
|
321
|
+
throw new Error(
|
|
322
|
+
`node '${name}' switches on undeclared attribute '${switched.switchOn}'`
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
if (Object.keys(switched.cases).length === 0) {
|
|
326
|
+
throw new Error(`node '${name}' has no DOM output cases`);
|
|
327
|
+
}
|
|
328
|
+
const discriminatorDefault = node.attrs[switched.switchOn]?.default;
|
|
329
|
+
validateAttributeDOMRules(name, switched, node.parseDOM, discriminatorDefault);
|
|
330
|
+
const { attrs: _attrs, ...variantCommon } = common;
|
|
331
|
+
for (const [caseKey, output] of Object.entries(switched.cases)) {
|
|
332
|
+
const tag = outputTag(output);
|
|
333
|
+
if (names.has(tag))
|
|
334
|
+
throw new Error(`schema produces duplicate native node '${tag}'`);
|
|
335
|
+
names.add(tag);
|
|
336
|
+
const { [switched.switchOn]: _discriminator, ...variantAttrs } = node.attrs ?? {};
|
|
337
|
+
nodes.push({
|
|
338
|
+
name: tag,
|
|
339
|
+
...variantCommon,
|
|
340
|
+
group: appendGroup(node.group, name),
|
|
341
|
+
...(Object.keys(variantAttrs).length === 0 ? {} : { attrs: variantAttrs }),
|
|
342
|
+
htmlTag: tag,
|
|
343
|
+
json: {
|
|
344
|
+
type: name,
|
|
345
|
+
attrs: {
|
|
346
|
+
[switched.switchOn]: caseAttributeValue(
|
|
347
|
+
caseKey,
|
|
348
|
+
switched.switchOn,
|
|
349
|
+
tag,
|
|
350
|
+
node.parseDOM,
|
|
351
|
+
discriminatorDefault
|
|
352
|
+
),
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (names.has(name)) throw new Error(`schema produces duplicate native node '${name}'`);
|
|
361
|
+
names.add(name);
|
|
362
|
+
const tag = staticDOMTag(
|
|
363
|
+
'node',
|
|
364
|
+
name,
|
|
365
|
+
node.parseDOM,
|
|
366
|
+
node.toDOM as DOMOutputSpec | undefined
|
|
367
|
+
);
|
|
368
|
+
nodes.push({
|
|
369
|
+
name,
|
|
370
|
+
...common,
|
|
371
|
+
...(tag == null ? {} : { htmlTag: tag }),
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
const marks: MarkSpec[] = Object.entries(spec.marks ?? {}).map(([name, mark]) => {
|
|
376
|
+
const tag = staticDOMTag('mark', name, mark.parseDOM, mark.toDOM);
|
|
377
|
+
const normalizedTag = tag?.toLowerCase();
|
|
378
|
+
if (normalizedTag != null && !ALLOWED_MARK_HTML_TAGS.has(normalizedTag)) {
|
|
379
|
+
throw new Error(`mark '${name}' has disallowed HTML tag '${tag}'`);
|
|
380
|
+
}
|
|
381
|
+
return {
|
|
382
|
+
name,
|
|
383
|
+
...(mark.attrs == null ? {} : { attrs: mark.attrs }),
|
|
384
|
+
...(mark.excludes == null ? {} : { excludes: mark.excludes }),
|
|
385
|
+
...(normalizedTag == null ? {} : { htmlTag: normalizedTag as MarkSpec['htmlTag'] }),
|
|
386
|
+
...(mark.allowUndeclaredAttrs == null
|
|
387
|
+
? {}
|
|
388
|
+
: { allowUndeclaredAttrs: mark.allowUndeclaredAttrs }),
|
|
389
|
+
};
|
|
390
|
+
});
|
|
391
|
+
const schema = { nodes, marks };
|
|
392
|
+
return spec.atoms == null || spec.atoms.length === 0
|
|
393
|
+
? schema
|
|
394
|
+
: withAtomsSchema(schema, spec.atoms);
|
|
395
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { DocumentJSON } from './NativeEditorBridge';
|
|
2
|
+
import { NativeEditorBoundaryError } from './NativeEditorBoundaryError';
|
|
3
|
+
import type { SchemaDefinition } from './schemaDefinition';
|
|
4
|
+
import { schemaBoundaryError, utf8ByteLengthUpTo } from './schemaNormalization';
|
|
5
|
+
import { constructDefaultEmptyDocument } from './schemaDocumentConstruction';
|
|
6
|
+
import {
|
|
7
|
+
resolveDescriptorLimits,
|
|
8
|
+
createSchemaWorkBudget,
|
|
9
|
+
admitSchemaCollections,
|
|
10
|
+
resolveDocumentSchema,
|
|
11
|
+
} from './schemaResolution';
|
|
12
|
+
import {
|
|
13
|
+
defaultSchema,
|
|
14
|
+
type DocumentDescriptorLimits,
|
|
15
|
+
type ResolvedDocumentSchema,
|
|
16
|
+
} from './schemaPresets';
|
|
17
|
+
|
|
18
|
+
export function defaultEmptyDocument(
|
|
19
|
+
schema: SchemaDefinition = defaultSchema,
|
|
20
|
+
limits?: DocumentDescriptorLimits
|
|
21
|
+
): DocumentJSON {
|
|
22
|
+
const resolvedLimits = resolveDescriptorLimits(limits);
|
|
23
|
+
if (schema.nodes.length > resolvedLimits.maxSchemaNodes) {
|
|
24
|
+
throw schemaBoundaryError(resolvedLimits.maxSchemaNodes, schema.nodes.length);
|
|
25
|
+
}
|
|
26
|
+
let expressionBytes = 0;
|
|
27
|
+
for (const node of schema.nodes) {
|
|
28
|
+
if (node != null && typeof node.content === 'string') {
|
|
29
|
+
expressionBytes += utf8ByteLengthUpTo(
|
|
30
|
+
node.content,
|
|
31
|
+
resolvedLimits.maxSchemaExpressionBytes - expressionBytes
|
|
32
|
+
);
|
|
33
|
+
if (expressionBytes > resolvedLimits.maxSchemaExpressionBytes) {
|
|
34
|
+
throw schemaBoundaryError(resolvedLimits.maxSchemaExpressionBytes, expressionBytes);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const admissionBudget = createSchemaWorkBudget(resolvedLimits);
|
|
39
|
+
const admittedCollections = admitSchemaCollections(schema, admissionBudget);
|
|
40
|
+
if (admittedCollections == null) {
|
|
41
|
+
throw new Error('schema cannot construct a default document: invalid schema collections');
|
|
42
|
+
}
|
|
43
|
+
return constructDefaultEmptyDocument(schema, resolvedLimits, admittedCollections);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Validate a schema and derive its document node name and empty document,
|
|
48
|
+
* mirroring what the Rust core does when a handle is created. Use it to build
|
|
49
|
+
* fragments or empty documents for a custom schema.
|
|
50
|
+
*
|
|
51
|
+
* @param schema Defaults to {@link defaultSchema}.
|
|
52
|
+
* @param limits Schema and document bounds. Defaults to
|
|
53
|
+
* {@link DEFAULT_EDITOR_RESOURCE_LIMITS}.
|
|
54
|
+
* @throws NativeEditorBoundaryError `SCHEMA_INVALID` when the schema is
|
|
55
|
+
* malformed, exceeds its limits, or declares no `role: 'doc'` node.
|
|
56
|
+
*/
|
|
57
|
+
export function resolveDocumentDescriptor(
|
|
58
|
+
schema?: SchemaDefinition,
|
|
59
|
+
limits?: DocumentDescriptorLimits
|
|
60
|
+
): ResolvedDocumentSchema {
|
|
61
|
+
const resolvedLimits = resolveDescriptorLimits(limits);
|
|
62
|
+
const resolvedSchema = resolveDocumentSchema(schema, resolvedLimits);
|
|
63
|
+
const documentNode = resolvedSchema.nodes.find((node) => node.role === 'doc');
|
|
64
|
+
if (!documentNode) {
|
|
65
|
+
throw new NativeEditorBoundaryError('SCHEMA_INVALID', 'schema has no document-role node');
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
schema: resolvedSchema,
|
|
69
|
+
documentNodeName: documentNode.name,
|
|
70
|
+
emptyDocument: defaultEmptyDocument(resolvedSchema, resolvedLimits),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function normalizeDocumentJson(
|
|
75
|
+
doc: DocumentJSON,
|
|
76
|
+
schemaOrDescriptor: SchemaDefinition | ResolvedDocumentSchema = defaultSchema,
|
|
77
|
+
limits?: DocumentDescriptorLimits
|
|
78
|
+
): DocumentJSON {
|
|
79
|
+
const descriptor =
|
|
80
|
+
'documentNodeName' in schemaOrDescriptor
|
|
81
|
+
? schemaOrDescriptor
|
|
82
|
+
: resolveDocumentDescriptor(schemaOrDescriptor, limits);
|
|
83
|
+
const root = doc as { type?: unknown; content?: unknown } | null;
|
|
84
|
+
if (root?.type !== descriptor.documentNodeName) {
|
|
85
|
+
return doc;
|
|
86
|
+
}
|
|
87
|
+
const content = root?.content;
|
|
88
|
+
if (Array.isArray(content) && content.length > 0) {
|
|
89
|
+
return doc;
|
|
90
|
+
}
|
|
91
|
+
return descriptor.emptyDocument;
|
|
92
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import type { ResolvedEditorResourceLimits } from './ResourceLimits';
|
|
2
|
+
import type { DocumentJSON } from './NativeEditorBridge';
|
|
3
|
+
import {
|
|
4
|
+
CONTENT_EXPRESSION_MAX_DEPTH,
|
|
5
|
+
DEFAULT_CONTENT_MAX_NODES,
|
|
6
|
+
minimalContentMatch,
|
|
7
|
+
} from './contentExpression';
|
|
8
|
+
import type { SchemaDefinition, NodeSpec } from './schemaDefinition';
|
|
9
|
+
import { type AdmittedSchemaCollections, schemaBoundaryError } from './schemaNormalization';
|
|
10
|
+
|
|
11
|
+
export function constructDefaultEmptyDocument(
|
|
12
|
+
schema: SchemaDefinition,
|
|
13
|
+
resolvedLimits: ResolvedEditorResourceLimits,
|
|
14
|
+
admittedCollections: AdmittedSchemaCollections
|
|
15
|
+
): DocumentJSON {
|
|
16
|
+
const docNode = schema.nodes.find((node) => node.role === 'doc');
|
|
17
|
+
if (!docNode) throw new Error('schema cannot construct a default document: missing doc role');
|
|
18
|
+
|
|
19
|
+
const budget = { nodes: 0, work: 0, exhausted: false };
|
|
20
|
+
const workLimit = Math.min(
|
|
21
|
+
DEFAULT_CONTENT_MAX_NODES,
|
|
22
|
+
resolvedLimits.maxSchemaNodes * 64 + resolvedLimits.maxSchemaExpressionBytes * 32
|
|
23
|
+
);
|
|
24
|
+
const consumeWork = (): boolean => {
|
|
25
|
+
if (budget.work >= workLimit) {
|
|
26
|
+
budget.exhausted = true;
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
budget.work += 1;
|
|
30
|
+
return true;
|
|
31
|
+
};
|
|
32
|
+
const candidatePriority = (candidate: NodeSpec): number => {
|
|
33
|
+
if (
|
|
34
|
+
candidate.role === 'textBlock' &&
|
|
35
|
+
(candidate.htmlTag === 'p' || candidate.name === 'paragraph')
|
|
36
|
+
) {
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
return candidate.role === 'textBlock' ? 1 : 2;
|
|
40
|
+
};
|
|
41
|
+
const candidatesBySymbol = new Map<string, NodeSpec[]>();
|
|
42
|
+
let candidateIndexAdmitted = true;
|
|
43
|
+
const addCandidate = (symbol: string, candidate: NodeSpec): boolean => {
|
|
44
|
+
if (!consumeWork()) return false;
|
|
45
|
+
const candidates = candidatesBySymbol.get(symbol);
|
|
46
|
+
if (candidates) candidates.push(candidate);
|
|
47
|
+
else candidatesBySymbol.set(symbol, [candidate]);
|
|
48
|
+
return true;
|
|
49
|
+
};
|
|
50
|
+
for (const candidate of schema.nodes) {
|
|
51
|
+
if (!addCandidate(candidate.name, candidate)) {
|
|
52
|
+
candidateIndexAdmitted = false;
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
for (const group of admittedCollections.groupsByNode.get(candidate) ?? []) {
|
|
56
|
+
if (group !== candidate.name && !addCandidate(group, candidate)) {
|
|
57
|
+
candidateIndexAdmitted = false;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (!candidateIndexAdmitted) break;
|
|
62
|
+
}
|
|
63
|
+
for (const candidates of candidatesBySymbol.values()) {
|
|
64
|
+
const sortingWork = Math.max(
|
|
65
|
+
candidates.length,
|
|
66
|
+
Math.ceil(candidates.length * Math.log2(Math.max(2, candidates.length)))
|
|
67
|
+
);
|
|
68
|
+
for (let index = 0; index < sortingWork; index += 1) {
|
|
69
|
+
if (!consumeWork()) {
|
|
70
|
+
candidateIndexAdmitted = false;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (!candidateIndexAdmitted) break;
|
|
75
|
+
candidates.sort(
|
|
76
|
+
(left, right) =>
|
|
77
|
+
candidatePriority(left) - candidatePriority(right) ||
|
|
78
|
+
left.name.localeCompare(right.name)
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
if (!candidateIndexAdmitted) {
|
|
82
|
+
throw schemaBoundaryError(workLimit, workLimit + 1);
|
|
83
|
+
}
|
|
84
|
+
const constructNode = (
|
|
85
|
+
node: NodeSpec,
|
|
86
|
+
visiting: Set<string>,
|
|
87
|
+
depth: number
|
|
88
|
+
): DocumentJSON | undefined => {
|
|
89
|
+
if (
|
|
90
|
+
depth > Math.min(CONTENT_EXPRESSION_MAX_DEPTH, resolvedLimits.maxDocumentDepth) ||
|
|
91
|
+
!consumeWork()
|
|
92
|
+
) {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
if (node.role === 'text' || visiting.has(node.name)) return undefined;
|
|
96
|
+
const attrs = admittedCollections.attrsByNode.get(node) ?? [];
|
|
97
|
+
for (const _attr of attrs) {
|
|
98
|
+
if (!consumeWork()) {
|
|
99
|
+
budget.exhausted = true;
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (attrs.some(([, spec]) => spec.default === undefined)) {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
visiting.add(node.name);
|
|
108
|
+
const children = minimalContentMatch(
|
|
109
|
+
node.content ?? '',
|
|
110
|
+
(symbol) => {
|
|
111
|
+
for (const candidate of candidatesBySymbol.get(symbol) ?? []) {
|
|
112
|
+
if (!consumeWork()) return undefined;
|
|
113
|
+
const constructed = constructNode(candidate, visiting, depth + 1);
|
|
114
|
+
if (constructed) return constructed;
|
|
115
|
+
}
|
|
116
|
+
return undefined;
|
|
117
|
+
},
|
|
118
|
+
consumeWork
|
|
119
|
+
);
|
|
120
|
+
visiting.delete(node.name);
|
|
121
|
+
if (!children) return undefined;
|
|
122
|
+
if (budget.nodes >= resolvedLimits.maxDocumentNodes) {
|
|
123
|
+
budget.exhausted = true;
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
budget.nodes += 1;
|
|
127
|
+
|
|
128
|
+
const result: DocumentJSON = { type: node.json?.type ?? node.name };
|
|
129
|
+
if (children.length > 0) result.content = children;
|
|
130
|
+
const projectedAttrs = Object.entries(node.json?.attrs ?? {});
|
|
131
|
+
if (attrs.length > 0 || projectedAttrs.length > 0) {
|
|
132
|
+
result.attrs = Object.fromEntries([
|
|
133
|
+
...attrs.map(([name, spec]) => [name, spec.default] as const),
|
|
134
|
+
...projectedAttrs,
|
|
135
|
+
]);
|
|
136
|
+
}
|
|
137
|
+
return result;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const document = constructNode(docNode, new Set(), 0);
|
|
141
|
+
if (!document) {
|
|
142
|
+
if (budget.exhausted || budget.work >= workLimit) {
|
|
143
|
+
throw schemaBoundaryError(workLimit, workLimit + 1);
|
|
144
|
+
}
|
|
145
|
+
throw new Error(`schema cannot construct a default document for '${docNode.name}'`);
|
|
146
|
+
}
|
|
147
|
+
return document;
|
|
148
|
+
}
|