@pixerate/editor 0.51.0 → 0.53.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 (69) hide show
  1. package/dist/agent/index.cjs +23 -23
  2. package/dist/agent/index.js +4 -4
  3. package/dist/chart/index.cjs +475 -124
  4. package/dist/chart/index.cjs.map +1 -1
  5. package/dist/chart/index.d.cts +174 -25
  6. package/dist/chart/index.d.ts +174 -25
  7. package/dist/chart/index.js +375 -24
  8. package/dist/chart/index.js.map +1 -1
  9. package/dist/{chunk-GJBIVWB2.js → chunk-3S72F46R.js} +387 -9
  10. package/dist/chunk-3S72F46R.js.map +1 -0
  11. package/dist/{chunk-5TWIN7ZJ.js → chunk-47WWV3LI.js} +34 -4
  12. package/dist/chunk-47WWV3LI.js.map +1 -0
  13. package/dist/{chunk-OV7UAKIY.js → chunk-633QC34G.js} +172 -1
  14. package/dist/chunk-633QC34G.js.map +1 -0
  15. package/dist/{chunk-MR2764X2.js → chunk-AGGUNWT6.js} +2 -322
  16. package/dist/chunk-AGGUNWT6.js.map +1 -0
  17. package/dist/{chunk-T6XU4B54.js → chunk-BQQZ6MOI.js} +7 -7
  18. package/dist/{chunk-LNKZPIQD.cjs → chunk-C3JHII3M.cjs} +67 -67
  19. package/dist/{chunk-LNKZPIQD.cjs.map → chunk-C3JHII3M.cjs.map} +1 -1
  20. package/dist/{chunk-JOX6MJW4.cjs → chunk-CKRNELPO.cjs} +176 -5
  21. package/dist/chunk-CKRNELPO.cjs.map +1 -0
  22. package/dist/{chunk-TGBCBQFV.cjs → chunk-DK6QBGCS.cjs} +45 -15
  23. package/dist/chunk-DK6QBGCS.cjs.map +1 -0
  24. package/dist/{chunk-GTZXF4BI.cjs → chunk-NK3WL5TJ.cjs} +298 -133
  25. package/dist/chunk-NK3WL5TJ.cjs.map +1 -0
  26. package/dist/{chunk-3JNRQVTS.cjs → chunk-NN3JGUSX.cjs} +402 -24
  27. package/dist/chunk-NN3JGUSX.cjs.map +1 -0
  28. package/dist/{chunk-3CC7OPUQ.cjs → chunk-O6FO6VI3.cjs} +3 -323
  29. package/dist/chunk-O6FO6VI3.cjs.map +1 -0
  30. package/dist/{chunk-DQPBQXKG.js → chunk-OIKYP7XC.js} +8 -8
  31. package/dist/{chunk-FEMIVHN3.cjs → chunk-P43HUQRX.cjs} +16 -16
  32. package/dist/{chunk-FEMIVHN3.cjs.map → chunk-P43HUQRX.cjs.map} +1 -1
  33. package/dist/{chunk-QFTVLEVN.js → chunk-RIXTW3C4.js} +3 -3
  34. package/dist/{chunk-WBOAXDKD.js → chunk-VODBAO32.js} +222 -57
  35. package/dist/chunk-VODBAO32.js.map +1 -0
  36. package/dist/{chunk-2Q46FKZK.cjs → chunk-YZZMX6V7.cjs} +25 -25
  37. package/dist/{chunk-2Q46FKZK.cjs.map → chunk-YZZMX6V7.cjs.map} +1 -1
  38. package/dist/{controller-DS3drIvy.d.cts → controller-CX0QfSv0.d.cts} +53 -2
  39. package/dist/{controller-BdKzaxs2.d.ts → controller-DscWQbjO.d.ts} +53 -2
  40. package/dist/export/index.cjs +5 -5
  41. package/dist/export/index.js +4 -4
  42. package/dist/extensions/index.cjs +7 -7
  43. package/dist/extensions/index.d.cts +2 -2
  44. package/dist/extensions/index.d.ts +2 -2
  45. package/dist/extensions/index.js +6 -6
  46. package/dist/{index-Dt9lzydb.d.ts → index-CALDD35B.d.ts} +1 -1
  47. package/dist/{index-DOy9HzfC.d.cts → index-DIWB6xMf.d.cts} +1 -1
  48. package/dist/index.cjs +15 -14
  49. package/dist/index.cjs.map +1 -1
  50. package/dist/index.d.cts +6 -113
  51. package/dist/index.d.ts +6 -113
  52. package/dist/index.js +13 -12
  53. package/dist/index.js.map +1 -1
  54. package/dist/zip-4nG0YAH7.d.cts +110 -0
  55. package/dist/zip-4nG0YAH7.d.ts +110 -0
  56. package/package.json +1 -1
  57. package/dist/chunk-3CC7OPUQ.cjs.map +0 -1
  58. package/dist/chunk-3JNRQVTS.cjs.map +0 -1
  59. package/dist/chunk-5TWIN7ZJ.js.map +0 -1
  60. package/dist/chunk-GJBIVWB2.js.map +0 -1
  61. package/dist/chunk-GTZXF4BI.cjs.map +0 -1
  62. package/dist/chunk-JOX6MJW4.cjs.map +0 -1
  63. package/dist/chunk-MR2764X2.js.map +0 -1
  64. package/dist/chunk-OV7UAKIY.js.map +0 -1
  65. package/dist/chunk-TGBCBQFV.cjs.map +0 -1
  66. package/dist/chunk-WBOAXDKD.js.map +0 -1
  67. /package/dist/{chunk-T6XU4B54.js.map → chunk-BQQZ6MOI.js.map} +0 -0
  68. /package/dist/{chunk-DQPBQXKG.js.map → chunk-OIKYP7XC.js.map} +0 -0
  69. /package/dist/{chunk-QFTVLEVN.js.map → chunk-RIXTW3C4.js.map} +0 -0
@@ -7,15 +7,16 @@ import {
7
7
  TRENDLINE_PROPS,
8
8
  VALUE,
9
9
  WIDTH
10
- } from "../chunk-5TWIN7ZJ.js";
10
+ } from "../chunk-47WWV3LI.js";
11
11
  import {
12
12
  CHART_OOXML_CONTENT_TYPE,
13
13
  CHART_OOXML_NS,
14
14
  CHART_OOXML_RELATIONSHIP,
15
15
  chartFormatToCode,
16
16
  chartFromOoxml,
17
- chartToOoxml
18
- } from "../chunk-GJBIVWB2.js";
17
+ chartToOoxml,
18
+ readZip
19
+ } from "../chunk-3S72F46R.js";
19
20
  import {
20
21
  CHART_COLOR_SCHEMES,
21
22
  CHART_DATE_STEPS,
@@ -34,6 +35,8 @@ import {
34
35
  chartMovingAverage,
35
36
  chartPresetPatch,
36
37
  chartQuantile,
38
+ chartScaleFromPixel,
39
+ chartScaleToPixel,
37
40
  chartSceneToDomSpec,
38
41
  chartSceneToSvg,
39
42
  chartSerialToDate,
@@ -61,6 +64,7 @@ import {
61
64
  layoutSparkline,
62
65
  linearMap,
63
66
  monochromeChartPalette,
67
+ niceLogScale,
64
68
  niceScale,
65
69
  niceStep,
66
70
  parseChartDate,
@@ -71,10 +75,14 @@ import {
71
75
  summarizeChart,
72
76
  summarizeChartSeries,
73
77
  trendNumberText
74
- } from "../chunk-WBOAXDKD.js";
78
+ } from "../chunk-VODBAO32.js";
75
79
  import {
76
80
  CHART_AXIS_KINDS,
81
+ CHART_AXIS_SCALES,
77
82
  CHART_CURVES,
83
+ CHART_ERROR_BAR_DIRECTIONS,
84
+ CHART_ERROR_BAR_LABELS,
85
+ CHART_ERROR_BAR_TYPES,
78
86
  CHART_LABEL_POSITIONS,
79
87
  CHART_LEGEND_POSITIONS,
80
88
  CHART_MARKERS,
@@ -95,6 +103,8 @@ import {
95
103
  chartContrastRatio,
96
104
  chartDataFromTable,
97
105
  chartDataToTable,
106
+ chartErrorAmounts,
107
+ chartErrorBarsOfType,
98
108
  chartFamily,
99
109
  chartLuminance,
100
110
  chartPointColor,
@@ -110,18 +120,23 @@ import {
110
120
  createChartSpec,
111
121
  cyclePaletteColor,
112
122
  defaultChartAxis,
123
+ defaultChartErrorBarValue,
124
+ describeChartErrorBars,
125
+ formatChartAmountList,
113
126
  isCartesianChart,
114
127
  isXyChart,
115
128
  normalizeChartAxis,
129
+ normalizeChartErrorBars,
116
130
  normalizeChartSpec,
117
131
  normalizeChartTrendline,
118
132
  normalizeChartValues,
133
+ parseChartAmountList,
119
134
  parseChartColor,
120
135
  parseChartValue,
121
136
  shadeChartColor,
122
137
  simulateChartVision,
123
138
  uniqueChartSeriesId
124
- } from "../chunk-OV7UAKIY.js";
139
+ } from "../chunk-633QC34G.js";
125
140
  import "../chunk-EKYHKQPG.js";
126
141
  import {
127
142
  parseCsv
@@ -135,9 +150,9 @@ function chartRasterSize(width, height, scale = 2, maxSize = CHART_RASTER_MAX_SI
135
150
  const factor = Math.min(scale > 0 ? scale : 1, maxSize / Math.max(width, height));
136
151
  return { width: Math.max(1, Math.round(width * factor)), height: Math.max(1, Math.round(height * factor)), scale: factor };
137
152
  }
138
- function closingParen(text, open) {
153
+ function closingParen(text, open2) {
139
154
  let depth = 0;
140
- for (let i = open; i < text.length; i++) {
155
+ for (let i = open2; i < text.length; i++) {
141
156
  if (text[i] === "(") depth++;
142
157
  else if (text[i] === ")" && --depth === 0) return i + 1;
143
158
  }
@@ -412,7 +427,7 @@ function createChartCommands(controller, options = {}) {
412
427
  id: `${prefix}update`,
413
428
  label: "Change Chart\u2026",
414
429
  keywords: ["chart", "title", "axis", "legend", "stack", "style", "format", "type"],
415
- description: "Changes chart presentation as one undo step: type, titles, axes (xAxis = categories, yAxis = values, yAxis2 = secondary values), legend, stacking, orientation, curve, points, data labels, palette, donut hole, bar spacing, histogram bins or waterfall total. Invalid values change nothing and return why.",
430
+ description: 'Changes chart presentation as one undo step: type, titles, axes (xAxis = categories, yAxis = values, yAxis2 = secondary values; reverse, and scale "log" on value axes), legend, stacking, orientation, curve, points, data labels, palette, donut hole, bar spacing, histogram bins or waterfall total. Invalid values change nothing and return why.',
416
431
  params: object(CHART_UPDATE_PROPERTIES),
417
432
  run: (_ctx, params) => {
418
433
  check(controller.update(params));
@@ -466,7 +481,7 @@ function createChartCommands(controller, options = {}) {
466
481
  id: `${prefix}updateSeries`,
467
482
  label: "Change Series\u2026",
468
483
  keywords: ["chart", "series", "rename", "colour", "color", "hide", "axis", "marker"],
469
- description: "Renames, recolours, hides, moves to the secondary axis or changes how a series is drawn (null resets a field).",
484
+ description: "Renames, recolours, hides, moves to the secondary axis or changes how a series is drawn, including error bars (null resets a field).",
470
485
  params: object({ series: SERIES_REF, ...Object.fromEntries(Object.entries(SERIES_PROPS).filter(([k]) => k !== "values")) }, ["series"]),
471
486
  run: (_ctx, params) => {
472
487
  const { series, ...patch } = params;
@@ -689,13 +704,14 @@ function snapChartDragValue(scene, value, options = {}) {
689
704
  const scale = options.scale ?? scene.valueScale;
690
705
  const tolerance = options.tolerancePx ?? 6;
691
706
  if (scale) {
692
- const px = (v) => linearMap(v, scale.domain, scale.range);
707
+ const px = (v) => chartScaleToPixel(v, scale);
693
708
  const at = px(value);
694
709
  let best = null;
695
710
  let bestDist = tolerance;
696
711
  for (const c of [...options.candidates ?? [], ...scale.ticks]) {
697
712
  if (!Number.isFinite(c)) continue;
698
713
  const d = Math.abs(px(c) - at);
714
+ if (!Number.isFinite(d)) continue;
699
715
  if (d <= bestDist) {
700
716
  best = c;
701
717
  bestDist = d;
@@ -703,7 +719,7 @@ function snapChartDragValue(scene, value, options = {}) {
703
719
  }
704
720
  if (best !== null) return best;
705
721
  }
706
- return snapChartValue(scene, value, options.step, scale?.ticks);
722
+ return snapChartValue(scene, value, options.step, scale?.ticks, scale?.logBase);
707
723
  }
708
724
  function startChartPointDrag(controller, scene, target, start, options = {}) {
709
725
  if (!canDragChartPoint(controller, scene, target)) return null;
@@ -737,27 +753,31 @@ function startChartPointDrag(controller, scene, target, start, options = {}) {
737
753
  const at = chartValueAtPoint(scene, point, secondary);
738
754
  if (at === void 0) return;
739
755
  const factor = moveOptions.fine ? 0.1 : 1;
740
- let dy = (at - startAt) * factor;
741
- let dx = 0;
756
+ const moved = (from, to, s, value) => s.logBase && value > 0 && from > 0 && to > 0 ? value * Math.pow(to / from, factor) : value + (to - from) * factor;
757
+ let moveY = true;
758
+ let moveX = false;
759
+ let atX;
742
760
  if (xy && startX !== null && startAtX !== void 0) {
743
- const atX = chartXAtPoint(scene, point);
744
- if (atX !== void 0) dx = (atX - startAtX) * factor;
761
+ atX = chartXAtPoint(scene, point);
762
+ moveX = atX !== void 0;
745
763
  if (moveOptions.lockAxis) {
746
- if (Math.abs(point.x - start.x) >= Math.abs(point.y - start.y)) dy = 0;
747
- else dx = 0;
764
+ if (Math.abs(point.x - start.x) >= Math.abs(point.y - start.y)) moveY = false;
765
+ else moveX = false;
748
766
  }
749
767
  }
750
768
  const snap = (v, s, c) => {
751
769
  if (moveOptions.noSnap) return Number(v.toPrecision(12));
752
770
  if (moveOptions.fine) {
771
+ if (s.logBase && !options.step) return v > 0 ? Number(v.toPrecision(3)) : v;
753
772
  const unit = options.step ? options.step / 10 : s.ticks.length > 1 ? (s.ticks[1] - s.ticks[0]) / 100 : void 0;
754
773
  return snapChartValue(scene, v, unit, s.ticks);
755
774
  }
756
775
  return snapChartDragValue(scene, v, { candidates: c, tolerancePx: options.tolerancePx, step: options.step, scale: s });
757
776
  };
758
- const y = snap(startValue + dy, scale, candidates);
777
+ const y = moveY ? snap(moved(startAt, at, scale, startValue), scale, candidates) : startValue;
759
778
  if (xy && startX !== null) {
760
- const x = dx !== 0 ? snap(startX + dx, scene.xScale, [0, startX]) : startX;
779
+ const nextX = moveX ? moved(startAtX, atX, scene.xScale, startX) : startX;
780
+ const x = nextX !== startX ? snap(nextX, scene.xScale, [0, startX]) : startX;
761
781
  const xs = [...series.x ?? []];
762
782
  xs[index] = x;
763
783
  controller.setValue(seriesId, index, y, { label });
@@ -804,11 +824,21 @@ function handleChartKey(controller, scene, event) {
804
824
  case "ArrowUp":
805
825
  case "ArrowDown": {
806
826
  if (selection?.kind !== "point" || scene?.percent) return false;
807
- const secondary = controller.getSeries(selection.seriesId)?.axis === "secondary";
808
- const ticks = (secondary ? scene?.valueScale2 : null)?.ticks ?? scene?.valueScale?.ticks ?? [];
827
+ const series = controller.getSeries(selection.seriesId);
828
+ const secondary = series?.axis === "secondary";
829
+ const scale = (secondary ? scene?.valueScale2 : null) ?? scene?.valueScale;
830
+ const ticks = scale?.ticks ?? [];
831
+ const up = event.key === "ArrowUp";
832
+ const current = series?.values[selection.index] ?? null;
833
+ if (scale?.logBase && current !== null && current > 0) {
834
+ const power = event.shiftKey ? 1 : event.altKey ? 0.01 : 0.1;
835
+ const next = Number((current * Math.pow(scale.logBase, up ? power : -power)).toPrecision(event.altKey ? 4 : 3));
836
+ controller.nudgeValue(selection.seriesId, selection.index, next - current);
837
+ return true;
838
+ }
809
839
  const step = ticks.length > 1 ? ticks[1] - ticks[0] : 1;
810
840
  const amount = event.shiftKey ? step : event.altKey ? step / 100 : step / 10;
811
- controller.nudgeValue(selection.seriesId, selection.index, amount * (event.key === "ArrowUp" ? 1 : -1));
841
+ controller.nudgeValue(selection.seriesId, selection.index, amount * (up ? 1 : -1));
812
842
  return true;
813
843
  }
814
844
  default:
@@ -1055,7 +1085,7 @@ function createChartToolProvider(controller, options = {}) {
1055
1085
  const updateChart = {
1056
1086
  name: "update_chart",
1057
1087
  title: "Change chart presentation",
1058
- description: "Changes how the chart looks, as one undo step: type, titles, axes (xAxis = categories or numeric x, yAxis = values, yAxis2 = secondary values), legend, stacking, orientation, curve, points, data labels and their position, palette, donut hole, bar spacing, histogram bins, waterfall total. All-or-nothing: invalid values change nothing and come back as sentences. Returns the new spec.",
1088
+ description: 'Changes how the chart looks, as one undo step: type, titles, axes (xAxis = categories or numeric x, yAxis = values, yAxis2 = secondary values; each can be reversed, and value axes can be logarithmic with scale "log"), legend, stacking, orientation, curve, points, data labels and their position, palette, donut hole, bar spacing, histogram bins, waterfall total. All-or-nothing: invalid values change nothing and come back as sentences. Returns the new spec.',
1059
1089
  inputSchema: {
1060
1090
  type: "object",
1061
1091
  properties: CHART_UPDATE_PROPERTIES,
@@ -1143,7 +1173,7 @@ function createChartToolProvider(controller, options = {}) {
1143
1173
  const updateSeries = {
1144
1174
  name: "update_chart_series",
1145
1175
  title: "Change a series",
1146
- description: "Renames, recolours, hides, moves to the secondary axis or changes how a series is drawn (marker, curve, labels, format, x values, bubble sizes, point colours). null resets a field. Values change with set_chart_values. Returns the series.",
1176
+ description: "Renames, recolours, hides, moves to the secondary axis or changes how a series is drawn (marker, curve, labels, format, x values, bubble sizes, point colours, error bars). null resets a field. Values change with set_chart_values. Returns the series.",
1147
1177
  inputSchema: {
1148
1178
  type: "object",
1149
1179
  properties: { series: SERIES_REF, ...Object.fromEntries(Object.entries(SERIES_PROPS).filter(([k]) => k !== "values")) },
@@ -1803,11 +1833,315 @@ var ChartDirector = class {
1803
1833
  }
1804
1834
  }
1805
1835
  };
1836
+
1837
+ // src/chart/office-files.ts
1838
+ var OfficeChartsError = class extends Error {
1839
+ constructor(message, options) {
1840
+ super(message, options);
1841
+ this.name = "OfficeChartsError";
1842
+ }
1843
+ };
1844
+ var CHARTEX_NS = "http://schemas.microsoft.com/office/drawing/2014/chartex";
1845
+ var STRICT_CHART_NS = "http://purl.oclc.org/ooxml/drawingml/chart";
1846
+ var dirname = (path) => path.slice(0, path.lastIndexOf("/") + 1);
1847
+ function resolvePartPath(baseDir, target) {
1848
+ const out = [];
1849
+ for (const segment of (target.startsWith("/") ? target.slice(1) : baseDir + target).split("/")) {
1850
+ if (segment === "" || segment === ".") continue;
1851
+ if (segment === "..") out.pop();
1852
+ else out.push(segment);
1853
+ }
1854
+ return out.join("/");
1855
+ }
1856
+ var relsPathFor = (partPath) => `${dirname(partPath)}_rels/${partPath.slice(dirname(partPath).length)}.rels`;
1857
+ function elements(root, localName) {
1858
+ return Array.from(root.getElementsByTagNameNS("*", localName));
1859
+ }
1860
+ function relId(el, localName = "id") {
1861
+ for (const a of Array.from(el.attributes)) {
1862
+ if (a.localName === localName && (a.namespaceURI?.includes("relationships") || a.prefix === "r")) return a.value;
1863
+ }
1864
+ return void 0;
1865
+ }
1866
+ var firstChild = (el, localName) => el ? Array.from(el.children ?? el.childNodes).find((n) => n.nodeType === 1 && n.localName === localName) : void 0;
1867
+ async function readXml(r, path) {
1868
+ const entry = r.zip.get(path) ?? r.zip.entries.find((e) => e.name.toLowerCase() === path.toLowerCase());
1869
+ if (!entry) return null;
1870
+ const doc = new r.Parser().parseFromString(await r.zip.readText(entry), "application/xml");
1871
+ return doc.getElementsByTagName("parsererror").length ? null : doc;
1872
+ }
1873
+ async function readRels(r, partPath) {
1874
+ const rels = /* @__PURE__ */ new Map();
1875
+ const doc = await readXml(r, relsPathFor(partPath));
1876
+ if (!doc) return rels;
1877
+ for (const rel of elements(doc, "Relationship")) {
1878
+ const id = rel.getAttribute("Id");
1879
+ if (!id) continue;
1880
+ const target = rel.getAttribute("Target") ?? "";
1881
+ const external = rel.getAttribute("TargetMode")?.toLowerCase() === "external";
1882
+ rels.set(id, { type: rel.getAttribute("Type") ?? "", target: external ? target : resolvePartPath(dirname(partPath), target), external });
1883
+ }
1884
+ return rels;
1885
+ }
1886
+ var isChartRef = (el) => el.localName === "chart" && (el.namespaceURI === CHART_OOXML_NS || el.namespaceURI === STRICT_CHART_NS || el.namespaceURI === CHARTEX_NS);
1887
+ function frameName(ref) {
1888
+ for (let el = ref.parentElement; el; el = el.parentElement) {
1889
+ if (el.localName === "graphicFrame") {
1890
+ const nv = elements(el, "cNvPr")[0];
1891
+ return nv?.getAttribute("name") || void 0;
1892
+ }
1893
+ }
1894
+ return void 0;
1895
+ }
1896
+ async function chartsInPart(r, root, rels, place) {
1897
+ for (const ref of elements(root, "chart")) {
1898
+ if (r.charts.length >= r.max) return;
1899
+ if (!isChartRef(ref)) continue;
1900
+ const rel = rels.get(relId(ref) ?? "");
1901
+ if (!rel || rel.external || r.seen.has(rel.target)) continue;
1902
+ const entry = r.zip.get(rel.target);
1903
+ if (!entry) continue;
1904
+ r.seen.add(rel.target);
1905
+ const read = chartFromOoxml(await r.zip.readText(entry), { DOMParser: r.Parser });
1906
+ const name = frameName(ref);
1907
+ r.charts.push({
1908
+ id: `chart-${r.charts.length + 1}`,
1909
+ path: rel.target,
1910
+ partKind: ref.namespaceURI === CHARTEX_NS ? "chartex" : "chart",
1911
+ ...place(ref),
1912
+ ...name ? { name } : {},
1913
+ title: read.spec.title,
1914
+ spec: read.spec,
1915
+ issues: read.issues.map((i) => i.message),
1916
+ unsupported: read.unsupported,
1917
+ lossless: read.lossless
1918
+ });
1919
+ }
1920
+ }
1921
+ function columnName(index) {
1922
+ let name = "";
1923
+ for (let n = index + 1; n > 0; n = Math.floor((n - 1) / 26)) name = String.fromCharCode(65 + (n - 1) % 26) + name;
1924
+ return name;
1925
+ }
1926
+ function anchorCell(marker) {
1927
+ const col = Number(firstChild(marker, "col")?.textContent);
1928
+ const row = Number(firstChild(marker, "row")?.textContent);
1929
+ return Number.isInteger(col) && Number.isInteger(row) && col >= 0 && row >= 0 ? `${columnName(col)}${row + 1}` : void 0;
1930
+ }
1931
+ function drawingPlace(ref) {
1932
+ for (let el = ref.parentElement; el; el = el.parentElement) {
1933
+ if (el.localName === "twoCellAnchor" || el.localName === "oneCellAnchor") {
1934
+ const anchor = anchorCell(firstChild(el, "from"));
1935
+ const to = el.localName === "twoCellAnchor" ? anchorCell(firstChild(el, "to")) : void 0;
1936
+ return { ...anchor ? { anchor } : {}, ...anchor && to ? { range: `${anchor}:${to}` } : {} };
1937
+ }
1938
+ if (el.localName === "absoluteAnchor") return {};
1939
+ }
1940
+ return {};
1941
+ }
1942
+ async function readMainPart(r) {
1943
+ const rootRels = await readRels(r, "");
1944
+ const main = [...rootRels.values()].find((rel) => /\/officeDocument$/.test(rel.type) && !rel.external);
1945
+ const doc = main ? await readXml(r, main.target) : null;
1946
+ if (!main || !doc) throw new OfficeChartsError("This is not an Office file: _rels/.rels names no main part (expected an .xlsx, .pptx or .docx file).");
1947
+ return { path: main.target, doc };
1948
+ }
1949
+ async function readXlsx(r, main) {
1950
+ const rels = await readRels(r, main.path);
1951
+ for (const sheet of elements(main.doc, "sheet")) {
1952
+ const rel = rels.get(relId(sheet) ?? "");
1953
+ if (!rel || rel.external) continue;
1954
+ const doc = await readXml(r, rel.target);
1955
+ if (!doc) continue;
1956
+ const sheetName = sheet.getAttribute("name") ?? rel.target;
1957
+ const sheetRels = await readRels(r, rel.target);
1958
+ for (const drawingRef of elements(doc, "drawing")) {
1959
+ const drawingRel = sheetRels.get(relId(drawingRef) ?? "");
1960
+ if (!drawingRel || drawingRel.external) continue;
1961
+ const drawing = await readXml(r, drawingRel.target);
1962
+ if (!drawing) continue;
1963
+ const drawingRels = await readRels(r, drawingRel.target);
1964
+ await chartsInPart(r, drawing, drawingRels, (ref) => ({ sheet: sheetName, ...drawingPlace(ref) }));
1965
+ }
1966
+ }
1967
+ }
1968
+ async function readPptx(r, main) {
1969
+ const rels = await readRels(r, main.path);
1970
+ const slides = elements(main.doc, "sldId");
1971
+ for (let i = 0; i < slides.length; i++) {
1972
+ const rel = rels.get(relId(slides[i]) ?? "");
1973
+ if (!rel || rel.external) continue;
1974
+ const doc = await readXml(r, rel.target);
1975
+ if (!doc) continue;
1976
+ await chartsInPart(r, doc, await readRels(r, rel.target), () => ({ slide: i + 1 }));
1977
+ }
1978
+ }
1979
+ async function readDocx(r, main) {
1980
+ await chartsInPart(r, main.doc, await readRels(r, main.path), () => ({}));
1981
+ }
1982
+ async function open(bytes, options) {
1983
+ const Parser = options.DOMParser ?? globalThis.DOMParser;
1984
+ if (!Parser) throw new OfficeChartsError("Reading Office files needs a DOMParser. In Node, pass one (e.g. from jsdom or @xmldom/xmldom) as { DOMParser }.");
1985
+ let zip;
1986
+ try {
1987
+ zip = await readZip(bytes, options);
1988
+ } catch (error) {
1989
+ throw new OfficeChartsError(`This is not an Office file: ${error.message}`, { cause: error });
1990
+ }
1991
+ const r = { zip, Parser, max: options.maxCharts ?? 500, charts: [], seen: /* @__PURE__ */ new Set() };
1992
+ const main = await readMainPart(r);
1993
+ const root = main.doc.documentElement.localName;
1994
+ const format = root === "workbook" ? "xlsx" : root === "presentation" ? "pptx" : root === "document" ? "docx" : void 0;
1995
+ if (!format) throw new OfficeChartsError(`The main part ${main.path} is a <${root}>; expected an Excel workbook, PowerPoint presentation or Word document.`);
1996
+ return { r, main, format };
1997
+ }
1998
+ var READERS = { xlsx: readXlsx, pptx: readPptx, docx: readDocx };
1999
+ async function extractOfficeCharts(bytes, options = {}) {
2000
+ const { r, main, format } = await open(bytes, options);
2001
+ await READERS[format](r, main);
2002
+ return { format, charts: r.charts };
2003
+ }
2004
+ async function extractAs(format, bytes, options) {
2005
+ const result = await extractOfficeCharts(bytes, options);
2006
+ if (result.format !== format) throw new OfficeChartsError(`This is a .${result.format} file, not a .${format} file.`);
2007
+ return result.charts;
2008
+ }
2009
+ var extractXlsxCharts = (bytes, options = {}) => extractAs("xlsx", bytes, options);
2010
+ var extractPptxCharts = (bytes, options = {}) => extractAs("pptx", bytes, options);
2011
+ var extractDocxCharts = (bytes, options = {}) => extractAs("docx", bytes, options);
2012
+ function describeOfficeChartPlace(chart) {
2013
+ if (chart.sheet !== void 0) return chart.anchor ? `${chart.sheet}!${chart.anchor}` : chart.sheet;
2014
+ if (chart.slide !== void 0) return `Slide ${chart.slide}`;
2015
+ return "Document";
2016
+ }
2017
+
2018
+ // src/chart/file-tools.ts
2019
+ var READ2 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
2020
+ var DESTRUCTIVE2 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
2021
+ var fail3 = (message) => {
2022
+ throw new Error(message);
2023
+ };
2024
+ function fromBase64(data) {
2025
+ const clean = data.replace(/^data:[^,]*,/, "").replace(/\s+/g, "");
2026
+ let binary;
2027
+ try {
2028
+ binary = atob(clean);
2029
+ } catch {
2030
+ return fail3('"data" is not valid base64. Pass the whole .xlsx, .pptx or .docx file encoded as base64 (a data: URL prefix is fine).');
2031
+ }
2032
+ const out = new Uint8Array(binary.length);
2033
+ for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
2034
+ return out;
2035
+ }
2036
+ function chartSummary(chart) {
2037
+ return {
2038
+ id: chart.id,
2039
+ place: describeOfficeChartPlace(chart),
2040
+ ...chart.sheet !== void 0 ? { sheet: chart.sheet } : {},
2041
+ ...chart.slide !== void 0 ? { slide: chart.slide } : {},
2042
+ ...chart.anchor ? { anchor: chart.anchor } : {},
2043
+ ...chart.range ? { range: chart.range } : {},
2044
+ ...chart.name ? { name: chart.name } : {},
2045
+ path: chart.path,
2046
+ partKind: chart.partKind,
2047
+ title: chart.title,
2048
+ type: chart.spec.type,
2049
+ series: chart.spec.series.map((s) => s.name),
2050
+ categories: chart.spec.categories.length,
2051
+ issues: chart.issues,
2052
+ unsupported: chart.unsupported,
2053
+ lossless: chart.lossless
2054
+ };
2055
+ }
2056
+ function createOfficeChartToolProvider(options = {}) {
2057
+ const cache = /* @__PURE__ */ new WeakMap();
2058
+ const readOnlyReason = () => {
2059
+ const r = typeof options.readOnly === "function" ? options.readOnly() : options.readOnly;
2060
+ if (!r) return null;
2061
+ return typeof r === "string" ? r : "This chart is read-only.";
2062
+ };
2063
+ const source = options.files ? { file: { type: "string", description: "Name of an open file, as list_open_files returns it." } } : { data: { type: "string", description: "The whole .xlsx, .pptx or .docx file as base64 (a data: URL prefix is allowed)." } };
2064
+ const sourceKey = options.files ? "file" : "data";
2065
+ const read = (args) => {
2066
+ if (!options.files) return extractOfficeCharts(fromBase64(String(args.data)), { DOMParser: options.DOMParser });
2067
+ const files = options.files();
2068
+ const file = files.find((f) => f.name === args.file);
2069
+ if (!file) return fail3(`There is no open file "${String(args.file)}"; expected one of ${files.map((f) => JSON.stringify(f.name)).join(", ") || "(none; ask the user to open an .xlsx, .pptx or .docx file)"}.`);
2070
+ let result = cache.get(file);
2071
+ if (!result) {
2072
+ result = extractOfficeCharts(file.data, { DOMParser: options.DOMParser });
2073
+ cache.set(file, result);
2074
+ result.catch(() => cache.delete(file));
2075
+ }
2076
+ return result;
2077
+ };
2078
+ const chartById = async (args) => {
2079
+ const { charts } = await read(args);
2080
+ const chart = charts.find((c) => c.id === args.chartId);
2081
+ if (!chart) fail3(`There is no chart "${String(args.chartId)}" in this file; expected one of ${charts.map((c) => `"${c.id}" (${describeOfficeChartPlace(c)})`).join(", ") || "(none: the file has no charts)"}.`);
2082
+ return chart;
2083
+ };
2084
+ const CHART_ID = { type: "string", description: 'Chart id from list_file_charts, e.g. "chart-1".' };
2085
+ const listOpenFiles = {
2086
+ name: "list_open_files",
2087
+ title: "List open files",
2088
+ description: "Lists the Office files the user opened that charts can be read from. Returns their names and sizes in bytes.",
2089
+ inputSchema: { type: "object", properties: {}, additionalProperties: false },
2090
+ annotations: { title: "List open files", ...READ2 },
2091
+ handler: () => ({ files: (options.files?.() ?? []).map((f) => ({ name: f.name, bytes: f.data.byteLength })) })
2092
+ };
2093
+ const listCharts = {
2094
+ name: "list_file_charts",
2095
+ title: "List the charts in an Office file",
2096
+ description: "Reads an Excel workbook, PowerPoint deck or Word document and lists its charts in file order: id, where it sits (sheet name and anchor cell, or slide number), title, type, series names, number of categories, read problems, features the chart editor cannot hold, and whether it reads losslessly. Pass an id to get_file_chart or load_file_chart.",
2097
+ inputSchema: { type: "object", properties: { ...source }, required: [sourceKey], additionalProperties: false },
2098
+ annotations: { title: "List the charts in an Office file", ...READ2 },
2099
+ handler: async (args) => {
2100
+ const result = await read(args);
2101
+ return { format: result.format, charts: result.charts.map(chartSummary) };
2102
+ }
2103
+ };
2104
+ const getChart = {
2105
+ name: "get_file_chart",
2106
+ title: "Get a chart from an Office file",
2107
+ description: "Returns one chart of an Office file with its full chart spec (data, axes, series styles), where it sits and its read problems.",
2108
+ inputSchema: { type: "object", properties: { ...source, chartId: CHART_ID }, required: [sourceKey, "chartId"], additionalProperties: false },
2109
+ annotations: { title: "Get a chart from an Office file", ...READ2 },
2110
+ handler: async (args) => {
2111
+ const chart = await chartById(args);
2112
+ return { ...chartSummary(chart), spec: chart.spec };
2113
+ }
2114
+ };
2115
+ const loadChart = {
2116
+ name: "load_file_chart",
2117
+ title: "Load a chart from an Office file",
2118
+ description: "Replaces the chart in the editor with a chart from an Office file, as one undo step. Returns the new spec, read problems and features the editor could not keep.",
2119
+ inputSchema: { type: "object", properties: { ...source, chartId: CHART_ID }, required: [sourceKey, "chartId"], additionalProperties: false },
2120
+ annotations: { title: "Load a chart from an Office file", ...DESTRUCTIVE2 },
2121
+ handler: async (args) => {
2122
+ const reason = readOnlyReason();
2123
+ if (reason) fail3(reason);
2124
+ const chart = await chartById(args);
2125
+ const result = options.controller.update({ ...chart.spec }, { label: "Load chart from file" });
2126
+ if (!result.ok) fail3(result.message ?? "The chart could not be loaded.");
2127
+ return { id: chart.id, place: describeOfficeChartPlace(chart), spec: options.controller.toJSON(), issues: chart.issues, unsupported: chart.unsupported, lossless: chart.lossless };
2128
+ }
2129
+ };
2130
+ return {
2131
+ id: options.id ?? "office-charts",
2132
+ ...options.namespace ? { namespace: options.namespace } : {},
2133
+ tools: () => [...options.files ? [listOpenFiles] : [], listCharts, getChart, ...options.controller && !readOnlyReason() ? [loadChart] : []]
2134
+ };
2135
+ }
1806
2136
  export {
1807
2137
  CHART_AXIS_KINDS,
2138
+ CHART_AXIS_SCALES,
1808
2139
  CHART_COLOR_SCHEMES,
1809
2140
  CHART_CURVES,
1810
2141
  CHART_DATE_STEPS,
2142
+ CHART_ERROR_BAR_DIRECTIONS,
2143
+ CHART_ERROR_BAR_LABELS,
2144
+ CHART_ERROR_BAR_TYPES,
1811
2145
  CHART_LABEL_POSITIONS,
1812
2146
  CHART_LAYOUT_PRESETS,
1813
2147
  CHART_LEGEND_POSITIONS,
@@ -1836,6 +2170,7 @@ export {
1836
2170
  MAX_CHART_DATA_LABELS,
1837
2171
  MAX_CHART_LINE_POINTS,
1838
2172
  MAX_CHART_MARKERS,
2173
+ OfficeChartsError,
1839
2174
  RENDER_CHART_INSTRUCTIONS,
1840
2175
  analyzeChartTable,
1841
2176
  blendChartScenes,
@@ -1850,6 +2185,8 @@ export {
1850
2185
  chartDataToTable,
1851
2186
  chartDateLabels,
1852
2187
  chartDateToSerial,
2188
+ chartErrorAmounts,
2189
+ chartErrorBarsOfType,
1853
2190
  chartFamily,
1854
2191
  chartFileName,
1855
2192
  chartFormatToCode,
@@ -1868,6 +2205,8 @@ export {
1868
2205
  chartRasterSize,
1869
2206
  chartRgbToHex,
1870
2207
  chartRgbToOklab,
2208
+ chartScaleFromPixel,
2209
+ chartScaleToPixel,
1871
2210
  chartSceneToDomSpec,
1872
2211
  chartSceneToSvg,
1873
2212
  chartSerialToDate,
@@ -1896,16 +2235,25 @@ export {
1896
2235
  createChartSpec,
1897
2236
  createChartToolProvider,
1898
2237
  createInstantChartClock,
2238
+ createOfficeChartToolProvider,
1899
2239
  cyclePaletteColor,
1900
2240
  decimateChartPoints,
1901
2241
  defaultChartAxis,
2242
+ defaultChartErrorBarValue,
1902
2243
  describeChart,
2244
+ describeChartErrorBars,
1903
2245
  describeChartSelection,
2246
+ describeOfficeChartPlace,
1904
2247
  downloadChartPng,
1905
2248
  easeChartTween,
1906
2249
  estimateChartTextWidth,
2250
+ extractDocxCharts,
2251
+ extractOfficeCharts,
2252
+ extractPptxCharts,
2253
+ extractXlsxCharts,
1907
2254
  findMermaidCharts,
1908
2255
  fitChartTrendline,
2256
+ formatChartAmountList,
1909
2257
  formatChartDate,
1910
2258
  formatChartNumber,
1911
2259
  formatChartValueWithCode,
@@ -1916,12 +2264,15 @@ export {
1916
2264
  layoutSparkline,
1917
2265
  linearMap,
1918
2266
  monochromeChartPalette,
2267
+ niceLogScale,
1919
2268
  niceScale,
1920
2269
  niceStep,
1921
2270
  normalizeChartAxis,
2271
+ normalizeChartErrorBars,
1922
2272
  normalizeChartSpec,
1923
2273
  normalizeChartTrendline,
1924
2274
  normalizeChartValues,
2275
+ parseChartAmountList,
1925
2276
  parseChartColor,
1926
2277
  parseChartDate,
1927
2278
  parseChartValue,