Skip to content

Commit eba8a27

Browse files
authored
fix: components' props types (#782)
* fix: fix components' props types fix #734, possible fix #741 * ci(size-limit): increase size
1 parent 74c169a commit eba8a27

12 files changed

+326
-214
lines changed

.clean-publish

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
2-
"packageManager": "yarn"
2+
"packageManager": "yarn",
3+
"fields": ["tsd"]
34
}

.github/workflows/checks.yml

+20
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,23 @@ jobs:
1717
uses: andresz1/size-limit-action@v1
1818
with:
1919
github_token: ${{ secrets.GITHUB_TOKEN }}
20+
typings:
21+
runs-on: ubuntu-latest
22+
name: Checking typings
23+
if: "!contains(github.event.head_commit.message, '[ci skip]')"
24+
steps:
25+
- name: Checkout the repository
26+
uses: actions/checkout@v2
27+
- name: Install Node.js
28+
uses: actions/setup-node@v2
29+
with:
30+
node-version: 12
31+
- name: Install dependencies
32+
uses: bahmutov/npm-install@v1
33+
with:
34+
install-command: yarn --frozen-lockfile --ignore-engines
35+
- name: Prebuild
36+
run: yarn build
37+
- name: Check typings
38+
if: success()
39+
run: yarn test:typings

.size-limit

+4-4
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
},
88
{
99
"path": "dist/index.js",
10-
"limit": "9.4 KB",
11-
"import": "ChartComponent"
10+
"limit": "9.5 KB",
11+
"import": "Chart"
1212
},
1313
{
1414
"path": "dist/index.modern.js",
@@ -18,7 +18,7 @@
1818
},
1919
{
2020
"path": "dist/index.modern.js",
21-
"limit": "9.4 KB",
22-
"import": "ChartComponent"
21+
"limit": "9.5 KB",
22+
"import": "Chart"
2323
}
2424
]

package.json

+7-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"description": "React components for Chart.js",
55
"main": "dist/index.js",
66
"module": "dist/index.modern.js",
7+
"types": "dist/index.d.ts",
78
"author": "Jeremy Ayerst",
89
"homepage": "https://github.com/reactchartjs/react-chartjs-2",
910
"license": "MIT",
@@ -31,7 +32,8 @@
3132
"test:unit": "jest -c jest.config.json",
3233
"test:build": "yarn build",
3334
"test:size": "size-limit",
34-
"test": "yarn test:lint && yarn test:unit && yarn test:build && yarn test:size",
35+
"test:typings": "tsd",
36+
"test": "yarn test:lint && yarn test:unit && yarn test:build",
3537
"format": "prettier --write src",
3638
"predeploy": "cd example && yarn && yarn build",
3739
"deploy": "gh-pages -d example/build",
@@ -96,9 +98,13 @@
9698
"simple-git-hooks": "^2.6.1",
9799
"size-limit": "^6.0.3",
98100
"standard-version": "^9.3.1",
101+
"tsd": "^0.18.0",
99102
"typescript": "^4.4.3",
100103
"webpack": "^5.58.2"
101104
},
105+
"tsd": {
106+
"directory": "./test"
107+
},
102108
"files": [
103109
"dist"
104110
]

src/chart.tsx

+41-32
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,43 @@ import React, {
66
useMemo,
77
forwardRef,
88
} from 'react';
9-
import Chart from 'chart.js/auto';
10-
import type { ChartData } from 'chart.js';
9+
import type { Ref, MouseEvent } from 'react';
10+
import ChartJS from 'chart.js/auto';
11+
import type { ChartData, ChartType, DefaultDataPoint } from 'chart.js';
1112
import merge from 'lodash/merge';
1213
import assign from 'lodash/assign';
1314
import find from 'lodash/find';
1415

15-
import { Props } from './types';
16+
import { Props, ChartJSOrUndefined, TypedChartComponent } from './types';
1617

17-
const ChartComponent = forwardRef<Chart | undefined, Props>((props, ref) => {
18-
const {
19-
id,
20-
className,
18+
function ChartComponent<
19+
TType extends ChartType = ChartType,
20+
TData = DefaultDataPoint<TType>,
21+
TLabel = unknown
22+
>(
23+
{
2124
height = 150,
2225
width = 300,
2326
redraw = false,
2427
type,
2528
data,
26-
options = {},
29+
options,
2730
plugins = [],
2831
getDatasetAtEvent,
2932
getElementAtEvent,
3033
getElementsAtEvent,
3134
fallbackContent,
32-
...rest
33-
} = props;
35+
onClick: onClickProp,
36+
...props
37+
}: Props<TType, TData, TLabel>,
38+
ref: Ref<ChartJS<TType, TData, TLabel>>
39+
) {
40+
type TypedChartJS = ChartJSOrUndefined<TType, TData, TLabel>;
41+
type TypedChartData = ChartData<TType, TData, TLabel>;
3442

3543
const canvas = useRef<HTMLCanvasElement>(null);
3644

37-
const computedData = useMemo<ChartData>(() => {
45+
const computedData = useMemo<TypedChartData>(() => {
3846
if (typeof data === 'function') {
3947
return canvas.current
4048
? data(canvas.current)
@@ -44,17 +52,15 @@ const ChartComponent = forwardRef<Chart | undefined, Props>((props, ref) => {
4452
} else return merge({}, data);
4553
}, [data, canvas.current]);
4654

47-
const [chart, setChart] = useState<Chart>();
55+
const [chart, setChart] = useState<TypedChartJS>();
4856

49-
useImperativeHandle<Chart | undefined, Chart | undefined>(ref, () => chart, [
50-
chart,
51-
]);
57+
useImperativeHandle<TypedChartJS, TypedChartJS>(ref, () => chart, [chart]);
5258

5359
const renderChart = () => {
5460
if (!canvas.current) return;
5561

5662
setChart(
57-
new Chart(canvas.current, {
63+
new ChartJS(canvas.current, {
5864
type,
5965
data: computedData,
6066
options,
@@ -63,38 +69,42 @@ const ChartComponent = forwardRef<Chart | undefined, Props>((props, ref) => {
6369
);
6470
};
6571

66-
const onClick = (e: React.MouseEvent<HTMLCanvasElement>) => {
72+
const onClick = (event: MouseEvent<HTMLCanvasElement>) => {
73+
if (onClickProp) {
74+
onClickProp(event);
75+
}
76+
6777
if (!chart) return;
6878

6979
getDatasetAtEvent &&
7080
getDatasetAtEvent(
7181
chart.getElementsAtEventForMode(
72-
e as unknown as Event,
82+
event.nativeEvent,
7383
'dataset',
7484
{ intersect: true },
7585
false
7686
),
77-
e
87+
event
7888
);
7989
getElementAtEvent &&
8090
getElementAtEvent(
8191
chart.getElementsAtEventForMode(
82-
e as unknown as Event,
92+
event.nativeEvent,
8393
'nearest',
8494
{ intersect: true },
8595
false
8696
),
87-
e
97+
event
8898
);
8999
getElementsAtEvent &&
90100
getElementsAtEvent(
91101
chart.getElementsAtEventForMode(
92-
e as unknown as Event,
102+
event.nativeEvent,
93103
'index',
94104
{ intersect: true },
95105
false
96106
),
97-
e
107+
event
98108
);
99109
};
100110

@@ -128,8 +138,10 @@ const ChartComponent = forwardRef<Chart | undefined, Props>((props, ref) => {
128138
if (!currentDataSet || !newDataSet.data) return { ...newDataSet };
129139

130140
if (!currentDataSet.data) {
141+
// @ts-expect-error Need to refactor
131142
currentDataSet.data = [];
132143
} else {
144+
// @ts-expect-error Need to refactor
133145
currentDataSet.data.length = newDataSet.data.length;
134146
}
135147

@@ -163,23 +175,20 @@ const ChartComponent = forwardRef<Chart | undefined, Props>((props, ref) => {
163175
} else {
164176
updateChart();
165177
}
166-
}, [props, computedData]);
178+
});
167179

168180
return (
169181
<canvas
170-
{...rest}
182+
ref={canvas}
183+
role='img'
171184
height={height}
172185
width={width}
173-
ref={canvas}
174-
id={id}
175-
className={className}
176186
onClick={onClick}
177-
data-testid='canvas'
178-
role='img'
187+
{...props}
179188
>
180189
{fallbackContent}
181190
</canvas>
182191
);
183-
});
192+
}
184193

185-
export default ChartComponent;
194+
export const Chart = forwardRef(ChartComponent) as TypedChartComponent;

src/index.tsx

+6-97
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,7 @@
1-
import React, { forwardRef } from 'react';
2-
import Chart from 'chart.js/auto';
3-
import { defaults } from 'chart.js';
1+
// @todo Remove these exports
2+
export { default as Chart } from 'chart.js/auto';
3+
export { defaults } from 'chart.js';
44

5-
import { Props } from './types';
6-
import ChartComponent from './chart';
7-
8-
export const Line = forwardRef<Chart | undefined, Omit<Props, 'type'>>(
9-
(props, ref) => (
10-
<ChartComponent
11-
{...props}
12-
type='line'
13-
ref={ref}
14-
options={props.options || {}}
15-
/>
16-
)
17-
);
18-
19-
export const Bar = forwardRef<Chart | undefined, Omit<Props, 'type'>>(
20-
(props, ref) => (
21-
<ChartComponent
22-
{...props}
23-
type='bar'
24-
ref={ref}
25-
options={props.options || {}}
26-
/>
27-
)
28-
);
29-
30-
export const Radar = forwardRef<Chart | undefined, Omit<Props, 'type'>>(
31-
(props, ref) => (
32-
<ChartComponent
33-
{...props}
34-
type='radar'
35-
ref={ref}
36-
options={props.options || {}}
37-
/>
38-
)
39-
);
40-
41-
export const Doughnut = forwardRef<Chart | undefined, Omit<Props, 'type'>>(
42-
(props, ref) => (
43-
<ChartComponent
44-
{...props}
45-
type='doughnut'
46-
ref={ref}
47-
options={props.options || {}}
48-
/>
49-
)
50-
);
51-
52-
export const PolarArea = forwardRef<Chart | undefined, Omit<Props, 'type'>>(
53-
(props, ref) => (
54-
<ChartComponent
55-
{...props}
56-
type='polarArea'
57-
ref={ref}
58-
options={props.options || {}}
59-
/>
60-
)
61-
);
62-
63-
export const Bubble = forwardRef<Chart | undefined, Omit<Props, 'type'>>(
64-
(props, ref) => (
65-
<ChartComponent
66-
{...props}
67-
type='bubble'
68-
ref={ref}
69-
options={props.options || {}}
70-
/>
71-
)
72-
);
73-
74-
export const Pie = forwardRef<Chart | undefined, Omit<Props, 'type'>>(
75-
(props, ref) => (
76-
<ChartComponent
77-
{...props}
78-
type='pie'
79-
ref={ref}
80-
options={props.options || {}}
81-
/>
82-
)
83-
);
84-
85-
export const Scatter = forwardRef<Chart | undefined, Omit<Props, 'type'>>(
86-
(props, ref) => (
87-
<ChartComponent
88-
{...props}
89-
type='scatter'
90-
ref={ref}
91-
options={props.options || {}}
92-
/>
93-
)
94-
);
95-
96-
export { Chart, defaults };
97-
98-
export default ChartComponent;
5+
// @todo Make named export instead of default
6+
export { Chart as default } from './chart';
7+
export * from './typedCharts';

src/typedCharts.tsx

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React, { forwardRef } from 'react';
2+
import { ChartType } from 'chart.js';
3+
4+
import { Props, ChartJSOrUndefined, TypedChartComponent } from './types';
5+
import { Chart } from './chart';
6+
7+
function createTypedChart<T extends ChartType>(type: T) {
8+
return forwardRef<ChartJSOrUndefined<T>, Omit<Props<T>, 'type'>>(
9+
(props, ref) => <Chart {...props} ref={ref} type={type} />
10+
) as TypedChartComponent<T, true>;
11+
}
12+
13+
export const Line = createTypedChart('line');
14+
15+
export const Bar = createTypedChart('bar');
16+
17+
export const Radar = createTypedChart('radar');
18+
19+
export const Doughnut = createTypedChart('doughnut');
20+
21+
export const PolarArea = createTypedChart('polarArea');
22+
23+
export const Bubble = createTypedChart('bubble');
24+
25+
export const Pie = createTypedChart('pie');
26+
27+
export const Scatter = createTypedChart('scatter');

0 commit comments

Comments
 (0)