@amad3v/solid-chart 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 amad3v
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # solid-chart
2
+
3
+ ---
4
+
5
+ A lightweight, reactive [SolidJS](https://www.solidjs.com/) wrapper for [Chart.js 4.5+](https://www.chartjs.org/).
6
+
7
+ This library provides a thin, high-performance layer over **Chart.js**, ensuring that chart instances stay in sync with Solid's fine-grained reactivity without the "Wrapper Tax" of older implementations.
8
+ ---
9
+ > 💡 **Important**
10
+
11
+ > This project is based on the original work by [s0ftik3/solid-chartjs](https://github.com/s0ftik3/solid-chartjs). It has been modernised to fix race conditions related to DOM rendering and updated for compatibility with the latest **Chart.js**.
12
+
13
+ > ⚠️ **Warning**
14
+
15
+ > This library is **not thoroughly tested** in production environments. Please use it with caution and report any issues.
16
+
17
+ ---
18
+ ## Features
19
+ - **Zero-Signal Architecture**: Uses synchronous `onMount` ref handling to prevent `getComputedStyle` errors.
20
+ - **Prop Protection**: Automatically unwraps Solid Stores before passing them to Chart.js to prevent Proxy-related crashes.
21
+ - **Typed Components**: Includes pre-defined components for `Line`, `Bar`, `Doughnut`, ...
22
+ - **Registration Utilities**: Built-in helpers to register only what you need, keeping your bundle small.
23
+ - **ESM-First**: Optimised for modern bundlers like Vite and Rspack.
24
+
25
+ ## Installation
26
+ ```bash
27
+ pnpm add @amad3v/solid-chart chart.js
28
+ # or
29
+ npm install @amad3v/solid-chart chart.js
30
+ ```
31
+
32
+ ## Setup (Registration)
33
+ To keep the bundle lean, `solid-chart` does not register Chart.js components globally by default. We provide utilities to register exactly what you need in your entry point (e.g., `index.tsx`):
34
+ ```tsx
35
+ import { registerCoreExtra, registerLine, registerBar } from 'solid-chart';
36
+
37
+ // Registers Tooltip, Legend, Colors, Title, and SubTitle
38
+ registerCoreExtra();
39
+
40
+ // Registers specific chart requirements
41
+ registerLine();
42
+ registerBar();
43
+ ```
44
+ If you have custom requirements or 3rd party plugins, use the exposed `registerComponent` helper:
45
+ ```tsx
46
+ import { registerComponent } from 'solid-chart';
47
+ import MyPlugin from 'chartjs-my-plugin';
48
+
49
+ registerComponent(MyPlugin);
50
+ ```
51
+
52
+ ## Usage
53
+ Using the library is straightforward. You can use the generic `DefaultChart` or any of the typed exports.
54
+
55
+ ```tsx
56
+ import { Line } from 'solid-chart';
57
+ import { createStore } from 'solid-js/store';
58
+
59
+ const App = () => {
60
+ const [data, setData] = createStore({
61
+ labels: ['January', 'February', 'March', 'April'],
62
+ datasets: [
63
+ {
64
+ label: 'Sales',
65
+ data: [12, 19, 3, 5],
66
+ backgroundColor: 'rgba(75, 192, 192, 0.2)',
67
+ borderColor: 'rgba(75, 192, 192, 1)',
68
+ borderWidth: 2,
69
+ tension: 0.4, // Smooth lines
70
+ },
71
+ ],
72
+ });
73
+
74
+ return (
75
+ <div style={{ width: '600px', height: '400px' }}>
76
+ <Line
77
+ data={data}
78
+ options={{
79
+ responsive: true,
80
+ maintainAspectRatio: false
81
+ }}
82
+ />
83
+ </div>
84
+ );
85
+ };
86
+ ```
87
+
88
+ ## API
89
+ ### Components
90
+ All components accept standard Chart.js configuration objects as props.
91
+
92
+ `DefaultChart`: The base component (requires a `type` prop).
93
+
94
+ `Line`, `Bar`, `Radar`, `Doughnut`, `PolarArea`, `Bubble`, `Pie`, `Scatter`: Type-safe shortcuts.
95
+
96
+ ## Registration Utilities
97
+
98
+ | Function | Description |
99
+ | --------------------------------- | ------------------------------------------------------- |
100
+ | registerComponent | Raw access to Chart.register(...args). |
101
+ | registerCore | Registers Tooltip and Legend. |
102
+ | registerCoreExtra | Registers Title, Tooltip, Legend, Colors, and SubTitle. |
103
+ | registerLine | Registers requirements for Line charts. |
104
+ | registerBar | Registers requirements for Bar charts. |
105
+ | registerPie / registerDoughnut | Registers requirements for Arc-based charts. |
106
+ | registerRadar / registerPolarArea | Registers requirements for Radial charts. |
107
+
108
+
109
+ ### Props
110
+ | Prop | Type | Description |
111
+ | ------- | ------------ | ------------------------------------------------- |
112
+ | data | ChartData | The reactive data object (Solid Store supported). |
113
+ | options | ChartOptions | Chart.js configuration options. |
114
+ | width | number | Default is 512. |
115
+ | height | number | Default is 512. |
116
+ | ref | Ref | Access to the underlying HTMLCanvasElement. |
117
+
118
+ ## Contributing
119
+
120
+ Contributions are welcome! Please fork the repository and submit a pull request for any improvements, bug fixes, or new features. Be sure to follow best practices and ensure all tests pass before submitting.
121
+
122
+ ## License
123
+
124
+ This project is licensed under the MIT License - see the [LICENSE](./LICENSE) file for details.
125
+
126
+ ## Acknowledgements
127
+
128
+ This library is a modernised and refactored version of [solid-chartjs](https://github.com/s0ftik3/solid-chartjs), tailored to support modern SolidJS and Chart.js 4.5+ architectures. All credit for the original [solid-chartjs](https://github.com/s0ftik3/solid-chartjs) library and its initial implementation goes to the original [authors](https://github.com/s0ftik3).
129
+
130
+ ## Disclaimer
131
+
132
+ Please note: This library is by no means a professional or production-ready solution. It was developed out of necessity for personal projects, and it may not meet the quality or stability standards required for a fully-fledged production environment. It is intended for personal use and experimentation, and contributions are highly encouraged to improve its functionality and stability.
@@ -0,0 +1,140 @@
1
+ import { ChartComponent } from 'chart.js';
2
+ import { ChartData } from 'chart.js';
3
+ import { ChartOptions } from 'chart.js';
4
+ import { ChartTypeRegistry } from 'chart.js';
5
+ import { Component } from 'solid-js';
6
+ import { JSXElement } from 'solid-js';
7
+ import { Plugin as Plugin_2 } from 'chart.js';
8
+ import { Ref } from '@solid-primitives/refs';
9
+
10
+ export declare const Bar: TypedChart;
11
+
12
+ export declare const Bubble: TypedChart;
13
+
14
+ /**
15
+ * Chart props
16
+ */
17
+ export declare interface ChartProps {
18
+ /**
19
+ * Chart.js chart type
20
+ */
21
+ type: keyof ChartTypeRegistry;
22
+ /**
23
+ * The data object that is passed into the Chart.js chart
24
+ * @see https://www.chartjs.org/docs/latest/getting-started/
25
+ */
26
+ data?: ChartData;
27
+ /**
28
+ * The options object that is passed into the Chart.js chart
29
+ * @see https://www.chartjs.org/docs/latest/general/options.html
30
+ * @default {}
31
+ */
32
+ options?: ChartOptions;
33
+ /**
34
+ * The plugins array that is passed into the Chart.js chart
35
+ * @see https://www.chartjs.org/docs/latest/developers/plugins.html
36
+ * @default []
37
+ */
38
+ plugins?: Plugin_2[];
39
+ /**
40
+ * The width of the canvas element
41
+ * @default 512
42
+ */
43
+ width?: number | undefined;
44
+ /**
45
+ * The height of the canvas element
46
+ * @default 512
47
+ */
48
+ height?: number | undefined;
49
+ /**
50
+ * The fallback element to render when the canvas cannot be rendered.
51
+ * @default null
52
+ */
53
+ fallback?: JSXElement | null;
54
+ /**
55
+ * Support for any other Chart.js options
56
+ * @default {}
57
+ */
58
+ [key: string]: unknown;
59
+ /**
60
+ * A ref to the Chart.js instance
61
+ * @default null
62
+ */
63
+ ref?: Ref<HTMLCanvasElement | null>;
64
+ }
65
+
66
+ export declare const DefaultChart: Component<ChartProps>;
67
+
68
+ export declare const Doughnut: TypedChart;
69
+
70
+ export declare const Line: TypedChart;
71
+
72
+ export declare const Pie: TypedChart;
73
+
74
+ export declare const PolarArea: TypedChart;
75
+
76
+ export declare const Radar: TypedChart;
77
+
78
+ /**
79
+ * Essential for Bar chart.
80
+ */
81
+ export declare const registerBar: () => void;
82
+
83
+ /**
84
+ * Essential for Bubble chart.
85
+ */
86
+ export declare const registerBubble: () => void;
87
+
88
+ /**
89
+ * Global registration helper for custom components and plugins.
90
+ * Use this to register 3rd party plugins or custom scales.
91
+ */
92
+ export declare const registerComponent: (...args: ChartComponent[]) => void;
93
+
94
+ /**
95
+ * Essential plugins most charts need.
96
+ */
97
+ export declare const registerCore: () => void;
98
+
99
+ /**
100
+ * Extra standard plugins for titles and automatic color palettes.
101
+ */
102
+ export declare const registerCoreExtra: () => void;
103
+
104
+ /**
105
+ * Essential for Doughnut chart.
106
+ */
107
+ export declare const registerDoughnut: () => void;
108
+
109
+ /**
110
+ * Essential for Line chart.
111
+ */
112
+ export declare const registerLine: () => void;
113
+
114
+ /**
115
+ * Essential for Pie chart.
116
+ */
117
+ export declare const registerPie: () => void;
118
+
119
+ /**
120
+ * Essential for PolarArea chart.
121
+ */
122
+ export declare const registerPolarArea: () => void;
123
+
124
+ /**
125
+ * Essential for Radar chart.
126
+ */
127
+ export declare const registerRadar: () => void;
128
+
129
+ /**
130
+ * Essential for Scatter chart.
131
+ */
132
+ export declare const registerScatter: () => void;
133
+
134
+ export declare const Scatter: TypedChart;
135
+
136
+ declare type TypedChart = Component<TypedChartProps>;
137
+
138
+ export declare type TypedChartProps = Omit<ChartProps, 'type'>;
139
+
140
+ export { }
@@ -0,0 +1,103 @@
1
+ import { template as R, use as x, insert as D, effect as O, setAttribute as v, createComponent as s, mergeProps as i } from "solid-js/web";
2
+ import { mergeRefs as P } from "@solid-primitives/refs";
3
+ import { Chart as w, PointElement as d, LinearScale as f, BubbleController as T, Legend as S, Tooltip as B, SubTitle as _, Colors as $, Title as k, ArcElement as y, DoughnutController as z, LineElement as L, CategoryScale as A, LineController as M, PieController as j, RadialLinearScale as E, PolarAreaController as q, RadarController as F, ScatterController as G, BarElement as H, BarController as I } from "chart.js";
4
+ import { mergeProps as J, onMount as K, createEffect as p, on as u, onCleanup as N } from "solid-js";
5
+ import { unwrap as g } from "solid-js/store";
6
+ var Q = /* @__PURE__ */ R("<canvas>");
7
+ const l = (e) => {
8
+ let h, o;
9
+ const t = J({
10
+ width: 512,
11
+ height: 512,
12
+ type: "line",
13
+ data: {},
14
+ options: {
15
+ responsive: !0
16
+ },
17
+ plugins: []
18
+ }, e), b = () => {
19
+ if (!h) return;
20
+ const n = h.getContext("2d"), r = {
21
+ ...g(t.options)
22
+ };
23
+ if (t.type !== "radar" && r.scales?.r) {
24
+ const {
25
+ r: C,
26
+ ...c
27
+ } = r.scales;
28
+ r.scales = c;
29
+ }
30
+ o = new w(n, {
31
+ type: t.type,
32
+ data: g(t.data),
33
+ // unwrap stores before passing to external libs
34
+ options: r,
35
+ plugins: t.plugins
36
+ });
37
+ };
38
+ return K(() => b()), p(u(() => t.data, (n) => {
39
+ o && (o.data = g(n), o.update("none"));
40
+ }, {
41
+ defer: !0
42
+ })), p(u(() => t.options, (n) => {
43
+ o && (o.options = g(n), o.update());
44
+ }, {
45
+ defer: !0
46
+ })), p(u([() => t.width, () => t.height], () => o?.resize(t.width, t.height), {
47
+ defer: !0
48
+ })), p(u(() => t.type, () => {
49
+ o && (o.destroy(), b());
50
+ }, {
51
+ defer: !0
52
+ })), N(() => {
53
+ o?.destroy(), P(e.ref, null);
54
+ }), (() => {
55
+ var n = Q(), m = P(e.ref, (r) => h = r);
56
+ return typeof m == "function" && x(m, n), D(n, () => t.fallback), O((r) => {
57
+ var C = t.height, c = t.width;
58
+ return C !== r.e && v(n, "height", r.e = C), c !== r.t && v(n, "width", r.t = c), r;
59
+ }, {
60
+ e: void 0,
61
+ t: void 0
62
+ }), n;
63
+ })();
64
+ }, a = (...e) => w.register(...e), Z = () => a(B, S), ee = () => a(k, B, S, $, _), te = () => a(M, A, f, d, L), re = () => a(I, A, f, H), oe = () => a(F, E, d, L), ne = () => a(z, y), ae = () => a(j, y), se = () => a(q, E, y), ie = () => a(T, f, d), le = () => a(G, f, d), ce = (e) => s(l, i({
65
+ type: "line"
66
+ }, e)), pe = (e) => s(l, i({
67
+ type: "bar"
68
+ }, e)), ue = (e) => s(l, i({
69
+ type: "radar"
70
+ }, e)), ge = (e) => s(l, i({
71
+ type: "doughnut"
72
+ }, e)), de = (e) => s(l, i({
73
+ type: "polarArea"
74
+ }, e)), fe = (e) => s(l, i({
75
+ type: "bubble"
76
+ }, e)), he = (e) => s(l, i({
77
+ type: "pie"
78
+ }, e)), me = (e) => s(l, i({
79
+ type: "scatter"
80
+ }, e));
81
+ export {
82
+ pe as Bar,
83
+ fe as Bubble,
84
+ l as DefaultChart,
85
+ ge as Doughnut,
86
+ ce as Line,
87
+ he as Pie,
88
+ de as PolarArea,
89
+ ue as Radar,
90
+ me as Scatter,
91
+ re as registerBar,
92
+ ie as registerBubble,
93
+ a as registerComponent,
94
+ Z as registerCore,
95
+ ee as registerCoreExtra,
96
+ ne as registerDoughnut,
97
+ te as registerLine,
98
+ ae as registerPie,
99
+ se as registerPolarArea,
100
+ oe as registerRadar,
101
+ le as registerScatter
102
+ };
103
+ //# sourceMappingURL=solid-chart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solid-chart.js","sources":["../src/chart.tsx","../src/registry.ts","../src/typedCharts.tsx"],"sourcesContent":["import { mergeRefs } from '@solid-primitives/refs';\nimport { Chart, ChartData, ChartItem, ChartOptions, Plugin } from 'chart.js';\nimport { Component, createEffect, mergeProps, on, onCleanup, onMount } from 'solid-js';\nimport { unwrap } from 'solid-js/store';\n\nimport { ChartProps } from './types';\n\nexport const DefaultChart: Component<ChartProps> = (props) => {\n let canvasRef: HTMLCanvasElement | null;\n let chart: Chart | undefined;\n\n const merged = mergeProps(\n {\n width: 512,\n height: 512,\n type: 'line' as const,\n data: {} as ChartData,\n options: { responsive: true } as ChartOptions,\n plugins: [] as Plugin[],\n },\n props,\n );\n\n const init = () => {\n if (!canvasRef) return;\n const ctx = canvasRef.getContext('2d') as ChartItem;\n\n // Clean unwrap and a safe copy of options\n const rawOptions = unwrap(merged.options);\n const configOptions = { ...rawOptions };\n\n // Handle the radar scale issue without mutating props\n if (merged.type !== 'radar' && configOptions.scales?.r) {\n const { r: _, ...otherScales } = configOptions.scales;\n configOptions.scales = otherScales;\n }\n\n chart = new Chart(ctx, {\n type: merged.type,\n data: unwrap(merged.data), // unwrap stores before passing to external libs\n options: configOptions,\n plugins: merged.plugins,\n });\n };\n\n onMount(() => init());\n\n createEffect(\n on(\n () => merged.data,\n (newData) => {\n if (chart) {\n chart.data = unwrap(newData);\n chart.update('none'); // Use 'none' for better performance on data updates\n }\n },\n { defer: true },\n ),\n );\n\n createEffect(\n on(\n () => merged.options,\n (newOptions) => {\n if (chart) {\n chart.options = unwrap(newOptions);\n chart.update();\n }\n },\n { defer: true },\n ),\n );\n\n createEffect(\n on(\n [() => merged.width, () => merged.height],\n () => chart?.resize(merged.width, merged.height),\n { defer: true },\n ),\n );\n\n createEffect(\n on(\n () => merged.type,\n () => {\n if (chart) {\n chart.destroy();\n init();\n }\n },\n { defer: true },\n ),\n );\n\n onCleanup(() => {\n chart?.destroy();\n // Standard cleanup for the ref\n mergeRefs(props.ref, null);\n });\n\n return (\n <canvas\n ref={mergeRefs(props.ref, (el) => (canvasRef = el))}\n height={merged.height}\n width={merged.width}\n >\n {merged.fallback}\n </canvas>\n );\n};\n","import {\n ArcElement,\n BarController,\n BarElement,\n BubbleController,\n CategoryScale,\n Chart,\n ChartComponent,\n Colors,\n DoughnutController,\n Legend,\n LinearScale,\n LineController,\n LineElement,\n PieController,\n PointElement,\n PolarAreaController,\n RadarController,\n RadialLinearScale,\n ScatterController,\n SubTitle,\n Title,\n Tooltip,\n} from 'chart.js';\n\n/**\n * Global registration helper for custom components and plugins.\n * Use this to register 3rd party plugins or custom scales.\n */\nexport const registerComponent = (...args: ChartComponent[]) => Chart.register(...args);\n\n/**\n * Essential plugins most charts need.\n */\nexport const registerCore = () => registerComponent(Tooltip, Legend);\n\n/**\n * Extra standard plugins for titles and automatic color palettes.\n */\nexport const registerCoreExtra = () => registerComponent(Title, Tooltip, Legend, Colors, SubTitle);\n\n/**\n * Essential for Line chart.\n */\nexport const registerLine = () =>\n registerComponent(LineController, CategoryScale, LinearScale, PointElement, LineElement);\n\n/**\n * Essential for Bar chart.\n */\nexport const registerBar = () =>\n registerComponent(BarController, CategoryScale, LinearScale, BarElement);\n\n/**\n * Essential for Radar chart.\n */\nexport const registerRadar = () =>\n registerComponent(RadarController, RadialLinearScale, PointElement, LineElement);\n\n/**\n * Essential for Doughnut chart.\n */\nexport const registerDoughnut = () => registerComponent(DoughnutController, ArcElement);\n\n/**\n * Essential for Pie chart.\n */\nexport const registerPie = () => registerComponent(PieController, ArcElement);\n\n/**\n * Essential for PolarArea chart.\n */\nexport const registerPolarArea = () =>\n registerComponent(PolarAreaController, RadialLinearScale, ArcElement);\n\n/**\n * Essential for Bubble chart.\n */\nexport const registerBubble = () => registerComponent(BubbleController, LinearScale, PointElement);\n\n/**\n * Essential for Scatter chart.\n */\nexport const registerScatter = () =>\n registerComponent(ScatterController, LinearScale, PointElement);\n","import { Component } from 'solid-js';\n\nimport { DefaultChart } from './chart';\nimport type { ChartProps } from './types';\n\n// Omit 'type' from props since these components define the type themselves\nexport type TypedChartProps = Omit<ChartProps, 'type'>;\ntype TypedChart = Component<TypedChartProps>;\n\nexport const Line: TypedChart = (props) => <DefaultChart type=\"line\" {...props} />;\nexport const Bar: TypedChart = (props) => <DefaultChart type=\"bar\" {...props} />;\nexport const Radar: TypedChart = (props) => <DefaultChart type=\"radar\" {...props} />;\nexport const Doughnut: TypedChart = (props) => <DefaultChart type=\"doughnut\" {...props} />;\nexport const PolarArea: TypedChart = (props) => <DefaultChart type=\"polarArea\" {...props} />;\nexport const Bubble: TypedChart = (props) => <DefaultChart type=\"bubble\" {...props} />;\nexport const Pie: TypedChart = (props) => <DefaultChart type=\"pie\" {...props} />;\nexport const Scatter: TypedChart = (props) => <DefaultChart type=\"scatter\" {...props} />;\n"],"names":["DefaultChart","props","canvasRef","chart","merged","mergeProps","width","height","type","data","options","responsive","plugins","init","ctx","getContext","configOptions","unwrap","rawOptions","scales","r","_","otherScales","Chart","onMount","createEffect","on","newData","update","defer","newOptions","resize","destroy","onCleanup","mergeRefs","ref","_el$","_tmpl$","_ref$","el","_$use","_$insert","fallback","_$effect","_p$","_v$","_v$2","e","_$setAttribute","t","undefined","registerComponent","args","registerCore","Tooltip","Legend","registerCoreExtra","Title","Colors","SubTitle","registerLine","LineController","CategoryScale","LinearScale","PointElement","LineElement","registerBar","BarController","BarElement","registerRadar","RadarController","RadialLinearScale","registerDoughnut","DoughnutController","ArcElement","registerPie","PieController","registerPolarArea","PolarAreaController","registerBubble","BubbleController","registerScatter","ScatterController","Line","_$createComponent","_$mergeProps","Bar","Radar","Doughnut","PolarArea","Bubble","Pie","Scatter"],"mappings":";;;;;;AAOO,MAAMA,IAAuCC,CAAAA,MAAU;AAC5D,MAAIC,GACAC;AAEJ,QAAMC,IAASC,EACb;AAAA,IACEC,OAAO;AAAA,IACPC,QAAQ;AAAA,IACRC,MAAM;AAAA,IACNC,MAAM,CAAA;AAAA,IACNC,SAAS;AAAA,MAAEC,YAAY;AAAA,IAAA;AAAA,IACvBC,SAAS,CAAA;AAAA,EAAA,GAEXX,CACF,GAEMY,IAAOA,MAAM;AACjB,QAAI,CAACX,EAAW;AAChB,UAAMY,IAAMZ,EAAUa,WAAW,IAAI,GAI/BC,IAAgB;AAAA,MAAE,GADLC,EAAOb,EAAOM,OAAO;AAAA,IACbQ;AAG3B,QAAId,EAAOI,SAAS,WAAWQ,EAAcG,QAAQC,GAAG;AACtD,YAAM;AAAA,QAAEA,GAAGC;AAAAA,QAAG,GAAGC;AAAAA,MAAAA,IAAgBN,EAAcG;AAC/CH,MAAAA,EAAcG,SAASG;AAAAA,IACzB;AAEAnB,IAAAA,IAAQ,IAAIoB,EAAMT,GAAK;AAAA,MACrBN,MAAMJ,EAAOI;AAAAA,MACbC,MAAMQ,EAAOb,EAAOK,IAAI;AAAA;AAAA,MACxBC,SAASM;AAAAA,MACTJ,SAASR,EAAOQ;AAAAA,IAAAA,CACjB;AAAA,EACH;AAEAY,SAAAA,EAAQ,MAAMX,GAAM,GAEpBY,EACEC,EACE,MAAMtB,EAAOK,MACZkB,CAAAA,MAAY;AACX,IAAIxB,MACFA,EAAMM,OAAOQ,EAAOU,CAAO,GAC3BxB,EAAMyB,OAAO,MAAM;AAAA,EAEvB,GACA;AAAA,IAAEC,OAAO;AAAA,EAAA,CACX,CACF,GAEAJ,EACEC,EACE,MAAMtB,EAAOM,SACZoB,CAAAA,MAAe;AACd,IAAI3B,MACFA,EAAMO,UAAUO,EAAOa,CAAU,GACjC3B,EAAMyB,OAAAA;AAAAA,EAEV,GACA;AAAA,IAAEC,OAAO;AAAA,EAAA,CACX,CACF,GAEAJ,EACEC,EACE,CAAC,MAAMtB,EAAOE,OAAO,MAAMF,EAAOG,MAAM,GACxC,MAAMJ,GAAO4B,OAAO3B,EAAOE,OAAOF,EAAOG,MAAM,GAC/C;AAAA,IAAEsB,OAAO;AAAA,EAAA,CACX,CACF,GAEAJ,EACEC,EACE,MAAMtB,EAAOI,MACb,MAAM;AACJ,IAAIL,MACFA,EAAM6B,QAAAA,GACNnB,EAAAA;AAAAA,EAEJ,GACA;AAAA,IAAEgB,OAAO;AAAA,EAAA,CACX,CACF,GAEAI,EAAU,MAAM;AACd9B,IAAAA,GAAO6B,QAAAA,GAEPE,EAAUjC,EAAMkC,KAAK,IAAI;AAAA,EAC3B,CAAC,IAED,MAAA;AAAA,QAAAC,IAAAC,EAAAA,GAAAC,IAESJ,EAAUjC,EAAMkC,KAAMI,CAAAA,MAAQrC,IAAYqC,CAAG;AAAC,kBAAAD,KAAA,cAAAE,EAAAF,GAAAF,CAAA,GAAAK,EAAAL,GAAA,MAIlDhC,EAAOsC,QAAQ,GAAAC,EAAAC,CAAAA,MAAA;AAAA,UAAAC,IAHRzC,EAAOG,QAAMuC,IACd1C,EAAOE;AAAKuC,aAAAA,MAAAD,EAAAG,KAAAC,EAAAZ,GAAA,UAAAQ,EAAAG,IAAAF,CAAA,GAAAC,MAAAF,EAAAK,KAAAD,EAAAZ,GAAA,SAAAQ,EAAAK,IAAAH,CAAA,GAAAF;AAAAA,IAAA,GAAA;AAAA,MAAAG,GAAAG;AAAAA,MAAAD,GAAAC;AAAAA,IAAAA,CAAA,GAAAd;AAAAA,EAAA,GAAA;AAKzB,GChFae,IAAoB,IAAIC,MAA2B7B,EAAM,SAAS,GAAG6B,CAAI,GAKzEC,IAAe,MAAMF,EAAkBG,GAASC,CAAM,GAKtDC,KAAoB,MAAML,EAAkBM,GAAOH,GAASC,GAAQG,GAAQC,CAAQ,GAKpFC,KAAe,MAC1BT,EAAkBU,GAAgBC,GAAeC,GAAaC,GAAcC,CAAW,GAK5EC,KAAc,MACzBf,EAAkBgB,GAAeL,GAAeC,GAAaK,CAAU,GAK5DC,KAAgB,MAC3BlB,EAAkBmB,GAAiBC,GAAmBP,GAAcC,CAAW,GAKpEO,KAAmB,MAAMrB,EAAkBsB,GAAoBC,CAAU,GAKzEC,KAAc,MAAMxB,EAAkByB,GAAeF,CAAU,GAK/DG,KAAoB,MAC/B1B,EAAkB2B,GAAqBP,GAAmBG,CAAU,GAKzDK,KAAiB,MAAM5B,EAAkB6B,GAAkBjB,GAAaC,CAAY,GAKpFiB,KAAkB,MAC7B9B,EAAkB+B,GAAmBnB,GAAaC,CAAY,GC3EnDmB,KAAoBlF,CAAAA,MAAKmF,EAAMpF,GAAYqF,EAAA;AAAA,EAAC7E,MAAI;AAAA,GAAYP,CAAK,CAAA,GACjEqF,KAAmBrF,CAAAA,MAAKmF,EAAMpF,GAAYqF,EAAA;AAAA,EAAC7E,MAAI;AAAA,GAAWP,CAAK,CAAA,GAC/DsF,KAAqBtF,CAAAA,MAAKmF,EAAMpF,GAAYqF,EAAA;AAAA,EAAC7E,MAAI;AAAA,GAAaP,CAAK,CAAA,GACnEuF,KAAwBvF,CAAAA,MAAKmF,EAAMpF,GAAYqF,EAAA;AAAA,EAAC7E,MAAI;AAAA,GAAgBP,CAAK,CAAA,GACzEwF,KAAyBxF,CAAAA,MAAKmF,EAAMpF,GAAYqF,EAAA;AAAA,EAAC7E,MAAI;AAAA,GAAiBP,CAAK,CAAA,GAC3EyF,KAAsBzF,CAAAA,MAAKmF,EAAMpF,GAAYqF,EAAA;AAAA,EAAC7E,MAAI;AAAA,GAAcP,CAAK,CAAA,GACrE0F,KAAmB1F,CAAAA,MAAKmF,EAAMpF,GAAYqF,EAAA;AAAA,EAAC7E,MAAI;AAAA,GAAWP,CAAK,CAAA,GAC/D2F,KAAuB3F,CAAAA,MAAKmF,EAAMpF,GAAYqF,EAAA;AAAA,EAAC7E,MAAI;AAAA,GAAeP,CAAK,CAAA;"}
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "@amad3v/solid-chart",
3
+ "version": "1.0.0",
4
+ "author": {
5
+ "name": "Mohamed JOUINI",
6
+ "email": "amad3v@gmail.com",
7
+ "url": "https://github.com/amad3v/"
8
+ },
9
+ "homepage": "https://github.com/amad3v/solid-chart",
10
+ "repository": {
11
+ "type": "github",
12
+ "url": "https://github.com/amad3v/solid-chart"
13
+ },
14
+ "bugs": {
15
+ "url": "https://github.com/amad3v/solid-chart/issues"
16
+ },
17
+ "description": "Chart.js wrapper for SolidJS.",
18
+ "license": "MIT",
19
+ "private": false,
20
+ "sideEffects": false,
21
+ "type": "module",
22
+ "files": [
23
+ "dist",
24
+ "src"
25
+ ],
26
+ "main": "./dist/solid-chart.js",
27
+ "module": "./dist/solid-chart.js",
28
+ "types": "./dist/solid-chart.d.ts",
29
+ "solid": "./src/index.ts",
30
+ "exports": {
31
+ ".": {
32
+ "types": "./dist/solid-chart.d.ts",
33
+ "solid": "./src/index.ts",
34
+ "import": "./dist/solid-chart.js"
35
+ }
36
+ },
37
+ "devDependencies": {
38
+ "@eslint/js": "^9.39.2",
39
+ "@types/node": "^25.0.3",
40
+ "@typescript-eslint/eslint-plugin": "^8.52.0",
41
+ "@typescript-eslint/parser": "^8.52.0",
42
+ "eslint": "^9.39.2",
43
+ "eslint-import-resolver-typescript": "^4.4.4",
44
+ "eslint-plugin-simple-import-sort": "^12.1.1",
45
+ "eslint-plugin-solid": "^0.14.5",
46
+ "globals": "^17.0.0",
47
+ "pathe": "^2.0.3",
48
+ "prettier": "^3.7.4",
49
+ "pretty-quick": "^4.2.2",
50
+ "rimraf": "^6.1.2",
51
+ "solid-js": "^1.9.10",
52
+ "tslib": "^2.8.1",
53
+ "typescript": "^5.9.3",
54
+ "typescript-eslint": "^8.52.0",
55
+ "vite": "^7.3.1",
56
+ "vite-plugin-dts": "^4.5.4",
57
+ "vite-plugin-eslint": "^1.8.1",
58
+ "vite-plugin-solid": "^2.11.10"
59
+ },
60
+ "peerDependencies": {
61
+ "chart.js": "^4.5.1",
62
+ "solid-js": "^1.9.10"
63
+ },
64
+ "keywords": [
65
+ "solidjs",
66
+ "chart.js"
67
+ ],
68
+ "dependencies": {
69
+ "@solid-primitives/refs": "^1.1.2"
70
+ },
71
+ "scripts": {
72
+ "dev": "vite",
73
+ "build": "rimraf ./dist && vite build",
74
+ "lint": "eslint ./src -c eslint.config.js --fix",
75
+ "fmt": "prettier --write \"**/*.{mjs,cjs,js,jsx,ts,tsx,json}\"",
76
+ "lint:fmt": "pnpm fmt && pnpm lint"
77
+ }
78
+ }
package/src/chart.tsx ADDED
@@ -0,0 +1,110 @@
1
+ import { mergeRefs } from '@solid-primitives/refs';
2
+ import { Chart, ChartData, ChartItem, ChartOptions, Plugin } from 'chart.js';
3
+ import { Component, createEffect, mergeProps, on, onCleanup, onMount } from 'solid-js';
4
+ import { unwrap } from 'solid-js/store';
5
+
6
+ import { ChartProps } from './types';
7
+
8
+ export const DefaultChart: Component<ChartProps> = (props) => {
9
+ let canvasRef: HTMLCanvasElement | null;
10
+ let chart: Chart | undefined;
11
+
12
+ const merged = mergeProps(
13
+ {
14
+ width: 512,
15
+ height: 512,
16
+ type: 'line' as const,
17
+ data: {} as ChartData,
18
+ options: { responsive: true } as ChartOptions,
19
+ plugins: [] as Plugin[],
20
+ },
21
+ props,
22
+ );
23
+
24
+ const init = () => {
25
+ if (!canvasRef) return;
26
+ const ctx = canvasRef.getContext('2d') as ChartItem;
27
+
28
+ // Clean unwrap and a safe copy of options
29
+ const rawOptions = unwrap(merged.options);
30
+ const configOptions = { ...rawOptions };
31
+
32
+ // Handle the radar scale issue without mutating props
33
+ if (merged.type !== 'radar' && configOptions.scales?.r) {
34
+ const { r: _, ...otherScales } = configOptions.scales;
35
+ configOptions.scales = otherScales;
36
+ }
37
+
38
+ chart = new Chart(ctx, {
39
+ type: merged.type,
40
+ data: unwrap(merged.data), // unwrap stores before passing to external libs
41
+ options: configOptions,
42
+ plugins: merged.plugins,
43
+ });
44
+ };
45
+
46
+ onMount(() => init());
47
+
48
+ createEffect(
49
+ on(
50
+ () => merged.data,
51
+ (newData) => {
52
+ if (chart) {
53
+ chart.data = unwrap(newData);
54
+ chart.update('none'); // Use 'none' for better performance on data updates
55
+ }
56
+ },
57
+ { defer: true },
58
+ ),
59
+ );
60
+
61
+ createEffect(
62
+ on(
63
+ () => merged.options,
64
+ (newOptions) => {
65
+ if (chart) {
66
+ chart.options = unwrap(newOptions);
67
+ chart.update();
68
+ }
69
+ },
70
+ { defer: true },
71
+ ),
72
+ );
73
+
74
+ createEffect(
75
+ on(
76
+ [() => merged.width, () => merged.height],
77
+ () => chart?.resize(merged.width, merged.height),
78
+ { defer: true },
79
+ ),
80
+ );
81
+
82
+ createEffect(
83
+ on(
84
+ () => merged.type,
85
+ () => {
86
+ if (chart) {
87
+ chart.destroy();
88
+ init();
89
+ }
90
+ },
91
+ { defer: true },
92
+ ),
93
+ );
94
+
95
+ onCleanup(() => {
96
+ chart?.destroy();
97
+ // Standard cleanup for the ref
98
+ mergeRefs(props.ref, null);
99
+ });
100
+
101
+ return (
102
+ <canvas
103
+ ref={mergeRefs(props.ref, (el) => (canvasRef = el))}
104
+ height={merged.height}
105
+ width={merged.width}
106
+ >
107
+ {merged.fallback}
108
+ </canvas>
109
+ );
110
+ };
package/src/env.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ interface ImportMetaEnv {
4
+ readonly VITE_SOLID_CHART_NAME: string;
5
+ readonly VITE_SOLID_CHART_VER: string;
6
+ }
7
+
8
+ export interface ImportMeta {
9
+ readonly env: ImportMetaEnv;
10
+ }
package/src/index.ts ADDED
@@ -0,0 +1,17 @@
1
+ export { DefaultChart } from './chart';
2
+ export {
3
+ registerBar,
4
+ registerBubble,
5
+ registerComponent,
6
+ registerCore,
7
+ registerCoreExtra,
8
+ registerDoughnut,
9
+ registerLine,
10
+ registerPie,
11
+ registerPolarArea,
12
+ registerRadar,
13
+ registerScatter,
14
+ } from './registry';
15
+ export { Bar, Bubble, Doughnut, Line, Pie, PolarArea, Radar, Scatter } from './typedCharts';
16
+ export type { TypedChartProps } from './typedCharts';
17
+ export type { ChartProps } from './types';
@@ -0,0 +1,85 @@
1
+ import {
2
+ ArcElement,
3
+ BarController,
4
+ BarElement,
5
+ BubbleController,
6
+ CategoryScale,
7
+ Chart,
8
+ ChartComponent,
9
+ Colors,
10
+ DoughnutController,
11
+ Legend,
12
+ LinearScale,
13
+ LineController,
14
+ LineElement,
15
+ PieController,
16
+ PointElement,
17
+ PolarAreaController,
18
+ RadarController,
19
+ RadialLinearScale,
20
+ ScatterController,
21
+ SubTitle,
22
+ Title,
23
+ Tooltip,
24
+ } from 'chart.js';
25
+
26
+ /**
27
+ * Global registration helper for custom components and plugins.
28
+ * Use this to register 3rd party plugins or custom scales.
29
+ */
30
+ export const registerComponent = (...args: ChartComponent[]) => Chart.register(...args);
31
+
32
+ /**
33
+ * Essential plugins most charts need.
34
+ */
35
+ export const registerCore = () => registerComponent(Tooltip, Legend);
36
+
37
+ /**
38
+ * Extra standard plugins for titles and automatic color palettes.
39
+ */
40
+ export const registerCoreExtra = () => registerComponent(Title, Tooltip, Legend, Colors, SubTitle);
41
+
42
+ /**
43
+ * Essential for Line chart.
44
+ */
45
+ export const registerLine = () =>
46
+ registerComponent(LineController, CategoryScale, LinearScale, PointElement, LineElement);
47
+
48
+ /**
49
+ * Essential for Bar chart.
50
+ */
51
+ export const registerBar = () =>
52
+ registerComponent(BarController, CategoryScale, LinearScale, BarElement);
53
+
54
+ /**
55
+ * Essential for Radar chart.
56
+ */
57
+ export const registerRadar = () =>
58
+ registerComponent(RadarController, RadialLinearScale, PointElement, LineElement);
59
+
60
+ /**
61
+ * Essential for Doughnut chart.
62
+ */
63
+ export const registerDoughnut = () => registerComponent(DoughnutController, ArcElement);
64
+
65
+ /**
66
+ * Essential for Pie chart.
67
+ */
68
+ export const registerPie = () => registerComponent(PieController, ArcElement);
69
+
70
+ /**
71
+ * Essential for PolarArea chart.
72
+ */
73
+ export const registerPolarArea = () =>
74
+ registerComponent(PolarAreaController, RadialLinearScale, ArcElement);
75
+
76
+ /**
77
+ * Essential for Bubble chart.
78
+ */
79
+ export const registerBubble = () => registerComponent(BubbleController, LinearScale, PointElement);
80
+
81
+ /**
82
+ * Essential for Scatter chart.
83
+ */
84
+ export const registerScatter = () =>
85
+ registerComponent(ScatterController, LinearScale, PointElement);
@@ -0,0 +1,17 @@
1
+ import { Component } from 'solid-js';
2
+
3
+ import { DefaultChart } from './chart';
4
+ import type { ChartProps } from './types';
5
+
6
+ // Omit 'type' from props since these components define the type themselves
7
+ export type TypedChartProps = Omit<ChartProps, 'type'>;
8
+ type TypedChart = Component<TypedChartProps>;
9
+
10
+ export const Line: TypedChart = (props) => <DefaultChart type="line" {...props} />;
11
+ export const Bar: TypedChart = (props) => <DefaultChart type="bar" {...props} />;
12
+ export const Radar: TypedChart = (props) => <DefaultChart type="radar" {...props} />;
13
+ export const Doughnut: TypedChart = (props) => <DefaultChart type="doughnut" {...props} />;
14
+ export const PolarArea: TypedChart = (props) => <DefaultChart type="polarArea" {...props} />;
15
+ export const Bubble: TypedChart = (props) => <DefaultChart type="bubble" {...props} />;
16
+ export const Pie: TypedChart = (props) => <DefaultChart type="pie" {...props} />;
17
+ export const Scatter: TypedChart = (props) => <DefaultChart type="scatter" {...props} />;
package/src/types.ts ADDED
@@ -0,0 +1,55 @@
1
+ import type { Ref } from '@solid-primitives/refs';
2
+ import type { ChartData, ChartOptions, ChartTypeRegistry, Plugin } from 'chart.js';
3
+ import type { JSXElement } from 'solid-js';
4
+
5
+ /**
6
+ * Chart props
7
+ */
8
+ export interface ChartProps {
9
+ /**
10
+ * Chart.js chart type
11
+ */
12
+ type: keyof ChartTypeRegistry;
13
+ /**
14
+ * The data object that is passed into the Chart.js chart
15
+ * @see https://www.chartjs.org/docs/latest/getting-started/
16
+ */
17
+ data?: ChartData;
18
+ /**
19
+ * The options object that is passed into the Chart.js chart
20
+ * @see https://www.chartjs.org/docs/latest/general/options.html
21
+ * @default {}
22
+ */
23
+ options?: ChartOptions;
24
+ /**
25
+ * The plugins array that is passed into the Chart.js chart
26
+ * @see https://www.chartjs.org/docs/latest/developers/plugins.html
27
+ * @default []
28
+ */
29
+ plugins?: Plugin[];
30
+ /**
31
+ * The width of the canvas element
32
+ * @default 512
33
+ */
34
+ width?: number | undefined;
35
+ /**
36
+ * The height of the canvas element
37
+ * @default 512
38
+ */
39
+ height?: number | undefined;
40
+ /**
41
+ * The fallback element to render when the canvas cannot be rendered.
42
+ * @default null
43
+ */
44
+ fallback?: JSXElement | null;
45
+ /**
46
+ * Support for any other Chart.js options
47
+ * @default {}
48
+ */
49
+ [key: string]: unknown;
50
+ /**
51
+ * A ref to the Chart.js instance
52
+ * @default null
53
+ */
54
+ ref?: Ref<HTMLCanvasElement | null>;
55
+ }