@dorsk/tsumikit 0.73.0 → 0.73.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.
- package/README.md +4 -0
- package/dist/components/atoms/Button.svelte +12 -1
- package/dist/components/atoms/Checkbox.svelte +12 -0
- package/dist/components/layouts/TabBar.svelte +3 -1
- package/dist/components/molecules/SegmentedControl.svelte +44 -0
- package/dist/components/molecules/SwipeRow.svelte +6 -2
- package/dist/components/molecules/SwipeRow.svelte.d.ts +4 -0
- package/dist/components/organisms/DataTable.svelte +12 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1033,6 +1033,10 @@ half the gap sideways, which stays inside the group's padding, so neighbours
|
|
|
1033
1033
|
never overlap. `Input size="sm"` cannot host a pseudo-element and grows to 40px
|
|
1034
1034
|
instead, as should any control that clips its own overflow:
|
|
1035
1035
|
`min-height: var(--touch-target-compact)`.
|
|
1036
|
+
`Checkbox`, `Button variant="link"` and the `DataTable` sort button take the same
|
|
1037
|
+
slab; inside a DataTable it is clipped at the table's top edge. A `SegmentedControl`
|
|
1038
|
+
wider than its container switches to the `scroll` layout until it fits again
|
|
1039
|
+
(`wrap` wraps instead), and `block` segments ellipsise their labels.
|
|
1036
1040
|
|
|
1037
1041
|
`--control-height-*` and `--box-*` are **required tokens**: a consumer that
|
|
1038
1042
|
forks `variables.css` must keep them (Button `control`, Select `sm`, every `box`)
|
|
@@ -561,7 +561,8 @@
|
|
|
561
561
|
overflow counts towards the scrollable overflow of every scroll ancestor, and
|
|
562
562
|
in a row that half lies under the next sibling anyway. Growing further towards
|
|
563
563
|
the start would let each slab cover the previous sibling's centre. Text
|
|
564
|
-
buttons at size sm take the same shape sized by
|
|
564
|
+
buttons at size sm and link buttons take the same shape sized by
|
|
565
|
+
--touch-slab. */
|
|
565
566
|
@media (pointer: coarse) {
|
|
566
567
|
.btn-icon:not(.hit-compact),
|
|
567
568
|
.btn-icon-inline:not(.hit-compact),
|
|
@@ -593,6 +594,16 @@
|
|
|
593
594
|
inset-inline-start: var(--touch-slab);
|
|
594
595
|
inset-inline-end: 0;
|
|
595
596
|
}
|
|
597
|
+
.btn-link:not(.hit-compact) {
|
|
598
|
+
position: relative;
|
|
599
|
+
}
|
|
600
|
+
.btn-link:not(.hit-compact)::before {
|
|
601
|
+
content: '';
|
|
602
|
+
position: absolute;
|
|
603
|
+
inset-block: var(--touch-slab);
|
|
604
|
+
inset-inline-start: var(--touch-slab);
|
|
605
|
+
inset-inline-end: 0;
|
|
606
|
+
}
|
|
596
607
|
}
|
|
597
608
|
|
|
598
609
|
/* Two-state (toggle) buttons — e.g. an IconButton with `pressed`. Reacts to
|
|
@@ -141,6 +141,18 @@
|
|
|
141
141
|
.checkbox:has(input:disabled) {
|
|
142
142
|
cursor: not-allowed;
|
|
143
143
|
}
|
|
144
|
+
@media (pointer: coarse) {
|
|
145
|
+
.checkbox {
|
|
146
|
+
position: relative;
|
|
147
|
+
}
|
|
148
|
+
.checkbox::before {
|
|
149
|
+
content: '';
|
|
150
|
+
position: absolute;
|
|
151
|
+
inset-block: var(--touch-slab);
|
|
152
|
+
inset-inline-start: var(--touch-slab);
|
|
153
|
+
inset-inline-end: 0;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
144
156
|
.sr-only {
|
|
145
157
|
position: absolute;
|
|
146
158
|
width: 1px;
|
|
@@ -207,7 +207,9 @@
|
|
|
207
207
|
.tabbar :global(.tabbar-badge) {
|
|
208
208
|
position: absolute;
|
|
209
209
|
top: -0.4rem;
|
|
210
|
-
left: calc(100% -
|
|
210
|
+
left: calc(100% - 2px);
|
|
211
|
+
max-width: none;
|
|
212
|
+
padding-inline: 0.3rem;
|
|
211
213
|
}
|
|
212
214
|
@media (prefers-reduced-motion: reduce) {
|
|
213
215
|
.tabbar-item {
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
// browser-free keyboard model matches Tabs: ←/→ and Home/End move selection,
|
|
25
25
|
// Space/Enter (or click) activate. `value` is bindable.
|
|
26
26
|
import type { Snippet } from 'svelte';
|
|
27
|
+
import type { Attachment } from 'svelte/attachments';
|
|
27
28
|
import Icon from '../atoms/Icon.svelte';
|
|
28
29
|
import { formatSegmentCount } from './segmented-control-count.js';
|
|
29
30
|
import { nextEnabledSegment } from './segmented-control-keyboard.js';
|
|
@@ -95,6 +96,26 @@
|
|
|
95
96
|
);
|
|
96
97
|
const segId = (val: string) => `${baseId}-${val}`;
|
|
97
98
|
|
|
99
|
+
// A pill wider than its container falls back to the `scroll` layout; the
|
|
100
|
+
// class is dropped again once the row fits so the touch slab stays unclipped.
|
|
101
|
+
let overflowing = $state(false);
|
|
102
|
+
const watchOverflow: Attachment<HTMLElement> = (node) => {
|
|
103
|
+
if (wrap || typeof ResizeObserver === 'undefined') {
|
|
104
|
+
overflowing = false;
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
const check = () => {
|
|
108
|
+
overflowing = node.scrollWidth - node.clientWidth > 1;
|
|
109
|
+
};
|
|
110
|
+
const ro = new ResizeObserver(check);
|
|
111
|
+
ro.observe(node);
|
|
112
|
+
check();
|
|
113
|
+
return () => {
|
|
114
|
+
ro.disconnect();
|
|
115
|
+
overflowing = false;
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
|
|
98
119
|
function select(val: string, focus = false) {
|
|
99
120
|
if (options.find((o) => o.value === val)?.disabled) return;
|
|
100
121
|
value = val;
|
|
@@ -127,8 +148,10 @@
|
|
|
127
148
|
class:collapse-container={collapseLabels === 'container'}
|
|
128
149
|
class:seg-scroll={scroll}
|
|
129
150
|
class:seg-block={block}
|
|
151
|
+
class:seg-overflow={overflowing}
|
|
130
152
|
data-tsu="SegmentedControl"
|
|
131
153
|
{onkeydown}
|
|
154
|
+
{@attach watchOverflow}
|
|
132
155
|
>
|
|
133
156
|
{#each options as o (o.value)}
|
|
134
157
|
{@const selected = value === o.value}
|
|
@@ -165,6 +188,8 @@
|
|
|
165
188
|
background: var(--bg-elevated-2);
|
|
166
189
|
border: 1px solid var(--border);
|
|
167
190
|
border-radius: var(--r-pill);
|
|
191
|
+
max-width: 100%;
|
|
192
|
+
min-width: 0;
|
|
168
193
|
}
|
|
169
194
|
.seg-icon {
|
|
170
195
|
border-radius: var(--r-md);
|
|
@@ -193,6 +218,19 @@
|
|
|
193
218
|
.seg-scroll .seg-item {
|
|
194
219
|
flex: none;
|
|
195
220
|
}
|
|
221
|
+
.seg-overflow {
|
|
222
|
+
flex-wrap: nowrap;
|
|
223
|
+
overflow-x: auto;
|
|
224
|
+
overflow-y: hidden;
|
|
225
|
+
scrollbar-width: none;
|
|
226
|
+
-webkit-overflow-scrolling: touch;
|
|
227
|
+
}
|
|
228
|
+
.seg-overflow::-webkit-scrollbar {
|
|
229
|
+
display: none;
|
|
230
|
+
}
|
|
231
|
+
.seg-overflow .seg-item {
|
|
232
|
+
flex: none;
|
|
233
|
+
}
|
|
196
234
|
.seg-block {
|
|
197
235
|
display: flex;
|
|
198
236
|
width: 100%;
|
|
@@ -200,6 +238,12 @@
|
|
|
200
238
|
.seg-block .seg-item {
|
|
201
239
|
flex: 1 1 0;
|
|
202
240
|
justify-content: center;
|
|
241
|
+
min-width: 0;
|
|
242
|
+
}
|
|
243
|
+
.seg-block .seg-label {
|
|
244
|
+
min-width: 0;
|
|
245
|
+
overflow: hidden;
|
|
246
|
+
text-overflow: ellipsis;
|
|
203
247
|
}
|
|
204
248
|
|
|
205
249
|
.seg-item {
|
|
@@ -18,6 +18,10 @@
|
|
|
18
18
|
* a drag that is more vertical than horizontal is left to the scroller.
|
|
19
19
|
* The same actions are reachable as visually hidden buttons for keyboard
|
|
20
20
|
* and screen-reader users.
|
|
21
|
+
*
|
|
22
|
+
* On touch the browser implicitly captures the pointer on the element under
|
|
23
|
+
* the finger; taking capture on the row makes that child fire a bubbling
|
|
24
|
+
* `lostpointercapture`, which must not be read as a cancel.
|
|
21
25
|
*/
|
|
22
26
|
import type { Snippet } from 'svelte';
|
|
23
27
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
@@ -162,8 +166,8 @@
|
|
|
162
166
|
e.preventDefault();
|
|
163
167
|
}
|
|
164
168
|
|
|
165
|
-
function onlostpointercapture() {
|
|
166
|
-
if (pointerId === null) return;
|
|
169
|
+
function onlostpointercapture(e: PointerEvent) {
|
|
170
|
+
if (pointerId === null || e.pointerId !== pointerId || e.target !== e.currentTarget) return;
|
|
167
171
|
pointerId = null;
|
|
168
172
|
locked = null;
|
|
169
173
|
dragging = false;
|
|
@@ -13,6 +13,10 @@ export interface SwipeAction {
|
|
|
13
13
|
* a drag that is more vertical than horizontal is left to the scroller.
|
|
14
14
|
* The same actions are reachable as visually hidden buttons for keyboard
|
|
15
15
|
* and screen-reader users.
|
|
16
|
+
*
|
|
17
|
+
* On touch the browser implicitly captures the pointer on the element under
|
|
18
|
+
* the finger; taking capture on the row makes that child fire a bubbling
|
|
19
|
+
* `lostpointercapture`, which must not be read as a cancel.
|
|
16
20
|
*/
|
|
17
21
|
import type { Snippet } from 'svelte';
|
|
18
22
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
@@ -503,6 +503,18 @@
|
|
|
503
503
|
.dt-actions {
|
|
504
504
|
opacity: 1;
|
|
505
505
|
}
|
|
506
|
+
/* Sort slab: inline-end stays at 0 so it never reaches the next header
|
|
507
|
+
cell, and the inline-start reach stays inside the cell's own padding. */
|
|
508
|
+
.dt-sort {
|
|
509
|
+
position: relative;
|
|
510
|
+
}
|
|
511
|
+
.dt-sort::before {
|
|
512
|
+
content: '';
|
|
513
|
+
position: absolute;
|
|
514
|
+
inset-block: var(--touch-slab);
|
|
515
|
+
inset-inline-start: var(--touch-slab);
|
|
516
|
+
inset-inline-end: 0;
|
|
517
|
+
}
|
|
506
518
|
}
|
|
507
519
|
@container (max-width: 30rem) {
|
|
508
520
|
[data-hide-below='sm'] {
|
package/package.json
CHANGED