@almadar/ui 4.51.14 → 4.51.16

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.
@@ -3887,6 +3887,67 @@ var init_Radio = __esm({
3887
3887
  Radio.displayName = "Radio";
3888
3888
  }
3889
3889
  });
3890
+ var COLOR_VAR, Sparkline;
3891
+ var init_Sparkline = __esm({
3892
+ "components/atoms/Sparkline.tsx"() {
3893
+ init_cn();
3894
+ COLOR_VAR = {
3895
+ primary: "var(--color-primary)",
3896
+ success: "var(--color-success)",
3897
+ warning: "var(--color-warning)",
3898
+ error: "var(--color-error)",
3899
+ info: "var(--color-info)",
3900
+ muted: "var(--color-muted-foreground)"
3901
+ };
3902
+ Sparkline = ({
3903
+ data,
3904
+ color = "auto",
3905
+ width = 80,
3906
+ height = 32,
3907
+ strokeWidth = 2,
3908
+ fill = false,
3909
+ className
3910
+ }) => {
3911
+ if (data.length < 2) return null;
3912
+ const pad = 2;
3913
+ const min = Math.min(...data);
3914
+ const max = Math.max(...data);
3915
+ const range = max - min || 1;
3916
+ const points = data.map((v, i) => {
3917
+ const x = pad + i / (data.length - 1) * (width - pad * 2);
3918
+ const y = pad + (1 - (v - min) / range) * (height - pad * 2);
3919
+ return `${x},${y}`;
3920
+ }).join(" ");
3921
+ const resolvedColor = color === "auto" ? data[data.length - 1] >= data[0] ? COLOR_VAR.success : COLOR_VAR.error : COLOR_VAR[color];
3922
+ const areaPath = fill ? `M ${pad},${height - pad} L ${points.split(" ").join(" L ")} L ${width - pad},${height - pad} Z` : null;
3923
+ return /* @__PURE__ */ jsxs(
3924
+ "svg",
3925
+ {
3926
+ width,
3927
+ height,
3928
+ viewBox: `0 0 ${width} ${height}`,
3929
+ className: cn("flex-shrink-0", className),
3930
+ "aria-hidden": "true",
3931
+ children: [
3932
+ areaPath && /* @__PURE__ */ jsx("path", { d: areaPath, fill: resolvedColor, opacity: 0.15 }),
3933
+ /* @__PURE__ */ jsx(
3934
+ "polyline",
3935
+ {
3936
+ fill: "none",
3937
+ stroke: resolvedColor,
3938
+ strokeWidth,
3939
+ strokeLinecap: "round",
3940
+ strokeLinejoin: "round",
3941
+ points
3942
+ }
3943
+ )
3944
+ ]
3945
+ }
3946
+ );
3947
+ };
3948
+ Sparkline.displayName = "Sparkline";
3949
+ }
3950
+ });
3890
3951
  var Switch;
3891
3952
  var init_Switch = __esm({
3892
3953
  "components/atoms/Switch.tsx"() {
@@ -9164,7 +9225,7 @@ var init_MapView = __esm({
9164
9225
  shadowSize: [41, 41]
9165
9226
  });
9166
9227
  L.Marker.prototype.options.icon = defaultIcon;
9167
- const { useEffect: useEffect68, useRef: useRef65, useCallback: useCallback110, useState: useState98 } = React80__default;
9228
+ const { useEffect: useEffect68, useRef: useRef65, useCallback: useCallback112, useState: useState99 } = React80__default;
9168
9229
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
9169
9230
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
9170
9231
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -9209,8 +9270,8 @@ var init_MapView = __esm({
9209
9270
  showAttribution = true
9210
9271
  }) {
9211
9272
  const eventBus = useEventBus2();
9212
- const [clickedPosition, setClickedPosition] = useState98(null);
9213
- const handleMapClick = useCallback110((lat, lng) => {
9273
+ const [clickedPosition, setClickedPosition] = useState99(null);
9274
+ const handleMapClick = useCallback112((lat, lng) => {
9214
9275
  if (showClickedPin) {
9215
9276
  setClickedPosition({ lat, lng });
9216
9277
  }
@@ -9219,7 +9280,7 @@ var init_MapView = __esm({
9219
9280
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
9220
9281
  }
9221
9282
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
9222
- const handleMarkerClick = useCallback110((marker) => {
9283
+ const handleMarkerClick = useCallback112((marker) => {
9223
9284
  onMarkerClick?.(marker);
9224
9285
  if (markerClickEvent) {
9225
9286
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -19014,7 +19075,7 @@ var init_CastleTemplate = __esm({
19014
19075
  CastleTemplate.displayName = "CastleTemplate";
19015
19076
  }
19016
19077
  });
19017
- var CHART_COLORS, BarChart, PieChart, LineChart, Chart;
19078
+ var CHART_COLORS, seriesColor, monthFormatter, formatTimeLabel, BarChart, PieChart, LineChart, ScatterChart, Chart;
19018
19079
  var init_Chart = __esm({
19019
19080
  "components/organisms/Chart.tsx"() {
19020
19081
  "use client";
@@ -19034,38 +19095,159 @@ var init_Chart = __esm({
19034
19095
  "var(--color-info)",
19035
19096
  "var(--color-accent)"
19036
19097
  ];
19037
- BarChart = ({ data, height, showValues }) => {
19038
- const maxValue = Math.max(...data.map((d) => d.value), 1);
19039
- return /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "end", className: "w-full", style: { height }, children: data.map((point, idx) => {
19040
- const barHeight = point.value / maxValue * 100;
19041
- const color = point.color || CHART_COLORS[idx % CHART_COLORS.length];
19042
- return /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "center", flex: true, className: "min-w-0", children: [
19043
- showValues && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: point.value }),
19044
- /* @__PURE__ */ jsx(
19045
- Box,
19046
- {
19047
- className: cn(
19048
- "w-full rounded-t-sm transition-all duration-500 ease-out min-h-[4px]"
19049
- ),
19050
- style: {
19051
- height: `${barHeight}%`,
19052
- backgroundColor: color
19053
- }
19098
+ seriesColor = (series, idx) => series.color ?? CHART_COLORS[idx % CHART_COLORS.length];
19099
+ monthFormatter = new Intl.DateTimeFormat(void 0, {
19100
+ month: "short",
19101
+ year: "2-digit"
19102
+ });
19103
+ formatTimeLabel = (raw) => {
19104
+ const parsed = new Date(raw);
19105
+ if (Number.isNaN(parsed.getTime())) return raw;
19106
+ return monthFormatter.format(parsed);
19107
+ };
19108
+ BarChart = ({ series, height, showValues, stack, timeAxis, histogram = false, onPointClick }) => {
19109
+ const categories = useMemo(() => {
19110
+ const set = [];
19111
+ const seen = /* @__PURE__ */ new Set();
19112
+ for (const s of series) {
19113
+ for (const p2 of s.data) {
19114
+ if (!seen.has(p2.label)) {
19115
+ seen.add(p2.label);
19116
+ set.push(p2.label);
19054
19117
  }
19055
- ),
19056
- /* @__PURE__ */ jsx(
19057
- Typography,
19058
- {
19059
- variant: "caption",
19060
- color: "secondary",
19061
- className: "truncate w-full text-center",
19062
- children: point.label
19118
+ }
19119
+ }
19120
+ return set;
19121
+ }, [series]);
19122
+ const valueAt = useCallback(
19123
+ (s, label) => {
19124
+ const p2 = s.data.find((d) => d.label === label);
19125
+ return p2 ? p2.value : 0;
19126
+ },
19127
+ []
19128
+ );
19129
+ const columnTotals = useMemo(() => {
19130
+ if (stack === "none") return null;
19131
+ return categories.map(
19132
+ (label) => series.reduce((sum, s) => sum + valueAt(s, label), 0)
19133
+ );
19134
+ }, [categories, series, stack, valueAt]);
19135
+ const maxValue = useMemo(() => {
19136
+ if (stack === "normalize") return 100;
19137
+ if (stack === "stack" && columnTotals) {
19138
+ return Math.max(...columnTotals, 1);
19139
+ }
19140
+ let m = 1;
19141
+ for (const s of series) {
19142
+ for (const p2 of s.data) if (p2.value > m) m = p2.value;
19143
+ }
19144
+ return m;
19145
+ }, [series, stack, columnTotals]);
19146
+ return /* @__PURE__ */ jsx(
19147
+ HStack,
19148
+ {
19149
+ gap: histogram ? "none" : "xs",
19150
+ align: "end",
19151
+ className: "w-full",
19152
+ style: { height },
19153
+ children: categories.map((label, catIdx) => {
19154
+ const displayLabel = timeAxis ? formatTimeLabel(label) : label;
19155
+ if (stack === "none") {
19156
+ return /* @__PURE__ */ jsxs(
19157
+ VStack,
19158
+ {
19159
+ gap: "xs",
19160
+ align: "center",
19161
+ flex: true,
19162
+ className: "min-w-0",
19163
+ children: [
19164
+ /* @__PURE__ */ jsx(HStack, { gap: histogram ? "none" : "xs", align: "end", className: "w-full", style: { height: "100%" }, children: series.map((s, sIdx) => {
19165
+ const value = valueAt(s, label);
19166
+ const barHeight = value / maxValue * 100;
19167
+ const color = seriesColor(s, sIdx);
19168
+ return /* @__PURE__ */ jsx(
19169
+ Box,
19170
+ {
19171
+ className: cn(
19172
+ "rounded-t-sm transition-all duration-500 ease-out min-h-[4px] cursor-pointer hover:opacity-80",
19173
+ histogram ? "flex-1 mx-0" : "flex-1"
19174
+ ),
19175
+ style: {
19176
+ height: `${barHeight}%`,
19177
+ backgroundColor: color
19178
+ },
19179
+ onClick: () => onPointClick?.(
19180
+ { label, value, color },
19181
+ s.name
19182
+ ),
19183
+ title: `${s.name}: ${value}`
19184
+ },
19185
+ s.name
19186
+ );
19187
+ }) }),
19188
+ showValues && series.length === 1 && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: valueAt(series[0], label) }),
19189
+ /* @__PURE__ */ jsx(
19190
+ Typography,
19191
+ {
19192
+ variant: "caption",
19193
+ color: "secondary",
19194
+ className: "truncate w-full text-center",
19195
+ children: displayLabel
19196
+ }
19197
+ )
19198
+ ]
19199
+ },
19200
+ label
19201
+ );
19063
19202
  }
19064
- )
19065
- ] }, point.label);
19066
- }) });
19203
+ const total = columnTotals?.[catIdx] ?? 1;
19204
+ return /* @__PURE__ */ jsxs(
19205
+ VStack,
19206
+ {
19207
+ gap: "xs",
19208
+ align: "center",
19209
+ flex: true,
19210
+ className: "min-w-0",
19211
+ children: [
19212
+ /* @__PURE__ */ jsx(VStack, { gap: "none", className: "w-full", style: { height: "100%" }, justify: "end", children: series.map((s, sIdx) => {
19213
+ const value = valueAt(s, label);
19214
+ const ratio = stack === "normalize" ? total === 0 ? 0 : value / total * 100 : value / maxValue * 100;
19215
+ const color = seriesColor(s, sIdx);
19216
+ return /* @__PURE__ */ jsx(
19217
+ Box,
19218
+ {
19219
+ className: "w-full transition-all duration-500 ease-out cursor-pointer hover:opacity-80",
19220
+ style: {
19221
+ height: `${ratio}%`,
19222
+ backgroundColor: color
19223
+ },
19224
+ onClick: () => onPointClick?.(
19225
+ { label, value, color },
19226
+ s.name
19227
+ ),
19228
+ title: `${s.name}: ${value}`
19229
+ },
19230
+ s.name
19231
+ );
19232
+ }) }),
19233
+ /* @__PURE__ */ jsx(
19234
+ Typography,
19235
+ {
19236
+ variant: "caption",
19237
+ color: "secondary",
19238
+ className: "truncate w-full text-center",
19239
+ children: displayLabel
19240
+ }
19241
+ )
19242
+ ]
19243
+ },
19244
+ label
19245
+ );
19246
+ })
19247
+ }
19248
+ );
19067
19249
  };
19068
- PieChart = ({ data, height, showValues, donut = false }) => {
19250
+ PieChart = ({ data, height, showValues, donut = false, onPointClick }) => {
19069
19251
  const total = data.reduce((sum, d) => sum + d.value, 0);
19070
19252
  const size = Math.min(height, 200);
19071
19253
  const radius = size / 2 - 8;
@@ -19111,7 +19293,11 @@ var init_Chart = __esm({
19111
19293
  fill: seg.color,
19112
19294
  stroke: "var(--color-card)",
19113
19295
  strokeWidth: "2",
19114
- className: "transition-opacity duration-200 hover:opacity-80"
19296
+ className: "transition-opacity duration-200 hover:opacity-80 cursor-pointer",
19297
+ onClick: () => onPointClick?.(
19298
+ { label: seg.label, value: seg.value, color: seg.color },
19299
+ "default"
19300
+ )
19115
19301
  },
19116
19302
  idx
19117
19303
  )),
@@ -19146,56 +19332,243 @@ var init_Chart = __esm({
19146
19332
  ] }, idx)) })
19147
19333
  ] });
19148
19334
  };
19149
- LineChart = ({ data, height, showValues, fill = false }) => {
19150
- const maxValue = Math.max(...data.map((d) => d.value), 1);
19335
+ LineChart = ({ series, height, showValues, fill = false, timeAxis, onPointClick }) => {
19151
19336
  const width = 400;
19152
19337
  const padding = { top: 20, right: 20, bottom: 30, left: 40 };
19153
19338
  const chartWidth = width - padding.left - padding.right;
19154
19339
  const chartHeight = height - padding.top - padding.bottom;
19155
- const points = useMemo(() => {
19156
- return data.map((point, idx) => ({
19157
- x: padding.left + idx / Math.max(data.length - 1, 1) * chartWidth,
19158
- y: padding.top + chartHeight - point.value / maxValue * chartHeight,
19159
- ...point
19160
- }));
19161
- }, [data, maxValue, chartWidth, chartHeight, padding]);
19162
- const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
19163
- const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
19164
- return /* @__PURE__ */ jsxs("svg", { width: "100%", height, viewBox: `0 0 ${width} ${height}`, preserveAspectRatio: "xMidYMid meet", children: [
19165
- [0, 0.25, 0.5, 0.75, 1].map((frac) => {
19166
- const y = padding.top + chartHeight * (1 - frac);
19167
- return /* @__PURE__ */ jsx(
19168
- "line",
19169
- {
19170
- x1: padding.left,
19171
- y1: y,
19172
- x2: width - padding.right,
19173
- y2: y,
19174
- stroke: "var(--color-border)",
19175
- strokeDasharray: "4 4",
19176
- opacity: 0.5
19177
- },
19178
- frac
19179
- );
19180
- }),
19181
- fill && /* @__PURE__ */ jsx("path", { d: areaPath, fill: "var(--color-primary)", opacity: 0.1 }),
19182
- /* @__PURE__ */ jsx("path", { d: linePath, fill: "none", stroke: "var(--color-primary)", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
19183
- points.map((p2, idx) => /* @__PURE__ */ jsxs("g", { children: [
19184
- /* @__PURE__ */ jsx("circle", { cx: p2.x, cy: p2.y, r: "4", fill: "var(--color-card)", stroke: "var(--color-primary)", strokeWidth: "2" }),
19185
- showValues && /* @__PURE__ */ jsx("text", { x: p2.x, y: p2.y - 10, textAnchor: "middle", fill: "var(--color-foreground)", fontSize: "10", fontWeight: "500", children: p2.value }),
19186
- /* @__PURE__ */ jsx(
19187
- "text",
19188
- {
19189
- x: p2.x,
19190
- y: height - 8,
19191
- textAnchor: "middle",
19192
- fill: "var(--color-muted-foreground)",
19193
- fontSize: "9",
19194
- children: p2.label
19340
+ const labels = useMemo(() => {
19341
+ const seen = /* @__PURE__ */ new Set();
19342
+ const out = [];
19343
+ for (const s of series) {
19344
+ for (const p2 of s.data) {
19345
+ if (!seen.has(p2.label)) {
19346
+ seen.add(p2.label);
19347
+ out.push(p2.label);
19195
19348
  }
19196
- )
19197
- ] }, idx))
19198
- ] });
19349
+ }
19350
+ }
19351
+ return out;
19352
+ }, [series]);
19353
+ const maxValue = useMemo(() => {
19354
+ let m = 1;
19355
+ for (const s of series) {
19356
+ for (const p2 of s.data) if (p2.value > m) m = p2.value;
19357
+ }
19358
+ return m;
19359
+ }, [series]);
19360
+ const xFor = useCallback(
19361
+ (idx) => padding.left + idx / Math.max(labels.length - 1, 1) * chartWidth,
19362
+ [labels.length, chartWidth, padding.left]
19363
+ );
19364
+ const yFor = useCallback(
19365
+ (value) => padding.top + chartHeight - value / maxValue * chartHeight,
19366
+ [maxValue, chartHeight, padding.top]
19367
+ );
19368
+ return /* @__PURE__ */ jsxs(
19369
+ "svg",
19370
+ {
19371
+ width: "100%",
19372
+ height,
19373
+ viewBox: `0 0 ${width} ${height}`,
19374
+ preserveAspectRatio: "xMidYMid meet",
19375
+ children: [
19376
+ [0, 0.25, 0.5, 0.75, 1].map((frac) => {
19377
+ const y = padding.top + chartHeight * (1 - frac);
19378
+ return /* @__PURE__ */ jsx(
19379
+ "line",
19380
+ {
19381
+ x1: padding.left,
19382
+ y1: y,
19383
+ x2: width - padding.right,
19384
+ y2: y,
19385
+ stroke: "var(--color-border)",
19386
+ strokeDasharray: "4 4",
19387
+ opacity: 0.5
19388
+ },
19389
+ frac
19390
+ );
19391
+ }),
19392
+ series.map((s, sIdx) => {
19393
+ const color = seriesColor(s, sIdx);
19394
+ const points = labels.map((label, idx) => {
19395
+ const point = s.data.find((d) => d.label === label);
19396
+ return {
19397
+ x: xFor(idx),
19398
+ y: yFor(point ? point.value : 0),
19399
+ value: point ? point.value : 0,
19400
+ label
19401
+ };
19402
+ });
19403
+ const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
19404
+ const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
19405
+ return /* @__PURE__ */ jsxs("g", { children: [
19406
+ fill && /* @__PURE__ */ jsx(
19407
+ "path",
19408
+ {
19409
+ d: areaPath,
19410
+ fill: color,
19411
+ opacity: series.length > 1 ? 0.08 : 0.1
19412
+ }
19413
+ ),
19414
+ /* @__PURE__ */ jsx(
19415
+ "path",
19416
+ {
19417
+ d: linePath,
19418
+ fill: "none",
19419
+ stroke: color,
19420
+ strokeWidth: "2",
19421
+ strokeLinecap: "round",
19422
+ strokeLinejoin: "round",
19423
+ strokeDasharray: s.dashed ? "6 4" : void 0
19424
+ }
19425
+ ),
19426
+ points.map((p2, idx) => /* @__PURE__ */ jsxs("g", { children: [
19427
+ /* @__PURE__ */ jsx(
19428
+ "circle",
19429
+ {
19430
+ cx: p2.x,
19431
+ cy: p2.y,
19432
+ r: "4",
19433
+ fill: "var(--color-card)",
19434
+ stroke: color,
19435
+ strokeWidth: "2",
19436
+ className: "cursor-pointer",
19437
+ onClick: () => onPointClick?.(
19438
+ { label: p2.label, value: p2.value, color },
19439
+ s.name
19440
+ )
19441
+ }
19442
+ ),
19443
+ showValues && series.length === 1 && /* @__PURE__ */ jsx(
19444
+ "text",
19445
+ {
19446
+ x: p2.x,
19447
+ y: p2.y - 10,
19448
+ textAnchor: "middle",
19449
+ fill: "var(--color-foreground)",
19450
+ fontSize: "10",
19451
+ fontWeight: "500",
19452
+ children: p2.value
19453
+ }
19454
+ )
19455
+ ] }, idx))
19456
+ ] }, s.name);
19457
+ }),
19458
+ labels.map((label, idx) => /* @__PURE__ */ jsx(
19459
+ "text",
19460
+ {
19461
+ x: xFor(idx),
19462
+ y: height - 8,
19463
+ textAnchor: "middle",
19464
+ fill: "var(--color-muted-foreground)",
19465
+ fontSize: "9",
19466
+ children: timeAxis ? formatTimeLabel(label) : label
19467
+ },
19468
+ label
19469
+ ))
19470
+ ]
19471
+ }
19472
+ );
19473
+ };
19474
+ ScatterChart = ({ data, height, onPointClick }) => {
19475
+ const width = 400;
19476
+ const padding = { top: 20, right: 20, bottom: 30, left: 40 };
19477
+ const chartWidth = width - padding.left - padding.right;
19478
+ const chartHeight = height - padding.top - padding.bottom;
19479
+ const { minX, maxX, minY, maxY } = useMemo(() => {
19480
+ if (data.length === 0) {
19481
+ return { minX: 0, maxX: 1, minY: 0, maxY: 1 };
19482
+ }
19483
+ let mnX = data[0].x;
19484
+ let mxX = data[0].x;
19485
+ let mnY = data[0].y;
19486
+ let mxY = data[0].y;
19487
+ for (const p2 of data) {
19488
+ if (p2.x < mnX) mnX = p2.x;
19489
+ if (p2.x > mxX) mxX = p2.x;
19490
+ if (p2.y < mnY) mnY = p2.y;
19491
+ if (p2.y > mxY) mxY = p2.y;
19492
+ }
19493
+ return { minX: mnX, maxX: mxX, minY: mnY, maxY: mxY };
19494
+ }, [data]);
19495
+ const rangeX = maxX - minX || 1;
19496
+ const rangeY = maxY - minY || 1;
19497
+ return /* @__PURE__ */ jsxs(
19498
+ "svg",
19499
+ {
19500
+ width: "100%",
19501
+ height,
19502
+ viewBox: `0 0 ${width} ${height}`,
19503
+ preserveAspectRatio: "xMidYMid meet",
19504
+ children: [
19505
+ [0, 0.25, 0.5, 0.75, 1].map((frac) => {
19506
+ const y = padding.top + chartHeight * (1 - frac);
19507
+ return /* @__PURE__ */ jsx(
19508
+ "line",
19509
+ {
19510
+ x1: padding.left,
19511
+ y1: y,
19512
+ x2: width - padding.right,
19513
+ y2: y,
19514
+ stroke: "var(--color-border)",
19515
+ strokeDasharray: "4 4",
19516
+ opacity: 0.5
19517
+ },
19518
+ frac
19519
+ );
19520
+ }),
19521
+ data.map((p2, idx) => {
19522
+ const cx = padding.left + (p2.x - minX) / rangeX * chartWidth;
19523
+ const cy = padding.top + chartHeight - (p2.y - minY) / rangeY * chartHeight;
19524
+ const r = p2.size ?? 5;
19525
+ const color = p2.color ?? CHART_COLORS[idx % CHART_COLORS.length];
19526
+ return /* @__PURE__ */ jsx(
19527
+ "circle",
19528
+ {
19529
+ cx,
19530
+ cy,
19531
+ r,
19532
+ fill: color,
19533
+ opacity: 0.7,
19534
+ className: "cursor-pointer hover:opacity-100",
19535
+ onClick: () => onPointClick?.(
19536
+ {
19537
+ label: p2.label ?? `(${p2.x}, ${p2.y})`,
19538
+ value: p2.y,
19539
+ color
19540
+ },
19541
+ "default"
19542
+ ),
19543
+ children: /* @__PURE__ */ jsx("title", { children: p2.label ?? `(${p2.x}, ${p2.y})` })
19544
+ },
19545
+ idx
19546
+ );
19547
+ }),
19548
+ /* @__PURE__ */ jsx(
19549
+ "text",
19550
+ {
19551
+ x: padding.left,
19552
+ y: height - 8,
19553
+ fill: "var(--color-muted-foreground)",
19554
+ fontSize: "9",
19555
+ children: minX.toFixed(1)
19556
+ }
19557
+ ),
19558
+ /* @__PURE__ */ jsx(
19559
+ "text",
19560
+ {
19561
+ x: width - padding.right,
19562
+ y: height - 8,
19563
+ textAnchor: "end",
19564
+ fill: "var(--color-muted-foreground)",
19565
+ fontSize: "9",
19566
+ children: maxX.toFixed(1)
19567
+ }
19568
+ )
19569
+ ]
19570
+ }
19571
+ );
19199
19572
  };
19200
19573
  Chart = ({
19201
19574
  title,
@@ -19203,9 +19576,13 @@ var init_Chart = __esm({
19203
19576
  chartType = "bar",
19204
19577
  series,
19205
19578
  data: simpleData,
19579
+ scatterData,
19206
19580
  height = 200,
19207
19581
  showLegend = true,
19208
19582
  showValues = false,
19583
+ stack = "none",
19584
+ timeAxis = false,
19585
+ drillEvent,
19209
19586
  actions,
19210
19587
  entity,
19211
19588
  isLoading = false,
@@ -19222,11 +19599,25 @@ var init_Chart = __esm({
19222
19599
  },
19223
19600
  [eventBus]
19224
19601
  );
19225
- const normalizedData = useMemo(() => {
19226
- if (simpleData) return simpleData;
19227
- if (series && series.length > 0) return series[0].data;
19602
+ const handlePointClick = useCallback(
19603
+ (point, seriesName) => {
19604
+ if (drillEvent) {
19605
+ eventBus.emit(`UI:${drillEvent}`, {
19606
+ label: point.label,
19607
+ value: point.value,
19608
+ seriesLabel: seriesName === "default" ? void 0 : seriesName
19609
+ });
19610
+ }
19611
+ },
19612
+ [drillEvent, eventBus]
19613
+ );
19614
+ const normalizedSeries = useMemo(() => {
19615
+ if (series && series.length > 0) return series;
19616
+ if (simpleData) return [{ name: "default", data: simpleData }];
19228
19617
  return [];
19229
19618
  }, [simpleData, series]);
19619
+ const firstSeriesData = normalizedSeries[0]?.data ?? [];
19620
+ const hasContent = chartType === "scatter" ? (scatterData?.length ?? 0) > 0 : normalizedSeries.some((s) => s.data.length > 0);
19230
19621
  if (isLoading) {
19231
19622
  return /* @__PURE__ */ jsx(LoadingState, { message: "Loading chart...", className });
19232
19623
  }
@@ -19240,7 +19631,7 @@ var init_Chart = __esm({
19240
19631
  }
19241
19632
  );
19242
19633
  }
19243
- if (normalizedData.length === 0) {
19634
+ if (!hasContent) {
19244
19635
  return /* @__PURE__ */ jsx(EmptyState, { title: t("empty.noData"), description: t("empty.noData"), className });
19245
19636
  }
19246
19637
  return /* @__PURE__ */ jsx(Card, { className: cn("p-6", className), children: /* @__PURE__ */ jsxs(VStack, { gap: "md", children: [
@@ -19261,18 +19652,84 @@ var init_Chart = __esm({
19261
19652
  )) })
19262
19653
  ] }),
19263
19654
  /* @__PURE__ */ jsxs(Box, { className: "w-full", children: [
19264
- chartType === "bar" && /* @__PURE__ */ jsx(BarChart, { data: normalizedData, height, showValues }),
19265
- chartType === "line" && /* @__PURE__ */ jsx(LineChart, { data: normalizedData, height, showValues }),
19266
- chartType === "area" && /* @__PURE__ */ jsx(LineChart, { data: normalizedData, height, showValues, fill: true }),
19267
- chartType === "pie" && /* @__PURE__ */ jsx(PieChart, { data: normalizedData, height, showValues: showLegend }),
19268
- chartType === "donut" && /* @__PURE__ */ jsx(PieChart, { data: normalizedData, height, showValues: showLegend, donut: true })
19655
+ chartType === "bar" && /* @__PURE__ */ jsx(
19656
+ BarChart,
19657
+ {
19658
+ series: normalizedSeries,
19659
+ height,
19660
+ showValues,
19661
+ stack,
19662
+ timeAxis,
19663
+ onPointClick: handlePointClick
19664
+ }
19665
+ ),
19666
+ chartType === "histogram" && /* @__PURE__ */ jsx(
19667
+ BarChart,
19668
+ {
19669
+ series: normalizedSeries,
19670
+ height,
19671
+ showValues,
19672
+ stack: "none",
19673
+ timeAxis: false,
19674
+ histogram: true,
19675
+ onPointClick: handlePointClick
19676
+ }
19677
+ ),
19678
+ chartType === "line" && /* @__PURE__ */ jsx(
19679
+ LineChart,
19680
+ {
19681
+ series: normalizedSeries,
19682
+ height,
19683
+ showValues,
19684
+ timeAxis,
19685
+ onPointClick: handlePointClick
19686
+ }
19687
+ ),
19688
+ chartType === "area" && /* @__PURE__ */ jsx(
19689
+ LineChart,
19690
+ {
19691
+ series: normalizedSeries,
19692
+ height,
19693
+ showValues,
19694
+ timeAxis,
19695
+ fill: true,
19696
+ onPointClick: handlePointClick
19697
+ }
19698
+ ),
19699
+ chartType === "pie" && /* @__PURE__ */ jsx(
19700
+ PieChart,
19701
+ {
19702
+ data: firstSeriesData,
19703
+ height,
19704
+ showValues: showLegend,
19705
+ onPointClick: handlePointClick
19706
+ }
19707
+ ),
19708
+ chartType === "donut" && /* @__PURE__ */ jsx(
19709
+ PieChart,
19710
+ {
19711
+ data: firstSeriesData,
19712
+ height,
19713
+ showValues: showLegend,
19714
+ donut: true,
19715
+ onPointClick: handlePointClick
19716
+ }
19717
+ ),
19718
+ chartType === "scatter" && /* @__PURE__ */ jsx(
19719
+ ScatterChart,
19720
+ {
19721
+ data: scatterData ?? [],
19722
+ height,
19723
+ onPointClick: handlePointClick
19724
+ }
19725
+ )
19269
19726
  ] }),
19270
- showLegend && series && series.length > 1 && /* @__PURE__ */ jsx(HStack, { gap: "md", justify: "center", wrap: true, children: series.map((s, idx) => /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
19727
+ showLegend && normalizedSeries.length > 1 && /* @__PURE__ */ jsx(HStack, { gap: "md", justify: "center", wrap: true, children: normalizedSeries.map((s, idx) => /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
19271
19728
  /* @__PURE__ */ jsx(
19272
19729
  Box,
19273
19730
  {
19274
19731
  className: "w-3 h-3 rounded-full flex-shrink-0",
19275
- style: { backgroundColor: s.color || CHART_COLORS[idx % CHART_COLORS.length] }
19732
+ style: { backgroundColor: seriesColor(s, idx) }
19276
19733
  }
19277
19734
  ),
19278
19735
  /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: s.name })
@@ -21119,7 +21576,6 @@ function useDataDnd(args) {
21119
21576
  const raw = it[dndItemIdField];
21120
21577
  return raw ?? `__idx_${idx}`;
21121
21578
  }),
21122
- // eslint-disable-next-line react-hooks/exhaustive-deps
21123
21579
  [itemIdsSignature]
21124
21580
  );
21125
21581
  const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
@@ -22649,7 +23105,16 @@ var init_FilterGroup = __esm({
22649
23105
  onClear: () => handleFilterSelect(`${filter.field}_to`, null)
22650
23106
  }
22651
23107
  )
22652
- ] }) : /* @__PURE__ */ jsx(
23108
+ ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
23109
+ Input,
23110
+ {
23111
+ value: selectedValues[filter.field] || "",
23112
+ onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
23113
+ placeholder: filter.label,
23114
+ clearable: true,
23115
+ onClear: () => handleFilterSelect(filter.field, null)
23116
+ }
23117
+ ) : /* @__PURE__ */ jsx(
22653
23118
  Select,
22654
23119
  {
22655
23120
  value: selectedValues[filter.field] || "all",
@@ -22716,7 +23181,17 @@ var init_FilterGroup = __esm({
22716
23181
  className: "text-sm min-w-[100px]"
22717
23182
  }
22718
23183
  )
22719
- ] }) : /* @__PURE__ */ jsx(
23184
+ ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
23185
+ Input,
23186
+ {
23187
+ value: selectedValues[filter.field] || "",
23188
+ onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
23189
+ placeholder: filter.label,
23190
+ clearable: true,
23191
+ onClear: () => handleFilterSelect(filter.field, null),
23192
+ className: "text-sm"
23193
+ }
23194
+ ) : /* @__PURE__ */ jsx(
22720
23195
  Select,
22721
23196
  {
22722
23197
  value: selectedValues[filter.field] || "all",
@@ -22821,7 +23296,17 @@ var init_FilterGroup = __esm({
22821
23296
  className: "min-w-[130px]"
22822
23297
  }
22823
23298
  )
22824
- ] }) : /* @__PURE__ */ jsx(
23299
+ ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
23300
+ Input,
23301
+ {
23302
+ value: selectedValues[filter.field] || "",
23303
+ onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
23304
+ placeholder: filter.label,
23305
+ clearable: true,
23306
+ onClear: () => handleFilterSelect(filter.field, null),
23307
+ className: "min-w-[160px]"
23308
+ }
23309
+ ) : /* @__PURE__ */ jsx(
22825
23310
  Select,
22826
23311
  {
22827
23312
  value: selectedValues[filter.field] || "all",
@@ -24110,6 +24595,151 @@ var init_FlipCard = __esm({
24110
24595
  FlipCard.displayName = "FlipCard";
24111
24596
  }
24112
24597
  });
24598
+ function toISODate(d) {
24599
+ return d.toISOString().slice(0, 10);
24600
+ }
24601
+ function startOfMonth(d) {
24602
+ return new Date(d.getFullYear(), d.getMonth(), 1);
24603
+ }
24604
+ function startOfQuarter(d) {
24605
+ return new Date(d.getFullYear(), Math.floor(d.getMonth() / 3) * 3, 1);
24606
+ }
24607
+ function startOfYear(d) {
24608
+ return new Date(d.getFullYear(), 0, 1);
24609
+ }
24610
+ function daysAgo(n) {
24611
+ const d = /* @__PURE__ */ new Date();
24612
+ d.setDate(d.getDate() - n);
24613
+ return d;
24614
+ }
24615
+ var DEFAULT_PRESETS, DateRangePicker;
24616
+ var init_DateRangePicker = __esm({
24617
+ "components/molecules/DateRangePicker.tsx"() {
24618
+ "use client";
24619
+ init_cn();
24620
+ init_Button();
24621
+ init_Input();
24622
+ init_Stack();
24623
+ init_Typography();
24624
+ init_useEventBus();
24625
+ DEFAULT_PRESETS = [
24626
+ {
24627
+ label: "Last 7 days",
24628
+ value: "7d",
24629
+ range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
24630
+ },
24631
+ {
24632
+ label: "Last 30 days",
24633
+ value: "30d",
24634
+ range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
24635
+ },
24636
+ {
24637
+ label: "This Month",
24638
+ value: "month",
24639
+ range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
24640
+ },
24641
+ {
24642
+ label: "This Quarter",
24643
+ value: "quarter",
24644
+ range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
24645
+ },
24646
+ {
24647
+ label: "YTD",
24648
+ value: "ytd",
24649
+ range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
24650
+ }
24651
+ ];
24652
+ DateRangePicker = ({
24653
+ from: fromProp,
24654
+ to: toProp,
24655
+ event,
24656
+ onChange,
24657
+ presets = DEFAULT_PRESETS,
24658
+ fromLabel = "From",
24659
+ toLabel = "To",
24660
+ className
24661
+ }) => {
24662
+ const eventBus = useEventBus();
24663
+ const [from, setFrom] = useState(fromProp ?? "");
24664
+ const [to, setTo] = useState(toProp ?? "");
24665
+ const [activePreset, setActivePreset] = useState(null);
24666
+ const emit = useCallback(
24667
+ (range) => {
24668
+ onChange?.(range);
24669
+ if (event) eventBus.emit(`UI:${event}`, range);
24670
+ },
24671
+ [onChange, event, eventBus]
24672
+ );
24673
+ const handleFromChange = useCallback(
24674
+ (next) => {
24675
+ setFrom(next);
24676
+ setActivePreset(null);
24677
+ emit({ from: next, to });
24678
+ },
24679
+ [to, emit]
24680
+ );
24681
+ const handleToChange = useCallback(
24682
+ (next) => {
24683
+ setTo(next);
24684
+ setActivePreset(null);
24685
+ emit({ from, to: next });
24686
+ },
24687
+ [from, emit]
24688
+ );
24689
+ const handlePreset = useCallback(
24690
+ (preset) => {
24691
+ const range = preset.range();
24692
+ setFrom(range.from);
24693
+ setTo(range.to);
24694
+ setActivePreset(preset.value);
24695
+ emit(range);
24696
+ },
24697
+ [emit]
24698
+ );
24699
+ const presetButtons = useMemo(
24700
+ () => presets.map((preset) => /* @__PURE__ */ jsx(
24701
+ Button,
24702
+ {
24703
+ variant: activePreset === preset.value ? "primary" : "ghost",
24704
+ size: "sm",
24705
+ onClick: () => handlePreset(preset),
24706
+ children: preset.label
24707
+ },
24708
+ preset.value
24709
+ )),
24710
+ [presets, activePreset, handlePreset]
24711
+ );
24712
+ return /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: cn(className), children: [
24713
+ /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "end", children: [
24714
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
24715
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: fromLabel }),
24716
+ /* @__PURE__ */ jsx(
24717
+ Input,
24718
+ {
24719
+ type: "date",
24720
+ value: from,
24721
+ onChange: (e) => handleFromChange(e.target.value)
24722
+ }
24723
+ )
24724
+ ] }),
24725
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
24726
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: toLabel }),
24727
+ /* @__PURE__ */ jsx(
24728
+ Input,
24729
+ {
24730
+ type: "date",
24731
+ value: to,
24732
+ onChange: (e) => handleToChange(e.target.value)
24733
+ }
24734
+ )
24735
+ ] })
24736
+ ] }),
24737
+ presets.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
24738
+ ] });
24739
+ };
24740
+ DateRangePicker.displayName = "DateRangePicker";
24741
+ }
24742
+ });
24113
24743
  var DEFAULT_OPTIONS, DateRangeSelector;
24114
24744
  var init_DateRangeSelector = __esm({
24115
24745
  "components/molecules/DateRangeSelector.tsx"() {
@@ -27081,7 +27711,9 @@ var init_StatDisplay = __esm({
27081
27711
  init_Typography();
27082
27712
  init_Box();
27083
27713
  init_Stack();
27714
+ init_Sparkline();
27084
27715
  init_Icon();
27716
+ init_useEventBus();
27085
27717
  variantColor = {
27086
27718
  default: "text-foreground",
27087
27719
  primary: "text-primary",
@@ -27096,6 +27728,10 @@ var init_StatDisplay = __esm({
27096
27728
  max,
27097
27729
  target,
27098
27730
  trend,
27731
+ trendPolarity = "higher-is-better",
27732
+ trendFormat = "absolute",
27733
+ sparklineData,
27734
+ clickEvent,
27099
27735
  prefix,
27100
27736
  suffix,
27101
27737
  icon: iconProp,
@@ -27109,6 +27745,10 @@ var init_StatDisplay = __esm({
27109
27745
  isLoading = false,
27110
27746
  error = null
27111
27747
  }) => {
27748
+ const eventBus = useEventBus();
27749
+ const handleClick = useCallback(() => {
27750
+ if (clickEvent) eventBus.emit(`UI:${clickEvent}`, { metricLabel: label });
27751
+ }, [clickEvent, eventBus, label]);
27112
27752
  const ResolvedIcon = typeof iconProp === "string" ? resolveIcon(iconProp) : null;
27113
27753
  const iconSizes3 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
27114
27754
  const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
@@ -27119,7 +27759,10 @@ var init_StatDisplay = __esm({
27119
27759
  const targetPct = showTarget ? Math.max(0, Math.min(100, numericValue / target * 100)) : 0;
27120
27760
  const showTrend = typeof trend === "number" && trend !== 0 && Number.isFinite(trend);
27121
27761
  const trendUp = showTrend && trend > 0;
27122
- const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${Math.abs(trend)}` : "";
27762
+ const trendIsGood = trendPolarity === "lower-is-better" ? !trendUp : trendUp;
27763
+ const trendMagnitude = Math.abs(trend);
27764
+ const trendSuffix = trendFormat === "percent" ? "%" : "";
27765
+ const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${trendMagnitude}${trendSuffix}` : "";
27123
27766
  if (error) {
27124
27767
  return /* @__PURE__ */ jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsx(Typography, { variant: "small", color: "error", children: error.message }) });
27125
27768
  }
@@ -27130,38 +27773,57 @@ var init_StatDisplay = __esm({
27130
27773
  ] }) });
27131
27774
  }
27132
27775
  if (compact) {
27133
- return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: cn("items-center", className), children: [
27134
- ResolvedIcon && /* @__PURE__ */ jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
27135
- typeof iconProp !== "string" && iconProp,
27136
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: label }),
27137
- /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
27138
- showTrend && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: cn("font-semibold", trendUp ? "text-success" : "text-error"), children: trendLabel })
27139
- ] });
27776
+ return /* @__PURE__ */ jsxs(
27777
+ HStack,
27778
+ {
27779
+ gap: "sm",
27780
+ className: cn("items-center", clickEvent && "cursor-pointer hover:opacity-80", className),
27781
+ onClick: clickEvent ? handleClick : void 0,
27782
+ children: [
27783
+ ResolvedIcon && /* @__PURE__ */ jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
27784
+ typeof iconProp !== "string" && iconProp,
27785
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: label }),
27786
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
27787
+ showTrend && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: cn("font-semibold", trendIsGood ? "text-success" : "text-error"), children: trendLabel }),
27788
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto", width: 60, height: 20 })
27789
+ ]
27790
+ }
27791
+ );
27140
27792
  }
27141
- return /* @__PURE__ */ jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxs(HStack, { align: "start", justify: "between", children: [
27142
- /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
27143
- /* @__PURE__ */ jsx(Typography, { variant: "overline", color: "secondary", children: label }),
27144
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "end", children: [
27145
- /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
27146
- showTrend && /* @__PURE__ */ jsx(
27147
- Typography,
27148
- {
27149
- variant: "caption",
27150
- className: cn("font-semibold pb-1", trendUp ? "text-success" : "text-error"),
27151
- children: trendLabel
27152
- }
27153
- )
27154
- ] }),
27155
- showTarget && /* @__PURE__ */ jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
27156
- Box,
27157
- {
27158
- className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
27159
- style: { width: `${targetPct}%` }
27160
- }
27161
- ) })
27162
- ] }),
27163
- (ResolvedIcon || typeof iconProp !== "string" && iconProp) && /* @__PURE__ */ jsx(Box, { className: cn("p-3 rounded-md", iconBg), children: ResolvedIcon ? /* @__PURE__ */ jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }) : iconProp })
27164
- ] }) });
27793
+ return /* @__PURE__ */ jsx(
27794
+ Card,
27795
+ {
27796
+ className: cn(padSizes[size], clickEvent && "cursor-pointer hover:shadow-md transition-shadow", className),
27797
+ onClick: clickEvent ? handleClick : void 0,
27798
+ children: /* @__PURE__ */ jsxs(HStack, { align: "start", justify: "between", children: [
27799
+ /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
27800
+ /* @__PURE__ */ jsx(Typography, { variant: "overline", color: "secondary", children: label }),
27801
+ /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "end", children: [
27802
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
27803
+ showTrend && /* @__PURE__ */ jsx(
27804
+ Typography,
27805
+ {
27806
+ variant: "caption",
27807
+ className: cn("font-semibold pb-1", trendIsGood ? "text-success" : "text-error"),
27808
+ children: trendLabel
27809
+ }
27810
+ )
27811
+ ] }),
27812
+ showTarget && /* @__PURE__ */ jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
27813
+ Box,
27814
+ {
27815
+ className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
27816
+ style: { width: `${targetPct}%` }
27817
+ }
27818
+ ) })
27819
+ ] }),
27820
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
27821
+ (ResolvedIcon || typeof iconProp !== "string" && iconProp) && /* @__PURE__ */ jsx(Box, { className: cn("p-3 rounded-md", iconBg), children: ResolvedIcon ? /* @__PURE__ */ jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }) : iconProp }),
27822
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto" })
27823
+ ] })
27824
+ ] })
27825
+ }
27826
+ );
27165
27827
  };
27166
27828
  StatDisplay.displayName = "StatDisplay";
27167
27829
  }
@@ -41505,6 +42167,7 @@ var init_StatCard = __esm({
41505
42167
  init_Box();
41506
42168
  init_Stack();
41507
42169
  init_Button();
42170
+ init_Sparkline();
41508
42171
  init_useEventBus();
41509
42172
  init_useTranslate();
41510
42173
  init_Icon();
@@ -41674,32 +42337,7 @@ var init_StatCard = __esm({
41674
42337
  ] }),
41675
42338
  /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
41676
42339
  Icon3 && /* @__PURE__ */ jsx(Box, { className: cn("p-3", iconBg), children: /* @__PURE__ */ jsx(Icon3, { className: cn("h-6 w-6", iconColor) }) }),
41677
- sparklineData && sparklineData.length > 1 && (() => {
41678
- const w = 80;
41679
- const h = 32;
41680
- const pad = 2;
41681
- const min = Math.min(...sparklineData);
41682
- const max = Math.max(...sparklineData);
41683
- const range = max - min || 1;
41684
- const points = sparklineData.map((v, i) => {
41685
- const x = pad + i / (sparklineData.length - 1) * (w - pad * 2);
41686
- const y = pad + (1 - (v - min) / range) * (h - pad * 2);
41687
- return `${x},${y}`;
41688
- }).join(" ");
41689
- const trending = sparklineData[sparklineData.length - 1] >= sparklineData[0];
41690
- const strokeColor = trending ? "var(--color-success)" : "var(--color-error)";
41691
- return /* @__PURE__ */ jsx("svg", { width: w, height: h, viewBox: `0 0 ${w} ${h}`, className: "flex-shrink-0", children: /* @__PURE__ */ jsx(
41692
- "polyline",
41693
- {
41694
- fill: "none",
41695
- stroke: strokeColor,
41696
- strokeWidth: "2",
41697
- strokeLinecap: "round",
41698
- strokeLinejoin: "round",
41699
- points
41700
- }
41701
- ) });
41702
- })()
42340
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto" })
41703
42341
  ] })
41704
42342
  ] }),
41705
42343
  action && /* @__PURE__ */ jsxs(
@@ -43597,6 +44235,7 @@ var init_component_registry_generated = __esm({
43597
44235
  init_DataGrid();
43598
44236
  init_DataList();
43599
44237
  init_DataTable();
44238
+ init_DateRangePicker();
43600
44239
  init_DateRangeSelector();
43601
44240
  init_DayCell();
43602
44241
  init_DebuggerBoard();
@@ -43729,6 +44368,7 @@ var init_component_registry_generated = __esm({
43729
44368
  init_Skeleton();
43730
44369
  init_SocialProof();
43731
44370
  init_SortableList();
44371
+ init_Sparkline();
43732
44372
  init_Split();
43733
44373
  init_SplitPane();
43734
44374
  init_SplitSection();
@@ -43877,6 +44517,7 @@ var init_component_registry_generated = __esm({
43877
44517
  "DataGrid": DataGrid,
43878
44518
  "DataList": DataList,
43879
44519
  "DataTable": DataTable,
44520
+ "DateRangePicker": DateRangePicker,
43880
44521
  "DateRangeSelector": DateRangeSelector,
43881
44522
  "DayCell": DayCell,
43882
44523
  "DebuggerBoard": DebuggerBoard,
@@ -44038,6 +44679,7 @@ var init_component_registry_generated = __esm({
44038
44679
  "SortableList": SortableList,
44039
44680
  "Spacer": SpacerPattern,
44040
44681
  "SpacerPattern": SpacerPattern,
44682
+ "Sparkline": Sparkline,
44041
44683
  "Spinner": SpinnerPattern,
44042
44684
  "SpinnerPattern": SpinnerPattern,
44043
44685
  "Split": Split,