@navikt/ds-css 8.9.1 → 8.10.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@navikt/ds-css",
3
- "version": "8.9.1",
3
+ "version": "8.10.0",
4
4
  "description": "CSS for Nav Designsystem",
5
5
  "author": "Aksel | Nav designsystem team",
6
6
  "keywords": [
@@ -30,7 +30,7 @@
30
30
  "css:get-version": "node config/get-version.js"
31
31
  },
32
32
  "devDependencies": {
33
- "@navikt/ds-tokens": "^8.9.1",
33
+ "@navikt/ds-tokens": "^8.10.0",
34
34
  "browserslist": "^4.25.0",
35
35
  "esbuild": "^0.27.4",
36
36
  "fast-glob": "3.3.3",
package/src/alert.css CHANGED
@@ -114,6 +114,11 @@
114
114
  &[data-variant="moderate"] {
115
115
  outline: 1px solid var(--ax-border-default);
116
116
  outline-offset: -1px;
117
+
118
+ /* Adjust horizontal padding for small moderate alerts */
119
+ &[data-size="small"] {
120
+ --__axc-base-alert-pi: var(--ax-space-16);
121
+ }
117
122
  }
118
123
 
119
124
  &[data-variant="strong"] {
@@ -145,6 +150,9 @@
145
150
  background: var(--ax-bg-moderate);
146
151
  color: var(--ax-text-default);
147
152
  border-color: var(--ax-border-subtleA);
153
+
154
+ /* Optical alignment */
155
+ padding-top: var(--ax-space-1);
148
156
  }
149
157
 
150
158
  .aksel-base-alert[data-variant="strong"] & {
@@ -172,6 +180,10 @@
172
180
  padding: var(--__axc-base-alert-content-p);
173
181
  background-color: var(--ax-bg-default);
174
182
 
183
+ &[data-color] {
184
+ color: var(--ax-text-neutral);
185
+ }
186
+
175
187
  .aksel-base-alert[data-global="true"] & {
176
188
  padding-inline: var(--__axc-global-alert-alignment);
177
189
  }
@@ -48,41 +48,70 @@
48
48
  background-color: var(--ax-bg-neutral-softA);
49
49
  }
50
50
  }
51
-
52
- &[data-truncate-content="true"] {
53
- .aksel-data-table__td:not(.aksel-data-table--UNSAFE_isSelection) > div {
54
- text-overflow: ellipsis;
55
- white-space: nowrap;
56
- overflow: hidden;
57
- }
58
- }
59
51
  }
60
52
 
61
53
  .aksel-data-table__thead {
62
54
  background-color: var(--ax-bg-raised);
63
- position: sticky;
64
- top: 0;
55
+
56
+ .aksel-data-table[data-loading="true"] &::after {
57
+ content: "";
58
+ position: absolute;
59
+ block-size: 2px;
60
+ inset-block-end: -2px;
61
+ background-color: var(--ax-bg-strong);
62
+ animation: animateDataTableLoading 1s linear infinite;
63
+ z-index: 11;
64
+ }
65
65
  }
66
66
 
67
67
  .aksel-data-table__tbody {
68
68
  background-color: var(--ax-bg-raised);
69
- }
69
+ position: relative;
70
70
 
71
- .aksel-data-table__tr--selected {
72
- background-color: var(--ax-bg-softA);
73
- box-shadow:
74
- inset 1px 0 0 0 var(--ax-border-default),
75
- inset -1px 0 0 0 var(--ax-border-default);
71
+ &[inert] {
72
+ transition: opacity 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
73
+ opacity: var(--ax-opacity-disabled);
76
74
 
77
- &:first-of-type {
78
- box-shadow:
79
- inset 1px 0 0 0 var(--ax-border-default),
80
- inset -1px 0 0 0 var(--ax-border-default),
81
- inset 0 1px 0 0 var(--ax-border-default);
75
+ @starting-style {
76
+ opacity: 0.001;
77
+ }
82
78
  }
83
79
 
84
- & :is(.aksel-data-table__td, .aksel-data-table__th) {
85
- border-color: var(--ax-border-default);
80
+ &[inert]::after {
81
+ content: "";
82
+ position: absolute;
83
+ inset: 0;
84
+ background-color: var(--ax-bg-overlay);
85
+ transition: opacity 200ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
86
+ z-index: 10;
87
+ opacity: 0.2;
88
+
89
+ /* iOS 26+: Ensure the backdrop covers the entire visible viewport. */
90
+
91
+ @starting-style {
92
+ opacity: 0.001;
93
+ }
94
+ }
95
+ }
96
+
97
+ .aksel-data-table__tr {
98
+ &[data-selected="true"] {
99
+ background-color: var(--ax-bg-softA);
100
+ }
101
+
102
+ .aksel-data-table__thead &[data-sticky="true"] {
103
+ position: sticky;
104
+ top: 0;
105
+ z-index: 3;
106
+
107
+ &::after {
108
+ content: "";
109
+ position: absolute;
110
+ inset-inline: 0;
111
+ bottom: -1px;
112
+ pointer-events: none;
113
+ border-bottom: 1px solid var(--ax-border-neutral-subtle);
114
+ }
86
115
  }
87
116
  }
88
117
 
@@ -100,6 +129,7 @@
100
129
  pointer-events: none;
101
130
  border: 1px solid var(--ax-border-neutral-subtle);
102
131
  border-radius: var(--ax-radius-12);
132
+ z-index: 3;
103
133
  }
104
134
  }
105
135
 
@@ -111,16 +141,23 @@
111
141
  }
112
142
 
113
143
  .aksel-data-table__thead {
144
+ position: relative; /* Shadow ends up behind loading/empty-state without, consider after-element instead like with sticky */
114
145
  box-shadow: 0 1px 0 0 var(--ax-border-neutral-subtle);
115
146
  }
116
147
 
117
- .aksel-data-table__th,
118
- .aksel-data-table__td {
148
+ .aksel-data-table__cell {
119
149
  /* border doesn't work on sticky thead when we have collapsed borders, so using box-shadow instead */
120
150
  box-shadow: inset 1px 1px 0 0 var(--ax-border-neutral-subtle);
151
+ text-align: start;
152
+ vertical-align: middle;
153
+ scroll-margin: var(--ax-space-0);
154
+
155
+ .aksel-data-table__thead & {
156
+ background-color: var(--ax-bg-neutral-soft);
157
+ }
121
158
 
122
159
  &[data-align="left"] {
123
- text-align: left;
160
+ text-align: start;
124
161
  }
125
162
 
126
163
  &[data-align="center"] {
@@ -128,18 +165,79 @@
128
165
  }
129
166
 
130
167
  &[data-align="right"] {
131
- text-align: right;
168
+ text-align: end;
169
+ }
170
+
171
+ &[data-sticky] {
172
+ position: sticky;
173
+ z-index: 1;
174
+
175
+ &::after {
176
+ content: "";
177
+ position: absolute;
178
+ inset-block: 0;
179
+ pointer-events: none;
180
+ border-color: var(--ax-border-neutral-subtle);
181
+ border-style: solid;
182
+ border-width: 0;
183
+ }
184
+
185
+ &[data-sticky="start"] {
186
+ left: 0;
187
+
188
+ &::after {
189
+ inset-inline: 0 -1px;
190
+ border-right-width: 1px;
191
+ }
192
+ }
193
+
194
+ &[data-sticky="end"] {
195
+ right: 0;
196
+ }
197
+
198
+ background-color: var(--ax-bg-raised);
199
+
200
+ .aksel-data-table__thead & {
201
+ background-color: var(--ax-bg-neutral-soft);
202
+ }
203
+ }
204
+
205
+ &:focus-visible,
206
+ /* Focus instead of focus-visible so that effect of sort-icon staying isnt strange */
207
+ /* TODO: Update from th to generic */
208
+ &:has(.aksel-data-table__th-sort-button:focus) {
209
+ outline: 2px solid var(--ax-border-focus);
210
+ outline-offset: -4px;
211
+ }
212
+
213
+ &[data-selectable="true"] {
214
+ padding: 0;
215
+
216
+ & > div {
217
+ display: grid;
218
+ place-content: center;
219
+ }
220
+ }
221
+
222
+ &:not([data-selectable="true"]) > div {
223
+ padding-block: var(--__axc-data-table-density);
224
+ padding-inline: var(--ax-space-16);
225
+
226
+ .aksel-data-table[data-truncate-content="true"] & {
227
+ text-overflow: ellipsis;
228
+ white-space: nowrap;
229
+ overflow: hidden;
230
+ }
132
231
  }
133
232
  }
134
233
 
135
234
  /* BORDER STYLING END */
136
235
 
137
- .aksel-data-table__th {
236
+ .aksel-data-table__column-header {
237
+ /* TODO: Might want this to be dynamic */
238
+ --__axc-data-table-density: var(--ax-space-8);
239
+
138
240
  position: relative;
139
- background-color: var(--ax-bg-neutral-soft);
140
- color: var(--ax-text-neutral);
141
- padding: var(--ax-space-8) var(--ax-space-16);
142
- text-align: start;
143
241
  font-weight: var(--ax-font-weight-bold);
144
242
 
145
243
  &:has(.aksel-data-table__th-sort-button):hover {
@@ -160,7 +258,6 @@
160
258
  display: flex;
161
259
  align-items: center;
162
260
  gap: var(--ax-space-2);
163
- padding-inline-start: var(--ax-space-16);
164
261
  block-size: calc(var(--__axc-data-table-density) + 1.5rem);
165
262
  width: 100%;
166
263
  cursor: pointer;
@@ -202,7 +299,7 @@
202
299
  }
203
300
 
204
301
  .aksel-data-table__th-resize-handle {
205
- z-index: 2;
302
+ z-index: 1;
206
303
  position: absolute;
207
304
  cursor: col-resize;
208
305
  margin: 0;
@@ -233,6 +330,13 @@
233
330
  transition: background 50ms linear;
234
331
  }
235
332
 
333
+ &:hover,
334
+ &:focus-visible,
335
+ &:active {
336
+ /* Avoids clipping when having sticky columns */
337
+ z-index: 3;
338
+ }
339
+
236
340
  &:hover::after {
237
341
  /* TODO: Consider if the resize-handle should be visible already when hovering the column header */
238
342
  background: var(--ax-bg-strong);
@@ -243,7 +347,7 @@
243
347
  background: var(--ax-bg-strong-pressed);
244
348
  }
245
349
 
246
- .aksel-data-table__th:last-of-type & {
350
+ .aksel-data-table__column-header:last-of-type & {
247
351
  inset-inline-end: 0;
248
352
  width: 15px;
249
353
 
@@ -301,18 +405,6 @@
301
405
  }
302
406
  }
303
407
 
304
- .aksel-data-table__td {
305
- text-align: start;
306
- vertical-align: middle;
307
- color: var(--ax-text-neutral-subtle);
308
-
309
- &:not(.aksel-data-table--UNSAFE_isSelection) > div {
310
- padding-block: var(--__axc-data-table-density);
311
- padding-inline: 1rem;
312
- }
313
- }
314
-
315
- .aksel-data-table__td,
316
408
  .aksel-data-table__th {
317
409
  scroll-margin-block: var(--ax-space-0);
318
410
  scroll-margin-inline: var(--ax-space-0);
@@ -324,9 +416,13 @@
324
416
  outline-offset: -4px;
325
417
  }
326
418
 
327
- &.aksel-data-table--UNSAFE_isSelection > div {
328
- display: grid;
329
- place-content: center;
419
+ &[data-selectable="true"] {
420
+ padding: 0;
421
+
422
+ & > div {
423
+ display: grid;
424
+ place-content: center;
425
+ }
330
426
  }
331
427
  }
332
428
 
@@ -382,26 +478,34 @@
382
478
  }
383
479
  }
384
480
 
385
- .aksel-data-drag-and-drop__drag-handler__arrow {
386
- height: 1.2rem;
387
- }
388
-
389
481
  .aksel-data-drag-and-drop__drag-handler__alt,
390
482
  .aksel-data-drag-and-drop__drag-handler {
391
483
  position: relative;
392
484
  height: 1.5rem;
393
485
 
394
486
  .aksel-data-drag-and-drop__drag-handler__arrow {
487
+ height: 1.8rem;
395
488
  position: absolute;
396
489
  left: 50%;
397
490
  transform: translate(-50%, -50%);
491
+ background: var(--ax-bg-default);
492
+ border: none;
493
+ cursor: pointer;
494
+ padding: 0;
495
+ border-radius: 50%;
496
+ z-index: 1;
398
497
 
399
498
  &[data-direction="up"] {
400
- top: -10px;
499
+ top: -18px;
401
500
  }
402
501
 
403
502
  &[data-direction="down"] {
404
- bottom: calc(-100% - 6px);
503
+ bottom: calc(-100% - 22px);
504
+ }
505
+
506
+ &:disabled {
507
+ opacity: 0.8;
508
+ cursor: not-allowed;
405
509
  }
406
510
  }
407
511
  }
@@ -425,16 +529,6 @@
425
529
  gap: var(--ax-space-8);
426
530
  justify-items: center;
427
531
  position: relative;
428
-
429
- &::before {
430
- content: "";
431
- position: absolute;
432
- inline-size: 100%;
433
- block-size: 2px;
434
- inset-block-start: -1px;
435
- background-color: var(--ax-bg-strong);
436
- animation: animateDataTableLoading 1s linear infinite;
437
- }
438
532
  }
439
533
 
440
534
  @keyframes animateDataTableLoading {
@@ -471,9 +565,9 @@
471
565
  /* TODO -
472
566
  * This is needed to prevent the cursor from changing back to default when dragging over interactive elements in the row.
473
567
  * Not sure if this is the best approach or breaks styling elsewhere */
474
- html[data-dragging="true"],
475
- html[data-dragging="true"] *,
476
- html[data-dragging="true"] *::before,
477
- html[data-dragging="true"] *::after {
568
+ html[data-dragging-cursor="true"],
569
+ html[data-dragging-cursor="true"] *,
570
+ html[data-dragging-cursor="true"] *::before,
571
+ html[data-dragging-cursor="true"] *::after {
478
572
  cursor: grabbing !important;
479
573
  }
package/src/date.css CHANGED
@@ -4,11 +4,11 @@
4
4
  padding: var(--ax-space-16);
5
5
 
6
6
  .rdp-table {
7
- border-collapse: separate; /* Some CSS-resets sets border-collapse:collapse on tables */
7
+ border-collapse: collapse;
8
8
  }
9
9
 
10
10
  .rdp-cell {
11
- padding: 1px; /* Some CSS-resets sets padding:0 on all items */
11
+ padding: 0;
12
12
 
13
13
  &[data-outside="true"] {
14
14
  width: var(--__axc-date-button-size);
@@ -23,18 +23,22 @@
23
23
  }
24
24
 
25
25
  .rdp-day_range_middle {
26
- &.rdp-day_disabled {
26
+ &.rdp-day_disabled .rdp-day__inner {
27
27
  color: var(--ax-text-neutral);
28
28
  background: var(--ax-bg-neutral-moderateA);
29
29
  }
30
30
 
31
- &.rdp-day_selected {
31
+ &.rdp-day_selected .rdp-day__inner {
32
32
  background-color: var(--ax-bg-moderate-pressedA);
33
33
  box-shadow: inset 0 0 0 1px var(--ax-border-subtleA);
34
34
  color: var(--ax-text-neutral);
35
35
  }
36
36
  }
37
37
 
38
+ .rdp-button.rdp-day__range-hover-middle .rdp-day__inner {
39
+ background-color: var(--ax-bg-moderate-hoverA);
40
+ }
41
+
38
42
  .rdp-month,
39
43
  &.rdp-month {
40
44
  display: grid;
@@ -52,22 +56,30 @@
52
56
 
53
57
  .rdp-button {
54
58
  all: unset;
55
- display: block;
56
- width: var(--__axc-date-button-size);
57
- height: var(--__axc-date-button-size);
58
- text-align: center;
59
+ padding: var(--ax-space-2);
60
+ cursor: pointer;
61
+
62
+ & .rdp-day__inner {
63
+ width: var(--__axc-date-button-size);
64
+ height: var(--__axc-date-button-size);
65
+ }
66
+ }
67
+
68
+ .rdp-day__inner {
69
+ display: grid;
70
+ place-items: center;
59
71
  border-radius: var(--ax-radius-8);
60
72
  }
61
73
 
62
- .rdp-day_range_start {
74
+ .rdp-day_range_start .rdp-day__inner {
63
75
  border-radius: 100% var(--ax-radius-12) var(--ax-radius-12) 100%;
64
76
  }
65
77
 
66
- .rdp-day_range_end:not(.rdp-day_range_start) {
78
+ .rdp-day_range_end:not(.rdp-day_range_start) .rdp-day__inner {
67
79
  border-radius: var(--ax-radius-8) 100% 100% var(--ax-radius-8);
68
80
  }
69
81
 
70
- .rdp-day_range_start.rdp-day_range_end {
82
+ .rdp-day_range_start.rdp-day_range_end .rdp-day__inner {
71
83
  border-radius: var(--ax-radius-8);
72
84
  }
73
85
 
@@ -78,24 +90,23 @@
78
90
  position: relative;
79
91
  }
80
92
 
81
- .rdp-day_selected,
82
- .aksel-monthpicker__month--selected {
93
+ .rdp-day_selected .rdp-day__inner {
83
94
  color: var(--ax-text-contrast);
84
95
  background: var(--ax-bg-strong-pressed);
85
- cursor: pointer;
86
96
  }
87
97
 
88
- .rdp-day_disabled {
98
+ .rdp-day_disabled .rdp-day__inner {
89
99
  cursor: not-allowed;
90
- text-decoration: line-through;
91
100
  background-color: var(--ax-bg-neutral-moderateA);
92
101
  color: var(--ax-text-neutral-subtle);
102
+ opacity: var(--ax-opacity-disabled);
93
103
  }
94
104
 
95
105
  .rdp-button:where(:not(.rdp-day_selected, [disabled])):hover,
96
106
  .aksel-date__month-button:where(:not(.rdp-day_selected, [disabled])):hover {
97
- background: var(--ax-bg-moderate-hoverA);
98
- cursor: pointer;
107
+ .rdp-day__inner {
108
+ background: var(--ax-bg-moderate-hoverA);
109
+ }
99
110
  }
100
111
 
101
112
  .rdp-day_today {
@@ -154,7 +165,7 @@
154
165
  justify-content: space-between;
155
166
  align-items: center;
156
167
  gap: var(--ax-space-4);
157
- padding-inline: var(--ax-space-4);
168
+ padding-inline: var(--ax-space-2);
158
169
  }
159
170
 
160
171
  .aksel-date__caption-button {
@@ -167,15 +178,17 @@
167
178
  text-transform: capitalize;
168
179
  }
169
180
 
170
- /* Monthpicker */
181
+ /* MonthPicker */
171
182
  .aksel-date__month-button {
172
183
  all: unset;
173
- text-align: center;
174
- width: 3rem;
175
- height: 3rem;
176
- text-transform: capitalize;
177
- border-radius: var(--ax-radius-8);
184
+ padding: var(--ax-space-2);
178
185
  cursor: pointer;
186
+
187
+ & .rdp-day__inner {
188
+ width: 3rem;
189
+ height: 3rem;
190
+ text-transform: capitalize;
191
+ }
179
192
  }
180
193
 
181
194
  .aksel-date__year-label {
@@ -190,12 +203,12 @@
190
203
 
191
204
  .rdp-cell > button.rdp-day,
192
205
  button.aksel-date__month-button {
193
- &:focus-visible {
206
+ &:focus-visible .rdp-day__inner {
194
207
  outline: 3px solid var(--ax-border-focus);
195
208
  outline-offset: 3px;
196
209
  }
197
210
 
198
- &:active:not(:disabled) {
211
+ &:active:not(:disabled) .rdp-day__inner {
199
212
  color: var(--ax-text-contrast);
200
213
  background-color: var(--ax-bg-strong-pressed);
201
214
  }
@@ -92,6 +92,12 @@
92
92
  border: var(--__axc-radio-checkbox-marker-border) solid var(--ax-border-neutral);
93
93
  border-radius: var(--ax-radius-4);
94
94
  position: relative;
95
+
96
+ &[data-standalone="true"]:disabled,
97
+ .aksel-checkbox__input-wrapper[data-standalone="true"] > &:disabled {
98
+ opacity: var(--ax-opacity-disabled);
99
+ cursor: not-allowed;
100
+ }
95
101
  }
96
102
 
97
103
  /* Visible marker */
@@ -2,6 +2,7 @@
2
2
  display: flex;
3
3
  flex-direction: column;
4
4
  min-height: 100vh;
5
+ /* biome-ignore lint/suspicious/noDuplicateProperties: vh is fallback for browsers that do not support lvh */
5
6
  min-height: 100lvh;
6
7
  }
7
8
 
@@ -19,6 +20,7 @@
19
20
 
20
21
  .aksel-page__content--fullheight {
21
22
  min-height: 100vh;
23
+ /* biome-ignore lint/suspicious/noDuplicateProperties: vh is fallback for browsers that do not support lvh */
22
24
  min-height: 100lvh;
23
25
  }
24
26
 
package/src/skeleton.css CHANGED
@@ -27,9 +27,7 @@
27
27
 
28
28
  .aksel-skeleton--text {
29
29
  height: auto;
30
- transform-origin: 0 55%;
31
- transform: scale(1, 0.6);
32
- border-radius: var(--ax-radius-8);
30
+ clip-path: inset(20% 0 round var(--ax-radius-4));
33
31
 
34
32
  &:empty::before {
35
33
  content: "\00a0";
package/src/table.css CHANGED
@@ -278,6 +278,12 @@
278
278
  border-bottom: 1px solid var(--ax-border-neutral-subtleA);
279
279
  }
280
280
 
281
+ .aksel-table__expandable-row {
282
+ &:has(+ .aksel-table__expanded-row[data-state="closed"] + .aksel-table__row--selected) > :is(th, td) {
283
+ border-color: var(--ax-border-default);
284
+ }
285
+ }
286
+
281
287
  .aksel-table__expanded-row {
282
288
  &:has(+ .aksel-table__row--selected) {
283
289
  & .aksel-table__expanded-row-collapse {
package/src/timeline.css CHANGED
@@ -41,6 +41,17 @@
41
41
  background: var(--ax-bg-neutral-softA);
42
42
  margin: var(--ax-space-16) 0;
43
43
  grid-column: 2;
44
+
45
+ &:focus {
46
+ outline: none;
47
+ }
48
+
49
+ @media (forced-colors: active) {
50
+ &:focus {
51
+ outline: 1px solid highlight;
52
+ outline-offset: -1px;
53
+ }
54
+ }
44
55
  }
45
56
 
46
57
  .aksel-timeline__row--active {
@@ -73,6 +84,7 @@
73
84
  }
74
85
 
75
86
  .aksel-timeline__period {
87
+ container-type: inline-size;
76
88
  height: 100%;
77
89
  border-radius: var(--ax-radius-full);
78
90
  position: absolute;
@@ -98,7 +110,7 @@
98
110
  }
99
111
 
100
112
  .aksel-timeline__period--inner {
101
- margin: 0 var(--ax-space-8);
113
+ margin: 0 clamp(var(--ax-space-4), 17cqi, var(--ax-space-8));
102
114
  overflow: hidden;
103
115
  white-space: nowrap;
104
116
  text-overflow: clip;
@@ -108,7 +120,13 @@
108
120
  }
109
121
 
110
122
  .aksel-timeline__period--inner svg {
111
- flex-shrink: 0;
123
+ flex-shrink: 1;
124
+ }
125
+
126
+ @container (inline-size < 1.4rem) {
127
+ .aksel-timeline__period--inner {
128
+ margin: 0 10cqi;
129
+ }
112
130
  }
113
131
 
114
132
  .aksel-timeline__period--clickable {