@classic-homes/charts-svelte 0.1.38 → 0.2.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.
Files changed (36) hide show
  1. package/dist/lib/components/base/ChartContainer.svelte +47 -8
  2. package/dist/lib/components/base/ChartContainer.svelte.d.ts +8 -0
  3. package/dist/lib/components/base/ChartLegend.svelte +59 -0
  4. package/dist/lib/components/base/ChartLegend.svelte.d.ts +10 -0
  5. package/dist/lib/components/base/index.d.ts +3 -0
  6. package/dist/lib/components/base/index.js +1 -0
  7. package/dist/lib/components/core/AreaChart.svelte +121 -54
  8. package/dist/lib/components/core/AreaChart.svelte.d.ts +2 -1
  9. package/dist/lib/components/core/BarChart.svelte +91 -35
  10. package/dist/lib/components/core/BarChart.svelte.d.ts +2 -1
  11. package/dist/lib/components/core/DonutChart.svelte +152 -82
  12. package/dist/lib/components/core/DonutChart.svelte.d.ts +2 -1
  13. package/dist/lib/components/core/LineChart.svelte +114 -47
  14. package/dist/lib/components/core/LineChart.svelte.d.ts +2 -1
  15. package/dist/lib/components/core/PieChart.svelte +100 -38
  16. package/dist/lib/components/core/PieChart.svelte.d.ts +2 -1
  17. package/dist/lib/components/core/ScatterChart.svelte +102 -34
  18. package/dist/lib/components/core/ScatterChart.svelte.d.ts +2 -1
  19. package/dist/lib/components/extended/CandlestickChart.svelte +44 -22
  20. package/dist/lib/components/extended/FunnelChart.svelte +102 -33
  21. package/dist/lib/components/extended/FunnelChart.svelte.d.ts +2 -1
  22. package/dist/lib/components/extended/GaugeChart.svelte +59 -38
  23. package/dist/lib/components/extended/HeatmapChart.svelte +47 -27
  24. package/dist/lib/components/extended/RadarChart.svelte +76 -22
  25. package/dist/lib/components/extended/RadarChart.svelte.d.ts +2 -1
  26. package/dist/lib/components/extended/SankeyChart.svelte +50 -21
  27. package/dist/lib/components/extended/TreemapChart.svelte +68 -27
  28. package/dist/lib/components/index.d.ts +1 -1
  29. package/dist/lib/components/index.js +1 -1
  30. package/dist/lib/composables/index.d.ts +1 -0
  31. package/dist/lib/composables/index.js +1 -0
  32. package/dist/lib/composables/useChartLegend.svelte.d.ts +37 -0
  33. package/dist/lib/composables/useChartLegend.svelte.js +54 -0
  34. package/dist/lib/index.d.ts +3 -3
  35. package/dist/lib/index.js +2 -2
  36. package/package.json +1 -1
@@ -6,9 +6,24 @@
6
6
  import type { EChartsOption } from 'echarts';
7
7
 
8
8
  import type { FunnelChartProps, SliceEventParams } from '@classic-homes/charts-core';
9
+ import {
10
+ buildDataLabel,
11
+ buildLegend,
12
+ buildTooltip,
13
+ escapeHtml,
14
+ formatTooltipValue,
15
+ getChartColors,
16
+ itemLabelLookup,
17
+ mergeChartOption,
18
+ pointLabel,
19
+ } from '@classic-homes/charts-core';
9
20
 
10
21
  import { cn } from '../../utils.js';
11
22
  import { useChart } from '../../composables/useChart.svelte.js';
23
+ import {
24
+ useChartLegend,
25
+ type CustomLegendProps,
26
+ } from '../../composables/useChartLegend.svelte.js';
12
27
  import ChartContainer from '../base/ChartContainer.svelte';
13
28
 
14
29
  echarts.use([
@@ -19,7 +34,7 @@
19
34
  CanvasRenderer,
20
35
  ]);
21
36
 
22
- interface Props extends Omit<FunnelChartProps, 'class'> {
37
+ interface Props extends Omit<FunnelChartProps, 'class'>, CustomLegendProps {
23
38
  class?: string;
24
39
  }
25
40
 
@@ -38,6 +53,13 @@
38
53
  sort = 'descending',
39
54
  orientation = 'vertical',
40
55
  showLabels = true,
56
+ labelFormatter,
57
+ tooltipFormatter,
58
+ tooltipValueFormatter,
59
+ legend: legendConfig,
60
+ renderLegend,
61
+ onLegendChange,
62
+ option: optionOverride,
41
63
  onClick,
42
64
  class: className,
43
65
  }: Props = $props();
@@ -47,44 +69,84 @@
47
69
  const option: EChartsOption = $derived.by(() => {
48
70
  if (isEmpty) return {};
49
71
 
50
- return {
51
- tooltip: showTooltip ? { trigger: 'item', formatter: '{a} <br/>{b}: {c}' } : undefined,
52
- legend: showLegend ? { data: data.map((d) => d.name), bottom: 0 } : undefined,
53
- series: [
54
- {
55
- name: title,
56
- type: 'funnel',
57
- left: '10%',
58
- top: 60,
59
- bottom: 60,
60
- width: '80%',
61
- min: 0,
62
- // reduce, not Math.max(...): spreading large arrays overflows the stack
63
- max: data.reduce((m, d) => (d.value > m ? d.value : m), -Infinity),
64
- minSize: '0%',
65
- maxSize: '100%',
66
- sort,
67
- orient: orientation,
68
- gap: 2,
69
- label: showLabels
70
- ? { show: true, position: 'inside', formatter: '{b}: {c}' }
71
- : { show: false },
72
- labelLine: { show: false },
73
- emphasis: { label: { fontSize: 16 } },
74
- data: data.map((item) => ({
75
- name: item.name,
76
- value: item.value,
77
- itemStyle: item.color ? { color: item.color } : undefined,
78
- })),
79
- },
80
- ],
81
- };
72
+ const getLabel = itemLabelLookup(data);
73
+
74
+ return mergeChartOption(
75
+ {
76
+ tooltip: buildTooltip(
77
+ {
78
+ trigger: 'item',
79
+ // A string template ignores valueFormatter, so format the value here
80
+ formatter:
81
+ tooltipValueFormatter && !tooltipFormatter
82
+ ? (params: unknown) => {
83
+ const p = params as { seriesName?: string; name?: string; value?: unknown };
84
+ return `${escapeHtml(p.seriesName)} <br/>${escapeHtml(p.name)}: ${escapeHtml(formatTooltipValue(p.value, tooltipValueFormatter))}`;
85
+ }
86
+ : '{a} <br/>{b}: {c}',
87
+ },
88
+ {
89
+ show: showTooltip,
90
+ formatter: tooltipFormatter,
91
+ valueFormatter: tooltipValueFormatter,
92
+ getLabel,
93
+ }
94
+ ),
95
+ legend: buildLegend(
96
+ data.map((d) => d.name),
97
+ legendConfig,
98
+ { show: showLegend, custom: !!renderLegend }
99
+ ),
100
+ series: [
101
+ {
102
+ name: title,
103
+ type: 'funnel',
104
+ left: '10%',
105
+ top: 60,
106
+ bottom: 60,
107
+ width: '80%',
108
+ min: 0,
109
+ // reduce, not Math.max(...): spreading large arrays overflows the stack
110
+ max: data.reduce((m, d) => (d.value > m ? d.value : m), -Infinity),
111
+ minSize: '0%',
112
+ maxSize: '100%',
113
+ sort,
114
+ orient: orientation,
115
+ gap: 2,
116
+ label: buildDataLabel(
117
+ { show: true, position: 'inside', formatter: '{b}: {c}' },
118
+ { show: false },
119
+ { show: showLabels, formatter: labelFormatter, getLabel }
120
+ ),
121
+ labelLine: { show: false },
122
+ emphasis: { label: { fontSize: 16 } },
123
+ data: data.map((item) => ({
124
+ name: item.name,
125
+ value: item.value,
126
+ itemStyle: item.color ? { color: item.color } : undefined,
127
+ label: pointLabel(item.label, labelFormatter, { position: 'inside' }),
128
+ })),
129
+ },
130
+ ],
131
+ } as EChartsOption,
132
+ optionOverride
133
+ );
82
134
  });
83
135
 
84
136
  const accessibilityDescription = $derived(
85
137
  description || (!isEmpty ? `${title}. Funnel chart with ${data.length} stages.` : undefined)
86
138
  );
87
139
 
140
+ // Legend selection state, shared with a custom legend
141
+ const legend = useChartLegend({
142
+ names: () => data?.map((d) => d.name) ?? [],
143
+ colors: () => data?.map((d) => d.color) ?? [],
144
+ palette: () => getChartColors(chart.theme).series,
145
+ config: () => legendConfig,
146
+ title: () => title,
147
+ onLegendChange: () => onLegendChange,
148
+ });
149
+
88
150
  // Manage ECharts instance lifecycle (init, theme, resize, option updates)
89
151
  const chart = useChart({
90
152
  option: () => option,
@@ -92,6 +154,7 @@
92
154
  animation: () => animation,
93
155
  isEmpty: () => isEmpty,
94
156
  onReady: (instance) => {
157
+ legend.attach(instance);
95
158
  if (onClick) {
96
159
  instance.on('click', (params) => {
97
160
  onClick({
@@ -107,6 +170,10 @@
107
170
  });
108
171
  </script>
109
172
 
173
+ {#snippet customLegend()}
174
+ {@render renderLegend?.(legend.renderProps)}
175
+ {/snippet}
176
+
110
177
  <ChartContainer
111
178
  {title}
112
179
  description={accessibilityDescription}
@@ -116,6 +183,8 @@
116
183
  empty={isEmpty}
117
184
  {emptyMessage}
118
185
  class={cn(className)}
186
+ legend={renderLegend ? customLegend : undefined}
187
+ legendPosition={legendConfig?.position}
119
188
  >
120
189
  <div bind:this={chart.container} class="h-full w-full"></div>
121
190
  </ChartContainer>
@@ -1,5 +1,6 @@
1
1
  import type { FunnelChartProps } from '@classic-homes/charts-core';
2
- interface Props extends Omit<FunnelChartProps, 'class'> {
2
+ import { type CustomLegendProps } from '../../composables/useChartLegend.svelte.js';
3
+ interface Props extends Omit<FunnelChartProps, 'class'>, CustomLegendProps {
3
4
  class?: string;
4
5
  }
5
6
  declare const FunnelChart: import("svelte").Component<Props, {}, "">;
@@ -1,18 +1,18 @@
1
1
  <script lang="ts">
2
2
  import * as echarts from 'echarts/core';
3
3
  import { GaugeChart as EChartsGaugeChart } from 'echarts/charts';
4
- import { TitleComponent } from 'echarts/components';
4
+ import { TitleComponent, TooltipComponent } from 'echarts/components';
5
5
  import { CanvasRenderer } from 'echarts/renderers';
6
6
  import type { EChartsOption } from 'echarts';
7
7
 
8
8
  import type { GaugeChartProps } from '@classic-homes/charts-core';
9
- import { getChartColors } from '@classic-homes/charts-core';
9
+ import { buildTooltip, getChartColors, mergeChartOption } from '@classic-homes/charts-core';
10
10
 
11
11
  import { cn } from '../../utils.js';
12
12
  import { useChart } from '../../composables/useChart.svelte.js';
13
13
  import ChartContainer from '../base/ChartContainer.svelte';
14
14
 
15
- echarts.use([EChartsGaugeChart, TitleComponent, CanvasRenderer]);
15
+ echarts.use([EChartsGaugeChart, TitleComponent, TooltipComponent, CanvasRenderer]);
16
16
 
17
17
  interface Props extends Omit<GaugeChartProps, 'class'> {
18
18
  class?: string;
@@ -33,6 +33,10 @@
33
33
  splitNumber = 10,
34
34
  showProgress = true,
35
35
  formatValue,
36
+ showTooltip = true,
37
+ tooltipFormatter,
38
+ tooltipValueFormatter,
39
+ option: optionOverride,
36
40
  class: className,
37
41
  }: Props = $props();
38
42
 
@@ -46,42 +50,59 @@
46
50
  // Per-element colours that follow the resolved chart theme
47
51
  const chartColors = $derived.by(() => getChartColors(chart.theme));
48
52
 
49
- const option: EChartsOption = $derived({
50
- series: [
53
+ const option: EChartsOption = $derived.by(() =>
54
+ mergeChartOption(
51
55
  {
52
- type: 'gauge',
53
- center: ['50%', '60%'],
54
- radius: '80%',
55
- min,
56
- max,
57
- splitNumber,
58
- progress: showProgress ? { show: true, width: 18 } : undefined,
59
- axisLine: { lineStyle: { width: 18 } },
60
- axisTick: {
61
- distance: -30,
62
- splitNumber: 5,
63
- lineStyle: { width: 2, color: chartColors.mutedForeground },
64
- },
65
- splitLine: {
66
- distance: -32,
67
- length: 10,
68
- lineStyle: { width: 3, color: chartColors.mutedForeground },
69
- },
70
- axisLabel: { distance: -20, color: chartColors.mutedForeground, fontSize: 12 },
71
- anchor: { show: true, size: 20, itemStyle: { borderWidth: 2 } },
72
- pointer: { width: 6, length: '60%' },
73
- title: { show: true, offsetCenter: [0, '70%'], fontSize: 14 },
74
- detail: {
75
- valueAnimation: animation && !chart.reducedMotion,
76
- fontSize: 28,
77
- fontWeight: 'bold',
78
- offsetCenter: [0, '40%'],
79
- formatter: formatValue || '{value}',
80
- },
81
- data: [{ value, name: title }],
82
- },
83
- ],
84
- });
56
+ // No tooltip by default; one appears only when a formatter is set
57
+ tooltip:
58
+ tooltipFormatter || tooltipValueFormatter
59
+ ? buildTooltip(
60
+ { trigger: 'item' },
61
+ {
62
+ show: showTooltip,
63
+ formatter: tooltipFormatter,
64
+ valueFormatter: tooltipValueFormatter,
65
+ }
66
+ )
67
+ : undefined,
68
+ series: [
69
+ {
70
+ type: 'gauge',
71
+ center: ['50%', '60%'],
72
+ radius: '80%',
73
+ min,
74
+ max,
75
+ splitNumber,
76
+ progress: showProgress ? { show: true, width: 18 } : undefined,
77
+ axisLine: { lineStyle: { width: 18 } },
78
+ axisTick: {
79
+ distance: -30,
80
+ splitNumber: 5,
81
+ lineStyle: { width: 2, color: chartColors.mutedForeground },
82
+ },
83
+ splitLine: {
84
+ distance: -32,
85
+ length: 10,
86
+ lineStyle: { width: 3, color: chartColors.mutedForeground },
87
+ },
88
+ axisLabel: { distance: -20, color: chartColors.mutedForeground, fontSize: 12 },
89
+ anchor: { show: true, size: 20, itemStyle: { borderWidth: 2 } },
90
+ pointer: { width: 6, length: '60%' },
91
+ title: { show: true, offsetCenter: [0, '70%'], fontSize: 14 },
92
+ detail: {
93
+ valueAnimation: animation && !chart.reducedMotion,
94
+ fontSize: 28,
95
+ fontWeight: 'bold',
96
+ offsetCenter: [0, '40%'],
97
+ formatter: formatValue || '{value}',
98
+ },
99
+ data: [{ value, name: title }],
100
+ },
101
+ ],
102
+ } as EChartsOption,
103
+ optionOverride
104
+ )
105
+ );
85
106
 
86
107
  const accessibilityDescription = $derived(
87
108
  description || `${title}. Gauge showing value ${value} on scale from ${min} to ${max}.`
@@ -11,7 +11,14 @@
11
11
  import type { EChartsOption } from 'echarts';
12
12
 
13
13
  import type { HeatmapChartProps, HeatmapEventParams } from '@classic-homes/charts-core';
14
- import { escapeHtml } from '@classic-homes/charts-core';
14
+ import {
15
+ buildAxis,
16
+ buildDataLabel,
17
+ buildTooltip,
18
+ escapeHtml,
19
+ formatTooltipValue,
20
+ mergeChartOption,
21
+ } from '@classic-homes/charts-core';
15
22
 
16
23
  import { cn } from '../../utils.js';
17
24
  import { useChart } from '../../composables/useChart.svelte.js';
@@ -44,6 +51,12 @@
44
51
  animation = true,
45
52
  showTooltip = true,
46
53
  showValues = false,
54
+ labelFormatter,
55
+ xAxisConfig,
56
+ yAxisConfig,
57
+ tooltipFormatter,
58
+ tooltipValueFormatter,
59
+ option: optionOverride,
47
60
  onClick,
48
61
  class: className,
49
62
  }: Props = $props();
@@ -66,39 +79,46 @@
66
79
  const option: EChartsOption = $derived.by(() => {
67
80
  if (isEmpty) return {};
68
81
 
69
- return {
70
- tooltip: showTooltip
71
- ? {
82
+ return mergeChartOption(
83
+ {
84
+ tooltip: buildTooltip(
85
+ {
72
86
  position: 'top' as const,
73
87
  formatter: (params: unknown) => {
74
88
  const p = params as { value?: [number, number, number] };
75
89
  if (!p.value) return '';
76
90
  const [xIdx, yIdx, value] = p.value;
77
- return `${escapeHtml(xAxis[xIdx])} / ${escapeHtml(yAxis[yIdx])}: ${escapeHtml(value)}`;
91
+ return `${escapeHtml(xAxis[xIdx])} / ${escapeHtml(yAxis[yIdx])}: ${escapeHtml(formatTooltipValue(value, tooltipValueFormatter))}`;
78
92
  },
79
- }
80
- : undefined,
81
- grid: { left: '3%', right: '10%', bottom: '3%', containLabel: true },
82
- xAxis: { type: 'category', data: xAxis, splitArea: { show: true } },
83
- yAxis: { type: 'category', data: yAxis, splitArea: { show: true } },
84
- visualMap: {
85
- min: minValue,
86
- max: maxValue,
87
- calculable: true,
88
- orient: 'vertical',
89
- right: '0%',
90
- top: 'center',
91
- },
92
- series: [
93
- {
94
- name: title,
95
- type: 'heatmap',
96
- data: data.data,
97
- label: showValues ? { show: true } : undefined,
98
- emphasis: { itemStyle: { shadowBlur: 10, shadowColor: 'rgba(0, 0, 0, 0.5)' } },
93
+ },
94
+ { show: showTooltip, formatter: tooltipFormatter, valueFormatter: tooltipValueFormatter }
95
+ ),
96
+ grid: { left: '3%', right: '10%', bottom: '3%', containLabel: true },
97
+ xAxis: buildAxis({ type: 'category', data: xAxis, splitArea: { show: true } }, xAxisConfig),
98
+ yAxis: buildAxis({ type: 'category', data: yAxis, splitArea: { show: true } }, yAxisConfig),
99
+ visualMap: {
100
+ min: minValue,
101
+ max: maxValue,
102
+ calculable: true,
103
+ orient: 'vertical',
104
+ right: '0%',
105
+ top: 'center',
99
106
  },
100
- ],
101
- };
107
+ series: [
108
+ {
109
+ name: title,
110
+ type: 'heatmap',
111
+ data: data.data,
112
+ label: buildDataLabel({ show: true }, undefined, {
113
+ show: showValues,
114
+ formatter: labelFormatter,
115
+ }),
116
+ emphasis: { itemStyle: { shadowBlur: 10, shadowColor: 'rgba(0, 0, 0, 0.5)' } },
117
+ },
118
+ ],
119
+ } as EChartsOption,
120
+ optionOverride
121
+ );
102
122
  });
103
123
 
104
124
  const accessibilityDescription = $derived(
@@ -11,9 +11,21 @@
11
11
  import type { EChartsOption } from 'echarts';
12
12
 
13
13
  import type { RadarChartProps } from '@classic-homes/charts-core';
14
+ import {
15
+ buildDataLabel,
16
+ buildLegend,
17
+ buildTooltip,
18
+ getChartColors,
19
+ legendCenter,
20
+ mergeChartOption,
21
+ } from '@classic-homes/charts-core';
14
22
 
15
23
  import { cn } from '../../utils.js';
16
24
  import { useChart } from '../../composables/useChart.svelte.js';
25
+ import {
26
+ useChartLegend,
27
+ type CustomLegendProps,
28
+ } from '../../composables/useChartLegend.svelte.js';
17
29
  import ChartContainer from '../base/ChartContainer.svelte';
18
30
 
19
31
  echarts.use([
@@ -25,7 +37,7 @@
25
37
  CanvasRenderer,
26
38
  ]);
27
39
 
28
- interface Props extends Omit<RadarChartProps, 'class'> {
40
+ interface Props extends Omit<RadarChartProps, 'class'>, CustomLegendProps {
29
41
  class?: string;
30
42
  }
31
43
 
@@ -43,6 +55,14 @@
43
55
  showLegend = true,
44
56
  showTooltip = true,
45
57
  shape = 'polygon',
58
+ showLabels = false,
59
+ labelFormatter,
60
+ tooltipFormatter,
61
+ tooltipValueFormatter,
62
+ legend: legendConfig,
63
+ renderLegend,
64
+ onLegendChange,
65
+ option: optionOverride,
46
66
  class: className,
47
67
  }: Props = $props();
48
68
 
@@ -53,29 +73,44 @@
53
73
  const option: EChartsOption = $derived.by(() => {
54
74
  if (isEmpty) return {};
55
75
 
56
- return {
57
- tooltip: showTooltip ? { trigger: 'item' } : undefined,
58
- legend: showLegend ? { data: data.series.map((s) => s.name), bottom: 0 } : undefined,
59
- radar: {
60
- indicator: indicators.map((ind) => ({
61
- name: ind.name,
62
- max: ind.max,
63
- min: ind.min,
64
- })),
65
- shape,
66
- },
67
- series: [
68
- {
69
- type: 'radar',
70
- data: data.series.map((series) => ({
71
- name: series.name,
72
- value: series.data,
73
- itemStyle: series.color ? { color: series.color } : undefined,
74
- areaStyle: { opacity: 0.2 },
76
+ return mergeChartOption(
77
+ {
78
+ tooltip: buildTooltip(
79
+ { trigger: 'item' },
80
+ { show: showTooltip, formatter: tooltipFormatter, valueFormatter: tooltipValueFormatter }
81
+ ),
82
+ legend: buildLegend(
83
+ data.series.map((s) => s.name),
84
+ legendConfig,
85
+ { show: showLegend, custom: !!renderLegend }
86
+ ),
87
+ radar: {
88
+ center: legendCenter(legendConfig, showLegend && !renderLegend, ['50%', '50%']),
89
+ indicator: indicators.map((ind) => ({
90
+ name: ind.name,
91
+ max: ind.max,
92
+ min: ind.min,
75
93
  })),
94
+ shape,
76
95
  },
77
- ],
78
- };
96
+ series: [
97
+ {
98
+ type: 'radar',
99
+ label: buildDataLabel({ show: true }, undefined, {
100
+ show: showLabels,
101
+ formatter: labelFormatter,
102
+ }),
103
+ data: data.series.map((series) => ({
104
+ name: series.name,
105
+ value: series.data,
106
+ itemStyle: series.color ? { color: series.color } : undefined,
107
+ areaStyle: { opacity: 0.2 },
108
+ })),
109
+ },
110
+ ],
111
+ } as EChartsOption,
112
+ optionOverride
113
+ );
79
114
  });
80
115
 
81
116
  const accessibilityDescription = $derived(
@@ -85,15 +120,32 @@
85
120
  : undefined)
86
121
  );
87
122
 
123
+ // Legend selection state, shared with a custom legend
124
+ const legend = useChartLegend({
125
+ names: () => data?.series?.map((s) => s.name) ?? [],
126
+ colors: () => data?.series?.map((s) => s.color) ?? [],
127
+ palette: () => getChartColors(chart.theme).series,
128
+ config: () => legendConfig,
129
+ title: () => title,
130
+ onLegendChange: () => onLegendChange,
131
+ });
132
+
88
133
  // Manage ECharts instance lifecycle (init, theme, resize, option updates)
89
134
  const chart = useChart({
90
135
  option: () => option,
91
136
  theme: () => theme,
92
137
  animation: () => animation,
93
138
  isEmpty: () => isEmpty,
139
+ onReady: (instance) => {
140
+ legend.attach(instance);
141
+ },
94
142
  });
95
143
  </script>
96
144
 
145
+ {#snippet customLegend()}
146
+ {@render renderLegend?.(legend.renderProps)}
147
+ {/snippet}
148
+
97
149
  <ChartContainer
98
150
  {title}
99
151
  description={accessibilityDescription}
@@ -103,6 +155,8 @@
103
155
  empty={isEmpty}
104
156
  {emptyMessage}
105
157
  class={cn(className)}
158
+ legend={renderLegend ? customLegend : undefined}
159
+ legendPosition={legendConfig?.position}
106
160
  >
107
161
  <div bind:this={chart.container} class="h-full w-full"></div>
108
162
  </ChartContainer>
@@ -1,5 +1,6 @@
1
1
  import type { RadarChartProps } from '@classic-homes/charts-core';
2
- interface Props extends Omit<RadarChartProps, 'class'> {
2
+ import { type CustomLegendProps } from '../../composables/useChartLegend.svelte.js';
3
+ interface Props extends Omit<RadarChartProps, 'class'>, CustomLegendProps {
3
4
  class?: string;
4
5
  }
5
6
  declare const RadarChart: import("svelte").Component<Props, {}, "">;