@pixerate/editor 0.162.0 → 0.163.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 (81) hide show
  1. package/README.md +1 -1
  2. package/dist/agent/index.cjs +34 -34
  3. package/dist/agent/index.js +5 -5
  4. package/dist/animation-editor/index.cjs +57 -57
  5. package/dist/animation-editor/index.js +3 -3
  6. package/dist/{brushstrokeRender-Q4LI22QV.js → brushstrokeRender-7LXCU7PD.js} +2 -2
  7. package/dist/{brushstrokeRender-5WANQIG4.cjs → brushstrokeRender-VO4ZTWVA.cjs} +5 -5
  8. package/dist/canvas/index.cjs +14 -14
  9. package/dist/canvas/index.js +3 -3
  10. package/dist/chart/commands.d.cts +2 -1
  11. package/dist/chart/commands.d.ts +2 -1
  12. package/dist/chart/controller.d.cts +109 -1
  13. package/dist/chart/controller.d.ts +109 -1
  14. package/dist/chart/index.cjs +605 -130
  15. package/dist/chart/index.d.cts +1 -0
  16. package/dist/chart/index.d.ts +1 -0
  17. package/dist/chart/index.js +490 -15
  18. package/dist/chart/layout-annotations.d.cts +29 -0
  19. package/dist/chart/layout-annotations.d.ts +29 -0
  20. package/dist/chart/layout-families.d.cts +23 -0
  21. package/dist/chart/layout-families.d.ts +23 -0
  22. package/dist/chart/mermaid.d.cts +2 -1
  23. package/dist/chart/mermaid.d.ts +2 -1
  24. package/dist/chart/schemas.d.cts +13 -0
  25. package/dist/chart/schemas.d.ts +13 -0
  26. package/dist/chart/spec.d.cts +30 -5
  27. package/dist/chart/spec.d.ts +30 -5
  28. package/dist/chart/stats.d.cts +9 -1
  29. package/dist/chart/stats.d.ts +9 -1
  30. package/dist/chart/tools.d.cts +1 -1
  31. package/dist/chart/tools.d.ts +1 -1
  32. package/dist/chart/tree.d.cts +62 -0
  33. package/dist/chart/tree.d.ts +62 -0
  34. package/dist/chart/types.d.cts +77 -3
  35. package/dist/chart/types.d.ts +77 -3
  36. package/dist/{chunk-7YBDRJXT.cjs → chunk-22KLZZGH.cjs} +8 -8
  37. package/dist/{chunk-LQLZHP6F.js → chunk-36OKQDCF.js} +7 -4
  38. package/dist/{chunk-HLOKB7WW.js → chunk-3NEZJCBY.js} +366 -6
  39. package/dist/{chunk-GWV4T5NZ.js → chunk-3VLOOO3G.js} +1 -1
  40. package/dist/{chunk-3GJH2MGH.cjs → chunk-5AARIS3R.cjs} +35 -35
  41. package/dist/{chunk-EVPZ5IKN.js → chunk-5FNGLV2D.js} +65 -3
  42. package/dist/{chunk-EQ46F75O.cjs → chunk-D54JHQK2.cjs} +51 -51
  43. package/dist/{chunk-NO5QQDHZ.js → chunk-DAPQGA55.js} +2 -2
  44. package/dist/{chunk-3IHNXRUV.cjs → chunk-GKNEJ6EN.cjs} +399 -67
  45. package/dist/{chunk-236TKNUR.cjs → chunk-JCXMJUQO.cjs} +2 -2
  46. package/dist/{chunk-4NGVHHJB.cjs → chunk-NZD2MZJC.cjs} +80 -18
  47. package/dist/{chunk-CX6JLDFC.js → chunk-OXERWBKE.js} +3 -3
  48. package/dist/{chunk-32MMQYCQ.cjs → chunk-PA3IMPPS.cjs} +81 -81
  49. package/dist/{chunk-7CKPUUN4.js → chunk-POR54B55.js} +61 -10
  50. package/dist/{chunk-KGTF55R3.js → chunk-QY4KUDMY.js} +1 -1
  51. package/dist/{chunk-LL3H5XUH.cjs → chunk-R3P2M7HU.cjs} +367 -7
  52. package/dist/{chunk-HDGBM7EA.cjs → chunk-SBQVEBSU.cjs} +580 -53
  53. package/dist/{chunk-2TKHLX6H.js → chunk-SET6KJOP.js} +1 -1
  54. package/dist/{chunk-XDCFJEU7.js → chunk-SZA42R4N.js} +346 -14
  55. package/dist/{chunk-GLMP22FT.js → chunk-TALQONZ5.js} +3 -3
  56. package/dist/{chunk-GNK7SESQ.cjs → chunk-V7GWZIZK.cjs} +7 -4
  57. package/dist/{chunk-EYVVIZJ3.cjs → chunk-WTW7QRTS.cjs} +1 -1
  58. package/dist/{chunk-NA4UVVJ4.cjs → chunk-YGG7WDWT.cjs} +76 -25
  59. package/dist/{chunk-JGKCC5OF.cjs → chunk-YQ5C5BVK.cjs} +10 -9
  60. package/dist/{chunk-EY22AY6R.cjs → chunk-YSAGBIRW.cjs} +16 -16
  61. package/dist/{chunk-A5UCR2TO.js → chunk-YXKLVD56.js} +10 -9
  62. package/dist/{chunk-DTSTNRPH.js → chunk-Z4P2RBMJ.js} +536 -9
  63. package/dist/{chunk-45XXVHVG.js → chunk-ZZGPYNS2.js} +1 -1
  64. package/dist/export/index.cjs +4 -4
  65. package/dist/export/index.js +3 -3
  66. package/dist/extensions/index.cjs +7 -7
  67. package/dist/extensions/index.js +6 -6
  68. package/dist/image-editor/index.cjs +638 -638
  69. package/dist/image-editor/index.js +4 -4
  70. package/dist/index.cjs +13 -13
  71. package/dist/index.js +7 -7
  72. package/dist/paint/index.cjs +2 -2
  73. package/dist/paint/index.js +1 -1
  74. package/dist/paint-editor/index.cjs +129 -149
  75. package/dist/paint-editor/index.js +5 -25
  76. package/dist/vector/index.cjs +948 -948
  77. package/dist/vector/index.js +3 -3
  78. package/package.json +3 -3
  79. package/skills/pixerate-canvas/SKILL.md +16 -0
  80. package/skills/pixerate-chart/SKILL.md +92 -9
  81. package/skills/pixerate-paint-editor/SKILL.md +0 -2
@@ -7,7 +7,7 @@
7
7
 
8
8
 
9
9
 
10
- var _chunkHDGBM7EAcjs = require('./chunk-HDGBM7EA.cjs');
10
+ var _chunkSBQVEBSUcjs = require('./chunk-SBQVEBSU.cjs');
11
11
 
12
12
 
13
13
 
@@ -27,7 +27,16 @@ var _chunkHDGBM7EAcjs = require('./chunk-HDGBM7EA.cjs');
27
27
 
28
28
 
29
29
 
30
- var _chunkLL3H5XUHcjs = require('./chunk-LL3H5XUH.cjs');
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+ var _chunkR3P2M7HUcjs = require('./chunk-R3P2M7HU.cjs');
31
40
 
32
41
 
33
42
 
@@ -63,8 +72,8 @@ function splitOutside(text, sep) {
63
72
  return out;
64
73
  }
65
74
  function chartMermaidFamily(spec) {
66
- const family = _chunkLL3H5XUHcjs.chartFamily.call(void 0, spec);
67
- if (family === "pie" || family === "funnel" || family === "treemap") return "pie";
75
+ const family = _chunkR3P2M7HUcjs.chartFamily.call(void 0, spec);
76
+ if (family === "pie" || family === "funnel" || family === "treemap" || family === "parliament" || family === "sunburst") return "pie";
68
77
  if (family === "radar") return "radar";
69
78
  return "xychart";
70
79
  }
@@ -227,8 +236,8 @@ function chartFromMermaid(text, options = {}) {
227
236
  let title = _nullishCoalesce(frontTitle, () => ( ""));
228
237
  const categories = [];
229
238
  const series = [];
230
- const xAxis = _chunkLL3H5XUHcjs.defaultChartAxis.call(void 0, false);
231
- const yAxis = _chunkLL3H5XUHcjs.defaultChartAxis.call(void 0, true);
239
+ const xAxis = _chunkR3P2M7HUcjs.defaultChartAxis.call(void 0, false);
240
+ const yAxis = _chunkR3P2M7HUcjs.defaultChartAxis.call(void 0, true);
232
241
  const radarAxes = [];
233
242
  const pieSlices = [];
234
243
  let legendShow = true;
@@ -388,7 +397,7 @@ function chartFromMermaid(text, options = {}) {
388
397
  input.series = metaSeries.map((extra, i) => ({ ..._nullishCoalesce(base[i], () => ( {})), ..._nullishCoalesce(extra, () => ( {})) }));
389
398
  }
390
399
  }
391
- const { spec, issues: specIssues } = _chunkLL3H5XUHcjs.normalizeChartSpec.call(void 0, input);
400
+ const { spec, issues: specIssues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, input);
392
401
  if (!family && !partial && !issues.length) issues.push({ path: "header", message: "The text is empty: expected a chart header (xychart-beta, pie or radar-beta)." });
393
402
  return { spec, issues: [...issues, ...specIssues], family, hasMeta: !!meta };
394
403
  }
@@ -427,11 +436,11 @@ function findMermaidCharts(text) {
427
436
  }
428
437
 
429
438
  // src/chart/summary.ts
430
- function summarizeChart(spec, size = { width: 640, height: 400 }, scene = _chunkHDGBM7EAcjs.layoutChart.call(void 0, spec, { ...size, selection: null })) {
439
+ function summarizeChart(spec, size = { width: 640, height: 400 }, scene = _chunkSBQVEBSUcjs.layoutChart.call(void 0, spec, { ...size, selection: null })) {
431
440
  const visible = spec.series.filter((s) => !s.hidden);
432
- const series = visible.map((s) => _chunkHDGBM7EAcjs.summarizeChartSeries.call(void 0, s, spec.categories));
433
- const colors = _chunkLL3H5XUHcjs.chartColorsByCategory.call(void 0, spec.type) ? spec.categories.map((_, i) => _optionalChain([visible, 'access', _10 => _10[0], 'optionalAccess', _11 => _11.pointColors, 'optionalAccess', _12 => _12[i]]) || _chunkLL3H5XUHcjs.chartSliceColor.call(void 0, spec, i)) : visible.map((s) => _chunkLL3H5XUHcjs.chartSeriesColor.call(void 0, spec, spec.series.indexOf(s)));
434
- const check = _chunkLL3H5XUHcjs.checkChartColors.call(void 0, colors, { surface: scene.theme.surface.startsWith("var(") ? "#ffffff" : scene.theme.surface });
441
+ const series = visible.map((s) => _chunkSBQVEBSUcjs.summarizeChartSeries.call(void 0, s, spec.categories));
442
+ const colors = _chunkR3P2M7HUcjs.chartSpecColorsByCategory.call(void 0, spec) ? spec.categories.map((_, i) => _optionalChain([visible, 'access', _10 => _10[0], 'optionalAccess', _11 => _11.pointColors, 'optionalAccess', _12 => _12[i]]) || _chunkR3P2M7HUcjs.chartSliceColor.call(void 0, spec, i)) : visible.map((s) => _chunkR3P2M7HUcjs.chartSeriesColor.call(void 0, spec, spec.series.indexOf(s)));
443
+ const check = _chunkR3P2M7HUcjs.checkChartColors.call(void 0, colors, { surface: scene.theme.surface.startsWith("var(") ? "#ffffff" : scene.theme.surface });
435
444
  const axis = (s, a) => s ? { min: s.domain[0], max: s.domain[1], ticks: [...s.ticks], ...s.logBase ? { logBase: s.logBase } : {}, ...a.reverse ? { reversed: true } : {} } : void 0;
436
445
  return {
437
446
  type: spec.type,
@@ -446,22 +455,58 @@ function summarizeChart(spec, size = { width: 640, height: 400 }, scene = _chunk
446
455
  description: describeChart(spec, series)
447
456
  };
448
457
  }
449
- function describeChart(spec, series = spec.series.filter((s) => !s.hidden).map((s) => _chunkHDGBM7EAcjs.summarizeChartSeries.call(void 0, s, spec.categories))) {
450
- const kind = _chunkLL3H5XUHcjs.CHART_TYPE_LABELS[spec.type].toLowerCase();
458
+ function describeChart(spec, series = spec.series.filter((s) => !s.hidden).map((s) => _chunkSBQVEBSUcjs.summarizeChartSeries.call(void 0, s, spec.categories))) {
459
+ const kind = _chunkR3P2M7HUcjs.CHART_TYPE_LABELS[spec.type].toLowerCase();
451
460
  const parts = [];
452
- const family = _chunkLL3H5XUHcjs.chartFamily.call(void 0, spec);
461
+ const family = _chunkR3P2M7HUcjs.chartFamily.call(void 0, spec);
453
462
  const format = spec.yAxis.format;
454
- const fmt = (v) => v === null ? "blank" : _chunkHDGBM7EAcjs.formatChartNumber.call(void 0, v, format);
463
+ const fmt = (v) => v === null ? "blank" : _chunkSBQVEBSUcjs.formatChartNumber.call(void 0, v, format);
455
464
  const head = spec.title ? `${spec.title}: a ${kind} chart` : `A ${kind} chart`;
456
465
  if (!series.length || series.every((s) => s.count === 0)) return `${head} with no data.`;
457
- if (family === "pie" || family === "funnel" || family === "treemap") {
466
+ if (family === "pie" || family === "funnel" || family === "treemap" || family === "sunburst") {
458
467
  const s = series[0];
459
468
  const total = _nullishCoalesce(s.sum, () => ( 0));
460
469
  const share = (v) => total && v !== null ? ` (${Math.round(v / total * 100)}%)` : "";
461
470
  parts.push(`${head} of ${s.name} across ${spec.categories.length} categories, totalling ${fmt(s.sum)}.`);
462
471
  parts.push(`The largest is ${s.maxAt} at ${fmt(s.max)}${share(s.max)}; the smallest is ${s.minAt} at ${fmt(s.min)}${share(s.min)}.`);
472
+ if (spec.tree.length) {
473
+ const depth = _chunkR3P2M7HUcjs.chartTreeDepth.call(void 0, spec.tree);
474
+ const items = _chunkR3P2M7HUcjs.chartTreeToRows.call(void 0, spec.tree).length;
475
+ parts.push(`The data is grouped ${depth} level${depth === 1 ? "" : "s"} deep with ${items} item${items === 1 ? "" : "s"}.`);
476
+ }
463
477
  return parts.join(" ");
464
478
  }
479
+ if (family === "parliament") {
480
+ const s = spec.series.find((x) => !x.hidden);
481
+ const seats = spec.categories.map((c, i) => ({ c, n: Math.max(0, Math.round(_nullishCoalesce(s.values[i], () => ( 0)))) }));
482
+ const total = seats.reduce((t, x) => t + x.n, 0);
483
+ const majority = _nullishCoalesce(spec.parliamentMajority, () => ( Math.floor(total / 2) + 1));
484
+ const largest = [...seats].sort((a, b) => b.n - a.n)[0];
485
+ const verdict = largest && largest.n >= majority ? `${largest.c} holds a majority with ${largest.n}` : `no group reaches the majority of ${majority}; the largest is ${_optionalChain([largest, 'optionalAccess', _13 => _13.c])} with ${_optionalChain([largest, 'optionalAccess', _14 => _14.n])}`;
486
+ return `${head} of ${total} seats across ${seats.length} groups: ${verdict}.`;
487
+ }
488
+ if (family === "slope") {
489
+ const [a, b] = spec.series.filter((x) => !x.hidden);
490
+ if (!b) return `${head} that needs a second series to compare against.`;
491
+ const moves = spec.categories.map((c, i) => ({ c, d: a.values[i] !== null && b.values[i] !== null ? b.values[i] - a.values[i] : null })).filter((m) => m.d !== null);
492
+ const up = moves.filter((m) => m.d > 0).length;
493
+ const down = moves.filter((m) => m.d < 0).length;
494
+ const top = [...moves].sort((x, y) => y.d - x.d);
495
+ const extremes = top.length ? ` The biggest rise is ${top[0].c} (${fmt(top[0].d)}); the biggest fall is ${top[top.length - 1].c} (${fmt(top[top.length - 1].d)}).` : "";
496
+ return `${head} from ${a.name} to ${b.name}: ${up} of ${moves.length} rose and ${down} fell.${extremes}`;
497
+ }
498
+ if (family === "likert") {
499
+ const answers = spec.series.filter((x) => !x.hidden);
500
+ const side = Math.floor(answers.length / 2);
501
+ const agree = spec.categories.map((c, i) => {
502
+ const vals = answers.map((x) => Math.max(0, _nullishCoalesce(x.values[i], () => ( 0))));
503
+ const total = vals.reduce((t, v) => t + v, 0);
504
+ return { c, share: total ? vals.slice(answers.length - side).reduce((t, v) => t + v, 0) / total : 0 };
505
+ });
506
+ const best = [...agree].sort((x, y) => y.share - x.share);
507
+ const pct = (v) => `${Math.round(v * 100)}%`;
508
+ return `${head} of ${spec.categories.length} questions with ${answers.length} answers from ${_optionalChain([answers, 'access', _15 => _15[0], 'optionalAccess', _16 => _16.name])} to ${_optionalChain([answers, 'access', _17 => _17[answers.length - 1], 'optionalAccess', _18 => _18.name])}. Most positive: ${_optionalChain([best, 'access', _19 => _19[0], 'optionalAccess', _20 => _20.c])} (${pct(_nullishCoalesce(_optionalChain([best, 'access', _21 => _21[0], 'optionalAccess', _22 => _22.share]), () => ( 0)))}); least: ${_optionalChain([best, 'access', _23 => _23[best.length - 1], 'optionalAccess', _24 => _24.c])} (${pct(_nullishCoalesce(_optionalChain([best, 'access', _25 => _25[best.length - 1], 'optionalAccess', _26 => _26.share]), () => ( 0)))}).`;
509
+ }
465
510
  if (family === "waterfall") {
466
511
  const s = spec.series.find((x) => !x.hidden);
467
512
  const steps = s.values.filter((v, i) => v !== null && Number.isFinite(v) && !/\b(sub)?total\b/i.test(_nullishCoalesce(spec.categories[i], () => ( ""))));
@@ -499,7 +544,7 @@ function describeChart(spec, series = spec.series.filter((s) => !s.hidden).map((
499
544
  }
500
545
  parts.push(...axes);
501
546
  for (const s of spec.series.filter((x) => !x.hidden && (x.errorBars || x.xErrorBars)).slice(0, 8)) {
502
- const bars = [s.errorBars ? _chunkLL3H5XUHcjs.describeChartErrorBars.call(void 0, s.errorBars) : "", s.xErrorBars ? `x ${_chunkLL3H5XUHcjs.describeChartErrorBars.call(void 0, s.xErrorBars)}` : ""].filter(Boolean).join(" and ");
547
+ const bars = [s.errorBars ? _chunkR3P2M7HUcjs.describeChartErrorBars.call(void 0, s.errorBars) : "", s.xErrorBars ? `x ${_chunkR3P2M7HUcjs.describeChartErrorBars.call(void 0, s.xErrorBars)}` : ""].filter(Boolean).join(" and ");
503
548
  parts.push(`${s.name} has ${bars}.`);
504
549
  }
505
550
  return parts.join(" ");
@@ -564,7 +609,7 @@ function chartSceneToSvg(scene, options = {}) {
564
609
  return `<svg xmlns="http://www.w3.org/2000/svg" width="${scene.width}" height="${scene.height}" viewBox="0 0 ${scene.width} ${scene.height}" role="img"${label ? ` aria-label="${escape(label)}"` : ""}${labelled ? ` aria-labelledby="${labelled}"` : ""}>${head}${body}</svg>`;
565
610
  }
566
611
  function chartToSvg(spec, options) {
567
- const scene = _chunkHDGBM7EAcjs.layoutChart.call(void 0, spec, { ...options, selection: null });
612
+ const scene = _chunkSBQVEBSUcjs.layoutChart.call(void 0, spec, { ...options, selection: null });
568
613
  return chartSceneToSvg(scene, { ...options, ariaLabel: _nullishCoalesce(options.ariaLabel, () => ( (spec.title || void 0))), description: _nullishCoalesce(options.description, () => ( describeChart(spec))) });
569
614
  }
570
615
  var SVG_NS = "http://www.w3.org/2000/svg";
@@ -602,10 +647,10 @@ var CHART_LAYOUT_PRESETS = [
602
647
  ];
603
648
  function monochromeChartPalette(base, count = 6) {
604
649
  const steps = count <= 1 ? [0] : Array.from({ length: count }, (_, i) => -0.45 + 1.05 * i / (count - 1));
605
- return steps.map((t) => _chunkLL3H5XUHcjs.shadeChartColor.call(void 0, base, t));
650
+ return steps.map((t) => _chunkR3P2M7HUcjs.shadeChartColor.call(void 0, base, t));
606
651
  }
607
652
  var CHART_COLOR_SCHEMES = [
608
- { id: "default", label: "Default", description: "Ten distinct colours, readable on light and dark backgrounds.", palette: _chunkLL3H5XUHcjs.DEFAULT_CHART_PALETTE },
653
+ { id: "default", label: "Default", description: "Ten distinct colours, readable on light and dark backgrounds.", palette: _chunkR3P2M7HUcjs.DEFAULT_CHART_PALETTE },
609
654
  { id: "okabe-ito", label: "Okabe\u2013Ito", description: "Eight colours chosen to stay distinct with colour-blindness.", palette: ["#e69f00", "#56b4e9", "#009e73", "#f0e442", "#0072b2", "#d55e00", "#cc79a7", "#000000"] },
610
655
  { id: "office", label: "Office", description: "The six accent colours of the default Office theme.", palette: ["#4472c4", "#ed7d31", "#a5a5a5", "#ffc000", "#5b9bd5", "#70ad47"] },
611
656
  { id: "warm", label: "Warm", description: "Reds, oranges and yellows.", palette: ["#b2182b", "#d6604d", "#f4a582", "#e08214", "#fdb863", "#8c510a"] },
@@ -632,6 +677,10 @@ function chartPresetPatch(options) {
632
677
  }
633
678
 
634
679
  // src/chart/controller.ts
680
+ function pointLists(s) {
681
+ const lists = [s.values, s.x, s.sizes, s.pointColors, s.callouts, _optionalChain([s, 'access', _27 => _27.errorBars, 'optionalAccess', _28 => _28.plus]), _optionalChain([s, 'access', _29 => _29.errorBars, 'optionalAccess', _30 => _30.minus]), _optionalChain([s, 'access', _31 => _31.xErrorBars, 'optionalAccess', _32 => _32.plus]), _optionalChain([s, 'access', _33 => _33.xErrorBars, 'optionalAccess', _34 => _34.minus])];
682
+ return lists.filter((l) => Array.isArray(l));
683
+ }
635
684
  function sameChartJson(a, b) {
636
685
  if (a === b) return true;
637
686
  if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) return Number.isNaN(a) && Number.isNaN(b);
@@ -664,14 +713,14 @@ var ChartController = (_class = class {
664
713
  constructor(options = {}) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);_class.prototype.__init5.call(this);_class.prototype.__init6.call(this);_class.prototype.__init7.call(this);_class.prototype.__init8.call(this);_class.prototype.__init9.call(this);_class.prototype.__init10.call(this);
665
714
  this.history = _nullishCoalesce(options.history, () => ( new (0, _chunkFJ2MSI43cjs.HistoryManager)()));
666
715
  this.onChange = options.onChange;
667
- const { spec, issues } = _chunkLL3H5XUHcjs.normalizeChartSpec.call(void 0, _nullishCoalesce(options.spec, () => ( {})));
716
+ const { spec, issues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, _nullishCoalesce(options.spec, () => ( {})));
668
717
  this.spec = spec;
669
718
  this.issues = issues;
670
719
  this.state = this.computeState();
671
720
  this.connect();
672
721
  }
673
722
  connect() {
674
- _optionalChain([this, 'access', _13 => _13.unsubscribeHistory, 'optionalCall', _14 => _14()]);
723
+ _optionalChain([this, 'access', _35 => _35.unsubscribeHistory, 'optionalCall', _36 => _36()]);
675
724
  this.unsubscribeHistory = this.history.subscribe((h) => {
676
725
  const s = this.state;
677
726
  if (this.applying || s.canUndo === h.canUndo && s.canRedo === h.canRedo && s.undoLabel === h.undoName && s.redoLabel === h.redoName) return;
@@ -701,12 +750,12 @@ var ChartController = (_class = class {
701
750
  computeState() {
702
751
  const h = this.history.getState();
703
752
  const sel = this.selection;
704
- const seriesId = _optionalChain([sel, 'optionalAccess', _15 => _15.kind]) === "series" || _optionalChain([sel, 'optionalAccess', _16 => _16.kind]) === "point" || _optionalChain([sel, 'optionalAccess', _17 => _17.kind]) === "trendline" ? sel.seriesId : null;
753
+ const seriesId = _optionalChain([sel, 'optionalAccess', _37 => _37.kind]) === "series" || _optionalChain([sel, 'optionalAccess', _38 => _38.kind]) === "point" || _optionalChain([sel, 'optionalAccess', _39 => _39.kind]) === "trendline" ? sel.seriesId : null;
705
754
  return {
706
755
  spec: this.spec,
707
756
  selection: sel,
708
757
  selectedSeries: seriesId ? _nullishCoalesce(this.spec.series.find((s) => s.id === seriesId), () => ( null)) : null,
709
- selectedIndex: _optionalChain([sel, 'optionalAccess', _18 => _18.kind]) === "point" || _optionalChain([sel, 'optionalAccess', _19 => _19.kind]) === "category" ? sel.index : null,
758
+ selectedIndex: _optionalChain([sel, 'optionalAccess', _40 => _40.kind]) === "point" || _optionalChain([sel, 'optionalAccess', _41 => _41.kind]) === "category" ? sel.index : null,
710
759
  issues: this.issues,
711
760
  gesture: this.gestureKey,
712
761
  canUndo: h.canUndo,
@@ -719,7 +768,7 @@ var ChartController = (_class = class {
719
768
  notify(specChanged) {
720
769
  this.revision++;
721
770
  this.state = this.computeState();
722
- if (specChanged) _optionalChain([this, 'access', _20 => _20.onChange, 'optionalCall', _21 => _21(this.spec)]);
771
+ if (specChanged) _optionalChain([this, 'access', _42 => _42.onChange, 'optionalCall', _43 => _43(this.spec)]);
723
772
  const state = this.state;
724
773
  this.listeners.forEach((listener) => {
725
774
  try {
@@ -743,7 +792,7 @@ var ChartController = (_class = class {
743
792
  case "category":
744
793
  return sel.index < spec.categories.length ? sel : null;
745
794
  case "trendline":
746
- return _optionalChain([spec, 'access', _22 => _22.series, 'access', _23 => _23.find, 'call', _24 => _24((s) => s.id === sel.seriesId), 'optionalAccess', _25 => _25.trendlines, 'optionalAccess', _26 => _26[sel.index]]) ? sel : null;
795
+ return _optionalChain([spec, 'access', _44 => _44.series, 'access', _45 => _45.find, 'call', _46 => _46((s) => s.id === sel.seriesId), 'optionalAccess', _47 => _47.trendlines, 'optionalAccess', _48 => _48[sel.index]]) ? sel : null;
747
796
  case "title":
748
797
  return spec.title ? sel : null;
749
798
  case "subtitle":
@@ -767,7 +816,7 @@ var ChartController = (_class = class {
767
816
  const hadIssues = this.issues.length > 0;
768
817
  this.issues = [];
769
818
  if (sameChartJson(before, next)) {
770
- const reselect = select !== void 0 && !_chunkHDGBM7EAcjs.sameChartSelection.call(void 0, this.selection, select) && !(select === null && this.selection === null);
819
+ const reselect = select !== void 0 && !_chunkSBQVEBSUcjs.sameChartSelection.call(void 0, this.selection, select) && !(select === null && this.selection === null);
771
820
  if (reselect) this.selection = select;
772
821
  if (reselect || hadIssues) this.notify(false);
773
822
  return;
@@ -790,7 +839,7 @@ var ChartController = (_class = class {
790
839
  }
791
840
  /** A copy of the spec with `edit` applied (series and categories copied as needed). */
792
841
  edited(edit) {
793
- const draft = _chunkLL3H5XUHcjs.cloneChartSpec.call(void 0, this.spec);
842
+ const draft = _chunkR3P2M7HUcjs.cloneChartSpec.call(void 0, this.spec);
794
843
  edit(draft);
795
844
  return draft;
796
845
  }
@@ -820,7 +869,7 @@ var ChartController = (_class = class {
820
869
  legend: patch.legend ? { ...s.legend, ...patch.legend } : s.legend,
821
870
  version: 1
822
871
  };
823
- const { spec, issues } = _chunkLL3H5XUHcjs.normalizeChartSpec.call(void 0, merged);
872
+ const { spec, issues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, merged);
824
873
  if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
825
874
  if (JSON.stringify(spec) === JSON.stringify(s)) return { ok: true };
826
875
  this.commit(_nullishCoalesce(options.label, () => ( updateLabel(patch))), spec);
@@ -861,17 +910,20 @@ var ChartController = (_class = class {
861
910
  * to the categories; all-or-nothing like `update`.
862
911
  */
863
912
  setData(data, options = {}) {
864
- return this.update({ ...data.categories ? { categories: data.categories } : {}, ...data.series ? { series: data.series } : {} }, { label: _nullishCoalesce(options.label, () => ( "Edit chart data")) });
913
+ const clear = (data.categories || data.series) && this.spec.tree.length ? { tree: [] } : {};
914
+ return this.update({ ...data.categories ? { categories: data.categories } : {}, ...data.series ? { series: data.series } : {}, ...clear }, { label: _nullishCoalesce(options.label, () => ( "Edit chart data")) });
865
915
  }
866
916
  /**
867
917
  * Sets one value (numbers, numeric text such as `1,200` or `12%`, or blank for a gap).
868
918
  * One undo step, or part of the current gesture.
869
919
  */
870
920
  setValue(seriesId, index, value, options = {}) {
921
+ const grouped = this.treeLocked();
922
+ if (grouped) return grouped;
871
923
  const series = this.getSeries(seriesId);
872
924
  if (!series) return this.unknownSeries(seriesId);
873
925
  if (!Number.isInteger(index) || index < 0 || index >= this.spec.categories.length) return this.badIndex(index);
874
- const parsed = _chunkLL3H5XUHcjs.parseChartValue.call(void 0, value);
926
+ const parsed = _chunkR3P2M7HUcjs.parseChartValue.call(void 0, value);
875
927
  if (parsed === void 0) return this.reject(`"${String(value)}" is not a number; enter a number or leave the cell blank.`, [{ path: `${seriesId}[${index}]`, message: `"${String(value)}" is not a number.` }]);
876
928
  if (series.values[index] === parsed) {
877
929
  if (this.issues.length) {
@@ -888,13 +940,15 @@ var ChartController = (_class = class {
888
940
  }
889
941
  /** Several values as one undo step (all-or-nothing). */
890
942
  setValues(cells, options = {}) {
943
+ const grouped = this.treeLocked();
944
+ if (grouped) return grouped;
891
945
  const issues = [];
892
946
  const parsed = [];
893
947
  for (const cell of cells) {
894
948
  if (!this.getSeries(cell.seriesId)) issues.push({ path: cell.seriesId, message: this.unknownSeries(cell.seriesId).message });
895
949
  else if (!Number.isInteger(cell.index) || cell.index < 0 || cell.index >= this.spec.categories.length) issues.push({ path: `${cell.seriesId}[${cell.index}]`, message: this.badIndex(cell.index).message });
896
950
  else {
897
- const value = _chunkLL3H5XUHcjs.parseChartValue.call(void 0, cell.value);
951
+ const value = _chunkR3P2M7HUcjs.parseChartValue.call(void 0, cell.value);
898
952
  if (value === void 0) issues.push({ path: `${cell.seriesId}[${cell.index}]`, message: `"${String(cell.value)}" is not a number.` });
899
953
  else parsed.push({ seriesId: cell.seriesId, index: cell.index, value });
900
954
  }
@@ -908,12 +962,12 @@ var ChartController = (_class = class {
908
962
  }
909
963
  /** Adds a series (values padded to the categories) and selects it. Returns its id. */
910
964
  addSeries(input = {}, options = {}) {
911
- const id = input.id && !this.getSeries(input.id) ? input.id : _chunkLL3H5XUHcjs.uniqueChartSeriesId.call(void 0, this.spec.series);
965
+ const id = input.id && !this.getSeries(input.id) ? input.id : _chunkR3P2M7HUcjs.uniqueChartSeriesId.call(void 0, this.spec.series);
912
966
  const name = _nullishCoalesce(input.name, () => ( `Series ${this.spec.series.length + 1}`));
913
967
  const at = Math.max(0, Math.min(this.spec.series.length, _nullishCoalesce(options.at, () => ( this.spec.series.length))));
914
968
  const series = [...this.spec.series];
915
969
  series.splice(at, 0, { ...input, id, name, values: _nullishCoalesce(input.values, () => ( [])) });
916
- const { spec, issues } = _chunkLL3H5XUHcjs.normalizeChartSpec.call(void 0, { ...this.spec, series });
970
+ const { spec, issues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, { ...this.spec, series });
917
971
  if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
918
972
  this.commit(`Add series "${name}"`, spec, { kind: "series", seriesId: id });
919
973
  return { ok: true, id };
@@ -925,6 +979,7 @@ var ChartController = (_class = class {
925
979
  `Delete series "${series.name}"`,
926
980
  this.edited((d) => {
927
981
  d.series = d.series.filter((s) => s.id !== id);
982
+ d.highlight = d.highlight.filter((h) => h !== id && (h !== series.name || d.series.some((s) => s.name === h) || d.categories.includes(h)));
928
983
  })
929
984
  );
930
985
  return { ok: true };
@@ -932,7 +987,7 @@ var ChartController = (_class = class {
932
987
  updateSeries(id, patch) {
933
988
  const series = this.getSeries(id);
934
989
  if (!series) return this.unknownSeries(id);
935
- const next = _chunkLL3H5XUHcjs.cloneChartSeries.call(void 0, series);
990
+ const next = _chunkR3P2M7HUcjs.cloneChartSeries.call(void 0, series);
936
991
  if (patch.name !== void 0) next.name = String(patch.name);
937
992
  if (patch.color === null || patch.color === "") delete next.color;
938
993
  else if (patch.color !== void 0) next.color = patch.color;
@@ -942,7 +997,7 @@ var ChartController = (_class = class {
942
997
  if (patch.hidden) next.hidden = true;
943
998
  else delete next.hidden;
944
999
  }
945
- const resettable = ["axis", "x", "sizes", "pointColors", "marker", "curve", "dataLabels", "format", "errorBars", "xErrorBars"];
1000
+ const resettable = ["axis", "x", "sizes", "pointColors", "callouts", "marker", "curve", "dataLabels", "format", "errorBars", "xErrorBars"];
946
1001
  for (const key of resettable) {
947
1002
  if (!(key in patch) || patch[key] === void 0) continue;
948
1003
  if (patch[key] === null) delete next[key];
@@ -950,7 +1005,9 @@ var ChartController = (_class = class {
950
1005
  }
951
1006
  if (next.axis === "primary") delete next.axis;
952
1007
  const series2 = this.spec.series.map((s) => s.id === id ? next : s);
953
- const { spec, issues } = _chunkLL3H5XUHcjs.normalizeChartSpec.call(void 0, { ...this.spec, series: series2 });
1008
+ const renamed = next.name !== series.name && this.spec.highlight.includes(series.name) && !this.spec.categories.includes(series.name);
1009
+ const highlight = renamed ? this.spec.highlight.map((h) => h === series.name ? next.name : h) : this.spec.highlight;
1010
+ const { spec, issues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, { ...this.spec, series: series2, highlight });
954
1011
  if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
955
1012
  if (JSON.stringify(spec.series) === JSON.stringify(this.spec.series)) return { ok: true };
956
1013
  const label = patch.hidden !== void 0 && Object.keys(patch).length === 1 ? `${patch.hidden ? "Hide" : "Show"} "${series.name}"` : patch.name !== void 0 && Object.keys(patch).length === 1 ? "Rename series" : `Change series "${series.name}"`;
@@ -979,41 +1036,52 @@ var ChartController = (_class = class {
979
1036
  }
980
1037
  /** Inserts a category (with gaps in every series) at `at` (default: the end). Returns its index. */
981
1038
  addCategory(label, options = {}) {
1039
+ const grouped = this.treeLocked();
1040
+ if (grouped) return grouped;
982
1041
  const at = Math.max(0, Math.min(this.spec.categories.length, _nullishCoalesce(options.at, () => ( this.spec.categories.length))));
983
1042
  const name = _nullishCoalesce(label, () => ( `${this.spec.categories.length + 1}`));
984
1043
  this.commit(
985
1044
  `Add category "${name}"`,
986
1045
  this.edited((d) => {
987
1046
  d.categories.splice(at, 0, name);
988
- for (const s of d.series) s.values.splice(at, 0, null);
1047
+ for (const s of d.series) for (const list of pointLists(s)) list.splice(at, 0, null);
989
1048
  }),
990
1049
  { kind: "category", index: at }
991
1050
  );
992
1051
  return { ok: true, index: at };
993
1052
  }
994
1053
  removeCategory(index) {
1054
+ const grouped = this.treeLocked();
1055
+ if (grouped) return grouped;
995
1056
  if (!Number.isInteger(index) || index < 0 || index >= this.spec.categories.length) return this.badIndex(index);
996
1057
  this.commit(
997
1058
  `Delete category "${this.spec.categories[index]}"`,
998
1059
  this.edited((d) => {
999
- d.categories.splice(index, 1);
1000
- for (const s of d.series) s.values.splice(index, 1);
1060
+ const [label] = d.categories.splice(index, 1);
1061
+ for (const s of d.series) for (const list of pointLists(s)) list.splice(index, 1);
1062
+ if (!d.categories.includes(label)) d.highlight = d.highlight.filter((h) => h !== label);
1001
1063
  })
1002
1064
  );
1003
1065
  return { ok: true };
1004
1066
  }
1005
1067
  renameCategory(index, label) {
1068
+ const grouped = this.treeLocked();
1069
+ if (grouped) return grouped;
1006
1070
  if (!Number.isInteger(index) || index < 0 || index >= this.spec.categories.length) return this.badIndex(index);
1007
1071
  if (this.spec.categories[index] === label) return { ok: true };
1008
1072
  this.commit(
1009
1073
  "Rename category",
1010
1074
  this.edited((d) => {
1075
+ const before = d.categories[index];
1011
1076
  d.categories[index] = String(label);
1077
+ if (d.highlight.includes(before) && !d.categories.includes(before)) d.highlight = d.highlight.map((h) => h === before ? String(label) : h);
1012
1078
  })
1013
1079
  );
1014
1080
  return { ok: true };
1015
1081
  }
1016
1082
  moveCategory(from, to) {
1083
+ const grouped = this.treeLocked();
1084
+ if (grouped) return grouped;
1017
1085
  if (!Number.isInteger(from) || from < 0 || from >= this.spec.categories.length) return this.badIndex(from);
1018
1086
  const target = Math.max(0, Math.min(this.spec.categories.length - 1, to));
1019
1087
  if (target === from) return { ok: true };
@@ -1025,7 +1093,7 @@ var ChartController = (_class = class {
1025
1093
  "Reorder categories",
1026
1094
  this.edited((d) => {
1027
1095
  move(d.categories);
1028
- for (const s of d.series) move(s.values);
1096
+ for (const s of d.series) for (const list of pointLists(s)) move(list);
1029
1097
  })
1030
1098
  );
1031
1099
  return { ok: true };
@@ -1036,6 +1104,8 @@ var ChartController = (_class = class {
1036
1104
  * grid grows to fit. Non-numeric value cells become gaps and are reported in `issues`.
1037
1105
  */
1038
1106
  pasteCells(row, column, cells) {
1107
+ const grouped = this.treeLocked();
1108
+ if (grouped) return grouped;
1039
1109
  const rows = typeof cells === "string" ? cells.includes(" ") ? _chunkN3KJFGXTcjs.parseTsv.call(void 0, cells) : _chunkN3KJFGXTcjs.parseCsv.call(void 0, cells) : cells.map((r) => [...r]);
1040
1110
  if (!rows.length) return { ok: true };
1041
1111
  const issues = [];
@@ -1043,7 +1113,7 @@ var ChartController = (_class = class {
1043
1113
  const width = Math.max(...rows.map((r) => r.length));
1044
1114
  const lastSeries = column + width - 1;
1045
1115
  while (d.series.length <= lastSeries) {
1046
- const id = _chunkLL3H5XUHcjs.uniqueChartSeriesId.call(void 0, d.series);
1116
+ const id = _chunkR3P2M7HUcjs.uniqueChartSeriesId.call(void 0, d.series);
1047
1117
  d.series.push({ id, name: `Series ${d.series.length + 1}`, values: d.categories.map(() => null) });
1048
1118
  }
1049
1119
  const lastRow = row + rows.length - 1;
@@ -1057,7 +1127,7 @@ var ChartController = (_class = class {
1057
1127
  const index = row + r;
1058
1128
  if (col < 0) d.categories[index] = cell === null || cell === void 0 ? "" : String(cell).trim();
1059
1129
  else {
1060
- const parsed = _chunkLL3H5XUHcjs.parseChartValue.call(void 0, cell);
1130
+ const parsed = _chunkR3P2M7HUcjs.parseChartValue.call(void 0, cell);
1061
1131
  if (parsed === void 0) issues.push({ path: `${d.series[col].id}[${index}]`, message: `"${String(cell)}" is not a number; it was left blank.` });
1062
1132
  d.series[col].values[index] = _nullishCoalesce(parsed, () => ( null));
1063
1133
  }
@@ -1076,14 +1146,14 @@ var ChartController = (_class = class {
1076
1146
  * colours and types are kept by name.
1077
1147
  */
1078
1148
  importTable(rows, options = {}) {
1079
- const data = _chunkLL3H5XUHcjs.chartDataFromTable.call(void 0, rows, options);
1149
+ const data = _chunkR3P2M7HUcjs.chartDataFromTable.call(void 0, rows, options);
1080
1150
  if (!data.categories.length || !data.series.length) return this.reject("There is no data to import: expected a header row and at least one row of values.");
1081
1151
  const byName = new Map(this.spec.series.map((s) => [s.name, s]));
1082
1152
  const series = data.series.map((s) => {
1083
1153
  const old = byName.get(s.name);
1084
- return { ...s, ..._optionalChain([old, 'optionalAccess', _27 => _27.color]) ? { color: old.color } : {}, ..._optionalChain([old, 'optionalAccess', _28 => _28.type]) ? { type: old.type } : {}, ...old ? { id: old.id } : {} };
1154
+ return { ...s, ..._optionalChain([old, 'optionalAccess', _49 => _49.color]) ? { color: old.color } : {}, ..._optionalChain([old, 'optionalAccess', _50 => _50.type]) ? { type: old.type } : {}, ...old ? { id: old.id } : {} };
1085
1155
  });
1086
- const { spec } = _chunkLL3H5XUHcjs.normalizeChartSpec.call(void 0, { ...this.spec, categories: data.categories, series });
1156
+ const { spec } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, { ...this.spec, categories: data.categories, series, tree: [] });
1087
1157
  this.commit("Import data", spec);
1088
1158
  if (data.issues.length) {
1089
1159
  this.issues = data.issues;
@@ -1098,18 +1168,264 @@ var ChartController = (_class = class {
1098
1168
  return this.importTable(_chunkN3KJFGXTcjs.parseCsv.call(void 0, text, { delimiter }), options);
1099
1169
  }
1100
1170
  // -------------------------------------------------------------------------
1171
+ // Grouped data (tree)
1172
+ // -------------------------------------------------------------------------
1173
+ /** A refusal while the data is a tree (cell edits would be overwritten by its totals), else null. */
1174
+ treeLocked() {
1175
+ if (!this.spec.tree.length) return null;
1176
+ return this.reject(
1177
+ "This chart's data is grouped (a tree): its categories and values are the top-level groups and their totals. Change it with setTree / the tree node edits (set_chart_tree, add_chart_tree_node, update_chart_tree_node, remove_chart_tree_node), or replace it with new data."
1178
+ );
1179
+ }
1180
+ /** Replaces the grouped data (an empty list goes back to the table, keeping the totals as values). One undo step. */
1181
+ setTree(tree, options = {}) {
1182
+ const issues = [];
1183
+ const next = _chunkR3P2M7HUcjs.normalizeChartTree.call(void 0, tree, issues);
1184
+ if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1185
+ return this.update({ tree: next }, { label: _nullishCoalesce(options.label, () => ( (next.length ? "Replace grouped data" : "Ungroup data"))) });
1186
+ }
1187
+ /**
1188
+ * Replaces the grouped data from rows of names and a value (group, …, item, value), as the
1189
+ * data grid edits it; colours of nodes whose path is unchanged are kept. All-or-nothing.
1190
+ */
1191
+ setTreeRows(rows, options = {}) {
1192
+ const issues = [];
1193
+ const next = _chunkR3P2M7HUcjs.chartTreeFromRows.call(void 0, rows, issues);
1194
+ if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1195
+ const keepColors = (list, prefix) => {
1196
+ for (const n of list) {
1197
+ const old = _chunkR3P2M7HUcjs.findChartTreeNode.call(void 0, this.spec.tree, [...prefix, n.name]);
1198
+ if (_optionalChain([old, 'optionalAccess', _51 => _51.color])) n.color = old.color;
1199
+ if (n.children) keepColors(n.children, [...prefix, n.name]);
1200
+ }
1201
+ };
1202
+ keepColors(next, []);
1203
+ return this.update({ tree: next }, { label: _nullishCoalesce(options.label, () => ( "Edit grouped data")) });
1204
+ }
1205
+ /** Replaces the data with a table of names and values (group, …, item, value); see `chartTreeFromTable`. */
1206
+ importTreeTable(rows, options = {}) {
1207
+ const issues = [];
1208
+ const next = _chunkR3P2M7HUcjs.chartTreeFromTable.call(void 0, rows, options, issues);
1209
+ if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1210
+ if (!next.length) return this.reject('There is no grouped data to import: expected rows of names followed by a value, e.g. "Europe,France,40".');
1211
+ return this.update({ tree: next }, { label: "Import grouped data" });
1212
+ }
1213
+ nodeAt(path) {
1214
+ const node = _chunkR3P2M7HUcjs.findChartTreeNode.call(void 0, this.spec.tree, path);
1215
+ if (node) return node;
1216
+ const known = path.length > 1 ? _chunkR3P2M7HUcjs.findChartTreeNode.call(void 0, this.spec.tree, path.slice(0, -1)) : null;
1217
+ const siblings = _nullishCoalesce((path.length > 1 ? _optionalChain([known, 'optionalAccess', _52 => _52.children]) : this.spec.tree), () => ( []));
1218
+ return fail(
1219
+ `There is no node ${JSON.stringify(path)}. ${siblings.length ? `${path.length > 1 && known ? `"${known.name}" contains` : "The top level has"} ${siblings.map((n) => `"${n.name}"`).slice(0, 20).join(", ")}.` : "The chart has no grouped data yet; add nodes with add_chart_tree_node or set_chart_tree."}`
1220
+ );
1221
+ }
1222
+ /** Adds a node under the group at `parent` ([] for the top level) at `at` (default: the end). Returns its path. */
1223
+ addTreeNode(parent, input, options = {}) {
1224
+ let siblings = this.spec.tree;
1225
+ if (parent.length) {
1226
+ const group = this.nodeAt(parent);
1227
+ if ("ok" in group) return group;
1228
+ if (!group.children) return this.reject(`"${group.name}" is an item with its own value, not a group; add the node next to it, or turn it into a group by replacing the tree with set_chart_tree.`);
1229
+ siblings = group.children;
1230
+ }
1231
+ const issues = [];
1232
+ const [node] = _chunkR3P2M7HUcjs.normalizeChartTree.call(void 0, [input], issues, "node");
1233
+ if (!node || issues.length) return this.reject(issues.map((i) => i.message).join(" ") || "The node is not valid.", issues);
1234
+ if (siblings.some((n) => n.name === node.name)) return this.reject(`"${node.name}" is already there; names under one group must be unique.`);
1235
+ const at = Math.max(0, Math.min(siblings.length, _nullishCoalesce(options.at, () => ( siblings.length))));
1236
+ const tree = _chunkR3P2M7HUcjs.cloneChartTree.call(void 0, this.spec.tree);
1237
+ const list = parent.length ? _chunkR3P2M7HUcjs.findChartTreeNode.call(void 0, tree, parent).children : tree;
1238
+ list.splice(at, 0, node);
1239
+ const result = this.update({ tree }, { label: `Add "${node.name}"` });
1240
+ if (!result.ok) return result;
1241
+ return { ok: true, path: [...parent, node.name] };
1242
+ }
1243
+ /** Renames, revalues (items only) or recolours a node; `color: null` goes back to the palette. Returns its path. */
1244
+ updateTreeNode(path, patch) {
1245
+ const node = this.nodeAt(path);
1246
+ if ("ok" in node) return node;
1247
+ if (patch.value !== void 0 && node.children) return this.reject(`"${node.name}" is a group: its value is the sum of its items. Change the items instead.`);
1248
+ const name = patch.name !== void 0 ? String(patch.name).trim() : node.name;
1249
+ const siblings = (path.length > 1 ? _chunkR3P2M7HUcjs.findChartTreeNode.call(void 0, this.spec.tree, path.slice(0, -1)).children : this.spec.tree).filter((n) => n !== node);
1250
+ if (siblings.some((n) => n.name === name)) return this.reject(`There is already a "${name}" next to "${node.name}"; names under one group must be unique.`);
1251
+ const tree = _chunkR3P2M7HUcjs.cloneChartTree.call(void 0, this.spec.tree);
1252
+ const target = _chunkR3P2M7HUcjs.findChartTreeNode.call(void 0, tree, path);
1253
+ const merged = { ...target, name };
1254
+ if (patch.value !== void 0) merged.value = patch.value;
1255
+ if (patch.color === null) delete merged.color;
1256
+ else if (patch.color !== void 0) merged.color = patch.color;
1257
+ const issues = [];
1258
+ const [checked] = _chunkR3P2M7HUcjs.normalizeChartTree.call(void 0, [merged], issues, "node");
1259
+ if (!checked || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1260
+ Object.assign(target, checked);
1261
+ if (patch.color === null) delete target.color;
1262
+ const result = this.update({ tree }, { label: patch.name !== void 0 && patch.name !== node.name ? "Rename group" : `Change "${node.name}"` });
1263
+ if (!result.ok) return result;
1264
+ return { ok: true, path: [...path.slice(0, -1), name] };
1265
+ }
1266
+ /** Removes a node (with everything under it). A group left empty becomes an item with value 0. */
1267
+ removeTreeNode(path) {
1268
+ const node = this.nodeAt(path);
1269
+ if ("ok" in node) return node;
1270
+ const tree = _chunkR3P2M7HUcjs.cloneChartTree.call(void 0, this.spec.tree);
1271
+ const parent = path.length > 1 ? _chunkR3P2M7HUcjs.findChartTreeNode.call(void 0, tree, path.slice(0, -1)) : null;
1272
+ const list = parent ? parent.children : tree;
1273
+ list.splice(
1274
+ list.findIndex((n) => n.name === node.name),
1275
+ 1
1276
+ );
1277
+ if (parent && !parent.children.length) {
1278
+ delete parent.children;
1279
+ parent.value = 0;
1280
+ }
1281
+ return this.update({ tree }, { label: `Delete "${node.name}"` });
1282
+ }
1283
+ // -------------------------------------------------------------------------
1284
+ // Annotations
1285
+ // -------------------------------------------------------------------------
1286
+ /** Sets the note written under the chart ("" removes it). */
1287
+ setNote(note) {
1288
+ return this.update({ note }, { label: note ? "Edit note" : "Remove note" });
1289
+ }
1290
+ /**
1291
+ * Draws the named categories (labels) and series (names or ids) normally and mutes the
1292
+ * rest; an empty list shows everything. Unknown names change nothing. Returns the category
1293
+ * indexes and series ids that matched.
1294
+ */
1295
+ setHighlight(names) {
1296
+ const s = this.spec;
1297
+ const list = [...new Set(names.map(String))];
1298
+ const unknown = list.filter((n) => !s.categories.includes(n) && !s.series.some((x) => x.id === n || x.name === n));
1299
+ if (unknown.length)
1300
+ return this.reject(
1301
+ `${unknown.map((u) => `"${u}"`).join(", ")} ${unknown.length === 1 ? "is" : "are"} neither a category nor a series. Categories: ${s.categories.slice(0, 20).map((c) => `"${c}"`).join(", ") || "(none)"}; series: ${s.series.map((x) => `"${x.name}"`).join(", ") || "(none)"}.`
1302
+ );
1303
+ const result = this.update({ highlight: list }, { label: list.length ? "Highlight" : "Clear highlight" });
1304
+ if (!result.ok) return result;
1305
+ return {
1306
+ ok: true,
1307
+ categories: s.categories.flatMap((c, i) => list.includes(c) ? [i] : []),
1308
+ series: s.series.filter((x) => list.includes(x.id) || list.includes(x.name)).map((x) => x.id)
1309
+ };
1310
+ }
1311
+ /** Why a reference on `axis` at `values` cannot be drawn on this chart, or null. */
1312
+ referenceProblem(axis, values) {
1313
+ const s = this.spec;
1314
+ const family = _chunkR3P2M7HUcjs.chartFamily.call(void 0, s);
1315
+ if (family !== "cartesian" && family !== "xy") return `Reference lines and bands are drawn on bar, line, area, scatter and bubble charts; this is a ${s.type} chart.`;
1316
+ if (axis === "x" && family !== "xy") return 'axis "x" needs a scatter or bubble chart with numeric x values; use "y" for the value axis.';
1317
+ if (axis === "y2" && (family !== "cartesian" || !s.series.some((x) => !x.hidden && x.axis === "secondary")))
1318
+ return 'axis "y2" needs a visible series on the secondary axis (set one with update_chart_series axis "secondary"), or use "y".';
1319
+ const scale = (axis === "x" ? s.xAxis : axis === "y2" ? s.yAxis2 : s.yAxis).scale;
1320
+ if (scale === "log" && values.some((v) => !(v > 0))) return "That axis is logarithmic, so the values must be above 0.";
1321
+ return null;
1322
+ }
1323
+ editReferences(kind, label, edit, select) {
1324
+ this.commit(
1325
+ label,
1326
+ this.edited((d) => edit(d[kind])),
1327
+ select
1328
+ );
1329
+ }
1330
+ /** Adds a reference line (a target, floor or average). Returns its index. */
1331
+ addReferenceLine(input) {
1332
+ const issues = [];
1333
+ const line = _chunkR3P2M7HUcjs.normalizeChartReferenceLine.call(void 0, input, "referenceLine", issues);
1334
+ if (!line || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1335
+ const problem = this.referenceProblem(line.axis, [line.value]);
1336
+ if (problem) return this.reject(problem);
1337
+ const index = this.spec.referenceLines.length;
1338
+ this.editReferences("referenceLines", `Add reference line${line.label ? ` "${line.label}"` : ""}`, (list) => list.push(line));
1339
+ return { ok: true, index };
1340
+ }
1341
+ /** Changes a reference line (all-or-nothing); `null` removes its label, colour or axis. */
1342
+ updateReferenceLine(index, patch) {
1343
+ const current = this.spec.referenceLines[index];
1344
+ if (!current) return fail(this.noReference("reference line", this.spec.referenceLines.length, index));
1345
+ const merged = { ...current, ...patch };
1346
+ for (const [k, v] of Object.entries(patch)) if (v === null) delete merged[k];
1347
+ const issues = [];
1348
+ const line = _chunkR3P2M7HUcjs.normalizeChartReferenceLine.call(void 0, merged, "referenceLine", issues);
1349
+ if (!line || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1350
+ const problem = this.referenceProblem(line.axis, [line.value]);
1351
+ if (problem) return this.reject(problem);
1352
+ this.editReferences("referenceLines", "Change reference line", (list) => list[index] = line);
1353
+ return { ok: true };
1354
+ }
1355
+ removeReferenceLine(index) {
1356
+ if (!this.spec.referenceLines[index]) return fail(this.noReference("reference line", this.spec.referenceLines.length, index));
1357
+ this.editReferences("referenceLines", "Delete reference line", (list) => list.splice(index, 1));
1358
+ return { ok: true };
1359
+ }
1360
+ /** Adds a reference band (a target range). Returns its index. */
1361
+ addReferenceBand(input) {
1362
+ const issues = [];
1363
+ const band = _chunkR3P2M7HUcjs.normalizeChartReferenceBand.call(void 0, input, "referenceBand", issues);
1364
+ if (!band || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1365
+ const problem = this.referenceProblem(band.axis, [band.from, band.to]);
1366
+ if (problem) return this.reject(problem);
1367
+ const index = this.spec.referenceBands.length;
1368
+ this.editReferences("referenceBands", `Add reference band${band.label ? ` "${band.label}"` : ""}`, (list) => list.push(band));
1369
+ return { ok: true, index };
1370
+ }
1371
+ /** Changes a reference band (all-or-nothing); `null` removes its label, colour or axis. */
1372
+ updateReferenceBand(index, patch) {
1373
+ const current = this.spec.referenceBands[index];
1374
+ if (!current) return fail(this.noReference("reference band", this.spec.referenceBands.length, index));
1375
+ const merged = { ...current, ...patch };
1376
+ for (const [k, v] of Object.entries(patch)) if (v === null) delete merged[k];
1377
+ const issues = [];
1378
+ const band = _chunkR3P2M7HUcjs.normalizeChartReferenceBand.call(void 0, merged, "referenceBand", issues);
1379
+ if (!band || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1380
+ const problem = this.referenceProblem(band.axis, [band.from, band.to]);
1381
+ if (problem) return this.reject(problem);
1382
+ this.editReferences("referenceBands", "Change reference band", (list) => list[index] = band);
1383
+ return { ok: true };
1384
+ }
1385
+ removeReferenceBand(index) {
1386
+ if (!this.spec.referenceBands[index]) return fail(this.noReference("reference band", this.spec.referenceBands.length, index));
1387
+ this.editReferences("referenceBands", "Delete reference band", (list) => list.splice(index, 1));
1388
+ return { ok: true };
1389
+ }
1390
+ noReference(what, count, index) {
1391
+ return `There is no ${what} ${index}; ${count ? `expected 0 to ${count - 1}` : `the chart has none yet`}.`;
1392
+ }
1393
+ /**
1394
+ * Pins a label to one bar or point (`null` or "" removes it) and selects the point. The
1395
+ * point must have a value, on a bar, line, area, scatter or bubble chart.
1396
+ */
1397
+ setCallout(seriesId, index, label) {
1398
+ const series = this.getSeries(seriesId);
1399
+ if (!series) return this.unknownSeries(seriesId);
1400
+ if (!Number.isInteger(index) || index < 0 || index >= this.spec.categories.length) return this.badIndex(index);
1401
+ const family = _chunkR3P2M7HUcjs.chartFamily.call(void 0, this.spec);
1402
+ const text = label === null ? "" : String(label).trim();
1403
+ if (text && family !== "cartesian" && family !== "xy") return this.reject(`Callouts are drawn on bar, line, area, scatter and bubble charts; this is a ${this.spec.type} chart.`);
1404
+ if (text && (series.values[index] === null || series.values[index] === void 0))
1405
+ return this.reject(`"${series.name}" has no value at "${this.spec.categories[index]}", so there is nothing to point at; set a value first.`);
1406
+ const next = this.edited((d) => {
1407
+ const s = d.series.find((x) => x.id === seriesId);
1408
+ const labels = s.callouts ? [...s.callouts] : d.categories.map(() => null);
1409
+ labels[index] = text || null;
1410
+ if (labels.some((l) => l)) s.callouts = labels;
1411
+ else delete s.callouts;
1412
+ });
1413
+ this.commit(text ? "Add callout" : "Remove callout", next, { kind: "point", seriesId, index });
1414
+ return { ok: true };
1415
+ }
1416
+ // -------------------------------------------------------------------------
1101
1417
  // Trendlines
1102
1418
  // -------------------------------------------------------------------------
1103
1419
  /** Adds a trendline to a series and selects it. Returns its index (and the fit, when it can be computed). */
1104
1420
  addTrendline(seriesId, input) {
1105
1421
  const series = this.getSeries(seriesId);
1106
1422
  if (!series) return this.unknownSeries(seriesId);
1107
- if (!_chunkHDGBM7EAcjs.chartSupportsTrendlines.call(void 0, this.spec.type, this.spec.stacking))
1423
+ if (!_chunkSBQVEBSUcjs.chartSupportsTrendlines.call(void 0, this.spec.type, this.spec.stacking))
1108
1424
  return this.reject(`Trendlines need an unstacked bar, line, area, scatter or bubble chart; this is a ${this.spec.stacking !== "none" ? `${this.spec.stacking} ` : ""}${this.spec.type} chart.`);
1109
1425
  const issues = [];
1110
- const line = _chunkLL3H5XUHcjs.normalizeChartTrendline.call(void 0, input, "trendline", issues);
1426
+ const line = _chunkR3P2M7HUcjs.normalizeChartTrendline.call(void 0, input, "trendline", issues);
1111
1427
  if (!line || issues.length) return this.reject(issues.map((i) => i.message).join(" ") || "The trendline is not valid.", issues);
1112
- const index = _nullishCoalesce(_optionalChain([series, 'access', _29 => _29.trendlines, 'optionalAccess', _30 => _30.length]), () => ( 0));
1428
+ const index = _nullishCoalesce(_optionalChain([series, 'access', _53 => _53.trendlines, 'optionalAccess', _54 => _54.length]), () => ( 0));
1113
1429
  const next = this.edited((d) => {
1114
1430
  const s = d.series.find((x) => x.id === seriesId);
1115
1431
  s.trendlines = [..._nullishCoalesce(s.trendlines, () => ( [])), line];
@@ -1121,12 +1437,12 @@ var ChartController = (_class = class {
1121
1437
  updateTrendline(seriesId, index, patch) {
1122
1438
  const series = this.getSeries(seriesId);
1123
1439
  if (!series) return this.unknownSeries(seriesId);
1124
- const current = _optionalChain([series, 'access', _31 => _31.trendlines, 'optionalAccess', _32 => _32[index]]);
1125
- if (!current) return fail(`"${series.name}" has no trendline ${index}; ${_optionalChain([series, 'access', _33 => _33.trendlines, 'optionalAccess', _34 => _34.length]) ? `expected 0 to ${series.trendlines.length - 1}` : "it has none yet"}.`);
1440
+ const current = _optionalChain([series, 'access', _55 => _55.trendlines, 'optionalAccess', _56 => _56[index]]);
1441
+ if (!current) return fail(`"${series.name}" has no trendline ${index}; ${_optionalChain([series, 'access', _57 => _57.trendlines, 'optionalAccess', _58 => _58.length]) ? `expected 0 to ${series.trendlines.length - 1}` : "it has none yet"}.`);
1126
1442
  const issues = [];
1127
1443
  const merged = { ...current, ...patch };
1128
1444
  for (const [k, v] of Object.entries(patch)) if (v === null) delete merged[k];
1129
- const line = _chunkLL3H5XUHcjs.normalizeChartTrendline.call(void 0, merged, "trendline", issues);
1445
+ const line = _chunkR3P2M7HUcjs.normalizeChartTrendline.call(void 0, merged, "trendline", issues);
1130
1446
  if (!line || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1131
1447
  this.commit(
1132
1448
  "Change trendline",
@@ -1139,7 +1455,7 @@ var ChartController = (_class = class {
1139
1455
  removeTrendline(seriesId, index) {
1140
1456
  const series = this.getSeries(seriesId);
1141
1457
  if (!series) return this.unknownSeries(seriesId);
1142
- if (!_optionalChain([series, 'access', _35 => _35.trendlines, 'optionalAccess', _36 => _36[index]])) return fail(`"${series.name}" has no trendline ${index}.`);
1458
+ if (!_optionalChain([series, 'access', _59 => _59.trendlines, 'optionalAccess', _60 => _60[index]])) return fail(`"${series.name}" has no trendline ${index}.`);
1143
1459
  this.commit(
1144
1460
  "Delete trendline",
1145
1461
  this.edited((d) => {
@@ -1154,25 +1470,25 @@ var ChartController = (_class = class {
1154
1470
  trendlinePoints(seriesId) {
1155
1471
  const series = this.getSeries(seriesId);
1156
1472
  if (!series) return [];
1157
- const xy = _chunkLL3H5XUHcjs.chartFamily.call(void 0, this.spec) === "xy";
1473
+ const xy = _chunkR3P2M7HUcjs.chartFamily.call(void 0, this.spec) === "xy";
1158
1474
  const out = [];
1159
1475
  series.values.forEach((v, i) => {
1160
- const x = xy ? _nullishCoalesce(_optionalChain([series, 'access', _37 => _37.x, 'optionalAccess', _38 => _38[i]]), () => ( (this.spec.type === "bubble" ? i + 1 : null))) : i + 1;
1476
+ const x = xy ? _nullishCoalesce(_optionalChain([series, 'access', _61 => _61.x, 'optionalAccess', _62 => _62[i]]), () => ( (this.spec.type === "bubble" ? i + 1 : null))) : i + 1;
1161
1477
  if (v !== null && x !== null && Number.isFinite(v) && Number.isFinite(x)) out.push([x, v]);
1162
1478
  });
1163
1479
  return out;
1164
1480
  }
1165
1481
  /** The fitted coefficients, R² and equation of a trendline (null for moving averages or unfittable data). */
1166
1482
  trendlineFit(seriesId, index) {
1167
- const line = _optionalChain([this, 'access', _39 => _39.getSeries, 'call', _40 => _40(seriesId), 'optionalAccess', _41 => _41.trendlines, 'optionalAccess', _42 => _42[index]]);
1483
+ const line = _optionalChain([this, 'access', _63 => _63.getSeries, 'call', _64 => _64(seriesId), 'optionalAccess', _65 => _65.trendlines, 'optionalAccess', _66 => _66[index]]);
1168
1484
  if (!line) return null;
1169
- return _chunkHDGBM7EAcjs.fitChartTrendline.call(void 0, line, this.trendlinePoints(seriesId));
1485
+ return _chunkSBQVEBSUcjs.fitChartTrendline.call(void 0, line, this.trendlinePoints(seriesId));
1170
1486
  }
1171
1487
  /** The moving-average points of a trendline (empty for other kinds). */
1172
1488
  trendlineMovingAverage(seriesId, index) {
1173
- const line = _optionalChain([this, 'access', _43 => _43.getSeries, 'call', _44 => _44(seriesId), 'optionalAccess', _45 => _45.trendlines, 'optionalAccess', _46 => _46[index]]);
1489
+ const line = _optionalChain([this, 'access', _67 => _67.getSeries, 'call', _68 => _68(seriesId), 'optionalAccess', _69 => _69.trendlines, 'optionalAccess', _70 => _70[index]]);
1174
1490
  if (!line || line.type !== "moving-average") return [];
1175
- return _chunkHDGBM7EAcjs.chartMovingAverage.call(void 0, this.trendlinePoints(seriesId), _nullishCoalesce(line.period, () => ( 2)));
1491
+ return _chunkSBQVEBSUcjs.chartMovingAverage.call(void 0, this.trendlinePoints(seriesId), _nullishCoalesce(line.period, () => ( 2)));
1176
1492
  }
1177
1493
  // -------------------------------------------------------------------------
1178
1494
  // Reshaping
@@ -1182,6 +1498,8 @@ var ChartController = (_class = class {
1182
1498
  * undo step). Series colours, types and other per-series settings are dropped.
1183
1499
  */
1184
1500
  transpose() {
1501
+ const grouped = this.treeLocked();
1502
+ if (grouped) return grouped;
1185
1503
  const s = this.spec;
1186
1504
  if (!s.series.length || !s.categories.length) return this.reject("There is no data to switch: the chart needs at least one series and one category.");
1187
1505
  const used = /* @__PURE__ */ new Set();
@@ -1191,7 +1509,7 @@ var ChartController = (_class = class {
1191
1509
  used.add(id);
1192
1510
  return { id, name, values: s.series.map((x) => _nullishCoalesce(x.values[i], () => ( null))) };
1193
1511
  });
1194
- const { spec } = _chunkLL3H5XUHcjs.normalizeChartSpec.call(void 0, { ...s, categories: s.series.map((x) => x.name), series });
1512
+ const { spec } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, { ...s, categories: s.series.map((x) => x.name), series });
1195
1513
  this.commit("Switch rows and columns", spec, null);
1196
1514
  return { ok: true };
1197
1515
  }
@@ -1201,7 +1519,7 @@ var ChartController = (_class = class {
1201
1519
  /** Selects a chart element (view state; not an undo step). */
1202
1520
  select(selection) {
1203
1521
  const next = this.validSelection(selection, this.spec);
1204
- if (_chunkHDGBM7EAcjs.sameChartSelection.call(void 0, next, this.selection) || next === null && this.selection === null) return;
1522
+ if (_chunkSBQVEBSUcjs.sameChartSelection.call(void 0, next, this.selection) || next === null && this.selection === null) return;
1205
1523
  this.selection = next;
1206
1524
  this.notify(false);
1207
1525
  }
@@ -1235,6 +1553,8 @@ var ChartController = (_class = class {
1235
1553
  }
1236
1554
  /** Adds `delta` to a value (a gap counts as 0). */
1237
1555
  nudgeValue(seriesId, index, delta) {
1556
+ const grouped = this.treeLocked();
1557
+ if (grouped) return grouped;
1238
1558
  const series = this.getSeries(seriesId);
1239
1559
  if (!series) return this.unknownSeries(seriesId);
1240
1560
  const current = _nullishCoalesce(series.values[index], () => ( 0));
@@ -1276,14 +1596,14 @@ var ChartController = (_class = class {
1276
1596
  // -------------------------------------------------------------------------
1277
1597
  /** The spec, for saving (a copy). */
1278
1598
  toJSON() {
1279
- return _chunkLL3H5XUHcjs.cloneChartSpec.call(void 0, this.spec);
1599
+ return _chunkR3P2M7HUcjs.cloneChartSpec.call(void 0, this.spec);
1280
1600
  }
1281
1601
  /**
1282
1602
  * Replaces the chart without an undo step (e.g. when opening a document). Problems are
1283
1603
  * fixed with defaults and reported in `state.issues` (and returned).
1284
1604
  */
1285
1605
  load(input, options = {}) {
1286
- const { spec, issues } = _chunkLL3H5XUHcjs.normalizeChartSpec.call(void 0, input);
1606
+ const { spec, issues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, input);
1287
1607
  this.spec = spec;
1288
1608
  this.issues = issues;
1289
1609
  this.selection = this.validSelection(this.selection, spec);
@@ -1303,7 +1623,7 @@ var ChartController = (_class = class {
1303
1623
  * nothing changes and every problem is returned (and shown in `state.issues`).
1304
1624
  */
1305
1625
  replace(input, options = {}) {
1306
- const { spec, issues } = _chunkLL3H5XUHcjs.normalizeChartSpec.call(void 0, input);
1626
+ const { spec, issues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, input);
1307
1627
  if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1308
1628
  this.commit(_nullishCoalesce(options.label, () => ( "Replace chart")), spec, this.validSelection(this.selection, spec));
1309
1629
  return { ok: true };
@@ -1318,7 +1638,7 @@ var ChartController = (_class = class {
1318
1638
  }
1319
1639
  /** Stops listening to the history (reconnected by the next `subscribe`). */
1320
1640
  destroy() {
1321
- _optionalChain([this, 'access', _47 => _47.unsubscribeHistory, 'optionalCall', _48 => _48()]);
1641
+ _optionalChain([this, 'access', _71 => _71.unsubscribeHistory, 'optionalCall', _72 => _72()]);
1322
1642
  this.unsubscribeHistory = void 0;
1323
1643
  this.listeners.clear();
1324
1644
  }
@@ -1343,6 +1663,18 @@ function updateLabel(patch) {
1343
1663
  overlap: "Change bar overlap",
1344
1664
  bins: "Change histogram bins",
1345
1665
  showTotal: "Toggle waterfall total",
1666
+ note: "Edit note",
1667
+ highlight: "Change highlight",
1668
+ referenceLines: "Change reference lines",
1669
+ referenceBands: "Change reference bands",
1670
+ varyColors: "Toggle colour by category",
1671
+ likertNeutral: "Change neutral answer",
1672
+ likertSort: "Sort questions",
1673
+ parliamentArc: "Change hemicycle sweep",
1674
+ parliamentMajority: "Change majority",
1675
+ parliamentLabel: "Edit seat caption",
1676
+ sunburstLabel: "Edit centre caption",
1677
+ tree: "Replace grouped data",
1346
1678
  radarTicks: "Change radar rings",
1347
1679
  radarGraticule: "Change radar grid",
1348
1680
  legend: "Change legend",
@@ -1365,7 +1697,7 @@ function layoutSparkline(values, options) {
1365
1697
  const h = Number.isFinite(options.height) ? Math.max(1, options.height) : 1;
1366
1698
  const color = _nullishCoalesce(options.color, () => ( "#4269d0"));
1367
1699
  const negative = _nullishCoalesce(options.negativeColor, () => ( "#e5484d"));
1368
- const theme = { ..._chunkLL3H5XUHcjs.DEFAULT_CHART_THEME, background: "transparent" };
1700
+ const theme = { ..._chunkR3P2M7HUcjs.DEFAULT_CHART_THEME, background: "transparent" };
1369
1701
  const marks = [];
1370
1702
  const scene = { width: w, height: h, plot: { x: 0, y: 0, width: w, height: h }, marks, percent: false, theme, warnings: [] };
1371
1703
  const vals = values.slice(0, MAX_POINTS).map((v) => v !== null && Number.isFinite(v) ? Math.max(-1e300, Math.min(1e300, v)) : null);
@@ -1398,7 +1730,7 @@ function layoutSparkline(values, options) {
1398
1730
  const flush = () => {
1399
1731
  if (run.length >= 2) {
1400
1732
  const pts = run.length > 4e3 ? run.filter((_, i) => i % (Math.floor(run.length / 2e3) + 1) === 0) : run;
1401
- d += pts.map(([x, y], i) => `${i ? "L" : "M"}${_chunkHDGBM7EAcjs.r2.call(void 0, x)},${_chunkHDGBM7EAcjs.r2.call(void 0, y)}`).join("");
1733
+ d += pts.map(([x, y], i) => `${i ? "L" : "M"}${_chunkSBQVEBSUcjs.r2.call(void 0, x)},${_chunkSBQVEBSUcjs.r2.call(void 0, y)}`).join("");
1402
1734
  }
1403
1735
  run = [];
1404
1736
  };