@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
|
@@ -2681,6 +2681,67 @@ var init_Radio = __esm({
|
|
|
2681
2681
|
exports.Radio.displayName = "Radio";
|
|
2682
2682
|
}
|
|
2683
2683
|
});
|
|
2684
|
+
var COLOR_VAR; exports.Sparkline = void 0;
|
|
2685
|
+
var init_Sparkline = __esm({
|
|
2686
|
+
"components/atoms/Sparkline.tsx"() {
|
|
2687
|
+
init_cn();
|
|
2688
|
+
COLOR_VAR = {
|
|
2689
|
+
primary: "var(--color-primary)",
|
|
2690
|
+
success: "var(--color-success)",
|
|
2691
|
+
warning: "var(--color-warning)",
|
|
2692
|
+
error: "var(--color-error)",
|
|
2693
|
+
info: "var(--color-info)",
|
|
2694
|
+
muted: "var(--color-muted-foreground)"
|
|
2695
|
+
};
|
|
2696
|
+
exports.Sparkline = ({
|
|
2697
|
+
data,
|
|
2698
|
+
color = "auto",
|
|
2699
|
+
width = 80,
|
|
2700
|
+
height = 32,
|
|
2701
|
+
strokeWidth = 2,
|
|
2702
|
+
fill = false,
|
|
2703
|
+
className
|
|
2704
|
+
}) => {
|
|
2705
|
+
if (data.length < 2) return null;
|
|
2706
|
+
const pad = 2;
|
|
2707
|
+
const min = Math.min(...data);
|
|
2708
|
+
const max = Math.max(...data);
|
|
2709
|
+
const range = max - min || 1;
|
|
2710
|
+
const points = data.map((v, i) => {
|
|
2711
|
+
const x = pad + i / (data.length - 1) * (width - pad * 2);
|
|
2712
|
+
const y = pad + (1 - (v - min) / range) * (height - pad * 2);
|
|
2713
|
+
return `${x},${y}`;
|
|
2714
|
+
}).join(" ");
|
|
2715
|
+
const resolvedColor = color === "auto" ? data[data.length - 1] >= data[0] ? COLOR_VAR.success : COLOR_VAR.error : COLOR_VAR[color];
|
|
2716
|
+
const areaPath = fill ? `M ${pad},${height - pad} L ${points.split(" ").join(" L ")} L ${width - pad},${height - pad} Z` : null;
|
|
2717
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2718
|
+
"svg",
|
|
2719
|
+
{
|
|
2720
|
+
width,
|
|
2721
|
+
height,
|
|
2722
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
2723
|
+
className: cn("flex-shrink-0", className),
|
|
2724
|
+
"aria-hidden": "true",
|
|
2725
|
+
children: [
|
|
2726
|
+
areaPath && /* @__PURE__ */ jsxRuntime.jsx("path", { d: areaPath, fill: resolvedColor, opacity: 0.15 }),
|
|
2727
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2728
|
+
"polyline",
|
|
2729
|
+
{
|
|
2730
|
+
fill: "none",
|
|
2731
|
+
stroke: resolvedColor,
|
|
2732
|
+
strokeWidth,
|
|
2733
|
+
strokeLinecap: "round",
|
|
2734
|
+
strokeLinejoin: "round",
|
|
2735
|
+
points
|
|
2736
|
+
}
|
|
2737
|
+
)
|
|
2738
|
+
]
|
|
2739
|
+
}
|
|
2740
|
+
);
|
|
2741
|
+
};
|
|
2742
|
+
exports.Sparkline.displayName = "Sparkline";
|
|
2743
|
+
}
|
|
2744
|
+
});
|
|
2684
2745
|
exports.Switch = void 0;
|
|
2685
2746
|
var init_Switch = __esm({
|
|
2686
2747
|
"components/atoms/Switch.tsx"() {
|
|
@@ -7754,7 +7815,7 @@ var init_MapView = __esm({
|
|
|
7754
7815
|
shadowSize: [41, 41]
|
|
7755
7816
|
});
|
|
7756
7817
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
7757
|
-
const { useEffect: useEffect70, useRef: useRef66, useCallback:
|
|
7818
|
+
const { useEffect: useEffect70, useRef: useRef66, useCallback: useCallback126, useState: useState107 } = React75__namespace.default;
|
|
7758
7819
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
7759
7820
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
7760
7821
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -7799,8 +7860,8 @@ var init_MapView = __esm({
|
|
|
7799
7860
|
showAttribution = true
|
|
7800
7861
|
}) {
|
|
7801
7862
|
const eventBus = useEventBus2();
|
|
7802
|
-
const [clickedPosition, setClickedPosition] =
|
|
7803
|
-
const handleMapClick =
|
|
7863
|
+
const [clickedPosition, setClickedPosition] = useState107(null);
|
|
7864
|
+
const handleMapClick = useCallback126((lat, lng) => {
|
|
7804
7865
|
if (showClickedPin) {
|
|
7805
7866
|
setClickedPosition({ lat, lng });
|
|
7806
7867
|
}
|
|
@@ -7809,7 +7870,7 @@ var init_MapView = __esm({
|
|
|
7809
7870
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
7810
7871
|
}
|
|
7811
7872
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
7812
|
-
const handleMarkerClick =
|
|
7873
|
+
const handleMarkerClick = useCallback126((marker) => {
|
|
7813
7874
|
onMarkerClick?.(marker);
|
|
7814
7875
|
if (markerClickEvent) {
|
|
7815
7876
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -17801,7 +17862,7 @@ var init_CastleTemplate = __esm({
|
|
|
17801
17862
|
CastleTemplate.displayName = "CastleTemplate";
|
|
17802
17863
|
}
|
|
17803
17864
|
});
|
|
17804
|
-
var CHART_COLORS, BarChart, PieChart, LineChart; exports.Chart = void 0;
|
|
17865
|
+
var CHART_COLORS, seriesColor, monthFormatter, formatTimeLabel, BarChart, PieChart, LineChart, ScatterChart; exports.Chart = void 0;
|
|
17805
17866
|
var init_Chart = __esm({
|
|
17806
17867
|
"components/organisms/Chart.tsx"() {
|
|
17807
17868
|
"use client";
|
|
@@ -17821,38 +17882,159 @@ var init_Chart = __esm({
|
|
|
17821
17882
|
"var(--color-info)",
|
|
17822
17883
|
"var(--color-accent)"
|
|
17823
17884
|
];
|
|
17824
|
-
|
|
17825
|
-
|
|
17826
|
-
|
|
17827
|
-
|
|
17828
|
-
|
|
17829
|
-
|
|
17830
|
-
|
|
17831
|
-
|
|
17832
|
-
|
|
17833
|
-
|
|
17834
|
-
|
|
17835
|
-
|
|
17836
|
-
|
|
17837
|
-
|
|
17838
|
-
|
|
17839
|
-
|
|
17840
|
-
|
|
17885
|
+
seriesColor = (series, idx) => series.color ?? CHART_COLORS[idx % CHART_COLORS.length];
|
|
17886
|
+
monthFormatter = new Intl.DateTimeFormat(void 0, {
|
|
17887
|
+
month: "short",
|
|
17888
|
+
year: "2-digit"
|
|
17889
|
+
});
|
|
17890
|
+
formatTimeLabel = (raw) => {
|
|
17891
|
+
const parsed = new Date(raw);
|
|
17892
|
+
if (Number.isNaN(parsed.getTime())) return raw;
|
|
17893
|
+
return monthFormatter.format(parsed);
|
|
17894
|
+
};
|
|
17895
|
+
BarChart = ({ series, height, showValues, stack, timeAxis, histogram = false, onPointClick }) => {
|
|
17896
|
+
const categories = React75.useMemo(() => {
|
|
17897
|
+
const set = [];
|
|
17898
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17899
|
+
for (const s of series) {
|
|
17900
|
+
for (const p2 of s.data) {
|
|
17901
|
+
if (!seen.has(p2.label)) {
|
|
17902
|
+
seen.add(p2.label);
|
|
17903
|
+
set.push(p2.label);
|
|
17841
17904
|
}
|
|
17842
|
-
|
|
17843
|
-
|
|
17844
|
-
|
|
17845
|
-
|
|
17846
|
-
|
|
17847
|
-
|
|
17848
|
-
|
|
17849
|
-
|
|
17905
|
+
}
|
|
17906
|
+
}
|
|
17907
|
+
return set;
|
|
17908
|
+
}, [series]);
|
|
17909
|
+
const valueAt = React75.useCallback(
|
|
17910
|
+
(s, label) => {
|
|
17911
|
+
const p2 = s.data.find((d) => d.label === label);
|
|
17912
|
+
return p2 ? p2.value : 0;
|
|
17913
|
+
},
|
|
17914
|
+
[]
|
|
17915
|
+
);
|
|
17916
|
+
const columnTotals = React75.useMemo(() => {
|
|
17917
|
+
if (stack === "none") return null;
|
|
17918
|
+
return categories.map(
|
|
17919
|
+
(label) => series.reduce((sum, s) => sum + valueAt(s, label), 0)
|
|
17920
|
+
);
|
|
17921
|
+
}, [categories, series, stack, valueAt]);
|
|
17922
|
+
const maxValue = React75.useMemo(() => {
|
|
17923
|
+
if (stack === "normalize") return 100;
|
|
17924
|
+
if (stack === "stack" && columnTotals) {
|
|
17925
|
+
return Math.max(...columnTotals, 1);
|
|
17926
|
+
}
|
|
17927
|
+
let m = 1;
|
|
17928
|
+
for (const s of series) {
|
|
17929
|
+
for (const p2 of s.data) if (p2.value > m) m = p2.value;
|
|
17930
|
+
}
|
|
17931
|
+
return m;
|
|
17932
|
+
}, [series, stack, columnTotals]);
|
|
17933
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
17934
|
+
exports.HStack,
|
|
17935
|
+
{
|
|
17936
|
+
gap: histogram ? "none" : "xs",
|
|
17937
|
+
align: "end",
|
|
17938
|
+
className: "w-full",
|
|
17939
|
+
style: { height },
|
|
17940
|
+
children: categories.map((label, catIdx) => {
|
|
17941
|
+
const displayLabel = timeAxis ? formatTimeLabel(label) : label;
|
|
17942
|
+
if (stack === "none") {
|
|
17943
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17944
|
+
exports.VStack,
|
|
17945
|
+
{
|
|
17946
|
+
gap: "xs",
|
|
17947
|
+
align: "center",
|
|
17948
|
+
flex: true,
|
|
17949
|
+
className: "min-w-0",
|
|
17950
|
+
children: [
|
|
17951
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: histogram ? "none" : "xs", align: "end", className: "w-full", style: { height: "100%" }, children: series.map((s, sIdx) => {
|
|
17952
|
+
const value = valueAt(s, label);
|
|
17953
|
+
const barHeight = value / maxValue * 100;
|
|
17954
|
+
const color = seriesColor(s, sIdx);
|
|
17955
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
17956
|
+
exports.Box,
|
|
17957
|
+
{
|
|
17958
|
+
className: cn(
|
|
17959
|
+
"rounded-t-sm transition-all duration-500 ease-out min-h-[4px] cursor-pointer hover:opacity-80",
|
|
17960
|
+
histogram ? "flex-1 mx-0" : "flex-1"
|
|
17961
|
+
),
|
|
17962
|
+
style: {
|
|
17963
|
+
height: `${barHeight}%`,
|
|
17964
|
+
backgroundColor: color
|
|
17965
|
+
},
|
|
17966
|
+
onClick: () => onPointClick?.(
|
|
17967
|
+
{ label, value, color },
|
|
17968
|
+
s.name
|
|
17969
|
+
),
|
|
17970
|
+
title: `${s.name}: ${value}`
|
|
17971
|
+
},
|
|
17972
|
+
s.name
|
|
17973
|
+
);
|
|
17974
|
+
}) }),
|
|
17975
|
+
showValues && series.length === 1 && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: valueAt(series[0], label) }),
|
|
17976
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17977
|
+
exports.Typography,
|
|
17978
|
+
{
|
|
17979
|
+
variant: "caption",
|
|
17980
|
+
color: "secondary",
|
|
17981
|
+
className: "truncate w-full text-center",
|
|
17982
|
+
children: displayLabel
|
|
17983
|
+
}
|
|
17984
|
+
)
|
|
17985
|
+
]
|
|
17986
|
+
},
|
|
17987
|
+
label
|
|
17988
|
+
);
|
|
17850
17989
|
}
|
|
17851
|
-
|
|
17852
|
-
|
|
17853
|
-
|
|
17990
|
+
const total = columnTotals?.[catIdx] ?? 1;
|
|
17991
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
17992
|
+
exports.VStack,
|
|
17993
|
+
{
|
|
17994
|
+
gap: "xs",
|
|
17995
|
+
align: "center",
|
|
17996
|
+
flex: true,
|
|
17997
|
+
className: "min-w-0",
|
|
17998
|
+
children: [
|
|
17999
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.VStack, { gap: "none", className: "w-full", style: { height: "100%" }, justify: "end", children: series.map((s, sIdx) => {
|
|
18000
|
+
const value = valueAt(s, label);
|
|
18001
|
+
const ratio = stack === "normalize" ? total === 0 ? 0 : value / total * 100 : value / maxValue * 100;
|
|
18002
|
+
const color = seriesColor(s, sIdx);
|
|
18003
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
18004
|
+
exports.Box,
|
|
18005
|
+
{
|
|
18006
|
+
className: "w-full transition-all duration-500 ease-out cursor-pointer hover:opacity-80",
|
|
18007
|
+
style: {
|
|
18008
|
+
height: `${ratio}%`,
|
|
18009
|
+
backgroundColor: color
|
|
18010
|
+
},
|
|
18011
|
+
onClick: () => onPointClick?.(
|
|
18012
|
+
{ label, value, color },
|
|
18013
|
+
s.name
|
|
18014
|
+
),
|
|
18015
|
+
title: `${s.name}: ${value}`
|
|
18016
|
+
},
|
|
18017
|
+
s.name
|
|
18018
|
+
);
|
|
18019
|
+
}) }),
|
|
18020
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18021
|
+
exports.Typography,
|
|
18022
|
+
{
|
|
18023
|
+
variant: "caption",
|
|
18024
|
+
color: "secondary",
|
|
18025
|
+
className: "truncate w-full text-center",
|
|
18026
|
+
children: displayLabel
|
|
18027
|
+
}
|
|
18028
|
+
)
|
|
18029
|
+
]
|
|
18030
|
+
},
|
|
18031
|
+
label
|
|
18032
|
+
);
|
|
18033
|
+
})
|
|
18034
|
+
}
|
|
18035
|
+
);
|
|
17854
18036
|
};
|
|
17855
|
-
PieChart = ({ data, height, showValues, donut = false }) => {
|
|
18037
|
+
PieChart = ({ data, height, showValues, donut = false, onPointClick }) => {
|
|
17856
18038
|
const total = data.reduce((sum, d) => sum + d.value, 0);
|
|
17857
18039
|
const size = Math.min(height, 200);
|
|
17858
18040
|
const radius = size / 2 - 8;
|
|
@@ -17898,7 +18080,11 @@ var init_Chart = __esm({
|
|
|
17898
18080
|
fill: seg.color,
|
|
17899
18081
|
stroke: "var(--color-card)",
|
|
17900
18082
|
strokeWidth: "2",
|
|
17901
|
-
className: "transition-opacity duration-200 hover:opacity-80"
|
|
18083
|
+
className: "transition-opacity duration-200 hover:opacity-80 cursor-pointer",
|
|
18084
|
+
onClick: () => onPointClick?.(
|
|
18085
|
+
{ label: seg.label, value: seg.value, color: seg.color },
|
|
18086
|
+
"default"
|
|
18087
|
+
)
|
|
17902
18088
|
},
|
|
17903
18089
|
idx
|
|
17904
18090
|
)),
|
|
@@ -17933,56 +18119,243 @@ var init_Chart = __esm({
|
|
|
17933
18119
|
] }, idx)) })
|
|
17934
18120
|
] });
|
|
17935
18121
|
};
|
|
17936
|
-
LineChart = ({
|
|
17937
|
-
const maxValue = Math.max(...data.map((d) => d.value), 1);
|
|
18122
|
+
LineChart = ({ series, height, showValues, fill = false, timeAxis, onPointClick }) => {
|
|
17938
18123
|
const width = 400;
|
|
17939
18124
|
const padding = { top: 20, right: 20, bottom: 30, left: 40 };
|
|
17940
18125
|
const chartWidth = width - padding.left - padding.right;
|
|
17941
18126
|
const chartHeight = height - padding.top - padding.bottom;
|
|
17942
|
-
const
|
|
17943
|
-
|
|
17944
|
-
|
|
17945
|
-
|
|
17946
|
-
|
|
17947
|
-
|
|
17948
|
-
|
|
17949
|
-
|
|
17950
|
-
const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
|
|
17951
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "100%", height, viewBox: `0 0 ${width} ${height}`, preserveAspectRatio: "xMidYMid meet", children: [
|
|
17952
|
-
[0, 0.25, 0.5, 0.75, 1].map((frac) => {
|
|
17953
|
-
const y = padding.top + chartHeight * (1 - frac);
|
|
17954
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
17955
|
-
"line",
|
|
17956
|
-
{
|
|
17957
|
-
x1: padding.left,
|
|
17958
|
-
y1: y,
|
|
17959
|
-
x2: width - padding.right,
|
|
17960
|
-
y2: y,
|
|
17961
|
-
stroke: "var(--color-border)",
|
|
17962
|
-
strokeDasharray: "4 4",
|
|
17963
|
-
opacity: 0.5
|
|
17964
|
-
},
|
|
17965
|
-
frac
|
|
17966
|
-
);
|
|
17967
|
-
}),
|
|
17968
|
-
fill && /* @__PURE__ */ jsxRuntime.jsx("path", { d: areaPath, fill: "var(--color-primary)", opacity: 0.1 }),
|
|
17969
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: linePath, fill: "none", stroke: "var(--color-primary)", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
17970
|
-
points.map((p2, idx) => /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
|
|
17971
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: p2.x, cy: p2.y, r: "4", fill: "var(--color-card)", stroke: "var(--color-primary)", strokeWidth: "2" }),
|
|
17972
|
-
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 }),
|
|
17973
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
17974
|
-
"text",
|
|
17975
|
-
{
|
|
17976
|
-
x: p2.x,
|
|
17977
|
-
y: height - 8,
|
|
17978
|
-
textAnchor: "middle",
|
|
17979
|
-
fill: "var(--color-muted-foreground)",
|
|
17980
|
-
fontSize: "9",
|
|
17981
|
-
children: p2.label
|
|
18127
|
+
const labels = React75.useMemo(() => {
|
|
18128
|
+
const seen = /* @__PURE__ */ new Set();
|
|
18129
|
+
const out = [];
|
|
18130
|
+
for (const s of series) {
|
|
18131
|
+
for (const p2 of s.data) {
|
|
18132
|
+
if (!seen.has(p2.label)) {
|
|
18133
|
+
seen.add(p2.label);
|
|
18134
|
+
out.push(p2.label);
|
|
17982
18135
|
}
|
|
17983
|
-
|
|
17984
|
-
|
|
17985
|
-
|
|
18136
|
+
}
|
|
18137
|
+
}
|
|
18138
|
+
return out;
|
|
18139
|
+
}, [series]);
|
|
18140
|
+
const maxValue = React75.useMemo(() => {
|
|
18141
|
+
let m = 1;
|
|
18142
|
+
for (const s of series) {
|
|
18143
|
+
for (const p2 of s.data) if (p2.value > m) m = p2.value;
|
|
18144
|
+
}
|
|
18145
|
+
return m;
|
|
18146
|
+
}, [series]);
|
|
18147
|
+
const xFor = React75.useCallback(
|
|
18148
|
+
(idx) => padding.left + idx / Math.max(labels.length - 1, 1) * chartWidth,
|
|
18149
|
+
[labels.length, chartWidth, padding.left]
|
|
18150
|
+
);
|
|
18151
|
+
const yFor = React75.useCallback(
|
|
18152
|
+
(value) => padding.top + chartHeight - value / maxValue * chartHeight,
|
|
18153
|
+
[maxValue, chartHeight, padding.top]
|
|
18154
|
+
);
|
|
18155
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
18156
|
+
"svg",
|
|
18157
|
+
{
|
|
18158
|
+
width: "100%",
|
|
18159
|
+
height,
|
|
18160
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
18161
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
18162
|
+
children: [
|
|
18163
|
+
[0, 0.25, 0.5, 0.75, 1].map((frac) => {
|
|
18164
|
+
const y = padding.top + chartHeight * (1 - frac);
|
|
18165
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
18166
|
+
"line",
|
|
18167
|
+
{
|
|
18168
|
+
x1: padding.left,
|
|
18169
|
+
y1: y,
|
|
18170
|
+
x2: width - padding.right,
|
|
18171
|
+
y2: y,
|
|
18172
|
+
stroke: "var(--color-border)",
|
|
18173
|
+
strokeDasharray: "4 4",
|
|
18174
|
+
opacity: 0.5
|
|
18175
|
+
},
|
|
18176
|
+
frac
|
|
18177
|
+
);
|
|
18178
|
+
}),
|
|
18179
|
+
series.map((s, sIdx) => {
|
|
18180
|
+
const color = seriesColor(s, sIdx);
|
|
18181
|
+
const points = labels.map((label, idx) => {
|
|
18182
|
+
const point = s.data.find((d) => d.label === label);
|
|
18183
|
+
return {
|
|
18184
|
+
x: xFor(idx),
|
|
18185
|
+
y: yFor(point ? point.value : 0),
|
|
18186
|
+
value: point ? point.value : 0,
|
|
18187
|
+
label
|
|
18188
|
+
};
|
|
18189
|
+
});
|
|
18190
|
+
const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
|
|
18191
|
+
const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
|
|
18192
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
|
|
18193
|
+
fill && /* @__PURE__ */ jsxRuntime.jsx(
|
|
18194
|
+
"path",
|
|
18195
|
+
{
|
|
18196
|
+
d: areaPath,
|
|
18197
|
+
fill: color,
|
|
18198
|
+
opacity: series.length > 1 ? 0.08 : 0.1
|
|
18199
|
+
}
|
|
18200
|
+
),
|
|
18201
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18202
|
+
"path",
|
|
18203
|
+
{
|
|
18204
|
+
d: linePath,
|
|
18205
|
+
fill: "none",
|
|
18206
|
+
stroke: color,
|
|
18207
|
+
strokeWidth: "2",
|
|
18208
|
+
strokeLinecap: "round",
|
|
18209
|
+
strokeLinejoin: "round",
|
|
18210
|
+
strokeDasharray: s.dashed ? "6 4" : void 0
|
|
18211
|
+
}
|
|
18212
|
+
),
|
|
18213
|
+
points.map((p2, idx) => /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
|
|
18214
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18215
|
+
"circle",
|
|
18216
|
+
{
|
|
18217
|
+
cx: p2.x,
|
|
18218
|
+
cy: p2.y,
|
|
18219
|
+
r: "4",
|
|
18220
|
+
fill: "var(--color-card)",
|
|
18221
|
+
stroke: color,
|
|
18222
|
+
strokeWidth: "2",
|
|
18223
|
+
className: "cursor-pointer",
|
|
18224
|
+
onClick: () => onPointClick?.(
|
|
18225
|
+
{ label: p2.label, value: p2.value, color },
|
|
18226
|
+
s.name
|
|
18227
|
+
)
|
|
18228
|
+
}
|
|
18229
|
+
),
|
|
18230
|
+
showValues && series.length === 1 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
18231
|
+
"text",
|
|
18232
|
+
{
|
|
18233
|
+
x: p2.x,
|
|
18234
|
+
y: p2.y - 10,
|
|
18235
|
+
textAnchor: "middle",
|
|
18236
|
+
fill: "var(--color-foreground)",
|
|
18237
|
+
fontSize: "10",
|
|
18238
|
+
fontWeight: "500",
|
|
18239
|
+
children: p2.value
|
|
18240
|
+
}
|
|
18241
|
+
)
|
|
18242
|
+
] }, idx))
|
|
18243
|
+
] }, s.name);
|
|
18244
|
+
}),
|
|
18245
|
+
labels.map((label, idx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
18246
|
+
"text",
|
|
18247
|
+
{
|
|
18248
|
+
x: xFor(idx),
|
|
18249
|
+
y: height - 8,
|
|
18250
|
+
textAnchor: "middle",
|
|
18251
|
+
fill: "var(--color-muted-foreground)",
|
|
18252
|
+
fontSize: "9",
|
|
18253
|
+
children: timeAxis ? formatTimeLabel(label) : label
|
|
18254
|
+
},
|
|
18255
|
+
label
|
|
18256
|
+
))
|
|
18257
|
+
]
|
|
18258
|
+
}
|
|
18259
|
+
);
|
|
18260
|
+
};
|
|
18261
|
+
ScatterChart = ({ data, height, onPointClick }) => {
|
|
18262
|
+
const width = 400;
|
|
18263
|
+
const padding = { top: 20, right: 20, bottom: 30, left: 40 };
|
|
18264
|
+
const chartWidth = width - padding.left - padding.right;
|
|
18265
|
+
const chartHeight = height - padding.top - padding.bottom;
|
|
18266
|
+
const { minX, maxX, minY, maxY } = React75.useMemo(() => {
|
|
18267
|
+
if (data.length === 0) {
|
|
18268
|
+
return { minX: 0, maxX: 1, minY: 0, maxY: 1 };
|
|
18269
|
+
}
|
|
18270
|
+
let mnX = data[0].x;
|
|
18271
|
+
let mxX = data[0].x;
|
|
18272
|
+
let mnY = data[0].y;
|
|
18273
|
+
let mxY = data[0].y;
|
|
18274
|
+
for (const p2 of data) {
|
|
18275
|
+
if (p2.x < mnX) mnX = p2.x;
|
|
18276
|
+
if (p2.x > mxX) mxX = p2.x;
|
|
18277
|
+
if (p2.y < mnY) mnY = p2.y;
|
|
18278
|
+
if (p2.y > mxY) mxY = p2.y;
|
|
18279
|
+
}
|
|
18280
|
+
return { minX: mnX, maxX: mxX, minY: mnY, maxY: mxY };
|
|
18281
|
+
}, [data]);
|
|
18282
|
+
const rangeX = maxX - minX || 1;
|
|
18283
|
+
const rangeY = maxY - minY || 1;
|
|
18284
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
18285
|
+
"svg",
|
|
18286
|
+
{
|
|
18287
|
+
width: "100%",
|
|
18288
|
+
height,
|
|
18289
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
18290
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
18291
|
+
children: [
|
|
18292
|
+
[0, 0.25, 0.5, 0.75, 1].map((frac) => {
|
|
18293
|
+
const y = padding.top + chartHeight * (1 - frac);
|
|
18294
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
18295
|
+
"line",
|
|
18296
|
+
{
|
|
18297
|
+
x1: padding.left,
|
|
18298
|
+
y1: y,
|
|
18299
|
+
x2: width - padding.right,
|
|
18300
|
+
y2: y,
|
|
18301
|
+
stroke: "var(--color-border)",
|
|
18302
|
+
strokeDasharray: "4 4",
|
|
18303
|
+
opacity: 0.5
|
|
18304
|
+
},
|
|
18305
|
+
frac
|
|
18306
|
+
);
|
|
18307
|
+
}),
|
|
18308
|
+
data.map((p2, idx) => {
|
|
18309
|
+
const cx = padding.left + (p2.x - minX) / rangeX * chartWidth;
|
|
18310
|
+
const cy = padding.top + chartHeight - (p2.y - minY) / rangeY * chartHeight;
|
|
18311
|
+
const r = p2.size ?? 5;
|
|
18312
|
+
const color = p2.color ?? CHART_COLORS[idx % CHART_COLORS.length];
|
|
18313
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
18314
|
+
"circle",
|
|
18315
|
+
{
|
|
18316
|
+
cx,
|
|
18317
|
+
cy,
|
|
18318
|
+
r,
|
|
18319
|
+
fill: color,
|
|
18320
|
+
opacity: 0.7,
|
|
18321
|
+
className: "cursor-pointer hover:opacity-100",
|
|
18322
|
+
onClick: () => onPointClick?.(
|
|
18323
|
+
{
|
|
18324
|
+
label: p2.label ?? `(${p2.x}, ${p2.y})`,
|
|
18325
|
+
value: p2.y,
|
|
18326
|
+
color
|
|
18327
|
+
},
|
|
18328
|
+
"default"
|
|
18329
|
+
),
|
|
18330
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("title", { children: p2.label ?? `(${p2.x}, ${p2.y})` })
|
|
18331
|
+
},
|
|
18332
|
+
idx
|
|
18333
|
+
);
|
|
18334
|
+
}),
|
|
18335
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18336
|
+
"text",
|
|
18337
|
+
{
|
|
18338
|
+
x: padding.left,
|
|
18339
|
+
y: height - 8,
|
|
18340
|
+
fill: "var(--color-muted-foreground)",
|
|
18341
|
+
fontSize: "9",
|
|
18342
|
+
children: minX.toFixed(1)
|
|
18343
|
+
}
|
|
18344
|
+
),
|
|
18345
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18346
|
+
"text",
|
|
18347
|
+
{
|
|
18348
|
+
x: width - padding.right,
|
|
18349
|
+
y: height - 8,
|
|
18350
|
+
textAnchor: "end",
|
|
18351
|
+
fill: "var(--color-muted-foreground)",
|
|
18352
|
+
fontSize: "9",
|
|
18353
|
+
children: maxX.toFixed(1)
|
|
18354
|
+
}
|
|
18355
|
+
)
|
|
18356
|
+
]
|
|
18357
|
+
}
|
|
18358
|
+
);
|
|
17986
18359
|
};
|
|
17987
18360
|
exports.Chart = ({
|
|
17988
18361
|
title,
|
|
@@ -17990,9 +18363,13 @@ var init_Chart = __esm({
|
|
|
17990
18363
|
chartType = "bar",
|
|
17991
18364
|
series,
|
|
17992
18365
|
data: simpleData,
|
|
18366
|
+
scatterData,
|
|
17993
18367
|
height = 200,
|
|
17994
18368
|
showLegend = true,
|
|
17995
18369
|
showValues = false,
|
|
18370
|
+
stack = "none",
|
|
18371
|
+
timeAxis = false,
|
|
18372
|
+
drillEvent,
|
|
17996
18373
|
actions,
|
|
17997
18374
|
entity,
|
|
17998
18375
|
isLoading = false,
|
|
@@ -18009,11 +18386,25 @@ var init_Chart = __esm({
|
|
|
18009
18386
|
},
|
|
18010
18387
|
[eventBus]
|
|
18011
18388
|
);
|
|
18012
|
-
const
|
|
18013
|
-
|
|
18014
|
-
|
|
18389
|
+
const handlePointClick = React75.useCallback(
|
|
18390
|
+
(point, seriesName) => {
|
|
18391
|
+
if (drillEvent) {
|
|
18392
|
+
eventBus.emit(`UI:${drillEvent}`, {
|
|
18393
|
+
label: point.label,
|
|
18394
|
+
value: point.value,
|
|
18395
|
+
seriesLabel: seriesName === "default" ? void 0 : seriesName
|
|
18396
|
+
});
|
|
18397
|
+
}
|
|
18398
|
+
},
|
|
18399
|
+
[drillEvent, eventBus]
|
|
18400
|
+
);
|
|
18401
|
+
const normalizedSeries = React75.useMemo(() => {
|
|
18402
|
+
if (series && series.length > 0) return series;
|
|
18403
|
+
if (simpleData) return [{ name: "default", data: simpleData }];
|
|
18015
18404
|
return [];
|
|
18016
18405
|
}, [simpleData, series]);
|
|
18406
|
+
const firstSeriesData = normalizedSeries[0]?.data ?? [];
|
|
18407
|
+
const hasContent = chartType === "scatter" ? (scatterData?.length ?? 0) > 0 : normalizedSeries.some((s) => s.data.length > 0);
|
|
18017
18408
|
if (isLoading) {
|
|
18018
18409
|
return /* @__PURE__ */ jsxRuntime.jsx(exports.LoadingState, { message: "Loading chart...", className });
|
|
18019
18410
|
}
|
|
@@ -18027,7 +18418,7 @@ var init_Chart = __esm({
|
|
|
18027
18418
|
}
|
|
18028
18419
|
);
|
|
18029
18420
|
}
|
|
18030
|
-
if (
|
|
18421
|
+
if (!hasContent) {
|
|
18031
18422
|
return /* @__PURE__ */ jsxRuntime.jsx(exports.EmptyState, { title: t("empty.noData"), description: t("empty.noData"), className });
|
|
18032
18423
|
}
|
|
18033
18424
|
return /* @__PURE__ */ jsxRuntime.jsx(exports.Card, { className: cn("p-6", className), children: /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "md", children: [
|
|
@@ -18048,18 +18439,84 @@ var init_Chart = __esm({
|
|
|
18048
18439
|
)) })
|
|
18049
18440
|
] }),
|
|
18050
18441
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.Box, { className: "w-full", children: [
|
|
18051
|
-
chartType === "bar" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
18052
|
-
|
|
18053
|
-
|
|
18054
|
-
|
|
18055
|
-
|
|
18442
|
+
chartType === "bar" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
18443
|
+
BarChart,
|
|
18444
|
+
{
|
|
18445
|
+
series: normalizedSeries,
|
|
18446
|
+
height,
|
|
18447
|
+
showValues,
|
|
18448
|
+
stack,
|
|
18449
|
+
timeAxis,
|
|
18450
|
+
onPointClick: handlePointClick
|
|
18451
|
+
}
|
|
18452
|
+
),
|
|
18453
|
+
chartType === "histogram" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
18454
|
+
BarChart,
|
|
18455
|
+
{
|
|
18456
|
+
series: normalizedSeries,
|
|
18457
|
+
height,
|
|
18458
|
+
showValues,
|
|
18459
|
+
stack: "none",
|
|
18460
|
+
timeAxis: false,
|
|
18461
|
+
histogram: true,
|
|
18462
|
+
onPointClick: handlePointClick
|
|
18463
|
+
}
|
|
18464
|
+
),
|
|
18465
|
+
chartType === "line" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
18466
|
+
LineChart,
|
|
18467
|
+
{
|
|
18468
|
+
series: normalizedSeries,
|
|
18469
|
+
height,
|
|
18470
|
+
showValues,
|
|
18471
|
+
timeAxis,
|
|
18472
|
+
onPointClick: handlePointClick
|
|
18473
|
+
}
|
|
18474
|
+
),
|
|
18475
|
+
chartType === "area" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
18476
|
+
LineChart,
|
|
18477
|
+
{
|
|
18478
|
+
series: normalizedSeries,
|
|
18479
|
+
height,
|
|
18480
|
+
showValues,
|
|
18481
|
+
timeAxis,
|
|
18482
|
+
fill: true,
|
|
18483
|
+
onPointClick: handlePointClick
|
|
18484
|
+
}
|
|
18485
|
+
),
|
|
18486
|
+
chartType === "pie" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
18487
|
+
PieChart,
|
|
18488
|
+
{
|
|
18489
|
+
data: firstSeriesData,
|
|
18490
|
+
height,
|
|
18491
|
+
showValues: showLegend,
|
|
18492
|
+
onPointClick: handlePointClick
|
|
18493
|
+
}
|
|
18494
|
+
),
|
|
18495
|
+
chartType === "donut" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
18496
|
+
PieChart,
|
|
18497
|
+
{
|
|
18498
|
+
data: firstSeriesData,
|
|
18499
|
+
height,
|
|
18500
|
+
showValues: showLegend,
|
|
18501
|
+
donut: true,
|
|
18502
|
+
onPointClick: handlePointClick
|
|
18503
|
+
}
|
|
18504
|
+
),
|
|
18505
|
+
chartType === "scatter" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
18506
|
+
ScatterChart,
|
|
18507
|
+
{
|
|
18508
|
+
data: scatterData ?? [],
|
|
18509
|
+
height,
|
|
18510
|
+
onPointClick: handlePointClick
|
|
18511
|
+
}
|
|
18512
|
+
)
|
|
18056
18513
|
] }),
|
|
18057
|
-
showLegend &&
|
|
18514
|
+
showLegend && normalizedSeries.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: "md", justify: "center", wrap: true, children: normalizedSeries.map((s, idx) => /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "xs", align: "center", children: [
|
|
18058
18515
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
18059
18516
|
exports.Box,
|
|
18060
18517
|
{
|
|
18061
18518
|
className: "w-3 h-3 rounded-full flex-shrink-0",
|
|
18062
|
-
style: { backgroundColor: s
|
|
18519
|
+
style: { backgroundColor: seriesColor(s, idx) }
|
|
18063
18520
|
}
|
|
18064
18521
|
),
|
|
18065
18522
|
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", color: "secondary", children: s.name })
|
|
@@ -20151,7 +20608,6 @@ function useDataDnd(args) {
|
|
|
20151
20608
|
const raw = it[dndItemIdField];
|
|
20152
20609
|
return raw ?? `__idx_${idx}`;
|
|
20153
20610
|
}),
|
|
20154
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
20155
20611
|
[itemIdsSignature]
|
|
20156
20612
|
);
|
|
20157
20613
|
const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
|
|
@@ -21753,7 +22209,16 @@ var init_FilterGroup = __esm({
|
|
|
21753
22209
|
onClear: () => handleFilterSelect(`${filter.field}_to`, null)
|
|
21754
22210
|
}
|
|
21755
22211
|
)
|
|
21756
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
22212
|
+
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
22213
|
+
exports.Input,
|
|
22214
|
+
{
|
|
22215
|
+
value: selectedValues[filter.field] || "",
|
|
22216
|
+
onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
|
|
22217
|
+
placeholder: filter.label,
|
|
22218
|
+
clearable: true,
|
|
22219
|
+
onClear: () => handleFilterSelect(filter.field, null)
|
|
22220
|
+
}
|
|
22221
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
21757
22222
|
exports.Select,
|
|
21758
22223
|
{
|
|
21759
22224
|
value: selectedValues[filter.field] || "all",
|
|
@@ -21820,7 +22285,17 @@ var init_FilterGroup = __esm({
|
|
|
21820
22285
|
className: "text-sm min-w-[100px]"
|
|
21821
22286
|
}
|
|
21822
22287
|
)
|
|
21823
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
22288
|
+
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
22289
|
+
exports.Input,
|
|
22290
|
+
{
|
|
22291
|
+
value: selectedValues[filter.field] || "",
|
|
22292
|
+
onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
|
|
22293
|
+
placeholder: filter.label,
|
|
22294
|
+
clearable: true,
|
|
22295
|
+
onClear: () => handleFilterSelect(filter.field, null),
|
|
22296
|
+
className: "text-sm"
|
|
22297
|
+
}
|
|
22298
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
21824
22299
|
exports.Select,
|
|
21825
22300
|
{
|
|
21826
22301
|
value: selectedValues[filter.field] || "all",
|
|
@@ -21925,7 +22400,17 @@ var init_FilterGroup = __esm({
|
|
|
21925
22400
|
className: "min-w-[130px]"
|
|
21926
22401
|
}
|
|
21927
22402
|
)
|
|
21928
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
22403
|
+
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
22404
|
+
exports.Input,
|
|
22405
|
+
{
|
|
22406
|
+
value: selectedValues[filter.field] || "",
|
|
22407
|
+
onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
|
|
22408
|
+
placeholder: filter.label,
|
|
22409
|
+
clearable: true,
|
|
22410
|
+
onClear: () => handleFilterSelect(filter.field, null),
|
|
22411
|
+
className: "min-w-[160px]"
|
|
22412
|
+
}
|
|
22413
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
21929
22414
|
exports.Select,
|
|
21930
22415
|
{
|
|
21931
22416
|
value: selectedValues[filter.field] || "all",
|
|
@@ -23214,6 +23699,151 @@ var init_FlipCard = __esm({
|
|
|
23214
23699
|
exports.FlipCard.displayName = "FlipCard";
|
|
23215
23700
|
}
|
|
23216
23701
|
});
|
|
23702
|
+
function toISODate(d) {
|
|
23703
|
+
return d.toISOString().slice(0, 10);
|
|
23704
|
+
}
|
|
23705
|
+
function startOfMonth(d) {
|
|
23706
|
+
return new Date(d.getFullYear(), d.getMonth(), 1);
|
|
23707
|
+
}
|
|
23708
|
+
function startOfQuarter(d) {
|
|
23709
|
+
return new Date(d.getFullYear(), Math.floor(d.getMonth() / 3) * 3, 1);
|
|
23710
|
+
}
|
|
23711
|
+
function startOfYear(d) {
|
|
23712
|
+
return new Date(d.getFullYear(), 0, 1);
|
|
23713
|
+
}
|
|
23714
|
+
function daysAgo(n) {
|
|
23715
|
+
const d = /* @__PURE__ */ new Date();
|
|
23716
|
+
d.setDate(d.getDate() - n);
|
|
23717
|
+
return d;
|
|
23718
|
+
}
|
|
23719
|
+
var DEFAULT_PRESETS; exports.DateRangePicker = void 0;
|
|
23720
|
+
var init_DateRangePicker = __esm({
|
|
23721
|
+
"components/molecules/DateRangePicker.tsx"() {
|
|
23722
|
+
"use client";
|
|
23723
|
+
init_cn();
|
|
23724
|
+
init_Button();
|
|
23725
|
+
init_Input();
|
|
23726
|
+
init_Stack();
|
|
23727
|
+
init_Typography();
|
|
23728
|
+
init_useEventBus();
|
|
23729
|
+
DEFAULT_PRESETS = [
|
|
23730
|
+
{
|
|
23731
|
+
label: "Last 7 days",
|
|
23732
|
+
value: "7d",
|
|
23733
|
+
range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
23734
|
+
},
|
|
23735
|
+
{
|
|
23736
|
+
label: "Last 30 days",
|
|
23737
|
+
value: "30d",
|
|
23738
|
+
range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
23739
|
+
},
|
|
23740
|
+
{
|
|
23741
|
+
label: "This Month",
|
|
23742
|
+
value: "month",
|
|
23743
|
+
range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
23744
|
+
},
|
|
23745
|
+
{
|
|
23746
|
+
label: "This Quarter",
|
|
23747
|
+
value: "quarter",
|
|
23748
|
+
range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
23749
|
+
},
|
|
23750
|
+
{
|
|
23751
|
+
label: "YTD",
|
|
23752
|
+
value: "ytd",
|
|
23753
|
+
range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
23754
|
+
}
|
|
23755
|
+
];
|
|
23756
|
+
exports.DateRangePicker = ({
|
|
23757
|
+
from: fromProp,
|
|
23758
|
+
to: toProp,
|
|
23759
|
+
event,
|
|
23760
|
+
onChange,
|
|
23761
|
+
presets = DEFAULT_PRESETS,
|
|
23762
|
+
fromLabel = "From",
|
|
23763
|
+
toLabel = "To",
|
|
23764
|
+
className
|
|
23765
|
+
}) => {
|
|
23766
|
+
const eventBus = useEventBus();
|
|
23767
|
+
const [from, setFrom] = React75.useState(fromProp ?? "");
|
|
23768
|
+
const [to, setTo] = React75.useState(toProp ?? "");
|
|
23769
|
+
const [activePreset, setActivePreset] = React75.useState(null);
|
|
23770
|
+
const emit = React75.useCallback(
|
|
23771
|
+
(range) => {
|
|
23772
|
+
onChange?.(range);
|
|
23773
|
+
if (event) eventBus.emit(`UI:${event}`, range);
|
|
23774
|
+
},
|
|
23775
|
+
[onChange, event, eventBus]
|
|
23776
|
+
);
|
|
23777
|
+
const handleFromChange = React75.useCallback(
|
|
23778
|
+
(next) => {
|
|
23779
|
+
setFrom(next);
|
|
23780
|
+
setActivePreset(null);
|
|
23781
|
+
emit({ from: next, to });
|
|
23782
|
+
},
|
|
23783
|
+
[to, emit]
|
|
23784
|
+
);
|
|
23785
|
+
const handleToChange = React75.useCallback(
|
|
23786
|
+
(next) => {
|
|
23787
|
+
setTo(next);
|
|
23788
|
+
setActivePreset(null);
|
|
23789
|
+
emit({ from, to: next });
|
|
23790
|
+
},
|
|
23791
|
+
[from, emit]
|
|
23792
|
+
);
|
|
23793
|
+
const handlePreset = React75.useCallback(
|
|
23794
|
+
(preset) => {
|
|
23795
|
+
const range = preset.range();
|
|
23796
|
+
setFrom(range.from);
|
|
23797
|
+
setTo(range.to);
|
|
23798
|
+
setActivePreset(preset.value);
|
|
23799
|
+
emit(range);
|
|
23800
|
+
},
|
|
23801
|
+
[emit]
|
|
23802
|
+
);
|
|
23803
|
+
const presetButtons = React75.useMemo(
|
|
23804
|
+
() => presets.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
23805
|
+
exports.Button,
|
|
23806
|
+
{
|
|
23807
|
+
variant: activePreset === preset.value ? "primary" : "ghost",
|
|
23808
|
+
size: "sm",
|
|
23809
|
+
onClick: () => handlePreset(preset),
|
|
23810
|
+
children: preset.label
|
|
23811
|
+
},
|
|
23812
|
+
preset.value
|
|
23813
|
+
)),
|
|
23814
|
+
[presets, activePreset, handlePreset]
|
|
23815
|
+
);
|
|
23816
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "sm", className: cn(className), children: [
|
|
23817
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "md", align: "end", children: [
|
|
23818
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "xs", children: [
|
|
23819
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", color: "secondary", children: fromLabel }),
|
|
23820
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
23821
|
+
exports.Input,
|
|
23822
|
+
{
|
|
23823
|
+
type: "date",
|
|
23824
|
+
value: from,
|
|
23825
|
+
onChange: (e) => handleFromChange(e.target.value)
|
|
23826
|
+
}
|
|
23827
|
+
)
|
|
23828
|
+
] }),
|
|
23829
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "xs", children: [
|
|
23830
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", color: "secondary", children: toLabel }),
|
|
23831
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
23832
|
+
exports.Input,
|
|
23833
|
+
{
|
|
23834
|
+
type: "date",
|
|
23835
|
+
value: to,
|
|
23836
|
+
onChange: (e) => handleToChange(e.target.value)
|
|
23837
|
+
}
|
|
23838
|
+
)
|
|
23839
|
+
] })
|
|
23840
|
+
] }),
|
|
23841
|
+
presets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: "xs", wrap: true, children: presetButtons })
|
|
23842
|
+
] });
|
|
23843
|
+
};
|
|
23844
|
+
exports.DateRangePicker.displayName = "DateRangePicker";
|
|
23845
|
+
}
|
|
23846
|
+
});
|
|
23217
23847
|
var DEFAULT_OPTIONS; exports.DateRangeSelector = void 0;
|
|
23218
23848
|
var init_DateRangeSelector = __esm({
|
|
23219
23849
|
"components/molecules/DateRangeSelector.tsx"() {
|
|
@@ -26469,7 +27099,9 @@ var init_StatDisplay = __esm({
|
|
|
26469
27099
|
init_Typography();
|
|
26470
27100
|
init_Box();
|
|
26471
27101
|
init_Stack();
|
|
27102
|
+
init_Sparkline();
|
|
26472
27103
|
init_Icon();
|
|
27104
|
+
init_useEventBus();
|
|
26473
27105
|
variantColor = {
|
|
26474
27106
|
default: "text-foreground",
|
|
26475
27107
|
primary: "text-primary",
|
|
@@ -26484,6 +27116,10 @@ var init_StatDisplay = __esm({
|
|
|
26484
27116
|
max,
|
|
26485
27117
|
target,
|
|
26486
27118
|
trend,
|
|
27119
|
+
trendPolarity = "higher-is-better",
|
|
27120
|
+
trendFormat = "absolute",
|
|
27121
|
+
sparklineData,
|
|
27122
|
+
clickEvent,
|
|
26487
27123
|
prefix,
|
|
26488
27124
|
suffix,
|
|
26489
27125
|
icon: iconProp,
|
|
@@ -26497,6 +27133,10 @@ var init_StatDisplay = __esm({
|
|
|
26497
27133
|
isLoading = false,
|
|
26498
27134
|
error = null
|
|
26499
27135
|
}) => {
|
|
27136
|
+
const eventBus = useEventBus();
|
|
27137
|
+
const handleClick = React75.useCallback(() => {
|
|
27138
|
+
if (clickEvent) eventBus.emit(`UI:${clickEvent}`, { metricLabel: label });
|
|
27139
|
+
}, [clickEvent, eventBus, label]);
|
|
26500
27140
|
const ResolvedIcon = typeof iconProp === "string" ? resolveIcon(iconProp) : null;
|
|
26501
27141
|
const iconSizes3 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
|
|
26502
27142
|
const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
|
|
@@ -26507,7 +27147,10 @@ var init_StatDisplay = __esm({
|
|
|
26507
27147
|
const targetPct = showTarget ? Math.max(0, Math.min(100, numericValue / target * 100)) : 0;
|
|
26508
27148
|
const showTrend = typeof trend === "number" && trend !== 0 && Number.isFinite(trend);
|
|
26509
27149
|
const trendUp = showTrend && trend > 0;
|
|
26510
|
-
const
|
|
27150
|
+
const trendIsGood = trendPolarity === "lower-is-better" ? !trendUp : trendUp;
|
|
27151
|
+
const trendMagnitude = Math.abs(trend);
|
|
27152
|
+
const trendSuffix = trendFormat === "percent" ? "%" : "";
|
|
27153
|
+
const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${trendMagnitude}${trendSuffix}` : "";
|
|
26511
27154
|
if (error) {
|
|
26512
27155
|
return /* @__PURE__ */ jsxRuntime.jsx(exports.Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "small", color: "error", children: error.message }) });
|
|
26513
27156
|
}
|
|
@@ -26518,38 +27161,57 @@ var init_StatDisplay = __esm({
|
|
|
26518
27161
|
] }) });
|
|
26519
27162
|
}
|
|
26520
27163
|
if (compact) {
|
|
26521
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
26522
|
-
|
|
26523
|
-
|
|
26524
|
-
|
|
26525
|
-
|
|
26526
|
-
|
|
26527
|
-
|
|
27164
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
27165
|
+
exports.HStack,
|
|
27166
|
+
{
|
|
27167
|
+
gap: "sm",
|
|
27168
|
+
className: cn("items-center", clickEvent && "cursor-pointer hover:opacity-80", className),
|
|
27169
|
+
onClick: clickEvent ? handleClick : void 0,
|
|
27170
|
+
children: [
|
|
27171
|
+
ResolvedIcon && /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
|
|
27172
|
+
typeof iconProp !== "string" && iconProp,
|
|
27173
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", color: "secondary", children: label }),
|
|
27174
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
|
|
27175
|
+
showTrend && /* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "caption", className: cn("font-semibold", trendIsGood ? "text-success" : "text-error"), children: trendLabel }),
|
|
27176
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(exports.Sparkline, { data: sparklineData, color: "auto", width: 60, height: 20 })
|
|
27177
|
+
]
|
|
27178
|
+
}
|
|
27179
|
+
);
|
|
26528
27180
|
}
|
|
26529
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
26530
|
-
|
|
26531
|
-
|
|
26532
|
-
|
|
26533
|
-
|
|
26534
|
-
|
|
26535
|
-
|
|
26536
|
-
{
|
|
26537
|
-
|
|
26538
|
-
className: cn("font-
|
|
26539
|
-
|
|
26540
|
-
|
|
26541
|
-
|
|
26542
|
-
|
|
26543
|
-
|
|
26544
|
-
|
|
26545
|
-
|
|
26546
|
-
|
|
26547
|
-
|
|
26548
|
-
|
|
26549
|
-
|
|
26550
|
-
|
|
26551
|
-
|
|
26552
|
-
|
|
27181
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
27182
|
+
exports.Card,
|
|
27183
|
+
{
|
|
27184
|
+
className: cn(padSizes[size], clickEvent && "cursor-pointer hover:shadow-md transition-shadow", className),
|
|
27185
|
+
onClick: clickEvent ? handleClick : void 0,
|
|
27186
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { align: "start", justify: "between", children: [
|
|
27187
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "none", className: "space-y-1 flex-1", children: [
|
|
27188
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "overline", color: "secondary", children: label }),
|
|
27189
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "sm", align: "end", children: [
|
|
27190
|
+
/* @__PURE__ */ jsxRuntime.jsx(exports.Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
|
|
27191
|
+
showTrend && /* @__PURE__ */ jsxRuntime.jsx(
|
|
27192
|
+
exports.Typography,
|
|
27193
|
+
{
|
|
27194
|
+
variant: "caption",
|
|
27195
|
+
className: cn("font-semibold pb-1", trendIsGood ? "text-success" : "text-error"),
|
|
27196
|
+
children: trendLabel
|
|
27197
|
+
}
|
|
27198
|
+
)
|
|
27199
|
+
] }),
|
|
27200
|
+
showTarget && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
27201
|
+
exports.Box,
|
|
27202
|
+
{
|
|
27203
|
+
className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
|
|
27204
|
+
style: { width: `${targetPct}%` }
|
|
27205
|
+
}
|
|
27206
|
+
) })
|
|
27207
|
+
] }),
|
|
27208
|
+
/* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "xs", align: "end", children: [
|
|
27209
|
+
(ResolvedIcon || typeof iconProp !== "string" && iconProp) && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: cn("p-3 rounded-md", iconBg), children: ResolvedIcon ? /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }) : iconProp }),
|
|
27210
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(exports.Sparkline, { data: sparklineData, color: "auto" })
|
|
27211
|
+
] })
|
|
27212
|
+
] })
|
|
27213
|
+
}
|
|
27214
|
+
);
|
|
26553
27215
|
};
|
|
26554
27216
|
exports.StatDisplay.displayName = "StatDisplay";
|
|
26555
27217
|
}
|
|
@@ -31898,6 +32560,7 @@ var init_molecules = __esm({
|
|
|
31898
32560
|
init_ViolationAlert();
|
|
31899
32561
|
init_FormSectionHeader();
|
|
31900
32562
|
init_FlipCard();
|
|
32563
|
+
init_DateRangePicker();
|
|
31901
32564
|
init_DateRangeSelector();
|
|
31902
32565
|
init_ChartLegend();
|
|
31903
32566
|
init_LineChart();
|
|
@@ -41454,6 +42117,7 @@ var init_StatCard = __esm({
|
|
|
41454
42117
|
init_Box();
|
|
41455
42118
|
init_Stack();
|
|
41456
42119
|
init_Button();
|
|
42120
|
+
init_Sparkline();
|
|
41457
42121
|
init_useEventBus();
|
|
41458
42122
|
init_useTranslate();
|
|
41459
42123
|
init_Icon();
|
|
@@ -41623,32 +42287,7 @@ var init_StatCard = __esm({
|
|
|
41623
42287
|
] }),
|
|
41624
42288
|
/* @__PURE__ */ jsxRuntime.jsxs(exports.VStack, { gap: "xs", align: "end", children: [
|
|
41625
42289
|
Icon3 && /* @__PURE__ */ jsxRuntime.jsx(exports.Box, { className: cn("p-3", iconBg), children: /* @__PURE__ */ jsxRuntime.jsx(Icon3, { className: cn("h-6 w-6", iconColor) }) }),
|
|
41626
|
-
sparklineData && sparklineData.length > 1 && (
|
|
41627
|
-
const w = 80;
|
|
41628
|
-
const h = 32;
|
|
41629
|
-
const pad = 2;
|
|
41630
|
-
const min = Math.min(...sparklineData);
|
|
41631
|
-
const max = Math.max(...sparklineData);
|
|
41632
|
-
const range = max - min || 1;
|
|
41633
|
-
const points = sparklineData.map((v, i) => {
|
|
41634
|
-
const x = pad + i / (sparklineData.length - 1) * (w - pad * 2);
|
|
41635
|
-
const y = pad + (1 - (v - min) / range) * (h - pad * 2);
|
|
41636
|
-
return `${x},${y}`;
|
|
41637
|
-
}).join(" ");
|
|
41638
|
-
const trending = sparklineData[sparklineData.length - 1] >= sparklineData[0];
|
|
41639
|
-
const strokeColor = trending ? "var(--color-success)" : "var(--color-error)";
|
|
41640
|
-
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: w, height: h, viewBox: `0 0 ${w} ${h}`, className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
41641
|
-
"polyline",
|
|
41642
|
-
{
|
|
41643
|
-
fill: "none",
|
|
41644
|
-
stroke: strokeColor,
|
|
41645
|
-
strokeWidth: "2",
|
|
41646
|
-
strokeLinecap: "round",
|
|
41647
|
-
strokeLinejoin: "round",
|
|
41648
|
-
points
|
|
41649
|
-
}
|
|
41650
|
-
) });
|
|
41651
|
-
})()
|
|
42290
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(exports.Sparkline, { data: sparklineData, color: "auto" })
|
|
41652
42291
|
] })
|
|
41653
42292
|
] }),
|
|
41654
42293
|
action && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -43735,6 +44374,7 @@ var init_component_registry_generated = __esm({
|
|
|
43735
44374
|
init_DataGrid();
|
|
43736
44375
|
init_DataList();
|
|
43737
44376
|
init_DataTable();
|
|
44377
|
+
init_DateRangePicker();
|
|
43738
44378
|
init_DateRangeSelector();
|
|
43739
44379
|
init_DayCell();
|
|
43740
44380
|
init_DebuggerBoard();
|
|
@@ -43867,6 +44507,7 @@ var init_component_registry_generated = __esm({
|
|
|
43867
44507
|
init_Skeleton();
|
|
43868
44508
|
init_SocialProof();
|
|
43869
44509
|
init_SortableList();
|
|
44510
|
+
init_Sparkline();
|
|
43870
44511
|
init_Split();
|
|
43871
44512
|
init_SplitPane();
|
|
43872
44513
|
init_SplitSection();
|
|
@@ -44015,6 +44656,7 @@ var init_component_registry_generated = __esm({
|
|
|
44015
44656
|
"DataGrid": DataGrid,
|
|
44016
44657
|
"DataList": DataList,
|
|
44017
44658
|
"DataTable": DataTable,
|
|
44659
|
+
"DateRangePicker": exports.DateRangePicker,
|
|
44018
44660
|
"DateRangeSelector": exports.DateRangeSelector,
|
|
44019
44661
|
"DayCell": DayCell,
|
|
44020
44662
|
"DebuggerBoard": DebuggerBoard,
|
|
@@ -44176,6 +44818,7 @@ var init_component_registry_generated = __esm({
|
|
|
44176
44818
|
"SortableList": exports.SortableList,
|
|
44177
44819
|
"Spacer": SpacerPattern,
|
|
44178
44820
|
"SpacerPattern": SpacerPattern,
|
|
44821
|
+
"Sparkline": exports.Sparkline,
|
|
44179
44822
|
"Spinner": SpinnerPattern,
|
|
44180
44823
|
"SpinnerPattern": SpinnerPattern,
|
|
44181
44824
|
"Split": exports.Split,
|
|
@@ -45180,6 +45823,7 @@ var init_atoms = __esm({
|
|
|
45180
45823
|
init_Icon();
|
|
45181
45824
|
init_ProgressBar();
|
|
45182
45825
|
init_Radio();
|
|
45826
|
+
init_Sparkline();
|
|
45183
45827
|
init_Switch();
|
|
45184
45828
|
init_Spacer();
|
|
45185
45829
|
init_Stack();
|