@trackunit/react-chart-components 1.3.84 → 1.3.87

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/index.cjs.js CHANGED
@@ -1,63 +1,191 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
- var cssClassVarianceUtilities = require('@trackunit/css-class-variance-utilities');
5
4
  var reactComponents = require('@trackunit/react-components');
6
- var EChart = require('echarts-for-react');
5
+ var cssClassVarianceUtilities = require('@trackunit/css-class-variance-utilities');
6
+ var sharedUtils = require('@trackunit/shared-utils');
7
+ var echarts = require('echarts');
7
8
  var react = require('react');
9
+ var uiDesignTokens = require('@trackunit/ui-design-tokens');
10
+
11
+ function _interopNamespaceDefault(e) {
12
+ var n = Object.create(null);
13
+ if (e) {
14
+ Object.keys(e).forEach(function (k) {
15
+ if (k !== 'default') {
16
+ var d = Object.getOwnPropertyDescriptor(e, k);
17
+ Object.defineProperty(n, k, d.get ? d : {
18
+ enumerable: true,
19
+ get: function () { return e[k]; }
20
+ });
21
+ }
22
+ });
23
+ }
24
+ n.default = e;
25
+ return Object.freeze(n);
26
+ }
8
27
 
28
+ var echarts__namespace = /*#__PURE__*/_interopNamespaceDefault(echarts);
29
+
30
+ function isECElementEvent(value) {
31
+ return (typeof value === "object" &&
32
+ value !== null &&
33
+ "type" in value &&
34
+ "componentType" in value &&
35
+ "componentSubType" in value &&
36
+ "componentIndex" in value &&
37
+ "seriesIndex" in value);
38
+ }
9
39
  /**
10
- * The Chart component is a wrapper component for ECharts.
11
- *
12
- * Handles events and click functionality.
13
- *
14
- * For more information see the [eCharts documentation](https://github.com/hustcc/echarts-for-react).
15
- *
16
- * @param {ChartProps} props - The props for the Chart component
17
- * @returns {ReactElement} Chart component
40
+ * A React wrapper for ECharts that handles initialization, events, and cleanup.
18
41
  */
19
- const Chart = ({ options, unsafeOptions, showLoading, className, style, onChartReady, onClick, onEvents, merge = true, loadingOption, timezoneLabel, renderer = "canvas", dataTestId, }) => {
20
- const echartsRef = react.useRef(null);
42
+ const EChart = ({ option, style, className, onChartReady, onClick, onEvents, notMerge = false, renderer = "canvas", dataTestId, }) => {
43
+ const containerRef = react.useRef(null);
44
+ const internalChartRef = react.useRef(undefined);
45
+ const isInitialRender = react.useRef(true);
46
+ const setupEventHandlers = react.useCallback((chart) => {
47
+ // Handle click events
48
+ if (onClick) {
49
+ chart.on("click", function (event) {
50
+ if (isECElementEvent(event)) {
51
+ onClick(event);
52
+ }
53
+ });
54
+ const zr = chart.getZr();
55
+ zr.setCursorStyle("pointer");
56
+ }
57
+ // Handle other events
58
+ if (onEvents) {
59
+ Object.entries(onEvents).forEach(([eventName, handler]) => {
60
+ if (eventName !== "click" || !onClick) {
61
+ // Don't double-register click if onClick is provided
62
+ chart.on(eventName, function (event) {
63
+ if (isECElementEvent(event)) {
64
+ handler(event);
65
+ }
66
+ });
67
+ }
68
+ });
69
+ }
70
+ }, [onClick, onEvents]);
71
+ const initChart = react.useCallback(() => {
72
+ const container = containerRef.current;
73
+ if (!container) {
74
+ return;
75
+ }
76
+ // Dispose existing instance if any
77
+ if (internalChartRef.current) {
78
+ internalChartRef.current.dispose();
79
+ internalChartRef.current = undefined;
80
+ }
81
+ // Create new chart instance
82
+ const newChart = echarts__namespace.init(container, undefined, {
83
+ renderer,
84
+ width: "auto",
85
+ height: "auto",
86
+ });
87
+ // Store reference and notify ready
88
+ internalChartRef.current = newChart;
89
+ if (onChartReady) {
90
+ onChartReady(newChart);
91
+ }
92
+ }, [renderer, onChartReady]);
93
+ // Initialize chart and handle cleanup
21
94
  react.useEffect(() => {
22
- const instance = echartsRef.current?.getEchartsInstance();
23
- if (instance) {
24
- if (onClick) {
25
- instance.on("click", onClick);
95
+ initChart();
96
+ isInitialRender.current = true;
97
+ const resizeObserver = new ResizeObserver(() => {
98
+ const chart = internalChartRef.current;
99
+ if (!chart) {
100
+ return;
101
+ }
102
+ if (!chart.isDisposed()) {
103
+ chart.resize();
104
+ }
105
+ });
106
+ const container = containerRef.current;
107
+ if (container) {
108
+ resizeObserver.observe(container);
109
+ }
110
+ return () => {
111
+ resizeObserver.disconnect();
112
+ const chart = internalChartRef.current;
113
+ if (!chart) {
114
+ return;
26
115
  }
27
- else {
28
- instance.getZr().setCursorStyle("default");
116
+ if (!chart.isDisposed()) {
117
+ const zr = chart.getZr();
118
+ zr.setCursorStyle("default");
119
+ chart.dispose();
120
+ internalChartRef.current = undefined;
29
121
  }
122
+ };
123
+ }, [initChart]);
124
+ // Setup event handlers
125
+ react.useEffect(() => {
126
+ const chart = internalChartRef.current;
127
+ if (chart && !chart.isDisposed()) {
128
+ // Setup handlers
129
+ setupEventHandlers(chart);
30
130
  }
31
131
  return () => {
32
- if (instance && !instance.isDisposed()) {
33
- instance.off("click", onClick);
132
+ if (chart && !chart.isDisposed()) {
133
+ // Clean up all event handlers
134
+ chart.off("click");
135
+ if (onEvents) {
136
+ sharedUtils.objectKeys(onEvents).forEach(eventName => {
137
+ chart.off(eventName);
138
+ });
139
+ }
34
140
  }
35
141
  };
36
- }, [onClick, echartsRef]);
37
- return (jsxRuntime.jsx("div", { className: cvaChartContainer(), "data-testid": dataTestId, style: { height: style?.height ?? "300px", width: style?.width ?? "100%" }, children: showLoading ? (jsxRuntime.jsxs("div", { className: cvaChartSpinnerContainer(), "data-testid": `${dataTestId}-loading`, children: [jsxRuntime.jsx(reactComponents.Spinner, { centering: "centered" }), loadingOption?.text ? (jsxRuntime.jsx(reactComponents.Text, { align: "center", subtle: true, children: loadingOption.text })) : null] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(EChart, { className: className, notMerge: !merge, onChartReady: onChartReady, onEvents: onEvents, option: options ?? unsafeOptions, opts: { width: "auto", height: "auto", renderer: renderer }, ref: echartsRef, style: style }), timezoneLabel] })) }));
142
+ }, [onEvents, setupEventHandlers]);
143
+ // Handle options updates
144
+ react.useEffect(() => {
145
+ const chart = internalChartRef.current;
146
+ if (!chart) {
147
+ return;
148
+ }
149
+ if (!chart.isDisposed()) {
150
+ // Force notMerge on initial render, respect prop afterwards
151
+ chart.setOption(option, isInitialRender.current || notMerge);
152
+ isInitialRender.current = false;
153
+ }
154
+ }, [option, notMerge]);
155
+ return jsxRuntime.jsx("div", { className: cvaEChart({ className }), "data-testid": dataTestId, ref: containerRef, style: style });
156
+ };
157
+ const cvaEChart = cssClassVarianceUtilities.cvaMerge(["w-full", "h-full"]);
158
+
159
+ /**
160
+ * The Chart component is a wrapper component for ECharts.
161
+ * Handles events and click functionality.
162
+ */
163
+ const Chart = ({ options, unsafeOptions, showLoading, className, style, onChartReady, onClick, onEvents, merge = true, loadingOption, timezoneLabel, renderer = "canvas", dataTestId, }) => {
164
+ const containerStyle = {
165
+ height: style?.height ?? "300px",
166
+ width: style?.width ?? "100%",
167
+ ...style,
168
+ };
169
+ return (jsxRuntime.jsx("div", { className: "grid h-full w-full grid-cols-1 grid-rows-1 items-center gap-1", "data-testid": dataTestId, style: containerStyle, children: showLoading ? (jsxRuntime.jsxs("div", { className: "grid place-items-center overflow-y-auto", "data-testid": `${dataTestId}-loading`, children: [jsxRuntime.jsx(reactComponents.Spinner, { centering: "centered" }), loadingOption?.text ? (jsxRuntime.jsx(reactComponents.Text, { align: "center", subtle: true, children: loadingOption.text })) : null] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(EChart, { className: className, dataTestId: `${dataTestId}-chart`, notMerge: !merge, onChartReady: onChartReady, onClick: onClick, onEvents: onEvents, option: options ?? unsafeOptions, renderer: renderer, style: style }), timezoneLabel] })) }));
38
170
  };
39
- const cvaChartContainer = cssClassVarianceUtilities.cvaMerge(["grid", "gap-1", "grid-rows-1", "grid-cols-1", "h-full", "w-full", "items-center"]);
40
- const cvaChartSpinnerContainer = cssClassVarianceUtilities.cvaMerge(["grid", "place-items-center", "overflow-y-auto"]);
41
171
 
42
172
  const cvaLegendItem = cssClassVarianceUtilities.cvaMerge([
43
- "inline-flex",
173
+ "flex",
44
174
  "items-center",
45
175
  "transition-all",
46
176
  "ease-in-out",
47
177
  "duration-200",
48
- "text-neutral-500",
49
- "hover:text-neutral-700",
50
- "text-sm",
51
- "gap-2",
178
+ "text-secondary-600",
179
+ "hover:text-secondary-900",
52
180
  ], {
53
181
  variants: {
54
182
  selected: {
55
183
  false: "",
56
- true: "font-medium text-black",
184
+ true: ["font-semibold", "text-secondary-900"],
57
185
  },
58
186
  disabled: {
59
187
  false: "",
60
- true: "text-neutral-300",
188
+ true: ["text-secondary-400", "hover:text-secondary-400"],
61
189
  },
62
190
  isClickable: {
63
191
  false: "cursor-default",
@@ -70,11 +198,11 @@ const cvaLegendItem = cssClassVarianceUtilities.cvaMerge([
70
198
  isClickable: false,
71
199
  },
72
200
  });
73
- const cvaLegendItemIndicator = cssClassVarianceUtilities.cvaMerge(["w-3", "h-3", "rounded-[50%]"], {
201
+ const cvaLegendItemIndicator = cssClassVarianceUtilities.cvaMerge(["w-3", "mr-1", "h-3", "rounded-[50%]", "flex-none"], {
74
202
  variants: {
75
203
  selected: {
76
204
  false: "",
77
- true: "border border-black border-opacity-50",
205
+ true: "",
78
206
  },
79
207
  },
80
208
  defaultVariants: {
@@ -88,79 +216,235 @@ const cvaLegendItemIndicator = cssClassVarianceUtilities.cvaMerge(["w-3", "h-3",
88
216
  * @param {LegendItem} props - The props for the LegendItem component
89
217
  * @returns {ReactElement} LegendItem component
90
218
  */
91
- const LegendItem = ({ className, label, disabled, selected, onClick, color, dataTestId }) => {
219
+ const LegendItem = ({ className, count, label, disabled, selected, onClick, color, dataTestId, onMouseEnter, onMouseLeave, }) => {
92
220
  const handleOnClick = onClick && !disabled ? () => onClick() : undefined;
93
- return (jsxRuntime.jsxs("div", { className: cvaLegendItem({ disabled, selected, isClickable: Boolean(onClick), className }), "data-testid": dataTestId, onClick: handleOnClick, children: [jsxRuntime.jsx("div", { className: cvaLegendItemIndicator({ selected }), "data-testid": dataTestId ? `${dataTestId}-indicator` : null, style: { backgroundColor: color } }), label ? jsxRuntime.jsx("p", { children: label }) : null] }));
221
+ return (jsxRuntime.jsxs("div", { className: cvaLegendItem({ disabled, selected, isClickable: !disabled && Boolean(onClick), className }), "data-testid": dataTestId, onClick: handleOnClick, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, children: [jsxRuntime.jsx("div", { className: cvaLegendItemIndicator({ selected }), "data-testid": dataTestId ? `${dataTestId}-indicator` : null, style: { backgroundColor: color } }), jsxRuntime.jsxs("p", { className: "truncate text-xs", children: [label, "\u00A0"] }), jsxRuntime.jsxs("p", { className: "text-xs", children: ["(", count || 0, ")"] })] }));
222
+ };
223
+
224
+ /**
225
+ * Re-ordered chart colors to ensure that adjacent colors are visually different.
226
+ *
227
+ * @returns {string[]} The reordered chart colors.
228
+ */
229
+ const useChartColor = () => {
230
+ const chartColor = react.useCallback((index) => {
231
+ return uiDesignTokens.DEFAULT_CHART_COLORS[index % uiDesignTokens.DEFAULT_CHART_COLORS.length] ?? "#000000";
232
+ }, []);
233
+ const chartColorArray = react.useCallback((total) => {
234
+ return Array.from({ length: total }, (_, index) => chartColor(index));
235
+ }, [chartColor]);
236
+ const chartStatusColor = react.useCallback((status) => {
237
+ return uiDesignTokens.CHART_STATUS_COLORS[status];
238
+ }, []);
239
+ return {
240
+ chartColor,
241
+ chartColorArray,
242
+ chartStatusColor,
243
+ };
244
+ };
245
+
246
+ /**
247
+ * Limits the data set to the given limit.
248
+ * If the data set is larger than the limit, the data set is limited to the limit and the rest of the data is added to the "Others" group.
249
+ *
250
+ * @param data - The data set to limit.
251
+ * @param limit - The limit to apply to the data set.
252
+ * @returns {object} The limited data set with and without the "others" category.
253
+ */
254
+ const useLimitDataSet = (data, limit) => {
255
+ const limitedData = react.useMemo(() => {
256
+ const sortedData = data.sort((a, b) => (b.count ?? 0) - (a.count ?? 0));
257
+ if (sortedData.length > limit) {
258
+ const result = sortedData.slice(0, limit);
259
+ result.push({
260
+ id: "defaultOther",
261
+ name: "Others",
262
+ selected: false,
263
+ count: sortedData.slice(limit).reduce((acc, curr) => acc + (curr.count ?? 0), 0),
264
+ color: uiDesignTokens.DEFAULT_CHART_OTHER,
265
+ original: { defaultOther: true },
266
+ });
267
+ return result;
268
+ }
269
+ return sortedData;
270
+ }, [data, limit]);
271
+ const limitedDataWithoutOthers = react.useMemo(() => limitedData.filter(item => !item.original?.defaultOther), [limitedData]);
272
+ return { limitedData, limitedDataWithoutOthers };
94
273
  };
95
274
 
96
275
  /**
97
- * Create a PieChart with legends based on our current Chart component
276
+ * Create a DonutChart with legends based on our current Chart component
98
277
  *
99
- * @param {PieChartProps} props - The props for the Chart component
278
+ * @param {DonutChartProps} props - The props for the Chart component
100
279
  * @returns {ReactElement} Chart component
101
280
  */
102
- const PieChart = ({ data, size = "full", loading, onClick, className, dataTestId, }) => {
103
- const totalCount = data?.map(item => item.count ?? 0).reduce((a, b) => a + b, 0) ?? 0;
104
- const { hovering, onMouseEnter, onMouseLeave } = reactComponents.useHover({ debounced: true });
105
- return (jsxRuntime.jsxs("div", { className: cvaChartRoot({ className }), "data-testid": dataTestId, children: [jsxRuntime.jsx("div", { children: size === "full" && (jsxRuntime.jsx("div", { className: "flex flex-col", "data-testid": "legend", children: data?.map(item => (jsxRuntime.jsx(LegendItem, { color: item.color, dataTestId: `legend-${item.id}`, label: item.count !== undefined ? `${item.name} (${item.count})` : item.name, onClick: onClick ? () => onClick(item) : undefined, selected: item.selected }, item.id))) })) }), jsxRuntime.jsx("div", { onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, children: jsxRuntime.jsx(Chart, { dataTestId: "pie-chart", onClick: evt => {
106
- const clickedEntry = data?.find(x => x.id === evt.data.id);
107
- if (onClick && clickedEntry) {
108
- onClick(clickedEntry);
109
- }
110
- }, options: {
111
- legend: {
112
- show: false,
113
- },
114
- tooltip: {
115
- show: false,
281
+ const DonutChart = ({ data, size = "full", loading, onClick, className, dataTestId, legendPosition = "Right", maxDataPoints = 6, showOthers = true, }) => {
282
+ const containerRef = react.useRef(null);
283
+ const chartRef = react.useRef(null);
284
+ const totalCount = react.useMemo(() => data?.map(item => item.count ?? 0).reduce((a, b) => a + b, 0) ?? 0, [data]);
285
+ const [hoveringItem, setHoveringItem] = react.useState(null);
286
+ const currentCount = react.useMemo(() => hoveringItem?.count ?? totalCount, [hoveringItem, totalCount]);
287
+ const { limitedData, limitedDataWithoutOthers } = useLimitDataSet(data ?? [], maxDataPoints);
288
+ const { chartColor } = useChartColor();
289
+ const handleChartReady = react.useCallback((chart) => {
290
+ chartRef.current = chart;
291
+ }, []);
292
+ const handleChartClick = react.useCallback((evt) => {
293
+ if (onClick && data) {
294
+ const clickedEntry = data.find(x => {
295
+ if (!evt.data || typeof evt.data !== "object" || !("id" in evt.data)) {
296
+ return false;
297
+ }
298
+ return x.id === evt.data.id;
299
+ });
300
+ if (clickedEntry) {
301
+ onClick(clickedEntry);
302
+ }
303
+ }
304
+ }, [onClick, data]);
305
+ const handleChartEvents = react.useMemo(() => ({
306
+ mouseover: (evt) => {
307
+ const hoveredItem = data?.[evt.dataIndex];
308
+ if (hoveredItem) {
309
+ setHoveringItem(hoveredItem);
310
+ }
311
+ },
312
+ mouseout: () => {
313
+ setHoveringItem(null);
314
+ },
315
+ }), [data, setHoveringItem]);
316
+ const handleLegendMouseEnter = react.useCallback((item) => {
317
+ setHoveringItem(item);
318
+ const chart = chartRef.current;
319
+ if (!chart) {
320
+ return;
321
+ }
322
+ // Find the index in the current chart data
323
+ const index = (showOthers ? limitedData : limitedDataWithoutOthers).findIndex(d => d.id === item.id);
324
+ if (index !== -1) {
325
+ chart.dispatchAction({
326
+ type: "highlight",
327
+ seriesIndex: 0,
328
+ dataIndex: index,
329
+ });
330
+ }
331
+ }, [limitedData, limitedDataWithoutOthers, showOthers]);
332
+ const handleLegendMouseLeave = react.useCallback(() => {
333
+ setHoveringItem(null);
334
+ const chart = chartRef.current;
335
+ if (!chart) {
336
+ return;
337
+ }
338
+ chart.dispatchAction({
339
+ type: "downplay",
340
+ seriesIndex: 0,
341
+ });
342
+ }, []);
343
+ const chartOptions = react.useMemo(() => {
344
+ return {
345
+ legend: {
346
+ show: false,
347
+ },
348
+ tooltip: {
349
+ show: false,
350
+ },
351
+ series: [
352
+ {
353
+ type: "pie",
354
+ radius: ["50%", "75%"],
355
+ center: ["50%", "50%"],
356
+ minAngle: 5,
357
+ selectedOffset: 8,
358
+ itemStyle: {
359
+ borderColor: "#ffffff",
360
+ borderWidth: 2,
361
+ },
362
+ avoidLabelOverlap: false,
363
+ label: {
364
+ show: true,
365
+ position: "center",
366
+ fontSize: size === "full" ? 18 : 12,
367
+ fontWeight: "bold",
368
+ formatter: currentCount.toString(),
369
+ },
370
+ emphasis: {
371
+ label: {
372
+ show: true,
373
+ formatter: "{c}",
116
374
  },
117
- series: [
118
- {
119
- type: "pie",
120
- radius: ["50%", "75%"], //can't be 100 since it'll be cut off when hovering
121
- center: ["50%", "50%"],
122
- minAngle: 10,
123
- selectedOffset: 8,
124
- itemStyle: {
125
- borderColor: "#ffffff",
126
- borderWidth: 2,
127
- },
128
- avoidLabelOverlap: false,
129
- label: {
130
- show: !hovering,
131
- position: "center",
132
- fontSize: size === "full" ? 18 : 12,
133
- fontWeight: "bold",
134
- formatter: totalCount.toString(),
135
- },
136
- emphasis: {
137
- label: {
138
- show: hovering,
139
- formatter: "{c}",
140
- },
141
- },
142
- labelLine: {
143
- show: false,
144
- },
145
- data: data?.map(item => ({
146
- id: item.id,
147
- name: item.name,
148
- value: item.count ?? 0,
149
- itemStyle: { color: item.color },
150
- })),
375
+ },
376
+ labelLine: {
377
+ show: false,
378
+ },
379
+ data: (showOthers ? limitedData : limitedDataWithoutOthers)
380
+ .map((item, index) => {
381
+ const itemColor = item.color ?? chartColor(index);
382
+ return {
383
+ id: item.id,
384
+ name: item.name,
385
+ value: item.count ?? 0,
386
+ itemStyle: {
387
+ color: itemColor,
151
388
  },
152
- ],
153
- }, showLoading: loading, style: size === "full" ? { height: 110, width: 110 } : { height: 60, width: 60 } }) })] }));
389
+ emphasis: {
390
+ disabled: false,
391
+ scale: true,
392
+ scaleSize: 5,
393
+ },
394
+ selected: hoveringItem?.id === item.id,
395
+ };
396
+ })
397
+ .filter(item => item.value),
398
+ },
399
+ ],
400
+ };
401
+ }, [size, currentCount, showOthers, limitedData, limitedDataWithoutOthers, chartColor, hoveringItem?.id]);
402
+ return (jsxRuntime.jsxs("div", { className: cvaChartRoot({ className, legendPosition }), "data-testid": dataTestId, ref: containerRef, children: [jsxRuntime.jsx("div", { className: cvaChartContainer({ legendPosition }), children: jsxRuntime.jsx(Chart, { className: cvaChart({ legendPosition, size }), dataTestId: "pie-chart", onChartReady: handleChartReady, onClick: handleChartClick, onEvents: handleChartEvents, options: chartOptions, showLoading: loading, style: { width: "100%", height: "100%" } }) }), size === "full" && (jsxRuntime.jsx("div", { className: cvaLegend({ legendPosition }), "data-testid": "legend", children: limitedData.map((item, index) => (jsxRuntime.jsx(LegendItem, { className: "p-1.5 py-0.5", color: item.color ?? chartColor(index), count: item.count, dataTestId: `legend-${item.id}`, disabled: item.count === 0, label: item.name, onClick: onClick ? () => onClick(item) : undefined, onMouseEnter: () => handleLegendMouseEnter(item), onMouseLeave: handleLegendMouseLeave, selected: item.selected }, item.id))) }))] }));
154
403
  };
155
- const cvaChartRoot = cssClassVarianceUtilities.cvaMerge([
156
- "flex",
157
- "flex-direction-col",
158
- "flex-wrap-reverse",
159
- "justify-between",
160
- "items-center",
161
- "h-full",
162
- ]);
404
+ const cvaChartRoot = cssClassVarianceUtilities.cvaMerge(["flex", "w-full", "h-full", "gap-4"], {
405
+ variants: {
406
+ legendPosition: {
407
+ Right: ["items-center", "justify-items-stretch", "flex-row"],
408
+ Bottom: ["items-center", "flex-col"],
409
+ },
410
+ },
411
+ });
412
+ const cvaChartContainer = cssClassVarianceUtilities.cvaMerge(["flex-1", "h-full"], {
413
+ variants: {
414
+ legendPosition: {
415
+ Right: ["justify-end"],
416
+ Bottom: ["flex", "items-center", "w-full"],
417
+ },
418
+ },
419
+ });
420
+ const cvaChart = cssClassVarianceUtilities.cvaMerge(["flex-0", "max-w-[200px]", "max-h-[200px]", "place-self-center"], {
421
+ variants: {
422
+ legendPosition: {
423
+ Right: [],
424
+ Bottom: ["max-h-[230px]"],
425
+ },
426
+ size: {
427
+ full: ["min-h-[140px]"],
428
+ compact: ["w-[60px]", "h-[60px]"],
429
+ },
430
+ },
431
+ defaultVariants: {
432
+ size: "full",
433
+ },
434
+ });
435
+ const cvaLegend = cssClassVarianceUtilities.cvaMerge(["flex", "overflow-auto"], {
436
+ variants: {
437
+ legendPosition: {
438
+ Right: ["justify-start", "flex-col", "flex-1"],
439
+ Bottom: ["flex-wrap", "justify-end", "flex-row"],
440
+ },
441
+ },
442
+ defaultVariants: {
443
+ legendPosition: "Right",
444
+ },
445
+ });
163
446
 
164
447
  exports.Chart = Chart;
448
+ exports.DonutChart = DonutChart;
165
449
  exports.LegendItem = LegendItem;
166
- exports.PieChart = PieChart;
450
+ exports.useChartColor = useChartColor;