@tensor_1/react 2.38.0 → 2.40.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 (60) hide show
  1. package/README.md +65 -0
  2. package/dist/{chart-theme-Cl0IrkKQ.d.cts → ChartCore-BKK2HEfi.d.cts} +77 -50
  3. package/dist/chart-analytic-guide.d.ts +6 -0
  4. package/dist/chart-analytic-guide.js +10 -0
  5. package/dist/chart-analytic-model.d.ts +145 -0
  6. package/dist/chart-analytic-model.js +259 -0
  7. package/dist/chart-analytic.cjs +1379 -0
  8. package/dist/chart-analytic.d.cts +339 -0
  9. package/dist/chart-analytic.d.ts +19 -0
  10. package/dist/chart-analytic.js +95 -0
  11. package/dist/chart-panels-model.d.ts +92 -0
  12. package/dist/chart-panels-model.js +284 -0
  13. package/dist/chart-preset.cjs +41 -4
  14. package/dist/chart-preset.d.cts +2 -2
  15. package/dist/chart-preset.d.ts +1 -1
  16. package/dist/chart-stats-o4zDhpVm.d.cts +46 -0
  17. package/dist/chart-stats.d.ts +46 -0
  18. package/dist/chart-stats.js +89 -0
  19. package/dist/chart-theme.d.ts +3 -0
  20. package/dist/chart-theme.js +2 -0
  21. package/dist/chart.cjs +41 -4
  22. package/dist/chart.d.cts +2 -2
  23. package/dist/chart.d.ts +1 -1
  24. package/dist/components/Chart.d.ts +1 -1
  25. package/dist/components/ChartCore.d.ts +23 -3
  26. package/dist/components/ChartCore.js +40 -5
  27. package/dist/components/ChartPanels.d.ts +52 -0
  28. package/dist/components/ChartPanels.js +170 -0
  29. package/dist/components/Comments.d.ts +4 -1
  30. package/dist/components/Comments.js +3 -2
  31. package/dist/components/InsightCard.d.ts +86 -0
  32. package/dist/components/InsightCard.js +118 -0
  33. package/dist/components/Markdown.d.ts +9 -2
  34. package/dist/components/Markdown.js +16 -2
  35. package/dist/components/RichTextEditor.d.ts +17 -0
  36. package/dist/components/RichTextEditor.js +179 -11
  37. package/dist/components/ToggleRow.d.ts +8 -1
  38. package/dist/components/ToggleRow.js +17 -3
  39. package/dist/correlation-scatter-model.d.ts +68 -0
  40. package/dist/correlation-scatter-model.js +179 -0
  41. package/dist/icons/Icon.d.ts +17 -17
  42. package/dist/index.cjs +1663 -1427
  43. package/dist/index.d.cts +96 -3
  44. package/dist/index.d.ts +2 -0
  45. package/dist/index.js +10 -0
  46. package/dist/markdown-model-Cuwi6pIk.d.cts +110 -0
  47. package/dist/markdown-model.d.ts +38 -1
  48. package/dist/markdown-model.js +67 -0
  49. package/dist/markdown.cjs +90 -4
  50. package/dist/markdown.d.cts +11 -75
  51. package/dist/markdown.d.ts +1 -1
  52. package/dist/markdown.js +16 -2
  53. package/dist/rich-text/mention.d.ts +14 -0
  54. package/dist/rich-text/mention.js +57 -0
  55. package/dist/rich-text/pipeline.js +4 -1
  56. package/dist/rich-text.cjs +1795 -1483
  57. package/dist/rich-text.d.cts +27 -1
  58. package/dist/rich-text.d.ts +3 -0
  59. package/dist/rich-text.js +6 -0
  60. package/package.json +6 -1
@@ -0,0 +1,1379 @@
1
+ "use strict";
2
+ "use client";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/chart-analytic.tsx
32
+ var chart_analytic_exports = {};
33
+ __export(chart_analytic_exports, {
34
+ CHART_PANELS_LAYOUT: () => CHART_PANELS_LAYOUT,
35
+ Chart: () => Chart,
36
+ ChartLegend: () => ChartLegend,
37
+ ChartLegendItem: () => ChartLegendItem,
38
+ ChartMetric: () => ChartMetric,
39
+ ChartPanels: () => ChartPanels,
40
+ CorrelationScatter: () => CorrelationScatter,
41
+ DEFAULT_ANALYTIC_LABELS: () => DEFAULT_ANALYTIC_LABELS,
42
+ DEFAULT_CHART_LABELS: () => DEFAULT_CHART_LABELS,
43
+ DEFAULT_CHART_PANELS_LABELS: () => DEFAULT_CHART_PANELS_LABELS,
44
+ DEFAULT_CORRELATION_SCATTER_LABELS: () => DEFAULT_CORRELATION_SCATTER_LABELS,
45
+ SCATTER_HIT_SIZE: () => SCATTER_HIT_SIZE,
46
+ chartPanelsModel: () => chartPanelsModel,
47
+ combineMarks: () => combineMarks,
48
+ comparisonSeries: () => comparisonSeries,
49
+ correlationScatterModel: () => correlationScatterModel,
50
+ crossingPoints: () => crossingPoints,
51
+ eventMarks: () => eventMarks,
52
+ findCrossings: () => findCrossings,
53
+ forecastSeries: () => forecastSeries,
54
+ formatCorrelation: () => formatCorrelation,
55
+ linearFit: () => linearFit,
56
+ mergeChartTheme: () => mergeChartTheme,
57
+ niceCeil: () => niceCeil,
58
+ normalQuantile: () => normalQuantile,
59
+ partialPeriod: () => partialPeriod,
60
+ predictionBand: () => predictionBand,
61
+ quantiles: () => quantiles,
62
+ studentTQuantile: () => studentTQuantile,
63
+ thresholdMarks: () => thresholdMarks,
64
+ uixChartAreaGradient: () => uixChartAreaGradient,
65
+ uixChartPalette: () => uixChartPalette,
66
+ uixChartTheme: () => uixChartTheme,
67
+ uixChartTokens: () => uixChartTokens
68
+ });
69
+ module.exports = __toCommonJS(chart_analytic_exports);
70
+ var echarts = __toESM(require("echarts/core"), 1);
71
+ var import_charts = require("echarts/charts");
72
+ var import_components = require("echarts/components");
73
+ var import_renderers = require("echarts/renderers");
74
+
75
+ // src/components/ChartCore.tsx
76
+ var import_react = require("react");
77
+
78
+ // src/cx.ts
79
+ function cx(...args) {
80
+ return args.filter(Boolean).join(" ");
81
+ }
82
+
83
+ // src/chart-theme.ts
84
+ function reader(source) {
85
+ if (typeof source === "function") return source;
86
+ if (typeof getComputedStyle === "undefined" || typeof document === "undefined") return () => "";
87
+ const style = getComputedStyle(source ?? document.documentElement);
88
+ return (token) => style.getPropertyValue(token).trim();
89
+ }
90
+ function uixChartTokens(source) {
91
+ const read = reader(source);
92
+ const t = (name) => read(`--uix-${name}`);
93
+ const unquote = (font) => font.replace(/"/g, "");
94
+ return {
95
+ palette: [1, 2, 3, 4, 5, 6, 7, 8].map((i) => t(`chart-${i}`)),
96
+ neutral: t("chart-neutral"),
97
+ grid: t("chart-grid"),
98
+ axis: t("chart-axis"),
99
+ reference: t("chart-reference"),
100
+ zoneWarning: t("chart-zone-warning"),
101
+ zoneDanger: t("chart-zone-danger"),
102
+ forecastBand: t("chart-forecast-band"),
103
+ event: t("chart-event"),
104
+ partial: t("chart-partial"),
105
+ comparison: t("chart-comparison"),
106
+ warning: t("warning"),
107
+ danger: t("danger"),
108
+ surface: t("surface"),
109
+ text: t("text"),
110
+ textMuted: t("text-muted"),
111
+ border: t("border-strong"),
112
+ fontSans: unquote(t("font-sans")),
113
+ fontMono: unquote(t("font-mono"))
114
+ };
115
+ }
116
+ function uixChartTheme(source) {
117
+ const k = uixChartTokens(source);
118
+ const read = reader(source);
119
+ const axis = {
120
+ axisLine: { lineStyle: { color: k.axis } },
121
+ axisTick: { show: false },
122
+ axisLabel: { color: k.textMuted, fontFamily: k.fontMono, fontSize: 11 },
123
+ splitLine: { lineStyle: { color: k.grid, type: "solid", width: 1 } }
124
+ };
125
+ return {
126
+ color: k.palette,
127
+ backgroundColor: "transparent",
128
+ textStyle: { color: k.textMuted, fontFamily: k.fontSans, fontSize: 12 },
129
+ title: { textStyle: { color: k.text, fontFamily: k.fontSans }, subtextStyle: { color: k.textMuted, fontFamily: k.fontSans } },
130
+ legend: { textStyle: { color: k.textMuted, fontFamily: k.fontSans, fontSize: 12 }, icon: "roundRect", itemWidth: 10, itemHeight: 6, itemGap: 12 },
131
+ tooltip: {
132
+ backgroundColor: k.surface,
133
+ borderColor: k.border,
134
+ borderWidth: 1,
135
+ padding: [8, 10],
136
+ textStyle: { color: k.text, fontFamily: k.fontSans, fontSize: 12 },
137
+ extraCssText: `border-radius:${read("--uix-radius-sm")};box-shadow:${read("--uix-shadow-popover")}`,
138
+ axisPointer: { lineStyle: { color: k.reference, width: 1 }, crossStyle: { color: k.reference }, shadowStyle: { color: k.forecastBand } }
139
+ },
140
+ xAxis: axis,
141
+ yAxis: axis
142
+ };
143
+ }
144
+ function uixChartAreaGradient(color) {
145
+ const alpha = (opacity) => {
146
+ const hex = color.replace("#", "");
147
+ if (!/^[0-9a-f]{6}$/i.test(hex)) return color;
148
+ const [r, g, b] = hex.match(/.{2}/g).map((channel) => Number.parseInt(channel, 16));
149
+ return `rgba(${r},${g},${b},${opacity})`;
150
+ };
151
+ return {
152
+ type: "linear",
153
+ x: 0,
154
+ y: 0,
155
+ x2: 0,
156
+ y2: 1,
157
+ colorStops: [{ offset: 0, color: alpha(0.28) }, { offset: 0.72, color: alpha(0.06) }, { offset: 1, color: alpha(0) }]
158
+ };
159
+ }
160
+ var isPlainObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
161
+ function deepMerge(base, over) {
162
+ if (over === void 0) return base;
163
+ if (!isPlainObject(base) || !isPlainObject(over)) return over;
164
+ const out = { ...base };
165
+ for (const key of Object.keys(over)) out[key] = deepMerge(base[key], over[key]);
166
+ return out;
167
+ }
168
+ var STYLED_ONLY = ["xAxis", "yAxis", "legend", "title"];
169
+ function mergeChartTheme(theme, option) {
170
+ const merged = deepMerge(theme, option);
171
+ const source = option;
172
+ const base = theme;
173
+ for (const key of STYLED_ONLY) {
174
+ if (Array.isArray(source[key])) merged[key] = source[key].map((axis) => deepMerge(base[key], axis));
175
+ else if (!(key in source)) delete merged[key];
176
+ }
177
+ return merged;
178
+ }
179
+
180
+ // src/components/ChartCore.tsx
181
+ var import_jsx_runtime = require("react/jsx-runtime");
182
+ function readToken(name) {
183
+ if (typeof getComputedStyle === "undefined") return "";
184
+ return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
185
+ }
186
+ function uixChartPalette() {
187
+ return [1, 2, 3, 4, 5, 6, 7, 8].map((i) => readToken(`--uix-chart-${i}`));
188
+ }
189
+ function themed(option, theme, element) {
190
+ const resolved = typeof option === "function" ? option(uixChartTokens(element)) : option;
191
+ return theme === "none" ? resolved : mergeChartTheme(uixChartTheme(element), resolved);
192
+ }
193
+ function motionSafe(option) {
194
+ if (typeof matchMedia !== "undefined" && matchMedia("(prefers-reduced-motion: reduce)").matches) {
195
+ return { ...option, animation: false };
196
+ }
197
+ return option;
198
+ }
199
+ var DEFAULT_CHART_LABELS = {
200
+ loading: "Loading chart\u2026",
201
+ chart: "Chart",
202
+ dataTableSuffix: "data table"
203
+ };
204
+ function ChartCore({
205
+ engine,
206
+ option,
207
+ title,
208
+ subtitle,
209
+ height = 280,
210
+ className,
211
+ style,
212
+ ariaLabel,
213
+ tableData,
214
+ tableHeaders,
215
+ onReady,
216
+ header,
217
+ headerAction,
218
+ footer,
219
+ loading = false,
220
+ empty,
221
+ labels: labelOverrides,
222
+ theme = "uix",
223
+ group,
224
+ onEvents,
225
+ tables
226
+ }) {
227
+ const labels = { ...DEFAULT_CHART_LABELS, ...labelOverrides };
228
+ const containerRef = (0, import_react.useRef)(null);
229
+ const chartRef = (0, import_react.useRef)(null);
230
+ const appliedOptionRef = (0, import_react.useRef)(null);
231
+ const onEventsRef = (0, import_react.useRef)(onEvents);
232
+ onEventsRef.current = onEvents;
233
+ const latestOptionRef = (0, import_react.useRef)(option);
234
+ const onReadyRef = (0, import_react.useRef)(onReady);
235
+ const tableId = (0, import_react.useId)();
236
+ const hasEmpty = empty != null;
237
+ const hasTextAlternative = Boolean(ariaLabel || title || tableData?.length || tables?.length);
238
+ const hasTextAlternativeRef = (0, import_react.useRef)(hasTextAlternative);
239
+ const themeRef = (0, import_react.useRef)(theme);
240
+ latestOptionRef.current = option;
241
+ themeRef.current = theme;
242
+ onReadyRef.current = onReady;
243
+ hasTextAlternativeRef.current = hasTextAlternative;
244
+ (0, import_react.useEffect)(() => {
245
+ const element = containerRef.current;
246
+ if (!element) return;
247
+ const chart = engine.init(element, null, { renderer: "svg" });
248
+ chartRef.current = chart;
249
+ chart.setOption(motionSafe(themed(latestOptionRef.current, themeRef.current, element)));
250
+ appliedOptionRef.current = latestOptionRef.current;
251
+ onReadyRef.current?.(chart);
252
+ const retheme = () => {
253
+ if (themeRef.current === "none") return;
254
+ chart.setOption(motionSafe(themed(latestOptionRef.current, themeRef.current, element)));
255
+ };
256
+ const themeObserver = typeof MutationObserver === "undefined" ? null : new MutationObserver(retheme);
257
+ themeObserver?.observe(document.documentElement, { attributes: true, attributeFilter: ["class", "data-theme"] });
258
+ const scheme = typeof matchMedia === "undefined" ? null : matchMedia("(prefers-color-scheme: dark)");
259
+ scheme?.addEventListener?.("change", retheme);
260
+ if (!hasTextAlternativeRef.current) {
261
+ console.warn("[uix] Chart has no text alternative \u2014 provide ariaLabel, title, or tableData.");
262
+ }
263
+ let frame = 0;
264
+ let width = element.clientWidth;
265
+ let height2 = element.clientHeight;
266
+ const observer = new ResizeObserver(() => {
267
+ const nextWidth = element.clientWidth;
268
+ const nextHeight = element.clientHeight;
269
+ if (nextWidth === width && nextHeight === height2) return;
270
+ width = nextWidth;
271
+ height2 = nextHeight;
272
+ if (frame) return;
273
+ frame = requestAnimationFrame(() => {
274
+ frame = 0;
275
+ chart.resize();
276
+ });
277
+ });
278
+ observer.observe(element);
279
+ return () => {
280
+ observer.disconnect();
281
+ themeObserver?.disconnect();
282
+ scheme?.removeEventListener?.("change", retheme);
283
+ if (frame) cancelAnimationFrame(frame);
284
+ chart.dispose();
285
+ chartRef.current = null;
286
+ appliedOptionRef.current = null;
287
+ };
288
+ }, [engine, hasEmpty]);
289
+ const eventNames = Object.keys(onEvents ?? {}).sort().join("|");
290
+ (0, import_react.useEffect)(() => {
291
+ const chart = chartRef.current;
292
+ if (!chart || !eventNames) return;
293
+ const bound = eventNames.split("|").map((name) => {
294
+ const handler = (params) => onEventsRef.current?.[name]?.(params);
295
+ chart.on(name, handler);
296
+ return [name, handler];
297
+ });
298
+ return () => {
299
+ if (chart.isDisposed()) return;
300
+ for (const [name, handler] of bound) chart.off(name, handler);
301
+ };
302
+ }, [engine, hasEmpty, eventNames]);
303
+ (0, import_react.useEffect)(() => {
304
+ const chart = chartRef.current;
305
+ if (!chart || !group) return;
306
+ chart.group = group;
307
+ engine.connect?.(group);
308
+ return () => {
309
+ if (!chart.isDisposed()) chart.group = "";
310
+ };
311
+ }, [engine, hasEmpty, group]);
312
+ (0, import_react.useEffect)(() => {
313
+ const chart = chartRef.current;
314
+ const element = containerRef.current;
315
+ if (!chart || !element || appliedOptionRef.current === option) return;
316
+ chart.setOption(motionSafe(themed(option, theme, element)), { notMerge: false });
317
+ appliedOptionRef.current = option;
318
+ }, [option, theme]);
319
+ const heightValue = typeof height === "number" ? `${height}px` : height;
320
+ const effectiveAriaLabel = ariaLabel ?? title ?? labels.chart;
321
+ const hasTable = Boolean(tableData?.length && tableHeaders?.length);
322
+ const extraTables = (tables ?? []).filter((table) => table.headers.length && table.rows.length);
323
+ const describedBy = [hasTable ? tableId : null, ...extraTables.map((_, index) => `${tableId}-${index}`)].filter(Boolean).join(" ") || void 0;
324
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cx("uix-chart", className), style, children: [
325
+ title != null || subtitle != null || header != null || headerAction != null ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "uix-chart__header", children: [
326
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "uix-chart__heading", children: [
327
+ header,
328
+ title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__title", children: title }) : null,
329
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__subtitle", children: subtitle }) : null
330
+ ] }),
331
+ headerAction
332
+ ] }) : null,
333
+ hasEmpty ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__plot", "data-empty": true, children: empty }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "uix-chart__plot", "data-loading": loading || void 0, "aria-busy": loading || void 0, children: [
334
+ loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "uix-chart__loading", children: labels.loading }) : null,
335
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
336
+ "div",
337
+ {
338
+ ref: containerRef,
339
+ style: { height: heightValue },
340
+ role: "img",
341
+ "aria-label": effectiveAriaLabel,
342
+ "aria-describedby": describedBy
343
+ }
344
+ )
345
+ ] }),
346
+ hasTable ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { id: tableId, className: "uix-visually-hidden", "aria-label": `${effectiveAriaLabel} \u2014 ${labels.dataTableSuffix}`, children: [
347
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { children: tableHeaders.map((label) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: label }, label)) }) }),
348
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: tableData.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { children: tableHeaders.map((label) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: row[label] }, label)) }, index)) })
349
+ ] }) : null,
350
+ extraTables.map((table, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { id: `${tableId}-${index}`, className: "uix-visually-hidden", "aria-label": table.caption, children: [
351
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { children: table.headers.map((label) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: label }, label)) }) }),
352
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: table.rows.map((row, rowIndex) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { children: table.headers.map((label) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: row[label] }, label)) }, rowIndex)) })
353
+ ] }, index)),
354
+ footer != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__footer", children: footer })
355
+ ] });
356
+ }
357
+ function ChartMetric({ value, label, delta, deltaTone = "neutral", className, ...props }) {
358
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cx("uix-chart__metric", className), ...props, children: [
359
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__metric-value", children: value }),
360
+ label != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__metric-label", children: label }),
361
+ delta != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__delta", "data-tone": deltaTone, children: delta })
362
+ ] });
363
+ }
364
+ function ChartLegend({ children, className, ...props }) {
365
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: cx("uix-legend", className), ...props, children });
366
+ }
367
+ function ChartLegendItem({ label, color, swatch = "block", className, style, ...props }) {
368
+ const mergedStyle = color ? { "--legend-color": color, ...style } : style;
369
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: cx("uix-legend__item", className), style: mergedStyle, ...props, children: [
370
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: cx("uix-legend__swatch", swatch !== "block" && `uix-legend__swatch--${swatch}`), "aria-hidden": "true" }),
371
+ label
372
+ ] });
373
+ }
374
+
375
+ // src/components/ChartPanels.tsx
376
+ var import_react2 = require("react");
377
+
378
+ // src/chart-analytic-model.ts
379
+ var DEFAULT_ANALYTIC_LABELS = {
380
+ projection: "Projection",
381
+ range: (level) => `${Math.round(level * 100)}% range`,
382
+ partial: "Partial",
383
+ crossed: (x) => `Crossed ${x}`,
384
+ lower: "Lower",
385
+ upper: "Upper",
386
+ threshold: "Threshold",
387
+ event: "Event",
388
+ formatX: (x) => String(x)
389
+ };
390
+ var GUTTER_LABEL_WIDTH = 88;
391
+ var markLineBase = (data) => ({
392
+ silent: true,
393
+ symbol: "none",
394
+ animation: false,
395
+ data
396
+ });
397
+ var markAreaBase = (data) => ({ silent: true, animation: false, data });
398
+ function combineMarks(...fragments) {
399
+ const lines = [];
400
+ const areas = [];
401
+ const points = [];
402
+ for (const fragment of fragments) {
403
+ if (!fragment) continue;
404
+ if (fragment.markLine?.data) lines.push(...fragment.markLine.data);
405
+ if (fragment.markArea?.data) areas.push(...fragment.markArea.data);
406
+ if (fragment.markPoint?.data) points.push(...fragment.markPoint.data);
407
+ }
408
+ const out = {};
409
+ if (lines.length) out.markLine = markLineBase(lines);
410
+ if (areas.length) out.markArea = markAreaBase(areas);
411
+ if (points.length) out.markPoint = { animation: false, data: points };
412
+ return out;
413
+ }
414
+ var zoneColor = (tone, tokens) => tone === "danger" ? tokens.zoneDanger : tone === "warning" ? tokens.zoneWarning : tokens.forecastBand;
415
+ function thresholdMarks(thresholds, options) {
416
+ const { tokens, extent } = options;
417
+ const lines = [];
418
+ const areas = [];
419
+ for (const threshold of thresholds) {
420
+ if (!Number.isFinite(threshold.value)) continue;
421
+ const zoneTo = threshold.to ?? (threshold.badSide && extent ? threshold.badSide === "above" ? extent[1] : extent[0] : void 0);
422
+ if (zoneTo != null && Number.isFinite(zoneTo) && zoneTo !== threshold.value) {
423
+ areas.push([
424
+ { yAxis: Math.min(threshold.value, zoneTo), itemStyle: { color: zoneColor(threshold.tone, tokens) } },
425
+ { yAxis: Math.max(threshold.value, zoneTo) }
426
+ ]);
427
+ }
428
+ lines.push({
429
+ yAxis: threshold.value,
430
+ lineStyle: { color: tokens.reference, width: 1, type: "solid" },
431
+ label: {
432
+ show: true,
433
+ position: "end",
434
+ formatter: threshold.label,
435
+ color: tokens.textMuted,
436
+ fontFamily: tokens.fontSans,
437
+ fontSize: 11,
438
+ width: GUTTER_LABEL_WIDTH,
439
+ overflow: "truncate",
440
+ distance: 6
441
+ }
442
+ });
443
+ }
444
+ return combineMarks(
445
+ lines.length ? { markLine: markLineBase(lines) } : null,
446
+ areas.length ? { markArea: markAreaBase(areas) } : null
447
+ );
448
+ }
449
+ var PIN_SYMBOL = {
450
+ neutral: "circle",
451
+ warning: "triangle",
452
+ danger: "diamond"
453
+ };
454
+ function eventMarks(events, options) {
455
+ const { tokens } = options;
456
+ const lines = [];
457
+ const areas = [];
458
+ events.forEach((event) => {
459
+ if (event.to != null) {
460
+ areas.push([{ xAxis: event.at, itemStyle: { color: tokens.forecastBand } }, { xAxis: event.to }]);
461
+ }
462
+ lines.push({ xAxis: event.at, lineStyle: { color: tokens.event, width: 1, type: "solid", opacity: 0.7 }, label: { show: false } });
463
+ });
464
+ const lane = {
465
+ series: {
466
+ id: options.seriesId ?? "uix-event-lane",
467
+ type: "scatter",
468
+ xAxisIndex: options.xAxisIndex ?? 0,
469
+ yAxisIndex: options.yAxisIndex ?? 0,
470
+ data: events.map((event, index) => ({
471
+ value: [event.at, 0, index],
472
+ symbol: PIN_SYMBOL[event.tone ?? "neutral"]
473
+ })),
474
+ symbolSize: 10,
475
+ itemStyle: { color: tokens.event, borderColor: tokens.surface, borderWidth: 2 },
476
+ emphasis: { scale: 1.3 },
477
+ cursor: "pointer",
478
+ animation: false,
479
+ z: 5
480
+ }
481
+ };
482
+ return {
483
+ ...combineMarks(
484
+ lines.length ? { markLine: markLineBase(lines) } : null,
485
+ areas.length ? { markArea: markAreaBase(areas) } : null
486
+ ),
487
+ lane
488
+ };
489
+ }
490
+ function forecastSeries(forecast, options) {
491
+ const labels = { ...DEFAULT_ANALYTIC_LABELS, ...options.labels };
492
+ const { tokens } = options;
493
+ const color = tokens.palette[(options.colorIndex ?? 0) % tokens.palette.length] || tokens.palette[0];
494
+ const stack = `${options.idPrefix ?? "forecast"}-band`;
495
+ const axes = { xAxisIndex: options.xAxisIndex ?? 0, yAxisIndex: options.yAxisIndex ?? 0 };
496
+ const points = forecast.points.filter((p) => [p.y, p.lower, p.upper].every(Number.isFinite));
497
+ const start = options.fromValue != null && Number.isFinite(options.fromValue) ? [{ x: forecast.from, y: options.fromValue, lower: options.fromValue, upper: options.fromValue }] : [];
498
+ const all = [...start, ...points];
499
+ const last = points[points.length - 1];
500
+ const prefix = options.idPrefix ?? "forecast";
501
+ return [
502
+ {
503
+ id: `${prefix}-lower`,
504
+ name: `${options.name} \xB7 ${labels.lower}`,
505
+ type: "line",
506
+ ...axes,
507
+ stack,
508
+ data: all.map((p) => [p.x, p.lower]),
509
+ lineStyle: { opacity: 0 },
510
+ symbol: "none",
511
+ silent: true,
512
+ tooltip: { show: false },
513
+ animation: false,
514
+ z: 1
515
+ },
516
+ {
517
+ id: `${prefix}-band`,
518
+ name: `${options.name} \xB7 ${labels.range(forecast.level)}`,
519
+ type: "line",
520
+ ...axes,
521
+ stack,
522
+ data: all.map((p) => [p.x, p.upper - p.lower]),
523
+ lineStyle: { opacity: 0 },
524
+ areaStyle: { color: tokens.forecastBand, opacity: 1 },
525
+ symbol: "none",
526
+ silent: true,
527
+ tooltip: { show: false },
528
+ animation: false,
529
+ z: 1
530
+ },
531
+ {
532
+ id: `${prefix}-centre`,
533
+ name: `${options.name} \xB7 ${labels.projection}`,
534
+ type: "line",
535
+ ...axes,
536
+ data: all.map((p) => [p.x, p.y]),
537
+ lineStyle: { color, width: 2, type: "dashed" },
538
+ itemStyle: { color },
539
+ symbol: "none",
540
+ animation: false,
541
+ z: 3,
542
+ ...last ? {
543
+ markArea: markAreaBase([[
544
+ {
545
+ xAxis: forecast.from,
546
+ itemStyle: { color: "transparent" },
547
+ label: { show: true, position: "insideTop", formatter: labels.projection, color: tokens.textMuted, fontFamily: tokens.fontSans, fontSize: 11 }
548
+ },
549
+ { xAxis: last.x }
550
+ ]])
551
+ } : {}
552
+ }
553
+ ];
554
+ }
555
+ function comparisonSeries(comparison, options) {
556
+ return {
557
+ id: options.id ?? "comparison",
558
+ name: comparison.label,
559
+ type: "line",
560
+ xAxisIndex: options.xAxisIndex ?? 0,
561
+ yAxisIndex: options.yAxisIndex ?? 0,
562
+ data: options.x.map((x, i) => [x, comparison.values[i] ?? null]),
563
+ lineStyle: { color: options.tokens.comparison, width: 1.5, type: "solid" },
564
+ itemStyle: { color: options.tokens.comparison },
565
+ symbol: "none",
566
+ connectNulls: false,
567
+ animation: false,
568
+ z: 1
569
+ };
570
+ }
571
+ function partialPeriod(lastX, options) {
572
+ const labels = { ...DEFAULT_ANALYTIC_LABELS, ...options.labels };
573
+ return {
574
+ markArea: markAreaBase([[
575
+ {
576
+ xAxis: options.from ?? lastX,
577
+ itemStyle: { color: options.tokens.partial },
578
+ label: { show: true, position: "insideBottom", formatter: labels.partial, color: options.tokens.textMuted, fontFamily: options.tokens.fontSans, fontSize: 11 }
579
+ },
580
+ { xAxis: lastX }
581
+ ]])
582
+ };
583
+ }
584
+ function findCrossings(values, threshold) {
585
+ const side = threshold.badSide ?? (threshold.kind === "floor" ? "below" : "above");
586
+ const bad = (v) => side === "above" ? v > threshold.value : v < threshold.value;
587
+ const out = [];
588
+ let previous = null;
589
+ values.forEach((value, index) => {
590
+ if (value == null || !Number.isFinite(value)) {
591
+ previous = null;
592
+ return;
593
+ }
594
+ const isBad = bad(value);
595
+ if (isBad && previous === false) out.push(index);
596
+ previous = isBad;
597
+ });
598
+ return out;
599
+ }
600
+ function crossingPoints(values, threshold, options) {
601
+ const labels = { ...DEFAULT_ANALYTIC_LABELS, ...options.labels };
602
+ const crossings = findCrossings(values, threshold);
603
+ const label = (text, show) => ({
604
+ show,
605
+ position: "top",
606
+ distance: 8,
607
+ formatter: text,
608
+ color: options.tokens.text,
609
+ fontFamily: options.tokens.fontSans,
610
+ fontSize: 11
611
+ });
612
+ const data = crossings.map((index, i) => {
613
+ const text = labels.crossed(labels.formatX(options.x[index]));
614
+ const latest = i === crossings.length - 1;
615
+ return {
616
+ name: text,
617
+ coord: [options.x[index], values[index]],
618
+ symbol: "circle",
619
+ symbolSize: 10,
620
+ itemStyle: { color: options.tokens.surface, borderColor: options.tokens.text, borderWidth: 2 },
621
+ label: label(text, latest),
622
+ ...latest ? {} : { emphasis: { label: label(text, true) } }
623
+ };
624
+ });
625
+ return data.length ? { markPoint: { animation: false, data } } : {};
626
+ }
627
+
628
+ // src/chart-panels-model.ts
629
+ var defaultNumber = new Intl.NumberFormat("en", { maximumFractionDigits: 1 });
630
+ var DEFAULT_CHART_PANELS_LABELS = {
631
+ ...DEFAULT_ANALYTIC_LABELS,
632
+ x: "Period",
633
+ table: (title) => `${title} \u2014 data table`,
634
+ formatValue: (value, unit) => {
635
+ const text = defaultNumber.format(value);
636
+ if (!unit) return text;
637
+ return unit === "%" ? `${text}%` : `${text} ${unit}`;
638
+ }
639
+ };
640
+ var CHART_PANELS_LAYOUT = {
641
+ top: 8,
642
+ lane: 14,
643
+ laneGap: 10,
644
+ title: 28,
645
+ panelHeight: 112,
646
+ panelGap: 14,
647
+ axisBand: 30,
648
+ left: 52,
649
+ right: 16,
650
+ gutter: 100
651
+ };
652
+ function niceCeil(value) {
653
+ if (!(value > 0)) return value === 0 ? 1 : value;
654
+ const exponent = Math.floor(Math.log10(value));
655
+ const base = 10 ** exponent;
656
+ for (const step of [1, 1.2, 1.5, 2, 2.5, 3, 4, 5, 6, 8, 10]) {
657
+ if (step * base >= value - 1e-12) return step * base;
658
+ }
659
+ return 10 * base;
660
+ }
661
+ var escapeHtml = (text) => text.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c] ?? c);
662
+ var finite = (v) => typeof v === "number" && Number.isFinite(v);
663
+ var sameX = (a, b) => String(a) === String(b);
664
+ function chartPanelsModel(spec, tokens, labelOverrides) {
665
+ const labels = { ...DEFAULT_CHART_PANELS_LABELS, ...labelOverrides };
666
+ const L = CHART_PANELS_LAYOUT;
667
+ const events = spec.events ?? [];
668
+ const hasLane = events.length > 0;
669
+ const hasGutter = spec.panels.some((panel) => panel.thresholds?.length);
670
+ const right = hasGutter ? L.gutter : L.right;
671
+ const anyBar = spec.panels.some((panel) => panel.kind === "bar");
672
+ const categories = [...spec.x.values];
673
+ for (const panel of spec.panels) {
674
+ for (const point of panel.forecast?.points ?? []) {
675
+ if (!categories.some((x) => sameX(x, point.x))) categories.push(point.x);
676
+ }
677
+ }
678
+ const lastActual = spec.x.values[spec.x.values.length - 1];
679
+ const previousActual = spec.x.values[spec.x.values.length - 2];
680
+ const grids = [];
681
+ const xAxes = [];
682
+ const yAxes = [];
683
+ const series = [];
684
+ const seriesPanel = {};
685
+ const legend = [];
686
+ let cursor = L.top;
687
+ const xAxisBase = (gridIndex, showLabels) => {
688
+ const common = {
689
+ gridIndex,
690
+ axisLabel: {
691
+ show: showLabels,
692
+ hideOverlap: true,
693
+ showMaxLabel: true,
694
+ // the first and last labels align inward, so neither runs into the y-axis labels or the gutter
695
+ alignMinLabel: "left",
696
+ alignMaxLabel: "right",
697
+ formatter: (value) => labels.formatX(value)
698
+ },
699
+ axisLine: { show: true },
700
+ splitLine: { show: false }
701
+ };
702
+ return spec.x.type === "time" ? { type: "time", ...common } : { type: "category", data: categories.map(String), boundaryGap: anyBar, ...common };
703
+ };
704
+ let laneSeriesId = "";
705
+ let eventFragment = null;
706
+ if (hasLane) {
707
+ grids.push({ top: cursor, height: L.lane, left: L.left, right, containLabel: false });
708
+ xAxes.push({ ...xAxisBase(0, false), axisLine: { show: false } });
709
+ yAxes.push({ type: "value", gridIndex: 0, min: -1, max: 1, show: false });
710
+ const marks = eventMarks(events, { tokens, xAxisIndex: 0, yAxisIndex: 0, seriesId: "uix-event-lane" });
711
+ laneSeriesId = "uix-event-lane";
712
+ series.push(marks.lane.series);
713
+ eventFragment = { markLine: marks.markLine, markArea: marks.markArea };
714
+ cursor += L.lane + L.laneGap;
715
+ }
716
+ const tables = [];
717
+ spec.panels.forEach((panel, panelIndex) => {
718
+ const gridIndex = grids.length;
719
+ const isLast = panelIndex === spec.panels.length - 1;
720
+ const height = panel.height ?? L.panelHeight;
721
+ cursor += L.title;
722
+ grids.push({ top: cursor, height, left: L.left, right, containLabel: false });
723
+ cursor += height + (isLast ? L.axisBand : L.panelGap);
724
+ const values = [];
725
+ for (const s of panel.series) values.push(...s.values.filter(finite));
726
+ values.push(...panel.comparison?.values.filter(finite) ?? []);
727
+ for (const p of panel.forecast?.points ?? []) values.push(p.lower, p.upper, p.y);
728
+ for (const t of panel.thresholds ?? []) values.push(t.value, ...finite(t.to) ? [t.to] : []);
729
+ const usable = values.filter(Number.isFinite);
730
+ const dataMax = usable.length ? Math.max(...usable) : 1;
731
+ const dataMin = usable.length ? Math.min(...usable) : 0;
732
+ const max = niceCeil(dataMax * 1.08);
733
+ const min = dataMin < 0 ? -niceCeil(-dataMin * 1.08) : 0;
734
+ xAxes.push(xAxisBase(gridIndex, isLast));
735
+ yAxes.push({
736
+ type: "value",
737
+ gridIndex,
738
+ min,
739
+ max,
740
+ // three ticks (min, half way, max): a short panel never prints a crowded extra max label
741
+ interval: (max - min) / 2,
742
+ name: panel.unit ? `${panel.title} (${panel.unit})` : panel.title,
743
+ nameLocation: "end",
744
+ nameGap: 14,
745
+ nameTextStyle: { align: "left", padding: [0, 0, 0, -L.left + 4], color: tokens.text, fontFamily: tokens.fontSans, fontSize: 12, fontWeight: 600, width: 320, overflow: "truncate" },
746
+ axisLabel: { formatter: (value) => labels.formatValue(value, panel.unit === "%" ? "%" : void 0) }
747
+ });
748
+ const axes = { xAxisIndex: gridIndex, yAxisIndex: gridIndex };
749
+ const pairs = (vals) => spec.x.values.map((x, i) => [x, vals[i] ?? null]);
750
+ panel.series.forEach((s, seriesIndex) => {
751
+ const colorIndex = s.colorIndex ?? seriesIndex;
752
+ const color = tokens.palette[colorIndex % tokens.palette.length];
753
+ const id = `${panel.id}:${s.id}`;
754
+ seriesPanel[id] = panel.id;
755
+ const isPrimary = seriesIndex === 0;
756
+ let marks = {};
757
+ if (isPrimary) {
758
+ const crossings = (panel.thresholds ?? []).filter((t) => t.kind !== "target" && (t.badSide || t.kind === "limit" || t.kind === "budget" || t.kind === "floor")).slice(0, 1).map((t) => crossingPoints(s.values.slice(0, spec.x.values.length), t, { x: spec.x.values, tokens, labels }));
759
+ marks = combineMarks(
760
+ panel.thresholds?.length ? thresholdMarks(panel.thresholds, { tokens, extent: [min, max] }) : null,
761
+ eventFragment,
762
+ spec.partialLast && lastActual != null ? partialWash(partialPeriod(lastActual, { tokens, from: previousActual, labels }), panelIndex === 0) : null,
763
+ ...crossings
764
+ );
765
+ }
766
+ if (panel.kind === "bar") {
767
+ series.push({
768
+ id,
769
+ name: s.label,
770
+ type: "bar",
771
+ ...axes,
772
+ data: pairs(s.values),
773
+ barMaxWidth: 24,
774
+ itemStyle: { color, borderRadius: [4, 4, 0, 0], borderColor: tokens.surface, borderWidth: 1 },
775
+ animation: false,
776
+ z: 2,
777
+ ...marks
778
+ });
779
+ } else {
780
+ series.push({
781
+ id,
782
+ name: s.label,
783
+ type: "line",
784
+ ...axes,
785
+ data: pairs(s.values),
786
+ symbol: "circle",
787
+ symbolSize: 8,
788
+ showSymbol: false,
789
+ connectNulls: false,
790
+ lineStyle: { color, width: 2, type: "solid" },
791
+ itemStyle: { color, borderColor: tokens.surface, borderWidth: 2 },
792
+ ...panel.kind === "area" ? { areaStyle: { color: uixChartAreaGradient(color) } } : {},
793
+ emphasis: { focus: "none" },
794
+ animation: false,
795
+ z: 2,
796
+ ...marks
797
+ });
798
+ }
799
+ if (panel.series.length > 1 || panel.comparison || panel.forecast) legend.push({ label: s.label, color, swatch: panel.kind === "bar" ? "block" : "line" });
800
+ });
801
+ if (panel.comparison) {
802
+ const id = `${panel.id}:comparison`;
803
+ seriesPanel[id] = panel.id;
804
+ series.push(comparisonSeries(panel.comparison, { x: spec.x.values, tokens, ...axes, id }));
805
+ if (!legend.some((item) => item.label === panel.comparison.label)) legend.push({ label: panel.comparison.label, color: tokens.comparison, swatch: "line" });
806
+ }
807
+ if (panel.forecast && panel.series[0]) {
808
+ const primary = panel.series[0];
809
+ const fromIndex = spec.x.values.findIndex((x) => sameX(x, panel.forecast.from));
810
+ const fromValue = fromIndex >= 0 ? primary.values[fromIndex] ?? null : null;
811
+ const colorIndex = primary.colorIndex ?? 0;
812
+ const fc = forecastSeries(panel.forecast, { name: primary.label, colorIndex, tokens, labels, fromValue, ...axes, idPrefix: `${panel.id}:forecast` });
813
+ for (const s of fc) seriesPanel[String(s.id)] = panel.id;
814
+ series.push(...fc);
815
+ if (!legend.some((item) => item.swatch === "dash")) {
816
+ legend.push({ label: labels.projection, color: tokens.palette[colorIndex % tokens.palette.length], swatch: "dash" });
817
+ legend.push({ label: labels.range(panel.forecast.level), color: tokens.forecastBand, swatch: "block" });
818
+ }
819
+ }
820
+ tables.push(panelTable(spec, panel, categories, events, labels));
821
+ });
822
+ const allX = xAxes.map((_, i) => i);
823
+ const option = {
824
+ animation: false,
825
+ grid: grids,
826
+ xAxis: xAxes,
827
+ yAxis: yAxes,
828
+ axisPointer: { link: [{ xAxisIndex: "all" }], label: { show: false } },
829
+ tooltip: {
830
+ trigger: "axis",
831
+ confine: true,
832
+ axisPointer: { type: "line" },
833
+ formatter: (params) => tooltipHtml(params, spec, categories, events, labels)
834
+ },
835
+ series,
836
+ ...spec.zoom ? { dataZoom: [{ type: "inside", xAxisIndex: allX, filterMode: "none" }] } : {}
837
+ };
838
+ return { option, height: cursor, legend, tables, categories, seriesPanel, laneSeriesId };
839
+ }
840
+ function partialWash(marks, labelled) {
841
+ if (labelled || !marks.markArea?.data) return marks;
842
+ const data = marks.markArea.data.map(([from, to]) => [{ ...from, label: { show: false } }, to]);
843
+ return { markArea: { ...marks.markArea, data } };
844
+ }
845
+ function panelTable(spec, panel, categories, events, labels) {
846
+ const headers = [labels.x, ...panel.series.map((s) => s.label)];
847
+ if (panel.comparison) headers.push(panel.comparison.label);
848
+ if (panel.forecast) headers.push(labels.projection, labels.lower, labels.upper);
849
+ for (const t of panel.thresholds ?? []) headers.push(`${labels.threshold}: ${t.label}`);
850
+ if (events.length) headers.push(labels.event);
851
+ const unit = panel.unit;
852
+ const fmt = (v) => finite(v) ? labels.formatValue(v, unit) : "";
853
+ const rows = categories.map((x, i) => {
854
+ const row = { [labels.x]: labels.formatX(x) };
855
+ for (const s of panel.series) row[s.label] = i < spec.x.values.length ? fmt(s.values[i]) : "";
856
+ if (panel.comparison) row[panel.comparison.label] = i < spec.x.values.length ? fmt(panel.comparison.values[i]) : "";
857
+ if (panel.forecast) {
858
+ const p = panel.forecast.points.find((point) => sameX(point.x, x));
859
+ row[labels.projection] = fmt(p?.y);
860
+ row[labels.lower] = fmt(p?.lower);
861
+ row[labels.upper] = fmt(p?.upper);
862
+ }
863
+ for (const t of panel.thresholds ?? []) row[`${labels.threshold}: ${t.label}`] = finite(t.to) ? `${fmt(t.value)}\u2013${fmt(t.to)}` : fmt(t.value);
864
+ if (events.length) row[labels.event] = events.filter((e) => sameX(e.at, x)).map((e) => e.label).join("; ");
865
+ return row;
866
+ });
867
+ return { caption: labels.table(panel.title), headers, rows };
868
+ }
869
+ function tooltipHtml(params, spec, categories, events, labels) {
870
+ const list = Array.isArray(params) ? params : [params];
871
+ const first = list[0];
872
+ if (!first) return "";
873
+ const axisValue = first.axisValue ?? (Array.isArray(first.value) ? first.value[0] : void 0);
874
+ const index = categories.findIndex((x2) => sameX(x2, axisValue));
875
+ if (index < 0) return "";
876
+ const x = categories[index];
877
+ const lines = [`<div style="font-weight:600;margin-bottom:4px">${escapeHtml(labels.formatX(x))}</div>`];
878
+ const row = (name, value) => `<div style="display:flex;justify-content:space-between;gap:16px"><span>${escapeHtml(name)}</span><span style="font-variant-numeric:tabular-nums">${escapeHtml(value)}</span></div>`;
879
+ for (const panel of spec.panels) {
880
+ for (const s of panel.series) {
881
+ const v = index < spec.x.values.length ? s.values[index] : null;
882
+ if (finite(v)) lines.push(row(s.label, labels.formatValue(v, panel.unit)));
883
+ }
884
+ const c = panel.comparison && index < spec.x.values.length ? panel.comparison.values[index] : null;
885
+ if (panel.comparison && finite(c)) lines.push(row(panel.comparison.label, labels.formatValue(c, panel.unit)));
886
+ const p = panel.forecast?.points.find((point) => sameX(point.x, x));
887
+ if (p && panel.forecast) {
888
+ lines.push(row(`${labels.projection} (${panel.forecast.method})`, labels.formatValue(p.y, panel.unit)));
889
+ lines.push(row(labels.range(panel.forecast.level), `${labels.formatValue(p.lower, panel.unit)} \u2013 ${labels.formatValue(p.upper, panel.unit)}`));
890
+ }
891
+ }
892
+ for (const e of events.filter((event) => sameX(event.at, x))) lines.push(row(e.kind, e.label));
893
+ if (spec.partialLast && index === spec.x.values.length - 1) lines.push(`<div style="opacity:.75">${escapeHtml(labels.partial)}</div>`);
894
+ return lines.join("");
895
+ }
896
+
897
+ // src/chart-stats.ts
898
+ var finite2 = (value) => typeof value === "number" && Number.isFinite(value);
899
+ function linearFit(points) {
900
+ const usable = points.filter((p) => finite2(p.x) && finite2(p.y));
901
+ const n = usable.length;
902
+ if (n < 2) return null;
903
+ let sumX = 0;
904
+ let sumY = 0;
905
+ for (const p of usable) {
906
+ sumX += p.x;
907
+ sumY += p.y;
908
+ }
909
+ const xMean = sumX / n;
910
+ const yMean = sumY / n;
911
+ let sxx = 0;
912
+ let syy = 0;
913
+ let sxy = 0;
914
+ for (const p of usable) {
915
+ const dx = p.x - xMean;
916
+ const dy = p.y - yMean;
917
+ sxx += dx * dx;
918
+ syy += dy * dy;
919
+ sxy += dx * dy;
920
+ }
921
+ if (sxx === 0) return null;
922
+ const slope = sxy / sxx;
923
+ const intercept = yMean - slope * xMean;
924
+ let sse = 0;
925
+ for (const p of usable) {
926
+ const residual = p.y - (intercept + slope * p.x);
927
+ sse += residual * residual;
928
+ }
929
+ const r = syy === 0 ? null : Math.max(-1, Math.min(1, sxy / Math.sqrt(sxx * syy)));
930
+ const residualStdError = n > 2 ? Math.sqrt(sse / (n - 2)) : 0;
931
+ return { slope, intercept, r, n, xMean, sxx, residualStdError };
932
+ }
933
+ function quantiles(values, ps) {
934
+ const sorted = values.filter(finite2).slice().sort((a, b) => a - b);
935
+ return ps.map((p) => {
936
+ if (!sorted.length || !finite2(p)) return null;
937
+ const clamped = Math.max(0, Math.min(1, p));
938
+ const h = (sorted.length - 1) * clamped;
939
+ const lo = Math.floor(h);
940
+ const hi = Math.ceil(h);
941
+ return sorted[lo] + (h - lo) * (sorted[hi] - sorted[lo]);
942
+ });
943
+ }
944
+ function normalQuantile(p) {
945
+ if (!(p > 0 && p < 1)) return p === 0 ? -Infinity : p === 1 ? Infinity : Number.NaN;
946
+ const a = [-39.69683028665376, 220.9460984245205, -275.9285104469687, 138.357751867269, -30.66479806614716, 2.506628277459239];
947
+ const b = [-54.47609879822406, 161.5858368580409, -155.6989798598866, 66.80131188771972, -13.28068155288572];
948
+ const c = [-0.007784894002430293, -0.3223964580411365, -2.400758277161838, -2.549732539343734, 4.374664141464968, 2.938163982698783];
949
+ const d = [0.007784695709041462, 0.3224671290700398, 2.445134137142996, 3.754408661907416];
950
+ const low = 0.02425;
951
+ if (p < low) {
952
+ const q2 = Math.sqrt(-2 * Math.log(p));
953
+ return (((((c[0] * q2 + c[1]) * q2 + c[2]) * q2 + c[3]) * q2 + c[4]) * q2 + c[5]) / ((((d[0] * q2 + d[1]) * q2 + d[2]) * q2 + d[3]) * q2 + 1);
954
+ }
955
+ if (p > 1 - low) {
956
+ const q2 = Math.sqrt(-2 * Math.log(1 - p));
957
+ return -(((((c[0] * q2 + c[1]) * q2 + c[2]) * q2 + c[3]) * q2 + c[4]) * q2 + c[5]) / ((((d[0] * q2 + d[1]) * q2 + d[2]) * q2 + d[3]) * q2 + 1);
958
+ }
959
+ const q = p - 0.5;
960
+ const r = q * q;
961
+ return (((((a[0] * r + a[1]) * r + a[2]) * r + a[3]) * r + a[4]) * r + a[5]) * q / (((((b[0] * r + b[1]) * r + b[2]) * r + b[3]) * r + b[4]) * r + 1);
962
+ }
963
+ function studentTQuantile(p, df) {
964
+ const z = normalQuantile(p);
965
+ if (!Number.isFinite(z) || !(df > 0)) return z;
966
+ const z3 = z ** 3;
967
+ const z5 = z ** 5;
968
+ const z7 = z ** 7;
969
+ return z + (z3 + z) / (4 * df) + (5 * z5 + 16 * z3 + 3 * z) / (96 * df ** 2) + (3 * z7 + 19 * z5 + 17 * z3 - 15 * z) / (384 * df ** 3);
970
+ }
971
+ function predictionBand(fit, xs, level = 0.8) {
972
+ const coverage = Math.max(0.01, Math.min(0.999, level));
973
+ const t = fit.n > 2 ? studentTQuantile(1 - (1 - coverage) / 2, fit.n - 2) : 0;
974
+ return xs.filter(finite2).map((x) => {
975
+ const y = fit.intercept + fit.slope * x;
976
+ const spread = t * fit.residualStdError * Math.sqrt(1 + 1 / fit.n + (x - fit.xMean) ** 2 / fit.sxx);
977
+ return { x, y, lower: y - spread, upper: y + spread };
978
+ });
979
+ }
980
+
981
+ // src/correlation-scatter-model.ts
982
+ var defaultNumber2 = new Intl.NumberFormat("en", { maximumFractionDigits: 2 });
983
+ function formatCorrelation(r) {
984
+ const shown = Math.abs(r) < 1 ? Math.trunc(r * 100) / 100 : Math.sign(r);
985
+ return shown.toFixed(2);
986
+ }
987
+ var DEFAULT_CORRELATION_SCATTER_LABELS = {
988
+ stats: ({ r, n }) => `${r == null ? "" : `r = ${formatCorrelation(r)} \xB7 `}n = ${n} \xB7 association, not cause`,
989
+ notEnough: (n, min) => `Not enough data (n = ${n} of ${min})`,
990
+ percentile: (p) => `p${p}`,
991
+ trend: "Trend",
992
+ point: "Point",
993
+ formatX: (x) => defaultNumber2.format(x),
994
+ formatY: (y) => defaultNumber2.format(y)
995
+ };
996
+ var SCATTER_HIT_SIZE = 26;
997
+ var DOT_SIZE = 9;
998
+ var escapeHtml2 = (text) => text.replace(/[&<>"']/g, (c) => ({ "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;" })[c] ?? c);
999
+ var niceRange = (values) => {
1000
+ const lo = Math.min(...values);
1001
+ const hi = Math.max(...values);
1002
+ const max = niceCeil(hi > 0 ? hi * 1.08 : hi || 1);
1003
+ const min = lo >= 0 ? 0 : -niceCeil(-lo * 1.08);
1004
+ return [min, max];
1005
+ };
1006
+ function correlationScatterModel(spec, tokens, labelOverrides) {
1007
+ const labels = { ...DEFAULT_CORRELATION_SCATTER_LABELS, ...labelOverrides };
1008
+ const minPoints = Math.max(2, spec.minPoints ?? 8);
1009
+ const points = spec.points.filter((p) => Number.isFinite(p.x) && Number.isFinite(p.y));
1010
+ const n = points.length;
1011
+ const enough = n >= minPoints;
1012
+ const fit = enough && spec.trend !== "none" ? linearFit(points) : null;
1013
+ const statsText = labels.stats({ r: fit?.r ?? null, n });
1014
+ const xs = [...points.map((p) => p.x), ...(spec.thresholds?.x ?? []).map((t) => t.value), ...spec.breakpoint ? [spec.breakpoint.x] : []];
1015
+ const ys = [...points.map((p) => p.y), ...(spec.thresholds?.y ?? []).map((t) => t.value)];
1016
+ const [xMin, xMax] = xs.length ? niceRange(xs) : [0, 1];
1017
+ const [yMin, yMax] = ys.length ? niceRange(ys) : [0, 1];
1018
+ const dotData = points.map((p) => ({
1019
+ value: [p.x, p.y],
1020
+ symbol: p.emphasis === "danger" ? "diamond" : p.emphasis === "warning" ? "triangle" : "circle",
1021
+ symbolSize: p.emphasis ? DOT_SIZE + 3 : DOT_SIZE,
1022
+ itemStyle: {
1023
+ color: p.emphasis === "danger" ? tokens.danger : p.emphasis === "warning" ? tokens.warning : tokens.palette[0],
1024
+ borderColor: tokens.surface,
1025
+ borderWidth: 2,
1026
+ opacity: 1
1027
+ }
1028
+ }));
1029
+ const pcts = (spec.percentiles ?? []).filter((p) => p > 0 && p < 100);
1030
+ const pctValues = quantiles(points.map((p) => p.y), pcts.map((p) => p / 100));
1031
+ const percentileLines = enough && pcts.length ? {
1032
+ markLine: {
1033
+ silent: true,
1034
+ symbol: "none",
1035
+ animation: false,
1036
+ data: pcts.flatMap((p, i) => {
1037
+ const value = pctValues[i];
1038
+ return value == null ? [] : [{
1039
+ yAxis: value,
1040
+ lineStyle: { color: tokens.reference, width: 1, type: "solid", opacity: 0.6 },
1041
+ label: { show: true, position: "end", formatter: labels.percentile(p), color: tokens.textMuted, fontFamily: tokens.fontSans, fontSize: 11, distance: 6 }
1042
+ }];
1043
+ })
1044
+ }
1045
+ } : {};
1046
+ const xLines = {
1047
+ markLine: {
1048
+ silent: true,
1049
+ symbol: "none",
1050
+ animation: false,
1051
+ data: [
1052
+ ...(spec.thresholds?.x ?? []).map((t) => ({
1053
+ xAxis: t.value,
1054
+ lineStyle: { color: tokens.reference, width: 1, type: "solid" },
1055
+ label: { show: true, position: "end", formatter: t.label, color: tokens.textMuted, fontFamily: tokens.fontSans, fontSize: 11 }
1056
+ })),
1057
+ ...spec.breakpoint && enough ? [{
1058
+ xAxis: spec.breakpoint.x,
1059
+ lineStyle: { color: tokens.text, width: 1, type: "solid" },
1060
+ label: { show: true, position: "end", formatter: spec.breakpoint.label, color: tokens.text, fontFamily: tokens.fontSans, fontSize: 11, fontWeight: 600 }
1061
+ }] : []
1062
+ ]
1063
+ }
1064
+ };
1065
+ const marks = combineMarks(
1066
+ spec.thresholds?.y?.length ? thresholdMarks(spec.thresholds.y, { tokens, extent: [yMin, yMax] }) : null,
1067
+ percentileLines,
1068
+ (xLines.markLine?.data).length ? xLines : null
1069
+ );
1070
+ const series = [
1071
+ {
1072
+ id: "points",
1073
+ name: spec.yLabel,
1074
+ type: "scatter",
1075
+ data: dotData,
1076
+ silent: true,
1077
+ animation: false,
1078
+ z: 3,
1079
+ ...marks
1080
+ },
1081
+ {
1082
+ // the hit layer: transparent 24 px targets over the dots carry the tooltip and the click
1083
+ id: "points-hit",
1084
+ name: spec.yLabel,
1085
+ type: "scatter",
1086
+ data: points.map((p, index) => ({ value: [p.x, p.y, index] })),
1087
+ symbol: "circle",
1088
+ symbolSize: SCATTER_HIT_SIZE,
1089
+ itemStyle: { color: "rgba(0,0,0,0)" },
1090
+ emphasis: { itemStyle: { color: "rgba(0,0,0,0)", borderColor: tokens.text, borderWidth: 1 } },
1091
+ cursor: "pointer",
1092
+ animation: false,
1093
+ z: 4
1094
+ }
1095
+ ];
1096
+ if (fit) {
1097
+ series.push({
1098
+ id: "trend",
1099
+ name: labels.trend,
1100
+ type: "line",
1101
+ data: [[xMin, fit.intercept + fit.slope * xMin], [xMax, fit.intercept + fit.slope * xMax]],
1102
+ symbol: "none",
1103
+ silent: true,
1104
+ lineStyle: { color: tokens.reference, width: 1.5, type: "solid" },
1105
+ tooltip: { show: false },
1106
+ animation: false,
1107
+ clip: true,
1108
+ z: 2
1109
+ });
1110
+ }
1111
+ const option = {
1112
+ animation: false,
1113
+ grid: { top: 28, right: spec.thresholds?.y?.length || pcts.length ? 100 : 20, bottom: 44, left: 52, containLabel: false },
1114
+ xAxis: {
1115
+ type: "value",
1116
+ min: xMin,
1117
+ max: xMax,
1118
+ name: spec.xLabel,
1119
+ nameLocation: "middle",
1120
+ nameGap: 28,
1121
+ nameTextStyle: { color: tokens.textMuted, fontFamily: tokens.fontSans, fontSize: 12 },
1122
+ axisLabel: { formatter: (v) => labels.formatX(v) },
1123
+ splitLine: { show: true }
1124
+ },
1125
+ yAxis: {
1126
+ type: "value",
1127
+ min: yMin,
1128
+ max: yMax,
1129
+ name: spec.yLabel,
1130
+ nameLocation: "end",
1131
+ nameGap: 10,
1132
+ nameTextStyle: { align: "left", padding: [0, 0, 0, -48], color: tokens.textMuted, fontFamily: tokens.fontSans, fontSize: 12 },
1133
+ axisLabel: { formatter: (v) => labels.formatY(v) }
1134
+ },
1135
+ tooltip: {
1136
+ trigger: "item",
1137
+ confine: true,
1138
+ formatter: (params) => {
1139
+ const p = params;
1140
+ if (p.seriesId !== "points-hit" || !Array.isArray(p.value)) return "";
1141
+ const point = points[Number(p.value[2])];
1142
+ if (!point) return "";
1143
+ return `<div style="font-weight:600;margin-bottom:4px">${escapeHtml2(point.label)}</div><div>${escapeHtml2(spec.xLabel)}: ${escapeHtml2(labels.formatX(point.x))}</div><div>${escapeHtml2(spec.yLabel)}: ${escapeHtml2(labels.formatY(point.y))}</div>`;
1144
+ }
1145
+ },
1146
+ series
1147
+ };
1148
+ const headers = [labels.point, spec.xLabel, spec.yLabel];
1149
+ const rows = points.map((p) => ({ [labels.point]: p.label, [spec.xLabel]: labels.formatX(p.x), [spec.yLabel]: labels.formatY(p.y) }));
1150
+ return { enough, n, minPoints, fit, option, statsText, table: { headers, rows }, hitSeriesId: "points-hit" };
1151
+ }
1152
+
1153
+ // src/components/ChartPanels.tsx
1154
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1155
+ var CSS_VAR_TOKENS = {
1156
+ palette: [1, 2, 3, 4, 5, 6, 7, 8].map((i) => `var(--uix-chart-${i})`),
1157
+ neutral: "var(--uix-chart-neutral)",
1158
+ grid: "var(--uix-chart-grid)",
1159
+ axis: "var(--uix-chart-axis)",
1160
+ reference: "var(--uix-chart-reference)",
1161
+ zoneWarning: "var(--uix-chart-zone-warning)",
1162
+ zoneDanger: "var(--uix-chart-zone-danger)",
1163
+ forecastBand: "var(--uix-chart-forecast-band)",
1164
+ event: "var(--uix-chart-event)",
1165
+ partial: "var(--uix-chart-partial)",
1166
+ comparison: "var(--uix-chart-comparison)",
1167
+ warning: "var(--uix-warning)",
1168
+ danger: "var(--uix-danger)",
1169
+ surface: "var(--uix-surface)",
1170
+ text: "var(--uix-text)",
1171
+ textMuted: "var(--uix-text-muted)",
1172
+ border: "var(--uix-border-strong)",
1173
+ fontSans: "inherit",
1174
+ fontMono: "inherit"
1175
+ };
1176
+ function ChartPanelsCore({
1177
+ engine,
1178
+ x,
1179
+ panels,
1180
+ events,
1181
+ partialLast,
1182
+ zoom,
1183
+ ariaLabel,
1184
+ title,
1185
+ subtitle,
1186
+ header,
1187
+ headerAction,
1188
+ footer,
1189
+ loading,
1190
+ empty,
1191
+ className,
1192
+ group,
1193
+ labels,
1194
+ onPointClick,
1195
+ onEventClick,
1196
+ legend
1197
+ }) {
1198
+ const spec = (0, import_react2.useMemo)(() => ({ x, panels, events, partialLast, zoom }), [x, panels, events, partialLast, zoom]);
1199
+ const layout = (0, import_react2.useMemo)(() => chartPanelsModel(spec, CSS_VAR_TOKENS, labels), [spec, labels]);
1200
+ const option = (0, import_react2.useMemo)(() => (tokens) => chartPanelsModel(spec, tokens, labels).option, [spec, labels]);
1201
+ const onEvents = (0, import_react2.useMemo)(() => ({
1202
+ click: (raw) => {
1203
+ const params = raw;
1204
+ const value = Array.isArray(params.value) ? params.value : [];
1205
+ if (params.seriesId && params.seriesId === layout.laneSeriesId) {
1206
+ const event = spec.events?.[Number(value[2])];
1207
+ if (!event) return;
1208
+ if (onEventClick) onEventClick(event);
1209
+ else if (event.href && typeof window !== "undefined") window.location.assign(event.href);
1210
+ return;
1211
+ }
1212
+ const panelId = params.seriesId ? layout.seriesPanel[params.seriesId] : void 0;
1213
+ if (panelId && onPointClick) onPointClick(panelId, value[0] ?? params.name);
1214
+ }
1215
+ }), [layout, spec.events, onEventClick, onPointClick]);
1216
+ const showLegend = legend ?? layout.legend.length > 0;
1217
+ const legendNode = showLegend && layout.legend.length ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChartLegend, { children: layout.legend.map((item) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChartLegendItem, { label: item.label, color: item.color, swatch: item.swatch }, `${item.swatch}:${item.label}`)) }) : null;
1218
+ const footerNode = legendNode || footer != null ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1219
+ legendNode,
1220
+ footer
1221
+ ] }) : void 0;
1222
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1223
+ ChartCore,
1224
+ {
1225
+ engine,
1226
+ option,
1227
+ height: layout.height,
1228
+ ariaLabel,
1229
+ title,
1230
+ subtitle,
1231
+ header,
1232
+ headerAction,
1233
+ footer: footerNode,
1234
+ loading,
1235
+ empty,
1236
+ className,
1237
+ group,
1238
+ labels,
1239
+ onEvents,
1240
+ tables: layout.tables
1241
+ }
1242
+ );
1243
+ }
1244
+ function CorrelationScatterCore({
1245
+ engine,
1246
+ points,
1247
+ xLabel,
1248
+ yLabel,
1249
+ trend,
1250
+ percentiles,
1251
+ thresholds,
1252
+ breakpoint,
1253
+ minPoints,
1254
+ ariaLabel,
1255
+ title,
1256
+ subtitle,
1257
+ header,
1258
+ headerAction,
1259
+ footer,
1260
+ loading,
1261
+ empty,
1262
+ className,
1263
+ group,
1264
+ labels,
1265
+ showStats = true,
1266
+ height = 280,
1267
+ onPointClick
1268
+ }) {
1269
+ const spec = (0, import_react2.useMemo)(
1270
+ () => ({ points, xLabel, yLabel, trend, percentiles, thresholds, breakpoint, minPoints }),
1271
+ [points, xLabel, yLabel, trend, percentiles, thresholds, breakpoint, minPoints]
1272
+ );
1273
+ const layout = (0, import_react2.useMemo)(() => correlationScatterModel(spec, CSS_VAR_TOKENS, labels), [spec, labels]);
1274
+ const option = (0, import_react2.useMemo)(() => (tokens) => correlationScatterModel(spec, tokens, labels).option, [spec, labels]);
1275
+ const usable = (0, import_react2.useMemo)(() => spec.points.filter((p) => Number.isFinite(p.x) && Number.isFinite(p.y)), [spec.points]);
1276
+ const onEvents = (0, import_react2.useMemo)(() => ({
1277
+ click: (raw) => {
1278
+ const params = raw;
1279
+ if (params.seriesId !== layout.hitSeriesId || !Array.isArray(params.value)) return;
1280
+ const point = usable[Number(params.value[2])];
1281
+ if (!point) return;
1282
+ if (onPointClick) onPointClick(point);
1283
+ else if (point.href && typeof window !== "undefined") window.location.assign(point.href);
1284
+ }
1285
+ }), [layout.hitSeriesId, usable, onPointClick]);
1286
+ const notEnough = !layout.enough ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "uix-chart__insufficient", children: (labels?.notEnough ?? DEFAULT_CORRELATION_SCATTER_LABELS.notEnough)(layout.n, layout.minPoints) }) : null;
1287
+ const stats = showStats && layout.enough ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "uix-chart__stats", children: layout.statsText }) : null;
1288
+ const footerNode = stats || footer != null ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1289
+ stats,
1290
+ footer
1291
+ ] }) : void 0;
1292
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1293
+ ChartCore,
1294
+ {
1295
+ engine,
1296
+ option,
1297
+ height,
1298
+ ariaLabel,
1299
+ title,
1300
+ subtitle,
1301
+ header,
1302
+ headerAction,
1303
+ footer: footerNode,
1304
+ loading,
1305
+ empty: empty ?? notEnough ?? void 0,
1306
+ className,
1307
+ group,
1308
+ labels,
1309
+ onEvents,
1310
+ tableHeaders: layout.table.headers,
1311
+ tableData: layout.table.rows
1312
+ }
1313
+ );
1314
+ }
1315
+
1316
+ // src/chart-analytic.tsx
1317
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1318
+ echarts.use([
1319
+ import_charts.BarChart,
1320
+ import_charts.LineChart,
1321
+ import_charts.ScatterChart,
1322
+ import_components.AxisPointerComponent,
1323
+ import_components.DataZoomInsideComponent,
1324
+ import_components.GridComponent,
1325
+ import_components.LegendComponent,
1326
+ import_components.MarkAreaComponent,
1327
+ import_components.MarkLineComponent,
1328
+ import_components.MarkPointComponent,
1329
+ import_components.TooltipComponent,
1330
+ import_components.VisualMapPiecewiseComponent,
1331
+ import_renderers.SVGRenderer
1332
+ ]);
1333
+ var analyticEngine = echarts;
1334
+ function Chart(props) {
1335
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChartCore, { ...props, engine: analyticEngine });
1336
+ }
1337
+ function ChartPanels(props) {
1338
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChartPanelsCore, { ...props, engine: analyticEngine });
1339
+ }
1340
+ function CorrelationScatter(props) {
1341
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CorrelationScatterCore, { ...props, engine: analyticEngine });
1342
+ }
1343
+ // Annotate the CommonJS export names for ESM import in node:
1344
+ 0 && (module.exports = {
1345
+ CHART_PANELS_LAYOUT,
1346
+ Chart,
1347
+ ChartLegend,
1348
+ ChartLegendItem,
1349
+ ChartMetric,
1350
+ ChartPanels,
1351
+ CorrelationScatter,
1352
+ DEFAULT_ANALYTIC_LABELS,
1353
+ DEFAULT_CHART_LABELS,
1354
+ DEFAULT_CHART_PANELS_LABELS,
1355
+ DEFAULT_CORRELATION_SCATTER_LABELS,
1356
+ SCATTER_HIT_SIZE,
1357
+ chartPanelsModel,
1358
+ combineMarks,
1359
+ comparisonSeries,
1360
+ correlationScatterModel,
1361
+ crossingPoints,
1362
+ eventMarks,
1363
+ findCrossings,
1364
+ forecastSeries,
1365
+ formatCorrelation,
1366
+ linearFit,
1367
+ mergeChartTheme,
1368
+ niceCeil,
1369
+ normalQuantile,
1370
+ partialPeriod,
1371
+ predictionBand,
1372
+ quantiles,
1373
+ studentTQuantile,
1374
+ thresholdMarks,
1375
+ uixChartAreaGradient,
1376
+ uixChartPalette,
1377
+ uixChartTheme,
1378
+ uixChartTokens
1379
+ });