@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.
@@ -2635,6 +2635,67 @@ var init_Radio = __esm({
2635
2635
  Radio.displayName = "Radio";
2636
2636
  }
2637
2637
  });
2638
+ var COLOR_VAR, Sparkline;
2639
+ var init_Sparkline = __esm({
2640
+ "components/atoms/Sparkline.tsx"() {
2641
+ init_cn();
2642
+ COLOR_VAR = {
2643
+ primary: "var(--color-primary)",
2644
+ success: "var(--color-success)",
2645
+ warning: "var(--color-warning)",
2646
+ error: "var(--color-error)",
2647
+ info: "var(--color-info)",
2648
+ muted: "var(--color-muted-foreground)"
2649
+ };
2650
+ Sparkline = ({
2651
+ data,
2652
+ color = "auto",
2653
+ width = 80,
2654
+ height = 32,
2655
+ strokeWidth = 2,
2656
+ fill = false,
2657
+ className
2658
+ }) => {
2659
+ if (data.length < 2) return null;
2660
+ const pad = 2;
2661
+ const min = Math.min(...data);
2662
+ const max = Math.max(...data);
2663
+ const range = max - min || 1;
2664
+ const points = data.map((v, i) => {
2665
+ const x = pad + i / (data.length - 1) * (width - pad * 2);
2666
+ const y = pad + (1 - (v - min) / range) * (height - pad * 2);
2667
+ return `${x},${y}`;
2668
+ }).join(" ");
2669
+ const resolvedColor = color === "auto" ? data[data.length - 1] >= data[0] ? COLOR_VAR.success : COLOR_VAR.error : COLOR_VAR[color];
2670
+ const areaPath = fill ? `M ${pad},${height - pad} L ${points.split(" ").join(" L ")} L ${width - pad},${height - pad} Z` : null;
2671
+ return /* @__PURE__ */ jsxs(
2672
+ "svg",
2673
+ {
2674
+ width,
2675
+ height,
2676
+ viewBox: `0 0 ${width} ${height}`,
2677
+ className: cn("flex-shrink-0", className),
2678
+ "aria-hidden": "true",
2679
+ children: [
2680
+ areaPath && /* @__PURE__ */ jsx("path", { d: areaPath, fill: resolvedColor, opacity: 0.15 }),
2681
+ /* @__PURE__ */ jsx(
2682
+ "polyline",
2683
+ {
2684
+ fill: "none",
2685
+ stroke: resolvedColor,
2686
+ strokeWidth,
2687
+ strokeLinecap: "round",
2688
+ strokeLinejoin: "round",
2689
+ points
2690
+ }
2691
+ )
2692
+ ]
2693
+ }
2694
+ );
2695
+ };
2696
+ Sparkline.displayName = "Sparkline";
2697
+ }
2698
+ });
2638
2699
  var Switch;
2639
2700
  var init_Switch = __esm({
2640
2701
  "components/atoms/Switch.tsx"() {
@@ -7708,7 +7769,7 @@ var init_MapView = __esm({
7708
7769
  shadowSize: [41, 41]
7709
7770
  });
7710
7771
  L.Marker.prototype.options.icon = defaultIcon;
7711
- const { useEffect: useEffect70, useRef: useRef66, useCallback: useCallback124, useState: useState106 } = React75__default;
7772
+ const { useEffect: useEffect70, useRef: useRef66, useCallback: useCallback126, useState: useState107 } = React75__default;
7712
7773
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
7713
7774
  const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
7714
7775
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -7753,8 +7814,8 @@ var init_MapView = __esm({
7753
7814
  showAttribution = true
7754
7815
  }) {
7755
7816
  const eventBus = useEventBus2();
7756
- const [clickedPosition, setClickedPosition] = useState106(null);
7757
- const handleMapClick = useCallback124((lat, lng) => {
7817
+ const [clickedPosition, setClickedPosition] = useState107(null);
7818
+ const handleMapClick = useCallback126((lat, lng) => {
7758
7819
  if (showClickedPin) {
7759
7820
  setClickedPosition({ lat, lng });
7760
7821
  }
@@ -7763,7 +7824,7 @@ var init_MapView = __esm({
7763
7824
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
7764
7825
  }
7765
7826
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
7766
- const handleMarkerClick = useCallback124((marker) => {
7827
+ const handleMarkerClick = useCallback126((marker) => {
7767
7828
  onMarkerClick?.(marker);
7768
7829
  if (markerClickEvent) {
7769
7830
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -17755,7 +17816,7 @@ var init_CastleTemplate = __esm({
17755
17816
  CastleTemplate.displayName = "CastleTemplate";
17756
17817
  }
17757
17818
  });
17758
- var CHART_COLORS, BarChart, PieChart, LineChart, Chart;
17819
+ var CHART_COLORS, seriesColor, monthFormatter, formatTimeLabel, BarChart, PieChart, LineChart, ScatterChart, Chart;
17759
17820
  var init_Chart = __esm({
17760
17821
  "components/organisms/Chart.tsx"() {
17761
17822
  "use client";
@@ -17775,38 +17836,159 @@ var init_Chart = __esm({
17775
17836
  "var(--color-info)",
17776
17837
  "var(--color-accent)"
17777
17838
  ];
17778
- BarChart = ({ data, height, showValues }) => {
17779
- const maxValue = Math.max(...data.map((d) => d.value), 1);
17780
- return /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "end", className: "w-full", style: { height }, children: data.map((point, idx) => {
17781
- const barHeight = point.value / maxValue * 100;
17782
- const color = point.color || CHART_COLORS[idx % CHART_COLORS.length];
17783
- return /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "center", flex: true, className: "min-w-0", children: [
17784
- showValues && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: point.value }),
17785
- /* @__PURE__ */ jsx(
17786
- Box,
17787
- {
17788
- className: cn(
17789
- "w-full rounded-t-sm transition-all duration-500 ease-out min-h-[4px]"
17790
- ),
17791
- style: {
17792
- height: `${barHeight}%`,
17793
- backgroundColor: color
17794
- }
17839
+ seriesColor = (series, idx) => series.color ?? CHART_COLORS[idx % CHART_COLORS.length];
17840
+ monthFormatter = new Intl.DateTimeFormat(void 0, {
17841
+ month: "short",
17842
+ year: "2-digit"
17843
+ });
17844
+ formatTimeLabel = (raw) => {
17845
+ const parsed = new Date(raw);
17846
+ if (Number.isNaN(parsed.getTime())) return raw;
17847
+ return monthFormatter.format(parsed);
17848
+ };
17849
+ BarChart = ({ series, height, showValues, stack, timeAxis, histogram = false, onPointClick }) => {
17850
+ const categories = useMemo(() => {
17851
+ const set = [];
17852
+ const seen = /* @__PURE__ */ new Set();
17853
+ for (const s of series) {
17854
+ for (const p2 of s.data) {
17855
+ if (!seen.has(p2.label)) {
17856
+ seen.add(p2.label);
17857
+ set.push(p2.label);
17795
17858
  }
17796
- ),
17797
- /* @__PURE__ */ jsx(
17798
- Typography,
17799
- {
17800
- variant: "caption",
17801
- color: "secondary",
17802
- className: "truncate w-full text-center",
17803
- children: point.label
17859
+ }
17860
+ }
17861
+ return set;
17862
+ }, [series]);
17863
+ const valueAt = useCallback(
17864
+ (s, label) => {
17865
+ const p2 = s.data.find((d) => d.label === label);
17866
+ return p2 ? p2.value : 0;
17867
+ },
17868
+ []
17869
+ );
17870
+ const columnTotals = useMemo(() => {
17871
+ if (stack === "none") return null;
17872
+ return categories.map(
17873
+ (label) => series.reduce((sum, s) => sum + valueAt(s, label), 0)
17874
+ );
17875
+ }, [categories, series, stack, valueAt]);
17876
+ const maxValue = useMemo(() => {
17877
+ if (stack === "normalize") return 100;
17878
+ if (stack === "stack" && columnTotals) {
17879
+ return Math.max(...columnTotals, 1);
17880
+ }
17881
+ let m = 1;
17882
+ for (const s of series) {
17883
+ for (const p2 of s.data) if (p2.value > m) m = p2.value;
17884
+ }
17885
+ return m;
17886
+ }, [series, stack, columnTotals]);
17887
+ return /* @__PURE__ */ jsx(
17888
+ HStack,
17889
+ {
17890
+ gap: histogram ? "none" : "xs",
17891
+ align: "end",
17892
+ className: "w-full",
17893
+ style: { height },
17894
+ children: categories.map((label, catIdx) => {
17895
+ const displayLabel = timeAxis ? formatTimeLabel(label) : label;
17896
+ if (stack === "none") {
17897
+ return /* @__PURE__ */ jsxs(
17898
+ VStack,
17899
+ {
17900
+ gap: "xs",
17901
+ align: "center",
17902
+ flex: true,
17903
+ className: "min-w-0",
17904
+ children: [
17905
+ /* @__PURE__ */ jsx(HStack, { gap: histogram ? "none" : "xs", align: "end", className: "w-full", style: { height: "100%" }, children: series.map((s, sIdx) => {
17906
+ const value = valueAt(s, label);
17907
+ const barHeight = value / maxValue * 100;
17908
+ const color = seriesColor(s, sIdx);
17909
+ return /* @__PURE__ */ jsx(
17910
+ Box,
17911
+ {
17912
+ className: cn(
17913
+ "rounded-t-sm transition-all duration-500 ease-out min-h-[4px] cursor-pointer hover:opacity-80",
17914
+ histogram ? "flex-1 mx-0" : "flex-1"
17915
+ ),
17916
+ style: {
17917
+ height: `${barHeight}%`,
17918
+ backgroundColor: color
17919
+ },
17920
+ onClick: () => onPointClick?.(
17921
+ { label, value, color },
17922
+ s.name
17923
+ ),
17924
+ title: `${s.name}: ${value}`
17925
+ },
17926
+ s.name
17927
+ );
17928
+ }) }),
17929
+ showValues && series.length === 1 && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: valueAt(series[0], label) }),
17930
+ /* @__PURE__ */ jsx(
17931
+ Typography,
17932
+ {
17933
+ variant: "caption",
17934
+ color: "secondary",
17935
+ className: "truncate w-full text-center",
17936
+ children: displayLabel
17937
+ }
17938
+ )
17939
+ ]
17940
+ },
17941
+ label
17942
+ );
17804
17943
  }
17805
- )
17806
- ] }, point.label);
17807
- }) });
17944
+ const total = columnTotals?.[catIdx] ?? 1;
17945
+ return /* @__PURE__ */ jsxs(
17946
+ VStack,
17947
+ {
17948
+ gap: "xs",
17949
+ align: "center",
17950
+ flex: true,
17951
+ className: "min-w-0",
17952
+ children: [
17953
+ /* @__PURE__ */ jsx(VStack, { gap: "none", className: "w-full", style: { height: "100%" }, justify: "end", children: series.map((s, sIdx) => {
17954
+ const value = valueAt(s, label);
17955
+ const ratio = stack === "normalize" ? total === 0 ? 0 : value / total * 100 : value / maxValue * 100;
17956
+ const color = seriesColor(s, sIdx);
17957
+ return /* @__PURE__ */ jsx(
17958
+ Box,
17959
+ {
17960
+ className: "w-full transition-all duration-500 ease-out cursor-pointer hover:opacity-80",
17961
+ style: {
17962
+ height: `${ratio}%`,
17963
+ backgroundColor: color
17964
+ },
17965
+ onClick: () => onPointClick?.(
17966
+ { label, value, color },
17967
+ s.name
17968
+ ),
17969
+ title: `${s.name}: ${value}`
17970
+ },
17971
+ s.name
17972
+ );
17973
+ }) }),
17974
+ /* @__PURE__ */ jsx(
17975
+ Typography,
17976
+ {
17977
+ variant: "caption",
17978
+ color: "secondary",
17979
+ className: "truncate w-full text-center",
17980
+ children: displayLabel
17981
+ }
17982
+ )
17983
+ ]
17984
+ },
17985
+ label
17986
+ );
17987
+ })
17988
+ }
17989
+ );
17808
17990
  };
17809
- PieChart = ({ data, height, showValues, donut = false }) => {
17991
+ PieChart = ({ data, height, showValues, donut = false, onPointClick }) => {
17810
17992
  const total = data.reduce((sum, d) => sum + d.value, 0);
17811
17993
  const size = Math.min(height, 200);
17812
17994
  const radius = size / 2 - 8;
@@ -17852,7 +18034,11 @@ var init_Chart = __esm({
17852
18034
  fill: seg.color,
17853
18035
  stroke: "var(--color-card)",
17854
18036
  strokeWidth: "2",
17855
- className: "transition-opacity duration-200 hover:opacity-80"
18037
+ className: "transition-opacity duration-200 hover:opacity-80 cursor-pointer",
18038
+ onClick: () => onPointClick?.(
18039
+ { label: seg.label, value: seg.value, color: seg.color },
18040
+ "default"
18041
+ )
17856
18042
  },
17857
18043
  idx
17858
18044
  )),
@@ -17887,56 +18073,243 @@ var init_Chart = __esm({
17887
18073
  ] }, idx)) })
17888
18074
  ] });
17889
18075
  };
17890
- LineChart = ({ data, height, showValues, fill = false }) => {
17891
- const maxValue = Math.max(...data.map((d) => d.value), 1);
18076
+ LineChart = ({ series, height, showValues, fill = false, timeAxis, onPointClick }) => {
17892
18077
  const width = 400;
17893
18078
  const padding = { top: 20, right: 20, bottom: 30, left: 40 };
17894
18079
  const chartWidth = width - padding.left - padding.right;
17895
18080
  const chartHeight = height - padding.top - padding.bottom;
17896
- const points = useMemo(() => {
17897
- return data.map((point, idx) => ({
17898
- x: padding.left + idx / Math.max(data.length - 1, 1) * chartWidth,
17899
- y: padding.top + chartHeight - point.value / maxValue * chartHeight,
17900
- ...point
17901
- }));
17902
- }, [data, maxValue, chartWidth, chartHeight, padding]);
17903
- const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
17904
- const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
17905
- return /* @__PURE__ */ jsxs("svg", { width: "100%", height, viewBox: `0 0 ${width} ${height}`, preserveAspectRatio: "xMidYMid meet", children: [
17906
- [0, 0.25, 0.5, 0.75, 1].map((frac) => {
17907
- const y = padding.top + chartHeight * (1 - frac);
17908
- return /* @__PURE__ */ jsx(
17909
- "line",
17910
- {
17911
- x1: padding.left,
17912
- y1: y,
17913
- x2: width - padding.right,
17914
- y2: y,
17915
- stroke: "var(--color-border)",
17916
- strokeDasharray: "4 4",
17917
- opacity: 0.5
17918
- },
17919
- frac
17920
- );
17921
- }),
17922
- fill && /* @__PURE__ */ jsx("path", { d: areaPath, fill: "var(--color-primary)", opacity: 0.1 }),
17923
- /* @__PURE__ */ jsx("path", { d: linePath, fill: "none", stroke: "var(--color-primary)", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
17924
- points.map((p2, idx) => /* @__PURE__ */ jsxs("g", { children: [
17925
- /* @__PURE__ */ jsx("circle", { cx: p2.x, cy: p2.y, r: "4", fill: "var(--color-card)", stroke: "var(--color-primary)", strokeWidth: "2" }),
17926
- showValues && /* @__PURE__ */ jsx("text", { x: p2.x, y: p2.y - 10, textAnchor: "middle", fill: "var(--color-foreground)", fontSize: "10", fontWeight: "500", children: p2.value }),
17927
- /* @__PURE__ */ jsx(
17928
- "text",
17929
- {
17930
- x: p2.x,
17931
- y: height - 8,
17932
- textAnchor: "middle",
17933
- fill: "var(--color-muted-foreground)",
17934
- fontSize: "9",
17935
- children: p2.label
18081
+ const labels = useMemo(() => {
18082
+ const seen = /* @__PURE__ */ new Set();
18083
+ const out = [];
18084
+ for (const s of series) {
18085
+ for (const p2 of s.data) {
18086
+ if (!seen.has(p2.label)) {
18087
+ seen.add(p2.label);
18088
+ out.push(p2.label);
17936
18089
  }
17937
- )
17938
- ] }, idx))
17939
- ] });
18090
+ }
18091
+ }
18092
+ return out;
18093
+ }, [series]);
18094
+ const maxValue = useMemo(() => {
18095
+ let m = 1;
18096
+ for (const s of series) {
18097
+ for (const p2 of s.data) if (p2.value > m) m = p2.value;
18098
+ }
18099
+ return m;
18100
+ }, [series]);
18101
+ const xFor = useCallback(
18102
+ (idx) => padding.left + idx / Math.max(labels.length - 1, 1) * chartWidth,
18103
+ [labels.length, chartWidth, padding.left]
18104
+ );
18105
+ const yFor = useCallback(
18106
+ (value) => padding.top + chartHeight - value / maxValue * chartHeight,
18107
+ [maxValue, chartHeight, padding.top]
18108
+ );
18109
+ return /* @__PURE__ */ jsxs(
18110
+ "svg",
18111
+ {
18112
+ width: "100%",
18113
+ height,
18114
+ viewBox: `0 0 ${width} ${height}`,
18115
+ preserveAspectRatio: "xMidYMid meet",
18116
+ children: [
18117
+ [0, 0.25, 0.5, 0.75, 1].map((frac) => {
18118
+ const y = padding.top + chartHeight * (1 - frac);
18119
+ return /* @__PURE__ */ jsx(
18120
+ "line",
18121
+ {
18122
+ x1: padding.left,
18123
+ y1: y,
18124
+ x2: width - padding.right,
18125
+ y2: y,
18126
+ stroke: "var(--color-border)",
18127
+ strokeDasharray: "4 4",
18128
+ opacity: 0.5
18129
+ },
18130
+ frac
18131
+ );
18132
+ }),
18133
+ series.map((s, sIdx) => {
18134
+ const color = seriesColor(s, sIdx);
18135
+ const points = labels.map((label, idx) => {
18136
+ const point = s.data.find((d) => d.label === label);
18137
+ return {
18138
+ x: xFor(idx),
18139
+ y: yFor(point ? point.value : 0),
18140
+ value: point ? point.value : 0,
18141
+ label
18142
+ };
18143
+ });
18144
+ const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
18145
+ const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
18146
+ return /* @__PURE__ */ jsxs("g", { children: [
18147
+ fill && /* @__PURE__ */ jsx(
18148
+ "path",
18149
+ {
18150
+ d: areaPath,
18151
+ fill: color,
18152
+ opacity: series.length > 1 ? 0.08 : 0.1
18153
+ }
18154
+ ),
18155
+ /* @__PURE__ */ jsx(
18156
+ "path",
18157
+ {
18158
+ d: linePath,
18159
+ fill: "none",
18160
+ stroke: color,
18161
+ strokeWidth: "2",
18162
+ strokeLinecap: "round",
18163
+ strokeLinejoin: "round",
18164
+ strokeDasharray: s.dashed ? "6 4" : void 0
18165
+ }
18166
+ ),
18167
+ points.map((p2, idx) => /* @__PURE__ */ jsxs("g", { children: [
18168
+ /* @__PURE__ */ jsx(
18169
+ "circle",
18170
+ {
18171
+ cx: p2.x,
18172
+ cy: p2.y,
18173
+ r: "4",
18174
+ fill: "var(--color-card)",
18175
+ stroke: color,
18176
+ strokeWidth: "2",
18177
+ className: "cursor-pointer",
18178
+ onClick: () => onPointClick?.(
18179
+ { label: p2.label, value: p2.value, color },
18180
+ s.name
18181
+ )
18182
+ }
18183
+ ),
18184
+ showValues && series.length === 1 && /* @__PURE__ */ jsx(
18185
+ "text",
18186
+ {
18187
+ x: p2.x,
18188
+ y: p2.y - 10,
18189
+ textAnchor: "middle",
18190
+ fill: "var(--color-foreground)",
18191
+ fontSize: "10",
18192
+ fontWeight: "500",
18193
+ children: p2.value
18194
+ }
18195
+ )
18196
+ ] }, idx))
18197
+ ] }, s.name);
18198
+ }),
18199
+ labels.map((label, idx) => /* @__PURE__ */ jsx(
18200
+ "text",
18201
+ {
18202
+ x: xFor(idx),
18203
+ y: height - 8,
18204
+ textAnchor: "middle",
18205
+ fill: "var(--color-muted-foreground)",
18206
+ fontSize: "9",
18207
+ children: timeAxis ? formatTimeLabel(label) : label
18208
+ },
18209
+ label
18210
+ ))
18211
+ ]
18212
+ }
18213
+ );
18214
+ };
18215
+ ScatterChart = ({ data, height, onPointClick }) => {
18216
+ const width = 400;
18217
+ const padding = { top: 20, right: 20, bottom: 30, left: 40 };
18218
+ const chartWidth = width - padding.left - padding.right;
18219
+ const chartHeight = height - padding.top - padding.bottom;
18220
+ const { minX, maxX, minY, maxY } = useMemo(() => {
18221
+ if (data.length === 0) {
18222
+ return { minX: 0, maxX: 1, minY: 0, maxY: 1 };
18223
+ }
18224
+ let mnX = data[0].x;
18225
+ let mxX = data[0].x;
18226
+ let mnY = data[0].y;
18227
+ let mxY = data[0].y;
18228
+ for (const p2 of data) {
18229
+ if (p2.x < mnX) mnX = p2.x;
18230
+ if (p2.x > mxX) mxX = p2.x;
18231
+ if (p2.y < mnY) mnY = p2.y;
18232
+ if (p2.y > mxY) mxY = p2.y;
18233
+ }
18234
+ return { minX: mnX, maxX: mxX, minY: mnY, maxY: mxY };
18235
+ }, [data]);
18236
+ const rangeX = maxX - minX || 1;
18237
+ const rangeY = maxY - minY || 1;
18238
+ return /* @__PURE__ */ jsxs(
18239
+ "svg",
18240
+ {
18241
+ width: "100%",
18242
+ height,
18243
+ viewBox: `0 0 ${width} ${height}`,
18244
+ preserveAspectRatio: "xMidYMid meet",
18245
+ children: [
18246
+ [0, 0.25, 0.5, 0.75, 1].map((frac) => {
18247
+ const y = padding.top + chartHeight * (1 - frac);
18248
+ return /* @__PURE__ */ jsx(
18249
+ "line",
18250
+ {
18251
+ x1: padding.left,
18252
+ y1: y,
18253
+ x2: width - padding.right,
18254
+ y2: y,
18255
+ stroke: "var(--color-border)",
18256
+ strokeDasharray: "4 4",
18257
+ opacity: 0.5
18258
+ },
18259
+ frac
18260
+ );
18261
+ }),
18262
+ data.map((p2, idx) => {
18263
+ const cx = padding.left + (p2.x - minX) / rangeX * chartWidth;
18264
+ const cy = padding.top + chartHeight - (p2.y - minY) / rangeY * chartHeight;
18265
+ const r = p2.size ?? 5;
18266
+ const color = p2.color ?? CHART_COLORS[idx % CHART_COLORS.length];
18267
+ return /* @__PURE__ */ jsx(
18268
+ "circle",
18269
+ {
18270
+ cx,
18271
+ cy,
18272
+ r,
18273
+ fill: color,
18274
+ opacity: 0.7,
18275
+ className: "cursor-pointer hover:opacity-100",
18276
+ onClick: () => onPointClick?.(
18277
+ {
18278
+ label: p2.label ?? `(${p2.x}, ${p2.y})`,
18279
+ value: p2.y,
18280
+ color
18281
+ },
18282
+ "default"
18283
+ ),
18284
+ children: /* @__PURE__ */ jsx("title", { children: p2.label ?? `(${p2.x}, ${p2.y})` })
18285
+ },
18286
+ idx
18287
+ );
18288
+ }),
18289
+ /* @__PURE__ */ jsx(
18290
+ "text",
18291
+ {
18292
+ x: padding.left,
18293
+ y: height - 8,
18294
+ fill: "var(--color-muted-foreground)",
18295
+ fontSize: "9",
18296
+ children: minX.toFixed(1)
18297
+ }
18298
+ ),
18299
+ /* @__PURE__ */ jsx(
18300
+ "text",
18301
+ {
18302
+ x: width - padding.right,
18303
+ y: height - 8,
18304
+ textAnchor: "end",
18305
+ fill: "var(--color-muted-foreground)",
18306
+ fontSize: "9",
18307
+ children: maxX.toFixed(1)
18308
+ }
18309
+ )
18310
+ ]
18311
+ }
18312
+ );
17940
18313
  };
17941
18314
  Chart = ({
17942
18315
  title,
@@ -17944,9 +18317,13 @@ var init_Chart = __esm({
17944
18317
  chartType = "bar",
17945
18318
  series,
17946
18319
  data: simpleData,
18320
+ scatterData,
17947
18321
  height = 200,
17948
18322
  showLegend = true,
17949
18323
  showValues = false,
18324
+ stack = "none",
18325
+ timeAxis = false,
18326
+ drillEvent,
17950
18327
  actions,
17951
18328
  entity,
17952
18329
  isLoading = false,
@@ -17963,11 +18340,25 @@ var init_Chart = __esm({
17963
18340
  },
17964
18341
  [eventBus]
17965
18342
  );
17966
- const normalizedData = useMemo(() => {
17967
- if (simpleData) return simpleData;
17968
- if (series && series.length > 0) return series[0].data;
18343
+ const handlePointClick = useCallback(
18344
+ (point, seriesName) => {
18345
+ if (drillEvent) {
18346
+ eventBus.emit(`UI:${drillEvent}`, {
18347
+ label: point.label,
18348
+ value: point.value,
18349
+ seriesLabel: seriesName === "default" ? void 0 : seriesName
18350
+ });
18351
+ }
18352
+ },
18353
+ [drillEvent, eventBus]
18354
+ );
18355
+ const normalizedSeries = useMemo(() => {
18356
+ if (series && series.length > 0) return series;
18357
+ if (simpleData) return [{ name: "default", data: simpleData }];
17969
18358
  return [];
17970
18359
  }, [simpleData, series]);
18360
+ const firstSeriesData = normalizedSeries[0]?.data ?? [];
18361
+ const hasContent = chartType === "scatter" ? (scatterData?.length ?? 0) > 0 : normalizedSeries.some((s) => s.data.length > 0);
17971
18362
  if (isLoading) {
17972
18363
  return /* @__PURE__ */ jsx(LoadingState, { message: "Loading chart...", className });
17973
18364
  }
@@ -17981,7 +18372,7 @@ var init_Chart = __esm({
17981
18372
  }
17982
18373
  );
17983
18374
  }
17984
- if (normalizedData.length === 0) {
18375
+ if (!hasContent) {
17985
18376
  return /* @__PURE__ */ jsx(EmptyState, { title: t("empty.noData"), description: t("empty.noData"), className });
17986
18377
  }
17987
18378
  return /* @__PURE__ */ jsx(Card, { className: cn("p-6", className), children: /* @__PURE__ */ jsxs(VStack, { gap: "md", children: [
@@ -18002,18 +18393,84 @@ var init_Chart = __esm({
18002
18393
  )) })
18003
18394
  ] }),
18004
18395
  /* @__PURE__ */ jsxs(Box, { className: "w-full", children: [
18005
- chartType === "bar" && /* @__PURE__ */ jsx(BarChart, { data: normalizedData, height, showValues }),
18006
- chartType === "line" && /* @__PURE__ */ jsx(LineChart, { data: normalizedData, height, showValues }),
18007
- chartType === "area" && /* @__PURE__ */ jsx(LineChart, { data: normalizedData, height, showValues, fill: true }),
18008
- chartType === "pie" && /* @__PURE__ */ jsx(PieChart, { data: normalizedData, height, showValues: showLegend }),
18009
- chartType === "donut" && /* @__PURE__ */ jsx(PieChart, { data: normalizedData, height, showValues: showLegend, donut: true })
18396
+ chartType === "bar" && /* @__PURE__ */ jsx(
18397
+ BarChart,
18398
+ {
18399
+ series: normalizedSeries,
18400
+ height,
18401
+ showValues,
18402
+ stack,
18403
+ timeAxis,
18404
+ onPointClick: handlePointClick
18405
+ }
18406
+ ),
18407
+ chartType === "histogram" && /* @__PURE__ */ jsx(
18408
+ BarChart,
18409
+ {
18410
+ series: normalizedSeries,
18411
+ height,
18412
+ showValues,
18413
+ stack: "none",
18414
+ timeAxis: false,
18415
+ histogram: true,
18416
+ onPointClick: handlePointClick
18417
+ }
18418
+ ),
18419
+ chartType === "line" && /* @__PURE__ */ jsx(
18420
+ LineChart,
18421
+ {
18422
+ series: normalizedSeries,
18423
+ height,
18424
+ showValues,
18425
+ timeAxis,
18426
+ onPointClick: handlePointClick
18427
+ }
18428
+ ),
18429
+ chartType === "area" && /* @__PURE__ */ jsx(
18430
+ LineChart,
18431
+ {
18432
+ series: normalizedSeries,
18433
+ height,
18434
+ showValues,
18435
+ timeAxis,
18436
+ fill: true,
18437
+ onPointClick: handlePointClick
18438
+ }
18439
+ ),
18440
+ chartType === "pie" && /* @__PURE__ */ jsx(
18441
+ PieChart,
18442
+ {
18443
+ data: firstSeriesData,
18444
+ height,
18445
+ showValues: showLegend,
18446
+ onPointClick: handlePointClick
18447
+ }
18448
+ ),
18449
+ chartType === "donut" && /* @__PURE__ */ jsx(
18450
+ PieChart,
18451
+ {
18452
+ data: firstSeriesData,
18453
+ height,
18454
+ showValues: showLegend,
18455
+ donut: true,
18456
+ onPointClick: handlePointClick
18457
+ }
18458
+ ),
18459
+ chartType === "scatter" && /* @__PURE__ */ jsx(
18460
+ ScatterChart,
18461
+ {
18462
+ data: scatterData ?? [],
18463
+ height,
18464
+ onPointClick: handlePointClick
18465
+ }
18466
+ )
18010
18467
  ] }),
18011
- 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: [
18468
+ 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: [
18012
18469
  /* @__PURE__ */ jsx(
18013
18470
  Box,
18014
18471
  {
18015
18472
  className: "w-3 h-3 rounded-full flex-shrink-0",
18016
- style: { backgroundColor: s.color || CHART_COLORS[idx % CHART_COLORS.length] }
18473
+ style: { backgroundColor: seriesColor(s, idx) }
18017
18474
  }
18018
18475
  ),
18019
18476
  /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: s.name })
@@ -20105,7 +20562,6 @@ function useDataDnd(args) {
20105
20562
  const raw = it[dndItemIdField];
20106
20563
  return raw ?? `__idx_${idx}`;
20107
20564
  }),
20108
- // eslint-disable-next-line react-hooks/exhaustive-deps
20109
20565
  [itemIdsSignature]
20110
20566
  );
20111
20567
  const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
@@ -21707,7 +22163,16 @@ var init_FilterGroup = __esm({
21707
22163
  onClear: () => handleFilterSelect(`${filter.field}_to`, null)
21708
22164
  }
21709
22165
  )
21710
- ] }) : /* @__PURE__ */ jsx(
22166
+ ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
22167
+ Input,
22168
+ {
22169
+ value: selectedValues[filter.field] || "",
22170
+ onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
22171
+ placeholder: filter.label,
22172
+ clearable: true,
22173
+ onClear: () => handleFilterSelect(filter.field, null)
22174
+ }
22175
+ ) : /* @__PURE__ */ jsx(
21711
22176
  Select,
21712
22177
  {
21713
22178
  value: selectedValues[filter.field] || "all",
@@ -21774,7 +22239,17 @@ var init_FilterGroup = __esm({
21774
22239
  className: "text-sm min-w-[100px]"
21775
22240
  }
21776
22241
  )
21777
- ] }) : /* @__PURE__ */ jsx(
22242
+ ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
22243
+ Input,
22244
+ {
22245
+ value: selectedValues[filter.field] || "",
22246
+ onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
22247
+ placeholder: filter.label,
22248
+ clearable: true,
22249
+ onClear: () => handleFilterSelect(filter.field, null),
22250
+ className: "text-sm"
22251
+ }
22252
+ ) : /* @__PURE__ */ jsx(
21778
22253
  Select,
21779
22254
  {
21780
22255
  value: selectedValues[filter.field] || "all",
@@ -21879,7 +22354,17 @@ var init_FilterGroup = __esm({
21879
22354
  className: "min-w-[130px]"
21880
22355
  }
21881
22356
  )
21882
- ] }) : /* @__PURE__ */ jsx(
22357
+ ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
22358
+ Input,
22359
+ {
22360
+ value: selectedValues[filter.field] || "",
22361
+ onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
22362
+ placeholder: filter.label,
22363
+ clearable: true,
22364
+ onClear: () => handleFilterSelect(filter.field, null),
22365
+ className: "min-w-[160px]"
22366
+ }
22367
+ ) : /* @__PURE__ */ jsx(
21883
22368
  Select,
21884
22369
  {
21885
22370
  value: selectedValues[filter.field] || "all",
@@ -23168,6 +23653,151 @@ var init_FlipCard = __esm({
23168
23653
  FlipCard.displayName = "FlipCard";
23169
23654
  }
23170
23655
  });
23656
+ function toISODate(d) {
23657
+ return d.toISOString().slice(0, 10);
23658
+ }
23659
+ function startOfMonth(d) {
23660
+ return new Date(d.getFullYear(), d.getMonth(), 1);
23661
+ }
23662
+ function startOfQuarter(d) {
23663
+ return new Date(d.getFullYear(), Math.floor(d.getMonth() / 3) * 3, 1);
23664
+ }
23665
+ function startOfYear(d) {
23666
+ return new Date(d.getFullYear(), 0, 1);
23667
+ }
23668
+ function daysAgo(n) {
23669
+ const d = /* @__PURE__ */ new Date();
23670
+ d.setDate(d.getDate() - n);
23671
+ return d;
23672
+ }
23673
+ var DEFAULT_PRESETS, DateRangePicker;
23674
+ var init_DateRangePicker = __esm({
23675
+ "components/molecules/DateRangePicker.tsx"() {
23676
+ "use client";
23677
+ init_cn();
23678
+ init_Button();
23679
+ init_Input();
23680
+ init_Stack();
23681
+ init_Typography();
23682
+ init_useEventBus();
23683
+ DEFAULT_PRESETS = [
23684
+ {
23685
+ label: "Last 7 days",
23686
+ value: "7d",
23687
+ range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
23688
+ },
23689
+ {
23690
+ label: "Last 30 days",
23691
+ value: "30d",
23692
+ range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
23693
+ },
23694
+ {
23695
+ label: "This Month",
23696
+ value: "month",
23697
+ range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
23698
+ },
23699
+ {
23700
+ label: "This Quarter",
23701
+ value: "quarter",
23702
+ range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
23703
+ },
23704
+ {
23705
+ label: "YTD",
23706
+ value: "ytd",
23707
+ range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
23708
+ }
23709
+ ];
23710
+ DateRangePicker = ({
23711
+ from: fromProp,
23712
+ to: toProp,
23713
+ event,
23714
+ onChange,
23715
+ presets = DEFAULT_PRESETS,
23716
+ fromLabel = "From",
23717
+ toLabel = "To",
23718
+ className
23719
+ }) => {
23720
+ const eventBus = useEventBus();
23721
+ const [from, setFrom] = useState(fromProp ?? "");
23722
+ const [to, setTo] = useState(toProp ?? "");
23723
+ const [activePreset, setActivePreset] = useState(null);
23724
+ const emit = useCallback(
23725
+ (range) => {
23726
+ onChange?.(range);
23727
+ if (event) eventBus.emit(`UI:${event}`, range);
23728
+ },
23729
+ [onChange, event, eventBus]
23730
+ );
23731
+ const handleFromChange = useCallback(
23732
+ (next) => {
23733
+ setFrom(next);
23734
+ setActivePreset(null);
23735
+ emit({ from: next, to });
23736
+ },
23737
+ [to, emit]
23738
+ );
23739
+ const handleToChange = useCallback(
23740
+ (next) => {
23741
+ setTo(next);
23742
+ setActivePreset(null);
23743
+ emit({ from, to: next });
23744
+ },
23745
+ [from, emit]
23746
+ );
23747
+ const handlePreset = useCallback(
23748
+ (preset) => {
23749
+ const range = preset.range();
23750
+ setFrom(range.from);
23751
+ setTo(range.to);
23752
+ setActivePreset(preset.value);
23753
+ emit(range);
23754
+ },
23755
+ [emit]
23756
+ );
23757
+ const presetButtons = useMemo(
23758
+ () => presets.map((preset) => /* @__PURE__ */ jsx(
23759
+ Button,
23760
+ {
23761
+ variant: activePreset === preset.value ? "primary" : "ghost",
23762
+ size: "sm",
23763
+ onClick: () => handlePreset(preset),
23764
+ children: preset.label
23765
+ },
23766
+ preset.value
23767
+ )),
23768
+ [presets, activePreset, handlePreset]
23769
+ );
23770
+ return /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: cn(className), children: [
23771
+ /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "end", children: [
23772
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
23773
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: fromLabel }),
23774
+ /* @__PURE__ */ jsx(
23775
+ Input,
23776
+ {
23777
+ type: "date",
23778
+ value: from,
23779
+ onChange: (e) => handleFromChange(e.target.value)
23780
+ }
23781
+ )
23782
+ ] }),
23783
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
23784
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: toLabel }),
23785
+ /* @__PURE__ */ jsx(
23786
+ Input,
23787
+ {
23788
+ type: "date",
23789
+ value: to,
23790
+ onChange: (e) => handleToChange(e.target.value)
23791
+ }
23792
+ )
23793
+ ] })
23794
+ ] }),
23795
+ presets.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
23796
+ ] });
23797
+ };
23798
+ DateRangePicker.displayName = "DateRangePicker";
23799
+ }
23800
+ });
23171
23801
  var DEFAULT_OPTIONS, DateRangeSelector;
23172
23802
  var init_DateRangeSelector = __esm({
23173
23803
  "components/molecules/DateRangeSelector.tsx"() {
@@ -26423,7 +27053,9 @@ var init_StatDisplay = __esm({
26423
27053
  init_Typography();
26424
27054
  init_Box();
26425
27055
  init_Stack();
27056
+ init_Sparkline();
26426
27057
  init_Icon();
27058
+ init_useEventBus();
26427
27059
  variantColor = {
26428
27060
  default: "text-foreground",
26429
27061
  primary: "text-primary",
@@ -26438,6 +27070,10 @@ var init_StatDisplay = __esm({
26438
27070
  max,
26439
27071
  target,
26440
27072
  trend,
27073
+ trendPolarity = "higher-is-better",
27074
+ trendFormat = "absolute",
27075
+ sparklineData,
27076
+ clickEvent,
26441
27077
  prefix,
26442
27078
  suffix,
26443
27079
  icon: iconProp,
@@ -26451,6 +27087,10 @@ var init_StatDisplay = __esm({
26451
27087
  isLoading = false,
26452
27088
  error = null
26453
27089
  }) => {
27090
+ const eventBus = useEventBus();
27091
+ const handleClick = useCallback(() => {
27092
+ if (clickEvent) eventBus.emit(`UI:${clickEvent}`, { metricLabel: label });
27093
+ }, [clickEvent, eventBus, label]);
26454
27094
  const ResolvedIcon = typeof iconProp === "string" ? resolveIcon(iconProp) : null;
26455
27095
  const iconSizes3 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
26456
27096
  const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
@@ -26461,7 +27101,10 @@ var init_StatDisplay = __esm({
26461
27101
  const targetPct = showTarget ? Math.max(0, Math.min(100, numericValue / target * 100)) : 0;
26462
27102
  const showTrend = typeof trend === "number" && trend !== 0 && Number.isFinite(trend);
26463
27103
  const trendUp = showTrend && trend > 0;
26464
- const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${Math.abs(trend)}` : "";
27104
+ const trendIsGood = trendPolarity === "lower-is-better" ? !trendUp : trendUp;
27105
+ const trendMagnitude = Math.abs(trend);
27106
+ const trendSuffix = trendFormat === "percent" ? "%" : "";
27107
+ const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${trendMagnitude}${trendSuffix}` : "";
26465
27108
  if (error) {
26466
27109
  return /* @__PURE__ */ jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsx(Typography, { variant: "small", color: "error", children: error.message }) });
26467
27110
  }
@@ -26472,38 +27115,57 @@ var init_StatDisplay = __esm({
26472
27115
  ] }) });
26473
27116
  }
26474
27117
  if (compact) {
26475
- return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: cn("items-center", className), children: [
26476
- ResolvedIcon && /* @__PURE__ */ jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
26477
- typeof iconProp !== "string" && iconProp,
26478
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: label }),
26479
- /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
26480
- showTrend && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: cn("font-semibold", trendUp ? "text-success" : "text-error"), children: trendLabel })
26481
- ] });
27118
+ return /* @__PURE__ */ jsxs(
27119
+ HStack,
27120
+ {
27121
+ gap: "sm",
27122
+ className: cn("items-center", clickEvent && "cursor-pointer hover:opacity-80", className),
27123
+ onClick: clickEvent ? handleClick : void 0,
27124
+ children: [
27125
+ ResolvedIcon && /* @__PURE__ */ jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
27126
+ typeof iconProp !== "string" && iconProp,
27127
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: label }),
27128
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
27129
+ showTrend && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: cn("font-semibold", trendIsGood ? "text-success" : "text-error"), children: trendLabel }),
27130
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto", width: 60, height: 20 })
27131
+ ]
27132
+ }
27133
+ );
26482
27134
  }
26483
- return /* @__PURE__ */ jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxs(HStack, { align: "start", justify: "between", children: [
26484
- /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
26485
- /* @__PURE__ */ jsx(Typography, { variant: "overline", color: "secondary", children: label }),
26486
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "end", children: [
26487
- /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
26488
- showTrend && /* @__PURE__ */ jsx(
26489
- Typography,
26490
- {
26491
- variant: "caption",
26492
- className: cn("font-semibold pb-1", trendUp ? "text-success" : "text-error"),
26493
- children: trendLabel
26494
- }
26495
- )
26496
- ] }),
26497
- showTarget && /* @__PURE__ */ jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
26498
- Box,
26499
- {
26500
- className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
26501
- style: { width: `${targetPct}%` }
26502
- }
26503
- ) })
26504
- ] }),
26505
- (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 })
26506
- ] }) });
27135
+ return /* @__PURE__ */ jsx(
27136
+ Card,
27137
+ {
27138
+ className: cn(padSizes[size], clickEvent && "cursor-pointer hover:shadow-md transition-shadow", className),
27139
+ onClick: clickEvent ? handleClick : void 0,
27140
+ children: /* @__PURE__ */ jsxs(HStack, { align: "start", justify: "between", children: [
27141
+ /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
27142
+ /* @__PURE__ */ jsx(Typography, { variant: "overline", color: "secondary", children: label }),
27143
+ /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "end", children: [
27144
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
27145
+ showTrend && /* @__PURE__ */ jsx(
27146
+ Typography,
27147
+ {
27148
+ variant: "caption",
27149
+ className: cn("font-semibold pb-1", trendIsGood ? "text-success" : "text-error"),
27150
+ children: trendLabel
27151
+ }
27152
+ )
27153
+ ] }),
27154
+ showTarget && /* @__PURE__ */ jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
27155
+ Box,
27156
+ {
27157
+ className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
27158
+ style: { width: `${targetPct}%` }
27159
+ }
27160
+ ) })
27161
+ ] }),
27162
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
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
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto" })
27165
+ ] })
27166
+ ] })
27167
+ }
27168
+ );
26507
27169
  };
26508
27170
  StatDisplay.displayName = "StatDisplay";
26509
27171
  }
@@ -31852,6 +32514,7 @@ var init_molecules = __esm({
31852
32514
  init_ViolationAlert();
31853
32515
  init_FormSectionHeader();
31854
32516
  init_FlipCard();
32517
+ init_DateRangePicker();
31855
32518
  init_DateRangeSelector();
31856
32519
  init_ChartLegend();
31857
32520
  init_LineChart();
@@ -41408,6 +42071,7 @@ var init_StatCard = __esm({
41408
42071
  init_Box();
41409
42072
  init_Stack();
41410
42073
  init_Button();
42074
+ init_Sparkline();
41411
42075
  init_useEventBus();
41412
42076
  init_useTranslate();
41413
42077
  init_Icon();
@@ -41577,32 +42241,7 @@ var init_StatCard = __esm({
41577
42241
  ] }),
41578
42242
  /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
41579
42243
  Icon3 && /* @__PURE__ */ jsx(Box, { className: cn("p-3", iconBg), children: /* @__PURE__ */ jsx(Icon3, { className: cn("h-6 w-6", iconColor) }) }),
41580
- sparklineData && sparklineData.length > 1 && (() => {
41581
- const w = 80;
41582
- const h = 32;
41583
- const pad = 2;
41584
- const min = Math.min(...sparklineData);
41585
- const max = Math.max(...sparklineData);
41586
- const range = max - min || 1;
41587
- const points = sparklineData.map((v, i) => {
41588
- const x = pad + i / (sparklineData.length - 1) * (w - pad * 2);
41589
- const y = pad + (1 - (v - min) / range) * (h - pad * 2);
41590
- return `${x},${y}`;
41591
- }).join(" ");
41592
- const trending = sparklineData[sparklineData.length - 1] >= sparklineData[0];
41593
- const strokeColor = trending ? "var(--color-success)" : "var(--color-error)";
41594
- return /* @__PURE__ */ jsx("svg", { width: w, height: h, viewBox: `0 0 ${w} ${h}`, className: "flex-shrink-0", children: /* @__PURE__ */ jsx(
41595
- "polyline",
41596
- {
41597
- fill: "none",
41598
- stroke: strokeColor,
41599
- strokeWidth: "2",
41600
- strokeLinecap: "round",
41601
- strokeLinejoin: "round",
41602
- points
41603
- }
41604
- ) });
41605
- })()
42244
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto" })
41606
42245
  ] })
41607
42246
  ] }),
41608
42247
  action && /* @__PURE__ */ jsxs(
@@ -43689,6 +44328,7 @@ var init_component_registry_generated = __esm({
43689
44328
  init_DataGrid();
43690
44329
  init_DataList();
43691
44330
  init_DataTable();
44331
+ init_DateRangePicker();
43692
44332
  init_DateRangeSelector();
43693
44333
  init_DayCell();
43694
44334
  init_DebuggerBoard();
@@ -43821,6 +44461,7 @@ var init_component_registry_generated = __esm({
43821
44461
  init_Skeleton();
43822
44462
  init_SocialProof();
43823
44463
  init_SortableList();
44464
+ init_Sparkline();
43824
44465
  init_Split();
43825
44466
  init_SplitPane();
43826
44467
  init_SplitSection();
@@ -43969,6 +44610,7 @@ var init_component_registry_generated = __esm({
43969
44610
  "DataGrid": DataGrid,
43970
44611
  "DataList": DataList,
43971
44612
  "DataTable": DataTable,
44613
+ "DateRangePicker": DateRangePicker,
43972
44614
  "DateRangeSelector": DateRangeSelector,
43973
44615
  "DayCell": DayCell,
43974
44616
  "DebuggerBoard": DebuggerBoard,
@@ -44130,6 +44772,7 @@ var init_component_registry_generated = __esm({
44130
44772
  "SortableList": SortableList,
44131
44773
  "Spacer": SpacerPattern,
44132
44774
  "SpacerPattern": SpacerPattern,
44775
+ "Sparkline": Sparkline,
44133
44776
  "Spinner": SpinnerPattern,
44134
44777
  "SpinnerPattern": SpinnerPattern,
44135
44778
  "Split": Split,
@@ -45134,6 +45777,7 @@ var init_atoms = __esm({
45134
45777
  init_Icon();
45135
45778
  init_ProgressBar();
45136
45779
  init_Radio();
45780
+ init_Sparkline();
45137
45781
  init_Switch();
45138
45782
  init_Spacer();
45139
45783
  init_Stack();
@@ -48072,4 +48716,4 @@ function useGitHubBranches(owner, repo, enabled = true) {
48072
48716
  });
48073
48717
  }
48074
48718
 
48075
- export { ALL_PRESETS, ALMADAR_DND_MIME, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, ActionButton, ActionButtons, Card2 as ActionCard, ActionPalette, ActionTile, Alert, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, AuthLayout, Avatar, Badge, BattleBoard, BattleTemplate, BehaviorView, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, Box, BranchingLogicBuilder, Breadcrumb, BuilderBoard, Button, ButtonGroup, CTABanner, CalendarGrid, CanvasEffect, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, CaseStudyCard, CaseStudyOrganism, CastleBoard, CastleTemplate, Center, Chart, ChartLegend, Checkbox, ChoiceButton, ClassifierBoard, CodeBlock, CodeExample, CodeView, CodeViewer, CollapsibleSection, CombatLog, ComboCounter, CommunityLinks, ConditionalWrapper, ConfettiEffect, ConfirmDialog, Container, ContentRenderer, ContentSection, ControlButton, CounterTemplate, CraftingRecipe, DEFAULT_LIKERT_OPTIONS, DEFAULT_MATRIX_COLUMNS, DEFAULT_SLOTS, DIAMOND_TOP_Y, DPad, DamageNumber, DashboardGrid, DashboardLayout, DataGrid, DataList, DataTable, DateRangeSelector, DayCell, DebuggerBoard, DetailPanel, DialogueBox, DialogueBubble, Divider, DocBreadcrumb, DocCodeBlock, DocPagination, DocSearch, DocSidebar, DocTOC, DocumentViewer, StateMachineView as DomStateMachineVisualizer, Drawer, DrawerSlot, EdgeDecoration, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EmptyState, EnemyPlate, EntityDisplayEvents, ErrorBoundary, ErrorState, EventHandlerBoard, EventLog, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FeatureCard, FeatureDetailPageTemplate, FeatureGrid, FeatureGridOrganism, FeatureRenderer2 as FeatureRenderer, FileTree, FilterGroup, FilterPill, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormActions, FormField, FormLayout, FormSection, FormSectionHeader, GameAudioContext, GameAudioProvider, GameAudioToggle, GameCanvas2D, GameHud, GameMenu, GameOverScreen, GameShell, GameTemplate, GenericAppTemplate, GeometricPattern, GradientDivider, GraphCanvas, GraphView, Grid, HStack, Header, Heading, HealthBar, HealthPanel, HeroOrganism, HeroSection, I18nProvider, IDENTITY_BOOK_FIELDS, Icon, InfiniteScrollSentinel, Input, InputGroup, InstallBox, InventoryGrid, InventoryPanel, IsometricCanvas, ItemSlot, JazariStateMachine, Label, LandingPageTemplate, LawReferenceTooltip, Lightbox, LikertScale, LineChart2 as LineChart, List3 as List, LoadingState, MapView, MarkdownContent, MarketingStatCard, MasterDetail, MasterDetailLayout, MatrixQuestion, MediaGallery, Menu, Meter, MiniMap, Modal, ModalSlot, ModuleCard, Navigation, NegotiatorBoard, NotifyListener, NumberStepper, ObjectRulePanel, OptionConstraintGroup, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, Overlay, PageHeader, Pagination, PatternTile, PhysicsManager, PlatformerCanvas, Popover, PositionedCanvas, PowerupSlots, PricingCard, PricingGrid, PricingOrganism, PricingPageTemplate, ProgressBar, ProgressDots, PullQuote, PullToRefresh, QrScanner, QuestTracker, QuizBlock, Radio, RangeSlider, RelationSelect, RepeatableFormSection, ReplyTree, ResourceBar, ResourceCounter, RichBlockEditor, RuleEditor, RuntimeDebugger, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, ScaledDiagram, ScoreBoard, ScoreDisplay, SearchInput, Section, SectionHeader, Select, SequenceBar, SequencerBoard, ServiceCatalog, ShowcaseCard, ShowcaseOrganism, SidePanel, Sidebar, SignaturePad, SimpleGrid, SimulationCanvas, SimulationControls, SimulationGraph, SimulatorBoard, Skeleton, SlotContentRenderer, SocialProof, SortableList, Spacer, Spinner, Split, SplitPane, SplitSection, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateArchitectBoard, StateIndicator, StateMachineView, StateNode2 as StateNode, StatsGrid, StatsOrganism, StatusBar, StatusDot, StatusEffect, StepFlow, StepFlowOrganism, SvgBranch, SvgConnection, SvgFlow, SvgGrid, SvgLobe, SvgMesh, SvgMorph, SvgNode, SvgPulse, SvgRing, SvgShield, SvgStack, SwipeableRow, Switch, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, Table, Tabs, TagCloud, TeamCard, TeamOrganism, TerrainPalette, Text, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, Timeline, TimerDisplay, Toast, ToastSlot, Tooltip, TraitFrame, TraitSlot, TraitStateViewer, TransitionArrow, TrendIndicator, TurnIndicator, TurnPanel, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UncontrolledBattleBoard, UnitCommandBar, UploadDropZone, VStack, VariablePanel, VersionDiff, ViolationAlert, VoteStack, WaypointMarker, WizardContainer, WizardNavigation, WizardProgress, WorldMapBoard, WorldMapTemplate, XPBar, applyTemporaryEffect, calculateAttackTargets, calculateDamage, calculateValidMoves, clearEntities, cn, combatAnimations, combatClasses, combatEffects, createInitialGameState, createTranslate, createUnitAnimationState, drawSprite, generateCombatMessage, getAllEntities, getByType, getCurrentFrame, getEntity, getSingleton, getTileDimensions, inferDirection, isoToScreen, mapBookData, parseQueryBinding, pendulum, projectileMotion, removeEntity, resolveFieldMap, resolveFrame, resolveSheetDirection, screenToIso, spawnEntity, springOscillator, tickAnimationState, transitionAnimation, updateEntity, updateSingleton, useAgentChat, useAuthContext, useBattleState, useCamera, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEmitEvent, useEntities, useEntitiesByType, useEntity as useEntityById, useEventBus, useEventListener, useExtensions, useFileEditor, useFileSystem, useGameAudio, useGameAudioContext, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useImageCache, useInfiniteScroll, useInput, useLongPress, useOrbitalHistory, usePhysics, usePhysics2D, usePinchZoom, usePlayer, usePreview, usePullToRefresh, useQuerySingleton, useSingletonEntity, useSpriteAnimations, useSwipeGesture, useTraitListens, useTranslate, useUIEvents, useUISlotManager, useValidation };
48719
+ export { ALL_PRESETS, ALMADAR_DND_MIME, AR_BOOK_FIELDS, AboutPageTemplate, Accordion, ActionButton, ActionButtons, Card2 as ActionCard, ActionPalette, ActionTile, Alert, AnimatedCounter, AnimatedGraphic, AnimatedReveal, ArticleSection, AuthLayout, Avatar, Badge, BattleBoard, BattleTemplate, BehaviorView, BookChapterView, BookCoverPage, BookNavBar, BookTableOfContents, BookViewer, Box, BranchingLogicBuilder, Breadcrumb, BuilderBoard, Button, ButtonGroup, CTABanner, CalendarGrid, CanvasEffect, Card, CardBody, CardContent, CardFooter, CardGrid, CardHeader, CardTitle, Carousel, CaseStudyCard, CaseStudyOrganism, CastleBoard, CastleTemplate, Center, Chart, ChartLegend, Checkbox, ChoiceButton, ClassifierBoard, CodeBlock, CodeExample, CodeView, CodeViewer, CollapsibleSection, CombatLog, ComboCounter, CommunityLinks, ConditionalWrapper, ConfettiEffect, ConfirmDialog, Container, ContentRenderer, ContentSection, ControlButton, CounterTemplate, CraftingRecipe, DEFAULT_LIKERT_OPTIONS, DEFAULT_MATRIX_COLUMNS, DEFAULT_SLOTS, DIAMOND_TOP_Y, DPad, DamageNumber, DashboardGrid, DashboardLayout, DataGrid, DataList, DataTable, DateRangePicker, DateRangeSelector, DayCell, DebuggerBoard, DetailPanel, DialogueBox, DialogueBubble, Divider, DocBreadcrumb, DocCodeBlock, DocPagination, DocSearch, DocSidebar, DocTOC, DocumentViewer, StateMachineView as DomStateMachineVisualizer, Drawer, DrawerSlot, EdgeDecoration, EditorCheckbox, EditorSelect, EditorSlider, EditorTextInput, EditorToolbar, EmptyState, EnemyPlate, EntityDisplayEvents, ErrorBoundary, ErrorState, EventHandlerBoard, EventLog, FEATURE_COLORS, FEATURE_TYPES, FLOOR_HEIGHT, FeatureCard, FeatureDetailPageTemplate, FeatureGrid, FeatureGridOrganism, FeatureRenderer2 as FeatureRenderer, FileTree, FilterGroup, FilterPill, Flex, FlipCard, FlipContainer, FloatingActionButton, Form, FormActions, FormField, FormLayout, FormSection, FormSectionHeader, GameAudioContext, GameAudioProvider, GameAudioToggle, GameCanvas2D, GameHud, GameMenu, GameOverScreen, GameShell, GameTemplate, GenericAppTemplate, GeometricPattern, GradientDivider, GraphCanvas, GraphView, Grid, HStack, Header, Heading, HealthBar, HealthPanel, HeroOrganism, HeroSection, I18nProvider, IDENTITY_BOOK_FIELDS, Icon, InfiniteScrollSentinel, Input, InputGroup, InstallBox, InventoryGrid, InventoryPanel, IsometricCanvas, ItemSlot, JazariStateMachine, Label, LandingPageTemplate, LawReferenceTooltip, Lightbox, LikertScale, LineChart2 as LineChart, List3 as List, LoadingState, MapView, MarkdownContent, MarketingStatCard, MasterDetail, MasterDetailLayout, MatrixQuestion, MediaGallery, Menu, Meter, MiniMap, Modal, ModalSlot, ModuleCard, Navigation, NegotiatorBoard, NotifyListener, NumberStepper, ObjectRulePanel, OptionConstraintGroup, StateMachineView as OrbitalStateMachineView, OrbitalVisualization, Overlay, PageHeader, Pagination, PatternTile, PhysicsManager, PlatformerCanvas, Popover, PositionedCanvas, PowerupSlots, PricingCard, PricingGrid, PricingOrganism, PricingPageTemplate, ProgressBar, ProgressDots, PullQuote, PullToRefresh, QrScanner, QuestTracker, QuizBlock, Radio, RangeSlider, RelationSelect, RepeatableFormSection, ReplyTree, ResourceBar, ResourceCounter, RichBlockEditor, RuleEditor, RuntimeDebugger, SHEET_COLUMNS, SPRITE_SHEET_LAYOUT, ScaledDiagram, ScoreBoard, ScoreDisplay, SearchInput, Section, SectionHeader, Select, SequenceBar, SequencerBoard, ServiceCatalog, ShowcaseCard, ShowcaseOrganism, SidePanel, Sidebar, SignaturePad, SimpleGrid, SimulationCanvas, SimulationControls, SimulationGraph, SimulatorBoard, Skeleton, SlotContentRenderer, SocialProof, SortableList, Spacer, Sparkline, Spinner, Split, SplitPane, SplitSection, Sprite, Stack, StarRating, StatBadge, StatCard, StatDisplay, StateArchitectBoard, StateIndicator, StateMachineView, StateNode2 as StateNode, StatsGrid, StatsOrganism, StatusBar, StatusDot, StatusEffect, StepFlow, StepFlowOrganism, SvgBranch, SvgConnection, SvgFlow, SvgGrid, SvgLobe, SvgMesh, SvgMorph, SvgNode, SvgPulse, SvgRing, SvgShield, SvgStack, SwipeableRow, Switch, TERRAIN_COLORS, TILE_HEIGHT, TILE_WIDTH, TabbedContainer, Table, Tabs, TagCloud, TeamCard, TeamOrganism, TerrainPalette, Text, TextHighlight, Textarea, ThemeSelector, ThemeToggle, TimeSlotCell, Timeline, TimerDisplay, Toast, ToastSlot, Tooltip, TraitFrame, TraitSlot, TraitStateViewer, TransitionArrow, TrendIndicator, TurnIndicator, TurnPanel, TypewriterText, Typography, UISlotComponent, UISlotRenderer, UncontrolledBattleBoard, UnitCommandBar, UploadDropZone, VStack, VariablePanel, VersionDiff, ViolationAlert, VoteStack, WaypointMarker, WizardContainer, WizardNavigation, WizardProgress, WorldMapBoard, WorldMapTemplate, XPBar, applyTemporaryEffect, calculateAttackTargets, calculateDamage, calculateValidMoves, clearEntities, cn, combatAnimations, combatClasses, combatEffects, createInitialGameState, createTranslate, createUnitAnimationState, drawSprite, generateCombatMessage, getAllEntities, getByType, getCurrentFrame, getEntity, getSingleton, getTileDimensions, inferDirection, isoToScreen, mapBookData, parseQueryBinding, pendulum, projectileMotion, removeEntity, resolveFieldMap, resolveFrame, resolveSheetDirection, screenToIso, spawnEntity, springOscillator, tickAnimationState, transitionAnimation, updateEntity, updateSingleton, useAgentChat, useAuthContext, useBattleState, useCamera, useCompile, useConnectGitHub, useDeepAgentGeneration, useDisconnectGitHub, useDragReorder, useDraggable, useDropZone, useEmitEvent, useEntities, useEntitiesByType, useEntity as useEntityById, useEventBus, useEventListener, useExtensions, useFileEditor, useFileSystem, useGameAudio, useGameAudioContext, useGitHubBranches, useGitHubRepo, useGitHubRepos, useGitHubStatus, useImageCache, useInfiniteScroll, useInput, useLongPress, useOrbitalHistory, usePhysics, usePhysics2D, usePinchZoom, usePlayer, usePreview, usePullToRefresh, useQuerySingleton, useSingletonEntity, useSpriteAnimations, useSwipeGesture, useTraitListens, useTranslate, useUIEvents, useUISlotManager, useValidation };