feat: 完成 DOCX R4 元素级视觉门禁

建立 Chromium、Word 与 WPS 的可编辑内容、段落几何、页眉页脚、封面、媒体和逐页视觉比较链路。

支持封面独立分节、正文页码重启、主题页边距与横向纸张,并将自然分页差异降为诊断项。

修正代码块内边距和折叠表格单元格边框映射,14 套主题生产矩阵与六组布局视觉矩阵通过。
This commit is contained in:
SkyJourney
2026-08-02 03:27:11 +08:00
parent f9f5fccfc9
commit 58f87cc19f
100 changed files with 10409 additions and 386 deletions
@@ -105,6 +105,7 @@ describe("DOCX 主题引擎契约", () => {
borderLeft: "0px none rgb(0, 0, 0)",
width: "100px",
maxWidth: "none",
minWidth: "0px",
minHeight: "0px",
height: "24px",
breakBefore: "auto",
@@ -40,6 +40,7 @@ const computed: DocxComputedStyle = {
borderLeft: "0px none rgb(17, 34, 51)",
width: "640px",
maxWidth: "none",
minWidth: "0px",
minHeight: "0px",
height: "24px",
breakBefore: "auto",
@@ -203,12 +204,40 @@ describe("DOCX 主题令牌归一化", () => {
expect(findSlot(tokens, "table").style.widthPercent).toBe(100);
});
it("按父级内容区归一化右置百分比结构容器", () => {
const tokens = resolveDocxThemeTokens({
snapshot: createSnapshot({
"official-signature": {
width: "332.8px",
containingBlockWidth: "640px",
marginLeft: "307.2px",
marginRight: "0px",
textAlign: "center"
}
}),
config: {
mode: "auto",
basePreset: "official",
overrides: {},
legacyPreset: false
}
});
expect(findSlot(tokens, "official-signature").style).toMatchObject({
widthPercent: 52,
leftIndentPt: 230.4,
rightIndentPt: 0,
alignment: "center"
});
});
it("保留封面高度、垂直对齐、轮廓线和隐藏字段语义", () => {
const tokens = resolveDocxThemeTokens({
snapshot: createSnapshot({
"tender-cover": {
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
minHeight: "220mm",
borderBottom: "0px none rgb(17, 34, 51)",
@@ -216,7 +245,9 @@ describe("DOCX 主题令牌归一化", () => {
outlineOffset: "-16px"
},
"tender-bidder": {
display: "none"
display: "none",
alignSelf: "flex-end",
contentPaddingLeft: "8px"
}
}),
config: {
@@ -231,6 +262,7 @@ describe("DOCX 主题令牌归一化", () => {
expect(cover.style).toMatchObject({
minimumHeightPt: 623.622,
verticalAlignment: "center",
childAlignment: "center",
borders: {
top: {
widthPt: 0.75,
@@ -239,7 +271,11 @@ describe("DOCX 主题令牌归一化", () => {
}
}
});
expect(findSlot(tokens, "tender-bidder").style.hidden).toBe(true);
expect(findSlot(tokens, "tender-bidder").style).toMatchObject({
hidden: true,
selfAlignment: "right",
contentPaddingLeftPt: 6
});
expect(
tokens.diagnostics.some(
(entry) =>
@@ -250,6 +286,31 @@ describe("DOCX 主题令牌归一化", () => {
).toBe(true);
});
it("保留结构槽位的实际宽度以映射 Flex 子项位置", () => {
const tokens = resolveDocxThemeTokens({
snapshot: createSnapshot({
document: {
width: "640px",
paddingLeft: "8px",
paddingRight: "8px"
},
"project-report-owner": {
minWidth: "70%"
}
}),
config: {
mode: "auto",
basePreset: "formal",
overrides: {},
legacyPreset: false
}
});
expect(
findSlot(tokens, "project-report-owner").style.minimumWidthPercent
).toBe(70);
});
it("将超出 Word 能力的装饰边收敛并生成诊断", () => {
const tokens = resolveDocxThemeTokens({
snapshot: createSnapshot({
@@ -38,6 +38,7 @@ const computedStyle: DocxComputedStyle = {
borderLeft: "0px none rgb(17, 17, 17)",
width: "640px",
maxWidth: "none",
minWidth: "0px",
minHeight: "0px",
height: "28px",
breakBefore: "auto",
@@ -73,6 +74,9 @@ describe("DOCX 标准样式探针", () => {
expect(new Set(slots)).toEqual(
new Set(DOCX_STYLE_SLOT_NAMES)
);
expect(markup).toMatch(
/^<article id="write"[^>]*>\s*<h1 data-docx-slot="heading-1">/u
);
});
it("拒绝缺失和重复槽位的探针", () => {
@@ -43,6 +43,7 @@ const computed: DocxComputedStyle = {
borderLeft: "0px none rgb(17, 17, 17)",
width: "640px",
maxWidth: "none",
minWidth: "0px",
minHeight: "0px",
height: "24px",
breakBefore: "auto",
@@ -79,6 +80,10 @@ describe("DOCX 主题样式浏览器运行时", () => {
themeCss: '#write::before { content: "</style><script>x</script>"; }'
});
expect(script).toContain("theme.textContent");
expect(script).toContain("style[property]");
expect(script).toContain("contentPaddingLeft");
expect(script).toContain("padding-left: 8px");
expect(script).toContain("#write pre.md-fences \\u003e code");
expect(script).toContain("frame.remove()");
expect(script).not.toContain("</style><script>x</script>");
});