@almadar/ui 4.51.13 → 4.51.15

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 })
@@ -28039,6 +28496,151 @@ var init_FlipCard = __esm({
28039
28496
  FlipCard.displayName = "FlipCard";
28040
28497
  }
28041
28498
  });
28499
+ function toISODate(d) {
28500
+ return d.toISOString().slice(0, 10);
28501
+ }
28502
+ function startOfMonth(d) {
28503
+ return new Date(d.getFullYear(), d.getMonth(), 1);
28504
+ }
28505
+ function startOfQuarter(d) {
28506
+ return new Date(d.getFullYear(), Math.floor(d.getMonth() / 3) * 3, 1);
28507
+ }
28508
+ function startOfYear(d) {
28509
+ return new Date(d.getFullYear(), 0, 1);
28510
+ }
28511
+ function daysAgo(n) {
28512
+ const d = /* @__PURE__ */ new Date();
28513
+ d.setDate(d.getDate() - n);
28514
+ return d;
28515
+ }
28516
+ var DEFAULT_PRESETS, DateRangePicker;
28517
+ var init_DateRangePicker = __esm({
28518
+ "components/molecules/DateRangePicker.tsx"() {
28519
+ "use client";
28520
+ init_cn();
28521
+ init_Button();
28522
+ init_Input();
28523
+ init_Stack();
28524
+ init_Typography();
28525
+ init_useEventBus();
28526
+ DEFAULT_PRESETS = [
28527
+ {
28528
+ label: "Last 7 days",
28529
+ value: "7d",
28530
+ range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
28531
+ },
28532
+ {
28533
+ label: "Last 30 days",
28534
+ value: "30d",
28535
+ range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
28536
+ },
28537
+ {
28538
+ label: "This Month",
28539
+ value: "month",
28540
+ range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
28541
+ },
28542
+ {
28543
+ label: "This Quarter",
28544
+ value: "quarter",
28545
+ range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
28546
+ },
28547
+ {
28548
+ label: "YTD",
28549
+ value: "ytd",
28550
+ range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
28551
+ }
28552
+ ];
28553
+ DateRangePicker = ({
28554
+ from: fromProp,
28555
+ to: toProp,
28556
+ event,
28557
+ onChange,
28558
+ presets = DEFAULT_PRESETS,
28559
+ fromLabel = "From",
28560
+ toLabel = "To",
28561
+ className
28562
+ }) => {
28563
+ const eventBus = useEventBus();
28564
+ const [from, setFrom] = React93.useState(fromProp ?? "");
28565
+ const [to, setTo] = React93.useState(toProp ?? "");
28566
+ const [activePreset, setActivePreset] = React93.useState(null);
28567
+ const emit = React93.useCallback(
28568
+ (range) => {
28569
+ onChange?.(range);
28570
+ if (event) eventBus.emit(`UI:${event}`, range);
28571
+ },
28572
+ [onChange, event, eventBus]
28573
+ );
28574
+ const handleFromChange = React93.useCallback(
28575
+ (next) => {
28576
+ setFrom(next);
28577
+ setActivePreset(null);
28578
+ emit({ from: next, to });
28579
+ },
28580
+ [to, emit]
28581
+ );
28582
+ const handleToChange = React93.useCallback(
28583
+ (next) => {
28584
+ setTo(next);
28585
+ setActivePreset(null);
28586
+ emit({ from, to: next });
28587
+ },
28588
+ [from, emit]
28589
+ );
28590
+ const handlePreset = React93.useCallback(
28591
+ (preset) => {
28592
+ const range = preset.range();
28593
+ setFrom(range.from);
28594
+ setTo(range.to);
28595
+ setActivePreset(preset.value);
28596
+ emit(range);
28597
+ },
28598
+ [emit]
28599
+ );
28600
+ const presetButtons = React93.useMemo(
28601
+ () => presets.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
28602
+ Button,
28603
+ {
28604
+ variant: activePreset === preset.value ? "primary" : "ghost",
28605
+ size: "sm",
28606
+ onClick: () => handlePreset(preset),
28607
+ children: preset.label
28608
+ },
28609
+ preset.value
28610
+ )),
28611
+ [presets, activePreset, handlePreset]
28612
+ );
28613
+ return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", className: cn(className), children: [
28614
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "md", align: "end", children: [
28615
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
28616
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: fromLabel }),
28617
+ /* @__PURE__ */ jsxRuntime.jsx(
28618
+ Input,
28619
+ {
28620
+ type: "date",
28621
+ value: from,
28622
+ onChange: (e) => handleFromChange(e.target.value)
28623
+ }
28624
+ )
28625
+ ] }),
28626
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
28627
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: toLabel }),
28628
+ /* @__PURE__ */ jsxRuntime.jsx(
28629
+ Input,
28630
+ {
28631
+ type: "date",
28632
+ value: to,
28633
+ onChange: (e) => handleToChange(e.target.value)
28634
+ }
28635
+ )
28636
+ ] })
28637
+ ] }),
28638
+ presets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
28639
+ ] });
28640
+ };
28641
+ DateRangePicker.displayName = "DateRangePicker";
28642
+ }
28643
+ });
28042
28644
  var DEFAULT_OPTIONS, DateRangeSelector;
28043
28645
  var init_DateRangeSelector = __esm({
28044
28646
  "components/molecules/DateRangeSelector.tsx"() {
@@ -31010,7 +31612,9 @@ var init_StatDisplay = __esm({
31010
31612
  init_Typography();
31011
31613
  init_Box();
31012
31614
  init_Stack();
31615
+ init_Sparkline();
31013
31616
  init_Icon();
31617
+ init_useEventBus();
31014
31618
  variantColor = {
31015
31619
  default: "text-foreground",
31016
31620
  primary: "text-primary",
@@ -31025,6 +31629,10 @@ var init_StatDisplay = __esm({
31025
31629
  max,
31026
31630
  target,
31027
31631
  trend,
31632
+ trendPolarity = "higher-is-better",
31633
+ trendFormat = "absolute",
31634
+ sparklineData,
31635
+ clickEvent,
31028
31636
  prefix,
31029
31637
  suffix,
31030
31638
  icon: iconProp,
@@ -31038,6 +31646,10 @@ var init_StatDisplay = __esm({
31038
31646
  isLoading = false,
31039
31647
  error = null
31040
31648
  }) => {
31649
+ const eventBus = useEventBus();
31650
+ const handleClick = React93.useCallback(() => {
31651
+ if (clickEvent) eventBus.emit(`UI:${clickEvent}`, { metricLabel: label });
31652
+ }, [clickEvent, eventBus, label]);
31041
31653
  const ResolvedIcon = typeof iconProp === "string" ? resolveIcon(iconProp) : null;
31042
31654
  const iconSizes3 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
31043
31655
  const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
@@ -31048,7 +31660,10 @@ var init_StatDisplay = __esm({
31048
31660
  const targetPct = showTarget ? Math.max(0, Math.min(100, numericValue / target * 100)) : 0;
31049
31661
  const showTrend = typeof trend === "number" && trend !== 0 && Number.isFinite(trend);
31050
31662
  const trendUp = showTrend && trend > 0;
31051
- const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${Math.abs(trend)}` : "";
31663
+ const trendIsGood = trendPolarity === "lower-is-better" ? !trendUp : trendUp;
31664
+ const trendMagnitude = Math.abs(trend);
31665
+ const trendSuffix = trendFormat === "percent" ? "%" : "";
31666
+ const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${trendMagnitude}${trendSuffix}` : "";
31052
31667
  if (error) {
31053
31668
  return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "error", children: error.message }) });
31054
31669
  }
@@ -31059,38 +31674,57 @@ var init_StatDisplay = __esm({
31059
31674
  ] }) });
31060
31675
  }
31061
31676
  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
- ] });
31677
+ return /* @__PURE__ */ jsxRuntime.jsxs(
31678
+ HStack,
31679
+ {
31680
+ gap: "sm",
31681
+ className: cn("items-center", clickEvent && "cursor-pointer hover:opacity-80", className),
31682
+ onClick: clickEvent ? handleClick : void 0,
31683
+ children: [
31684
+ ResolvedIcon && /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
31685
+ typeof iconProp !== "string" && iconProp,
31686
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: label }),
31687
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
31688
+ showTrend && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: cn("font-semibold", trendIsGood ? "text-success" : "text-error"), children: trendLabel }),
31689
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto", width: 60, height: 20 })
31690
+ ]
31691
+ }
31692
+ );
31069
31693
  }
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
- ] }) });
31694
+ return /* @__PURE__ */ jsxRuntime.jsx(
31695
+ Card,
31696
+ {
31697
+ className: cn(padSizes[size], clickEvent && "cursor-pointer hover:shadow-md transition-shadow", className),
31698
+ onClick: clickEvent ? handleClick : void 0,
31699
+ children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "start", justify: "between", children: [
31700
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
31701
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "overline", color: "secondary", children: label }),
31702
+ /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "end", children: [
31703
+ /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
31704
+ showTrend && /* @__PURE__ */ jsxRuntime.jsx(
31705
+ Typography,
31706
+ {
31707
+ variant: "caption",
31708
+ className: cn("font-semibold pb-1", trendIsGood ? "text-success" : "text-error"),
31709
+ children: trendLabel
31710
+ }
31711
+ )
31712
+ ] }),
31713
+ showTarget && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
31714
+ Box,
31715
+ {
31716
+ className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
31717
+ style: { width: `${targetPct}%` }
31718
+ }
31719
+ ) })
31720
+ ] }),
31721
+ /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "end", children: [
31722
+ (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 }),
31723
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto" })
31724
+ ] })
31725
+ ] })
31726
+ }
31727
+ );
31094
31728
  };
31095
31729
  StatDisplay.displayName = "StatDisplay";
31096
31730
  }
@@ -45169,6 +45803,7 @@ var init_StatCard = __esm({
45169
45803
  init_Box();
45170
45804
  init_Stack();
45171
45805
  init_Button();
45806
+ init_Sparkline();
45172
45807
  init_useEventBus();
45173
45808
  init_useTranslate();
45174
45809
  init_Icon();
@@ -45338,32 +45973,7 @@ var init_StatCard = __esm({
45338
45973
  ] }),
45339
45974
  /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "end", children: [
45340
45975
  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
- })()
45976
+ sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto" })
45367
45977
  ] })
45368
45978
  ] }),
45369
45979
  action && /* @__PURE__ */ jsxRuntime.jsxs(
@@ -52733,6 +53343,7 @@ var init_component_registry_generated = __esm({
52733
53343
  init_DataGrid();
52734
53344
  init_DataList();
52735
53345
  init_DataTable();
53346
+ init_DateRangePicker();
52736
53347
  init_DateRangeSelector();
52737
53348
  init_DayCell();
52738
53349
  init_DebuggerBoard();
@@ -52865,6 +53476,7 @@ var init_component_registry_generated = __esm({
52865
53476
  init_Skeleton();
52866
53477
  init_SocialProof();
52867
53478
  init_SortableList();
53479
+ init_Sparkline();
52868
53480
  init_Split();
52869
53481
  init_SplitPane();
52870
53482
  init_SplitSection();
@@ -53013,6 +53625,7 @@ var init_component_registry_generated = __esm({
53013
53625
  "DataGrid": DataGrid,
53014
53626
  "DataList": DataList,
53015
53627
  "DataTable": DataTable,
53628
+ "DateRangePicker": DateRangePicker,
53016
53629
  "DateRangeSelector": DateRangeSelector,
53017
53630
  "DayCell": DayCell,
53018
53631
  "DebuggerBoard": DebuggerBoard,
@@ -53174,6 +53787,7 @@ var init_component_registry_generated = __esm({
53174
53787
  "SortableList": SortableList,
53175
53788
  "Spacer": SpacerPattern,
53176
53789
  "SpacerPattern": SpacerPattern,
53790
+ "Sparkline": Sparkline,
53177
53791
  "Spinner": SpinnerPattern,
53178
53792
  "SpinnerPattern": SpinnerPattern,
53179
53793
  "Split": Split,
@@ -60242,7 +60856,8 @@ function findTraits(schema, orbitalName) {
60242
60856
  }
60243
60857
  function findPatternInTree(root, path) {
60244
60858
  if (!path || path === "root") return root;
60245
- const parts = path.split(".");
60859
+ const cleanPath = path.startsWith("root.") ? path.slice("root.".length) : path;
60860
+ const parts = cleanPath.split(".");
60246
60861
  let current = root;
60247
60862
  for (const part of parts) {
60248
60863
  if (current === null || current === void 0 || typeof current !== "object") return null;
@@ -60479,8 +61094,19 @@ function OrbInspector({ node, schema, editable = false, userType = "builder", th
60479
61094
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground text-[10px] uppercase tracking-wider mb-2", children: t("Props") }),
60480
61095
  /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "flex flex-col gap-1.5", children: Object.entries(patternDef.propsSchema).slice(0, 12).map(([propName, propSchema]) => {
60481
61096
  const ps = propSchema;
60482
- const currentValue = patternConfig ? patternConfig[propName] : void 0;
61097
+ const explicitValue = patternConfig ? patternConfig[propName] : void 0;
61098
+ const defaultValue = ps.default;
61099
+ const isImplicit = explicitValue === void 0 && defaultValue !== void 0;
61100
+ const currentValue = explicitValue !== void 0 ? explicitValue : defaultValue;
60483
61101
  const displayValue = currentValue !== void 0 ? typeof currentValue === "object" ? JSON.stringify(currentValue) : String(currentValue) : "";
61102
+ inspectorLog.debug("prop-row", () => ({
61103
+ patternType: patternDef.type,
61104
+ patternId: selectedPattern?.patternId ?? "",
61105
+ propName,
61106
+ explicitValue: explicitValue === void 0 ? "<unset>" : JSON.stringify(explicitValue),
61107
+ defaultValue: defaultValue === void 0 ? "<unset>" : JSON.stringify(defaultValue),
61108
+ isImplicit: String(isImplicit)
61109
+ }));
60484
61110
  return /* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "flex items-center gap-2", children: [
60485
61111
  /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", className: "text-muted-foreground text-[11px] w-20 shrink-0 font-mono", children: propName }),
60486
61112
  editable ? /* @__PURE__ */ jsxRuntime.jsx(