@pixerate/editor 0.164.0 → 0.165.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 (141) hide show
  1. package/dist/agent/index.cjs +54 -39
  2. package/dist/agent/index.js +24 -9
  3. package/dist/animation/index.cjs +6 -5
  4. package/dist/animation/index.js +5 -4
  5. package/dist/animation-editor/index.cjs +65 -64
  6. package/dist/animation-editor/index.js +8 -7
  7. package/dist/bridge/cli.cjs +3 -3
  8. package/dist/bridge/cli.js +2 -2
  9. package/dist/bridge/index.cjs +3 -3
  10. package/dist/bridge/index.js +2 -2
  11. package/dist/canvas/index.cjs +89 -87
  12. package/dist/canvas/index.js +11 -9
  13. package/dist/chart/controller.d.cts +31 -2
  14. package/dist/chart/controller.d.ts +31 -2
  15. package/dist/chart/index.cjs +504 -132
  16. package/dist/chart/index.d.cts +2 -0
  17. package/dist/chart/index.d.ts +2 -0
  18. package/dist/chart/index.js +386 -14
  19. package/dist/chart/layout-families.d.cts +7 -0
  20. package/dist/chart/layout-families.d.ts +7 -0
  21. package/dist/chart/links.d.cts +34 -0
  22. package/dist/chart/links.d.ts +34 -0
  23. package/dist/chart/mermaid.d.cts +9 -6
  24. package/dist/chart/mermaid.d.ts +9 -6
  25. package/dist/chart/schemas.d.cts +3 -0
  26. package/dist/chart/schemas.d.ts +3 -0
  27. package/dist/chart/spec.d.cts +3 -2
  28. package/dist/chart/spec.d.ts +3 -2
  29. package/dist/chart/style.d.cts +33 -0
  30. package/dist/chart/style.d.ts +33 -0
  31. package/dist/chart/types.d.cts +24 -2
  32. package/dist/chart/types.d.ts +24 -2
  33. package/dist/{chunk-TALQONZ5.js → chunk-2J5VLJHC.js} +3 -3
  34. package/dist/{chunk-3NEZJCBY.js → chunk-2ZRN43IN.js} +340 -201
  35. package/dist/{chunk-ZVNAMTFO.cjs → chunk-3FSUJIXN.cjs} +18 -174
  36. package/dist/{chunk-RQCMSEM5.cjs → chunk-4QUUHTGJ.cjs} +2 -2
  37. package/dist/{chunk-CIPIESX4.cjs → chunk-4ZC5QJE2.cjs} +3 -3
  38. package/dist/{chunk-S6X2QRVU.cjs → chunk-5UEFBM2M.cjs} +1 -138
  39. package/dist/{chunk-YSAGBIRW.cjs → chunk-64VWWR5U.cjs} +16 -16
  40. package/dist/{chunk-QYZGBVNC.js → chunk-7272D3K2.js} +10 -8
  41. package/dist/{chunk-462WGGXX.cjs → chunk-AMX23CSN.cjs} +27 -16
  42. package/dist/{chunk-3VLOOO3G.js → chunk-BDIM6NVW.js} +1 -1
  43. package/dist/{chunk-POR54B55.js → chunk-CRFSQWKQ.js} +4 -1
  44. package/dist/{chunk-GZ2FM3ZB.js → chunk-DKNEQX7T.js} +6 -162
  45. package/dist/{chunk-JCXMJUQO.cjs → chunk-EGZM52EO.cjs} +3 -3
  46. package/dist/{chunk-ES3UEVUT.cjs → chunk-EUIDTZNQ.cjs} +112 -110
  47. package/dist/{chunk-H3OEM3Q2.js → chunk-F6R67I3A.js} +1 -1
  48. package/dist/{chunk-5FNGLV2D.js → chunk-FEU2XVQH.js} +15 -3
  49. package/dist/{chunk-SZA42R4N.js → chunk-FRBRLKNQ.js} +154 -16
  50. package/dist/chunk-HIDFL5LQ.js +484 -0
  51. package/dist/{chunk-MKTDELCD.js → chunk-I5MRJW7B.js} +1 -1
  52. package/dist/{chunk-SDHZG5TF.js → chunk-ILP77UD6.js} +160 -2
  53. package/dist/{chunk-GKNEJ6EN.cjs → chunk-IMRXC7OA.cjs} +241 -103
  54. package/dist/chunk-KGRZMHZB.js +204 -0
  55. package/dist/{chunk-SET6KJOP.js → chunk-LPIKXPBM.js} +1 -1
  56. package/dist/{chunk-BQWGN5WH.js → chunk-M2TPMYJE.js} +1 -1
  57. package/dist/{chunk-GTELFJRE.cjs → chunk-M5GLQQWG.cjs} +2 -2
  58. package/dist/{chunk-4VU4CP7R.js → chunk-MHLU6GRJ.js} +1 -138
  59. package/dist/{chunk-D54JHQK2.cjs → chunk-MKXK6E4O.cjs} +51 -51
  60. package/dist/{chunk-DAPQGA55.js → chunk-N7NBGT2Y.js} +2 -2
  61. package/dist/chunk-O6OGNDND.js +164 -0
  62. package/dist/{chunk-22KLZZGH.cjs → chunk-ODFCS7HF.cjs} +8 -8
  63. package/dist/{chunk-PA3IMPPS.cjs → chunk-OVYQAYGH.cjs} +81 -81
  64. package/dist/{chunk-YXOW456B.js → chunk-PPEDZ5WR.js} +1 -1
  65. package/dist/{chunk-YGG7WDWT.cjs → chunk-Q25WAFTD.cjs} +21 -18
  66. package/dist/{chunk-SBQVEBSU.cjs → chunk-QO2T6KA5.cjs} +165 -67
  67. package/dist/{chunk-24M7VD6M.cjs → chunk-S4EIAIEW.cjs} +7 -7
  68. package/dist/{chunk-M4MIZPQI.cjs → chunk-SJ2CPTQC.cjs} +189 -15
  69. package/dist/chunk-TFF2GTGN.cjs +153 -0
  70. package/dist/chunk-TTCJPX4U.cjs +204 -0
  71. package/dist/{chunk-NZD2MZJC.cjs → chunk-TVQW26AV.cjs} +35 -23
  72. package/dist/{chunk-R3P2M7HU.cjs → chunk-UVXTOZ2B.cjs} +346 -207
  73. package/dist/{chunk-WI7QJA7A.cjs → chunk-UXETV2NC.cjs} +161 -3
  74. package/dist/{chunk-Z4P2RBMJ.js → chunk-V5GSY3NC.js} +101 -3
  75. package/dist/{chunk-QY4KUDMY.js → chunk-VRXXAXUT.js} +2 -2
  76. package/dist/chunk-VU6WQSMB.cjs +164 -0
  77. package/dist/{chunk-OXERWBKE.js → chunk-X5W645RI.js} +3 -3
  78. package/dist/{chunk-NHLYK3AX.js → chunk-XBQX76CT.js} +182 -8
  79. package/dist/{chunk-5AARIS3R.cjs → chunk-XCDGM7TD.cjs} +37 -37
  80. package/dist/{chunk-EVXQNQND.js → chunk-XZB3TJ6K.js} +16 -5
  81. package/dist/chunk-YBAPT7NL.js +153 -0
  82. package/dist/chunk-Z2UQYMPS.cjs +484 -0
  83. package/dist/color/index.cjs +5 -3
  84. package/dist/color/index.js +12 -10
  85. package/dist/diagram/index.cjs +55 -243
  86. package/dist/diagram/index.js +12 -200
  87. package/dist/export/index.cjs +7 -6
  88. package/dist/export/index.js +6 -5
  89. package/dist/extensions/index.cjs +12 -9
  90. package/dist/extensions/index.js +11 -8
  91. package/dist/gradient/index.cjs +29 -27
  92. package/dist/gradient/index.js +6 -4
  93. package/dist/image-editor/index.cjs +644 -643
  94. package/dist/image-editor/index.js +7 -6
  95. package/dist/index.cjs +21 -18
  96. package/dist/index.js +14 -11
  97. package/dist/paint-editor/index.cjs +19 -18
  98. package/dist/paint-editor/index.js +7 -6
  99. package/dist/parameters/index.cjs +2 -2
  100. package/dist/parameters/index.js +1 -1
  101. package/dist/persistence/assetWrites.d.cts +22 -0
  102. package/dist/persistence/assetWrites.d.ts +22 -0
  103. package/dist/persistence/assets.d.cts +71 -0
  104. package/dist/persistence/assets.d.ts +71 -0
  105. package/dist/persistence/documentStore.d.cts +17 -1
  106. package/dist/persistence/documentStore.d.ts +17 -1
  107. package/dist/persistence/documentTools.d.cts +5 -1
  108. package/dist/persistence/documentTools.d.ts +5 -1
  109. package/dist/persistence/editorAutosave.d.cts +7 -0
  110. package/dist/persistence/editorAutosave.d.ts +7 -0
  111. package/dist/persistence/index.cjs +141 -21
  112. package/dist/persistence/index.js +130 -10
  113. package/dist/persistence/storage.d.cts +13 -1
  114. package/dist/persistence/storage.d.ts +13 -1
  115. package/dist/spreadsheet/index.cjs +3 -3
  116. package/dist/spreadsheet/index.js +2 -2
  117. package/dist/tokens/index.cjs +11 -3
  118. package/dist/tokens/index.d.cts +1 -0
  119. package/dist/tokens/index.d.ts +1 -0
  120. package/dist/tokens/index.js +10 -2
  121. package/dist/tokens/style.d.cts +36 -0
  122. package/dist/tokens/style.d.ts +36 -0
  123. package/dist/tools/index.cjs +15 -3
  124. package/dist/tools/index.d.cts +2 -0
  125. package/dist/tools/index.d.ts +2 -0
  126. package/dist/tools/index.js +14 -2
  127. package/dist/tools/style-tools.d.cts +19 -0
  128. package/dist/tools/style-tools.d.ts +19 -0
  129. package/dist/tools/style.d.cts +212 -0
  130. package/dist/tools/style.d.ts +212 -0
  131. package/dist/tools/view.d.cts +6 -0
  132. package/dist/tools/view.d.ts +6 -0
  133. package/dist/typography/index.cjs +8 -6
  134. package/dist/typography/index.js +5 -3
  135. package/dist/vector/index.cjs +953 -952
  136. package/dist/vector/index.js +7 -6
  137. package/dist/video-editor/index.cjs +8 -7
  138. package/dist/video-editor/index.js +6 -5
  139. package/package.json +1 -1
  140. package/dist/chunk-ERAGQL2N.cjs +0 -68
  141. package/dist/chunk-KMU6QJB7.js +0 -68
@@ -1,16 +1,17 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;
2
2
 
3
3
 
4
+ var _chunkTTCJPX4Ucjs = require('./chunk-TTCJPX4U.cjs');
4
5
 
5
6
 
6
7
 
7
8
 
8
9
 
9
10
 
10
- var _chunkSBQVEBSUcjs = require('./chunk-SBQVEBSU.cjs');
11
11
 
12
12
 
13
13
 
14
+ var _chunkQO2T6KA5cjs = require('./chunk-QO2T6KA5.cjs');
14
15
 
15
16
 
16
17
 
@@ -36,7 +37,14 @@ var _chunkSBQVEBSUcjs = require('./chunk-SBQVEBSU.cjs');
36
37
 
37
38
 
38
39
 
39
- var _chunkR3P2M7HUcjs = require('./chunk-R3P2M7HU.cjs');
40
+
41
+
42
+
43
+
44
+
45
+
46
+
47
+ var _chunkUVXTOZ2Bcjs = require('./chunk-UVXTOZ2B.cjs');
40
48
 
41
49
 
42
50
 
@@ -71,9 +79,14 @@ function splitOutside(text, sep) {
71
79
  out.push(cur);
72
80
  return out;
73
81
  }
82
+ var csvField = (text) => /[",\n]|^\s|\s$/.test(text) ? `"${text.replace(/"/g, '""')}"` : text;
83
+ var treemapName = (name) => !name.includes('"') ? `"${name}"` : !name.includes("'") ? `'${name}'` : `"${name.replace(/"/g, "'")}"`;
84
+ var yamlText = (text) => /^[\w][\w .,!?()/&+-]*$/.test(text) && !/:\s/.test(text) ? text : JSON.stringify(text);
74
85
  function chartMermaidFamily(spec) {
75
- const family = _chunkR3P2M7HUcjs.chartFamily.call(void 0, spec);
76
- if (family === "pie" || family === "funnel" || family === "treemap" || family === "parliament" || family === "sunburst") return "pie";
86
+ const family = _chunkUVXTOZ2Bcjs.chartFamily.call(void 0, spec);
87
+ if (family === "sankey" && _optionalChain([spec, 'access', _2 => _2.links, 'optionalAccess', _3 => _3.length])) return "sankey";
88
+ if (family === "treemap" || family === "sunburst") return "treemap";
89
+ if (family === "pie" || family === "funnel" || family === "parliament") return "pie";
77
90
  if (family === "radar") return "radar";
78
91
  return "xychart";
79
92
  }
@@ -114,12 +127,32 @@ function chartToMermaid(spec, options = {}) {
114
127
  const visible = spec.series.filter((s) => !s.hidden);
115
128
  const lines = [];
116
129
  const v = (x) => x === null || !Number.isFinite(x) ? "0" : num(x);
117
- if (family === "pie") {
130
+ const front = [];
131
+ if (family === "sankey") {
132
+ if (spec.title) front.push("---", `title: ${yamlText(spec.title)}`, "---");
133
+ lines.push("sankey-beta");
134
+ for (const l of spec.links) lines.push(`${csvField(l.source)},${csvField(l.target)},${num(l.value)}`);
135
+ } else if (family === "treemap") {
136
+ lines.push("treemap-beta");
137
+ if (spec.title) lines.push(`title ${spec.title}`);
138
+ const first = _nullishCoalesce(visible[0], () => ( spec.series[0]));
139
+ const tree = spec.tree.length ? spec.tree : _chunkUVXTOZ2Bcjs.chartTreeFromSeries.call(void 0, spec.categories, _nullishCoalesce(_optionalChain([first, 'optionalAccess', _4 => _4.values]), () => ( [])));
140
+ const write = (nodes, depth) => {
141
+ for (const n of nodes) {
142
+ const pad = ind.repeat(depth);
143
+ if (n.children) {
144
+ lines.push(`${pad}${treemapName(n.name)}`);
145
+ write(n.children, depth + 1);
146
+ } else lines.push(`${pad}${treemapName(n.name)}: ${num(_nullishCoalesce(n.value, () => ( 0)))}`);
147
+ }
148
+ };
149
+ write(tree, 1);
150
+ } else if (family === "pie") {
118
151
  const s = _nullishCoalesce(visible[0], () => ( spec.series[0]));
119
152
  lines.push(`pie${spec.dataLabels ? " showData" : ""}`);
120
153
  if (spec.title) lines.push(`${ind}title ${spec.title}`);
121
154
  spec.categories.forEach((c, i) => {
122
- const value = _optionalChain([s, 'optionalAccess', _2 => _2.values, 'access', _3 => _3[i]]);
155
+ const value = _optionalChain([s, 'optionalAccess', _5 => _5.values, 'access', _6 => _6[i]]);
123
156
  if (value !== null && value !== void 0 && Number.isFinite(value) && value > 0) lines.push(`${ind}${quote(c)} : ${num(value)}`);
124
157
  });
125
158
  } else if (family === "radar") {
@@ -160,13 +193,13 @@ function chartToMermaid(spec, options = {}) {
160
193
  lines.push(`${ind}${kind} ${quote(s.name)} [${s.values.map(v).join(", ")}]`);
161
194
  }
162
195
  }
163
- let text = `${lines.join("\n")}
196
+ let text = `${[...front, ...lines].join("\n")}
164
197
  `;
165
198
  if (options.meta !== false) {
166
199
  const meta = metaFor(spec, text);
167
200
  if (meta) {
168
201
  const [header, ...rest] = lines;
169
- text = `${[header, `${CHART_MERMAID_META_PREFIX}${JSON.stringify({ v: 1, ...meta })}`, ...rest].join("\n")}
202
+ text = `${[...front, header, `${CHART_MERMAID_META_PREFIX}${JSON.stringify({ v: 1, ...meta })}`, ...rest].join("\n")}
170
203
  `;
171
204
  }
172
205
  }
@@ -202,7 +235,7 @@ function chartFromMermaid(text, options = {}) {
202
235
  const all = text.replace(/^/, "").split(/\r?\n/);
203
236
  let start = 0;
204
237
  let frontTitle;
205
- if (_optionalChain([all, 'access', _4 => _4[0], 'optionalAccess', _5 => _5.trim, 'call', _6 => _6()]) === "---") {
238
+ if (_optionalChain([all, 'access', _7 => _7[0], 'optionalAccess', _8 => _8.trim, 'call', _9 => _9()]) === "---") {
206
239
  const end = all.findIndex((l, i) => i > 0 && l.trim() === "---");
207
240
  if (end > 0) {
208
241
  for (const l of all.slice(1, end)) {
@@ -223,21 +256,23 @@ function chartFromMermaid(text, options = {}) {
223
256
  let m;
224
257
  if (m = /^xychart(?:-beta)?(?:\s+(horizontal|vertical))?\s*$/i.exec(t)) {
225
258
  family = "xychart";
226
- horizontal = _optionalChain([m, 'access', _7 => _7[1], 'optionalAccess', _8 => _8.toLowerCase, 'call', _9 => _9()]) === "horizontal";
259
+ horizontal = _optionalChain([m, 'access', _10 => _10[1], 'optionalAccess', _11 => _11.toLowerCase, 'call', _12 => _12()]) === "horizontal";
227
260
  } else if (m = /^pie(\s+showData)?(?:\s+title\s+(.*))?\s*$/i.exec(t)) {
228
261
  family = "pie";
229
262
  showData = !!m[1];
230
263
  if (m[2]) frontTitle = m[2].trim();
231
264
  } else if (/^radar(?:-beta)?\s*$/i.test(t)) family = "radar";
232
- else issues.push({ path: "header", line: i + 1, message: `Line ${i + 1}: expected a chart header (xychart-beta, pie or radar-beta), got "${t.slice(0, 40)}".` });
265
+ else if (/^sankey(?:-beta)?\s*$/i.test(t)) family = "sankey";
266
+ else if (/^treemap(?:-beta)?\s*$/i.test(t)) family = "treemap";
267
+ else issues.push({ path: "header", line: i + 1, message: `Line ${i + 1}: expected a chart header (xychart-beta, pie, radar-beta, sankey-beta or treemap-beta), got "${t.slice(0, 40)}".` });
233
268
  headerLine = i;
234
269
  break;
235
270
  }
236
271
  let title = _nullishCoalesce(frontTitle, () => ( ""));
237
272
  const categories = [];
238
273
  const series = [];
239
- const xAxis = _chunkR3P2M7HUcjs.defaultChartAxis.call(void 0, false);
240
- const yAxis = _chunkR3P2M7HUcjs.defaultChartAxis.call(void 0, true);
274
+ const xAxis = _chunkUVXTOZ2Bcjs.defaultChartAxis.call(void 0, false);
275
+ const yAxis = _chunkUVXTOZ2Bcjs.defaultChartAxis.call(void 0, true);
241
276
  const radarAxes = [];
242
277
  const pieSlices = [];
243
278
  let legendShow = true;
@@ -245,6 +280,7 @@ function chartFromMermaid(text, options = {}) {
245
280
  let graticule = "circle";
246
281
  const counts = { bar: 0, line: 0 };
247
282
  const lineIssue = (i, message) => issues.push({ path: `line ${i + 1}`, line: i + 1, message: `Line ${i + 1}: ${message}` });
283
+ const whole = family === "sankey" || family === "treemap";
248
284
  for (let i = headerLine + 1; family && i < all.length; i++) {
249
285
  const raw = all[i];
250
286
  const t = raw.trim();
@@ -260,7 +296,7 @@ function chartFromMermaid(text, options = {}) {
260
296
  }
261
297
  continue;
262
298
  }
263
- if (t.startsWith("%%")) continue;
299
+ if (t.startsWith("%%") || whole) continue;
264
300
  const isLast = i === all.length - 1 || all.slice(i + 1).every((l) => !l.trim());
265
301
  let m;
266
302
  if (m = /^title\s+(.+)$/i.exec(t)) {
@@ -362,7 +398,8 @@ function chartFromMermaid(text, options = {}) {
362
398
  if (!(partial && isLast)) lineIssue(i, `could not read "${t.slice(0, 60)}"; it was skipped.`);
363
399
  }
364
400
  let input;
365
- if (family === "pie") {
401
+ if (whole) input = readWholeMermaid(family, all, headerLine, partial, title, issues);
402
+ else if (family === "pie") {
366
403
  input = {
367
404
  type: "pie",
368
405
  title,
@@ -397,19 +434,55 @@ function chartFromMermaid(text, options = {}) {
397
434
  input.series = metaSeries.map((extra, i) => ({ ..._nullishCoalesce(base[i], () => ( {})), ..._nullishCoalesce(extra, () => ( {})) }));
398
435
  }
399
436
  }
400
- const { spec, issues: specIssues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, input);
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)." });
437
+ const { spec, issues: specIssues } = _chunkUVXTOZ2Bcjs.normalizeChartSpec.call(void 0, input);
438
+ if (!family && !partial && !issues.length) issues.push({ path: "header", message: "The text is empty: expected a chart header (xychart-beta, pie, radar-beta, sankey-beta or treemap-beta)." });
402
439
  return { spec, issues: [...issues, ...specIssues], family, hasMeta: !!meta };
403
440
  }
441
+ function readWholeMermaid(family, all, headerLine, partial, title, issues) {
442
+ const body = all.slice(headerLine).map((l) => l.trim().startsWith(CHART_MERMAID_META_PREFIX.trim()) ? "%%" : l);
443
+ const parse = (lines) => family === "sankey" ? _chunkTTCJPX4Ucjs.parseSankey.call(void 0, lines.join("\n")) : _chunkTTCJPX4Ucjs.parseTreemap.call(void 0, lines.join("\n"));
444
+ let read = parse(body);
445
+ if ("error" in read && partial && body.length > 1) read = parse(body.slice(0, -1));
446
+ const lineOf = (n) => n === void 0 ? void 0 : n + headerLine;
447
+ if ("error" in read) {
448
+ const line = lineOf(read.line);
449
+ if (!(partial && body.length <= 2)) issues.push({ path: family, ...line ? { line } : {}, message: line ? `Line ${line}: ${read.error}` : read.error });
450
+ return { type: family === "sankey" ? "sankey" : "treemap", title };
451
+ }
452
+ if (family === "sankey") {
453
+ const data2 = read.data;
454
+ return { type: "sankey", title, links: data2.links, sankeyNodes: data2.nodes, series: [{ id: "series-1", name: "Values", values: [] }] };
455
+ }
456
+ const data = read.data;
457
+ let items = data.items;
458
+ let name = _nullishCoalesce(data.title, () => ( title));
459
+ if (items.length === 1 && _optionalChain([items, 'access', _13 => _13[0], 'access', _14 => _14.children, 'optionalAccess', _15 => _15.length])) {
460
+ name ||= items[0].name;
461
+ items = items[0].children;
462
+ }
463
+ const toNode = (item) => _optionalChain([item, 'access', _16 => _16.children, 'optionalAccess', _17 => _17.length]) ? { name: item.name, children: item.children.map(toNode) } : { name: item.name, value: _nullishCoalesce(item.value, () => ( 0)) };
464
+ const tree = items.map(toNode);
465
+ const leaf = (n) => !n.children;
466
+ const flatOrOneLevel = tree.every(leaf) || tree.every((n) => _optionalChain([n, 'access', _18 => _18.children, 'optionalAccess', _19 => _19.every, 'call', _20 => _20(leaf)]));
467
+ return { type: flatOrOneLevel ? "treemap" : "sunburst", title: name, tree, categories: tree.map((n) => n.name), series: [{ id: "series-1", name: "Values", values: tree.map(_chunkUVXTOZ2Bcjs.chartTreeTotal) }] };
468
+ }
404
469
  function findMermaidCharts(text) {
405
470
  const lines = text.replace(/^/, "").split(/\r?\n/);
406
471
  const found = [];
407
472
  const familyOf = (body) => {
408
- const header = body.split(/\r?\n/).find((l) => l.trim() && !l.trim().startsWith("%%") && l.trim() !== "---");
473
+ let rows = body.split(/\r?\n/);
474
+ const firstRow = rows.findIndex((l) => l.trim());
475
+ if (_optionalChain([rows, 'access', _21 => _21[firstRow], 'optionalAccess', _22 => _22.trim, 'call', _23 => _23()]) === "---") {
476
+ const end = rows.findIndex((l, i) => i > firstRow && l.trim() === "---");
477
+ if (end > 0) rows = rows.slice(end + 1);
478
+ }
479
+ const header = rows.find((l) => l.trim() && !l.trim().startsWith("%%"));
409
480
  if (!header) return null;
410
481
  if (/^\s*xychart(-beta)?\b/.test(header)) return "xychart";
411
482
  if (/^\s*pie\b/.test(header)) return "pie";
412
483
  if (/^\s*radar(-beta)?\b/.test(header)) return "radar";
484
+ if (/^\s*sankey(-beta)?\s*$/.test(header)) return "sankey";
485
+ if (/^\s*treemap(-beta)?\s*$/.test(header)) return "treemap";
413
486
  return null;
414
487
  };
415
488
  for (let i = 0; i < lines.length; i++) {
@@ -436,11 +509,11 @@ function findMermaidCharts(text) {
436
509
  }
437
510
 
438
511
  // src/chart/summary.ts
439
- function summarizeChart(spec, size = { width: 640, height: 400 }, scene = _chunkSBQVEBSUcjs.layoutChart.call(void 0, spec, { ...size, selection: null })) {
512
+ function summarizeChart(spec, size = { width: 640, height: 400 }, scene = _chunkQO2T6KA5cjs.layoutChart.call(void 0, spec, { ...size, selection: null })) {
440
513
  const visible = spec.series.filter((s) => !s.hidden);
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 });
514
+ const series = visible.map((s) => _chunkQO2T6KA5cjs.summarizeChartSeries.call(void 0, s, spec.categories));
515
+ const colors = _chunkUVXTOZ2Bcjs.chartSpecColorsByCategory.call(void 0, spec) ? spec.categories.map((_, i) => _optionalChain([visible, 'access', _24 => _24[0], 'optionalAccess', _25 => _25.pointColors, 'optionalAccess', _26 => _26[i]]) || _chunkUVXTOZ2Bcjs.chartSliceColor.call(void 0, spec, i)) : visible.map((s) => _chunkUVXTOZ2Bcjs.chartSeriesColor.call(void 0, spec, spec.series.indexOf(s)));
516
+ const check = _chunkUVXTOZ2Bcjs.checkChartColors.call(void 0, colors, { surface: scene.theme.surface.startsWith("var(") ? "#ffffff" : scene.theme.surface });
444
517
  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;
445
518
  return {
446
519
  type: spec.type,
@@ -455,12 +528,12 @@ function summarizeChart(spec, size = { width: 640, height: 400 }, scene = _chunk
455
528
  description: describeChart(spec, series)
456
529
  };
457
530
  }
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();
531
+ function describeChart(spec, series = spec.series.filter((s) => !s.hidden).map((s) => _chunkQO2T6KA5cjs.summarizeChartSeries.call(void 0, s, spec.categories))) {
532
+ const kind = _chunkUVXTOZ2Bcjs.CHART_TYPE_LABELS[spec.type].toLowerCase();
460
533
  const parts = [];
461
- const family = _chunkR3P2M7HUcjs.chartFamily.call(void 0, spec);
534
+ const family = _chunkUVXTOZ2Bcjs.chartFamily.call(void 0, spec);
462
535
  const format = spec.yAxis.format;
463
- const fmt = (v) => v === null ? "blank" : _chunkSBQVEBSUcjs.formatChartNumber.call(void 0, v, format);
536
+ const fmt = (v) => v === null ? "blank" : _chunkQO2T6KA5cjs.formatChartNumber.call(void 0, v, format);
464
537
  const head = spec.title ? `${spec.title}: a ${kind} chart` : `A ${kind} chart`;
465
538
  if (!series.length || series.every((s) => s.count === 0)) return `${head} with no data.`;
466
539
  if (family === "pie" || family === "funnel" || family === "treemap" || family === "sunburst") {
@@ -470,19 +543,27 @@ function describeChart(spec, series = spec.series.filter((s) => !s.hidden).map((
470
543
  parts.push(`${head} of ${s.name} across ${spec.categories.length} categories, totalling ${fmt(s.sum)}.`);
471
544
  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
545
  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;
546
+ const depth = _chunkUVXTOZ2Bcjs.chartTreeDepth.call(void 0, spec.tree);
547
+ const items = _chunkUVXTOZ2Bcjs.chartTreeToRows.call(void 0, spec.tree).length;
475
548
  parts.push(`The data is grouped ${depth} level${depth === 1 ? "" : "s"} deep with ${items} item${items === 1 ? "" : "s"}.`);
476
549
  }
477
550
  return parts.join(" ");
478
551
  }
552
+ if (family === "sankey") {
553
+ if (!spec.links.length) return `${head} with no flows yet.`;
554
+ const total = spec.links.reduce((t, l) => t + l.value, 0);
555
+ const largest = [...spec.links].sort((a, b) => b.value - a.value)[0];
556
+ const sources = spec.sankeyNodes.filter((n) => !spec.links.some((l) => l.target === n));
557
+ const sinks = spec.sankeyNodes.filter((n) => !spec.links.some((l) => l.source === n));
558
+ return `${head} of ${spec.links.length} flows between ${spec.sankeyNodes.length} nodes, from ${sources.join(", ")} to ${sinks.join(", ")}. The largest flow is ${largest.source} \u2192 ${largest.target} (${fmt(largest.value)}); all flows add up to ${fmt(total)}.`;
559
+ }
479
560
  if (family === "parliament") {
480
561
  const s = spec.series.find((x) => !x.hidden);
481
562
  const seats = spec.categories.map((c, i) => ({ c, n: Math.max(0, Math.round(_nullishCoalesce(s.values[i], () => ( 0)))) }));
482
563
  const total = seats.reduce((t, x) => t + x.n, 0);
483
564
  const majority = _nullishCoalesce(spec.parliamentMajority, () => ( Math.floor(total / 2) + 1));
484
565
  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])}`;
566
+ 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', _27 => _27.c])} with ${_optionalChain([largest, 'optionalAccess', _28 => _28.n])}`;
486
567
  return `${head} of ${total} seats across ${seats.length} groups: ${verdict}.`;
487
568
  }
488
569
  if (family === "slope") {
@@ -505,7 +586,7 @@ function describeChart(spec, series = spec.series.filter((s) => !s.hidden).map((
505
586
  });
506
587
  const best = [...agree].sort((x, y) => y.share - x.share);
507
588
  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)))}).`;
589
+ return `${head} of ${spec.categories.length} questions with ${answers.length} answers from ${_optionalChain([answers, 'access', _29 => _29[0], 'optionalAccess', _30 => _30.name])} to ${_optionalChain([answers, 'access', _31 => _31[answers.length - 1], 'optionalAccess', _32 => _32.name])}. Most positive: ${_optionalChain([best, 'access', _33 => _33[0], 'optionalAccess', _34 => _34.c])} (${pct(_nullishCoalesce(_optionalChain([best, 'access', _35 => _35[0], 'optionalAccess', _36 => _36.share]), () => ( 0)))}); least: ${_optionalChain([best, 'access', _37 => _37[best.length - 1], 'optionalAccess', _38 => _38.c])} (${pct(_nullishCoalesce(_optionalChain([best, 'access', _39 => _39[best.length - 1], 'optionalAccess', _40 => _40.share]), () => ( 0)))}).`;
509
590
  }
510
591
  if (family === "waterfall") {
511
592
  const s = spec.series.find((x) => !x.hidden);
@@ -544,7 +625,7 @@ function describeChart(spec, series = spec.series.filter((s) => !s.hidden).map((
544
625
  }
545
626
  parts.push(...axes);
546
627
  for (const s of spec.series.filter((x) => !x.hidden && (x.errorBars || x.xErrorBars)).slice(0, 8)) {
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 ");
628
+ const bars = [s.errorBars ? _chunkUVXTOZ2Bcjs.describeChartErrorBars.call(void 0, s.errorBars) : "", s.xErrorBars ? `x ${_chunkUVXTOZ2Bcjs.describeChartErrorBars.call(void 0, s.xErrorBars)}` : ""].filter(Boolean).join(" and ");
548
629
  parts.push(`${s.name} has ${bars}.`);
549
630
  }
550
631
  return parts.join(" ");
@@ -609,7 +690,7 @@ function chartSceneToSvg(scene, options = {}) {
609
690
  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>`;
610
691
  }
611
692
  function chartToSvg(spec, options) {
612
- const scene = _chunkSBQVEBSUcjs.layoutChart.call(void 0, spec, { ...options, selection: null });
693
+ const scene = _chunkQO2T6KA5cjs.layoutChart.call(void 0, spec, { ...options, selection: null });
613
694
  return chartSceneToSvg(scene, { ...options, ariaLabel: _nullishCoalesce(options.ariaLabel, () => ( (spec.title || void 0))), description: _nullishCoalesce(options.description, () => ( describeChart(spec))) });
614
695
  }
615
696
  var SVG_NS = "http://www.w3.org/2000/svg";
@@ -647,10 +728,10 @@ var CHART_LAYOUT_PRESETS = [
647
728
  ];
648
729
  function monochromeChartPalette(base, count = 6) {
649
730
  const steps = count <= 1 ? [0] : Array.from({ length: count }, (_, i) => -0.45 + 1.05 * i / (count - 1));
650
- return steps.map((t) => _chunkR3P2M7HUcjs.shadeChartColor.call(void 0, base, t));
731
+ return steps.map((t) => _chunkUVXTOZ2Bcjs.shadeChartColor.call(void 0, base, t));
651
732
  }
652
733
  var CHART_COLOR_SCHEMES = [
653
- { id: "default", label: "Default", description: "Ten distinct colours, readable on light and dark backgrounds.", palette: _chunkR3P2M7HUcjs.DEFAULT_CHART_PALETTE },
734
+ { id: "default", label: "Default", description: "Ten distinct colours, readable on light and dark backgrounds.", palette: _chunkUVXTOZ2Bcjs.DEFAULT_CHART_PALETTE },
654
735
  { 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"] },
655
736
  { id: "office", label: "Office", description: "The six accent colours of the default Office theme.", palette: ["#4472c4", "#ed7d31", "#a5a5a5", "#ffc000", "#5b9bd5", "#70ad47"] },
656
737
  { id: "warm", label: "Warm", description: "Reds, oranges and yellows.", palette: ["#b2182b", "#d6604d", "#f4a582", "#e08214", "#fdb863", "#8c510a"] },
@@ -678,7 +759,7 @@ function chartPresetPatch(options) {
678
759
 
679
760
  // src/chart/controller.ts
680
761
  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])];
762
+ const lists = [s.values, s.x, s.sizes, s.pointColors, s.callouts, _optionalChain([s, 'access', _41 => _41.errorBars, 'optionalAccess', _42 => _42.plus]), _optionalChain([s, 'access', _43 => _43.errorBars, 'optionalAccess', _44 => _44.minus]), _optionalChain([s, 'access', _45 => _45.xErrorBars, 'optionalAccess', _46 => _46.plus]), _optionalChain([s, 'access', _47 => _47.xErrorBars, 'optionalAccess', _48 => _48.minus])];
682
763
  return lists.filter((l) => Array.isArray(l));
683
764
  }
684
765
  function sameChartJson(a, b) {
@@ -713,14 +794,14 @@ var ChartController = (_class = class {
713
794
  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);
714
795
  this.history = _nullishCoalesce(options.history, () => ( new (0, _chunkFJ2MSI43cjs.HistoryManager)()));
715
796
  this.onChange = options.onChange;
716
- const { spec, issues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, _nullishCoalesce(options.spec, () => ( {})));
797
+ const { spec, issues } = _chunkUVXTOZ2Bcjs.normalizeChartSpec.call(void 0, _nullishCoalesce(options.spec, () => ( {})));
717
798
  this.spec = spec;
718
799
  this.issues = issues;
719
800
  this.state = this.computeState();
720
801
  this.connect();
721
802
  }
722
803
  connect() {
723
- _optionalChain([this, 'access', _35 => _35.unsubscribeHistory, 'optionalCall', _36 => _36()]);
804
+ _optionalChain([this, 'access', _49 => _49.unsubscribeHistory, 'optionalCall', _50 => _50()]);
724
805
  this.unsubscribeHistory = this.history.subscribe((h) => {
725
806
  const s = this.state;
726
807
  if (this.applying || s.canUndo === h.canUndo && s.canRedo === h.canRedo && s.undoLabel === h.undoName && s.redoLabel === h.redoName) return;
@@ -750,12 +831,12 @@ var ChartController = (_class = class {
750
831
  computeState() {
751
832
  const h = this.history.getState();
752
833
  const sel = this.selection;
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;
834
+ const seriesId = _optionalChain([sel, 'optionalAccess', _51 => _51.kind]) === "series" || _optionalChain([sel, 'optionalAccess', _52 => _52.kind]) === "point" || _optionalChain([sel, 'optionalAccess', _53 => _53.kind]) === "trendline" ? sel.seriesId : null;
754
835
  return {
755
836
  spec: this.spec,
756
837
  selection: sel,
757
838
  selectedSeries: seriesId ? _nullishCoalesce(this.spec.series.find((s) => s.id === seriesId), () => ( null)) : null,
758
- selectedIndex: _optionalChain([sel, 'optionalAccess', _40 => _40.kind]) === "point" || _optionalChain([sel, 'optionalAccess', _41 => _41.kind]) === "category" ? sel.index : null,
839
+ selectedIndex: _optionalChain([sel, 'optionalAccess', _54 => _54.kind]) === "point" || _optionalChain([sel, 'optionalAccess', _55 => _55.kind]) === "category" ? sel.index : null,
759
840
  issues: this.issues,
760
841
  gesture: this.gestureKey,
761
842
  canUndo: h.canUndo,
@@ -768,7 +849,7 @@ var ChartController = (_class = class {
768
849
  notify(specChanged) {
769
850
  this.revision++;
770
851
  this.state = this.computeState();
771
- if (specChanged) _optionalChain([this, 'access', _42 => _42.onChange, 'optionalCall', _43 => _43(this.spec)]);
852
+ if (specChanged) _optionalChain([this, 'access', _56 => _56.onChange, 'optionalCall', _57 => _57(this.spec)]);
772
853
  const state = this.state;
773
854
  this.listeners.forEach((listener) => {
774
855
  try {
@@ -792,7 +873,7 @@ var ChartController = (_class = class {
792
873
  case "category":
793
874
  return sel.index < spec.categories.length ? sel : null;
794
875
  case "trendline":
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;
876
+ return _optionalChain([spec, 'access', _58 => _58.series, 'access', _59 => _59.find, 'call', _60 => _60((s) => s.id === sel.seriesId), 'optionalAccess', _61 => _61.trendlines, 'optionalAccess', _62 => _62[sel.index]]) ? sel : null;
796
877
  case "title":
797
878
  return spec.title ? sel : null;
798
879
  case "subtitle":
@@ -816,7 +897,7 @@ var ChartController = (_class = class {
816
897
  const hadIssues = this.issues.length > 0;
817
898
  this.issues = [];
818
899
  if (sameChartJson(before, next)) {
819
- const reselect = select !== void 0 && !_chunkSBQVEBSUcjs.sameChartSelection.call(void 0, this.selection, select) && !(select === null && this.selection === null);
900
+ const reselect = select !== void 0 && !_chunkQO2T6KA5cjs.sameChartSelection.call(void 0, this.selection, select) && !(select === null && this.selection === null);
820
901
  if (reselect) this.selection = select;
821
902
  if (reselect || hadIssues) this.notify(false);
822
903
  return;
@@ -839,7 +920,7 @@ var ChartController = (_class = class {
839
920
  }
840
921
  /** A copy of the spec with `edit` applied (series and categories copied as needed). */
841
922
  edited(edit) {
842
- const draft = _chunkR3P2M7HUcjs.cloneChartSpec.call(void 0, this.spec);
923
+ const draft = _chunkUVXTOZ2Bcjs.cloneChartSpec.call(void 0, this.spec);
843
924
  edit(draft);
844
925
  return draft;
845
926
  }
@@ -869,7 +950,7 @@ var ChartController = (_class = class {
869
950
  legend: patch.legend ? { ...s.legend, ...patch.legend } : s.legend,
870
951
  version: 1
871
952
  };
872
- const { spec, issues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, merged);
953
+ const { spec, issues } = _chunkUVXTOZ2Bcjs.normalizeChartSpec.call(void 0, merged);
873
954
  if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
874
955
  if (JSON.stringify(spec) === JSON.stringify(s)) return { ok: true };
875
956
  this.commit(_nullishCoalesce(options.label, () => ( updateLabel(patch))), spec);
@@ -910,7 +991,7 @@ var ChartController = (_class = class {
910
991
  * to the categories; all-or-nothing like `update`.
911
992
  */
912
993
  setData(data, options = {}) {
913
- const clear = (data.categories || data.series) && this.spec.tree.length ? { tree: [] } : {};
994
+ const clear = (data.categories || data.series) && (this.spec.tree.length || this.spec.links.length) ? { tree: [], links: [] } : {};
914
995
  return this.update({ ...data.categories ? { categories: data.categories } : {}, ...data.series ? { series: data.series } : {}, ...clear }, { label: _nullishCoalesce(options.label, () => ( "Edit chart data")) });
915
996
  }
916
997
  /**
@@ -923,7 +1004,7 @@ var ChartController = (_class = class {
923
1004
  const series = this.getSeries(seriesId);
924
1005
  if (!series) return this.unknownSeries(seriesId);
925
1006
  if (!Number.isInteger(index) || index < 0 || index >= this.spec.categories.length) return this.badIndex(index);
926
- const parsed = _chunkR3P2M7HUcjs.parseChartValue.call(void 0, value);
1007
+ const parsed = _chunkUVXTOZ2Bcjs.parseChartValue.call(void 0, value);
927
1008
  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.` }]);
928
1009
  if (series.values[index] === parsed) {
929
1010
  if (this.issues.length) {
@@ -948,7 +1029,7 @@ var ChartController = (_class = class {
948
1029
  if (!this.getSeries(cell.seriesId)) issues.push({ path: cell.seriesId, message: this.unknownSeries(cell.seriesId).message });
949
1030
  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 });
950
1031
  else {
951
- const value = _chunkR3P2M7HUcjs.parseChartValue.call(void 0, cell.value);
1032
+ const value = _chunkUVXTOZ2Bcjs.parseChartValue.call(void 0, cell.value);
952
1033
  if (value === void 0) issues.push({ path: `${cell.seriesId}[${cell.index}]`, message: `"${String(cell.value)}" is not a number.` });
953
1034
  else parsed.push({ seriesId: cell.seriesId, index: cell.index, value });
954
1035
  }
@@ -962,12 +1043,12 @@ var ChartController = (_class = class {
962
1043
  }
963
1044
  /** Adds a series (values padded to the categories) and selects it. Returns its id. */
964
1045
  addSeries(input = {}, options = {}) {
965
- const id = input.id && !this.getSeries(input.id) ? input.id : _chunkR3P2M7HUcjs.uniqueChartSeriesId.call(void 0, this.spec.series);
1046
+ const id = input.id && !this.getSeries(input.id) ? input.id : _chunkUVXTOZ2Bcjs.uniqueChartSeriesId.call(void 0, this.spec.series);
966
1047
  const name = _nullishCoalesce(input.name, () => ( `Series ${this.spec.series.length + 1}`));
967
1048
  const at = Math.max(0, Math.min(this.spec.series.length, _nullishCoalesce(options.at, () => ( this.spec.series.length))));
968
1049
  const series = [...this.spec.series];
969
1050
  series.splice(at, 0, { ...input, id, name, values: _nullishCoalesce(input.values, () => ( [])) });
970
- const { spec, issues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, { ...this.spec, series });
1051
+ const { spec, issues } = _chunkUVXTOZ2Bcjs.normalizeChartSpec.call(void 0, { ...this.spec, series });
971
1052
  if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
972
1053
  this.commit(`Add series "${name}"`, spec, { kind: "series", seriesId: id });
973
1054
  return { ok: true, id };
@@ -987,7 +1068,7 @@ var ChartController = (_class = class {
987
1068
  updateSeries(id, patch) {
988
1069
  const series = this.getSeries(id);
989
1070
  if (!series) return this.unknownSeries(id);
990
- const next = _chunkR3P2M7HUcjs.cloneChartSeries.call(void 0, series);
1071
+ const next = _chunkUVXTOZ2Bcjs.cloneChartSeries.call(void 0, series);
991
1072
  if (patch.name !== void 0) next.name = String(patch.name);
992
1073
  if (patch.color === null || patch.color === "") delete next.color;
993
1074
  else if (patch.color !== void 0) next.color = patch.color;
@@ -1007,7 +1088,7 @@ var ChartController = (_class = class {
1007
1088
  const series2 = this.spec.series.map((s) => s.id === id ? next : s);
1008
1089
  const renamed = next.name !== series.name && this.spec.highlight.includes(series.name) && !this.spec.categories.includes(series.name);
1009
1090
  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 });
1091
+ const { spec, issues } = _chunkUVXTOZ2Bcjs.normalizeChartSpec.call(void 0, { ...this.spec, series: series2, highlight });
1011
1092
  if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1012
1093
  if (JSON.stringify(spec.series) === JSON.stringify(this.spec.series)) return { ok: true };
1013
1094
  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}"`;
@@ -1113,7 +1194,7 @@ var ChartController = (_class = class {
1113
1194
  const width = Math.max(...rows.map((r) => r.length));
1114
1195
  const lastSeries = column + width - 1;
1115
1196
  while (d.series.length <= lastSeries) {
1116
- const id = _chunkR3P2M7HUcjs.uniqueChartSeriesId.call(void 0, d.series);
1197
+ const id = _chunkUVXTOZ2Bcjs.uniqueChartSeriesId.call(void 0, d.series);
1117
1198
  d.series.push({ id, name: `Series ${d.series.length + 1}`, values: d.categories.map(() => null) });
1118
1199
  }
1119
1200
  const lastRow = row + rows.length - 1;
@@ -1127,7 +1208,7 @@ var ChartController = (_class = class {
1127
1208
  const index = row + r;
1128
1209
  if (col < 0) d.categories[index] = cell === null || cell === void 0 ? "" : String(cell).trim();
1129
1210
  else {
1130
- const parsed = _chunkR3P2M7HUcjs.parseChartValue.call(void 0, cell);
1211
+ const parsed = _chunkUVXTOZ2Bcjs.parseChartValue.call(void 0, cell);
1131
1212
  if (parsed === void 0) issues.push({ path: `${d.series[col].id}[${index}]`, message: `"${String(cell)}" is not a number; it was left blank.` });
1132
1213
  d.series[col].values[index] = _nullishCoalesce(parsed, () => ( null));
1133
1214
  }
@@ -1146,14 +1227,14 @@ var ChartController = (_class = class {
1146
1227
  * colours and types are kept by name.
1147
1228
  */
1148
1229
  importTable(rows, options = {}) {
1149
- const data = _chunkR3P2M7HUcjs.chartDataFromTable.call(void 0, rows, options);
1230
+ const data = _chunkUVXTOZ2Bcjs.chartDataFromTable.call(void 0, rows, options);
1150
1231
  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.");
1151
1232
  const byName = new Map(this.spec.series.map((s) => [s.name, s]));
1152
1233
  const series = data.series.map((s) => {
1153
1234
  const old = byName.get(s.name);
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 } : {} };
1235
+ return { ...s, ..._optionalChain([old, 'optionalAccess', _63 => _63.color]) ? { color: old.color } : {}, ..._optionalChain([old, 'optionalAccess', _64 => _64.type]) ? { type: old.type } : {}, ...old ? { id: old.id } : {} };
1155
1236
  });
1156
- const { spec } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, { ...this.spec, categories: data.categories, series, tree: [] });
1237
+ const { spec } = _chunkUVXTOZ2Bcjs.normalizeChartSpec.call(void 0, { ...this.spec, categories: data.categories, series, tree: [], links: [] });
1157
1238
  this.commit("Import data", spec);
1158
1239
  if (data.issues.length) {
1159
1240
  this.issues = data.issues;
@@ -1170,8 +1251,12 @@ var ChartController = (_class = class {
1170
1251
  // -------------------------------------------------------------------------
1171
1252
  // Grouped data (tree)
1172
1253
  // -------------------------------------------------------------------------
1173
- /** A refusal while the data is a tree (cell edits would be overwritten by its totals), else null. */
1254
+ /** A refusal while the data is a tree or flows (cell edits would be overwritten by their totals), else null. */
1174
1255
  treeLocked() {
1256
+ if (this.spec.links.length)
1257
+ return this.reject(
1258
+ "This chart's data is flows (links): its categories are the nodes and its values how much passes through each. Change it with setLinks / the flow edits (set_chart_links, add_chart_link, update_chart_link, remove_chart_link), or replace it with new data."
1259
+ );
1175
1260
  if (!this.spec.tree.length) return null;
1176
1261
  return this.reject(
1177
1262
  "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."
@@ -1180,9 +1265,9 @@ var ChartController = (_class = class {
1180
1265
  /** Replaces the grouped data (an empty list goes back to the table, keeping the totals as values). One undo step. */
1181
1266
  setTree(tree, options = {}) {
1182
1267
  const issues = [];
1183
- const next = _chunkR3P2M7HUcjs.normalizeChartTree.call(void 0, tree, issues);
1268
+ const next = _chunkUVXTOZ2Bcjs.normalizeChartTree.call(void 0, tree, issues);
1184
1269
  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"))) });
1270
+ return this.update({ tree: next, links: [] }, { label: _nullishCoalesce(options.label, () => ( (next.length ? "Replace grouped data" : "Ungroup data"))) });
1186
1271
  }
1187
1272
  /**
1188
1273
  * Replaces the grouped data from rows of names and a value (group, …, item, value), as the
@@ -1190,12 +1275,12 @@ var ChartController = (_class = class {
1190
1275
  */
1191
1276
  setTreeRows(rows, options = {}) {
1192
1277
  const issues = [];
1193
- const next = _chunkR3P2M7HUcjs.chartTreeFromRows.call(void 0, rows, issues);
1278
+ const next = _chunkUVXTOZ2Bcjs.chartTreeFromRows.call(void 0, rows, issues);
1194
1279
  if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1195
1280
  const keepColors = (list, prefix) => {
1196
1281
  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;
1282
+ const old = _chunkUVXTOZ2Bcjs.findChartTreeNode.call(void 0, this.spec.tree, [...prefix, n.name]);
1283
+ if (_optionalChain([old, 'optionalAccess', _65 => _65.color])) n.color = old.color;
1199
1284
  if (n.children) keepColors(n.children, [...prefix, n.name]);
1200
1285
  }
1201
1286
  };
@@ -1205,16 +1290,16 @@ var ChartController = (_class = class {
1205
1290
  /** Replaces the data with a table of names and values (group, …, item, value); see `chartTreeFromTable`. */
1206
1291
  importTreeTable(rows, options = {}) {
1207
1292
  const issues = [];
1208
- const next = _chunkR3P2M7HUcjs.chartTreeFromTable.call(void 0, rows, options, issues);
1293
+ const next = _chunkUVXTOZ2Bcjs.chartTreeFromTable.call(void 0, rows, options, issues);
1209
1294
  if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1210
1295
  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" });
1296
+ return this.update({ tree: next, links: [] }, { label: "Import grouped data" });
1212
1297
  }
1213
1298
  nodeAt(path) {
1214
- const node = _chunkR3P2M7HUcjs.findChartTreeNode.call(void 0, this.spec.tree, path);
1299
+ const node = _chunkUVXTOZ2Bcjs.findChartTreeNode.call(void 0, this.spec.tree, path);
1215
1300
  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), () => ( []));
1301
+ const known = path.length > 1 ? _chunkUVXTOZ2Bcjs.findChartTreeNode.call(void 0, this.spec.tree, path.slice(0, -1)) : null;
1302
+ const siblings = _nullishCoalesce((path.length > 1 ? _optionalChain([known, 'optionalAccess', _66 => _66.children]) : this.spec.tree), () => ( []));
1218
1303
  return fail(
1219
1304
  `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
1305
  );
@@ -1229,12 +1314,12 @@ var ChartController = (_class = class {
1229
1314
  siblings = group.children;
1230
1315
  }
1231
1316
  const issues = [];
1232
- const [node] = _chunkR3P2M7HUcjs.normalizeChartTree.call(void 0, [input], issues, "node");
1317
+ const [node] = _chunkUVXTOZ2Bcjs.normalizeChartTree.call(void 0, [input], issues, "node");
1233
1318
  if (!node || issues.length) return this.reject(issues.map((i) => i.message).join(" ") || "The node is not valid.", issues);
1234
1319
  if (siblings.some((n) => n.name === node.name)) return this.reject(`"${node.name}" is already there; names under one group must be unique.`);
1235
1320
  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;
1321
+ const tree = _chunkUVXTOZ2Bcjs.cloneChartTree.call(void 0, this.spec.tree);
1322
+ const list = parent.length ? _chunkUVXTOZ2Bcjs.findChartTreeNode.call(void 0, tree, parent).children : tree;
1238
1323
  list.splice(at, 0, node);
1239
1324
  const result = this.update({ tree }, { label: `Add "${node.name}"` });
1240
1325
  if (!result.ok) return result;
@@ -1246,16 +1331,16 @@ var ChartController = (_class = class {
1246
1331
  if ("ok" in node) return node;
1247
1332
  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
1333
  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);
1334
+ const siblings = (path.length > 1 ? _chunkUVXTOZ2Bcjs.findChartTreeNode.call(void 0, this.spec.tree, path.slice(0, -1)).children : this.spec.tree).filter((n) => n !== node);
1250
1335
  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);
1336
+ const tree = _chunkUVXTOZ2Bcjs.cloneChartTree.call(void 0, this.spec.tree);
1337
+ const target = _chunkUVXTOZ2Bcjs.findChartTreeNode.call(void 0, tree, path);
1253
1338
  const merged = { ...target, name };
1254
1339
  if (patch.value !== void 0) merged.value = patch.value;
1255
1340
  if (patch.color === null) delete merged.color;
1256
1341
  else if (patch.color !== void 0) merged.color = patch.color;
1257
1342
  const issues = [];
1258
- const [checked] = _chunkR3P2M7HUcjs.normalizeChartTree.call(void 0, [merged], issues, "node");
1343
+ const [checked] = _chunkUVXTOZ2Bcjs.normalizeChartTree.call(void 0, [merged], issues, "node");
1259
1344
  if (!checked || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1260
1345
  Object.assign(target, checked);
1261
1346
  if (patch.color === null) delete target.color;
@@ -1267,8 +1352,8 @@ var ChartController = (_class = class {
1267
1352
  removeTreeNode(path) {
1268
1353
  const node = this.nodeAt(path);
1269
1354
  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;
1355
+ const tree = _chunkUVXTOZ2Bcjs.cloneChartTree.call(void 0, this.spec.tree);
1356
+ const parent = path.length > 1 ? _chunkUVXTOZ2Bcjs.findChartTreeNode.call(void 0, tree, path.slice(0, -1)) : null;
1272
1357
  const list = parent ? parent.children : tree;
1273
1358
  list.splice(
1274
1359
  list.findIndex((n) => n.name === node.name),
@@ -1281,6 +1366,56 @@ var ChartController = (_class = class {
1281
1366
  return this.update({ tree }, { label: `Delete "${node.name}"` });
1282
1367
  }
1283
1368
  // -------------------------------------------------------------------------
1369
+ // Flows (links)
1370
+ // -------------------------------------------------------------------------
1371
+ /**
1372
+ * Replaces the flows (and, when given, the node order). An empty list goes back to the
1373
+ * table, keeping how much passed through each node as values. One undo step, all-or-nothing.
1374
+ */
1375
+ setLinks(links, options = {}) {
1376
+ const issues = [];
1377
+ const next = _chunkUVXTOZ2Bcjs.normalizeChartLinks.call(void 0, links, issues);
1378
+ if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1379
+ const used = new Set(next.flatMap((l) => [l.source, l.target]));
1380
+ const sankeyNodes = options.nodes ? [...options.nodes] : this.spec.sankeyNodes.filter((n) => used.has(n));
1381
+ return this.update({ links: next, tree: [], sankeyNodes }, { label: _nullishCoalesce(options.label, () => ( (next.length ? "Replace flows" : "Remove flows"))) });
1382
+ }
1383
+ /** Replaces the data with flows from a table of source, target and value columns. */
1384
+ importLinksTable(rows, options = {}) {
1385
+ const raw = _chunkUVXTOZ2Bcjs.chartLinksFromTable.call(void 0, rows, options);
1386
+ if (!raw.length) return this.reject('There are no flows to import: expected rows of source, target and value, e.g. "Website,Signup,120".');
1387
+ return this.setLinks(raw, { label: "Import flows" });
1388
+ }
1389
+ badLink(index) {
1390
+ const n = this.spec.links.length;
1391
+ return fail(`There is no flow ${index}; ${n ? `expected 0 to ${n - 1}` : "the chart has none yet"}.`);
1392
+ }
1393
+ /** Adds a flow and returns its index. */
1394
+ addLink(link) {
1395
+ const result = this.setLinks([...this.spec.links, link], { label: `Add flow ${String(_nullishCoalesce(_optionalChain([link, 'optionalAccess', _67 => _67.source]), () => ( "")))} \u2192 ${String(_nullishCoalesce(_optionalChain([link, 'optionalAccess', _68 => _68.target]), () => ( "")))}` });
1396
+ if (!result.ok) return result;
1397
+ return { ok: true, index: this.spec.links.length - 1 };
1398
+ }
1399
+ /** Changes a flow's source, target, value or colour (`color: null` goes back to the default). */
1400
+ updateLink(index, patch) {
1401
+ const current = this.spec.links[index];
1402
+ if (!current) return this.badLink(index);
1403
+ const merged = { ...current, ...patch };
1404
+ if (patch.color === null) delete merged.color;
1405
+ return this.setLinks(
1406
+ this.spec.links.map((l, i) => i === index ? merged : l),
1407
+ { label: "Change flow" }
1408
+ );
1409
+ }
1410
+ removeLink(index) {
1411
+ const current = this.spec.links[index];
1412
+ if (!current) return this.badLink(index);
1413
+ return this.setLinks(
1414
+ this.spec.links.filter((_, i) => i !== index),
1415
+ { label: `Delete flow ${current.source} \u2192 ${current.target}` }
1416
+ );
1417
+ }
1418
+ // -------------------------------------------------------------------------
1284
1419
  // Annotations
1285
1420
  // -------------------------------------------------------------------------
1286
1421
  /** Sets the note written under the chart ("" removes it). */
@@ -1311,7 +1446,7 @@ var ChartController = (_class = class {
1311
1446
  /** Why a reference on `axis` at `values` cannot be drawn on this chart, or null. */
1312
1447
  referenceProblem(axis, values) {
1313
1448
  const s = this.spec;
1314
- const family = _chunkR3P2M7HUcjs.chartFamily.call(void 0, s);
1449
+ const family = _chunkUVXTOZ2Bcjs.chartFamily.call(void 0, s);
1315
1450
  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
1451
  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
1452
  if (axis === "y2" && (family !== "cartesian" || !s.series.some((x) => !x.hidden && x.axis === "secondary")))
@@ -1330,7 +1465,7 @@ var ChartController = (_class = class {
1330
1465
  /** Adds a reference line (a target, floor or average). Returns its index. */
1331
1466
  addReferenceLine(input) {
1332
1467
  const issues = [];
1333
- const line = _chunkR3P2M7HUcjs.normalizeChartReferenceLine.call(void 0, input, "referenceLine", issues);
1468
+ const line = _chunkUVXTOZ2Bcjs.normalizeChartReferenceLine.call(void 0, input, "referenceLine", issues);
1334
1469
  if (!line || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1335
1470
  const problem = this.referenceProblem(line.axis, [line.value]);
1336
1471
  if (problem) return this.reject(problem);
@@ -1345,7 +1480,7 @@ var ChartController = (_class = class {
1345
1480
  const merged = { ...current, ...patch };
1346
1481
  for (const [k, v] of Object.entries(patch)) if (v === null) delete merged[k];
1347
1482
  const issues = [];
1348
- const line = _chunkR3P2M7HUcjs.normalizeChartReferenceLine.call(void 0, merged, "referenceLine", issues);
1483
+ const line = _chunkUVXTOZ2Bcjs.normalizeChartReferenceLine.call(void 0, merged, "referenceLine", issues);
1349
1484
  if (!line || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1350
1485
  const problem = this.referenceProblem(line.axis, [line.value]);
1351
1486
  if (problem) return this.reject(problem);
@@ -1360,7 +1495,7 @@ var ChartController = (_class = class {
1360
1495
  /** Adds a reference band (a target range). Returns its index. */
1361
1496
  addReferenceBand(input) {
1362
1497
  const issues = [];
1363
- const band = _chunkR3P2M7HUcjs.normalizeChartReferenceBand.call(void 0, input, "referenceBand", issues);
1498
+ const band = _chunkUVXTOZ2Bcjs.normalizeChartReferenceBand.call(void 0, input, "referenceBand", issues);
1364
1499
  if (!band || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1365
1500
  const problem = this.referenceProblem(band.axis, [band.from, band.to]);
1366
1501
  if (problem) return this.reject(problem);
@@ -1375,7 +1510,7 @@ var ChartController = (_class = class {
1375
1510
  const merged = { ...current, ...patch };
1376
1511
  for (const [k, v] of Object.entries(patch)) if (v === null) delete merged[k];
1377
1512
  const issues = [];
1378
- const band = _chunkR3P2M7HUcjs.normalizeChartReferenceBand.call(void 0, merged, "referenceBand", issues);
1513
+ const band = _chunkUVXTOZ2Bcjs.normalizeChartReferenceBand.call(void 0, merged, "referenceBand", issues);
1379
1514
  if (!band || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1380
1515
  const problem = this.referenceProblem(band.axis, [band.from, band.to]);
1381
1516
  if (problem) return this.reject(problem);
@@ -1398,7 +1533,7 @@ var ChartController = (_class = class {
1398
1533
  const series = this.getSeries(seriesId);
1399
1534
  if (!series) return this.unknownSeries(seriesId);
1400
1535
  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);
1536
+ const family = _chunkUVXTOZ2Bcjs.chartFamily.call(void 0, this.spec);
1402
1537
  const text = label === null ? "" : String(label).trim();
1403
1538
  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
1539
  if (text && (series.values[index] === null || series.values[index] === void 0))
@@ -1420,12 +1555,12 @@ var ChartController = (_class = class {
1420
1555
  addTrendline(seriesId, input) {
1421
1556
  const series = this.getSeries(seriesId);
1422
1557
  if (!series) return this.unknownSeries(seriesId);
1423
- if (!_chunkSBQVEBSUcjs.chartSupportsTrendlines.call(void 0, this.spec.type, this.spec.stacking))
1558
+ if (!_chunkQO2T6KA5cjs.chartSupportsTrendlines.call(void 0, this.spec.type, this.spec.stacking))
1424
1559
  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.`);
1425
1560
  const issues = [];
1426
- const line = _chunkR3P2M7HUcjs.normalizeChartTrendline.call(void 0, input, "trendline", issues);
1561
+ const line = _chunkUVXTOZ2Bcjs.normalizeChartTrendline.call(void 0, input, "trendline", issues);
1427
1562
  if (!line || issues.length) return this.reject(issues.map((i) => i.message).join(" ") || "The trendline is not valid.", issues);
1428
- const index = _nullishCoalesce(_optionalChain([series, 'access', _53 => _53.trendlines, 'optionalAccess', _54 => _54.length]), () => ( 0));
1563
+ const index = _nullishCoalesce(_optionalChain([series, 'access', _69 => _69.trendlines, 'optionalAccess', _70 => _70.length]), () => ( 0));
1429
1564
  const next = this.edited((d) => {
1430
1565
  const s = d.series.find((x) => x.id === seriesId);
1431
1566
  s.trendlines = [..._nullishCoalesce(s.trendlines, () => ( [])), line];
@@ -1437,12 +1572,12 @@ var ChartController = (_class = class {
1437
1572
  updateTrendline(seriesId, index, patch) {
1438
1573
  const series = this.getSeries(seriesId);
1439
1574
  if (!series) return this.unknownSeries(seriesId);
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"}.`);
1575
+ const current = _optionalChain([series, 'access', _71 => _71.trendlines, 'optionalAccess', _72 => _72[index]]);
1576
+ if (!current) return fail(`"${series.name}" has no trendline ${index}; ${_optionalChain([series, 'access', _73 => _73.trendlines, 'optionalAccess', _74 => _74.length]) ? `expected 0 to ${series.trendlines.length - 1}` : "it has none yet"}.`);
1442
1577
  const issues = [];
1443
1578
  const merged = { ...current, ...patch };
1444
1579
  for (const [k, v] of Object.entries(patch)) if (v === null) delete merged[k];
1445
- const line = _chunkR3P2M7HUcjs.normalizeChartTrendline.call(void 0, merged, "trendline", issues);
1580
+ const line = _chunkUVXTOZ2Bcjs.normalizeChartTrendline.call(void 0, merged, "trendline", issues);
1446
1581
  if (!line || issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1447
1582
  this.commit(
1448
1583
  "Change trendline",
@@ -1455,7 +1590,7 @@ var ChartController = (_class = class {
1455
1590
  removeTrendline(seriesId, index) {
1456
1591
  const series = this.getSeries(seriesId);
1457
1592
  if (!series) return this.unknownSeries(seriesId);
1458
- if (!_optionalChain([series, 'access', _59 => _59.trendlines, 'optionalAccess', _60 => _60[index]])) return fail(`"${series.name}" has no trendline ${index}.`);
1593
+ if (!_optionalChain([series, 'access', _75 => _75.trendlines, 'optionalAccess', _76 => _76[index]])) return fail(`"${series.name}" has no trendline ${index}.`);
1459
1594
  this.commit(
1460
1595
  "Delete trendline",
1461
1596
  this.edited((d) => {
@@ -1470,25 +1605,25 @@ var ChartController = (_class = class {
1470
1605
  trendlinePoints(seriesId) {
1471
1606
  const series = this.getSeries(seriesId);
1472
1607
  if (!series) return [];
1473
- const xy = _chunkR3P2M7HUcjs.chartFamily.call(void 0, this.spec) === "xy";
1608
+ const xy = _chunkUVXTOZ2Bcjs.chartFamily.call(void 0, this.spec) === "xy";
1474
1609
  const out = [];
1475
1610
  series.values.forEach((v, i) => {
1476
- const x = xy ? _nullishCoalesce(_optionalChain([series, 'access', _61 => _61.x, 'optionalAccess', _62 => _62[i]]), () => ( (this.spec.type === "bubble" ? i + 1 : null))) : i + 1;
1611
+ const x = xy ? _nullishCoalesce(_optionalChain([series, 'access', _77 => _77.x, 'optionalAccess', _78 => _78[i]]), () => ( (this.spec.type === "bubble" ? i + 1 : null))) : i + 1;
1477
1612
  if (v !== null && x !== null && Number.isFinite(v) && Number.isFinite(x)) out.push([x, v]);
1478
1613
  });
1479
1614
  return out;
1480
1615
  }
1481
1616
  /** The fitted coefficients, R² and equation of a trendline (null for moving averages or unfittable data). */
1482
1617
  trendlineFit(seriesId, index) {
1483
- const line = _optionalChain([this, 'access', _63 => _63.getSeries, 'call', _64 => _64(seriesId), 'optionalAccess', _65 => _65.trendlines, 'optionalAccess', _66 => _66[index]]);
1618
+ const line = _optionalChain([this, 'access', _79 => _79.getSeries, 'call', _80 => _80(seriesId), 'optionalAccess', _81 => _81.trendlines, 'optionalAccess', _82 => _82[index]]);
1484
1619
  if (!line) return null;
1485
- return _chunkSBQVEBSUcjs.fitChartTrendline.call(void 0, line, this.trendlinePoints(seriesId));
1620
+ return _chunkQO2T6KA5cjs.fitChartTrendline.call(void 0, line, this.trendlinePoints(seriesId));
1486
1621
  }
1487
1622
  /** The moving-average points of a trendline (empty for other kinds). */
1488
1623
  trendlineMovingAverage(seriesId, index) {
1489
- const line = _optionalChain([this, 'access', _67 => _67.getSeries, 'call', _68 => _68(seriesId), 'optionalAccess', _69 => _69.trendlines, 'optionalAccess', _70 => _70[index]]);
1624
+ const line = _optionalChain([this, 'access', _83 => _83.getSeries, 'call', _84 => _84(seriesId), 'optionalAccess', _85 => _85.trendlines, 'optionalAccess', _86 => _86[index]]);
1490
1625
  if (!line || line.type !== "moving-average") return [];
1491
- return _chunkSBQVEBSUcjs.chartMovingAverage.call(void 0, this.trendlinePoints(seriesId), _nullishCoalesce(line.period, () => ( 2)));
1626
+ return _chunkQO2T6KA5cjs.chartMovingAverage.call(void 0, this.trendlinePoints(seriesId), _nullishCoalesce(line.period, () => ( 2)));
1492
1627
  }
1493
1628
  // -------------------------------------------------------------------------
1494
1629
  // Reshaping
@@ -1509,7 +1644,7 @@ var ChartController = (_class = class {
1509
1644
  used.add(id);
1510
1645
  return { id, name, values: s.series.map((x) => _nullishCoalesce(x.values[i], () => ( null))) };
1511
1646
  });
1512
- const { spec } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, { ...s, categories: s.series.map((x) => x.name), series });
1647
+ const { spec } = _chunkUVXTOZ2Bcjs.normalizeChartSpec.call(void 0, { ...s, categories: s.series.map((x) => x.name), series });
1513
1648
  this.commit("Switch rows and columns", spec, null);
1514
1649
  return { ok: true };
1515
1650
  }
@@ -1519,7 +1654,7 @@ var ChartController = (_class = class {
1519
1654
  /** Selects a chart element (view state; not an undo step). */
1520
1655
  select(selection) {
1521
1656
  const next = this.validSelection(selection, this.spec);
1522
- if (_chunkSBQVEBSUcjs.sameChartSelection.call(void 0, next, this.selection) || next === null && this.selection === null) return;
1657
+ if (_chunkQO2T6KA5cjs.sameChartSelection.call(void 0, next, this.selection) || next === null && this.selection === null) return;
1523
1658
  this.selection = next;
1524
1659
  this.notify(false);
1525
1660
  }
@@ -1596,14 +1731,14 @@ var ChartController = (_class = class {
1596
1731
  // -------------------------------------------------------------------------
1597
1732
  /** The spec, for saving (a copy). */
1598
1733
  toJSON() {
1599
- return _chunkR3P2M7HUcjs.cloneChartSpec.call(void 0, this.spec);
1734
+ return _chunkUVXTOZ2Bcjs.cloneChartSpec.call(void 0, this.spec);
1600
1735
  }
1601
1736
  /**
1602
1737
  * Replaces the chart without an undo step (e.g. when opening a document). Problems are
1603
1738
  * fixed with defaults and reported in `state.issues` (and returned).
1604
1739
  */
1605
1740
  load(input, options = {}) {
1606
- const { spec, issues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, input);
1741
+ const { spec, issues } = _chunkUVXTOZ2Bcjs.normalizeChartSpec.call(void 0, input);
1607
1742
  this.spec = spec;
1608
1743
  this.issues = issues;
1609
1744
  this.selection = this.validSelection(this.selection, spec);
@@ -1623,7 +1758,7 @@ var ChartController = (_class = class {
1623
1758
  * nothing changes and every problem is returned (and shown in `state.issues`).
1624
1759
  */
1625
1760
  replace(input, options = {}) {
1626
- const { spec, issues } = _chunkR3P2M7HUcjs.normalizeChartSpec.call(void 0, input);
1761
+ const { spec, issues } = _chunkUVXTOZ2Bcjs.normalizeChartSpec.call(void 0, input);
1627
1762
  if (issues.length) return this.reject(issues.map((i) => i.message).join(" "), issues);
1628
1763
  this.commit(_nullishCoalesce(options.label, () => ( "Replace chart")), spec, this.validSelection(this.selection, spec));
1629
1764
  return { ok: true };
@@ -1638,7 +1773,7 @@ var ChartController = (_class = class {
1638
1773
  }
1639
1774
  /** Stops listening to the history (reconnected by the next `subscribe`). */
1640
1775
  destroy() {
1641
- _optionalChain([this, 'access', _71 => _71.unsubscribeHistory, 'optionalCall', _72 => _72()]);
1776
+ _optionalChain([this, 'access', _87 => _87.unsubscribeHistory, 'optionalCall', _88 => _88()]);
1642
1777
  this.unsubscribeHistory = void 0;
1643
1778
  this.listeners.clear();
1644
1779
  }
@@ -1675,6 +1810,9 @@ function updateLabel(patch) {
1675
1810
  parliamentLabel: "Edit seat caption",
1676
1811
  sunburstLabel: "Edit centre caption",
1677
1812
  tree: "Replace grouped data",
1813
+ links: "Replace flows",
1814
+ sankeyNodes: "Reorder nodes",
1815
+ sankeyLinkColor: "Change flow colours",
1678
1816
  radarTicks: "Change radar rings",
1679
1817
  radarGraticule: "Change radar grid",
1680
1818
  legend: "Change legend",
@@ -1697,7 +1835,7 @@ function layoutSparkline(values, options) {
1697
1835
  const h = Number.isFinite(options.height) ? Math.max(1, options.height) : 1;
1698
1836
  const color = _nullishCoalesce(options.color, () => ( "#4269d0"));
1699
1837
  const negative = _nullishCoalesce(options.negativeColor, () => ( "#e5484d"));
1700
- const theme = { ..._chunkR3P2M7HUcjs.DEFAULT_CHART_THEME, background: "transparent" };
1838
+ const theme = { ..._chunkUVXTOZ2Bcjs.DEFAULT_CHART_THEME, background: "transparent" };
1701
1839
  const marks = [];
1702
1840
  const scene = { width: w, height: h, plot: { x: 0, y: 0, width: w, height: h }, marks, percent: false, theme, warnings: [] };
1703
1841
  const vals = values.slice(0, MAX_POINTS).map((v) => v !== null && Number.isFinite(v) ? Math.max(-1e300, Math.min(1e300, v)) : null);
@@ -1730,7 +1868,7 @@ function layoutSparkline(values, options) {
1730
1868
  const flush = () => {
1731
1869
  if (run.length >= 2) {
1732
1870
  const pts = run.length > 4e3 ? run.filter((_, i) => i % (Math.floor(run.length / 2e3) + 1) === 0) : run;
1733
- d += pts.map(([x, y], i) => `${i ? "L" : "M"}${_chunkSBQVEBSUcjs.r2.call(void 0, x)},${_chunkSBQVEBSUcjs.r2.call(void 0, y)}`).join("");
1871
+ d += pts.map(([x, y], i) => `${i ? "L" : "M"}${_chunkQO2T6KA5cjs.r2.call(void 0, x)},${_chunkQO2T6KA5cjs.r2.call(void 0, y)}`).join("");
1734
1872
  }
1735
1873
  run = [];
1736
1874
  };