@object-ui/plugin-charts 0.3.0 → 0.5.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.
- package/.turbo/turbo-build.log +20 -0
- package/CHANGELOG.md +11 -0
- package/README.md +4 -4
- package/dist/AdvancedChartImpl-DcIHnCct.js +4529 -0
- package/dist/BarChart-C_I0OFbj.js +18488 -0
- package/dist/{ChartImpl-DiqV9Evl.js → ChartImpl-CU5lEzui.js} +2 -2
- package/dist/index-DgxI83zT.js +478 -0
- package/dist/index.js +5 -6
- package/dist/index.umd.cjs +50 -74
- package/dist/src/AdvancedChartImpl.d.ts +1 -1
- package/dist/src/ChartContainerImpl.d.ts +7 -0
- package/dist/src/ChartImpl.d.ts +7 -0
- package/dist/src/ChartRenderer.d.ts +35 -0
- package/dist/src/ObjectChart.d.ts +1 -0
- package/dist/src/index.d.ts +5 -39
- package/dist/src/types.d.ts +3 -3
- package/examples/chart-examples.ts +54 -0
- package/package.json +19 -9
- package/src/AdvancedChartImpl.tsx +102 -18
- package/src/ChartContainerImpl.tsx +8 -0
- package/src/ChartImpl.tsx +8 -0
- package/src/ChartRenderer.tsx +112 -0
- package/src/ObjectChart.tsx +74 -0
- package/src/index.test.ts +15 -7
- package/src/index.tsx +79 -119
- package/src/registration.test.tsx +22 -0
- package/src/types.ts +10 -2
- package/vite.config.ts +23 -0
- package/vitest.config.ts +13 -0
- package/vitest.setup.ts +1 -0
- package/dist/AdvancedChartImpl-LUnT2ZAf.js +0 -2320
- package/dist/BarChart-CRc8MAtI.js +0 -17766
- package/dist/index-BcjHuFVN.js +0 -738
- package/dist/src/index.test.d.ts +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ChartConfig } from './ChartContainerImpl';
|
|
2
2
|
export interface AdvancedChartImplProps {
|
|
3
|
-
chartType?: 'bar' | 'line' | 'area' | 'pie';
|
|
3
|
+
chartType?: 'bar' | 'line' | 'area' | 'pie' | 'donut' | 'radar' | 'scatter';
|
|
4
4
|
data?: Array<Record<string, any>>;
|
|
5
5
|
config?: ChartConfig;
|
|
6
6
|
xAxisKey?: string;
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { ResponsiveContainer, Tooltip, Legend } from 'recharts';
|
|
2
|
+
/**
|
|
3
|
+
* ObjectUI
|
|
4
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
5
|
+
*
|
|
6
|
+
* This source code is licensed under the MIT license found in the
|
|
7
|
+
* LICENSE file in the root directory of this source tree.
|
|
8
|
+
*/
|
|
2
9
|
import * as React from "react";
|
|
3
10
|
declare const THEMES: {
|
|
4
11
|
readonly light: "";
|
package/dist/src/ChartImpl.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
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
|
+
*/
|
|
1
8
|
export interface ChartImplProps {
|
|
2
9
|
data?: Array<Record<string, any>>;
|
|
3
10
|
dataKey?: string;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export interface ChartBarRendererProps {
|
|
3
|
+
schema: {
|
|
4
|
+
type: string;
|
|
5
|
+
id?: string;
|
|
6
|
+
className?: string;
|
|
7
|
+
data?: Array<Record<string, any>>;
|
|
8
|
+
dataKey?: string;
|
|
9
|
+
xAxisKey?: string;
|
|
10
|
+
height?: number;
|
|
11
|
+
color?: string;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* ChartBarRenderer - The public API for the bar chart component
|
|
16
|
+
*/
|
|
17
|
+
export declare const ChartBarRenderer: React.FC<ChartBarRendererProps>;
|
|
18
|
+
export interface ChartRendererProps {
|
|
19
|
+
schema: {
|
|
20
|
+
type: string;
|
|
21
|
+
id?: string;
|
|
22
|
+
className?: string;
|
|
23
|
+
chartType?: 'bar' | 'line' | 'area';
|
|
24
|
+
data?: Array<Record<string, any>>;
|
|
25
|
+
config?: Record<string, any>;
|
|
26
|
+
xAxisKey?: string;
|
|
27
|
+
series?: Array<{
|
|
28
|
+
dataKey: string;
|
|
29
|
+
}>;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* ChartRenderer - The public API for the advanced chart component
|
|
34
|
+
*/
|
|
35
|
+
export declare const ChartRenderer: React.FC<ChartRendererProps>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ObjectChart: (props: any) => import("react/jsx-runtime").JSX.Element;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,42 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChartBarRenderer, ChartRenderer } from './ChartRenderer';
|
|
2
2
|
export type { BarChartSchema } from './types';
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
type: string;
|
|
6
|
-
id?: string;
|
|
7
|
-
className?: string;
|
|
8
|
-
data?: Array<Record<string, any>>;
|
|
9
|
-
dataKey?: string;
|
|
10
|
-
xAxisKey?: string;
|
|
11
|
-
height?: number;
|
|
12
|
-
color?: string;
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* ChartBarRenderer - The public API for the bar chart component
|
|
17
|
-
* This wrapper handles lazy loading internally using React.Suspense
|
|
18
|
-
*/
|
|
19
|
-
export declare const ChartBarRenderer: React.FC<ChartBarRendererProps>;
|
|
20
|
-
export interface ChartRendererProps {
|
|
21
|
-
schema: {
|
|
22
|
-
type: string;
|
|
23
|
-
id?: string;
|
|
24
|
-
className?: string;
|
|
25
|
-
chartType?: 'bar' | 'line' | 'area';
|
|
26
|
-
data?: Array<Record<string, any>>;
|
|
27
|
-
config?: Record<string, any>;
|
|
28
|
-
xAxisKey?: string;
|
|
29
|
-
series?: Array<{
|
|
30
|
-
dataKey: string;
|
|
31
|
-
}>;
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* ChartRenderer - The public API for the advanced chart component
|
|
36
|
-
* Supports multiple chart types (bar, line, area) with full configuration
|
|
37
|
-
*/
|
|
38
|
-
export declare const ChartRenderer: React.FC<ChartRendererProps>;
|
|
3
|
+
export { ChartBarRenderer, ChartRenderer };
|
|
4
|
+
export { ObjectChart } from './ObjectChart';
|
|
39
5
|
export declare const chartComponents: {
|
|
40
|
-
'chart
|
|
41
|
-
chart:
|
|
6
|
+
'bar-chart': import('react').FC<import('./ChartRenderer').ChartBarRendererProps>;
|
|
7
|
+
chart: import('react').FC<import('./ChartRenderer').ChartRendererProps>;
|
|
42
8
|
};
|
package/dist/src/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BaseSchema } from '
|
|
1
|
+
import { BaseSchema } from '../../types/src';
|
|
2
2
|
/**
|
|
3
3
|
* Bar Chart component schema.
|
|
4
4
|
* Renders a bar chart using Recharts library.
|
|
@@ -8,7 +8,7 @@ import { BaseSchema } from '@object-ui/types';
|
|
|
8
8
|
* import type { BarChartSchema } from '@object-ui/plugin-charts';
|
|
9
9
|
*
|
|
10
10
|
* const chartSchema: BarChartSchema = {
|
|
11
|
-
* type: 'chart
|
|
11
|
+
* type: 'bar-chart',
|
|
12
12
|
* data: [
|
|
13
13
|
* { name: 'Jan', value: 400 },
|
|
14
14
|
* { name: 'Feb', value: 300 }
|
|
@@ -19,7 +19,7 @@ import { BaseSchema } from '@object-ui/types';
|
|
|
19
19
|
* ```
|
|
20
20
|
*/
|
|
21
21
|
export interface BarChartSchema extends BaseSchema {
|
|
22
|
-
type: 'chart
|
|
22
|
+
type: 'bar-chart';
|
|
23
23
|
/**
|
|
24
24
|
* Array of data points to display in the chart.
|
|
25
25
|
*/
|
|
@@ -0,0 +1,54 @@
|
|
|
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
|
+
/**
|
|
10
|
+
* Example: Using all new chart types
|
|
11
|
+
*
|
|
12
|
+
* This example demonstrates the new Pie, Donut, Radar, and Scatter chart types
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export const pieChartExample = {
|
|
16
|
+
type: 'pie-chart',
|
|
17
|
+
data: [
|
|
18
|
+
{ name: 'Chrome', value: 65 },
|
|
19
|
+
{ name: 'Firefox', value: 20 },
|
|
20
|
+
{ name: 'Safari', value: 10 },
|
|
21
|
+
{ name: 'Edge', value: 5 },
|
|
22
|
+
],
|
|
23
|
+
xAxisKey: 'name',
|
|
24
|
+
series: [{ dataKey: 'value' }],
|
|
25
|
+
config: {
|
|
26
|
+
Chrome: { label: 'Chrome', color: 'hsl(var(--chart-1))' },
|
|
27
|
+
Firefox: { label: 'Firefox', color: 'hsl(var(--chart-2))' },
|
|
28
|
+
Safari: { label: 'Safari', color: 'hsl(var(--chart-3))' },
|
|
29
|
+
Edge: { label: 'Edge', color: 'hsl(var(--chart-4))' },
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const donutChartExample = {
|
|
34
|
+
type: 'donut-chart',
|
|
35
|
+
data: [
|
|
36
|
+
{ category: 'Electronics', revenue: 45000 },
|
|
37
|
+
{ category: 'Clothing', revenue: 32000 },
|
|
38
|
+
{ category: 'Food', revenue: 28000 },
|
|
39
|
+
{ category: 'Books', revenue: 15000 },
|
|
40
|
+
],
|
|
41
|
+
xAxisKey: 'category',
|
|
42
|
+
series: [{ dataKey: 'revenue' }]
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const radarChartExample = {
|
|
46
|
+
type: 'radar-chart',
|
|
47
|
+
data: [
|
|
48
|
+
{ skill: 'React', score: 90 },
|
|
49
|
+
{ skill: 'TypeScript', score: 85 },
|
|
50
|
+
{ skill: 'Node.js', score: 80 }
|
|
51
|
+
],
|
|
52
|
+
xAxisKey: 'skill',
|
|
53
|
+
series: [{ dataKey: 'score' }]
|
|
54
|
+
};
|
package/package.json
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@object-ui/plugin-charts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
|
+
"description": "Chart components plugin for Object UI, powered by Recharts",
|
|
7
|
+
"homepage": "https://www.objectui.org",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/objectstack-ai/objectui.git",
|
|
11
|
+
"directory": "packages/plugin-charts"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/objectstack-ai/objectui/issues"
|
|
15
|
+
},
|
|
6
16
|
"main": "dist/index.umd.cjs",
|
|
7
17
|
"module": "dist/index.js",
|
|
8
18
|
"types": "dist/index.d.ts",
|
|
@@ -14,20 +24,20 @@
|
|
|
14
24
|
}
|
|
15
25
|
},
|
|
16
26
|
"dependencies": {
|
|
17
|
-
"recharts": "^
|
|
18
|
-
"@object-ui/components": "0.
|
|
19
|
-
"@object-ui/core": "0.
|
|
20
|
-
"@object-ui/react": "0.
|
|
21
|
-
"@object-ui/types": "0.
|
|
27
|
+
"recharts": "^3.7.0",
|
|
28
|
+
"@object-ui/components": "0.5.0",
|
|
29
|
+
"@object-ui/core": "0.5.0",
|
|
30
|
+
"@object-ui/react": "0.5.0",
|
|
31
|
+
"@object-ui/types": "0.5.0"
|
|
22
32
|
},
|
|
23
33
|
"peerDependencies": {
|
|
24
34
|
"react": "^18.0.0 || ^19.0.0",
|
|
25
35
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
26
36
|
},
|
|
27
37
|
"devDependencies": {
|
|
28
|
-
"@types/react": "^
|
|
29
|
-
"@types/react-dom": "^
|
|
30
|
-
"@vitejs/plugin-react": "^
|
|
38
|
+
"@types/react": "^19.2.10",
|
|
39
|
+
"@types/react-dom": "^19.2.3",
|
|
40
|
+
"@vitejs/plugin-react": "^5.1.3",
|
|
31
41
|
"typescript": "^5.9.3",
|
|
32
42
|
"vite": "^7.3.1",
|
|
33
43
|
"vite-plugin-dts": "^4.5.4"
|
|
@@ -1,3 +1,11 @@
|
|
|
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
|
+
|
|
1
9
|
import * as React from "react"
|
|
2
10
|
import {
|
|
3
11
|
Bar,
|
|
@@ -8,6 +16,14 @@ import {
|
|
|
8
16
|
AreaChart,
|
|
9
17
|
Pie,
|
|
10
18
|
PieChart,
|
|
19
|
+
Radar,
|
|
20
|
+
RadarChart,
|
|
21
|
+
PolarGrid,
|
|
22
|
+
PolarAngleAxis,
|
|
23
|
+
PolarRadiusAxis,
|
|
24
|
+
Scatter,
|
|
25
|
+
ScatterChart,
|
|
26
|
+
ZAxis,
|
|
11
27
|
Cell,
|
|
12
28
|
XAxis,
|
|
13
29
|
YAxis,
|
|
@@ -54,7 +70,7 @@ const TW_COLORS: Record<string, string> = {
|
|
|
54
70
|
const resolveColor = (color: string) => TW_COLORS[color] || color;
|
|
55
71
|
|
|
56
72
|
export interface AdvancedChartImplProps {
|
|
57
|
-
chartType?: 'bar' | 'line' | 'area' | 'pie';
|
|
73
|
+
chartType?: 'bar' | 'line' | 'area' | 'pie' | 'donut' | 'radar' | 'scatter';
|
|
58
74
|
data?: Array<Record<string, any>>;
|
|
59
75
|
config?: ChartConfig;
|
|
60
76
|
xAxisKey?: string;
|
|
@@ -79,11 +95,25 @@ export default function AdvancedChartImpl({
|
|
|
79
95
|
line: LineChart,
|
|
80
96
|
area: AreaChart,
|
|
81
97
|
pie: PieChart,
|
|
98
|
+
donut: PieChart,
|
|
99
|
+
radar: RadarChart,
|
|
100
|
+
scatter: ScatterChart,
|
|
82
101
|
}[chartType] || BarChart;
|
|
83
102
|
|
|
84
103
|
console.log('📈 Rendering Chart:', { chartType, dataLength: data.length, config, series, xAxisKey });
|
|
85
104
|
|
|
86
|
-
|
|
105
|
+
// Helper function to get color palette
|
|
106
|
+
const getPalette = () => [
|
|
107
|
+
'hsl(var(--chart-1))',
|
|
108
|
+
'hsl(var(--chart-2))',
|
|
109
|
+
'hsl(var(--chart-3))',
|
|
110
|
+
'hsl(var(--chart-4))',
|
|
111
|
+
'hsl(var(--chart-5))'
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
// Pie and Donut charts
|
|
115
|
+
if (chartType === 'pie' || chartType === 'donut') {
|
|
116
|
+
const innerRadius = chartType === 'donut' ? 60 : 0;
|
|
87
117
|
return (
|
|
88
118
|
<ChartContainer config={config} className={className}>
|
|
89
119
|
<PieChart>
|
|
@@ -92,7 +122,7 @@ export default function AdvancedChartImpl({
|
|
|
92
122
|
data={data}
|
|
93
123
|
dataKey={series[0]?.dataKey || 'value'}
|
|
94
124
|
nameKey={xAxisKey || 'name'}
|
|
95
|
-
innerRadius={
|
|
125
|
+
innerRadius={innerRadius}
|
|
96
126
|
strokeWidth={5}
|
|
97
127
|
paddingAngle={2}
|
|
98
128
|
outerRadius={80}
|
|
@@ -101,22 +131,9 @@ export default function AdvancedChartImpl({
|
|
|
101
131
|
// 1. Try config by nameKey (category)
|
|
102
132
|
let c = config[entry[xAxisKey]]?.color;
|
|
103
133
|
|
|
104
|
-
// 2.
|
|
134
|
+
// 2. Fallback to palette
|
|
105
135
|
if (!c) {
|
|
106
|
-
|
|
107
|
-
// Actually my adapter logic in index.tsx was: config[seriesKey].color = colors[idx]
|
|
108
|
-
// But here we are iterating DATA items, not SERIES.
|
|
109
|
-
// So we need a cycling palette.
|
|
110
|
-
// Let's assume the user didn't provide per-category config here, so we cycle default colors.
|
|
111
|
-
const palette = [
|
|
112
|
-
'hsl(var(--chart-1))',
|
|
113
|
-
'hsl(var(--chart-2))',
|
|
114
|
-
'hsl(var(--chart-3))',
|
|
115
|
-
'hsl(var(--chart-4))',
|
|
116
|
-
'hsl(var(--chart-5))'
|
|
117
|
-
];
|
|
118
|
-
// Check if we can get colors from the first series config?
|
|
119
|
-
// No, let's just use the palette or resolveColor from entry if provided in data.
|
|
136
|
+
const palette = getPalette();
|
|
120
137
|
c = palette[index % palette.length];
|
|
121
138
|
}
|
|
122
139
|
|
|
@@ -129,6 +146,73 @@ export default function AdvancedChartImpl({
|
|
|
129
146
|
);
|
|
130
147
|
}
|
|
131
148
|
|
|
149
|
+
// Radar chart
|
|
150
|
+
if (chartType === 'radar') {
|
|
151
|
+
return (
|
|
152
|
+
<ChartContainer config={config} className={className}>
|
|
153
|
+
<RadarChart data={data}>
|
|
154
|
+
<PolarGrid />
|
|
155
|
+
<PolarAngleAxis dataKey={xAxisKey} />
|
|
156
|
+
<PolarRadiusAxis />
|
|
157
|
+
<ChartTooltip content={<ChartTooltipContent />} />
|
|
158
|
+
<ChartLegend content={<ChartLegendContent />} />
|
|
159
|
+
{series.map((s: any) => {
|
|
160
|
+
const color = resolveColor(config[s.dataKey]?.color || DEFAULT_CHART_COLOR);
|
|
161
|
+
return (
|
|
162
|
+
<Radar
|
|
163
|
+
key={s.dataKey}
|
|
164
|
+
dataKey={s.dataKey}
|
|
165
|
+
stroke={color}
|
|
166
|
+
fill={color}
|
|
167
|
+
fillOpacity={0.6}
|
|
168
|
+
/>
|
|
169
|
+
);
|
|
170
|
+
})}
|
|
171
|
+
</RadarChart>
|
|
172
|
+
</ChartContainer>
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Scatter chart
|
|
177
|
+
if (chartType === 'scatter') {
|
|
178
|
+
return (
|
|
179
|
+
<ChartContainer config={config} className={className}>
|
|
180
|
+
<ScatterChart>
|
|
181
|
+
<CartesianGrid vertical={false} />
|
|
182
|
+
<XAxis
|
|
183
|
+
type="number"
|
|
184
|
+
dataKey={xAxisKey}
|
|
185
|
+
name={String(config[xAxisKey]?.label || xAxisKey)}
|
|
186
|
+
tickLine={false}
|
|
187
|
+
axisLine={false}
|
|
188
|
+
/>
|
|
189
|
+
<YAxis
|
|
190
|
+
type="number"
|
|
191
|
+
dataKey={series[0]?.dataKey || 'value'}
|
|
192
|
+
name={String(config[series[0]?.dataKey]?.label || series[0]?.dataKey)}
|
|
193
|
+
tickLine={false}
|
|
194
|
+
axisLine={false}
|
|
195
|
+
/>
|
|
196
|
+
<ZAxis type="number" range={[60, 400]} />
|
|
197
|
+
<ChartTooltip content={<ChartTooltipContent />} />
|
|
198
|
+
<ChartLegend content={<ChartLegendContent />} />
|
|
199
|
+
{series.map((s: any, index: number) => {
|
|
200
|
+
const palette = getPalette();
|
|
201
|
+
const color = resolveColor(config[s.dataKey]?.color || palette[index % palette.length]);
|
|
202
|
+
return (
|
|
203
|
+
<Scatter
|
|
204
|
+
key={s.dataKey}
|
|
205
|
+
name={config[s.dataKey]?.label || s.dataKey}
|
|
206
|
+
data={data}
|
|
207
|
+
fill={color}
|
|
208
|
+
/>
|
|
209
|
+
);
|
|
210
|
+
})}
|
|
211
|
+
</ScatterChart>
|
|
212
|
+
</ChartContainer>
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
132
216
|
return (
|
|
133
217
|
<ChartContainer config={config} className={className}>
|
|
134
218
|
<ChartComponent data={data}>
|
package/src/ChartImpl.tsx
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
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
|
+
|
|
1
9
|
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from 'recharts';
|
|
2
10
|
|
|
3
11
|
export interface ChartImplProps {
|
|
@@ -0,0 +1,112 @@
|
|
|
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-[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';
|
|
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: 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-[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
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
|
|
2
|
+
import React, { useState, useEffect } from 'react';
|
|
3
|
+
import { useDataScope, useSchemaContext } from '@object-ui/react';
|
|
4
|
+
import { ChartRenderer } from './ChartRenderer';
|
|
5
|
+
import { ComponentRegistry } from '@object-ui/core';
|
|
6
|
+
|
|
7
|
+
export const ObjectChart = (props: any) => {
|
|
8
|
+
const { schema } = props;
|
|
9
|
+
const context = useSchemaContext();
|
|
10
|
+
const dataSource = props.dataSource || context.dataSource;
|
|
11
|
+
const boundData = useDataScope(schema.bind);
|
|
12
|
+
|
|
13
|
+
const [fetchedData, setFetchedData] = useState<any[]>([]);
|
|
14
|
+
const [loading, setLoading] = useState(false);
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
let isMounted = true;
|
|
18
|
+
const fetchData = async () => {
|
|
19
|
+
if (!dataSource || !schema.objectName) return;
|
|
20
|
+
if (isMounted) setLoading(true);
|
|
21
|
+
try {
|
|
22
|
+
// Apply filtering?
|
|
23
|
+
const results = await dataSource.find(schema.objectName, {
|
|
24
|
+
$filter: schema.filter
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
let data: any[] = [];
|
|
28
|
+
if (Array.isArray(results)) {
|
|
29
|
+
data = results;
|
|
30
|
+
} else if (results && typeof results === 'object') {
|
|
31
|
+
if (Array.isArray((results as any).value)) {
|
|
32
|
+
data = (results as any).value;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (isMounted) {
|
|
37
|
+
setFetchedData(data);
|
|
38
|
+
}
|
|
39
|
+
} catch (e) {
|
|
40
|
+
console.error('[ObjectChart] Fetch error:', e);
|
|
41
|
+
} finally {
|
|
42
|
+
if (isMounted) setLoading(false);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
if (schema.objectName && !boundData && !schema.data) {
|
|
47
|
+
fetchData();
|
|
48
|
+
}
|
|
49
|
+
return () => { isMounted = false; };
|
|
50
|
+
}, [schema.objectName, dataSource, boundData, schema.data, schema.filter]);
|
|
51
|
+
|
|
52
|
+
const finalData = boundData || schema.data || fetchedData || [];
|
|
53
|
+
|
|
54
|
+
// Merge data if not provided in schema
|
|
55
|
+
const finalSchema = {
|
|
56
|
+
...schema,
|
|
57
|
+
data: finalData
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
if (loading && finalData.length === 0) {
|
|
61
|
+
// Return skeleton or loading state?
|
|
62
|
+
// ChartRenderer has suspense/skeleton handling but needs to be triggered.
|
|
63
|
+
// We pass empty data but it might render empty chart.
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return <ChartRenderer {...props} schema={finalSchema} />;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Register it
|
|
70
|
+
ComponentRegistry.register('object-chart', ObjectChart, {
|
|
71
|
+
namespace: 'plugin-charts',
|
|
72
|
+
label: 'Object Chart',
|
|
73
|
+
category: 'view'
|
|
74
|
+
});
|