reamkit 1.16.0 → 1.17.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 (65) hide show
  1. package/dist/esm/core/bidi/segments.js +1 -2
  2. package/dist/esm/core/converter/project.js +5 -1
  3. package/dist/esm/core/document-model/index.d.ts +1 -1
  4. package/dist/esm/core/document-model/types.d.ts +473 -7
  5. package/dist/esm/core/drawingml/chart-geometry.d.ts +8 -12
  6. package/dist/esm/core/drawingml/chart-geometry.js +58 -9
  7. package/dist/esm/core/drawingml/chart-parser.js +44 -5
  8. package/dist/esm/core/drawingml/colors.d.ts +1 -1
  9. package/dist/esm/core/drawingml/colors.js +27 -1
  10. package/dist/esm/core/drawingml/preset-geometry.js +233 -0
  11. package/dist/esm/core/drawingml/shape-render.d.ts +12 -0
  12. package/dist/esm/core/drawingml/shape-render.js +116 -3
  13. package/dist/esm/core/drawingml/theme-parser.d.ts +10 -0
  14. package/dist/esm/core/drawingml/theme-parser.js +19 -1
  15. package/dist/esm/core/font/measure.d.ts +5 -0
  16. package/dist/esm/core/font/measure.js +21 -1
  17. package/dist/esm/core/images.d.ts +2 -2
  18. package/dist/esm/core/images.js +181 -0
  19. package/dist/esm/core/ir/flow.d.ts +23 -1
  20. package/dist/esm/core/numbering/apply.d.ts +5 -3
  21. package/dist/esm/core/numbering/apply.js +42 -11
  22. package/dist/esm/core/numbering/index.js +2 -0
  23. package/dist/esm/core/numbering/state.d.ts +13 -1
  24. package/dist/esm/core/numbering/state.js +256 -15
  25. package/dist/esm/core/po-helpers.js +16 -1
  26. package/dist/esm/core/style-cascade/resolver.js +66 -11
  27. package/dist/esm/core/style-cascade/table.js +35 -11
  28. package/dist/esm/core/style-cascade/types.d.ts +42 -1
  29. package/dist/esm/core/style-cascade/types.js +4 -0
  30. package/dist/esm/core/vector.d.ts +17 -0
  31. package/dist/esm/excel/print-model.js +1 -1
  32. package/dist/esm/excel/sheet-to-flow.js +10 -8
  33. package/dist/esm/excel/worksheet-parser.js +1 -1
  34. package/dist/esm/html/html-writer.js +18 -4
  35. package/dist/esm/layout/page-doc.d.ts +62 -2
  36. package/dist/esm/layout/styled-layout.d.ts +44 -2
  37. package/dist/esm/layout/styled-layout.js +1870 -228
  38. package/dist/esm/pdf/shading.js +76 -6
  39. package/dist/esm/pdf/styled-page-emitter.js +217 -43
  40. package/dist/esm/pdf/vector-graphics.d.ts +28 -1
  41. package/dist/esm/pdf/vector-graphics.js +94 -11
  42. package/dist/esm/pptx/pptx-reader.js +1 -0
  43. package/dist/esm/pptx/slide-parser.d.ts +21 -4
  44. package/dist/esm/pptx/slide-parser.js +86 -23
  45. package/dist/esm/svg/svg-writer.js +1 -1
  46. package/dist/esm/word/document-parser.d.ts +96 -7
  47. package/dist/esm/word/document-parser.js +537 -116
  48. package/dist/esm/word/docx-reader.js +135 -43
  49. package/dist/esm/word/docx-writer.js +6 -1
  50. package/dist/esm/word/drawing-parser.d.ts +53 -5
  51. package/dist/esm/word/drawing-parser.js +1540 -54
  52. package/dist/esm/word/index.d.ts +4 -4
  53. package/dist/esm/word/numbering-parser.d.ts +2 -1
  54. package/dist/esm/word/numbering-parser.js +107 -21
  55. package/dist/esm/word/paragraph-properties.d.ts +11 -1
  56. package/dist/esm/word/paragraph-properties.js +219 -10
  57. package/dist/esm/word/run-properties.js +45 -1
  58. package/dist/esm/word/settings-parser.d.ts +24 -0
  59. package/dist/esm/word/settings-parser.js +31 -5
  60. package/dist/esm/word/shading.d.ts +11 -0
  61. package/dist/esm/word/shading.js +64 -0
  62. package/dist/esm/word/styles-parser.js +8 -2
  63. package/dist/esm/word/table-parser.d.ts +9 -1
  64. package/dist/esm/word/table-parser.js +182 -30
  65. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { Chart, ChartSeries } from '../document-model/index.js';
1
+ import { Chart, ChartSeries, ShapeDash } from '../document-model/index.js';
2
2
  /**
3
3
  * An axis-aligned rectangle in the scene's local y-up frame: bars, scatter
4
4
  * point markers, legend swatches. Position is the bottom-left corner.
@@ -11,6 +11,8 @@ export interface ChartRect {
11
11
  readonly fillHex?: string;
12
12
  readonly strokeHex?: string;
13
13
  readonly strokeWidthPt?: number;
14
+ /** §20.1.10.49 — the outline's preset dash, when it names one. */
15
+ readonly strokeDash?: ShapeDash;
14
16
  }
15
17
  /** An open stroked polyline: line-chart series, gridlines and axis lines. */
16
18
  export interface ChartPolyline {
@@ -73,6 +75,11 @@ export interface ChartScene {
73
75
  readonly polygons?: ReadonlyArray<ChartPolygon>;
74
76
  /** §21.2.2.198 chart-space fill + outline: drawn under everything else. */
75
77
  readonly background?: ChartRect;
78
+ /**
79
+ * §21.2.2.145 the PLOT rectangle's own fill + outline, drawn over the chart
80
+ * frame and under the gridlines.
81
+ */
82
+ readonly plotBackground?: ChartRect;
76
83
  /**
77
84
  * Major gridlines, drawn UNDER the plotted data. Kept apart from the other
78
85
  * polylines because z-order is the whole point: gridlines over the bars strip
@@ -131,17 +138,6 @@ export declare function niceScale(dataMin: number, dataMax: number, maxTicks?: n
131
138
  * @returns The label text.
132
139
  */
133
140
  export declare function formatTick(v: number, step: number): string;
134
- /**
135
- * Lay out a bar/column {@link Chart} into a {@link ChartScene}. Honours
136
- * `chart.grouping` (clustered / stacked / percentStacked) and `chart.barDir`
137
- * (column vs horizontal bar), over the shared cartesian frame.
138
- *
139
- * @param chart The bar/column chart.
140
- * @param wPt Frame width in points.
141
- * @param hPt Frame height in points.
142
- * @param measure Text measurer used to size labels and reserve axis gutters.
143
- * @returns The positioned scene primitives.
144
- */
145
141
  export declare function buildBarScene(chart: Chart, wPt: number, hPt: number, measure: MeasureText): ChartScene;
146
142
  /**
147
143
  * The name a series shows in the legend: its own `c:tx`, or Excel's positional
@@ -186,7 +186,7 @@ function buildFrame(chart, wPt, hPt, measure, horizontal, opts = {}) {
186
186
  const fmtVal = opts.formatValue ?? ((v) => formatTick(v, scale.step));
187
187
  const tickVals = ticks(scale);
188
188
  const vals2 = onSecondary.flatMap((s) => s.values.slice(0, nCats));
189
- const scale2 = vals2.length > 0 ? niceScale(Math.min(0, ...vals2), Math.max(0, ...vals2), Math.min(10, Math.max(4, Math.round(hPt / 24)))) : void 0;
189
+ const scale2 = vals2.length > 0 ? niceScale(Math.min(0, ...vals2), Math.max(0, ...vals2), tickBudget(hPt)) : void 0;
190
190
  const tickVals2 = scale2 ? ticks(scale2) : [];
191
191
  let top = 4;
192
192
  if (chart.title) top += 13 * 1.6;
@@ -202,6 +202,18 @@ function buildFrame(chart, wPt, hPt, measure, horizontal, opts = {}) {
202
202
  const plotH = Math.max(1, hPt - top - y0);
203
203
  const valueOffset = (v) => (v - scale.min) / (scale.max - scale.min) * (horizontal ? plotW : plotH);
204
204
  const zeroOffset = valueOffset(0);
205
+ const plotBackground = chart.plotFillHex ?? chart.plotLine?.colorHex ? {
206
+ x: x0,
207
+ y: y0,
208
+ w: plotW,
209
+ h: plotH,
210
+ ...chart.plotFillHex ? { fillHex: chart.plotFillHex } : {},
211
+ ...chart.plotLine?.colorHex ? {
212
+ strokeHex: chart.plotLine.colorHex,
213
+ strokeWidthPt: chart.plotLine.widthPt ?? .75,
214
+ ...chart.plotLine.dash ? { strokeDash: chart.plotLine.dash } : {}
215
+ } : {}
216
+ } : void 0;
205
217
  pushChartTitle(labels, chart, wPt, hPt);
206
218
  if (chart.valAxisTitle) labels.push({
207
219
  text: chart.valAxisTitle,
@@ -288,6 +300,7 @@ function buildFrame(chart, wPt, hPt, measure, horizontal, opts = {}) {
288
300
  rects,
289
301
  polylines,
290
302
  gridlines,
303
+ ...plotBackground ? { plotBackground } : {},
291
304
  labels
292
305
  };
293
306
  }
@@ -352,6 +365,24 @@ function chartValueFormatter(chart) {
352
365
  * @param measure Text measurer used to size labels and reserve axis gutters.
353
366
  * @returns The positioned scene primitives.
354
367
  */
368
+ /**
369
+ * §21.2.2.198 `c:ser/c:spPr/a:ln` — a bar's own outline, as the stroke fields a
370
+ * {@link ChartRect} carries. Chart_BorderLine_Style.docx outlines each of its
371
+ * series in a colour and dash of its own, and drawing bars unstroked lost all
372
+ * of it.
373
+ *
374
+ * @param series The series the bar belongs to.
375
+ * @returns The stroke fields, or an empty object when the series has no rule.
376
+ */
377
+ function barOutline(series) {
378
+ const ln = series.line;
379
+ if (!ln || ln.none === true || !ln.colorHex) return {};
380
+ return {
381
+ strokeHex: ln.colorHex,
382
+ strokeWidthPt: ln.widthPt ?? .75,
383
+ ...ln.dash && ln.dash !== "solid" ? { strokeDash: ln.dash } : {}
384
+ };
385
+ }
355
386
  function buildBarScene(chart, wPt, hPt, measure) {
356
387
  const g = chart.grouping ?? "clustered";
357
388
  const stacked = g === "stacked" || g === "percentStacked";
@@ -379,19 +410,22 @@ function buildBarScene(chart, wPt, hPt, measure) {
379
410
  const lo = Math.min(o0, o1);
380
411
  const span = Math.abs(o1 - o0);
381
412
  const color = pointColor(series, c) ?? seriesColor(series, s, chart.seriesColorCycle);
413
+ const outline = barOutline(series);
382
414
  if (horizontal) f.rects.push({
383
415
  x: f.x0 + lo,
384
416
  y: along,
385
417
  w: span,
386
418
  h: barW,
387
- fillHex: color
419
+ fillHex: color,
420
+ ...outline
388
421
  });
389
422
  else f.rects.push({
390
423
  x: along,
391
424
  y: f.y0 + lo,
392
425
  w: barW,
393
426
  h: span,
394
- fillHex: color
427
+ fillHex: color,
428
+ ...outline
395
429
  });
396
430
  if (chart.showValues && span > 9) {
397
431
  const raw = series.values[c] ?? 0;
@@ -407,6 +441,8 @@ function buildBarScene(chart, wPt, hPt, measure) {
407
441
  rects: f.rects,
408
442
  polylines: f.polylines,
409
443
  gridlines: f.gridlines,
444
+ ...f.plotBackground ? { plotBackground: f.plotBackground } : {},
445
+ ...f.plotBackground ? { plotBackground: f.plotBackground } : {},
410
446
  wedges: [],
411
447
  labels: f.labels
412
448
  };
@@ -423,6 +459,7 @@ function buildBarScene(chart, wPt, hPt, measure) {
423
459
  const len = f.valueOffset(series.values[c] ?? 0) - f.zeroOffset;
424
460
  const color = pointColor(series, c) ?? seriesColor(series, s, chart.seriesColorCycle);
425
461
  const along = slotStart + b * barW;
462
+ const outline = barOutline(series);
426
463
  if (horizontal) {
427
464
  const bx = f.x0 + f.zeroOffset + Math.min(0, len);
428
465
  f.rects.push({
@@ -430,7 +467,8 @@ function buildBarScene(chart, wPt, hPt, measure) {
430
467
  y: along,
431
468
  w: Math.abs(len),
432
469
  h: barW,
433
- fillHex: color
470
+ fillHex: color,
471
+ ...outline
434
472
  });
435
473
  } else {
436
474
  const by = f.y0 + f.zeroOffset + Math.min(0, len);
@@ -439,7 +477,8 @@ function buildBarScene(chart, wPt, hPt, measure) {
439
477
  y: by,
440
478
  w: barW,
441
479
  h: Math.abs(len),
442
- fillHex: color
480
+ fillHex: color,
481
+ ...outline
443
482
  });
444
483
  }
445
484
  if (chart.showValues) {
@@ -466,6 +505,7 @@ function buildBarScene(chart, wPt, hPt, measure) {
466
505
  rects: f.rects,
467
506
  polylines: f.polylines,
468
507
  gridlines: f.gridlines,
508
+ ...f.plotBackground ? { plotBackground: f.plotBackground } : {},
469
509
  wedges: [],
470
510
  labels: f.labels
471
511
  };
@@ -580,6 +620,7 @@ function buildAreaScene(chart, wPt, hPt, measure) {
580
620
  rects: f.rects,
581
621
  polylines: f.polylines,
582
622
  gridlines: f.gridlines,
623
+ ...f.plotBackground ? { plotBackground: f.plotBackground } : {},
583
624
  wedges: [],
584
625
  labels: f.labels,
585
626
  polygons
@@ -670,8 +711,12 @@ function autoRange(vals) {
670
711
  const hi = Math.max(...vals);
671
712
  return [lo > 0 && lo < 5 / 6 * hi ? 0 : lo, hi];
672
713
  }
673
- /** Ticks that fit along an axis `extentPt` long (mirrors {@link axisScale}). */
674
- var tickBudget = (extentPt) => Math.min(10, Math.max(4, Math.round(extentPt / 24)));
714
+ /**
715
+ * Ticks that fit along an axis `extentPt` long (mirrors {@link axisScale}).
716
+ * A tick every 32pt is what both references draw: at 24 a 250pt plot carried
717
+ * eleven of them (0, 0.5, 1 … 5.5) where both label 0…6 in whole numbers.
718
+ */
719
+ var tickBudget = (extentPt) => Math.min(10, Math.max(4, Math.round(extentPt / 32)));
675
720
  /** Side (points) of the square stamped for a series that names no symbol. */
676
721
  var DEFAULT_MARKER_PT = 4;
677
722
  /**
@@ -722,7 +767,9 @@ function pushMarker(rects, wedges, marker, x, y, color) {
722
767
  */
723
768
  function buildLineScene(chart, wPt, hPt, measure) {
724
769
  const allVals = chart.series.flatMap((s) => s.values);
725
- const range = allVals.length > 0 ? [Math.min(...allVals), Math.max(...allVals)] : [0, 1];
770
+ const lo = allVals.length > 0 ? Math.min(...allVals) : 0;
771
+ const hi = allVals.length > 0 ? Math.max(...allVals) : 1;
772
+ const range = lo > 0 && lo > 5 / 6 * hi ? [lo, hi] : [Math.min(0, lo), Math.max(0, hi)];
726
773
  const lineFormat = chartValueFormatter(chart);
727
774
  const f = buildFrame(chart, wPt, hPt, measure, false, {
728
775
  dataRange: range,
@@ -760,6 +807,7 @@ function buildLineScene(chart, wPt, hPt, measure) {
760
807
  rects: f.rects,
761
808
  polylines: f.polylines,
762
809
  gridlines: f.gridlines,
810
+ ...f.plotBackground ? { plotBackground: f.plotBackground } : {},
763
811
  wedges,
764
812
  labels: f.labels
765
813
  };
@@ -1003,7 +1051,8 @@ function withFrame(scene, chart, wPt, hPt) {
1003
1051
  ...chart.frameFillHex ? { fillHex: chart.frameFillHex } : {},
1004
1052
  ...chart.frameLineHex ? {
1005
1053
  strokeHex: chart.frameLineHex,
1006
- strokeWidthPt: .75
1054
+ strokeWidthPt: chart.frameLineWidthPt ?? .75,
1055
+ ...chart.frameLineDash ? { strokeDash: chart.frameLineDash } : {}
1007
1056
  } : {}
1008
1057
  };
1009
1058
  return {
@@ -100,10 +100,15 @@ function parseChart(chartXml, resolveColor) {
100
100
  const valAxisMin = axisScaling(plotArea, "c:min");
101
101
  const valAxisMax = axisScaling(plotArea, "c:max");
102
102
  const catAxisReversed = axisOrientation(catAxNode) === "maxMin";
103
- const spaceSpPr = poChildren(tree.find((c) => poIs(c, "c:chartSpace"))).find((c) => poIs(c, "c:spPr"));
104
- const frameFillHex = fillColorOf(spaceSpPr, resolveColor);
103
+ const chartSpace = tree.find((c) => poIs(c, "c:chartSpace"));
104
+ const spaceSpPr = poChildren(chartSpace).find((c) => poIs(c, "c:spPr"));
105
105
  const frameLine = spaceSpPr ? poChildren(spaceSpPr).find((c) => poIs(c, "a:ln")) : void 0;
106
- const frameLineHex = frameLine ? fillColorOf(frameLine, resolveColor) : void 0;
106
+ const frameStyle = lineStyleOf(chartSpace, resolveColor);
107
+ const frameFillHex = spaceSpPr ? frameFillOf(spaceSpPr, resolveColor) : "FFFFFF";
108
+ const plotSpPr = poChildren(plotArea).find((c) => poIs(c, "c:spPr"));
109
+ const plotFillHex = plotSpPr ? frameFillOf(plotSpPr, resolveColor) : void 0;
110
+ const plotLine = lineStyleOf(plotArea, resolveColor);
111
+ const frameLineHex = spaceSpPr ? frameLine ? frameFillOf(frameLine, resolveColor) : void 0 : "D9D9D9";
107
112
  const numberFormat = valueFormatCode(plotArea);
108
113
  const legend = poChildren(chart).find((c) => poIs(c, "c:legend"));
109
114
  const legendPos = legend ? poVal(poChildren(legend).find((c) => poIs(c, "c:legendPos"))) : void 0;
@@ -138,6 +143,10 @@ function parseChart(chartXml, resolveColor) {
138
143
  ...valAxisMax !== void 0 ? { valAxisMax } : {},
139
144
  ...frameFillHex ? { frameFillHex } : {},
140
145
  ...frameLineHex ? { frameLineHex } : {},
146
+ ...frameStyle?.widthPt !== void 0 ? { frameLineWidthPt: frameStyle.widthPt } : {},
147
+ ...frameStyle?.dash ? { frameLineDash: frameStyle.dash } : {},
148
+ ...plotFillHex ? { plotFillHex } : {},
149
+ ...plotLine && plotLine.none !== true ? { plotLine } : {},
141
150
  ...numberFormat ? { numberFormat } : {}
142
151
  };
143
152
  }
@@ -238,6 +247,22 @@ function dataPointColors(ser, resolveColor) {
238
247
  }
239
248
  return out;
240
249
  }
250
+ /**
251
+ * The BACKGROUND fill of a frame (the chart space, the plot rectangle): its own
252
+ * `a:solidFill` and nothing else. Unlike a series, a frame that states
253
+ * `<a:noFill/>` is not filled in the colour of its own rule —
254
+ * Chart_Plot_BorderLine_Style.docx rules its plot in orange and we painted the
255
+ * whole plot orange.
256
+ *
257
+ * @param spPr The frame's `c:spPr`, or `undefined`.
258
+ * @param resolveColor Maps a DrawingML colour reference to 6-hex.
259
+ * @returns The fill colour, or `undefined` when the frame states none.
260
+ */
261
+ function frameFillOf(spPr, resolveColor) {
262
+ if (!spPr) return void 0;
263
+ const solid = poChildren(spPr).find((c) => poIs(c, "a:solidFill"));
264
+ return solid ? colorFromSolidFill(solid, resolveColor) : void 0;
265
+ }
241
266
  function fillColorOf(spPr, resolveColor) {
242
267
  if (!spPr) return void 0;
243
268
  const directFill = poChildren(spPr).find((c) => poIs(c, "a:solidFill"));
@@ -349,6 +374,16 @@ function axisScaling(plotArea, tag) {
349
374
  * @param resolveColor Maps a DrawingML colour reference to 6 hex digits.
350
375
  * @returns The rule, or undefined when the node says nothing about it.
351
376
  */
377
+ var DASHES = new Set([
378
+ "solid",
379
+ "dot",
380
+ "dash",
381
+ "dashDot",
382
+ "lgDash",
383
+ "lgDashDot",
384
+ "sysDash",
385
+ "sysDot"
386
+ ]);
352
387
  function lineStyleOf(owner, resolveColor) {
353
388
  const spPr = owner ? poChildren(owner).find((c) => poIs(c, "c:spPr")) : void 0;
354
389
  const ln = spPr ? poChildren(spPr).find((c) => poIs(c, "a:ln")) : void 0;
@@ -358,10 +393,14 @@ function lineStyleOf(owner, resolveColor) {
358
393
  const colorHex = solid ? colorFromSolidFill(solid, resolveColor) : void 0;
359
394
  const emu = Number(poAttr(ln, "w"));
360
395
  const widthPt = Number.isFinite(emu) && emu > 0 ? emu / 12700 : void 0;
361
- if (!colorHex && widthPt === void 0) return void 0;
396
+ const prst = poChildren(ln).find((c) => poIs(c, "a:prstDash"));
397
+ const dashVal = prst ? poAttr(prst, "val") : void 0;
398
+ const dash = dashVal !== void 0 && DASHES.has(dashVal) ? dashVal : void 0;
399
+ if (!colorHex && widthPt === void 0 && !dash) return void 0;
362
400
  return {
363
401
  ...colorHex ? { colorHex } : {},
364
- ...widthPt !== void 0 ? { widthPt } : {}
402
+ ...widthPt !== void 0 ? { widthPt } : {},
403
+ ...dash ? { dash } : {}
365
404
  };
366
405
  }
367
406
  function valueFormatCode(plotArea) {
@@ -2,7 +2,7 @@ import { PoNode } from '../po-helpers.js';
2
2
  /**
3
3
  * A colour transform child (§20.1.2.3): `lumMod`/`lumOff` modulate luminance,
4
4
  * `shade` darkens toward black, `tint` lightens toward white. `val` is normalised
5
- * to 0..1 (the XML stores thousandths of a percent). `alpha` is parsed but ignored
5
+ * to 0..1 (the XML stores thousandths of a percent). `alpha` composites over white
6
6
  * (solid fills emit no transparency).
7
7
  */
8
8
  export interface ColorMod {
@@ -102,7 +102,11 @@ function applyColorMods(hex, mods) {
102
102
  } else if (m.kind === "satOff") {
103
103
  const [h, sat, l] = rgbToHsl(r, g, b);
104
104
  [r, g, b] = hslToRgb(h, clamp01(sat + m.val), l);
105
- } else if (m.kind === "satMod") {
105
+ } else if (m.kind === "alpha") {
106
+ r = r * m.val + (1 - m.val);
107
+ g = g * m.val + (1 - m.val);
108
+ b = b * m.val + (1 - m.val);
109
+ } else {
106
110
  const [h, s, l] = rgbToHsl(r, g, b);
107
111
  [r, g, b] = hslToRgb(h, clamp01(s * m.val), l);
108
112
  }
@@ -157,6 +161,22 @@ function makeColorResolver(palette) {
157
161
  }
158
162
  /** A {@link ColorResolver} backed by the {@link DEFAULT_THEME_PALETTE}. */
159
163
  var defaultColorResolver = makeColorResolver(DEFAULT_THEME_PALETTE);
164
+ var PRESET_COLORS = new Map([
165
+ ["black", "000000"],
166
+ ["white", "FFFFFF"],
167
+ ["gray", "808080"],
168
+ ["grey", "808080"],
169
+ ["darkGray".toLowerCase(), "A9A9A9"],
170
+ ["lightGray".toLowerCase(), "D3D3D3"],
171
+ ["red", "FF0000"],
172
+ ["green", "008000"],
173
+ ["blue", "0000FF"],
174
+ ["yellow", "FFFF00"],
175
+ ["cyan", "00FFFF"],
176
+ ["magenta", "FF00FF"],
177
+ ["dkGray".toLowerCase(), "A9A9A9"],
178
+ ["ltGray".toLowerCase(), "D3D3D3"]
179
+ ]);
160
180
  /**
161
181
  * Read the colour transform children ({@link ColorMod}s) under an `a:srgbClr` /
162
182
  * `a:schemeClr` node, normalising each `val` from thousandths-of-a-percent to 0..1.
@@ -221,6 +241,12 @@ function resolveColorNode(c, resolveColor) {
221
241
  if (last && /^[0-9A-Fa-f]{6}$/.test(last)) return last.toUpperCase();
222
242
  return SYSTEM_COLORS.get(poAttr(c, "val") ?? "");
223
243
  }
244
+ if (poIs(c, "a:prstClr")) {
245
+ const hex = PRESET_COLORS.get((poAttr(c, "val") ?? "").toLowerCase());
246
+ if (hex === void 0) return void 0;
247
+ const presetMods = readColorMods(c);
248
+ return presetMods.length > 0 ? applyColorMods(hex, presetMods) : hex;
249
+ }
224
250
  const isSrgb = poIs(c, "a:srgbClr");
225
251
  if (!isSrgb && !poIs(c, "a:schemeClr")) return void 0;
226
252
  const v = poAttr(c, "val");
@@ -86,8 +86,33 @@ function presetPaths(preset, w, h, adjust) {
86
86
  [0, h / 2]
87
87
  ])];
88
88
  }
89
+ case "round1Rect":
90
+ case "round2SameRect":
91
+ case "round2DiagRect":
92
+ case "snip1Rect":
93
+ case "snip2SameRect":
94
+ case "snip2DiagRect":
95
+ case "snipRoundRect": return [cornerRect(preset, w, h, adjust)];
96
+ case "star4":
97
+ case "star5":
98
+ case "star6":
99
+ case "star7":
100
+ case "star8":
101
+ case "star10":
102
+ case "star12":
103
+ case "star16":
104
+ case "star24":
105
+ case "star32": {
106
+ const s = STARS.get(preset);
107
+ return s ? [star(w, h, s, adjust)] : null;
108
+ }
89
109
  case "line":
90
110
  case "straightConnector1": return [new PathBuilder().moveTo(0, h).lineTo(w, 0).build()];
111
+ case "bentConnector2": return [new PathBuilder().moveTo(0, h).lineTo(w, h).lineTo(w, 0).build()];
112
+ case "bentConnector3": {
113
+ const bx = clamp(frac(adjust, "adj1", 5e4), 0, 1) * w;
114
+ return [new PathBuilder().moveTo(0, h).lineTo(bx, h).lineTo(bx, 0).lineTo(w, 0).build()];
115
+ }
91
116
  case "rightArrow": return [blockArrow(w, h, adjust, "right")];
92
117
  case "leftArrow": return [blockArrow(w, h, adjust, "left")];
93
118
  case "upArrow": return [blockArrow(w, h, adjust, "up")];
@@ -157,6 +182,214 @@ function customPaths(geom, wPt, hPt) {
157
182
  }
158
183
  return [b.build()];
159
184
  }
185
+ var SQUARE = {
186
+ cut: 0,
187
+ round: false
188
+ };
189
+ var CORNER_RECTS = new Map([
190
+ ["round1Rect", {
191
+ defaults: [16667, 0],
192
+ corners: [
193
+ void 0,
194
+ 0,
195
+ void 0,
196
+ void 0
197
+ ],
198
+ round: true
199
+ }],
200
+ ["snip1Rect", {
201
+ defaults: [16667, 0],
202
+ corners: [
203
+ void 0,
204
+ 0,
205
+ void 0,
206
+ void 0
207
+ ],
208
+ round: false
209
+ }],
210
+ ["round2SameRect", {
211
+ defaults: [16667, 0],
212
+ corners: [
213
+ 0,
214
+ 0,
215
+ 1,
216
+ 1
217
+ ],
218
+ round: true
219
+ }],
220
+ ["snip2SameRect", {
221
+ defaults: [16667, 0],
222
+ corners: [
223
+ 0,
224
+ 0,
225
+ 1,
226
+ 1
227
+ ],
228
+ round: false
229
+ }],
230
+ ["round2DiagRect", {
231
+ defaults: [16667, 0],
232
+ corners: [
233
+ 0,
234
+ 1,
235
+ 0,
236
+ 1
237
+ ],
238
+ round: true
239
+ }],
240
+ ["snip2DiagRect", {
241
+ defaults: [16667, 0],
242
+ corners: [
243
+ 0,
244
+ 1,
245
+ 0,
246
+ 1
247
+ ],
248
+ round: false
249
+ }],
250
+ ["snipRoundRect", {
251
+ defaults: [16667, 16667],
252
+ corners: [
253
+ 0,
254
+ 1,
255
+ void 0,
256
+ void 0
257
+ ],
258
+ round: [false, true]
259
+ }]
260
+ ]);
261
+ function cornerRect(preset, w, h, adjust) {
262
+ const spec = CORNER_RECTS.get(preset);
263
+ const ss = Math.min(w, h);
264
+ const guide = (i) => {
265
+ return clamp((adjust.get(i === 0 ? "adj1" : "adj2") ?? (i === 0 ? adjust.get("adj") : void 0) ?? spec.defaults[i]) / 1e5, 0, .5) * ss;
266
+ };
267
+ return roundedCorners(w, h, spec.corners.map((g) => {
268
+ if (g === void 0) return SQUARE;
269
+ const round = typeof spec.round === "boolean" ? spec.round : spec.round[g];
270
+ return {
271
+ cut: guide(g),
272
+ round
273
+ };
274
+ }));
275
+ }
276
+ function roundedCorners(w, h, [tl, tr, br, bl]) {
277
+ const at = [
278
+ {
279
+ c: tl,
280
+ from: [0, h - tl.cut],
281
+ to: [tl.cut, h],
282
+ centre: [tl.cut, h - tl.cut],
283
+ start: Math.PI
284
+ },
285
+ {
286
+ c: tr,
287
+ from: [w - tr.cut, h],
288
+ to: [w, h - tr.cut],
289
+ centre: [w - tr.cut, h - tr.cut],
290
+ start: Math.PI / 2
291
+ },
292
+ {
293
+ c: br,
294
+ from: [w, br.cut],
295
+ to: [w - br.cut, 0],
296
+ centre: [w - br.cut, br.cut],
297
+ start: 0
298
+ },
299
+ {
300
+ c: bl,
301
+ from: [bl.cut, 0],
302
+ to: [0, bl.cut],
303
+ centre: [bl.cut, bl.cut],
304
+ start: -Math.PI / 2
305
+ }
306
+ ];
307
+ const b = new PathBuilder();
308
+ at.forEach((corner, i) => {
309
+ if (i === 0) b.moveTo(corner.from[0], corner.from[1]);
310
+ else b.lineTo(corner.from[0], corner.from[1]);
311
+ if (corner.c.cut <= 0) return;
312
+ if (corner.c.round) b.append(arcToBeziers(corner.centre[0], corner.centre[1], corner.c.cut, corner.c.cut, corner.start, -Math.PI / 2));
313
+ else b.lineTo(corner.to[0], corner.to[1]);
314
+ });
315
+ return b.close().build();
316
+ }
317
+ var STARS = new Map([
318
+ ["star4", {
319
+ points: 4,
320
+ adj: 12500,
321
+ hf: 1e5,
322
+ vf: 1e5
323
+ }],
324
+ ["star5", {
325
+ points: 5,
326
+ adj: 19098,
327
+ hf: 105146,
328
+ vf: 110557
329
+ }],
330
+ ["star6", {
331
+ points: 6,
332
+ adj: 28868,
333
+ hf: 115470,
334
+ vf: 1e5
335
+ }],
336
+ ["star7", {
337
+ points: 7,
338
+ adj: 34601,
339
+ hf: 102572,
340
+ vf: 105210
341
+ }],
342
+ ["star8", {
343
+ points: 8,
344
+ adj: 37500,
345
+ hf: 1e5,
346
+ vf: 1e5
347
+ }],
348
+ ["star10", {
349
+ points: 10,
350
+ adj: 42533,
351
+ hf: 105146,
352
+ vf: 1e5
353
+ }],
354
+ ["star12", {
355
+ points: 12,
356
+ adj: 37500,
357
+ hf: 1e5,
358
+ vf: 1e5
359
+ }],
360
+ ["star16", {
361
+ points: 16,
362
+ adj: 37500,
363
+ hf: 1e5,
364
+ vf: 1e5
365
+ }],
366
+ ["star24", {
367
+ points: 24,
368
+ adj: 37500,
369
+ hf: 1e5,
370
+ vf: 1e5
371
+ }],
372
+ ["star32", {
373
+ points: 32,
374
+ adj: 37500,
375
+ hf: 1e5,
376
+ vf: 1e5
377
+ }]
378
+ ]);
379
+ function star(w, h, preset, adjust) {
380
+ const inner = clamp(frac(adjust, "adj", preset.adj) * 2, 0, 1);
381
+ const hf = preset.hf / 1e5;
382
+ const vf = preset.vf / 1e5;
383
+ const pts = [];
384
+ for (let i = 0; i < preset.points; i++) {
385
+ const out = -Math.PI / 2 + i * 2 * Math.PI / preset.points;
386
+ for (const [angle, r] of [[out, 1], [out + Math.PI / preset.points, inner]]) {
387
+ const x = w / 2 * (1 + hf * r * Math.cos(angle));
388
+ pts.push([x, h - h / 2 * vf * (1 + r * Math.sin(angle))]);
389
+ }
390
+ }
391
+ return polygon(pts);
392
+ }
160
393
  function regularPolygon(w, h, n) {
161
394
  const cx = w / 2;
162
395
  const cy = h / 2;
@@ -37,6 +37,18 @@ export declare function gradientToSolid(gradient: ShapeGradient): string;
37
37
  * @returns The `<linearGradient>` or `<radialGradient>` markup.
38
38
  */
39
39
  export declare function gradientSvgDef(id: string, g: ShapeGradient): string;
40
+ /**
41
+ * §20.1.8.24 / §20.1.8.42 — the arrowheads a line asks for at its ends, as
42
+ * filled paths in the same local frame as the shape's own geometry. The head
43
+ * rides the first point of the first subpath and the tail the last point of
44
+ * the last one, each turned along the segment that reaches it.
45
+ *
46
+ * @param paths The shape's geometry paths.
47
+ * @param line The parsed line (its `headEnd`/`tailEnd` are read).
48
+ * @param strokeWidthPt The pen width the decorations are sized against.
49
+ * @returns The decoration paths (empty when the line asks for none).
50
+ */
51
+ export declare function lineEndPaths(paths: ReadonlyArray<VectorPath>, line: ShapeLine | undefined, strokeWidthPt: number): Array<VectorPath>;
40
52
  /**
41
53
  * Build a {@link StrokeStyle} from a shape's `a:ln` line, resolving the default
42
54
  * width (0.75pt), dash pattern and line cap. Returns `undefined` for no line or