@pixerate/editor 0.48.0 → 0.49.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 (54) hide show
  1. package/dist/agent/index.cjs +24 -22
  2. package/dist/agent/index.cjs.map +1 -1
  3. package/dist/agent/index.js +6 -4
  4. package/dist/agent/index.js.map +1 -1
  5. package/dist/chart/index.cjs +81 -79
  6. package/dist/chart/index.cjs.map +1 -1
  7. package/dist/chart/index.js +52 -50
  8. package/dist/chart/index.js.map +1 -1
  9. package/dist/{chunk-TXXNBDQX.cjs → chunk-2Q46FKZK.cjs} +113 -34
  10. package/dist/chunk-2Q46FKZK.cjs.map +1 -0
  11. package/dist/{chunk-PIMCHMZE.cjs → chunk-3JNRQVTS.cjs} +16 -16
  12. package/dist/{chunk-PIMCHMZE.cjs.map → chunk-3JNRQVTS.cjs.map} +1 -1
  13. package/dist/{chunk-HXUL3LS7.js → chunk-5TWIN7ZJ.js} +2 -2
  14. package/dist/{chunk-VKPEPWKZ.js → chunk-DQPBQXKG.js} +4 -4
  15. package/dist/{chunk-MUCYWI6W.cjs → chunk-FEMIVHN3.cjs} +17 -15
  16. package/dist/chunk-FEMIVHN3.cjs.map +1 -0
  17. package/dist/{chunk-XUUD43OV.js → chunk-GJBIVWB2.js} +2 -2
  18. package/dist/{chunk-PRSJJZBS.cjs → chunk-GTZXF4BI.cjs} +191 -841
  19. package/dist/chunk-GTZXF4BI.cjs.map +1 -0
  20. package/dist/chunk-JOX6MJW4.cjs +674 -0
  21. package/dist/chunk-JOX6MJW4.cjs.map +1 -0
  22. package/dist/{chunk-WXEHCVJQ.cjs → chunk-LNKZPIQD.cjs} +52 -52
  23. package/dist/{chunk-WXEHCVJQ.cjs.map → chunk-LNKZPIQD.cjs.map} +1 -1
  24. package/dist/chunk-OV7UAKIY.js +674 -0
  25. package/dist/chunk-OV7UAKIY.js.map +1 -0
  26. package/dist/{chunk-PKBWLEL7.js → chunk-QFTVLEVN.js} +6 -4
  27. package/dist/{chunk-PKBWLEL7.js.map → chunk-QFTVLEVN.js.map} +1 -1
  28. package/dist/{chunk-KRGXUQ2Y.js → chunk-T6XU4B54.js} +82 -3
  29. package/dist/chunk-T6XU4B54.js.map +1 -0
  30. package/dist/{chunk-U6IZKC7B.cjs → chunk-TGBCBQFV.cjs} +14 -14
  31. package/dist/{chunk-U6IZKC7B.cjs.map → chunk-TGBCBQFV.cjs.map} +1 -1
  32. package/dist/{chunk-LTUM52X6.js → chunk-WBOAXDKD.js} +109 -759
  33. package/dist/chunk-WBOAXDKD.js.map +1 -0
  34. package/dist/export/index.cjs +4 -2
  35. package/dist/export/index.cjs.map +1 -1
  36. package/dist/export/index.d.cts +5 -1
  37. package/dist/export/index.d.ts +5 -1
  38. package/dist/export/index.js +3 -1
  39. package/dist/extensions/index.cjs +6 -5
  40. package/dist/extensions/index.cjs.map +1 -1
  41. package/dist/extensions/index.js +5 -4
  42. package/dist/index.cjs +12 -11
  43. package/dist/index.cjs.map +1 -1
  44. package/dist/index.js +6 -5
  45. package/dist/index.js.map +1 -1
  46. package/package.json +1 -1
  47. package/dist/chunk-KRGXUQ2Y.js.map +0 -1
  48. package/dist/chunk-LTUM52X6.js.map +0 -1
  49. package/dist/chunk-MUCYWI6W.cjs.map +0 -1
  50. package/dist/chunk-PRSJJZBS.cjs.map +0 -1
  51. package/dist/chunk-TXXNBDQX.cjs.map +0 -1
  52. /package/dist/{chunk-HXUL3LS7.js.map → chunk-5TWIN7ZJ.js.map} +0 -0
  53. /package/dist/{chunk-VKPEPWKZ.js.map → chunk-DQPBQXKG.js.map} +0 -0
  54. /package/dist/{chunk-XUUD43OV.js.map → chunk-GJBIVWB2.js.map} +0 -0
@@ -1,3 +1,24 @@
1
+ import {
2
+ CHART_TYPE_LABELS,
3
+ DEFAULT_CHART_PALETTE,
4
+ DEFAULT_CHART_THEME,
5
+ chartColorsByCategory,
6
+ chartDataFromTable,
7
+ chartFamily,
8
+ chartPointColor,
9
+ chartSeriesColor,
10
+ chartSeriesType,
11
+ chartSliceColor,
12
+ checkChartColors,
13
+ cloneChartSeries,
14
+ cloneChartSpec,
15
+ defaultChartAxis,
16
+ normalizeChartSpec,
17
+ normalizeChartTrendline,
18
+ parseChartValue,
19
+ shadeChartColor,
20
+ uniqueChartSeriesId
21
+ } from "./chunk-OV7UAKIY.js";
1
22
  import {
2
23
  NumberFormat
3
24
  } from "./chunk-EKYHKQPG.js";
@@ -9,644 +30,21 @@ import {
9
30
  HistoryManager
10
31
  } from "./chunk-QVZZGT4X.js";
11
32
 
12
- // src/chart/color.ts
13
- var NAMED = {
14
- black: "#000000",
15
- white: "#ffffff",
16
- red: "#ff0000",
17
- green: "#008000",
18
- blue: "#0000ff",
19
- yellow: "#ffff00",
20
- orange: "#ffa500",
21
- purple: "#800080",
22
- gray: "#808080",
23
- grey: "#808080",
24
- teal: "#008080",
25
- navy: "#000080",
26
- maroon: "#800000",
27
- olive: "#808000",
28
- silver: "#c0c0c0",
29
- lime: "#00ff00",
30
- aqua: "#00ffff",
31
- cyan: "#00ffff",
32
- fuchsia: "#ff00ff",
33
- magenta: "#ff00ff",
34
- pink: "#ffc0cb",
35
- brown: "#a52a2a"
36
- };
37
- function parseChartColor(color) {
38
- const text2 = color.trim().toLowerCase();
39
- const hex = NAMED[text2] ?? text2;
40
- let m = /^#([0-9a-f]{3})$/.exec(hex);
41
- if (m) return [...m[1]].map((c) => parseInt(c + c, 16) / 255);
42
- m = /^#([0-9a-f]{6})([0-9a-f]{2})?$/.exec(hex);
43
- if (m) return [0, 2, 4].map((i) => parseInt(m[1].slice(i, i + 2), 16) / 255);
44
- m = /^rgba?\(\s*([\d.]+)%?[\s,]+([\d.]+)%?[\s,]+([\d.]+)%?(?:[\s,/]+[\d.]+%?)?\s*\)$/.exec(text2);
45
- if (m) {
46
- const pct = text2.includes("%");
47
- return [m[1], m[2], m[3]].map((v) => Math.max(0, Math.min(1, Number(v) / (pct ? 100 : 255))));
48
- }
49
- return null;
50
- }
51
- function chartRgbToHex(rgb) {
52
- return `#${rgb.map((c) => Math.round(Math.max(0, Math.min(1, c)) * 255).toString(16).padStart(2, "0")).join("")}`;
53
- }
54
- function shadeChartColor(color, amount) {
55
- const rgb = parseChartColor(color);
56
- if (!rgb || !amount) return color;
57
- const t = Math.max(-1, Math.min(1, amount));
58
- return chartRgbToHex(rgb.map((c) => t > 0 ? c + (1 - c) * t : c * (1 + t)));
59
- }
60
- var CHART_PALETTE_SHADES = [0, 0.4, -0.25, 0.6, -0.5, 0.2];
61
- function cyclePaletteColor(palette, index) {
62
- const base = palette[index % palette.length];
63
- const round2 = Math.floor(index / palette.length) % CHART_PALETTE_SHADES.length;
64
- return shadeChartColor(base, CHART_PALETTE_SHADES[round2]);
65
- }
66
- var toLinear = (c) => c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
67
- var fromLinear = (c) => c <= 31308e-7 ? c * 12.92 : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
68
- function chartLuminance(rgb) {
69
- const [r, g, b] = rgb.map(toLinear);
70
- return 0.2126 * r + 0.7152 * g + 0.0722 * b;
71
- }
72
- function chartContrastRatio(a, b) {
73
- const ra = parseChartColor(a);
74
- const rb = parseChartColor(b);
75
- if (!ra || !rb) return null;
76
- const la = chartLuminance(ra);
77
- const lb = chartLuminance(rb);
78
- return (Math.max(la, lb) + 0.05) / (Math.min(la, lb) + 0.05);
79
- }
80
- function chartTextOn(fill, fallback, dark = "#0f172a", light = "#ffffff") {
81
- const rgb = parseChartColor(fill);
82
- if (!rgb) return fallback;
83
- const darkRatio = chartContrastRatio(fill, dark);
84
- const lightRatio = chartContrastRatio(fill, light);
85
- return darkRatio >= lightRatio ? dark : light;
86
- }
87
- function chartRgbToOklab(rgb) {
88
- const [r, g, b] = rgb.map(toLinear);
89
- const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
90
- const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
91
- const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
92
- return [
93
- 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
94
- 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
95
- 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s
96
- ];
97
- }
98
- function chartColorDistance(a, b) {
99
- const p = chartRgbToOklab(a);
100
- const q = chartRgbToOklab(b);
101
- return Math.hypot(p[0] - q[0], p[1] - q[1], p[2] - q[2]);
102
- }
103
- var CVD = {
104
- protanopia: [
105
- [0.152286, 1.052583, -0.204868],
106
- [0.114503, 0.786281, 0.099216],
107
- [-3882e-6, -0.048116, 1.051998]
108
- ],
109
- deuteranopia: [
110
- [0.367322, 0.860646, -0.227968],
111
- [0.280085, 0.672501, 0.047413],
112
- [-0.01182, 0.04294, 0.968881]
113
- ],
114
- tritanopia: [
115
- [1.255528, -0.076749, -0.178779],
116
- [-0.078411, 0.930809, 0.147602],
117
- [4733e-6, 0.691367, 0.3039]
118
- ]
119
- };
120
- function simulateChartVision(rgb, vision) {
121
- if (vision === "normal") return rgb;
122
- const lin = rgb.map(toLinear);
123
- const m = CVD[vision];
124
- return m.map((row) => fromLinear(Math.max(0, Math.min(1, row[0] * lin[0] + row[1] * lin[1] + row[2] * lin[2]))));
125
- }
126
- function checkChartColors(colors, options = {}) {
127
- const surface = options.surface ?? "#ffffff";
128
- const minDistance = options.minDistance ?? 0.08;
129
- const minContrast = options.minContrast ?? 1.5;
130
- const visions = options.visions ?? ["normal", "protanopia", "deuteranopia", "tritanopia"];
131
- const parsed = colors.map(parseChartColor);
132
- const skipped = colors.filter((_, i) => !parsed[i]);
133
- const issues = [];
134
- const closest = {};
135
- for (const vision of visions) {
136
- const seen = parsed.map((c) => c ? simulateChartVision(c, vision) : null);
137
- let best;
138
- for (let a = 0; a < seen.length; a++) {
139
- for (let b = a + 1; b < seen.length; b++) {
140
- if (!seen[a] || !seen[b]) continue;
141
- const distance = chartColorDistance(seen[a], seen[b]);
142
- if (!best || distance < best.distance) best = { a, b, colors: [colors[a], colors[b]], distance: Math.round(distance * 1e3) / 1e3 };
143
- }
144
- }
145
- if (best) {
146
- closest[vision] = best;
147
- if (best.distance < minDistance) {
148
- const who = vision === "normal" ? "" : ` with ${vision}`;
149
- issues.push(`Colours ${best.a + 1} (${best.colors[0]}) and ${best.b + 1} (${best.colors[1]}) are hard to tell apart${who} (distance ${best.distance}, want at least ${minDistance}).`);
150
- }
151
- }
152
- }
153
- const contrast = colors.map((c) => {
154
- const ratio = chartContrastRatio(c, surface);
155
- return ratio === null ? null : Math.round(ratio * 100) / 100;
156
- });
157
- contrast.forEach((ratio, i) => {
158
- if (ratio !== null && ratio < minContrast) issues.push(`Colour ${i + 1} (${colors[i]}) barely stands out from the background ${surface} (contrast ${ratio}:1, want at least ${minContrast}:1).`);
159
- });
160
- return { ok: issues.length === 0, closest, contrast, issues, skipped };
161
- }
162
-
163
- // src/chart/spec.ts
164
- var CHART_TYPES = ["bar", "line", "area", "scatter", "bubble", "pie", "donut", "radar", "waterfall", "histogram", "box", "funnel", "treemap"];
165
- var CHART_MARKERS = ["circle", "square", "diamond", "triangle", "cross", "none"];
166
- var CHART_TRENDLINE_TYPES = ["linear", "exponential", "logarithmic", "power", "polynomial", "moving-average"];
167
- var CHART_LABEL_POSITIONS = ["auto", "inside", "outside", "center"];
168
- var CHART_AXIS_KINDS = ["category", "date"];
169
- var CHART_SERIES_TYPES = ["bar", "line", "area", "scatter"];
170
- var CHART_STACKINGS = ["none", "stacked", "percent"];
171
- var CHART_CURVES = ["linear", "smooth", "step"];
172
- var CHART_ORIENTATIONS = ["vertical", "horizontal"];
173
- var CHART_LEGEND_POSITIONS = ["top", "bottom", "left", "right"];
174
- var CHART_NUMBER_STYLES = ["number", "percent", "currency", "compact"];
175
- var CHART_TYPE_LABELS = {
176
- bar: "Bar",
177
- line: "Line",
178
- area: "Area",
179
- scatter: "Scatter",
180
- bubble: "Bubble",
181
- pie: "Pie",
182
- donut: "Donut",
183
- radar: "Radar",
184
- waterfall: "Waterfall",
185
- histogram: "Histogram",
186
- box: "Box plot",
187
- funnel: "Funnel",
188
- treemap: "Treemap"
189
- };
190
- var DEFAULT_CHART_PALETTE = ["#4269d0", "#efb118", "#ff725c", "#6cc5b0", "#3ca951", "#ff8ab7", "#a463f2", "#97bbf5", "#9c6b4e", "#9498a0"];
191
- var DEFAULT_CHART_THEME = {
192
- background: "#ffffff",
193
- surface: "#ffffff",
194
- text: "#0f172a",
195
- mutedText: "#64748b",
196
- grid: "#e2e8f0",
197
- axis: "#94a3b8",
198
- selection: "#2563eb",
199
- positive: "#3ca951",
200
- negative: "#e5484d",
201
- fontFamily: 'system-ui, -apple-system, "Segoe UI", sans-serif',
202
- fontSize: 11,
203
- titleSize: 15
204
- };
205
- var CSS_VARIABLE_CHART_THEME = {
206
- ...DEFAULT_CHART_THEME,
207
- background: "transparent",
208
- surface: "var(--background, #ffffff)",
209
- text: "var(--foreground, #0f172a)",
210
- mutedText: "var(--muted-foreground, #64748b)",
211
- grid: "var(--border, #e2e8f0)",
212
- axis: "var(--muted-foreground, #94a3b8)",
213
- selection: "var(--primary, #2563eb)",
214
- fontFamily: "inherit"
215
- };
216
- function isCartesianChart(type) {
217
- return type === "bar" || type === "line" || type === "area" || type === "scatter";
218
- }
219
- function isXyChart(spec) {
220
- if (spec.type === "bubble") return true;
221
- return spec.type === "scatter" && spec.series.some((s) => !s.hidden && Array.isArray(s.x) && s.x.some((v) => v !== null));
222
- }
223
- function chartFamily(spec) {
224
- if (isXyChart(spec)) return "xy";
225
- switch (spec.type) {
226
- case "pie":
227
- case "donut":
228
- return "pie";
229
- case "radar":
230
- case "waterfall":
231
- case "histogram":
232
- case "box":
233
- case "funnel":
234
- case "treemap":
235
- return spec.type;
236
- case "bubble":
237
- return "xy";
238
- default:
239
- return "cartesian";
240
- }
241
- }
242
- function chartColorsByCategory(type) {
243
- return type === "pie" || type === "donut" || type === "funnel" || type === "treemap";
244
- }
245
- function defaultChartAxis(value) {
246
- return { show: true, title: "", min: null, max: null, step: null, gridlines: value, format: {} };
247
- }
248
- function createChartSpec(partial = {}) {
249
- return normalizeChartSpec(partial).spec;
250
- }
251
- function chartSeriesColor(spec, seriesIndex) {
252
- const series = spec.series[seriesIndex];
253
- if (series?.color) return series.color;
254
- return cyclePaletteColor(spec.palette.length ? spec.palette : DEFAULT_CHART_PALETTE, seriesIndex);
255
- }
256
- function chartSliceColor(spec, index) {
257
- return cyclePaletteColor(spec.palette.length ? spec.palette : DEFAULT_CHART_PALETTE, index);
258
- }
259
- function chartPointColor(spec, seriesIndex, index) {
260
- return spec.series[seriesIndex]?.pointColors?.[index] || chartSeriesColor(spec, seriesIndex);
261
- }
262
- function chartSeriesType(spec, series) {
263
- if (series.type) return series.type;
264
- if (spec.type === "bubble") return "scatter";
265
- return isCartesianChart(spec.type) ? spec.type : "bar";
266
- }
267
- function uniqueChartSeriesId(series, base = "series") {
268
- const used = new Set(series.map((s) => s.id));
269
- for (let i = series.length + 1; ; i++) {
270
- const id = `${base}-${i}`;
271
- if (!used.has(id)) return id;
272
- }
273
- }
274
- function parseChartValue(input) {
275
- if (input === null || input === void 0) return null;
276
- if (typeof input === "number") return Number.isFinite(input) ? input : void 0;
277
- if (typeof input !== "string") return void 0;
278
- let text2 = input.trim();
279
- if (!text2 || text2 === "-" || text2 === "\u2014") return null;
280
- let negative = false;
281
- if (/^\(.*\)$/.test(text2)) {
282
- negative = true;
283
- text2 = text2.slice(1, -1).trim();
284
- }
285
- const percent = text2.endsWith("%");
286
- if (percent) text2 = text2.slice(0, -1).trim();
287
- text2 = text2.replace(/^[$€£¥]/, "").replace(/,/g, "").replace(/\s+/g, "");
288
- if (!/^[-+]?(\d+\.?\d*|\.\d+)(e[-+]?\d+)?$/i.test(text2)) return void 0;
289
- let value = Number(text2);
290
- if (percent) value /= 100;
291
- if (negative) value = -value;
292
- return Number.isFinite(value) ? value : void 0;
293
- }
294
- var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
295
- function pick(value, options, fallback, path, issues) {
296
- if (value === void 0) return fallback;
297
- if (typeof value === "string" && options.includes(value)) return value;
298
- issues.push({ path, message: `${path} must be one of ${options.map((o) => `"${o}"`).join(", ")}; got ${JSON.stringify(value)}.` });
299
- return fallback;
300
- }
301
- function text(value, fallback, path, issues) {
302
- if (value === void 0 || value === null) return fallback;
303
- if (typeof value === "string") return value;
304
- if (typeof value === "number" || typeof value === "boolean") return String(value);
305
- issues.push({ path, message: `${path} must be text.` });
306
- return fallback;
307
- }
308
- function flag(value, fallback, path, issues) {
309
- if (value === void 0) return fallback;
310
- if (typeof value === "boolean") return value;
311
- issues.push({ path, message: `${path} must be true or false.` });
312
- return fallback;
313
- }
314
- function bound(value, path, issues) {
315
- if (value === void 0 || value === null || value === "") return null;
316
- const n = typeof value === "string" ? Number(value) : value;
317
- if (typeof n === "number" && Number.isFinite(n)) return n;
318
- issues.push({ path, message: `${path} must be a number or null.` });
319
- return null;
320
- }
321
- function normalizeFormat(value, path, issues) {
322
- if (value === void 0 || value === null) return {};
323
- if (!isRecord(value)) {
324
- issues.push({ path, message: `${path} must be an object.` });
325
- return {};
326
- }
327
- const out = {};
328
- if (value.style !== void 0) out.style = pick(value.style, CHART_NUMBER_STYLES, "number", `${path}.style`, issues);
329
- if (value.decimals !== void 0) {
330
- const d = Number(value.decimals);
331
- if (Number.isInteger(d) && d >= 0 && d <= 10) out.decimals = d;
332
- else issues.push({ path: `${path}.decimals`, message: `${path}.decimals must be a whole number from 0 to 10.` });
333
- }
334
- for (const key2 of ["currency", "prefix", "suffix", "code"]) {
335
- if (value[key2] !== void 0) out[key2] = text(value[key2], "", `${path}.${key2}`, issues);
336
- }
337
- return out;
338
- }
339
- function normalizeChartAxis(value, fallback, path, issues = []) {
340
- if (value === void 0) return { ...fallback, format: { ...fallback.format } };
341
- if (!isRecord(value)) {
342
- issues.push({ path, message: `${path} must be an object.` });
343
- return { ...fallback, format: { ...fallback.format } };
344
- }
345
- let min = "min" in value ? bound(value.min, `${path}.min`, issues) : fallback.min;
346
- let max = "max" in value ? bound(value.max, `${path}.max`, issues) : fallback.max;
347
- if (min !== null && max !== null && min >= max) {
348
- issues.push({ path: `${path}.max`, message: `${path}.max (${max}) must be greater than ${path}.min (${min}).` });
349
- min = fallback.min;
350
- max = fallback.max;
351
- }
352
- let step = "step" in value ? bound(value.step, `${path}.step`, issues) : fallback.step;
353
- if (step !== null && !(step > 0)) {
354
- issues.push({ path: `${path}.step`, message: `${path}.step must be greater than 0 (or null for automatic).` });
355
- step = fallback.step;
356
- }
357
- const axis = {
358
- show: flag(value.show, fallback.show, `${path}.show`, issues),
359
- title: text(value.title, fallback.title, `${path}.title`, issues),
360
- min,
361
- max,
362
- step,
363
- gridlines: flag(value.gridlines, fallback.gridlines, `${path}.gridlines`, issues),
364
- format: "format" in value ? normalizeFormat(value.format, `${path}.format`, issues) : { ...fallback.format }
365
- };
366
- const kind = "kind" in value ? value.kind === null ? void 0 : pick(value.kind, CHART_AXIS_KINDS, "category", `${path}.kind`, issues) : fallback.kind;
367
- if (kind && kind !== "category") axis.kind = kind;
368
- return axis;
369
- }
370
- function normalizeLegend(value, issues) {
371
- const fallback = { show: true, position: "bottom" };
372
- if (value === void 0) return fallback;
373
- if (!isRecord(value)) {
374
- issues.push({ path: "legend", message: "legend must be an object." });
375
- return fallback;
376
- }
377
- return {
378
- show: flag(value.show, fallback.show, "legend.show", issues),
379
- position: pick(value.position, CHART_LEGEND_POSITIONS, fallback.position, "legend.position", issues)
380
- };
381
- }
382
- function normalizeChartValues(value, length, path, issues = []) {
383
- if (value === void 0) return length ? Array(length).fill(null) : [];
384
- if (!Array.isArray(value)) {
385
- issues.push({ path, message: `${path} must be an array of numbers.` });
386
- return length ? Array(length).fill(null) : [];
387
- }
388
- const out = value.map((v, i) => {
389
- const parsed = parseChartValue(v);
390
- if (parsed === void 0) {
391
- issues.push({ path: `${path}[${i}]`, message: `${path}[${i}] is not a number: ${JSON.stringify(v)}.` });
392
- return null;
393
- }
394
- return parsed;
395
- });
396
- if (length === void 0) return out;
397
- if (out.length > length) return out.slice(0, length);
398
- while (out.length < length) out.push(null);
399
- return out;
400
- }
401
- function normalizeSeries(value, length, used, index, issues) {
402
- const path = `series[${index}]`;
403
- if (!isRecord(value)) {
404
- issues.push({ path, message: `${path} must be an object with a name and values.` });
405
- return null;
406
- }
407
- let id = typeof value.id === "string" && value.id.trim() ? value.id.trim() : "";
408
- if (!id || used.has(id)) {
409
- if (id) issues.push({ path: `${path}.id`, message: `Series id "${id}" is used twice; the second was renamed.` });
410
- for (let n = index + 1; ; n++) {
411
- id = `series-${n}`;
412
- if (!used.has(id)) break;
413
- }
414
- }
415
- used.add(id);
416
- const series = {
417
- id,
418
- name: text(value.name, `Series ${index + 1}`, `${path}.name`, issues),
419
- values: normalizeChartValues(value.values, length, `${path}.values`, issues)
420
- };
421
- if (typeof value.color === "string" && value.color.trim()) series.color = value.color.trim();
422
- if (value.type !== void 0 && value.type !== null) series.type = pick(value.type, CHART_SERIES_TYPES, "bar", `${path}.type`, issues);
423
- if (value.hidden === true) series.hidden = true;
424
- if (value.axis !== void 0 && value.axis !== null && pick(value.axis, ["primary", "secondary"], "primary", `${path}.axis`, issues) === "secondary") series.axis = "secondary";
425
- for (const key2 of ["x", "sizes"]) {
426
- if (value[key2] === void 0 || value[key2] === null) continue;
427
- const list = normalizeChartValues(value[key2], length, `${path}.${key2}`, issues);
428
- if (list.some((v) => v !== null)) series[key2] = list;
429
- }
430
- if (key(value, "sizes") && series.sizes?.some((v) => v !== null && v < 0)) {
431
- issues.push({ path: `${path}.sizes`, message: `${path}.sizes must not be negative.` });
432
- series.sizes = series.sizes.map((v) => v !== null && v < 0 ? null : v);
433
- }
434
- if (value.pointColors !== void 0 && value.pointColors !== null) {
435
- if (!Array.isArray(value.pointColors)) issues.push({ path: `${path}.pointColors`, message: `${path}.pointColors must be an array of colours or nulls.` });
436
- else {
437
- const colors = Array.from({ length }, (_, i) => {
438
- const c = value.pointColors[i];
439
- return typeof c === "string" && c.trim() ? c.trim() : null;
440
- });
441
- if (colors.some((c) => c !== null)) series.pointColors = colors;
442
- }
443
- }
444
- if (value.marker !== void 0 && value.marker !== null) series.marker = pick(value.marker, CHART_MARKERS, "circle", `${path}.marker`, issues);
445
- if (value.curve !== void 0 && value.curve !== null) series.curve = pick(value.curve, CHART_CURVES, "linear", `${path}.curve`, issues);
446
- if (value.dataLabels !== void 0 && value.dataLabels !== null) series.dataLabels = flag(value.dataLabels, false, `${path}.dataLabels`, issues);
447
- if (value.format !== void 0 && value.format !== null) {
448
- const format = normalizeFormat(value.format, `${path}.format`, issues);
449
- if (Object.keys(format).length) series.format = format;
450
- }
451
- if (value.trendlines !== void 0 && value.trendlines !== null) {
452
- if (!Array.isArray(value.trendlines)) issues.push({ path: `${path}.trendlines`, message: `${path}.trendlines must be an array.` });
453
- else {
454
- const lines = value.trendlines.map((t, i) => normalizeChartTrendline(t, `${path}.trendlines[${i}]`, issues)).filter((t) => t !== null);
455
- if (lines.length) series.trendlines = lines;
456
- }
457
- }
458
- return series;
459
- }
460
- var key = (value, name) => value[name] !== void 0 && value[name] !== null;
461
- function normalizeChartTrendline(value, path, issues = []) {
462
- if (!isRecord(value)) {
463
- issues.push({ path, message: `${path} must be an object with a type.` });
464
- return null;
465
- }
466
- const type = pick(value.type, CHART_TRENDLINE_TYPES, "linear", `${path}.type`, issues);
467
- const line = { type };
468
- const whole = (name, min, max) => {
469
- if (!key(value, name)) return;
470
- const n = Number(value[name]);
471
- if (Number.isInteger(n) && n >= min && n <= max) line[name] = n;
472
- else issues.push({ path: `${path}.${name}`, message: `${path}.${name} must be a whole number from ${min} to ${max}.` });
473
- };
474
- if (type === "polynomial") whole("order", 2, 6);
475
- if (type === "moving-average") whole("period", 2, 1e3);
476
- for (const name of ["forward", "backward"]) {
477
- if (!key(value, name)) continue;
478
- const n = Number(value[name]);
479
- if (Number.isFinite(n) && n >= 0) {
480
- if (n > 0) line[name] = n;
481
- } else issues.push({ path: `${path}.${name}`, message: `${path}.${name} must be a number of x units, 0 or more.` });
482
- }
483
- if (key(value, "intercept")) {
484
- const n = Number(value.intercept);
485
- if (!Number.isFinite(n)) issues.push({ path: `${path}.intercept`, message: `${path}.intercept must be a number or null.` });
486
- else if (type === "linear" || type === "polynomial" || type === "exponential") {
487
- if (type === "exponential" && n <= 0) issues.push({ path: `${path}.intercept`, message: `${path}.intercept must be greater than 0 for an exponential trendline.` });
488
- else line.intercept = n;
489
- } else issues.push({ path: `${path}.intercept`, message: `A ${type} trendline cannot have a fixed intercept; use linear, polynomial or exponential.` });
490
- }
491
- for (const name of ["showEquation", "showR2"]) if (key(value, name) && flag(value[name], false, `${path}.${name}`, issues)) line[name] = true;
492
- for (const name of ["name", "color"]) {
493
- if (!key(value, name)) continue;
494
- const t = text(value[name], "", `${path}.${name}`, issues).trim();
495
- if (t) line[name] = t;
496
- }
497
- return line;
498
- }
499
- function normalizeChartSpec(input) {
500
- const issues = [];
501
- const value = isRecord(input) ? input : {};
502
- if (input !== void 0 && !isRecord(input)) issues.push({ path: "", message: "A chart must be an object." });
503
- const type = pick(value.type, CHART_TYPES, "bar", "type", issues);
504
- const rawSeries = Array.isArray(value.series) ? value.series : [];
505
- if (value.series !== void 0 && !Array.isArray(value.series)) issues.push({ path: "series", message: "series must be an array." });
506
- let categories;
507
- if (Array.isArray(value.categories)) categories = value.categories.map((c, i) => text(c, "", `categories[${i}]`, issues));
508
- else {
509
- if (value.categories !== void 0) issues.push({ path: "categories", message: "categories must be an array of labels." });
510
- const longest = rawSeries.reduce((n, s) => Math.max(n, isRecord(s) && Array.isArray(s.values) ? s.values.length : 0), 0);
511
- categories = Array.from({ length: longest }, (_, i) => `${i + 1}`);
512
- }
513
- const used = /* @__PURE__ */ new Set();
514
- const series = rawSeries.map((s, i) => normalizeSeries(s, categories.length, used, i, issues)).filter((s) => s !== null);
515
- let palette = [...DEFAULT_CHART_PALETTE];
516
- if (Array.isArray(value.palette)) {
517
- const colors = value.palette.filter((c) => typeof c === "string" && c.trim() !== "");
518
- if (colors.length) palette = colors;
519
- else issues.push({ path: "palette", message: "palette must list at least one colour." });
520
- } else if (value.palette !== void 0) issues.push({ path: "palette", message: "palette must be an array of colours." });
521
- const fraction = (name, fallback, min, max) => {
522
- if (value[name] === void 0) return fallback;
523
- const r = Number(value[name]);
524
- if (value[name] !== null && Number.isFinite(r) && r >= min && r <= max) return r;
525
- issues.push({ path: name, message: `${name} must be a number from ${min} to ${max}.` });
526
- return fallback;
527
- };
528
- const innerRadius = fraction("innerRadius", 0.55, 0, 0.9);
529
- const gapWidth = fraction("gapWidth", 0.28, 0, 0.9);
530
- const overlap = fraction("overlap", -0.12, -1, 1);
531
- let bins = null;
532
- if (value.bins !== void 0 && value.bins !== null) {
533
- const b = Number(value.bins);
534
- if (Number.isInteger(b) && b >= 1 && b <= 500) bins = b;
535
- else issues.push({ path: "bins", message: "bins must be a whole number from 1 to 500, or null for automatic." });
536
- }
537
- const spec = {
538
- version: 1,
539
- type,
540
- title: text(value.title, "", "title", issues),
541
- subtitle: text(value.subtitle, "", "subtitle", issues),
542
- categories,
543
- series,
544
- xAxis: normalizeChartAxis(value.xAxis, defaultChartAxis(false), "xAxis", issues),
545
- yAxis: normalizeChartAxis(value.yAxis, defaultChartAxis(true), "yAxis", issues),
546
- yAxis2: normalizeChartAxis(value.yAxis2, defaultChartAxis(false), "yAxis2", issues),
547
- legend: normalizeLegend(value.legend, issues),
548
- stacking: pick(value.stacking, CHART_STACKINGS, "none", "stacking", issues),
549
- orientation: pick(value.orientation, CHART_ORIENTATIONS, "vertical", "orientation", issues),
550
- curve: pick(value.curve, CHART_CURVES, "linear", "curve", issues),
551
- points: flag(value.points, true, "points", issues),
552
- dataLabels: flag(value.dataLabels, false, "dataLabels", issues),
553
- labelPosition: pick(value.labelPosition, CHART_LABEL_POSITIONS, "auto", "labelPosition", issues),
554
- palette,
555
- innerRadius,
556
- gapWidth,
557
- overlap,
558
- bins,
559
- showTotal: flag(value.showTotal, true, "showTotal", issues)
560
- };
561
- return { spec, issues };
562
- }
563
- function cloneChartSpec(spec) {
564
- return {
565
- ...spec,
566
- categories: [...spec.categories],
567
- series: spec.series.map(cloneChartSeries),
568
- xAxis: { ...spec.xAxis, format: { ...spec.xAxis.format } },
569
- yAxis: { ...spec.yAxis, format: { ...spec.yAxis.format } },
570
- yAxis2: { ...spec.yAxis2, format: { ...spec.yAxis2.format } },
571
- legend: { ...spec.legend },
572
- palette: [...spec.palette]
573
- };
574
- }
575
- function cloneChartSeries(series) {
576
- const copy = { ...series, values: [...series.values] };
577
- if (series.x) copy.x = [...series.x];
578
- if (series.sizes) copy.sizes = [...series.sizes];
579
- if (series.pointColors) copy.pointColors = [...series.pointColors];
580
- if (series.format) copy.format = { ...series.format };
581
- if (series.trendlines) copy.trendlines = series.trendlines.map((t) => ({ ...t }));
582
- return copy;
583
- }
584
- function chartDataFromTable(rows, options = {}) {
585
- let grid = rows.map((r) => [...r]).filter((r) => r.some((c) => c !== null && c !== void 0 && String(c).trim() !== ""));
586
- if (options.seriesIn === "rows") {
587
- const width2 = Math.max(0, ...grid.map((r) => r.length));
588
- grid = Array.from({ length: width2 }, (_, c) => grid.map((r) => r[c]));
589
- }
590
- const issues = [];
591
- if (!grid.length) return { categories: [], series: [], issues };
592
- const width = Math.max(...grid.map((r) => r.length));
593
- const header = options.header === "auto" ? grid[0].slice(1).some((c) => c !== null && c !== void 0 && String(c).trim() !== "" && parseChartValue(c) === void 0) : options.header ?? true;
594
- const names = header ? grid[0] : [];
595
- const body = header ? grid.slice(1) : grid;
596
- const categories = body.map((r, i) => {
597
- const c = r[0];
598
- return c === null || c === void 0 || String(c).trim() === "" ? `${i + 1}` : String(c).trim();
599
- });
600
- const series = [];
601
- for (let col = 1; col < width; col++) {
602
- const name = names[col] !== void 0 && String(names[col]).trim() ? String(names[col]).trim() : `Series ${col}`;
603
- const values = body.map((r, i) => {
604
- const parsed = parseChartValue(r[col] ?? null);
605
- if (parsed === void 0) {
606
- issues.push({ path: `${name}[${i}]`, message: `"${String(r[col])}" in ${name} (${categories[i]}) is not a number; it was left blank.` });
607
- return null;
608
- }
609
- return parsed;
610
- });
611
- series.push({ id: `series-${col}`, name, values });
612
- }
613
- if (options.xFromFirstColumn) {
614
- const x = body.map((r, i) => {
615
- const parsed = parseChartValue(r[0] ?? null);
616
- if (parsed === void 0) issues.push({ path: `x[${i}]`, message: `"${String(r[0])}" in the first column is not a number; that point has no x.` });
617
- return parsed ?? null;
618
- });
619
- for (const s of series) s.x = [...x];
620
- }
621
- return { categories, series, issues };
622
- }
623
- function chartDataToTable(spec, options = {}) {
624
- return [
625
- [options.categoryHeader ?? "", ...spec.series.map((s) => s.name)],
626
- ...spec.categories.map((category, i) => [category, ...spec.series.map((s) => s.values[i] ?? null)])
627
- ];
628
- }
629
- function chartColorInputValue(color) {
630
- if (/^#[0-9a-f]{6}$/i.test(color)) return color.toLowerCase();
631
- if (/^#[0-9a-f]{3}$/i.test(color)) return `#${[...color.slice(1)].map((c) => c + c).join("")}`.toLowerCase();
632
- return "#000000";
633
- }
634
-
635
33
  // src/chart/mermaid.ts
636
34
  var CHART_MERMAID_META_PREFIX = "%% @pixerate ";
637
- var quote = (text2) => `"${text2.replace(/"/g, "#quot;")}"`;
638
- var unquote = (text2) => {
639
- const t = text2.trim();
35
+ var quote = (text) => `"${text.replace(/"/g, "#quot;")}"`;
36
+ var unquote = (text) => {
37
+ const t = text.trim();
640
38
  return (t.length >= 2 && t.startsWith('"') && t.endsWith('"') ? t.slice(1, -1) : t).replace(/#quot;/g, '"');
641
39
  };
642
- var word = (text2) => /^[A-Za-z0-9_]+$/.test(text2) ? text2 : quote(text2);
40
+ var word = (text) => /^[A-Za-z0-9_]+$/.test(text) ? text : quote(text);
643
41
  var num = (value) => Number.isInteger(value) ? String(value) : String(Number(value.toPrecision(10)));
644
- function splitOutside(text2, sep) {
42
+ function splitOutside(text, sep) {
645
43
  const out = [];
646
44
  let cur = "";
647
45
  let quoted = false;
648
46
  let depth = 0;
649
- for (const ch of text2) {
47
+ for (const ch of text) {
650
48
  if (ch === '"') quoted = !quoted;
651
49
  else if (!quoted && (ch === "[" || ch === "{")) depth++;
652
50
  else if (!quoted && (ch === "]" || ch === "}")) depth--;
@@ -672,13 +70,13 @@ function slug(label, i, taken) {
672
70
  taken.add(id);
673
71
  return id;
674
72
  }
675
- function metaFor(spec, text2) {
676
- const base = chartFromMermaid(text2, { ignoreMeta: true }).spec;
73
+ function metaFor(spec, text) {
74
+ const base = chartFromMermaid(text, { ignoreMeta: true }).spec;
677
75
  const meta = {};
678
76
  const same = (a, b) => JSON.stringify(a) === JSON.stringify(b);
679
- for (const key2 of Object.keys(spec)) {
680
- if (key2 === "series" || key2 === "version") continue;
681
- if (!same(spec[key2], base[key2])) meta[key2] = spec[key2];
77
+ for (const key of Object.keys(spec)) {
78
+ if (key === "series" || key === "version") continue;
79
+ if (!same(spec[key], base[key])) meta[key] = spec[key];
682
80
  }
683
81
  const series = spec.series.map((s, i) => {
684
82
  const b = base.series[i];
@@ -745,21 +143,21 @@ function chartToMermaid(spec, options = {}) {
745
143
  lines.push(`${ind}${kind} ${quote(s.name)} [${s.values.map(v).join(", ")}]`);
746
144
  }
747
145
  }
748
- let text2 = `${lines.join("\n")}
146
+ let text = `${lines.join("\n")}
749
147
  `;
750
148
  if (options.meta !== false) {
751
- const meta = metaFor(spec, text2);
149
+ const meta = metaFor(spec, text);
752
150
  if (meta) {
753
151
  const [header, ...rest] = lines;
754
- text2 = `${[header, `${CHART_MERMAID_META_PREFIX}${JSON.stringify({ v: 1, ...meta })}`, ...rest].join("\n")}
152
+ text = `${[header, `${CHART_MERMAID_META_PREFIX}${JSON.stringify({ v: 1, ...meta })}`, ...rest].join("\n")}
755
153
  `;
756
154
  }
757
155
  }
758
- return text2;
156
+ return text;
759
157
  }
760
158
  var RANGE = /^(-?\d+(?:\.\d+)?)\s*-->\s*(-?\d+(?:\.\d+)?)$/;
761
- function takeTitle(text2) {
762
- const t = text2.trim();
159
+ function takeTitle(text) {
160
+ const t = text.trim();
763
161
  if (t.startsWith('"')) {
764
162
  const end = t.indexOf('"', 1);
765
163
  if (end > 0) return { title: unquote(t.slice(0, end + 1)), rest: t.slice(end + 1).trim() };
@@ -768,8 +166,8 @@ function takeTitle(text2) {
768
166
  const m = /^(\S+)\s*(.*)$/.exec(t);
769
167
  return { title: m[1], rest: m[2].trim() };
770
168
  }
771
- function parseList(text2, partial) {
772
- const t = text2.trim();
169
+ function parseList(text, partial) {
170
+ const t = text.trim();
773
171
  let m = /^\[(.*)\]$/s.exec(t);
774
172
  if (!m && partial) m = /^\[(.*)$/s.exec(t);
775
173
  if (!m) return void 0;
@@ -781,10 +179,10 @@ function parseList(text2, partial) {
781
179
  }
782
180
  return items.map(unquote);
783
181
  }
784
- function chartFromMermaid(text2, options = {}) {
182
+ function chartFromMermaid(text, options = {}) {
785
183
  const issues = [];
786
184
  const partial = !!options.partial;
787
- const all = text2.replace(/^/, "").split(/\r?\n/);
185
+ const all = text.replace(/^/, "").split(/\r?\n/);
788
186
  let start = 0;
789
187
  let frontTitle;
790
188
  if (all[0]?.trim() === "---") {
@@ -978,8 +376,8 @@ function chartFromMermaid(text2, options = {}) {
978
376
  if (!family && !partial && !issues.length) issues.push({ path: "header", message: "The text is empty: expected a chart header (xychart-beta, pie or radar-beta)." });
979
377
  return { spec, issues: [...issues, ...specIssues], family, hasMeta: !!meta };
980
378
  }
981
- function findMermaidCharts(text2) {
982
- const lines = text2.replace(/^/, "").split(/\r?\n/);
379
+ function findMermaidCharts(text) {
380
+ const lines = text.replace(/^/, "").split(/\r?\n/);
983
381
  const found = [];
984
382
  const familyOf = (body) => {
985
383
  const header = body.split(/\r?\n/).find((l) => l.trim() && !l.trim().startsWith("%%") && l.trim() !== "---");
@@ -1005,8 +403,8 @@ function findMermaidCharts(text2) {
1005
403
  i = end;
1006
404
  }
1007
405
  if (!found.length) {
1008
- const family = familyOf(text2);
1009
- if (family) found.push({ source: `${text2.trim()}
406
+ const family = familyOf(text);
407
+ if (family) found.push({ source: `${text.trim()}
1010
408
  `, family, line: 1 });
1011
409
  }
1012
410
  return found;
@@ -1015,20 +413,20 @@ function findMermaidCharts(text2) {
1015
413
  // src/chart/date.ts
1016
414
  var MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
1017
415
  function parseChartDate(label) {
1018
- const text2 = label.trim();
1019
- let m = /^(\d{4})$/.exec(text2);
416
+ const text = label.trim();
417
+ let m = /^(\d{4})$/.exec(text);
1020
418
  if (m) return Date.UTC(Number(m[1]), 0, 1);
1021
- m = /^(\d{4})[-/](\d{1,2})$/.exec(text2);
419
+ m = /^(\d{4})[-/](\d{1,2})$/.exec(text);
1022
420
  if (m) return valid(Number(m[1]), Number(m[2]) - 1, 1);
1023
- m = /^(\d{4})[-/](\d{1,2})[-/](\d{1,2})(?:[T ](\d{1,2}):(\d{2})(?::(\d{2}))?(?:\.\d+)?(Z|[+-]\d{2}:?\d{2})?)?$/.exec(text2);
421
+ m = /^(\d{4})[-/](\d{1,2})[-/](\d{1,2})(?:[T ](\d{1,2}):(\d{2})(?::(\d{2}))?(?:\.\d+)?(Z|[+-]\d{2}:?\d{2})?)?$/.exec(text);
1024
422
  if (m) {
1025
423
  if (m[4] !== void 0) {
1026
- const t = Date.parse(text2.replace(" ", "T").replace(/\//g, "-") + (m[7] ? "" : "Z"));
424
+ const t = Date.parse(text.replace(" ", "T").replace(/\//g, "-") + (m[7] ? "" : "Z"));
1027
425
  return Number.isFinite(t) ? t : null;
1028
426
  }
1029
427
  return valid(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
1030
428
  }
1031
- m = /^(?:(\d{1,2})\s+)?([A-Za-z]{3})[a-z]*\.?,?\s+(\d{4})$/.exec(text2);
429
+ m = /^(?:(\d{1,2})\s+)?([A-Za-z]{3})[a-z]*\.?,?\s+(\d{4})$/.exec(text);
1032
430
  if (m) {
1033
431
  const month = MONTHS.findIndex((x) => x.toLowerCase() === m[2].toLowerCase());
1034
432
  if (month >= 0) return valid(Number(m[3]), month, m[1] ? Number(m[1]) : 1);
@@ -1243,7 +641,7 @@ function linearMap(value, domain, range) {
1243
641
  }
1244
642
 
1245
643
  // src/chart/layout-shared.ts
1246
- var estimateChartTextWidth = (text2, size, weight = 400) => text2.length * size * (weight >= 600 ? 0.6 : 0.56);
644
+ var estimateChartTextWidth = (text, size, weight = 400) => text.length * size * (weight >= 600 ? 0.6 : 0.56);
1247
645
  function sameChartSelection(a, b) {
1248
646
  if (!a || !b || a.kind !== b.kind) return false;
1249
647
  switch (a.kind) {
@@ -1326,9 +724,9 @@ function arcPath(cx, cy, outer, inner, start, end) {
1326
724
  else d += `L${r2(cx)},${r2(cy)}Z`;
1327
725
  return d;
1328
726
  }
1329
- function truncate(text2, maxWidth, size, measure) {
1330
- if (measure(text2, size) <= maxWidth) return text2;
1331
- let out = text2;
727
+ function truncate(text, maxWidth, size, measure) {
728
+ if (measure(text, size) <= maxWidth) return text;
729
+ let out = text;
1332
730
  while (out.length > 1 && measure(`${out}\u2026`, size) > maxWidth) out = out.slice(0, -1);
1333
731
  return `${out}\u2026`;
1334
732
  }
@@ -1841,11 +1239,11 @@ function categoryFrame(ctx, area, input) {
1841
1239
  const band = catLen / n;
1842
1240
  const catCenter = (i) => catStart + band * (i + 0.5);
1843
1241
  const map = (p) => horizontal ? [p.v, p.c] : [p.c, p.v];
1844
- const gridAt = (info, key2) => info.scale.ticks.forEach((t, i) => {
1242
+ const gridAt = (info, key) => info.scale.ticks.forEach((t, i) => {
1845
1243
  const p = info.px(t);
1846
1244
  const [x1, y1] = map({ c: catStart, v: p });
1847
1245
  const [x2, y2] = map({ c: catStart + catLen, v: p });
1848
- marks.push({ kind: "line", key: `grid-${key2}-${i}`, role: "grid", x1, y1, x2, y2, stroke: theme.grid, strokeWidth: 1 });
1246
+ marks.push({ kind: "line", key: `grid-${key}-${i}`, role: "grid", x1, y1, x2, y2, stroke: theme.grid, strokeWidth: 1 });
1849
1247
  });
1850
1248
  if (primary.axis.gridlines) gridAt(value, "y");
1851
1249
  if (value2 && secondary.axis.gridlines) gridAt(value2, "y2");
@@ -1863,12 +1261,12 @@ function categoryFrame(ctx, area, input) {
1863
1261
  info.scale.ticks.forEach((t, i) => {
1864
1262
  const p = info.px(t);
1865
1263
  const label = info.tickText(t);
1866
- const key2 = `tick-${v.key}-${i}`;
1264
+ const key = `tick-${v.key}-${i}`;
1867
1265
  if (horizontal) {
1868
- if (far) marks.push({ kind: "text", key: key2, role: "tick-label", x: p, y: plot.y - 6, text: label, anchor: "middle", baseline: "bottom", size: fs, fill: theme.mutedText, target });
1869
- else marks.push({ kind: "text", key: key2, role: "tick-label", x: p, y: plot.y + plot.height + 6, text: label, anchor: "middle", baseline: "top", size: fs, fill: theme.mutedText, target });
1870
- } else if (far) marks.push({ kind: "text", key: key2, role: "tick-label", x: plot.x + plot.width + 8, y: p, text: label, anchor: "start", baseline: "middle", size: fs, fill: theme.mutedText, target });
1871
- else marks.push({ kind: "text", key: key2, role: "tick-label", x: plot.x - 8, y: p, text: label, anchor: "end", baseline: "middle", size: fs, fill: theme.mutedText, target });
1266
+ if (far) marks.push({ kind: "text", key, role: "tick-label", x: p, y: plot.y - 6, text: label, anchor: "middle", baseline: "bottom", size: fs, fill: theme.mutedText, target });
1267
+ else marks.push({ kind: "text", key, role: "tick-label", x: p, y: plot.y + plot.height + 6, text: label, anchor: "middle", baseline: "top", size: fs, fill: theme.mutedText, target });
1268
+ } else if (far) marks.push({ kind: "text", key, role: "tick-label", x: plot.x + plot.width + 8, y: p, text: label, anchor: "start", baseline: "middle", size: fs, fill: theme.mutedText, target });
1269
+ else marks.push({ kind: "text", key, role: "tick-label", x: plot.x - 8, y: p, text: label, anchor: "end", baseline: "middle", size: fs, fill: theme.mutedText, target });
1872
1270
  });
1873
1271
  };
1874
1272
  ticksFor(value, primary, false);
@@ -1893,18 +1291,18 @@ function categoryFrame(ctx, area, input) {
1893
1291
  const extra = target ? { target, selected } : {};
1894
1292
  if (horizontal) {
1895
1293
  const maxW = left - (xAxis.title ? titleBand : 0) - 8;
1896
- const text2 = truncate(text0, maxW, fs, measure);
1897
- if (text2 !== text0) truncated++;
1898
- marks.push({ kind: "text", key: `tick-x-${i}`, role: "tick-label", x: plot.x - 8, y: catCenter(i), text: text2, anchor: "end", baseline: "middle", size: fs, fill, ...extra });
1294
+ const text = truncate(text0, maxW, fs, measure);
1295
+ if (text !== text0) truncated++;
1296
+ marks.push({ kind: "text", key: `tick-x-${i}`, role: "tick-label", x: plot.x - 8, y: catCenter(i), text, anchor: "end", baseline: "middle", size: fs, fill, ...extra });
1899
1297
  } else if (rotate) {
1900
1298
  const room = (catCenter(i) - 2) / Math.cos(Math.PI / 4.5);
1901
- const text2 = truncate(text0, Math.max(fs, Math.min(rotatedMax, room)), fs, measure);
1902
- if (text2 !== text0) truncated++;
1903
- marks.push({ kind: "text", key: `tick-x-${i}`, role: "tick-label", x: catCenter(i), y: plot.y + plot.height + 8, text: text2, anchor: "end", baseline: "middle", size: fs, fill, rotate, ...extra });
1299
+ const text = truncate(text0, Math.max(fs, Math.min(rotatedMax, room)), fs, measure);
1300
+ if (text !== text0) truncated++;
1301
+ marks.push({ kind: "text", key: `tick-x-${i}`, role: "tick-label", x: catCenter(i), y: plot.y + plot.height + 8, text, anchor: "end", baseline: "middle", size: fs, fill, rotate, ...extra });
1904
1302
  } else {
1905
- const text2 = dateLabels ? text0 : truncate(text0, Math.max(band - 4, fs * 2), fs, measure);
1906
- if (text2 !== text0) truncated++;
1907
- marks.push({ kind: "text", key: `tick-x-${i}`, role: "tick-label", x: catCenter(i), y: plot.y + plot.height + 6, text: text2, anchor: dateLabels ? "start" : "middle", baseline: "top", size: fs, fill, ...extra });
1303
+ const text = dateLabels ? text0 : truncate(text0, Math.max(band - 4, fs * 2), fs, measure);
1304
+ if (text !== text0) truncated++;
1305
+ marks.push({ kind: "text", key: `tick-x-${i}`, role: "tick-label", x: catCenter(i), y: plot.y + plot.height + 6, text, anchor: dateLabels ? "start" : "middle", baseline: "top", size: fs, fill, ...extra });
1908
1306
  }
1909
1307
  });
1910
1308
  if (dateLabels) {
@@ -1985,10 +1383,10 @@ function drawTrendLabels(ctx, plot, labels) {
1985
1383
  (l, i) => ctx.marks.push({ kind: "text", key: `trendline-label-${i}`, role: "trendline-label", x: plot.x + plot.width - 4, y: plot.y + 4 + i * (ctx.fs + 3), text: l.text, anchor: "end", baseline: "top", size: ctx.fs - 1, fill: l.color, target: l.target })
1986
1384
  );
1987
1385
  }
1988
- function barLabel(ctx, text2, rect, horizontal, positive, stacked, fill, plot) {
1386
+ function barLabel(ctx, text, rect, horizontal, positive, stacked, fill, plot) {
1989
1387
  const { measure, fs, spec, theme } = ctx;
1990
1388
  const size = fs - 1;
1991
- const tw = measure(text2, size);
1389
+ const tw = measure(text, size);
1992
1390
  const th = size + 2;
1993
1391
  const along = horizontal ? rect.width : rect.height;
1994
1392
  const across = horizontal ? rect.height : rect.width;
@@ -2134,13 +1532,13 @@ function layoutCartesian(ctx, area, visible) {
2134
1532
  if (selected) ctx.outline(`bar-${s.id}-${i}-selection`, { x: rect.x - 2, y: rect.y - 2, width: rect.width + 4, height: rect.height + 4 });
2135
1533
  if (labelsOn) {
2136
1534
  const v = percent ? seg[1] - seg[0] : raw;
2137
- const text2 = dataLabel(v);
2138
- const at = barLabel(ctx, text2, rect, horizontal, seg[1] >= seg[0], stacked, fill, plot);
1535
+ const text = dataLabel(v);
1536
+ const at = barLabel(ctx, text, rect, horizontal, seg[1] >= seg[0], stacked, fill, plot);
2139
1537
  if (!at) {
2140
1538
  hiddenLabels++;
2141
1539
  return;
2142
1540
  }
2143
- labelMarks.push({ kind: "text", key: `label-${s.id}-${i}`, role: "data-label", ...at, text: text2, size: fs - 1, target });
1541
+ labelMarks.push({ kind: "text", key: `label-${s.id}-${i}`, role: "data-label", ...at, text, size: fs - 1, target });
2144
1542
  }
2145
1543
  });
2146
1544
  } else {
@@ -2412,12 +1810,12 @@ function layoutPie(ctx, area, series) {
2412
1810
  return;
2413
1811
  }
2414
1812
  const share = v / total;
2415
- const text2 = format.style || format.code ? formatChartNumber(v, format) : `${Math.round(share * 100)}%`;
1813
+ const text = format.style || format.code ? formatChartNumber(v, format) : `${Math.round(share * 100)}%`;
2416
1814
  const lr = outer + fs * 1.1;
2417
1815
  const lx = ox + lr * Math.sin(mid);
2418
1816
  const ly = oy - lr * Math.cos(mid);
2419
1817
  const anchor = Math.abs(Math.sin(mid)) < 0.2 ? "middle" : Math.sin(mid) > 0 ? "start" : "end";
2420
- marks.push({ kind: "text", key: `label-slice-${i}`, role: "data-label", x: lx, y: ly, text: text2, anchor, baseline: "middle", size: fs, fill: theme.text, target });
1818
+ marks.push({ kind: "text", key: `label-slice-${i}`, role: "data-label", x: lx, y: ly, text, anchor, baseline: "middle", size: fs, fill: theme.text, target });
2421
1819
  });
2422
1820
  if (hidden) ctx.warn("data-labels-hidden", `${hidden} slice label${hidden === 1 ? " is" : "s are"} hidden: the slices are too thin.`);
2423
1821
  if (spec.type === "donut" && inner > fs * 2) {
@@ -2539,10 +1937,10 @@ function layoutWaterfall(ctx, area, series) {
2539
1937
  }
2540
1938
  prevEnd = s.to;
2541
1939
  if (labelsOn) {
2542
- const text2 = formatChartNumber(s.total ? s.to : s.to - s.from, format);
1940
+ const text = formatChartNumber(s.total ? s.to : s.to - s.from, format);
2543
1941
  const up = s.to >= s.from;
2544
1942
  const [lx, ly] = map({ c: catCenter(k), v: horizontal ? Math.max(a, b) + 4 : up ? Math.min(a, b) - 4 : Math.max(a, b) + 4 });
2545
- marks.push({ kind: "text", key: `label-${series.id}-${s.index ?? "total"}`, role: "data-label", x: lx, y: ly, text: text2, anchor: horizontal ? "start" : "middle", baseline: horizontal ? "middle" : up ? "bottom" : "top", size: fs - 1, fill: theme.text, target });
1943
+ marks.push({ kind: "text", key: `label-${series.id}-${s.index ?? "total"}`, role: "data-label", x: lx, y: ly, text, anchor: horizontal ? "start" : "middle", baseline: horizontal ? "middle" : up ? "bottom" : "top", size: fs - 1, fill: theme.text, target });
2546
1944
  }
2547
1945
  });
2548
1946
  return { plot: frame.plot, valueScale: toValueScale(value, horizontal ? "x" : "y") };
@@ -2612,7 +2010,7 @@ function layoutBox(ctx, area, visible) {
2612
2010
  const selected = ctx.seriesSelected(s.id);
2613
2011
  const c = catCenter(i);
2614
2012
  const y = value.px;
2615
- const line = (key2, x1, y1, x2, y2, width = 1.25, stroke = color) => marks.push({ kind: "line", key: key2, role: "whisker", x1, y1, x2, y2, stroke, strokeWidth: width, target });
2013
+ const line = (key, x1, y1, x2, y2, width = 1.25, stroke = color) => marks.push({ kind: "line", key, role: "whisker", x1, y1, x2, y2, stroke, strokeWidth: width, target });
2616
2014
  line(`whisker-hi-${s.id}`, c, y(st.upperWhisker), c, y(st.q3));
2617
2015
  line(`whisker-lo-${s.id}`, c, y(st.q1), c, y(st.lowerWhisker));
2618
2016
  line(`cap-hi-${s.id}`, c - bw / 4, y(st.upperWhisker), c + bw / 4, y(st.upperWhisker));
@@ -2654,9 +2052,9 @@ function layoutFunnel(ctx, area, series) {
2654
2052
  marks.push({ kind: "rect", key: `bar-${series.id}-${i}`, role: "bar", x: cx - w / 2, y: cy - h / 2, width: w, height: h, fill, radius: 2, target, selected });
2655
2053
  if (selected) ctx.outline(`bar-${series.id}-${i}-selection`, { x: cx - w / 2 - 2, y: cy - h / 2 - 2, width: w + 4, height: h + 4 });
2656
2054
  if (labelsOn) {
2657
- const text2 = formatChartNumber(v, format);
2658
- const fits = measure(text2, fs) + 8 <= w && fs + 2 <= h;
2659
- marks.push({ kind: "text", key: `label-${series.id}-${i}`, role: "data-label", x: fits ? cx : cx + w / 2 + 4, y: cy, text: text2, anchor: fits ? "middle" : "start", baseline: "middle", size: fs, fill: fits ? contrastingTextColor(fill) : theme.text, target });
2055
+ const text = formatChartNumber(v, format);
2056
+ const fits = measure(text, fs) + 8 <= w && fs + 2 <= h;
2057
+ marks.push({ kind: "text", key: `label-${series.id}-${i}`, role: "data-label", x: fits ? cx : cx + w / 2 + 4, y: cy, text, anchor: fits ? "middle" : "start", baseline: "middle", size: fs, fill: fits ? contrastingTextColor(fill) : theme.text, target });
2660
2058
  }
2661
2059
  });
2662
2060
  return { plot };
@@ -2753,7 +2151,7 @@ function layoutChart(spec, options) {
2753
2151
  selection,
2754
2152
  isSelected: (target) => sameChartSelection(selection, target),
2755
2153
  seriesSelected: (id) => selection?.kind === "series" && selection.seriesId === id,
2756
- outline: (key2, box) => marks.push({ kind: "rect", key: key2, role: "selection", ...box, fill: "none", stroke: theme.selection, strokeWidth: 1, radius: 3 }),
2154
+ outline: (key, box) => marks.push({ kind: "rect", key, role: "selection", ...box, fill: "none", stroke: theme.selection, strokeWidth: 1, radius: 3 }),
2757
2155
  warn: (code, message) => {
2758
2156
  if (!warnings.some((w) => w.code === code && w.message === message)) warnings.push({ code, message });
2759
2157
  }
@@ -2924,13 +2322,13 @@ function addReadout(ctx, readout, plot) {
2924
2322
  } else return;
2925
2323
  const axis = series.axis === "secondary" ? spec.yAxis2 : spec.yAxis;
2926
2324
  const x = series.x?.[readout.index];
2927
- const text2 = x !== null && x !== void 0 && chartFamily(spec) === "xy" ? `${formatChartNumber(x, spec.xAxis.format)}, ${formatChartNumber(value, axis.format)}` : `${spec.categories[readout.index] ?? ""}: ${formatChartNumber(value, series.format ?? axis.format)}`;
2928
- const w = measure(text2, fs, 600) + 10;
2325
+ const text = x !== null && x !== void 0 && chartFamily(spec) === "xy" ? `${formatChartNumber(x, spec.xAxis.format)}, ${formatChartNumber(value, axis.format)}` : `${spec.categories[readout.index] ?? ""}: ${formatChartNumber(value, series.format ?? axis.format)}`;
2326
+ const w = measure(text, fs, 600) + 10;
2929
2327
  const h = fs + 8;
2930
2328
  const bx = Math.max(plot.x, Math.min(plot.x + plot.width - w, ax - w / 2));
2931
2329
  const by = Math.max(plot.y, Math.min(plot.y + plot.height - h, ay - h - 6));
2932
2330
  marks.push({ kind: "rect", key: "drag-readout-box", role: "drag-readout", x: bx, y: by, width: w, height: h, fill: theme.text, radius: 3, opacity: 0.9 });
2933
- marks.push({ kind: "text", key: "drag-readout", role: "drag-readout", x: bx + w / 2, y: by + h / 2, text: text2, anchor: "middle", baseline: "middle", size: fs, weight: 600, fill: theme.surface });
2331
+ marks.push({ kind: "text", key: "drag-readout", role: "drag-readout", x: bx + w / 2, y: by + h / 2, text, anchor: "middle", baseline: "middle", size: fs, weight: 600, fill: theme.surface });
2934
2332
  }
2935
2333
  var finite = (...n) => n.every((v) => v === void 0 || Number.isFinite(v));
2936
2334
  function finalizeMarks(marks, width, height) {
@@ -3051,13 +2449,13 @@ function chartTextBaseline(baseline) {
3051
2449
  function chartTextTransform(mark) {
3052
2450
  return mark.rotate ? `rotate(${mark.rotate} ${mark.x} ${mark.y})` : void 0;
3053
2451
  }
3054
- var escape = (text2) => text2.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
2452
+ var escape = (text) => text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
3055
2453
  function markParts(mark, fontFamily) {
3056
2454
  const common = { opacity: mark.opacity, "data-role": mark.role };
3057
- const parts = (tag, values, text2) => ({
2455
+ const parts = (tag, values, text) => ({
3058
2456
  tag,
3059
2457
  attrs: Object.fromEntries(Object.entries(values).filter(([, v]) => v !== void 0 && v !== "").map(([k, v]) => [k, String(v)])),
3060
- text: text2
2458
+ text
3061
2459
  });
3062
2460
  switch (mark.kind) {
3063
2461
  case "rect":
@@ -3088,9 +2486,9 @@ function markParts(mark, fontFamily) {
3088
2486
  }
3089
2487
  }
3090
2488
  function markToSvg(mark, fontFamily) {
3091
- const { tag, attrs, text: text2 } = markParts(mark, fontFamily);
2489
+ const { tag, attrs, text } = markParts(mark, fontFamily);
3092
2490
  const attrText = Object.entries(attrs).map(([k, v]) => ` ${k}="${escape(v)}"`).join("");
3093
- return text2 === void 0 ? `<${tag}${attrText}/>` : `<${tag}${attrText}>${escape(text2)}</${tag}>`;
2491
+ return text === void 0 ? `<${tag}${attrText}/>` : `<${tag}${attrText}>${escape(text)}</${tag}>`;
3094
2492
  }
3095
2493
  function chartSceneToSvg(scene, options = {}) {
3096
2494
  const hide = options.hideSelection ?? true;
@@ -3116,8 +2514,8 @@ function chartSceneToDomSpec(scene, options = {}) {
3116
2514
  if (options.description) children.push([tag("desc"), {}, options.description]);
3117
2515
  for (const mark of scene.marks) {
3118
2516
  if (hide && mark.role === "selection") continue;
3119
- const { tag: name, attrs: attrs2, text: text2 } = markParts(mark, font);
3120
- children.push(text2 === void 0 ? [tag(name), attrs2] : [tag(name), attrs2, text2]);
2517
+ const { tag: name, attrs: attrs2, text } = markParts(mark, font);
2518
+ children.push(text === void 0 ? [tag(name), attrs2] : [tag(name), attrs2, text]);
3121
2519
  }
3122
2520
  const attrs = {
3123
2521
  width: String(scene.width),
@@ -3376,8 +2774,8 @@ var ChartController = class {
3376
2774
  }
3377
2775
  /** Changes the category (`x`), value (`y`) or secondary value (`y2`) axis. */
3378
2776
  setAxis(axis, patch) {
3379
- const key2 = axis === "x" ? "xAxis" : axis === "y" ? "yAxis" : "yAxis2";
3380
- return this.update({ [key2]: patch }, { label: `Change ${axis === "x" ? "category" : axis === "y" ? "value" : "secondary value"} axis` });
2777
+ const key = axis === "x" ? "xAxis" : axis === "y" ? "yAxis" : "yAxis2";
2778
+ return this.update({ [key]: patch }, { label: `Change ${axis === "x" ? "category" : axis === "y" ? "value" : "secondary value"} axis` });
3381
2779
  }
3382
2780
  /**
3383
2781
  * Applies a named quick layout and / or colour scheme (see `CHART_LAYOUT_PRESETS` and
@@ -3482,10 +2880,10 @@ var ChartController = class {
3482
2880
  else delete next.hidden;
3483
2881
  }
3484
2882
  const resettable = ["axis", "x", "sizes", "pointColors", "marker", "curve", "dataLabels", "format"];
3485
- for (const key2 of resettable) {
3486
- if (!(key2 in patch) || patch[key2] === void 0) continue;
3487
- if (patch[key2] === null) delete next[key2];
3488
- else next[key2] = patch[key2];
2883
+ for (const key of resettable) {
2884
+ if (!(key in patch) || patch[key] === void 0) continue;
2885
+ if (patch[key] === null) delete next[key];
2886
+ else next[key] = patch[key];
3489
2887
  }
3490
2888
  if (next.axis === "primary") delete next.axis;
3491
2889
  const series2 = this.spec.series.map((s) => s.id === id ? next : s);
@@ -3632,9 +3030,9 @@ var ChartController = class {
3632
3030
  return { ok: true };
3633
3031
  }
3634
3032
  /** Imports CSV (or TSV, detected by tabs) text; see `importTable`. */
3635
- importCsv(text2, options = {}) {
3636
- const delimiter = options.delimiter ?? (text2.includes(" ") ? " " : ",");
3637
- return this.importTable(parseCsv(text2, { delimiter }), options);
3033
+ importCsv(text, options = {}) {
3034
+ const delimiter = options.delimiter ?? (text.includes(" ") ? " " : ",");
3035
+ return this.importTable(parseCsv(text, { delimiter }), options);
3638
3036
  }
3639
3037
  // -------------------------------------------------------------------------
3640
3038
  // Trendlines
@@ -3780,10 +3178,10 @@ var ChartController = class {
3780
3178
  return this.setValue(seriesId, index, Number((current + delta).toPrecision(12)), { label: `Edit ${series.name} \xB7 ${this.spec.categories[index] ?? index}` });
3781
3179
  }
3782
3180
  /** Starts a continuous edit (a drag): every change until `endGesture()` is one undo step. */
3783
- beginGesture(key2) {
3784
- if (this.gestureKey === key2) return;
3181
+ beginGesture(key) {
3182
+ if (this.gestureKey === key) return;
3785
3183
  this.history.endGesture();
3786
- this.gestureKey = key2;
3184
+ this.gestureKey = key;
3787
3185
  this.gestureCount++;
3788
3186
  this.gestureStart = { spec: this.spec, mark: this.history.mark() };
3789
3187
  this.notify(false);
@@ -3968,54 +3366,6 @@ function sparklineToSvg(values, options) {
3968
3366
  }
3969
3367
 
3970
3368
  export {
3971
- parseChartColor,
3972
- chartRgbToHex,
3973
- shadeChartColor,
3974
- CHART_PALETTE_SHADES,
3975
- cyclePaletteColor,
3976
- chartLuminance,
3977
- chartContrastRatio,
3978
- chartTextOn,
3979
- chartRgbToOklab,
3980
- chartColorDistance,
3981
- simulateChartVision,
3982
- checkChartColors,
3983
- CHART_TYPES,
3984
- CHART_MARKERS,
3985
- CHART_TRENDLINE_TYPES,
3986
- CHART_LABEL_POSITIONS,
3987
- CHART_AXIS_KINDS,
3988
- CHART_SERIES_TYPES,
3989
- CHART_STACKINGS,
3990
- CHART_CURVES,
3991
- CHART_ORIENTATIONS,
3992
- CHART_LEGEND_POSITIONS,
3993
- CHART_NUMBER_STYLES,
3994
- CHART_TYPE_LABELS,
3995
- DEFAULT_CHART_PALETTE,
3996
- DEFAULT_CHART_THEME,
3997
- CSS_VARIABLE_CHART_THEME,
3998
- isCartesianChart,
3999
- isXyChart,
4000
- chartFamily,
4001
- chartColorsByCategory,
4002
- defaultChartAxis,
4003
- createChartSpec,
4004
- chartSeriesColor,
4005
- chartSliceColor,
4006
- chartPointColor,
4007
- chartSeriesType,
4008
- uniqueChartSeriesId,
4009
- parseChartValue,
4010
- normalizeChartAxis,
4011
- normalizeChartValues,
4012
- normalizeChartTrendline,
4013
- normalizeChartSpec,
4014
- cloneChartSpec,
4015
- cloneChartSeries,
4016
- chartDataFromTable,
4017
- chartDataToTable,
4018
- chartColorInputValue,
4019
3369
  CHART_MERMAID_META_PREFIX,
4020
3370
  chartMermaidFamily,
4021
3371
  chartToMermaid,
@@ -4071,4 +3421,4 @@ export {
4071
3421
  layoutSparkline,
4072
3422
  sparklineToSvg
4073
3423
  };
4074
- //# sourceMappingURL=chunk-LTUM52X6.js.map
3424
+ //# sourceMappingURL=chunk-WBOAXDKD.js.map