@classic-homes/charts-svelte 0.1.1

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.
Files changed (53) hide show
  1. package/dist/lib/components/base/ChartContainer.svelte +63 -0
  2. package/dist/lib/components/base/ChartContainer.svelte.d.ts +17 -0
  3. package/dist/lib/components/base/ChartEmpty.svelte +39 -0
  4. package/dist/lib/components/base/ChartEmpty.svelte.d.ts +8 -0
  5. package/dist/lib/components/base/ChartError.svelte +49 -0
  6. package/dist/lib/components/base/ChartError.svelte.d.ts +9 -0
  7. package/dist/lib/components/base/ChartSkeleton.svelte +37 -0
  8. package/dist/lib/components/base/ChartSkeleton.svelte.d.ts +7 -0
  9. package/dist/lib/components/base/index.d.ts +4 -0
  10. package/dist/lib/components/base/index.js +4 -0
  11. package/dist/lib/components/core/AreaChart.svelte +198 -0
  12. package/dist/lib/components/core/AreaChart.svelte.d.ts +7 -0
  13. package/dist/lib/components/core/BarChart.svelte +186 -0
  14. package/dist/lib/components/core/BarChart.svelte.d.ts +7 -0
  15. package/dist/lib/components/core/DonutChart.svelte +207 -0
  16. package/dist/lib/components/core/DonutChart.svelte.d.ts +7 -0
  17. package/dist/lib/components/core/LineChart.svelte +203 -0
  18. package/dist/lib/components/core/LineChart.svelte.d.ts +7 -0
  19. package/dist/lib/components/core/PieChart.svelte +156 -0
  20. package/dist/lib/components/core/PieChart.svelte.d.ts +7 -0
  21. package/dist/lib/components/core/ScatterChart.svelte +224 -0
  22. package/dist/lib/components/core/ScatterChart.svelte.d.ts +7 -0
  23. package/dist/lib/components/core/index.d.ts +6 -0
  24. package/dist/lib/components/core/index.js +6 -0
  25. package/dist/lib/components/extended/CandlestickChart.svelte +200 -0
  26. package/dist/lib/components/extended/CandlestickChart.svelte.d.ts +7 -0
  27. package/dist/lib/components/extended/FunnelChart.svelte +142 -0
  28. package/dist/lib/components/extended/FunnelChart.svelte.d.ts +7 -0
  29. package/dist/lib/components/extended/GaugeChart.svelte +113 -0
  30. package/dist/lib/components/extended/GaugeChart.svelte.d.ts +7 -0
  31. package/dist/lib/components/extended/HeatmapChart.svelte +159 -0
  32. package/dist/lib/components/extended/HeatmapChart.svelte.d.ts +7 -0
  33. package/dist/lib/components/extended/RadarChart.svelte +131 -0
  34. package/dist/lib/components/extended/RadarChart.svelte.d.ts +7 -0
  35. package/dist/lib/components/extended/SankeyChart.svelte +129 -0
  36. package/dist/lib/components/extended/SankeyChart.svelte.d.ts +7 -0
  37. package/dist/lib/components/extended/TreemapChart.svelte +133 -0
  38. package/dist/lib/components/extended/TreemapChart.svelte.d.ts +7 -0
  39. package/dist/lib/components/extended/index.d.ts +7 -0
  40. package/dist/lib/components/extended/index.js +7 -0
  41. package/dist/lib/components/index.d.ts +3 -0
  42. package/dist/lib/components/index.js +6 -0
  43. package/dist/lib/composables/index.d.ts +2 -0
  44. package/dist/lib/composables/index.js +2 -0
  45. package/dist/lib/composables/useChartTheme.svelte.d.ts +11 -0
  46. package/dist/lib/composables/useChartTheme.svelte.js +66 -0
  47. package/dist/lib/composables/useReducedMotion.svelte.d.ts +6 -0
  48. package/dist/lib/composables/useReducedMotion.svelte.js +26 -0
  49. package/dist/lib/index.d.ts +9 -0
  50. package/dist/lib/index.js +17 -0
  51. package/dist/lib/utils.d.ts +2 -0
  52. package/dist/lib/utils.js +5 -0
  53. package/package.json +45 -0
@@ -0,0 +1,63 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ import { cn } from '../../utils.js';
4
+ import ChartSkeleton from './ChartSkeleton.svelte';
5
+ import ChartError from './ChartError.svelte';
6
+ import ChartEmpty from './ChartEmpty.svelte';
7
+
8
+ interface Props {
9
+ title: string;
10
+ description?: string;
11
+ height?: number | string;
12
+ loading?: boolean;
13
+ error?: string | null;
14
+ empty?: boolean;
15
+ emptyMessage?: string;
16
+ onRetry?: () => void;
17
+ class?: string;
18
+ wrapperClass?: string;
19
+ children: Snippet;
20
+ }
21
+
22
+ let {
23
+ title,
24
+ description,
25
+ height = 400,
26
+ loading,
27
+ error,
28
+ empty,
29
+ emptyMessage,
30
+ onRetry,
31
+ class: className,
32
+ wrapperClass,
33
+ children,
34
+ }: Props = $props();
35
+
36
+ const heightStyle = $derived(typeof height === 'number' ? `${height}px` : height);
37
+ const descriptionId = $derived(
38
+ description ? `${title.replace(/\s+/g, '-').toLowerCase()}-desc` : undefined
39
+ );
40
+ </script>
41
+
42
+ {#if loading}
43
+ <ChartSkeleton {height} class={wrapperClass} />
44
+ {:else if error}
45
+ <ChartError message={error} {height} {onRetry} class={wrapperClass} />
46
+ {:else if empty}
47
+ <ChartEmpty message={emptyMessage} {height} class={wrapperClass} />
48
+ {:else}
49
+ <div
50
+ role="img"
51
+ aria-label={title}
52
+ aria-describedby={descriptionId}
53
+ data-testid="chart-container"
54
+ class={cn('rounded-lg border border-border bg-card', wrapperClass)}
55
+ >
56
+ {#if description}
57
+ <span id={descriptionId} class="sr-only">{description}</span>
58
+ {/if}
59
+ <div class={cn('h-full w-full', className)} style:height={heightStyle}>
60
+ {@render children()}
61
+ </div>
62
+ </div>
63
+ {/if}
@@ -0,0 +1,17 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ title: string;
4
+ description?: string;
5
+ height?: number | string;
6
+ loading?: boolean;
7
+ error?: string | null;
8
+ empty?: boolean;
9
+ emptyMessage?: string;
10
+ onRetry?: () => void;
11
+ class?: string;
12
+ wrapperClass?: string;
13
+ children: Snippet;
14
+ }
15
+ declare const ChartContainer: import("svelte").Component<Props, {}, "">;
16
+ type ChartContainer = ReturnType<typeof ChartContainer>;
17
+ export default ChartContainer;
@@ -0,0 +1,39 @@
1
+ <script lang="ts">
2
+ import { cn } from '../../utils.js';
3
+
4
+ interface Props {
5
+ message?: string;
6
+ height?: number | string;
7
+ class?: string;
8
+ }
9
+
10
+ let { message = 'No data available', height = 400, class: className }: Props = $props();
11
+
12
+ const heightStyle = $derived(typeof height === 'number' ? `${height}px` : height);
13
+ </script>
14
+
15
+ <div
16
+ data-testid="chart-empty"
17
+ class={cn(
18
+ 'flex flex-col items-center justify-center rounded-lg border border-border bg-muted/50',
19
+ className
20
+ )}
21
+ style:height={heightStyle}
22
+ >
23
+ <svg
24
+ class="mb-3 h-10 w-10 text-muted-foreground"
25
+ xmlns="http://www.w3.org/2000/svg"
26
+ fill="none"
27
+ viewBox="0 0 24 24"
28
+ stroke="currentColor"
29
+ aria-hidden="true"
30
+ >
31
+ <path
32
+ stroke-linecap="round"
33
+ stroke-linejoin="round"
34
+ stroke-width="1.5"
35
+ d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"
36
+ />
37
+ </svg>
38
+ <p class="text-sm text-muted-foreground">{message}</p>
39
+ </div>
@@ -0,0 +1,8 @@
1
+ interface Props {
2
+ message?: string;
3
+ height?: number | string;
4
+ class?: string;
5
+ }
6
+ declare const ChartEmpty: import("svelte").Component<Props, {}, "">;
7
+ type ChartEmpty = ReturnType<typeof ChartEmpty>;
8
+ export default ChartEmpty;
@@ -0,0 +1,49 @@
1
+ <script lang="ts">
2
+ import { cn } from '../../utils.js';
3
+
4
+ interface Props {
5
+ message: string;
6
+ height?: number | string;
7
+ onRetry?: () => void;
8
+ class?: string;
9
+ }
10
+
11
+ let { message, height = 400, onRetry, class: className }: Props = $props();
12
+
13
+ const heightStyle = $derived(typeof height === 'number' ? `${height}px` : height);
14
+ </script>
15
+
16
+ <div
17
+ data-testid="chart-error"
18
+ role="alert"
19
+ class={cn(
20
+ 'flex flex-col items-center justify-center rounded-lg border border-destructive/50 bg-destructive/10',
21
+ className
22
+ )}
23
+ style:height={heightStyle}
24
+ >
25
+ <svg
26
+ class="mb-3 h-10 w-10 text-destructive"
27
+ xmlns="http://www.w3.org/2000/svg"
28
+ fill="none"
29
+ viewBox="0 0 24 24"
30
+ stroke="currentColor"
31
+ aria-hidden="true"
32
+ >
33
+ <path
34
+ stroke-linecap="round"
35
+ stroke-linejoin="round"
36
+ stroke-width="2"
37
+ d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
38
+ />
39
+ </svg>
40
+ <p class="mb-2 text-sm font-medium text-destructive">{message}</p>
41
+ {#if onRetry}
42
+ <button
43
+ onclick={onRetry}
44
+ class="rounded-md bg-destructive px-3 py-1.5 text-xs font-medium text-destructive-foreground transition-colors hover:bg-destructive/90"
45
+ >
46
+ Retry
47
+ </button>
48
+ {/if}
49
+ </div>
@@ -0,0 +1,9 @@
1
+ interface Props {
2
+ message: string;
3
+ height?: number | string;
4
+ onRetry?: () => void;
5
+ class?: string;
6
+ }
7
+ declare const ChartError: import("svelte").Component<Props, {}, "">;
8
+ type ChartError = ReturnType<typeof ChartError>;
9
+ export default ChartError;
@@ -0,0 +1,37 @@
1
+ <script lang="ts">
2
+ import { cn } from '../../utils.js';
3
+
4
+ interface Props {
5
+ height?: number | string;
6
+ class?: string;
7
+ }
8
+
9
+ let { height = 400, class: className }: Props = $props();
10
+
11
+ const heightStyle = $derived(typeof height === 'number' ? `${height}px` : height);
12
+ </script>
13
+
14
+ <div
15
+ data-testid="chart-skeleton"
16
+ class={cn('animate-pulse rounded-lg border border-border bg-muted', className)}
17
+ style:height={heightStyle}
18
+ >
19
+ <div class="flex h-full flex-col p-4">
20
+ <!-- Title skeleton -->
21
+ <div class="mb-4 h-5 w-1/3 rounded bg-muted-foreground/20"></div>
22
+
23
+ <!-- Chart area skeleton -->
24
+ <div class="flex flex-1 items-end gap-2 px-4 pb-8">
25
+ {#each [40, 65, 45, 80, 55, 70, 50] as barHeight}
26
+ <div class="flex-1 rounded-t bg-muted-foreground/20" style:height="{barHeight}%"></div>
27
+ {/each}
28
+ </div>
29
+
30
+ <!-- X-axis skeleton -->
31
+ <div class="flex justify-between px-4">
32
+ {#each [1, 2, 3, 4, 5, 6, 7] as _}
33
+ <div class="h-3 w-8 rounded bg-muted-foreground/20"></div>
34
+ {/each}
35
+ </div>
36
+ </div>
37
+ </div>
@@ -0,0 +1,7 @@
1
+ interface Props {
2
+ height?: number | string;
3
+ class?: string;
4
+ }
5
+ declare const ChartSkeleton: import("svelte").Component<Props, {}, "">;
6
+ type ChartSkeleton = ReturnType<typeof ChartSkeleton>;
7
+ export default ChartSkeleton;
@@ -0,0 +1,4 @@
1
+ export { default as ChartContainer } from './ChartContainer.svelte';
2
+ export { default as ChartSkeleton } from './ChartSkeleton.svelte';
3
+ export { default as ChartError } from './ChartError.svelte';
4
+ export { default as ChartEmpty } from './ChartEmpty.svelte';
@@ -0,0 +1,4 @@
1
+ export { default as ChartContainer } from './ChartContainer.svelte';
2
+ export { default as ChartSkeleton } from './ChartSkeleton.svelte';
3
+ export { default as ChartError } from './ChartError.svelte';
4
+ export { default as ChartEmpty } from './ChartEmpty.svelte';
@@ -0,0 +1,198 @@
1
+ <script lang="ts">
2
+ import * as echarts from 'echarts/core';
3
+ import { LineChart as EChartsLineChart } from 'echarts/charts';
4
+ import {
5
+ GridComponent,
6
+ TooltipComponent,
7
+ LegendComponent,
8
+ TitleComponent,
9
+ } from 'echarts/components';
10
+ import { CanvasRenderer } from 'echarts/renderers';
11
+ import type { EChartsOption } from 'echarts';
12
+
13
+ import type { AreaChartProps, DataPointEventParams } from '@classic-homes/charts-core';
14
+
15
+ import { cn } from '../../utils.js';
16
+ import { useChartTheme } from '../../composables/useChartTheme.svelte.js';
17
+ import { useReducedMotion } from '../../composables/useReducedMotion.svelte.js';
18
+ import ChartContainer from '../base/ChartContainer.svelte';
19
+
20
+ // Register required ECharts modules
21
+ echarts.use([
22
+ EChartsLineChart,
23
+ GridComponent,
24
+ TooltipComponent,
25
+ LegendComponent,
26
+ TitleComponent,
27
+ CanvasRenderer,
28
+ ]);
29
+
30
+ interface Props extends Omit<AreaChartProps, 'class'> {
31
+ class?: string;
32
+ }
33
+
34
+ let {
35
+ title,
36
+ description,
37
+ data,
38
+ height = 400,
39
+ loading,
40
+ error,
41
+ emptyMessage,
42
+ theme = 'auto',
43
+ animation = true,
44
+ showLegend = true,
45
+ showTooltip = true,
46
+ showGrid = true,
47
+ smooth = false,
48
+ stacked = false,
49
+ gradient = true,
50
+ onClick,
51
+ class: className,
52
+ }: Props = $props();
53
+
54
+ let containerEl: HTMLDivElement | null = $state(null);
55
+ let chart: echarts.ECharts | null = null;
56
+
57
+ const chartTheme = useChartTheme(() => theme);
58
+ const reducedMotion = useReducedMotion();
59
+
60
+ const isEmpty = $derived(
61
+ !data?.categories?.length || !data?.series?.length || data.series.every((s) => !s.data?.length)
62
+ );
63
+
64
+ const option: EChartsOption = $derived.by(() => {
65
+ if (isEmpty) return {};
66
+
67
+ return {
68
+ grid: {
69
+ left: '3%',
70
+ right: '4%',
71
+ bottom: '3%',
72
+ containLabel: true,
73
+ },
74
+ tooltip: showTooltip
75
+ ? {
76
+ trigger: 'axis',
77
+ axisPointer: {
78
+ type: 'cross',
79
+ label: {
80
+ backgroundColor: '#6a7985',
81
+ },
82
+ },
83
+ }
84
+ : undefined,
85
+ legend: showLegend
86
+ ? {
87
+ data: data.series.map((s) => s.name),
88
+ bottom: 0,
89
+ }
90
+ : undefined,
91
+ xAxis: {
92
+ type: 'category',
93
+ boundaryGap: false,
94
+ data: data.categories,
95
+ },
96
+ yAxis: {
97
+ type: 'value',
98
+ splitLine: {
99
+ show: showGrid,
100
+ },
101
+ },
102
+ series: data.series.map((series, index) => ({
103
+ name: series.name,
104
+ type: 'line',
105
+ data: series.data,
106
+ smooth,
107
+ stack: stacked ? 'Total' : undefined,
108
+ areaStyle: gradient
109
+ ? {
110
+ opacity: 0.8,
111
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
112
+ {
113
+ offset: 0,
114
+ color:
115
+ series.color ||
116
+ `rgba(${60 + index * 40}, ${160 - index * 20}, ${180 - index * 30}, 0.8)`,
117
+ },
118
+ {
119
+ offset: 1,
120
+ color:
121
+ series.color ||
122
+ `rgba(${60 + index * 40}, ${160 - index * 20}, ${180 - index * 30}, 0.1)`,
123
+ },
124
+ ]),
125
+ }
126
+ : { opacity: 0.5 },
127
+ itemStyle: series.color ? { color: series.color } : undefined,
128
+ emphasis: {
129
+ focus: 'series',
130
+ },
131
+ showSymbol: false,
132
+ })),
133
+ animation: animation && !reducedMotion.value,
134
+ };
135
+ });
136
+
137
+ const accessibilityDescription = $derived(
138
+ description ||
139
+ (!isEmpty
140
+ ? `${title}. Area chart with ${data.categories.length} data points across ${data.series.length} series.`
141
+ : undefined)
142
+ );
143
+
144
+ // Initialize chart instance (only depends on container and theme)
145
+ $effect(() => {
146
+ if (!containerEl) return;
147
+
148
+ if (chart) {
149
+ chart.dispose();
150
+ }
151
+
152
+ chart = echarts.init(containerEl, chartTheme.theme);
153
+
154
+ if (onClick) {
155
+ chart.on('click', (params) => {
156
+ onClick({
157
+ type: params.type || 'click',
158
+ componentType: params.componentType || 'series',
159
+ seriesIndex: params.seriesIndex,
160
+ seriesName: params.seriesName || '',
161
+ dataIndex: params.dataIndex || 0,
162
+ name: params.name || '',
163
+ value: params.value as number,
164
+ color: params.color as string,
165
+ } as DataPointEventParams);
166
+ });
167
+ }
168
+
169
+ const handleResize = () => chart?.resize();
170
+ window.addEventListener('resize', handleResize);
171
+
172
+ return () => {
173
+ window.removeEventListener('resize', handleResize);
174
+ chart?.dispose();
175
+ chart = null;
176
+ };
177
+ });
178
+
179
+ // Update options when they change (handles both initial and subsequent updates)
180
+ $effect(() => {
181
+ if (chart && !isEmpty) {
182
+ chart.setOption(option, { notMerge: true, lazyUpdate: true });
183
+ }
184
+ });
185
+ </script>
186
+
187
+ <ChartContainer
188
+ {title}
189
+ description={accessibilityDescription}
190
+ {height}
191
+ {loading}
192
+ {error}
193
+ empty={isEmpty}
194
+ {emptyMessage}
195
+ class={cn(className)}
196
+ >
197
+ <div bind:this={containerEl} class="h-full w-full"></div>
198
+ </ChartContainer>
@@ -0,0 +1,7 @@
1
+ import type { AreaChartProps } from '@classic-homes/charts-core';
2
+ interface Props extends Omit<AreaChartProps, 'class'> {
3
+ class?: string;
4
+ }
5
+ declare const AreaChart: import("svelte").Component<Props, {}, "">;
6
+ type AreaChart = ReturnType<typeof AreaChart>;
7
+ export default AreaChart;
@@ -0,0 +1,186 @@
1
+ <script lang="ts">
2
+ import * as echarts from 'echarts/core';
3
+ import { BarChart as EChartsBarChart } from 'echarts/charts';
4
+ import {
5
+ GridComponent,
6
+ TooltipComponent,
7
+ LegendComponent,
8
+ TitleComponent,
9
+ } from 'echarts/components';
10
+ import { CanvasRenderer } from 'echarts/renderers';
11
+ import type { EChartsOption } from 'echarts';
12
+
13
+ import type { BarChartProps, DataPointEventParams } from '@classic-homes/charts-core';
14
+ import { generateBarChartDescription } from '@classic-homes/charts-core';
15
+
16
+ import { cn } from '../../utils.js';
17
+ import { useChartTheme } from '../../composables/useChartTheme.svelte.js';
18
+ import { useReducedMotion } from '../../composables/useReducedMotion.svelte.js';
19
+ import ChartContainer from '../base/ChartContainer.svelte';
20
+
21
+ // Register required ECharts modules
22
+ echarts.use([
23
+ EChartsBarChart,
24
+ GridComponent,
25
+ TooltipComponent,
26
+ LegendComponent,
27
+ TitleComponent,
28
+ CanvasRenderer,
29
+ ]);
30
+
31
+ interface Props extends Omit<BarChartProps, 'class'> {
32
+ class?: string;
33
+ }
34
+
35
+ let {
36
+ title,
37
+ description,
38
+ data,
39
+ height = 400,
40
+ loading,
41
+ error,
42
+ emptyMessage,
43
+ theme = 'auto',
44
+ animation = true,
45
+ showLegend = true,
46
+ showTooltip = true,
47
+ showGrid = true,
48
+ orientation = 'vertical',
49
+ stacked = false,
50
+ showValues = false,
51
+ onClick,
52
+ class: className,
53
+ }: Props = $props();
54
+
55
+ let containerEl: HTMLDivElement | null = $state(null);
56
+ let chart: echarts.ECharts | null = null;
57
+
58
+ const chartTheme = useChartTheme(() => theme);
59
+ const reducedMotion = useReducedMotion();
60
+
61
+ const isEmpty = $derived(
62
+ !data?.categories?.length || !data?.series?.length || data.series.every((s) => !s.data?.length)
63
+ );
64
+
65
+ const isHorizontal = $derived(orientation === 'horizontal');
66
+
67
+ const option: EChartsOption = $derived.by(() => {
68
+ if (isEmpty) return {};
69
+
70
+ const categoryAxis = {
71
+ type: 'category' as const,
72
+ data: data.categories,
73
+ axisTick: {
74
+ alignWithLabel: true,
75
+ },
76
+ };
77
+
78
+ const valueAxis = {
79
+ type: 'value' as const,
80
+ splitLine: {
81
+ show: showGrid,
82
+ },
83
+ };
84
+
85
+ return {
86
+ grid: {
87
+ left: '3%',
88
+ right: '4%',
89
+ bottom: '3%',
90
+ containLabel: true,
91
+ },
92
+ tooltip: showTooltip
93
+ ? {
94
+ trigger: 'axis',
95
+ axisPointer: {
96
+ type: 'shadow',
97
+ },
98
+ }
99
+ : undefined,
100
+ legend: showLegend
101
+ ? {
102
+ data: data.series.map((s) => s.name),
103
+ bottom: 0,
104
+ }
105
+ : undefined,
106
+ xAxis: isHorizontal ? valueAxis : categoryAxis,
107
+ yAxis: isHorizontal ? categoryAxis : valueAxis,
108
+ series: data.series.map((series) => ({
109
+ name: series.name,
110
+ type: 'bar',
111
+ data: series.data,
112
+ stack: stacked ? 'Total' : undefined,
113
+ itemStyle: series.color ? { color: series.color } : undefined,
114
+ label: showValues
115
+ ? {
116
+ show: true,
117
+ position: isHorizontal ? 'right' : 'top',
118
+ }
119
+ : undefined,
120
+ emphasis: {
121
+ focus: 'series',
122
+ },
123
+ })),
124
+ animation: animation && !reducedMotion.value,
125
+ };
126
+ });
127
+
128
+ const accessibilityDescription = $derived(
129
+ description || (!isEmpty ? generateBarChartDescription(title, data) : undefined)
130
+ );
131
+
132
+ // Initialize chart instance (only depends on container and theme)
133
+ $effect(() => {
134
+ if (!containerEl) return;
135
+
136
+ if (chart) {
137
+ chart.dispose();
138
+ }
139
+
140
+ chart = echarts.init(containerEl, chartTheme.theme);
141
+
142
+ if (onClick) {
143
+ chart.on('click', (params) => {
144
+ onClick({
145
+ type: params.type || 'click',
146
+ componentType: params.componentType || 'series',
147
+ seriesIndex: params.seriesIndex,
148
+ seriesName: params.seriesName || '',
149
+ dataIndex: params.dataIndex || 0,
150
+ name: params.name || '',
151
+ value: params.value as number,
152
+ color: params.color as string,
153
+ } as DataPointEventParams);
154
+ });
155
+ }
156
+
157
+ const handleResize = () => chart?.resize();
158
+ window.addEventListener('resize', handleResize);
159
+
160
+ return () => {
161
+ window.removeEventListener('resize', handleResize);
162
+ chart?.dispose();
163
+ chart = null;
164
+ };
165
+ });
166
+
167
+ // Update options when they change (handles both initial and subsequent updates)
168
+ $effect(() => {
169
+ if (chart && !isEmpty) {
170
+ chart.setOption(option, { notMerge: true, lazyUpdate: true });
171
+ }
172
+ });
173
+ </script>
174
+
175
+ <ChartContainer
176
+ {title}
177
+ description={accessibilityDescription}
178
+ {height}
179
+ {loading}
180
+ {error}
181
+ empty={isEmpty}
182
+ {emptyMessage}
183
+ class={cn(className)}
184
+ >
185
+ <div bind:this={containerEl} class="h-full w-full"></div>
186
+ </ChartContainer>
@@ -0,0 +1,7 @@
1
+ import type { BarChartProps } from '@classic-homes/charts-core';
2
+ interface Props extends Omit<BarChartProps, 'class'> {
3
+ class?: string;
4
+ }
5
+ declare const BarChart: import("svelte").Component<Props, {}, "">;
6
+ type BarChart = ReturnType<typeof BarChart>;
7
+ export default BarChart;