@json-to-office/core-docx 3.3.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +556 -36
- package/dist/index.js.map +1 -1
- package/dist/plugin/example/index.js +368 -33
- package/dist/plugin/example/index.js.map +1 -1
- package/dist/quality/facts.d.ts +27 -1
- package/dist/quality/facts.d.ts.map +1 -1
- package/dist/quality/rules.d.ts +38 -1
- package/dist/quality/rules.d.ts.map +1 -1
- package/dist/quality/text-inventory.d.ts +45 -0
- package/dist/quality/text-inventory.d.ts.map +1 -0
- package/dist/templates/themes/consulting.docx.theme.json +1 -0
- package/dist/templates/themes/devportal.docx.theme.json +1 -0
- package/dist/templates/themes/index.d.ts +5 -0
- package/dist/templates/themes/index.d.ts.map +1 -1
- package/dist/templates/themes/minimal.docx.theme.json +1 -0
- package/dist/templates/themes/vermilion.docx.theme.json +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
|
@@ -193,6 +193,7 @@ var init_minimal_docx_theme = __esm({
|
|
|
193
193
|
name: "minimal",
|
|
194
194
|
displayName: "Minimal Clean",
|
|
195
195
|
description: "A quiet, warm minimal theme \u2014 Calibri throughout, sage-green ink on ivory neutrals, a large tracked-tight bold title, wide margins and hairline rules",
|
|
196
|
+
whenToUse: "Quiet documents where the type carries the tone: notes, briefs, drafts and internal papers that want warmth without decoration.",
|
|
196
197
|
version: "4.0.0",
|
|
197
198
|
colors: {
|
|
198
199
|
primary: "#2B302B",
|
|
@@ -382,6 +383,7 @@ var init_devportal_docx_theme = __esm({
|
|
|
382
383
|
name: "devportal",
|
|
383
384
|
displayName: "Field Editorial",
|
|
384
385
|
description: "A compact editorial theme \u2014 Helvetica in near-black ink with a burnt-orange accent, tight condensed titles, letterspaced labels, warm tinted fills and hairline rules",
|
|
386
|
+
whenToUse: "Developer and product documentation, API guides and technical handbooks: dense text, code and tables that need compact, letterspaced structure.",
|
|
385
387
|
version: "4.0.0",
|
|
386
388
|
colors: {
|
|
387
389
|
primary: "#12191F",
|
|
@@ -580,6 +582,7 @@ var init_vermilion_docx_theme = __esm({
|
|
|
580
582
|
name: "vermilion",
|
|
581
583
|
displayName: "Vermilion Editorial",
|
|
582
584
|
description: "Poster-red editorial system \u2014 vermilion display headings, ink text, warm creams and hairline rules",
|
|
585
|
+
whenToUse: "Editorial and annual-report work that wants a strong red display voice: covers, feature-style sections, reports built around a few large headings.",
|
|
583
586
|
version: "1.0.0",
|
|
584
587
|
colors: {
|
|
585
588
|
primary: "#282829",
|
|
@@ -798,6 +801,7 @@ var init_consulting_docx_theme = __esm({
|
|
|
798
801
|
name: "consulting",
|
|
799
802
|
displayName: "Consulting House",
|
|
800
803
|
description: "The house style for client and technical reports \u2014 near-black ink, three greys and one deep-blue accent, Calibri body under Arial headings, hairline rules, no fills behind body text, safe fonts only",
|
|
804
|
+
whenToUse: "Client and technical reports, memos and anything a client will read as the house's own work; the default choice for a report unless the brief names a brand.",
|
|
801
805
|
version: "1.0.0",
|
|
802
806
|
colors: {
|
|
803
807
|
primary: "#1A1F26",
|
|
@@ -12132,8 +12136,10 @@ import {
|
|
|
12132
12136
|
} from "@json-to-office/quality";
|
|
12133
12137
|
import { DEFAULT_DOCX_RENDERER_ID as DEFAULT_DOCX_RENDERER_ID2 } from "@json-to-office/shared-docx";
|
|
12134
12138
|
import {
|
|
12139
|
+
designCanvas as designCanvas2,
|
|
12135
12140
|
designColors as designColors2,
|
|
12136
|
-
resolveDesignColor as resolveDesignColor2
|
|
12141
|
+
resolveDesignColor as resolveDesignColor2,
|
|
12142
|
+
typeScaleSizes
|
|
12137
12143
|
} from "@json-to-office/shared";
|
|
12138
12144
|
|
|
12139
12145
|
// src/json/normalizer.ts
|
|
@@ -12476,9 +12482,176 @@ async function expandBlocksWithPlugins(document, theme, plugins, render, preserv
|
|
|
12476
12482
|
init_styleHelpers();
|
|
12477
12483
|
init_defaults();
|
|
12478
12484
|
init_widthUtils();
|
|
12485
|
+
|
|
12486
|
+
// src/quality/text-inventory.ts
|
|
12479
12487
|
function asRecord(value) {
|
|
12480
12488
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
12481
12489
|
}
|
|
12490
|
+
function twipsToPt(value) {
|
|
12491
|
+
return typeof value === "number" && Number.isFinite(value) ? value / 20 : void 0;
|
|
12492
|
+
}
|
|
12493
|
+
function frameOf(props) {
|
|
12494
|
+
const widthPt = twipsToPt(asRecord(props.floating)?.width);
|
|
12495
|
+
return widthPt === void 0 ? void 0 : { widthPt };
|
|
12496
|
+
}
|
|
12497
|
+
function collectDocxTextInventory(children, basePath = "/children") {
|
|
12498
|
+
const entries = [];
|
|
12499
|
+
const add = (path3, text, role, extra = {}) => {
|
|
12500
|
+
if (typeof text !== "string" || text.trim() === "") return;
|
|
12501
|
+
entries.push({
|
|
12502
|
+
id: `docx:text:${path3}`,
|
|
12503
|
+
kind: "docx/text",
|
|
12504
|
+
path: path3,
|
|
12505
|
+
text,
|
|
12506
|
+
role,
|
|
12507
|
+
order: entries.length,
|
|
12508
|
+
...extra
|
|
12509
|
+
});
|
|
12510
|
+
};
|
|
12511
|
+
const visitCell = (cell, path3, role, inherited) => {
|
|
12512
|
+
const cellRole = inherited.repeats ? "chrome" : role;
|
|
12513
|
+
const extra = inherited.repeats ? { repeats: true } : {};
|
|
12514
|
+
if (typeof cell === "string") {
|
|
12515
|
+
add(path3, cell, cellRole, extra);
|
|
12516
|
+
return;
|
|
12517
|
+
}
|
|
12518
|
+
const rec = asRecord(cell);
|
|
12519
|
+
if (!rec) return;
|
|
12520
|
+
if ("content" in rec) {
|
|
12521
|
+
if (typeof rec.content === "string")
|
|
12522
|
+
add(`${path3}/content`, rec.content, cellRole, extra);
|
|
12523
|
+
else {
|
|
12524
|
+
const inner = asRecord(rec.content);
|
|
12525
|
+
if (inner) visitNode(inner, `${path3}/content`, inherited);
|
|
12526
|
+
}
|
|
12527
|
+
return;
|
|
12528
|
+
}
|
|
12529
|
+
if (typeof rec.name === "string") visitNode(rec, path3, inherited);
|
|
12530
|
+
};
|
|
12531
|
+
const visitNode = (node, path3, inherited) => {
|
|
12532
|
+
if (node.enabled === false) return;
|
|
12533
|
+
const props = asRecord(node.props) ?? {};
|
|
12534
|
+
const name = typeof node.name === "string" ? node.name : "";
|
|
12535
|
+
const extra = {
|
|
12536
|
+
...inherited.repeats && { repeats: true }
|
|
12537
|
+
};
|
|
12538
|
+
switch (name) {
|
|
12539
|
+
case "heading": {
|
|
12540
|
+
if (inherited.repeats) {
|
|
12541
|
+
add(`${path3}/props/text`, props.text, "chrome", extra);
|
|
12542
|
+
break;
|
|
12543
|
+
}
|
|
12544
|
+
const level = typeof props.level === "number" && Number.isFinite(props.level) ? props.level : 1;
|
|
12545
|
+
add(`${path3}/props/text`, props.text, "heading", { ...extra, level });
|
|
12546
|
+
break;
|
|
12547
|
+
}
|
|
12548
|
+
case "paragraph": {
|
|
12549
|
+
const frame = frameOf(props);
|
|
12550
|
+
add(
|
|
12551
|
+
`${path3}/props/text`,
|
|
12552
|
+
props.text,
|
|
12553
|
+
inherited.repeats ? "chrome" : "body",
|
|
12554
|
+
{
|
|
12555
|
+
...extra,
|
|
12556
|
+
...frame && { frame }
|
|
12557
|
+
}
|
|
12558
|
+
);
|
|
12559
|
+
break;
|
|
12560
|
+
}
|
|
12561
|
+
case "list": {
|
|
12562
|
+
if (Array.isArray(props.items)) {
|
|
12563
|
+
props.items.forEach((item, index) => {
|
|
12564
|
+
const itemPath = `${path3}/props/items/${index}`;
|
|
12565
|
+
if (typeof item === "string")
|
|
12566
|
+
add(itemPath, item, "list-item", extra);
|
|
12567
|
+
else {
|
|
12568
|
+
const rec = asRecord(item);
|
|
12569
|
+
if (rec) add(`${itemPath}/text`, rec.text, "list-item", extra);
|
|
12570
|
+
}
|
|
12571
|
+
});
|
|
12572
|
+
}
|
|
12573
|
+
break;
|
|
12574
|
+
}
|
|
12575
|
+
case "table": {
|
|
12576
|
+
const columns = Array.isArray(props.columns) ? props.columns.map(asRecord) : [];
|
|
12577
|
+
columns.forEach((column, columnIndex) => {
|
|
12578
|
+
if (!column) return;
|
|
12579
|
+
visitCell(
|
|
12580
|
+
column.header,
|
|
12581
|
+
`${path3}/props/columns/${columnIndex}/header`,
|
|
12582
|
+
"table-header",
|
|
12583
|
+
inherited
|
|
12584
|
+
);
|
|
12585
|
+
});
|
|
12586
|
+
const rows = Math.max(
|
|
12587
|
+
0,
|
|
12588
|
+
...columns.map(
|
|
12589
|
+
(column) => Array.isArray(column?.cells) ? column.cells.length : 0
|
|
12590
|
+
)
|
|
12591
|
+
);
|
|
12592
|
+
for (let row = 0; row < rows; row++) {
|
|
12593
|
+
columns.forEach((column, columnIndex) => {
|
|
12594
|
+
if (!column || !Array.isArray(column.cells)) return;
|
|
12595
|
+
if (row >= column.cells.length) return;
|
|
12596
|
+
visitCell(
|
|
12597
|
+
column.cells[row],
|
|
12598
|
+
`${path3}/props/columns/${columnIndex}/cells/${row}`,
|
|
12599
|
+
"table-cell",
|
|
12600
|
+
inherited
|
|
12601
|
+
);
|
|
12602
|
+
});
|
|
12603
|
+
}
|
|
12604
|
+
break;
|
|
12605
|
+
}
|
|
12606
|
+
case "statistic": {
|
|
12607
|
+
add(`${path3}/props/number`, props.number, "statistic", extra);
|
|
12608
|
+
add(`${path3}/props/description`, props.description, "statistic", extra);
|
|
12609
|
+
break;
|
|
12610
|
+
}
|
|
12611
|
+
case "image":
|
|
12612
|
+
case "chart":
|
|
12613
|
+
case "highcharts":
|
|
12614
|
+
case "visual":
|
|
12615
|
+
case "visual-native": {
|
|
12616
|
+
add(`${path3}/props/caption`, props.caption, "caption", extra);
|
|
12617
|
+
break;
|
|
12618
|
+
}
|
|
12619
|
+
case "section": {
|
|
12620
|
+
for (const part of ["header", "footer"]) {
|
|
12621
|
+
const components = props[part];
|
|
12622
|
+
if (!Array.isArray(components)) continue;
|
|
12623
|
+
components.forEach((component, index) => {
|
|
12624
|
+
const rec = asRecord(component);
|
|
12625
|
+
if (rec) {
|
|
12626
|
+
visitNode(rec, `${path3}/props/${part}/${index}`, {
|
|
12627
|
+
repeats: true
|
|
12628
|
+
});
|
|
12629
|
+
}
|
|
12630
|
+
});
|
|
12631
|
+
}
|
|
12632
|
+
break;
|
|
12633
|
+
}
|
|
12634
|
+
default:
|
|
12635
|
+
break;
|
|
12636
|
+
}
|
|
12637
|
+
if (Array.isArray(node.children)) {
|
|
12638
|
+
node.children.forEach((child, index) => {
|
|
12639
|
+
const rec = asRecord(child);
|
|
12640
|
+
if (rec) visitNode(rec, `${path3}/children/${index}`, inherited);
|
|
12641
|
+
});
|
|
12642
|
+
}
|
|
12643
|
+
};
|
|
12644
|
+
children.forEach((child, index) => {
|
|
12645
|
+
const rec = asRecord(child);
|
|
12646
|
+
if (rec) visitNode(rec, `${basePath}/${index}`, {});
|
|
12647
|
+
});
|
|
12648
|
+
return entries;
|
|
12649
|
+
}
|
|
12650
|
+
|
|
12651
|
+
// src/quality/facts.ts
|
|
12652
|
+
function asRecord2(value) {
|
|
12653
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
12654
|
+
}
|
|
12482
12655
|
function pageBox(theme, themeName, pageOverride) {
|
|
12483
12656
|
const page = createSectionProperties(
|
|
12484
12657
|
getColumnSettings("single"),
|
|
@@ -12504,7 +12677,7 @@ function tableFact(props, path3, availableWidthTwips) {
|
|
|
12504
12677
|
let percentSum = 0;
|
|
12505
12678
|
const explicitWidths = [];
|
|
12506
12679
|
columns.forEach((column, index) => {
|
|
12507
|
-
const width =
|
|
12680
|
+
const width = asRecord2(column)?.width;
|
|
12508
12681
|
if (typeof width === "number" && Number.isFinite(width)) {
|
|
12509
12682
|
hasExplicitWidth = true;
|
|
12510
12683
|
explicitWidths.push({ index, width });
|
|
@@ -12585,7 +12758,7 @@ function chartFact(node, props, path3, paletteTokens) {
|
|
|
12585
12758
|
const categoryCount = Math.max(
|
|
12586
12759
|
0,
|
|
12587
12760
|
...series.map((entry) => {
|
|
12588
|
-
const record =
|
|
12761
|
+
const record = asRecord2(entry);
|
|
12589
12762
|
const labels = Array.isArray(record?.labels) ? record.labels.length : 0;
|
|
12590
12763
|
const values = Array.isArray(record?.values) ? record.values.length : 0;
|
|
12591
12764
|
return Math.max(labels, values);
|
|
@@ -12627,8 +12800,8 @@ function statesOwnBorders(authored) {
|
|
|
12627
12800
|
return true;
|
|
12628
12801
|
}
|
|
12629
12802
|
const layers = [
|
|
12630
|
-
|
|
12631
|
-
|
|
12803
|
+
asRecord2(authored.cellDefaults),
|
|
12804
|
+
asRecord2(authored.headerCellDefaults)
|
|
12632
12805
|
];
|
|
12633
12806
|
if (layers.some(
|
|
12634
12807
|
(layer) => layer?.borderSize !== void 0 || layer?.borderColor !== void 0
|
|
@@ -12637,8 +12810,8 @@ function statesOwnBorders(authored) {
|
|
|
12637
12810
|
}
|
|
12638
12811
|
const columns = Array.isArray(authored.columns) ? authored.columns : [];
|
|
12639
12812
|
return columns.some((column) => {
|
|
12640
|
-
const record =
|
|
12641
|
-
const defaults =
|
|
12813
|
+
const record = asRecord2(column);
|
|
12814
|
+
const defaults = asRecord2(record?.cellDefaults);
|
|
12642
12815
|
return defaults?.borderSize !== void 0 || defaults?.borderColor !== void 0;
|
|
12643
12816
|
});
|
|
12644
12817
|
}
|
|
@@ -12662,7 +12835,7 @@ function tableDesignFact(props, path3, theme, themeName, authored) {
|
|
|
12662
12835
|
);
|
|
12663
12836
|
const columns = authoredColumns.map(
|
|
12664
12837
|
(column, index) => {
|
|
12665
|
-
const authoredColumn =
|
|
12838
|
+
const authoredColumn = asRecord2(column) ?? {};
|
|
12666
12839
|
const cells = Array.isArray(authoredColumn.cells) ? authoredColumn.cells : [];
|
|
12667
12840
|
const alignments = /* @__PURE__ */ new Set();
|
|
12668
12841
|
const values = [];
|
|
@@ -12681,11 +12854,11 @@ function tableDesignFact(props, path3, theme, themeName, authored) {
|
|
|
12681
12854
|
},
|
|
12682
12855
|
values,
|
|
12683
12856
|
alignment: alignments.size === 1 ? [...alignments][0] : alignments.size === 0 ? "left" : "mixed",
|
|
12684
|
-
hasCellDefaults:
|
|
12685
|
-
hasHeader:
|
|
12857
|
+
hasCellDefaults: asRecord2(authoredColumn.cellDefaults) !== void 0,
|
|
12858
|
+
hasHeader: asRecord2(authoredColumn.header) !== void 0,
|
|
12686
12859
|
generated: false,
|
|
12687
12860
|
cellsWithOwnAlignment: cells.flatMap((cell, cellIndex) => {
|
|
12688
|
-
const alignment2 =
|
|
12861
|
+
const alignment2 = asRecord2(cell)?.horizontalAlignment;
|
|
12689
12862
|
return typeof alignment2 === "string" && DOCX_ALIGNMENTS.has(alignment2) && alignment2 !== "right" ? [cellIndex] : [];
|
|
12690
12863
|
})
|
|
12691
12864
|
};
|
|
@@ -12706,7 +12879,7 @@ function finiteNumber(value) {
|
|
|
12706
12879
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
12707
12880
|
}
|
|
12708
12881
|
function lineHeightPt(fontSizePt, spacing) {
|
|
12709
|
-
const rule =
|
|
12882
|
+
const rule = asRecord2(spacing);
|
|
12710
12883
|
const value = finiteNumber(rule?.value);
|
|
12711
12884
|
switch (rule?.type) {
|
|
12712
12885
|
// `exactly` is an absolute line box, and display type routinely sets it
|
|
@@ -12723,7 +12896,7 @@ function lineHeightPt(fontSizePt, spacing) {
|
|
|
12723
12896
|
}
|
|
12724
12897
|
}
|
|
12725
12898
|
function characterSpacingPt(spacing) {
|
|
12726
|
-
const rule =
|
|
12899
|
+
const rule = asRecord2(spacing);
|
|
12727
12900
|
const value = finiteNumber(rule?.value);
|
|
12728
12901
|
if (rule === void 0 || value === void 0) return 0;
|
|
12729
12902
|
return rule.type === "condensed" ? -value / TWIPS_PER_POINT3 : value / TWIPS_PER_POINT3;
|
|
@@ -12737,7 +12910,7 @@ function nodeAtPointer(root, pointer) {
|
|
|
12737
12910
|
current = current[index];
|
|
12738
12911
|
continue;
|
|
12739
12912
|
}
|
|
12740
|
-
const record =
|
|
12913
|
+
const record = asRecord2(current);
|
|
12741
12914
|
if (!record) return void 0;
|
|
12742
12915
|
current = record[token];
|
|
12743
12916
|
}
|
|
@@ -12753,10 +12926,10 @@ function styleKey(node, props) {
|
|
|
12753
12926
|
return typeof props.themeStyle === "string" && props.themeStyle !== "" ? props.themeStyle : "normal";
|
|
12754
12927
|
}
|
|
12755
12928
|
function effectiveFontSize(node, props, typography) {
|
|
12756
|
-
const authored = finiteNumber(
|
|
12929
|
+
const authored = finiteNumber(asRecord2(props.font)?.size);
|
|
12757
12930
|
if (authored !== void 0) return { fontSizePt: authored, authored: true };
|
|
12758
12931
|
const { styles, theme } = typography;
|
|
12759
|
-
const style =
|
|
12932
|
+
const style = asRecord2(styles[styleKey(node, props)]) ?? asRecord2(styles.normal);
|
|
12760
12933
|
const stated = finiteNumber(style?.size);
|
|
12761
12934
|
if (stated !== void 0) return { fontSizePt: stated, authored: false };
|
|
12762
12935
|
const reference = style?.font === "heading" || style?.font === "body" || style?.font === "mono" || style?.font === "light" ? style.font : void 0;
|
|
@@ -12766,11 +12939,11 @@ function effectiveFontSize(node, props, typography) {
|
|
|
12766
12939
|
function pinnedLineBox(props, path3) {
|
|
12767
12940
|
const candidates = [
|
|
12768
12941
|
[props.lineSpacing, `${path3}/props/lineSpacing`],
|
|
12769
|
-
[
|
|
12942
|
+
[asRecord2(props.font)?.lineSpacing, `${path3}/props/font/lineSpacing`]
|
|
12770
12943
|
];
|
|
12771
12944
|
for (const [spacing, pointer] of candidates) {
|
|
12772
12945
|
if (spacing === void 0) continue;
|
|
12773
|
-
const rule =
|
|
12946
|
+
const rule = asRecord2(spacing);
|
|
12774
12947
|
if (rule?.type !== "exactly") return void 0;
|
|
12775
12948
|
const lineBoxPt = finiteNumber(rule.value);
|
|
12776
12949
|
return lineBoxPt === void 0 ? void 0 : { lineBoxPt, pointer };
|
|
@@ -12796,8 +12969,8 @@ function lineBoxFact(node, props, path3, typography, authored) {
|
|
|
12796
12969
|
};
|
|
12797
12970
|
}
|
|
12798
12971
|
function frameSignature(floating) {
|
|
12799
|
-
const horizontal =
|
|
12800
|
-
const vertical =
|
|
12972
|
+
const horizontal = asRecord2(floating.horizontalPosition);
|
|
12973
|
+
const vertical = asRecord2(floating.verticalPosition);
|
|
12801
12974
|
return JSON.stringify([
|
|
12802
12975
|
floating.width ?? null,
|
|
12803
12976
|
floating.height ?? null,
|
|
@@ -12807,24 +12980,24 @@ function frameSignature(floating) {
|
|
|
12807
12980
|
vertical?.offset ?? null,
|
|
12808
12981
|
vertical?.relative ?? null,
|
|
12809
12982
|
vertical?.align ?? null,
|
|
12810
|
-
|
|
12983
|
+
asRecord2(floating.wrap)?.type ?? null
|
|
12811
12984
|
]);
|
|
12812
12985
|
}
|
|
12813
12986
|
function frameTextFact(props, path3, page, frameChainId, flowIndex) {
|
|
12814
|
-
const floating =
|
|
12987
|
+
const floating = asRecord2(props.floating);
|
|
12815
12988
|
const frameWidthTwips = finiteNumber(floating?.width);
|
|
12816
12989
|
if (frameWidthTwips === void 0) return void 0;
|
|
12817
12990
|
const text = typeof props.text === "string" ? props.text : "";
|
|
12818
12991
|
if (text.trim() === "") return void 0;
|
|
12819
|
-
const font =
|
|
12992
|
+
const font = asRecord2(props.font);
|
|
12820
12993
|
const fontSizePt = finiteNumber(font?.size);
|
|
12821
12994
|
if (fontSizePt === void 0) return void 0;
|
|
12822
12995
|
const longestWord = text.split(/\s+/).reduce(
|
|
12823
12996
|
(longest, word) => word.length > longest.length ? word : longest,
|
|
12824
12997
|
""
|
|
12825
12998
|
);
|
|
12826
|
-
const horizontal =
|
|
12827
|
-
const vertical =
|
|
12999
|
+
const horizontal = asRecord2(floating?.horizontalPosition);
|
|
13000
|
+
const vertical = asRecord2(floating?.verticalPosition);
|
|
12828
13001
|
const offsetX = finiteNumber(horizontal?.offset);
|
|
12829
13002
|
const offsetY = finiteNumber(vertical?.offset);
|
|
12830
13003
|
const absolutelyPinned = horizontal?.offset !== void 0 || vertical?.offset !== void 0;
|
|
@@ -12895,7 +13068,7 @@ function svgTextFacts(props, path3) {
|
|
|
12895
13068
|
return facts;
|
|
12896
13069
|
}
|
|
12897
13070
|
function walkActive(node, path3, page, visit) {
|
|
12898
|
-
const rec =
|
|
13071
|
+
const rec = asRecord2(node);
|
|
12899
13072
|
if (!rec || rec.enabled === false) return;
|
|
12900
13073
|
visit(rec, path3, page);
|
|
12901
13074
|
const children = Array.isArray(rec.children) ? rec.children : [];
|
|
@@ -12903,6 +13076,93 @@ function walkActive(node, path3, page, visit) {
|
|
|
12903
13076
|
(child, index) => walkActive(child, `${path3}/children/${index}`, page, visit)
|
|
12904
13077
|
);
|
|
12905
13078
|
}
|
|
13079
|
+
function textSizeFact(node, props, path3, typography, role) {
|
|
13080
|
+
const size = effectiveFontSize(node, props, typography);
|
|
13081
|
+
if (size === void 0) return void 0;
|
|
13082
|
+
return {
|
|
13083
|
+
id: `docx:text-size:${path3}`,
|
|
13084
|
+
kind: "docx/text-size",
|
|
13085
|
+
path: path3,
|
|
13086
|
+
role: role ?? styleKey(node, props),
|
|
13087
|
+
fontSizePt: size.fontSizePt,
|
|
13088
|
+
authored: size.authored,
|
|
13089
|
+
...size.authored && { sizePath: `${path3}/props/font/size` }
|
|
13090
|
+
};
|
|
13091
|
+
}
|
|
13092
|
+
function tableTextSizeFacts(props, authored, path3, typography, page) {
|
|
13093
|
+
const facts = [];
|
|
13094
|
+
const sizeOf = (holder) => finiteNumber(asRecord2(asRecord2(holder)?.font)?.size);
|
|
13095
|
+
const authoredSize = (holder, pointer, role) => {
|
|
13096
|
+
const size = sizeOf(holder);
|
|
13097
|
+
if (size === void 0) return;
|
|
13098
|
+
facts.push({
|
|
13099
|
+
id: `docx:text-size:${pointer}`,
|
|
13100
|
+
kind: "docx/text-size",
|
|
13101
|
+
path: pointer,
|
|
13102
|
+
role,
|
|
13103
|
+
fontSizePt: size,
|
|
13104
|
+
authored: true,
|
|
13105
|
+
sizePath: `${pointer}/font/size`
|
|
13106
|
+
});
|
|
13107
|
+
};
|
|
13108
|
+
const cellContent = (holder, pointer, role) => {
|
|
13109
|
+
const content = asRecord2(holder)?.content;
|
|
13110
|
+
if (asRecord2(content) === void 0) return;
|
|
13111
|
+
walkActive(content, `${pointer}/content`, page, (node, nodePath) => {
|
|
13112
|
+
if (node.name !== "paragraph" && node.name !== "heading") return;
|
|
13113
|
+
const nodeProps = asRecord2(node.props) ?? {};
|
|
13114
|
+
if (typeof nodeProps.text !== "string" || nodeProps.text.trim() === "")
|
|
13115
|
+
return;
|
|
13116
|
+
const fact = textSizeFact(node, nodeProps, nodePath, typography, role);
|
|
13117
|
+
if (fact) facts.push(fact);
|
|
13118
|
+
});
|
|
13119
|
+
};
|
|
13120
|
+
if (authored) {
|
|
13121
|
+
authoredSize(
|
|
13122
|
+
authored.cellDefaults,
|
|
13123
|
+
`${path3}/props/cellDefaults`,
|
|
13124
|
+
"tableCell"
|
|
13125
|
+
);
|
|
13126
|
+
authoredSize(
|
|
13127
|
+
authored.headerCellDefaults,
|
|
13128
|
+
`${path3}/props/headerCellDefaults`,
|
|
13129
|
+
"tableHeader"
|
|
13130
|
+
);
|
|
13131
|
+
const columns = Array.isArray(authored.columns) ? authored.columns : [];
|
|
13132
|
+
columns.forEach((column, index) => {
|
|
13133
|
+
const record = asRecord2(column) ?? {};
|
|
13134
|
+
const columnPath = `${path3}/props/columns/${index}`;
|
|
13135
|
+
authoredSize(
|
|
13136
|
+
record.cellDefaults,
|
|
13137
|
+
`${columnPath}/cellDefaults`,
|
|
13138
|
+
"tableCell"
|
|
13139
|
+
);
|
|
13140
|
+
authoredSize(record.header, `${columnPath}/header`, "tableHeader");
|
|
13141
|
+
cellContent(record.header, `${columnPath}/header`, "tableHeader");
|
|
13142
|
+
const cells = Array.isArray(record.cells) ? record.cells : [];
|
|
13143
|
+
cells.forEach((cell, cellIndex) => {
|
|
13144
|
+
authoredSize(cell, `${columnPath}/cells/${cellIndex}`, "tableCell");
|
|
13145
|
+
cellContent(cell, `${columnPath}/cells/${cellIndex}`, "tableCell");
|
|
13146
|
+
});
|
|
13147
|
+
});
|
|
13148
|
+
}
|
|
13149
|
+
for (const [key, role] of [
|
|
13150
|
+
["cellDefaults", "tableCell"],
|
|
13151
|
+
["headerCellDefaults", "tableHeader"]
|
|
13152
|
+
]) {
|
|
13153
|
+
const size = sizeOf(props[key]);
|
|
13154
|
+
if (size === void 0) continue;
|
|
13155
|
+
facts.push({
|
|
13156
|
+
id: `docx:text-size:${path3}:${role}`,
|
|
13157
|
+
kind: "docx/text-size",
|
|
13158
|
+
path: path3,
|
|
13159
|
+
role,
|
|
13160
|
+
fontSizePt: size,
|
|
13161
|
+
authored: false
|
|
13162
|
+
});
|
|
13163
|
+
}
|
|
13164
|
+
return facts;
|
|
13165
|
+
}
|
|
12906
13166
|
function prepareDocxQualityDocument(document, options = {}) {
|
|
12907
13167
|
const themed = options.context ?? resolveThemeContext(normalizeDocument(document)[0], {
|
|
12908
13168
|
customThemes: options.customThemes,
|
|
@@ -12967,11 +13227,48 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
12967
13227
|
let inherited = {};
|
|
12968
13228
|
topLevel.forEach((node, index) => {
|
|
12969
13229
|
if (node?.name !== "section") return;
|
|
12970
|
-
const props =
|
|
13230
|
+
const props = asRecord2(node.props) ?? {};
|
|
12971
13231
|
const part = (kind) => props[kind] === "linkToPrevious" ? inherited[kind] : props[kind];
|
|
12972
13232
|
const header = part("header");
|
|
12973
13233
|
const footer = part("footer");
|
|
12974
13234
|
inherited = { header, footer };
|
|
13235
|
+
for (const kind of ["header", "footer"]) {
|
|
13236
|
+
if (!Array.isArray(props[kind])) continue;
|
|
13237
|
+
const drawnByBlock = !Array.isArray(
|
|
13238
|
+
asRecord2(
|
|
13239
|
+
asRecord2(
|
|
13240
|
+
(Array.isArray(themed.document.children) ? themed.document.children : [])[index]
|
|
13241
|
+
)?.props
|
|
13242
|
+
)?.[kind]
|
|
13243
|
+
);
|
|
13244
|
+
const part2 = props[kind];
|
|
13245
|
+
const visitChrome = (child, childPath) => {
|
|
13246
|
+
if (child.name !== "paragraph" && child.name !== "heading") return;
|
|
13247
|
+
const childProps = asRecord2(child.props) ?? {};
|
|
13248
|
+
if (typeof childProps.text !== "string" || childProps.text.trim() === "")
|
|
13249
|
+
return;
|
|
13250
|
+
const fact = textSizeFact(
|
|
13251
|
+
child,
|
|
13252
|
+
childProps,
|
|
13253
|
+
childPath,
|
|
13254
|
+
typography,
|
|
13255
|
+
kind
|
|
13256
|
+
);
|
|
13257
|
+
if (fact)
|
|
13258
|
+
addFact({
|
|
13259
|
+
...fact,
|
|
13260
|
+
generated: drawnByBlock || authoredPath(childPath) !== childPath
|
|
13261
|
+
});
|
|
13262
|
+
};
|
|
13263
|
+
part2.forEach(
|
|
13264
|
+
(child, childIndex) => walkActive(
|
|
13265
|
+
child,
|
|
13266
|
+
`/children/${index}/props/${kind}/${childIndex}`,
|
|
13267
|
+
basePage,
|
|
13268
|
+
visitChrome
|
|
13269
|
+
)
|
|
13270
|
+
);
|
|
13271
|
+
}
|
|
12975
13272
|
addFact({
|
|
12976
13273
|
id: `docx:section-chrome:${index}`,
|
|
12977
13274
|
kind: "docx/section-chrome",
|
|
@@ -13004,13 +13301,35 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
13004
13301
|
const paletteTokens = resolved.theme.palette?.chart?.map(
|
|
13005
13302
|
(value) => `#${resolveDesignColor2(value, visualColors)}`
|
|
13006
13303
|
) ?? SERIES_COLOR_TOKENS.filter((token) => paletteHexes[token] !== void 0);
|
|
13007
|
-
const authoredPropsAt = (pointer) =>
|
|
13304
|
+
const authoredPropsAt = (pointer) => asRecord2(asRecord2(nodeAtPointer(context.document, pointer))?.props);
|
|
13305
|
+
const roleSizesPt = {};
|
|
13306
|
+
for (const key of Object.keys(typography.styles)) {
|
|
13307
|
+
const size = effectiveFontSize(
|
|
13308
|
+
{ name: "paragraph" },
|
|
13309
|
+
{ themeStyle: key },
|
|
13310
|
+
typography
|
|
13311
|
+
);
|
|
13312
|
+
if (size) roleSizesPt[key] = size.fontSizePt;
|
|
13313
|
+
}
|
|
13314
|
+
const scale = resolved.theme.typography?.scale?.[designCanvas2("docx", resolved.theme.page?.size)];
|
|
13315
|
+
const typeScalePt = [
|
|
13316
|
+
.../* @__PURE__ */ new Set([
|
|
13317
|
+
...Object.values(roleSizesPt),
|
|
13318
|
+
...["heading", "body", "mono", "light"].flatMap((role) => {
|
|
13319
|
+
const size = resolveFontSize(resolved.theme, role);
|
|
13320
|
+
return size === void 0 ? [] : [size];
|
|
13321
|
+
}),
|
|
13322
|
+
...scale ? typeScaleSizes(scale) : []
|
|
13323
|
+
])
|
|
13324
|
+
].sort((a, b) => a - b);
|
|
13008
13325
|
addFact({
|
|
13009
13326
|
id: "docx:theme",
|
|
13010
13327
|
kind: "docx/theme",
|
|
13011
13328
|
path: "/props",
|
|
13012
13329
|
themeName: context.themeName,
|
|
13013
13330
|
paletteHexes,
|
|
13331
|
+
typeScalePt,
|
|
13332
|
+
roleSizesPt,
|
|
13014
13333
|
// `heading` and `body` only. A theme also names `mono` and `light`, but
|
|
13015
13334
|
// those paint nothing until a component asks for them — counting an
|
|
13016
13335
|
// unused `Courier New` against a document's family budget would flag a
|
|
@@ -13018,7 +13337,7 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
13018
13337
|
fontFamilies: [
|
|
13019
13338
|
...new Set(
|
|
13020
13339
|
["heading", "body"].flatMap((role) => {
|
|
13021
|
-
const family =
|
|
13340
|
+
const family = asRecord2(
|
|
13022
13341
|
resolved.theme.fonts?.[role]
|
|
13023
13342
|
)?.family;
|
|
13024
13343
|
return typeof family === "string" && family.trim() !== "" ? [family] : [];
|
|
@@ -13054,15 +13373,27 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
13054
13373
|
excerpt: occurrence.match.excerpt
|
|
13055
13374
|
});
|
|
13056
13375
|
});
|
|
13376
|
+
for (const entry of collectDocxTextInventory(resolved.children)) {
|
|
13377
|
+
addFact({ ...entry, generated: authoredPath(entry.path) !== entry.path });
|
|
13378
|
+
}
|
|
13057
13379
|
let previousVisitPath;
|
|
13058
13380
|
let lastFrame;
|
|
13059
13381
|
let flowIndex = 0;
|
|
13060
13382
|
const parentOf = (path3) => path3.slice(0, path3.lastIndexOf("/"));
|
|
13061
13383
|
const visit = (node, path3, page) => {
|
|
13062
|
-
const props =
|
|
13384
|
+
const props = asRecord2(node.props) ?? {};
|
|
13063
13385
|
if (node.name === "table") {
|
|
13064
13386
|
const fact = tableFact(props, path3, page.availableWidthTwips);
|
|
13065
13387
|
if (fact) addFact(fact);
|
|
13388
|
+
for (const size of tableTextSizeFacts(
|
|
13389
|
+
props,
|
|
13390
|
+
authoredPropsAt(path3),
|
|
13391
|
+
path3,
|
|
13392
|
+
typography,
|
|
13393
|
+
page
|
|
13394
|
+
)) {
|
|
13395
|
+
addFact({ ...size, generated: authoredPath(size.path) !== size.path });
|
|
13396
|
+
}
|
|
13066
13397
|
const design = tableDesignFact(
|
|
13067
13398
|
props,
|
|
13068
13399
|
path3,
|
|
@@ -13079,7 +13410,7 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
13079
13410
|
return {
|
|
13080
13411
|
...column,
|
|
13081
13412
|
path: authored,
|
|
13082
|
-
generated: table2 === void 0 ||
|
|
13413
|
+
generated: table2 === void 0 || asRecord2(nodeAtPointer(themed.document, table2))?.name !== "table"
|
|
13083
13414
|
};
|
|
13084
13415
|
})
|
|
13085
13416
|
});
|
|
@@ -13095,7 +13426,7 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
13095
13426
|
addFact({
|
|
13096
13427
|
...fact,
|
|
13097
13428
|
generated: !["chart", "highcharts"].includes(
|
|
13098
|
-
String(
|
|
13429
|
+
String(asRecord2(nodeAtPointer(themed.document, authored))?.name)
|
|
13099
13430
|
),
|
|
13100
13431
|
seriesColorsPath: authoredPath(fact.seriesColorsPath),
|
|
13101
13432
|
...fact.annotation && {
|
|
@@ -13109,7 +13440,7 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
13109
13440
|
}
|
|
13110
13441
|
}
|
|
13111
13442
|
if (node.name === "paragraph" || node.name === "text-box") {
|
|
13112
|
-
const floating =
|
|
13443
|
+
const floating = asRecord2(props.floating);
|
|
13113
13444
|
if (floating) {
|
|
13114
13445
|
const signature = frameSignature(floating);
|
|
13115
13446
|
const chainId = lastFrame !== void 0 && previousVisitPath === lastFrame.path && parentOf(lastFrame.path) === parentOf(path3) && lastFrame.signature === signature ? lastFrame.chainId : `docx:frame-chain:${path3}`;
|
|
@@ -13121,6 +13452,10 @@ function prepareDocxQualityDocument(document, options = {}) {
|
|
|
13121
13452
|
if (node.name === "paragraph" || node.name === "heading") {
|
|
13122
13453
|
const fact = lineBoxFact(node, props, path3, typography, context.document);
|
|
13123
13454
|
if (fact) addFact(fact);
|
|
13455
|
+
if (typeof props.text === "string" && props.text.trim() !== "") {
|
|
13456
|
+
const fact2 = textSizeFact(node, props, path3, typography);
|
|
13457
|
+
if (fact2) addFact({ ...fact2, generated: authoredPath(path3) !== path3 });
|
|
13458
|
+
}
|
|
13124
13459
|
}
|
|
13125
13460
|
if (node.name === "image" || node.name === "visual") {
|
|
13126
13461
|
for (const fact of svgTextFacts(props, path3)) addFact(fact);
|