@stll/folio-core 0.25.3 → 0.25.5
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/docx/compatibility.js +2 -2
- package/dist/docx/runParser.js +3 -2
- package/dist/docx/serializer/runSerializer.js +5 -1
- package/dist/docx/shapeParser.js +26 -3
- package/dist/layout-bridge/convert/toFlowBlocks.js +2 -7
- package/dist/layout-engine/measure/cache.d.ts +1 -4
- package/dist/layout-engine/measure/cache.js +31 -34
- package/dist/layout-painter/renderParagraph.js +26 -18
- package/dist/prosemirror/attrs/index.js +9 -1
- package/dist/prosemirror/commands/image.js +2 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +26 -6
- package/dist/prosemirror/conversion/toProseDoc.js +17 -6
- package/dist/prosemirror/extensions/core/ParagraphExtension.d.ts +2 -0
- package/dist/prosemirror/extensions/core/ParagraphExtension.js +15 -3
- package/dist/prosemirror/extensions/features/BaseKeymapExtension.js +6 -1
- package/dist/prosemirror/extensions/nodes/ImageExtension.js +1 -0
- package/dist/prosemirror/extensions/nodes/ShapeExtension.d.ts +7 -1
- package/dist/prosemirror/extensions/nodes/ShapeExtension.js +55 -3
- package/dist/prosemirror/schema/nodes.d.ts +6 -0
- package/dist/prosemirror/shapeGeometryAdjustments.d.ts +5 -0
- package/dist/prosemirror/shapeGeometryAdjustments.js +24 -0
- package/dist/prosemirror/styles/resolvedStyleAttrs.d.ts +5 -1
- package/dist/prosemirror/styles/resolvedStyleAttrs.js +4 -2
- package/dist/types/content.d.ts +2 -2
- package/dist/types/index.d.ts +3 -1
- package/dist/utils/tableOfContentsStyle.d.ts +9 -0
- package/dist/utils/tableOfContentsStyle.js +14 -0
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DOCX_CONFORMANCE_CLASSES } from "@stll/docx-core/model";
|
|
1
|
+
import { DOCX_CONFORMANCE_CLASSES, DRAWING_RAW_XML_MODES } from "@stll/docx-core/model";
|
|
2
2
|
//#region src/docx/compatibility.ts
|
|
3
3
|
const resolveCompatibilityContext = (doc, options) => ({
|
|
4
4
|
host: options.host ?? "unknown",
|
|
@@ -146,7 +146,7 @@ function inspectHyperlink(hyperlink, context) {
|
|
|
146
146
|
});
|
|
147
147
|
}
|
|
148
148
|
function inspectRun(run, context) {
|
|
149
|
-
for (const [contentIndex, content] of run.content.entries()) if (content.type === "drawing" && content.rawXml) context.record({
|
|
149
|
+
for (const [contentIndex, content] of run.content.entries()) if (content.type === "drawing" && content.rawXml && content.rawXmlMode !== DRAWING_RAW_XML_MODES.PRESERVE_ONLY) context.record({
|
|
150
150
|
...context.blockId === void 0 ? {} : { blockId: context.blockId },
|
|
151
151
|
part: context.part,
|
|
152
152
|
path: `${context.path}.content[${contentIndex}]`
|
package/dist/docx/runParser.js
CHANGED
|
@@ -7,7 +7,7 @@ import { requiresXmlSpacePreserve } from "./textWhitespace.js";
|
|
|
7
7
|
import { resolveThemeFontRef } from "./themeParser.js";
|
|
8
8
|
import { parseVmlImageContent } from "./vmlImageParser.js";
|
|
9
9
|
import { cloneWithXmlnsDeclarations, elementToXml, findAllDeep, findChild, findChildren, getAttribute, getChildElements, getLocalName, getTextContent, mergeXmlnsDeclarations, parseBooleanElement, parseNumericAttribute } from "./xmlParser.js";
|
|
10
|
-
import { normalizeRevisionId } from "@stll/docx-core/model";
|
|
10
|
+
import { DRAWING_RAW_XML_MODES, normalizeRevisionId } from "@stll/docx-core/model";
|
|
11
11
|
//#region src/docx/runParser.ts
|
|
12
12
|
/**
|
|
13
13
|
* Sanity cap on `w:lang` `@w:val`/`@w:eastAsia`/`@w:bidi` tag length. BCP-47
|
|
@@ -500,7 +500,8 @@ function parseDrawingContent(element, rels, media) {
|
|
|
500
500
|
},
|
|
501
501
|
wrap: { type: "inline" }
|
|
502
502
|
},
|
|
503
|
-
rawXml: elementToXml(element)
|
|
503
|
+
rawXml: elementToXml(element),
|
|
504
|
+
rawXmlMode: DRAWING_RAW_XML_MODES.PRESERVE_ONLY
|
|
504
505
|
};
|
|
505
506
|
const shape = parseShapeFromDrawing(element);
|
|
506
507
|
if (shape) return {
|
|
@@ -448,6 +448,10 @@ function serializeDrawingContent(content) {
|
|
|
448
448
|
function serializeShapeTextBody(blocks) {
|
|
449
449
|
return blocks.map((block) => block.type === "paragraph" ? serializeParagraph(block) : serializeTable(block, serializeParagraph)).join("");
|
|
450
450
|
}
|
|
451
|
+
function serializeGeometryAdjustments(shape) {
|
|
452
|
+
if (!shape.geometryAdjustments || shape.geometryAdjustments.length === 0) return "<a:avLst/>";
|
|
453
|
+
return `<a:avLst>${shape.geometryAdjustments.map(({ name, formula }) => `<a:gd name="${escapeXml(name)}" fmla="${escapeXml(formula)}"/>`).join("")}</a:avLst>`;
|
|
454
|
+
}
|
|
451
455
|
/**
|
|
452
456
|
* Serialize shape content to full DrawingML XML (wps:wsp inside w:drawing)
|
|
453
457
|
*/
|
|
@@ -470,7 +474,7 @@ function serializeShapeContent(content) {
|
|
|
470
474
|
"<a:off x=\"0\" y=\"0\"/>",
|
|
471
475
|
`<a:ext cx="${intAttr(cx)}" cy="${intAttr(cy)}"/>`,
|
|
472
476
|
"</a:xfrm>",
|
|
473
|
-
`<a:prstGeom prst="${shape.shapeType === "textBox" ? "rect" : shape.shapeType}"
|
|
477
|
+
`<a:prstGeom prst="${shape.shapeType === "textBox" ? "rect" : shape.shapeType}">${serializeGeometryAdjustments(shape)}</a:prstGeom>`,
|
|
474
478
|
serializeFill(shape.fill),
|
|
475
479
|
serializeOutline(shape.outline),
|
|
476
480
|
"</wps:spPr>"
|
package/dist/docx/shapeParser.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parseAnchorPosition, parseAnchorWrap, parseFill, parseOutline } from "./drawingUtils.js";
|
|
2
2
|
import { ShapeTypeSchema, narrowEnum } from "./parserEnums.js";
|
|
3
|
-
import { findAllDeep, findChildByLocalName, getAttribute, parseNumericAttribute } from "./xmlParser.js";
|
|
3
|
+
import { findAllDeep, findChildByLocalName, findChildren, getAttribute, getChildElements, parseNumericAttribute } from "./xmlParser.js";
|
|
4
4
|
//#region src/docx/shapeParser.ts
|
|
5
5
|
/** Convert OOXML rotation (1/60000ths of a degree) to degrees. */
|
|
6
6
|
function rotToDegrees(rot) {
|
|
@@ -56,8 +56,29 @@ function hasUnsupportedGeometry(spPr) {
|
|
|
56
56
|
if (!spPr) return false;
|
|
57
57
|
const prstGeom = findChildByLocalName(spPr, "prstGeom");
|
|
58
58
|
if (!prstGeom) return findChildByLocalName(spPr, "custGeom") !== null;
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
const avLst = findChildByLocalName(prstGeom, "avLst");
|
|
60
|
+
const prst = getAttribute(prstGeom, null, "prst");
|
|
61
|
+
if (narrowEnum(prst, ShapeTypeSchema) === void 0) return true;
|
|
62
|
+
const adjustmentChildren = avLst ? getChildElements(avLst) : [];
|
|
63
|
+
if (adjustmentChildren.length === 0) return false;
|
|
64
|
+
const adjustments = findChildren(avLst, "a", "gd");
|
|
65
|
+
const adjustmentNames = new Set(adjustments.map((adjustment) => getAttribute(adjustment, null, "name")));
|
|
66
|
+
return !(prst === "rightBrace" && adjustments.length === 2 && adjustmentChildren.length === adjustments.length && adjustmentNames.size === 2 && adjustmentNames.has("adj1") && adjustmentNames.has("adj2") && adjustments.every((adjustment) => /^val\s+-?\d+$/u.test(getAttribute(adjustment, null, "fmla") ?? "")));
|
|
67
|
+
}
|
|
68
|
+
function parseGeometryAdjustments(spPr) {
|
|
69
|
+
const prstGeom = spPr ? findChildByLocalName(spPr, "prstGeom") : null;
|
|
70
|
+
const avLst = prstGeom ? findChildByLocalName(prstGeom, "avLst") : null;
|
|
71
|
+
if (!avLst) return;
|
|
72
|
+
const adjustments = [];
|
|
73
|
+
for (const adjustment of findChildren(avLst, "a", "gd")) {
|
|
74
|
+
const name = getAttribute(adjustment, null, "name");
|
|
75
|
+
const formula = getAttribute(adjustment, null, "fmla");
|
|
76
|
+
if (name !== null && formula !== null) adjustments.push({
|
|
77
|
+
name,
|
|
78
|
+
formula
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return adjustments.length === 0 ? void 0 : adjustments;
|
|
61
82
|
}
|
|
62
83
|
function hasUnsupportedRgbColorModifiers(spPr) {
|
|
63
84
|
for (const color of findAllDeep(spPr, "a", "srgbClr")) if (color.elements?.some((child) => child.type === "element")) return true;
|
|
@@ -94,6 +115,8 @@ function parseShape(node) {
|
|
|
94
115
|
shapeType,
|
|
95
116
|
size
|
|
96
117
|
};
|
|
118
|
+
const geometryAdjustments = parseGeometryAdjustments(spPr);
|
|
119
|
+
if (geometryAdjustments !== void 0) shape.geometryAdjustments = geometryAdjustments;
|
|
97
120
|
if (id !== void 0) shape.id = id;
|
|
98
121
|
if (name !== void 0) shape.name = name;
|
|
99
122
|
if (fill !== void 0) shape.fill = fill;
|
|
@@ -15,6 +15,7 @@ import { resolveColor, resolveHighlightToCss } from "../../utils/colorResolver.j
|
|
|
15
15
|
import { resolveThemeFont } from "../../utils/fontResolver.js";
|
|
16
16
|
import { resolveShadingFill } from "../../utils/formatToStyle.js";
|
|
17
17
|
import { decodeOoxmlSymbolCharacter } from "../../utils/ooxmlSymbol.js";
|
|
18
|
+
import { tableOfContentsStyleLevel } from "../../utils/tableOfContentsStyle.js";
|
|
18
19
|
import { AUTO_PARAGRAPH_SPACING_PX, halfPointsToPixels, halfPointsToPoints, pointsToPixels } from "../../utils/units.js";
|
|
19
20
|
import { getColumns } from "../sectionColumns.js";
|
|
20
21
|
import { groupParagraphFrames } from "./paragraphFrames.js";
|
|
@@ -454,12 +455,6 @@ function buildImageRun(attrs, constrained, pmStart, pmEnd, trackedChange) {
|
|
|
454
455
|
return run;
|
|
455
456
|
}
|
|
456
457
|
/**
|
|
457
|
-
* Paragraph styleId pattern used by Word for TOC entries (TOC, TOC1, TOC2, …).
|
|
458
|
-
* Hyperlinks inside these paragraphs must render in the paragraph's own colour,
|
|
459
|
-
* not the Hyperlink character style — see {@link stripTocHyperlinkStyle}.
|
|
460
|
-
*/
|
|
461
|
-
const TOC_STYLE_ID = /^TOC\d*$/iu;
|
|
462
|
-
/**
|
|
463
458
|
* In TOC paragraphs, strip the resolved Hyperlink character-style colour and
|
|
464
459
|
* underline so the painter's link fallback doesn't fire. The PM doc keeps the
|
|
465
460
|
* original marks so copy/paste out of a TOC still carries the Hyperlink
|
|
@@ -484,7 +479,7 @@ function paragraphToRuns(node, startPos, _options) {
|
|
|
484
479
|
const pmAttrs = expectParagraphAttrs(node);
|
|
485
480
|
const paraDefaults = paragraphRunDefaults(pmAttrs, theme);
|
|
486
481
|
const paragraphStyleId = pmAttrs.styleId;
|
|
487
|
-
const inTocParagraph =
|
|
482
|
+
const inTocParagraph = pmAttrs._tableOfContentsLevel !== void 0 || tableOfContentsStyleLevel({ styleId: paragraphStyleId }) !== void 0;
|
|
488
483
|
let leadingRenderedPageBreakPending = pmAttrs.renderedPageBreakBefore === true;
|
|
489
484
|
function pushRunsForChild(child, childPos) {
|
|
490
485
|
if (child.type.name === "renderedPageBreak") {
|
|
@@ -54,10 +54,7 @@ declare function setFontCacheSize(size: number): void;
|
|
|
54
54
|
* Get current font metrics cache size
|
|
55
55
|
*/
|
|
56
56
|
declare function getFontCacheSize(): number;
|
|
57
|
-
/**
|
|
58
|
-
* Generate a simple hash for a paragraph block
|
|
59
|
-
* Used as cache key to identify identical content
|
|
60
|
-
*/
|
|
57
|
+
/** Serialize the complete paragraph measurement contract into a cache key. */
|
|
61
58
|
declare function hashParagraphBlock(block: ParagraphBlock): string;
|
|
62
59
|
/**
|
|
63
60
|
* Get cached paragraph measurement or return undefined
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { lineBreakPolicyCacheParts } from "./effectiveLineBreakPolicy.js";
|
|
2
1
|
import { getLineBreakProviderGeneration } from "./lineBreakProvider.js";
|
|
3
2
|
import { clearFontResolvedCache } from "./measureHelpers.js";
|
|
4
3
|
//#region src/layout-engine/measure/cache.ts
|
|
@@ -164,40 +163,38 @@ let paragraphCacheMaxSize = 5e3;
|
|
|
164
163
|
* Key format: block content hash
|
|
165
164
|
*/
|
|
166
165
|
const paragraphMeasureCache = /* @__PURE__ */ new Map();
|
|
167
|
-
/**
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
const marker = attrs.listMarkerFormatting;
|
|
191
|
-
parts.push(`marker:${attrs.listMarker}|${attrs.listMarkerHidden}|${attrs.listMarkerAlignment}|${attrs.listMarkerSuffix}|${marker?.fontFamily}|${marker?.eastAsiaFontFamily}|${marker?.complexScriptFontFamily}|${marker?.fontSize}|${marker?.complexScriptFontSize}|${marker?.bold}|${marker?.complexScriptBold}|${marker?.italic}|${marker?.complexScriptItalic}|${marker?.rtl}|${marker?.forceComplexScript}`);
|
|
192
|
-
}
|
|
193
|
-
parts.push(...lineBreakPolicyCacheParts(attrs));
|
|
194
|
-
const borders = attrs.borders;
|
|
195
|
-
if (borders) {
|
|
196
|
-
const signature = (border) => border ? `${border.width ?? ""},${border.style ?? ""},${border.color ?? ""}` : "";
|
|
197
|
-
parts.push(`bdr:${signature(borders.top)}|${signature(borders.bottom)}|${signature(borders.left)}|${signature(borders.right)}`);
|
|
198
|
-
}
|
|
166
|
+
/** Keep image payloads bounded while classifying every field as measured or intentionally ignored. */
|
|
167
|
+
const imageMeasureCacheInput = (run) => ({
|
|
168
|
+
kind: run.kind,
|
|
169
|
+
width: run.width,
|
|
170
|
+
height: run.height,
|
|
171
|
+
transform: run.transform,
|
|
172
|
+
wrapType: run.wrapType,
|
|
173
|
+
displayMode: run.displayMode,
|
|
174
|
+
distTop: run.distTop,
|
|
175
|
+
distBottom: run.distBottom,
|
|
176
|
+
exactLineHeight: run.exactLineHeight,
|
|
177
|
+
positioned: run.position !== void 0
|
|
178
|
+
});
|
|
179
|
+
const runMeasureCacheInput = (run) => {
|
|
180
|
+
switch (run.kind) {
|
|
181
|
+
case "text":
|
|
182
|
+
case "tab":
|
|
183
|
+
case "lineBreak":
|
|
184
|
+
case "renderedPageBreak":
|
|
185
|
+
case "field":
|
|
186
|
+
case "math": return run;
|
|
187
|
+
case "image": return imageMeasureCacheInput(run);
|
|
188
|
+
default: return run;
|
|
199
189
|
}
|
|
200
|
-
|
|
190
|
+
};
|
|
191
|
+
/** Serialize the complete paragraph measurement contract into a cache key. */
|
|
192
|
+
function hashParagraphBlock(block) {
|
|
193
|
+
return JSON.stringify({
|
|
194
|
+
lineBreakProviderGeneration: getLineBreakProviderGeneration(),
|
|
195
|
+
attrs: block.attrs,
|
|
196
|
+
runs: block.runs.map(runMeasureCacheInput)
|
|
197
|
+
});
|
|
201
198
|
}
|
|
202
199
|
/**
|
|
203
200
|
* Evict oldest entries if paragraph cache exceeds max size
|
|
@@ -1454,9 +1454,10 @@ function renderParagraphFragment(fragment, block, measure, context, options = {}
|
|
|
1454
1454
|
});
|
|
1455
1455
|
const isFlexLine = lineEl.dataset["flexLine"] === "true";
|
|
1456
1456
|
const lineMarginLeft = Math.min(indentLeft, 0) + lineLeftOffset;
|
|
1457
|
+
const lineMarginRight = Math.min(indentRight, 0) + lineRightOffset;
|
|
1457
1458
|
if (lineMarginLeft !== 0 || lineRightOffset > 0 || indentLeft < 0 || indentRight < 0) {
|
|
1458
1459
|
lineEl.style.marginLeft = `${lineMarginLeft}px`;
|
|
1459
|
-
if (
|
|
1460
|
+
if (lineMarginRight !== 0) lineEl.style.marginRight = `${lineMarginRight}px`;
|
|
1460
1461
|
const constrainedWidth = lineAvailableWidth - lineLeftOffset - lineRightOffset;
|
|
1461
1462
|
if (constrainedWidth > 0) lineEl.style.width = `${constrainedWidth}px`;
|
|
1462
1463
|
}
|
|
@@ -1476,27 +1477,33 @@ function renderParagraphFragment(fragment, block, measure, context, options = {}
|
|
|
1476
1477
|
if (isFirstLine && block.attrs?.listMarker && !block.attrs.listMarkerHidden) {
|
|
1477
1478
|
const hanging = indent?.hanging ?? 0;
|
|
1478
1479
|
const firstLine = indent?.firstLine ?? 0;
|
|
1479
|
-
const
|
|
1480
|
-
|
|
1480
|
+
const markerPhysicalStart = isRtl ? "right" : "left";
|
|
1481
|
+
const markerIndent = markerPhysicalStart === "right" ? indentRight : indentLeft;
|
|
1482
|
+
const markerStart = hanging > 0 ? markerIndent - hanging : markerIndent + firstLine;
|
|
1483
|
+
const logicalMarkerVisualOffset = getListMarkerVisualOffset(block);
|
|
1484
|
+
if (markerPhysicalStart === "right") lineEl.style.paddingRight = `${Math.max(0, markerStart)}px`;
|
|
1485
|
+
else lineEl.style.paddingLeft = `${Math.max(0, markerStart)}px`;
|
|
1481
1486
|
lineEl.style.textIndent = "0";
|
|
1482
|
-
const marker = renderListMarker(
|
|
1483
|
-
|
|
1484
|
-
|
|
1487
|
+
const marker = renderListMarker({
|
|
1488
|
+
marker: block.attrs.listMarker,
|
|
1489
|
+
inlineWidth: getListMarkerInlineWidth(block),
|
|
1490
|
+
visualOffset: markerPhysicalStart === "right" ? -logicalMarkerVisualOffset : logicalMarkerVisualOffset,
|
|
1491
|
+
doc,
|
|
1492
|
+
formatting: resolveListMarkerFont(block),
|
|
1493
|
+
...block.attrs.listMarkerRevision === void 0 ? {} : { revision: block.attrs.listMarkerRevision },
|
|
1494
|
+
...block.attrs.listMarkerSecondSlotOffsetTwips === void 0 ? {} : { secondSlotOffsetTwips: block.attrs.listMarkerSecondSlotOffsetTwips },
|
|
1495
|
+
physicalStart: markerPhysicalStart
|
|
1496
|
+
});
|
|
1497
|
+
const markerMarginLeft = markerStart - (markerPhysicalStart === "right" ? Math.min(indentRight, 0) : Math.min(indentLeft, 0));
|
|
1498
|
+
if (markerMarginLeft < 0) if (markerPhysicalStart === "right") marker.style.marginRight = `${markerMarginLeft}px`;
|
|
1499
|
+
else marker.style.marginLeft = `${markerMarginLeft}px`;
|
|
1485
1500
|
lineEl.prepend(marker);
|
|
1486
1501
|
}
|
|
1487
1502
|
fragmentEl.append(lineEl);
|
|
1488
1503
|
}
|
|
1489
1504
|
return fragmentEl;
|
|
1490
1505
|
}
|
|
1491
|
-
|
|
1492
|
-
* Render a list marker element as an inline-block at the start of the first
|
|
1493
|
-
* body line. `inlineWidth` (from `getListMarkerInlineWidth`) sizes the marker
|
|
1494
|
-
* so the body text aligns at the next tab stop per ECMA-376 §17.9.25 —
|
|
1495
|
-
* this honours `w:suff` (`tab` / `space` / `nothing`) and the document's
|
|
1496
|
-
* tab grid. Long markers like "1.1.1." therefore grow to the next stop
|
|
1497
|
-
* instead of butting against the body text.
|
|
1498
|
-
*/
|
|
1499
|
-
function renderListMarker(marker, inlineWidth, visualOffset, doc, formatting, revision, secondSlotOffsetTwips) {
|
|
1506
|
+
function renderListMarker({ marker, inlineWidth, visualOffset, doc, formatting, revision, secondSlotOffsetTwips, physicalStart }) {
|
|
1500
1507
|
const span = doc.createElement("span");
|
|
1501
1508
|
span.className = "layout-list-marker";
|
|
1502
1509
|
span.style.display = "inline-block";
|
|
@@ -1505,8 +1512,8 @@ function renderListMarker(marker, inlineWidth, visualOffset, doc, formatting, re
|
|
|
1505
1512
|
if (formatting.bold !== void 0) span.style.fontWeight = formatting.bold ? "700" : "normal";
|
|
1506
1513
|
if (formatting.italic !== void 0) span.style.fontStyle = formatting.italic ? "italic" : "normal";
|
|
1507
1514
|
if (formatting.rtl !== void 0) span.dir = formatting.rtl ? "rtl" : "ltr";
|
|
1508
|
-
span.style.textAlign =
|
|
1509
|
-
span.style.textAlignLast =
|
|
1515
|
+
span.style.textAlign = physicalStart;
|
|
1516
|
+
span.style.textAlignLast = physicalStart;
|
|
1510
1517
|
span.style.boxSizing = "border-box";
|
|
1511
1518
|
span.style.width = `${inlineWidth}px`;
|
|
1512
1519
|
if (visualOffset !== 0) span.style.transform = `translateX(${visualOffset}px)`;
|
|
@@ -1540,7 +1547,8 @@ function renderListMarker(marker, inlineWidth, visualOffset, doc, formatting, re
|
|
|
1540
1547
|
secondSlot.style.display = "inline-block";
|
|
1541
1548
|
span.style.position = "relative";
|
|
1542
1549
|
secondSlot.style.position = "absolute";
|
|
1543
|
-
secondSlot.style.
|
|
1550
|
+
if (physicalStart === "right") secondSlot.style.right = `${secondSlotOffsetTwips / 15}px`;
|
|
1551
|
+
else secondSlot.style.left = `${secondSlotOffsetTwips / 15}px`;
|
|
1544
1552
|
secondSlot.style.top = "0";
|
|
1545
1553
|
span.append(firstSlot, secondSlot);
|
|
1546
1554
|
return span;
|
|
@@ -2,7 +2,7 @@ import { EMPHASIS_MARK_VALUES, FIELD_TYPE_VALUES, FONT_HINT_VALUES, FONT_THEME_V
|
|
|
2
2
|
import { isParagraphDirection } from "../paragraphDirection.js";
|
|
3
3
|
import { TRACKED_CHANGE_PROVENANCE_VALUES } from "../schema/marks.js";
|
|
4
4
|
import { panic } from "better-result";
|
|
5
|
-
import { isOoxmlSymbolCharacter } from "@stll/docx-core/model";
|
|
5
|
+
import { DRAWING_RAW_XML_MODES, isOoxmlSymbolCharacter } from "@stll/docx-core/model";
|
|
6
6
|
//#region src/prosemirror/attrs/index.ts
|
|
7
7
|
const SECTION_BREAK_TYPES = [
|
|
8
8
|
"nextPage",
|
|
@@ -143,6 +143,7 @@ const readParagraphAttrs = (node) => {
|
|
|
143
143
|
optionalString(attrs, "textId", "paragraph.attrs.textId", issues);
|
|
144
144
|
optionalOneOf(attrs, "alignment", "paragraph.attrs.alignment", issues, PARAGRAPH_ALIGNMENT_VALUES);
|
|
145
145
|
optionalString(attrs, "styleId", "paragraph.attrs.styleId", issues);
|
|
146
|
+
optionalNumber(attrs, "_tableOfContentsLevel", "paragraph.attrs._tableOfContentsLevel", issues);
|
|
146
147
|
optionalBoolean(attrs, "kinsoku", "paragraph.attrs.kinsoku", issues);
|
|
147
148
|
optionalBoolean(attrs, "overflowPunctuation", "paragraph.attrs.overflowPunctuation", issues);
|
|
148
149
|
optionalBoolean(attrs, "suppressAutoHyphens", "paragraph.attrs.suppressAutoHyphens", issues);
|
|
@@ -357,6 +358,12 @@ const readImageAttrs = (node) => {
|
|
|
357
358
|
optionalString(attrs, "hlinkHref", "image.attrs.hlinkHref", issues);
|
|
358
359
|
optionalString(attrs, "hlinkRId", "image.attrs.hlinkRId", issues);
|
|
359
360
|
optionalString(attrs, "_docxRawXml", "image.attrs._docxRawXml", issues);
|
|
361
|
+
optionalOneOf(attrs, "_docxRawXmlMode", "image.attrs._docxRawXmlMode", issues, Object.values(DRAWING_RAW_XML_MODES));
|
|
362
|
+
const rawXml = attrs["_docxRawXml"];
|
|
363
|
+
if (attrs["_docxRawXmlMode"] === DRAWING_RAW_XML_MODES.PRESERVE_ONLY && (typeof rawXml !== "string" || rawXml.trim().length === 0)) issues.push({
|
|
364
|
+
path: "image.attrs._docxRawXml",
|
|
365
|
+
message: "Preservation-only drawings require raw XML."
|
|
366
|
+
});
|
|
360
367
|
optionalBoolean(attrs, "_docxObjectPreview", "image.attrs._docxObjectPreview", issues);
|
|
361
368
|
return attrsResult(attrs, issues);
|
|
362
369
|
};
|
|
@@ -422,6 +429,7 @@ const readShapeAttrs = (node) => {
|
|
|
422
429
|
const issues = [];
|
|
423
430
|
expectNodeType(node, "shape", issues);
|
|
424
431
|
optionalString(attrs, "shapeType", "shape.attrs.shapeType", issues);
|
|
432
|
+
optionalString(attrs, "geometryAdjustments", "shape.attrs.geometryAdjustments", issues);
|
|
425
433
|
optionalString(attrs, "shapeId", "shape.attrs.shapeId", issues);
|
|
426
434
|
optionalNumber(attrs, "width", "shape.attrs.width", issues);
|
|
427
435
|
optionalNumber(attrs, "height", "shape.attrs.height", issues);
|
|
@@ -105,7 +105,8 @@ const constrainImageSize = (width, height) => {
|
|
|
105
105
|
};
|
|
106
106
|
const imageNodeAt = (view, pos) => {
|
|
107
107
|
const node = view.state.doc.nodeAt(pos);
|
|
108
|
-
|
|
108
|
+
if (!node || node.type.name !== "image") return null;
|
|
109
|
+
return expectImageAttrs(node)._docxRawXmlMode ? null : node;
|
|
109
110
|
};
|
|
110
111
|
/** Change the wrap mode of the image at `pos`. Returns whether it applied. */
|
|
111
112
|
const applyImageWrapType = (view, pos, wrapType) => {
|
|
@@ -7,13 +7,27 @@ import { autospacingMatchesBase, hasAutospacingBaseSide } from "../autospacingBa
|
|
|
7
7
|
import { applyRunFormattingOverrideAttrs } from "../extensions/marks/RunFormattingOverrideExtension.js";
|
|
8
8
|
import { directionToBidi } from "../paragraphDirection.js";
|
|
9
9
|
import { RUN_FORMATTING_MARK_NAMES } from "../runFormattingMarkNames.js";
|
|
10
|
+
import { parseShapeGeometryAdjustments } from "../shapeGeometryAdjustments.js";
|
|
10
11
|
import { expectTextBoxAnchorAttrs } from "../textBoxAnchorAttrs.js";
|
|
11
12
|
import { assertValidProseMirrorDocument } from "../validation.js";
|
|
12
13
|
import { runShadingAttrsToShading } from "./runShadingMark.js";
|
|
13
14
|
import { decodeSdtListItems, sdtPropertiesFromAttrs, sdtPropertiesMatchAttrs } from "./sdtAttrs.js";
|
|
14
15
|
import { textFormattingToMarks } from "./toProseDoc.js";
|
|
16
|
+
import { panic } from "better-result";
|
|
17
|
+
import { DRAWING_RAW_XML_MODES } from "@stll/docx-core/model";
|
|
15
18
|
import { Fragment } from "prosemirror-model";
|
|
16
19
|
//#region src/prosemirror/conversion/fromProseDoc.ts
|
|
20
|
+
/**
|
|
21
|
+
* ProseMirror to Document Conversion
|
|
22
|
+
*
|
|
23
|
+
* Converts a ProseMirror document back to our Document type.
|
|
24
|
+
* This enables round-trip editing: DOCX -> Document -> PM -> Document -> DOCX
|
|
25
|
+
*
|
|
26
|
+
* Key responsibilities:
|
|
27
|
+
* - Coalesce consecutive text with same marks into single Runs
|
|
28
|
+
* - Preserve paragraph attributes (paraId, textId, formatting)
|
|
29
|
+
* - Handle marks -> TextFormatting conversion
|
|
30
|
+
*/
|
|
17
31
|
function normalizeShapeOutlineStyle(style) {
|
|
18
32
|
if (!style) return;
|
|
19
33
|
if (style in OUTLINE_STYLE_CSS_ALIASES) return OUTLINE_STYLE_CSS_ALIASES[style];
|
|
@@ -1256,14 +1270,18 @@ function createImageRun(node) {
|
|
|
1256
1270
|
if (cropLeft !== void 0) crop.left = cropLeft;
|
|
1257
1271
|
image.crop = crop;
|
|
1258
1272
|
}
|
|
1259
|
-
const drawingContent = {
|
|
1260
|
-
type: "drawing",
|
|
1261
|
-
image
|
|
1262
|
-
};
|
|
1263
|
-
if (attrs._docxRawXml) drawingContent.rawXml = attrs._docxRawXml;
|
|
1264
1273
|
return {
|
|
1265
1274
|
type: "run",
|
|
1266
|
-
content: [
|
|
1275
|
+
content: [attrs._docxRawXmlMode === DRAWING_RAW_XML_MODES.PRESERVE_ONLY ? {
|
|
1276
|
+
type: "drawing",
|
|
1277
|
+
image,
|
|
1278
|
+
rawXml: attrs._docxRawXml ?? panic("Preservation-only ProseMirror image attrs must include raw XML."),
|
|
1279
|
+
rawXmlMode: DRAWING_RAW_XML_MODES.PRESERVE_ONLY
|
|
1280
|
+
} : {
|
|
1281
|
+
type: "drawing",
|
|
1282
|
+
image,
|
|
1283
|
+
...attrs._docxRawXml ? { rawXml: attrs._docxRawXml } : {}
|
|
1284
|
+
}]
|
|
1267
1285
|
};
|
|
1268
1286
|
}
|
|
1269
1287
|
/**
|
|
@@ -1280,6 +1298,8 @@ function createShapeRun(node) {
|
|
|
1280
1298
|
}
|
|
1281
1299
|
};
|
|
1282
1300
|
if (attrs.shapeId) shape.id = attrs.shapeId;
|
|
1301
|
+
const geometryAdjustments = parseShapeGeometryAdjustments(attrs.geometryAdjustments);
|
|
1302
|
+
if (geometryAdjustments !== void 0) shape.geometryAdjustments = geometryAdjustments;
|
|
1283
1303
|
const shapeTransform = parseTransformAttr(attrs.transform);
|
|
1284
1304
|
if (shapeTransform) shape.transform = shapeTransform;
|
|
1285
1305
|
const wrap = { type: attrs.wrapType || "inline" };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { resolveColorValueToHex } from "../../docx/drawingUtils.js";
|
|
2
2
|
import { createStyleEngine } from "../../style-engine/styleEngine.js";
|
|
3
3
|
import { mergeParagraphFormatting, mergeParagraphTabStops } from "../../utils/paragraphFormattingMerge.js";
|
|
4
|
+
import { tableOfContentsStyleLevel } from "../../utils/tableOfContentsStyle.js";
|
|
4
5
|
import { mergeTextFormatting } from "../../utils/textFormattingMerge.js";
|
|
5
6
|
import { emuToPixels } from "../../utils/units.js";
|
|
6
7
|
import { setAutospacingBaseValue } from "../autospacingBase.js";
|
|
@@ -13,8 +14,6 @@ import { marksToTextFormatting } from "./fromProseDoc.js";
|
|
|
13
14
|
import { shadingToRunShadingAttrs } from "./runShadingMark.js";
|
|
14
15
|
import { sdtAttrsFromProperties } from "./sdtAttrs.js";
|
|
15
16
|
//#region src/prosemirror/conversion/toProseDoc.ts
|
|
16
|
-
const TOC_STYLE_ID = /^TOC\d*$/iu;
|
|
17
|
-
const isTocStyleId = (styleId) => styleId !== void 0 && TOC_STYLE_ID.test(styleId);
|
|
18
17
|
/**
|
|
19
18
|
* Build a `nextTextBoxGroupId()` generator salted with a random per-load
|
|
20
19
|
* nonce, so minted text-box anchor ids (`<salt>:<group>:<index>`) are unique
|
|
@@ -128,7 +127,7 @@ function convertBlockSdt(blockSdt, convertBlocks) {
|
|
|
128
127
|
*/
|
|
129
128
|
function convertParagraph(paragraph, styleResolver, nextHyperlinkInstanceIndex, activeCommentIds, extraRunFormatting, tableParagraphOverlay, textBoxAnchors) {
|
|
130
129
|
const attrs = paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOverlay);
|
|
131
|
-
const isTocParagraph =
|
|
130
|
+
const isTocParagraph = attrs._tableOfContentsLevel !== void 0;
|
|
132
131
|
const inlineNodes = [];
|
|
133
132
|
let inlineOffset = 0;
|
|
134
133
|
let bookmarksArr;
|
|
@@ -280,10 +279,16 @@ function canCarryTrackedRunMark(node, markType) {
|
|
|
280
279
|
function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOverlay) {
|
|
281
280
|
const formatting = paragraph.formatting;
|
|
282
281
|
const styleId = formatting?.styleId;
|
|
282
|
+
const styleName = styleId ? styleResolver?.getStyle(styleId)?.name : void 0;
|
|
283
|
+
const tableOfContentsLevel = tableOfContentsStyleLevel({
|
|
284
|
+
styleId,
|
|
285
|
+
...styleName ? { styleName } : {}
|
|
286
|
+
});
|
|
283
287
|
const attrs = {};
|
|
284
288
|
if (paragraph.paraId) attrs.paraId = paragraph.paraId;
|
|
285
289
|
if (paragraph.textId) attrs.textId = paragraph.textId;
|
|
286
290
|
if (styleId) attrs.styleId = styleId;
|
|
291
|
+
if (tableOfContentsLevel !== void 0) attrs._tableOfContentsLevel = tableOfContentsLevel;
|
|
287
292
|
if (formatting?.numPr) attrs.numPr = formatting.numPr;
|
|
288
293
|
if (formatting?.numPrFromStyle) attrs.numPrFromStyle = formatting.numPrFromStyle;
|
|
289
294
|
if (paragraph.listRendering?.numFmt) attrs.listNumFmt = paragraph.listRendering.numFmt;
|
|
@@ -350,7 +355,7 @@ function paragraphFormattingToAttrs(paragraph, styleResolver, tableParagraphOver
|
|
|
350
355
|
set("runInWithNext", formatting?.runInWithNext ?? stylePpr?.runInWithNext);
|
|
351
356
|
set("outlineLevel", formatting?.outlineLevel ?? stylePpr?.outlineLevel);
|
|
352
357
|
set("direction", directionFromBidi(formatting?.bidi ?? stylePpr?.bidi));
|
|
353
|
-
set("defaultTextFormatting", resolveParagraphDefaultTextFormatting(styleId, formatting, styleResolver, { includeParagraphMarkRunProperties:
|
|
358
|
+
set("defaultTextFormatting", resolveParagraphDefaultTextFormatting(styleId, formatting, styleResolver, { includeParagraphMarkRunProperties: tableOfContentsLevel === void 0 }));
|
|
354
359
|
if (!formatting?.numPr && stylePpr?.numPr && stylePpr.numPr.numId !== 0) {
|
|
355
360
|
attrs.numPr = stylePpr.numPr;
|
|
356
361
|
attrs.numPrFromStyle = stylePpr.numPr;
|
|
@@ -1050,7 +1055,11 @@ function convertRunContent(content, marks, formatting, textBoxAnchors) {
|
|
|
1050
1055
|
return [];
|
|
1051
1056
|
case "renderedPageBreak": return [schema.node("renderedPageBreak").mark(marks)];
|
|
1052
1057
|
case "tab": return [schema.node("tab", content.positional ? { positional: content.positional } : void 0).mark(marks)];
|
|
1053
|
-
case "drawing": return [withHyperlinkBoundaryMarks(convertImage(
|
|
1058
|
+
case "drawing": return [withHyperlinkBoundaryMarks(convertImage({
|
|
1059
|
+
image: content.image,
|
|
1060
|
+
rawXml: content.rawXml,
|
|
1061
|
+
rawXmlMode: content.rawXmlMode
|
|
1062
|
+
}), marks)];
|
|
1054
1063
|
case "shape": {
|
|
1055
1064
|
const shp = content.shape;
|
|
1056
1065
|
if (shp.textBody) {
|
|
@@ -1089,7 +1098,7 @@ function withHyperlinkBoundaryMarks(node, marks) {
|
|
|
1089
1098
|
if (!marks.some((mark) => mark.type.name === "hyperlink")) return node;
|
|
1090
1099
|
return node.mark(marks);
|
|
1091
1100
|
}
|
|
1092
|
-
function convertImage(image, rawXml) {
|
|
1101
|
+
function convertImage({ image, rawXml, rawXmlMode }) {
|
|
1093
1102
|
const imageSize = image.size;
|
|
1094
1103
|
const widthPx = imageSize?.width ? emuToPixels(imageSize.width) : void 0;
|
|
1095
1104
|
const heightPx = imageSize?.height ? emuToPixels(imageSize.height) : void 0;
|
|
@@ -1190,6 +1199,7 @@ function convertImage(image, rawXml) {
|
|
|
1190
1199
|
hlinkHref: image.hlinkHref,
|
|
1191
1200
|
hlinkRId: image.hlinkRId,
|
|
1192
1201
|
_docxRawXml: rawXml,
|
|
1202
|
+
_docxRawXmlMode: rawXmlMode,
|
|
1193
1203
|
_docxObjectPreview: rawXml !== void 0 && /<(?:[A-Za-z_][\w.-]*:)?object(?:\s|>)/u.test(rawXml)
|
|
1194
1204
|
});
|
|
1195
1205
|
}
|
|
@@ -1347,6 +1357,7 @@ function convertShape(shape) {
|
|
|
1347
1357
|
};
|
|
1348
1358
|
return schema.node("shape", {
|
|
1349
1359
|
shapeType: shapeAttrs.shapeType ?? "rect",
|
|
1360
|
+
geometryAdjustments: shape.geometryAdjustments === void 0 ? void 0 : JSON.stringify(shape.geometryAdjustments),
|
|
1350
1361
|
shapeId: shape.id,
|
|
1351
1362
|
width: widthPx,
|
|
1352
1363
|
height: heightPx,
|
|
@@ -6,6 +6,8 @@ import { EditorState } from "prosemirror-state";
|
|
|
6
6
|
type ResolvedStyleAttrs = {
|
|
7
7
|
paragraphFormatting?: document_d_exports.ParagraphFormatting;
|
|
8
8
|
runFormatting?: document_d_exports.TextFormatting;
|
|
9
|
+
/** Canonical OOXML style name, used when the document-local style id is localized. */
|
|
10
|
+
styleName?: string;
|
|
9
11
|
/**
|
|
10
12
|
* Numbering definitions from the document package. When the applied style
|
|
11
13
|
* carries a `w:numPr`, these resolve the numbering level into the list
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { paragraphToStyle } from "../../../utils/formatToStyle.js";
|
|
2
2
|
import { collectHeadings } from "../../../utils/headingCollector.js";
|
|
3
|
+
import { tableOfContentsStyleLevel } from "../../../utils/tableOfContentsStyle.js";
|
|
3
4
|
import { expectParagraphAttrs } from "../../attrs/index.js";
|
|
4
5
|
import { autospacingMatchesBase } from "../../autospacingBase.js";
|
|
5
6
|
import { directionIsRtl } from "../../paragraphDirection.js";
|
|
@@ -215,6 +216,7 @@ const paragraphNodeSpec = {
|
|
|
215
216
|
listAbstractNumId: { default: null },
|
|
216
217
|
listStartOverride: { default: null },
|
|
217
218
|
styleId: { default: null },
|
|
219
|
+
_tableOfContentsLevel: { default: null },
|
|
218
220
|
borders: { default: null },
|
|
219
221
|
shading: { default: null },
|
|
220
222
|
tabs: { default: null },
|
|
@@ -248,11 +250,13 @@ const paragraphNodeSpec = {
|
|
|
248
250
|
const paraId = element.dataset["paraId"];
|
|
249
251
|
const alignment = element.dataset["alignment"];
|
|
250
252
|
const styleId = element.dataset["styleId"];
|
|
253
|
+
const tableOfContentsLevel = Number(element.dataset["tableOfContentsLevel"]);
|
|
251
254
|
const sectionBreakType = element.dataset["sectionBreak"];
|
|
252
255
|
const attrs = {
|
|
253
256
|
...paraId ? { paraId } : {},
|
|
254
257
|
...alignment ? { alignment } : {},
|
|
255
258
|
...styleId ? { styleId } : {},
|
|
259
|
+
...Number.isSafeInteger(tableOfContentsLevel) && tableOfContentsLevel > 0 ? { _tableOfContentsLevel: tableOfContentsLevel } : {},
|
|
256
260
|
...sectionBreakType ? { sectionBreakType } : {}
|
|
257
261
|
};
|
|
258
262
|
const styleAttrs = extractParagraphAttrsFromStyle(element);
|
|
@@ -291,6 +295,7 @@ const paragraphNodeSpec = {
|
|
|
291
295
|
if (attrs.paraId) domAttrs["data-para-id"] = attrs.paraId;
|
|
292
296
|
if (attrs.alignment) domAttrs["data-alignment"] = attrs.alignment;
|
|
293
297
|
if (attrs.styleId) domAttrs["data-style-id"] = attrs.styleId;
|
|
298
|
+
if (typeof attrs._tableOfContentsLevel === "number") domAttrs["data-table-of-contents-level"] = String(attrs._tableOfContentsLevel);
|
|
294
299
|
if (attrs.listMarker) domAttrs["data-list-marker"] = attrs.listMarker;
|
|
295
300
|
if (directionIsRtl(attrs.direction)) domAttrs["dir"] = "rtl";
|
|
296
301
|
if (attrs.sectionBreakType) {
|
|
@@ -460,10 +465,14 @@ function makeApplyStyle(schema) {
|
|
|
460
465
|
seen.add(pos);
|
|
461
466
|
const newAttrs = {
|
|
462
467
|
...node.attrs,
|
|
463
|
-
styleId
|
|
468
|
+
styleId,
|
|
469
|
+
_tableOfContentsLevel: tableOfContentsStyleLevel({ styleId }) ?? null
|
|
464
470
|
};
|
|
465
471
|
if (resolvedAttrs) {
|
|
466
|
-
Object.assign(newAttrs, paragraphAttrsFromResolvedStyle(resolvedAttrs
|
|
472
|
+
Object.assign(newAttrs, paragraphAttrsFromResolvedStyle(resolvedAttrs, {
|
|
473
|
+
styleId,
|
|
474
|
+
...resolvedAttrs.styleName ? { styleName: resolvedAttrs.styleName } : {}
|
|
475
|
+
}));
|
|
467
476
|
const listAttrs = listAttrsFromResolvedStyle(resolvedAttrs, resolvedAttrs.numbering);
|
|
468
477
|
if (listAttrs) Object.assign(newAttrs, listAttrs);
|
|
469
478
|
}
|
|
@@ -534,7 +543,10 @@ const ParagraphExtension = createNodeExtension({
|
|
|
534
543
|
hangingIndent: hanging ?? false
|
|
535
544
|
}),
|
|
536
545
|
applyStyle: (styleId, resolvedAttrs) => applyStyleFn(styleId, resolvedAttrs),
|
|
537
|
-
clearStyle: () =>
|
|
546
|
+
clearStyle: () => setParagraphAttrsCmd({
|
|
547
|
+
styleId: null,
|
|
548
|
+
_tableOfContentsLevel: null
|
|
549
|
+
}),
|
|
538
550
|
insertSectionBreak: (breakType) => setParagraphAttr("sectionBreakType", breakType),
|
|
539
551
|
removeSectionBreak: () => setParagraphAttr("sectionBreakType", null),
|
|
540
552
|
generateTOC: () => (state, dispatch) => {
|
|
@@ -53,6 +53,7 @@ const clearIndentOnBackspace = (state, dispatch) => {
|
|
|
53
53
|
const INHERITED_PARA_ATTRS = [
|
|
54
54
|
"defaultTextFormatting",
|
|
55
55
|
"styleId",
|
|
56
|
+
"_tableOfContentsLevel",
|
|
56
57
|
"lineSpacing",
|
|
57
58
|
"lineSpacingRule",
|
|
58
59
|
"snapToGrid",
|
|
@@ -77,11 +78,15 @@ function applyNextParagraphStyle(tr, sourcePara, newPara, resolver) {
|
|
|
77
78
|
const nextStyleId = resolver.getNextStyleId(sourcePara.attrs["styleId"]);
|
|
78
79
|
if (!nextStyleId) return false;
|
|
79
80
|
const resolved = resolver.resolveParagraphStyle(nextStyleId);
|
|
81
|
+
const styleName = resolver.getStyle(nextStyleId)?.name;
|
|
80
82
|
const { $from } = tr.selection;
|
|
81
83
|
tr.setNodeMarkup($from.before(), void 0, {
|
|
82
84
|
...newPara.attrs,
|
|
83
85
|
styleId: nextStyleId,
|
|
84
|
-
...paragraphAttrsFromResolvedStyle(resolved
|
|
86
|
+
...paragraphAttrsFromResolvedStyle(resolved, {
|
|
87
|
+
styleId: nextStyleId,
|
|
88
|
+
...styleName ? { styleName } : {}
|
|
89
|
+
})
|
|
85
90
|
});
|
|
86
91
|
tr.setStoredMarks(resolved.runFormatting ? textFormattingToMarks(resolved.runFormatting, tr.doc.type.schema) : []);
|
|
87
92
|
return true;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { document_d_exports } from "../../../types/document.js";
|
|
1
2
|
import { ShapeAttrs as ShapeAttrs$1 } from "../../schema/nodes.js";
|
|
2
3
|
import { NodeExtension } from "../types.js";
|
|
3
4
|
//#region src/prosemirror/extensions/nodes/ShapeExtension.d.ts
|
|
@@ -7,6 +8,11 @@ declare function sanitizeTransform(value: string | null | undefined): string | n
|
|
|
7
8
|
declare function sanitizeSvgId(value: string | null | undefined): string | null;
|
|
8
9
|
declare function sanitizeShapeDimension(value: number | null | undefined, fallback: number): number;
|
|
9
10
|
declare function strokeDashArrayForOutlineStyle(outlineStyle: string | undefined): string | undefined;
|
|
11
|
+
type RightBracePaths = {
|
|
12
|
+
fill: string;
|
|
13
|
+
outline: string;
|
|
14
|
+
};
|
|
15
|
+
declare function buildRightBracePaths(w: number, h: number, adjustments: readonly document_d_exports.ShapeGeometryAdjustment[]): RightBracePaths;
|
|
10
16
|
/**
|
|
11
17
|
* Build the `points` string for a polygon-based shape preset.
|
|
12
18
|
*
|
|
@@ -26,4 +32,4 @@ type GradientStop = {
|
|
|
26
32
|
declare function parseGradientStops(raw: string | undefined): GradientStop[];
|
|
27
33
|
declare const ShapeExtension: (options?: Partial<Record<string, unknown>> | undefined) => NodeExtension;
|
|
28
34
|
//#endregion
|
|
29
|
-
export { ShapeAttrs, ShapeExtension, buildShapePolygonPoints, parseGradientStops, sanitizeColor, sanitizeShapeDimension, sanitizeSvgId, sanitizeTransform, strokeDashArrayForOutlineStyle };
|
|
35
|
+
export { ShapeAttrs, ShapeExtension, buildRightBracePaths, buildShapePolygonPoints, parseGradientStops, sanitizeColor, sanitizeShapeDimension, sanitizeSvgId, sanitizeTransform, strokeDashArrayForOutlineStyle };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { expectShapeAttrs } from "../../attrs/index.js";
|
|
2
|
+
import { parseShapeGeometryAdjustments } from "../../shapeGeometryAdjustments.js";
|
|
2
3
|
import { createNodeExtension } from "../create.js";
|
|
3
4
|
//#region src/prosemirror/extensions/nodes/ShapeExtension.ts
|
|
4
5
|
/**
|
|
@@ -123,6 +124,40 @@ function setNum(el, name, value) {
|
|
|
123
124
|
function fmt(n) {
|
|
124
125
|
return Number.isInteger(n) ? String(n) : Number(n.toFixed(3)).toString();
|
|
125
126
|
}
|
|
127
|
+
const RIGHT_BRACE_DEFAULT_THICKNESS = 8333;
|
|
128
|
+
const RIGHT_BRACE_DEFAULT_CUSP = 5e4;
|
|
129
|
+
const GEOMETRY_PERCENT_SCALE = 1e5;
|
|
130
|
+
const geometryAdjustment = (adjustments, name, fallback) => {
|
|
131
|
+
const authored = adjustments.find((adjustment) => adjustment.name === name);
|
|
132
|
+
if (!authored) return fallback;
|
|
133
|
+
const match = /^val\s+(-?\d+)$/u.exec(authored.formula);
|
|
134
|
+
if (!match) return fallback;
|
|
135
|
+
return Number(match.at(1));
|
|
136
|
+
};
|
|
137
|
+
function buildRightBracePaths(w, h, adjustments) {
|
|
138
|
+
const shortSide = Math.min(w, h);
|
|
139
|
+
const cuspAdjustment = Math.min(GEOMETRY_PERCENT_SCALE, Math.max(0, geometryAdjustment(adjustments, "adj2", RIGHT_BRACE_DEFAULT_CUSP)));
|
|
140
|
+
const maxThickness = Math.min(cuspAdjustment, GEOMETRY_PERCENT_SCALE - cuspAdjustment) / 2 * h / shortSide;
|
|
141
|
+
const radius = shortSide * Math.min(maxThickness, Math.max(0, geometryAdjustment(adjustments, "adj1", RIGHT_BRACE_DEFAULT_THICKNESS))) / GEOMETRY_PERCENT_SCALE;
|
|
142
|
+
const halfWidth = w / 2;
|
|
143
|
+
const cusp = h * cuspAdjustment / GEOMETRY_PERCENT_SCALE;
|
|
144
|
+
const upperStemEnd = cusp - radius;
|
|
145
|
+
const lowerStemStart = cusp + radius;
|
|
146
|
+
const bottomCurveStart = h - radius;
|
|
147
|
+
const commands = [
|
|
148
|
+
"M 0 0",
|
|
149
|
+
`A ${fmt(halfWidth)} ${fmt(radius)} 0 0 1 ${fmt(halfWidth)} ${fmt(radius)}`,
|
|
150
|
+
`L ${fmt(halfWidth)} ${fmt(upperStemEnd)}`,
|
|
151
|
+
`A ${fmt(halfWidth)} ${fmt(radius)} 0 0 0 ${fmt(w)} ${fmt(cusp)}`,
|
|
152
|
+
`A ${fmt(halfWidth)} ${fmt(radius)} 0 0 0 ${fmt(halfWidth)} ${fmt(lowerStemStart)}`,
|
|
153
|
+
`L ${fmt(halfWidth)} ${fmt(bottomCurveStart)}`,
|
|
154
|
+
`A ${fmt(halfWidth)} ${fmt(radius)} 0 0 1 0 ${fmt(h)}`
|
|
155
|
+
].join(" ");
|
|
156
|
+
return {
|
|
157
|
+
fill: `${commands} Z`,
|
|
158
|
+
outline: commands
|
|
159
|
+
};
|
|
160
|
+
}
|
|
126
161
|
/**
|
|
127
162
|
* Build the `points` string for a polygon-based shape preset.
|
|
128
163
|
*
|
|
@@ -209,7 +244,7 @@ function buildShapePolygonPoints(type, w, h) {
|
|
|
209
244
|
* displays. The original `<a:prstGeom prst>` value round-trips through the
|
|
210
245
|
* model regardless of what the renderer chooses to draw.
|
|
211
246
|
*/
|
|
212
|
-
function createShapeElement(type, w, h) {
|
|
247
|
+
function createShapeElement(type, w, h, adjustments) {
|
|
213
248
|
switch (type) {
|
|
214
249
|
case "ellipse":
|
|
215
250
|
case "oval": {
|
|
@@ -238,6 +273,19 @@ function createShapeElement(type, w, h) {
|
|
|
238
273
|
setNum(el, "y2", h / 2);
|
|
239
274
|
return el;
|
|
240
275
|
}
|
|
276
|
+
case "rightBrace": {
|
|
277
|
+
const paths = buildRightBracePaths(w, h, adjustments);
|
|
278
|
+
const group = document.createElementNS(SVG_NS, "g");
|
|
279
|
+
const fill = document.createElementNS(SVG_NS, "path");
|
|
280
|
+
fill.setAttribute("d", paths.fill);
|
|
281
|
+
fill.setAttribute("stroke", "none");
|
|
282
|
+
group.append(fill);
|
|
283
|
+
const outline = document.createElementNS(SVG_NS, "path");
|
|
284
|
+
outline.setAttribute("d", paths.outline);
|
|
285
|
+
outline.setAttribute("fill", "none");
|
|
286
|
+
group.append(outline);
|
|
287
|
+
return group;
|
|
288
|
+
}
|
|
241
289
|
default: {
|
|
242
290
|
const points = buildShapePolygonPoints(type, w, h);
|
|
243
291
|
if (points !== null) {
|
|
@@ -320,6 +368,7 @@ const ShapeExtension = createNodeExtension({
|
|
|
320
368
|
atom: true,
|
|
321
369
|
attrs: {
|
|
322
370
|
shapeType: { default: "rect" },
|
|
371
|
+
geometryAdjustments: { default: null },
|
|
323
372
|
shapeId: { default: null },
|
|
324
373
|
width: { default: 100 },
|
|
325
374
|
height: { default: 80 },
|
|
@@ -362,6 +411,7 @@ const ShapeExtension = createNodeExtension({
|
|
|
362
411
|
const outlineTailEnd = parseShapeLineEnd(d["outlineTailEnd"]);
|
|
363
412
|
return {
|
|
364
413
|
shapeType: d["shapeType"] || "rect",
|
|
414
|
+
...d["geometryAdjustments"] ? { geometryAdjustments: d["geometryAdjustments"] } : {},
|
|
365
415
|
...d["shapeId"] ? { shapeId: d["shapeId"] } : {},
|
|
366
416
|
...d["width"] ? { width: Number(d["width"]) } : {},
|
|
367
417
|
...d["height"] ? { height: Number(d["height"]) } : {},
|
|
@@ -403,6 +453,7 @@ const ShapeExtension = createNodeExtension({
|
|
|
403
453
|
class: "docx-shape",
|
|
404
454
|
"data-shape-type": attrs.shapeType || "rect"
|
|
405
455
|
};
|
|
456
|
+
if (attrs.geometryAdjustments) domAttrs["data-geometry-adjustments"] = attrs.geometryAdjustments;
|
|
406
457
|
if (attrs.shapeId) domAttrs["data-shape-id"] = attrs.shapeId;
|
|
407
458
|
domAttrs["data-width"] = String(w);
|
|
408
459
|
domAttrs["data-height"] = String(h);
|
|
@@ -489,7 +540,8 @@ const ShapeExtension = createNodeExtension({
|
|
|
489
540
|
defs.append(gradient);
|
|
490
541
|
svg.append(defs);
|
|
491
542
|
}
|
|
492
|
-
const
|
|
543
|
+
const geometryAdjustments = parseShapeGeometryAdjustments(attrs.geometryAdjustments) ?? [];
|
|
544
|
+
const shapeEl = createShapeElement(attrs.shapeType || "rect", w, h, geometryAdjustments);
|
|
493
545
|
const strokeDasharray = strokeDashArrayForOutlineStyle(attrs.outlineStyle);
|
|
494
546
|
if (strokeDasharray) shapeEl.setAttribute("stroke-dasharray", strokeDasharray);
|
|
495
547
|
svg.append(shapeEl);
|
|
@@ -501,4 +553,4 @@ const ShapeExtension = createNodeExtension({
|
|
|
501
553
|
}
|
|
502
554
|
});
|
|
503
555
|
//#endregion
|
|
504
|
-
export { ShapeExtension, buildShapePolygonPoints, parseGradientStops, sanitizeColor, sanitizeShapeDimension, sanitizeSvgId, sanitizeTransform, strokeDashArrayForOutlineStyle };
|
|
556
|
+
export { ShapeExtension, buildRightBracePaths, buildShapePolygonPoints, parseGradientStops, sanitizeColor, sanitizeShapeDimension, sanitizeSvgId, sanitizeTransform, strokeDashArrayForOutlineStyle };
|
|
@@ -102,6 +102,8 @@ type ParagraphAttrs = {
|
|
|
102
102
|
/** Numbering start override for this numId/level. */
|
|
103
103
|
listStartOverride?: number;
|
|
104
104
|
styleId?: string;
|
|
105
|
+
/** Imported built-in TOC entry level, resolved from the canonical style name. */
|
|
106
|
+
_tableOfContentsLevel?: number;
|
|
105
107
|
borders?: {
|
|
106
108
|
top?: document_d_exports.BorderSpec;
|
|
107
109
|
bottom?: document_d_exports.BorderSpec;
|
|
@@ -275,6 +277,8 @@ type ImageAttrs = {
|
|
|
275
277
|
hlinkRId?: string;
|
|
276
278
|
/** Original OOXML for opaque/unsupported DOCX drawings. */
|
|
277
279
|
_docxRawXml?: string;
|
|
280
|
+
/** Raw XML preserved without an editable image projection. */
|
|
281
|
+
_docxRawXmlMode?: document_d_exports.DrawingRawXmlMode;
|
|
278
282
|
/** Embedded-object previews use their authored box as the exact line height. */
|
|
279
283
|
_docxObjectPreview?: boolean;
|
|
280
284
|
};
|
|
@@ -382,6 +386,8 @@ type BlockSdtAttrs = {
|
|
|
382
386
|
type ShapeAttrs = {
|
|
383
387
|
/** Shape type preset */
|
|
384
388
|
shapeType?: string;
|
|
389
|
+
/** Preset geometry adjustments serialized as JSON. */
|
|
390
|
+
geometryAdjustments?: string;
|
|
385
391
|
/** Unique identifier */
|
|
386
392
|
shapeId?: string;
|
|
387
393
|
/** Width in pixels */
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
2
|
+
//#region src/prosemirror/shapeGeometryAdjustments.d.ts
|
|
3
|
+
declare const parseShapeGeometryAdjustments: (raw: string | undefined) => document_d_exports.ShapeGeometryAdjustment[] | undefined;
|
|
4
|
+
//#endregion
|
|
5
|
+
export { parseShapeGeometryAdjustments };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/prosemirror/shapeGeometryAdjustments.ts
|
|
2
|
+
const MAX_ADJUSTMENT_COUNT = 32;
|
|
3
|
+
const MAX_ADJUSTMENT_NAME_LENGTH = 64;
|
|
4
|
+
const MAX_ADJUSTMENT_FORMULA_LENGTH = 128;
|
|
5
|
+
const parseShapeGeometryAdjustments = (raw) => {
|
|
6
|
+
if (!raw) return;
|
|
7
|
+
try {
|
|
8
|
+
const parsed = JSON.parse(raw);
|
|
9
|
+
if (!Array.isArray(parsed) || parsed.length > MAX_ADJUSTMENT_COUNT) return;
|
|
10
|
+
const adjustments = [];
|
|
11
|
+
for (const item of parsed) {
|
|
12
|
+
if (typeof item !== "object" || item === null || !("name" in item) || typeof item.name !== "string" || item.name.length === 0 || item.name.length > MAX_ADJUSTMENT_NAME_LENGTH || !("formula" in item) || typeof item.formula !== "string" || item.formula.length === 0 || item.formula.length > MAX_ADJUSTMENT_FORMULA_LENGTH) return;
|
|
13
|
+
adjustments.push({
|
|
14
|
+
name: item.name,
|
|
15
|
+
formula: item.formula
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return adjustments.length === 0 ? void 0 : adjustments;
|
|
19
|
+
} catch {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
//#endregion
|
|
24
|
+
export { parseShapeGeometryAdjustments };
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { NumberingMap } from "../../docx/numberingParser.js";
|
|
2
2
|
import { ResolvedParagraphStyle } from "./styleResolver.js";
|
|
3
3
|
//#region src/prosemirror/styles/resolvedStyleAttrs.d.ts
|
|
4
|
+
type ResolvedStyleIdentity = {
|
|
5
|
+
styleId: string;
|
|
6
|
+
styleName?: string;
|
|
7
|
+
};
|
|
4
8
|
/**
|
|
5
9
|
* The paragraph attrs a style definition controls. Applying a style resets
|
|
6
10
|
* every one of these to the style's value (or `null` to clear), so a prior
|
|
7
11
|
* style's properties (e.g. a heading's spacing) never leak through. Returns
|
|
8
12
|
* a partial attrs object to merge over the paragraph's existing attrs.
|
|
9
13
|
*/
|
|
10
|
-
declare function paragraphAttrsFromResolvedStyle(resolved: ResolvedParagraphStyle): Record<string, unknown>;
|
|
14
|
+
declare function paragraphAttrsFromResolvedStyle(resolved: ResolvedParagraphStyle, identity: ResolvedStyleIdentity): Record<string, unknown>;
|
|
11
15
|
/**
|
|
12
16
|
* The list attrs a style's `w:pPr/w:numPr` controls (numbering reference plus
|
|
13
17
|
* the baked marker-rendering attrs that `toProseDoc` normally derives from
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { computeListRendering } from "../../docx/numberingParser.js";
|
|
2
|
+
import { tableOfContentsStyleLevel } from "../../utils/tableOfContentsStyle.js";
|
|
2
3
|
import { setAutospacingBaseValue } from "../autospacingBase.js";
|
|
3
4
|
//#region src/prosemirror/styles/resolvedStyleAttrs.ts
|
|
4
5
|
/**
|
|
@@ -17,7 +18,7 @@ import { setAutospacingBaseValue } from "../autospacingBase.js";
|
|
|
17
18
|
* style's properties (e.g. a heading's spacing) never leak through. Returns
|
|
18
19
|
* a partial attrs object to merge over the paragraph's existing attrs.
|
|
19
20
|
*/
|
|
20
|
-
function paragraphAttrsFromResolvedStyle(resolved) {
|
|
21
|
+
function paragraphAttrsFromResolvedStyle(resolved, identity) {
|
|
21
22
|
const ppr = resolved.paragraphFormatting;
|
|
22
23
|
const runFormatting = resolved.runFormatting;
|
|
23
24
|
const hasRunFormatting = !!runFormatting && Object.keys(runFormatting).length > 0;
|
|
@@ -40,7 +41,8 @@ function paragraphAttrsFromResolvedStyle(resolved) {
|
|
|
40
41
|
outlineLevel: ppr?.outlineLevel ?? null,
|
|
41
42
|
borders: ppr?.borders ?? null,
|
|
42
43
|
defaultTextFormatting: hasRunFormatting ? runFormatting : null,
|
|
43
|
-
_autospacingBase: autospacingBaseFromResolvedParagraphFormatting(ppr)
|
|
44
|
+
_autospacingBase: autospacingBaseFromResolvedParagraphFormatting(ppr),
|
|
45
|
+
_tableOfContentsLevel: tableOfContentsStyleLevel(identity) ?? null
|
|
44
46
|
};
|
|
45
47
|
}
|
|
46
48
|
function autospacingBaseFromResolvedParagraphFormatting(ppr) {
|
package/dist/types/content.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { BlockContent, BlockSdt, BookmarkEnd, BookmarkStart, BreakContent, Column, Comment, CommentRangeEnd, CommentRangeStart, CommentReference, ComplexField, Deletion, DocumentBody, DrawingContent, Endnote, EndnotePosition, EndnoteProperties, Field, FieldCharContent, FieldType, FooterReference, Footnote, FootnotePosition, FootnoteProperties, HeaderFooter, HeaderFooterType, HeaderReference, Hyperlink, Image, ImageCrop, ImagePadding, ImagePosition, ImageSize, ImageTransform, ImageWrap, InlineSdt, Insertion, InstrTextContent, LineNumberRestart, MathEquation, MoveFrom, MoveFromRangeEnd, MoveFromRangeStart, MoveTo, MoveToRangeEnd, MoveToRangeStart, NoBreakHyphenContent, NoteNumberRestart, NoteReferenceContent, PageOrientation, Paragraph, ParagraphContent, ParagraphPropertyChange, PositionalTab, PropertyChangeInfo, Run, RunContent, RunPropertyChange, SdtProperties, SdtType, Section, SectionProperties, SectionStart, Shape, ShapeContent, ShapeFill, ShapeOutline, ShapeTextBody, ShapeType, SimpleField, SoftHyphenContent, SymbolContent, TabContent, Table, TableCell, TableCellPropertyChange, TableRow, TableRowPropertyChange, TableStructuralChangeInfo, TextBox, TextContent, TrackedChangeInfo, TrackedRunChange, VerticalAlign } from "@stll/docx-core/model";
|
|
2
|
-
export type { BlockContent, BlockSdt, BookmarkEnd, BookmarkStart, BreakContent, Column, Comment, CommentRangeEnd, CommentRangeStart, CommentReference, ComplexField, Deletion, DocumentBody, DrawingContent, Endnote, EndnotePosition, EndnoteProperties, Field, FieldCharContent, FieldType, FooterReference, Footnote, FootnotePosition, FootnoteProperties, HeaderFooter, HeaderFooterType, HeaderReference, Hyperlink, Image, ImageCrop, ImagePadding, ImagePosition, ImageSize, ImageTransform, ImageWrap, InlineSdt, Insertion, InstrTextContent, LineNumberRestart, MathEquation, MoveFrom, MoveFromRangeEnd, MoveFromRangeStart, MoveTo, MoveToRangeEnd, MoveToRangeStart, NoBreakHyphenContent, NoteNumberRestart, NoteReferenceContent, PageOrientation, Paragraph, ParagraphContent, ParagraphPropertyChange, PositionalTab, PropertyChangeInfo, Run, RunContent, RunPropertyChange, SdtProperties, SdtType, Section, SectionProperties, SectionStart, Shape, ShapeContent, ShapeFill, ShapeOutline, ShapeTextBody, ShapeType, SimpleField, SoftHyphenContent, SymbolContent, TabContent, Table, TableCell, TableCellPropertyChange, TableRow, TableRowPropertyChange, TableStructuralChangeInfo, TextBox, TextContent, TrackedChangeInfo, TrackedRunChange, VerticalAlign };
|
|
1
|
+
import { BlockContent, BlockSdt, BookmarkEnd, BookmarkStart, BreakContent, Column, Comment, CommentRangeEnd, CommentRangeStart, CommentReference, ComplexField, Deletion, DocumentBody, DrawingContent, DrawingRawXmlMode, Endnote, EndnotePosition, EndnoteProperties, Field, FieldCharContent, FieldType, FooterReference, Footnote, FootnotePosition, FootnoteProperties, HeaderFooter, HeaderFooterType, HeaderReference, Hyperlink, Image, ImageCrop, ImagePadding, ImagePosition, ImageSize, ImageTransform, ImageWrap, InlineSdt, Insertion, InstrTextContent, LineNumberRestart, MathEquation, MoveFrom, MoveFromRangeEnd, MoveFromRangeStart, MoveTo, MoveToRangeEnd, MoveToRangeStart, NoBreakHyphenContent, NoteNumberRestart, NoteReferenceContent, PageOrientation, Paragraph, ParagraphContent, ParagraphPropertyChange, PositionalTab, PropertyChangeInfo, Run, RunContent, RunPropertyChange, SdtProperties, SdtType, Section, SectionProperties, SectionStart, Shape, ShapeContent, ShapeFill, ShapeGeometryAdjustment, ShapeOutline, ShapeTextBody, ShapeType, SimpleField, SoftHyphenContent, SymbolContent, TabContent, Table, TableCell, TableCellPropertyChange, TableRow, TableRowPropertyChange, TableStructuralChangeInfo, TextBox, TextContent, TrackedChangeInfo, TrackedRunChange, VerticalAlign } from "@stll/docx-core/model";
|
|
2
|
+
export type { BlockContent, BlockSdt, BookmarkEnd, BookmarkStart, BreakContent, Column, Comment, CommentRangeEnd, CommentRangeStart, CommentReference, ComplexField, Deletion, DocumentBody, DrawingContent, DrawingRawXmlMode, Endnote, EndnotePosition, EndnoteProperties, Field, FieldCharContent, FieldType, FooterReference, Footnote, FootnotePosition, FootnoteProperties, HeaderFooter, HeaderFooterType, HeaderReference, Hyperlink, Image, ImageCrop, ImagePadding, ImagePosition, ImageSize, ImageTransform, ImageWrap, InlineSdt, Insertion, InstrTextContent, LineNumberRestart, MathEquation, MoveFrom, MoveFromRangeEnd, MoveFromRangeStart, MoveTo, MoveToRangeEnd, MoveToRangeStart, NoBreakHyphenContent, NoteNumberRestart, NoteReferenceContent, PageOrientation, Paragraph, ParagraphContent, ParagraphPropertyChange, PositionalTab, PropertyChangeInfo, Run, RunContent, RunPropertyChange, SdtProperties, SdtType, Section, SectionProperties, SectionStart, Shape, ShapeContent, ShapeFill, ShapeGeometryAdjustment, ShapeOutline, ShapeTextBody, ShapeType, SimpleField, SoftHyphenContent, SymbolContent, TabContent, Table, TableCell, TableCellPropertyChange, TableRow, TableRowPropertyChange, TableStructuralChangeInfo, TextBox, TextContent, TrackedChangeInfo, TrackedRunChange, VerticalAlign };
|
package/dist/types/index.d.ts
CHANGED
|
@@ -16,6 +16,7 @@ type DocumentBody = document_d_exports.DocumentBody;
|
|
|
16
16
|
type DocxConformanceClass = document_d_exports.DocxConformanceClass;
|
|
17
17
|
type DocxPackage = document_d_exports.DocxPackage;
|
|
18
18
|
type DrawingContent = document_d_exports.DrawingContent;
|
|
19
|
+
type DrawingRawXmlMode = document_d_exports.DrawingRawXmlMode;
|
|
19
20
|
type EmphasisMark = document_d_exports.EmphasisMark;
|
|
20
21
|
type Endnote = document_d_exports.Endnote;
|
|
21
22
|
type EndnotePosition = document_d_exports.EndnotePosition;
|
|
@@ -72,6 +73,7 @@ type ShadingProperties = document_d_exports.ShadingProperties;
|
|
|
72
73
|
type Shape = document_d_exports.Shape;
|
|
73
74
|
type ShapeContent = document_d_exports.ShapeContent;
|
|
74
75
|
type ShapeFill = document_d_exports.ShapeFill;
|
|
76
|
+
type ShapeGeometryAdjustment = document_d_exports.ShapeGeometryAdjustment;
|
|
75
77
|
type ShapeOutline = document_d_exports.ShapeOutline;
|
|
76
78
|
type ShapeTextBody = document_d_exports.ShapeTextBody;
|
|
77
79
|
type ShapeType = document_d_exports.ShapeType;
|
|
@@ -106,4 +108,4 @@ type ThemeFont = document_d_exports.ThemeFont;
|
|
|
106
108
|
type ThemeFontScheme = document_d_exports.ThemeFontScheme;
|
|
107
109
|
type UnderlineStyle = document_d_exports.UnderlineStyle;
|
|
108
110
|
type VerticalAlign = document_d_exports.VerticalAlign;
|
|
109
|
-
export type { AbstractNumbering, BlockContent, BookmarkEnd, BookmarkStart, BorderSpec, BreakContent, CellMargins, ColorValue, Column, ComplexField, ConditionalFormatStyle, DocDefaults, Document, DocumentBody, DocxConformanceClass, DocxPackage, DrawingContent, EmphasisMark, Endnote, EndnotePosition, EndnoteProperties, Field, FieldCharContent, FieldType, FloatingTableProperties, FontInfo, FontTable, FooterReference, Footnote, FootnotePosition, FootnoteProperties, HeaderFooter, HeaderFooterType, HeaderReference, Hyperlink, Image, ImageCrop, ImagePadding, ImagePosition, ImageSize, ImageTransform, ImageWrap, InstrTextContent, LevelSuffix, LineNumberRestart, LineSpacingRule, ListLevel, ListRendering, MediaFile, NoBreakHyphenContent, NoteNumberRestart, NoteReferenceContent, NumberFormat, NumberingDefinitions, NumberingInstance, PageOrientation, Paragraph, ParagraphAlignment, ParagraphContent, ParagraphFormatting, PositionalTab, Relationship, RelationshipMap, RelationshipType, Run, RunContent, Section, SectionProperties, SectionStart, ShadingProperties, Shape, ShapeContent, ShapeFill, ShapeOutline, ShapeTextBody, ShapeType, SimpleField, SoftHyphenContent, Style, StyleDefinitions, StyleType, SymbolContent, TabContent, TabLeader, TabStop, TabStopAlignment, Table, TableBorders, TableCell, TableCellFormatting, TableFormatting, TableLook, TableMeasurement, TableRow, TableRowFormatting, TableWidthType, TextBox, TextContent, TextEffect, TextFormatting, Theme, ThemeColorScheme, ThemeColorSlot, ThemeFont, ThemeFontScheme, UnderlineStyle, VerticalAlign };
|
|
111
|
+
export type { AbstractNumbering, BlockContent, BookmarkEnd, BookmarkStart, BorderSpec, BreakContent, CellMargins, ColorValue, Column, ComplexField, ConditionalFormatStyle, DocDefaults, Document, DocumentBody, DocxConformanceClass, DocxPackage, DrawingContent, DrawingRawXmlMode, EmphasisMark, Endnote, EndnotePosition, EndnoteProperties, Field, FieldCharContent, FieldType, FloatingTableProperties, FontInfo, FontTable, FooterReference, Footnote, FootnotePosition, FootnoteProperties, HeaderFooter, HeaderFooterType, HeaderReference, Hyperlink, Image, ImageCrop, ImagePadding, ImagePosition, ImageSize, ImageTransform, ImageWrap, InstrTextContent, LevelSuffix, LineNumberRestart, LineSpacingRule, ListLevel, ListRendering, MediaFile, NoBreakHyphenContent, NoteNumberRestart, NoteReferenceContent, NumberFormat, NumberingDefinitions, NumberingInstance, PageOrientation, Paragraph, ParagraphAlignment, ParagraphContent, ParagraphFormatting, PositionalTab, Relationship, RelationshipMap, RelationshipType, Run, RunContent, Section, SectionProperties, SectionStart, ShadingProperties, Shape, ShapeContent, ShapeFill, ShapeGeometryAdjustment, ShapeOutline, ShapeTextBody, ShapeType, SimpleField, SoftHyphenContent, Style, StyleDefinitions, StyleType, SymbolContent, TabContent, TabLeader, TabStop, TabStopAlignment, Table, TableBorders, TableCell, TableCellFormatting, TableFormatting, TableLook, TableMeasurement, TableRow, TableRowFormatting, TableWidthType, TextBox, TextContent, TextEffect, TextFormatting, Theme, ThemeColorScheme, ThemeColorSlot, ThemeFont, ThemeFontScheme, UnderlineStyle, VerticalAlign };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/utils/tableOfContentsStyle.d.ts
|
|
2
|
+
type TableOfContentsStyleIdentity = {
|
|
3
|
+
styleId: string | undefined;
|
|
4
|
+
styleName?: string;
|
|
5
|
+
};
|
|
6
|
+
/** Resolve a built-in TOC entry style without relying on its localized style id. */
|
|
7
|
+
declare const tableOfContentsStyleLevel: ({ styleId, styleName }: TableOfContentsStyleIdentity) => number | undefined;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { tableOfContentsStyleLevel };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region src/utils/tableOfContentsStyle.ts
|
|
2
|
+
const TABLE_OF_CONTENTS_STYLE_ID = /^TOC(?<level>\d*)$/iu;
|
|
3
|
+
const TABLE_OF_CONTENTS_STYLE_NAME = /^toc\s+(?<level>\d+)$/iu;
|
|
4
|
+
const parsedLevel = (match) => {
|
|
5
|
+
if (!match) return;
|
|
6
|
+
const rawLevel = match.groups?.["level"];
|
|
7
|
+
if (rawLevel === "") return 1;
|
|
8
|
+
const level = Number(rawLevel);
|
|
9
|
+
return Number.isSafeInteger(level) && level > 0 ? level : void 0;
|
|
10
|
+
};
|
|
11
|
+
/** Resolve a built-in TOC entry style without relying on its localized style id. */
|
|
12
|
+
const tableOfContentsStyleLevel = ({ styleId, styleName }) => parsedLevel(TABLE_OF_CONTENTS_STYLE_ID.exec(styleId ?? "")) ?? parsedLevel(TABLE_OF_CONTENTS_STYLE_NAME.exec(styleName ?? ""));
|
|
13
|
+
//#endregion
|
|
14
|
+
export { tableOfContentsStyleLevel };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stll/folio-core",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.5",
|
|
4
4
|
"description": "Headless, framework-neutral core of folio: the OOXML (.docx) parser, document model, ProseMirror integration, and page-layout engine. No React.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"document-model",
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
"perf": "bun scripts/profile-editor.ts"
|
|
114
114
|
},
|
|
115
115
|
"dependencies": {
|
|
116
|
-
"@stll/docx-core": "^0.17.
|
|
116
|
+
"@stll/docx-core": "^0.17.1",
|
|
117
117
|
"@stll/docx-utils": "^0.1.0",
|
|
118
118
|
"@stll/template-conditions": "^0.1.0",
|
|
119
119
|
"better-result": "3.0.1",
|