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,2251 @@
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-tooltip.tsx
769
+ import * as RechartsPrimitive2 from "recharts";
770
+ import * as React2 from "react";
771
+ import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
772
+ var roundnessMap = {
773
+ sm: "rounded-bruv-sm",
774
+ md: "rounded-bruv-md",
775
+ lg: "rounded-bruv-lg",
776
+ xl: "rounded-bruv-xl"
777
+ };
778
+ var variantMap = {
779
+ default: "bg-bruv-base-2",
780
+ "frosted-glass": "bg-bruv-base-2/70 backdrop-blur-sm"
781
+ };
782
+ function ChartTooltipContent({
783
+ active,
784
+ payload,
785
+ className,
786
+ indicator = "dot",
787
+ hideLabel = false,
788
+ hideIndicator = false,
789
+ label,
790
+ labelFormatter,
791
+ labelClassName,
792
+ formatter,
793
+ nameKey,
794
+ labelKey,
795
+ selected,
796
+ roundness = "lg",
797
+ variant = "default"
798
+ }) {
799
+ const { config } = useChart();
800
+ const tooltipLabel = React2.useMemo(() => {
801
+ if (hideLabel || !payload?.length) {
802
+ return null;
803
+ }
804
+ const [item] = payload;
805
+ const key = `${labelKey ?? item?.dataKey ?? item?.name ?? "value"}`;
806
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
807
+ const value = !labelKey && typeof label === "string" ? config[label]?.label ?? label : itemConfig?.label;
808
+ if (labelFormatter) {
809
+ return /* @__PURE__ */ jsx3("div", { className: cn("font-medium", labelClassName), children: labelFormatter(value, payload) });
810
+ }
811
+ if (!value) {
812
+ return null;
813
+ }
814
+ return /* @__PURE__ */ jsx3("div", { className: cn("font-medium", labelClassName), children: value });
815
+ }, [
816
+ label,
817
+ labelFormatter,
818
+ payload,
819
+ hideLabel,
820
+ labelClassName,
821
+ config,
822
+ labelKey
823
+ ]);
824
+ if (!active || !payload?.length) {
825
+ return /* @__PURE__ */ jsx3("span", { className: "p-4" });
826
+ }
827
+ const nestLabel = payload.length === 1 && indicator !== "dot";
828
+ return /* @__PURE__ */ jsxs3(
829
+ "div",
830
+ {
831
+ className: cn(
832
+ "border-bruv-neutral/50 grid min-w-32 items-start gap-1.5 border px-2.5 py-1.5 text-xs shadow-xl",
833
+ roundnessMap[roundness],
834
+ variantMap[variant],
835
+ className
836
+ ),
837
+ children: [
838
+ !nestLabel ? tooltipLabel : null,
839
+ /* @__PURE__ */ jsx3("div", { className: "grid gap-1.5", children: payload.filter((item) => item.type !== "none").map((item, index) => {
840
+ const payloadName = nameKey && item.payload ? item.payload[nameKey] : void 0;
841
+ const key = `${payloadName ?? item.name ?? item.dataKey ?? "value"}`;
842
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
843
+ const colorsCount = itemConfig ? getColorsCount(itemConfig) : 1;
844
+ return /* @__PURE__ */ jsx3(
845
+ "div",
846
+ {
847
+ className: cn(
848
+ "[&>svg]:text-bruv-secondary flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5",
849
+ indicator === "dot" && "items-center",
850
+ selected != null && selected !== item.dataKey && "opacity-30"
851
+ ),
852
+ children: formatter && item?.value !== void 0 && item.name ? formatter(item.value, item.name, item, index, item.payload) : /* @__PURE__ */ jsxs3(Fragment3, { children: [
853
+ itemConfig?.icon ? /* @__PURE__ */ jsx3(itemConfig.icon, {}) : !hideIndicator && /* @__PURE__ */ jsx3(
854
+ "div",
855
+ {
856
+ className: cn("shrink-0 rounded-[2px]", {
857
+ "h-2.5 w-2.5": indicator === "dot",
858
+ "w-1": indicator === "line",
859
+ "w-0 border-[1.5px] border-dashed bg-transparent!": indicator === "dashed",
860
+ "my-0.5": nestLabel && indicator === "dashed"
861
+ }),
862
+ style: getIndicatorColorStyle(key, colorsCount)
863
+ }
864
+ ),
865
+ /* @__PURE__ */ jsxs3(
866
+ "div",
867
+ {
868
+ className: cn(
869
+ "flex flex-1 justify-between gap-4 leading-none",
870
+ nestLabel ? "items-end" : "items-center"
871
+ ),
872
+ children: [
873
+ /* @__PURE__ */ jsxs3("div", { className: "grid gap-1.5", children: [
874
+ nestLabel ? tooltipLabel : null,
875
+ /* @__PURE__ */ jsx3("span", { className: "text-bruv-secondary", children: itemConfig?.label ?? item.name })
876
+ ] }),
877
+ item.value != null && /* @__PURE__ */ jsx3("span", { className: "text-bruv-primary font-mono font-medium tabular-nums", children: typeof item.value === "number" ? item.value.toLocaleString() : String(item.value) })
878
+ ]
879
+ }
880
+ )
881
+ ] })
882
+ },
883
+ index
884
+ );
885
+ }) })
886
+ ]
887
+ }
888
+ );
889
+ }
890
+ function getIndicatorColorStyle(dataKey, colorsCount) {
891
+ if (colorsCount <= 1) {
892
+ return { background: `var(--color-${dataKey}-0)` };
893
+ }
894
+ const stops = Array.from({ length: colorsCount }, (_, index) => {
895
+ const offset = index / (colorsCount - 1) * 100;
896
+ return `var(--color-${dataKey}-${index}) ${offset}%`;
897
+ }).join(", ");
898
+ return { background: `linear-gradient(to right, ${stops})` };
899
+ }
900
+ var ChartTooltip = ({
901
+ animationDuration = 200,
902
+ ...props
903
+ }) => /* @__PURE__ */ jsx3(RechartsPrimitive2.Tooltip, { animationDuration, ...props });
904
+
905
+ // src/components/charts/chart-legend.tsx
906
+ import * as RechartsPrimitive3 from "recharts";
907
+ import "react";
908
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
909
+ function ChartLegendContent({
910
+ className,
911
+ hideIcon = false,
912
+ nameKey,
913
+ payload,
914
+ verticalAlign,
915
+ align = "right",
916
+ selected,
917
+ onSelectChange,
918
+ isClickable,
919
+ variant = "rounded-square"
920
+ }) {
921
+ const { config } = useChart();
922
+ if (!payload?.length) {
923
+ return null;
924
+ }
925
+ return /* @__PURE__ */ jsx4(
926
+ "div",
927
+ {
928
+ className: cn(
929
+ "flex items-center gap-4 select-none",
930
+ align === "left" && "justify-start",
931
+ align === "center" && "justify-center",
932
+ align === "right" && "justify-end",
933
+ verticalAlign === "top" ? "pb-4" : "pt-4",
934
+ className
935
+ ),
936
+ children: payload.filter((item) => item.type !== "none").map((item) => {
937
+ const payloadName = nameKey && item.payload ? item.payload[nameKey] : void 0;
938
+ const key = `${payloadName ?? item.value ?? item.dataKey ?? "value"}`;
939
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
940
+ const isSelected = selected === null || selected === key;
941
+ const colorsCount = itemConfig ? getColorsCount(itemConfig) : 1;
942
+ return /* @__PURE__ */ jsxs4(
943
+ "div",
944
+ {
945
+ className: cn(
946
+ "[&>svg]:text-bruv-secondary flex items-center gap-1.5 transition-opacity [&>svg]:h-3 [&>svg]:w-3",
947
+ !isSelected && "opacity-30",
948
+ isClickable && "cursor-pointer"
949
+ ),
950
+ onClick: () => {
951
+ if (!isClickable) return;
952
+ onSelectChange?.(selected === key ? null : key);
953
+ },
954
+ children: [
955
+ itemConfig?.icon && !hideIcon ? /* @__PURE__ */ jsx4(itemConfig.icon, {}) : /* @__PURE__ */ jsx4(
956
+ LegendIndicator,
957
+ {
958
+ variant,
959
+ dataKey: key,
960
+ colorsCount
961
+ }
962
+ ),
963
+ itemConfig?.label
964
+ ]
965
+ },
966
+ key
967
+ );
968
+ })
969
+ }
970
+ );
971
+ }
972
+ function LegendIndicator({
973
+ variant,
974
+ dataKey,
975
+ colorsCount
976
+ }) {
977
+ const fillStyle = getLegendFillStyle(dataKey, colorsCount);
978
+ const outlineStyle = getLegendOutlineStyle(dataKey, colorsCount);
979
+ switch (variant) {
980
+ case "square":
981
+ return /* @__PURE__ */ jsx4("div", { className: "h-2 w-2 shrink-0", style: fillStyle });
982
+ case "circle":
983
+ return /* @__PURE__ */ jsx4("div", { className: "h-2 w-2 shrink-0 rounded-full", style: fillStyle });
984
+ case "circle-outline":
985
+ return /* @__PURE__ */ jsx4(
986
+ "div",
987
+ {
988
+ className: "h-2.5 w-2.5 shrink-0 rounded-full p-[1.5px]",
989
+ style: outlineStyle
990
+ }
991
+ );
992
+ case "vertical-bar":
993
+ return /* @__PURE__ */ jsx4("div", { className: "h-3 w-1 shrink-0 rounded-[2px]", style: fillStyle });
994
+ case "horizontal-bar":
995
+ return /* @__PURE__ */ jsx4("div", { className: "h-1 w-3 shrink-0 rounded-[2px]", style: fillStyle });
996
+ case "rounded-square-outline":
997
+ return /* @__PURE__ */ jsx4(
998
+ "div",
999
+ {
1000
+ className: "h-2.5 w-2.5 shrink-0 rounded-[3px] p-[1.5px]",
1001
+ style: outlineStyle
1002
+ }
1003
+ );
1004
+ case "rounded-square":
1005
+ default:
1006
+ return /* @__PURE__ */ jsx4("div", { className: "h-2 w-2 shrink-0 rounded-[2px]", style: fillStyle });
1007
+ }
1008
+ }
1009
+ function getLegendFillStyle(dataKey, colorsCount) {
1010
+ if (colorsCount <= 1) {
1011
+ return { backgroundColor: `var(--color-${dataKey}-0)` };
1012
+ }
1013
+ const stops = Array.from({ length: colorsCount }, (_, i) => {
1014
+ const offset = i / (colorsCount - 1) * 100;
1015
+ return `var(--color-${dataKey}-${i}) ${offset}%`;
1016
+ }).join(", ");
1017
+ return { background: `linear-gradient(to right, ${stops})` };
1018
+ }
1019
+ function getLegendOutlineStyle(dataKey, colorsCount) {
1020
+ const maskStyle = {
1021
+ WebkitMask: "linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)",
1022
+ WebkitMaskComposite: "xor",
1023
+ mask: "linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)",
1024
+ maskComposite: "exclude"
1025
+ };
1026
+ if (colorsCount <= 1) {
1027
+ return {
1028
+ backgroundColor: `var(--color-${dataKey}-0)`,
1029
+ ...maskStyle
1030
+ };
1031
+ }
1032
+ const stops = Array.from({ length: colorsCount }, (_, i) => {
1033
+ const offset = i / (colorsCount - 1) * 100;
1034
+ return `var(--color-${dataKey}-${i}) ${offset}%`;
1035
+ }).join(", ");
1036
+ return {
1037
+ background: `linear-gradient(to right, ${stops})`,
1038
+ ...maskStyle
1039
+ };
1040
+ }
1041
+ var ChartLegend = RechartsPrimitive3.Legend;
1042
+
1043
+ // src/components/charts/chart-background.tsx
1044
+ import { ZIndexLayer } from "recharts";
1045
+ import { useId as useId3 } from "react";
1046
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
1047
+ var DotsPattern = ({ id }) => /* @__PURE__ */ jsx5(
1048
+ "pattern",
1049
+ {
1050
+ id,
1051
+ x: "0",
1052
+ y: "0",
1053
+ width: "20",
1054
+ height: "20",
1055
+ patternUnits: "userSpaceOnUse",
1056
+ children: /* @__PURE__ */ jsx5(
1057
+ "circle",
1058
+ {
1059
+ className: "text-bruv-chart-grid text-bruv-chart-grid",
1060
+ cx: "2",
1061
+ cy: "2",
1062
+ r: "1",
1063
+ fill: "currentColor"
1064
+ }
1065
+ )
1066
+ }
1067
+ );
1068
+ var GridPattern = ({ id }) => /* @__PURE__ */ jsx5(
1069
+ "pattern",
1070
+ {
1071
+ id,
1072
+ x: "0",
1073
+ y: "0",
1074
+ width: "20",
1075
+ height: "20",
1076
+ patternUnits: "userSpaceOnUse",
1077
+ children: /* @__PURE__ */ jsx5(
1078
+ "path",
1079
+ {
1080
+ className: "text-bruv-chart-grid text-bruv-chart-grid",
1081
+ d: "M 20 0 L 0 0 0 20",
1082
+ fill: "none",
1083
+ stroke: "currentColor",
1084
+ strokeWidth: "0.5"
1085
+ }
1086
+ )
1087
+ }
1088
+ );
1089
+ var CrossHatchPattern = ({ id }) => /* @__PURE__ */ jsx5(
1090
+ "pattern",
1091
+ {
1092
+ id,
1093
+ x: "0",
1094
+ y: "0",
1095
+ width: "20",
1096
+ height: "20",
1097
+ patternUnits: "userSpaceOnUse",
1098
+ children: /* @__PURE__ */ jsx5(
1099
+ "path",
1100
+ {
1101
+ className: "text-bruv-chart-grid/60 text-bruv-chart-grid/50",
1102
+ d: "M 0 0 L 20 20 M 20 0 L 0 20",
1103
+ fill: "none",
1104
+ stroke: "currentColor",
1105
+ strokeWidth: "0.5"
1106
+ }
1107
+ )
1108
+ }
1109
+ );
1110
+ var DiagonalLinesPattern = ({ id }) => /* @__PURE__ */ jsx5(
1111
+ "pattern",
1112
+ {
1113
+ id,
1114
+ x: "0",
1115
+ y: "0",
1116
+ width: "6",
1117
+ height: "6",
1118
+ patternUnits: "userSpaceOnUse",
1119
+ patternTransform: "rotate(45)",
1120
+ children: /* @__PURE__ */ jsx5(
1121
+ "line",
1122
+ {
1123
+ className: "text-bruv-chart-grid text-bruv-chart-grid",
1124
+ x1: "0",
1125
+ y1: "0",
1126
+ x2: "0",
1127
+ y2: "6",
1128
+ stroke: "currentColor",
1129
+ strokeWidth: "0.5"
1130
+ }
1131
+ )
1132
+ }
1133
+ );
1134
+ var PlusPattern = ({ id }) => /* @__PURE__ */ jsx5(
1135
+ "pattern",
1136
+ {
1137
+ id,
1138
+ x: "0",
1139
+ y: "0",
1140
+ width: "16",
1141
+ height: "16",
1142
+ patternUnits: "userSpaceOnUse",
1143
+ children: /* @__PURE__ */ jsx5(
1144
+ "path",
1145
+ {
1146
+ className: "text-bruv-chart-grid text-bruv-chart-grid",
1147
+ d: "M 8 4 L 8 12 M 4 8 L 12 8",
1148
+ fill: "none",
1149
+ stroke: "currentColor",
1150
+ strokeWidth: "0.5",
1151
+ strokeLinecap: "round"
1152
+ }
1153
+ )
1154
+ }
1155
+ );
1156
+ var FallingTrianglesPattern = ({ id }) => /* @__PURE__ */ jsx5(
1157
+ "pattern",
1158
+ {
1159
+ id,
1160
+ x: "0",
1161
+ y: "0",
1162
+ width: "18",
1163
+ height: "36",
1164
+ patternUnits: "userSpaceOnUse",
1165
+ children: /* @__PURE__ */ jsx5(
1166
+ "path",
1167
+ {
1168
+ className: "text-bruv-chart-grid text-bruv-chart-grid",
1169
+ d: "M2 6h12L8 18 2 6zm18 36h12l-6 12-6-12z",
1170
+ transform: "scale(0.5)",
1171
+ fill: "currentColor",
1172
+ fillOpacity: "0.4"
1173
+ }
1174
+ )
1175
+ }
1176
+ );
1177
+ var FourPointedStarPattern = ({ id }) => /* @__PURE__ */ jsx5(
1178
+ "pattern",
1179
+ {
1180
+ id,
1181
+ x: "0",
1182
+ y: "0",
1183
+ width: "16",
1184
+ height: "16",
1185
+ patternUnits: "userSpaceOnUse",
1186
+ children: /* @__PURE__ */ jsx5(
1187
+ "polygon",
1188
+ {
1189
+ className: "text-bruv-chart-grid text-bruv-chart-grid",
1190
+ fillRule: "evenodd",
1191
+ points: "5 3 8 4 5 5 4 8 3 5 0 4 3 3 4 0 5 3",
1192
+ fill: "currentColor",
1193
+ fillOpacity: "0.4"
1194
+ }
1195
+ )
1196
+ }
1197
+ );
1198
+ var TinyCheckersPattern = ({ id }) => /* @__PURE__ */ jsx5(
1199
+ "pattern",
1200
+ {
1201
+ id,
1202
+ x: "0",
1203
+ y: "0",
1204
+ width: "8",
1205
+ height: "8",
1206
+ patternUnits: "userSpaceOnUse",
1207
+ children: /* @__PURE__ */ jsx5(
1208
+ "path",
1209
+ {
1210
+ className: "text-bruv-chart-grid text-bruv-chart-grid",
1211
+ fillRule: "evenodd",
1212
+ d: "M0 0h4v4H0V0zm4 4h4v4H4V4z",
1213
+ fill: "currentColor",
1214
+ fillOpacity: "0.2"
1215
+ }
1216
+ )
1217
+ }
1218
+ );
1219
+ var OverlappingCirclesPattern = ({ id }) => /* @__PURE__ */ jsx5(
1220
+ "pattern",
1221
+ {
1222
+ id,
1223
+ x: "0",
1224
+ y: "0",
1225
+ width: "40",
1226
+ height: "40",
1227
+ patternUnits: "userSpaceOnUse",
1228
+ children: /* @__PURE__ */ jsx5(
1229
+ "path",
1230
+ {
1231
+ className: "text-bruv-chart-grid text-bruv-chart-grid",
1232
+ fillRule: "evenodd",
1233
+ d: "M25 25c0-2.762 2.238-5 5-5s5 2.238 5 5-2.238 5-5 5c0 2.762-2.238 5-5 5s-5-2.238-5-5 2.238-5 5-5zM5 5c0-2.762 2.238-5 5-5s5 2.238 5 5-2.238 5-5 5c0 2.762-2.238 5-5 5S0 12.762 0 10s2.238-5 5-5zm5 4c2.209 0 4-1.791 4-4s-1.791-4-4-4-4 1.791-4 4 1.791 4 4 4zm20 20c2.209 0 4-1.791 4-4s-1.791-4-4-4-4 1.791-4 4 1.791 4 4 4z",
1234
+ fill: "currentColor",
1235
+ fillOpacity: "0.4"
1236
+ }
1237
+ )
1238
+ }
1239
+ );
1240
+ var WiggleLinesPattern = ({ id }) => /* @__PURE__ */ jsx5(
1241
+ "pattern",
1242
+ {
1243
+ id,
1244
+ x: "0",
1245
+ y: "0",
1246
+ width: "52",
1247
+ height: "26",
1248
+ patternUnits: "userSpaceOnUse",
1249
+ patternTransform: "scale(0.6)",
1250
+ children: /* @__PURE__ */ jsx5(
1251
+ "path",
1252
+ {
1253
+ className: "text-bruv-chart-grid text-bruv-chart-grid",
1254
+ d: "M10 10c0-2.21-1.79-4-4-4-3.314 0-6-2.686-6-6h2c0 2.21 1.79 4 4 4 3.314 0 6 2.686 6 6 0 2.21 1.79 4 4 4 3.314 0 6 2.686 6 6 0 2.21 1.79 4 4 4v2c-3.314 0-6-2.686-6-6 0-2.21-1.79-4-4-4-3.314 0-6-2.686-6-6zm25.464-1.95l8.486 8.486-1.414 1.414-8.486-8.486 1.414-1.414z",
1255
+ fill: "currentColor",
1256
+ fillOpacity: "0.4"
1257
+ }
1258
+ )
1259
+ }
1260
+ );
1261
+ var BubblesPattern = ({ id }) => /* @__PURE__ */ jsx5(
1262
+ "pattern",
1263
+ {
1264
+ id,
1265
+ x: "0",
1266
+ y: "0",
1267
+ width: "100",
1268
+ height: "100",
1269
+ patternUnits: "userSpaceOnUse",
1270
+ patternTransform: "scale(0.6667)",
1271
+ children: /* @__PURE__ */ jsx5(
1272
+ "path",
1273
+ {
1274
+ className: "text-bruv-chart-grid text-bruv-chart-grid",
1275
+ d: "M11 18c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm48 25c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm-43-7c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm63 31c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM34 90c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm56-76c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM12 86c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm28-65c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm23-11c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-6 60c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm29 22c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zM32 63c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm57-13c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-9-21c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM60 91c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM35 41c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM12 60c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2z",
1276
+ fill: "currentColor",
1277
+ fillOpacity: "0.4",
1278
+ fillRule: "evenodd"
1279
+ }
1280
+ )
1281
+ }
1282
+ );
1283
+ var PATTERN_MAP = {
1284
+ dots: DotsPattern,
1285
+ grid: GridPattern,
1286
+ plus: PlusPattern,
1287
+ bubbles: BubblesPattern,
1288
+ "cross-hatch": CrossHatchPattern,
1289
+ "diagonal-lines": DiagonalLinesPattern,
1290
+ "falling-triangles": FallingTrianglesPattern,
1291
+ "4-pointed-star": FourPointedStarPattern,
1292
+ "tiny-checkers": TinyCheckersPattern,
1293
+ "overlapping-circles": OverlappingCirclesPattern,
1294
+ "wiggle-lines": WiggleLinesPattern
1295
+ };
1296
+ function ChartBackground({ variant }) {
1297
+ const baseId = useId3().replace(/:/g, "");
1298
+ const patternId = `${baseId}-bg-${variant}`;
1299
+ const maskId = `${baseId}-bg-edge-fade`;
1300
+ const filterId = `${baseId}-bg-blur`;
1301
+ const PatternComponent = PATTERN_MAP[variant];
1302
+ return /* @__PURE__ */ jsxs5(ZIndexLayer, { zIndex: -1, children: [
1303
+ /* @__PURE__ */ jsxs5("defs", { children: [
1304
+ /* @__PURE__ */ jsx5(PatternComponent, { id: patternId }),
1305
+ /* @__PURE__ */ jsx5("filter", { id: filterId, children: /* @__PURE__ */ jsx5("feGaussianBlur", { stdDeviation: "25" }) }),
1306
+ /* @__PURE__ */ jsx5("mask", { id: maskId, maskUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx5(
1307
+ "rect",
1308
+ {
1309
+ x: "8%",
1310
+ y: "20%",
1311
+ width: "85%",
1312
+ height: "60%",
1313
+ fill: "white",
1314
+ filter: `url(#${filterId})`
1315
+ }
1316
+ ) })
1317
+ ] }),
1318
+ /* @__PURE__ */ jsx5(
1319
+ "rect",
1320
+ {
1321
+ width: "100%",
1322
+ height: "100%",
1323
+ fill: `url(#${patternId})`,
1324
+ mask: `url(#${maskId})`
1325
+ }
1326
+ )
1327
+ ] });
1328
+ }
1329
+
1330
+ // src/components/charts/bar-chart.tsx
1331
+ import {
1332
+ createContext as createContext2,
1333
+ use,
1334
+ useCallback as useCallback2,
1335
+ useId as useId4,
1336
+ useMemo as useMemo3,
1337
+ useRef as useRef2,
1338
+ useState as useState2
1339
+ } from "react";
1340
+ import {
1341
+ Bar as RechartsBar,
1342
+ BarChart as RechartsBarChart,
1343
+ CartesianGrid,
1344
+ Rectangle,
1345
+ ReferenceLine,
1346
+ XAxis as RechartsXAxis,
1347
+ YAxis as RechartsYAxis
1348
+ } from "recharts";
1349
+ import { motion as motion2, useReducedMotion } from "motion/react";
1350
+ import { Fragment as Fragment4, jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
1351
+ var DEFAULT_BAR_RADIUS = 2;
1352
+ var LOADING_BAR_DATA_KEY = "loading";
1353
+ var LOADING_ANIMATION_DURATION = 2e3;
1354
+ var STACK_ID = "evil-stacked";
1355
+ var BAR_GROW_DURATION = 0.5;
1356
+ var BAR_STAGGER = 0.05;
1357
+ var REVEAL_EASE = [0, 0.7, 0.5, 1];
1358
+ var BarChartContext = createContext2(null);
1359
+ function useBarChart() {
1360
+ const context = use(BarChartContext);
1361
+ if (!context) {
1362
+ throw new Error(
1363
+ "Bar chart parts (<Bar />, <XAxis />, \u2026) must be used within <BarChart />"
1364
+ );
1365
+ }
1366
+ return context;
1367
+ }
1368
+ function BarChart2({
1369
+ config,
1370
+ data,
1371
+ children,
1372
+ className,
1373
+ chartProps,
1374
+ stackType = "default",
1375
+ layout = "vertical",
1376
+ barRadius = DEFAULT_BAR_RADIUS,
1377
+ animationType = "left-to-right",
1378
+ barGap,
1379
+ barCategoryGap,
1380
+ backgroundVariant,
1381
+ defaultSelectedDataKey = null,
1382
+ onSelectionChange,
1383
+ isLoading = false,
1384
+ loadingBars,
1385
+ showBrush = false,
1386
+ xDataKey,
1387
+ brushHeight,
1388
+ brushFormatLabel,
1389
+ onBrushChange
1390
+ }) {
1391
+ const chartId = useId4().replace(/:/g, "");
1392
+ const [introStartedAt] = useState2(() => Date.now());
1393
+ const [selectedDataKey, setSelectedDataKey] = useState2(
1394
+ defaultSelectedDataKey
1395
+ );
1396
+ const [isMouseInChart, setIsMouseInChart] = useState2(false);
1397
+ const { loadingData, onShimmerExit } = useLoadingData(isLoading, loadingBars);
1398
+ const { visibleData, brushProps } = useBrush({ data });
1399
+ const isStacked = stackType === "stacked" || stackType === "percent";
1400
+ const isHorizontal = layout === "horizontal";
1401
+ const displayData = showBrush && !isLoading ? visibleData : data;
1402
+ const selectDataKey = useCallback2(
1403
+ (newSelectedDataKey) => {
1404
+ setSelectedDataKey(newSelectedDataKey);
1405
+ onSelectionChange?.(newSelectedDataKey);
1406
+ },
1407
+ [onSelectionChange]
1408
+ );
1409
+ const contextValue = useMemo3(
1410
+ () => ({
1411
+ config,
1412
+ isStacked,
1413
+ isHorizontal,
1414
+ isLoading,
1415
+ barRadius,
1416
+ animationType,
1417
+ introStartedAt,
1418
+ dataLength: displayData.length,
1419
+ selectedDataKey,
1420
+ selectDataKey,
1421
+ isMouseInChart
1422
+ }),
1423
+ [
1424
+ config,
1425
+ isStacked,
1426
+ isHorizontal,
1427
+ isLoading,
1428
+ barRadius,
1429
+ animationType,
1430
+ introStartedAt,
1431
+ displayData.length,
1432
+ selectedDataKey,
1433
+ selectDataKey,
1434
+ isMouseInChart
1435
+ ]
1436
+ );
1437
+ return /* @__PURE__ */ jsx6(BarChartContext, { value: contextValue, children: /* @__PURE__ */ jsxs6(
1438
+ Chart,
1439
+ {
1440
+ className,
1441
+ config,
1442
+ footer: showBrush && !isLoading && /* @__PURE__ */ jsx6(
1443
+ Brush,
1444
+ {
1445
+ data,
1446
+ chartConfig: config,
1447
+ xDataKey,
1448
+ variant: "bar",
1449
+ barRadius,
1450
+ height: brushHeight,
1451
+ formatLabel: brushFormatLabel,
1452
+ stacked: isStacked,
1453
+ skipStyle: true,
1454
+ className: "mt-1",
1455
+ ...brushProps,
1456
+ onChange: (range) => {
1457
+ brushProps.onChange(range);
1458
+ onBrushChange?.(range);
1459
+ }
1460
+ }
1461
+ ),
1462
+ children: [
1463
+ /* @__PURE__ */ jsx6(LoadingIndicator, { isLoading }),
1464
+ /* @__PURE__ */ jsxs6(
1465
+ RechartsBarChart,
1466
+ {
1467
+ id: chartId,
1468
+ accessibilityLayer: true,
1469
+ layout: isHorizontal ? "vertical" : "horizontal",
1470
+ data: isLoading ? loadingData : displayData,
1471
+ barGap,
1472
+ barCategoryGap,
1473
+ stackOffset: stackType === "percent" ? "expand" : void 0,
1474
+ onMouseEnter: () => setIsMouseInChart(true),
1475
+ onMouseLeave: () => setIsMouseInChart(false),
1476
+ ...chartProps,
1477
+ children: [
1478
+ backgroundVariant && /* @__PURE__ */ jsx6(ChartBackground, { variant: backgroundVariant }),
1479
+ /* @__PURE__ */ jsx6(ReferenceLine, { color: "white" }),
1480
+ children,
1481
+ isLoading && /* @__PURE__ */ jsx6(LoadingBar, { chartId, onShimmerExit })
1482
+ ]
1483
+ }
1484
+ )
1485
+ ]
1486
+ }
1487
+ ) });
1488
+ }
1489
+ function Bar2({
1490
+ dataKey,
1491
+ variant = "default",
1492
+ radius,
1493
+ animationType,
1494
+ isClickable = false,
1495
+ enableHoverHighlight = false,
1496
+ bufferBar = false,
1497
+ barProps
1498
+ }) {
1499
+ const {
1500
+ config,
1501
+ isStacked,
1502
+ isHorizontal,
1503
+ isLoading,
1504
+ barRadius: defaultRadius,
1505
+ animationType: defaultAnimation,
1506
+ introStartedAt,
1507
+ dataLength,
1508
+ selectedDataKey,
1509
+ selectDataKey,
1510
+ isMouseInChart
1511
+ } = useBarChart();
1512
+ const id = useId4().replace(/:/g, "");
1513
+ const shouldReduceMotion = useReducedMotion();
1514
+ if (isLoading) return null;
1515
+ const resolvedRadius = radius ?? defaultRadius;
1516
+ const isSelected = selectedDataKey === dataKey;
1517
+ const revealType = shouldReduceMotion ? "none" : animationType ?? defaultAnimation;
1518
+ const customBarProps = {
1519
+ id,
1520
+ dataKey,
1521
+ variant,
1522
+ barRadius: resolvedRadius,
1523
+ bufferBar,
1524
+ isClickable,
1525
+ enableHoverHighlight,
1526
+ isMouseInChart,
1527
+ isHorizontal,
1528
+ introStartedAt,
1529
+ selectedDataKey,
1530
+ dataLength,
1531
+ onClick: () => {
1532
+ if (!isClickable) return;
1533
+ selectDataKey(isSelected ? null : dataKey);
1534
+ }
1535
+ };
1536
+ return /* @__PURE__ */ jsxs6(Fragment4, { children: [
1537
+ /* @__PURE__ */ jsx6(
1538
+ RechartsBar,
1539
+ {
1540
+ dataKey,
1541
+ stackId: isStacked ? STACK_ID : void 0,
1542
+ fill: `url(#${id}-colors-${dataKey})`,
1543
+ radius: resolvedRadius,
1544
+ isAnimationActive: false,
1545
+ style: isClickable || enableHoverHighlight ? { cursor: "pointer" } : void 0,
1546
+ shape: (props) => /* @__PURE__ */ jsx6(
1547
+ CustomBar,
1548
+ {
1549
+ ...props,
1550
+ ...customBarProps,
1551
+ animationType: revealType
1552
+ }
1553
+ ),
1554
+ activeBar: (props) => /* @__PURE__ */ jsx6(
1555
+ CustomBar,
1556
+ {
1557
+ ...props,
1558
+ ...customBarProps,
1559
+ animationType: "none"
1560
+ }
1561
+ ),
1562
+ ...barProps
1563
+ }
1564
+ ),
1565
+ /* @__PURE__ */ jsxs6("defs", { children: [
1566
+ /* @__PURE__ */ jsx6(ColorGradient, { id, dataKey, config }),
1567
+ variant === "duotone" && /* @__PURE__ */ jsx6(DuotonePattern, { id, dataKey, config }),
1568
+ variant === "duotone-reverse" && /* @__PURE__ */ jsx6(DuotoneReversePattern, { id, dataKey, config }),
1569
+ variant === "gradient" && /* @__PURE__ */ jsx6(GradientPattern, { id, dataKey }),
1570
+ variant === "stripped" && /* @__PURE__ */ jsx6(StrippedPattern, { id, dataKey })
1571
+ ] })
1572
+ ] });
1573
+ }
1574
+ function XAxis({
1575
+ tickLine = false,
1576
+ axisLine = false,
1577
+ tickMargin = 8,
1578
+ minTickGap = 8,
1579
+ type,
1580
+ ...props
1581
+ }) {
1582
+ const { isLoading, isHorizontal } = useBarChart();
1583
+ if (isLoading) return null;
1584
+ return /* @__PURE__ */ jsx6(
1585
+ RechartsXAxis,
1586
+ {
1587
+ tickLine,
1588
+ axisLine,
1589
+ tickMargin,
1590
+ minTickGap,
1591
+ type: type ?? (isHorizontal ? "number" : "category"),
1592
+ ...props
1593
+ }
1594
+ );
1595
+ }
1596
+ function YAxis({
1597
+ tickLine = false,
1598
+ axisLine = false,
1599
+ tickMargin = 8,
1600
+ minTickGap = 8,
1601
+ width = "auto",
1602
+ type,
1603
+ ...props
1604
+ }) {
1605
+ const { isLoading, isHorizontal } = useBarChart();
1606
+ if (isLoading) return null;
1607
+ return /* @__PURE__ */ jsx6(
1608
+ RechartsYAxis,
1609
+ {
1610
+ tickLine,
1611
+ axisLine,
1612
+ tickMargin,
1613
+ minTickGap,
1614
+ width,
1615
+ type: type ?? (isHorizontal ? "category" : "number"),
1616
+ ...props
1617
+ }
1618
+ );
1619
+ }
1620
+ function Grid({
1621
+ strokeDasharray = "3 3",
1622
+ vertical,
1623
+ horizontal,
1624
+ ...props
1625
+ }) {
1626
+ const { isHorizontal } = useBarChart();
1627
+ return /* @__PURE__ */ jsx6(
1628
+ CartesianGrid,
1629
+ {
1630
+ strokeDasharray,
1631
+ vertical: vertical ?? isHorizontal,
1632
+ horizontal: horizontal ?? !isHorizontal,
1633
+ ...props
1634
+ }
1635
+ );
1636
+ }
1637
+ function Tooltip2({ variant, roundness, defaultIndex }) {
1638
+ const { isLoading, selectedDataKey } = useBarChart();
1639
+ if (isLoading) return null;
1640
+ return /* @__PURE__ */ jsx6(
1641
+ ChartTooltip,
1642
+ {
1643
+ cursor: false,
1644
+ defaultIndex,
1645
+ content: /* @__PURE__ */ jsx6(
1646
+ ChartTooltipContent,
1647
+ {
1648
+ selected: selectedDataKey,
1649
+ roundness,
1650
+ variant
1651
+ }
1652
+ )
1653
+ }
1654
+ );
1655
+ }
1656
+ function Legend2({
1657
+ variant,
1658
+ align = "right",
1659
+ verticalAlign = "top",
1660
+ isClickable = false
1661
+ }) {
1662
+ const { selectedDataKey, selectDataKey } = useBarChart();
1663
+ return /* @__PURE__ */ jsx6(
1664
+ ChartLegend,
1665
+ {
1666
+ verticalAlign,
1667
+ align,
1668
+ content: /* @__PURE__ */ jsx6(
1669
+ ChartLegendContent,
1670
+ {
1671
+ selected: selectedDataKey,
1672
+ onSelectChange: selectDataKey,
1673
+ isClickable,
1674
+ variant
1675
+ }
1676
+ )
1677
+ }
1678
+ );
1679
+ }
1680
+ var CustomBar = (props) => {
1681
+ const {
1682
+ x = 0,
1683
+ y = 0,
1684
+ width = 0,
1685
+ height = 0,
1686
+ id,
1687
+ dataKey,
1688
+ variant,
1689
+ barRadius,
1690
+ bufferBar,
1691
+ isClickable,
1692
+ enableHoverHighlight,
1693
+ isMouseInChart,
1694
+ isHorizontal = false,
1695
+ animationType = "none",
1696
+ introStartedAt = 0,
1697
+ selectedDataKey,
1698
+ isActive,
1699
+ dataLength = 0,
1700
+ onClick
1701
+ } = props;
1702
+ const index = typeof props.index === "number" ? props.index : -1;
1703
+ const isLastBar = bufferBar && dataLength > 0 && index === dataLength - 1;
1704
+ const isStripped = variant === "stripped";
1705
+ const grow = getBarGrowAnimation(
1706
+ animationType,
1707
+ index,
1708
+ dataLength,
1709
+ isHorizontal,
1710
+ introStartedAt
1711
+ );
1712
+ const fill = getVariantFill(variant, id, dataKey);
1713
+ const fillOpacity = getBarOpacity({
1714
+ isClickable,
1715
+ selectedDataKey,
1716
+ dataKey,
1717
+ enableHoverHighlight,
1718
+ isMouseInChart,
1719
+ isActive
1720
+ });
1721
+ const barFillOpacity = isLastBar ? fillOpacity * 0.35 : fillOpacity;
1722
+ const cursorStyle = isClickable || enableHoverHighlight ? { cursor: "pointer" } : void 0;
1723
+ const radius = isStripped ? [barRadius, barRadius, 0, 0] : barRadius;
1724
+ const visibleBar = /* @__PURE__ */ jsxs6(Fragment4, { children: [
1725
+ /* @__PURE__ */ jsx6(
1726
+ Rectangle,
1727
+ {
1728
+ x,
1729
+ y,
1730
+ width,
1731
+ opacity: barFillOpacity,
1732
+ height: Math.max(0, height - 3),
1733
+ radius,
1734
+ fill,
1735
+ stroke: isLastBar ? `url(#${id}-colors-${dataKey})` : void 0,
1736
+ strokeWidth: isLastBar ? 1 : void 0,
1737
+ strokeDasharray: isLastBar ? "4 4" : void 0,
1738
+ strokeOpacity: isLastBar ? 0.6 : void 0
1739
+ }
1740
+ ),
1741
+ isStripped && /* @__PURE__ */ jsx6(
1742
+ Rectangle,
1743
+ {
1744
+ x,
1745
+ y: y - 4,
1746
+ width,
1747
+ height: 2,
1748
+ radius: 1,
1749
+ fill: `url(#${id}-colors-${dataKey})`
1750
+ }
1751
+ )
1752
+ ] });
1753
+ return /* @__PURE__ */ jsxs6("g", { style: cursorStyle, onClick, children: [
1754
+ /* @__PURE__ */ jsx6(Rectangle, { ...props, fill: "transparent" }),
1755
+ grow ? /* @__PURE__ */ jsx6(
1756
+ motion2.g,
1757
+ {
1758
+ initial: grow.initial,
1759
+ animate: grow.animate,
1760
+ transition: grow.transition,
1761
+ style: grow.style,
1762
+ children: visibleBar
1763
+ }
1764
+ ) : visibleBar
1765
+ ] });
1766
+ };
1767
+ var getBarGrowAnimation = (animationType, index, dataLength, isHorizontal, introStartedAt) => {
1768
+ if (animationType === "none" || index < 0 || dataLength <= 0) return null;
1769
+ const lastIndex = dataLength - 1;
1770
+ const center = lastIndex / 2;
1771
+ let step;
1772
+ switch (animationType) {
1773
+ case "right-to-left":
1774
+ step = lastIndex - index;
1775
+ break;
1776
+ case "center-out":
1777
+ step = Math.abs(index - center);
1778
+ break;
1779
+ case "edges-in":
1780
+ step = center - Math.abs(index - center);
1781
+ break;
1782
+ default:
1783
+ step = index;
1784
+ }
1785
+ const startMs = step * BAR_STAGGER * 1e3;
1786
+ const durationMs = BAR_GROW_DURATION * 1e3;
1787
+ const endMs = startMs + durationMs;
1788
+ const elapsed = Date.now() - introStartedAt;
1789
+ if (elapsed >= endMs) return null;
1790
+ const from = elapsed <= startMs ? 0 : (elapsed - startMs) / durationMs;
1791
+ const transition = {
1792
+ duration: (endMs - Math.max(elapsed, startMs)) / 1e3,
1793
+ ease: REVEAL_EASE,
1794
+ delay: Math.max(0, startMs - elapsed) / 1e3
1795
+ };
1796
+ return isHorizontal ? {
1797
+ initial: { scaleX: from },
1798
+ animate: { scaleX: 1 },
1799
+ transition,
1800
+ style: { originX: 0 }
1801
+ } : {
1802
+ initial: { scaleY: from },
1803
+ animate: { scaleY: 1 },
1804
+ transition,
1805
+ style: { originY: 1 }
1806
+ };
1807
+ };
1808
+ var getVariantFill = (variant, id, dataKey) => {
1809
+ switch (variant) {
1810
+ case "duotone":
1811
+ return `url(#${id}-duotone-${dataKey})`;
1812
+ case "duotone-reverse":
1813
+ return `url(#${id}-duotone-reverse-${dataKey})`;
1814
+ case "gradient":
1815
+ return `url(#${id}-gradient-${dataKey})`;
1816
+ case "stripped":
1817
+ return `url(#${id}-stripped-${dataKey})`;
1818
+ default:
1819
+ return `url(#${id}-colors-${dataKey})`;
1820
+ }
1821
+ };
1822
+ var getBarOpacity = ({
1823
+ isClickable,
1824
+ selectedDataKey,
1825
+ dataKey,
1826
+ enableHoverHighlight,
1827
+ isMouseInChart,
1828
+ isActive
1829
+ }) => {
1830
+ const isSelectedDataKey = selectedDataKey === null || selectedDataKey === dataKey;
1831
+ const clickOpacity = isClickable && selectedDataKey !== null ? isSelectedDataKey ? 1 : 0.3 : 1;
1832
+ if (enableHoverHighlight && isMouseInChart) {
1833
+ return isActive ? clickOpacity : clickOpacity * 0.3;
1834
+ }
1835
+ return clickOpacity;
1836
+ };
1837
+ var ColorGradient = ({
1838
+ id,
1839
+ dataKey,
1840
+ config
1841
+ }) => {
1842
+ const colorsCount = getColorsCount(config[dataKey] ?? {});
1843
+ return /* @__PURE__ */ jsx6("linearGradient", { id: `${id}-colors-${dataKey}`, x1: "0", y1: "0", x2: "0", y2: "1", children: colorsCount === 1 ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
1844
+ /* @__PURE__ */ jsx6("stop", { offset: "0%", stopColor: `var(--color-${dataKey}-0)` }),
1845
+ /* @__PURE__ */ jsx6("stop", { offset: "100%", stopColor: `var(--color-${dataKey}-0)` })
1846
+ ] }) : Array.from({ length: colorsCount }, (_, index) => {
1847
+ const offset = `${index / (colorsCount - 1) * 100}%`;
1848
+ return /* @__PURE__ */ jsx6(
1849
+ "stop",
1850
+ {
1851
+ offset,
1852
+ stopColor: `var(--color-${dataKey}-${index}, var(--color-${dataKey}-0))`
1853
+ },
1854
+ offset
1855
+ );
1856
+ }) });
1857
+ };
1858
+ var DuotonePattern = ({
1859
+ id,
1860
+ dataKey,
1861
+ config
1862
+ }) => {
1863
+ const colorsCount = getColorsCount(config[dataKey] ?? {});
1864
+ return /* @__PURE__ */ jsxs6(Fragment4, { children: [
1865
+ /* @__PURE__ */ jsxs6(
1866
+ "linearGradient",
1867
+ {
1868
+ id: `${id}-duotone-mask-gradient-${dataKey}`,
1869
+ gradientUnits: "objectBoundingBox",
1870
+ x1: "0",
1871
+ y1: "0",
1872
+ x2: "1",
1873
+ y2: "0",
1874
+ children: [
1875
+ /* @__PURE__ */ jsx6("stop", { offset: "50%", stopColor: "white", stopOpacity: 0.4 }),
1876
+ /* @__PURE__ */ jsx6("stop", { offset: "50%", stopColor: "white", stopOpacity: 1 })
1877
+ ]
1878
+ }
1879
+ ),
1880
+ /* @__PURE__ */ jsx6(
1881
+ "linearGradient",
1882
+ {
1883
+ id: `${id}-duotone-colors-${dataKey}`,
1884
+ gradientUnits: "objectBoundingBox",
1885
+ x1: "0",
1886
+ y1: "0",
1887
+ x2: "0",
1888
+ y2: "1",
1889
+ children: colorsCount === 1 ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
1890
+ /* @__PURE__ */ jsx6("stop", { offset: "0%", stopColor: `var(--color-${dataKey}-0)` }),
1891
+ /* @__PURE__ */ jsx6("stop", { offset: "100%", stopColor: `var(--color-${dataKey}-0)` })
1892
+ ] }) : Array.from({ length: colorsCount }, (_, index) => {
1893
+ const offset = `${index / (colorsCount - 1) * 100}%`;
1894
+ return /* @__PURE__ */ jsx6(
1895
+ "stop",
1896
+ {
1897
+ offset,
1898
+ stopColor: `var(--color-${dataKey}-${index}, var(--color-${dataKey}-0))`
1899
+ },
1900
+ offset
1901
+ );
1902
+ })
1903
+ }
1904
+ ),
1905
+ /* @__PURE__ */ jsx6(
1906
+ "mask",
1907
+ {
1908
+ id: `${id}-duotone-mask-${dataKey}`,
1909
+ maskContentUnits: "objectBoundingBox",
1910
+ children: /* @__PURE__ */ jsx6(
1911
+ "rect",
1912
+ {
1913
+ x: "0",
1914
+ y: "0",
1915
+ width: "1",
1916
+ height: "1",
1917
+ fill: `url(#${id}-duotone-mask-gradient-${dataKey})`
1918
+ }
1919
+ )
1920
+ }
1921
+ ),
1922
+ /* @__PURE__ */ jsx6(
1923
+ "pattern",
1924
+ {
1925
+ id: `${id}-duotone-${dataKey}`,
1926
+ patternUnits: "objectBoundingBox",
1927
+ patternContentUnits: "objectBoundingBox",
1928
+ width: "1",
1929
+ height: "1",
1930
+ children: /* @__PURE__ */ jsx6(
1931
+ "rect",
1932
+ {
1933
+ x: "0",
1934
+ y: "0",
1935
+ width: "1",
1936
+ height: "1",
1937
+ fill: `url(#${id}-duotone-colors-${dataKey})`,
1938
+ mask: `url(#${id}-duotone-mask-${dataKey})`
1939
+ }
1940
+ )
1941
+ }
1942
+ )
1943
+ ] });
1944
+ };
1945
+ var DuotoneReversePattern = ({
1946
+ id,
1947
+ dataKey,
1948
+ config
1949
+ }) => {
1950
+ const colorsCount = getColorsCount(config[dataKey] ?? {});
1951
+ return /* @__PURE__ */ jsxs6(Fragment4, { children: [
1952
+ /* @__PURE__ */ jsxs6(
1953
+ "linearGradient",
1954
+ {
1955
+ id: `${id}-duotone-reverse-mask-gradient-${dataKey}`,
1956
+ gradientUnits: "objectBoundingBox",
1957
+ x1: "0",
1958
+ y1: "0",
1959
+ x2: "1",
1960
+ y2: "0",
1961
+ children: [
1962
+ /* @__PURE__ */ jsx6("stop", { offset: "50%", stopColor: "white", stopOpacity: 1 }),
1963
+ /* @__PURE__ */ jsx6("stop", { offset: "50%", stopColor: "white", stopOpacity: 0.4 })
1964
+ ]
1965
+ }
1966
+ ),
1967
+ /* @__PURE__ */ jsx6(
1968
+ "linearGradient",
1969
+ {
1970
+ id: `${id}-duotone-reverse-colors-${dataKey}`,
1971
+ gradientUnits: "objectBoundingBox",
1972
+ x1: "0",
1973
+ y1: "0",
1974
+ x2: "0",
1975
+ y2: "1",
1976
+ children: colorsCount === 1 ? /* @__PURE__ */ jsxs6(Fragment4, { children: [
1977
+ /* @__PURE__ */ jsx6("stop", { offset: "0%", stopColor: `var(--color-${dataKey}-0)` }),
1978
+ /* @__PURE__ */ jsx6("stop", { offset: "100%", stopColor: `var(--color-${dataKey}-0)` })
1979
+ ] }) : Array.from({ length: colorsCount }, (_, index) => {
1980
+ const offset = `${index / (colorsCount - 1) * 100}%`;
1981
+ return /* @__PURE__ */ jsx6(
1982
+ "stop",
1983
+ {
1984
+ offset,
1985
+ stopColor: `var(--color-${dataKey}-${index}, var(--color-${dataKey}-0))`
1986
+ },
1987
+ offset
1988
+ );
1989
+ })
1990
+ }
1991
+ ),
1992
+ /* @__PURE__ */ jsx6(
1993
+ "mask",
1994
+ {
1995
+ id: `${id}-duotone-reverse-mask-${dataKey}`,
1996
+ maskContentUnits: "objectBoundingBox",
1997
+ children: /* @__PURE__ */ jsx6(
1998
+ "rect",
1999
+ {
2000
+ x: "0",
2001
+ y: "0",
2002
+ width: "1",
2003
+ height: "1",
2004
+ fill: `url(#${id}-duotone-reverse-mask-gradient-${dataKey})`
2005
+ }
2006
+ )
2007
+ }
2008
+ ),
2009
+ /* @__PURE__ */ jsx6(
2010
+ "pattern",
2011
+ {
2012
+ id: `${id}-duotone-reverse-${dataKey}`,
2013
+ patternUnits: "objectBoundingBox",
2014
+ patternContentUnits: "objectBoundingBox",
2015
+ width: "1",
2016
+ height: "1",
2017
+ children: /* @__PURE__ */ jsx6(
2018
+ "rect",
2019
+ {
2020
+ x: "0",
2021
+ y: "0",
2022
+ width: "1",
2023
+ height: "1",
2024
+ fill: `url(#${id}-duotone-reverse-colors-${dataKey})`,
2025
+ mask: `url(#${id}-duotone-reverse-mask-${dataKey})`
2026
+ }
2027
+ )
2028
+ }
2029
+ )
2030
+ ] });
2031
+ };
2032
+ var GradientPattern = ({ id, dataKey }) => {
2033
+ return /* @__PURE__ */ jsxs6(Fragment4, { children: [
2034
+ /* @__PURE__ */ jsxs6(
2035
+ "linearGradient",
2036
+ {
2037
+ id: `${id}-gradient-mask-gradient`,
2038
+ x1: "0",
2039
+ y1: "0",
2040
+ x2: "0",
2041
+ y2: "1",
2042
+ children: [
2043
+ /* @__PURE__ */ jsx6("stop", { offset: "20%", stopColor: "white", stopOpacity: 1 }),
2044
+ /* @__PURE__ */ jsx6("stop", { offset: "90%", stopColor: "white", stopOpacity: 0 })
2045
+ ]
2046
+ }
2047
+ ),
2048
+ /* @__PURE__ */ jsx6("mask", { id: `${id}-gradient-mask-${dataKey}`, children: /* @__PURE__ */ jsx6(
2049
+ "rect",
2050
+ {
2051
+ width: "100%",
2052
+ height: "100%",
2053
+ fill: `url(#${id}-gradient-mask-gradient)`
2054
+ }
2055
+ ) }),
2056
+ /* @__PURE__ */ jsx6(
2057
+ "pattern",
2058
+ {
2059
+ id: `${id}-gradient-${dataKey}`,
2060
+ patternUnits: "userSpaceOnUse",
2061
+ width: "100%",
2062
+ height: "100%",
2063
+ children: /* @__PURE__ */ jsx6(
2064
+ "rect",
2065
+ {
2066
+ width: "100%",
2067
+ height: "100%",
2068
+ fill: `url(#${id}-colors-${dataKey})`,
2069
+ mask: `url(#${id}-gradient-mask-${dataKey})`
2070
+ }
2071
+ )
2072
+ }
2073
+ )
2074
+ ] });
2075
+ };
2076
+ var StrippedPattern = ({ id, dataKey }) => {
2077
+ return /* @__PURE__ */ jsxs6(Fragment4, { children: [
2078
+ /* @__PURE__ */ jsxs6(
2079
+ "linearGradient",
2080
+ {
2081
+ id: `${id}-stripped-mask-gradient`,
2082
+ x1: "0",
2083
+ y1: "0",
2084
+ x2: "0",
2085
+ y2: "1",
2086
+ children: [
2087
+ /* @__PURE__ */ jsx6("stop", { offset: "0%", stopColor: "white", stopOpacity: 0.2 }),
2088
+ /* @__PURE__ */ jsx6("stop", { offset: "100%", stopColor: "white", stopOpacity: 0.2 })
2089
+ ]
2090
+ }
2091
+ ),
2092
+ /* @__PURE__ */ jsx6("mask", { id: `${id}-stripped-mask-${dataKey}`, children: /* @__PURE__ */ jsx6(
2093
+ "rect",
2094
+ {
2095
+ width: "100%",
2096
+ height: "100%",
2097
+ fill: `url(#${id}-stripped-mask-gradient)`
2098
+ }
2099
+ ) }),
2100
+ /* @__PURE__ */ jsx6(
2101
+ "pattern",
2102
+ {
2103
+ id: `${id}-stripped-${dataKey}`,
2104
+ patternUnits: "userSpaceOnUse",
2105
+ width: "100%",
2106
+ height: "100%",
2107
+ children: /* @__PURE__ */ jsx6(
2108
+ "rect",
2109
+ {
2110
+ width: "100%",
2111
+ height: "100%",
2112
+ fill: `url(#${id}-colors-${dataKey})`,
2113
+ mask: `url(#${id}-stripped-mask-${dataKey})`
2114
+ }
2115
+ )
2116
+ }
2117
+ )
2118
+ ] });
2119
+ };
2120
+ var generateEasedGradientStops = (steps = 17, minOpacity = 0.05, maxOpacity = 0.9) => {
2121
+ return Array.from({ length: steps }, (_, i) => {
2122
+ const t = i / (steps - 1);
2123
+ const eased = Math.sin(t * Math.PI) ** 2;
2124
+ const opacity = minOpacity + eased * (maxOpacity - minOpacity);
2125
+ return {
2126
+ offset: `${(t * 100).toFixed(0)}%`,
2127
+ opacity: Number(opacity.toFixed(3))
2128
+ };
2129
+ });
2130
+ };
2131
+ function useLoadingData(isLoading, loadingBars = 12) {
2132
+ const [loadingDataKey, setLoadingDataKey] = useState2(false);
2133
+ const onShimmerExit = useCallback2(() => {
2134
+ if (isLoading) {
2135
+ setLoadingDataKey((prev) => !prev);
2136
+ }
2137
+ }, [isLoading]);
2138
+ const loadingData = useMemo3(
2139
+ () => getLoadingData(loadingBars, 20, 80),
2140
+ [loadingBars, loadingDataKey]
2141
+ );
2142
+ return { loadingData, onShimmerExit };
2143
+ }
2144
+ var LoadingBar = ({
2145
+ chartId,
2146
+ onShimmerExit
2147
+ }) => {
2148
+ return /* @__PURE__ */ jsxs6(Fragment4, { children: [
2149
+ /* @__PURE__ */ jsx6(
2150
+ RechartsBar,
2151
+ {
2152
+ dataKey: LOADING_BAR_DATA_KEY,
2153
+ fill: "currentColor",
2154
+ fillOpacity: 0.15,
2155
+ radius: DEFAULT_BAR_RADIUS,
2156
+ isAnimationActive: false,
2157
+ legendType: "none",
2158
+ style: { mask: `url(#${chartId}-loading-mask)` }
2159
+ }
2160
+ ),
2161
+ /* @__PURE__ */ jsx6("defs", { children: /* @__PURE__ */ jsx6(LoadingBarPattern, { chartId, onShimmerExit }) })
2162
+ ] });
2163
+ };
2164
+ var LoadingBarPattern = ({
2165
+ chartId,
2166
+ onShimmerExit
2167
+ }) => {
2168
+ const gradientStops = generateEasedGradientStops();
2169
+ const patternWidth = 3;
2170
+ const startX = -1;
2171
+ const endX = 2;
2172
+ const lastXRef = useRef2(startX);
2173
+ return /* @__PURE__ */ jsxs6(Fragment4, { children: [
2174
+ /* @__PURE__ */ jsx6(
2175
+ "linearGradient",
2176
+ {
2177
+ id: `${chartId}-loading-mask-gradient`,
2178
+ x1: "0",
2179
+ y1: "0",
2180
+ x2: "1",
2181
+ y2: "0",
2182
+ children: gradientStops.map(({ offset, opacity }) => /* @__PURE__ */ jsx6(
2183
+ "stop",
2184
+ {
2185
+ offset,
2186
+ stopColor: "white",
2187
+ stopOpacity: opacity
2188
+ },
2189
+ offset
2190
+ ))
2191
+ }
2192
+ ),
2193
+ /* @__PURE__ */ jsx6(
2194
+ "pattern",
2195
+ {
2196
+ id: `${chartId}-loading-mask-pattern`,
2197
+ patternUnits: "objectBoundingBox",
2198
+ patternContentUnits: "objectBoundingBox",
2199
+ patternTransform: "rotate(25)",
2200
+ width: patternWidth,
2201
+ height: "1",
2202
+ x: "0",
2203
+ y: "0",
2204
+ children: /* @__PURE__ */ jsx6(
2205
+ motion2.rect,
2206
+ {
2207
+ y: "0",
2208
+ width: "1",
2209
+ height: "1",
2210
+ fill: `url(#${chartId}-loading-mask-gradient)`,
2211
+ initial: { x: startX },
2212
+ animate: { x: endX },
2213
+ transition: {
2214
+ duration: LOADING_ANIMATION_DURATION / 1e3,
2215
+ ease: "linear",
2216
+ repeat: Infinity,
2217
+ repeatType: "loop"
2218
+ },
2219
+ onUpdate: (latest) => {
2220
+ const xValue = typeof latest.x === "number" ? latest.x : startX;
2221
+ const lastX = lastXRef.current;
2222
+ if (xValue >= 1 && lastX < 1) {
2223
+ onShimmerExit();
2224
+ }
2225
+ lastXRef.current = xValue;
2226
+ }
2227
+ }
2228
+ )
2229
+ }
2230
+ ),
2231
+ /* @__PURE__ */ jsx6("mask", { id: `${chartId}-loading-mask`, maskUnits: "userSpaceOnUse", children: /* @__PURE__ */ jsx6(
2232
+ "rect",
2233
+ {
2234
+ width: "100%",
2235
+ height: "100%",
2236
+ fill: `url(#${chartId}-loading-mask-pattern)`
2237
+ }
2238
+ ) })
2239
+ ] });
2240
+ };
2241
+ export {
2242
+ Bar2 as Bar,
2243
+ BarChart2 as BarChart,
2244
+ Grid,
2245
+ Legend2 as Legend,
2246
+ Tooltip2 as Tooltip,
2247
+ XAxis,
2248
+ YAxis,
2249
+ useLoadingData
2250
+ };
2251
+ //# sourceMappingURL=bar-chart.js.map