@klodd/ds 3.5.4 → 3.5.6
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/SKILL.md +13 -1
- package/css/components/card.css +8 -8
- package/css/components/chip.css +20 -0
- package/css/components/dropdown.css +15 -15
- package/css/components/hero-roll.css +9 -9
- package/css/components/inline-edit.css +9 -0
- package/css/components/input.css +12 -0
- package/css/components/list-row.css +5 -0
- package/css/components/nav.css +22 -12
- package/css/components/overlay.css +8 -8
- package/css/components/swipe-stack.css +10 -0
- package/css/components/tab-bar.css +5 -0
- package/css/components/tooltip.css +7 -1
- package/js/hero-roll.js +3 -3
- package/js/nav-optimistic.js +5 -5
- package/js/sheet-drag.js +2 -2
- package/js/turbo-nav.js +2 -2
- package/package.json +1 -1
- package/references/02-components.md +1 -1
- package/references/03-quality-bar.md +7 -0
package/SKILL.md
CHANGED
|
@@ -108,4 +108,16 @@ v3.5.3 lagger till .heading-utan-N (17px) for dialog-titlar och sheet-rubriker.
|
|
|
108
108
|
v3.5.4 (Sprint D-3) introducerar --fs-16 token (16px) for iOS-anti-zoom
|
|
109
109
|
pa inputs och applicerar pa inline-edit__input. Token ar dokumenterad
|
|
110
110
|
som BARA for input-element - vanlig text anvander fortfarande 15 eller 17.
|
|
111
|
-
Sprint
|
|
111
|
+
v3.5.5 (Sprint E) konsoliderar :focus-visible over 7 komponenter (chip,
|
|
112
|
+
list-row, tab-bar, nav, swipe-stack, inline-edit) - 11 nya selectorer
|
|
113
|
+
fick outline 2px solid var(--border-focus) med outline-offset 2px. Plus
|
|
114
|
+
.tab outline-offset normaliserad 1px->2px. input.css och .inline-edit__input
|
|
115
|
+
ar dokumenterade undantag som behaller :focus (text-input-konvention).
|
|
116
|
+
v3.5.6 (Sprint F) konsoliderar BEM over 5 komponenter (card, dropdown,
|
|
117
|
+
hero-roll, overlay, nav) - 23 flat-hyphen element-klasser konverterade
|
|
118
|
+
till .block__element-syntax. Inkluderar JS-koordinering pa hero-roll,
|
|
119
|
+
sheet-drag, turbo-nav, nav-optimistic dar querySelector/classList
|
|
120
|
+
adresserar de bytta klasserna. .bottom-nav-item.active konverterad till
|
|
121
|
+
BEM-modifier .bottom-nav__item--active. tooltip-wrapper bevarad som
|
|
122
|
+
compound block per references/03-quality-bar.md regel 1. Sprint C fas 2
|
|
123
|
+
template-migration pagaar.)
|
package/css/components/card.css
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
pa klickbara kort. .card--flush tar bort padding (anvand for
|
|
6
6
|
inbaddat innehall som hanterar egen padding).
|
|
7
7
|
|
|
8
|
-
Slot-konvention: .
|
|
9
|
-
strukturerat innehall. .
|
|
8
|
+
Slot-konvention: .card__header / .card__body / .card__footer for
|
|
9
|
+
strukturerat innehall. .card__divider for horisontell separator.
|
|
10
10
|
================================================================ */
|
|
11
11
|
|
|
12
12
|
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
|
|
55
55
|
/* --flush tar bort default padding sa innehallet kan ga edge-to-edge.
|
|
56
56
|
Anvand nar barn-element har egen padding (ex. lista med list-rows). */
|
|
57
|
-
.card--flush > .
|
|
57
|
+
.card--flush > .card__body {
|
|
58
58
|
padding: 0;
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -62,24 +62,24 @@
|
|
|
62
62
|
/* ================================================================
|
|
63
63
|
==== SLOTS
|
|
64
64
|
Header och footer har samma padding som body men separator-linjer.
|
|
65
|
-
Anvand .
|
|
65
|
+
Anvand .card__divider for visuell uppdelning inom samma slot.
|
|
66
66
|
================================================================ */
|
|
67
|
-
.
|
|
67
|
+
.card__header {
|
|
68
68
|
padding: var(--space-16) var(--space-16) var(--space-12);
|
|
69
69
|
border-bottom: 1px solid var(--border-subtle);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
.
|
|
72
|
+
.card__body {
|
|
73
73
|
padding: var(--space-16);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
.
|
|
76
|
+
.card__footer {
|
|
77
77
|
padding: var(--space-12) var(--space-16);
|
|
78
78
|
border-top: 1px solid var(--border-subtle);
|
|
79
79
|
background: var(--surface-default);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
.
|
|
82
|
+
.card__divider {
|
|
83
83
|
height: 1px;
|
|
84
84
|
background: var(--border-subtle);
|
|
85
85
|
margin: 0 calc(-1 * var(--space-16));
|
package/css/components/chip.css
CHANGED
|
@@ -101,6 +101,11 @@
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
.chip-list__delete:focus-visible {
|
|
105
|
+
outline: 2px solid var(--border-focus);
|
|
106
|
+
outline-offset: 2px;
|
|
107
|
+
}
|
|
108
|
+
|
|
104
109
|
.chip-list__add {
|
|
105
110
|
background: transparent;
|
|
106
111
|
border-style: dashed;
|
|
@@ -120,6 +125,11 @@
|
|
|
120
125
|
}
|
|
121
126
|
}
|
|
122
127
|
|
|
128
|
+
.chip-list__add:focus-visible {
|
|
129
|
+
outline: 2px solid var(--border-focus);
|
|
130
|
+
outline-offset: 2px;
|
|
131
|
+
}
|
|
132
|
+
|
|
123
133
|
|
|
124
134
|
/* ================================================================
|
|
125
135
|
==== BRAND-PILL
|
|
@@ -245,6 +255,11 @@
|
|
|
245
255
|
.install-chip__install:hover { background: var(--accent-10); }
|
|
246
256
|
}
|
|
247
257
|
|
|
258
|
+
.install-chip__install:focus-visible {
|
|
259
|
+
outline: 2px solid var(--border-focus);
|
|
260
|
+
outline-offset: 2px;
|
|
261
|
+
}
|
|
262
|
+
|
|
248
263
|
.install-chip__dismiss {
|
|
249
264
|
background: transparent;
|
|
250
265
|
border: none;
|
|
@@ -261,6 +276,11 @@
|
|
|
261
276
|
.install-chip__dismiss:hover { color: var(--text-default); }
|
|
262
277
|
}
|
|
263
278
|
|
|
279
|
+
.install-chip__dismiss:focus-visible {
|
|
280
|
+
outline: 2px solid var(--border-focus);
|
|
281
|
+
outline-offset: 2px;
|
|
282
|
+
}
|
|
283
|
+
|
|
264
284
|
@keyframes install-chip-up {
|
|
265
285
|
from { transform: translateY(calc(100% + 100px)); opacity: 0; }
|
|
266
286
|
to { transform: translateY(0); opacity: 1; }
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/* ================================================================
|
|
2
2
|
components/dropdown.css
|
|
3
|
-
Kontextuell meny. Wrapper med trigger + .
|
|
3
|
+
Kontextuell meny. Wrapper med trigger + .dropdown__menu som
|
|
4
4
|
visas via .is-open-toggling fran JS.
|
|
5
5
|
|
|
6
6
|
Markup-pattern:
|
|
7
7
|
<div class="dropdown" data-dropdown>
|
|
8
8
|
<button class="btn btn--icon" data-dropdown-trigger>...</button>
|
|
9
|
-
<div class="
|
|
10
|
-
<button class="
|
|
11
|
-
<hr class="
|
|
12
|
-
<button class="
|
|
9
|
+
<div class="dropdown__menu" role="menu">
|
|
10
|
+
<button class="dropdown__item" role="menuitem">Item 1</button>
|
|
11
|
+
<hr class="dropdown__divider">
|
|
12
|
+
<button class="dropdown__item dropdown__item--danger">Ta bort</button>
|
|
13
13
|
</div>
|
|
14
14
|
</div>
|
|
15
15
|
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
display: inline-flex;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
.
|
|
24
|
+
.dropdown__menu {
|
|
25
25
|
position: absolute;
|
|
26
26
|
top: calc(100% + var(--space-4));
|
|
27
27
|
left: 0;
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
display: none;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
.dropdown.is-open .
|
|
38
|
+
.dropdown.is-open .dropdown__menu {
|
|
39
39
|
display: block;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
.
|
|
42
|
+
.dropdown__item {
|
|
43
43
|
display: flex;
|
|
44
44
|
align-items: center;
|
|
45
45
|
gap: var(--space-8);
|
|
@@ -56,32 +56,32 @@
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
@media (hover: hover) and (pointer: fine) {
|
|
59
|
-
.
|
|
59
|
+
.dropdown__item:hover {
|
|
60
60
|
background: var(--surface-hover);
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
.
|
|
64
|
+
.dropdown__item:active {
|
|
65
65
|
background: var(--surface-active);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
.
|
|
68
|
+
.dropdown__item:focus-visible {
|
|
69
69
|
outline: 2px solid var(--border-focus);
|
|
70
70
|
outline-offset: -2px;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
.
|
|
74
|
-
.
|
|
73
|
+
.dropdown__item[disabled],
|
|
74
|
+
.dropdown__item:disabled {
|
|
75
75
|
opacity: 0.5;
|
|
76
76
|
cursor: not-allowed;
|
|
77
77
|
pointer-events: none;
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
.
|
|
80
|
+
.dropdown__item--danger {
|
|
81
81
|
color: var(--bg-danger);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
.
|
|
84
|
+
.dropdown__divider {
|
|
85
85
|
border: none;
|
|
86
86
|
border-top: 1px solid var(--border-subtle);
|
|
87
87
|
margin: var(--space-4) 0;
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
En per siffra. Containrar en track av siffror som translateY:as
|
|
43
43
|
till slutvardet. Overflow:hidden klipper allt utom synlig position.
|
|
44
44
|
================================================================ */
|
|
45
|
-
.hero-
|
|
45
|
+
.hero-amount__digit-roller {
|
|
46
46
|
display: inline-block;
|
|
47
47
|
height: var(--hero-digit-height, 1em);
|
|
48
48
|
line-height: var(--hero-digit-height, 1em);
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
/* Vignett over och under sa siffrorna fadar ut nar de rullar in/ut.
|
|
55
55
|
--hero-vignette-color satts av app-konsumenten om subtle fade
|
|
56
56
|
onskas mot bg, default transparent. */
|
|
57
|
-
.hero-
|
|
58
|
-
.hero-
|
|
57
|
+
.hero-amount__digit-roller::before,
|
|
58
|
+
.hero-amount__digit-roller::after {
|
|
59
59
|
content: '';
|
|
60
60
|
position: absolute;
|
|
61
61
|
left: 0;
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
background: transparent;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
.hero-
|
|
69
|
+
.hero-amount__digit-roller::before {
|
|
70
70
|
top: 0;
|
|
71
71
|
background: linear-gradient(
|
|
72
72
|
to bottom,
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
.hero-
|
|
78
|
+
.hero-amount__digit-roller::after {
|
|
79
79
|
bottom: 0;
|
|
80
80
|
background: linear-gradient(
|
|
81
81
|
to top,
|
|
@@ -91,13 +91,13 @@
|
|
|
91
91
|
transition + transform. tabular-nums upprepad pa span-niva som
|
|
92
92
|
safety-net om hero-amount-arvet skulle brytas av nan parent.
|
|
93
93
|
================================================================ */
|
|
94
|
-
.hero-
|
|
94
|
+
.hero-amount__digit-track {
|
|
95
95
|
display: flex;
|
|
96
96
|
flex-direction: column;
|
|
97
97
|
will-change: transform;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
.hero-
|
|
100
|
+
.hero-amount__digit-track > span {
|
|
101
101
|
height: var(--hero-digit-height, 1em);
|
|
102
102
|
line-height: var(--hero-digit-height, 1em);
|
|
103
103
|
display: block;
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
Mellanslag och "kr"-suffix runt rollers. white-space: pre bevarar
|
|
111
111
|
exakta blanksteg.
|
|
112
112
|
================================================================ */
|
|
113
|
-
.hero-
|
|
113
|
+
.hero-amount__static-char {
|
|
114
114
|
display: inline-block;
|
|
115
115
|
white-space: pre;
|
|
116
116
|
}
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
denna regel bara safety-net for befintliga inline-transitions.
|
|
124
124
|
================================================================ */
|
|
125
125
|
@media (prefers-reduced-motion: reduce) {
|
|
126
|
-
.hero-
|
|
126
|
+
.hero-amount__digit-track {
|
|
127
127
|
transition: none !important;
|
|
128
128
|
}
|
|
129
129
|
}
|
|
@@ -41,6 +41,11 @@
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
.inline-edit__btn:focus-visible {
|
|
45
|
+
outline: 2px solid var(--border-focus);
|
|
46
|
+
outline-offset: 2px;
|
|
47
|
+
}
|
|
48
|
+
|
|
44
49
|
.inline-edit__form {
|
|
45
50
|
display: inline-flex;
|
|
46
51
|
align-items: center;
|
|
@@ -68,6 +73,10 @@
|
|
|
68
73
|
outline: none;
|
|
69
74
|
}
|
|
70
75
|
|
|
76
|
+
/* :focus (INTE :focus-visible) - text-input-undantag analogt med
|
|
77
|
+
input.css. Anvandare klickar/touchar inputen och forvantar sig
|
|
78
|
+
visuell feedback oavsett input-method. Border + box-shadow ar
|
|
79
|
+
integrerad i input-utseendet. */
|
|
71
80
|
.inline-edit__input:focus {
|
|
72
81
|
border-color: var(--accent-9);
|
|
73
82
|
box-shadow: 0 0 0 3px var(--accent-a3);
|
package/css/components/input.css
CHANGED
|
@@ -61,6 +61,18 @@
|
|
|
61
61
|
/* ================================================================
|
|
62
62
|
==== STATES
|
|
63
63
|
================================================================ */
|
|
64
|
+
|
|
65
|
+
/* Inputs anvander :focus (INTE :focus-visible) som dokumenterat
|
|
66
|
+
undantag fran paketets generella focus-visible-monster.
|
|
67
|
+
|
|
68
|
+
Skal: text-inputs ar specialfall - anvandare klickar/touchar dem
|
|
69
|
+
och forvantar sig visuell feedback oavsett input-method (mus eller
|
|
70
|
+
tangentbord). Att gomma fokus-ring vid mus-klick (vilket
|
|
71
|
+
:focus-visible skulle gora) kan forvirra anvandare om vilket falt
|
|
72
|
+
som ar aktivt. Konvention foljer Radix UI, MUI, shadcn etc.
|
|
73
|
+
|
|
74
|
+
Fokus-feedback ar border-color + box-shadow ring (inte outline) -
|
|
75
|
+
integrerad i input-utseendet snarare an "added on top". */
|
|
64
76
|
.input:focus,
|
|
65
77
|
.textarea:focus,
|
|
66
78
|
.select:focus {
|
package/css/components/nav.css
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
border-radius: 0;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
.bottom-
|
|
34
|
+
.bottom-nav__item {
|
|
35
35
|
display: flex;
|
|
36
36
|
flex-direction: column;
|
|
37
37
|
align-items: center;
|
|
@@ -51,17 +51,22 @@
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
@media (hover: hover) and (pointer: fine) {
|
|
54
|
-
.bottom-
|
|
54
|
+
.bottom-nav__item:hover {
|
|
55
55
|
color: var(--text-default);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
.bottom-
|
|
59
|
+
.bottom-nav__item:focus-visible {
|
|
60
|
+
outline: 2px solid var(--border-focus);
|
|
61
|
+
outline-offset: 2px;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.bottom-nav__item--active {
|
|
60
65
|
color: var(--accent-text);
|
|
61
66
|
}
|
|
62
67
|
|
|
63
|
-
.bottom-
|
|
64
|
-
.bottom-
|
|
68
|
+
.bottom-nav__item .icon,
|
|
69
|
+
.bottom-nav__item svg {
|
|
65
70
|
width: var(--space-20);
|
|
66
71
|
height: var(--space-20);
|
|
67
72
|
}
|
|
@@ -80,7 +85,7 @@
|
|
|
80
85
|
margin-bottom: var(--space-16);
|
|
81
86
|
}
|
|
82
87
|
|
|
83
|
-
.
|
|
88
|
+
.topbar__back {
|
|
84
89
|
display: inline-flex;
|
|
85
90
|
align-items: center;
|
|
86
91
|
justify-content: center;
|
|
@@ -97,17 +102,17 @@
|
|
|
97
102
|
}
|
|
98
103
|
|
|
99
104
|
@media (hover: hover) and (pointer: fine) {
|
|
100
|
-
.
|
|
105
|
+
.topbar__back:hover {
|
|
101
106
|
background: var(--surface-hover);
|
|
102
107
|
}
|
|
103
108
|
}
|
|
104
109
|
|
|
105
|
-
.
|
|
110
|
+
.topbar__back:focus-visible {
|
|
106
111
|
outline: 2px solid var(--border-focus);
|
|
107
112
|
outline-offset: 2px;
|
|
108
113
|
}
|
|
109
114
|
|
|
110
|
-
.
|
|
115
|
+
.topbar__title {
|
|
111
116
|
flex: 1;
|
|
112
117
|
min-width: 0;
|
|
113
118
|
font-size: var(--fs-17);
|
|
@@ -120,7 +125,7 @@
|
|
|
120
125
|
white-space: nowrap;
|
|
121
126
|
}
|
|
122
127
|
|
|
123
|
-
.
|
|
128
|
+
.topbar__action {
|
|
124
129
|
display: inline-flex;
|
|
125
130
|
align-items: center;
|
|
126
131
|
justify-content: center;
|
|
@@ -136,11 +141,16 @@
|
|
|
136
141
|
}
|
|
137
142
|
|
|
138
143
|
@media (hover: hover) and (pointer: fine) {
|
|
139
|
-
.
|
|
144
|
+
.topbar__action:hover {
|
|
140
145
|
color: var(--text-default);
|
|
141
146
|
}
|
|
142
147
|
}
|
|
143
148
|
|
|
149
|
+
.topbar__action:focus-visible {
|
|
150
|
+
outline: 2px solid var(--border-focus);
|
|
151
|
+
outline-offset: 2px;
|
|
152
|
+
}
|
|
153
|
+
|
|
144
154
|
|
|
145
155
|
/* ================================================================
|
|
146
156
|
==== TAB-BAR (inline tabs i panel)
|
|
@@ -188,5 +198,5 @@
|
|
|
188
198
|
|
|
189
199
|
.tab:focus-visible {
|
|
190
200
|
outline: 2px solid var(--border-focus);
|
|
191
|
-
outline-offset:
|
|
201
|
+
outline-offset: 2px;
|
|
192
202
|
}
|
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
==== DIALOG-BACKDROP
|
|
14
14
|
Halvtransparent overlay med blur. Anvands av bade .dialog och
|
|
15
15
|
.sheet. native ::backdrop pseudo-element (om <dialog>) eller en
|
|
16
|
-
konkret <div class="
|
|
16
|
+
konkret <div class="dialog__backdrop"> for portal-baserade modaler.
|
|
17
17
|
================================================================ */
|
|
18
|
-
.
|
|
18
|
+
.dialog__backdrop,
|
|
19
19
|
dialog.dialog::backdrop,
|
|
20
20
|
dialog.sheet::backdrop {
|
|
21
21
|
background: color-mix(in oklch, var(--surface-page) 60%, transparent);
|
|
@@ -54,7 +54,7 @@ dialog.sheet::backdrop {
|
|
|
54
54
|
inset: auto;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
.
|
|
57
|
+
.dialog__header {
|
|
58
58
|
display: flex;
|
|
59
59
|
align-items: center;
|
|
60
60
|
justify-content: space-between;
|
|
@@ -63,13 +63,13 @@ dialog.sheet::backdrop {
|
|
|
63
63
|
border-bottom: 1px solid var(--border-subtle);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
.
|
|
66
|
+
.dialog__body {
|
|
67
67
|
padding: var(--space-20);
|
|
68
68
|
overflow-y: auto;
|
|
69
69
|
max-height: 60vh;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
.
|
|
72
|
+
.dialog__footer {
|
|
73
73
|
display: flex;
|
|
74
74
|
justify-content: flex-end;
|
|
75
75
|
gap: var(--space-8);
|
|
@@ -111,7 +111,7 @@ dialog.sheet::backdrop {
|
|
|
111
111
|
inset: auto 0 0 0;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
.
|
|
114
|
+
.sheet__handle {
|
|
115
115
|
width: 32px;
|
|
116
116
|
height: 4px;
|
|
117
117
|
margin: 0 auto var(--space-16);
|
|
@@ -119,12 +119,12 @@ dialog.sheet::backdrop {
|
|
|
119
119
|
border-radius: var(--radius-full);
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
.
|
|
122
|
+
.sheet__body {
|
|
123
123
|
padding-top: var(--space-4);
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
/* Sheet-section divider for grupper inom samma sheet. */
|
|
127
|
-
.
|
|
127
|
+
.sheet__divider {
|
|
128
128
|
height: 1px;
|
|
129
129
|
background: var(--border-subtle);
|
|
130
130
|
margin: var(--space-16) calc(-1 * var(--space-20));
|
|
@@ -47,6 +47,11 @@
|
|
|
47
47
|
|
|
48
48
|
.swipe-card:active { cursor: grabbing; }
|
|
49
49
|
|
|
50
|
+
.swipe-card:focus-visible {
|
|
51
|
+
outline: 2px solid var(--border-focus);
|
|
52
|
+
outline-offset: 2px;
|
|
53
|
+
}
|
|
54
|
+
|
|
50
55
|
.swipe-card--back {
|
|
51
56
|
transform: scale(0.96);
|
|
52
57
|
opacity: 0.85;
|
|
@@ -154,6 +159,11 @@
|
|
|
154
159
|
transition: transform var(--press-in-duration) var(--press-in-easing);
|
|
155
160
|
}
|
|
156
161
|
|
|
162
|
+
.swipe-action-btn:focus-visible {
|
|
163
|
+
outline: 2px solid var(--border-focus);
|
|
164
|
+
outline-offset: 2px;
|
|
165
|
+
}
|
|
166
|
+
|
|
157
167
|
.swipe-action-btn--save { color: var(--positive); }
|
|
158
168
|
.swipe-action-btn--dismiss { color: var(--negative); }
|
|
159
169
|
|
|
@@ -13,7 +13,13 @@
|
|
|
13
13
|
tooltip-elementet sa det inte snor klick fran wrappern.
|
|
14
14
|
|
|
15
15
|
prefers-reduced-motion respekteras (opacity-fade tas bort).
|
|
16
|
-
|
|
16
|
+
|
|
17
|
+
BEM-anteckning (Sprint F): .tooltip-wrapper ar ett COMPOUND BLOCK,
|
|
18
|
+
inte ett flat-element av .tooltip. Wrappern ar utanfor .tooltip i
|
|
19
|
+
DOM (parent, inte child). Compound-block-monstret foljer .hub-card-
|
|
20
|
+
konventionen per references/03-quality-bar.md regel 1 ("Block:
|
|
21
|
+
substantiv (.card, .banner, .hub-card)"). Ingen __wrapper-syntax
|
|
22
|
+
eftersom wrappern inte ar ett element AV tooltip. */
|
|
17
23
|
.tooltip-wrapper {
|
|
18
24
|
position: relative;
|
|
19
25
|
display: inline-flex;
|
package/js/hero-roll.js
CHANGED
|
@@ -77,10 +77,10 @@
|
|
|
77
77
|
|
|
78
78
|
function buildRoller ( targetDigit ) {
|
|
79
79
|
const roller = document.createElement( 'span' );
|
|
80
|
-
roller.className = 'hero-
|
|
80
|
+
roller.className = 'hero-amount__digit-roller';
|
|
81
81
|
|
|
82
82
|
const track = document.createElement( 'span' );
|
|
83
|
-
track.className = 'hero-
|
|
83
|
+
track.className = 'hero-amount__digit-track';
|
|
84
84
|
|
|
85
85
|
const totalSteps = targetDigit + ( EXTRA_ROUNDS * 10 );
|
|
86
86
|
for ( let i = 0; i <= totalSteps; i++ ) {
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
|
|
96
96
|
function buildStaticChar ( text ) {
|
|
97
97
|
const span = document.createElement( 'span' );
|
|
98
|
-
span.className = 'hero-
|
|
98
|
+
span.className = 'hero-amount__static-char';
|
|
99
99
|
span.textContent = text;
|
|
100
100
|
return span;
|
|
101
101
|
}
|
package/js/nav-optimistic.js
CHANGED
|
@@ -41,11 +41,11 @@
|
|
|
41
41
|
|
|
42
42
|
const pod = e.target.closest( '.nav-pod' );
|
|
43
43
|
if ( ! pod || ! nav.contains( pod ) ) return;
|
|
44
|
-
if ( pod.classList.contains( 'active' ) ) return;
|
|
44
|
+
if ( pod.classList.contains( 'bottom-nav__item--active' ) ) return;
|
|
45
45
|
|
|
46
46
|
const previousActive = nav.querySelector( '.nav-pod.active' );
|
|
47
|
-
previousActive && previousActive.classList.remove( 'active' );
|
|
48
|
-
pod.classList.add( 'active' );
|
|
47
|
+
previousActive && previousActive.classList.remove( 'bottom-nav__item--active' );
|
|
48
|
+
pod.classList.add( 'bottom-nav__item--active' );
|
|
49
49
|
|
|
50
50
|
pendingNav = { from: previousActive, to: pod };
|
|
51
51
|
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
clearTimeout( failsafeTimer );
|
|
56
56
|
failsafeTimer = setTimeout( () => {
|
|
57
57
|
if ( pendingNav ) {
|
|
58
|
-
pendingNav.to.classList.remove( 'active' );
|
|
59
|
-
pendingNav.from && pendingNav.from.classList.add( 'active' );
|
|
58
|
+
pendingNav.to.classList.remove( 'bottom-nav__item--active' );
|
|
59
|
+
pendingNav.from && pendingNav.from.classList.add( 'bottom-nav__item--active' );
|
|
60
60
|
reset();
|
|
61
61
|
}
|
|
62
62
|
}, 3000 );
|
package/js/sheet-drag.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*--------------------------------------------------------------
|
|
2
2
|
Ekonom - Sheet drag-to-dismiss (Sprint C2).
|
|
3
3
|
|
|
4
|
-
Pointer Events-baserad drag fran
|
|
4
|
+
Pointer Events-baserad drag fran sheet__handle (eller sheet-toppen
|
|
5
5
|
nar sheet ar scrollad till topp). 1:1 tracking under drag.
|
|
6
6
|
Threshold for dismiss: 40% av sheet-hojd ELLER velocity > 0.5 px/ms.
|
|
7
7
|
Spring-back om under threshold (CSS bounce-easing).
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
if (dialog.dataset.dragAttached) return;
|
|
23
23
|
dialog.dataset.dragAttached = '1';
|
|
24
24
|
|
|
25
|
-
const handle = dialog.querySelector('.
|
|
25
|
+
const handle = dialog.querySelector('.sheet__handle');
|
|
26
26
|
if (!handle) return;
|
|
27
27
|
|
|
28
28
|
let dragging = false;
|
package/js/turbo-nav.js
CHANGED
|
@@ -186,12 +186,12 @@
|
|
|
186
186
|
if ( newNav && liveNav ) {
|
|
187
187
|
const newActiveHref = newNav.querySelector( '.nav-pod.active' );
|
|
188
188
|
const liveActive = liveNav.querySelector( '.nav-pod.active' );
|
|
189
|
-
if ( liveActive ) liveActive.classList.remove( 'active' );
|
|
189
|
+
if ( liveActive ) liveActive.classList.remove( 'bottom-nav__item--active' );
|
|
190
190
|
if ( newActiveHref ) {
|
|
191
191
|
const target = liveNav.querySelector(
|
|
192
192
|
'a[href="' + newActiveHref.getAttribute( 'href' ) + '"]'
|
|
193
193
|
);
|
|
194
|
-
if ( target ) target.classList.add( 'active' );
|
|
194
|
+
if ( target ) target.classList.add( 'bottom-nav__item--active' );
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
197
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@klodd/ds",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.6",
|
|
4
4
|
"description": "Klodd Design System - shared tokens, typography, components and JS for Jubb, Ekonom, and future apps. v3.5.3 (2026-05-09): tillagg .heading (17px medium tight) i base/typography.css for dialog-titlar och sheet-rubriker. Tackar luckan mellan .heading-2 (18px) och .heading-3 (15px) - matchar Ekonoms gamla .heading-class.",
|
|
5
5
|
"main": "css/index.css",
|
|
6
6
|
"bin": {
|
|
@@ -54,7 +54,7 @@ inga primitives. BEM-konvention (block__element--modifier).
|
|
|
54
54
|
- **Tokens:** `currentColor` - parent-element styr fargen
|
|
55
55
|
|
|
56
56
|
### hero-roll (`hero-roll.css`)
|
|
57
|
-
- **Klasser:** `.hero-amount[data-animate-roll]`, `.hero-
|
|
57
|
+
- **Klasser:** `.hero-amount[data-animate-roll]`, `.hero-amount__digit-track`
|
|
58
58
|
- **Anvand:** Display-siffer-animation pa hero-vyer (kodlas-rullning)
|
|
59
59
|
- **INTE:** Vanliga numeriska varden (anvand `.hero__amount` utan data-animate-roll)
|
|
60
60
|
- **Tokens:** `--text-default`, `--lh-tight`, `--ls-tightest`, `--fs-80`. **Undantag:** `font-weight: 600` (display-undantaget fran 400/500-policyn).
|
|
@@ -62,6 +62,13 @@ Lista over absoluta krav som inte ska brytas. Varje krav har konkret
|
|
|
62
62
|
- ALDRIG `rgba(0, 0, 0, 0.4)` - anvand `color-mix(in oklch, ...)` eller
|
|
63
63
|
semantic alpha-token
|
|
64
64
|
|
|
65
|
+
**Scope:**
|
|
66
|
+
Galler komponenter i `components/*.css` och per-app domain-filer
|
|
67
|
+
(`X-domain.css`, `X.css`). Galler INTE `apps/X.css` - den filen ar
|
|
68
|
+
per definition det lager som haller app-specifika ravarden och
|
|
69
|
+
far referera primitives eller explicita hex-varden for app-karaktar
|
|
70
|
+
som saknar Radix-ekvivalent.
|
|
71
|
+
|
|
65
72
|
**Varfor:**
|
|
66
73
|
- Single source of truth: andring i 00-primitives.css landar omedelbart
|
|
67
74
|
i alla komponenter
|