@stll/folio-core 0.7.0 → 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 +76 -9
- 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/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/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/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 +42 -3
- 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 +36 -82
- 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 +13 -4
- 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 +7 -6
- 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 +17 -8
- package/dist/layout-engine/types.js +15 -2
- package/dist/layout-painter/renderPage.js +2 -2
- package/dist/layout-painter/renderParagraph.js +6 -5
- 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 +27 -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/TextBoxExtension.d.ts +2 -1
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +7 -0
- package/dist/prosemirror/schema/nodes.d.ts +4 -2
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
- package/dist/server.d.ts +4 -2
- package/dist/server.js +3 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/utils/createDocument.js +26 -18
- package/dist/utils/hexId.d.ts +8 -1
- package/dist/utils/hexId.js +11 -3
- package/package.json +1 -1
|
@@ -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;
|
|
@@ -616,8 +617,9 @@ function convertTable(table, styleResolver, context) {
|
|
|
616
617
|
function countTableColumns(rows) {
|
|
617
618
|
let maxColumns = 0;
|
|
618
619
|
for (const row of rows) {
|
|
619
|
-
let rowColumns = 0;
|
|
620
|
+
let rowColumns = row.formatting?.gridBefore ?? 0;
|
|
620
621
|
for (const cell of row.cells) rowColumns += cell.formatting?.gridSpan ?? 1;
|
|
622
|
+
rowColumns += row.formatting?.gridAfter ?? 0;
|
|
621
623
|
maxColumns = Math.max(maxColumns, rowColumns);
|
|
622
624
|
}
|
|
623
625
|
return maxColumns;
|
|
@@ -651,7 +653,7 @@ function convertTableRow(row, styleResolver, context, isHeaderRow, columnWidths,
|
|
|
651
653
|
if (totalCols > 1) fallback.formatting = { gridSpan: totalCols };
|
|
652
654
|
effectiveCells = [fallback];
|
|
653
655
|
}
|
|
654
|
-
let colIndex = 0;
|
|
656
|
+
let colIndex = row.formatting?.gridBefore ?? 0;
|
|
655
657
|
const cells = [];
|
|
656
658
|
for (const cellIndex_item of effectiveCells) {
|
|
657
659
|
const cell = cellIndex_item;
|
|
@@ -1264,6 +1266,7 @@ function extractTextBoxesFromParagraph(paragraph) {
|
|
|
1264
1266
|
if (shape.fill) textBox.fill = shape.fill;
|
|
1265
1267
|
if (shape.outline) textBox.outline = shape.outline;
|
|
1266
1268
|
if (shape.textBody.margins) textBox.margins = shape.textBody.margins;
|
|
1269
|
+
if (shape.textBody.autoFit) textBox.autoFit = shape.textBody.autoFit;
|
|
1267
1270
|
textBoxes.push(textBox);
|
|
1268
1271
|
}
|
|
1269
1272
|
}
|
|
@@ -1332,6 +1335,7 @@ function convertTextBox(textBox, styleResolver, options = {}) {
|
|
|
1332
1335
|
return schema.node("textBox", {
|
|
1333
1336
|
width: widthPx,
|
|
1334
1337
|
height: heightPx,
|
|
1338
|
+
autoFit: textBox.autoFit,
|
|
1335
1339
|
textBoxId: textBox.id,
|
|
1336
1340
|
fillColor,
|
|
1337
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 },
|
|
@@ -4,26 +4,76 @@ import { ignoreTrackedChanges } from "./ParagraphChangeTrackerExtension.js";
|
|
|
4
4
|
import { Plugin, PluginKey } from "prosemirror-state";
|
|
5
5
|
//#region src/prosemirror/extensions/features/ParaIdAllocatorExtension.ts
|
|
6
6
|
const paraIdAllocatorKey = new PluginKey("paraIdAllocator");
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
const isUsableParaId = (value) => typeof value === "string" && value.length > 0 && value !== "00000000";
|
|
8
|
+
/**
|
|
9
|
+
* For every valid paraId in the pre-transaction doc, the position its
|
|
10
|
+
* paragraph ends up at after `transactions` — the occurrence that
|
|
11
|
+
* rightfully keeps the id when the new doc holds duplicates. Ids whose
|
|
12
|
+
* paragraph start was deleted by the steps are left out.
|
|
13
|
+
*/
|
|
14
|
+
const mapKeeperPositions = (oldDoc, transactions) => {
|
|
15
|
+
const keepers = /* @__PURE__ */ new Map();
|
|
16
|
+
oldDoc.descendants((node, pos) => {
|
|
17
|
+
if (node.type.name !== "paragraph") return true;
|
|
18
|
+
const id = node.attrs["paraId"];
|
|
19
|
+
if (!isUsableParaId(id) || keepers.has(id)) return false;
|
|
20
|
+
let mapped = pos;
|
|
21
|
+
let deleted = false;
|
|
22
|
+
for (const tr of transactions) {
|
|
23
|
+
const result = tr.mapping.mapResult(mapped);
|
|
24
|
+
if (result.deleted) {
|
|
25
|
+
deleted = true;
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
mapped = result.pos;
|
|
29
|
+
}
|
|
30
|
+
if (!deleted) keepers.set(id, mapped);
|
|
31
|
+
return false;
|
|
32
|
+
});
|
|
33
|
+
return keepers;
|
|
34
|
+
};
|
|
35
|
+
const collectParaIdUpdates = (doc, keeperPositions) => {
|
|
36
|
+
const missing = [];
|
|
37
|
+
const occurrencesById = /* @__PURE__ */ new Map();
|
|
10
38
|
doc.descendants((node, pos) => {
|
|
11
|
-
if (node.type.name !== "paragraph") return;
|
|
39
|
+
if (node.type.name !== "paragraph") return true;
|
|
12
40
|
const id = node.attrs["paraId"];
|
|
13
|
-
if (
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
41
|
+
if (!isUsableParaId(id)) missing.push({
|
|
42
|
+
pos,
|
|
43
|
+
attrs: node.attrs
|
|
44
|
+
});
|
|
45
|
+
else {
|
|
46
|
+
const occurrences = occurrencesById.get(id) ?? [];
|
|
47
|
+
occurrences.push({
|
|
18
48
|
pos,
|
|
19
|
-
attrs:
|
|
20
|
-
...node.attrs,
|
|
21
|
-
paraId: newId
|
|
22
|
-
}
|
|
49
|
+
attrs: node.attrs
|
|
23
50
|
});
|
|
24
|
-
|
|
51
|
+
occurrencesById.set(id, occurrences);
|
|
52
|
+
}
|
|
25
53
|
return false;
|
|
26
54
|
});
|
|
55
|
+
const needFreshId = [...missing];
|
|
56
|
+
for (const [id, occurrences] of occurrencesById) {
|
|
57
|
+
if (occurrences.length === 1) continue;
|
|
58
|
+
const keeperPos = keeperPositions?.get(id);
|
|
59
|
+
const keeper = occurrences.find((occurrence) => occurrence.pos === keeperPos) ?? occurrences[0];
|
|
60
|
+
for (const occurrence of occurrences) if (occurrence !== keeper) needFreshId.push(occurrence);
|
|
61
|
+
}
|
|
62
|
+
const taken = new Set(occurrencesById.keys());
|
|
63
|
+
const updates = [];
|
|
64
|
+
for (const { pos, attrs } of needFreshId) {
|
|
65
|
+
let newId = generateHexId();
|
|
66
|
+
while (taken.has(newId)) newId = generateHexId();
|
|
67
|
+
taken.add(newId);
|
|
68
|
+
updates.push({
|
|
69
|
+
pos,
|
|
70
|
+
attrs: {
|
|
71
|
+
...attrs,
|
|
72
|
+
paraId: newId
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
updates.sort((a, b) => a.pos - b.pos);
|
|
27
77
|
return updates;
|
|
28
78
|
};
|
|
29
79
|
const ensureParaIdsInState = (state) => {
|
|
@@ -38,12 +88,14 @@ const ensureParaIdsInState = (state) => {
|
|
|
38
88
|
};
|
|
39
89
|
const createParaIdAllocatorPlugin = () => new Plugin({
|
|
40
90
|
key: paraIdAllocatorKey,
|
|
41
|
-
appendTransaction(transactions,
|
|
91
|
+
appendTransaction(transactions, oldState, newState) {
|
|
42
92
|
if (!transactions.some((t) => t.docChanged)) return null;
|
|
43
|
-
const
|
|
93
|
+
const keeperPositions = mapKeeperPositions(oldState.doc, transactions);
|
|
94
|
+
const updates = collectParaIdUpdates(newState.doc, keeperPositions);
|
|
44
95
|
if (updates.length === 0) return null;
|
|
45
96
|
const tr = newState.tr;
|
|
46
97
|
for (const u of updates) tr.setNodeMarkup(u.pos, void 0, u.attrs);
|
|
98
|
+
ignoreTrackedChanges(tr);
|
|
47
99
|
tr.setMeta(paraIdAllocatorKey, "allocated");
|
|
48
100
|
tr.setMeta("addToHistory", false);
|
|
49
101
|
return tr;
|
|
@@ -6,7 +6,8 @@ import { ImagePositionAttrs } from "../../schema/nodes.js";
|
|
|
6
6
|
//#region src/prosemirror/extensions/nodes/TextBoxExtension.d.ts
|
|
7
7
|
type TextBoxAttrs = {
|
|
8
8
|
/** Width in pixels */width?: number; /** Height in pixels */
|
|
9
|
-
height?: number; /**
|
|
9
|
+
height?: number; /** Text fitting behavior */
|
|
10
|
+
autoFit?: document_d_exports.ShapeTextBody["autoFit"]; /** Unique identifier */
|
|
10
11
|
textBoxId?: string; /** Fill color as CSS color */
|
|
11
12
|
fillColor?: string; /** Outline width in pixels */
|
|
12
13
|
outlineWidth?: number; /** Outline color as CSS color */
|
|
@@ -15,6 +15,9 @@ function parseTextBoxPosition(raw) {
|
|
|
15
15
|
function parseTextBoxWrapType(raw) {
|
|
16
16
|
for (const value of IMAGE_WRAP_TYPE_VALUES) if (value === raw) return value;
|
|
17
17
|
}
|
|
18
|
+
function parseTextBoxAutoFit(raw) {
|
|
19
|
+
if (raw === "none" || raw === "normal" || raw === "shape") return raw;
|
|
20
|
+
}
|
|
18
21
|
const TextBoxExtension = createNodeExtension({
|
|
19
22
|
name: "textBox",
|
|
20
23
|
schemaNodeName: "textBox",
|
|
@@ -26,6 +29,7 @@ const TextBoxExtension = createNodeExtension({
|
|
|
26
29
|
attrs: {
|
|
27
30
|
width: { default: 200 },
|
|
28
31
|
height: { default: null },
|
|
32
|
+
autoFit: { default: null },
|
|
29
33
|
textBoxId: { default: null },
|
|
30
34
|
fillColor: { default: null },
|
|
31
35
|
outlineWidth: { default: null },
|
|
@@ -55,9 +59,11 @@ const TextBoxExtension = createNodeExtension({
|
|
|
55
59
|
const d = dom.dataset;
|
|
56
60
|
const position = parseTextBoxPosition(d["position"]);
|
|
57
61
|
const wrapType = parseTextBoxWrapType(d["wrapType"]);
|
|
62
|
+
const autoFit = parseTextBoxAutoFit(d["autoFit"]);
|
|
58
63
|
return {
|
|
59
64
|
...d["width"] ? { width: Number(d["width"]) } : {},
|
|
60
65
|
...d["height"] ? { height: Number(d["height"]) } : {},
|
|
66
|
+
...autoFit ? { autoFit } : {},
|
|
61
67
|
...d["textboxId"] ? { textBoxId: d["textboxId"] } : {},
|
|
62
68
|
...d["fillColor"] ? { fillColor: d["fillColor"] } : {},
|
|
63
69
|
...d["outlineWidth"] ? { outlineWidth: Number(d["outlineWidth"]) } : {},
|
|
@@ -85,6 +91,7 @@ const TextBoxExtension = createNodeExtension({
|
|
|
85
91
|
const domAttrs = { class: "docx-textbox" };
|
|
86
92
|
if (attrs.width) domAttrs["data-width"] = String(attrs.width);
|
|
87
93
|
if (attrs.height) domAttrs["data-height"] = String(attrs.height);
|
|
94
|
+
if (attrs.autoFit) domAttrs["data-auto-fit"] = attrs.autoFit;
|
|
88
95
|
if (attrs.textBoxId) domAttrs["data-textbox-id"] = attrs.textBoxId;
|
|
89
96
|
if (attrs.fillColor) domAttrs["data-fill-color"] = attrs.fillColor;
|
|
90
97
|
if (attrs.outlineWidth) domAttrs["data-outline-width"] = String(attrs.outlineWidth);
|
|
@@ -46,7 +46,8 @@ type ParagraphAttrs = {
|
|
|
46
46
|
listMarker?: string; /** Whether the list marker is hidden (w:vanish on numbering level rPr) */
|
|
47
47
|
listMarkerHidden?: boolean; /** Marker font family from numbering level rPr */
|
|
48
48
|
listMarkerFontFamily?: string; /** Marker font size from numbering level rPr, in points */
|
|
49
|
-
listMarkerFontSize?: number;
|
|
49
|
+
listMarkerFontSize?: number; /** Horizontal alignment of the marker around the paragraph's list anchor. */
|
|
50
|
+
listMarkerAlignment?: "left" | "center" | "right";
|
|
50
51
|
/**
|
|
51
52
|
* `w:suff` (§17.9.25) — what follows the marker before body text.
|
|
52
53
|
* `tab` (default) grows the marker to the next tab stop; `space` adds one
|
|
@@ -307,7 +308,8 @@ type ShapeAttrs = {
|
|
|
307
308
|
*/
|
|
308
309
|
type TextBoxAttrs = {
|
|
309
310
|
/** Width in pixels */width?: number; /** Height in pixels */
|
|
310
|
-
height?: number; /**
|
|
311
|
+
height?: number; /** Text fitting behavior */
|
|
312
|
+
autoFit?: document_d_exports.ShapeTextBody["autoFit"]; /** Unique identifier */
|
|
311
313
|
textBoxId?: string; /** Fill color as CSS color */
|
|
312
314
|
fillColor?: string; /** Outline width in pixels */
|
|
313
315
|
outlineWidth?: number; /** Outline color as CSS color */
|
|
@@ -86,6 +86,7 @@ function listAttrsFromResolvedStyle(resolved, numbering) {
|
|
|
86
86
|
listMarkerHidden: rendering?.markerHidden ?? null,
|
|
87
87
|
listMarkerFontFamily: rendering?.markerFontFamily ?? null,
|
|
88
88
|
listMarkerFontSize: rendering?.markerFontSize ?? null,
|
|
89
|
+
listMarkerAlignment: rendering?.markerAlignment ?? null,
|
|
89
90
|
listMarkerSuffix: rendering?.markerSuffix ?? null,
|
|
90
91
|
listMarkerAllCaps: rendering?.markerAllCaps ?? null,
|
|
91
92
|
listImplicitChildLevelAdvances: null,
|