@stll/folio-core 0.52.0 → 0.54.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/README.md +23 -0
- package/dist/ai-edits/apply.d.ts +26 -1
- package/dist/ai-edits/apply.js +1779 -141
- package/dist/ai-edits/batch-claims.d.ts +145 -0
- package/dist/ai-edits/batch-claims.js +275 -0
- package/dist/ai-edits/blockRange.js +9 -3
- package/dist/ai-edits/character-boundaries.d.ts +43 -0
- package/dist/ai-edits/character-boundaries.js +95 -0
- package/dist/ai-edits/clean-text.d.ts +33 -3
- package/dist/ai-edits/clean-text.js +52 -6
- package/dist/ai-edits/comment-lifecycle.d.ts +18 -0
- package/dist/ai-edits/comment-lifecycle.js +52 -0
- package/dist/ai-edits/headless.d.ts +91 -7
- package/dist/ai-edits/headless.js +520 -51
- package/dist/ai-edits/index.d.ts +2 -1
- package/dist/ai-edits/index.js +2 -1
- package/dist/ai-edits/minimal-replacement.d.ts +21 -6
- package/dist/ai-edits/minimal-replacement.js +134 -15
- package/dist/ai-edits/newListNumbering.d.ts +23 -0
- package/dist/ai-edits/newListNumbering.js +94 -0
- package/dist/ai-edits/note-references.d.ts +96 -0
- package/dist/ai-edits/note-references.js +139 -0
- package/dist/ai-edits/pending-suggestions.d.ts +79 -0
- package/dist/ai-edits/pending-suggestions.js +306 -0
- package/dist/ai-edits/read.d.ts +6 -4
- package/dist/ai-edits/read.js +113 -50
- package/dist/ai-edits/result-validation.d.ts +29 -0
- package/dist/ai-edits/result-validation.js +164 -0
- package/dist/ai-edits/revisionStretches.d.ts +17 -0
- package/dist/ai-edits/revisionStretches.js +80 -0
- package/dist/ai-edits/snapshot.d.ts +36 -3
- package/dist/ai-edits/snapshot.js +180 -25
- package/dist/ai-edits/table-cell-mutations.d.ts +4 -2
- package/dist/ai-edits/table-cell-mutations.js +6 -2
- package/dist/ai-edits/table-geometry.d.ts +1 -1
- package/dist/ai-edits/table-row-column-mutations.d.ts +44 -17
- package/dist/ai-edits/table-row-column-mutations.js +86 -34
- package/dist/ai-edits/types.d.ts +155 -16
- package/dist/compare/compare.d.ts +1 -1
- package/dist/compare/compare.js +65 -16
- package/dist/compare/content-alignment.d.ts +5 -1
- package/dist/compare/content-alignment.js +52 -34
- package/dist/compare/content-types.d.ts +7 -0
- package/dist/compare/content.d.ts +4 -1
- package/dist/compare/content.js +6 -1
- package/dist/compare/formatting.js +2 -1
- package/dist/compare/inline-atoms.d.ts +21 -4
- package/dist/compare/inline-atoms.js +138 -16
- package/dist/compare/inline-provenance.js +1 -1
- package/dist/compare/plan.js +10 -5
- package/dist/compare/scenario.js +14 -3
- package/dist/compare/section-boundary-properties.js +1 -1
- package/dist/compare/types.d.ts +4 -2
- package/dist/compare/types.js +2 -1
- package/dist/compare/verification.d.ts +1 -1
- package/dist/compare/verification.js +15 -3
- package/dist/controller/committedLayoutDiff.d.ts +25 -0
- package/dist/controller/committedLayoutDiff.js +71 -0
- package/dist/controller/contentControlWidgetController.d.ts +1 -1
- package/dist/controller/folioEditor.d.ts +1 -1
- package/dist/controller/fontReadiness.d.ts +70 -3
- package/dist/controller/fontReadiness.js +100 -10
- package/dist/controller/headerFooterEditorManager.js +6 -1
- package/dist/controller/layoutPipeline.d.ts +12 -10
- package/dist/controller/layoutPipeline.js +65 -11
- package/dist/controller/layoutRunOptions.d.ts +24 -0
- package/dist/controller/layoutRunOptions.js +17 -0
- package/dist/controller/layoutScheduler.d.ts +19 -14
- package/dist/controller/layoutScheduler.js +15 -12
- package/dist/controller/layoutSession.d.ts +26 -2
- package/dist/controller/layoutSession.js +1 -1
- package/dist/controller/noteEditorManager.js +8 -3
- package/dist/document-operations.d.ts +11 -2
- package/dist/document-operations.js +230 -21
- package/dist/docx/altChunk.d.ts +8 -0
- package/dist/docx/altChunk.js +17 -0
- package/dist/docx/archiveInflation.d.ts +127 -0
- package/dist/docx/archiveInflation.js +181 -0
- package/dist/docx/attributeRemainder.d.ts +1 -1
- package/dist/docx/blockContentParser.d.ts +64 -1
- package/dist/docx/blockContentParser.js +17 -4
- package/dist/docx/blockCustomXmlShell.d.ts +7 -0
- package/dist/docx/blockCustomXmlShell.js +14 -0
- package/dist/docx/blockPlainText.js +7 -0
- package/dist/docx/commentAnchorIndex.js +1 -1
- package/dist/docx/commentRangeIntegrity.js +8 -3
- package/dist/docx/commentReferenceNormalization.js +1 -1
- package/dist/docx/commentReplyMarkers.js +20 -1
- package/dist/docx/compatibility.d.ts +1 -1
- package/dist/docx/compatibility.js +34 -13
- package/dist/docx/containerChildren.gen.d.ts +1 -1
- package/dist/docx/containerChildren.gen.js +1 -0
- package/dist/docx/documentParser.js +12 -12
- package/dist/docx/drawingIdNormalization.d.ts +3 -1
- package/dist/docx/drawingIdNormalization.js +6 -1
- package/dist/docx/ensureParaIds.js +119 -97
- package/dist/docx/footnoteParser.js +8 -4
- package/dist/docx/headerFooterParser.js +3 -3
- package/dist/docx/headerFooterReferenceNormalization.d.ts +20 -1
- package/dist/docx/headerFooterReferenceNormalization.js +52 -27
- package/dist/docx/hyperlinkParser.d.ts +1 -1
- package/dist/docx/index.d.ts +1 -1
- package/dist/docx/listNumberingInstances.d.ts +59 -0
- package/dist/docx/listNumberingInstances.js +249 -0
- package/dist/docx/metadataPrivacy.js +24 -1
- package/dist/docx/normalizeBaseDirection.js +2 -1
- package/dist/docx/noteReferenceMark.d.ts +15 -0
- package/dist/docx/noteReferenceMark.js +48 -0
- package/dist/docx/opaqueCarrier.d.ts +7 -0
- package/dist/docx/opaqueCarrier.js +38 -0
- package/dist/docx/packageParts.js +4 -1
- package/dist/docx/paragraphParser.js +96 -27
- package/dist/docx/paragraphPropertySource.d.ts +4 -2
- package/dist/docx/paragraphPropertySource.js +10 -2
- package/dist/docx/paragraphTraversal.js +1 -0
- package/dist/docx/parseWarningMessage.js +4 -1
- package/dist/docx/parser.js +175 -22
- package/dist/docx/rezip.js +31 -7
- package/dist/docx/sdtProperties.js +1 -1
- package/dist/docx/sdtPropertiesPatch.js +3 -0
- package/dist/docx/selectiveSave.js +16 -9
- package/dist/docx/selectiveXmlPatch.d.ts +3 -1
- package/dist/docx/selectiveXmlPatch.js +186 -39
- package/dist/docx/serializer/blockCustomXmlSerializer.d.ts +5 -0
- package/dist/docx/serializer/blockCustomXmlSerializer.js +4 -0
- package/dist/docx/serializer/documentSerializer.js +2 -0
- package/dist/docx/serializer/headerFooterSerializer.js +2 -0
- package/dist/docx/serializer/noteSerializer.js +3 -1
- package/dist/docx/serializer/paragraphSerializer.js +33 -9
- package/dist/docx/serializer/tableSerializer.js +25 -38
- package/dist/docx/server/boundedArchive.d.ts +8 -13
- package/dist/docx/server/boundedArchive.js +70 -59
- package/dist/docx/server/createBilingualDocument.js +3 -3
- package/dist/docx/server/extractDocxText.d.ts +8 -2
- package/dist/docx/server/extractDocxText.js +2 -2
- package/dist/docx/server/validateDocxConformance.d.ts +1 -1
- package/dist/docx/server/validateDocxConformance.js +1 -0
- package/dist/docx/tableParser.d.ts +157 -1
- package/dist/docx/tableParser.js +89 -10
- package/dist/docx/textBoxParser.js +1 -1
- package/dist/docx/unzip.d.ts +20 -2
- package/dist/docx/unzip.js +136 -25
- package/dist/docx/wordprocessingPrefixes.d.ts +78 -0
- package/dist/docx/wordprocessingPrefixes.js +286 -0
- package/dist/fonts/embeddedFonts.js +1 -1
- package/dist/i18n/messages/catalogs.gen.d.ts +170 -34
- package/dist/i18n/messages/catalogs.gen.js +187 -51
- package/dist/i18n/messages/messages.gen.d.ts +10 -2
- package/dist/internal/compare/inline-presentation.d.ts +2 -1
- package/dist/internal/compare/inline-presentation.js +11 -10
- package/dist/internal/headlessRevisionResolutionGuard.d.ts +2 -8
- package/dist/internal/headlessRevisionResolutionGuard.js +2 -11
- package/dist/internal/indexedPositionMap.d.ts +11 -0
- package/dist/internal/indexedPositionMap.js +42 -0
- package/dist/internal/pageBreakRunSourceDescendantIndex.js +2 -1
- package/dist/internal/revisionResolutionEdits.d.ts +13 -0
- package/dist/internal/revisionResolutionEdits.js +19 -0
- package/dist/internal/revisionResolutionInline.d.ts +24 -0
- package/dist/internal/{headlessRevisionResolution.js → revisionResolutionInline.js} +61 -43
- package/dist/internal/revisionResolutionStep.d.ts +34 -0
- package/dist/internal/revisionResolutionStep.js +282 -0
- package/dist/internal/revisionResolutionTracking.d.ts +11 -0
- package/dist/internal/revisionResolutionTracking.js +124 -0
- package/dist/internal/wholeStoryRevisionResolution.d.ts +56 -0
- package/dist/internal/wholeStoryRevisionResolution.js +600 -0
- package/dist/layout-bridge/convert/markupViewFlow.d.ts +20 -0
- package/dist/layout-bridge/convert/markupViewFlow.js +123 -0
- package/dist/layout-bridge/convert/tableConversion.js +1 -1
- package/dist/layout-bridge/convert/toFlowBlocks.js +10 -1
- package/dist/layout-engine/layoutInstrumentation.d.ts +9 -1
- package/dist/layout-engine/layoutInstrumentation.js +4 -1
- package/dist/layout-engine/measure/cache.d.ts +18 -1
- package/dist/layout-engine/measure/cache.js +31 -1
- package/dist/layout-engine/measure/font-metrics.worker.js +3 -7
- package/dist/layout-engine/measure/measureContainer.js +7 -47
- package/dist/layout-engine/measure/measureHelpers.d.ts +6 -1
- package/dist/layout-engine/measure/measureHelpers.js +22 -2
- package/dist/layout-engine/measure/measureParagraph.js +2 -2
- package/dist/layout-engine/measure/measureWorker.js +2 -3
- package/dist/layout-engine/measure/measureWorkerProtocol.d.ts +6 -7
- package/dist/layout-engine/measure/measureWorkerProtocol.js +1 -2
- package/dist/layout-engine/measure/paragraphMeasureShared.d.ts +12 -1
- package/dist/layout-engine/measure/paragraphMeasureShared.js +14 -1
- package/dist/layout-engine/types.d.ts +6 -0
- package/dist/layout-painter/renderPage.js +1 -0
- package/dist/layout-painter/renderParagraph.js +1 -1
- package/dist/managers/ContextMenuManager.js +5 -2
- package/dist/managers/types.d.ts +3 -0
- package/dist/markdown/escape.d.ts +2 -2
- package/dist/markdown/escape.js +4 -5
- package/dist/markdown/fromMarkdown.js +2 -1
- package/dist/markdown/internals.d.ts +11 -1
- package/dist/markdown/internals.js +24 -3
- package/dist/markdown/renderBlock.js +121 -25
- package/dist/markdown/renderParagraph.d.ts +13 -1
- package/dist/markdown/renderParagraph.js +85 -38
- package/dist/markdown/renderRuns.d.ts +10 -1
- package/dist/markdown/renderRuns.js +323 -69
- package/dist/markdown/renderTable.js +24 -12
- package/dist/markdown/trailers.js +2 -2
- package/dist/markdown/types.d.ts +29 -7
- package/dist/paged-layout/incrementalMeasure.d.ts +1 -2
- package/dist/paged-layout/incrementalMeasure.js +1 -9
- package/dist/paged-layout/transactionDirtyRange.d.ts +1 -3
- package/dist/paged-layout/transactionDirtyRange.js +29 -41
- package/dist/panel-layout.d.ts +83 -0
- package/dist/panel-layout.js +96 -0
- package/dist/prosemirror/anchoredTextBoxes.d.ts +37 -0
- package/dist/prosemirror/anchoredTextBoxes.js +156 -0
- package/dist/prosemirror/attrs/index.d.ts +6 -2
- package/dist/prosemirror/attrs/index.js +172 -1
- package/dist/prosemirror/clearRunColor.d.ts +6 -0
- package/dist/prosemirror/clearRunColor.js +46 -0
- package/dist/prosemirror/commands/comments.d.ts +7 -8
- package/dist/prosemirror/commands/comments.js +281 -212
- package/dist/prosemirror/commands/contentControls.d.ts +1 -1
- package/dist/prosemirror/commands/formatPainter.d.ts +1 -1
- package/dist/prosemirror/commands/formatPainter.js +1 -1
- package/dist/prosemirror/commands/formatting.d.ts +1 -1
- package/dist/prosemirror/commands/hyperlink.js +2 -1
- package/dist/prosemirror/commands/index.d.ts +2 -2
- package/dist/prosemirror/commands/index.js +2 -2
- package/dist/prosemirror/commands/paragraph.d.ts +7 -1
- package/dist/prosemirror/commands/paragraph.js +9 -1
- package/dist/prosemirror/commands/paragraphBookmarkJoin.d.ts +13 -0
- package/dist/prosemirror/commands/paragraphBookmarkJoin.js +22 -0
- package/dist/prosemirror/commands/pastePlainText.d.ts +1 -1
- package/dist/prosemirror/commands/propertyChangeScope.d.ts +3 -2
- package/dist/prosemirror/commands/propertyChangeScope.js +24 -3
- package/dist/prosemirror/commands/resolveAllTableChanges.d.ts +40 -0
- package/dist/prosemirror/commands/resolveAllTableChanges.js +620 -0
- package/dist/prosemirror/commands/resolveNodePropertyChangeAttrs.d.ts +15 -0
- package/dist/prosemirror/commands/resolveNodePropertyChangeAttrs.js +46 -0
- package/dist/prosemirror/commands/resolveParagraphProperties.d.ts +16 -0
- package/dist/prosemirror/commands/resolveParagraphProperties.js +73 -0
- package/dist/prosemirror/commands/sectionBreak.js +2 -1
- package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +15 -2
- package/dist/prosemirror/commands/tableCellMergeResolution.js +23 -7
- package/dist/prosemirror/containerFinalParagraph.d.ts +11 -5
- package/dist/prosemirror/containerFinalParagraph.js +7 -6
- package/dist/prosemirror/contentControlRevisions.d.ts +1 -1
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -13
- package/dist/prosemirror/conversion/fromProseDoc.js +177 -605
- package/dist/prosemirror/conversion/toProseDoc.d.ts +4 -11
- package/dist/prosemirror/conversion/toProseDoc.js +70 -154
- package/dist/prosemirror/documentSchema.d.ts +8 -0
- package/dist/prosemirror/documentSchema.js +18 -0
- package/dist/prosemirror/emptyFieldResultRuns.d.ts +18 -0
- package/dist/prosemirror/emptyFieldResultRuns.js +33 -0
- package/dist/prosemirror/extensions/ExtensionManager.d.ts +1 -1
- package/dist/prosemirror/extensions/ExtensionManager.js +3 -1
- package/dist/prosemirror/extensions/StarterKit.js +5 -1
- package/dist/prosemirror/extensions/core/DocExtension.js +1 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +116 -63
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +4 -1
- package/dist/prosemirror/extensions/features/EmptyParagraphFormatExtension.js +24 -3
- package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.d.ts +20 -0
- package/dist/prosemirror/extensions/features/JoinedRunStyleExtension.js +43 -0
- package/dist/prosemirror/extensions/features/ListExtension.js +167 -128
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +19 -2
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +33 -20
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +31 -2
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +270 -99
- package/dist/prosemirror/extensions/features/PasteCleanupExtension.js +3 -2
- package/dist/prosemirror/extensions/features/pasteCleanup.js +2 -1
- package/dist/prosemirror/extensions/features/pastedHeadingStyles.js +1 -1
- package/dist/prosemirror/extensions/features/pastedHtmlLists.d.ts +12 -0
- package/dist/prosemirror/extensions/features/pastedHtmlLists.js +124 -0
- package/dist/prosemirror/extensions/marks/FootnoteRefExtension.js +33 -11
- package/dist/prosemirror/extensions/marks/HyperlinkExtension.js +8 -4
- package/dist/prosemirror/extensions/marks/RunIdentityExtension.d.ts +21 -18
- package/dist/prosemirror/extensions/marks/RunIdentityExtension.js +37 -17
- package/dist/prosemirror/extensions/marks/StrikeExtension.js +2 -2
- package/dist/prosemirror/extensions/marks/SubscriptExtension.js +2 -2
- package/dist/prosemirror/extensions/marks/SuperscriptExtension.js +2 -2
- package/dist/prosemirror/extensions/marks/TextColorExtension.js +4 -3
- package/dist/prosemirror/extensions/marks/markUtils.d.ts +15 -8
- package/dist/prosemirror/extensions/marks/markUtils.js +25 -10
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.d.ts +12 -0
- package/dist/prosemirror/extensions/marks/noteReferenceDeletion.js +46 -0
- package/dist/prosemirror/extensions/nodes/BlockCustomXmlExtension.d.ts +6 -0
- package/dist/prosemirror/extensions/nodes/BlockCustomXmlExtension.js +52 -0
- package/dist/prosemirror/extensions/nodes/CommentReferenceExtension.js +2 -2
- package/dist/prosemirror/extensions/nodes/FieldExtension.d.ts +3 -3
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +50 -15
- package/dist/prosemirror/extensions/nodes/HardBreakExtension.js +5 -3
- package/dist/prosemirror/extensions/nodes/PreservedBlockExtension.js +4 -1
- package/dist/prosemirror/extensions/nodes/TableExtension.d.ts +1 -1
- package/dist/prosemirror/extensions/nodes/TableExtension.js +121 -226
- package/dist/prosemirror/extensions/types.d.ts +11 -1
- package/dist/prosemirror/findReplaceSelection.js +1 -1
- package/dist/prosemirror/hyperlinkRemoval.d.ts +9 -0
- package/dist/prosemirror/hyperlinkRemoval.js +129 -0
- package/dist/prosemirror/index.d.ts +5 -3
- package/dist/prosemirror/index.js +5 -3
- package/dist/prosemirror/indexedNodeLookup.d.ts +17 -0
- package/dist/prosemirror/indexedNodeLookup.js +103 -0
- package/dist/prosemirror/listAutoformatMarkers.d.ts +19 -0
- package/dist/prosemirror/listAutoformatMarkers.js +98 -0
- package/dist/prosemirror/listInstanceReferences.d.ts +12 -0
- package/dist/prosemirror/listInstanceReferences.js +72 -0
- package/dist/prosemirror/listLabels.d.ts +24 -0
- package/dist/prosemirror/listLabels.js +111 -0
- package/dist/prosemirror/listNumbering.d.ts +92 -0
- package/dist/prosemirror/listNumbering.js +330 -0
- package/dist/prosemirror/listRendering.d.ts +27 -0
- package/dist/prosemirror/listRendering.js +27 -0
- package/dist/prosemirror/listRenderingAttrs.d.ts +11 -2
- package/dist/prosemirror/listRenderingAttrs.js +8 -1
- package/dist/prosemirror/markupViewNotes.d.ts +8 -0
- package/dist/prosemirror/markupViewNotes.js +49 -0
- package/dist/prosemirror/markupViewProjection.d.ts +97 -0
- package/dist/prosemirror/markupViewProjection.js +88 -0
- package/dist/prosemirror/noteReferenceReview.d.ts +77 -0
- package/dist/prosemirror/noteReferenceReview.js +332 -0
- package/dist/prosemirror/numberingAttr.d.ts +9 -1
- package/dist/prosemirror/numberingAttr.js +9 -1
- package/dist/prosemirror/outlineLevelAttr.js +1 -1
- package/dist/prosemirror/paragraphIndentation.d.ts +10 -1
- package/dist/prosemirror/paragraphIndentation.js +32 -7
- package/dist/prosemirror/paragraphMarkJoin.d.ts +21 -0
- package/dist/prosemirror/paragraphMarkJoin.js +26 -0
- package/dist/prosemirror/paragraphPropertyCarry.d.ts +64 -0
- package/dist/prosemirror/paragraphPropertyCarry.js +158 -0
- package/dist/prosemirror/plugins/createDocScanPlugin.d.ts +1 -1
- package/dist/prosemirror/plugins/documentNumbering.d.ts +27 -1
- package/dist/prosemirror/plugins/documentNumbering.js +97 -11
- package/dist/prosemirror/plugins/documentStyleState.d.ts +26 -0
- package/dist/prosemirror/plugins/documentStyleState.js +32 -0
- package/dist/prosemirror/plugins/documentStyles.d.ts +3 -13
- package/dist/prosemirror/plugins/documentStyles.js +67 -17
- package/dist/prosemirror/plugins/index.d.ts +2 -1
- package/dist/prosemirror/plugins/index.js +2 -1
- package/dist/prosemirror/plugins/paragraphStyleResolution.d.ts +15 -0
- package/dist/prosemirror/plugins/paragraphStyleResolution.js +230 -0
- package/dist/prosemirror/plugins/suggestionMode.d.ts +27 -3
- package/dist/prosemirror/plugins/suggestionMode.js +490 -63
- package/dist/prosemirror/plugins/templateDirectives.d.ts +1 -1
- package/dist/prosemirror/plugins/transactionInvariants.d.ts +32 -0
- package/dist/prosemirror/plugins/transactionInvariants.js +86 -0
- package/dist/prosemirror/positionSweep.d.ts +24 -0
- package/dist/prosemirror/positionSweep.js +222 -0
- package/dist/prosemirror/rebaseParagraphRunFormatting.d.ts +23 -3
- package/dist/prosemirror/rebaseParagraphRunFormatting.js +39 -13
- package/dist/prosemirror/rebaseParagraphRuns.d.ts +36 -0
- package/dist/prosemirror/rebaseParagraphRuns.js +99 -0
- package/dist/prosemirror/rejoinRunCarriers.d.ts +1 -1
- package/dist/prosemirror/replacedAnnotations.d.ts +33 -1
- package/dist/prosemirror/replacedAnnotations.js +170 -1
- package/dist/prosemirror/runFormattingFromMarks.d.ts +18 -0
- package/dist/prosemirror/runFormattingFromMarks.js +567 -0
- package/dist/prosemirror/runFormattingInlineCarriers.d.ts +1 -1
- package/dist/prosemirror/runFormattingReconciliation.js +10 -9
- package/dist/prosemirror/schema/index.d.ts +2 -2
- package/dist/prosemirror/schema/index.js +3 -0
- package/dist/prosemirror/schema/nodes.d.ts +44 -11
- package/dist/prosemirror/sectionMarkEdits.d.ts +20 -0
- package/dist/prosemirror/sectionMarkEdits.js +59 -0
- package/dist/prosemirror/storyListNumbering.d.ts +17 -0
- package/dist/prosemirror/storyListNumbering.js +102 -0
- package/dist/prosemirror/styles/paragraphStyleCascade.d.ts +59 -0
- package/dist/prosemirror/styles/paragraphStyleCascade.js +145 -0
- package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +21 -2
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +38 -1
- package/dist/prosemirror/styles/tableStyleRegions.d.ts +31 -0
- package/dist/prosemirror/styles/tableStyleRegions.js +55 -0
- package/dist/prosemirror/tableCellPaste.d.ts +74 -0
- package/dist/prosemirror/tableCellPaste.js +525 -0
- package/dist/prosemirror/tableGridMutation.d.ts +87 -2
- package/dist/prosemirror/tableGridMutation.js +255 -2
- package/dist/prosemirror/tableRunIn.d.ts +51 -0
- package/dist/prosemirror/tableRunIn.js +165 -0
- package/dist/prosemirror/textInput.js +11 -2
- package/dist/prosemirror/trackedRevisionPath.d.ts +17 -0
- package/dist/prosemirror/trackedRevisionPath.js +32 -0
- package/dist/prosemirror/validation.js +5 -1
- package/dist/redline.js +93 -9
- package/dist/render-dom/BodySelectionOverlay.d.ts +4 -1
- package/dist/render-dom/BodySelectionOverlay.js +3 -2
- package/dist/server.d.ts +2 -2
- package/dist/utils/findReplace.js +2 -2
- package/dist/utils/mergeDocumentContent.js +1 -1
- package/dist/utils/noteReferenceLabels.d.ts +36 -0
- package/dist/utils/noteReferenceLabels.js +32 -0
- package/dist/utils/replaceText.js +1 -1
- package/dist/version-comparison.d.ts +1 -0
- package/dist/version-comparison.js +1 -0
- package/package.json +6 -5
- package/dist/internal/headlessRevisionResolution.d.ts +0 -23
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
//#region src/prosemirror/styles/tableStyleRegions.ts
|
|
2
|
+
/**
|
|
3
|
+
* The horizontal band a row takes by position: every row but a styled first
|
|
4
|
+
* or last row alternates, starting with band 1.
|
|
5
|
+
*/
|
|
6
|
+
const tableRowBand = (look, rowIndex, totalRows) => {
|
|
7
|
+
if (look.noHBand) return;
|
|
8
|
+
const styledFirstRow = rowIndex === 0 && look.firstRow;
|
|
9
|
+
const styledLastRow = rowIndex === totalRows - 1 && look.lastRow;
|
|
10
|
+
if (styledFirstRow || styledLastRow) return;
|
|
11
|
+
return (look.firstRow && rowIndex > 0 ? rowIndex - 1 : rowIndex) % 2 === 0 ? "band1Horz" : "band2Horz";
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* The regions that apply to one cell, lowest precedence first: the whole
|
|
15
|
+
* table, banding, columns, rows, then corners (ECMA-376 §17.7.6). A cell's or
|
|
16
|
+
* row's `w:cnfStyle` overrides what its position implies.
|
|
17
|
+
*/
|
|
18
|
+
const tableCellStyleRegions = ({ look, rowIndex, totalRows, column, colspan, totalColumns, rowBand, rowConditionalFormat: rowCnf, cellConditionalFormat: cellCnf }) => {
|
|
19
|
+
const rowIsFirstRow = rowCnf?.firstRow ?? rowIndex === 0;
|
|
20
|
+
const rowIsLastRow = rowCnf?.lastRow ?? rowIndex === totalRows - 1;
|
|
21
|
+
const isFirstRow = cellCnf?.firstRow ?? rowIsFirstRow;
|
|
22
|
+
const isLastRow = cellCnf?.lastRow ?? rowIsLastRow;
|
|
23
|
+
const isFirstCol = cellCnf?.firstColumn ?? column === 0;
|
|
24
|
+
const isLastCol = cellCnf?.lastColumn ?? column + colspan === totalColumns;
|
|
25
|
+
let verticalBand;
|
|
26
|
+
if (!look.noVBand) {
|
|
27
|
+
const bandColumn = column - (look.firstColumn ? 1 : 0);
|
|
28
|
+
if (bandColumn >= 0 && !(look.lastColumn && isLastCol) && !(look.firstColumn && isFirstCol)) verticalBand = bandColumn % 2 === 0 ? "band1Vert" : "band2Vert";
|
|
29
|
+
}
|
|
30
|
+
if (cellCnf?.oddVBand) verticalBand = "band1Vert";
|
|
31
|
+
else if (cellCnf?.evenVBand) verticalBand = "band2Vert";
|
|
32
|
+
let horizontalBand = rowBand;
|
|
33
|
+
if (rowCnf?.oddHBand) horizontalBand = "band1Horz";
|
|
34
|
+
else if (rowCnf?.evenHBand) horizontalBand = "band2Horz";
|
|
35
|
+
if (cellCnf?.oddHBand) horizontalBand = "band1Horz";
|
|
36
|
+
else if (cellCnf?.evenHBand) horizontalBand = "band2Horz";
|
|
37
|
+
const firstRowOn = look.firstRow || rowCnf?.firstRow === true || cellCnf?.firstRow === true;
|
|
38
|
+
const lastRowOn = look.lastRow || rowCnf?.lastRow === true || cellCnf?.lastRow === true;
|
|
39
|
+
const firstColOn = look.firstColumn || rowCnf?.firstColumn === true || cellCnf?.firstColumn === true;
|
|
40
|
+
const lastColOn = look.lastColumn || rowCnf?.lastColumn === true || cellCnf?.lastColumn === true;
|
|
41
|
+
const regions = ["wholeTable"];
|
|
42
|
+
if (horizontalBand) regions.push(horizontalBand);
|
|
43
|
+
if (verticalBand) regions.push(verticalBand);
|
|
44
|
+
if (isFirstCol && firstColOn) regions.push("firstCol");
|
|
45
|
+
if (isLastCol && lastColOn) regions.push("lastCol");
|
|
46
|
+
if (isFirstRow && firstRowOn) regions.push("firstRow");
|
|
47
|
+
if (isLastRow && lastRowOn) regions.push("lastRow");
|
|
48
|
+
if (isFirstRow && isFirstCol && firstRowOn && firstColOn) regions.push("nwCell");
|
|
49
|
+
if (isFirstRow && isLastCol && firstRowOn && lastColOn) regions.push("neCell");
|
|
50
|
+
if (isLastRow && isFirstCol && lastRowOn && firstColOn) regions.push("swCell");
|
|
51
|
+
if (isLastRow && isLastCol && lastRowOn && lastColOn) regions.push("seCell");
|
|
52
|
+
return regions;
|
|
53
|
+
};
|
|
54
|
+
//#endregion
|
|
55
|
+
export { tableCellStyleRegions, tableRowBand };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Fragment, Node, Slice } from "prosemirror-model";
|
|
2
|
+
import { EditorState, Transaction } from "prosemirror-state";
|
|
3
|
+
import { CellSelection, Rect } from "prosemirror-tables";
|
|
4
|
+
//#region src/prosemirror/tableCellPaste.d.ts
|
|
5
|
+
/** A rectangular block of cells, one fragment of cells per row. */
|
|
6
|
+
type PastedCells = {
|
|
7
|
+
width: number;
|
|
8
|
+
height: number;
|
|
9
|
+
rows: Fragment[];
|
|
10
|
+
};
|
|
11
|
+
/** What a tracked paste records its changes as. */
|
|
12
|
+
type TableCellPasteRevision = {
|
|
13
|
+
revisionId: number;
|
|
14
|
+
author: string;
|
|
15
|
+
date: string;
|
|
16
|
+
};
|
|
17
|
+
type TableCellPasteHooks = {
|
|
18
|
+
/**
|
|
19
|
+
* The revision a split merge, a grown row or a grown column is tracked
|
|
20
|
+
* under; untracked when absent.
|
|
21
|
+
*/
|
|
22
|
+
revision?: TableCellPasteRevision;
|
|
23
|
+
/**
|
|
24
|
+
* Replace the content of the cell at `cellPos` with `slice`. Untracked
|
|
25
|
+
* pastes replace it outright; a tracked paste keeps the old content as a
|
|
26
|
+
* deletion.
|
|
27
|
+
*/
|
|
28
|
+
replaceCellContent?: CellContentReplacer;
|
|
29
|
+
};
|
|
30
|
+
type CellContentReplacer = (tr: Transaction, cellPos: number, slice: Slice) => void;
|
|
31
|
+
/**
|
|
32
|
+
* A pasted slice whose table cells are new cells: a copy of a cell must not
|
|
33
|
+
* claim the source cell's identity, revisions, or the continuation cells its
|
|
34
|
+
* merge stored, whatever the paste lands on.
|
|
35
|
+
*/
|
|
36
|
+
declare const pastedSliceWithNewTableCells: (slice: Slice) => Slice;
|
|
37
|
+
/** The cells a slice holds, or null when it holds none (it is not table content). */
|
|
38
|
+
declare const pastedCells: (slice: Slice) => PastedCells | null;
|
|
39
|
+
/**
|
|
40
|
+
* The range of a cell's content a paste replaces. A block of whole paragraphs
|
|
41
|
+
* (a pasted cell's content) replaces all of it; open content (text, or
|
|
42
|
+
* paragraphs cut from a longer run) goes from the start of the first paragraph
|
|
43
|
+
* to the end of the last, so it takes on the cell's paragraph formatting the
|
|
44
|
+
* way a paste into a paragraph does.
|
|
45
|
+
*/
|
|
46
|
+
declare const cellPasteRange: (cell: Node, cellPos: number, slice: Slice) => {
|
|
47
|
+
from: number;
|
|
48
|
+
to: number;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* Paste a block of cells into the table at `tableStart` from (`top`, `left`):
|
|
52
|
+
* grow the table to hold it, split the merges its edges cut through, then give
|
|
53
|
+
* each cell the block covers its pasted cell. Where the block's cells have the
|
|
54
|
+
* table's shapes the table keeps its cells, with their formatting and
|
|
55
|
+
* identity, and takes the pasted content; otherwise the block's cells replace
|
|
56
|
+
* them, except in a tracked paste, which keeps the table's shape. Selects the
|
|
57
|
+
* pasted block.
|
|
58
|
+
*/
|
|
59
|
+
declare const insertTableCells: (tr: Transaction, tableStart: number, { top, left }: Pick<Rect, "top" | "left">, cells: PastedCells, { revision, replaceCellContent }?: TableCellPasteHooks) => Transaction;
|
|
60
|
+
/**
|
|
61
|
+
* Paste into every cell of a cell selection: each takes the pasted cell at its
|
|
62
|
+
* place in the block, the block repeating to cover the selection, or the
|
|
63
|
+
* pasted content itself when it holds no cells. The table keeps its shape.
|
|
64
|
+
*/
|
|
65
|
+
declare const fillSelectedCells: (tr: Transaction, selection: CellSelection, slice: Slice, { replaceCellContent }?: TableCellPasteHooks) => Transaction;
|
|
66
|
+
/**
|
|
67
|
+
* Paste `slice` into the table the selection is in: into every selected cell
|
|
68
|
+
* of a cell selection, or, when the slice holds cells, as a block of cells
|
|
69
|
+
* from the cell holding the cursor. False otherwise, so the paste falls
|
|
70
|
+
* through to the ordinary one.
|
|
71
|
+
*/
|
|
72
|
+
declare const pasteTableCells: (state: EditorState, slice: Slice, dispatch?: (tr: Transaction) => void, hooks?: TableCellPasteHooks) => boolean;
|
|
73
|
+
//#endregion
|
|
74
|
+
export { CellContentReplacer, PastedCells, TableCellPasteHooks, TableCellPasteRevision, cellPasteRange, fillSelectedCells, insertTableCells, pasteTableCells, pastedCells, pastedSliceWithNewTableCells };
|
|
@@ -0,0 +1,525 @@
|
|
|
1
|
+
import { decodeTableCellParagraphSourcePayload, transportTableCellsWithParagraphPropertySources } from "../docx/paragraphPropertySource.js";
|
|
2
|
+
import { expectTableAttrs, mergeTableAttrs } from "./attrs/index.js";
|
|
3
|
+
import { Fragment, Slice } from "prosemirror-model";
|
|
4
|
+
import { CellSelection, TableMap, cellAround, tableNodeTypes } from "prosemirror-tables";
|
|
5
|
+
import { Transform } from "prosemirror-transform";
|
|
6
|
+
//#region src/prosemirror/tableCellPaste.ts
|
|
7
|
+
/**
|
|
8
|
+
* Pasting table cells into a table: the pasted cells overwrite the cells they
|
|
9
|
+
* land on, merges the pasted block cuts through are split first, and the table
|
|
10
|
+
* grows when the block reaches past its edge. A paste into a cell selection
|
|
11
|
+
* fills every selected cell instead and leaves the table's shape alone.
|
|
12
|
+
*
|
|
13
|
+
* `prosemirror-tables` ships the same operation as its `handlePaste`, but its
|
|
14
|
+
* merge splitting inserts the lower half of a vertical merge at a position
|
|
15
|
+
* relative to the table rather than to the document, so in any table that does
|
|
16
|
+
* not open the document the new cell lands inside an earlier cell and the
|
|
17
|
+
* paste either throws or leaves rows that no longer tile the grid. Its split
|
|
18
|
+
* halves also copy every attribute of the cell they came from, so both halves
|
|
19
|
+
* claim the same source cell and the same stored merge continuation.
|
|
20
|
+
*
|
|
21
|
+
* With suggestions on, the paste is tracked: each overwritten cell keeps its
|
|
22
|
+
* content as a deletion before the pasted content, a vertical merge the block
|
|
23
|
+
* cuts through is split as a tracked cell merge, and the rows and cells the
|
|
24
|
+
* table grows by are tracked insertions, so rejecting every change gives the
|
|
25
|
+
* table back. A horizontal merge has no tracked split, so one the block cuts
|
|
26
|
+
* through is split directly, as the structural table commands do.
|
|
27
|
+
*/
|
|
28
|
+
const fitSlice = (nodeType, slice) => {
|
|
29
|
+
const node = nodeType.createAndFill();
|
|
30
|
+
if (!node) throw new RangeError(`Cannot create an empty ${nodeType.name}`);
|
|
31
|
+
return new Transform(node).replace(0, node.content.size, slice).doc;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* A cell's attributes with `count` of its columns, from the `from`th on, taken
|
|
35
|
+
* out of its span and its column widths.
|
|
36
|
+
*/
|
|
37
|
+
const withoutColumns = (attrs, from, count) => {
|
|
38
|
+
const colwidth = attrs["colwidth"];
|
|
39
|
+
const widths = Array.isArray(colwidth) ? colwidth.toSpliced(from, count) : null;
|
|
40
|
+
return {
|
|
41
|
+
...attrs,
|
|
42
|
+
colspan: Math.max(1, Number(attrs["colspan"]) || 1) - count,
|
|
43
|
+
colwidth: widths?.some((width) => Number(width) > 0) ? widths : null
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
const spanOf = (cell, name) => Math.max(1, Number(cell.attrs[name]) || 1);
|
|
47
|
+
/** Pad short rows with empty cells so the block is rectangular. */
|
|
48
|
+
const ensureRectangular = (schema, rows) => {
|
|
49
|
+
const widths = [];
|
|
50
|
+
for (const [index, row] of rows.entries()) for (let child = row.childCount - 1; child >= 0; child--) {
|
|
51
|
+
const cell = row.child(child);
|
|
52
|
+
for (let covered = index; covered < index + spanOf(cell, "rowspan"); covered++) widths[covered] = (widths[covered] ?? 0) + spanOf(cell, "colspan");
|
|
53
|
+
}
|
|
54
|
+
const width = Math.max(0, ...widths.map((value) => value ?? 0));
|
|
55
|
+
for (let index = 0; index < widths.length; index++) {
|
|
56
|
+
if (index >= rows.length) rows.push(Fragment.empty);
|
|
57
|
+
const rowWidth = widths[index] ?? 0;
|
|
58
|
+
if (rowWidth < width) {
|
|
59
|
+
const cells = [];
|
|
60
|
+
for (let column = rowWidth; column < width; column++) {
|
|
61
|
+
const empty = tableNodeTypes(schema).cell.createAndFill();
|
|
62
|
+
if (empty) cells.push(empty);
|
|
63
|
+
}
|
|
64
|
+
rows[index] = (rows[index] ?? Fragment.empty).append(Fragment.from(cells));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
height: rows.length,
|
|
69
|
+
width,
|
|
70
|
+
rows
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* The attributes of a cell made from another one, split off it or pasted from
|
|
75
|
+
* a copy of it: the same formatting, but not the other cell's identity, its
|
|
76
|
+
* revisions, or the continuation cells its merge stored, whose paragraphs
|
|
77
|
+
* belong to the other cell.
|
|
78
|
+
*/
|
|
79
|
+
const newCellAttrs = (attrs) => ({
|
|
80
|
+
...attrs,
|
|
81
|
+
_docxCellId: null,
|
|
82
|
+
cellMarker: null,
|
|
83
|
+
tcPrChange: null,
|
|
84
|
+
_preserveVMergeRestart: null,
|
|
85
|
+
_docxVMergeContinuationCells: null
|
|
86
|
+
});
|
|
87
|
+
const withNewTableCells = (node) => {
|
|
88
|
+
if (node.isTextblock || node.isLeaf) return node;
|
|
89
|
+
const content = withNewTableCellsIn(node.content);
|
|
90
|
+
const role = node.type.spec["tableRole"];
|
|
91
|
+
const isCell = role === "cell" || role === "header_cell";
|
|
92
|
+
return content === node.content && !isCell ? node : node.type.create(isCell ? newCellAttrs(node.attrs) : node.attrs, content, node.marks);
|
|
93
|
+
};
|
|
94
|
+
const withNewTableCellsIn = (fragment) => {
|
|
95
|
+
let changed = false;
|
|
96
|
+
const nodes = [];
|
|
97
|
+
fragment.forEach((node) => {
|
|
98
|
+
const next = withNewTableCells(node);
|
|
99
|
+
changed ||= next !== node;
|
|
100
|
+
nodes.push(next);
|
|
101
|
+
});
|
|
102
|
+
return changed ? Fragment.from(nodes) : fragment;
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* A pasted slice whose table cells are new cells: a copy of a cell must not
|
|
106
|
+
* claim the source cell's identity, revisions, or the continuation cells its
|
|
107
|
+
* merge stored, whatever the paste lands on.
|
|
108
|
+
*/
|
|
109
|
+
const pastedSliceWithNewTableCells = (slice) => {
|
|
110
|
+
const content = withNewTableCellsIn(slice.content);
|
|
111
|
+
return content === slice.content ? slice : new Slice(content, slice.openStart, slice.openEnd);
|
|
112
|
+
};
|
|
113
|
+
/** The cells a slice holds, or null when it holds none (it is not table content). */
|
|
114
|
+
const pastedCells = (slice) => {
|
|
115
|
+
if (slice.size === 0) return null;
|
|
116
|
+
let { content, openStart, openEnd } = slice;
|
|
117
|
+
while (content.childCount === 1 && (openStart > 0 && openEnd > 0 || content.child(0).type.spec["tableRole"] === "table")) {
|
|
118
|
+
openStart--;
|
|
119
|
+
openEnd--;
|
|
120
|
+
content = content.child(0).content;
|
|
121
|
+
}
|
|
122
|
+
const first = content.firstChild;
|
|
123
|
+
if (!first) return null;
|
|
124
|
+
const role = first.type.spec["tableRole"];
|
|
125
|
+
const { schema } = first.type;
|
|
126
|
+
const rows = [];
|
|
127
|
+
if (role === "row") for (let index = 0; index < content.childCount; index++) {
|
|
128
|
+
let cells = content.child(index).content;
|
|
129
|
+
const left = index ? 0 : Math.max(0, openStart - 1);
|
|
130
|
+
const right = index < content.childCount - 1 ? 0 : Math.max(0, openEnd - 1);
|
|
131
|
+
if (left || right) cells = fitSlice(tableNodeTypes(schema).row, new Slice(cells, left, right)).content;
|
|
132
|
+
rows.push(cells);
|
|
133
|
+
}
|
|
134
|
+
else if (role === "cell" || role === "header_cell") rows.push(openStart || openEnd ? fitSlice(tableNodeTypes(schema).row, new Slice(content, openStart, openEnd)).content : content);
|
|
135
|
+
else return null;
|
|
136
|
+
const newCells = rows.map((row) => {
|
|
137
|
+
const cells = [];
|
|
138
|
+
row.forEach((cell) => {
|
|
139
|
+
cells.push(cell.type.create(newCellAttrs(cell.attrs), cell.content, cell.marks));
|
|
140
|
+
});
|
|
141
|
+
return Fragment.from(cells);
|
|
142
|
+
});
|
|
143
|
+
return ensureRectangular(schema, newCells);
|
|
144
|
+
};
|
|
145
|
+
const readTable = (tr, tableStart) => {
|
|
146
|
+
const table = tr.doc.nodeAt(tableStart - 1);
|
|
147
|
+
if (!table || table.type.spec["tableRole"] !== "table") throw new RangeError("The pasted-into table is gone");
|
|
148
|
+
return {
|
|
149
|
+
table,
|
|
150
|
+
map: TableMap.get(table),
|
|
151
|
+
tableStart,
|
|
152
|
+
mapFrom: tr.mapping.maps.length
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
const mapPosition = (tr, context, pos) => tr.mapping.slice(context.mapFrom).map(pos);
|
|
156
|
+
/** A new, empty cell of the same kind as `like`, with nothing that names another cell. */
|
|
157
|
+
const emptyCellLike = (like, schema) => {
|
|
158
|
+
const types = tableNodeTypes(schema);
|
|
159
|
+
const cell = (like?.type === types.header_cell ? types.header_cell : types.cell).createAndFill();
|
|
160
|
+
if (!cell) throw new RangeError("Cannot create an empty table cell");
|
|
161
|
+
return cell;
|
|
162
|
+
};
|
|
163
|
+
const isOmittedGridSlot = (cell) => cell.attrs["_omittedGridSlot"] != null;
|
|
164
|
+
const hasOmittedGridSlots = (table) => {
|
|
165
|
+
let found = false;
|
|
166
|
+
table.forEach((row) => {
|
|
167
|
+
row.forEach((cell) => {
|
|
168
|
+
found ||= isOmittedGridSlot(cell);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
return found;
|
|
172
|
+
};
|
|
173
|
+
/**
|
|
174
|
+
* The `w:vMerge` continuation cells a merged cell stored for the rows below its
|
|
175
|
+
* first, one per row, empty ones standing in for any it did not store.
|
|
176
|
+
*/
|
|
177
|
+
const continuationCells = (cell, rowspan) => {
|
|
178
|
+
const stored = cell.attrs["_docxVMergeContinuationCells"];
|
|
179
|
+
const cells = stored === void 0 || stored === null ? [] : [...decodeTableCellParagraphSourcePayload(stored).cells];
|
|
180
|
+
while (cells.length < rowspan - 1) cells.push({
|
|
181
|
+
type: "tableCell",
|
|
182
|
+
formatting: { vMerge: "continue" },
|
|
183
|
+
content: [{
|
|
184
|
+
type: "paragraph",
|
|
185
|
+
content: []
|
|
186
|
+
}]
|
|
187
|
+
});
|
|
188
|
+
return cells;
|
|
189
|
+
};
|
|
190
|
+
/** Stored continuation cells to carry, or null for none. */
|
|
191
|
+
const continuationAttr = (cells) => cells.length > 0 ? transportTableCellsWithParagraphPropertySources(cells) : null;
|
|
192
|
+
/** Add columns and rows so the table reaches `width` × `height`. */
|
|
193
|
+
const growTable = (tr, context, width, height, revision) => {
|
|
194
|
+
const { table, map, tableStart } = context;
|
|
195
|
+
const { schema } = tr.doc.type;
|
|
196
|
+
let grown = false;
|
|
197
|
+
if (width > map.width) {
|
|
198
|
+
let rowEnd = 0;
|
|
199
|
+
for (let row = 0; row < map.height; row++) {
|
|
200
|
+
const rowNode = table.child(row);
|
|
201
|
+
rowEnd += rowNode.nodeSize;
|
|
202
|
+
const cells = [];
|
|
203
|
+
for (let column = map.width; column < width; column++) {
|
|
204
|
+
const cell = emptyCellLike(rowNode.lastChild, schema);
|
|
205
|
+
cells.push(revision ? cell.type.create({
|
|
206
|
+
...cell.attrs,
|
|
207
|
+
cellMarker: {
|
|
208
|
+
kind: "ins",
|
|
209
|
+
info: { ...revision }
|
|
210
|
+
}
|
|
211
|
+
}, cell.content) : cell);
|
|
212
|
+
}
|
|
213
|
+
tr.insert(mapPosition(tr, context, rowEnd - 1 + tableStart), cells);
|
|
214
|
+
}
|
|
215
|
+
const widths = expectTableAttrs(table).columnWidths;
|
|
216
|
+
const lastWidth = widths?.at(-1);
|
|
217
|
+
tr.setNodeMarkup(mapPosition(tr, context, tableStart - 1), void 0, mergeTableAttrs(table, { columnWidths: widths?.length === map.width && lastWidth !== void 0 ? [...widths, ...Array.from({ length: width - map.width }, () => lastWidth)] : void 0 }));
|
|
218
|
+
grown = true;
|
|
219
|
+
}
|
|
220
|
+
if (height > map.height) {
|
|
221
|
+
const lastRowStart = (map.height - 1) * map.width;
|
|
222
|
+
const cells = [];
|
|
223
|
+
for (let column = 0; column < Math.max(map.width, width); column++) {
|
|
224
|
+
const above = column < map.width ? table.nodeAt(map.map[lastRowStart + column] ?? -1) : null;
|
|
225
|
+
cells.push(emptyCellLike(above ?? null, schema));
|
|
226
|
+
}
|
|
227
|
+
const rowType = tableNodeTypes(schema).row;
|
|
228
|
+
const rows = [];
|
|
229
|
+
for (let row = map.height; row < height; row++) rows.push(rowType.create(revision ? { trIns: { ...revision } } : null, cells));
|
|
230
|
+
tr.insert(mapPosition(tr, context, tableStart + table.nodeSize - 2), rows);
|
|
231
|
+
grown = true;
|
|
232
|
+
}
|
|
233
|
+
return grown;
|
|
234
|
+
};
|
|
235
|
+
/** Split every vertical merge that crosses the line above row `top`, within [left, right). */
|
|
236
|
+
const isolateHorizontal = (tr, context, left, right, top, revision) => {
|
|
237
|
+
const { table, map, tableStart } = context;
|
|
238
|
+
if (top === 0 || top === map.height) return false;
|
|
239
|
+
let found = false;
|
|
240
|
+
for (let column = left; column < right; column++) {
|
|
241
|
+
const index = top * map.width + column;
|
|
242
|
+
const pos = map.map[index];
|
|
243
|
+
if (pos === void 0 || map.map[index - map.width] !== pos) continue;
|
|
244
|
+
found = true;
|
|
245
|
+
const cell = table.nodeAt(pos);
|
|
246
|
+
if (!cell) continue;
|
|
247
|
+
const { top: cellTop, left: cellLeft } = map.findCell(pos);
|
|
248
|
+
const rowspan = spanOf(cell, "rowspan");
|
|
249
|
+
const upperRows = top - cellTop;
|
|
250
|
+
const lowerRows = rowspan - upperRows;
|
|
251
|
+
const continuations = continuationCells(cell, rowspan);
|
|
252
|
+
tr.setNodeMarkup(mapPosition(tr, context, tableStart + pos), null, {
|
|
253
|
+
...cell.attrs,
|
|
254
|
+
rowspan: upperRows,
|
|
255
|
+
_docxVMergeContinuationCells: continuationAttr(continuations.slice(0, upperRows - 1))
|
|
256
|
+
});
|
|
257
|
+
const lower = cell.type.createAndFill({
|
|
258
|
+
...newCellAttrs(cell.attrs),
|
|
259
|
+
rowspan: lowerRows,
|
|
260
|
+
_docxVMergeContinuationCells: continuationAttr(continuations.slice(upperRows)),
|
|
261
|
+
cellMarker: revision ? {
|
|
262
|
+
kind: "merge",
|
|
263
|
+
info: { ...revision },
|
|
264
|
+
verticalMergeOriginal: "continue"
|
|
265
|
+
} : null
|
|
266
|
+
});
|
|
267
|
+
if (!lower) throw new RangeError("Cannot split a merged table cell");
|
|
268
|
+
tr.insert(mapPosition(tr, context, tableStart + map.positionAt(top, cellLeft, table)), lower);
|
|
269
|
+
column += spanOf(cell, "colspan") - 1;
|
|
270
|
+
}
|
|
271
|
+
return found;
|
|
272
|
+
};
|
|
273
|
+
/** Split every horizontal merge that crosses the line left of column `left`, within [top, bottom). */
|
|
274
|
+
const isolateVertical = (tr, context, top, bottom, left) => {
|
|
275
|
+
const { table, map, tableStart } = context;
|
|
276
|
+
if (left === 0 || left === map.width) return false;
|
|
277
|
+
let found = false;
|
|
278
|
+
for (let row = top; row < bottom; row++) {
|
|
279
|
+
const index = row * map.width + left;
|
|
280
|
+
const pos = map.map[index];
|
|
281
|
+
if (pos === void 0 || map.map[index - 1] !== pos) continue;
|
|
282
|
+
found = true;
|
|
283
|
+
const cell = table.nodeAt(pos);
|
|
284
|
+
if (!cell) continue;
|
|
285
|
+
const cellLeft = map.colCount(pos);
|
|
286
|
+
const colspan = spanOf(cell, "colspan");
|
|
287
|
+
const updatePos = mapPosition(tr, context, tableStart + pos);
|
|
288
|
+
tr.setNodeMarkup(updatePos, null, withoutColumns(cell.attrs, left - cellLeft, colspan - (left - cellLeft)));
|
|
289
|
+
const right = cell.type.createAndFill(withoutColumns(newCellAttrs(cell.attrs), 0, left - cellLeft));
|
|
290
|
+
if (!right) throw new RangeError("Cannot split a merged table cell");
|
|
291
|
+
tr.insert(updatePos + cell.nodeSize, right);
|
|
292
|
+
row += spanOf(cell, "rowspan") - 1;
|
|
293
|
+
}
|
|
294
|
+
return found;
|
|
295
|
+
};
|
|
296
|
+
/**
|
|
297
|
+
* The range of a cell's content a paste replaces. A block of whole paragraphs
|
|
298
|
+
* (a pasted cell's content) replaces all of it; open content (text, or
|
|
299
|
+
* paragraphs cut from a longer run) goes from the start of the first paragraph
|
|
300
|
+
* to the end of the last, so it takes on the cell's paragraph formatting the
|
|
301
|
+
* way a paste into a paragraph does.
|
|
302
|
+
*/
|
|
303
|
+
const cellPasteRange = (cell, cellPos, slice) => {
|
|
304
|
+
const from = cellPos + 1;
|
|
305
|
+
const to = cellPos + cell.nodeSize - 1;
|
|
306
|
+
if (slice.openStart === 0 && slice.openEnd === 0 && slice.content.firstChild?.isBlock) return {
|
|
307
|
+
from,
|
|
308
|
+
to
|
|
309
|
+
};
|
|
310
|
+
return {
|
|
311
|
+
from: cell.firstChild?.isTextblock ? from + 1 : from,
|
|
312
|
+
to: cell.lastChild?.isTextblock ? to - 1 : to
|
|
313
|
+
};
|
|
314
|
+
};
|
|
315
|
+
/** Replace a cell's content outright. */
|
|
316
|
+
const replaceCellContentDirectly = (tr, cellPos, slice) => {
|
|
317
|
+
const cell = tr.doc.nodeAt(cellPos);
|
|
318
|
+
if (!cell) throw new RangeError("The pasted-into table cell is gone");
|
|
319
|
+
const { from, to } = cellPasteRange(cell, cellPos, slice);
|
|
320
|
+
tr.replace(from, to, slice);
|
|
321
|
+
};
|
|
322
|
+
/** Keep overwritten cells live until review resolves the pasted vertical merges. */
|
|
323
|
+
const verticalPasteTargets = ({ context: { map, table, tableStart }, cells, placement: { top, left } }) => {
|
|
324
|
+
const targets = [];
|
|
325
|
+
const covered = /* @__PURE__ */ new Set();
|
|
326
|
+
for (const [offset, fragment] of cells.rows.entries()) {
|
|
327
|
+
const row = top + offset;
|
|
328
|
+
let column = left;
|
|
329
|
+
for (let child = 0; child < fragment.childCount; child++) {
|
|
330
|
+
const pasted = fragment.child(child);
|
|
331
|
+
while (covered.has(row * map.width + column)) column++;
|
|
332
|
+
const right = column + spanOf(pasted, "colspan");
|
|
333
|
+
const bottom = row + spanOf(pasted, "rowspan");
|
|
334
|
+
for (let nextRow = row; nextRow < bottom;) {
|
|
335
|
+
const pos = map.map[nextRow * map.width + column];
|
|
336
|
+
const cell = pos === void 0 ? null : table.nodeAt(pos);
|
|
337
|
+
if (pos === void 0 || !cell || cell.attrs["cellMarker"] != null) return null;
|
|
338
|
+
const rect = map.findCell(pos);
|
|
339
|
+
if (rect.top !== nextRow || rect.left !== column || rect.right !== right || rect.bottom > bottom) return null;
|
|
340
|
+
const anchor = nextRow === row;
|
|
341
|
+
targets.push({
|
|
342
|
+
pos: tableStart + pos,
|
|
343
|
+
slice: anchor ? new Slice(pasted.content, 0, 0) : new Slice(Fragment.from(table.type.schema.node("paragraph")), 0, 0),
|
|
344
|
+
merge: anchor ? "anchor" : "continuation"
|
|
345
|
+
});
|
|
346
|
+
nextRow = rect.bottom;
|
|
347
|
+
}
|
|
348
|
+
for (let r = row; r < bottom; r++) for (let c = column; c < right; c++) covered.add(r * map.width + c);
|
|
349
|
+
column = right;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return targets;
|
|
353
|
+
};
|
|
354
|
+
/**
|
|
355
|
+
* The table cell each pasted cell lands on, when every one lands on a cell of
|
|
356
|
+
* its own shape; null when the block's cells are shaped differently.
|
|
357
|
+
*/
|
|
358
|
+
const matchingCells = ({ map, tableStart }, cells, top, left) => {
|
|
359
|
+
const matches = [];
|
|
360
|
+
const covered = /* @__PURE__ */ new Set();
|
|
361
|
+
for (const [offset, fragment] of cells.rows.entries()) {
|
|
362
|
+
const row = top + offset;
|
|
363
|
+
let column = left;
|
|
364
|
+
for (let child = 0; child < fragment.childCount; child++) {
|
|
365
|
+
const pasted = fragment.child(child);
|
|
366
|
+
while (covered.has(row * map.width + column)) column++;
|
|
367
|
+
const pos = map.map[row * map.width + column];
|
|
368
|
+
if (pos === void 0) return null;
|
|
369
|
+
const rect = map.findCell(pos);
|
|
370
|
+
if (rect.top !== row || rect.left !== column || rect.right - rect.left !== spanOf(pasted, "colspan") || rect.bottom - rect.top !== spanOf(pasted, "rowspan")) return null;
|
|
371
|
+
for (let r = rect.top; r < rect.bottom; r++) for (let c = rect.left; c < rect.right; c++) covered.add(r * map.width + c);
|
|
372
|
+
matches.push({
|
|
373
|
+
pos: tableStart + pos,
|
|
374
|
+
slice: new Slice(pasted.content, 0, 0)
|
|
375
|
+
});
|
|
376
|
+
column = rect.right;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return matches;
|
|
380
|
+
};
|
|
381
|
+
/** The pasted cell covering (`row`, `column`) of the block, repeating the block past its edge. */
|
|
382
|
+
const pastedCellAt = (cells, row, column) => {
|
|
383
|
+
const wantedRow = row % cells.height;
|
|
384
|
+
const wantedColumn = column % cells.width;
|
|
385
|
+
const covered = [];
|
|
386
|
+
for (const [index, fragment] of cells.rows.entries()) {
|
|
387
|
+
let at = 0;
|
|
388
|
+
for (let child = 0; child < fragment.childCount; child++) {
|
|
389
|
+
const cell = fragment.child(child);
|
|
390
|
+
while (covered[index]?.[at]) at++;
|
|
391
|
+
for (let r = index; r < index + spanOf(cell, "rowspan"); r++) for (let c = at; c < at + spanOf(cell, "colspan"); c++) (covered[r] ??= [])[c] = 1;
|
|
392
|
+
if (wantedRow >= index && wantedRow < index + spanOf(cell, "rowspan") && wantedColumn >= at && wantedColumn < at + spanOf(cell, "colspan")) return cell;
|
|
393
|
+
at += spanOf(cell, "colspan");
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return null;
|
|
397
|
+
};
|
|
398
|
+
/**
|
|
399
|
+
* Every cell of the table touching `rect`, each taking the pasted cell at its
|
|
400
|
+
* place in the block (the block repeating to cover the rectangle), or the
|
|
401
|
+
* pasted content itself when it is not cells. The table's shape is untouched.
|
|
402
|
+
*/
|
|
403
|
+
const fillTargets = ({ map, table, tableStart }, rect, cells, slice) => {
|
|
404
|
+
const targets = [];
|
|
405
|
+
for (const pos of map.cellsInRect(rect)) {
|
|
406
|
+
const cellRect = map.findCell(pos);
|
|
407
|
+
const row = Math.max(cellRect.top, rect.top) - rect.top;
|
|
408
|
+
const column = Math.max(cellRect.left, rect.left) - rect.left;
|
|
409
|
+
const pasted = cells ? pastedCellAt(cells, row, column) : null;
|
|
410
|
+
const cell = table.nodeAt(pos);
|
|
411
|
+
if (cells && !pasted || !cell || isOmittedGridSlot(cell)) continue;
|
|
412
|
+
targets.push({
|
|
413
|
+
pos: tableStart + pos,
|
|
414
|
+
slice: pasted ? new Slice(pasted.content, 0, 0) : slice
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
return targets;
|
|
418
|
+
};
|
|
419
|
+
const replaceTargets = (tr, targets, replaceCellContent) => {
|
|
420
|
+
for (const { pos, slice } of targets.toSorted((a, b) => b.pos - a.pos)) replaceCellContent(tr, pos, slice);
|
|
421
|
+
};
|
|
422
|
+
const selectBlock = (tr, tableStart, rect) => {
|
|
423
|
+
const { map, table } = readTable(tr, tableStart);
|
|
424
|
+
tr.setSelection(new CellSelection(tr.doc.resolve(tableStart + map.positionAt(rect.top, rect.left, table)), tr.doc.resolve(tableStart + map.positionAt(rect.bottom - 1, rect.right - 1, table))));
|
|
425
|
+
};
|
|
426
|
+
/**
|
|
427
|
+
* Paste a block of cells into the table at `tableStart` from (`top`, `left`):
|
|
428
|
+
* grow the table to hold it, split the merges its edges cut through, then give
|
|
429
|
+
* each cell the block covers its pasted cell. Where the block's cells have the
|
|
430
|
+
* table's shapes the table keeps its cells, with their formatting and
|
|
431
|
+
* identity, and takes the pasted content; otherwise the block's cells replace
|
|
432
|
+
* them, except in a tracked paste, which keeps the table's shape. Selects the
|
|
433
|
+
* pasted block.
|
|
434
|
+
*/
|
|
435
|
+
const insertTableCells = (tr, tableStart, { top, left }, cells, { revision, replaceCellContent = replaceCellContentDirectly } = {}) => {
|
|
436
|
+
let rect = {
|
|
437
|
+
top,
|
|
438
|
+
left,
|
|
439
|
+
right: left + cells.width,
|
|
440
|
+
bottom: top + cells.height
|
|
441
|
+
};
|
|
442
|
+
let context = readTable(tr, tableStart);
|
|
443
|
+
if (hasOmittedGridSlots(context.table)) {
|
|
444
|
+
rect = {
|
|
445
|
+
...rect,
|
|
446
|
+
right: Math.min(rect.right, context.map.width),
|
|
447
|
+
bottom: Math.min(rect.bottom, context.map.height)
|
|
448
|
+
};
|
|
449
|
+
replaceTargets(tr, fillTargets(context, rect, cells, Slice.empty), replaceCellContent);
|
|
450
|
+
selectBlock(tr, tableStart, rect);
|
|
451
|
+
return tr;
|
|
452
|
+
}
|
|
453
|
+
const recompute = (changed) => {
|
|
454
|
+
if (changed) context = readTable(tr, tableStart);
|
|
455
|
+
};
|
|
456
|
+
recompute(growTable(tr, context, rect.right, rect.bottom, revision));
|
|
457
|
+
recompute(isolateHorizontal(tr, context, rect.left, rect.right, rect.top, revision));
|
|
458
|
+
recompute(isolateHorizontal(tr, context, rect.left, rect.right, rect.bottom, revision));
|
|
459
|
+
recompute(isolateVertical(tr, context, rect.top, rect.bottom, rect.left));
|
|
460
|
+
recompute(isolateVertical(tr, context, rect.top, rect.bottom, rect.right));
|
|
461
|
+
const matches = matchingCells(context, cells, rect.top, rect.left);
|
|
462
|
+
if (matches) replaceTargets(tr, matches, replaceCellContent);
|
|
463
|
+
else if (revision) {
|
|
464
|
+
const vertical = verticalPasteTargets({
|
|
465
|
+
context,
|
|
466
|
+
cells,
|
|
467
|
+
placement: rect
|
|
468
|
+
});
|
|
469
|
+
if (vertical) for (const { pos, slice, merge } of vertical.toSorted((a, b) => b.pos - a.pos)) {
|
|
470
|
+
replaceCellContent(tr, pos, slice);
|
|
471
|
+
if (merge === "continuation") tr.setNodeAttribute(pos, "cellMarker", {
|
|
472
|
+
kind: "merge",
|
|
473
|
+
info: { ...revision },
|
|
474
|
+
verticalMerge: "continue",
|
|
475
|
+
verticalMergeOriginal: "rest"
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
else replaceTargets(tr, fillTargets(context, rect, cells, Slice.empty), replaceCellContent);
|
|
479
|
+
} else for (let row = rect.top; row < rect.bottom; row++) {
|
|
480
|
+
const from = context.map.positionAt(row, rect.left, context.table);
|
|
481
|
+
const to = context.map.positionAt(row, rect.right, context.table);
|
|
482
|
+
tr.replace(mapPosition(tr, context, from + tableStart), mapPosition(tr, context, to + tableStart), new Slice(cells.rows[row - rect.top] ?? Fragment.empty, 0, 0));
|
|
483
|
+
}
|
|
484
|
+
selectBlock(tr, tableStart, rect);
|
|
485
|
+
return tr;
|
|
486
|
+
};
|
|
487
|
+
/**
|
|
488
|
+
* Paste into every cell of a cell selection: each takes the pasted cell at its
|
|
489
|
+
* place in the block, the block repeating to cover the selection, or the
|
|
490
|
+
* pasted content itself when it holds no cells. The table keeps its shape.
|
|
491
|
+
*/
|
|
492
|
+
const fillSelectedCells = (tr, selection, slice, { replaceCellContent = replaceCellContentDirectly } = {}) => {
|
|
493
|
+
const tableStart = selection.$anchorCell.start(-1);
|
|
494
|
+
const context = readTable(tr, tableStart);
|
|
495
|
+
const rect = context.map.rectBetween(selection.$anchorCell.pos - tableStart, selection.$headCell.pos - tableStart);
|
|
496
|
+
replaceTargets(tr, fillTargets(context, rect, pastedCells(slice), slice), replaceCellContent);
|
|
497
|
+
const after = readTable(tr, tableStart);
|
|
498
|
+
tr.setSelection(new CellSelection(tr.doc.resolve(tableStart + after.map.positionAt(rect.top, rect.left, after.table)), tr.doc.resolve(tableStart + after.map.positionAt(rect.bottom - 1, rect.right - 1, after.table))));
|
|
499
|
+
return tr;
|
|
500
|
+
};
|
|
501
|
+
/**
|
|
502
|
+
* Paste `slice` into the table the selection is in: into every selected cell
|
|
503
|
+
* of a cell selection, or, when the slice holds cells, as a block of cells
|
|
504
|
+
* from the cell holding the cursor. False otherwise, so the paste falls
|
|
505
|
+
* through to the ordinary one.
|
|
506
|
+
*/
|
|
507
|
+
const pasteTableCells = (state, slice, dispatch, hooks) => {
|
|
508
|
+
const { selection } = state;
|
|
509
|
+
let run = null;
|
|
510
|
+
if (selection instanceof CellSelection) run = (tr) => fillSelectedCells(tr, selection, slice, hooks);
|
|
511
|
+
else {
|
|
512
|
+
const cells = pastedCells(slice);
|
|
513
|
+
const $cell = cells ? cellAround(selection.$head) : null;
|
|
514
|
+
if (cells && $cell) {
|
|
515
|
+
const tableStart = $cell.start(-1);
|
|
516
|
+
const rect = TableMap.get($cell.node(-1)).findCell($cell.pos - tableStart);
|
|
517
|
+
run = (tr) => insertTableCells(tr, tableStart, rect, cells, hooks);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
if (!run) return false;
|
|
521
|
+
if (dispatch) dispatch(run(state.tr).scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste"));
|
|
522
|
+
return true;
|
|
523
|
+
};
|
|
524
|
+
//#endregion
|
|
525
|
+
export { cellPasteRange, fillSelectedCells, insertTableCells, pasteTableCells, pastedCells, pastedSliceWithNewTableCells };
|