@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,10 +1,12 @@
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; }
2
2
 
3
- var _chunkES3UEVUTcjs = require('./chunk-ES3UEVUT.cjs');
3
+ var _chunkEUIDTZNQcjs = require('./chunk-EUIDTZNQ.cjs');
4
4
 
5
5
 
6
+ var _chunkTFF2GTGNcjs = require('./chunk-TFF2GTGN.cjs');
6
7
 
7
- var _chunkS6X2QRVUcjs = require('./chunk-S6X2QRVU.cjs');
8
+
9
+ var _chunk5UEFBM2Mcjs = require('./chunk-5UEFBM2M.cjs');
8
10
 
9
11
  // src/chart/color.ts
10
12
  var NAMED = {
@@ -81,18 +83,18 @@ function chartTextOn(fill, fallback, dark = "#0f172a", light = "#ffffff") {
81
83
  return darkRatio >= lightRatio ? dark : light;
82
84
  }
83
85
  function chartRgbToOklab(rgb) {
84
- const lab = _chunkS6X2QRVUcjs.rgbToOklab.call(void 0, { r: rgb[0], g: rgb[1], b: rgb[2], a: 1 });
86
+ const lab = _chunk5UEFBM2Mcjs.rgbToOklab.call(void 0, { r: rgb[0], g: rgb[1], b: rgb[2], a: 1 });
85
87
  return [lab.l, lab.a, lab.b];
86
88
  }
87
89
  function chartColorDistance(a, b) {
88
- return _chunkS6X2QRVUcjs.deltaEOK.call(void 0,
90
+ return _chunkTFF2GTGNcjs.deltaEOK.call(void 0,
89
91
  { r: a[0], g: a[1], b: a[2], a: 1 },
90
92
  { r: b[0], g: b[1], b: b[2], a: 1 }
91
93
  );
92
94
  }
93
95
  function simulateChartVision(rgb, vision) {
94
96
  if (vision === "normal") return rgb;
95
- const c = _chunkES3UEVUTcjs.simulateColorVision.call(void 0, { r: rgb[0], g: rgb[1], b: rgb[2], a: 1 }, vision);
97
+ const c = _chunkEUIDTZNQcjs.simulateColorVision.call(void 0, { r: rgb[0], g: rgb[1], b: rgb[2], a: 1 }, vision);
96
98
  return [c.r, c.g, c.b];
97
99
  }
98
100
  function checkChartColors(colors, options = {}) {
@@ -223,8 +225,208 @@ function parseChartAmountList(text2) {
223
225
  return text2.split(/[;,\s]+/).filter((t) => t !== "").map((t) => t === "-" ? null : t);
224
226
  }
225
227
 
228
+ // src/chart/tree.ts
229
+ var MAX_CHART_TREE_DEPTH = 6;
230
+ var MAX_CHART_TREE_NODES = 5e3;
231
+ var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
232
+ function normalizeChartTree(value, issues = [], path = "tree") {
233
+ if (value === void 0 || value === null) return [];
234
+ if (!Array.isArray(value)) {
235
+ issues.push({ path, message: `${path} must be an array of nodes such as {"name": "Europe", "children": [{"name": "France", "value": 40}]}.` });
236
+ return [];
237
+ }
238
+ let count = 0;
239
+ const read = (list, at, depth) => {
240
+ const out = [];
241
+ const names = /* @__PURE__ */ new Set();
242
+ list.forEach((raw, i) => {
243
+ const where = `${at}[${i}]`;
244
+ if (!isRecord(raw)) {
245
+ issues.push({ path: where, message: `${where} must be an object with a name and a value or children.` });
246
+ return;
247
+ }
248
+ const name = typeof raw.name === "number" ? String(raw.name) : typeof raw.name === "string" ? raw.name.trim() : "";
249
+ if (!name) {
250
+ issues.push({ path: `${where}.name`, message: `${where} needs a name.` });
251
+ return;
252
+ }
253
+ if (names.has(name)) {
254
+ issues.push({ path: `${where}.name`, message: `"${name}" appears twice under the same group in ${at}; sibling names must be unique, so the second was left out.` });
255
+ return;
256
+ }
257
+ if (++count > MAX_CHART_TREE_NODES) {
258
+ if (count === MAX_CHART_TREE_NODES + 1) issues.push({ path, message: `The tree has more than ${MAX_CHART_TREE_NODES} nodes; the rest were left out.` });
259
+ return;
260
+ }
261
+ names.add(name);
262
+ for (const k of Object.keys(raw)) if (!["name", "value", "children", "color"].includes(k)) issues.push({ path: `${where}.${k}`, message: `${where} has no "${k}"; a node takes name, value, children and color.` });
263
+ const node = { name };
264
+ if (typeof raw.color === "string" && raw.color.trim()) node.color = raw.color.trim();
265
+ if (Array.isArray(raw.children) && raw.children.length) {
266
+ if (depth >= MAX_CHART_TREE_DEPTH) {
267
+ issues.push({ path: `${where}.children`, message: `${where} is more than ${MAX_CHART_TREE_DEPTH} levels deep; its children were left out.` });
268
+ node.value = 0;
269
+ } else {
270
+ if (raw.value !== void 0 && raw.value !== null) issues.push({ path: `${where}.value`, message: `"${name}" is a group: its value is the sum of its children, so the value given was ignored.` });
271
+ const children = read(raw.children, `${where}.children`, depth + 1);
272
+ if (children.length) node.children = children;
273
+ else node.value = 0;
274
+ }
275
+ } else {
276
+ if (raw.children !== void 0 && raw.children !== null && !Array.isArray(raw.children)) issues.push({ path: `${where}.children`, message: `${where}.children must be an array of nodes.` });
277
+ const v = parseChartValue(raw.value);
278
+ if (raw.value === void 0 || raw.value === null) node.value = 0;
279
+ else if (typeof v === "number" && v >= 0) node.value = v;
280
+ else {
281
+ issues.push({ path: `${where}.value`, message: `"${name}" needs a value of 0 or more; got ${JSON.stringify(raw.value)}.` });
282
+ node.value = 0;
283
+ }
284
+ }
285
+ out.push(node);
286
+ });
287
+ return out;
288
+ };
289
+ return read(value, path, 1);
290
+ }
291
+ function chartTreeTotal(node) {
292
+ return node.children ? node.children.reduce((t, c) => t + chartTreeTotal(c), 0) : _nullishCoalesce(node.value, () => ( 0));
293
+ }
294
+ function chartTreeDepth(tree) {
295
+ return tree.reduce((d, n) => Math.max(d, 1 + (n.children ? chartTreeDepth(n.children) : 0)), 0);
296
+ }
297
+ function findChartTreeNode(tree, path) {
298
+ let list = tree;
299
+ let node;
300
+ for (const name of path) {
301
+ node = _optionalChain([list, 'optionalAccess', _10 => _10.find, 'call', _11 => _11((n) => n.name === name)]);
302
+ if (!node) return void 0;
303
+ list = node.children;
304
+ }
305
+ return node;
306
+ }
307
+ function chartTreeToRows(tree) {
308
+ const out = [];
309
+ const walk = (list, prefix) => {
310
+ for (const n of list) {
311
+ if (n.children) walk(n.children, [...prefix, n.name]);
312
+ else out.push({ path: [...prefix, n.name], value: _nullishCoalesce(n.value, () => ( 0)) });
313
+ }
314
+ };
315
+ walk(tree, []);
316
+ return out;
317
+ }
318
+ function chartTreeFromRows(rows, issues = []) {
319
+ const tree = [];
320
+ rows.forEach((row, r) => {
321
+ const path = [];
322
+ for (const cell of row.path) {
323
+ const name = cell === null || cell === void 0 ? "" : String(cell).trim();
324
+ if (!name) break;
325
+ path.push(name);
326
+ }
327
+ if (!path.length) return;
328
+ if (path.length > MAX_CHART_TREE_DEPTH) {
329
+ issues.push({ path: `rows[${r}]`, message: `Row ${r + 1} is ${path.length} levels deep; the tree keeps at most ${MAX_CHART_TREE_DEPTH}, so the row was left out.` });
330
+ return;
331
+ }
332
+ const v = parseChartValue(row.value);
333
+ if (row.value !== null && row.value !== void 0 && String(row.value).trim() !== "" && !(typeof v === "number" && v >= 0)) {
334
+ issues.push({ path: `rows[${r}]`, message: `Row ${r + 1} (${path.join(" / ")}) needs a value of 0 or more; got ${JSON.stringify(row.value)}. It was counted as 0.` });
335
+ }
336
+ const value = typeof v === "number" && v >= 0 ? v : 0;
337
+ let list = tree;
338
+ for (let k = 0; k < path.length; k++) {
339
+ const last = k === path.length - 1;
340
+ let node = list.find((n) => n.name === path[k]);
341
+ if (!node) {
342
+ node = last ? { name: path[k], value } : { name: path[k], children: [] };
343
+ list.push(node);
344
+ if (last) return;
345
+ } else if (last) {
346
+ issues.push({ path: `rows[${r}]`, message: `Row ${r + 1} (${path.join(" / ")}) ${node.children ? "names a group that already has items" : "repeats an earlier row"}; it was left out.` });
347
+ return;
348
+ } else if (!node.children) {
349
+ issues.push({ path: `rows[${r}]`, message: `Row ${r + 1} puts items under "${path.slice(0, k + 1).join(" / ")}", which an earlier row made an item with its own value; it was left out.` });
350
+ return;
351
+ }
352
+ list = node.children;
353
+ }
354
+ });
355
+ return tree;
356
+ }
357
+ function chartTreeFromTable(rows, options = {}, issues = []) {
358
+ const grid = rows.filter((r) => r.some((c) => c !== null && c !== void 0 && String(c).trim() !== ""));
359
+ if (!grid.length) return [];
360
+ const width = Math.max(...grid.map((r) => r.length));
361
+ if (width < 2) {
362
+ issues.push({ path: "rows", message: "A tree table needs at least two columns: names, then values." });
363
+ return [];
364
+ }
365
+ const header = _nullishCoalesce(options.header, () => ( "auto"));
366
+ const skip = header === true || header === "auto" && typeof parseChartValue(grid[0][width - 1]) !== "number";
367
+ const body = skip ? grid.slice(1) : grid;
368
+ let above = [];
369
+ return chartTreeFromRows(
370
+ body.map((r) => {
371
+ const cells = Array.from({ length: width - 1 }, (_, k) => r[k] === null || r[k] === void 0 ? "" : String(r[k]).trim());
372
+ const first = cells.findIndex((c) => c !== "");
373
+ if (first < 0) return { path: [], value: r[width - 1] };
374
+ const own = [];
375
+ for (const c of cells.slice(first)) {
376
+ if (!c) break;
377
+ own.push(c);
378
+ }
379
+ const path = [...above.slice(0, first), ...own];
380
+ above = path;
381
+ return { path, value: r[width - 1] };
382
+ }),
383
+ issues
384
+ );
385
+ }
386
+ function chartTreeFromSeries(categories, values) {
387
+ const seen = /* @__PURE__ */ new Set();
388
+ const out = [];
389
+ categories.forEach((c, i) => {
390
+ const name = c.trim() || `${i + 1}`;
391
+ if (seen.has(name)) return;
392
+ seen.add(name);
393
+ const v = values[i];
394
+ out.push({ name, value: v !== null && v !== void 0 && Number.isFinite(v) && v > 0 ? v : 0 });
395
+ });
396
+ return out;
397
+ }
398
+ function cloneChartTree(tree) {
399
+ return tree.map((n) => ({ ...n, ...n.children ? { children: cloneChartTree(n.children) } : {} }));
400
+ }
401
+ function chartTreeColumnLabels(depth) {
402
+ if (depth <= 1) return ["Item"];
403
+ return Array.from({ length: depth }, (_, k) => k === 0 ? "Group" : k === depth - 1 ? "Item" : `Level ${k + 1}`);
404
+ }
405
+ function setChartTreeRowName(rows, row, level, name) {
406
+ return rows.map((r, i) => {
407
+ if (i !== row) return { path: [...r.path], value: r.value };
408
+ const path = [...r.path];
409
+ while (path.length <= level) path.push("");
410
+ path[level] = name.trim();
411
+ return { path, value: r.value };
412
+ });
413
+ }
414
+ function setChartTreeRowValue(rows, row, value) {
415
+ return rows.map((r, i) => ({ path: [...r.path], value: i === row ? value : r.value }));
416
+ }
417
+ function addChartTreeRow(rows) {
418
+ const parent = rows.length ? rows[rows.length - 1].path.slice(0, -1) : [];
419
+ const taken = new Set(rows.filter((r) => r.path.length === parent.length + 1 && parent.every((p, k) => r.path[k] === p)).map((r) => r.path[parent.length]));
420
+ let n = rows.length + 1;
421
+ while (taken.has(`Item ${n}`)) n++;
422
+ return [...rows.map((r) => ({ path: [...r.path], value: r.value })), { path: [...parent, `Item ${n}`], value: 0 }];
423
+ }
424
+ function removeChartTreeRow(rows, row) {
425
+ return rows.filter((_, i) => i !== row).map((r) => ({ path: [...r.path], value: r.value }));
426
+ }
427
+
226
428
  // src/chart/spec.ts
227
- var CHART_TYPES = ["bar", "line", "area", "scatter", "bubble", "pie", "donut", "radar", "waterfall", "histogram", "box", "funnel", "treemap", "sunburst", "slope", "likert", "parliament"];
429
+ var CHART_TYPES = ["bar", "line", "area", "scatter", "bubble", "pie", "donut", "radar", "waterfall", "histogram", "box", "funnel", "treemap", "sunburst", "sankey", "slope", "likert", "parliament"];
228
430
  var CHART_MARKERS = ["circle", "square", "diamond", "triangle", "cross", "none"];
229
431
  var CHART_TRENDLINE_TYPES = ["linear", "exponential", "logarithmic", "power", "polynomial", "moving-average"];
230
432
  var CHART_LABEL_POSITIONS = ["auto", "inside", "outside", "center"];
@@ -236,6 +438,7 @@ var CHART_CURVES = ["linear", "smooth", "step"];
236
438
  var CHART_RADAR_GRATICULES = ["polygon", "circle"];
237
439
  var CHART_LIKERT_NEUTRALS = ["split", "separate"];
238
440
  var CHART_LIKERT_SORTS = ["none", "positive", "negative"];
441
+ var CHART_SANKEY_LINK_COLORS = ["source", "target", "gray"];
239
442
  var CHART_REFERENCE_AXES = ["y", "y2", "x"];
240
443
  var CHART_ORIENTATIONS = ["vertical", "horizontal"];
241
444
  var CHART_LEGEND_POSITIONS = ["top", "bottom", "left", "right"];
@@ -257,7 +460,8 @@ var CHART_TYPE_LABELS = {
257
460
  slope: "Slope",
258
461
  likert: "Likert",
259
462
  parliament: "Parliament",
260
- sunburst: "Sunburst"
463
+ sunburst: "Sunburst",
464
+ sankey: "Sankey"
261
465
  };
262
466
  var DEFAULT_CHART_PALETTE = ["#4269d0", "#efb118", "#ff725c", "#6cc5b0", "#3ca951", "#ff8ab7", "#a463f2", "#97bbf5", "#9c6b4e", "#9498a0"];
263
467
  var DEFAULT_CHART_THEME = {
@@ -308,6 +512,7 @@ function chartFamily(spec) {
308
512
  case "likert":
309
513
  case "parliament":
310
514
  case "sunburst":
515
+ case "sankey":
311
516
  return spec.type;
312
517
  case "bubble":
313
518
  return "xy";
@@ -316,7 +521,7 @@ function chartFamily(spec) {
316
521
  }
317
522
  }
318
523
  function chartColorsByCategory(type) {
319
- return type === "pie" || type === "donut" || type === "funnel" || type === "treemap" || type === "slope" || type === "parliament" || type === "sunburst";
524
+ return type === "pie" || type === "donut" || type === "funnel" || type === "treemap" || type === "slope" || type === "parliament" || type === "sunburst" || type === "sankey";
320
525
  }
321
526
  function chartSpecColorsByCategory(spec) {
322
527
  return chartColorsByCategory(spec.type) || chartVariesColors(spec);
@@ -329,7 +534,7 @@ function createChartSpec(partial = {}) {
329
534
  }
330
535
  function chartSeriesColor(spec, seriesIndex) {
331
536
  const series = spec.series[seriesIndex];
332
- if (_optionalChain([series, 'optionalAccess', _10 => _10.color])) return series.color;
537
+ if (_optionalChain([series, 'optionalAccess', _12 => _12.color])) return series.color;
333
538
  if (spec.type === "likert") return chartLikertColor(spec.series.length, seriesIndex);
334
539
  return cyclePaletteColor(spec.palette.length ? spec.palette : DEFAULT_CHART_PALETTE, seriesIndex);
335
540
  }
@@ -352,7 +557,7 @@ function chartVariesColors(spec) {
352
557
  return !!spec.varyColors && isCartesianChart(spec.type) && spec.series.filter((s) => !s.hidden).length === 1;
353
558
  }
354
559
  function chartPointColor(spec, seriesIndex, index) {
355
- const own = _optionalChain([spec, 'access', _11 => _11.series, 'access', _12 => _12[seriesIndex], 'optionalAccess', _13 => _13.pointColors, 'optionalAccess', _14 => _14[index]]);
560
+ const own = _optionalChain([spec, 'access', _13 => _13.series, 'access', _14 => _14[seriesIndex], 'optionalAccess', _15 => _15.pointColors, 'optionalAccess', _16 => _16[index]]);
356
561
  if (own) return own;
357
562
  if (spec.type && chartVariesColors(spec)) return chartSliceColor(spec, index);
358
563
  return chartSeriesColor(spec, seriesIndex);
@@ -390,7 +595,7 @@ function parseChartValue(input) {
390
595
  if (negative) value = -value;
391
596
  return Number.isFinite(value) ? value : void 0;
392
597
  }
393
- var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
598
+ var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
394
599
  function pick(value, options, fallback, path, issues) {
395
600
  if (value === void 0) return fallback;
396
601
  if (typeof value === "string" && options.includes(value)) return value;
@@ -419,7 +624,7 @@ function bound(value, path, issues) {
419
624
  }
420
625
  function normalizeFormat(value, path, issues) {
421
626
  if (value === void 0 || value === null) return {};
422
- if (!isRecord(value)) {
627
+ if (!isRecord2(value)) {
423
628
  issues.push({ path, message: `${path} must be an object.` });
424
629
  return {};
425
630
  }
@@ -437,7 +642,7 @@ function normalizeFormat(value, path, issues) {
437
642
  }
438
643
  function normalizeChartAxis(value, fallback, path, issues = []) {
439
644
  if (value === void 0) return { ...fallback, format: { ...fallback.format } };
440
- if (!isRecord(value)) {
645
+ if (!isRecord2(value)) {
441
646
  issues.push({ path, message: `${path} must be an object.` });
442
647
  return { ...fallback, format: { ...fallback.format } };
443
648
  }
@@ -487,7 +692,7 @@ function normalizeChartAxis(value, fallback, path, issues = []) {
487
692
  function normalizeLegend(value, issues) {
488
693
  const fallback = { show: true, position: "bottom" };
489
694
  if (value === void 0) return fallback;
490
- if (!isRecord(value)) {
695
+ if (!isRecord2(value)) {
491
696
  issues.push({ path: "legend", message: "legend must be an object." });
492
697
  return fallback;
493
698
  }
@@ -517,7 +722,7 @@ function normalizeChartValues(value, length, path, issues = []) {
517
722
  }
518
723
  function normalizeSeries(value, length, used, index, issues) {
519
724
  const path = `series[${index}]`;
520
- if (!isRecord(value)) {
725
+ if (!isRecord2(value)) {
521
726
  issues.push({ path, message: `${path} must be an object with a name and values.` });
522
727
  return null;
523
728
  }
@@ -544,7 +749,7 @@ function normalizeSeries(value, length, used, index, issues) {
544
749
  const list = normalizeChartValues(value[key2], length, `${path}.${key2}`, issues);
545
750
  if (list.some((v) => v !== null)) series[key2] = list;
546
751
  }
547
- if (key(value, "sizes") && _optionalChain([series, 'access', _15 => _15.sizes, 'optionalAccess', _16 => _16.some, 'call', _17 => _17((v) => v !== null && v < 0)])) {
752
+ if (key(value, "sizes") && _optionalChain([series, 'access', _17 => _17.sizes, 'optionalAccess', _18 => _18.some, 'call', _19 => _19((v) => v !== null && v < 0)])) {
548
753
  issues.push({ path: `${path}.sizes`, message: `${path}.sizes must not be negative.` });
549
754
  series.sizes = series.sizes.map((v) => v !== null && v < 0 ? null : v);
550
755
  }
@@ -607,7 +812,7 @@ var finiteNumber = (value) => {
607
812
  return typeof n === "number" && Number.isFinite(n) ? n : null;
608
813
  };
609
814
  function normalizeChartReferenceLine(value, path, issues = []) {
610
- if (!isRecord(value)) {
815
+ if (!isRecord2(value)) {
611
816
  issues.push({ path, message: `${path} must be an object with a value, e.g. {"value": 100, "label": "Target"}.` });
612
817
  return null;
613
818
  }
@@ -620,7 +825,7 @@ function normalizeChartReferenceLine(value, path, issues = []) {
620
825
  return { value: at, ...referenceCommon(value, path, issues) };
621
826
  }
622
827
  function normalizeChartReferenceBand(value, path, issues = []) {
623
- if (!isRecord(value)) {
828
+ if (!isRecord2(value)) {
624
829
  issues.push({ path, message: `${path} must be an object with from and to, e.g. {"from": 80, "to": 120, "label": "Target range"}.` });
625
830
  return null;
626
831
  }
@@ -634,7 +839,7 @@ function normalizeChartReferenceBand(value, path, issues = []) {
634
839
  return { from: Math.min(from, to), to: Math.max(from, to), ...referenceCommon(value, path, issues) };
635
840
  }
636
841
  function normalizeChartErrorBars(value, length, path, issues = []) {
637
- if (!isRecord(value)) {
842
+ if (!isRecord2(value)) {
638
843
  issues.push({ path, message: `${path} must be an object with a type (${CHART_ERROR_BAR_TYPES.join(", ")}), or null for none.` });
639
844
  return null;
640
845
  }
@@ -667,7 +872,7 @@ function normalizeChartErrorBars(value, length, path, issues = []) {
667
872
  return issues.length > before ? null : bars;
668
873
  }
669
874
  function normalizeChartTrendline(value, path, issues = []) {
670
- if (!isRecord(value)) {
875
+ if (!isRecord2(value)) {
671
876
  issues.push({ path, message: `${path} must be an object with a type.` });
672
877
  return null;
673
878
  }
@@ -706,8 +911,8 @@ function normalizeChartTrendline(value, path, issues = []) {
706
911
  }
707
912
  function normalizeChartSpec(input) {
708
913
  const issues = [];
709
- const value = isRecord(input) ? input : {};
710
- if (input !== void 0 && !isRecord(input)) issues.push({ path: "", message: "A chart must be an object." });
914
+ const value = isRecord2(input) ? input : {};
915
+ if (input !== void 0 && !isRecord2(input)) issues.push({ path: "", message: "A chart must be an object." });
711
916
  const type = pick(value.type, CHART_TYPES, "bar", "type", issues);
712
917
  const rawSeries = Array.isArray(value.series) ? value.series : [];
713
918
  if (value.series !== void 0 && !Array.isArray(value.series)) issues.push({ path: "series", message: "series must be an array." });
@@ -715,16 +920,21 @@ function normalizeChartSpec(input) {
715
920
  if (Array.isArray(value.categories)) categories = value.categories.map((c, i) => text(c, "", `categories[${i}]`, issues));
716
921
  else {
717
922
  if (value.categories !== void 0) issues.push({ path: "categories", message: "categories must be an array of labels." });
718
- const longest = rawSeries.reduce((n, s) => Math.max(n, isRecord(s) && Array.isArray(s.values) ? s.values.length : 0), 0);
923
+ const longest = rawSeries.reduce((n, s) => Math.max(n, isRecord2(s) && Array.isArray(s.values) ? s.values.length : 0), 0);
719
924
  categories = Array.from({ length: longest }, (_, i) => `${i + 1}`);
720
925
  }
721
926
  const tree = normalizeChartTree(value.tree, issues);
722
- if (tree.length) categories = tree.map((n) => n.name);
927
+ const links = normalizeChartLinks(value.links, issues);
928
+ const sankeyNodes = chartSankeyNodes(links, Array.isArray(value.sankeyNodes) ? value.sankeyNodes.map(String) : [], issues);
929
+ if (value.sankeyNodes !== void 0 && value.sankeyNodes !== null && !Array.isArray(value.sankeyNodes)) issues.push({ path: "sankeyNodes", message: "sankeyNodes must be an array of node names." });
930
+ if (tree.length && links.length) issues.push({ path: "links", message: "A chart holds either grouped data (tree) or flows (links), not both; the flows were used." });
931
+ if (links.length) categories = [...sankeyNodes];
932
+ else if (tree.length) categories = tree.map((n) => n.name);
723
933
  const used = /* @__PURE__ */ new Set();
724
934
  const series = rawSeries.map((s, i) => normalizeSeries(s, categories.length, used, i, issues)).filter((s) => s !== null);
725
- if (tree.length) {
935
+ if (tree.length || links.length) {
726
936
  if (!series.length) series.push({ id: uniqueChartSeriesId(series), name: "Values", values: [] });
727
- series[0] = { ...series[0], values: tree.map(chartTreeTotal) };
937
+ series[0] = { ...series[0], values: links.length ? chartSankeyNodeValues(links, sankeyNodes) : tree.map(chartTreeTotal) };
728
938
  }
729
939
  let palette = [...DEFAULT_CHART_PALETTE];
730
940
  if (Array.isArray(value.palette)) {
@@ -815,8 +1025,11 @@ function normalizeChartSpec(input) {
815
1025
  parliamentArc: fraction("parliamentArc", 180, 90, 360),
816
1026
  parliamentMajority,
817
1027
  parliamentLabel: text(value.parliamentLabel, "", "parliamentLabel", issues),
818
- tree,
819
- sunburstLabel: text(value.sunburstLabel, "", "sunburstLabel", issues)
1028
+ tree: links.length ? [] : tree,
1029
+ sunburstLabel: text(value.sunburstLabel, "", "sunburstLabel", issues),
1030
+ links,
1031
+ sankeyNodes: links.length ? sankeyNodes : [],
1032
+ sankeyLinkColor: pick(value.sankeyLinkColor, CHART_SANKEY_LINK_COLORS, "source", "sankeyLinkColor", issues)
820
1033
  };
821
1034
  if (spec.stacking === "percent")
822
1035
  for (const name of ["yAxis", "yAxis2"]) {
@@ -840,7 +1053,9 @@ function cloneChartSpec(spec) {
840
1053
  highlight: [...spec.highlight],
841
1054
  referenceLines: spec.referenceLines.map((l) => ({ ...l })),
842
1055
  referenceBands: spec.referenceBands.map((b) => ({ ...b })),
843
- tree: cloneChartTree(spec.tree)
1056
+ tree: cloneChartTree(spec.tree),
1057
+ links: spec.links.map((l) => ({ ...l })),
1058
+ sankeyNodes: [...spec.sankeyNodes]
844
1059
  };
845
1060
  }
846
1061
  function cloneChartSeries(series) {
@@ -909,204 +1124,120 @@ function chartColorInputValue(color) {
909
1124
  return "#000000";
910
1125
  }
911
1126
 
912
- // src/chart/tree.ts
913
- var MAX_CHART_TREE_DEPTH = 6;
914
- var MAX_CHART_TREE_NODES = 5e3;
915
- var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
916
- function normalizeChartTree(value, issues = [], path = "tree") {
1127
+ // src/chart/links.ts
1128
+ var MAX_CHART_LINKS = 2e3;
1129
+ var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
1130
+ var nameOf = (value) => typeof value === "number" ? String(value) : typeof value === "string" ? value.trim() : "";
1131
+ function normalizeChartLinks(value, issues = [], path = "links") {
917
1132
  if (value === void 0 || value === null) return [];
918
1133
  if (!Array.isArray(value)) {
919
- issues.push({ path, message: `${path} must be an array of nodes such as {"name": "Europe", "children": [{"name": "France", "value": 40}]}.` });
1134
+ issues.push({ path, message: `${path} must be an array of flows such as {"source": "Website", "target": "Signup", "value": 120}.` });
920
1135
  return [];
921
1136
  }
922
- let count = 0;
923
- const read = (list, at, depth) => {
924
- const out = [];
925
- const names = /* @__PURE__ */ new Set();
926
- list.forEach((raw, i) => {
927
- const where = `${at}[${i}]`;
928
- if (!isRecord2(raw)) {
929
- issues.push({ path: where, message: `${where} must be an object with a name and a value or children.` });
930
- return;
931
- }
932
- const name = typeof raw.name === "number" ? String(raw.name) : typeof raw.name === "string" ? raw.name.trim() : "";
933
- if (!name) {
934
- issues.push({ path: `${where}.name`, message: `${where} needs a name.` });
935
- return;
936
- }
937
- if (names.has(name)) {
938
- issues.push({ path: `${where}.name`, message: `"${name}" appears twice under the same group in ${at}; sibling names must be unique, so the second was left out.` });
939
- return;
940
- }
941
- if (++count > MAX_CHART_TREE_NODES) {
942
- if (count === MAX_CHART_TREE_NODES + 1) issues.push({ path, message: `The tree has more than ${MAX_CHART_TREE_NODES} nodes; the rest were left out.` });
943
- return;
944
- }
945
- names.add(name);
946
- for (const k of Object.keys(raw)) if (!["name", "value", "children", "color"].includes(k)) issues.push({ path: `${where}.${k}`, message: `${where} has no "${k}"; a node takes name, value, children and color.` });
947
- const node = { name };
948
- if (typeof raw.color === "string" && raw.color.trim()) node.color = raw.color.trim();
949
- if (Array.isArray(raw.children) && raw.children.length) {
950
- if (depth >= MAX_CHART_TREE_DEPTH) {
951
- issues.push({ path: `${where}.children`, message: `${where} is more than ${MAX_CHART_TREE_DEPTH} levels deep; its children were left out.` });
952
- node.value = 0;
953
- } else {
954
- if (raw.value !== void 0 && raw.value !== null) issues.push({ path: `${where}.value`, message: `"${name}" is a group: its value is the sum of its children, so the value given was ignored.` });
955
- const children = read(raw.children, `${where}.children`, depth + 1);
956
- if (children.length) node.children = children;
957
- else node.value = 0;
958
- }
959
- } else {
960
- if (raw.children !== void 0 && raw.children !== null && !Array.isArray(raw.children)) issues.push({ path: `${where}.children`, message: `${where}.children must be an array of nodes.` });
961
- const v = parseChartValue(raw.value);
962
- if (raw.value === void 0 || raw.value === null) node.value = 0;
963
- else if (typeof v === "number" && v >= 0) node.value = v;
964
- else {
965
- issues.push({ path: `${where}.value`, message: `"${name}" needs a value of 0 or more; got ${JSON.stringify(raw.value)}.` });
966
- node.value = 0;
967
- }
968
- }
969
- out.push(node);
970
- });
971
- return out;
972
- };
973
- return read(value, path, 1);
974
- }
975
- function chartTreeTotal(node) {
976
- return node.children ? node.children.reduce((t, c) => t + chartTreeTotal(c), 0) : _nullishCoalesce(node.value, () => ( 0));
977
- }
978
- function chartTreeDepth(tree) {
979
- return tree.reduce((d, n) => Math.max(d, 1 + (n.children ? chartTreeDepth(n.children) : 0)), 0);
980
- }
981
- function findChartTreeNode(tree, path) {
982
- let list = tree;
983
- let node;
984
- for (const name of path) {
985
- node = _optionalChain([list, 'optionalAccess', _18 => _18.find, 'call', _19 => _19((n) => n.name === name)]);
986
- if (!node) return void 0;
987
- list = node.children;
988
- }
989
- return node;
990
- }
991
- function chartTreeToRows(tree) {
992
1137
  const out = [];
993
- const walk = (list, prefix) => {
994
- for (const n of list) {
995
- if (n.children) walk(n.children, [...prefix, n.name]);
996
- else out.push({ path: [...prefix, n.name], value: _nullishCoalesce(n.value, () => ( 0)) });
1138
+ const seen = /* @__PURE__ */ new Set();
1139
+ const next = /* @__PURE__ */ new Map();
1140
+ const reaches = (to, from) => {
1141
+ const stack = [to];
1142
+ const visited = /* @__PURE__ */ new Set();
1143
+ while (stack.length) {
1144
+ const n = stack.pop();
1145
+ if (n === from) return true;
1146
+ if (visited.has(n)) continue;
1147
+ visited.add(n);
1148
+ for (const m of _nullishCoalesce(next.get(n), () => ( []))) stack.push(m);
997
1149
  }
1150
+ return false;
998
1151
  };
999
- walk(tree, []);
1000
- return out;
1001
- }
1002
- function chartTreeFromRows(rows, issues = []) {
1003
- const tree = [];
1004
- rows.forEach((row, r) => {
1005
- const path = [];
1006
- for (const cell of row.path) {
1007
- const name = cell === null || cell === void 0 ? "" : String(cell).trim();
1008
- if (!name) break;
1009
- path.push(name);
1152
+ value.forEach((raw, i) => {
1153
+ const where = `${path}[${i}]`;
1154
+ if (out.length >= MAX_CHART_LINKS) {
1155
+ if (out.length === MAX_CHART_LINKS && i === MAX_CHART_LINKS) issues.push({ path, message: `There are more than ${MAX_CHART_LINKS} flows; the rest were left out.` });
1156
+ return;
1010
1157
  }
1011
- if (!path.length) return;
1012
- if (path.length > MAX_CHART_TREE_DEPTH) {
1013
- issues.push({ path: `rows[${r}]`, message: `Row ${r + 1} is ${path.length} levels deep; the tree keeps at most ${MAX_CHART_TREE_DEPTH}, so the row was left out.` });
1158
+ if (!isRecord3(raw)) {
1159
+ issues.push({ path: where, message: `${where} must be an object with source, target and value.` });
1014
1160
  return;
1015
1161
  }
1016
- const v = parseChartValue(row.value);
1017
- if (row.value !== null && row.value !== void 0 && String(row.value).trim() !== "" && !(typeof v === "number" && v >= 0)) {
1018
- issues.push({ path: `rows[${r}]`, message: `Row ${r + 1} (${path.join(" / ")}) needs a value of 0 or more; got ${JSON.stringify(row.value)}. It was counted as 0.` });
1162
+ for (const k of Object.keys(raw)) if (!["source", "target", "value", "color"].includes(k)) issues.push({ path: `${where}.${k}`, message: `${where} has no "${k}"; a flow takes source, target, value and color.` });
1163
+ const source = nameOf(raw.source);
1164
+ const target = nameOf(raw.target);
1165
+ if (!source || !target) {
1166
+ issues.push({ path: where, message: `${where} needs a source and a target (node names).` });
1167
+ return;
1019
1168
  }
1020
- const value = typeof v === "number" && v >= 0 ? v : 0;
1021
- let list = tree;
1022
- for (let k = 0; k < path.length; k++) {
1023
- const last = k === path.length - 1;
1024
- let node = list.find((n) => n.name === path[k]);
1025
- if (!node) {
1026
- node = last ? { name: path[k], value } : { name: path[k], children: [] };
1027
- list.push(node);
1028
- if (last) return;
1029
- } else if (last) {
1030
- issues.push({ path: `rows[${r}]`, message: `Row ${r + 1} (${path.join(" / ")}) ${node.children ? "names a group that already has items" : "repeats an earlier row"}; it was left out.` });
1031
- return;
1032
- } else if (!node.children) {
1033
- issues.push({ path: `rows[${r}]`, message: `Row ${r + 1} puts items under "${path.slice(0, k + 1).join(" / ")}", which an earlier row made an item with its own value; it was left out.` });
1034
- return;
1035
- }
1036
- list = node.children;
1169
+ if (source === target) {
1170
+ issues.push({ path: where, message: `${where} goes from "${source}" to itself; a flow must join two different nodes.` });
1171
+ return;
1172
+ }
1173
+ const v = parseChartValue(raw.value);
1174
+ if (!(typeof v === "number" && v > 0)) {
1175
+ issues.push({ path: `${where}.value`, message: `The flow from "${source}" to "${target}" needs a value above 0; got ${JSON.stringify(raw.value)}.` });
1176
+ return;
1177
+ }
1178
+ const key2 = `${source}\0${target}`;
1179
+ if (seen.has(key2)) {
1180
+ issues.push({ path: where, message: `The flow from "${source}" to "${target}" appears twice; add the values into one flow. The second was left out.` });
1181
+ return;
1182
+ }
1183
+ if (reaches(target, source)) {
1184
+ issues.push({ path: where, message: `The flow from "${source}" to "${target}" would close a loop (${target} already leads back to ${source}); flows must only go forwards, so it was left out.` });
1185
+ return;
1037
1186
  }
1187
+ seen.add(key2);
1188
+ if (!next.has(source)) next.set(source, /* @__PURE__ */ new Set());
1189
+ next.get(source).add(target);
1190
+ const link = { source, target, value: v };
1191
+ if (typeof raw.color === "string" && raw.color.trim()) link.color = raw.color.trim();
1192
+ out.push(link);
1038
1193
  });
1039
- return tree;
1194
+ return out;
1040
1195
  }
1041
- function chartTreeFromTable(rows, options = {}, issues = []) {
1042
- const grid = rows.filter((r) => r.some((c) => c !== null && c !== void 0 && String(c).trim() !== ""));
1043
- if (!grid.length) return [];
1044
- const width = Math.max(...grid.map((r) => r.length));
1045
- if (width < 2) {
1046
- issues.push({ path: "rows", message: "A tree table needs at least two columns: names, then values." });
1047
- return [];
1048
- }
1049
- const header = _nullishCoalesce(options.header, () => ( "auto"));
1050
- const skip = header === true || header === "auto" && typeof parseChartValue(grid[0][width - 1]) !== "number";
1051
- const body = skip ? grid.slice(1) : grid;
1052
- let above = [];
1053
- return chartTreeFromRows(
1054
- body.map((r) => {
1055
- const cells = Array.from({ length: width - 1 }, (_, k) => r[k] === null || r[k] === void 0 ? "" : String(r[k]).trim());
1056
- const first = cells.findIndex((c) => c !== "");
1057
- if (first < 0) return { path: [], value: r[width - 1] };
1058
- const own = [];
1059
- for (const c of cells.slice(first)) {
1060
- if (!c) break;
1061
- own.push(c);
1196
+ function chartSankeyNodes(links, order = [], issues = []) {
1197
+ const used = /* @__PURE__ */ new Set();
1198
+ const named = [];
1199
+ for (const l of links)
1200
+ for (const n of [l.source, l.target])
1201
+ if (!used.has(n)) {
1202
+ used.add(n);
1203
+ named.push(n);
1062
1204
  }
1063
- const path = [...above.slice(0, first), ...own];
1064
- above = path;
1065
- return { path, value: r[width - 1] };
1066
- }),
1067
- issues
1068
- );
1069
- }
1070
- function chartTreeFromSeries(categories, values) {
1071
- const seen = /* @__PURE__ */ new Set();
1072
1205
  const out = [];
1073
- categories.forEach((c, i) => {
1074
- const name = c.trim() || `${i + 1}`;
1075
- if (seen.has(name)) return;
1076
- seen.add(name);
1077
- const v = values[i];
1078
- out.push({ name, value: v !== null && v !== void 0 && Number.isFinite(v) && v > 0 ? v : 0 });
1079
- });
1206
+ for (const n of order) {
1207
+ if (!used.has(n)) {
1208
+ if (links.length) issues.push({ path: "sankeyNodes", message: `sankeyNodes names "${n}", which no flow uses; it was left out.` });
1209
+ continue;
1210
+ }
1211
+ if (!out.includes(n)) out.push(n);
1212
+ }
1213
+ for (const n of named) if (!out.includes(n)) out.push(n);
1080
1214
  return out;
1081
1215
  }
1082
- function cloneChartTree(tree) {
1083
- return tree.map((n) => ({ ...n, ...n.children ? { children: cloneChartTree(n.children) } : {} }));
1084
- }
1085
- function chartTreeColumnLabels(depth) {
1086
- if (depth <= 1) return ["Item"];
1087
- return Array.from({ length: depth }, (_, k) => k === 0 ? "Group" : k === depth - 1 ? "Item" : `Level ${k + 1}`);
1088
- }
1089
- function setChartTreeRowName(rows, row, level, name) {
1090
- return rows.map((r, i) => {
1091
- if (i !== row) return { path: [...r.path], value: r.value };
1092
- const path = [...r.path];
1093
- while (path.length <= level) path.push("");
1094
- path[level] = name.trim();
1095
- return { path, value: r.value };
1096
- });
1216
+ function chartSankeyNodeValues(links, nodes) {
1217
+ const inflow = /* @__PURE__ */ new Map();
1218
+ const outflow = /* @__PURE__ */ new Map();
1219
+ for (const l of links) {
1220
+ outflow.set(l.source, (_nullishCoalesce(outflow.get(l.source), () => ( 0))) + l.value);
1221
+ inflow.set(l.target, (_nullishCoalesce(inflow.get(l.target), () => ( 0))) + l.value);
1222
+ }
1223
+ return nodes.map((n) => Math.max(_nullishCoalesce(inflow.get(n), () => ( 0)), _nullishCoalesce(outflow.get(n), () => ( 0))));
1097
1224
  }
1098
- function setChartTreeRowValue(rows, row, value) {
1099
- return rows.map((r, i) => ({ path: [...r.path], value: i === row ? value : r.value }));
1225
+ function chartLinksFromTable(rows, options = {}) {
1226
+ const grid = rows.filter((r) => r.some((c) => c !== null && c !== void 0 && String(c).trim() !== ""));
1227
+ if (!grid.length) return [];
1228
+ const header = _nullishCoalesce(options.header, () => ( "auto"));
1229
+ const skip = header === true || header === "auto" && typeof parseChartValue(grid[0][2]) !== "number";
1230
+ return (skip ? grid.slice(1) : grid).map((r) => ({ source: r[0], target: r[1], value: r[2] }));
1100
1231
  }
1101
- function addChartTreeRow(rows) {
1102
- const parent = rows.length ? rows[rows.length - 1].path.slice(0, -1) : [];
1103
- const taken = new Set(rows.filter((r) => r.path.length === parent.length + 1 && parent.every((p, k) => r.path[k] === p)).map((r) => r.path[parent.length]));
1104
- let n = rows.length + 1;
1105
- while (taken.has(`Item ${n}`)) n++;
1106
- return [...rows.map((r) => ({ path: [...r.path], value: r.value })), { path: [...parent, `Item ${n}`], value: 0 }];
1232
+ function setChartLinkField(links, index, field, text2) {
1233
+ return links.map((l, i) => i === index ? { ...l, [field]: field === "value" ? text2 : text2.trim() } : { ...l });
1107
1234
  }
1108
- function removeChartTreeRow(rows, row) {
1109
- return rows.filter((_, i) => i !== row).map((r) => ({ path: [...r.path], value: r.value }));
1235
+ function addChartLink(links) {
1236
+ const last = links[links.length - 1];
1237
+ const names = new Set(links.flatMap((l) => [l.source, l.target]));
1238
+ let n = names.size + 1;
1239
+ while (names.has(`Step ${n}`)) n++;
1240
+ return [...links.map((l) => ({ ...l })), { source: _nullishCoalesce(_optionalChain([last, 'optionalAccess', _20 => _20.target]), () => ( "Start")), target: `Step ${n}`, value: _nullishCoalesce(_optionalChain([last, 'optionalAccess', _21 => _21.value]), () => ( 1)) }];
1110
1241
  }
1111
1242
 
1112
1243
 
@@ -1194,4 +1325,12 @@ function removeChartTreeRow(rows, row) {
1194
1325
 
1195
1326
 
1196
1327
 
1197
- exports.parseChartColor = parseChartColor; exports.chartRgbToHex = chartRgbToHex; exports.shadeChartColor = shadeChartColor; exports.CHART_PALETTE_SHADES = CHART_PALETTE_SHADES; exports.cyclePaletteColor = cyclePaletteColor; exports.chartLuminance = chartLuminance; exports.chartContrastRatio = chartContrastRatio; exports.chartTextOn = chartTextOn; exports.chartRgbToOklab = chartRgbToOklab; exports.chartColorDistance = chartColorDistance; exports.simulateChartVision = simulateChartVision; exports.checkChartColors = checkChartColors; exports.CHART_ERROR_BAR_TYPES = CHART_ERROR_BAR_TYPES; exports.CHART_ERROR_BAR_DIRECTIONS = CHART_ERROR_BAR_DIRECTIONS; exports.CHART_ERROR_BAR_LABELS = CHART_ERROR_BAR_LABELS; exports.defaultChartErrorBarValue = defaultChartErrorBarValue; exports.chartErrorAmounts = chartErrorAmounts; exports.describeChartErrorBars = describeChartErrorBars; exports.chartErrorBarsOfType = chartErrorBarsOfType; exports.formatChartAmountList = formatChartAmountList; exports.parseChartAmountList = parseChartAmountList; exports.MAX_CHART_TREE_DEPTH = MAX_CHART_TREE_DEPTH; exports.MAX_CHART_TREE_NODES = MAX_CHART_TREE_NODES; exports.normalizeChartTree = normalizeChartTree; exports.chartTreeTotal = chartTreeTotal; exports.chartTreeDepth = chartTreeDepth; exports.findChartTreeNode = findChartTreeNode; exports.chartTreeToRows = chartTreeToRows; exports.chartTreeFromRows = chartTreeFromRows; exports.chartTreeFromTable = chartTreeFromTable; exports.chartTreeFromSeries = chartTreeFromSeries; exports.cloneChartTree = cloneChartTree; exports.chartTreeColumnLabels = chartTreeColumnLabels; exports.setChartTreeRowName = setChartTreeRowName; exports.setChartTreeRowValue = setChartTreeRowValue; exports.addChartTreeRow = addChartTreeRow; exports.removeChartTreeRow = removeChartTreeRow; exports.CHART_TYPES = CHART_TYPES; exports.CHART_MARKERS = CHART_MARKERS; exports.CHART_TRENDLINE_TYPES = CHART_TRENDLINE_TYPES; exports.CHART_LABEL_POSITIONS = CHART_LABEL_POSITIONS; exports.CHART_AXIS_KINDS = CHART_AXIS_KINDS; exports.CHART_AXIS_SCALES = CHART_AXIS_SCALES; exports.CHART_SERIES_TYPES = CHART_SERIES_TYPES; exports.CHART_STACKINGS = CHART_STACKINGS; exports.CHART_CURVES = CHART_CURVES; exports.CHART_RADAR_GRATICULES = CHART_RADAR_GRATICULES; exports.CHART_LIKERT_NEUTRALS = CHART_LIKERT_NEUTRALS; exports.CHART_LIKERT_SORTS = CHART_LIKERT_SORTS; exports.CHART_REFERENCE_AXES = CHART_REFERENCE_AXES; exports.CHART_ORIENTATIONS = CHART_ORIENTATIONS; exports.CHART_LEGEND_POSITIONS = CHART_LEGEND_POSITIONS; exports.CHART_NUMBER_STYLES = CHART_NUMBER_STYLES; exports.CHART_TYPE_LABELS = CHART_TYPE_LABELS; exports.DEFAULT_CHART_PALETTE = DEFAULT_CHART_PALETTE; exports.DEFAULT_CHART_THEME = DEFAULT_CHART_THEME; exports.CSS_VARIABLE_CHART_THEME = CSS_VARIABLE_CHART_THEME; exports.isCartesianChart = isCartesianChart; exports.isXyChart = isXyChart; exports.chartFamily = chartFamily; exports.chartColorsByCategory = chartColorsByCategory; exports.chartSpecColorsByCategory = chartSpecColorsByCategory; exports.defaultChartAxis = defaultChartAxis; exports.createChartSpec = createChartSpec; exports.chartSeriesColor = chartSeriesColor; exports.chartLikertColor = chartLikertColor; exports.chartSliceColor = chartSliceColor; exports.chartVariesColors = chartVariesColors; exports.chartPointColor = chartPointColor; exports.chartSeriesType = chartSeriesType; exports.uniqueChartSeriesId = uniqueChartSeriesId; exports.parseChartValue = parseChartValue; exports.normalizeChartAxis = normalizeChartAxis; exports.normalizeChartValues = normalizeChartValues; exports.normalizeChartReferenceLine = normalizeChartReferenceLine; exports.normalizeChartReferenceBand = normalizeChartReferenceBand; exports.normalizeChartErrorBars = normalizeChartErrorBars; exports.normalizeChartTrendline = normalizeChartTrendline; exports.normalizeChartSpec = normalizeChartSpec; exports.cloneChartSpec = cloneChartSpec; exports.cloneChartSeries = cloneChartSeries; exports.chartDataFromTable = chartDataFromTable; exports.chartDataToTable = chartDataToTable; exports.chartColorInputValue = chartColorInputValue;
1328
+
1329
+
1330
+
1331
+
1332
+
1333
+
1334
+
1335
+
1336
+ exports.parseChartColor = parseChartColor; exports.chartRgbToHex = chartRgbToHex; exports.shadeChartColor = shadeChartColor; exports.CHART_PALETTE_SHADES = CHART_PALETTE_SHADES; exports.cyclePaletteColor = cyclePaletteColor; exports.chartLuminance = chartLuminance; exports.chartContrastRatio = chartContrastRatio; exports.chartTextOn = chartTextOn; exports.chartRgbToOklab = chartRgbToOklab; exports.chartColorDistance = chartColorDistance; exports.simulateChartVision = simulateChartVision; exports.checkChartColors = checkChartColors; exports.CHART_ERROR_BAR_TYPES = CHART_ERROR_BAR_TYPES; exports.CHART_ERROR_BAR_DIRECTIONS = CHART_ERROR_BAR_DIRECTIONS; exports.CHART_ERROR_BAR_LABELS = CHART_ERROR_BAR_LABELS; exports.defaultChartErrorBarValue = defaultChartErrorBarValue; exports.chartErrorAmounts = chartErrorAmounts; exports.describeChartErrorBars = describeChartErrorBars; exports.chartErrorBarsOfType = chartErrorBarsOfType; exports.formatChartAmountList = formatChartAmountList; exports.parseChartAmountList = parseChartAmountList; exports.MAX_CHART_LINKS = MAX_CHART_LINKS; exports.normalizeChartLinks = normalizeChartLinks; exports.chartSankeyNodes = chartSankeyNodes; exports.chartSankeyNodeValues = chartSankeyNodeValues; exports.chartLinksFromTable = chartLinksFromTable; exports.setChartLinkField = setChartLinkField; exports.addChartLink = addChartLink; exports.MAX_CHART_TREE_DEPTH = MAX_CHART_TREE_DEPTH; exports.MAX_CHART_TREE_NODES = MAX_CHART_TREE_NODES; exports.normalizeChartTree = normalizeChartTree; exports.chartTreeTotal = chartTreeTotal; exports.chartTreeDepth = chartTreeDepth; exports.findChartTreeNode = findChartTreeNode; exports.chartTreeToRows = chartTreeToRows; exports.chartTreeFromRows = chartTreeFromRows; exports.chartTreeFromTable = chartTreeFromTable; exports.chartTreeFromSeries = chartTreeFromSeries; exports.cloneChartTree = cloneChartTree; exports.chartTreeColumnLabels = chartTreeColumnLabels; exports.setChartTreeRowName = setChartTreeRowName; exports.setChartTreeRowValue = setChartTreeRowValue; exports.addChartTreeRow = addChartTreeRow; exports.removeChartTreeRow = removeChartTreeRow; exports.CHART_TYPES = CHART_TYPES; exports.CHART_MARKERS = CHART_MARKERS; exports.CHART_TRENDLINE_TYPES = CHART_TRENDLINE_TYPES; exports.CHART_LABEL_POSITIONS = CHART_LABEL_POSITIONS; exports.CHART_AXIS_KINDS = CHART_AXIS_KINDS; exports.CHART_AXIS_SCALES = CHART_AXIS_SCALES; exports.CHART_SERIES_TYPES = CHART_SERIES_TYPES; exports.CHART_STACKINGS = CHART_STACKINGS; exports.CHART_CURVES = CHART_CURVES; exports.CHART_RADAR_GRATICULES = CHART_RADAR_GRATICULES; exports.CHART_LIKERT_NEUTRALS = CHART_LIKERT_NEUTRALS; exports.CHART_LIKERT_SORTS = CHART_LIKERT_SORTS; exports.CHART_SANKEY_LINK_COLORS = CHART_SANKEY_LINK_COLORS; exports.CHART_REFERENCE_AXES = CHART_REFERENCE_AXES; exports.CHART_ORIENTATIONS = CHART_ORIENTATIONS; exports.CHART_LEGEND_POSITIONS = CHART_LEGEND_POSITIONS; exports.CHART_NUMBER_STYLES = CHART_NUMBER_STYLES; exports.CHART_TYPE_LABELS = CHART_TYPE_LABELS; exports.DEFAULT_CHART_PALETTE = DEFAULT_CHART_PALETTE; exports.DEFAULT_CHART_THEME = DEFAULT_CHART_THEME; exports.CSS_VARIABLE_CHART_THEME = CSS_VARIABLE_CHART_THEME; exports.isCartesianChart = isCartesianChart; exports.isXyChart = isXyChart; exports.chartFamily = chartFamily; exports.chartColorsByCategory = chartColorsByCategory; exports.chartSpecColorsByCategory = chartSpecColorsByCategory; exports.defaultChartAxis = defaultChartAxis; exports.createChartSpec = createChartSpec; exports.chartSeriesColor = chartSeriesColor; exports.chartLikertColor = chartLikertColor; exports.chartSliceColor = chartSliceColor; exports.chartVariesColors = chartVariesColors; exports.chartPointColor = chartPointColor; exports.chartSeriesType = chartSeriesType; exports.uniqueChartSeriesId = uniqueChartSeriesId; exports.parseChartValue = parseChartValue; exports.normalizeChartAxis = normalizeChartAxis; exports.normalizeChartValues = normalizeChartValues; exports.normalizeChartReferenceLine = normalizeChartReferenceLine; exports.normalizeChartReferenceBand = normalizeChartReferenceBand; exports.normalizeChartErrorBars = normalizeChartErrorBars; exports.normalizeChartTrendline = normalizeChartTrendline; exports.normalizeChartSpec = normalizeChartSpec; exports.cloneChartSpec = cloneChartSpec; exports.cloneChartSeries = cloneChartSeries; exports.chartDataFromTable = chartDataFromTable; exports.chartDataToTable = chartDataToTable; exports.chartColorInputValue = chartColorInputValue;