@object-ui/plugin-charts 3.1.5 → 3.3.1

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 (36) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +24 -0
  3. package/dist/{AdvancedChartImpl-DmHTUUVD.js → AdvancedChartImpl-DxaZtNlE.js} +1214 -1206
  4. package/dist/{BarChart-XZkfLmcU.js → BarChart-BQS4sYHd.js} +3859 -3766
  5. package/dist/{ChartImpl-0VlpsMWG.js → ChartImpl-BaXisyXJ.js} +6 -6
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.js +207 -63
  8. package/dist/index.umd.cjs +19 -19
  9. package/dist/{jsx-runtime-C8d0IhUE.js → jsx-runtime-Caia9pQX.js} +1 -1
  10. package/dist/packages/plugin-charts/src/ObjectChart.d.ts +31 -0
  11. package/package.json +34 -10
  12. package/.turbo/turbo-build.log +0 -26
  13. package/dist/src/ObjectChart.d.ts +0 -12
  14. package/examples/chart-examples.ts +0 -54
  15. package/src/AdvancedChartImpl.tsx +0 -309
  16. package/src/ChartContainerImpl.tsx +0 -353
  17. package/src/ChartImpl.tsx +0 -91
  18. package/src/ChartRenderer.tsx +0 -112
  19. package/src/ObjectChart.stories.tsx +0 -104
  20. package/src/ObjectChart.tsx +0 -145
  21. package/src/__tests__/ObjectChart.aggregation.test.ts +0 -166
  22. package/src/__tests__/ObjectChart.dataFetch.test.tsx +0 -303
  23. package/src/index.test.ts +0 -136
  24. package/src/index.tsx +0 -172
  25. package/src/types.ts +0 -68
  26. package/tsconfig.json +0 -17
  27. package/vite.config.ts +0 -61
  28. package/vitest.config.ts +0 -13
  29. package/vitest.setup.ts +0 -1
  30. /package/dist/{src → packages/plugin-charts/src}/AdvancedChartImpl.d.ts +0 -0
  31. /package/dist/{src → packages/plugin-charts/src}/ChartContainerImpl.d.ts +0 -0
  32. /package/dist/{src → packages/plugin-charts/src}/ChartImpl.d.ts +0 -0
  33. /package/dist/{src → packages/plugin-charts/src}/ChartRenderer.d.ts +0 -0
  34. /package/dist/{src → packages/plugin-charts/src}/ObjectChart.stories.d.ts +0 -0
  35. /package/dist/{src → packages/plugin-charts/src}/index.d.ts +0 -0
  36. /package/dist/{src → packages/plugin-charts/src}/types.d.ts +0 -0
@@ -1,353 +0,0 @@
1
- /**
2
- * ObjectUI
3
- * Copyright (c) 2024-present ObjectStack Inc.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- */
8
-
9
- "use client"
10
-
11
- import * as React from "react"
12
- import { ResponsiveContainer, Tooltip, Legend } from "recharts"
13
-
14
- // Utility function to merge class names (inline to avoid external dependency)
15
- const cn = (...classes: (string | undefined)[]) => classes.filter(Boolean).join(' ')
16
-
17
- // Format: { THEME_NAME: CSS_SELECTOR }
18
- const THEMES = { light: "", dark: ".dark" } as const
19
-
20
- export type ChartConfig = {
21
- [k in string]: {
22
- label?: React.ReactNode
23
- icon?: React.ComponentType
24
- } & (
25
- | { color?: string; theme?: never }
26
- | { color?: never; theme: Record<keyof typeof THEMES, string> }
27
- )
28
- }
29
-
30
- type ChartContextProps = {
31
- config: ChartConfig
32
- }
33
-
34
- const ChartContext = React.createContext<ChartContextProps | null>(null)
35
-
36
- function useChart() {
37
- const context = React.useContext(ChartContext)
38
-
39
- if (!context) {
40
- throw new Error("useChart must be used within a <ChartContainer />")
41
- }
42
-
43
- return context
44
- }
45
-
46
- function ChartContainer({
47
- id,
48
- className,
49
- children,
50
- config,
51
- ...props
52
- }: React.ComponentProps<"div"> & {
53
- config: ChartConfig
54
- children: React.ComponentProps<
55
- typeof ResponsiveContainer
56
- >["children"]
57
- }) {
58
- const uniqueId = React.useId()
59
- const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`
60
-
61
- return (
62
- <ChartContext.Provider value={{ config }}>
63
- <div
64
- data-slot="chart"
65
- data-chart={chartId}
66
- className={cn(
67
- "flex w-full h-[350px] justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground",
68
- className
69
- )}
70
- {...props}
71
- >
72
- <ChartStyle id={chartId} config={config} />
73
- <ResponsiveContainer width="100%" height="100%">
74
- {children}
75
- </ResponsiveContainer>
76
- </div>
77
- </ChartContext.Provider>
78
- )
79
- }
80
-
81
- const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
82
- const colorConfig = Object.entries(config).filter(
83
- ([, config]) => config.theme || config.color
84
- )
85
-
86
- if (!colorConfig.length) {
87
- return null
88
- }
89
-
90
- return (
91
- <style
92
- dangerouslySetInnerHTML={{
93
- __html: Object.entries(THEMES)
94
- .map(
95
- ([theme, prefix]) => `
96
- ${prefix} [data-chart=${id}] {
97
- ${colorConfig
98
- .map(([key, itemConfig]) => {
99
- const color =
100
- itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
101
- itemConfig.color
102
- return color ? ` --color-${key}: ${color};` : null
103
- })
104
- .join("\n")}
105
- }
106
- `
107
- )
108
- .join("\n"),
109
- }}
110
- />
111
- )
112
- }
113
-
114
- const ChartTooltip = Tooltip
115
-
116
- function ChartTooltipContent({
117
- active,
118
- payload,
119
- className,
120
- indicator = "dot",
121
- hideLabel = false,
122
- hideIndicator = false,
123
- label,
124
- labelFormatter,
125
- labelClassName,
126
- formatter,
127
- color,
128
- nameKey,
129
- labelKey,
130
- }: any) {
131
- const { config } = useChart()
132
-
133
- const tooltipLabel = React.useMemo(() => {
134
- if (hideLabel || !payload?.length) {
135
- return null
136
- }
137
-
138
- const [item] = payload
139
- const key = `${labelKey || item?.dataKey || item?.name || "value"}`
140
- const itemConfig = getPayloadConfigFromPayload(config, item, key)
141
- const value =
142
- !labelKey && typeof label === "string"
143
- ? config[label as keyof typeof config]?.label || label
144
- : itemConfig?.label
145
-
146
- if (labelFormatter) {
147
- return (
148
- <div className={cn("font-medium", labelClassName)}>
149
- {labelFormatter(value, payload)}
150
- </div>
151
- )
152
- }
153
-
154
- if (!value) {
155
- return null
156
- }
157
-
158
- return <div className={cn("font-medium", labelClassName)}>{value}</div>
159
- }, [
160
- label,
161
- labelFormatter,
162
- payload,
163
- hideLabel,
164
- labelClassName,
165
- config,
166
- labelKey,
167
- ])
168
-
169
- if (!active || !payload?.length) {
170
- return null
171
- }
172
-
173
- const nestLabel = payload.length === 1 && indicator !== "dot"
174
-
175
- return (
176
- <div
177
- className={cn(
178
- "border-border/50 bg-background grid min-w-[8rem] items-start gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs shadow-xl",
179
- className
180
- )}
181
- >
182
- {!nestLabel ? tooltipLabel : null}
183
- <div className="grid gap-1.5">
184
- {payload
185
- .filter((item: any) => item.type !== "none")
186
- .map((item: any, index: number) => {
187
- const key = `${nameKey || item.name || item.dataKey || "value"}`
188
- const itemConfig = getPayloadConfigFromPayload(config, item, key)
189
- const indicatorColor = color || item.payload.fill || item.color
190
-
191
- return (
192
- <div
193
- key={item.dataKey}
194
- className={cn(
195
- "[&>svg]:text-muted-foreground flex w-full flex-wrap items-stretch gap-2 [&>svg]:h-2.5 [&>svg]:w-2.5",
196
- indicator === "dot" ? "items-center" : ""
197
- )}
198
- >
199
- {formatter && item?.value !== undefined && item.name ? (
200
- formatter(item.value, item.name, item, index, item.payload)
201
- ) : (
202
- <>
203
- {itemConfig?.icon ? (
204
- <itemConfig.icon />
205
- ) : (
206
- !hideIndicator && (
207
- <div
208
- className={cn(
209
- "shrink-0 rounded-[2px] border-(--color-border) bg-(--color-bg)",
210
- indicator === "dot" ? "h-2.5 w-2.5" : "",
211
- indicator === "line" ? "w-1" : "",
212
- indicator === "dashed" ? "w-0 border-[1.5px] border-dashed bg-transparent" : "",
213
- (nestLabel && indicator === "dashed") ? "my-0.5" : "",
214
- )}
215
- style={
216
-
217
- {
218
- "--color-bg": indicatorColor,
219
- "--color-border": indicatorColor,
220
- } as React.CSSProperties
221
- }
222
- />
223
- )
224
- )}
225
- <div
226
- className={cn(
227
- "flex flex-1 justify-between leading-none",
228
- nestLabel ? "items-end" : "items-center"
229
- )}
230
- >
231
- <div className="grid gap-1.5">
232
- {nestLabel ? tooltipLabel : null}
233
- <span className="text-muted-foreground">
234
- {itemConfig?.label || item.name}
235
- </span>
236
- </div>
237
- {item.value && (
238
- <span className="text-foreground font-mono font-medium tabular-nums">
239
- {item.value.toLocaleString()}
240
- </span>
241
- )}
242
- </div>
243
- </>
244
- )}
245
- </div>
246
- )
247
- })}
248
- </div>
249
- </div>
250
- )
251
- }
252
-
253
- const ChartLegend = Legend
254
-
255
- function ChartLegendContent({
256
- className,
257
- hideIcon = false,
258
- payload,
259
- verticalAlign = "bottom",
260
- nameKey,
261
- }: any) {
262
- const { config } = useChart()
263
-
264
- if (!payload?.length) {
265
- return null
266
- }
267
-
268
- return (
269
- <div
270
- className={cn(
271
- "flex items-center justify-center gap-4",
272
- verticalAlign === "top" ? "pb-3" : "pt-3",
273
- className
274
- )}
275
- >
276
- {payload
277
- .filter((item: any) => item.type !== "none")
278
- .map((item: any) => {
279
- const key = `${nameKey || item.dataKey || "value"}`
280
- const itemConfig = getPayloadConfigFromPayload(config, item, key)
281
-
282
- return (
283
- <div
284
- key={item.value}
285
- className={cn(
286
- "[&>svg]:text-muted-foreground flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3"
287
- )}
288
- >
289
- {itemConfig?.icon && !hideIcon ? (
290
- <itemConfig.icon />
291
- ) : (
292
- <div
293
- className="h-2 w-2 shrink-0 rounded-[2px]"
294
- style={{
295
- backgroundColor: item.color,
296
- }}
297
- />
298
- )}
299
- {itemConfig?.label}
300
- </div>
301
- )
302
- })}
303
- </div>
304
- )
305
- }
306
-
307
- // Helper to extract item config from a payload.
308
- function getPayloadConfigFromPayload(
309
- config: ChartConfig,
310
- payload: unknown,
311
- key: string
312
- ) {
313
- if (typeof payload !== "object" || payload === null) {
314
- return undefined
315
- }
316
-
317
- const payloadPayload =
318
- "payload" in payload &&
319
- typeof payload.payload === "object" &&
320
- payload.payload !== null
321
- ? payload.payload
322
- : undefined
323
-
324
- let configLabelKey: string = key
325
-
326
- if (
327
- key in payload &&
328
- typeof payload[key as keyof typeof payload] === "string"
329
- ) {
330
- configLabelKey = payload[key as keyof typeof payload] as string
331
- } else if (
332
- payloadPayload &&
333
- key in payloadPayload &&
334
- typeof payloadPayload[key as keyof typeof payloadPayload] === "string"
335
- ) {
336
- configLabelKey = payloadPayload[
337
- key as keyof typeof payloadPayload
338
- ] as string
339
- }
340
-
341
- return configLabelKey in config
342
- ? config[configLabelKey]
343
- : config[key as keyof typeof config]
344
- }
345
-
346
- export {
347
- ChartContainer,
348
- ChartTooltip,
349
- ChartTooltipContent,
350
- ChartLegend,
351
- ChartLegendContent,
352
- ChartStyle,
353
- }
package/src/ChartImpl.tsx DELETED
@@ -1,91 +0,0 @@
1
- /**
2
- * ObjectUI
3
- * Copyright (c) 2024-present ObjectStack Inc.
4
- *
5
- * This source code is licensed under the MIT license found in the
6
- * LICENSE file in the root directory of this source tree.
7
- */
8
-
9
- import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
10
-
11
- export interface ChartImplProps {
12
- data?: Array<Record<string, any>>;
13
- dataKey?: string;
14
- xAxisKey?: string;
15
- height?: number;
16
- className?: string;
17
- color?: string;
18
- }
19
-
20
- /**
21
- * ChartImpl - The heavy implementation that imports Recharts
22
- * This component is lazy-loaded to avoid including Recharts in the initial bundle
23
- */
24
- export default function ChartImpl({
25
- data = [],
26
- dataKey = 'value',
27
- xAxisKey = 'name',
28
- height = 400,
29
- className = '',
30
- // Default to standard primary color
31
- color = 'hsl(var(--primary))',
32
- }: ChartImplProps) {
33
- return (
34
- <div className={`p-2 sm:p-3 md:p-4 rounded-xl border border-border bg-card/40 backdrop-blur-sm shadow-lg shadow-background/5 ${className}`}>
35
- <ResponsiveContainer width="100%" height={height}>
36
- <BarChart data={data} margin={{ top: 10, right: 10, left: 10, bottom: 5 }}>
37
- <defs>
38
- <linearGradient id="barGradient" x1="0" y1="0" x2="0" y2="1">
39
- <stop offset="0%" stopColor={color} stopOpacity={1} />
40
- <stop offset="90%" stopColor={color} stopOpacity={0.6} />
41
- <stop offset="100%" stopColor={color} stopOpacity={0.3} />
42
- </linearGradient>
43
- <filter id="glow" height="130%">
44
- <feGaussianBlur in="SourceAlpha" stdDeviation="3" result="blur" />
45
- <feOffset in="blur" dx="0" dy="0" result="offsetBlur" />
46
- <feFlood floodColor={color} floodOpacity="0.5" result="offsetColor" />
47
- <feComposite in="offsetColor" in2="offsetBlur" operator="in" result="offsetBlur" />
48
- <feMerge>
49
- <feMergeNode in="offsetBlur" />
50
- <feMergeNode in="SourceGraphic" />
51
- </feMerge>
52
- </filter>
53
- </defs>
54
- <CartesianGrid strokeDasharray="3 3" stroke="hsl(var(--border))" vertical={false} />
55
- <XAxis
56
- dataKey={xAxisKey}
57
- tick={{ fill: 'hsl(var(--muted-foreground))', fontSize: 12, fontFamily: 'monospace' }}
58
- tickLine={false}
59
- axisLine={{ stroke: 'hsl(var(--border))' }}
60
- dy={10}
61
- />
62
- <YAxis
63
- tick={{ fill: 'hsl(var(--muted-foreground))', fontSize: 12, fontFamily: 'monospace' }}
64
- tickLine={false}
65
- axisLine={false}
66
- />
67
- <Tooltip
68
- cursor={{ fill: 'hsl(var(--muted))', opacity: 0.2 }}
69
- contentStyle={{
70
- backgroundColor: 'hsl(var(--popover))',
71
- borderColor: 'hsl(var(--border))',
72
- color: 'hsl(var(--popover-foreground))',
73
- borderRadius: '8px',
74
- fontFamily: 'monospace',
75
- boxShadow: '0 4px 6px -1px rgb(0 0 0 / 0.1)'
76
- }}
77
- itemStyle={{ color: 'hsl(var(--primary))' }}
78
- />
79
- <Legend wrapperStyle={{ paddingTop: '20px', fontFamily: 'monospace' }} />
80
- <Bar
81
- dataKey={dataKey}
82
- fill="url(#barGradient)"
83
- radius={[4, 4, 0, 0]}
84
- filter="url(#glow)"
85
- animationDuration={1500}
86
- />
87
- </BarChart>
88
- </ResponsiveContainer>
89
- </div>
90
- );
91
- }
@@ -1,112 +0,0 @@
1
-
2
- import React, { Suspense } from 'react';
3
- import { Skeleton } from '@object-ui/components';
4
- import type { ChartConfig } from './ChartContainerImpl';
5
-
6
- // 🚀 Lazy load the implementation files
7
- const LazyChart = React.lazy(() => import('./ChartImpl'));
8
- const LazyAdvancedChart = React.lazy(() => import('./AdvancedChartImpl'));
9
-
10
- export interface ChartBarRendererProps {
11
- schema: {
12
- type: string;
13
- id?: string;
14
- className?: string;
15
- data?: Array<Record<string, any>>;
16
- dataKey?: string;
17
- xAxisKey?: string;
18
- height?: number;
19
- color?: string;
20
- };
21
- }
22
-
23
- /**
24
- * ChartBarRenderer - The public API for the bar chart component
25
- */
26
- export const ChartBarRenderer: React.FC<ChartBarRendererProps> = ({ schema }) => {
27
- return (
28
- <Suspense fallback={<Skeleton className="w-full h-48 sm:h-64 md:h-80 lg:h-[400px]" />}>
29
- <LazyChart
30
- data={schema.data}
31
- dataKey={schema.dataKey}
32
- xAxisKey={schema.xAxisKey}
33
- height={schema.height}
34
- className={schema.className}
35
- color={schema.color}
36
- />
37
- </Suspense>
38
- );
39
- };
40
-
41
- export interface ChartRendererProps {
42
- schema: {
43
- type: string;
44
- id?: string;
45
- className?: string;
46
- chartType?: 'bar' | 'line' | 'area' | 'pie' | 'donut' | 'radar' | 'scatter' | 'combo';
47
- data?: Array<Record<string, any>>;
48
- config?: Record<string, any>;
49
- xAxisKey?: string;
50
- series?: Array<{ dataKey: string }>;
51
- };
52
- }
53
-
54
- /**
55
- * ChartRenderer - The public API for the advanced chart component
56
- */
57
- export const ChartRenderer: React.FC<ChartRendererProps> = ({ schema }) => {
58
- // ⚡️ Adapter: Normalize JSON schema to Recharts Props
59
- const props = React.useMemo(() => {
60
- // 1. Defaults
61
- let series = schema.series;
62
- let xAxisKey = schema.xAxisKey;
63
- let config = schema.config;
64
-
65
- // 2. Adapt Tremor/Simple format (categories -> series, index -> xAxisKey)
66
- if (!xAxisKey) {
67
- if ((schema as any).index) xAxisKey = (schema as any).index;
68
- else if ((schema as any).category) xAxisKey = (schema as any).category; // Support Pie/Donut category
69
- }
70
-
71
- if (!series) {
72
- if ((schema as any).categories) {
73
- series = (schema as any).categories.map((cat: string) => ({ dataKey: cat }));
74
- } else if ((schema as any).value) {
75
- // Single value adapter (for Pie/Simple charts)
76
- series = [{ dataKey: (schema as any).value }];
77
- }
78
- }
79
-
80
- // 3. Auto-generate config/colors if missing
81
- if (!config && series) {
82
- const colors = (schema as any).colors || ['hsl(var(--chart-1))', 'hsl(var(--chart-2))', 'hsl(var(--chart-3))'];
83
- const newConfig: ChartConfig = {};
84
- series.forEach((s: any, idx: number) => {
85
- newConfig[s.dataKey] = { label: s.dataKey, color: colors[idx % colors.length] };
86
- });
87
- config = newConfig;
88
- }
89
-
90
- return {
91
- chartType: schema.chartType,
92
- data: Array.isArray(schema.data) ? schema.data : [],
93
- config,
94
- xAxisKey,
95
- series,
96
- className: schema.className
97
- };
98
- }, [schema]);
99
-
100
- return (
101
- <Suspense fallback={<Skeleton className="w-full h-48 sm:h-64 md:h-80 lg:h-[400px]" />}>
102
- <LazyAdvancedChart
103
- chartType={props.chartType}
104
- data={props.data}
105
- config={props.config}
106
- xAxisKey={props.xAxisKey}
107
- series={props.series}
108
- className={props.className}
109
- />
110
- </Suspense>
111
- );
112
- };
@@ -1,104 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react';
2
- import { SchemaRenderer } from '@object-ui/react';
3
- import type { BaseSchema } from '@object-ui/types';
4
-
5
- const meta = {
6
- title: 'Plugins/ObjectChart',
7
- component: SchemaRenderer,
8
- parameters: {
9
- layout: 'padded',
10
- },
11
- tags: ['autodocs'],
12
- argTypes: {
13
- schema: { table: { disable: true } },
14
- },
15
- } satisfies Meta<any>;
16
-
17
- export default meta;
18
- type Story = StoryObj<typeof meta>;
19
-
20
- const renderStory = (args: any) => <SchemaRenderer schema={args as unknown as BaseSchema} />;
21
-
22
- export const Default: Story = {
23
- render: renderStory,
24
- args: {
25
- type: 'chart',
26
- chartType: 'bar',
27
- data: [
28
- { month: 'Jan', revenue: 4200 },
29
- { month: 'Feb', revenue: 3800 },
30
- { month: 'Mar', revenue: 5100 },
31
- { month: 'Apr', revenue: 6300 },
32
- { month: 'May', revenue: 5800 },
33
- { month: 'Jun', revenue: 7200 },
34
- ],
35
- xAxisKey: 'month',
36
- series: [{ dataKey: 'revenue' }],
37
- config: {
38
- revenue: { label: 'Revenue', color: '#3b82f6' },
39
- },
40
- } as any,
41
- };
42
-
43
- export const LineChart: Story = {
44
- render: renderStory,
45
- args: {
46
- type: 'chart',
47
- chartType: 'line',
48
- data: [
49
- { month: 'Jan', users: 150, sessions: 520 },
50
- { month: 'Feb', users: 210, sessions: 680 },
51
- { month: 'Mar', users: 280, sessions: 910 },
52
- { month: 'Apr', users: 350, sessions: 1250 },
53
- { month: 'May', users: 430, sessions: 1600 },
54
- { month: 'Jun', users: 540, sessions: 2050 },
55
- ],
56
- config: {
57
- users: { label: 'Active Users', color: '#8b5cf6' },
58
- sessions: { label: 'Sessions', color: '#ec4899' },
59
- },
60
- xAxisKey: 'month',
61
- series: [{ dataKey: 'users' }, { dataKey: 'sessions' }],
62
- } as any,
63
- };
64
-
65
- export const PieChart: Story = {
66
- render: renderStory,
67
- args: {
68
- type: 'pie-chart',
69
- data: [
70
- { name: 'Desktop', value: 55 },
71
- { name: 'Mobile', value: 35 },
72
- { name: 'Tablet', value: 10 },
73
- ],
74
- xAxisKey: 'name',
75
- series: [{ dataKey: 'value' }],
76
- config: {
77
- Desktop: { label: 'Desktop', color: 'hsl(var(--chart-1))' },
78
- Mobile: { label: 'Mobile', color: 'hsl(var(--chart-2))' },
79
- Tablet: { label: 'Tablet', color: 'hsl(var(--chart-3))' },
80
- },
81
- } as any,
82
- };
83
-
84
- export const AreaChart: Story = {
85
- render: renderStory,
86
- args: {
87
- type: 'chart',
88
- chartType: 'area',
89
- data: [
90
- { date: 'Mon', traffic: 3200 },
91
- { date: 'Tue', traffic: 2800 },
92
- { date: 'Wed', traffic: 4100 },
93
- { date: 'Thu', traffic: 3600 },
94
- { date: 'Fri', traffic: 4800 },
95
- { date: 'Sat', traffic: 2900 },
96
- { date: 'Sun', traffic: 3400 },
97
- ],
98
- config: {
99
- traffic: { label: 'Page Views', color: '#06b6d4' },
100
- },
101
- xAxisKey: 'date',
102
- series: [{ dataKey: 'traffic' }],
103
- } as any,
104
- };