@stll/folio-core 0.6.1 → 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 +86 -11
- 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/groupDrawingParser.d.ts +1 -1
- package/dist/docx/groupDrawingParser.js +49 -8
- 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/runParser.js +11 -2
- 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/server/boundedArchive.d.ts +24 -0
- package/dist/docx/server/boundedArchive.js +106 -0
- package/dist/docx/server/extractDocxText.d.ts +23 -0
- package/dist/docx/server/extractDocxText.js +154 -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 +106 -13
- 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 +125 -72
- package/dist/layout-engine/keep-together.d.ts +7 -5
- package/dist/layout-engine/keep-together.js +20 -4
- package/dist/layout-engine/measure/cache.js +2 -0
- 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 +42 -15
- 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 +17 -8
- 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 +31 -10
- package/dist/layout-engine/types.js +15 -2
- package/dist/layout-painter/renderPage.js +2 -2
- package/dist/layout-painter/renderParagraph.js +94 -10
- 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 +29 -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/TableExtension.js +1 -0
- 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 +6 -3
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
- package/dist/prosemirror/utils/tabCalculator.js +1 -1
- package/dist/server.d.ts +6 -2
- package/dist/server.js +5 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/utils/createDocument.js +26 -18
- package/dist/utils/formatToStyle.js +3 -3
- package/dist/utils/hexId.d.ts +8 -1
- package/dist/utils/hexId.js +11 -3
- package/dist/utils/units.d.ts +6 -6
- package/dist/utils/units.js +8 -8
- package/package.json +1 -1
|
@@ -5,7 +5,7 @@ import { calculateTabWidth } from "../prosemirror/utils/tabCalculator.js";
|
|
|
5
5
|
import { inlineImageBoundingBox, parseRotationDegrees, rotatedBoundingBox } from "../utils/rotationBoundingBox.js";
|
|
6
6
|
import { hasCjk, segmentByScript } from "../utils/scriptSegments.js";
|
|
7
7
|
import { isFloatingImageRun } from "../layout-engine/types.js";
|
|
8
|
-
import { getListMarkerInlineWidth } from "../layout-engine/measure/listMarkerWidth.js";
|
|
8
|
+
import { getListMarkerInlineWidth, getListMarkerVisualOffset } from "../layout-engine/measure/listMarkerWidth.js";
|
|
9
9
|
import { applySdtDataAttrs } from "./sdtBoundary.js";
|
|
10
10
|
import { applyImageVisualAttrs, hasImageVisualAttrs, wrapImageWithCrop } from "./renderImage.js";
|
|
11
11
|
import { ommlToMathml } from "../docx/mathToMathml.js";
|
|
@@ -709,6 +709,75 @@ function splitTextRunsByEastAsia(runs) {
|
|
|
709
709
|
}
|
|
710
710
|
return result;
|
|
711
711
|
}
|
|
712
|
+
const paintsLineEdgeSpaces = (run) => Boolean(run.underline || run.strike || run.highlight || run.shading || run.hyperlink || run.hidden || run.templatePreview || run.isInsertion || run.isDeletion || run.commentIds?.length || run.textEffect || run.emphasisMark);
|
|
713
|
+
const splitTextRunAt = (run, index) => {
|
|
714
|
+
const leading = {
|
|
715
|
+
...run,
|
|
716
|
+
text: run.text.slice(0, index)
|
|
717
|
+
};
|
|
718
|
+
const trailing = {
|
|
719
|
+
...run,
|
|
720
|
+
text: run.text.slice(index)
|
|
721
|
+
};
|
|
722
|
+
if (run.pmStart === void 0) return [leading, trailing];
|
|
723
|
+
const splitPosition = Math.min(run.pmStart + index, run.pmEnd ?? Number.POSITIVE_INFINITY);
|
|
724
|
+
leading.pmEnd = splitPosition;
|
|
725
|
+
trailing.pmStart = splitPosition;
|
|
726
|
+
return [leading, trailing];
|
|
727
|
+
};
|
|
728
|
+
/**
|
|
729
|
+
* Word keeps ordinary line-edge spaces addressable in the document model but
|
|
730
|
+
* gives them no painted advance. Collapsible trailing spaces always collapse;
|
|
731
|
+
* leading spaces collapse only after a soft wrap, not at the authored
|
|
732
|
+
* paragraph start or after a manual line break. Split paint runs to preserve
|
|
733
|
+
* exact PM ranges.
|
|
734
|
+
*/
|
|
735
|
+
const splitCollapsibleLineEdgeSpaces = (sourceRuns, collapseLeading) => {
|
|
736
|
+
const runs = [...sourceRuns];
|
|
737
|
+
const collapsedLeadingRuns = /* @__PURE__ */ new Set();
|
|
738
|
+
const collapsedTrailingRuns = /* @__PURE__ */ new Set();
|
|
739
|
+
for (let index = runs.length - 1; index >= 0; index--) {
|
|
740
|
+
const run = runs[index];
|
|
741
|
+
if (!run || !isTextRun(run)) break;
|
|
742
|
+
if (run.text.length === 0) continue;
|
|
743
|
+
const trailingSpaces = / +$/u.exec(run.text);
|
|
744
|
+
if (!trailingSpaces || paintsLineEdgeSpaces(run)) break;
|
|
745
|
+
if (trailingSpaces.index === 0) {
|
|
746
|
+
collapsedTrailingRuns.add(run);
|
|
747
|
+
continue;
|
|
748
|
+
}
|
|
749
|
+
const [leading, trailing] = splitTextRunAt(run, trailingSpaces.index);
|
|
750
|
+
runs.splice(index, 1, leading, trailing);
|
|
751
|
+
collapsedTrailingRuns.add(trailing);
|
|
752
|
+
break;
|
|
753
|
+
}
|
|
754
|
+
if (collapseLeading) for (let index = 0; index < runs.length; index++) {
|
|
755
|
+
const run = runs[index];
|
|
756
|
+
if (!run || !isTextRun(run)) break;
|
|
757
|
+
if (run.text.length === 0) continue;
|
|
758
|
+
const leadingSpaces = /^ +/u.exec(run.text);
|
|
759
|
+
if (!leadingSpaces || paintsLineEdgeSpaces(run)) break;
|
|
760
|
+
if (leadingSpaces[0].length === run.text.length) {
|
|
761
|
+
collapsedLeadingRuns.add(run);
|
|
762
|
+
continue;
|
|
763
|
+
}
|
|
764
|
+
const [leading, trailing] = splitTextRunAt(run, leadingSpaces[0].length);
|
|
765
|
+
runs.splice(index, 1, leading, trailing);
|
|
766
|
+
collapsedLeadingRuns.add(leading);
|
|
767
|
+
break;
|
|
768
|
+
}
|
|
769
|
+
return {
|
|
770
|
+
runs,
|
|
771
|
+
collapsedLeadingRuns,
|
|
772
|
+
collapsedTrailingRuns
|
|
773
|
+
};
|
|
774
|
+
};
|
|
775
|
+
const startsAfterSoftWrap = (block, line) => {
|
|
776
|
+
if (line.fromChar > 0) return true;
|
|
777
|
+
if (line.fromRun === 0) return false;
|
|
778
|
+
const previousRun = block.runs.at(line.fromRun - 1);
|
|
779
|
+
return previousRun !== void 0 && !isLineBreakRun(previousRun);
|
|
780
|
+
};
|
|
712
781
|
/**
|
|
713
782
|
* Sub-pixel tolerance when comparing canvas-measured widths against the DOM's
|
|
714
783
|
* actual right edge. Accumulated rounding from canvas measureText vs. browser
|
|
@@ -878,7 +947,20 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
878
947
|
lineEl.style.boxSizing = "content-box";
|
|
879
948
|
lineEl.style.height = `${line.lineHeight}px`;
|
|
880
949
|
lineEl.style.lineHeight = `${line.lineHeight}px`;
|
|
881
|
-
const
|
|
950
|
+
const splitRuns = splitTextRunsByEastAsia(sliceRunsForLine(block, line));
|
|
951
|
+
const { runs: runsForLine, collapsedLeadingRuns: collapsedLeadingSpaceRuns, collapsedTrailingRuns: collapsedTrailingSpaceRuns } = splitCollapsibleLineEdgeSpaces(splitRuns, startsAfterSoftWrap(block, line));
|
|
952
|
+
const isCollapsedLineEdgeSpaceRun = (run) => collapsedLeadingSpaceRuns.has(run) || collapsedTrailingSpaceRuns.has(run);
|
|
953
|
+
const renderLineTextRun = (run) => {
|
|
954
|
+
const runEl = renderTextRun(run, doc);
|
|
955
|
+
if (collapsedLeadingSpaceRuns.has(run)) runEl.dataset["collapsedLeadingSpaces"] = "true";
|
|
956
|
+
if (collapsedTrailingSpaceRuns.has(run)) runEl.dataset["collapsedTrailingSpaces"] = "true";
|
|
957
|
+
if (isCollapsedLineEdgeSpaceRun(run)) {
|
|
958
|
+
runEl.style.fontSize = "0";
|
|
959
|
+
runEl.style.letterSpacing = "0";
|
|
960
|
+
runEl.style.wordSpacing = "0";
|
|
961
|
+
}
|
|
962
|
+
return runEl;
|
|
963
|
+
};
|
|
882
964
|
const onlyRun = runsForLine.length === 1 ? runsForLine[0] : void 0;
|
|
883
965
|
if (onlyRun && isMathRun(onlyRun) && onlyRun.display === "block" && block.attrs?.alignment !== "right") lineEl.style.textAlign = "center";
|
|
884
966
|
if (runsForLine.length === 1 && isImageRun(runsForLine[0])) {
|
|
@@ -914,7 +996,7 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
914
996
|
const firstLineHangingExpansionPx = hasVisibleListMarker ? Math.min(firstLineHangingPx, Math.max(0, options.leftIndentPx ?? 0)) : firstLineHangingPx;
|
|
915
997
|
const justifyCapacityPx = options.availableWidth + firstLineHangingExpansionPx;
|
|
916
998
|
const overfullPx = line.width - justifyCapacityPx;
|
|
917
|
-
const shrinkableSpaces = countShrinkableSpaces(runsForLine);
|
|
999
|
+
const shrinkableSpaces = countShrinkableSpaces(runsForLine.filter((run) => !isTextRun(run) || !isCollapsedLineEdgeSpaceRun(run)));
|
|
918
1000
|
if (overfullPx > RIGHT_EDGE_EPSILON_PX && shrinkableSpaces > 0) {
|
|
919
1001
|
lineEl.style.textAlign = "left";
|
|
920
1002
|
lineEl.style.textAlignLast = "auto";
|
|
@@ -989,7 +1071,7 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
989
1071
|
for (let j = i + 1; j < runsForLine.length; j++) {
|
|
990
1072
|
const next = runsForLine[j];
|
|
991
1073
|
if (isTabRun(next) || isLineBreakRun(next)) break;
|
|
992
|
-
if (isTextRun(next)) lineEl.append(
|
|
1074
|
+
if (isTextRun(next)) lineEl.append(renderLineTextRun(next));
|
|
993
1075
|
else if (isFieldRun(next) && options?.context) lineEl.append(renderFieldRun(next, doc, options.context));
|
|
994
1076
|
else if (isImageRun(next)) {
|
|
995
1077
|
if (isFloatingImageRun(next)) continue;
|
|
@@ -1003,13 +1085,14 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
1003
1085
|
break;
|
|
1004
1086
|
}
|
|
1005
1087
|
let tabWidth = tabResult.width;
|
|
1006
|
-
if (lineRightEdgeX !== void 0 && canClampTabToRightEdge(tabResult.alignment, i > 0, runsForLine.slice(0, i).some(isTabRun), options?.isLastLine === true) && currentX + tabWidth + followingWidthForCheck > lineRightEdgeX) tabWidth = Math.max(1, lineRightEdgeX - currentX - followingWidthForCheck);
|
|
1088
|
+
if (!(tabResult.alignment === "start" && leftIndentPx > 0 && Math.abs(currentX + tabWidth - leftIndentPx) <= RIGHT_EDGE_EPSILON_PX) && lineRightEdgeX !== void 0 && canClampTabToRightEdge(tabResult.alignment, i > 0, runsForLine.slice(0, i).some(isTabRun), options?.isLastLine === true) && currentX + tabWidth + followingWidthForCheck > lineRightEdgeX) tabWidth = Math.max(1, lineRightEdgeX - currentX - followingWidthForCheck);
|
|
1007
1089
|
const tabEl = renderTabRun(run, doc, tabWidth, tabResult.leader);
|
|
1008
1090
|
lineEl.append(tabEl);
|
|
1009
1091
|
currentX += tabWidth;
|
|
1010
1092
|
} else if (isTextRun(run)) {
|
|
1011
|
-
const runEl =
|
|
1093
|
+
const runEl = renderLineTextRun(run);
|
|
1012
1094
|
lineEl.append(runEl);
|
|
1095
|
+
if (isCollapsedLineEdgeSpaceRun(run)) continue;
|
|
1013
1096
|
const fontSize = run.fontSize || 11;
|
|
1014
1097
|
const fontFamily = run.fontFamily || "Calibri";
|
|
1015
1098
|
const measuredWidth = measureText(run.allCaps ? run.text.toLocaleUpperCase() : run.text, fontSize, fontFamily, {
|
|
@@ -1268,7 +1351,7 @@ function renderParagraphFragment(fragment, block, measure, context, options = {}
|
|
|
1268
1351
|
}
|
|
1269
1352
|
const markerFontFamily = block.attrs.listMarkerFontFamily ?? firstTextRun?.fontFamily ?? block.attrs.defaultFontFamily;
|
|
1270
1353
|
const markerFontSize = block.attrs.listMarkerFontSize ?? firstTextRun?.fontSize ?? block.attrs.defaultFontSize;
|
|
1271
|
-
const marker = renderListMarker(block.attrs.listMarker, getListMarkerInlineWidth(block), doc, markerFontFamily, markerFontSize, block.attrs.listMarkerRevision, block.attrs.listMarkerSecondSlotOffsetTwips);
|
|
1354
|
+
const marker = renderListMarker(block.attrs.listMarker, getListMarkerInlineWidth(block), getListMarkerVisualOffset(block), doc, markerFontFamily, markerFontSize, block.attrs.listMarkerRevision, block.attrs.listMarkerSecondSlotOffsetTwips);
|
|
1272
1355
|
const markerMarginLeft = markerStart - Math.min(indentLeft, 0);
|
|
1273
1356
|
if (markerMarginLeft < 0) marker.style.marginLeft = `${markerMarginLeft}px`;
|
|
1274
1357
|
lineEl.prepend(marker);
|
|
@@ -1279,13 +1362,13 @@ function renderParagraphFragment(fragment, block, measure, context, options = {}
|
|
|
1279
1362
|
}
|
|
1280
1363
|
/**
|
|
1281
1364
|
* Render a list marker element as an inline-block at the start of the first
|
|
1282
|
-
* body line. `
|
|
1365
|
+
* body line. `inlineWidth` (from `getListMarkerInlineWidth`) sizes the marker
|
|
1283
1366
|
* so the body text aligns at the next tab stop per ECMA-376 §17.9.25 —
|
|
1284
1367
|
* this honours `w:suff` (`tab` / `space` / `nothing`) and the document's
|
|
1285
1368
|
* tab grid. Long markers like "1.1.1." therefore grow to the next stop
|
|
1286
1369
|
* instead of butting against the body text.
|
|
1287
1370
|
*/
|
|
1288
|
-
function renderListMarker(marker,
|
|
1371
|
+
function renderListMarker(marker, inlineWidth, visualOffset, doc, fontFamily, fontSize, revision, secondSlotOffsetTwips) {
|
|
1289
1372
|
const span = doc.createElement("span");
|
|
1290
1373
|
span.className = "layout-list-marker";
|
|
1291
1374
|
span.style.display = "inline-block";
|
|
@@ -1294,7 +1377,8 @@ function renderListMarker(marker, minWidth, doc, fontFamily, fontSize, revision,
|
|
|
1294
1377
|
span.style.textAlign = "left";
|
|
1295
1378
|
span.style.textAlignLast = "left";
|
|
1296
1379
|
span.style.boxSizing = "border-box";
|
|
1297
|
-
|
|
1380
|
+
span.style.width = `${inlineWidth}px`;
|
|
1381
|
+
if (visualOffset !== 0) span.style.transform = `translateX(${visualOffset}px)`;
|
|
1298
1382
|
if (revision) {
|
|
1299
1383
|
const authorIdx = getAuthorColorIdx(revision.author ?? "");
|
|
1300
1384
|
const authorColor = AUTHOR_COLORS[authorIdx];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { emuToPixels } from "../utils/units.js";
|
|
2
|
-
import { isFloatingImageRun, isFloatingTextBoxBlock, tableColumnsArePinned } from "../layout-engine/types.js";
|
|
2
|
+
import { getTableRowLeadingWidth, isFloatingImageRun, isFloatingTextBoxBlock, tableColumnsArePinned } from "../layout-engine/types.js";
|
|
3
3
|
import { measureParagraph } from "../layout-engine/measure/measureParagraph.js";
|
|
4
4
|
import { getAutomaticTextColorForBackground } from "./documentColors.js";
|
|
5
5
|
import { renderParagraphFragment } from "./renderParagraph.js";
|
|
@@ -207,6 +207,7 @@ function renderNestedTable(block, measure, context, doc) {
|
|
|
207
207
|
rowYPositions.push(yPos);
|
|
208
208
|
const spanningCells = /* @__PURE__ */ new Map();
|
|
209
209
|
const columnsPinned = tableColumnsArePinned(block);
|
|
210
|
+
const cellGrid = buildTableCellGrid(block, measure.columnWidths.length);
|
|
210
211
|
let y = 0;
|
|
211
212
|
for (let rowIndex = 0; rowIndex < block.rows.length; rowIndex++) {
|
|
212
213
|
const row = block.rows[rowIndex];
|
|
@@ -216,7 +217,7 @@ function renderNestedTable(block, measure, context, doc) {
|
|
|
216
217
|
y += rowMeasure.height;
|
|
217
218
|
continue;
|
|
218
219
|
}
|
|
219
|
-
const rowEl = renderTableRow(row, rowMeasure, rowIndex, y, measure.columnWidths, block.rows.length, context, doc, spanningCells, rowYPositions, void 0, block.bidi, columnsPinned);
|
|
220
|
+
const rowEl = renderTableRow(row, rowMeasure, rowIndex, y, measure.columnWidths, block.rows.length, context, doc, spanningCells, rowYPositions, void 0, block.bidi, columnsPinned, cellGrid);
|
|
220
221
|
tableEl.append(rowEl);
|
|
221
222
|
y += rowMeasure.height;
|
|
222
223
|
}
|
|
@@ -255,10 +256,10 @@ function renderTableCell(cell, cellMeasure, x, rowHeight, borderFlags, columnsPi
|
|
|
255
256
|
const padLeft = cell.padding?.left ?? 7;
|
|
256
257
|
cellEl.style.padding = `${padTop}px ${padRight}px ${padBottom}px ${padLeft}px`;
|
|
257
258
|
if (cell.borders) {
|
|
258
|
-
if (borderFlags.
|
|
259
|
+
if (borderFlags.drawTop) applyBorder(cellEl, "top", cell.borders.top);
|
|
259
260
|
applyBorder(cellEl, "right", cell.borders.right);
|
|
260
261
|
applyBorder(cellEl, "bottom", cell.borders.bottom);
|
|
261
|
-
if (borderFlags.
|
|
262
|
+
if (borderFlags.drawLeft) applyBorder(cellEl, "left", cell.borders.left);
|
|
262
263
|
}
|
|
263
264
|
if (cell.background) {
|
|
264
265
|
cellEl.style.backgroundColor = cell.background;
|
|
@@ -303,10 +304,30 @@ function renderTableCell(cell, cellMeasure, x, rowHeight, borderFlags, columnsPi
|
|
|
303
304
|
}
|
|
304
305
|
return cellEl;
|
|
305
306
|
}
|
|
307
|
+
const tableCellGridKey = (rowIndex, columnIndex) => `${rowIndex}:${columnIndex}`;
|
|
308
|
+
function buildTableCellGrid(block, columnCount) {
|
|
309
|
+
const grid = /* @__PURE__ */ new Map();
|
|
310
|
+
for (let rowIndex = 0; rowIndex < block.rows.length; rowIndex++) {
|
|
311
|
+
const row = block.rows[rowIndex];
|
|
312
|
+
if (!row) continue;
|
|
313
|
+
let columnIndex = 0;
|
|
314
|
+
for (const cell of row.cells) {
|
|
315
|
+
while (grid.has(tableCellGridKey(rowIndex, columnIndex))) columnIndex += 1;
|
|
316
|
+
const colSpan = cell.colSpan ?? 1;
|
|
317
|
+
const rowSpan = cell.rowSpan ?? 1;
|
|
318
|
+
const rowEnd = Math.min(block.rows.length, rowIndex + rowSpan);
|
|
319
|
+
const columnEnd = Math.min(columnCount, columnIndex + colSpan);
|
|
320
|
+
for (let gridRow = rowIndex; gridRow < rowEnd; gridRow++) for (let gridColumn = columnIndex; gridColumn < columnEnd; gridColumn++) grid.set(tableCellGridKey(gridRow, gridColumn), cell);
|
|
321
|
+
columnIndex += colSpan;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return grid;
|
|
325
|
+
}
|
|
326
|
+
const hasVisibleBorder = (border) => border !== void 0 && border.width !== 0 && border.style !== "none" && border.style !== "nil";
|
|
306
327
|
/**
|
|
307
328
|
* Render a table row with rowSpan support
|
|
308
329
|
*/
|
|
309
|
-
function renderTableRow(row, rowMeasure, rowIndex, y, columnWidths, totalRows, context, doc, spanningCells, rowYPositions, isFirstRowInFragment, bidi = false, columnsPinned = false) {
|
|
330
|
+
function renderTableRow(row, rowMeasure, rowIndex, y, columnWidths, totalRows, context, doc, spanningCells, rowYPositions, isFirstRowInFragment, bidi = false, columnsPinned = false, cellGrid) {
|
|
310
331
|
const rowEl = doc.createElement("div");
|
|
311
332
|
rowEl.className = TABLE_CLASS_NAMES.row;
|
|
312
333
|
const tableWidth = bidi ? columnWidths.reduce((sum, columnWidth) => sum + columnWidth, 0) : 0;
|
|
@@ -320,8 +341,9 @@ function renderTableRow(row, rowMeasure, rowIndex, y, columnWidths, totalRows, c
|
|
|
320
341
|
if (spanningCells) {
|
|
321
342
|
for (const [, spanCell] of spanningCells) if (spanCell.startRow < rowIndex && spanCell.startRow + spanCell.rowSpan > rowIndex) for (let c = 0; c < spanCell.colSpan; c++) occupiedColumns.add(spanCell.columnIndex + c);
|
|
322
343
|
}
|
|
323
|
-
|
|
324
|
-
let
|
|
344
|
+
const gridBefore = row.gridBefore ?? 0;
|
|
345
|
+
let x = getTableRowLeadingWidth(row, columnWidths);
|
|
346
|
+
let columnIndex = gridBefore;
|
|
325
347
|
while (occupiedColumns.has(columnIndex)) {
|
|
326
348
|
x += columnWidths[columnIndex] ?? 0;
|
|
327
349
|
columnIndex++;
|
|
@@ -345,11 +367,18 @@ function renderTableRow(row, rowMeasure, rowIndex, y, columnWidths, totalRows, c
|
|
|
345
367
|
const isLastRow = rowIndex + rowSpan >= totalRows;
|
|
346
368
|
const atLogicalStart = columnIndex === 0;
|
|
347
369
|
const atLogicalEnd = columnIndex + colSpan >= columnWidths.length;
|
|
370
|
+
const isFirstCol = bidi ? atLogicalEnd : atLogicalStart;
|
|
371
|
+
const isLastCol = bidi ? atLogicalStart : atLogicalEnd;
|
|
372
|
+
const aboveCell = cellGrid?.get(tableCellGridKey(rowIndex - 1, columnIndex));
|
|
373
|
+
const leftNeighborColumn = bidi ? columnIndex + colSpan : columnIndex - 1;
|
|
374
|
+
const leftCell = cellGrid?.get(tableCellGridKey(rowIndex, leftNeighborColumn));
|
|
375
|
+
const drawTop = isFirstRow || !hasVisibleBorder(aboveCell?.borders?.bottom);
|
|
376
|
+
const drawLeft = isFirstCol || !hasVisibleBorder(leftCell?.borders?.right);
|
|
348
377
|
const cellEl = renderTableCell(cell, cellMeasure, cellLeft, cellHeight, {
|
|
349
|
-
|
|
378
|
+
drawTop,
|
|
350
379
|
isLastRow,
|
|
351
|
-
|
|
352
|
-
isLastCol
|
|
380
|
+
drawLeft,
|
|
381
|
+
isLastCol
|
|
353
382
|
}, columnsPinned, context, doc);
|
|
354
383
|
cellEl.dataset["cellIndex"] = String(cellIndex);
|
|
355
384
|
cellEl.dataset["columnIndex"] = String(columnIndex);
|
|
@@ -429,6 +458,7 @@ function renderTableFragment(fragment, block, measure, context, options = {}) {
|
|
|
429
458
|
rowYPositions.push(yPos);
|
|
430
459
|
const spanningCells = /* @__PURE__ */ new Map();
|
|
431
460
|
const columnsPinned = tableColumnsArePinned(block);
|
|
461
|
+
const cellGrid = buildTableCellGrid(block, measure.columnWidths.length);
|
|
432
462
|
const headerRowCount = fragment.headerRowCount ?? 0;
|
|
433
463
|
let y = 0;
|
|
434
464
|
if (headerRowCount > 0 && fragment.continuesFromPrev) for (let hdrIdx = 0; hdrIdx < headerRowCount; hdrIdx++) {
|
|
@@ -439,7 +469,7 @@ function renderTableFragment(fragment, block, measure, context, options = {}) {
|
|
|
439
469
|
y += hdrRowMeasure.height;
|
|
440
470
|
continue;
|
|
441
471
|
}
|
|
442
|
-
const rowEl = renderTableRow(hdrRow, hdrRowMeasure, hdrIdx, y, measure.columnWidths, block.rows.length, context, doc, spanningCells, rowYPositions, hdrIdx === 0, block.bidi, columnsPinned);
|
|
472
|
+
const rowEl = renderTableRow(hdrRow, hdrRowMeasure, hdrIdx, y, measure.columnWidths, block.rows.length, context, doc, spanningCells, rowYPositions, hdrIdx === 0, block.bidi, columnsPinned, cellGrid);
|
|
443
473
|
rowEl.dataset["repeatedHeader"] = "true";
|
|
444
474
|
tableEl.append(rowEl);
|
|
445
475
|
y += hdrRowMeasure.height;
|
|
@@ -467,7 +497,7 @@ function renderTableFragment(fragment, block, measure, context, options = {}) {
|
|
|
467
497
|
continue;
|
|
468
498
|
}
|
|
469
499
|
const isFirstRowInFragment = headerRowCount > 0 && fragment.continuesFromPrev ? false : fragment.continuesFromPrev && rowIndex === fragment.fromRow;
|
|
470
|
-
const rowEl = renderTableRow(row, rowMeasure, rowIndex, y, measure.columnWidths, block.rows.length, context, doc, spanningCells, rowYPositions, isFirstRowInFragment, block.bidi, columnsPinned);
|
|
500
|
+
const rowEl = renderTableRow(row, rowMeasure, rowIndex, y, measure.columnWidths, block.rows.length, context, doc, spanningCells, rowYPositions, isFirstRowInFragment, block.bidi, columnsPinned, cellGrid);
|
|
471
501
|
contentParent.append(rowEl);
|
|
472
502
|
y += rowMeasure.height;
|
|
473
503
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_TEXTBOX_MARGINS } from "../layout-engine/types.js";
|
|
2
2
|
import { renderParagraphFragment } from "./renderParagraph.js";
|
|
3
|
+
import { layoutTextBoxParagraphs } from "../layout-engine/measure/textBoxParagraphLayout.js";
|
|
3
4
|
//#region src/layout-painter/renderTextBox.ts
|
|
4
5
|
/**
|
|
5
6
|
* Text Box Renderer
|
|
@@ -38,28 +39,37 @@ function renderTextBoxFragment(fragment, block, measure, context, options = {})
|
|
|
38
39
|
if (fragment.pmStart !== void 0) containerEl.dataset["pmStart"] = String(fragment.pmStart);
|
|
39
40
|
if (fragment.pmEnd !== void 0) containerEl.dataset["pmEnd"] = String(fragment.pmEnd);
|
|
40
41
|
const innerWidth = fragment.width - margins.left - margins.right;
|
|
41
|
-
|
|
42
|
+
const paragraphLayout = layoutTextBoxParagraphs(block.content, measure.innerMeasures);
|
|
42
43
|
for (let i = 0; i < block.content.length; i++) {
|
|
43
44
|
const paraBlock = block.content[i];
|
|
44
45
|
const paraMeasure = measure.innerMeasures[i];
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
const placement = paragraphLayout.placements[i];
|
|
47
|
+
if (!paraBlock || !paraMeasure || !placement) continue;
|
|
48
|
+
const paraFragment = {
|
|
47
49
|
kind: "paragraph",
|
|
48
50
|
blockId: paraBlock.id,
|
|
49
51
|
x: 0,
|
|
50
|
-
y:
|
|
52
|
+
y: 0,
|
|
51
53
|
width: innerWidth,
|
|
52
|
-
height:
|
|
54
|
+
height: placement.contentHeight,
|
|
53
55
|
...paraBlock.pmStart !== void 0 ? { pmStart: paraBlock.pmStart } : {},
|
|
54
56
|
...paraBlock.pmEnd !== void 0 ? { pmEnd: paraBlock.pmEnd } : {},
|
|
55
57
|
fromLine: 0,
|
|
56
58
|
toLine: paraMeasure.lines.length
|
|
57
|
-
}
|
|
59
|
+
};
|
|
60
|
+
const prevBorders = block.content[i - 1]?.attrs?.borders;
|
|
61
|
+
const nextBorders = block.content[i + 1]?.attrs?.borders;
|
|
62
|
+
const paraEl = renderParagraphFragment(paraFragment, paraBlock, paraMeasure, context, {
|
|
63
|
+
document: doc,
|
|
64
|
+
...prevBorders !== void 0 ? { prevBorders } : {},
|
|
65
|
+
...nextBorders !== void 0 ? { nextBorders } : {}
|
|
66
|
+
});
|
|
58
67
|
paraEl.style.position = "relative";
|
|
59
68
|
paraEl.style.left = "0";
|
|
60
69
|
paraEl.style.top = "0";
|
|
70
|
+
paraEl.style.height = `${placement.contentHeight}px`;
|
|
71
|
+
paraEl.style.marginTop = `${placement.leadingSpacing}px`;
|
|
61
72
|
containerEl.append(paraEl);
|
|
62
|
-
yOffset += paraMeasure.totalHeight;
|
|
63
73
|
}
|
|
64
74
|
return containerEl;
|
|
65
75
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { inspectDocxCompatibility } from "../docx/compatibility.js";
|
|
1
2
|
import { resetAuthorColors } from "../utils/authorColors.js";
|
|
2
3
|
import { loadFontsWithMapping } from "../utils/fontLoader.js";
|
|
3
4
|
import { parseDocx } from "../docx/parser.js";
|
|
4
5
|
import { recordDocumentLoadPhase } from "../layout-engine/layoutInstrumentation.js";
|
|
5
|
-
import { inspectDocxCompatibility } from "../docx/compatibility.js";
|
|
6
6
|
//#region src/managers/DocumentLoaderManager.ts
|
|
7
7
|
/**
|
|
8
8
|
* DocumentLoaderManager
|
|
@@ -35,6 +35,9 @@ function computePerBlockMeasureInputs({ blocks, bodyConfig, finalConfig }) {
|
|
|
35
35
|
const widths = [];
|
|
36
36
|
const marginTops = [];
|
|
37
37
|
const pageHeights = [];
|
|
38
|
+
const pageWidths = [];
|
|
39
|
+
const marginLefts = [];
|
|
40
|
+
const marginRights = [];
|
|
38
41
|
const marginBottoms = [];
|
|
39
42
|
for (let i = 0; i < blocks.length; i++) {
|
|
40
43
|
const config = sectionConfigs[sectionIdx] ?? finalConfig;
|
|
@@ -42,6 +45,9 @@ function computePerBlockMeasureInputs({ blocks, bodyConfig, finalConfig }) {
|
|
|
42
45
|
widths.push(colWidth(contentWidth(config), columns, columnIndex));
|
|
43
46
|
marginTops.push(config.margins.top);
|
|
44
47
|
pageHeights.push(config.pageSize.h);
|
|
48
|
+
pageWidths.push(config.pageSize.w);
|
|
49
|
+
marginLefts.push(config.margins.left);
|
|
50
|
+
marginRights.push(config.margins.right);
|
|
45
51
|
marginBottoms.push(config.margins.bottom);
|
|
46
52
|
if (sectionIdx < breakIndices.length && i === breakIndices[sectionIdx]) {
|
|
47
53
|
sectionIdx++;
|
|
@@ -53,6 +59,9 @@ function computePerBlockMeasureInputs({ blocks, bodyConfig, finalConfig }) {
|
|
|
53
59
|
widths,
|
|
54
60
|
marginTops,
|
|
55
61
|
pageHeights,
|
|
62
|
+
pageWidths,
|
|
63
|
+
marginLefts,
|
|
64
|
+
marginRights,
|
|
56
65
|
marginBottoms
|
|
57
66
|
};
|
|
58
67
|
}
|
|
@@ -9,7 +9,7 @@ const DEFAULT_MARGINS = {
|
|
|
9
9
|
bottom: 96,
|
|
10
10
|
left: 96
|
|
11
11
|
};
|
|
12
|
-
const twipsToPixels = (twips) =>
|
|
12
|
+
const twipsToPixels = (twips) => twips / 1440 * 96;
|
|
13
13
|
/**
|
|
14
14
|
* Convert an offset-like twip dimension to px. Explicit 0 is meaningful for
|
|
15
15
|
* page margins and header/footer distances; only absence should use fallback.
|
|
@@ -18,6 +18,11 @@ const IMAGE_CSS_FLOATS = [
|
|
|
18
18
|
"right",
|
|
19
19
|
"none"
|
|
20
20
|
];
|
|
21
|
+
const TEXT_BOX_AUTO_FIT_VALUES = [
|
|
22
|
+
"none",
|
|
23
|
+
"normal",
|
|
24
|
+
"shape"
|
|
25
|
+
];
|
|
21
26
|
const FIELD_KINDS = ["simple", "complex"];
|
|
22
27
|
const MATH_DISPLAYS = ["inline", "block"];
|
|
23
28
|
const SHAPE_FILL_TYPES = [
|
|
@@ -156,6 +161,11 @@ const readParagraphAttrs = (node) => {
|
|
|
156
161
|
optionalBoolean(attrs, "listMarkerHidden", "paragraph.attrs.listMarkerHidden", issues);
|
|
157
162
|
optionalString(attrs, "listMarkerFontFamily", "paragraph.attrs.listMarkerFontFamily", issues);
|
|
158
163
|
optionalNumber(attrs, "listMarkerFontSize", "paragraph.attrs.listMarkerFontSize", issues);
|
|
164
|
+
optionalOneOf(attrs, "listMarkerAlignment", "paragraph.attrs.listMarkerAlignment", issues, [
|
|
165
|
+
"left",
|
|
166
|
+
"center",
|
|
167
|
+
"right"
|
|
168
|
+
]);
|
|
159
169
|
optionalString(attrs, "listMarkerSuffix", "paragraph.attrs.listMarkerSuffix", issues);
|
|
160
170
|
optionalBoolean(attrs, "listMarkerAllCaps", "paragraph.attrs.listMarkerAllCaps", issues);
|
|
161
171
|
optionalNumber(attrs, "listImplicitChildLevelAdvances", "paragraph.attrs.listImplicitChildLevelAdvances", issues);
|
|
@@ -410,6 +420,7 @@ const readTextBoxAttrs = (node) => {
|
|
|
410
420
|
expectNodeType(node, "textBox", issues);
|
|
411
421
|
optionalNumber(attrs, "width", "textBox.attrs.width", issues);
|
|
412
422
|
optionalNumber(attrs, "height", "textBox.attrs.height", issues);
|
|
423
|
+
optionalOneOf(attrs, "autoFit", "textBox.attrs.autoFit", issues, TEXT_BOX_AUTO_FIT_VALUES);
|
|
413
424
|
optionalString(attrs, "textBoxId", "textBox.attrs.textBoxId", issues);
|
|
414
425
|
optionalString(attrs, "fillColor", "textBox.attrs.fillColor", issues);
|
|
415
426
|
optionalNumber(attrs, "outlineWidth", "textBox.attrs.outlineWidth", issues);
|
|
@@ -210,6 +210,7 @@ function listRenderingFromAttrs(attrs) {
|
|
|
210
210
|
...attrs.listMarkerHidden != null && { markerHidden: attrs.listMarkerHidden },
|
|
211
211
|
...attrs.listMarkerFontFamily != null && { markerFontFamily: attrs.listMarkerFontFamily },
|
|
212
212
|
...attrs.listMarkerFontSize != null && { markerFontSize: attrs.listMarkerFontSize },
|
|
213
|
+
...attrs.listMarkerAlignment != null && { markerAlignment: attrs.listMarkerAlignment },
|
|
213
214
|
...attrs.listMarkerSuffix != null && { markerSuffix: attrs.listMarkerSuffix },
|
|
214
215
|
...attrs.listMarkerAllCaps != null && { markerAllCaps: attrs.listMarkerAllCaps },
|
|
215
216
|
...attrs.listImplicitChildLevelAdvances != null && { implicitChildLevelAdvances: attrs.listImplicitChildLevelAdvances },
|
|
@@ -1516,6 +1517,7 @@ function convertPMTextBox(node) {
|
|
|
1516
1517
|
type: "paragraph",
|
|
1517
1518
|
content: []
|
|
1518
1519
|
}],
|
|
1520
|
+
...attrs.autoFit !== void 0 ? { autoFit: attrs.autoFit } : {},
|
|
1519
1521
|
margins: (() => {
|
|
1520
1522
|
const m = {};
|
|
1521
1523
|
if (typeof attrs.marginTop === "number") m.top = pixelsToEmu(attrs.marginTop);
|
|
@@ -227,6 +227,7 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
|
|
|
227
227
|
if (paragraph.listRendering?.markerHidden) attrs.listMarkerHidden = paragraph.listRendering.markerHidden;
|
|
228
228
|
if (paragraph.listRendering?.markerFontFamily) attrs.listMarkerFontFamily = paragraph.listRendering.markerFontFamily;
|
|
229
229
|
if (paragraph.listRendering?.markerFontSize) attrs.listMarkerFontSize = paragraph.listRendering.markerFontSize;
|
|
230
|
+
if (paragraph.listRendering?.markerAlignment) attrs.listMarkerAlignment = paragraph.listRendering.markerAlignment;
|
|
230
231
|
if (paragraph.listRendering?.markerSuffix) attrs.listMarkerSuffix = paragraph.listRendering.markerSuffix;
|
|
231
232
|
if (paragraph.listRendering?.markerAllCaps) attrs.listMarkerAllCaps = paragraph.listRendering.markerAllCaps;
|
|
232
233
|
if (paragraph.listRendering?.implicitChildLevelAdvances !== void 0) attrs.listImplicitChildLevelAdvances = paragraph.listRendering.implicitChildLevelAdvances;
|
|
@@ -259,11 +260,11 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
|
|
|
259
260
|
if (formatting?.spaceBefore === void 0 && tableParagraphOverlay?.spaceBefore === void 0 && paragraphStyle?.pPr?.spaceBefore === void 0 && docDefaultSpacing?.spaceBefore !== void 0) spacingFromDocDefaults.before = true;
|
|
260
261
|
if (formatting?.spaceAfter === void 0 && tableParagraphOverlay?.spaceAfter === void 0 && paragraphStyle?.pPr?.spaceAfter === void 0 && docDefaultSpacing?.spaceAfter !== void 0) spacingFromDocDefaults.after = true;
|
|
261
262
|
if (spacingFromDocDefaults.before || spacingFromDocDefaults.after) attrs.spacingFromDocDefaults = spacingFromDocDefaults;
|
|
262
|
-
|
|
263
|
+
const numberingStyleIndent = formatting?.numPr?.numId === 0 && stylePpr?.numPr !== void 0 && stylePpr.numPr.numId !== 0 ? void 0 : stylePpr;
|
|
264
|
+
set("indentLeft", formatting?.indentLeft ?? numberingStyleIndent?.indentLeft);
|
|
263
265
|
set("indentRight", formatting?.indentRight ?? stylePpr?.indentRight);
|
|
264
|
-
|
|
265
|
-
set("
|
|
266
|
-
set("hangingIndent", formatting?.hangingIndent ?? styleFirstLine?.hangingIndent);
|
|
266
|
+
set("indentFirstLine", formatting?.indentFirstLine ?? numberingStyleIndent?.indentFirstLine);
|
|
267
|
+
set("hangingIndent", formatting?.hangingIndent ?? numberingStyleIndent?.hangingIndent);
|
|
267
268
|
set("borders", formatting?.borders ?? stylePpr?.borders);
|
|
268
269
|
set("shading", formatting?.shading ?? stylePpr?.shading);
|
|
269
270
|
set("tabs", formatting?.tabs ?? stylePpr?.tabs);
|
|
@@ -301,7 +302,7 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
|
|
|
301
302
|
set("runInWithNext", formatting?.runInWithNext);
|
|
302
303
|
set("outlineLevel", formatting?.outlineLevel);
|
|
303
304
|
set("direction", directionFromBidi(formatting?.bidi));
|
|
304
|
-
set("defaultTextFormatting", resolveTextFormatting(formatting?.runProperties, styleResolver));
|
|
305
|
+
set("defaultTextFormatting", stripParagraphMarkOnlyFormatting(resolveTextFormatting(formatting?.runProperties, styleResolver) ?? {}));
|
|
305
306
|
}
|
|
306
307
|
if (paragraph.sectionProperties) {
|
|
307
308
|
attrs._sectionProperties = paragraph.sectionProperties;
|
|
@@ -401,33 +402,33 @@ function hasDirectRunFormatting(formatting) {
|
|
|
401
402
|
return Object.entries(formatting).some(([key, value]) => key !== "styleId" && value !== void 0);
|
|
402
403
|
}
|
|
403
404
|
function stripParagraphMarkOnlyFormatting(formatting) {
|
|
404
|
-
const { allCaps: _ac, highlight: _h, shading: _s, smallCaps: _sc, ...rest } = formatting;
|
|
405
|
+
const { allCaps: _ac, highlight: _h, shading: _s, smallCaps: _sc, vertAlign: _va, ...rest } = formatting;
|
|
405
406
|
return Object.keys(rest).length > 0 ? rest : void 0;
|
|
406
407
|
}
|
|
407
408
|
function suppressParagraphMarkFormatting(base, paragraphMark, direct, paragraphMarkPrecedesStyle = false) {
|
|
408
409
|
if (!paragraphMark) return base;
|
|
409
410
|
const result = (paragraphMarkPrecedesStyle ? mergeTextFormatting(paragraphMark, base) : mergeTextFormatting(base, paragraphMark)) ?? {};
|
|
410
|
-
suppressBooleanParagraphMark(result, paragraphMark, direct, "bold");
|
|
411
|
-
suppressBooleanParagraphMark(result, paragraphMark, direct, "italic");
|
|
412
|
-
suppressBooleanParagraphMark(result, paragraphMark, direct, "strike");
|
|
413
|
-
suppressBooleanParagraphMark(result, paragraphMark, direct, "doubleStrike");
|
|
414
|
-
suppressBooleanParagraphMark(result, paragraphMark, direct, "allCaps");
|
|
415
|
-
suppressBooleanParagraphMark(result, paragraphMark, direct, "smallCaps");
|
|
416
|
-
suppressBooleanParagraphMark(result, paragraphMark, direct, "hidden");
|
|
417
|
-
suppressBooleanParagraphMark(result, paragraphMark, direct, "emboss");
|
|
418
|
-
suppressBooleanParagraphMark(result, paragraphMark, direct, "imprint");
|
|
419
|
-
suppressBooleanParagraphMark(result, paragraphMark, direct, "shadow");
|
|
420
|
-
suppressBooleanParagraphMark(result, paragraphMark, direct, "outline");
|
|
421
|
-
suppressBooleanParagraphMark(result, paragraphMark, direct, "rtl");
|
|
411
|
+
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "bold");
|
|
412
|
+
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "italic");
|
|
413
|
+
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "strike");
|
|
414
|
+
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "doubleStrike");
|
|
415
|
+
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "allCaps");
|
|
416
|
+
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "smallCaps");
|
|
417
|
+
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "hidden");
|
|
418
|
+
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "emboss");
|
|
419
|
+
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "imprint");
|
|
420
|
+
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "shadow");
|
|
421
|
+
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "outline");
|
|
422
|
+
suppressBooleanParagraphMark(result, base, paragraphMark, direct, "rtl");
|
|
422
423
|
if (paragraphMark.fontSize !== void 0 && direct?.fontSize === void 0 && base?.fontSize !== void 0) result.fontSize = base.fontSize;
|
|
423
424
|
if (paragraphMark.fontSizeCs !== void 0 && direct?.fontSizeCs === void 0 && base?.fontSizeCs !== void 0) result.fontSizeCs = base.fontSizeCs;
|
|
424
425
|
if (paragraphMark.underline !== void 0 && direct?.underline === void 0) result.underline = { style: "none" };
|
|
425
426
|
if (paragraphMark.spacing !== void 0 && direct?.spacing === void 0) result.spacing = 0;
|
|
426
427
|
return Object.keys(result).length > 0 ? result : void 0;
|
|
427
428
|
}
|
|
428
|
-
function suppressBooleanParagraphMark(result, paragraphMark, direct, key) {
|
|
429
|
+
function suppressBooleanParagraphMark(result, base, paragraphMark, direct, key) {
|
|
429
430
|
if (paragraphMark[key] === void 0 || direct?.[key] !== void 0) return;
|
|
430
|
-
result[key] = false;
|
|
431
|
+
result[key] = base?.[key] ?? false;
|
|
431
432
|
}
|
|
432
433
|
function resolveTextFormatting(formatting, styleResolver) {
|
|
433
434
|
if (!formatting) return styleResolver?.resolveRunStyle(null);
|
|
@@ -456,7 +457,7 @@ function calculateRowSpans(table) {
|
|
|
456
457
|
clearActiveVerticalMerges(activeMerges, result);
|
|
457
458
|
continue;
|
|
458
459
|
}
|
|
459
|
-
let colIndex = 0;
|
|
460
|
+
let colIndex = row.formatting?.gridBefore ?? 0;
|
|
460
461
|
const rowCells = row.cells.map((cell) => {
|
|
461
462
|
const colspan = cell.formatting?.gridSpan ?? 1;
|
|
462
463
|
const vMerge = cell.formatting?.vMerge;
|
|
@@ -549,6 +550,7 @@ function convertTable(table, styleResolver, context) {
|
|
|
549
550
|
const fallbackTableStyle = tableStyleId ? void 0 : defaultTableStyle;
|
|
550
551
|
const conditionalTableStyleId = tableStyle?.styleId ?? fallbackTableStyle?.styleId;
|
|
551
552
|
const resolvedTableBorders = table.formatting?.borders ?? tableStyle?.tblPr?.borders ?? fallbackTableStyle?.tblPr?.borders;
|
|
553
|
+
const resolvedTableIndent = table.formatting?.indent ?? tableStyle?.tblPr?.indent ?? fallbackTableStyle?.tblPr?.indent;
|
|
552
554
|
const tableCellMargins = table.formatting?.cellMargins ?? tableStyle?.tblPr?.cellMargins ?? fallbackTableStyle?.tblPr?.cellMargins;
|
|
553
555
|
let cellMarginsAttr;
|
|
554
556
|
if (tableCellMargins) {
|
|
@@ -569,6 +571,7 @@ function convertTable(table, styleResolver, context) {
|
|
|
569
571
|
if (cellMarginsAttr) attrs.cellMargins = cellMarginsAttr;
|
|
570
572
|
if (table.formatting?.look) attrs.look = table.formatting.look;
|
|
571
573
|
if (table.formatting?.borders) attrs.borders = table.formatting.borders;
|
|
574
|
+
if (resolvedTableIndent) attrs._resolvedIndent = resolvedTableIndent;
|
|
572
575
|
if (table.formatting) attrs._originalFormatting = table.formatting;
|
|
573
576
|
if (table.propertyChanges && table.propertyChanges.length > 0) attrs.tblPrChange = [...table.propertyChanges];
|
|
574
577
|
const conditionalStyles = {};
|
|
@@ -614,8 +617,9 @@ function convertTable(table, styleResolver, context) {
|
|
|
614
617
|
function countTableColumns(rows) {
|
|
615
618
|
let maxColumns = 0;
|
|
616
619
|
for (const row of rows) {
|
|
617
|
-
let rowColumns = 0;
|
|
620
|
+
let rowColumns = row.formatting?.gridBefore ?? 0;
|
|
618
621
|
for (const cell of row.cells) rowColumns += cell.formatting?.gridSpan ?? 1;
|
|
622
|
+
rowColumns += row.formatting?.gridAfter ?? 0;
|
|
619
623
|
maxColumns = Math.max(maxColumns, rowColumns);
|
|
620
624
|
}
|
|
621
625
|
return maxColumns;
|
|
@@ -649,7 +653,7 @@ function convertTableRow(row, styleResolver, context, isHeaderRow, columnWidths,
|
|
|
649
653
|
if (totalCols > 1) fallback.formatting = { gridSpan: totalCols };
|
|
650
654
|
effectiveCells = [fallback];
|
|
651
655
|
}
|
|
652
|
-
let colIndex = 0;
|
|
656
|
+
let colIndex = row.formatting?.gridBefore ?? 0;
|
|
653
657
|
const cells = [];
|
|
654
658
|
for (const cellIndex_item of effectiveCells) {
|
|
655
659
|
const cell = cellIndex_item;
|
|
@@ -1262,6 +1266,7 @@ function extractTextBoxesFromParagraph(paragraph) {
|
|
|
1262
1266
|
if (shape.fill) textBox.fill = shape.fill;
|
|
1263
1267
|
if (shape.outline) textBox.outline = shape.outline;
|
|
1264
1268
|
if (shape.textBody.margins) textBox.margins = shape.textBody.margins;
|
|
1269
|
+
if (shape.textBody.autoFit) textBox.autoFit = shape.textBody.autoFit;
|
|
1265
1270
|
textBoxes.push(textBox);
|
|
1266
1271
|
}
|
|
1267
1272
|
}
|
|
@@ -1330,6 +1335,7 @@ function convertTextBox(textBox, styleResolver, options = {}) {
|
|
|
1330
1335
|
return schema.node("textBox", {
|
|
1331
1336
|
width: widthPx,
|
|
1332
1337
|
height: heightPx,
|
|
1338
|
+
autoFit: textBox.autoFit,
|
|
1333
1339
|
textBoxId: textBox.id,
|
|
1334
1340
|
fillColor,
|
|
1335
1341
|
outlineWidth,
|
|
@@ -199,6 +199,7 @@ const paragraphNodeSpec = {
|
|
|
199
199
|
listMarkerHidden: { default: null },
|
|
200
200
|
listMarkerFontFamily: { default: null },
|
|
201
201
|
listMarkerFontSize: { default: null },
|
|
202
|
+
listMarkerAlignment: { default: null },
|
|
202
203
|
listMarkerSuffix: { default: null },
|
|
203
204
|
listMarkerAllCaps: { default: null },
|
|
204
205
|
listImplicitChildLevelAdvances: { default: null },
|