@almadar/ui 4.51.14 → 4.51.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/avl/index.cjs +775 -150
- package/dist/avl/index.js +775 -150
- package/dist/components/atoms/Sparkline.d.ts +30 -0
- package/dist/components/atoms/index.d.ts +1 -0
- package/dist/components/index.cjs +765 -149
- package/dist/components/index.js +766 -150
- package/dist/components/molecules/DateRangePicker.d.ts +56 -0
- package/dist/components/molecules/FilterGroup.d.ts +3 -3
- package/dist/components/molecules/StatDisplay.d.ts +9 -1
- package/dist/components/molecules/index.d.ts +1 -0
- package/dist/components/organisms/Chart.d.ts +32 -12
- package/dist/providers/index.cjs +763 -149
- package/dist/providers/index.js +763 -149
- package/dist/runtime/index.cjs +763 -149
- package/dist/runtime/index.js +763 -149
- package/package.json +1 -1
package/dist/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 })
|
|
@@ -24110,6 +24567,151 @@ var init_FlipCard = __esm({
|
|
|
24110
24567
|
FlipCard.displayName = "FlipCard";
|
|
24111
24568
|
}
|
|
24112
24569
|
});
|
|
24570
|
+
function toISODate(d) {
|
|
24571
|
+
return d.toISOString().slice(0, 10);
|
|
24572
|
+
}
|
|
24573
|
+
function startOfMonth(d) {
|
|
24574
|
+
return new Date(d.getFullYear(), d.getMonth(), 1);
|
|
24575
|
+
}
|
|
24576
|
+
function startOfQuarter(d) {
|
|
24577
|
+
return new Date(d.getFullYear(), Math.floor(d.getMonth() / 3) * 3, 1);
|
|
24578
|
+
}
|
|
24579
|
+
function startOfYear(d) {
|
|
24580
|
+
return new Date(d.getFullYear(), 0, 1);
|
|
24581
|
+
}
|
|
24582
|
+
function daysAgo(n) {
|
|
24583
|
+
const d = /* @__PURE__ */ new Date();
|
|
24584
|
+
d.setDate(d.getDate() - n);
|
|
24585
|
+
return d;
|
|
24586
|
+
}
|
|
24587
|
+
var DEFAULT_PRESETS, DateRangePicker;
|
|
24588
|
+
var init_DateRangePicker = __esm({
|
|
24589
|
+
"components/molecules/DateRangePicker.tsx"() {
|
|
24590
|
+
"use client";
|
|
24591
|
+
init_cn();
|
|
24592
|
+
init_Button();
|
|
24593
|
+
init_Input();
|
|
24594
|
+
init_Stack();
|
|
24595
|
+
init_Typography();
|
|
24596
|
+
init_useEventBus();
|
|
24597
|
+
DEFAULT_PRESETS = [
|
|
24598
|
+
{
|
|
24599
|
+
label: "Last 7 days",
|
|
24600
|
+
value: "7d",
|
|
24601
|
+
range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24602
|
+
},
|
|
24603
|
+
{
|
|
24604
|
+
label: "Last 30 days",
|
|
24605
|
+
value: "30d",
|
|
24606
|
+
range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24607
|
+
},
|
|
24608
|
+
{
|
|
24609
|
+
label: "This Month",
|
|
24610
|
+
value: "month",
|
|
24611
|
+
range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24612
|
+
},
|
|
24613
|
+
{
|
|
24614
|
+
label: "This Quarter",
|
|
24615
|
+
value: "quarter",
|
|
24616
|
+
range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24617
|
+
},
|
|
24618
|
+
{
|
|
24619
|
+
label: "YTD",
|
|
24620
|
+
value: "ytd",
|
|
24621
|
+
range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24622
|
+
}
|
|
24623
|
+
];
|
|
24624
|
+
DateRangePicker = ({
|
|
24625
|
+
from: fromProp,
|
|
24626
|
+
to: toProp,
|
|
24627
|
+
event,
|
|
24628
|
+
onChange,
|
|
24629
|
+
presets = DEFAULT_PRESETS,
|
|
24630
|
+
fromLabel = "From",
|
|
24631
|
+
toLabel = "To",
|
|
24632
|
+
className
|
|
24633
|
+
}) => {
|
|
24634
|
+
const eventBus = useEventBus();
|
|
24635
|
+
const [from, setFrom] = useState(fromProp ?? "");
|
|
24636
|
+
const [to, setTo] = useState(toProp ?? "");
|
|
24637
|
+
const [activePreset, setActivePreset] = useState(null);
|
|
24638
|
+
const emit = useCallback(
|
|
24639
|
+
(range) => {
|
|
24640
|
+
onChange?.(range);
|
|
24641
|
+
if (event) eventBus.emit(`UI:${event}`, range);
|
|
24642
|
+
},
|
|
24643
|
+
[onChange, event, eventBus]
|
|
24644
|
+
);
|
|
24645
|
+
const handleFromChange = useCallback(
|
|
24646
|
+
(next) => {
|
|
24647
|
+
setFrom(next);
|
|
24648
|
+
setActivePreset(null);
|
|
24649
|
+
emit({ from: next, to });
|
|
24650
|
+
},
|
|
24651
|
+
[to, emit]
|
|
24652
|
+
);
|
|
24653
|
+
const handleToChange = useCallback(
|
|
24654
|
+
(next) => {
|
|
24655
|
+
setTo(next);
|
|
24656
|
+
setActivePreset(null);
|
|
24657
|
+
emit({ from, to: next });
|
|
24658
|
+
},
|
|
24659
|
+
[from, emit]
|
|
24660
|
+
);
|
|
24661
|
+
const handlePreset = useCallback(
|
|
24662
|
+
(preset) => {
|
|
24663
|
+
const range = preset.range();
|
|
24664
|
+
setFrom(range.from);
|
|
24665
|
+
setTo(range.to);
|
|
24666
|
+
setActivePreset(preset.value);
|
|
24667
|
+
emit(range);
|
|
24668
|
+
},
|
|
24669
|
+
[emit]
|
|
24670
|
+
);
|
|
24671
|
+
const presetButtons = useMemo(
|
|
24672
|
+
() => presets.map((preset) => /* @__PURE__ */ jsx(
|
|
24673
|
+
Button,
|
|
24674
|
+
{
|
|
24675
|
+
variant: activePreset === preset.value ? "primary" : "ghost",
|
|
24676
|
+
size: "sm",
|
|
24677
|
+
onClick: () => handlePreset(preset),
|
|
24678
|
+
children: preset.label
|
|
24679
|
+
},
|
|
24680
|
+
preset.value
|
|
24681
|
+
)),
|
|
24682
|
+
[presets, activePreset, handlePreset]
|
|
24683
|
+
);
|
|
24684
|
+
return /* @__PURE__ */ jsxs(VStack, { gap: "sm", className: cn(className), children: [
|
|
24685
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "md", align: "end", children: [
|
|
24686
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
24687
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: fromLabel }),
|
|
24688
|
+
/* @__PURE__ */ jsx(
|
|
24689
|
+
Input,
|
|
24690
|
+
{
|
|
24691
|
+
type: "date",
|
|
24692
|
+
value: from,
|
|
24693
|
+
onChange: (e) => handleFromChange(e.target.value)
|
|
24694
|
+
}
|
|
24695
|
+
)
|
|
24696
|
+
] }),
|
|
24697
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "xs", children: [
|
|
24698
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: toLabel }),
|
|
24699
|
+
/* @__PURE__ */ jsx(
|
|
24700
|
+
Input,
|
|
24701
|
+
{
|
|
24702
|
+
type: "date",
|
|
24703
|
+
value: to,
|
|
24704
|
+
onChange: (e) => handleToChange(e.target.value)
|
|
24705
|
+
}
|
|
24706
|
+
)
|
|
24707
|
+
] })
|
|
24708
|
+
] }),
|
|
24709
|
+
presets.length > 0 && /* @__PURE__ */ jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
|
|
24710
|
+
] });
|
|
24711
|
+
};
|
|
24712
|
+
DateRangePicker.displayName = "DateRangePicker";
|
|
24713
|
+
}
|
|
24714
|
+
});
|
|
24113
24715
|
var DEFAULT_OPTIONS, DateRangeSelector;
|
|
24114
24716
|
var init_DateRangeSelector = __esm({
|
|
24115
24717
|
"components/molecules/DateRangeSelector.tsx"() {
|
|
@@ -27081,7 +27683,9 @@ var init_StatDisplay = __esm({
|
|
|
27081
27683
|
init_Typography();
|
|
27082
27684
|
init_Box();
|
|
27083
27685
|
init_Stack();
|
|
27686
|
+
init_Sparkline();
|
|
27084
27687
|
init_Icon();
|
|
27688
|
+
init_useEventBus();
|
|
27085
27689
|
variantColor = {
|
|
27086
27690
|
default: "text-foreground",
|
|
27087
27691
|
primary: "text-primary",
|
|
@@ -27096,6 +27700,10 @@ var init_StatDisplay = __esm({
|
|
|
27096
27700
|
max,
|
|
27097
27701
|
target,
|
|
27098
27702
|
trend,
|
|
27703
|
+
trendPolarity = "higher-is-better",
|
|
27704
|
+
trendFormat = "absolute",
|
|
27705
|
+
sparklineData,
|
|
27706
|
+
clickEvent,
|
|
27099
27707
|
prefix,
|
|
27100
27708
|
suffix,
|
|
27101
27709
|
icon: iconProp,
|
|
@@ -27109,6 +27717,10 @@ var init_StatDisplay = __esm({
|
|
|
27109
27717
|
isLoading = false,
|
|
27110
27718
|
error = null
|
|
27111
27719
|
}) => {
|
|
27720
|
+
const eventBus = useEventBus();
|
|
27721
|
+
const handleClick = useCallback(() => {
|
|
27722
|
+
if (clickEvent) eventBus.emit(`UI:${clickEvent}`, { metricLabel: label });
|
|
27723
|
+
}, [clickEvent, eventBus, label]);
|
|
27112
27724
|
const ResolvedIcon = typeof iconProp === "string" ? resolveIcon(iconProp) : null;
|
|
27113
27725
|
const iconSizes3 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
|
|
27114
27726
|
const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
|
|
@@ -27119,7 +27731,10 @@ var init_StatDisplay = __esm({
|
|
|
27119
27731
|
const targetPct = showTarget ? Math.max(0, Math.min(100, numericValue / target * 100)) : 0;
|
|
27120
27732
|
const showTrend = typeof trend === "number" && trend !== 0 && Number.isFinite(trend);
|
|
27121
27733
|
const trendUp = showTrend && trend > 0;
|
|
27122
|
-
const
|
|
27734
|
+
const trendIsGood = trendPolarity === "lower-is-better" ? !trendUp : trendUp;
|
|
27735
|
+
const trendMagnitude = Math.abs(trend);
|
|
27736
|
+
const trendSuffix = trendFormat === "percent" ? "%" : "";
|
|
27737
|
+
const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${trendMagnitude}${trendSuffix}` : "";
|
|
27123
27738
|
if (error) {
|
|
27124
27739
|
return /* @__PURE__ */ jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsx(Typography, { variant: "small", color: "error", children: error.message }) });
|
|
27125
27740
|
}
|
|
@@ -27130,38 +27745,57 @@ var init_StatDisplay = __esm({
|
|
|
27130
27745
|
] }) });
|
|
27131
27746
|
}
|
|
27132
27747
|
if (compact) {
|
|
27133
|
-
return /* @__PURE__ */ jsxs(
|
|
27134
|
-
|
|
27135
|
-
|
|
27136
|
-
|
|
27137
|
-
|
|
27138
|
-
|
|
27139
|
-
|
|
27748
|
+
return /* @__PURE__ */ jsxs(
|
|
27749
|
+
HStack,
|
|
27750
|
+
{
|
|
27751
|
+
gap: "sm",
|
|
27752
|
+
className: cn("items-center", clickEvent && "cursor-pointer hover:opacity-80", className),
|
|
27753
|
+
onClick: clickEvent ? handleClick : void 0,
|
|
27754
|
+
children: [
|
|
27755
|
+
ResolvedIcon && /* @__PURE__ */ jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
|
|
27756
|
+
typeof iconProp !== "string" && iconProp,
|
|
27757
|
+
/* @__PURE__ */ jsx(Typography, { variant: "caption", color: "secondary", children: label }),
|
|
27758
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
|
|
27759
|
+
showTrend && /* @__PURE__ */ jsx(Typography, { variant: "caption", className: cn("font-semibold", trendIsGood ? "text-success" : "text-error"), children: trendLabel }),
|
|
27760
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto", width: 60, height: 20 })
|
|
27761
|
+
]
|
|
27762
|
+
}
|
|
27763
|
+
);
|
|
27140
27764
|
}
|
|
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
|
-
|
|
27765
|
+
return /* @__PURE__ */ jsx(
|
|
27766
|
+
Card,
|
|
27767
|
+
{
|
|
27768
|
+
className: cn(padSizes[size], clickEvent && "cursor-pointer hover:shadow-md transition-shadow", className),
|
|
27769
|
+
onClick: clickEvent ? handleClick : void 0,
|
|
27770
|
+
children: /* @__PURE__ */ jsxs(HStack, { align: "start", justify: "between", children: [
|
|
27771
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
|
|
27772
|
+
/* @__PURE__ */ jsx(Typography, { variant: "overline", color: "secondary", children: label }),
|
|
27773
|
+
/* @__PURE__ */ jsxs(HStack, { gap: "sm", align: "end", children: [
|
|
27774
|
+
/* @__PURE__ */ jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
|
|
27775
|
+
showTrend && /* @__PURE__ */ jsx(
|
|
27776
|
+
Typography,
|
|
27777
|
+
{
|
|
27778
|
+
variant: "caption",
|
|
27779
|
+
className: cn("font-semibold pb-1", trendIsGood ? "text-success" : "text-error"),
|
|
27780
|
+
children: trendLabel
|
|
27781
|
+
}
|
|
27782
|
+
)
|
|
27783
|
+
] }),
|
|
27784
|
+
showTarget && /* @__PURE__ */ jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
27785
|
+
Box,
|
|
27786
|
+
{
|
|
27787
|
+
className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
|
|
27788
|
+
style: { width: `${targetPct}%` }
|
|
27789
|
+
}
|
|
27790
|
+
) })
|
|
27791
|
+
] }),
|
|
27792
|
+
/* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
|
|
27793
|
+
(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 }),
|
|
27794
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto" })
|
|
27795
|
+
] })
|
|
27796
|
+
] })
|
|
27797
|
+
}
|
|
27798
|
+
);
|
|
27165
27799
|
};
|
|
27166
27800
|
StatDisplay.displayName = "StatDisplay";
|
|
27167
27801
|
}
|
|
@@ -41505,6 +42139,7 @@ var init_StatCard = __esm({
|
|
|
41505
42139
|
init_Box();
|
|
41506
42140
|
init_Stack();
|
|
41507
42141
|
init_Button();
|
|
42142
|
+
init_Sparkline();
|
|
41508
42143
|
init_useEventBus();
|
|
41509
42144
|
init_useTranslate();
|
|
41510
42145
|
init_Icon();
|
|
@@ -41674,32 +42309,7 @@ var init_StatCard = __esm({
|
|
|
41674
42309
|
] }),
|
|
41675
42310
|
/* @__PURE__ */ jsxs(VStack, { gap: "xs", align: "end", children: [
|
|
41676
42311
|
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
|
-
})()
|
|
42312
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsx(Sparkline, { data: sparklineData, color: "auto" })
|
|
41703
42313
|
] })
|
|
41704
42314
|
] }),
|
|
41705
42315
|
action && /* @__PURE__ */ jsxs(
|
|
@@ -43597,6 +44207,7 @@ var init_component_registry_generated = __esm({
|
|
|
43597
44207
|
init_DataGrid();
|
|
43598
44208
|
init_DataList();
|
|
43599
44209
|
init_DataTable();
|
|
44210
|
+
init_DateRangePicker();
|
|
43600
44211
|
init_DateRangeSelector();
|
|
43601
44212
|
init_DayCell();
|
|
43602
44213
|
init_DebuggerBoard();
|
|
@@ -43729,6 +44340,7 @@ var init_component_registry_generated = __esm({
|
|
|
43729
44340
|
init_Skeleton();
|
|
43730
44341
|
init_SocialProof();
|
|
43731
44342
|
init_SortableList();
|
|
44343
|
+
init_Sparkline();
|
|
43732
44344
|
init_Split();
|
|
43733
44345
|
init_SplitPane();
|
|
43734
44346
|
init_SplitSection();
|
|
@@ -43877,6 +44489,7 @@ var init_component_registry_generated = __esm({
|
|
|
43877
44489
|
"DataGrid": DataGrid,
|
|
43878
44490
|
"DataList": DataList,
|
|
43879
44491
|
"DataTable": DataTable,
|
|
44492
|
+
"DateRangePicker": DateRangePicker,
|
|
43880
44493
|
"DateRangeSelector": DateRangeSelector,
|
|
43881
44494
|
"DayCell": DayCell,
|
|
43882
44495
|
"DebuggerBoard": DebuggerBoard,
|
|
@@ -44038,6 +44651,7 @@ var init_component_registry_generated = __esm({
|
|
|
44038
44651
|
"SortableList": SortableList,
|
|
44039
44652
|
"Spacer": SpacerPattern,
|
|
44040
44653
|
"SpacerPattern": SpacerPattern,
|
|
44654
|
+
"Sparkline": Sparkline,
|
|
44041
44655
|
"Spinner": SpinnerPattern,
|
|
44042
44656
|
"SpinnerPattern": SpinnerPattern,
|
|
44043
44657
|
"Split": Split,
|