@stll/folio-core 0.48.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/apply.js +565 -121
- package/dist/ai-edits/headless.d.ts +37 -1
- package/dist/ai-edits/headless.js +47 -16
- package/dist/ai-edits/minimal-replacement.d.ts +64 -0
- package/dist/ai-edits/minimal-replacement.js +282 -0
- package/dist/controller/layoutPipeline.js +11 -1
- package/dist/display-list/build/paragraphPrimitives.js +63 -7
- package/dist/display-list/build/textBoxPrimitives.js +1 -1
- package/dist/display-list/build/unsupported.d.ts +2 -2
- package/dist/display-list/build/unsupported.js +0 -0
- package/dist/display-list/dom/renderDisplayListToDom.d.ts +10 -1
- package/dist/display-list/dom/renderDisplayListToDom.js +8 -8
- 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/docx/blockContentParser.js +2 -2
- package/dist/docx/bulletMarkers.d.ts +18 -2
- package/dist/docx/bulletMarkers.js +27 -2
- package/dist/docx/drawingGroupChildren.d.ts +60 -0
- package/dist/docx/drawingGroupChildren.js +176 -0
- package/dist/docx/drawingUtils.js +3 -0
- package/dist/docx/groupDrawingParser.d.ts +7 -1
- package/dist/docx/groupDrawingParser.js +123 -32
- package/dist/docx/packageParts.d.ts +45 -1
- package/dist/docx/packageParts.js +93 -2
- package/dist/docx/paraIdAttribute.d.ts +3 -2
- package/dist/docx/paragraphParser.js +91 -7
- package/dist/docx/paragraphTextBoxEnrichment.js +126 -4
- package/dist/docx/runParser.js +10 -0
- package/dist/docx/selectiveSaveFlags.d.ts +10 -3
- package/dist/docx/selectiveSaveFlags.js +1 -1
- package/dist/docx/selectiveXmlPatch.d.ts +56 -34
- package/dist/docx/selectiveXmlPatch.js +222 -115
- package/dist/docx/serializer/groupTextBoxWriteBack.d.ts +12 -0
- package/dist/docx/serializer/groupTextBoxWriteBack.js +101 -0
- package/dist/docx/serializer/paragraphSerializer.js +5 -4
- package/dist/docx/serializer/runSerializer.d.ts +5 -1
- package/dist/docx/serializer/runSerializer.js +4 -3
- package/dist/docx/shapeAlternateContent.d.ts +25 -0
- package/dist/docx/shapeAlternateContent.js +52 -0
- package/dist/docx/textBoxParser.d.ts +10 -2
- package/dist/docx/textBoxParser.js +9 -3
- 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/internal/headlessRevisionResolution.js +50 -13
- 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 -2060
- 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 +4 -19
- package/dist/layout-engine/index.js +14 -910
- package/dist/layout-engine/keep-together.d.ts +5 -2
- package/dist/layout-engine/keep-together.js +5 -1
- package/dist/layout-engine/layoutFlowShared.d.ts +6 -0
- package/dist/layout-engine/layoutFlowShared.js +8 -0
- package/dist/layout-engine/measure/advanceComposition.js +49 -3
- 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 +7 -4
- package/dist/layout-engine/measure/measureContainer.js +46 -3
- package/dist/layout-engine/measure/measureHelpers.js +13 -3
- package/dist/layout-engine/measure/measureParagraph.d.ts +1 -20
- package/dist/layout-engine/measure/measureParagraph.js +41 -780
- 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/measure/smallCapsCasing.d.ts +56 -0
- package/dist/layout-engine/measure/smallCapsCasing.js +88 -0
- package/dist/layout-engine/paginator.d.ts +2 -0
- package/dist/layout-engine/paginator.js +5 -1
- package/dist/layout-engine/paragraphLayout.d.ts +23 -0
- package/dist/layout-engine/paragraphLayout.js +204 -0
- package/dist/layout-engine/paragraphSpacing.d.ts +4 -2
- package/dist/layout-engine/paragraphSpacing.js +2 -1
- 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/tableRowBreak.d.ts +8 -1
- package/dist/layout-engine/tableRowBreak.js +22 -1
- package/dist/layout-engine/textBoxLayout.d.ts +15 -0
- package/dist/layout-engine/textBoxLayout.js +137 -0
- package/dist/layout-engine/types.d.ts +21 -2
- package/dist/layout-painter/renderPage.js +1 -0
- package/dist/layout-painter/renderParagraph.js +41 -4
- package/dist/layout-painter/renderTextBox.d.ts +12 -2
- package/dist/layout-painter/renderTextBox.js +26 -2
- package/dist/paged-layout/sectionBlockWidths.d.ts +2 -1
- package/dist/paged-layout/sectionBlockWidths.js +1 -1
- package/dist/prosemirror/alternateContentAttrs.d.ts +9 -0
- package/dist/prosemirror/alternateContentAttrs.js +35 -0
- package/dist/prosemirror/attrs/index.js +90 -0
- package/dist/prosemirror/commands/comments.js +51 -41
- package/dist/prosemirror/contentControlRevisions.d.ts +43 -0
- package/dist/prosemirror/contentControlRevisions.js +84 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +46 -22
- package/dist/prosemirror/conversion/toProseDoc.js +42 -19
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.d.ts +7 -7
- package/dist/prosemirror/extensions/features/AutoBidiDetectionExtension.js +7 -7
- package/dist/prosemirror/extensions/nodes/FieldExtension.js +6 -3
- package/dist/prosemirror/extensions/nodes/SdtExtension.js +9 -2
- package/dist/prosemirror/extensions/nodes/ShapeExtension.js +1 -0
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +3 -0
- package/dist/prosemirror/listMarker.js +2 -2
- package/dist/prosemirror/paragraphDirection.d.ts +29 -2
- package/dist/prosemirror/paragraphDirection.js +21 -2
- package/dist/prosemirror/plugins/suggestionMode.js +37 -8
- package/dist/prosemirror/rejoinRunCarriers.d.ts +27 -0
- package/dist/prosemirror/rejoinRunCarriers.js +66 -0
- package/dist/prosemirror/runIdentityAcrossRevisions.d.ts +10 -0
- package/dist/prosemirror/runIdentityAcrossRevisions.js +90 -0
- package/dist/prosemirror/schema/nodes.d.ts +37 -5
- package/dist/server.d.ts +3 -2
- package/dist/types/content.d.ts +2 -2
- package/package.json +2 -2
- package/dist/layout-engine/justifiedLineFit.d.ts +0 -7
- package/dist/layout-engine/justifiedLineFit.js +0 -6
|
@@ -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 };
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { bulletMarkerFontName, convertBulletToUnicode } from "../../docx/bulletMarkers.js";
|
|
2
|
+
import { getFontAlternate } from "../../fonts/fontAlternates.js";
|
|
3
|
+
import { autospacingMatchesBase } from "../../prosemirror/autospacingBase.js";
|
|
4
|
+
import { advanceVisibleListMarker } from "../../prosemirror/listMarker.js";
|
|
5
|
+
import { directionIsRtl, directionToBidi } from "../../prosemirror/paragraphDirection.js";
|
|
6
|
+
import { mergeParagraphTabStops } from "../../utils/paragraphFormattingMerge.js";
|
|
7
|
+
import { AUTO_PARAGRAPH_SPACING_PX } from "../../utils/units.js";
|
|
8
|
+
import { convertBorderSpecToLayout } from "./flowBorders.js";
|
|
9
|
+
import { twipsToPixels } from "./flowConversionShared.js";
|
|
10
|
+
import { applyDeletedListMarkerAttrs, applyMarkerAllCaps, isAddedNumberingChange, isChangedNumberingChange, isRemovedNumberingChange, toListMarkerRevision } from "./listMarkers.js";
|
|
11
|
+
import { listMarkerFormattingFor, resolveWesternThemeFont } from "./textFormattingConversion.js";
|
|
12
|
+
import { paragraphNumberingLevel, paragraphNumberingReferenceId } from "@stll/docx-core/model";
|
|
13
|
+
//#region src/layout-bridge/convert/paragraphAttrs.ts
|
|
14
|
+
/**
|
|
15
|
+
* Converts ProseMirror paragraph attributes to layout ParagraphAttrs:
|
|
16
|
+
* alignment, spacing, indentation, borders, tab stops, and list markers.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Every `ST_Jc` member, and the flow alignment that paints it.
|
|
20
|
+
*
|
|
21
|
+
* `start` and `end` stay unresolved here: they name an edge of the writing
|
|
22
|
+
* direction, not a side of the page, so which of `left` and `right` paints
|
|
23
|
+
* them depends on the paragraph's direction. `numTab` has no flow alignment at
|
|
24
|
+
* all — it aligns the paragraph to the list number's tab stop, which the flow
|
|
25
|
+
* engine does not model — so it falls back to the start edge, which is where a
|
|
26
|
+
* numbered paragraph without one sits.
|
|
27
|
+
*/
|
|
28
|
+
const FLOW_ALIGNMENT_BY_PARAGRAPH_ALIGNMENT = {
|
|
29
|
+
start: "start",
|
|
30
|
+
end: "end",
|
|
31
|
+
numTab: "start",
|
|
32
|
+
left: "left",
|
|
33
|
+
center: "center",
|
|
34
|
+
right: "right",
|
|
35
|
+
both: "justify",
|
|
36
|
+
distribute: "justify",
|
|
37
|
+
mediumKashida: "justify",
|
|
38
|
+
highKashida: "justify",
|
|
39
|
+
lowKashida: "justify",
|
|
40
|
+
thaiDistribute: "justify"
|
|
41
|
+
};
|
|
42
|
+
/** Resolve a logical alignment against the direction the paragraph runs in. */
|
|
43
|
+
const resolveFlowAlignment = (alignment, rightToLeft) => {
|
|
44
|
+
const flow = FLOW_ALIGNMENT_BY_PARAGRAPH_ALIGNMENT[alignment];
|
|
45
|
+
switch (flow) {
|
|
46
|
+
case "start": return rightToLeft ? "right" : "left";
|
|
47
|
+
case "end": return rightToLeft ? "left" : "right";
|
|
48
|
+
default: return flow;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
function convertParagraphAttrs(pmAttrs, { theme, fontAlternates, listCounterStreams, defaultTabStopTwips, paragraphMarkFormatting }) {
|
|
52
|
+
const attrs = {};
|
|
53
|
+
if (pmAttrs.alignment) attrs.alignment = resolveFlowAlignment(pmAttrs.alignment, directionIsRtl(pmAttrs.direction));
|
|
54
|
+
if (pmAttrs.outlineLevel !== void 0) attrs.outlineLevel = pmAttrs.outlineLevel;
|
|
55
|
+
const spaceBefore = pmAttrs.spaceBefore;
|
|
56
|
+
const spaceAfter = pmAttrs.spaceAfter;
|
|
57
|
+
const lineSpacing = pmAttrs.lineSpacing;
|
|
58
|
+
if (typeof pmAttrs.snapToGrid === "boolean") attrs.snapToGrid = pmAttrs.snapToGrid;
|
|
59
|
+
const autoBefore = autospacingMatchesBase(pmAttrs._autospacingBase, "before", spaceBefore);
|
|
60
|
+
const autoAfter = autospacingMatchesBase(pmAttrs._autospacingBase, "after", spaceAfter);
|
|
61
|
+
if (autoBefore || autoAfter || typeof spaceBefore === "number" || typeof spaceAfter === "number" || typeof lineSpacing === "number") {
|
|
62
|
+
attrs.spacing = {};
|
|
63
|
+
if (autoBefore) attrs.spacing.before = AUTO_PARAGRAPH_SPACING_PX;
|
|
64
|
+
else if (typeof spaceBefore === "number") attrs.spacing.before = twipsToPixels(spaceBefore);
|
|
65
|
+
if (autoAfter) attrs.spacing.after = AUTO_PARAGRAPH_SPACING_PX;
|
|
66
|
+
else if (typeof spaceAfter === "number") attrs.spacing.after = twipsToPixels(spaceAfter);
|
|
67
|
+
if (autoBefore || autoAfter) attrs.automaticSpacing = {
|
|
68
|
+
...autoBefore ? { before: true } : {},
|
|
69
|
+
...autoAfter ? { after: true } : {}
|
|
70
|
+
};
|
|
71
|
+
const pmSpacingExplicit = pmAttrs.spacingExplicit;
|
|
72
|
+
const spacingFromDocDefaults = pmAttrs.spacingFromDocDefaults;
|
|
73
|
+
const spacingFromImplicitDefaultStyle = pmAttrs.spacingFromImplicitDefaultStyle;
|
|
74
|
+
const explicit = {};
|
|
75
|
+
if (autoBefore || pmSpacingExplicit?.before || spacingFromDocDefaults?.before || spacingFromImplicitDefaultStyle?.before) explicit.before = true;
|
|
76
|
+
if (autoAfter || pmSpacingExplicit?.after || spacingFromDocDefaults?.after || spacingFromImplicitDefaultStyle?.after) explicit.after = true;
|
|
77
|
+
if (explicit.before !== void 0 || explicit.after !== void 0) attrs.spacingExplicit = explicit;
|
|
78
|
+
if (typeof lineSpacing === "number") if (pmAttrs.lineSpacingRule === "exact" || pmAttrs.lineSpacingRule === "atLeast") {
|
|
79
|
+
attrs.spacing.line = twipsToPixels(lineSpacing);
|
|
80
|
+
attrs.spacing.lineUnit = "px";
|
|
81
|
+
attrs.spacing.lineRule = pmAttrs.lineSpacingRule;
|
|
82
|
+
} else {
|
|
83
|
+
attrs.spacing.line = lineSpacing / 240;
|
|
84
|
+
attrs.spacing.lineUnit = "multiplier";
|
|
85
|
+
attrs.spacing.lineRule = "auto";
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
let indentLeft = typeof pmAttrs.indentLeft === "number" ? pmAttrs.indentLeft : void 0;
|
|
89
|
+
let indentFirstLine = typeof pmAttrs.indentFirstLine === "number" ? pmAttrs.indentFirstLine : void 0;
|
|
90
|
+
let hangingIndent = pmAttrs.hangingIndent;
|
|
91
|
+
if (paragraphNumberingReferenceId(pmAttrs.numPr) !== void 0 && indentLeft === void 0 && indentFirstLine === void 0) {
|
|
92
|
+
indentLeft = ((paragraphNumberingLevel(pmAttrs.numPr) ?? 0) + 1) * 720;
|
|
93
|
+
if (indentFirstLine === void 0) {
|
|
94
|
+
indentFirstLine = -360;
|
|
95
|
+
hangingIndent = true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (indentLeft !== void 0 || typeof pmAttrs.indentRight === "number" || indentFirstLine !== void 0) {
|
|
99
|
+
attrs.indent = {};
|
|
100
|
+
if (indentLeft !== void 0) attrs.indent.left = twipsToPixels(indentLeft);
|
|
101
|
+
if (typeof pmAttrs.indentRight === "number") attrs.indent.right = twipsToPixels(pmAttrs.indentRight);
|
|
102
|
+
if (indentFirstLine !== void 0) if (hangingIndent) attrs.indent.hanging = Math.abs(twipsToPixels(indentFirstLine));
|
|
103
|
+
else attrs.indent.firstLine = twipsToPixels(indentFirstLine);
|
|
104
|
+
}
|
|
105
|
+
if (pmAttrs.styleId) attrs.styleId = pmAttrs.styleId;
|
|
106
|
+
if (pmAttrs.borders) {
|
|
107
|
+
const borders = pmAttrs.borders;
|
|
108
|
+
attrs.borders = {};
|
|
109
|
+
const convertBorder = (border) => border ? convertBorderSpecToLayout(border, theme) : void 0;
|
|
110
|
+
const topBorder = borders.top ? convertBorder(borders.top) : void 0;
|
|
111
|
+
if (topBorder) attrs.borders.top = topBorder;
|
|
112
|
+
const bottomBorder = borders.bottom ? convertBorder(borders.bottom) : void 0;
|
|
113
|
+
if (bottomBorder) attrs.borders.bottom = bottomBorder;
|
|
114
|
+
const leftBorder = borders.left ? convertBorder(borders.left) : void 0;
|
|
115
|
+
if (leftBorder) attrs.borders.left = leftBorder;
|
|
116
|
+
const rightBorder = borders.right ? convertBorder(borders.right) : void 0;
|
|
117
|
+
if (rightBorder) attrs.borders.right = rightBorder;
|
|
118
|
+
const betweenBorder = borders.between ? convertBorder(borders.between) : void 0;
|
|
119
|
+
if (betweenBorder) attrs.borders.between = betweenBorder;
|
|
120
|
+
const barBorder = borders.bar ? convertBorder(borders.bar) : void 0;
|
|
121
|
+
if (barBorder) attrs.borders.bar = barBorder;
|
|
122
|
+
if (!attrs.borders.top && !attrs.borders.bottom && !attrs.borders.left && !attrs.borders.right && !attrs.borders.between && !attrs.borders.bar) delete attrs.borders;
|
|
123
|
+
}
|
|
124
|
+
const shadingRgb = pmAttrs.shading?.fill?.rgb?.toUpperCase();
|
|
125
|
+
if (shadingRgb && shadingRgb !== "FFFFFF" && shadingRgb !== "FFFFFE") attrs.shading = `#${pmAttrs.shading?.fill?.rgb}`;
|
|
126
|
+
const tabs = mergeParagraphTabStops(pmAttrs.listLevelTabs ?? void 0, pmAttrs.tabs ?? void 0);
|
|
127
|
+
if (tabs && tabs.length > 0) {
|
|
128
|
+
const rightToLeft = directionIsRtl(pmAttrs.direction);
|
|
129
|
+
attrs.tabs = tabs.map((tab) => {
|
|
130
|
+
const tabStop = {
|
|
131
|
+
val: resolveTabAlignment(tab.alignment, rightToLeft),
|
|
132
|
+
pos: tab.position
|
|
133
|
+
};
|
|
134
|
+
if (tab.leader) tabStop.leader = tab.leader;
|
|
135
|
+
return tabStop;
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
if (pmAttrs.pageBreakBefore) attrs.pageBreakBefore = true;
|
|
139
|
+
if (pmAttrs.kinsoku !== void 0 && pmAttrs.kinsoku !== null) attrs.kinsoku = pmAttrs.kinsoku;
|
|
140
|
+
if (pmAttrs.overflowPunctuation !== void 0 && pmAttrs.overflowPunctuation !== null) attrs.overflowPunctuation = pmAttrs.overflowPunctuation;
|
|
141
|
+
if (pmAttrs.suppressAutoHyphens !== void 0 && pmAttrs.suppressAutoHyphens !== null) attrs.suppressAutoHyphens = pmAttrs.suppressAutoHyphens;
|
|
142
|
+
if (pmAttrs.renderedPageBreakBefore) attrs.renderedPageBreakBefore = true;
|
|
143
|
+
if (pmAttrs.keepNext) attrs.keepNext = true;
|
|
144
|
+
if (pmAttrs.keepLines) attrs.keepLines = true;
|
|
145
|
+
if (pmAttrs.widowControl === false) attrs.widowControl = false;
|
|
146
|
+
if (pmAttrs.contextualSpacing) attrs.contextualSpacing = true;
|
|
147
|
+
if (pmAttrs.runInWithNext) attrs.runInWithNext = true;
|
|
148
|
+
const bidi = directionToBidi(pmAttrs.direction);
|
|
149
|
+
if (bidi !== void 0) attrs.bidi = bidi;
|
|
150
|
+
if (pmAttrs.styleId) attrs.styleId = pmAttrs.styleId;
|
|
151
|
+
const propertyChanges = pmAttrs._propertyChanges ?? [];
|
|
152
|
+
let changedNumberingChange;
|
|
153
|
+
if (pmAttrs.numPr) {
|
|
154
|
+
attrs.numPr = pmAttrs.numPr;
|
|
155
|
+
if (pmAttrs.pPrMark?.kind === "del") attrs.listMarkerRevision = toListMarkerRevision("del", pmAttrs.pPrMark.info);
|
|
156
|
+
else if (pmAttrs.pPrMark?.kind === "ins") attrs.listMarkerRevision = toListMarkerRevision("ins", pmAttrs.pPrMark.info);
|
|
157
|
+
else {
|
|
158
|
+
const numberingAddedChange = propertyChanges.find(isAddedNumberingChange);
|
|
159
|
+
const currentNumPr = pmAttrs.numPr;
|
|
160
|
+
changedNumberingChange = propertyChanges.find((change) => isChangedNumberingChange(currentNumPr, change));
|
|
161
|
+
const numberingInsertionChange = numberingAddedChange ?? changedNumberingChange;
|
|
162
|
+
if (numberingInsertionChange) attrs.listMarkerRevision = toListMarkerRevision("ins", numberingInsertionChange.info);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const resolvedMarker = applyMarkerAllCaps(advanceVisibleListMarker(pmAttrs, listCounterStreams).marker, pmAttrs.listMarkerAllCaps);
|
|
166
|
+
if (resolvedMarker !== null) attrs.listMarker = resolvedMarker;
|
|
167
|
+
else if (pmAttrs.listMarker) attrs.listMarker = pmAttrs.listIsBullet ? convertBulletToUnicode(pmAttrs.listMarker, bulletMarkerFontName(pmAttrs.listMarkerFormatting)) : pmAttrs.listMarker;
|
|
168
|
+
if (pmAttrs.listIsBullet !== void 0) attrs.listIsBullet = pmAttrs.listIsBullet;
|
|
169
|
+
if (pmAttrs.listMarkerHidden) attrs.listMarkerHidden = true;
|
|
170
|
+
if (attrs.listMarker !== void 0 || pmAttrs.listMarkerFormatting) {
|
|
171
|
+
const listMarkerFormatting = listMarkerFormattingFor(pmAttrs.listMarkerFormatting, paragraphMarkFormatting(), theme, fontAlternates);
|
|
172
|
+
if (listMarkerFormatting) attrs.listMarkerFormatting = listMarkerFormatting;
|
|
173
|
+
}
|
|
174
|
+
if (pmAttrs.listMarkerAlignment) attrs.listMarkerAlignment = pmAttrs.listMarkerAlignment;
|
|
175
|
+
if (pmAttrs.listMarkerSuffix) attrs.listMarkerSuffix = pmAttrs.listMarkerSuffix;
|
|
176
|
+
if (pmAttrs.listMarkerSecondSlotOffsetTwips !== void 0) attrs.listMarkerSecondSlotOffsetTwips = pmAttrs.listMarkerSecondSlotOffsetTwips;
|
|
177
|
+
if (!pmAttrs.numPr) {
|
|
178
|
+
const numberingRemovedChange = propertyChanges.find(isRemovedNumberingChange);
|
|
179
|
+
if (numberingRemovedChange) {
|
|
180
|
+
applyDeletedListMarkerAttrs(attrs, numberingRemovedChange, void 0, theme, fontAlternates, paragraphMarkFormatting);
|
|
181
|
+
if (resolvedMarker !== null) {
|
|
182
|
+
attrs.listMarker = resolvedMarker;
|
|
183
|
+
attrs.listMarkerRevision = toListMarkerRevision("del", numberingRemovedChange.info);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (defaultTabStopTwips !== void 0) attrs.defaultTabStopTwips = defaultTabStopTwips;
|
|
188
|
+
const dtf = pmAttrs.defaultTextFormatting;
|
|
189
|
+
if (dtf) {
|
|
190
|
+
if (dtf.fontSize !== void 0) attrs.defaultFontSize = dtf.fontSize / 2;
|
|
191
|
+
if (attrs.listMarker !== void 0 && !attrs.listMarkerHidden && (attrs.bidi === true || dtf.rtl === true || dtf.cs === true) && dtf.fontSizeCs !== void 0 && (dtf.fontSize === void 0 || dtf.fontSizeCs > dtf.fontSize)) attrs.listParagraphMarkFontSize = dtf.fontSizeCs / 2;
|
|
192
|
+
if (dtf.fontFamily) {
|
|
193
|
+
const resolvedFamily = resolveWesternThemeFont(dtf.fontFamily, theme);
|
|
194
|
+
if (resolvedFamily) {
|
|
195
|
+
attrs.defaultFontFamily = resolvedFamily;
|
|
196
|
+
const alternate = getFontAlternate(resolvedFamily, fontAlternates);
|
|
197
|
+
if (alternate) attrs.defaultAlternateFontFamily = alternate;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return attrs;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Every `ST_TabJc` member, and the layout engine's name for it.
|
|
205
|
+
*
|
|
206
|
+
* The engine's `start` and `end` are its names for the left and right edges of
|
|
207
|
+
* the line, not direction-aware ones, so `w:tab w:val="left"` maps to `start`
|
|
208
|
+
* unconditionally. `ST_TabJc`'s own `start` and `end` *are* direction-aware
|
|
209
|
+
* and stay unresolved here, under names the engine has no member for.
|
|
210
|
+
* `num`, the tab a numbered paragraph's text hangs from, has no engine
|
|
211
|
+
* alignment of its own and falls back to the line's start edge.
|
|
212
|
+
*/
|
|
213
|
+
const TAB_ALIGNMENT_BY_TAB_STOP_ALIGNMENT = {
|
|
214
|
+
start: "logicalStart",
|
|
215
|
+
end: "logicalEnd",
|
|
216
|
+
num: "logicalStart",
|
|
217
|
+
left: "start",
|
|
218
|
+
right: "end",
|
|
219
|
+
center: "center",
|
|
220
|
+
decimal: "decimal",
|
|
221
|
+
bar: "bar",
|
|
222
|
+
clear: "clear"
|
|
223
|
+
};
|
|
224
|
+
/** Resolve a logical tab alignment against the direction the paragraph runs in. */
|
|
225
|
+
const resolveTabAlignment = (alignment, rightToLeft) => {
|
|
226
|
+
const mapped = TAB_ALIGNMENT_BY_TAB_STOP_ALIGNMENT[alignment];
|
|
227
|
+
switch (mapped) {
|
|
228
|
+
case "logicalStart": return rightToLeft ? "end" : "start";
|
|
229
|
+
case "logicalEnd": return rightToLeft ? "start" : "end";
|
|
230
|
+
default: return mapped;
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
//#endregion
|
|
234
|
+
export { convertParagraphAttrs };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ParagraphAttrs } from "../../prosemirror/schema/nodes.js";
|
|
2
|
+
import { ParagraphAttrs as ParagraphAttrs$1, ParagraphBlock } from "../../layout-engine/types.js";
|
|
3
|
+
import { FlowConversionOptions } from "./flowConversionShared.js";
|
|
4
|
+
import { PageBreakRunProjection } from "./paragraphRuns.js";
|
|
5
|
+
import { Node } from "prosemirror-model";
|
|
6
|
+
//#region src/layout-bridge/convert/paragraphConversion.d.ts
|
|
7
|
+
declare function hasVisibleParagraphPayload(attrs: ParagraphAttrs$1): boolean;
|
|
8
|
+
/** Whether any `w:pBdr` side draws a rule (`none`/`nil` sides draw nothing). */
|
|
9
|
+
declare function drawsParagraphBorder(borders: ParagraphAttrs["borders"]): boolean;
|
|
10
|
+
declare function convertParagraph(node: Node, startPos: number, options: FlowConversionOptions, pageBreaks?: PageBreakRunProjection[]): ParagraphBlock;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { convertParagraph, drawsParagraphBorder, hasVisibleParagraphPayload };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { getFontAlternate } from "../../fonts/fontAlternates.js";
|
|
2
|
+
import { setParagraphFrame } from "../../layout-engine/paragraphFrame.js";
|
|
3
|
+
import { expectParagraphAttrs } from "../../prosemirror/attrs/index.js";
|
|
4
|
+
import { expectTextBoxAnchorAttrs } from "../../prosemirror/textBoxAnchorAttrs.js";
|
|
5
|
+
import { nextBlockId, twipsToPixels } from "./flowConversionShared.js";
|
|
6
|
+
import { convertParagraphAttrs } from "./paragraphAttrs.js";
|
|
7
|
+
import { resolveParagraphMarkFormatting, resolveParagraphMarkOwnFormatting } from "./paragraphMarkFormatting.js";
|
|
8
|
+
import { paragraphToRuns } from "./paragraphRuns.js";
|
|
9
|
+
import { resolveWesternThemeFont } from "./textFormattingConversion.js";
|
|
10
|
+
import { panic } from "better-result";
|
|
11
|
+
import { statesNoBorder } from "@stll/docx-core/model";
|
|
12
|
+
//#region src/layout-bridge/convert/paragraphConversion.ts
|
|
13
|
+
const DETACHED_WATERMARK_HOST_ATTR = "_detachedWatermarkHost";
|
|
14
|
+
const expectDetachedWatermarkHostAttr = (attrs) => {
|
|
15
|
+
const value = Reflect.get(attrs, DETACHED_WATERMARK_HOST_ATTR);
|
|
16
|
+
if (value === null || value === void 0) return false;
|
|
17
|
+
if (typeof value !== "boolean") panic("Invalid ProseMirror detached watermark host attrs:\nparagraph.attrs._detachedWatermarkHost: Expected a boolean.");
|
|
18
|
+
return value;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Convert a paragraph node to a ParagraphBlock.
|
|
22
|
+
*/
|
|
23
|
+
function hasOnlyVisuallyEmptyTextRuns(runs) {
|
|
24
|
+
return runs.length > 0 && runs.every((run) => run.kind === "text" && run.text.replace(/\u00a0/gu, " ").trim().length === 0);
|
|
25
|
+
}
|
|
26
|
+
function hasOnlyHiddenTextRuns(runs) {
|
|
27
|
+
return runs.length > 0 && runs.every((run) => run.kind === "text" && run.hidden === true);
|
|
28
|
+
}
|
|
29
|
+
function hasVisibleParagraphPayload(attrs) {
|
|
30
|
+
return attrs.listMarker !== void 0 && !attrs.listMarkerHidden || attrs.borders?.top !== void 0 || attrs.borders?.bottom !== void 0 || attrs.borders?.left !== void 0 || attrs.borders?.right !== void 0 || attrs.borders?.between !== void 0 || attrs.borders?.bar !== void 0 || attrs.shading !== void 0;
|
|
31
|
+
}
|
|
32
|
+
/** Whether any `w:pBdr` side draws a rule (`none`/`nil` sides draw nothing). */
|
|
33
|
+
function drawsParagraphBorder(borders) {
|
|
34
|
+
if (!borders) return false;
|
|
35
|
+
return [
|
|
36
|
+
borders.top,
|
|
37
|
+
borders.bottom,
|
|
38
|
+
borders.left,
|
|
39
|
+
borders.right,
|
|
40
|
+
borders.between,
|
|
41
|
+
borders.bar
|
|
42
|
+
].some((border) => border?.style !== void 0 && !statesNoBorder(border.style));
|
|
43
|
+
}
|
|
44
|
+
function convertParagraph(node, startPos, options, pageBreaks) {
|
|
45
|
+
const pmAttrs = expectParagraphAttrs(node);
|
|
46
|
+
const runs = paragraphToRuns(node, startPos, options, pageBreaks);
|
|
47
|
+
const attrs = convertParagraphAttrs(pmAttrs, {
|
|
48
|
+
theme: options.theme,
|
|
49
|
+
fontAlternates: options.fontAlternates,
|
|
50
|
+
listCounterStreams: options.listCounterStreams,
|
|
51
|
+
defaultTabStopTwips: options.defaultTabStopTwips,
|
|
52
|
+
paragraphMarkFormatting: () => resolveParagraphMarkFormatting(pmAttrs, options.styleResolver)
|
|
53
|
+
});
|
|
54
|
+
if (options.numberingTabIgnoresIndent && attrs.listMarker !== void 0) attrs.listNumberingTabIgnoresIndent = true;
|
|
55
|
+
if (options.defaultFont !== void 0) attrs.defaultFontFamily ??= options.defaultFont;
|
|
56
|
+
if (options.defaultSize !== void 0) attrs.defaultFontSize ??= options.defaultSize;
|
|
57
|
+
if (options.lineBreakRules) attrs.lineBreakRules = options.lineBreakRules;
|
|
58
|
+
if (options.justificationCompatibility) attrs.justificationCompatibility = options.justificationCompatibility;
|
|
59
|
+
if (options.automaticHyphenation) attrs.automaticHyphenation = options.automaticHyphenation;
|
|
60
|
+
const defaultTextFormatting = pmAttrs.defaultTextFormatting;
|
|
61
|
+
if (runs.length === 0 || hasOnlyVisuallyEmptyTextRuns(runs)) {
|
|
62
|
+
if (pmAttrs._originalFormatting && Object.entries(pmAttrs._originalFormatting).some(([key, value]) => key !== "runProperties" && value !== void 0 && value !== null)) attrs.hasDirectParagraphFormatting = true;
|
|
63
|
+
const directParagraphMarkFormatting = pmAttrs._originalFormatting?.runProperties;
|
|
64
|
+
if (directParagraphMarkFormatting && Object.values(directParagraphMarkFormatting).some((value) => value !== void 0 && value !== null)) attrs.hasDirectParagraphMarkFormatting = true;
|
|
65
|
+
const paragraphMarkFormatting = resolveParagraphMarkOwnFormatting(directParagraphMarkFormatting, options.styleResolver);
|
|
66
|
+
if (paragraphMarkFormatting?.fontSize !== void 0) attrs.defaultFontSize = paragraphMarkFormatting.fontSize / 2;
|
|
67
|
+
const paragraphMarkFontFamily = paragraphMarkFormatting?.fontFamily ? resolveWesternThemeFont(paragraphMarkFormatting.fontFamily, options.theme) : void 0;
|
|
68
|
+
if (paragraphMarkFontFamily) {
|
|
69
|
+
attrs.defaultFontFamily = paragraphMarkFontFamily;
|
|
70
|
+
const alternate = getFontAlternate(paragraphMarkFontFamily, options.fontAlternates);
|
|
71
|
+
if (alternate) attrs.defaultAlternateFontFamily = alternate;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const isFullyHiddenParagraph = defaultTextFormatting?.hidden === true && (runs.length === 0 || hasOnlyHiddenTextRuns(runs));
|
|
75
|
+
if (isFullyHiddenParagraph && attrs.listMarker !== void 0) attrs.listMarkerHidden = true;
|
|
76
|
+
if (isFullyHiddenParagraph) attrs.suppressEmptyParagraphHeight = true;
|
|
77
|
+
if (runs.length === 0 && expectDetachedWatermarkHostAttr(node.attrs)) attrs.suppressEmptyParagraphHeight = false;
|
|
78
|
+
if (runs.length === 0 && pmAttrs._pageBreakCarrier === true && !hasVisibleParagraphPayload(attrs)) attrs.suppressEmptyParagraphHeight = true;
|
|
79
|
+
const bookmarkNames = pmAttrs.bookmarks?.map((b) => b.name);
|
|
80
|
+
const block = {
|
|
81
|
+
kind: "paragraph",
|
|
82
|
+
id: nextBlockId(),
|
|
83
|
+
runs,
|
|
84
|
+
attrs,
|
|
85
|
+
...pmAttrs.paraId ? { paraId: pmAttrs.paraId } : {},
|
|
86
|
+
...bookmarkNames && bookmarkNames.length > 0 ? { bookmarks: bookmarkNames } : {},
|
|
87
|
+
pmStart: startPos,
|
|
88
|
+
pmEnd: startPos + node.nodeSize
|
|
89
|
+
};
|
|
90
|
+
const frame = pmAttrs._originalFormatting?.frame;
|
|
91
|
+
if (frame !== void 0 && frame.dropCap !== "drop" && frame.dropCap !== "margin") setParagraphFrame(block, {
|
|
92
|
+
...frame.width !== void 0 ? { width: twipsToPixels(frame.width) } : {},
|
|
93
|
+
...frame.height !== void 0 ? { height: twipsToPixels(frame.height) } : {},
|
|
94
|
+
...frame.hSpace !== void 0 ? { hSpace: twipsToPixels(frame.hSpace) } : {},
|
|
95
|
+
...frame.vSpace !== void 0 ? { vSpace: twipsToPixels(frame.vSpace) } : {},
|
|
96
|
+
...frame.hAnchor !== void 0 ? { hAnchor: frame.hAnchor } : {},
|
|
97
|
+
...frame.vAnchor !== void 0 ? { vAnchor: frame.vAnchor } : {},
|
|
98
|
+
...frame.x !== void 0 ? { x: twipsToPixels(frame.x) } : {},
|
|
99
|
+
...frame.y !== void 0 ? { y: twipsToPixels(frame.y) } : {},
|
|
100
|
+
...frame.xAlign !== void 0 ? { xAlign: frame.xAlign } : {},
|
|
101
|
+
...frame.yAlign !== void 0 ? { yAlign: frame.yAlign } : {},
|
|
102
|
+
...frame.wrap !== void 0 ? { wrap: frame.wrap } : {}
|
|
103
|
+
});
|
|
104
|
+
node.descendants((child) => {
|
|
105
|
+
if (child.type.name !== "textBoxAnchor") return true;
|
|
106
|
+
options.textBoxAnchorBlockIds.set(expectTextBoxAnchorAttrs(child).anchorId, block.id);
|
|
107
|
+
return false;
|
|
108
|
+
});
|
|
109
|
+
return block;
|
|
110
|
+
}
|
|
111
|
+
//#endregion
|
|
112
|
+
export { convertParagraph, drawsParagraphBorder, hasVisibleParagraphPayload };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Run, RunFormatting } from "../../layout-engine/types.js";
|
|
2
|
+
import { FlowConversionOptions } from "./flowConversionShared.js";
|
|
3
|
+
import { Node } from "prosemirror-model";
|
|
4
|
+
//#region src/layout-bridge/convert/paragraphRuns.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Convert a paragraph node to runs.
|
|
7
|
+
*/
|
|
8
|
+
type PageBreakRunProjection = {
|
|
9
|
+
pmStart: number;
|
|
10
|
+
pmEnd: number;
|
|
11
|
+
trackedChange?: Pick<RunFormatting, "isInsertion" | "changeAuthor" | "changeDate" | "changeRevisionId" | "isSuggestion" | "suggestionId">;
|
|
12
|
+
};
|
|
13
|
+
declare function paragraphToRuns(node: Node, startPos: number, _options: FlowConversionOptions, pageBreaks?: PageBreakRunProjection[]): Run[];
|
|
14
|
+
//#endregion
|
|
15
|
+
export { PageBreakRunProjection, paragraphToRuns };
|