@turtleclub/ui 0.7.0-beta.3 → 0.7.0-beta.30

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 (69) hide show
  1. package/.turbo/turbo-build.log +143 -132
  2. package/CHANGELOG.md +152 -0
  3. package/dist/index.cjs +76 -36
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.js +36068 -17674
  6. package/dist/index.js.map +1 -1
  7. package/dist/styles.css +1 -1
  8. package/dist/types/components/charts/area-chart.d.ts +108 -0
  9. package/dist/types/components/charts/area-chart.d.ts.map +1 -0
  10. package/dist/types/components/charts/bar-chart.d.ts +110 -0
  11. package/dist/types/components/charts/bar-chart.d.ts.map +1 -0
  12. package/dist/types/components/charts/index.d.ts +5 -0
  13. package/dist/types/components/charts/index.d.ts.map +1 -0
  14. package/dist/types/components/charts/pie-chart.d.ts +94 -0
  15. package/dist/types/components/charts/pie-chart.d.ts.map +1 -0
  16. package/dist/types/components/charts/radial-chart.d.ts +151 -0
  17. package/dist/types/components/charts/radial-chart.d.ts.map +1 -0
  18. package/dist/types/components/features/data-table/data-table.d.ts +7 -4
  19. package/dist/types/components/features/data-table/data-table.d.ts.map +1 -1
  20. package/dist/types/components/features/data-table/sort-dropdown.d.ts.map +1 -1
  21. package/dist/types/components/features/search-bar.d.ts +1 -0
  22. package/dist/types/components/features/search-bar.d.ts.map +1 -1
  23. package/dist/types/components/molecules/swap-input.d.ts +3 -0
  24. package/dist/types/components/molecules/swap-input.d.ts.map +1 -1
  25. package/dist/types/components/molecules/token-selector.d.ts +2 -1
  26. package/dist/types/components/molecules/token-selector.d.ts.map +1 -1
  27. package/dist/types/components/ui/avatar.d.ts +2 -2
  28. package/dist/types/components/ui/avatar.d.ts.map +1 -1
  29. package/dist/types/components/ui/chart.d.ts +18 -4
  30. package/dist/types/components/ui/chart.d.ts.map +1 -1
  31. package/dist/types/components/ui/combobox.d.ts +21 -0
  32. package/dist/types/components/ui/combobox.d.ts.map +1 -1
  33. package/dist/types/components/ui/dialog.d.ts.map +1 -1
  34. package/dist/types/components/ui/dropdown.d.ts +2 -1
  35. package/dist/types/components/ui/dropdown.d.ts.map +1 -1
  36. package/dist/types/components/ui/index.d.ts +1 -0
  37. package/dist/types/components/ui/index.d.ts.map +1 -1
  38. package/dist/types/components/ui/multi-select.d.ts.map +1 -1
  39. package/dist/types/components/ui/segment-control.d.ts +1 -0
  40. package/dist/types/components/ui/segment-control.d.ts.map +1 -1
  41. package/dist/types/components/ui/slider.d.ts.map +1 -1
  42. package/dist/types/index.d.ts +1 -0
  43. package/dist/types/index.d.ts.map +1 -1
  44. package/package.json +3 -3
  45. package/src/components/charts/QUICK_REFERENCE.md +323 -0
  46. package/src/components/charts/README.md +658 -0
  47. package/src/components/charts/RECHARTS_FEATURES.md +458 -0
  48. package/src/components/charts/area-chart.tsx +248 -0
  49. package/src/components/charts/bar-chart.tsx +362 -0
  50. package/src/components/charts/index.ts +4 -0
  51. package/src/components/charts/pie-chart.tsx +277 -0
  52. package/src/components/charts/radial-chart.tsx +312 -0
  53. package/src/components/features/data-table/data-table.tsx +136 -125
  54. package/src/components/features/data-table/sort-dropdown.tsx +8 -11
  55. package/src/components/features/search-bar.tsx +6 -1
  56. package/src/components/molecules/swap-input.tsx +44 -30
  57. package/src/components/molecules/token-selector.tsx +10 -1
  58. package/src/components/ui/avatar.tsx +8 -15
  59. package/src/components/ui/chart.tsx +100 -109
  60. package/src/components/ui/combobox.tsx +150 -137
  61. package/src/components/ui/dialog.tsx +9 -23
  62. package/src/components/ui/dropdown.tsx +3 -1
  63. package/src/components/ui/index.ts +1 -0
  64. package/src/components/ui/multi-select.tsx +325 -307
  65. package/src/components/ui/segment-control.tsx +7 -2
  66. package/src/components/ui/slider.tsx +6 -11
  67. package/src/index.ts +1 -0
  68. package/src/styles/globals.css +4 -0
  69. package/src/styles/themes/semantic.css +26 -56
@@ -0,0 +1,458 @@
1
+ # Recharts Native Features Usage
2
+
3
+ This document details how our chart components leverage Recharts' built-in features for optimal performance and functionality.
4
+
5
+ ## Overview
6
+
7
+ Our chart components are designed as **thin wrappers** around Recharts, utilizing its native capabilities wherever possible rather than implementing custom solutions. This approach ensures:
8
+
9
+ - ✅ Better performance (native rendering)
10
+ - ✅ Consistent behavior with Recharts ecosystem
11
+ - ✅ Easier maintenance and updates
12
+ - ✅ Access to full Recharts API when needed
13
+
14
+ ## Core Native Features
15
+
16
+ ### 1. Cell Component
17
+
18
+ **What it is:** Recharts' built-in component for styling individual chart elements (bars, pie segments, etc.)
19
+
20
+ **How we use it:**
21
+
22
+ ```tsx
23
+ // In BarChart component
24
+ <Bar dataKey="sales" fill="var(--color-sales)" radius={5}>
25
+ {data.map((entry, index) => (
26
+ <Cell
27
+ key={`cell-${index}`}
28
+ fill={customColor || defaultColor}
29
+ />
30
+ ))}
31
+ </Bar>
32
+ ```
33
+
34
+ **Benefits:**
35
+ - Per-item customization without custom rendering
36
+ - Conditional coloring based on data values
37
+ - Native performance optimization
38
+
39
+ **User-facing API:**
40
+
41
+ ```tsx
42
+ <BarChart
43
+ data={data}
44
+ config={config}
45
+ categoryKey="month"
46
+ dataKeys={["sales"]}
47
+ getBarColor={(entry, index, dataKey) => {
48
+ // Return custom color or undefined for default
49
+ return entry.sales > 200 ? "hsl(var(--destructive))" : undefined;
50
+ }}
51
+ />
52
+ ```
53
+
54
+ ### 2. Linear Gradients (SVG Defs)
55
+
56
+ **What it is:** Recharts supports SVG `<defs>` for defining reusable graphics like gradients
57
+
58
+ **How we use it:**
59
+
60
+ ```tsx
61
+ // In BarChart component
62
+ <defs>
63
+ {gradient && dataKeys.map((key) => (
64
+ <linearGradient
65
+ key={key}
66
+ id={`gradient-bar-${key}`}
67
+ x1={isVertical ? "1" : "0"}
68
+ y1={isVertical ? "0" : "0"}
69
+ x2={isVertical ? "0" : "0"}
70
+ y2={isVertical ? "0" : "1"}
71
+ >
72
+ <stop offset="0%" stopColor={`var(--color-${key})`} stopOpacity={1} />
73
+ <stop offset="100%" stopColor={`var(--color-${key})`} stopOpacity={0.1} />
74
+ </linearGradient>
75
+ ))}
76
+ </defs>
77
+
78
+ <Bar fill={gradient ? `url(#gradient-bar-${key})` : `var(--color-${key})`} />
79
+ ```
80
+
81
+ **Benefits:**
82
+ - Native SVG rendering
83
+ - Automatic orientation handling
84
+ - Hardware-accelerated graphics
85
+ - Proper gradient direction per chart orientation
86
+
87
+ **Gradient directions per chart type:**
88
+ - **BarChart (vertical bars):** Top to bottom (`y1="0" y2="1"`)
89
+ - **BarChart (horizontal bars):** Right to left (`x1="1" x2="0"`)
90
+ - **AreaChart:** Top to bottom (`y1="0" y2="1"`)
91
+ - **PieChart:** Radial from center (`radialGradient`)
92
+ - **RadialBarChart:** Horizontal along bar (`x1="0" x2="1"`)
93
+
94
+ ### 3. Active Shape Props
95
+
96
+ **What it is:** Recharts' built-in props for handling hover/active states
97
+
98
+ **Available props:**
99
+ - `activeShape` - Custom renderer for active element
100
+ - `activeDot` - Active dot styling for line/area charts
101
+ - `activeBar` - Active bar styling for bar charts
102
+
103
+ **How we use it:**
104
+
105
+ ```tsx
106
+ // In AreaChart component
107
+ <Area
108
+ dataKey="revenue"
109
+ activeDot={
110
+ activeDot !== undefined
111
+ ? activeDot
112
+ : showDots ? { r: 4, strokeWidth: 2 } : undefined
113
+ }
114
+ />
115
+ ```
116
+
117
+ **User-facing API:**
118
+
119
+ ```tsx
120
+ <AreaChart
121
+ data={data}
122
+ config={config}
123
+ categoryKey="month"
124
+ dataKeys={["revenue"]}
125
+ showDots={true}
126
+ activeDot={{ r: 6, strokeWidth: 2, fill: "hsl(var(--primary))" }}
127
+ />
128
+ ```
129
+
130
+ ### 4. PolarGrid Component
131
+
132
+ **What it is:** Recharts' component for rendering grids in polar coordinate systems
133
+
134
+ **How we use it:**
135
+
136
+ ```tsx
137
+ // In PieChart component
138
+ <PolarGrid
139
+ gridType="circle"
140
+ radialLines={true}
141
+ polarAngles={Array.from(
142
+ { length: radialGridLines },
143
+ (_, i) => (360 / radialGridLines) * i
144
+ )}
145
+ stroke="hsl(var(--border))"
146
+ strokeOpacity={0.3}
147
+ strokeWidth={1}
148
+ />
149
+ ```
150
+
151
+ **User-facing API:**
152
+
153
+ ```tsx
154
+ <PieChart
155
+ data={data}
156
+ config={config}
157
+ nameKey="category"
158
+ dataKey="value"
159
+ showRadialGrid={true}
160
+ radialGridLines={12}
161
+ />
162
+ ```
163
+
164
+ ### 5. CartesianGrid Component
165
+
166
+ **What it is:** Recharts' component for rendering grid lines in Cartesian charts
167
+
168
+ **How we use it:**
169
+
170
+ ```tsx
171
+ // In BarChart, AreaChart components
172
+ <CartesianGrid
173
+ strokeDasharray="3 3"
174
+ horizontal={gridConfig.horizontal}
175
+ vertical={gridConfig.vertical}
176
+ />
177
+ ```
178
+
179
+ **User-facing API:**
180
+
181
+ ```tsx
182
+ // Boolean (both axes)
183
+ <BarChart showGrid={true} />
184
+
185
+ // Granular control
186
+ <BarChart
187
+ showGrid={{
188
+ horizontal: true,
189
+ vertical: false
190
+ }}
191
+ />
192
+ ```
193
+
194
+ ### 6. Shape Prop (Custom Rendering)
195
+
196
+ **What it is:** Recharts allows custom shape renderers for complete control
197
+
198
+ **How we use it:**
199
+
200
+ ```tsx
201
+ // In PieChart component for scaled radius
202
+ const renderCustomShape = (props) => {
203
+ const { cx, cy, innerRadius, outerRadius, startAngle, endAngle, fill, value } = props;
204
+
205
+ // Calculate scaled radius
206
+ let scaledOuterRadius = outerRadius;
207
+ if (scaledRadius && maxValue > 0) {
208
+ const percentage = Number(value) / maxValue;
209
+ scaledOuterRadius = outerRadius * (0.4 + percentage * 0.6);
210
+ }
211
+
212
+ return (
213
+ <Sector
214
+ cx={cx}
215
+ cy={cy}
216
+ innerRadius={innerRadius}
217
+ outerRadius={scaledOuterRadius}
218
+ startAngle={startAngle}
219
+ endAngle={endAngle}
220
+ fill={fill}
221
+ />
222
+ );
223
+ };
224
+
225
+ <Pie shape={renderCustomShape} />
226
+ ```
227
+
228
+ **User-facing API:**
229
+
230
+ ```tsx
231
+ <PieChart
232
+ data={data}
233
+ config={config}
234
+ nameKey="category"
235
+ dataKey="value"
236
+ scaledRadius={true} // Segments scale based on value
237
+ />
238
+ ```
239
+
240
+ ## Implementation Patterns
241
+
242
+ ### Pattern 1: Conditional Rendering with Cell
243
+
244
+ **Use case:** Color individual bars/segments based on data values
245
+
246
+ ```tsx
247
+ {dataKeys.map((key) => (
248
+ <Bar key={key} dataKey={key} fill={defaultFill}>
249
+ {getBarColor && data.map((entry, index) => {
250
+ const customColor = getBarColor(entry, index, key);
251
+ return (
252
+ <Cell
253
+ key={`cell-${key}-${index}`}
254
+ fill={customColor || defaultFill}
255
+ />
256
+ );
257
+ })}
258
+ </Bar>
259
+ ))}
260
+ ```
261
+
262
+ ### Pattern 2: Dynamic Gradient Definitions
263
+
264
+ **Use case:** Create gradients that adapt to chart configuration
265
+
266
+ ```tsx
267
+ <defs>
268
+ {gradient && dataKeys.map((key) => (
269
+ <linearGradient
270
+ key={key}
271
+ id={`gradient-${chartType}-${key}`}
272
+ x1={orientation === "horizontal" ? "1" : "0"}
273
+ y1={orientation === "horizontal" ? "0" : "0"}
274
+ x2={orientation === "horizontal" ? "0" : "0"}
275
+ y2={orientation === "horizontal" ? "0" : "1"}
276
+ >
277
+ <stop offset="0%" stopColor={`var(--color-${key})`} stopOpacity={1} />
278
+ <stop offset="100%" stopColor={`var(--color-${key})`} stopOpacity={0.1} />
279
+ </linearGradient>
280
+ ))}
281
+ </defs>
282
+ ```
283
+
284
+ ### Pattern 3: Responsive Container
285
+
286
+ **Use case:** Charts that adapt to parent container size
287
+
288
+ ```tsx
289
+ // We use ChartContainer which wraps ResponsiveContainer
290
+ <ChartContainer config={config} className={grow ? "h-full w-full" : aspectRatio}>
291
+ <RechartsBarChart data={data}>
292
+ {/* chart elements */}
293
+ </RechartsBarChart>
294
+ </ChartContainer>
295
+ ```
296
+
297
+ ## Why Native Features Matter
298
+
299
+ ### Performance
300
+
301
+ Native Recharts features are optimized for:
302
+ - Efficient SVG rendering
303
+ - Minimal re-renders
304
+ - Hardware acceleration where possible
305
+ - React reconciliation optimization
306
+
307
+ ### Maintainability
308
+
309
+ Using native features means:
310
+ - Fewer custom implementations to maintain
311
+ - Easier to update when Recharts updates
312
+ - Better TypeScript support
313
+ - Consistent with Recharts documentation
314
+
315
+ ### Extensibility
316
+
317
+ Users can:
318
+ - Pass additional Recharts props through
319
+ - Extend components without rewriting
320
+ - Use Recharts plugins and extensions
321
+ - Access full Recharts ecosystem
322
+
323
+ ## Examples
324
+
325
+ ### Example 1: Traffic Light Colors
326
+
327
+ ```tsx
328
+ const data = [
329
+ { status: "Critical", count: 12 },
330
+ { status: "Warning", count: 45 },
331
+ { status: "Good", count: 89 },
332
+ ];
333
+
334
+ <BarChart
335
+ data={data}
336
+ config={config}
337
+ categoryKey="status"
338
+ dataKeys={["count"]}
339
+ getBarColor={(entry) => {
340
+ switch (entry.status) {
341
+ case "Critical": return "hsl(0 84% 60%)"; // Red
342
+ case "Warning": return "hsl(48 96% 53%)"; // Yellow
343
+ case "Good": return "hsl(142 76% 36%)"; // Green
344
+ default: return undefined;
345
+ }
346
+ }}
347
+ />
348
+ ```
349
+
350
+ ### Example 2: Threshold-Based Coloring
351
+
352
+ ```tsx
353
+ const data = [
354
+ { month: "Jan", revenue: 1200, target: 1000 },
355
+ { month: "Feb", revenue: 800, target: 1000 },
356
+ { month: "Mar", revenue: 1500, target: 1000 },
357
+ ];
358
+
359
+ <BarChart
360
+ data={data}
361
+ config={config}
362
+ categoryKey="month"
363
+ dataKeys={["revenue"]}
364
+ getBarColor={(entry) => {
365
+ const percentage = (entry.revenue / entry.target) * 100;
366
+ if (percentage >= 100) return "hsl(142 76% 36%)"; // Green: Met target
367
+ if (percentage >= 80) return "hsl(48 96% 53%)"; // Yellow: Close
368
+ return "hsl(0 84% 60%)"; // Red: Below target
369
+ }}
370
+ />
371
+ ```
372
+
373
+ ### Example 3: Gradient with Conditional Override
374
+
375
+ ```tsx
376
+ <BarChart
377
+ data={data}
378
+ config={config}
379
+ categoryKey="month"
380
+ dataKeys={["sales"]}
381
+ gradient={true}
382
+ getBarColor={(entry) => {
383
+ // Highlight special cases with solid color, let others use gradient
384
+ if (entry.month === "Dec") {
385
+ return "hsl(var(--primary))"; // Solid color for December
386
+ }
387
+ return undefined; // Use gradient for others
388
+ }}
389
+ />
390
+ ```
391
+
392
+ ### Example 4: Interactive Area Chart
393
+
394
+ ```tsx
395
+ <AreaChart
396
+ data={data}
397
+ config={config}
398
+ categoryKey="date"
399
+ dataKeys={["value"]}
400
+ gradient={true}
401
+ showDots={true}
402
+ activeDot={{
403
+ r: 6,
404
+ strokeWidth: 2,
405
+ fill: "hsl(var(--primary))",
406
+ stroke: "hsl(var(--background))",
407
+ }}
408
+ curveType="monotone"
409
+ />
410
+ ```
411
+
412
+ ## Best Practices
413
+
414
+ ### ✅ Do
415
+
416
+ - Use `Cell` component for per-item customization
417
+ - Leverage native gradient support via `<defs>`
418
+ - Use Recharts' active state props for hover effects
419
+ - Keep gradient IDs unique per chart instance
420
+ - Return `undefined` from color functions to use defaults
421
+
422
+ ### ❌ Don't
423
+
424
+ - Implement custom rendering when native features suffice
425
+ - Hardcode gradient definitions outside `<defs>`
426
+ - Override all Recharts styles (let native theming work)
427
+ - Ignore orientation when defining gradients
428
+ - Create duplicate gradient definitions
429
+
430
+ ## Future Enhancements
431
+
432
+ Potential native features to explore:
433
+
434
+ 1. **Brush component** - For data zooming/panning
435
+ 2. **ReferenceLines** - For threshold indicators
436
+ 3. **ReferenceDots** - For specific data point highlighting
437
+ 4. **Customized Label** - For advanced label positioning
438
+ 5. **Legend customization** - Using native Legend props
439
+ 6. **Animation props** - Recharts' native animation system
440
+
441
+ ## Resources
442
+
443
+ - [Recharts Documentation](https://recharts.org/)
444
+ - [Recharts API Reference](https://recharts.org/en-US/api)
445
+ - [Recharts GitHub](https://github.com/recharts/recharts)
446
+ - [SVG Gradients MDN](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/linearGradient)
447
+
448
+ ## Summary
449
+
450
+ Our chart components are **Recharts-first** implementations that:
451
+
452
+ 1. **Expose native Recharts features** through clean, typed APIs
453
+ 2. **Enhance with convenience props** while maintaining Recharts compatibility
454
+ 3. **Use Cell, gradients, and native props** for styling and interactivity
455
+ 4. **Avoid custom rendering** unless absolutely necessary
456
+ 5. **Stay compatible** with Recharts ecosystem and updates
457
+
458
+ This approach gives users the full power of Recharts while providing sensible defaults and TypeScript safety.
@@ -0,0 +1,248 @@
1
+ "use client";
2
+
3
+ import { Area, AreaChart as RechartsAreaChart, CartesianGrid, XAxis, YAxis, Dot } from "recharts";
4
+ import {
5
+ ChartConfig,
6
+ ChartContainer,
7
+ ChartLegend,
8
+ ChartLegendContent,
9
+ ChartTooltip,
10
+ ChartTooltipContent,
11
+ } from "../ui/chart";
12
+ import { cn } from "@/lib/utils";
13
+
14
+ export interface AreaChartData {
15
+ [key: string]: string | number;
16
+ }
17
+
18
+ export interface AreaChartProps {
19
+ /**
20
+ * Array of data objects to be displayed in the chart
21
+ */
22
+ data: AreaChartData[];
23
+ /**
24
+ * Configuration for chart styling and labels
25
+ */
26
+ config: ChartConfig;
27
+ /**
28
+ * Key from data objects to use for X-axis categories
29
+ */
30
+ categoryKey: string;
31
+ /**
32
+ * Array of keys from data objects to display as areas
33
+ */
34
+ dataKeys: string[];
35
+ /**
36
+ * Show grid lines. Can be boolean for both axes or object for granular control
37
+ * @default true
38
+ */
39
+ showGrid?: boolean | { horizontal?: boolean; vertical?: boolean };
40
+ /**
41
+ * Show legend
42
+ * @default false
43
+ */
44
+ showLegend?: boolean;
45
+ /**
46
+ * Show tooltip on hover
47
+ * @default true
48
+ */
49
+ showTooltip?: boolean;
50
+ /**
51
+ * Stack areas on top of each other
52
+ * @default false
53
+ */
54
+ stacked?: boolean;
55
+ /**
56
+ * Area curve type
57
+ * @default "monotone"
58
+ */
59
+ curveType?:
60
+ | "basis"
61
+ | "basisClosed"
62
+ | "basisOpen"
63
+ | "linear"
64
+ | "linearClosed"
65
+ | "natural"
66
+ | "monotoneX"
67
+ | "monotoneY"
68
+ | "monotone"
69
+ | "step"
70
+ | "stepBefore"
71
+ | "stepAfter";
72
+ /**
73
+ * Fill opacity for areas
74
+ * @default 0.6
75
+ */
76
+ fillOpacity?: number;
77
+ /**
78
+ * Stroke width for area lines
79
+ * @default 2
80
+ */
81
+ strokeWidth?: number;
82
+ /**
83
+ * Enable gradient fill for areas (uses Recharts native gradient support)
84
+ * @default true
85
+ */
86
+ gradient?: boolean;
87
+ /**
88
+ * Active dot props for highlighting data points on hover
89
+ * @default undefined
90
+ */
91
+ activeDot?: boolean | object;
92
+ /**
93
+ * Custom className for the container
94
+ */
95
+ className?: string;
96
+ /**
97
+ * Chart height aspect ratio
98
+ * @default "aspect-video"
99
+ */
100
+ aspectRatio?: string;
101
+ /**
102
+ * Make chart grow to fill parent container (ignores aspectRatio if true)
103
+ * @default false
104
+ */
105
+ grow?: boolean;
106
+ /**
107
+ * Show dots on data points
108
+ * @default false
109
+ */
110
+ showDots?: boolean;
111
+ /**
112
+ * Custom formatter function for Y-axis tick labels
113
+ * @example (value) => `$${value.toLocaleString()}`
114
+ * @example (value) => formatCompactNumber(value)
115
+ */
116
+ yAxisFormatter?: (value: number) => string;
117
+ /**
118
+ * Custom formatter function for X-axis tick labels
119
+ * @example (value) => new Date(value).toLocaleDateString()
120
+ * @example (value) => formatCompactNumber(value)
121
+ */
122
+ xAxisFormatter?: (value: any) => string;
123
+ /**
124
+ * Custom formatter function for tooltip values
125
+ * @example (value, name, item, index, payload) => `$${value.toLocaleString()}`
126
+ */
127
+ tooltipFormatter?: (
128
+ value: any,
129
+ name: any,
130
+ item: any,
131
+ index: number,
132
+ payload: any
133
+ ) => React.ReactNode;
134
+ }
135
+
136
+ export function AreaChart({
137
+ data,
138
+ config,
139
+ categoryKey,
140
+ dataKeys,
141
+ showGrid = true,
142
+ showLegend = false,
143
+ showTooltip = true,
144
+ stacked = false,
145
+ curveType = "monotone",
146
+ fillOpacity = 0.6,
147
+ strokeWidth = 2,
148
+ gradient = true,
149
+ className,
150
+ aspectRatio = "aspect-video",
151
+ showDots = false,
152
+ grow = false,
153
+ activeDot,
154
+ yAxisFormatter,
155
+ xAxisFormatter,
156
+ tooltipFormatter,
157
+ }: AreaChartProps) {
158
+ const stackId = stacked ? "stack" : undefined;
159
+
160
+ // Parse grid configuration
161
+ const gridConfig =
162
+ typeof showGrid === "boolean"
163
+ ? { horizontal: showGrid, vertical: showGrid }
164
+ : { horizontal: showGrid?.horizontal ?? false, vertical: showGrid?.vertical ?? false };
165
+
166
+ return (
167
+ <ChartContainer config={config} className={cn(grow ? "h-full w-full" : aspectRatio, className)}>
168
+ <RechartsAreaChart
169
+ accessibilityLayer
170
+ data={data}
171
+ margin={{
172
+ top: 10,
173
+ right: 10,
174
+ bottom: 10,
175
+ left: 10,
176
+ }}
177
+ >
178
+ {(gridConfig.horizontal || gridConfig.vertical) && (
179
+ <CartesianGrid
180
+ strokeDasharray="3 3"
181
+ horizontal={gridConfig.horizontal}
182
+ vertical={gridConfig.vertical}
183
+ />
184
+ )}
185
+
186
+ <XAxis
187
+ dataKey={categoryKey}
188
+ tickLine={false}
189
+ tickMargin={10}
190
+ axisLine={false}
191
+ tickFormatter={(value) => {
192
+ if (xAxisFormatter) {
193
+ return xAxisFormatter(value);
194
+ }
195
+ return config[value as keyof typeof config]?.label?.toString() || value;
196
+ }}
197
+ />
198
+ <YAxis
199
+ tickLine={false}
200
+ axisLine={false}
201
+ tickFormatter={(value) => (yAxisFormatter ? yAxisFormatter(value) : value)}
202
+ width={yAxisFormatter ? 50 : undefined}
203
+ />
204
+
205
+ {showTooltip && (
206
+ <ChartTooltip
207
+ cursor={false}
208
+ content={
209
+ <ChartTooltipContent
210
+ indicator={stacked ? "line" : "dot"}
211
+ formatter={tooltipFormatter}
212
+ />
213
+ }
214
+ />
215
+ )}
216
+
217
+ {showLegend && <ChartLegend content={<ChartLegendContent />} />}
218
+
219
+ <defs>
220
+ {gradient &&
221
+ dataKeys.map((key) => (
222
+ <linearGradient key={key} id={`gradient-area-${key}`} x1="0" y1="0" x2="0" y2="1">
223
+ <stop offset="0%" stopColor={`var(--color-${key})`} stopOpacity={0.6} />
224
+ <stop offset="100%" stopColor={`var(--color-${key})`} stopOpacity={0.05} />
225
+ </linearGradient>
226
+ ))}
227
+ </defs>
228
+
229
+ {dataKeys.map((key) => (
230
+ <Area
231
+ key={key}
232
+ dataKey={key}
233
+ type={curveType}
234
+ fill={gradient ? `url(#gradient-area-${key})` : `var(--color-${key})`}
235
+ stroke={`var(--color-${key})`}
236
+ fillOpacity={gradient ? 1 : fillOpacity}
237
+ strokeWidth={strokeWidth}
238
+ stackId={stackId}
239
+ dot={showDots}
240
+ activeDot={
241
+ activeDot !== undefined ? activeDot : showDots ? { r: 4, strokeWidth: 2 } : undefined
242
+ }
243
+ />
244
+ ))}
245
+ </RechartsAreaChart>
246
+ </ChartContainer>
247
+ );
248
+ }