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