reamkit 1.31.0 → 1.32.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 (83) hide show
  1. package/README.md +10 -0
  2. package/dist/esm/core/bidi/index.d.ts +10 -0
  3. package/dist/esm/core/bidi/index.js +18 -2
  4. package/dist/esm/core/converter/facade.js +10 -5
  5. package/dist/esm/core/converter/project.js +1 -0
  6. package/dist/esm/core/converter/ream.js +17 -6
  7. package/dist/esm/core/converter/sheet-images.d.ts +17 -0
  8. package/dist/esm/core/converter/sheet-images.js +33 -0
  9. package/dist/esm/core/document-model/index.d.ts +1 -1
  10. package/dist/esm/core/document-model/types.d.ts +112 -0
  11. package/dist/esm/core/drawingml/chart-geometry.d.ts +21 -8
  12. package/dist/esm/core/drawingml/chart-geometry.js +198 -108
  13. package/dist/esm/core/drawingml/chart-parser.js +73 -2
  14. package/dist/esm/core/drawingml/colors.d.ts +6 -0
  15. package/dist/esm/core/drawingml/colors.js +23 -3
  16. package/dist/esm/core/drawingml/shape-render.d.ts +3 -1
  17. package/dist/esm/core/drawingml/shape-render.js +4 -2
  18. package/dist/esm/core/font/measure.d.ts +9 -0
  19. package/dist/esm/core/font/measure.js +9 -1
  20. package/dist/esm/core/fonts/families.js +4 -2
  21. package/dist/esm/core/fonts/scripts.js +4 -2
  22. package/dist/esm/core/ir/flow.d.ts +6 -0
  23. package/dist/esm/core/ir/sheet.d.ts +43 -0
  24. package/dist/esm/core/number-format.js +16 -11
  25. package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
  26. package/dist/esm/core/spreadsheet-model/types.d.ts +96 -0
  27. package/dist/esm/core/style-cascade/resolver.js +4 -2
  28. package/dist/esm/excel/column-bands.d.ts +39 -6
  29. package/dist/esm/excel/column-bands.js +41 -17
  30. package/dist/esm/excel/comments-parser.js +19 -0
  31. package/dist/esm/excel/conditional-format.d.ts +7 -3
  32. package/dist/esm/excel/conditional-format.js +77 -39
  33. package/dist/esm/excel/formula/context.d.ts +18 -0
  34. package/dist/esm/excel/formula/eval.js +51 -0
  35. package/dist/esm/excel/formula/index.d.ts +2 -2
  36. package/dist/esm/excel/formula/lexer.d.ts +1 -1
  37. package/dist/esm/excel/formula/lexer.js +41 -0
  38. package/dist/esm/excel/formula/parser.d.ts +25 -0
  39. package/dist/esm/excel/formula/parser.js +95 -0
  40. package/dist/esm/excel/print-model.d.ts +38 -1
  41. package/dist/esm/excel/print-model.js +522 -80
  42. package/dist/esm/excel/shared-strings-parser.d.ts +9 -0
  43. package/dist/esm/excel/shared-strings-parser.js +11 -1
  44. package/dist/esm/excel/sheet-drawing.d.ts +38 -2
  45. package/dist/esm/excel/sheet-drawing.js +47 -13
  46. package/dist/esm/excel/sheet-shape-parser.d.ts +6 -2
  47. package/dist/esm/excel/sheet-shape-parser.js +18 -6
  48. package/dist/esm/excel/sheet-to-flow.d.ts +17 -0
  49. package/dist/esm/excel/sheet-to-flow.js +434 -47
  50. package/dist/esm/excel/styles-parser.d.ts +9 -0
  51. package/dist/esm/excel/styles-parser.js +80 -26
  52. package/dist/esm/excel/table-parser.js +5 -0
  53. package/dist/esm/excel/table-style-presets.d.ts +26 -0
  54. package/dist/esm/excel/table-style-presets.js +1555 -0
  55. package/dist/esm/excel/table-style.d.ts +13 -0
  56. package/dist/esm/excel/table-style.js +75 -0
  57. package/dist/esm/excel/tint.d.ts +10 -0
  58. package/dist/esm/excel/tint.js +75 -0
  59. package/dist/esm/excel/vml-drawing.d.ts +41 -3
  60. package/dist/esm/excel/vml-drawing.js +143 -10
  61. package/dist/esm/excel/worksheet-parser.js +89 -15
  62. package/dist/esm/excel/xls/biff-reader.js +10 -2
  63. package/dist/esm/excel/xlsx-reader.js +195 -14
  64. package/dist/esm/excel/xlsx-writer.js +8 -7
  65. package/dist/esm/html/html-writer.js +202 -20
  66. package/dist/esm/layout/fit-pages.d.ts +11 -0
  67. package/dist/esm/layout/fit-pages.js +86 -0
  68. package/dist/esm/layout/line-paint.d.ts +58 -0
  69. package/dist/esm/layout/line-paint.js +107 -0
  70. package/dist/esm/layout/page-doc.d.ts +51 -0
  71. package/dist/esm/layout/page-doc.js +141 -1
  72. package/dist/esm/layout/styled-layout.d.ts +7 -0
  73. package/dist/esm/layout/styled-layout.js +274 -51
  74. package/dist/esm/layout/turned-section.js +14 -2
  75. package/dist/esm/markdown/markdown-writer.js +17 -6
  76. package/dist/esm/pdf/styled-page-emitter.js +49 -71
  77. package/dist/esm/pdf/styled-page-renderer.js +1 -1
  78. package/dist/esm/pdf-reader/font.js +3 -3
  79. package/dist/esm/svg/svg-text.d.ts +58 -0
  80. package/dist/esm/svg/svg-text.js +322 -0
  81. package/dist/esm/svg/svg-writer.js +135 -71
  82. package/dist/esm/word/docx-writer.js +11 -2
  83. package/package.json +5 -1
@@ -148,6 +148,25 @@ var DEFAULT_THEME_PALETTE = new Map([
148
148
  ["hlink", "0563C1"],
149
149
  ["folHlink", "954F72"]
150
150
  ]);
151
+ /**
152
+ * The Office 2023 theme's palette — what Excel colours a workbook that carries
153
+ * no theme part with. Its own PDF of theme slots 0…9 in such a workbook
154
+ * (2026-10-01) paints exactly these: accent1 is 156082, not 2013's 4472C4.
155
+ */
156
+ var OFFICE_2023_THEME_PALETTE = new Map([
157
+ ["dk1", "000000"],
158
+ ["lt1", "FFFFFF"],
159
+ ["dk2", "0E2841"],
160
+ ["lt2", "E8E8E8"],
161
+ ["accent1", "156082"],
162
+ ["accent2", "E97132"],
163
+ ["accent3", "196B24"],
164
+ ["accent4", "0F9ED5"],
165
+ ["accent5", "A02B93"],
166
+ ["accent6", "4EA72E"],
167
+ ["hlink", "467886"],
168
+ ["folHlink", "96607D"]
169
+ ]);
151
170
  var DEFAULT_SCHEME_ALIAS = {
152
171
  tx1: "dk1",
153
172
  bg1: "lt1",
@@ -284,8 +303,9 @@ var SYSTEM_COLORS = new Map([
284
303
  function resolveColorNode(c, resolveColor) {
285
304
  if (poIs(c, "a:sysClr")) {
286
305
  const last = poAttr(c, "lastClr");
287
- if (last && /^[0-9A-Fa-f]{6}$/.test(last)) return last.toUpperCase();
288
- return SYSTEM_COLORS.get(poAttr(c, "val") ?? "");
306
+ const hex = last && /^[0-9A-Fa-f]{6}$/.test(last) ? last.toUpperCase() : SYSTEM_COLORS.get(poAttr(c, "val") ?? "");
307
+ const sysMods = readColorMods(c);
308
+ return hex !== void 0 && sysMods.length > 0 ? applyColorMods(hex, sysMods) : hex;
289
309
  }
290
310
  if (poIs(c, "a:prstClr")) {
291
311
  const hex = PRESET_COLORS.get((poAttr(c, "val") ?? "").toLowerCase());
@@ -305,4 +325,4 @@ function resolveColorNode(c, resolveColor) {
305
325
  } : raw);
306
326
  }
307
327
  //#endregion
308
- export { DEFAULT_SCHEME_ALIAS, DEFAULT_THEME_PALETTE, applyColorMods, defaultColorResolver, makeColorResolver, placeholderColors, readColorMods, resolveColorNode };
328
+ export { DEFAULT_SCHEME_ALIAS, DEFAULT_THEME_PALETTE, OFFICE_2023_THEME_PALETTE, defaultColorResolver, makeColorResolver, placeholderColors, readColorMods, resolveColorNode };
@@ -30,7 +30,9 @@ export declare function gradientToSolid(gradient: ShapeGradient): string;
30
30
  * An SVG `<linearGradient>` / `<radialGradient>` definition for a gradient fill
31
31
  * (EP16), shared by the SVG and HTML writers. The linear vector is expressed in
32
32
  * `objectBoundingBox` space; the angle is negated because the shape's own path
33
- * transform flips y (local y-up → page y-down).
33
+ * transform flips y (local y-up → page y-down) — and a radial centre, given in
34
+ * fractions down from the box's top, is measured up from its bottom for the
35
+ * same reason.
34
36
  *
35
37
  * @param id The gradient element id (referenced by `fill="url(#id)"`).
36
38
  * @param g The gradient fill.
@@ -51,7 +51,9 @@ function gradientToSolid(gradient) {
51
51
  * An SVG `<linearGradient>` / `<radialGradient>` definition for a gradient fill
52
52
  * (EP16), shared by the SVG and HTML writers. The linear vector is expressed in
53
53
  * `objectBoundingBox` space; the angle is negated because the shape's own path
54
- * transform flips y (local y-up → page y-down).
54
+ * transform flips y (local y-up → page y-down) — and a radial centre, given in
55
+ * fractions down from the box's top, is measured up from its bottom for the
56
+ * same reason.
55
57
  *
56
58
  * @param id The gradient element id (referenced by `fill="url(#id)"`).
57
59
  * @param g The gradient fill.
@@ -64,7 +66,7 @@ function gradientSvgDef(id, g) {
64
66
  const c = g.center;
65
67
  if (!c) return `<radialGradient id="${id}">${stops}</radialGradient>`;
66
68
  const r = Math.SQRT2 / 2;
67
- return `<radialGradient id="${id}" cx="${n(c.x)}" cy="${n(c.y)}" r="${n(r)}">${stops}</radialGradient>`;
69
+ return `<radialGradient id="${id}" cx="${n(c.x)}" cy="${n(1 - c.y)}" r="${n(r)}">${stops}</radialGradient>`;
68
70
  }
69
71
  const rad = -(g.angle ?? 0) * Math.PI / 180;
70
72
  const dx = Math.cos(rad) / 2;
@@ -29,6 +29,15 @@ export interface FontMeasure {
29
29
  * `[…] TJ` array when shaping moved a glyph off its own advance.
30
30
  */
31
31
  readonly showText: (text: string) => string;
32
+ /**
33
+ * The glyphs `text` is drawn with and the advance each one takes, in font
34
+ * units — exactly what {@link showText} shows, kerning and ligatures
35
+ * included — for a writer that places each glyph itself.
36
+ */
37
+ readonly glyphRun: (text: string) => {
38
+ readonly gids: ReadonlyArray<number>;
39
+ readonly advances: ReadonlyArray<number>;
40
+ };
32
41
  }
33
42
  /**
34
43
  * Build a {@link FontMeasure} over a parsed font.
@@ -52,6 +52,13 @@ function createFontMeasure(parsed, kern = true) {
52
52
  if (hex !== "") parts.push(`<${hex}>`);
53
53
  return `[${parts.join(" ")}] TJ`;
54
54
  };
55
+ const glyphRun = (text) => {
56
+ const shaped = shapeText(text, parsed.glyphForCodepoint, parsed.advanceWidths, parsed.ligatures, kerning, parsed.joiningForms);
57
+ return {
58
+ gids: shaped.gids,
59
+ advances: shaped.advances
60
+ };
61
+ };
55
62
  const glyf = parsed.tables.get("glyf");
56
63
  const glyphInk = (gid) => {
57
64
  if (!glyf || gid < 0 || gid >= parsed.numGlyphs) return void 0;
@@ -92,7 +99,8 @@ function createFontMeasure(parsed, kern = true) {
92
99
  textWidthPt,
93
100
  textInkPt,
94
101
  encodeTextAsCidHex,
95
- showText
102
+ showText,
103
+ glyphRun
96
104
  };
97
105
  }
98
106
  //#endregion
@@ -28,8 +28,10 @@ function familiesInFlow(flow) {
28
28
  for (const el of elements) if (el.kind === "paragraph") {
29
29
  add(el.paragraph.properties.runProperties?.fontFamily?.ascii);
30
30
  for (const run of el.paragraph.runs) add(run.properties.fontFamily?.ascii);
31
- } else if (el.kind === "table") for (const row of el.table.rows) for (const cell of row.cells) visit(cell.content);
32
- else if (el.kind === "shape") shapeText(el.shape);
31
+ } else if (el.kind === "table") {
32
+ for (const row of el.table.rows) for (const cell of row.cells) visit(cell.content);
33
+ visit(el.table.overlay?.drawings ?? []);
34
+ } else if (el.kind === "shape") shapeText(el.shape);
33
35
  };
34
36
  visit(flow.body);
35
37
  for (const band of flow.headersFooters?.values() ?? []) visit(band);
@@ -163,8 +163,10 @@ function scriptsInFlow(flow) {
163
163
  };
164
164
  const visit = (elements) => {
165
165
  for (const el of elements) if (el.kind === "paragraph") for (const run of el.paragraph.runs) read(run.text);
166
- else if (el.kind === "table") for (const row of el.table.rows) for (const cell of row.cells) visit(cell.content);
167
- else if (el.kind === "shape") shapeText(el.shape);
166
+ else if (el.kind === "table") {
167
+ for (const row of el.table.rows) for (const cell of row.cells) visit(cell.content);
168
+ visit(el.table.overlay?.drawings ?? []);
169
+ } else if (el.kind === "shape") shapeText(el.shape);
168
170
  };
169
171
  visit(flow.body);
170
172
  for (const band of flow.headersFooters?.values() ?? []) visit(band);
@@ -155,4 +155,10 @@ export interface FlowDoc {
155
155
  * room.
156
156
  */
157
157
  readonly typesetBy?: 'word';
158
+ /**
159
+ * The document's front floats cover the text under them, as a spreadsheet's
160
+ * drawings cover its cells: a note's box hides the value beside its cell,
161
+ * and a chart the figures it sits on. Absent, the text is painted over them.
162
+ */
163
+ readonly floatsOverText?: true;
158
164
  }
@@ -13,6 +13,11 @@ export interface SheetChartRef {
13
13
  /** Where the anchor puts it, in points from the grid's top-left. */
14
14
  readonly xPt?: number;
15
15
  readonly yPt?: number;
16
+ /**
17
+ * §20.5.2.3 `fPrintsWithSheet="0"` — on the sheet, not on its paper: a
18
+ * window shows it, a print leaves it out.
19
+ */
20
+ readonly screenOnly?: true;
16
21
  }
17
22
  /**
18
23
  * §20.5.2.1 xdr:pic — a picture anchored over a sheet's grid, sized from its
@@ -26,6 +31,11 @@ export interface SheetImageRef {
26
31
  /** Where the anchor puts it, in points from the grid's top-left. */
27
32
  readonly xPt?: number;
28
33
  readonly yPt?: number;
34
+ /**
35
+ * §20.5.2.3 `fPrintsWithSheet="0"` — on the sheet, not on its paper: a
36
+ * window shows it, a print leaves it out.
37
+ */
38
+ readonly screenOnly?: true;
29
39
  }
30
40
  /** One item (label + selection state) in a {@link SheetSlicer}. */
31
41
  export interface SheetSlicerItem {
@@ -70,7 +80,35 @@ export interface SheetComment {
70
80
  readonly ref: string;
71
81
  readonly author?: string;
72
82
  readonly text: string;
83
+ /** The note as written, run by run with each run's own font — the bold "Author:" line included. */
84
+ readonly runs?: ReadonlyArray<SheetRichRun>;
73
85
  readonly threaded: boolean;
86
+ /**
87
+ * The note's box, when its legacy VML shape SHOWS it (`<x:Visible/>`):
88
+ * Excel draws a shown note on the sheet beside its cell, with a line to the
89
+ * cell's corner, and prints it there when `<pageSetup cellComments>` is
90
+ * `asDisplayed`. Absent ⇒ the note is only flagged in its cell.
91
+ */
92
+ readonly shown?: SheetNoteBox;
93
+ }
94
+ /**
95
+ * Where a shown note stands and how it is painted. Distances are in points
96
+ * from the sheet's top-left corner, measured in the file's own column order —
97
+ * a sheet that reads from the right mirrors them with everything else.
98
+ */
99
+ export interface SheetNoteBox {
100
+ readonly xPt: number;
101
+ readonly yPt: number;
102
+ readonly widthPt: number;
103
+ readonly heightPt: number;
104
+ /** The top-right corner of the cell (or merge) the note belongs to — its line ends there. */
105
+ readonly cornerXPt: number;
106
+ readonly cornerYPt: number;
107
+ readonly fillHex: string;
108
+ readonly lineHex: string;
109
+ readonly shadow: boolean;
110
+ /** The side the note's text is set to; absent ⇒ its start. */
111
+ readonly textAlign?: 'left' | 'center' | 'right';
74
112
  }
75
113
  /**
76
114
  * A form control resolved against its ctrlProp part (E-SHEET W8): the display
@@ -150,6 +188,11 @@ export interface Sheet {
150
188
  readonly images?: ReadonlyArray<SheetImageRef>;
151
189
  /** Drawing shapes on this sheet (E-SHEET W2), fully resolved + anchor-ordered. */
152
190
  readonly shapes?: ReadonlyArray<ShapeBlock>;
191
+ /**
192
+ * The indexes into {@link shapes} of those that do not print with the sheet
193
+ * (§20.5.2.3 `fPrintsWithSheet="0"`): a window shows them, paper does not.
194
+ */
195
+ readonly screenOnlyShapes?: ReadonlySet<number>;
153
196
  /**
154
197
  * Cell hyperlinks resolved to external URLs (E-SHEET W3); the projection sets
155
198
  * `run.href` on covered cells. In-workbook (location-only) links are not carried.
@@ -713,20 +713,25 @@ function applyNumericSection(value, format, negativeSection) {
713
713
  if (isPercent) magnitude *= 100;
714
714
  const { intFormat, decFormat, literalPrefix, literalSuffix, scaleCommas } = splitNumberFormat(cleaned);
715
715
  if (scaleCommas > 0) magnitude /= 1e3 ** scaleCommas;
716
- let decimals = 0;
717
- for (const c of decFormat) if (c === "0" || c === "#") decimals++;
716
+ const decPlaceholders = [...decFormat].filter((c) => c === "0" || c === "#" || c === "?");
717
+ const decimals = decPlaceholders.length;
718
718
  const [intRaw, decRaw] = toFixedDecimal(magnitude, decimals).split(".");
719
- const intStr = /,(?=\d)/.test(intFormat) || /[0#],[0#]/.test(intFormat) ? intRaw.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : intRaw;
720
- let numberPart = intRaw === "0" && !/[0?]/.test(intFormat) ? "" : intStr;
719
+ const useThousands = /,(?=\d)/.test(intFormat) || /[0#?],[0#?]/.test(intFormat);
720
+ const intPlaceholders = [...intFormat].filter((c) => c === "0" || c === "#" || c === "?");
721
+ const significant = intRaw === "0" && !intFormat.includes("0") ? "" : intRaw;
722
+ let zeros = "";
723
+ let spaces = "";
724
+ for (let i = 0; i < intPlaceholders.length - significant.length; i++) if (intPlaceholders[i] === "0") zeros += "0";
725
+ else if (intPlaceholders[i] === "?") spaces += " ";
726
+ const intDigits = zeros + significant;
727
+ let numberPart = spaces + (useThousands ? intDigits.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : intDigits);
721
728
  if (decimals > 0) {
722
729
  let dec = decRaw ?? "".padEnd(decimals, "0");
723
730
  if (dec.length < decimals) dec = dec.padEnd(decimals, "0");
724
- let kept = "";
725
- for (let i = 0; i < decFormat.length; i++) {
726
- const placeholder = decFormat[i];
727
- if (placeholder === "0" || placeholder === "#") kept += dec[i] ?? "0";
728
- }
729
- for (let i = kept.length - 1; i >= 0 && kept[i] === "0" && decFormat[i] === "#"; i--) kept = kept.substring(0, i);
731
+ let kept = dec.substring(0, decimals);
732
+ for (let i = kept.length - 1; i >= 0 && kept[i] === "0"; i--) if (decPlaceholders[i] === "#") kept = kept.substring(0, i);
733
+ else if (decPlaceholders[i] === "?") kept = `${kept.substring(0, i)} ${kept.substring(i + 1)}`;
734
+ else break;
730
735
  if (kept.length > 0) numberPart += "." + kept;
731
736
  else if (decFormat.includes("0")) numberPart += "." + dec;
732
737
  }
@@ -739,7 +744,7 @@ function splitNumberFormat(cleaned) {
739
744
  let lastDigit = -1;
740
745
  for (let i = 0; i < cleaned.length; i++) {
741
746
  const ch = cleaned[i];
742
- if (ch === "0" || ch === "#") {
747
+ if (ch === "0" || ch === "#" || ch === "?") {
743
748
  if (firstDigit < 0) firstDigit = i;
744
749
  lastDigit = i;
745
750
  }
@@ -1 +1 @@
1
- export type { CellType, WorksheetCell, ColumnStyle, ColumnWidth, MergedRange, RowHeight, RowStyle, XlsxPageMargins, XlsxPageSetup, XlsxPrintOptions, ParsedWorksheet, XlsxFont, XlsxFill, XlsxBorderStyleName, XlsxBorderEdge, XlsxBorder, XlsxHorizontalAlign, XlsxVerticalAlign, XlsxCellAlignment, XlsxCellXf, XlsxStyles, DefinedName, Dxf, CfOperator, CfRuleCellIs, CfvoType, Cfvo, CfRuleColorScale, CfRuleDataBar, CfRuleIconSet, CfRuleTop10, CfRuleAboveAverage, CfRuleDupUnique, CfRuleText, CfRuleExpression, CfRuleTimePeriod, TimePeriodKind, CfRule, ConditionalFormat, DataValidationType, DataValidation, HyperlinkRef, HeaderFooter, FormControlRef, OleObjectRef, SheetRichRun, SparklineKind, ParsedSparkline, ExcelTable, PivotTable, SheetPane, } from './types.js';
1
+ export type { CellType, WorksheetCell, ColumnStyle, ColumnWidth, MergedRange, RowHeight, RowStyle, XlsxPageMargins, XlsxPageSetup, XlsxPrintOptions, ParsedWorksheet, XlsxFont, XlsxFill, XlsxBorderStyleName, XlsxBorderEdge, XlsxBorder, XlsxHorizontalAlign, XlsxVerticalAlign, XlsxCellAlignment, XlsxCellXf, XlsxStyles, DefinedName, Dxf, CfOperator, CfRuleCellIs, CfvoType, Cfvo, CfRuleColorScale, CfRuleDataBar, CfRuleIconSet, CfRuleTop10, CfRuleAboveAverage, CfRuleDupUnique, CfRuleText, CfRuleExpression, CfRuleTimePeriod, TimePeriodKind, CfRule, ConditionalFormat, DataValidationType, DataValidation, HyperlinkRef, HeaderFooter, FormControlRef, OleObjectRef, SheetRichRun, SparklineKind, ParsedSparkline, ExcelTable, TableStyleElementType, TableStyleRegion, TableStyleFormat, XlsxTableStyle, PivotTable, SheetPane, } from './types.js';
@@ -171,6 +171,12 @@ export interface ParsedWorksheet {
171
171
  readonly colBreaks?: ReadonlyArray<number>;
172
172
  /** §18.3.1.36 `<drawing r:id>` — the sheet's drawing part (charts/shapes). */
173
173
  readonly drawingRelId?: string;
174
+ /**
175
+ * §18.3.1.99 — the sheet is a `<chartsheet>`: nothing but a chart, which
176
+ * prints filling the page, and on a landscape one unless the sheet says
177
+ * otherwise.
178
+ */
179
+ readonly chartSheet?: boolean;
174
180
  /**
175
181
  * §18.3.1.36 `<legacyDrawing r:id>` — the relationship to the sheet's VML
176
182
  * drawing part. A form control put on the sheet by Excel's Forms toolbar is
@@ -226,6 +232,22 @@ export interface ParsedWorksheet {
226
232
  * (E-SHEET SE2/SE3).
227
233
  */
228
234
  readonly pane?: SheetPane;
235
+ /**
236
+ * ECMA-376 §18.3.1.87 `<sheetView showGridLines>` — whether the sheet's
237
+ * window draws the cell gridlines. A VIEW setting, like the pane: what
238
+ * prints is `<printOptions gridLines>`. Carried for a screen projection and
239
+ * the round trip; absent ⇒ shown, the default.
240
+ */
241
+ readonly showGridLines?: boolean;
242
+ /**
243
+ * ECMA-376 §18.3.1.87 `<sheetView rightToLeft>` — the sheet reads from the
244
+ * right: column A stands at the right edge and the columns run leftward,
245
+ * and each cell's left and right borders cross over with it. What a cell's
246
+ * text does is unchanged — it keeps the side its alignment names. Unlike
247
+ * the pane and the gridlines this one prints: Excel puts the sheet on the
248
+ * paper the way the window shows it. Absent ⇒ left to right.
249
+ */
250
+ readonly rightToLeft?: boolean;
229
251
  }
230
252
  /**
231
253
  * A frozen pane: the count of leading rows / columns frozen in the worksheet
@@ -236,6 +258,28 @@ export interface SheetPane {
236
258
  readonly frozenRows: number;
237
259
  readonly frozenCols: number;
238
260
  }
261
+ /**
262
+ * §18.18.77 ST_TableStyleType — the regions of a table a table style formats,
263
+ * in the order they apply (§18.8.41): a later region's format wins where both
264
+ * say something.
265
+ */
266
+ export type TableStyleElementType = 'wholeTable' | 'firstColumnStripe' | 'secondColumnStripe' | 'firstRowStripe' | 'secondRowStripe' | 'lastColumn' | 'firstColumn' | 'headerRow' | 'totalRow' | 'firstHeaderCell' | 'lastHeaderCell' | 'firstTotalCell' | 'lastTotalCell';
267
+ /** §18.8.40 — one region's format in a table style: its dxf, and a stripe's band size. */
268
+ export interface TableStyleRegion {
269
+ readonly dxf: Dxf;
270
+ /** §18.8.41 `size` — rows (or columns) in one band of a stripe; default 1. */
271
+ readonly size?: number;
272
+ }
273
+ /** §18.8.40 — a table style, region by region, its colours resolved. */
274
+ export type TableStyleFormat = Partial<Record<TableStyleElementType, TableStyleRegion>>;
275
+ /** §18.8.40 `<tableStyle>` — a style a workbook defines itself: each region's dxf. */
276
+ export interface XlsxTableStyle {
277
+ readonly elements: ReadonlyArray<{
278
+ readonly type: TableStyleElementType;
279
+ readonly dxfId: number;
280
+ readonly size?: number;
281
+ }>;
282
+ }
239
283
  /**
240
284
  * ECMA-376 §18.5.1.2 `<table>` — a structured table over a cell range with a
241
285
  * banded style. The raw parse carries the range, header rows and style flags;
@@ -247,6 +291,13 @@ export interface ExcelTable {
247
291
  readonly name?: string;
248
292
  readonly styleName?: string;
249
293
  readonly headerRowCount: number;
294
+ /** §18.5.1.2 `totalsRowCount` — the totals rows at the foot of the table (default 0). */
295
+ readonly totalsRowCount?: number;
296
+ /**
297
+ * §18.5.1.3 `<tableColumn name>` — the columns' names, left to right: what a
298
+ * structured reference (`tblIncome[Amount]`) names a column by.
299
+ */
300
+ readonly columns?: ReadonlyArray<string>;
250
301
  readonly showRowStripes: boolean;
251
302
  readonly showColumnStripes: boolean;
252
303
  readonly showFirstColumn: boolean;
@@ -259,6 +310,12 @@ export interface ExcelTable {
259
310
  readonly headerHex?: string;
260
311
  readonly bandHex?: string;
261
312
  readonly headerTextHex?: string;
313
+ /**
314
+ * §18.8.40 — the style the table names, region by region: one Excel builds
315
+ * in (TableStyleMedium2) or one the workbook defines, its colours resolved
316
+ * against the workbook's theme.
317
+ */
318
+ readonly style?: TableStyleFormat;
262
319
  }
263
320
  /**
264
321
  * ECMA-376 §18.10.1.73 `<pivotTableDefinition>` — a pivot table. Its OUTPUT
@@ -314,6 +371,14 @@ export interface XlsxFont {
314
371
  /** §18.8.37 `<strike/>` — the font is struck through. */
315
372
  readonly strike?: boolean;
316
373
  readonly colorHex?: string;
374
+ /**
375
+ * §18.8.3 — how the `<color>` names the colour, not what it comes to:
376
+ * `theme:1:0`, `rgb:FF000000`, `indexed:8`, `auto`; undefined for a font with
377
+ * no `<color>`. Excel lets a table style colour a cell's text only where the
378
+ * cell names its colour as the Normal style does — `theme="1"` black takes
379
+ * the style's white, `rgb="FF000000"` black keeps its own.
380
+ */
381
+ readonly colorRef?: string;
317
382
  readonly name?: string;
318
383
  }
319
384
  /** §18.8.20 `<fill>` — one fill record: pattern type plus foreground/background colours. */
@@ -343,6 +408,13 @@ export interface XlsxBorder {
343
408
  readonly diagonal?: XlsxBorderEdge;
344
409
  readonly diagonalUp?: boolean;
345
410
  readonly diagonalDown?: boolean;
411
+ /**
412
+ * §18.8.4 `<vertical>`/`<horizontal>` — the lines BETWEEN the cells of a range
413
+ * a differential format covers: a table style's rules between its columns
414
+ * and between its rows. A cell's own border has no use for them.
415
+ */
416
+ readonly vertical?: XlsxBorderEdge;
417
+ readonly horizontal?: XlsxBorderEdge;
346
418
  }
347
419
  /** §18.18.40 ST_HorizontalAlignment — `<alignment horizontal>`. */
348
420
  export type XlsxHorizontalAlign = 'left' | 'center' | 'right' | 'fill' | 'justify' | 'centerContinuous' | 'distributed';
@@ -362,6 +434,12 @@ export interface XlsxCellAlignment {
362
434
  readonly textRotation?: number;
363
435
  /** §18.8.1 `shrinkToFit` — scale the text down so it fits the cell on one line (W6). */
364
436
  readonly shrinkToFit?: boolean;
437
+ /**
438
+ * §18.8.1 `readingOrder` — `1` left to right, `2` right to left. Absent (or
439
+ * `0`) is "context": the direction of the text's first strong character,
440
+ * which is also what a General cell aligns its text by.
441
+ */
442
+ readonly readingOrder?: 'ltr' | 'rtl';
365
443
  }
366
444
  /**
367
445
  * §18.8.45 `<xf>` — one cell format record: indices into the font/fill/border/
@@ -395,6 +473,11 @@ export interface XlsxStyles {
395
473
  * rules (E-SHEET SC1); only the properties a dxf sets override the base.
396
474
  */
397
475
  readonly dxfs?: ReadonlyArray<Dxf>;
476
+ /**
477
+ * §18.8.42 `<tableStyles>` — the table styles the workbook defines itself,
478
+ * by name; their regions point into {@link XlsxStyles.dxfs}.
479
+ */
480
+ readonly tableStyles?: ReadonlyMap<string, XlsxTableStyle>;
398
481
  }
399
482
  /** §18.8.14 `<dxf>` — a differential (override) format a `cfRule` applies on match. */
400
483
  export interface Dxf {
@@ -489,6 +572,11 @@ export interface CfRuleDataBar {
489
572
  * figure does not sit on top of its own gauge.
490
573
  */
491
574
  readonly showValue?: boolean;
575
+ /**
576
+ * The 2009 extension's `<x14:dataBar gradient>` — false paints the bar in
577
+ * one solid colour, where Excel's default fades it from the axis.
578
+ */
579
+ readonly gradient?: boolean;
492
580
  }
493
581
  /**
494
582
  * §18.3.1.49 `<cfRule type="iconSet">` — picks one glyph per cell from a named
@@ -501,6 +589,12 @@ export interface CfRuleIconSet {
501
589
  readonly iconSet: string;
502
590
  readonly cfvos: ReadonlyArray<Cfvo>;
503
591
  readonly reverse?: boolean;
592
+ /**
593
+ * §18.3.1.49 `showValue` — false means the cell shows its ICON ONLY, as a
594
+ * status column of ticks and crosses does: the figure is what the icon
595
+ * already says.
596
+ */
597
+ readonly showValue?: boolean;
504
598
  }
505
599
  /**
506
600
  * §18.3.1.10 `<cfRule type="top10">` — the top (or `bottom`) N values of the
@@ -708,6 +802,8 @@ export interface SheetRichRun {
708
802
  readonly sizePt?: number;
709
803
  /** §18.4.2 `<vertAlign>` — superscript / subscript within the cell text. */
710
804
  readonly vertAlign?: 'superscript' | 'subscript';
805
+ /** §18.4.5 `<rFont>` — the run's typeface, where the producer names one. */
806
+ readonly fontName?: string;
711
807
  }
712
808
  /**
713
809
  * §18.18.18 ST_DataValidationType — the constraint a `<dataValidation>`
@@ -262,8 +262,10 @@ function resolveBodyStyles(body, sheet) {
262
262
  };
263
263
  const visit = (el) => {
264
264
  if (el.kind === "paragraph") visitParagraph(el.paragraph);
265
- 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);
266
- else if (el.kind === "shape") {
265
+ else if (el.kind === "table") {
266
+ for (const row of el.table.rows) for (const cell of row.cells) for (const child of cell.content) visit(child);
267
+ for (const drawing of el.table.overlay?.drawings ?? []) visit(drawing);
268
+ } else if (el.kind === "shape") {
267
269
  const shapeText = (sh) => {
268
270
  for (const child of sh.text?.content ?? []) visit(child);
269
271
  for (const member of sh.children ?? []) shapeText(member.shape);
@@ -1,4 +1,21 @@
1
1
  import { BodyElement, TableProperties, TableRow } from '../core/document-model/index.js';
2
+ /** §18.3.1.70 — the width of the row-number column, in twips. */
3
+ export declare const HEADING_COL_TWIPS = 460;
4
+ /**
5
+ * §18.3.1.70 — how the printed headings stand: the sheet's print scale shrinks
6
+ * them with it, as it shrinks everything else on the page.
7
+ */
8
+ export interface HeadingBand {
9
+ /** How tall the letters row stands — exactly, so a drawing anchored to the
10
+ * grid can be moved down by just as much. */
11
+ readonly lettersPt?: number;
12
+ /** The row-number column's width, in twips; {@link HEADING_COL_TWIPS} unscaled. */
13
+ readonly colTwips?: number;
14
+ /** The size the letters and numbers are set in; the sheet's default unscaled. */
15
+ readonly fontPt?: number;
16
+ /** The width of the boxes' lines; 0.5pt unscaled. */
17
+ readonly lineWidthPt?: number;
18
+ }
2
19
  /**
3
20
  * Wrap a grid in its printed row and column headings (§18.3.1.70 `headings`):
4
21
  * the column letters across the top, the row numbers down the left, each in a
@@ -7,14 +24,23 @@ import { BodyElement, TableProperties, TableRow } from '../core/document-model/i
7
24
  *
8
25
  * @param rows The band's rows.
9
26
  * @param widths The band's column widths in twips.
10
- * @param colStart The absolute index of the band's first column.
27
+ * @param columns The absolute index of each of those columns — a hidden
28
+ * one between them is skipped, and so is its letter.
11
29
  * @param rowNumbers The absolute 1-based row number of each row.
30
+ * @param band How the headings stand, at the print scale.
12
31
  * @returns The rows and widths with the heading band added.
13
32
  */
14
- export declare function withHeadingBand(rows: ReadonlyArray<TableRow>, widths: ReadonlyArray<number>, colStart: number, rowNumbers: ReadonlyArray<number>): {
33
+ export declare function withHeadingBand(rows: ReadonlyArray<TableRow>, widths: ReadonlyArray<number>, columns: ReadonlyArray<number>, rowNumbers: ReadonlyArray<number>, band?: HeadingBand): {
15
34
  rows: Array<TableRow>;
16
35
  widths: Array<number>;
17
36
  };
37
+ /** Where a drawing lies on its sheet, in points from the sheet's top-left corner. */
38
+ export interface DrawingBox {
39
+ readonly xPt: number;
40
+ readonly yPt: number;
41
+ readonly widthPt: number;
42
+ readonly heightPt: number;
43
+ }
18
44
  /** A contiguous run of columns that prints together as one band (E-SHEET SE1). */
19
45
  export interface ColumnBand {
20
46
  /** First local column index (inclusive). */
@@ -50,12 +76,19 @@ export declare function computeColumnBands(columnWidths: ReadonlyArray<number>,
50
76
  * @param titleRowIndex The print-title row, or -1.
51
77
  * @param drawingReachTwips How far right the sheet's drawings reach (0 if none).
52
78
  * @param headings §18.3.1.70 — the printed row/column headings, when the sheet
53
- * asks for them: the absolute index of the grid's first column and the sheet
54
- * row number of each emitted row. Each band gets ITS OWN letters, which is
55
- * what both references print across the top of a continuation page.
79
+ * asks for them: the absolute index of each column and the sheet row number
80
+ * of each emitted row. Each band gets ITS OWN letters, which is what both
81
+ * references print across the top of a continuation page.
82
+ * @param sheet §20.5 — where the grid's first column stands on the sheet and
83
+ * where its printed drawings lie, at the print scale: each band is framed
84
+ * for the drawings over it (TableOverlay) and keeps the rows they cover.
56
85
  * @returns One table body element per band, in band order.
57
86
  */
58
87
  export declare function bandedTables(rows: ReadonlyArray<TableRow>, columnWidths: ReadonlyArray<number>, bands: ReadonlyArray<ColumnBand>, properties: TableProperties, titleRowIndex?: number, drawingReachTwips?: number, headings?: {
59
- readonly colStart: number;
88
+ readonly columns: ReadonlyArray<number>;
60
89
  readonly rowNumbers: ReadonlyArray<number>;
90
+ readonly band?: HeadingBand;
91
+ }, sheet?: {
92
+ readonly sheetLeftPt: number;
93
+ readonly drawings: ReadonlyArray<DrawingBox>;
61
94
  }): Array<BodyElement>;