@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.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 })
|
|
@@ -21165,7 +21622,6 @@ function useDataDnd(args) {
|
|
|
21165
21622
|
const raw = it[dndItemIdField];
|
|
21166
21623
|
return raw ?? `__idx_${idx}`;
|
|
21167
21624
|
}),
|
|
21168
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
21169
21625
|
[itemIdsSignature]
|
|
21170
21626
|
);
|
|
21171
21627
|
const itemsContentSig = items.map((it, idx) => String(it[dndItemIdField] ?? `__${idx}`)).join("|");
|
|
@@ -22695,7 +23151,16 @@ var init_FilterGroup = __esm({
|
|
|
22695
23151
|
onClear: () => handleFilterSelect(`${filter.field}_to`, null)
|
|
22696
23152
|
}
|
|
22697
23153
|
)
|
|
22698
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
23154
|
+
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
23155
|
+
Input,
|
|
23156
|
+
{
|
|
23157
|
+
value: selectedValues[filter.field] || "",
|
|
23158
|
+
onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
|
|
23159
|
+
placeholder: filter.label,
|
|
23160
|
+
clearable: true,
|
|
23161
|
+
onClear: () => handleFilterSelect(filter.field, null)
|
|
23162
|
+
}
|
|
23163
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
22699
23164
|
Select,
|
|
22700
23165
|
{
|
|
22701
23166
|
value: selectedValues[filter.field] || "all",
|
|
@@ -22762,7 +23227,17 @@ var init_FilterGroup = __esm({
|
|
|
22762
23227
|
className: "text-sm min-w-[100px]"
|
|
22763
23228
|
}
|
|
22764
23229
|
)
|
|
22765
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
23230
|
+
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
23231
|
+
Input,
|
|
23232
|
+
{
|
|
23233
|
+
value: selectedValues[filter.field] || "",
|
|
23234
|
+
onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
|
|
23235
|
+
placeholder: filter.label,
|
|
23236
|
+
clearable: true,
|
|
23237
|
+
onClear: () => handleFilterSelect(filter.field, null),
|
|
23238
|
+
className: "text-sm"
|
|
23239
|
+
}
|
|
23240
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
22766
23241
|
Select,
|
|
22767
23242
|
{
|
|
22768
23243
|
value: selectedValues[filter.field] || "all",
|
|
@@ -22867,7 +23342,17 @@ var init_FilterGroup = __esm({
|
|
|
22867
23342
|
className: "min-w-[130px]"
|
|
22868
23343
|
}
|
|
22869
23344
|
)
|
|
22870
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
23345
|
+
] }) : resolveFilterType(filter) === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
23346
|
+
Input,
|
|
23347
|
+
{
|
|
23348
|
+
value: selectedValues[filter.field] || "",
|
|
23349
|
+
onChange: (e) => handleFilterSelect(filter.field, e.target.value || null),
|
|
23350
|
+
placeholder: filter.label,
|
|
23351
|
+
clearable: true,
|
|
23352
|
+
onClear: () => handleFilterSelect(filter.field, null),
|
|
23353
|
+
className: "min-w-[160px]"
|
|
23354
|
+
}
|
|
23355
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
22871
23356
|
Select,
|
|
22872
23357
|
{
|
|
22873
23358
|
value: selectedValues[filter.field] || "all",
|
|
@@ -24156,6 +24641,151 @@ var init_FlipCard = __esm({
|
|
|
24156
24641
|
FlipCard.displayName = "FlipCard";
|
|
24157
24642
|
}
|
|
24158
24643
|
});
|
|
24644
|
+
function toISODate(d) {
|
|
24645
|
+
return d.toISOString().slice(0, 10);
|
|
24646
|
+
}
|
|
24647
|
+
function startOfMonth(d) {
|
|
24648
|
+
return new Date(d.getFullYear(), d.getMonth(), 1);
|
|
24649
|
+
}
|
|
24650
|
+
function startOfQuarter(d) {
|
|
24651
|
+
return new Date(d.getFullYear(), Math.floor(d.getMonth() / 3) * 3, 1);
|
|
24652
|
+
}
|
|
24653
|
+
function startOfYear(d) {
|
|
24654
|
+
return new Date(d.getFullYear(), 0, 1);
|
|
24655
|
+
}
|
|
24656
|
+
function daysAgo(n) {
|
|
24657
|
+
const d = /* @__PURE__ */ new Date();
|
|
24658
|
+
d.setDate(d.getDate() - n);
|
|
24659
|
+
return d;
|
|
24660
|
+
}
|
|
24661
|
+
var DEFAULT_PRESETS, DateRangePicker;
|
|
24662
|
+
var init_DateRangePicker = __esm({
|
|
24663
|
+
"components/molecules/DateRangePicker.tsx"() {
|
|
24664
|
+
"use client";
|
|
24665
|
+
init_cn();
|
|
24666
|
+
init_Button();
|
|
24667
|
+
init_Input();
|
|
24668
|
+
init_Stack();
|
|
24669
|
+
init_Typography();
|
|
24670
|
+
init_useEventBus();
|
|
24671
|
+
DEFAULT_PRESETS = [
|
|
24672
|
+
{
|
|
24673
|
+
label: "Last 7 days",
|
|
24674
|
+
value: "7d",
|
|
24675
|
+
range: () => ({ from: toISODate(daysAgo(7)), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24676
|
+
},
|
|
24677
|
+
{
|
|
24678
|
+
label: "Last 30 days",
|
|
24679
|
+
value: "30d",
|
|
24680
|
+
range: () => ({ from: toISODate(daysAgo(30)), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24681
|
+
},
|
|
24682
|
+
{
|
|
24683
|
+
label: "This Month",
|
|
24684
|
+
value: "month",
|
|
24685
|
+
range: () => ({ from: toISODate(startOfMonth(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24686
|
+
},
|
|
24687
|
+
{
|
|
24688
|
+
label: "This Quarter",
|
|
24689
|
+
value: "quarter",
|
|
24690
|
+
range: () => ({ from: toISODate(startOfQuarter(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24691
|
+
},
|
|
24692
|
+
{
|
|
24693
|
+
label: "YTD",
|
|
24694
|
+
value: "ytd",
|
|
24695
|
+
range: () => ({ from: toISODate(startOfYear(/* @__PURE__ */ new Date())), to: toISODate(/* @__PURE__ */ new Date()) })
|
|
24696
|
+
}
|
|
24697
|
+
];
|
|
24698
|
+
DateRangePicker = ({
|
|
24699
|
+
from: fromProp,
|
|
24700
|
+
to: toProp,
|
|
24701
|
+
event,
|
|
24702
|
+
onChange,
|
|
24703
|
+
presets = DEFAULT_PRESETS,
|
|
24704
|
+
fromLabel = "From",
|
|
24705
|
+
toLabel = "To",
|
|
24706
|
+
className
|
|
24707
|
+
}) => {
|
|
24708
|
+
const eventBus = useEventBus();
|
|
24709
|
+
const [from, setFrom] = React80.useState(fromProp ?? "");
|
|
24710
|
+
const [to, setTo] = React80.useState(toProp ?? "");
|
|
24711
|
+
const [activePreset, setActivePreset] = React80.useState(null);
|
|
24712
|
+
const emit = React80.useCallback(
|
|
24713
|
+
(range) => {
|
|
24714
|
+
onChange?.(range);
|
|
24715
|
+
if (event) eventBus.emit(`UI:${event}`, range);
|
|
24716
|
+
},
|
|
24717
|
+
[onChange, event, eventBus]
|
|
24718
|
+
);
|
|
24719
|
+
const handleFromChange = React80.useCallback(
|
|
24720
|
+
(next) => {
|
|
24721
|
+
setFrom(next);
|
|
24722
|
+
setActivePreset(null);
|
|
24723
|
+
emit({ from: next, to });
|
|
24724
|
+
},
|
|
24725
|
+
[to, emit]
|
|
24726
|
+
);
|
|
24727
|
+
const handleToChange = React80.useCallback(
|
|
24728
|
+
(next) => {
|
|
24729
|
+
setTo(next);
|
|
24730
|
+
setActivePreset(null);
|
|
24731
|
+
emit({ from, to: next });
|
|
24732
|
+
},
|
|
24733
|
+
[from, emit]
|
|
24734
|
+
);
|
|
24735
|
+
const handlePreset = React80.useCallback(
|
|
24736
|
+
(preset) => {
|
|
24737
|
+
const range = preset.range();
|
|
24738
|
+
setFrom(range.from);
|
|
24739
|
+
setTo(range.to);
|
|
24740
|
+
setActivePreset(preset.value);
|
|
24741
|
+
emit(range);
|
|
24742
|
+
},
|
|
24743
|
+
[emit]
|
|
24744
|
+
);
|
|
24745
|
+
const presetButtons = React80.useMemo(
|
|
24746
|
+
() => presets.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
24747
|
+
Button,
|
|
24748
|
+
{
|
|
24749
|
+
variant: activePreset === preset.value ? "primary" : "ghost",
|
|
24750
|
+
size: "sm",
|
|
24751
|
+
onClick: () => handlePreset(preset),
|
|
24752
|
+
children: preset.label
|
|
24753
|
+
},
|
|
24754
|
+
preset.value
|
|
24755
|
+
)),
|
|
24756
|
+
[presets, activePreset, handlePreset]
|
|
24757
|
+
);
|
|
24758
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "sm", className: cn(className), children: [
|
|
24759
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "md", align: "end", children: [
|
|
24760
|
+
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
24761
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: fromLabel }),
|
|
24762
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
24763
|
+
Input,
|
|
24764
|
+
{
|
|
24765
|
+
type: "date",
|
|
24766
|
+
value: from,
|
|
24767
|
+
onChange: (e) => handleFromChange(e.target.value)
|
|
24768
|
+
}
|
|
24769
|
+
)
|
|
24770
|
+
] }),
|
|
24771
|
+
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", children: [
|
|
24772
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: toLabel }),
|
|
24773
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
24774
|
+
Input,
|
|
24775
|
+
{
|
|
24776
|
+
type: "date",
|
|
24777
|
+
value: to,
|
|
24778
|
+
onChange: (e) => handleToChange(e.target.value)
|
|
24779
|
+
}
|
|
24780
|
+
)
|
|
24781
|
+
] })
|
|
24782
|
+
] }),
|
|
24783
|
+
presets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "xs", wrap: true, children: presetButtons })
|
|
24784
|
+
] });
|
|
24785
|
+
};
|
|
24786
|
+
DateRangePicker.displayName = "DateRangePicker";
|
|
24787
|
+
}
|
|
24788
|
+
});
|
|
24159
24789
|
var DEFAULT_OPTIONS, DateRangeSelector;
|
|
24160
24790
|
var init_DateRangeSelector = __esm({
|
|
24161
24791
|
"components/molecules/DateRangeSelector.tsx"() {
|
|
@@ -27127,7 +27757,9 @@ var init_StatDisplay = __esm({
|
|
|
27127
27757
|
init_Typography();
|
|
27128
27758
|
init_Box();
|
|
27129
27759
|
init_Stack();
|
|
27760
|
+
init_Sparkline();
|
|
27130
27761
|
init_Icon();
|
|
27762
|
+
init_useEventBus();
|
|
27131
27763
|
variantColor = {
|
|
27132
27764
|
default: "text-foreground",
|
|
27133
27765
|
primary: "text-primary",
|
|
@@ -27142,6 +27774,10 @@ var init_StatDisplay = __esm({
|
|
|
27142
27774
|
max,
|
|
27143
27775
|
target,
|
|
27144
27776
|
trend,
|
|
27777
|
+
trendPolarity = "higher-is-better",
|
|
27778
|
+
trendFormat = "absolute",
|
|
27779
|
+
sparklineData,
|
|
27780
|
+
clickEvent,
|
|
27145
27781
|
prefix,
|
|
27146
27782
|
suffix,
|
|
27147
27783
|
icon: iconProp,
|
|
@@ -27155,6 +27791,10 @@ var init_StatDisplay = __esm({
|
|
|
27155
27791
|
isLoading = false,
|
|
27156
27792
|
error = null
|
|
27157
27793
|
}) => {
|
|
27794
|
+
const eventBus = useEventBus();
|
|
27795
|
+
const handleClick = React80.useCallback(() => {
|
|
27796
|
+
if (clickEvent) eventBus.emit(`UI:${clickEvent}`, { metricLabel: label });
|
|
27797
|
+
}, [clickEvent, eventBus, label]);
|
|
27158
27798
|
const ResolvedIcon = typeof iconProp === "string" ? resolveIcon(iconProp) : null;
|
|
27159
27799
|
const iconSizes3 = { sm: "h-4 w-4", md: "h-5 w-5", lg: "h-6 w-6" };
|
|
27160
27800
|
const valueSizes = { sm: "text-lg", md: "text-2xl", lg: "text-3xl" };
|
|
@@ -27165,7 +27805,10 @@ var init_StatDisplay = __esm({
|
|
|
27165
27805
|
const targetPct = showTarget ? Math.max(0, Math.min(100, numericValue / target * 100)) : 0;
|
|
27166
27806
|
const showTrend = typeof trend === "number" && trend !== 0 && Number.isFinite(trend);
|
|
27167
27807
|
const trendUp = showTrend && trend > 0;
|
|
27168
|
-
const
|
|
27808
|
+
const trendIsGood = trendPolarity === "lower-is-better" ? !trendUp : trendUp;
|
|
27809
|
+
const trendMagnitude = Math.abs(trend);
|
|
27810
|
+
const trendSuffix = trendFormat === "percent" ? "%" : "";
|
|
27811
|
+
const trendLabel = showTrend ? `${trendUp ? "\u2191" : "\u2193"} ${trendMagnitude}${trendSuffix}` : "";
|
|
27169
27812
|
if (error) {
|
|
27170
27813
|
return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cn(padSizes[size], className), children: /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "small", color: "error", children: error.message }) });
|
|
27171
27814
|
}
|
|
@@ -27176,38 +27819,57 @@ var init_StatDisplay = __esm({
|
|
|
27176
27819
|
] }) });
|
|
27177
27820
|
}
|
|
27178
27821
|
if (compact) {
|
|
27179
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
27180
|
-
|
|
27181
|
-
|
|
27182
|
-
|
|
27183
|
-
|
|
27184
|
-
|
|
27185
|
-
|
|
27822
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
27823
|
+
HStack,
|
|
27824
|
+
{
|
|
27825
|
+
gap: "sm",
|
|
27826
|
+
className: cn("items-center", clickEvent && "cursor-pointer hover:opacity-80", className),
|
|
27827
|
+
onClick: clickEvent ? handleClick : void 0,
|
|
27828
|
+
children: [
|
|
27829
|
+
ResolvedIcon && /* @__PURE__ */ jsxRuntime.jsx(ResolvedIcon, { className: cn(iconSizes3[size], iconColor) }),
|
|
27830
|
+
typeof iconProp !== "string" && iconProp,
|
|
27831
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", color: "secondary", children: label }),
|
|
27832
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
|
|
27833
|
+
showTrend && /* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "caption", className: cn("font-semibold", trendIsGood ? "text-success" : "text-error"), children: trendLabel }),
|
|
27834
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto", width: 60, height: 20 })
|
|
27835
|
+
]
|
|
27836
|
+
}
|
|
27837
|
+
);
|
|
27186
27838
|
}
|
|
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
|
-
|
|
27839
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
27840
|
+
Card,
|
|
27841
|
+
{
|
|
27842
|
+
className: cn(padSizes[size], clickEvent && "cursor-pointer hover:shadow-md transition-shadow", className),
|
|
27843
|
+
onClick: clickEvent ? handleClick : void 0,
|
|
27844
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(HStack, { align: "start", justify: "between", children: [
|
|
27845
|
+
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "none", className: "space-y-1 flex-1", children: [
|
|
27846
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "overline", color: "secondary", children: label }),
|
|
27847
|
+
/* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "sm", align: "end", children: [
|
|
27848
|
+
/* @__PURE__ */ jsxRuntime.jsx(Typography, { variant: "h4", className: cn("font-bold", valueSizes[size], variantColor[variant]), children: displayValue }),
|
|
27849
|
+
showTrend && /* @__PURE__ */ jsxRuntime.jsx(
|
|
27850
|
+
Typography,
|
|
27851
|
+
{
|
|
27852
|
+
variant: "caption",
|
|
27853
|
+
className: cn("font-semibold pb-1", trendIsGood ? "text-success" : "text-error"),
|
|
27854
|
+
children: trendLabel
|
|
27855
|
+
}
|
|
27856
|
+
)
|
|
27857
|
+
] }),
|
|
27858
|
+
showTarget && /* @__PURE__ */ jsxRuntime.jsx(Box, { className: "mt-2 h-1.5 w-full bg-muted rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
27859
|
+
Box,
|
|
27860
|
+
{
|
|
27861
|
+
className: cn("h-full rounded-full transition-all", `bg-${variant === "default" ? "primary" : variant}`),
|
|
27862
|
+
style: { width: `${targetPct}%` }
|
|
27863
|
+
}
|
|
27864
|
+
) })
|
|
27865
|
+
] }),
|
|
27866
|
+
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "end", children: [
|
|
27867
|
+
(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 }),
|
|
27868
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto" })
|
|
27869
|
+
] })
|
|
27870
|
+
] })
|
|
27871
|
+
}
|
|
27872
|
+
);
|
|
27211
27873
|
};
|
|
27212
27874
|
StatDisplay.displayName = "StatDisplay";
|
|
27213
27875
|
}
|
|
@@ -41551,6 +42213,7 @@ var init_StatCard = __esm({
|
|
|
41551
42213
|
init_Box();
|
|
41552
42214
|
init_Stack();
|
|
41553
42215
|
init_Button();
|
|
42216
|
+
init_Sparkline();
|
|
41554
42217
|
init_useEventBus();
|
|
41555
42218
|
init_useTranslate();
|
|
41556
42219
|
init_Icon();
|
|
@@ -41720,32 +42383,7 @@ var init_StatCard = __esm({
|
|
|
41720
42383
|
] }),
|
|
41721
42384
|
/* @__PURE__ */ jsxRuntime.jsxs(VStack, { gap: "xs", align: "end", children: [
|
|
41722
42385
|
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
|
-
})()
|
|
42386
|
+
sparklineData && sparklineData.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(Sparkline, { data: sparklineData, color: "auto" })
|
|
41749
42387
|
] })
|
|
41750
42388
|
] }),
|
|
41751
42389
|
action && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -43643,6 +44281,7 @@ var init_component_registry_generated = __esm({
|
|
|
43643
44281
|
init_DataGrid();
|
|
43644
44282
|
init_DataList();
|
|
43645
44283
|
init_DataTable();
|
|
44284
|
+
init_DateRangePicker();
|
|
43646
44285
|
init_DateRangeSelector();
|
|
43647
44286
|
init_DayCell();
|
|
43648
44287
|
init_DebuggerBoard();
|
|
@@ -43775,6 +44414,7 @@ var init_component_registry_generated = __esm({
|
|
|
43775
44414
|
init_Skeleton();
|
|
43776
44415
|
init_SocialProof();
|
|
43777
44416
|
init_SortableList();
|
|
44417
|
+
init_Sparkline();
|
|
43778
44418
|
init_Split();
|
|
43779
44419
|
init_SplitPane();
|
|
43780
44420
|
init_SplitSection();
|
|
@@ -43923,6 +44563,7 @@ var init_component_registry_generated = __esm({
|
|
|
43923
44563
|
"DataGrid": DataGrid,
|
|
43924
44564
|
"DataList": DataList,
|
|
43925
44565
|
"DataTable": DataTable,
|
|
44566
|
+
"DateRangePicker": DateRangePicker,
|
|
43926
44567
|
"DateRangeSelector": DateRangeSelector,
|
|
43927
44568
|
"DayCell": DayCell,
|
|
43928
44569
|
"DebuggerBoard": DebuggerBoard,
|
|
@@ -44084,6 +44725,7 @@ var init_component_registry_generated = __esm({
|
|
|
44084
44725
|
"SortableList": SortableList,
|
|
44085
44726
|
"Spacer": SpacerPattern,
|
|
44086
44727
|
"SpacerPattern": SpacerPattern,
|
|
44728
|
+
"Sparkline": Sparkline,
|
|
44087
44729
|
"Spinner": SpinnerPattern,
|
|
44088
44730
|
"SpinnerPattern": SpinnerPattern,
|
|
44089
44731
|
"Split": Split,
|