@dorsk/tsumikit 0.79.0 → 0.80.1

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 (53) hide show
  1. package/dist/components/atoms/Artwork.svelte +14 -10
  2. package/dist/components/atoms/Artwork.svelte.d.ts +1 -1
  3. package/dist/components/atoms/Badge.svelte +1 -4
  4. package/dist/components/atoms/Button.svelte +303 -9
  5. package/dist/components/atoms/Button.svelte.d.ts +4 -1
  6. package/dist/components/atoms/Card.svelte +142 -0
  7. package/dist/components/atoms/Checkbox.svelte +177 -1
  8. package/dist/components/atoms/Input.svelte +35 -0
  9. package/dist/components/atoms/Link.svelte +61 -0
  10. package/dist/components/atoms/Progress.svelte +74 -1
  11. package/dist/components/atoms/Progress.svelte.d.ts +1 -0
  12. package/dist/components/atoms/Select.svelte +30 -0
  13. package/dist/components/atoms/Skeleton.svelte +54 -3
  14. package/dist/components/atoms/Skeleton.svelte.d.ts +1 -0
  15. package/dist/components/atoms/Spinner.svelte +152 -3
  16. package/dist/components/atoms/Spinner.svelte.d.ts +1 -1
  17. package/dist/components/atoms/Switch.svelte +135 -0
  18. package/dist/components/atoms/Textarea.svelte +36 -0
  19. package/dist/components/atoms/Thinking.svelte +130 -0
  20. package/dist/components/atoms/Thinking.svelte.d.ts +15 -0
  21. package/dist/components/molecules/CopyButton.svelte +146 -5
  22. package/dist/components/molecules/Field.svelte +55 -1
  23. package/dist/components/molecules/FileButton.svelte +4 -2
  24. package/dist/components/molecules/InputGroup.svelte +1 -1
  25. package/dist/components/molecules/LookPicker.svelte +100 -0
  26. package/dist/components/molecules/LookPicker.svelte.d.ts +17 -0
  27. package/dist/components/molecules/MotionSettings.svelte +166 -0
  28. package/dist/components/molecules/MotionSettings.svelte.d.ts +18 -0
  29. package/dist/components/molecules/RadioGroup.svelte +61 -0
  30. package/dist/components/molecules/SectionHeader.svelte +2 -0
  31. package/dist/components/molecules/Tabs.svelte +157 -4
  32. package/dist/components/molecules/ThemePicker.svelte +8 -3
  33. package/dist/fx.d.ts +149 -0
  34. package/dist/fx.js +111 -0
  35. package/dist/fx.md +58 -0
  36. package/dist/index.d.ts +8 -2
  37. package/dist/index.js +8 -2
  38. package/dist/looks/README.md +101 -0
  39. package/dist/looks/depth.css +939 -0
  40. package/dist/looks/editorial.css +545 -0
  41. package/dist/looks/tactile.css +871 -0
  42. package/dist/markdown.js +47 -21
  43. package/dist/pointer.d.ts +3 -0
  44. package/dist/pointer.js +40 -0
  45. package/dist/stores/fx.svelte.d.ts +17 -0
  46. package/dist/stores/fx.svelte.js +64 -0
  47. package/dist/stores/theme.svelte.d.ts +8 -2
  48. package/dist/stores/theme.svelte.js +33 -7
  49. package/dist/styles/themes.css +249 -249
  50. package/dist/styles/tokens.css +4 -3
  51. package/dist/theme-mode.d.ts +31 -0
  52. package/dist/theme-mode.js +19 -0
  53. package/package.json +3 -2
@@ -8,7 +8,11 @@
8
8
  | 'bars'
9
9
  | 'grid'
10
10
  | 'clock'
11
- | 'bounce';
11
+ | 'bounce'
12
+ | 'comet'
13
+ | 'breath'
14
+ | 'morph'
15
+ | 'sweep';
12
16
 
13
17
  // Inner spans per variant; `.in` wraps the flex/grid ones in an absolute
14
18
  // layer so the root keeps the same inline baseline as the others.
@@ -20,7 +24,11 @@
20
24
  bars: { count: 4, wrap: true },
21
25
  grid: { count: 9, wrap: true },
22
26
  clock: { count: 0, wrap: false },
23
- bounce: { count: 2, wrap: false }
27
+ bounce: { count: 2, wrap: false },
28
+ comet: { count: 1, wrap: false },
29
+ breath: { count: 5, wrap: true },
30
+ morph: { count: 0, wrap: false },
31
+ sweep: { count: 0, wrap: false }
24
32
  };
25
33
  </script>
26
34
 
@@ -29,7 +37,7 @@
29
37
  // other variants are pure-CSS pictograms drawn in currentColor inside a 1em
30
38
  // box. Every variant's base style is a meaningful static pose, which is what
31
39
  // shows under prefers-reduced-motion. `--spinner-speed` scales the tempo.
32
- // `clock` and `bounce` read best at 20px and up.
40
+ // `clock` and `bounce` read best at 20px and up; `breath` is 2.5em wide.
33
41
  import Icon from './Icon.svelte';
34
42
 
35
43
  let {
@@ -82,6 +90,11 @@
82
90
  inherits: false;
83
91
  initial-value: 100deg;
84
92
  }
93
+ @property --tsu-spin-sweep {
94
+ syntax: '<angle>';
95
+ inherits: false;
96
+ initial-value: 0deg;
97
+ }
85
98
 
86
99
  .spinner {
87
100
  --sw: max(1.5px, 0.11em);
@@ -472,6 +485,142 @@
472
485
  }
473
486
  }
474
487
 
488
+ .v-comet::before,
489
+ .v-comet > span,
490
+ .v-sweep::before {
491
+ content: '';
492
+ position: absolute;
493
+ inset: 0;
494
+ border-radius: 50%;
495
+ -webkit-mask: radial-gradient(
496
+ farthest-side,
497
+ transparent calc(100% - var(--sw)),
498
+ #000 calc(100% - var(--sw) + 0.5px)
499
+ );
500
+ mask: radial-gradient(
501
+ farthest-side,
502
+ transparent calc(100% - var(--sw)),
503
+ #000 calc(100% - var(--sw) + 0.5px)
504
+ );
505
+ }
506
+ .v-comet::before {
507
+ background: currentColor;
508
+ opacity: 0.1;
509
+ }
510
+ .v-comet > span {
511
+ background: conic-gradient(from 0deg, transparent 0 35%, currentColor 100%);
512
+ animation: tsu-spin-comet calc(var(--t) * 1.1) linear infinite;
513
+ }
514
+ .v-comet > span::after {
515
+ content: '';
516
+ position: absolute;
517
+ top: 0;
518
+ left: 50%;
519
+ width: var(--sw);
520
+ height: var(--sw);
521
+ border-radius: 50%;
522
+ background: currentColor;
523
+ box-shadow: 0 0 0.25em 0.04em currentColor;
524
+ transform: translateX(-50%);
525
+ }
526
+ @keyframes tsu-spin-comet {
527
+ to {
528
+ transform: rotate(360deg);
529
+ }
530
+ }
531
+
532
+ .v-sweep::before {
533
+ background: conic-gradient(
534
+ from var(--tsu-spin-sweep),
535
+ color-mix(in srgb, currentColor 18%, transparent),
536
+ currentColor 50%,
537
+ color-mix(in srgb, currentColor 18%, transparent)
538
+ );
539
+ animation: tsu-spin-sweep calc(var(--t) * 1.4) linear infinite;
540
+ }
541
+ @keyframes tsu-spin-sweep {
542
+ to {
543
+ --tsu-spin-sweep: 360deg;
544
+ }
545
+ }
546
+
547
+ .v-morph::before {
548
+ content: '';
549
+ position: absolute;
550
+ inset: 0.08em;
551
+ border-radius: 50%;
552
+ background: currentColor;
553
+ animation: tsu-spin-morph calc(var(--t) * 2.4) cubic-bezier(0.77, 0, 0.175, 1) infinite;
554
+ }
555
+ @keyframes tsu-spin-morph {
556
+ 0% {
557
+ border-radius: 50%;
558
+ transform: rotate(0deg) scale(1);
559
+ }
560
+ 25% {
561
+ border-radius: 24%;
562
+ transform: rotate(90deg) scale(0.92);
563
+ }
564
+ 50% {
565
+ border-radius: 50%;
566
+ transform: rotate(180deg) scale(1);
567
+ }
568
+ 75% {
569
+ border-radius: 24%;
570
+ transform: rotate(270deg) scale(0.92);
571
+ }
572
+ 100% {
573
+ border-radius: 50%;
574
+ transform: rotate(360deg) scale(1);
575
+ }
576
+ }
577
+
578
+ .v-breath {
579
+ width: 2.5em;
580
+ }
581
+ .v-breath .in {
582
+ display: flex;
583
+ align-items: center;
584
+ justify-content: space-between;
585
+ }
586
+ .v-breath .in span {
587
+ width: 0.34em;
588
+ height: 0.34em;
589
+ border-radius: 50%;
590
+ background: currentColor;
591
+ animation: tsu-spin-breath calc(var(--t) * 1.3) cubic-bezier(0.77, 0, 0.175, 1) infinite;
592
+ }
593
+ .v-breath .in span:nth-child(1) {
594
+ opacity: 1;
595
+ animation-delay: calc(var(--t) * -0.52);
596
+ }
597
+ .v-breath .in span:nth-child(2) {
598
+ opacity: 0.75;
599
+ animation-delay: calc(var(--t) * -0.39);
600
+ }
601
+ .v-breath .in span:nth-child(3) {
602
+ opacity: 0.55;
603
+ animation-delay: calc(var(--t) * -0.26);
604
+ }
605
+ .v-breath .in span:nth-child(4) {
606
+ opacity: 0.4;
607
+ animation-delay: calc(var(--t) * -0.13);
608
+ }
609
+ .v-breath .in span:nth-child(5) {
610
+ opacity: 0.28;
611
+ }
612
+ @keyframes tsu-spin-breath {
613
+ 0%,
614
+ 100% {
615
+ opacity: 0.3;
616
+ transform: scale(0.6);
617
+ }
618
+ 40% {
619
+ opacity: 1;
620
+ transform: scale(1);
621
+ }
622
+ }
623
+
475
624
  @media (prefers-reduced-motion: reduce) {
476
625
  .spinner.spinner,
477
626
  .spinner.spinner span,
@@ -1,4 +1,4 @@
1
- export type SpinnerVariant = 'icon' | 'arc' | 'dots' | 'orbit' | 'pulse' | 'bars' | 'grid' | 'clock' | 'bounce';
1
+ export type SpinnerVariant = 'icon' | 'arc' | 'dots' | 'orbit' | 'pulse' | 'bars' | 'grid' | 'clock' | 'bounce' | 'comet' | 'breath' | 'morph' | 'sweep';
2
2
  type $$ComponentProps = {
3
3
  variant?: SpinnerVariant;
4
4
  /** Explicit pixel size. Omit to track the surrounding text (1em). */
@@ -36,11 +36,13 @@
36
36
 
37
37
  const field = getFieldContext();
38
38
  const isInvalid = $derived(invalid || !!field?.invalid);
39
+ let armed = $state(false);
39
40
 
40
41
  function toggle(e: MouseEvent & { currentTarget: EventTarget & HTMLButtonElement }) {
41
42
  onclick?.(e);
42
43
  if (e.defaultPrevented) return;
43
44
  checked = !checked;
45
+ armed = true;
44
46
  playSound(checked ? 'toggle-on' : 'toggle-off', sound);
45
47
  }
46
48
  </script>
@@ -53,6 +55,7 @@
53
55
  class="switch {klass}"
54
56
  class:on={checked}
55
57
  class:switch-sm={size === 'sm'}
58
+ class:armed
56
59
  role="switch"
57
60
  aria-checked={checked}
58
61
  id={id ?? field?.id}
@@ -78,6 +81,8 @@
78
81
  /* Track and knob sit on the 4px grid: md 24 / sm 20 tall, knob = track minus
79
82
  border and padding, travel = track width minus the knob and insets. */
80
83
  .switch {
84
+ position: relative;
85
+ isolation: isolate;
81
86
  --sw-h: var(--chip-md);
82
87
  --sw-w: 2.75rem;
83
88
  --sw-inset: calc(var(--sp-0-5) + 1px);
@@ -97,6 +102,7 @@
97
102
  border-color var(--dur-fast) var(--ease);
98
103
  }
99
104
  .switch .knob {
105
+ position: relative;
100
106
  width: var(--sw-knob);
101
107
  height: var(--sw-knob);
102
108
  border-radius: var(--r-pill);
@@ -122,6 +128,135 @@
122
128
  scale: calc(1 + (var(--press-scale) - var(--press-scale-sm)) * 2.4) 1;
123
129
  transition-duration: var(--dur-press);
124
130
  }
131
+ /* Effects follow the closest data-fx-switch ancestor; squash is the default. */
132
+ .switch:not(:global([data-fx-switch]:not([data-fx-switch='squash'])) *),
133
+ :global([data-fx-switch='squash']) .switch:not(:global([data-fx-switch='squash'] [data-fx-switch]:not([data-fx-switch='squash'])) *) {
134
+ &.armed.on .knob {
135
+ animation: sw-squash-on var(--dur-spring) var(--ease-out);
136
+ }
137
+ &.armed:not(.on) .knob {
138
+ animation: sw-squash-off var(--dur-spring) var(--ease-out);
139
+ }
140
+ }
141
+ /* On and off use separate names so the animation restarts on every toggle. */
142
+ @keyframes sw-squash-on {
143
+ 35% {
144
+ scale: 1.4 0.8;
145
+ }
146
+ 70% {
147
+ scale: 0.86 1.1;
148
+ }
149
+ }
150
+ @keyframes sw-squash-off {
151
+ 35% {
152
+ scale: 1.4 0.8;
153
+ }
154
+ 70% {
155
+ scale: 0.86 1.1;
156
+ }
157
+ }
158
+
159
+ /* A streak trails the knob in flight; a soft accent halo glows while on. */
160
+ :global([data-fx-switch='glow']) .switch:not(:global([data-fx-switch='glow'] [data-fx-switch]:not([data-fx-switch='glow'])) *) {
161
+ &::after {
162
+ content: '';
163
+ position: absolute;
164
+ inset: -40% -18%;
165
+ z-index: -1;
166
+ pointer-events: none;
167
+ background: radial-gradient(closest-side, color-mix(in srgb, var(--accent) 45%, transparent), transparent);
168
+ opacity: 0;
169
+ transition: opacity var(--dur-slow) var(--ease);
170
+ }
171
+ &.on::after {
172
+ opacity: 1;
173
+ }
174
+ & .knob::before {
175
+ content: '';
176
+ position: absolute;
177
+ top: 18%;
178
+ bottom: 18%;
179
+ width: 170%;
180
+ z-index: -1;
181
+ pointer-events: none;
182
+ border-radius: var(--r-pill);
183
+ opacity: 0;
184
+ }
185
+ &.on .knob::before {
186
+ right: 40%;
187
+ transform-origin: right center;
188
+ background: linear-gradient(to left, color-mix(in srgb, var(--text-on-accent) 75%, transparent), transparent);
189
+ }
190
+ &:not(.on) .knob::before {
191
+ left: 40%;
192
+ transform-origin: left center;
193
+ background: linear-gradient(to right, color-mix(in srgb, var(--accent) 80%, transparent), transparent);
194
+ }
195
+ &.armed.on .knob::before {
196
+ animation: sw-trail-on var(--dur-spring) var(--ease-out);
197
+ }
198
+ &.armed:not(.on) .knob::before {
199
+ animation: sw-trail-off var(--dur-spring) var(--ease-out);
200
+ }
201
+ }
202
+ @keyframes sw-trail-on {
203
+ 0%,
204
+ 100% {
205
+ opacity: 0;
206
+ scale: 0.2 1;
207
+ }
208
+ 30% {
209
+ opacity: 1;
210
+ scale: 1;
211
+ }
212
+ }
213
+ @keyframes sw-trail-off {
214
+ 0%,
215
+ 100% {
216
+ opacity: 0;
217
+ scale: 0.2 1;
218
+ }
219
+ 30% {
220
+ opacity: 1;
221
+ scale: 1;
222
+ }
223
+ }
224
+
225
+ /* Calm: an unhurried glide with no overshoot; a small accent pip settles into the knob once on. */
226
+ :global([data-fx-switch='calm']) .switch:not(:global([data-fx-switch='calm'] [data-fx-switch]:not([data-fx-switch='calm'])) *) {
227
+ transition:
228
+ background var(--dur-slow) var(--ease),
229
+ border-color var(--dur-slow) var(--ease);
230
+ & .knob {
231
+ transform-origin: center;
232
+ transition:
233
+ translate var(--dur-slow) var(--ease-in-out),
234
+ scale var(--dur-fast) var(--ease-out),
235
+ background var(--dur-slow) var(--ease);
236
+ }
237
+ &:active:not(:disabled) .knob {
238
+ scale: var(--press-scale-sm);
239
+ }
240
+ & .knob::after {
241
+ content: '';
242
+ position: absolute;
243
+ inset: 32%;
244
+ border-radius: var(--r-pill);
245
+ background: var(--accent);
246
+ opacity: 0;
247
+ scale: 0.4;
248
+ transition:
249
+ opacity var(--dur-exit-fast) var(--ease-out),
250
+ scale var(--dur-exit-fast) var(--ease-out);
251
+ }
252
+ &.on .knob::after {
253
+ opacity: 1;
254
+ scale: 1;
255
+ transition:
256
+ opacity var(--dur-base) var(--ease) var(--dur-fast),
257
+ scale var(--dur-base) var(--ease-out) var(--dur-fast);
258
+ }
259
+ }
125
260
  .switch:focus-visible {
126
261
  outline: var(--focus-ring);
127
262
  outline-offset: var(--focus-ring-offset);
@@ -211,6 +211,7 @@
211
211
  bind:value
212
212
  use:autoresizeAction={typeof value === 'string' ? value : ''}
213
213
  {...rest}
214
+ placeholder={rest.placeholder ?? (field ? ' ' : undefined)}
214
215
  onkeydown={onsubmit || onkeydown ? handleKeydown : undefined}
215
216
  id={id ?? field?.id}
216
217
  aria-describedby={ariaDescribedby ?? field?.describedBy}
@@ -230,6 +231,7 @@
230
231
  style:max-height={maxHeight}
231
232
  bind:value
232
233
  {...rest}
234
+ placeholder={rest.placeholder ?? (field ? ' ' : undefined)}
233
235
  onkeydown={onsubmit || onkeydown ? handleKeydown : undefined}
234
236
  id={id ?? field?.id}
235
237
  aria-describedby={ariaDescribedby ?? field?.describedBy}
@@ -302,6 +304,10 @@
302
304
  outline-offset: var(--focus-ring-offset);
303
305
  box-shadow: var(--control-shadow), var(--focus-glow);
304
306
  }
307
+ .textarea::placeholder {
308
+ color: var(--text-faint);
309
+ opacity: 1;
310
+ }
305
311
  .textarea:disabled {
306
312
  cursor: not-allowed;
307
313
  }
@@ -335,6 +341,36 @@
335
341
  .textarea[aria-invalid='true']:focus {
336
342
  border-color: var(--danger);
337
343
  }
344
+ .textarea {
345
+ --focus-tint: var(--accent);
346
+ }
347
+ .textarea[aria-invalid='true'] {
348
+ --focus-tint: var(--danger);
349
+ }
350
+ /* Focus bloom: a solid ring whose soft halo swells, then settles to a quieter glow. */
351
+ .textarea:not(.grouped):focus:not(:global([data-fx-focus='none']) *),
352
+ :global(:is([data-fx-focus='bloom'], [data-fx-focus='label'])) .textarea:not(.grouped):focus:not(:global(:is([data-fx-focus='bloom'], [data-fx-focus='label']) [data-fx-focus='none']) *) {
353
+ outline: none;
354
+ box-shadow:
355
+ var(--control-shadow),
356
+ 0 0 0 var(--focus-ring-width) var(--focus-tint),
357
+ 0 0 16px 2px color-mix(in srgb, var(--focus-tint) 24%, transparent);
358
+ animation: focus-bloom var(--dur-fast) var(--ease-out);
359
+ }
360
+ @keyframes focus-bloom {
361
+ 0% {
362
+ box-shadow:
363
+ var(--control-shadow),
364
+ 0 0 0 0 transparent,
365
+ 0 0 0 0 transparent;
366
+ }
367
+ 45% {
368
+ box-shadow:
369
+ var(--control-shadow),
370
+ 0 0 0 calc(var(--focus-ring-width) + 1px) var(--focus-tint),
371
+ 0 0 20px 4px color-mix(in srgb, var(--focus-tint) 32%, transparent);
372
+ }
373
+ }
338
374
  /* Inside an InputGroup the group draws the focus ring and the overlaid
339
375
  adornments report their widths; the text stays clear of them. */
340
376
  .textarea.grouped {
@@ -0,0 +1,130 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+ // Chat "assistant is working" indicator. `dots`: three dots rise one after
4
+ // the other, drawn in currentColor. `sheen`: a light sweeps through the
5
+ // status word (children, or `label`), with a blinking caret after it.
6
+ let {
7
+ variant = 'dots',
8
+ label = 'Thinking',
9
+ caret = true,
10
+ children,
11
+ class: klass = '',
12
+ style: styleProp = '',
13
+ ...rest
14
+ }: {
15
+ variant?: 'dots' | 'sheen';
16
+ /** Announced to AT; also the visible word of `sheen` when there are no children. */
17
+ label?: string;
18
+ /** Blinking caret after the sheen text. */
19
+ caret?: boolean;
20
+ children?: Snippet;
21
+ class?: string;
22
+ style?: string;
23
+ [key: string]: unknown;
24
+ } = $props();
25
+ </script>
26
+
27
+ <span
28
+ data-tsu="Thinking"
29
+ class="thinking v-{variant} {klass}"
30
+ style={styleProp}
31
+ role="status"
32
+ aria-label={variant === 'dots' ? label : undefined}
33
+ {...rest}
34
+ >
35
+ {#if variant === 'dots'}
36
+ <span class="dots" aria-hidden="true"><span></span><span></span><span></span></span>
37
+ {:else}
38
+ <span class="text">{#if children}{@render children()}{:else}{label}{/if}</span>
39
+ {#if caret}<span class="caret" aria-hidden="true"></span>{/if}
40
+ {/if}
41
+ </span>
42
+
43
+ <style>
44
+ .thinking {
45
+ display: inline-flex;
46
+ align-items: center;
47
+ line-height: 1;
48
+ vertical-align: middle;
49
+ }
50
+ .dots {
51
+ display: inline-flex;
52
+ align-items: center;
53
+ gap: 0.3em;
54
+ padding: 0.25em 0;
55
+ }
56
+ .dots span {
57
+ display: block;
58
+ width: 0.4em;
59
+ height: 0.4em;
60
+ border-radius: 50%;
61
+ background: currentColor;
62
+ animation: tsu-thinking-dot 1.2s var(--ease-in-out) infinite;
63
+ }
64
+ .dots span:nth-child(1) {
65
+ opacity: 1;
66
+ }
67
+ .dots span:nth-child(2) {
68
+ opacity: 0.6;
69
+ animation-delay: 0.15s;
70
+ }
71
+ .dots span:nth-child(3) {
72
+ opacity: 0.3;
73
+ animation-delay: 0.3s;
74
+ }
75
+ @keyframes tsu-thinking-dot {
76
+ 0%,
77
+ 55%,
78
+ 100% {
79
+ opacity: 0.35;
80
+ transform: translateY(0);
81
+ }
82
+ 25% {
83
+ opacity: 1;
84
+ transform: translateY(-0.3em);
85
+ }
86
+ }
87
+
88
+ .v-sheen {
89
+ line-height: inherit;
90
+ }
91
+ .text {
92
+ background: linear-gradient(90deg, var(--text-muted) 0 38%, var(--text) 50%, var(--text-muted) 62% 100%);
93
+ background-size: 300% 100%;
94
+ background-position: 100% 0;
95
+ -webkit-background-clip: text;
96
+ background-clip: text;
97
+ color: transparent;
98
+ animation: tsu-thinking-sheen 1.8s linear infinite;
99
+ }
100
+ @keyframes tsu-thinking-sheen {
101
+ to {
102
+ background-position: 0% 0;
103
+ }
104
+ }
105
+ .caret {
106
+ display: inline-block;
107
+ width: 2px;
108
+ height: 1em;
109
+ margin-left: 0.2em;
110
+ border-radius: 1px;
111
+ background: var(--accent);
112
+ animation: tsu-thinking-blink 1s steps(2, jump-none) infinite;
113
+ }
114
+ @keyframes tsu-thinking-blink {
115
+ to {
116
+ opacity: 0;
117
+ }
118
+ }
119
+
120
+ @media (prefers-reduced-motion: reduce) {
121
+ .dots span,
122
+ .text,
123
+ .caret {
124
+ animation: none;
125
+ }
126
+ .text {
127
+ background-position: 50% 0;
128
+ }
129
+ }
130
+ </style>
@@ -0,0 +1,15 @@
1
+ import type { Snippet } from 'svelte';
2
+ type $$ComponentProps = {
3
+ variant?: 'dots' | 'sheen';
4
+ /** Announced to AT; also the visible word of `sheen` when there are no children. */
5
+ label?: string;
6
+ /** Blinking caret after the sheen text. */
7
+ caret?: boolean;
8
+ children?: Snippet;
9
+ class?: string;
10
+ style?: string;
11
+ [key: string]: unknown;
12
+ };
13
+ declare const Thinking: import("svelte").Component<$$ComponentProps, {}, "">;
14
+ type Thinking = ReturnType<typeof Thinking>;
15
+ export default Thinking;