bruv-ui 0.2.0

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.
Files changed (44) hide show
  1. package/dist/area-chart.d.ts +84 -0
  2. package/dist/area-chart.js +2002 -0
  3. package/dist/area-chart.js.map +1 -0
  4. package/dist/bar-chart.d.ts +80 -0
  5. package/dist/bar-chart.js +2251 -0
  6. package/dist/bar-chart.js.map +1 -0
  7. package/dist/chart-background-BK77UXhl.d.ts +9 -0
  8. package/dist/chart-brush-BoxY9aDm.d.ts +72 -0
  9. package/dist/chart-dot-8H287EDv.d.ts +17 -0
  10. package/dist/chart-legend-Dv9pqes-.d.ts +16 -0
  11. package/dist/chart-tooltip-DajpzJRy.d.ts +68 -0
  12. package/dist/charts.d.ts +17 -0
  13. package/dist/charts.js +5097 -0
  14. package/dist/charts.js.map +1 -0
  15. package/dist/composed-chart.d.ts +93 -0
  16. package/dist/composed-chart.js +2338 -0
  17. package/dist/composed-chart.js.map +1 -0
  18. package/dist/form-dK_DJRTw.d.ts +43 -0
  19. package/dist/form-rhf.d.ts +26 -0
  20. package/dist/form-rhf.js +268 -0
  21. package/dist/form-rhf.js.map +1 -0
  22. package/dist/index.d.ts +2881 -0
  23. package/dist/index.js +9368 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/line-chart.d.ts +81 -0
  26. package/dist/line-chart.js +1879 -0
  27. package/dist/line-chart.js.map +1 -0
  28. package/dist/pie-chart.d.ts +64 -0
  29. package/dist/pie-chart.js +1094 -0
  30. package/dist/pie-chart.js.map +1 -0
  31. package/dist/radar-chart.d.ts +67 -0
  32. package/dist/radar-chart.js +1318 -0
  33. package/dist/radar-chart.js.map +1 -0
  34. package/dist/radial-chart.d.ts +56 -0
  35. package/dist/radial-chart.js +1051 -0
  36. package/dist/radial-chart.js.map +1 -0
  37. package/dist/sankey-chart.d.ts +58 -0
  38. package/dist/sankey-chart.js +1179 -0
  39. package/dist/sankey-chart.js.map +1 -0
  40. package/package.json +135 -0
  41. package/src/scales.css +288 -0
  42. package/src/shiki.css +37 -0
  43. package/src/styles.css +23 -0
  44. package/src/theme.css +659 -0
@@ -0,0 +1,2338 @@
1
+ // src/components/charts/chart.tsx
2
+ import * as RechartsPrimitive from "recharts";
3
+
4
+ // src/lib/cn.ts
5
+ import { clsx } from "clsx";
6
+ import { extendTailwindMerge } from "tailwind-merge";
7
+ var twMerge = extendTailwindMerge({
8
+ extend: {
9
+ classGroups: {
10
+ "font-size": [{ "text-cui": ["sm", "base", "lg", "xl"] }],
11
+ "text-color": [
12
+ {
13
+ "text-cui": [
14
+ "primary",
15
+ "secondary",
16
+ "tertiary",
17
+ "inverse",
18
+ "accent",
19
+ "accent-on",
20
+ "danger",
21
+ "danger-on",
22
+ "warn",
23
+ "warn-on",
24
+ "success",
25
+ "success-on"
26
+ ]
27
+ }
28
+ ]
29
+ }
30
+ }
31
+ });
32
+ function cn(...inputs) {
33
+ return twMerge(clsx(inputs));
34
+ }
35
+
36
+ // src/components/charts/chart.tsx
37
+ import {
38
+ forwardRef,
39
+ useId,
40
+ createContext,
41
+ useContext
42
+ } from "react";
43
+ import { jsx, jsxs } from "react/jsx-runtime";
44
+ var THEMES = { light: "", dark: '[data-theme="dark"]' };
45
+ var VALID_THEME_KEYS = Object.keys(THEMES);
46
+ var DEFAULT_PALETTE = [
47
+ "var(--color-bruv-chart-1)",
48
+ "var(--color-bruv-chart-2)",
49
+ "var(--color-bruv-chart-3)",
50
+ "var(--color-bruv-chart-4)",
51
+ "var(--color-bruv-chart-5)",
52
+ "var(--color-bruv-chart-6)"
53
+ ];
54
+ var ChartContext = createContext(null);
55
+ function useChart() {
56
+ const context = useContext(ChartContext);
57
+ if (!context) {
58
+ throw new Error("useChart must be used within a <Chart />");
59
+ }
60
+ return context;
61
+ }
62
+ function validateChartConfigColors(config) {
63
+ for (const [key, value] of Object.entries(config)) {
64
+ if (value.colors) {
65
+ const hasValidThemeKey = VALID_THEME_KEYS.some(
66
+ (themeKey) => value.colors?.[themeKey] !== void 0
67
+ );
68
+ if (!hasValidThemeKey) {
69
+ throw new Error(
70
+ `[BruvCharts] Invalid chart config for "${key}": colors object must have at least one theme key (${VALID_THEME_KEYS.join(", ")}).`
71
+ );
72
+ }
73
+ }
74
+ }
75
+ }
76
+ function applyDefaultChartColors(config) {
77
+ const entries = Object.entries(config);
78
+ return Object.fromEntries(
79
+ entries.map(([key, item], index) => {
80
+ if (item.colors || item.color) {
81
+ if (item.color && !item.colors) {
82
+ return [
83
+ key,
84
+ {
85
+ ...item,
86
+ colors: {
87
+ light: [item.color],
88
+ dark: [item.color]
89
+ }
90
+ }
91
+ ];
92
+ }
93
+ return [key, item];
94
+ }
95
+ const paletteColor = DEFAULT_PALETTE[index % DEFAULT_PALETTE.length] ?? DEFAULT_PALETTE[0];
96
+ return [
97
+ key,
98
+ {
99
+ ...item,
100
+ colors: {
101
+ light: [paletteColor],
102
+ dark: [paletteColor]
103
+ }
104
+ }
105
+ ];
106
+ })
107
+ );
108
+ }
109
+ var Chart = forwardRef(function Chart2({
110
+ id,
111
+ config,
112
+ initialDimension = { width: 320, height: 200 },
113
+ className,
114
+ children,
115
+ footer,
116
+ ...props
117
+ }, ref) {
118
+ const uniqueId = useId();
119
+ const chartId = `chart-${id ?? uniqueId.replace(/:/g, "")}`;
120
+ const resolvedConfig = applyDefaultChartColors(config);
121
+ validateChartConfigColors(resolvedConfig);
122
+ return /* @__PURE__ */ jsx(ChartContext.Provider, { value: { config: resolvedConfig }, children: /* @__PURE__ */ jsxs(
123
+ "div",
124
+ {
125
+ ref,
126
+ "data-slot": "chart",
127
+ "data-chart": chartId,
128
+ className: cn(
129
+ "bruv-chart relative flex min-h-0 w-full flex-1 flex-col justify-center text-bruv-sm text-bruv-secondary",
130
+ "[&_.recharts-cartesian-axis-tick_text]:fill-bruv-chart-axis [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-bruv-chart-grid/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-bruv-chart-cursor [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-bruv-chart-grid [&_.recharts-radial-bar-background-sector]:fill-bruv-subtle [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-bruv-subtle [&_.recharts-reference-line_[stroke='#ccc']]:stroke-bruv-chart-grid [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-hidden [&_.recharts-sector]:outline-hidden [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-surface]:outline-hidden",
131
+ !footer && "aspect-video",
132
+ className
133
+ ),
134
+ ...props,
135
+ children: [
136
+ /* @__PURE__ */ jsx(ChartStyle, { id: chartId, config: resolvedConfig }),
137
+ /* @__PURE__ */ jsx(
138
+ RechartsPrimitive.ResponsiveContainer,
139
+ {
140
+ className: "min-h-0 w-full flex-1",
141
+ initialDimension,
142
+ children
143
+ }
144
+ ),
145
+ footer
146
+ ]
147
+ }
148
+ ) });
149
+ });
150
+ function LoadingIndicator({ isLoading }) {
151
+ if (!isLoading) return null;
152
+ return /* @__PURE__ */ jsx("div", { className: "pointer-events-none absolute inset-0 z-20 flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "border-bruv-neutral bg-bruv-base-2 text-bruv-sm text-bruv-primary rounded-bruv-md flex items-center justify-center gap-2 border px-2 py-0.5", children: [
153
+ /* @__PURE__ */ jsx("div", { className: "border-bruv-neutral border-t-bruv-accent size-3 animate-spin rounded-full border" }),
154
+ /* @__PURE__ */ jsx("span", { children: "Loading" })
155
+ ] }) });
156
+ }
157
+ function distributeColors(colorsArray, maxCount) {
158
+ const availableCount = colorsArray.length;
159
+ if (availableCount >= maxCount) {
160
+ return colorsArray.slice(0, maxCount);
161
+ }
162
+ const result = [];
163
+ const baseSlots = Math.floor(maxCount / availableCount);
164
+ const extraSlots = maxCount % availableCount;
165
+ for (let colorIdx = 0; colorIdx < availableCount; colorIdx++) {
166
+ const isExtraColor = colorIdx >= availableCount - extraSlots;
167
+ const slotsForThisColor = baseSlots + (isExtraColor ? 1 : 0);
168
+ for (let j = 0; j < slotsForThisColor; j++) {
169
+ const color = colorsArray[colorIdx];
170
+ if (color) result.push(color);
171
+ }
172
+ }
173
+ return result;
174
+ }
175
+ function ChartStyle({
176
+ id,
177
+ config
178
+ }) {
179
+ const colorConfig = Object.entries(config).filter(([, item]) => item.colors);
180
+ if (!colorConfig.length) return null;
181
+ const generateCssVars = (theme) => colorConfig.flatMap(([key, itemConfig]) => {
182
+ const colorsArray = itemConfig.colors?.[theme];
183
+ if (!colorsArray?.length) return [];
184
+ const maxCount = getColorsCount(itemConfig);
185
+ const distributedColors = distributeColors(colorsArray, maxCount);
186
+ return distributedColors.map(
187
+ (color, index) => ` --color-${key}-${index}: ${color};`
188
+ );
189
+ }).filter(Boolean).join("\n");
190
+ const css = Object.entries(THEMES).map(
191
+ ([theme, prefix]) => `${prefix} [data-chart=${id}] {
192
+ ${generateCssVars(theme)}
193
+ }`
194
+ ).join("\n");
195
+ return /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: css } });
196
+ }
197
+ function getPayloadConfigFromPayload(config, payload, key) {
198
+ if (typeof payload !== "object" || payload === null) return void 0;
199
+ const payloadPayload = "payload" in payload && typeof payload.payload === "object" && payload.payload !== null ? payload.payload : void 0;
200
+ let configLabelKey = key;
201
+ if (key in payload && typeof payload[key] === "string") {
202
+ configLabelKey = payload[key];
203
+ } else if (payloadPayload && key in payloadPayload && typeof payloadPayload[key] === "string") {
204
+ configLabelKey = payloadPayload[key];
205
+ }
206
+ return configLabelKey in config ? config[configLabelKey] : config[key];
207
+ }
208
+ function getColorsCount(config) {
209
+ if (!config.colors) return 1;
210
+ const counts = VALID_THEME_KEYS.map(
211
+ (theme) => config.colors?.[theme]?.length ?? 0
212
+ );
213
+ return Math.max(...counts, 1);
214
+ }
215
+ var getLoadingData = (points = 10, min = 0, max = 70) => {
216
+ const range = max - min;
217
+ return Array.from({ length: points }, () => ({
218
+ loading: Math.floor(Math.random() * range) + min
219
+ }));
220
+ };
221
+
222
+ // src/components/charts/chart-brush.tsx
223
+ import {
224
+ motion,
225
+ useMotionValue,
226
+ useMotionValueEvent,
227
+ useSpring,
228
+ useTransform
229
+ } from "motion/react";
230
+ import {
231
+ ResponsiveContainer as ResponsiveContainer2,
232
+ AreaChart,
233
+ Area,
234
+ LineChart,
235
+ Line,
236
+ BarChart,
237
+ Bar
238
+ } from "recharts";
239
+ import { useCallback, useEffect } from "react";
240
+ import * as React from "react";
241
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
242
+ var SPRING_CONFIG = { stiffness: 300, damping: 35, mass: 0.8 };
243
+ function useBrushDrag({
244
+ range,
245
+ totalPoints,
246
+ containerRef,
247
+ commit
248
+ }) {
249
+ const dragRef = React.useRef(null);
250
+ const [isDragging, setIsDragging] = React.useState(false);
251
+ const toIndexDelta = useCallback(
252
+ (px) => {
253
+ if (!containerRef.current || totalPoints <= 1) return 0;
254
+ return Math.round(
255
+ px / containerRef.current.getBoundingClientRect().width * (totalPoints - 1)
256
+ );
257
+ },
258
+ [totalPoints, containerRef]
259
+ );
260
+ const onPointerDown = useCallback(
261
+ (e, type) => {
262
+ e.preventDefault();
263
+ e.target.setPointerCapture(e.pointerId);
264
+ dragRef.current = { type, originX: e.clientX, originRange: { ...range } };
265
+ setIsDragging(true);
266
+ },
267
+ [range]
268
+ );
269
+ const onPointerMove = useCallback(
270
+ (e) => {
271
+ const d = dragRef.current;
272
+ if (!d) return;
273
+ const delta = toIndexDelta(e.clientX - d.originX);
274
+ const { type, originRange: o } = d;
275
+ if (type === "left") {
276
+ commit(
277
+ { startIndex: o.startIndex + delta, endIndex: o.endIndex },
278
+ "left"
279
+ );
280
+ } else if (type === "right") {
281
+ commit(
282
+ { startIndex: o.startIndex, endIndex: o.endIndex + delta },
283
+ "right"
284
+ );
285
+ } else {
286
+ const span = o.endIndex - o.startIndex;
287
+ let s = o.startIndex + delta;
288
+ let e2 = s + span;
289
+ if (s < 0) {
290
+ s = 0;
291
+ e2 = span;
292
+ }
293
+ if (e2 > totalPoints - 1) {
294
+ e2 = totalPoints - 1;
295
+ s = Math.max(0, e2 - span);
296
+ }
297
+ commit({ startIndex: s, endIndex: e2 }, "middle");
298
+ }
299
+ },
300
+ [toIndexDelta, totalPoints, commit]
301
+ );
302
+ const onPointerUp = useCallback((e) => {
303
+ ;
304
+ e.target.releasePointerCapture(e.pointerId);
305
+ dragRef.current = null;
306
+ setIsDragging(false);
307
+ }, []);
308
+ const bind = useCallback(
309
+ (type) => ({
310
+ onPointerDown: (e) => onPointerDown(e, type),
311
+ onPointerMove,
312
+ onPointerUp
313
+ }),
314
+ [onPointerDown, onPointerMove, onPointerUp]
315
+ );
316
+ return { isDragging, bind };
317
+ }
318
+ function Brush({
319
+ data,
320
+ chartConfig,
321
+ dataKeys,
322
+ xDataKey,
323
+ variant = "area",
324
+ height = 56,
325
+ className,
326
+ stacked = false,
327
+ strokeVariant = "solid",
328
+ connectNulls = false,
329
+ barRadius,
330
+ startIndex: controlledStart,
331
+ endIndex: controlledEnd,
332
+ defaultStartIndex = 0,
333
+ defaultEndIndex,
334
+ onChange,
335
+ formatLabel,
336
+ curveType = "monotone",
337
+ minSpan = 2,
338
+ showLabels = true,
339
+ skipStyle = false
340
+ }) {
341
+ const containerRef = React.useRef(null);
342
+ const keys = React.useMemo(
343
+ () => dataKeys ?? Object.keys(chartConfig),
344
+ [dataKeys, chartConfig]
345
+ );
346
+ const totalPoints = data.length;
347
+ const chartId = React.useId().replace(/:/g, "");
348
+ const isControlled = controlledStart !== void 0 && controlledEnd !== void 0;
349
+ const [internalRange, setInternalRange] = React.useState(() => ({
350
+ startIndex: Math.max(0, Math.min(defaultStartIndex, totalPoints - 1)),
351
+ endIndex: Math.max(
352
+ 0,
353
+ Math.min(defaultEndIndex ?? totalPoints - 1, totalPoints - 1)
354
+ )
355
+ }));
356
+ const lastCommittedRef = React.useRef(internalRange);
357
+ useEffect(() => {
358
+ if (!isControlled) {
359
+ setInternalRange((prev) => {
360
+ const adjusted = {
361
+ startIndex: Math.min(prev.startIndex, Math.max(0, totalPoints - 1)),
362
+ endIndex: Math.min(prev.endIndex, Math.max(0, totalPoints - 1))
363
+ };
364
+ lastCommittedRef.current = adjusted;
365
+ return adjusted;
366
+ });
367
+ }
368
+ }, [totalPoints, isControlled]);
369
+ const clampRange = useCallback(
370
+ (range2, mode) => {
371
+ let { startIndex, endIndex } = range2;
372
+ const maxIndex = Math.max(0, totalPoints - 1);
373
+ startIndex = Math.max(0, Math.min(startIndex, maxIndex));
374
+ endIndex = Math.max(0, Math.min(endIndex, maxIndex));
375
+ if (mode === "left") {
376
+ const maxStart = Math.max(0, endIndex - minSpan);
377
+ startIndex = Math.min(startIndex, maxStart);
378
+ return { startIndex, endIndex };
379
+ }
380
+ if (mode === "right") {
381
+ const minEnd = Math.min(maxIndex, startIndex + minSpan);
382
+ endIndex = Math.max(endIndex, minEnd);
383
+ return { startIndex, endIndex };
384
+ }
385
+ if (endIndex - startIndex < minSpan) {
386
+ endIndex = Math.min(startIndex + minSpan, maxIndex);
387
+ if (endIndex - startIndex < minSpan) {
388
+ startIndex = Math.max(0, endIndex - minSpan);
389
+ }
390
+ }
391
+ return { startIndex, endIndex };
392
+ },
393
+ [totalPoints, minSpan]
394
+ );
395
+ const commit = useCallback(
396
+ (next, mode) => {
397
+ const clamped = clampRange(next, mode);
398
+ const last = lastCommittedRef.current;
399
+ if (last.startIndex === clamped.startIndex && last.endIndex === clamped.endIndex) {
400
+ return;
401
+ }
402
+ lastCommittedRef.current = clamped;
403
+ setInternalRange(clamped);
404
+ React.startTransition(() => {
405
+ onChange?.(clamped);
406
+ });
407
+ },
408
+ [clampRange, onChange]
409
+ );
410
+ const { isDragging, bind } = useBrushDrag({
411
+ range: internalRange,
412
+ totalPoints,
413
+ containerRef,
414
+ commit
415
+ });
416
+ const range = internalRange;
417
+ useEffect(() => {
418
+ if (isControlled && !isDragging) {
419
+ const syncedRange = {
420
+ startIndex: controlledStart,
421
+ endIndex: controlledEnd
422
+ };
423
+ setInternalRange(syncedRange);
424
+ lastCommittedRef.current = syncedRange;
425
+ }
426
+ }, [isControlled, controlledStart, controlledEnd, isDragging]);
427
+ const leftPct = totalPoints > 1 ? range.startIndex / (totalPoints - 1) * 100 : 0;
428
+ const rightPct = totalPoints > 1 ? range.endIndex / (totalPoints - 1) * 100 : 100;
429
+ const leftTarget = useMotionValue(leftPct);
430
+ const rightTarget = useMotionValue(rightPct);
431
+ if (leftTarget.get() !== leftPct) leftTarget.set(leftPct);
432
+ if (rightTarget.get() !== rightPct) rightTarget.set(rightPct);
433
+ const leftSpring = useSpring(leftTarget, SPRING_CONFIG);
434
+ const rightSpring = useSpring(rightTarget, SPRING_CONFIG);
435
+ const leftPosition = useTransform(leftSpring, (v) => `${v}%`);
436
+ const rightPosition = useTransform(rightSpring, (v) => `${v}%`);
437
+ const leftOverlayWidth = useTransform(leftSpring, (v) => `${v}%`);
438
+ const rightOverlayWidth = useTransform(
439
+ rightSpring,
440
+ (v) => `${Math.max(0, 100 - v)}%`
441
+ );
442
+ const selectedWidth = useMotionValue(`${Math.max(0, rightPct - leftPct)}%`);
443
+ const updateSelectedWidth = useCallback(() => {
444
+ selectedWidth.set(`${Math.max(0, rightSpring.get() - leftSpring.get())}%`);
445
+ }, [leftSpring, rightSpring, selectedWidth]);
446
+ useMotionValueEvent(leftSpring, "change", updateSelectedWidth);
447
+ useMotionValueEvent(rightSpring, "change", updateSelectedWidth);
448
+ const getLabel = useCallback(
449
+ (idx) => {
450
+ if (!xDataKey) return String(idx);
451
+ const v = data[idx]?.[xDataKey];
452
+ return formatLabel ? formatLabel(v, idx) : String(v ?? idx);
453
+ },
454
+ [data, xDataKey, formatLabel]
455
+ );
456
+ if (totalPoints === 0) return null;
457
+ return /* @__PURE__ */ jsxs2(
458
+ "div",
459
+ {
460
+ ref: containerRef,
461
+ "data-chart": skipStyle ? void 0 : chartId,
462
+ className: cn("group relative select-none", className),
463
+ style: { height },
464
+ children: [
465
+ !skipStyle && /* @__PURE__ */ jsx2(ChartStyle, { id: chartId, config: chartConfig }),
466
+ /* @__PURE__ */ jsx2("div", { className: "rounded-bruv-md absolute inset-0 overflow-hidden", children: /* @__PURE__ */ jsx2(
467
+ MiniChart,
468
+ {
469
+ data,
470
+ keys,
471
+ chartConfig,
472
+ variant,
473
+ curveType,
474
+ chartId,
475
+ stacked,
476
+ strokeVariant: strokeVariant === "animated-dashed" ? "dashed" : strokeVariant,
477
+ connectNulls,
478
+ barRadius
479
+ }
480
+ ) }),
481
+ /* @__PURE__ */ jsx2(
482
+ motion.div,
483
+ {
484
+ className: "bg-bruv-base-2/70 pointer-events-none absolute inset-y-0 left-0 rounded-l-md backdrop-blur-[2px]",
485
+ style: { width: leftOverlayWidth }
486
+ }
487
+ ),
488
+ /* @__PURE__ */ jsx2(
489
+ motion.div,
490
+ {
491
+ className: "bg-bruv-base-2/70 pointer-events-none absolute inset-y-0 right-0 rounded-r-md backdrop-blur-[2px]",
492
+ style: { width: rightOverlayWidth }
493
+ }
494
+ ),
495
+ /* @__PURE__ */ jsx2(
496
+ motion.div,
497
+ {
498
+ className: "rounded-bruv-sm absolute inset-y-0 cursor-grab touch-none border active:cursor-grabbing",
499
+ style: { left: leftPosition, width: selectedWidth },
500
+ ...bind("middle")
501
+ }
502
+ ),
503
+ /* @__PURE__ */ jsx2(
504
+ BrushHandle,
505
+ {
506
+ side: "left",
507
+ position: leftPosition,
508
+ label: showLabels ? getLabel(range.startIndex) : void 0,
509
+ bind: bind("left")
510
+ }
511
+ ),
512
+ /* @__PURE__ */ jsx2(
513
+ BrushHandle,
514
+ {
515
+ side: "right",
516
+ position: rightPosition,
517
+ label: showLabels ? getLabel(range.endIndex) : void 0,
518
+ bind: bind("right")
519
+ }
520
+ )
521
+ ]
522
+ }
523
+ );
524
+ }
525
+ function BrushHandle({
526
+ side,
527
+ position,
528
+ label,
529
+ bind
530
+ }) {
531
+ const isLeft = side === "left";
532
+ return /* @__PURE__ */ jsxs2(motion.div, { className: "absolute inset-y-0 z-10", style: { left: position }, children: [
533
+ /* @__PURE__ */ jsx2(
534
+ "div",
535
+ {
536
+ className: cn(
537
+ "group absolute inset-y-0 flex w-3 cursor-ew-resize touch-none items-center justify-center after:absolute after:inset-y-0 after:-left-4 after:w-11 after:content-['']",
538
+ isLeft ? "" : "-translate-x-full"
539
+ ),
540
+ ...bind,
541
+ children: /* @__PURE__ */ jsx2(
542
+ "div",
543
+ {
544
+ className: cn(
545
+ "bg-muted-foreground group-hover:bg-foreground relative flex h-4 w-1.5 items-center justify-center rounded-bruv-md transition-colors",
546
+ isLeft ? "-left-[5.5px]" : "-right-[5.5px]"
547
+ ),
548
+ children: /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-[2px]", children: [
549
+ /* @__PURE__ */ jsx2("div", { className: "bg-bruv-base-2/70 h-[2px] w-[2px] rounded-full" }),
550
+ /* @__PURE__ */ jsx2("div", { className: "bg-bruv-base-2/70 h-[2px] w-[2px] rounded-full" }),
551
+ /* @__PURE__ */ jsx2("div", { className: "bg-bruv-base-2/70 h-[2px] w-[2px] rounded-full" })
552
+ ] })
553
+ }
554
+ )
555
+ }
556
+ ),
557
+ label && /* @__PURE__ */ jsx2(
558
+ "div",
559
+ {
560
+ className: cn(
561
+ "bg-foreground text-bruv-base-1 pointer-events-none absolute -bottom-3 -translate-y-1/2 rounded-[3px] px-1 py-px text-[8px] leading-tight font-medium whitespace-nowrap opacity-0 group-hover:opacity-100",
562
+ isLeft ? "left-1.5" : "right-1.5"
563
+ ),
564
+ children: label
565
+ }
566
+ )
567
+ ] });
568
+ }
569
+ function MiniChart({
570
+ data,
571
+ keys,
572
+ chartConfig,
573
+ variant,
574
+ curveType,
575
+ chartId,
576
+ stacked,
577
+ strokeVariant = "solid",
578
+ connectNulls = false,
579
+ barRadius
580
+ }) {
581
+ const gradients = React.useMemo(
582
+ () => Object.entries(chartConfig).filter(([key]) => keys.includes(key)).map(([dataKey, config]) => ({
583
+ dataKey,
584
+ colorsCount: getColorsCount(config)
585
+ })),
586
+ [chartConfig, keys]
587
+ );
588
+ const dashArray = strokeVariant === "dashed" || strokeVariant === "animated-dashed" ? "4 4" : void 0;
589
+ const defsContent = /* @__PURE__ */ jsxs2(Fragment2, { children: [
590
+ variant === "area" && /* @__PURE__ */ jsxs2(
591
+ "linearGradient",
592
+ {
593
+ id: `${chartId}-zm-vertical-fade`,
594
+ x1: "0",
595
+ y1: "0",
596
+ x2: "0",
597
+ y2: "1",
598
+ children: [
599
+ /* @__PURE__ */ jsx2("stop", { offset: "0%", stopColor: "white", stopOpacity: 0.15 }),
600
+ /* @__PURE__ */ jsx2("stop", { offset: "100%", stopColor: "white", stopOpacity: 0 })
601
+ ]
602
+ }
603
+ ),
604
+ gradients.map(({ dataKey, colorsCount }) => {
605
+ const colorStops = colorsCount === 1 ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
606
+ /* @__PURE__ */ jsx2("stop", { offset: "0%", stopColor: `var(--color-${dataKey}-0)` }),
607
+ /* @__PURE__ */ jsx2("stop", { offset: "100%", stopColor: `var(--color-${dataKey}-0)` })
608
+ ] }) : Array.from({ length: colorsCount }, (_, i) => /* @__PURE__ */ jsx2(
609
+ "stop",
610
+ {
611
+ offset: `${i / (colorsCount - 1) * 100}%`,
612
+ stopColor: `var(--color-${dataKey}-${i}, var(--color-${dataKey}-0))`
613
+ },
614
+ i
615
+ ));
616
+ return /* @__PURE__ */ jsxs2(React.Fragment, { children: [
617
+ /* @__PURE__ */ jsx2(
618
+ "linearGradient",
619
+ {
620
+ id: `${chartId}-zm-${dataKey}`,
621
+ x1: "0",
622
+ y1: "0",
623
+ x2: "0",
624
+ y2: "1",
625
+ children: colorStops
626
+ }
627
+ ),
628
+ variant === "area" && /* @__PURE__ */ jsxs2(Fragment2, { children: [
629
+ /* @__PURE__ */ jsx2("mask", { id: `${chartId}-zm-fill-mask-${dataKey}`, children: /* @__PURE__ */ jsx2(
630
+ "rect",
631
+ {
632
+ width: "100%",
633
+ height: "100%",
634
+ fill: `url(#${chartId}-zm-vertical-fade)`
635
+ }
636
+ ) }),
637
+ /* @__PURE__ */ jsx2(
638
+ "pattern",
639
+ {
640
+ id: `${chartId}-zm-fill-${dataKey}`,
641
+ patternUnits: "userSpaceOnUse",
642
+ width: "100%",
643
+ height: "100%",
644
+ children: /* @__PURE__ */ jsx2(
645
+ "rect",
646
+ {
647
+ width: "100%",
648
+ height: "100%",
649
+ fill: `url(#${chartId}-zm-${dataKey})`,
650
+ mask: `url(#${chartId}-zm-fill-mask-${dataKey})`
651
+ }
652
+ )
653
+ }
654
+ )
655
+ ] })
656
+ ] }, dataKey);
657
+ })
658
+ ] });
659
+ if (variant === "line") {
660
+ return /* @__PURE__ */ jsx2(ResponsiveContainer2, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs2(
661
+ LineChart,
662
+ {
663
+ data,
664
+ margin: { top: 4, right: 0, bottom: 0, left: 0 },
665
+ children: [
666
+ /* @__PURE__ */ jsx2("defs", { children: defsContent }),
667
+ keys.map((dk) => /* @__PURE__ */ jsx2(
668
+ Line,
669
+ {
670
+ type: curveType,
671
+ dataKey: dk,
672
+ stroke: `url(#${chartId}-zm-${dk})`,
673
+ strokeWidth: 1,
674
+ strokeOpacity: 0.5,
675
+ strokeDasharray: dashArray,
676
+ connectNulls,
677
+ dot: false,
678
+ activeDot: false,
679
+ isAnimationActive: false
680
+ },
681
+ dk
682
+ ))
683
+ ]
684
+ }
685
+ ) });
686
+ }
687
+ if (variant === "bar") {
688
+ const r = barRadius ?? 3;
689
+ return /* @__PURE__ */ jsx2(ResponsiveContainer2, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs2(
690
+ BarChart,
691
+ {
692
+ data,
693
+ margin: { top: 2, right: 0, bottom: 0, left: 0 },
694
+ barGap: 2,
695
+ barSize: 14,
696
+ children: [
697
+ /* @__PURE__ */ jsx2("defs", { children: defsContent }),
698
+ keys.map((dk) => /* @__PURE__ */ jsx2(
699
+ Bar,
700
+ {
701
+ dataKey: dk,
702
+ fill: `url(#${chartId}-zm-${dk})`,
703
+ fillOpacity: 0.35,
704
+ stackId: stacked ? "zm-stack" : void 0,
705
+ isAnimationActive: false,
706
+ radius: [r, r, r, r]
707
+ },
708
+ dk
709
+ ))
710
+ ]
711
+ }
712
+ ) });
713
+ }
714
+ return /* @__PURE__ */ jsx2(ResponsiveContainer2, { width: "100%", height: "100%", children: /* @__PURE__ */ jsxs2(AreaChart, { data, margin: { top: 4, right: 0, bottom: 0, left: 0 }, children: [
715
+ /* @__PURE__ */ jsx2("defs", { children: defsContent }),
716
+ keys.map((dk) => /* @__PURE__ */ jsx2(
717
+ Area,
718
+ {
719
+ type: curveType,
720
+ dataKey: dk,
721
+ stroke: `url(#${chartId}-zm-${dk})`,
722
+ fill: `url(#${chartId}-zm-fill-${dk})`,
723
+ strokeWidth: 1,
724
+ strokeOpacity: 0.5,
725
+ strokeDasharray: dashArray,
726
+ connectNulls,
727
+ fillOpacity: 1,
728
+ stackId: stacked ? "zm-stack" : void 0,
729
+ dot: false,
730
+ activeDot: false,
731
+ isAnimationActive: false
732
+ },
733
+ dk
734
+ ))
735
+ ] }) });
736
+ }
737
+ function useBrush({
738
+ data,
739
+ defaultStartIndex = 0,
740
+ defaultEndIndex
741
+ }) {
742
+ const [range, setRange] = React.useState({
743
+ startIndex: defaultStartIndex,
744
+ endIndex: defaultEndIndex ?? Math.max(0, data.length - 1)
745
+ });
746
+ const deferredRange = React.useDeferredValue(range);
747
+ useEffect(() => {
748
+ setRange({
749
+ startIndex: 0,
750
+ endIndex: Math.max(0, data.length - 1)
751
+ });
752
+ }, [data.length]);
753
+ const visibleData = React.useMemo(
754
+ () => data.slice(deferredRange.startIndex, deferredRange.endIndex + 1),
755
+ [data, deferredRange.startIndex, deferredRange.endIndex]
756
+ );
757
+ return {
758
+ range,
759
+ visibleData,
760
+ brushProps: {
761
+ startIndex: range.startIndex,
762
+ endIndex: range.endIndex,
763
+ onChange: setRange
764
+ }
765
+ };
766
+ }
767
+
768
+ // src/components/charts/chart-legend.tsx
769
+ import * as RechartsPrimitive2 from "recharts";
770
+ import "react";
771
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
772
+ function ChartLegendContent({
773
+ className,
774
+ hideIcon = false,
775
+ nameKey,
776
+ payload,
777
+ verticalAlign,
778
+ align = "right",
779
+ selected,
780
+ onSelectChange,
781
+ isClickable,
782
+ variant = "rounded-square"
783
+ }) {
784
+ const { config } = useChart();
785
+ if (!payload?.length) {
786
+ return null;
787
+ }
788
+ return /* @__PURE__ */ jsx3(
789
+ "div",
790
+ {
791
+ className: cn(
792
+ "flex items-center gap-4 select-none",
793
+ align === "left" && "justify-start",
794
+ align === "center" && "justify-center",
795
+ align === "right" && "justify-end",
796
+ verticalAlign === "top" ? "pb-4" : "pt-4",
797
+ className
798
+ ),
799
+ children: payload.filter((item) => item.type !== "none").map((item) => {
800
+ const payloadName = nameKey && item.payload ? item.payload[nameKey] : void 0;
801
+ const key = `${payloadName ?? item.value ?? item.dataKey ?? "value"}`;
802
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
803
+ const isSelected = selected === null || selected === key;
804
+ const colorsCount = itemConfig ? getColorsCount(itemConfig) : 1;
805
+ return /* @__PURE__ */ jsxs3(
806
+ "div",
807
+ {
808
+ className: cn(
809
+ "[&>svg]:text-bruv-secondary flex items-center gap-1.5 transition-opacity [&>svg]:h-3 [&>svg]:w-3",
810
+ !isSelected && "opacity-30",
811
+ isClickable && "cursor-pointer"
812
+ ),
813
+ onClick: () => {
814
+ if (!isClickable) return;
815
+ onSelectChange?.(selected === key ? null : key);
816
+ },
817
+ children: [
818
+ itemConfig?.icon && !hideIcon ? /* @__PURE__ */ jsx3(itemConfig.icon, {}) : /* @__PURE__ */ jsx3(
819
+ LegendIndicator,
820
+ {
821
+ variant,
822
+ dataKey: key,
823
+ colorsCount
824
+ }
825
+ ),
826
+ itemConfig?.label
827
+ ]
828
+ },
829
+ key
830
+ );
831
+ })
832
+ }
833
+ );
834
+ }
835
+ function LegendIndicator({
836
+ variant,
837
+ dataKey,
838
+ colorsCount
839
+ }) {
840
+ const fillStyle = getLegendFillStyle(dataKey, colorsCount);
841
+ const outlineStyle = getLegendOutlineStyle(dataKey, colorsCount);
842
+ switch (variant) {
843
+ case "square":
844
+ return /* @__PURE__ */ jsx3("div", { className: "h-2 w-2 shrink-0", style: fillStyle });
845
+ case "circle":
846
+ return /* @__PURE__ */ jsx3("div", { className: "h-2 w-2 shrink-0 rounded-full", style: fillStyle });
847
+ case "circle-outline":
848
+ return /* @__PURE__ */ jsx3(
849
+ "div",
850
+ {
851
+ className: "h-2.5 w-2.5 shrink-0 rounded-full p-[1.5px]",
852
+ style: outlineStyle
853
+ }
854
+ );
855
+ case "vertical-bar":
856
+ return /* @__PURE__ */ jsx3("div", { className: "h-3 w-1 shrink-0 rounded-[2px]", style: fillStyle });
857
+ case "horizontal-bar":
858
+ return /* @__PURE__ */ jsx3("div", { className: "h-1 w-3 shrink-0 rounded-[2px]", style: fillStyle });
859
+ case "rounded-square-outline":
860
+ return /* @__PURE__ */ jsx3(
861
+ "div",
862
+ {
863
+ className: "h-2.5 w-2.5 shrink-0 rounded-[3px] p-[1.5px]",
864
+ style: outlineStyle
865
+ }
866
+ );
867
+ case "rounded-square":
868
+ default:
869
+ return /* @__PURE__ */ jsx3("div", { className: "h-2 w-2 shrink-0 rounded-[2px]", style: fillStyle });
870
+ }
871
+ }
872
+ function getLegendFillStyle(dataKey, colorsCount) {
873
+ if (colorsCount <= 1) {
874
+ return { backgroundColor: `var(--color-${dataKey}-0)` };
875
+ }
876
+ const stops = Array.from({ length: colorsCount }, (_, i) => {
877
+ const offset = i / (colorsCount - 1) * 100;
878
+ return `var(--color-${dataKey}-${i}) ${offset}%`;
879
+ }).join(", ");
880
+ return { background: `linear-gradient(to right, ${stops})` };
881
+ }
882
+ function getLegendOutlineStyle(dataKey, colorsCount) {
883
+ const maskStyle = {
884
+ WebkitMask: "linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)",
885
+ WebkitMaskComposite: "xor",
886
+ mask: "linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)",
887
+ maskComposite: "exclude"
888
+ };
889
+ if (colorsCount <= 1) {
890
+ return {
891
+ backgroundColor: `var(--color-${dataKey}-0)`,
892
+ ...maskStyle
893
+ };
894
+ }
895
+ const stops = Array.from({ length: colorsCount }, (_, i) => {
896
+ const offset = i / (colorsCount - 1) * 100;
897
+ return `var(--color-${dataKey}-${i}) ${offset}%`;
898
+ }).join(", ");
899
+ return {
900
+ background: `linear-gradient(to right, ${stops})`,
901
+ ...maskStyle
902
+ };
903
+ }
904
+ var ChartLegend = RechartsPrimitive2.Legend;
905
+
906
+ // src/components/charts/chart-tooltip.tsx
907
+ import * as RechartsPrimitive3 from "recharts";
908
+ import * as React3 from "react";
909
+ import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
910
+ var roundnessMap = {
911
+ sm: "rounded-bruv-sm",
912
+ md: "rounded-bruv-md",
913
+ lg: "rounded-bruv-lg",
914
+ xl: "rounded-bruv-xl"
915
+ };
916
+ var variantMap = {
917
+ default: "bg-bruv-base-2",
918
+ "frosted-glass": "bg-bruv-base-2/70 backdrop-blur-sm"
919
+ };
920
+ function ChartTooltipContent({
921
+ active,
922
+ payload,
923
+ className,
924
+ indicator = "dot",
925
+ hideLabel = false,
926
+ hideIndicator = false,
927
+ label,
928
+ labelFormatter,
929
+ labelClassName,
930
+ formatter,
931
+ nameKey,
932
+ labelKey,
933
+ selected,
934
+ roundness = "lg",
935
+ variant = "default"
936
+ }) {
937
+ const { config } = useChart();
938
+ const tooltipLabel = React3.useMemo(() => {
939
+ if (hideLabel || !payload?.length) {
940
+ return null;
941
+ }
942
+ const [item] = payload;
943
+ const key = `${labelKey ?? item?.dataKey ?? item?.name ?? "value"}`;
944
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
945
+ const value = !labelKey && typeof label === "string" ? config[label]?.label ?? label : itemConfig?.label;
946
+ if (labelFormatter) {
947
+ return /* @__PURE__ */ jsx4("div", { className: cn("font-medium", labelClassName), children: labelFormatter(value, payload) });
948
+ }
949
+ if (!value) {
950
+ return null;
951
+ }
952
+ return /* @__PURE__ */ jsx4("div", { className: cn("font-medium", labelClassName), children: value });
953
+ }, [
954
+ label,
955
+ labelFormatter,
956
+ payload,
957
+ hideLabel,
958
+ labelClassName,
959
+ config,
960
+ labelKey
961
+ ]);
962
+ if (!active || !payload?.length) {
963
+ return /* @__PURE__ */ jsx4("span", { className: "p-4" });
964
+ }
965
+ const nestLabel = payload.length === 1 && indicator !== "dot";
966
+ return /* @__PURE__ */ jsxs4(
967
+ "div",
968
+ {
969
+ className: cn(
970
+ "border-bruv-neutral/50 grid min-w-32 items-start gap-1.5 border px-2.5 py-1.5 text-xs shadow-xl",
971
+ roundnessMap[roundness],
972
+ variantMap[variant],
973
+ className
974
+ ),
975
+ children: [
976
+ !nestLabel ? tooltipLabel : null,
977
+ /* @__PURE__ */ jsx4("div", { className: "grid gap-1.5", children: payload.filter((item) => item.type !== "none").map((item, index) => {
978
+ const payloadName = nameKey && item.payload ? item.payload[nameKey] : void 0;
979
+ const key = `${payloadName ?? item.name ?? item.dataKey ?? "value"}`;
980
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
981
+ const colorsCount = itemConfig ? getColorsCount(itemConfig) : 1;
982
+ return /* @__PURE__ */ jsx4(
983
+ "div",
984
+ {
985
+ className: cn(
986
+ "[&>svg]:text-bruv-secondary flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5",
987
+ indicator === "dot" && "items-center",
988
+ selected != null && selected !== item.dataKey && "opacity-30"
989
+ ),
990
+ children: formatter && item?.value !== void 0 && item.name ? formatter(item.value, item.name, item, index, item.payload) : /* @__PURE__ */ jsxs4(Fragment3, { children: [
991
+ itemConfig?.icon ? /* @__PURE__ */ jsx4(itemConfig.icon, {}) : !hideIndicator && /* @__PURE__ */ jsx4(
992
+ "div",
993
+ {
994
+ className: cn("shrink-0 rounded-[2px]", {
995
+ "h-2.5 w-2.5": indicator === "dot",
996
+ "w-1": indicator === "line",
997
+ "w-0 border-[1.5px] border-dashed bg-transparent!": indicator === "dashed",
998
+ "my-0.5": nestLabel && indicator === "dashed"
999
+ }),
1000
+ style: getIndicatorColorStyle(key, colorsCount)
1001
+ }
1002
+ ),
1003
+ /* @__PURE__ */ jsxs4(
1004
+ "div",
1005
+ {
1006
+ className: cn(
1007
+ "flex flex-1 justify-between gap-4 leading-none",
1008
+ nestLabel ? "items-end" : "items-center"
1009
+ ),
1010
+ children: [
1011
+ /* @__PURE__ */ jsxs4("div", { className: "grid gap-1.5", children: [
1012
+ nestLabel ? tooltipLabel : null,
1013
+ /* @__PURE__ */ jsx4("span", { className: "text-bruv-secondary", children: itemConfig?.label ?? item.name })
1014
+ ] }),
1015
+ item.value != null && /* @__PURE__ */ jsx4("span", { className: "text-bruv-primary font-mono font-medium tabular-nums", children: typeof item.value === "number" ? item.value.toLocaleString() : String(item.value) })
1016
+ ]
1017
+ }
1018
+ )
1019
+ ] })
1020
+ },
1021
+ index
1022
+ );
1023
+ }) })
1024
+ ]
1025
+ }
1026
+ );
1027
+ }
1028
+ function getIndicatorColorStyle(dataKey, colorsCount) {
1029
+ if (colorsCount <= 1) {
1030
+ return { background: `var(--color-${dataKey}-0)` };
1031
+ }
1032
+ const stops = Array.from({ length: colorsCount }, (_, index) => {
1033
+ const offset = index / (colorsCount - 1) * 100;
1034
+ return `var(--color-${dataKey}-${index}) ${offset}%`;
1035
+ }).join(", ");
1036
+ return { background: `linear-gradient(to right, ${stops})` };
1037
+ }
1038
+ var ChartTooltip = ({
1039
+ animationDuration = 200,
1040
+ ...props
1041
+ }) => /* @__PURE__ */ jsx4(RechartsPrimitive3.Tooltip, { animationDuration, ...props });
1042
+
1043
+ // src/components/charts/chart-dot.tsx
1044
+ import * as React4 from "react";
1045
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1046
+ var ChartDot = React4.memo(function ChartDot2({
1047
+ cx,
1048
+ cy,
1049
+ dataKey,
1050
+ chartId,
1051
+ className,
1052
+ fillOpacity = 1,
1053
+ type = "default",
1054
+ maskId
1055
+ }) {
1056
+ const dotId = React4.useId().replace(/:/g, "");
1057
+ const gradientUrl = `url(#${chartId}-colors-${String(dataKey)})`;
1058
+ if (cx === void 0 || cy === void 0) return null;
1059
+ switch (type) {
1060
+ case "border":
1061
+ return /* @__PURE__ */ jsx5(
1062
+ PrimaryBorderDot,
1063
+ {
1064
+ cx,
1065
+ cy,
1066
+ dotId,
1067
+ fillOpacity,
1068
+ gradientUrl,
1069
+ className,
1070
+ maskId
1071
+ }
1072
+ );
1073
+ case "colored-border":
1074
+ return /* @__PURE__ */ jsx5(
1075
+ ColoredBorderDot,
1076
+ {
1077
+ cx,
1078
+ cy,
1079
+ dotId,
1080
+ fillOpacity,
1081
+ gradientUrl,
1082
+ className,
1083
+ maskId
1084
+ }
1085
+ );
1086
+ default:
1087
+ return /* @__PURE__ */ jsx5(
1088
+ DefaultDot,
1089
+ {
1090
+ cx,
1091
+ cy,
1092
+ dotId,
1093
+ fillOpacity,
1094
+ gradientUrl,
1095
+ className,
1096
+ maskId
1097
+ }
1098
+ );
1099
+ }
1100
+ });
1101
+ var DefaultDot = React4.memo(
1102
+ ({
1103
+ cx,
1104
+ cy,
1105
+ dotId,
1106
+ fillOpacity,
1107
+ gradientUrl,
1108
+ className,
1109
+ maskId
1110
+ }) => {
1111
+ const r = 3;
1112
+ return /* @__PURE__ */ jsxs5("g", { className, mask: maskId ? `url(#${maskId})` : void 0, children: [
1113
+ /* @__PURE__ */ jsx5("defs", { children: /* @__PURE__ */ jsx5("clipPath", { id: `dot-clip-${dotId}`, children: /* @__PURE__ */ jsx5("circle", { cx, cy, r }) }) }),
1114
+ /* @__PURE__ */ jsx5(
1115
+ "rect",
1116
+ {
1117
+ x: "0",
1118
+ y: cy - r,
1119
+ width: "100%",
1120
+ height: r * 2,
1121
+ fill: gradientUrl,
1122
+ fillOpacity,
1123
+ clipPath: `url(#dot-clip-${dotId})`
1124
+ }
1125
+ )
1126
+ ] });
1127
+ }
1128
+ );
1129
+ DefaultDot.displayName = "DefaultDot";
1130
+ var PrimaryBorderDot = React4.memo(
1131
+ ({
1132
+ cx,
1133
+ cy,
1134
+ dotId,
1135
+ fillOpacity,
1136
+ gradientUrl,
1137
+ className,
1138
+ maskId
1139
+ }) => {
1140
+ const r = 6;
1141
+ const strokeWidth = 5;
1142
+ return /* @__PURE__ */ jsxs5(
1143
+ "g",
1144
+ {
1145
+ className: cn(className, "text-bruv-base-1"),
1146
+ mask: maskId ? `url(#${maskId})` : void 0,
1147
+ children: [
1148
+ /* @__PURE__ */ jsx5("defs", { children: /* @__PURE__ */ jsx5("clipPath", { id: `dot-clip-${dotId}`, children: /* @__PURE__ */ jsx5("circle", { cx, cy, r }) }) }),
1149
+ /* @__PURE__ */ jsx5("circle", { cx, cy, r, fill: "currentColor" }),
1150
+ /* @__PURE__ */ jsx5(
1151
+ "rect",
1152
+ {
1153
+ x: "0",
1154
+ y: cy - (r - strokeWidth / 2),
1155
+ width: "100%",
1156
+ height: (r - strokeWidth / 2) * 2,
1157
+ fill: gradientUrl,
1158
+ fillOpacity,
1159
+ clipPath: `url(#dot-clip-inner-${dotId})`
1160
+ }
1161
+ ),
1162
+ /* @__PURE__ */ jsx5("defs", { children: /* @__PURE__ */ jsx5("clipPath", { id: `dot-clip-inner-${dotId}`, children: /* @__PURE__ */ jsx5("circle", { cx, cy, r: r - strokeWidth / 2 }) }) })
1163
+ ]
1164
+ }
1165
+ );
1166
+ }
1167
+ );
1168
+ PrimaryBorderDot.displayName = "PrimaryBorderDot";
1169
+ var ColoredBorderDot = React4.memo(
1170
+ ({
1171
+ cx,
1172
+ cy,
1173
+ dotId,
1174
+ fillOpacity,
1175
+ gradientUrl,
1176
+ className,
1177
+ maskId
1178
+ }) => {
1179
+ const r = 3;
1180
+ const strokeWidth = 1;
1181
+ return /* @__PURE__ */ jsxs5(
1182
+ "g",
1183
+ {
1184
+ className: cn(className, "text-bruv-base-1"),
1185
+ mask: maskId ? `url(#${maskId})` : void 0,
1186
+ children: [
1187
+ /* @__PURE__ */ jsx5("defs", { children: /* @__PURE__ */ jsx5("clipPath", { id: `dot-clip-${dotId}`, children: /* @__PURE__ */ jsx5("circle", { cx, cy, r: r + strokeWidth / 2 }) }) }),
1188
+ /* @__PURE__ */ jsx5(
1189
+ "rect",
1190
+ {
1191
+ x: "0",
1192
+ y: cy - r - strokeWidth / 2,
1193
+ width: "100%",
1194
+ height: (r + strokeWidth / 2) * 2,
1195
+ fill: gradientUrl,
1196
+ fillOpacity,
1197
+ clipPath: `url(#dot-clip-${dotId})`
1198
+ }
1199
+ ),
1200
+ /* @__PURE__ */ jsx5("circle", { cx, cy, r: r - strokeWidth / 2, fill: "currentColor" })
1201
+ ]
1202
+ }
1203
+ );
1204
+ }
1205
+ );
1206
+ ColoredBorderDot.displayName = "ColoredBorderDot";
1207
+
1208
+ // src/components/charts/composed-chart.tsx
1209
+ import {
1210
+ Children,
1211
+ createContext as createContext2,
1212
+ isValidElement,
1213
+ use,
1214
+ useCallback as useCallback2,
1215
+ useId as useId4,
1216
+ useMemo as useMemo3,
1217
+ useRef as useRef2,
1218
+ useState as useState2
1219
+ } from "react";
1220
+ import {
1221
+ Bar as RechartsBar,
1222
+ CartesianGrid,
1223
+ ComposedChart as RechartsComposedChart,
1224
+ Line as RechartsLine,
1225
+ XAxis as RechartsXAxis,
1226
+ YAxis as RechartsYAxis
1227
+ } from "recharts";
1228
+ import { motion as motion2, useReducedMotion } from "motion/react";
1229
+ import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1230
+ var STROKE_WIDTH = 2;
1231
+ var DEFAULT_BAR_RADIUS = 4;
1232
+ var LOADING_DATA_KEY = "loading";
1233
+ var LOADING_ANIMATION_DURATION = 2e3;
1234
+ var REVEAL_DURATION = 1;
1235
+ var REVEAL_EASE = [0, 0.7, 0.5, 1];
1236
+ var BAR_GROW_DURATION = 0.5;
1237
+ var BAR_STAGGER = 0.05;
1238
+ var ComposedChartContext = createContext2(
1239
+ null
1240
+ );
1241
+ function useComposedChart() {
1242
+ const context = use(ComposedChartContext);
1243
+ if (!context) {
1244
+ throw new Error(
1245
+ "Composed chart parts (<Bar />, <Line />, <XAxis />, \u2026) must be used within <ComposedChart />"
1246
+ );
1247
+ }
1248
+ return context;
1249
+ }
1250
+ function ComposedChart({
1251
+ config,
1252
+ data,
1253
+ children,
1254
+ className,
1255
+ chartProps,
1256
+ curveType = "linear",
1257
+ animationType = "left-to-right",
1258
+ barGap,
1259
+ barCategoryGap,
1260
+ defaultSelectedDataKey = null,
1261
+ onSelectionChange,
1262
+ isLoading = false,
1263
+ loadingBars,
1264
+ showBrush = false,
1265
+ xDataKey,
1266
+ brushHeight,
1267
+ brushFormatLabel,
1268
+ onBrushChange
1269
+ }) {
1270
+ const chartId = useId4().replace(/:/g, "");
1271
+ const [introStartedAt] = useState2(() => Date.now());
1272
+ const [selectedDataKey, setSelectedDataKey] = useState2(
1273
+ defaultSelectedDataKey
1274
+ );
1275
+ const [hoveredIndex, setHoveredIndex] = useState2(null);
1276
+ const { loadingData, onShimmerExit } = useLoadingData(isLoading, loadingBars);
1277
+ const { visibleData, brushProps } = useBrush({ data });
1278
+ const displayData = showBrush && !isLoading ? visibleData : data;
1279
+ const selectDataKey = useCallback2(
1280
+ (newSelectedDataKey) => {
1281
+ setSelectedDataKey(newSelectedDataKey);
1282
+ onSelectionChange?.(newSelectedDataKey);
1283
+ },
1284
+ [onSelectionChange]
1285
+ );
1286
+ const contextValue = useMemo3(
1287
+ () => ({
1288
+ config,
1289
+ curveType,
1290
+ animationType,
1291
+ introStartedAt,
1292
+ dataLength: displayData.length,
1293
+ isLoading,
1294
+ hoveredIndex,
1295
+ selectedDataKey,
1296
+ selectDataKey
1297
+ }),
1298
+ [
1299
+ config,
1300
+ curveType,
1301
+ animationType,
1302
+ introStartedAt,
1303
+ displayData.length,
1304
+ isLoading,
1305
+ hoveredIndex,
1306
+ selectedDataKey,
1307
+ selectDataKey
1308
+ ]
1309
+ );
1310
+ return /* @__PURE__ */ jsx6(ComposedChartContext, { value: contextValue, children: /* @__PURE__ */ jsxs6(
1311
+ Chart,
1312
+ {
1313
+ className,
1314
+ config,
1315
+ footer: showBrush && !isLoading && /* @__PURE__ */ jsx6(
1316
+ Brush,
1317
+ {
1318
+ data,
1319
+ chartConfig: config,
1320
+ xDataKey,
1321
+ variant: "area",
1322
+ curveType,
1323
+ height: brushHeight,
1324
+ formatLabel: brushFormatLabel,
1325
+ skipStyle: true,
1326
+ className: "mt-1",
1327
+ ...brushProps,
1328
+ onChange: (range) => {
1329
+ brushProps.onChange(range);
1330
+ onBrushChange?.(range);
1331
+ }
1332
+ }
1333
+ ),
1334
+ children: [
1335
+ /* @__PURE__ */ jsx6(LoadingIndicator, { isLoading }),
1336
+ /* @__PURE__ */ jsxs6(
1337
+ RechartsComposedChart,
1338
+ {
1339
+ id: chartId,
1340
+ accessibilityLayer: true,
1341
+ data: isLoading ? loadingData : displayData,
1342
+ barGap,
1343
+ barCategoryGap,
1344
+ onMouseLeave: () => setHoveredIndex(null),
1345
+ ...chartProps,
1346
+ children: [
1347
+ children,
1348
+ isLoading && /* @__PURE__ */ jsx6(
1349
+ LoadingBar,
1350
+ {
1351
+ chartId,
1352
+ barRadius: DEFAULT_BAR_RADIUS,
1353
+ onShimmerExit
1354
+ }
1355
+ )
1356
+ ]
1357
+ }
1358
+ )
1359
+ ]
1360
+ }
1361
+ ) });
1362
+ }
1363
+ function Bar2({
1364
+ dataKey,
1365
+ variant = "default",
1366
+ radius = DEFAULT_BAR_RADIUS,
1367
+ animationType,
1368
+ isClickable = false,
1369
+ enableHoverHighlight = false,
1370
+ barProps
1371
+ }) {
1372
+ const {
1373
+ config,
1374
+ animationType: defaultAnimation,
1375
+ introStartedAt,
1376
+ dataLength,
1377
+ isLoading,
1378
+ hoveredIndex,
1379
+ selectedDataKey,
1380
+ selectDataKey
1381
+ } = useComposedChart();
1382
+ const id = useId4().replace(/:/g, "");
1383
+ const shouldReduceMotion = useReducedMotion();
1384
+ if (isLoading) return null;
1385
+ const isSelected = selectedDataKey === null || selectedDataKey === dataKey;
1386
+ const revealType = shouldReduceMotion ? "none" : animationType ?? defaultAnimation;
1387
+ return /* @__PURE__ */ jsxs6(Fragment4, { children: [
1388
+ /* @__PURE__ */ jsx6(
1389
+ RechartsBar,
1390
+ {
1391
+ dataKey,
1392
+ fill: `url(#${id}-bar-colors)`,
1393
+ radius,
1394
+ isAnimationActive: false,
1395
+ style: isClickable || enableHoverHighlight ? { cursor: "pointer" } : void 0,
1396
+ shape: (props) => {
1397
+ const barShapeProps = props;
1398
+ const index = typeof barShapeProps.index === "number" ? barShapeProps.index : -1;
1399
+ return /* @__PURE__ */ jsx6(
1400
+ CustomBar,
1401
+ {
1402
+ ...barShapeProps,
1403
+ id,
1404
+ variant,
1405
+ barRadius: radius,
1406
+ fillOpacity: getBarOpacity({
1407
+ isClickable,
1408
+ isSelected,
1409
+ selectedDataKey,
1410
+ enableHoverHighlight,
1411
+ hoveredIndex,
1412
+ index
1413
+ }),
1414
+ isClickable,
1415
+ enableHoverHighlight,
1416
+ animationType: revealType,
1417
+ dataLength,
1418
+ introStartedAt,
1419
+ onClick: () => {
1420
+ if (!isClickable) return;
1421
+ selectDataKey(selectedDataKey === dataKey ? null : dataKey);
1422
+ }
1423
+ }
1424
+ );
1425
+ },
1426
+ ...barProps
1427
+ }
1428
+ ),
1429
+ /* @__PURE__ */ jsxs6("defs", { children: [
1430
+ /* @__PURE__ */ jsx6(VerticalColorGradient, { id, dataKey, config }),
1431
+ variant === "duotone" && /* @__PURE__ */ jsx6(DuotonePattern, { id, dataKey, config }),
1432
+ variant === "duotone-reverse" && /* @__PURE__ */ jsx6(DuotoneReversePattern, { id, dataKey, config }),
1433
+ variant === "gradient" && /* @__PURE__ */ jsx6(GradientPattern, { id, dataKey }),
1434
+ variant === "stripped" && /* @__PURE__ */ jsx6(StrippedPattern, { id, dataKey })
1435
+ ] })
1436
+ ] });
1437
+ }
1438
+ function Line2({
1439
+ dataKey,
1440
+ strokeVariant = "solid",
1441
+ curveType,
1442
+ animationType,
1443
+ connectNulls = false,
1444
+ isClickable = false,
1445
+ children,
1446
+ lineProps
1447
+ }) {
1448
+ const {
1449
+ config,
1450
+ curveType: defaultCurve,
1451
+ animationType: defaultAnimation,
1452
+ isLoading,
1453
+ selectedDataKey,
1454
+ selectDataKey
1455
+ } = useComposedChart();
1456
+ const id = useId4().replace(/:/g, "");
1457
+ const shouldReduceMotion = useReducedMotion();
1458
+ if (isLoading) return null;
1459
+ const resolvedCurve = curveType ?? defaultCurve;
1460
+ const revealType = shouldReduceMotion ? "none" : animationType ?? defaultAnimation;
1461
+ const maskId = revealType === "none" ? void 0 : `${id}-reveal-mask`;
1462
+ const opacity = getOpacity(selectedDataKey, dataKey);
1463
+ const hasSelection = selectedDataKey !== null;
1464
+ const { dot, activeDot } = resolveDots(
1465
+ children,
1466
+ id,
1467
+ dataKey,
1468
+ opacity.dot,
1469
+ maskId
1470
+ );
1471
+ const isAnimatedDashed = strokeVariant === "animated-dashed";
1472
+ const isDashed = strokeVariant === "dashed" || isAnimatedDashed;
1473
+ const handleLineClick = () => {
1474
+ if (!isClickable) return;
1475
+ selectDataKey(selectedDataKey === dataKey ? null : dataKey);
1476
+ };
1477
+ return /* @__PURE__ */ jsxs6(Fragment4, { children: [
1478
+ isClickable && /* @__PURE__ */ jsx6(
1479
+ RechartsLine,
1480
+ {
1481
+ type: resolvedCurve,
1482
+ dataKey,
1483
+ connectNulls,
1484
+ stroke: "transparent",
1485
+ strokeWidth: 20,
1486
+ dot: false,
1487
+ activeDot: false,
1488
+ isAnimationActive: false,
1489
+ legendType: "none",
1490
+ tooltipType: "none",
1491
+ style: { cursor: "pointer" },
1492
+ onClick: handleLineClick
1493
+ }
1494
+ ),
1495
+ /* @__PURE__ */ jsx6(
1496
+ RechartsLine,
1497
+ {
1498
+ type: resolvedCurve,
1499
+ dataKey,
1500
+ connectNulls,
1501
+ strokeOpacity: opacity.stroke,
1502
+ stroke: `url(#${id}-line-colors-${dataKey})`,
1503
+ dot,
1504
+ activeDot,
1505
+ strokeWidth: STROKE_WIDTH,
1506
+ strokeDasharray: isDashed ? "5 5" : void 0,
1507
+ isAnimationActive: false,
1508
+ style: {
1509
+ ...maskId ? { mask: `url(#${maskId})` } : {},
1510
+ ...isClickable ? { cursor: "pointer", pointerEvents: "none" } : {}
1511
+ },
1512
+ ...lineProps,
1513
+ children: isAnimatedDashed && !hasSelection && /* @__PURE__ */ jsx6(AnimatedDashedStroke, {})
1514
+ }
1515
+ ),
1516
+ /* @__PURE__ */ jsxs6("defs", { children: [
1517
+ revealType !== "none" && /* @__PURE__ */ jsx6(RevealMask, { id, type: revealType }),
1518
+ /* @__PURE__ */ jsx6(HorizontalColorGradient, { id, dataKey, config })
1519
+ ] })
1520
+ ] });
1521
+ }
1522
+ var Dot = () => null;
1523
+ var ActiveDot = () => null;
1524
+ function XAxis({
1525
+ tickLine = false,
1526
+ axisLine = false,
1527
+ tickMargin = 8,
1528
+ minTickGap = 8,
1529
+ ...props
1530
+ }) {
1531
+ const { isLoading } = useComposedChart();
1532
+ if (isLoading) return null;
1533
+ return /* @__PURE__ */ jsx6(
1534
+ RechartsXAxis,
1535
+ {
1536
+ tickLine,
1537
+ axisLine,
1538
+ tickMargin,
1539
+ minTickGap,
1540
+ ...props
1541
+ }
1542
+ );
1543
+ }
1544
+ function YAxis({
1545
+ tickLine = false,
1546
+ axisLine = false,
1547
+ tickMargin = 8,
1548
+ minTickGap = 8,
1549
+ width = "auto",
1550
+ ...props
1551
+ }) {
1552
+ const { isLoading } = useComposedChart();
1553
+ if (isLoading) return null;
1554
+ return /* @__PURE__ */ jsx6(
1555
+ RechartsYAxis,
1556
+ {
1557
+ tickLine,
1558
+ axisLine,
1559
+ tickMargin,
1560
+ minTickGap,
1561
+ width,
1562
+ ...props
1563
+ }
1564
+ );
1565
+ }
1566
+ function Grid({
1567
+ vertical = false,
1568
+ strokeDasharray = "3 3",
1569
+ ...props
1570
+ }) {
1571
+ return /* @__PURE__ */ jsx6(
1572
+ CartesianGrid,
1573
+ {
1574
+ vertical,
1575
+ strokeDasharray,
1576
+ ...props
1577
+ }
1578
+ );
1579
+ }
1580
+ function Tooltip2({
1581
+ variant,
1582
+ roundness,
1583
+ defaultIndex,
1584
+ cursor = true
1585
+ }) {
1586
+ const { isLoading, selectedDataKey } = useComposedChart();
1587
+ if (isLoading) return null;
1588
+ return /* @__PURE__ */ jsx6(
1589
+ ChartTooltip,
1590
+ {
1591
+ defaultIndex,
1592
+ cursor: cursor ? { strokeDasharray: "3 3", strokeWidth: STROKE_WIDTH } : false,
1593
+ content: /* @__PURE__ */ jsx6(
1594
+ ChartTooltipContent,
1595
+ {
1596
+ selected: selectedDataKey,
1597
+ roundness,
1598
+ variant
1599
+ }
1600
+ )
1601
+ }
1602
+ );
1603
+ }
1604
+ function Legend2({
1605
+ variant,
1606
+ align = "right",
1607
+ verticalAlign = "top",
1608
+ isClickable = false
1609
+ }) {
1610
+ const { selectedDataKey, selectDataKey } = useComposedChart();
1611
+ return /* @__PURE__ */ jsx6(
1612
+ ChartLegend,
1613
+ {
1614
+ verticalAlign,
1615
+ align,
1616
+ content: /* @__PURE__ */ jsx6(
1617
+ ChartLegendContent,
1618
+ {
1619
+ selected: selectedDataKey,
1620
+ onSelectChange: selectDataKey,
1621
+ isClickable,
1622
+ variant
1623
+ }
1624
+ )
1625
+ }
1626
+ );
1627
+ }
1628
+ var getOpacity = (selectedDataKey, dataKey) => {
1629
+ if (selectedDataKey === null) {
1630
+ return { stroke: 1, dot: 1 };
1631
+ }
1632
+ return selectedDataKey === dataKey ? { stroke: 1, dot: 1 } : { stroke: 0.3, dot: 0.3 };
1633
+ };
1634
+ var getBarOpacity = ({
1635
+ isClickable,
1636
+ isSelected,
1637
+ selectedDataKey,
1638
+ enableHoverHighlight,
1639
+ hoveredIndex,
1640
+ index
1641
+ }) => {
1642
+ const clickOpacity = isClickable && selectedDataKey !== null ? isSelected ? 1 : 0.3 : 1;
1643
+ if (enableHoverHighlight && hoveredIndex !== null) {
1644
+ return hoveredIndex === index ? clickOpacity : clickOpacity * 0.3;
1645
+ }
1646
+ return clickOpacity;
1647
+ };
1648
+ var resolveDots = (children, id, dataKey, dotOpacity, maskId) => {
1649
+ let dot = false;
1650
+ let activeDot = false;
1651
+ Children.forEach(children, (child) => {
1652
+ if (!isValidElement(child)) return;
1653
+ if (child.type === Dot) {
1654
+ const { variant } = child.props;
1655
+ dot = /* @__PURE__ */ jsx6(
1656
+ ChartDot,
1657
+ {
1658
+ type: variant,
1659
+ dataKey,
1660
+ chartId: `${id}-line`,
1661
+ fillOpacity: dotOpacity,
1662
+ maskId
1663
+ }
1664
+ );
1665
+ }
1666
+ if (child.type === ActiveDot) {
1667
+ const { variant } = child.props;
1668
+ activeDot = /* @__PURE__ */ jsx6(
1669
+ ChartDot,
1670
+ {
1671
+ type: variant,
1672
+ dataKey,
1673
+ chartId: `${id}-line`,
1674
+ fillOpacity: dotOpacity
1675
+ }
1676
+ );
1677
+ }
1678
+ });
1679
+ return { dot, activeDot };
1680
+ };
1681
+ var CustomBar = ({
1682
+ x = 0,
1683
+ y = 0,
1684
+ width = 0,
1685
+ height = 0,
1686
+ fillOpacity = 1,
1687
+ background,
1688
+ index = -1,
1689
+ id,
1690
+ variant,
1691
+ barRadius,
1692
+ isClickable,
1693
+ enableHoverHighlight,
1694
+ animationType = "none",
1695
+ dataLength = 0,
1696
+ introStartedAt = 0,
1697
+ onClick
1698
+ }) => {
1699
+ const cursorStyle = isClickable || enableHoverHighlight ? { cursor: "pointer" } : void 0;
1700
+ const hitAreaX = background?.x ?? x;
1701
+ const hitAreaY = background?.y ?? y;
1702
+ const hitAreaWidth = background?.width ?? width;
1703
+ const hitAreaHeight = background?.height ?? height;
1704
+ const grow = getBarGrowAnimation(animationType, index, dataLength, introStartedAt) ?? {};
1705
+ const getFill = () => {
1706
+ switch (variant) {
1707
+ case "duotone":
1708
+ return `url(#${id}-duotone)`;
1709
+ case "duotone-reverse":
1710
+ return `url(#${id}-duotone-reverse)`;
1711
+ case "gradient":
1712
+ return `url(#${id}-gradient)`;
1713
+ case "stripped":
1714
+ return `url(#${id}-stripped)`;
1715
+ default:
1716
+ return `url(#${id}-bar-colors)`;
1717
+ }
1718
+ };
1719
+ const hitArea = enableHoverHighlight ? /* @__PURE__ */ jsx6(
1720
+ "rect",
1721
+ {
1722
+ x: hitAreaX,
1723
+ y: hitAreaY,
1724
+ width: hitAreaWidth,
1725
+ height: hitAreaHeight,
1726
+ fill: "transparent"
1727
+ }
1728
+ ) : null;
1729
+ if (variant === "stripped") {
1730
+ return /* @__PURE__ */ jsxs6("g", { style: cursorStyle, onClick, children: [
1731
+ /* @__PURE__ */ jsxs6(
1732
+ motion2.g,
1733
+ {
1734
+ ...grow,
1735
+ opacity: fillOpacity,
1736
+ className: "transition-opacity duration-200",
1737
+ children: [
1738
+ /* @__PURE__ */ jsx6("rect", { x, y, width, height, fill: getFill() }),
1739
+ /* @__PURE__ */ jsx6(
1740
+ "rect",
1741
+ {
1742
+ x,
1743
+ y,
1744
+ width,
1745
+ height: 2,
1746
+ fill: `url(#${id}-bar-colors)`
1747
+ }
1748
+ )
1749
+ ]
1750
+ }
1751
+ ),
1752
+ hitArea
1753
+ ] });
1754
+ }
1755
+ return /* @__PURE__ */ jsxs6("g", { style: cursorStyle, onClick, children: [
1756
+ /* @__PURE__ */ jsx6(motion2.g, { ...grow, children: /* @__PURE__ */ jsx6(
1757
+ "rect",
1758
+ {
1759
+ x,
1760
+ y,
1761
+ width,
1762
+ height,
1763
+ rx: barRadius,
1764
+ ry: barRadius,
1765
+ fill: getFill(),
1766
+ opacity: fillOpacity,
1767
+ className: "transition-opacity duration-200"
1768
+ }
1769
+ ) }),
1770
+ hitArea
1771
+ ] });
1772
+ };
1773
+ var getBarGrowAnimation = (animationType, index, dataLength, introStartedAt) => {
1774
+ if (animationType === "none" || index < 0 || dataLength <= 0) return null;
1775
+ const lastIndex = dataLength - 1;
1776
+ const center = lastIndex / 2;
1777
+ let step;
1778
+ switch (animationType) {
1779
+ case "right-to-left":
1780
+ step = lastIndex - index;
1781
+ break;
1782
+ case "center-out":
1783
+ step = Math.abs(index - center);
1784
+ break;
1785
+ case "edges-in":
1786
+ step = center - Math.abs(index - center);
1787
+ break;
1788
+ default:
1789
+ step = index;
1790
+ }
1791
+ const startMs = step * BAR_STAGGER * 1e3;
1792
+ const durationMs = BAR_GROW_DURATION * 1e3;
1793
+ const endMs = startMs + durationMs;
1794
+ const elapsed = Date.now() - introStartedAt;
1795
+ if (elapsed >= endMs) return null;
1796
+ const from = elapsed <= startMs ? 0 : (elapsed - startMs) / durationMs;
1797
+ return {
1798
+ initial: { scaleY: from },
1799
+ animate: { scaleY: 1 },
1800
+ transition: {
1801
+ duration: (endMs - Math.max(elapsed, startMs)) / 1e3,
1802
+ ease: REVEAL_EASE,
1803
+ delay: Math.max(0, startMs - elapsed) / 1e3
1804
+ },
1805
+ style: { originY: 1 }
1806
+ };
1807
+ };
1808
+ var SINGLE_REVEAL_ORIGIN = {
1809
+ "left-to-right": 0,
1810
+ "right-to-left": 1,
1811
+ "center-out": 0.5
1812
+ };
1813
+ var RevealMask = ({
1814
+ id,
1815
+ type
1816
+ }) => {
1817
+ const reveal = {
1818
+ initial: { scaleX: 0 },
1819
+ animate: { scaleX: 1 },
1820
+ transition: { duration: REVEAL_DURATION, ease: REVEAL_EASE }
1821
+ };
1822
+ return /* @__PURE__ */ jsx6(
1823
+ "mask",
1824
+ {
1825
+ id: `${id}-reveal-mask`,
1826
+ maskUnits: "userSpaceOnUse",
1827
+ maskContentUnits: "userSpaceOnUse",
1828
+ x: "0",
1829
+ y: "0",
1830
+ width: "100%",
1831
+ height: "100%",
1832
+ children: type === "edges-in" ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
1833
+ /* @__PURE__ */ jsx6(
1834
+ motion2.rect,
1835
+ {
1836
+ ...reveal,
1837
+ x: "0",
1838
+ y: "0",
1839
+ width: "50%",
1840
+ height: "100%",
1841
+ fill: "white",
1842
+ style: { originX: 0 }
1843
+ }
1844
+ ),
1845
+ /* @__PURE__ */ jsx6(
1846
+ motion2.rect,
1847
+ {
1848
+ ...reveal,
1849
+ x: "50%",
1850
+ y: "0",
1851
+ width: "50%",
1852
+ height: "100%",
1853
+ fill: "white",
1854
+ style: { originX: 1 }
1855
+ }
1856
+ )
1857
+ ] }) : /* @__PURE__ */ jsx6(
1858
+ motion2.rect,
1859
+ {
1860
+ ...reveal,
1861
+ x: "0",
1862
+ y: "0",
1863
+ width: "100%",
1864
+ height: "100%",
1865
+ fill: "white",
1866
+ style: { originX: SINGLE_REVEAL_ORIGIN[type] }
1867
+ }
1868
+ )
1869
+ }
1870
+ );
1871
+ };
1872
+ var AnimatedDashedStroke = () => {
1873
+ return /* @__PURE__ */ jsxs6(Fragment4, { children: [
1874
+ /* @__PURE__ */ jsx6(
1875
+ "animate",
1876
+ {
1877
+ attributeName: "stroke-dasharray",
1878
+ values: "5 5; 0 5; 5 5",
1879
+ dur: "1s",
1880
+ repeatCount: "indefinite",
1881
+ keyTimes: "0;0.5;1"
1882
+ }
1883
+ ),
1884
+ /* @__PURE__ */ jsx6(
1885
+ "animate",
1886
+ {
1887
+ attributeName: "stroke-dashoffset",
1888
+ values: "0; -10",
1889
+ dur: "1s",
1890
+ repeatCount: "indefinite",
1891
+ keyTimes: "0;1"
1892
+ }
1893
+ )
1894
+ ] });
1895
+ };
1896
+ var VerticalColorGradient = ({
1897
+ id,
1898
+ dataKey,
1899
+ config
1900
+ }) => {
1901
+ const colorsCount = getColorsCount(config[dataKey] ?? {});
1902
+ return /* @__PURE__ */ jsx6("linearGradient", { id: `${id}-bar-colors`, x1: "0", y1: "0", x2: "0", y2: "1", children: colorsCount === 1 ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
1903
+ /* @__PURE__ */ jsx6("stop", { offset: "0%", stopColor: `var(--color-${dataKey}-0)` }),
1904
+ /* @__PURE__ */ jsx6("stop", { offset: "100%", stopColor: `var(--color-${dataKey}-0)` })
1905
+ ] }) : Array.from({ length: colorsCount }, (_, index) => {
1906
+ const offset = `${index / (colorsCount - 1) * 100}%`;
1907
+ return /* @__PURE__ */ jsx6(
1908
+ "stop",
1909
+ {
1910
+ offset,
1911
+ stopColor: `var(--color-${dataKey}-${index}, var(--color-${dataKey}-0))`
1912
+ },
1913
+ offset
1914
+ );
1915
+ }) });
1916
+ };
1917
+ var HorizontalColorGradient = ({
1918
+ id,
1919
+ dataKey,
1920
+ config
1921
+ }) => {
1922
+ const colorsCount = getColorsCount(config[dataKey] ?? {});
1923
+ return /* @__PURE__ */ jsx6(
1924
+ "linearGradient",
1925
+ {
1926
+ id: `${id}-line-colors-${dataKey}`,
1927
+ x1: "0",
1928
+ y1: "0",
1929
+ x2: "1",
1930
+ y2: "0",
1931
+ children: colorsCount === 1 ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
1932
+ /* @__PURE__ */ jsx6("stop", { offset: "0%", stopColor: `var(--color-${dataKey}-0)` }),
1933
+ /* @__PURE__ */ jsx6("stop", { offset: "100%", stopColor: `var(--color-${dataKey}-0)` })
1934
+ ] }) : Array.from({ length: colorsCount }, (_, index) => {
1935
+ const offset = `${index / (colorsCount - 1) * 100}%`;
1936
+ return /* @__PURE__ */ jsx6(
1937
+ "stop",
1938
+ {
1939
+ offset,
1940
+ stopColor: `var(--color-${dataKey}-${index}, var(--color-${dataKey}-0))`
1941
+ },
1942
+ offset
1943
+ );
1944
+ })
1945
+ }
1946
+ );
1947
+ };
1948
+ var DuotonePattern = ({
1949
+ id,
1950
+ dataKey,
1951
+ config
1952
+ }) => {
1953
+ const colorsCount = getColorsCount(config[dataKey] ?? {});
1954
+ return /* @__PURE__ */ jsxs6(Fragment4, { children: [
1955
+ /* @__PURE__ */ jsxs6(
1956
+ "linearGradient",
1957
+ {
1958
+ id: `${id}-duotone-mask-gradient`,
1959
+ gradientUnits: "objectBoundingBox",
1960
+ x1: "0",
1961
+ y1: "0",
1962
+ x2: "1",
1963
+ y2: "0",
1964
+ children: [
1965
+ /* @__PURE__ */ jsx6("stop", { offset: "50%", stopColor: "white", stopOpacity: 0.4 }),
1966
+ /* @__PURE__ */ jsx6("stop", { offset: "50%", stopColor: "white", stopOpacity: 1 })
1967
+ ]
1968
+ }
1969
+ ),
1970
+ /* @__PURE__ */ jsx6(
1971
+ "linearGradient",
1972
+ {
1973
+ id: `${id}-duotone-colors`,
1974
+ gradientUnits: "objectBoundingBox",
1975
+ x1: "0",
1976
+ y1: "0",
1977
+ x2: "0",
1978
+ y2: "1",
1979
+ children: colorsCount === 1 ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
1980
+ /* @__PURE__ */ jsx6("stop", { offset: "0%", stopColor: `var(--color-${dataKey}-0)` }),
1981
+ /* @__PURE__ */ jsx6("stop", { offset: "100%", stopColor: `var(--color-${dataKey}-0)` })
1982
+ ] }) : Array.from({ length: colorsCount }, (_, index) => {
1983
+ const offset = `${index / (colorsCount - 1) * 100}%`;
1984
+ return /* @__PURE__ */ jsx6(
1985
+ "stop",
1986
+ {
1987
+ offset,
1988
+ stopColor: `var(--color-${dataKey}-${index}, var(--color-${dataKey}-0))`
1989
+ },
1990
+ offset
1991
+ );
1992
+ })
1993
+ }
1994
+ ),
1995
+ /* @__PURE__ */ jsx6("mask", { id: `${id}-duotone-mask`, maskContentUnits: "objectBoundingBox", children: /* @__PURE__ */ jsx6(
1996
+ "rect",
1997
+ {
1998
+ x: "0",
1999
+ y: "0",
2000
+ width: "1",
2001
+ height: "1",
2002
+ fill: `url(#${id}-duotone-mask-gradient)`
2003
+ }
2004
+ ) }),
2005
+ /* @__PURE__ */ jsx6(
2006
+ "pattern",
2007
+ {
2008
+ id: `${id}-duotone`,
2009
+ patternUnits: "objectBoundingBox",
2010
+ patternContentUnits: "objectBoundingBox",
2011
+ width: "1",
2012
+ height: "1",
2013
+ children: /* @__PURE__ */ jsx6(
2014
+ "rect",
2015
+ {
2016
+ x: "0",
2017
+ y: "0",
2018
+ width: "1",
2019
+ height: "1",
2020
+ fill: `url(#${id}-duotone-colors)`,
2021
+ mask: `url(#${id}-duotone-mask)`
2022
+ }
2023
+ )
2024
+ }
2025
+ )
2026
+ ] });
2027
+ };
2028
+ var DuotoneReversePattern = ({
2029
+ id,
2030
+ dataKey,
2031
+ config
2032
+ }) => {
2033
+ const colorsCount = getColorsCount(config[dataKey] ?? {});
2034
+ return /* @__PURE__ */ jsxs6(Fragment4, { children: [
2035
+ /* @__PURE__ */ jsxs6(
2036
+ "linearGradient",
2037
+ {
2038
+ id: `${id}-duotone-reverse-mask-gradient`,
2039
+ gradientUnits: "objectBoundingBox",
2040
+ x1: "0",
2041
+ y1: "0",
2042
+ x2: "1",
2043
+ y2: "0",
2044
+ children: [
2045
+ /* @__PURE__ */ jsx6("stop", { offset: "50%", stopColor: "white", stopOpacity: 1 }),
2046
+ /* @__PURE__ */ jsx6("stop", { offset: "50%", stopColor: "white", stopOpacity: 0.4 })
2047
+ ]
2048
+ }
2049
+ ),
2050
+ /* @__PURE__ */ jsx6(
2051
+ "linearGradient",
2052
+ {
2053
+ id: `${id}-duotone-reverse-colors`,
2054
+ gradientUnits: "objectBoundingBox",
2055
+ x1: "0",
2056
+ y1: "0",
2057
+ x2: "0",
2058
+ y2: "1",
2059
+ children: colorsCount === 1 ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
2060
+ /* @__PURE__ */ jsx6("stop", { offset: "0%", stopColor: `var(--color-${dataKey}-0)` }),
2061
+ /* @__PURE__ */ jsx6("stop", { offset: "100%", stopColor: `var(--color-${dataKey}-0)` })
2062
+ ] }) : Array.from({ length: colorsCount }, (_, index) => {
2063
+ const offset = `${index / (colorsCount - 1) * 100}%`;
2064
+ return /* @__PURE__ */ jsx6(
2065
+ "stop",
2066
+ {
2067
+ offset,
2068
+ stopColor: `var(--color-${dataKey}-${index}, var(--color-${dataKey}-0))`
2069
+ },
2070
+ offset
2071
+ );
2072
+ })
2073
+ }
2074
+ ),
2075
+ /* @__PURE__ */ jsx6(
2076
+ "mask",
2077
+ {
2078
+ id: `${id}-duotone-reverse-mask`,
2079
+ maskContentUnits: "objectBoundingBox",
2080
+ children: /* @__PURE__ */ jsx6(
2081
+ "rect",
2082
+ {
2083
+ x: "0",
2084
+ y: "0",
2085
+ width: "1",
2086
+ height: "1",
2087
+ fill: `url(#${id}-duotone-reverse-mask-gradient)`
2088
+ }
2089
+ )
2090
+ }
2091
+ ),
2092
+ /* @__PURE__ */ jsx6(
2093
+ "pattern",
2094
+ {
2095
+ id: `${id}-duotone-reverse`,
2096
+ patternUnits: "objectBoundingBox",
2097
+ patternContentUnits: "objectBoundingBox",
2098
+ width: "1",
2099
+ height: "1",
2100
+ children: /* @__PURE__ */ jsx6(
2101
+ "rect",
2102
+ {
2103
+ x: "0",
2104
+ y: "0",
2105
+ width: "1",
2106
+ height: "1",
2107
+ fill: `url(#${id}-duotone-reverse-colors)`,
2108
+ mask: `url(#${id}-duotone-reverse-mask)`
2109
+ }
2110
+ )
2111
+ }
2112
+ )
2113
+ ] });
2114
+ };
2115
+ var GradientPattern = ({ id }) => {
2116
+ return /* @__PURE__ */ jsxs6(Fragment4, { children: [
2117
+ /* @__PURE__ */ jsxs6(
2118
+ "linearGradient",
2119
+ {
2120
+ id: `${id}-gradient-mask-gradient`,
2121
+ x1: "0",
2122
+ y1: "0",
2123
+ x2: "0",
2124
+ y2: "1",
2125
+ children: [
2126
+ /* @__PURE__ */ jsx6("stop", { offset: "20%", stopColor: "white", stopOpacity: 1 }),
2127
+ /* @__PURE__ */ jsx6("stop", { offset: "90%", stopColor: "white", stopOpacity: 0 })
2128
+ ]
2129
+ }
2130
+ ),
2131
+ /* @__PURE__ */ jsx6("mask", { id: `${id}-gradient-mask`, children: /* @__PURE__ */ jsx6(
2132
+ "rect",
2133
+ {
2134
+ width: "100%",
2135
+ height: "100%",
2136
+ fill: `url(#${id}-gradient-mask-gradient)`
2137
+ }
2138
+ ) }),
2139
+ /* @__PURE__ */ jsx6(
2140
+ "pattern",
2141
+ {
2142
+ id: `${id}-gradient`,
2143
+ patternUnits: "userSpaceOnUse",
2144
+ width: "100%",
2145
+ height: "100%",
2146
+ children: /* @__PURE__ */ jsx6(
2147
+ "rect",
2148
+ {
2149
+ width: "100%",
2150
+ height: "100%",
2151
+ fill: `url(#${id}-bar-colors)`,
2152
+ mask: `url(#${id}-gradient-mask)`
2153
+ }
2154
+ )
2155
+ }
2156
+ )
2157
+ ] });
2158
+ };
2159
+ var StrippedPattern = ({ id }) => {
2160
+ return /* @__PURE__ */ jsxs6(Fragment4, { children: [
2161
+ /* @__PURE__ */ jsxs6(
2162
+ "linearGradient",
2163
+ {
2164
+ id: `${id}-stripped-mask-gradient`,
2165
+ x1: "0",
2166
+ y1: "0",
2167
+ x2: "0",
2168
+ y2: "1",
2169
+ children: [
2170
+ /* @__PURE__ */ jsx6("stop", { offset: "0%", stopColor: "white", stopOpacity: 0.4 }),
2171
+ /* @__PURE__ */ jsx6("stop", { offset: "100%", stopColor: "white", stopOpacity: 0.1 })
2172
+ ]
2173
+ }
2174
+ ),
2175
+ /* @__PURE__ */ jsx6("mask", { id: `${id}-stripped-mask`, children: /* @__PURE__ */ jsx6(
2176
+ "rect",
2177
+ {
2178
+ width: "100%",
2179
+ height: "100%",
2180
+ fill: `url(#${id}-stripped-mask-gradient)`
2181
+ }
2182
+ ) }),
2183
+ /* @__PURE__ */ jsx6(
2184
+ "pattern",
2185
+ {
2186
+ id: `${id}-stripped`,
2187
+ patternUnits: "userSpaceOnUse",
2188
+ width: "100%",
2189
+ height: "100%",
2190
+ children: /* @__PURE__ */ jsx6(
2191
+ "rect",
2192
+ {
2193
+ width: "100%",
2194
+ height: "100%",
2195
+ fill: `url(#${id}-bar-colors)`,
2196
+ mask: `url(#${id}-stripped-mask)`
2197
+ }
2198
+ )
2199
+ }
2200
+ )
2201
+ ] });
2202
+ };
2203
+ var generateEasedGradientStops = (steps = 17, minOpacity = 0.05, maxOpacity = 0.9) => {
2204
+ return Array.from({ length: steps }, (_, i) => {
2205
+ const t = i / (steps - 1);
2206
+ const eased = Math.sin(t * Math.PI) ** 2;
2207
+ const opacity = minOpacity + eased * (maxOpacity - minOpacity);
2208
+ return {
2209
+ offset: `${(t * 100).toFixed(0)}%`,
2210
+ opacity: Number(opacity.toFixed(3))
2211
+ };
2212
+ });
2213
+ };
2214
+ function useLoadingData(isLoading, loadingBars = 12) {
2215
+ const [loadingDataKey, setLoadingDataKey] = useState2(false);
2216
+ const onShimmerExit = useCallback2(() => {
2217
+ if (isLoading) {
2218
+ setLoadingDataKey((prev) => !prev);
2219
+ }
2220
+ }, [isLoading]);
2221
+ const loadingData = useMemo3(
2222
+ () => getLoadingData(loadingBars, 20, 80),
2223
+ [loadingBars, loadingDataKey]
2224
+ );
2225
+ return { loadingData, onShimmerExit };
2226
+ }
2227
+ var LoadingBar = ({
2228
+ chartId,
2229
+ barRadius,
2230
+ onShimmerExit
2231
+ }) => {
2232
+ return /* @__PURE__ */ jsxs6(Fragment4, { children: [
2233
+ /* @__PURE__ */ jsx6(
2234
+ RechartsBar,
2235
+ {
2236
+ dataKey: LOADING_DATA_KEY,
2237
+ fill: "currentColor",
2238
+ fillOpacity: 0.15,
2239
+ radius: barRadius,
2240
+ isAnimationActive: false,
2241
+ legendType: "none",
2242
+ style: { mask: `url(#${chartId}-loading-mask)` }
2243
+ }
2244
+ ),
2245
+ /* @__PURE__ */ jsx6("defs", { children: /* @__PURE__ */ jsx6(LoadingPattern, { chartId, onShimmerExit }) })
2246
+ ] });
2247
+ };
2248
+ var LoadingPattern = ({
2249
+ chartId,
2250
+ onShimmerExit
2251
+ }) => {
2252
+ const gradientStops = generateEasedGradientStops();
2253
+ const patternWidth = 3;
2254
+ const startX = -1;
2255
+ const endX = 2;
2256
+ const lastXRef = useRef2(startX);
2257
+ return /* @__PURE__ */ jsxs6(Fragment4, { children: [
2258
+ /* @__PURE__ */ jsx6(
2259
+ "linearGradient",
2260
+ {
2261
+ id: `${chartId}-loading-gradient`,
2262
+ x1: "0",
2263
+ y1: "0",
2264
+ x2: "1",
2265
+ y2: "0",
2266
+ children: gradientStops.map(({ offset, opacity }) => /* @__PURE__ */ jsx6(
2267
+ "stop",
2268
+ {
2269
+ offset,
2270
+ stopColor: "white",
2271
+ stopOpacity: opacity
2272
+ },
2273
+ offset
2274
+ ))
2275
+ }
2276
+ ),
2277
+ /* @__PURE__ */ jsx6(
2278
+ "pattern",
2279
+ {
2280
+ id: `${chartId}-loading-pattern`,
2281
+ patternUnits: "objectBoundingBox",
2282
+ patternContentUnits: "objectBoundingBox",
2283
+ patternTransform: "rotate(25)",
2284
+ width: patternWidth,
2285
+ height: "1",
2286
+ x: "0",
2287
+ y: "0",
2288
+ children: /* @__PURE__ */ jsx6(
2289
+ motion2.rect,
2290
+ {
2291
+ y: "0",
2292
+ width: "1",
2293
+ height: "1",
2294
+ fill: `url(#${chartId}-loading-gradient)`,
2295
+ initial: { x: startX },
2296
+ animate: { x: endX },
2297
+ transition: {
2298
+ duration: LOADING_ANIMATION_DURATION / 1e3,
2299
+ ease: "linear",
2300
+ repeat: Infinity,
2301
+ repeatType: "loop"
2302
+ },
2303
+ onUpdate: (latest) => {
2304
+ const xValue = typeof latest.x === "number" ? latest.x : startX;
2305
+ const lastX = lastXRef.current;
2306
+ if (xValue >= 1 && lastX < 1) {
2307
+ onShimmerExit();
2308
+ }
2309
+ lastXRef.current = xValue;
2310
+ }
2311
+ }
2312
+ )
2313
+ }
2314
+ ),
2315
+ /* @__PURE__ */ jsx6("mask", { id: `${chartId}-loading-mask`, maskUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx6(
2316
+ "rect",
2317
+ {
2318
+ width: "100%",
2319
+ height: "100%",
2320
+ fill: `url(#${chartId}-loading-pattern)`
2321
+ }
2322
+ ) })
2323
+ ] });
2324
+ };
2325
+ export {
2326
+ ActiveDot,
2327
+ Bar2 as Bar,
2328
+ ComposedChart,
2329
+ Dot,
2330
+ Grid,
2331
+ Legend2 as Legend,
2332
+ Line2 as Line,
2333
+ Tooltip2 as Tooltip,
2334
+ XAxis,
2335
+ YAxis,
2336
+ useLoadingData
2337
+ };
2338
+ //# sourceMappingURL=composed-chart.js.map