@stll/folio-core 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-edits/apply.d.ts +3 -9
- package/dist/ai-edits/apply.js +94 -14
- package/dist/ai-edits/blockRange.d.ts +33 -0
- package/dist/ai-edits/blockRange.js +58 -0
- package/dist/ai-edits/headless.d.ts +37 -4
- package/dist/ai-edits/headless.js +134 -16
- package/dist/ai-edits/index.d.ts +5 -3
- package/dist/ai-edits/index.js +3 -2
- package/dist/ai-edits/snapshot.d.ts +14 -2
- package/dist/ai-edits/snapshot.js +12 -1
- package/dist/ai-edits/types.d.ts +42 -3
- package/dist/compat/eigenpal.d.ts +3 -2
- package/dist/compat/eigenpal.js +6 -5
- package/dist/controller/layoutPipeline.d.ts +1 -0
- package/dist/controller/layoutPipeline.js +35 -137
- package/dist/controller/layoutScheduler.d.ts +2 -1
- package/dist/controller/layoutScheduler.js +6 -0
- package/dist/document-operations.d.ts +139 -0
- package/dist/document-operations.js +578 -0
- package/dist/docx/blockContentParser.js +17 -7
- package/dist/docx/encryption/agileDecryption.js +2 -1
- package/dist/docx/encryption/compoundFile.js +4 -2
- package/dist/docx/footnoteParser.d.ts +1 -17
- package/dist/docx/footnoteParser.js +1 -27
- package/dist/docx/groupDrawingParser.d.ts +8 -0
- package/dist/docx/groupDrawingParser.js +131 -0
- package/dist/docx/numberingParser.d.ts +3 -1
- package/dist/docx/numberingParser.js +8 -2
- package/dist/docx/paragraphParser.js +9 -3
- package/dist/docx/runParser.js +8 -1
- package/dist/docx/selectiveXmlPatch.js +4 -10
- package/dist/docx/serializer/numberingSerializer.js +3 -1
- package/dist/docx/settingsParser.d.ts +6 -3
- package/dist/docx/settingsParser.js +2 -0
- package/dist/docx/xmlParser.js +11 -4
- package/dist/i18n/messages/catalogs.gen.d.ts +1054 -34
- package/dist/i18n/messages/catalogs.gen.js +1122 -68
- package/dist/i18n/messages/messages.gen.d.ts +62 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +6 -5
- package/dist/layout-bridge/convert/footnoteLayout.d.ts +37 -1
- package/dist/layout-bridge/convert/footnoteLayout.js +138 -14
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +5 -7
- package/dist/layout-bridge/convert/headerFooterLayout.js +5 -7
- package/dist/layout-bridge/convert/toFlowBlocks.js +56 -19
- package/dist/layout-engine/index.d.ts +6 -5
- package/dist/layout-engine/index.js +143 -30
- package/dist/layout-engine/keep-together.d.ts +13 -8
- package/dist/layout-engine/keep-together.js +40 -25
- package/dist/layout-engine/layoutInstrumentation.d.ts +11 -1
- package/dist/layout-engine/layoutInstrumentation.js +10 -1
- package/dist/layout-engine/measure/measureBlocks.js +50 -18
- package/dist/layout-engine/measure/measureParagraph.js +61 -15
- package/dist/layout-engine/paginator.d.ts +2 -1
- package/dist/layout-engine/paginator.js +9 -3
- package/dist/layout-engine/textBoxGroup.d.ts +7 -0
- package/dist/layout-engine/textBoxGroup.js +8 -0
- package/dist/layout-engine/types.d.ts +30 -9
- package/dist/layout-engine/types.js +20 -2
- package/dist/layout-painter/renderPage.d.ts +15 -1
- package/dist/layout-painter/renderPage.js +27 -11
- package/dist/layout-painter/renderParagraph.js +18 -8
- package/dist/layout-painter/renderTable.js +10 -7
- package/dist/managers/DocumentLoaderManager.js +12 -5
- package/dist/model.js +1 -1
- package/dist/paged-layout/pageText.d.ts +14 -0
- package/dist/paged-layout/pageText.js +21 -0
- package/dist/prosemirror/attrs/index.js +2 -0
- package/dist/prosemirror/commands/comments.js +75 -5
- package/dist/prosemirror/commands/hyperlink.js +4 -2
- package/dist/prosemirror/commands/image.js +2 -1
- package/dist/prosemirror/commands/propertyChangeScope.d.ts +68 -0
- package/dist/prosemirror/commands/propertyChangeScope.js +242 -0
- package/dist/prosemirror/conversion/fromProseDoc.js +14 -3
- package/dist/prosemirror/conversion/toProseDoc.js +29 -8
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -0
- package/dist/prosemirror/extensions/features/ListExtension.js +6 -0
- package/dist/prosemirror/extensions/nodes/TableExtension.js +10 -11
- package/dist/prosemirror/findReplaceSelection.js +2 -1
- package/dist/prosemirror/schema/nodes.d.ts +10 -5
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +1 -0
- package/dist/prosemirror/utils/tabCalculator.js +4 -2
- package/dist/redline.d.ts +20 -0
- package/dist/redline.js +127 -0
- package/dist/server.d.ts +7 -3
- package/dist/server.js +6 -2
- package/dist/symbols.d.ts +35 -0
- package/dist/symbols.js +512 -0
- package/dist/utils/clipboard.js +3 -3
- package/dist/utils/fontLoader.js +3 -0
- package/dist/utils/fontResolver.js +48 -1
- package/dist/utils/zoom.d.ts +21 -0
- package/dist/utils/zoom.js +21 -0
- package/dist/version-comparison.d.ts +92 -0
- package/dist/version-comparison.js +436 -0
- package/package.json +3 -3
- package/dist/paged-layout/headerFooterMargins.d.ts +0 -75
- package/dist/paged-layout/headerFooterMargins.js +0 -122
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
//#region src/layout-engine/keep-together.ts
|
|
2
|
+
function isVisuallyEmptyParagraph(block) {
|
|
3
|
+
if (block.runs.length === 0) return true;
|
|
4
|
+
if (block.runs.length !== 1) return false;
|
|
5
|
+
const run = block.runs.at(0);
|
|
6
|
+
return run?.kind === "text" && run.text === "";
|
|
7
|
+
}
|
|
2
8
|
/**
|
|
3
9
|
* Pre-scan blocks to find all keepNext chains.
|
|
4
10
|
*
|
|
5
|
-
* A keepNext chain
|
|
6
|
-
*
|
|
7
|
-
*
|
|
11
|
+
* A keepNext chain starts with a paragraph whose keepNext=true and continues
|
|
12
|
+
* through further keepNext paragraphs and structural empty separators. The
|
|
13
|
+
* first visible non-keepNext paragraph is its anchor.
|
|
8
14
|
*
|
|
9
15
|
* Returns a map from chain start index to chain info.
|
|
10
16
|
*/
|
|
@@ -22,7 +28,8 @@ function computeKeepNextChains(blocks) {
|
|
|
22
28
|
const nextBlock = blocks[j];
|
|
23
29
|
if (nextBlock.kind === "sectionBreak" || nextBlock.kind === "pageBreak" || nextBlock.kind === "columnBreak") break;
|
|
24
30
|
if (nextBlock.kind !== "paragraph") break;
|
|
25
|
-
|
|
31
|
+
const nextPara = nextBlock;
|
|
32
|
+
if (nextPara.attrs?.keepNext || isVisuallyEmptyParagraph(nextPara)) {
|
|
26
33
|
memberIndices.push(j);
|
|
27
34
|
endIndex = j;
|
|
28
35
|
processed.add(j);
|
|
@@ -44,30 +51,38 @@ function computeKeepNextChains(blocks) {
|
|
|
44
51
|
return chains;
|
|
45
52
|
}
|
|
46
53
|
/**
|
|
47
|
-
* Calculate the
|
|
54
|
+
* Calculate the height needed to keep consecutive paragraph boundaries from
|
|
55
|
+
* breaking across pages.
|
|
48
56
|
*
|
|
49
|
-
*
|
|
57
|
+
* Single-line and `keepLines` members are indivisible, so the reservation must
|
|
58
|
+
* continue through them to the anchor's first line. A multi-line member without
|
|
59
|
+
* `keepLines` may itself split; only its first line is needed to satisfy the
|
|
60
|
+
* preceding member's `keepNext`, and the chain can stop there.
|
|
50
61
|
*/
|
|
51
62
|
function calculateChainHeight(chain, blocks, measures) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
63
|
+
const firstMemberIndex = chain.memberIndices.at(0);
|
|
64
|
+
if (firstMemberIndex === void 0) return 0;
|
|
65
|
+
const firstBlock = blocks[firstMemberIndex];
|
|
66
|
+
const firstMeasure = measures[firstMemberIndex];
|
|
67
|
+
if (firstBlock?.kind !== "paragraph" || firstMeasure?.kind !== "paragraph") return 0;
|
|
68
|
+
let totalHeight = (firstBlock.attrs?.spacing?.before ?? 0) + firstMeasure.totalHeight;
|
|
69
|
+
let trailingSpacing = firstBlock.attrs?.spacing?.after ?? 0;
|
|
70
|
+
const successorIndices = [...chain.memberIndices.slice(1)];
|
|
71
|
+
if (chain.anchorIndex !== -1) successorIndices.push(chain.anchorIndex);
|
|
72
|
+
for (let index = 0; index < successorIndices.length; index++) {
|
|
73
|
+
const successorIndex = successorIndices[index];
|
|
74
|
+
if (successorIndex === void 0) continue;
|
|
75
|
+
const successorBlock = blocks[successorIndex];
|
|
76
|
+
const successorMeasure = measures[successorIndex];
|
|
77
|
+
if (successorBlock?.kind !== "paragraph" || successorMeasure?.kind !== "paragraph") return totalHeight;
|
|
78
|
+
totalHeight += Math.max(trailingSpacing, successorBlock.attrs?.spacing?.before ?? 0);
|
|
79
|
+
const firstLine = successorMeasure.lines.at(0);
|
|
80
|
+
if (!firstLine) return totalHeight;
|
|
81
|
+
const isAnchor = index === successorIndices.length - 1 && chain.anchorIndex !== -1;
|
|
82
|
+
const isSplittable = successorMeasure.lines.length > 1 && !successorBlock.attrs?.keepLines;
|
|
83
|
+
if (isAnchor || isSplittable) return totalHeight + firstLine.lineHeight;
|
|
84
|
+
totalHeight += successorMeasure.totalHeight;
|
|
85
|
+
trailingSpacing = successorBlock.attrs?.spacing?.after ?? 0;
|
|
71
86
|
}
|
|
72
87
|
return totalHeight;
|
|
73
88
|
}
|
|
@@ -5,7 +5,12 @@ type LayoutRunReason = "font-ready" | "initial" | "layout-input" | "manual" | "t
|
|
|
5
5
|
type LayoutPhase = "flow-blocks" | "header-footer" | "initial-fonts" | "layout-document" | "measure-blocks" | "render-pages";
|
|
6
6
|
type HiddenEditorStateReason = "external-document" | "mount";
|
|
7
7
|
type HiddenEditorPhase = "editor-state" | "editor-view" | "to-prose-doc" | "update-state";
|
|
8
|
+
type DocumentLoadPhase = "docx-parse";
|
|
8
9
|
type LayoutInstrumentation = {
|
|
10
|
+
onDocumentLoadPhase?: (event: {
|
|
11
|
+
durationMs: number;
|
|
12
|
+
phase: DocumentLoadPhase;
|
|
13
|
+
}) => void;
|
|
9
14
|
onHiddenEditorPhase?: (event: {
|
|
10
15
|
durationMs: number;
|
|
11
16
|
phase: HiddenEditorPhase;
|
|
@@ -21,6 +26,9 @@ type LayoutInstrumentation = {
|
|
|
21
26
|
message: string;
|
|
22
27
|
reason: LayoutRunReason;
|
|
23
28
|
}) => void;
|
|
29
|
+
onLayoutStart?: (event: {
|
|
30
|
+
reason: LayoutRunReason;
|
|
31
|
+
}) => void;
|
|
24
32
|
onLayoutPhase?: (event: {
|
|
25
33
|
durationMs: number;
|
|
26
34
|
phase: LayoutPhase;
|
|
@@ -42,9 +50,11 @@ declare global {
|
|
|
42
50
|
declare function recordMeasureBlock(blockIndex: number, block: FlowBlock): void;
|
|
43
51
|
declare function recordMeasureBlockError(blockIndex: number, block: FlowBlock, error: unknown): void;
|
|
44
52
|
declare function recordLayoutComplete(reason?: LayoutRunReason): void;
|
|
53
|
+
declare function recordLayoutStart(reason: LayoutRunReason): void;
|
|
45
54
|
declare function recordLayoutError(reason: LayoutRunReason, error: unknown): void;
|
|
46
55
|
declare function recordLayoutPhase(reason: LayoutRunReason, phase: LayoutPhase, durationMs: number): void;
|
|
47
56
|
declare function recordHiddenEditorStateCreate(reason: HiddenEditorStateReason): void;
|
|
48
57
|
declare function recordHiddenEditorPhase(reason: HiddenEditorStateReason, phase: HiddenEditorPhase, durationMs: number): void;
|
|
58
|
+
declare function recordDocumentLoadPhase(phase: DocumentLoadPhase, durationMs: number): void;
|
|
49
59
|
//#endregion
|
|
50
|
-
export { HiddenEditorPhase, HiddenEditorStateReason, LayoutInstrumentation, LayoutPhase, LayoutRunReason, recordHiddenEditorPhase, recordHiddenEditorStateCreate, recordLayoutComplete, recordLayoutError, recordLayoutPhase, recordMeasureBlock, recordMeasureBlockError };
|
|
60
|
+
export { DocumentLoadPhase, HiddenEditorPhase, HiddenEditorStateReason, LayoutInstrumentation, LayoutPhase, LayoutRunReason, recordDocumentLoadPhase, recordHiddenEditorPhase, recordHiddenEditorStateCreate, recordLayoutComplete, recordLayoutError, recordLayoutPhase, recordLayoutStart, recordMeasureBlock, recordMeasureBlockError };
|
|
@@ -15,6 +15,9 @@ function recordMeasureBlockError(blockIndex, block, error) {
|
|
|
15
15
|
function recordLayoutComplete(reason = "manual") {
|
|
16
16
|
globalThis.__folioLayoutInstrumentation?.onLayoutComplete?.({ reason });
|
|
17
17
|
}
|
|
18
|
+
function recordLayoutStart(reason) {
|
|
19
|
+
globalThis.__folioLayoutInstrumentation?.onLayoutStart?.({ reason });
|
|
20
|
+
}
|
|
18
21
|
function recordLayoutError(reason, error) {
|
|
19
22
|
const message = error instanceof Error ? error.message : String(error);
|
|
20
23
|
globalThis.__folioLayoutInstrumentation?.onLayoutError?.({
|
|
@@ -39,5 +42,11 @@ function recordHiddenEditorPhase(reason, phase, durationMs) {
|
|
|
39
42
|
reason
|
|
40
43
|
});
|
|
41
44
|
}
|
|
45
|
+
function recordDocumentLoadPhase(phase, durationMs) {
|
|
46
|
+
globalThis.__folioLayoutInstrumentation?.onDocumentLoadPhase?.({
|
|
47
|
+
durationMs,
|
|
48
|
+
phase
|
|
49
|
+
});
|
|
50
|
+
}
|
|
42
51
|
//#endregion
|
|
43
|
-
export { recordHiddenEditorPhase, recordHiddenEditorStateCreate, recordLayoutComplete, recordLayoutError, recordLayoutPhase, recordMeasureBlock, recordMeasureBlockError };
|
|
52
|
+
export { recordDocumentLoadPhase, recordHiddenEditorPhase, recordHiddenEditorStateCreate, recordLayoutComplete, recordLayoutError, recordLayoutPhase, recordLayoutStart, recordMeasureBlock, recordMeasureBlockError };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { DEFAULT_TEXTBOX_MARGINS, floatingTextBoxReservesBand } from "../types.js";
|
|
1
|
+
import { DEFAULT_TEXTBOX_MARGINS, floatingTextBoxReservesBand, tableColumnsArePinned } from "../types.js";
|
|
2
2
|
import { findClearLineY, measureParagraph } from "./measureParagraph.js";
|
|
3
3
|
import { getCachedParagraphMeasure, setCachedParagraphMeasure } from "./cache.js";
|
|
4
|
+
import { getTextBoxGroupId } from "../textBoxGroup.js";
|
|
4
5
|
import { recordMeasureBlock, recordMeasureBlockError } from "../layoutInstrumentation.js";
|
|
5
6
|
import { bandTopContentY, isPageFrameRelativeAnchor } from "../textBoxFlow.js";
|
|
6
7
|
//#region src/layout-engine/measure/measureBlocks.ts
|
|
@@ -80,8 +81,8 @@ function measureTableCellBlockVisualHeight(block, blockMeasure) {
|
|
|
80
81
|
const spacingAfter = paragraphBlock.attrs?.spacing?.after ?? 0;
|
|
81
82
|
return spacingBefore + maxImageHeight + spacingAfter;
|
|
82
83
|
}
|
|
83
|
-
function getTableCellVerticalBorderHeight(cell) {
|
|
84
|
-
return (cell?.borders?.top?.width ?? 0) + (cell?.borders?.bottom?.width ?? 0);
|
|
84
|
+
function getTableCellVerticalBorderHeight(cell, isFirstRow) {
|
|
85
|
+
return (isFirstRow ? cell?.borders?.top?.width ?? 0 : 0) + (cell?.borders?.bottom?.width ?? 0);
|
|
85
86
|
}
|
|
86
87
|
function measureTableBlock(tableBlock, contentWidth, fieldValues) {
|
|
87
88
|
const DEFAULT_CELL_PADDING_X = 7;
|
|
@@ -118,6 +119,7 @@ function measureTableBlock(tableBlock, contentWidth, fieldValues) {
|
|
|
118
119
|
while (occupied.has(colIdx)) colIdx++;
|
|
119
120
|
}
|
|
120
121
|
}
|
|
122
|
+
const columnsPinned = tableColumnsArePinned(tableBlock);
|
|
121
123
|
const rows = tableBlock.rows.map((row, rowIdx) => {
|
|
122
124
|
let columnIndex = 0;
|
|
123
125
|
const occupied = occupiedColumnsPerRow.get(rowIdx) ?? /* @__PURE__ */ new Set();
|
|
@@ -133,7 +135,7 @@ function measureTableBlock(tableBlock, contentWidth, fieldValues) {
|
|
|
133
135
|
const padLeft = cell.padding?.left ?? DEFAULT_CELL_PADDING_X;
|
|
134
136
|
const padRight = cell.padding?.right ?? DEFAULT_CELL_PADDING_X;
|
|
135
137
|
const cellContentWidth = Math.max(1, cellWidth - padLeft - padRight);
|
|
136
|
-
const measureWidth = cell.noWrap ? NO_WRAP_MEASURE_WIDTH : cellContentWidth;
|
|
138
|
+
const measureWidth = cell.noWrap === true && !columnsPinned ? NO_WRAP_MEASURE_WIDTH : cellContentWidth;
|
|
137
139
|
const cellMeasure = {
|
|
138
140
|
blocks: cell.blocks.map((b) => measureBlock(b, measureWidth, void 0, void 0, fieldValues)),
|
|
139
141
|
width: cellWidth,
|
|
@@ -160,6 +162,7 @@ function measureTableBlock(tableBlock, contentWidth, fieldValues) {
|
|
|
160
162
|
}
|
|
161
163
|
const sourceRowCells = tableBlock.rows[rowIdx]?.cells;
|
|
162
164
|
let maxCellHeightWithBorders = 0;
|
|
165
|
+
let maxBorderHeight = 0;
|
|
163
166
|
for (let cellIdx = 0; cellIdx < row.cells.length; cellIdx++) {
|
|
164
167
|
const cell = row.cells[cellIdx];
|
|
165
168
|
const sourceCell = sourceRowCells?.[cellIdx];
|
|
@@ -173,14 +176,38 @@ function measureTableBlock(tableBlock, contentWidth, fieldValues) {
|
|
|
173
176
|
const padTop = sourceCell?.padding?.top ?? DEFAULT_CELL_PADDING_Y;
|
|
174
177
|
const padBottom = sourceCell?.padding?.bottom ?? DEFAULT_CELL_PADDING_Y;
|
|
175
178
|
cell.height += padTop + padBottom;
|
|
176
|
-
|
|
179
|
+
if ((sourceCell?.rowSpan ?? 1) > 1) continue;
|
|
180
|
+
const borderHeight = getTableCellVerticalBorderHeight(sourceCell, rowIdx === 0);
|
|
181
|
+
maxCellHeightWithBorders = Math.max(maxCellHeightWithBorders, cell.height + borderHeight);
|
|
182
|
+
maxBorderHeight = Math.max(maxBorderHeight, borderHeight);
|
|
177
183
|
}
|
|
178
184
|
const explicitHeight = sourceRow?.height;
|
|
179
185
|
const heightRule = sourceRow?.heightRule;
|
|
180
186
|
if (explicitHeight && heightRule === "exact") row.height = explicitHeight;
|
|
181
|
-
else if (explicitHeight) row.height = Math.max(maxCellHeightWithBorders, explicitHeight);
|
|
187
|
+
else if (explicitHeight) row.height = Math.max(maxCellHeightWithBorders, explicitHeight + maxBorderHeight);
|
|
182
188
|
else row.height = maxCellHeightWithBorders;
|
|
183
189
|
}
|
|
190
|
+
for (let rowIdx = 0; rowIdx < rows.length; rowIdx++) {
|
|
191
|
+
const sourceRow = tableBlock.rows[rowIdx];
|
|
192
|
+
const measuredRow = rows[rowIdx];
|
|
193
|
+
if (!sourceRow || !measuredRow) continue;
|
|
194
|
+
for (let cellIdx = 0; cellIdx < sourceRow.cells.length; cellIdx++) {
|
|
195
|
+
const sourceCell = sourceRow.cells[cellIdx];
|
|
196
|
+
const measuredCell = measuredRow.cells[cellIdx];
|
|
197
|
+
const rowSpan = sourceCell?.rowSpan ?? 1;
|
|
198
|
+
if (!sourceCell || !measuredCell || rowSpan <= 1) continue;
|
|
199
|
+
const spanEnd = Math.min(rows.length, rowIdx + rowSpan);
|
|
200
|
+
let combinedHeight = 0;
|
|
201
|
+
for (let spannedRowIdx = rowIdx; spannedRowIdx < spanEnd; spannedRowIdx++) combinedHeight += rows[spannedRowIdx]?.height ?? 0;
|
|
202
|
+
const deficit = measuredCell.height + getTableCellVerticalBorderHeight(sourceCell, rowIdx === 0) - combinedHeight;
|
|
203
|
+
if (deficit <= 0) continue;
|
|
204
|
+
for (let spannedRowIdx = spanEnd - 1; spannedRowIdx >= rowIdx; spannedRowIdx--) {
|
|
205
|
+
if (tableBlock.rows[spannedRowIdx]?.heightRule === "exact") continue;
|
|
206
|
+
rows[spannedRowIdx].height += deficit;
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
184
211
|
const totalHeight = rows.reduce((h, r) => h + r.height, 0);
|
|
185
212
|
const totalWidth = columnWidths.reduce((w, cw) => w + cw, 0) || explicitWidthPx || contentWidth;
|
|
186
213
|
return {
|
|
@@ -197,6 +224,7 @@ function perBlockNumberValue(value, blockIndex, fallback) {
|
|
|
197
224
|
}
|
|
198
225
|
function extractFloatingZones(blocks, contentWidth, marginTop = 0, pageGeometry) {
|
|
199
226
|
const zones = [];
|
|
227
|
+
const textBoxGroupAnchors = /* @__PURE__ */ new Map();
|
|
200
228
|
const defaultMarginTop = Array.isArray(marginTop) ? marginTop[0] ?? 0 : marginTop;
|
|
201
229
|
const pageHeightInput = pageGeometry?.pageHeight ?? 0;
|
|
202
230
|
const marginBottomInput = pageGeometry?.marginBottom ?? 0;
|
|
@@ -286,28 +314,31 @@ function extractFloatingZones(blocks, contentWidth, marginTop = 0, pageGeometry)
|
|
|
286
314
|
const block = blocks[blockIndex];
|
|
287
315
|
if (block.kind !== "textBox") continue;
|
|
288
316
|
const tb = block;
|
|
289
|
-
if (!floatingTextBoxReservesBand(tb)) continue;
|
|
317
|
+
if (!floatingTextBoxReservesBand(tb) || tb.position === void 0) continue;
|
|
290
318
|
const v = tb.position?.vertical;
|
|
291
|
-
if (!isPageFrameRelativeAnchor(v?.relativeTo)) continue;
|
|
292
319
|
const height = measureTextBoxBlock(tb).height;
|
|
293
320
|
const distTop = tb.distTop ?? 0;
|
|
294
321
|
const distBottom = tb.distBottom ?? 0;
|
|
295
322
|
const blockMarginTop = perBlockNumberValue(marginTop, blockIndex, defaultMarginTop);
|
|
296
|
-
const
|
|
323
|
+
const pageFrameRelative = isPageFrameRelativeAnchor(v?.relativeTo);
|
|
324
|
+
const rawTop = pageFrameRelative ? bandTopContentY(v, {
|
|
297
325
|
pageHeight: perBlockNumberValue(pageHeightInput, blockIndex, defaultPageHeight),
|
|
298
326
|
marginTop: blockMarginTop,
|
|
299
327
|
marginBottom: perBlockNumberValue(marginBottomInput, blockIndex, defaultMarginBottom),
|
|
300
328
|
boxHeight: height
|
|
301
|
-
});
|
|
329
|
+
}) : emuToPixels(v?.posOffset ?? 0);
|
|
302
330
|
const bottomY = rawTop + height + distBottom;
|
|
303
331
|
if (bottomY <= 0) continue;
|
|
332
|
+
const groupId = getTextBoxGroupId(tb);
|
|
333
|
+
const anchorBlockIndex = groupId ? textBoxGroupAnchors.get(groupId) ?? blockIndex : blockIndex;
|
|
334
|
+
if (groupId && !textBoxGroupAnchors.has(groupId)) textBoxGroupAnchors.set(groupId, blockIndex);
|
|
304
335
|
zones.push({
|
|
305
336
|
leftMargin: 0,
|
|
306
337
|
rightMargin: 0,
|
|
307
338
|
topY: Math.max(0, rawTop - distTop),
|
|
308
339
|
bottomY,
|
|
309
|
-
anchorBlockIndex
|
|
310
|
-
isMarginRelative: true,
|
|
340
|
+
anchorBlockIndex,
|
|
341
|
+
...pageFrameRelative ? { isMarginRelative: true } : {},
|
|
311
342
|
fullWidthBlock: true
|
|
312
343
|
});
|
|
313
344
|
}
|
|
@@ -367,14 +398,15 @@ function measureTextBoxBlock(tb, fieldValues) {
|
|
|
367
398
|
};
|
|
368
399
|
}
|
|
369
400
|
/**
|
|
370
|
-
* `true` for a section break that starts a new page
|
|
371
|
-
* `oddPage
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
* band that lands right after the break.
|
|
401
|
+
* `true` for a section break that explicitly starts a new page
|
|
402
|
+
* (`nextPage`/`evenPage`/`oddPage`). An absent type follows
|
|
403
|
+
* `scheduleSectionBreak` and stays continuous, so measurement must retain any
|
|
404
|
+
* active exclusion zones across it. Used by `measureBlocks` to reset the
|
|
405
|
+
* running Y for a page-pinned band that lands right after the break.
|
|
406
|
+
* eigenpal #694.
|
|
375
407
|
*/
|
|
376
408
|
function isNextPageSectionBreak(block) {
|
|
377
|
-
return block.kind === "sectionBreak" && block.type !== "continuous";
|
|
409
|
+
return block.kind === "sectionBreak" && block.type !== void 0 && block.type !== "continuous";
|
|
378
410
|
}
|
|
379
411
|
/**
|
|
380
412
|
* Measure all blocks with floating image support.
|
|
@@ -22,8 +22,10 @@ const DEFAULT_FONT_FAMILY = "Calibri";
|
|
|
22
22
|
const DEFAULT_LINE_HEIGHT_MULTIPLIER = 1;
|
|
23
23
|
const WIDTH_TOLERANCE = .5;
|
|
24
24
|
const JUSTIFY_SHRINK_TOLERANCE_RATIO = .016;
|
|
25
|
+
const JUSTIFY_LITERAL_TAB_CONTINUATION_SHRINK_TOLERANCE_RATIO = .017;
|
|
25
26
|
const JUSTIFY_PROSE_SHRINK_TOLERANCE_RATIO = .025;
|
|
26
27
|
const JUSTIFY_HANGING_TAB_SHRINK_TOLERANCE_RATIO = .021;
|
|
28
|
+
const DEFAULT_LIST_HANGING_INDENT_PX = 24;
|
|
27
29
|
const ALL_CAPS_RATIO_THRESHOLD = .8;
|
|
28
30
|
/**
|
|
29
31
|
* Find the longest prefix of `text` that fits within `maxWidth` pixels.
|
|
@@ -270,8 +272,16 @@ function hasFollowingTabOnLine(runs, tabIndex) {
|
|
|
270
272
|
}
|
|
271
273
|
return false;
|
|
272
274
|
}
|
|
273
|
-
function
|
|
274
|
-
|
|
275
|
+
function hasPriorTabOnLine(runs, tabIndex) {
|
|
276
|
+
for (let i = tabIndex - 1; i >= 0; i--) {
|
|
277
|
+
const prior = runs[i];
|
|
278
|
+
if (!prior || isLineBreakRun(prior) || isImageRun(prior) && isBlockLayoutImageRun(prior)) break;
|
|
279
|
+
if (isTabRun(prior)) return true;
|
|
280
|
+
}
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
function canClampTabToRightEdge(alignment, currentLineWidth, hasPriorTab, followingWidth, availableWidth) {
|
|
284
|
+
if (alignment === "start" || alignment === "default") return currentLineWidth > WIDTH_TOLERANCE && (hasPriorTab || followingWidth <= availableWidth);
|
|
275
285
|
return true;
|
|
276
286
|
}
|
|
277
287
|
/**
|
|
@@ -319,10 +329,18 @@ function uppercaseLetterRatio(text) {
|
|
|
319
329
|
}
|
|
320
330
|
return letters === 0 ? 0 : uppercase / letters;
|
|
321
331
|
}
|
|
322
|
-
function justifyShrinkToleranceRatio(block) {
|
|
332
|
+
function justifyShrinkToleranceRatio(block, isFirstLine, regularSpaceCount, nonBreakingSpaceCount) {
|
|
333
|
+
if (block.attrs?.listMarker !== void 0) {
|
|
334
|
+
if ((block.attrs.indent?.hanging ?? 0) <= DEFAULT_LIST_HANGING_INDENT_PX) return JUSTIFY_SHRINK_TOLERANCE_RATIO;
|
|
335
|
+
if (isFirstLine) return JUSTIFY_HANGING_TAB_SHRINK_TOLERANCE_RATIO;
|
|
336
|
+
const totalSpaces = regularSpaceCount + nonBreakingSpaceCount;
|
|
337
|
+
if (totalSpaces === 0) return JUSTIFY_PROSE_SHRINK_TOLERANCE_RATIO;
|
|
338
|
+
return Math.max(JUSTIFY_SHRINK_TOLERANCE_RATIO, JUSTIFY_PROSE_SHRINK_TOLERANCE_RATIO * (regularSpaceCount / totalSpaces));
|
|
339
|
+
}
|
|
323
340
|
const hasTabStops = (block.attrs?.tabs?.length ?? 0) > 0;
|
|
324
341
|
const hasTabRuns = block.runs.some(isTabRun);
|
|
325
|
-
if (
|
|
342
|
+
if (!isFirstLine && hasTabRuns && !hasTabStops) return JUSTIFY_LITERAL_TAB_CONTINUATION_SHRINK_TOLERANCE_RATIO;
|
|
343
|
+
if ((isFirstLine || hasTabStops) && (hasTabStops || hasTabRuns)) return (block.attrs?.indent?.firstLine ?? 0) === 0 ? JUSTIFY_HANGING_TAB_SHRINK_TOLERANCE_RATIO : JUSTIFY_SHRINK_TOLERANCE_RATIO;
|
|
326
344
|
if (uppercaseLetterRatio(block.runs.map((run) => isTextRun(run) ? run.text ?? "" : "").join("")) > ALL_CAPS_RATIO_THRESHOLD) return JUSTIFY_SHRINK_TOLERANCE_RATIO;
|
|
327
345
|
return JUSTIFY_PROSE_SHRINK_TOLERANCE_RATIO;
|
|
328
346
|
}
|
|
@@ -412,7 +430,6 @@ function measureParagraph(block, maxWidth, options) {
|
|
|
412
430
|
const attrs = block.attrs;
|
|
413
431
|
const spacing = attrs?.spacing;
|
|
414
432
|
const isJustifiedParagraph = attrs?.alignment === "justify";
|
|
415
|
-
const justifyToleranceRatio = justifyShrinkToleranceRatio(block);
|
|
416
433
|
const floatingZones = options?.floatingZones;
|
|
417
434
|
const paragraphYOffset = options?.paragraphYOffset ?? 0;
|
|
418
435
|
const indent = attrs?.indent;
|
|
@@ -506,6 +523,9 @@ function measureParagraph(block, maxWidth, options) {
|
|
|
506
523
|
toRun: 0,
|
|
507
524
|
toChar: 0,
|
|
508
525
|
width: 0,
|
|
526
|
+
trailingWhitespaceWidth: 0,
|
|
527
|
+
regularSpaceCount: 0,
|
|
528
|
+
nonBreakingSpaceCount: 0,
|
|
509
529
|
maxFontSize: DEFAULT_FONT_SIZE,
|
|
510
530
|
maxFontMetrics: null,
|
|
511
531
|
maxImageHeightPx: 0,
|
|
@@ -552,7 +572,7 @@ function measureParagraph(block, maxWidth, options) {
|
|
|
552
572
|
fromChar: currentLine.fromChar,
|
|
553
573
|
toRun: currentLine.toRun,
|
|
554
574
|
toChar: currentLine.toChar,
|
|
555
|
-
width: currentLine.width,
|
|
575
|
+
width: Math.max(0, currentLine.width - currentLine.trailingWhitespaceWidth),
|
|
556
576
|
...finalTypography
|
|
557
577
|
};
|
|
558
578
|
if (currentLine.leftOffset > 0) line.leftOffset = currentLine.leftOffset;
|
|
@@ -572,17 +592,21 @@ function measureParagraph(block, maxWidth, options) {
|
|
|
572
592
|
const estimatedLineHeight = ptToPx(DEFAULT_FONT_SIZE) * DEFAULT_LINE_HEIGHT_MULTIPLIER;
|
|
573
593
|
skipObstructingFloats(estimatedLineHeight, bodyContentWidth);
|
|
574
594
|
const floatingMargins = getFloatingMargins(cumulativeHeight, estimatedLineHeight, floatingZones, paragraphYOffset);
|
|
595
|
+
const adjustedWidth = Math.max(1, getFloatingAvailableWidth(floatingMargins, bodyContentWidth));
|
|
575
596
|
currentLine = {
|
|
576
597
|
fromRun: runIndex,
|
|
577
598
|
fromChar: charIndex,
|
|
578
599
|
toRun: runIndex,
|
|
579
600
|
toChar: charIndex,
|
|
580
601
|
width: 0,
|
|
602
|
+
trailingWhitespaceWidth: 0,
|
|
603
|
+
regularSpaceCount: 0,
|
|
604
|
+
nonBreakingSpaceCount: 0,
|
|
581
605
|
maxFontSize: DEFAULT_FONT_SIZE,
|
|
582
606
|
maxFontMetrics: null,
|
|
583
607
|
maxImageHeightPx: 0,
|
|
584
608
|
maxMathHeightPx: 0,
|
|
585
|
-
availableWidth:
|
|
609
|
+
availableWidth: adjustedWidth,
|
|
586
610
|
leftOffset: floatingMargins.leftMargin,
|
|
587
611
|
rightOffset: floatingMargins.rightMargin,
|
|
588
612
|
...floatingMargins.segments?.length ? { segmentZones: floatingMargins.segments } : {}
|
|
@@ -620,6 +644,7 @@ function measureParagraph(block, maxWidth, options) {
|
|
|
620
644
|
const contentX = indentLeft + (isFirstLine ? firstLineOffset + markerInlineWidth : 0) + lineX;
|
|
621
645
|
const tabResult = calculateTabWidth(contentX, {
|
|
622
646
|
...attrs?.tabs !== void 0 ? { explicitStops: attrs.tabs } : {},
|
|
647
|
+
...attrs?.defaultTabStopTwips !== void 0 ? { defaultTabInterval: attrs.defaultTabStopTwips } : {},
|
|
623
648
|
leftIndent: pixelsToTwips(indentLeft)
|
|
624
649
|
}, {
|
|
625
650
|
followingWidth,
|
|
@@ -627,12 +652,13 @@ function measureParagraph(block, maxWidth, options) {
|
|
|
627
652
|
});
|
|
628
653
|
let tabWidth = tabResult.width;
|
|
629
654
|
const lineRightEdgeX = indentLeft + (isFirstLine ? firstLineOffset + markerInlineWidth : 0) + currentLine.availableWidth + currentLine.leftOffset;
|
|
630
|
-
if (!hasFollowingTabOnLine(runs, runIndex) && canClampTabToRightEdge(tabResult.alignment, currentLine.width) && (tabWidth > 0 || followingWidth > 0) && contentX + tabWidth + followingWidth > lineRightEdgeX + WIDTH_TOLERANCE) tabWidth = Math.max(1, lineRightEdgeX - contentX - followingWidth);
|
|
655
|
+
if (!hasFollowingTabOnLine(runs, runIndex) && canClampTabToRightEdge(tabResult.alignment, currentLine.width, hasPriorTabOnLine(runs, runIndex), followingWidth, currentLine.availableWidth) && (tabWidth > 0 || followingWidth > 0) && contentX + tabWidth + followingWidth > lineRightEdgeX + WIDTH_TOLERANCE) tabWidth = Math.max(1, lineRightEdgeX - contentX - followingWidth);
|
|
631
656
|
if (currentLine.width + tabWidth > currentLine.availableWidth + WIDTH_TOLERANCE) {
|
|
632
657
|
startNewLine(runIndex, 0);
|
|
633
658
|
updateMaxFont(style);
|
|
634
659
|
}
|
|
635
660
|
currentLine.width += tabWidth;
|
|
661
|
+
currentLine.trailingWhitespaceWidth = 0;
|
|
636
662
|
currentLine.toRun = runIndex;
|
|
637
663
|
currentLine.toChar = 1;
|
|
638
664
|
continue;
|
|
@@ -662,6 +688,7 @@ function measureParagraph(block, maxWidth, options) {
|
|
|
662
688
|
const imageFootprintPx = imageHeight + (run.distTop ?? 0) + (run.distBottom ?? 0);
|
|
663
689
|
if (imageFootprintPx > currentLine.maxImageHeightPx) currentLine.maxImageHeightPx = imageFootprintPx;
|
|
664
690
|
currentLine.width += imageWidth;
|
|
691
|
+
currentLine.trailingWhitespaceWidth = 0;
|
|
665
692
|
currentLine.toRun = runIndex;
|
|
666
693
|
currentLine.toChar = 1;
|
|
667
694
|
continue;
|
|
@@ -676,6 +703,7 @@ function measureParagraph(block, maxWidth, options) {
|
|
|
676
703
|
updateMaxFont(style);
|
|
677
704
|
}
|
|
678
705
|
currentLine.width += fieldWidth;
|
|
706
|
+
currentLine.trailingWhitespaceWidth = 0;
|
|
679
707
|
currentLine.toRun = runIndex;
|
|
680
708
|
currentLine.toChar = 1;
|
|
681
709
|
continue;
|
|
@@ -696,6 +724,7 @@ function measureParagraph(block, maxWidth, options) {
|
|
|
696
724
|
}
|
|
697
725
|
if (mathFootprintPx > currentLine.maxMathHeightPx) currentLine.maxMathHeightPx = mathFootprintPx;
|
|
698
726
|
currentLine.width += mathWidth;
|
|
727
|
+
currentLine.trailingWhitespaceWidth = 0;
|
|
699
728
|
currentLine.toRun = runIndex;
|
|
700
729
|
currentLine.toChar = 1;
|
|
701
730
|
continue;
|
|
@@ -720,13 +749,17 @@ function measureParagraph(block, maxWidth, options) {
|
|
|
720
749
|
break;
|
|
721
750
|
}
|
|
722
751
|
const word = text.slice(charIndex, nextBreak);
|
|
723
|
-
const
|
|
724
|
-
const
|
|
752
|
+
const measuredWord = trimTrailingSpacesAndTabs(word);
|
|
753
|
+
const wordWidth = measureTextWidth(measuredWord, style);
|
|
754
|
+
const fullWordWidth = measureTextWidth(word, style);
|
|
755
|
+
const regularSpaces = measuredWord.split(" ").length - 1;
|
|
756
|
+
const nonBreakingSpaces = measuredWord.split("\xA0").length - 1;
|
|
757
|
+
const widthTolerance = isJustifiedParagraph ? Math.max(WIDTH_TOLERANCE, currentLine.availableWidth * justifyShrinkToleranceRatio(block, lines.length === 0, currentLine.regularSpaceCount + regularSpaces, currentLine.nonBreakingSpaceCount + nonBreakingSpaces)) : WIDTH_TOLERANCE;
|
|
725
758
|
if (wordWidth > currentLine.availableWidth + widthTolerance) {
|
|
726
759
|
let chunkStart = 0;
|
|
727
|
-
while (chunkStart <
|
|
760
|
+
while (chunkStart < measuredWord.length) {
|
|
728
761
|
const spaceLeft = currentLine.availableWidth - currentLine.width + WIDTH_TOLERANCE;
|
|
729
|
-
let bestEnd = findMaxFittingLength(
|
|
762
|
+
let bestEnd = findMaxFittingLength(measuredWord.slice(chunkStart), style, spaceLeft);
|
|
730
763
|
if (bestEnd === 0) {
|
|
731
764
|
if (currentLine.width > 0) {
|
|
732
765
|
startNewLine(runIndex, charIndex + chunkStart);
|
|
@@ -736,16 +769,26 @@ function measureParagraph(block, maxWidth, options) {
|
|
|
736
769
|
bestEnd = 1;
|
|
737
770
|
}
|
|
738
771
|
const chunkEnd = chunkStart + bestEnd;
|
|
739
|
-
const
|
|
772
|
+
const chunk = measuredWord.slice(chunkStart, chunkEnd);
|
|
773
|
+
const chunkWidth = measureTextWidth(chunk, style);
|
|
740
774
|
currentLine.width += chunkWidth;
|
|
775
|
+
currentLine.trailingWhitespaceWidth = chunkWidth - measureTextWidth(trimTrailingSpacesAndTabs(chunk), style);
|
|
776
|
+
currentLine.regularSpaceCount += chunk.split(" ").length - 1;
|
|
777
|
+
currentLine.nonBreakingSpaceCount += chunk.split("\xA0").length - 1;
|
|
741
778
|
currentLine.toRun = runIndex;
|
|
742
779
|
currentLine.toChar = charIndex + chunkEnd;
|
|
743
780
|
chunkStart = chunkEnd;
|
|
744
|
-
if (chunkStart <
|
|
781
|
+
if (chunkStart < measuredWord.length) {
|
|
745
782
|
startNewLine(runIndex, charIndex + chunkStart);
|
|
746
783
|
updateMaxFont(lineHeightStyle);
|
|
747
784
|
}
|
|
748
785
|
}
|
|
786
|
+
const trailingWhitespaceWidth = fullWordWidth - wordWidth;
|
|
787
|
+
currentLine.width += trailingWhitespaceWidth;
|
|
788
|
+
currentLine.trailingWhitespaceWidth = trailingWhitespaceWidth;
|
|
789
|
+
currentLine.regularSpaceCount += word.split(" ").length - 1;
|
|
790
|
+
currentLine.nonBreakingSpaceCount += word.split("\xA0").length - 1;
|
|
791
|
+
currentLine.toChar = nextBreak;
|
|
749
792
|
charIndex = nextBreak;
|
|
750
793
|
continue;
|
|
751
794
|
}
|
|
@@ -755,7 +798,10 @@ function measureParagraph(block, maxWidth, options) {
|
|
|
755
798
|
startNewLine(runIndex, charIndex);
|
|
756
799
|
updateMaxFont(lineHeightStyle);
|
|
757
800
|
}
|
|
758
|
-
currentLine.width +=
|
|
801
|
+
currentLine.width += fullWordWidth;
|
|
802
|
+
currentLine.trailingWhitespaceWidth = fullWordWidth - wordWidth;
|
|
803
|
+
currentLine.regularSpaceCount += word.split(" ").length - 1;
|
|
804
|
+
currentLine.nonBreakingSpaceCount += word.split("\xA0").length - 1;
|
|
759
805
|
currentLine.toRun = runIndex;
|
|
760
806
|
currentLine.toChar = nextBreak;
|
|
761
807
|
charIndex = nextBreak;
|
|
@@ -27,7 +27,8 @@ type PaginatorOptions = {
|
|
|
27
27
|
w: number;
|
|
28
28
|
h: number;
|
|
29
29
|
}; /** Page margins. */
|
|
30
|
-
margins: PageMargins;
|
|
30
|
+
margins: PageMargins; /** Swap left/right margins on even physical pages. */
|
|
31
|
+
mirrorMargins?: boolean;
|
|
31
32
|
/**
|
|
32
33
|
* Margins applied only to the very first page (page 1) of the paginator.
|
|
33
34
|
* Used when a `<w:titlePg/>`-enabled section needs different margins for
|
|
@@ -46,7 +46,7 @@ function createPaginator(options) {
|
|
|
46
46
|
}
|
|
47
47
|
function currentPageUsesActiveLayout(state) {
|
|
48
48
|
if (pendingPageSize || pendingMargins) return false;
|
|
49
|
-
return arePageSizesEqual(state.page.size, pageSize) && areMarginsEqual(state.page.margins,
|
|
49
|
+
return arePageSizesEqual(state.page.size, pageSize) && areMarginsEqual(state.page.margins, getPageMargins(state.page.number));
|
|
50
50
|
}
|
|
51
51
|
if (getContentHeight() <= 0) panic("Paginator: page size and margins yield no content area");
|
|
52
52
|
let columnWidth = calculateColumnWidth(pageSize.w, margins.left, margins.right, columns);
|
|
@@ -62,14 +62,20 @@ function createPaginator(options) {
|
|
|
62
62
|
recalculateColumnWidth();
|
|
63
63
|
}
|
|
64
64
|
function getPageMargins(pageNumber) {
|
|
65
|
-
|
|
65
|
+
const pageMargins = pageNumber === 1 && options.firstPageMargins ? { ...options.firstPageMargins } : { ...margins };
|
|
66
|
+
if (options.mirrorMargins === true && pageNumber % 2 === 0) return {
|
|
67
|
+
...pageMargins,
|
|
68
|
+
left: pageMargins.right,
|
|
69
|
+
right: pageMargins.left
|
|
70
|
+
};
|
|
71
|
+
return pageMargins;
|
|
66
72
|
}
|
|
67
73
|
let columnRegionTop = margins.top;
|
|
68
74
|
/**
|
|
69
75
|
* Get X position for a given column index.
|
|
70
76
|
*/
|
|
71
77
|
function getColumnX(columnIndex) {
|
|
72
|
-
return margins.left + columnIndex * (columnWidth + columns.gap);
|
|
78
|
+
return (states.at(-1)?.page.margins.left ?? getPageMargins(1).left) + columnIndex * (columnWidth + columns.gap);
|
|
73
79
|
}
|
|
74
80
|
/**
|
|
75
81
|
* Create a new page and add it to the list.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { TextBoxBlock } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/layout-engine/textBoxGroup.d.ts
|
|
4
|
+
declare const setTextBoxGroupId: (textBox: TextBoxBlock, groupId: string) => void;
|
|
5
|
+
declare const getTextBoxGroupId: (textBox: TextBoxBlock) => string | undefined;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { getTextBoxGroupId, setTextBoxGroupId };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/layout-engine/textBoxGroup.ts
|
|
2
|
+
const textBoxGroupIds = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
const setTextBoxGroupId = (textBox, groupId) => {
|
|
4
|
+
textBoxGroupIds.set(textBox, groupId);
|
|
5
|
+
};
|
|
6
|
+
const getTextBoxGroupId = (textBox) => textBoxGroupIds.get(textBox);
|
|
7
|
+
//#endregion
|
|
8
|
+
export { getTextBoxGroupId, setTextBoxGroupId };
|