@almadar/ui 4.51.14 → 4.51.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/avl/index.cjs +807 -154
- package/dist/avl/index.js +807 -154
- package/dist/components/atoms/Sparkline.d.ts +30 -0
- package/dist/components/atoms/index.d.ts +1 -0
- package/dist/components/index.cjs +797 -153
- package/dist/components/index.js +798 -154
- 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 +795 -153
- package/dist/providers/index.js +795 -153
- package/dist/runtime/index.cjs +795 -153
- package/dist/runtime/index.js +795 -153
- package/package.json +1 -1
package/dist/providers/index.cjs
CHANGED
|
@@ -3649,6 +3649,67 @@ var init_Radio = __esm({
|
|
|
3649
3649
|
Radio.displayName = "Radio";
|
|
3650
3650
|
}
|
|
3651
3651
|
});
|
|
3652
|
+
var COLOR_VAR, Sparkline;
|
|
3653
|
+
var init_Sparkline = __esm({
|
|
3654
|
+
"components/atoms/Sparkline.tsx"() {
|
|
3655
|
+
init_cn();
|
|
3656
|
+
COLOR_VAR = {
|
|
3657
|
+
primary: "var(--color-primary)",
|
|
3658
|
+
success: "var(--color-success)",
|
|
3659
|
+
warning: "var(--color-warning)",
|
|
3660
|
+
error: "var(--color-error)",
|
|
3661
|
+
info: "var(--color-info)",
|
|
3662
|
+
muted: "var(--color-muted-foreground)"
|
|
3663
|
+
};
|
|
3664
|
+
Sparkline = ({
|
|
3665
|
+
data,
|
|
3666
|
+
color = "auto",
|
|
3667
|
+
width = 80,
|
|
3668
|
+
height = 32,
|
|
3669
|
+
strokeWidth = 2,
|
|
3670
|
+
fill = false,
|
|
3671
|
+
className
|
|
3672
|
+
}) => {
|
|
3673
|
+
if (data.length < 2) return null;
|
|
3674
|
+
const pad = 2;
|
|
3675
|
+
const min = Math.min(...data);
|
|
3676
|
+
const max = Math.max(...data);
|
|
3677
|
+
const range = max - min || 1;
|
|
3678
|
+
const points = data.map((v, i) => {
|
|
3679
|
+
const x = pad + i / (data.length - 1) * (width - pad * 2);
|
|
3680
|
+
const y = pad + (1 - (v - min) / range) * (height - pad * 2);
|
|
3681
|
+
return `${x},${y}`;
|
|
3682
|
+
}).join(" ");
|
|
3683
|
+
const resolvedColor = color === "auto" ? data[data.length - 1] >= data[0] ? COLOR_VAR.success : COLOR_VAR.error : COLOR_VAR[color];
|
|
3684
|
+
const areaPath = fill ? `M ${pad},${height - pad} L ${points.split(" ").join(" L ")} L ${width - pad},${height - pad} Z` : null;
|
|
3685
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3686
|
+
"svg",
|
|
3687
|
+
{
|
|
3688
|
+
width,
|
|
3689
|
+
height,
|
|
3690
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
3691
|
+
className: cn("flex-shrink-0", className),
|
|
3692
|
+
"aria-hidden": "true",
|
|
3693
|
+
children: [
|
|
3694
|
+
areaPath && /* @__PURE__ */ jsxRuntime.jsx("path", { d: areaPath, fill: resolvedColor, opacity: 0.15 }),
|
|
3695
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3696
|
+
"polyline",
|
|
3697
|
+
{
|
|
3698
|
+
fill: "none",
|
|
3699
|
+
stroke: resolvedColor,
|
|
3700
|
+
strokeWidth,
|
|
3701
|
+
strokeLinecap: "round",
|
|
3702
|
+
strokeLinejoin: "round",
|
|
3703
|
+
points
|
|
3704
|
+
}
|
|
3705
|
+
)
|
|
3706
|
+
]
|
|
3707
|
+
}
|
|
3708
|
+
);
|
|
3709
|
+
};
|
|
3710
|
+
Sparkline.displayName = "Sparkline";
|
|
3711
|
+
}
|
|
3712
|
+
});
|
|
3652
3713
|
var Switch;
|
|
3653
3714
|
var init_Switch = __esm({
|
|
3654
3715
|
"components/atoms/Switch.tsx"() {
|
|
@@ -9322,7 +9383,7 @@ var init_MapView = __esm({
|
|
|
9322
9383
|
shadowSize: [41, 41]
|
|
9323
9384
|
});
|
|
9324
9385
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
9325
|
-
const { useEffect: useEffect67, useRef: useRef65, useCallback:
|
|
9386
|
+
const { useEffect: useEffect67, useRef: useRef65, useCallback: useCallback112, useState: useState96 } = React81__namespace.default;
|
|
9326
9387
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
9327
9388
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
9328
9389
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -9367,8 +9428,8 @@ var init_MapView = __esm({
|
|
|
9367
9428
|
showAttribution = true
|
|
9368
9429
|
}) {
|
|
9369
9430
|
const eventBus = useEventBus2();
|
|
9370
|
-
const [clickedPosition, setClickedPosition] =
|
|
9371
|
-
const handleMapClick =
|
|
9431
|
+
const [clickedPosition, setClickedPosition] = useState96(null);
|
|
9432
|
+
const handleMapClick = useCallback112((lat, lng) => {
|
|
9372
9433
|
if (showClickedPin) {
|
|
9373
9434
|
setClickedPosition({ lat, lng });
|
|
9374
9435
|
}
|
|
@@ -9377,7 +9438,7 @@ var init_MapView = __esm({
|
|
|
9377
9438
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
9378
9439
|
}
|
|
9379
9440
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
9380
|
-
const handleMarkerClick =
|
|
9441
|
+
const handleMarkerClick = useCallback112((marker) => {
|
|
9381
9442
|
onMarkerClick?.(marker);
|
|
9382
9443
|
if (markerClickEvent) {
|
|
9383
9444
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -19277,7 +19338,7 @@ var init_CastleTemplate = __esm({
|
|
|
19277
19338
|
CastleTemplate.displayName = "CastleTemplate";
|
|
19278
19339
|
}
|
|
19279
19340
|
});
|
|
19280
|
-
var CHART_COLORS, BarChart, PieChart, LineChart, Chart;
|
|
19341
|
+
var CHART_COLORS, seriesColor, monthFormatter, formatTimeLabel, BarChart, PieChart, LineChart, ScatterChart, Chart;
|
|
19281
19342
|
var init_Chart = __esm({
|
|
19282
19343
|
"components/organisms/Chart.tsx"() {
|
|
19283
19344
|
"use client";
|
|
@@ -19297,38 +19358,159 @@ var init_Chart = __esm({
|
|
|
19297
19358
|
"var(--color-info)",
|
|
19298
19359
|
"var(--color-accent)"
|
|
19299
19360
|
];
|
|
19300
|
-
|
|
19301
|
-
|
|
19302
|
-
|
|
19303
|
-
|
|
19304
|
-
|
|
19305
|
-
|
|
19306
|
-
|
|
19307
|
-
|
|
19308
|
-
|
|
19309
|
-
|
|
19310
|
-
|
|
19311
|
-
|
|
19312
|
-
|
|
19313
|
-
|
|
19314
|
-
|
|
19315
|
-
|
|
19316
|
-
|
|
19361
|
+
seriesColor = (series, idx) => series.color ?? CHART_COLORS[idx % CHART_COLORS.length];
|
|
19362
|
+
monthFormatter = new Intl.DateTimeFormat(void 0, {
|
|
19363
|
+
month: "short",
|
|
19364
|
+
year: "2-digit"
|
|
19365
|
+
});
|
|
19366
|
+
formatTimeLabel = (raw) => {
|
|
19367
|
+
const parsed = new Date(raw);
|
|
19368
|
+
if (Number.isNaN(parsed.getTime())) return raw;
|
|
19369
|
+
return monthFormatter.format(parsed);
|
|
19370
|
+
};
|
|
19371
|
+
BarChart = ({ series, height, showValues, stack, timeAxis, histogram = false, onPointClick }) => {
|
|
19372
|
+
const categories = React81.useMemo(() => {
|
|
19373
|
+
const set = [];
|
|
19374
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19375
|
+
for (const s of series) {
|
|
19376
|
+
for (const p2 of s.data) {
|
|
19377
|
+
if (!seen.has(p2.label)) {
|
|
19378
|
+
seen.add(p2.label);
|
|
19379
|
+
set.push(p2.label);
|
|
19317
19380
|
}
|
|
19318
|
-
|
|
19319
|
-
|
|
19320
|
-
|
|
19321
|
-
|
|
19322
|
-
|
|
19323
|
-
|
|
19324
|
-
|
|
19325
|
-
|
|
19381
|
+
}
|
|
19382
|
+
}
|
|
19383
|
+
return set;
|
|
19384
|
+
}, [series]);
|
|
19385
|
+
const valueAt = React81.useCallback(
|
|
19386
|
+
(s, label) => {
|
|
19387
|
+
const p2 = s.data.find((d) => d.label === label);
|
|
19388
|
+
return p2 ? p2.value : 0;
|
|
19389
|
+
},
|
|
19390
|
+
[]
|
|
19391
|
+
);
|
|
19392
|
+
const columnTotals = React81.useMemo(() => {
|
|
19393
|
+
if (stack === "none") return null;
|
|
19394
|
+
return categories.map(
|
|
19395
|
+
(label) => series.reduce((sum, s) => sum + valueAt(s, label), 0)
|
|
19396
|
+
);
|
|
19397
|
+
}, [categories, series, stack, valueAt]);
|
|
19398
|
+
const maxValue = React81.useMemo(() => {
|
|
19399
|
+
if (stack === "normalize") return 100;
|
|
19400
|
+
if (stack === "stack" && columnTotals) {
|
|
19401
|
+
return Math.max(...columnTotals, 1);
|
|
19402
|
+
}
|
|
19403
|
+
let m = 1;
|
|
19404
|
+
for (const s of series) {
|
|
19405
|
+
for (const p2 of s.data) if (p2.value > m) m = p2.value;
|
|
19406
|
+
}
|
|
19407
|
+
return m;
|
|
19408
|
+
}, [series, stack, columnTotals]);
|
|
19409
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19410
|
+
HStack,
|
|
19411
|
+
{
|
|
19412
|
+
gap: histogram ? "none" : "xs",
|
|
19413
|
+
align: "end",
|
|
19414
|
+
className: "w-full",
|
|
19415
|
+
style: { height },
|
|
19416
|
+
children: categories.map((label, catIdx) => {
|
|
19417
|
+
const displayLabel = timeAxis ? formatTimeLabel(label) : label;
|
|
19418
|
+
if (stack === "none") {
|
|
19419
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
19420
|
+
VStack,
|
|
19421
|
+
{
|
|
19422
|
+
gap: "xs",
|
|
19423
|
+
align: "center",
|
|
19424
|
+
flex: true,
|
|
19425
|
+
className: "min-w-0",
|
|
19426
|
+
children: [
|
|
19427
|
+
/* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: histogram ? "none" : "xs", align: "end", className: "w-full", style: { height: "100%" }, children: series.map((s, sIdx) => {
|
|
19428
|
+
const value = valueAt(s, label);
|
|
19429
|
+
const barHeight = value / maxValue * 100;
|
|
19430
|
+
const color = seriesColor(s, sIdx);
|
|
19431
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19432
|
+
Box,
|
|
19433
|
+
{
|
|
19434
|
+
className: cn(
|
|
19435
|
+
"rounded-t-sm transition-all duration-500 ease-out min-h-[4px] cursor-pointer hover:opacity-80",
|
|
19436
|
+
histogram ? "flex-1 mx-0" : "flex-1"
|
|
19437
|
+
),
|
|
19438
|
+
style: {
|
|
19439
|
+
height: `${barHeight}%`,
|
|
19440
|
+
backgroundColor: color
|
|
19441
|
+
},
|
|
19442
|
+
onClick: () => onPointClick?.(
|
|
19443
|
+
{ label, value, color },
|
|
19444
|
+
s.name
|
|
19445
|
+
),
|
|
19446
|
+
title: `${s.name}: ${value}`
|
|
19447
|
+
},
|
|
19448
|
+
s.name
|
|
19449
|
+
);
|
|
19450
|
+
}) }),
|
|
19451
|
+
showValues && series.length === 1 && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: valueAt(series[0], label) }),
|
|
19452
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19453
|
+
Typography,
|
|
19454
|
+
{
|
|
19455
|
+
variant: "caption",
|
|
19456
|
+
color: "secondary",
|
|
19457
|
+
className: "truncate w-full text-center",
|
|
19458
|
+
children: displayLabel
|
|
19459
|
+
}
|
|
19460
|
+
)
|
|
19461
|
+
]
|
|
19462
|
+
},
|
|
19463
|
+
label
|
|
19464
|
+
);
|
|
19326
19465
|
}
|
|
19327
|
-
|
|
19328
|
-
|
|
19329
|
-
|
|
19466
|
+
const total = columnTotals?.[catIdx] ?? 1;
|
|
19467
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
19468
|
+
VStack,
|
|
19469
|
+
{
|
|
19470
|
+
gap: "xs",
|
|
19471
|
+
align: "center",
|
|
19472
|
+
flex: true,
|
|
19473
|
+
className: "min-w-0",
|
|
19474
|
+
children: [
|
|
19475
|
+
/* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "none", className: "w-full", style: { height: "100%" }, justify: "end", children: series.map((s, sIdx) => {
|
|
19476
|
+
const value = valueAt(s, label);
|
|
19477
|
+
const ratio = stack === "normalize" ? total === 0 ? 0 : value / total * 100 : value / maxValue * 100;
|
|
19478
|
+
const color = seriesColor(s, sIdx);
|
|
19479
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19480
|
+
Box,
|
|
19481
|
+
{
|
|
19482
|
+
className: "w-full transition-all duration-500 ease-out cursor-pointer hover:opacity-80",
|
|
19483
|
+
style: {
|
|
19484
|
+
height: `${ratio}%`,
|
|
19485
|
+
backgroundColor: color
|
|
19486
|
+
},
|
|
19487
|
+
onClick: () => onPointClick?.(
|
|
19488
|
+
{ label, value, color },
|
|
19489
|
+
s.name
|
|
19490
|
+
),
|
|
19491
|
+
title: `${s.name}: ${value}`
|
|
19492
|
+
},
|
|
19493
|
+
s.name
|
|
19494
|
+
);
|
|
19495
|
+
}) }),
|
|
19496
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19497
|
+
Typography,
|
|
19498
|
+
{
|
|
19499
|
+
variant: "caption",
|
|
19500
|
+
color: "secondary",
|
|
19501
|
+
className: "truncate w-full text-center",
|
|
19502
|
+
children: displayLabel
|
|
19503
|
+
}
|
|
19504
|
+
)
|
|
19505
|
+
]
|
|
19506
|
+
},
|
|
19507
|
+
label
|
|
19508
|
+
);
|
|
19509
|
+
})
|
|
19510
|
+
}
|
|
19511
|
+
);
|
|
19330
19512
|
};
|
|
19331
|
-
PieChart = ({ data, height, showValues, donut = false }) => {
|
|
19513
|
+
PieChart = ({ data, height, showValues, donut = false, onPointClick }) => {
|
|
19332
19514
|
const total = data.reduce((sum, d) => sum + d.value, 0);
|
|
19333
19515
|
const size = Math.min(height, 200);
|
|
19334
19516
|
const radius = size / 2 - 8;
|
|
@@ -19374,7 +19556,11 @@ var init_Chart = __esm({
|
|
|
19374
19556
|
fill: seg.color,
|
|
19375
19557
|
stroke: "var(--color-card)",
|
|
19376
19558
|
strokeWidth: "2",
|
|
19377
|
-
className: "transition-opacity duration-200 hover:opacity-80"
|
|
19559
|
+
className: "transition-opacity duration-200 hover:opacity-80 cursor-pointer",
|
|
19560
|
+
onClick: () => onPointClick?.(
|
|
19561
|
+
{ label: seg.label, value: seg.value, color: seg.color },
|
|
19562
|
+
"default"
|
|
19563
|
+
)
|
|
19378
19564
|
},
|
|
19379
19565
|
idx
|
|
19380
19566
|
)),
|
|
@@ -19409,56 +19595,243 @@ var init_Chart = __esm({
|
|
|
19409
19595
|
] }, idx)) })
|
|
19410
19596
|
] });
|
|
19411
19597
|
};
|
|
19412
|
-
LineChart = ({
|
|
19413
|
-
const maxValue = Math.max(...data.map((d) => d.value), 1);
|
|
19598
|
+
LineChart = ({ series, height, showValues, fill = false, timeAxis, onPointClick }) => {
|
|
19414
19599
|
const width = 400;
|
|
19415
19600
|
const padding = { top: 20, right: 20, bottom: 30, left: 40 };
|
|
19416
19601
|
const chartWidth = width - padding.left - padding.right;
|
|
19417
19602
|
const chartHeight = height - padding.top - padding.bottom;
|
|
19418
|
-
const
|
|
19419
|
-
|
|
19420
|
-
|
|
19421
|
-
|
|
19422
|
-
|
|
19423
|
-
|
|
19424
|
-
|
|
19425
|
-
|
|
19426
|
-
const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
|
|
19427
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "100%", height, viewBox: `0 0 ${width} ${height}`, preserveAspectRatio: "xMidYMid meet", children: [
|
|
19428
|
-
[0, 0.25, 0.5, 0.75, 1].map((frac) => {
|
|
19429
|
-
const y = padding.top + chartHeight * (1 - frac);
|
|
19430
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19431
|
-
"line",
|
|
19432
|
-
{
|
|
19433
|
-
x1: padding.left,
|
|
19434
|
-
y1: y,
|
|
19435
|
-
x2: width - padding.right,
|
|
19436
|
-
y2: y,
|
|
19437
|
-
stroke: "var(--color-border)",
|
|
19438
|
-
strokeDasharray: "4 4",
|
|
19439
|
-
opacity: 0.5
|
|
19440
|
-
},
|
|
19441
|
-
frac
|
|
19442
|
-
);
|
|
19443
|
-
}),
|
|
19444
|
-
fill && /* @__PURE__ */ jsxRuntime.jsx("path", { d: areaPath, fill: "var(--color-primary)", opacity: 0.1 }),
|
|
19445
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: linePath, fill: "none", stroke: "var(--color-primary)", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
19446
|
-
points.map((p2, idx) => /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
|
|
19447
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: p2.x, cy: p2.y, r: "4", fill: "var(--color-card)", stroke: "var(--color-primary)", strokeWidth: "2" }),
|
|
19448
|
-
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 }),
|
|
19449
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19450
|
-
"text",
|
|
19451
|
-
{
|
|
19452
|
-
x: p2.x,
|
|
19453
|
-
y: height - 8,
|
|
19454
|
-
textAnchor: "middle",
|
|
19455
|
-
fill: "var(--color-muted-foreground)",
|
|
19456
|
-
fontSize: "9",
|
|
19457
|
-
children: p2.label
|
|
19603
|
+
const labels = React81.useMemo(() => {
|
|
19604
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19605
|
+
const out = [];
|
|
19606
|
+
for (const s of series) {
|
|
19607
|
+
for (const p2 of s.data) {
|
|
19608
|
+
if (!seen.has(p2.label)) {
|
|
19609
|
+
seen.add(p2.label);
|
|
19610
|
+
out.push(p2.label);
|
|
19458
19611
|
}
|
|
19459
|
-
|
|
19460
|
-
|
|
19461
|
-
|
|
19612
|
+
}
|
|
19613
|
+
}
|
|
19614
|
+
return out;
|
|
19615
|
+
}, [series]);
|
|
19616
|
+
const maxValue = React81.useMemo(() => {
|
|
19617
|
+
let m = 1;
|
|
19618
|
+
for (const s of series) {
|
|
19619
|
+
for (const p2 of s.data) if (p2.value > m) m = p2.value;
|
|
19620
|
+
}
|
|
19621
|
+
return m;
|
|
19622
|
+
}, [series]);
|
|
19623
|
+
const xFor = React81.useCallback(
|
|
19624
|
+
(idx) => padding.left + idx / Math.max(labels.length - 1, 1) * chartWidth,
|
|
19625
|
+
[labels.length, chartWidth, padding.left]
|
|
19626
|
+
);
|
|
19627
|
+
const yFor = React81.useCallback(
|
|
19628
|
+
(value) => padding.top + chartHeight - value / maxValue * chartHeight,
|
|
19629
|
+
[maxValue, chartHeight, padding.top]
|
|
19630
|
+
);
|
|
19631
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
19632
|
+
"svg",
|
|
19633
|
+
{
|
|
19634
|
+
width: "100%",
|
|
19635
|
+
height,
|
|
19636
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
19637
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
19638
|
+
children: [
|
|
19639
|
+
[0, 0.25, 0.5, 0.75, 1].map((frac) => {
|
|
19640
|
+
const y = padding.top + chartHeight * (1 - frac);
|
|
19641
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19642
|
+
"line",
|
|
19643
|
+
{
|
|
19644
|
+
x1: padding.left,
|
|
19645
|
+
y1: y,
|
|
19646
|
+
x2: width - padding.right,
|
|
19647
|
+
y2: y,
|
|
19648
|
+
stroke: "var(--color-border)",
|
|
19649
|
+
strokeDasharray: "4 4",
|
|
19650
|
+
opacity: 0.5
|
|
19651
|
+
},
|
|
19652
|
+
frac
|
|
19653
|
+
);
|
|
19654
|
+
}),
|
|
19655
|
+
series.map((s, sIdx) => {
|
|
19656
|
+
const color = seriesColor(s, sIdx);
|
|
19657
|
+
const points = labels.map((label, idx) => {
|
|
19658
|
+
const point = s.data.find((d) => d.label === label);
|
|
19659
|
+
return {
|
|
19660
|
+
x: xFor(idx),
|
|
19661
|
+
y: yFor(point ? point.value : 0),
|
|
19662
|
+
value: point ? point.value : 0,
|
|
19663
|
+
label
|
|
19664
|
+
};
|
|
19665
|
+
});
|
|
19666
|
+
const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
|
|
19667
|
+
const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
|
|
19668
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
|
|
19669
|
+
fill && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19670
|
+
"path",
|
|
19671
|
+
{
|
|
19672
|
+
d: areaPath,
|
|
19673
|
+
fill: color,
|
|
19674
|
+
opacity: series.length > 1 ? 0.08 : 0.1
|
|
19675
|
+
}
|
|
19676
|
+
),
|
|
19677
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19678
|
+
"path",
|
|
19679
|
+
{
|
|
19680
|
+
d: linePath,
|
|
19681
|
+
fill: "none",
|
|
19682
|
+
stroke: color,
|
|
19683
|
+
strokeWidth: "2",
|
|
19684
|
+
strokeLinecap: "round",
|
|
19685
|
+
strokeLinejoin: "round",
|
|
19686
|
+
strokeDasharray: s.dashed ? "6 4" : void 0
|
|
19687
|
+
}
|
|
19688
|
+
),
|
|
19689
|
+
points.map((p2, idx) => /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
|
|
19690
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19691
|
+
"circle",
|
|
19692
|
+
{
|
|
19693
|
+
cx: p2.x,
|
|
19694
|
+
cy: p2.y,
|
|
19695
|
+
r: "4",
|
|
19696
|
+
fill: "var(--color-card)",
|
|
19697
|
+
stroke: color,
|
|
19698
|
+
strokeWidth: "2",
|
|
19699
|
+
className: "cursor-pointer",
|
|
19700
|
+
onClick: () => onPointClick?.(
|
|
19701
|
+
{ label: p2.label, value: p2.value, color },
|
|
19702
|
+
s.name
|
|
19703
|
+
)
|
|
19704
|
+
}
|
|
19705
|
+
),
|
|
19706
|
+
showValues && series.length === 1 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19707
|
+
"text",
|
|
19708
|
+
{
|
|
19709
|
+
x: p2.x,
|
|
19710
|
+
y: p2.y - 10,
|
|
19711
|
+
textAnchor: "middle",
|
|
19712
|
+
fill: "var(--color-foreground)",
|
|
19713
|
+
fontSize: "10",
|
|
19714
|
+
fontWeight: "500",
|
|
19715
|
+
children: p2.value
|
|
19716
|
+
}
|
|
19717
|
+
)
|
|
19718
|
+
] }, idx))
|
|
19719
|
+
] }, s.name);
|
|
19720
|
+
}),
|
|
19721
|
+
labels.map((label, idx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
19722
|
+
"text",
|
|
19723
|
+
{
|
|
19724
|
+
x: xFor(idx),
|
|
19725
|
+
y: height - 8,
|
|
19726
|
+
textAnchor: "middle",
|
|
19727
|
+
fill: "var(--color-muted-foreground)",
|
|
19728
|
+
fontSize: "9",
|
|
19729
|
+
children: timeAxis ? formatTimeLabel(label) : label
|
|
19730
|
+
},
|
|
19731
|
+
label
|
|
19732
|
+
))
|
|
19733
|
+
]
|
|
19734
|
+
}
|
|
19735
|
+
);
|
|
19736
|
+
};
|
|
19737
|
+
ScatterChart = ({ data, height, onPointClick }) => {
|
|
19738
|
+
const width = 400;
|
|
19739
|
+
const padding = { top: 20, right: 20, bottom: 30, left: 40 };
|
|
19740
|
+
const chartWidth = width - padding.left - padding.right;
|
|
19741
|
+
const chartHeight = height - padding.top - padding.bottom;
|
|
19742
|
+
const { minX, maxX, minY, maxY } = React81.useMemo(() => {
|
|
19743
|
+
if (data.length === 0) {
|
|
19744
|
+
return { minX: 0, maxX: 1, minY: 0, maxY: 1 };
|
|
19745
|
+
}
|
|
19746
|
+
let mnX = data[0].x;
|
|
19747
|
+
let mxX = data[0].x;
|
|
19748
|
+
let mnY = data[0].y;
|
|
19749
|
+
let mxY = data[0].y;
|
|
19750
|
+
for (const p2 of data) {
|
|
19751
|
+
if (p2.x < mnX) mnX = p2.x;
|
|
19752
|
+
if (p2.x > mxX) mxX = p2.x;
|
|
19753
|
+
if (p2.y < mnY) mnY = p2.y;
|
|
19754
|
+
if (p2.y > mxY) mxY = p2.y;
|
|
19755
|
+
}
|
|
19756
|
+
return { minX: mnX, maxX: mxX, minY: mnY, maxY: mxY };
|
|
19757
|
+
}, [data]);
|
|
19758
|
+
const rangeX = maxX - minX || 1;
|
|
19759
|
+
const rangeY = maxY - minY || 1;
|
|
19760
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
19761
|
+
"svg",
|
|
19762
|
+
{
|
|
19763
|
+
width: "100%",
|
|
19764
|
+
height,
|
|
19765
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
19766
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
19767
|
+
children: [
|
|
19768
|
+
[0, 0.25, 0.5, 0.75, 1].map((frac) => {
|
|
19769
|
+
const y = padding.top + chartHeight * (1 - frac);
|
|
19770
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19771
|
+
"line",
|
|
19772
|
+
{
|
|
19773
|
+
x1: padding.left,
|
|
19774
|
+
y1: y,
|
|
19775
|
+
x2: width - padding.right,
|
|
19776
|
+
y2: y,
|
|
19777
|
+
stroke: "var(--color-border)",
|
|
19778
|
+
strokeDasharray: "4 4",
|
|
19779
|
+
opacity: 0.5
|
|
19780
|
+
},
|
|
19781
|
+
frac
|
|
19782
|
+
);
|
|
19783
|
+
}),
|
|
19784
|
+
data.map((p2, idx) => {
|
|
19785
|
+
const cx = padding.left + (p2.x - minX) / rangeX * chartWidth;
|
|
19786
|
+
const cy = padding.top + chartHeight - (p2.y - minY) / rangeY * chartHeight;
|
|
19787
|
+
const r = p2.size ?? 5;
|
|
19788
|
+
const color = p2.color ?? CHART_COLORS[idx % CHART_COLORS.length];
|
|
19789
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19790
|
+
"circle",
|
|
19791
|
+
{
|
|
19792
|
+
cx,
|
|
19793
|
+
cy,
|
|
19794
|
+
r,
|
|
19795
|
+
fill: color,
|
|
19796
|
+
opacity: 0.7,
|
|
19797
|
+
className: "cursor-pointer hover:opacity-100",
|
|
19798
|
+
onClick: () => onPointClick?.(
|
|
19799
|
+
{
|
|
19800
|
+
label: p2.label ?? `(${p2.x}, ${p2.y})`,
|
|
19801
|
+
value: p2.y,
|
|
19802
|
+
color
|
|
19803
|
+
},
|
|
19804
|
+
"default"
|
|
19805
|
+
),
|
|
19806
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("title", { children: p2.label ?? `(${p2.x}, ${p2.y})` })
|
|
19807
|
+
},
|
|
19808
|
+
idx
|
|
19809
|
+
);
|
|
19810
|
+
}),
|
|
19811
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19812
|
+
"text",
|
|
19813
|
+
{
|
|
19814
|
+
x: padding.left,
|
|
19815
|
+
y: height - 8,
|
|
19816
|
+
fill: "var(--color-muted-foreground)",
|
|
19817
|
+
fontSize: "9",
|
|
19818
|
+
children: minX.toFixed(1)
|
|
19819
|
+
}
|
|
19820
|
+
),
|
|
19821
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19822
|
+
"text",
|
|
19823
|
+
{
|
|
19824
|
+
x: width - padding.right,
|
|
19825
|
+
y: height - 8,
|
|
19826
|
+
textAnchor: "end",
|
|
19827
|
+
fill: "var(--color-muted-foreground)",
|
|
19828
|
+
fontSize: "9",
|
|
19829
|
+
children: maxX.toFixed(1)
|
|
19830
|
+
}
|
|
19831
|
+
)
|
|
19832
|
+
]
|
|
19833
|
+
}
|
|
19834
|
+
);
|
|
19462
19835
|
};
|
|
19463
19836
|
Chart = ({
|
|
19464
19837
|
title,
|
|
@@ -19466,9 +19839,13 @@ var init_Chart = __esm({
|
|
|
19466
19839
|
chartType = "bar",
|
|
19467
19840
|
series,
|
|
19468
19841
|
data: simpleData,
|
|
19842
|
+
scatterData,
|
|
19469
19843
|
height = 200,
|
|
19470
19844
|
showLegend = true,
|
|
19471
19845
|
showValues = false,
|
|
19846
|
+
stack = "none",
|
|
19847
|
+
timeAxis = false,
|
|
19848
|
+
drillEvent,
|
|
19472
19849
|
actions,
|
|
19473
19850
|
entity,
|
|
19474
19851
|
isLoading = false,
|
|
@@ -19485,11 +19862,25 @@ var init_Chart = __esm({
|
|
|
19485
19862
|
},
|
|
19486
19863
|
[eventBus]
|
|
19487
19864
|
);
|
|
19488
|
-
const
|
|
19489
|
-
|
|
19490
|
-
|
|
19865
|
+
const handlePointClick = React81.useCallback(
|
|
19866
|
+
(point, seriesName) => {
|
|
19867
|
+
if (drillEvent) {
|
|
19868
|
+
eventBus.emit(`UI:${drillEvent}`, {
|
|
19869
|
+
label: point.label,
|
|
19870
|
+
value: point.value,
|
|
19871
|
+
seriesLabel: seriesName === "default" ? void 0 : seriesName
|
|
19872
|
+
});
|
|
19873
|
+
}
|
|
19874
|
+
},
|
|
19875
|
+
[drillEvent, eventBus]
|
|
19876
|
+
);
|
|
19877
|
+
const normalizedSeries = React81.useMemo(() => {
|
|
19878
|
+
if (series && series.length > 0) return series;
|
|
19879
|
+
if (simpleData) return [{ name: "default", data: simpleData }];
|
|
19491
19880
|
return [];
|
|
19492
19881
|
}, [simpleData, series]);
|
|
19882
|
+
const firstSeriesData = normalizedSeries[0]?.data ?? [];
|
|
19883
|
+
const hasContent = chartType === "scatter" ? (scatterData?.length ?? 0) > 0 : normalizedSeries.some((s) => s.data.length > 0);
|
|
19493
19884
|
if (isLoading) {
|
|
19494
19885
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingState, { message: "Loading chart...", className });
|
|
19495
19886
|
}
|
|
@@ -19503,7 +19894,7 @@ var init_Chart = __esm({
|
|
|
19503
19894
|
}
|
|
19504
19895
|
);
|
|
19505
19896
|
}
|
|
19506
|
-
if (
|
|
19897
|
+
if (!hasContent) {
|
|
19507
19898
|
return /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { title: t("empty.noData"), description: t("empty.noData"), className });
|
|
19508
19899
|
}
|
|
19509
19900
|
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn("p-6", className), children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "md", children: [
|
|
@@ -19524,18 +19915,84 @@ var init_Chart = __esm({
|
|
|
19524
19915
|
)) })
|
|
19525
19916
|
] }),
|
|
19526
19917
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "w-full", children: [
|
|
19527
|
-
chartType === "bar" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19528
|
-
|
|
19529
|
-
|
|
19530
|
-
|
|
19531
|
-
|
|
19918
|
+
chartType === "bar" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19919
|
+
BarChart,
|
|
19920
|
+
{
|
|
19921
|
+
series: normalizedSeries,
|
|
19922
|
+
height,
|
|
19923
|
+
showValues,
|
|
19924
|
+
stack,
|
|
19925
|
+
timeAxis,
|
|
19926
|
+
onPointClick: handlePointClick
|
|
19927
|
+
}
|
|
19928
|
+
),
|
|
19929
|
+
chartType === "histogram" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19930
|
+
BarChart,
|
|
19931
|
+
{
|
|
19932
|
+
series: normalizedSeries,
|
|
19933
|
+
height,
|
|
19934
|
+
showValues,
|
|
19935
|
+
stack: "none",
|
|
19936
|
+
timeAxis: false,
|
|
19937
|
+
histogram: true,
|
|
19938
|
+
onPointClick: handlePointClick
|
|
19939
|
+
}
|
|
19940
|
+
),
|
|
19941
|
+
chartType === "line" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19942
|
+
LineChart,
|
|
19943
|
+
{
|
|
19944
|
+
series: normalizedSeries,
|
|
19945
|
+
height,
|
|
19946
|
+
showValues,
|
|
19947
|
+
timeAxis,
|
|
19948
|
+
onPointClick: handlePointClick
|
|
19949
|
+
}
|
|
19950
|
+
),
|
|
19951
|
+
chartType === "area" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19952
|
+
LineChart,
|
|
19953
|
+
{
|
|
19954
|
+
series: normalizedSeries,
|
|
19955
|
+
height,
|
|
19956
|
+
showValues,
|
|
19957
|
+
timeAxis,
|
|
19958
|
+
fill: true,
|
|
19959
|
+
onPointClick: handlePointClick
|
|
19960
|
+
}
|
|
19961
|
+
),
|
|
19962
|
+
chartType === "pie" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19963
|
+
PieChart,
|
|
19964
|
+
{
|
|
19965
|
+
data: firstSeriesData,
|
|
19966
|
+
height,
|
|
19967
|
+
showValues: showLegend,
|
|
19968
|
+
onPointClick: handlePointClick
|
|
19969
|
+
}
|
|
19970
|
+
),
|
|
19971
|
+
chartType === "donut" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19972
|
+
PieChart,
|
|
19973
|
+
{
|
|
19974
|
+
data: firstSeriesData,
|
|
19975
|
+
height,
|
|
19976
|
+
showValues: showLegend,
|
|
19977
|
+
donut: true,
|
|
19978
|
+
onPointClick: handlePointClick
|
|
19979
|
+
}
|
|
19980
|
+
),
|
|
19981
|
+
chartType === "scatter" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19982
|
+
ScatterChart,
|
|
19983
|
+
{
|
|
19984
|
+
data: scatterData ?? [],
|
|
19985
|
+
height,
|
|
19986
|
+
onPointClick: handlePointClick
|
|
19987
|
+
}
|
|
19988
|
+
)
|
|
19532
19989
|
] }),
|
|
19533
|
-
showLegend &&
|
|
19990
|
+
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: [
|
|
19534
19991
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19535
19992
|
Box,
|
|
19536
19993
|
{
|
|
19537
19994
|
className: "w-3 h-3 rounded-full flex-shrink-0",
|
|
19538
|
-
style: { backgroundColor: s
|
|
19995
|
+
style: { backgroundColor: seriesColor(s, idx) }
|
|
19539
19996
|
}
|
|
19540
19997
|
),
|
|
19541
19998
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: s.name })
|
|
@@ -21396,7 +21853,6 @@ function useDataDnd(args) {
|
|
|
21396
21853
|
const raw = it[dndItemIdField];
|
|
21397
21854
|
return raw ?? `__idx_${idx}`;
|
|
21398
21855
|
}),
|
|
21399
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
21400
21856
|
[itemIdsSignature]
|
|
21401
21857
|
);
|
|
21402
21858
|
const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
|
|
@@ -22990,7 +23446,16 @@ var init_FilterGroup = __esm({
|
|
|
22990
23446
|
onClear: () => handleFilterSelect(`${filter.field}_to`, null)
|
|
22991
23447
|
}
|
|
22992
23448
|
)
|
|
22993
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
23449
|
+
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
23450
|
+
Input,
|
|
23451
|
+
{
|
|
23452
|
+
value: selectedValues[filter.field] || "",
|
|
23453
|
+
onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
|
|
23454
|
+
placeholder: filter.label,
|
|
23455
|
+
clearable: true,
|
|
23456
|
+
onClear: () => handleFilterSelect(filter.field, null)
|
|
23457
|
+
}
|
|
23458
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
22994
23459
|
Select,
|
|
22995
23460
|
{
|
|
22996
23461
|
value: selectedValues[filter.field] || "all",
|
|
@@ -23057,7 +23522,17 @@ var init_FilterGroup = __esm({
|
|
|
23057
23522
|
className: "text-sm min-w-[100px]"
|
|
23058
23523
|
}
|
|
23059
23524
|
)
|
|
23060
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
23525
|
+
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
23526
|
+
Input,
|
|
23527
|
+
{
|
|
23528
|
+
value: selectedValues[filter.field] || "",
|
|
23529
|
+
onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
|
|
23530
|
+
placeholder: filter.label,
|
|
23531
|
+
clearable: true,
|
|
23532
|
+
onClear: () => handleFilterSelect(filter.field, null),
|
|
23533
|
+
className: "text-sm"
|
|
23534
|
+
}
|
|
23535
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
23061
23536
|
Select,
|
|
23062
23537
|
{
|
|
23063
23538
|
value: selectedValues[filter.field] || "all",
|
|
@@ -23162,7 +23637,17 @@ var init_FilterGroup = __esm({
|
|
|
23162
23637
|
className: "min-w-[130px]"
|
|
23163
23638
|
}
|
|
23164
23639
|
)
|
|
23165
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
23640
|
+
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
23641
|
+
Input,
|
|
23642
|
+
{
|
|
23643
|
+
value: selectedValues[filter.field] || "",
|
|
23644
|
+
onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
|
|
23645
|
+
placeholder: filter.label,
|
|
23646
|
+
clearable: true,
|
|
23647
|
+
onClear: () => handleFilterSelect(filter.field, null),
|
|
23648
|
+
className: "min-w-[160px]"
|
|
23649
|
+
}
|
|
23650
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
23166
23651
|
Select,
|
|
23167
23652
|
{
|
|
23168
23653
|
value: selectedValues[filter.field] || "all",
|
|
@@ -24451,6 +24936,151 @@ var init_FlipCard = __esm({
|
|
|
24451
24936
|
FlipCard.displayName = "FlipCard";
|
|
24452
24937
|
}
|
|
24453
24938
|
});
|
|
24939
|
+
function toISODate(d) {
|
|
24940
|
+
return d.toISOString().slice(0, 10);
|
|
24941
|
+
}
|
|
24942
|
+
function startOfMonth(d) {
|
|
24943
|
+
return new Date(d.getFullYear(), d.getMonth(), 1);
|
|
24944
|
+
}
|
|
24945
|
+
function startOfQuarter(d) {
|
|
24946
|
+
return new Date(d.getFullYear(), Math.floor(d.getMonth() / 3) * 3, 1);
|
|
24947
|
+
}
|
|
24948
|
+
function startOfYear(d) {
|
|
24949
|
+
return new Date(d.getFullYear(), 0, 1);
|
|
24950
|
+
}
|
|
24951
|
+
function daysAgo(n) {
|
|
24952
|
+
const d = /* @__PURE__ */ new Date();
|
|
24953
|
+
d.setDate(d.getDate() - n);
|
|
24954
|
+
return d;
|
|
24955
|
+
}
|
|
24956
|
+
var DEFAULT_PRESETS, DateRangePicker;
|
|
24957
|
+
var init_DateRangePicker = __esm({
|
|
24958
|
+
"components/molecules/DateRangePicker.tsx"() {
|
|
24959
|
+
"use client";
|
|
24960
|
+
init_cn();
|
|
24961
|
+
init_Button();
|
|
24962
|
+
init_Input();
|
|
24963
|
+
init_Stack();
|
|
24964
|
+
init_Typography();
|
|
24965
|
+
init_useEventBus();
|
|
24966
|
+
DEFAULT_PRESETS = [
|
|
24967
|
+
{
|
|
24968
|
+
label: "Last 7 days",
|
|
24969
|
+
value: "7d",
|
|
24970
|
+
range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24971
|
+
},
|
|
24972
|
+
{
|
|
24973
|
+
label: "Last 30 days",
|
|
24974
|
+
value: "30d",
|
|
24975
|
+
range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24976
|
+
},
|
|
24977
|
+
{
|
|
24978
|
+
label: "This Month",
|
|
24979
|
+
value: "month",
|
|
24980
|
+
range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24981
|
+
},
|
|
24982
|
+
{
|
|
24983
|
+
label: "This Quarter",
|
|
24984
|
+
value: "quarter",
|
|
24985
|
+
range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24986
|
+
},
|
|
24987
|
+
{
|
|
24988
|
+
label: "YTD",
|
|
24989
|
+
value: "ytd",
|
|
24990
|
+
range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24991
|
+
}
|
|
24992
|
+
];
|
|
24993
|
+
DateRangePicker = ({
|
|
24994
|
+
from: fromProp,
|
|
24995
|
+
to: toProp,
|
|
24996
|
+
event,
|
|
24997
|
+
onChange,
|
|
24998
|
+
presets = DEFAULT_PRESETS,
|
|
24999
|
+
fromLabel = "From",
|
|
25000
|
+
toLabel = "To",
|
|
25001
|
+
className
|
|
25002
|
+
}) => {
|
|
25003
|
+
const eventBus = useEventBus();
|
|
25004
|
+
const [from, setFrom] = React81.useState(fromProp ?? "");
|
|
25005
|
+
const [to, setTo] = React81.useState(toProp ?? "");
|
|
25006
|
+
const [activePreset, setActivePreset] = React81.useState(null);
|
|
25007
|
+
const emit = React81.useCallback(
|
|
25008
|
+
(range) => {
|
|
25009
|
+
onChange?.(range);
|
|
25010
|
+
if (event) eventBus.emit(`UI:${event}`, range);
|
|
25011
|
+
},
|
|
25012
|
+
[onChange, event, eventBus]
|
|
25013
|
+
);
|
|
25014
|
+
const handleFromChange = React81.useCallback(
|
|
25015
|
+
(next) => {
|
|
25016
|
+
setFrom(next);
|
|
25017
|
+
setActivePreset(null);
|
|
25018
|
+
emit({ from: next, to });
|
|
25019
|
+
},
|
|
25020
|
+
[to, emit]
|
|
25021
|
+
);
|
|
25022
|
+
const handleToChange = React81.useCallback(
|
|
25023
|
+
(next) => {
|
|
25024
|
+
setTo(next);
|
|
25025
|
+
setActivePreset(null);
|
|
25026
|
+
emit({ from, to: next });
|
|
25027
|
+
},
|
|
25028
|
+
[from, emit]
|
|
25029
|
+
);
|
|
25030
|
+
const handlePreset = React81.useCallback(
|
|
25031
|
+
(preset) => {
|
|
25032
|
+
const range = preset.range();
|
|
25033
|
+
setFrom(range.from);
|
|
25034
|
+
setTo(range.to);
|
|
25035
|
+
setActivePreset(preset.value);
|
|
25036
|
+
emit(range);
|
|
25037
|
+
},
|
|
25038
|
+
[emit]
|
|
25039
|
+
);
|
|
25040
|
+
const presetButtons = React81.useMemo(
|
|
25041
|
+
() => presets.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
25042
|
+
Button,
|
|
25043
|
+
{
|
|
25044
|
+
variant: activePreset === preset.value ? "primary" : "ghost",
|
|
25045
|
+
size: "sm",
|
|
25046
|
+
onClick: () => handlePreset(preset),
|
|
25047
|
+
children: preset.label
|
|
25048
|
+
},
|
|
25049
|
+
preset.value
|
|
25050
|
+
)),
|
|
25051
|
+
[presets, activePreset, handlePreset]
|
|
25052
|
+
);
|
|
25053
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", className: cn(className), children: [
|
|
25054
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "md", align: "end", children: [
|
|
25055
|
+
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
25056
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: fromLabel }),
|
|
25057
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
25058
|
+
Input,
|
|
25059
|
+
{
|
|
25060
|
+
type: "date",
|
|
25061
|
+
value: from,
|
|
25062
|
+
onChange: (e) => handleFromChange(e.target.value)
|
|
25063
|
+
}
|
|
25064
|
+
)
|
|
25065
|
+
] }),
|
|
25066
|
+
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
25067
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: toLabel }),
|
|
25068
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
25069
|
+
Input,
|
|
25070
|
+
{
|
|
25071
|
+
type: "date",
|
|
25072
|
+
value: to,
|
|
25073
|
+
onChange: (e) => handleToChange(e.target.value)
|
|
25074
|
+
}
|
|
25075
|
+
)
|
|
25076
|
+
] })
|
|
25077
|
+
] }),
|
|
25078
|
+
presets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
|
|
25079
|
+
] });
|
|
25080
|
+
};
|
|
25081
|
+
DateRangePicker.displayName = "DateRangePicker";
|
|
25082
|
+
}
|
|
25083
|
+
});
|
|
24454
25084
|
var DEFAULT_OPTIONS, DateRangeSelector;
|
|
24455
25085
|
var init_DateRangeSelector = __esm({
|
|
24456
25086
|
"components/molecules/DateRangeSelector.tsx"() {
|
|
@@ -27422,7 +28052,9 @@ var init_StatDisplay = __esm({
|
|
|
27422
28052
|
init_Typography();
|
|
27423
28053
|
init_Box();
|
|
27424
28054
|
init_Stack();
|
|
28055
|
+
init_Sparkline();
|
|
27425
28056
|
init_Icon();
|
|
28057
|
+
init_useEventBus();
|
|
27426
28058
|
variantColor = {
|
|
27427
28059
|
default: "text-foreground",
|
|
27428
28060
|
primary: "text-primary",
|
|
@@ -27437,6 +28069,10 @@ var init_StatDisplay = __esm({
|
|
|
27437
28069
|
max,
|
|
27438
28070
|
target,
|
|
27439
28071
|
trend,
|
|
28072
|
+
trendPolarity = "higher-is-better",
|
|
28073
|
+
trendFormat = "absolute",
|
|
28074
|
+
sparklineData,
|
|
28075
|
+
clickEvent,
|
|
27440
28076
|
prefix,
|
|
27441
28077
|
suffix,
|
|
27442
28078
|
icon: iconProp,
|
|
@@ -27450,6 +28086,10 @@ var init_StatDisplay = __esm({
|
|
|
27450
28086
|
isLoading = false,
|
|
27451
28087
|
error = null
|
|
27452
28088
|
}) => {
|
|
28089
|
+
const eventBus = useEventBus();
|
|
28090
|
+
const handleClick = React81.useCallback(() => {
|
|
28091
|
+
if (clickEvent) eventBus.emit(`UI:${clickEvent}`, { metricLabel: label });
|
|
28092
|
+
}, [clickEvent, eventBus, label]);
|
|
27453
28093
|
const ResolvedIcon = typeof iconProp === "string" ? resolveIcon(iconProp) : null;
|
|
27454
28094
|
const iconSizes3 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
|
|
27455
28095
|
const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
|
|
@@ -27460,7 +28100,10 @@ var init_StatDisplay = __esm({
|
|
|
27460
28100
|
const targetPct = showTarget ? Math.max(0, Math.min(100, numericValue / target * 100)) : 0;
|
|
27461
28101
|
const showTrend = typeof trend === "number" && trend !== 0 && Number.isFinite(trend);
|
|
27462
28102
|
const trendUp = showTrend && trend > 0;
|
|
27463
|
-
const
|
|
28103
|
+
const trendIsGood = trendPolarity === "lower-is-better" ? !trendUp : trendUp;
|
|
28104
|
+
const trendMagnitude = Math.abs(trend);
|
|
28105
|
+
const trendSuffix = trendFormat === "percent" ? "%" : "";
|
|
28106
|
+
const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${trendMagnitude}${trendSuffix}` : "";
|
|
27464
28107
|
if (error) {
|
|
27465
28108
|
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "error", children: error.message }) });
|
|
27466
28109
|
}
|
|
@@ -27471,38 +28114,57 @@ var init_StatDisplay = __esm({
|
|
|
27471
28114
|
] }) });
|
|
27472
28115
|
}
|
|
27473
28116
|
if (compact) {
|
|
27474
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
27475
|
-
|
|
27476
|
-
|
|
27477
|
-
|
|
27478
|
-
|
|
27479
|
-
|
|
27480
|
-
|
|
28117
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
28118
|
+
HStack,
|
|
28119
|
+
{
|
|
28120
|
+
gap: "sm",
|
|
28121
|
+
className: cn("items-center", clickEvent && "cursor-pointer hover:opacity-80", className),
|
|
28122
|
+
onClick: clickEvent ? handleClick : void 0,
|
|
28123
|
+
children: [
|
|
28124
|
+
ResolvedIcon && /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
|
|
28125
|
+
typeof iconProp !== "string" && iconProp,
|
|
28126
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: label }),
|
|
28127
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
|
|
28128
|
+
showTrend && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: cn("font-semibold", trendIsGood ? "text-success" : "text-error"), children: trendLabel }),
|
|
28129
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto", width: 60, height: 20 })
|
|
28130
|
+
]
|
|
28131
|
+
}
|
|
28132
|
+
);
|
|
27481
28133
|
}
|
|
27482
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
27483
|
-
|
|
27484
|
-
|
|
27485
|
-
|
|
27486
|
-
|
|
27487
|
-
|
|
27488
|
-
|
|
27489
|
-
{
|
|
27490
|
-
|
|
27491
|
-
className: cn("font-
|
|
27492
|
-
|
|
27493
|
-
|
|
27494
|
-
|
|
27495
|
-
|
|
27496
|
-
|
|
27497
|
-
|
|
27498
|
-
|
|
27499
|
-
|
|
27500
|
-
|
|
27501
|
-
|
|
27502
|
-
|
|
27503
|
-
|
|
27504
|
-
|
|
27505
|
-
|
|
28134
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
28135
|
+
Card,
|
|
28136
|
+
{
|
|
28137
|
+
className: cn(padSizes[size], clickEvent && "cursor-pointer hover:shadow-md transition-shadow", className),
|
|
28138
|
+
onClick: clickEvent ? handleClick : void 0,
|
|
28139
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "start", justify: "between", children: [
|
|
28140
|
+
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
|
|
28141
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "overline", color: "secondary", children: label }),
|
|
28142
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "end", children: [
|
|
28143
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
|
|
28144
|
+
showTrend && /* @__PURE__ */ jsxRuntime.jsx(
|
|
28145
|
+
Typography,
|
|
28146
|
+
{
|
|
28147
|
+
variant: "caption",
|
|
28148
|
+
className: cn("font-semibold pb-1", trendIsGood ? "text-success" : "text-error"),
|
|
28149
|
+
children: trendLabel
|
|
28150
|
+
}
|
|
28151
|
+
)
|
|
28152
|
+
] }),
|
|
28153
|
+
showTarget && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
28154
|
+
Box,
|
|
28155
|
+
{
|
|
28156
|
+
className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
|
|
28157
|
+
style: { width: `${targetPct}%` }
|
|
28158
|
+
}
|
|
28159
|
+
) })
|
|
28160
|
+
] }),
|
|
28161
|
+
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "end", children: [
|
|
28162
|
+
(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 }),
|
|
28163
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto" })
|
|
28164
|
+
] })
|
|
28165
|
+
] })
|
|
28166
|
+
}
|
|
28167
|
+
);
|
|
27506
28168
|
};
|
|
27507
28169
|
StatDisplay.displayName = "StatDisplay";
|
|
27508
28170
|
}
|
|
@@ -41965,6 +42627,7 @@ var init_StatCard = __esm({
|
|
|
41965
42627
|
init_Box();
|
|
41966
42628
|
init_Stack();
|
|
41967
42629
|
init_Button();
|
|
42630
|
+
init_Sparkline();
|
|
41968
42631
|
init_useEventBus();
|
|
41969
42632
|
init_useTranslate();
|
|
41970
42633
|
init_Icon();
|
|
@@ -42134,32 +42797,7 @@ var init_StatCard = __esm({
|
|
|
42134
42797
|
] }),
|
|
42135
42798
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "end", children: [
|
|
42136
42799
|
Icon3 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("p-3", iconBg), children: /* @__PURE__ */ jsxRuntime.jsx(Icon3, { className: cn("h-6 w-6", iconColor) }) }),
|
|
42137
|
-
sparklineData && sparklineData.length > 1 && (
|
|
42138
|
-
const w = 80;
|
|
42139
|
-
const h = 32;
|
|
42140
|
-
const pad = 2;
|
|
42141
|
-
const min = Math.min(...sparklineData);
|
|
42142
|
-
const max = Math.max(...sparklineData);
|
|
42143
|
-
const range = max - min || 1;
|
|
42144
|
-
const points = sparklineData.map((v, i) => {
|
|
42145
|
-
const x = pad + i / (sparklineData.length - 1) * (w - pad * 2);
|
|
42146
|
-
const y = pad + (1 - (v - min) / range) * (h - pad * 2);
|
|
42147
|
-
return `${x},${y}`;
|
|
42148
|
-
}).join(" ");
|
|
42149
|
-
const trending = sparklineData[sparklineData.length - 1] >= sparklineData[0];
|
|
42150
|
-
const strokeColor = trending ? "var(--color-success)" : "var(--color-error)";
|
|
42151
|
-
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: w, height: h, viewBox: `0 0 ${w} ${h}`, className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
42152
|
-
"polyline",
|
|
42153
|
-
{
|
|
42154
|
-
fill: "none",
|
|
42155
|
-
stroke: strokeColor,
|
|
42156
|
-
strokeWidth: "2",
|
|
42157
|
-
strokeLinecap: "round",
|
|
42158
|
-
strokeLinejoin: "round",
|
|
42159
|
-
points
|
|
42160
|
-
}
|
|
42161
|
-
) });
|
|
42162
|
-
})()
|
|
42800
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto" })
|
|
42163
42801
|
] })
|
|
42164
42802
|
] }),
|
|
42165
42803
|
action && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -44057,6 +44695,7 @@ var init_component_registry_generated = __esm({
|
|
|
44057
44695
|
init_DataGrid();
|
|
44058
44696
|
init_DataList();
|
|
44059
44697
|
init_DataTable();
|
|
44698
|
+
init_DateRangePicker();
|
|
44060
44699
|
init_DateRangeSelector();
|
|
44061
44700
|
init_DayCell();
|
|
44062
44701
|
init_DebuggerBoard();
|
|
@@ -44189,6 +44828,7 @@ var init_component_registry_generated = __esm({
|
|
|
44189
44828
|
init_Skeleton();
|
|
44190
44829
|
init_SocialProof();
|
|
44191
44830
|
init_SortableList();
|
|
44831
|
+
init_Sparkline();
|
|
44192
44832
|
init_Split();
|
|
44193
44833
|
init_SplitPane();
|
|
44194
44834
|
init_SplitSection();
|
|
@@ -44337,6 +44977,7 @@ var init_component_registry_generated = __esm({
|
|
|
44337
44977
|
"DataGrid": DataGrid,
|
|
44338
44978
|
"DataList": DataList,
|
|
44339
44979
|
"DataTable": DataTable,
|
|
44980
|
+
"DateRangePicker": DateRangePicker,
|
|
44340
44981
|
"DateRangeSelector": DateRangeSelector,
|
|
44341
44982
|
"DayCell": DayCell,
|
|
44342
44983
|
"DebuggerBoard": DebuggerBoard,
|
|
@@ -44498,6 +45139,7 @@ var init_component_registry_generated = __esm({
|
|
|
44498
45139
|
"SortableList": SortableList,
|
|
44499
45140
|
"Spacer": SpacerPattern,
|
|
44500
45141
|
"SpacerPattern": SpacerPattern,
|
|
45142
|
+
"Sparkline": Sparkline,
|
|
44501
45143
|
"Spinner": SpinnerPattern,
|
|
44502
45144
|
"SpinnerPattern": SpinnerPattern,
|
|
44503
45145
|
"Split": Split,
|