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.
Files changed (76) hide show
  1. package/dist/esm/core/bidi/segments.js +1 -2
  2. package/dist/esm/core/converter/project.js +5 -1
  3. package/dist/esm/core/document-model/index.d.ts +1 -1
  4. package/dist/esm/core/document-model/types.d.ts +526 -8
  5. package/dist/esm/core/drawingml/chart-geometry.d.ts +8 -12
  6. package/dist/esm/core/drawingml/chart-geometry.js +58 -9
  7. package/dist/esm/core/drawingml/chart-parser.js +44 -5
  8. package/dist/esm/core/drawingml/colors.d.ts +1 -1
  9. package/dist/esm/core/drawingml/colors.js +27 -1
  10. package/dist/esm/core/drawingml/preset-geometry.js +233 -0
  11. package/dist/esm/core/drawingml/shape-render.d.ts +12 -0
  12. package/dist/esm/core/drawingml/shape-render.js +116 -3
  13. package/dist/esm/core/drawingml/theme-parser.d.ts +10 -0
  14. package/dist/esm/core/drawingml/theme-parser.js +19 -1
  15. package/dist/esm/core/font/measure.d.ts +5 -0
  16. package/dist/esm/core/font/measure.js +21 -1
  17. package/dist/esm/core/images.d.ts +2 -2
  18. package/dist/esm/core/images.js +219 -0
  19. package/dist/esm/core/ir/flow.d.ts +23 -1
  20. package/dist/esm/core/lzw.d.ts +17 -0
  21. package/dist/esm/core/lzw.js +83 -0
  22. package/dist/esm/core/metafile/emf.d.ts +16 -0
  23. package/dist/esm/core/metafile/emf.js +635 -0
  24. package/dist/esm/core/metafile/picture.d.ts +106 -0
  25. package/dist/esm/core/metafile/picture.js +55 -0
  26. package/dist/esm/core/metafile/wmf.d.ts +9 -0
  27. package/dist/esm/core/metafile/wmf.js +371 -0
  28. package/dist/esm/core/numbering/apply.d.ts +5 -3
  29. package/dist/esm/core/numbering/apply.js +42 -11
  30. package/dist/esm/core/numbering/index.js +2 -0
  31. package/dist/esm/core/numbering/state.d.ts +13 -1
  32. package/dist/esm/core/numbering/state.js +256 -15
  33. package/dist/esm/core/po-helpers.js +16 -1
  34. package/dist/esm/core/style-cascade/resolver.js +66 -11
  35. package/dist/esm/core/style-cascade/table.js +35 -11
  36. package/dist/esm/core/style-cascade/types.d.ts +42 -1
  37. package/dist/esm/core/style-cascade/types.js +4 -0
  38. package/dist/esm/core/tiff.d.ts +20 -0
  39. package/dist/esm/core/tiff.js +339 -0
  40. package/dist/esm/core/vector.d.ts +22 -0
  41. package/dist/esm/excel/print-model.js +4 -2
  42. package/dist/esm/excel/sheet-to-flow.js +10 -8
  43. package/dist/esm/excel/worksheet-parser.js +1 -1
  44. package/dist/esm/html/html-writer.js +20 -5
  45. package/dist/esm/layout/page-doc.d.ts +107 -4
  46. package/dist/esm/layout/styled-layout.d.ts +44 -2
  47. package/dist/esm/layout/styled-layout.js +2330 -283
  48. package/dist/esm/pdf/shading.js +76 -6
  49. package/dist/esm/pdf/styled-page-emitter.js +294 -45
  50. package/dist/esm/pdf/vector-graphics.d.ts +29 -2
  51. package/dist/esm/pdf/vector-graphics.js +96 -12
  52. package/dist/esm/pdf-reader/image-decode.js +7 -75
  53. package/dist/esm/pptx/pptx-reader.js +1 -0
  54. package/dist/esm/pptx/slide-parser.d.ts +21 -4
  55. package/dist/esm/pptx/slide-parser.js +86 -23
  56. package/dist/esm/svg/svg-writer.js +2 -2
  57. package/dist/esm/word/document-parser.d.ts +96 -7
  58. package/dist/esm/word/document-parser.js +540 -116
  59. package/dist/esm/word/docx-reader.js +135 -43
  60. package/dist/esm/word/docx-writer.js +6 -1
  61. package/dist/esm/word/drawing-parser.d.ts +58 -5
  62. package/dist/esm/word/drawing-parser.js +1632 -63
  63. package/dist/esm/word/index.d.ts +4 -4
  64. package/dist/esm/word/numbering-parser.d.ts +2 -1
  65. package/dist/esm/word/numbering-parser.js +107 -21
  66. package/dist/esm/word/paragraph-properties.d.ts +11 -1
  67. package/dist/esm/word/paragraph-properties.js +219 -10
  68. package/dist/esm/word/run-properties.js +45 -1
  69. package/dist/esm/word/settings-parser.d.ts +24 -0
  70. package/dist/esm/word/settings-parser.js +31 -5
  71. package/dist/esm/word/shading.d.ts +11 -0
  72. package/dist/esm/word/shading.js +64 -0
  73. package/dist/esm/word/styles-parser.js +8 -2
  74. package/dist/esm/word/table-parser.d.ts +9 -1
  75. package/dist/esm/word/table-parser.js +182 -30
  76. package/package.json +1 -1
@@ -1,11 +1,37 @@
1
1
  //#region src/core/numbering/state.ts
2
2
  /**
3
+ * §17.9.27 — the levels an INSTANCE actually numbers by: its abstract
4
+ * definition's, with any `w:lvlOverride/w:lvl` shadowing them. Cached per
5
+ * instance, since every list paragraph asks for it.
6
+ *
7
+ * @param numbering The parsed numbering definitions.
8
+ * @param instance The `w:num` the paragraph refers to.
9
+ * @returns The effective abstract numbering, or `undefined` when the instance
10
+ * names one that is not there.
11
+ */
12
+ function effectiveAbstract(numbering, instance) {
13
+ const base = numbering.abstractNums.get(instance.abstractNumId);
14
+ if (!base || !instance.levelOverrides || instance.levelOverrides.size === 0) return base;
15
+ const hit = effectiveCache.get(instance);
16
+ if (hit) return hit;
17
+ const levels = new Map(base.levels);
18
+ for (const [ilvl, lvl] of instance.levelOverrides) levels.set(ilvl, lvl);
19
+ const merged = {
20
+ id: base.id,
21
+ levels
22
+ };
23
+ effectiveCache.set(instance, merged);
24
+ return merged;
25
+ }
26
+ var effectiveCache = /* @__PURE__ */ new WeakMap();
27
+ /**
3
28
  * Mutable list-counter state for one numbering scope (e.g. a body or a single
4
29
  * header/footer band). Tracks a counter per list per level and advances them as
5
30
  * paragraphs are visited in order.
6
31
  */
7
32
  var NumberingState = class {
8
33
  counters = /* @__PURE__ */ new Map();
34
+ restarted = /* @__PURE__ */ new Set();
9
35
  /**
10
36
  * Advance the counter for `ref` (resetting deeper levels) and format its
11
37
  * marker text. The first hit at a level seeds it from the level's `start`;
@@ -19,19 +45,27 @@ var NumberingState = class {
19
45
  resolveMarker(numbering, ref) {
20
46
  const instance = numbering.numInstances.get(ref.numId);
21
47
  if (!instance) return null;
22
- const abstractNum = numbering.abstractNums.get(instance.abstractNumId);
48
+ const abstractNum = effectiveAbstract(numbering, instance);
23
49
  if (!abstractNum) return null;
24
50
  const level = abstractNum.levels.get(ref.ilvl);
25
51
  if (!level) return null;
26
- let arr = this.counters.get(ref.numId);
52
+ let arr = this.counters.get(instance.abstractNumId);
27
53
  if (!arr) {
28
- arr = new Array(9).fill(0);
29
- this.counters.set(ref.numId, arr);
54
+ arr = new Array(9).fill(void 0);
55
+ this.counters.set(instance.abstractNumId, arr);
56
+ }
57
+ for (let k = ref.ilvl + 1; k < arr.length; k++) arr[k] = void 0;
58
+ const startAt = (i, fallback) => instance.startOverrides?.get(i) ?? fallback ?? 0;
59
+ const restartKey = `${ref.numId}:${String(ref.ilvl)}`;
60
+ const override = instance.startOverrides?.get(ref.ilvl);
61
+ if (override !== void 0 && !this.restarted.has(restartKey)) {
62
+ this.restarted.add(restartKey);
63
+ arr[ref.ilvl] = override;
64
+ } else {
65
+ const current = arr[ref.ilvl];
66
+ arr[ref.ilvl] = current === void 0 ? startAt(ref.ilvl, level.start) : current + 1;
30
67
  }
31
- for (let k = ref.ilvl + 1; k < arr.length; k++) arr[k] = 0;
32
- if (arr[ref.ilvl] === 0) arr[ref.ilvl] = level.start;
33
- else arr[ref.ilvl] += 1;
34
- return formatLevelMarker(abstractNum, level, arr);
68
+ return formatLevelMarker(abstractNum, level, arr.map((n, i) => n ?? startAt(i, abstractNum.levels.get(i)?.start)));
35
69
  }
36
70
  };
37
71
  function formatLevelMarker(abstractNum, currentLevel, counters) {
@@ -40,20 +74,227 @@ function formatLevelMarker(abstractNum, currentLevel, counters) {
40
74
  const lvlIdx = Number(n) - 1;
41
75
  const level = abstractNum.levels.get(lvlIdx);
42
76
  const counter = counters[lvlIdx] ?? 0;
43
- return formatCounter(level?.format ?? "decimal", counter);
77
+ return formatCounter(currentLevel.isLegal === true && lvlIdx !== currentLevel.ilvl ? "decimal" : level?.format ?? "decimal", counter);
44
78
  });
45
79
  }
46
80
  function formatCounter(format, n) {
47
- if (n <= 0) return "";
81
+ if (n < 0) return "";
48
82
  switch (format) {
49
83
  case "decimal": return String(n);
50
- case "lowerLetter": return toLetters(n).toLowerCase();
51
- case "upperLetter": return toLetters(n);
52
- case "lowerRoman": return toRoman(n).toLowerCase();
53
- case "upperRoman": return toRoman(n);
84
+ case "decimalZero": return n < 10 ? `0${String(n)}` : String(n);
85
+ case "decimalFullWidth": return digitByDigit(n, FULL_WIDTH_DIGITS);
86
+ case "ordinal": return `${String(n)}${ordinalSuffix(n)}`;
87
+ case "lowerLetter": return n === 0 ? "" : toLetters(n).toLowerCase();
88
+ case "upperLetter": return n === 0 ? "" : toLetters(n);
89
+ case "lowerRoman": return n === 0 ? "" : toRoman(n).toLowerCase();
90
+ case "upperRoman": return n === 0 ? "" : toRoman(n);
91
+ case "ideographTraditional": return n === 0 ? "" : n <= HEAVENLY_STEMS.length ? HEAVENLY_STEMS[n - 1] : String(n);
92
+ case "ideographZodiac": return n === 0 ? "" : n <= EARTHLY_BRANCHES.length ? EARTHLY_BRANCHES[n - 1] : String(n);
93
+ case "ideographDigital":
94
+ case "koreanDigital2": return digitByDigit(n, IDEOGRAPH_DIGITS);
95
+ case "ideographLegalTraditional": return counting(n, LEGAL_DIGITS, LEGAL_UNITS, false);
96
+ case "chineseCounting":
97
+ case "chineseCountingThousand":
98
+ case "japaneseCounting":
99
+ case "koreanCounting":
100
+ case "taiwaneseCounting":
101
+ case "taiwaneseCountingThousand": return counting(n, IDEOGRAPH_DIGITS, COUNTING_UNITS, true);
102
+ case "hebrew1": return n === 0 ? "" : toHebrewNumeral(n);
103
+ case "hebrew2": return n === 0 ? "" : HEBREW_ALPHABET[(n - 1) % HEBREW_ALPHABET.length];
104
+ case "decimalEnclosedCircle": return n >= 1 && n <= 20 ? String.fromCodePoint(9311 + n) : String(n);
105
+ case "chicago":
106
+ if (n < 1) return "";
107
+ return CHICAGO_MARKS[(n - 1) % CHICAGO_MARKS.length].repeat(Math.floor((n - 1) / CHICAGO_MARKS.length) + 1);
54
108
  default: return "";
55
109
  }
56
110
  }
111
+ var HEBREW_ONES = [
112
+ "",
113
+ "א",
114
+ "ב",
115
+ "ג",
116
+ "ד",
117
+ "ה",
118
+ "ו",
119
+ "ז",
120
+ "ח",
121
+ "ט"
122
+ ];
123
+ var HEBREW_TENS = [
124
+ "",
125
+ "י",
126
+ "כ",
127
+ "ל",
128
+ "מ",
129
+ "נ",
130
+ "ס",
131
+ "ע",
132
+ "פ",
133
+ "צ"
134
+ ];
135
+ var HEBREW_HUNDREDS = [
136
+ "",
137
+ "ק",
138
+ "ר",
139
+ "ש",
140
+ "ת"
141
+ ];
142
+ var HEBREW_ALPHABET = [
143
+ "א",
144
+ "ב",
145
+ "ג",
146
+ "ד",
147
+ "ה",
148
+ "ו",
149
+ "ז",
150
+ "ח",
151
+ "ט",
152
+ "י",
153
+ "כ",
154
+ "ל",
155
+ "מ",
156
+ "נ",
157
+ "ס",
158
+ "ע",
159
+ "פ",
160
+ "צ",
161
+ "ק",
162
+ "ר",
163
+ "ש",
164
+ "ת"
165
+ ];
166
+ function toHebrewNumeral(n) {
167
+ let rest = n;
168
+ let out = "";
169
+ while (rest >= 400) {
170
+ out += "ת";
171
+ rest -= 400;
172
+ }
173
+ out += HEBREW_HUNDREDS[Math.floor(rest / 100)] ?? "";
174
+ rest %= 100;
175
+ if (rest === 15 || rest === 16) out += rest === 15 ? "טו" : "טז";
176
+ else {
177
+ out += HEBREW_TENS[Math.floor(rest / 10)] ?? "";
178
+ out += HEBREW_ONES[rest % 10] ?? "";
179
+ }
180
+ return out;
181
+ }
182
+ var CHICAGO_MARKS = [
183
+ "*",
184
+ "†",
185
+ "‡",
186
+ "§"
187
+ ];
188
+ var IDEOGRAPH_DIGITS = [
189
+ "零",
190
+ "一",
191
+ "二",
192
+ "三",
193
+ "四",
194
+ "五",
195
+ "六",
196
+ "七",
197
+ "八",
198
+ "九"
199
+ ];
200
+ var COUNTING_UNITS = [
201
+ "",
202
+ "十",
203
+ "百",
204
+ "千"
205
+ ];
206
+ var LEGAL_DIGITS = [
207
+ "零",
208
+ "壹",
209
+ "貳",
210
+ "參",
211
+ "肆",
212
+ "伍",
213
+ "陸",
214
+ "柒",
215
+ "捌",
216
+ "玖"
217
+ ];
218
+ var LEGAL_UNITS = [
219
+ "",
220
+ "拾",
221
+ "佰",
222
+ "仟"
223
+ ];
224
+ var HEAVENLY_STEMS = [
225
+ "甲",
226
+ "乙",
227
+ "丙",
228
+ "丁",
229
+ "戊",
230
+ "己",
231
+ "庚",
232
+ "辛",
233
+ "壬",
234
+ "癸"
235
+ ];
236
+ var EARTHLY_BRANCHES = [
237
+ "子",
238
+ "丑",
239
+ "寅",
240
+ "卯",
241
+ "辰",
242
+ "巳",
243
+ "午",
244
+ "未",
245
+ "申",
246
+ "酉",
247
+ "戌",
248
+ "亥"
249
+ ];
250
+ var FULL_WIDTH_DIGITS = [
251
+ "0",
252
+ "1",
253
+ "2",
254
+ "3",
255
+ "4",
256
+ "5",
257
+ "6",
258
+ "7",
259
+ "8",
260
+ "9"
261
+ ];
262
+ /** Each decimal digit as its own glyph — no units, no elision (10 → 一零). */
263
+ function digitByDigit(n, digits) {
264
+ return String(n).split("").map((d) => digits[Number(d)] ?? d).join("");
265
+ }
266
+ /**
267
+ * The counting systems: digits carrying place units (十百千). `elideTen` drops
268
+ * the leading 一 of the tens place, which is what the plain counting systems do
269
+ * (11 → 十一) and the formal one does not (11 → 壹拾壹). Above the units the
270
+ * table covers, plain digits — a list marker never gets that far.
271
+ */
272
+ function counting(n, digits, units, elideTen) {
273
+ if (n >= 10 ** units.length) return String(n);
274
+ const ds = String(n).split("").map(Number);
275
+ let out = "";
276
+ ds.forEach((d, i) => {
277
+ const place = ds.length - 1 - i;
278
+ if (d === 0) {
279
+ if (out.length > 0 && !out.endsWith(digits[0]) && ds.slice(i).some((x) => x > 0)) out += digits[0];
280
+ return;
281
+ }
282
+ const head = elideTen && d === 1 && place === 1 && i === 0 ? "" : digits[d];
283
+ out += head + units[place];
284
+ });
285
+ return out;
286
+ }
287
+ /** `1st`, `2nd`, `3rd`, `4th` — the English ordinal suffixes (§17.18.59). */
288
+ function ordinalSuffix(n) {
289
+ const two = n % 100;
290
+ if (two >= 11 && two <= 13) return "th";
291
+ switch (n % 10) {
292
+ case 1: return "st";
293
+ case 2: return "nd";
294
+ case 3: return "rd";
295
+ default: return "th";
296
+ }
297
+ }
57
298
  function toLetters(n) {
58
299
  let s = "";
59
300
  let v = n;
@@ -95,4 +336,4 @@ function normalizeBullet(lvlText) {
95
336
  return lvlText;
96
337
  }
97
338
  //#endregion
98
- export { NumberingState };
339
+ export { NumberingState, effectiveAbstract, formatLevelMarker };
@@ -65,7 +65,22 @@ function poIntAttr(node, name) {
65
65
  const v = poAttr(node, name);
66
66
  if (v === void 0) return void 0;
67
67
  const n = Number(v);
68
- return Number.isFinite(n) ? n : void 0;
68
+ if (Number.isFinite(n)) return n;
69
+ return universalMeasureTwips(v);
70
+ }
71
+ var MEASURE_TWIPS = new Map([
72
+ ["pt", 20],
73
+ ["pc", 240],
74
+ ["pi", 240],
75
+ ["in", 1440],
76
+ ["cm", 1440 / 2.54],
77
+ ["mm", 144 / 2.54]
78
+ ]);
79
+ function universalMeasureTwips(raw) {
80
+ const m = /^\s*(-?[0-9]+(?:\.[0-9]+)?)(pt|pc|pi|in|cm|mm)\s*$/iu.exec(raw);
81
+ if (!m) return void 0;
82
+ const per = MEASURE_TWIPS.get(m[2].toLowerCase());
83
+ return per === void 0 ? void 0 : Number(m[1]) * per;
69
84
  }
70
85
  /** Shorthand for the `val` attribute (`@w:val`/…). */
71
86
  function poVal(node) {
@@ -38,8 +38,10 @@ function resolveRunProperties(runDirect, paragraphDirect, sheet) {
38
38
  }
39
39
  function computeRunProperties(runDirect, paragraphDirect, sheet) {
40
40
  let acc = mergeRun(DEFAULT_RESOLVED_RUN, sheet.defaultRunProperties);
41
- if (paragraphDirect.styleId) {
42
- const chain = resolveStyleChain(paragraphDirect.styleId, sheet);
41
+ if (paragraphDirect.inheritedRun) acc = mergeRun(acc, paragraphDirect.inheritedRun);
42
+ const styleId = paragraphDirect.styleId ?? defaultParagraphStyleId(sheet);
43
+ if (styleId) {
44
+ const chain = resolveStyleChain(styleId, sheet);
43
45
  acc = mergeRun(acc, chain.rPr);
44
46
  }
45
47
  if (runDirect.styleId) {
@@ -71,12 +73,27 @@ function resolveParagraphProperties(paragraphDirect, sheet) {
71
73
  }
72
74
  function computeParagraphProperties(paragraphDirect, sheet) {
73
75
  let acc = mergePar(DEFAULT_RESOLVED_PARAGRAPH, sheet.defaultParagraphProperties);
74
- if (paragraphDirect.styleId) {
75
- const chain = resolveStyleChain(paragraphDirect.styleId, sheet);
76
+ if (paragraphDirect.tableStyle ?? paragraphDirect.inheritedRun) acc = mergePar(acc, {
77
+ ...paragraphDirect.tableStyle,
78
+ ...paragraphDirect.inheritedRun ? { runProperties: paragraphDirect.inheritedRun } : {}
79
+ });
80
+ const styleId = paragraphDirect.styleId ?? defaultParagraphStyleId(sheet);
81
+ if (styleId) {
82
+ const chain = resolveStyleChain(styleId, sheet);
76
83
  acc = mergePar(acc, chain.pPr);
77
84
  }
78
85
  return mergePar(acc, paragraphDirect);
79
86
  }
87
+ /** The id of the `w:default="1"` paragraph style, cached per sheet. */
88
+ var defaultParagraphStyleCache = /* @__PURE__ */ new WeakMap();
89
+ function defaultParagraphStyleId(sheet) {
90
+ const hit = defaultParagraphStyleCache.get(sheet);
91
+ if (hit !== void 0) return hit ?? void 0;
92
+ let found = null;
93
+ for (const style of sheet.styles.values()) if (style.type === "paragraph" && style.isDefault) found = style.id;
94
+ defaultParagraphStyleCache.set(sheet, found);
95
+ return found ?? void 0;
96
+ }
80
97
  function resolveStyleChain(styleId, sheet) {
81
98
  const chain = [];
82
99
  const visited = /* @__PURE__ */ new Set();
@@ -108,40 +125,72 @@ function mergeRun(base, override) {
108
125
  bold: override.bold ?? base.bold,
109
126
  italic: override.italic ?? base.italic,
110
127
  underline: override.underline ?? base.underline,
128
+ ...override.underlineColorHex ?? base.underlineColorHex ? { underlineColorHex: override.underlineColorHex ?? base.underlineColorHex } : {},
111
129
  strike: override.strike ?? base.strike,
130
+ caps: override.caps ?? base.caps,
131
+ smallCaps: override.smallCaps ?? base.smallCaps,
112
132
  fontSizePt: override.fontSizePt ?? base.fontSizePt,
113
133
  colorHex: override.colorHex ?? base.colorHex,
114
134
  fontFamily: override.fontFamily ?? base.fontFamily,
115
135
  verticalAlign: override.verticalAlign ?? base.verticalAlign,
116
136
  rtl: override.rtl ?? base.rtl,
117
- ...lang !== void 0 ? { lang } : {}
137
+ ...lang !== void 0 ? { lang } : {},
138
+ ...(override.shadingColorHex ?? base.shadingColorHex) !== void 0 ? { shadingColorHex: override.shadingColorHex ?? base.shadingColorHex } : {},
139
+ ...(override.letterSpacingPt ?? base.letterSpacingPt) !== void 0 ? { letterSpacingPt: override.letterSpacingPt ?? base.letterSpacingPt } : {}
118
140
  };
119
141
  }
120
142
  function mergePar(base, override) {
121
143
  const outlineLevel = override.outlineLevel ?? base.outlineLevel;
122
144
  const styleId = override.styleId ?? base.styleId;
123
- const numbering = override.numbering ?? base.numbering;
145
+ const numbering = override.numbering ?? (override.numberingLevel !== void 0 && base.numbering !== void 0 ? {
146
+ ...base.numbering,
147
+ ilvl: override.numberingLevel
148
+ } : base.numbering);
149
+ const runProperties = override.runProperties ?? base.runProperties;
150
+ const frame = override.frame ?? base.frame;
151
+ const sectionBreak = override.sectionBreak ?? base.sectionBreak;
152
+ const textDirection = override.textDirection ?? base.textDirection;
153
+ const snapToGrid = override.snapToGrid ?? base.snapToGrid;
124
154
  return {
125
155
  alignment: override.alignment ?? base.alignment,
126
- spacingBefore: override.spacingBefore ?? base.spacingBefore,
127
- spacingAfter: override.spacingAfter ?? base.spacingAfter,
156
+ spacingBefore: override.spacingBeforeAuto ?? override.spacingBefore ?? base.spacingBefore,
157
+ spacingAfter: override.spacingAfterAuto ?? override.spacingAfter ?? base.spacingAfter,
128
158
  spacingLine: override.spacingLine ?? base.spacingLine,
129
159
  spacingLineRule: override.spacingLineRule ?? base.spacingLineRule,
130
160
  indentLeft: override.indentLeft ?? base.indentLeft,
131
161
  indentRight: override.indentRight ?? base.indentRight,
132
162
  indentFirstLine: override.indentFirstLine ?? base.indentFirstLine,
133
163
  pageBreakBefore: override.pageBreakBefore ?? base.pageBreakBefore,
164
+ contextualSpacing: override.contextualSpacing ?? base.contextualSpacing,
165
+ tabs: override.tabs ?? base.tabs,
134
166
  bidi: override.bidi ?? base.bidi,
167
+ ...override.borders ?? base.borders ? { borders: override.borders ?? base.borders } : {},
168
+ ...override.shading ?? base.shading ? { shading: override.shading ?? base.shading } : {},
135
169
  ...outlineLevel !== void 0 ? { outlineLevel } : {},
136
170
  ...styleId !== void 0 ? { styleId } : {},
137
- ...numbering !== void 0 ? { numbering } : {}
171
+ ...numbering !== void 0 ? { numbering } : {},
172
+ ...runProperties !== void 0 ? { runProperties } : {},
173
+ ...frame !== void 0 ? { frame } : {},
174
+ ...sectionBreak !== void 0 ? { sectionBreak } : {},
175
+ ...textDirection !== void 0 ? { textDirection } : {},
176
+ ...snapToGrid !== void 0 ? { snapToGrid } : {}
138
177
  };
139
178
  }
140
179
  function mergeRunPartial(base, override) {
141
180
  return copyDefined(base, override);
142
181
  }
143
182
  function mergeParPartial(base, override) {
144
- return copyDefined(base, override);
183
+ const out = copyDefined(base, override);
184
+ if (override.numbering === void 0 && override.numberingLevel !== void 0) {
185
+ if (base.numbering !== void 0) return {
186
+ ...out,
187
+ numbering: {
188
+ ...base.numbering,
189
+ ilvl: override.numberingLevel
190
+ }
191
+ };
192
+ }
193
+ return out;
145
194
  }
146
195
  function copyDefined(base, override) {
147
196
  const out = { ...base };
@@ -188,7 +237,13 @@ function resolveBodyStyles(body, sheet) {
188
237
  const visit = (el) => {
189
238
  if (el.kind === "paragraph") visitParagraph(el.paragraph);
190
239
  else if (el.kind === "table") for (const row of el.table.rows) for (const cell of row.cells) for (const child of cell.content) visit(child);
191
- else if (el.kind === "shape" && el.shape.text) for (const child of el.shape.text.content) visit(child);
240
+ else if (el.kind === "shape") {
241
+ const shapeText = (sh) => {
242
+ for (const child of sh.text?.content ?? []) visit(child);
243
+ for (const member of sh.children ?? []) shapeText(member.shape);
244
+ };
245
+ shapeText(el.shape);
246
+ }
192
247
  };
193
248
  for (const el of body) visit(el);
194
249
  return body;
@@ -22,8 +22,10 @@ function applyTableStyle(table, sheet) {
22
22
  const folded = foldTableStyleChain(styleId, sheet);
23
23
  if (!folded) return;
24
24
  const tp = table.properties;
25
+ const directBorders = tp.borders;
25
26
  if (!tp.borders && folded.base.borders) tp.borders = folded.base.borders;
26
27
  if (!tp.defaultCellMargins && folded.base.cellMargins) tp.defaultCellMargins = folded.base.cellMargins;
28
+ if (tp.indentPt === void 0 && folded.base.indentPt !== void 0) tp.indentPt = folded.base.indentPt;
27
29
  const look = table.properties.look ?? {};
28
30
  const rows = table.rows;
29
31
  const colCount = Math.max(table.grid.length, ...rows.map((r) => r.cells.reduce((s, c) => s + (c.properties.colSpan ?? 1), 0)));
@@ -33,8 +35,8 @@ function applyTableStyle(table, sheet) {
33
35
  for (const cell of row.cells) {
34
36
  const span = cell.properties.colSpan ?? 1;
35
37
  const layer = cellLayer(folded, look, {
36
- firstRow: r === 0,
37
- lastRow: r === rows.length - 1,
38
+ firstRow: r === 0 || row.properties.conditional?.firstRow === true,
39
+ lastRow: r === rows.length - 1 || row.properties.conditional?.lastRow === true,
38
40
  firstCol: colStart === 0,
39
41
  lastCol: colStart + span >= colCount,
40
42
  rowBand: bandIndex(r, look.firstRow === true, folded.rowBandSize),
@@ -42,20 +44,34 @@ function applyTableStyle(table, sheet) {
42
44
  noHBand: look.noHBand === true,
43
45
  noVBand: look.noVBand === true
44
46
  });
47
+ const pos = {
48
+ firstRow: r === 0 || row.properties.conditional?.firstRow === true,
49
+ lastRow: r === rows.length - 1 || row.properties.conditional?.lastRow === true,
50
+ firstCol: colStart === 0,
51
+ lastCol: colStart + span >= colCount
52
+ };
45
53
  colStart += span;
46
54
  if (!layer) continue;
47
- applyLayerToCell(cell, layer);
55
+ applyLayerToCell(cell, layer, directBorders, pos);
48
56
  }
49
57
  }
50
58
  }
51
- function applyLayerToCell(tableCell, layer) {
59
+ function applyLayerToCell(tableCell, layer, directBorders, pos) {
52
60
  const cell = tableCell;
53
61
  if (layer.shading && !cell.properties.shading) cell.properties.shading = layer.shading;
54
62
  if (layer.cellMargins && !cell.properties.margins) cell.properties.margins = layer.cellMargins;
55
63
  if (layer.borders) {
56
64
  const own = cell.properties.borders ?? {};
65
+ const fromStyle = { ...layer.borders };
66
+ if (directBorders) {
67
+ const stated = (side, outer) => (outer ? directBorders[side] : directBorders[side === "top" || side === "bottom" ? "insideH" : "insideV"]) !== void 0;
68
+ if (stated("top", pos.firstRow)) delete fromStyle.top;
69
+ if (stated("bottom", pos.lastRow)) delete fromStyle.bottom;
70
+ if (stated("left", pos.firstCol)) delete fromStyle.left;
71
+ if (stated("right", pos.lastCol)) delete fromStyle.right;
72
+ }
57
73
  const merged = {
58
- ...layer.borders,
74
+ ...fromStyle,
59
75
  ...definedOnly(own)
60
76
  };
61
77
  cell.properties.borders = merged;
@@ -64,12 +80,18 @@ function applyLayerToCell(tableCell, layer) {
64
80
  if (el.kind !== "paragraph") continue;
65
81
  const p = el.paragraph;
66
82
  if (layer.paragraphProperties) p.properties = {
67
- ...layer.paragraphProperties,
68
- ...definedOnly(p.properties)
83
+ ...p.properties,
84
+ tableStyle: {
85
+ ...p.properties.tableStyle,
86
+ ...layer.paragraphProperties
87
+ }
69
88
  };
70
- if (layer.runProperties) for (const run of p.runs) run.properties = {
71
- ...layer.runProperties,
72
- ...definedOnly(run.properties)
89
+ if (layer.runProperties) p.properties = {
90
+ ...p.properties,
91
+ inheritedRun: {
92
+ ...p.properties.inheritedRun,
93
+ ...layer.runProperties
94
+ }
73
95
  };
74
96
  }
75
97
  }
@@ -79,7 +101,8 @@ function bandIndex(index, skipFirst, bandSize) {
79
101
  return Math.floor(adjusted / Math.max(1, bandSize));
80
102
  }
81
103
  function cellLayer(folded, look, pos) {
82
- const layers = [folded.base];
104
+ const { borders: _tableWide, ...withoutBorders } = folded.base;
105
+ const layers = [withoutBorders];
83
106
  const cond = (t) => folded.conditions.get(t);
84
107
  if (!pos.noVBand && pos.colBand >= 0) layers.push(pos.colBand % 2 === 0 ? cond("band1Vert") : cond("band2Vert"));
85
108
  if (!pos.noHBand && pos.rowBand >= 0) layers.push(pos.rowBand % 2 === 0 ? cond("band1Horz") : cond("band2Horz"));
@@ -145,6 +168,7 @@ function mergeLayer(base, override) {
145
168
  ...base.cellMargins,
146
169
  ...definedOnly(override.cellMargins ?? {})
147
170
  } } : {},
171
+ ...(override.indentPt ?? base.indentPt) !== void 0 ? { indentPt: override.indentPt ?? base.indentPt } : {},
148
172
  ...override.shading ?? base.shading ? { shading: override.shading ?? base.shading } : {},
149
173
  ...override.runProperties ?? base.runProperties ? { runProperties: {
150
174
  ...base.runProperties,
@@ -1,4 +1,4 @@
1
- import { Alignment, FontFamilyMap, NumberingReference, UnderlineStyle, VerticalAlign } from '../document-model/index.js';
1
+ import { Alignment, CellBorders, CellShading, FontFamilyMap, FrameProperties, NumberingReference, RunProperties, TabStop, UnderlineStyle, VerticalAlign } from '../document-model/index.js';
2
2
  import { Pt } from '../ir/index.js';
3
3
  /**
4
4
  * A run's fully-resolved properties: every field required because the cascade
@@ -9,7 +9,13 @@ export interface ResolvedRunProperties {
9
9
  readonly bold: boolean;
10
10
  readonly italic: boolean;
11
11
  readonly underline: UnderlineStyle;
12
+ /** §17.3.2.40 `w:u @w:color` — the underline's own colour; absent means the text's. */
13
+ readonly underlineColorHex?: string;
12
14
  readonly strike: boolean;
15
+ /** §17.3.2.5 `w:caps` — displayed in capitals. */
16
+ readonly caps: boolean;
17
+ /** §17.3.2.33 `w:smallCaps` — displayed in capitals, the lower case smaller. */
18
+ readonly smallCaps: boolean;
13
19
  readonly fontSizePt: Pt;
14
20
  readonly colorHex: string;
15
21
  readonly fontFamily: FontFamilyMap;
@@ -20,6 +26,10 @@ export interface ResolvedRunProperties {
20
26
  * specifies one; consumed by the tagged-PDF per-element `/Lang`, never layout.
21
27
  */
22
28
  readonly lang?: string;
29
+ /** §17.3.2.32 — the background painted behind the run's glyphs. */
30
+ readonly shadingColorHex?: string;
31
+ /** §17.3.2.35 — extra space between the run's characters, in points. */
32
+ readonly letterSpacingPt?: Pt;
23
33
  }
24
34
  /**
25
35
  * A paragraph's fully-resolved properties: every field required, the cascade
@@ -35,6 +45,14 @@ export interface ResolvedParagraphProperties {
35
45
  readonly indentRight: Pt;
36
46
  readonly indentFirstLine: Pt;
37
47
  readonly pageBreakBefore: boolean;
48
+ /** §17.3.1.9 — drop the space between this paragraph and a same-styled neighbour. */
49
+ readonly contextualSpacing: boolean;
50
+ /** §17.3.1.37 — the paragraph's tab stops, in ascending position order. */
51
+ readonly tabs: ReadonlyArray<TabStop>;
52
+ /** §17.3.1.24 `w:pBdr` — rules drawn around the paragraph. */
53
+ readonly borders?: CellBorders;
54
+ /** §17.3.1.31 `w:pPr/w:shd` — the paragraph's own background fill. */
55
+ readonly shading?: CellShading;
38
56
  readonly bidi: boolean;
39
57
  /**
40
58
  * ECMA-376 §17.3.1.20 — resolved outline level (0–8). Undefined = body text.
@@ -46,11 +64,34 @@ export interface ResolvedParagraphProperties {
46
64
  * detection when a style lacks an explicit outline level.
47
65
  */
48
66
  readonly styleId?: string;
67
+ /**
68
+ * §17.3.1.29 `w:pPr/w:rPr` — the formatting of the paragraph MARK. An empty
69
+ * paragraph is as tall as its mark, so dropping this on resolution collapsed
70
+ * a 36pt empty cell to a line of body text (conditionalstyles-tbllook.docx).
71
+ */
72
+ readonly runProperties?: RunProperties;
73
+ /** §17.3.1.11 — the paragraph floats as a text frame. */
74
+ readonly frame?: FrameProperties;
75
+ /** §17.3.1.41 — which way the paragraph's lines run (`lrTb` is not recorded). */
76
+ readonly textDirection?: 'btLr' | 'tbRl';
77
+ /** §17.3.1.32 — whether these lines stand on the section's grid. Absent ⇒ they do. */
78
+ readonly snapToGrid?: boolean;
79
+ /**
80
+ * §17.6.17 — the paragraph mark carries the section break, so a paragraph
81
+ * with no content of its own prints nothing at all.
82
+ */
83
+ readonly sectionBreak?: boolean;
49
84
  /**
50
85
  * §17.9 list reference, carried through for tagged-PDF list structure
51
86
  * (L/LI nesting) — markers themselves are materialized by `applyNumbering`.
52
87
  */
53
88
  readonly numbering?: NumberingReference;
89
+ /**
90
+ * §17.6.5 — the line pitch of the section's document grid, in points. Not a
91
+ * property of the paragraph at all: the section it falls in owns it, and the
92
+ * layout stamps it here so a line knows the grid it stands on.
93
+ */
94
+ readonly gridLinePitchPt?: Pt;
54
95
  }
55
96
  /** Word's empty-document run defaults (used when `docDefaults` is absent). */
56
97
  export declare const DEFAULT_RESOLVED_RUN: ResolvedRunProperties;
@@ -6,6 +6,8 @@ var DEFAULT_RESOLVED_RUN = {
6
6
  italic: false,
7
7
  underline: "none",
8
8
  strike: false,
9
+ caps: false,
10
+ smallCaps: false,
9
11
  fontSizePt: halfPtToPt(22),
10
12
  colorHex: "000000",
11
13
  fontFamily: {},
@@ -23,6 +25,8 @@ var DEFAULT_RESOLVED_PARAGRAPH = {
23
25
  indentRight: twipsToPt(0),
24
26
  indentFirstLine: twipsToPt(0),
25
27
  pageBreakBefore: false,
28
+ contextualSpacing: false,
29
+ tabs: [],
26
30
  bidi: false
27
31
  };
28
32
  //#endregion