@stll/folio-core 0.25.1 → 0.25.3
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 +6 -0
- package/dist/ai-edits/headless.js +60 -7
- package/dist/ai-edits/read.d.ts +26 -1
- package/dist/ai-edits/read.js +26 -1
- package/dist/docx/rezip.d.ts +2 -0
- package/dist/docx/rezip.js +61 -58
- package/dist/docx/selectiveXmlPatch.d.ts +24 -1
- package/dist/docx/selectiveXmlPatch.js +186 -1
- package/dist/docx/xmlParser.d.ts +7 -1
- package/dist/docx/xmlParser.js +11 -4
- package/dist/layout-bridge/convert/toFlowBlocks.js +3 -4
- package/dist/layout-bridge/engine/clickToPosition.js +13 -28
- package/dist/layout-bridge/engine/hitTest.d.ts +2 -0
- package/dist/layout-bridge/engine/hitTest.js +28 -13
- package/dist/layout-bridge/engine/selectionRects.js +26 -15
- package/dist/layout-engine/index.js +6 -9
- package/dist/layout-engine/measure/hyperlinkInstance.d.ts +6 -0
- package/dist/layout-engine/measure/hyperlinkInstance.js +8 -0
- package/dist/layout-engine/measure/tableCellGrid.d.ts +15 -1
- package/dist/layout-engine/measure/tableCellGrid.js +29 -6
- package/dist/layout-engine/measure/tableInlinePlacement.d.ts +12 -0
- package/dist/layout-engine/measure/tableInlinePlacement.js +22 -0
- package/dist/layout-engine/types.d.ts +1 -1
- package/dist/layout-painter/renderParagraph.d.ts +3 -0
- package/dist/layout-painter/renderParagraph.js +13 -19
- package/dist/layout-painter/renderTable.js +36 -74
- package/dist/prosemirror/conversion/toProseDoc.js +42 -44
- package/dist/prosemirror/extensions/marks/CommentExtension.js +1 -0
- package/dist/utils/paragraphInlineLayout.d.ts +14 -0
- package/dist/utils/paragraphInlineLayout.js +25 -0
- package/package.json +1 -1
|
@@ -5,10 +5,24 @@ type TableCellGrid = {
|
|
|
5
5
|
sourceCellsByRow: ReadonlyMap<number, ReadonlyMap<number, TableCell>>;
|
|
6
6
|
sourceColumnsByCell: ReadonlyMap<TableCell, number>;
|
|
7
7
|
};
|
|
8
|
+
type TableCellPlacement = {
|
|
9
|
+
sourceColumn: number;
|
|
10
|
+
columnSpan: number;
|
|
11
|
+
left: number;
|
|
12
|
+
width: number;
|
|
13
|
+
};
|
|
14
|
+
type TableCellPlacements = ReadonlyMap<TableCell, TableCellPlacement>;
|
|
15
|
+
type BuildTableCellPlacementsOptions = {
|
|
16
|
+
grid: TableCellGrid;
|
|
17
|
+
columnWidths: readonly number[];
|
|
18
|
+
bidi: boolean;
|
|
19
|
+
};
|
|
8
20
|
declare const buildTableCellGrid: (rows: readonly TableRow[], columnCount: number) => TableCellGrid;
|
|
9
21
|
declare const getFirstAvailableColumn: (grid: TableCellGrid, rowIndex: number, startingColumn: number) => number;
|
|
10
22
|
declare const getSourceCellAt: (grid: TableCellGrid, rowIndex: number, columnIndex: number) => TableCell | undefined;
|
|
11
23
|
declare const getSourceCellColumn: (grid: TableCellGrid, cell: TableCell) => number | undefined;
|
|
24
|
+
/** Resolve all source cells to canonical logical columns and physical boxes. */
|
|
25
|
+
declare const buildTableCellPlacements: ({ grid, columnWidths, bidi }: BuildTableCellPlacementsOptions) => TableCellPlacements;
|
|
12
26
|
declare const getTableCellVerticalBorderHeight: (grid: TableCellGrid, cell: TableCell | undefined, rowIndex: number) => number;
|
|
13
27
|
//#endregion
|
|
14
|
-
export { TableCellGrid, buildTableCellGrid, getFirstAvailableColumn, getSourceCellAt, getSourceCellColumn, getTableCellVerticalBorderHeight };
|
|
28
|
+
export { TableCellGrid, TableCellPlacement, TableCellPlacements, buildTableCellGrid, buildTableCellPlacements, getFirstAvailableColumn, getSourceCellAt, getSourceCellColumn, getTableCellVerticalBorderHeight };
|
|
@@ -6,10 +6,11 @@ const buildTableCellGrid = (rows, columnCount) => {
|
|
|
6
6
|
for (let rowIndex = 0; rowIndex < rows.length; rowIndex++) {
|
|
7
7
|
const row = rows[rowIndex];
|
|
8
8
|
if (!row) continue;
|
|
9
|
-
|
|
9
|
+
const gridBefore = Math.max(0, Math.min(columnCount, Math.trunc(row.gridBefore ?? 0)));
|
|
10
|
+
let columnIndex = firstAvailableColumn(occupiedColumnsByRow.get(rowIndex), gridBefore);
|
|
10
11
|
for (const cell of row.cells) {
|
|
11
|
-
const columnSpan = cell.colSpan ?? 1;
|
|
12
|
-
const rowSpan = cell.rowSpan ?? 1;
|
|
12
|
+
const columnSpan = Math.max(1, Math.trunc(cell.colSpan ?? 1));
|
|
13
|
+
const rowSpan = Math.max(1, Math.trunc(cell.rowSpan ?? 1));
|
|
13
14
|
sourceColumnsByCell.set(cell, columnIndex);
|
|
14
15
|
const rowEnd = Math.min(rows.length, rowIndex + rowSpan);
|
|
15
16
|
const columnEnd = Math.min(columnCount, columnIndex + columnSpan);
|
|
@@ -17,9 +18,9 @@ const buildTableCellGrid = (rows, columnCount) => {
|
|
|
17
18
|
const cellsByColumn = getOrCreateCellRow(sourceCellsByRow, gridRowIndex);
|
|
18
19
|
for (let gridColumnIndex = columnIndex; gridColumnIndex < columnEnd; gridColumnIndex++) cellsByColumn.set(gridColumnIndex, cell);
|
|
19
20
|
}
|
|
20
|
-
if (rowSpan > 1) for (let spannedRowIndex = rowIndex + 1; spannedRowIndex <
|
|
21
|
+
if (rowSpan > 1) for (let spannedRowIndex = rowIndex + 1; spannedRowIndex < rowEnd; spannedRowIndex++) {
|
|
21
22
|
const occupied = getOrCreateOccupiedRow(occupiedColumnsByRow, spannedRowIndex);
|
|
22
|
-
for (let
|
|
23
|
+
for (let gridColumnIndex = columnIndex; gridColumnIndex < columnEnd; gridColumnIndex++) occupied.add(gridColumnIndex);
|
|
23
24
|
}
|
|
24
25
|
columnIndex = firstAvailableColumn(occupiedColumnsByRow.get(rowIndex), columnIndex + columnSpan);
|
|
25
26
|
}
|
|
@@ -33,6 +34,28 @@ const buildTableCellGrid = (rows, columnCount) => {
|
|
|
33
34
|
const getFirstAvailableColumn = (grid, rowIndex, startingColumn) => firstAvailableColumn(grid.occupiedColumnsByRow.get(rowIndex), startingColumn);
|
|
34
35
|
const getSourceCellAt = (grid, rowIndex, columnIndex) => grid.sourceCellsByRow.get(rowIndex)?.get(columnIndex);
|
|
35
36
|
const getSourceCellColumn = (grid, cell) => grid.sourceColumnsByCell.get(cell);
|
|
37
|
+
/** Resolve all source cells to canonical logical columns and physical boxes. */
|
|
38
|
+
const buildTableCellPlacements = ({ grid, columnWidths, bidi }) => {
|
|
39
|
+
const columnOffsets = [0];
|
|
40
|
+
for (const columnWidth of columnWidths) columnOffsets.push((columnOffsets.at(-1) ?? 0) + columnWidth);
|
|
41
|
+
const tableWidth = columnOffsets.at(-1) ?? 0;
|
|
42
|
+
const placements = /* @__PURE__ */ new Map();
|
|
43
|
+
for (const [cell, sourceColumn] of grid.sourceColumnsByCell) {
|
|
44
|
+
if (sourceColumn < 0 || sourceColumn >= columnWidths.length) continue;
|
|
45
|
+
const declaredColumnSpan = Math.max(1, Math.trunc(cell.colSpan ?? 1));
|
|
46
|
+
const columnSpan = Math.min(declaredColumnSpan, columnWidths.length - sourceColumn);
|
|
47
|
+
const logicalLeft = columnOffsets.at(sourceColumn) ?? 0;
|
|
48
|
+
const logicalRight = columnOffsets.at(sourceColumn + columnSpan) ?? logicalLeft;
|
|
49
|
+
const width = logicalRight - logicalLeft;
|
|
50
|
+
placements.set(cell, {
|
|
51
|
+
sourceColumn,
|
|
52
|
+
columnSpan,
|
|
53
|
+
left: bidi ? tableWidth - logicalRight : logicalLeft,
|
|
54
|
+
width
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
return placements;
|
|
58
|
+
};
|
|
36
59
|
const getTableCellVerticalBorderHeight = (grid, cell, rowIndex) => {
|
|
37
60
|
const sourceColumn = cell ? getSourceCellColumn(grid, cell) : void 0;
|
|
38
61
|
const aboveBottom = (sourceColumn === void 0 ? void 0 : getSourceCellAt(grid, rowIndex - 1, sourceColumn))?.borders?.bottom;
|
|
@@ -59,4 +82,4 @@ const getOrCreateOccupiedRow = (occupiedColumnsByRow, rowIndex) => {
|
|
|
59
82
|
return occupiedColumns;
|
|
60
83
|
};
|
|
61
84
|
//#endregion
|
|
62
|
-
export { buildTableCellGrid, getFirstAvailableColumn, getSourceCellAt, getSourceCellColumn, getTableCellVerticalBorderHeight };
|
|
85
|
+
export { buildTableCellGrid, buildTableCellPlacements, getFirstAvailableColumn, getSourceCellAt, getSourceCellColumn, getTableCellVerticalBorderHeight };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TableBlock } from "../types.js";
|
|
2
|
+
//#region src/layout-engine/measure/tableInlinePlacement.d.ts
|
|
3
|
+
type TableInlinePlacement = {
|
|
4
|
+
alignment: "center";
|
|
5
|
+
} | {
|
|
6
|
+
alignment: "left" | "right";
|
|
7
|
+
offset: number;
|
|
8
|
+
};
|
|
9
|
+
/** Resolve an inline table's horizontal anchor without losing RTL leading-edge semantics. */
|
|
10
|
+
declare const resolveTableInlinePlacement: (table: Pick<TableBlock, "bidi" | "indent" | "justification" | "rows">) => TableInlinePlacement;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { resolveTableInlinePlacement };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { resolveTableCellPadding } from "../types.js";
|
|
2
|
+
//#region src/layout-engine/measure/tableInlinePlacement.ts
|
|
3
|
+
/** Resolve an inline table's horizontal anchor without losing RTL leading-edge semantics. */
|
|
4
|
+
const resolveTableInlinePlacement = (table) => {
|
|
5
|
+
if (table.justification === "center") return { alignment: "center" };
|
|
6
|
+
if (table.justification === "right") return {
|
|
7
|
+
alignment: "right",
|
|
8
|
+
offset: 0
|
|
9
|
+
};
|
|
10
|
+
const firstCell = table.rows.at(0)?.cells.at(0);
|
|
11
|
+
const firstCellPadding = firstCell ? resolveTableCellPadding(firstCell) : void 0;
|
|
12
|
+
if (table.justification === "left" || table.bidi !== true) return {
|
|
13
|
+
alignment: "left",
|
|
14
|
+
offset: table.indent ?? -(firstCellPadding?.left ?? 0)
|
|
15
|
+
};
|
|
16
|
+
return {
|
|
17
|
+
alignment: "right",
|
|
18
|
+
offset: table.indent ?? -(firstCellPadding?.right ?? 0)
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
//#endregion
|
|
22
|
+
export { resolveTableInlinePlacement };
|
|
@@ -632,7 +632,7 @@ type TableBlock = {
|
|
|
632
632
|
layout?: "fixed" | "autofit";
|
|
633
633
|
/** Table horizontal alignment */
|
|
634
634
|
justification?: "left" | "center" | "right";
|
|
635
|
-
/** Table indent from
|
|
635
|
+
/** Table indent from the leading margin (in pixels, from w:tblInd). */
|
|
636
636
|
indent?: number;
|
|
637
637
|
/** Right-to-left column order (w:bidiVisual): logical column 0 paints on the right. */
|
|
638
638
|
bidi?: boolean;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HyperlinkInfo, MeasuredLine, ParagraphBlock, ParagraphBorders, ParagraphFragment, ParagraphMeasure, Run, TabStop } from "../layout-engine/types.js";
|
|
2
2
|
import { RenderContext } from "./renderUtils.js";
|
|
3
|
+
import { PhysicalParagraphInlineLayout } from "../utils/paragraphInlineLayout.js";
|
|
3
4
|
//#region src/layout-painter/renderParagraph.d.ts
|
|
4
5
|
/**
|
|
5
6
|
* CSS class names for paragraph rendering
|
|
@@ -70,6 +71,8 @@ type RenderLineOptions = {
|
|
|
70
71
|
firstLineIndentPx?: number;
|
|
71
72
|
/** Paragraph base direction for logical first-line indentation. */
|
|
72
73
|
isRtl?: boolean;
|
|
74
|
+
/** Explicit alignment after resolving authored bidi physical sides. */
|
|
75
|
+
explicitAlignment?: PhysicalParagraphInlineLayout["explicitAlignment"];
|
|
73
76
|
/** Full paragraph content-box width before physical indents. */
|
|
74
77
|
contentWidthPx?: number;
|
|
75
78
|
/** Line-specific floating image margins (calculated per-line based on Y overlap) */
|
|
@@ -2,6 +2,7 @@ import { ommlToMathml } from "../docx/mathToMathml.js";
|
|
|
2
2
|
import { parseXmlDocument } from "../docx/xmlParser.js";
|
|
3
3
|
import { evaluateFieldInstruction } from "../fields/evaluateField.js";
|
|
4
4
|
import { hasComplexScriptFormatting, resolveComplexScriptFormatting } from "../layout-engine/measure/complexScriptFormatting.js";
|
|
5
|
+
import { getHyperlinkInstanceIndex } from "../layout-engine/measure/hyperlinkInstance.js";
|
|
5
6
|
import { getListMarkerInlineWidth, getListMarkerVisualOffset, resolveListMarkerFont } from "../layout-engine/measure/listMarkerWidth.js";
|
|
6
7
|
import { DOCX_SCRIPT_FONT_SCALE } from "../layout-engine/measure/measureHelpers.js";
|
|
7
8
|
import { FONT_KERNING_MODE, countCompressibleSpaces, getFontKerningMode, getRunFontKerningMode, toPaintedText } from "../layout-engine/measure/textMeasurementPolicy.js";
|
|
@@ -10,7 +11,7 @@ import { calculateTabWidth } from "../prosemirror/utils/tabCalculator.js";
|
|
|
10
11
|
import { AUTHOR_COLORS, getAuthorColorIdx } from "../utils/authorColors.js";
|
|
11
12
|
import { resolveFontFamily } from "../utils/fontResolver.js";
|
|
12
13
|
import "../utils/fontWeights.js";
|
|
13
|
-
import {
|
|
14
|
+
import { resolvePhysicalParagraphInlineLayout } from "../utils/paragraphInlineLayout.js";
|
|
14
15
|
import { inlineImageBoundingBox, parseRotationDegrees, rotatedBoundingBox } from "../utils/rotationBoundingBox.js";
|
|
15
16
|
import { applySanitizedImageSrc } from "../utils/sanitizeImageSrc.js";
|
|
16
17
|
import { SCRIPT_CLASS, hasCjk, hasComplexScript, segmentByScript } from "../utils/scriptSegments.js";
|
|
@@ -49,6 +50,9 @@ function isTextRun(run) {
|
|
|
49
50
|
return run.kind === "text";
|
|
50
51
|
}
|
|
51
52
|
function hyperlinksMatch(left, right) {
|
|
53
|
+
const leftInstanceIndex = getHyperlinkInstanceIndex(left);
|
|
54
|
+
const rightInstanceIndex = getHyperlinkInstanceIndex(right);
|
|
55
|
+
if (leftInstanceIndex !== void 0 || rightInstanceIndex !== void 0) return leftInstanceIndex === rightInstanceIndex;
|
|
52
56
|
return left.href === right.href && left.tooltip === right.tooltip && left.noDefaultStyle === right.noDefaultStyle;
|
|
53
57
|
}
|
|
54
58
|
function collectLeftToRightDisplayedUrlHyperlinks(runs) {
|
|
@@ -1097,7 +1101,7 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
1097
1101
|
return runEl;
|
|
1098
1102
|
};
|
|
1099
1103
|
const onlyRun = runsForLine.length === 1 ? runsForLine[0] : void 0;
|
|
1100
|
-
if (onlyRun && isMathRun(onlyRun) && onlyRun.display === "block" && block.
|
|
1104
|
+
if (onlyRun && isMathRun(onlyRun) && onlyRun.display === "block" && (options?.explicitAlignment ?? resolvePhysicalParagraphInlineLayout(block).explicitAlignment) !== "right") lineEl.style.textAlign = "center";
|
|
1101
1105
|
if (runsForLine.length === 1 && isImageRun(runsForLine[0])) {
|
|
1102
1106
|
lineEl.style.display = "flex";
|
|
1103
1107
|
lineEl.style.alignItems = "center";
|
|
@@ -1342,26 +1346,15 @@ function renderParagraphFragment(fragment, block, measure, context, options = {}
|
|
|
1342
1346
|
if (fragment.continuesFromPrev) fragmentEl.dataset["continuesFromPrev"] = "true";
|
|
1343
1347
|
if (fragment.continuesOnNext) fragmentEl.dataset["continuesOnNext"] = "true";
|
|
1344
1348
|
const lines = measure.lines.slice(fragment.fromLine, fragment.toLine);
|
|
1345
|
-
const
|
|
1349
|
+
const inlineLayout = resolvePhysicalParagraphInlineLayout(block);
|
|
1350
|
+
const { alignment, indentLeft, indentRight, isRtl } = inlineLayout;
|
|
1346
1351
|
if (block.attrs?.styleId) fragmentEl.dataset["styleId"] = block.attrs.styleId;
|
|
1347
|
-
const isRtl = isRtlParagraph(block);
|
|
1348
1352
|
if (isRtl) fragmentEl.dir = "rtl";
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
else if (isRtl) fragmentEl.style.textAlign = "right";
|
|
1354
|
-
const effectiveAlignment = alignment ?? (isRtl ? "right" : void 0);
|
|
1353
|
+
let fragmentAlignment = alignment;
|
|
1354
|
+
if (alignment === "justify") fragmentAlignment = isRtl ? "right" : "left";
|
|
1355
|
+
fragmentEl.style.textAlign = fragmentAlignment;
|
|
1356
|
+
const effectiveAlignment = alignment;
|
|
1355
1357
|
const indent = block.attrs?.indent;
|
|
1356
|
-
let indentLeft = 0;
|
|
1357
|
-
let indentRight = 0;
|
|
1358
|
-
if (indent) if (isRtl) {
|
|
1359
|
-
if (indent.left !== void 0) indentRight = indent.left;
|
|
1360
|
-
if (indent.right !== void 0) indentLeft = indent.right;
|
|
1361
|
-
} else {
|
|
1362
|
-
if (indent.left !== void 0) indentLeft = indent.left;
|
|
1363
|
-
if (indent.right !== void 0) indentRight = indent.right;
|
|
1364
|
-
}
|
|
1365
1358
|
const borders = block.attrs?.borders;
|
|
1366
1359
|
if (borders) {
|
|
1367
1360
|
const borderStyleToCss = (style) => {
|
|
@@ -1448,6 +1441,7 @@ function renderParagraphFragment(fragment, block, measure, context, options = {}
|
|
|
1448
1441
|
tabLeftIndentPx: indent?.left ?? 0,
|
|
1449
1442
|
firstLineIndentPx: isFirstLine ? firstLineIndentPx : 0,
|
|
1450
1443
|
isRtl,
|
|
1444
|
+
...inlineLayout.explicitAlignment === void 0 ? {} : { explicitAlignment: inlineLayout.explicitAlignment },
|
|
1451
1445
|
contentWidthPx: fragment.width,
|
|
1452
1446
|
context,
|
|
1453
1447
|
floatingMargins: {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { measureParagraph } from "../layout-engine/measure/measureParagraph.js";
|
|
2
2
|
import { buildTableCellFloatingZones, getTableCellContentWidth, getTableCellFloatingImages } from "../layout-engine/measure/tableCellFloating.js";
|
|
3
3
|
import { createTableCellFlowState, finishTableCellFlow, placeTableCellBlock } from "../layout-engine/measure/tableCellFlow.js";
|
|
4
|
-
import {
|
|
4
|
+
import { buildTableCellGrid, buildTableCellPlacements, getSourceCellAt } from "../layout-engine/measure/tableCellGrid.js";
|
|
5
|
+
import { resolveTableInlinePlacement } from "../layout-engine/measure/tableInlinePlacement.js";
|
|
6
|
+
import { isFloatingImageRun, isFloatingTextBoxBlock, resolveTableCellPadding, tableColumnsArePinned } from "../layout-engine/types.js";
|
|
5
7
|
import { applySanitizedImageSrc } from "../utils/sanitizeImageSrc.js";
|
|
6
8
|
import { emuToPixels } from "../utils/units.js";
|
|
7
9
|
import { resolveAnchoredImagePosition } from "./anchoredImagePosition.js";
|
|
@@ -228,11 +230,14 @@ function renderNestedTable(block, measure, context, doc) {
|
|
|
228
230
|
tableEl.style.position = "relative";
|
|
229
231
|
tableEl.style.width = `${measure.totalWidth}px`;
|
|
230
232
|
tableEl.style.display = "block";
|
|
231
|
-
|
|
233
|
+
const placement = resolveTableInlinePlacement(block);
|
|
234
|
+
if (placement.alignment === "center") {
|
|
232
235
|
tableEl.style.marginLeft = "auto";
|
|
233
236
|
tableEl.style.marginRight = "auto";
|
|
234
|
-
} else if (
|
|
235
|
-
|
|
237
|
+
} else if (placement.alignment === "right") {
|
|
238
|
+
tableEl.style.marginLeft = "auto";
|
|
239
|
+
tableEl.style.marginRight = `${placement.offset}px`;
|
|
240
|
+
} else tableEl.style.marginLeft = `${placement.offset}px`;
|
|
236
241
|
tableEl.dataset["blockId"] = String(block.id);
|
|
237
242
|
if (block.pmStart !== void 0) tableEl.dataset["pmStart"] = String(block.pmStart);
|
|
238
243
|
if (block.pmEnd !== void 0) tableEl.dataset["pmEnd"] = String(block.pmEnd);
|
|
@@ -243,9 +248,13 @@ function renderNestedTable(block, measure, context, doc) {
|
|
|
243
248
|
yPos += i_item.height;
|
|
244
249
|
}
|
|
245
250
|
rowYPositions.push(yPos);
|
|
246
|
-
const spanningCells = /* @__PURE__ */ new Map();
|
|
247
251
|
const columnsPinned = tableColumnsArePinned(block);
|
|
248
|
-
const cellGrid = buildTableCellGrid(block, measure.columnWidths.length);
|
|
252
|
+
const cellGrid = buildTableCellGrid(block.rows, measure.columnWidths.length);
|
|
253
|
+
const cellPlacements = buildTableCellPlacements({
|
|
254
|
+
grid: cellGrid,
|
|
255
|
+
columnWidths: measure.columnWidths,
|
|
256
|
+
bidi: block.bidi === true
|
|
257
|
+
});
|
|
249
258
|
let y = 0;
|
|
250
259
|
for (let rowIndex = 0; rowIndex < block.rows.length; rowIndex++) {
|
|
251
260
|
const row = block.rows[rowIndex];
|
|
@@ -264,11 +273,11 @@ function renderNestedTable(block, measure, context, doc) {
|
|
|
264
273
|
totalRows: block.rows.length,
|
|
265
274
|
context,
|
|
266
275
|
doc,
|
|
267
|
-
spanningCells,
|
|
268
276
|
rowYPositions,
|
|
269
277
|
bidi: block.bidi === true,
|
|
270
278
|
columnsPinned,
|
|
271
|
-
cellGrid
|
|
279
|
+
cellGrid,
|
|
280
|
+
cellPlacements
|
|
272
281
|
});
|
|
273
282
|
tableEl.append(rowEl);
|
|
274
283
|
y += rowMeasure.height;
|
|
@@ -320,13 +329,13 @@ function renderCellDiagonalBorder({ border, direction, cellWidth, cellHeight, do
|
|
|
320
329
|
}
|
|
321
330
|
return line;
|
|
322
331
|
}
|
|
323
|
-
function renderTableCell({ cell, cellMeasure, x, rowHeight, borderFlags, columnsPinned, context, doc, contentClip, pageContentPosition }) {
|
|
332
|
+
function renderTableCell({ cell, cellMeasure, x, width, rowHeight, borderFlags, columnsPinned, context, doc, contentClip, pageContentPosition }) {
|
|
324
333
|
const cellEl = doc.createElement("div");
|
|
325
334
|
cellEl.className = TABLE_CLASS_NAMES.cell;
|
|
326
335
|
cellEl.style.position = "absolute";
|
|
327
336
|
cellEl.style.left = `${x}px`;
|
|
328
337
|
cellEl.style.top = "0";
|
|
329
|
-
cellEl.style.width = `${
|
|
338
|
+
cellEl.style.width = `${width}px`;
|
|
330
339
|
cellEl.style.height = `${rowHeight}px`;
|
|
331
340
|
cellEl.style.overflow = "hidden";
|
|
332
341
|
cellEl.style.boxSizing = "border-box";
|
|
@@ -396,7 +405,7 @@ function renderTableCell({ cell, cellMeasure, x, rowHeight, borderFlags, columns
|
|
|
396
405
|
const topLeftToBottomRight = renderCellDiagonalBorder({
|
|
397
406
|
border: cell.borders?.topLeftToBottomRight,
|
|
398
407
|
direction: "top-left-to-bottom-right",
|
|
399
|
-
cellWidth:
|
|
408
|
+
cellWidth: width,
|
|
400
409
|
cellHeight: rowHeight,
|
|
401
410
|
doc
|
|
402
411
|
});
|
|
@@ -404,7 +413,7 @@ function renderTableCell({ cell, cellMeasure, x, rowHeight, borderFlags, columns
|
|
|
404
413
|
const topRightToBottomLeft = renderCellDiagonalBorder({
|
|
405
414
|
border: cell.borders?.topRightToBottomLeft,
|
|
406
415
|
direction: "top-right-to-bottom-left",
|
|
407
|
-
cellWidth:
|
|
416
|
+
cellWidth: width,
|
|
408
417
|
cellHeight: rowHeight,
|
|
409
418
|
doc
|
|
410
419
|
});
|
|
@@ -423,52 +432,23 @@ function renderTableCell({ cell, cellMeasure, x, rowHeight, borderFlags, columns
|
|
|
423
432
|
}
|
|
424
433
|
return cellEl;
|
|
425
434
|
}
|
|
426
|
-
const tableCellGridKey = (rowIndex, columnIndex) => `${rowIndex}:${columnIndex}`;
|
|
427
|
-
function buildTableCellGrid(block, columnCount) {
|
|
428
|
-
const grid = /* @__PURE__ */ new Map();
|
|
429
|
-
for (let rowIndex = 0; rowIndex < block.rows.length; rowIndex++) {
|
|
430
|
-
const row = block.rows[rowIndex];
|
|
431
|
-
if (!row) continue;
|
|
432
|
-
let columnIndex = 0;
|
|
433
|
-
for (const cell of row.cells) {
|
|
434
|
-
while (grid.has(tableCellGridKey(rowIndex, columnIndex))) columnIndex += 1;
|
|
435
|
-
const colSpan = cell.colSpan ?? 1;
|
|
436
|
-
const rowSpan = cell.rowSpan ?? 1;
|
|
437
|
-
const rowEnd = Math.min(block.rows.length, rowIndex + rowSpan);
|
|
438
|
-
const columnEnd = Math.min(columnCount, columnIndex + colSpan);
|
|
439
|
-
for (let gridRow = rowIndex; gridRow < rowEnd; gridRow++) for (let gridColumn = columnIndex; gridColumn < columnEnd; gridColumn++) grid.set(tableCellGridKey(gridRow, gridColumn), cell);
|
|
440
|
-
columnIndex += colSpan;
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
return grid;
|
|
444
|
-
}
|
|
445
435
|
const hasVisibleBorder = (border) => border !== void 0 && border.style !== "none" && border.style !== "nil";
|
|
446
|
-
function renderTableRow({ row, rowMeasure, rowIndex, y, columnWidths, totalRows, context, doc,
|
|
436
|
+
function renderTableRow({ row, rowMeasure, rowIndex, y, columnWidths, totalRows, context, doc, rowYPositions, isFirstRowInFragment, bidi = false, columnsPinned = false, cellGrid, cellPlacements, contentClip, pageContentPosition }) {
|
|
447
437
|
const rowEl = doc.createElement("div");
|
|
448
438
|
rowEl.className = TABLE_CLASS_NAMES.row;
|
|
449
|
-
const tableWidth = bidi ? columnWidths.reduce((sum, columnWidth) => sum + columnWidth, 0) : 0;
|
|
450
439
|
rowEl.style.position = "absolute";
|
|
451
440
|
rowEl.style.left = "0";
|
|
452
441
|
rowEl.style.top = `${y}px`;
|
|
453
442
|
rowEl.style.width = "100%";
|
|
454
443
|
rowEl.style.height = `${rowMeasure.height}px`;
|
|
455
444
|
rowEl.dataset["rowIndex"] = String(rowIndex);
|
|
456
|
-
const occupiedColumns = /* @__PURE__ */ new Set();
|
|
457
|
-
if (spanningCells) {
|
|
458
|
-
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);
|
|
459
|
-
}
|
|
460
|
-
const gridBefore = row.gridBefore ?? 0;
|
|
461
|
-
let x = getTableRowLeadingWidth(row, columnWidths);
|
|
462
|
-
let columnIndex = gridBefore;
|
|
463
|
-
while (occupiedColumns.has(columnIndex)) {
|
|
464
|
-
x += columnWidths[columnIndex] ?? 0;
|
|
465
|
-
columnIndex++;
|
|
466
|
-
}
|
|
467
445
|
for (let cellIndex = 0; cellIndex < row.cells.length; cellIndex++) {
|
|
468
446
|
const cell = row.cells[cellIndex];
|
|
469
447
|
const cellMeasure = rowMeasure.cells[cellIndex];
|
|
470
448
|
if (!cell || !cellMeasure) continue;
|
|
471
|
-
const
|
|
449
|
+
const placement = cellPlacements.get(cell);
|
|
450
|
+
if (!placement) continue;
|
|
451
|
+
const { sourceColumn: columnIndex, columnSpan: colSpan, left: cellLeft, width } = placement;
|
|
472
452
|
const rowSpan = cell.rowSpan ?? 1;
|
|
473
453
|
let cellHeight = rowMeasure.height;
|
|
474
454
|
if (rowSpan > 1 && rowYPositions) {
|
|
@@ -476,24 +456,21 @@ function renderTableRow({ row, rowMeasure, rowIndex, y, columnWidths, totalRows,
|
|
|
476
456
|
for (let r = rowIndex; r < rowIndex + rowSpan && r < rowYPositions.length - 1; r++) cellHeight += (rowYPositions[r + 1] ?? 0) - (rowYPositions[r] ?? 0);
|
|
477
457
|
if (cellHeight === 0) cellHeight = rowMeasure.height * rowSpan;
|
|
478
458
|
}
|
|
479
|
-
let cellWidth = 0;
|
|
480
|
-
for (let c = 0; c < colSpan && columnIndex + c < columnWidths.length; c++) cellWidth += columnWidths[columnIndex + c] ?? 0;
|
|
481
|
-
const cellLeft = bidi ? tableWidth - x - cellWidth : x;
|
|
482
459
|
const isFirstRow = rowIndex === 0 || isFirstRowInFragment === true;
|
|
483
460
|
const isLastRow = rowIndex + rowSpan >= totalRows;
|
|
484
461
|
const atLogicalStart = columnIndex === 0;
|
|
485
462
|
const atLogicalEnd = columnIndex + colSpan >= columnWidths.length;
|
|
486
463
|
const isFirstCol = bidi ? atLogicalEnd : atLogicalStart;
|
|
487
464
|
const isLastCol = bidi ? atLogicalStart : atLogicalEnd;
|
|
488
|
-
const aboveCell = cellGrid
|
|
489
|
-
const
|
|
490
|
-
const leftCell = cellGrid?.get(tableCellGridKey(rowIndex, leftNeighborColumn));
|
|
465
|
+
const aboveCell = getSourceCellAt(cellGrid, rowIndex - 1, columnIndex);
|
|
466
|
+
const leftCell = getSourceCellAt(cellGrid, rowIndex, bidi ? columnIndex + colSpan : columnIndex - 1);
|
|
491
467
|
const drawTop = isFirstRow || !hasVisibleBorder(aboveCell?.borders?.bottom);
|
|
492
468
|
const drawLeft = isFirstCol || !hasVisibleBorder(leftCell?.borders?.right);
|
|
493
469
|
const cellEl = renderTableCell({
|
|
494
470
|
cell,
|
|
495
471
|
cellMeasure,
|
|
496
472
|
x: cellLeft,
|
|
473
|
+
width,
|
|
497
474
|
rowHeight: cellHeight,
|
|
498
475
|
borderFlags: {
|
|
499
476
|
drawTop,
|
|
@@ -515,25 +492,6 @@ function renderTableRow({ row, rowMeasure, rowIndex, y, columnWidths, totalRows,
|
|
|
515
492
|
cellEl.dataset["columnIndex"] = String(columnIndex);
|
|
516
493
|
if (rowSpan > 1) cellEl.dataset["rowSpan"] = String(rowSpan);
|
|
517
494
|
rowEl.append(cellEl);
|
|
518
|
-
if (rowSpan > 1 && spanningCells) {
|
|
519
|
-
const key = `${rowIndex}-${columnIndex}`;
|
|
520
|
-
spanningCells.set(key, {
|
|
521
|
-
cell,
|
|
522
|
-
cellMeasure,
|
|
523
|
-
columnIndex,
|
|
524
|
-
startRow: rowIndex,
|
|
525
|
-
rowSpan,
|
|
526
|
-
colSpan,
|
|
527
|
-
x: cellLeft,
|
|
528
|
-
totalHeight: cellHeight
|
|
529
|
-
});
|
|
530
|
-
}
|
|
531
|
-
x += cellWidth;
|
|
532
|
-
columnIndex += colSpan;
|
|
533
|
-
while (occupiedColumns.has(columnIndex)) {
|
|
534
|
-
x += columnWidths[columnIndex] ?? 0;
|
|
535
|
-
columnIndex++;
|
|
536
|
-
}
|
|
537
495
|
}
|
|
538
496
|
return rowEl;
|
|
539
497
|
}
|
|
@@ -592,9 +550,13 @@ function renderTableFragment(fragment, block, measure, context, options = {}) {
|
|
|
592
550
|
yPos += i_item.height;
|
|
593
551
|
}
|
|
594
552
|
rowYPositions.push(yPos);
|
|
595
|
-
const spanningCells = /* @__PURE__ */ new Map();
|
|
596
553
|
const columnsPinned = tableColumnsArePinned(block);
|
|
597
|
-
const cellGrid = buildTableCellGrid(block, measure.columnWidths.length);
|
|
554
|
+
const cellGrid = buildTableCellGrid(block.rows, measure.columnWidths.length);
|
|
555
|
+
const cellPlacements = buildTableCellPlacements({
|
|
556
|
+
grid: cellGrid,
|
|
557
|
+
columnWidths: measure.columnWidths,
|
|
558
|
+
bidi: block.bidi === true
|
|
559
|
+
});
|
|
598
560
|
const headerRowCount = fragment.headerRowCount ?? 0;
|
|
599
561
|
let y = 0;
|
|
600
562
|
if (headerRowCount > 0 && fragment.continuesFromPrev) for (let hdrIdx = 0; hdrIdx < headerRowCount; hdrIdx++) {
|
|
@@ -614,12 +576,12 @@ function renderTableFragment(fragment, block, measure, context, options = {}) {
|
|
|
614
576
|
totalRows: block.rows.length,
|
|
615
577
|
context,
|
|
616
578
|
doc,
|
|
617
|
-
spanningCells,
|
|
618
579
|
rowYPositions,
|
|
619
580
|
isFirstRowInFragment: hdrIdx === 0,
|
|
620
581
|
bidi: block.bidi === true,
|
|
621
582
|
columnsPinned,
|
|
622
583
|
cellGrid,
|
|
584
|
+
cellPlacements,
|
|
623
585
|
...tablePageContentPosition ? { pageContentPosition: {
|
|
624
586
|
...tablePageContentPosition,
|
|
625
587
|
y: tablePageContentPosition.y + y
|
|
@@ -667,12 +629,12 @@ function renderTableFragment(fragment, block, measure, context, options = {}) {
|
|
|
667
629
|
totalRows: block.rows.length,
|
|
668
630
|
context,
|
|
669
631
|
doc,
|
|
670
|
-
spanningCells,
|
|
671
632
|
rowYPositions,
|
|
672
633
|
isFirstRowInFragment,
|
|
673
634
|
bidi: block.bidi === true,
|
|
674
635
|
columnsPinned,
|
|
675
636
|
cellGrid,
|
|
637
|
+
cellPlacements,
|
|
676
638
|
...contentClip ? { contentClip } : {},
|
|
677
639
|
...tablePageContentPosition ? { pageContentPosition: {
|
|
678
640
|
...tablePageContentPosition,
|