@stll/folio-core 0.10.0 → 0.12.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/dist/ai-edits/apply.js +602 -50
- package/dist/ai-edits/block-identity.d.ts +4 -0
- package/dist/ai-edits/block-identity.js +9 -0
- package/dist/ai-edits/blockRange.d.ts +28 -1
- package/dist/ai-edits/blockRange.js +67 -1
- package/dist/ai-edits/headless.d.ts +4 -4
- package/dist/ai-edits/headless.js +9 -9
- package/dist/ai-edits/index.d.ts +2 -2
- package/dist/ai-edits/index.js +2 -2
- package/dist/ai-edits/read.d.ts +7 -7
- package/dist/ai-edits/read.js +110 -3
- package/dist/ai-edits/table-cell-mutations.d.ts +48 -0
- package/dist/ai-edits/table-cell-mutations.js +237 -0
- package/dist/ai-edits/table-mutation-plan.d.ts +38 -0
- package/dist/ai-edits/table-mutation-plan.js +90 -0
- package/dist/ai-edits/table-row-column-mutations.d.ts +100 -0
- package/dist/ai-edits/table-row-column-mutations.js +300 -0
- package/dist/ai-edits/table-targets.d.ts +32 -0
- package/dist/ai-edits/table-targets.js +70 -0
- package/dist/ai-edits/types.d.ts +34 -0
- package/dist/compat/eigenpal.js +1 -1
- package/dist/content-controls/mutateContentControls.js +1 -1
- package/dist/controller/activeEditorStory.d.ts +36 -0
- package/dist/controller/activeEditorStory.js +30 -0
- package/dist/controller/collaborationModules.d.ts +7 -0
- package/dist/controller/collaborationModules.js +15 -0
- package/dist/controller/contentControlWidgetController.d.ts +55 -0
- package/dist/controller/contentControlWidgetController.js +141 -0
- package/dist/controller/folioEditor.d.ts +1 -1
- package/dist/controller/fontReadiness.js +2 -0
- package/dist/controller/headerFooterEditorManager.d.ts +41 -0
- package/dist/controller/headerFooterEditorManager.js +182 -0
- package/dist/controller/hiddenEditorApi.js +2 -2
- package/dist/controller/hiddenEditorManager.d.ts +13 -2
- package/dist/controller/hiddenEditorManager.js +32 -11
- package/dist/controller/layoutPipeline.d.ts +2 -0
- package/dist/controller/layoutPipeline.js +16 -1
- package/dist/controller/noteEditorManager.d.ts +36 -0
- package/dist/controller/noteEditorManager.js +210 -0
- package/dist/document-operations.d.ts +35 -3
- package/dist/document-operations.js +161 -3
- package/dist/docx/blockContentParser.js +2 -2
- package/dist/docx/commentParser.js +6 -1
- package/dist/docx/conformance.js +8 -1
- package/dist/docx/documentGrid.d.ts +8 -0
- package/dist/docx/documentGrid.js +8 -0
- package/dist/docx/drawingUtils.js +1 -1
- package/dist/docx/ensureParaIds.js +1 -1
- package/dist/docx/fieldParser.js +1 -1
- package/dist/docx/notePropertiesParser.js +1 -1
- package/dist/docx/numberingParser.js +1 -1
- package/dist/docx/paragraphParser.js +63 -58
- package/dist/docx/paragraphTextBoxEnrichment.d.ts +2 -1
- package/dist/docx/paragraphTextBoxEnrichment.js +67 -13
- package/dist/docx/paragraphTraversal.js +1 -1
- package/dist/docx/parser.js +3 -3
- package/dist/docx/rezip.js +1 -1
- package/dist/docx/runParser.js +4 -2
- package/dist/docx/sdtProperties.js +1 -1
- package/dist/docx/sectionParser.js +1 -1
- package/dist/docx/selectiveSave.js +1 -1
- package/dist/docx/serializer/commentSerializer.js +1 -2
- package/dist/docx/serializer/documentSerializer.js +2 -2
- package/dist/docx/serializer/headerFooterSerializer.js +2 -2
- package/dist/docx/serializer/noteSerializer.js +2 -2
- package/dist/docx/serializer/paragraphSerializer.js +7 -1
- package/dist/docx/serializer/runSerializer.js +4 -2
- package/dist/docx/serializer/stylesSerializer.js +1 -1
- package/dist/docx/serializer/tableSerializer.d.ts +5 -4
- package/dist/docx/serializer/tableSerializer.js +17 -13
- package/dist/docx/server/applyDocxXmlPatchProposal.d.ts +87 -0
- package/dist/docx/server/applyDocxXmlPatchProposal.js +204 -0
- package/dist/docx/server/boundedArchive.d.ts +14 -3
- package/dist/docx/server/boundedArchive.js +56 -11
- package/dist/docx/server/evaluateDocxXmlPatchProposal.d.ts +85 -0
- package/dist/docx/server/evaluateDocxXmlPatchProposal.js +361 -0
- package/dist/docx/server/inspectDocxPackage.d.ts +70 -0
- package/dist/docx/server/inspectDocxPackage.js +217 -0
- package/dist/docx/server/validateDocxConformance.d.ts +41 -0
- package/dist/docx/server/validateDocxConformance.js +336 -0
- package/dist/docx/settingsParser.js +11 -1
- package/dist/docx/shapeParser.js +1 -1
- package/dist/docx/styleParser.js +4 -2
- package/dist/docx/tableParser.js +18 -7
- package/dist/docx/textBoxParser.d.ts +3 -3
- package/dist/docx/textBoxParser.js +16 -12
- package/dist/docx/xmlSafety.d.ts +5 -0
- package/dist/docx/xmlSafety.js +9 -0
- package/dist/fields/resolveFieldValues.js +1 -3
- package/dist/i18n/messages/catalogs.gen.d.ts +17 -0
- package/dist/i18n/messages/catalogs.gen.js +17 -0
- package/dist/i18n/messages/messages.gen.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/footnoteLayout.js +47 -40
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +1 -0
- package/dist/layout-bridge/convert/headerFooterLayout.js +3 -0
- package/dist/layout-bridge/convert/templatePreviewFlow.js +3 -3
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +4 -2
- package/dist/layout-bridge/convert/toFlowBlocks.js +136 -20
- package/dist/layout-bridge/dom/noteStoryDom.d.ts +6 -0
- package/dist/layout-bridge/dom/noteStoryDom.js +17 -0
- package/dist/layout-bridge/engine/clickToPosition.js +2 -2
- package/dist/layout-engine/index.d.ts +2 -2
- package/dist/layout-engine/index.js +43 -28
- package/dist/layout-engine/justificationCompatibility.d.ts +6 -0
- package/dist/layout-engine/justificationCompatibility.js +8 -0
- package/dist/layout-engine/keep-together.js +11 -1
- package/dist/layout-engine/measure/cache.js +21 -5
- package/dist/layout-engine/measure/lineBreakProvider.js +53 -34
- package/dist/layout-engine/measure/measureBlocks.js +6 -3
- package/dist/layout-engine/measure/measureContainer.js +1 -1
- package/dist/layout-engine/measure/measureHelpers.d.ts +1 -1
- package/dist/layout-engine/measure/measureHelpers.js +3 -3
- package/dist/layout-engine/measure/measureParagraph.js +69 -25
- package/dist/layout-engine/measure/measureProvider.js +4 -3
- package/dist/layout-engine/measure/tableCellFlow.js +5 -2
- package/dist/layout-engine/measure/textBoxParagraphLayout.d.ts +9 -7
- package/dist/layout-engine/measure/textBoxParagraphLayout.js +22 -6
- package/dist/layout-engine/measure/textMeasurementPolicy.d.ts +3 -1
- package/dist/layout-engine/measure/textMeasurementPolicy.js +7 -1
- package/dist/layout-engine/paginator.js +5 -1
- package/dist/layout-engine/paragraphSpacing.d.ts +28 -4
- package/dist/layout-engine/paragraphSpacing.js +107 -13
- package/dist/layout-engine/renderedBreakReconciliation.js +1 -1
- package/dist/layout-engine/types.d.ts +26 -13
- package/dist/layout-painter/registry/modules/textBox.js +5 -1
- package/dist/layout-painter/renderPage.d.ts +5 -2
- package/dist/layout-painter/renderPage.js +56 -12
- package/dist/layout-painter/renderParagraph.js +22 -6
- package/dist/layout-painter/renderTable.d.ts +5 -1
- package/dist/layout-painter/renderTable.js +5 -2
- package/dist/layout-painter/renderTextBox.d.ts +2 -1
- package/dist/layout-painter/renderTextBox.js +25 -14
- package/dist/managers/DocumentLoaderManager.js +1 -1
- package/dist/managers/FindReplaceManager.d.ts +8 -0
- package/dist/managers/FindReplaceManager.js +18 -0
- package/dist/managers/TableSelectionManager.d.ts +6 -0
- package/dist/managers/TableSelectionManager.js +14 -0
- package/dist/model.js +1 -1
- package/dist/prosemirror/attrs/index.d.ts +4 -2
- package/dist/prosemirror/attrs/index.js +154 -18
- package/dist/prosemirror/commands/comments.d.ts +3 -3
- package/dist/prosemirror/commands/comments.js +248 -12
- package/dist/prosemirror/commands/contentControls.js +1 -1
- package/dist/prosemirror/commands/index.js +1 -1
- package/dist/prosemirror/commands/pageBreak.js +1 -1
- package/dist/prosemirror/commands/propertyChangeScope.d.ts +2 -2
- package/dist/prosemirror/commands/propertyChangeScope.js +3 -2
- package/dist/prosemirror/commands/tableCellMergeResolution.d.ts +9 -0
- package/dist/prosemirror/commands/tableCellMergeResolution.js +181 -0
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +2 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +286 -61
- package/dist/prosemirror/conversion/sdtAttrs.d.ts +9 -0
- package/dist/prosemirror/conversion/sdtAttrs.js +49 -0
- package/dist/prosemirror/conversion/toProseDoc.d.ts +2 -1
- package/dist/prosemirror/conversion/toProseDoc.js +347 -98
- package/dist/prosemirror/extensions/ExtensionManager.js +1 -1
- package/dist/prosemirror/extensions/StarterKit.js +6 -1
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +4 -1
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +1 -0
- package/dist/prosemirror/extensions/features/ListExtension.js +1 -1
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +10 -1
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +93 -2
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.d.ts +2 -1
- package/dist/prosemirror/extensions/features/ParagraphChangeTrackerExtension.js +6 -2
- package/dist/prosemirror/extensions/marks/CharacterSpacingExtension.js +1 -1
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.d.ts +9 -1
- package/dist/prosemirror/extensions/marks/TrackedChangeExtensions.js +24 -1
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +1 -1
- package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.d.ts +7 -0
- package/dist/prosemirror/extensions/nodes/RenderedPageBreakExtension.js +22 -0
- package/dist/prosemirror/extensions/nodes/TableExtension.js +9 -3
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.d.ts +13 -0
- package/dist/prosemirror/extensions/nodes/TextBoxAnchorExtension.js +41 -0
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +5 -2
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +4 -1
- package/dist/prosemirror/findReplaceSelection.d.ts +6 -1
- package/dist/prosemirror/findReplaceSelection.js +57 -13
- package/dist/prosemirror/plugins/contentControlWidgets.d.ts +34 -8
- package/dist/prosemirror/plugins/contentControlWidgets.js +125 -91
- package/dist/prosemirror/plugins/selectionTracker.js +1 -0
- package/dist/prosemirror/plugins/suggestionMode.js +1 -1
- package/dist/prosemirror/schema/index.d.ts +2 -2
- package/dist/prosemirror/schema/marks.d.ts +5 -1
- package/dist/prosemirror/schema/nodes.d.ts +64 -7
- package/dist/prosemirror/selectionState.js +1 -0
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
- package/dist/prosemirror/tableCellMergeRevision.d.ts +9 -0
- package/dist/prosemirror/tableCellMergeRevision.js +22 -0
- package/dist/prosemirror/textBoxAnchorAttrs.d.ts +9 -0
- package/dist/prosemirror/textBoxAnchorAttrs.js +33 -0
- package/dist/prosemirror/utils/extractTrackedChanges.d.ts +1 -1
- package/dist/prosemirror/utils/extractTrackedChanges.js +62 -14
- package/dist/prosemirror/validation.js +9 -1
- package/dist/render-dom/BodySelectionOverlay.d.ts +31 -0
- package/dist/render-dom/BodySelectionOverlay.js +76 -0
- package/dist/render-dom/HeaderFooterSelectionOverlay.d.ts +28 -0
- package/dist/render-dom/HeaderFooterSelectionOverlay.js +121 -0
- package/dist/render-dom/RemoteSelectionOverlay.d.ts +30 -0
- package/dist/render-dom/RemoteSelectionOverlay.js +67 -0
- package/dist/render-dom/RenderedDomContext.d.ts +40 -0
- package/dist/render-dom/RenderedDomContext.js +126 -0
- package/dist/render-dom/resolveSidebarItemPositions.d.ts +33 -0
- package/dist/render-dom/resolveSidebarItemPositions.js +45 -0
- package/dist/server.d.ts +6 -2
- package/dist/server.js +5 -1
- package/dist/utils/findReplace.d.ts +32 -0
- package/dist/utils/findReplace.js +118 -0
- package/dist/utils/fontFamilyMerge.js +9 -11
- package/dist/utils/fontLoader.js +3 -2
- package/dist/utils/fontResolver.js +22 -4
- package/dist/utils/fontWeights.d.ts +1 -1
- package/dist/utils/fontWeights.js +1 -1
- package/dist/utils/headerFooter.js +24 -1
- package/dist/utils/paragraphFormattingMerge.js +1 -0
- package/package.json +1 -1
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { NUMBER_FORMAT_VALUES } from "../../types/documentEnumValues.js";
|
|
2
|
-
import { AUTO_PARAGRAPH_SPACING_PX, halfPointsToPixels, halfPointsToPoints, pointsToPixels } from "../../utils/units.js";
|
|
3
|
-
import { convertBulletToUnicode } from "../../docx/bulletMarkers.js";
|
|
4
|
-
import { padDecimal } from "../../docx/numberingParser.js";
|
|
5
|
-
import { autospacingMatchesBase } from "../../prosemirror/autospacingBase.js";
|
|
6
2
|
import { directionIsRtl } from "../../prosemirror/paragraphDirection.js";
|
|
7
3
|
import { expectBlockSdtAttrs, expectCharacterSpacingMarkAttrs, expectCommentMarkAttrs, expectEmphasisMarkAttrs, expectFieldAttrs, expectFontFamilyMarkAttrs, expectFontSizeMarkAttrs, expectFootnoteRefMarkAttrs, expectHardBreakAttrs, expectHighlightMarkAttrs, expectHyperlinkMarkAttrs, expectImageAttrs, expectLanguageMarkAttrs, expectMathAttrs, expectParagraphAttrs, expectRunFormattingOverrideMarkAttrs, expectRunShadingMarkAttrs, expectTableAttrs, expectTableCellAttrs, expectTableRowAttrs, expectTextBoxAttrs, expectTextColorMarkAttrs, expectTextEffectMarkAttrs, expectTrackedChangeMarkAttrs, expectUnderlineMarkAttrs } from "../../prosemirror/attrs/index.js";
|
|
4
|
+
import { padDecimal } from "../../docx/numberingParser.js";
|
|
5
|
+
import { AUTO_PARAGRAPH_SPACING_PX, halfPointsToPixels, halfPointsToPoints, pointsToPixels } from "../../utils/units.js";
|
|
6
|
+
import { autospacingMatchesBase } from "../../prosemirror/autospacingBase.js";
|
|
8
7
|
import { assertValidProseMirrorDocument } from "../../prosemirror/validation.js";
|
|
9
8
|
import { runShadingAttrsToShading } from "../../prosemirror/conversion/runShadingMark.js";
|
|
10
9
|
import { resolveColor, resolveHighlightToCss } from "../../utils/colorResolver.js";
|
|
10
|
+
import { resolveThemeFont } from "../../utils/fontResolver.js";
|
|
11
11
|
import { resolveShadingFill } from "../../utils/formatToStyle.js";
|
|
12
|
+
import { convertBulletToUnicode } from "../../docx/bulletMarkers.js";
|
|
12
13
|
import { DEFAULT_TEXTBOX_MARGINS } from "../../layout-engine/types.js";
|
|
14
|
+
import { resolveDocumentGridLinePitch } from "../../docx/documentGrid.js";
|
|
13
15
|
import { setTextBoxGroupId } from "../../layout-engine/textBoxGroup.js";
|
|
14
16
|
import { setParagraphFrame } from "../../layout-engine/paragraphFrame.js";
|
|
15
17
|
import { getColumns } from "../sectionColumns.js";
|
|
@@ -239,9 +241,10 @@ function extractRunFormatting(marks, theme) {
|
|
|
239
241
|
break;
|
|
240
242
|
case "fontFamily": {
|
|
241
243
|
const attrs = expectFontFamilyMarkAttrs(mark);
|
|
242
|
-
const font = attrs
|
|
244
|
+
const font = resolveWesternThemeFont(attrs, theme);
|
|
243
245
|
if (font) formatting.fontFamily = font;
|
|
244
|
-
|
|
246
|
+
const eastAsiaFont = resolveEastAsiaThemeFont(attrs, theme);
|
|
247
|
+
if (eastAsiaFont) formatting.eastAsiaFontFamily = eastAsiaFont;
|
|
245
248
|
break;
|
|
246
249
|
}
|
|
247
250
|
case "language": {
|
|
@@ -345,6 +348,13 @@ function extractRunFormatting(marks, theme) {
|
|
|
345
348
|
if (hasNoteRef && formatting.subscript) delete formatting.superscript;
|
|
346
349
|
return formatting;
|
|
347
350
|
}
|
|
351
|
+
const resolveWesternThemeFont = (fontFamily, theme) => {
|
|
352
|
+
const themeRef = fontFamily.asciiTheme ?? fontFamily.hAnsiTheme;
|
|
353
|
+
return (themeRef ? resolveThemeFont(themeRef, theme?.fontScheme) : null) ?? fontFamily.ascii ?? fontFamily.hAnsi ?? void 0;
|
|
354
|
+
};
|
|
355
|
+
const resolveEastAsiaThemeFont = (fontFamily, theme) => {
|
|
356
|
+
return (fontFamily.eastAsiaTheme ? resolveThemeFont(fontFamily.eastAsiaTheme, theme?.fontScheme) : null) ?? fontFamily.eastAsia ?? void 0;
|
|
357
|
+
};
|
|
348
358
|
function isAutomaticTextColorValue(color) {
|
|
349
359
|
const rgb = color.rgb?.trim().toLowerCase();
|
|
350
360
|
return color.auto === true || rgb === "auto" || !rgb && !color.themeColor;
|
|
@@ -381,9 +391,10 @@ function paragraphRunDefaults(pmAttrs, theme) {
|
|
|
381
391
|
const defaultTextFormatting = pmAttrs.defaultTextFormatting;
|
|
382
392
|
if (!defaultTextFormatting) return {};
|
|
383
393
|
const result = {};
|
|
384
|
-
const fontFamily = defaultTextFormatting.fontFamily
|
|
394
|
+
const fontFamily = defaultTextFormatting.fontFamily ? resolveWesternThemeFont(defaultTextFormatting.fontFamily, theme) : void 0;
|
|
385
395
|
if (fontFamily) result.fontFamily = fontFamily;
|
|
386
|
-
|
|
396
|
+
const eastAsiaFontFamily = defaultTextFormatting.fontFamily ? resolveEastAsiaThemeFont(defaultTextFormatting.fontFamily, theme) : void 0;
|
|
397
|
+
if (eastAsiaFontFamily) result.eastAsiaFontFamily = eastAsiaFontFamily;
|
|
387
398
|
if (defaultTextFormatting.language) result.language = { ...defaultTextFormatting.language };
|
|
388
399
|
if (defaultTextFormatting.fontSize !== void 0) result.fontSize = defaultTextFormatting.fontSize / 2;
|
|
389
400
|
if (defaultTextFormatting.bold !== void 0) result.bold = defaultTextFormatting.bold;
|
|
@@ -488,7 +499,21 @@ function paragraphToRuns(node, startPos, _options) {
|
|
|
488
499
|
const paraDefaults = paragraphRunDefaults(pmAttrs, theme);
|
|
489
500
|
const paragraphStyleId = pmAttrs.styleId;
|
|
490
501
|
const inTocParagraph = typeof paragraphStyleId === "string" && TOC_STYLE_ID.test(paragraphStyleId);
|
|
502
|
+
let leadingRenderedPageBreakPending = pmAttrs.renderedPageBreakBefore === true;
|
|
491
503
|
function pushRunsForChild(child, childPos) {
|
|
504
|
+
if (child.type.name === "renderedPageBreak") {
|
|
505
|
+
if (leadingRenderedPageBreakPending) {
|
|
506
|
+
leadingRenderedPageBreakPending = false;
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
runs.push({
|
|
510
|
+
kind: "renderedPageBreak",
|
|
511
|
+
pmStart: childPos,
|
|
512
|
+
pmEnd: childPos + child.nodeSize
|
|
513
|
+
});
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
if (child.type.name !== "sdt") leadingRenderedPageBreakPending = false;
|
|
492
517
|
if (child.isText && child.text) {
|
|
493
518
|
const formatting = extractRunFormatting(child.marks, theme);
|
|
494
519
|
if (inTocParagraph) stripTocHyperlinkStyle(formatting);
|
|
@@ -700,6 +725,7 @@ function convertParagraphAttrs(pmAttrs, theme, listCounters, listAbstractCounter
|
|
|
700
725
|
const spaceBefore = pmAttrs.spaceBefore;
|
|
701
726
|
const spaceAfter = pmAttrs.spaceAfter;
|
|
702
727
|
const lineSpacing = pmAttrs.lineSpacing;
|
|
728
|
+
if (typeof pmAttrs.snapToGrid === "boolean") attrs.snapToGrid = pmAttrs.snapToGrid;
|
|
703
729
|
const autoBefore = autospacingMatchesBase(pmAttrs._autospacingBase, "before", spaceBefore);
|
|
704
730
|
const autoAfter = autospacingMatchesBase(pmAttrs._autospacingBase, "after", spaceAfter);
|
|
705
731
|
if (autoBefore || autoAfter || typeof spaceBefore === "number" || typeof spaceAfter === "number" || typeof lineSpacing === "number") {
|
|
@@ -714,9 +740,10 @@ function convertParagraphAttrs(pmAttrs, theme, listCounters, listAbstractCounter
|
|
|
714
740
|
};
|
|
715
741
|
const pmSpacingExplicit = pmAttrs.spacingExplicit;
|
|
716
742
|
const spacingFromDocDefaults = pmAttrs.spacingFromDocDefaults;
|
|
743
|
+
const spacingFromImplicitDefaultStyle = pmAttrs.spacingFromImplicitDefaultStyle;
|
|
717
744
|
const explicit = {};
|
|
718
|
-
if (autoBefore || pmSpacingExplicit?.before || spacingFromDocDefaults?.before) explicit.before = true;
|
|
719
|
-
if (autoAfter || pmSpacingExplicit?.after || spacingFromDocDefaults?.after) explicit.after = true;
|
|
745
|
+
if (autoBefore || pmSpacingExplicit?.before || spacingFromDocDefaults?.before || spacingFromImplicitDefaultStyle?.before) explicit.before = true;
|
|
746
|
+
if (autoAfter || pmSpacingExplicit?.after || spacingFromDocDefaults?.after || spacingFromImplicitDefaultStyle?.after) explicit.after = true;
|
|
720
747
|
if (explicit.before !== void 0 || explicit.after !== void 0) attrs.spacingExplicit = explicit;
|
|
721
748
|
if (typeof lineSpacing === "number") if (pmAttrs.lineSpacingRule === "exact" || pmAttrs.lineSpacingRule === "atLeast") {
|
|
722
749
|
attrs.spacing.line = twipsToPixels(lineSpacing);
|
|
@@ -832,7 +859,7 @@ function convertParagraphAttrs(pmAttrs, theme, listCounters, listAbstractCounter
|
|
|
832
859
|
if (dtf) {
|
|
833
860
|
if (dtf.fontSize !== void 0) attrs.defaultFontSize = dtf.fontSize / 2;
|
|
834
861
|
if (dtf.fontFamily) {
|
|
835
|
-
const resolvedFamily = dtf.fontFamily
|
|
862
|
+
const resolvedFamily = resolveWesternThemeFont(dtf.fontFamily, theme);
|
|
836
863
|
if (resolvedFamily) attrs.defaultFontFamily = resolvedFamily;
|
|
837
864
|
}
|
|
838
865
|
}
|
|
@@ -856,19 +883,23 @@ function mapTabAlignment(align) {
|
|
|
856
883
|
/**
|
|
857
884
|
* Convert a paragraph node to a ParagraphBlock.
|
|
858
885
|
*/
|
|
886
|
+
function hasOnlyVisuallyEmptyTextRuns(runs) {
|
|
887
|
+
return runs.length > 0 && runs.every((run) => run.kind === "text" && run.text.replace(/\u00a0/gu, " ").trim().length === 0);
|
|
888
|
+
}
|
|
859
889
|
function convertParagraph(node, startPos, options) {
|
|
860
890
|
const pmAttrs = expectParagraphAttrs(node);
|
|
861
891
|
const runs = paragraphToRuns(node, startPos, options);
|
|
862
892
|
const attrs = convertParagraphAttrs(pmAttrs, options.theme, options.listCounters, options.listAbstractCounters, options.listSeenNumIds, options.defaultTabStopTwips, options.originalListCounters, options.originalListAbstractCounters, options.originalListSeenNumIds);
|
|
863
893
|
if (options.lineBreakRules) attrs.lineBreakRules = options.lineBreakRules;
|
|
894
|
+
if (options.justificationCompatibility) attrs.justificationCompatibility = options.justificationCompatibility;
|
|
864
895
|
if (options.automaticHyphenation) attrs.automaticHyphenation = options.automaticHyphenation;
|
|
865
896
|
const defaultTextFormatting = pmAttrs.defaultTextFormatting;
|
|
866
|
-
if (runs.length === 0) {
|
|
897
|
+
if (runs.length === 0 || hasOnlyVisuallyEmptyTextRuns(runs)) {
|
|
867
898
|
if (pmAttrs._originalFormatting && Object.entries(pmAttrs._originalFormatting).some(([key, value]) => key !== "runProperties" && value !== void 0 && value !== null)) attrs.hasDirectParagraphFormatting = true;
|
|
868
899
|
const paragraphMarkFormatting = pmAttrs._originalFormatting?.runProperties;
|
|
869
900
|
if (paragraphMarkFormatting && Object.values(paragraphMarkFormatting).some((value) => value !== void 0 && value !== null)) attrs.hasDirectParagraphMarkFormatting = true;
|
|
870
901
|
if (paragraphMarkFormatting?.fontSize !== void 0) attrs.defaultFontSize = paragraphMarkFormatting.fontSize / 2;
|
|
871
|
-
const paragraphMarkFontFamily = paragraphMarkFormatting?.fontFamily
|
|
902
|
+
const paragraphMarkFontFamily = paragraphMarkFormatting?.fontFamily ? resolveWesternThemeFont(paragraphMarkFormatting.fontFamily, options.theme) : void 0;
|
|
872
903
|
if (paragraphMarkFontFamily) attrs.defaultFontFamily = paragraphMarkFontFamily;
|
|
873
904
|
}
|
|
874
905
|
if (runs.length === 0 && defaultTextFormatting?.hidden === true) {
|
|
@@ -1037,12 +1068,13 @@ function convertTableCell(node, startPos, options, tableCellMargins) {
|
|
|
1037
1068
|
suppressEmptyParagraphHeight: true
|
|
1038
1069
|
};
|
|
1039
1070
|
const attrs = expectTableCellAttrs(node);
|
|
1071
|
+
if (attrs.hideMark && trailingBlock?.kind === "paragraph" && trailingBlock.runs.every((run) => run.kind === "text" && run.text.length === 0)) trailingBlock.attrs = {
|
|
1072
|
+
...trailingBlock.attrs,
|
|
1073
|
+
suppressEmptyParagraphHeight: true
|
|
1074
|
+
};
|
|
1040
1075
|
const margins = attrs.margins;
|
|
1041
1076
|
const resolvePaddingSide = (side, cellTwips, tableTwips) => {
|
|
1042
|
-
if (cellTwips !== void 0)
|
|
1043
|
-
const px = twipsToPixels(cellTwips);
|
|
1044
|
-
if (px > 0) return px;
|
|
1045
|
-
}
|
|
1077
|
+
if (cellTwips !== void 0) return twipsToPixels(cellTwips);
|
|
1046
1078
|
if (tableTwips !== void 0) return twipsToPixels(tableTwips);
|
|
1047
1079
|
return twipsToPixels(DEFAULT_TABLE_CELL_MARGIN_TWIPS[side]);
|
|
1048
1080
|
};
|
|
@@ -1191,10 +1223,12 @@ function convertTextBoxNode(node, startPos, opts) {
|
|
|
1191
1223
|
const attrs = expectTextBoxAttrs(node);
|
|
1192
1224
|
const contentBlocks = [];
|
|
1193
1225
|
node.forEach((child, offset) => {
|
|
1226
|
+
const childPos = startPos + 1 + offset;
|
|
1194
1227
|
if (child.type.name === "paragraph") {
|
|
1195
|
-
|
|
1196
|
-
|
|
1228
|
+
contentBlocks.push(convertParagraph(child, childPos, opts));
|
|
1229
|
+
return;
|
|
1197
1230
|
}
|
|
1231
|
+
if (child.type.name === "table") contentBlocks.push(convertTable(child, childPos, opts));
|
|
1198
1232
|
});
|
|
1199
1233
|
const textBox = {
|
|
1200
1234
|
kind: "textBox",
|
|
@@ -1271,6 +1305,23 @@ function toFlowBlocks(doc, options = {}) {
|
|
|
1271
1305
|
tagBlockWithSdtStack(block);
|
|
1272
1306
|
blocks.push(block);
|
|
1273
1307
|
};
|
|
1308
|
+
const trailingPageBreakSectionPositions = /* @__PURE__ */ new Set();
|
|
1309
|
+
const consumedPageBreakPositions = /* @__PURE__ */ new Set();
|
|
1310
|
+
const collectTrailingPageBreakSections = (parent, contentStart) => {
|
|
1311
|
+
let childStart = contentStart;
|
|
1312
|
+
for (let index = 0; index < parent.childCount; index += 1) {
|
|
1313
|
+
const child = parent.child(index);
|
|
1314
|
+
const next = index + 1 < parent.childCount ? parent.child(index + 1) : void 0;
|
|
1315
|
+
const paragraphAttrs = child.type.name === "paragraph" ? expectParagraphAttrs(child) : void 0;
|
|
1316
|
+
if (paragraphAttrs && next?.type.name === "pageBreak" && paragraphAttrs._trailingPageBreak === true && (paragraphAttrs._sectionProperties || paragraphAttrs.sectionBreakType)) {
|
|
1317
|
+
trailingPageBreakSectionPositions.add(childStart);
|
|
1318
|
+
consumedPageBreakPositions.add(childStart + child.nodeSize);
|
|
1319
|
+
}
|
|
1320
|
+
if (child.type.name === "blockSdt") collectTrailingPageBreakSections(child, childStart + 1);
|
|
1321
|
+
childStart += child.nodeSize;
|
|
1322
|
+
}
|
|
1323
|
+
};
|
|
1324
|
+
collectTrailingPageBreakSections(doc, offset);
|
|
1274
1325
|
const visit = (node, pos) => {
|
|
1275
1326
|
switch (node.type.name) {
|
|
1276
1327
|
case "blockSdt": {
|
|
@@ -1356,6 +1407,41 @@ function toFlowBlocks(doc, options = {}) {
|
|
|
1356
1407
|
trackedPush(paragraph);
|
|
1357
1408
|
} else if (node.content.size > 0 || hasListFormatting || !hasSectionBreak) trackedPush(convertParagraph(node, pos, opts));
|
|
1358
1409
|
if (hasSectionBreak) {
|
|
1410
|
+
if (trailingPageBreakSectionPositions.has(pos)) {
|
|
1411
|
+
const sourceParagraph = blocks.at(-1);
|
|
1412
|
+
if (sourceParagraph?.kind === "paragraph" && sourceParagraph.pmStart === pos) {
|
|
1413
|
+
const pageBreak = {
|
|
1414
|
+
kind: "pageBreak",
|
|
1415
|
+
id: nextBlockId(),
|
|
1416
|
+
pmStart: pos + node.nodeSize,
|
|
1417
|
+
pmEnd: pos + node.nodeSize + 1
|
|
1418
|
+
};
|
|
1419
|
+
trackedPush(pageBreak);
|
|
1420
|
+
const sourceAttrs = sourceParagraph.attrs;
|
|
1421
|
+
const carrierSpacing = sourceAttrs?.spacing ? { ...sourceAttrs.spacing } : void 0;
|
|
1422
|
+
if (carrierSpacing) delete carrierSpacing.before;
|
|
1423
|
+
const carrierAttrs = {
|
|
1424
|
+
...carrierSpacing ? { spacing: carrierSpacing } : {},
|
|
1425
|
+
...sourceAttrs?.automaticSpacing?.after === true ? { automaticSpacing: { after: true } } : {},
|
|
1426
|
+
...sourceAttrs?.spacingExplicit?.after === true ? { spacingExplicit: { after: true } } : {},
|
|
1427
|
+
...sourceAttrs?.hasDirectParagraphFormatting === true ? { hasDirectParagraphFormatting: true } : {},
|
|
1428
|
+
...sourceAttrs?.hasDirectParagraphMarkFormatting === true ? { hasDirectParagraphMarkFormatting: true } : {},
|
|
1429
|
+
...sourceAttrs?.snapToGrid !== void 0 ? { snapToGrid: sourceAttrs.snapToGrid } : {},
|
|
1430
|
+
...sourceAttrs?.documentGridLinePitch !== void 0 ? { documentGridLinePitch: sourceAttrs.documentGridLinePitch } : {},
|
|
1431
|
+
...sourceAttrs?.defaultFontSize !== void 0 ? { defaultFontSize: sourceAttrs.defaultFontSize } : {},
|
|
1432
|
+
...sourceAttrs?.defaultFontFamily !== void 0 ? { defaultFontFamily: sourceAttrs.defaultFontFamily } : {}
|
|
1433
|
+
};
|
|
1434
|
+
const carrier = {
|
|
1435
|
+
kind: "paragraph",
|
|
1436
|
+
id: nextBlockId(),
|
|
1437
|
+
runs: [],
|
|
1438
|
+
attrs: carrierAttrs,
|
|
1439
|
+
pmStart: pos + node.nodeSize,
|
|
1440
|
+
pmEnd: pos + node.nodeSize
|
|
1441
|
+
};
|
|
1442
|
+
trackedPush(carrier);
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1359
1445
|
const sectionBreak = {
|
|
1360
1446
|
kind: "sectionBreak",
|
|
1361
1447
|
id: nextBlockId()
|
|
@@ -1363,6 +1449,8 @@ function toFlowBlocks(doc, options = {}) {
|
|
|
1363
1449
|
const breakType = secProps?.sectionStart ?? pmAttrs.sectionBreakType;
|
|
1364
1450
|
if (breakType) sectionBreak.type = breakType;
|
|
1365
1451
|
if (secProps) {
|
|
1452
|
+
const documentGridLinePitchTwips = resolveDocumentGridLinePitch(secProps.docGrid);
|
|
1453
|
+
if (documentGridLinePitchTwips !== void 0) sectionBreak.documentGridLinePitchTwips = documentGridLinePitchTwips;
|
|
1366
1454
|
if (secProps.pageWidth || secProps.pageHeight) sectionBreak.pageSize = {
|
|
1367
1455
|
w: twipsToPixels(secProps.pageWidth ?? 12240),
|
|
1368
1456
|
h: twipsToPixels(secProps.pageHeight ?? 15840)
|
|
@@ -1401,6 +1489,7 @@ function toFlowBlocks(doc, options = {}) {
|
|
|
1401
1489
|
break;
|
|
1402
1490
|
case "horizontalRule":
|
|
1403
1491
|
case "pageBreak": {
|
|
1492
|
+
if (consumedPageBreakPositions.has(pos)) break;
|
|
1404
1493
|
const pb = {
|
|
1405
1494
|
kind: "pageBreak",
|
|
1406
1495
|
id: nextBlockId(),
|
|
@@ -1419,7 +1508,34 @@ function toFlowBlocks(doc, options = {}) {
|
|
|
1419
1508
|
reserveLeadingEmptyOutlineHeight(blocks);
|
|
1420
1509
|
suppressTerminalEmptyParagraphsAfterTable(blocks);
|
|
1421
1510
|
suppressFinalParagraphInRepeatedEmptySuffix(blocks);
|
|
1422
|
-
return groupParagraphFrames(mergeRunInParagraphs(blocks), nextBlockId);
|
|
1511
|
+
return groupParagraphFrames(applySectionDocumentGrid(mergeRunInParagraphs(blocks), opts.finalSectionDocumentGridLinePitchTwips), nextBlockId);
|
|
1512
|
+
}
|
|
1513
|
+
function applySectionDocumentGrid(blocks, finalLinePitchTwips) {
|
|
1514
|
+
const result = [...blocks];
|
|
1515
|
+
let sectionStart = 0;
|
|
1516
|
+
const stampSection = (end, linePitchTwips) => {
|
|
1517
|
+
if (linePitchTwips === void 0 || linePitchTwips <= 0) return;
|
|
1518
|
+
const linePitch = twipsToPixels(linePitchTwips);
|
|
1519
|
+
for (let index = sectionStart; index < end; index += 1) {
|
|
1520
|
+
const block = result[index];
|
|
1521
|
+
if (block?.kind !== "paragraph") continue;
|
|
1522
|
+
result[index] = {
|
|
1523
|
+
...block,
|
|
1524
|
+
attrs: {
|
|
1525
|
+
...block.attrs,
|
|
1526
|
+
documentGridLinePitch: linePitch
|
|
1527
|
+
}
|
|
1528
|
+
};
|
|
1529
|
+
}
|
|
1530
|
+
};
|
|
1531
|
+
for (let index = 0; index < blocks.length; index += 1) {
|
|
1532
|
+
const block = blocks[index];
|
|
1533
|
+
if (block?.kind !== "sectionBreak") continue;
|
|
1534
|
+
stampSection(index, block.documentGridLinePitchTwips);
|
|
1535
|
+
sectionStart = index + 1;
|
|
1536
|
+
}
|
|
1537
|
+
stampSection(blocks.length, finalLinePitchTwips);
|
|
1538
|
+
return result;
|
|
1423
1539
|
}
|
|
1424
1540
|
/**
|
|
1425
1541
|
* Merge consecutive paragraph blocks where the first carries
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/layout-bridge/dom/noteStoryDom.ts
|
|
2
|
+
const isClosestNoteTarget = (value) => typeof value === "object" && value !== null && "closest" in value && typeof value.closest === "function";
|
|
3
|
+
const findNoteStoryForTarget = (target) => {
|
|
4
|
+
if (!isClosestNoteTarget(target)) return null;
|
|
5
|
+
const noteTarget = target.closest("[data-note-kind][data-note-id]");
|
|
6
|
+
const kind = noteTarget?.dataset["noteKind"];
|
|
7
|
+
const rawNoteId = noteTarget?.dataset["noteId"] ?? "";
|
|
8
|
+
if (!/^-?\d+$/u.test(rawNoteId)) return null;
|
|
9
|
+
const noteId = Number(rawNoteId);
|
|
10
|
+
if (kind !== "footnote" && kind !== "endnote" || !Number.isSafeInteger(noteId)) return null;
|
|
11
|
+
return {
|
|
12
|
+
kind,
|
|
13
|
+
noteId
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
//#endregion
|
|
17
|
+
export { findNoteStoryForTarget };
|
|
@@ -72,7 +72,7 @@ function computeLinePmRange(block, line) {
|
|
|
72
72
|
if (!run) continue;
|
|
73
73
|
if (runIndex < line.fromRun) {
|
|
74
74
|
if (run.kind === "text") charOffset += run.text.length;
|
|
75
|
-
else if (run.kind === "tab" || run.kind === "lineBreak") charOffset += 1;
|
|
75
|
+
else if (run.kind === "tab" || run.kind === "lineBreak" || run.kind === "renderedPageBreak") charOffset += 1;
|
|
76
76
|
else if (run.kind === "image") charOffset += 1;
|
|
77
77
|
} else if (runIndex === line.fromRun) {
|
|
78
78
|
charOffset += line.fromChar;
|
|
@@ -90,7 +90,7 @@ function computeLinePmRange(block, line) {
|
|
|
90
90
|
const start = runIndex === line.fromRun ? line.fromChar : 0;
|
|
91
91
|
const end = runIndex === line.toRun ? line.toChar : text.length;
|
|
92
92
|
lineLength += end - start;
|
|
93
|
-
} else if (run.kind === "tab" || run.kind === "lineBreak") lineLength += 1;
|
|
93
|
+
} else if (run.kind === "tab" || run.kind === "lineBreak" || run.kind === "renderedPageBreak") lineLength += 1;
|
|
94
94
|
else if (run.kind === "image") lineLength += 1;
|
|
95
95
|
}
|
|
96
96
|
pmEnd = pmStart + lineLength;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BlockId, BorderStyle, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, Layout, LayoutOptions, LineBreakRun, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, tableColumnsArePinned } from "./types.js";
|
|
1
|
+
import { BlockId, BorderStyle, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, Layout, LayoutOptions, LineBreakRun, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, RenderedPageBreakRun, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, tableColumnsArePinned } from "./types.js";
|
|
2
2
|
import { PageState, Paginator, PaginatorOptions, createPaginator } from "./paginator.js";
|
|
3
3
|
import { KeepNextChain, calculateChainHeight, computeKeepNextChains, getMidChainIndices, hasKeepLines, hasPageBreakBefore } from "./keep-together.js";
|
|
4
4
|
import { resolveSectionHeaderFooterRefs } from "./headerFooterRefs.js";
|
|
@@ -44,4 +44,4 @@ declare function layoutDocument(blocks: FlowBlock[], measures: Measure[], option
|
|
|
44
44
|
*/
|
|
45
45
|
declare function getHeaderRowsHeight(measure: TableMeasure, headerRowCount: number): number;
|
|
46
46
|
//#endregion
|
|
47
|
-
export { BlockId, BorderStyle, type BreakDecision, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, type KeepNextChain, Layout, LayoutOptions, LineBreakRun, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, type PageState, type Paginator, type PaginatorOptions, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionLayoutConfig, type SectionState, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, applyContextualSpacing, applyPendingToActive, assertExhaustiveFlowBlock, calculateChainHeight, collectSectionConfigs, computeKeepNextChains, createInitialSectionState, createPaginator, findPageIndexContainingPmPos, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getEffectiveColumns, getEffectiveMargins, getEffectivePageSize, getHeaderRowsHeight, getMidChainIndices, getTableRowLeadingWidth, hasKeepLines, hasPageBreakBefore, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, layoutDocument, resolveSectionHeaderFooterRefs, scheduleSectionBreak, tableColumnsArePinned };
|
|
47
|
+
export { BlockId, BorderStyle, type BreakDecision, CellBorderSpec, CellBorders, ColumnBreakBlock, ColumnBreakMeasure, ColumnLayout, DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, DocumentPosition, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, FieldRun, FloatingTablePosition, FlowBlock, FootnoteContent, Fragment, FragmentBase, HeaderFooterContent, HeaderFooterContentHeights, HeaderFooterLayout, HitTestResult, HyperlinkInfo, ImageBlock, ImageFragment, ImageMeasure, ImageRun, ImageRunPosition, type KeepNextChain, Layout, LayoutOptions, LineBreakRun, ListNumPr, MathRun, Measure, MeasuredLine, Page, PageBreakBlock, PageBreakMeasure, PageHeaderFooterRefs, PageMargins, type PageState, type Paginator, type PaginatorOptions, ParagraphAttrs, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphIndent, ParagraphMeasure, ParagraphSpacing, RenderedPageBreakRun, Run, RunFormatting, SdtGroup, SectionBreakBlock, SectionBreakMeasure, SectionLayoutConfig, type SectionState, TabAlignment, TabRun, TabStop, TableBlock, TableCell, TableCellMeasure, TableFragment, TableMeasure, TableRow, TableRowMeasure, TextBoxBlock, TextBoxFlowAttrs, TextBoxFragment, TextBoxMeasure, TextRun, applyContextualSpacing, applyPendingToActive, assertExhaustiveFlowBlock, calculateChainHeight, collectSectionConfigs, computeKeepNextChains, createInitialSectionState, createPaginator, findPageIndexContainingPmPos, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getEffectiveColumns, getEffectiveMargins, getEffectivePageSize, getHeaderRowsHeight, getMidChainIndices, getTableRowLeadingWidth, hasKeepLines, hasPageBreakBefore, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, layoutDocument, resolveSectionHeaderFooterRefs, scheduleSectionBreak, tableColumnsArePinned };
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { emuToPixels } from "../utils/units.js";
|
|
2
2
|
import { measuredLineAdvance } from "./lineFlow.js";
|
|
3
3
|
import { DEFAULT_TEXTBOX_MARGINS, DEFAULT_TEXTBOX_WIDTH, FOOTNOTE_ENTRY_MARGIN_BOTTOM, FOOTNOTE_FALLBACK_LINE_HEIGHT, FOOTNOTE_SEPARATOR_HEIGHT, floatingTextBoxReservesBand, floatingTextBoxWrapsText, getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, tableColumnsArePinned } from "./types.js";
|
|
4
|
-
import { getParagraphSpacingAfter, getParagraphSpacingBefore } from "./paragraphSpacing.js";
|
|
4
|
+
import { collapseParagraphSpacing, getParagraphSpacingAfter, getParagraphSpacingBefore, paragraphsShareStyle, resolveEffectiveParagraphSpacingTree } from "./paragraphSpacing.js";
|
|
5
5
|
import { calculateChainHeight, computeKeepNextChains, getMidChainIndices, hasKeepLines, hasPageBreakBefore } from "./keep-together.js";
|
|
6
|
-
import { continuesNumberedSequence } from "./paragraphSequence.js";
|
|
7
6
|
import { createPaginator } from "./paginator.js";
|
|
8
7
|
import { getParagraphFragmentPmRange } from "./paragraphFragmentRange.js";
|
|
9
8
|
import { INITIAL_RENDERED_BREAK_STATE, reconcileAfterBlock, reconcileBreakBeforeBlock, recordReflowBoundary } from "./renderedBreakReconciliation.js";
|
|
@@ -19,6 +18,7 @@ import { panic } from "better-result";
|
|
|
19
18
|
*
|
|
20
19
|
* Converts blocks + measures into positioned fragments on pages.
|
|
21
20
|
*/
|
|
21
|
+
const RENDERED_BREAK_REFLOW_TOLERANCE_LINES = 3;
|
|
22
22
|
const DEFAULT_COLUMNS = {
|
|
23
23
|
count: 1,
|
|
24
24
|
gap: 0
|
|
@@ -58,7 +58,10 @@ function balancedParagraphSectionHeight({ blocks, measures, startIndex, endIndex
|
|
|
58
58
|
const measure = measures[index];
|
|
59
59
|
if (block?.kind !== "paragraph" || measure?.kind !== "paragraph") return;
|
|
60
60
|
if (block.attrs?.keepNext === true || block.attrs?.keepLines === true || block.runs.some((run) => run.kind === "text" && run.footnoteRefId !== void 0)) return;
|
|
61
|
-
const leadingSpacing =
|
|
61
|
+
const leadingSpacing = collapseParagraphSpacing({
|
|
62
|
+
before: getParagraphSpacingBefore(block),
|
|
63
|
+
after: trailingSpacing
|
|
64
|
+
});
|
|
62
65
|
if (measure.lines.length === 0) {
|
|
63
66
|
if (leadingSpacing > 0) {
|
|
64
67
|
lineUnits.push(leadingSpacing);
|
|
@@ -117,7 +120,7 @@ function applyContextualSpacing(blocks) {
|
|
|
117
120
|
if (curr.kind !== "paragraph" || next.kind !== "paragraph") continue;
|
|
118
121
|
const currAttrs = curr.attrs;
|
|
119
122
|
const nextAttrs = next.attrs;
|
|
120
|
-
if (
|
|
123
|
+
if (!paragraphsShareStyle(curr, next)) continue;
|
|
121
124
|
if (currAttrs?.contextualSpacing && currAttrs.spacing) currAttrs.spacing = {
|
|
122
125
|
...currAttrs.spacing,
|
|
123
126
|
after: 0
|
|
@@ -130,24 +133,6 @@ function applyContextualSpacing(blocks) {
|
|
|
130
133
|
for (const block of blocks) if (block.kind === "table") for (const row of block.rows) for (const cell of row.cells) applyContextualSpacing(cell.blocks);
|
|
131
134
|
else if (block.kind === "textBox") applyContextualSpacing(block.content);
|
|
132
135
|
}
|
|
133
|
-
/** Suppress automatic inter-item spacing within one numbered sequence. */
|
|
134
|
-
const applyAutomaticListSpacing = (blocks) => {
|
|
135
|
-
for (let index = 1; index < blocks.length; index++) {
|
|
136
|
-
const previous = blocks[index - 1];
|
|
137
|
-
const current = blocks[index];
|
|
138
|
-
if (previous?.kind !== "paragraph" || current?.kind !== "paragraph" || !continuesNumberedSequence(previous, current)) continue;
|
|
139
|
-
if (previous.attrs?.automaticSpacing?.after && previous.attrs.spacing) previous.attrs.spacing = {
|
|
140
|
-
...previous.attrs.spacing,
|
|
141
|
-
after: 0
|
|
142
|
-
};
|
|
143
|
-
if (current.attrs?.automaticSpacing?.before && current.attrs.spacing) current.attrs.spacing = {
|
|
144
|
-
...current.attrs.spacing,
|
|
145
|
-
before: 0
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
for (const block of blocks) if (block.kind === "table") for (const row of block.rows) for (const cell of row.cells) applyAutomaticListSpacing(cell.blocks);
|
|
149
|
-
else if (block.kind === "textBox") applyAutomaticListSpacing(block.content);
|
|
150
|
-
};
|
|
151
136
|
/**
|
|
152
137
|
* Layout a document: convert blocks + measures into pages with positioned fragments.
|
|
153
138
|
*
|
|
@@ -196,8 +181,7 @@ function layoutDocument(blocks, measures, options) {
|
|
|
196
181
|
...options.footnoteReservedHeights !== void 0 ? { footnoteReservedHeights: options.footnoteReservedHeights } : {},
|
|
197
182
|
...options.sectionHeaderFooterRefs !== void 0 ? { sectionHeaderFooterRefs: options.sectionHeaderFooterRefs } : {}
|
|
198
183
|
});
|
|
199
|
-
|
|
200
|
-
applyAutomaticListSpacing(blocks);
|
|
184
|
+
blocks = resolveEffectiveParagraphSpacingTree(blocks);
|
|
201
185
|
const keepNextChains = computeKeepNextChains(blocks);
|
|
202
186
|
const midChainIndices = getMidChainIndices(keepNextChains);
|
|
203
187
|
const blocksById = /* @__PURE__ */ new Map();
|
|
@@ -210,7 +194,9 @@ function layoutDocument(blocks, measures, options) {
|
|
|
210
194
|
for (let i = 0; i < blocks.length; i++) {
|
|
211
195
|
const block = blocks[i];
|
|
212
196
|
const measure = measures[i];
|
|
213
|
-
const
|
|
197
|
+
const firstLine = measure.kind === "paragraph" ? measure.lines.at(0) : void 0;
|
|
198
|
+
const firstLineAdvance = firstLine ? measuredLineAdvance(firstLine) : 0;
|
|
199
|
+
const renderedBreakNeedsSnap = measure.kind === "paragraph" && (!paginator.fits(measure.totalHeight) || firstLineAdvance > 0 && paginator.getAvailableHeight() <= firstLineAdvance * RENDERED_BREAK_REFLOW_TOLERANCE_LINES);
|
|
214
200
|
const hasExplicitPageBreak = hasPageBreakBefore(block);
|
|
215
201
|
const breakDecision = reconcileBreakBeforeBlock({
|
|
216
202
|
state: renderedBreakState,
|
|
@@ -370,11 +356,20 @@ function layoutParagraph({ block, measure, paginator, contentWidth, footnoteHeig
|
|
|
370
356
|
while (currentLineIndex < lines.length) {
|
|
371
357
|
const state = paginator.getCurrentState();
|
|
372
358
|
const availableHeight = paginator.getAvailableHeight();
|
|
359
|
+
const currentLine = lines.at(currentLineIndex);
|
|
360
|
+
const markerAlreadySatisfied = state.columnIndex === 0 && state.cursorY === state.topMargin && state.page.fragments.length === 0;
|
|
361
|
+
if (currentLine?.renderedPageBreakBefore === true && !markerAlreadySatisfied && availableHeight <= measuredLineAdvance(currentLine) * RENDERED_BREAK_REFLOW_TOLERANCE_LINES) {
|
|
362
|
+
paginator.forcePageBreak();
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
373
365
|
if (currentLineIndex === 0 && state.trailingSpacing > 0 && state.cursorY !== state.topMargin) {
|
|
374
366
|
const firstLine = lines[0];
|
|
375
367
|
const firstLineRefs = getLineFootnoteRefs(block, firstLine.fromRun, firstLine.toRun, footnoteHeightById);
|
|
376
368
|
const firstLineHeight = measuredLineAdvance(firstLine) + firstLineRefs.height;
|
|
377
|
-
const collapsedLead =
|
|
369
|
+
const collapsedLead = collapseParagraphSpacing({
|
|
370
|
+
before: spaceBefore,
|
|
371
|
+
after: state.trailingSpacing
|
|
372
|
+
});
|
|
378
373
|
const columnCapacity = state.contentBottom - state.topMargin;
|
|
379
374
|
if (collapsedLead + firstLineHeight > availableHeight && spaceBefore + firstLineHeight <= columnCapacity) {
|
|
380
375
|
paginator.ensureFits(collapsedLead + firstLineHeight);
|
|
@@ -385,10 +380,18 @@ function layoutParagraph({ block, measure, paginator, contentWidth, footnoteHeig
|
|
|
385
380
|
let linesFnHeight = 0;
|
|
386
381
|
const linesFnIds = [];
|
|
387
382
|
let fittingLines = 0;
|
|
388
|
-
|
|
383
|
+
let forcePageBreakAfterFragment = false;
|
|
384
|
+
const firstFragmentSpaceBefore = currentLineIndex === 0 ? collapseParagraphSpacing({
|
|
385
|
+
before: spaceBefore,
|
|
386
|
+
after: state.trailingSpacing
|
|
387
|
+
}) : 0;
|
|
389
388
|
for (let j = currentLineIndex; j < lines.length; j++) {
|
|
390
389
|
const line = lines[j];
|
|
391
390
|
const lineAdvance = measuredLineAdvance(line);
|
|
391
|
+
if (j > currentLineIndex && line.renderedPageBreakBefore === true && availableHeight - (linesHeight + firstFragmentSpaceBefore + linesFnHeight) <= lineAdvance * RENDERED_BREAK_REFLOW_TOLERANCE_LINES) {
|
|
392
|
+
forcePageBreakAfterFragment = true;
|
|
393
|
+
break;
|
|
394
|
+
}
|
|
392
395
|
const lineRefs = getLineFootnoteRefs(block, line.fromRun, line.toRun, footnoteHeightById);
|
|
393
396
|
const totalWithLine = linesHeight + lineAdvance;
|
|
394
397
|
if (totalWithLine + firstFragmentSpaceBefore + linesFnHeight + lineRefs.height <= availableHeight || fittingLines === 0) {
|
|
@@ -447,7 +450,8 @@ function layoutParagraph({ block, measure, paginator, contentWidth, footnoteHeig
|
|
|
447
450
|
fragment.y = paginator.addFragment(fragment, linesHeight, effectiveSpaceBefore, effectiveSpaceAfter).y;
|
|
448
451
|
if (linesFnHeight > 0) paginator.addFootnoteHeight(linesFnHeight, linesFnIds);
|
|
449
452
|
currentLineIndex += fittingLines;
|
|
450
|
-
if (currentLineIndex < lines.length) if (
|
|
453
|
+
if (currentLineIndex < lines.length) if (forcePageBreakAfterFragment) paginator.forcePageBreak();
|
|
454
|
+
else if (forceBreakAfterFragment) paginator.forceColumnBreak();
|
|
451
455
|
else paginator.ensureFits(measuredLineAdvance(lines[currentLineIndex]));
|
|
452
456
|
}
|
|
453
457
|
}
|
|
@@ -469,6 +473,10 @@ function getHeaderRowsHeight(measure, headerRowCount) {
|
|
|
469
473
|
for (let i = 0; i < headerRowCount && i < measure.rows.length; i++) height += measure.rows[i].height;
|
|
470
474
|
return height;
|
|
471
475
|
}
|
|
476
|
+
const tableRowStartsWithRenderedPageBreak = (block, rowIndex) => block.rows[rowIndex]?.cells.some((cell) => {
|
|
477
|
+
const firstBlock = cell.blocks.at(0);
|
|
478
|
+
return firstBlock?.kind === "paragraph" && firstBlock.attrs?.renderedPageBreakBefore === true;
|
|
479
|
+
}) ?? false;
|
|
472
480
|
/**
|
|
473
481
|
* Layout a table block onto pages.
|
|
474
482
|
*/
|
|
@@ -511,6 +519,13 @@ function layoutTable(block, measure, paginator, footnoteHeightById) {
|
|
|
511
519
|
return oversized || row.height > currentAvailableHeight;
|
|
512
520
|
};
|
|
513
521
|
while (currentRowIndex < rows.length) {
|
|
522
|
+
const rowState = paginator.getCurrentState();
|
|
523
|
+
const rowHeaderOverhead = shouldRepeatHeaderRows(currentRowIndex, 0, rowState) ? headerRowsHeight : 0;
|
|
524
|
+
const rowAvailableHeight = paginator.getAvailableHeight() - rowHeaderOverhead - rowState.trailingSpacing;
|
|
525
|
+
if (!(rowState.cursorY === rowState.topMargin && rowState.page.fragments.length === 0) && tableRowStartsWithRenderedPageBreak(block, currentRowIndex) && rows[currentRowIndex].height > rowAvailableHeight) {
|
|
526
|
+
paginator.forcePageBreak();
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
514
529
|
const splittableRow = rows[currentRowIndex];
|
|
515
530
|
if (canSplitRow(currentRowIndex)) {
|
|
516
531
|
let consumed = 0;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ParagraphAttrs } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/layout-engine/justificationCompatibility.d.ts
|
|
4
|
+
declare function resolveJustificationCompatibility(compatibilityMode: number | undefined): NonNullable<ParagraphAttrs["justificationCompatibility"]> | undefined;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { resolveJustificationCompatibility };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/layout-engine/justificationCompatibility.ts
|
|
2
|
+
const LEGACY_JUSTIFICATION_MAX_COMPATIBILITY_MODE = 14;
|
|
3
|
+
function resolveJustificationCompatibility(compatibilityMode) {
|
|
4
|
+
if (compatibilityMode === void 0 || compatibilityMode > LEGACY_JUSTIFICATION_MAX_COMPATIBILITY_MODE) return;
|
|
5
|
+
return { type: "legacy" };
|
|
6
|
+
}
|
|
7
|
+
//#endregion
|
|
8
|
+
export { resolveJustificationCompatibility };
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
+
import { collapseParagraphSpacing } from "./paragraphSpacing.js";
|
|
1
2
|
//#region src/layout-engine/keep-together.ts
|
|
3
|
+
/**
|
|
4
|
+
* Keep Together Logic - Handle keepNext and keepLines paragraph properties
|
|
5
|
+
*
|
|
6
|
+
* DOCX paragraphs can have keepNext (keep with next paragraph) and keepLines
|
|
7
|
+
* (keep all lines together) properties that affect pagination.
|
|
8
|
+
*/
|
|
2
9
|
function isVisuallyEmptyParagraph(block) {
|
|
3
10
|
if (block.runs.length === 0) return true;
|
|
4
11
|
if (block.runs.length !== 1) return false;
|
|
@@ -87,7 +94,10 @@ function calculateChainHeight(chain, blocks, measures) {
|
|
|
87
94
|
const successorBlock = blocks[successorIndex];
|
|
88
95
|
const successorMeasure = measures[successorIndex];
|
|
89
96
|
if (successorBlock?.kind !== "paragraph" || successorMeasure?.kind !== "paragraph") return totalHeight;
|
|
90
|
-
totalHeight +=
|
|
97
|
+
totalHeight += collapseParagraphSpacing({
|
|
98
|
+
before: successorBlock.attrs?.spacing?.before ?? 0,
|
|
99
|
+
after: trailingSpacing
|
|
100
|
+
});
|
|
91
101
|
const firstLine = successorMeasure.lines.at(0);
|
|
92
102
|
if (!firstLine) return totalHeight;
|
|
93
103
|
const isAnchor = index === successorIndices.length - 1 && chain.anchorIndex !== -1;
|
|
@@ -2,9 +2,16 @@ import { getLineBreakProviderGeneration } from "./lineBreakProvider.js";
|
|
|
2
2
|
import { lineBreakPolicyCacheParts } from "./effectiveLineBreakPolicy.js";
|
|
3
3
|
//#region src/layout-engine/measure/cache.ts
|
|
4
4
|
/**
|
|
5
|
+
* Default max entries for text width cache
|
|
6
|
+
* Large documents (30+ pages) can generate 20,000+ unique text measurements.
|
|
7
|
+
* A generous default avoids cache thrashing on big docs.
|
|
8
|
+
*/
|
|
9
|
+
const DEFAULT_TEXT_CACHE_SIZE = 2e4;
|
|
10
|
+
const TEXT_CACHE_REFRESH_AFTER_HITS = 16;
|
|
11
|
+
/**
|
|
5
12
|
* Current max size for text width cache
|
|
6
13
|
*/
|
|
7
|
-
let textCacheMaxSize =
|
|
14
|
+
let textCacheMaxSize = DEFAULT_TEXT_CACHE_SIZE;
|
|
8
15
|
/**
|
|
9
16
|
* LRU cache for text width measurements
|
|
10
17
|
* Key format: "text|font|letterSpacing"
|
|
@@ -34,8 +41,12 @@ function getCachedTextWidth(text, font, letterSpacing = 0) {
|
|
|
34
41
|
const key = makeTextKey(text, font, letterSpacing);
|
|
35
42
|
const entry = textWidthCache.get(key);
|
|
36
43
|
if (entry !== void 0) {
|
|
37
|
-
|
|
38
|
-
|
|
44
|
+
entry.hitsSinceRefresh += 1;
|
|
45
|
+
if (entry.hitsSinceRefresh >= TEXT_CACHE_REFRESH_AFTER_HITS) {
|
|
46
|
+
entry.hitsSinceRefresh = 0;
|
|
47
|
+
textWidthCache.delete(key);
|
|
48
|
+
textWidthCache.set(key, entry);
|
|
49
|
+
}
|
|
39
50
|
return entry.width;
|
|
40
51
|
}
|
|
41
52
|
}
|
|
@@ -44,8 +55,11 @@ function getCachedTextWidth(text, font, letterSpacing = 0) {
|
|
|
44
55
|
*/
|
|
45
56
|
function setCachedTextWidth(text, font, letterSpacing, width) {
|
|
46
57
|
const key = makeTextKey(text, font, letterSpacing);
|
|
47
|
-
textWidthCache.set(key, {
|
|
48
|
-
|
|
58
|
+
textWidthCache.set(key, {
|
|
59
|
+
hitsSinceRefresh: 0,
|
|
60
|
+
width
|
|
61
|
+
});
|
|
62
|
+
if (textWidthCache.size > textCacheMaxSize) evictTextEntries();
|
|
49
63
|
}
|
|
50
64
|
/**
|
|
51
65
|
* Clear the text width cache
|
|
@@ -169,6 +183,8 @@ function hashParagraphBlock(block) {
|
|
|
169
183
|
if (attrs.defaultFontFamily != null) parts.push(`dff:${attrs.defaultFontFamily}`);
|
|
170
184
|
if (attrs.suppressEmptyParagraphHeight) parts.push("sup");
|
|
171
185
|
if (attrs.reserveEmptyOutlineHeight) parts.push("outline-empty-reserve");
|
|
186
|
+
if (attrs.documentGridLinePitch !== void 0) parts.push(`documentGrid:${attrs.documentGridLinePitch}|${attrs.snapToGrid !== false}`);
|
|
187
|
+
if (attrs.justificationCompatibility) parts.push(`justify-compat:${attrs.justificationCompatibility.type}`);
|
|
172
188
|
parts.push(...lineBreakPolicyCacheParts(attrs));
|
|
173
189
|
const borders = attrs.borders;
|
|
174
190
|
if (borders) {
|