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.
- package/README.md +10 -0
- package/dist/esm/core/bidi/index.d.ts +10 -0
- package/dist/esm/core/bidi/index.js +18 -2
- package/dist/esm/core/converter/facade.js +10 -5
- package/dist/esm/core/converter/project.js +1 -0
- package/dist/esm/core/converter/ream.js +17 -6
- package/dist/esm/core/converter/sheet-images.d.ts +17 -0
- package/dist/esm/core/converter/sheet-images.js +33 -0
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +112 -0
- package/dist/esm/core/drawingml/chart-geometry.d.ts +21 -8
- package/dist/esm/core/drawingml/chart-geometry.js +198 -108
- package/dist/esm/core/drawingml/chart-parser.js +73 -2
- package/dist/esm/core/drawingml/colors.d.ts +6 -0
- package/dist/esm/core/drawingml/colors.js +23 -3
- package/dist/esm/core/drawingml/shape-render.d.ts +3 -1
- package/dist/esm/core/drawingml/shape-render.js +4 -2
- package/dist/esm/core/font/measure.d.ts +9 -0
- package/dist/esm/core/font/measure.js +9 -1
- package/dist/esm/core/fonts/families.js +4 -2
- package/dist/esm/core/fonts/scripts.js +4 -2
- package/dist/esm/core/ir/flow.d.ts +6 -0
- package/dist/esm/core/ir/sheet.d.ts +43 -0
- package/dist/esm/core/number-format.js +16 -11
- package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
- package/dist/esm/core/spreadsheet-model/types.d.ts +96 -0
- package/dist/esm/core/style-cascade/resolver.js +4 -2
- package/dist/esm/excel/column-bands.d.ts +39 -6
- package/dist/esm/excel/column-bands.js +41 -17
- package/dist/esm/excel/comments-parser.js +19 -0
- package/dist/esm/excel/conditional-format.d.ts +7 -3
- package/dist/esm/excel/conditional-format.js +77 -39
- package/dist/esm/excel/formula/context.d.ts +18 -0
- package/dist/esm/excel/formula/eval.js +51 -0
- package/dist/esm/excel/formula/index.d.ts +2 -2
- package/dist/esm/excel/formula/lexer.d.ts +1 -1
- package/dist/esm/excel/formula/lexer.js +41 -0
- package/dist/esm/excel/formula/parser.d.ts +25 -0
- package/dist/esm/excel/formula/parser.js +95 -0
- package/dist/esm/excel/print-model.d.ts +38 -1
- package/dist/esm/excel/print-model.js +522 -80
- package/dist/esm/excel/shared-strings-parser.d.ts +9 -0
- package/dist/esm/excel/shared-strings-parser.js +11 -1
- package/dist/esm/excel/sheet-drawing.d.ts +38 -2
- package/dist/esm/excel/sheet-drawing.js +47 -13
- package/dist/esm/excel/sheet-shape-parser.d.ts +6 -2
- package/dist/esm/excel/sheet-shape-parser.js +18 -6
- package/dist/esm/excel/sheet-to-flow.d.ts +17 -0
- package/dist/esm/excel/sheet-to-flow.js +434 -47
- package/dist/esm/excel/styles-parser.d.ts +9 -0
- package/dist/esm/excel/styles-parser.js +80 -26
- package/dist/esm/excel/table-parser.js +5 -0
- package/dist/esm/excel/table-style-presets.d.ts +26 -0
- package/dist/esm/excel/table-style-presets.js +1555 -0
- package/dist/esm/excel/table-style.d.ts +13 -0
- package/dist/esm/excel/table-style.js +75 -0
- package/dist/esm/excel/tint.d.ts +10 -0
- package/dist/esm/excel/tint.js +75 -0
- package/dist/esm/excel/vml-drawing.d.ts +41 -3
- package/dist/esm/excel/vml-drawing.js +143 -10
- package/dist/esm/excel/worksheet-parser.js +89 -15
- package/dist/esm/excel/xls/biff-reader.js +10 -2
- package/dist/esm/excel/xlsx-reader.js +195 -14
- package/dist/esm/excel/xlsx-writer.js +8 -7
- package/dist/esm/html/html-writer.js +202 -20
- package/dist/esm/layout/fit-pages.d.ts +11 -0
- package/dist/esm/layout/fit-pages.js +86 -0
- package/dist/esm/layout/line-paint.d.ts +58 -0
- package/dist/esm/layout/line-paint.js +107 -0
- package/dist/esm/layout/page-doc.d.ts +51 -0
- package/dist/esm/layout/page-doc.js +141 -1
- package/dist/esm/layout/styled-layout.d.ts +7 -0
- package/dist/esm/layout/styled-layout.js +274 -51
- package/dist/esm/layout/turned-section.js +14 -2
- package/dist/esm/markdown/markdown-writer.js +17 -6
- package/dist/esm/pdf/styled-page-emitter.js +49 -71
- package/dist/esm/pdf/styled-page-renderer.js +1 -1
- package/dist/esm/pdf-reader/font.js +3 -3
- package/dist/esm/svg/svg-text.d.ts +58 -0
- package/dist/esm/svg/svg-text.js +322 -0
- package/dist/esm/svg/svg-writer.js +135 -71
- package/dist/esm/word/docx-writer.js +11 -2
- package/package.json +5 -1
|
@@ -195,6 +195,8 @@ function readSheet(wb, view, start, blips, resources, sharedStrings, chartData,
|
|
|
195
195
|
const hyperlinks = [];
|
|
196
196
|
const rowHeights = [];
|
|
197
197
|
let frozen = false;
|
|
198
|
+
let showGrid = true;
|
|
199
|
+
let rightToLeft = false;
|
|
198
200
|
let paneSplit;
|
|
199
201
|
let maxRow = -1;
|
|
200
202
|
let maxColumn = -1;
|
|
@@ -300,7 +302,11 @@ function readSheet(wb, view, start, blips, resources, sharedStrings, chartData,
|
|
|
300
302
|
}
|
|
301
303
|
break;
|
|
302
304
|
case REC.WINDOW2:
|
|
303
|
-
if (d.length >= 2)
|
|
305
|
+
if (d.length >= 2) {
|
|
306
|
+
frozen = (readU16(d, 0) & 8) !== 0;
|
|
307
|
+
showGrid = (readU16(d, 0) & 2) !== 0;
|
|
308
|
+
rightToLeft = (readU16(d, 0) & 64) !== 0;
|
|
309
|
+
}
|
|
304
310
|
break;
|
|
305
311
|
case REC.PANE:
|
|
306
312
|
if (d.length >= 4) paneSplit = {
|
|
@@ -331,7 +337,9 @@ function readSheet(wb, view, start, blips, resources, sharedStrings, chartData,
|
|
|
331
337
|
...parsePrintModel(records),
|
|
332
338
|
...dataValidations.length > 0 ? { dataValidations } : {},
|
|
333
339
|
...conditionalFormats.length > 0 ? { conditionalFormats } : {},
|
|
334
|
-
...pane ? { pane } : {}
|
|
340
|
+
...pane ? { pane } : {},
|
|
341
|
+
...showGrid ? {} : { showGridLines: false },
|
|
342
|
+
...rightToLeft ? { rightToLeft: true } : {}
|
|
335
343
|
};
|
|
336
344
|
const drawing = gatherDrawing(records, REC.MSODRAWING);
|
|
337
345
|
const place = anchorPlacer(grid);
|
|
@@ -1,22 +1,24 @@
|
|
|
1
1
|
import { ResourceStore } from "../core/ir/resources.js";
|
|
2
2
|
import { FEATURES } from "../core/ir/features.js";
|
|
3
3
|
import { detectImageFormat } from "../core/images.js";
|
|
4
|
+
import { INDEXED_COLORS } from "../core/indexed-colors.js";
|
|
4
5
|
import { bytesInclude, packageHasPart } from "../core/bytes.js";
|
|
5
|
-
import {
|
|
6
|
+
import { OFFICE_2023_THEME_PALETTE, makeColorResolver } from "../core/drawingml/colors.js";
|
|
6
7
|
import { parseChart, withChartColorStyle } from "../core/drawingml/chart-parser.js";
|
|
7
8
|
import { parseTheme, parseThemeEffectStyles, parseThemeFillStyles, parseThemeLineWidths } from "../core/drawingml/theme-parser.js";
|
|
8
9
|
import { isOoxmlRel } from "../core/opc/relationship-types.js";
|
|
9
10
|
import { OpcPackage } from "../core/opc/package.js";
|
|
10
11
|
import { parseCoreProperties } from "../core/opc/core-properties.js";
|
|
11
12
|
import "../core/opc/index.js";
|
|
13
|
+
import { parseCellRef } from "./cell-reference.js";
|
|
12
14
|
import { parseAreaRef } from "./defined-name-ref.js";
|
|
13
15
|
import { parseSharedStrings } from "./shared-strings-parser.js";
|
|
14
16
|
import { parseWorkbook } from "./workbook-parser.js";
|
|
15
17
|
import { EMPTY_XLSX_STYLES, parseXlsxStyles } from "./styles-parser.js";
|
|
16
18
|
import { parseWorksheet } from "./worksheet-parser.js";
|
|
17
19
|
import "./index.js";
|
|
18
|
-
import { resolveCellText } from "./print-model.js";
|
|
19
|
-
import { parseSheetDrawing } from "./sheet-drawing.js";
|
|
20
|
+
import { columnUnitTwips, resolveCellText } from "./print-model.js";
|
|
21
|
+
import { makeColWidthPt, makeRowHeightPt, parseSheetDrawing } from "./sheet-drawing.js";
|
|
20
22
|
import { parseTablePartFull } from "./table-parser.js";
|
|
21
23
|
import { parsePivotTablePart } from "./pivot-table-parser.js";
|
|
22
24
|
import { parseSlicerCachePart, parseSlicerPart } from "./slicer-parser.js";
|
|
@@ -28,6 +30,7 @@ import { parseRichValueText } from "./rich-value.js";
|
|
|
28
30
|
import { activeXBinRelId, activeXType, activeXTypeFromPart, parseActiveX, parseActiveXBin } from "./activex-parser.js";
|
|
29
31
|
import { parseDiagramFrames, parseDiagramShapes, parseSheetShapes } from "./sheet-shape-parser.js";
|
|
30
32
|
import { projectSheetDoc } from "./sheet-to-flow.js";
|
|
33
|
+
import { resolveTableStyleFormat } from "./table-style.js";
|
|
31
34
|
//#region src/excel/xlsx-reader.ts
|
|
32
35
|
var WORKBOOK_PART = "xl/workbook.xml";
|
|
33
36
|
var SHARED_STRINGS_PART = "xl/sharedStrings.xml";
|
|
@@ -92,6 +95,7 @@ function readXlsxToSheetDoc(xlsx) {
|
|
|
92
95
|
const richValueText = parseRichValueText(pkg.getPart(METADATA_PART), pkg.getPart(RICH_VALUE_STRUCTURE_PART), pkg.getPart(RICH_VALUE_PART));
|
|
93
96
|
const stylesData = pkg.getPart(STYLES_PART);
|
|
94
97
|
const styles = stylesData ? parseXlsxStyles(stylesData, themePalette) : EMPTY_XLSX_STYLES;
|
|
98
|
+
const colUnit = columnUnitTwips(styles);
|
|
95
99
|
const persons = /* @__PURE__ */ new Map();
|
|
96
100
|
for (const rel of workbookRels) {
|
|
97
101
|
if (!rel.type.endsWith(PERSON_REL_TAIL)) continue;
|
|
@@ -118,15 +122,23 @@ function readXlsxToSheetDoc(xlsx) {
|
|
|
118
122
|
if (!resolved) continue;
|
|
119
123
|
let worksheet = parseWorksheet(resolved.data, themePalette);
|
|
120
124
|
worksheet = withPrinterPageSetup(worksheet, pkg, resolved.path, pkg.getPartRelationships(resolved.path));
|
|
125
|
+
if (worksheet.chartSheet && worksheet.pageSetup?.orientation === void 0) worksheet = {
|
|
126
|
+
...worksheet,
|
|
127
|
+
pageSetup: {
|
|
128
|
+
...worksheet.pageSetup,
|
|
129
|
+
orientation: "landscape"
|
|
130
|
+
}
|
|
131
|
+
};
|
|
121
132
|
worksheet = withRichValues(worksheet, richValueText);
|
|
122
133
|
const charts = [];
|
|
123
134
|
const images = [];
|
|
124
135
|
let shapes;
|
|
136
|
+
const screenOnlyShapes = /* @__PURE__ */ new Set();
|
|
125
137
|
if (worksheet.drawingRelId) {
|
|
126
138
|
const drawingRel = pkg.getPartRelationships(resolved.path).find((r) => r.id === worksheet.drawingRelId);
|
|
127
139
|
const drawing = drawingRel ? pkg.resolveRelatedPart(resolved.path, drawingRel) : void 0;
|
|
128
140
|
if (drawing) {
|
|
129
|
-
const { charts: chartRefs, pictures } = parseSheetDrawing(drawing.data, drawing.path, pkg, worksheet);
|
|
141
|
+
const { charts: chartRefs, pictures } = parseSheetDrawing(drawing.data, drawing.path, pkg, worksheet, colUnit);
|
|
130
142
|
for (const ref of chartRefs) {
|
|
131
143
|
if (!chartData.has(ref.chartPartPath)) {
|
|
132
144
|
const chartXml = pkg.getPart(ref.chartPartPath);
|
|
@@ -139,7 +151,8 @@ function readXlsxToSheetDoc(xlsx) {
|
|
|
139
151
|
widthPt: ref.widthPt,
|
|
140
152
|
heightPt: ref.heightPt,
|
|
141
153
|
xPt: ref.xPt,
|
|
142
|
-
yPt: ref.yPt
|
|
154
|
+
yPt: ref.yPt,
|
|
155
|
+
...ref.screenOnly ? { screenOnly: true } : {}
|
|
143
156
|
});
|
|
144
157
|
}
|
|
145
158
|
for (const pic of pictures) {
|
|
@@ -151,14 +164,15 @@ function readXlsxToSheetDoc(xlsx) {
|
|
|
151
164
|
widthPt: pic.widthPt,
|
|
152
165
|
heightPt: pic.heightPt,
|
|
153
166
|
xPt: pic.xPt,
|
|
154
|
-
yPt: pic.yPt
|
|
167
|
+
yPt: pic.yPt,
|
|
168
|
+
...pic.screenOnly ? { screenOnly: true } : {}
|
|
155
169
|
});
|
|
156
170
|
}
|
|
157
171
|
if (bytesInclude(drawing.data, ":sp>") || bytesInclude(drawing.data, ":sp ")) {
|
|
158
|
-
const parsed = parseSheetShapes(drawing.data, worksheet, resolveColor, themeLineWidths, themeFillStyles, themeEffectStyles);
|
|
172
|
+
const parsed = parseSheetShapes(drawing.data, worksheet, resolveColor, themeLineWidths, themeFillStyles, themeEffectStyles, screenOnlyShapes, colUnit);
|
|
159
173
|
if (parsed.length > 0) shapes = parsed;
|
|
160
174
|
}
|
|
161
|
-
const frames = parseDiagramFrames(drawing.data, worksheet);
|
|
175
|
+
const frames = parseDiagramFrames(drawing.data, worksheet, colUnit);
|
|
162
176
|
if (frames.length > 0) {
|
|
163
177
|
const dsp = pkg.getPartRelationships(drawing.path).filter((r) => r.type.endsWith("/diagramDrawing"));
|
|
164
178
|
const fromDiagrams = [];
|
|
@@ -181,7 +195,7 @@ function readXlsxToSheetDoc(xlsx) {
|
|
|
181
195
|
const part = rel ? pkg.resolveRelatedPart(resolved.path, rel) : void 0;
|
|
182
196
|
const full = part ? parseTablePartFull(part.data) : void 0;
|
|
183
197
|
if (!full) continue;
|
|
184
|
-
resolvedTables.push(resolveTableStyle(full.table, palette));
|
|
198
|
+
resolvedTables.push(withTableStyle(resolveTableStyle(full.table, palette), styles, themePalette));
|
|
185
199
|
if (full.id !== void 0) tableIndex.set(full.id, {
|
|
186
200
|
cells: worksheet.cells,
|
|
187
201
|
ref: full.table.ref,
|
|
@@ -266,7 +280,8 @@ function readXlsxToSheetDoc(xlsx) {
|
|
|
266
280
|
...props
|
|
267
281
|
};
|
|
268
282
|
};
|
|
269
|
-
const legacyVml = readLegacyVml(pkg, resolved.path, wsRels, worksheet);
|
|
283
|
+
const legacyVml = readLegacyVml(pkg, resolved.path, wsRels, worksheet, colUnit);
|
|
284
|
+
if (comments && legacyVml.notes.length > 0) comments = withShownNotes(comments, legacyVml.notes, worksheet, colUnit);
|
|
270
285
|
let formControls;
|
|
271
286
|
if (worksheet.formControls && worksheet.formControls.length > 0) {
|
|
272
287
|
const resolvedControls = [];
|
|
@@ -275,7 +290,7 @@ function readXlsxToSheetDoc(xlsx) {
|
|
|
275
290
|
if (fc.shapeId !== void 0 && legacyVml.nonPrinting.has(fc.shapeId)) continue;
|
|
276
291
|
const rel = wsRels.find((r) => r.id === fc.relId);
|
|
277
292
|
const part = rel ? pkg.resolveRelatedPart(resolved.path, rel) : void 0;
|
|
278
|
-
const box = fc.shapeId !== void 0 ? legacyVml.boxes.get(fc.shapeId) : void 0;
|
|
293
|
+
const box = fc.shapeId !== void 0 ? legacyVml.anchoredBoxes.get(fc.shapeId) ?? legacyVml.boxes.get(fc.shapeId) : void 0;
|
|
279
294
|
if (part && ACTIVEX_PART.test(part.path)) {
|
|
280
295
|
resolvedAx.push({
|
|
281
296
|
...activeXState(part),
|
|
@@ -320,6 +335,7 @@ function readXlsxToSheetDoc(xlsx) {
|
|
|
320
335
|
...charts.length > 0 ? { charts } : {},
|
|
321
336
|
...images.length > 0 ? { images } : {},
|
|
322
337
|
...shapes ? { shapes } : {},
|
|
338
|
+
...shapes && screenOnlyShapes.size > 0 ? { screenOnlyShapes: new Set(shapes.flatMap((shape, i) => screenOnlyShapes.has(shape) ? [i] : [])) } : {},
|
|
323
339
|
...hyperlinks ? { hyperlinks } : {},
|
|
324
340
|
...comments ? { comments } : {},
|
|
325
341
|
...formControls ? { formControls } : {},
|
|
@@ -488,10 +504,12 @@ function withPrinterPageSetup(worksheet, pkg, sheetPath, wsRels) {
|
|
|
488
504
|
* through the activeX part. What is left is the Forms-toolbar kind, whose
|
|
489
505
|
* caption and checked state exist nowhere else in the package.
|
|
490
506
|
*/
|
|
491
|
-
function readLegacyVml(pkg, sheetPath, wsRels, worksheet) {
|
|
507
|
+
function readLegacyVml(pkg, sheetPath, wsRels, worksheet, colUnitTwips) {
|
|
492
508
|
const empty = {
|
|
493
509
|
controls: [],
|
|
510
|
+
notes: [],
|
|
494
511
|
boxes: /* @__PURE__ */ new Map(),
|
|
512
|
+
anchoredBoxes: /* @__PURE__ */ new Map(),
|
|
495
513
|
nonPrinting: /* @__PURE__ */ new Set()
|
|
496
514
|
};
|
|
497
515
|
const relId = worksheet.legacyDrawingRelId;
|
|
@@ -501,9 +519,25 @@ function readLegacyVml(pkg, sheetPath, wsRels, worksheet) {
|
|
|
501
519
|
if (!part) return empty;
|
|
502
520
|
const activeXShapeIds = new Set((worksheet.formControls ?? []).map((fc) => fc.shapeId).filter((id) => id !== void 0));
|
|
503
521
|
const drawing = parseVmlDrawing(part.data);
|
|
522
|
+
const colWidthPt = makeColWidthPt(worksheet, colUnitTwips);
|
|
523
|
+
const rowHeightPt = makeRowHeightPt(worksheet);
|
|
524
|
+
const anchoredBoxes = /* @__PURE__ */ new Map();
|
|
525
|
+
for (const [id, anchor] of drawing.anchors) {
|
|
526
|
+
const box = anchoredBox(anchor, colWidthPt, rowHeightPt);
|
|
527
|
+
if (box) anchoredBoxes.set(id, box);
|
|
528
|
+
}
|
|
529
|
+
const colOnce = memoTrack(colWidthPt);
|
|
530
|
+
const rowOnce = memoTrack(rowHeightPt);
|
|
531
|
+
const onGrid = (box) => anchoredBox(pixelAnchor(box, colOnce, rowOnce), colOnce, rowOnce);
|
|
532
|
+
for (const [id, box] of drawing.boxes) {
|
|
533
|
+
if (anchoredBoxes.has(id)) continue;
|
|
534
|
+
const placed = onGrid(box);
|
|
535
|
+
if (placed) anchoredBoxes.set(id, placed);
|
|
536
|
+
}
|
|
504
537
|
const out = [];
|
|
505
538
|
for (const shape of drawing.controls) {
|
|
506
539
|
if (shape.shapeId !== void 0 && activeXShapeIds.has(shape.shapeId)) continue;
|
|
540
|
+
const box = (shape.anchor && anchoredBox(shape.anchor, colWidthPt, rowHeightPt)) ?? (shape.box && onGrid(shape.box)) ?? shape.box;
|
|
507
541
|
out.push({
|
|
508
542
|
objectType: shape.objectType,
|
|
509
543
|
...shape.caption ? {
|
|
@@ -511,18 +545,154 @@ function readLegacyVml(pkg, sheetPath, wsRels, worksheet) {
|
|
|
511
545
|
caption: shape.caption
|
|
512
546
|
} : {},
|
|
513
547
|
...shape.checked ? { checked: true } : {},
|
|
514
|
-
...
|
|
548
|
+
...box ? { box } : {},
|
|
515
549
|
...shape.fontSizePt !== void 0 ? { fontSizePt: shape.fontSizePt } : {}
|
|
516
550
|
});
|
|
517
551
|
}
|
|
518
552
|
return {
|
|
519
553
|
controls: out,
|
|
554
|
+
notes: drawing.notes,
|
|
520
555
|
boxes: drawing.boxes,
|
|
556
|
+
anchoredBoxes,
|
|
521
557
|
nonPrinting: drawing.nonPrinting
|
|
522
558
|
};
|
|
523
559
|
}
|
|
560
|
+
/**
|
|
561
|
+
* A legacy VML shape's box by the cells its `<x:Anchor>` names — on the grid
|
|
562
|
+
* we draw, whatever measure of the columns the producer wrote its `style` in.
|
|
563
|
+
*
|
|
564
|
+
* @param anchor The anchor: cells and pixels into them.
|
|
565
|
+
* @param colWidthPt The sheet's column widths.
|
|
566
|
+
* @param rowHeightPt The sheet's row heights.
|
|
567
|
+
* @returns The box, or undefined for an anchor that names no box on the sheet.
|
|
568
|
+
*/
|
|
569
|
+
function anchoredBox(anchor, colWidthPt, rowHeightPt) {
|
|
570
|
+
if (anchor[0] < 0 || anchor[2] < 0) return void 0;
|
|
571
|
+
const x0 = trackPt(anchor[0], anchor[1], colWidthPt);
|
|
572
|
+
const x1 = trackPt(anchor[4], anchor[5], colWidthPt);
|
|
573
|
+
const y0 = trackPt(anchor[2], anchor[3], rowHeightPt);
|
|
574
|
+
const y1 = trackPt(anchor[6], anchor[7], rowHeightPt);
|
|
575
|
+
return x1 > x0 && y1 > y0 ? {
|
|
576
|
+
xPt: x0,
|
|
577
|
+
yPt: y0,
|
|
578
|
+
widthPt: x1 - x0,
|
|
579
|
+
heightPt: y1 - y0
|
|
580
|
+
} : void 0;
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* The cells a box placed by points alone stands on, as a `<x:Anchor>` would
|
|
584
|
+
* name them — counted the way Excel counts its own sheet when it writes such a
|
|
585
|
+
* box: columns in whole pixels, which ours are, and rows in whole pixels too,
|
|
586
|
+
* a row's points truncated (20.1pt is 26px). 45540_form_Footer.xlsx says so
|
|
587
|
+
* itself: a check box anchored at row 7 + 9px stands at `margin-top:184.5pt`,
|
|
588
|
+
* and its seven rows above come to the 237px that leaves only truncated.
|
|
589
|
+
* Taken as points on our grid, whose rows keep their fractions, a box placed
|
|
590
|
+
* that way stood the more rows above its cells the further down it was.
|
|
591
|
+
*
|
|
592
|
+
* @param box The box, in the producer's points.
|
|
593
|
+
* @param colWidthPt The sheet's column widths.
|
|
594
|
+
* @param rowHeightPt The sheet's row heights.
|
|
595
|
+
* @returns The anchor: cells, 0-based, and pixels into them.
|
|
596
|
+
*/
|
|
597
|
+
function pixelAnchor(box, colWidthPt, rowHeightPt) {
|
|
598
|
+
const colPx = (i) => Math.round(colWidthPt(i) / PT_PER_PX);
|
|
599
|
+
const rowPx = (i) => Math.trunc(rowHeightPt(i) / PT_PER_PX + 1e-6);
|
|
600
|
+
const locate = (pt, track, limit) => {
|
|
601
|
+
let i = 0;
|
|
602
|
+
let rest = pt / PT_PER_PX;
|
|
603
|
+
while (i < limit && rest >= track(i)) {
|
|
604
|
+
rest -= track(i);
|
|
605
|
+
i++;
|
|
606
|
+
}
|
|
607
|
+
return [i, rest];
|
|
608
|
+
};
|
|
609
|
+
const [c0, dx0] = locate(box.xPt, colPx, MAX_COLUMNS);
|
|
610
|
+
const [r0, dy0] = locate(box.yPt, rowPx, MAX_ROWS);
|
|
611
|
+
const [c1, dx1] = locate(box.xPt + box.widthPt, colPx, MAX_COLUMNS);
|
|
612
|
+
const [r1, dy1] = locate(box.yPt + box.heightPt, rowPx, MAX_ROWS);
|
|
613
|
+
return [
|
|
614
|
+
c0,
|
|
615
|
+
dx0,
|
|
616
|
+
r0,
|
|
617
|
+
dy0,
|
|
618
|
+
c1,
|
|
619
|
+
dx1,
|
|
620
|
+
r1,
|
|
621
|
+
dy1
|
|
622
|
+
];
|
|
623
|
+
}
|
|
624
|
+
/** A track accessor that answers each index once. */
|
|
625
|
+
function memoTrack(track) {
|
|
626
|
+
const seen = /* @__PURE__ */ new Map();
|
|
627
|
+
return (i) => {
|
|
628
|
+
let v = seen.get(i);
|
|
629
|
+
if (v === void 0) seen.set(i, v = track(i));
|
|
630
|
+
return v;
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
/** SpreadsheetML's grid: 16 384 columns, 1 048 576 rows. */
|
|
634
|
+
var MAX_COLUMNS = 16384;
|
|
635
|
+
var MAX_ROWS = 1048576;
|
|
636
|
+
/** Where `offsetPx` pixels into track `index` stands, in points from the first track. */
|
|
637
|
+
function trackPt(index, offsetPx, track) {
|
|
638
|
+
let total = 0;
|
|
639
|
+
for (let i = 0; i < index; i++) total += track(i);
|
|
640
|
+
return total + offsetPx * PT_PER_PX;
|
|
641
|
+
}
|
|
642
|
+
var PT_PER_PX = .75;
|
|
643
|
+
/**
|
|
644
|
+
* §18.7 + the legacy VML drawing — a comment's box, where its shape SHOWS it.
|
|
645
|
+
* The comments part holds what a note says; the VML shape says whether it is
|
|
646
|
+
* shown and where, and the two meet at the cell (`<x:Row>`/`<x:Column>`
|
|
647
|
+
* against the comment's `ref`).
|
|
648
|
+
*
|
|
649
|
+
* The box is placed by its `<x:Anchor>` — cells plus pixels — so it lands on
|
|
650
|
+
* the grid we draw, whatever widths the producer measured with; the shape's
|
|
651
|
+
* `style` is the fallback for an anchor that is missing or unusable
|
|
652
|
+
* (LibreOffice writes negative columns on a sheet that reads from the right).
|
|
653
|
+
*
|
|
654
|
+
* @param comments The sheet's comments, legacy and threaded.
|
|
655
|
+
* @param notes The note shapes of the sheet's legacy VML drawing.
|
|
656
|
+
* @param worksheet The sheet, for its column widths, row heights and merges.
|
|
657
|
+
* @returns The comments, a shown one carrying its box.
|
|
658
|
+
*/
|
|
659
|
+
function withShownNotes(comments, notes, worksheet, colUnitTwips) {
|
|
660
|
+
const shown = /* @__PURE__ */ new Map();
|
|
661
|
+
for (const n of notes) if (n.visible) shown.set(`${n.row}:${n.column}`, n);
|
|
662
|
+
if (shown.size === 0) return [...comments];
|
|
663
|
+
const colWidthPt = makeColWidthPt(worksheet, colUnitTwips);
|
|
664
|
+
const rowHeightPt = makeRowHeightPt(worksheet);
|
|
665
|
+
const along = trackPt;
|
|
666
|
+
return comments.map((c) => {
|
|
667
|
+
if (c.threaded) return c;
|
|
668
|
+
let cell;
|
|
669
|
+
try {
|
|
670
|
+
cell = parseCellRef(c.ref);
|
|
671
|
+
} catch {
|
|
672
|
+
return c;
|
|
673
|
+
}
|
|
674
|
+
const note = shown.get(`${cell.row}:${cell.column}`);
|
|
675
|
+
if (!note) return c;
|
|
676
|
+
let box = note.anchor ? anchoredBox(note.anchor, colWidthPt, rowHeightPt) : void 0;
|
|
677
|
+
if (!box && note.box && note.box.xPt >= 0 && note.box.yPt >= 0) box = note.box;
|
|
678
|
+
if (!box) return c;
|
|
679
|
+
const merge = worksheet.merges.find((m) => m.startRow === cell.row && m.startColumn === cell.column);
|
|
680
|
+
return {
|
|
681
|
+
...c,
|
|
682
|
+
shown: {
|
|
683
|
+
...box,
|
|
684
|
+
cornerXPt: along((merge?.endColumn ?? cell.column) + 1, 0, colWidthPt),
|
|
685
|
+
cornerYPt: along(cell.row, 0, rowHeightPt),
|
|
686
|
+
fillHex: note.fillHex,
|
|
687
|
+
lineHex: note.lineHex,
|
|
688
|
+
shadow: note.shadow,
|
|
689
|
+
...note.textAlign ? { textAlign: note.textAlign } : {}
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
});
|
|
693
|
+
}
|
|
524
694
|
function buildThemePalette(pkg, workbookRels) {
|
|
525
|
-
const palette = new Map(
|
|
695
|
+
const palette = new Map(OFFICE_2023_THEME_PALETTE);
|
|
526
696
|
for (const rel of workbookRels) {
|
|
527
697
|
if (!isOoxmlRel(rel.type, "theme")) continue;
|
|
528
698
|
const resolved = pkg.resolveRelatedPart(WORKBOOK_PART, rel);
|
|
@@ -574,6 +744,17 @@ function resolveTableStyle(t, palette) {
|
|
|
574
744
|
headerTextHex: "FFFFFF"
|
|
575
745
|
};
|
|
576
746
|
}
|
|
747
|
+
function withTableStyle(t, styles, theme) {
|
|
748
|
+
if (t.styleName === void 0) return t;
|
|
749
|
+
const style = resolveTableStyleFormat(t.styleName, styles, {
|
|
750
|
+
...theme ? { theme } : {},
|
|
751
|
+
indexed: INDEXED_COLORS
|
|
752
|
+
});
|
|
753
|
+
return style ? {
|
|
754
|
+
...t,
|
|
755
|
+
style
|
|
756
|
+
} : t;
|
|
757
|
+
}
|
|
577
758
|
function resolvePivotStyle(p, palette) {
|
|
578
759
|
const m = p.styleName ? /PivotStyle(Light|Medium|Dark)(\d+)/i.exec(p.styleName) : null;
|
|
579
760
|
if (!m) return p;
|
|
@@ -213,22 +213,23 @@ function worksheetXml(grid, tableRelIds = [], drawingRelId) {
|
|
|
213
213
|
return `<row r="${r + 1}"${heightAttrs}>${cells.map(cellXml).join("")}</row>`;
|
|
214
214
|
}).join("");
|
|
215
215
|
const mergesXml = grid.merges.length > 0 ? `<mergeCells count="${grid.merges.length}">${grid.merges.map((m) => `<mergeCell ref="${cellRef(m.startRow, m.startColumn)}:${cellRef(m.endRow, m.endColumn)}"/>`).join("")}</mergeCells>` : "";
|
|
216
|
-
return XML_DECL + `<worksheet xmlns="${MAIN_NS}" xmlns:r="${R_NS}">` + (grid.fitToPage ? "<sheetPr><pageSetUpPr fitToPage=\"1\"/></sheetPr>" : "") + dimension + sheetViewsXml(grid.pane) + colsXml + `<sheetData>${rowsXml}</sheetData>` + mergesXml + conditionalFormattingXml(grid.conditionalFormats) + dataValidationsXml(grid.dataValidations) + printOptionsXml(grid.printOptions) + pageMarginsXml(grid.pageMargins) + pageSetupXml(grid.pageSetup) + breaksXml("rowBreaks", grid.rowBreaks) + breaksXml("colBreaks", grid.colBreaks) + (drawingRelId ? `<drawing r:id="${drawingRelId}"/>` : "") + (tableRelIds.length > 0 ? `<tableParts count="${tableRelIds.length}">${tableRelIds.map((id) => `<tablePart r:id="${id}"/>`).join("")}</tableParts>` : "") + sparklineExtXml(grid.sparklines) + "</worksheet>";
|
|
216
|
+
return XML_DECL + `<worksheet xmlns="${MAIN_NS}" xmlns:r="${R_NS}">` + (grid.fitToPage ? "<sheetPr><pageSetUpPr fitToPage=\"1\"/></sheetPr>" : "") + dimension + sheetViewsXml(grid.pane, grid.showGridLines, grid.rightToLeft) + colsXml + `<sheetData>${rowsXml}</sheetData>` + mergesXml + conditionalFormattingXml(grid.conditionalFormats) + dataValidationsXml(grid.dataValidations) + printOptionsXml(grid.printOptions) + pageMarginsXml(grid.pageMargins) + pageSetupXml(grid.pageSetup) + breaksXml("rowBreaks", grid.rowBreaks) + breaksXml("colBreaks", grid.colBreaks) + (drawingRelId ? `<drawing r:id="${drawingRelId}"/>` : "") + (tableRelIds.length > 0 ? `<tableParts count="${tableRelIds.length}">${tableRelIds.map((id) => `<tablePart r:id="${id}"/>`).join("")}</tableParts>` : "") + sparklineExtXml(grid.sparklines) + "</worksheet>";
|
|
217
217
|
}
|
|
218
|
-
function sheetViewsXml(pane) {
|
|
219
|
-
|
|
218
|
+
function sheetViewsXml(pane, showGridLines, rightToLeft) {
|
|
219
|
+
const grid = (showGridLines === false ? " showGridLines=\"0\"" : "") + (rightToLeft ? " rightToLeft=\"1\"" : "");
|
|
220
|
+
if (!pane || pane.frozenRows <= 0 && pane.frozenCols <= 0) return grid ? `<sheetViews><sheetView${grid} workbookViewId="0"/></sheetViews>` : "";
|
|
220
221
|
const { frozenRows, frozenCols } = pane;
|
|
221
222
|
const topLeftCell = cellRef(frozenRows, frozenCols);
|
|
222
223
|
const activePane = frozenRows > 0 && frozenCols > 0 ? "bottomRight" : frozenRows > 0 ? "bottomLeft" : "topRight";
|
|
223
|
-
return `<sheetViews><sheetView workbookViewId="0"><pane${(frozenCols > 0 ? ` xSplit="${frozenCols}"` : "") + (frozenRows > 0 ? ` ySplit="${frozenRows}"` : "") + ` topLeftCell="${topLeftCell}" activePane="${activePane}" state="frozen"`}/></sheetView></sheetViews>`;
|
|
224
|
+
return `<sheetViews><sheetView${grid} workbookViewId="0"><pane${(frozenCols > 0 ? ` xSplit="${frozenCols}"` : "") + (frozenRows > 0 ? ` ySplit="${frozenRows}"` : "") + ` topLeftCell="${topLeftCell}" activePane="${activePane}" state="frozen"`}/></sheetView></sheetViews>`;
|
|
224
225
|
}
|
|
225
226
|
function tableXml(t, id) {
|
|
226
227
|
const ref = rangeRef(t.ref);
|
|
227
228
|
const name = t.name ?? `Table${id}`;
|
|
228
229
|
const ncols = t.ref.endColumn - t.ref.startColumn + 1;
|
|
229
|
-
const columns = Array.from({ length: ncols }, (_, c) => `<tableColumn id="${c + 1}" name="Column${c + 1}"/>`).join("");
|
|
230
|
+
const columns = Array.from({ length: ncols }, (_, c) => `<tableColumn id="${c + 1}" name="${escapeAttr(t.columns?.[c] ?? `Column${c + 1}`)}"/>`).join("");
|
|
230
231
|
const styleInfo = t.styleName ? `<tableStyleInfo name="${escapeAttr(t.styleName)}" showFirstColumn="${t.showFirstColumn ? 1 : 0}" showLastColumn="${t.showLastColumn ? 1 : 0}" showRowStripes="${t.showRowStripes ? 1 : 0}" showColumnStripes="${t.showColumnStripes ? 1 : 0}"/>` : "";
|
|
231
|
-
return XML_DECL + `<table xmlns="${MAIN_NS}" id="${id}" name="${escapeAttr(name)}" displayName="${escapeAttr(name)}" ref="${ref}"${t.headerRowCount !== 1 ? ` headerRowCount="${t.headerRowCount}"` : ""}
|
|
232
|
+
return XML_DECL + `<table xmlns="${MAIN_NS}" id="${id}" name="${escapeAttr(name)}" displayName="${escapeAttr(name)}" ref="${ref}"${t.headerRowCount !== 1 ? ` headerRowCount="${t.headerRowCount}"` : ""}${t.totalsRowCount ? ` totalsRowCount="${t.totalsRowCount}"` : " totalsRowShown=\"0\""}>` + (t.autoFilter ? `<autoFilter ref="${ref}"/>` : "") + `<tableColumns count="${ncols}">${columns}</tableColumns>` + styleInfo + "</table>";
|
|
232
233
|
}
|
|
233
234
|
function conditionalFormattingXml(cfs) {
|
|
234
235
|
if (!cfs || cfs.length === 0) return "";
|
|
@@ -346,7 +347,7 @@ function edgeXml(name, edge) {
|
|
|
346
347
|
function cellXfXml(xf) {
|
|
347
348
|
const apply = applyAttr("applyNumberFormat", xf.applyNumberFormat) + applyAttr("applyFont", xf.applyFont) + applyAttr("applyFill", xf.applyFill) + applyAttr("applyBorder", xf.applyBorder) + applyAttr("applyAlignment", xf.applyAlignment);
|
|
348
349
|
const a = xf.alignment;
|
|
349
|
-
const alignment = a ? `<alignment${a.horizontal ? ` horizontal="${a.horizontal}"` : ""}${a.vertical ? ` vertical="${a.vertical}"` : ""}${a.wrapText ? " wrapText=\"1\"" : ""}${a.textRotation !== void 0 ? ` textRotation="${a.textRotation}"` : ""}${a.indent !== void 0 ? ` indent="${a.indent}"` : ""}${a.shrinkToFit ? " shrinkToFit=\"1\"" : ""}/>` : "";
|
|
350
|
+
const alignment = a ? `<alignment${a.horizontal ? ` horizontal="${a.horizontal}"` : ""}${a.vertical ? ` vertical="${a.vertical}"` : ""}${a.wrapText ? " wrapText=\"1\"" : ""}${a.textRotation !== void 0 ? ` textRotation="${a.textRotation}"` : ""}${a.indent !== void 0 ? ` indent="${a.indent}"` : ""}${a.shrinkToFit ? " shrinkToFit=\"1\"" : ""}${a.readingOrder ? ` readingOrder="${a.readingOrder === "rtl" ? 2 : 1}"` : ""}/>` : "";
|
|
350
351
|
return `<xf numFmtId="${xf.numFmtId}" fontId="${xf.fontId}" fillId="${xf.fillId}" borderId="${xf.borderId}"${apply}>` + alignment + "</xf>";
|
|
351
352
|
}
|
|
352
353
|
function applyAttr(name, value) {
|