@chartml/react 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 Alytic Pty Ltd
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,437 @@
1
+ # @chartml/react
2
+
3
+ React wrapper component for ChartML - render beautiful data visualizations in React with ease.
4
+
5
+ ## Features
6
+
7
+ - ✅ **React Component** - Clean, idiomatic React API
8
+ - ✅ **useChartML Hook** - Manage ChartML instances with React hooks
9
+ - ✅ **Auto-Cleanup** - Automatic cleanup on unmount
10
+ - ✅ **Plugin Support** - Register custom chart renderers and data sources
11
+ - ✅ **Event Callbacks** - Progress, cache hit/miss, and error events
12
+ - ✅ **TypeScript Ready** - Includes TypeScript definitions
13
+ - ✅ **All Chart Types** - Includes pie, scatter, and metric chart plugins
14
+ - ✅ **Zero Config** - Works out of the box with sensible defaults
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @chartml/react
20
+ ```
21
+
22
+ **Peer Dependencies:**
23
+ - `react` ^18.0.0
24
+ - `react-dom` ^18.0.0
25
+
26
+ The core ChartML library is included automatically.
27
+
28
+ ## Quick Start
29
+
30
+ ### Basic Usage
31
+
32
+ ```jsx
33
+ import { ChartMLChart } from '@chartml/react';
34
+
35
+ function SalesChart() {
36
+ const spec = `
37
+ type: chart
38
+ version: 1
39
+
40
+ data:
41
+ - month: "Jan"
42
+ revenue: 45000
43
+ - month: "Feb"
44
+ revenue: 52000
45
+ - month: "Mar"
46
+ revenue: 48000
47
+
48
+ visualize:
49
+ type: bar
50
+ columns: month
51
+ rows: revenue
52
+ style:
53
+ title: "Monthly Revenue"
54
+ `;
55
+
56
+ return <ChartMLChart spec={spec} />;
57
+ }
58
+ ```
59
+
60
+ ### With Styling
61
+
62
+ ```jsx
63
+ <ChartMLChart
64
+ spec={spec}
65
+ className="my-chart"
66
+ style={{ maxWidth: '800px', margin: '0 auto' }}
67
+ />
68
+ ```
69
+
70
+ ### With Event Callbacks
71
+
72
+ ```jsx
73
+ import { ChartMLChart } from '@chartml/react';
74
+ import { useState } from 'react';
75
+
76
+ function ChartWithStatus() {
77
+ const [status, setStatus] = useState('idle');
78
+
79
+ return (
80
+ <div>
81
+ <p>Status: {status}</p>
82
+ <ChartMLChart
83
+ spec={spec}
84
+ options={{
85
+ onProgress: (e) => setStatus(`Loading: ${e.percent}%`),
86
+ onCacheHit: () => setStatus('Loaded from cache'),
87
+ onCacheMiss: () => setStatus('Fetching data'),
88
+ onError: (err) => setStatus(`Error: ${err.message}`)
89
+ }}
90
+ />
91
+ </div>
92
+ );
93
+ }
94
+ ```
95
+
96
+ ## Advanced Usage
97
+
98
+ ### Using the useChartML Hook
99
+
100
+ For more control, use the `useChartML` hook to manage your own ChartML instance:
101
+
102
+ ```jsx
103
+ import { ChartMLChart, useChartML } from '@chartml/react';
104
+ import { useEffect } from 'react';
105
+
106
+ function CustomChart() {
107
+ const chartml = useChartML({
108
+ onProgress: (e) => console.log(`Progress: ${e.percent}%`),
109
+ palettes: {
110
+ custom: ['#ff0000', '#00ff00', '#0000ff']
111
+ }
112
+ });
113
+
114
+ // Register custom renderers if needed
115
+ useEffect(() => {
116
+ // Custom plugins would be registered here
117
+ // chartml.registerChartRenderer('custom', myRenderer);
118
+ }, [chartml]);
119
+
120
+ return <ChartMLChart spec={spec} chartml={chartml} />;
121
+ }
122
+ ```
123
+
124
+ ### Dynamic Specs with State
125
+
126
+ ```jsx
127
+ import { ChartMLChart } from '@chartml/react';
128
+ import { useState } from 'react';
129
+
130
+ function DynamicChart() {
131
+ const [chartType, setChartType] = useState('bar');
132
+
133
+ const spec = `
134
+ type: chart
135
+ version: 1
136
+
137
+ data:
138
+ - month: "Jan"
139
+ revenue: 45000
140
+ - month: "Feb"
141
+ revenue: 52000
142
+
143
+ visualize:
144
+ type: ${chartType}
145
+ columns: month
146
+ rows: revenue
147
+ `;
148
+
149
+ return (
150
+ <div>
151
+ <button onClick={() => setChartType('bar')}>Bar</button>
152
+ <button onClick={() => setChartType('line')}>Line</button>
153
+ <button onClick={() => setChartType('area')}>Area</button>
154
+ <ChartMLChart spec={spec} />
155
+ </div>
156
+ );
157
+ }
158
+ ```
159
+
160
+ ### Fetching Data from API
161
+
162
+ ```jsx
163
+ import { ChartMLChart } from '@chartml/react';
164
+ import { useState, useEffect } from 'react';
165
+
166
+ function APIChart() {
167
+ const [chartData, setChartData] = useState(null);
168
+
169
+ useEffect(() => {
170
+ fetch('/api/sales-data')
171
+ .then(res => res.json())
172
+ .then(data => {
173
+ const spec = {
174
+ type: 'chart',
175
+ version: 1,
176
+ data: data,
177
+ visualize: {
178
+ type: 'bar',
179
+ columns: 'month',
180
+ rows: 'revenue'
181
+ }
182
+ };
183
+ setChartData(spec);
184
+ });
185
+ }, []);
186
+
187
+ if (!chartData) return <div>Loading...</div>;
188
+
189
+ return <ChartMLChart spec={chartData} />;
190
+ }
191
+ ```
192
+
193
+ ## All Chart Types Available
194
+
195
+ This package includes all ChartML chart plugins by default:
196
+
197
+ ### Built-in Chart Types
198
+ - `bar` - Vertical and horizontal bar charts
199
+ - `line` - Single and multi-series line charts
200
+ - `area` - Stacked and normalized area charts
201
+
202
+ ### Included Plugins
203
+ - `pie` - Pie charts (from @chartml/chart-pie)
204
+ - `doughnut` - Doughnut charts (from @chartml/chart-pie)
205
+ - `scatter` - Scatter plots and bubble charts (from @chartml/chart-scatter)
206
+ - `metric` - Metric cards for KPIs (from @chartml/chart-metric)
207
+
208
+ All types work out of the box - no additional imports needed!
209
+
210
+ ## API Reference
211
+
212
+ ### `<ChartMLChart>` Component
213
+
214
+ **Props:**
215
+
216
+ | Prop | Type | Description |
217
+ |------|------|-------------|
218
+ | `spec` | `string \| object` | ChartML specification (YAML string or object) |
219
+ | `chartml` | `ChartML` | Optional ChartML instance (for custom plugins) |
220
+ | `options` | `object` | Options for ChartML instance |
221
+ | `options.onProgress` | `function` | Progress callback: `(event) => void` |
222
+ | `options.onCacheHit` | `function` | Cache hit callback: `(event) => void` |
223
+ | `options.onCacheMiss` | `function` | Cache miss callback: `(event) => void` |
224
+ | `options.onError` | `function` | Error callback: `(error) => void` |
225
+ | `options.palettes` | `object` | Custom color palettes |
226
+ | `className` | `string` | CSS class for container |
227
+ | `style` | `object` | Inline styles for container |
228
+
229
+ **Example:**
230
+
231
+ ```jsx
232
+ <ChartMLChart
233
+ spec={mySpec}
234
+ className="chart-container"
235
+ style={{ maxWidth: '100%' }}
236
+ options={{
237
+ onProgress: (e) => console.log(e.percent),
238
+ onError: (err) => console.error(err)
239
+ }}
240
+ />
241
+ ```
242
+
243
+ ### `useChartML()` Hook
244
+
245
+ Creates and manages a ChartML instance with React hooks.
246
+
247
+ **Parameters:**
248
+ - `options` (object, optional) - ChartML options
249
+
250
+ **Returns:** `ChartML` instance
251
+
252
+ **Example:**
253
+
254
+ ```jsx
255
+ const chartml = useChartML({
256
+ onProgress: (e) => console.log(`Loading: ${e.percent}%`),
257
+ palettes: {
258
+ custom: ['#ff0000', '#00ff00', '#0000ff']
259
+ }
260
+ });
261
+ ```
262
+
263
+ ## Examples
264
+
265
+ ### Pie Chart
266
+
267
+ ```jsx
268
+ const pieSpec = `
269
+ type: chart
270
+ version: 1
271
+
272
+ data:
273
+ - category: "Product A"
274
+ sales: 1200
275
+ - category: "Product B"
276
+ sales: 850
277
+ - category: "Product C"
278
+ sales: 1450
279
+
280
+ visualize:
281
+ type: pie
282
+ columns: category
283
+ rows: sales
284
+ style:
285
+ title: "Sales by Product"
286
+ `;
287
+
288
+ <ChartMLChart spec={pieSpec} />
289
+ ```
290
+
291
+ ### Scatter Plot
292
+
293
+ ```jsx
294
+ const scatterSpec = `
295
+ type: chart
296
+ version: 1
297
+
298
+ data:
299
+ - temperature: 65
300
+ sales: 120
301
+ - temperature: 70
302
+ sales: 140
303
+ - temperature: 75
304
+ sales: 180
305
+
306
+ visualize:
307
+ type: scatter
308
+ columns: temperature
309
+ rows: sales
310
+ style:
311
+ title: "Sales vs Temperature"
312
+ `;
313
+
314
+ <ChartMLChart spec={scatterSpec} />
315
+ ```
316
+
317
+ ### Metric Card
318
+
319
+ ```jsx
320
+ const metricSpec = `
321
+ type: chart
322
+ version: 1
323
+
324
+ data:
325
+ - value: 1234
326
+
327
+ visualize:
328
+ type: metric
329
+ rows: value
330
+ style:
331
+ title: "Total Revenue"
332
+ format: "$,.0f"
333
+ `;
334
+
335
+ <ChartMLChart spec={metricSpec} />
336
+ ```
337
+
338
+ ## TypeScript Support
339
+
340
+ Type definitions are included:
341
+
342
+ ```tsx
343
+ import { ChartMLChart, useChartML } from '@chartml/react';
344
+ import type { ChartML } from '@chartml/core';
345
+
346
+ interface ChartProps {
347
+ data: any[];
348
+ }
349
+
350
+ function TypedChart({ data }: ChartProps) {
351
+ const chartml: ChartML = useChartML();
352
+
353
+ const spec = {
354
+ type: 'chart' as const,
355
+ version: 1,
356
+ data,
357
+ visualize: {
358
+ type: 'bar' as const,
359
+ columns: 'month',
360
+ rows: 'revenue'
361
+ }
362
+ };
363
+
364
+ return <ChartMLChart spec={spec} chartml={chartml} />;
365
+ }
366
+ ```
367
+
368
+ ## Best Practices
369
+
370
+ ### 1. Memoize Spec Objects
371
+
372
+ If passing spec as an object (not string), memoize it to prevent unnecessary re-renders:
373
+
374
+ ```jsx
375
+ import { useMemo } from 'react';
376
+
377
+ const spec = useMemo(() => ({
378
+ type: 'chart',
379
+ version: 1,
380
+ data: chartData,
381
+ visualize: { type: 'bar', columns: 'x', rows: 'y' }
382
+ }), [chartData]);
383
+
384
+ <ChartMLChart spec={spec} />
385
+ ```
386
+
387
+ ### 2. Use String Specs for Static Charts
388
+
389
+ For static charts, YAML strings are more readable:
390
+
391
+ ```jsx
392
+ const spec = `
393
+ type: chart
394
+ version: 1
395
+ data: [...]
396
+ visualize: { type: bar }
397
+ `;
398
+ ```
399
+
400
+ ### 3. Handle Loading States
401
+
402
+ Always handle loading states for async data:
403
+
404
+ ```jsx
405
+ if (!data) return <div>Loading chart...</div>;
406
+ return <ChartMLChart spec={buildSpec(data)} />;
407
+ ```
408
+
409
+ ### 4. Error Boundaries
410
+
411
+ Wrap charts in error boundaries for production:
412
+
413
+ ```jsx
414
+ <ErrorBoundary fallback={<div>Chart failed to load</div>}>
415
+ <ChartMLChart spec={spec} />
416
+ </ErrorBoundary>
417
+ ```
418
+
419
+ ## Browser Support
420
+
421
+ - React 18+
422
+ - Modern browsers with SVG support
423
+ - IE11+ (with polyfills)
424
+
425
+ ## Documentation
426
+
427
+ - **ChartML Specification**: https://chartml.org/spec
428
+ - **Examples**: https://chartml.org/examples
429
+ - **API Reference**: https://chartml.org/api
430
+
431
+ ## License
432
+
433
+ MIT © 2025 Alytic Pty Ltd
434
+
435
+ ## Powered By
436
+
437
+ ChartML is maintained by the team at [Kyomi](https://kyomi.ai) and is the visualization engine that powers the platform.
package/dist/index.js ADDED
@@ -0,0 +1,25 @@
1
+ import { useRef as u, useEffect as l } from "react";
2
+ import { ChartML as f } from "@chartml/core";
3
+ function R({ spec: e, chartml: r, options: n = {}, className: o = "", style: i = {} }) {
4
+ const t = u(null), c = u(null);
5
+ return l(() => (c.current || (c.current = r || new f(n)), (async () => {
6
+ if (t.current && e)
7
+ try {
8
+ await c.current.render(e, t.current);
9
+ } catch (a) {
10
+ console.error("[ChartML React] Render failed:", a), n.onError && n.onError(a);
11
+ }
12
+ })(), () => {
13
+ t.current && (t.current.innerHTML = "");
14
+ }), [e, r, n]), /* @__PURE__ */ React.createElement("div", { ref: t, className: o, style: i });
15
+ }
16
+ function m(e = {}) {
17
+ const r = u(null);
18
+ return r.current || (r.current = new f(e)), r.current;
19
+ }
20
+ export {
21
+ R as ChartMLChart,
22
+ R as default,
23
+ m as useChartML
24
+ };
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/index.jsx"],"sourcesContent":["/**\n * @chartml/react\n *\n * React wrapper component for ChartML\n * Provides a convenient React API for rendering ChartML specifications\n *\n * @example\n * import { ChartMLChart } from '@chartml/react';\n * import { ChartML } from '@chartml/core';\n *\n * function MyComponent() {\n * const spec = `\n * data:\n * - month: Jan\n * revenue: 45000\n * - month: Feb\n * revenue: 52000\n *\n * visualize:\n * type: bar\n * columns: month\n * rows: revenue\n * style:\n * title: \"Monthly Revenue\"\n * `;\n *\n * return <ChartMLChart spec={spec} />;\n * }\n */\n\nimport { useEffect, useRef } from 'react';\nimport { ChartML } from '@chartml/core';\n\n/**\n * ChartMLChart Component\n *\n * @param {Object} props\n * @param {string|object} props.spec - ChartML specification (YAML string or object)\n * @param {ChartML} [props.chartml] - Optional ChartML instance (for custom plugins)\n * @param {Object} [props.options] - Options for ChartML instance (if not providing instance)\n * @param {Function} [props.options.onProgress] - Progress callback\n * @param {Function} [props.options.onCacheHit] - Cache hit callback\n * @param {Function} [props.options.onCacheMiss] - Cache miss callback\n * @param {Function} [props.options.onError] - Error callback\n * @param {Object} [props.options.palettes] - Custom color palettes\n * @param {string} [props.className] - CSS class for container\n * @param {Object} [props.style] - Inline styles for container\n *\n * @example\n * // Basic usage\n * <ChartMLChart spec={yamlSpec} />\n *\n * @example\n * // With custom ChartML instance (for plugins)\n * const chartml = new ChartML();\n * chartml.registerChartRenderer('pie', pieRenderer);\n * <ChartMLChart spec={spec} chartml={chartml} />\n *\n * @example\n * // With hooks\n * <ChartMLChart\n * spec={spec}\n * options={{\n * onProgress: (event) => console.log(`Progress: ${event.percent}%`),\n * onCacheHit: (event) => console.log('Cache hit!'),\n * palettes: { myPalette: ['#ff0000', '#00ff00', '#0000ff'] }\n * }}\n * />\n */\nexport function ChartMLChart({ spec, chartml, options = {}, className = '', style = {} }) {\n const containerRef = useRef(null);\n const chartmlRef = useRef(null);\n\n useEffect(() => {\n // Create or use provided ChartML instance\n if (!chartmlRef.current) {\n chartmlRef.current = chartml || new ChartML(options);\n }\n\n // Render chart\n const renderChart = async () => {\n if (containerRef.current && spec) {\n try {\n await chartmlRef.current.render(spec, containerRef.current);\n } catch (error) {\n console.error('[ChartML React] Render failed:', error);\n if (options.onError) {\n options.onError(error);\n }\n }\n }\n };\n\n renderChart();\n\n // Cleanup function\n return () => {\n // Clear container on unmount\n if (containerRef.current) {\n containerRef.current.innerHTML = '';\n }\n };\n }, [spec, chartml, options]);\n\n return <div ref={containerRef} className={className} style={style} />;\n}\n\n/**\n * useChartML Hook\n *\n * Creates and manages a ChartML instance with plugins\n *\n * @param {Object} options - ChartML options\n * @returns {ChartML} ChartML instance\n *\n * @example\n * import { useChartML } from '@chartml/react';\n * import { createPieChartRenderer } from '@chartml/chart-pie';\n *\n * function MyComponent() {\n * const chartml = useChartML({\n * onProgress: (e) => console.log(`Progress: ${e.percent}%`)\n * });\n *\n * useEffect(() => {\n * chartml.registerChartRenderer('pie', createPieChartRenderer());\n * }, [chartml]);\n *\n * return <ChartMLChart spec={spec} chartml={chartml} />;\n * }\n */\nexport function useChartML(options = {}) {\n const chartmlRef = useRef(null);\n\n if (!chartmlRef.current) {\n chartmlRef.current = new ChartML(options);\n }\n\n return chartmlRef.current;\n}\n\nexport default ChartMLChart;\n"],"names":["ChartMLChart","spec","chartml","options","className","style","containerRef","useRef","chartmlRef","useEffect","ChartML","error","useChartML"],"mappings":";;AAqEO,SAASA,EAAa,EAAE,MAAAC,GAAM,SAAAC,GAAS,SAAAC,IAAU,IAAI,WAAAC,IAAY,IAAI,OAAAC,IAAQ,CAAA,KAAM;AACxF,QAAMC,IAAeC,EAAO,IAAI,GAC1BC,IAAaD,EAAO,IAAI;AAE9B,SAAAE,EAAU,OAEHD,EAAW,YACdA,EAAW,UAAUN,KAAW,IAAIQ,EAAQP,CAAO,KAIjC,YAAY;AAC9B,QAAIG,EAAa,WAAWL;AAC1B,UAAI;AACF,cAAMO,EAAW,QAAQ,OAAOP,GAAMK,EAAa,OAAO;AAAA,MAC5D,SAASK,GAAO;AACd,gBAAQ,MAAM,kCAAkCA,CAAK,GACjDR,EAAQ,WACVA,EAAQ,QAAQQ,CAAK;AAAA,MAEzB;AAAA,EAEJ,GAEA,GAGO,MAAM;AAEX,IAAIL,EAAa,YACfA,EAAa,QAAQ,YAAY;AAAA,EAErC,IACC,CAACL,GAAMC,GAASC,CAAO,CAAC,GAEpB,sBAAA,cAAC,OAAA,EAAI,KAAKG,GAAc,WAAAF,GAAsB,OAAAC,GAAc;AACrE;AA0BO,SAASO,EAAWT,IAAU,IAAI;AACvC,QAAMK,IAAaD,EAAO,IAAI;AAE9B,SAAKC,EAAW,YACdA,EAAW,UAAU,IAAIE,EAAQP,CAAO,IAGnCK,EAAW;AACpB;"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@chartml/react",
3
+ "version": "1.0.0",
4
+ "description": "React wrapper component for ChartML",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "module": "dist/index.js",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "scripts": {
20
+ "build": "vite build",
21
+ "dev": "vite build --watch"
22
+ },
23
+ "keywords": [
24
+ "chartml",
25
+ "react",
26
+ "chart",
27
+ "visualization",
28
+ "wrapper"
29
+ ],
30
+ "author": "Jason Adams",
31
+ "license": "MIT",
32
+ "dependencies": {
33
+ "@chartml/core": "^1.0.0",
34
+ "@chartml/chart-pie": "^1.0.0",
35
+ "@chartml/chart-scatter": "^1.0.0",
36
+ "@chartml/chart-metric": "^1.0.0"
37
+ },
38
+ "peerDependencies": {
39
+ "react": "^18.0.0",
40
+ "react-dom": "^18.0.0"
41
+ },
42
+ "devDependencies": {
43
+ "vite": "^5.0.0"
44
+ },
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "https://github.com/chartml/chartml.git",
48
+ "directory": "packages/react"
49
+ },
50
+ "homepage": "https://chartml.org"
51
+ }