@zendir/ui 0.1.8 → 0.1.9

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 (79) hide show
  1. package/dist/index.js +0 -137
  2. package/dist/index.js.map +1 -1
  3. package/dist/react/context/DisplaySettingsContext.js +0 -12
  4. package/dist/react/context/DisplaySettingsContext.js.map +1 -1
  5. package/dist/react/index.d.ts +0 -30
  6. package/dist/react/utils/index.js +0 -8
  7. package/dist/react/utils/index.js.map +1 -1
  8. package/dist/react.js +0 -137
  9. package/dist/react.js.map +1 -1
  10. package/package.json +1 -1
  11. package/dist/react/3d/EarthViewer.js +0 -836
  12. package/dist/react/3d/EarthViewer.js.map +0 -1
  13. package/dist/react/3d/SolarSystemViewer.js +0 -372
  14. package/dist/react/3d/SolarSystemViewer.js.map +0 -1
  15. package/dist/react/3d/ZenSpace3D.js +0 -1253
  16. package/dist/react/3d/ZenSpace3D.js.map +0 -1
  17. package/dist/react/3d/ZenSpace3DCesium.js +0 -186
  18. package/dist/react/3d/ZenSpace3DCesium.js.map +0 -1
  19. package/dist/react/3d/ZenSpace3DShaders.js +0 -94
  20. package/dist/react/3d/ZenSpace3DShaders.js.map +0 -1
  21. package/dist/react/3d/ZenSpace3DUtils.js +0 -213
  22. package/dist/react/3d/ZenSpace3DUtils.js.map +0 -1
  23. package/dist/react/3d/threeLoader.js +0 -18
  24. package/dist/react/3d/threeLoader.js.map +0 -1
  25. package/dist/react/cards/AccessCard.js +0 -410
  26. package/dist/react/cards/AccessCard.js.map +0 -1
  27. package/dist/react/cards/OrbitCard.js +0 -372
  28. package/dist/react/cards/OrbitCard.js.map +0 -1
  29. package/dist/react/cards/SpacecraftCard.js +0 -941
  30. package/dist/react/cards/SpacecraftCard.js.map +0 -1
  31. package/dist/react/cards/TelemetryCard.js +0 -742
  32. package/dist/react/cards/TelemetryCard.js.map +0 -1
  33. package/dist/react/cards/TelemetryStreamCard.js +0 -309
  34. package/dist/react/cards/TelemetryStreamCard.js.map +0 -1
  35. package/dist/react/charts/GroundTrackMap.js +0 -1123
  36. package/dist/react/charts/GroundTrackMap.js.map +0 -1
  37. package/dist/react/charts/GroundTrackMapLeaflet.js +0 -571
  38. package/dist/react/charts/GroundTrackMapLeaflet.js.map +0 -1
  39. package/dist/react/charts/groundTrackMapLeafletTiles.js +0 -11
  40. package/dist/react/charts/groundTrackMapLeafletTiles.js.map +0 -1
  41. package/dist/react/charts/groundTrackMapLeafletUtils.js +0 -109
  42. package/dist/react/charts/groundTrackMapLeafletUtils.js.map +0 -1
  43. package/dist/react/charts/unified/AstroChart.js +0 -1405
  44. package/dist/react/charts/unified/AstroChart.js.map +0 -1
  45. package/dist/react/charts/unified/PowerOverviewChart.js +0 -488
  46. package/dist/react/charts/unified/PowerOverviewChart.js.map +0 -1
  47. package/dist/react/charts/unified/domain.js +0 -3168
  48. package/dist/react/charts/unified/domain.js.map +0 -1
  49. package/dist/react/charts/unified/generators.js +0 -518
  50. package/dist/react/charts/unified/generators.js.map +0 -1
  51. package/dist/react/charts/unified/presets.js +0 -999
  52. package/dist/react/charts/unified/presets.js.map +0 -1
  53. package/dist/react/charts/unified/sync.js +0 -219
  54. package/dist/react/charts/unified/sync.js.map +0 -1
  55. package/dist/react/charts/unified/theme.js +0 -562
  56. package/dist/react/charts/unified/theme.js.map +0 -1
  57. package/dist/react/charts/unified/useChartStream.js +0 -226
  58. package/dist/react/charts/unified/useChartStream.js.map +0 -1
  59. package/dist/react/visualizations/EclipseTimerCard.js +0 -250
  60. package/dist/react/visualizations/EclipseTimerCard.js.map +0 -1
  61. package/dist/react/visualizations/LinkBudgetCard.js +0 -444
  62. package/dist/react/visualizations/LinkBudgetCard.js.map +0 -1
  63. package/dist/react/visualizations/NavBallCard.js +0 -243
  64. package/dist/react/visualizations/NavBallCard.js.map +0 -1
  65. package/dist/react/visualizations/PropulsionCard.js +0 -298
  66. package/dist/react/visualizations/PropulsionCard.js.map +0 -1
  67. package/dist/react/visualizations/SensorFootprintCard.js +0 -326
  68. package/dist/react/visualizations/SensorFootprintCard.js.map +0 -1
  69. package/dist/react/visualizations/ThermalHeatmapCard.js +0 -372
  70. package/dist/react/visualizations/ThermalHeatmapCard.js.map +0 -1
  71. package/dist/shaders/atmosphere.frag.js +0 -5
  72. package/dist/shaders/atmosphere.frag.js.map +0 -1
  73. package/dist/shaders/atmosphere.vert.js +0 -5
  74. package/dist/shaders/atmosphere.vert.js.map +0 -1
  75. package/dist/shaders/stars.frag.js +0 -5
  76. package/dist/shaders/stars.frag.js.map +0 -1
  77. package/dist/shaders/stars.vert.js +0 -5
  78. package/dist/shaders/stars.vert.js.map +0 -1
  79. package/dist/style.css +0 -143
@@ -1,1405 +0,0 @@
1
- import { jsxs, jsx } from "react/jsx-runtime";
2
- import { memo, forwardRef, useRef, useMemo, useCallback, useImperativeHandle, useState, useEffect } from "react";
3
- import ReactEChartsCore from "echarts-for-react/lib/core";
4
- import * as echarts from "echarts/core";
5
- import { LineChart, BarChart, PieChart, ScatterChart, RadarChart, GaugeChart, HeatmapChart, CandlestickChart, BoxplotChart, TreemapChart, SunburstChart, FunnelChart, SankeyChart, CustomChart, GraphChart, ParallelChart } from "echarts/charts";
6
- import { GridComponent, TooltipComponent, TitleComponent, LegendComponent, DataZoomComponent, ToolboxComponent, MarkLineComponent, MarkAreaComponent, MarkPointComponent, VisualMapComponent, BrushComponent, PolarComponent, RadarComponent, GeoComponent, ParallelComponent } from "echarts/components";
7
- import { CanvasRenderer, SVGRenderer } from "echarts/renderers";
8
- import { AstroIcon } from "../../core/AstroIcon.js";
9
- import { HeaderIconWithStatus } from "../../core/HeaderIconWithStatus.js";
10
- import { useCardBorderStyle } from "../../context/DisplaySettingsContext.js";
11
- import { createAstroEChartsTheme, getSeriesColor, createAreaGradient } from "./theme.js";
12
- import { useTheme } from "../../theme/ThemeProvider.js";
13
- const STATUS_SHAPES = {
14
- off: (size, color) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 12 12", width: size, height: size, children: /* @__PURE__ */ jsx("circle", { cx: "6", cy: "6", r: "5", fill: color }) }),
15
- standby: (size, color) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 12 12", width: size, height: size, children: /* @__PURE__ */ jsx("circle", { cx: "6", cy: "6", r: "5", fill: color }) }),
16
- normal: (size, color) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 12 12", width: size, height: size, children: /* @__PURE__ */ jsx("circle", { cx: "6", cy: "6", r: "5", fill: color }) }),
17
- caution: (size, color) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 12 12", width: size, height: size, children: /* @__PURE__ */ jsx("rect", { x: "1", y: "1", width: "10", height: "10", fill: color }) }),
18
- serious: (size, color) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 12 12", width: size, height: size, children: /* @__PURE__ */ jsx("polygon", { points: "6,1 11,6 6,11 1,6", fill: color }) }),
19
- critical: (size, color) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 12 12", width: size, height: size, children: /* @__PURE__ */ jsx("polygon", { points: "6,11 1,2 11,2", fill: color }) })
20
- };
21
- const STATUS_LABELS = {
22
- off: "Off",
23
- standby: "Standby",
24
- normal: "Normal",
25
- caution: "Caution",
26
- serious: "Serious",
27
- critical: "Critical"
28
- };
29
- function slug(str) {
30
- return str.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
31
- }
32
- function derivedExportBaseName(title, seriesNames, chartType) {
33
- const parts = ["zendir"];
34
- if (title) parts.push(slug(title));
35
- else parts.push("chart");
36
- const seriesSlug = seriesNames.slice(0, 4).map(slug).filter(Boolean).join("-");
37
- if (seriesSlug) parts.push(seriesSlug);
38
- parts.push(slug(chartType));
39
- return parts.join("-") || "zendir-chart";
40
- }
41
- echarts.use([
42
- LineChart,
43
- BarChart,
44
- PieChart,
45
- ScatterChart,
46
- RadarChart,
47
- GaugeChart,
48
- HeatmapChart,
49
- CandlestickChart,
50
- BoxplotChart,
51
- TreemapChart,
52
- SunburstChart,
53
- FunnelChart,
54
- SankeyChart,
55
- CustomChart,
56
- GraphChart,
57
- ParallelChart,
58
- GridComponent,
59
- TooltipComponent,
60
- TitleComponent,
61
- LegendComponent,
62
- DataZoomComponent,
63
- ToolboxComponent,
64
- MarkLineComponent,
65
- MarkAreaComponent,
66
- MarkPointComponent,
67
- VisualMapComponent,
68
- BrushComponent,
69
- PolarComponent,
70
- RadarComponent,
71
- GeoComponent,
72
- ParallelComponent,
73
- CanvasRenderer,
74
- SVGRenderer
75
- ]);
76
- function transformSeriesToECharts(series, chartType, theme) {
77
- return series.map((s, index) => {
78
- var _a, _b, _c, _d, _e;
79
- const seriesType = s.type || chartType;
80
- const color = s.color || getSeriesColor(index);
81
- const baseSeries = {
82
- id: s.id,
83
- name: s.name,
84
- type: mapChartType(seriesType),
85
- data: transformData(s.data, seriesType),
86
- yAxisIndex: s.yAxisIndex || 0,
87
- showSymbol: seriesType === "scatter" || ((_a = s.symbol) == null ? void 0 : _a.type) !== "none",
88
- smooth: s.smooth ?? (seriesType === "line" || seriesType === "area")
89
- };
90
- if (seriesType === "line" || seriesType === "area") {
91
- baseSeries.lineStyle = {
92
- width: ((_b = s.lineStyle) == null ? void 0 : _b.width) ?? 2,
93
- type: ((_c = s.lineStyle) == null ? void 0 : _c.type) ?? "solid",
94
- opacity: ((_d = s.lineStyle) == null ? void 0 : _d.opacity) ?? 1
95
- };
96
- baseSeries.itemStyle = { color };
97
- if (seriesType === "area") {
98
- baseSeries.areaStyle = s.areaStyle || {
99
- opacity: 0.3,
100
- color: createAreaGradient(color)
101
- };
102
- }
103
- if (s.symbol) {
104
- baseSeries.symbol = s.symbol.type || "circle";
105
- baseSeries.symbolSize = s.symbol.size || 6;
106
- }
107
- }
108
- if (seriesType === "bar") {
109
- baseSeries.itemStyle = {
110
- color,
111
- borderRadius: [4, 4, 0, 0]
112
- };
113
- if (s.stack) {
114
- baseSeries.stack = s.stack;
115
- }
116
- }
117
- if (seriesType === "pie" || seriesType === "donut") {
118
- baseSeries.radius = seriesType === "donut" ? ["40%", "70%"] : "70%";
119
- baseSeries.label = {
120
- show: true,
121
- formatter: "{b}: {d}%",
122
- color: theme.textStyle.color,
123
- textBorderWidth: 0,
124
- textBorderColor: "transparent"
125
- };
126
- baseSeries.emphasis = {
127
- itemStyle: {
128
- shadowBlur: 10,
129
- shadowOffsetX: 0,
130
- shadowColor: "rgba(0, 0, 0, 0.5)"
131
- }
132
- };
133
- }
134
- if (seriesType === "scatter") {
135
- baseSeries.symbolSize = ((_e = s.symbol) == null ? void 0 : _e.size) || 10;
136
- baseSeries.itemStyle = { color };
137
- }
138
- if (seriesType === "gauge") {
139
- baseSeries.detail = {
140
- formatter: "{value}%",
141
- fontSize: 20,
142
- color: theme.textStyle.color
143
- };
144
- baseSeries.axisLine = {
145
- lineStyle: {
146
- width: 10,
147
- color: [
148
- [0.3, theme.color[1]],
149
- // Green
150
- [0.7, theme.color[3]],
151
- // Yellow
152
- [1, theme.color[2]]
153
- // Red
154
- ]
155
- }
156
- };
157
- }
158
- return baseSeries;
159
- });
160
- }
161
- function mapChartType(type) {
162
- switch (type) {
163
- case "area":
164
- return "line";
165
- case "donut":
166
- return "pie";
167
- default:
168
- return type;
169
- }
170
- }
171
- function transformData(data, type) {
172
- if (!data || data.length === 0) return [];
173
- if (typeof data[0] === "number") {
174
- return data;
175
- }
176
- if (Array.isArray(data[0])) {
177
- return data;
178
- }
179
- const firstItem = data[0];
180
- if ("time" in firstItem) {
181
- return data.map((d) => [d.time, d.value]);
182
- }
183
- if (type === "pie" || type === "donut") {
184
- return data.map((d) => ({
185
- name: String(d.x),
186
- value: d.y,
187
- // Apply color via itemStyle if specified
188
- ...d.color ? { itemStyle: { color: d.color } } : {},
189
- // Preserve any additional metadata
190
- ...d.meta || {}
191
- }));
192
- }
193
- return data.map((d) => [d.x, d.y]);
194
- }
195
- function buildEChartsOptions(props, theme, hideTitle = false) {
196
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
197
- const {
198
- type,
199
- series,
200
- title,
201
- subtitle,
202
- xAxis,
203
- yAxis,
204
- tooltip,
205
- legend,
206
- zoom,
207
- annotations,
208
- loading,
209
- compactAxes = true
210
- // Default: hide axis names for more chart space
211
- } = props;
212
- const showEChartsTitle = title && !hideTitle;
213
- const isPolar = type === "radar";
214
- const isPie = type === "pie" || type === "donut";
215
- const isGauge = type === "gauge";
216
- const isSankey = type === "sankey";
217
- const isTreemap = type === "treemap" || type === "sunburst";
218
- const isGraph = ((_a = props.echartsOptions) == null ? void 0 : _a.series) && Array.isArray(props.echartsOptions.series) && props.echartsOptions.series.some((s) => (s == null ? void 0 : s.type) === "graph");
219
- const is3D = !!(((_b = props.echartsOptions) == null ? void 0 : _b.grid3D) || ((_c = props.echartsOptions) == null ? void 0 : _c.xAxis3D) || ((_d = props.echartsOptions) == null ? void 0 : _d.globe) || ((_e = props.echartsOptions) == null ? void 0 : _e.series) && Array.isArray(props.echartsOptions.series) && props.echartsOptions.series.some((s) => {
220
- const seriesType = (s == null ? void 0 : s.type) || "";
221
- return seriesType.includes("3D") || seriesType.includes("3d");
222
- }));
223
- const needsGrid = !isPolar && !isPie && !isGauge && !isSankey && !isTreemap && !isGraph && !is3D && !props.hideAxes;
224
- const hasTitle = hideTitle ? true : !!title;
225
- const hasSubtitle = hideTitle ? false : !!subtitle;
226
- const legendPosition = (legend == null ? void 0 : legend.position) ?? "bottom";
227
- const legendAtTop = legendPosition === "top";
228
- const legendAtBottom = legendPosition === "bottom";
229
- const showLegend = (legend == null ? void 0 : legend.show) !== false;
230
- const options = {
231
- // Title - positioned to avoid legend overlap (hidden when using custom header)
232
- title: showEChartsTitle ? {
233
- text: title,
234
- subtext: subtitle,
235
- left: "center",
236
- top: legendAtTop && showLegend ? 35 : 10,
237
- textStyle: { ...theme.title.textStyle, fontWeight: theme.title.textStyle.fontWeight ?? "normal" },
238
- subtextStyle: theme.title.subtextStyle
239
- } : void 0,
240
- // Tooltip with improved contrast
241
- // When compactAxes is true, axis names are shown in the axisPointer label on hover
242
- tooltip: (tooltip == null ? void 0 : tooltip.enabled) !== false ? {
243
- trigger: (tooltip == null ? void 0 : tooltip.trigger) || (isPie ? "item" : "axis"),
244
- axisPointer: {
245
- type: (tooltip == null ? void 0 : tooltip.crosshair) === true || (tooltip == null ? void 0 : tooltip.crosshair) === "both" ? "cross" : "line",
246
- lineStyle: theme.axisPointer.lineStyle,
247
- crossStyle: theme.axisPointer.crossStyle,
248
- // Show axis value labels on hover (includes axis name context)
249
- label: compactAxes ? {
250
- show: true,
251
- backgroundColor: theme.tooltip.backgroundColor,
252
- borderColor: theme.tooltip.borderColor,
253
- color: theme.tooltip.textStyle.color,
254
- fontSize: 11,
255
- padding: [4, 8],
256
- // Add axis name prefix to the label when in compact mode
257
- formatter: (params) => {
258
- var _a2;
259
- const axisName = params.axisDimension === "x" ? xAxis == null ? void 0 : xAxis.name : Array.isArray(yAxis) ? (_a2 = yAxis[params.axisIndex]) == null ? void 0 : _a2.name : yAxis == null ? void 0 : yAxis.name;
260
- const value = typeof params.value === "number" ? params.value.toLocaleString() : params.value;
261
- return axisName ? `${axisName}: ${value}` : String(value);
262
- }
263
- } : void 0
264
- },
265
- backgroundColor: theme.tooltip.backgroundColor,
266
- borderColor: theme.tooltip.borderColor,
267
- borderWidth: theme.tooltip.borderWidth,
268
- textStyle: {
269
- ...theme.tooltip.textStyle,
270
- fontSize: 14
271
- // AstroUXDS minimum 14pt
272
- },
273
- extraCssText: theme.tooltip.extraCssText,
274
- confine: (tooltip == null ? void 0 : tooltip.confine) ?? true,
275
- formatter: tooltip == null ? void 0 : tooltip.formatter
276
- } : void 0,
277
- // Legend - ultra-compact styling for maximum chart space
278
- legend: showLegend ? {
279
- show: true,
280
- type: "scroll",
281
- orient: (legend == null ? void 0 : legend.orient) || "horizontal",
282
- left: (legend == null ? void 0 : legend.position) === "left" ? "left" : (legend == null ? void 0 : legend.position) === "right" ? "right" : "center",
283
- top: legendAtTop ? 4 : void 0,
284
- bottom: legendAtBottom ? 2 : void 0,
285
- padding: [2, 6],
286
- itemGap: 8,
287
- itemWidth: 12,
288
- itemHeight: 6,
289
- textStyle: {
290
- ...theme.legend.textStyle,
291
- fontSize: 10
292
- // Ultra-compact for maximum chart space
293
- },
294
- inactiveColor: theme.legend.inactiveColor,
295
- selectedMode: (legend == null ? void 0 : legend.interactive) !== false
296
- } : { show: false },
297
- // Grid - minimal spacing for maximum chart plotting area
298
- // When compactAxes is true, axis names are hidden so we need minimal padding
299
- // containLabel: true ensures axis tick labels don't get cut off
300
- // Extra space only needed for slider zoom (inside zoom is invisible)
301
- grid: needsGrid ? {
302
- left: compactAxes ? 8 : 40,
303
- right: Array.isArray(yAxis) && yAxis.length > 1 ? compactAxes ? 8 : 40 : 8,
304
- top: hasTitle ? hasSubtitle ? 50 : 36 : legendAtTop && showLegend ? 26 : 4,
305
- bottom: (legendAtBottom && showLegend ? 26 : 16) + ((zoom == null ? void 0 : zoom.type) === "slider" || (zoom == null ? void 0 : zoom.type) === "both" ? 26 : 0),
306
- containLabel: true
307
- } : void 0,
308
- // X Axis - compact font sizes for more chart space
309
- // In compact mode, hide axis name (shown in tooltip instead)
310
- xAxis: needsGrid ? {
311
- type: (xAxis == null ? void 0 : xAxis.type) || "time",
312
- name: compactAxes ? void 0 : xAxis == null ? void 0 : xAxis.name,
313
- nameLocation: (xAxis == null ? void 0 : xAxis.nameLocation) || "middle",
314
- nameGap: 18,
315
- nameTextStyle: {
316
- ...theme.xAxis.nameTextStyle,
317
- fontSize: 10,
318
- // Ultra-compact for maximum chart space
319
- fontWeight: 500
320
- },
321
- min: xAxis == null ? void 0 : xAxis.min,
322
- max: xAxis == null ? void 0 : xAxis.max,
323
- axisLine: {
324
- show: (xAxis == null ? void 0 : xAxis.showLine) !== false,
325
- lineStyle: theme.xAxis.axisLine.lineStyle
326
- },
327
- axisTick: {
328
- lineStyle: theme.xAxis.axisTick.lineStyle
329
- },
330
- axisLabel: {
331
- ...theme.xAxis.axisLabel,
332
- fontSize: 10,
333
- // Ultra-compact for maximum chart space
334
- formatter: xAxis == null ? void 0 : xAxis.labelFormatter,
335
- // Prevent label overlap - auto-hide overlapping labels
336
- hideOverlap: true,
337
- // Rotate labels slightly if needed for better fit
338
- rotate: 0,
339
- // Show fewer labels when space is tight
340
- interval: "auto"
341
- },
342
- splitLine: {
343
- show: (xAxis == null ? void 0 : xAxis.showGrid) !== false,
344
- lineStyle: { ...theme.xAxis.splitLine.lineStyle, type: theme.xAxis.splitLine.lineStyle.type ?? "solid" }
345
- },
346
- inverse: xAxis == null ? void 0 : xAxis.inverse
347
- } : void 0,
348
- // Y Axis - ultra-compact font sizes for maximum chart space
349
- // In compact mode, hide axis name (shown in tooltip instead)
350
- yAxis: needsGrid ? (Array.isArray(yAxis) ? yAxis : [yAxis || {}]).map((axis, i) => ({
351
- type: (axis == null ? void 0 : axis.type) || "value",
352
- name: compactAxes ? void 0 : axis == null ? void 0 : axis.name,
353
- nameLocation: (axis == null ? void 0 : axis.nameLocation) || "middle",
354
- nameGap: 28,
355
- nameTextStyle: {
356
- ...theme.yAxis.nameTextStyle,
357
- fontSize: 10,
358
- // Ultra-compact for maximum chart space
359
- fontWeight: 500
360
- },
361
- position: (axis == null ? void 0 : axis.position) || (i === 0 ? "left" : "right"),
362
- min: axis == null ? void 0 : axis.min,
363
- max: axis == null ? void 0 : axis.max,
364
- splitNumber: axis == null ? void 0 : axis.splitNumber,
365
- axisLine: {
366
- show: (axis == null ? void 0 : axis.showLine) !== false,
367
- lineStyle: theme.yAxis.axisLine.lineStyle
368
- },
369
- axisTick: {
370
- lineStyle: theme.yAxis.axisTick.lineStyle
371
- },
372
- axisLabel: {
373
- ...theme.yAxis.axisLabel,
374
- fontSize: 10,
375
- // Ultra-compact for maximum chart space
376
- formatter: (axis == null ? void 0 : axis.labelFormatter) ? axis.labelFormatter : (axis == null ? void 0 : axis.unit) ? (v) => `${v}${axis.unit}` : void 0
377
- },
378
- splitLine: {
379
- show: (axis == null ? void 0 : axis.showGrid) !== false,
380
- lineStyle: theme.yAxis.splitLine.lineStyle
381
- },
382
- inverse: axis == null ? void 0 : axis.inverse
383
- })) : void 0,
384
- // Radar (for radar charts) - transparent background for glassmorphic look
385
- radar: isPolar ? {
386
- indicator: ((_g = (_f = series[0]) == null ? void 0 : _f.data) == null ? void 0 : _g.map((d) => {
387
- const point = d;
388
- return {
389
- name: point.label || point.category || String(point.x),
390
- max: 100
391
- };
392
- })) || [],
393
- splitArea: {
394
- show: true,
395
- areaStyle: {
396
- color: ["transparent", "transparent", "transparent", "transparent", "transparent"]
397
- }
398
- },
399
- splitLine: {
400
- lineStyle: {
401
- color: theme.xAxis.splitLine.lineStyle.color,
402
- opacity: 0.4
403
- }
404
- },
405
- axisLine: {
406
- lineStyle: {
407
- color: theme.xAxis.axisLine.lineStyle.color,
408
- opacity: 0.4
409
- }
410
- },
411
- axisName: {
412
- color: theme.xAxis.axisLabel.color,
413
- fontSize: 12
414
- }
415
- } : void 0,
416
- // Data Zoom - inside zoom enabled by default for mouse wheel/pinch
417
- // Use zoom={{ enabled: false }} to disable, or zoom={{ type: 'slider' }} for slider
418
- dataZoom: (zoom == null ? void 0 : zoom.enabled) === false ? void 0 : [
419
- // Inside zoom (mouse wheel / pinch) - ENABLED BY DEFAULT
420
- ...(zoom == null ? void 0 : zoom.type) === "inside" || (zoom == null ? void 0 : zoom.type) === "both" || !(zoom == null ? void 0 : zoom.type) ? [{
421
- type: "inside",
422
- xAxisIndex: (zoom == null ? void 0 : zoom.axis) === "x" || (zoom == null ? void 0 : zoom.axis) === "both" || !(zoom == null ? void 0 : zoom.axis) ? 0 : void 0,
423
- yAxisIndex: (zoom == null ? void 0 : zoom.axis) === "y" || (zoom == null ? void 0 : zoom.axis) === "both" ? 0 : void 0,
424
- start: (zoom == null ? void 0 : zoom.start) ?? 0,
425
- end: (zoom == null ? void 0 : zoom.end) ?? 100,
426
- minSpan: zoom == null ? void 0 : zoom.minSpan,
427
- maxSpan: zoom == null ? void 0 : zoom.maxSpan,
428
- // Smooth zoom animation
429
- throttle: 50
430
- }] : [],
431
- // Slider zoom (only when explicitly requested)
432
- ...(zoom == null ? void 0 : zoom.type) === "slider" || (zoom == null ? void 0 : zoom.type) === "both" ? [{
433
- type: "slider",
434
- show: true,
435
- xAxisIndex: (zoom == null ? void 0 : zoom.axis) === "x" || (zoom == null ? void 0 : zoom.axis) === "both" ? 0 : void 0,
436
- yAxisIndex: (zoom == null ? void 0 : zoom.axis) === "y" || (zoom == null ? void 0 : zoom.axis) === "both" ? 0 : void 0,
437
- start: (zoom == null ? void 0 : zoom.start) ?? 0,
438
- end: (zoom == null ? void 0 : zoom.end) ?? 100,
439
- minSpan: zoom == null ? void 0 : zoom.minSpan,
440
- maxSpan: zoom == null ? void 0 : zoom.maxSpan,
441
- backgroundColor: theme.dataZoom.backgroundColor,
442
- borderColor: theme.dataZoom.borderColor,
443
- fillerColor: theme.dataZoom.fillerColor,
444
- handleStyle: { color: theme.dataZoom.handleColor },
445
- textStyle: theme.dataZoom.textStyle,
446
- height: 25,
447
- bottom: 10
448
- }] : []
449
- ],
450
- // Toolbox (export) – always use custom dropdown for consistent UI
451
- toolbox: ((_h = props.export) == null ? void 0 : _h.enabled) ? (() => {
452
- var _a2;
453
- return {
454
- show: false,
455
- // Hide ECharts toolbox, use custom export button instead
456
- right: 20,
457
- top: 10,
458
- feature: {
459
- dataView: ((_a2 = props.export.formats) == null ? void 0 : _a2.includes("json")) ? {
460
- show: true,
461
- readOnly: true
462
- } : void 0
463
- },
464
- iconStyle: {
465
- borderColor: theme.textStyle.color
466
- }
467
- };
468
- })() : void 0,
469
- // Series
470
- series: transformSeriesToECharts(series, type, theme),
471
- // Animation
472
- animation: !loading,
473
- animationDuration: 300,
474
- animationEasing: "cubicOut"
475
- };
476
- if ((annotations == null ? void 0 : annotations.markLines) && options.series) {
477
- const seriesArray = options.series;
478
- if (seriesArray.length > 0) {
479
- seriesArray[0].markLine = {
480
- silent: true,
481
- symbol: "none",
482
- data: annotations.markLines.data.map((line) => {
483
- var _a2, _b2;
484
- return {
485
- ...line,
486
- lineStyle: {
487
- color: line.color || theme.color[2],
488
- type: ((_a2 = line.lineStyle) == null ? void 0 : _a2.type) || "dashed",
489
- width: ((_b2 = line.lineStyle) == null ? void 0 : _b2.width) || 1
490
- },
491
- label: {
492
- show: !!line.label,
493
- formatter: line.label,
494
- position: "middle",
495
- // center of line so label doesn't overlap y-axis at bottom
496
- distance: 8,
497
- color: theme.textStyle.color,
498
- fontWeight: 600,
499
- fontSize: 11,
500
- textBorderWidth: 0,
501
- textBorderColor: "transparent",
502
- backgroundColor: theme.tooltip.backgroundColor,
503
- borderColor: line.color || theme.color[2],
504
- borderWidth: 1,
505
- borderRadius: 4,
506
- padding: [2, 6]
507
- }
508
- };
509
- })
510
- };
511
- }
512
- }
513
- if ((annotations == null ? void 0 : annotations.markAreas) && options.series) {
514
- const seriesArray = options.series;
515
- const axisLabelColor = ((_j = (_i = theme.xAxis) == null ? void 0 : _i.axisLabel) == null ? void 0 : _j.color) ?? ((_k = theme.textStyle) == null ? void 0 : _k.color) ?? "#94a3b8";
516
- const fadedColor = axisLabelColor.startsWith("rgba") ? axisLabelColor : `${axisLabelColor}cc`;
517
- const defaultLabelStyle = {
518
- show: true,
519
- color: fadedColor,
520
- fontSize: 11,
521
- fontWeight: "500",
522
- textBorderWidth: 0,
523
- textBorderColor: "transparent",
524
- formatter: (params) => {
525
- const name = ((params == null ? void 0 : params.name) ?? "") || (typeof (params == null ? void 0 : params.value) === "string" ? params.value : "");
526
- if (!name) return "";
527
- const icon = name.toLowerCase().includes("eclipse") ? "◐ " : "";
528
- return icon ? `${icon}${name}` : name;
529
- }
530
- };
531
- if (seriesArray.length > 0) {
532
- seriesArray[0].markArea = {
533
- silent: true,
534
- data: annotations.markAreas.data.map((pair) => {
535
- const [start, end] = pair;
536
- return [
537
- { ...start, label: { ...defaultLabelStyle, formatter: defaultLabelStyle.formatter } },
538
- end
539
- ];
540
- }),
541
- itemStyle: annotations.markAreas.itemStyle
542
- };
543
- }
544
- }
545
- if (props.echartsOptions) {
546
- return mergeOptions(options, props.echartsOptions);
547
- }
548
- return options;
549
- }
550
- function mergeOptions(base, custom) {
551
- let mergedSeries = base.series;
552
- if (custom.series) {
553
- const baseSeries = base.series || [];
554
- const customSeries = custom.series;
555
- const allBaseSeriesEmpty = baseSeries.length === 0 || baseSeries.every((s) => {
556
- if (!s) return true;
557
- if (!s.data) return true;
558
- if (Array.isArray(s.data) && s.data.length === 0) return true;
559
- return false;
560
- });
561
- const baseLen = baseSeries.length;
562
- const customLen = customSeries.length;
563
- if (baseLen === 1 && customLen === 1) {
564
- const b = baseSeries[0];
565
- const c = customSeries[0];
566
- if ((b == null ? void 0 : b.type) === "gauge" && (c == null ? void 0 : c.type) === "gauge") {
567
- mergedSeries = customSeries;
568
- } else if (allBaseSeriesEmpty) {
569
- mergedSeries = customSeries;
570
- } else {
571
- mergedSeries = [...baseSeries, ...customSeries];
572
- }
573
- } else if (allBaseSeriesEmpty) {
574
- mergedSeries = customSeries;
575
- } else {
576
- mergedSeries = [...baseSeries, ...customSeries];
577
- }
578
- }
579
- return {
580
- ...base,
581
- ...custom,
582
- series: mergedSeries
583
- };
584
- }
585
- const AstroChart = memo(forwardRef(
586
- function AstroChart2(props, ref) {
587
- var _a, _b, _c, _d, _e, _f, _g;
588
- const {
589
- width = "100%",
590
- height = 400,
591
- loading = false,
592
- emptyMessage = "No data available",
593
- className = "",
594
- style,
595
- ariaLabel,
596
- onChartReady,
597
- onClick,
598
- onHover,
599
- onZoomChange,
600
- onBrushSelect,
601
- realTime,
602
- series = [],
603
- infoTooltip,
604
- // Header icon/status system
605
- icon,
606
- iconStatus,
607
- statusMessage,
608
- showStatusBadge = false
609
- } = props;
610
- const chartRef = useRef(null);
611
- const { tokens, mode, theme: themeVariant } = useTheme();
612
- const isTransparentTheme = themeVariant === "transparent" || themeVariant === "transparent-bold" || themeVariant === "transparent-minimal";
613
- const isBoldVariant = themeVariant === "transparent-bold";
614
- const isMinimalVariant = themeVariant === "transparent-minimal";
615
- const cardBorderStyle = useCardBorderStyle(tokens, isTransparentTheme);
616
- const glassAccentColor = tokens.colors.accent.primary;
617
- const glassAccentMuted = `${glassAccentColor}66`;
618
- const headingConfig = ((_b = (_a = tokens.layout) == null ? void 0 : _a.card) == null ? void 0 : _b.heading) ?? {
619
- iconSize: 20,
620
- iconSizeCompact: 16,
621
- titleFontSize: "1.125rem",
622
- titleFontSizeChart: "0.875rem",
623
- titleFontWeight: 500,
624
- gap: 8
625
- };
626
- const chartTitleFontSize = headingConfig.titleFontSizeChart ?? headingConfig.titleFontSize;
627
- const theme = useMemo(
628
- () => createAstroEChartsTheme(tokens, mode, themeVariant),
629
- [tokens, mode, themeVariant]
630
- );
631
- const hideEChartsTitle = !!(icon || props.title);
632
- const options = useMemo(
633
- () => buildEChartsOptions(props, theme, hideEChartsTitle),
634
- [props, theme, hideEChartsTitle]
635
- );
636
- const getChart = useCallback(() => {
637
- var _a2;
638
- return (_a2 = chartRef.current) == null ? void 0 : _a2.getEchartsInstance();
639
- }, []);
640
- const getExportFileName = useCallback((extension, includeTimestamp = true) => {
641
- var _a2, _b2;
642
- const context = {
643
- title: props.title,
644
- subtitle: props.subtitle,
645
- seriesNames: series.map((s) => s.name),
646
- chartType: props.type
647
- };
648
- let base;
649
- if ((_a2 = props.export) == null ? void 0 : _a2.getExportFileName) {
650
- base = props.export.getExportFileName(context);
651
- } else if ((_b2 = props.export) == null ? void 0 : _b2.fileName) {
652
- base = props.export.fileName;
653
- } else {
654
- base = derivedExportBaseName(props.title, context.seriesNames, props.type);
655
- }
656
- if (includeTimestamp) {
657
- const d = /* @__PURE__ */ new Date();
658
- const ts = d.toISOString().slice(0, 19).replace(/[-T:]/g, "").replace(/(\d{8})(\d{6})/, "$1-$2");
659
- base = `${base}-${ts}`;
660
- }
661
- if (extension) base = `${base}.${extension.replace(/^\./, "")}`;
662
- return base;
663
- }, [props.title, props.subtitle, props.type, props.export, series]);
664
- useImperativeHandle(ref, () => ({
665
- getChart,
666
- resize: () => {
667
- var _a2;
668
- return (_a2 = getChart()) == null ? void 0 : _a2.resize();
669
- },
670
- getExportFileName,
671
- exportImage: (type = "png", pixelRatio = 2) => {
672
- const chart = getChart();
673
- if (!chart) return void 0;
674
- const imgType = type === "jpg" ? "jpeg" : type;
675
- return chart.getDataURL({
676
- type: imgType,
677
- pixelRatio,
678
- backgroundColor: "transparent"
679
- });
680
- },
681
- exportCSV: () => {
682
- var _a2, _b2;
683
- const rows = [];
684
- const headers = ["Index", ...series.map((s) => s.name)];
685
- rows.push(headers.join(","));
686
- const maxLen = Math.max(...series.map((s) => {
687
- var _a3;
688
- return ((_a3 = s.data) == null ? void 0 : _a3.length) || 0;
689
- }));
690
- for (let i = 0; i < maxLen; i++) {
691
- const row = [i.toString()];
692
- for (const s of series) {
693
- const data = s.data;
694
- const value = data == null ? void 0 : data[i];
695
- if (typeof value === "number") {
696
- row.push(value.toString());
697
- } else if (Array.isArray(value)) {
698
- row.push(((_a2 = value[1]) == null ? void 0 : _a2.toString()) || "");
699
- } else if (value && typeof value === "object") {
700
- const point = value;
701
- row.push(((_b2 = "value" in point ? point.value : point.y) == null ? void 0 : _b2.toString()) || "");
702
- } else {
703
- row.push("");
704
- }
705
- }
706
- rows.push(row.join(","));
707
- }
708
- return rows.join("\n");
709
- },
710
- appendData: (seriesIndex, data) => {
711
- var _a2;
712
- const chart = getChart();
713
- if (!chart) return;
714
- const option = chart.getOption();
715
- const seriesOpt = (_a2 = option.series) == null ? void 0 : _a2[seriesIndex];
716
- if (!seriesOpt) return;
717
- const currentData = [...seriesOpt.data || []];
718
- const newPoint = "time" in data ? [data.time, data.value] : [data.x, data.y];
719
- currentData.push(newPoint);
720
- const maxPoints = (realTime == null ? void 0 : realTime.maxPoints) || 1e3;
721
- while (currentData.length > maxPoints) {
722
- currentData.shift();
723
- }
724
- chart.setOption({
725
- series: [{
726
- data: currentData
727
- }]
728
- }, {
729
- replaceMerge: ["series"]
730
- });
731
- },
732
- clearData: () => {
733
- const chart = getChart();
734
- if (!chart) return;
735
- chart.setOption({
736
- series: series.map(() => ({ data: [] }))
737
- });
738
- },
739
- dispatchAction: (action) => {
740
- var _a2;
741
- (_a2 = getChart()) == null ? void 0 : _a2.dispatchAction(action);
742
- }
743
- }), [getChart, series, realTime]);
744
- const handleEvents = useMemo(() => {
745
- const events = {};
746
- if (onClick) {
747
- events.click = (params) => {
748
- onClick(params);
749
- };
750
- }
751
- if (onHover) {
752
- events.mouseover = (params) => {
753
- onHover(params);
754
- };
755
- }
756
- if (onZoomChange) {
757
- events.datazoom = (params) => {
758
- var _a2, _b2, _c2, _d2;
759
- const p = params;
760
- onZoomChange({
761
- start: ((_b2 = (_a2 = p.batch) == null ? void 0 : _a2[0]) == null ? void 0 : _b2.start) ?? p.start ?? 0,
762
- end: ((_d2 = (_c2 = p.batch) == null ? void 0 : _c2[0]) == null ? void 0 : _d2.end) ?? p.end ?? 100
763
- });
764
- };
765
- }
766
- if (onBrushSelect) {
767
- events.brushselected = (params) => {
768
- onBrushSelect(params);
769
- };
770
- }
771
- return events;
772
- }, [onClick, onHover, onZoomChange, onBrushSelect]);
773
- const handleChartReady = useCallback((chart) => {
774
- onChartReady == null ? void 0 : onChartReady(chart);
775
- }, [onChartReady]);
776
- const exportFormats = ((_c = props.export) == null ? void 0 : _c.formats) ?? ["png"];
777
- const useCustomExportDropdown = (_d = props.export) == null ? void 0 : _d.enabled;
778
- const [exportMenuOpen, setExportMenuOpen] = useState(false);
779
- const exportMenuRef = useRef(null);
780
- const [infoTooltipOpen, setInfoTooltipOpen] = useState(false);
781
- const infoTooltipRef = useRef(null);
782
- useEffect(() => {
783
- if (!infoTooltip || !infoTooltipOpen) return;
784
- const handleClickOutside = (e) => {
785
- if (infoTooltipRef.current && !infoTooltipRef.current.contains(e.target)) {
786
- setInfoTooltipOpen(false);
787
- }
788
- };
789
- document.addEventListener("mousedown", handleClickOutside);
790
- return () => document.removeEventListener("mousedown", handleClickOutside);
791
- }, [infoTooltip, infoTooltipOpen]);
792
- useEffect(() => {
793
- if (!useCustomExportDropdown || !exportMenuOpen) return;
794
- const handleClickOutside = (e) => {
795
- if (exportMenuRef.current && !exportMenuRef.current.contains(e.target)) {
796
- setExportMenuOpen(false);
797
- }
798
- };
799
- document.addEventListener("mousedown", handleClickOutside);
800
- return () => document.removeEventListener("mousedown", handleClickOutside);
801
- }, [useCustomExportDropdown, exportMenuOpen]);
802
- const handleExportFormat = useCallback((format) => {
803
- var _a2, _b2, _c2, _d2;
804
- const chart = getChart();
805
- if (format === "csv") {
806
- const rows = [];
807
- const headers = ["Index", ...series.map((s) => s.name)];
808
- rows.push(headers.join(","));
809
- const maxLen = Math.max(...series.map((s) => {
810
- var _a3;
811
- return ((_a3 = s.data) == null ? void 0 : _a3.length) || 0;
812
- }));
813
- for (let i = 0; i < maxLen; i++) {
814
- const row = [i.toString()];
815
- for (const s of series) {
816
- const data = s.data;
817
- const value = data == null ? void 0 : data[i];
818
- if (typeof value === "number") row.push(value.toString());
819
- else if (Array.isArray(value)) row.push(((_a2 = value[1]) == null ? void 0 : _a2.toString()) || "");
820
- else if (value && typeof value === "object") {
821
- const point = value;
822
- row.push(((_b2 = "value" in point ? point.value : point.y) == null ? void 0 : _b2.toString()) || "");
823
- } else row.push("");
824
- }
825
- rows.push(row.join(","));
826
- }
827
- const csv = rows.join("\n");
828
- const filename = getExportFileName("csv", true);
829
- const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
830
- const url = URL.createObjectURL(blob);
831
- const a = document.createElement("a");
832
- a.href = url;
833
- a.download = filename;
834
- a.click();
835
- URL.revokeObjectURL(url);
836
- } else if (chart) {
837
- const imgType = format === "jpeg" ? "jpeg" : format;
838
- const dataUrl = chart.getDataURL({
839
- type: imgType,
840
- pixelRatio: ((_c2 = props.export) == null ? void 0 : _c2.pixelRatio) || 2,
841
- backgroundColor: ((_d2 = props.export) == null ? void 0 : _d2.backgroundColor) || "transparent"
842
- });
843
- if (dataUrl) {
844
- const ext = format === "jpeg" ? "jpg" : format;
845
- const filename = getExportFileName(ext, true);
846
- const a = document.createElement("a");
847
- a.href = dataUrl;
848
- a.download = filename;
849
- a.click();
850
- }
851
- }
852
- setExportMenuOpen(false);
853
- }, [getChart, series, getExportFileName, (_e = props.export) == null ? void 0 : _e.pixelRatio, (_f = props.export) == null ? void 0 : _f.backgroundColor]);
854
- useEffect(() => {
855
- var _a2;
856
- const chart = getChart();
857
- if (!chart) return;
858
- let mounted = true;
859
- const resizeObserver = new ResizeObserver(() => {
860
- if (!mounted) return;
861
- try {
862
- chart.resize();
863
- } catch {
864
- }
865
- });
866
- const container = (_a2 = chartRef.current) == null ? void 0 : _a2.ele;
867
- if (container) {
868
- resizeObserver.observe(container);
869
- }
870
- return () => {
871
- mounted = false;
872
- resizeObserver.disconnect();
873
- };
874
- }, [getChart]);
875
- const needs3DCanvas = useMemo(() => {
876
- const eo = props.echartsOptions;
877
- if (!eo) return false;
878
- if (eo.grid3D || eo.xAxis3D || eo.yAxis3D || eo.zAxis3D || eo.globe || eo.geo3D) return true;
879
- if (Array.isArray(eo.series)) {
880
- return eo.series.some((s) => {
881
- const t = (s == null ? void 0 : s.type) || "";
882
- return t.includes("3D") || t.includes("3d") || t === "scatter3D" || t === "bar3D" || t === "surface" || t === "lines3D";
883
- });
884
- }
885
- return false;
886
- }, [props.echartsOptions]);
887
- const hasSeriesData = series.some((s) => s.data && s.data.length > 0);
888
- const hasEchartsOptionsSeries = ((_g = props.echartsOptions) == null ? void 0 : _g.series) && (Array.isArray(props.echartsOptions.series) ? props.echartsOptions.series.length > 0 : props.echartsOptions.series !== void 0);
889
- const hasData = hasSeriesData || hasEchartsOptionsSeries;
890
- const getStatusColor = (status) => {
891
- var _a2, _b2, _c2, _d2, _e2, _f2;
892
- switch (status) {
893
- case "critical":
894
- return ((_a2 = tokens.colors.status) == null ? void 0 : _a2.critical) || "#ff3838";
895
- case "serious":
896
- return ((_b2 = tokens.colors.status) == null ? void 0 : _b2.serious) || "#ffb302";
897
- case "caution":
898
- return ((_c2 = tokens.colors.status) == null ? void 0 : _c2.caution) || "#fce83a";
899
- case "normal":
900
- return ((_d2 = tokens.colors.status) == null ? void 0 : _d2.normal) || "#56f000";
901
- case "standby":
902
- return ((_e2 = tokens.colors.status) == null ? void 0 : _e2.standby) || "#2dccff";
903
- case "off":
904
- return ((_f2 = tokens.colors.status) == null ? void 0 : _f2.off) || "#a4abb6";
905
- default:
906
- return tokens.colors.text.secondary;
907
- }
908
- };
909
- const hasHeader = !!(icon || props.title);
910
- const useGlassMode = isBoldVariant || isMinimalVariant;
911
- const containerStyle = {
912
- width: typeof width === "number" ? `${width}px` : width,
913
- height: typeof height === "number" ? `${height}px` : height,
914
- borderRadius: tokens.borderRadius.lg,
915
- padding: tokens.spacing.sm,
916
- position: "relative",
917
- overflow: "hidden",
918
- // Glass mode styling for bold/minimal (matching Container)
919
- ...useGlassMode ? {
920
- backgroundColor: "rgba(10, 15, 25, 0.35)",
921
- backdropFilter: "blur(12px)",
922
- WebkitBackdropFilter: "blur(12px)",
923
- border: `1px solid ${glassAccentMuted}`,
924
- borderTop: isBoldVariant ? `2px solid ${glassAccentColor}` : `1px solid ${glassAccentColor}`,
925
- transition: "all 0.3s ease-out, box-shadow 0.3s ease-out"
926
- } : isTransparentTheme ? {
927
- // Regular transparent (glass) theme — match top cards (ISS): transparent + blur
928
- backgroundColor: "transparent",
929
- backdropFilter: "blur(12px)",
930
- WebkitBackdropFilter: "blur(12px)",
931
- ...cardBorderStyle
932
- } : {
933
- // Non-transparent themes — use same border as Container (muted) so chart doesn't stand out
934
- backgroundColor: tokens.colors.background.surface,
935
- border: `1px solid ${tokens.colors.border.muted}`
936
- },
937
- ...style
938
- };
939
- const glassGradient = useGlassMode ? `linear-gradient(135deg, ${glassAccentColor}10 0%, ${glassAccentColor}03 100%)` : void 0;
940
- if (!hasData && !loading) {
941
- return /* @__PURE__ */ jsxs(
942
- "div",
943
- {
944
- className: `astro-chart astro-chart--empty ${className}`,
945
- style: containerStyle,
946
- role: "group",
947
- "aria-roledescription": "chart",
948
- "aria-label": ariaLabel || "Empty chart",
949
- children: [
950
- useGlassMode && glassGradient && /* @__PURE__ */ jsx(
951
- "div",
952
- {
953
- style: {
954
- position: "absolute",
955
- inset: 0,
956
- background: glassGradient,
957
- pointerEvents: "none",
958
- zIndex: 0
959
- }
960
- }
961
- ),
962
- /* @__PURE__ */ jsx("div", { style: {
963
- display: "flex",
964
- alignItems: "center",
965
- justifyContent: "center",
966
- height: "100%",
967
- color: tokens.colors.text.secondary,
968
- fontFamily: tokens.typography.fontFamily.primary,
969
- fontSize: tokens.typography.fontSize.sm,
970
- position: "relative",
971
- zIndex: 1
972
- }, children: emptyMessage })
973
- ]
974
- }
975
- );
976
- }
977
- const exportImageFormats = exportFormats.filter((f) => ["png", "jpeg", "jpg", "svg"].includes(f));
978
- const hasCsv = exportFormats.includes("csv");
979
- return /* @__PURE__ */ jsxs(
980
- "div",
981
- {
982
- className: `astro-chart ${className}`,
983
- style: containerStyle,
984
- role: "group",
985
- "aria-roledescription": "chart",
986
- "aria-label": ariaLabel || props.title || "Chart",
987
- children: [
988
- useGlassMode && glassGradient && /* @__PURE__ */ jsx(
989
- "div",
990
- {
991
- style: {
992
- position: "absolute",
993
- inset: 0,
994
- background: glassGradient,
995
- pointerEvents: "none",
996
- zIndex: 0
997
- }
998
- }
999
- ),
1000
- hasHeader && isBoldVariant && /* @__PURE__ */ jsxs("div", { style: { position: "relative", zIndex: 1 }, children: [
1001
- /* @__PURE__ */ jsx("div", { style: {
1002
- display: "flex",
1003
- alignItems: "center",
1004
- justifyContent: "space-between",
1005
- padding: `12px ${tokens.spacing.sm} 0`
1006
- }, children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: headingConfig.gap }, children: [
1007
- icon && iconStatus && /* @__PURE__ */ jsx(
1008
- HeaderIconWithStatus,
1009
- {
1010
- icon,
1011
- size: headingConfig.iconSize,
1012
- status: iconStatus,
1013
- statusColor: getStatusColor(iconStatus)
1014
- }
1015
- ),
1016
- icon && !iconStatus && /* @__PURE__ */ jsx(
1017
- AstroIcon,
1018
- {
1019
- name: icon,
1020
- size: headingConfig.iconSize,
1021
- color: glassAccentColor
1022
- }
1023
- ),
1024
- props.title && /* @__PURE__ */ jsx("h3", { style: {
1025
- margin: 0,
1026
- fontSize: chartTitleFontSize,
1027
- fontWeight: headingConfig.titleFontWeight,
1028
- color: glassAccentColor,
1029
- letterSpacing: "0.5px",
1030
- textShadow: `0 0 20px ${glassAccentMuted}`
1031
- }, children: props.title })
1032
- ] }) }),
1033
- /* @__PURE__ */ jsxs("div", { style: {
1034
- display: "flex",
1035
- alignItems: "center",
1036
- gap: "8px",
1037
- padding: `10px ${tokens.spacing.sm} 0`,
1038
- marginBottom: tokens.spacing.xs
1039
- }, children: [
1040
- /* @__PURE__ */ jsx("div", { style: {
1041
- flex: 1,
1042
- height: "2px",
1043
- background: `linear-gradient(90deg, ${glassAccentColor} 0%, ${glassAccentMuted} 50%, transparent 100%)`,
1044
- boxShadow: `0 0 8px ${glassAccentMuted}`
1045
- } }),
1046
- showStatusBadge && iconStatus && /* @__PURE__ */ jsxs("span", { style: {
1047
- display: "inline-flex",
1048
- alignItems: "center",
1049
- gap: "4px",
1050
- padding: "2px 8px",
1051
- fontSize: "0.625rem",
1052
- // 10px in rem
1053
- fontWeight: 500,
1054
- // AstroUXDS medium (not 600)
1055
- letterSpacing: "0.05em",
1056
- color: getStatusColor(iconStatus),
1057
- backgroundColor: `${getStatusColor(iconStatus)}20`,
1058
- border: `1px solid ${getStatusColor(iconStatus)}40`,
1059
- borderRadius: "3px",
1060
- whiteSpace: "nowrap"
1061
- }, children: [
1062
- STATUS_SHAPES[iconStatus](6, getStatusColor(iconStatus)),
1063
- STATUS_LABELS[iconStatus]
1064
- ] })
1065
- ] })
1066
- ] }),
1067
- hasHeader && isMinimalVariant && /* @__PURE__ */ jsxs("div", { style: {
1068
- display: "flex",
1069
- alignItems: "center",
1070
- padding: `${tokens.spacing.xs} ${tokens.spacing.sm} 0`,
1071
- marginBottom: tokens.spacing.xs,
1072
- position: "relative",
1073
- zIndex: 1
1074
- }, children: [
1075
- icon && iconStatus && /* @__PURE__ */ jsx(
1076
- HeaderIconWithStatus,
1077
- {
1078
- icon,
1079
- size: headingConfig.iconSizeCompact,
1080
- status: iconStatus,
1081
- statusColor: getStatusColor(iconStatus),
1082
- style: { marginRight: tokens.spacing.sm }
1083
- }
1084
- ),
1085
- icon && !iconStatus && /* @__PURE__ */ jsx(
1086
- AstroIcon,
1087
- {
1088
- name: icon,
1089
- size: headingConfig.iconSizeCompact,
1090
- color: glassAccentColor,
1091
- style: { marginRight: tokens.spacing.sm }
1092
- }
1093
- ),
1094
- props.title && /* @__PURE__ */ jsx("h3", { style: {
1095
- margin: 0,
1096
- fontSize: chartTitleFontSize,
1097
- fontWeight: headingConfig.titleFontWeight,
1098
- color: glassAccentColor,
1099
- textShadow: `0 0 16px ${glassAccentMuted}`,
1100
- letterSpacing: "0.02em",
1101
- whiteSpace: "nowrap",
1102
- marginRight: "12px"
1103
- }, children: props.title }),
1104
- /* @__PURE__ */ jsxs("div", { style: {
1105
- flex: 1,
1106
- display: "flex",
1107
- alignItems: "center",
1108
- gap: headingConfig.gap,
1109
- minWidth: 40
1110
- }, children: [
1111
- /* @__PURE__ */ jsx("div", { style: {
1112
- flex: 1,
1113
- height: "1px",
1114
- background: `linear-gradient(90deg, ${glassAccentColor} 0%, ${glassAccentMuted} 60%, transparent 100%)`
1115
- } }),
1116
- showStatusBadge && iconStatus && /* @__PURE__ */ jsxs("span", { style: {
1117
- display: "inline-flex",
1118
- alignItems: "center",
1119
- gap: "3px",
1120
- padding: "1px 6px",
1121
- fontSize: "0.5625rem",
1122
- // 9px in rem (micro)
1123
- fontWeight: 500,
1124
- // AstroUXDS medium (not 600)
1125
- letterSpacing: "0.05em",
1126
- color: getStatusColor(iconStatus),
1127
- backgroundColor: `${getStatusColor(iconStatus)}15`,
1128
- border: `1px solid ${getStatusColor(iconStatus)}30`,
1129
- borderRadius: "2px",
1130
- whiteSpace: "nowrap"
1131
- }, children: [
1132
- STATUS_SHAPES[iconStatus](5, getStatusColor(iconStatus)),
1133
- STATUS_LABELS[iconStatus]
1134
- ] })
1135
- ] })
1136
- ] }),
1137
- hasHeader && isTransparentTheme && !useGlassMode && /* @__PURE__ */ jsxs(
1138
- "div",
1139
- {
1140
- title: statusMessage,
1141
- style: {
1142
- position: "absolute",
1143
- top: 6,
1144
- left: 8,
1145
- display: "flex",
1146
- alignItems: "center",
1147
- gap: headingConfig.gap,
1148
- zIndex: 10
1149
- },
1150
- children: [
1151
- icon && iconStatus && /* @__PURE__ */ jsx(
1152
- HeaderIconWithStatus,
1153
- {
1154
- icon,
1155
- size: headingConfig.iconSizeCompact,
1156
- status: iconStatus,
1157
- statusColor: getStatusColor(iconStatus)
1158
- }
1159
- ),
1160
- icon && !iconStatus && /* @__PURE__ */ jsx(
1161
- AstroIcon,
1162
- {
1163
- name: icon,
1164
- size: headingConfig.iconSizeCompact,
1165
- color: tokens.colors.text.tertiary
1166
- }
1167
- ),
1168
- props.title && /* @__PURE__ */ jsx("span", { style: {
1169
- fontSize: chartTitleFontSize,
1170
- fontWeight: headingConfig.titleFontWeight,
1171
- color: tokens.colors.text.primary
1172
- }, children: props.title })
1173
- ]
1174
- }
1175
- ),
1176
- hasHeader && !isTransparentTheme && /* @__PURE__ */ jsxs(
1177
- "div",
1178
- {
1179
- title: statusMessage,
1180
- style: {
1181
- position: "absolute",
1182
- top: 6,
1183
- left: 8,
1184
- display: "flex",
1185
- alignItems: "center",
1186
- gap: headingConfig.gap,
1187
- zIndex: 10
1188
- },
1189
- children: [
1190
- icon && iconStatus && /* @__PURE__ */ jsx(
1191
- HeaderIconWithStatus,
1192
- {
1193
- icon,
1194
- size: headingConfig.iconSizeCompact,
1195
- status: iconStatus,
1196
- statusColor: getStatusColor(iconStatus)
1197
- }
1198
- ),
1199
- icon && !iconStatus && /* @__PURE__ */ jsx(
1200
- AstroIcon,
1201
- {
1202
- name: icon,
1203
- size: headingConfig.iconSizeCompact,
1204
- color: tokens.colors.text.tertiary
1205
- }
1206
- ),
1207
- props.title && /* @__PURE__ */ jsx("span", { style: {
1208
- fontSize: chartTitleFontSize,
1209
- fontWeight: headingConfig.titleFontWeight,
1210
- color: tokens.colors.text.primary
1211
- }, children: props.title })
1212
- ]
1213
- }
1214
- ),
1215
- /* @__PURE__ */ jsx(
1216
- ReactEChartsCore,
1217
- {
1218
- ref: chartRef,
1219
- echarts,
1220
- option: options,
1221
- opts: {
1222
- renderer: props.renderer ?? (needs3DCanvas ? "canvas" : "svg"),
1223
- ...(props.renderer === "canvas" || needs3DCanvas) && typeof window !== "undefined" && { devicePixelRatio: window.devicePixelRatio || 1 }
1224
- },
1225
- style: { width: "100%", height: "100%" },
1226
- notMerge: true,
1227
- lazyUpdate: true,
1228
- showLoading: loading,
1229
- loadingOption: {
1230
- text: "Loading...",
1231
- color: tokens.colors.accent.primary,
1232
- textColor: tokens.colors.text.primary,
1233
- maskColor: isTransparentTheme ? "rgba(10, 15, 25, 0.6)" : `${tokens.colors.background.surface}80`
1234
- },
1235
- onEvents: handleEvents,
1236
- onChartReady: handleChartReady
1237
- }
1238
- ),
1239
- /* @__PURE__ */ jsxs("div", { style: {
1240
- position: "absolute",
1241
- right: 8,
1242
- top: 6,
1243
- zIndex: 10,
1244
- display: "flex",
1245
- alignItems: "center",
1246
- gap: 4
1247
- }, children: [
1248
- infoTooltip && /* @__PURE__ */ jsxs("div", { ref: infoTooltipRef, style: { position: "relative" }, children: [
1249
- /* @__PURE__ */ jsx(
1250
- "button",
1251
- {
1252
- type: "button",
1253
- onClick: () => setInfoTooltipOpen((v) => !v),
1254
- "aria-label": "Chart information",
1255
- "aria-expanded": infoTooltipOpen,
1256
- style: {
1257
- display: "flex",
1258
- alignItems: "center",
1259
- justifyContent: "center",
1260
- width: 20,
1261
- height: 20,
1262
- padding: 4,
1263
- border: `1px solid ${tokens.colors.border.default}`,
1264
- borderRadius: "50%",
1265
- background: infoTooltipOpen ? tokens.colors.accent.primary : isTransparentTheme ? "rgba(10, 15, 25, 0.5)" : tokens.colors.background.surface,
1266
- color: infoTooltipOpen ? tokens.colors.background.base : tokens.colors.text.secondary,
1267
- cursor: "pointer",
1268
- transition: "all 0.15s ease"
1269
- },
1270
- children: infoTooltip.icon || /* @__PURE__ */ jsx("svg", { width: "10", height: "10", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z" }) })
1271
- }
1272
- ),
1273
- infoTooltipOpen && /* @__PURE__ */ jsx(
1274
- "div",
1275
- {
1276
- role: "tooltip",
1277
- style: {
1278
- position: "absolute",
1279
- right: 0,
1280
- top: "100%",
1281
- marginTop: 8,
1282
- minWidth: 200,
1283
- maxWidth: infoTooltip.maxWidth || 300,
1284
- padding: "12px 16px",
1285
- background: isTransparentTheme ? "rgba(10, 15, 25, 0.85)" : tokens.colors.background.surface,
1286
- backdropFilter: isTransparentTheme ? "blur(12px)" : void 0,
1287
- border: `1px solid ${tokens.colors.border.default}`,
1288
- borderRadius: tokens.borderRadius.md,
1289
- boxShadow: "0 4px 16px rgba(0,0,0,0.25)",
1290
- color: tokens.colors.text.primary,
1291
- fontFamily: tokens.typography.fontFamily.primary,
1292
- fontSize: tokens.typography.fontSize.sm,
1293
- lineHeight: 1.5,
1294
- zIndex: 20
1295
- },
1296
- children: infoTooltip.content
1297
- }
1298
- )
1299
- ] }),
1300
- useCustomExportDropdown && /* @__PURE__ */ jsxs("div", { ref: exportMenuRef, style: { position: "relative" }, children: [
1301
- /* @__PURE__ */ jsx(
1302
- "button",
1303
- {
1304
- type: "button",
1305
- onClick: () => setExportMenuOpen((v) => !v),
1306
- "aria-haspopup": "true",
1307
- "aria-expanded": exportMenuOpen,
1308
- "aria-label": "Save chart as",
1309
- style: {
1310
- display: "flex",
1311
- alignItems: "center",
1312
- justifyContent: "center",
1313
- width: 20,
1314
- height: 20,
1315
- padding: 4,
1316
- border: `1px solid ${tokens.colors.border.default}`,
1317
- borderRadius: "50%",
1318
- background: isTransparentTheme ? "rgba(10, 15, 25, 0.5)" : tokens.colors.background.surface,
1319
- color: tokens.colors.text.secondary,
1320
- cursor: "pointer",
1321
- transition: "all 0.15s ease"
1322
- },
1323
- children: /* @__PURE__ */ jsxs("svg", { width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1324
- /* @__PURE__ */ jsx("path", { d: "M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" }),
1325
- /* @__PURE__ */ jsx("polyline", { points: "7 10 12 15 17 10" }),
1326
- /* @__PURE__ */ jsx("line", { x1: "12", y1: "15", x2: "12", y2: "3" })
1327
- ] })
1328
- }
1329
- ),
1330
- exportMenuOpen && /* @__PURE__ */ jsxs(
1331
- "div",
1332
- {
1333
- role: "menu",
1334
- style: {
1335
- position: "absolute",
1336
- right: 0,
1337
- top: "100%",
1338
- marginTop: 4,
1339
- minWidth: 120,
1340
- padding: 4,
1341
- background: tokens.colors.background.surface,
1342
- border: `1px solid ${tokens.colors.border.default}`,
1343
- borderRadius: tokens.borderRadius.md,
1344
- boxShadow: "0 4px 12px rgba(0,0,0,0.2)"
1345
- },
1346
- children: [
1347
- exportImageFormats.map((f) => /* @__PURE__ */ jsx(
1348
- "button",
1349
- {
1350
- type: "button",
1351
- role: "menuitem",
1352
- onClick: () => handleExportFormat(f === "jpg" ? "jpeg" : f),
1353
- style: {
1354
- display: "block",
1355
- width: "100%",
1356
- padding: "8px 12px",
1357
- border: "none",
1358
- borderRadius: tokens.borderRadius.sm,
1359
- background: "transparent",
1360
- color: tokens.colors.text.primary,
1361
- fontFamily: tokens.typography.fontFamily.primary,
1362
- fontSize: tokens.typography.fontSize.sm,
1363
- textAlign: "left",
1364
- cursor: "pointer"
1365
- },
1366
- children: f.toUpperCase()
1367
- },
1368
- f
1369
- )),
1370
- hasCsv && /* @__PURE__ */ jsx(
1371
- "button",
1372
- {
1373
- type: "button",
1374
- role: "menuitem",
1375
- onClick: () => handleExportFormat("csv"),
1376
- style: {
1377
- display: "block",
1378
- width: "100%",
1379
- padding: "8px 12px",
1380
- border: "none",
1381
- borderRadius: tokens.borderRadius.sm,
1382
- background: "transparent",
1383
- color: tokens.colors.text.primary,
1384
- fontFamily: tokens.typography.fontFamily.primary,
1385
- fontSize: tokens.typography.fontSize.sm,
1386
- textAlign: "left",
1387
- cursor: "pointer"
1388
- },
1389
- children: "CSV"
1390
- }
1391
- )
1392
- ]
1393
- }
1394
- )
1395
- ] })
1396
- ] })
1397
- ]
1398
- }
1399
- );
1400
- }
1401
- ));
1402
- export {
1403
- AstroChart
1404
- };
1405
- //# sourceMappingURL=AstroChart.js.map