@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.
- package/dist/avl/index.cjs +777 -151
- package/dist/avl/index.js +777 -151
- package/dist/components/atoms/Sparkline.d.ts +30 -0
- package/dist/components/atoms/index.d.ts +1 -0
- package/dist/components/index.cjs +765 -149
- package/dist/components/index.js +766 -150
- package/dist/components/molecules/DateRangePicker.d.ts +56 -0
- package/dist/components/molecules/FilterGroup.d.ts +3 -3
- package/dist/components/molecules/StatDisplay.d.ts +9 -1
- package/dist/components/molecules/index.d.ts +1 -0
- package/dist/components/organisms/Chart.d.ts +32 -12
- package/dist/providers/index.cjs +763 -149
- package/dist/providers/index.js +763 -149
- package/dist/runtime/index.cjs +763 -149
- package/dist/runtime/index.js +763 -149
- package/package.json +1 -1
package/dist/providers/index.js
CHANGED
|
@@ -3603,6 +3603,67 @@ var init_Radio = __esm({
|
|
|
3603
3603
|
Radio.displayName = "Radio";
|
|
3604
3604
|
}
|
|
3605
3605
|
});
|
|
3606
|
+
var COLOR_VAR, Sparkline;
|
|
3607
|
+
var init_Sparkline = __esm({
|
|
3608
|
+
"components/atoms/Sparkline.tsx"() {
|
|
3609
|
+
init_cn();
|
|
3610
|
+
COLOR_VAR = {
|
|
3611
|
+
primary: "var(--color-primary)",
|
|
3612
|
+
success: "var(--color-success)",
|
|
3613
|
+
warning: "var(--color-warning)",
|
|
3614
|
+
error: "var(--color-error)",
|
|
3615
|
+
info: "var(--color-info)",
|
|
3616
|
+
muted: "var(--color-muted-foreground)"
|
|
3617
|
+
};
|
|
3618
|
+
Sparkline = ({
|
|
3619
|
+
data,
|
|
3620
|
+
color = "auto",
|
|
3621
|
+
width = 80,
|
|
3622
|
+
height = 32,
|
|
3623
|
+
strokeWidth = 2,
|
|
3624
|
+
fill = false,
|
|
3625
|
+
className
|
|
3626
|
+
}) => {
|
|
3627
|
+
if (data.length < 2) return null;
|
|
3628
|
+
const pad = 2;
|
|
3629
|
+
const min = Math.min(...data);
|
|
3630
|
+
const max = Math.max(...data);
|
|
3631
|
+
const range = max - min || 1;
|
|
3632
|
+
const points = data.map((v, i) => {
|
|
3633
|
+
const x = pad + i / (data.length - 1) * (width - pad * 2);
|
|
3634
|
+
const y = pad + (1 - (v - min) / range) * (height - pad * 2);
|
|
3635
|
+
return `${x},${y}`;
|
|
3636
|
+
}).join(" ");
|
|
3637
|
+
const resolvedColor = color === "auto" ? data[data.length - 1] >= data[0] ? COLOR_VAR.success : COLOR_VAR.error : COLOR_VAR[color];
|
|
3638
|
+
const areaPath = fill ? `M ${pad},${height - pad} L ${points.split(" ").join(" L ")} L ${width - pad},${height - pad} Z` : null;
|
|
3639
|
+
return /* @__PURE__ */ jsxs(
|
|
3640
|
+
"svg",
|
|
3641
|
+
{
|
|
3642
|
+
width,
|
|
3643
|
+
height,
|
|
3644
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
3645
|
+
className: cn("flex-shrink-0", className),
|
|
3646
|
+
"aria-hidden": "true",
|
|
3647
|
+
children: [
|
|
3648
|
+
areaPath && /* @__PURE__ */ jsx("path", { d: areaPath, fill: resolvedColor, opacity: 0.15 }),
|
|
3649
|
+
/* @__PURE__ */ jsx(
|
|
3650
|
+
"polyline",
|
|
3651
|
+
{
|
|
3652
|
+
fill: "none",
|
|
3653
|
+
stroke: resolvedColor,
|
|
3654
|
+
strokeWidth,
|
|
3655
|
+
strokeLinecap: "round",
|
|
3656
|
+
strokeLinejoin: "round",
|
|
3657
|
+
points
|
|
3658
|
+
}
|
|
3659
|
+
)
|
|
3660
|
+
]
|
|
3661
|
+
}
|
|
3662
|
+
);
|
|
3663
|
+
};
|
|
3664
|
+
Sparkline.displayName = "Sparkline";
|
|
3665
|
+
}
|
|
3666
|
+
});
|
|
3606
3667
|
var Switch;
|
|
3607
3668
|
var init_Switch = __esm({
|
|
3608
3669
|
"components/atoms/Switch.tsx"() {
|
|
@@ -9276,7 +9337,7 @@ var init_MapView = __esm({
|
|
|
9276
9337
|
shadowSize: [41, 41]
|
|
9277
9338
|
});
|
|
9278
9339
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
9279
|
-
const { useEffect: useEffect67, useRef: useRef65, useCallback:
|
|
9340
|
+
const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback112, useState: useState96 } = React81__default;
|
|
9280
9341
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
9281
9342
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
9282
9343
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -9321,8 +9382,8 @@ var init_MapView = __esm({
|
|
|
9321
9382
|
showAttribution = true
|
|
9322
9383
|
}) {
|
|
9323
9384
|
const eventBus = useEventBus2();
|
|
9324
|
-
const [clickedPosition, setClickedPosition] =
|
|
9325
|
-
const handleMapClick =
|
|
9385
|
+
const [clickedPosition, setClickedPosition] = useState96(null);
|
|
9386
|
+
const handleMapClick = useCallback112((lat, lng) => {
|
|
9326
9387
|
if (showClickedPin) {
|
|
9327
9388
|
setClickedPosition({ lat, lng });
|
|
9328
9389
|
}
|
|
@@ -9331,7 +9392,7 @@ var init_MapView = __esm({
|
|
|
9331
9392
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
9332
9393
|
}
|
|
9333
9394
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
9334
|
-
const handleMarkerClick =
|
|
9395
|
+
const handleMarkerClick = useCallback112((marker) => {
|
|
9335
9396
|
onMarkerClick?.(marker);
|
|
9336
9397
|
if (markerClickEvent) {
|
|
9337
9398
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -19231,7 +19292,7 @@ var init_CastleTemplate = __esm({
|
|
|
19231
19292
|
CastleTemplate.displayName = "CastleTemplate";
|
|
19232
19293
|
}
|
|
19233
19294
|
});
|
|
19234
|
-
var CHART_COLORS, BarChart, PieChart, LineChart, Chart;
|
|
19295
|
+
var CHART_COLORS, seriesColor, monthFormatter, formatTimeLabel, BarChart, PieChart, LineChart, ScatterChart, Chart;
|
|
19235
19296
|
var init_Chart = __esm({
|
|
19236
19297
|
"components/organisms/Chart.tsx"() {
|
|
19237
19298
|
"use client";
|
|
@@ -19251,38 +19312,159 @@ var init_Chart = __esm({
|
|
|
19251
19312
|
"var(--color-info)",
|
|
19252
19313
|
"var(--color-accent)"
|
|
19253
19314
|
];
|
|
19254
|
-
|
|
19255
|
-
|
|
19256
|
-
|
|
19257
|
-
|
|
19258
|
-
|
|
19259
|
-
|
|
19260
|
-
|
|
19261
|
-
|
|
19262
|
-
|
|
19263
|
-
|
|
19264
|
-
|
|
19265
|
-
|
|
19266
|
-
|
|
19267
|
-
|
|
19268
|
-
|
|
19269
|
-
|
|
19270
|
-
|
|
19315
|
+
seriesColor = (series, idx) => series.color ?? CHART_COLORS[idx % CHART_COLORS.length];
|
|
19316
|
+
monthFormatter = new Intl.DateTimeFormat(void 0, {
|
|
19317
|
+
month: "short",
|
|
19318
|
+
year: "2-digit"
|
|
19319
|
+
});
|
|
19320
|
+
formatTimeLabel = (raw) => {
|
|
19321
|
+
const parsed = new Date(raw);
|
|
19322
|
+
if (Number.isNaN(parsed.getTime())) return raw;
|
|
19323
|
+
return monthFormatter.format(parsed);
|
|
19324
|
+
};
|
|
19325
|
+
BarChart = ({ series, height, showValues, stack, timeAxis, histogram = false, onPointClick }) => {
|
|
19326
|
+
const categories = useMemo(() => {
|
|
19327
|
+
const set = [];
|
|
19328
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19329
|
+
for (const s of series) {
|
|
19330
|
+
for (const p2 of s.data) {
|
|
19331
|
+
if (!seen.has(p2.label)) {
|
|
19332
|
+
seen.add(p2.label);
|
|
19333
|
+
set.push(p2.label);
|
|
19271
19334
|
}
|
|
19272
|
-
|
|
19273
|
-
|
|
19274
|
-
|
|
19275
|
-
|
|
19276
|
-
|
|
19277
|
-
|
|
19278
|
-
|
|
19279
|
-
|
|
19335
|
+
}
|
|
19336
|
+
}
|
|
19337
|
+
return set;
|
|
19338
|
+
}, [series]);
|
|
19339
|
+
const valueAt = useCallback(
|
|
19340
|
+
(s, label) => {
|
|
19341
|
+
const p2 = s.data.find((d) => d.label === label);
|
|
19342
|
+
return p2 ? p2.value : 0;
|
|
19343
|
+
},
|
|
19344
|
+
[]
|
|
19345
|
+
);
|
|
19346
|
+
const columnTotals = useMemo(() => {
|
|
19347
|
+
if (stack === "none") return null;
|
|
19348
|
+
return categories.map(
|
|
19349
|
+
(label) => series.reduce((sum, s) => sum + valueAt(s, label), 0)
|
|
19350
|
+
);
|
|
19351
|
+
}, [categories, series, stack, valueAt]);
|
|
19352
|
+
const maxValue = useMemo(() => {
|
|
19353
|
+
if (stack === "normalize") return 100;
|
|
19354
|
+
if (stack === "stack" && columnTotals) {
|
|
19355
|
+
return Math.max(...columnTotals, 1);
|
|
19356
|
+
}
|
|
19357
|
+
let m = 1;
|
|
19358
|
+
for (const s of series) {
|
|
19359
|
+
for (const p2 of s.data) if (p2.value > m) m = p2.value;
|
|
19360
|
+
}
|
|
19361
|
+
return m;
|
|
19362
|
+
}, [series, stack, columnTotals]);
|
|
19363
|
+
return /* @__PURE__ */ jsx(
|
|
19364
|
+
HStack,
|
|
19365
|
+
{
|
|
19366
|
+
gap: histogram ? "none" : "xs",
|
|
19367
|
+
align: "end",
|
|
19368
|
+
className: "w-full",
|
|
19369
|
+
style: { height },
|
|
19370
|
+
children: categories.map((label, catIdx) => {
|
|
19371
|
+
const displayLabel = timeAxis ? formatTimeLabel(label) : label;
|
|
19372
|
+
if (stack === "none") {
|
|
19373
|
+
return /* @__PURE__ */ jsxs(
|
|
19374
|
+
VStack,
|
|
19375
|
+
{
|
|
19376
|
+
gap: "xs",
|
|
19377
|
+
align: "center",
|
|
19378
|
+
flex: true,
|
|
19379
|
+
className: "min-w-0",
|
|
19380
|
+
children: [
|
|
19381
|
+
/* @__PURE__ */ jsx(HStack, { gap: histogram ? "none" : "xs", align: "end", className: "w-full", style: { height: "100%" }, children: series.map((s, sIdx) => {
|
|
19382
|
+
const value = valueAt(s, label);
|
|
19383
|
+
const barHeight = value / maxValue * 100;
|
|
19384
|
+
const color = seriesColor(s, sIdx);
|
|
19385
|
+
return /* @__PURE__ */ jsx(
|
|
19386
|
+
Box,
|
|
19387
|
+
{
|
|
19388
|
+
className: cn(
|
|
19389
|
+
"rounded-t-sm transition-all duration-500 ease-out min-h-[4px] cursor-pointer hover:opacity-80",
|
|
19390
|
+
histogram ? "flex-1 mx-0" : "flex-1"
|
|
19391
|
+
),
|
|
19392
|
+
style: {
|
|
19393
|
+
height: `${barHeight}%`,
|
|
19394
|
+
backgroundColor: color
|
|
19395
|
+
},
|
|
19396
|
+
onClick: () => onPointClick?.(
|
|
19397
|
+
{ label, value, color },
|
|
19398
|
+
s.name
|
|
19399
|
+
),
|
|
19400
|
+
title: `${s.name}: ${value}`
|
|
19401
|
+
},
|
|
19402
|
+
s.name
|
|
19403
|
+
);
|
|
19404
|
+
}) }),
|
|
19405
|
+
showValues && series.length === 1 && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: valueAt(series[0], label) }),
|
|
19406
|
+
/* @__PURE__ */ jsx(
|
|
19407
|
+
Typography,
|
|
19408
|
+
{
|
|
19409
|
+
variant: "caption",
|
|
19410
|
+
color: "secondary",
|
|
19411
|
+
className: "truncate w-full text-center",
|
|
19412
|
+
children: displayLabel
|
|
19413
|
+
}
|
|
19414
|
+
)
|
|
19415
|
+
]
|
|
19416
|
+
},
|
|
19417
|
+
label
|
|
19418
|
+
);
|
|
19280
19419
|
}
|
|
19281
|
-
|
|
19282
|
-
|
|
19283
|
-
|
|
19420
|
+
const total = columnTotals?.[catIdx] ?? 1;
|
|
19421
|
+
return /* @__PURE__ */ jsxs(
|
|
19422
|
+
VStack,
|
|
19423
|
+
{
|
|
19424
|
+
gap: "xs",
|
|
19425
|
+
align: "center",
|
|
19426
|
+
flex: true,
|
|
19427
|
+
className: "min-w-0",
|
|
19428
|
+
children: [
|
|
19429
|
+
/* @__PURE__ */ jsx(VStack, { gap: "none", className: "w-full", style: { height: "100%" }, justify: "end", children: series.map((s, sIdx) => {
|
|
19430
|
+
const value = valueAt(s, label);
|
|
19431
|
+
const ratio = stack === "normalize" ? total === 0 ? 0 : value / total * 100 : value / maxValue * 100;
|
|
19432
|
+
const color = seriesColor(s, sIdx);
|
|
19433
|
+
return /* @__PURE__ */ jsx(
|
|
19434
|
+
Box,
|
|
19435
|
+
{
|
|
19436
|
+
className: "w-full transition-all duration-500 ease-out cursor-pointer hover:opacity-80",
|
|
19437
|
+
style: {
|
|
19438
|
+
height: `${ratio}%`,
|
|
19439
|
+
backgroundColor: color
|
|
19440
|
+
},
|
|
19441
|
+
onClick: () => onPointClick?.(
|
|
19442
|
+
{ label, value, color },
|
|
19443
|
+
s.name
|
|
19444
|
+
),
|
|
19445
|
+
title: `${s.name}: ${value}`
|
|
19446
|
+
},
|
|
19447
|
+
s.name
|
|
19448
|
+
);
|
|
19449
|
+
}) }),
|
|
19450
|
+
/* @__PURE__ */ jsx(
|
|
19451
|
+
Typography,
|
|
19452
|
+
{
|
|
19453
|
+
variant: "caption",
|
|
19454
|
+
color: "secondary",
|
|
19455
|
+
className: "truncate w-full text-center",
|
|
19456
|
+
children: displayLabel
|
|
19457
|
+
}
|
|
19458
|
+
)
|
|
19459
|
+
]
|
|
19460
|
+
},
|
|
19461
|
+
label
|
|
19462
|
+
);
|
|
19463
|
+
})
|
|
19464
|
+
}
|
|
19465
|
+
);
|
|
19284
19466
|
};
|
|
19285
|
-
PieChart = ({ data, height, showValues, donut = false }) => {
|
|
19467
|
+
PieChart = ({ data, height, showValues, donut = false, onPointClick }) => {
|
|
19286
19468
|
const total = data.reduce((sum, d) => sum + d.value, 0);
|
|
19287
19469
|
const size = Math.min(height, 200);
|
|
19288
19470
|
const radius = size / 2 - 8;
|
|
@@ -19328,7 +19510,11 @@ var init_Chart = __esm({
|
|
|
19328
19510
|
fill: seg.color,
|
|
19329
19511
|
stroke: "var(--color-card)",
|
|
19330
19512
|
strokeWidth: "2",
|
|
19331
|
-
className: "transition-opacity duration-200 hover:opacity-80"
|
|
19513
|
+
className: "transition-opacity duration-200 hover:opacity-80 cursor-pointer",
|
|
19514
|
+
onClick: () => onPointClick?.(
|
|
19515
|
+
{ label: seg.label, value: seg.value, color: seg.color },
|
|
19516
|
+
"default"
|
|
19517
|
+
)
|
|
19332
19518
|
},
|
|
19333
19519
|
idx
|
|
19334
19520
|
)),
|
|
@@ -19363,56 +19549,243 @@ var init_Chart = __esm({
|
|
|
19363
19549
|
] }, idx)) })
|
|
19364
19550
|
] });
|
|
19365
19551
|
};
|
|
19366
|
-
LineChart = ({
|
|
19367
|
-
const maxValue = Math.max(...data.map((d) => d.value), 1);
|
|
19552
|
+
LineChart = ({ series, height, showValues, fill = false, timeAxis, onPointClick }) => {
|
|
19368
19553
|
const width = 400;
|
|
19369
19554
|
const padding = { top: 20, right: 20, bottom: 30, left: 40 };
|
|
19370
19555
|
const chartWidth = width - padding.left - padding.right;
|
|
19371
19556
|
const chartHeight = height - padding.top - padding.bottom;
|
|
19372
|
-
const
|
|
19373
|
-
|
|
19374
|
-
|
|
19375
|
-
|
|
19376
|
-
|
|
19377
|
-
|
|
19378
|
-
|
|
19379
|
-
|
|
19380
|
-
const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
|
|
19381
|
-
return /* @__PURE__ */ jsxs("svg", { width: "100%", height, viewBox: `0 0 ${width} ${height}`, preserveAspectRatio: "xMidYMid meet", children: [
|
|
19382
|
-
[0, 0.25, 0.5, 0.75, 1].map((frac) => {
|
|
19383
|
-
const y = padding.top + chartHeight * (1 - frac);
|
|
19384
|
-
return /* @__PURE__ */ jsx(
|
|
19385
|
-
"line",
|
|
19386
|
-
{
|
|
19387
|
-
x1: padding.left,
|
|
19388
|
-
y1: y,
|
|
19389
|
-
x2: width - padding.right,
|
|
19390
|
-
y2: y,
|
|
19391
|
-
stroke: "var(--color-border)",
|
|
19392
|
-
strokeDasharray: "4 4",
|
|
19393
|
-
opacity: 0.5
|
|
19394
|
-
},
|
|
19395
|
-
frac
|
|
19396
|
-
);
|
|
19397
|
-
}),
|
|
19398
|
-
fill && /* @__PURE__ */ jsx("path", { d: areaPath, fill: "var(--color-primary)", opacity: 0.1 }),
|
|
19399
|
-
/* @__PURE__ */ jsx("path", { d: linePath, fill: "none", stroke: "var(--color-primary)", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
19400
|
-
points.map((p2, idx) => /* @__PURE__ */ jsxs("g", { children: [
|
|
19401
|
-
/* @__PURE__ */ jsx("circle", { cx: p2.x, cy: p2.y, r: "4", fill: "var(--color-card)", stroke: "var(--color-primary)", strokeWidth: "2" }),
|
|
19402
|
-
showValues && /* @__PURE__ */ jsx("text", { x: p2.x, y: p2.y - 10, textAnchor: "middle", fill: "var(--color-foreground)", fontSize: "10", fontWeight: "500", children: p2.value }),
|
|
19403
|
-
/* @__PURE__ */ jsx(
|
|
19404
|
-
"text",
|
|
19405
|
-
{
|
|
19406
|
-
x: p2.x,
|
|
19407
|
-
y: height - 8,
|
|
19408
|
-
textAnchor: "middle",
|
|
19409
|
-
fill: "var(--color-muted-foreground)",
|
|
19410
|
-
fontSize: "9",
|
|
19411
|
-
children: p2.label
|
|
19557
|
+
const labels = useMemo(() => {
|
|
19558
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19559
|
+
const out = [];
|
|
19560
|
+
for (const s of series) {
|
|
19561
|
+
for (const p2 of s.data) {
|
|
19562
|
+
if (!seen.has(p2.label)) {
|
|
19563
|
+
seen.add(p2.label);
|
|
19564
|
+
out.push(p2.label);
|
|
19412
19565
|
}
|
|
19413
|
-
|
|
19414
|
-
|
|
19415
|
-
|
|
19566
|
+
}
|
|
19567
|
+
}
|
|
19568
|
+
return out;
|
|
19569
|
+
}, [series]);
|
|
19570
|
+
const maxValue = useMemo(() => {
|
|
19571
|
+
let m = 1;
|
|
19572
|
+
for (const s of series) {
|
|
19573
|
+
for (const p2 of s.data) if (p2.value > m) m = p2.value;
|
|
19574
|
+
}
|
|
19575
|
+
return m;
|
|
19576
|
+
}, [series]);
|
|
19577
|
+
const xFor = useCallback(
|
|
19578
|
+
(idx) => padding.left + idx / Math.max(labels.length - 1, 1) * chartWidth,
|
|
19579
|
+
[labels.length, chartWidth, padding.left]
|
|
19580
|
+
);
|
|
19581
|
+
const yFor = useCallback(
|
|
19582
|
+
(value) => padding.top + chartHeight - value / maxValue * chartHeight,
|
|
19583
|
+
[maxValue, chartHeight, padding.top]
|
|
19584
|
+
);
|
|
19585
|
+
return /* @__PURE__ */ jsxs(
|
|
19586
|
+
"svg",
|
|
19587
|
+
{
|
|
19588
|
+
width: "100%",
|
|
19589
|
+
height,
|
|
19590
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
19591
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
19592
|
+
children: [
|
|
19593
|
+
[0, 0.25, 0.5, 0.75, 1].map((frac) => {
|
|
19594
|
+
const y = padding.top + chartHeight * (1 - frac);
|
|
19595
|
+
return /* @__PURE__ */ jsx(
|
|
19596
|
+
"line",
|
|
19597
|
+
{
|
|
19598
|
+
x1: padding.left,
|
|
19599
|
+
y1: y,
|
|
19600
|
+
x2: width - padding.right,
|
|
19601
|
+
y2: y,
|
|
19602
|
+
stroke: "var(--color-border)",
|
|
19603
|
+
strokeDasharray: "4 4",
|
|
19604
|
+
opacity: 0.5
|
|
19605
|
+
},
|
|
19606
|
+
frac
|
|
19607
|
+
);
|
|
19608
|
+
}),
|
|
19609
|
+
series.map((s, sIdx) => {
|
|
19610
|
+
const color = seriesColor(s, sIdx);
|
|
19611
|
+
const points = labels.map((label, idx) => {
|
|
19612
|
+
const point = s.data.find((d) => d.label === label);
|
|
19613
|
+
return {
|
|
19614
|
+
x: xFor(idx),
|
|
19615
|
+
y: yFor(point ? point.value : 0),
|
|
19616
|
+
value: point ? point.value : 0,
|
|
19617
|
+
label
|
|
19618
|
+
};
|
|
19619
|
+
});
|
|
19620
|
+
const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
|
|
19621
|
+
const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
|
|
19622
|
+
return /* @__PURE__ */ jsxs("g", { children: [
|
|
19623
|
+
fill && /* @__PURE__ */ jsx(
|
|
19624
|
+
"path",
|
|
19625
|
+
{
|
|
19626
|
+
d: areaPath,
|
|
19627
|
+
fill: color,
|
|
19628
|
+
opacity: series.length > 1 ? 0.08 : 0.1
|
|
19629
|
+
}
|
|
19630
|
+
),
|
|
19631
|
+
/* @__PURE__ */ jsx(
|
|
19632
|
+
"path",
|
|
19633
|
+
{
|
|
19634
|
+
d: linePath,
|
|
19635
|
+
fill: "none",
|
|
19636
|
+
stroke: color,
|
|
19637
|
+
strokeWidth: "2",
|
|
19638
|
+
strokeLinecap: "round",
|
|
19639
|
+
strokeLinejoin: "round",
|
|
19640
|
+
strokeDasharray: s.dashed ? "6 4" : void 0
|
|
19641
|
+
}
|
|
19642
|
+
),
|
|
19643
|
+
points.map((p2, idx) => /* @__PURE__ */ jsxs("g", { children: [
|
|
19644
|
+
/* @__PURE__ */ jsx(
|
|
19645
|
+
"circle",
|
|
19646
|
+
{
|
|
19647
|
+
cx: p2.x,
|
|
19648
|
+
cy: p2.y,
|
|
19649
|
+
r: "4",
|
|
19650
|
+
fill: "var(--color-card)",
|
|
19651
|
+
stroke: color,
|
|
19652
|
+
strokeWidth: "2",
|
|
19653
|
+
className: "cursor-pointer",
|
|
19654
|
+
onClick: () => onPointClick?.(
|
|
19655
|
+
{ label: p2.label, value: p2.value, color },
|
|
19656
|
+
s.name
|
|
19657
|
+
)
|
|
19658
|
+
}
|
|
19659
|
+
),
|
|
19660
|
+
showValues && series.length === 1 && /* @__PURE__ */ jsx(
|
|
19661
|
+
"text",
|
|
19662
|
+
{
|
|
19663
|
+
x: p2.x,
|
|
19664
|
+
y: p2.y - 10,
|
|
19665
|
+
textAnchor: "middle",
|
|
19666
|
+
fill: "var(--color-foreground)",
|
|
19667
|
+
fontSize: "10",
|
|
19668
|
+
fontWeight: "500",
|
|
19669
|
+
children: p2.value
|
|
19670
|
+
}
|
|
19671
|
+
)
|
|
19672
|
+
] }, idx))
|
|
19673
|
+
] }, s.name);
|
|
19674
|
+
}),
|
|
19675
|
+
labels.map((label, idx) => /* @__PURE__ */ jsx(
|
|
19676
|
+
"text",
|
|
19677
|
+
{
|
|
19678
|
+
x: xFor(idx),
|
|
19679
|
+
y: height - 8,
|
|
19680
|
+
textAnchor: "middle",
|
|
19681
|
+
fill: "var(--color-muted-foreground)",
|
|
19682
|
+
fontSize: "9",
|
|
19683
|
+
children: timeAxis ? formatTimeLabel(label) : label
|
|
19684
|
+
},
|
|
19685
|
+
label
|
|
19686
|
+
))
|
|
19687
|
+
]
|
|
19688
|
+
}
|
|
19689
|
+
);
|
|
19690
|
+
};
|
|
19691
|
+
ScatterChart = ({ data, height, onPointClick }) => {
|
|
19692
|
+
const width = 400;
|
|
19693
|
+
const padding = { top: 20, right: 20, bottom: 30, left: 40 };
|
|
19694
|
+
const chartWidth = width - padding.left - padding.right;
|
|
19695
|
+
const chartHeight = height - padding.top - padding.bottom;
|
|
19696
|
+
const { minX, maxX, minY, maxY } = useMemo(() => {
|
|
19697
|
+
if (data.length === 0) {
|
|
19698
|
+
return { minX: 0, maxX: 1, minY: 0, maxY: 1 };
|
|
19699
|
+
}
|
|
19700
|
+
let mnX = data[0].x;
|
|
19701
|
+
let mxX = data[0].x;
|
|
19702
|
+
let mnY = data[0].y;
|
|
19703
|
+
let mxY = data[0].y;
|
|
19704
|
+
for (const p2 of data) {
|
|
19705
|
+
if (p2.x < mnX) mnX = p2.x;
|
|
19706
|
+
if (p2.x > mxX) mxX = p2.x;
|
|
19707
|
+
if (p2.y < mnY) mnY = p2.y;
|
|
19708
|
+
if (p2.y > mxY) mxY = p2.y;
|
|
19709
|
+
}
|
|
19710
|
+
return { minX: mnX, maxX: mxX, minY: mnY, maxY: mxY };
|
|
19711
|
+
}, [data]);
|
|
19712
|
+
const rangeX = maxX - minX || 1;
|
|
19713
|
+
const rangeY = maxY - minY || 1;
|
|
19714
|
+
return /* @__PURE__ */ jsxs(
|
|
19715
|
+
"svg",
|
|
19716
|
+
{
|
|
19717
|
+
width: "100%",
|
|
19718
|
+
height,
|
|
19719
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
19720
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
19721
|
+
children: [
|
|
19722
|
+
[0, 0.25, 0.5, 0.75, 1].map((frac) => {
|
|
19723
|
+
const y = padding.top + chartHeight * (1 - frac);
|
|
19724
|
+
return /* @__PURE__ */ jsx(
|
|
19725
|
+
"line",
|
|
19726
|
+
{
|
|
19727
|
+
x1: padding.left,
|
|
19728
|
+
y1: y,
|
|
19729
|
+
x2: width - padding.right,
|
|
19730
|
+
y2: y,
|
|
19731
|
+
stroke: "var(--color-border)",
|
|
19732
|
+
strokeDasharray: "4 4",
|
|
19733
|
+
opacity: 0.5
|
|
19734
|
+
},
|
|
19735
|
+
frac
|
|
19736
|
+
);
|
|
19737
|
+
}),
|
|
19738
|
+
data.map((p2, idx) => {
|
|
19739
|
+
const cx = padding.left + (p2.x - minX) / rangeX * chartWidth;
|
|
19740
|
+
const cy = padding.top + chartHeight - (p2.y - minY) / rangeY * chartHeight;
|
|
19741
|
+
const r = p2.size ?? 5;
|
|
19742
|
+
const color = p2.color ?? CHART_COLORS[idx % CHART_COLORS.length];
|
|
19743
|
+
return /* @__PURE__ */ jsx(
|
|
19744
|
+
"circle",
|
|
19745
|
+
{
|
|
19746
|
+
cx,
|
|
19747
|
+
cy,
|
|
19748
|
+
r,
|
|
19749
|
+
fill: color,
|
|
19750
|
+
opacity: 0.7,
|
|
19751
|
+
className: "cursor-pointer hover:opacity-100",
|
|
19752
|
+
onClick: () => onPointClick?.(
|
|
19753
|
+
{
|
|
19754
|
+
label: p2.label ?? `(${p2.x}, ${p2.y})`,
|
|
19755
|
+
value: p2.y,
|
|
19756
|
+
color
|
|
19757
|
+
},
|
|
19758
|
+
"default"
|
|
19759
|
+
),
|
|
19760
|
+
children: /* @__PURE__ */ jsx("title", { children: p2.label ?? `(${p2.x}, ${p2.y})` })
|
|
19761
|
+
},
|
|
19762
|
+
idx
|
|
19763
|
+
);
|
|
19764
|
+
}),
|
|
19765
|
+
/* @__PURE__ */ jsx(
|
|
19766
|
+
"text",
|
|
19767
|
+
{
|
|
19768
|
+
x: padding.left,
|
|
19769
|
+
y: height - 8,
|
|
19770
|
+
fill: "var(--color-muted-foreground)",
|
|
19771
|
+
fontSize: "9",
|
|
19772
|
+
children: minX.toFixed(1)
|
|
19773
|
+
}
|
|
19774
|
+
),
|
|
19775
|
+
/* @__PURE__ */ jsx(
|
|
19776
|
+
"text",
|
|
19777
|
+
{
|
|
19778
|
+
x: width - padding.right,
|
|
19779
|
+
y: height - 8,
|
|
19780
|
+
textAnchor: "end",
|
|
19781
|
+
fill: "var(--color-muted-foreground)",
|
|
19782
|
+
fontSize: "9",
|
|
19783
|
+
children: maxX.toFixed(1)
|
|
19784
|
+
}
|
|
19785
|
+
)
|
|
19786
|
+
]
|
|
19787
|
+
}
|
|
19788
|
+
);
|
|
19416
19789
|
};
|
|
19417
19790
|
Chart = ({
|
|
19418
19791
|
title,
|
|
@@ -19420,9 +19793,13 @@ var init_Chart = __esm({
|
|
|
19420
19793
|
chartType = "bar",
|
|
19421
19794
|
series,
|
|
19422
19795
|
data: simpleData,
|
|
19796
|
+
scatterData,
|
|
19423
19797
|
height = 200,
|
|
19424
19798
|
showLegend = true,
|
|
19425
19799
|
showValues = false,
|
|
19800
|
+
stack = "none",
|
|
19801
|
+
timeAxis = false,
|
|
19802
|
+
drillEvent,
|
|
19426
19803
|
actions,
|
|
19427
19804
|
entity,
|
|
19428
19805
|
isLoading = false,
|
|
@@ -19439,11 +19816,25 @@ var init_Chart = __esm({
|
|
|
19439
19816
|
},
|
|
19440
19817
|
[eventBus]
|
|
19441
19818
|
);
|
|
19442
|
-
const
|
|
19443
|
-
|
|
19444
|
-
|
|
19819
|
+
const handlePointClick = useCallback(
|
|
19820
|
+
(point, seriesName) => {
|
|
19821
|
+
if (drillEvent) {
|
|
19822
|
+
eventBus.emit(`UI:${drillEvent}`, {
|
|
19823
|
+
label: point.label,
|
|
19824
|
+
value: point.value,
|
|
19825
|
+
seriesLabel: seriesName === "default" ? void 0 : seriesName
|
|
19826
|
+
});
|
|
19827
|
+
}
|
|
19828
|
+
},
|
|
19829
|
+
[drillEvent, eventBus]
|
|
19830
|
+
);
|
|
19831
|
+
const normalizedSeries = useMemo(() => {
|
|
19832
|
+
if (series && series.length > 0) return series;
|
|
19833
|
+
if (simpleData) return [{ name: "default", data: simpleData }];
|
|
19445
19834
|
return [];
|
|
19446
19835
|
}, [simpleData, series]);
|
|
19836
|
+
const firstSeriesData = normalizedSeries[0]?.data ?? [];
|
|
19837
|
+
const hasContent = chartType === "scatter" ? (scatterData?.length ?? 0) > 0 : normalizedSeries.some((s) => s.data.length > 0);
|
|
19447
19838
|
if (isLoading) {
|
|
19448
19839
|
return /* @__PURE__ */ jsx(LoadingState, { message: "Loading chart...", className });
|
|
19449
19840
|
}
|
|
@@ -19457,7 +19848,7 @@ var init_Chart = __esm({
|
|
|
19457
19848
|
}
|
|
19458
19849
|
);
|
|
19459
19850
|
}
|
|
19460
|
-
if (
|
|
19851
|
+
if (!hasContent) {
|
|
19461
19852
|
return /* @__PURE__ */ jsx(EmptyState, { title: t("empty.noData"), description: t("empty.noData"), className });
|
|
19462
19853
|
}
|
|
19463
19854
|
return /* @__PURE__ */ jsx(Card, { className: cn("p-6", className), children: /* @__PURE__ */ jsxs(VStack, { gap: "md", children: [
|
|
@@ -19478,18 +19869,84 @@ var init_Chart = __esm({
|
|
|
19478
19869
|
)) })
|
|
19479
19870
|
] }),
|
|
19480
19871
|
/* @__PURE__ */ jsxs(Box, { className: "w-full", children: [
|
|
19481
|
-
chartType === "bar" && /* @__PURE__ */ jsx(
|
|
19482
|
-
|
|
19483
|
-
|
|
19484
|
-
|
|
19485
|
-
|
|
19872
|
+
chartType === "bar" && /* @__PURE__ */ jsx(
|
|
19873
|
+
BarChart,
|
|
19874
|
+
{
|
|
19875
|
+
series: normalizedSeries,
|
|
19876
|
+
height,
|
|
19877
|
+
showValues,
|
|
19878
|
+
stack,
|
|
19879
|
+
timeAxis,
|
|
19880
|
+
onPointClick: handlePointClick
|
|
19881
|
+
}
|
|
19882
|
+
),
|
|
19883
|
+
chartType === "histogram" && /* @__PURE__ */ jsx(
|
|
19884
|
+
BarChart,
|
|
19885
|
+
{
|
|
19886
|
+
series: normalizedSeries,
|
|
19887
|
+
height,
|
|
19888
|
+
showValues,
|
|
19889
|
+
stack: "none",
|
|
19890
|
+
timeAxis: false,
|
|
19891
|
+
histogram: true,
|
|
19892
|
+
onPointClick: handlePointClick
|
|
19893
|
+
}
|
|
19894
|
+
),
|
|
19895
|
+
chartType === "line" && /* @__PURE__ */ jsx(
|
|
19896
|
+
LineChart,
|
|
19897
|
+
{
|
|
19898
|
+
series: normalizedSeries,
|
|
19899
|
+
height,
|
|
19900
|
+
showValues,
|
|
19901
|
+
timeAxis,
|
|
19902
|
+
onPointClick: handlePointClick
|
|
19903
|
+
}
|
|
19904
|
+
),
|
|
19905
|
+
chartType === "area" && /* @__PURE__ */ jsx(
|
|
19906
|
+
LineChart,
|
|
19907
|
+
{
|
|
19908
|
+
series: normalizedSeries,
|
|
19909
|
+
height,
|
|
19910
|
+
showValues,
|
|
19911
|
+
timeAxis,
|
|
19912
|
+
fill: true,
|
|
19913
|
+
onPointClick: handlePointClick
|
|
19914
|
+
}
|
|
19915
|
+
),
|
|
19916
|
+
chartType === "pie" && /* @__PURE__ */ jsx(
|
|
19917
|
+
PieChart,
|
|
19918
|
+
{
|
|
19919
|
+
data: firstSeriesData,
|
|
19920
|
+
height,
|
|
19921
|
+
showValues: showLegend,
|
|
19922
|
+
onPointClick: handlePointClick
|
|
19923
|
+
}
|
|
19924
|
+
),
|
|
19925
|
+
chartType === "donut" && /* @__PURE__ */ jsx(
|
|
19926
|
+
PieChart,
|
|
19927
|
+
{
|
|
19928
|
+
data: firstSeriesData,
|
|
19929
|
+
height,
|
|
19930
|
+
showValues: showLegend,
|
|
19931
|
+
donut: true,
|
|
19932
|
+
onPointClick: handlePointClick
|
|
19933
|
+
}
|
|
19934
|
+
),
|
|
19935
|
+
chartType === "scatter" && /* @__PURE__ */ jsx(
|
|
19936
|
+
ScatterChart,
|
|
19937
|
+
{
|
|
19938
|
+
data: scatterData ?? [],
|
|
19939
|
+
height,
|
|
19940
|
+
onPointClick: handlePointClick
|
|
19941
|
+
}
|
|
19942
|
+
)
|
|
19486
19943
|
] }),
|
|
19487
|
-
showLegend &&
|
|
19944
|
+
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: [
|
|
19488
19945
|
/* @__PURE__ */ jsx(
|
|
19489
19946
|
Box,
|
|
19490
19947
|
{
|
|
19491
19948
|
className: "w-3 h-3 rounded-full flex-shrink-0",
|
|
19492
|
-
style: { backgroundColor: s
|
|
19949
|
+
style: { backgroundColor: seriesColor(s, idx) }
|
|
19493
19950
|
}
|
|
19494
19951
|
),
|
|
19495
19952
|
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: s.name })
|
|
@@ -24405,6 +24862,151 @@ var init_FlipCard = __esm({
|
|
|
24405
24862
|
FlipCard.displayName = "FlipCard";
|
|
24406
24863
|
}
|
|
24407
24864
|
});
|
|
24865
|
+
function toISODate(d) {
|
|
24866
|
+
return d.toISOString().slice(0, 10);
|
|
24867
|
+
}
|
|
24868
|
+
function startOfMonth(d) {
|
|
24869
|
+
return new Date(d.getFullYear(), d.getMonth(), 1);
|
|
24870
|
+
}
|
|
24871
|
+
function startOfQuarter(d) {
|
|
24872
|
+
return new Date(d.getFullYear(), Math.floor(d.getMonth() / 3) * 3, 1);
|
|
24873
|
+
}
|
|
24874
|
+
function startOfYear(d) {
|
|
24875
|
+
return new Date(d.getFullYear(), 0, 1);
|
|
24876
|
+
}
|
|
24877
|
+
function daysAgo(n) {
|
|
24878
|
+
const d = /* @__PURE__ */ new Date();
|
|
24879
|
+
d.setDate(d.getDate() - n);
|
|
24880
|
+
return d;
|
|
24881
|
+
}
|
|
24882
|
+
var DEFAULT_PRESETS, DateRangePicker;
|
|
24883
|
+
var init_DateRangePicker = __esm({
|
|
24884
|
+
"components/molecules/DateRangePicker.tsx"() {
|
|
24885
|
+
"use client";
|
|
24886
|
+
init_cn();
|
|
24887
|
+
init_Button();
|
|
24888
|
+
init_Input();
|
|
24889
|
+
init_Stack();
|
|
24890
|
+
init_Typography();
|
|
24891
|
+
init_useEventBus();
|
|
24892
|
+
DEFAULT_PRESETS = [
|
|
24893
|
+
{
|
|
24894
|
+
label: "Last 7 days",
|
|
24895
|
+
value: "7d",
|
|
24896
|
+
range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24897
|
+
},
|
|
24898
|
+
{
|
|
24899
|
+
label: "Last 30 days",
|
|
24900
|
+
value: "30d",
|
|
24901
|
+
range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24902
|
+
},
|
|
24903
|
+
{
|
|
24904
|
+
label: "This Month",
|
|
24905
|
+
value: "month",
|
|
24906
|
+
range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24907
|
+
},
|
|
24908
|
+
{
|
|
24909
|
+
label: "This Quarter",
|
|
24910
|
+
value: "quarter",
|
|
24911
|
+
range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24912
|
+
},
|
|
24913
|
+
{
|
|
24914
|
+
label: "YTD",
|
|
24915
|
+
value: "ytd",
|
|
24916
|
+
range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24917
|
+
}
|
|
24918
|
+
];
|
|
24919
|
+
DateRangePicker = ({
|
|
24920
|
+
from: fromProp,
|
|
24921
|
+
to: toProp,
|
|
24922
|
+
event,
|
|
24923
|
+
onChange,
|
|
24924
|
+
presets = DEFAULT_PRESETS,
|
|
24925
|
+
fromLabel = "From",
|
|
24926
|
+
toLabel = "To",
|
|
24927
|
+
className
|
|
24928
|
+
}) => {
|
|
24929
|
+
const eventBus = useEventBus();
|
|
24930
|
+
const [from, setFrom] = useState(fromProp ?? "");
|
|
24931
|
+
const [to, setTo] = useState(toProp ?? "");
|
|
24932
|
+
const [activePreset, setActivePreset] = useState(null);
|
|
24933
|
+
const emit = useCallback(
|
|
24934
|
+
(range) => {
|
|
24935
|
+
onChange?.(range);
|
|
24936
|
+
if (event) eventBus.emit(`UI:${event}`, range);
|
|
24937
|
+
},
|
|
24938
|
+
[onChange, event, eventBus]
|
|
24939
|
+
);
|
|
24940
|
+
const handleFromChange = useCallback(
|
|
24941
|
+
(next) => {
|
|
24942
|
+
setFrom(next);
|
|
24943
|
+
setActivePreset(null);
|
|
24944
|
+
emit({ from: next, to });
|
|
24945
|
+
},
|
|
24946
|
+
[to, emit]
|
|
24947
|
+
);
|
|
24948
|
+
const handleToChange = useCallback(
|
|
24949
|
+
(next) => {
|
|
24950
|
+
setTo(next);
|
|
24951
|
+
setActivePreset(null);
|
|
24952
|
+
emit({ from, to: next });
|
|
24953
|
+
},
|
|
24954
|
+
[from, emit]
|
|
24955
|
+
);
|
|
24956
|
+
const handlePreset = useCallback(
|
|
24957
|
+
(preset) => {
|
|
24958
|
+
const range = preset.range();
|
|
24959
|
+
setFrom(range.from);
|
|
24960
|
+
setTo(range.to);
|
|
24961
|
+
setActivePreset(preset.value);
|
|
24962
|
+
emit(range);
|
|
24963
|
+
},
|
|
24964
|
+
[emit]
|
|
24965
|
+
);
|
|
24966
|
+
const presetButtons = useMemo(
|
|
24967
|
+
() => presets.map((preset) => /* @__PURE__ */ jsx(
|
|
24968
|
+
Button,
|
|
24969
|
+
{
|
|
24970
|
+
variant: activePreset === preset.value ? "primary" : "ghost",
|
|
24971
|
+
size: "sm",
|
|
24972
|
+
onClick: () => handlePreset(preset),
|
|
24973
|
+
children: preset.label
|
|
24974
|
+
},
|
|
24975
|
+
preset.value
|
|
24976
|
+
)),
|
|
24977
|
+
[presets, activePreset, handlePreset]
|
|
24978
|
+
);
|
|
24979
|
+
return /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: cn(className), children: [
|
|
24980
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "md", align: "end", children: [
|
|
24981
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
24982
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: fromLabel }),
|
|
24983
|
+
/* @__PURE__ */ jsx(
|
|
24984
|
+
Input,
|
|
24985
|
+
{
|
|
24986
|
+
type: "date",
|
|
24987
|
+
value: from,
|
|
24988
|
+
onChange: (e) => handleFromChange(e.target.value)
|
|
24989
|
+
}
|
|
24990
|
+
)
|
|
24991
|
+
] }),
|
|
24992
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
24993
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: toLabel }),
|
|
24994
|
+
/* @__PURE__ */ jsx(
|
|
24995
|
+
Input,
|
|
24996
|
+
{
|
|
24997
|
+
type: "date",
|
|
24998
|
+
value: to,
|
|
24999
|
+
onChange: (e) => handleToChange(e.target.value)
|
|
25000
|
+
}
|
|
25001
|
+
)
|
|
25002
|
+
] })
|
|
25003
|
+
] }),
|
|
25004
|
+
presets.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
|
|
25005
|
+
] });
|
|
25006
|
+
};
|
|
25007
|
+
DateRangePicker.displayName = "DateRangePicker";
|
|
25008
|
+
}
|
|
25009
|
+
});
|
|
24408
25010
|
var DEFAULT_OPTIONS, DateRangeSelector;
|
|
24409
25011
|
var init_DateRangeSelector = __esm({
|
|
24410
25012
|
"components/molecules/DateRangeSelector.tsx"() {
|
|
@@ -27376,7 +27978,9 @@ var init_StatDisplay = __esm({
|
|
|
27376
27978
|
init_Typography();
|
|
27377
27979
|
init_Box();
|
|
27378
27980
|
init_Stack();
|
|
27981
|
+
init_Sparkline();
|
|
27379
27982
|
init_Icon();
|
|
27983
|
+
init_useEventBus();
|
|
27380
27984
|
variantColor = {
|
|
27381
27985
|
default: "text-foreground",
|
|
27382
27986
|
primary: "text-primary",
|
|
@@ -27391,6 +27995,10 @@ var init_StatDisplay = __esm({
|
|
|
27391
27995
|
max,
|
|
27392
27996
|
target,
|
|
27393
27997
|
trend,
|
|
27998
|
+
trendPolarity = "higher-is-better",
|
|
27999
|
+
trendFormat = "absolute",
|
|
28000
|
+
sparklineData,
|
|
28001
|
+
clickEvent,
|
|
27394
28002
|
prefix,
|
|
27395
28003
|
suffix,
|
|
27396
28004
|
icon: iconProp,
|
|
@@ -27404,6 +28012,10 @@ var init_StatDisplay = __esm({
|
|
|
27404
28012
|
isLoading = false,
|
|
27405
28013
|
error = null
|
|
27406
28014
|
}) => {
|
|
28015
|
+
const eventBus = useEventBus();
|
|
28016
|
+
const handleClick = useCallback(() => {
|
|
28017
|
+
if (clickEvent) eventBus.emit(`UI:${clickEvent}`, { metricLabel: label });
|
|
28018
|
+
}, [clickEvent, eventBus, label]);
|
|
27407
28019
|
const ResolvedIcon = typeof iconProp === "string" ? resolveIcon(iconProp) : null;
|
|
27408
28020
|
const iconSizes3 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
|
|
27409
28021
|
const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
|
|
@@ -27414,7 +28026,10 @@ var init_StatDisplay = __esm({
|
|
|
27414
28026
|
const targetPct = showTarget ? Math.max(0, Math.min(100, numericValue / target * 100)) : 0;
|
|
27415
28027
|
const showTrend = typeof trend === "number" && trend !== 0 && Number.isFinite(trend);
|
|
27416
28028
|
const trendUp = showTrend && trend > 0;
|
|
27417
|
-
const
|
|
28029
|
+
const trendIsGood = trendPolarity === "lower-is-better" ? !trendUp : trendUp;
|
|
28030
|
+
const trendMagnitude = Math.abs(trend);
|
|
28031
|
+
const trendSuffix = trendFormat === "percent" ? "%" : "";
|
|
28032
|
+
const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${trendMagnitude}${trendSuffix}` : "";
|
|
27418
28033
|
if (error) {
|
|
27419
28034
|
return /* @__PURE__ */ jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsx(Typography, { variant: "small", color: "error", children: error.message }) });
|
|
27420
28035
|
}
|
|
@@ -27425,38 +28040,57 @@ var init_StatDisplay = __esm({
|
|
|
27425
28040
|
] }) });
|
|
27426
28041
|
}
|
|
27427
28042
|
if (compact) {
|
|
27428
|
-
return /* @__PURE__ */ jsxs(
|
|
27429
|
-
|
|
27430
|
-
|
|
27431
|
-
|
|
27432
|
-
|
|
27433
|
-
|
|
27434
|
-
|
|
28043
|
+
return /* @__PURE__ */ jsxs(
|
|
28044
|
+
HStack,
|
|
28045
|
+
{
|
|
28046
|
+
gap: "sm",
|
|
28047
|
+
className: cn("items-center", clickEvent && "cursor-pointer hover:opacity-80", className),
|
|
28048
|
+
onClick: clickEvent ? handleClick : void 0,
|
|
28049
|
+
children: [
|
|
28050
|
+
ResolvedIcon && /* @__PURE__ */ jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
|
|
28051
|
+
typeof iconProp !== "string" && iconProp,
|
|
28052
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: label }),
|
|
28053
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
|
|
28054
|
+
showTrend && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: cn("font-semibold", trendIsGood ? "text-success" : "text-error"), children: trendLabel }),
|
|
28055
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto", width: 60, height: 20 })
|
|
28056
|
+
]
|
|
28057
|
+
}
|
|
28058
|
+
);
|
|
27435
28059
|
}
|
|
27436
|
-
return /* @__PURE__ */ jsx(
|
|
27437
|
-
|
|
27438
|
-
|
|
27439
|
-
|
|
27440
|
-
|
|
27441
|
-
|
|
27442
|
-
|
|
27443
|
-
{
|
|
27444
|
-
|
|
27445
|
-
className: cn("font-
|
|
27446
|
-
|
|
27447
|
-
|
|
27448
|
-
|
|
27449
|
-
|
|
27450
|
-
|
|
27451
|
-
|
|
27452
|
-
|
|
27453
|
-
|
|
27454
|
-
|
|
27455
|
-
|
|
27456
|
-
|
|
27457
|
-
|
|
27458
|
-
|
|
27459
|
-
|
|
28060
|
+
return /* @__PURE__ */ jsx(
|
|
28061
|
+
Card,
|
|
28062
|
+
{
|
|
28063
|
+
className: cn(padSizes[size], clickEvent && "cursor-pointer hover:shadow-md transition-shadow", className),
|
|
28064
|
+
onClick: clickEvent ? handleClick : void 0,
|
|
28065
|
+
children: /* @__PURE__ */ jsxs(HStack, { align: "start", justify: "between", children: [
|
|
28066
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
|
|
28067
|
+
/* @__PURE__ */ jsx(Typography, { variant: "overline", color: "secondary", children: label }),
|
|
28068
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "end", children: [
|
|
28069
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
|
|
28070
|
+
showTrend && /* @__PURE__ */ jsx(
|
|
28071
|
+
Typography,
|
|
28072
|
+
{
|
|
28073
|
+
variant: "caption",
|
|
28074
|
+
className: cn("font-semibold pb-1", trendIsGood ? "text-success" : "text-error"),
|
|
28075
|
+
children: trendLabel
|
|
28076
|
+
}
|
|
28077
|
+
)
|
|
28078
|
+
] }),
|
|
28079
|
+
showTarget && /* @__PURE__ */ jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
28080
|
+
Box,
|
|
28081
|
+
{
|
|
28082
|
+
className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
|
|
28083
|
+
style: { width: `${targetPct}%` }
|
|
28084
|
+
}
|
|
28085
|
+
) })
|
|
28086
|
+
] }),
|
|
28087
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
|
|
28088
|
+
(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 }),
|
|
28089
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto" })
|
|
28090
|
+
] })
|
|
28091
|
+
] })
|
|
28092
|
+
}
|
|
28093
|
+
);
|
|
27460
28094
|
};
|
|
27461
28095
|
StatDisplay.displayName = "StatDisplay";
|
|
27462
28096
|
}
|
|
@@ -41919,6 +42553,7 @@ var init_StatCard = __esm({
|
|
|
41919
42553
|
init_Box();
|
|
41920
42554
|
init_Stack();
|
|
41921
42555
|
init_Button();
|
|
42556
|
+
init_Sparkline();
|
|
41922
42557
|
init_useEventBus();
|
|
41923
42558
|
init_useTranslate();
|
|
41924
42559
|
init_Icon();
|
|
@@ -42088,32 +42723,7 @@ var init_StatCard = __esm({
|
|
|
42088
42723
|
] }),
|
|
42089
42724
|
/* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
|
|
42090
42725
|
Icon3 && /* @__PURE__ */ jsx(Box, { className: cn("p-3", iconBg), children: /* @__PURE__ */ jsx(Icon3, { className: cn("h-6 w-6", iconColor) }) }),
|
|
42091
|
-
sparklineData && sparklineData.length > 1 && (
|
|
42092
|
-
const w = 80;
|
|
42093
|
-
const h = 32;
|
|
42094
|
-
const pad = 2;
|
|
42095
|
-
const min = Math.min(...sparklineData);
|
|
42096
|
-
const max = Math.max(...sparklineData);
|
|
42097
|
-
const range = max - min || 1;
|
|
42098
|
-
const points = sparklineData.map((v, i) => {
|
|
42099
|
-
const x = pad + i / (sparklineData.length - 1) * (w - pad * 2);
|
|
42100
|
-
const y = pad + (1 - (v - min) / range) * (h - pad * 2);
|
|
42101
|
-
return `${x},${y}`;
|
|
42102
|
-
}).join(" ");
|
|
42103
|
-
const trending = sparklineData[sparklineData.length - 1] >= sparklineData[0];
|
|
42104
|
-
const strokeColor = trending ? "var(--color-success)" : "var(--color-error)";
|
|
42105
|
-
return /* @__PURE__ */ jsx("svg", { width: w, height: h, viewBox: `0 0 ${w} ${h}`, className: "flex-shrink-0", children: /* @__PURE__ */ jsx(
|
|
42106
|
-
"polyline",
|
|
42107
|
-
{
|
|
42108
|
-
fill: "none",
|
|
42109
|
-
stroke: strokeColor,
|
|
42110
|
-
strokeWidth: "2",
|
|
42111
|
-
strokeLinecap: "round",
|
|
42112
|
-
strokeLinejoin: "round",
|
|
42113
|
-
points
|
|
42114
|
-
}
|
|
42115
|
-
) });
|
|
42116
|
-
})()
|
|
42726
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto" })
|
|
42117
42727
|
] })
|
|
42118
42728
|
] }),
|
|
42119
42729
|
action && /* @__PURE__ */ jsxs(
|
|
@@ -44011,6 +44621,7 @@ var init_component_registry_generated = __esm({
|
|
|
44011
44621
|
init_DataGrid();
|
|
44012
44622
|
init_DataList();
|
|
44013
44623
|
init_DataTable();
|
|
44624
|
+
init_DateRangePicker();
|
|
44014
44625
|
init_DateRangeSelector();
|
|
44015
44626
|
init_DayCell();
|
|
44016
44627
|
init_DebuggerBoard();
|
|
@@ -44143,6 +44754,7 @@ var init_component_registry_generated = __esm({
|
|
|
44143
44754
|
init_Skeleton();
|
|
44144
44755
|
init_SocialProof();
|
|
44145
44756
|
init_SortableList();
|
|
44757
|
+
init_Sparkline();
|
|
44146
44758
|
init_Split();
|
|
44147
44759
|
init_SplitPane();
|
|
44148
44760
|
init_SplitSection();
|
|
@@ -44291,6 +44903,7 @@ var init_component_registry_generated = __esm({
|
|
|
44291
44903
|
"DataGrid": DataGrid,
|
|
44292
44904
|
"DataList": DataList,
|
|
44293
44905
|
"DataTable": DataTable,
|
|
44906
|
+
"DateRangePicker": DateRangePicker,
|
|
44294
44907
|
"DateRangeSelector": DateRangeSelector,
|
|
44295
44908
|
"DayCell": DayCell,
|
|
44296
44909
|
"DebuggerBoard": DebuggerBoard,
|
|
@@ -44452,6 +45065,7 @@ var init_component_registry_generated = __esm({
|
|
|
44452
45065
|
"SortableList": SortableList,
|
|
44453
45066
|
"Spacer": SpacerPattern,
|
|
44454
45067
|
"SpacerPattern": SpacerPattern,
|
|
45068
|
+
"Sparkline": Sparkline,
|
|
44455
45069
|
"Spinner": SpinnerPattern,
|
|
44456
45070
|
"SpinnerPattern": SpinnerPattern,
|
|
44457
45071
|
"Split": Split,
|