@pactor-app/chart 0.0.0-stage → 1.46.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.
package/dist/index.cjs ADDED
@@ -0,0 +1,1444 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ AreaChart: () => AreaChart,
34
+ BarChart: () => BarChart2,
35
+ BubbleChart: () => BubbleChart,
36
+ ColumnChart: () => ColumnChart,
37
+ ComposedChart: () => ComposedChart,
38
+ DonutChart: () => DonutChart,
39
+ EChartBase: () => EChartBase,
40
+ FunnelChart: () => FunnelChart2,
41
+ GaugeChart: () => GaugeChart2,
42
+ Heatmap: () => Heatmap,
43
+ LineChart: () => LineChart2,
44
+ MapChart: () => MapChart2,
45
+ MetricCard: () => MetricCard,
46
+ PieChart: () => PieChart2,
47
+ RadarChart: () => RadarChart2,
48
+ SankeyChart: () => SankeyChart2,
49
+ ScatterChart: () => ScatterChart2,
50
+ TreeChart: () => TreeChart2,
51
+ chartComponents: () => chartComponents,
52
+ createChartComponentRegistry: () => createChartComponentRegistry,
53
+ registerChartComponents: () => registerChartComponents
54
+ });
55
+ module.exports = __toCommonJS(index_exports);
56
+ var import_core = require("@pactor-app/core");
57
+
58
+ // src/components/MetricCard/index.tsx
59
+ var import_lucide_react = require("lucide-react");
60
+
61
+ // src/lib/utils.ts
62
+ var import_clsx = require("clsx");
63
+ var import_tailwind_merge = require("tailwind-merge");
64
+ function cn(...inputs) {
65
+ return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
66
+ }
67
+
68
+ // src/components/MetricCard/index.tsx
69
+ var import_jsx_runtime = require("react/jsx-runtime");
70
+ function MetricCard({
71
+ title,
72
+ value,
73
+ prefix,
74
+ suffix,
75
+ trend,
76
+ trendLabel,
77
+ className,
78
+ style
79
+ }) {
80
+ const showTrend = typeof trend === "number" && trend !== 0;
81
+ const rising = (trend ?? 0) > 0;
82
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
83
+ "div",
84
+ {
85
+ "data-slot": "metric-card",
86
+ className: cn("rounded-lg border bg-card p-4 text-card-foreground shadow-sm", className),
87
+ style,
88
+ children: [
89
+ title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "data-slot": "metric-card-title", className: "text-sm text-muted-foreground", children: title }) : null,
90
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
91
+ "div",
92
+ {
93
+ "data-slot": "metric-card-value",
94
+ className: "mt-1 text-2xl font-semibold tracking-tight tabular-nums",
95
+ children: [
96
+ prefix,
97
+ value,
98
+ suffix
99
+ ]
100
+ }
101
+ ),
102
+ showTrend ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
103
+ "div",
104
+ {
105
+ "data-slot": "metric-card-trend",
106
+ "data-trend": rising ? "up" : "down",
107
+ className: cn(
108
+ "mt-1 inline-flex items-center gap-0.5 text-sm",
109
+ rising ? "text-success" : "text-destructive"
110
+ ),
111
+ children: [
112
+ rising ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowUpRight, { className: "size-4" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ArrowDownRight, { className: "size-4" }),
113
+ Math.abs(trend ?? 0),
114
+ "%",
115
+ trendLabel ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-1 text-muted-foreground", children: trendLabel }) : null
116
+ ]
117
+ }
118
+ ) : null
119
+ ]
120
+ }
121
+ );
122
+ }
123
+
124
+ // src/components/EChartBase/index.tsx
125
+ var import_react = require("react");
126
+
127
+ // src/components/echarts-modules.ts
128
+ var echarts = __toESM(require("echarts/core"), 1);
129
+ var import_charts = require("echarts/charts");
130
+ var import_components = require("echarts/components");
131
+ var import_renderers = require("echarts/renderers");
132
+ echarts.use([
133
+ import_charts.LineChart,
134
+ import_charts.BarChart,
135
+ import_charts.PieChart,
136
+ import_charts.ScatterChart,
137
+ import_charts.RadarChart,
138
+ import_charts.FunnelChart,
139
+ import_charts.GaugeChart,
140
+ import_charts.HeatmapChart,
141
+ import_charts.TreeChart,
142
+ import_charts.SankeyChart,
143
+ import_charts.MapChart,
144
+ import_components.GridComponent,
145
+ import_components.TooltipComponent,
146
+ import_components.LegendComponent,
147
+ import_components.TitleComponent,
148
+ import_components.VisualMapComponent,
149
+ import_components.DataZoomComponent,
150
+ import_components.GeoComponent,
151
+ import_components.RadarComponent,
152
+ import_renderers.CanvasRenderer
153
+ ]);
154
+
155
+ // src/components/EChartBase/index.tsx
156
+ var import_jsx_runtime2 = require("react/jsx-runtime");
157
+ function EChartBase({
158
+ option,
159
+ height = 256,
160
+ onSelect,
161
+ className,
162
+ style,
163
+ slot
164
+ }) {
165
+ const hostRef = (0, import_react.useRef)(null);
166
+ const chartRef = (0, import_react.useRef)(null);
167
+ const onSelectRef = (0, import_react.useRef)(onSelect);
168
+ onSelectRef.current = onSelect;
169
+ const [failed, setFailed] = (0, import_react.useState)(false);
170
+ (0, import_react.useEffect)(() => {
171
+ const host = hostRef.current;
172
+ if (!host) return;
173
+ let chart = null;
174
+ try {
175
+ chart = echarts.init(host);
176
+ } catch {
177
+ setFailed(true);
178
+ return;
179
+ }
180
+ chartRef.current = chart;
181
+ chart.on("click", (params) => {
182
+ onSelectRef.current?.({
183
+ name: params.name,
184
+ value: params.value,
185
+ seriesName: params.seriesName,
186
+ dataIndex: params.dataIndex
187
+ });
188
+ });
189
+ const observer2 = new ResizeObserver(() => chart?.resize());
190
+ observer2.observe(host);
191
+ return () => {
192
+ observer2.disconnect();
193
+ chart?.dispose();
194
+ chartRef.current = null;
195
+ };
196
+ }, []);
197
+ (0, import_react.useEffect)(() => {
198
+ try {
199
+ chartRef.current?.setOption(option, { notMerge: true });
200
+ } catch {
201
+ }
202
+ }, [option]);
203
+ if (failed) {
204
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
205
+ "div",
206
+ {
207
+ "data-slot": "chart-fallback",
208
+ className: cn(
209
+ "flex h-32 w-full items-center justify-center rounded-md border border-dashed text-sm text-muted-foreground",
210
+ className
211
+ ),
212
+ style,
213
+ children: "\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301\u56FE\u8868\u6E32\u67D3"
214
+ }
215
+ );
216
+ }
217
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
218
+ "div",
219
+ {
220
+ ref: hostRef,
221
+ "data-slot": slot,
222
+ className: cn("w-full", className),
223
+ style: { height: typeof height === "number" ? `${height}px` : height, ...style }
224
+ }
225
+ );
226
+ }
227
+
228
+ // src/components/lib/option-builders.ts
229
+ function pickColor(theme, colors, index) {
230
+ if (colors && colors.length > 0) return colors[index % colors.length];
231
+ return theme.palette[index % theme.palette.length];
232
+ }
233
+ function toNumber(value) {
234
+ const n = Number(value);
235
+ return Number.isFinite(n) ? n : 0;
236
+ }
237
+ function axisLabel(theme) {
238
+ return { color: theme.muted };
239
+ }
240
+ function grid() {
241
+ return { left: 8, right: 16, top: 40, bottom: 4, containLabel: true };
242
+ }
243
+ function axisTooltip(theme) {
244
+ return {
245
+ trigger: "axis",
246
+ backgroundColor: theme.card,
247
+ borderColor: theme.border,
248
+ textStyle: { color: theme.foreground }
249
+ };
250
+ }
251
+ function itemTooltip(theme) {
252
+ return {
253
+ trigger: "item",
254
+ backgroundColor: theme.card,
255
+ borderColor: theme.border,
256
+ textStyle: { color: theme.foreground }
257
+ };
258
+ }
259
+ function titleOption(title) {
260
+ return title ? { text: title, left: 8, top: 4 } : void 0;
261
+ }
262
+ function legendOption(theme, show) {
263
+ return show ? { top: 4, textStyle: { color: theme.muted } } : void 0;
264
+ }
265
+ function categorySeries(input, theme, kind, area) {
266
+ const rows = input.data;
267
+ const keys = input.yKeys && input.yKeys.length > 0 ? input.yKeys : ["value"];
268
+ const series = keys.map((key, index) => ({
269
+ type: kind,
270
+ name: key,
271
+ data: rows.map((row) => toNumber(row[key])),
272
+ ...kind === "line" ? { smooth: input.smooth ?? false, symbolSize: 6 } : {},
273
+ ...area ? { areaStyle: { opacity: input.fillOpacity ?? 0.25 } } : {},
274
+ ...input.stacked ? { stack: "total" } : {},
275
+ ...kind === "line" ? { emphasis: { focus: "series" } } : {},
276
+ itemStyle: { color: pickColor(theme, input.colors, index) },
277
+ ...kind === "line" ? { lineStyle: { color: pickColor(theme, input.colors, index) } } : {},
278
+ ...area ? { lineStyle: { color: pickColor(theme, input.colors, index) } } : {}
279
+ }));
280
+ const legend = legendOption(theme, keys.length > 1);
281
+ return {
282
+ color: input.colors && input.colors.length > 0 ? input.colors : theme.palette,
283
+ title: titleOption(input.title),
284
+ grid: grid(),
285
+ tooltip: axisTooltip(theme),
286
+ ...legend ? { legend } : {},
287
+ xAxis: { type: "category", data: rows.map((row) => String(input.xKey ? row[input.xKey] : "")), axisLabel: axisLabel(theme), axisLine: { lineStyle: { color: theme.border } } },
288
+ yAxis: { type: "value", axisLabel: axisLabel(theme), splitLine: { lineStyle: { color: theme.border } } },
289
+ series
290
+ };
291
+ }
292
+ function buildLineOption(input, theme) {
293
+ return categorySeries(input, theme, "line", input.showArea ?? false);
294
+ }
295
+ function buildColumnOption(input, theme) {
296
+ return categorySeries(input, theme, "bar", false);
297
+ }
298
+ function buildBarOption(input, theme) {
299
+ const rows = input.data;
300
+ const keys = input.yKeys && input.yKeys.length > 0 ? input.yKeys : ["value"];
301
+ const series = keys.map((key, index) => ({
302
+ type: "bar",
303
+ name: key,
304
+ data: rows.map((row) => toNumber(row[key])),
305
+ ...input.stacked ? { stack: "total" } : {},
306
+ itemStyle: { color: pickColor(theme, input.colors, index) }
307
+ }));
308
+ const legend = legendOption(theme, keys.length > 1);
309
+ return {
310
+ color: input.colors && input.colors.length > 0 ? input.colors : theme.palette,
311
+ title: titleOption(input.title),
312
+ grid: grid(),
313
+ tooltip: axisTooltip(theme),
314
+ ...legend ? { legend } : {},
315
+ xAxis: { type: "value", axisLabel: axisLabel(theme), splitLine: { lineStyle: { color: theme.border } } },
316
+ yAxis: { type: "category", data: rows.map((row) => String(input.yKey ? row[input.yKey] : "")), axisLabel: axisLabel(theme), axisLine: { lineStyle: { color: theme.border } } },
317
+ series
318
+ };
319
+ }
320
+ function buildAreaOption(input, theme) {
321
+ const withArea = { ...input, showArea: true };
322
+ return categorySeries(withArea, theme, "line", true);
323
+ }
324
+ function pieOption(input, theme, radius, extra) {
325
+ const nameKey = input.nameKey ?? "name";
326
+ const valueKey = input.valueKey ?? "value";
327
+ return {
328
+ color: input.colors && input.colors.length > 0 ? input.colors : theme.palette,
329
+ title: titleOption(input.title),
330
+ tooltip: itemTooltip(theme),
331
+ legend: { bottom: 0, textStyle: { color: theme.muted } },
332
+ series: [
333
+ {
334
+ type: "pie",
335
+ radius,
336
+ center: ["50%", "52%"],
337
+ data: input.data.map((row) => ({ name: String(row[nameKey] ?? ""), value: toNumber(row[valueKey]) })),
338
+ label: { show: input.showLabel ?? false, color: theme.muted },
339
+ emphasis: { scaleSize: 6 }
340
+ }
341
+ ],
342
+ ...extra
343
+ };
344
+ }
345
+ function buildPieOption(input, theme) {
346
+ return pieOption(input, theme, [0, "72%"], {});
347
+ }
348
+ function buildDonutOption(input, theme) {
349
+ const inner = input.innerRadius ?? "48%";
350
+ const outer = input.outerRadius ?? "72%";
351
+ const extra = {};
352
+ if (input.centerValue !== void 0 || input.centerLabel !== void 0) {
353
+ extra.title = {
354
+ text: input.centerValue !== void 0 ? String(input.centerValue) : "",
355
+ subtext: input.centerLabel ?? "",
356
+ left: "center",
357
+ top: "40%",
358
+ textStyle: { color: theme.foreground, fontSize: 22 },
359
+ subtextStyle: { color: theme.muted }
360
+ };
361
+ }
362
+ return pieOption(input, theme, [inner, outer], extra);
363
+ }
364
+ function scatterSeries(input, theme, extra) {
365
+ const xKey = input.xKey ?? "x";
366
+ const yKey = input.yKey ?? "y";
367
+ const groups = /* @__PURE__ */ new Map();
368
+ if (input.seriesKey) {
369
+ for (const row of input.data) {
370
+ const g = String(row[input.seriesKey] ?? "");
371
+ if (!groups.has(g)) groups.set(g, []);
372
+ groups.get(g).push(row);
373
+ }
374
+ } else {
375
+ groups.set("", input.data);
376
+ }
377
+ const names = [...groups.keys()];
378
+ const series = names.map((name, index) => ({
379
+ type: "scatter",
380
+ name: name || void 0,
381
+ data: groups.get(name).map(
382
+ (row) => extra?.datum ? extra.datum(row) : [toNumber(row[xKey]), toNumber(row[yKey])]
383
+ ),
384
+ symbolSize: extra?.symbolSize ?? 10,
385
+ itemStyle: { color: pickColor(theme, input.colors, index) }
386
+ }));
387
+ const legend = legendOption(theme, input.seriesKey !== void 0 && names.length > 1);
388
+ return {
389
+ color: input.colors && input.colors.length > 0 ? input.colors : theme.palette,
390
+ title: titleOption(input.title),
391
+ grid: grid(),
392
+ tooltip: axisTooltip(theme),
393
+ ...legend ? { legend } : {},
394
+ xAxis: { type: "value", axisLabel: axisLabel(theme), splitLine: { lineStyle: { color: theme.border } } },
395
+ yAxis: { type: "value", axisLabel: axisLabel(theme), splitLine: { lineStyle: { color: theme.border } } },
396
+ series
397
+ };
398
+ }
399
+ function buildScatterOption(input, theme) {
400
+ return scatterSeries(input, theme);
401
+ }
402
+ function buildBubbleOption(input, theme) {
403
+ const sizeKey = input.sizeKey ?? "size";
404
+ const sizes = input.data.map((row) => toNumber(row[sizeKey]));
405
+ const min = Math.min(...sizes, 0);
406
+ const max = Math.max(...sizes, 1);
407
+ const span = max - min || 1;
408
+ return scatterSeries(input, theme, {
409
+ datum: (row) => [toNumber(row[input.xKey ?? "x"]), toNumber(row[input.yKey ?? "y"]), toNumber(row[sizeKey])],
410
+ symbolSize: (datum) => {
411
+ const [x, y, size] = datum;
412
+ void x;
413
+ void y;
414
+ return 12 + (toNumber(size) - min) / span * 36;
415
+ }
416
+ });
417
+ }
418
+ function buildRadarOption(input, theme) {
419
+ const indicatorKey = input.indicatorKey ?? "indicator";
420
+ const keys = input.yKeys && input.yKeys.length > 0 ? input.yKeys : ["value"];
421
+ return {
422
+ color: input.colors && input.colors.length > 0 ? input.colors : theme.palette,
423
+ title: titleOption(input.title),
424
+ tooltip: itemTooltip(theme),
425
+ ...keys.length > 1 ? { legend: legendOption(theme, true) } : {},
426
+ radar: {
427
+ indicator: input.data.map((row) => ({ name: String(row[indicatorKey] ?? ""), max: 100 })),
428
+ axisName: { color: theme.muted },
429
+ splitLine: { lineStyle: { color: theme.border } },
430
+ splitArea: { areaStyle: { color: [] } }
431
+ },
432
+ series: [
433
+ {
434
+ type: "radar",
435
+ data: keys.map((key) => ({
436
+ name: key,
437
+ value: input.data.map((row) => toNumber(row[key]))
438
+ }))
439
+ }
440
+ ]
441
+ };
442
+ }
443
+ function buildFunnelOption(input, theme) {
444
+ const nameKey = input.nameKey ?? "name";
445
+ const valueKey = input.valueKey ?? "value";
446
+ return {
447
+ color: input.colors && input.colors.length > 0 ? input.colors : theme.palette,
448
+ title: titleOption(input.title),
449
+ tooltip: itemTooltip(theme),
450
+ series: [
451
+ {
452
+ type: "funnel",
453
+ left: "12%",
454
+ width: "76%",
455
+ sort: input.sort ?? "descending",
456
+ gap: 2,
457
+ label: { show: true, position: "inside", color: theme.card },
458
+ data: input.data.map((row) => ({ name: String(row[nameKey] ?? ""), value: toNumber(row[valueKey]) }))
459
+ }
460
+ ]
461
+ };
462
+ }
463
+ function buildGaugeOption(input, theme) {
464
+ const min = input.min ?? 0;
465
+ const max = input.max ?? 100;
466
+ const span = max - min || 1;
467
+ const defaultThresholds = [{ value: max, color: theme.palette[0] }];
468
+ const stops = (input.thresholds && input.thresholds.length > 0 ? input.thresholds : defaultThresholds).slice().sort((a, b) => a.value - b.value).map((t, index, arr) => {
469
+ const upper = index < arr.length - 1 ? t.value : max;
470
+ return [(upper - min) / span, t.color ?? theme.palette[0]];
471
+ });
472
+ return {
473
+ title: titleOption(input.title),
474
+ series: [
475
+ {
476
+ type: "gauge",
477
+ min,
478
+ max,
479
+ startAngle: 210,
480
+ endAngle: -30,
481
+ progress: { show: true, width: 10 },
482
+ axisLine: { lineStyle: { width: 10, color: stops } },
483
+ axisTick: { show: false },
484
+ splitLine: { show: false },
485
+ axisLabel: { show: false },
486
+ pointer: { show: false },
487
+ anchor: { show: false },
488
+ title: { show: false },
489
+ detail: {
490
+ valueAnimation: true,
491
+ offsetCenter: [0, 0],
492
+ fontSize: 26,
493
+ color: theme.foreground,
494
+ formatter: (value) => `${value}${input.unit ?? ""}`
495
+ },
496
+ data: [{ value: toNumber(input.value) }]
497
+ }
498
+ ]
499
+ };
500
+ }
501
+ function valueRange(values) {
502
+ if (values.length === 0) return { min: 0, max: 1 };
503
+ const min = Math.min(...values);
504
+ const max = Math.max(...values);
505
+ return max === min ? { min, max: min + 1 } : { min, max };
506
+ }
507
+ function buildHeatmapOption(input, theme) {
508
+ const xKey = input.xKey ?? "x";
509
+ const yKey = input.yKey ?? "y";
510
+ const valueKey = input.valueKey ?? "value";
511
+ const xs = [...new Set(input.data.map((row) => String(row[xKey])))];
512
+ const ys = [...new Set(input.data.map((row) => String(row[yKey])))];
513
+ const range = valueRange(input.data.map((row) => toNumber(row[valueKey])));
514
+ return {
515
+ title: titleOption(input.title),
516
+ grid: grid(),
517
+ tooltip: itemTooltip(theme),
518
+ xAxis: { type: "category", data: xs, axisLabel: axisLabel(theme), splitArea: { show: true } },
519
+ yAxis: { type: "category", data: ys, axisLabel: axisLabel(theme), splitArea: { show: true } },
520
+ visualMap: {
521
+ min: range.min,
522
+ max: range.max,
523
+ calculable: true,
524
+ orient: "horizontal",
525
+ left: "center",
526
+ bottom: 0,
527
+ textStyle: { color: theme.muted },
528
+ inRange: { color: [theme.palette[2] ?? theme.palette[0], theme.palette[0]] }
529
+ },
530
+ series: [
531
+ {
532
+ type: "heatmap",
533
+ data: input.data.map((row) => [String(row[xKey]), String(row[yKey]), toNumber(row[valueKey])]),
534
+ label: { show: false }
535
+ }
536
+ ]
537
+ };
538
+ }
539
+ function buildTreeOption(input, theme) {
540
+ const horizontal = input.orient === "horizontal";
541
+ return {
542
+ title: titleOption(input.title),
543
+ tooltip: itemTooltip(theme),
544
+ series: [
545
+ {
546
+ type: "tree",
547
+ data: input.data,
548
+ layout: "orthogonal",
549
+ orient: horizontal ? "LR" : "TB",
550
+ edgeShape: input.edgeShape ?? "curve",
551
+ roam: false,
552
+ expandAndCollapse: true,
553
+ initialTreeDepth: input.initialTreeDepth ?? 2,
554
+ label: {
555
+ show: true,
556
+ position: horizontal ? "right" : "bottom",
557
+ color: theme.foreground,
558
+ fontSize: 12
559
+ },
560
+ itemStyle: { color: theme.palette[0], borderColor: theme.palette[0] },
561
+ lineStyle: { color: theme.border, width: 1.5, curveness: 0.5 },
562
+ leaves: {
563
+ itemStyle: { color: theme.palette[1], borderColor: theme.palette[1] }
564
+ },
565
+ emphasis: { focus: "relative" }
566
+ }
567
+ ]
568
+ };
569
+ }
570
+ function buildSankeyOption(input, theme) {
571
+ return {
572
+ color: theme.palette,
573
+ title: titleOption(input.title),
574
+ tooltip: itemTooltip(theme),
575
+ series: [
576
+ {
577
+ type: "sankey",
578
+ left: 24,
579
+ right: 64,
580
+ top: 40,
581
+ bottom: 24,
582
+ nodeWidth: 16,
583
+ nodeGap: 12,
584
+ draggable: false,
585
+ label: { color: theme.muted },
586
+ lineStyle: { color: "gradient", curveness: 0.5 },
587
+ emphasis: { focus: "adjacency" },
588
+ data: input.nodes,
589
+ links: input.links
590
+ }
591
+ ]
592
+ };
593
+ }
594
+ function buildMapOption(input, theme) {
595
+ const nameKey = input.nameKey ?? "name";
596
+ const valueKey = input.valueKey ?? "value";
597
+ const range = valueRange(input.data.map((row) => toNumber(row[valueKey])));
598
+ return {
599
+ title: titleOption(input.title),
600
+ tooltip: itemTooltip(theme),
601
+ visualMap: {
602
+ min: range.min,
603
+ max: range.max,
604
+ left: 8,
605
+ bottom: 8,
606
+ textStyle: { color: theme.muted },
607
+ inRange: { color: [theme.palette[2] ?? theme.palette[0], theme.palette[0]] }
608
+ },
609
+ series: [
610
+ {
611
+ type: "map",
612
+ map: input.mapName,
613
+ roam: false,
614
+ label: { show: false },
615
+ emphasis: { label: { show: true, color: theme.foreground } },
616
+ itemStyle: { borderColor: theme.card, borderWidth: 1 },
617
+ data: input.data.map((row) => ({ name: String(row[nameKey] ?? ""), value: toNumber(row[valueKey]) }))
618
+ }
619
+ ]
620
+ };
621
+ }
622
+ function buildComposedOption(input, theme) {
623
+ const rows = input.data;
624
+ const hasSecondAxis = input.series.some((s) => s.yAxisIndex === 1);
625
+ const series = input.series.map((s, index) => {
626
+ const color = pickColor(theme, input.colors, index);
627
+ return {
628
+ type: s.type === "area" ? "line" : s.type,
629
+ name: s.name ?? s.dataKey,
630
+ data: rows.map((row) => toNumber(row[s.dataKey])),
631
+ ...s.type === "line" ? { smooth: false, symbolSize: 6 } : {},
632
+ ...s.type === "area" ? { areaStyle: { opacity: 0.25 } } : {},
633
+ yAxisIndex: s.yAxisIndex ?? 0,
634
+ itemStyle: { color },
635
+ ...s.type !== "bar" ? { lineStyle: { color } } : {}
636
+ };
637
+ });
638
+ return {
639
+ color: input.colors && input.colors.length > 0 ? input.colors : theme.palette,
640
+ title: titleOption(input.title),
641
+ grid: grid(),
642
+ tooltip: axisTooltip(theme),
643
+ legend: legendOption(theme, true),
644
+ xAxis: { type: "category", data: rows.map((row) => String(input.xKey ? row[input.xKey] : "")), axisLabel: axisLabel(theme), axisLine: { lineStyle: { color: theme.border } } },
645
+ yAxis: hasSecondAxis ? [
646
+ { type: "value", axisLabel: axisLabel(theme), splitLine: { lineStyle: { color: theme.border } } },
647
+ { type: "value", axisLabel: axisLabel(theme), splitLine: { show: false } }
648
+ ] : { type: "value", axisLabel: axisLabel(theme), splitLine: { lineStyle: { color: theme.border } } },
649
+ series
650
+ };
651
+ }
652
+
653
+ // src/components/lib/use-chart-theme.ts
654
+ var import_react2 = require("react");
655
+
656
+ // src/components/lib/color.ts
657
+ var LPAREN = String.fromCharCode(40);
658
+ var RPAREN = String.fromCharCode(41);
659
+ var OKLCH_RE = new RegExp(
660
+ "^oklch" + String.fromCharCode(92) + LPAREN + "\\s*([\\d.]+%?)\\s+([-\\d.eE]+)\\s+([-\\d.eE]+)(?:\\s*\\/\\s*[\\d.]+%?)?\\s*" + String.fromCharCode(92) + RPAREN + "$",
661
+ "i"
662
+ );
663
+ var OKLAB_RE = new RegExp(
664
+ "^oklab" + String.fromCharCode(92) + LPAREN + "\\s*([\\d.]+%?)\\s+([-\\d.eE]+)\\s+([-\\d.eE]+)(?:\\s*\\/\\s*[\\d.]+%?)?\\s*" + String.fromCharCode(92) + RPAREN + "$",
665
+ "i"
666
+ );
667
+ function parseLightness(raw) {
668
+ const value = parseFloat(raw);
669
+ return raw.endsWith("%") ? value / 100 : value;
670
+ }
671
+ function oklabToLinearSrgbColor(L, a, b) {
672
+ const l_ = L + 0.3963377774 * a + 0.2158037573 * b;
673
+ const m_ = L - 0.1055613458 * a - 0.0638541728 * b;
674
+ const s_ = L - 0.0894841775 * a - 1.291485548 * b;
675
+ const l = l_ * l_ * l_;
676
+ const m = m_ * m_ * m_;
677
+ const s = s_ * s_ * s_;
678
+ return [
679
+ 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
680
+ -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
681
+ -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s
682
+ ];
683
+ }
684
+ function linearToSrgbChannel(c) {
685
+ const clamped = Math.min(1, Math.max(0, c));
686
+ const encoded = clamped <= 31308e-7 ? 12.92 * clamped : 1.055 * Math.pow(clamped, 1 / 2.4) - 0.055;
687
+ return Math.round(encoded * 255);
688
+ }
689
+ function formatSrgbString(r, g, b) {
690
+ return "rgb" + LPAREN + `${linearToSrgbChannel(r)}, ${linearToSrgbChannel(g)}, ${linearToSrgbChannel(b)}` + RPAREN;
691
+ }
692
+ function normalizeColor(value) {
693
+ const trimmed = value.trim();
694
+ const oklch = OKLCH_RE.exec(trimmed);
695
+ if (oklch) {
696
+ const L = parseLightness(oklch[1]);
697
+ const C = parseFloat(oklch[2]);
698
+ const h = parseFloat(oklch[3]) * Math.PI / 180;
699
+ const [r, g, b] = oklabToLinearSrgbColor(L, C * Math.cos(h), C * Math.sin(h));
700
+ return formatSrgbString(r, g, b);
701
+ }
702
+ const oklab = OKLAB_RE.exec(trimmed);
703
+ if (oklab) {
704
+ const L = parseLightness(oklab[1]);
705
+ const a = parseFloat(oklab[2]);
706
+ const b = parseFloat(oklab[3]);
707
+ const [r, g, bl] = oklabToLinearSrgbColor(L, a, b);
708
+ return formatSrgbString(r, g, bl);
709
+ }
710
+ return trimmed;
711
+ }
712
+
713
+ // src/components/lib/theme.ts
714
+ var FALLBACK_THEME = {
715
+ palette: ["steelblue", "seagreen", "darkorange", "slateblue", "tomato"],
716
+ foreground: "black",
717
+ muted: "gray",
718
+ border: "gainsboro",
719
+ card: "white",
720
+ success: "seagreen",
721
+ warning: "darkorange",
722
+ destructive: "tomato",
723
+ info: "steelblue"
724
+ };
725
+ var cached = null;
726
+ function getChartTheme() {
727
+ if (cached) return cached;
728
+ if (typeof document === "undefined") return FALLBACK_THEME;
729
+ try {
730
+ const style = getComputedStyle(document.documentElement);
731
+ const read = (name) => normalizeColor(style.getPropertyValue(name));
732
+ const readColor = (name, fallback) => read(name) || fallback;
733
+ const palette = [1, 2, 3, 4, 5].map(
734
+ (i, index) => readColor(`--chart-${i}`, FALLBACK_THEME.palette[index])
735
+ );
736
+ cached = {
737
+ palette,
738
+ foreground: readColor("--foreground", FALLBACK_THEME.foreground),
739
+ muted: readColor("--muted-foreground", FALLBACK_THEME.muted),
740
+ border: readColor("--border", FALLBACK_THEME.border),
741
+ card: readColor("--card", FALLBACK_THEME.card),
742
+ success: readColor("--success", FALLBACK_THEME.success),
743
+ warning: readColor("--warning", FALLBACK_THEME.warning),
744
+ destructive: readColor("--destructive", FALLBACK_THEME.destructive),
745
+ info: readColor("--info", FALLBACK_THEME.info)
746
+ };
747
+ return cached;
748
+ } catch {
749
+ return FALLBACK_THEME;
750
+ }
751
+ }
752
+ function resetChartTheme() {
753
+ cached = null;
754
+ }
755
+ var CHART_SKIN_CHANGE_EVENT = "pactor:skin-change";
756
+ var listeners = /* @__PURE__ */ new Set();
757
+ var observer = null;
758
+ var scheduled = false;
759
+ function scheduleNotify() {
760
+ if (scheduled) return;
761
+ scheduled = true;
762
+ const enqueue = typeof requestAnimationFrame === "function" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
763
+ enqueue(() => {
764
+ scheduled = false;
765
+ resetChartTheme();
766
+ for (const listener of [...listeners]) {
767
+ listener();
768
+ }
769
+ });
770
+ }
771
+ function handleResourceLoad(event) {
772
+ const target = event.target;
773
+ if (target instanceof HTMLLinkElement || target instanceof HTMLStyleElement) {
774
+ scheduleNotify();
775
+ }
776
+ }
777
+ function subscribeChartTheme(listener) {
778
+ if (typeof document === "undefined" || typeof MutationObserver === "undefined") {
779
+ return () => {
780
+ };
781
+ }
782
+ listeners.add(listener);
783
+ if (!observer) {
784
+ observer = new MutationObserver(scheduleNotify);
785
+ observer.observe(document.documentElement, { attributes: true });
786
+ observer.observe(document.head, {
787
+ attributes: true,
788
+ childList: true,
789
+ characterData: true,
790
+ subtree: true
791
+ });
792
+ document.addEventListener("load", handleResourceLoad, true);
793
+ window.addEventListener(CHART_SKIN_CHANGE_EVENT, scheduleNotify);
794
+ }
795
+ return () => {
796
+ listeners.delete(listener);
797
+ if (listeners.size === 0 && observer) {
798
+ observer.disconnect();
799
+ observer = null;
800
+ document.removeEventListener("load", handleResourceLoad, true);
801
+ window.removeEventListener(CHART_SKIN_CHANGE_EVENT, scheduleNotify);
802
+ }
803
+ };
804
+ }
805
+
806
+ // src/components/lib/use-chart-theme.ts
807
+ function useChartTheme() {
808
+ return (0, import_react2.useSyncExternalStore)(subscribeChartTheme, getChartTheme, getChartTheme);
809
+ }
810
+
811
+ // src/components/LineChart/index.tsx
812
+ var import_jsx_runtime3 = require("react/jsx-runtime");
813
+ function LineChart2({
814
+ data = [],
815
+ xKey,
816
+ yKeys,
817
+ smooth = false,
818
+ showArea = false,
819
+ stacked = false,
820
+ colors,
821
+ title,
822
+ height,
823
+ onSelect,
824
+ className,
825
+ style
826
+ }) {
827
+ const option = buildLineOption(
828
+ { data, xKey, yKeys, smooth, showArea, stacked, colors, title },
829
+ useChartTheme()
830
+ );
831
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
832
+ EChartBase,
833
+ {
834
+ slot: "line-chart",
835
+ option,
836
+ height,
837
+ onSelect,
838
+ className,
839
+ style
840
+ }
841
+ );
842
+ }
843
+
844
+ // src/components/ColumnChart/index.tsx
845
+ var import_jsx_runtime4 = require("react/jsx-runtime");
846
+ function ColumnChart({
847
+ data = [],
848
+ xKey,
849
+ yKeys,
850
+ stacked = false,
851
+ colors,
852
+ title,
853
+ height,
854
+ onSelect,
855
+ className,
856
+ style
857
+ }) {
858
+ const option = buildColumnOption(
859
+ { data, xKey, yKeys, stacked, colors, title },
860
+ useChartTheme()
861
+ );
862
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
863
+ EChartBase,
864
+ {
865
+ slot: "column-chart",
866
+ option,
867
+ height,
868
+ onSelect,
869
+ className,
870
+ style
871
+ }
872
+ );
873
+ }
874
+
875
+ // src/components/BarChart/index.tsx
876
+ var import_jsx_runtime5 = require("react/jsx-runtime");
877
+ function BarChart2({
878
+ data = [],
879
+ yKey,
880
+ xKeys,
881
+ stacked = false,
882
+ colors,
883
+ title,
884
+ height,
885
+ onSelect,
886
+ className,
887
+ style
888
+ }) {
889
+ const option = buildBarOption(
890
+ { data, yKey, yKeys: xKeys, stacked, colors, title },
891
+ useChartTheme()
892
+ );
893
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
894
+ EChartBase,
895
+ {
896
+ slot: "bar-chart",
897
+ option,
898
+ height,
899
+ onSelect,
900
+ className,
901
+ style
902
+ }
903
+ );
904
+ }
905
+
906
+ // src/components/AreaChart/index.tsx
907
+ var import_jsx_runtime6 = require("react/jsx-runtime");
908
+ function AreaChart({
909
+ data = [],
910
+ xKey,
911
+ yKeys,
912
+ stacked = false,
913
+ fillOpacity,
914
+ colors,
915
+ title,
916
+ height,
917
+ onSelect,
918
+ className,
919
+ style
920
+ }) {
921
+ const option = buildAreaOption(
922
+ { data, xKey, yKeys, stacked, fillOpacity, colors, title },
923
+ useChartTheme()
924
+ );
925
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
926
+ EChartBase,
927
+ {
928
+ slot: "area-chart",
929
+ option,
930
+ height,
931
+ onSelect,
932
+ className,
933
+ style
934
+ }
935
+ );
936
+ }
937
+
938
+ // src/components/PieChart/index.tsx
939
+ var import_jsx_runtime7 = require("react/jsx-runtime");
940
+ function PieChart2({
941
+ data = [],
942
+ nameKey,
943
+ valueKey,
944
+ showLabel,
945
+ colors,
946
+ title,
947
+ height,
948
+ onSelect,
949
+ className,
950
+ style
951
+ }) {
952
+ const option = buildPieOption(
953
+ { data, nameKey, valueKey, showLabel, colors, title },
954
+ useChartTheme()
955
+ );
956
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
957
+ EChartBase,
958
+ {
959
+ slot: "pie-chart",
960
+ option,
961
+ height,
962
+ onSelect,
963
+ className,
964
+ style
965
+ }
966
+ );
967
+ }
968
+
969
+ // src/components/DonutChart/index.tsx
970
+ var import_jsx_runtime8 = require("react/jsx-runtime");
971
+ function DonutChart({
972
+ data = [],
973
+ nameKey,
974
+ valueKey,
975
+ innerRadius,
976
+ outerRadius,
977
+ centerLabel,
978
+ centerValue,
979
+ showLabel,
980
+ colors,
981
+ title,
982
+ height,
983
+ onSelect,
984
+ className,
985
+ style
986
+ }) {
987
+ const option = buildDonutOption(
988
+ {
989
+ data,
990
+ nameKey,
991
+ valueKey,
992
+ innerRadius,
993
+ outerRadius,
994
+ centerLabel,
995
+ centerValue,
996
+ showLabel,
997
+ colors,
998
+ title
999
+ },
1000
+ useChartTheme()
1001
+ );
1002
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1003
+ EChartBase,
1004
+ {
1005
+ slot: "donut-chart",
1006
+ option,
1007
+ height,
1008
+ onSelect,
1009
+ className,
1010
+ style
1011
+ }
1012
+ );
1013
+ }
1014
+
1015
+ // src/components/ScatterChart/index.tsx
1016
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1017
+ function ScatterChart2({
1018
+ data = [],
1019
+ xKey,
1020
+ yKey,
1021
+ seriesKey,
1022
+ colors,
1023
+ title,
1024
+ height,
1025
+ onSelect,
1026
+ className,
1027
+ style
1028
+ }) {
1029
+ const option = buildScatterOption(
1030
+ { data, xKey, yKey, seriesKey, colors, title },
1031
+ useChartTheme()
1032
+ );
1033
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1034
+ EChartBase,
1035
+ {
1036
+ slot: "scatter-chart",
1037
+ option,
1038
+ height,
1039
+ onSelect,
1040
+ className,
1041
+ style
1042
+ }
1043
+ );
1044
+ }
1045
+
1046
+ // src/components/BubbleChart/index.tsx
1047
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1048
+ function BubbleChart({
1049
+ data = [],
1050
+ xKey,
1051
+ yKey,
1052
+ sizeKey,
1053
+ seriesKey,
1054
+ colors,
1055
+ title,
1056
+ height,
1057
+ onSelect,
1058
+ className,
1059
+ style
1060
+ }) {
1061
+ const option = buildBubbleOption(
1062
+ { data, xKey, yKey, sizeKey, seriesKey, colors, title },
1063
+ useChartTheme()
1064
+ );
1065
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1066
+ EChartBase,
1067
+ {
1068
+ slot: "bubble-chart",
1069
+ option,
1070
+ height,
1071
+ onSelect,
1072
+ className,
1073
+ style
1074
+ }
1075
+ );
1076
+ }
1077
+
1078
+ // src/components/RadarChart/index.tsx
1079
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1080
+ function RadarChart2({
1081
+ data = [],
1082
+ indicatorKey,
1083
+ yKeys,
1084
+ colors,
1085
+ title,
1086
+ height,
1087
+ onSelect,
1088
+ className,
1089
+ style
1090
+ }) {
1091
+ const option = buildRadarOption(
1092
+ { data, indicatorKey, yKeys, colors, title },
1093
+ useChartTheme()
1094
+ );
1095
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1096
+ EChartBase,
1097
+ {
1098
+ slot: "radar-chart",
1099
+ option,
1100
+ height,
1101
+ onSelect,
1102
+ className,
1103
+ style
1104
+ }
1105
+ );
1106
+ }
1107
+
1108
+ // src/components/FunnelChart/index.tsx
1109
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1110
+ function FunnelChart2({
1111
+ data = [],
1112
+ nameKey,
1113
+ valueKey,
1114
+ sort,
1115
+ colors,
1116
+ title,
1117
+ height,
1118
+ onSelect,
1119
+ className,
1120
+ style
1121
+ }) {
1122
+ const option = buildFunnelOption(
1123
+ { data, nameKey, valueKey, sort, colors, title },
1124
+ useChartTheme()
1125
+ );
1126
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1127
+ EChartBase,
1128
+ {
1129
+ slot: "funnel-chart",
1130
+ option,
1131
+ height,
1132
+ onSelect,
1133
+ className,
1134
+ style
1135
+ }
1136
+ );
1137
+ }
1138
+
1139
+ // src/components/GaugeChart/index.tsx
1140
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1141
+ function GaugeChart2({
1142
+ value = 0,
1143
+ min,
1144
+ max,
1145
+ thresholds,
1146
+ unit,
1147
+ title,
1148
+ height,
1149
+ onSelect,
1150
+ className,
1151
+ style
1152
+ }) {
1153
+ const option = buildGaugeOption(
1154
+ { value, min, max, thresholds, unit, title },
1155
+ useChartTheme()
1156
+ );
1157
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1158
+ EChartBase,
1159
+ {
1160
+ slot: "gauge-chart",
1161
+ option,
1162
+ height,
1163
+ onSelect,
1164
+ className,
1165
+ style
1166
+ }
1167
+ );
1168
+ }
1169
+
1170
+ // src/components/Heatmap/index.tsx
1171
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1172
+ function Heatmap({
1173
+ data = [],
1174
+ xKey,
1175
+ yKey,
1176
+ valueKey,
1177
+ title,
1178
+ height,
1179
+ onSelect,
1180
+ className,
1181
+ style
1182
+ }) {
1183
+ const option = buildHeatmapOption(
1184
+ { data, xKey, yKey, valueKey, title },
1185
+ useChartTheme()
1186
+ );
1187
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1188
+ EChartBase,
1189
+ {
1190
+ slot: "heatmap",
1191
+ option,
1192
+ height,
1193
+ onSelect,
1194
+ className,
1195
+ style
1196
+ }
1197
+ );
1198
+ }
1199
+
1200
+ // src/components/TreeChart/index.tsx
1201
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1202
+ function TreeChart2({
1203
+ data = [],
1204
+ title,
1205
+ orient,
1206
+ edgeShape,
1207
+ initialTreeDepth,
1208
+ height,
1209
+ onSelect,
1210
+ className,
1211
+ style
1212
+ }) {
1213
+ const option = buildTreeOption(
1214
+ { data, title, orient, edgeShape, initialTreeDepth },
1215
+ useChartTheme()
1216
+ );
1217
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1218
+ EChartBase,
1219
+ {
1220
+ slot: "tree-chart",
1221
+ option,
1222
+ height,
1223
+ onSelect,
1224
+ className,
1225
+ style
1226
+ }
1227
+ );
1228
+ }
1229
+
1230
+ // src/components/SankeyChart/index.tsx
1231
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1232
+ function SankeyChart2({
1233
+ nodes = [],
1234
+ links = [],
1235
+ title,
1236
+ height,
1237
+ onSelect,
1238
+ className,
1239
+ style
1240
+ }) {
1241
+ const option = buildSankeyOption({ nodes, links, title }, useChartTheme());
1242
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1243
+ EChartBase,
1244
+ {
1245
+ slot: "sankey-chart",
1246
+ option,
1247
+ height,
1248
+ onSelect,
1249
+ className,
1250
+ style
1251
+ }
1252
+ );
1253
+ }
1254
+
1255
+ // src/components/MapChart/index.tsx
1256
+ var import_react3 = require("react");
1257
+ var import_components2 = require("@pactor-app/ui/components");
1258
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1259
+ var fetchedMaps = /* @__PURE__ */ new Set();
1260
+ function hasRegisteredMap(mapName) {
1261
+ try {
1262
+ return typeof echarts.getMap === "function" && echarts.getMap(mapName) != null;
1263
+ } catch {
1264
+ return false;
1265
+ }
1266
+ }
1267
+ function MapChart2({
1268
+ mapName = "map",
1269
+ data = [],
1270
+ nameKey,
1271
+ valueKey,
1272
+ geoJson,
1273
+ geoJsonUrl,
1274
+ title,
1275
+ height,
1276
+ onSelect,
1277
+ className,
1278
+ style
1279
+ }) {
1280
+ const theme = useChartTheme();
1281
+ const [loadState, setLoadState] = (0, import_react3.useState)(
1282
+ () => geoJson || !geoJsonUrl || hasRegisteredMap(mapName) ? "idle" : "loading"
1283
+ );
1284
+ if (geoJson) {
1285
+ try {
1286
+ echarts.registerMap(mapName, geoJson);
1287
+ } catch {
1288
+ }
1289
+ }
1290
+ (0, import_react3.useEffect)(() => {
1291
+ if (geoJson || !geoJsonUrl || hasRegisteredMap(mapName) || fetchedMaps.has(mapName)) {
1292
+ setLoadState("idle");
1293
+ return;
1294
+ }
1295
+ let cancelled = false;
1296
+ setLoadState("loading");
1297
+ fetch(geoJsonUrl).then((res) => {
1298
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
1299
+ return res.json();
1300
+ }).then((json) => {
1301
+ if (cancelled) return;
1302
+ echarts.registerMap(mapName, json);
1303
+ fetchedMaps.add(mapName);
1304
+ setLoadState("ready");
1305
+ }).catch(() => {
1306
+ if (cancelled) return;
1307
+ console.warn(`[MapChart] \u5730\u56FE\u6570\u636E\u52A0\u8F7D\u5931\u8D25\uFF1A${geoJsonUrl}`);
1308
+ setLoadState("error");
1309
+ });
1310
+ return () => {
1311
+ cancelled = true;
1312
+ };
1313
+ }, [geoJson, geoJsonUrl, mapName]);
1314
+ if (geoJsonUrl && !geoJson && loadState === "loading") {
1315
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1316
+ "div",
1317
+ {
1318
+ "data-slot": "map-chart-loading",
1319
+ className,
1320
+ style: { height: typeof height === "number" ? `${height}px` : height ?? 256, ...style }
1321
+ }
1322
+ );
1323
+ }
1324
+ if (!geoJson && loadState === "error") {
1325
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1326
+ import_components2.Empty,
1327
+ {
1328
+ title: "\u5730\u56FE\u52A0\u8F7D\u5931\u8D25",
1329
+ description: "\u8BF7\u68C0\u67E5 geoJsonUrl \u7F51\u7EDC\u53EF\u8FBE\u6027\uFF0C\u6216\u6539\u7528 geoJson / \u9884\u6CE8\u518C\u5730\u56FE",
1330
+ className,
1331
+ style
1332
+ }
1333
+ );
1334
+ }
1335
+ if (!geoJson && !hasRegisteredMap(mapName)) {
1336
+ console.warn(`[MapChart] \u5730\u56FE "${mapName}" \u672A\u6CE8\u518C\uFF1A\u8BF7\u4F20\u5165 geoJson / geoJsonUrl\uFF0C\u6216\u5728\u5E94\u7528\u542F\u52A8\u65F6 echarts.registerMap`);
1337
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1338
+ import_components2.Empty,
1339
+ {
1340
+ title: "\u5730\u56FE\u672A\u6CE8\u518C",
1341
+ description: "\u8BF7\u4F20\u5165 geoJson / geoJsonUrl\uFF0C\u6216\u5728\u5E94\u7528\u542F\u52A8\u65F6\u6CE8\u518C\u5730\u56FE\u6570\u636E",
1342
+ className,
1343
+ style
1344
+ }
1345
+ );
1346
+ }
1347
+ const option = buildMapOption({ mapName, data, nameKey, valueKey, title }, theme);
1348
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1349
+ EChartBase,
1350
+ {
1351
+ slot: "map-chart",
1352
+ option,
1353
+ height,
1354
+ onSelect,
1355
+ className,
1356
+ style
1357
+ }
1358
+ );
1359
+ }
1360
+
1361
+ // src/components/ComposedChart/index.tsx
1362
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1363
+ function ComposedChart({
1364
+ data = [],
1365
+ xKey,
1366
+ series = [],
1367
+ colors,
1368
+ title,
1369
+ height,
1370
+ onSelect,
1371
+ className,
1372
+ style
1373
+ }) {
1374
+ const option = buildComposedOption(
1375
+ { data, xKey, series, colors, title },
1376
+ useChartTheme()
1377
+ );
1378
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1379
+ EChartBase,
1380
+ {
1381
+ slot: "composed-chart",
1382
+ option,
1383
+ height,
1384
+ onSelect,
1385
+ className,
1386
+ style
1387
+ }
1388
+ );
1389
+ }
1390
+
1391
+ // src/index.ts
1392
+ var chartComponents = {
1393
+ MetricCard,
1394
+ LineChart: LineChart2,
1395
+ ColumnChart,
1396
+ BarChart: BarChart2,
1397
+ AreaChart,
1398
+ PieChart: PieChart2,
1399
+ DonutChart,
1400
+ ScatterChart: ScatterChart2,
1401
+ BubbleChart,
1402
+ RadarChart: RadarChart2,
1403
+ FunnelChart: FunnelChart2,
1404
+ GaugeChart: GaugeChart2,
1405
+ Heatmap,
1406
+ TreeChart: TreeChart2,
1407
+ SankeyChart: SankeyChart2,
1408
+ MapChart: MapChart2,
1409
+ ComposedChart
1410
+ };
1411
+ function registerChartComponents(registry) {
1412
+ for (const [type, component] of Object.entries(chartComponents)) {
1413
+ registry.register(type, component);
1414
+ }
1415
+ }
1416
+ function createChartComponentRegistry() {
1417
+ const registry = new import_core.Registry("ComponentRegistry");
1418
+ registerChartComponents(registry);
1419
+ return registry;
1420
+ }
1421
+ // Annotate the CommonJS export names for ESM import in node:
1422
+ 0 && (module.exports = {
1423
+ AreaChart,
1424
+ BarChart,
1425
+ BubbleChart,
1426
+ ColumnChart,
1427
+ ComposedChart,
1428
+ DonutChart,
1429
+ EChartBase,
1430
+ FunnelChart,
1431
+ GaugeChart,
1432
+ Heatmap,
1433
+ LineChart,
1434
+ MapChart,
1435
+ MetricCard,
1436
+ PieChart,
1437
+ RadarChart,
1438
+ SankeyChart,
1439
+ ScatterChart,
1440
+ TreeChart,
1441
+ chartComponents,
1442
+ createChartComponentRegistry,
1443
+ registerChartComponents
1444
+ });