@dorsk/tsumikit 0.73.2 → 0.75.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 (137) hide show
  1. package/README.md +38 -1
  2. package/dist/autoresize.d.ts +2 -0
  3. package/dist/autoresize.js +8 -1
  4. package/dist/components/atoms/Artwork.svelte +12 -5
  5. package/dist/components/atoms/Avatar.svelte +1 -1
  6. package/dist/components/atoms/Badge.svelte +59 -23
  7. package/dist/components/atoms/Button.svelte +130 -96
  8. package/dist/components/atoms/Button.svelte.d.ts +2 -0
  9. package/dist/components/atoms/Card.svelte +10 -4
  10. package/dist/components/atoms/Checkbox.svelte +36 -9
  11. package/dist/components/atoms/Checkbox.svelte.d.ts +2 -0
  12. package/dist/components/atoms/Gauge.svelte +20 -14
  13. package/dist/components/atoms/Heading.svelte +1 -1
  14. package/dist/components/atoms/Icon.svelte +1 -0
  15. package/dist/components/atoms/Input.svelte +67 -13
  16. package/dist/components/atoms/Kbd.svelte +3 -3
  17. package/dist/components/atoms/Link.svelte +7 -2
  18. package/dist/components/atoms/Progress.svelte +12 -6
  19. package/dist/components/atoms/Scrim.svelte +3 -8
  20. package/dist/components/atoms/SegmentedProgress.svelte +5 -4
  21. package/dist/components/atoms/Select.svelte +58 -27
  22. package/dist/components/atoms/Skeleton.svelte +14 -8
  23. package/dist/components/atoms/Slider.svelte +79 -22
  24. package/dist/components/atoms/Slider.svelte.d.ts +2 -0
  25. package/dist/components/atoms/Spinner.svelte +464 -5
  26. package/dist/components/atoms/Spinner.svelte.d.ts +2 -0
  27. package/dist/components/atoms/Swatch.svelte +19 -8
  28. package/dist/components/atoms/Switch.svelte +34 -21
  29. package/dist/components/atoms/Switch.svelte.d.ts +2 -0
  30. package/dist/components/atoms/Text.svelte +1 -1
  31. package/dist/components/atoms/Textarea.svelte +34 -12
  32. package/dist/components/atoms/TimeDisplay.svelte +4 -2
  33. package/dist/components/layouts/AppShell.svelte +26 -15
  34. package/dist/components/layouts/MasterDetail.svelte +23 -21
  35. package/dist/components/layouts/NavBar.svelte +11 -8
  36. package/dist/components/layouts/NavItem.svelte +15 -7
  37. package/dist/components/layouts/NavSection.svelte +1 -1
  38. package/dist/components/layouts/ResizablePanel.svelte +37 -16
  39. package/dist/components/layouts/TabBar.svelte +24 -14
  40. package/dist/components/layouts/TabBar.svelte.d.ts +2 -0
  41. package/dist/components/molecules/Accordion.svelte +4 -0
  42. package/dist/components/molecules/Accordion.svelte.d.ts +2 -0
  43. package/dist/components/molecules/AttachmentList.svelte +14 -11
  44. package/dist/components/molecules/Breadcrumb.svelte +13 -9
  45. package/dist/components/molecules/Callout.svelte +3 -3
  46. package/dist/components/molecules/CapBar.svelte +23 -22
  47. package/dist/components/molecules/Carousel.svelte +27 -17
  48. package/dist/components/molecules/ChatBubble.svelte +2 -2
  49. package/dist/components/molecules/CodeBlock.svelte +2 -2
  50. package/dist/components/molecules/Combobox.svelte +30 -1
  51. package/dist/components/molecules/Combobox.svelte.d.ts +4 -0
  52. package/dist/components/molecules/Composer.svelte +2 -2
  53. package/dist/components/molecules/ConfirmModal.svelte +4 -0
  54. package/dist/components/molecules/ConfirmModal.svelte.d.ts +2 -0
  55. package/dist/components/molecules/CopyButton.svelte +46 -2
  56. package/dist/components/molecules/CopyButton.svelte.d.ts +2 -0
  57. package/dist/components/molecules/Disclosure.svelte +23 -12
  58. package/dist/components/molecules/Disclosure.svelte.d.ts +2 -0
  59. package/dist/components/molecules/Drawer.svelte +43 -23
  60. package/dist/components/molecules/Drawer.svelte.d.ts +2 -0
  61. package/dist/components/molecules/Dropzone.svelte +24 -8
  62. package/dist/components/molecules/EmojiPicker.svelte +27 -8
  63. package/dist/components/molecules/EmojiPicker.svelte.d.ts +2 -0
  64. package/dist/components/molecules/EmptyState.svelte +5 -5
  65. package/dist/components/molecules/Fieldset.svelte +8 -13
  66. package/dist/components/molecules/FileButton.svelte +57 -31
  67. package/dist/components/molecules/FileButton.svelte.d.ts +2 -0
  68. package/dist/components/molecules/FilterInput.svelte +51 -11
  69. package/dist/components/molecules/FontScalePicker.svelte +20 -9
  70. package/dist/components/molecules/GitRef.svelte +9 -7
  71. package/dist/components/molecules/GlyphStack.svelte +38 -14
  72. package/dist/components/molecules/IconButton.svelte +6 -3
  73. package/dist/components/molecules/IconButton.svelte.d.ts +2 -0
  74. package/dist/components/molecules/InputGroup.svelte +13 -12
  75. package/dist/components/molecules/LoadMore.svelte +6 -1
  76. package/dist/components/molecules/LoadMore.svelte.d.ts +2 -0
  77. package/dist/components/molecules/Menu.svelte +33 -7
  78. package/dist/components/molecules/Menu.svelte.d.ts +2 -0
  79. package/dist/components/molecules/Metric.svelte +11 -9
  80. package/dist/components/molecules/Modal.svelte +76 -26
  81. package/dist/components/molecules/Modal.svelte.d.ts +2 -0
  82. package/dist/components/molecules/OptionButton.svelte +28 -10
  83. package/dist/components/molecules/OptionButton.svelte.d.ts +2 -0
  84. package/dist/components/molecules/Pagination.svelte +26 -9
  85. package/dist/components/molecules/Pagination.svelte.d.ts +2 -0
  86. package/dist/components/molecules/Popover.svelte +107 -51
  87. package/dist/components/molecules/Popover.svelte.d.ts +2 -0
  88. package/dist/components/molecules/Prose.svelte +1 -1
  89. package/dist/components/molecules/PullToRefresh.svelte +14 -10
  90. package/dist/components/molecules/PullToRefresh.svelte.d.ts +2 -0
  91. package/dist/components/molecules/RadialMenu.svelte +52 -19
  92. package/dist/components/molecules/RadialMenu.svelte.d.ts +2 -0
  93. package/dist/components/molecules/RadioGroup.svelte +38 -23
  94. package/dist/components/molecules/RadioGroup.svelte.d.ts +2 -0
  95. package/dist/components/molecules/SectionHeader.svelte +13 -8
  96. package/dist/components/molecules/SeekSlider.svelte +38 -27
  97. package/dist/components/molecules/SeekSlider.svelte.d.ts +2 -0
  98. package/dist/components/molecules/SegmentedControl.svelte +139 -86
  99. package/dist/components/molecules/SegmentedControl.svelte.d.ts +2 -0
  100. package/dist/components/molecules/SelectButton.svelte +21 -6
  101. package/dist/components/molecules/SelectButton.svelte.d.ts +2 -0
  102. package/dist/components/molecules/SortableList.svelte +10 -11
  103. package/dist/components/molecules/SoundSettings.svelte +161 -0
  104. package/dist/components/molecules/SoundSettings.svelte.d.ts +17 -0
  105. package/dist/components/molecules/SplitButton.svelte +30 -3
  106. package/dist/components/molecules/SplitButton.svelte.d.ts +2 -0
  107. package/dist/components/molecules/SwipeRow.svelte +18 -15
  108. package/dist/components/molecules/SwipeRow.svelte.d.ts +2 -0
  109. package/dist/components/molecules/Tabs.svelte +92 -10
  110. package/dist/components/molecules/Tabs.svelte.d.ts +2 -0
  111. package/dist/components/molecules/ThemePicker.svelte +25 -10
  112. package/dist/components/molecules/Timestamp.svelte +12 -7
  113. package/dist/components/molecules/Toaster.svelte +65 -14
  114. package/dist/components/molecules/Toaster.svelte.d.ts +2 -0
  115. package/dist/components/molecules/Toggle.svelte +36 -13
  116. package/dist/components/molecules/Toggle.svelte.d.ts +2 -0
  117. package/dist/components/molecules/Tooltip.svelte +41 -10
  118. package/dist/components/molecules/Tooltip.svelte.d.ts +1 -1
  119. package/dist/components/molecules/VolumeSlider.svelte +34 -14
  120. package/dist/components/molecules/VolumeSlider.svelte.d.ts +2 -0
  121. package/dist/components/molecules/WorkingDir.svelte +1 -0
  122. package/dist/components/organisms/ConversationFeed.svelte +4 -0
  123. package/dist/components/organisms/DataTable.svelte +37 -14
  124. package/dist/floating.js +26 -0
  125. package/dist/index.d.ts +4 -0
  126. package/dist/index.js +4 -1
  127. package/dist/sound-synth.d.ts +3 -0
  128. package/dist/sound-synth.js +91 -0
  129. package/dist/sound.d.ts +1 -0
  130. package/dist/sound.js +3 -0
  131. package/dist/stores/sound.svelte.d.ts +20 -0
  132. package/dist/stores/sound.svelte.js +150 -0
  133. package/dist/stores/toast.svelte.d.ts +9 -0
  134. package/dist/stores/toast.svelte.js +45 -9
  135. package/dist/styles/reset.css +19 -2
  136. package/dist/styles/tokens.css +89 -6
  137. package/package.json +1 -1
@@ -136,15 +136,17 @@
136
136
 
137
137
  <style>
138
138
  .input {
139
+ --input-icon: var(--control-icon-md);
139
140
  width: 100%;
140
141
  min-height: var(--input-size, var(--control-height-default));
141
- padding: var(--sp-2) var(--sp-3);
142
+ padding: var(--sp-2) var(--control-px-md);
143
+ font-size: var(--control-fs-md);
142
144
  line-height: var(--lh-tight);
143
145
  background: var(--input-bg, var(--bg));
144
146
  border: 1px solid var(--input-border, var(--border-strong));
145
147
  border-radius: var(--input-radius, var(--r-md));
146
148
  color: var(--input-fg, var(--text));
147
- transition: border-color 0.12s var(--ease);
149
+ transition: border-color var(--dur-fast) ease;
148
150
  }
149
151
  .input:focus {
150
152
  outline: none;
@@ -154,21 +156,33 @@
154
156
  outline: var(--focus-ring);
155
157
  outline-offset: var(--focus-ring-offset);
156
158
  }
159
+ .input:disabled {
160
+ opacity: var(--disabled-opacity);
161
+ cursor: not-allowed;
162
+ }
157
163
  .input-sm {
158
164
  min-height: var(--input-size, var(--control-height-compact));
159
- padding: var(--sp-1) var(--sp-2);
160
- font-size: var(--fs-sm);
165
+ padding: var(--sp-1) var(--control-px-sm);
166
+ font-size: var(--control-fs-sm);
167
+ --input-icon: var(--control-icon-sm);
161
168
  }
162
169
  .input-lg {
163
170
  min-height: var(--input-size, var(--control-height-large));
164
- padding: var(--sp-3) var(--sp-4);
165
- font-size: max(16px, var(--fs-md));
171
+ padding: var(--sp-3) var(--control-px-lg);
172
+ font-size: var(--control-fs-lg);
173
+ --input-icon: var(--control-icon-lg);
166
174
  }
167
175
  /* iOS auto-zooms any field under 16px on focus; on touch the size modifiers
168
176
  carry their difference through padding and height alone. */
169
177
  @media (pointer: coarse) {
178
+ .input {
179
+ font-size: max(16px, var(--control-fs-md));
180
+ }
170
181
  .input-sm {
171
- font-size: max(16px, var(--fs-sm));
182
+ font-size: max(16px, var(--control-fs-sm));
183
+ }
184
+ .input-lg {
185
+ font-size: max(16px, var(--control-fs-lg));
172
186
  }
173
187
  .input-sm:not(.grouped) {
174
188
  min-height: max(var(--touch-target-compact), var(--input-size, var(--control-height-compact)));
@@ -192,8 +206,8 @@
192
206
  .input[aria-invalid='true']:focus {
193
207
  border-color: var(--danger);
194
208
  }
195
- /* Inside an InputGroup the group draws the focus ring and the overlaid
196
- adornments report their widths; the text stays clear of them. */
209
+ /* Inside an InputGroup the group draws the focus ring, dims the whole group
210
+ and the overlaid adornments report their widths; the text stays clear of them. */
197
211
  .input.grouped {
198
212
  width: 100%;
199
213
  border-radius: var(--ig-radius);
@@ -203,6 +217,9 @@
203
217
  .input.grouped:focus-visible {
204
218
  outline: none;
205
219
  }
220
+ .input.grouped:disabled {
221
+ opacity: 1;
222
+ }
206
223
  .mono {
207
224
  font-family: var(--font-mono);
208
225
  }
@@ -216,11 +233,18 @@
216
233
  .input-wrap .input {
217
234
  width: 100%;
218
235
  }
236
+ /* The wrap dims as one so the icon and the clear button fade with the field. */
237
+ .input-wrap:has(.input:disabled) {
238
+ opacity: var(--disabled-opacity);
239
+ }
240
+ .input-wrap .input:disabled {
241
+ opacity: 1;
242
+ }
219
243
  .has-icon {
220
- padding-inline-start: calc(var(--sp-3) + 1em + var(--sp-2));
244
+ padding-inline-start: calc(var(--control-px-md) + var(--input-icon) + var(--sp-2));
221
245
  }
222
246
  .has-clear {
223
- padding-inline-end: calc(var(--sp-3) + 1em + var(--sp-2));
247
+ padding-inline-end: calc(var(--control-px-md) + var(--input-icon) + var(--sp-2));
224
248
  }
225
249
  .input-icon,
226
250
  .input-clear {
@@ -229,13 +253,21 @@
229
253
  bottom: 0;
230
254
  display: flex;
231
255
  align-items: center;
256
+ font-size: var(--input-icon, var(--control-icon-md));
232
257
  color: var(--text-faint);
233
258
  pointer-events: none;
234
259
  }
260
+ .input-wrap:has(.input-sm) {
261
+ --input-icon: var(--control-icon-sm);
262
+ }
263
+ .input-wrap:has(.input-lg) {
264
+ --input-icon: var(--control-icon-lg);
265
+ }
235
266
  .input-icon {
236
- left: var(--sp-3);
267
+ left: var(--control-px-md);
237
268
  }
238
269
  .input-clear {
270
+ --clear-scale-dur: var(--dur-fast);
239
271
  right: var(--sp-2);
240
272
  pointer-events: auto;
241
273
  border: 0;
@@ -243,9 +275,31 @@
243
275
  padding: 0 var(--sp-1);
244
276
  cursor: pointer;
245
277
  border-radius: var(--r-sm);
278
+ transition:
279
+ color var(--dur-fast) ease,
280
+ opacity var(--dur-fast) ease,
281
+ scale var(--clear-scale-dur) var(--ease-out);
282
+ }
283
+ @starting-style {
284
+ .input-clear {
285
+ opacity: 0;
286
+ }
246
287
  }
247
- .input-clear:hover,
248
288
  .input-clear:focus-visible {
249
289
  color: var(--text);
290
+ outline: var(--focus-ring);
291
+ outline-offset: var(--focus-ring-offset-inset);
292
+ }
293
+ .input-clear:active {
294
+ --clear-scale-dur: var(--dur-press);
295
+ scale: var(--press-scale-sm);
296
+ }
297
+ @media (hover: hover) and (pointer: fine) {
298
+ .input:hover:not(:disabled, :focus, [aria-invalid='true']) {
299
+ border-color: var(--text-faint);
300
+ }
301
+ .input-clear:hover {
302
+ color: var(--text);
303
+ }
250
304
  }
251
305
  </style>
@@ -95,7 +95,7 @@
95
95
  .kbd-group {
96
96
  display: inline-flex;
97
97
  align-items: center;
98
- gap: 2px;
98
+ gap: var(--sp-0-5);
99
99
  font-size: var(--fs-xs);
100
100
  color: var(--text-muted);
101
101
  vertical-align: baseline;
@@ -106,7 +106,7 @@
106
106
  .kbd {
107
107
  font-family: var(--font-mono);
108
108
  font-size: inherit;
109
- line-height: 1.4;
109
+ line-height: var(--lh-snug);
110
110
  padding: 0 var(--sp-1);
111
111
  border: 1px solid var(--border-strong);
112
112
  border-bottom-width: 2px;
@@ -124,7 +124,7 @@
124
124
  white-space: nowrap;
125
125
  }
126
126
  .kbd-sep {
127
- font-size: 0.85em;
127
+ font-size: var(--fs-2xs);
128
128
  color: var(--text-faint);
129
129
  }
130
130
  </style>
@@ -56,6 +56,9 @@
56
56
  text-decoration: underline;
57
57
  font: inherit;
58
58
  text-align: start;
59
+ transition:
60
+ color var(--dur-fast) ease,
61
+ text-decoration-color var(--dur-fast) ease;
59
62
  }
60
63
  .tone-info {
61
64
  color: var(--info);
@@ -70,8 +73,10 @@
70
73
  .underline-none {
71
74
  text-decoration: none;
72
75
  }
73
- .underline-hover:hover {
74
- text-decoration: underline;
76
+ @media (hover: hover) and (pointer: fine) {
77
+ .underline-hover:hover {
78
+ text-decoration: underline;
79
+ }
75
80
  }
76
81
  .align-center {
77
82
  text-align: center;
@@ -95,7 +95,7 @@
95
95
  aria-valuemax={indeterminate ? undefined : max}
96
96
  aria-valuenow={indeterminate ? undefined : value}
97
97
  >
98
- <div class="bar" style={indeterminate ? undefined : `width: ${pct}%`}></div>
98
+ <div class="bar" style={indeterminate ? undefined : `--p: ${pct / 100}`}></div>
99
99
  {#each markers as m, i (`${i}:${m.at}`)}
100
100
  <span
101
101
  class="marker tone-{m.tone ? canonicalTone(m.tone) : 'text'}"
@@ -154,10 +154,12 @@
154
154
  height: 0.3125rem;
155
155
  }
156
156
  .bar {
157
+ width: 100%;
157
158
  height: 100%;
158
159
  background: var(--fill, var(--accent));
159
160
  border-radius: inherit;
160
- transition: width 0.2s var(--ease);
161
+ translate: calc((var(--p, 1) - 1) * 100%) 0;
162
+ transition: translate var(--dur-base) var(--ease-out);
161
163
  }
162
164
  .marker {
163
165
  position: absolute;
@@ -233,22 +235,22 @@
233
235
  }
234
236
  .progress.indeterminate .bar {
235
237
  width: 40%;
236
- animation: kt-progress-slide 1.1s ease-in-out infinite;
238
+ animation: kt-progress-slide 1.3s cubic-bezier(0.65, 0, 0.35, 1) infinite;
237
239
  }
238
240
  .progress.striped .bar {
239
241
  animation: kt-stripe 0.6s linear infinite;
240
242
  }
241
243
  .progress.striped.indeterminate .bar {
242
244
  animation:
243
- kt-progress-slide 1.1s ease-in-out infinite,
245
+ kt-progress-slide 1.3s cubic-bezier(0.65, 0, 0.35, 1) infinite,
244
246
  kt-stripe 0.6s linear infinite;
245
247
  }
246
248
  @keyframes kt-progress-slide {
247
249
  0% {
248
- transform: translateX(-110%);
250
+ transform: translateX(-100%);
249
251
  }
250
252
  100% {
251
- transform: translateX(310%);
253
+ transform: translateX(250%);
252
254
  }
253
255
  }
254
256
  @keyframes kt-stripe {
@@ -265,5 +267,9 @@
265
267
  .progress.striped.indeterminate .bar {
266
268
  animation: none;
267
269
  }
270
+ .progress.indeterminate .bar {
271
+ width: 100%;
272
+ opacity: 0.35;
273
+ }
268
274
  }
269
275
  </style>
@@ -88,16 +88,11 @@
88
88
  border: 0;
89
89
  background: color-mix(in srgb, var(--bg) 45%, transparent);
90
90
  cursor: default;
91
- animation: scrim-fade 0.18s var(--ease);
91
+ transition: opacity var(--dur-base) var(--ease-out);
92
92
  }
93
- @keyframes scrim-fade {
94
- from {
95
- opacity: 0;
96
- }
97
- }
98
- @media (prefers-reduced-motion: reduce) {
93
+ @starting-style {
99
94
  .scrim {
100
- animation: none;
95
+ opacity: 0;
101
96
  }
102
97
  }
103
98
  </style>
@@ -103,7 +103,7 @@
103
103
  >
104
104
  {#each segments as seg, i (i)}
105
105
  <div class="segment tone-{seg.tone ?? 'accent'}" style="flex-grow: {grow(seg)}" title={seg.label}>
106
- <div class="bar" style="width: {pct(seg)}%"></div>
106
+ <div class="bar" style="--p: {pct(seg) / 100}"></div>
107
107
  </div>
108
108
  {/each}
109
109
  {#if remainder > 0}
@@ -124,7 +124,7 @@
124
124
  >
125
125
  {#each segments as seg, i (i)}
126
126
  <div class="segment tone-{seg.tone ?? 'accent'}" style="flex-grow: {grow(seg)}" title={seg.label}>
127
- <div class="bar" style="width: {pct(seg)}%"></div>
127
+ <div class="bar" style="--p: {pct(seg) / 100}"></div>
128
128
  </div>
129
129
  {/each}
130
130
  </div>
@@ -180,9 +180,11 @@
180
180
  border-bottom-right-radius: var(--r-pill);
181
181
  }
182
182
  .bar {
183
+ width: 100%;
183
184
  height: 100%;
184
185
  background: var(--fill, var(--accent));
185
- transition: width 0.2s var(--ease);
186
+ translate: calc((var(--p, 1) - 1) * 100%) 0;
187
+ transition: translate var(--dur-base) var(--ease-out);
186
188
  }
187
189
  .tone-success,
188
190
  .tone-ok {
@@ -210,7 +212,6 @@
210
212
  min-width: 0;
211
213
  border-radius: 0;
212
214
  background: transparent;
213
- transition: flex-grow 0.2s var(--ease);
214
215
  }
215
216
 
216
217
  .segmented-progress-wrap {
@@ -171,7 +171,7 @@
171
171
  {#if hasFace}
172
172
  <span class="select-face" class:compact={small} aria-hidden="true">
173
173
  {#if selected?.icon}
174
- <Icon name={selected.icon} size={small ? 14 : 16} />
174
+ <Icon name={selected.icon} />
175
175
  {:else if selected?.emoji}
176
176
  <span class="select-emoji">{selected.emoji}</span>
177
177
  {/if}
@@ -183,7 +183,7 @@
183
183
  {/if}
184
184
  {#if showChevron}
185
185
  <span class="select-chevron" aria-hidden="true">
186
- <Icon name="chevron-down" size={16} />
186
+ <Icon name="chevron-down" />
187
187
  </span>
188
188
  {/if}
189
189
  </div>
@@ -191,6 +191,7 @@
191
191
 
192
192
  <style>
193
193
  .select-wrap {
194
+ --select-icon: var(--control-icon-md);
194
195
  position: relative;
195
196
  display: block;
196
197
  width: 100%;
@@ -203,39 +204,46 @@
203
204
  flex: 1 1 0;
204
205
  min-width: 0;
205
206
  }
207
+ .select-wrap:has(.select.compact) {
208
+ --select-icon: var(--control-icon-sm);
209
+ }
210
+ .select-wrap:has(.select.select-lg) {
211
+ --select-icon: var(--control-icon-lg);
212
+ }
206
213
  .select {
207
214
  width: 100%;
208
215
  min-height: var(--select-size, var(--control-height-default));
209
- padding: var(--sp-2) var(--sp-3);
216
+ padding: var(--sp-2) var(--control-px-md);
217
+ font-size: var(--control-fs-md);
210
218
  line-height: var(--lh-tight);
211
219
  background: var(--select-bg, var(--bg));
212
220
  border: 1px solid var(--select-border, var(--border-strong));
213
221
  border-radius: var(--select-radius, var(--r-md));
214
222
  color: var(--select-fg, var(--text));
215
- transition: border-color 0.12s var(--ease);
223
+ transition: border-color var(--dur-fast) ease;
216
224
  }
217
225
  /* Default variant: drop the OS chevron, reserve room for our own. */
218
226
  .select-wrap .select {
219
227
  appearance: none;
220
228
  -webkit-appearance: none;
221
- padding-right: calc(var(--sp-3) + 1.25rem);
229
+ padding-right: calc(var(--control-px-md) + var(--select-icon) + var(--sp-1));
222
230
  }
223
231
  /* No custom chevron: reclaim the reserved right padding. */
224
232
  .select-wrap.no-chevron .select {
225
- padding-right: var(--sp-3);
233
+ padding-right: var(--control-px-md);
226
234
  }
227
- /* Compact inline form for dense headers/toolbars. */
228
235
  .select.select-lg {
229
236
  min-height: var(--select-size, var(--control-height-large));
230
- padding: var(--sp-3) var(--sp-4);
231
- font-size: max(16px, var(--fs-md));
237
+ padding: var(--sp-3) var(--control-px-lg);
238
+ font-size: var(--control-fs-lg);
232
239
  }
240
+ /* Compact inline form for dense headers/toolbars. */
233
241
  .select.compact {
234
- padding: var(--sp-1) var(--sp-2);
235
- font-size: var(--fs-xs);
242
+ padding: var(--sp-1) var(--control-px-sm);
243
+ font-size: var(--control-fs-sm);
236
244
  }
237
245
  .select-wrap:not(.no-chevron) .select.compact {
238
- padding-right: calc(var(--sp-2) + 1rem);
246
+ padding-right: calc(var(--control-px-sm) + var(--select-icon) + var(--sp-1));
239
247
  }
240
248
  /* Toolbar contract: size="sm" shares the compact control height so it lines up
241
249
  with Button size="sm", Popover size="sm" and SegmentedControl size="sm". */
@@ -263,6 +271,13 @@
263
271
  .select[aria-invalid='true']:focus {
264
272
  border-color: var(--danger);
265
273
  }
274
+ .select:disabled {
275
+ cursor: not-allowed;
276
+ }
277
+ /* The wrap dims as one so the face and the chevron fade with the control. */
278
+ .select-wrap:has(.select:disabled) {
279
+ opacity: var(--disabled-opacity);
280
+ }
266
281
  /* The face draws the trigger text; the native text underneath stays laid out
267
282
  (so `width="auto"` still sizes to it) but invisible. Popup options keep
268
283
  their own colour so the transparency does not inherit into the list. */
@@ -280,38 +295,45 @@
280
295
  display: flex;
281
296
  align-items: center;
282
297
  gap: var(--sp-2);
283
- padding: 0 var(--sp-3);
284
- padding-right: calc(var(--sp-3) + 1.25rem);
298
+ padding: 0 var(--control-px-md);
299
+ padding-right: calc(var(--control-px-md) + var(--select-icon) + var(--sp-1));
300
+ font-size: var(--control-fs-md);
285
301
  color: var(--select-fg, var(--text));
286
302
  pointer-events: none;
287
303
  overflow: hidden;
288
304
  }
305
+ .select-face > :global(svg) {
306
+ flex: none;
307
+ font-size: var(--select-icon);
308
+ }
289
309
  .select-wrap.no-chevron .select-face {
290
- padding-right: var(--sp-3);
310
+ padding-right: var(--control-px-md);
291
311
  }
292
312
  .select-face.compact {
293
- padding: 0 var(--sp-2);
294
- padding-right: calc(var(--sp-2) + 1rem);
295
- font-size: var(--fs-xs);
313
+ padding: 0 var(--control-px-sm);
314
+ padding-right: calc(var(--control-px-sm) + var(--select-icon) + var(--sp-1));
315
+ font-size: var(--control-fs-sm);
296
316
  }
297
317
  .select-wrap.no-chevron .select-face.compact {
298
- padding-right: var(--sp-2);
318
+ padding-right: var(--control-px-sm);
299
319
  }
300
320
  /* iOS auto-zooms any field under 16px on focus; on touch the size modifiers
301
321
  carry their difference through padding and height alone. */
302
322
  @media (pointer: coarse) {
303
- .select.compact {
304
- font-size: max(16px, var(--fs-xs));
323
+ .select,
324
+ .select-face {
325
+ font-size: max(16px, var(--control-fs-md));
305
326
  }
327
+ .select.select-lg {
328
+ font-size: max(16px, var(--control-fs-lg));
329
+ }
330
+ .select.compact,
306
331
  .select-face.compact {
307
- font-size: max(16px, var(--fs-xs));
332
+ font-size: max(16px, var(--control-fs-sm));
308
333
  }
309
334
  }
310
- .select:disabled ~ .select-face {
311
- color: var(--text-muted);
312
- }
313
335
  .select-emoji {
314
- line-height: 1;
336
+ line-height: var(--lh-none);
315
337
  }
316
338
  .select-label {
317
339
  flex: 1 1 auto;
@@ -330,12 +352,21 @@
330
352
  .select-chevron {
331
353
  position: absolute;
332
354
  top: 50%;
333
- right: var(--sp-3);
355
+ right: var(--control-px-md);
334
356
  transform: translateY(-50%);
335
357
  display: inline-flex;
358
+ font-size: var(--select-icon);
336
359
  color: var(--text-muted);
337
360
  pointer-events: none; /* clicks fall through to the select */
338
361
  }
362
+ .select-wrap:has(.select.compact) .select-chevron {
363
+ right: var(--control-px-sm);
364
+ }
365
+ @media (hover: hover) and (pointer: fine) {
366
+ .select:hover:not(:disabled, :focus, [aria-invalid='true'], .ghost, .embedded) {
367
+ border-color: var(--text-faint);
368
+ }
369
+ }
339
370
  /* Transparent overlay: fills the positioned parent, the trigger shows through. */
340
371
  .select.ghost {
341
372
  position: absolute;
@@ -2,6 +2,8 @@
2
2
  import type { HTMLAttributes } from 'svelte/elements';
3
3
  // Shimmering placeholder bar(s) standing in for content that is still
4
4
  // loading. Decorative only — the surrounding region should carry aria-busy.
5
+ // Bars are tinted from --text so they read on any surface; the sweep is
6
+ // viewport-anchored so every bar on screen shimmers in sync.
5
7
  type Own = {
6
8
  width?: string;
7
9
  height?: string;
@@ -46,24 +48,28 @@
46
48
  max-width: 100%;
47
49
  }
48
50
  .skeleton-bar {
51
+ --sk-base: var(--skeleton, color-mix(in srgb, var(--text) 7%, transparent));
52
+ --sk-hi: var(--skeleton-highlight, color-mix(in srgb, var(--text) 13%, transparent));
49
53
  display: block;
50
54
  width: 100%;
51
- background: linear-gradient(90deg, var(--bg-elevated-2) 25%, var(--bg-elevated) 50%, var(--bg-elevated-2) 75%);
52
- background-size: 200% 100%;
53
- animation: tsu-shimmer 1.4s ease-in-out infinite;
55
+ background: linear-gradient(100deg, var(--sk-base) 42%, var(--sk-hi) 50%, var(--sk-base) 58%) var(--sk-base);
56
+ background-size: 200vw 100%;
57
+ background-attachment: fixed;
58
+ animation: tsu-shimmer 1.8s linear infinite;
54
59
  }
55
60
  @keyframes tsu-shimmer {
56
- from {
57
- background-position: 200% 0;
61
+ 0% {
62
+ background-position: 100% 0;
58
63
  }
59
- to {
60
- background-position: -200% 0;
64
+ 75%,
65
+ 100% {
66
+ background-position: 0% 0;
61
67
  }
62
68
  }
63
69
  @media (prefers-reduced-motion: reduce) {
64
70
  .skeleton-bar {
65
71
  animation: none;
66
- background: var(--bg-elevated-2);
72
+ background: var(--sk-base);
67
73
  }
68
74
  }
69
75
  </style>