@juspay/svelte-ui-components 2.31.0 → 2.32.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 (43) hide show
  1. package/dist/AreaChart/AreaChart.svelte +421 -0
  2. package/dist/AreaChart/AreaChart.svelte.d.ts +4 -0
  3. package/dist/AreaChart/properties.d.ts +62 -0
  4. package/dist/AreaChart/properties.js +1 -0
  5. package/dist/BarChart/BarChart.svelte +372 -0
  6. package/dist/BarChart/BarChart.svelte.d.ts +4 -0
  7. package/dist/BarChart/properties.d.ts +44 -0
  8. package/dist/BarChart/properties.js +1 -0
  9. package/dist/LineChart/LineChart.svelte +361 -0
  10. package/dist/LineChart/LineChart.svelte.d.ts +4 -0
  11. package/dist/LineChart/properties.d.ts +59 -0
  12. package/dist/LineChart/properties.js +1 -0
  13. package/dist/PieChart/PieChart.svelte +236 -0
  14. package/dist/PieChart/PieChart.svelte.d.ts +4 -0
  15. package/dist/PieChart/properties.d.ts +36 -0
  16. package/dist/PieChart/properties.js +1 -0
  17. package/dist/SankeyChart/SankeyChart.svelte +312 -0
  18. package/dist/SankeyChart/SankeyChart.svelte.d.ts +4 -0
  19. package/dist/SankeyChart/properties.d.ts +52 -0
  20. package/dist/SankeyChart/properties.js +1 -0
  21. package/dist/_chart/Axis.svelte +143 -0
  22. package/dist/_chart/Axis.svelte.d.ts +4 -0
  23. package/dist/_chart/ChartContainer.svelte +81 -0
  24. package/dist/_chart/ChartContainer.svelte.d.ts +4 -0
  25. package/dist/_chart/ChartTooltip.svelte +81 -0
  26. package/dist/_chart/ChartTooltip.svelte.d.ts +4 -0
  27. package/dist/_chart/Legend.svelte +59 -0
  28. package/dist/_chart/Legend.svelte.d.ts +4 -0
  29. package/dist/_chart/colors.d.ts +4 -0
  30. package/dist/_chart/colors.js +36 -0
  31. package/dist/_chart/format.d.ts +3 -0
  32. package/dist/_chart/format.js +28 -0
  33. package/dist/_chart/geometry.d.ts +24 -0
  34. package/dist/_chart/geometry.js +204 -0
  35. package/dist/_chart/paths.d.ts +4 -0
  36. package/dist/_chart/paths.js +138 -0
  37. package/dist/_chart/scales.d.ts +5 -0
  38. package/dist/_chart/scales.js +77 -0
  39. package/dist/_chart/types.d.ts +128 -0
  40. package/dist/_chart/types.js +1 -0
  41. package/dist/index.d.ts +10 -0
  42. package/dist/index.js +5 -0
  43. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,312 @@
1
+ <script lang="ts">
2
+ import type { SankeyChartProperties, SankeyTooltipContext } from './properties';
3
+ import ChartContainer from '../_chart/ChartContainer.svelte';
4
+ import ChartTooltip from '../_chart/ChartTooltip.svelte';
5
+ import { computeSankeyLayout } from '../_chart/geometry';
6
+ import { getColor } from '../_chart/colors';
7
+ import { formatNumber } from '../_chart/format';
8
+ import { SvelteSet } from 'svelte/reactivity';
9
+
10
+ // ── Props ──────────────────────────────────────────────────────
11
+
12
+ let {
13
+ nodes,
14
+ links,
15
+ nodeWidth = 16,
16
+ nodePadding = 8,
17
+ iterations = 6,
18
+ showValues = false,
19
+ showLabels = true,
20
+ aspectRatio = 16 / 9,
21
+ valueFormat,
22
+ tooltipSnippet,
23
+ empty,
24
+ onnodeclick,
25
+ onlinkclick,
26
+ onnodehover,
27
+ onlinkhover,
28
+ testId,
29
+ classes
30
+ }: SankeyChartProperties = $props();
31
+
32
+ // ── State ──────────────────────────────────────────────────────
33
+
34
+ let containerEl: HTMLDivElement | null = $state(null);
35
+ let chartWidth = $state(0);
36
+ let chartHeight = $state(0);
37
+ let hoveredNode = $state<string | null>(null);
38
+ let hoveredLink = $state<{ source: string; target: string } | null>(null);
39
+ let mouseX = $state(0);
40
+ let mouseY = $state(0);
41
+
42
+ // ── Layout ─────────────────────────────────────────────────────
43
+
44
+ let format = $derived(valueFormat ?? formatNumber);
45
+ let isEmpty = $derived(nodes.length === 0);
46
+ const MARGIN = 40;
47
+ let layout = $derived(
48
+ computeSankeyLayout(
49
+ nodes,
50
+ links,
51
+ Math.max(0, chartWidth - MARGIN * 2),
52
+ Math.max(0, chartHeight - MARGIN * 2),
53
+ nodeWidth,
54
+ nodePadding,
55
+ iterations
56
+ )
57
+ );
58
+
59
+ let connectedNodes = $derived.by(() => {
60
+ if (hoveredNode !== null) {
61
+ const connected = new SvelteSet<string>([hoveredNode]);
62
+ for (const l of links) {
63
+ if (l.source === hoveredNode || l.target === hoveredNode) {
64
+ connected.add(l.source);
65
+ connected.add(l.target);
66
+ }
67
+ }
68
+ return connected;
69
+ }
70
+ if (hoveredLink !== null) {
71
+ return new SvelteSet([hoveredLink.source, hoveredLink.target]);
72
+ }
73
+ return null;
74
+ });
75
+
76
+ // ── Tooltip ────────────────────────────────────────────────────
77
+
78
+ let tooltipData = $derived.by(() => {
79
+ if (hoveredNode !== null) {
80
+ const n = layout.nodes.find((nd) => nd.id === hoveredNode);
81
+ if (!n) {
82
+ return null;
83
+ }
84
+ return {
85
+ title: n.label,
86
+ items: [
87
+ {
88
+ label: 'Total flow',
89
+ value: format(n.value),
90
+ color: n.color ?? getColor(layout.nodes.indexOf(n))
91
+ }
92
+ ]
93
+ };
94
+ }
95
+ if (hoveredLink !== null) {
96
+ const l = links.find(
97
+ (lk) => lk.source === hoveredLink!.source && lk.target === hoveredLink!.target
98
+ );
99
+ if (!l) {
100
+ return null;
101
+ }
102
+ return {
103
+ title: `${nodes.find((n) => n.id === l.source)?.label ?? l.source} → ${nodes.find((n) => n.id === l.target)?.label ?? l.target}`,
104
+ items: [{ label: 'Flow', value: format(l.value) }]
105
+ };
106
+ }
107
+ return null;
108
+ });
109
+
110
+ let tooltipContext = $derived.by<SankeyTooltipContext | null>(() => {
111
+ if (hoveredNode !== null) {
112
+ const n = findNode(hoveredNode);
113
+ const computed = layout.nodes.find((nd) => nd.id === hoveredNode);
114
+ if (!n || !computed) {
115
+ return null;
116
+ }
117
+ return { type: 'node', node: n, value: computed.value };
118
+ }
119
+ if (hoveredLink !== null) {
120
+ const l = findLink(hoveredLink.source, hoveredLink.target);
121
+ if (!l) {
122
+ return null;
123
+ }
124
+ return { type: 'link', link: l };
125
+ }
126
+ return null;
127
+ });
128
+
129
+ // ── Interactions ───────────────────────────────────────────────
130
+
131
+ function trackMouse(e: MouseEvent) {
132
+ if (containerEl === null) {
133
+ return;
134
+ }
135
+ const rect = containerEl.getBoundingClientRect();
136
+ mouseX = e.clientX - rect.left;
137
+ mouseY = e.clientY - rect.top;
138
+ }
139
+
140
+ function isLinkHighlighted(source: string, target: string): boolean {
141
+ if (hoveredLink !== null) {
142
+ return source === hoveredLink.source && target === hoveredLink.target;
143
+ }
144
+ if (hoveredNode !== null) {
145
+ return source === hoveredNode || target === hoveredNode;
146
+ }
147
+ return false;
148
+ }
149
+
150
+ function findNode(id: string) {
151
+ return nodes.find((n) => n.id === id);
152
+ }
153
+
154
+ function findLink(source: string, target: string) {
155
+ return links.find((l) => l.source === source && l.target === target);
156
+ }
157
+
158
+ function handleNodeEnter(e: MouseEvent, id: string) {
159
+ hoveredNode = id;
160
+ trackMouse(e);
161
+ const orig = findNode(id);
162
+ if (orig) {
163
+ onnodehover?.({ node: orig });
164
+ }
165
+ }
166
+
167
+ function handleNodeLeave() {
168
+ hoveredNode = null;
169
+ onnodehover?.(null);
170
+ }
171
+
172
+ function handleNodeClick(id: string) {
173
+ const orig = findNode(id);
174
+ if (orig) {
175
+ onnodeclick?.({ node: orig });
176
+ }
177
+ }
178
+
179
+ function handleLinkEnter(e: MouseEvent, source: string, target: string) {
180
+ hoveredLink = { source, target };
181
+ trackMouse(e);
182
+ const orig = findLink(source, target);
183
+ if (orig) {
184
+ onlinkhover?.({ link: orig });
185
+ }
186
+ }
187
+
188
+ function handleLinkLeave() {
189
+ hoveredLink = null;
190
+ onlinkhover?.(null);
191
+ }
192
+
193
+ function handleLinkClick(source: string, target: string) {
194
+ const orig = findLink(source, target);
195
+ if (orig) {
196
+ onlinkclick?.({ link: orig });
197
+ }
198
+ }
199
+ </script>
200
+
201
+ <div
202
+ class="sankey-chart {classes ?? ''}"
203
+ bind:this={containerEl}
204
+ data-pw={typeof testId === 'string' ? testId : null}
205
+ >
206
+ {#if isEmpty && typeof empty === 'function'}
207
+ <div class="chart-empty">{@render empty()}</div>
208
+ {:else}
209
+ <ChartContainer bind:width={chartWidth} bind:height={chartHeight} {aspectRatio}>
210
+ <g transform="translate({MARGIN}, {MARGIN})">
211
+ {#each layout.links as link, i (i)}
212
+ {@const highlighted = isLinkHighlighted(link.source, link.target)}
213
+ {@const dimmed = (hoveredNode !== null || hoveredLink !== null) && !highlighted}
214
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
215
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
216
+ <path
217
+ class="sankey-link"
218
+ d={link.path}
219
+ fill="none"
220
+ stroke={link.color ?? getColor(layout.nodes.findIndex((n) => n.id === link.source))}
221
+ stroke-width={Math.max(1, link.width)}
222
+ stroke-opacity={highlighted ? 0.7 : dimmed ? 0.08 : 0.4}
223
+ onmouseenter={(e) => handleLinkEnter(e, link.source, link.target)}
224
+ onmousemove={trackMouse}
225
+ onmouseleave={handleLinkLeave}
226
+ onclick={() => handleLinkClick(link.source, link.target)}
227
+ />
228
+ {/each}
229
+
230
+ {#each layout.nodes as node, ni (ni)}
231
+ {@const color = node.color ?? getColor(ni)}
232
+ {@const dimmed = connectedNodes !== null && !connectedNodes.has(node.id)}
233
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
234
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
235
+ <rect
236
+ class="sankey-node"
237
+ class:node-dimmed={dimmed}
238
+ x={node.x}
239
+ y={node.y}
240
+ width={node.width}
241
+ height={node.height}
242
+ rx={2}
243
+ ry={2}
244
+ fill={color}
245
+ onmouseenter={(e) => handleNodeEnter(e, node.id)}
246
+ onmousemove={trackMouse}
247
+ onmouseleave={handleNodeLeave}
248
+ onclick={() => handleNodeClick(node.id)}
249
+ />
250
+ {#if showLabels}
251
+ <text
252
+ class="sankey-label"
253
+ class:node-dimmed={dimmed}
254
+ x={node.column === 0 ? node.x - 6 : node.x + node.width + 6}
255
+ y={node.y + node.height / 2}
256
+ text-anchor={node.column === 0 ? 'end' : 'start'}
257
+ dominant-baseline="middle"
258
+ >{node.label}{#if showValues}
259
+ ({format(node.value)}){/if}</text
260
+ >
261
+ {/if}
262
+ {/each}
263
+ </g>
264
+ </ChartContainer>
265
+
266
+ {#if typeof tooltipSnippet === 'function' && tooltipContext !== null}
267
+ <div class="chart-tooltip-slot" style="left: {mouseX + 12}px; top: {mouseY - 12}px;">
268
+ {@render tooltipSnippet(tooltipContext)}
269
+ </div>
270
+ {:else}
271
+ <ChartTooltip data={tooltipData} {mouseX} {mouseY} />
272
+ {/if}
273
+ {/if}
274
+ </div>
275
+
276
+ <style>
277
+ .sankey-chart {
278
+ width: 100%;
279
+ position: relative;
280
+ }
281
+ .sankey-link {
282
+ transition: stroke-opacity var(--chart-transition-duration, 0.2s) ease;
283
+ cursor: pointer;
284
+ }
285
+ .sankey-node {
286
+ transition: opacity var(--chart-transition-duration, 0.2s) ease;
287
+ cursor: pointer;
288
+ }
289
+ .sankey-node.node-dimmed {
290
+ opacity: var(--sankey-dimmed-opacity, 0.15);
291
+ }
292
+ .sankey-label {
293
+ fill: var(--sankey-label-color, #333);
294
+ font-size: var(--sankey-label-font-size, 12px);
295
+ font-family: var(--chart-font-family, inherit);
296
+ pointer-events: none;
297
+ transition: opacity var(--chart-transition-duration, 0.2s) ease;
298
+ }
299
+ .sankey-label.node-dimmed {
300
+ opacity: var(--sankey-dimmed-opacity, 0.15);
301
+ }
302
+ .chart-tooltip-slot {
303
+ position: absolute;
304
+ z-index: 10;
305
+ pointer-events: none;
306
+ }
307
+ .chart-empty {
308
+ padding: var(--chart-empty-padding, 32px 24px);
309
+ color: var(--chart-empty-color, #9ca3af);
310
+ text-align: center;
311
+ }
312
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { SankeyChartProperties } from './properties';
2
+ declare const SankeyChart: import("svelte").Component<SankeyChartProperties, {}, "">;
3
+ type SankeyChart = ReturnType<typeof SankeyChart>;
4
+ export default SankeyChart;
@@ -0,0 +1,52 @@
1
+ import type { Snippet } from 'svelte';
2
+ export type SankeyNode = {
3
+ id: string;
4
+ label?: string;
5
+ color?: string;
6
+ };
7
+ export type SankeyLink = {
8
+ source: string;
9
+ target: string;
10
+ value: number;
11
+ color?: string;
12
+ };
13
+ export type SankeyTooltipContext = {
14
+ type: 'node';
15
+ node: SankeyNode;
16
+ value: number;
17
+ } | {
18
+ type: 'link';
19
+ link: SankeyLink;
20
+ };
21
+ export type SankeyChartProperties = MandatorySankeyChartProperties & OptionalSankeyChartProperties & SankeyChartEventProperties;
22
+ export type MandatorySankeyChartProperties = {
23
+ nodes: SankeyNode[];
24
+ links: SankeyLink[];
25
+ };
26
+ export type OptionalSankeyChartProperties = {
27
+ nodeWidth?: number;
28
+ nodePadding?: number;
29
+ iterations?: number;
30
+ showValues?: boolean;
31
+ showLabels?: boolean;
32
+ aspectRatio?: number;
33
+ valueFormat?: (value: number) => string;
34
+ tooltipSnippet?: Snippet<[SankeyTooltipContext]>;
35
+ empty?: Snippet;
36
+ testId?: string;
37
+ classes?: string;
38
+ };
39
+ export type SankeyChartEventProperties = {
40
+ onnodeclick?: (event: {
41
+ node: SankeyNode;
42
+ }) => void;
43
+ onlinkclick?: (event: {
44
+ link: SankeyLink;
45
+ }) => void;
46
+ onnodehover?: (event: {
47
+ node: SankeyNode;
48
+ } | null) => void;
49
+ onlinkhover?: (event: {
50
+ link: SankeyLink;
51
+ } | null) => void;
52
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,143 @@
1
+ <script lang="ts">
2
+ import type { AxisProperties } from './types';
3
+ import { defaultTickFormat } from './format';
4
+
5
+ let {
6
+ orientation,
7
+ scale,
8
+ tickCount = 5,
9
+ tickFormat,
10
+ showGridlines = false,
11
+ gridlineLength = 0,
12
+ label,
13
+ classes
14
+ }: AxisProperties = $props();
15
+
16
+ let format = $derived(tickFormat ?? defaultTickFormat);
17
+
18
+ let isHorizontal = $derived(orientation === 'top' || orientation === 'bottom');
19
+
20
+ let tickValues = $derived.by(() => {
21
+ if ('ticks' in scale && typeof scale.ticks === 'function') {
22
+ return scale.ticks(tickCount);
23
+ }
24
+ if ('domain' in scale && Array.isArray(scale.domain)) {
25
+ return scale.domain;
26
+ }
27
+ return [];
28
+ });
29
+
30
+ let isBand = $derived('bandwidth' in scale);
31
+ let bandOffset = $derived(isBand && 'bandwidth' in scale ? scale.bandwidth / 2 : 0);
32
+
33
+ function positionTick(tick: number | string): number {
34
+ if ('bandwidth' in scale) {
35
+ return scale(String(tick)) + bandOffset;
36
+ }
37
+ return scale(Number(tick)) + bandOffset;
38
+ }
39
+
40
+ const TICK_SIZE = 6;
41
+ </script>
42
+
43
+ <g class="axis axis-{orientation} {classes ?? ''}">
44
+ {#if isHorizontal}
45
+ <line class="axis-line" x1={scale.range[0]} x2={scale.range[1]} y1={0} y2={0} />
46
+ {#each tickValues as tick, i (i)}
47
+ {@const x = positionTick(tick)}
48
+ <g class="tick" transform="translate({x}, 0)">
49
+ <line class="tick-mark" y2={orientation === 'bottom' ? TICK_SIZE : -TICK_SIZE} />
50
+ <text
51
+ class="tick-label"
52
+ y={orientation === 'bottom' ? TICK_SIZE + 4 : -(TICK_SIZE + 4)}
53
+ text-anchor="middle"
54
+ dominant-baseline={orientation === 'bottom' ? 'hanging' : 'auto'}
55
+ >
56
+ {format(tick)}
57
+ </text>
58
+ {#if showGridlines && gridlineLength > 0}
59
+ <line
60
+ class="gridline"
61
+ y1={0}
62
+ y2={orientation === 'bottom' ? -gridlineLength : gridlineLength}
63
+ />
64
+ {/if}
65
+ </g>
66
+ {/each}
67
+ {#if label}
68
+ <text
69
+ class="axis-label"
70
+ x={(scale.range[0] + scale.range[1]) / 2}
71
+ y={orientation === 'bottom' ? 36 : -30}
72
+ text-anchor="middle"
73
+ >
74
+ {label}
75
+ </text>
76
+ {/if}
77
+ {:else}
78
+ <line class="axis-line" y1={scale.range[0]} y2={scale.range[1]} x1={0} x2={0} />
79
+ {#each tickValues as tick, i (i)}
80
+ {@const y = positionTick(tick)}
81
+ <g class="tick" transform="translate(0, {y})">
82
+ <line class="tick-mark" x2={orientation === 'left' ? -TICK_SIZE : TICK_SIZE} />
83
+ <text
84
+ class="tick-label"
85
+ x={orientation === 'left' ? -(TICK_SIZE + 4) : TICK_SIZE + 4}
86
+ text-anchor={orientation === 'left' ? 'end' : 'start'}
87
+ dominant-baseline="middle"
88
+ >
89
+ {format(tick)}
90
+ </text>
91
+ {#if showGridlines && gridlineLength > 0}
92
+ <line
93
+ class="gridline"
94
+ x1={0}
95
+ x2={orientation === 'left' ? gridlineLength : -gridlineLength}
96
+ />
97
+ {/if}
98
+ </g>
99
+ {/each}
100
+ {#if label}
101
+ <text
102
+ class="axis-label"
103
+ transform="rotate(-90)"
104
+ x={-(scale.range[0] + scale.range[1]) / 2}
105
+ y={orientation === 'left' ? -40 : 40}
106
+ text-anchor="middle"
107
+ >
108
+ {label}
109
+ </text>
110
+ {/if}
111
+ {/if}
112
+ </g>
113
+
114
+ <style>
115
+ .axis-line {
116
+ stroke: var(--chart-axis-color, #666);
117
+ stroke-width: var(--chart-axis-stroke-width, 1);
118
+ }
119
+
120
+ .tick-mark {
121
+ stroke: var(--chart-axis-color, #666);
122
+ stroke-width: var(--chart-axis-stroke-width, 1);
123
+ }
124
+
125
+ .tick-label {
126
+ fill: var(--chart-axis-color, #666);
127
+ font-size: var(--chart-axis-font-size, 11px);
128
+ font-family: var(--chart-axis-font-family, inherit);
129
+ }
130
+
131
+ .axis-label {
132
+ fill: var(--chart-axis-label-color, #333);
133
+ font-size: var(--chart-axis-label-font-size, 12px);
134
+ font-family: var(--chart-axis-font-family, inherit);
135
+ font-weight: 500;
136
+ }
137
+
138
+ .gridline {
139
+ stroke: var(--chart-gridline-color, #e0e0e0);
140
+ stroke-opacity: var(--chart-gridline-opacity, 0.5);
141
+ stroke-dasharray: var(--chart-gridline-dash, 4 4);
142
+ }
143
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { AxisProperties } from './types';
2
+ declare const Axis: import("svelte").Component<AxisProperties, {}, "">;
3
+ type Axis = ReturnType<typeof Axis>;
4
+ export default Axis;
@@ -0,0 +1,81 @@
1
+ <script lang="ts">
2
+ import type { ChartContainerProperties } from './types';
3
+ import { onMount } from 'svelte';
4
+
5
+ let {
6
+ width = $bindable(0),
7
+ height = $bindable(0),
8
+ aspectRatio = 16 / 9,
9
+ minHeight = 0,
10
+ testId,
11
+ classes,
12
+ children
13
+ }: ChartContainerProperties = $props();
14
+
15
+ let containerEl: HTMLDivElement | null = $state(null);
16
+
17
+ onMount(() => {
18
+ if (containerEl === null) {
19
+ return;
20
+ }
21
+
22
+ function measure() {
23
+ if (containerEl === null) {
24
+ return;
25
+ }
26
+ const rect = containerEl.getBoundingClientRect();
27
+ const w = Math.round(rect.width);
28
+ width = w;
29
+ height = Math.max(minHeight, Math.round(w / aspectRatio));
30
+ }
31
+
32
+ measure();
33
+
34
+ // Coalesce bursts of resize events into a single measure per frame, always
35
+ // using the latest size (a leading-edge debounce would drop the final size).
36
+ let frame = 0;
37
+ const observer = new ResizeObserver(() => {
38
+ cancelAnimationFrame(frame);
39
+ frame = requestAnimationFrame(measure);
40
+ });
41
+ observer.observe(containerEl);
42
+
43
+ return () => {
44
+ cancelAnimationFrame(frame);
45
+ observer.disconnect();
46
+ };
47
+ });
48
+ </script>
49
+
50
+ <div
51
+ class="chart-container {classes ?? ''}"
52
+ bind:this={containerEl}
53
+ data-pw={typeof testId === 'string' ? testId : null}
54
+ >
55
+ {#if width > 0 && height > 0}
56
+ <svg
57
+ viewBox="0 0 {width} {height}"
58
+ preserveAspectRatio="xMidYMid meet"
59
+ role="img"
60
+ {width}
61
+ {height}
62
+ >
63
+ {@render children()}
64
+ </svg>
65
+ {/if}
66
+ </div>
67
+
68
+ <style>
69
+ .chart-container {
70
+ width: 100%;
71
+ background: var(--chart-background, transparent);
72
+ font-family: var(--chart-font-family, inherit);
73
+ }
74
+
75
+ svg {
76
+ display: block;
77
+ width: 100%;
78
+ height: auto;
79
+ overflow: visible;
80
+ }
81
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { ChartContainerProperties } from './types';
2
+ declare const ChartContainer: import("svelte").Component<ChartContainerProperties, {}, "width" | "height">;
3
+ type ChartContainer = ReturnType<typeof ChartContainer>;
4
+ export default ChartContainer;
@@ -0,0 +1,81 @@
1
+ <script lang="ts">
2
+ import type { ChartTooltipProperties } from './types';
3
+
4
+ let { data, mouseX = 0, mouseY = 0, customSnippet, classes }: ChartTooltipProperties = $props();
5
+ </script>
6
+
7
+ {#if data !== null}
8
+ <div class="chart-tooltip {classes ?? ''}" style="left: {mouseX + 12}px; top: {mouseY - 12}px;">
9
+ {#if typeof customSnippet === 'function'}
10
+ {@render customSnippet(data)}
11
+ {:else}
12
+ {#if data.title}
13
+ <div class="tooltip-title">{data.title}</div>
14
+ {/if}
15
+ {#each data.items as item, i (i)}
16
+ <div class="tooltip-item">
17
+ {#if item.color}
18
+ <span class="tooltip-swatch" style="background: {item.color}"></span>
19
+ {/if}
20
+ <span class="tooltip-label">{item.label}</span>
21
+ <span class="tooltip-value">{item.value}</span>
22
+ </div>
23
+ {/each}
24
+ {/if}
25
+ </div>
26
+ {/if}
27
+
28
+ <style>
29
+ .chart-tooltip {
30
+ position: absolute;
31
+ z-index: var(--chart-tooltip-z-index, 10);
32
+ background: var(--chart-tooltip-background, rgba(0, 0, 0, 0.85));
33
+ color: var(--chart-tooltip-color, #fff);
34
+ font-size: var(--chart-tooltip-font-size, 12px);
35
+ font-family: var(--chart-font-family, inherit);
36
+ padding: var(--chart-tooltip-padding, 8px 12px);
37
+ border-radius: var(--chart-tooltip-border-radius, 4px);
38
+ box-shadow: var(--chart-tooltip-shadow, 0 2px 8px rgba(0, 0, 0, 0.2));
39
+ pointer-events: none;
40
+ max-width: var(--chart-tooltip-max-width, 280px);
41
+ width: fit-content;
42
+ }
43
+
44
+ .tooltip-title {
45
+ font-weight: 600;
46
+ margin-bottom: 4px;
47
+ overflow: hidden;
48
+ text-overflow: ellipsis;
49
+ white-space: nowrap;
50
+ }
51
+
52
+ .tooltip-item {
53
+ display: flex;
54
+ align-items: center;
55
+ gap: 6px;
56
+ padding: 1px 0;
57
+ }
58
+
59
+ .tooltip-swatch {
60
+ display: inline-block;
61
+ width: 8px;
62
+ height: 8px;
63
+ border-radius: 2px;
64
+ flex-shrink: 0;
65
+ }
66
+
67
+ .tooltip-label {
68
+ opacity: 0.8;
69
+ overflow: hidden;
70
+ text-overflow: ellipsis;
71
+ white-space: nowrap;
72
+ min-width: 0;
73
+ }
74
+
75
+ .tooltip-value {
76
+ font-weight: 600;
77
+ margin-left: auto;
78
+ padding-left: 12px;
79
+ white-space: nowrap;
80
+ }
81
+ </style>
@@ -0,0 +1,4 @@
1
+ import type { ChartTooltipProperties } from './types';
2
+ declare const ChartTooltip: import("svelte").Component<ChartTooltipProperties, {}, "">;
3
+ type ChartTooltip = ReturnType<typeof ChartTooltip>;
4
+ export default ChartTooltip;