@stll/folio-core 0.25.2 → 0.25.4
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/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/cache.d.ts +1 -4
- package/dist/layout-engine/measure/cache.js +31 -34
- 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 +39 -37
- package/dist/layout-painter/renderTable.js +36 -74
- package/dist/prosemirror/conversion/toProseDoc.js +35 -39
- package/dist/utils/paragraphInlineLayout.d.ts +14 -0
- package/dist/utils/paragraphInlineLayout.js +25 -0
- package/package.json +1 -1
|
@@ -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: {
|
|
@@ -1460,9 +1454,10 @@ function renderParagraphFragment(fragment, block, measure, context, options = {}
|
|
|
1460
1454
|
});
|
|
1461
1455
|
const isFlexLine = lineEl.dataset["flexLine"] === "true";
|
|
1462
1456
|
const lineMarginLeft = Math.min(indentLeft, 0) + lineLeftOffset;
|
|
1457
|
+
const lineMarginRight = Math.min(indentRight, 0) + lineRightOffset;
|
|
1463
1458
|
if (lineMarginLeft !== 0 || lineRightOffset > 0 || indentLeft < 0 || indentRight < 0) {
|
|
1464
1459
|
lineEl.style.marginLeft = `${lineMarginLeft}px`;
|
|
1465
|
-
if (
|
|
1460
|
+
if (lineMarginRight !== 0) lineEl.style.marginRight = `${lineMarginRight}px`;
|
|
1466
1461
|
const constrainedWidth = lineAvailableWidth - lineLeftOffset - lineRightOffset;
|
|
1467
1462
|
if (constrainedWidth > 0) lineEl.style.width = `${constrainedWidth}px`;
|
|
1468
1463
|
}
|
|
@@ -1482,27 +1477,33 @@ function renderParagraphFragment(fragment, block, measure, context, options = {}
|
|
|
1482
1477
|
if (isFirstLine && block.attrs?.listMarker && !block.attrs.listMarkerHidden) {
|
|
1483
1478
|
const hanging = indent?.hanging ?? 0;
|
|
1484
1479
|
const firstLine = indent?.firstLine ?? 0;
|
|
1485
|
-
const
|
|
1486
|
-
|
|
1480
|
+
const markerPhysicalStart = isRtl ? "right" : "left";
|
|
1481
|
+
const markerIndent = markerPhysicalStart === "right" ? indentRight : indentLeft;
|
|
1482
|
+
const markerStart = hanging > 0 ? markerIndent - hanging : markerIndent + firstLine;
|
|
1483
|
+
const logicalMarkerVisualOffset = getListMarkerVisualOffset(block);
|
|
1484
|
+
if (markerPhysicalStart === "right") lineEl.style.paddingRight = `${Math.max(0, markerStart)}px`;
|
|
1485
|
+
else lineEl.style.paddingLeft = `${Math.max(0, markerStart)}px`;
|
|
1487
1486
|
lineEl.style.textIndent = "0";
|
|
1488
|
-
const marker = renderListMarker(
|
|
1489
|
-
|
|
1490
|
-
|
|
1487
|
+
const marker = renderListMarker({
|
|
1488
|
+
marker: block.attrs.listMarker,
|
|
1489
|
+
inlineWidth: getListMarkerInlineWidth(block),
|
|
1490
|
+
visualOffset: markerPhysicalStart === "right" ? -logicalMarkerVisualOffset : logicalMarkerVisualOffset,
|
|
1491
|
+
doc,
|
|
1492
|
+
formatting: resolveListMarkerFont(block),
|
|
1493
|
+
...block.attrs.listMarkerRevision === void 0 ? {} : { revision: block.attrs.listMarkerRevision },
|
|
1494
|
+
...block.attrs.listMarkerSecondSlotOffsetTwips === void 0 ? {} : { secondSlotOffsetTwips: block.attrs.listMarkerSecondSlotOffsetTwips },
|
|
1495
|
+
physicalStart: markerPhysicalStart
|
|
1496
|
+
});
|
|
1497
|
+
const markerMarginLeft = markerStart - (markerPhysicalStart === "right" ? Math.min(indentRight, 0) : Math.min(indentLeft, 0));
|
|
1498
|
+
if (markerMarginLeft < 0) if (markerPhysicalStart === "right") marker.style.marginRight = `${markerMarginLeft}px`;
|
|
1499
|
+
else marker.style.marginLeft = `${markerMarginLeft}px`;
|
|
1491
1500
|
lineEl.prepend(marker);
|
|
1492
1501
|
}
|
|
1493
1502
|
fragmentEl.append(lineEl);
|
|
1494
1503
|
}
|
|
1495
1504
|
return fragmentEl;
|
|
1496
1505
|
}
|
|
1497
|
-
|
|
1498
|
-
* Render a list marker element as an inline-block at the start of the first
|
|
1499
|
-
* body line. `inlineWidth` (from `getListMarkerInlineWidth`) sizes the marker
|
|
1500
|
-
* so the body text aligns at the next tab stop per ECMA-376 §17.9.25 —
|
|
1501
|
-
* this honours `w:suff` (`tab` / `space` / `nothing`) and the document's
|
|
1502
|
-
* tab grid. Long markers like "1.1.1." therefore grow to the next stop
|
|
1503
|
-
* instead of butting against the body text.
|
|
1504
|
-
*/
|
|
1505
|
-
function renderListMarker(marker, inlineWidth, visualOffset, doc, formatting, revision, secondSlotOffsetTwips) {
|
|
1506
|
+
function renderListMarker({ marker, inlineWidth, visualOffset, doc, formatting, revision, secondSlotOffsetTwips, physicalStart }) {
|
|
1506
1507
|
const span = doc.createElement("span");
|
|
1507
1508
|
span.className = "layout-list-marker";
|
|
1508
1509
|
span.style.display = "inline-block";
|
|
@@ -1511,8 +1512,8 @@ function renderListMarker(marker, inlineWidth, visualOffset, doc, formatting, re
|
|
|
1511
1512
|
if (formatting.bold !== void 0) span.style.fontWeight = formatting.bold ? "700" : "normal";
|
|
1512
1513
|
if (formatting.italic !== void 0) span.style.fontStyle = formatting.italic ? "italic" : "normal";
|
|
1513
1514
|
if (formatting.rtl !== void 0) span.dir = formatting.rtl ? "rtl" : "ltr";
|
|
1514
|
-
span.style.textAlign =
|
|
1515
|
-
span.style.textAlignLast =
|
|
1515
|
+
span.style.textAlign = physicalStart;
|
|
1516
|
+
span.style.textAlignLast = physicalStart;
|
|
1516
1517
|
span.style.boxSizing = "border-box";
|
|
1517
1518
|
span.style.width = `${inlineWidth}px`;
|
|
1518
1519
|
if (visualOffset !== 0) span.style.transform = `translateX(${visualOffset}px)`;
|
|
@@ -1546,7 +1547,8 @@ function renderListMarker(marker, inlineWidth, visualOffset, doc, formatting, re
|
|
|
1546
1547
|
secondSlot.style.display = "inline-block";
|
|
1547
1548
|
span.style.position = "relative";
|
|
1548
1549
|
secondSlot.style.position = "absolute";
|
|
1549
|
-
secondSlot.style.
|
|
1550
|
+
if (physicalStart === "right") secondSlot.style.right = `${secondSlotOffsetTwips / 15}px`;
|
|
1551
|
+
else secondSlot.style.left = `${secondSlotOffsetTwips / 15}px`;
|
|
1550
1552
|
secondSlot.style.top = "0";
|
|
1551
1553
|
span.append(firstSlot, secondSlot);
|
|
1552
1554
|
return span;
|
|
@@ -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,
|
|
@@ -30,6 +30,11 @@ const createTextBoxGroupIdFactory = () => {
|
|
|
30
30
|
let index = 0;
|
|
31
31
|
return () => `${salt}:${index++}`;
|
|
32
32
|
};
|
|
33
|
+
/** Keep imported hyperlink identity unique across every nested conversion scope. */
|
|
34
|
+
const createHyperlinkInstanceIndexAllocator = () => {
|
|
35
|
+
let index = 0;
|
|
36
|
+
return () => index++;
|
|
37
|
+
};
|
|
33
38
|
/**
|
|
34
39
|
* Convert a Document to a ProseMirror document
|
|
35
40
|
*
|
|
@@ -42,6 +47,11 @@ function toProseDoc(document, options) {
|
|
|
42
47
|
const styleResolver = createStyleEngine(options?.styles ?? document.package.styles);
|
|
43
48
|
const theme = options?.theme ?? document.package.theme ?? null;
|
|
44
49
|
const nextTextBoxGroupId = createTextBoxGroupIdFactory();
|
|
50
|
+
const conversionContext = {
|
|
51
|
+
theme,
|
|
52
|
+
nextTextBoxGroupId,
|
|
53
|
+
nextHyperlinkInstanceIndex: createHyperlinkInstanceIndexAllocator()
|
|
54
|
+
};
|
|
45
55
|
const convertBodyBlocks = (blocks) => {
|
|
46
56
|
const out = [];
|
|
47
57
|
for (const block of blocks) if (block.type === "paragraph") {
|
|
@@ -49,10 +59,7 @@ function toProseDoc(document, options) {
|
|
|
49
59
|
if (pbPos === "before") out.push(schema.node("pageBreak"));
|
|
50
60
|
const converted = convertParagraphWithTextBoxes(block, styleResolver, {
|
|
51
61
|
textBoxGroupId: nextTextBoxGroupId(),
|
|
52
|
-
context:
|
|
53
|
-
theme,
|
|
54
|
-
nextTextBoxGroupId
|
|
55
|
-
}
|
|
62
|
+
context: conversionContext
|
|
56
63
|
});
|
|
57
64
|
const firstConverted = converted.at(0);
|
|
58
65
|
if (pbPos === "before" && converted.length === 1 && firstConverted?.type.name === "paragraph" && firstConverted.content.size === 0 && document.package.settings?.splitPageBreakAndParagraphMark !== true) {
|
|
@@ -72,10 +79,7 @@ function toProseDoc(document, options) {
|
|
|
72
79
|
}
|
|
73
80
|
out.push(...converted);
|
|
74
81
|
if (pbPos === "after") out.push(schema.node("pageBreak"));
|
|
75
|
-
} else if (block.type === "table") out.push(convertTable(block, styleResolver,
|
|
76
|
-
theme,
|
|
77
|
-
nextTextBoxGroupId
|
|
78
|
-
}));
|
|
82
|
+
} else if (block.type === "table") out.push(convertTable(block, styleResolver, conversionContext));
|
|
79
83
|
else out.push(convertBlockSdt(block, convertBodyBlocks));
|
|
80
84
|
return out;
|
|
81
85
|
};
|
|
@@ -122,14 +126,13 @@ function convertBlockSdt(blockSdt, convertBlocks) {
|
|
|
122
126
|
* Resolves style-based text formatting and passes it to runs so that
|
|
123
127
|
* paragraph styles (like Heading1) apply their font size, color, etc.
|
|
124
128
|
*/
|
|
125
|
-
function convertParagraph(paragraph, styleResolver, activeCommentIds, extraRunFormatting, tableParagraphOverlay, textBoxAnchors) {
|
|
129
|
+
function convertParagraph(paragraph, styleResolver, nextHyperlinkInstanceIndex, activeCommentIds, extraRunFormatting, tableParagraphOverlay, textBoxAnchors) {
|
|
126
130
|
const attrs = paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOverlay);
|
|
127
131
|
const isTocParagraph = isTocStyleId(paragraph.formatting?.styleId);
|
|
128
132
|
const inlineNodes = [];
|
|
129
133
|
let inlineOffset = 0;
|
|
130
134
|
let bookmarksArr;
|
|
131
135
|
let emptyHyperlinks;
|
|
132
|
-
let hyperlinkIndex = 0;
|
|
133
136
|
const commentIds = activeCommentIds ?? /* @__PURE__ */ new Set();
|
|
134
137
|
const emitInlineNodes = (nodes) => {
|
|
135
138
|
if (nodes.length === 0) return;
|
|
@@ -160,7 +163,7 @@ function convertParagraph(paragraph, styleResolver, activeCommentIds, extraRunFo
|
|
|
160
163
|
return suppressParagraphMarkFormatting(baseRunFormatting, inheritableParagraphRunFormatting, formatting, paragraphMarkPrecedesStyle);
|
|
161
164
|
};
|
|
162
165
|
const emitTrackedChange = (change, markType, moveKind) => {
|
|
163
|
-
emitInlineNodes(convertTrackedChange(change, markType, getInheritedRunFormatting, styleResolver, moveKind, textBoxAnchors));
|
|
166
|
+
emitInlineNodes(convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, moveKind, textBoxAnchors));
|
|
164
167
|
};
|
|
165
168
|
for (const content of paragraph.content) {
|
|
166
169
|
if (content.type === "commentRangeStart") commentIds.add(content.id);
|
|
@@ -168,12 +171,10 @@ function convertParagraph(paragraph, styleResolver, activeCommentIds, extraRunFo
|
|
|
168
171
|
else if (content.type === "commentReference") anchorPointComment(inlineNodes, content.id);
|
|
169
172
|
else if (content.type === "run") emitInlineNodes(convertRun(content, getInheritedRunFormatting(content.formatting), styleResolver, textBoxAnchors));
|
|
170
173
|
else if (content.type === "hyperlink") {
|
|
171
|
-
const currentHyperlinkIndex = hyperlinkIndex;
|
|
172
|
-
hyperlinkIndex += 1;
|
|
173
174
|
const linkNodes = convertHyperlink(content, {
|
|
174
175
|
getInheritedRunFormatting,
|
|
175
176
|
styleResolver,
|
|
176
|
-
hyperlinkIndex:
|
|
177
|
+
hyperlinkIndex: nextHyperlinkInstanceIndex(),
|
|
177
178
|
textBoxAnchors
|
|
178
179
|
});
|
|
179
180
|
if (linkNodes.length === 0) {
|
|
@@ -189,7 +190,7 @@ function convertParagraph(paragraph, styleResolver, activeCommentIds, extraRunFo
|
|
|
189
190
|
}
|
|
190
191
|
emitInlineNodes(linkNodes);
|
|
191
192
|
} else if (content.type === "simpleField" || content.type === "complexField") emitInlineNode(convertField(content, getInheritedRunFormatting, styleResolver));
|
|
192
|
-
else if (content.type === "inlineSdt") emitInlineNode(convertInlineSdt(content, getInheritedRunFormatting, styleResolver, textBoxAnchors));
|
|
193
|
+
else if (content.type === "inlineSdt") emitInlineNode(convertInlineSdt(content, nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, textBoxAnchors));
|
|
193
194
|
else if (content.type === "insertion" || content.type === "moveTo") emitTrackedChange(content, "insertion", content.type === "moveTo" ? "moveTo" : null);
|
|
194
195
|
else if (content.type === "deletion" || content.type === "moveFrom") emitTrackedChange(content, "deletion", content.type === "moveFrom" ? "moveFrom" : null);
|
|
195
196
|
else if (content.type === "mathEquation") emitInlineNode(convertMathEquation(content));
|
|
@@ -243,13 +244,11 @@ function anchorPointComment(nodes, commentId) {
|
|
|
243
244
|
* Convert tracked change (insertion or deletion) content to PM nodes with
|
|
244
245
|
* an insertion/deletion mark applied.
|
|
245
246
|
*/
|
|
246
|
-
function convertTrackedChange(change, markType, getInheritedRunFormatting, styleResolver, moveKind = null, textBoxAnchors) {
|
|
247
|
+
function convertTrackedChange(change, markType, nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, moveKind = null, textBoxAnchors) {
|
|
247
248
|
const nodes = [];
|
|
248
|
-
let hyperlinkIndex = 0;
|
|
249
249
|
for (const item of change.content) if (item.type === "run") nodes.push(...convertRun(item, getInheritedRunFormatting(item.formatting), styleResolver, textBoxAnchors));
|
|
250
250
|
else {
|
|
251
|
-
const currentHyperlinkIndex =
|
|
252
|
-
hyperlinkIndex += 1;
|
|
251
|
+
const currentHyperlinkIndex = nextHyperlinkInstanceIndex();
|
|
253
252
|
nodes.push(...convertHyperlink(item, {
|
|
254
253
|
getInheritedRunFormatting,
|
|
255
254
|
styleResolver,
|
|
@@ -921,7 +920,8 @@ function standaloneTableCellToProseMirror(cell, nodeType) {
|
|
|
921
920
|
styleResolver: null,
|
|
922
921
|
context: {
|
|
923
922
|
theme: null,
|
|
924
|
-
nextTextBoxGroupId: createTextBoxGroupIdFactory()
|
|
923
|
+
nextTextBoxGroupId: createTextBoxGroupIdFactory(),
|
|
924
|
+
nextHyperlinkInstanceIndex: createHyperlinkInstanceIndexAllocator()
|
|
925
925
|
},
|
|
926
926
|
isHeader: nodeType === "tableHeader",
|
|
927
927
|
gridWidthPercent: void 0,
|
|
@@ -973,20 +973,17 @@ function convertMathEquation(math) {
|
|
|
973
973
|
/**
|
|
974
974
|
* Convert an InlineSdt to a ProseMirror sdt node with inline content.
|
|
975
975
|
*/
|
|
976
|
-
function convertInlineSdt(sdt, getInheritedRunFormatting, styleResolver, textBoxAnchors) {
|
|
976
|
+
function convertInlineSdt(sdt, nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, textBoxAnchors) {
|
|
977
977
|
const props = sdt.properties;
|
|
978
978
|
const inlineNodes = [];
|
|
979
|
-
let hyperlinkIndex = 0;
|
|
980
979
|
for (const content of sdt.content) if (content.type === "run") {
|
|
981
980
|
const runNodes = convertRun(content, getInheritedRunFormatting(content.formatting), styleResolver, textBoxAnchors);
|
|
982
981
|
inlineNodes.push(...runNodes);
|
|
983
982
|
} else if (content.type === "hyperlink") {
|
|
984
|
-
const currentHyperlinkIndex = hyperlinkIndex;
|
|
985
|
-
hyperlinkIndex += 1;
|
|
986
983
|
const linkNodes = convertHyperlink(content, {
|
|
987
984
|
getInheritedRunFormatting,
|
|
988
985
|
styleResolver,
|
|
989
|
-
hyperlinkIndex:
|
|
986
|
+
hyperlinkIndex: nextHyperlinkInstanceIndex(),
|
|
990
987
|
textBoxAnchors
|
|
991
988
|
});
|
|
992
989
|
inlineNodes.push(...linkNodes);
|
|
@@ -994,12 +991,12 @@ function convertInlineSdt(sdt, getInheritedRunFormatting, styleResolver, textBox
|
|
|
994
991
|
const fieldNode = convertField(content, getInheritedRunFormatting, styleResolver);
|
|
995
992
|
if (fieldNode) inlineNodes.push(fieldNode);
|
|
996
993
|
} else if (content.type === "inlineSdt") {
|
|
997
|
-
const nestedSdt = convertInlineSdt(content, getInheritedRunFormatting, styleResolver, textBoxAnchors);
|
|
994
|
+
const nestedSdt = convertInlineSdt(content, nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, textBoxAnchors);
|
|
998
995
|
if (nestedSdt) inlineNodes.push(nestedSdt);
|
|
999
|
-
} else if (content.type === "insertion") inlineNodes.push(...convertTrackedChange(content, "insertion", getInheritedRunFormatting, styleResolver, null, textBoxAnchors));
|
|
1000
|
-
else if (content.type === "deletion") inlineNodes.push(...convertTrackedChange(content, "deletion", getInheritedRunFormatting, styleResolver, null, textBoxAnchors));
|
|
1001
|
-
else if (content.type === "moveTo") inlineNodes.push(...convertTrackedChange(content, "insertion", getInheritedRunFormatting, styleResolver, "moveTo", textBoxAnchors));
|
|
1002
|
-
else if (content.type === "moveFrom") inlineNodes.push(...convertTrackedChange(content, "deletion", getInheritedRunFormatting, styleResolver, "moveFrom", textBoxAnchors));
|
|
996
|
+
} else if (content.type === "insertion") inlineNodes.push(...convertTrackedChange(content, "insertion", nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, null, textBoxAnchors));
|
|
997
|
+
else if (content.type === "deletion") inlineNodes.push(...convertTrackedChange(content, "deletion", nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, null, textBoxAnchors));
|
|
998
|
+
else if (content.type === "moveTo") inlineNodes.push(...convertTrackedChange(content, "insertion", nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, "moveTo", textBoxAnchors));
|
|
999
|
+
else if (content.type === "moveFrom") inlineNodes.push(...convertTrackedChange(content, "deletion", nextHyperlinkInstanceIndex, getInheritedRunFormatting, styleResolver, "moveFrom", textBoxAnchors));
|
|
1003
1000
|
else {
|
|
1004
1001
|
const mathNode = convertMathEquation(content);
|
|
1005
1002
|
if (mathNode) inlineNodes.push(mathNode);
|
|
@@ -1380,7 +1377,7 @@ function convertShape(shape) {
|
|
|
1380
1377
|
}
|
|
1381
1378
|
function convertParagraphWithTextBoxes(block, styleResolver, { textBoxGroupId, context, extraRunFormatting, tableParagraphOverlay }) {
|
|
1382
1379
|
const { textBoxes, textBoxAnchors } = extractTextBoxesFromParagraph(block, textBoxGroupId);
|
|
1383
|
-
const pmParagraph = convertParagraph(block, styleResolver, void 0, extraRunFormatting, tableParagraphOverlay, textBoxAnchors);
|
|
1380
|
+
const pmParagraph = convertParagraph(block, styleResolver, context.nextHyperlinkInstanceIndex, void 0, extraRunFormatting, tableParagraphOverlay, textBoxAnchors);
|
|
1384
1381
|
const nodes = [];
|
|
1385
1382
|
const isEmptyAfterExtraction = textBoxes.length > 0 && !hasContentBesidesTextBoxAnchors(pmParagraph);
|
|
1386
1383
|
const keepWrapperParagraph = isEmptyAfterExtraction && hasParagraphBoundaryPayload(block, pmParagraph);
|
|
@@ -1639,19 +1636,18 @@ function headerFooterToProseDoc(content, options) {
|
|
|
1639
1636
|
const styleResolver = options?.styles ? createStyleEngine(options.styles) : null;
|
|
1640
1637
|
const theme = options?.theme ?? null;
|
|
1641
1638
|
const nextTextBoxGroupId = createTextBoxGroupIdFactory();
|
|
1639
|
+
const conversionContext = {
|
|
1640
|
+
theme,
|
|
1641
|
+
nextTextBoxGroupId,
|
|
1642
|
+
nextHyperlinkInstanceIndex: createHyperlinkInstanceIndexAllocator()
|
|
1643
|
+
};
|
|
1642
1644
|
const convertBlocks = (blocks) => {
|
|
1643
1645
|
const out = [];
|
|
1644
1646
|
for (const block of blocks) if (block.type === "paragraph") out.push(...convertParagraphWithTextBoxes(block, styleResolver, {
|
|
1645
1647
|
textBoxGroupId: nextTextBoxGroupId(),
|
|
1646
|
-
context:
|
|
1647
|
-
theme,
|
|
1648
|
-
nextTextBoxGroupId
|
|
1649
|
-
}
|
|
1650
|
-
}));
|
|
1651
|
-
else if (block.type === "table") out.push(convertTable(block, styleResolver, {
|
|
1652
|
-
theme,
|
|
1653
|
-
nextTextBoxGroupId
|
|
1648
|
+
context: conversionContext
|
|
1654
1649
|
}));
|
|
1650
|
+
else if (block.type === "table") out.push(convertTable(block, styleResolver, conversionContext));
|
|
1655
1651
|
else out.push(convertBlockSdt(block, convertBlocks));
|
|
1656
1652
|
return out;
|
|
1657
1653
|
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ParagraphAttrs, ParagraphBlock } from "../layout-engine/types.js";
|
|
2
|
+
//#region src/utils/paragraphInlineLayout.d.ts
|
|
3
|
+
type ParagraphAlignment = NonNullable<ParagraphAttrs["alignment"]>;
|
|
4
|
+
type PhysicalParagraphInlineLayout = {
|
|
5
|
+
alignment: ParagraphAlignment;
|
|
6
|
+
explicitAlignment?: ParagraphAlignment;
|
|
7
|
+
indentLeft: number;
|
|
8
|
+
indentRight: number;
|
|
9
|
+
isRtl: boolean;
|
|
10
|
+
};
|
|
11
|
+
/** Resolve logical OOXML paragraph sides into physical inline geometry. */
|
|
12
|
+
declare const resolvePhysicalParagraphInlineLayout: (block: ParagraphBlock) => PhysicalParagraphInlineLayout;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { PhysicalParagraphInlineLayout, resolvePhysicalParagraphInlineLayout };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { isRtlParagraph } from "./paragraphBaseDirection.js";
|
|
2
|
+
//#region src/utils/paragraphInlineLayout.ts
|
|
3
|
+
const mirrorHorizontalAlignment = (alignment) => {
|
|
4
|
+
if (alignment === "left") return "right";
|
|
5
|
+
if (alignment === "right") return "left";
|
|
6
|
+
return alignment;
|
|
7
|
+
};
|
|
8
|
+
/** Resolve logical OOXML paragraph sides into physical inline geometry. */
|
|
9
|
+
const resolvePhysicalParagraphInlineLayout = (block) => {
|
|
10
|
+
const attrs = block.attrs;
|
|
11
|
+
const isRtl = isRtlParagraph(block);
|
|
12
|
+
const mirrorsHorizontalSides = attrs?.bidi === true;
|
|
13
|
+
const explicitAlignment = mirrorsHorizontalSides ? mirrorHorizontalAlignment(attrs?.alignment) : attrs?.alignment;
|
|
14
|
+
const indentLeft = attrs?.indent?.left ?? 0;
|
|
15
|
+
const indentRight = attrs?.indent?.right ?? 0;
|
|
16
|
+
return {
|
|
17
|
+
alignment: explicitAlignment ?? (isRtl ? "right" : "left"),
|
|
18
|
+
...explicitAlignment === void 0 ? {} : { explicitAlignment },
|
|
19
|
+
indentLeft: mirrorsHorizontalSides ? indentRight : indentLeft,
|
|
20
|
+
indentRight: mirrorsHorizontalSides ? indentLeft : indentRight,
|
|
21
|
+
isRtl
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
//#endregion
|
|
25
|
+
export { resolvePhysicalParagraphInlineLayout };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stll/folio-core",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.4",
|
|
4
4
|
"description": "Headless, framework-neutral core of folio: the OOXML (.docx) parser, document model, ProseMirror integration, and page-layout engine. No React.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"document-model",
|