seblify 0.2.1 → 0.3.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 (47) hide show
  1. package/README.md +118 -45
  2. package/dist/components/action/input/select/checkbox/Checkbox.svelte +378 -16
  3. package/dist/components/action/input/select/checkbox/Checkbox.svelte.d.ts +7 -0
  4. package/dist/components/action/input/select/checkbox/checkbox-relations.svelte.d.ts +47 -0
  5. package/dist/components/action/input/select/checkbox/checkbox-relations.svelte.js +154 -0
  6. package/dist/components/action/input/select/switch/Switch.svelte +349 -40
  7. package/dist/components/action/input/select/switch/Switch.svelte.d.ts +8 -3
  8. package/dist/components/display/annotation/tag/Tag.svelte +19 -0
  9. package/dist/components/display/data-display/metric/duration/Duration.svelte +64 -0
  10. package/dist/components/display/data-display/metric/duration/Duration.svelte.d.ts +16 -0
  11. package/dist/components/display/data-display/metric/relative-time/RelativeTime.svelte +104 -0
  12. package/dist/components/display/data-display/metric/relative-time/RelativeTime.svelte.d.ts +16 -0
  13. package/dist/components/display/data-display/visual/timeline/TimelineItem.svelte +19 -0
  14. package/dist/components/display/feedback/loading/loading-dots/LoadingDots.svelte +19 -0
  15. package/dist/components/display/feedback/loading/spinner/Spinner.svelte +19 -0
  16. package/dist/components/display/motion/collapse/Collapse.svelte +115 -0
  17. package/dist/components/display/motion/collapse/Collapse.svelte.d.ts +17 -0
  18. package/dist/components/display/typography/accordion/Accordion.svelte +347 -0
  19. package/dist/components/display/typography/accordion/Accordion.svelte.d.ts +13 -0
  20. package/dist/components/display/typography/accordion/AccordionGroup.svelte +132 -0
  21. package/dist/components/display/typography/accordion/AccordionGroup.svelte.d.ts +11 -0
  22. package/dist/components/display/typography/accordion/context.d.ts +8 -0
  23. package/dist/components/display/typography/accordion/context.js +8 -0
  24. package/dist/components/framework/overlay/tooltip/Tooltip.svelte +1012 -0
  25. package/dist/components/framework/overlay/tooltip/Tooltip.svelte.d.ts +31 -0
  26. package/dist/components/utility/format/duration/formatDuration.d.ts +15 -0
  27. package/dist/components/utility/format/duration/formatDuration.js +218 -0
  28. package/dist/components/utility/format/relative-time/formatRelativeTime.d.ts +35 -0
  29. package/dist/components/utility/format/relative-time/formatRelativeTime.js +343 -0
  30. package/dist/design-system/reserved-props/allowed-options.d.ts +6 -3
  31. package/dist/design-system/theme/tokens.js +48 -0
  32. package/dist/icons/generated/check-thick.svelte +16 -0
  33. package/dist/icons/generated/check-thick.svelte.d.ts +7 -0
  34. package/dist/icons/generated/check.svelte +16 -0
  35. package/dist/icons/generated/check.svelte.d.ts +7 -0
  36. package/dist/icons/generated/close-thick.svelte +16 -0
  37. package/dist/icons/generated/close-thick.svelte.d.ts +7 -0
  38. package/dist/icons/generated/close.svelte +16 -0
  39. package/dist/icons/generated/close.svelte.d.ts +7 -0
  40. package/dist/icons/generated/index.d.ts +4 -0
  41. package/dist/icons/generated/index.js +4 -0
  42. package/dist/icons/generated/manifest.js +28 -0
  43. package/dist/index.d.ts +9 -0
  44. package/dist/index.js +9 -0
  45. package/dist/styles/tone-context.css +19 -0
  46. package/dist/theme.css +22 -0
  47. package/package.json +15 -3
@@ -3,7 +3,8 @@
3
3
  import { CircleOutlineIcon, HandleGripIcon, MinusIcon } from 'seblify/icons';
4
4
 
5
5
  type SwitchRadius = 'none' | 'sm' | 'md' | 'lg' | 'full' | CustomCssSize;
6
- type SwitchAnimation = 'smooth' | 'snappy' | 'bouncy';
6
+ type SwitchAnimation = 'smooth' | 'bouncy';
7
+ type SwitchOrientation = 'horizontal' | 'vertical';
7
8
  type SwitchShape = 'pill' | 'floating' | 'line' | 'flat' | 'long';
8
9
  type SwitchSize =
9
10
  | 'xxs'
@@ -17,20 +18,25 @@
17
18
  type SwitchTone =
18
19
  | 'neutral'
19
20
  | 'primary'
21
+ | 'secondary'
20
22
  | 'success'
21
23
  | 'danger'
22
24
  | 'warning'
23
25
  | 'info'
24
26
  | 'inverse';
25
- type SwitchVariant = 'solid' | 'soft' | 'tint';
27
+ type SwitchVariant = 'solid' | 'soft' | 'tint' | 'outline';
26
28
 
27
29
  type Props = SeblifyProps<{
28
30
  animation?: SwitchAnimation;
31
+ ariaLabel?: string;
29
32
  checked?: boolean;
30
33
  description?: string;
31
34
  disabled?: boolean;
35
+ duration?: number;
36
+ focusTone?: SwitchTone;
32
37
  label?: string;
33
38
  name?: string;
39
+ orientation?: SwitchOrientation;
34
40
  radius?: SwitchRadius;
35
41
  shape?: SwitchShape;
36
42
  showGripIcon?: boolean;
@@ -80,13 +86,44 @@
80
86
  );
81
87
  }
82
88
 
89
+ function resolveDurationNumber(duration: number): number {
90
+ if (!Number.isFinite(duration)) {
91
+ return 0;
92
+ }
93
+
94
+ return Math.max(0, duration);
95
+ }
96
+
97
+ function resolveDurationValue(duration: number): string {
98
+ return `${resolveDurationNumber(duration)}ms`;
99
+ }
100
+
101
+ function supportsThumbGrip(shape: SwitchShape): boolean {
102
+ return shape === 'pill' || shape === 'floating' || shape === 'line';
103
+ }
104
+
105
+ function supportsTrackIcons(shape: SwitchShape): boolean {
106
+ return shape !== 'line';
107
+ }
108
+
109
+ function resolveGripIconSize(shape: SwitchShape): string {
110
+ return shape === 'floating' || shape === 'line' ? '1em' : '0.75em';
111
+ }
112
+
113
+ const BOUNCY_MOTION_CLEAR_BUFFER = 80;
114
+ const switchId = $props.id();
115
+
83
116
  let {
84
117
  checked = $bindable(false),
85
118
  animation = 'smooth',
119
+ ariaLabel,
86
120
  description,
87
121
  disabled = false,
122
+ duration = 190,
123
+ focusTone,
88
124
  label,
89
125
  name,
126
+ orientation = 'horizontal',
90
127
  radius = 'full',
91
128
  shape = 'pill',
92
129
  showGripIcon = false,
@@ -102,31 +139,56 @@
102
139
 
103
140
  const sizeValue = $derived(resolveSizeValue(size));
104
141
  const radiusValue = $derived(resolveRadiusValue(radius));
105
- const showThumbGrip = $derived(
106
- showGripIcon &&
107
- (shape === 'pill' || shape === 'floating' || shape === 'line'),
108
- );
109
- const showTrackIcons = $derived(showTrackIcon && shape !== 'line');
110
- const gripIconSize = $derived(
111
- shape === 'floating' || shape === 'line' ? '1em' : '0.75em',
142
+ const resolvedDuration = $derived(resolveDurationNumber(duration));
143
+ const durationValue = $derived(resolveDurationValue(duration));
144
+ const labelId = $derived(label ? `${switchId}-label` : undefined);
145
+ const descriptionId = $derived(
146
+ description ? `${switchId}-description` : undefined,
112
147
  );
148
+ const showContent = $derived(Boolean(label || description));
149
+ const showThumbGrip = $derived(showGripIcon && supportsThumbGrip(shape));
150
+ const showTrackIcons = $derived(showTrackIcon && supportsTrackIcons(shape));
151
+ const gripIconSize = $derived(resolveGripIconSize(shape));
113
152
  const onTrackIconSize = $derived(shape === 'pill' ? '0.95em' : '0.75em');
114
153
  const offTrackIconSize = $derived(shape === 'pill' ? '0.9em' : '0.7em');
115
154
 
116
155
  $effect(() => {
117
156
  const currentChecked = checked;
157
+ const canBounce = animation === 'bouncy' && resolvedDuration > 0;
118
158
 
119
159
  if (!hasMounted) {
120
160
  hasMounted = true;
121
161
  previousChecked = currentChecked;
162
+ bouncyMotion = 'none';
163
+ return;
164
+ }
165
+
166
+ if (!canBounce) {
167
+ previousChecked = currentChecked;
168
+ bouncyMotion = 'none';
122
169
  return;
123
170
  }
124
171
 
125
172
  if (currentChecked !== previousChecked) {
126
- bouncyMotion =
127
- animation === 'bouncy' ? (currentChecked ? 'to-on' : 'to-off') : 'none';
173
+ bouncyMotion = currentChecked ? 'to-on' : 'to-off';
128
174
  previousChecked = currentChecked;
129
175
  }
176
+
177
+ const activeMotion = bouncyMotion;
178
+
179
+ if (activeMotion === 'none') {
180
+ return;
181
+ }
182
+
183
+ const timeout = window.setTimeout(() => {
184
+ if (bouncyMotion === activeMotion) {
185
+ bouncyMotion = 'none';
186
+ }
187
+ }, resolvedDuration + BOUNCY_MOTION_CLEAR_BUFFER);
188
+
189
+ return () => {
190
+ window.clearTimeout(timeout);
191
+ };
130
192
  });
131
193
 
132
194
  function handleThumbAnimationEnd() {
@@ -141,13 +203,26 @@
141
203
  class="switch seblify-tone-context"
142
204
  data-animation={animation}
143
205
  data-bouncy-motion={bouncyMotion}
206
+ data-focus-tone={focusTone ?? tone ?? 'inherit'}
207
+ data-orientation={orientation}
144
208
  data-seblify-tone={tone ?? 'inherit'}
145
209
  data-shape={shape}
146
210
  data-variant={variant}
147
211
  style:--switch-size={sizeValue}
148
212
  style:--switch-radius={radiusValue}
213
+ style:--switch-duration={durationValue}
149
214
  >
150
- <input bind:checked {disabled} {name} role="switch" type="checkbox" {value} />
215
+ <input
216
+ aria-describedby={descriptionId}
217
+ aria-label={labelId ? undefined : ariaLabel}
218
+ aria-labelledby={labelId}
219
+ bind:checked
220
+ {disabled}
221
+ {name}
222
+ role="switch"
223
+ type="checkbox"
224
+ {value}
225
+ />
151
226
  <span class="control" aria-hidden="true">
152
227
  {#if showTrackIcons}
153
228
  <span class="track-icons">
@@ -167,14 +242,16 @@
167
242
  {/if}
168
243
  </span>
169
244
  </span>
170
- <span class="content">
171
- {#if label}
172
- <span class="label">{label}</span>
173
- {/if}
174
- {#if description}
175
- <span class="description">{description}</span>
176
- {/if}
177
- </span>
245
+ {#if showContent}
246
+ <span class="content">
247
+ {#if label}
248
+ <span class="label" id={labelId}>{label}</span>
249
+ {/if}
250
+ {#if description}
251
+ <span class="description" id={descriptionId}>{description}</span>
252
+ {/if}
253
+ </span>
254
+ {/if}
178
255
  </label>
179
256
 
180
257
  <style>:where(.seblify-tone-context) {
@@ -216,6 +293,14 @@
216
293
  --seblify-tone-border: var(--seblify-color-border, #c8d2df);
217
294
  }
218
295
 
296
+ :where(.seblify-tone-context[data-seblify-tone='strong']) {
297
+ --seblify-tone-fill: var(--seblify-color-fill-strong, #172033);
298
+ --seblify-tone-fill-text: var(--seblify-color-fill-strong-text, #ffffff);
299
+ --seblify-tone-surface: var(--seblify-color-surface-raised, #ffffff);
300
+ --seblify-tone-text: var(--seblify-color-text, #172033);
301
+ --seblify-tone-border: var(--seblify-color-border-strong, #aab7c5);
302
+ }
303
+
219
304
  :where(.seblify-tone-context[data-seblify-tone='primary']) {
220
305
  --seblify-tone-fill: var(--seblify-color-fill-primary, #146a6f);
221
306
  --seblify-tone-fill-text: var(--seblify-color-fill-primary-text, #ffffff);
@@ -224,6 +309,17 @@
224
309
  --seblify-tone-border: var(--seblify-color-border-accent, #9ab7ba);
225
310
  }
226
311
 
312
+ :where(.seblify-tone-context[data-seblify-tone='secondary']) {
313
+ --seblify-tone-fill: var(--seblify-color-fill-secondary, #5b5fc7);
314
+ --seblify-tone-fill-text: var(
315
+ --seblify-color-fill-secondary-text,
316
+ #ffffff
317
+ );
318
+ --seblify-tone-surface: var(--seblify-color-secondary-surface, #f0efff);
319
+ --seblify-tone-text: var(--seblify-color-secondary-text, #2f316f);
320
+ --seblify-tone-border: var(--seblify-color-secondary-border, #c8c6f4);
321
+ }
322
+
227
323
  :where(.seblify-tone-context[data-seblify-tone='success']) {
228
324
  --seblify-tone-fill: var(--seblify-color-fill-success, #1f7a3f);
229
325
  --seblify-tone-fill-text: var(--seblify-color-fill-success-text, #ffffff);
@@ -272,6 +368,8 @@
272
368
  --seblify-current-tone-border: var(--seblify-tone-border);
273
369
  }
274
370
 
371
+ /* Base */
372
+
275
373
  .switch {
276
374
  --switch-track-width: calc(var(--switch-size) * 1.75);
277
375
  --switch-track-height: var(--switch-size);
@@ -284,12 +382,15 @@
284
382
  var(--switch-track-height) - 2 * var(--switch-radius-inset)
285
383
  );
286
384
  --switch-thumb-width: var(--switch-thumb-size);
385
+ --switch-thumb-height: var(--switch-thumb-size);
287
386
  --switch-thumb-travel: calc(
288
387
  var(--switch-track-width) - var(--switch-thumb-width) - 2 *
289
388
  var(--switch-radius-inset)
290
389
  );
291
390
  --switch-thumb-position-off: 0px;
292
391
  --switch-thumb-position-on: var(--switch-thumb-travel);
392
+ --switch-thumb-transform-off: translateX(var(--switch-thumb-position-off));
393
+ --switch-thumb-transform-on: translateX(var(--switch-thumb-position-on));
293
394
  --switch-thumb-radius: max(
294
395
  0px,
295
396
  min(
@@ -299,6 +400,7 @@
299
400
  );
300
401
  --switch-solid-border: var(--seblify-tone-fill);
301
402
  --switch-solid-surface: var(--seblify-tone-fill);
403
+ --switch-focus-tone-fill: var(--seblify-tone-fill);
302
404
  --switch-solid-thumb: color-mix(
303
405
  in srgb,
304
406
  var(--seblify-tone-fill) 8%,
@@ -319,6 +421,13 @@
319
421
  var(--seblify-tone-fill) 78%,
320
422
  var(--seblify-color-surface, #ffffff)
321
423
  );
424
+ --switch-outline-border: var(--seblify-tone-fill);
425
+ --switch-outline-surface: color-mix(
426
+ in srgb,
427
+ var(--seblify-tone-fill) 7%,
428
+ var(--seblify-color-surface, #ffffff)
429
+ );
430
+ --switch-outline-thumb: var(--seblify-tone-fill);
322
431
  --switch-off-border: var(--seblify-color-border-strong, #aab7c5);
323
432
  --switch-off-surface: var(--seblify-color-surface-muted, #d9e0e8);
324
433
  --switch-off-thumb: var(--seblify-color-surface, #ffffff);
@@ -335,9 +444,9 @@
335
444
  );
336
445
  --switch-bouncy-runup: max(1px, calc(var(--switch-thumb-size) * 0.1));
337
446
  --switch-bouncy-overshoot: max(1px, calc(var(--switch-thumb-size) * 0.07));
338
- --switch-thumb-motion-duration: 160ms;
447
+ --switch-thumb-motion-duration: var(--switch-duration);
339
448
  --switch-thumb-motion-timing: cubic-bezier(0.32, 0.72, 0, 1);
340
- --switch-state-duration: 160ms;
449
+ --switch-state-duration: var(--switch-duration);
341
450
  --switch-state-timing: ease;
342
451
  --switch-track-icon-on-color: color-mix(
343
452
  in srgb,
@@ -351,7 +460,7 @@
351
460
  );
352
461
  --switch-focus-ring-color: color-mix(
353
462
  in srgb,
354
- var(--seblify-tone-fill) 56%,
463
+ var(--switch-focus-tone-fill) 56%,
355
464
  transparent
356
465
  );
357
466
 
@@ -363,6 +472,8 @@
363
472
  cursor: pointer;
364
473
  }
365
474
 
475
+ /* Tone */
476
+
366
477
  .switch[data-seblify-tone='inherit'] {
367
478
  --seblify-tone-fill: var(
368
479
  --seblify-current-tone-fill,
@@ -386,24 +497,46 @@
386
497
  );
387
498
  }
388
499
 
389
- .switch[data-animation='smooth'] {
390
- --switch-thumb-motion-duration: 190ms;
391
- --switch-thumb-motion-timing: cubic-bezier(0.32, 0.72, 0, 1);
392
- --switch-state-duration: 190ms;
393
- --switch-state-timing: ease;
500
+ .switch[data-focus-tone='inherit'] {
501
+ --switch-focus-tone-fill: var(--seblify-tone-fill);
502
+ }
503
+
504
+ .switch[data-focus-tone='neutral'] {
505
+ --switch-focus-tone-fill: var(--seblify-color-fill-neutral, #516176);
506
+ }
507
+
508
+ .switch[data-focus-tone='primary'] {
509
+ --switch-focus-tone-fill: var(--seblify-color-fill-primary, #146a6f);
510
+ }
511
+
512
+ .switch[data-focus-tone='secondary'] {
513
+ --switch-focus-tone-fill: var(--seblify-color-fill-secondary, #5b5fc7);
514
+ }
515
+
516
+ .switch[data-focus-tone='success'] {
517
+ --switch-focus-tone-fill: var(--seblify-color-fill-success, #1f7a3f);
518
+ }
519
+
520
+ .switch[data-focus-tone='danger'] {
521
+ --switch-focus-tone-fill: var(--seblify-color-fill-danger, #c93434);
522
+ }
523
+
524
+ .switch[data-focus-tone='warning'] {
525
+ --switch-focus-tone-fill: var(--seblify-color-fill-warning, #8a5a00);
526
+ }
527
+
528
+ .switch[data-focus-tone='info'] {
529
+ --switch-focus-tone-fill: var(--seblify-color-fill-info, #1f6fb2);
394
530
  }
395
531
 
396
- .switch[data-animation='snappy'] {
397
- --switch-thumb-motion-duration: 90ms;
398
- --switch-thumb-motion-timing: cubic-bezier(0.12, 0.92, 0.18, 1);
399
- --switch-state-duration: 90ms;
400
- --switch-state-timing: linear;
532
+ .switch[data-focus-tone='inverse'] {
533
+ --switch-focus-tone-fill: var(--seblify-color-fill-inverse, #172033);
401
534
  }
402
535
 
536
+ /* Motion */
537
+
403
538
  .switch[data-animation='bouncy'] {
404
- --switch-thumb-motion-duration: 380ms;
405
539
  --switch-thumb-motion-timing: cubic-bezier(0.24, 1.18, 0.4, 1);
406
- --switch-state-duration: 220ms;
407
540
  --switch-state-timing: ease;
408
541
  }
409
542
 
@@ -451,6 +584,50 @@
451
584
  }
452
585
  }
453
586
 
587
+ @keyframes switch-bouncy-vertical-to-on {
588
+ 0% {
589
+ transform: translateY(var(--switch-thumb-position-off));
590
+ }
591
+
592
+ 20% {
593
+ transform: translateY(
594
+ calc(var(--switch-thumb-position-off) - var(--switch-bouncy-runup))
595
+ );
596
+ }
597
+
598
+ 76% {
599
+ transform: translateY(
600
+ calc(var(--switch-thumb-position-on) + var(--switch-bouncy-overshoot))
601
+ );
602
+ }
603
+
604
+ 100% {
605
+ transform: translateY(var(--switch-thumb-position-on));
606
+ }
607
+ }
608
+
609
+ @keyframes switch-bouncy-vertical-to-off {
610
+ 0% {
611
+ transform: translateY(var(--switch-thumb-position-on));
612
+ }
613
+
614
+ 20% {
615
+ transform: translateY(
616
+ calc(var(--switch-thumb-position-on) + var(--switch-bouncy-runup))
617
+ );
618
+ }
619
+
620
+ 76% {
621
+ transform: translateY(
622
+ calc(var(--switch-thumb-position-off) - var(--switch-bouncy-overshoot))
623
+ );
624
+ }
625
+
626
+ 100% {
627
+ transform: translateY(var(--switch-thumb-position-off));
628
+ }
629
+ }
630
+
454
631
  input {
455
632
  position: absolute;
456
633
  width: 1px;
@@ -462,6 +639,8 @@ input {
462
639
  white-space: nowrap;
463
640
  }
464
641
 
642
+ /* Structure */
643
+
465
644
  .control {
466
645
  position: relative;
467
646
  display: inline-flex;
@@ -512,7 +691,7 @@ input {
512
691
  .thumb {
513
692
  display: inline-flex;
514
693
  width: var(--switch-thumb-width);
515
- height: var(--switch-thumb-size);
694
+ height: var(--switch-thumb-height);
516
695
  align-items: center;
517
696
  justify-content: center;
518
697
  border-radius: var(--switch-thumb-radius);
@@ -524,7 +703,7 @@ input {
524
703
  var(--seblify-color-text-muted, #516176) 36%,
525
704
  transparent
526
705
  );
527
- transform: translateX(var(--switch-thumb-position-off));
706
+ transform: var(--switch-thumb-transform-off);
528
707
  transition:
529
708
  transform var(--switch-thumb-motion-duration)
530
709
  var(--switch-thumb-motion-timing),
@@ -533,6 +712,8 @@ input {
533
712
  color var(--switch-state-duration) var(--switch-state-timing);
534
713
  }
535
714
 
715
+ /* Shapes */
716
+
536
717
  .switch[data-shape='floating'],
537
718
  .switch[data-shape='line'] {
538
719
  --switch-track-height: calc(var(--switch-size) * 0.6666667);
@@ -596,6 +777,86 @@ input {
596
777
  --switch-thumb-width: var(--switch-thumb-size);
597
778
  }
598
779
 
780
+ /* Orientation */
781
+
782
+ .switch[data-orientation='vertical'] {
783
+ --switch-track-width: var(--switch-size);
784
+ --switch-track-height: calc(var(--switch-size) * 1.75);
785
+ --switch-thumb-size: calc(
786
+ var(--switch-track-width) - 2 * var(--switch-radius-inset)
787
+ );
788
+ --switch-thumb-width: var(--switch-thumb-size);
789
+ --switch-thumb-height: var(--switch-thumb-size);
790
+ --switch-thumb-travel: calc(
791
+ var(--switch-track-height) - var(--switch-thumb-height) - 2 *
792
+ var(--switch-radius-inset)
793
+ );
794
+ --switch-thumb-position-off: var(--switch-thumb-travel);
795
+ --switch-thumb-position-on: 0px;
796
+ --switch-thumb-transform-off: translateY(var(--switch-thumb-position-off));
797
+ --switch-thumb-transform-on: translateY(var(--switch-thumb-position-on));
798
+ --switch-track-icon-offset: calc(
799
+ var(--switch-radius-inset) + var(--switch-thumb-size) * 0.08
800
+ );
801
+ }
802
+
803
+ .switch[data-orientation='vertical'] .control {
804
+ flex-direction: column;
805
+ }
806
+
807
+ .switch[data-orientation='vertical'][data-shape='flat'],
808
+ .switch[data-orientation='vertical'][data-shape='long'] {
809
+ --switch-track-width: calc(var(--switch-size) * 0.75);
810
+ --switch-track-height: calc(var(--switch-size) * 1.75);
811
+ --switch-thumb-size: calc(
812
+ var(--switch-track-width) - 2 * var(--switch-radius-inset)
813
+ );
814
+ --switch-thumb-width: var(--switch-thumb-size);
815
+ --switch-thumb-height: calc(var(--switch-thumb-size) * 1.55);
816
+ }
817
+
818
+ .switch[data-orientation='vertical'][data-shape='long'] {
819
+ --switch-thumb-height: var(--switch-thumb-size);
820
+ }
821
+
822
+ .switch[data-orientation='vertical'][data-shape='floating'],
823
+ .switch[data-orientation='vertical'][data-shape='line'] {
824
+ --switch-track-width: calc(var(--switch-size) * 0.6666667);
825
+ --switch-track-height: calc(var(--switch-size) * 1.75);
826
+ --switch-padding: 0px;
827
+ --switch-radius-inset: var(--switch-border-width);
828
+ --switch-thumb-size: var(--switch-size);
829
+ --switch-thumb-width: var(--switch-thumb-size);
830
+ --switch-thumb-height: var(--switch-thumb-size);
831
+ --switch-thumb-travel: calc(
832
+ var(--switch-track-height) - var(--switch-thumb-height)
833
+ );
834
+ --switch-thumb-position-off: var(--switch-thumb-travel);
835
+ --switch-thumb-position-on: calc(-2 * var(--switch-border-width));
836
+ }
837
+
838
+ .switch[data-orientation='vertical'][data-shape='line'] {
839
+ --switch-track-width: calc(var(--switch-size) * 0.3333333);
840
+ }
841
+
842
+ .switch[data-orientation='vertical'] .track-icon {
843
+ left: 50%;
844
+ transform: translateX(-50%);
845
+ }
846
+
847
+ .switch[data-orientation='vertical'] .track-icon--on {
848
+ top: var(--switch-track-icon-offset);
849
+ transform: translateX(-50%) rotate(90deg);
850
+ }
851
+
852
+ .switch[data-orientation='vertical'] .track-icon--off {
853
+ top: auto;
854
+ right: auto;
855
+ bottom: var(--switch-track-icon-offset);
856
+ }
857
+
858
+ /* States */
859
+
599
860
  input:checked + .control {
600
861
  border-color: var(--switch-on-border);
601
862
  background: var(--switch-on-surface);
@@ -622,7 +883,7 @@ input:checked + .control .thumb {
622
883
  }
623
884
 
624
885
  input:checked + .control .thumb {
625
- transform: translateX(var(--switch-thumb-position-on));
886
+ transform: var(--switch-thumb-transform-on);
626
887
  }
627
888
 
628
889
  .thumb-grip {
@@ -639,16 +900,34 @@ input:checked + .control .thumb {
639
900
  overflow: visible;
640
901
  }
641
902
 
642
- .switch[data-animation='bouncy'][data-bouncy-motion='to-on'] .thumb {
903
+ /* Animation selectors */
904
+
905
+ .switch[data-orientation='horizontal'][data-animation='bouncy'][data-bouncy-motion='to-on']
906
+ .thumb {
643
907
  animation: switch-bouncy-to-on var(--switch-thumb-motion-duration)
644
908
  var(--switch-thumb-motion-timing);
645
909
  }
646
910
 
647
- .switch[data-animation='bouncy'][data-bouncy-motion='to-off'] .thumb {
911
+ .switch[data-orientation='horizontal'][data-animation='bouncy'][data-bouncy-motion='to-off']
912
+ .thumb {
648
913
  animation: switch-bouncy-to-off var(--switch-thumb-motion-duration)
649
914
  var(--switch-thumb-motion-timing);
650
915
  }
651
916
 
917
+ .switch[data-orientation='vertical'][data-animation='bouncy'][data-bouncy-motion='to-on']
918
+ .thumb {
919
+ animation: switch-bouncy-vertical-to-on var(--switch-thumb-motion-duration)
920
+ var(--switch-thumb-motion-timing);
921
+ }
922
+
923
+ .switch[data-orientation='vertical'][data-animation='bouncy'][data-bouncy-motion='to-off']
924
+ .thumb {
925
+ animation: switch-bouncy-vertical-to-off var(--switch-thumb-motion-duration)
926
+ var(--switch-thumb-motion-timing);
927
+ }
928
+
929
+ /* Variants */
930
+
652
931
  .switch[data-variant='soft'] {
653
932
  --switch-on-border: var(--switch-soft-border);
654
933
  --switch-on-surface: var(--switch-soft-surface);
@@ -662,6 +941,23 @@ input:checked + .control .thumb {
662
941
  --switch-off-thumb: var(--switch-soft-thumb);
663
942
  }
664
943
 
944
+ .switch[data-variant='outline'] {
945
+ --switch-off-border: var(--seblify-color-border-strong, #aab7c5);
946
+ --switch-off-surface: var(--seblify-color-surface, #ffffff);
947
+ --switch-off-thumb: var(--switch-off-border);
948
+ --switch-on-border: var(--switch-outline-border);
949
+ --switch-on-surface: var(--switch-outline-surface);
950
+ --switch-on-thumb-base: var(--switch-outline-thumb);
951
+ --switch-on-thumb: var(--switch-on-thumb-base);
952
+ --switch-track-icon-on-color: color-mix(
953
+ in srgb,
954
+ var(--seblify-tone-fill) 48%,
955
+ transparent
956
+ );
957
+ }
958
+
959
+ /* Color schemes */
960
+
665
961
  :global([data-theme='dark']) .switch {
666
962
  --switch-solid-thumb: color-mix(
667
963
  in srgb,
@@ -696,6 +992,19 @@ input:checked + .control .thumb {
696
992
  }
697
993
  }
698
994
 
995
+ @media (prefers-reduced-motion: reduce) {
996
+ .switch {
997
+ --switch-thumb-motion-duration: 0ms;
998
+ --switch-thumb-motion-timing: linear;
999
+ --switch-state-duration: 0ms;
1000
+ --switch-state-timing: linear;
1001
+ }
1002
+
1003
+ .switch[data-animation='bouncy'] .thumb {
1004
+ animation: none;
1005
+ }
1006
+ }
1007
+
699
1008
  input:focus-visible + .control {
700
1009
  outline: 3px solid var(--switch-focus-ring-color);
701
1010
  outline-offset: 2px;
@@ -1,17 +1,22 @@
1
1
  import type { CustomCssSize } from 'seblify';
2
2
  type SwitchRadius = 'none' | 'sm' | 'md' | 'lg' | 'full' | CustomCssSize;
3
- type SwitchAnimation = 'smooth' | 'snappy' | 'bouncy';
3
+ type SwitchAnimation = 'smooth' | 'bouncy';
4
+ type SwitchOrientation = 'horizontal' | 'vertical';
4
5
  type SwitchShape = 'pill' | 'floating' | 'line' | 'flat' | 'long';
5
6
  type SwitchSize = 'xxs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | CustomCssSize;
6
- type SwitchTone = 'neutral' | 'primary' | 'success' | 'danger' | 'warning' | 'info' | 'inverse';
7
- type SwitchVariant = 'solid' | 'soft' | 'tint';
7
+ type SwitchTone = 'neutral' | 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'inverse';
8
+ type SwitchVariant = 'solid' | 'soft' | 'tint' | 'outline';
8
9
  declare const Switch: import("svelte").Component<{
9
10
  animation?: SwitchAnimation | undefined;
11
+ ariaLabel?: string | undefined;
10
12
  checked?: boolean | undefined;
11
13
  description?: string | undefined;
12
14
  disabled?: boolean | undefined;
15
+ duration?: number | undefined;
16
+ focusTone?: SwitchTone | undefined;
13
17
  label?: string | undefined;
14
18
  name?: string | undefined;
19
+ orientation?: SwitchOrientation | undefined;
15
20
  radius?: SwitchRadius | undefined;
16
21
  shape?: SwitchShape | undefined;
17
22
  showGripIcon?: boolean | undefined;
@@ -102,6 +102,14 @@
102
102
  --seblify-tone-border: var(--seblify-color-border, #c8d2df);
103
103
  }
104
104
 
105
+ :where(.seblify-tone-context[data-seblify-tone='strong']) {
106
+ --seblify-tone-fill: var(--seblify-color-fill-strong, #172033);
107
+ --seblify-tone-fill-text: var(--seblify-color-fill-strong-text, #ffffff);
108
+ --seblify-tone-surface: var(--seblify-color-surface-raised, #ffffff);
109
+ --seblify-tone-text: var(--seblify-color-text, #172033);
110
+ --seblify-tone-border: var(--seblify-color-border-strong, #aab7c5);
111
+ }
112
+
105
113
  :where(.seblify-tone-context[data-seblify-tone='primary']) {
106
114
  --seblify-tone-fill: var(--seblify-color-fill-primary, #146a6f);
107
115
  --seblify-tone-fill-text: var(--seblify-color-fill-primary-text, #ffffff);
@@ -110,6 +118,17 @@
110
118
  --seblify-tone-border: var(--seblify-color-border-accent, #9ab7ba);
111
119
  }
112
120
 
121
+ :where(.seblify-tone-context[data-seblify-tone='secondary']) {
122
+ --seblify-tone-fill: var(--seblify-color-fill-secondary, #5b5fc7);
123
+ --seblify-tone-fill-text: var(
124
+ --seblify-color-fill-secondary-text,
125
+ #ffffff
126
+ );
127
+ --seblify-tone-surface: var(--seblify-color-secondary-surface, #f0efff);
128
+ --seblify-tone-text: var(--seblify-color-secondary-text, #2f316f);
129
+ --seblify-tone-border: var(--seblify-color-secondary-border, #c8c6f4);
130
+ }
131
+
113
132
  :where(.seblify-tone-context[data-seblify-tone='success']) {
114
133
  --seblify-tone-fill: var(--seblify-color-fill-success, #1f7a3f);
115
134
  --seblify-tone-fill-text: var(--seblify-color-fill-success-text, #ffffff);