reamkit 1.16.0 → 1.18.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/esm/core/bidi/segments.js +1 -2
- package/dist/esm/core/converter/project.js +5 -1
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +526 -8
- package/dist/esm/core/drawingml/chart-geometry.d.ts +8 -12
- package/dist/esm/core/drawingml/chart-geometry.js +58 -9
- package/dist/esm/core/drawingml/chart-parser.js +44 -5
- package/dist/esm/core/drawingml/colors.d.ts +1 -1
- package/dist/esm/core/drawingml/colors.js +27 -1
- package/dist/esm/core/drawingml/preset-geometry.js +233 -0
- package/dist/esm/core/drawingml/shape-render.d.ts +12 -0
- package/dist/esm/core/drawingml/shape-render.js +116 -3
- package/dist/esm/core/drawingml/theme-parser.d.ts +10 -0
- package/dist/esm/core/drawingml/theme-parser.js +19 -1
- package/dist/esm/core/font/measure.d.ts +5 -0
- package/dist/esm/core/font/measure.js +21 -1
- package/dist/esm/core/images.d.ts +2 -2
- package/dist/esm/core/images.js +219 -0
- package/dist/esm/core/ir/flow.d.ts +23 -1
- package/dist/esm/core/lzw.d.ts +17 -0
- package/dist/esm/core/lzw.js +83 -0
- package/dist/esm/core/metafile/emf.d.ts +16 -0
- package/dist/esm/core/metafile/emf.js +635 -0
- package/dist/esm/core/metafile/picture.d.ts +106 -0
- package/dist/esm/core/metafile/picture.js +55 -0
- package/dist/esm/core/metafile/wmf.d.ts +9 -0
- package/dist/esm/core/metafile/wmf.js +371 -0
- package/dist/esm/core/numbering/apply.d.ts +5 -3
- package/dist/esm/core/numbering/apply.js +42 -11
- package/dist/esm/core/numbering/index.js +2 -0
- package/dist/esm/core/numbering/state.d.ts +13 -1
- package/dist/esm/core/numbering/state.js +256 -15
- package/dist/esm/core/po-helpers.js +16 -1
- package/dist/esm/core/style-cascade/resolver.js +66 -11
- package/dist/esm/core/style-cascade/table.js +35 -11
- package/dist/esm/core/style-cascade/types.d.ts +42 -1
- package/dist/esm/core/style-cascade/types.js +4 -0
- package/dist/esm/core/tiff.d.ts +20 -0
- package/dist/esm/core/tiff.js +339 -0
- package/dist/esm/core/vector.d.ts +22 -0
- package/dist/esm/excel/print-model.js +4 -2
- package/dist/esm/excel/sheet-to-flow.js +10 -8
- package/dist/esm/excel/worksheet-parser.js +1 -1
- package/dist/esm/html/html-writer.js +20 -5
- package/dist/esm/layout/page-doc.d.ts +107 -4
- package/dist/esm/layout/styled-layout.d.ts +44 -2
- package/dist/esm/layout/styled-layout.js +2330 -283
- package/dist/esm/pdf/shading.js +76 -6
- package/dist/esm/pdf/styled-page-emitter.js +294 -45
- package/dist/esm/pdf/vector-graphics.d.ts +29 -2
- package/dist/esm/pdf/vector-graphics.js +96 -12
- package/dist/esm/pdf-reader/image-decode.js +7 -75
- package/dist/esm/pptx/pptx-reader.js +1 -0
- package/dist/esm/pptx/slide-parser.d.ts +21 -4
- package/dist/esm/pptx/slide-parser.js +86 -23
- package/dist/esm/svg/svg-writer.js +2 -2
- package/dist/esm/word/document-parser.d.ts +96 -7
- package/dist/esm/word/document-parser.js +540 -116
- package/dist/esm/word/docx-reader.js +135 -43
- package/dist/esm/word/docx-writer.js +6 -1
- package/dist/esm/word/drawing-parser.d.ts +58 -5
- package/dist/esm/word/drawing-parser.js +1632 -63
- package/dist/esm/word/index.d.ts +4 -4
- package/dist/esm/word/numbering-parser.d.ts +2 -1
- package/dist/esm/word/numbering-parser.js +107 -21
- package/dist/esm/word/paragraph-properties.d.ts +11 -1
- package/dist/esm/word/paragraph-properties.js +219 -10
- package/dist/esm/word/run-properties.js +45 -1
- package/dist/esm/word/settings-parser.d.ts +24 -0
- package/dist/esm/word/settings-parser.js +31 -5
- package/dist/esm/word/shading.d.ts +11 -0
- package/dist/esm/word/shading.js +64 -0
- package/dist/esm/word/styles-parser.js +8 -2
- package/dist/esm/word/table-parser.d.ts +9 -1
- package/dist/esm/word/table-parser.js +182 -30
- package/package.json +1 -1
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
//#region src/word/shading.ts
|
|
2
|
+
/** §17.18.78 ST_Shd — the pattern densities, as the share of `color` over `fill`. */
|
|
3
|
+
var PATTERN_DENSITY = new Map([
|
|
4
|
+
["solid", 1],
|
|
5
|
+
["pct5", .05],
|
|
6
|
+
["pct10", .1],
|
|
7
|
+
["pct12", .125],
|
|
8
|
+
["pct15", .15],
|
|
9
|
+
["pct20", .2],
|
|
10
|
+
["pct25", .25],
|
|
11
|
+
["pct30", .3],
|
|
12
|
+
["pct35", .35],
|
|
13
|
+
["pct37", .375],
|
|
14
|
+
["pct40", .4],
|
|
15
|
+
["pct45", .45],
|
|
16
|
+
["pct50", .5],
|
|
17
|
+
["pct55", .55],
|
|
18
|
+
["pct60", .6],
|
|
19
|
+
["pct62", .625],
|
|
20
|
+
["pct65", .65],
|
|
21
|
+
["pct70", .7],
|
|
22
|
+
["pct75", .75],
|
|
23
|
+
["pct80", .8],
|
|
24
|
+
["pct85", .85],
|
|
25
|
+
["pct87", .875],
|
|
26
|
+
["pct90", .9],
|
|
27
|
+
["pct95", .95],
|
|
28
|
+
["thinHorzStripe", .25],
|
|
29
|
+
["thinVertStripe", .25],
|
|
30
|
+
["thinDiagStripe", .25],
|
|
31
|
+
["thinHorzCross", .3],
|
|
32
|
+
["thinDiagCross", .3],
|
|
33
|
+
["horzStripe", .4],
|
|
34
|
+
["vertStripe", .4],
|
|
35
|
+
["diagStripe", .4],
|
|
36
|
+
["horzCross", .5],
|
|
37
|
+
["diagCross", .5]
|
|
38
|
+
]);
|
|
39
|
+
var HEX6 = /^[0-9A-Fa-f]{6}$/u;
|
|
40
|
+
/**
|
|
41
|
+
* The colour a `w:shd` actually paints: its `w:fill` background with the
|
|
42
|
+
* pattern colour blended in at the pattern's density. `clear` (and an absent
|
|
43
|
+
* `w:val`) is the fill alone; `nil` paints nothing.
|
|
44
|
+
*
|
|
45
|
+
* @param val `w:val` — the pattern.
|
|
46
|
+
* @param color `w:color` — the pattern's own colour (`auto` ⇒ black).
|
|
47
|
+
* @param fill `w:fill` — the background (`auto` ⇒ white).
|
|
48
|
+
* @returns The 6-hex colour to paint, or `undefined` when nothing is painted.
|
|
49
|
+
*/
|
|
50
|
+
function shadingFillHex(val, color, fill) {
|
|
51
|
+
if (val === "nil") return void 0;
|
|
52
|
+
const bg = fill !== void 0 && HEX6.test(fill) ? fill.toUpperCase() : void 0;
|
|
53
|
+
const density = val !== void 0 ? PATTERN_DENSITY.get(val) : void 0;
|
|
54
|
+
if (density === void 0) return bg;
|
|
55
|
+
return blend(color !== void 0 && HEX6.test(color) ? color.toUpperCase() : "000000", bg ?? "FFFFFF", density);
|
|
56
|
+
}
|
|
57
|
+
/** `a` over `b` at `t` (0..1), per channel. */
|
|
58
|
+
function blend(a, b, t) {
|
|
59
|
+
const ch = (hex, i) => parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
60
|
+
const mix = (i) => Math.round(ch(a, i) * t + ch(b, i) * (1 - t)).toString(16).padStart(2, "0");
|
|
61
|
+
return (mix(0) + mix(1) + mix(2)).toUpperCase();
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
export { shadingFillHex };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { eighthPtToPt, twipsToPt } from "../core/ir/units.js";
|
|
2
2
|
import { EMPTY_STYLE_SHEET } from "../core/style-cascade/resolver.js";
|
|
3
3
|
import "../core/style-cascade/index.js";
|
|
4
|
-
import { asArray, asElement, getAttr, getVal } from "./xml-helpers.js";
|
|
4
|
+
import { asArray, asElement, getAttr, getVal, parseIntAttr } from "./xml-helpers.js";
|
|
5
5
|
import { parseRunProperties } from "./run-properties.js";
|
|
6
6
|
import { parseParagraphProperties } from "./paragraph-properties.js";
|
|
7
7
|
import { XMLParser } from "fast-xml-parser";
|
|
@@ -119,12 +119,17 @@ function parseTableStyleLayer(el) {
|
|
|
119
119
|
const tcPr = asElement(el["w:tcPr"]);
|
|
120
120
|
const borders = parseFlatBorders(tblPr ? asElement(tblPr["w:tblBorders"]) : void 0) ?? parseFlatBorders(tcPr ? asElement(tcPr["w:tcBorders"]) : void 0);
|
|
121
121
|
const cellMargins = parseFlatCellMargins(tblPr ? asElement(tblPr["w:tblCellMar"]) : void 0);
|
|
122
|
+
const tblInd = tblPr ? asElement(tblPr["w:tblInd"]) : void 0;
|
|
123
|
+
const indW = tblInd ? parseIntAttr(tblInd, "w") : void 0;
|
|
124
|
+
const indType = tblInd ? getAttr(tblInd, "type") : void 0;
|
|
125
|
+
const indentPt = indW !== void 0 && (indType === void 0 || indType === "dxa") ? twipsToPt(indW) : void 0;
|
|
122
126
|
const shading = parseFlatShading(tcPr ? tcPr["w:shd"] : void 0);
|
|
123
127
|
const runProperties = parseRunProperties(el["w:rPr"]);
|
|
124
128
|
const paragraphProperties = parseParagraphProperties(el["w:pPr"]);
|
|
125
129
|
const layer = {
|
|
126
130
|
...borders ? { borders } : {},
|
|
127
131
|
...cellMargins ? { cellMargins } : {},
|
|
132
|
+
...indentPt !== void 0 ? { indentPt } : {},
|
|
128
133
|
...shading ? { shading } : {},
|
|
129
134
|
...Object.keys(runProperties).length > 0 ? { runProperties } : {},
|
|
130
135
|
...Object.keys(paragraphProperties).length > 0 ? { paragraphProperties } : {}
|
|
@@ -137,7 +142,8 @@ var FLAT_BORDER_STYLES = new Set([
|
|
|
137
142
|
"double",
|
|
138
143
|
"thick",
|
|
139
144
|
"dotted",
|
|
140
|
-
"dashed"
|
|
145
|
+
"dashed",
|
|
146
|
+
"dashSmallGap"
|
|
141
147
|
]);
|
|
142
148
|
function parseFlatBorder(node) {
|
|
143
149
|
const el = asElement(node);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Table } from '../core/document-model/index.js';
|
|
1
|
+
import { CellBorders, Table } from '../core/document-model/index.js';
|
|
2
2
|
import { PoNode } from '../core/po-helpers.js';
|
|
3
3
|
import { ParseContext } from './document-parser.js';
|
|
4
4
|
/**
|
|
@@ -13,3 +13,11 @@ import { ParseContext } from './document-parser.js';
|
|
|
13
13
|
* @returns The parsed table.
|
|
14
14
|
*/
|
|
15
15
|
export declare function parseTable(tbl: PoNode, ctx?: ParseContext): Table;
|
|
16
|
+
/**
|
|
17
|
+
* A `w:tcBorders` / `w:tblBorders` / §17.6.10 `w:pgBorders` element: the rule on
|
|
18
|
+
* each edge. Every one of them is spelled the same way.
|
|
19
|
+
*
|
|
20
|
+
* @param node The borders element, or `undefined`.
|
|
21
|
+
* @returns The edges that name a rule, or `undefined` when none do.
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseBorders(node: PoNode | undefined): CellBorders | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { eighthPtToPt, twipsToPt } from "../core/ir/units.js";
|
|
2
|
-
import { poAttr, poChildren, poChildrenWith, poFirstChild, poIntAttr, poToggle, poVal } from "../core/po-helpers.js";
|
|
3
|
-
import { DEFAULT_PARSE_CONTEXT, parseBodyElements } from "./document-parser.js";
|
|
1
|
+
import { eighthPtToPt, pt, twipsToPt } from "../core/ir/units.js";
|
|
2
|
+
import { poAttr, poChildren, poChildrenWith, poFirstChild, poIntAttr, poIs, poToggle, poVal } from "../core/po-helpers.js";
|
|
3
|
+
import { DEFAULT_PARSE_CONTEXT, parseBodyElements, sdtRunProperties } from "./document-parser.js";
|
|
4
4
|
//#region src/word/table-parser.ts
|
|
5
5
|
var BORDER_STYLES = new Set([
|
|
6
6
|
"none",
|
|
@@ -8,7 +8,23 @@ var BORDER_STYLES = new Set([
|
|
|
8
8
|
"double",
|
|
9
9
|
"thick",
|
|
10
10
|
"dotted",
|
|
11
|
-
"dashed"
|
|
11
|
+
"dashed",
|
|
12
|
+
"dashSmallGap"
|
|
13
|
+
]);
|
|
14
|
+
var MULTI_LINE_BORDERS = new Set([
|
|
15
|
+
"triple",
|
|
16
|
+
"doubleWave",
|
|
17
|
+
"thinThickSmallGap",
|
|
18
|
+
"thickThinSmallGap",
|
|
19
|
+
"thinThickThinSmallGap",
|
|
20
|
+
"thinThickMediumGap",
|
|
21
|
+
"thickThinMediumGap",
|
|
22
|
+
"thinThickThinMediumGap",
|
|
23
|
+
"thinThickLargeGap",
|
|
24
|
+
"thickThinLargeGap",
|
|
25
|
+
"thinThickThinLargeGap",
|
|
26
|
+
"outset",
|
|
27
|
+
"inset"
|
|
12
28
|
]);
|
|
13
29
|
var WIDTH_TYPES = new Set([
|
|
14
30
|
"auto",
|
|
@@ -21,6 +37,34 @@ var HEIGHT_RULES = new Set([
|
|
|
21
37
|
"atLeast",
|
|
22
38
|
"exact"
|
|
23
39
|
]);
|
|
40
|
+
function parseTablePosition(tblpPr) {
|
|
41
|
+
const horz = poAttr(tblpPr, "horzAnchor");
|
|
42
|
+
const vert = poAttr(tblpPr, "vertAnchor");
|
|
43
|
+
const hRel = horz === "page" ? "page" : horz === "margin" ? "margin" : "column";
|
|
44
|
+
const vRel = vert === "page" ? "page" : vert === "margin" ? "margin" : "paragraph";
|
|
45
|
+
const xSpec = poAttr(tblpPr, "tblpXSpec");
|
|
46
|
+
const align = xSpec === "center" ? "center" : xSpec === "right" ? "right" : xSpec === "left" ? "left" : void 0;
|
|
47
|
+
const x = poIntAttr(tblpPr, "tblpX");
|
|
48
|
+
const y = poIntAttr(tblpPr, "tblpY");
|
|
49
|
+
const dist = (name) => twipsToPt(poIntAttr(tblpPr, name) ?? 0);
|
|
50
|
+
return {
|
|
51
|
+
wrap: "square",
|
|
52
|
+
posH: {
|
|
53
|
+
relativeFrom: hRel,
|
|
54
|
+
...align ? { align } : { offsetPt: twipsToPt(x ?? 0) }
|
|
55
|
+
},
|
|
56
|
+
posV: {
|
|
57
|
+
relativeFrom: vRel,
|
|
58
|
+
offsetPt: twipsToPt(y ?? 0)
|
|
59
|
+
},
|
|
60
|
+
wrapDist: {
|
|
61
|
+
topPt: dist("topFromText"),
|
|
62
|
+
bottomPt: dist("bottomFromText"),
|
|
63
|
+
leftPt: dist("leftFromText"),
|
|
64
|
+
rightPt: dist("rightFromText")
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
24
68
|
/**
|
|
25
69
|
* Parse a `w:tbl` (ECMA-376 Part 1 §17.4) in preserveOrder shape into the typed
|
|
26
70
|
* {@link Table} model: its properties (style ref, look, width, layout, borders,
|
|
@@ -36,26 +80,53 @@ function parseTable(tbl, ctx = DEFAULT_PARSE_CONTEXT) {
|
|
|
36
80
|
const properties = parseTableProperties(poFirstChild(tbl, "w:tblPr"));
|
|
37
81
|
const grid = parseTableGrid(poFirstChild(tbl, "w:tblGrid"));
|
|
38
82
|
const draftRows = [];
|
|
39
|
-
for (const tr of
|
|
83
|
+
for (const tr of poChildrenThroughSdt(tbl, "w:tr")) {
|
|
84
|
+
if (isDeletedRow(tr)) continue;
|
|
85
|
+
draftRows.push(parseTableRow(tr, ctx));
|
|
86
|
+
}
|
|
40
87
|
const roles = resolveMergeRoles(draftRows.map((r) => r.cells));
|
|
88
|
+
const rows = draftRows.map((draft, rowIdx) => ({
|
|
89
|
+
properties: draft.properties,
|
|
90
|
+
cells: draft.cells.map((d, cellIdx) => {
|
|
91
|
+
const merge = roles[rowIdx][cellIdx];
|
|
92
|
+
return merge ? {
|
|
93
|
+
...d.cell,
|
|
94
|
+
properties: {
|
|
95
|
+
...d.cell.properties,
|
|
96
|
+
merge
|
|
97
|
+
}
|
|
98
|
+
} : d.cell;
|
|
99
|
+
})
|
|
100
|
+
}));
|
|
101
|
+
if (poFirstChild(poFirstChild(tbl, "w:tblPr"), "w:bidiVisual")) return {
|
|
102
|
+
properties,
|
|
103
|
+
grid: [...grid].reverse(),
|
|
104
|
+
rows: rows.map((row) => ({
|
|
105
|
+
...row,
|
|
106
|
+
cells: [...row.cells].reverse()
|
|
107
|
+
}))
|
|
108
|
+
};
|
|
41
109
|
return {
|
|
42
110
|
properties,
|
|
43
111
|
grid,
|
|
44
|
-
rows
|
|
45
|
-
properties: draft.properties,
|
|
46
|
-
cells: draft.cells.map((d, cellIdx) => {
|
|
47
|
-
const merge = roles[rowIdx][cellIdx];
|
|
48
|
-
return merge ? {
|
|
49
|
-
...d.cell,
|
|
50
|
-
properties: {
|
|
51
|
-
...d.cell.properties,
|
|
52
|
-
merge
|
|
53
|
-
}
|
|
54
|
-
} : d.cell;
|
|
55
|
-
})
|
|
56
|
-
}))
|
|
112
|
+
rows
|
|
57
113
|
};
|
|
58
114
|
}
|
|
115
|
+
function poChildrenThroughSdt(node, tag) {
|
|
116
|
+
return childrenThroughSdt(node, tag).map((c) => c.node);
|
|
117
|
+
}
|
|
118
|
+
function childrenThroughSdt(node, tag) {
|
|
119
|
+
const out = [];
|
|
120
|
+
for (const child of poChildren(node)) if (poIs(child, tag)) out.push({ node: child });
|
|
121
|
+
else if (poIs(child, "w:sdt")) {
|
|
122
|
+
const props = sdtRunProperties(child);
|
|
123
|
+
for (const inner of poChildrenWith(poFirstChild(child, "w:sdtContent"), tag)) out.push({
|
|
124
|
+
node: inner,
|
|
125
|
+
...props ? { sdtRunProps: props } : {}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return out;
|
|
129
|
+
}
|
|
59
130
|
function resolveMergeRoles(rows) {
|
|
60
131
|
const out = rows.map((r) => new Array(r.length).fill(void 0));
|
|
61
132
|
const colSlots = /* @__PURE__ */ new Map();
|
|
@@ -109,11 +180,23 @@ function parseTableProperties(tblPr) {
|
|
|
109
180
|
else if (w !== void 0) out.widthPt = twipsToPt(w);
|
|
110
181
|
if (type && WIDTH_TYPES.has(type)) out.widthType = type;
|
|
111
182
|
}
|
|
183
|
+
const tblInd = poFirstChild(tblPr, "w:tblInd");
|
|
184
|
+
if (tblInd) {
|
|
185
|
+
const w = poIntAttr(tblInd, "w");
|
|
186
|
+
const type = poAttr(tblInd, "type");
|
|
187
|
+
if (w !== void 0 && (type === void 0 || type === "dxa")) out.indentPt = twipsToPt(w);
|
|
188
|
+
}
|
|
189
|
+
const tblpPr = poFirstChild(tblPr, "w:tblpPr");
|
|
190
|
+
if (tblpPr) out.float = parseTablePosition(tblpPr);
|
|
112
191
|
const tblLayout = poFirstChild(tblPr, "w:tblLayout");
|
|
113
192
|
if (tblLayout) {
|
|
114
193
|
const t = poAttr(tblLayout, "type");
|
|
115
194
|
if (t === "fixed" || t === "auto") out.layout = t;
|
|
116
195
|
}
|
|
196
|
+
const tblJc = poVal(poFirstChild(tblPr, "w:jc"));
|
|
197
|
+
if (tblJc === "center") out.alignment = "center";
|
|
198
|
+
else if (tblJc === "right" || tblJc === "end") out.alignment = "right";
|
|
199
|
+
else if (tblJc === "left" || tblJc === "start") out.alignment = "left";
|
|
117
200
|
const borders = parseBorders(poFirstChild(tblPr, "w:tblBorders"));
|
|
118
201
|
if (borders) out.borders = borders;
|
|
119
202
|
const margins = parseCellMargins(poFirstChild(tblPr, "w:tblCellMar"));
|
|
@@ -154,15 +237,61 @@ function parseTableGrid(tblGrid) {
|
|
|
154
237
|
}
|
|
155
238
|
return cols;
|
|
156
239
|
}
|
|
240
|
+
/**
|
|
241
|
+
* §17.13.5.15 — whether a row was deleted, under the reader's accept-all
|
|
242
|
+
* reading of tracked changes (the same one that drops `w:del` runs).
|
|
243
|
+
*
|
|
244
|
+
* Two spellings. `w:trPr/w:del` says it outright. The other is how a producer
|
|
245
|
+
* writes a row whose CONTENT was taken away: every paragraph mark in it carries
|
|
246
|
+
* `w:del` or `w:moveFrom`, which deletes the mark, and a row whose every mark
|
|
247
|
+
* is gone is a row that is gone. TC-table-DnD-move.docx moves a table that way,
|
|
248
|
+
* and accepting only the runs left a ghost of empty bordered rows behind where
|
|
249
|
+
* Word and LibreOffice leave nothing.
|
|
250
|
+
*
|
|
251
|
+
* @param tr The `w:tr` element.
|
|
252
|
+
* @returns Whether to drop the row.
|
|
253
|
+
*/
|
|
254
|
+
function isDeletedRow(tr) {
|
|
255
|
+
const trPr = poFirstChild(tr, "w:trPr");
|
|
256
|
+
if (trPr && (poFirstChild(trPr, "w:del") ?? poFirstChild(trPr, "w:moveFrom"))) return true;
|
|
257
|
+
const cells = poChildrenThroughSdt(tr, "w:tc");
|
|
258
|
+
if (cells.length === 0) return false;
|
|
259
|
+
let marks = 0;
|
|
260
|
+
for (const tc of cells) {
|
|
261
|
+
for (const p of poChildrenWith(tc, "w:p")) {
|
|
262
|
+
const rPr = poFirstChild(poFirstChild(p, "w:pPr"), "w:rPr");
|
|
263
|
+
if (!rPr || !(poFirstChild(rPr, "w:del") ?? poFirstChild(rPr, "w:moveFrom"))) return false;
|
|
264
|
+
marks++;
|
|
265
|
+
}
|
|
266
|
+
if (poChildrenWith(tc, "w:tbl").length > 0) return false;
|
|
267
|
+
}
|
|
268
|
+
return marks > 0;
|
|
269
|
+
}
|
|
157
270
|
function parseTableRow(tr, ctx) {
|
|
158
271
|
const properties = parseRowProperties(poFirstChild(tr, "w:trPr"));
|
|
159
272
|
const cells = [];
|
|
160
|
-
for (const
|
|
273
|
+
for (const { node, sdtRunProps } of childrenThroughSdt(tr, "w:tc")) cells.push(parseTableCell(node, ctx, sdtRunProps));
|
|
161
274
|
return {
|
|
162
275
|
properties,
|
|
163
276
|
cells
|
|
164
277
|
};
|
|
165
278
|
}
|
|
279
|
+
function parseRowConditional(cnf) {
|
|
280
|
+
if (!cnf) return void 0;
|
|
281
|
+
const bits = poAttr(cnf, "val");
|
|
282
|
+
const bit = (i) => bits?.[i] === "1";
|
|
283
|
+
const flag = (name) => {
|
|
284
|
+
const v = poAttr(cnf, name);
|
|
285
|
+
return v === void 0 ? void 0 : v === "1" || v === "true" || v === "on";
|
|
286
|
+
};
|
|
287
|
+
const firstRow = flag("firstRow") ?? bit(0);
|
|
288
|
+
const lastRow = flag("lastRow") ?? bit(1);
|
|
289
|
+
if (!firstRow && !lastRow) return void 0;
|
|
290
|
+
return {
|
|
291
|
+
...firstRow ? { firstRow } : {},
|
|
292
|
+
...lastRow ? { lastRow } : {}
|
|
293
|
+
};
|
|
294
|
+
}
|
|
166
295
|
function parseRowProperties(trPr) {
|
|
167
296
|
if (!trPr) return {};
|
|
168
297
|
const out = {};
|
|
@@ -172,17 +301,22 @@ function parseRowProperties(trPr) {
|
|
|
172
301
|
const rule = poAttr(trHeight, "hRule");
|
|
173
302
|
if (val !== void 0) out.height = twipsToPt(val);
|
|
174
303
|
if (rule && HEIGHT_RULES.has(rule)) out.heightRule = rule;
|
|
304
|
+
else if (val !== void 0) out.heightRule = "atLeast";
|
|
175
305
|
}
|
|
176
306
|
if (poFirstChild(trPr, "w:cantSplit")) out.cantSplit = poToggle(poFirstChild(trPr, "w:cantSplit")) ?? true;
|
|
177
307
|
if (poFirstChild(trPr, "w:tblHeader")) out.isHeader = poToggle(poFirstChild(trPr, "w:tblHeader")) ?? true;
|
|
308
|
+
const before = poIntAttr(poFirstChild(trPr, "w:gridBefore"), "val");
|
|
309
|
+
if (before !== void 0 && before > 0) out.gridBefore = before;
|
|
310
|
+
const cnf = parseRowConditional(poFirstChild(trPr, "w:cnfStyle"));
|
|
311
|
+
if (cnf) out.conditional = cnf;
|
|
178
312
|
return out;
|
|
179
313
|
}
|
|
180
|
-
function parseTableCell(tc, ctx) {
|
|
314
|
+
function parseTableCell(tc, ctx, sdtRunProps) {
|
|
181
315
|
const { properties, vMerge } = parseCellProperties(poFirstChild(tc, "w:tcPr"));
|
|
182
316
|
return {
|
|
183
317
|
cell: {
|
|
184
318
|
properties,
|
|
185
|
-
content: parseBodyElements(poChildren(tc), ctx)
|
|
319
|
+
content: parseBodyElements(poChildren(tc), ctx, void 0, sdtRunProps)
|
|
186
320
|
},
|
|
187
321
|
...vMerge ? { vMerge } : {}
|
|
188
322
|
};
|
|
@@ -194,7 +328,12 @@ function parseCellProperties(tcPr) {
|
|
|
194
328
|
const tcW = poFirstChild(tcPr, "w:tcW");
|
|
195
329
|
if (tcW) {
|
|
196
330
|
const w = poIntAttr(tcW, "w");
|
|
197
|
-
|
|
331
|
+
const type = poAttr(tcW, "type");
|
|
332
|
+
if (type === "pct" || type === "dxa" || type === "auto" || type === "nil") out.widthType = type;
|
|
333
|
+
if (w !== void 0) {
|
|
334
|
+
if (type === "pct") out.widthFraction = w / 5e3;
|
|
335
|
+
else if (type !== "auto" && type !== "nil") out.width = twipsToPt(w);
|
|
336
|
+
}
|
|
198
337
|
}
|
|
199
338
|
const gridSpan = poFirstChild(tcPr, "w:gridSpan");
|
|
200
339
|
if (gridSpan) {
|
|
@@ -212,11 +351,21 @@ function parseCellProperties(tcPr) {
|
|
|
212
351
|
const fill = poAttr(shd, "fill");
|
|
213
352
|
if (fill && fill !== "auto" && /^[0-9A-Fa-f]{6}$/.test(fill)) out.shading = { colorHex: fill.toUpperCase() };
|
|
214
353
|
}
|
|
354
|
+
const vAlign = poVal(poFirstChild(tcPr, "w:vAlign"));
|
|
355
|
+
if (vAlign === "center" || vAlign === "bottom" || vAlign === "top") out.verticalAlign = vAlign;
|
|
356
|
+
if (poFirstChild(tcPr, "w:hideMark")) out.hideMark = true;
|
|
215
357
|
return {
|
|
216
358
|
properties: out,
|
|
217
359
|
...rawVMerge ? { vMerge: rawVMerge } : {}
|
|
218
360
|
};
|
|
219
361
|
}
|
|
362
|
+
/**
|
|
363
|
+
* A `w:tcBorders` / `w:tblBorders` / §17.6.10 `w:pgBorders` element: the rule on
|
|
364
|
+
* each edge. Every one of them is spelled the same way.
|
|
365
|
+
*
|
|
366
|
+
* @param node The borders element, or `undefined`.
|
|
367
|
+
* @returns The edges that name a rule, or `undefined` when none do.
|
|
368
|
+
*/
|
|
220
369
|
function parseBorders(node) {
|
|
221
370
|
if (!node) return void 0;
|
|
222
371
|
const out = {};
|
|
@@ -236,12 +385,15 @@ function parseBorders(node) {
|
|
|
236
385
|
}
|
|
237
386
|
function parseBorder(node) {
|
|
238
387
|
if (!node) return void 0;
|
|
239
|
-
const
|
|
240
|
-
if (!
|
|
388
|
+
const raw = poVal(node);
|
|
389
|
+
if (!raw) return void 0;
|
|
390
|
+
const val = raw === "nil" ? "none" : BORDER_STYLES.has(raw) ? raw : MULTI_LINE_BORDERS.has(raw) ? "double" : "single";
|
|
241
391
|
const sz = poIntAttr(node, "sz");
|
|
242
392
|
const color = poAttr(node, "color");
|
|
243
393
|
const out = { style: val };
|
|
244
|
-
if (sz !== void 0) out.width = eighthPtToPt(sz);
|
|
394
|
+
if (sz !== void 0) out.width = eighthPtToPt(MULTI_LINE_BORDERS.has(raw) ? sz * 3 : sz);
|
|
395
|
+
const space = poIntAttr(node, "space");
|
|
396
|
+
if (space !== void 0) out.spacePt = pt(space);
|
|
245
397
|
if (color && color !== "auto" && /^[0-9A-Fa-f]{6}$/.test(color)) out.colorHex = color.toUpperCase();
|
|
246
398
|
return out;
|
|
247
399
|
}
|
|
@@ -252,11 +404,11 @@ function parseCellMargins(node) {
|
|
|
252
404
|
const bottom = poIntAttr(poFirstChild(node, "w:bottom"), "w");
|
|
253
405
|
const left = poIntAttr(poFirstChild(node, "w:left") ?? poFirstChild(node, "w:start"), "w");
|
|
254
406
|
const right = poIntAttr(poFirstChild(node, "w:right") ?? poFirstChild(node, "w:end"), "w");
|
|
255
|
-
if (top !== void 0) out.top = twipsToPt(top);
|
|
256
|
-
if (bottom !== void 0) out.bottom = twipsToPt(bottom);
|
|
257
|
-
if (left !== void 0) out.left = twipsToPt(left);
|
|
258
|
-
if (right !== void 0) out.right = twipsToPt(right);
|
|
407
|
+
if (top !== void 0) out.top = twipsToPt(Math.max(0, top));
|
|
408
|
+
if (bottom !== void 0) out.bottom = twipsToPt(Math.max(0, bottom));
|
|
409
|
+
if (left !== void 0) out.left = twipsToPt(Math.max(0, left));
|
|
410
|
+
if (right !== void 0) out.right = twipsToPt(Math.max(0, right));
|
|
259
411
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
260
412
|
}
|
|
261
413
|
//#endregion
|
|
262
|
-
export { parseTable };
|
|
414
|
+
export { parseBorders, parseTable };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reamkit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.0",
|
|
4
4
|
"description": "Ream — convert DOCX, XLSX, PPTX and PDF to PDF, SVG, HTML, DOCX and XLSX, built from scratch on the ECMA-376 and ISO 32000 specifications. Parse once, convert anywhere.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Alex Krassavin <info@reamkit.dev>",
|