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,4 +1,10 @@
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 Theme = 'default' | 'tradingview' | 'dark' | 'light';
5
+ type CandleStyle = 'filled' | 'hollow' | 'heikinashi' | 'line' | 'area';
6
+ type ScaleType = 'linear' | 'log';
7
+ type GridStyle = 'solid' | 'dashed' | 'dotted' | 'none';
2
8
  type CandleData = {
3
9
  date: string | Date;
4
10
  open: number;
@@ -7,6 +13,20 @@ type CandleData = {
7
13
  close: number;
8
14
  volume?: number;
9
15
  };
16
+ type Indicator = {
17
+ type: 'sma';
18
+ period: number;
19
+ color?: Color;
20
+ } | {
21
+ type: 'ema';
22
+ period: number;
23
+ color?: Color;
24
+ } | {
25
+ type: 'bollinger';
26
+ period: number;
27
+ stdDev?: number;
28
+ color?: Color;
29
+ };
10
30
  type Margin = {
11
31
  top: number;
12
32
  right: number;
@@ -32,6 +52,26 @@ type Props = {
32
52
  maxVisibleCandles?: number;
33
53
  rootClass?: string;
34
54
  chartClass?: string;
55
+ size?: Size;
56
+ theme?: Theme;
57
+ candleStyle?: CandleStyle;
58
+ scaleType?: ScaleType;
59
+ showCrosshair?: boolean;
60
+ showYAxisLabels?: boolean;
61
+ showXAxisLabels?: boolean;
62
+ gridStyle?: GridStyle;
63
+ showLastPrice?: boolean;
64
+ indicators?: Indicator[];
65
+ onClick?: (candle: CandleData, index: number) => void;
66
+ onRangeChange?: (start: number, end: number) => void;
67
+ priceFormatter?: (value: number) => string;
68
+ dateFormatter?: (date: Date | string) => string;
69
+ animated?: boolean;
70
+ tooltipContent?: Snippet<[{
71
+ candle: CandleData;
72
+ change: number;
73
+ changePercent: number;
74
+ }]>;
35
75
  };
36
76
  declare const Candlestick: import("svelte").Component<Props, {}, "">;
37
77
  type Candlestick = ReturnType<typeof Candlestick>;
@@ -1,10 +1,42 @@
1
1
  @layer components {
2
2
  .arc-chart-container {
3
- @apply relative w-full flex flex-col md:flex-row justify-center items-center gap-4;
3
+ @apply relative w-full flex justify-center items-center gap-4;
4
+ }
5
+
6
+ .arc-chart-container.flex-row {
7
+ @apply flex-col md:flex-row;
8
+ }
9
+
10
+ .arc-chart-container.flex-row-reverse {
11
+ @apply flex-col-reverse md:flex-row-reverse;
12
+ }
13
+
14
+ .arc-chart-container.flex-col {
15
+ @apply flex-col;
16
+ }
17
+
18
+ .arc-chart-container.flex-col-reverse {
19
+ @apply flex-col-reverse;
4
20
  }
5
21
 
6
22
  .arc-chart {
7
- @apply relative flex items-center justify-center w-auto h-56;
23
+ @apply relative flex items-center justify-center w-auto;
24
+ }
25
+
26
+ .arc-chart.is-sm {
27
+ @apply h-[150px];
28
+ }
29
+
30
+ .arc-chart.is-md {
31
+ @apply h-56;
32
+ }
33
+
34
+ .arc-chart.is-lg {
35
+ @apply h-[300px];
36
+ }
37
+
38
+ .arc-chart.is-xl {
39
+ @apply h-[400px];
8
40
  }
9
41
 
10
42
  .arc-chart-svg {
@@ -14,20 +46,37 @@
14
46
  .arc-chart-background {
15
47
  @apply fill-none stroke-muted;
16
48
  stroke-opacity: 0.2;
17
- stroke-linecap: round;
18
49
  }
19
50
 
20
51
  .arc-chart-arc {
21
52
  @apply fill-none transition-all duration-200 ease-in-out cursor-pointer;
22
- stroke-linecap: round;
23
53
  }
24
54
 
25
- .arc-chart-arc:hover {
55
+ .arc-chart-arc:hover,
56
+ .arc-chart-arc.is-hovered {
26
57
  opacity: 0.8;
27
58
  transform: scale(1.02);
28
59
  transform-origin: center;
29
60
  }
30
61
 
62
+ .arc-chart-arc.is-selected {
63
+ stroke-width: calc(100% + 4px);
64
+ filter: brightness(1.1);
65
+ }
66
+
67
+ .arc-chart-arc.is-disabled {
68
+ opacity: 0.4;
69
+ cursor: not-allowed;
70
+ }
71
+
72
+ .arc-chart-arc.has-glow {
73
+ filter: drop-shadow(0 0 8px currentColor);
74
+ }
75
+
76
+ .arc-chart-arc.has-glow.is-selected {
77
+ filter: drop-shadow(0 0 12px currentColor) brightness(1.1);
78
+ }
79
+
31
80
  .arc-chart-arc.is-primary {
32
81
  @apply stroke-primary;
33
82
  }
@@ -97,10 +146,19 @@
97
146
  @apply fill-on-background opacity-70;
98
147
  }
99
148
 
149
+ .arc-chart-inline-label {
150
+ @apply fill-on-background font-medium;
151
+ pointer-events: none;
152
+ }
153
+
100
154
  .arc-chart-min-max {
101
155
  @apply fill-on-background;
102
156
  }
103
157
 
158
+ .arc-chart-center-custom {
159
+ @apply flex items-center justify-center w-full h-full text-center;
160
+ }
161
+
104
162
  .arc-chart-tooltip {
105
163
  position: fixed;
106
164
  pointer-events: none;
@@ -188,7 +246,15 @@
188
246
  }
189
247
 
190
248
  .arc-chart-legend {
191
- @apply flex flex-wrap md:flex-col gap-2 items-center justify-center text-sm text-on-muted text-nowrap;
249
+ @apply flex gap-2 items-center justify-center text-sm text-on-muted text-nowrap;
250
+ }
251
+
252
+ .arc-chart-legend.flex-col {
253
+ @apply flex-wrap md:flex-col;
254
+ }
255
+
256
+ .arc-chart-legend.flex-row {
257
+ @apply flex-row flex-wrap;
192
258
  }
193
259
 
194
260
  .arc-chart-legend-item {
@@ -199,6 +265,10 @@
199
265
  @apply opacity-80;
200
266
  }
201
267
 
268
+ .arc-chart-legend-item.is-selected {
269
+ @apply font-semibold;
270
+ }
271
+
202
272
  .arc-chart-legend-color {
203
273
  @apply w-3 h-3 rounded-sm;
204
274
  }
@@ -3,12 +3,68 @@
3
3
  @apply relative w-full h-full;
4
4
  }
5
5
 
6
+ .candlestick-chart-container.is-sm {
7
+ height: 200px;
8
+ }
9
+
10
+ .candlestick-chart-container.is-md {
11
+ height: 350px;
12
+ }
13
+
14
+ .candlestick-chart-container.is-lg {
15
+ height: 500px;
16
+ }
17
+
18
+ .candlestick-chart-container.is-xl {
19
+ height: 700px;
20
+ }
21
+
22
+ .candlestick-chart-container.theme-tradingview {
23
+ --chart-text: #d1d4dc;
24
+ --chart-grid: #363c4e;
25
+ }
26
+
27
+ .candlestick-chart-container.theme-dark {
28
+ --chart-text: #e0e0e0;
29
+ --chart-grid: #2d2d44;
30
+ }
31
+
32
+ .candlestick-chart-container.theme-light {
33
+ --chart-text: #333333;
34
+ --chart-grid: #e0e0e0;
35
+ }
36
+
6
37
  .candlestick-chart {
7
- @apply relative w-full h-56 text-on-muted;
38
+ @apply relative w-full h-full text-on-muted;
39
+ }
40
+
41
+ .candlestick-chart.is-sm {
42
+ height: 200px;
43
+ }
44
+
45
+ .candlestick-chart.is-md {
46
+ height: 350px;
47
+ }
48
+
49
+ .candlestick-chart.is-lg {
50
+ height: 500px;
51
+ }
52
+
53
+ .candlestick-chart.is-xl {
54
+ height: 700px;
8
55
  }
9
56
 
10
57
  .candlestick-chart-svg {
11
58
  @apply w-full h-full overflow-visible;
59
+ cursor: crosshair;
60
+ }
61
+
62
+ .candlestick-chart-svg:active {
63
+ cursor: grabbing;
64
+ }
65
+
66
+ .candlestick-chart-dragging {
67
+ cursor: grabbing !important;
12
68
  }
13
69
 
14
70
  .candlestick-chart-axis-line {
@@ -16,6 +72,11 @@
16
72
  stroke-width: 1;
17
73
  }
18
74
 
75
+ .theme-tradingview .candlestick-chart-axis-line,
76
+ .theme-dark .candlestick-chart-axis-line {
77
+ stroke: var(--chart-grid);
78
+ }
79
+
19
80
  .candlestick-chart-axis-label {
20
81
  @apply fill-on-muted text-xs;
21
82
  user-select: none;
@@ -24,21 +85,37 @@
24
85
  -ms-user-select: none;
25
86
  }
26
87
 
88
+ .theme-tradingview .candlestick-chart-axis-label,
89
+ .theme-dark .candlestick-chart-axis-label,
90
+ .theme-light .candlestick-chart-axis-label {
91
+ fill: var(--chart-text);
92
+ }
93
+
27
94
  .candlestick-chart-grid-line {
28
95
  @apply stroke-muted;
29
96
  stroke-opacity: 0.3;
30
97
  stroke-width: 1;
31
- stroke-dasharray: 2, 2;
98
+ }
99
+
100
+ .theme-tradingview .candlestick-chart-grid-line,
101
+ .theme-dark .candlestick-chart-grid-line {
102
+ stroke: var(--chart-grid);
103
+ stroke-opacity: 0.5;
32
104
  }
33
105
 
34
106
  .candlestick-chart-candle {
35
- @apply cursor-pointer;
107
+ @apply cursor-pointer transition-opacity duration-150;
36
108
  }
37
109
 
38
110
  .candlestick-chart-candle:hover {
39
111
  @apply opacity-80;
40
112
  }
41
113
 
114
+ .candlestick-chart-candle.is-hollow {
115
+ fill: transparent !important;
116
+ stroke-width: 1.5;
117
+ }
118
+
42
119
  .candlestick-chart-candle.is-primary {
43
120
  @apply fill-primary stroke-primary;
44
121
  }
@@ -127,6 +204,126 @@
127
204
  @apply fill-muted;
128
205
  }
129
206
 
207
+ .candlestick-chart-line.is-primary {
208
+ @apply stroke-primary;
209
+ }
210
+
211
+ .candlestick-chart-line.is-secondary {
212
+ @apply stroke-secondary;
213
+ }
214
+
215
+ .candlestick-chart-line.is-success {
216
+ @apply stroke-success;
217
+ }
218
+
219
+ .candlestick-chart-line.is-info {
220
+ @apply stroke-info;
221
+ }
222
+
223
+ .candlestick-chart-line.is-warning {
224
+ @apply stroke-warning;
225
+ }
226
+
227
+ .candlestick-chart-line.is-danger {
228
+ @apply stroke-danger;
229
+ }
230
+
231
+ .candlestick-chart-line.is-muted {
232
+ @apply stroke-muted;
233
+ }
234
+
235
+ .candlestick-chart-area {
236
+ @apply opacity-20;
237
+ }
238
+
239
+ .candlestick-chart-area.is-primary {
240
+ @apply fill-primary;
241
+ }
242
+
243
+ .candlestick-chart-area.is-secondary {
244
+ @apply fill-secondary;
245
+ }
246
+
247
+ .candlestick-chart-area.is-success {
248
+ @apply fill-success;
249
+ }
250
+
251
+ .candlestick-chart-area.is-info {
252
+ @apply fill-info;
253
+ }
254
+
255
+ .candlestick-chart-area.is-warning {
256
+ @apply fill-warning;
257
+ }
258
+
259
+ .candlestick-chart-area.is-danger {
260
+ @apply fill-danger;
261
+ }
262
+
263
+ .candlestick-chart-area.is-muted {
264
+ @apply fill-muted;
265
+ }
266
+
267
+ .candlestick-chart-indicator {
268
+ pointer-events: none;
269
+ }
270
+
271
+ .candlestick-chart-bollinger-band {
272
+ stroke-dasharray: 2, 2;
273
+ }
274
+
275
+ .candlestick-chart-last-price {
276
+ stroke-width: 1;
277
+ }
278
+
279
+ .candlestick-chart-last-price.is-success {
280
+ @apply stroke-success;
281
+ }
282
+
283
+ .candlestick-chart-last-price.is-danger {
284
+ @apply stroke-danger;
285
+ }
286
+
287
+ .candlestick-chart-last-price.is-primary {
288
+ @apply stroke-primary;
289
+ }
290
+
291
+ .candlestick-chart-last-price-label-bg {
292
+ @apply opacity-90;
293
+ }
294
+
295
+ .candlestick-chart-last-price-label-bg.is-success {
296
+ @apply fill-success;
297
+ }
298
+
299
+ .candlestick-chart-last-price-label-bg.is-danger {
300
+ @apply fill-danger;
301
+ }
302
+
303
+ .candlestick-chart-last-price-label-bg.is-primary {
304
+ @apply fill-primary;
305
+ }
306
+
307
+ .candlestick-chart-last-price-label {
308
+ @apply fill-on-primary font-semibold;
309
+ }
310
+
311
+ .candlestick-chart-crosshair {
312
+ @apply stroke-on-muted;
313
+ stroke-width: 1;
314
+ stroke-dasharray: 4, 4;
315
+ opacity: 0.7;
316
+ pointer-events: none;
317
+ }
318
+
319
+ .candlestick-chart-crosshair-label-bg {
320
+ @apply fill-on-muted opacity-90;
321
+ }
322
+
323
+ .candlestick-chart-crosshair-label {
324
+ @apply fill-muted font-medium;
325
+ }
326
+
130
327
  .candlestick-chart-tooltip {
131
328
  position: fixed;
132
329
  pointer-events: none;
@@ -162,6 +359,19 @@
162
359
  @apply font-semibold;
163
360
  }
164
361
 
362
+ .candlestick-chart-tooltip-value.is-bullish {
363
+ color: var(--color-success, #22c55e);
364
+ }
365
+
366
+ .candlestick-chart-tooltip-value.is-bearish {
367
+ color: var(--color-danger, #ef4444);
368
+ }
369
+
370
+ .candlestick-chart-tooltip-change {
371
+ @apply pt-1 mt-1;
372
+ border-top: 1px solid rgba(255, 255, 255, 0.2);
373
+ }
374
+
165
375
  .candlestick-chart-tooltip-volume {
166
376
  @apply pt-1 mt-1;
167
377
  border-top: 1px solid rgba(255, 255, 255, 0.2);
@@ -171,6 +381,27 @@
171
381
  @apply flex flex-col items-center justify-center h-full;
172
382
  }
173
383
 
384
+ .candlestick-chart-loading-skeleton {
385
+ @apply w-full h-full bg-muted opacity-20 rounded-md;
386
+ background: linear-gradient(
387
+ 90deg,
388
+ var(--color-muted) 25%,
389
+ var(--color-on-muted) 50%,
390
+ var(--color-muted) 75%
391
+ );
392
+ background-size: 200% 100%;
393
+ animation: candlestick-skeleton 1.5s ease-in-out infinite;
394
+ }
395
+
396
+ @keyframes candlestick-skeleton {
397
+ 0% {
398
+ background-position: 200% 0;
399
+ }
400
+ 100% {
401
+ background-position: -200% 0;
402
+ }
403
+ }
404
+
174
405
  .candlestick-chart-loading-icon {
175
406
  @apply h-12 w-auto text-primary;
176
407
  }
@@ -183,14 +414,6 @@
183
414
  @apply w-12 h-12 mb-2;
184
415
  }
185
416
 
186
- .candlestick-chart-dragging {
187
- cursor: grabbing !important;
188
- }
189
-
190
- .candlestick-chart-svg {
191
- cursor: grab;
192
- }
193
-
194
417
  .candlestick-chart-scrollbar {
195
418
  @apply relative w-full h-2 bg-muted rounded-full mt-2;
196
419
  }
@@ -194,18 +194,14 @@
194
194
  aria-valuemin="0"
195
195
  aria-valuemax="100"
196
196
  >
197
- {#if isAnalyzing}
198
- <div class="media-loading">Analizando...</div>
199
- {:else}
200
- <div class="media-bars">
201
- {#each waveformData as height, i}
202
- {@const progress = duration > 0 ? currentTime / duration : 0}
203
- {@const barPosition = (i + 0.5) / waveformData.length}
204
- {@const isPlayed = barPosition <= progress}
205
- <div class="media-bar" class:active={isPlayed} style="height: {height * 100}%"></div>
206
- {/each}
207
- </div>
208
- {/if}
197
+ <div class="media-bars">
198
+ {#each waveformData as height, i}
199
+ {@const progress = duration > 0 ? currentTime / duration : 0}
200
+ {@const barPosition = (i + 0.5) / waveformData.length}
201
+ {@const isPlayed = barPosition <= progress}
202
+ <div class="media-bar" class:active={isPlayed} style="height: {height * 100}%"></div>
203
+ {/each}
204
+ </div>
209
205
  </div>
210
206
 
211
207
  <span class="media-time">{duration > 0 ? formatTime(duration - currentTime) : '0:00'}</span>
@@ -9,6 +9,7 @@
9
9
  children: Snippet;
10
10
  onclick?: () => void;
11
11
  href?: string;
12
+ target?: '_self' | '_blank' | '_parent' | '_top';
12
13
  type?: 'button' | 'submit' | 'reset';
13
14
  variant?:
14
15
  | 'primary'
@@ -34,6 +35,7 @@
34
35
  children,
35
36
  onclick,
36
37
  href,
38
+ target,
37
39
  type = 'button',
38
40
  variant = 'primary',
39
41
  size = 'md',
@@ -89,7 +91,7 @@
89
91
  {/snippet}
90
92
 
91
93
  {#if href}
92
- <a class={baseClasses} {href}>
94
+ <a class={baseClasses} {href} {target}>
93
95
  {@render content()}
94
96
  </a>
95
97
  {:else}
@@ -4,6 +4,7 @@ type Props = {
4
4
  children: Snippet;
5
5
  onclick?: () => void;
6
6
  href?: string;
7
+ target?: '_self' | '_blank' | '_parent' | '_top';
7
8
  type?: 'button' | 'submit' | 'reset';
8
9
  variant?: 'primary' | 'secondary' | 'muted' | 'success' | 'info' | 'danger' | 'warning' | 'outlined' | 'ghost';
9
10
  size?: 'xs' | 'sm' | 'md' | 'lg';
@@ -7,6 +7,7 @@
7
7
  type Props = {
8
8
  onclick?: () => void;
9
9
  href?: string;
10
+ target?: '_self' | '_blank' | '_parent' | '_top';
10
11
  type?: 'button' | 'submit' | 'reset';
11
12
  variant?:
12
13
  | 'primary'
@@ -29,6 +30,7 @@
29
30
  const {
30
31
  onclick,
31
32
  href,
33
+ target,
32
34
  type = 'button',
33
35
  variant = 'primary',
34
36
  size = 'md',
@@ -76,7 +78,7 @@
76
78
  {/snippet}
77
79
 
78
80
  {#if href}
79
- <a class={baseClasses} {href}>
81
+ <a class={baseClasses} {href} {target}>
80
82
  {@render content()}
81
83
  </a>
82
84
  {:else}
@@ -2,6 +2,7 @@ import type { IconData } from '../display/Icon.svelte';
2
2
  type Props = {
3
3
  onclick?: () => void;
4
4
  href?: string;
5
+ target?: '_self' | '_blank' | '_parent' | '_top';
5
6
  type?: 'button' | 'submit' | 'reset';
6
7
  variant?: 'primary' | 'secondary' | 'muted' | 'success' | 'info' | 'danger' | 'warning' | 'outlined' | 'ghost';
7
8
  size?: 'xs' | 'sm' | 'md' | 'lg';
@@ -0,0 +1,82 @@
1
+ <script lang="ts">
2
+ import type { IconData } from '../display/Icon.svelte';
3
+ import { Icon } from '../index.js';
4
+ import { cn } from '../utils/class-names.js';
5
+
6
+ type ToggleGroupItem = {
7
+ id: string;
8
+ label: string;
9
+ icon?: IconData;
10
+ };
11
+
12
+ type Props = {
13
+ items: ToggleGroupItem[];
14
+ value?: string;
15
+ onchange?: (value: string) => void;
16
+ variant?: 'default' | 'primary' | 'secondary' | 'outlined';
17
+ size?: 'xs' | 'sm' | 'md' | 'lg';
18
+ class?: string;
19
+ isWide?: boolean;
20
+ isVertical?: boolean;
21
+ isDisabled?: boolean;
22
+ };
23
+
24
+ let {
25
+ items,
26
+ value = $bindable(items[0]?.id ?? ''),
27
+ onchange,
28
+ variant = 'default',
29
+ size = 'md',
30
+ class: className,
31
+ isWide,
32
+ isVertical,
33
+ isDisabled
34
+ }: Props = $props();
35
+
36
+ const variantClasses: Record<string, string> = {
37
+ default: '',
38
+ primary: 'is-primary',
39
+ secondary: 'is-secondary',
40
+ outlined: 'is-outlined'
41
+ };
42
+
43
+ const sizeClasses: Record<string, string> = {
44
+ xs: 'is-xs',
45
+ sm: 'is-sm',
46
+ md: 'is-md',
47
+ lg: 'is-lg'
48
+ };
49
+
50
+ let groupClasses = $derived(
51
+ cn(
52
+ 'toggle-group',
53
+ variantClasses[variant],
54
+ isWide && 'is-wide',
55
+ isVertical && 'is-vertical',
56
+ className
57
+ )
58
+ );
59
+
60
+ function handleClick(id: string) {
61
+ if (isDisabled) return;
62
+ value = id;
63
+ onchange?.(id);
64
+ }
65
+ </script>
66
+
67
+ <div class={groupClasses} role="group">
68
+ {#each items as item}
69
+ <button
70
+ type="button"
71
+ class={cn('toggle-group-item', sizeClasses[size], value === item.id && 'is-active')}
72
+ onclick={() => handleClick(item.id)}
73
+ disabled={isDisabled}
74
+ aria-pressed={value === item.id}
75
+ >
76
+ {#if item.icon}
77
+ <Icon icon={item.icon} />
78
+ {/if}
79
+ {item.label}
80
+ </button>
81
+ {/each}
82
+ </div>
@@ -0,0 +1,20 @@
1
+ import type { IconData } from '../display/Icon.svelte';
2
+ type ToggleGroupItem = {
3
+ id: string;
4
+ label: string;
5
+ icon?: IconData;
6
+ };
7
+ type Props = {
8
+ items: ToggleGroupItem[];
9
+ value?: string;
10
+ onchange?: (value: string) => void;
11
+ variant?: 'default' | 'primary' | 'secondary' | 'outlined';
12
+ size?: 'xs' | 'sm' | 'md' | 'lg';
13
+ class?: string;
14
+ isWide?: boolean;
15
+ isVertical?: boolean;
16
+ isDisabled?: boolean;
17
+ };
18
+ declare const ToggleGroup: import("svelte").Component<Props, {}, "value">;
19
+ type ToggleGroup = ReturnType<typeof ToggleGroup>;
20
+ export default ToggleGroup;
@@ -194,7 +194,7 @@
194
194
  }
195
195
 
196
196
  .btn-close {
197
- @apply absolute right-1 top-1;
197
+ @apply absolute right-2 top-2;
198
198
  }
199
199
  .btn-close-icon {
200
200
  @apply h-4 w-4 cursor-pointer;