@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.
package/dist/avl/index.js CHANGED
@@ -8418,6 +8418,67 @@ var init_Radio = __esm({
8418
8418
  Radio.displayName = "Radio";
8419
8419
  }
8420
8420
  });
8421
+ var COLOR_VAR, Sparkline;
8422
+ var init_Sparkline = __esm({
8423
+ "components/atoms/Sparkline.tsx"() {
8424
+ init_cn();
8425
+ COLOR_VAR = {
8426
+ primary: "var(--color-primary)",
8427
+ success: "var(--color-success)",
8428
+ warning: "var(--color-warning)",
8429
+ error: "var(--color-error)",
8430
+ info: "var(--color-info)",
8431
+ muted: "var(--color-muted-foreground)"
8432
+ };
8433
+ Sparkline = ({
8434
+ data,
8435
+ color = "auto",
8436
+ width = 80,
8437
+ height = 32,
8438
+ strokeWidth = 2,
8439
+ fill = false,
8440
+ className
8441
+ }) => {
8442
+ if (data.length < 2) return null;
8443
+ const pad = 2;
8444
+ const min = Math.min(...data);
8445
+ const max = Math.max(...data);
8446
+ const range = max - min || 1;
8447
+ const points = data.map((v, i) => {
8448
+ const x = pad + i / (data.length - 1) * (width - pad * 2);
8449
+ const y = pad + (1 - (v - min) / range) * (height - pad * 2);
8450
+ return `${x},${y}`;
8451
+ }).join(" ");
8452
+ const resolvedColor = color === "auto" ? data[data.length - 1] >= data[0] ? COLOR_VAR.success : COLOR_VAR.error : COLOR_VAR[color];
8453
+ const areaPath = fill ? `M ${pad},${height - pad} L ${points.split(" ").join(" L ")} L ${width - pad},${height - pad} Z` : null;
8454
+ return /* @__PURE__ */ jsxs(
8455
+ "svg",
8456
+ {
8457
+ width,
8458
+ height,
8459
+ viewBox: `0 0 ${width} ${height}`,
8460
+ className: cn("flex-shrink-0", className),
8461
+ "aria-hidden": "true",
8462
+ children: [
8463
+ areaPath && /* @__PURE__ */ jsx("path", { d: areaPath, fill: resolvedColor, opacity: 0.15 }),
8464
+ /* @__PURE__ */ jsx(
8465
+ "polyline",
8466
+ {
8467
+ fill: "none",
8468
+ stroke: resolvedColor,
8469
+ strokeWidth,
8470
+ strokeLinecap: "round",
8471
+ strokeLinejoin: "round",
8472
+ points
8473
+ }
8474
+ )
8475
+ ]
8476
+ }
8477
+ );
8478
+ };
8479
+ Sparkline.displayName = "Sparkline";
8480
+ }
8481
+ });
8421
8482
  var Switch;
8422
8483
  var init_Switch = __esm({
8423
8484
  "components/atoms/Switch.tsx"() {
@@ -13651,7 +13712,7 @@ var init_MapView = __esm({
13651
13712
  shadowSize: [41, 41]
13652
13713
  });
13653
13714
  L.Marker.prototype.options.icon = defaultIcon;
13654
- const { useEffect: useEffect87, useRef: useRef88, useCallback: useCallback126, useState: useState120 } = React93__default;
13715
+ const { useEffect: useEffect87, useRef: useRef88, useCallback: useCallback128, useState: useState121 } = React93__default;
13655
13716
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
13656
13717
  const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
13657
13718
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -13696,8 +13757,8 @@ var init_MapView = __esm({
13696
13757
  showAttribution = true
13697
13758
  }) {
13698
13759
  const eventBus = useEventBus3();
13699
- const [clickedPosition, setClickedPosition] = useState120(null);
13700
- const handleMapClick = useCallback126((lat, lng) => {
13760
+ const [clickedPosition, setClickedPosition] = useState121(null);
13761
+ const handleMapClick = useCallback128((lat, lng) => {
13701
13762
  if (showClickedPin) {
13702
13763
  setClickedPosition({ lat, lng });
13703
13764
  }
@@ -13706,7 +13767,7 @@ var init_MapView = __esm({
13706
13767
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
13707
13768
  }
13708
13769
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
13709
- const handleMarkerClick = useCallback126((marker) => {
13770
+ const handleMarkerClick = useCallback128((marker) => {
13710
13771
  onMarkerClick?.(marker);
13711
13772
  if (markerClickEvent) {
13712
13773
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -22819,7 +22880,7 @@ var init_CastleTemplate = __esm({
22819
22880
  CastleTemplate.displayName = "CastleTemplate";
22820
22881
  }
22821
22882
  });
22822
- var CHART_COLORS, BarChart, PieChart, LineChart, Chart;
22883
+ var CHART_COLORS, seriesColor, monthFormatter, formatTimeLabel, BarChart, PieChart, LineChart, ScatterChart, Chart;
22823
22884
  var init_Chart = __esm({
22824
22885
  "components/organisms/Chart.tsx"() {
22825
22886
  "use client";
@@ -22839,38 +22900,159 @@ var init_Chart = __esm({
22839
22900
  "var(--color-info)",
22840
22901
  "var(--color-accent)"
22841
22902
  ];
22842
- BarChart = ({ data, height, showValues }) => {
22843
- const maxValue = Math.max(...data.map((d) => d.value), 1);
22844
- return /* @__PURE__ */ jsx(HStack, { gap: "xs", align: "end", className: "w-full", style: { height }, children: data.map((point, idx) => {
22845
- const barHeight = point.value / maxValue * 100;
22846
- const color = point.color || CHART_COLORS[idx % CHART_COLORS.length];
22847
- return /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "center", flex: true, className: "min-w-0", children: [
22848
- showValues && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: point.value }),
22849
- /* @__PURE__ */ jsx(
22850
- Box,
22851
- {
22852
- className: cn(
22853
- "w-full rounded-t-sm transition-all duration-500 ease-out min-h-[4px]"
22854
- ),
22855
- style: {
22856
- height: `${barHeight}%`,
22857
- backgroundColor: color
22858
- }
22903
+ seriesColor = (series, idx) => series.color ?? CHART_COLORS[idx % CHART_COLORS.length];
22904
+ monthFormatter = new Intl.DateTimeFormat(void 0, {
22905
+ month: "short",
22906
+ year: "2-digit"
22907
+ });
22908
+ formatTimeLabel = (raw) => {
22909
+ const parsed = new Date(raw);
22910
+ if (Number.isNaN(parsed.getTime())) return raw;
22911
+ return monthFormatter.format(parsed);
22912
+ };
22913
+ BarChart = ({ series, height, showValues, stack, timeAxis, histogram = false, onPointClick }) => {
22914
+ const categories = useMemo(() => {
22915
+ const set = [];
22916
+ const seen = /* @__PURE__ */ new Set();
22917
+ for (const s of series) {
22918
+ for (const p2 of s.data) {
22919
+ if (!seen.has(p2.label)) {
22920
+ seen.add(p2.label);
22921
+ set.push(p2.label);
22859
22922
  }
22860
- ),
22861
- /* @__PURE__ */ jsx(
22862
- Typography,
22863
- {
22864
- variant: "caption",
22865
- color: "secondary",
22866
- className: "truncate w-full text-center",
22867
- children: point.label
22923
+ }
22924
+ }
22925
+ return set;
22926
+ }, [series]);
22927
+ const valueAt = useCallback(
22928
+ (s, label) => {
22929
+ const p2 = s.data.find((d) => d.label === label);
22930
+ return p2 ? p2.value : 0;
22931
+ },
22932
+ []
22933
+ );
22934
+ const columnTotals = useMemo(() => {
22935
+ if (stack === "none") return null;
22936
+ return categories.map(
22937
+ (label) => series.reduce((sum, s) => sum + valueAt(s, label), 0)
22938
+ );
22939
+ }, [categories, series, stack, valueAt]);
22940
+ const maxValue = useMemo(() => {
22941
+ if (stack === "normalize") return 100;
22942
+ if (stack === "stack" && columnTotals) {
22943
+ return Math.max(...columnTotals, 1);
22944
+ }
22945
+ let m = 1;
22946
+ for (const s of series) {
22947
+ for (const p2 of s.data) if (p2.value > m) m = p2.value;
22948
+ }
22949
+ return m;
22950
+ }, [series, stack, columnTotals]);
22951
+ return /* @__PURE__ */ jsx(
22952
+ HStack,
22953
+ {
22954
+ gap: histogram ? "none" : "xs",
22955
+ align: "end",
22956
+ className: "w-full",
22957
+ style: { height },
22958
+ children: categories.map((label, catIdx) => {
22959
+ const displayLabel = timeAxis ? formatTimeLabel(label) : label;
22960
+ if (stack === "none") {
22961
+ return /* @__PURE__ */ jsxs(
22962
+ VStack,
22963
+ {
22964
+ gap: "xs",
22965
+ align: "center",
22966
+ flex: true,
22967
+ className: "min-w-0",
22968
+ children: [
22969
+ /* @__PURE__ */ jsx(HStack, { gap: histogram ? "none" : "xs", align: "end", className: "w-full", style: { height: "100%" }, children: series.map((s, sIdx) => {
22970
+ const value = valueAt(s, label);
22971
+ const barHeight = value / maxValue * 100;
22972
+ const color = seriesColor(s, sIdx);
22973
+ return /* @__PURE__ */ jsx(
22974
+ Box,
22975
+ {
22976
+ className: cn(
22977
+ "rounded-t-sm transition-all duration-500 ease-out min-h-[4px] cursor-pointer hover:opacity-80",
22978
+ histogram ? "flex-1 mx-0" : "flex-1"
22979
+ ),
22980
+ style: {
22981
+ height: `${barHeight}%`,
22982
+ backgroundColor: color
22983
+ },
22984
+ onClick: () => onPointClick?.(
22985
+ { label, value, color },
22986
+ s.name
22987
+ ),
22988
+ title: `${s.name}: ${value}`
22989
+ },
22990
+ s.name
22991
+ );
22992
+ }) }),
22993
+ showValues && series.length === 1 && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: valueAt(series[0], label) }),
22994
+ /* @__PURE__ */ jsx(
22995
+ Typography,
22996
+ {
22997
+ variant: "caption",
22998
+ color: "secondary",
22999
+ className: "truncate w-full text-center",
23000
+ children: displayLabel
23001
+ }
23002
+ )
23003
+ ]
23004
+ },
23005
+ label
23006
+ );
22868
23007
  }
22869
- )
22870
- ] }, point.label);
22871
- }) });
23008
+ const total = columnTotals?.[catIdx] ?? 1;
23009
+ return /* @__PURE__ */ jsxs(
23010
+ VStack,
23011
+ {
23012
+ gap: "xs",
23013
+ align: "center",
23014
+ flex: true,
23015
+ className: "min-w-0",
23016
+ children: [
23017
+ /* @__PURE__ */ jsx(VStack, { gap: "none", className: "w-full", style: { height: "100%" }, justify: "end", children: series.map((s, sIdx) => {
23018
+ const value = valueAt(s, label);
23019
+ const ratio = stack === "normalize" ? total === 0 ? 0 : value / total * 100 : value / maxValue * 100;
23020
+ const color = seriesColor(s, sIdx);
23021
+ return /* @__PURE__ */ jsx(
23022
+ Box,
23023
+ {
23024
+ className: "w-full transition-all duration-500 ease-out cursor-pointer hover:opacity-80",
23025
+ style: {
23026
+ height: `${ratio}%`,
23027
+ backgroundColor: color
23028
+ },
23029
+ onClick: () => onPointClick?.(
23030
+ { label, value, color },
23031
+ s.name
23032
+ ),
23033
+ title: `${s.name}: ${value}`
23034
+ },
23035
+ s.name
23036
+ );
23037
+ }) }),
23038
+ /* @__PURE__ */ jsx(
23039
+ Typography,
23040
+ {
23041
+ variant: "caption",
23042
+ color: "secondary",
23043
+ className: "truncate w-full text-center",
23044
+ children: displayLabel
23045
+ }
23046
+ )
23047
+ ]
23048
+ },
23049
+ label
23050
+ );
23051
+ })
23052
+ }
23053
+ );
22872
23054
  };
22873
- PieChart = ({ data, height, showValues, donut = false }) => {
23055
+ PieChart = ({ data, height, showValues, donut = false, onPointClick }) => {
22874
23056
  const total = data.reduce((sum, d) => sum + d.value, 0);
22875
23057
  const size = Math.min(height, 200);
22876
23058
  const radius = size / 2 - 8;
@@ -22916,7 +23098,11 @@ var init_Chart = __esm({
22916
23098
  fill: seg.color,
22917
23099
  stroke: "var(--color-card)",
22918
23100
  strokeWidth: "2",
22919
- className: "transition-opacity duration-200 hover:opacity-80"
23101
+ className: "transition-opacity duration-200 hover:opacity-80 cursor-pointer",
23102
+ onClick: () => onPointClick?.(
23103
+ { label: seg.label, value: seg.value, color: seg.color },
23104
+ "default"
23105
+ )
22920
23106
  },
22921
23107
  idx
22922
23108
  )),
@@ -22951,56 +23137,243 @@ var init_Chart = __esm({
22951
23137
  ] }, idx)) })
22952
23138
  ] });
22953
23139
  };
22954
- LineChart = ({ data, height, showValues, fill = false }) => {
22955
- const maxValue = Math.max(...data.map((d) => d.value), 1);
23140
+ LineChart = ({ series, height, showValues, fill = false, timeAxis, onPointClick }) => {
22956
23141
  const width = 400;
22957
23142
  const padding = { top: 20, right: 20, bottom: 30, left: 40 };
22958
23143
  const chartWidth = width - padding.left - padding.right;
22959
23144
  const chartHeight = height - padding.top - padding.bottom;
22960
- const points = useMemo(() => {
22961
- return data.map((point, idx) => ({
22962
- x: padding.left + idx / Math.max(data.length - 1, 1) * chartWidth,
22963
- y: padding.top + chartHeight - point.value / maxValue * chartHeight,
22964
- ...point
22965
- }));
22966
- }, [data, maxValue, chartWidth, chartHeight, padding]);
22967
- const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
22968
- const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
22969
- return /* @__PURE__ */ jsxs("svg", { width: "100%", height, viewBox: `0 0 ${width} ${height}`, preserveAspectRatio: "xMidYMid meet", children: [
22970
- [0, 0.25, 0.5, 0.75, 1].map((frac) => {
22971
- const y = padding.top + chartHeight * (1 - frac);
22972
- return /* @__PURE__ */ jsx(
22973
- "line",
22974
- {
22975
- x1: padding.left,
22976
- y1: y,
22977
- x2: width - padding.right,
22978
- y2: y,
22979
- stroke: "var(--color-border)",
22980
- strokeDasharray: "4 4",
22981
- opacity: 0.5
22982
- },
22983
- frac
22984
- );
22985
- }),
22986
- fill && /* @__PURE__ */ jsx("path", { d: areaPath, fill: "var(--color-primary)", opacity: 0.1 }),
22987
- /* @__PURE__ */ jsx("path", { d: linePath, fill: "none", stroke: "var(--color-primary)", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
22988
- points.map((p2, idx) => /* @__PURE__ */ jsxs("g", { children: [
22989
- /* @__PURE__ */ jsx("circle", { cx: p2.x, cy: p2.y, r: "4", fill: "var(--color-card)", stroke: "var(--color-primary)", strokeWidth: "2" }),
22990
- showValues && /* @__PURE__ */ jsx("text", { x: p2.x, y: p2.y - 10, textAnchor: "middle", fill: "var(--color-foreground)", fontSize: "10", fontWeight: "500", children: p2.value }),
22991
- /* @__PURE__ */ jsx(
22992
- "text",
22993
- {
22994
- x: p2.x,
22995
- y: height - 8,
22996
- textAnchor: "middle",
22997
- fill: "var(--color-muted-foreground)",
22998
- fontSize: "9",
22999
- children: p2.label
23145
+ const labels = useMemo(() => {
23146
+ const seen = /* @__PURE__ */ new Set();
23147
+ const out = [];
23148
+ for (const s of series) {
23149
+ for (const p2 of s.data) {
23150
+ if (!seen.has(p2.label)) {
23151
+ seen.add(p2.label);
23152
+ out.push(p2.label);
23000
23153
  }
23001
- )
23002
- ] }, idx))
23003
- ] });
23154
+ }
23155
+ }
23156
+ return out;
23157
+ }, [series]);
23158
+ const maxValue = useMemo(() => {
23159
+ let m = 1;
23160
+ for (const s of series) {
23161
+ for (const p2 of s.data) if (p2.value > m) m = p2.value;
23162
+ }
23163
+ return m;
23164
+ }, [series]);
23165
+ const xFor = useCallback(
23166
+ (idx) => padding.left + idx / Math.max(labels.length - 1, 1) * chartWidth,
23167
+ [labels.length, chartWidth, padding.left]
23168
+ );
23169
+ const yFor = useCallback(
23170
+ (value) => padding.top + chartHeight - value / maxValue * chartHeight,
23171
+ [maxValue, chartHeight, padding.top]
23172
+ );
23173
+ return /* @__PURE__ */ jsxs(
23174
+ "svg",
23175
+ {
23176
+ width: "100%",
23177
+ height,
23178
+ viewBox: `0 0 ${width} ${height}`,
23179
+ preserveAspectRatio: "xMidYMid meet",
23180
+ children: [
23181
+ [0, 0.25, 0.5, 0.75, 1].map((frac) => {
23182
+ const y = padding.top + chartHeight * (1 - frac);
23183
+ return /* @__PURE__ */ jsx(
23184
+ "line",
23185
+ {
23186
+ x1: padding.left,
23187
+ y1: y,
23188
+ x2: width - padding.right,
23189
+ y2: y,
23190
+ stroke: "var(--color-border)",
23191
+ strokeDasharray: "4 4",
23192
+ opacity: 0.5
23193
+ },
23194
+ frac
23195
+ );
23196
+ }),
23197
+ series.map((s, sIdx) => {
23198
+ const color = seriesColor(s, sIdx);
23199
+ const points = labels.map((label, idx) => {
23200
+ const point = s.data.find((d) => d.label === label);
23201
+ return {
23202
+ x: xFor(idx),
23203
+ y: yFor(point ? point.value : 0),
23204
+ value: point ? point.value : 0,
23205
+ label
23206
+ };
23207
+ });
23208
+ const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
23209
+ const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
23210
+ return /* @__PURE__ */ jsxs("g", { children: [
23211
+ fill && /* @__PURE__ */ jsx(
23212
+ "path",
23213
+ {
23214
+ d: areaPath,
23215
+ fill: color,
23216
+ opacity: series.length > 1 ? 0.08 : 0.1
23217
+ }
23218
+ ),
23219
+ /* @__PURE__ */ jsx(
23220
+ "path",
23221
+ {
23222
+ d: linePath,
23223
+ fill: "none",
23224
+ stroke: color,
23225
+ strokeWidth: "2",
23226
+ strokeLinecap: "round",
23227
+ strokeLinejoin: "round",
23228
+ strokeDasharray: s.dashed ? "6 4" : void 0
23229
+ }
23230
+ ),
23231
+ points.map((p2, idx) => /* @__PURE__ */ jsxs("g", { children: [
23232
+ /* @__PURE__ */ jsx(
23233
+ "circle",
23234
+ {
23235
+ cx: p2.x,
23236
+ cy: p2.y,
23237
+ r: "4",
23238
+ fill: "var(--color-card)",
23239
+ stroke: color,
23240
+ strokeWidth: "2",
23241
+ className: "cursor-pointer",
23242
+ onClick: () => onPointClick?.(
23243
+ { label: p2.label, value: p2.value, color },
23244
+ s.name
23245
+ )
23246
+ }
23247
+ ),
23248
+ showValues && series.length === 1 && /* @__PURE__ */ jsx(
23249
+ "text",
23250
+ {
23251
+ x: p2.x,
23252
+ y: p2.y - 10,
23253
+ textAnchor: "middle",
23254
+ fill: "var(--color-foreground)",
23255
+ fontSize: "10",
23256
+ fontWeight: "500",
23257
+ children: p2.value
23258
+ }
23259
+ )
23260
+ ] }, idx))
23261
+ ] }, s.name);
23262
+ }),
23263
+ labels.map((label, idx) => /* @__PURE__ */ jsx(
23264
+ "text",
23265
+ {
23266
+ x: xFor(idx),
23267
+ y: height - 8,
23268
+ textAnchor: "middle",
23269
+ fill: "var(--color-muted-foreground)",
23270
+ fontSize: "9",
23271
+ children: timeAxis ? formatTimeLabel(label) : label
23272
+ },
23273
+ label
23274
+ ))
23275
+ ]
23276
+ }
23277
+ );
23278
+ };
23279
+ ScatterChart = ({ data, height, onPointClick }) => {
23280
+ const width = 400;
23281
+ const padding = { top: 20, right: 20, bottom: 30, left: 40 };
23282
+ const chartWidth = width - padding.left - padding.right;
23283
+ const chartHeight = height - padding.top - padding.bottom;
23284
+ const { minX, maxX, minY, maxY } = useMemo(() => {
23285
+ if (data.length === 0) {
23286
+ return { minX: 0, maxX: 1, minY: 0, maxY: 1 };
23287
+ }
23288
+ let mnX = data[0].x;
23289
+ let mxX = data[0].x;
23290
+ let mnY = data[0].y;
23291
+ let mxY = data[0].y;
23292
+ for (const p2 of data) {
23293
+ if (p2.x < mnX) mnX = p2.x;
23294
+ if (p2.x > mxX) mxX = p2.x;
23295
+ if (p2.y < mnY) mnY = p2.y;
23296
+ if (p2.y > mxY) mxY = p2.y;
23297
+ }
23298
+ return { minX: mnX, maxX: mxX, minY: mnY, maxY: mxY };
23299
+ }, [data]);
23300
+ const rangeX = maxX - minX || 1;
23301
+ const rangeY = maxY - minY || 1;
23302
+ return /* @__PURE__ */ jsxs(
23303
+ "svg",
23304
+ {
23305
+ width: "100%",
23306
+ height,
23307
+ viewBox: `0 0 ${width} ${height}`,
23308
+ preserveAspectRatio: "xMidYMid meet",
23309
+ children: [
23310
+ [0, 0.25, 0.5, 0.75, 1].map((frac) => {
23311
+ const y = padding.top + chartHeight * (1 - frac);
23312
+ return /* @__PURE__ */ jsx(
23313
+ "line",
23314
+ {
23315
+ x1: padding.left,
23316
+ y1: y,
23317
+ x2: width - padding.right,
23318
+ y2: y,
23319
+ stroke: "var(--color-border)",
23320
+ strokeDasharray: "4 4",
23321
+ opacity: 0.5
23322
+ },
23323
+ frac
23324
+ );
23325
+ }),
23326
+ data.map((p2, idx) => {
23327
+ const cx = padding.left + (p2.x - minX) / rangeX * chartWidth;
23328
+ const cy = padding.top + chartHeight - (p2.y - minY) / rangeY * chartHeight;
23329
+ const r2 = p2.size ?? 5;
23330
+ const color = p2.color ?? CHART_COLORS[idx % CHART_COLORS.length];
23331
+ return /* @__PURE__ */ jsx(
23332
+ "circle",
23333
+ {
23334
+ cx,
23335
+ cy,
23336
+ r: r2,
23337
+ fill: color,
23338
+ opacity: 0.7,
23339
+ className: "cursor-pointer hover:opacity-100",
23340
+ onClick: () => onPointClick?.(
23341
+ {
23342
+ label: p2.label ?? `(${p2.x}, ${p2.y})`,
23343
+ value: p2.y,
23344
+ color
23345
+ },
23346
+ "default"
23347
+ ),
23348
+ children: /* @__PURE__ */ jsx("title", { children: p2.label ?? `(${p2.x}, ${p2.y})` })
23349
+ },
23350
+ idx
23351
+ );
23352
+ }),
23353
+ /* @__PURE__ */ jsx(
23354
+ "text",
23355
+ {
23356
+ x: padding.left,
23357
+ y: height - 8,
23358
+ fill: "var(--color-muted-foreground)",
23359
+ fontSize: "9",
23360
+ children: minX.toFixed(1)
23361
+ }
23362
+ ),
23363
+ /* @__PURE__ */ jsx(
23364
+ "text",
23365
+ {
23366
+ x: width - padding.right,
23367
+ y: height - 8,
23368
+ textAnchor: "end",
23369
+ fill: "var(--color-muted-foreground)",
23370
+ fontSize: "9",
23371
+ children: maxX.toFixed(1)
23372
+ }
23373
+ )
23374
+ ]
23375
+ }
23376
+ );
23004
23377
  };
23005
23378
  Chart = ({
23006
23379
  title,
@@ -23008,9 +23381,13 @@ var init_Chart = __esm({
23008
23381
  chartType = "bar",
23009
23382
  series,
23010
23383
  data: simpleData,
23384
+ scatterData,
23011
23385
  height = 200,
23012
23386
  showLegend = true,
23013
23387
  showValues = false,
23388
+ stack = "none",
23389
+ timeAxis = false,
23390
+ drillEvent,
23014
23391
  actions,
23015
23392
  entity,
23016
23393
  isLoading = false,
@@ -23027,11 +23404,25 @@ var init_Chart = __esm({
23027
23404
  },
23028
23405
  [eventBus]
23029
23406
  );
23030
- const normalizedData = useMemo(() => {
23031
- if (simpleData) return simpleData;
23032
- if (series && series.length > 0) return series[0].data;
23407
+ const handlePointClick = useCallback(
23408
+ (point, seriesName) => {
23409
+ if (drillEvent) {
23410
+ eventBus.emit(`UI:${drillEvent}`, {
23411
+ label: point.label,
23412
+ value: point.value,
23413
+ seriesLabel: seriesName === "default" ? void 0 : seriesName
23414
+ });
23415
+ }
23416
+ },
23417
+ [drillEvent, eventBus]
23418
+ );
23419
+ const normalizedSeries = useMemo(() => {
23420
+ if (series && series.length > 0) return series;
23421
+ if (simpleData) return [{ name: "default", data: simpleData }];
23033
23422
  return [];
23034
23423
  }, [simpleData, series]);
23424
+ const firstSeriesData = normalizedSeries[0]?.data ?? [];
23425
+ const hasContent = chartType === "scatter" ? (scatterData?.length ?? 0) > 0 : normalizedSeries.some((s) => s.data.length > 0);
23035
23426
  if (isLoading) {
23036
23427
  return /* @__PURE__ */ jsx(LoadingState, { message: "Loading chart...", className });
23037
23428
  }
@@ -23045,7 +23436,7 @@ var init_Chart = __esm({
23045
23436
  }
23046
23437
  );
23047
23438
  }
23048
- if (normalizedData.length === 0) {
23439
+ if (!hasContent) {
23049
23440
  return /* @__PURE__ */ jsx(EmptyState, { title: t("empty.noData"), description: t("empty.noData"), className });
23050
23441
  }
23051
23442
  return /* @__PURE__ */ jsx(Card, { className: cn("p-6", className), children: /* @__PURE__ */ jsxs(VStack, { gap: "md", children: [
@@ -23066,18 +23457,84 @@ var init_Chart = __esm({
23066
23457
  )) })
23067
23458
  ] }),
23068
23459
  /* @__PURE__ */ jsxs(Box, { className: "w-full", children: [
23069
- chartType === "bar" && /* @__PURE__ */ jsx(BarChart, { data: normalizedData, height, showValues }),
23070
- chartType === "line" && /* @__PURE__ */ jsx(LineChart, { data: normalizedData, height, showValues }),
23071
- chartType === "area" && /* @__PURE__ */ jsx(LineChart, { data: normalizedData, height, showValues, fill: true }),
23072
- chartType === "pie" && /* @__PURE__ */ jsx(PieChart, { data: normalizedData, height, showValues: showLegend }),
23073
- chartType === "donut" && /* @__PURE__ */ jsx(PieChart, { data: normalizedData, height, showValues: showLegend, donut: true })
23460
+ chartType === "bar" && /* @__PURE__ */ jsx(
23461
+ BarChart,
23462
+ {
23463
+ series: normalizedSeries,
23464
+ height,
23465
+ showValues,
23466
+ stack,
23467
+ timeAxis,
23468
+ onPointClick: handlePointClick
23469
+ }
23470
+ ),
23471
+ chartType === "histogram" && /* @__PURE__ */ jsx(
23472
+ BarChart,
23473
+ {
23474
+ series: normalizedSeries,
23475
+ height,
23476
+ showValues,
23477
+ stack: "none",
23478
+ timeAxis: false,
23479
+ histogram: true,
23480
+ onPointClick: handlePointClick
23481
+ }
23482
+ ),
23483
+ chartType === "line" && /* @__PURE__ */ jsx(
23484
+ LineChart,
23485
+ {
23486
+ series: normalizedSeries,
23487
+ height,
23488
+ showValues,
23489
+ timeAxis,
23490
+ onPointClick: handlePointClick
23491
+ }
23492
+ ),
23493
+ chartType === "area" && /* @__PURE__ */ jsx(
23494
+ LineChart,
23495
+ {
23496
+ series: normalizedSeries,
23497
+ height,
23498
+ showValues,
23499
+ timeAxis,
23500
+ fill: true,
23501
+ onPointClick: handlePointClick
23502
+ }
23503
+ ),
23504
+ chartType === "pie" && /* @__PURE__ */ jsx(
23505
+ PieChart,
23506
+ {
23507
+ data: firstSeriesData,
23508
+ height,
23509
+ showValues: showLegend,
23510
+ onPointClick: handlePointClick
23511
+ }
23512
+ ),
23513
+ chartType === "donut" && /* @__PURE__ */ jsx(
23514
+ PieChart,
23515
+ {
23516
+ data: firstSeriesData,
23517
+ height,
23518
+ showValues: showLegend,
23519
+ donut: true,
23520
+ onPointClick: handlePointClick
23521
+ }
23522
+ ),
23523
+ chartType === "scatter" && /* @__PURE__ */ jsx(
23524
+ ScatterChart,
23525
+ {
23526
+ data: scatterData ?? [],
23527
+ height,
23528
+ onPointClick: handlePointClick
23529
+ }
23530
+ )
23074
23531
  ] }),
23075
- 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: [
23532
+ 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: [
23076
23533
  /* @__PURE__ */ jsx(
23077
23534
  Box,
23078
23535
  {
23079
23536
  className: "w-3 h-3 rounded-full flex-shrink-0",
23080
- style: { backgroundColor: s.color || CHART_COLORS[idx % CHART_COLORS.length] }
23537
+ style: { backgroundColor: seriesColor(s, idx) }
23081
23538
  }
23082
23539
  ),
23083
23540
  /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: s.name })
@@ -24938,7 +25395,6 @@ function useDataDnd(args) {
24938
25395
  const raw = it[dndItemIdField];
24939
25396
  return raw ?? `__idx_${idx}`;
24940
25397
  }),
24941
- // eslint-disable-next-line react-hooks/exhaustive-deps
24942
25398
  [itemIdsSignature]
24943
25399
  );
24944
25400
  const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
@@ -26532,7 +26988,16 @@ var init_FilterGroup = __esm({
26532
26988
  onClear: () => handleFilterSelect(`${filter.field}_to`, null)
26533
26989
  }
26534
26990
  )
26535
- ] }) : /* @__PURE__ */ jsx(
26991
+ ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
26992
+ Input,
26993
+ {
26994
+ value: selectedValues[filter.field] || "",
26995
+ onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
26996
+ placeholder: filter.label,
26997
+ clearable: true,
26998
+ onClear: () => handleFilterSelect(filter.field, null)
26999
+ }
27000
+ ) : /* @__PURE__ */ jsx(
26536
27001
  Select,
26537
27002
  {
26538
27003
  value: selectedValues[filter.field] || "all",
@@ -26599,7 +27064,17 @@ var init_FilterGroup = __esm({
26599
27064
  className: "text-sm min-w-[100px]"
26600
27065
  }
26601
27066
  )
26602
- ] }) : /* @__PURE__ */ jsx(
27067
+ ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
27068
+ Input,
27069
+ {
27070
+ value: selectedValues[filter.field] || "",
27071
+ onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
27072
+ placeholder: filter.label,
27073
+ clearable: true,
27074
+ onClear: () => handleFilterSelect(filter.field, null),
27075
+ className: "text-sm"
27076
+ }
27077
+ ) : /* @__PURE__ */ jsx(
26603
27078
  Select,
26604
27079
  {
26605
27080
  value: selectedValues[filter.field] || "all",
@@ -26704,7 +27179,17 @@ var init_FilterGroup = __esm({
26704
27179
  className: "min-w-[130px]"
26705
27180
  }
26706
27181
  )
26707
- ] }) : /* @__PURE__ */ jsx(
27182
+ ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
27183
+ Input,
27184
+ {
27185
+ value: selectedValues[filter.field] || "",
27186
+ onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
27187
+ placeholder: filter.label,
27188
+ clearable: true,
27189
+ onClear: () => handleFilterSelect(filter.field, null),
27190
+ className: "min-w-[160px]"
27191
+ }
27192
+ ) : /* @__PURE__ */ jsx(
26708
27193
  Select,
26709
27194
  {
26710
27195
  value: selectedValues[filter.field] || "all",
@@ -27993,6 +28478,151 @@ var init_FlipCard = __esm({
27993
28478
  FlipCard.displayName = "FlipCard";
27994
28479
  }
27995
28480
  });
28481
+ function toISODate(d) {
28482
+ return d.toISOString().slice(0, 10);
28483
+ }
28484
+ function startOfMonth(d) {
28485
+ return new Date(d.getFullYear(), d.getMonth(), 1);
28486
+ }
28487
+ function startOfQuarter(d) {
28488
+ return new Date(d.getFullYear(), Math.floor(d.getMonth() / 3) * 3, 1);
28489
+ }
28490
+ function startOfYear(d) {
28491
+ return new Date(d.getFullYear(), 0, 1);
28492
+ }
28493
+ function daysAgo(n) {
28494
+ const d = /* @__PURE__ */ new Date();
28495
+ d.setDate(d.getDate() - n);
28496
+ return d;
28497
+ }
28498
+ var DEFAULT_PRESETS, DateRangePicker;
28499
+ var init_DateRangePicker = __esm({
28500
+ "components/molecules/DateRangePicker.tsx"() {
28501
+ "use client";
28502
+ init_cn();
28503
+ init_Button();
28504
+ init_Input();
28505
+ init_Stack();
28506
+ init_Typography();
28507
+ init_useEventBus();
28508
+ DEFAULT_PRESETS = [
28509
+ {
28510
+ label: "Last 7 days",
28511
+ value: "7d",
28512
+ range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
28513
+ },
28514
+ {
28515
+ label: "Last 30 days",
28516
+ value: "30d",
28517
+ range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
28518
+ },
28519
+ {
28520
+ label: "This Month",
28521
+ value: "month",
28522
+ range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
28523
+ },
28524
+ {
28525
+ label: "This Quarter",
28526
+ value: "quarter",
28527
+ range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
28528
+ },
28529
+ {
28530
+ label: "YTD",
28531
+ value: "ytd",
28532
+ range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
28533
+ }
28534
+ ];
28535
+ DateRangePicker = ({
28536
+ from: fromProp,
28537
+ to: toProp,
28538
+ event,
28539
+ onChange,
28540
+ presets = DEFAULT_PRESETS,
28541
+ fromLabel = "From",
28542
+ toLabel = "To",
28543
+ className
28544
+ }) => {
28545
+ const eventBus = useEventBus();
28546
+ const [from, setFrom] = useState(fromProp ?? "");
28547
+ const [to, setTo] = useState(toProp ?? "");
28548
+ const [activePreset, setActivePreset] = useState(null);
28549
+ const emit = useCallback(
28550
+ (range) => {
28551
+ onChange?.(range);
28552
+ if (event) eventBus.emit(`UI:${event}`, range);
28553
+ },
28554
+ [onChange, event, eventBus]
28555
+ );
28556
+ const handleFromChange = useCallback(
28557
+ (next) => {
28558
+ setFrom(next);
28559
+ setActivePreset(null);
28560
+ emit({ from: next, to });
28561
+ },
28562
+ [to, emit]
28563
+ );
28564
+ const handleToChange = useCallback(
28565
+ (next) => {
28566
+ setTo(next);
28567
+ setActivePreset(null);
28568
+ emit({ from, to: next });
28569
+ },
28570
+ [from, emit]
28571
+ );
28572
+ const handlePreset = useCallback(
28573
+ (preset) => {
28574
+ const range = preset.range();
28575
+ setFrom(range.from);
28576
+ setTo(range.to);
28577
+ setActivePreset(preset.value);
28578
+ emit(range);
28579
+ },
28580
+ [emit]
28581
+ );
28582
+ const presetButtons = useMemo(
28583
+ () => presets.map((preset) => /* @__PURE__ */ jsx(
28584
+ Button,
28585
+ {
28586
+ variant: activePreset === preset.value ? "primary" : "ghost",
28587
+ size: "sm",
28588
+ onClick: () => handlePreset(preset),
28589
+ children: preset.label
28590
+ },
28591
+ preset.value
28592
+ )),
28593
+ [presets, activePreset, handlePreset]
28594
+ );
28595
+ return /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: cn(className), children: [
28596
+ /* @__PURE__ */ jsxs(HStack, { gap: "md", align: "end", children: [
28597
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
28598
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: fromLabel }),
28599
+ /* @__PURE__ */ jsx(
28600
+ Input,
28601
+ {
28602
+ type: "date",
28603
+ value: from,
28604
+ onChange: (e) => handleFromChange(e.target.value)
28605
+ }
28606
+ )
28607
+ ] }),
28608
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
28609
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: toLabel }),
28610
+ /* @__PURE__ */ jsx(
28611
+ Input,
28612
+ {
28613
+ type: "date",
28614
+ value: to,
28615
+ onChange: (e) => handleToChange(e.target.value)
28616
+ }
28617
+ )
28618
+ ] })
28619
+ ] }),
28620
+ presets.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
28621
+ ] });
28622
+ };
28623
+ DateRangePicker.displayName = "DateRangePicker";
28624
+ }
28625
+ });
27996
28626
  var DEFAULT_OPTIONS, DateRangeSelector;
27997
28627
  var init_DateRangeSelector = __esm({
27998
28628
  "components/molecules/DateRangeSelector.tsx"() {
@@ -30964,7 +31594,9 @@ var init_StatDisplay = __esm({
30964
31594
  init_Typography();
30965
31595
  init_Box();
30966
31596
  init_Stack();
31597
+ init_Sparkline();
30967
31598
  init_Icon();
31599
+ init_useEventBus();
30968
31600
  variantColor = {
30969
31601
  default: "text-foreground",
30970
31602
  primary: "text-primary",
@@ -30979,6 +31611,10 @@ var init_StatDisplay = __esm({
30979
31611
  max,
30980
31612
  target,
30981
31613
  trend,
31614
+ trendPolarity = "higher-is-better",
31615
+ trendFormat = "absolute",
31616
+ sparklineData,
31617
+ clickEvent,
30982
31618
  prefix,
30983
31619
  suffix,
30984
31620
  icon: iconProp,
@@ -30992,6 +31628,10 @@ var init_StatDisplay = __esm({
30992
31628
  isLoading = false,
30993
31629
  error = null
30994
31630
  }) => {
31631
+ const eventBus = useEventBus();
31632
+ const handleClick = useCallback(() => {
31633
+ if (clickEvent) eventBus.emit(`UI:${clickEvent}`, { metricLabel: label });
31634
+ }, [clickEvent, eventBus, label]);
30995
31635
  const ResolvedIcon = typeof iconProp === "string" ? resolveIcon(iconProp) : null;
30996
31636
  const iconSizes3 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
30997
31637
  const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
@@ -31002,7 +31642,10 @@ var init_StatDisplay = __esm({
31002
31642
  const targetPct = showTarget ? Math.max(0, Math.min(100, numericValue / target * 100)) : 0;
31003
31643
  const showTrend = typeof trend === "number" && trend !== 0 && Number.isFinite(trend);
31004
31644
  const trendUp = showTrend && trend > 0;
31005
- const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${Math.abs(trend)}` : "";
31645
+ const trendIsGood = trendPolarity === "lower-is-better" ? !trendUp : trendUp;
31646
+ const trendMagnitude = Math.abs(trend);
31647
+ const trendSuffix = trendFormat === "percent" ? "%" : "";
31648
+ const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${trendMagnitude}${trendSuffix}` : "";
31006
31649
  if (error) {
31007
31650
  return /* @__PURE__ */ jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsx(Typography, { variant: "small", color: "error", children: error.message }) });
31008
31651
  }
@@ -31013,38 +31656,57 @@ var init_StatDisplay = __esm({
31013
31656
  ] }) });
31014
31657
  }
31015
31658
  if (compact) {
31016
- return /* @__PURE__ */ jsxs(HStack, { gap: "sm", className: cn("items-center", className), children: [
31017
- ResolvedIcon && /* @__PURE__ */ jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
31018
- typeof iconProp !== "string" && iconProp,
31019
- /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: label }),
31020
- /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
31021
- showTrend && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: cn("font-semibold", trendUp ? "text-success" : "text-error"), children: trendLabel })
31022
- ] });
31659
+ return /* @__PURE__ */ jsxs(
31660
+ HStack,
31661
+ {
31662
+ gap: "sm",
31663
+ className: cn("items-center", clickEvent && "cursor-pointer hover:opacity-80", className),
31664
+ onClick: clickEvent ? handleClick : void 0,
31665
+ children: [
31666
+ ResolvedIcon && /* @__PURE__ */ jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
31667
+ typeof iconProp !== "string" && iconProp,
31668
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: label }),
31669
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
31670
+ showTrend && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: cn("font-semibold", trendIsGood ? "text-success" : "text-error"), children: trendLabel }),
31671
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto", width: 60, height: 20 })
31672
+ ]
31673
+ }
31674
+ );
31023
31675
  }
31024
- return /* @__PURE__ */ jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxs(HStack, { align: "start", justify: "between", children: [
31025
- /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
31026
- /* @__PURE__ */ jsx(Typography, { variant: "overline", color: "secondary", children: label }),
31027
- /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "end", children: [
31028
- /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
31029
- showTrend && /* @__PURE__ */ jsx(
31030
- Typography,
31031
- {
31032
- variant: "caption",
31033
- className: cn("font-semibold pb-1", trendUp ? "text-success" : "text-error"),
31034
- children: trendLabel
31035
- }
31036
- )
31037
- ] }),
31038
- showTarget && /* @__PURE__ */ jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
31039
- Box,
31040
- {
31041
- className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
31042
- style: { width: `${targetPct}%` }
31043
- }
31044
- ) })
31045
- ] }),
31046
- (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 })
31047
- ] }) });
31676
+ return /* @__PURE__ */ jsx(
31677
+ Card,
31678
+ {
31679
+ className: cn(padSizes[size], clickEvent && "cursor-pointer hover:shadow-md transition-shadow", className),
31680
+ onClick: clickEvent ? handleClick : void 0,
31681
+ children: /* @__PURE__ */ jsxs(HStack, { align: "start", justify: "between", children: [
31682
+ /* @__PURE__ */ jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
31683
+ /* @__PURE__ */ jsx(Typography, { variant: "overline", color: "secondary", children: label }),
31684
+ /* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "end", children: [
31685
+ /* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
31686
+ showTrend && /* @__PURE__ */ jsx(
31687
+ Typography,
31688
+ {
31689
+ variant: "caption",
31690
+ className: cn("font-semibold pb-1", trendIsGood ? "text-success" : "text-error"),
31691
+ children: trendLabel
31692
+ }
31693
+ )
31694
+ ] }),
31695
+ showTarget && /* @__PURE__ */ jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
31696
+ Box,
31697
+ {
31698
+ className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
31699
+ style: { width: `${targetPct}%` }
31700
+ }
31701
+ ) })
31702
+ ] }),
31703
+ /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
31704
+ (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 }),
31705
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto" })
31706
+ ] })
31707
+ ] })
31708
+ }
31709
+ );
31048
31710
  };
31049
31711
  StatDisplay.displayName = "StatDisplay";
31050
31712
  }
@@ -45123,6 +45785,7 @@ var init_StatCard = __esm({
45123
45785
  init_Box();
45124
45786
  init_Stack();
45125
45787
  init_Button();
45788
+ init_Sparkline();
45126
45789
  init_useEventBus();
45127
45790
  init_useTranslate();
45128
45791
  init_Icon();
@@ -45292,32 +45955,7 @@ var init_StatCard = __esm({
45292
45955
  ] }),
45293
45956
  /* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
45294
45957
  Icon3 && /* @__PURE__ */ jsx(Box, { className: cn("p-3", iconBg), children: /* @__PURE__ */ jsx(Icon3, { className: cn("h-6 w-6", iconColor) }) }),
45295
- sparklineData && sparklineData.length > 1 && (() => {
45296
- const w = 80;
45297
- const h = 32;
45298
- const pad = 2;
45299
- const min = Math.min(...sparklineData);
45300
- const max = Math.max(...sparklineData);
45301
- const range = max - min || 1;
45302
- const points = sparklineData.map((v, i) => {
45303
- const x = pad + i / (sparklineData.length - 1) * (w - pad * 2);
45304
- const y = pad + (1 - (v - min) / range) * (h - pad * 2);
45305
- return `${x},${y}`;
45306
- }).join(" ");
45307
- const trending = sparklineData[sparklineData.length - 1] >= sparklineData[0];
45308
- const strokeColor = trending ? "var(--color-success)" : "var(--color-error)";
45309
- return /* @__PURE__ */ jsx("svg", { width: w, height: h, viewBox: `0 0 ${w} ${h}`, className: "flex-shrink-0", children: /* @__PURE__ */ jsx(
45310
- "polyline",
45311
- {
45312
- fill: "none",
45313
- stroke: strokeColor,
45314
- strokeWidth: "2",
45315
- strokeLinecap: "round",
45316
- strokeLinejoin: "round",
45317
- points
45318
- }
45319
- ) });
45320
- })()
45958
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto" })
45321
45959
  ] })
45322
45960
  ] }),
45323
45961
  action && /* @__PURE__ */ jsxs(
@@ -52687,6 +53325,7 @@ var init_component_registry_generated = __esm({
52687
53325
  init_DataGrid();
52688
53326
  init_DataList();
52689
53327
  init_DataTable();
53328
+ init_DateRangePicker();
52690
53329
  init_DateRangeSelector();
52691
53330
  init_DayCell();
52692
53331
  init_DebuggerBoard();
@@ -52819,6 +53458,7 @@ var init_component_registry_generated = __esm({
52819
53458
  init_Skeleton();
52820
53459
  init_SocialProof();
52821
53460
  init_SortableList();
53461
+ init_Sparkline();
52822
53462
  init_Split();
52823
53463
  init_SplitPane();
52824
53464
  init_SplitSection();
@@ -52967,6 +53607,7 @@ var init_component_registry_generated = __esm({
52967
53607
  "DataGrid": DataGrid,
52968
53608
  "DataList": DataList,
52969
53609
  "DataTable": DataTable,
53610
+ "DateRangePicker": DateRangePicker,
52970
53611
  "DateRangeSelector": DateRangeSelector,
52971
53612
  "DayCell": DayCell,
52972
53613
  "DebuggerBoard": DebuggerBoard,
@@ -53128,6 +53769,7 @@ var init_component_registry_generated = __esm({
53128
53769
  "SortableList": SortableList,
53129
53770
  "Spacer": SpacerPattern,
53130
53771
  "SpacerPattern": SpacerPattern,
53772
+ "Sparkline": Sparkline,
53131
53773
  "Spinner": SpinnerPattern,
53132
53774
  "SpinnerPattern": SpinnerPattern,
53133
53775
  "Split": Split,
@@ -60434,8 +61076,19 @@ function OrbInspector({ node, schema, editable = false, userType = "builder", th
60434
61076
  /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-muted-foreground text-[10px] uppercase tracking-wider mb-2", children: t("Props") }),
60435
61077
  /* @__PURE__ */ jsx(Box, { className: "flex flex-col gap-1.5", children: Object.entries(patternDef.propsSchema).slice(0, 12).map(([propName, propSchema]) => {
60436
61078
  const ps = propSchema;
60437
- const currentValue = patternConfig ? patternConfig[propName] : void 0;
61079
+ const explicitValue = patternConfig ? patternConfig[propName] : void 0;
61080
+ const defaultValue = ps.default;
61081
+ const isImplicit = explicitValue === void 0 && defaultValue !== void 0;
61082
+ const currentValue = explicitValue !== void 0 ? explicitValue : defaultValue;
60438
61083
  const displayValue = currentValue !== void 0 ? typeof currentValue === "object" ? JSON.stringify(currentValue) : String(currentValue) : "";
61084
+ inspectorLog.debug("prop-row", () => ({
61085
+ patternType: patternDef.type,
61086
+ patternId: selectedPattern?.patternId ?? "",
61087
+ propName,
61088
+ explicitValue: explicitValue === void 0 ? "<unset>" : JSON.stringify(explicitValue),
61089
+ defaultValue: defaultValue === void 0 ? "<unset>" : JSON.stringify(defaultValue),
61090
+ isImplicit: String(isImplicit)
61091
+ }));
60439
61092
  return /* @__PURE__ */ jsxs(Box, { className: "flex items-center gap-2", children: [
60440
61093
  /* @__PURE__ */ jsx(Typography, { variant: "small", className: "text-muted-foreground text-[11px] w-20 shrink-0 font-mono", children: propName }),
60441
61094
  editable ? /* @__PURE__ */ jsx(