@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.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 })
|
|
@@ -21350,7 +21807,6 @@ function useDataDnd(args) {
|
|
|
21350
21807
|
const raw = it[dndItemIdField];
|
|
21351
21808
|
return raw ?? `__idx_${idx}`;
|
|
21352
21809
|
}),
|
|
21353
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
21354
21810
|
[itemIdsSignature]
|
|
21355
21811
|
);
|
|
21356
21812
|
const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
|
|
@@ -22944,7 +23400,16 @@ var init_FilterGroup = __esm({
|
|
|
22944
23400
|
onClear: () => handleFilterSelect(`${filter.field}_to`, null)
|
|
22945
23401
|
}
|
|
22946
23402
|
)
|
|
22947
|
-
] }) : /* @__PURE__ */ jsx(
|
|
23403
|
+
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
|
|
23404
|
+
Input,
|
|
23405
|
+
{
|
|
23406
|
+
value: selectedValues[filter.field] || "",
|
|
23407
|
+
onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
|
|
23408
|
+
placeholder: filter.label,
|
|
23409
|
+
clearable: true,
|
|
23410
|
+
onClear: () => handleFilterSelect(filter.field, null)
|
|
23411
|
+
}
|
|
23412
|
+
) : /* @__PURE__ */ jsx(
|
|
22948
23413
|
Select,
|
|
22949
23414
|
{
|
|
22950
23415
|
value: selectedValues[filter.field] || "all",
|
|
@@ -23011,7 +23476,17 @@ var init_FilterGroup = __esm({
|
|
|
23011
23476
|
className: "text-sm min-w-[100px]"
|
|
23012
23477
|
}
|
|
23013
23478
|
)
|
|
23014
|
-
] }) : /* @__PURE__ */ jsx(
|
|
23479
|
+
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
|
|
23480
|
+
Input,
|
|
23481
|
+
{
|
|
23482
|
+
value: selectedValues[filter.field] || "",
|
|
23483
|
+
onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
|
|
23484
|
+
placeholder: filter.label,
|
|
23485
|
+
clearable: true,
|
|
23486
|
+
onClear: () => handleFilterSelect(filter.field, null),
|
|
23487
|
+
className: "text-sm"
|
|
23488
|
+
}
|
|
23489
|
+
) : /* @__PURE__ */ jsx(
|
|
23015
23490
|
Select,
|
|
23016
23491
|
{
|
|
23017
23492
|
value: selectedValues[filter.field] || "all",
|
|
@@ -23116,7 +23591,17 @@ var init_FilterGroup = __esm({
|
|
|
23116
23591
|
className: "min-w-[130px]"
|
|
23117
23592
|
}
|
|
23118
23593
|
)
|
|
23119
|
-
] }) : /* @__PURE__ */ jsx(
|
|
23594
|
+
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
|
|
23595
|
+
Input,
|
|
23596
|
+
{
|
|
23597
|
+
value: selectedValues[filter.field] || "",
|
|
23598
|
+
onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
|
|
23599
|
+
placeholder: filter.label,
|
|
23600
|
+
clearable: true,
|
|
23601
|
+
onClear: () => handleFilterSelect(filter.field, null),
|
|
23602
|
+
className: "min-w-[160px]"
|
|
23603
|
+
}
|
|
23604
|
+
) : /* @__PURE__ */ jsx(
|
|
23120
23605
|
Select,
|
|
23121
23606
|
{
|
|
23122
23607
|
value: selectedValues[filter.field] || "all",
|
|
@@ -24405,6 +24890,151 @@ var init_FlipCard = __esm({
|
|
|
24405
24890
|
FlipCard.displayName = "FlipCard";
|
|
24406
24891
|
}
|
|
24407
24892
|
});
|
|
24893
|
+
function toISODate(d) {
|
|
24894
|
+
return d.toISOString().slice(0, 10);
|
|
24895
|
+
}
|
|
24896
|
+
function startOfMonth(d) {
|
|
24897
|
+
return new Date(d.getFullYear(), d.getMonth(), 1);
|
|
24898
|
+
}
|
|
24899
|
+
function startOfQuarter(d) {
|
|
24900
|
+
return new Date(d.getFullYear(), Math.floor(d.getMonth() / 3) * 3, 1);
|
|
24901
|
+
}
|
|
24902
|
+
function startOfYear(d) {
|
|
24903
|
+
return new Date(d.getFullYear(), 0, 1);
|
|
24904
|
+
}
|
|
24905
|
+
function daysAgo(n) {
|
|
24906
|
+
const d = /* @__PURE__ */ new Date();
|
|
24907
|
+
d.setDate(d.getDate() - n);
|
|
24908
|
+
return d;
|
|
24909
|
+
}
|
|
24910
|
+
var DEFAULT_PRESETS, DateRangePicker;
|
|
24911
|
+
var init_DateRangePicker = __esm({
|
|
24912
|
+
"components/molecules/DateRangePicker.tsx"() {
|
|
24913
|
+
"use client";
|
|
24914
|
+
init_cn();
|
|
24915
|
+
init_Button();
|
|
24916
|
+
init_Input();
|
|
24917
|
+
init_Stack();
|
|
24918
|
+
init_Typography();
|
|
24919
|
+
init_useEventBus();
|
|
24920
|
+
DEFAULT_PRESETS = [
|
|
24921
|
+
{
|
|
24922
|
+
label: "Last 7 days",
|
|
24923
|
+
value: "7d",
|
|
24924
|
+
range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24925
|
+
},
|
|
24926
|
+
{
|
|
24927
|
+
label: "Last 30 days",
|
|
24928
|
+
value: "30d",
|
|
24929
|
+
range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24930
|
+
},
|
|
24931
|
+
{
|
|
24932
|
+
label: "This Month",
|
|
24933
|
+
value: "month",
|
|
24934
|
+
range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24935
|
+
},
|
|
24936
|
+
{
|
|
24937
|
+
label: "This Quarter",
|
|
24938
|
+
value: "quarter",
|
|
24939
|
+
range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24940
|
+
},
|
|
24941
|
+
{
|
|
24942
|
+
label: "YTD",
|
|
24943
|
+
value: "ytd",
|
|
24944
|
+
range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24945
|
+
}
|
|
24946
|
+
];
|
|
24947
|
+
DateRangePicker = ({
|
|
24948
|
+
from: fromProp,
|
|
24949
|
+
to: toProp,
|
|
24950
|
+
event,
|
|
24951
|
+
onChange,
|
|
24952
|
+
presets = DEFAULT_PRESETS,
|
|
24953
|
+
fromLabel = "From",
|
|
24954
|
+
toLabel = "To",
|
|
24955
|
+
className
|
|
24956
|
+
}) => {
|
|
24957
|
+
const eventBus = useEventBus();
|
|
24958
|
+
const [from, setFrom] = useState(fromProp ?? "");
|
|
24959
|
+
const [to, setTo] = useState(toProp ?? "");
|
|
24960
|
+
const [activePreset, setActivePreset] = useState(null);
|
|
24961
|
+
const emit = useCallback(
|
|
24962
|
+
(range) => {
|
|
24963
|
+
onChange?.(range);
|
|
24964
|
+
if (event) eventBus.emit(`UI:${event}`, range);
|
|
24965
|
+
},
|
|
24966
|
+
[onChange, event, eventBus]
|
|
24967
|
+
);
|
|
24968
|
+
const handleFromChange = useCallback(
|
|
24969
|
+
(next) => {
|
|
24970
|
+
setFrom(next);
|
|
24971
|
+
setActivePreset(null);
|
|
24972
|
+
emit({ from: next, to });
|
|
24973
|
+
},
|
|
24974
|
+
[to, emit]
|
|
24975
|
+
);
|
|
24976
|
+
const handleToChange = useCallback(
|
|
24977
|
+
(next) => {
|
|
24978
|
+
setTo(next);
|
|
24979
|
+
setActivePreset(null);
|
|
24980
|
+
emit({ from, to: next });
|
|
24981
|
+
},
|
|
24982
|
+
[from, emit]
|
|
24983
|
+
);
|
|
24984
|
+
const handlePreset = useCallback(
|
|
24985
|
+
(preset) => {
|
|
24986
|
+
const range = preset.range();
|
|
24987
|
+
setFrom(range.from);
|
|
24988
|
+
setTo(range.to);
|
|
24989
|
+
setActivePreset(preset.value);
|
|
24990
|
+
emit(range);
|
|
24991
|
+
},
|
|
24992
|
+
[emit]
|
|
24993
|
+
);
|
|
24994
|
+
const presetButtons = useMemo(
|
|
24995
|
+
() => presets.map((preset) => /* @__PURE__ */ jsx(
|
|
24996
|
+
Button,
|
|
24997
|
+
{
|
|
24998
|
+
variant: activePreset === preset.value ? "primary" : "ghost",
|
|
24999
|
+
size: "sm",
|
|
25000
|
+
onClick: () => handlePreset(preset),
|
|
25001
|
+
children: preset.label
|
|
25002
|
+
},
|
|
25003
|
+
preset.value
|
|
25004
|
+
)),
|
|
25005
|
+
[presets, activePreset, handlePreset]
|
|
25006
|
+
);
|
|
25007
|
+
return /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: cn(className), children: [
|
|
25008
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "md", align: "end", children: [
|
|
25009
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
25010
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: fromLabel }),
|
|
25011
|
+
/* @__PURE__ */ jsx(
|
|
25012
|
+
Input,
|
|
25013
|
+
{
|
|
25014
|
+
type: "date",
|
|
25015
|
+
value: from,
|
|
25016
|
+
onChange: (e) => handleFromChange(e.target.value)
|
|
25017
|
+
}
|
|
25018
|
+
)
|
|
25019
|
+
] }),
|
|
25020
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
25021
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: toLabel }),
|
|
25022
|
+
/* @__PURE__ */ jsx(
|
|
25023
|
+
Input,
|
|
25024
|
+
{
|
|
25025
|
+
type: "date",
|
|
25026
|
+
value: to,
|
|
25027
|
+
onChange: (e) => handleToChange(e.target.value)
|
|
25028
|
+
}
|
|
25029
|
+
)
|
|
25030
|
+
] })
|
|
25031
|
+
] }),
|
|
25032
|
+
presets.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
|
|
25033
|
+
] });
|
|
25034
|
+
};
|
|
25035
|
+
DateRangePicker.displayName = "DateRangePicker";
|
|
25036
|
+
}
|
|
25037
|
+
});
|
|
24408
25038
|
var DEFAULT_OPTIONS, DateRangeSelector;
|
|
24409
25039
|
var init_DateRangeSelector = __esm({
|
|
24410
25040
|
"components/molecules/DateRangeSelector.tsx"() {
|
|
@@ -27376,7 +28006,9 @@ var init_StatDisplay = __esm({
|
|
|
27376
28006
|
init_Typography();
|
|
27377
28007
|
init_Box();
|
|
27378
28008
|
init_Stack();
|
|
28009
|
+
init_Sparkline();
|
|
27379
28010
|
init_Icon();
|
|
28011
|
+
init_useEventBus();
|
|
27380
28012
|
variantColor = {
|
|
27381
28013
|
default: "text-foreground",
|
|
27382
28014
|
primary: "text-primary",
|
|
@@ -27391,6 +28023,10 @@ var init_StatDisplay = __esm({
|
|
|
27391
28023
|
max,
|
|
27392
28024
|
target,
|
|
27393
28025
|
trend,
|
|
28026
|
+
trendPolarity = "higher-is-better",
|
|
28027
|
+
trendFormat = "absolute",
|
|
28028
|
+
sparklineData,
|
|
28029
|
+
clickEvent,
|
|
27394
28030
|
prefix,
|
|
27395
28031
|
suffix,
|
|
27396
28032
|
icon: iconProp,
|
|
@@ -27404,6 +28040,10 @@ var init_StatDisplay = __esm({
|
|
|
27404
28040
|
isLoading = false,
|
|
27405
28041
|
error = null
|
|
27406
28042
|
}) => {
|
|
28043
|
+
const eventBus = useEventBus();
|
|
28044
|
+
const handleClick = useCallback(() => {
|
|
28045
|
+
if (clickEvent) eventBus.emit(`UI:${clickEvent}`, { metricLabel: label });
|
|
28046
|
+
}, [clickEvent, eventBus, label]);
|
|
27407
28047
|
const ResolvedIcon = typeof iconProp === "string" ? resolveIcon(iconProp) : null;
|
|
27408
28048
|
const iconSizes3 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
|
|
27409
28049
|
const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
|
|
@@ -27414,7 +28054,10 @@ var init_StatDisplay = __esm({
|
|
|
27414
28054
|
const targetPct = showTarget ? Math.max(0, Math.min(100, numericValue / target * 100)) : 0;
|
|
27415
28055
|
const showTrend = typeof trend === "number" && trend !== 0 && Number.isFinite(trend);
|
|
27416
28056
|
const trendUp = showTrend && trend > 0;
|
|
27417
|
-
const
|
|
28057
|
+
const trendIsGood = trendPolarity === "lower-is-better" ? !trendUp : trendUp;
|
|
28058
|
+
const trendMagnitude = Math.abs(trend);
|
|
28059
|
+
const trendSuffix = trendFormat === "percent" ? "%" : "";
|
|
28060
|
+
const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${trendMagnitude}${trendSuffix}` : "";
|
|
27418
28061
|
if (error) {
|
|
27419
28062
|
return /* @__PURE__ */ jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsx(Typography, { variant: "small", color: "error", children: error.message }) });
|
|
27420
28063
|
}
|
|
@@ -27425,38 +28068,57 @@ var init_StatDisplay = __esm({
|
|
|
27425
28068
|
] }) });
|
|
27426
28069
|
}
|
|
27427
28070
|
if (compact) {
|
|
27428
|
-
return /* @__PURE__ */ jsxs(
|
|
27429
|
-
|
|
27430
|
-
|
|
27431
|
-
|
|
27432
|
-
|
|
27433
|
-
|
|
27434
|
-
|
|
28071
|
+
return /* @__PURE__ */ jsxs(
|
|
28072
|
+
HStack,
|
|
28073
|
+
{
|
|
28074
|
+
gap: "sm",
|
|
28075
|
+
className: cn("items-center", clickEvent && "cursor-pointer hover:opacity-80", className),
|
|
28076
|
+
onClick: clickEvent ? handleClick : void 0,
|
|
28077
|
+
children: [
|
|
28078
|
+
ResolvedIcon && /* @__PURE__ */ jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
|
|
28079
|
+
typeof iconProp !== "string" && iconProp,
|
|
28080
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: label }),
|
|
28081
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
|
|
28082
|
+
showTrend && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: cn("font-semibold", trendIsGood ? "text-success" : "text-error"), children: trendLabel }),
|
|
28083
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto", width: 60, height: 20 })
|
|
28084
|
+
]
|
|
28085
|
+
}
|
|
28086
|
+
);
|
|
27435
28087
|
}
|
|
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
|
-
|
|
28088
|
+
return /* @__PURE__ */ jsx(
|
|
28089
|
+
Card,
|
|
28090
|
+
{
|
|
28091
|
+
className: cn(padSizes[size], clickEvent && "cursor-pointer hover:shadow-md transition-shadow", className),
|
|
28092
|
+
onClick: clickEvent ? handleClick : void 0,
|
|
28093
|
+
children: /* @__PURE__ */ jsxs(HStack, { align: "start", justify: "between", children: [
|
|
28094
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
|
|
28095
|
+
/* @__PURE__ */ jsx(Typography, { variant: "overline", color: "secondary", children: label }),
|
|
28096
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "end", children: [
|
|
28097
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
|
|
28098
|
+
showTrend && /* @__PURE__ */ jsx(
|
|
28099
|
+
Typography,
|
|
28100
|
+
{
|
|
28101
|
+
variant: "caption",
|
|
28102
|
+
className: cn("font-semibold pb-1", trendIsGood ? "text-success" : "text-error"),
|
|
28103
|
+
children: trendLabel
|
|
28104
|
+
}
|
|
28105
|
+
)
|
|
28106
|
+
] }),
|
|
28107
|
+
showTarget && /* @__PURE__ */ jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
28108
|
+
Box,
|
|
28109
|
+
{
|
|
28110
|
+
className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
|
|
28111
|
+
style: { width: `${targetPct}%` }
|
|
28112
|
+
}
|
|
28113
|
+
) })
|
|
28114
|
+
] }),
|
|
28115
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
|
|
28116
|
+
(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 }),
|
|
28117
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto" })
|
|
28118
|
+
] })
|
|
28119
|
+
] })
|
|
28120
|
+
}
|
|
28121
|
+
);
|
|
27460
28122
|
};
|
|
27461
28123
|
StatDisplay.displayName = "StatDisplay";
|
|
27462
28124
|
}
|
|
@@ -41919,6 +42581,7 @@ var init_StatCard = __esm({
|
|
|
41919
42581
|
init_Box();
|
|
41920
42582
|
init_Stack();
|
|
41921
42583
|
init_Button();
|
|
42584
|
+
init_Sparkline();
|
|
41922
42585
|
init_useEventBus();
|
|
41923
42586
|
init_useTranslate();
|
|
41924
42587
|
init_Icon();
|
|
@@ -42088,32 +42751,7 @@ var init_StatCard = __esm({
|
|
|
42088
42751
|
] }),
|
|
42089
42752
|
/* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
|
|
42090
42753
|
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
|
-
})()
|
|
42754
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto" })
|
|
42117
42755
|
] })
|
|
42118
42756
|
] }),
|
|
42119
42757
|
action && /* @__PURE__ */ jsxs(
|
|
@@ -44011,6 +44649,7 @@ var init_component_registry_generated = __esm({
|
|
|
44011
44649
|
init_DataGrid();
|
|
44012
44650
|
init_DataList();
|
|
44013
44651
|
init_DataTable();
|
|
44652
|
+
init_DateRangePicker();
|
|
44014
44653
|
init_DateRangeSelector();
|
|
44015
44654
|
init_DayCell();
|
|
44016
44655
|
init_DebuggerBoard();
|
|
@@ -44143,6 +44782,7 @@ var init_component_registry_generated = __esm({
|
|
|
44143
44782
|
init_Skeleton();
|
|
44144
44783
|
init_SocialProof();
|
|
44145
44784
|
init_SortableList();
|
|
44785
|
+
init_Sparkline();
|
|
44146
44786
|
init_Split();
|
|
44147
44787
|
init_SplitPane();
|
|
44148
44788
|
init_SplitSection();
|
|
@@ -44291,6 +44931,7 @@ var init_component_registry_generated = __esm({
|
|
|
44291
44931
|
"DataGrid": DataGrid,
|
|
44292
44932
|
"DataList": DataList,
|
|
44293
44933
|
"DataTable": DataTable,
|
|
44934
|
+
"DateRangePicker": DateRangePicker,
|
|
44294
44935
|
"DateRangeSelector": DateRangeSelector,
|
|
44295
44936
|
"DayCell": DayCell,
|
|
44296
44937
|
"DebuggerBoard": DebuggerBoard,
|
|
@@ -44452,6 +45093,7 @@ var init_component_registry_generated = __esm({
|
|
|
44452
45093
|
"SortableList": SortableList,
|
|
44453
45094
|
"Spacer": SpacerPattern,
|
|
44454
45095
|
"SpacerPattern": SpacerPattern,
|
|
45096
|
+
"Sparkline": Sparkline,
|
|
44455
45097
|
"Spinner": SpinnerPattern,
|
|
44456
45098
|
"SpinnerPattern": SpinnerPattern,
|
|
44457
45099
|
"Split": Split,
|