reamkit 1.13.0 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/dist/esm/core/document-model/types.d.ts +2 -0
  2. package/dist/esm/core/ir/sheet.d.ts +35 -3
  3. package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
  4. package/dist/esm/core/spreadsheet-model/types.d.ts +62 -1
  5. package/dist/esm/excel/comments-parser.d.ts +4 -0
  6. package/dist/esm/excel/comments-parser.js +104 -0
  7. package/dist/esm/excel/conditional-format.d.ts +2 -2
  8. package/dist/esm/excel/conditional-format.js +113 -11
  9. package/dist/esm/excel/form-control-parser.d.ts +6 -0
  10. package/dist/esm/excel/form-control-parser.js +29 -0
  11. package/dist/esm/excel/header-footer.d.ts +2 -0
  12. package/dist/esm/excel/header-footer.js +127 -0
  13. package/dist/esm/excel/index.d.ts +1 -1
  14. package/dist/esm/excel/print-model.d.ts +4 -2
  15. package/dist/esm/excel/print-model.js +123 -16
  16. package/dist/esm/excel/shared-strings-parser.d.ts +6 -1
  17. package/dist/esm/excel/shared-strings-parser.js +91 -12
  18. package/dist/esm/excel/sheet-drawing.d.ts +13 -1
  19. package/dist/esm/excel/sheet-drawing.js +47 -14
  20. package/dist/esm/excel/sheet-shape-parser.d.ts +4 -0
  21. package/dist/esm/excel/sheet-shape-parser.js +96 -0
  22. package/dist/esm/excel/sheet-to-flow.js +125 -2
  23. package/dist/esm/excel/styles-parser.js +37 -0
  24. package/dist/esm/excel/worksheet-parser.js +125 -1
  25. package/dist/esm/excel/xlsx-reader.js +107 -14
  26. package/dist/esm/excel/xlsx-writer.js +10 -2
  27. package/dist/esm/layout/styled-layout.js +29 -0
  28. package/dist/esm/pptx/slide-parser.d.ts +4 -2
  29. package/dist/esm/pptx/slide-parser.js +1 -1
  30. package/package.json +1 -1
@@ -192,7 +192,7 @@ function worksheetToBody(worksheet, sharedStrings, styles, date1904, print) {
192
192
  }
193
193
  return props;
194
194
  };
195
- const cfFormatter = buildConditionalFormatter(worksheet.conditionalFormats, styles, worksheet.cells);
195
+ const cfFormatter = buildConditionalFormatter(worksheet.conditionalFormats, styles, worksheet.cells, (cell) => resolveCellText(cell, sharedStrings, styles, date1904));
196
196
  const sparklineByCell = buildSparklineLookup(worksheet, print);
197
197
  const tableFormatByCell = buildTableFormatLookup(worksheet);
198
198
  const dropdownRanges = listDropdownRanges(worksheet.dataValidations);
@@ -210,6 +210,7 @@ function worksheetToBody(worksheet, sharedStrings, styles, date1904, print) {
210
210
  }
211
211
  const ws = cellMatrix[r]?.[c];
212
212
  let text = ws ? resolveCellText(ws, sharedStrings, styles, date1904) : "";
213
+ const cfText = text.length > 0 ? text : void 0;
213
214
  if (text.length > textBudget) text = text.slice(0, Math.max(0, textBudget));
214
215
  textBudget -= text.length;
215
216
  const xf = ws && ws.styleIndex !== void 0 ? styles.cellXfs[ws.styleIndex] : void 0;
@@ -227,7 +228,7 @@ function worksheetToBody(worksheet, sharedStrings, styles, date1904, print) {
227
228
  let icon;
228
229
  const sparkline = sparklineByCell.get(key(absR, absC));
229
230
  if (cfFormatter && ws) {
230
- const over = cfFormatter(absR, absC, ws.type === "n" && Number.isFinite(Number(ws.rawValue)) ? Number(ws.rawValue) : void 0);
231
+ const over = cfFormatter(absR, absC, ws.type === "n" && Number.isFinite(Number(ws.rawValue)) ? Number(ws.rawValue) : void 0, cfText);
231
232
  if (over) {
232
233
  if (over.fillHex) shading = { colorHex: over.fillHex };
233
234
  if (over.dataBar) dataBar = over.dataBar;
@@ -235,7 +236,11 @@ function worksheetToBody(worksheet, sharedStrings, styles, date1904, print) {
235
236
  runProps = applyCfOverride(runProps, over);
236
237
  }
237
238
  }
238
- if (text.length > 0 && !merge && ws && (ws.type === "s" || ws.type === "str" || ws.type === "inlineStr") && (alignment === void 0 || alignment === "left")) {
239
+ const wrapText = xf?.alignment?.wrapText === true;
240
+ const rotation = xf?.alignment?.textRotation;
241
+ const rotated = rotation !== void 0 && rotation !== 0 && text.length > 0;
242
+ const shrinkToFit = xf?.alignment?.shrinkToFit === true && !wrapText && !rotated;
243
+ if (text.length > 0 && !merge && !wrapText && !rotated && !shrinkToFit && ws && (ws.type === "s" || ws.type === "str" || ws.type === "inlineStr") && (alignment === void 0 || alignment === "left")) {
239
244
  let availTwips = columnWidths[c];
240
245
  let cc = c + 1;
241
246
  while (cc < colCount && !cellHasContent(cellMatrix[r]?.[cc])) {
@@ -247,7 +252,19 @@ function worksheetToBody(worksheet, sharedStrings, styles, date1904, print) {
247
252
  if (text.length > charsFit) text = text.slice(0, charsFit);
248
253
  }
249
254
  }
255
+ if (shrinkToFit && ws && text.length > 0) {
256
+ const charsFit = Math.max(1, columnWidths[c] / 105);
257
+ if (text.length > charsFit) {
258
+ const baseHalfPt = (styles.fonts[xf.fontId]?.sizePt ?? 11) * 2;
259
+ const scaledHalfPt = Math.max(2, Math.round(baseHalfPt * charsFit / text.length));
260
+ runProps = {
261
+ ...runProps,
262
+ fontSizePt: halfPtToPt(scaledHalfPt)
263
+ };
264
+ }
265
+ }
250
266
  const dropdown = dropdownRanges.length > 0 && rangesCover(dropdownRanges, absR, absC);
267
+ const href = print.hyperlinks && print.hyperlinks.length > 0 ? hyperlinkUrlAt(print.hyperlinks, absR, absC) : void 0;
251
268
  const visibleEndCol = merge ? Math.min(merge.endColumn, colWindowEnd) : 0;
252
269
  const properties = {
253
270
  ...merge && visibleEndCol > merge.startColumn ? { colSpan: visibleEndCol - merge.startColumn + 1 } : {},
@@ -259,19 +276,32 @@ function worksheetToBody(worksheet, sharedStrings, styles, date1904, print) {
259
276
  ...borders ? { borders } : {},
260
277
  ...dropdown ? { dropdown: true } : {}
261
278
  };
262
- const paragraphProps = cellParaProps(alignment);
279
+ const indentLevels = xf?.alignment?.indent ?? 0;
280
+ const baseParaProps = cellParaProps(alignment);
281
+ const paragraphProps = indentLevels > 0 ? {
282
+ ...baseParaProps,
283
+ indentLeft: twipsToPt(indentLevels * 3 * 105)
284
+ } : baseParaProps;
285
+ const richRuns = ws && ws.type === "s" && print.sharedStringRuns ? print.sharedStringRuns[Number(ws.rawValue)] : void 0;
286
+ const cellRuns = richRuns && richRuns.length > 0 ? richRuns.map((rr) => ({
287
+ text: rr.text,
288
+ properties: richRunProps(runProps, rr),
289
+ ...href ? { href } : {}
290
+ })) : text.length > 0 ? [{
291
+ text,
292
+ properties: runProps,
293
+ ...href ? { href } : {}
294
+ }] : [];
295
+ const content = rotated ? stackedVerticalContent(text, runProps, href) : [{
296
+ kind: "paragraph",
297
+ paragraph: {
298
+ properties: paragraphProps,
299
+ runs: cellRuns
300
+ }
301
+ }];
263
302
  cells.push({
264
303
  properties,
265
- content: [{
266
- kind: "paragraph",
267
- paragraph: {
268
- properties: paragraphProps,
269
- runs: text.length > 0 ? [{
270
- text,
271
- properties: runProps
272
- }] : []
273
- }
274
- }]
304
+ content
275
305
  });
276
306
  }
277
307
  const baseRowProps = rowHeightMap.get(r);
@@ -377,6 +407,31 @@ function runPropsFromXf(xf, styles) {
377
407
  if (font.colorHex) props.colorHex = font.colorHex;
378
408
  return props;
379
409
  }
410
+ function stackedVerticalContent(text, runProps, href) {
411
+ const out = [];
412
+ for (const ch of text) out.push({
413
+ kind: "paragraph",
414
+ paragraph: {
415
+ properties: { alignment: "center" },
416
+ runs: [{
417
+ text: ch,
418
+ properties: runProps,
419
+ ...href ? { href } : {}
420
+ }]
421
+ }
422
+ });
423
+ return out;
424
+ }
425
+ function richRunProps(base, rr) {
426
+ const out = { ...base };
427
+ if (rr.bold) out.bold = true;
428
+ if (rr.italic) out.italic = true;
429
+ if (rr.underline) out.underline = "single";
430
+ if (rr.colorHex) out.colorHex = rr.colorHex;
431
+ if (rr.sizePt !== void 0) out.fontSizePt = halfPtToPt(Math.round(rr.sizePt * 2));
432
+ if (rr.vertAlign) out.verticalAlign = rr.vertAlign;
433
+ return out;
434
+ }
380
435
  function applyCfOverride(base, o) {
381
436
  return {
382
437
  ...base,
@@ -398,14 +453,55 @@ function mapAlignment(h) {
398
453
  if (h === "justify") return "both";
399
454
  if (h === "distributed") return "distribute";
400
455
  }
456
+ var PATTERN_DENSITY = {
457
+ darkGray: .75,
458
+ mediumGray: .5,
459
+ lightGray: .25,
460
+ gray125: .125,
461
+ gray0625: .0625,
462
+ darkHorizontal: .5,
463
+ darkVertical: .5,
464
+ darkDown: .5,
465
+ darkUp: .5,
466
+ darkGrid: .62,
467
+ darkTrellis: .75,
468
+ lightHorizontal: .25,
469
+ lightVertical: .25,
470
+ lightDown: .25,
471
+ lightUp: .25,
472
+ lightGrid: .37,
473
+ lightTrellis: .5
474
+ };
401
475
  function shadingFromXf(xf, styles) {
402
476
  if (xf.applyFill === false) return void 0;
403
477
  if (xf.fillId === 0 || xf.fillId === 1) {
404
478
  if (!xf.applyFill) return void 0;
405
479
  }
406
480
  const fill = styles.fills[xf.fillId];
407
- if (!fill || fill.patternType !== "solid" || !fill.fgColorHex) return void 0;
408
- return { colorHex: fill.fgColorHex };
481
+ if (!fill) return void 0;
482
+ const pattern = fill.patternType;
483
+ if (!pattern || pattern === "none") return void 0;
484
+ if (pattern === "solid") return fill.fgColorHex ? { colorHex: fill.fgColorHex } : void 0;
485
+ const density = PATTERN_DENSITY[pattern];
486
+ if (density === void 0 || !fill.fgColorHex) return void 0;
487
+ const blended = blendHex(fill.fgColorHex, fill.bgColorHex ?? "FFFFFF", density);
488
+ return blended ? { colorHex: blended } : void 0;
489
+ }
490
+ function blendHex(fg, bg, fraction) {
491
+ const a = hexToRgb(fg);
492
+ const b = hexToRgb(bg);
493
+ if (!a || !b) return void 0;
494
+ const mix = (x, y) => Math.max(0, Math.min(255, Math.round(x * fraction + y * (1 - fraction)))).toString(16).padStart(2, "0").toUpperCase();
495
+ return `${mix(a[0], b[0])}${mix(a[1], b[1])}${mix(a[2], b[2])}`;
496
+ }
497
+ function hexToRgb(hex) {
498
+ const h = hex.length === 8 ? hex.slice(2) : hex;
499
+ if (!/^[0-9A-Fa-f]{6}$/.test(h)) return void 0;
500
+ return [
501
+ parseInt(h.slice(0, 2), 16),
502
+ parseInt(h.slice(2, 4), 16),
503
+ parseInt(h.slice(4, 6), 16)
504
+ ];
409
505
  }
410
506
  function bordersFromXf(xf, styles) {
411
507
  if (xf.applyBorder === false) return void 0;
@@ -421,6 +517,11 @@ function bordersFromXf(xf, styles) {
421
517
  if (right) out.right = right;
422
518
  if (bottom) out.bottom = bottom;
423
519
  if (left) out.left = left;
520
+ const diagonal = border.diagonal ? mapBorderEdge(border.diagonal) : void 0;
521
+ if (diagonal) {
522
+ if (border.diagonalDown) out.diagonalDown = diagonal;
523
+ if (border.diagonalUp) out.diagonalUp = diagonal;
524
+ }
424
525
  return Object.keys(out).length > 0 ? out : void 0;
425
526
  }
426
527
  function mapBorderEdge(edge) {
@@ -490,6 +591,12 @@ function rangesCover(ranges, row, col) {
490
591
  for (const r of ranges) if (row >= r.startRow && row <= r.endRow && col >= r.startColumn && col <= r.endColumn) return true;
491
592
  return false;
492
593
  }
594
+ function hyperlinkUrlAt(links, row, col) {
595
+ for (const l of links) {
596
+ const r = l.ref;
597
+ if (row >= r.startRow && row <= r.endRow && col >= r.startColumn && col <= r.endColumn) return l.url;
598
+ }
599
+ }
493
600
  function buildSparklineLookup(worksheet, print) {
494
601
  const out = /* @__PURE__ */ new Map();
495
602
  for (const sp of worksheet.sparklines ?? []) {
@@ -1 +1,6 @@
1
- export declare function parseSharedStrings(data: Uint8Array): Array<string>;
1
+ import { SheetRichRun } from '../core/spreadsheet-model/index.js';
2
+ export interface SharedStrings {
3
+ readonly texts: ReadonlyArray<string>;
4
+ readonly runs: ReadonlyArray<ReadonlyArray<SheetRichRun> | undefined>;
5
+ }
6
+ export declare function parseSharedStrings(data: Uint8Array): SharedStrings;
@@ -17,22 +17,101 @@ function capLen(s) {
17
17
  function parseSharedStrings(data) {
18
18
  const xml = decoder.decode(data);
19
19
  const sst = parser.parse(xml)["sst"];
20
- if (!sst || typeof sst !== "object") return [];
20
+ if (!sst || typeof sst !== "object") return {
21
+ texts: [],
22
+ runs: []
23
+ };
21
24
  const siRaw = sst["si"];
22
- return (Array.isArray(siRaw) ? siRaw : siRaw !== void 0 ? [siRaw] : []).map((item) => capLen(extractSiText(item)));
25
+ const items = Array.isArray(siRaw) ? siRaw : siRaw !== void 0 ? [siRaw] : [];
26
+ const texts = [];
27
+ const runs = [];
28
+ for (const item of items) {
29
+ const parsed = extractSi(item);
30
+ texts.push(capLen(parsed.text));
31
+ runs.push(parsed.runs);
32
+ }
33
+ return {
34
+ texts,
35
+ runs
36
+ };
23
37
  }
24
- function extractSiText(si) {
25
- if (typeof si === "string") return si;
26
- if (typeof si === "number") return String(si);
27
- if (!si || typeof si !== "object") return "";
38
+ function extractSi(si) {
39
+ if (typeof si === "string") return {
40
+ text: si,
41
+ runs: void 0
42
+ };
43
+ if (typeof si === "number") return {
44
+ text: String(si),
45
+ runs: void 0
46
+ };
47
+ if (!si || typeof si !== "object") return {
48
+ text: "",
49
+ runs: void 0
50
+ };
28
51
  const obj = si;
29
- const t = obj["t"];
30
- const direct = textOf(t);
31
- if (direct) return direct;
52
+ const direct = textOf(obj["t"]);
53
+ if (direct) return {
54
+ text: direct,
55
+ runs: void 0
56
+ };
32
57
  const r = obj["r"];
33
- if (Array.isArray(r)) return r.map((rr) => textOf(rr?.["t"])).join("");
34
- if (r && typeof r === "object") return textOf(r["t"]);
35
- return "";
58
+ const rs = Array.isArray(r) ? r : r && typeof r === "object" ? [r] : [];
59
+ if (rs.length === 0) return {
60
+ text: "",
61
+ runs: void 0
62
+ };
63
+ const runs = [];
64
+ let anyFormatting = false;
65
+ for (const rr of rs) {
66
+ const ro = rr;
67
+ const text = textOf(ro?.["t"]);
68
+ if (text.length === 0) continue;
69
+ const run = richRun(text, ro?.["rPr"]);
70
+ if (Object.keys(run).length > 1) anyFormatting = true;
71
+ runs.push(run);
72
+ }
73
+ return {
74
+ text: runs.map((x) => x.text).join(""),
75
+ runs: anyFormatting && runs.length > 0 ? runs : void 0
76
+ };
77
+ }
78
+ function richRun(text, rPr) {
79
+ const p = rPr && typeof rPr === "object" ? rPr : void 0;
80
+ if (!p) return { text };
81
+ const out = { text };
82
+ if (has(p, "b")) out.bold = true;
83
+ if (has(p, "i")) out.italic = true;
84
+ if (has(p, "u")) out.underline = true;
85
+ const color = colorRgb(p["color"]);
86
+ if (color) out.colorHex = color;
87
+ const sz = attrNum(p["sz"], "val");
88
+ if (sz !== void 0) out.sizePt = sz;
89
+ const vert = attrStr(p["vertAlign"], "val");
90
+ if (vert === "superscript" || vert === "subscript") out.vertAlign = vert;
91
+ return out;
92
+ }
93
+ function has(p, key) {
94
+ if (!(key in p)) return false;
95
+ const node = p[key];
96
+ const val = attrStr(node, "val");
97
+ return val !== "0" && val !== "false";
98
+ }
99
+ function attrStr(node, key) {
100
+ if (!node || typeof node !== "object") return void 0;
101
+ const v = node[`@_${key}`];
102
+ return typeof v === "string" ? v : void 0;
103
+ }
104
+ function attrNum(node, key) {
105
+ const s = attrStr(node, key);
106
+ if (s === void 0) return void 0;
107
+ const n = Number(s);
108
+ return Number.isFinite(n) ? n : void 0;
109
+ }
110
+ function colorRgb(node) {
111
+ const rgb = attrStr(node, "rgb");
112
+ if (!rgb) return void 0;
113
+ const hex = rgb.length === 8 ? rgb.slice(2) : rgb;
114
+ return /^[0-9A-Fa-f]{6}$/.test(hex) ? hex.toUpperCase() : void 0;
36
115
  }
37
116
  function textOf(node) {
38
117
  if (typeof node === "string") return node;
@@ -6,4 +6,16 @@ export interface SheetChartRef {
6
6
  readonly heightPt: number;
7
7
  readonly anchorRow: number;
8
8
  }
9
- export declare function parseSheetDrawing(drawingXml: Uint8Array, drawingPartPath: string, pkg: OpcPackage, worksheet: ParsedWorksheet): Array<SheetChartRef>;
9
+ export interface SheetPicture {
10
+ readonly imagePartPath: string;
11
+ readonly widthPt: number;
12
+ readonly heightPt: number;
13
+ readonly anchorRow: number;
14
+ }
15
+ export interface SheetDrawing {
16
+ readonly charts: Array<SheetChartRef>;
17
+ readonly pictures: Array<SheetPicture>;
18
+ }
19
+ export declare function parseSheetDrawing(drawingXml: Uint8Array, drawingPartPath: string, pkg: OpcPackage, worksheet: ParsedWorksheet): SheetDrawing;
20
+ export declare function makeColWidthPt(ws: ParsedWorksheet): (col: number) => number;
21
+ export declare function makeRowHeightPt(ws: ParsedWorksheet): (row: number) => number;
@@ -12,12 +12,20 @@ var parser = new XMLParser({
12
12
  var TWIPS_PER_PT = 20;
13
13
  function parseSheetDrawing(drawingXml, drawingPartPath, pkg, worksheet) {
14
14
  const root = parser.parse(new TextDecoder().decode(drawingXml))["wsDr"];
15
- if (!root || typeof root !== "object") return [];
15
+ if (!root || typeof root !== "object") return {
16
+ charts: [],
17
+ pictures: []
18
+ };
16
19
  const rootObj = root;
17
20
  const colWidthPt = makeColWidthPt(worksheet);
18
21
  const rowHeightPt = makeRowHeightPt(worksheet);
19
22
  const rels = pkg.getPartRelationships(drawingPartPath);
20
- const out = [];
23
+ const partPathOf = (relId) => {
24
+ const rel = rels.find((r) => r.id === relId);
25
+ return rel ? pkg.resolveRelatedPart(drawingPartPath, rel)?.path : void 0;
26
+ };
27
+ const charts = [];
28
+ const pictures = [];
21
29
  for (const kind of [
22
30
  "twoCellAnchor",
23
31
  "oneCellAnchor",
@@ -26,10 +34,8 @@ function parseSheetDrawing(drawingXml, drawingPartPath, pkg, worksheet) {
26
34
  if (!anchor || typeof anchor !== "object") continue;
27
35
  const a = anchor;
28
36
  const chartRelId = chartRelIdOf(a);
29
- if (!chartRelId) continue;
30
- const rel = rels.find((r) => r.id === chartRelId);
31
- const resolved = rel ? pkg.resolveRelatedPart(drawingPartPath, rel) : void 0;
32
- if (!resolved) continue;
37
+ const picRelId = chartRelId ? void 0 : picRelIdOf(a);
38
+ if (!chartRelId && !picRelId) continue;
33
39
  const from = cellMarker(a["from"]);
34
40
  let widthPt = 0;
35
41
  let heightPt = 0;
@@ -46,14 +52,41 @@ function parseSheetDrawing(drawingXml, drawingPartPath, pkg, worksheet) {
46
52
  heightPt = emuToPt(num(e["@_cy"]) ?? 0);
47
53
  }
48
54
  if (widthPt <= 0 || heightPt <= 0) continue;
49
- out.push({
50
- chartPartPath: resolved.path,
51
- widthPt,
52
- heightPt,
53
- anchorRow: from?.row ?? 0
54
- });
55
+ const anchorRow = from?.row ?? 0;
56
+ if (chartRelId) {
57
+ const path = partPathOf(chartRelId);
58
+ if (path) charts.push({
59
+ chartPartPath: path,
60
+ widthPt,
61
+ heightPt,
62
+ anchorRow
63
+ });
64
+ } else if (picRelId) {
65
+ const path = partPathOf(picRelId);
66
+ if (path) pictures.push({
67
+ imagePartPath: path,
68
+ widthPt,
69
+ heightPt,
70
+ anchorRow
71
+ });
72
+ }
55
73
  }
56
- return out.sort((x, y) => x.anchorRow - y.anchorRow);
74
+ charts.sort((x, y) => x.anchorRow - y.anchorRow);
75
+ pictures.sort((x, y) => x.anchorRow - y.anchorRow);
76
+ return {
77
+ charts,
78
+ pictures
79
+ };
80
+ }
81
+ function picRelIdOf(anchor) {
82
+ const pic = anchor["pic"];
83
+ if (!pic || typeof pic !== "object") return void 0;
84
+ const blipFill = pic["blipFill"];
85
+ if (!blipFill || typeof blipFill !== "object") return void 0;
86
+ const blip = blipFill["blip"];
87
+ if (!blip || typeof blip !== "object") return void 0;
88
+ const embed = blip["@_embed"];
89
+ return typeof embed === "string" && embed !== "" ? embed : void 0;
57
90
  }
58
91
  function chartRelIdOf(anchor) {
59
92
  const frame = anchor["graphicFrame"];
@@ -110,4 +143,4 @@ function asArray(v) {
110
143
  return Array.isArray(v) ? v : v !== void 0 ? [v] : [];
111
144
  }
112
145
  //#endregion
113
- export { parseSheetDrawing };
146
+ export { makeColWidthPt, makeRowHeightPt, parseSheetDrawing };
@@ -0,0 +1,4 @@
1
+ import { ShapeBlock } from '../core/document-model/index.js';
2
+ import { ColorResolver } from '../core/drawingml/colors.js';
3
+ import { ParsedWorksheet } from '../core/spreadsheet-model/index.js';
4
+ export declare function parseSheetShapes(drawingXml: Uint8Array, worksheet: ParsedWorksheet, colors: ColorResolver): Array<ShapeBlock>;
@@ -0,0 +1,96 @@
1
+ import { emuToPt, pt } from "../core/ir/units.js";
2
+ import { poChildren, poFirstChild, poIntAttr, poIs, poText } from "../core/po-helpers.js";
3
+ import { parseFill, parseLine } from "../word/drawing-parser.js";
4
+ import { parseGeometry, parseTxBody } from "../pptx/slide-parser.js";
5
+ import { parseXml } from "../pptx/pptx-reader.js";
6
+ import { makeColWidthPt, makeRowHeightPt } from "./sheet-drawing.js";
7
+ //#region src/excel/sheet-shape-parser.ts
8
+ var ANCHOR_KINDS = [
9
+ "xdr:twoCellAnchor",
10
+ "xdr:oneCellAnchor",
11
+ "xdr:absoluteAnchor"
12
+ ];
13
+ function parseSheetShapes(drawingXml, worksheet, colors) {
14
+ const wsDr = parseXml(drawingXml).find((n) => poIs(n, "xdr:wsDr"));
15
+ if (!wsDr) return [];
16
+ const colWidthPt = makeColWidthPt(worksheet);
17
+ const rowHeightPt = makeRowHeightPt(worksheet);
18
+ const shapes = [];
19
+ for (const anchor of poChildren(wsDr)) {
20
+ if (!ANCHOR_KINDS.some((k) => poIs(anchor, k))) continue;
21
+ const sp = poChildren(anchor).find((c) => poIs(c, "xdr:sp"));
22
+ if (!sp) continue;
23
+ const box = anchorBox(anchor, colWidthPt, rowHeightPt);
24
+ if (!box) continue;
25
+ const spPr = poChildren(sp).find((c) => poIs(c, "xdr:spPr"));
26
+ const geometry = parseGeometry(spPr);
27
+ const fill = spPr ? parseFill(spPr, colors) : { kind: "none" };
28
+ const line = spPr ? parseLine(spPr, colors) : void 0;
29
+ const txBody = poChildren(sp).find((c) => poIs(c, "xdr:txBody"));
30
+ const text = txBody ? parseTxBody(txBody, void 0, void 0, colors, void 0) : void 0;
31
+ const visibleLine = line !== void 0 && line.fill !== "none";
32
+ if (!text && fill.kind === "none" && !visibleLine) continue;
33
+ shapes.push({
34
+ shape: {
35
+ width: pt(box.widthPt),
36
+ height: pt(box.heightPt),
37
+ geometry,
38
+ fill,
39
+ ...line ? { line } : {},
40
+ ...text ? { text } : {},
41
+ paragraphProperties: {}
42
+ },
43
+ anchorRow: box.anchorRow
44
+ });
45
+ }
46
+ shapes.sort((a, b) => a.anchorRow - b.anchorRow);
47
+ return shapes.map((s) => s.shape);
48
+ }
49
+ function anchorBox(anchor, colWidthPt, rowHeightPt) {
50
+ const from = marker(poChildren(anchor).find((c) => poIs(c, "xdr:from")));
51
+ if (poIs(anchor, "xdr:twoCellAnchor")) {
52
+ const to = marker(poChildren(anchor).find((c) => poIs(c, "xdr:to")));
53
+ if (!from || !to) return void 0;
54
+ const widthPt = span(from.col, from.colOffPt, to.col, to.colOffPt, colWidthPt);
55
+ const heightPt = span(from.row, from.rowOffPt, to.row, to.rowOffPt, rowHeightPt);
56
+ return widthPt > 0 && heightPt > 0 ? {
57
+ widthPt,
58
+ heightPt,
59
+ anchorRow: from.row
60
+ } : void 0;
61
+ }
62
+ const ext = poChildren(anchor).find((c) => poIs(c, "xdr:ext"));
63
+ if (!ext) return void 0;
64
+ const widthPt = emuToPt(poIntAttr(ext, "cx") ?? 0);
65
+ const heightPt = emuToPt(poIntAttr(ext, "cy") ?? 0);
66
+ return widthPt > 0 && heightPt > 0 ? {
67
+ widthPt,
68
+ heightPt,
69
+ anchorRow: from?.row ?? 0
70
+ } : void 0;
71
+ }
72
+ function marker(node) {
73
+ if (!node) return void 0;
74
+ const col = childInt(node, "xdr:col");
75
+ const row = childInt(node, "xdr:row");
76
+ if (col === void 0 || row === void 0) return void 0;
77
+ return {
78
+ col,
79
+ row,
80
+ colOffPt: emuToPt(childInt(node, "xdr:colOff") ?? 0),
81
+ rowOffPt: emuToPt(childInt(node, "xdr:rowOff") ?? 0)
82
+ };
83
+ }
84
+ function childInt(parent, tag) {
85
+ const child = poFirstChild(parent, tag);
86
+ if (!child) return void 0;
87
+ const n = Number(poText(child));
88
+ return Number.isFinite(n) ? n : void 0;
89
+ }
90
+ function span(from, fromOffPt, to, toOffPt, trackPt) {
91
+ let total = 0;
92
+ for (let i = from; i < to; i++) total += trackPt(i);
93
+ return total - fromOffPt + toOffPt;
94
+ }
95
+ //#endregion
96
+ export { parseSheetShapes };