@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.
@@ -8464,6 +8464,67 @@ var init_Radio = __esm({
8464
8464
  Radio.displayName = "Radio";
8465
8465
  }
8466
8466
  });
8467
+ var COLOR_VAR, Sparkline;
8468
+ var init_Sparkline = __esm({
8469
+ "components/atoms/Sparkline.tsx"() {
8470
+ init_cn();
8471
+ COLOR_VAR = {
8472
+ primary: "var(--color-primary)",
8473
+ success: "var(--color-success)",
8474
+ warning: "var(--color-warning)",
8475
+ error: "var(--color-error)",
8476
+ info: "var(--color-info)",
8477
+ muted: "var(--color-muted-foreground)"
8478
+ };
8479
+ Sparkline = ({
8480
+ data,
8481
+ color = "auto",
8482
+ width = 80,
8483
+ height = 32,
8484
+ strokeWidth = 2,
8485
+ fill = false,
8486
+ className
8487
+ }) => {
8488
+ if (data.length < 2) return null;
8489
+ const pad = 2;
8490
+ const min = Math.min(...data);
8491
+ const max = Math.max(...data);
8492
+ const range = max - min || 1;
8493
+ const points = data.map((v, i) => {
8494
+ const x = pad + i / (data.length - 1) * (width - pad * 2);
8495
+ const y = pad + (1 - (v - min) / range) * (height - pad * 2);
8496
+ return `${x},${y}`;
8497
+ }).join(" ");
8498
+ const resolvedColor = color === "auto" ? data[data.length - 1] >= data[0] ? COLOR_VAR.success : COLOR_VAR.error : COLOR_VAR[color];
8499
+ const areaPath = fill ? `M ${pad},${height - pad} L ${points.split(" ").join(" L ")} L ${width - pad},${height - pad} Z` : null;
8500
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8501
+ "svg",
8502
+ {
8503
+ width,
8504
+ height,
8505
+ viewBox: `0 0 ${width} ${height}`,
8506
+ className: cn("flex-shrink-0", className),
8507
+ "aria-hidden": "true",
8508
+ children: [
8509
+ areaPath && /* @__PURE__ */ jsxRuntime.jsx("path", { d: areaPath, fill: resolvedColor, opacity: 0.15 }),
8510
+ /* @__PURE__ */ jsxRuntime.jsx(
8511
+ "polyline",
8512
+ {
8513
+ fill: "none",
8514
+ stroke: resolvedColor,
8515
+ strokeWidth,
8516
+ strokeLinecap: "round",
8517
+ strokeLinejoin: "round",
8518
+ points
8519
+ }
8520
+ )
8521
+ ]
8522
+ }
8523
+ );
8524
+ };
8525
+ Sparkline.displayName = "Sparkline";
8526
+ }
8527
+ });
8467
8528
  var Switch;
8468
8529
  var init_Switch = __esm({
8469
8530
  "components/atoms/Switch.tsx"() {
@@ -13697,7 +13758,7 @@ var init_MapView = __esm({
13697
13758
  shadowSize: [41, 41]
13698
13759
  });
13699
13760
  L.Marker.prototype.options.icon = defaultIcon;
13700
- const { useEffect: useEffect87, useRef: useRef88, useCallback: useCallback126, useState: useState120 } = React93__namespace.default;
13761
+ const { useEffect: useEffect87, useRef: useRef88, useCallback: useCallback128, useState: useState121 } = React93__namespace.default;
13701
13762
  const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
13702
13763
  const { useEventBus: useEventBus3 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
13703
13764
  function MapUpdater({ centerLat, centerLng, zoom }) {
@@ -13742,8 +13803,8 @@ var init_MapView = __esm({
13742
13803
  showAttribution = true
13743
13804
  }) {
13744
13805
  const eventBus = useEventBus3();
13745
- const [clickedPosition, setClickedPosition] = useState120(null);
13746
- const handleMapClick = useCallback126((lat, lng) => {
13806
+ const [clickedPosition, setClickedPosition] = useState121(null);
13807
+ const handleMapClick = useCallback128((lat, lng) => {
13747
13808
  if (showClickedPin) {
13748
13809
  setClickedPosition({ lat, lng });
13749
13810
  }
@@ -13752,7 +13813,7 @@ var init_MapView = __esm({
13752
13813
  eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
13753
13814
  }
13754
13815
  }, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
13755
- const handleMarkerClick = useCallback126((marker) => {
13816
+ const handleMarkerClick = useCallback128((marker) => {
13756
13817
  onMarkerClick?.(marker);
13757
13818
  if (markerClickEvent) {
13758
13819
  eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
@@ -22865,7 +22926,7 @@ var init_CastleTemplate = __esm({
22865
22926
  CastleTemplate.displayName = "CastleTemplate";
22866
22927
  }
22867
22928
  });
22868
- var CHART_COLORS, BarChart, PieChart, LineChart, Chart;
22929
+ var CHART_COLORS, seriesColor, monthFormatter, formatTimeLabel, BarChart, PieChart, LineChart, ScatterChart, Chart;
22869
22930
  var init_Chart = __esm({
22870
22931
  "components/organisms/Chart.tsx"() {
22871
22932
  "use client";
@@ -22885,38 +22946,159 @@ var init_Chart = __esm({
22885
22946
  "var(--color-info)",
22886
22947
  "var(--color-accent)"
22887
22948
  ];
22888
- BarChart = ({ data, height, showValues }) => {
22889
- const maxValue = Math.max(...data.map((d) => d.value), 1);
22890
- return /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", align: "end", className: "w-full", style: { height }, children: data.map((point, idx) => {
22891
- const barHeight = point.value / maxValue * 100;
22892
- const color = point.color || CHART_COLORS[idx % CHART_COLORS.length];
22893
- return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "center", flex: true, className: "min-w-0", children: [
22894
- showValues && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: point.value }),
22895
- /* @__PURE__ */ jsxRuntime.jsx(
22896
- Box,
22897
- {
22898
- className: cn(
22899
- "w-full rounded-t-sm transition-all duration-500 ease-out min-h-[4px]"
22900
- ),
22901
- style: {
22902
- height: `${barHeight}%`,
22903
- backgroundColor: color
22904
- }
22949
+ seriesColor = (series, idx) => series.color ?? CHART_COLORS[idx % CHART_COLORS.length];
22950
+ monthFormatter = new Intl.DateTimeFormat(void 0, {
22951
+ month: "short",
22952
+ year: "2-digit"
22953
+ });
22954
+ formatTimeLabel = (raw) => {
22955
+ const parsed = new Date(raw);
22956
+ if (Number.isNaN(parsed.getTime())) return raw;
22957
+ return monthFormatter.format(parsed);
22958
+ };
22959
+ BarChart = ({ series, height, showValues, stack, timeAxis, histogram = false, onPointClick }) => {
22960
+ const categories = React93.useMemo(() => {
22961
+ const set = [];
22962
+ const seen = /* @__PURE__ */ new Set();
22963
+ for (const s of series) {
22964
+ for (const p2 of s.data) {
22965
+ if (!seen.has(p2.label)) {
22966
+ seen.add(p2.label);
22967
+ set.push(p2.label);
22905
22968
  }
22906
- ),
22907
- /* @__PURE__ */ jsxRuntime.jsx(
22908
- Typography,
22909
- {
22910
- variant: "caption",
22911
- color: "secondary",
22912
- className: "truncate w-full text-center",
22913
- children: point.label
22969
+ }
22970
+ }
22971
+ return set;
22972
+ }, [series]);
22973
+ const valueAt = React93.useCallback(
22974
+ (s, label) => {
22975
+ const p2 = s.data.find((d) => d.label === label);
22976
+ return p2 ? p2.value : 0;
22977
+ },
22978
+ []
22979
+ );
22980
+ const columnTotals = React93.useMemo(() => {
22981
+ if (stack === "none") return null;
22982
+ return categories.map(
22983
+ (label) => series.reduce((sum, s) => sum + valueAt(s, label), 0)
22984
+ );
22985
+ }, [categories, series, stack, valueAt]);
22986
+ const maxValue = React93.useMemo(() => {
22987
+ if (stack === "normalize") return 100;
22988
+ if (stack === "stack" && columnTotals) {
22989
+ return Math.max(...columnTotals, 1);
22990
+ }
22991
+ let m = 1;
22992
+ for (const s of series) {
22993
+ for (const p2 of s.data) if (p2.value > m) m = p2.value;
22994
+ }
22995
+ return m;
22996
+ }, [series, stack, columnTotals]);
22997
+ return /* @__PURE__ */ jsxRuntime.jsx(
22998
+ HStack,
22999
+ {
23000
+ gap: histogram ? "none" : "xs",
23001
+ align: "end",
23002
+ className: "w-full",
23003
+ style: { height },
23004
+ children: categories.map((label, catIdx) => {
23005
+ const displayLabel = timeAxis ? formatTimeLabel(label) : label;
23006
+ if (stack === "none") {
23007
+ return /* @__PURE__ */ jsxRuntime.jsxs(
23008
+ VStack,
23009
+ {
23010
+ gap: "xs",
23011
+ align: "center",
23012
+ flex: true,
23013
+ className: "min-w-0",
23014
+ children: [
23015
+ /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: histogram ? "none" : "xs", align: "end", className: "w-full", style: { height: "100%" }, children: series.map((s, sIdx) => {
23016
+ const value = valueAt(s, label);
23017
+ const barHeight = value / maxValue * 100;
23018
+ const color = seriesColor(s, sIdx);
23019
+ return /* @__PURE__ */ jsxRuntime.jsx(
23020
+ Box,
23021
+ {
23022
+ className: cn(
23023
+ "rounded-t-sm transition-all duration-500 ease-out min-h-[4px] cursor-pointer hover:opacity-80",
23024
+ histogram ? "flex-1 mx-0" : "flex-1"
23025
+ ),
23026
+ style: {
23027
+ height: `${barHeight}%`,
23028
+ backgroundColor: color
23029
+ },
23030
+ onClick: () => onPointClick?.(
23031
+ { label, value, color },
23032
+ s.name
23033
+ ),
23034
+ title: `${s.name}: ${value}`
23035
+ },
23036
+ s.name
23037
+ );
23038
+ }) }),
23039
+ showValues && series.length === 1 && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: valueAt(series[0], label) }),
23040
+ /* @__PURE__ */ jsxRuntime.jsx(
23041
+ Typography,
23042
+ {
23043
+ variant: "caption",
23044
+ color: "secondary",
23045
+ className: "truncate w-full text-center",
23046
+ children: displayLabel
23047
+ }
23048
+ )
23049
+ ]
23050
+ },
23051
+ label
23052
+ );
22914
23053
  }
22915
- )
22916
- ] }, point.label);
22917
- }) });
23054
+ const total = columnTotals?.[catIdx] ?? 1;
23055
+ return /* @__PURE__ */ jsxRuntime.jsxs(
23056
+ VStack,
23057
+ {
23058
+ gap: "xs",
23059
+ align: "center",
23060
+ flex: true,
23061
+ className: "min-w-0",
23062
+ children: [
23063
+ /* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "none", className: "w-full", style: { height: "100%" }, justify: "end", children: series.map((s, sIdx) => {
23064
+ const value = valueAt(s, label);
23065
+ const ratio = stack === "normalize" ? total === 0 ? 0 : value / total * 100 : value / maxValue * 100;
23066
+ const color = seriesColor(s, sIdx);
23067
+ return /* @__PURE__ */ jsxRuntime.jsx(
23068
+ Box,
23069
+ {
23070
+ className: "w-full transition-all duration-500 ease-out cursor-pointer hover:opacity-80",
23071
+ style: {
23072
+ height: `${ratio}%`,
23073
+ backgroundColor: color
23074
+ },
23075
+ onClick: () => onPointClick?.(
23076
+ { label, value, color },
23077
+ s.name
23078
+ ),
23079
+ title: `${s.name}: ${value}`
23080
+ },
23081
+ s.name
23082
+ );
23083
+ }) }),
23084
+ /* @__PURE__ */ jsxRuntime.jsx(
23085
+ Typography,
23086
+ {
23087
+ variant: "caption",
23088
+ color: "secondary",
23089
+ className: "truncate w-full text-center",
23090
+ children: displayLabel
23091
+ }
23092
+ )
23093
+ ]
23094
+ },
23095
+ label
23096
+ );
23097
+ })
23098
+ }
23099
+ );
22918
23100
  };
22919
- PieChart = ({ data, height, showValues, donut = false }) => {
23101
+ PieChart = ({ data, height, showValues, donut = false, onPointClick }) => {
22920
23102
  const total = data.reduce((sum, d) => sum + d.value, 0);
22921
23103
  const size = Math.min(height, 200);
22922
23104
  const radius = size / 2 - 8;
@@ -22962,7 +23144,11 @@ var init_Chart = __esm({
22962
23144
  fill: seg.color,
22963
23145
  stroke: "var(--color-card)",
22964
23146
  strokeWidth: "2",
22965
- className: "transition-opacity duration-200 hover:opacity-80"
23147
+ className: "transition-opacity duration-200 hover:opacity-80 cursor-pointer",
23148
+ onClick: () => onPointClick?.(
23149
+ { label: seg.label, value: seg.value, color: seg.color },
23150
+ "default"
23151
+ )
22966
23152
  },
22967
23153
  idx
22968
23154
  )),
@@ -22997,56 +23183,243 @@ var init_Chart = __esm({
22997
23183
  ] }, idx)) })
22998
23184
  ] });
22999
23185
  };
23000
- LineChart = ({ data, height, showValues, fill = false }) => {
23001
- const maxValue = Math.max(...data.map((d) => d.value), 1);
23186
+ LineChart = ({ series, height, showValues, fill = false, timeAxis, onPointClick }) => {
23002
23187
  const width = 400;
23003
23188
  const padding = { top: 20, right: 20, bottom: 30, left: 40 };
23004
23189
  const chartWidth = width - padding.left - padding.right;
23005
23190
  const chartHeight = height - padding.top - padding.bottom;
23006
- const points = React93.useMemo(() => {
23007
- return data.map((point, idx) => ({
23008
- x: padding.left + idx / Math.max(data.length - 1, 1) * chartWidth,
23009
- y: padding.top + chartHeight - point.value / maxValue * chartHeight,
23010
- ...point
23011
- }));
23012
- }, [data, maxValue, chartWidth, chartHeight, padding]);
23013
- const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
23014
- const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
23015
- return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "100%", height, viewBox: `0 0 ${width} ${height}`, preserveAspectRatio: "xMidYMid meet", children: [
23016
- [0, 0.25, 0.5, 0.75, 1].map((frac) => {
23017
- const y = padding.top + chartHeight * (1 - frac);
23018
- return /* @__PURE__ */ jsxRuntime.jsx(
23019
- "line",
23020
- {
23021
- x1: padding.left,
23022
- y1: y,
23023
- x2: width - padding.right,
23024
- y2: y,
23025
- stroke: "var(--color-border)",
23026
- strokeDasharray: "4 4",
23027
- opacity: 0.5
23028
- },
23029
- frac
23030
- );
23031
- }),
23032
- fill && /* @__PURE__ */ jsxRuntime.jsx("path", { d: areaPath, fill: "var(--color-primary)", opacity: 0.1 }),
23033
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: linePath, fill: "none", stroke: "var(--color-primary)", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
23034
- points.map((p2, idx) => /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
23035
- /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: p2.x, cy: p2.y, r: "4", fill: "var(--color-card)", stroke: "var(--color-primary)", strokeWidth: "2" }),
23036
- showValues && /* @__PURE__ */ jsxRuntime.jsx("text", { x: p2.x, y: p2.y - 10, textAnchor: "middle", fill: "var(--color-foreground)", fontSize: "10", fontWeight: "500", children: p2.value }),
23037
- /* @__PURE__ */ jsxRuntime.jsx(
23038
- "text",
23039
- {
23040
- x: p2.x,
23041
- y: height - 8,
23042
- textAnchor: "middle",
23043
- fill: "var(--color-muted-foreground)",
23044
- fontSize: "9",
23045
- children: p2.label
23191
+ const labels = React93.useMemo(() => {
23192
+ const seen = /* @__PURE__ */ new Set();
23193
+ const out = [];
23194
+ for (const s of series) {
23195
+ for (const p2 of s.data) {
23196
+ if (!seen.has(p2.label)) {
23197
+ seen.add(p2.label);
23198
+ out.push(p2.label);
23046
23199
  }
23047
- )
23048
- ] }, idx))
23049
- ] });
23200
+ }
23201
+ }
23202
+ return out;
23203
+ }, [series]);
23204
+ const maxValue = React93.useMemo(() => {
23205
+ let m = 1;
23206
+ for (const s of series) {
23207
+ for (const p2 of s.data) if (p2.value > m) m = p2.value;
23208
+ }
23209
+ return m;
23210
+ }, [series]);
23211
+ const xFor = React93.useCallback(
23212
+ (idx) => padding.left + idx / Math.max(labels.length - 1, 1) * chartWidth,
23213
+ [labels.length, chartWidth, padding.left]
23214
+ );
23215
+ const yFor = React93.useCallback(
23216
+ (value) => padding.top + chartHeight - value / maxValue * chartHeight,
23217
+ [maxValue, chartHeight, padding.top]
23218
+ );
23219
+ return /* @__PURE__ */ jsxRuntime.jsxs(
23220
+ "svg",
23221
+ {
23222
+ width: "100%",
23223
+ height,
23224
+ viewBox: `0 0 ${width} ${height}`,
23225
+ preserveAspectRatio: "xMidYMid meet",
23226
+ children: [
23227
+ [0, 0.25, 0.5, 0.75, 1].map((frac) => {
23228
+ const y = padding.top + chartHeight * (1 - frac);
23229
+ return /* @__PURE__ */ jsxRuntime.jsx(
23230
+ "line",
23231
+ {
23232
+ x1: padding.left,
23233
+ y1: y,
23234
+ x2: width - padding.right,
23235
+ y2: y,
23236
+ stroke: "var(--color-border)",
23237
+ strokeDasharray: "4 4",
23238
+ opacity: 0.5
23239
+ },
23240
+ frac
23241
+ );
23242
+ }),
23243
+ series.map((s, sIdx) => {
23244
+ const color = seriesColor(s, sIdx);
23245
+ const points = labels.map((label, idx) => {
23246
+ const point = s.data.find((d) => d.label === label);
23247
+ return {
23248
+ x: xFor(idx),
23249
+ y: yFor(point ? point.value : 0),
23250
+ value: point ? point.value : 0,
23251
+ label
23252
+ };
23253
+ });
23254
+ const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
23255
+ const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
23256
+ return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
23257
+ fill && /* @__PURE__ */ jsxRuntime.jsx(
23258
+ "path",
23259
+ {
23260
+ d: areaPath,
23261
+ fill: color,
23262
+ opacity: series.length > 1 ? 0.08 : 0.1
23263
+ }
23264
+ ),
23265
+ /* @__PURE__ */ jsxRuntime.jsx(
23266
+ "path",
23267
+ {
23268
+ d: linePath,
23269
+ fill: "none",
23270
+ stroke: color,
23271
+ strokeWidth: "2",
23272
+ strokeLinecap: "round",
23273
+ strokeLinejoin: "round",
23274
+ strokeDasharray: s.dashed ? "6 4" : void 0
23275
+ }
23276
+ ),
23277
+ points.map((p2, idx) => /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
23278
+ /* @__PURE__ */ jsxRuntime.jsx(
23279
+ "circle",
23280
+ {
23281
+ cx: p2.x,
23282
+ cy: p2.y,
23283
+ r: "4",
23284
+ fill: "var(--color-card)",
23285
+ stroke: color,
23286
+ strokeWidth: "2",
23287
+ className: "cursor-pointer",
23288
+ onClick: () => onPointClick?.(
23289
+ { label: p2.label, value: p2.value, color },
23290
+ s.name
23291
+ )
23292
+ }
23293
+ ),
23294
+ showValues && series.length === 1 && /* @__PURE__ */ jsxRuntime.jsx(
23295
+ "text",
23296
+ {
23297
+ x: p2.x,
23298
+ y: p2.y - 10,
23299
+ textAnchor: "middle",
23300
+ fill: "var(--color-foreground)",
23301
+ fontSize: "10",
23302
+ fontWeight: "500",
23303
+ children: p2.value
23304
+ }
23305
+ )
23306
+ ] }, idx))
23307
+ ] }, s.name);
23308
+ }),
23309
+ labels.map((label, idx) => /* @__PURE__ */ jsxRuntime.jsx(
23310
+ "text",
23311
+ {
23312
+ x: xFor(idx),
23313
+ y: height - 8,
23314
+ textAnchor: "middle",
23315
+ fill: "var(--color-muted-foreground)",
23316
+ fontSize: "9",
23317
+ children: timeAxis ? formatTimeLabel(label) : label
23318
+ },
23319
+ label
23320
+ ))
23321
+ ]
23322
+ }
23323
+ );
23324
+ };
23325
+ ScatterChart = ({ data, height, onPointClick }) => {
23326
+ const width = 400;
23327
+ const padding = { top: 20, right: 20, bottom: 30, left: 40 };
23328
+ const chartWidth = width - padding.left - padding.right;
23329
+ const chartHeight = height - padding.top - padding.bottom;
23330
+ const { minX, maxX, minY, maxY } = React93.useMemo(() => {
23331
+ if (data.length === 0) {
23332
+ return { minX: 0, maxX: 1, minY: 0, maxY: 1 };
23333
+ }
23334
+ let mnX = data[0].x;
23335
+ let mxX = data[0].x;
23336
+ let mnY = data[0].y;
23337
+ let mxY = data[0].y;
23338
+ for (const p2 of data) {
23339
+ if (p2.x < mnX) mnX = p2.x;
23340
+ if (p2.x > mxX) mxX = p2.x;
23341
+ if (p2.y < mnY) mnY = p2.y;
23342
+ if (p2.y > mxY) mxY = p2.y;
23343
+ }
23344
+ return { minX: mnX, maxX: mxX, minY: mnY, maxY: mxY };
23345
+ }, [data]);
23346
+ const rangeX = maxX - minX || 1;
23347
+ const rangeY = maxY - minY || 1;
23348
+ return /* @__PURE__ */ jsxRuntime.jsxs(
23349
+ "svg",
23350
+ {
23351
+ width: "100%",
23352
+ height,
23353
+ viewBox: `0 0 ${width} ${height}`,
23354
+ preserveAspectRatio: "xMidYMid meet",
23355
+ children: [
23356
+ [0, 0.25, 0.5, 0.75, 1].map((frac) => {
23357
+ const y = padding.top + chartHeight * (1 - frac);
23358
+ return /* @__PURE__ */ jsxRuntime.jsx(
23359
+ "line",
23360
+ {
23361
+ x1: padding.left,
23362
+ y1: y,
23363
+ x2: width - padding.right,
23364
+ y2: y,
23365
+ stroke: "var(--color-border)",
23366
+ strokeDasharray: "4 4",
23367
+ opacity: 0.5
23368
+ },
23369
+ frac
23370
+ );
23371
+ }),
23372
+ data.map((p2, idx) => {
23373
+ const cx = padding.left + (p2.x - minX) / rangeX * chartWidth;
23374
+ const cy = padding.top + chartHeight - (p2.y - minY) / rangeY * chartHeight;
23375
+ const r2 = p2.size ?? 5;
23376
+ const color = p2.color ?? CHART_COLORS[idx % CHART_COLORS.length];
23377
+ return /* @__PURE__ */ jsxRuntime.jsx(
23378
+ "circle",
23379
+ {
23380
+ cx,
23381
+ cy,
23382
+ r: r2,
23383
+ fill: color,
23384
+ opacity: 0.7,
23385
+ className: "cursor-pointer hover:opacity-100",
23386
+ onClick: () => onPointClick?.(
23387
+ {
23388
+ label: p2.label ?? `(${p2.x}, ${p2.y})`,
23389
+ value: p2.y,
23390
+ color
23391
+ },
23392
+ "default"
23393
+ ),
23394
+ children: /* @__PURE__ */ jsxRuntime.jsx("title", { children: p2.label ?? `(${p2.x}, ${p2.y})` })
23395
+ },
23396
+ idx
23397
+ );
23398
+ }),
23399
+ /* @__PURE__ */ jsxRuntime.jsx(
23400
+ "text",
23401
+ {
23402
+ x: padding.left,
23403
+ y: height - 8,
23404
+ fill: "var(--color-muted-foreground)",
23405
+ fontSize: "9",
23406
+ children: minX.toFixed(1)
23407
+ }
23408
+ ),
23409
+ /* @__PURE__ */ jsxRuntime.jsx(
23410
+ "text",
23411
+ {
23412
+ x: width - padding.right,
23413
+ y: height - 8,
23414
+ textAnchor: "end",
23415
+ fill: "var(--color-muted-foreground)",
23416
+ fontSize: "9",
23417
+ children: maxX.toFixed(1)
23418
+ }
23419
+ )
23420
+ ]
23421
+ }
23422
+ );
23050
23423
  };
23051
23424
  Chart = ({
23052
23425
  title,
@@ -23054,9 +23427,13 @@ var init_Chart = __esm({
23054
23427
  chartType = "bar",
23055
23428
  series,
23056
23429
  data: simpleData,
23430
+ scatterData,
23057
23431
  height = 200,
23058
23432
  showLegend = true,
23059
23433
  showValues = false,
23434
+ stack = "none",
23435
+ timeAxis = false,
23436
+ drillEvent,
23060
23437
  actions,
23061
23438
  entity,
23062
23439
  isLoading = false,
@@ -23073,11 +23450,25 @@ var init_Chart = __esm({
23073
23450
  },
23074
23451
  [eventBus]
23075
23452
  );
23076
- const normalizedData = React93.useMemo(() => {
23077
- if (simpleData) return simpleData;
23078
- if (series && series.length > 0) return series[0].data;
23453
+ const handlePointClick = React93.useCallback(
23454
+ (point, seriesName) => {
23455
+ if (drillEvent) {
23456
+ eventBus.emit(`UI:${drillEvent}`, {
23457
+ label: point.label,
23458
+ value: point.value,
23459
+ seriesLabel: seriesName === "default" ? void 0 : seriesName
23460
+ });
23461
+ }
23462
+ },
23463
+ [drillEvent, eventBus]
23464
+ );
23465
+ const normalizedSeries = React93.useMemo(() => {
23466
+ if (series && series.length > 0) return series;
23467
+ if (simpleData) return [{ name: "default", data: simpleData }];
23079
23468
  return [];
23080
23469
  }, [simpleData, series]);
23470
+ const firstSeriesData = normalizedSeries[0]?.data ?? [];
23471
+ const hasContent = chartType === "scatter" ? (scatterData?.length ?? 0) > 0 : normalizedSeries.some((s) => s.data.length > 0);
23081
23472
  if (isLoading) {
23082
23473
  return /* @__PURE__ */ jsxRuntime.jsx(LoadingState, { message: "Loading chart...", className });
23083
23474
  }
@@ -23091,7 +23482,7 @@ var init_Chart = __esm({
23091
23482
  }
23092
23483
  );
23093
23484
  }
23094
- if (normalizedData.length === 0) {
23485
+ if (!hasContent) {
23095
23486
  return /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { title: t("empty.noData"), description: t("empty.noData"), className });
23096
23487
  }
23097
23488
  return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn("p-6", className), children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "md", children: [
@@ -23112,18 +23503,84 @@ var init_Chart = __esm({
23112
23503
  )) })
23113
23504
  ] }),
23114
23505
  /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "w-full", children: [
23115
- chartType === "bar" && /* @__PURE__ */ jsxRuntime.jsx(BarChart, { data: normalizedData, height, showValues }),
23116
- chartType === "line" && /* @__PURE__ */ jsxRuntime.jsx(LineChart, { data: normalizedData, height, showValues }),
23117
- chartType === "area" && /* @__PURE__ */ jsxRuntime.jsx(LineChart, { data: normalizedData, height, showValues, fill: true }),
23118
- chartType === "pie" && /* @__PURE__ */ jsxRuntime.jsx(PieChart, { data: normalizedData, height, showValues: showLegend }),
23119
- chartType === "donut" && /* @__PURE__ */ jsxRuntime.jsx(PieChart, { data: normalizedData, height, showValues: showLegend, donut: true })
23506
+ chartType === "bar" && /* @__PURE__ */ jsxRuntime.jsx(
23507
+ BarChart,
23508
+ {
23509
+ series: normalizedSeries,
23510
+ height,
23511
+ showValues,
23512
+ stack,
23513
+ timeAxis,
23514
+ onPointClick: handlePointClick
23515
+ }
23516
+ ),
23517
+ chartType === "histogram" && /* @__PURE__ */ jsxRuntime.jsx(
23518
+ BarChart,
23519
+ {
23520
+ series: normalizedSeries,
23521
+ height,
23522
+ showValues,
23523
+ stack: "none",
23524
+ timeAxis: false,
23525
+ histogram: true,
23526
+ onPointClick: handlePointClick
23527
+ }
23528
+ ),
23529
+ chartType === "line" && /* @__PURE__ */ jsxRuntime.jsx(
23530
+ LineChart,
23531
+ {
23532
+ series: normalizedSeries,
23533
+ height,
23534
+ showValues,
23535
+ timeAxis,
23536
+ onPointClick: handlePointClick
23537
+ }
23538
+ ),
23539
+ chartType === "area" && /* @__PURE__ */ jsxRuntime.jsx(
23540
+ LineChart,
23541
+ {
23542
+ series: normalizedSeries,
23543
+ height,
23544
+ showValues,
23545
+ timeAxis,
23546
+ fill: true,
23547
+ onPointClick: handlePointClick
23548
+ }
23549
+ ),
23550
+ chartType === "pie" && /* @__PURE__ */ jsxRuntime.jsx(
23551
+ PieChart,
23552
+ {
23553
+ data: firstSeriesData,
23554
+ height,
23555
+ showValues: showLegend,
23556
+ onPointClick: handlePointClick
23557
+ }
23558
+ ),
23559
+ chartType === "donut" && /* @__PURE__ */ jsxRuntime.jsx(
23560
+ PieChart,
23561
+ {
23562
+ data: firstSeriesData,
23563
+ height,
23564
+ showValues: showLegend,
23565
+ donut: true,
23566
+ onPointClick: handlePointClick
23567
+ }
23568
+ ),
23569
+ chartType === "scatter" && /* @__PURE__ */ jsxRuntime.jsx(
23570
+ ScatterChart,
23571
+ {
23572
+ data: scatterData ?? [],
23573
+ height,
23574
+ onPointClick: handlePointClick
23575
+ }
23576
+ )
23120
23577
  ] }),
23121
- showLegend && series && series.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "md", justify: "center", wrap: true, children: series.map((s, idx) => /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
23578
+ showLegend && normalizedSeries.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "md", justify: "center", wrap: true, children: normalizedSeries.map((s, idx) => /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
23122
23579
  /* @__PURE__ */ jsxRuntime.jsx(
23123
23580
  Box,
23124
23581
  {
23125
23582
  className: "w-3 h-3 rounded-full flex-shrink-0",
23126
- style: { backgroundColor: s.color || CHART_COLORS[idx % CHART_COLORS.length] }
23583
+ style: { backgroundColor: seriesColor(s, idx) }
23127
23584
  }
23128
23585
  ),
23129
23586
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: s.name })
@@ -24984,7 +25441,6 @@ function useDataDnd(args) {
24984
25441
  const raw = it[dndItemIdField];
24985
25442
  return raw ?? `__idx_${idx}`;
24986
25443
  }),
24987
- // eslint-disable-next-line react-hooks/exhaustive-deps
24988
25444
  [itemIdsSignature]
24989
25445
  );
24990
25446
  const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
@@ -26578,7 +27034,16 @@ var init_FilterGroup = __esm({
26578
27034
  onClear: () => handleFilterSelect(`${filter.field}_to`, null)
26579
27035
  }
26580
27036
  )
26581
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(
27037
+ ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
27038
+ Input,
27039
+ {
27040
+ value: selectedValues[filter.field] || "",
27041
+ onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
27042
+ placeholder: filter.label,
27043
+ clearable: true,
27044
+ onClear: () => handleFilterSelect(filter.field, null)
27045
+ }
27046
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
26582
27047
  Select,
26583
27048
  {
26584
27049
  value: selectedValues[filter.field] || "all",
@@ -26645,7 +27110,17 @@ var init_FilterGroup = __esm({
26645
27110
  className: "text-sm min-w-[100px]"
26646
27111
  }
26647
27112
  )
26648
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(
27113
+ ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
27114
+ Input,
27115
+ {
27116
+ value: selectedValues[filter.field] || "",
27117
+ onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
27118
+ placeholder: filter.label,
27119
+ clearable: true,
27120
+ onClear: () => handleFilterSelect(filter.field, null),
27121
+ className: "text-sm"
27122
+ }
27123
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
26649
27124
  Select,
26650
27125
  {
26651
27126
  value: selectedValues[filter.field] || "all",
@@ -26750,7 +27225,17 @@ var init_FilterGroup = __esm({
26750
27225
  className: "min-w-[130px]"
26751
27226
  }
26752
27227
  )
26753
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(
27228
+ ] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
27229
+ Input,
27230
+ {
27231
+ value: selectedValues[filter.field] || "",
27232
+ onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
27233
+ placeholder: filter.label,
27234
+ clearable: true,
27235
+ onClear: () => handleFilterSelect(filter.field, null),
27236
+ className: "min-w-[160px]"
27237
+ }
27238
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
26754
27239
  Select,
26755
27240
  {
26756
27241
  value: selectedValues[filter.field] || "all",
@@ -28039,6 +28524,151 @@ var init_FlipCard = __esm({
28039
28524
  FlipCard.displayName = "FlipCard";
28040
28525
  }
28041
28526
  });
28527
+ function toISODate(d) {
28528
+ return d.toISOString().slice(0, 10);
28529
+ }
28530
+ function startOfMonth(d) {
28531
+ return new Date(d.getFullYear(), d.getMonth(), 1);
28532
+ }
28533
+ function startOfQuarter(d) {
28534
+ return new Date(d.getFullYear(), Math.floor(d.getMonth() / 3) * 3, 1);
28535
+ }
28536
+ function startOfYear(d) {
28537
+ return new Date(d.getFullYear(), 0, 1);
28538
+ }
28539
+ function daysAgo(n) {
28540
+ const d = /* @__PURE__ */ new Date();
28541
+ d.setDate(d.getDate() - n);
28542
+ return d;
28543
+ }
28544
+ var DEFAULT_PRESETS, DateRangePicker;
28545
+ var init_DateRangePicker = __esm({
28546
+ "components/molecules/DateRangePicker.tsx"() {
28547
+ "use client";
28548
+ init_cn();
28549
+ init_Button();
28550
+ init_Input();
28551
+ init_Stack();
28552
+ init_Typography();
28553
+ init_useEventBus();
28554
+ DEFAULT_PRESETS = [
28555
+ {
28556
+ label: "Last 7 days",
28557
+ value: "7d",
28558
+ range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
28559
+ },
28560
+ {
28561
+ label: "Last 30 days",
28562
+ value: "30d",
28563
+ range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
28564
+ },
28565
+ {
28566
+ label: "This Month",
28567
+ value: "month",
28568
+ range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
28569
+ },
28570
+ {
28571
+ label: "This Quarter",
28572
+ value: "quarter",
28573
+ range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
28574
+ },
28575
+ {
28576
+ label: "YTD",
28577
+ value: "ytd",
28578
+ range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
28579
+ }
28580
+ ];
28581
+ DateRangePicker = ({
28582
+ from: fromProp,
28583
+ to: toProp,
28584
+ event,
28585
+ onChange,
28586
+ presets = DEFAULT_PRESETS,
28587
+ fromLabel = "From",
28588
+ toLabel = "To",
28589
+ className
28590
+ }) => {
28591
+ const eventBus = useEventBus();
28592
+ const [from, setFrom] = React93.useState(fromProp ?? "");
28593
+ const [to, setTo] = React93.useState(toProp ?? "");
28594
+ const [activePreset, setActivePreset] = React93.useState(null);
28595
+ const emit = React93.useCallback(
28596
+ (range) => {
28597
+ onChange?.(range);
28598
+ if (event) eventBus.emit(`UI:${event}`, range);
28599
+ },
28600
+ [onChange, event, eventBus]
28601
+ );
28602
+ const handleFromChange = React93.useCallback(
28603
+ (next) => {
28604
+ setFrom(next);
28605
+ setActivePreset(null);
28606
+ emit({ from: next, to });
28607
+ },
28608
+ [to, emit]
28609
+ );
28610
+ const handleToChange = React93.useCallback(
28611
+ (next) => {
28612
+ setTo(next);
28613
+ setActivePreset(null);
28614
+ emit({ from, to: next });
28615
+ },
28616
+ [from, emit]
28617
+ );
28618
+ const handlePreset = React93.useCallback(
28619
+ (preset) => {
28620
+ const range = preset.range();
28621
+ setFrom(range.from);
28622
+ setTo(range.to);
28623
+ setActivePreset(preset.value);
28624
+ emit(range);
28625
+ },
28626
+ [emit]
28627
+ );
28628
+ const presetButtons = React93.useMemo(
28629
+ () => presets.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
28630
+ Button,
28631
+ {
28632
+ variant: activePreset === preset.value ? "primary" : "ghost",
28633
+ size: "sm",
28634
+ onClick: () => handlePreset(preset),
28635
+ children: preset.label
28636
+ },
28637
+ preset.value
28638
+ )),
28639
+ [presets, activePreset, handlePreset]
28640
+ );
28641
+ return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", className: cn(className), children: [
28642
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "md", align: "end", children: [
28643
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
28644
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: fromLabel }),
28645
+ /* @__PURE__ */ jsxRuntime.jsx(
28646
+ Input,
28647
+ {
28648
+ type: "date",
28649
+ value: from,
28650
+ onChange: (e) => handleFromChange(e.target.value)
28651
+ }
28652
+ )
28653
+ ] }),
28654
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
28655
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: toLabel }),
28656
+ /* @__PURE__ */ jsxRuntime.jsx(
28657
+ Input,
28658
+ {
28659
+ type: "date",
28660
+ value: to,
28661
+ onChange: (e) => handleToChange(e.target.value)
28662
+ }
28663
+ )
28664
+ ] })
28665
+ ] }),
28666
+ presets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
28667
+ ] });
28668
+ };
28669
+ DateRangePicker.displayName = "DateRangePicker";
28670
+ }
28671
+ });
28042
28672
  var DEFAULT_OPTIONS, DateRangeSelector;
28043
28673
  var init_DateRangeSelector = __esm({
28044
28674
  "components/molecules/DateRangeSelector.tsx"() {
@@ -31010,7 +31640,9 @@ var init_StatDisplay = __esm({
31010
31640
  init_Typography();
31011
31641
  init_Box();
31012
31642
  init_Stack();
31643
+ init_Sparkline();
31013
31644
  init_Icon();
31645
+ init_useEventBus();
31014
31646
  variantColor = {
31015
31647
  default: "text-foreground",
31016
31648
  primary: "text-primary",
@@ -31025,6 +31657,10 @@ var init_StatDisplay = __esm({
31025
31657
  max,
31026
31658
  target,
31027
31659
  trend,
31660
+ trendPolarity = "higher-is-better",
31661
+ trendFormat = "absolute",
31662
+ sparklineData,
31663
+ clickEvent,
31028
31664
  prefix,
31029
31665
  suffix,
31030
31666
  icon: iconProp,
@@ -31038,6 +31674,10 @@ var init_StatDisplay = __esm({
31038
31674
  isLoading = false,
31039
31675
  error = null
31040
31676
  }) => {
31677
+ const eventBus = useEventBus();
31678
+ const handleClick = React93.useCallback(() => {
31679
+ if (clickEvent) eventBus.emit(`UI:${clickEvent}`, { metricLabel: label });
31680
+ }, [clickEvent, eventBus, label]);
31041
31681
  const ResolvedIcon = typeof iconProp === "string" ? resolveIcon(iconProp) : null;
31042
31682
  const iconSizes3 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
31043
31683
  const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
@@ -31048,7 +31688,10 @@ var init_StatDisplay = __esm({
31048
31688
  const targetPct = showTarget ? Math.max(0, Math.min(100, numericValue / target * 100)) : 0;
31049
31689
  const showTrend = typeof trend === "number" && trend !== 0 && Number.isFinite(trend);
31050
31690
  const trendUp = showTrend && trend > 0;
31051
- const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${Math.abs(trend)}` : "";
31691
+ const trendIsGood = trendPolarity === "lower-is-better" ? !trendUp : trendUp;
31692
+ const trendMagnitude = Math.abs(trend);
31693
+ const trendSuffix = trendFormat === "percent" ? "%" : "";
31694
+ const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${trendMagnitude}${trendSuffix}` : "";
31052
31695
  if (error) {
31053
31696
  return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "error", children: error.message }) });
31054
31697
  }
@@ -31059,38 +31702,57 @@ var init_StatDisplay = __esm({
31059
31702
  ] }) });
31060
31703
  }
31061
31704
  if (compact) {
31062
- return /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", className: cn("items-center", className), children: [
31063
- ResolvedIcon && /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
31064
- typeof iconProp !== "string" && iconProp,
31065
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: label }),
31066
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
31067
- showTrend && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: cn("font-semibold", trendUp ? "text-success" : "text-error"), children: trendLabel })
31068
- ] });
31705
+ return /* @__PURE__ */ jsxRuntime.jsxs(
31706
+ HStack,
31707
+ {
31708
+ gap: "sm",
31709
+ className: cn("items-center", clickEvent && "cursor-pointer hover:opacity-80", className),
31710
+ onClick: clickEvent ? handleClick : void 0,
31711
+ children: [
31712
+ ResolvedIcon && /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
31713
+ typeof iconProp !== "string" && iconProp,
31714
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: label }),
31715
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
31716
+ showTrend && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: cn("font-semibold", trendIsGood ? "text-success" : "text-error"), children: trendLabel }),
31717
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto", width: 60, height: 20 })
31718
+ ]
31719
+ }
31720
+ );
31069
31721
  }
31070
- return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "start", justify: "between", children: [
31071
- /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
31072
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "overline", color: "secondary", children: label }),
31073
- /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "end", children: [
31074
- /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
31075
- showTrend && /* @__PURE__ */ jsxRuntime.jsx(
31076
- Typography,
31077
- {
31078
- variant: "caption",
31079
- className: cn("font-semibold pb-1", trendUp ? "text-success" : "text-error"),
31080
- children: trendLabel
31081
- }
31082
- )
31083
- ] }),
31084
- showTarget && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
31085
- Box,
31086
- {
31087
- className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
31088
- style: { width: `${targetPct}%` }
31089
- }
31090
- ) })
31091
- ] }),
31092
- (ResolvedIcon || typeof iconProp !== "string" && iconProp) && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("p-3 rounded-md", iconBg), children: ResolvedIcon ? /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }) : iconProp })
31093
- ] }) });
31722
+ return /* @__PURE__ */ jsxRuntime.jsx(
31723
+ Card,
31724
+ {
31725
+ className: cn(padSizes[size], clickEvent && "cursor-pointer hover:shadow-md transition-shadow", className),
31726
+ onClick: clickEvent ? handleClick : void 0,
31727
+ children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "start", justify: "between", children: [
31728
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
31729
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "overline", color: "secondary", children: label }),
31730
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "end", children: [
31731
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
31732
+ showTrend && /* @__PURE__ */ jsxRuntime.jsx(
31733
+ Typography,
31734
+ {
31735
+ variant: "caption",
31736
+ className: cn("font-semibold pb-1", trendIsGood ? "text-success" : "text-error"),
31737
+ children: trendLabel
31738
+ }
31739
+ )
31740
+ ] }),
31741
+ showTarget && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
31742
+ Box,
31743
+ {
31744
+ className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
31745
+ style: { width: `${targetPct}%` }
31746
+ }
31747
+ ) })
31748
+ ] }),
31749
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "end", children: [
31750
+ (ResolvedIcon || typeof iconProp !== "string" && iconProp) && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("p-3 rounded-md", iconBg), children: ResolvedIcon ? /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }) : iconProp }),
31751
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto" })
31752
+ ] })
31753
+ ] })
31754
+ }
31755
+ );
31094
31756
  };
31095
31757
  StatDisplay.displayName = "StatDisplay";
31096
31758
  }
@@ -45169,6 +45831,7 @@ var init_StatCard = __esm({
45169
45831
  init_Box();
45170
45832
  init_Stack();
45171
45833
  init_Button();
45834
+ init_Sparkline();
45172
45835
  init_useEventBus();
45173
45836
  init_useTranslate();
45174
45837
  init_Icon();
@@ -45338,32 +46001,7 @@ var init_StatCard = __esm({
45338
46001
  ] }),
45339
46002
  /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "end", children: [
45340
46003
  Icon3 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("p-3", iconBg), children: /* @__PURE__ */ jsxRuntime.jsx(Icon3, { className: cn("h-6 w-6", iconColor) }) }),
45341
- sparklineData && sparklineData.length > 1 && (() => {
45342
- const w = 80;
45343
- const h = 32;
45344
- const pad = 2;
45345
- const min = Math.min(...sparklineData);
45346
- const max = Math.max(...sparklineData);
45347
- const range = max - min || 1;
45348
- const points = sparklineData.map((v, i) => {
45349
- const x = pad + i / (sparklineData.length - 1) * (w - pad * 2);
45350
- const y = pad + (1 - (v - min) / range) * (h - pad * 2);
45351
- return `${x},${y}`;
45352
- }).join(" ");
45353
- const trending = sparklineData[sparklineData.length - 1] >= sparklineData[0];
45354
- const strokeColor = trending ? "var(--color-success)" : "var(--color-error)";
45355
- return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: w, height: h, viewBox: `0 0 ${w} ${h}`, className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
45356
- "polyline",
45357
- {
45358
- fill: "none",
45359
- stroke: strokeColor,
45360
- strokeWidth: "2",
45361
- strokeLinecap: "round",
45362
- strokeLinejoin: "round",
45363
- points
45364
- }
45365
- ) });
45366
- })()
46004
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto" })
45367
46005
  ] })
45368
46006
  ] }),
45369
46007
  action && /* @__PURE__ */ jsxRuntime.jsxs(
@@ -52733,6 +53371,7 @@ var init_component_registry_generated = __esm({
52733
53371
  init_DataGrid();
52734
53372
  init_DataList();
52735
53373
  init_DataTable();
53374
+ init_DateRangePicker();
52736
53375
  init_DateRangeSelector();
52737
53376
  init_DayCell();
52738
53377
  init_DebuggerBoard();
@@ -52865,6 +53504,7 @@ var init_component_registry_generated = __esm({
52865
53504
  init_Skeleton();
52866
53505
  init_SocialProof();
52867
53506
  init_SortableList();
53507
+ init_Sparkline();
52868
53508
  init_Split();
52869
53509
  init_SplitPane();
52870
53510
  init_SplitSection();
@@ -53013,6 +53653,7 @@ var init_component_registry_generated = __esm({
53013
53653
  "DataGrid": DataGrid,
53014
53654
  "DataList": DataList,
53015
53655
  "DataTable": DataTable,
53656
+ "DateRangePicker": DateRangePicker,
53016
53657
  "DateRangeSelector": DateRangeSelector,
53017
53658
  "DayCell": DayCell,
53018
53659
  "DebuggerBoard": DebuggerBoard,
@@ -53174,6 +53815,7 @@ var init_component_registry_generated = __esm({
53174
53815
  "SortableList": SortableList,
53175
53816
  "Spacer": SpacerPattern,
53176
53817
  "SpacerPattern": SpacerPattern,
53818
+ "Sparkline": Sparkline,
53177
53819
  "Spinner": SpinnerPattern,
53178
53820
  "SpinnerPattern": SpinnerPattern,
53179
53821
  "Split": Split,
@@ -60480,8 +61122,19 @@ function OrbInspector({ node, schema, editable = false, userType = "builder", th
60480
61122
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground text-[10px] uppercase tracking-wider mb-2", children: t("Props") }),
60481
61123
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-1.5", children: Object.entries(patternDef.propsSchema).slice(0, 12).map(([propName, propSchema]) => {
60482
61124
  const ps = propSchema;
60483
- const currentValue = patternConfig ? patternConfig[propName] : void 0;
61125
+ const explicitValue = patternConfig ? patternConfig[propName] : void 0;
61126
+ const defaultValue = ps.default;
61127
+ const isImplicit = explicitValue === void 0 && defaultValue !== void 0;
61128
+ const currentValue = explicitValue !== void 0 ? explicitValue : defaultValue;
60484
61129
  const displayValue = currentValue !== void 0 ? typeof currentValue === "object" ? JSON.stringify(currentValue) : String(currentValue) : "";
61130
+ inspectorLog.debug("prop-row", () => ({
61131
+ patternType: patternDef.type,
61132
+ patternId: selectedPattern?.patternId ?? "",
61133
+ propName,
61134
+ explicitValue: explicitValue === void 0 ? "<unset>" : JSON.stringify(explicitValue),
61135
+ defaultValue: defaultValue === void 0 ? "<unset>" : JSON.stringify(defaultValue),
61136
+ isImplicit: String(isImplicit)
61137
+ }));
60485
61138
  return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2", children: [
60486
61139
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground text-[11px] w-20 shrink-0 font-mono", children: propName }),
60487
61140
  editable ? /* @__PURE__ */ jsxRuntime.jsx(