@dorsk/tsumikit 0.77.0 → 0.79.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 (62) hide show
  1. package/dist/components/atoms/Artwork.svelte +5 -3
  2. package/dist/components/atoms/Badge.svelte +1 -1
  3. package/dist/components/atoms/Button.svelte +24 -8
  4. package/dist/components/atoms/Card.svelte +18 -12
  5. package/dist/components/atoms/Checkbox.svelte +4 -2
  6. package/dist/components/atoms/Gauge.svelte +2 -2
  7. package/dist/components/atoms/Input.svelte +6 -3
  8. package/dist/components/atoms/Kbd.svelte +1 -1
  9. package/dist/components/atoms/Progress.svelte +1 -1
  10. package/dist/components/atoms/SegmentedProgress.svelte +2 -2
  11. package/dist/components/atoms/Select.svelte +9 -3
  12. package/dist/components/atoms/Slider.svelte +8 -6
  13. package/dist/components/atoms/Swatch.svelte +1 -1
  14. package/dist/components/atoms/Switch.svelte +3 -2
  15. package/dist/components/atoms/Textarea.svelte +6 -3
  16. package/dist/components/layouts/AppShell.svelte +7 -6
  17. package/dist/components/layouts/MasterDetail.svelte +3 -3
  18. package/dist/components/layouts/NavBar.svelte +7 -4
  19. package/dist/components/layouts/NavSection.svelte +1 -1
  20. package/dist/components/layouts/ResizablePanel.svelte +7 -7
  21. package/dist/components/layouts/TabBar.svelte +2 -2
  22. package/dist/components/molecules/Accordion.svelte +2 -2
  23. package/dist/components/molecules/AttachmentList.svelte +2 -2
  24. package/dist/components/molecules/Callout.svelte +5 -5
  25. package/dist/components/molecules/CapBar.svelte +2 -2
  26. package/dist/components/molecules/ChatBubble.svelte +4 -0
  27. package/dist/components/molecules/CodeBlock.svelte +12 -5
  28. package/dist/components/molecules/Combobox.svelte +3 -3
  29. package/dist/components/molecules/Drawer.svelte +8 -8
  30. package/dist/components/molecules/EmojiPicker.svelte +1 -1
  31. package/dist/components/molecules/FileButton.svelte +16 -4
  32. package/dist/components/molecules/FilterInput.svelte +6 -5
  33. package/dist/components/molecules/GitRef.svelte +2 -2
  34. package/dist/components/molecules/GlyphStack.svelte +21 -3
  35. package/dist/components/molecules/InputGroup.svelte +2 -2
  36. package/dist/components/molecules/Modal.svelte +5 -5
  37. package/dist/components/molecules/OptionButton.svelte +8 -3
  38. package/dist/components/molecules/Pagination.svelte +3 -1
  39. package/dist/components/molecules/Popover.svelte +18 -11
  40. package/dist/components/molecules/Prose.svelte +6 -6
  41. package/dist/components/molecules/RadialMenu.svelte +3 -3
  42. package/dist/components/molecules/RadioGroup.svelte +6 -4
  43. package/dist/components/molecules/RichSelect.svelte +6 -4
  44. package/dist/components/molecules/SectionHeader.svelte +1 -1
  45. package/dist/components/molecules/SeekSlider.svelte +6 -6
  46. package/dist/components/molecules/SegmentedControl.svelte +7 -7
  47. package/dist/components/molecules/SortableList.svelte +2 -2
  48. package/dist/components/molecules/SplitButton.svelte +1 -1
  49. package/dist/components/molecules/StatusBar.svelte +2 -0
  50. package/dist/components/molecules/Tabs.svelte +3 -3
  51. package/dist/components/molecules/ThemePicker.svelte +1 -1
  52. package/dist/components/molecules/Timestamp.svelte +1 -1
  53. package/dist/components/molecules/Toggle.svelte +5 -3
  54. package/dist/components/molecules/Tooltip.svelte +2 -2
  55. package/dist/components/molecules/Truncate.svelte +21 -3
  56. package/dist/components/molecules/VolumeSlider.svelte +3 -3
  57. package/dist/components/organisms/ConversationFeed.svelte +2 -1
  58. package/dist/components/organisms/ConversationPanel.svelte +3 -3
  59. package/dist/components/organisms/DataTable.svelte +18 -16
  60. package/dist/components/organisms/FilterSearchBar.svelte +8 -2
  61. package/dist/styles/tokens.css +34 -0
  62. package/package.json +1 -1
@@ -542,11 +542,11 @@
542
542
  width: max(var(--radial-petal-size, 3.5rem), var(--touch-target));
543
543
  height: max(var(--radial-petal-size, 3.5rem), var(--touch-target));
544
544
  padding: 0 var(--sp-0-5);
545
- border: 1px solid var(--border-strong);
545
+ border: var(--edge-width) solid var(--raised-edge);
546
546
  border-radius: 50%;
547
- background: var(--bg-elevated);
547
+ background: var(--raised-fill);
548
548
  color: var(--text);
549
- box-shadow: var(--shadow-md);
549
+ box-shadow: var(--raised-shadow);
550
550
  font-size: var(--fs-xs);
551
551
  line-height: var(--lh-heading);
552
552
  translate: -50% -50%;
@@ -172,9 +172,10 @@
172
172
  width: var(--chip-sm);
173
173
  height: var(--chip-sm);
174
174
  margin-top: var(--sp-px);
175
- border: 1px solid var(--border-strong);
175
+ border: var(--edge-width) solid var(--control-edge);
176
176
  border-radius: var(--r-pill);
177
- background: var(--bg);
177
+ background: var(--control-fill);
178
+ box-shadow: var(--control-shadow);
178
179
  transition: border-color var(--dur-fast) var(--ease);
179
180
  }
180
181
  .dot-ctl::after {
@@ -205,6 +206,7 @@
205
206
  input:focus-visible + .dot-ctl {
206
207
  outline: var(--focus-ring);
207
208
  outline-offset: var(--focus-ring-offset);
209
+ box-shadow: var(--control-shadow), var(--focus-glow);
208
210
  }
209
211
  .texts {
210
212
  display: flex;
@@ -231,7 +233,7 @@
231
233
  min-width: 0;
232
234
  gap: var(--sp-2);
233
235
  padding: var(--pad, var(--sp-2) var(--sp-3));
234
- border: 1px solid var(--border);
236
+ border: var(--edge-width) solid var(--surface-edge);
235
237
  border-radius: var(--r-md);
236
238
  transition:
237
239
  border-color var(--dur-fast) var(--ease),
@@ -239,7 +241,7 @@
239
241
  }
240
242
  .row.selected {
241
243
  border-color: var(--accent-dim);
242
- background: var(--bg-elevated);
244
+ background: var(--surface-fill);
243
245
  }
244
246
  .row .radio {
245
247
  flex: 1 1 auto;
@@ -431,9 +431,10 @@
431
431
  min-width: 0;
432
432
  min-height: var(--rs-height);
433
433
  padding: var(--sp-1) var(--sp-2) var(--sp-1) var(--sp-1);
434
- border: 1px solid var(--border-strong);
434
+ border: var(--edge-width) solid var(--control-edge);
435
435
  border-radius: var(--r-md);
436
436
  background: var(--surface);
437
+ box-shadow: var(--control-shadow);
437
438
  color: var(--text);
438
439
  text-align: start;
439
440
  cursor: pointer;
@@ -444,6 +445,7 @@
444
445
  .rich-select :global(.pop-trigger.rs-trigger:focus-visible) {
445
446
  outline: var(--focus-ring);
446
447
  outline-offset: var(--focus-ring-offset);
448
+ box-shadow: var(--control-shadow), var(--focus-glow);
447
449
  }
448
450
  .rich-select :global(.pop-trigger.rs-trigger:active:not(:disabled)) {
449
451
  scale: var(--press-scale-lg);
@@ -534,8 +536,8 @@
534
536
  }
535
537
  .rs-row[data-dragging] {
536
538
  z-index: 1;
537
- box-shadow: var(--shadow-md);
538
- background: var(--bg-elevated);
539
+ box-shadow: var(--raised-shadow);
540
+ background: var(--raised-fill);
539
541
  transition: none;
540
542
  }
541
543
  .rs-option {
@@ -587,6 +589,6 @@
587
589
  display: flex;
588
590
  flex-direction: column;
589
591
  padding-top: var(--sp-1);
590
- border-top: 1px solid var(--border);
592
+ border-top: var(--edge-width) solid var(--surface-edge);
591
593
  }
592
594
  </style>
@@ -172,7 +172,7 @@
172
172
  }
173
173
  .sh-divider > .sh-row {
174
174
  padding-bottom: var(--sp-2);
175
- border-bottom: 1px solid var(--border);
175
+ border-bottom: var(--edge-width) solid var(--surface-edge);
176
176
  }
177
177
  .sh-group > .sh-row {
178
178
  flex-wrap: nowrap;
@@ -276,7 +276,7 @@
276
276
  height: var(--seek-track);
277
277
  margin-top: calc(var(--seek-track) / -2);
278
278
  border-radius: var(--r-pill);
279
- background: var(--bg-elevated-2);
279
+ background: var(--track-fill);
280
280
  overflow: hidden;
281
281
  transform-origin: center;
282
282
  transition: scale var(--dur-fast) var(--ease);
@@ -322,7 +322,7 @@
322
322
  border-radius: var(--r-pill);
323
323
  background: var(--seek-accent);
324
324
  border: 2px solid var(--bg);
325
- box-shadow: var(--shadow-sm);
325
+ box-shadow: var(--thumb-shadow);
326
326
  transform: translate(-50%, -50%);
327
327
  scale: 0.6;
328
328
  opacity: 0;
@@ -346,7 +346,7 @@
346
346
  .seek:not(.seek--inert):hover .seek-thumb {
347
347
  opacity: 1;
348
348
  scale: 1;
349
- box-shadow: var(--shadow-sm), var(--seek-halo);
349
+ box-shadow: var(--thumb-shadow), var(--seek-halo);
350
350
  }
351
351
  .seek--dragging .seek-thumb {
352
352
  scale: 1.15;
@@ -370,9 +370,9 @@
370
370
  gap: var(--sp-1);
371
371
  padding: var(--sp-1) var(--sp-2);
372
372
  border-radius: var(--r-sm);
373
- background: var(--bg-elevated);
374
- border: 1px solid var(--border);
375
- box-shadow: var(--shadow-md);
373
+ background: var(--raised-fill);
374
+ border: var(--edge-width) solid var(--surface-edge);
375
+ box-shadow: var(--raised-shadow);
376
376
  color: var(--text);
377
377
  font-size: var(--fs-xs);
378
378
  font-variant-numeric: tabular-nums;
@@ -238,7 +238,7 @@
238
238
  items fill the inside, which is the height minus border and padding. */
239
239
  .seg {
240
240
  --seg-h: var(--control-md);
241
- --seg-inset: calc(var(--sp-0-5) + 1px);
241
+ --seg-inset: calc(var(--sp-0-5) + var(--edge-width));
242
242
  --seg-item-h: calc(var(--seg-h) - 2 * var(--seg-inset));
243
243
  position: relative;
244
244
  display: inline-flex;
@@ -247,8 +247,8 @@
247
247
  height: var(--seg-h);
248
248
  min-height: var(--seg-h);
249
249
  padding: var(--sp-0-5);
250
- background: var(--bg-elevated-2);
251
- border: 1px solid var(--border);
250
+ background: var(--track-fill);
251
+ border: var(--edge-width) solid var(--track-edge);
252
252
  border-radius: var(--r-pill);
253
253
  max-width: 100%;
254
254
  min-width: 0;
@@ -326,8 +326,8 @@
326
326
  width: 0;
327
327
  height: 0;
328
328
  border-radius: var(--r-pill);
329
- background: var(--bg);
330
- box-shadow: var(--shadow-sm);
329
+ background: var(--thumb-fill);
330
+ box-shadow: var(--thumb-shadow);
331
331
  transform-origin: top left;
332
332
  pointer-events: none;
333
333
  transition:
@@ -430,8 +430,8 @@
430
430
  }
431
431
  .seg-item.selected {
432
432
  color: var(--text);
433
- background: var(--bg);
434
- box-shadow: var(--shadow-sm);
433
+ background: var(--thumb-fill);
434
+ box-shadow: var(--thumb-shadow);
435
435
  }
436
436
  .seg.placed .seg-item.selected {
437
437
  background: transparent;
@@ -571,7 +571,7 @@
571
571
  }
572
572
  .sl-row {
573
573
  position: relative;
574
- border-bottom: 1px solid var(--border);
574
+ border-bottom: var(--edge-width) solid var(--surface-edge);
575
575
  }
576
576
  .sl-row:last-child {
577
577
  border-bottom: 0;
@@ -609,7 +609,7 @@
609
609
  position: relative;
610
610
  z-index: 1;
611
611
  background: var(--bg-elevated-2);
612
- box-shadow: var(--shadow-md);
612
+ box-shadow: var(--raised-shadow);
613
613
  transition: none;
614
614
  }
615
615
  .sl-grip,
@@ -168,7 +168,7 @@
168
168
  position: relative;
169
169
  width: var(--split-height);
170
170
  flex: none;
171
- margin-inline-start: -1px;
171
+ margin-inline-start: calc(-1 * var(--edge-width));
172
172
  --pop-trigger-radius: 0 var(--r-md) var(--r-md) 0;
173
173
  --pop-trigger-pad: 0;
174
174
  }
@@ -74,6 +74,8 @@
74
74
  .status-label {
75
75
  flex: 1;
76
76
  min-width: 0;
77
+ padding-block: calc(var(--focus-ring-width) + var(--focus-ring-offset));
78
+ margin-block: calc(-1 * (var(--focus-ring-width) + var(--focus-ring-offset)));
77
79
  overflow: hidden;
78
80
  text-overflow: ellipsis;
79
81
  white-space: nowrap;
@@ -297,7 +297,7 @@
297
297
  flex: 1 1 auto;
298
298
  min-width: 0;
299
299
  gap: var(--sp-1);
300
- border-bottom: 1px solid var(--border);
300
+ border-bottom: var(--edge-width) solid var(--surface-edge);
301
301
  overflow-x: auto;
302
302
  overflow-y: hidden;
303
303
  scrollbar-width: thin;
@@ -330,7 +330,7 @@
330
330
  font-weight: var(--fw-medium);
331
331
  --icon-size: var(--control-icon-md);
332
332
  border-bottom: 2px solid transparent;
333
- margin-bottom: -1px;
333
+ margin-bottom: calc(-1 * var(--edge-width));
334
334
  max-width: var(--tab-max-width, none);
335
335
  transition:
336
336
  color var(--dur-fast) var(--ease),
@@ -373,7 +373,7 @@
373
373
  align-items: center;
374
374
  gap: var(--sp-1);
375
375
  padding-inline-start: var(--sp-2);
376
- border-bottom: 1px solid var(--border);
376
+ border-bottom: var(--edge-width) solid var(--surface-edge);
377
377
  }
378
378
  .tabpanel {
379
379
  padding-top: var(--sp-4);
@@ -257,7 +257,7 @@
257
257
  margin-top: var(--sp-2);
258
258
  padding: var(--sp-1) var(--sp-2);
259
259
  border: 2px solid transparent;
260
- border-top: 1px solid var(--border);
260
+ border-top: var(--edge-width) solid var(--surface-edge);
261
261
  border-radius: var(--r-md);
262
262
  background: none;
263
263
  color: inherit;
@@ -226,7 +226,7 @@
226
226
  .ts-mode {
227
227
  flex: 1;
228
228
  padding: var(--sp-1) var(--sp-2);
229
- border: 1px solid var(--border-strong);
229
+ border: var(--edge-width) solid var(--btn-edge);
230
230
  border-radius: var(--r-sm);
231
231
  background: transparent;
232
232
  color: var(--text-muted);
@@ -82,15 +82,16 @@
82
82
  font-weight: var(--fw-medium);
83
83
  line-height: var(--lh-none);
84
84
  --icon-size: var(--control-icon-sm);
85
- background: var(--bg-elevated-2);
85
+ background: var(--surface-fill-2);
86
86
  color: var(--text-muted);
87
- border: 1px solid var(--border);
87
+ border: var(--edge-width) solid var(--surface-edge);
88
88
  white-space: nowrap;
89
89
  user-select: none;
90
90
  transition:
91
91
  background var(--dur-fast) var(--ease),
92
92
  border-color var(--dur-fast) var(--ease),
93
93
  color var(--dur-fast) var(--ease),
94
+ translate var(--dur-fast) var(--ease),
94
95
  scale var(--dur-fast) var(--ease-out);
95
96
  }
96
97
  .toggle:disabled {
@@ -125,7 +126,8 @@
125
126
  }
126
127
  @media (hover: hover) and (pointer: fine) {
127
128
  .toggle:hover:not(:disabled) {
128
- border-color: var(--border-strong);
129
+ border-color: var(--surface-edge-strong);
130
+ translate: 0 calc(-1 * var(--hover-lift));
129
131
  }
130
132
  }
131
133
  .toggle:active:not(:disabled) {
@@ -206,9 +206,9 @@
206
206
  padding: var(--sp-1) var(--sp-2);
207
207
  background: var(--bg-elevated-2);
208
208
  color: var(--text);
209
- border: 1px solid var(--border-strong);
209
+ border: var(--edge-width) solid var(--raised-edge);
210
210
  border-radius: var(--r-sm);
211
- box-shadow: var(--shadow-md);
211
+ box-shadow: var(--raised-shadow);
212
212
  font-size: var(--fs-xs);
213
213
  line-height: var(--lh-snug);
214
214
  white-space: normal;
@@ -9,6 +9,7 @@
9
9
  // observed and the longest candidate that fits is shown (mode `path`
10
10
  // abbreviates fish-style). `copyable` copies the full text on click.
11
11
  import { copyToClipboard } from '../../clipboard';
12
+ import { untrack } from 'svelte';
12
13
  import { pathCandidates, truncate, type TruncateMode } from '../../truncate';
13
14
  import Tooltip from './Tooltip.svelte';
14
15
 
@@ -72,15 +73,18 @@
72
73
  let probe = $state<HTMLSpanElement | null>(null);
73
74
  let avail = $state(Number.POSITIVE_INFINITY);
74
75
  let chPx = $state(8);
76
+ let cap = $state(Number.POSITIVE_INFINITY);
75
77
 
76
78
  $effect(() => {
77
79
  if (!fit || !rail) return;
78
80
  const el = rail;
79
81
  const measure = () => {
80
- avail = el.clientWidth;
82
+ const w = el.clientWidth;
83
+ if (w > avail) cap = Number.POSITIVE_INFINITY;
84
+ avail = w;
81
85
  if (probe) chPx = probe.getBoundingClientRect().width / 10 || chPx;
82
86
  };
83
- measure();
87
+ untrack(measure);
84
88
  const ro = new ResizeObserver(measure);
85
89
  ro.observe(el);
86
90
  return () => ro.disconnect();
@@ -88,7 +92,7 @@
88
92
 
89
93
  const shown = $derived.by(() => {
90
94
  if (fit) {
91
- const budget = Math.max(0, avail - 1);
95
+ const budget = Math.max(0, Math.min(avail - 1, cap));
92
96
  return candidates.find((c) => [...c].length * chPx <= budget) ?? candidates[candidates.length - 1];
93
97
  }
94
98
  if (max === undefined) return text;
@@ -96,6 +100,17 @@
96
100
  });
97
101
  const isTruncated = $derived(shown !== text);
98
102
 
103
+ // The per-character estimate can undershoot (glyph fallbacks, late fonts): cap the budget below the spilling candidate.
104
+ $effect(() => {
105
+ if (!fit || !rail || shown === candidates[candidates.length - 1]) return;
106
+ const el = rail;
107
+ const id = requestAnimationFrame(() => {
108
+ const over = el.scrollWidth - el.clientWidth;
109
+ if (over > 0) cap = Math.min(untrack(() => cap), [...shown].length * chPx - over);
110
+ });
111
+ return () => cancelAnimationFrame(id);
112
+ });
113
+
99
114
  let status = $state('');
100
115
  let timer: ReturnType<typeof setTimeout> | undefined;
101
116
  async function copy(e: MouseEvent) {
@@ -173,6 +188,9 @@
173
188
  max-width: 100%;
174
189
  overflow: hidden;
175
190
  }
191
+ .rail .trunc:focus-visible {
192
+ outline-offset: var(--focus-ring-offset-inset);
193
+ }
176
194
  .grow {
177
195
  flex: 1 1 0;
178
196
  }
@@ -306,7 +306,7 @@
306
306
  height: var(--vol-track);
307
307
  margin-top: calc(var(--vol-track) / -2);
308
308
  border-radius: var(--r-pill);
309
- background: var(--bg-elevated-2);
309
+ background: var(--track-fill);
310
310
  overflow: hidden;
311
311
  }
312
312
  .vol--vertical .vol-track {
@@ -354,7 +354,7 @@
354
354
  border-radius: var(--r-pill);
355
355
  background: var(--vol-accent);
356
356
  border: 2px solid var(--bg);
357
- box-shadow: var(--shadow-sm);
357
+ box-shadow: var(--thumb-shadow);
358
358
  transform: translate(-50%, -50%);
359
359
  scale: 0.6;
360
360
  opacity: 0;
@@ -375,7 +375,7 @@
375
375
  .vol-slab:not([aria-disabled='true']):hover .vol-thumb {
376
376
  opacity: 1;
377
377
  scale: 1;
378
- box-shadow: var(--shadow-sm), var(--vol-halo);
378
+ box-shadow: var(--thumb-shadow), var(--vol-halo);
379
379
  }
380
380
  .vol--dragging .vol-thumb {
381
381
  scale: 1.15;
@@ -154,6 +154,7 @@
154
154
  min-height: 0;
155
155
  }
156
156
  .feed {
157
+ position: relative;
157
158
  flex: 1;
158
159
  min-height: 0;
159
160
  overflow: auto;
@@ -180,6 +181,6 @@
180
181
  margin-inline: auto;
181
182
  z-index: 1;
182
183
  border-radius: var(--r-pill);
183
- box-shadow: var(--shadow-md);
184
+ box-shadow: var(--raised-shadow);
184
185
  }
185
186
  </style>
@@ -45,7 +45,7 @@
45
45
  gap: var(--sp-2);
46
46
  min-width: 0;
47
47
  padding: var(--sp-2) var(--sp-3);
48
- border-bottom: 1px solid var(--border);
48
+ border-bottom: var(--edge-width) solid var(--surface-edge);
49
49
  }
50
50
  .panel-body {
51
51
  flex: 1;
@@ -55,12 +55,12 @@
55
55
  }
56
56
  .panel-status {
57
57
  flex: none;
58
- border-top: 1px solid var(--border);
58
+ border-top: var(--edge-width) solid var(--surface-edge);
59
59
  }
60
60
  .panel-composer {
61
61
  flex: none;
62
62
  padding: var(--sp-2) var(--sp-3) var(--sp-3);
63
- border-top: 1px solid var(--border);
63
+ border-top: var(--edge-width) solid var(--surface-edge);
64
64
  }
65
65
  .panel-status + .panel-composer {
66
66
  border-top: 0;
@@ -239,6 +239,7 @@
239
239
  <th
240
240
  scope="col"
241
241
  data-hide-below={col.hideBelow}
242
+ class:dt-sortable={col.sortable && !headerSnippets[col.key]}
242
243
  style:width={col.width}
243
244
  style:text-align={col.align ?? 'left'}
244
245
  aria-sort={col.sortable
@@ -363,7 +364,7 @@
363
364
  width: 100%;
364
365
  overflow-x: auto;
365
366
  -webkit-overflow-scrolling: touch;
366
- border: 1px solid var(--border);
367
+ border: var(--edge-width) solid var(--surface-edge);
367
368
  border-radius: var(--r-lg);
368
369
  container-type: inline-size;
369
370
  }
@@ -382,7 +383,7 @@
382
383
  th,
383
384
  td {
384
385
  padding: var(--sp-2) var(--sp-3);
385
- border-bottom: 1px solid var(--border);
386
+ border-bottom: var(--edge-width) solid var(--surface-edge);
386
387
  }
387
388
  .dt.sm th,
388
389
  .dt.sm td {
@@ -394,7 +395,7 @@
394
395
  color: var(--text-muted);
395
396
  text-transform: uppercase;
396
397
  letter-spacing: 0.04em;
397
- background: var(--bg-elevated-2);
398
+ background: var(--surface-fill-2);
398
399
  white-space: nowrap;
399
400
  }
400
401
  .dt.sticky th {
@@ -430,6 +431,15 @@
430
431
  color: inherit;
431
432
  cursor: pointer;
432
433
  }
434
+ th.dt-sortable {
435
+ position: relative;
436
+ }
437
+ /* The whole header cell is the sort hit area. */
438
+ .dt-sort::after {
439
+ content: '';
440
+ position: absolute;
441
+ inset: 0;
442
+ }
433
443
  .dt-arrow {
434
444
  display: inline-block;
435
445
  opacity: 0.4;
@@ -527,17 +537,9 @@
527
537
  tbody tr:last-child td :global(.checkbox::before) {
528
538
  inset-block-end: 0;
529
539
  }
530
- /* Sort slab: inline-end stays at 0 so it never reaches the next header
531
- cell, and the inline-start reach stays inside the cell's own padding. */
532
- .dt-sort {
533
- position: relative;
534
- }
535
- .dt-sort::before {
536
- content: '';
537
- position: absolute;
538
- inset-block: var(--touch-slab);
539
- inset-inline-start: var(--touch-slab);
540
- inset-inline-end: 0;
540
+ /* The cell overlay grows vertically to the compact target, never sideways. */
541
+ .dt-sort::after {
542
+ inset-block: min(0px, calc((100% - var(--touch-target-compact)) / 2));
541
543
  }
542
544
  }
543
545
  @container (max-width: 30rem) {
@@ -587,7 +589,7 @@
587
589
  align-items: baseline;
588
590
  gap: var(--sp-1) var(--sp-3);
589
591
  padding: var(--sp-3);
590
- border-bottom: 1px solid var(--border);
592
+ border-bottom: var(--edge-width) solid var(--surface-edge);
591
593
  }
592
594
  [data-stacked] tbody tr:last-child {
593
595
  border-bottom: none;
@@ -679,7 +681,7 @@
679
681
  .dt-more {
680
682
  text-align: center;
681
683
  padding: var(--sp-2);
682
- border-top: 1px solid var(--border);
684
+ border-top: var(--edge-width) solid var(--surface-edge);
683
685
  }
684
686
  .dt-more-btn {
685
687
  border: 0;
@@ -97,14 +97,20 @@
97
97
  {#if showChips && (chips.length || text)}
98
98
  <div class="fsb__chips">
99
99
  {#each chips as f (f.span[0])}
100
- <Badge tone="info" removable onremove={() => remove(f.span)}>
100
+ <Badge
101
+ tone="info"
102
+ truncate
103
+ title="{labelFor(f.field)} {operatorById(f.op)?.label} {f.values.join(', ') || '∅'}"
104
+ removable
105
+ onremove={() => remove(f.span)}
106
+ >
101
107
  <span class="fsb__chip-field">{labelFor(f.field)}</span>
102
108
  <span class="fsb__chip-op">{operatorById(f.op)?.label}</span>
103
109
  <span class="fsb__chip-val">{f.values.join(', ') || '∅'}</span>
104
110
  </Badge>
105
111
  {/each}
106
112
  {#if text}
107
- <Badge tone="neutral">
113
+ <Badge tone="neutral" truncate title="text {text}">
108
114
  <span class="fsb__chip-op">text</span>
109
115
  <span class="fsb__chip-val">{text}</span>
110
116
  </Badge>
@@ -285,6 +285,40 @@
285
285
  --shift-xs: 2px;
286
286
  --shift-sm: 4px;
287
287
  --shift-md: 8px;
288
+
289
+ /* Structural look. Components read these instead of hardcoding borders,
290
+ fills and shadows, so a theme can restyle the kit's surfaces from tokens. */
291
+ --edge-width: 1px;
292
+ --surface-fill: var(--bg-elevated);
293
+ --surface-fill-2: var(--bg-elevated-2);
294
+ --surface-edge: var(--border);
295
+ --surface-edge-strong: var(--border-strong);
296
+ --surface-shadow: 0 0 0 0 transparent;
297
+ --surface-shadow-hover: var(--surface-shadow);
298
+ --raised-fill: var(--bg-elevated);
299
+ --raised-edge: var(--border-strong);
300
+ --raised-shadow: var(--shadow-md);
301
+ --overlay-fill: var(--bg-elevated);
302
+ --overlay-edge: var(--border);
303
+ --overlay-shadow: var(--shadow-lg);
304
+ --control-fill: var(--bg);
305
+ --control-edge: var(--border-strong);
306
+ --control-edge-hover: var(--text-faint);
307
+ --control-shadow: 0 0 0 0 transparent;
308
+ --track-fill: var(--bg-elevated-2);
309
+ --track-edge: var(--border);
310
+ --thumb-fill: var(--bg);
311
+ --thumb-shadow: var(--shadow-sm);
312
+ --btn-fill: var(--surface);
313
+ --btn-edge: var(--border-strong);
314
+ --btn-shadow: 0 0 0 0 transparent;
315
+ --btn-shadow-hover: var(--btn-shadow);
316
+ --btn-primary-fill: var(--accent);
317
+ --btn-primary-edge: var(--accent);
318
+ --btn-primary-shadow: 0 0 0 0 transparent;
319
+ --btn-primary-shadow-hover: var(--btn-primary-shadow);
320
+ --hover-lift: 0px;
321
+ --focus-glow: 0 0 0 0 transparent;
288
322
  }
289
323
 
290
324
  @supports (animation-timing-function: linear(0, 1)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dorsk/tsumikit",
3
- "version": "0.77.0",
3
+ "version": "0.79.0",
4
4
  "description": "Minimal, dependency-free Svelte 5 + pure-CSS UI kit. Token-driven atoms, molecules & layouts with theming out of the box.",
5
5
  "type": "module",
6
6
  "license": "MIT",