@stll/folio-core 0.49.0 → 0.50.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/headless.d.ts +37 -1
- package/dist/ai-edits/headless.js +47 -16
- package/dist/display-list/dom/renderDisplayListToDom.d.ts +10 -1
- package/dist/display-list/dom/renderDisplayListToDom.js +8 -7
- package/dist/display-list/html/renderDisplayListToHtml.d.ts +21 -0
- package/dist/display-list/html/renderDisplayListToHtml.js +126 -0
- package/dist/display-list/selectDisplayPages.d.ts +6 -0
- package/dist/display-list/selectDisplayPages.js +44 -0
- package/dist/export-pdf.d.ts +35 -2
- package/dist/export-pdf.js +51 -20
- package/dist/fonts/fontsourceFaces.d.ts +47 -0
- package/dist/fonts/fontsourceFaces.js +230 -0
- package/dist/layout-bridge/convert/flowBlockPostprocessing.d.ts +8 -0
- package/dist/layout-bridge/convert/flowBlockPostprocessing.js +106 -0
- package/dist/layout-bridge/convert/flowBorders.d.ts +17 -0
- package/dist/layout-bridge/convert/flowBorders.js +31 -0
- package/dist/layout-bridge/convert/flowConversionShared.d.ts +111 -0
- package/dist/layout-bridge/convert/flowConversionShared.js +23 -0
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +2 -1
- package/dist/layout-bridge/convert/footnoteLayout.js +2 -1
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +2 -1
- package/dist/layout-bridge/convert/imageConversion.d.ts +33 -0
- package/dist/layout-bridge/convert/imageConversion.js +118 -0
- package/dist/layout-bridge/convert/listMarkers.d.ts +28 -0
- package/dist/layout-bridge/convert/listMarkers.js +98 -0
- package/dist/layout-bridge/convert/noteReferences.d.ts +14 -0
- package/dist/layout-bridge/convert/noteReferences.js +29 -0
- package/dist/layout-bridge/convert/pageBreakSplitting.d.ts +16 -0
- package/dist/layout-bridge/convert/pageBreakSplitting.js +140 -0
- package/dist/layout-bridge/convert/paragraphAttrs.d.ts +20 -0
- package/dist/layout-bridge/convert/paragraphAttrs.js +234 -0
- package/dist/layout-bridge/convert/paragraphConversion.d.ts +12 -0
- package/dist/layout-bridge/convert/paragraphConversion.js +112 -0
- package/dist/layout-bridge/convert/paragraphRuns.d.ts +15 -0
- package/dist/layout-bridge/convert/paragraphRuns.js +281 -0
- package/dist/layout-bridge/convert/runFormattingMerge.d.ts +19 -0
- package/dist/layout-bridge/convert/runFormattingMerge.js +167 -0
- package/dist/layout-bridge/convert/runMarkFormatting.d.ts +11 -0
- package/dist/layout-bridge/convert/runMarkFormatting.js +291 -0
- package/dist/layout-bridge/convert/sectionBoundaries.d.ts +35 -0
- package/dist/layout-bridge/convert/sectionBoundaries.js +114 -0
- package/dist/layout-bridge/convert/tableConversion.d.ts +12 -0
- package/dist/layout-bridge/convert/tableConversion.js +303 -0
- package/dist/layout-bridge/convert/textBoxFill.d.ts +20 -0
- package/dist/layout-bridge/convert/textBoxFill.js +42 -0
- package/dist/layout-bridge/convert/textFormattingConversion.d.ts +22 -0
- package/dist/layout-bridge/convert/textFormattingConversion.js +120 -0
- package/dist/layout-bridge/convert/toFlowBlocks.d.ts +5 -113
- package/dist/layout-bridge/convert/toFlowBlocks.js +11 -2082
- package/dist/layout-bridge/engine/hitTest.js +1 -1
- package/dist/layout-bridge/engine/measuring/index.d.ts +2 -1
- package/dist/layout-bridge/engine/measuring/index.js +2 -1
- package/dist/layout-bridge/engine/selectionRects.js +1 -1
- package/dist/layout-engine/imageLayout.d.ts +9 -0
- package/dist/layout-engine/imageLayout.js +48 -0
- package/dist/layout-engine/index.d.ts +3 -18
- package/dist/layout-engine/index.js +12 -937
- package/dist/layout-engine/layoutFlowShared.d.ts +6 -0
- package/dist/layout-engine/layoutFlowShared.js +8 -0
- package/dist/layout-engine/measure/crossRunWords.d.ts +45 -0
- package/dist/layout-engine/measure/crossRunWords.js +172 -0
- package/dist/layout-engine/measure/floatingLineClearance.d.ts +24 -0
- package/dist/layout-engine/measure/floatingLineClearance.js +44 -0
- package/dist/layout-engine/measure/inlineObjectMetrics.d.ts +6 -0
- package/dist/layout-engine/measure/inlineObjectMetrics.js +52 -0
- package/dist/layout-engine/measure/justification.d.ts +32 -0
- package/dist/layout-engine/measure/justification.js +83 -0
- package/dist/layout-engine/measure/lineFitting.d.ts +48 -0
- package/dist/layout-engine/measure/lineFitting.js +145 -0
- package/dist/layout-engine/measure/lineTypography.d.ts +44 -0
- package/dist/layout-engine/measure/lineTypography.js +124 -0
- package/dist/layout-engine/measure/measureBlocks.js +2 -1
- package/dist/layout-engine/measure/measureParagraph.d.ts +1 -20
- package/dist/layout-engine/measure/measureParagraph.js +32 -734
- package/dist/layout-engine/measure/paragraphMeasureShared.d.ts +109 -0
- package/dist/layout-engine/measure/paragraphMeasureShared.js +82 -0
- package/dist/layout-engine/measure/paragraphTabs.d.ts +18 -0
- package/dist/layout-engine/measure/paragraphTabs.js +78 -0
- package/dist/layout-engine/paragraphLayout.d.ts +23 -0
- package/dist/layout-engine/paragraphLayout.js +204 -0
- package/dist/layout-engine/sectionLayout.d.ts +45 -0
- package/dist/layout-engine/sectionLayout.js +216 -0
- package/dist/layout-engine/tableLayout.d.ts +17 -0
- package/dist/layout-engine/tableLayout.js +369 -0
- package/dist/layout-engine/textBoxLayout.d.ts +15 -0
- package/dist/layout-engine/textBoxLayout.js +137 -0
- package/dist/layout-painter/renderPage.js +1 -0
- package/dist/paged-layout/sectionBlockWidths.d.ts +2 -1
- package/dist/paged-layout/sectionBlockWidths.js +1 -1
- package/dist/server.d.ts +3 -2
- package/package.json +2 -2
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { expectImageAttrs } from "../../prosemirror/attrs/index.js";
|
|
2
|
+
import { cssBorderStyleOf } from "../../utils/borderCss.js";
|
|
3
|
+
import { sanitizeImageSrc } from "../../utils/sanitizeImageSrc.js";
|
|
4
|
+
import { nextBlockId } from "./flowConversionShared.js";
|
|
5
|
+
//#region src/layout-bridge/convert/imageConversion.ts
|
|
6
|
+
/**
|
|
7
|
+
* Constrain image dimensions to fit within the page content area.
|
|
8
|
+
* Scales proportionally if height exceeds pageContentHeight.
|
|
9
|
+
*/
|
|
10
|
+
function constrainImageToPage(width, height, pageContentHeight) {
|
|
11
|
+
if (!pageContentHeight || height <= pageContentHeight) return {
|
|
12
|
+
width,
|
|
13
|
+
height
|
|
14
|
+
};
|
|
15
|
+
const scale = pageContentHeight / height;
|
|
16
|
+
return {
|
|
17
|
+
width: Math.round(width * scale),
|
|
18
|
+
height: pageContentHeight
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Build an ImageRun from ProseMirror node attrs, applying conditional property assignment
|
|
23
|
+
* to satisfy exactOptionalPropertyTypes.
|
|
24
|
+
*/
|
|
25
|
+
function buildImageRun(attrs, constrained, pmStart, pmEnd, trackedChange, forceLayoutInCell) {
|
|
26
|
+
const run = {
|
|
27
|
+
kind: "image",
|
|
28
|
+
src: attrs.src,
|
|
29
|
+
...attrs.preview ? { preview: attrs.preview } : {},
|
|
30
|
+
width: constrained.width,
|
|
31
|
+
height: constrained.height,
|
|
32
|
+
pmStart,
|
|
33
|
+
pmEnd
|
|
34
|
+
};
|
|
35
|
+
if (attrs.alt !== void 0) run.alt = attrs.alt;
|
|
36
|
+
if (attrs.transform !== void 0) run.transform = attrs.transform;
|
|
37
|
+
if (attrs.opacity != null) run.opacity = attrs.opacity;
|
|
38
|
+
if (attrs.brightness != null) run.brightness = attrs.brightness;
|
|
39
|
+
if (attrs.contrast != null) run.contrast = attrs.contrast;
|
|
40
|
+
if (attrs.wrapType !== void 0) run.wrapType = attrs.wrapType;
|
|
41
|
+
if (attrs.displayMode !== void 0) run.displayMode = attrs.displayMode;
|
|
42
|
+
if (attrs.cssFloat !== void 0) run.cssFloat = attrs.cssFloat;
|
|
43
|
+
if (attrs.distTop !== void 0) run.distTop = attrs.distTop;
|
|
44
|
+
if (attrs.distBottom !== void 0) run.distBottom = attrs.distBottom;
|
|
45
|
+
if (attrs.distLeft !== void 0) run.distLeft = attrs.distLeft;
|
|
46
|
+
if (attrs.distRight !== void 0) run.distRight = attrs.distRight;
|
|
47
|
+
if (attrs._docxObjectPreview === true) run.exactLineHeight = true;
|
|
48
|
+
if (attrs.cropTop != null) run.cropTop = attrs.cropTop;
|
|
49
|
+
if (attrs.cropRight != null) run.cropRight = attrs.cropRight;
|
|
50
|
+
if (attrs.cropBottom != null) run.cropBottom = attrs.cropBottom;
|
|
51
|
+
if (attrs.cropLeft != null) run.cropLeft = attrs.cropLeft;
|
|
52
|
+
if (attrs.borderWidth != null) run.borderWidth = attrs.borderWidth;
|
|
53
|
+
if (attrs.borderColor) run.borderColor = attrs.borderColor;
|
|
54
|
+
const runBorderStyle = cssBorderStyleOf(attrs.borderStyle);
|
|
55
|
+
if (runBorderStyle) run.borderStyle = runBorderStyle;
|
|
56
|
+
if (attrs.position !== void 0) run.position = attrs.position;
|
|
57
|
+
if (forceLayoutInCell) run.layoutInCell = true;
|
|
58
|
+
else if (attrs.anchor?.layoutInCell !== void 0) run.layoutInCell = attrs.anchor.layoutInCell;
|
|
59
|
+
if (trackedChange?.isInsertion) run.isInsertion = true;
|
|
60
|
+
if (trackedChange?.isDeletion) run.isDeletion = true;
|
|
61
|
+
if (trackedChange?.changeAuthor !== void 0) run.changeAuthor = trackedChange.changeAuthor;
|
|
62
|
+
if (trackedChange?.changeDate !== void 0) run.changeDate = trackedChange.changeDate;
|
|
63
|
+
if (trackedChange?.changeRevisionId !== void 0) run.changeRevisionId = trackedChange.changeRevisionId;
|
|
64
|
+
return run;
|
|
65
|
+
}
|
|
66
|
+
/** A package image whose bytes cannot paint still owns its authored line box. */
|
|
67
|
+
const hasRelationshipBackedImageBox = (attrs) => typeof attrs.rId === "string" && attrs.rId.trim().length > 0 && typeof attrs.width === "number" && Number.isFinite(attrs.width) && attrs.width >= 0 && typeof attrs.height === "number" && Number.isFinite(attrs.height) && attrs.height >= 0;
|
|
68
|
+
/**
|
|
69
|
+
* A preview counts as a source: the bytes are not in the attrs, but the
|
|
70
|
+
* display list can produce them without I/O when it interns the descriptor.
|
|
71
|
+
*/
|
|
72
|
+
const hasPaintableImageSource = (attrs) => attrs.preview !== void 0 || sanitizeImageSrc(attrs.src) !== void 0;
|
|
73
|
+
/**
|
|
74
|
+
* Convert an image node to an ImageBlock.
|
|
75
|
+
*/
|
|
76
|
+
function convertImage(node, startPos, pageContentHeight) {
|
|
77
|
+
const attrs = expectImageAttrs(node);
|
|
78
|
+
if (!hasPaintableImageSource(attrs) && !hasRelationshipBackedImageBox(attrs)) return;
|
|
79
|
+
const wrapType = attrs.wrapType;
|
|
80
|
+
const shouldAnchor = wrapType === "behind" || wrapType === "inFront";
|
|
81
|
+
const constrained = constrainImageToPage(attrs.width ?? 100, attrs.height ?? 100, pageContentHeight);
|
|
82
|
+
const imgBlock = {
|
|
83
|
+
kind: "image",
|
|
84
|
+
id: nextBlockId(),
|
|
85
|
+
src: attrs.src,
|
|
86
|
+
...attrs.preview ? { preview: attrs.preview } : {},
|
|
87
|
+
width: constrained.width,
|
|
88
|
+
height: constrained.height,
|
|
89
|
+
pmStart: startPos,
|
|
90
|
+
pmEnd: startPos + node.nodeSize
|
|
91
|
+
};
|
|
92
|
+
if (attrs.alt) imgBlock.alt = attrs.alt;
|
|
93
|
+
if (attrs.transform) imgBlock.transform = attrs.transform;
|
|
94
|
+
if (attrs.opacity != null) imgBlock.opacity = attrs.opacity;
|
|
95
|
+
if (attrs.brightness != null) imgBlock.brightness = attrs.brightness;
|
|
96
|
+
if (attrs.contrast != null) imgBlock.contrast = attrs.contrast;
|
|
97
|
+
if (shouldAnchor) {
|
|
98
|
+
const anchor = {
|
|
99
|
+
isAnchored: true,
|
|
100
|
+
behindDoc: wrapType === "behind"
|
|
101
|
+
};
|
|
102
|
+
if (attrs.distLeft !== void 0) anchor.offsetH = attrs.distLeft;
|
|
103
|
+
if (attrs.distTop !== void 0) anchor.offsetV = attrs.distTop;
|
|
104
|
+
imgBlock.anchor = anchor;
|
|
105
|
+
}
|
|
106
|
+
if (attrs.hlinkHref) imgBlock.hlinkHref = attrs.hlinkHref;
|
|
107
|
+
if (attrs.cropTop != null) imgBlock.cropTop = attrs.cropTop;
|
|
108
|
+
if (attrs.cropRight != null) imgBlock.cropRight = attrs.cropRight;
|
|
109
|
+
if (attrs.cropBottom != null) imgBlock.cropBottom = attrs.cropBottom;
|
|
110
|
+
if (attrs.cropLeft != null) imgBlock.cropLeft = attrs.cropLeft;
|
|
111
|
+
if (attrs.borderWidth != null) imgBlock.borderWidth = attrs.borderWidth;
|
|
112
|
+
if (attrs.borderColor) imgBlock.borderColor = attrs.borderColor;
|
|
113
|
+
const imageBorderStyle = cssBorderStyleOf(attrs.borderStyle);
|
|
114
|
+
if (imageBorderStyle) imgBlock.borderStyle = imageBorderStyle;
|
|
115
|
+
return imgBlock;
|
|
116
|
+
}
|
|
117
|
+
//#endregion
|
|
118
|
+
export { buildImageRun, constrainImageToPage, convertImage, hasPaintableImageSource, hasRelationshipBackedImageBox };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { document_d_exports } from "../../types/document.js";
|
|
2
|
+
import { ParagraphAttrs, ParagraphPropertyChangeAttrs } from "../../prosemirror/schema/nodes.js";
|
|
3
|
+
import { ParagraphAttrs as ParagraphAttrs$1 } from "../../layout-engine/types.js";
|
|
4
|
+
import { FontAlternates } from "../../fonts/fontAlternates.js";
|
|
5
|
+
import { ListCounterState } from "../../prosemirror/listMarker.js";
|
|
6
|
+
//#region src/layout-bridge/convert/listMarkers.d.ts
|
|
7
|
+
declare function applyMarkerAllCaps(marker: string | null, allCaps: boolean | undefined): string | null;
|
|
8
|
+
/**
|
|
9
|
+
* Convert PM paragraph attrs to layout engine paragraph attrs.
|
|
10
|
+
*/
|
|
11
|
+
type ListMarkerRevision = NonNullable<ParagraphAttrs$1["listMarkerRevision"]>;
|
|
12
|
+
type ListPropertyChange = ParagraphPropertyChangeAttrs;
|
|
13
|
+
type ListPropertyFormatting = NonNullable<ListPropertyChange["previousFormatting"]>;
|
|
14
|
+
declare function toListMarkerRevision(kind: ListMarkerRevision["kind"], info: ListPropertyChange["info"]): ListMarkerRevision;
|
|
15
|
+
declare function isAddedNumberingChange(change: ListPropertyChange): change is ListPropertyChange & {
|
|
16
|
+
previousFormatting: ListPropertyFormatting;
|
|
17
|
+
};
|
|
18
|
+
declare function isRemovedNumberingChange(change: ListPropertyChange): change is ListPropertyChange & {
|
|
19
|
+
previousFormatting: ListPropertyFormatting;
|
|
20
|
+
};
|
|
21
|
+
declare function isChangedNumberingChange(currentNumPr: NonNullable<ParagraphAttrs["numPr"]>, change: ListPropertyChange): change is ListPropertyChange & {
|
|
22
|
+
previousFormatting: ListPropertyFormatting;
|
|
23
|
+
};
|
|
24
|
+
declare function applyDeletedListMarkerAttrs(attrs: ParagraphAttrs$1, change: ListPropertyChange & {
|
|
25
|
+
previousFormatting: ListPropertyFormatting;
|
|
26
|
+
}, listCounterState: ListCounterState | undefined, theme: document_d_exports.Theme | null | undefined, fontAlternates: FontAlternates | undefined, paragraphMarkFormatting: () => document_d_exports.TextFormatting | undefined): void;
|
|
27
|
+
//#endregion
|
|
28
|
+
export { ListPropertyChange, ListPropertyFormatting, applyDeletedListMarkerAttrs, applyMarkerAllCaps, isAddedNumberingChange, isChangedNumberingChange, isRemovedNumberingChange, toListMarkerRevision };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { bulletMarkerFontName, convertBulletToUnicode } from "../../docx/bulletMarkers.js";
|
|
2
|
+
import { isListNumPr } from "../../layout-engine/types.js";
|
|
3
|
+
import { advanceListMarker } from "../../prosemirror/listMarker.js";
|
|
4
|
+
import { listMarkerFormattingFor } from "./textFormattingConversion.js";
|
|
5
|
+
import { sameStatedParagraphNumbering } from "@stll/docx-core/model";
|
|
6
|
+
//#region src/layout-bridge/convert/listMarkers.ts
|
|
7
|
+
/**
|
|
8
|
+
* List-marker resolution for paragraphs, including tracked numbering changes
|
|
9
|
+
* (inserted, removed, and changed list markers).
|
|
10
|
+
*/
|
|
11
|
+
function applyMarkerAllCaps(marker, allCaps) {
|
|
12
|
+
if (marker === null || !allCaps) return marker;
|
|
13
|
+
return marker.toLocaleUpperCase();
|
|
14
|
+
}
|
|
15
|
+
function computeListMarker(pmAttrs, state) {
|
|
16
|
+
return advanceListMarker(pmAttrs, state);
|
|
17
|
+
}
|
|
18
|
+
function toListMarkerRevision(kind, info) {
|
|
19
|
+
const revision = { kind };
|
|
20
|
+
if (typeof info?.author === "string") revision.author = info.author;
|
|
21
|
+
if (typeof info?.date === "string") revision.date = info.date;
|
|
22
|
+
if (typeof info?.id === "number") revision.revisionId = info.id;
|
|
23
|
+
return revision;
|
|
24
|
+
}
|
|
25
|
+
function isAddedNumberingChange(change) {
|
|
26
|
+
const previousFormatting = change.previousFormatting;
|
|
27
|
+
return previousFormatting != null && Object.hasOwn(previousFormatting, "numPr") && previousFormatting.numPr == null;
|
|
28
|
+
}
|
|
29
|
+
function isRemovedNumberingChange(change) {
|
|
30
|
+
const previousFormatting = change.previousFormatting;
|
|
31
|
+
return previousFormatting != null && Object.hasOwn(previousFormatting, "numPr") && isListNumPr(previousFormatting.numPr);
|
|
32
|
+
}
|
|
33
|
+
function isChangedNumberingChange(currentNumPr, change) {
|
|
34
|
+
const previousFormatting = change.previousFormatting;
|
|
35
|
+
return previousFormatting != null && Object.hasOwn(previousFormatting, "numPr") && isListNumPr(previousFormatting.numPr) && !sameStatedParagraphNumbering(previousFormatting.numPr, currentNumPr);
|
|
36
|
+
}
|
|
37
|
+
function toPreviousListAttrs(previousFormatting) {
|
|
38
|
+
const attrs = {};
|
|
39
|
+
const numPr = previousFormatting.numPr;
|
|
40
|
+
if (isListNumPr(numPr)) attrs.numPr = numPr;
|
|
41
|
+
const listIsBullet = previousFormatting.listIsBullet;
|
|
42
|
+
if (listIsBullet !== void 0) attrs.listIsBullet = listIsBullet;
|
|
43
|
+
const listIsLegal = previousFormatting.listIsLegal;
|
|
44
|
+
if (listIsLegal !== void 0) attrs.listIsLegal = listIsLegal;
|
|
45
|
+
const listMarker = previousFormatting.listMarker;
|
|
46
|
+
if (listMarker !== void 0) attrs.listMarker = listMarker;
|
|
47
|
+
const listMarkerTemplate = previousFormatting.listMarkerTemplate;
|
|
48
|
+
if (listMarkerTemplate !== void 0) attrs.listMarkerTemplate = listMarkerTemplate;
|
|
49
|
+
const listNumFmt = previousFormatting.listNumFmt;
|
|
50
|
+
if (listNumFmt !== void 0) attrs.listNumFmt = listNumFmt;
|
|
51
|
+
const listLevelNumFmts = previousFormatting.listLevelNumFmts;
|
|
52
|
+
if (listLevelNumFmts !== void 0) attrs.listLevelNumFmts = listLevelNumFmts;
|
|
53
|
+
const listLevelStarts = previousFormatting.listLevelStarts;
|
|
54
|
+
if (listLevelStarts !== void 0) attrs.listLevelStarts = listLevelStarts;
|
|
55
|
+
const listAbstractNumId = previousFormatting.listAbstractNumId;
|
|
56
|
+
if (listAbstractNumId !== void 0) attrs.listAbstractNumId = listAbstractNumId;
|
|
57
|
+
const listStartOverride = previousFormatting.listStartOverride;
|
|
58
|
+
if (listStartOverride !== void 0) attrs.listStartOverride = listStartOverride;
|
|
59
|
+
const listMarkerHidden = previousFormatting.listMarkerHidden;
|
|
60
|
+
if (listMarkerHidden !== void 0) attrs.listMarkerHidden = listMarkerHidden;
|
|
61
|
+
const listMarkerFormatting = previousFormatting.listMarkerFormatting;
|
|
62
|
+
if (listMarkerFormatting !== void 0) attrs.listMarkerFormatting = listMarkerFormatting;
|
|
63
|
+
const listMarkerAlignment = previousFormatting.listMarkerAlignment;
|
|
64
|
+
if (listMarkerAlignment !== void 0) attrs.listMarkerAlignment = listMarkerAlignment;
|
|
65
|
+
const listMarkerSuffix = previousFormatting.listMarkerSuffix;
|
|
66
|
+
if (listMarkerSuffix !== void 0) attrs.listMarkerSuffix = listMarkerSuffix;
|
|
67
|
+
const listMarkerAllCaps = previousFormatting.listMarkerAllCaps;
|
|
68
|
+
if (listMarkerAllCaps !== void 0) attrs.listMarkerAllCaps = listMarkerAllCaps;
|
|
69
|
+
const listImplicitChildLevelAdvances = previousFormatting.listImplicitChildLevelAdvances;
|
|
70
|
+
if (listImplicitChildLevelAdvances !== void 0) attrs.listImplicitChildLevelAdvances = listImplicitChildLevelAdvances;
|
|
71
|
+
const listMarkerSecondSlotOffsetTwips = previousFormatting.listMarkerSecondSlotOffsetTwips;
|
|
72
|
+
if (listMarkerSecondSlotOffsetTwips !== void 0) attrs.listMarkerSecondSlotOffsetTwips = listMarkerSecondSlotOffsetTwips;
|
|
73
|
+
return attrs;
|
|
74
|
+
}
|
|
75
|
+
function resolveDeletedListMarker(previousListAttrs, listCounterState) {
|
|
76
|
+
if (listCounterState && previousListAttrs.numPr) {
|
|
77
|
+
const marker = computeListMarker(previousListAttrs, listCounterState);
|
|
78
|
+
if (marker) return marker;
|
|
79
|
+
}
|
|
80
|
+
if (previousListAttrs.listMarker) return previousListAttrs.listIsBullet ? convertBulletToUnicode(previousListAttrs.listMarker, bulletMarkerFontName(previousListAttrs.listMarkerFormatting)) : previousListAttrs.listMarker;
|
|
81
|
+
if (previousListAttrs.listIsBullet) return "•";
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
function applyDeletedListMarkerAttrs(attrs, change, listCounterState, theme, fontAlternates, paragraphMarkFormatting) {
|
|
85
|
+
const previousListAttrs = toPreviousListAttrs(change.previousFormatting);
|
|
86
|
+
const marker = resolveDeletedListMarker(previousListAttrs, listCounterState);
|
|
87
|
+
if (!marker) return;
|
|
88
|
+
attrs.listMarker = marker;
|
|
89
|
+
attrs.listMarkerRevision = toListMarkerRevision("del", change.info);
|
|
90
|
+
if (previousListAttrs.listIsBullet !== void 0) attrs.listIsBullet = previousListAttrs.listIsBullet;
|
|
91
|
+
if (previousListAttrs.listMarkerHidden !== void 0) attrs.listMarkerHidden = previousListAttrs.listMarkerHidden;
|
|
92
|
+
const listMarkerFormatting = listMarkerFormattingFor(previousListAttrs.listMarkerFormatting, paragraphMarkFormatting(), theme, fontAlternates);
|
|
93
|
+
if (listMarkerFormatting) attrs.listMarkerFormatting = listMarkerFormatting;
|
|
94
|
+
if (previousListAttrs.listMarkerAlignment) attrs.listMarkerAlignment = previousListAttrs.listMarkerAlignment;
|
|
95
|
+
if (previousListAttrs.listMarkerSuffix) attrs.listMarkerSuffix = previousListAttrs.listMarkerSuffix;
|
|
96
|
+
}
|
|
97
|
+
//#endregion
|
|
98
|
+
export { applyDeletedListMarkerAttrs, applyMarkerAllCaps, isAddedNumberingChange, isChangedNumberingChange, isRemovedNumberingChange, toListMarkerRevision };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { FlowBlock } from "../../layout-engine/types.js";
|
|
2
|
+
//#region src/layout-bridge/convert/noteReferences.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Runs with `idKey` set, in document order: the note references a block list
|
|
5
|
+
* makes, through table cells (and tables within cells) and text boxes.
|
|
6
|
+
*/
|
|
7
|
+
declare function collectNoteRefs(blocks: readonly FlowBlock[], idKey: "footnoteRefId" | "endnoteRefId"): {
|
|
8
|
+
noteId: number;
|
|
9
|
+
pmPos: number;
|
|
10
|
+
}[];
|
|
11
|
+
/** Whether captured run-child markup is a note story's `w:footnoteRef`/`w:endnoteRef`. */
|
|
12
|
+
declare function isNoteReferenceMarkXml(xml: string): boolean;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { collectNoteRefs, isNoteReferenceMarkXml };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/layout-bridge/convert/noteReferences.ts
|
|
2
|
+
const NOTE_REFERENCE_MARK_XML = /^<(?:[^\s:/>]+:)?(?:footnoteRef|endnoteRef)[\s/>]/u;
|
|
3
|
+
/**
|
|
4
|
+
* Runs with `idKey` set, in document order: the note references a block list
|
|
5
|
+
* makes, through table cells (and tables within cells) and text boxes.
|
|
6
|
+
*/
|
|
7
|
+
function collectNoteRefs(blocks, idKey) {
|
|
8
|
+
const refs = [];
|
|
9
|
+
const walk = (containerBlocks) => {
|
|
10
|
+
for (const block of containerBlocks) if (block.kind === "paragraph") for (const run of block.runs) {
|
|
11
|
+
if (run.kind !== "text") continue;
|
|
12
|
+
const noteId = run[idKey];
|
|
13
|
+
if (noteId !== void 0) refs.push({
|
|
14
|
+
noteId,
|
|
15
|
+
pmPos: run.pmStart ?? 0
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
else if (block.kind === "table") for (const row of block.rows) for (const cell of row.cells) walk(cell.blocks);
|
|
19
|
+
else if (block.kind === "textBox") walk(block.content);
|
|
20
|
+
};
|
|
21
|
+
walk(blocks);
|
|
22
|
+
return refs;
|
|
23
|
+
}
|
|
24
|
+
/** Whether captured run-child markup is a note story's `w:footnoteRef`/`w:endnoteRef`. */
|
|
25
|
+
function isNoteReferenceMarkXml(xml) {
|
|
26
|
+
return NOTE_REFERENCE_MARK_XML.test(xml);
|
|
27
|
+
}
|
|
28
|
+
//#endregion
|
|
29
|
+
export { collectNoteRefs, isNoteReferenceMarkXml };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { PageBreakBlock, ParagraphBlock, Run } from "../../layout-engine/types.js";
|
|
2
|
+
import { PageBreakRunProjection } from "./paragraphRuns.js";
|
|
3
|
+
import { Node } from "prosemirror-model";
|
|
4
|
+
//#region src/layout-bridge/convert/pageBreakSplitting.d.ts
|
|
5
|
+
type SplitParagraphAtPageBreaksOptions = {
|
|
6
|
+
pageBreaks: readonly PageBreakRunProjection[];
|
|
7
|
+
paragraph: ParagraphBlock;
|
|
8
|
+
splitPageBreakAndParagraphMark: boolean;
|
|
9
|
+
};
|
|
10
|
+
/** Every page-break run under a node, nested tables and text boxes included. */
|
|
11
|
+
declare const countPageBreakRuns: (node: Node) => number;
|
|
12
|
+
/** Decide leading-break eligibility from the exact projected runs consumed by layout. */
|
|
13
|
+
declare const hasSingleLeadingProjectedPageBreak: (runs: readonly Run[], pageBreaks: readonly PageBreakRunProjection[]) => boolean;
|
|
14
|
+
declare function splitParagraphAtPageBreaks({ pageBreaks, paragraph, splitPageBreakAndParagraphMark }: SplitParagraphAtPageBreaksOptions): (ParagraphBlock | PageBreakBlock)[];
|
|
15
|
+
//#endregion
|
|
16
|
+
export { countPageBreakRuns, hasSingleLeadingProjectedPageBreak, splitParagraphAtPageBreaks };
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { partitionRunsAtPageBreaks } from "../../internal/pageBreakRunPartition.js";
|
|
2
|
+
import { nextBlockId } from "./flowConversionShared.js";
|
|
3
|
+
import { hasVisibleParagraphPayload } from "./paragraphConversion.js";
|
|
4
|
+
import { panic } from "better-result";
|
|
5
|
+
//#region src/layout-bridge/convert/pageBreakSplitting.ts
|
|
6
|
+
function paragraphFragmentAttrs(source, index, count) {
|
|
7
|
+
if (!source) return;
|
|
8
|
+
const attrs = {
|
|
9
|
+
...source,
|
|
10
|
+
...source.indent ? { indent: { ...source.indent } } : {},
|
|
11
|
+
...source.spacing ? { spacing: { ...source.spacing } } : {},
|
|
12
|
+
...source.automaticSpacing ? { automaticSpacing: { ...source.automaticSpacing } } : {},
|
|
13
|
+
...source.spacingExplicit ? { spacingExplicit: { ...source.spacingExplicit } } : {}
|
|
14
|
+
};
|
|
15
|
+
if (index > 0) {
|
|
16
|
+
delete attrs.listMarker;
|
|
17
|
+
delete attrs.listIsBullet;
|
|
18
|
+
delete attrs.listMarkerFormatting;
|
|
19
|
+
delete attrs.listMarkerHidden;
|
|
20
|
+
delete attrs.listMarkerAlignment;
|
|
21
|
+
delete attrs.listMarkerSuffix;
|
|
22
|
+
delete attrs.listMarkerRevision;
|
|
23
|
+
delete attrs.listMarkerSecondSlotOffsetTwips;
|
|
24
|
+
delete attrs.reserveEmptyOutlineHeight;
|
|
25
|
+
delete attrs.pageBreakBefore;
|
|
26
|
+
delete attrs.renderedPageBreakBefore;
|
|
27
|
+
if (attrs.indent) {
|
|
28
|
+
delete attrs.indent.firstLine;
|
|
29
|
+
delete attrs.indent.hanging;
|
|
30
|
+
}
|
|
31
|
+
if (attrs.spacing) delete attrs.spacing.before;
|
|
32
|
+
if (attrs.automaticSpacing) delete attrs.automaticSpacing.before;
|
|
33
|
+
if (attrs.spacingExplicit) delete attrs.spacingExplicit.before;
|
|
34
|
+
}
|
|
35
|
+
if (index < count - 1) {
|
|
36
|
+
delete attrs.keepNext;
|
|
37
|
+
delete attrs.runInWithNext;
|
|
38
|
+
delete attrs.listParagraphMarkFontSize;
|
|
39
|
+
if (attrs.spacing) delete attrs.spacing.after;
|
|
40
|
+
if (attrs.automaticSpacing) delete attrs.automaticSpacing.after;
|
|
41
|
+
if (attrs.spacingExplicit) delete attrs.spacingExplicit.after;
|
|
42
|
+
}
|
|
43
|
+
return attrs;
|
|
44
|
+
}
|
|
45
|
+
const runIsZeroWidthBoundaryMarker = (run) => {
|
|
46
|
+
switch (run.kind) {
|
|
47
|
+
case "text": return run.text.length === 0;
|
|
48
|
+
case "field": return (run.fallback ?? "").length === 0;
|
|
49
|
+
case "renderedPageBreak": return true;
|
|
50
|
+
case "image":
|
|
51
|
+
case "lineBreak":
|
|
52
|
+
case "math":
|
|
53
|
+
case "tab": return false;
|
|
54
|
+
default: return run;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
/** Every page-break run under a node, nested tables and text boxes included. */
|
|
58
|
+
const countPageBreakRuns = (node) => {
|
|
59
|
+
let count = node.type.name === "pageBreakRun" ? 1 : 0;
|
|
60
|
+
node.descendants((descendant) => {
|
|
61
|
+
if (descendant.type.name === "pageBreakRun") count += 1;
|
|
62
|
+
return true;
|
|
63
|
+
});
|
|
64
|
+
return count;
|
|
65
|
+
};
|
|
66
|
+
/** Decide leading-break eligibility from the exact projected runs consumed by layout. */
|
|
67
|
+
const hasSingleLeadingProjectedPageBreak = (runs, pageBreaks) => {
|
|
68
|
+
if (pageBreaks.length !== 1) return false;
|
|
69
|
+
const partitioned = partitionRunsAtPageBreaks(runs, pageBreaks);
|
|
70
|
+
if (partitioned.type === "overlap") return false;
|
|
71
|
+
return partitioned.partitions[0]?.before.every(runIsZeroWidthBoundaryMarker) === true;
|
|
72
|
+
};
|
|
73
|
+
function splitParagraphAtPageBreaks({ pageBreaks, paragraph, splitPageBreakAndParagraphMark }) {
|
|
74
|
+
if (pageBreaks.length === 0) return [paragraph];
|
|
75
|
+
const result = [];
|
|
76
|
+
let fragmentStart = paragraph.pmStart ?? pageBreaks[0].pmStart;
|
|
77
|
+
let emittedParagraph = false;
|
|
78
|
+
const appendParagraph = (runs, pmStart, pmEnd) => {
|
|
79
|
+
const fragment = {
|
|
80
|
+
...paragraph,
|
|
81
|
+
id: emittedParagraph ? nextBlockId() : paragraph.id,
|
|
82
|
+
runs,
|
|
83
|
+
pmStart,
|
|
84
|
+
pmEnd
|
|
85
|
+
};
|
|
86
|
+
if (emittedParagraph) delete fragment.bookmarks;
|
|
87
|
+
result.push(fragment);
|
|
88
|
+
emittedParagraph = true;
|
|
89
|
+
};
|
|
90
|
+
const partitioned = partitionRunsAtPageBreaks(paragraph.runs, pageBreaks);
|
|
91
|
+
if (partitioned.type === "overlap") panic("An inline layout run overlaps an explicit page-break carrier");
|
|
92
|
+
for (const { before, pageBreak } of partitioned.partitions) {
|
|
93
|
+
if (before.length > 0) appendParagraph(before, fragmentStart, pageBreak.pmStart);
|
|
94
|
+
result.push({
|
|
95
|
+
kind: "pageBreak",
|
|
96
|
+
id: nextBlockId(),
|
|
97
|
+
pmStart: pageBreak.pmStart,
|
|
98
|
+
pmEnd: pageBreak.pmEnd,
|
|
99
|
+
...pageBreak.trackedChange
|
|
100
|
+
});
|
|
101
|
+
fragmentStart = pageBreak.pmEnd;
|
|
102
|
+
}
|
|
103
|
+
const remainingRuns = partitioned.remaining;
|
|
104
|
+
let paragraphMarkCarrier;
|
|
105
|
+
if (remainingRuns.length > 0) appendParagraph(remainingRuns, fragmentStart, paragraph.pmEnd ?? fragmentStart);
|
|
106
|
+
else if (paragraph.runs.length === 0 || splitPageBreakAndParagraphMark && pageBreaks.at(-1)?.pmEnd === (paragraph.pmEnd ?? fragmentStart) - 1) {
|
|
107
|
+
appendParagraph([], fragmentStart, paragraph.pmEnd ?? fragmentStart);
|
|
108
|
+
const carrier = result.at(-1);
|
|
109
|
+
if (carrier?.kind === "paragraph" && !splitPageBreakAndParagraphMark && !hasVisibleParagraphPayload(carrier.attrs ?? {})) {
|
|
110
|
+
carrier.attrs = {
|
|
111
|
+
...carrier.attrs,
|
|
112
|
+
suppressEmptyParagraphHeight: true
|
|
113
|
+
};
|
|
114
|
+
paragraphMarkCarrier = carrier;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const fragments = result.filter((block) => block.kind === "paragraph");
|
|
118
|
+
for (let index = 0; index < fragments.length; index += 1) {
|
|
119
|
+
const fragment = fragments[index];
|
|
120
|
+
if (!fragment) continue;
|
|
121
|
+
const attrs = paragraphFragmentAttrs(fragment.attrs, index, fragments.length);
|
|
122
|
+
if (attrs) fragment.attrs = attrs;
|
|
123
|
+
else delete fragment.attrs;
|
|
124
|
+
}
|
|
125
|
+
if (paragraphMarkCarrier?.attrs) paragraphMarkCarrier.attrs = withoutParagraphSpacing(paragraphMarkCarrier.attrs);
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
function withoutParagraphSpacing(source) {
|
|
129
|
+
const attrs = { ...source };
|
|
130
|
+
if (attrs.spacing) {
|
|
131
|
+
const { before: _before, after: _after, ...lineSpacing } = attrs.spacing;
|
|
132
|
+
if (Object.keys(lineSpacing).length > 0) attrs.spacing = lineSpacing;
|
|
133
|
+
else delete attrs.spacing;
|
|
134
|
+
}
|
|
135
|
+
delete attrs.automaticSpacing;
|
|
136
|
+
delete attrs.spacingExplicit;
|
|
137
|
+
return attrs;
|
|
138
|
+
}
|
|
139
|
+
//#endregion
|
|
140
|
+
export { countPageBreakRuns, hasSingleLeadingProjectedPageBreak, splitParagraphAtPageBreaks };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { document_d_exports } from "../../types/document.js";
|
|
2
|
+
import { ParagraphAttrs } from "../../prosemirror/schema/nodes.js";
|
|
3
|
+
import { ParagraphAttrs as ParagraphAttrs$1 } from "../../layout-engine/types.js";
|
|
4
|
+
import { FontAlternates } from "../../fonts/fontAlternates.js";
|
|
5
|
+
import { ListCounterStreams } from "../../prosemirror/listMarker.js";
|
|
6
|
+
//#region src/layout-bridge/convert/paragraphAttrs.d.ts
|
|
7
|
+
type ConvertParagraphAttrsOptions = {
|
|
8
|
+
theme: document_d_exports.Theme | null | undefined;
|
|
9
|
+
fontAlternates: FontAlternates | undefined;
|
|
10
|
+
listCounterStreams: ListCounterStreams;
|
|
11
|
+
defaultTabStopTwips: number | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Resolved paragraph-mark run properties, the base of the list marker's
|
|
14
|
+
* typography. Lazy: only paragraphs that paint a marker resolve them.
|
|
15
|
+
*/
|
|
16
|
+
paragraphMarkFormatting: () => document_d_exports.TextFormatting | undefined;
|
|
17
|
+
};
|
|
18
|
+
declare function convertParagraphAttrs(pmAttrs: ParagraphAttrs, { theme, fontAlternates, listCounterStreams, defaultTabStopTwips, paragraphMarkFormatting }: ConvertParagraphAttrsOptions): ParagraphAttrs$1;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { convertParagraphAttrs };
|