@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.cjs
CHANGED
|
@@ -3933,6 +3933,67 @@ var init_Radio = __esm({
|
|
|
3933
3933
|
Radio.displayName = "Radio";
|
|
3934
3934
|
}
|
|
3935
3935
|
});
|
|
3936
|
+
var COLOR_VAR, Sparkline;
|
|
3937
|
+
var init_Sparkline = __esm({
|
|
3938
|
+
"components/atoms/Sparkline.tsx"() {
|
|
3939
|
+
init_cn();
|
|
3940
|
+
COLOR_VAR = {
|
|
3941
|
+
primary: "var(--color-primary)",
|
|
3942
|
+
success: "var(--color-success)",
|
|
3943
|
+
warning: "var(--color-warning)",
|
|
3944
|
+
error: "var(--color-error)",
|
|
3945
|
+
info: "var(--color-info)",
|
|
3946
|
+
muted: "var(--color-muted-foreground)"
|
|
3947
|
+
};
|
|
3948
|
+
Sparkline = ({
|
|
3949
|
+
data,
|
|
3950
|
+
color = "auto",
|
|
3951
|
+
width = 80,
|
|
3952
|
+
height = 32,
|
|
3953
|
+
strokeWidth = 2,
|
|
3954
|
+
fill = false,
|
|
3955
|
+
className
|
|
3956
|
+
}) => {
|
|
3957
|
+
if (data.length < 2) return null;
|
|
3958
|
+
const pad = 2;
|
|
3959
|
+
const min = Math.min(...data);
|
|
3960
|
+
const max = Math.max(...data);
|
|
3961
|
+
const range = max - min || 1;
|
|
3962
|
+
const points = data.map((v, i) => {
|
|
3963
|
+
const x = pad + i / (data.length - 1) * (width - pad * 2);
|
|
3964
|
+
const y = pad + (1 - (v - min) / range) * (height - pad * 2);
|
|
3965
|
+
return `${x},${y}`;
|
|
3966
|
+
}).join(" ");
|
|
3967
|
+
const resolvedColor = color === "auto" ? data[data.length - 1] >= data[0] ? COLOR_VAR.success : COLOR_VAR.error : COLOR_VAR[color];
|
|
3968
|
+
const areaPath = fill ? `M ${pad},${height - pad} L ${points.split(" ").join(" L ")} L ${width - pad},${height - pad} Z` : null;
|
|
3969
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3970
|
+
"svg",
|
|
3971
|
+
{
|
|
3972
|
+
width,
|
|
3973
|
+
height,
|
|
3974
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
3975
|
+
className: cn("flex-shrink-0", className),
|
|
3976
|
+
"aria-hidden": "true",
|
|
3977
|
+
children: [
|
|
3978
|
+
areaPath && /* @__PURE__ */ jsxRuntime.jsx("path", { d: areaPath, fill: resolvedColor, opacity: 0.15 }),
|
|
3979
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3980
|
+
"polyline",
|
|
3981
|
+
{
|
|
3982
|
+
fill: "none",
|
|
3983
|
+
stroke: resolvedColor,
|
|
3984
|
+
strokeWidth,
|
|
3985
|
+
strokeLinecap: "round",
|
|
3986
|
+
strokeLinejoin: "round",
|
|
3987
|
+
points
|
|
3988
|
+
}
|
|
3989
|
+
)
|
|
3990
|
+
]
|
|
3991
|
+
}
|
|
3992
|
+
);
|
|
3993
|
+
};
|
|
3994
|
+
Sparkline.displayName = "Sparkline";
|
|
3995
|
+
}
|
|
3996
|
+
});
|
|
3936
3997
|
var Switch;
|
|
3937
3998
|
var init_Switch = __esm({
|
|
3938
3999
|
"components/atoms/Switch.tsx"() {
|
|
@@ -9210,7 +9271,7 @@ var init_MapView = __esm({
|
|
|
9210
9271
|
shadowSize: [41, 41]
|
|
9211
9272
|
});
|
|
9212
9273
|
L.Marker.prototype.options.icon = defaultIcon;
|
|
9213
|
-
const { useEffect: useEffect68, useRef: useRef65, useCallback:
|
|
9274
|
+
const { useEffect: useEffect68, useRef: useRef65, useCallback: useCallback112, useState: useState99 } = React80__namespace.default;
|
|
9214
9275
|
const { Typography: Typography2 } = await Promise.resolve().then(() => (init_Typography(), Typography_exports));
|
|
9215
9276
|
const { useEventBus: useEventBus2 } = await Promise.resolve().then(() => (init_useEventBus(), useEventBus_exports));
|
|
9216
9277
|
function MapUpdater({ centerLat, centerLng, zoom }) {
|
|
@@ -9255,8 +9316,8 @@ var init_MapView = __esm({
|
|
|
9255
9316
|
showAttribution = true
|
|
9256
9317
|
}) {
|
|
9257
9318
|
const eventBus = useEventBus2();
|
|
9258
|
-
const [clickedPosition, setClickedPosition] =
|
|
9259
|
-
const handleMapClick =
|
|
9319
|
+
const [clickedPosition, setClickedPosition] = useState99(null);
|
|
9320
|
+
const handleMapClick = useCallback112((lat, lng) => {
|
|
9260
9321
|
if (showClickedPin) {
|
|
9261
9322
|
setClickedPosition({ lat, lng });
|
|
9262
9323
|
}
|
|
@@ -9265,7 +9326,7 @@ var init_MapView = __esm({
|
|
|
9265
9326
|
eventBus.emit(`UI:${mapClickEvent}`, { latitude: lat, longitude: lng });
|
|
9266
9327
|
}
|
|
9267
9328
|
}, [onMapClick, mapClickEvent, eventBus, showClickedPin]);
|
|
9268
|
-
const handleMarkerClick =
|
|
9329
|
+
const handleMarkerClick = useCallback112((marker) => {
|
|
9269
9330
|
onMarkerClick?.(marker);
|
|
9270
9331
|
if (markerClickEvent) {
|
|
9271
9332
|
eventBus.emit(`UI:${markerClickEvent}`, { ...marker });
|
|
@@ -19060,7 +19121,7 @@ var init_CastleTemplate = __esm({
|
|
|
19060
19121
|
CastleTemplate.displayName = "CastleTemplate";
|
|
19061
19122
|
}
|
|
19062
19123
|
});
|
|
19063
|
-
var CHART_COLORS, BarChart, PieChart, LineChart, Chart;
|
|
19124
|
+
var CHART_COLORS, seriesColor, monthFormatter, formatTimeLabel, BarChart, PieChart, LineChart, ScatterChart, Chart;
|
|
19064
19125
|
var init_Chart = __esm({
|
|
19065
19126
|
"components/organisms/Chart.tsx"() {
|
|
19066
19127
|
"use client";
|
|
@@ -19080,38 +19141,159 @@ var init_Chart = __esm({
|
|
|
19080
19141
|
"var(--color-info)",
|
|
19081
19142
|
"var(--color-accent)"
|
|
19082
19143
|
];
|
|
19083
|
-
|
|
19084
|
-
|
|
19085
|
-
|
|
19086
|
-
|
|
19087
|
-
|
|
19088
|
-
|
|
19089
|
-
|
|
19090
|
-
|
|
19091
|
-
|
|
19092
|
-
|
|
19093
|
-
|
|
19094
|
-
|
|
19095
|
-
|
|
19096
|
-
|
|
19097
|
-
|
|
19098
|
-
|
|
19099
|
-
|
|
19144
|
+
seriesColor = (series, idx) => series.color ?? CHART_COLORS[idx % CHART_COLORS.length];
|
|
19145
|
+
monthFormatter = new Intl.DateTimeFormat(void 0, {
|
|
19146
|
+
month: "short",
|
|
19147
|
+
year: "2-digit"
|
|
19148
|
+
});
|
|
19149
|
+
formatTimeLabel = (raw) => {
|
|
19150
|
+
const parsed = new Date(raw);
|
|
19151
|
+
if (Number.isNaN(parsed.getTime())) return raw;
|
|
19152
|
+
return monthFormatter.format(parsed);
|
|
19153
|
+
};
|
|
19154
|
+
BarChart = ({ series, height, showValues, stack, timeAxis, histogram = false, onPointClick }) => {
|
|
19155
|
+
const categories = React80.useMemo(() => {
|
|
19156
|
+
const set = [];
|
|
19157
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19158
|
+
for (const s of series) {
|
|
19159
|
+
for (const p2 of s.data) {
|
|
19160
|
+
if (!seen.has(p2.label)) {
|
|
19161
|
+
seen.add(p2.label);
|
|
19162
|
+
set.push(p2.label);
|
|
19100
19163
|
}
|
|
19101
|
-
|
|
19102
|
-
|
|
19103
|
-
|
|
19104
|
-
|
|
19105
|
-
|
|
19106
|
-
|
|
19107
|
-
|
|
19108
|
-
|
|
19164
|
+
}
|
|
19165
|
+
}
|
|
19166
|
+
return set;
|
|
19167
|
+
}, [series]);
|
|
19168
|
+
const valueAt = React80.useCallback(
|
|
19169
|
+
(s, label) => {
|
|
19170
|
+
const p2 = s.data.find((d) => d.label === label);
|
|
19171
|
+
return p2 ? p2.value : 0;
|
|
19172
|
+
},
|
|
19173
|
+
[]
|
|
19174
|
+
);
|
|
19175
|
+
const columnTotals = React80.useMemo(() => {
|
|
19176
|
+
if (stack === "none") return null;
|
|
19177
|
+
return categories.map(
|
|
19178
|
+
(label) => series.reduce((sum, s) => sum + valueAt(s, label), 0)
|
|
19179
|
+
);
|
|
19180
|
+
}, [categories, series, stack, valueAt]);
|
|
19181
|
+
const maxValue = React80.useMemo(() => {
|
|
19182
|
+
if (stack === "normalize") return 100;
|
|
19183
|
+
if (stack === "stack" && columnTotals) {
|
|
19184
|
+
return Math.max(...columnTotals, 1);
|
|
19185
|
+
}
|
|
19186
|
+
let m = 1;
|
|
19187
|
+
for (const s of series) {
|
|
19188
|
+
for (const p2 of s.data) if (p2.value > m) m = p2.value;
|
|
19189
|
+
}
|
|
19190
|
+
return m;
|
|
19191
|
+
}, [series, stack, columnTotals]);
|
|
19192
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19193
|
+
HStack,
|
|
19194
|
+
{
|
|
19195
|
+
gap: histogram ? "none" : "xs",
|
|
19196
|
+
align: "end",
|
|
19197
|
+
className: "w-full",
|
|
19198
|
+
style: { height },
|
|
19199
|
+
children: categories.map((label, catIdx) => {
|
|
19200
|
+
const displayLabel = timeAxis ? formatTimeLabel(label) : label;
|
|
19201
|
+
if (stack === "none") {
|
|
19202
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
19203
|
+
VStack,
|
|
19204
|
+
{
|
|
19205
|
+
gap: "xs",
|
|
19206
|
+
align: "center",
|
|
19207
|
+
flex: true,
|
|
19208
|
+
className: "min-w-0",
|
|
19209
|
+
children: [
|
|
19210
|
+
/* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: histogram ? "none" : "xs", align: "end", className: "w-full", style: { height: "100%" }, children: series.map((s, sIdx) => {
|
|
19211
|
+
const value = valueAt(s, label);
|
|
19212
|
+
const barHeight = value / maxValue * 100;
|
|
19213
|
+
const color = seriesColor(s, sIdx);
|
|
19214
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19215
|
+
Box,
|
|
19216
|
+
{
|
|
19217
|
+
className: cn(
|
|
19218
|
+
"rounded-t-sm transition-all duration-500 ease-out min-h-[4px] cursor-pointer hover:opacity-80",
|
|
19219
|
+
histogram ? "flex-1 mx-0" : "flex-1"
|
|
19220
|
+
),
|
|
19221
|
+
style: {
|
|
19222
|
+
height: `${barHeight}%`,
|
|
19223
|
+
backgroundColor: color
|
|
19224
|
+
},
|
|
19225
|
+
onClick: () => onPointClick?.(
|
|
19226
|
+
{ label, value, color },
|
|
19227
|
+
s.name
|
|
19228
|
+
),
|
|
19229
|
+
title: `${s.name}: ${value}`
|
|
19230
|
+
},
|
|
19231
|
+
s.name
|
|
19232
|
+
);
|
|
19233
|
+
}) }),
|
|
19234
|
+
showValues && series.length === 1 && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", className: "tabular-nums", children: valueAt(series[0], label) }),
|
|
19235
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19236
|
+
Typography,
|
|
19237
|
+
{
|
|
19238
|
+
variant: "caption",
|
|
19239
|
+
color: "secondary",
|
|
19240
|
+
className: "truncate w-full text-center",
|
|
19241
|
+
children: displayLabel
|
|
19242
|
+
}
|
|
19243
|
+
)
|
|
19244
|
+
]
|
|
19245
|
+
},
|
|
19246
|
+
label
|
|
19247
|
+
);
|
|
19109
19248
|
}
|
|
19110
|
-
|
|
19111
|
-
|
|
19112
|
-
|
|
19249
|
+
const total = columnTotals?.[catIdx] ?? 1;
|
|
19250
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
19251
|
+
VStack,
|
|
19252
|
+
{
|
|
19253
|
+
gap: "xs",
|
|
19254
|
+
align: "center",
|
|
19255
|
+
flex: true,
|
|
19256
|
+
className: "min-w-0",
|
|
19257
|
+
children: [
|
|
19258
|
+
/* @__PURE__ */ jsxRuntime.jsx(VStack, { gap: "none", className: "w-full", style: { height: "100%" }, justify: "end", children: series.map((s, sIdx) => {
|
|
19259
|
+
const value = valueAt(s, label);
|
|
19260
|
+
const ratio = stack === "normalize" ? total === 0 ? 0 : value / total * 100 : value / maxValue * 100;
|
|
19261
|
+
const color = seriesColor(s, sIdx);
|
|
19262
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19263
|
+
Box,
|
|
19264
|
+
{
|
|
19265
|
+
className: "w-full transition-all duration-500 ease-out cursor-pointer hover:opacity-80",
|
|
19266
|
+
style: {
|
|
19267
|
+
height: `${ratio}%`,
|
|
19268
|
+
backgroundColor: color
|
|
19269
|
+
},
|
|
19270
|
+
onClick: () => onPointClick?.(
|
|
19271
|
+
{ label, value, color },
|
|
19272
|
+
s.name
|
|
19273
|
+
),
|
|
19274
|
+
title: `${s.name}: ${value}`
|
|
19275
|
+
},
|
|
19276
|
+
s.name
|
|
19277
|
+
);
|
|
19278
|
+
}) }),
|
|
19279
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19280
|
+
Typography,
|
|
19281
|
+
{
|
|
19282
|
+
variant: "caption",
|
|
19283
|
+
color: "secondary",
|
|
19284
|
+
className: "truncate w-full text-center",
|
|
19285
|
+
children: displayLabel
|
|
19286
|
+
}
|
|
19287
|
+
)
|
|
19288
|
+
]
|
|
19289
|
+
},
|
|
19290
|
+
label
|
|
19291
|
+
);
|
|
19292
|
+
})
|
|
19293
|
+
}
|
|
19294
|
+
);
|
|
19113
19295
|
};
|
|
19114
|
-
PieChart = ({ data, height, showValues, donut = false }) => {
|
|
19296
|
+
PieChart = ({ data, height, showValues, donut = false, onPointClick }) => {
|
|
19115
19297
|
const total = data.reduce((sum, d) => sum + d.value, 0);
|
|
19116
19298
|
const size = Math.min(height, 200);
|
|
19117
19299
|
const radius = size / 2 - 8;
|
|
@@ -19157,7 +19339,11 @@ var init_Chart = __esm({
|
|
|
19157
19339
|
fill: seg.color,
|
|
19158
19340
|
stroke: "var(--color-card)",
|
|
19159
19341
|
strokeWidth: "2",
|
|
19160
|
-
className: "transition-opacity duration-200 hover:opacity-80"
|
|
19342
|
+
className: "transition-opacity duration-200 hover:opacity-80 cursor-pointer",
|
|
19343
|
+
onClick: () => onPointClick?.(
|
|
19344
|
+
{ label: seg.label, value: seg.value, color: seg.color },
|
|
19345
|
+
"default"
|
|
19346
|
+
)
|
|
19161
19347
|
},
|
|
19162
19348
|
idx
|
|
19163
19349
|
)),
|
|
@@ -19192,56 +19378,243 @@ var init_Chart = __esm({
|
|
|
19192
19378
|
] }, idx)) })
|
|
19193
19379
|
] });
|
|
19194
19380
|
};
|
|
19195
|
-
LineChart = ({
|
|
19196
|
-
const maxValue = Math.max(...data.map((d) => d.value), 1);
|
|
19381
|
+
LineChart = ({ series, height, showValues, fill = false, timeAxis, onPointClick }) => {
|
|
19197
19382
|
const width = 400;
|
|
19198
19383
|
const padding = { top: 20, right: 20, bottom: 30, left: 40 };
|
|
19199
19384
|
const chartWidth = width - padding.left - padding.right;
|
|
19200
19385
|
const chartHeight = height - padding.top - padding.bottom;
|
|
19201
|
-
const
|
|
19202
|
-
|
|
19203
|
-
|
|
19204
|
-
|
|
19205
|
-
|
|
19206
|
-
|
|
19207
|
-
|
|
19208
|
-
|
|
19209
|
-
const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
|
|
19210
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "100%", height, viewBox: `0 0 ${width} ${height}`, preserveAspectRatio: "xMidYMid meet", children: [
|
|
19211
|
-
[0, 0.25, 0.5, 0.75, 1].map((frac) => {
|
|
19212
|
-
const y = padding.top + chartHeight * (1 - frac);
|
|
19213
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19214
|
-
"line",
|
|
19215
|
-
{
|
|
19216
|
-
x1: padding.left,
|
|
19217
|
-
y1: y,
|
|
19218
|
-
x2: width - padding.right,
|
|
19219
|
-
y2: y,
|
|
19220
|
-
stroke: "var(--color-border)",
|
|
19221
|
-
strokeDasharray: "4 4",
|
|
19222
|
-
opacity: 0.5
|
|
19223
|
-
},
|
|
19224
|
-
frac
|
|
19225
|
-
);
|
|
19226
|
-
}),
|
|
19227
|
-
fill && /* @__PURE__ */ jsxRuntime.jsx("path", { d: areaPath, fill: "var(--color-primary)", opacity: 0.1 }),
|
|
19228
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: linePath, fill: "none", stroke: "var(--color-primary)", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
19229
|
-
points.map((p2, idx) => /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
|
|
19230
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: p2.x, cy: p2.y, r: "4", fill: "var(--color-card)", stroke: "var(--color-primary)", strokeWidth: "2" }),
|
|
19231
|
-
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 }),
|
|
19232
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19233
|
-
"text",
|
|
19234
|
-
{
|
|
19235
|
-
x: p2.x,
|
|
19236
|
-
y: height - 8,
|
|
19237
|
-
textAnchor: "middle",
|
|
19238
|
-
fill: "var(--color-muted-foreground)",
|
|
19239
|
-
fontSize: "9",
|
|
19240
|
-
children: p2.label
|
|
19386
|
+
const labels = React80.useMemo(() => {
|
|
19387
|
+
const seen = /* @__PURE__ */ new Set();
|
|
19388
|
+
const out = [];
|
|
19389
|
+
for (const s of series) {
|
|
19390
|
+
for (const p2 of s.data) {
|
|
19391
|
+
if (!seen.has(p2.label)) {
|
|
19392
|
+
seen.add(p2.label);
|
|
19393
|
+
out.push(p2.label);
|
|
19241
19394
|
}
|
|
19242
|
-
|
|
19243
|
-
|
|
19244
|
-
|
|
19395
|
+
}
|
|
19396
|
+
}
|
|
19397
|
+
return out;
|
|
19398
|
+
}, [series]);
|
|
19399
|
+
const maxValue = React80.useMemo(() => {
|
|
19400
|
+
let m = 1;
|
|
19401
|
+
for (const s of series) {
|
|
19402
|
+
for (const p2 of s.data) if (p2.value > m) m = p2.value;
|
|
19403
|
+
}
|
|
19404
|
+
return m;
|
|
19405
|
+
}, [series]);
|
|
19406
|
+
const xFor = React80.useCallback(
|
|
19407
|
+
(idx) => padding.left + idx / Math.max(labels.length - 1, 1) * chartWidth,
|
|
19408
|
+
[labels.length, chartWidth, padding.left]
|
|
19409
|
+
);
|
|
19410
|
+
const yFor = React80.useCallback(
|
|
19411
|
+
(value) => padding.top + chartHeight - value / maxValue * chartHeight,
|
|
19412
|
+
[maxValue, chartHeight, padding.top]
|
|
19413
|
+
);
|
|
19414
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
19415
|
+
"svg",
|
|
19416
|
+
{
|
|
19417
|
+
width: "100%",
|
|
19418
|
+
height,
|
|
19419
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
19420
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
19421
|
+
children: [
|
|
19422
|
+
[0, 0.25, 0.5, 0.75, 1].map((frac) => {
|
|
19423
|
+
const y = padding.top + chartHeight * (1 - frac);
|
|
19424
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19425
|
+
"line",
|
|
19426
|
+
{
|
|
19427
|
+
x1: padding.left,
|
|
19428
|
+
y1: y,
|
|
19429
|
+
x2: width - padding.right,
|
|
19430
|
+
y2: y,
|
|
19431
|
+
stroke: "var(--color-border)",
|
|
19432
|
+
strokeDasharray: "4 4",
|
|
19433
|
+
opacity: 0.5
|
|
19434
|
+
},
|
|
19435
|
+
frac
|
|
19436
|
+
);
|
|
19437
|
+
}),
|
|
19438
|
+
series.map((s, sIdx) => {
|
|
19439
|
+
const color = seriesColor(s, sIdx);
|
|
19440
|
+
const points = labels.map((label, idx) => {
|
|
19441
|
+
const point = s.data.find((d) => d.label === label);
|
|
19442
|
+
return {
|
|
19443
|
+
x: xFor(idx),
|
|
19444
|
+
y: yFor(point ? point.value : 0),
|
|
19445
|
+
value: point ? point.value : 0,
|
|
19446
|
+
label
|
|
19447
|
+
};
|
|
19448
|
+
});
|
|
19449
|
+
const linePath = points.map((p2, i) => `${i === 0 ? "M" : "L"} ${p2.x} ${p2.y}`).join(" ");
|
|
19450
|
+
const areaPath = `${linePath} L ${points[points.length - 1]?.x ?? 0} ${padding.top + chartHeight} L ${padding.left} ${padding.top + chartHeight} Z`;
|
|
19451
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
|
|
19452
|
+
fill && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19453
|
+
"path",
|
|
19454
|
+
{
|
|
19455
|
+
d: areaPath,
|
|
19456
|
+
fill: color,
|
|
19457
|
+
opacity: series.length > 1 ? 0.08 : 0.1
|
|
19458
|
+
}
|
|
19459
|
+
),
|
|
19460
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19461
|
+
"path",
|
|
19462
|
+
{
|
|
19463
|
+
d: linePath,
|
|
19464
|
+
fill: "none",
|
|
19465
|
+
stroke: color,
|
|
19466
|
+
strokeWidth: "2",
|
|
19467
|
+
strokeLinecap: "round",
|
|
19468
|
+
strokeLinejoin: "round",
|
|
19469
|
+
strokeDasharray: s.dashed ? "6 4" : void 0
|
|
19470
|
+
}
|
|
19471
|
+
),
|
|
19472
|
+
points.map((p2, idx) => /* @__PURE__ */ jsxRuntime.jsxs("g", { children: [
|
|
19473
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19474
|
+
"circle",
|
|
19475
|
+
{
|
|
19476
|
+
cx: p2.x,
|
|
19477
|
+
cy: p2.y,
|
|
19478
|
+
r: "4",
|
|
19479
|
+
fill: "var(--color-card)",
|
|
19480
|
+
stroke: color,
|
|
19481
|
+
strokeWidth: "2",
|
|
19482
|
+
className: "cursor-pointer",
|
|
19483
|
+
onClick: () => onPointClick?.(
|
|
19484
|
+
{ label: p2.label, value: p2.value, color },
|
|
19485
|
+
s.name
|
|
19486
|
+
)
|
|
19487
|
+
}
|
|
19488
|
+
),
|
|
19489
|
+
showValues && series.length === 1 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19490
|
+
"text",
|
|
19491
|
+
{
|
|
19492
|
+
x: p2.x,
|
|
19493
|
+
y: p2.y - 10,
|
|
19494
|
+
textAnchor: "middle",
|
|
19495
|
+
fill: "var(--color-foreground)",
|
|
19496
|
+
fontSize: "10",
|
|
19497
|
+
fontWeight: "500",
|
|
19498
|
+
children: p2.value
|
|
19499
|
+
}
|
|
19500
|
+
)
|
|
19501
|
+
] }, idx))
|
|
19502
|
+
] }, s.name);
|
|
19503
|
+
}),
|
|
19504
|
+
labels.map((label, idx) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
19505
|
+
"text",
|
|
19506
|
+
{
|
|
19507
|
+
x: xFor(idx),
|
|
19508
|
+
y: height - 8,
|
|
19509
|
+
textAnchor: "middle",
|
|
19510
|
+
fill: "var(--color-muted-foreground)",
|
|
19511
|
+
fontSize: "9",
|
|
19512
|
+
children: timeAxis ? formatTimeLabel(label) : label
|
|
19513
|
+
},
|
|
19514
|
+
label
|
|
19515
|
+
))
|
|
19516
|
+
]
|
|
19517
|
+
}
|
|
19518
|
+
);
|
|
19519
|
+
};
|
|
19520
|
+
ScatterChart = ({ data, height, onPointClick }) => {
|
|
19521
|
+
const width = 400;
|
|
19522
|
+
const padding = { top: 20, right: 20, bottom: 30, left: 40 };
|
|
19523
|
+
const chartWidth = width - padding.left - padding.right;
|
|
19524
|
+
const chartHeight = height - padding.top - padding.bottom;
|
|
19525
|
+
const { minX, maxX, minY, maxY } = React80.useMemo(() => {
|
|
19526
|
+
if (data.length === 0) {
|
|
19527
|
+
return { minX: 0, maxX: 1, minY: 0, maxY: 1 };
|
|
19528
|
+
}
|
|
19529
|
+
let mnX = data[0].x;
|
|
19530
|
+
let mxX = data[0].x;
|
|
19531
|
+
let mnY = data[0].y;
|
|
19532
|
+
let mxY = data[0].y;
|
|
19533
|
+
for (const p2 of data) {
|
|
19534
|
+
if (p2.x < mnX) mnX = p2.x;
|
|
19535
|
+
if (p2.x > mxX) mxX = p2.x;
|
|
19536
|
+
if (p2.y < mnY) mnY = p2.y;
|
|
19537
|
+
if (p2.y > mxY) mxY = p2.y;
|
|
19538
|
+
}
|
|
19539
|
+
return { minX: mnX, maxX: mxX, minY: mnY, maxY: mxY };
|
|
19540
|
+
}, [data]);
|
|
19541
|
+
const rangeX = maxX - minX || 1;
|
|
19542
|
+
const rangeY = maxY - minY || 1;
|
|
19543
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
19544
|
+
"svg",
|
|
19545
|
+
{
|
|
19546
|
+
width: "100%",
|
|
19547
|
+
height,
|
|
19548
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
19549
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
19550
|
+
children: [
|
|
19551
|
+
[0, 0.25, 0.5, 0.75, 1].map((frac) => {
|
|
19552
|
+
const y = padding.top + chartHeight * (1 - frac);
|
|
19553
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19554
|
+
"line",
|
|
19555
|
+
{
|
|
19556
|
+
x1: padding.left,
|
|
19557
|
+
y1: y,
|
|
19558
|
+
x2: width - padding.right,
|
|
19559
|
+
y2: y,
|
|
19560
|
+
stroke: "var(--color-border)",
|
|
19561
|
+
strokeDasharray: "4 4",
|
|
19562
|
+
opacity: 0.5
|
|
19563
|
+
},
|
|
19564
|
+
frac
|
|
19565
|
+
);
|
|
19566
|
+
}),
|
|
19567
|
+
data.map((p2, idx) => {
|
|
19568
|
+
const cx = padding.left + (p2.x - minX) / rangeX * chartWidth;
|
|
19569
|
+
const cy = padding.top + chartHeight - (p2.y - minY) / rangeY * chartHeight;
|
|
19570
|
+
const r = p2.size ?? 5;
|
|
19571
|
+
const color = p2.color ?? CHART_COLORS[idx % CHART_COLORS.length];
|
|
19572
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
19573
|
+
"circle",
|
|
19574
|
+
{
|
|
19575
|
+
cx,
|
|
19576
|
+
cy,
|
|
19577
|
+
r,
|
|
19578
|
+
fill: color,
|
|
19579
|
+
opacity: 0.7,
|
|
19580
|
+
className: "cursor-pointer hover:opacity-100",
|
|
19581
|
+
onClick: () => onPointClick?.(
|
|
19582
|
+
{
|
|
19583
|
+
label: p2.label ?? `(${p2.x}, ${p2.y})`,
|
|
19584
|
+
value: p2.y,
|
|
19585
|
+
color
|
|
19586
|
+
},
|
|
19587
|
+
"default"
|
|
19588
|
+
),
|
|
19589
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("title", { children: p2.label ?? `(${p2.x}, ${p2.y})` })
|
|
19590
|
+
},
|
|
19591
|
+
idx
|
|
19592
|
+
);
|
|
19593
|
+
}),
|
|
19594
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19595
|
+
"text",
|
|
19596
|
+
{
|
|
19597
|
+
x: padding.left,
|
|
19598
|
+
y: height - 8,
|
|
19599
|
+
fill: "var(--color-muted-foreground)",
|
|
19600
|
+
fontSize: "9",
|
|
19601
|
+
children: minX.toFixed(1)
|
|
19602
|
+
}
|
|
19603
|
+
),
|
|
19604
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19605
|
+
"text",
|
|
19606
|
+
{
|
|
19607
|
+
x: width - padding.right,
|
|
19608
|
+
y: height - 8,
|
|
19609
|
+
textAnchor: "end",
|
|
19610
|
+
fill: "var(--color-muted-foreground)",
|
|
19611
|
+
fontSize: "9",
|
|
19612
|
+
children: maxX.toFixed(1)
|
|
19613
|
+
}
|
|
19614
|
+
)
|
|
19615
|
+
]
|
|
19616
|
+
}
|
|
19617
|
+
);
|
|
19245
19618
|
};
|
|
19246
19619
|
Chart = ({
|
|
19247
19620
|
title,
|
|
@@ -19249,9 +19622,13 @@ var init_Chart = __esm({
|
|
|
19249
19622
|
chartType = "bar",
|
|
19250
19623
|
series,
|
|
19251
19624
|
data: simpleData,
|
|
19625
|
+
scatterData,
|
|
19252
19626
|
height = 200,
|
|
19253
19627
|
showLegend = true,
|
|
19254
19628
|
showValues = false,
|
|
19629
|
+
stack = "none",
|
|
19630
|
+
timeAxis = false,
|
|
19631
|
+
drillEvent,
|
|
19255
19632
|
actions,
|
|
19256
19633
|
entity,
|
|
19257
19634
|
isLoading = false,
|
|
@@ -19268,11 +19645,25 @@ var init_Chart = __esm({
|
|
|
19268
19645
|
},
|
|
19269
19646
|
[eventBus]
|
|
19270
19647
|
);
|
|
19271
|
-
const
|
|
19272
|
-
|
|
19273
|
-
|
|
19648
|
+
const handlePointClick = React80.useCallback(
|
|
19649
|
+
(point, seriesName) => {
|
|
19650
|
+
if (drillEvent) {
|
|
19651
|
+
eventBus.emit(`UI:${drillEvent}`, {
|
|
19652
|
+
label: point.label,
|
|
19653
|
+
value: point.value,
|
|
19654
|
+
seriesLabel: seriesName === "default" ? void 0 : seriesName
|
|
19655
|
+
});
|
|
19656
|
+
}
|
|
19657
|
+
},
|
|
19658
|
+
[drillEvent, eventBus]
|
|
19659
|
+
);
|
|
19660
|
+
const normalizedSeries = React80.useMemo(() => {
|
|
19661
|
+
if (series && series.length > 0) return series;
|
|
19662
|
+
if (simpleData) return [{ name: "default", data: simpleData }];
|
|
19274
19663
|
return [];
|
|
19275
19664
|
}, [simpleData, series]);
|
|
19665
|
+
const firstSeriesData = normalizedSeries[0]?.data ?? [];
|
|
19666
|
+
const hasContent = chartType === "scatter" ? (scatterData?.length ?? 0) > 0 : normalizedSeries.some((s) => s.data.length > 0);
|
|
19276
19667
|
if (isLoading) {
|
|
19277
19668
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingState, { message: "Loading chart...", className });
|
|
19278
19669
|
}
|
|
@@ -19286,7 +19677,7 @@ var init_Chart = __esm({
|
|
|
19286
19677
|
}
|
|
19287
19678
|
);
|
|
19288
19679
|
}
|
|
19289
|
-
if (
|
|
19680
|
+
if (!hasContent) {
|
|
19290
19681
|
return /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { title: t("empty.noData"), description: t("empty.noData"), className });
|
|
19291
19682
|
}
|
|
19292
19683
|
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn("p-6", className), children: /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "md", children: [
|
|
@@ -19307,18 +19698,84 @@ var init_Chart = __esm({
|
|
|
19307
19698
|
)) })
|
|
19308
19699
|
] }),
|
|
19309
19700
|
/* @__PURE__ */ jsxRuntime.jsxs(Box, { className: "w-full", children: [
|
|
19310
|
-
chartType === "bar" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19311
|
-
|
|
19312
|
-
|
|
19313
|
-
|
|
19314
|
-
|
|
19701
|
+
chartType === "bar" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19702
|
+
BarChart,
|
|
19703
|
+
{
|
|
19704
|
+
series: normalizedSeries,
|
|
19705
|
+
height,
|
|
19706
|
+
showValues,
|
|
19707
|
+
stack,
|
|
19708
|
+
timeAxis,
|
|
19709
|
+
onPointClick: handlePointClick
|
|
19710
|
+
}
|
|
19711
|
+
),
|
|
19712
|
+
chartType === "histogram" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19713
|
+
BarChart,
|
|
19714
|
+
{
|
|
19715
|
+
series: normalizedSeries,
|
|
19716
|
+
height,
|
|
19717
|
+
showValues,
|
|
19718
|
+
stack: "none",
|
|
19719
|
+
timeAxis: false,
|
|
19720
|
+
histogram: true,
|
|
19721
|
+
onPointClick: handlePointClick
|
|
19722
|
+
}
|
|
19723
|
+
),
|
|
19724
|
+
chartType === "line" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19725
|
+
LineChart,
|
|
19726
|
+
{
|
|
19727
|
+
series: normalizedSeries,
|
|
19728
|
+
height,
|
|
19729
|
+
showValues,
|
|
19730
|
+
timeAxis,
|
|
19731
|
+
onPointClick: handlePointClick
|
|
19732
|
+
}
|
|
19733
|
+
),
|
|
19734
|
+
chartType === "area" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19735
|
+
LineChart,
|
|
19736
|
+
{
|
|
19737
|
+
series: normalizedSeries,
|
|
19738
|
+
height,
|
|
19739
|
+
showValues,
|
|
19740
|
+
timeAxis,
|
|
19741
|
+
fill: true,
|
|
19742
|
+
onPointClick: handlePointClick
|
|
19743
|
+
}
|
|
19744
|
+
),
|
|
19745
|
+
chartType === "pie" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19746
|
+
PieChart,
|
|
19747
|
+
{
|
|
19748
|
+
data: firstSeriesData,
|
|
19749
|
+
height,
|
|
19750
|
+
showValues: showLegend,
|
|
19751
|
+
onPointClick: handlePointClick
|
|
19752
|
+
}
|
|
19753
|
+
),
|
|
19754
|
+
chartType === "donut" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19755
|
+
PieChart,
|
|
19756
|
+
{
|
|
19757
|
+
data: firstSeriesData,
|
|
19758
|
+
height,
|
|
19759
|
+
showValues: showLegend,
|
|
19760
|
+
donut: true,
|
|
19761
|
+
onPointClick: handlePointClick
|
|
19762
|
+
}
|
|
19763
|
+
),
|
|
19764
|
+
chartType === "scatter" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
19765
|
+
ScatterChart,
|
|
19766
|
+
{
|
|
19767
|
+
data: scatterData ?? [],
|
|
19768
|
+
height,
|
|
19769
|
+
onPointClick: handlePointClick
|
|
19770
|
+
}
|
|
19771
|
+
)
|
|
19315
19772
|
] }),
|
|
19316
|
-
showLegend &&
|
|
19773
|
+
showLegend && normalizedSeries.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "md", justify: "center", wrap: true, children: normalizedSeries.map((s, idx) => /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
|
|
19317
19774
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
19318
19775
|
Box,
|
|
19319
19776
|
{
|
|
19320
19777
|
className: "w-3 h-3 rounded-full flex-shrink-0",
|
|
19321
|
-
style: { backgroundColor: s
|
|
19778
|
+
style: { backgroundColor: seriesColor(s, idx) }
|
|
19322
19779
|
}
|
|
19323
19780
|
),
|
|
19324
19781
|
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: s.name })
|
|
@@ -24156,6 +24613,151 @@ var init_FlipCard = __esm({
|
|
|
24156
24613
|
FlipCard.displayName = "FlipCard";
|
|
24157
24614
|
}
|
|
24158
24615
|
});
|
|
24616
|
+
function toISODate(d) {
|
|
24617
|
+
return d.toISOString().slice(0, 10);
|
|
24618
|
+
}
|
|
24619
|
+
function startOfMonth(d) {
|
|
24620
|
+
return new Date(d.getFullYear(), d.getMonth(), 1);
|
|
24621
|
+
}
|
|
24622
|
+
function startOfQuarter(d) {
|
|
24623
|
+
return new Date(d.getFullYear(), Math.floor(d.getMonth() / 3) * 3, 1);
|
|
24624
|
+
}
|
|
24625
|
+
function startOfYear(d) {
|
|
24626
|
+
return new Date(d.getFullYear(), 0, 1);
|
|
24627
|
+
}
|
|
24628
|
+
function daysAgo(n) {
|
|
24629
|
+
const d = /* @__PURE__ */ new Date();
|
|
24630
|
+
d.setDate(d.getDate() - n);
|
|
24631
|
+
return d;
|
|
24632
|
+
}
|
|
24633
|
+
var DEFAULT_PRESETS, DateRangePicker;
|
|
24634
|
+
var init_DateRangePicker = __esm({
|
|
24635
|
+
"components/molecules/DateRangePicker.tsx"() {
|
|
24636
|
+
"use client";
|
|
24637
|
+
init_cn();
|
|
24638
|
+
init_Button();
|
|
24639
|
+
init_Input();
|
|
24640
|
+
init_Stack();
|
|
24641
|
+
init_Typography();
|
|
24642
|
+
init_useEventBus();
|
|
24643
|
+
DEFAULT_PRESETS = [
|
|
24644
|
+
{
|
|
24645
|
+
label: "Last 7 days",
|
|
24646
|
+
value: "7d",
|
|
24647
|
+
range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24648
|
+
},
|
|
24649
|
+
{
|
|
24650
|
+
label: "Last 30 days",
|
|
24651
|
+
value: "30d",
|
|
24652
|
+
range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24653
|
+
},
|
|
24654
|
+
{
|
|
24655
|
+
label: "This Month",
|
|
24656
|
+
value: "month",
|
|
24657
|
+
range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24658
|
+
},
|
|
24659
|
+
{
|
|
24660
|
+
label: "This Quarter",
|
|
24661
|
+
value: "quarter",
|
|
24662
|
+
range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24663
|
+
},
|
|
24664
|
+
{
|
|
24665
|
+
label: "YTD",
|
|
24666
|
+
value: "ytd",
|
|
24667
|
+
range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24668
|
+
}
|
|
24669
|
+
];
|
|
24670
|
+
DateRangePicker = ({
|
|
24671
|
+
from: fromProp,
|
|
24672
|
+
to: toProp,
|
|
24673
|
+
event,
|
|
24674
|
+
onChange,
|
|
24675
|
+
presets = DEFAULT_PRESETS,
|
|
24676
|
+
fromLabel = "From",
|
|
24677
|
+
toLabel = "To",
|
|
24678
|
+
className
|
|
24679
|
+
}) => {
|
|
24680
|
+
const eventBus = useEventBus();
|
|
24681
|
+
const [from, setFrom] = React80.useState(fromProp ?? "");
|
|
24682
|
+
const [to, setTo] = React80.useState(toProp ?? "");
|
|
24683
|
+
const [activePreset, setActivePreset] = React80.useState(null);
|
|
24684
|
+
const emit = React80.useCallback(
|
|
24685
|
+
(range) => {
|
|
24686
|
+
onChange?.(range);
|
|
24687
|
+
if (event) eventBus.emit(`UI:${event}`, range);
|
|
24688
|
+
},
|
|
24689
|
+
[onChange, event, eventBus]
|
|
24690
|
+
);
|
|
24691
|
+
const handleFromChange = React80.useCallback(
|
|
24692
|
+
(next) => {
|
|
24693
|
+
setFrom(next);
|
|
24694
|
+
setActivePreset(null);
|
|
24695
|
+
emit({ from: next, to });
|
|
24696
|
+
},
|
|
24697
|
+
[to, emit]
|
|
24698
|
+
);
|
|
24699
|
+
const handleToChange = React80.useCallback(
|
|
24700
|
+
(next) => {
|
|
24701
|
+
setTo(next);
|
|
24702
|
+
setActivePreset(null);
|
|
24703
|
+
emit({ from, to: next });
|
|
24704
|
+
},
|
|
24705
|
+
[from, emit]
|
|
24706
|
+
);
|
|
24707
|
+
const handlePreset = React80.useCallback(
|
|
24708
|
+
(preset) => {
|
|
24709
|
+
const range = preset.range();
|
|
24710
|
+
setFrom(range.from);
|
|
24711
|
+
setTo(range.to);
|
|
24712
|
+
setActivePreset(preset.value);
|
|
24713
|
+
emit(range);
|
|
24714
|
+
},
|
|
24715
|
+
[emit]
|
|
24716
|
+
);
|
|
24717
|
+
const presetButtons = React80.useMemo(
|
|
24718
|
+
() => presets.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
24719
|
+
Button,
|
|
24720
|
+
{
|
|
24721
|
+
variant: activePreset === preset.value ? "primary" : "ghost",
|
|
24722
|
+
size: "sm",
|
|
24723
|
+
onClick: () => handlePreset(preset),
|
|
24724
|
+
children: preset.label
|
|
24725
|
+
},
|
|
24726
|
+
preset.value
|
|
24727
|
+
)),
|
|
24728
|
+
[presets, activePreset, handlePreset]
|
|
24729
|
+
);
|
|
24730
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", className: cn(className), children: [
|
|
24731
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "md", align: "end", children: [
|
|
24732
|
+
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
24733
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: fromLabel }),
|
|
24734
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
24735
|
+
Input,
|
|
24736
|
+
{
|
|
24737
|
+
type: "date",
|
|
24738
|
+
value: from,
|
|
24739
|
+
onChange: (e) => handleFromChange(e.target.value)
|
|
24740
|
+
}
|
|
24741
|
+
)
|
|
24742
|
+
] }),
|
|
24743
|
+
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
24744
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: toLabel }),
|
|
24745
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
24746
|
+
Input,
|
|
24747
|
+
{
|
|
24748
|
+
type: "date",
|
|
24749
|
+
value: to,
|
|
24750
|
+
onChange: (e) => handleToChange(e.target.value)
|
|
24751
|
+
}
|
|
24752
|
+
)
|
|
24753
|
+
] })
|
|
24754
|
+
] }),
|
|
24755
|
+
presets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
|
|
24756
|
+
] });
|
|
24757
|
+
};
|
|
24758
|
+
DateRangePicker.displayName = "DateRangePicker";
|
|
24759
|
+
}
|
|
24760
|
+
});
|
|
24159
24761
|
var DEFAULT_OPTIONS, DateRangeSelector;
|
|
24160
24762
|
var init_DateRangeSelector = __esm({
|
|
24161
24763
|
"components/molecules/DateRangeSelector.tsx"() {
|
|
@@ -27127,7 +27729,9 @@ var init_StatDisplay = __esm({
|
|
|
27127
27729
|
init_Typography();
|
|
27128
27730
|
init_Box();
|
|
27129
27731
|
init_Stack();
|
|
27732
|
+
init_Sparkline();
|
|
27130
27733
|
init_Icon();
|
|
27734
|
+
init_useEventBus();
|
|
27131
27735
|
variantColor = {
|
|
27132
27736
|
default: "text-foreground",
|
|
27133
27737
|
primary: "text-primary",
|
|
@@ -27142,6 +27746,10 @@ var init_StatDisplay = __esm({
|
|
|
27142
27746
|
max,
|
|
27143
27747
|
target,
|
|
27144
27748
|
trend,
|
|
27749
|
+
trendPolarity = "higher-is-better",
|
|
27750
|
+
trendFormat = "absolute",
|
|
27751
|
+
sparklineData,
|
|
27752
|
+
clickEvent,
|
|
27145
27753
|
prefix,
|
|
27146
27754
|
suffix,
|
|
27147
27755
|
icon: iconProp,
|
|
@@ -27155,6 +27763,10 @@ var init_StatDisplay = __esm({
|
|
|
27155
27763
|
isLoading = false,
|
|
27156
27764
|
error = null
|
|
27157
27765
|
}) => {
|
|
27766
|
+
const eventBus = useEventBus();
|
|
27767
|
+
const handleClick = React80.useCallback(() => {
|
|
27768
|
+
if (clickEvent) eventBus.emit(`UI:${clickEvent}`, { metricLabel: label });
|
|
27769
|
+
}, [clickEvent, eventBus, label]);
|
|
27158
27770
|
const ResolvedIcon = typeof iconProp === "string" ? resolveIcon(iconProp) : null;
|
|
27159
27771
|
const iconSizes3 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
|
|
27160
27772
|
const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
|
|
@@ -27165,7 +27777,10 @@ var init_StatDisplay = __esm({
|
|
|
27165
27777
|
const targetPct = showTarget ? Math.max(0, Math.min(100, numericValue / target * 100)) : 0;
|
|
27166
27778
|
const showTrend = typeof trend === "number" && trend !== 0 && Number.isFinite(trend);
|
|
27167
27779
|
const trendUp = showTrend && trend > 0;
|
|
27168
|
-
const
|
|
27780
|
+
const trendIsGood = trendPolarity === "lower-is-better" ? !trendUp : trendUp;
|
|
27781
|
+
const trendMagnitude = Math.abs(trend);
|
|
27782
|
+
const trendSuffix = trendFormat === "percent" ? "%" : "";
|
|
27783
|
+
const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${trendMagnitude}${trendSuffix}` : "";
|
|
27169
27784
|
if (error) {
|
|
27170
27785
|
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "error", children: error.message }) });
|
|
27171
27786
|
}
|
|
@@ -27176,38 +27791,57 @@ var init_StatDisplay = __esm({
|
|
|
27176
27791
|
] }) });
|
|
27177
27792
|
}
|
|
27178
27793
|
if (compact) {
|
|
27179
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
27180
|
-
|
|
27181
|
-
|
|
27182
|
-
|
|
27183
|
-
|
|
27184
|
-
|
|
27185
|
-
|
|
27794
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
27795
|
+
HStack,
|
|
27796
|
+
{
|
|
27797
|
+
gap: "sm",
|
|
27798
|
+
className: cn("items-center", clickEvent && "cursor-pointer hover:opacity-80", className),
|
|
27799
|
+
onClick: clickEvent ? handleClick : void 0,
|
|
27800
|
+
children: [
|
|
27801
|
+
ResolvedIcon && /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
|
|
27802
|
+
typeof iconProp !== "string" && iconProp,
|
|
27803
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: label }),
|
|
27804
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
|
|
27805
|
+
showTrend && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: cn("font-semibold", trendIsGood ? "text-success" : "text-error"), children: trendLabel }),
|
|
27806
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto", width: 60, height: 20 })
|
|
27807
|
+
]
|
|
27808
|
+
}
|
|
27809
|
+
);
|
|
27186
27810
|
}
|
|
27187
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
27188
|
-
|
|
27189
|
-
|
|
27190
|
-
|
|
27191
|
-
|
|
27192
|
-
|
|
27193
|
-
|
|
27194
|
-
{
|
|
27195
|
-
|
|
27196
|
-
className: cn("font-
|
|
27197
|
-
|
|
27198
|
-
|
|
27199
|
-
|
|
27200
|
-
|
|
27201
|
-
|
|
27202
|
-
|
|
27203
|
-
|
|
27204
|
-
|
|
27205
|
-
|
|
27206
|
-
|
|
27207
|
-
|
|
27208
|
-
|
|
27209
|
-
|
|
27210
|
-
|
|
27811
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
27812
|
+
Card,
|
|
27813
|
+
{
|
|
27814
|
+
className: cn(padSizes[size], clickEvent && "cursor-pointer hover:shadow-md transition-shadow", className),
|
|
27815
|
+
onClick: clickEvent ? handleClick : void 0,
|
|
27816
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "start", justify: "between", children: [
|
|
27817
|
+
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
|
|
27818
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "overline", color: "secondary", children: label }),
|
|
27819
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "end", children: [
|
|
27820
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
|
|
27821
|
+
showTrend && /* @__PURE__ */ jsxRuntime.jsx(
|
|
27822
|
+
Typography,
|
|
27823
|
+
{
|
|
27824
|
+
variant: "caption",
|
|
27825
|
+
className: cn("font-semibold pb-1", trendIsGood ? "text-success" : "text-error"),
|
|
27826
|
+
children: trendLabel
|
|
27827
|
+
}
|
|
27828
|
+
)
|
|
27829
|
+
] }),
|
|
27830
|
+
showTarget && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
27831
|
+
Box,
|
|
27832
|
+
{
|
|
27833
|
+
className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
|
|
27834
|
+
style: { width: `${targetPct}%` }
|
|
27835
|
+
}
|
|
27836
|
+
) })
|
|
27837
|
+
] }),
|
|
27838
|
+
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "end", children: [
|
|
27839
|
+
(ResolvedIcon || typeof iconProp !== "string" && iconProp) && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("p-3 rounded-md", iconBg), children: ResolvedIcon ? /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }) : iconProp }),
|
|
27840
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto" })
|
|
27841
|
+
] })
|
|
27842
|
+
] })
|
|
27843
|
+
}
|
|
27844
|
+
);
|
|
27211
27845
|
};
|
|
27212
27846
|
StatDisplay.displayName = "StatDisplay";
|
|
27213
27847
|
}
|
|
@@ -41551,6 +42185,7 @@ var init_StatCard = __esm({
|
|
|
41551
42185
|
init_Box();
|
|
41552
42186
|
init_Stack();
|
|
41553
42187
|
init_Button();
|
|
42188
|
+
init_Sparkline();
|
|
41554
42189
|
init_useEventBus();
|
|
41555
42190
|
init_useTranslate();
|
|
41556
42191
|
init_Icon();
|
|
@@ -41720,32 +42355,7 @@ var init_StatCard = __esm({
|
|
|
41720
42355
|
] }),
|
|
41721
42356
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "end", children: [
|
|
41722
42357
|
Icon3 && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: cn("p-3", iconBg), children: /* @__PURE__ */ jsxRuntime.jsx(Icon3, { className: cn("h-6 w-6", iconColor) }) }),
|
|
41723
|
-
sparklineData && sparklineData.length > 1 && (
|
|
41724
|
-
const w = 80;
|
|
41725
|
-
const h = 32;
|
|
41726
|
-
const pad = 2;
|
|
41727
|
-
const min = Math.min(...sparklineData);
|
|
41728
|
-
const max = Math.max(...sparklineData);
|
|
41729
|
-
const range = max - min || 1;
|
|
41730
|
-
const points = sparklineData.map((v, i) => {
|
|
41731
|
-
const x = pad + i / (sparklineData.length - 1) * (w - pad * 2);
|
|
41732
|
-
const y = pad + (1 - (v - min) / range) * (h - pad * 2);
|
|
41733
|
-
return `${x},${y}`;
|
|
41734
|
-
}).join(" ");
|
|
41735
|
-
const trending = sparklineData[sparklineData.length - 1] >= sparklineData[0];
|
|
41736
|
-
const strokeColor = trending ? "var(--color-success)" : "var(--color-error)";
|
|
41737
|
-
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: w, height: h, viewBox: `0 0 ${w} ${h}`, className: "flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
41738
|
-
"polyline",
|
|
41739
|
-
{
|
|
41740
|
-
fill: "none",
|
|
41741
|
-
stroke: strokeColor,
|
|
41742
|
-
strokeWidth: "2",
|
|
41743
|
-
strokeLinecap: "round",
|
|
41744
|
-
strokeLinejoin: "round",
|
|
41745
|
-
points
|
|
41746
|
-
}
|
|
41747
|
-
) });
|
|
41748
|
-
})()
|
|
42358
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto" })
|
|
41749
42359
|
] })
|
|
41750
42360
|
] }),
|
|
41751
42361
|
action && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -43643,6 +44253,7 @@ var init_component_registry_generated = __esm({
|
|
|
43643
44253
|
init_DataGrid();
|
|
43644
44254
|
init_DataList();
|
|
43645
44255
|
init_DataTable();
|
|
44256
|
+
init_DateRangePicker();
|
|
43646
44257
|
init_DateRangeSelector();
|
|
43647
44258
|
init_DayCell();
|
|
43648
44259
|
init_DebuggerBoard();
|
|
@@ -43775,6 +44386,7 @@ var init_component_registry_generated = __esm({
|
|
|
43775
44386
|
init_Skeleton();
|
|
43776
44387
|
init_SocialProof();
|
|
43777
44388
|
init_SortableList();
|
|
44389
|
+
init_Sparkline();
|
|
43778
44390
|
init_Split();
|
|
43779
44391
|
init_SplitPane();
|
|
43780
44392
|
init_SplitSection();
|
|
@@ -43923,6 +44535,7 @@ var init_component_registry_generated = __esm({
|
|
|
43923
44535
|
"DataGrid": DataGrid,
|
|
43924
44536
|
"DataList": DataList,
|
|
43925
44537
|
"DataTable": DataTable,
|
|
44538
|
+
"DateRangePicker": DateRangePicker,
|
|
43926
44539
|
"DateRangeSelector": DateRangeSelector,
|
|
43927
44540
|
"DayCell": DayCell,
|
|
43928
44541
|
"DebuggerBoard": DebuggerBoard,
|
|
@@ -44084,6 +44697,7 @@ var init_component_registry_generated = __esm({
|
|
|
44084
44697
|
"SortableList": SortableList,
|
|
44085
44698
|
"Spacer": SpacerPattern,
|
|
44086
44699
|
"SpacerPattern": SpacerPattern,
|
|
44700
|
+
"Sparkline": Sparkline,
|
|
44087
44701
|
"Spinner": SpinnerPattern,
|
|
44088
44702
|
"SpinnerPattern": SpinnerPattern,
|
|
44089
44703
|
"Split": Split,
|