@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.
@@ -3603,6 +3603,67 @@ var init_Radio = __esm({
3603
3603
  Radio.displayName = "Radio";
3604
3604
  }
3605
3605
  });
3606
+ var COLOR_VAR, Sparkline;
3607
+ var init_Sparkline = __esm({
3608
+ "components/atoms/Sparkline.tsx"() {
3609
+ init_cn();
3610
+ COLOR_VAR = {
3611
+ primary: "var(--color-primary)",
3612
+ success: "var(--color-success)",
3613
+ warning: "var(--color-warning)",
3614
+ error: "var(--color-error)",
3615
+ info: "var(--color-info)",
3616
+ muted: "var(--color-muted-foreground)"
3617
+ };
3618
+ Sparkline = ({
3619
+ data,
3620
+ color = "auto",
3621
+ width = 80,
3622
+ height = 32,
3623
+ strokeWidth = 2,
3624
+ fill = false,
3625
+ className
3626
+ }) => {
3627
+ if (data.length < 2) return null;
3628
+ const pad = 2;
3629
+ const min = Math.min(...data);
3630
+ const max = Math.max(...data);
3631
+ const range = max - min || 1;
3632
+ const points = data.map((v, i) => {
3633
+ const x = pad + i / (data.length - 1) * (width - pad * 2);
3634
+ const y = pad + (1 - (v - min) / range) * (height - pad * 2);
3635
+ return `${x},${y}`;
3636
+ }).join(" ");
3637
+ const resolvedColor = color === "auto" ? data[data.length - 1] >= data[0] ? COLOR_VAR.success : COLOR_VAR.error : COLOR_VAR[color];
3638
+ const areaPath = fill ? `M ${pad},${height - pad} L ${points.split(" ").join(" L ")} L ${width - pad},${height - pad} Z` : null;
3639
+ return /* @__PURE__ */ jsxs(
3640
+ "svg",
3641
+ {
3642
+ width,
3643
+ height,
3644
+ viewBox: `0 0 ${width} ${height}`,
3645
+ className: cn("flex-shrink-0", className),
3646
+ "aria-hidden": "true",
3647
+ children: [
3648
+ areaPath && /* @__PURE__ */ jsx("path", { d: areaPath, fill: resolvedColor, opacity: 0.15 }),
3649
+ /* @__PURE__ */ jsx(
3650
+ "polyline",
3651
+ {
3652
+ fill: "none",
3653
+ stroke: resolvedColor,
3654
+ strokeWidth,
3655
+ strokeLinecap: "round",
3656
+ strokeLinejoin: "round",
3657
+ points
3658
+ }
3659
+ )
3660
+ ]
3661
+ }
3662
+ );
3663
+ };
3664
+ Sparkline.displayName = "Sparkline";
3665
+ }
3666
+ });
3606
3667
  var Switch;
3607
3668
  var init_Switch = __esm({
3608
3669
  "components/atoms/Switch.tsx"() {
@@ -9276,7 +9337,7 @@ var init_MapView = __esm({
9276
9337
  shadowSize: [41, 41]
9277
9338
  });
9278
9339
  L.Marker.prototype.options.icon = defaultIcon;
9279
- const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback110, useState: useState95 } = React81__default;
9340
+ const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback112, useState: useState96 } = React81__default;
9280
9341
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
9281
9342
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
9282
9343
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -9321,8 +9382,8 @@ var init_MapView = __esm({
9321
9382
  showAttribution = true
9322
9383
  }) {
9323
9384
  const eventBus = useEventBus2();
9324
- const [clickedPosition, setClickedPosition] = useState95(null);
9325
- const handleMapClick = useCallback110((lat, lng) => {
9385
+ const [clickedPosition, setClickedPosition] = useState96(null);
9386
+ const handleMapClick = useCallback112((lat, lng) => {
9326
9387
  if (showClickedPin) {
9327
9388
  setClickedPosition({ lat, lng });
9328
9389
  }
@@ -9331,7 +9392,7 @@ var init_MapView = __esm({
9331
9392
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
9332
9393
  }
9333
9394
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
9334
- const handleMarkerClick = useCallback110((marker) => {
9395
+ const handleMarkerClick = useCallback112((marker) => {
9335
9396
  onMarkerClick?.(marker);
9336
9397
  if (markerClickEvent) {
9337
9398
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -19231,7 +19292,7 @@ var init_CastleTemplate = __esm({
19231
19292
  CastleTemplate.displayName = "CastleTemplate";
19232
19293
  }
19233
19294
  });
19234
- var CHART_COLORS, BarChart, PieChart, LineChart, Chart;
19295
+ var CHART_COLORS, seriesColor, monthFormatter, formatTimeLabel, BarChart, PieChart, LineChart, ScatterChart, Chart;
19235
19296
  var init_Chart = __esm({
19236
19297
  "components/organisms/Chart.tsx"() {
19237
19298
  "use client";
@@ -19251,38 +19312,159 @@ var init_Chart = __esm({
19251
19312
  "var(--color-info)",
19252
19313
  "var(--color-accent)"
19253
19314
  ];
19254
- BarChart = ({ data, height, showValues }) => {
19255
- const maxValue = Math.max(...data.map((d) => d.value), 1);
19256
- return /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "end", className: "w-full", style: { height }, children: data.map((point, idx) => {
19257
- const barHeight = point.value / maxValue * 100;
19258
- const color = point.color || CHART_COLORS[idx % CHART_COLORS.length];
19259
- return /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "center", flex: true, className: "min-w-0", children: [
19260
- showValues && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: point.value }),
19261
- /* @__PURE__ */ jsx(
19262
- Box,
19263
- {
19264
- className: cn(
19265
- "w-full rounded-t-sm transition-all duration-500 ease-out min-h-[4px]"
19266
- ),
19267
- style: {
19268
- height: `${barHeight}%`,
19269
- backgroundColor: color
19270
- }
19315
+ seriesColor = (series, idx) => series.color ?? CHART_COLORS[idx % CHART_COLORS.length];
19316
+ monthFormatter = new Intl.DateTimeFormat(void 0, {
19317
+ month: "short",
19318
+ year: "2-digit"
19319
+ });
19320
+ formatTimeLabel = (raw) => {
19321
+ const parsed = new Date(raw);
19322
+ if (Number.isNaN(parsed.getTime())) return raw;
19323
+ return monthFormatter.format(parsed);
19324
+ };
19325
+ BarChart = ({ series, height, showValues, stack, timeAxis, histogram = false, onPointClick }) => {
19326
+ const categories = useMemo(() => {
19327
+ const set = [];
19328
+ const seen = /* @__PURE__ */ new Set();
19329
+ for (const s of series) {
19330
+ for (const p2 of s.data) {
19331
+ if (!seen.has(p2.label)) {
19332
+ seen.add(p2.label);
19333
+ set.push(p2.label);
19271
19334
  }
19272
- ),
19273
- /* @__PURE__ */ jsx(
19274
- Typography,
19275
- {
19276
- variant: "caption",
19277
- color: "secondary",
19278
- className: "truncate w-full text-center",
19279
- children: point.label
19335
+ }
19336
+ }
19337
+ return set;
19338
+ }, [series]);
19339
+ const valueAt = useCallback(
19340
+ (s, label) => {
19341
+ const p2 = s.data.find((d) => d.label === label);
19342
+ return p2 ? p2.value : 0;
19343
+ },
19344
+ []
19345
+ );
19346
+ const columnTotals = useMemo(() => {
19347
+ if (stack === "none") return null;
19348
+ return categories.map(
19349
+ (label) => series.reduce((sum, s) => sum + valueAt(s, label), 0)
19350
+ );
19351
+ }, [categories, series, stack, valueAt]);
19352
+ const maxValue = useMemo(() => {
19353
+ if (stack === "normalize") return 100;
19354
+ if (stack === "stack" && columnTotals) {
19355
+ return Math.max(...columnTotals, 1);
19356
+ }
19357
+ let m = 1;
19358
+ for (const s of series) {
19359
+ for (const p2 of s.data) if (p2.value > m) m = p2.value;
19360
+ }
19361
+ return m;
19362
+ }, [series, stack, columnTotals]);
19363
+ return /* @__PURE__ */ jsx(
19364
+ HStack,
19365
+ {
19366
+ gap: histogram ? "none" : "xs",
19367
+ align: "end",
19368
+ className: "w-full",
19369
+ style: { height },
19370
+ children: categories.map((label, catIdx) => {
19371
+ const displayLabel = timeAxis ? formatTimeLabel(label) : label;
19372
+ if (stack === "none") {
19373
+ return /* @__PURE__ */ jsxs(
19374
+ VStack,
19375
+ {
19376
+ gap: "xs",
19377
+ align: "center",
19378
+ flex: true,
19379
+ className: "min-w-0",
19380
+ children: [
19381
+ /* @__PURE__ */ jsx(HStack, { gap: histogram ? "none" : "xs", align: "end", className: "w-full", style: { height: "100%" }, children: series.map((s, sIdx) => {
19382
+ const value = valueAt(s, label);
19383
+ const barHeight = value / maxValue * 100;
19384
+ const color = seriesColor(s, sIdx);
19385
+ return /* @__PURE__ */ jsx(
19386
+ Box,
19387
+ {
19388
+ className: cn(
19389
+ "rounded-t-sm transition-all duration-500 ease-out min-h-[4px] cursor-pointer hover:opacity-80",
19390
+ histogram ? "flex-1 mx-0" : "flex-1"
19391
+ ),
19392
+ style: {
19393
+ height: `${barHeight}%`,
19394
+ backgroundColor: color
19395
+ },
19396
+ onClick: () => onPointClick?.(
19397
+ { label, value, color },
19398
+ s.name
19399
+ ),
19400
+ title: `${s.name}: ${value}`
19401
+ },
19402
+ s.name
19403
+ );
19404
+ }) }),
19405
+ showValues && series.length === 1 && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: valueAt(series[0], label) }),
19406
+ /* @__PURE__ */ jsx(
19407
+ Typography,
19408
+ {
19409
+ variant: "caption",
19410
+ color: "secondary",
19411
+ className: "truncate w-full text-center",
19412
+ children: displayLabel
19413
+ }
19414
+ )
19415
+ ]
19416
+ },
19417
+ label
19418
+ );
19280
19419
  }
19281
- )
19282
- ] }, point.label);
19283
- }) });
19420
+ const total = columnTotals?.[catIdx] ?? 1;
19421
+ return /* @__PURE__ */ jsxs(
19422
+ VStack,
19423
+ {
19424
+ gap: "xs",
19425
+ align: "center",
19426
+ flex: true,
19427
+ className: "min-w-0",
19428
+ children: [
19429
+ /* @__PURE__ */ jsx(VStack, { gap: "none", className: "w-full", style: { height: "100%" }, justify: "end", children: series.map((s, sIdx) => {
19430
+ const value = valueAt(s, label);
19431
+ const ratio = stack === "normalize" ? total === 0 ? 0 : value / total * 100 : value / maxValue * 100;
19432
+ const color = seriesColor(s, sIdx);
19433
+ return /* @__PURE__ */ jsx(
19434
+ Box,
19435
+ {
19436
+ className: "w-full transition-all duration-500 ease-out cursor-pointer hover:opacity-80",
19437
+ style: {
19438
+ height: `${ratio}%`,
19439
+ backgroundColor: color
19440
+ },
19441
+ onClick: () => onPointClick?.(
19442
+ { label, value, color },
19443
+ s.name
19444
+ ),
19445
+ title: `${s.name}: ${value}`
19446
+ },
19447
+ s.name
19448
+ );
19449
+ }) }),
19450
+ /* @__PURE__ */ jsx(
19451
+ Typography,
19452
+ {
19453
+ variant: "caption",
19454
+ color: "secondary",
19455
+ className: "truncate w-full text-center",
19456
+ children: displayLabel
19457
+ }
19458
+ )
19459
+ ]
19460
+ },
19461
+ label
19462
+ );
19463
+ })
19464
+ }
19465
+ );
19284
19466
  };
19285
- PieChart = ({ data, height, showValues, donut = false }) => {
19467
+ PieChart = ({ data, height, showValues, donut = false, onPointClick }) => {
19286
19468
  const total = data.reduce((sum, d) => sum + d.value, 0);
19287
19469
  const size = Math.min(height, 200);
19288
19470
  const radius = size / 2 - 8;
@@ -19328,7 +19510,11 @@ var init_Chart = __esm({
19328
19510
  fill: seg.color,
19329
19511
  stroke: "var(--color-card)",
19330
19512
  strokeWidth: "2",
19331
- className: "transition-opacity duration-200 hover:opacity-80"
19513
+ className: "transition-opacity duration-200 hover:opacity-80 cursor-pointer",
19514
+ onClick: () => onPointClick?.(
19515
+ { label: seg.label, value: seg.value, color: seg.color },
19516
+ "default"
19517
+ )
19332
19518
  },
19333
19519
  idx
19334
19520
  )),
@@ -19363,56 +19549,243 @@ var init_Chart = __esm({
19363
19549
  ] }, idx)) })
19364
19550
  ] });
19365
19551
  };
19366
- LineChart = ({ data, height, showValues, fill = false }) => {
19367
- const maxValue = Math.max(...data.map((d) => d.value), 1);
19552
+ LineChart = ({ series, height, showValues, fill = false, timeAxis, onPointClick }) => {
19368
19553
  const width = 400;
19369
19554
  const padding = { top: 20, right: 20, bottom: 30, left: 40 };
19370
19555
  const chartWidth = width - padding.left - padding.right;
19371
19556
  const chartHeight = height - padding.top - padding.bottom;
19372
- const points = useMemo(() => {
19373
- return data.map((point, idx) => ({
19374
- x: padding.left + idx / Math.max(data.length - 1, 1) * chartWidth,
19375
- y: padding.top + chartHeight - point.value / maxValue * chartHeight,
19376
- ...point
19377
- }));
19378
- }, [data, maxValue, chartWidth, chartHeight, padding]);
19379
- const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
19380
- const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
19381
- return /* @__PURE__ */ jsxs("svg", { width: "100%", height, viewBox: `0 0 ${width} ${height}`, preserveAspectRatio: "xMidYMid meet", children: [
19382
- [0, 0.25, 0.5, 0.75, 1].map((frac) => {
19383
- const y = padding.top + chartHeight * (1 - frac);
19384
- return /* @__PURE__ */ jsx(
19385
- "line",
19386
- {
19387
- x1: padding.left,
19388
- y1: y,
19389
- x2: width - padding.right,
19390
- y2: y,
19391
- stroke: "var(--color-border)",
19392
- strokeDasharray: "4 4",
19393
- opacity: 0.5
19394
- },
19395
- frac
19396
- );
19397
- }),
19398
- fill && /* @__PURE__ */ jsx("path", { d: areaPath, fill: "var(--color-primary)", opacity: 0.1 }),
19399
- /* @__PURE__ */ jsx("path", { d: linePath, fill: "none", stroke: "var(--color-primary)", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
19400
- points.map((p2, idx) => /* @__PURE__ */ jsxs("g", { children: [
19401
- /* @__PURE__ */ jsx("circle", { cx: p2.x, cy: p2.y, r: "4", fill: "var(--color-card)", stroke: "var(--color-primary)", strokeWidth: "2" }),
19402
- showValues && /* @__PURE__ */ jsx("text", { x: p2.x, y: p2.y - 10, textAnchor: "middle", fill: "var(--color-foreground)", fontSize: "10", fontWeight: "500", children: p2.value }),
19403
- /* @__PURE__ */ jsx(
19404
- "text",
19405
- {
19406
- x: p2.x,
19407
- y: height - 8,
19408
- textAnchor: "middle",
19409
- fill: "var(--color-muted-foreground)",
19410
- fontSize: "9",
19411
- children: p2.label
19557
+ const labels = useMemo(() => {
19558
+ const seen = /* @__PURE__ */ new Set();
19559
+ const out = [];
19560
+ for (const s of series) {
19561
+ for (const p2 of s.data) {
19562
+ if (!seen.has(p2.label)) {
19563
+ seen.add(p2.label);
19564
+ out.push(p2.label);
19412
19565
  }
19413
- )
19414
- ] }, idx))
19415
- ] });
19566
+ }
19567
+ }
19568
+ return out;
19569
+ }, [series]);
19570
+ const maxValue = useMemo(() => {
19571
+ let m = 1;
19572
+ for (const s of series) {
19573
+ for (const p2 of s.data) if (p2.value > m) m = p2.value;
19574
+ }
19575
+ return m;
19576
+ }, [series]);
19577
+ const xFor = useCallback(
19578
+ (idx) => padding.left + idx / Math.max(labels.length - 1, 1) * chartWidth,
19579
+ [labels.length, chartWidth, padding.left]
19580
+ );
19581
+ const yFor = useCallback(
19582
+ (value) => padding.top + chartHeight - value / maxValue * chartHeight,
19583
+ [maxValue, chartHeight, padding.top]
19584
+ );
19585
+ return /* @__PURE__ */ jsxs(
19586
+ "svg",
19587
+ {
19588
+ width: "100%",
19589
+ height,
19590
+ viewBox: `0 0 ${width} ${height}`,
19591
+ preserveAspectRatio: "xMidYMid meet",
19592
+ children: [
19593
+ [0, 0.25, 0.5, 0.75, 1].map((frac) => {
19594
+ const y = padding.top + chartHeight * (1 - frac);
19595
+ return /* @__PURE__ */ jsx(
19596
+ "line",
19597
+ {
19598
+ x1: padding.left,
19599
+ y1: y,
19600
+ x2: width - padding.right,
19601
+ y2: y,
19602
+ stroke: "var(--color-border)",
19603
+ strokeDasharray: "4 4",
19604
+ opacity: 0.5
19605
+ },
19606
+ frac
19607
+ );
19608
+ }),
19609
+ series.map((s, sIdx) => {
19610
+ const color = seriesColor(s, sIdx);
19611
+ const points = labels.map((label, idx) => {
19612
+ const point = s.data.find((d) => d.label === label);
19613
+ return {
19614
+ x: xFor(idx),
19615
+ y: yFor(point ? point.value : 0),
19616
+ value: point ? point.value : 0,
19617
+ label
19618
+ };
19619
+ });
19620
+ const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
19621
+ const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
19622
+ return /* @__PURE__ */ jsxs("g", { children: [
19623
+ fill && /* @__PURE__ */ jsx(
19624
+ "path",
19625
+ {
19626
+ d: areaPath,
19627
+ fill: color,
19628
+ opacity: series.length > 1 ? 0.08 : 0.1
19629
+ }
19630
+ ),
19631
+ /* @__PURE__ */ jsx(
19632
+ "path",
19633
+ {
19634
+ d: linePath,
19635
+ fill: "none",
19636
+ stroke: color,
19637
+ strokeWidth: "2",
19638
+ strokeLinecap: "round",
19639
+ strokeLinejoin: "round",
19640
+ strokeDasharray: s.dashed ? "6 4" : void 0
19641
+ }
19642
+ ),
19643
+ points.map((p2, idx) => /* @__PURE__ */ jsxs("g", { children: [
19644
+ /* @__PURE__ */ jsx(
19645
+ "circle",
19646
+ {
19647
+ cx: p2.x,
19648
+ cy: p2.y,
19649
+ r: "4",
19650
+ fill: "var(--color-card)",
19651
+ stroke: color,
19652
+ strokeWidth: "2",
19653
+ className: "cursor-pointer",
19654
+ onClick: () => onPointClick?.(
19655
+ { label: p2.label, value: p2.value, color },
19656
+ s.name
19657
+ )
19658
+ }
19659
+ ),
19660
+ showValues && series.length === 1 && /* @__PURE__ */ jsx(
19661
+ "text",
19662
+ {
19663
+ x: p2.x,
19664
+ y: p2.y - 10,
19665
+ textAnchor: "middle",
19666
+ fill: "var(--color-foreground)",
19667
+ fontSize: "10",
19668
+ fontWeight: "500",
19669
+ children: p2.value
19670
+ }
19671
+ )
19672
+ ] }, idx))
19673
+ ] }, s.name);
19674
+ }),
19675
+ labels.map((label, idx) => /* @__PURE__ */ jsx(
19676
+ "text",
19677
+ {
19678
+ x: xFor(idx),
19679
+ y: height - 8,
19680
+ textAnchor: "middle",
19681
+ fill: "var(--color-muted-foreground)",
19682
+ fontSize: "9",
19683
+ children: timeAxis ? formatTimeLabel(label) : label
19684
+ },
19685
+ label
19686
+ ))
19687
+ ]
19688
+ }
19689
+ );
19690
+ };
19691
+ ScatterChart = ({ data, height, onPointClick }) => {
19692
+ const width = 400;
19693
+ const padding = { top: 20, right: 20, bottom: 30, left: 40 };
19694
+ const chartWidth = width - padding.left - padding.right;
19695
+ const chartHeight = height - padding.top - padding.bottom;
19696
+ const { minX, maxX, minY, maxY } = useMemo(() => {
19697
+ if (data.length === 0) {
19698
+ return { minX: 0, maxX: 1, minY: 0, maxY: 1 };
19699
+ }
19700
+ let mnX = data[0].x;
19701
+ let mxX = data[0].x;
19702
+ let mnY = data[0].y;
19703
+ let mxY = data[0].y;
19704
+ for (const p2 of data) {
19705
+ if (p2.x < mnX) mnX = p2.x;
19706
+ if (p2.x > mxX) mxX = p2.x;
19707
+ if (p2.y < mnY) mnY = p2.y;
19708
+ if (p2.y > mxY) mxY = p2.y;
19709
+ }
19710
+ return { minX: mnX, maxX: mxX, minY: mnY, maxY: mxY };
19711
+ }, [data]);
19712
+ const rangeX = maxX - minX || 1;
19713
+ const rangeY = maxY - minY || 1;
19714
+ return /* @__PURE__ */ jsxs(
19715
+ "svg",
19716
+ {
19717
+ width: "100%",
19718
+ height,
19719
+ viewBox: `0 0 ${width} ${height}`,
19720
+ preserveAspectRatio: "xMidYMid meet",
19721
+ children: [
19722
+ [0, 0.25, 0.5, 0.75, 1].map((frac) => {
19723
+ const y = padding.top + chartHeight * (1 - frac);
19724
+ return /* @__PURE__ */ jsx(
19725
+ "line",
19726
+ {
19727
+ x1: padding.left,
19728
+ y1: y,
19729
+ x2: width - padding.right,
19730
+ y2: y,
19731
+ stroke: "var(--color-border)",
19732
+ strokeDasharray: "4 4",
19733
+ opacity: 0.5
19734
+ },
19735
+ frac
19736
+ );
19737
+ }),
19738
+ data.map((p2, idx) => {
19739
+ const cx = padding.left + (p2.x - minX) / rangeX * chartWidth;
19740
+ const cy = padding.top + chartHeight - (p2.y - minY) / rangeY * chartHeight;
19741
+ const r = p2.size ?? 5;
19742
+ const color = p2.color ?? CHART_COLORS[idx % CHART_COLORS.length];
19743
+ return /* @__PURE__ */ jsx(
19744
+ "circle",
19745
+ {
19746
+ cx,
19747
+ cy,
19748
+ r,
19749
+ fill: color,
19750
+ opacity: 0.7,
19751
+ className: "cursor-pointer hover:opacity-100",
19752
+ onClick: () => onPointClick?.(
19753
+ {
19754
+ label: p2.label ?? `(${p2.x}, ${p2.y})`,
19755
+ value: p2.y,
19756
+ color
19757
+ },
19758
+ "default"
19759
+ ),
19760
+ children: /* @__PURE__ */ jsx("title", { children: p2.label ?? `(${p2.x}, ${p2.y})` })
19761
+ },
19762
+ idx
19763
+ );
19764
+ }),
19765
+ /* @__PURE__ */ jsx(
19766
+ "text",
19767
+ {
19768
+ x: padding.left,
19769
+ y: height - 8,
19770
+ fill: "var(--color-muted-foreground)",
19771
+ fontSize: "9",
19772
+ children: minX.toFixed(1)
19773
+ }
19774
+ ),
19775
+ /* @__PURE__ */ jsx(
19776
+ "text",
19777
+ {
19778
+ x: width - padding.right,
19779
+ y: height - 8,
19780
+ textAnchor: "end",
19781
+ fill: "var(--color-muted-foreground)",
19782
+ fontSize: "9",
19783
+ children: maxX.toFixed(1)
19784
+ }
19785
+ )
19786
+ ]
19787
+ }
19788
+ );
19416
19789
  };
19417
19790
  Chart = ({
19418
19791
  title,
@@ -19420,9 +19793,13 @@ var init_Chart = __esm({
19420
19793
  chartType = "bar",
19421
19794
  series,
19422
19795
  data: simpleData,
19796
+ scatterData,
19423
19797
  height = 200,
19424
19798
  showLegend = true,
19425
19799
  showValues = false,
19800
+ stack = "none",
19801
+ timeAxis = false,
19802
+ drillEvent,
19426
19803
  actions,
19427
19804
  entity,
19428
19805
  isLoading = false,
@@ -19439,11 +19816,25 @@ var init_Chart = __esm({
19439
19816
  },
19440
19817
  [eventBus]
19441
19818
  );
19442
- const normalizedData = useMemo(() => {
19443
- if (simpleData) return simpleData;
19444
- if (series && series.length > 0) return series[0].data;
19819
+ const handlePointClick = useCallback(
19820
+ (point, seriesName) => {
19821
+ if (drillEvent) {
19822
+ eventBus.emit(`UI:${drillEvent}`, {
19823
+ label: point.label,
19824
+ value: point.value,
19825
+ seriesLabel: seriesName === "default" ? void 0 : seriesName
19826
+ });
19827
+ }
19828
+ },
19829
+ [drillEvent, eventBus]
19830
+ );
19831
+ const normalizedSeries = useMemo(() => {
19832
+ if (series && series.length > 0) return series;
19833
+ if (simpleData) return [{ name: "default", data: simpleData }];
19445
19834
  return [];
19446
19835
  }, [simpleData, series]);
19836
+ const firstSeriesData = normalizedSeries[0]?.data ?? [];
19837
+ const hasContent = chartType === "scatter" ? (scatterData?.length ?? 0) > 0 : normalizedSeries.some((s) => s.data.length > 0);
19447
19838
  if (isLoading) {
19448
19839
  return /* @__PURE__ */ jsx(LoadingState, { message: "Loading chart...", className });
19449
19840
  }
@@ -19457,7 +19848,7 @@ var init_Chart = __esm({
19457
19848
  }
19458
19849
  );
19459
19850
  }
19460
- if (normalizedData.length === 0) {
19851
+ if (!hasContent) {
19461
19852
  return /* @__PURE__ */ jsx(EmptyState, { title: t("empty.noData"), description: t("empty.noData"), className });
19462
19853
  }
19463
19854
  return /* @__PURE__ */ jsx(Card, { className: cn("p-6", className), children: /* @__PURE__ */ jsxs(VStack, { gap: "md", children: [
@@ -19478,18 +19869,84 @@ var init_Chart = __esm({
19478
19869
  )) })
19479
19870
  ] }),
19480
19871
  /* @__PURE__ */ jsxs(Box, { className: "w-full", children: [
19481
- chartType === "bar" && /* @__PURE__ */ jsx(BarChart, { data: normalizedData, height, showValues }),
19482
- chartType === "line" && /* @__PURE__ */ jsx(LineChart, { data: normalizedData, height, showValues }),
19483
- chartType === "area" && /* @__PURE__ */ jsx(LineChart, { data: normalizedData, height, showValues, fill: true }),
19484
- chartType === "pie" && /* @__PURE__ */ jsx(PieChart, { data: normalizedData, height, showValues: showLegend }),
19485
- chartType === "donut" && /* @__PURE__ */ jsx(PieChart, { data: normalizedData, height, showValues: showLegend, donut: true })
19872
+ chartType === "bar" && /* @__PURE__ */ jsx(
19873
+ BarChart,
19874
+ {
19875
+ series: normalizedSeries,
19876
+ height,
19877
+ showValues,
19878
+ stack,
19879
+ timeAxis,
19880
+ onPointClick: handlePointClick
19881
+ }
19882
+ ),
19883
+ chartType === "histogram" && /* @__PURE__ */ jsx(
19884
+ BarChart,
19885
+ {
19886
+ series: normalizedSeries,
19887
+ height,
19888
+ showValues,
19889
+ stack: "none",
19890
+ timeAxis: false,
19891
+ histogram: true,
19892
+ onPointClick: handlePointClick
19893
+ }
19894
+ ),
19895
+ chartType === "line" && /* @__PURE__ */ jsx(
19896
+ LineChart,
19897
+ {
19898
+ series: normalizedSeries,
19899
+ height,
19900
+ showValues,
19901
+ timeAxis,
19902
+ onPointClick: handlePointClick
19903
+ }
19904
+ ),
19905
+ chartType === "area" && /* @__PURE__ */ jsx(
19906
+ LineChart,
19907
+ {
19908
+ series: normalizedSeries,
19909
+ height,
19910
+ showValues,
19911
+ timeAxis,
19912
+ fill: true,
19913
+ onPointClick: handlePointClick
19914
+ }
19915
+ ),
19916
+ chartType === "pie" && /* @__PURE__ */ jsx(
19917
+ PieChart,
19918
+ {
19919
+ data: firstSeriesData,
19920
+ height,
19921
+ showValues: showLegend,
19922
+ onPointClick: handlePointClick
19923
+ }
19924
+ ),
19925
+ chartType === "donut" && /* @__PURE__ */ jsx(
19926
+ PieChart,
19927
+ {
19928
+ data: firstSeriesData,
19929
+ height,
19930
+ showValues: showLegend,
19931
+ donut: true,
19932
+ onPointClick: handlePointClick
19933
+ }
19934
+ ),
19935
+ chartType === "scatter" && /* @__PURE__ */ jsx(
19936
+ ScatterChart,
19937
+ {
19938
+ data: scatterData ?? [],
19939
+ height,
19940
+ onPointClick: handlePointClick
19941
+ }
19942
+ )
19486
19943
  ] }),
19487
- 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: [
19944
+ 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: [
19488
19945
  /* @__PURE__ */ jsx(
19489
19946
  Box,
19490
19947
  {
19491
19948
  className: "w-3 h-3 rounded-full flex-shrink-0",
19492
- style: { backgroundColor: s.color || CHART_COLORS[idx % CHART_COLORS.length] }
19949
+ style: { backgroundColor: seriesColor(s, idx) }
19493
19950
  }
19494
19951
  ),
19495
19952
  /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: s.name })
@@ -21350,7 +21807,6 @@ function useDataDnd(args) {
21350
21807
  const raw = it[dndItemIdField];
21351
21808
  return raw ?? `__idx_${idx}`;
21352
21809
  }),
21353
- // eslint-disable-next-line react-hooks/exhaustive-deps
21354
21810
  [itemIdsSignature]
21355
21811
  );
21356
21812
  const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
@@ -22944,7 +23400,16 @@ var init_FilterGroup = __esm({
22944
23400
  onClear: () => handleFilterSelect(`${filter.field}_to`, null)
22945
23401
  }
22946
23402
  )
22947
- ] }) : /* @__PURE__ */ jsx(
23403
+ ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
23404
+ Input,
23405
+ {
23406
+ value: selectedValues[filter.field] || "",
23407
+ onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
23408
+ placeholder: filter.label,
23409
+ clearable: true,
23410
+ onClear: () => handleFilterSelect(filter.field, null)
23411
+ }
23412
+ ) : /* @__PURE__ */ jsx(
22948
23413
  Select,
22949
23414
  {
22950
23415
  value: selectedValues[filter.field] || "all",
@@ -23011,7 +23476,17 @@ var init_FilterGroup = __esm({
23011
23476
  className: "text-sm min-w-[100px]"
23012
23477
  }
23013
23478
  )
23014
- ] }) : /* @__PURE__ */ jsx(
23479
+ ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
23480
+ Input,
23481
+ {
23482
+ value: selectedValues[filter.field] || "",
23483
+ onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
23484
+ placeholder: filter.label,
23485
+ clearable: true,
23486
+ onClear: () => handleFilterSelect(filter.field, null),
23487
+ className: "text-sm"
23488
+ }
23489
+ ) : /* @__PURE__ */ jsx(
23015
23490
  Select,
23016
23491
  {
23017
23492
  value: selectedValues[filter.field] || "all",
@@ -23116,7 +23591,17 @@ var init_FilterGroup = __esm({
23116
23591
  className: "min-w-[130px]"
23117
23592
  }
23118
23593
  )
23119
- ] }) : /* @__PURE__ */ jsx(
23594
+ ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
23595
+ Input,
23596
+ {
23597
+ value: selectedValues[filter.field] || "",
23598
+ onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
23599
+ placeholder: filter.label,
23600
+ clearable: true,
23601
+ onClear: () => handleFilterSelect(filter.field, null),
23602
+ className: "min-w-[160px]"
23603
+ }
23604
+ ) : /* @__PURE__ */ jsx(
23120
23605
  Select,
23121
23606
  {
23122
23607
  value: selectedValues[filter.field] || "all",
@@ -24405,6 +24890,151 @@ var init_FlipCard = __esm({
24405
24890
  FlipCard.displayName = "FlipCard";
24406
24891
  }
24407
24892
  });
24893
+ function toISODate(d) {
24894
+ return d.toISOString().slice(0, 10);
24895
+ }
24896
+ function startOfMonth(d) {
24897
+ return new Date(d.getFullYear(), d.getMonth(), 1);
24898
+ }
24899
+ function startOfQuarter(d) {
24900
+ return new Date(d.getFullYear(), Math.floor(d.getMonth() / 3) * 3, 1);
24901
+ }
24902
+ function startOfYear(d) {
24903
+ return new Date(d.getFullYear(), 0, 1);
24904
+ }
24905
+ function daysAgo(n) {
24906
+ const d = /* @__PURE__ */ new Date();
24907
+ d.setDate(d.getDate() - n);
24908
+ return d;
24909
+ }
24910
+ var DEFAULT_PRESETS, DateRangePicker;
24911
+ var init_DateRangePicker = __esm({
24912
+ "components/molecules/DateRangePicker.tsx"() {
24913
+ "use client";
24914
+ init_cn();
24915
+ init_Button();
24916
+ init_Input();
24917
+ init_Stack();
24918
+ init_Typography();
24919
+ init_useEventBus();
24920
+ DEFAULT_PRESETS = [
24921
+ {
24922
+ label: "Last 7 days",
24923
+ value: "7d",
24924
+ range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
24925
+ },
24926
+ {
24927
+ label: "Last 30 days",
24928
+ value: "30d",
24929
+ range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
24930
+ },
24931
+ {
24932
+ label: "This Month",
24933
+ value: "month",
24934
+ range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
24935
+ },
24936
+ {
24937
+ label: "This Quarter",
24938
+ value: "quarter",
24939
+ range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
24940
+ },
24941
+ {
24942
+ label: "YTD",
24943
+ value: "ytd",
24944
+ range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
24945
+ }
24946
+ ];
24947
+ DateRangePicker = ({
24948
+ from: fromProp,
24949
+ to: toProp,
24950
+ event,
24951
+ onChange,
24952
+ presets = DEFAULT_PRESETS,
24953
+ fromLabel = "From",
24954
+ toLabel = "To",
24955
+ className
24956
+ }) => {
24957
+ const eventBus = useEventBus();
24958
+ const [from, setFrom] = useState(fromProp ?? "");
24959
+ const [to, setTo] = useState(toProp ?? "");
24960
+ const [activePreset, setActivePreset] = useState(null);
24961
+ const emit = useCallback(
24962
+ (range) => {
24963
+ onChange?.(range);
24964
+ if (event) eventBus.emit(`UI:${event}`, range);
24965
+ },
24966
+ [onChange, event, eventBus]
24967
+ );
24968
+ const handleFromChange = useCallback(
24969
+ (next) => {
24970
+ setFrom(next);
24971
+ setActivePreset(null);
24972
+ emit({ from: next, to });
24973
+ },
24974
+ [to, emit]
24975
+ );
24976
+ const handleToChange = useCallback(
24977
+ (next) => {
24978
+ setTo(next);
24979
+ setActivePreset(null);
24980
+ emit({ from, to: next });
24981
+ },
24982
+ [from, emit]
24983
+ );
24984
+ const handlePreset = useCallback(
24985
+ (preset) => {
24986
+ const range = preset.range();
24987
+ setFrom(range.from);
24988
+ setTo(range.to);
24989
+ setActivePreset(preset.value);
24990
+ emit(range);
24991
+ },
24992
+ [emit]
24993
+ );
24994
+ const presetButtons = useMemo(
24995
+ () => presets.map((preset) => /* @__PURE__ */ jsx(
24996
+ Button,
24997
+ {
24998
+ variant: activePreset === preset.value ? "primary" : "ghost",
24999
+ size: "sm",
25000
+ onClick: () => handlePreset(preset),
25001
+ children: preset.label
25002
+ },
25003
+ preset.value
25004
+ )),
25005
+ [presets, activePreset, handlePreset]
25006
+ );
25007
+ return /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: cn(className), children: [
25008
+ /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "end", children: [
25009
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
25010
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: fromLabel }),
25011
+ /* @__PURE__ */ jsx(
25012
+ Input,
25013
+ {
25014
+ type: "date",
25015
+ value: from,
25016
+ onChange: (e) => handleFromChange(e.target.value)
25017
+ }
25018
+ )
25019
+ ] }),
25020
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
25021
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: toLabel }),
25022
+ /* @__PURE__ */ jsx(
25023
+ Input,
25024
+ {
25025
+ type: "date",
25026
+ value: to,
25027
+ onChange: (e) => handleToChange(e.target.value)
25028
+ }
25029
+ )
25030
+ ] })
25031
+ ] }),
25032
+ presets.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
25033
+ ] });
25034
+ };
25035
+ DateRangePicker.displayName = "DateRangePicker";
25036
+ }
25037
+ });
24408
25038
  var DEFAULT_OPTIONS, DateRangeSelector;
24409
25039
  var init_DateRangeSelector = __esm({
24410
25040
  "components/molecules/DateRangeSelector.tsx"() {
@@ -27376,7 +28006,9 @@ var init_StatDisplay = __esm({
27376
28006
  init_Typography();
27377
28007
  init_Box();
27378
28008
  init_Stack();
28009
+ init_Sparkline();
27379
28010
  init_Icon();
28011
+ init_useEventBus();
27380
28012
  variantColor = {
27381
28013
  default: "text-foreground",
27382
28014
  primary: "text-primary",
@@ -27391,6 +28023,10 @@ var init_StatDisplay = __esm({
27391
28023
  max,
27392
28024
  target,
27393
28025
  trend,
28026
+ trendPolarity = "higher-is-better",
28027
+ trendFormat = "absolute",
28028
+ sparklineData,
28029
+ clickEvent,
27394
28030
  prefix,
27395
28031
  suffix,
27396
28032
  icon: iconProp,
@@ -27404,6 +28040,10 @@ var init_StatDisplay = __esm({
27404
28040
  isLoading = false,
27405
28041
  error = null
27406
28042
  }) => {
28043
+ const eventBus = useEventBus();
28044
+ const handleClick = useCallback(() => {
28045
+ if (clickEvent) eventBus.emit(`UI:${clickEvent}`, { metricLabel: label });
28046
+ }, [clickEvent, eventBus, label]);
27407
28047
  const ResolvedIcon = typeof iconProp === "string" ? resolveIcon(iconProp) : null;
27408
28048
  const iconSizes3 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
27409
28049
  const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
@@ -27414,7 +28054,10 @@ var init_StatDisplay = __esm({
27414
28054
  const targetPct = showTarget ? Math.max(0, Math.min(100, numericValue / target * 100)) : 0;
27415
28055
  const showTrend = typeof trend === "number" && trend !== 0 && Number.isFinite(trend);
27416
28056
  const trendUp = showTrend && trend > 0;
27417
- const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${Math.abs(trend)}` : "";
28057
+ const trendIsGood = trendPolarity === "lower-is-better" ? !trendUp : trendUp;
28058
+ const trendMagnitude = Math.abs(trend);
28059
+ const trendSuffix = trendFormat === "percent" ? "%" : "";
28060
+ const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${trendMagnitude}${trendSuffix}` : "";
27418
28061
  if (error) {
27419
28062
  return /* @__PURE__ */ jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsx(Typography, { variant: "small", color: "error", children: error.message }) });
27420
28063
  }
@@ -27425,38 +28068,57 @@ var init_StatDisplay = __esm({
27425
28068
  ] }) });
27426
28069
  }
27427
28070
  if (compact) {
27428
- return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: cn("items-center", className), children: [
27429
- ResolvedIcon && /* @__PURE__ */ jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
27430
- typeof iconProp !== "string" && iconProp,
27431
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: label }),
27432
- /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
27433
- showTrend && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: cn("font-semibold", trendUp ? "text-success" : "text-error"), children: trendLabel })
27434
- ] });
28071
+ return /* @__PURE__ */ jsxs(
28072
+ HStack,
28073
+ {
28074
+ gap: "sm",
28075
+ className: cn("items-center", clickEvent && "cursor-pointer hover:opacity-80", className),
28076
+ onClick: clickEvent ? handleClick : void 0,
28077
+ children: [
28078
+ ResolvedIcon && /* @__PURE__ */ jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
28079
+ typeof iconProp !== "string" && iconProp,
28080
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: label }),
28081
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
28082
+ showTrend && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: cn("font-semibold", trendIsGood ? "text-success" : "text-error"), children: trendLabel }),
28083
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto", width: 60, height: 20 })
28084
+ ]
28085
+ }
28086
+ );
27435
28087
  }
27436
- return /* @__PURE__ */ jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxs(HStack, { align: "start", justify: "between", children: [
27437
- /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
27438
- /* @__PURE__ */ jsx(Typography, { variant: "overline", color: "secondary", children: label }),
27439
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "end", children: [
27440
- /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
27441
- showTrend && /* @__PURE__ */ jsx(
27442
- Typography,
27443
- {
27444
- variant: "caption",
27445
- className: cn("font-semibold pb-1", trendUp ? "text-success" : "text-error"),
27446
- children: trendLabel
27447
- }
27448
- )
27449
- ] }),
27450
- showTarget && /* @__PURE__ */ jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
27451
- Box,
27452
- {
27453
- className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
27454
- style: { width: `${targetPct}%` }
27455
- }
27456
- ) })
27457
- ] }),
27458
- (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 })
27459
- ] }) });
28088
+ return /* @__PURE__ */ jsx(
28089
+ Card,
28090
+ {
28091
+ className: cn(padSizes[size], clickEvent && "cursor-pointer hover:shadow-md transition-shadow", className),
28092
+ onClick: clickEvent ? handleClick : void 0,
28093
+ children: /* @__PURE__ */ jsxs(HStack, { align: "start", justify: "between", children: [
28094
+ /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
28095
+ /* @__PURE__ */ jsx(Typography, { variant: "overline", color: "secondary", children: label }),
28096
+ /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "end", children: [
28097
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
28098
+ showTrend && /* @__PURE__ */ jsx(
28099
+ Typography,
28100
+ {
28101
+ variant: "caption",
28102
+ className: cn("font-semibold pb-1", trendIsGood ? "text-success" : "text-error"),
28103
+ children: trendLabel
28104
+ }
28105
+ )
28106
+ ] }),
28107
+ showTarget && /* @__PURE__ */ jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
28108
+ Box,
28109
+ {
28110
+ className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
28111
+ style: { width: `${targetPct}%` }
28112
+ }
28113
+ ) })
28114
+ ] }),
28115
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
28116
+ (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 }),
28117
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto" })
28118
+ ] })
28119
+ ] })
28120
+ }
28121
+ );
27460
28122
  };
27461
28123
  StatDisplay.displayName = "StatDisplay";
27462
28124
  }
@@ -41919,6 +42581,7 @@ var init_StatCard = __esm({
41919
42581
  init_Box();
41920
42582
  init_Stack();
41921
42583
  init_Button();
42584
+ init_Sparkline();
41922
42585
  init_useEventBus();
41923
42586
  init_useTranslate();
41924
42587
  init_Icon();
@@ -42088,32 +42751,7 @@ var init_StatCard = __esm({
42088
42751
  ] }),
42089
42752
  /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
42090
42753
  Icon3 && /* @__PURE__ */ jsx(Box, { className: cn("p-3", iconBg), children: /* @__PURE__ */ jsx(Icon3, { className: cn("h-6 w-6", iconColor) }) }),
42091
- sparklineData && sparklineData.length > 1 && (() => {
42092
- const w = 80;
42093
- const h = 32;
42094
- const pad = 2;
42095
- const min = Math.min(...sparklineData);
42096
- const max = Math.max(...sparklineData);
42097
- const range = max - min || 1;
42098
- const points = sparklineData.map((v, i) => {
42099
- const x = pad + i / (sparklineData.length - 1) * (w - pad * 2);
42100
- const y = pad + (1 - (v - min) / range) * (h - pad * 2);
42101
- return `${x},${y}`;
42102
- }).join(" ");
42103
- const trending = sparklineData[sparklineData.length - 1] >= sparklineData[0];
42104
- const strokeColor = trending ? "var(--color-success)" : "var(--color-error)";
42105
- return /* @__PURE__ */ jsx("svg", { width: w, height: h, viewBox: `0 0 ${w} ${h}`, className: "flex-shrink-0", children: /* @__PURE__ */ jsx(
42106
- "polyline",
42107
- {
42108
- fill: "none",
42109
- stroke: strokeColor,
42110
- strokeWidth: "2",
42111
- strokeLinecap: "round",
42112
- strokeLinejoin: "round",
42113
- points
42114
- }
42115
- ) });
42116
- })()
42754
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto" })
42117
42755
  ] })
42118
42756
  ] }),
42119
42757
  action && /* @__PURE__ */ jsxs(
@@ -44011,6 +44649,7 @@ var init_component_registry_generated = __esm({
44011
44649
  init_DataGrid();
44012
44650
  init_DataList();
44013
44651
  init_DataTable();
44652
+ init_DateRangePicker();
44014
44653
  init_DateRangeSelector();
44015
44654
  init_DayCell();
44016
44655
  init_DebuggerBoard();
@@ -44143,6 +44782,7 @@ var init_component_registry_generated = __esm({
44143
44782
  init_Skeleton();
44144
44783
  init_SocialProof();
44145
44784
  init_SortableList();
44785
+ init_Sparkline();
44146
44786
  init_Split();
44147
44787
  init_SplitPane();
44148
44788
  init_SplitSection();
@@ -44291,6 +44931,7 @@ var init_component_registry_generated = __esm({
44291
44931
  "DataGrid": DataGrid,
44292
44932
  "DataList": DataList,
44293
44933
  "DataTable": DataTable,
44934
+ "DateRangePicker": DateRangePicker,
44294
44935
  "DateRangeSelector": DateRangeSelector,
44295
44936
  "DayCell": DayCell,
44296
44937
  "DebuggerBoard": DebuggerBoard,
@@ -44452,6 +45093,7 @@ var init_component_registry_generated = __esm({
44452
45093
  "SortableList": SortableList,
44453
45094
  "Spacer": SpacerPattern,
44454
45095
  "SpacerPattern": SpacerPattern,
45096
+ "Sparkline": Sparkline,
44455
45097
  "Spinner": SpinnerPattern,
44456
45098
  "SpinnerPattern": SpinnerPattern,
44457
45099
  "Split": Split,