ui-svelte 0.2.3 → 0.2.5

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 (55) hide show
  1. package/dist/assets/country-flags.d.ts +1 -0
  2. package/dist/assets/country-flags.js +1612 -0
  3. package/dist/charts/ArcChart.svelte +291 -48
  4. package/dist/charts/ArcChart.svelte.d.ts +32 -1
  5. package/dist/charts/Candlestick.svelte +663 -115
  6. package/dist/charts/Candlestick.svelte.d.ts +40 -0
  7. package/dist/charts/css/arc-chart.css +76 -6
  8. package/dist/charts/css/candlestick.css +234 -11
  9. package/dist/control/Audio.svelte +8 -12
  10. package/dist/control/Button.svelte +3 -1
  11. package/dist/control/Button.svelte.d.ts +1 -0
  12. package/dist/control/IconButton.svelte +3 -1
  13. package/dist/control/IconButton.svelte.d.ts +1 -0
  14. package/dist/control/ToggleGroup.svelte +82 -0
  15. package/dist/control/ToggleGroup.svelte.d.ts +20 -0
  16. package/dist/control/css/btn.css +1 -1
  17. package/dist/control/css/toggle-group.css +85 -0
  18. package/dist/css/base.css +23 -15
  19. package/dist/css/utilities.css +45 -0
  20. package/dist/display/AvatarGroup.svelte +59 -0
  21. package/dist/display/AvatarGroup.svelte.d.ts +17 -0
  22. package/dist/display/Code.svelte +9 -2
  23. package/dist/display/Code.svelte.d.ts +1 -0
  24. package/dist/display/Section.svelte +1 -1
  25. package/dist/display/css/avatar-group.css +46 -0
  26. package/dist/display/css/avatar.css +1 -10
  27. package/dist/display/css/card.css +0 -10
  28. package/dist/form/ComboBox.svelte.d.ts +1 -1
  29. package/dist/form/PhoneField.svelte +8 -4
  30. package/dist/form/Select.svelte.d.ts +1 -1
  31. package/dist/index.css +43 -21
  32. package/dist/index.d.ts +3 -1
  33. package/dist/index.js +3 -1
  34. package/dist/layout/AppBar.svelte +28 -1
  35. package/dist/layout/AppBar.svelte.d.ts +2 -0
  36. package/dist/layout/Footer.svelte +25 -1
  37. package/dist/layout/Footer.svelte.d.ts +1 -0
  38. package/dist/layout/Sidebar.svelte +33 -3
  39. package/dist/layout/Sidebar.svelte.d.ts +1 -0
  40. package/dist/layout/css/app-bar.css +63 -0
  41. package/dist/layout/css/bottom-bar.css +63 -0
  42. package/dist/layout/css/footer.css +63 -0
  43. package/dist/layout/css/sidebar.css +63 -0
  44. package/dist/navigation/NavMenu.svelte +3 -9
  45. package/dist/navigation/SideNav.svelte +0 -9
  46. package/dist/navigation/SideNav.svelte.d.ts +0 -1
  47. package/dist/navigation/css/footer-group.css +3 -4
  48. package/dist/navigation/css/nav-menu.css +90 -30
  49. package/dist/navigation/css/side-nav.css +127 -66
  50. package/dist/overlay/css/modal.css +2 -2
  51. package/package.json +2 -2
  52. /package/dist/{form/js → assets}/countries.d.ts +0 -0
  53. /package/dist/{form/js → assets}/countries.js +0 -0
  54. /package/dist/{form/js → assets}/phone-examples.d.ts +0 -0
  55. /package/dist/{form/js → assets}/phone-examples.js +0 -0
@@ -1,14 +1,21 @@
1
1
  <script lang="ts">
2
2
  import { cn } from '../utils/class-names.js';
3
- import { onMount, untrack } from 'svelte';
3
+ import { onMount, untrack, type Snippet } from 'svelte';
4
4
 
5
5
  type Color = 'primary' | 'secondary' | 'success' | 'info' | 'warning' | 'danger' | 'muted';
6
+ type Size = 'sm' | 'md' | 'lg' | 'xl';
7
+ type LegendPosition = 'top' | 'right' | 'bottom' | 'left' | 'none';
8
+ type Linecap = 'round' | 'butt' | 'square';
9
+ type Palette = 'default' | 'rainbow' | 'ocean' | 'sunset' | 'forest' | 'neon';
6
10
 
7
11
  type ArcData = {
8
12
  value: number;
9
13
  max?: number;
10
- color: Color;
14
+ color?: Color;
15
+ gradient?: { from: string; to: string };
11
16
  label?: string;
17
+ unit?: string;
18
+ disabled?: boolean;
12
19
  };
13
20
 
14
21
  type Props = {
@@ -26,6 +33,23 @@
26
33
  showValues?: boolean;
27
34
  rootClass?: string;
28
35
  chartClass?: string;
36
+ size?: Size;
37
+ innerRadius?: number;
38
+ outerRadius?: number;
39
+ startAngle?: number;
40
+ endAngle?: number;
41
+ showGradient?: boolean;
42
+ showGlow?: boolean;
43
+ linecap?: Linecap;
44
+ palette?: Palette;
45
+ legendPosition?: LegendPosition;
46
+ valueFormatter?: (value: number) => string;
47
+ onClick?: (arc: ArcData, index: number) => void;
48
+ onHover?: (arc: ArcData | null, index: number) => void;
49
+ selected?: number[];
50
+ showInlineLabels?: boolean;
51
+ centerContent?: Snippet;
52
+ tooltipContent?: Snippet<[{ arc: ArcData; percentage: number }]>;
29
53
  };
30
54
 
31
55
  let {
@@ -42,10 +66,46 @@
42
66
  showLegend = true,
43
67
  showValues = true,
44
68
  rootClass,
45
- chartClass
69
+ chartClass,
70
+ size = 'md',
71
+ innerRadius,
72
+ outerRadius,
73
+ startAngle = -90,
74
+ endAngle = 270,
75
+ showGradient = false,
76
+ showGlow = false,
77
+ linecap = 'round',
78
+ palette,
79
+ legendPosition = 'right',
80
+ valueFormatter,
81
+ onClick,
82
+ onHover,
83
+ selected = [],
84
+ showInlineLabels = false,
85
+ centerContent,
86
+ tooltipContent
46
87
  }: Props = $props();
47
88
 
48
- const colorClass = {
89
+ const sizePresets: Record<
90
+ Size,
91
+ { height: number; thickness: number; labelSize: number; valueSize: number }
92
+ > = {
93
+ sm: { height: 150, thickness: 12, labelSize: 10, valueSize: 20 },
94
+ md: { height: 224, thickness: 16, labelSize: 14, valueSize: 32 },
95
+ lg: { height: 300, thickness: 20, labelSize: 16, valueSize: 40 },
96
+ xl: { height: 400, thickness: 24, labelSize: 18, valueSize: 48 }
97
+ };
98
+
99
+ const colorPalettes: Record<Palette, Color[]> = {
100
+ default: ['primary', 'secondary', 'success', 'info', 'warning', 'danger', 'muted'],
101
+ rainbow: ['danger', 'warning', 'success', 'info', 'primary', 'secondary', 'muted'],
102
+ ocean: ['info', 'primary', 'secondary', 'success', 'muted', 'warning', 'danger'],
103
+ sunset: ['warning', 'danger', 'secondary', 'primary', 'info', 'success', 'muted'],
104
+ forest: ['success', 'primary', 'info', 'secondary', 'muted', 'warning', 'danger'],
105
+ neon: ['secondary', 'primary', 'success', 'warning', 'danger', 'info', 'muted']
106
+ };
107
+
108
+ const colorClass: Record<Color, string> = {
49
109
  primary: 'is-primary',
50
110
  secondary: 'is-secondary',
51
111
  success: 'is-success',
@@ -55,50 +115,76 @@
55
115
  muted: 'is-muted'
56
116
  };
57
117
 
118
+ // Get arc color based on palette or individual color
119
+ function getArcColor(arc: ArcData, index: number): Color {
120
+ if (arc.color) return arc.color;
121
+ if (palette) {
122
+ const paletteColors = colorPalettes[palette];
123
+ return paletteColors[index % paletteColors.length];
124
+ }
125
+ return colorPalettes.default[index % colorPalettes.default.length];
126
+ }
127
+
128
+ function formatValue(value: number, unit?: string): string {
129
+ if (valueFormatter) return valueFormatter(value);
130
+ if (unit) return `${value}${unit}`;
131
+ return String(value);
132
+ }
133
+
58
134
  let containerEl: HTMLDivElement | undefined = $state();
135
+ // svelte-ignore state_referenced_locally
59
136
  let displayPercentages = $state<number[]>(data.map(() => 0));
60
137
  let animationFrameId: number | null = null;
61
138
 
62
- let tooltipData = $state<(ArcData & { percentage: number }) | null>(null);
139
+ let tooltipData = $state<(ArcData & { percentage: number; index: number }) | null>(null);
63
140
  let tooltipPosition = $state<{ x: number; y: number }>({ x: 0, y: 0 });
64
141
  let isTooltipActive = $state(false);
142
+ let hoveredIndex = $state<number | null>(null);
65
143
 
66
144
  let containerSize = $state({ width: 0, height: 0 });
145
+ let sizeConfig = $derived(sizePresets[size]);
146
+ let effectiveThickness = $derived(thickness || sizeConfig.thickness);
147
+ let effectiveHeight = $derived(sizeConfig.height);
148
+
67
149
  let width = $derived(containerSize.width);
68
150
  let height = $derived(containerSize.height);
69
- let size = $derived(Math.min(containerSize.width, containerSize.height));
70
- let viewBoxSize = $derived(size);
151
+ let viewBoxSize = $derived(
152
+ Math.min(containerSize.width, containerSize.height) || effectiveHeight
153
+ );
71
154
  let center = $derived(viewBoxSize / 2);
72
155
 
73
156
  let responsiveThickness = $derived(() => {
74
157
  const baseSize = 300;
75
- const scale = size / baseSize;
76
- return Math.max(8, Math.min(thickness * scale, thickness));
158
+ const scale = viewBoxSize / baseSize;
159
+ return Math.max(8, Math.min(effectiveThickness * scale, effectiveThickness));
77
160
  });
78
161
 
79
162
  let responsiveGap = $derived(() => {
80
163
  const baseSize = 300;
81
- const scale = size / baseSize;
164
+ const scale = viewBoxSize / baseSize;
82
165
  return Math.max(4, Math.min(gap * scale, gap));
83
166
  });
84
167
 
85
- let maxRadius = $derived(center - 20);
168
+ let maxRadius = $derived(outerRadius || center - 20);
86
169
 
87
170
  let responsiveLabelFontSize = $derived(() => {
88
171
  const baseSize = 300;
89
- const scale = size / baseSize;
90
- return Math.max(10, Math.min(14 * scale, 14));
172
+ const scale = viewBoxSize / baseSize;
173
+ return Math.max(10, Math.min(sizeConfig.labelSize * scale, sizeConfig.labelSize));
91
174
  });
92
175
 
93
176
  let responsiveValueFontSize = $derived(() => {
94
177
  const baseSize = 300;
95
- const scale = size / baseSize;
96
- return Math.max(16, Math.min(32 * scale, 32));
178
+ const scale = viewBoxSize / baseSize;
179
+ return Math.max(16, Math.min(sizeConfig.valueSize * scale, sizeConfig.valueSize));
97
180
  });
98
181
 
99
- let shouldShowText = $derived(size >= 120);
182
+ let shouldShowText = $derived(viewBoxSize >= 120);
100
183
 
101
- let computedCenterValue = $derived(centerValue || data.reduce((sum, arc) => sum + arc.value, 0));
184
+ let computedCenterValue = $derived(() => {
185
+ const val = centerValue || data.reduce((sum, arc) => sum + arc.value, 0);
186
+ return valueFormatter && typeof val === 'number' ? valueFormatter(val) : val;
187
+ });
102
188
 
103
189
  let totalMax = $derived(() => {
104
190
  if (data.length === 0) return 0;
@@ -108,6 +194,14 @@
108
194
  return data.reduce((sum, arc) => sum + (arc.max || arc.value), 0);
109
195
  });
110
196
 
197
+ // Arc angle calculations
198
+ let angleRange = $derived(endAngle - startAngle);
199
+
200
+ // Generate gradient IDs
201
+ let gradientIds = $derived(
202
+ data.map((_, i) => `arc-gradient-${i}-${Math.random().toString(36).slice(2, 9)}`)
203
+ );
204
+
111
205
  onMount(() => {
112
206
  const updateSize = () => {
113
207
  if (containerEl) {
@@ -116,17 +210,28 @@
116
210
  }
117
211
  };
118
212
 
213
+ const handleScroll = () => {
214
+ if (isTooltipActive) {
215
+ isTooltipActive = false;
216
+ hoveredIndex = null;
217
+ tooltipData = null;
218
+ }
219
+ };
220
+
119
221
  updateSize();
120
222
  const resizeObserver = new ResizeObserver(updateSize);
121
223
  if (containerEl) {
122
224
  resizeObserver.observe(containerEl);
123
225
  }
124
226
 
227
+ window.addEventListener('scroll', handleScroll, true);
228
+
125
229
  return () => {
126
230
  if (animationFrameId !== null) {
127
231
  cancelAnimationFrame(animationFrameId);
128
232
  }
129
233
  resizeObserver.disconnect();
234
+ window.removeEventListener('scroll', handleScroll, true);
130
235
  };
131
236
  });
132
237
 
@@ -152,7 +257,7 @@
152
257
  const easeProgress = 1 - Math.pow(1 - progress, 3);
153
258
 
154
259
  const newPercentages = startPercentages.map(
155
- (start, i) => start + (targetPercentages[i] - start) * easeProgress
260
+ (start, i) => start + ((targetPercentages[i] || 0) - start) * easeProgress
156
261
  );
157
262
 
158
263
  displayPercentages = newPercentages;
@@ -170,31 +275,86 @@
170
275
  }
171
276
  });
172
277
 
173
- function handleArcHover(arc: ArcData, percentage: number, event: MouseEvent): void {
278
+ function handleArcHover(
279
+ arc: ArcData,
280
+ percentage: number,
281
+ index: number,
282
+ event: MouseEvent
283
+ ): void {
174
284
  const target = event.target as SVGCircleElement;
175
285
  const rect = target.getBoundingClientRect();
176
286
 
177
287
  const max = data.length === 1 && arc.max !== undefined ? arc.max : totalMax();
178
288
 
179
- tooltipData = { ...arc, max, percentage: percentage * 100 };
289
+ tooltipData = { ...arc, max, percentage: percentage * 100, index };
180
290
  tooltipPosition = {
181
291
  x: rect.left + rect.width / 2,
182
292
  y: rect.top - 10
183
293
  };
184
294
  isTooltipActive = true;
295
+ hoveredIndex = index;
296
+
297
+ if (onHover) {
298
+ onHover(arc, index);
299
+ }
185
300
  }
186
301
 
187
302
  function handleArcLeave(): void {
188
303
  isTooltipActive = false;
304
+ hoveredIndex = null;
305
+
306
+ if (onHover) {
307
+ onHover(null, -1);
308
+ }
309
+
189
310
  setTimeout(() => {
190
311
  if (!isTooltipActive) {
191
312
  tooltipData = null;
192
313
  }
193
314
  }, 100);
194
315
  }
316
+
317
+ function handleArcClick(arc: ArcData, index: number): void {
318
+ if (onClick && !arc.disabled) {
319
+ onClick(arc, index);
320
+ }
321
+ }
322
+
323
+ function getArcMidpoint(radius: number, percentage: number): { x: number; y: number } {
324
+ const angle = startAngle + (angleRange * percentage) / 2;
325
+ const radians = (angle * Math.PI) / 180;
326
+ return {
327
+ x: center + radius * Math.cos(radians),
328
+ y: center + radius * Math.sin(radians)
329
+ };
330
+ }
331
+
332
+ let containerLayoutClass = $derived(() => {
333
+ switch (legendPosition) {
334
+ case 'top':
335
+ return 'flex-col-reverse';
336
+ case 'bottom':
337
+ return 'flex-col';
338
+ case 'left':
339
+ return 'flex-row-reverse';
340
+ case 'right':
341
+ default:
342
+ return 'flex-row';
343
+ }
344
+ });
345
+
346
+ let legendLayoutClass = $derived(() => {
347
+ switch (legendPosition) {
348
+ case 'top':
349
+ case 'bottom':
350
+ return 'flex-row flex-wrap';
351
+ default:
352
+ return 'flex-col';
353
+ }
354
+ });
195
355
  </script>
196
356
 
197
- <div class={cn('arc-chart-container', rootClass)}>
357
+ <div class={cn('arc-chart-container', `is-${size}`, containerLayoutClass(), rootClass)}>
198
358
  {#if loading}
199
359
  <div class="arc-chart-loading">
200
360
  <svg class="arc-chart-loading-spinner" viewBox="0 0 24 24">
@@ -218,43 +378,109 @@
218
378
  <span>{emptyText}</span>
219
379
  </div>
220
380
  {:else}
221
- <div bind:this={containerEl} class={cn('arc-chart', chartClass)}>
381
+ <div bind:this={containerEl} class={cn('arc-chart', `is-${size}`, chartClass)}>
222
382
  <svg class="arc-chart-svg" viewBox="0 0 {viewBoxSize} {viewBoxSize}">
383
+ {#if showGradient}
384
+ <defs>
385
+ {#each data as arc, i}
386
+ {@const color = getArcColor(arc, i)}
387
+ {#if arc.gradient}
388
+ <linearGradient id={gradientIds[i]} x1="0%" y1="0%" x2="100%" y2="0%">
389
+ <stop offset="0%" style="stop-color:{arc.gradient.from}" />
390
+ <stop offset="100%" style="stop-color:{arc.gradient.to}" />
391
+ </linearGradient>
392
+ {:else}
393
+ <linearGradient id={gradientIds[i]} x1="0%" y1="0%" x2="100%" y2="0%">
394
+ <stop offset="0%" style="stop-color:var(--color-{color})" />
395
+ <stop
396
+ offset="100%"
397
+ style="stop-color:var(--color-{color}-dark, var(--color-{color}))"
398
+ />
399
+ </linearGradient>
400
+ {/if}
401
+ {/each}
402
+ </defs>
403
+ {/if}
404
+
223
405
  {#each data as arc, i}
224
406
  {@const currentThickness = responsiveThickness()}
225
407
  {@const currentGap = responsiveGap()}
226
408
  {@const radius = maxRadius - i * (currentThickness + currentGap)}
227
- {@const percentage = displayPercentages[i]}
409
+ {@const percentage = displayPercentages[i] || 0}
228
410
  {@const circumference = 2 * Math.PI * radius}
229
- {@const strokeDashoffset = circumference * (1 - percentage)}
230
-
411
+ {@const arcLength = (circumference * angleRange) / 360}
412
+ {@const strokeDashoffset = arcLength * (1 - percentage)}
413
+ {@const color = getArcColor(arc, i)}
414
+ {@const isSelected = selected.includes(i)}
415
+ {@const isHovered = hoveredIndex === i}
416
+ {@const isDisabled = arc.disabled}
417
+
418
+ <!-- Background arc -->
231
419
  <circle
232
420
  cx={center}
233
421
  cy={center}
234
422
  r={radius}
235
423
  class="arc-chart-background"
236
424
  stroke-width={currentThickness}
425
+ stroke-linecap={linecap}
426
+ style="
427
+ transform: rotate({startAngle}deg);
428
+ transform-origin: center;
429
+ stroke-dasharray: {arcLength} {circumference};
430
+ "
237
431
  />
238
432
 
433
+ <!-- Active arc -->
239
434
  <!-- svelte-ignore a11y_no_static_element_interactions -->
435
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
240
436
  <circle
241
437
  cx={center}
242
438
  cy={center}
243
439
  r={radius}
244
- class="arc-chart-arc is-{arc.color}"
440
+ class={cn(
441
+ 'arc-chart-arc',
442
+ colorClass[color],
443
+ isSelected && 'is-selected',
444
+ showGlow && 'has-glow',
445
+ isHovered && 'is-hovered',
446
+ isDisabled && 'is-disabled'
447
+ )}
245
448
  stroke-width={currentThickness}
449
+ stroke-linecap={linecap}
246
450
  style="
247
- stroke-dasharray: {circumference};
451
+ stroke-dasharray: {arcLength};
248
452
  stroke-dashoffset: {strokeDashoffset};
249
- transform: rotate(-90deg);
453
+ transform: rotate({startAngle}deg);
250
454
  transform-origin: center;
455
+ {showGradient ? `stroke: url(#${gradientIds[i]});` : ''}
251
456
  "
252
- onmouseenter={(e) => handleArcHover(arc, percentage, e)}
457
+ onmouseenter={(e) => handleArcHover(arc, percentage, i, e)}
253
458
  onmouseleave={handleArcLeave}
459
+ onclick={() => handleArcClick(arc, i)}
254
460
  />
461
+
462
+ {#if showInlineLabels && arc.label && percentage > 0.1}
463
+ {@const midpoint = getArcMidpoint(radius, percentage)}
464
+ <text
465
+ x={midpoint.x}
466
+ y={midpoint.y}
467
+ class="arc-chart-inline-label"
468
+ text-anchor="middle"
469
+ dominant-baseline="middle"
470
+ style="font-size: {responsiveLabelFontSize() * 0.8}px;"
471
+ >
472
+ {arc.label}
473
+ </text>
474
+ {/if}
255
475
  {/each}
256
476
 
257
- {#if (centerText || computedCenterValue) && shouldShowText}
477
+ {#if centerContent}
478
+ <foreignObject x={center - 50} y={center - 30} width="100" height="60">
479
+ <div class="arc-chart-center-custom">
480
+ {@render centerContent()}
481
+ </div>
482
+ </foreignObject>
483
+ {:else if (centerText || computedCenterValue()) && shouldShowText}
258
484
  <text
259
485
  x={center}
260
486
  y={center - 10}
@@ -273,7 +499,7 @@
273
499
  dominant-baseline="middle"
274
500
  style="font-size: {responsiveValueFontSize()}px;"
275
501
  >
276
- {computedCenterValue}
502
+ {computedCenterValue()}
277
503
  </text>
278
504
  {/if}
279
505
  </svg>
@@ -284,32 +510,49 @@
284
510
  class="arc-chart-tooltip"
285
511
  style="left: {tooltipPosition.x}px; top: {tooltipPosition.y}px;"
286
512
  >
287
- <div class="arc-chart-tooltip-content">
288
- {#if tooltipData.label}
289
- <div class="arc-chart-tooltip-title">{tooltipData.label}</div>
290
- {/if}
291
- <div class="arc-chart-tooltip-row">
292
- <div class="arc-chart-tooltip-color is-{tooltipData.color}"></div>
293
- <span class="arc-chart-tooltip-value">
294
- {tooltipData.value} / {tooltipData.max} ({tooltipData.percentage.toFixed(1)}%)
295
- </span>
513
+ {#if tooltipContent}
514
+ {@render tooltipContent({ arc: tooltipData, percentage: tooltipData.percentage })}
515
+ {:else}
516
+ <div class="arc-chart-tooltip-content">
517
+ {#if tooltipData.label}
518
+ <div class="arc-chart-tooltip-title">{tooltipData.label}</div>
519
+ {/if}
520
+ <div class="arc-chart-tooltip-row">
521
+ <div
522
+ class="arc-chart-tooltip-color is-{getArcColor(tooltipData, tooltipData.index)}"
523
+ ></div>
524
+ <span class="arc-chart-tooltip-value">
525
+ {formatValue(tooltipData.value, tooltipData.unit)} / {formatValue(
526
+ tooltipData.max || 0,
527
+ tooltipData.unit
528
+ )} ({tooltipData.percentage.toFixed(1)}%)
529
+ </span>
530
+ </div>
296
531
  </div>
297
- </div>
532
+ {/if}
298
533
  </div>
299
534
  {/if}
300
535
 
301
- {#if showLegend}
302
- <div class="arc-chart-legend">
536
+ {#if showLegend && legendPosition !== 'none'}
537
+ <div class={cn('arc-chart-legend', legendLayoutClass())}>
303
538
  {#each data as arc, i}
304
- {@const percentage = displayPercentages[i]}
539
+ {@const percentage = displayPercentages[i] || 0}
540
+ {@const color = getArcColor(arc, i)}
305
541
  {@const max = data.length === 1 && arc.max !== undefined ? arc.max : totalMax()}
306
- <div class="arc-chart-legend-item">
307
- <div class={cn('arc-chart-legend-color', colorClass[arc.color])}></div>
542
+ {@const isSelected = selected.includes(i)}
543
+ <div
544
+ class={cn('arc-chart-legend-item', isSelected && 'is-selected')}
545
+ onclick={() => handleArcClick(arc, i)}
546
+ onkeydown={(e) => e.key === 'Enter' && handleArcClick(arc, i)}
547
+ role="button"
548
+ tabindex="0"
549
+ >
550
+ <div class={cn('arc-chart-legend-color', colorClass[color])}></div>
308
551
  <span>{arc.label || `Arc ${i + 1}`}</span>
309
552
  {#if showValues}
310
553
  <span class="arc-chart-legend-value">
311
- ({arc.value}{#if max}
312
- / {max}{/if})
554
+ ({formatValue(arc.value, arc.unit)}{#if max}
555
+ / {formatValue(max, arc.unit)}{/if})
313
556
  </span>
314
557
  {/if}
315
558
  </div>
@@ -1,9 +1,20 @@
1
+ import { type Snippet } from 'svelte';
1
2
  type Color = 'primary' | 'secondary' | 'success' | 'info' | 'warning' | 'danger' | 'muted';
3
+ type Size = 'sm' | 'md' | 'lg' | 'xl';
4
+ type LegendPosition = 'top' | 'right' | 'bottom' | 'left' | 'none';
5
+ type Linecap = 'round' | 'butt' | 'square';
6
+ type Palette = 'default' | 'rainbow' | 'ocean' | 'sunset' | 'forest' | 'neon';
2
7
  type ArcData = {
3
8
  value: number;
4
9
  max?: number;
5
- color: Color;
10
+ color?: Color;
11
+ gradient?: {
12
+ from: string;
13
+ to: string;
14
+ };
6
15
  label?: string;
16
+ unit?: string;
17
+ disabled?: boolean;
7
18
  };
8
19
  type Props = {
9
20
  data?: ArcData[];
@@ -20,6 +31,26 @@ type Props = {
20
31
  showValues?: boolean;
21
32
  rootClass?: string;
22
33
  chartClass?: string;
34
+ size?: Size;
35
+ innerRadius?: number;
36
+ outerRadius?: number;
37
+ startAngle?: number;
38
+ endAngle?: number;
39
+ showGradient?: boolean;
40
+ showGlow?: boolean;
41
+ linecap?: Linecap;
42
+ palette?: Palette;
43
+ legendPosition?: LegendPosition;
44
+ valueFormatter?: (value: number) => string;
45
+ onClick?: (arc: ArcData, index: number) => void;
46
+ onHover?: (arc: ArcData | null, index: number) => void;
47
+ selected?: number[];
48
+ showInlineLabels?: boolean;
49
+ centerContent?: Snippet;
50
+ tooltipContent?: Snippet<[{
51
+ arc: ArcData;
52
+ percentage: number;
53
+ }]>;
23
54
  };
24
55
  declare const ArcChart: import("svelte").Component<Props, {}, "">;
25
56
  type ArcChart = ReturnType<typeof ArcChart>;