@almadar/ui 4.51.13 → 4.51.15

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.
@@ -3933,6 +3933,67 @@ var init_Radio = __esm({
3933
3933
  Radio.displayName = "Radio";
3934
3934
  }
3935
3935
  });
3936
+ var COLOR_VAR, Sparkline;
3937
+ var init_Sparkline = __esm({
3938
+ "components/atoms/Sparkline.tsx"() {
3939
+ init_cn();
3940
+ COLOR_VAR = {
3941
+ primary: "var(--color-primary)",
3942
+ success: "var(--color-success)",
3943
+ warning: "var(--color-warning)",
3944
+ error: "var(--color-error)",
3945
+ info: "var(--color-info)",
3946
+ muted: "var(--color-muted-foreground)"
3947
+ };
3948
+ Sparkline = ({
3949
+ data,
3950
+ color = "auto",
3951
+ width = 80,
3952
+ height = 32,
3953
+ strokeWidth = 2,
3954
+ fill = false,
3955
+ className
3956
+ }) => {
3957
+ if (data.length < 2) return null;
3958
+ const pad = 2;
3959
+ const min = Math.min(...data);
3960
+ const max = Math.max(...data);
3961
+ const range = max - min || 1;
3962
+ const points = data.map((v, i) => {
3963
+ const x = pad + i / (data.length - 1) * (width - pad * 2);
3964
+ const y = pad + (1 - (v - min) / range) * (height - pad * 2);
3965
+ return `${x},${y}`;
3966
+ }).join(" ");
3967
+ const resolvedColor = color === "auto" ? data[data.length - 1] >= data[0] ? COLOR_VAR.success : COLOR_VAR.error : COLOR_VAR[color];
3968
+ const areaPath = fill ? `M ${pad},${height - pad} L ${points.split(" ").join(" L ")} L ${width - pad},${height - pad} Z` : null;
3969
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3970
+ "svg",
3971
+ {
3972
+ width,
3973
+ height,
3974
+ viewBox: `0 0 ${width} ${height}`,
3975
+ className: cn("flex-shrink-0", className),
3976
+ "aria-hidden": "true",
3977
+ children: [
3978
+ areaPath && /* @__PURE__ */ jsxRuntime.jsx("path", { d: areaPath, fill: resolvedColor, opacity: 0.15 }),
3979
+ /* @__PURE__ */ jsxRuntime.jsx(
3980
+ "polyline",
3981
+ {
3982
+ fill: "none",
3983
+ stroke: resolvedColor,
3984
+ strokeWidth,
3985
+ strokeLinecap: "round",
3986
+ strokeLinejoin: "round",
3987
+ points
3988
+ }
3989
+ )
3990
+ ]
3991
+ }
3992
+ );
3993
+ };
3994
+ Sparkline.displayName = "Sparkline";
3995
+ }
3996
+ });
3936
3997
  var Switch;
3937
3998
  var init_Switch = __esm({
3938
3999
  "components/atoms/Switch.tsx"() {
@@ -9210,7 +9271,7 @@ var init_MapView = __esm({
9210
9271
  shadowSize: [41, 41]
9211
9272
  });
9212
9273
  L.Marker.prototype.options.icon = defaultIcon;
9213
- const { useEffect: useEffect68, useRef: useRef65, useCallback: useCallback110, useState: useState98 } = React80__namespace.default;
9274
+ const { useEffect: useEffect68, useRef: useRef65, useCallback: useCallback112, useState: useState99 } = React80__namespace.default;
9214
9275
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
9215
9276
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
9216
9277
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -9255,8 +9316,8 @@ var init_MapView = __esm({
9255
9316
  showAttribution = true
9256
9317
  }) {
9257
9318
  const eventBus = useEventBus2();
9258
- const [clickedPosition, setClickedPosition] = useState98(null);
9259
- const handleMapClick = useCallback110((lat, lng) => {
9319
+ const [clickedPosition, setClickedPosition] = useState99(null);
9320
+ const handleMapClick = useCallback112((lat, lng) => {
9260
9321
  if (showClickedPin) {
9261
9322
  setClickedPosition({ lat, lng });
9262
9323
  }
@@ -9265,7 +9326,7 @@ var init_MapView = __esm({
9265
9326
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
9266
9327
  }
9267
9328
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
9268
- const handleMarkerClick = useCallback110((marker) => {
9329
+ const handleMarkerClick = useCallback112((marker) => {
9269
9330
  onMarkerClick?.(marker);
9270
9331
  if (markerClickEvent) {
9271
9332
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -19060,7 +19121,7 @@ var init_CastleTemplate = __esm({
19060
19121
  CastleTemplate.displayName = "CastleTemplate";
19061
19122
  }
19062
19123
  });
19063
- var CHART_COLORS, BarChart, PieChart, LineChart, Chart;
19124
+ var CHART_COLORS, seriesColor, monthFormatter, formatTimeLabel, BarChart, PieChart, LineChart, ScatterChart, Chart;
19064
19125
  var init_Chart = __esm({
19065
19126
  "components/organisms/Chart.tsx"() {
19066
19127
  "use client";
@@ -19080,38 +19141,159 @@ var init_Chart = __esm({
19080
19141
  "var(--color-info)",
19081
19142
  "var(--color-accent)"
19082
19143
  ];
19083
- BarChart = ({ data, height, showValues }) => {
19084
- const maxValue = Math.max(...data.map((d) => d.value), 1);
19085
- return /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", align: "end", className: "w-full", style: { height }, children: data.map((point, idx) => {
19086
- const barHeight = point.value / maxValue * 100;
19087
- const color = point.color || CHART_COLORS[idx % CHART_COLORS.length];
19088
- return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "center", flex: true, className: "min-w-0", children: [
19089
- showValues && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: point.value }),
19090
- /* @__PURE__ */ jsxRuntime.jsx(
19091
- Box,
19092
- {
19093
- className: cn(
19094
- "w-full rounded-t-sm transition-all duration-500 ease-out min-h-[4px]"
19095
- ),
19096
- style: {
19097
- height: `${barHeight}%`,
19098
- backgroundColor: color
19099
- }
19144
+ seriesColor = (series, idx) => series.color ?? CHART_COLORS[idx % CHART_COLORS.length];
19145
+ monthFormatter = new Intl.DateTimeFormat(void 0, {
19146
+ month: "short",
19147
+ year: "2-digit"
19148
+ });
19149
+ formatTimeLabel = (raw) => {
19150
+ const parsed = new Date(raw);
19151
+ if (Number.isNaN(parsed.getTime())) return raw;
19152
+ return monthFormatter.format(parsed);
19153
+ };
19154
+ BarChart = ({ series, height, showValues, stack, timeAxis, histogram = false, onPointClick }) => {
19155
+ const categories = React80.useMemo(() => {
19156
+ const set = [];
19157
+ const seen = /* @__PURE__ */ new Set();
19158
+ for (const s of series) {
19159
+ for (const p2 of s.data) {
19160
+ if (!seen.has(p2.label)) {
19161
+ seen.add(p2.label);
19162
+ set.push(p2.label);
19100
19163
  }
19101
- ),
19102
- /* @__PURE__ */ jsxRuntime.jsx(
19103
- Typography,
19104
- {
19105
- variant: "caption",
19106
- color: "secondary",
19107
- className: "truncate w-full text-center",
19108
- children: point.label
19164
+ }
19165
+ }
19166
+ return set;
19167
+ }, [series]);
19168
+ const valueAt = React80.useCallback(
19169
+ (s, label) => {
19170
+ const p2 = s.data.find((d) => d.label === label);
19171
+ return p2 ? p2.value : 0;
19172
+ },
19173
+ []
19174
+ );
19175
+ const columnTotals = React80.useMemo(() => {
19176
+ if (stack === "none") return null;
19177
+ return categories.map(
19178
+ (label) => series.reduce((sum, s) => sum + valueAt(s, label), 0)
19179
+ );
19180
+ }, [categories, series, stack, valueAt]);
19181
+ const maxValue = React80.useMemo(() => {
19182
+ if (stack === "normalize") return 100;
19183
+ if (stack === "stack" && columnTotals) {
19184
+ return Math.max(...columnTotals, 1);
19185
+ }
19186
+ let m = 1;
19187
+ for (const s of series) {
19188
+ for (const p2 of s.data) if (p2.value > m) m = p2.value;
19189
+ }
19190
+ return m;
19191
+ }, [series, stack, columnTotals]);
19192
+ return /* @__PURE__ */ jsxRuntime.jsx(
19193
+ HStack,
19194
+ {
19195
+ gap: histogram ? "none" : "xs",
19196
+ align: "end",
19197
+ className: "w-full",
19198
+ style: { height },
19199
+ children: categories.map((label, catIdx) => {
19200
+ const displayLabel = timeAxis ? formatTimeLabel(label) : label;
19201
+ if (stack === "none") {
19202
+ return /* @__PURE__ */ jsxRuntime.jsxs(
19203
+ VStack,
19204
+ {
19205
+ gap: "xs",
19206
+ align: "center",
19207
+ flex: true,
19208
+ className: "min-w-0",
19209
+ children: [
19210
+ /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: histogram ? "none" : "xs", align: "end", className: "w-full", style: { height: "100%" }, children: series.map((s, sIdx) => {
19211
+ const value = valueAt(s, label);
19212
+ const barHeight = value / maxValue * 100;
19213
+ const color = seriesColor(s, sIdx);
19214
+ return /* @__PURE__ */ jsxRuntime.jsx(
19215
+ Box,
19216
+ {
19217
+ className: cn(
19218
+ "rounded-t-sm transition-all duration-500 ease-out min-h-[4px] cursor-pointer hover:opacity-80",
19219
+ histogram ? "flex-1 mx-0" : "flex-1"
19220
+ ),
19221
+ style: {
19222
+ height: `${barHeight}%`,
19223
+ backgroundColor: color
19224
+ },
19225
+ onClick: () => onPointClick?.(
19226
+ { label, value, color },
19227
+ s.name
19228
+ ),
19229
+ title: `${s.name}: ${value}`
19230
+ },
19231
+ s.name
19232
+ );
19233
+ }) }),
19234
+ showValues && series.length === 1 && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: valueAt(series[0], label) }),
19235
+ /* @__PURE__ */ jsxRuntime.jsx(
19236
+ Typography,
19237
+ {
19238
+ variant: "caption",
19239
+ color: "secondary",
19240
+ className: "truncate w-full text-center",
19241
+ children: displayLabel
19242
+ }
19243
+ )
19244
+ ]
19245
+ },
19246
+ label
19247
+ );
19109
19248
  }
19110
- )
19111
- ] }, point.label);
19112
- }) });
19249
+ const total = columnTotals?.[catIdx] ?? 1;
19250
+ return /* @__PURE__ */ jsxRuntime.jsxs(
19251
+ VStack,
19252
+ {
19253
+ gap: "xs",
19254
+ align: "center",
19255
+ flex: true,
19256
+ className: "min-w-0",
19257
+ children: [
19258
+ /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "none", className: "w-full", style: { height: "100%" }, justify: "end", children: series.map((s, sIdx) => {
19259
+ const value = valueAt(s, label);
19260
+ const ratio = stack === "normalize" ? total === 0 ? 0 : value / total * 100 : value / maxValue * 100;
19261
+ const color = seriesColor(s, sIdx);
19262
+ return /* @__PURE__ */ jsxRuntime.jsx(
19263
+ Box,
19264
+ {
19265
+ className: "w-full transition-all duration-500 ease-out cursor-pointer hover:opacity-80",
19266
+ style: {
19267
+ height: `${ratio}%`,
19268
+ backgroundColor: color
19269
+ },
19270
+ onClick: () => onPointClick?.(
19271
+ { label, value, color },
19272
+ s.name
19273
+ ),
19274
+ title: `${s.name}: ${value}`
19275
+ },
19276
+ s.name
19277
+ );
19278
+ }) }),
19279
+ /* @__PURE__ */ jsxRuntime.jsx(
19280
+ Typography,
19281
+ {
19282
+ variant: "caption",
19283
+ color: "secondary",
19284
+ className: "truncate w-full text-center",
19285
+ children: displayLabel
19286
+ }
19287
+ )
19288
+ ]
19289
+ },
19290
+ label
19291
+ );
19292
+ })
19293
+ }
19294
+ );
19113
19295
  };
19114
- PieChart = ({ data, height, showValues, donut = false }) => {
19296
+ PieChart = ({ data, height, showValues, donut = false, onPointClick }) => {
19115
19297
  const total = data.reduce((sum, d) => sum + d.value, 0);
19116
19298
  const size = Math.min(height, 200);
19117
19299
  const radius = size / 2 - 8;
@@ -19157,7 +19339,11 @@ var init_Chart = __esm({
19157
19339
  fill: seg.color,
19158
19340
  stroke: "var(--color-card)",
19159
19341
  strokeWidth: "2",
19160
- className: "transition-opacity duration-200 hover:opacity-80"
19342
+ className: "transition-opacity duration-200 hover:opacity-80 cursor-pointer",
19343
+ onClick: () => onPointClick?.(
19344
+ { label: seg.label, value: seg.value, color: seg.color },
19345
+ "default"
19346
+ )
19161
19347
  },
19162
19348
  idx
19163
19349
  )),
@@ -19192,56 +19378,243 @@ var init_Chart = __esm({
19192
19378
  ] }, idx)) })
19193
19379
  ] });
19194
19380
  };
19195
- LineChart = ({ data, height, showValues, fill = false }) => {
19196
- const maxValue = Math.max(...data.map((d) => d.value), 1);
19381
+ LineChart = ({ series, height, showValues, fill = false, timeAxis, onPointClick }) => {
19197
19382
  const width = 400;
19198
19383
  const padding = { top: 20, right: 20, bottom: 30, left: 40 };
19199
19384
  const chartWidth = width - padding.left - padding.right;
19200
19385
  const chartHeight = height - padding.top - padding.bottom;
19201
- const points = React80.useMemo(() => {
19202
- return data.map((point, idx) => ({
19203
- x: padding.left + idx / Math.max(data.length - 1, 1) * chartWidth,
19204
- y: padding.top + chartHeight - point.value / maxValue * chartHeight,
19205
- ...point
19206
- }));
19207
- }, [data, maxValue, chartWidth, chartHeight, padding]);
19208
- const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
19209
- const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
19210
- return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "100%", height, viewBox: `0 0 ${width} ${height}`, preserveAspectRatio: "xMidYMid meet", children: [
19211
- [0, 0.25, 0.5, 0.75, 1].map((frac) => {
19212
- const y = padding.top + chartHeight * (1 - frac);
19213
- return /* @__PURE__ */ jsxRuntime.jsx(
19214
- "line",
19215
- {
19216
- x1: padding.left,
19217
- y1: y,
19218
- x2: width - padding.right,
19219
- y2: y,
19220
- stroke: "var(--color-border)",
19221
- strokeDasharray: "4 4",
19222
- opacity: 0.5
19223
- },
19224
- frac
19225
- );
19226
- }),
19227
- fill && /* @__PURE__ */ jsxRuntime.jsx("path", { d: areaPath, fill: "var(--color-primary)", opacity: 0.1 }),
19228
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: linePath, fill: "none", stroke: "var(--color-primary)", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
19229
- points.map((p2, idx) => /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
19230
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: p2.x, cy: p2.y, r: "4", fill: "var(--color-card)", stroke: "var(--color-primary)", strokeWidth: "2" }),
19231
- showValues && /* @__PURE__ */ jsxRuntime.jsx("text", { x: p2.x, y: p2.y - 10, textAnchor: "middle", fill: "var(--color-foreground)", fontSize: "10", fontWeight: "500", children: p2.value }),
19232
- /* @__PURE__ */ jsxRuntime.jsx(
19233
- "text",
19234
- {
19235
- x: p2.x,
19236
- y: height - 8,
19237
- textAnchor: "middle",
19238
- fill: "var(--color-muted-foreground)",
19239
- fontSize: "9",
19240
- children: p2.label
19386
+ const labels = React80.useMemo(() => {
19387
+ const seen = /* @__PURE__ */ new Set();
19388
+ const out = [];
19389
+ for (const s of series) {
19390
+ for (const p2 of s.data) {
19391
+ if (!seen.has(p2.label)) {
19392
+ seen.add(p2.label);
19393
+ out.push(p2.label);
19241
19394
  }
19242
- )
19243
- ] }, idx))
19244
- ] });
19395
+ }
19396
+ }
19397
+ return out;
19398
+ }, [series]);
19399
+ const maxValue = React80.useMemo(() => {
19400
+ let m = 1;
19401
+ for (const s of series) {
19402
+ for (const p2 of s.data) if (p2.value > m) m = p2.value;
19403
+ }
19404
+ return m;
19405
+ }, [series]);
19406
+ const xFor = React80.useCallback(
19407
+ (idx) => padding.left + idx / Math.max(labels.length - 1, 1) * chartWidth,
19408
+ [labels.length, chartWidth, padding.left]
19409
+ );
19410
+ const yFor = React80.useCallback(
19411
+ (value) => padding.top + chartHeight - value / maxValue * chartHeight,
19412
+ [maxValue, chartHeight, padding.top]
19413
+ );
19414
+ return /* @__PURE__ */ jsxRuntime.jsxs(
19415
+ "svg",
19416
+ {
19417
+ width: "100%",
19418
+ height,
19419
+ viewBox: `0 0 ${width} ${height}`,
19420
+ preserveAspectRatio: "xMidYMid meet",
19421
+ children: [
19422
+ [0, 0.25, 0.5, 0.75, 1].map((frac) => {
19423
+ const y = padding.top + chartHeight * (1 - frac);
19424
+ return /* @__PURE__ */ jsxRuntime.jsx(
19425
+ "line",
19426
+ {
19427
+ x1: padding.left,
19428
+ y1: y,
19429
+ x2: width - padding.right,
19430
+ y2: y,
19431
+ stroke: "var(--color-border)",
19432
+ strokeDasharray: "4 4",
19433
+ opacity: 0.5
19434
+ },
19435
+ frac
19436
+ );
19437
+ }),
19438
+ series.map((s, sIdx) => {
19439
+ const color = seriesColor(s, sIdx);
19440
+ const points = labels.map((label, idx) => {
19441
+ const point = s.data.find((d) => d.label === label);
19442
+ return {
19443
+ x: xFor(idx),
19444
+ y: yFor(point ? point.value : 0),
19445
+ value: point ? point.value : 0,
19446
+ label
19447
+ };
19448
+ });
19449
+ const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
19450
+ const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
19451
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
19452
+ fill && /* @__PURE__ */ jsxRuntime.jsx(
19453
+ "path",
19454
+ {
19455
+ d: areaPath,
19456
+ fill: color,
19457
+ opacity: series.length > 1 ? 0.08 : 0.1
19458
+ }
19459
+ ),
19460
+ /* @__PURE__ */ jsxRuntime.jsx(
19461
+ "path",
19462
+ {
19463
+ d: linePath,
19464
+ fill: "none",
19465
+ stroke: color,
19466
+ strokeWidth: "2",
19467
+ strokeLinecap: "round",
19468
+ strokeLinejoin: "round",
19469
+ strokeDasharray: s.dashed ? "6 4" : void 0
19470
+ }
19471
+ ),
19472
+ points.map((p2, idx) => /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
19473
+ /* @__PURE__ */ jsxRuntime.jsx(
19474
+ "circle",
19475
+ {
19476
+ cx: p2.x,
19477
+ cy: p2.y,
19478
+ r: "4",
19479
+ fill: "var(--color-card)",
19480
+ stroke: color,
19481
+ strokeWidth: "2",
19482
+ className: "cursor-pointer",
19483
+ onClick: () => onPointClick?.(
19484
+ { label: p2.label, value: p2.value, color },
19485
+ s.name
19486
+ )
19487
+ }
19488
+ ),
19489
+ showValues && series.length === 1 && /* @__PURE__ */ jsxRuntime.jsx(
19490
+ "text",
19491
+ {
19492
+ x: p2.x,
19493
+ y: p2.y - 10,
19494
+ textAnchor: "middle",
19495
+ fill: "var(--color-foreground)",
19496
+ fontSize: "10",
19497
+ fontWeight: "500",
19498
+ children: p2.value
19499
+ }
19500
+ )
19501
+ ] }, idx))
19502
+ ] }, s.name);
19503
+ }),
19504
+ labels.map((label, idx) => /* @__PURE__ */ jsxRuntime.jsx(
19505
+ "text",
19506
+ {
19507
+ x: xFor(idx),
19508
+ y: height - 8,
19509
+ textAnchor: "middle",
19510
+ fill: "var(--color-muted-foreground)",
19511
+ fontSize: "9",
19512
+ children: timeAxis ? formatTimeLabel(label) : label
19513
+ },
19514
+ label
19515
+ ))
19516
+ ]
19517
+ }
19518
+ );
19519
+ };
19520
+ ScatterChart = ({ data, height, onPointClick }) => {
19521
+ const width = 400;
19522
+ const padding = { top: 20, right: 20, bottom: 30, left: 40 };
19523
+ const chartWidth = width - padding.left - padding.right;
19524
+ const chartHeight = height - padding.top - padding.bottom;
19525
+ const { minX, maxX, minY, maxY } = React80.useMemo(() => {
19526
+ if (data.length === 0) {
19527
+ return { minX: 0, maxX: 1, minY: 0, maxY: 1 };
19528
+ }
19529
+ let mnX = data[0].x;
19530
+ let mxX = data[0].x;
19531
+ let mnY = data[0].y;
19532
+ let mxY = data[0].y;
19533
+ for (const p2 of data) {
19534
+ if (p2.x < mnX) mnX = p2.x;
19535
+ if (p2.x > mxX) mxX = p2.x;
19536
+ if (p2.y < mnY) mnY = p2.y;
19537
+ if (p2.y > mxY) mxY = p2.y;
19538
+ }
19539
+ return { minX: mnX, maxX: mxX, minY: mnY, maxY: mxY };
19540
+ }, [data]);
19541
+ const rangeX = maxX - minX || 1;
19542
+ const rangeY = maxY - minY || 1;
19543
+ return /* @__PURE__ */ jsxRuntime.jsxs(
19544
+ "svg",
19545
+ {
19546
+ width: "100%",
19547
+ height,
19548
+ viewBox: `0 0 ${width} ${height}`,
19549
+ preserveAspectRatio: "xMidYMid meet",
19550
+ children: [
19551
+ [0, 0.25, 0.5, 0.75, 1].map((frac) => {
19552
+ const y = padding.top + chartHeight * (1 - frac);
19553
+ return /* @__PURE__ */ jsxRuntime.jsx(
19554
+ "line",
19555
+ {
19556
+ x1: padding.left,
19557
+ y1: y,
19558
+ x2: width - padding.right,
19559
+ y2: y,
19560
+ stroke: "var(--color-border)",
19561
+ strokeDasharray: "4 4",
19562
+ opacity: 0.5
19563
+ },
19564
+ frac
19565
+ );
19566
+ }),
19567
+ data.map((p2, idx) => {
19568
+ const cx = padding.left + (p2.x - minX) / rangeX * chartWidth;
19569
+ const cy = padding.top + chartHeight - (p2.y - minY) / rangeY * chartHeight;
19570
+ const r = p2.size ?? 5;
19571
+ const color = p2.color ?? CHART_COLORS[idx % CHART_COLORS.length];
19572
+ return /* @__PURE__ */ jsxRuntime.jsx(
19573
+ "circle",
19574
+ {
19575
+ cx,
19576
+ cy,
19577
+ r,
19578
+ fill: color,
19579
+ opacity: 0.7,
19580
+ className: "cursor-pointer hover:opacity-100",
19581
+ onClick: () => onPointClick?.(
19582
+ {
19583
+ label: p2.label ?? `(${p2.x}, ${p2.y})`,
19584
+ value: p2.y,
19585
+ color
19586
+ },
19587
+ "default"
19588
+ ),
19589
+ children: /* @__PURE__ */ jsxRuntime.jsx("title", { children: p2.label ?? `(${p2.x}, ${p2.y})` })
19590
+ },
19591
+ idx
19592
+ );
19593
+ }),
19594
+ /* @__PURE__ */ jsxRuntime.jsx(
19595
+ "text",
19596
+ {
19597
+ x: padding.left,
19598
+ y: height - 8,
19599
+ fill: "var(--color-muted-foreground)",
19600
+ fontSize: "9",
19601
+ children: minX.toFixed(1)
19602
+ }
19603
+ ),
19604
+ /* @__PURE__ */ jsxRuntime.jsx(
19605
+ "text",
19606
+ {
19607
+ x: width - padding.right,
19608
+ y: height - 8,
19609
+ textAnchor: "end",
19610
+ fill: "var(--color-muted-foreground)",
19611
+ fontSize: "9",
19612
+ children: maxX.toFixed(1)
19613
+ }
19614
+ )
19615
+ ]
19616
+ }
19617
+ );
19245
19618
  };
19246
19619
  Chart = ({
19247
19620
  title,
@@ -19249,9 +19622,13 @@ var init_Chart = __esm({
19249
19622
  chartType = "bar",
19250
19623
  series,
19251
19624
  data: simpleData,
19625
+ scatterData,
19252
19626
  height = 200,
19253
19627
  showLegend = true,
19254
19628
  showValues = false,
19629
+ stack = "none",
19630
+ timeAxis = false,
19631
+ drillEvent,
19255
19632
  actions,
19256
19633
  entity,
19257
19634
  isLoading = false,
@@ -19268,11 +19645,25 @@ var init_Chart = __esm({
19268
19645
  },
19269
19646
  [eventBus]
19270
19647
  );
19271
- const normalizedData = React80.useMemo(() => {
19272
- if (simpleData) return simpleData;
19273
- if (series && series.length > 0) return series[0].data;
19648
+ const handlePointClick = React80.useCallback(
19649
+ (point, seriesName) => {
19650
+ if (drillEvent) {
19651
+ eventBus.emit(`UI:${drillEvent}`, {
19652
+ label: point.label,
19653
+ value: point.value,
19654
+ seriesLabel: seriesName === "default" ? void 0 : seriesName
19655
+ });
19656
+ }
19657
+ },
19658
+ [drillEvent, eventBus]
19659
+ );
19660
+ const normalizedSeries = React80.useMemo(() => {
19661
+ if (series && series.length > 0) return series;
19662
+ if (simpleData) return [{ name: "default", data: simpleData }];
19274
19663
  return [];
19275
19664
  }, [simpleData, series]);
19665
+ const firstSeriesData = normalizedSeries[0]?.data ?? [];
19666
+ const hasContent = chartType === "scatter" ? (scatterData?.length ?? 0) > 0 : normalizedSeries.some((s) => s.data.length > 0);
19276
19667
  if (isLoading) {
19277
19668
  return /* @__PURE__ */ jsxRuntime.jsx(LoadingState, { message: "Loading chart...", className });
19278
19669
  }
@@ -19286,7 +19677,7 @@ var init_Chart = __esm({
19286
19677
  }
19287
19678
  );
19288
19679
  }
19289
- if (normalizedData.length === 0) {
19680
+ if (!hasContent) {
19290
19681
  return /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { title: t("empty.noData"), description: t("empty.noData"), className });
19291
19682
  }
19292
19683
  return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn("p-6", className), children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "md", children: [
@@ -19307,18 +19698,84 @@ var init_Chart = __esm({
19307
19698
  )) })
19308
19699
  ] }),
19309
19700
  /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "w-full", children: [
19310
- chartType === "bar" && /* @__PURE__ */ jsxRuntime.jsx(BarChart, { data: normalizedData, height, showValues }),
19311
- chartType === "line" && /* @__PURE__ */ jsxRuntime.jsx(LineChart, { data: normalizedData, height, showValues }),
19312
- chartType === "area" && /* @__PURE__ */ jsxRuntime.jsx(LineChart, { data: normalizedData, height, showValues, fill: true }),
19313
- chartType === "pie" && /* @__PURE__ */ jsxRuntime.jsx(PieChart, { data: normalizedData, height, showValues: showLegend }),
19314
- chartType === "donut" && /* @__PURE__ */ jsxRuntime.jsx(PieChart, { data: normalizedData, height, showValues: showLegend, donut: true })
19701
+ chartType === "bar" && /* @__PURE__ */ jsxRuntime.jsx(
19702
+ BarChart,
19703
+ {
19704
+ series: normalizedSeries,
19705
+ height,
19706
+ showValues,
19707
+ stack,
19708
+ timeAxis,
19709
+ onPointClick: handlePointClick
19710
+ }
19711
+ ),
19712
+ chartType === "histogram" && /* @__PURE__ */ jsxRuntime.jsx(
19713
+ BarChart,
19714
+ {
19715
+ series: normalizedSeries,
19716
+ height,
19717
+ showValues,
19718
+ stack: "none",
19719
+ timeAxis: false,
19720
+ histogram: true,
19721
+ onPointClick: handlePointClick
19722
+ }
19723
+ ),
19724
+ chartType === "line" && /* @__PURE__ */ jsxRuntime.jsx(
19725
+ LineChart,
19726
+ {
19727
+ series: normalizedSeries,
19728
+ height,
19729
+ showValues,
19730
+ timeAxis,
19731
+ onPointClick: handlePointClick
19732
+ }
19733
+ ),
19734
+ chartType === "area" && /* @__PURE__ */ jsxRuntime.jsx(
19735
+ LineChart,
19736
+ {
19737
+ series: normalizedSeries,
19738
+ height,
19739
+ showValues,
19740
+ timeAxis,
19741
+ fill: true,
19742
+ onPointClick: handlePointClick
19743
+ }
19744
+ ),
19745
+ chartType === "pie" && /* @__PURE__ */ jsxRuntime.jsx(
19746
+ PieChart,
19747
+ {
19748
+ data: firstSeriesData,
19749
+ height,
19750
+ showValues: showLegend,
19751
+ onPointClick: handlePointClick
19752
+ }
19753
+ ),
19754
+ chartType === "donut" && /* @__PURE__ */ jsxRuntime.jsx(
19755
+ PieChart,
19756
+ {
19757
+ data: firstSeriesData,
19758
+ height,
19759
+ showValues: showLegend,
19760
+ donut: true,
19761
+ onPointClick: handlePointClick
19762
+ }
19763
+ ),
19764
+ chartType === "scatter" && /* @__PURE__ */ jsxRuntime.jsx(
19765
+ ScatterChart,
19766
+ {
19767
+ data: scatterData ?? [],
19768
+ height,
19769
+ onPointClick: handlePointClick
19770
+ }
19771
+ )
19315
19772
  ] }),
19316
- showLegend && series && series.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "md", justify: "center", wrap: true, children: series.map((s, idx) => /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
19773
+ showLegend && normalizedSeries.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "md", justify: "center", wrap: true, children: normalizedSeries.map((s, idx) => /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
19317
19774
  /* @__PURE__ */ jsxRuntime.jsx(
19318
19775
  Box,
19319
19776
  {
19320
19777
  className: "w-3 h-3 rounded-full flex-shrink-0",
19321
- style: { backgroundColor: s.color || CHART_COLORS[idx % CHART_COLORS.length] }
19778
+ style: { backgroundColor: seriesColor(s, idx) }
19322
19779
  }
19323
19780
  ),
19324
19781
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: s.name })
@@ -24156,6 +24613,151 @@ var init_FlipCard = __esm({
24156
24613
  FlipCard.displayName = "FlipCard";
24157
24614
  }
24158
24615
  });
24616
+ function toISODate(d) {
24617
+ return d.toISOString().slice(0, 10);
24618
+ }
24619
+ function startOfMonth(d) {
24620
+ return new Date(d.getFullYear(), d.getMonth(), 1);
24621
+ }
24622
+ function startOfQuarter(d) {
24623
+ return new Date(d.getFullYear(), Math.floor(d.getMonth() / 3) * 3, 1);
24624
+ }
24625
+ function startOfYear(d) {
24626
+ return new Date(d.getFullYear(), 0, 1);
24627
+ }
24628
+ function daysAgo(n) {
24629
+ const d = /* @__PURE__ */ new Date();
24630
+ d.setDate(d.getDate() - n);
24631
+ return d;
24632
+ }
24633
+ var DEFAULT_PRESETS, DateRangePicker;
24634
+ var init_DateRangePicker = __esm({
24635
+ "components/molecules/DateRangePicker.tsx"() {
24636
+ "use client";
24637
+ init_cn();
24638
+ init_Button();
24639
+ init_Input();
24640
+ init_Stack();
24641
+ init_Typography();
24642
+ init_useEventBus();
24643
+ DEFAULT_PRESETS = [
24644
+ {
24645
+ label: "Last 7 days",
24646
+ value: "7d",
24647
+ range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
24648
+ },
24649
+ {
24650
+ label: "Last 30 days",
24651
+ value: "30d",
24652
+ range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
24653
+ },
24654
+ {
24655
+ label: "This Month",
24656
+ value: "month",
24657
+ range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
24658
+ },
24659
+ {
24660
+ label: "This Quarter",
24661
+ value: "quarter",
24662
+ range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
24663
+ },
24664
+ {
24665
+ label: "YTD",
24666
+ value: "ytd",
24667
+ range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
24668
+ }
24669
+ ];
24670
+ DateRangePicker = ({
24671
+ from: fromProp,
24672
+ to: toProp,
24673
+ event,
24674
+ onChange,
24675
+ presets = DEFAULT_PRESETS,
24676
+ fromLabel = "From",
24677
+ toLabel = "To",
24678
+ className
24679
+ }) => {
24680
+ const eventBus = useEventBus();
24681
+ const [from, setFrom] = React80.useState(fromProp ?? "");
24682
+ const [to, setTo] = React80.useState(toProp ?? "");
24683
+ const [activePreset, setActivePreset] = React80.useState(null);
24684
+ const emit = React80.useCallback(
24685
+ (range) => {
24686
+ onChange?.(range);
24687
+ if (event) eventBus.emit(`UI:${event}`, range);
24688
+ },
24689
+ [onChange, event, eventBus]
24690
+ );
24691
+ const handleFromChange = React80.useCallback(
24692
+ (next) => {
24693
+ setFrom(next);
24694
+ setActivePreset(null);
24695
+ emit({ from: next, to });
24696
+ },
24697
+ [to, emit]
24698
+ );
24699
+ const handleToChange = React80.useCallback(
24700
+ (next) => {
24701
+ setTo(next);
24702
+ setActivePreset(null);
24703
+ emit({ from, to: next });
24704
+ },
24705
+ [from, emit]
24706
+ );
24707
+ const handlePreset = React80.useCallback(
24708
+ (preset) => {
24709
+ const range = preset.range();
24710
+ setFrom(range.from);
24711
+ setTo(range.to);
24712
+ setActivePreset(preset.value);
24713
+ emit(range);
24714
+ },
24715
+ [emit]
24716
+ );
24717
+ const presetButtons = React80.useMemo(
24718
+ () => presets.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
24719
+ Button,
24720
+ {
24721
+ variant: activePreset === preset.value ? "primary" : "ghost",
24722
+ size: "sm",
24723
+ onClick: () => handlePreset(preset),
24724
+ children: preset.label
24725
+ },
24726
+ preset.value
24727
+ )),
24728
+ [presets, activePreset, handlePreset]
24729
+ );
24730
+ return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", className: cn(className), children: [
24731
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "md", align: "end", children: [
24732
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
24733
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: fromLabel }),
24734
+ /* @__PURE__ */ jsxRuntime.jsx(
24735
+ Input,
24736
+ {
24737
+ type: "date",
24738
+ value: from,
24739
+ onChange: (e) => handleFromChange(e.target.value)
24740
+ }
24741
+ )
24742
+ ] }),
24743
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
24744
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: toLabel }),
24745
+ /* @__PURE__ */ jsxRuntime.jsx(
24746
+ Input,
24747
+ {
24748
+ type: "date",
24749
+ value: to,
24750
+ onChange: (e) => handleToChange(e.target.value)
24751
+ }
24752
+ )
24753
+ ] })
24754
+ ] }),
24755
+ presets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
24756
+ ] });
24757
+ };
24758
+ DateRangePicker.displayName = "DateRangePicker";
24759
+ }
24760
+ });
24159
24761
  var DEFAULT_OPTIONS, DateRangeSelector;
24160
24762
  var init_DateRangeSelector = __esm({
24161
24763
  "components/molecules/DateRangeSelector.tsx"() {
@@ -27127,7 +27729,9 @@ var init_StatDisplay = __esm({
27127
27729
  init_Typography();
27128
27730
  init_Box();
27129
27731
  init_Stack();
27732
+ init_Sparkline();
27130
27733
  init_Icon();
27734
+ init_useEventBus();
27131
27735
  variantColor = {
27132
27736
  default: "text-foreground",
27133
27737
  primary: "text-primary",
@@ -27142,6 +27746,10 @@ var init_StatDisplay = __esm({
27142
27746
  max,
27143
27747
  target,
27144
27748
  trend,
27749
+ trendPolarity = "higher-is-better",
27750
+ trendFormat = "absolute",
27751
+ sparklineData,
27752
+ clickEvent,
27145
27753
  prefix,
27146
27754
  suffix,
27147
27755
  icon: iconProp,
@@ -27155,6 +27763,10 @@ var init_StatDisplay = __esm({
27155
27763
  isLoading = false,
27156
27764
  error = null
27157
27765
  }) => {
27766
+ const eventBus = useEventBus();
27767
+ const handleClick = React80.useCallback(() => {
27768
+ if (clickEvent) eventBus.emit(`UI:${clickEvent}`, { metricLabel: label });
27769
+ }, [clickEvent, eventBus, label]);
27158
27770
  const ResolvedIcon = typeof iconProp === "string" ? resolveIcon(iconProp) : null;
27159
27771
  const iconSizes3 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
27160
27772
  const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
@@ -27165,7 +27777,10 @@ var init_StatDisplay = __esm({
27165
27777
  const targetPct = showTarget ? Math.max(0, Math.min(100, numericValue / target * 100)) : 0;
27166
27778
  const showTrend = typeof trend === "number" && trend !== 0 && Number.isFinite(trend);
27167
27779
  const trendUp = showTrend && trend > 0;
27168
- const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${Math.abs(trend)}` : "";
27780
+ const trendIsGood = trendPolarity === "lower-is-better" ? !trendUp : trendUp;
27781
+ const trendMagnitude = Math.abs(trend);
27782
+ const trendSuffix = trendFormat === "percent" ? "%" : "";
27783
+ const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${trendMagnitude}${trendSuffix}` : "";
27169
27784
  if (error) {
27170
27785
  return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "error", children: error.message }) });
27171
27786
  }
@@ -27176,38 +27791,57 @@ var init_StatDisplay = __esm({
27176
27791
  ] }) });
27177
27792
  }
27178
27793
  if (compact) {
27179
- return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: cn("items-center", className), children: [
27180
- ResolvedIcon && /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
27181
- typeof iconProp !== "string" && iconProp,
27182
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: label }),
27183
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
27184
- showTrend && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: cn("font-semibold", trendUp ? "text-success" : "text-error"), children: trendLabel })
27185
- ] });
27794
+ return /* @__PURE__ */ jsxRuntime.jsxs(
27795
+ HStack,
27796
+ {
27797
+ gap: "sm",
27798
+ className: cn("items-center", clickEvent && "cursor-pointer hover:opacity-80", className),
27799
+ onClick: clickEvent ? handleClick : void 0,
27800
+ children: [
27801
+ ResolvedIcon && /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
27802
+ typeof iconProp !== "string" && iconProp,
27803
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: label }),
27804
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
27805
+ showTrend && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: cn("font-semibold", trendIsGood ? "text-success" : "text-error"), children: trendLabel }),
27806
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto", width: 60, height: 20 })
27807
+ ]
27808
+ }
27809
+ );
27186
27810
  }
27187
- return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "start", justify: "between", children: [
27188
- /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
27189
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "overline", color: "secondary", children: label }),
27190
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "end", children: [
27191
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
27192
- showTrend && /* @__PURE__ */ jsxRuntime.jsx(
27193
- Typography,
27194
- {
27195
- variant: "caption",
27196
- className: cn("font-semibold pb-1", trendUp ? "text-success" : "text-error"),
27197
- children: trendLabel
27198
- }
27199
- )
27200
- ] }),
27201
- showTarget && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
27202
- Box,
27203
- {
27204
- className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
27205
- style: { width: `${targetPct}%` }
27206
- }
27207
- ) })
27208
- ] }),
27209
- (ResolvedIcon || typeof iconProp !== "string" && iconProp) && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("p-3 rounded-md", iconBg), children: ResolvedIcon ? /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }) : iconProp })
27210
- ] }) });
27811
+ return /* @__PURE__ */ jsxRuntime.jsx(
27812
+ Card,
27813
+ {
27814
+ className: cn(padSizes[size], clickEvent && "cursor-pointer hover:shadow-md transition-shadow", className),
27815
+ onClick: clickEvent ? handleClick : void 0,
27816
+ children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "start", justify: "between", children: [
27817
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
27818
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "overline", color: "secondary", children: label }),
27819
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "end", children: [
27820
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
27821
+ showTrend && /* @__PURE__ */ jsxRuntime.jsx(
27822
+ Typography,
27823
+ {
27824
+ variant: "caption",
27825
+ className: cn("font-semibold pb-1", trendIsGood ? "text-success" : "text-error"),
27826
+ children: trendLabel
27827
+ }
27828
+ )
27829
+ ] }),
27830
+ showTarget && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
27831
+ Box,
27832
+ {
27833
+ className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
27834
+ style: { width: `${targetPct}%` }
27835
+ }
27836
+ ) })
27837
+ ] }),
27838
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "end", children: [
27839
+ (ResolvedIcon || typeof iconProp !== "string" && iconProp) && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("p-3 rounded-md", iconBg), children: ResolvedIcon ? /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }) : iconProp }),
27840
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto" })
27841
+ ] })
27842
+ ] })
27843
+ }
27844
+ );
27211
27845
  };
27212
27846
  StatDisplay.displayName = "StatDisplay";
27213
27847
  }
@@ -41551,6 +42185,7 @@ var init_StatCard = __esm({
41551
42185
  init_Box();
41552
42186
  init_Stack();
41553
42187
  init_Button();
42188
+ init_Sparkline();
41554
42189
  init_useEventBus();
41555
42190
  init_useTranslate();
41556
42191
  init_Icon();
@@ -41720,32 +42355,7 @@ var init_StatCard = __esm({
41720
42355
  ] }),
41721
42356
  /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "end", children: [
41722
42357
  Icon3 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("p-3", iconBg), children: /* @__PURE__ */ jsxRuntime.jsx(Icon3, { className: cn("h-6 w-6", iconColor) }) }),
41723
- sparklineData && sparklineData.length > 1 && (() => {
41724
- const w = 80;
41725
- const h = 32;
41726
- const pad = 2;
41727
- const min = Math.min(...sparklineData);
41728
- const max = Math.max(...sparklineData);
41729
- const range = max - min || 1;
41730
- const points = sparklineData.map((v, i) => {
41731
- const x = pad + i / (sparklineData.length - 1) * (w - pad * 2);
41732
- const y = pad + (1 - (v - min) / range) * (h - pad * 2);
41733
- return `${x},${y}`;
41734
- }).join(" ");
41735
- const trending = sparklineData[sparklineData.length - 1] >= sparklineData[0];
41736
- const strokeColor = trending ? "var(--color-success)" : "var(--color-error)";
41737
- return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: w, height: h, viewBox: `0 0 ${w} ${h}`, className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
41738
- "polyline",
41739
- {
41740
- fill: "none",
41741
- stroke: strokeColor,
41742
- strokeWidth: "2",
41743
- strokeLinecap: "round",
41744
- strokeLinejoin: "round",
41745
- points
41746
- }
41747
- ) });
41748
- })()
42358
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto" })
41749
42359
  ] })
41750
42360
  ] }),
41751
42361
  action && /* @__PURE__ */ jsxRuntime.jsxs(
@@ -43643,6 +44253,7 @@ var init_component_registry_generated = __esm({
43643
44253
  init_DataGrid();
43644
44254
  init_DataList();
43645
44255
  init_DataTable();
44256
+ init_DateRangePicker();
43646
44257
  init_DateRangeSelector();
43647
44258
  init_DayCell();
43648
44259
  init_DebuggerBoard();
@@ -43775,6 +44386,7 @@ var init_component_registry_generated = __esm({
43775
44386
  init_Skeleton();
43776
44387
  init_SocialProof();
43777
44388
  init_SortableList();
44389
+ init_Sparkline();
43778
44390
  init_Split();
43779
44391
  init_SplitPane();
43780
44392
  init_SplitSection();
@@ -43923,6 +44535,7 @@ var init_component_registry_generated = __esm({
43923
44535
  "DataGrid": DataGrid,
43924
44536
  "DataList": DataList,
43925
44537
  "DataTable": DataTable,
44538
+ "DateRangePicker": DateRangePicker,
43926
44539
  "DateRangeSelector": DateRangeSelector,
43927
44540
  "DayCell": DayCell,
43928
44541
  "DebuggerBoard": DebuggerBoard,
@@ -44084,6 +44697,7 @@ var init_component_registry_generated = __esm({
44084
44697
  "SortableList": SortableList,
44085
44698
  "Spacer": SpacerPattern,
44086
44699
  "SpacerPattern": SpacerPattern,
44700
+ "Sparkline": Sparkline,
44087
44701
  "Spinner": SpinnerPattern,
44088
44702
  "SpinnerPattern": SpinnerPattern,
44089
44703
  "Split": Split,