@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/runtime/index.js
CHANGED
|
@@ -3887,6 +3887,67 @@ var init_Radio = __esm({
|
|
|
3887
3887
|
Radio.displayName = "Radio";
|
|
3888
3888
|
}
|
|
3889
3889
|
});
|
|
3890
|
+
var COLOR_VAR, Sparkline;
|
|
3891
|
+
var init_Sparkline = __esm({
|
|
3892
|
+
"components/atoms/Sparkline.tsx"() {
|
|
3893
|
+
init_cn();
|
|
3894
|
+
COLOR_VAR = {
|
|
3895
|
+
primary: "var(--color-primary)",
|
|
3896
|
+
success: "var(--color-success)",
|
|
3897
|
+
warning: "var(--color-warning)",
|
|
3898
|
+
error: "var(--color-error)",
|
|
3899
|
+
info: "var(--color-info)",
|
|
3900
|
+
muted: "var(--color-muted-foreground)"
|
|
3901
|
+
};
|
|
3902
|
+
Sparkline = ({
|
|
3903
|
+
data,
|
|
3904
|
+
color = "auto",
|
|
3905
|
+
width = 80,
|
|
3906
|
+
height = 32,
|
|
3907
|
+
strokeWidth = 2,
|
|
3908
|
+
fill = false,
|
|
3909
|
+
className
|
|
3910
|
+
}) => {
|
|
3911
|
+
if (data.length < 2) return null;
|
|
3912
|
+
const pad = 2;
|
|
3913
|
+
const min = Math.min(...data);
|
|
3914
|
+
const max = Math.max(...data);
|
|
3915
|
+
const range = max - min || 1;
|
|
3916
|
+
const points = data.map((v, i) => {
|
|
3917
|
+
const x = pad + i / (data.length - 1) * (width - pad * 2);
|
|
3918
|
+
const y = pad + (1 - (v - min) / range) * (height - pad * 2);
|
|
3919
|
+
return `${x},${y}`;
|
|
3920
|
+
}).join(" ");
|
|
3921
|
+
const resolvedColor = color === "auto" ? data[data.length - 1] >= data[0] ? COLOR_VAR.success : COLOR_VAR.error : COLOR_VAR[color];
|
|
3922
|
+
const areaPath = fill ? `M ${pad},${height - pad} L ${points.split(" ").join(" L ")} L ${width - pad},${height - pad} Z` : null;
|
|
3923
|
+
return /* @__PURE__ */ jsxs(
|
|
3924
|
+
"svg",
|
|
3925
|
+
{
|
|
3926
|
+
width,
|
|
3927
|
+
height,
|
|
3928
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
3929
|
+
className: cn("flex-shrink-0", className),
|
|
3930
|
+
"aria-hidden": "true",
|
|
3931
|
+
children: [
|
|
3932
|
+
areaPath && /* @__PURE__ */ jsx("path", { d: areaPath, fill: resolvedColor, opacity: 0.15 }),
|
|
3933
|
+
/* @__PURE__ */ jsx(
|
|
3934
|
+
"polyline",
|
|
3935
|
+
{
|
|
3936
|
+
fill: "none",
|
|
3937
|
+
stroke: resolvedColor,
|
|
3938
|
+
strokeWidth,
|
|
3939
|
+
strokeLinecap: "round",
|
|
3940
|
+
strokeLinejoin: "round",
|
|
3941
|
+
points
|
|
3942
|
+
}
|
|
3943
|
+
)
|
|
3944
|
+
]
|
|
3945
|
+
}
|
|
3946
|
+
);
|
|
3947
|
+
};
|
|
3948
|
+
Sparkline.displayName = "Sparkline";
|
|
3949
|
+
}
|
|
3950
|
+
});
|
|
3890
3951
|
var Switch;
|
|
3891
3952
|
var init_Switch = __esm({
|
|
3892
3953
|
"components/atoms/Switch.tsx"() {
|
|
@@ -9164,7 +9225,7 @@ var init_MapView = __esm({
|
|
|
9164
9225
|
shadowSize: [41, 41]
|
|
9165
9226
|
});
|
|
9166
9227
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
9167
|
-
const { useEffect: useEffect68, useRef: useRef65, useCallback:
|
|
9228
|
+
const { useEffect: useEffect68, useRef: useRef65, useCallback: useCallback112, useState: useState99 } = React80__default;
|
|
9168
9229
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
9169
9230
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
9170
9231
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -9209,8 +9270,8 @@ var init_MapView = __esm({
|
|
|
9209
9270
|
showAttribution = true
|
|
9210
9271
|
}) {
|
|
9211
9272
|
const eventBus = useEventBus2();
|
|
9212
|
-
const [clickedPosition, setClickedPosition] =
|
|
9213
|
-
const handleMapClick =
|
|
9273
|
+
const [clickedPosition, setClickedPosition] = useState99(null);
|
|
9274
|
+
const handleMapClick = useCallback112((lat, lng) => {
|
|
9214
9275
|
if (showClickedPin) {
|
|
9215
9276
|
setClickedPosition({ lat, lng });
|
|
9216
9277
|
}
|
|
@@ -9219,7 +9280,7 @@ var init_MapView = __esm({
|
|
|
9219
9280
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
9220
9281
|
}
|
|
9221
9282
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
9222
|
-
const handleMarkerClick =
|
|
9283
|
+
const handleMarkerClick = useCallback112((marker) => {
|
|
9223
9284
|
onMarkerClick?.(marker);
|
|
9224
9285
|
if (markerClickEvent) {
|
|
9225
9286
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -19014,7 +19075,7 @@ var init_CastleTemplate = __esm({
|
|
|
19014
19075
|
CastleTemplate.displayName = "CastleTemplate";
|
|
19015
19076
|
}
|
|
19016
19077
|
});
|
|
19017
|
-
var CHART_COLORS, BarChart, PieChart, LineChart, Chart;
|
|
19078
|
+
var CHART_COLORS, seriesColor, monthFormatter, formatTimeLabel, BarChart, PieChart, LineChart, ScatterChart, Chart;
|
|
19018
19079
|
var init_Chart = __esm({
|
|
19019
19080
|
"components/organisms/Chart.tsx"() {
|
|
19020
19081
|
"use client";
|
|
@@ -19034,38 +19095,159 @@ var init_Chart = __esm({
|
|
|
19034
19095
|
"var(--color-info)",
|
|
19035
19096
|
"var(--color-accent)"
|
|
19036
19097
|
];
|
|
19037
|
-
|
|
19038
|
-
|
|
19039
|
-
|
|
19040
|
-
|
|
19041
|
-
|
|
19042
|
-
|
|
19043
|
-
|
|
19044
|
-
|
|
19045
|
-
|
|
19046
|
-
|
|
19047
|
-
|
|
19048
|
-
|
|
19049
|
-
|
|
19050
|
-
|
|
19051
|
-
|
|
19052
|
-
|
|
19053
|
-
|
|
19098
|
+
seriesColor = (series, idx) => series.color ?? CHART_COLORS[idx % CHART_COLORS.length];
|
|
19099
|
+
monthFormatter = new Intl.DateTimeFormat(void 0, {
|
|
19100
|
+
month: "short",
|
|
19101
|
+
year: "2-digit"
|
|
19102
|
+
});
|
|
19103
|
+
formatTimeLabel = (raw) => {
|
|
19104
|
+
const parsed = new Date(raw);
|
|
19105
|
+
if (Number.isNaN(parsed.getTime())) return raw;
|
|
19106
|
+
return monthFormatter.format(parsed);
|
|
19107
|
+
};
|
|
19108
|
+
BarChart = ({ series, height, showValues, stack, timeAxis, histogram = false, onPointClick }) => {
|
|
19109
|
+
const categories = useMemo(() => {
|
|
19110
|
+
const set = [];
|
|
19111
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19112
|
+
for (const s of series) {
|
|
19113
|
+
for (const p2 of s.data) {
|
|
19114
|
+
if (!seen.has(p2.label)) {
|
|
19115
|
+
seen.add(p2.label);
|
|
19116
|
+
set.push(p2.label);
|
|
19054
19117
|
}
|
|
19055
|
-
|
|
19056
|
-
|
|
19057
|
-
|
|
19058
|
-
|
|
19059
|
-
|
|
19060
|
-
|
|
19061
|
-
|
|
19062
|
-
|
|
19118
|
+
}
|
|
19119
|
+
}
|
|
19120
|
+
return set;
|
|
19121
|
+
}, [series]);
|
|
19122
|
+
const valueAt = useCallback(
|
|
19123
|
+
(s, label) => {
|
|
19124
|
+
const p2 = s.data.find((d) => d.label === label);
|
|
19125
|
+
return p2 ? p2.value : 0;
|
|
19126
|
+
},
|
|
19127
|
+
[]
|
|
19128
|
+
);
|
|
19129
|
+
const columnTotals = useMemo(() => {
|
|
19130
|
+
if (stack === "none") return null;
|
|
19131
|
+
return categories.map(
|
|
19132
|
+
(label) => series.reduce((sum, s) => sum + valueAt(s, label), 0)
|
|
19133
|
+
);
|
|
19134
|
+
}, [categories, series, stack, valueAt]);
|
|
19135
|
+
const maxValue = useMemo(() => {
|
|
19136
|
+
if (stack === "normalize") return 100;
|
|
19137
|
+
if (stack === "stack" && columnTotals) {
|
|
19138
|
+
return Math.max(...columnTotals, 1);
|
|
19139
|
+
}
|
|
19140
|
+
let m = 1;
|
|
19141
|
+
for (const s of series) {
|
|
19142
|
+
for (const p2 of s.data) if (p2.value > m) m = p2.value;
|
|
19143
|
+
}
|
|
19144
|
+
return m;
|
|
19145
|
+
}, [series, stack, columnTotals]);
|
|
19146
|
+
return /* @__PURE__ */ jsx(
|
|
19147
|
+
HStack,
|
|
19148
|
+
{
|
|
19149
|
+
gap: histogram ? "none" : "xs",
|
|
19150
|
+
align: "end",
|
|
19151
|
+
className: "w-full",
|
|
19152
|
+
style: { height },
|
|
19153
|
+
children: categories.map((label, catIdx) => {
|
|
19154
|
+
const displayLabel = timeAxis ? formatTimeLabel(label) : label;
|
|
19155
|
+
if (stack === "none") {
|
|
19156
|
+
return /* @__PURE__ */ jsxs(
|
|
19157
|
+
VStack,
|
|
19158
|
+
{
|
|
19159
|
+
gap: "xs",
|
|
19160
|
+
align: "center",
|
|
19161
|
+
flex: true,
|
|
19162
|
+
className: "min-w-0",
|
|
19163
|
+
children: [
|
|
19164
|
+
/* @__PURE__ */ jsx(HStack, { gap: histogram ? "none" : "xs", align: "end", className: "w-full", style: { height: "100%" }, children: series.map((s, sIdx) => {
|
|
19165
|
+
const value = valueAt(s, label);
|
|
19166
|
+
const barHeight = value / maxValue * 100;
|
|
19167
|
+
const color = seriesColor(s, sIdx);
|
|
19168
|
+
return /* @__PURE__ */ jsx(
|
|
19169
|
+
Box,
|
|
19170
|
+
{
|
|
19171
|
+
className: cn(
|
|
19172
|
+
"rounded-t-sm transition-all duration-500 ease-out min-h-[4px] cursor-pointer hover:opacity-80",
|
|
19173
|
+
histogram ? "flex-1 mx-0" : "flex-1"
|
|
19174
|
+
),
|
|
19175
|
+
style: {
|
|
19176
|
+
height: `${barHeight}%`,
|
|
19177
|
+
backgroundColor: color
|
|
19178
|
+
},
|
|
19179
|
+
onClick: () => onPointClick?.(
|
|
19180
|
+
{ label, value, color },
|
|
19181
|
+
s.name
|
|
19182
|
+
),
|
|
19183
|
+
title: `${s.name}: ${value}`
|
|
19184
|
+
},
|
|
19185
|
+
s.name
|
|
19186
|
+
);
|
|
19187
|
+
}) }),
|
|
19188
|
+
showValues && series.length === 1 && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: valueAt(series[0], label) }),
|
|
19189
|
+
/* @__PURE__ */ jsx(
|
|
19190
|
+
Typography,
|
|
19191
|
+
{
|
|
19192
|
+
variant: "caption",
|
|
19193
|
+
color: "secondary",
|
|
19194
|
+
className: "truncate w-full text-center",
|
|
19195
|
+
children: displayLabel
|
|
19196
|
+
}
|
|
19197
|
+
)
|
|
19198
|
+
]
|
|
19199
|
+
},
|
|
19200
|
+
label
|
|
19201
|
+
);
|
|
19063
19202
|
}
|
|
19064
|
-
|
|
19065
|
-
|
|
19066
|
-
|
|
19203
|
+
const total = columnTotals?.[catIdx] ?? 1;
|
|
19204
|
+
return /* @__PURE__ */ jsxs(
|
|
19205
|
+
VStack,
|
|
19206
|
+
{
|
|
19207
|
+
gap: "xs",
|
|
19208
|
+
align: "center",
|
|
19209
|
+
flex: true,
|
|
19210
|
+
className: "min-w-0",
|
|
19211
|
+
children: [
|
|
19212
|
+
/* @__PURE__ */ jsx(VStack, { gap: "none", className: "w-full", style: { height: "100%" }, justify: "end", children: series.map((s, sIdx) => {
|
|
19213
|
+
const value = valueAt(s, label);
|
|
19214
|
+
const ratio = stack === "normalize" ? total === 0 ? 0 : value / total * 100 : value / maxValue * 100;
|
|
19215
|
+
const color = seriesColor(s, sIdx);
|
|
19216
|
+
return /* @__PURE__ */ jsx(
|
|
19217
|
+
Box,
|
|
19218
|
+
{
|
|
19219
|
+
className: "w-full transition-all duration-500 ease-out cursor-pointer hover:opacity-80",
|
|
19220
|
+
style: {
|
|
19221
|
+
height: `${ratio}%`,
|
|
19222
|
+
backgroundColor: color
|
|
19223
|
+
},
|
|
19224
|
+
onClick: () => onPointClick?.(
|
|
19225
|
+
{ label, value, color },
|
|
19226
|
+
s.name
|
|
19227
|
+
),
|
|
19228
|
+
title: `${s.name}: ${value}`
|
|
19229
|
+
},
|
|
19230
|
+
s.name
|
|
19231
|
+
);
|
|
19232
|
+
}) }),
|
|
19233
|
+
/* @__PURE__ */ jsx(
|
|
19234
|
+
Typography,
|
|
19235
|
+
{
|
|
19236
|
+
variant: "caption",
|
|
19237
|
+
color: "secondary",
|
|
19238
|
+
className: "truncate w-full text-center",
|
|
19239
|
+
children: displayLabel
|
|
19240
|
+
}
|
|
19241
|
+
)
|
|
19242
|
+
]
|
|
19243
|
+
},
|
|
19244
|
+
label
|
|
19245
|
+
);
|
|
19246
|
+
})
|
|
19247
|
+
}
|
|
19248
|
+
);
|
|
19067
19249
|
};
|
|
19068
|
-
PieChart = ({ data, height, showValues, donut = false }) => {
|
|
19250
|
+
PieChart = ({ data, height, showValues, donut = false, onPointClick }) => {
|
|
19069
19251
|
const total = data.reduce((sum, d) => sum + d.value, 0);
|
|
19070
19252
|
const size = Math.min(height, 200);
|
|
19071
19253
|
const radius = size / 2 - 8;
|
|
@@ -19111,7 +19293,11 @@ var init_Chart = __esm({
|
|
|
19111
19293
|
fill: seg.color,
|
|
19112
19294
|
stroke: "var(--color-card)",
|
|
19113
19295
|
strokeWidth: "2",
|
|
19114
|
-
className: "transition-opacity duration-200 hover:opacity-80"
|
|
19296
|
+
className: "transition-opacity duration-200 hover:opacity-80 cursor-pointer",
|
|
19297
|
+
onClick: () => onPointClick?.(
|
|
19298
|
+
{ label: seg.label, value: seg.value, color: seg.color },
|
|
19299
|
+
"default"
|
|
19300
|
+
)
|
|
19115
19301
|
},
|
|
19116
19302
|
idx
|
|
19117
19303
|
)),
|
|
@@ -19146,56 +19332,243 @@ var init_Chart = __esm({
|
|
|
19146
19332
|
] }, idx)) })
|
|
19147
19333
|
] });
|
|
19148
19334
|
};
|
|
19149
|
-
LineChart = ({
|
|
19150
|
-
const maxValue = Math.max(...data.map((d) => d.value), 1);
|
|
19335
|
+
LineChart = ({ series, height, showValues, fill = false, timeAxis, onPointClick }) => {
|
|
19151
19336
|
const width = 400;
|
|
19152
19337
|
const padding = { top: 20, right: 20, bottom: 30, left: 40 };
|
|
19153
19338
|
const chartWidth = width - padding.left - padding.right;
|
|
19154
19339
|
const chartHeight = height - padding.top - padding.bottom;
|
|
19155
|
-
const
|
|
19156
|
-
|
|
19157
|
-
|
|
19158
|
-
|
|
19159
|
-
|
|
19160
|
-
|
|
19161
|
-
|
|
19162
|
-
|
|
19163
|
-
const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
|
|
19164
|
-
return /* @__PURE__ */ jsxs("svg", { width: "100%", height, viewBox: `0 0 ${width} ${height}`, preserveAspectRatio: "xMidYMid meet", children: [
|
|
19165
|
-
[0, 0.25, 0.5, 0.75, 1].map((frac) => {
|
|
19166
|
-
const y = padding.top + chartHeight * (1 - frac);
|
|
19167
|
-
return /* @__PURE__ */ jsx(
|
|
19168
|
-
"line",
|
|
19169
|
-
{
|
|
19170
|
-
x1: padding.left,
|
|
19171
|
-
y1: y,
|
|
19172
|
-
x2: width - padding.right,
|
|
19173
|
-
y2: y,
|
|
19174
|
-
stroke: "var(--color-border)",
|
|
19175
|
-
strokeDasharray: "4 4",
|
|
19176
|
-
opacity: 0.5
|
|
19177
|
-
},
|
|
19178
|
-
frac
|
|
19179
|
-
);
|
|
19180
|
-
}),
|
|
19181
|
-
fill && /* @__PURE__ */ jsx("path", { d: areaPath, fill: "var(--color-primary)", opacity: 0.1 }),
|
|
19182
|
-
/* @__PURE__ */ jsx("path", { d: linePath, fill: "none", stroke: "var(--color-primary)", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
19183
|
-
points.map((p2, idx) => /* @__PURE__ */ jsxs("g", { children: [
|
|
19184
|
-
/* @__PURE__ */ jsx("circle", { cx: p2.x, cy: p2.y, r: "4", fill: "var(--color-card)", stroke: "var(--color-primary)", strokeWidth: "2" }),
|
|
19185
|
-
showValues && /* @__PURE__ */ jsx("text", { x: p2.x, y: p2.y - 10, textAnchor: "middle", fill: "var(--color-foreground)", fontSize: "10", fontWeight: "500", children: p2.value }),
|
|
19186
|
-
/* @__PURE__ */ jsx(
|
|
19187
|
-
"text",
|
|
19188
|
-
{
|
|
19189
|
-
x: p2.x,
|
|
19190
|
-
y: height - 8,
|
|
19191
|
-
textAnchor: "middle",
|
|
19192
|
-
fill: "var(--color-muted-foreground)",
|
|
19193
|
-
fontSize: "9",
|
|
19194
|
-
children: p2.label
|
|
19340
|
+
const labels = useMemo(() => {
|
|
19341
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19342
|
+
const out = [];
|
|
19343
|
+
for (const s of series) {
|
|
19344
|
+
for (const p2 of s.data) {
|
|
19345
|
+
if (!seen.has(p2.label)) {
|
|
19346
|
+
seen.add(p2.label);
|
|
19347
|
+
out.push(p2.label);
|
|
19195
19348
|
}
|
|
19196
|
-
|
|
19197
|
-
|
|
19198
|
-
|
|
19349
|
+
}
|
|
19350
|
+
}
|
|
19351
|
+
return out;
|
|
19352
|
+
}, [series]);
|
|
19353
|
+
const maxValue = useMemo(() => {
|
|
19354
|
+
let m = 1;
|
|
19355
|
+
for (const s of series) {
|
|
19356
|
+
for (const p2 of s.data) if (p2.value > m) m = p2.value;
|
|
19357
|
+
}
|
|
19358
|
+
return m;
|
|
19359
|
+
}, [series]);
|
|
19360
|
+
const xFor = useCallback(
|
|
19361
|
+
(idx) => padding.left + idx / Math.max(labels.length - 1, 1) * chartWidth,
|
|
19362
|
+
[labels.length, chartWidth, padding.left]
|
|
19363
|
+
);
|
|
19364
|
+
const yFor = useCallback(
|
|
19365
|
+
(value) => padding.top + chartHeight - value / maxValue * chartHeight,
|
|
19366
|
+
[maxValue, chartHeight, padding.top]
|
|
19367
|
+
);
|
|
19368
|
+
return /* @__PURE__ */ jsxs(
|
|
19369
|
+
"svg",
|
|
19370
|
+
{
|
|
19371
|
+
width: "100%",
|
|
19372
|
+
height,
|
|
19373
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
19374
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
19375
|
+
children: [
|
|
19376
|
+
[0, 0.25, 0.5, 0.75, 1].map((frac) => {
|
|
19377
|
+
const y = padding.top + chartHeight * (1 - frac);
|
|
19378
|
+
return /* @__PURE__ */ jsx(
|
|
19379
|
+
"line",
|
|
19380
|
+
{
|
|
19381
|
+
x1: padding.left,
|
|
19382
|
+
y1: y,
|
|
19383
|
+
x2: width - padding.right,
|
|
19384
|
+
y2: y,
|
|
19385
|
+
stroke: "var(--color-border)",
|
|
19386
|
+
strokeDasharray: "4 4",
|
|
19387
|
+
opacity: 0.5
|
|
19388
|
+
},
|
|
19389
|
+
frac
|
|
19390
|
+
);
|
|
19391
|
+
}),
|
|
19392
|
+
series.map((s, sIdx) => {
|
|
19393
|
+
const color = seriesColor(s, sIdx);
|
|
19394
|
+
const points = labels.map((label, idx) => {
|
|
19395
|
+
const point = s.data.find((d) => d.label === label);
|
|
19396
|
+
return {
|
|
19397
|
+
x: xFor(idx),
|
|
19398
|
+
y: yFor(point ? point.value : 0),
|
|
19399
|
+
value: point ? point.value : 0,
|
|
19400
|
+
label
|
|
19401
|
+
};
|
|
19402
|
+
});
|
|
19403
|
+
const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
|
|
19404
|
+
const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
|
|
19405
|
+
return /* @__PURE__ */ jsxs("g", { children: [
|
|
19406
|
+
fill && /* @__PURE__ */ jsx(
|
|
19407
|
+
"path",
|
|
19408
|
+
{
|
|
19409
|
+
d: areaPath,
|
|
19410
|
+
fill: color,
|
|
19411
|
+
opacity: series.length > 1 ? 0.08 : 0.1
|
|
19412
|
+
}
|
|
19413
|
+
),
|
|
19414
|
+
/* @__PURE__ */ jsx(
|
|
19415
|
+
"path",
|
|
19416
|
+
{
|
|
19417
|
+
d: linePath,
|
|
19418
|
+
fill: "none",
|
|
19419
|
+
stroke: color,
|
|
19420
|
+
strokeWidth: "2",
|
|
19421
|
+
strokeLinecap: "round",
|
|
19422
|
+
strokeLinejoin: "round",
|
|
19423
|
+
strokeDasharray: s.dashed ? "6 4" : void 0
|
|
19424
|
+
}
|
|
19425
|
+
),
|
|
19426
|
+
points.map((p2, idx) => /* @__PURE__ */ jsxs("g", { children: [
|
|
19427
|
+
/* @__PURE__ */ jsx(
|
|
19428
|
+
"circle",
|
|
19429
|
+
{
|
|
19430
|
+
cx: p2.x,
|
|
19431
|
+
cy: p2.y,
|
|
19432
|
+
r: "4",
|
|
19433
|
+
fill: "var(--color-card)",
|
|
19434
|
+
stroke: color,
|
|
19435
|
+
strokeWidth: "2",
|
|
19436
|
+
className: "cursor-pointer",
|
|
19437
|
+
onClick: () => onPointClick?.(
|
|
19438
|
+
{ label: p2.label, value: p2.value, color },
|
|
19439
|
+
s.name
|
|
19440
|
+
)
|
|
19441
|
+
}
|
|
19442
|
+
),
|
|
19443
|
+
showValues && series.length === 1 && /* @__PURE__ */ jsx(
|
|
19444
|
+
"text",
|
|
19445
|
+
{
|
|
19446
|
+
x: p2.x,
|
|
19447
|
+
y: p2.y - 10,
|
|
19448
|
+
textAnchor: "middle",
|
|
19449
|
+
fill: "var(--color-foreground)",
|
|
19450
|
+
fontSize: "10",
|
|
19451
|
+
fontWeight: "500",
|
|
19452
|
+
children: p2.value
|
|
19453
|
+
}
|
|
19454
|
+
)
|
|
19455
|
+
] }, idx))
|
|
19456
|
+
] }, s.name);
|
|
19457
|
+
}),
|
|
19458
|
+
labels.map((label, idx) => /* @__PURE__ */ jsx(
|
|
19459
|
+
"text",
|
|
19460
|
+
{
|
|
19461
|
+
x: xFor(idx),
|
|
19462
|
+
y: height - 8,
|
|
19463
|
+
textAnchor: "middle",
|
|
19464
|
+
fill: "var(--color-muted-foreground)",
|
|
19465
|
+
fontSize: "9",
|
|
19466
|
+
children: timeAxis ? formatTimeLabel(label) : label
|
|
19467
|
+
},
|
|
19468
|
+
label
|
|
19469
|
+
))
|
|
19470
|
+
]
|
|
19471
|
+
}
|
|
19472
|
+
);
|
|
19473
|
+
};
|
|
19474
|
+
ScatterChart = ({ data, height, onPointClick }) => {
|
|
19475
|
+
const width = 400;
|
|
19476
|
+
const padding = { top: 20, right: 20, bottom: 30, left: 40 };
|
|
19477
|
+
const chartWidth = width - padding.left - padding.right;
|
|
19478
|
+
const chartHeight = height - padding.top - padding.bottom;
|
|
19479
|
+
const { minX, maxX, minY, maxY } = useMemo(() => {
|
|
19480
|
+
if (data.length === 0) {
|
|
19481
|
+
return { minX: 0, maxX: 1, minY: 0, maxY: 1 };
|
|
19482
|
+
}
|
|
19483
|
+
let mnX = data[0].x;
|
|
19484
|
+
let mxX = data[0].x;
|
|
19485
|
+
let mnY = data[0].y;
|
|
19486
|
+
let mxY = data[0].y;
|
|
19487
|
+
for (const p2 of data) {
|
|
19488
|
+
if (p2.x < mnX) mnX = p2.x;
|
|
19489
|
+
if (p2.x > mxX) mxX = p2.x;
|
|
19490
|
+
if (p2.y < mnY) mnY = p2.y;
|
|
19491
|
+
if (p2.y > mxY) mxY = p2.y;
|
|
19492
|
+
}
|
|
19493
|
+
return { minX: mnX, maxX: mxX, minY: mnY, maxY: mxY };
|
|
19494
|
+
}, [data]);
|
|
19495
|
+
const rangeX = maxX - minX || 1;
|
|
19496
|
+
const rangeY = maxY - minY || 1;
|
|
19497
|
+
return /* @__PURE__ */ jsxs(
|
|
19498
|
+
"svg",
|
|
19499
|
+
{
|
|
19500
|
+
width: "100%",
|
|
19501
|
+
height,
|
|
19502
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
19503
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
19504
|
+
children: [
|
|
19505
|
+
[0, 0.25, 0.5, 0.75, 1].map((frac) => {
|
|
19506
|
+
const y = padding.top + chartHeight * (1 - frac);
|
|
19507
|
+
return /* @__PURE__ */ jsx(
|
|
19508
|
+
"line",
|
|
19509
|
+
{
|
|
19510
|
+
x1: padding.left,
|
|
19511
|
+
y1: y,
|
|
19512
|
+
x2: width - padding.right,
|
|
19513
|
+
y2: y,
|
|
19514
|
+
stroke: "var(--color-border)",
|
|
19515
|
+
strokeDasharray: "4 4",
|
|
19516
|
+
opacity: 0.5
|
|
19517
|
+
},
|
|
19518
|
+
frac
|
|
19519
|
+
);
|
|
19520
|
+
}),
|
|
19521
|
+
data.map((p2, idx) => {
|
|
19522
|
+
const cx = padding.left + (p2.x - minX) / rangeX * chartWidth;
|
|
19523
|
+
const cy = padding.top + chartHeight - (p2.y - minY) / rangeY * chartHeight;
|
|
19524
|
+
const r = p2.size ?? 5;
|
|
19525
|
+
const color = p2.color ?? CHART_COLORS[idx % CHART_COLORS.length];
|
|
19526
|
+
return /* @__PURE__ */ jsx(
|
|
19527
|
+
"circle",
|
|
19528
|
+
{
|
|
19529
|
+
cx,
|
|
19530
|
+
cy,
|
|
19531
|
+
r,
|
|
19532
|
+
fill: color,
|
|
19533
|
+
opacity: 0.7,
|
|
19534
|
+
className: "cursor-pointer hover:opacity-100",
|
|
19535
|
+
onClick: () => onPointClick?.(
|
|
19536
|
+
{
|
|
19537
|
+
label: p2.label ?? `(${p2.x}, ${p2.y})`,
|
|
19538
|
+
value: p2.y,
|
|
19539
|
+
color
|
|
19540
|
+
},
|
|
19541
|
+
"default"
|
|
19542
|
+
),
|
|
19543
|
+
children: /* @__PURE__ */ jsx("title", { children: p2.label ?? `(${p2.x}, ${p2.y})` })
|
|
19544
|
+
},
|
|
19545
|
+
idx
|
|
19546
|
+
);
|
|
19547
|
+
}),
|
|
19548
|
+
/* @__PURE__ */ jsx(
|
|
19549
|
+
"text",
|
|
19550
|
+
{
|
|
19551
|
+
x: padding.left,
|
|
19552
|
+
y: height - 8,
|
|
19553
|
+
fill: "var(--color-muted-foreground)",
|
|
19554
|
+
fontSize: "9",
|
|
19555
|
+
children: minX.toFixed(1)
|
|
19556
|
+
}
|
|
19557
|
+
),
|
|
19558
|
+
/* @__PURE__ */ jsx(
|
|
19559
|
+
"text",
|
|
19560
|
+
{
|
|
19561
|
+
x: width - padding.right,
|
|
19562
|
+
y: height - 8,
|
|
19563
|
+
textAnchor: "end",
|
|
19564
|
+
fill: "var(--color-muted-foreground)",
|
|
19565
|
+
fontSize: "9",
|
|
19566
|
+
children: maxX.toFixed(1)
|
|
19567
|
+
}
|
|
19568
|
+
)
|
|
19569
|
+
]
|
|
19570
|
+
}
|
|
19571
|
+
);
|
|
19199
19572
|
};
|
|
19200
19573
|
Chart = ({
|
|
19201
19574
|
title,
|
|
@@ -19203,9 +19576,13 @@ var init_Chart = __esm({
|
|
|
19203
19576
|
chartType = "bar",
|
|
19204
19577
|
series,
|
|
19205
19578
|
data: simpleData,
|
|
19579
|
+
scatterData,
|
|
19206
19580
|
height = 200,
|
|
19207
19581
|
showLegend = true,
|
|
19208
19582
|
showValues = false,
|
|
19583
|
+
stack = "none",
|
|
19584
|
+
timeAxis = false,
|
|
19585
|
+
drillEvent,
|
|
19209
19586
|
actions,
|
|
19210
19587
|
entity,
|
|
19211
19588
|
isLoading = false,
|
|
@@ -19222,11 +19599,25 @@ var init_Chart = __esm({
|
|
|
19222
19599
|
},
|
|
19223
19600
|
[eventBus]
|
|
19224
19601
|
);
|
|
19225
|
-
const
|
|
19226
|
-
|
|
19227
|
-
|
|
19602
|
+
const handlePointClick = useCallback(
|
|
19603
|
+
(point, seriesName) => {
|
|
19604
|
+
if (drillEvent) {
|
|
19605
|
+
eventBus.emit(`UI:${drillEvent}`, {
|
|
19606
|
+
label: point.label,
|
|
19607
|
+
value: point.value,
|
|
19608
|
+
seriesLabel: seriesName === "default" ? void 0 : seriesName
|
|
19609
|
+
});
|
|
19610
|
+
}
|
|
19611
|
+
},
|
|
19612
|
+
[drillEvent, eventBus]
|
|
19613
|
+
);
|
|
19614
|
+
const normalizedSeries = useMemo(() => {
|
|
19615
|
+
if (series && series.length > 0) return series;
|
|
19616
|
+
if (simpleData) return [{ name: "default", data: simpleData }];
|
|
19228
19617
|
return [];
|
|
19229
19618
|
}, [simpleData, series]);
|
|
19619
|
+
const firstSeriesData = normalizedSeries[0]?.data ?? [];
|
|
19620
|
+
const hasContent = chartType === "scatter" ? (scatterData?.length ?? 0) > 0 : normalizedSeries.some((s) => s.data.length > 0);
|
|
19230
19621
|
if (isLoading) {
|
|
19231
19622
|
return /* @__PURE__ */ jsx(LoadingState, { message: "Loading chart...", className });
|
|
19232
19623
|
}
|
|
@@ -19240,7 +19631,7 @@ var init_Chart = __esm({
|
|
|
19240
19631
|
}
|
|
19241
19632
|
);
|
|
19242
19633
|
}
|
|
19243
|
-
if (
|
|
19634
|
+
if (!hasContent) {
|
|
19244
19635
|
return /* @__PURE__ */ jsx(EmptyState, { title: t("empty.noData"), description: t("empty.noData"), className });
|
|
19245
19636
|
}
|
|
19246
19637
|
return /* @__PURE__ */ jsx(Card, { className: cn("p-6", className), children: /* @__PURE__ */ jsxs(VStack, { gap: "md", children: [
|
|
@@ -19261,18 +19652,84 @@ var init_Chart = __esm({
|
|
|
19261
19652
|
)) })
|
|
19262
19653
|
] }),
|
|
19263
19654
|
/* @__PURE__ */ jsxs(Box, { className: "w-full", children: [
|
|
19264
|
-
chartType === "bar" && /* @__PURE__ */ jsx(
|
|
19265
|
-
|
|
19266
|
-
|
|
19267
|
-
|
|
19268
|
-
|
|
19655
|
+
chartType === "bar" && /* @__PURE__ */ jsx(
|
|
19656
|
+
BarChart,
|
|
19657
|
+
{
|
|
19658
|
+
series: normalizedSeries,
|
|
19659
|
+
height,
|
|
19660
|
+
showValues,
|
|
19661
|
+
stack,
|
|
19662
|
+
timeAxis,
|
|
19663
|
+
onPointClick: handlePointClick
|
|
19664
|
+
}
|
|
19665
|
+
),
|
|
19666
|
+
chartType === "histogram" && /* @__PURE__ */ jsx(
|
|
19667
|
+
BarChart,
|
|
19668
|
+
{
|
|
19669
|
+
series: normalizedSeries,
|
|
19670
|
+
height,
|
|
19671
|
+
showValues,
|
|
19672
|
+
stack: "none",
|
|
19673
|
+
timeAxis: false,
|
|
19674
|
+
histogram: true,
|
|
19675
|
+
onPointClick: handlePointClick
|
|
19676
|
+
}
|
|
19677
|
+
),
|
|
19678
|
+
chartType === "line" && /* @__PURE__ */ jsx(
|
|
19679
|
+
LineChart,
|
|
19680
|
+
{
|
|
19681
|
+
series: normalizedSeries,
|
|
19682
|
+
height,
|
|
19683
|
+
showValues,
|
|
19684
|
+
timeAxis,
|
|
19685
|
+
onPointClick: handlePointClick
|
|
19686
|
+
}
|
|
19687
|
+
),
|
|
19688
|
+
chartType === "area" && /* @__PURE__ */ jsx(
|
|
19689
|
+
LineChart,
|
|
19690
|
+
{
|
|
19691
|
+
series: normalizedSeries,
|
|
19692
|
+
height,
|
|
19693
|
+
showValues,
|
|
19694
|
+
timeAxis,
|
|
19695
|
+
fill: true,
|
|
19696
|
+
onPointClick: handlePointClick
|
|
19697
|
+
}
|
|
19698
|
+
),
|
|
19699
|
+
chartType === "pie" && /* @__PURE__ */ jsx(
|
|
19700
|
+
PieChart,
|
|
19701
|
+
{
|
|
19702
|
+
data: firstSeriesData,
|
|
19703
|
+
height,
|
|
19704
|
+
showValues: showLegend,
|
|
19705
|
+
onPointClick: handlePointClick
|
|
19706
|
+
}
|
|
19707
|
+
),
|
|
19708
|
+
chartType === "donut" && /* @__PURE__ */ jsx(
|
|
19709
|
+
PieChart,
|
|
19710
|
+
{
|
|
19711
|
+
data: firstSeriesData,
|
|
19712
|
+
height,
|
|
19713
|
+
showValues: showLegend,
|
|
19714
|
+
donut: true,
|
|
19715
|
+
onPointClick: handlePointClick
|
|
19716
|
+
}
|
|
19717
|
+
),
|
|
19718
|
+
chartType === "scatter" && /* @__PURE__ */ jsx(
|
|
19719
|
+
ScatterChart,
|
|
19720
|
+
{
|
|
19721
|
+
data: scatterData ?? [],
|
|
19722
|
+
height,
|
|
19723
|
+
onPointClick: handlePointClick
|
|
19724
|
+
}
|
|
19725
|
+
)
|
|
19269
19726
|
] }),
|
|
19270
|
-
showLegend &&
|
|
19727
|
+
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: [
|
|
19271
19728
|
/* @__PURE__ */ jsx(
|
|
19272
19729
|
Box,
|
|
19273
19730
|
{
|
|
19274
19731
|
className: "w-3 h-3 rounded-full flex-shrink-0",
|
|
19275
|
-
style: { backgroundColor: s
|
|
19732
|
+
style: { backgroundColor: seriesColor(s, idx) }
|
|
19276
19733
|
}
|
|
19277
19734
|
),
|
|
19278
19735
|
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: s.name })
|
|
@@ -21119,7 +21576,6 @@ function useDataDnd(args) {
|
|
|
21119
21576
|
const raw = it[dndItemIdField];
|
|
21120
21577
|
return raw ?? `__idx_${idx}`;
|
|
21121
21578
|
}),
|
|
21122
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
21123
21579
|
[itemIdsSignature]
|
|
21124
21580
|
);
|
|
21125
21581
|
const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
|
|
@@ -22649,7 +23105,16 @@ var init_FilterGroup = __esm({
|
|
|
22649
23105
|
onClear: () => handleFilterSelect(`${filter.field}_to`, null)
|
|
22650
23106
|
}
|
|
22651
23107
|
)
|
|
22652
|
-
] }) : /* @__PURE__ */ jsx(
|
|
23108
|
+
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
|
|
23109
|
+
Input,
|
|
23110
|
+
{
|
|
23111
|
+
value: selectedValues[filter.field] || "",
|
|
23112
|
+
onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
|
|
23113
|
+
placeholder: filter.label,
|
|
23114
|
+
clearable: true,
|
|
23115
|
+
onClear: () => handleFilterSelect(filter.field, null)
|
|
23116
|
+
}
|
|
23117
|
+
) : /* @__PURE__ */ jsx(
|
|
22653
23118
|
Select,
|
|
22654
23119
|
{
|
|
22655
23120
|
value: selectedValues[filter.field] || "all",
|
|
@@ -22716,7 +23181,17 @@ var init_FilterGroup = __esm({
|
|
|
22716
23181
|
className: "text-sm min-w-[100px]"
|
|
22717
23182
|
}
|
|
22718
23183
|
)
|
|
22719
|
-
] }) : /* @__PURE__ */ jsx(
|
|
23184
|
+
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
|
|
23185
|
+
Input,
|
|
23186
|
+
{
|
|
23187
|
+
value: selectedValues[filter.field] || "",
|
|
23188
|
+
onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
|
|
23189
|
+
placeholder: filter.label,
|
|
23190
|
+
clearable: true,
|
|
23191
|
+
onClear: () => handleFilterSelect(filter.field, null),
|
|
23192
|
+
className: "text-sm"
|
|
23193
|
+
}
|
|
23194
|
+
) : /* @__PURE__ */ jsx(
|
|
22720
23195
|
Select,
|
|
22721
23196
|
{
|
|
22722
23197
|
value: selectedValues[filter.field] || "all",
|
|
@@ -22821,7 +23296,17 @@ var init_FilterGroup = __esm({
|
|
|
22821
23296
|
className: "min-w-[130px]"
|
|
22822
23297
|
}
|
|
22823
23298
|
)
|
|
22824
|
-
] }) : /* @__PURE__ */ jsx(
|
|
23299
|
+
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsx(
|
|
23300
|
+
Input,
|
|
23301
|
+
{
|
|
23302
|
+
value: selectedValues[filter.field] || "",
|
|
23303
|
+
onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
|
|
23304
|
+
placeholder: filter.label,
|
|
23305
|
+
clearable: true,
|
|
23306
|
+
onClear: () => handleFilterSelect(filter.field, null),
|
|
23307
|
+
className: "min-w-[160px]"
|
|
23308
|
+
}
|
|
23309
|
+
) : /* @__PURE__ */ jsx(
|
|
22825
23310
|
Select,
|
|
22826
23311
|
{
|
|
22827
23312
|
value: selectedValues[filter.field] || "all",
|
|
@@ -24110,6 +24595,151 @@ var init_FlipCard = __esm({
|
|
|
24110
24595
|
FlipCard.displayName = "FlipCard";
|
|
24111
24596
|
}
|
|
24112
24597
|
});
|
|
24598
|
+
function toISODate(d) {
|
|
24599
|
+
return d.toISOString().slice(0, 10);
|
|
24600
|
+
}
|
|
24601
|
+
function startOfMonth(d) {
|
|
24602
|
+
return new Date(d.getFullYear(), d.getMonth(), 1);
|
|
24603
|
+
}
|
|
24604
|
+
function startOfQuarter(d) {
|
|
24605
|
+
return new Date(d.getFullYear(), Math.floor(d.getMonth() / 3) * 3, 1);
|
|
24606
|
+
}
|
|
24607
|
+
function startOfYear(d) {
|
|
24608
|
+
return new Date(d.getFullYear(), 0, 1);
|
|
24609
|
+
}
|
|
24610
|
+
function daysAgo(n) {
|
|
24611
|
+
const d = /* @__PURE__ */ new Date();
|
|
24612
|
+
d.setDate(d.getDate() - n);
|
|
24613
|
+
return d;
|
|
24614
|
+
}
|
|
24615
|
+
var DEFAULT_PRESETS, DateRangePicker;
|
|
24616
|
+
var init_DateRangePicker = __esm({
|
|
24617
|
+
"components/molecules/DateRangePicker.tsx"() {
|
|
24618
|
+
"use client";
|
|
24619
|
+
init_cn();
|
|
24620
|
+
init_Button();
|
|
24621
|
+
init_Input();
|
|
24622
|
+
init_Stack();
|
|
24623
|
+
init_Typography();
|
|
24624
|
+
init_useEventBus();
|
|
24625
|
+
DEFAULT_PRESETS = [
|
|
24626
|
+
{
|
|
24627
|
+
label: "Last 7 days",
|
|
24628
|
+
value: "7d",
|
|
24629
|
+
range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24630
|
+
},
|
|
24631
|
+
{
|
|
24632
|
+
label: "Last 30 days",
|
|
24633
|
+
value: "30d",
|
|
24634
|
+
range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24635
|
+
},
|
|
24636
|
+
{
|
|
24637
|
+
label: "This Month",
|
|
24638
|
+
value: "month",
|
|
24639
|
+
range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24640
|
+
},
|
|
24641
|
+
{
|
|
24642
|
+
label: "This Quarter",
|
|
24643
|
+
value: "quarter",
|
|
24644
|
+
range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24645
|
+
},
|
|
24646
|
+
{
|
|
24647
|
+
label: "YTD",
|
|
24648
|
+
value: "ytd",
|
|
24649
|
+
range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24650
|
+
}
|
|
24651
|
+
];
|
|
24652
|
+
DateRangePicker = ({
|
|
24653
|
+
from: fromProp,
|
|
24654
|
+
to: toProp,
|
|
24655
|
+
event,
|
|
24656
|
+
onChange,
|
|
24657
|
+
presets = DEFAULT_PRESETS,
|
|
24658
|
+
fromLabel = "From",
|
|
24659
|
+
toLabel = "To",
|
|
24660
|
+
className
|
|
24661
|
+
}) => {
|
|
24662
|
+
const eventBus = useEventBus();
|
|
24663
|
+
const [from, setFrom] = useState(fromProp ?? "");
|
|
24664
|
+
const [to, setTo] = useState(toProp ?? "");
|
|
24665
|
+
const [activePreset, setActivePreset] = useState(null);
|
|
24666
|
+
const emit = useCallback(
|
|
24667
|
+
(range) => {
|
|
24668
|
+
onChange?.(range);
|
|
24669
|
+
if (event) eventBus.emit(`UI:${event}`, range);
|
|
24670
|
+
},
|
|
24671
|
+
[onChange, event, eventBus]
|
|
24672
|
+
);
|
|
24673
|
+
const handleFromChange = useCallback(
|
|
24674
|
+
(next) => {
|
|
24675
|
+
setFrom(next);
|
|
24676
|
+
setActivePreset(null);
|
|
24677
|
+
emit({ from: next, to });
|
|
24678
|
+
},
|
|
24679
|
+
[to, emit]
|
|
24680
|
+
);
|
|
24681
|
+
const handleToChange = useCallback(
|
|
24682
|
+
(next) => {
|
|
24683
|
+
setTo(next);
|
|
24684
|
+
setActivePreset(null);
|
|
24685
|
+
emit({ from, to: next });
|
|
24686
|
+
},
|
|
24687
|
+
[from, emit]
|
|
24688
|
+
);
|
|
24689
|
+
const handlePreset = useCallback(
|
|
24690
|
+
(preset) => {
|
|
24691
|
+
const range = preset.range();
|
|
24692
|
+
setFrom(range.from);
|
|
24693
|
+
setTo(range.to);
|
|
24694
|
+
setActivePreset(preset.value);
|
|
24695
|
+
emit(range);
|
|
24696
|
+
},
|
|
24697
|
+
[emit]
|
|
24698
|
+
);
|
|
24699
|
+
const presetButtons = useMemo(
|
|
24700
|
+
() => presets.map((preset) => /* @__PURE__ */ jsx(
|
|
24701
|
+
Button,
|
|
24702
|
+
{
|
|
24703
|
+
variant: activePreset === preset.value ? "primary" : "ghost",
|
|
24704
|
+
size: "sm",
|
|
24705
|
+
onClick: () => handlePreset(preset),
|
|
24706
|
+
children: preset.label
|
|
24707
|
+
},
|
|
24708
|
+
preset.value
|
|
24709
|
+
)),
|
|
24710
|
+
[presets, activePreset, handlePreset]
|
|
24711
|
+
);
|
|
24712
|
+
return /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: cn(className), children: [
|
|
24713
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "md", align: "end", children: [
|
|
24714
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
24715
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: fromLabel }),
|
|
24716
|
+
/* @__PURE__ */ jsx(
|
|
24717
|
+
Input,
|
|
24718
|
+
{
|
|
24719
|
+
type: "date",
|
|
24720
|
+
value: from,
|
|
24721
|
+
onChange: (e) => handleFromChange(e.target.value)
|
|
24722
|
+
}
|
|
24723
|
+
)
|
|
24724
|
+
] }),
|
|
24725
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
24726
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: toLabel }),
|
|
24727
|
+
/* @__PURE__ */ jsx(
|
|
24728
|
+
Input,
|
|
24729
|
+
{
|
|
24730
|
+
type: "date",
|
|
24731
|
+
value: to,
|
|
24732
|
+
onChange: (e) => handleToChange(e.target.value)
|
|
24733
|
+
}
|
|
24734
|
+
)
|
|
24735
|
+
] })
|
|
24736
|
+
] }),
|
|
24737
|
+
presets.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
|
|
24738
|
+
] });
|
|
24739
|
+
};
|
|
24740
|
+
DateRangePicker.displayName = "DateRangePicker";
|
|
24741
|
+
}
|
|
24742
|
+
});
|
|
24113
24743
|
var DEFAULT_OPTIONS, DateRangeSelector;
|
|
24114
24744
|
var init_DateRangeSelector = __esm({
|
|
24115
24745
|
"components/molecules/DateRangeSelector.tsx"() {
|
|
@@ -27081,7 +27711,9 @@ var init_StatDisplay = __esm({
|
|
|
27081
27711
|
init_Typography();
|
|
27082
27712
|
init_Box();
|
|
27083
27713
|
init_Stack();
|
|
27714
|
+
init_Sparkline();
|
|
27084
27715
|
init_Icon();
|
|
27716
|
+
init_useEventBus();
|
|
27085
27717
|
variantColor = {
|
|
27086
27718
|
default: "text-foreground",
|
|
27087
27719
|
primary: "text-primary",
|
|
@@ -27096,6 +27728,10 @@ var init_StatDisplay = __esm({
|
|
|
27096
27728
|
max,
|
|
27097
27729
|
target,
|
|
27098
27730
|
trend,
|
|
27731
|
+
trendPolarity = "higher-is-better",
|
|
27732
|
+
trendFormat = "absolute",
|
|
27733
|
+
sparklineData,
|
|
27734
|
+
clickEvent,
|
|
27099
27735
|
prefix,
|
|
27100
27736
|
suffix,
|
|
27101
27737
|
icon: iconProp,
|
|
@@ -27109,6 +27745,10 @@ var init_StatDisplay = __esm({
|
|
|
27109
27745
|
isLoading = false,
|
|
27110
27746
|
error = null
|
|
27111
27747
|
}) => {
|
|
27748
|
+
const eventBus = useEventBus();
|
|
27749
|
+
const handleClick = useCallback(() => {
|
|
27750
|
+
if (clickEvent) eventBus.emit(`UI:${clickEvent}`, { metricLabel: label });
|
|
27751
|
+
}, [clickEvent, eventBus, label]);
|
|
27112
27752
|
const ResolvedIcon = typeof iconProp === "string" ? resolveIcon(iconProp) : null;
|
|
27113
27753
|
const iconSizes3 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
|
|
27114
27754
|
const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
|
|
@@ -27119,7 +27759,10 @@ var init_StatDisplay = __esm({
|
|
|
27119
27759
|
const targetPct = showTarget ? Math.max(0, Math.min(100, numericValue / target * 100)) : 0;
|
|
27120
27760
|
const showTrend = typeof trend === "number" && trend !== 0 && Number.isFinite(trend);
|
|
27121
27761
|
const trendUp = showTrend && trend > 0;
|
|
27122
|
-
const
|
|
27762
|
+
const trendIsGood = trendPolarity === "lower-is-better" ? !trendUp : trendUp;
|
|
27763
|
+
const trendMagnitude = Math.abs(trend);
|
|
27764
|
+
const trendSuffix = trendFormat === "percent" ? "%" : "";
|
|
27765
|
+
const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${trendMagnitude}${trendSuffix}` : "";
|
|
27123
27766
|
if (error) {
|
|
27124
27767
|
return /* @__PURE__ */ jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsx(Typography, { variant: "small", color: "error", children: error.message }) });
|
|
27125
27768
|
}
|
|
@@ -27130,38 +27773,57 @@ var init_StatDisplay = __esm({
|
|
|
27130
27773
|
] }) });
|
|
27131
27774
|
}
|
|
27132
27775
|
if (compact) {
|
|
27133
|
-
return /* @__PURE__ */ jsxs(
|
|
27134
|
-
|
|
27135
|
-
|
|
27136
|
-
|
|
27137
|
-
|
|
27138
|
-
|
|
27139
|
-
|
|
27776
|
+
return /* @__PURE__ */ jsxs(
|
|
27777
|
+
HStack,
|
|
27778
|
+
{
|
|
27779
|
+
gap: "sm",
|
|
27780
|
+
className: cn("items-center", clickEvent && "cursor-pointer hover:opacity-80", className),
|
|
27781
|
+
onClick: clickEvent ? handleClick : void 0,
|
|
27782
|
+
children: [
|
|
27783
|
+
ResolvedIcon && /* @__PURE__ */ jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
|
|
27784
|
+
typeof iconProp !== "string" && iconProp,
|
|
27785
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: label }),
|
|
27786
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
|
|
27787
|
+
showTrend && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: cn("font-semibold", trendIsGood ? "text-success" : "text-error"), children: trendLabel }),
|
|
27788
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto", width: 60, height: 20 })
|
|
27789
|
+
]
|
|
27790
|
+
}
|
|
27791
|
+
);
|
|
27140
27792
|
}
|
|
27141
|
-
return /* @__PURE__ */ jsx(
|
|
27142
|
-
|
|
27143
|
-
|
|
27144
|
-
|
|
27145
|
-
|
|
27146
|
-
|
|
27147
|
-
|
|
27148
|
-
{
|
|
27149
|
-
|
|
27150
|
-
className: cn("font-
|
|
27151
|
-
|
|
27152
|
-
|
|
27153
|
-
|
|
27154
|
-
|
|
27155
|
-
|
|
27156
|
-
|
|
27157
|
-
|
|
27158
|
-
|
|
27159
|
-
|
|
27160
|
-
|
|
27161
|
-
|
|
27162
|
-
|
|
27163
|
-
|
|
27164
|
-
|
|
27793
|
+
return /* @__PURE__ */ jsx(
|
|
27794
|
+
Card,
|
|
27795
|
+
{
|
|
27796
|
+
className: cn(padSizes[size], clickEvent && "cursor-pointer hover:shadow-md transition-shadow", className),
|
|
27797
|
+
onClick: clickEvent ? handleClick : void 0,
|
|
27798
|
+
children: /* @__PURE__ */ jsxs(HStack, { align: "start", justify: "between", children: [
|
|
27799
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
|
|
27800
|
+
/* @__PURE__ */ jsx(Typography, { variant: "overline", color: "secondary", children: label }),
|
|
27801
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "end", children: [
|
|
27802
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
|
|
27803
|
+
showTrend && /* @__PURE__ */ jsx(
|
|
27804
|
+
Typography,
|
|
27805
|
+
{
|
|
27806
|
+
variant: "caption",
|
|
27807
|
+
className: cn("font-semibold pb-1", trendIsGood ? "text-success" : "text-error"),
|
|
27808
|
+
children: trendLabel
|
|
27809
|
+
}
|
|
27810
|
+
)
|
|
27811
|
+
] }),
|
|
27812
|
+
showTarget && /* @__PURE__ */ jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
27813
|
+
Box,
|
|
27814
|
+
{
|
|
27815
|
+
className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
|
|
27816
|
+
style: { width: `${targetPct}%` }
|
|
27817
|
+
}
|
|
27818
|
+
) })
|
|
27819
|
+
] }),
|
|
27820
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
|
|
27821
|
+
(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 }),
|
|
27822
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto" })
|
|
27823
|
+
] })
|
|
27824
|
+
] })
|
|
27825
|
+
}
|
|
27826
|
+
);
|
|
27165
27827
|
};
|
|
27166
27828
|
StatDisplay.displayName = "StatDisplay";
|
|
27167
27829
|
}
|
|
@@ -41505,6 +42167,7 @@ var init_StatCard = __esm({
|
|
|
41505
42167
|
init_Box();
|
|
41506
42168
|
init_Stack();
|
|
41507
42169
|
init_Button();
|
|
42170
|
+
init_Sparkline();
|
|
41508
42171
|
init_useEventBus();
|
|
41509
42172
|
init_useTranslate();
|
|
41510
42173
|
init_Icon();
|
|
@@ -41674,32 +42337,7 @@ var init_StatCard = __esm({
|
|
|
41674
42337
|
] }),
|
|
41675
42338
|
/* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
|
|
41676
42339
|
Icon3 && /* @__PURE__ */ jsx(Box, { className: cn("p-3", iconBg), children: /* @__PURE__ */ jsx(Icon3, { className: cn("h-6 w-6", iconColor) }) }),
|
|
41677
|
-
sparklineData && sparklineData.length > 1 && (
|
|
41678
|
-
const w = 80;
|
|
41679
|
-
const h = 32;
|
|
41680
|
-
const pad = 2;
|
|
41681
|
-
const min = Math.min(...sparklineData);
|
|
41682
|
-
const max = Math.max(...sparklineData);
|
|
41683
|
-
const range = max - min || 1;
|
|
41684
|
-
const points = sparklineData.map((v, i) => {
|
|
41685
|
-
const x = pad + i / (sparklineData.length - 1) * (w - pad * 2);
|
|
41686
|
-
const y = pad + (1 - (v - min) / range) * (h - pad * 2);
|
|
41687
|
-
return `${x},${y}`;
|
|
41688
|
-
}).join(" ");
|
|
41689
|
-
const trending = sparklineData[sparklineData.length - 1] >= sparklineData[0];
|
|
41690
|
-
const strokeColor = trending ? "var(--color-success)" : "var(--color-error)";
|
|
41691
|
-
return /* @__PURE__ */ jsx("svg", { width: w, height: h, viewBox: `0 0 ${w} ${h}`, className: "flex-shrink-0", children: /* @__PURE__ */ jsx(
|
|
41692
|
-
"polyline",
|
|
41693
|
-
{
|
|
41694
|
-
fill: "none",
|
|
41695
|
-
stroke: strokeColor,
|
|
41696
|
-
strokeWidth: "2",
|
|
41697
|
-
strokeLinecap: "round",
|
|
41698
|
-
strokeLinejoin: "round",
|
|
41699
|
-
points
|
|
41700
|
-
}
|
|
41701
|
-
) });
|
|
41702
|
-
})()
|
|
42340
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto" })
|
|
41703
42341
|
] })
|
|
41704
42342
|
] }),
|
|
41705
42343
|
action && /* @__PURE__ */ jsxs(
|
|
@@ -43597,6 +44235,7 @@ var init_component_registry_generated = __esm({
|
|
|
43597
44235
|
init_DataGrid();
|
|
43598
44236
|
init_DataList();
|
|
43599
44237
|
init_DataTable();
|
|
44238
|
+
init_DateRangePicker();
|
|
43600
44239
|
init_DateRangeSelector();
|
|
43601
44240
|
init_DayCell();
|
|
43602
44241
|
init_DebuggerBoard();
|
|
@@ -43729,6 +44368,7 @@ var init_component_registry_generated = __esm({
|
|
|
43729
44368
|
init_Skeleton();
|
|
43730
44369
|
init_SocialProof();
|
|
43731
44370
|
init_SortableList();
|
|
44371
|
+
init_Sparkline();
|
|
43732
44372
|
init_Split();
|
|
43733
44373
|
init_SplitPane();
|
|
43734
44374
|
init_SplitSection();
|
|
@@ -43877,6 +44517,7 @@ var init_component_registry_generated = __esm({
|
|
|
43877
44517
|
"DataGrid": DataGrid,
|
|
43878
44518
|
"DataList": DataList,
|
|
43879
44519
|
"DataTable": DataTable,
|
|
44520
|
+
"DateRangePicker": DateRangePicker,
|
|
43880
44521
|
"DateRangeSelector": DateRangeSelector,
|
|
43881
44522
|
"DayCell": DayCell,
|
|
43882
44523
|
"DebuggerBoard": DebuggerBoard,
|
|
@@ -44038,6 +44679,7 @@ var init_component_registry_generated = __esm({
|
|
|
44038
44679
|
"SortableList": SortableList,
|
|
44039
44680
|
"Spacer": SpacerPattern,
|
|
44040
44681
|
"SpacerPattern": SpacerPattern,
|
|
44682
|
+
"Sparkline": Sparkline,
|
|
44041
44683
|
"Spinner": SpinnerPattern,
|
|
44042
44684
|
"SpinnerPattern": SpinnerPattern,
|
|
44043
44685
|
"Split": Split,
|