reamkit 1.31.0 → 1.32.1

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 (98) 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/crypto/offcrypto.js +56 -12
  10. package/dist/esm/core/document-model/index.d.ts +1 -1
  11. package/dist/esm/core/document-model/types.d.ts +112 -0
  12. package/dist/esm/core/drawingml/chart-geometry.d.ts +36 -13
  13. package/dist/esm/core/drawingml/chart-geometry.js +372 -146
  14. package/dist/esm/core/drawingml/chart-parser.d.ts +19 -0
  15. package/dist/esm/core/drawingml/chart-parser.js +126 -18
  16. package/dist/esm/core/drawingml/colors.d.ts +6 -0
  17. package/dist/esm/core/drawingml/colors.js +23 -3
  18. package/dist/esm/core/drawingml/shape-render.d.ts +3 -1
  19. package/dist/esm/core/drawingml/shape-render.js +4 -2
  20. package/dist/esm/core/font/measure.d.ts +9 -0
  21. package/dist/esm/core/font/measure.js +9 -1
  22. package/dist/esm/core/fonts/families.js +4 -2
  23. package/dist/esm/core/fonts/scripts.js +4 -2
  24. package/dist/esm/core/ir/flow.d.ts +6 -0
  25. package/dist/esm/core/ir/sheet.d.ts +43 -0
  26. package/dist/esm/core/number-format.d.ts +40 -15
  27. package/dist/esm/core/number-format.js +295 -83
  28. package/dist/esm/core/opc/tag-scan.d.ts +15 -0
  29. package/dist/esm/core/opc/tag-scan.js +41 -0
  30. package/dist/esm/core/opc/xml-entities.js +39 -2
  31. package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
  32. package/dist/esm/core/spreadsheet-model/types.d.ts +96 -0
  33. package/dist/esm/core/style-cascade/resolver.js +4 -2
  34. package/dist/esm/excel/column-bands.d.ts +39 -6
  35. package/dist/esm/excel/column-bands.js +41 -17
  36. package/dist/esm/excel/comments-parser.js +19 -0
  37. package/dist/esm/excel/conditional-format.d.ts +7 -3
  38. package/dist/esm/excel/conditional-format.js +77 -39
  39. package/dist/esm/excel/formula/context.d.ts +18 -0
  40. package/dist/esm/excel/formula/eval.js +51 -0
  41. package/dist/esm/excel/formula/functions.js +37 -14
  42. package/dist/esm/excel/formula/index.d.ts +2 -2
  43. package/dist/esm/excel/formula/lexer.d.ts +1 -1
  44. package/dist/esm/excel/formula/lexer.js +41 -0
  45. package/dist/esm/excel/formula/parser.d.ts +25 -0
  46. package/dist/esm/excel/formula/parser.js +95 -0
  47. package/dist/esm/excel/print-model.d.ts +38 -1
  48. package/dist/esm/excel/print-model.js +536 -83
  49. package/dist/esm/excel/shared-strings-parser.d.ts +9 -0
  50. package/dist/esm/excel/shared-strings-parser.js +11 -1
  51. package/dist/esm/excel/sheet-drawing.d.ts +38 -2
  52. package/dist/esm/excel/sheet-drawing.js +47 -13
  53. package/dist/esm/excel/sheet-shape-parser.d.ts +6 -2
  54. package/dist/esm/excel/sheet-shape-parser.js +18 -6
  55. package/dist/esm/excel/sheet-to-flow.d.ts +17 -0
  56. package/dist/esm/excel/sheet-to-flow.js +434 -47
  57. package/dist/esm/excel/styles-parser.d.ts +9 -0
  58. package/dist/esm/excel/styles-parser.js +80 -26
  59. package/dist/esm/excel/table-parser.js +5 -0
  60. package/dist/esm/excel/table-style-presets.d.ts +26 -0
  61. package/dist/esm/excel/table-style-presets.js +1555 -0
  62. package/dist/esm/excel/table-style.d.ts +13 -0
  63. package/dist/esm/excel/table-style.js +75 -0
  64. package/dist/esm/excel/tint.d.ts +10 -0
  65. package/dist/esm/excel/tint.js +75 -0
  66. package/dist/esm/excel/vml-drawing.d.ts +41 -3
  67. package/dist/esm/excel/vml-drawing.js +144 -11
  68. package/dist/esm/excel/worksheet-parser.js +89 -15
  69. package/dist/esm/excel/xls/biff-reader.js +10 -2
  70. package/dist/esm/excel/xlsx-reader.js +234 -19
  71. package/dist/esm/excel/xlsx-writer.js +8 -7
  72. package/dist/esm/html/html-writer.js +202 -20
  73. package/dist/esm/layout/fit-pages.d.ts +11 -0
  74. package/dist/esm/layout/fit-pages.js +86 -0
  75. package/dist/esm/layout/line-paint.d.ts +58 -0
  76. package/dist/esm/layout/line-paint.js +107 -0
  77. package/dist/esm/layout/page-doc.d.ts +51 -0
  78. package/dist/esm/layout/page-doc.js +141 -1
  79. package/dist/esm/layout/styled-layout.d.ts +7 -0
  80. package/dist/esm/layout/styled-layout.js +275 -52
  81. package/dist/esm/layout/turned-section.js +14 -2
  82. package/dist/esm/markdown/markdown-writer.js +75 -13
  83. package/dist/esm/pdf/styled-page-emitter.js +49 -71
  84. package/dist/esm/pdf/styled-page-renderer.js +1 -1
  85. package/dist/esm/pdf-reader/annot-draw.js +2 -2
  86. package/dist/esm/pdf-reader/annots.js +3 -1
  87. package/dist/esm/pdf-reader/font.js +4 -4
  88. package/dist/esm/pdf-reader/layout.js +1 -1
  89. package/dist/esm/svg/svg-text.d.ts +58 -0
  90. package/dist/esm/svg/svg-text.js +322 -0
  91. package/dist/esm/svg/svg-writer.js +135 -71
  92. package/dist/esm/word/document-parser.js +1 -1
  93. package/dist/esm/word/docx-reader.js +13 -8
  94. package/dist/esm/word/docx-to-pdf.js +3 -3
  95. package/dist/esm/word/docx-writer.js +11 -2
  96. package/dist/esm/word/font-table.js +89 -10
  97. package/dist/esm/word/numbering-parser.js +1 -1
  98. package/package.json +7 -3
package/README.md CHANGED
@@ -208,6 +208,16 @@ what it heads, table borders that take the room they are wide, a Word 2010
208
208
  table placed by its first cell's text, and sections whose lines run down the
209
209
  sheet.
210
210
 
211
+ A workbook is drawn the way Excel draws it, each rule checked against Excel's
212
+ own PDF: columns in the Normal font's digit as Excel counts it, a table in the
213
+ style it names, a theme colour's tint to the digit, a sheet that reads from the
214
+ right turned round, the notes it shows beside their cells, its drawings over
215
+ the cells and cut where its pages are, a chart's axes scaled and crossed where
216
+ Excel puts them. As HTML a workbook comes out as Excel's window shows it —
217
+ every tab, its gridlines, a noted cell flagged with the note on hover — and as
218
+ SVG as pictures of its sheets, each whole, its text drawn from the faces' own
219
+ outlines.
220
+
211
221
  **Reads PDF, too.** `Ream.parse` accepts a PDF and reconstructs a `FlowDoc` — a
212
222
  tagged PDF from its structure tree (headings, tables, lists, reading order), an
213
223
  untagged one from where its glyphs stand: lines and paragraphs at the page's own
@@ -36,6 +36,16 @@ export declare function analyzeString(text: string, dir?: Direction): StringBidi
36
36
  * or Arabic presentation-form ranges.
37
37
  */
38
38
  export declare function hasBidiCharacters(text: string): boolean;
39
+ /**
40
+ * The direction of a string's first strong character (UAX #9 P2): `rtl` for
41
+ * an `R` or `AL` one, `ltr` for an `L` one, undefined when it has none — a
42
+ * number, punctuation, a blank. This is what an application means by a
43
+ * "context" reading order.
44
+ *
45
+ * @param text The string to scan.
46
+ * @returns The direction its first strong character sets, if any.
47
+ */
48
+ export declare function firstStrongDirection(text: string): 'ltr' | 'rtl' | undefined;
39
49
  /**
40
50
  * Reverse a string by code point (so surrogate pairs stay intact). Used to emit
41
51
  * an RTL run's glyphs in visual (right-to-left) order, since our glyph placement
@@ -1,4 +1,4 @@
1
- import "./char-types.js";
1
+ import { bidiClass } from "./char-types.js";
2
2
  import { computeBidi } from "./algorithm.js";
3
3
  import "./segments.js";
4
4
  //#region src/core/bidi/index.ts
@@ -39,6 +39,22 @@ function hasBidiCharacters(text) {
39
39
  return false;
40
40
  }
41
41
  /**
42
+ * The direction of a string's first strong character (UAX #9 P2): `rtl` for
43
+ * an `R` or `AL` one, `ltr` for an `L` one, undefined when it has none — a
44
+ * number, punctuation, a blank. This is what an application means by a
45
+ * "context" reading order.
46
+ *
47
+ * @param text The string to scan.
48
+ * @returns The direction its first strong character sets, if any.
49
+ */
50
+ function firstStrongDirection(text) {
51
+ for (const ch of text) {
52
+ const cls = bidiClass(ch.codePointAt(0));
53
+ if (cls === "L") return "ltr";
54
+ if (cls === "R" || cls === "AL") return "rtl";
55
+ }
56
+ }
57
+ /**
42
58
  * Reverse a string by code point (so surrogate pairs stay intact). Used to emit
43
59
  * an RTL run's glyphs in visual (right-to-left) order, since our glyph placement
44
60
  * advances left-to-right.
@@ -50,4 +66,4 @@ function reverseByCodePoint(text) {
50
66
  return [...text].reverse().join("");
51
67
  }
52
68
  //#endregion
53
- export { analyzeString, hasBidiCharacters, reverseByCodePoint };
69
+ export { analyzeString, firstStrongDirection, hasBidiCharacters, reverseByCodePoint };
@@ -11,6 +11,7 @@ import { projectSheetDoc } from "../../excel/sheet-to-flow.js";
11
11
  import { xlsxReader } from "../../excel/xlsx-reader.js";
12
12
  import { chainProviders } from "../fonts/provider.js";
13
13
  import { flowRenderOptions } from "./project.js";
14
+ import { layoutSheetImages } from "./sheet-images.js";
14
15
  import { writeDocx } from "../../word/docx-writer.js";
15
16
  import { writeXlsx } from "../../excel/xlsx-writer.js";
16
17
  import { writeHtml } from "../../html/html-writer.js";
@@ -78,7 +79,10 @@ function createConverter(opts = {}) {
78
79
  };
79
80
  }
80
81
  if (to === "html") {
81
- const { doc: flow, losses: readLosses } = readToFlow(reader, bytes, rest.now ? { now: rest.now } : void 0);
82
+ const { doc: flow, losses: readLosses } = readToFlow(reader, bytes, {
83
+ ...rest.now ? { now: rest.now } : {},
84
+ screen: true
85
+ });
82
86
  losses.push(...readLosses);
83
87
  const html = writeHtml(flow);
84
88
  losses.push(...html.losses);
@@ -123,10 +127,11 @@ function createConverter(opts = {}) {
123
127
  if (to === "svg") {
124
128
  const fonts = conv.fonts ?? (conv.fontBytes ? { regular: conv.fontBytes } : void 0);
125
129
  if (!fonts) throw new Error("to: 'svg' requires options.fonts/fontBytes or fontProviders");
126
- const { doc: flow } = readToFlow(reader, bytes, rest.now ? { now: rest.now } : void 0);
127
- const svg = writeSvg(layoutStyledDocument(flow.body, {
128
- registry: FontRegistry.fromBytes(fonts),
129
- ...flowRenderOptions(flow)
130
+ const { doc } = reader.read(bytes);
131
+ const registry = FontRegistry.fromBytes(fonts);
132
+ const svg = writeSvg(doc.kind === "sheet" ? layoutSheetImages(doc, { registry }, rest.now ? { now: rest.now } : {}) : layoutStyledDocument(doc.body, {
133
+ registry,
134
+ ...flowRenderOptions(doc)
130
135
  }));
131
136
  losses.push(...svg.losses);
132
137
  if (strict && losses.length > 0) throw new ConversionLossError(losses[0]);
@@ -30,6 +30,7 @@ function flowRenderOptions(flow) {
30
30
  ...flow.pageBackgroundFill ? { pageBackgroundFill: flow.pageBackgroundFill } : {},
31
31
  ...flow.gutterAtTop ? { gutterAtTop: true } : {},
32
32
  ...flow.typesetBy ? { typesetBy: flow.typesetBy } : {},
33
+ ...flow.floatsOverText ? { floatsOverText: true } : {},
33
34
  ...flow.compatibilityMode !== void 0 ? { compatibilityMode: flow.compatibilityMode } : {}
34
35
  };
35
36
  }
@@ -9,6 +9,7 @@ import { renderStyledPdf, renderStyledPdfEncrypted } from "../../pdf/styled-page
9
9
  import "../../pdf/index.js";
10
10
  import { projectSheetDoc } from "../../excel/sheet-to-flow.js";
11
11
  import { flowRenderOptions } from "./project.js";
12
+ import { layoutSheetImages } from "./sheet-images.js";
12
13
  import { writeDocx } from "../../word/docx-writer.js";
13
14
  import { writeXlsx } from "../../excel/xlsx-writer.js";
14
15
  import { writeHtml } from "../../html/html-writer.js";
@@ -128,7 +129,11 @@ var Ream = class Ream {
128
129
  ...options.fileName ? { fileName: options.fileName } : {}
129
130
  }) : this.flow;
130
131
  if (to === "html") {
131
- const html = writeHtml(flow);
132
+ const html = writeHtml(this.sheet ? projectSheetDoc(this.sheet, {
133
+ ...options.now ? { now: options.now } : {},
134
+ ...options.fileName ? { fileName: options.fileName } : {},
135
+ screen: true
136
+ }) : flow);
132
137
  losses.push(...html.losses);
133
138
  this.enforceStrict(options, losses);
134
139
  return {
@@ -173,15 +178,21 @@ var Ream = class Ream {
173
178
  }
174
179
  const { fonts, registriesByFamily } = await this.resolveFonts(options, losses, flow);
175
180
  const registry = FontRegistry.fromBytes(fonts);
176
- const paginated = this.sheet ? projectSheetDoc(this.sheet, {
181
+ const sheetOptions = {
177
182
  ...options.now ? { now: options.now } : {},
178
183
  ...options.fileName ? { fileName: options.fileName } : {},
179
184
  digitWidthPt: createFontMeasure(registry.resolveByStyle(false, false).parsed).textWidthPt("0", DEFAULT_WORKBOOK_FONT_PT)
180
- }) : flow;
185
+ };
186
+ const { fonts: _a, fontBytes: _b, fontFamily: _c, fontFetch: _d, fontProviders: _e, strict: _f, embedSource, signature, info: callerInfo, attachments: callerAttachments, ...renderOptions } = options;
181
187
  if (to === "svg") {
182
- const svg = writeSvg(layoutStyledDocument(paginated.body, {
188
+ const faces = {
183
189
  registry,
184
- ...flowRenderOptions(paginated)
190
+ ...registriesByFamily ? { registriesByFamily } : {}
191
+ };
192
+ const svg = writeSvg(this.sheet ? layoutSheetImages(this.sheet, faces, sheetOptions, renderOptions) : layoutStyledDocument(flow.body, {
193
+ ...faces,
194
+ ...flowRenderOptions(flow),
195
+ ...renderOptions
185
196
  }));
186
197
  losses.push(...svg.losses);
187
198
  this.enforceStrict(options, losses);
@@ -190,7 +201,7 @@ var Ream = class Ream {
190
201
  losses
191
202
  };
192
203
  }
193
- const { fonts: _a, fontBytes: _b, fontFamily: _c, fontFetch: _d, fontProviders: _e, strict: _f, embedSource, signature, info: callerInfo, attachments: callerAttachments, ...renderOptions } = options;
204
+ const paginated = this.sheet ? projectSheetDoc(this.sheet, sheetOptions) : flow;
194
205
  const info = paginated.info || callerInfo ? {
195
206
  ...paginated.info,
196
207
  ...callerInfo
@@ -0,0 +1,17 @@
1
+ import { SheetDoc } from '../ir/sheet.js';
2
+ import { ProjectSheetOptions } from '../../excel/sheet-to-flow.js';
3
+ import { LaidOutDocument } from '../../layout/page-doc.js';
4
+ import { StyledRenderOptions } from '../../pdf/index.js';
5
+ /**
6
+ * Lay a workbook out as images of its sheets: the screen projection, one page a
7
+ * sheet with room for all of it, each page then cut to its content.
8
+ *
9
+ * @param sheet The workbook.
10
+ * @param faces The faces the sheets are measured and drawn in: the registry,
11
+ * and one per family where the document names several.
12
+ * @param options The projection's other knobs (reference date, file name, the
13
+ * render face's digit width).
14
+ * @param render The caller's own layout options, over the document's.
15
+ * @returns One page per visible sheet, each as large as what it holds.
16
+ */
17
+ export declare function layoutSheetImages(sheet: SheetDoc, faces: Pick<StyledRenderOptions, 'registry' | 'registriesByFamily'>, options?: Omit<ProjectSheetOptions, 'screen' | 'wholeSheetPages'>, render?: Partial<StyledRenderOptions>): LaidOutDocument;
@@ -0,0 +1,33 @@
1
+ import { layoutStyledDocument } from "../../layout/styled-layout.js";
2
+ import { projectSheetDoc } from "../../excel/sheet-to-flow.js";
3
+ import { flowRenderOptions } from "./project.js";
4
+ import { fitPagesToContent } from "../../layout/fit-pages.js";
5
+ //#region src/core/converter/sheet-images.ts
6
+ /** The room kept past a sheet's content, as the layout keeps it before it. */
7
+ var SHEET_IMAGE_PAD_PT = 2;
8
+ /**
9
+ * Lay a workbook out as images of its sheets: the screen projection, one page a
10
+ * sheet with room for all of it, each page then cut to its content.
11
+ *
12
+ * @param sheet The workbook.
13
+ * @param faces The faces the sheets are measured and drawn in: the registry,
14
+ * and one per family where the document names several.
15
+ * @param options The projection's other knobs (reference date, file name, the
16
+ * render face's digit width).
17
+ * @param render The caller's own layout options, over the document's.
18
+ * @returns One page per visible sheet, each as large as what it holds.
19
+ */
20
+ function layoutSheetImages(sheet, faces, options = {}, render = {}) {
21
+ const flow = projectSheetDoc(sheet, {
22
+ ...options,
23
+ screen: true,
24
+ wholeSheetPages: true
25
+ });
26
+ return fitPagesToContent(layoutStyledDocument(flow.body, {
27
+ ...faces,
28
+ ...flowRenderOptions(flow),
29
+ ...render
30
+ }), SHEET_IMAGE_PAD_PT);
31
+ }
32
+ //#endregion
33
+ export { layoutSheetImages };
@@ -159,29 +159,73 @@ function agileKeyData(attrs) {
159
159
  };
160
160
  }
161
161
  function passwordKeyEncryptor(xml) {
162
- const re = /<[A-Za-z0-9]*:?encryptedKey\b([^>]*)\/?>/gu;
163
- let m = re.exec(xml);
164
- while (m) {
165
- const attrs = parseAttrs(m[1] ?? "");
162
+ for (const raw of elementsNamed(xml, "encryptedKey")) {
163
+ const attrs = parseAttrs(raw);
166
164
  if (attrs["spinCount"] !== void 0) return attrs;
167
- m = re.exec(xml);
168
165
  }
169
166
  throw new Error("No password key encryptor in the encryption descriptor");
170
167
  }
171
168
  function attrsOf(xml, tag) {
172
- const m = new RegExp(`<[A-Za-z0-9]*:?${tag}\\b([^>]*)/?>`, "u").exec(xml);
173
- return m ? parseAttrs(m[1] ?? "") : {};
169
+ const raw = elementsNamed(xml, tag)[0];
170
+ return raw === void 0 ? {} : parseAttrs(raw);
171
+ }
172
+ function elementsNamed(xml, tag) {
173
+ const out = [];
174
+ let open = xml.indexOf("<");
175
+ while (open >= 0) {
176
+ const end = nameEnd(xml, open + 1, tag);
177
+ if (end < 0) {
178
+ open = xml.indexOf("<", open + 1);
179
+ continue;
180
+ }
181
+ const close = xml.indexOf(">", end);
182
+ if (close < 0) break;
183
+ out.push(xml.slice(end, close));
184
+ open = xml.indexOf("<", close + 1);
185
+ }
186
+ return out;
187
+ }
188
+ function nameEnd(xml, from, tag) {
189
+ let end = from;
190
+ while (isAlnum(xml.charCodeAt(end))) end++;
191
+ const prefixed = end + 1 + tag.length;
192
+ if (xml[end] === ":" && xml.startsWith(tag, end + 1) && !isWordChar(xml.charCodeAt(prefixed))) return prefixed;
193
+ if (end - from >= tag.length && xml.startsWith(tag, end - tag.length)) return isWordChar(xml.charCodeAt(end)) ? -1 : end;
194
+ return -1;
174
195
  }
175
196
  function parseAttrs(raw) {
176
197
  const out = {};
177
- const re = /([A-Za-z0-9_:]+)\s*=\s*"([^"]*)"/gu;
178
- let m = re.exec(raw);
179
- while (m) {
180
- out[m[1].replace(/^.*:/u, "")] = m[2];
181
- m = re.exec(raw);
198
+ let at = 0;
199
+ while (at < raw.length) {
200
+ if (!isNameChar(raw.charCodeAt(at))) {
201
+ at++;
202
+ continue;
203
+ }
204
+ let end = at;
205
+ while (isNameChar(raw.charCodeAt(end))) end++;
206
+ let k = skipSpace(raw, end);
207
+ if (raw[k] === "=") {
208
+ k = skipSpace(raw, k + 1);
209
+ const close = raw[k] === "\"" ? raw.indexOf("\"", k + 1) : -1;
210
+ if (close >= 0) {
211
+ const name = raw.slice(at, end);
212
+ out[name.slice(name.lastIndexOf(":") + 1)] = raw.slice(k + 1, close);
213
+ at = close + 1;
214
+ continue;
215
+ }
216
+ }
217
+ at = end;
182
218
  }
183
219
  return out;
184
220
  }
221
+ var isAlnum = (c) => c >= 48 && c <= 57 || c >= 65 && c <= 90 || c >= 97 && c <= 122;
222
+ var isWordChar = (c) => isAlnum(c) || c === 95;
223
+ var isNameChar = (c) => isWordChar(c) || c === 58;
224
+ function skipSpace(s, from) {
225
+ let at = from;
226
+ while (at < s.length && /\s/u.test(s[at])) at++;
227
+ return at;
228
+ }
185
229
  function utf16le(s) {
186
230
  const out = new Uint8Array(s.length * 2);
187
231
  const v = new DataView(out.buffer);
@@ -5,4 +5,4 @@
5
5
  *
6
6
  * @packageDocumentation
7
7
  */
8
- export type { AbstractNumbering, Alignment, Border, BorderStyle, BodyElement, Comment, CellBorders, CellMerge, DocumentInfo, CellMargins, CellProperties, CellShading, CellDataBar, CellIcon, CellIconShape, CellSparkline, Chart, ChartBlock, ChartDataPoint, ChartLineStyle, ChartMarker, ChartMarkerSymbol, ChartSeries, ChartType, CustomGeometry, CustomPathCmd, DocumentModel, FontFamilyMap, HeaderFooterReference, HeaderFooterType, ImageBlock, ImageCrop, InlineImage, MathAccent, MathBar, MathDelimiter, MathEqArray, MathFraction, MathFunc, MathGroupChr, MathLimit, MathMatrix, MathNary, MathNode, MathRadical, MathRow, MathRun, MathScript, Numbering, NumberingFormat, NumberingInstance, NumberingLevel, PictureBullet, PictureOutline, NumberingReference, PageMargins, PageSize, Paragraph, ParagraphProperties, FrameProperties, RelativeSize, TabStop, Run, RunProperties, TextOutline, Ligatures, RowConditionalFormat, RowProperties, Section, FloatAnchor, SectionColumns, SectionProperties, ShapeBlock, ShapeShadow, ShapeDash, ShapeFill, ShapeFillKind, ShapeGeometry, ShapeGroupChild, ShapeLine, LineEnd, ShapeTextBody, ShapeTransform, Style, StyleSheet, StyleType, Table, TableCell, TableLook, TableProperties, TableStyleCondition, TableStyleConditionType, TableStyleLayer, TableRow, UnderlineStyle, VerticalAlign, } from './types.js';
8
+ export type { AbstractNumbering, Alignment, Border, BorderStyle, BodyElement, Comment, CellBorders, CellMerge, DocumentInfo, CellMargins, CellProperties, CellShading, CellDataBar, CellIcon, CellNoteFlag, CellIconShape, CellSparkline, Chart, ChartBlock, ChartDataPoint, ChartLineStyle, ChartMarker, ChartMarkerSymbol, ChartSeries, ChartType, CustomGeometry, CustomPathCmd, DocumentModel, FontFamilyMap, HeaderFooterReference, HeaderFooterType, ImageBlock, ImageCrop, InlineImage, MathAccent, MathBar, MathDelimiter, MathEqArray, MathFraction, MathFunc, MathGroupChr, MathLimit, MathMatrix, MathNary, MathNode, MathRadical, MathRow, MathRun, MathScript, Numbering, NumberingFormat, NumberingInstance, NumberingLevel, PictureBullet, PictureOutline, NumberingReference, PageMargins, PageSize, Paragraph, ParagraphProperties, FrameProperties, RelativeSize, TabStop, Run, RunProperties, TextOutline, Ligatures, RowConditionalFormat, RowProperties, Section, FloatAnchor, SectionColumns, SectionProperties, ShapeBlock, ShapeShadow, ShapeDash, ShapeFill, ShapeFillKind, ShapeGeometry, ShapeGroupChild, ShapeLine, LineEnd, ShapeTextBody, ShapeTransform, Style, StyleSheet, StyleType, Table, TableCell, TableLook, TableOverlay, TableProperties, TableStyleCondition, TableStyleConditionType, TableStyleLayer, TableRow, UnderlineStyle, VerticalAlign, } from './types.js';
@@ -731,6 +731,19 @@ export interface CellDataBar {
731
731
  * axis, and which way that is depends on the sign.
732
732
  */
733
733
  readonly negative?: boolean;
734
+ /** The bar is one solid colour, not faded from the axis (`<x14:dataBar gradient="0">`). */
735
+ readonly solid?: boolean;
736
+ }
737
+ /**
738
+ * How a window flags a cell that carries a note: red for a legacy note, purple
739
+ * for a threaded comment, in the top corner on the side the cell ends — the
740
+ * right, or the left on a sheet that reads from the right.
741
+ */
742
+ export interface CellNoteFlag {
743
+ readonly kind: 'note' | 'thread';
744
+ /** The note as one reads it on hover: author and text, a conversation line by line. */
745
+ readonly text: string;
746
+ readonly atLeft?: boolean;
734
747
  }
735
748
  /**
736
749
  * A conditional-format icon: a small glyph at the cell's left, chosen by the
@@ -801,6 +814,12 @@ export interface CellProperties {
801
814
  * what a merge wants.
802
815
  */
803
816
  readonly paintColumns?: number;
817
+ /**
818
+ * The paint covers the LAST {@link paintColumns} of the span rather than the
819
+ * first. A sheet that reads from the right runs a cell's text over the
820
+ * neighbours on its left, so the cell the paint belongs to ends the span.
821
+ */
822
+ readonly paintAtEnd?: boolean;
804
823
  readonly shading?: CellShading;
805
824
  readonly dataBar?: CellDataBar;
806
825
  readonly icon?: CellIcon;
@@ -810,6 +829,12 @@ export interface CellProperties {
810
829
  * dropdown affordance at the cell's right edge (a small button + ▾ glyph).
811
830
  */
812
831
  readonly dropdown?: boolean;
832
+ /**
833
+ * A note or comment on the cell, as a WINDOW flags it (E-SHEET W7): a small
834
+ * triangle in the cell's top corner, the note's text shown on hover where
835
+ * the medium can. Set by screen projections only — paper never shows it.
836
+ */
837
+ readonly noteFlag?: CellNoteFlag;
813
838
  /**
814
839
  * The cell's text is not allowed to wrap: it renders on one line and whatever
815
840
  * does not fit the cell box is cut, as a spreadsheet cell without `wrapText`
@@ -867,6 +892,13 @@ export interface RowProperties {
867
892
  * header row `w:firstRow="1"` so it is painted like the first.
868
893
  */
869
894
  readonly conditional?: RowConditionalFormat;
895
+ /**
896
+ * Where a spreadsheet row's top stands on its sheet, measured down from the
897
+ * sheet's first row in the frame its table's drawings are placed in (see
898
+ * {@link TableOverlay}). A row the sheet does not have — the printed column
899
+ * letters — carries none.
900
+ */
901
+ readonly sheetTopPt?: Pt;
870
902
  }
871
903
  /** §17.4.7 — the row-level conditional-format flags a `w:cnfStyle` declares. */
872
904
  export interface RowConditionalFormat {
@@ -900,6 +932,14 @@ export interface TableProperties {
900
932
  readonly layout?: 'auto' | 'fixed';
901
933
  readonly defaultCellMargins?: CellMargins;
902
934
  readonly borders?: CellBorders;
935
+ /**
936
+ * A worksheet's gridlines as its WINDOW draws them (§18.3.1.87), where the
937
+ * sheet was projected for a screen: the line a cell's edge takes when no
938
+ * border claims it — but not around a filled cell, whose fill covers them.
939
+ * A screen-only hint: the paginated layout draws a grid only where the
940
+ * sheet PRINTS one, and that comes as `borders`.
941
+ */
942
+ readonly gridlines?: Border;
903
943
  /**
904
944
  * ECMA-376 §17.4.27 (`w:jc`) / xlsx `<printOptions horizontalCentered>`.
905
945
  * Centers or right-aligns a table narrower than the content width; absent ⇒ left.
@@ -946,6 +986,32 @@ export interface Table {
946
986
  readonly properties: TableProperties;
947
987
  readonly grid: ReadonlyArray<Pt>;
948
988
  readonly rows: ReadonlyArray<TableRow>;
989
+ /** The drawings that lie over a spreadsheet grid and print with it. */
990
+ readonly overlay?: TableOverlay;
991
+ }
992
+ /**
993
+ * §20.5 — a spreadsheet's drawings over the part of the sheet one table
994
+ * prints. A drawing is anchored to cells, not to paper: each page the table
995
+ * spans shows the part of every drawing that lies over the rows and columns it
996
+ * prints, and cuts it off where they end — a chart across a page break is
997
+ * printed in two pieces, a drawing in the repeated title rows on every page,
998
+ * and what runs out of the print area not at all. Excel prints a sheet so.
999
+ */
1000
+ export interface TableOverlay {
1001
+ /** Where the sheet's columns this table prints begin, in the drawings' frame. */
1002
+ readonly sheetLeftPt: Pt;
1003
+ /** How wide those columns run. */
1004
+ readonly widthPt: Pt;
1005
+ /** Where they stand in the table, from its left edge (past a printed row-number column). */
1006
+ readonly leftPt: Pt;
1007
+ /** §18.3.1.87 — the sheet reads from the right: its first column stands at the right. */
1008
+ readonly mirrored?: boolean;
1009
+ /**
1010
+ * The drawings, out-of-flow floats placed in the sheet's own frame: `posH`
1011
+ * from the sheet's left edge, `posV` from its top, the frame of
1012
+ * {@link RowProperties.sheetTopPt}.
1013
+ */
1014
+ readonly drawings: ReadonlyArray<BodyElement>;
949
1015
  }
950
1016
  /**
951
1017
  * ECMA-376 Part 1 §20.4.2.8 — a block-level image (`wp:inline` picture extent).
@@ -1430,6 +1496,16 @@ export interface Chart {
1430
1496
  readonly categories: ReadonlyArray<string>;
1431
1497
  /** §21.2.2.24 `c:cat/…/c:f` — where the categories live, when uncached. */
1432
1498
  readonly categoriesRef?: string;
1499
+ /**
1500
+ * §21.2.2.115 `c:multiLvlStrCache` — the outer levels of a category axis
1501
+ * labelled on more than one: each level's groups, innermost level first,
1502
+ * each group from the category it starts at to the next group's start.
1503
+ * {@link Chart.categories} is the innermost level, one label per category.
1504
+ */
1505
+ readonly categoryGroups?: ReadonlyArray<ReadonlyArray<{
1506
+ readonly start: number;
1507
+ readonly label: string;
1508
+ }>>;
1433
1509
  readonly series: ReadonlyArray<ChartSeries>;
1434
1510
  readonly hasLegend: boolean;
1435
1511
  readonly legendPos?: 'r' | 'l' | 't' | 'b';
@@ -1450,6 +1526,27 @@ export interface Chart {
1450
1526
  * and we printed the ranking upside down).
1451
1527
  */
1452
1528
  readonly catAxisReversed?: boolean;
1529
+ /**
1530
+ * §21.2.2.33/§21.2.2.34 `c:catAx/c:crosses`, `c:crossesAt` — where along the
1531
+ * value axis the category axis lies, and so where bars grow from: at the
1532
+ * axis's minimum or maximum, or at a stated value. Absent ⇒ `autoZero`, at
1533
+ * zero (or the end of the value axis nearest it).
1534
+ */
1535
+ readonly catAxisCrosses?: 'min' | 'max' | number;
1536
+ /**
1537
+ * §21.2.2.207 `c:catAx/c:tickLblPos` — where the category labels stand: at
1538
+ * the low or high end of the value axis, or nowhere. Absent ⇒ `nextTo`,
1539
+ * beside the category axis wherever it crosses — on the zero line of a chart
1540
+ * with values below zero.
1541
+ */
1542
+ readonly catTickLabelPos?: 'low' | 'high' | 'none';
1543
+ /**
1544
+ * §21.2.2.33 `c:valAx/c:crosses` — where along the category axis the value
1545
+ * axis lies: at the last category (`max`) or the first (absent, `autoZero`).
1546
+ * The first is at the far end when the categories run backwards
1547
+ * ({@link Chart.catAxisReversed}): a ranked bar chart has its values on top.
1548
+ */
1549
+ readonly valAxisCrosses?: 'min' | 'max' | number;
1453
1550
  readonly valAxisTitle?: string;
1454
1551
  /** §21.2.2.168 — the title of the secondary value axis, when one is drawn. */
1455
1552
  readonly secondaryValAxisTitle?: string;
@@ -1480,6 +1577,11 @@ export interface Chart {
1480
1577
  */
1481
1578
  readonly valAxisMin?: number;
1482
1579
  readonly valAxisMax?: number;
1580
+ /**
1581
+ * §21.2.2.98 `c:valAx/c:majorUnit` — the step between the value axis's
1582
+ * labels, when the author fixed it. Absent ⇒ the application's own choice.
1583
+ */
1584
+ readonly valAxisMajorUnit?: number;
1483
1585
  /**
1484
1586
  * §21.2.2.198 `c:chartSpace/c:spPr` — the frame around the whole chart: its
1485
1587
  * background fill and its outline. Excel writes both on every chart it
@@ -1744,6 +1846,16 @@ export interface SectionColumns {
1744
1846
  export interface Section {
1745
1847
  readonly properties: SectionProperties;
1746
1848
  readonly endIndex: number;
1849
+ /**
1850
+ * The worksheet this section IS, where a workbook was projected for a screen
1851
+ * rather than for paper (`ProjectSheetOptions.screen`): its tab's name. Such
1852
+ * a section is one surface with no pages — the grid as Excel shows it — and
1853
+ * a float in it is placed from the surface's top-left corner, which is the
1854
+ * corner of the first cell.
1855
+ */
1856
+ readonly sheet?: {
1857
+ readonly name: string;
1858
+ };
1747
1859
  }
1748
1860
  /** The parsed WordprocessingML document: body, stylesheet, numbering and section setup. */
1749
1861
  export interface DocumentModel {
@@ -118,26 +118,49 @@ export interface Scale {
118
118
  readonly step: number;
119
119
  }
120
120
  /**
121
- * Compute a human-friendly axis {@link Scale} for the data range using
122
- * Heckbert's "nice numbers" algorithm: rounded endpoints and a 1/2/5·10ⁿ step
123
- * that yields about `maxTicks` ticks. A degenerate range (`dataMin === dataMax`)
124
- * is widened by 1 so the axis is non-empty.
121
+ * The scale Excel gives a value axis it is left to choose, measured against
122
+ * Excel's own PDF of its column charts (2026-10-01 and -02):
125
123
  *
126
- * @param dataMin The smallest data value to cover.
127
- * @param dataMax The largest data value to cover.
128
- * @param maxTicks Target upper bound on tick count (default 6).
124
+ * - the ends: values all of one sign put the axis's near end at zero —
125
+ * unless their spread is under a sixth of the largest of them, when it
126
+ * stops half a spread short of the nearest (93…97 runs from 91) — and the
127
+ * far end takes 5% of its reach from that near end before it is rounded
128
+ * out to the step. 70…96 reaches 100.8 and runs 0…120 by 20, where 5% of
129
+ * the data's own spread stopped at 97.3 and ran it 0…100 by 10. Both ends
130
+ * of a range across zero take 5% of the spread;
131
+ * - the step: the smallest 1, 2 or 5 × 10ⁿ that leaves at most ten intervals
132
+ * (`maxIntervals`), whatever the chart's height — 3 750 runs 0…4 000 by 500
133
+ * on a 150pt chart as on a 400pt one. Only an axis too short to hold the
134
+ * labels asks for fewer, and the caller says so.
135
+ *
136
+ * Every case of the probes lands where Excel puts it: −1…1.2 on −1.5…1.5 by
137
+ * 0.5, 0.3…4.7 on 0…5 by 0.5, 120…950 on 0…1 000 by 100, 0.012…0.047 on
138
+ * 0…0.05 by 0.005, 1E-150…3E-150 on 0…3.5E-150. Heckbert's nice numbers with
139
+ * a budget of ticks by height stepped the budget chart by 1 000 and started
140
+ * 93…97 at zero.
141
+ *
142
+ * @param dataMin The smallest value to cover.
143
+ * @param dataMax The largest value to cover.
144
+ * @param maxIntervals At most this many steps between the ends (default 10).
129
145
  * @returns The rounded min/max and tick step.
130
146
  */
131
- export declare function niceScale(dataMin: number, dataMax: number, maxTicks?: number): Scale;
147
+ export declare function niceScale(dataMin: number, dataMax: number, maxIntervals?: number): Scale;
132
148
  /**
133
- * Format an axis tick value, choosing decimal places from the tick `step` so
134
- * `0.25`-spaced ticks read `0.25` while integer steps drop the fraction.
149
+ * A value-axis tick as Excel labels it under General. An axis is not a cell:
150
+ * its General gives every label nine characters, the sign among them, on an
151
+ * axis 150pt or 500pt long, upright or lying alike — Excel's own PDF of 44
152
+ * axes (2026-10-01 and -02). Within them it is the cells' rule
153
+ * ({@link generalRenderings}): the number as it is where it fits (0.25 — we
154
+ * wrote 0.3 on an axis stepped by 0.25 — 500000000, −50000000, 0.0000003),
155
+ * else the finest of it rounded or in scientific notation (0.1234568,
156
+ * −0.123457, 123456771, 1E+09, 1.235E+09, −1.23E+09, 1.235E-05, 5E-151).
157
+ * Places counted from the step and written by `toFixed` threw past a hundred
158
+ * of them, which a step of 1E-150 asked for.
135
159
  *
136
- * @param v The tick value.
137
- * @param step The tick spacing (from {@link niceScale}).
160
+ * @param v The tick value.
138
161
  * @returns The label text.
139
162
  */
140
- export declare function formatTick(v: number, step: number): string;
163
+ export declare function formatTick(v: number): string;
141
164
  export declare function buildBarScene(chart: Chart, wPt: number, hPt: number, measure: MeasureText): ChartScene;
142
165
  /**
143
166
  * The name a series shows in the legend: its own `c:tx`, or Excel's positional