@stll/folio-core 0.7.0 → 0.8.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/blockRange.d.ts +13 -2
- package/dist/ai-edits/blockRange.js +23 -2
- package/dist/ai-edits/index.d.ts +4 -2
- package/dist/ai-edits/index.js +3 -1
- package/dist/ai-edits/scoped-reading.d.ts +9 -0
- package/dist/ai-edits/scoped-reading.js +60 -0
- package/dist/ai-edits/snapshot.js +13 -4
- package/dist/ai-edits/types.d.ts +44 -2
- package/dist/compat/eigenpal.d.ts +5 -2
- package/dist/compat/eigenpal.js +4 -1
- package/dist/controller/fontReadiness.d.ts +29 -0
- package/dist/controller/fontReadiness.js +139 -0
- package/dist/controller/layoutPipeline.js +76 -9
- package/dist/docx/blockContentParser.js +51 -8
- package/dist/docx/capabilities.d.ts +41 -0
- package/dist/docx/capabilities.js +322 -0
- package/dist/docx/compatibility.d.ts +34 -2
- package/dist/docx/compatibility.js +128 -38
- package/dist/docx/conformance.d.ts +6 -0
- package/dist/docx/conformance.js +18 -0
- package/dist/docx/ensureParaIds.d.ts +29 -0
- package/dist/docx/ensureParaIds.js +423 -0
- package/dist/docx/numberingParser.js +1 -0
- package/dist/docx/paragraphParser.js +9 -0
- package/dist/docx/paragraphTextBoxEnrichment.js +141 -2
- package/dist/docx/parser.js +2 -0
- package/dist/docx/selectiveXmlPatch.d.ts +10 -1
- package/dist/docx/selectiveXmlPatch.js +1 -1
- package/dist/docx/serializer/paragraphSerializer.js +4 -0
- package/dist/docx/serializer/runSerializer.js +7 -2
- package/dist/docx/serializer/tableSerializer.js +4 -0
- package/dist/docx/tableParser.js +8 -0
- package/dist/docx/textBoxParser.js +6 -1
- package/dist/docx/vmlImageParser.js +145 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +4 -1
- package/dist/layout-bridge/convert/headerFooterLayout.js +16 -2
- package/dist/layout-bridge/convert/paragraphFrames.d.ts +7 -0
- package/dist/layout-bridge/convert/paragraphFrames.js +136 -0
- package/dist/layout-bridge/convert/toFlowBlocks.js +42 -3
- package/dist/layout-bridge/engine/hitTest.js +2 -1
- package/dist/layout-bridge/engine/selectionRects.js +2 -1
- package/dist/layout-engine/headerFooterRefs.d.ts +7 -0
- package/dist/layout-engine/headerFooterRefs.js +40 -0
- package/dist/layout-engine/index.d.ts +3 -2
- package/dist/layout-engine/index.js +36 -82
- package/dist/layout-engine/measure/listMarkerWidth.d.ts +3 -1
- package/dist/layout-engine/measure/listMarkerWidth.js +23 -4
- package/dist/layout-engine/measure/measureBlocks.d.ts +3 -0
- package/dist/layout-engine/measure/measureBlocks.js +133 -51
- package/dist/layout-engine/measure/measureParagraph.js +13 -4
- package/dist/layout-engine/measure/tableCellGrid.d.ts +15 -0
- package/dist/layout-engine/measure/tableCellGrid.js +62 -0
- package/dist/layout-engine/measure/textBoxParagraphLayout.d.ts +18 -0
- package/dist/layout-engine/measure/textBoxParagraphLayout.js +32 -0
- package/dist/layout-engine/paginator.d.ts +2 -1
- package/dist/layout-engine/paginator.js +7 -6
- package/dist/layout-engine/paragraphFrame.d.ts +22 -0
- package/dist/layout-engine/paragraphFrame.js +17 -0
- package/dist/layout-engine/paragraphSequence.d.ts +7 -0
- package/dist/layout-engine/paragraphSequence.js +25 -0
- package/dist/layout-engine/paragraphSpacing.d.ts +17 -0
- package/dist/layout-engine/paragraphSpacing.js +30 -0
- package/dist/layout-engine/renderedBreakReconciliation.d.ts +58 -0
- package/dist/layout-engine/renderedBreakReconciliation.js +63 -0
- package/dist/layout-engine/types.d.ts +17 -8
- package/dist/layout-engine/types.js +15 -2
- package/dist/layout-painter/renderPage.js +2 -2
- package/dist/layout-painter/renderParagraph.js +6 -5
- package/dist/layout-painter/renderTable.js +42 -12
- package/dist/layout-painter/renderTextBox.js +17 -7
- package/dist/managers/DocumentLoaderManager.js +1 -1
- package/dist/paged-layout/sectionBlockWidths.d.ts +3 -0
- package/dist/paged-layout/sectionBlockWidths.js +9 -0
- package/dist/paged-layout/sectionGeometry.js +1 -1
- package/dist/prosemirror/attrs/index.js +11 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +2 -0
- package/dist/prosemirror/conversion/toProseDoc.js +27 -23
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +1 -0
- package/dist/prosemirror/extensions/features/ListExtension.js +1 -0
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +68 -16
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +2 -1
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +7 -0
- package/dist/prosemirror/schema/nodes.d.ts +4 -2
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
- package/dist/server.d.ts +4 -2
- package/dist/server.js +3 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/utils/createDocument.js +26 -18
- package/dist/utils/hexId.d.ts +8 -1
- package/dist/utils/hexId.js +11 -3
- package/package.json +1 -1
|
@@ -16,6 +16,10 @@ function hasAuthoredVisualContent(block) {
|
|
|
16
16
|
if (attrs.spacingExplicit?.before || attrs.spacingExplicit?.after) return true;
|
|
17
17
|
return false;
|
|
18
18
|
}
|
|
19
|
+
function preservesInheritedSpacing(block) {
|
|
20
|
+
if (!isVisuallyEmptyParagraph(block)) return false;
|
|
21
|
+
return block.attrs?.styleId !== void 0 || block.attrs?.hasDirectParagraphFormatting === true || block.attrs?.hasDirectParagraphMarkFormatting === true;
|
|
22
|
+
}
|
|
19
23
|
function normalizeHeaderFooterMeasureBlocks(blocks, section = "header") {
|
|
20
24
|
return normalizeFlowBlockArray(blocks, { suppressTrailingEmptyAfterTable: section === "header" });
|
|
21
25
|
}
|
|
@@ -33,8 +37,9 @@ function normalizeFlowBlockArray(blocks, normalization) {
|
|
|
33
37
|
const explicit = block.attrs?.spacingExplicit;
|
|
34
38
|
const hasResolvedBefore = block.attrs?.spacing?.before != null;
|
|
35
39
|
const hasResolvedAfter = block.attrs?.spacing?.after != null;
|
|
36
|
-
const
|
|
37
|
-
const
|
|
40
|
+
const preserveInherited = preservesInheritedSpacing(block);
|
|
41
|
+
const beforeIsInherited = hasResolvedBefore && !explicit?.before && !preserveInherited;
|
|
42
|
+
const afterIsInherited = hasResolvedAfter && !explicit?.after && !preserveInherited;
|
|
38
43
|
const stripsSpacing = beforeIsInherited || afterIsInherited;
|
|
39
44
|
const stripsImages = block.runs.some(isAnchoredImageRun);
|
|
40
45
|
if (!stripsSpacing && !stripsImages && !isTrailingEmpty) return block;
|
|
@@ -79,6 +84,10 @@ function isVisuallyEmptyParagraph(block) {
|
|
|
79
84
|
if (block.kind !== "paragraph") return false;
|
|
80
85
|
return block.runs.every((run) => run.kind === "text" && run.text.trim().length === 0);
|
|
81
86
|
}
|
|
87
|
+
function isPaintlessParagraph(block) {
|
|
88
|
+
if (block.kind !== "paragraph") return false;
|
|
89
|
+
return block.runs.every((run) => run.kind === "text" && run.text.trim().length === 0 || run.kind === "tab" || run.kind === "lineBreak");
|
|
90
|
+
}
|
|
82
91
|
function normalizeTableBlock(block) {
|
|
83
92
|
const blockState = { changed: false };
|
|
84
93
|
const rows = block.rows.map((row) => {
|
|
@@ -232,6 +241,10 @@ function calculateHeaderFooterVisualBounds(blocks, measures, flowHeight, metrics
|
|
|
232
241
|
* these bounds separately describe the in-flow portion for API consumers.
|
|
233
242
|
*/
|
|
234
243
|
function calculateHeaderFooterMarginPushBounds(blocks, measures, flowHeight, metrics) {
|
|
244
|
+
if (blocks.length > 0 && blocks.every((block) => isPaintlessParagraph(block) && !hasAuthoredVisualContent(block))) return {
|
|
245
|
+
top: 0,
|
|
246
|
+
bottom: 0
|
|
247
|
+
};
|
|
235
248
|
let top = 0;
|
|
236
249
|
let bottom = 0;
|
|
237
250
|
let cursorY = 0;
|
|
@@ -422,6 +435,7 @@ function serializeParagraphAttrs(attrs) {
|
|
|
422
435
|
"listMarker",
|
|
423
436
|
"listIsBullet",
|
|
424
437
|
"listMarkerHidden",
|
|
438
|
+
"listMarkerAlignment",
|
|
425
439
|
"listMarkerSuffix",
|
|
426
440
|
"tabs"
|
|
427
441
|
];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { BlockId, FlowBlock } from "../../layout-engine/types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/layout-bridge/convert/paragraphFrames.d.ts
|
|
4
|
+
type BlockIdFactory = () => BlockId;
|
|
5
|
+
declare function groupParagraphFrames(blocks: FlowBlock[], nextBlockId: BlockIdFactory): FlowBlock[];
|
|
6
|
+
//#endregion
|
|
7
|
+
export { groupParagraphFrames };
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { pixelsToEmu } from "../../utils/units.js";
|
|
2
|
+
import { setTextBoxGroupId } from "../../layout-engine/textBoxGroup.js";
|
|
3
|
+
import { getParagraphFrame, markParagraphFrameTextBox } from "../../layout-engine/paragraphFrame.js";
|
|
4
|
+
//#region src/layout-bridge/convert/paragraphFrames.ts
|
|
5
|
+
const FRAME_PROPERTIES = [
|
|
6
|
+
"width",
|
|
7
|
+
"height",
|
|
8
|
+
"hSpace",
|
|
9
|
+
"vSpace",
|
|
10
|
+
"hAnchor",
|
|
11
|
+
"vAnchor",
|
|
12
|
+
"x",
|
|
13
|
+
"y",
|
|
14
|
+
"xAlign",
|
|
15
|
+
"yAlign",
|
|
16
|
+
"wrap"
|
|
17
|
+
];
|
|
18
|
+
function framesEqual(left, right) {
|
|
19
|
+
return FRAME_PROPERTIES.every((property) => left[property] === right[property]);
|
|
20
|
+
}
|
|
21
|
+
function horizontalRelativeTo(anchor) {
|
|
22
|
+
if (anchor === "page" || anchor === "margin") return anchor;
|
|
23
|
+
return "column";
|
|
24
|
+
}
|
|
25
|
+
function verticalRelativeTo(anchor) {
|
|
26
|
+
if (anchor === "page" || anchor === "margin") return anchor;
|
|
27
|
+
return "paragraph";
|
|
28
|
+
}
|
|
29
|
+
function framePosition(frame) {
|
|
30
|
+
const horizontal = frame.x !== void 0 || frame.xAlign !== void 0 || frame.hAnchor !== void 0 ? {
|
|
31
|
+
relativeTo: horizontalRelativeTo(frame.hAnchor),
|
|
32
|
+
...frame.x !== void 0 ? { posOffset: pixelsToEmu(frame.x) } : {},
|
|
33
|
+
...frame.xAlign !== void 0 ? { align: frame.xAlign } : {}
|
|
34
|
+
} : void 0;
|
|
35
|
+
const verticalAlign = frame.yAlign === "inline" ? void 0 : frame.yAlign;
|
|
36
|
+
const vertical = frame.y !== void 0 || verticalAlign !== void 0 || frame.vAnchor !== void 0 ? {
|
|
37
|
+
relativeTo: verticalRelativeTo(frame.vAnchor),
|
|
38
|
+
...frame.y !== void 0 ? { posOffset: pixelsToEmu(frame.y) } : {},
|
|
39
|
+
...verticalAlign !== void 0 ? { align: verticalAlign } : {}
|
|
40
|
+
} : void 0;
|
|
41
|
+
if (horizontal === void 0 && vertical === void 0) return;
|
|
42
|
+
return {
|
|
43
|
+
...horizontal !== void 0 ? { horizontal } : {},
|
|
44
|
+
...vertical !== void 0 ? { vertical } : {}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function frameWrapType(frame) {
|
|
48
|
+
switch (frame.wrap) {
|
|
49
|
+
case "notBeside": return "topAndBottom";
|
|
50
|
+
case "none": return "inFront";
|
|
51
|
+
case "through": return "through";
|
|
52
|
+
case "tight": return "tight";
|
|
53
|
+
case "around":
|
|
54
|
+
case "auto":
|
|
55
|
+
case void 0: return "square";
|
|
56
|
+
default:
|
|
57
|
+
frame.wrap;
|
|
58
|
+
return "square";
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function toFrameTextBox(content, frame, nextBlockId) {
|
|
62
|
+
const first = content.at(0);
|
|
63
|
+
const last = content.at(-1);
|
|
64
|
+
const textBox = {
|
|
65
|
+
kind: "textBox",
|
|
66
|
+
id: nextBlockId(),
|
|
67
|
+
width: frame.width ?? 200,
|
|
68
|
+
margins: {
|
|
69
|
+
top: 0,
|
|
70
|
+
right: 0,
|
|
71
|
+
bottom: 0,
|
|
72
|
+
left: 0
|
|
73
|
+
},
|
|
74
|
+
content,
|
|
75
|
+
displayMode: "float",
|
|
76
|
+
wrapType: frameWrapType(frame),
|
|
77
|
+
wrapText: "bothSides",
|
|
78
|
+
distTop: frame.vSpace ?? 0,
|
|
79
|
+
distBottom: frame.vSpace ?? 0,
|
|
80
|
+
distLeft: frame.hSpace ?? 0,
|
|
81
|
+
distRight: frame.hSpace ?? 0,
|
|
82
|
+
...first?.pmStart !== void 0 ? { pmStart: first.pmStart } : {},
|
|
83
|
+
...last?.pmEnd !== void 0 ? { pmEnd: last.pmEnd } : {}
|
|
84
|
+
};
|
|
85
|
+
if (frame.height !== void 0) textBox.height = frame.height;
|
|
86
|
+
const position = framePosition(frame);
|
|
87
|
+
if (position !== void 0) textBox.position = position;
|
|
88
|
+
markParagraphFrameTextBox(textBox);
|
|
89
|
+
return textBox;
|
|
90
|
+
}
|
|
91
|
+
function groupParagraphFrames(blocks, nextBlockId) {
|
|
92
|
+
const grouped = [];
|
|
93
|
+
let index = 0;
|
|
94
|
+
let activeFrameSetId;
|
|
95
|
+
while (index < blocks.length) {
|
|
96
|
+
const block = blocks[index];
|
|
97
|
+
if (block?.kind !== "paragraph") {
|
|
98
|
+
if (block) grouped.push(block);
|
|
99
|
+
activeFrameSetId = void 0;
|
|
100
|
+
index += 1;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const frame = getParagraphFrame(block);
|
|
104
|
+
if (frame === void 0) {
|
|
105
|
+
grouped.push(block);
|
|
106
|
+
if (block.runs.length > 0 || activeFrameSetId === void 0 || !hasFollowingParagraphFrame(blocks, index + 1)) activeFrameSetId = void 0;
|
|
107
|
+
index += 1;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
activeFrameSetId ??= `paragraph-frame-${block.pmStart ?? block.id}`;
|
|
111
|
+
const content = [];
|
|
112
|
+
while (index < blocks.length) {
|
|
113
|
+
const paragraph = blocks[index];
|
|
114
|
+
if (paragraph?.kind !== "paragraph") break;
|
|
115
|
+
const paragraphFrame = getParagraphFrame(paragraph);
|
|
116
|
+
if (paragraphFrame === void 0 || !framesEqual(frame, paragraphFrame)) break;
|
|
117
|
+
content.push(paragraph);
|
|
118
|
+
index += 1;
|
|
119
|
+
}
|
|
120
|
+
const textBox = toFrameTextBox(content, frame, nextBlockId);
|
|
121
|
+
setTextBoxGroupId(textBox, activeFrameSetId);
|
|
122
|
+
grouped.push(textBox);
|
|
123
|
+
}
|
|
124
|
+
return grouped;
|
|
125
|
+
}
|
|
126
|
+
function hasFollowingParagraphFrame(blocks, startIndex) {
|
|
127
|
+
for (let index = startIndex; index < blocks.length; index++) {
|
|
128
|
+
const block = blocks[index];
|
|
129
|
+
if (block?.kind !== "paragraph") return false;
|
|
130
|
+
if (getParagraphFrame(block) !== void 0) return true;
|
|
131
|
+
if (block.runs.length > 0) return false;
|
|
132
|
+
}
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
export { groupParagraphFrames };
|
|
@@ -6,12 +6,14 @@ import { resolveColor, resolveHighlightToCss } from "../../utils/colorResolver.j
|
|
|
6
6
|
import { resolveShadingFill } from "../../utils/formatToStyle.js";
|
|
7
7
|
import { convertBulletToUnicode } from "../../docx/bulletMarkers.js";
|
|
8
8
|
import { setTextBoxGroupId } from "../../layout-engine/textBoxGroup.js";
|
|
9
|
+
import { setParagraphFrame } from "../../layout-engine/paragraphFrame.js";
|
|
9
10
|
import { getColumns } from "../sectionColumns.js";
|
|
10
11
|
import { directionIsRtl } from "../../prosemirror/paragraphDirection.js";
|
|
11
12
|
import { expectBlockSdtAttrs, expectCharacterSpacingMarkAttrs, expectCommentMarkAttrs, expectEmphasisMarkAttrs, expectFieldAttrs, expectFontFamilyMarkAttrs, expectFontSizeMarkAttrs, expectFootnoteRefMarkAttrs, expectHardBreakAttrs, expectHighlightMarkAttrs, expectHyperlinkMarkAttrs, expectImageAttrs, expectMathAttrs, expectParagraphAttrs, expectRunFormattingOverrideMarkAttrs, expectRunShadingMarkAttrs, expectTableAttrs, expectTableCellAttrs, expectTableRowAttrs, expectTextBoxAttrs, expectTextColorMarkAttrs, expectTextEffectMarkAttrs, expectTrackedChangeMarkAttrs, expectUnderlineMarkAttrs } from "../../prosemirror/attrs/index.js";
|
|
12
13
|
import { autospacingMatchesBase } from "../../prosemirror/autospacingBase.js";
|
|
13
14
|
import { runShadingAttrsToShading } from "../../prosemirror/conversion/runShadingMark.js";
|
|
14
15
|
import { assertValidProseMirrorDocument } from "../../prosemirror/validation.js";
|
|
16
|
+
import { groupParagraphFrames } from "./paragraphFrames.js";
|
|
15
17
|
//#region src/layout-bridge/convert/toFlowBlocks.ts
|
|
16
18
|
const DEFAULT_FONT = "Calibri";
|
|
17
19
|
const DEFAULT_TABLE_CELL_MARGIN_TWIPS = {
|
|
@@ -613,6 +615,9 @@ function readNumberFormats(value) {
|
|
|
613
615
|
function readListMarkerSuffix(value) {
|
|
614
616
|
if (value === "tab" || value === "space" || value === "nothing") return value;
|
|
615
617
|
}
|
|
618
|
+
function readListMarkerAlignment(value) {
|
|
619
|
+
if (value === "left" || value === "center" || value === "right") return value;
|
|
620
|
+
}
|
|
616
621
|
function toPreviousListAttrs(previousFormatting) {
|
|
617
622
|
const attrs = {};
|
|
618
623
|
const numPr = previousFormatting["numPr"];
|
|
@@ -639,6 +644,8 @@ function toPreviousListAttrs(previousFormatting) {
|
|
|
639
644
|
if (typeof listMarkerFontFamily === "string") attrs.listMarkerFontFamily = listMarkerFontFamily;
|
|
640
645
|
const listMarkerFontSize = previousFormatting["listMarkerFontSize"];
|
|
641
646
|
if (typeof listMarkerFontSize === "number") attrs.listMarkerFontSize = listMarkerFontSize;
|
|
647
|
+
const listMarkerAlignment = readListMarkerAlignment(previousFormatting["listMarkerAlignment"]);
|
|
648
|
+
if (listMarkerAlignment) attrs.listMarkerAlignment = listMarkerAlignment;
|
|
642
649
|
const listMarkerSuffix = readListMarkerSuffix(previousFormatting["listMarkerSuffix"]);
|
|
643
650
|
if (listMarkerSuffix) attrs.listMarkerSuffix = listMarkerSuffix;
|
|
644
651
|
return attrs;
|
|
@@ -662,6 +669,7 @@ function applyDeletedListMarkerAttrs(attrs, change, listCounters, listAbstractCo
|
|
|
662
669
|
if (previousListAttrs.listMarkerHidden !== void 0) attrs.listMarkerHidden = previousListAttrs.listMarkerHidden;
|
|
663
670
|
if (previousListAttrs.listMarkerFontFamily) attrs.listMarkerFontFamily = previousListAttrs.listMarkerFontFamily;
|
|
664
671
|
if (previousListAttrs.listMarkerFontSize) attrs.listMarkerFontSize = previousListAttrs.listMarkerFontSize;
|
|
672
|
+
if (previousListAttrs.listMarkerAlignment) attrs.listMarkerAlignment = previousListAttrs.listMarkerAlignment;
|
|
665
673
|
if (previousListAttrs.listMarkerSuffix) attrs.listMarkerSuffix = previousListAttrs.listMarkerSuffix;
|
|
666
674
|
}
|
|
667
675
|
function convertParagraphAttrs(pmAttrs, theme, listCounters, listAbstractCounters, listSeenNumIds, defaultTabStopTwips, originalListCounters, originalListAbstractCounters, originalListSeenNumIds) {
|
|
@@ -793,6 +801,7 @@ function convertParagraphAttrs(pmAttrs, theme, listCounters, listAbstractCounter
|
|
|
793
801
|
if (pmAttrs.listMarkerHidden) attrs.listMarkerHidden = true;
|
|
794
802
|
if (pmAttrs.listMarkerFontFamily) attrs.listMarkerFontFamily = pmAttrs.listMarkerFontFamily;
|
|
795
803
|
if (pmAttrs.listMarkerFontSize) attrs.listMarkerFontSize = pmAttrs.listMarkerFontSize;
|
|
804
|
+
if (pmAttrs.listMarkerAlignment) attrs.listMarkerAlignment = pmAttrs.listMarkerAlignment;
|
|
796
805
|
if (pmAttrs.listMarkerSuffix) attrs.listMarkerSuffix = pmAttrs.listMarkerSuffix;
|
|
797
806
|
if (pmAttrs.listMarkerSecondSlotOffsetTwips !== void 0) attrs.listMarkerSecondSlotOffsetTwips = pmAttrs.listMarkerSecondSlotOffsetTwips;
|
|
798
807
|
if (!pmAttrs.numPr) {
|
|
@@ -836,6 +845,7 @@ function convertParagraph(node, startPos, options) {
|
|
|
836
845
|
if (runs.length === 0) {
|
|
837
846
|
if (pmAttrs._originalFormatting && Object.entries(pmAttrs._originalFormatting).some(([key, value]) => key !== "runProperties" && value !== void 0 && value !== null)) attrs.hasDirectParagraphFormatting = true;
|
|
838
847
|
const paragraphMarkFormatting = pmAttrs._originalFormatting?.runProperties;
|
|
848
|
+
if (paragraphMarkFormatting && Object.values(paragraphMarkFormatting).some((value) => value !== void 0 && value !== null)) attrs.hasDirectParagraphMarkFormatting = true;
|
|
839
849
|
if (paragraphMarkFormatting?.fontSize !== void 0) attrs.defaultFontSize = paragraphMarkFormatting.fontSize / 2;
|
|
840
850
|
const paragraphMarkFontFamily = paragraphMarkFormatting?.fontFamily?.ascii ?? paragraphMarkFormatting?.fontFamily?.hAnsi;
|
|
841
851
|
if (paragraphMarkFontFamily) attrs.defaultFontFamily = paragraphMarkFontFamily;
|
|
@@ -845,7 +855,7 @@ function convertParagraph(node, startPos, options) {
|
|
|
845
855
|
if (attrs.listMarker !== void 0) attrs.listMarkerHidden = true;
|
|
846
856
|
}
|
|
847
857
|
const bookmarkNames = pmAttrs.bookmarks?.map((b) => b.name);
|
|
848
|
-
|
|
858
|
+
const block = {
|
|
849
859
|
kind: "paragraph",
|
|
850
860
|
id: nextBlockId(),
|
|
851
861
|
runs,
|
|
@@ -855,6 +865,21 @@ function convertParagraph(node, startPos, options) {
|
|
|
855
865
|
pmStart: startPos,
|
|
856
866
|
pmEnd: startPos + node.nodeSize
|
|
857
867
|
};
|
|
868
|
+
const frame = pmAttrs._originalFormatting?.frame;
|
|
869
|
+
if (frame !== void 0 && frame.dropCap !== "drop" && frame.dropCap !== "margin") setParagraphFrame(block, {
|
|
870
|
+
...frame.width !== void 0 ? { width: twipsToPixels(frame.width) } : {},
|
|
871
|
+
...frame.height !== void 0 ? { height: twipsToPixels(frame.height) } : {},
|
|
872
|
+
...frame.hSpace !== void 0 ? { hSpace: twipsToPixels(frame.hSpace) } : {},
|
|
873
|
+
...frame.vSpace !== void 0 ? { vSpace: twipsToPixels(frame.vSpace) } : {},
|
|
874
|
+
...frame.hAnchor !== void 0 ? { hAnchor: frame.hAnchor } : {},
|
|
875
|
+
...frame.vAnchor !== void 0 ? { vAnchor: frame.vAnchor } : {},
|
|
876
|
+
...frame.x !== void 0 ? { x: twipsToPixels(frame.x) } : {},
|
|
877
|
+
...frame.y !== void 0 ? { y: twipsToPixels(frame.y) } : {},
|
|
878
|
+
...frame.xAlign !== void 0 ? { xAlign: frame.xAlign } : {},
|
|
879
|
+
...frame.yAlign !== void 0 ? { yAlign: frame.yAlign } : {},
|
|
880
|
+
...frame.wrap !== void 0 ? { wrap: frame.wrap } : {}
|
|
881
|
+
});
|
|
882
|
+
return block;
|
|
858
883
|
}
|
|
859
884
|
/**
|
|
860
885
|
* Word keeps terminal empty body paragraphs after a final table as editable
|
|
@@ -879,6 +904,16 @@ function suppressTerminalEmptyParagraphsAfterTable(blocks) {
|
|
|
879
904
|
};
|
|
880
905
|
}
|
|
881
906
|
}
|
|
907
|
+
function suppressFinalParagraphInRepeatedEmptySuffix(blocks) {
|
|
908
|
+
let suffixStart = blocks.length;
|
|
909
|
+
while (suffixStart > 0 && isPaintlessTerminalParagraph(blocks[suffixStart - 1])) suffixStart -= 1;
|
|
910
|
+
if (suffixStart === 0 || blocks.length - suffixStart < 2 || blocks[suffixStart - 1]?.kind === "table") return;
|
|
911
|
+
const finalBlock = blocks.at(-1);
|
|
912
|
+
if (isPaintlessTerminalParagraph(finalBlock)) finalBlock.attrs = {
|
|
913
|
+
...finalBlock.attrs,
|
|
914
|
+
suppressEmptyParagraphHeight: true
|
|
915
|
+
};
|
|
916
|
+
}
|
|
882
917
|
function reserveLeadingEmptyOutlineHeight(blocks) {
|
|
883
918
|
const firstBlock = blocks.at(0);
|
|
884
919
|
if (firstBlock?.kind !== "paragraph" || firstBlock.runs.length !== 0 || firstBlock.attrs?.outlineLevel !== 0) return;
|
|
@@ -983,7 +1018,7 @@ function convertTableCell(node, startPos, options, tableCellMargins) {
|
|
|
983
1018
|
};
|
|
984
1019
|
const cell = {
|
|
985
1020
|
id: nextBlockId(),
|
|
986
|
-
blocks,
|
|
1021
|
+
blocks: groupParagraphFrames(blocks, nextBlockId),
|
|
987
1022
|
colSpan: attrs.colspan,
|
|
988
1023
|
rowSpan: attrs.rowspan,
|
|
989
1024
|
padding
|
|
@@ -1011,6 +1046,8 @@ function convertTableRow(node, startPos, options, tableCellMargins) {
|
|
|
1011
1046
|
id: nextBlockId(),
|
|
1012
1047
|
cells
|
|
1013
1048
|
};
|
|
1049
|
+
if (attrs._originalFormatting?.gridBefore) row.gridBefore = attrs._originalFormatting.gridBefore;
|
|
1050
|
+
if (attrs._originalFormatting?.gridAfter) row.gridAfter = attrs._originalFormatting.gridAfter;
|
|
1014
1051
|
if (attrs.height) row.height = twipsToPixels(attrs.height);
|
|
1015
1052
|
if (attrs.heightRule) row.heightRule = attrs.heightRule;
|
|
1016
1053
|
if (attrs.isHeader) row.isHeader = attrs.isHeader;
|
|
@@ -1136,6 +1173,7 @@ function convertTextBoxNode(node, startPos, opts) {
|
|
|
1136
1173
|
pmEnd: startPos + node.nodeSize
|
|
1137
1174
|
};
|
|
1138
1175
|
if (attrs.height !== void 0) textBox.height = attrs.height;
|
|
1176
|
+
if (attrs.autoFit !== void 0) textBox.autoFit = attrs.autoFit;
|
|
1139
1177
|
if (attrs.fillColor !== void 0) textBox.fillColor = attrs.fillColor;
|
|
1140
1178
|
if (attrs.outlineWidth !== void 0) textBox.outlineWidth = attrs.outlineWidth;
|
|
1141
1179
|
if (attrs.outlineColor !== void 0) textBox.outlineColor = attrs.outlineColor;
|
|
@@ -1342,7 +1380,8 @@ function toFlowBlocks(doc, options = {}) {
|
|
|
1342
1380
|
});
|
|
1343
1381
|
reserveLeadingEmptyOutlineHeight(blocks);
|
|
1344
1382
|
suppressTerminalEmptyParagraphsAfterTable(blocks);
|
|
1345
|
-
|
|
1383
|
+
suppressFinalParagraphInRepeatedEmptySuffix(blocks);
|
|
1384
|
+
return groupParagraphFrames(mergeRunInParagraphs(blocks), nextBlockId);
|
|
1346
1385
|
}
|
|
1347
1386
|
/**
|
|
1348
1387
|
* Merge consecutive paragraph blocks where the first carries
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { measuredLineRangeHeight } from "../../layout-engine/lineFlow.js";
|
|
2
|
+
import { getTableRowLeadingWidth } from "../../layout-engine/types.js";
|
|
2
3
|
import { getHeaderRowsHeight } from "../../layout-engine/index.js";
|
|
3
4
|
//#region src/layout-bridge/engine/hitTest.ts
|
|
4
5
|
/**
|
|
@@ -213,7 +214,7 @@ function hitTestTableCell(pageHit, blocks, measures, pagePoint) {
|
|
|
213
214
|
const rowMeasure = tableMeasure.rows[rowIndex];
|
|
214
215
|
const row = tableBlock.rows[rowIndex];
|
|
215
216
|
if (!rowMeasure || !row) continue;
|
|
216
|
-
let colX =
|
|
217
|
+
let colX = getTableRowLeadingWidth(row, tableMeasure.columnWidths);
|
|
217
218
|
let colIndex = -1;
|
|
218
219
|
if (rowMeasure.cells.length === 0 || row.cells.length === 0) continue;
|
|
219
220
|
for (let c = 0; c < rowMeasure.cells.length; c++) {
|
|
@@ -2,6 +2,7 @@ import { measureRun } from "../../layout-engine/measure/measureProvider.js";
|
|
|
2
2
|
import { buildRunFontStyle } from "../../layout-engine/measure/measureHelpers.js";
|
|
3
3
|
import { inlineImageBoundingBox } from "../../utils/rotationBoundingBox.js";
|
|
4
4
|
import { measuredLineContentOffset } from "../../layout-engine/lineFlow.js";
|
|
5
|
+
import { getTableRowLeadingWidth } from "../../layout-engine/types.js";
|
|
5
6
|
import { measureParagraph } from "../../layout-engine/measure/measureParagraph.js";
|
|
6
7
|
import { buildTableCellFloatingZones, getTableCellContentWidth, getTableCellFloatingImages } from "../../layout-engine/measure/tableCellFloating.js";
|
|
7
8
|
import { getHeaderRowsHeight } from "../../layout-engine/index.js";
|
|
@@ -314,7 +315,7 @@ function selectionToRects(layout, blocks, measures, from, to) {
|
|
|
314
315
|
if (!row || !rowMeasure) continue;
|
|
315
316
|
const clipTop = tableFragment.topClip ?? 0;
|
|
316
317
|
const clipBottom = tableFragment.bottomClip ?? rowMeasure.height;
|
|
317
|
-
let cellX =
|
|
318
|
+
let cellX = getTableRowLeadingWidth(row, tableMeasure.columnWidths);
|
|
318
319
|
for (let cellIndex = 0; cellIndex < row.cells.length; cellIndex++) {
|
|
319
320
|
const cell = row.cells[cellIndex];
|
|
320
321
|
const cellMeasure = rowMeasure.cells[cellIndex];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
import { PageHeaderFooterRefs } from "./types.js";
|
|
3
|
+
|
|
4
|
+
//#region src/layout-engine/headerFooterRefs.d.ts
|
|
5
|
+
declare const resolveSectionHeaderFooterRefs: (documentModel: document_d_exports.Document | null | undefined) => PageHeaderFooterRefs[] | undefined;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { resolveSectionHeaderFooterRefs };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//#region src/layout-engine/headerFooterRefs.ts
|
|
2
|
+
const resolveSectionRefs = (props, inherited, documentEvenAndOddHeaders) => {
|
|
3
|
+
const refs = {
|
|
4
|
+
...inherited,
|
|
5
|
+
evenAndOddHeaders: props.evenAndOddHeaders ?? documentEvenAndOddHeaders
|
|
6
|
+
};
|
|
7
|
+
if (props.titlePg !== void 0) refs.titlePg = props.titlePg;
|
|
8
|
+
for (const ref of props.headerReferences ?? []) if (ref.type === "default") refs.headerDefault = ref.rId;
|
|
9
|
+
else if (ref.type === "first") refs.headerFirst = ref.rId;
|
|
10
|
+
else refs.headerEven = ref.rId;
|
|
11
|
+
for (const ref of props.footerReferences ?? []) if (ref.type === "default") refs.footerDefault = ref.rId;
|
|
12
|
+
else if (ref.type === "first") refs.footerFirst = ref.rId;
|
|
13
|
+
else refs.footerEven = ref.rId;
|
|
14
|
+
return refs;
|
|
15
|
+
};
|
|
16
|
+
const inheritedRefsFrom = (refs) => ({
|
|
17
|
+
...refs.headerDefault === void 0 ? {} : { headerDefault: refs.headerDefault },
|
|
18
|
+
...refs.headerFirst === void 0 ? {} : { headerFirst: refs.headerFirst },
|
|
19
|
+
...refs.headerEven === void 0 ? {} : { headerEven: refs.headerEven },
|
|
20
|
+
...refs.footerDefault === void 0 ? {} : { footerDefault: refs.footerDefault },
|
|
21
|
+
...refs.footerFirst === void 0 ? {} : { footerFirst: refs.footerFirst },
|
|
22
|
+
...refs.footerEven === void 0 ? {} : { footerEven: refs.footerEven }
|
|
23
|
+
});
|
|
24
|
+
const resolveSectionHeaderFooterRefs = (documentModel) => {
|
|
25
|
+
const body = documentModel?.package.document;
|
|
26
|
+
if (!body) return;
|
|
27
|
+
const sections = [];
|
|
28
|
+
if (body.sections && body.sections.length > 0) sections.push(...body.sections.map(({ properties }) => properties));
|
|
29
|
+
else if (body.finalSectionProperties) sections.push(body.finalSectionProperties);
|
|
30
|
+
if (sections.length === 0) return;
|
|
31
|
+
const documentEvenAndOddHeaders = documentModel.package.settings?.evenAndOddHeaders === true;
|
|
32
|
+
let inherited = {};
|
|
33
|
+
return sections.map((props) => {
|
|
34
|
+
const refs = resolveSectionRefs(props, inherited, documentEvenAndOddHeaders);
|
|
35
|
+
inherited = inheritedRefsFrom(refs);
|
|
36
|
+
return refs;
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
//#endregion
|
|
40
|
+
export { resolveSectionHeaderFooterRefs };
|
|
@@ -1,6 +1,7 @@
|
|
|
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, 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, 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
|
+
import { resolveSectionHeaderFooterRefs } from "./headerFooterRefs.js";
|
|
4
5
|
import { BreakDecision, SectionState, applyPendingToActive, createInitialSectionState, getEffectiveColumns, getEffectiveMargins, getEffectivePageSize, scheduleSectionBreak } from "./section-breaks.js";
|
|
5
6
|
import { assertExhaustiveFlowBlock, findPageIndexContainingPmPos } from "./pmPageIndex.js";
|
|
6
7
|
|
|
@@ -43,4 +44,4 @@ declare function layoutDocument(blocks: FlowBlock[], measures: Measure[], option
|
|
|
43
44
|
*/
|
|
44
45
|
declare function getHeaderRowsHeight(measure: TableMeasure, headerRowCount: number): number;
|
|
45
46
|
//#endregion
|
|
46
|
-
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, hasKeepLines, hasPageBreakBefore, isFloatingImageRun, isFloatingTextBoxBlock, isTextWrappingFloatingImageRun, layoutDocument, 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, 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 };
|