@stll/folio-core 0.37.2 → 0.37.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/ai-edits/table-cell-mutations.js +10 -5
- package/dist/ai-edits/table-template.js +19 -5
- package/dist/controller/hiddenEditorManager.js +11 -0
- package/dist/controller/layoutPipeline.js +1 -1
- package/dist/display-list/build/textBoxPrimitives.js +34 -1
- package/dist/display-list/dom/renderDisplayListToDom.js +5 -2
- package/dist/display-list/types.d.ts +8 -4
- package/dist/docx/paragraphPropertySource.d.ts +82 -2
- package/dist/docx/paragraphPropertySource.js +569 -3
- package/dist/docx/parser.js +9 -0
- package/dist/docx/server/materializeYjsDocx.d.ts +1 -1
- package/dist/docx/server/materializeYjsDocx.js +21 -2
- package/dist/headless-layout.js +1 -1
- package/dist/layout-bridge/convert/headerFooterLayout.d.ts +7 -1
- package/dist/layout-bridge/convert/headerFooterLayout.js +20 -3
- package/dist/layout-bridge/convert/toFlowBlocks.js +43 -12
- package/dist/layout-engine/index.js +20 -10
- package/dist/layout-engine/measure/measureBlocks.d.ts +7 -3
- package/dist/layout-engine/measure/measureBlocks.js +10 -7
- package/dist/layout-engine/measure/measureParagraph.d.ts +2 -0
- package/dist/layout-engine/measure/measureParagraph.js +1 -1
- package/dist/layout-engine/paginator.d.ts +1 -1
- package/dist/layout-engine/paginator.js +41 -4
- package/dist/layout-engine/textBoxFlow.d.ts +2 -0
- package/dist/layout-engine/textBoxFlow.js +9 -5
- package/dist/layout-engine/types.d.ts +6 -0
- package/dist/layout-painter/documentColors.d.ts +10 -1
- package/dist/layout-painter/documentColors.js +16 -1
- package/dist/layout-painter/renderParagraph.js +9 -24
- package/dist/layout-painter/renderTable.js +3 -3
- package/dist/layout-painter/renderTextBox.js +2 -1
- package/dist/pdf/pageSpace.d.ts +12 -1
- package/dist/pdf/pageSpace.js +24 -1
- package/dist/pdf/paint.js +2 -2
- package/dist/prosemirror/attrs/index.js +32 -8
- package/dist/prosemirror/commands/comments.js +12 -3
- package/dist/prosemirror/commands/tableCellMergeResolution.js +18 -11
- package/dist/prosemirror/conversion/fromProseDoc.js +114 -25
- package/dist/prosemirror/conversion/toProseDoc.js +101 -8
- package/dist/prosemirror/extensions/core/DocExtension.js +2 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +2 -0
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.d.ts +5 -1
- package/dist/prosemirror/extensions/features/ParaIdAllocatorExtension.js +132 -41
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.d.ts +2 -61
- package/dist/prosemirror/extensions/nodes/TextBoxExtension.js +16 -0
- package/dist/prosemirror/schema/nodes.d.ts +14 -2
- package/dist/prosemirror/schema/nodes.js +7 -0
- package/dist/prosemirror/yjsParagraphSourceContract.d.ts +9 -0
- package/dist/prosemirror/yjsParagraphSourceContract.js +26 -0
- package/dist/utils/rotationBoundingBox.d.ts +5 -1
- package/dist/utils/rotationBoundingBox.js +9 -1
- package/package.json +2 -2
|
@@ -604,6 +604,8 @@ type TableRow = {
|
|
|
604
604
|
isHeader?: boolean;
|
|
605
605
|
/** `w:cantSplit`: keep this row in one flow region. */
|
|
606
606
|
cantSplit?: boolean;
|
|
607
|
+
/** A leading authored page break in a cell advances the whole row. */
|
|
608
|
+
breakBefore?: "page";
|
|
607
609
|
hidden?: boolean;
|
|
608
610
|
};
|
|
609
611
|
/**
|
|
@@ -802,6 +804,8 @@ type TextBoxBlock = {
|
|
|
802
804
|
outlineColor?: string;
|
|
803
805
|
/** Outline dash style, or `"none"` for an explicit no-outline. */
|
|
804
806
|
outlineStyle?: OutlineStyleAttr;
|
|
807
|
+
/** DrawingML rotation and/or flips, serialized as CSS transform functions. */
|
|
808
|
+
transform?: string;
|
|
805
809
|
/** Internal padding */
|
|
806
810
|
margins?: {
|
|
807
811
|
top: number;
|
|
@@ -1032,6 +1036,8 @@ type FragmentBase = {
|
|
|
1032
1036
|
*/
|
|
1033
1037
|
type ParagraphFragment = FragmentBase & {
|
|
1034
1038
|
kind: "paragraph";
|
|
1039
|
+
/** Structural PM carrier that must not make an otherwise blank page visible. */
|
|
1040
|
+
paginationRole?: "empty-carrier";
|
|
1035
1041
|
/** First line index (inclusive) from the measure. */
|
|
1036
1042
|
fromLine: number;
|
|
1037
1043
|
/** Last line index (exclusive) from the measure. */
|
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
//#region src/layout-painter/documentColors.d.ts
|
|
2
|
+
declare const AUTHORED_BACKGROUND_COLOR_VAR = "--doc-authored-background-color";
|
|
3
|
+
declare const AUTHORED_TEXT_COLOR_VAR = "--doc-run-color";
|
|
4
|
+
/** Paint a document text color and expose it to the dark-mode color transform. */
|
|
5
|
+
declare const setAuthoredTextColor: (style: CSSStyleDeclaration, color: string) => void;
|
|
6
|
+
/**
|
|
7
|
+
* Paint an OOXML background and retain its authored color for dark-mode adaptation.
|
|
8
|
+
* The custom property is presentation-only; serialization still uses the model value.
|
|
9
|
+
*/
|
|
10
|
+
declare const setAuthoredBackgroundColor: (style: CSSStyleDeclaration, color: string) => void;
|
|
2
11
|
declare function getAutomaticTextColorForBackground(backgroundColor: string | undefined): string | undefined;
|
|
3
12
|
//#endregion
|
|
4
|
-
export { getAutomaticTextColorForBackground };
|
|
13
|
+
export { AUTHORED_BACKGROUND_COLOR_VAR, AUTHORED_TEXT_COLOR_VAR, getAutomaticTextColorForBackground, setAuthoredBackgroundColor, setAuthoredTextColor };
|
|
@@ -5,6 +5,21 @@ const WHITE_TEXT_COLOR = "#FFFFFF";
|
|
|
5
5
|
const BLACK_LUMINANCE = 0;
|
|
6
6
|
const WHITE_LUMINANCE = 1;
|
|
7
7
|
const CONTRAST_OFFSET = .05;
|
|
8
|
+
const AUTHORED_BACKGROUND_COLOR_VAR = "--doc-authored-background-color";
|
|
9
|
+
const AUTHORED_TEXT_COLOR_VAR = "--doc-run-color";
|
|
10
|
+
/** Paint a document text color and expose it to the dark-mode color transform. */
|
|
11
|
+
const setAuthoredTextColor = (style, color) => {
|
|
12
|
+
style.color = color;
|
|
13
|
+
style.setProperty(AUTHORED_TEXT_COLOR_VAR, color);
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Paint an OOXML background and retain its authored color for dark-mode adaptation.
|
|
17
|
+
* The custom property is presentation-only; serialization still uses the model value.
|
|
18
|
+
*/
|
|
19
|
+
const setAuthoredBackgroundColor = (style, color) => {
|
|
20
|
+
style.backgroundColor = color;
|
|
21
|
+
style.setProperty(AUTHORED_BACKGROUND_COLOR_VAR, color);
|
|
22
|
+
};
|
|
8
23
|
function normalizeHexColor(color) {
|
|
9
24
|
const trimmed = color.trim();
|
|
10
25
|
if (!HEX_COLOR_RE.test(trimmed)) return null;
|
|
@@ -37,4 +52,4 @@ function getAutomaticTextColorForBackground(backgroundColor) {
|
|
|
37
52
|
return contrastRatio(luminance, BLACK_LUMINANCE) >= contrastRatio(luminance, WHITE_LUMINANCE) ? BLACK_TEXT_COLOR : WHITE_TEXT_COLOR;
|
|
38
53
|
}
|
|
39
54
|
//#endregion
|
|
40
|
-
export { getAutomaticTextColorForBackground };
|
|
55
|
+
export { AUTHORED_BACKGROUND_COLOR_VAR, AUTHORED_TEXT_COLOR_VAR, getAutomaticTextColorForBackground, setAuthoredBackgroundColor, setAuthoredTextColor };
|
|
@@ -19,7 +19,7 @@ import { SCRIPT_CLASS, hasCjk, hasComplexScript, segmentByScript } from "../util
|
|
|
19
19
|
import { sanitizeExternalUrl } from "../utils/urlSecurity.js";
|
|
20
20
|
import { borderStrokeToCss, resolveParagraphBorderHorizontalOutsets } from "./borderStroke.js";
|
|
21
21
|
import { planCursiveJoiners, withCursiveJoiners } from "./cursiveJoiners.js";
|
|
22
|
-
import { getAutomaticTextColorForBackground } from "./documentColors.js";
|
|
22
|
+
import { getAutomaticTextColorForBackground, setAuthoredBackgroundColor, setAuthoredTextColor } from "./documentColors.js";
|
|
23
23
|
import { applyImageBorder, applyImageVisualAttrs, hasImageCrop, hasImageVisualAttrs, wrapImageWithCrop } from "./renderImage.js";
|
|
24
24
|
import { resolveImageLineAlign } from "./renderUtils.js";
|
|
25
25
|
import { applySdtDataAttrs } from "./sdtBoundary.js";
|
|
@@ -124,12 +124,6 @@ const DEFAULT_BLACK_TEXT_COLOR_VALUES = /* @__PURE__ */ new Set(["000000", "000"
|
|
|
124
124
|
const SUGGESTION_COLOR_CSS = "var(--suggestion-color, #6d3bd6)";
|
|
125
125
|
const SUGGESTION_TINT_CSS = "var(--suggestion-bg, color-mix(in oklch, #6d3bd6 12%, transparent))";
|
|
126
126
|
const SUGGESTION_TINT_LAYER_CSS = `linear-gradient(${SUGGESTION_TINT_CSS}, ${SUGGESTION_TINT_CSS})`;
|
|
127
|
-
const RUN_BACKGROUND_TEXT_COLOR_VAR = "--doc-run-background-text-color";
|
|
128
|
-
const setRunBackgroundTextColor = (element, color) => {
|
|
129
|
-
element.classList.add("docx-run-background-text");
|
|
130
|
-
element.style.setProperty(RUN_BACKGROUND_TEXT_COLOR_VAR, color);
|
|
131
|
-
};
|
|
132
|
-
const hasRunBackgroundTextSurface = (run) => Boolean(run.highlight ?? run.shading) && !run.isInsertion && !run.isDeletion && !(run.commentIds !== void 0 && run.commentIds.length > 0);
|
|
133
127
|
function normalizeTextColorValue(color) {
|
|
134
128
|
return color.trim().toLowerCase().replace(/^#/u, "");
|
|
135
129
|
}
|
|
@@ -180,8 +174,7 @@ function applyRunStyles(element, run) {
|
|
|
180
174
|
let hasExplicitTextColor = false;
|
|
181
175
|
const textColor = getRenderableTextColor(run);
|
|
182
176
|
if (textColor) {
|
|
183
|
-
element.style
|
|
184
|
-
element.style.setProperty("--doc-run-color", textColor);
|
|
177
|
+
setAuthoredTextColor(element.style, textColor);
|
|
185
178
|
hasExplicitTextColor = true;
|
|
186
179
|
}
|
|
187
180
|
if (run.letterSpacing) element.style.letterSpacing = `${run.letterSpacing}px`;
|
|
@@ -219,13 +212,11 @@ function applyRunStyles(element, run) {
|
|
|
219
212
|
}
|
|
220
213
|
const runBackground = run.highlight ?? run.shading;
|
|
221
214
|
if (runBackground) {
|
|
222
|
-
element.style
|
|
215
|
+
setAuthoredBackgroundColor(element.style, runBackground);
|
|
223
216
|
const hasTrackedChangeColor = run.isInsertion || run.isDeletion;
|
|
224
217
|
const hasCommentHighlight = run.commentIds !== void 0 && run.commentIds.length > 0;
|
|
225
218
|
const automaticTextColor = hasExplicitTextColor || hasTrackedChangeColor || hasCommentHighlight ? void 0 : getAutomaticTextColorForBackground(runBackground);
|
|
226
|
-
if (automaticTextColor) element.style
|
|
227
|
-
const backgroundTextColor = hasExplicitTextColor ? textColor : automaticTextColor;
|
|
228
|
-
if (backgroundTextColor && hasRunBackgroundTextSurface(run)) setRunBackgroundTextColor(element, backgroundTextColor);
|
|
219
|
+
if (automaticTextColor) setAuthoredTextColor(element.style, automaticTextColor);
|
|
229
220
|
}
|
|
230
221
|
const decorations = [];
|
|
231
222
|
let explicitDecorationStyle = false;
|
|
@@ -378,15 +369,9 @@ function renderTextRun(run, doc, options) {
|
|
|
378
369
|
});
|
|
379
370
|
if (!run.hyperlink.noDefaultStyle) {
|
|
380
371
|
const hyperlinkColor = getHyperlinkTextColor(run, span.style.color);
|
|
381
|
-
anchor.style
|
|
372
|
+
setAuthoredTextColor(anchor.style, hyperlinkColor);
|
|
382
373
|
anchor.style.textDecoration = "underline";
|
|
383
|
-
span.style
|
|
384
|
-
anchor.style.setProperty("--doc-run-color", hyperlinkColor);
|
|
385
|
-
span.style.setProperty("--doc-run-color", hyperlinkColor);
|
|
386
|
-
if (hasRunBackgroundTextSurface(run)) {
|
|
387
|
-
setRunBackgroundTextColor(span, hyperlinkColor);
|
|
388
|
-
setRunBackgroundTextColor(anchor, hyperlinkColor);
|
|
389
|
-
}
|
|
374
|
+
setAuthoredTextColor(span.style, hyperlinkColor);
|
|
390
375
|
}
|
|
391
376
|
span.append(anchor);
|
|
392
377
|
} else appendPaintedText({
|
|
@@ -1295,7 +1280,7 @@ function renderLine(block, line, alignment, doc, options) {
|
|
|
1295
1280
|
}
|
|
1296
1281
|
const authoredEndpoint = currentX + tabResult.width + followingWidthForCheck;
|
|
1297
1282
|
const activeContentRightEdge = options?.contentWidthPx === void 0 ? void 0 : options.contentWidthPx - (options.floatingMargins?.rightMargin ?? 0);
|
|
1298
|
-
const preservesAuthoredEndStop = activeContentRightEdge !== void 0 && tabResult.alignment === "end" && authoredEndpoint <= activeContentRightEdge + RIGHT_EDGE_EPSILON_PX;
|
|
1283
|
+
const preservesAuthoredEndStop = activeContentRightEdge !== void 0 && tabResult.alignment === "end" && (options?.context?.section === "header" || options?.context?.section === "footer" || authoredEndpoint <= activeContentRightEdge + RIGHT_EDGE_EPSILON_PX);
|
|
1299
1284
|
const preservesAuthoredEndStopPastIndent = lineRightEdgeX !== void 0 && preservesAuthoredEndStop && authoredEndpoint > lineRightEdgeX + RIGHT_EDGE_EPSILON_PX;
|
|
1300
1285
|
if (lineRightEdgeX !== void 0 && options?.isRtl !== true && tabResult.alignment === "end" && !hasFollowingTab && !preservesAuthoredEndStopPastIndent && authoredEndpoint >= lineRightEdgeX - RIGHT_EDGE_EPSILON_PX) {
|
|
1301
1286
|
lineEl.style.display = "flex";
|
|
@@ -1534,9 +1519,9 @@ function renderParagraphFragment(fragment, block, measure, context, options = {}
|
|
|
1534
1519
|
}
|
|
1535
1520
|
}
|
|
1536
1521
|
if (block.attrs?.shading) {
|
|
1537
|
-
fragmentEl.style
|
|
1522
|
+
setAuthoredBackgroundColor(fragmentEl.style, block.attrs.shading);
|
|
1538
1523
|
const automaticTextColor = getAutomaticTextColorForBackground(block.attrs.shading);
|
|
1539
|
-
if (automaticTextColor) fragmentEl.style
|
|
1524
|
+
if (automaticTextColor) setAuthoredTextColor(fragmentEl.style, automaticTextColor);
|
|
1540
1525
|
}
|
|
1541
1526
|
const availableWidth = fragment.width - indentLeft - indentRight;
|
|
1542
1527
|
const paragraphEndsWithLineBreak = block.runs.at(-1)?.kind === "lineBreak";
|
|
@@ -9,7 +9,7 @@ import { applySanitizedImageSrc } from "../utils/sanitizeImageSrc.js";
|
|
|
9
9
|
import { emuToPixels } from "../utils/units.js";
|
|
10
10
|
import { resolveAnchoredImagePosition } from "./anchoredImagePosition.js";
|
|
11
11
|
import { borderStrokeToCss, resolveCssBorderStroke } from "./borderStroke.js";
|
|
12
|
-
import { getAutomaticTextColorForBackground } from "./documentColors.js";
|
|
12
|
+
import { getAutomaticTextColorForBackground, setAuthoredBackgroundColor, setAuthoredTextColor } from "./documentColors.js";
|
|
13
13
|
import { applyImageVisualAttrs, hasImageCrop, hasImageVisualAttrs } from "./renderImage.js";
|
|
14
14
|
import { renderParagraphFragment } from "./renderParagraph.js";
|
|
15
15
|
import { renderTextBoxFragment } from "./renderTextBox.js";
|
|
@@ -394,9 +394,9 @@ function renderTableCell({ cell, cellMeasure, x, width, rowHeight, borderFlags,
|
|
|
394
394
|
if (borderFlags.drawLeft) applyBorder(cellEl, "left", cell.borders.left);
|
|
395
395
|
}
|
|
396
396
|
if (cell.background) {
|
|
397
|
-
cellEl.style
|
|
397
|
+
setAuthoredBackgroundColor(cellEl.style, cell.background);
|
|
398
398
|
const automaticTextColor = getAutomaticTextColorForBackground(cell.background);
|
|
399
|
-
if (automaticTextColor) cellEl.style
|
|
399
|
+
if (automaticTextColor) setAuthoredTextColor(cellEl.style, automaticTextColor);
|
|
400
400
|
}
|
|
401
401
|
if (cell.noWrap && !columnsPinned) cellEl.style.whiteSpace = "nowrap";
|
|
402
402
|
if (cell.verticalAlign) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { layoutTextBoxContent } from "../layout-engine/measure/textBoxParagraphLayout.js";
|
|
2
2
|
import { DEFAULT_TEXTBOX_MARGINS } from "../layout-engine/types.js";
|
|
3
|
+
import { setAuthoredBackgroundColor } from "./documentColors.js";
|
|
3
4
|
import { renderParagraphFragment } from "./renderParagraph.js";
|
|
4
5
|
import { panic } from "better-result";
|
|
5
6
|
//#region src/layout-painter/renderTextBox.ts
|
|
@@ -28,7 +29,7 @@ function renderTextBoxFragment(fragment, block, measure, context, options = {})
|
|
|
28
29
|
containerEl.style.height = `${fragment.height}px`;
|
|
29
30
|
containerEl.style.overflow = block.textWrap === "none" ? "visible" : "hidden";
|
|
30
31
|
containerEl.style.boxSizing = "border-box";
|
|
31
|
-
if (block.fillColor) containerEl.style
|
|
32
|
+
if (block.fillColor) setAuthoredBackgroundColor(containerEl.style, block.fillColor);
|
|
32
33
|
if (block.outlineWidth && block.outlineWidth > 0) {
|
|
33
34
|
const style = block.outlineStyle || "solid";
|
|
34
35
|
const color = block.outlineColor || "#000000";
|
package/dist/pdf/pageSpace.d.ts
CHANGED
|
@@ -39,5 +39,16 @@ declare const displayPointToPdf: (pageHeightPx: number, xPx: number, yPx: number
|
|
|
39
39
|
* screen, which is what a positive CSS/OOXML angle means.
|
|
40
40
|
*/
|
|
41
41
|
declare const rotationMatrix: (degrees: number, originXPx: number, originYPx: number) => PdfMatrix;
|
|
42
|
+
/**
|
|
43
|
+
* A DrawingML flip and rotation about one display-list point. CSS applies the
|
|
44
|
+
* rightmost scale first, then the rotation; this matrix does the same.
|
|
45
|
+
*/
|
|
46
|
+
declare const transformMatrix: ({ degrees, originXPx, originYPx, scaleX, scaleY }: {
|
|
47
|
+
readonly degrees: number;
|
|
48
|
+
readonly originXPx: number;
|
|
49
|
+
readonly originYPx: number;
|
|
50
|
+
readonly scaleX?: -1;
|
|
51
|
+
readonly scaleY?: -1;
|
|
52
|
+
}) => PdfMatrix;
|
|
42
53
|
//#endregion
|
|
43
|
-
export { POINTS_PER_PIXEL, PdfMatrix, applyMatrix, basePageMatrix, displayPointToPdf, pxToPt, rotationMatrix };
|
|
54
|
+
export { POINTS_PER_PIXEL, PdfMatrix, applyMatrix, basePageMatrix, displayPointToPdf, pxToPt, rotationMatrix, transformMatrix };
|
package/dist/pdf/pageSpace.js
CHANGED
|
@@ -53,5 +53,28 @@ const rotationMatrix = (degrees, originXPx, originYPx) => {
|
|
|
53
53
|
originYPx - originXPx * sin - originYPx * cos
|
|
54
54
|
];
|
|
55
55
|
};
|
|
56
|
+
/**
|
|
57
|
+
* A DrawingML flip and rotation about one display-list point. CSS applies the
|
|
58
|
+
* rightmost scale first, then the rotation; this matrix does the same.
|
|
59
|
+
*/
|
|
60
|
+
const transformMatrix = ({ degrees, originXPx, originYPx, scaleX, scaleY }) => {
|
|
61
|
+
const radians = degrees * Math.PI / 180;
|
|
62
|
+
const cos = Math.cos(radians);
|
|
63
|
+
const sin = Math.sin(radians);
|
|
64
|
+
const horizontalScale = scaleX ?? 1;
|
|
65
|
+
const verticalScale = scaleY ?? 1;
|
|
66
|
+
const a = cos * horizontalScale;
|
|
67
|
+
const b = sin * horizontalScale;
|
|
68
|
+
const c = -sin * verticalScale;
|
|
69
|
+
const d = cos * verticalScale;
|
|
70
|
+
return [
|
|
71
|
+
a,
|
|
72
|
+
b,
|
|
73
|
+
c,
|
|
74
|
+
d,
|
|
75
|
+
originXPx - originXPx * a - originYPx * c,
|
|
76
|
+
originYPx - originXPx * b - originYPx * d
|
|
77
|
+
];
|
|
78
|
+
};
|
|
56
79
|
//#endregion
|
|
57
|
-
export { POINTS_PER_PIXEL, applyMatrix, basePageMatrix, displayPointToPdf, pxToPt, rotationMatrix };
|
|
80
|
+
export { POINTS_PER_PIXEL, applyMatrix, basePageMatrix, displayPointToPdf, pxToPt, rotationMatrix, transformMatrix };
|
package/dist/pdf/paint.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { STROKE_DASH_FACTORS, glyphCellOffsetsPx } from "../display-list/primitives.js";
|
|
2
2
|
import { needsShaping } from "../shaping/placeRun.js";
|
|
3
3
|
import { TEXT_RENDER_MODE, createContentStream } from "./contentStream.js";
|
|
4
|
-
import { basePageMatrix,
|
|
4
|
+
import { basePageMatrix, transformMatrix } from "./pageSpace.js";
|
|
5
5
|
import { Result, TaggedError, panic } from "better-result";
|
|
6
6
|
//#region src/pdf/paint.ts
|
|
7
7
|
/**
|
|
@@ -358,7 +358,7 @@ const paintPrimitive = (context, primitive) => {
|
|
|
358
358
|
return;
|
|
359
359
|
case "rotateGroup":
|
|
360
360
|
context.stream.save();
|
|
361
|
-
context.stream.concat(
|
|
361
|
+
context.stream.concat(transformMatrix(primitive));
|
|
362
362
|
for (const child of primitive.children) paintPrimitive(context, child);
|
|
363
363
|
context.stream.restore();
|
|
364
364
|
return;
|
|
@@ -2,6 +2,7 @@ import { EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FONT_HINT_VALUES, FONT_THEME_V
|
|
|
2
2
|
import { normalizeHorizontalScalePercent } from "../../utils/horizontalScale.js";
|
|
3
3
|
import { isParagraphDirection } from "../paragraphDirection.js";
|
|
4
4
|
import { COMPLEX_SCRIPT_RUN_PROPERTY_KEYS, RUN_FORMATTING_BOOLEAN_PROPERTIES, RUN_FORMATTING_VALUE_PROPERTIES, TRACKED_CHANGE_PROVENANCE_VALUES } from "../schema/marks.js";
|
|
5
|
+
import { TEXT_BOX_TEXT_BODY_CONTENT_STATE_TYPES } from "../schema/nodes.js";
|
|
5
6
|
import { panic } from "better-result";
|
|
6
7
|
import { DRAWING_RAW_XML_MODES, isOoxmlSymbolCharacter } from "@stll/docx-core/model";
|
|
7
8
|
//#region src/prosemirror/attrs/index.ts
|
|
@@ -27,6 +28,8 @@ const TEXT_BOX_AUTO_FIT_VALUES = [
|
|
|
27
28
|
"shape"
|
|
28
29
|
];
|
|
29
30
|
const TEXT_BOX_TEXT_WRAP_VALUES = ["square", "none"];
|
|
31
|
+
/** The complete DrawingML transform subset carried by text boxes. */
|
|
32
|
+
const TEXT_BOX_TRANSFORM_PATTERN = /^(?=rotate|scaleX|scaleY)(?:rotate\(-?\d+(?:\.\d+)?deg\)(?: )?)?(?:scaleX\(-1\)(?: )?)?(?:scaleY\(-1\))?$/u;
|
|
30
33
|
const FIELD_KINDS = ["simple", "complex"];
|
|
31
34
|
const MATH_DISPLAYS = ["inline", "block"];
|
|
32
35
|
const SHAPE_FILL_TYPES = [
|
|
@@ -168,6 +171,7 @@ const readParagraphAttrs = (node) => {
|
|
|
168
171
|
const issues = [];
|
|
169
172
|
expectNodeType(node, "paragraph", issues);
|
|
170
173
|
optionalString(attrs, "paraId", "paragraph.attrs.paraId", issues);
|
|
174
|
+
optionalString(attrs, "_docxParagraphSourceToken", "paragraph.attrs._docxParagraphSourceToken", issues);
|
|
171
175
|
optionalString(attrs, "textId", "paragraph.attrs.textId", issues);
|
|
172
176
|
optionalOneOf(attrs, "alignment", "paragraph.attrs.alignment", issues, PARAGRAPH_ALIGNMENT_VALUES);
|
|
173
177
|
optionalOneOf(attrs, "alignmentFromStyle", "paragraph.attrs.alignmentFromStyle", issues, PARAGRAPH_ALIGNMENT_VALUES);
|
|
@@ -367,7 +371,6 @@ const readTableCellAttrs = (node) => {
|
|
|
367
371
|
optionalRecord(attrs, "_originalFormatting", "tableCell.attrs._originalFormatting", issues);
|
|
368
372
|
optionalTableCellRevision(attrs, issues);
|
|
369
373
|
optionalBoolean(attrs, "_preserveVMergeRestart", "tableCell.attrs._preserveVMergeRestart", issues);
|
|
370
|
-
optionalArray(attrs, "_docxVMergeContinuationCells", "tableCell.attrs._docxVMergeContinuationCells", issues);
|
|
371
374
|
return attrsResult(attrs, issues);
|
|
372
375
|
};
|
|
373
376
|
const expectTableCellAttrs = (node) => expectCachedNodeAttrs(node, tableCellAttrsCache, readTableCellAttrs, "table cell attrs");
|
|
@@ -520,6 +523,7 @@ const readTextBoxAttrs = (node) => {
|
|
|
520
523
|
optionalNumber(attrs, "outlineWidth", "textBox.attrs.outlineWidth", issues);
|
|
521
524
|
optionalString(attrs, "outlineColor", "textBox.attrs.outlineColor", issues);
|
|
522
525
|
optionalOneOf(attrs, "outlineStyle", "textBox.attrs.outlineStyle", issues, OUTLINE_STYLE_ATTR_VALUES);
|
|
526
|
+
optionalTextBoxTransform(attrs, "transform", "textBox.attrs.transform", issues);
|
|
523
527
|
optionalNumber(attrs, "marginTop", "textBox.attrs.marginTop", issues);
|
|
524
528
|
optionalNumber(attrs, "marginBottom", "textBox.attrs.marginBottom", issues);
|
|
525
529
|
optionalNumber(attrs, "marginLeft", "textBox.attrs.marginLeft", issues);
|
|
@@ -537,6 +541,7 @@ const readTextBoxAttrs = (node) => {
|
|
|
537
541
|
optionalOneOf(attrs, "_docxPlacement", "textBox.attrs._docxPlacement", issues, TEXT_BOX_DOCX_PLACEMENTS);
|
|
538
542
|
optionalString(attrs, "_docxGroupId", "textBox.attrs._docxGroupId", issues);
|
|
539
543
|
optionalString(attrs, "_docxAnchorId", "textBox.attrs._docxAnchorId", issues);
|
|
544
|
+
requiredTextBoxBodyContentState(attrs, issues);
|
|
540
545
|
optionalTextBoxTrackedChange(attrs, issues);
|
|
541
546
|
optionalTextBoxInlineSdts(attrs, issues);
|
|
542
547
|
return attrsResult(attrs, issues);
|
|
@@ -905,6 +910,21 @@ const optionalString = (attrs, key, path, issues) => {
|
|
|
905
910
|
message: "Expected a string."
|
|
906
911
|
});
|
|
907
912
|
};
|
|
913
|
+
const optionalTextBoxTransform = (attrs, key, path, issues) => {
|
|
914
|
+
const value = attrs[key];
|
|
915
|
+
if (value === void 0 || value === null) return;
|
|
916
|
+
if (typeof value !== "string") {
|
|
917
|
+
issues.push({
|
|
918
|
+
path,
|
|
919
|
+
message: "Expected a string."
|
|
920
|
+
});
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
if (!TEXT_BOX_TRANSFORM_PATTERN.test(value)) issues.push({
|
|
924
|
+
path,
|
|
925
|
+
message: "Expected DrawingML rotation and/or horizontal or vertical flips."
|
|
926
|
+
});
|
|
927
|
+
};
|
|
908
928
|
const optionalSdtListItems = (attrs, key, path, issues) => {
|
|
909
929
|
const value = attrs[key];
|
|
910
930
|
if (value === void 0 || value === null) return;
|
|
@@ -1185,6 +1205,17 @@ const optionalTextBoxTrackedChange = (attrs, issues) => {
|
|
|
1185
1205
|
requiredString(info, "author", "textBox.attrs._docxTrackedChange.info.author", issues);
|
|
1186
1206
|
optionalString(info, "date", "textBox.attrs._docxTrackedChange.info.date", issues);
|
|
1187
1207
|
};
|
|
1208
|
+
const requiredTextBoxBodyContentState = (attrs, issues) => {
|
|
1209
|
+
const value = attrs["_docxTextBodyContentState"];
|
|
1210
|
+
if (!isRecord(value)) {
|
|
1211
|
+
issues.push({
|
|
1212
|
+
path: "textBox.attrs._docxTextBodyContentState",
|
|
1213
|
+
message: "Expected an object."
|
|
1214
|
+
});
|
|
1215
|
+
return;
|
|
1216
|
+
}
|
|
1217
|
+
requiredOneOf(value, "type", "textBox.attrs._docxTextBodyContentState.type", issues, TEXT_BOX_TEXT_BODY_CONTENT_STATE_TYPES);
|
|
1218
|
+
};
|
|
1188
1219
|
const optionalTextBoxInlineSdts = (attrs, issues) => {
|
|
1189
1220
|
const value = attrs["_docxInlineSdts"];
|
|
1190
1221
|
if (value === void 0 || value === null) return;
|
|
@@ -1236,13 +1267,6 @@ const optionalAutospacingBase = (attrs, path, issues) => {
|
|
|
1236
1267
|
optionalNumber(value, "before", `${path}.before`, issues);
|
|
1237
1268
|
optionalNumber(value, "after", `${path}.after`, issues);
|
|
1238
1269
|
};
|
|
1239
|
-
const optionalArray = (attrs, key, path, issues) => {
|
|
1240
|
-
const value = attrs[key];
|
|
1241
|
-
if (value !== void 0 && value !== null && !Array.isArray(value)) issues.push({
|
|
1242
|
-
path,
|
|
1243
|
-
message: "Expected an array."
|
|
1244
|
-
});
|
|
1245
|
-
};
|
|
1246
1270
|
const optionalBorderMap = (attrs, key, path, issues, sides) => {
|
|
1247
1271
|
const value = attrs[key];
|
|
1248
1272
|
if (value === void 0 || value === null) return;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { joinProseParagraphsWithRightPropertySource } from "../../docx/paragraphPropertySource.js";
|
|
1
2
|
import { appendHeadlessInlineResolution } from "../../internal/headlessRevisionResolution.js";
|
|
2
3
|
import { stateAllowsHeadlessRevisionResolution } from "../../internal/headlessRevisionResolutionGuard.js";
|
|
3
4
|
import { expectParagraphAttrs, expectRunPropertyChangeMarkAttrs } from "../attrs/index.js";
|
|
@@ -232,15 +233,23 @@ function resolveChange(from, to, mode, revisionIds, execution = "legacy") {
|
|
|
232
233
|
tr.setNodeAttribute(mappedPos, "pPrMark", null);
|
|
233
234
|
continue;
|
|
234
235
|
}
|
|
236
|
+
const emptyFirstParagraph = holdsNoContent(paragraph);
|
|
235
237
|
const joinedAttrs = {
|
|
236
|
-
...(
|
|
238
|
+
...(emptyFirstParagraph ? nextNode : paragraph).attrs,
|
|
237
239
|
pPrMark: nextNode.attrs["pPrMark"],
|
|
238
240
|
sectionBreakType: nextNode.attrs["sectionBreakType"],
|
|
239
241
|
_sectionProperties: nextNode.attrs["_sectionProperties"]
|
|
240
242
|
};
|
|
241
243
|
try {
|
|
242
|
-
|
|
243
|
-
|
|
244
|
+
if (emptyFirstParagraph) joinProseParagraphsWithRightPropertySource({
|
|
245
|
+
attrs: joinedAttrs,
|
|
246
|
+
pos: joinPos,
|
|
247
|
+
transaction: tr
|
|
248
|
+
});
|
|
249
|
+
else {
|
|
250
|
+
tr.join(joinPos);
|
|
251
|
+
tr.setNodeMarkup(mappedPos, void 0, joinedAttrs);
|
|
252
|
+
}
|
|
244
253
|
if (ownsSectionEndpoint(paragraph)) {
|
|
245
254
|
removedSectionEndpointCount++;
|
|
246
255
|
removedSectionReferences.push(...sectionReferencesOf(paragraph));
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
import { decodeTableCellParagraphSourcePayload, restoreTableCellsWithParagraphPropertySources, transportTableCellsWithParagraphPropertySources } from "../../docx/paragraphPropertySource.js";
|
|
1
2
|
import { standaloneTableCellFromProseMirror } from "../conversion/fromProseDoc.js";
|
|
2
3
|
import { standaloneTableCellToProseMirror } from "../conversion/toProseDoc.js";
|
|
3
4
|
import { getTableCellMergeChange } from "../tableCellMergeRevision.js";
|
|
4
5
|
import { Result } from "better-result";
|
|
5
6
|
import { TableMap } from "prosemirror-tables";
|
|
6
7
|
//#region src/prosemirror/commands/tableCellMergeResolution.ts
|
|
8
|
+
const tableCellContinuationPayload = (node) => {
|
|
9
|
+
const value = node.attrs["_docxVMergeContinuationCells"];
|
|
10
|
+
return value === void 0 || value === null ? null : decodeTableCellParagraphSourcePayload(value);
|
|
11
|
+
};
|
|
7
12
|
const hasMatchingCollapsedTableCellMerge = (node, revisionSet) => {
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
return continuationCells.some((cell) => {
|
|
13
|
+
const payload = tableCellContinuationPayload(node);
|
|
14
|
+
return payload !== null && payload.cells.some((cell) => {
|
|
11
15
|
const change = getTableCellMergeChange(cell);
|
|
12
16
|
return change !== null && (revisionSet === null || revisionSet.has(change.info.id));
|
|
13
17
|
});
|
|
@@ -71,19 +75,19 @@ const mergeTableCellWithCellAbove = (tr, cellPos) => {
|
|
|
71
75
|
if (!aboveCell || typeof aboveRowspan !== "number" || typeof cellRowspan !== "number" || aboveRowspan < 1 || cellRowspan < 1) return false;
|
|
72
76
|
const continuationCells = tableCellContinuationCells(aboveCell, aboveRowspan);
|
|
73
77
|
continuationCells.push(tableCellContinuationFromNode(cell));
|
|
74
|
-
const
|
|
75
|
-
if (
|
|
78
|
+
const nestedPayload = tableCellContinuationPayload(cell);
|
|
79
|
+
if (nestedPayload) continuationCells.push(...nestedPayload.cells);
|
|
76
80
|
tr.delete(cellPos, cellPos + cell.nodeSize);
|
|
77
81
|
tr.setNodeMarkup(abovePos, void 0, {
|
|
78
82
|
...aboveCell.attrs,
|
|
79
83
|
rowspan: aboveRowspan + cellRowspan,
|
|
80
|
-
_docxVMergeContinuationCells: continuationCells
|
|
84
|
+
_docxVMergeContinuationCells: transportTableCellsWithParagraphPropertySources(continuationCells)
|
|
81
85
|
});
|
|
82
86
|
return true;
|
|
83
87
|
};
|
|
84
88
|
const tableCellContinuationCells = (cell, rowspan) => {
|
|
85
|
-
const
|
|
86
|
-
const cells =
|
|
89
|
+
const payload = tableCellContinuationPayload(cell);
|
|
90
|
+
const cells = payload ? [...payload.cells] : [];
|
|
87
91
|
while (cells.length < rowspan - 1) cells.push(emptyVerticalMergeContinuation());
|
|
88
92
|
return cells;
|
|
89
93
|
};
|
|
@@ -109,8 +113,10 @@ const emptyVerticalMergeContinuation = () => ({
|
|
|
109
113
|
});
|
|
110
114
|
const resolveCollapsedTableCellMerge = (tr, cellPos, mode, revisionSet) => {
|
|
111
115
|
const cell = tr.doc.nodeAt(cellPos);
|
|
112
|
-
|
|
113
|
-
|
|
116
|
+
if (!cell) return false;
|
|
117
|
+
const payload = tableCellContinuationPayload(cell);
|
|
118
|
+
if (!payload) return false;
|
|
119
|
+
const stored = payload.cells;
|
|
114
120
|
const matchingIndices = [];
|
|
115
121
|
const nextCells = stored.map((continuationCell, index) => {
|
|
116
122
|
const change = getTableCellMergeChange(continuationCell);
|
|
@@ -142,8 +148,9 @@ const resolveCollapsedTableCellMerge = (tr, cellPos, mode, revisionSet) => {
|
|
|
142
148
|
const rowspan = cell.attrs["rowspan"];
|
|
143
149
|
if (typeof rowspan !== "number" || rowspan !== stored.length + 1 || rectangle.bottom - rectangle.top !== rowspan) return false;
|
|
144
150
|
const restorations = [];
|
|
151
|
+
const restoredCells = restoreTableCellsWithParagraphPropertySources(payload);
|
|
145
152
|
for (const index of splitIndices) {
|
|
146
|
-
const source =
|
|
153
|
+
const source = restoredCells[index];
|
|
147
154
|
if (!source) return false;
|
|
148
155
|
const restoredCell = createRestoredTableCell(cell, source);
|
|
149
156
|
if (!restoredCell) return false;
|