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