@classic-homes/charts-svelte 0.1.35 → 0.1.37

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.
@@ -13,9 +13,7 @@
13
13
  import type { AreaChartProps, DataPointEventParams } from '@classic-homes/charts-core';
14
14
 
15
15
  import { cn } from '../../utils.js';
16
- import { useChartTheme } from '../../composables/useChartTheme.svelte.js';
17
- import { useReducedMotion } from '../../composables/useReducedMotion.svelte.js';
18
- import { useChartResize } from '../../composables/useChartResize.svelte.js';
16
+ import { useChart } from '../../composables/useChart.svelte.js';
19
17
  import ChartContainer from '../base/ChartContainer.svelte';
20
18
 
21
19
  // Register required ECharts modules
@@ -52,13 +50,6 @@
52
50
  class: className,
53
51
  }: Props = $props();
54
52
 
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
- const chartResize = useChartResize();
61
-
62
53
  const isEmpty = $derived(
63
54
  !data?.categories?.length || !data?.series?.length || data.series.every((s) => !s.data?.length)
64
55
  );
@@ -132,7 +123,6 @@
132
123
  },
133
124
  showSymbol: false,
134
125
  })),
135
- animation: animation && !reducedMotion.value,
136
126
  };
137
127
  });
138
128
 
@@ -143,46 +133,28 @@
143
133
  : undefined)
144
134
  );
145
135
 
146
- // Initialize chart instance (only depends on container and theme)
147
- $effect(() => {
148
- if (!containerEl) return;
149
-
150
- if (chart) {
151
- chart.dispose();
152
- }
153
-
154
- chart = echarts.init(containerEl, chartTheme.theme);
155
-
156
- if (onClick) {
157
- chart.on('click', (params) => {
158
- onClick({
159
- type: params.type || 'click',
160
- componentType: params.componentType || 'series',
161
- seriesIndex: params.seriesIndex,
162
- seriesName: params.seriesName || '',
163
- dataIndex: params.dataIndex || 0,
164
- name: params.name || '',
165
- value: params.value as number,
166
- color: params.color as string,
167
- } as DataPointEventParams);
168
- });
169
- }
170
-
171
- // Set up ResizeObserver for container-aware resizing
172
- chartResize.observe(containerEl, chart);
173
-
174
- return () => {
175
- chartResize.cleanup();
176
- chart?.dispose();
177
- chart = null;
178
- };
179
- });
180
-
181
- // Update options when they change (handles both initial and subsequent updates)
182
- $effect(() => {
183
- if (chart && !isEmpty) {
184
- chart.setOption(option, { notMerge: true, lazyUpdate: true });
185
- }
136
+ // Manage ECharts instance lifecycle (init, theme, resize, option updates)
137
+ const chart = useChart({
138
+ option: () => option,
139
+ theme: () => theme,
140
+ animation: () => animation,
141
+ isEmpty: () => isEmpty,
142
+ onReady: (instance) => {
143
+ if (onClick) {
144
+ instance.on('click', (params) => {
145
+ onClick({
146
+ type: params.type || 'click',
147
+ componentType: params.componentType || 'series',
148
+ seriesIndex: params.seriesIndex,
149
+ seriesName: params.seriesName || '',
150
+ dataIndex: params.dataIndex || 0,
151
+ name: params.name || '',
152
+ value: params.value as number,
153
+ color: params.color as string,
154
+ } as DataPointEventParams);
155
+ });
156
+ }
157
+ },
186
158
  });
187
159
  </script>
188
160
 
@@ -196,5 +168,5 @@
196
168
  {emptyMessage}
197
169
  class={cn(className)}
198
170
  >
199
- <div bind:this={containerEl} class="h-full w-full"></div>
171
+ <div bind:this={chart.container} class="h-full w-full"></div>
200
172
  </ChartContainer>
@@ -14,9 +14,7 @@
14
14
  import { generateBarChartDescription } from '@classic-homes/charts-core';
15
15
 
16
16
  import { cn } from '../../utils.js';
17
- import { useChartTheme } from '../../composables/useChartTheme.svelte.js';
18
- import { useReducedMotion } from '../../composables/useReducedMotion.svelte.js';
19
- import { useChartResize } from '../../composables/useChartResize.svelte.js';
17
+ import { useChart } from '../../composables/useChart.svelte.js';
20
18
  import ChartContainer from '../base/ChartContainer.svelte';
21
19
 
22
20
  // Register required ECharts modules
@@ -53,13 +51,6 @@
53
51
  class: className,
54
52
  }: Props = $props();
55
53
 
56
- let containerEl: HTMLDivElement | null = $state(null);
57
- let chart: echarts.ECharts | null = null;
58
-
59
- const chartTheme = useChartTheme(() => theme);
60
- const reducedMotion = useReducedMotion();
61
- const chartResize = useChartResize();
62
-
63
54
  const isEmpty = $derived(
64
55
  !data?.categories?.length || !data?.series?.length || data.series.every((s) => !s.data?.length)
65
56
  );
@@ -123,7 +114,6 @@
123
114
  focus: 'series',
124
115
  },
125
116
  })),
126
- animation: animation && !reducedMotion.value,
127
117
  };
128
118
  });
129
119
 
@@ -131,46 +121,28 @@
131
121
  description || (!isEmpty ? generateBarChartDescription(title, data) : undefined)
132
122
  );
133
123
 
134
- // Initialize chart instance (only depends on container and theme)
135
- $effect(() => {
136
- if (!containerEl) return;
137
-
138
- if (chart) {
139
- chart.dispose();
140
- }
141
-
142
- chart = echarts.init(containerEl, chartTheme.theme);
143
-
144
- if (onClick) {
145
- chart.on('click', (params) => {
146
- onClick({
147
- type: params.type || 'click',
148
- componentType: params.componentType || 'series',
149
- seriesIndex: params.seriesIndex,
150
- seriesName: params.seriesName || '',
151
- dataIndex: params.dataIndex || 0,
152
- name: params.name || '',
153
- value: params.value as number,
154
- color: params.color as string,
155
- } as DataPointEventParams);
156
- });
157
- }
158
-
159
- // Set up ResizeObserver for container-aware resizing
160
- chartResize.observe(containerEl, chart);
161
-
162
- return () => {
163
- chartResize.cleanup();
164
- chart?.dispose();
165
- chart = null;
166
- };
167
- });
168
-
169
- // Update options when they change (handles both initial and subsequent updates)
170
- $effect(() => {
171
- if (chart && !isEmpty) {
172
- chart.setOption(option, { notMerge: true, lazyUpdate: true });
173
- }
124
+ // Manage ECharts instance lifecycle (init, theme, resize, option updates)
125
+ const chart = useChart({
126
+ option: () => option,
127
+ theme: () => theme,
128
+ animation: () => animation,
129
+ isEmpty: () => isEmpty,
130
+ onReady: (instance) => {
131
+ if (onClick) {
132
+ instance.on('click', (params) => {
133
+ onClick({
134
+ type: params.type || 'click',
135
+ componentType: params.componentType || 'series',
136
+ seriesIndex: params.seriesIndex,
137
+ seriesName: params.seriesName || '',
138
+ dataIndex: params.dataIndex || 0,
139
+ name: params.name || '',
140
+ value: params.value as number,
141
+ color: params.color as string,
142
+ } as DataPointEventParams);
143
+ });
144
+ }
145
+ },
174
146
  });
175
147
  </script>
176
148
 
@@ -184,5 +156,5 @@
184
156
  {emptyMessage}
185
157
  class={cn(className)}
186
158
  >
187
- <div bind:this={containerEl} class="h-full w-full"></div>
159
+ <div bind:this={chart.container} class="h-full w-full"></div>
188
160
  </ChartContainer>
@@ -9,9 +9,7 @@
9
9
  import { generatePieChartDescription } from '@classic-homes/charts-core';
10
10
 
11
11
  import { cn } from '../../utils.js';
12
- import { useChartTheme } from '../../composables/useChartTheme.svelte.js';
13
- import { useReducedMotion } from '../../composables/useReducedMotion.svelte.js';
14
- import { useChartResize } from '../../composables/useChartResize.svelte.js';
12
+ import { useChart } from '../../composables/useChart.svelte.js';
15
13
  import ChartContainer from '../base/ChartContainer.svelte';
16
14
 
17
15
  // Register required ECharts modules
@@ -42,13 +40,6 @@
42
40
  class: className,
43
41
  }: Props = $props();
44
42
 
45
- let containerEl: HTMLDivElement | null = $state(null);
46
- let chart: echarts.ECharts | null = null;
47
-
48
- const chartTheme = useChartTheme(() => theme);
49
- const reducedMotion = useReducedMotion();
50
- const chartResize = useChartResize();
51
-
52
43
  const isEmpty = $derived(!data?.length);
53
44
 
54
45
  const option: EChartsOption = $derived.by(() => {
@@ -146,7 +137,6 @@
146
137
  },
147
138
  },
148
139
  ],
149
- animation: animation && !reducedMotion.value,
150
140
  };
151
141
  });
152
142
 
@@ -154,44 +144,26 @@
154
144
  description || (!isEmpty ? generatePieChartDescription(title, data, true) : undefined)
155
145
  );
156
146
 
157
- // Initialize chart instance (only depends on container and theme)
158
- $effect(() => {
159
- if (!containerEl) return;
160
-
161
- if (chart) {
162
- chart.dispose();
163
- }
164
-
165
- chart = echarts.init(containerEl, chartTheme.theme);
166
-
167
- if (onClick) {
168
- chart.on('click', (params) => {
169
- onClick({
170
- type: params.type || 'click',
171
- componentType: params.componentType || 'series',
172
- name: params.name || '',
173
- value: params.value as number,
174
- percent: params.percent,
175
- color: params.color as string,
176
- } as SliceEventParams);
177
- });
178
- }
179
-
180
- // Set up ResizeObserver for container-aware resizing
181
- chartResize.observe(containerEl, chart);
182
-
183
- return () => {
184
- chartResize.cleanup();
185
- chart?.dispose();
186
- chart = null;
187
- };
188
- });
189
-
190
- // Update options when they change (handles both initial and subsequent updates)
191
- $effect(() => {
192
- if (chart && !isEmpty) {
193
- chart.setOption(option, { notMerge: true, lazyUpdate: true });
194
- }
147
+ // Manage ECharts instance lifecycle (init, theme, resize, option updates)
148
+ const chart = useChart({
149
+ option: () => option,
150
+ theme: () => theme,
151
+ animation: () => animation,
152
+ isEmpty: () => isEmpty,
153
+ onReady: (instance) => {
154
+ if (onClick) {
155
+ instance.on('click', (params) => {
156
+ onClick({
157
+ type: params.type || 'click',
158
+ componentType: params.componentType || 'series',
159
+ name: params.name || '',
160
+ value: params.value as number,
161
+ percent: params.percent,
162
+ color: params.color as string,
163
+ } as SliceEventParams);
164
+ });
165
+ }
166
+ },
195
167
  });
196
168
  </script>
197
169
 
@@ -205,5 +177,5 @@
205
177
  {emptyMessage}
206
178
  class={cn(className)}
207
179
  >
208
- <div bind:this={containerEl} class="h-full w-full"></div>
180
+ <div bind:this={chart.container} class="h-full w-full"></div>
209
181
  </ChartContainer>
@@ -14,9 +14,7 @@
14
14
  import { generateLineChartDescription } from '@classic-homes/charts-core';
15
15
 
16
16
  import { cn } from '../../utils.js';
17
- import { useChartTheme } from '../../composables/useChartTheme.svelte.js';
18
- import { useReducedMotion } from '../../composables/useReducedMotion.svelte.js';
19
- import { useChartResize } from '../../composables/useChartResize.svelte.js';
17
+ import { useChart } from '../../composables/useChart.svelte.js';
20
18
  import ChartContainer from '../base/ChartContainer.svelte';
21
19
 
22
20
  // Register required ECharts modules
@@ -55,13 +53,6 @@
55
53
  class: className,
56
54
  }: Props = $props();
57
55
 
58
- let containerEl: HTMLDivElement | null = $state(null);
59
- let chart: echarts.ECharts | null = null;
60
-
61
- const chartTheme = useChartTheme(() => theme);
62
- const reducedMotion = useReducedMotion();
63
- const chartResize = useChartResize();
64
-
65
56
  const isEmpty = $derived(
66
57
  !data?.categories?.length || !data?.series?.length || data.series.every((s) => !s.data?.length)
67
58
  );
@@ -121,7 +112,6 @@
121
112
  focus: 'series',
122
113
  },
123
114
  })),
124
- animation: animation && !reducedMotion.value,
125
115
  };
126
116
  });
127
117
 
@@ -129,64 +119,43 @@
129
119
  description || (!isEmpty ? generateLineChartDescription(title, data) : undefined)
130
120
  );
131
121
 
132
- // Initialize chart instance (only depends on container and theme)
133
- $effect(() => {
134
- if (!containerEl) return;
135
-
136
- // Dispose existing chart if any
137
- if (chart) {
138
- chart.dispose();
139
- }
140
-
141
- // Create new chart instance
142
- chart = echarts.init(containerEl, chartTheme.theme);
143
-
144
- // Setup event handlers
145
- if (onClick) {
146
- chart.on('click', (params) => {
147
- onClick({
148
- type: params.type || 'click',
149
- componentType: params.componentType || 'series',
150
- seriesIndex: params.seriesIndex,
151
- seriesName: params.seriesName || '',
152
- dataIndex: params.dataIndex || 0,
153
- name: params.name || '',
154
- value: params.value as number,
155
- color: params.color as string,
156
- } as DataPointEventParams);
157
- });
158
- }
159
-
160
- if (onHover) {
161
- chart.on('mouseover', (params) => {
162
- onHover({
163
- type: params.type || 'mouseover',
164
- componentType: params.componentType || 'series',
165
- seriesIndex: params.seriesIndex,
166
- seriesName: params.seriesName || '',
167
- dataIndex: params.dataIndex || 0,
168
- name: params.name || '',
169
- value: params.value as number,
170
- color: params.color as string,
171
- } as DataPointEventParams);
172
- });
173
- }
174
-
175
- // Set up ResizeObserver for container-aware resizing
176
- chartResize.observe(containerEl, chart);
177
-
178
- return () => {
179
- chartResize.cleanup();
180
- chart?.dispose();
181
- chart = null;
182
- };
183
- });
184
-
185
- // Update options when they change (handles both initial and subsequent updates)
186
- $effect(() => {
187
- if (chart && !isEmpty) {
188
- chart.setOption(option, { notMerge: true, lazyUpdate: true });
189
- }
122
+ // Manage ECharts instance lifecycle (init, theme, resize, option updates)
123
+ const chart = useChart({
124
+ option: () => option,
125
+ theme: () => theme,
126
+ animation: () => animation,
127
+ isEmpty: () => isEmpty,
128
+ onReady: (instance) => {
129
+ if (onClick) {
130
+ instance.on('click', (params) => {
131
+ onClick({
132
+ type: params.type || 'click',
133
+ componentType: params.componentType || 'series',
134
+ seriesIndex: params.seriesIndex,
135
+ seriesName: params.seriesName || '',
136
+ dataIndex: params.dataIndex || 0,
137
+ name: params.name || '',
138
+ value: params.value as number,
139
+ color: params.color as string,
140
+ } as DataPointEventParams);
141
+ });
142
+ }
143
+
144
+ if (onHover) {
145
+ instance.on('mouseover', (params) => {
146
+ onHover({
147
+ type: params.type || 'mouseover',
148
+ componentType: params.componentType || 'series',
149
+ seriesIndex: params.seriesIndex,
150
+ seriesName: params.seriesName || '',
151
+ dataIndex: params.dataIndex || 0,
152
+ name: params.name || '',
153
+ value: params.value as number,
154
+ color: params.color as string,
155
+ } as DataPointEventParams);
156
+ });
157
+ }
158
+ },
190
159
  });
191
160
  </script>
192
161
 
@@ -200,5 +169,5 @@
200
169
  {emptyMessage}
201
170
  class={cn(className)}
202
171
  >
203
- <div bind:this={containerEl} class="h-full w-full"></div>
172
+ <div bind:this={chart.container} class="h-full w-full"></div>
204
173
  </ChartContainer>
@@ -9,9 +9,7 @@
9
9
  import { generatePieChartDescription } from '@classic-homes/charts-core';
10
10
 
11
11
  import { cn } from '../../utils.js';
12
- import { useChartTheme } from '../../composables/useChartTheme.svelte.js';
13
- import { useReducedMotion } from '../../composables/useReducedMotion.svelte.js';
14
- import { useChartResize } from '../../composables/useChartResize.svelte.js';
12
+ import { useChart } from '../../composables/useChart.svelte.js';
15
13
  import ChartContainer from '../base/ChartContainer.svelte';
16
14
 
17
15
  // Register required ECharts modules
@@ -40,13 +38,6 @@
40
38
  class: className,
41
39
  }: Props = $props();
42
40
 
43
- let containerEl: HTMLDivElement | null = $state(null);
44
- let chart: echarts.ECharts | null = null;
45
-
46
- const chartTheme = useChartTheme(() => theme);
47
- const reducedMotion = useReducedMotion();
48
- const chartResize = useChartResize();
49
-
50
41
  const isEmpty = $derived(!data?.length);
51
42
 
52
43
  const option: EChartsOption = $derived.by(() => {
@@ -95,7 +86,6 @@
95
86
  },
96
87
  },
97
88
  ],
98
- animation: animation && !reducedMotion.value,
99
89
  };
100
90
  });
101
91
 
@@ -103,44 +93,26 @@
103
93
  description || (!isEmpty ? generatePieChartDescription(title, data, false) : undefined)
104
94
  );
105
95
 
106
- // Initialize chart instance (only depends on container and theme)
107
- $effect(() => {
108
- if (!containerEl) return;
109
-
110
- if (chart) {
111
- chart.dispose();
112
- }
113
-
114
- chart = echarts.init(containerEl, chartTheme.theme);
115
-
116
- if (onClick) {
117
- chart.on('click', (params) => {
118
- onClick({
119
- type: params.type || 'click',
120
- componentType: params.componentType || 'series',
121
- name: params.name || '',
122
- value: params.value as number,
123
- percent: params.percent,
124
- color: params.color as string,
125
- } as SliceEventParams);
126
- });
127
- }
128
-
129
- // Set up ResizeObserver for container-aware resizing
130
- chartResize.observe(containerEl, chart);
131
-
132
- return () => {
133
- chartResize.cleanup();
134
- chart?.dispose();
135
- chart = null;
136
- };
137
- });
138
-
139
- // Update options when they change (handles both initial and subsequent updates)
140
- $effect(() => {
141
- if (chart && !isEmpty) {
142
- chart.setOption(option, { notMerge: true, lazyUpdate: true });
143
- }
96
+ // Manage ECharts instance lifecycle (init, theme, resize, option updates)
97
+ const chart = useChart({
98
+ option: () => option,
99
+ theme: () => theme,
100
+ animation: () => animation,
101
+ isEmpty: () => isEmpty,
102
+ onReady: (instance) => {
103
+ if (onClick) {
104
+ instance.on('click', (params) => {
105
+ onClick({
106
+ type: params.type || 'click',
107
+ componentType: params.componentType || 'series',
108
+ name: params.name || '',
109
+ value: params.value as number,
110
+ percent: params.percent,
111
+ color: params.color as string,
112
+ } as SliceEventParams);
113
+ });
114
+ }
115
+ },
144
116
  });
145
117
  </script>
146
118
 
@@ -154,5 +126,5 @@
154
126
  {emptyMessage}
155
127
  class={cn(className)}
156
128
  >
157
- <div bind:this={containerEl} class="h-full w-full"></div>
129
+ <div bind:this={chart.container} class="h-full w-full"></div>
158
130
  </ChartContainer>