@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.
@@ -3649,6 +3649,67 @@ var init_Radio = __esm({
3649
3649
  Radio.displayName = "Radio";
3650
3650
  }
3651
3651
  });
3652
+ var COLOR_VAR, Sparkline;
3653
+ var init_Sparkline = __esm({
3654
+ "components/atoms/Sparkline.tsx"() {
3655
+ init_cn();
3656
+ COLOR_VAR = {
3657
+ primary: "var(--color-primary)",
3658
+ success: "var(--color-success)",
3659
+ warning: "var(--color-warning)",
3660
+ error: "var(--color-error)",
3661
+ info: "var(--color-info)",
3662
+ muted: "var(--color-muted-foreground)"
3663
+ };
3664
+ Sparkline = ({
3665
+ data,
3666
+ color = "auto",
3667
+ width = 80,
3668
+ height = 32,
3669
+ strokeWidth = 2,
3670
+ fill = false,
3671
+ className
3672
+ }) => {
3673
+ if (data.length < 2) return null;
3674
+ const pad = 2;
3675
+ const min = Math.min(...data);
3676
+ const max = Math.max(...data);
3677
+ const range = max - min || 1;
3678
+ const points = data.map((v, i) => {
3679
+ const x = pad + i / (data.length - 1) * (width - pad * 2);
3680
+ const y = pad + (1 - (v - min) / range) * (height - pad * 2);
3681
+ return `${x},${y}`;
3682
+ }).join(" ");
3683
+ const resolvedColor = color === "auto" ? data[data.length - 1] >= data[0] ? COLOR_VAR.success : COLOR_VAR.error : COLOR_VAR[color];
3684
+ const areaPath = fill ? `M ${pad},${height - pad} L ${points.split(" ").join(" L ")} L ${width - pad},${height - pad} Z` : null;
3685
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3686
+ "svg",
3687
+ {
3688
+ width,
3689
+ height,
3690
+ viewBox: `0 0 ${width} ${height}`,
3691
+ className: cn("flex-shrink-0", className),
3692
+ "aria-hidden": "true",
3693
+ children: [
3694
+ areaPath && /* @__PURE__ */ jsxRuntime.jsx("path", { d: areaPath, fill: resolvedColor, opacity: 0.15 }),
3695
+ /* @__PURE__ */ jsxRuntime.jsx(
3696
+ "polyline",
3697
+ {
3698
+ fill: "none",
3699
+ stroke: resolvedColor,
3700
+ strokeWidth,
3701
+ strokeLinecap: "round",
3702
+ strokeLinejoin: "round",
3703
+ points
3704
+ }
3705
+ )
3706
+ ]
3707
+ }
3708
+ );
3709
+ };
3710
+ Sparkline.displayName = "Sparkline";
3711
+ }
3712
+ });
3652
3713
  var Switch;
3653
3714
  var init_Switch = __esm({
3654
3715
  "components/atoms/Switch.tsx"() {
@@ -9322,7 +9383,7 @@ var init_MapView = __esm({
9322
9383
  shadowSize: [41, 41]
9323
9384
  });
9324
9385
  L.Marker.prototype.options.icon = defaultIcon;
9325
- const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback110, useState: useState95 } = React81__namespace.default;
9386
+ const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback112, useState: useState96 } = React81__namespace.default;
9326
9387
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
9327
9388
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
9328
9389
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -9367,8 +9428,8 @@ var init_MapView = __esm({
9367
9428
  showAttribution = true
9368
9429
  }) {
9369
9430
  const eventBus = useEventBus2();
9370
- const [clickedPosition, setClickedPosition] = useState95(null);
9371
- const handleMapClick = useCallback110((lat, lng) => {
9431
+ const [clickedPosition, setClickedPosition] = useState96(null);
9432
+ const handleMapClick = useCallback112((lat, lng) => {
9372
9433
  if (showClickedPin) {
9373
9434
  setClickedPosition({ lat, lng });
9374
9435
  }
@@ -9377,7 +9438,7 @@ var init_MapView = __esm({
9377
9438
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
9378
9439
  }
9379
9440
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
9380
- const handleMarkerClick = useCallback110((marker) => {
9441
+ const handleMarkerClick = useCallback112((marker) => {
9381
9442
  onMarkerClick?.(marker);
9382
9443
  if (markerClickEvent) {
9383
9444
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -19277,7 +19338,7 @@ var init_CastleTemplate = __esm({
19277
19338
  CastleTemplate.displayName = "CastleTemplate";
19278
19339
  }
19279
19340
  });
19280
- var CHART_COLORS, BarChart, PieChart, LineChart, Chart;
19341
+ var CHART_COLORS, seriesColor, monthFormatter, formatTimeLabel, BarChart, PieChart, LineChart, ScatterChart, Chart;
19281
19342
  var init_Chart = __esm({
19282
19343
  "components/organisms/Chart.tsx"() {
19283
19344
  "use client";
@@ -19297,38 +19358,159 @@ var init_Chart = __esm({
19297
19358
  "var(--color-info)",
19298
19359
  "var(--color-accent)"
19299
19360
  ];
19300
- BarChart = ({ data, height, showValues }) => {
19301
- const maxValue = Math.max(...data.map((d) => d.value), 1);
19302
- return /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", align: "end", className: "w-full", style: { height }, children: data.map((point, idx) => {
19303
- const barHeight = point.value / maxValue * 100;
19304
- const color = point.color || CHART_COLORS[idx % CHART_COLORS.length];
19305
- return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "center", flex: true, className: "min-w-0", children: [
19306
- showValues && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: point.value }),
19307
- /* @__PURE__ */ jsxRuntime.jsx(
19308
- Box,
19309
- {
19310
- className: cn(
19311
- "w-full rounded-t-sm transition-all duration-500 ease-out min-h-[4px]"
19312
- ),
19313
- style: {
19314
- height: `${barHeight}%`,
19315
- backgroundColor: color
19316
- }
19361
+ seriesColor = (series, idx) => series.color ?? CHART_COLORS[idx % CHART_COLORS.length];
19362
+ monthFormatter = new Intl.DateTimeFormat(void 0, {
19363
+ month: "short",
19364
+ year: "2-digit"
19365
+ });
19366
+ formatTimeLabel = (raw) => {
19367
+ const parsed = new Date(raw);
19368
+ if (Number.isNaN(parsed.getTime())) return raw;
19369
+ return monthFormatter.format(parsed);
19370
+ };
19371
+ BarChart = ({ series, height, showValues, stack, timeAxis, histogram = false, onPointClick }) => {
19372
+ const categories = React81.useMemo(() => {
19373
+ const set = [];
19374
+ const seen = /* @__PURE__ */ new Set();
19375
+ for (const s of series) {
19376
+ for (const p2 of s.data) {
19377
+ if (!seen.has(p2.label)) {
19378
+ seen.add(p2.label);
19379
+ set.push(p2.label);
19317
19380
  }
19318
- ),
19319
- /* @__PURE__ */ jsxRuntime.jsx(
19320
- Typography,
19321
- {
19322
- variant: "caption",
19323
- color: "secondary",
19324
- className: "truncate w-full text-center",
19325
- children: point.label
19381
+ }
19382
+ }
19383
+ return set;
19384
+ }, [series]);
19385
+ const valueAt = React81.useCallback(
19386
+ (s, label) => {
19387
+ const p2 = s.data.find((d) => d.label === label);
19388
+ return p2 ? p2.value : 0;
19389
+ },
19390
+ []
19391
+ );
19392
+ const columnTotals = React81.useMemo(() => {
19393
+ if (stack === "none") return null;
19394
+ return categories.map(
19395
+ (label) => series.reduce((sum, s) => sum + valueAt(s, label), 0)
19396
+ );
19397
+ }, [categories, series, stack, valueAt]);
19398
+ const maxValue = React81.useMemo(() => {
19399
+ if (stack === "normalize") return 100;
19400
+ if (stack === "stack" && columnTotals) {
19401
+ return Math.max(...columnTotals, 1);
19402
+ }
19403
+ let m = 1;
19404
+ for (const s of series) {
19405
+ for (const p2 of s.data) if (p2.value > m) m = p2.value;
19406
+ }
19407
+ return m;
19408
+ }, [series, stack, columnTotals]);
19409
+ return /* @__PURE__ */ jsxRuntime.jsx(
19410
+ HStack,
19411
+ {
19412
+ gap: histogram ? "none" : "xs",
19413
+ align: "end",
19414
+ className: "w-full",
19415
+ style: { height },
19416
+ children: categories.map((label, catIdx) => {
19417
+ const displayLabel = timeAxis ? formatTimeLabel(label) : label;
19418
+ if (stack === "none") {
19419
+ return /* @__PURE__ */ jsxRuntime.jsxs(
19420
+ VStack,
19421
+ {
19422
+ gap: "xs",
19423
+ align: "center",
19424
+ flex: true,
19425
+ className: "min-w-0",
19426
+ children: [
19427
+ /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: histogram ? "none" : "xs", align: "end", className: "w-full", style: { height: "100%" }, children: series.map((s, sIdx) => {
19428
+ const value = valueAt(s, label);
19429
+ const barHeight = value / maxValue * 100;
19430
+ const color = seriesColor(s, sIdx);
19431
+ return /* @__PURE__ */ jsxRuntime.jsx(
19432
+ Box,
19433
+ {
19434
+ className: cn(
19435
+ "rounded-t-sm transition-all duration-500 ease-out min-h-[4px] cursor-pointer hover:opacity-80",
19436
+ histogram ? "flex-1 mx-0" : "flex-1"
19437
+ ),
19438
+ style: {
19439
+ height: `${barHeight}%`,
19440
+ backgroundColor: color
19441
+ },
19442
+ onClick: () => onPointClick?.(
19443
+ { label, value, color },
19444
+ s.name
19445
+ ),
19446
+ title: `${s.name}: ${value}`
19447
+ },
19448
+ s.name
19449
+ );
19450
+ }) }),
19451
+ showValues && series.length === 1 && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: valueAt(series[0], label) }),
19452
+ /* @__PURE__ */ jsxRuntime.jsx(
19453
+ Typography,
19454
+ {
19455
+ variant: "caption",
19456
+ color: "secondary",
19457
+ className: "truncate w-full text-center",
19458
+ children: displayLabel
19459
+ }
19460
+ )
19461
+ ]
19462
+ },
19463
+ label
19464
+ );
19326
19465
  }
19327
- )
19328
- ] }, point.label);
19329
- }) });
19466
+ const total = columnTotals?.[catIdx] ?? 1;
19467
+ return /* @__PURE__ */ jsxRuntime.jsxs(
19468
+ VStack,
19469
+ {
19470
+ gap: "xs",
19471
+ align: "center",
19472
+ flex: true,
19473
+ className: "min-w-0",
19474
+ children: [
19475
+ /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "none", className: "w-full", style: { height: "100%" }, justify: "end", children: series.map((s, sIdx) => {
19476
+ const value = valueAt(s, label);
19477
+ const ratio = stack === "normalize" ? total === 0 ? 0 : value / total * 100 : value / maxValue * 100;
19478
+ const color = seriesColor(s, sIdx);
19479
+ return /* @__PURE__ */ jsxRuntime.jsx(
19480
+ Box,
19481
+ {
19482
+ className: "w-full transition-all duration-500 ease-out cursor-pointer hover:opacity-80",
19483
+ style: {
19484
+ height: `${ratio}%`,
19485
+ backgroundColor: color
19486
+ },
19487
+ onClick: () => onPointClick?.(
19488
+ { label, value, color },
19489
+ s.name
19490
+ ),
19491
+ title: `${s.name}: ${value}`
19492
+ },
19493
+ s.name
19494
+ );
19495
+ }) }),
19496
+ /* @__PURE__ */ jsxRuntime.jsx(
19497
+ Typography,
19498
+ {
19499
+ variant: "caption",
19500
+ color: "secondary",
19501
+ className: "truncate w-full text-center",
19502
+ children: displayLabel
19503
+ }
19504
+ )
19505
+ ]
19506
+ },
19507
+ label
19508
+ );
19509
+ })
19510
+ }
19511
+ );
19330
19512
  };
19331
- PieChart = ({ data, height, showValues, donut = false }) => {
19513
+ PieChart = ({ data, height, showValues, donut = false, onPointClick }) => {
19332
19514
  const total = data.reduce((sum, d) => sum + d.value, 0);
19333
19515
  const size = Math.min(height, 200);
19334
19516
  const radius = size / 2 - 8;
@@ -19374,7 +19556,11 @@ var init_Chart = __esm({
19374
19556
  fill: seg.color,
19375
19557
  stroke: "var(--color-card)",
19376
19558
  strokeWidth: "2",
19377
- className: "transition-opacity duration-200 hover:opacity-80"
19559
+ className: "transition-opacity duration-200 hover:opacity-80 cursor-pointer",
19560
+ onClick: () => onPointClick?.(
19561
+ { label: seg.label, value: seg.value, color: seg.color },
19562
+ "default"
19563
+ )
19378
19564
  },
19379
19565
  idx
19380
19566
  )),
@@ -19409,56 +19595,243 @@ var init_Chart = __esm({
19409
19595
  ] }, idx)) })
19410
19596
  ] });
19411
19597
  };
19412
- LineChart = ({ data, height, showValues, fill = false }) => {
19413
- const maxValue = Math.max(...data.map((d) => d.value), 1);
19598
+ LineChart = ({ series, height, showValues, fill = false, timeAxis, onPointClick }) => {
19414
19599
  const width = 400;
19415
19600
  const padding = { top: 20, right: 20, bottom: 30, left: 40 };
19416
19601
  const chartWidth = width - padding.left - padding.right;
19417
19602
  const chartHeight = height - padding.top - padding.bottom;
19418
- const points = React81.useMemo(() => {
19419
- return data.map((point, idx) => ({
19420
- x: padding.left + idx / Math.max(data.length - 1, 1) * chartWidth,
19421
- y: padding.top + chartHeight - point.value / maxValue * chartHeight,
19422
- ...point
19423
- }));
19424
- }, [data, maxValue, chartWidth, chartHeight, padding]);
19425
- const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
19426
- const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
19427
- return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "100%", height, viewBox: `0 0 ${width} ${height}`, preserveAspectRatio: "xMidYMid meet", children: [
19428
- [0, 0.25, 0.5, 0.75, 1].map((frac) => {
19429
- const y = padding.top + chartHeight * (1 - frac);
19430
- return /* @__PURE__ */ jsxRuntime.jsx(
19431
- "line",
19432
- {
19433
- x1: padding.left,
19434
- y1: y,
19435
- x2: width - padding.right,
19436
- y2: y,
19437
- stroke: "var(--color-border)",
19438
- strokeDasharray: "4 4",
19439
- opacity: 0.5
19440
- },
19441
- frac
19442
- );
19443
- }),
19444
- fill && /* @__PURE__ */ jsxRuntime.jsx("path", { d: areaPath, fill: "var(--color-primary)", opacity: 0.1 }),
19445
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: linePath, fill: "none", stroke: "var(--color-primary)", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
19446
- points.map((p2, idx) => /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
19447
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: p2.x, cy: p2.y, r: "4", fill: "var(--color-card)", stroke: "var(--color-primary)", strokeWidth: "2" }),
19448
- 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 }),
19449
- /* @__PURE__ */ jsxRuntime.jsx(
19450
- "text",
19451
- {
19452
- x: p2.x,
19453
- y: height - 8,
19454
- textAnchor: "middle",
19455
- fill: "var(--color-muted-foreground)",
19456
- fontSize: "9",
19457
- children: p2.label
19603
+ const labels = React81.useMemo(() => {
19604
+ const seen = /* @__PURE__ */ new Set();
19605
+ const out = [];
19606
+ for (const s of series) {
19607
+ for (const p2 of s.data) {
19608
+ if (!seen.has(p2.label)) {
19609
+ seen.add(p2.label);
19610
+ out.push(p2.label);
19458
19611
  }
19459
- )
19460
- ] }, idx))
19461
- ] });
19612
+ }
19613
+ }
19614
+ return out;
19615
+ }, [series]);
19616
+ const maxValue = React81.useMemo(() => {
19617
+ let m = 1;
19618
+ for (const s of series) {
19619
+ for (const p2 of s.data) if (p2.value > m) m = p2.value;
19620
+ }
19621
+ return m;
19622
+ }, [series]);
19623
+ const xFor = React81.useCallback(
19624
+ (idx) => padding.left + idx / Math.max(labels.length - 1, 1) * chartWidth,
19625
+ [labels.length, chartWidth, padding.left]
19626
+ );
19627
+ const yFor = React81.useCallback(
19628
+ (value) => padding.top + chartHeight - value / maxValue * chartHeight,
19629
+ [maxValue, chartHeight, padding.top]
19630
+ );
19631
+ return /* @__PURE__ */ jsxRuntime.jsxs(
19632
+ "svg",
19633
+ {
19634
+ width: "100%",
19635
+ height,
19636
+ viewBox: `0 0 ${width} ${height}`,
19637
+ preserveAspectRatio: "xMidYMid meet",
19638
+ children: [
19639
+ [0, 0.25, 0.5, 0.75, 1].map((frac) => {
19640
+ const y = padding.top + chartHeight * (1 - frac);
19641
+ return /* @__PURE__ */ jsxRuntime.jsx(
19642
+ "line",
19643
+ {
19644
+ x1: padding.left,
19645
+ y1: y,
19646
+ x2: width - padding.right,
19647
+ y2: y,
19648
+ stroke: "var(--color-border)",
19649
+ strokeDasharray: "4 4",
19650
+ opacity: 0.5
19651
+ },
19652
+ frac
19653
+ );
19654
+ }),
19655
+ series.map((s, sIdx) => {
19656
+ const color = seriesColor(s, sIdx);
19657
+ const points = labels.map((label, idx) => {
19658
+ const point = s.data.find((d) => d.label === label);
19659
+ return {
19660
+ x: xFor(idx),
19661
+ y: yFor(point ? point.value : 0),
19662
+ value: point ? point.value : 0,
19663
+ label
19664
+ };
19665
+ });
19666
+ const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
19667
+ const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
19668
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
19669
+ fill && /* @__PURE__ */ jsxRuntime.jsx(
19670
+ "path",
19671
+ {
19672
+ d: areaPath,
19673
+ fill: color,
19674
+ opacity: series.length > 1 ? 0.08 : 0.1
19675
+ }
19676
+ ),
19677
+ /* @__PURE__ */ jsxRuntime.jsx(
19678
+ "path",
19679
+ {
19680
+ d: linePath,
19681
+ fill: "none",
19682
+ stroke: color,
19683
+ strokeWidth: "2",
19684
+ strokeLinecap: "round",
19685
+ strokeLinejoin: "round",
19686
+ strokeDasharray: s.dashed ? "6 4" : void 0
19687
+ }
19688
+ ),
19689
+ points.map((p2, idx) => /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
19690
+ /* @__PURE__ */ jsxRuntime.jsx(
19691
+ "circle",
19692
+ {
19693
+ cx: p2.x,
19694
+ cy: p2.y,
19695
+ r: "4",
19696
+ fill: "var(--color-card)",
19697
+ stroke: color,
19698
+ strokeWidth: "2",
19699
+ className: "cursor-pointer",
19700
+ onClick: () => onPointClick?.(
19701
+ { label: p2.label, value: p2.value, color },
19702
+ s.name
19703
+ )
19704
+ }
19705
+ ),
19706
+ showValues && series.length === 1 && /* @__PURE__ */ jsxRuntime.jsx(
19707
+ "text",
19708
+ {
19709
+ x: p2.x,
19710
+ y: p2.y - 10,
19711
+ textAnchor: "middle",
19712
+ fill: "var(--color-foreground)",
19713
+ fontSize: "10",
19714
+ fontWeight: "500",
19715
+ children: p2.value
19716
+ }
19717
+ )
19718
+ ] }, idx))
19719
+ ] }, s.name);
19720
+ }),
19721
+ labels.map((label, idx) => /* @__PURE__ */ jsxRuntime.jsx(
19722
+ "text",
19723
+ {
19724
+ x: xFor(idx),
19725
+ y: height - 8,
19726
+ textAnchor: "middle",
19727
+ fill: "var(--color-muted-foreground)",
19728
+ fontSize: "9",
19729
+ children: timeAxis ? formatTimeLabel(label) : label
19730
+ },
19731
+ label
19732
+ ))
19733
+ ]
19734
+ }
19735
+ );
19736
+ };
19737
+ ScatterChart = ({ data, height, onPointClick }) => {
19738
+ const width = 400;
19739
+ const padding = { top: 20, right: 20, bottom: 30, left: 40 };
19740
+ const chartWidth = width - padding.left - padding.right;
19741
+ const chartHeight = height - padding.top - padding.bottom;
19742
+ const { minX, maxX, minY, maxY } = React81.useMemo(() => {
19743
+ if (data.length === 0) {
19744
+ return { minX: 0, maxX: 1, minY: 0, maxY: 1 };
19745
+ }
19746
+ let mnX = data[0].x;
19747
+ let mxX = data[0].x;
19748
+ let mnY = data[0].y;
19749
+ let mxY = data[0].y;
19750
+ for (const p2 of data) {
19751
+ if (p2.x < mnX) mnX = p2.x;
19752
+ if (p2.x > mxX) mxX = p2.x;
19753
+ if (p2.y < mnY) mnY = p2.y;
19754
+ if (p2.y > mxY) mxY = p2.y;
19755
+ }
19756
+ return { minX: mnX, maxX: mxX, minY: mnY, maxY: mxY };
19757
+ }, [data]);
19758
+ const rangeX = maxX - minX || 1;
19759
+ const rangeY = maxY - minY || 1;
19760
+ return /* @__PURE__ */ jsxRuntime.jsxs(
19761
+ "svg",
19762
+ {
19763
+ width: "100%",
19764
+ height,
19765
+ viewBox: `0 0 ${width} ${height}`,
19766
+ preserveAspectRatio: "xMidYMid meet",
19767
+ children: [
19768
+ [0, 0.25, 0.5, 0.75, 1].map((frac) => {
19769
+ const y = padding.top + chartHeight * (1 - frac);
19770
+ return /* @__PURE__ */ jsxRuntime.jsx(
19771
+ "line",
19772
+ {
19773
+ x1: padding.left,
19774
+ y1: y,
19775
+ x2: width - padding.right,
19776
+ y2: y,
19777
+ stroke: "var(--color-border)",
19778
+ strokeDasharray: "4 4",
19779
+ opacity: 0.5
19780
+ },
19781
+ frac
19782
+ );
19783
+ }),
19784
+ data.map((p2, idx) => {
19785
+ const cx = padding.left + (p2.x - minX) / rangeX * chartWidth;
19786
+ const cy = padding.top + chartHeight - (p2.y - minY) / rangeY * chartHeight;
19787
+ const r = p2.size ?? 5;
19788
+ const color = p2.color ?? CHART_COLORS[idx % CHART_COLORS.length];
19789
+ return /* @__PURE__ */ jsxRuntime.jsx(
19790
+ "circle",
19791
+ {
19792
+ cx,
19793
+ cy,
19794
+ r,
19795
+ fill: color,
19796
+ opacity: 0.7,
19797
+ className: "cursor-pointer hover:opacity-100",
19798
+ onClick: () => onPointClick?.(
19799
+ {
19800
+ label: p2.label ?? `(${p2.x}, ${p2.y})`,
19801
+ value: p2.y,
19802
+ color
19803
+ },
19804
+ "default"
19805
+ ),
19806
+ children: /* @__PURE__ */ jsxRuntime.jsx("title", { children: p2.label ?? `(${p2.x}, ${p2.y})` })
19807
+ },
19808
+ idx
19809
+ );
19810
+ }),
19811
+ /* @__PURE__ */ jsxRuntime.jsx(
19812
+ "text",
19813
+ {
19814
+ x: padding.left,
19815
+ y: height - 8,
19816
+ fill: "var(--color-muted-foreground)",
19817
+ fontSize: "9",
19818
+ children: minX.toFixed(1)
19819
+ }
19820
+ ),
19821
+ /* @__PURE__ */ jsxRuntime.jsx(
19822
+ "text",
19823
+ {
19824
+ x: width - padding.right,
19825
+ y: height - 8,
19826
+ textAnchor: "end",
19827
+ fill: "var(--color-muted-foreground)",
19828
+ fontSize: "9",
19829
+ children: maxX.toFixed(1)
19830
+ }
19831
+ )
19832
+ ]
19833
+ }
19834
+ );
19462
19835
  };
19463
19836
  Chart = ({
19464
19837
  title,
@@ -19466,9 +19839,13 @@ var init_Chart = __esm({
19466
19839
  chartType = "bar",
19467
19840
  series,
19468
19841
  data: simpleData,
19842
+ scatterData,
19469
19843
  height = 200,
19470
19844
  showLegend = true,
19471
19845
  showValues = false,
19846
+ stack = "none",
19847
+ timeAxis = false,
19848
+ drillEvent,
19472
19849
  actions,
19473
19850
  entity,
19474
19851
  isLoading = false,
@@ -19485,11 +19862,25 @@ var init_Chart = __esm({
19485
19862
  },
19486
19863
  [eventBus]
19487
19864
  );
19488
- const normalizedData = React81.useMemo(() => {
19489
- if (simpleData) return simpleData;
19490
- if (series && series.length > 0) return series[0].data;
19865
+ const handlePointClick = React81.useCallback(
19866
+ (point, seriesName) => {
19867
+ if (drillEvent) {
19868
+ eventBus.emit(`UI:${drillEvent}`, {
19869
+ label: point.label,
19870
+ value: point.value,
19871
+ seriesLabel: seriesName === "default" ? void 0 : seriesName
19872
+ });
19873
+ }
19874
+ },
19875
+ [drillEvent, eventBus]
19876
+ );
19877
+ const normalizedSeries = React81.useMemo(() => {
19878
+ if (series && series.length > 0) return series;
19879
+ if (simpleData) return [{ name: "default", data: simpleData }];
19491
19880
  return [];
19492
19881
  }, [simpleData, series]);
19882
+ const firstSeriesData = normalizedSeries[0]?.data ?? [];
19883
+ const hasContent = chartType === "scatter" ? (scatterData?.length ?? 0) > 0 : normalizedSeries.some((s) => s.data.length > 0);
19493
19884
  if (isLoading) {
19494
19885
  return /* @__PURE__ */ jsxRuntime.jsx(LoadingState, { message: "Loading chart...", className });
19495
19886
  }
@@ -19503,7 +19894,7 @@ var init_Chart = __esm({
19503
19894
  }
19504
19895
  );
19505
19896
  }
19506
- if (normalizedData.length === 0) {
19897
+ if (!hasContent) {
19507
19898
  return /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { title: t("empty.noData"), description: t("empty.noData"), className });
19508
19899
  }
19509
19900
  return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn("p-6", className), children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "md", children: [
@@ -19524,18 +19915,84 @@ var init_Chart = __esm({
19524
19915
  )) })
19525
19916
  ] }),
19526
19917
  /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "w-full", children: [
19527
- chartType === "bar" && /* @__PURE__ */ jsxRuntime.jsx(BarChart, { data: normalizedData, height, showValues }),
19528
- chartType === "line" && /* @__PURE__ */ jsxRuntime.jsx(LineChart, { data: normalizedData, height, showValues }),
19529
- chartType === "area" && /* @__PURE__ */ jsxRuntime.jsx(LineChart, { data: normalizedData, height, showValues, fill: true }),
19530
- chartType === "pie" && /* @__PURE__ */ jsxRuntime.jsx(PieChart, { data: normalizedData, height, showValues: showLegend }),
19531
- chartType === "donut" && /* @__PURE__ */ jsxRuntime.jsx(PieChart, { data: normalizedData, height, showValues: showLegend, donut: true })
19918
+ chartType === "bar" && /* @__PURE__ */ jsxRuntime.jsx(
19919
+ BarChart,
19920
+ {
19921
+ series: normalizedSeries,
19922
+ height,
19923
+ showValues,
19924
+ stack,
19925
+ timeAxis,
19926
+ onPointClick: handlePointClick
19927
+ }
19928
+ ),
19929
+ chartType === "histogram" && /* @__PURE__ */ jsxRuntime.jsx(
19930
+ BarChart,
19931
+ {
19932
+ series: normalizedSeries,
19933
+ height,
19934
+ showValues,
19935
+ stack: "none",
19936
+ timeAxis: false,
19937
+ histogram: true,
19938
+ onPointClick: handlePointClick
19939
+ }
19940
+ ),
19941
+ chartType === "line" && /* @__PURE__ */ jsxRuntime.jsx(
19942
+ LineChart,
19943
+ {
19944
+ series: normalizedSeries,
19945
+ height,
19946
+ showValues,
19947
+ timeAxis,
19948
+ onPointClick: handlePointClick
19949
+ }
19950
+ ),
19951
+ chartType === "area" && /* @__PURE__ */ jsxRuntime.jsx(
19952
+ LineChart,
19953
+ {
19954
+ series: normalizedSeries,
19955
+ height,
19956
+ showValues,
19957
+ timeAxis,
19958
+ fill: true,
19959
+ onPointClick: handlePointClick
19960
+ }
19961
+ ),
19962
+ chartType === "pie" && /* @__PURE__ */ jsxRuntime.jsx(
19963
+ PieChart,
19964
+ {
19965
+ data: firstSeriesData,
19966
+ height,
19967
+ showValues: showLegend,
19968
+ onPointClick: handlePointClick
19969
+ }
19970
+ ),
19971
+ chartType === "donut" && /* @__PURE__ */ jsxRuntime.jsx(
19972
+ PieChart,
19973
+ {
19974
+ data: firstSeriesData,
19975
+ height,
19976
+ showValues: showLegend,
19977
+ donut: true,
19978
+ onPointClick: handlePointClick
19979
+ }
19980
+ ),
19981
+ chartType === "scatter" && /* @__PURE__ */ jsxRuntime.jsx(
19982
+ ScatterChart,
19983
+ {
19984
+ data: scatterData ?? [],
19985
+ height,
19986
+ onPointClick: handlePointClick
19987
+ }
19988
+ )
19532
19989
  ] }),
19533
- 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: [
19990
+ 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: [
19534
19991
  /* @__PURE__ */ jsxRuntime.jsx(
19535
19992
  Box,
19536
19993
  {
19537
19994
  className: "w-3 h-3 rounded-full flex-shrink-0",
19538
- style: { backgroundColor: s.color || CHART_COLORS[idx % CHART_COLORS.length] }
19995
+ style: { backgroundColor: seriesColor(s, idx) }
19539
19996
  }
19540
19997
  ),
19541
19998
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: s.name })
@@ -21396,7 +21853,6 @@ function useDataDnd(args) {
21396
21853
  const raw = it[dndItemIdField];
21397
21854
  return raw ?? `__idx_${idx}`;
21398
21855
  }),
21399
- // eslint-disable-next-line react-hooks/exhaustive-deps
21400
21856
  [itemIdsSignature]
21401
21857
  );
21402
21858
  const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
@@ -22990,7 +23446,16 @@ var init_FilterGroup = __esm({
22990
23446
  onClear: () => handleFilterSelect(`${filter.field}_to`, null)
22991
23447
  }
22992
23448
  )
22993
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(
23449
+ ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
23450
+ Input,
23451
+ {
23452
+ value: selectedValues[filter.field] || "",
23453
+ onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
23454
+ placeholder: filter.label,
23455
+ clearable: true,
23456
+ onClear: () => handleFilterSelect(filter.field, null)
23457
+ }
23458
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
22994
23459
  Select,
22995
23460
  {
22996
23461
  value: selectedValues[filter.field] || "all",
@@ -23057,7 +23522,17 @@ var init_FilterGroup = __esm({
23057
23522
  className: "text-sm min-w-[100px]"
23058
23523
  }
23059
23524
  )
23060
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(
23525
+ ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
23526
+ Input,
23527
+ {
23528
+ value: selectedValues[filter.field] || "",
23529
+ onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
23530
+ placeholder: filter.label,
23531
+ clearable: true,
23532
+ onClear: () => handleFilterSelect(filter.field, null),
23533
+ className: "text-sm"
23534
+ }
23535
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
23061
23536
  Select,
23062
23537
  {
23063
23538
  value: selectedValues[filter.field] || "all",
@@ -23162,7 +23637,17 @@ var init_FilterGroup = __esm({
23162
23637
  className: "min-w-[130px]"
23163
23638
  }
23164
23639
  )
23165
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(
23640
+ ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
23641
+ Input,
23642
+ {
23643
+ value: selectedValues[filter.field] || "",
23644
+ onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
23645
+ placeholder: filter.label,
23646
+ clearable: true,
23647
+ onClear: () => handleFilterSelect(filter.field, null),
23648
+ className: "min-w-[160px]"
23649
+ }
23650
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
23166
23651
  Select,
23167
23652
  {
23168
23653
  value: selectedValues[filter.field] || "all",
@@ -24451,6 +24936,151 @@ var init_FlipCard = __esm({
24451
24936
  FlipCard.displayName = "FlipCard";
24452
24937
  }
24453
24938
  });
24939
+ function toISODate(d) {
24940
+ return d.toISOString().slice(0, 10);
24941
+ }
24942
+ function startOfMonth(d) {
24943
+ return new Date(d.getFullYear(), d.getMonth(), 1);
24944
+ }
24945
+ function startOfQuarter(d) {
24946
+ return new Date(d.getFullYear(), Math.floor(d.getMonth() / 3) * 3, 1);
24947
+ }
24948
+ function startOfYear(d) {
24949
+ return new Date(d.getFullYear(), 0, 1);
24950
+ }
24951
+ function daysAgo(n) {
24952
+ const d = /* @__PURE__ */ new Date();
24953
+ d.setDate(d.getDate() - n);
24954
+ return d;
24955
+ }
24956
+ var DEFAULT_PRESETS, DateRangePicker;
24957
+ var init_DateRangePicker = __esm({
24958
+ "components/molecules/DateRangePicker.tsx"() {
24959
+ "use client";
24960
+ init_cn();
24961
+ init_Button();
24962
+ init_Input();
24963
+ init_Stack();
24964
+ init_Typography();
24965
+ init_useEventBus();
24966
+ DEFAULT_PRESETS = [
24967
+ {
24968
+ label: "Last 7 days",
24969
+ value: "7d",
24970
+ range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
24971
+ },
24972
+ {
24973
+ label: "Last 30 days",
24974
+ value: "30d",
24975
+ range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
24976
+ },
24977
+ {
24978
+ label: "This Month",
24979
+ value: "month",
24980
+ range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
24981
+ },
24982
+ {
24983
+ label: "This Quarter",
24984
+ value: "quarter",
24985
+ range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
24986
+ },
24987
+ {
24988
+ label: "YTD",
24989
+ value: "ytd",
24990
+ range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
24991
+ }
24992
+ ];
24993
+ DateRangePicker = ({
24994
+ from: fromProp,
24995
+ to: toProp,
24996
+ event,
24997
+ onChange,
24998
+ presets = DEFAULT_PRESETS,
24999
+ fromLabel = "From",
25000
+ toLabel = "To",
25001
+ className
25002
+ }) => {
25003
+ const eventBus = useEventBus();
25004
+ const [from, setFrom] = React81.useState(fromProp ?? "");
25005
+ const [to, setTo] = React81.useState(toProp ?? "");
25006
+ const [activePreset, setActivePreset] = React81.useState(null);
25007
+ const emit = React81.useCallback(
25008
+ (range) => {
25009
+ onChange?.(range);
25010
+ if (event) eventBus.emit(`UI:${event}`, range);
25011
+ },
25012
+ [onChange, event, eventBus]
25013
+ );
25014
+ const handleFromChange = React81.useCallback(
25015
+ (next) => {
25016
+ setFrom(next);
25017
+ setActivePreset(null);
25018
+ emit({ from: next, to });
25019
+ },
25020
+ [to, emit]
25021
+ );
25022
+ const handleToChange = React81.useCallback(
25023
+ (next) => {
25024
+ setTo(next);
25025
+ setActivePreset(null);
25026
+ emit({ from, to: next });
25027
+ },
25028
+ [from, emit]
25029
+ );
25030
+ const handlePreset = React81.useCallback(
25031
+ (preset) => {
25032
+ const range = preset.range();
25033
+ setFrom(range.from);
25034
+ setTo(range.to);
25035
+ setActivePreset(preset.value);
25036
+ emit(range);
25037
+ },
25038
+ [emit]
25039
+ );
25040
+ const presetButtons = React81.useMemo(
25041
+ () => presets.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
25042
+ Button,
25043
+ {
25044
+ variant: activePreset === preset.value ? "primary" : "ghost",
25045
+ size: "sm",
25046
+ onClick: () => handlePreset(preset),
25047
+ children: preset.label
25048
+ },
25049
+ preset.value
25050
+ )),
25051
+ [presets, activePreset, handlePreset]
25052
+ );
25053
+ return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", className: cn(className), children: [
25054
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "md", align: "end", children: [
25055
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
25056
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: fromLabel }),
25057
+ /* @__PURE__ */ jsxRuntime.jsx(
25058
+ Input,
25059
+ {
25060
+ type: "date",
25061
+ value: from,
25062
+ onChange: (e) => handleFromChange(e.target.value)
25063
+ }
25064
+ )
25065
+ ] }),
25066
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
25067
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: toLabel }),
25068
+ /* @__PURE__ */ jsxRuntime.jsx(
25069
+ Input,
25070
+ {
25071
+ type: "date",
25072
+ value: to,
25073
+ onChange: (e) => handleToChange(e.target.value)
25074
+ }
25075
+ )
25076
+ ] })
25077
+ ] }),
25078
+ presets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
25079
+ ] });
25080
+ };
25081
+ DateRangePicker.displayName = "DateRangePicker";
25082
+ }
25083
+ });
24454
25084
  var DEFAULT_OPTIONS, DateRangeSelector;
24455
25085
  var init_DateRangeSelector = __esm({
24456
25086
  "components/molecules/DateRangeSelector.tsx"() {
@@ -27422,7 +28052,9 @@ var init_StatDisplay = __esm({
27422
28052
  init_Typography();
27423
28053
  init_Box();
27424
28054
  init_Stack();
28055
+ init_Sparkline();
27425
28056
  init_Icon();
28057
+ init_useEventBus();
27426
28058
  variantColor = {
27427
28059
  default: "text-foreground",
27428
28060
  primary: "text-primary",
@@ -27437,6 +28069,10 @@ var init_StatDisplay = __esm({
27437
28069
  max,
27438
28070
  target,
27439
28071
  trend,
28072
+ trendPolarity = "higher-is-better",
28073
+ trendFormat = "absolute",
28074
+ sparklineData,
28075
+ clickEvent,
27440
28076
  prefix,
27441
28077
  suffix,
27442
28078
  icon: iconProp,
@@ -27450,6 +28086,10 @@ var init_StatDisplay = __esm({
27450
28086
  isLoading = false,
27451
28087
  error = null
27452
28088
  }) => {
28089
+ const eventBus = useEventBus();
28090
+ const handleClick = React81.useCallback(() => {
28091
+ if (clickEvent) eventBus.emit(`UI:${clickEvent}`, { metricLabel: label });
28092
+ }, [clickEvent, eventBus, label]);
27453
28093
  const ResolvedIcon = typeof iconProp === "string" ? resolveIcon(iconProp) : null;
27454
28094
  const iconSizes3 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
27455
28095
  const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
@@ -27460,7 +28100,10 @@ var init_StatDisplay = __esm({
27460
28100
  const targetPct = showTarget ? Math.max(0, Math.min(100, numericValue / target * 100)) : 0;
27461
28101
  const showTrend = typeof trend === "number" && trend !== 0 && Number.isFinite(trend);
27462
28102
  const trendUp = showTrend && trend > 0;
27463
- const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${Math.abs(trend)}` : "";
28103
+ const trendIsGood = trendPolarity === "lower-is-better" ? !trendUp : trendUp;
28104
+ const trendMagnitude = Math.abs(trend);
28105
+ const trendSuffix = trendFormat === "percent" ? "%" : "";
28106
+ const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${trendMagnitude}${trendSuffix}` : "";
27464
28107
  if (error) {
27465
28108
  return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "error", children: error.message }) });
27466
28109
  }
@@ -27471,38 +28114,57 @@ var init_StatDisplay = __esm({
27471
28114
  ] }) });
27472
28115
  }
27473
28116
  if (compact) {
27474
- return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: cn("items-center", className), children: [
27475
- ResolvedIcon && /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
27476
- typeof iconProp !== "string" && iconProp,
27477
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: label }),
27478
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
27479
- showTrend && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: cn("font-semibold", trendUp ? "text-success" : "text-error"), children: trendLabel })
27480
- ] });
28117
+ return /* @__PURE__ */ jsxRuntime.jsxs(
28118
+ HStack,
28119
+ {
28120
+ gap: "sm",
28121
+ className: cn("items-center", clickEvent && "cursor-pointer hover:opacity-80", className),
28122
+ onClick: clickEvent ? handleClick : void 0,
28123
+ children: [
28124
+ ResolvedIcon && /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
28125
+ typeof iconProp !== "string" && iconProp,
28126
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: label }),
28127
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
28128
+ showTrend && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: cn("font-semibold", trendIsGood ? "text-success" : "text-error"), children: trendLabel }),
28129
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto", width: 60, height: 20 })
28130
+ ]
28131
+ }
28132
+ );
27481
28133
  }
27482
- return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "start", justify: "between", children: [
27483
- /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
27484
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "overline", color: "secondary", children: label }),
27485
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "end", children: [
27486
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
27487
- showTrend && /* @__PURE__ */ jsxRuntime.jsx(
27488
- Typography,
27489
- {
27490
- variant: "caption",
27491
- className: cn("font-semibold pb-1", trendUp ? "text-success" : "text-error"),
27492
- children: trendLabel
27493
- }
27494
- )
27495
- ] }),
27496
- showTarget && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
27497
- Box,
27498
- {
27499
- className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
27500
- style: { width: `${targetPct}%` }
27501
- }
27502
- ) })
27503
- ] }),
27504
- (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 })
27505
- ] }) });
28134
+ return /* @__PURE__ */ jsxRuntime.jsx(
28135
+ Card,
28136
+ {
28137
+ className: cn(padSizes[size], clickEvent && "cursor-pointer hover:shadow-md transition-shadow", className),
28138
+ onClick: clickEvent ? handleClick : void 0,
28139
+ children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "start", justify: "between", children: [
28140
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
28141
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "overline", color: "secondary", children: label }),
28142
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "end", children: [
28143
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
28144
+ showTrend && /* @__PURE__ */ jsxRuntime.jsx(
28145
+ Typography,
28146
+ {
28147
+ variant: "caption",
28148
+ className: cn("font-semibold pb-1", trendIsGood ? "text-success" : "text-error"),
28149
+ children: trendLabel
28150
+ }
28151
+ )
28152
+ ] }),
28153
+ showTarget && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
28154
+ Box,
28155
+ {
28156
+ className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
28157
+ style: { width: `${targetPct}%` }
28158
+ }
28159
+ ) })
28160
+ ] }),
28161
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "end", children: [
28162
+ (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 }),
28163
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto" })
28164
+ ] })
28165
+ ] })
28166
+ }
28167
+ );
27506
28168
  };
27507
28169
  StatDisplay.displayName = "StatDisplay";
27508
28170
  }
@@ -41965,6 +42627,7 @@ var init_StatCard = __esm({
41965
42627
  init_Box();
41966
42628
  init_Stack();
41967
42629
  init_Button();
42630
+ init_Sparkline();
41968
42631
  init_useEventBus();
41969
42632
  init_useTranslate();
41970
42633
  init_Icon();
@@ -42134,32 +42797,7 @@ var init_StatCard = __esm({
42134
42797
  ] }),
42135
42798
  /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "end", children: [
42136
42799
  Icon3 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("p-3", iconBg), children: /* @__PURE__ */ jsxRuntime.jsx(Icon3, { className: cn("h-6 w-6", iconColor) }) }),
42137
- sparklineData && sparklineData.length > 1 && (() => {
42138
- const w = 80;
42139
- const h = 32;
42140
- const pad = 2;
42141
- const min = Math.min(...sparklineData);
42142
- const max = Math.max(...sparklineData);
42143
- const range = max - min || 1;
42144
- const points = sparklineData.map((v, i) => {
42145
- const x = pad + i / (sparklineData.length - 1) * (w - pad * 2);
42146
- const y = pad + (1 - (v - min) / range) * (h - pad * 2);
42147
- return `${x},${y}`;
42148
- }).join(" ");
42149
- const trending = sparklineData[sparklineData.length - 1] >= sparklineData[0];
42150
- const strokeColor = trending ? "var(--color-success)" : "var(--color-error)";
42151
- return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: w, height: h, viewBox: `0 0 ${w} ${h}`, className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
42152
- "polyline",
42153
- {
42154
- fill: "none",
42155
- stroke: strokeColor,
42156
- strokeWidth: "2",
42157
- strokeLinecap: "round",
42158
- strokeLinejoin: "round",
42159
- points
42160
- }
42161
- ) });
42162
- })()
42800
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto" })
42163
42801
  ] })
42164
42802
  ] }),
42165
42803
  action && /* @__PURE__ */ jsxRuntime.jsxs(
@@ -44057,6 +44695,7 @@ var init_component_registry_generated = __esm({
44057
44695
  init_DataGrid();
44058
44696
  init_DataList();
44059
44697
  init_DataTable();
44698
+ init_DateRangePicker();
44060
44699
  init_DateRangeSelector();
44061
44700
  init_DayCell();
44062
44701
  init_DebuggerBoard();
@@ -44189,6 +44828,7 @@ var init_component_registry_generated = __esm({
44189
44828
  init_Skeleton();
44190
44829
  init_SocialProof();
44191
44830
  init_SortableList();
44831
+ init_Sparkline();
44192
44832
  init_Split();
44193
44833
  init_SplitPane();
44194
44834
  init_SplitSection();
@@ -44337,6 +44977,7 @@ var init_component_registry_generated = __esm({
44337
44977
  "DataGrid": DataGrid,
44338
44978
  "DataList": DataList,
44339
44979
  "DataTable": DataTable,
44980
+ "DateRangePicker": DateRangePicker,
44340
44981
  "DateRangeSelector": DateRangeSelector,
44341
44982
  "DayCell": DayCell,
44342
44983
  "DebuggerBoard": DebuggerBoard,
@@ -44498,6 +45139,7 @@ var init_component_registry_generated = __esm({
44498
45139
  "SortableList": SortableList,
44499
45140
  "Spacer": SpacerPattern,
44500
45141
  "SpacerPattern": SpacerPattern,
45142
+ "Sparkline": Sparkline,
44501
45143
  "Spinner": SpinnerPattern,
44502
45144
  "SpinnerPattern": SpinnerPattern,
44503
45145
  "Split": Split,