reamkit 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -8
- package/dist/esm/core/converter/facade.d.ts +12 -6
- package/dist/esm/core/converter/facade.js +34 -5
- package/dist/esm/core/converter/ream.d.ts +5 -3
- package/dist/esm/core/converter/ream.js +18 -4
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +26 -0
- package/dist/esm/core/drawingml/sparkline-geometry.d.ts +8 -0
- package/dist/esm/core/drawingml/sparkline-geometry.js +111 -0
- package/dist/esm/core/ir/adapters.d.ts +5 -5
- package/dist/esm/core/ir/sheet.d.ts +31 -0
- package/dist/esm/core/opc/relationships.js +1 -0
- package/dist/esm/core/spreadsheet-model/index.d.ts +1 -0
- package/dist/esm/core/spreadsheet-model/types.d.ts +189 -0
- package/dist/esm/excel/column-bands.d.ts +7 -0
- package/dist/esm/excel/column-bands.js +87 -0
- package/dist/esm/excel/conditional-format.d.ts +16 -0
- package/dist/esm/excel/conditional-format.js +327 -0
- package/dist/esm/excel/index.d.ts +4 -3
- package/dist/esm/excel/print-model.d.ts +2 -1
- package/dist/esm/excel/print-model.js +144 -13
- package/dist/esm/excel/sheet-drawing.d.ts +1 -1
- package/dist/esm/excel/sheet-to-flow.d.ts +3 -0
- package/dist/esm/excel/sheet-to-flow.js +51 -0
- package/dist/esm/excel/styles-parser.d.ts +1 -50
- package/dist/esm/excel/styles-parser.js +38 -1
- package/dist/esm/excel/table-parser.d.ts +2 -0
- package/dist/esm/excel/table-parser.js +51 -0
- package/dist/esm/excel/workbook-parser.d.ts +1 -5
- package/dist/esm/excel/worksheet-parser.d.ts +1 -60
- package/dist/esm/excel/worksheet-parser.js +265 -1
- package/dist/esm/excel/xlsx-reader.d.ts +3 -1
- package/dist/esm/excel/xlsx-reader.js +86 -51
- package/dist/esm/excel/xlsx-writer.d.ts +4 -0
- package/dist/esm/excel/xlsx-writer.js +278 -0
- package/dist/esm/html/html-writer.js +126 -4
- package/dist/esm/layout/styled-layout.js +160 -1
- package/dist/esm/pdf-reader/cmap.d.ts +5 -0
- package/dist/esm/pdf-reader/cmap.js +72 -0
- package/dist/esm/pdf-reader/content.d.ts +14 -0
- package/dist/esm/pdf-reader/content.js +292 -0
- package/dist/esm/pdf-reader/document.d.ts +23 -0
- package/dist/esm/pdf-reader/document.js +230 -0
- package/dist/esm/pdf-reader/flow-build.d.ts +4 -0
- package/dist/esm/pdf-reader/flow-build.js +27 -0
- package/dist/esm/pdf-reader/font.d.ts +4 -0
- package/dist/esm/pdf-reader/font.js +69 -0
- package/dist/esm/pdf-reader/layout.d.ts +3 -0
- package/dist/esm/pdf-reader/layout.js +69 -0
- package/dist/esm/pdf-reader/lexer.d.ts +43 -0
- package/dist/esm/pdf-reader/lexer.js +250 -0
- package/dist/esm/pdf-reader/parser.d.ts +10 -0
- package/dist/esm/pdf-reader/parser.js +86 -0
- package/dist/esm/pdf-reader/reader.d.ts +4 -0
- package/dist/esm/pdf-reader/reader.js +43 -0
- package/dist/esm/pdf-reader/struct-tree.d.ts +14 -0
- package/dist/esm/pdf-reader/struct-tree.js +92 -0
- package/dist/esm/pdf-reader/tagged.d.ts +3 -0
- package/dist/esm/pdf-reader/tagged.js +88 -0
- package/dist/esm/pdf-reader/text.d.ts +3 -0
- package/dist/esm/pdf-reader/text.js +18 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -30,11 +30,12 @@ import { Ream } from 'reamkit';
|
|
|
30
30
|
// e.g. from an <input type="file"> or a fetch() — anything that yields bytes.
|
|
31
31
|
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
32
32
|
|
|
33
|
-
const doc = Ream.parse(bytes); // docx or
|
|
33
|
+
const doc = Ream.parse(bytes); // docx, xlsx or pdf — sniffed
|
|
34
34
|
const pdf = await doc.convert('pdf'); // async — fetches a font if needed
|
|
35
35
|
const svg = await doc.convert('svg'); // same parse, different target
|
|
36
36
|
const html = await doc.convert('html'); // flowed HTML — needs no fonts at all
|
|
37
37
|
const docx = await doc.convert('docx'); // write WordprocessingML back out
|
|
38
|
+
const xlsx = await doc.convert('xlsx'); // write SpreadsheetML back (xlsx source)
|
|
38
39
|
|
|
39
40
|
// Hand the bytes to the browser: preview, download, upload, …
|
|
40
41
|
const url = URL.createObjectURL(new Blob([pdf], { type: 'application/pdf' }));
|
|
@@ -129,7 +130,7 @@ rendering — inspect or analyze it without converting:
|
|
|
129
130
|
|
|
130
131
|
```ts
|
|
131
132
|
const doc = Ream.parse(bytes);
|
|
132
|
-
doc.format; // 'docx' | 'xlsx'
|
|
133
|
+
doc.format; // 'docx' | 'xlsx' | 'pdf'
|
|
133
134
|
doc.flow.body; // paragraphs / tables / images / charts …
|
|
134
135
|
doc.losses; // read-time losses
|
|
135
136
|
```
|
|
@@ -166,14 +167,15 @@ multi-section and multi-column layout/headers-footers (incl. PAGE/NUMPAGES
|
|
|
166
167
|
fields)/footnotes and endnotes/hyperlinks and bookmarks/floating drawings/
|
|
167
168
|
images/tracked changes, SpreadsheetML grids,
|
|
168
169
|
number formats and the print model (gridlines, print area, fit-to-page,
|
|
169
|
-
repeated titles, page breaks),
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
170
|
+
repeated titles, page breaks), **conditional formatting** (color scales, data
|
|
171
|
+
bars, icon sets), **sparklines** and **Excel tables**, DrawingML shapes and
|
|
172
|
+
charts, OMML math, Type0+CIDFontType2 embedding with subsetting, Knuth-Plass
|
|
173
|
+
line breaking, Liang hyphenation, OpenType ligatures/kerning + Arabic cursive
|
|
174
|
+
joining, BiDi (UAX #9), hyperlinks (PDF link annotations + HTML anchors,
|
|
173
175
|
scheme-allowlisted), tagged PDF, PDF/A-1/2/3 (a/b/u), PDF/UA-1, AES-256
|
|
174
176
|
encryption, digital signatures (PKCS#7/ECDSA/PAdES/RFC 3161), SVG page
|
|
175
|
-
preview, flowed HTML export, and **docx output** (write WordprocessingML
|
|
176
|
-
out, incl.
|
|
177
|
+
preview, flowed HTML export, and **docx + xlsx output** (write WordprocessingML
|
|
178
|
+
/ SpreadsheetML back out, incl. round-trips). Reads OOXML Transitional and Strict.
|
|
177
179
|
|
|
178
180
|
See `handoff.md` for the full feature matrix and known limitations.
|
|
179
181
|
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { ConvertDocxOptions } from '../../word/docx-to-pdf.js';
|
|
2
2
|
import { DocumentReader } from '../ir/adapters.js';
|
|
3
3
|
import { FlowDoc } from '../ir/flow.js';
|
|
4
|
+
import { SheetDoc } from '../ir/sheet.js';
|
|
4
5
|
import { FontProvider } from '../fonts/provider.js';
|
|
5
6
|
import { Loss, LossReport } from '../ir/index.js';
|
|
6
7
|
import { FontBytesByVariant } from '../font/index.js';
|
|
7
8
|
export interface ConvertOptions extends ConvertDocxOptions {
|
|
8
|
-
/**
|
|
9
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Target: 'pdf' (default), 'svg' (page-stack preview), 'html'/'docx' (flowed),
|
|
11
|
+
* or 'xlsx' (the native grid writer — spreadsheet input only).
|
|
12
|
+
*/
|
|
13
|
+
readonly to?: 'pdf' | 'svg' | 'html' | 'docx' | 'xlsx';
|
|
10
14
|
/**
|
|
11
15
|
* Strict mode (handoff v1 §5): throw ConversionLossError on the first
|
|
12
16
|
* recorded loss instead of returning it in the report.
|
|
@@ -26,18 +30,20 @@ export interface ConvertResult {
|
|
|
26
30
|
readonly bytes: Uint8Array;
|
|
27
31
|
readonly losses: LossReport;
|
|
28
32
|
}
|
|
33
|
+
export type SourceDoc = FlowDoc | SheetDoc;
|
|
34
|
+
export declare function toFlowDoc(doc: SourceDoc): FlowDoc;
|
|
29
35
|
export interface Converter {
|
|
30
36
|
/** The registered readers, in sniffing order. */
|
|
31
|
-
readonly readers: ReadonlyArray<DocumentReader<
|
|
37
|
+
readonly readers: ReadonlyArray<DocumentReader<SourceDoc>>;
|
|
32
38
|
/** Detect the input format by reader sniffing; undefined when unknown. */
|
|
33
|
-
detect: (bytes: Uint8Array) => DocumentReader<
|
|
39
|
+
detect: (bytes: Uint8Array) => DocumentReader<SourceDoc> | undefined;
|
|
34
40
|
convert: (bytes: Uint8Array, options?: ConvertOptions) => Promise<ConvertResult>;
|
|
35
41
|
}
|
|
36
42
|
export interface CreateConverterOptions {
|
|
37
43
|
/** Override / extend the reader registry (defaults to docx + xlsx). */
|
|
38
|
-
readonly readers?: ReadonlyArray<DocumentReader<
|
|
44
|
+
readonly readers?: ReadonlyArray<DocumentReader<SourceDoc>>;
|
|
39
45
|
}
|
|
40
|
-
export declare const DEFAULT_READERS: ReadonlyArray<DocumentReader<
|
|
46
|
+
export declare const DEFAULT_READERS: ReadonlyArray<DocumentReader<SourceDoc>>;
|
|
41
47
|
export declare function createConverter(opts?: CreateConverterOptions): Converter;
|
|
42
48
|
export declare function resolveFontsViaChain(providers: ReadonlyArray<FontProvider>): Promise<{
|
|
43
49
|
fonts?: FontBytesByVariant;
|
|
@@ -3,16 +3,33 @@ import { FEATURES } from "../ir/features.js";
|
|
|
3
3
|
import { ConversionLossError } from "../ir/loss.js";
|
|
4
4
|
import { layoutStyledDocument } from "../../layout/styled-layout.js";
|
|
5
5
|
import { docxReader } from "../../word/docx-reader.js";
|
|
6
|
+
import { projectSheetDoc } from "../../excel/sheet-to-flow.js";
|
|
6
7
|
import { xlsxReader } from "../../excel/xlsx-reader.js";
|
|
7
8
|
import { chainProviders } from "../fonts/provider.js";
|
|
8
9
|
import { flowRenderOptions } from "./project.js";
|
|
9
10
|
import { writeDocx } from "../../word/docx-writer.js";
|
|
11
|
+
import { writeXlsx } from "../../excel/xlsx-writer.js";
|
|
10
12
|
import { writeHtml } from "../../html/html-writer.js";
|
|
11
13
|
import { writeSvg } from "../../svg/svg-writer.js";
|
|
12
14
|
import { convertDocxToPdf } from "../../word/docx-to-pdf.js";
|
|
13
15
|
import { convertXlsxToPdf } from "../../excel/xlsx-to-pdf.js";
|
|
16
|
+
import { pdfReader } from "../../pdf-reader/reader.js";
|
|
14
17
|
//#region src/core/converter/facade.ts
|
|
15
|
-
|
|
18
|
+
function toFlowDoc(doc) {
|
|
19
|
+
return doc.kind === "sheet" ? projectSheetDoc(doc) : doc;
|
|
20
|
+
}
|
|
21
|
+
function readToFlow(reader, bytes) {
|
|
22
|
+
const { doc, losses } = reader.read(bytes);
|
|
23
|
+
return {
|
|
24
|
+
doc: toFlowDoc(doc),
|
|
25
|
+
losses
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
var DEFAULT_READERS = [
|
|
29
|
+
docxReader,
|
|
30
|
+
xlsxReader,
|
|
31
|
+
pdfReader
|
|
32
|
+
];
|
|
16
33
|
function createConverter(opts = {}) {
|
|
17
34
|
const readers = opts.readers ?? DEFAULT_READERS;
|
|
18
35
|
const detect = (bytes) => readers.find((r) => r.sniff(bytes));
|
|
@@ -22,7 +39,7 @@ function createConverter(opts = {}) {
|
|
|
22
39
|
if (!reader) throw new Error("Unrecognized input format (no registered reader sniffs these bytes)");
|
|
23
40
|
const losses = [];
|
|
24
41
|
if (to === "docx") {
|
|
25
|
-
const { doc: flow, losses: readLosses } = reader
|
|
42
|
+
const { doc: flow, losses: readLosses } = readToFlow(reader, bytes);
|
|
26
43
|
losses.push(...readLosses);
|
|
27
44
|
const out = writeDocx(flow);
|
|
28
45
|
losses.push(...out.losses);
|
|
@@ -33,7 +50,7 @@ function createConverter(opts = {}) {
|
|
|
33
50
|
};
|
|
34
51
|
}
|
|
35
52
|
if (to === "html") {
|
|
36
|
-
const { doc: flow, losses: readLosses } = reader
|
|
53
|
+
const { doc: flow, losses: readLosses } = readToFlow(reader, bytes);
|
|
37
54
|
losses.push(...readLosses);
|
|
38
55
|
const html = writeHtml(flow);
|
|
39
56
|
losses.push(...html.losses);
|
|
@@ -43,6 +60,18 @@ function createConverter(opts = {}) {
|
|
|
43
60
|
losses
|
|
44
61
|
};
|
|
45
62
|
}
|
|
63
|
+
if (to === "xlsx") {
|
|
64
|
+
const { doc, losses: readLosses } = reader.read(bytes);
|
|
65
|
+
losses.push(...readLosses);
|
|
66
|
+
if (doc.kind !== "sheet") throw new Error("to: 'xlsx' requires a spreadsheet input; a flow document has no grid");
|
|
67
|
+
const out = writeXlsx(doc);
|
|
68
|
+
losses.push(...out.losses);
|
|
69
|
+
if (strict && losses.length > 0) throw new ConversionLossError(losses[0]);
|
|
70
|
+
return {
|
|
71
|
+
bytes: out.bytes,
|
|
72
|
+
losses
|
|
73
|
+
};
|
|
74
|
+
}
|
|
46
75
|
let conv = rest;
|
|
47
76
|
if (fontProviders && fontProviders.length > 0 && !rest.fonts && !rest.fontBytes) {
|
|
48
77
|
const { fonts, loss } = await resolveFontsViaChain(fontProviders);
|
|
@@ -55,7 +84,7 @@ function createConverter(opts = {}) {
|
|
|
55
84
|
if (to === "svg") {
|
|
56
85
|
const fonts = conv.fonts ?? (conv.fontBytes ? { regular: conv.fontBytes } : void 0);
|
|
57
86
|
if (!fonts) throw new Error("to: 'svg' requires options.fonts/fontBytes or fontProviders");
|
|
58
|
-
const { doc: flow } = reader
|
|
87
|
+
const { doc: flow } = readToFlow(reader, bytes);
|
|
59
88
|
const svg = writeSvg(layoutStyledDocument(flow.body, {
|
|
60
89
|
registry: FontRegistry.fromBytes(fonts),
|
|
61
90
|
...flowRenderOptions(flow)
|
|
@@ -110,4 +139,4 @@ async function resolveFontsViaChain(providers) {
|
|
|
110
139
|
};
|
|
111
140
|
}
|
|
112
141
|
//#endregion
|
|
113
|
-
export { DEFAULT_READERS, createConverter, resolveFontsViaChain };
|
|
142
|
+
export { DEFAULT_READERS, createConverter, resolveFontsViaChain, toFlowDoc };
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { ConvertResult } from './facade.js';
|
|
1
|
+
import { ConvertResult, SourceDoc } from './facade.js';
|
|
2
2
|
import { FontBytesByVariant } from '../font/index.js';
|
|
3
3
|
import { FetchLike } from '../fonts/index.js';
|
|
4
4
|
import { FontProvider } from '../fonts/provider.js';
|
|
5
5
|
import { Loss } from '../ir/index.js';
|
|
6
6
|
import { DocumentReader } from '../ir/adapters.js';
|
|
7
7
|
import { FlowDoc } from '../ir/flow.js';
|
|
8
|
+
import { SheetDoc } from '../ir/sheet.js';
|
|
8
9
|
import { SignatureOptions, StyledRenderOptions } from '../../pdf/index.js';
|
|
9
|
-
export type ReamTarget = 'pdf' | 'svg' | 'html' | 'docx';
|
|
10
|
+
export type ReamTarget = 'pdf' | 'svg' | 'html' | 'docx' | 'xlsx';
|
|
10
11
|
export interface ReamParseOptions {
|
|
11
|
-
readonly readers?: ReadonlyArray<DocumentReader
|
|
12
|
+
readonly readers?: ReadonlyArray<DocumentReader<SourceDoc>>;
|
|
12
13
|
}
|
|
13
14
|
export interface ReamConvertOptions extends Omit<StyledRenderOptions, 'registry' | 'styles'> {
|
|
14
15
|
readonly fonts?: FontBytesByVariant;
|
|
@@ -22,6 +23,7 @@ export interface ReamConvertOptions extends Omit<StyledRenderOptions, 'registry'
|
|
|
22
23
|
}
|
|
23
24
|
export declare class Ream {
|
|
24
25
|
readonly flow: FlowDoc;
|
|
26
|
+
readonly sheet: SheetDoc | undefined;
|
|
25
27
|
readonly losses: ReadonlyArray<Loss>;
|
|
26
28
|
private readonly source;
|
|
27
29
|
private readonly readerId;
|
|
@@ -7,18 +7,21 @@ import { renderStyledPdf, renderStyledPdfEncrypted } from "../../pdf/styled-page
|
|
|
7
7
|
import "../../pdf/index.js";
|
|
8
8
|
import { flowRenderOptions } from "./project.js";
|
|
9
9
|
import { writeDocx } from "../../word/docx-writer.js";
|
|
10
|
+
import { writeXlsx } from "../../excel/xlsx-writer.js";
|
|
10
11
|
import { writeHtml } from "../../html/html-writer.js";
|
|
11
12
|
import { writeSvg } from "../../svg/svg-writer.js";
|
|
12
13
|
import { resolveDocxAutoFonts } from "../../word/docx-to-pdf.js";
|
|
13
|
-
import { DEFAULT_READERS, resolveFontsViaChain } from "./facade.js";
|
|
14
|
+
import { DEFAULT_READERS, resolveFontsViaChain, toFlowDoc } from "./facade.js";
|
|
14
15
|
//#region src/core/converter/ream.ts
|
|
15
16
|
var SOURCE_MIME = {
|
|
16
17
|
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
17
|
-
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
18
|
+
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
19
|
+
pdf: "application/pdf"
|
|
18
20
|
};
|
|
19
21
|
var Ream = class Ream {
|
|
20
|
-
constructor(flow, losses, source, readerId) {
|
|
22
|
+
constructor(flow, sheet, losses, source, readerId) {
|
|
21
23
|
this.flow = flow;
|
|
24
|
+
this.sheet = sheet;
|
|
22
25
|
this.losses = losses;
|
|
23
26
|
this.source = source;
|
|
24
27
|
this.readerId = readerId;
|
|
@@ -28,7 +31,8 @@ var Ream = class Ream {
|
|
|
28
31
|
const reader = readers.find((r) => r.sniff(bytes));
|
|
29
32
|
if (!reader) throw new Error(`Unrecognized document format (readers: ${readers.map((r) => r.id).join(", ")})`);
|
|
30
33
|
const { doc, losses } = reader.read(bytes);
|
|
31
|
-
|
|
34
|
+
const sheet = doc.kind === "sheet" ? doc : void 0;
|
|
35
|
+
return new Ream(toFlowDoc(doc), sheet, losses, bytes, reader.id);
|
|
32
36
|
}
|
|
33
37
|
get format() {
|
|
34
38
|
return this.readerId;
|
|
@@ -56,6 +60,16 @@ var Ream = class Ream {
|
|
|
56
60
|
losses
|
|
57
61
|
};
|
|
58
62
|
}
|
|
63
|
+
if (to === "xlsx") {
|
|
64
|
+
if (!this.sheet) throw new Error("convert('xlsx') requires a spreadsheet source; this document has no grid");
|
|
65
|
+
const xlsx = writeXlsx(this.sheet);
|
|
66
|
+
losses.push(...xlsx.losses);
|
|
67
|
+
this.enforceStrict(options, losses);
|
|
68
|
+
return {
|
|
69
|
+
bytes: xlsx.bytes,
|
|
70
|
+
losses
|
|
71
|
+
};
|
|
72
|
+
}
|
|
59
73
|
const { fonts, registriesByFamily } = await this.resolveFonts(options, losses);
|
|
60
74
|
const registry = FontRegistry.fromBytes(fonts);
|
|
61
75
|
if (to === "svg") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export type { AbstractNumbering, Alignment, Border, BorderStyle, BodyElement, CellBorders, CellMerge, DocumentInfo, CellMargins, CellProperties, CellShading, Chart, ChartBlock, ChartDataPoint, ChartSeries, ChartType, CustomGeometry, CustomPathCmd, DocumentModel, FontFamilyMap, HeaderFooterReference, HeaderFooterType, ImageBlock, InlineImage, MathAccent, MathBar, MathDelimiter, MathEqArray, MathFraction, MathFunc, MathGroupChr, MathLimit, MathMatrix, MathNary, MathNode, MathRadical, MathRow, MathRun, MathScript, Numbering, NumberingFormat, NumberingInstance, NumberingLevel, NumberingReference, PageMargins, PageSize, Paragraph, ParagraphProperties, Run, RunProperties, RowProperties, Section, FloatAnchor, SectionColumns, SectionProperties, ShapeBlock, ShapeDash, ShapeFill, ShapeFillKind, ShapeGeometry, ShapeLine, ShapeTextBody, ShapeTransform, Style, StyleSheet, StyleType, Table, TableCell, TableLook, TableProperties, TableStyleCondition, TableStyleConditionType, TableStyleLayer, TableRow, UnderlineStyle, VerticalAlign, } from './types.js';
|
|
1
|
+
export type { AbstractNumbering, Alignment, Border, BorderStyle, BodyElement, CellBorders, CellMerge, DocumentInfo, CellMargins, CellProperties, CellShading, CellDataBar, CellIcon, CellIconShape, CellSparkline, Chart, ChartBlock, ChartDataPoint, ChartSeries, ChartType, CustomGeometry, CustomPathCmd, DocumentModel, FontFamilyMap, HeaderFooterReference, HeaderFooterType, ImageBlock, InlineImage, MathAccent, MathBar, MathDelimiter, MathEqArray, MathFraction, MathFunc, MathGroupChr, MathLimit, MathMatrix, MathNary, MathNode, MathRadical, MathRow, MathRun, MathScript, Numbering, NumberingFormat, NumberingInstance, NumberingLevel, NumberingReference, PageMargins, PageSize, Paragraph, ParagraphProperties, Run, RunProperties, RowProperties, Section, FloatAnchor, SectionColumns, SectionProperties, ShapeBlock, ShapeDash, ShapeFill, ShapeFillKind, ShapeGeometry, ShapeLine, ShapeTextBody, ShapeTransform, Style, StyleSheet, StyleType, Table, TableCell, TableLook, TableProperties, TableStyleCondition, TableStyleConditionType, TableStyleLayer, TableRow, UnderlineStyle, VerticalAlign, } from './types.js';
|
|
@@ -221,6 +221,25 @@ export interface CellMargins {
|
|
|
221
221
|
export interface CellShading {
|
|
222
222
|
readonly colorHex: string;
|
|
223
223
|
}
|
|
224
|
+
export interface CellDataBar {
|
|
225
|
+
readonly fraction: number;
|
|
226
|
+
readonly colorHex: string;
|
|
227
|
+
readonly startFraction?: number;
|
|
228
|
+
}
|
|
229
|
+
export type CellIconShape = 'circle' | 'square' | 'diamond' | 'triangleUp' | 'triangleDown' | 'triangleRight' | 'check' | 'cross' | 'exclamation' | 'bars' | 'pie';
|
|
230
|
+
export interface CellIcon {
|
|
231
|
+
readonly shape: CellIconShape;
|
|
232
|
+
readonly colorHex: string;
|
|
233
|
+
readonly fill?: {
|
|
234
|
+
readonly filled: number;
|
|
235
|
+
readonly levels: number;
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
export interface CellSparkline {
|
|
239
|
+
readonly kind: 'line' | 'column' | 'winLoss';
|
|
240
|
+
readonly values: ReadonlyArray<number | null>;
|
|
241
|
+
readonly colorHex?: string;
|
|
242
|
+
}
|
|
224
243
|
export type CellMerge = 'start' | 'middle' | 'end';
|
|
225
244
|
export interface CellProperties {
|
|
226
245
|
readonly width?: Pt;
|
|
@@ -229,6 +248,9 @@ export interface CellProperties {
|
|
|
229
248
|
readonly borders?: CellBorders;
|
|
230
249
|
readonly margins?: CellMargins;
|
|
231
250
|
readonly shading?: CellShading;
|
|
251
|
+
readonly dataBar?: CellDataBar;
|
|
252
|
+
readonly icon?: CellIcon;
|
|
253
|
+
readonly sparkline?: CellSparkline;
|
|
232
254
|
}
|
|
233
255
|
export interface RowProperties {
|
|
234
256
|
readonly height?: Pt;
|
|
@@ -255,6 +277,10 @@ export interface TableProperties {
|
|
|
255
277
|
readonly defaultCellMargins?: CellMargins;
|
|
256
278
|
readonly borders?: CellBorders;
|
|
257
279
|
readonly alignment?: 'left' | 'center' | 'right';
|
|
280
|
+
readonly frozen?: {
|
|
281
|
+
readonly rows: number;
|
|
282
|
+
readonly cols: number;
|
|
283
|
+
};
|
|
258
284
|
}
|
|
259
285
|
export interface TableCell {
|
|
260
286
|
readonly properties: CellProperties;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { StrokeStyle, VectorPath } from '../vector.js';
|
|
2
|
+
export type SparklineKind = 'line' | 'column' | 'winLoss';
|
|
3
|
+
export interface SparklinePrim {
|
|
4
|
+
readonly paths: ReadonlyArray<VectorPath>;
|
|
5
|
+
readonly fillColorHex?: string;
|
|
6
|
+
readonly stroke?: StrokeStyle;
|
|
7
|
+
}
|
|
8
|
+
export declare function buildSparkline(kind: SparklineKind, values: ReadonlyArray<number | null>, width: number, height: number, colorHex?: string): Array<SparklinePrim>;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { PathBuilder } from "../vector.js";
|
|
2
|
+
//#region src/core/drawingml/sparkline-geometry.ts
|
|
3
|
+
var DEFAULT_SERIES_HEX = "376092";
|
|
4
|
+
var LOSS_HEX = "D00000";
|
|
5
|
+
function buildSparkline(kind, values, width, height, colorHex) {
|
|
6
|
+
if (width <= 0 || height <= 0 || values.every((v) => v === null)) return [];
|
|
7
|
+
const color = colorHex ?? DEFAULT_SERIES_HEX;
|
|
8
|
+
switch (kind) {
|
|
9
|
+
case "line": return lineSpark(values, width, height, color);
|
|
10
|
+
case "column": return columnSpark(values, width, height, color);
|
|
11
|
+
case "winLoss": return winLossSpark(values, width, height, color);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function lineSpark(values, w, h, color) {
|
|
15
|
+
const n = values.length;
|
|
16
|
+
const pad = Math.min(1, h * .12);
|
|
17
|
+
const { min, span } = extent(values);
|
|
18
|
+
const x = (i) => n === 1 ? w / 2 : i / (n - 1) * w;
|
|
19
|
+
const y = (v) => pad + (v - min) / span * (h - 2 * pad);
|
|
20
|
+
const b = new PathBuilder();
|
|
21
|
+
let penDown = false;
|
|
22
|
+
for (let i = 0; i < n; i++) {
|
|
23
|
+
const v = values[i];
|
|
24
|
+
if (v === null || v === void 0) {
|
|
25
|
+
penDown = false;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (penDown) b.lineTo(x(i), y(v));
|
|
29
|
+
else {
|
|
30
|
+
b.moveTo(x(i), y(v));
|
|
31
|
+
penDown = true;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return [{
|
|
35
|
+
paths: [b.build()],
|
|
36
|
+
stroke: {
|
|
37
|
+
colorHex: color,
|
|
38
|
+
widthPt: .75,
|
|
39
|
+
join: "round"
|
|
40
|
+
}
|
|
41
|
+
}];
|
|
42
|
+
}
|
|
43
|
+
function columnSpark(values, w, h, color) {
|
|
44
|
+
const n = values.length;
|
|
45
|
+
const { min, span } = extent(values);
|
|
46
|
+
const slot = w / n;
|
|
47
|
+
const bw = slot * .72;
|
|
48
|
+
const off = (slot - bw) / 2;
|
|
49
|
+
const pad = h * .06;
|
|
50
|
+
const paths = [];
|
|
51
|
+
for (let i = 0; i < n; i++) {
|
|
52
|
+
const v = values[i];
|
|
53
|
+
if (v === null || v === void 0) continue;
|
|
54
|
+
const frac = (v - min) / span;
|
|
55
|
+
const bh = Math.max(.4, pad + frac * (h - pad));
|
|
56
|
+
paths.push(rectPath(i * slot + off, 0, bw, bh));
|
|
57
|
+
}
|
|
58
|
+
return paths.length > 0 ? [{
|
|
59
|
+
paths,
|
|
60
|
+
fillColorHex: color
|
|
61
|
+
}] : [];
|
|
62
|
+
}
|
|
63
|
+
function winLossSpark(values, w, h, color) {
|
|
64
|
+
const n = values.length;
|
|
65
|
+
const slot = w / n;
|
|
66
|
+
const bw = slot * .72;
|
|
67
|
+
const off = (slot - bw) / 2;
|
|
68
|
+
const mid = h / 2;
|
|
69
|
+
const barH = h * .4;
|
|
70
|
+
const wins = [];
|
|
71
|
+
const losses = [];
|
|
72
|
+
for (let i = 0; i < n; i++) {
|
|
73
|
+
const v = values[i];
|
|
74
|
+
if (v === null || v === void 0 || v === 0) continue;
|
|
75
|
+
const x = i * slot + off;
|
|
76
|
+
if (v > 0) wins.push(rectPath(x, mid, bw, barH));
|
|
77
|
+
else losses.push(rectPath(x, mid - barH, bw, barH));
|
|
78
|
+
}
|
|
79
|
+
const out = [];
|
|
80
|
+
if (wins.length > 0) out.push({
|
|
81
|
+
paths: wins,
|
|
82
|
+
fillColorHex: color
|
|
83
|
+
});
|
|
84
|
+
if (losses.length > 0) out.push({
|
|
85
|
+
paths: losses,
|
|
86
|
+
fillColorHex: LOSS_HEX
|
|
87
|
+
});
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
function extent(values) {
|
|
91
|
+
let min = Infinity;
|
|
92
|
+
let max = -Infinity;
|
|
93
|
+
for (const v of values) {
|
|
94
|
+
if (v === null) continue;
|
|
95
|
+
if (v < min) min = v;
|
|
96
|
+
if (v > max) max = v;
|
|
97
|
+
}
|
|
98
|
+
if (min === Infinity) return {
|
|
99
|
+
min: 0,
|
|
100
|
+
span: 1
|
|
101
|
+
};
|
|
102
|
+
return {
|
|
103
|
+
min,
|
|
104
|
+
span: max - min || 1
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function rectPath(x, y, w, h) {
|
|
108
|
+
return new PathBuilder().moveTo(x, y).lineTo(x + w, y).lineTo(x + w, y + h).lineTo(x, y + h).close().build();
|
|
109
|
+
}
|
|
110
|
+
//#endregion
|
|
111
|
+
export { buildSparkline };
|
|
@@ -12,8 +12,8 @@ export interface ReadResult<TDoc> {
|
|
|
12
12
|
export interface DocumentReader<TDoc = FlowDoc> {
|
|
13
13
|
/** Format id: 'docx', 'xlsx', 'pdf', … */
|
|
14
14
|
readonly id: string;
|
|
15
|
-
/** Which tree this reader produces. */
|
|
16
|
-
readonly produces: 'flow' | 'page';
|
|
15
|
+
/** Which tree this reader produces ('sheet' projects to flow at the boundary). */
|
|
16
|
+
readonly produces: 'flow' | 'page' | 'sheet';
|
|
17
17
|
/** Feature vocabulary this reader understands (capability matrix source). */
|
|
18
18
|
readonly supports: ReadonlySet<Feature>;
|
|
19
19
|
/** Cheap format detection (magic bytes / container markers). */
|
|
@@ -28,10 +28,10 @@ export interface WriteResult {
|
|
|
28
28
|
readonly losses: LossReport;
|
|
29
29
|
}
|
|
30
30
|
export interface DocumentWriter<TDoc> {
|
|
31
|
-
/** Output format id: 'pdf', 'svg', 'html', 'docx', … */
|
|
31
|
+
/** Output format id: 'pdf', 'svg', 'html', 'docx', 'xlsx', … */
|
|
32
32
|
readonly id: string;
|
|
33
|
-
/** Which tree this writer consumes. */
|
|
34
|
-
readonly consumes: 'flow' | 'page';
|
|
33
|
+
/** Which tree this writer consumes ('sheet' for the native grid writer). */
|
|
34
|
+
readonly consumes: 'flow' | 'page' | 'sheet';
|
|
35
35
|
readonly supports: ReadonlySet<Feature>;
|
|
36
36
|
write: (doc: TDoc, opts?: WriteOptions) => WriteResult;
|
|
37
37
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Chart, DocumentInfo } from '../document-model/index.js';
|
|
2
|
+
import { DefinedName, ParsedWorksheet, XlsxStyles } from '../spreadsheet-model/index.js';
|
|
3
|
+
import { ResourceStore } from './resources.js';
|
|
4
|
+
export interface SheetChartRef {
|
|
5
|
+
readonly chartPartPath: string;
|
|
6
|
+
readonly widthPt: number;
|
|
7
|
+
readonly heightPt: number;
|
|
8
|
+
}
|
|
9
|
+
export interface Sheet {
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly grid: ParsedWorksheet;
|
|
12
|
+
readonly charts?: ReadonlyArray<SheetChartRef>;
|
|
13
|
+
}
|
|
14
|
+
export interface SheetDoc {
|
|
15
|
+
readonly kind: 'sheet';
|
|
16
|
+
readonly sheets: ReadonlyArray<Sheet>;
|
|
17
|
+
/** §18.8 workbook style table (cellXfs + fonts/fills/borders/numFmts). */
|
|
18
|
+
readonly styles: XlsxStyles;
|
|
19
|
+
/** §18.4 shared string table; a cell with type 's' indexes into it. */
|
|
20
|
+
readonly sharedStrings: ReadonlyArray<string>;
|
|
21
|
+
/** §18.2.5 workbook defined names (print areas/titles, named ranges). */
|
|
22
|
+
readonly definedNames: ReadonlyArray<DefinedName>;
|
|
23
|
+
/** §18.2.28 1904 date system (serial-to-date epoch). */
|
|
24
|
+
readonly date1904: boolean;
|
|
25
|
+
/** Parsed charts keyed by part path (SheetChartRef.chartPartPath). */
|
|
26
|
+
readonly chartData?: ReadonlyMap<string, Chart>;
|
|
27
|
+
/** Content-addressed binary resources (sheet images). */
|
|
28
|
+
readonly resources: ResourceStore;
|
|
29
|
+
/** Document metadata from docProps/core.xml. */
|
|
30
|
+
readonly info?: DocumentInfo;
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { CellType, WorksheetCell, ColumnWidth, MergedRange, RowHeight, XlsxPageMargins, XlsxPageSetup, XlsxPrintOptions, ParsedWorksheet, XlsxFont, XlsxFill, XlsxBorderStyleName, XlsxBorderEdge, XlsxBorder, XlsxHorizontalAlign, XlsxVerticalAlign, XlsxCellAlignment, XlsxCellXf, XlsxStyles, DefinedName, Dxf, CfOperator, CfRuleCellIs, CfvoType, Cfvo, CfRuleColorScale, CfRuleDataBar, CfRuleIconSet, CfRule, ConditionalFormat, SparklineKind, ParsedSparkline, ExcelTable, SheetPane, } from './types.js';
|