Skip to content

Commit f45d853

Browse files
eirikbackerBarsnes
andauthored
fix: start implementing css principles (#2313)
- ✅ Changes to only `Alert`, `Button`, `Divider` and `Link` to demonstrate principles :) - ✅ Using the pattern `dsc-button-background` and `dsc-button-background--active` for recognition of state variables - ✅ Using pseudo elements with `mask` instead of inline `<svg>` elements for easy reconstruction in other frameworks - ✅ Alphabetically sorting CSS properties for consistent setup - or whatever is automated by our formatter <3 - ✅ Using attributes for setting `size`, `variant` or `colors` - aligning the props interface across frameworks and avoiding invalid states (▶️ Move to `data-ds-variant=""` aka `element.dataset.dsVariant`) - ✅ Moving to `:focus-visible` styling to CSS token _as well_ as utility class, using `box-shadow` only to avoid half pixels - ✅ Moving default styling to main class name, as this allows skipping setting `data-size="md"` on all components - ✅ Moving to `color` instead of `severity` for `Alert` as this aligns with other components props API - ✅ Rendering `Alert` icon inside first heading if present as this makes typographic alignment better (worked with Øyvind) - ✅ Several TODO/questions added to code we should discuss, and font sizing is being discussed with designers 23.08.24 - Closes #2320 - Closes #1992 - Closes #2065 --------- Co-authored-by: Tobias Barsnes <[email protected]>
1 parent 2a5f764 commit f45d853

File tree

28 files changed

+379
-524
lines changed

28 files changed

+379
-524
lines changed

.changeset/healthy-apples-explode.md

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
"@digdir/designsystemet-css": patch
3+
"@digdir/designsystemet-react": patch
4+
"@repo/components": patch
5+
"storefront": patch
6+
"@designsystemet/storybook": patch
7+
"theme": patch
8+
---
9+
10+
Alert, Avatar, Button, Divider, Link: Use data-attributes for variant, size and color and move icons to CSS

apps/_components/src/CodeSnippet/CodeSnippet.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ const CodeSnippet = ({
8282
onMouseEnter={() => setToolTipText('Kopier')}
8383
onClick={() => onButtonClick()}
8484
className={classes.copyButton}
85-
title='Kopier'
85+
aria-label='Kopier'
8686
icon
8787
color='neutral'
8888
size='sm'

apps/storefront/components/SidebarMenu/SidebarMenu.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,13 @@ const SidebarMenu = ({ routerPath }: SidebarMenuProps) => {
4040
<>
4141
<Button
4242
className={classes.toggleBtn}
43-
fullWidth
4443
size='md'
4544
color='neutral'
4645
variant='secondary'
4746
onClick={() => setShowMenu(!showMenu)}
4847
aria-expanded={showMenu}
4948
>
50-
{showMenu ? 'Skjul' : 'Vis'} side meny
49+
{showMenu ? 'Skjul' : 'Vis'} sidemeny
5150
</Button>
5251

5352
<div className={cl(classes.menu, showMenu && classes.activeMenu)}>

apps/storybook/docs-components/Information/Information.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const texts: Record<Texts, { description: string; title?: string }> = {
3030
},
3131
};
3232

33-
const getSeverity = (text: Texts): AlertProps['severity'] => {
33+
const getColor = (text: Texts): AlertProps['color'] => {
3434
switch (text) {
3535
case 'deprecated':
3636
return 'danger';
@@ -50,7 +50,7 @@ export const Information = ({ text, description }: InformationProps) => {
5050
const textData = texts[text];
5151

5252
return (
53-
<Alert className={classes.container} severity={getSeverity(text)}>
53+
<Alert className={classes.container} color={getColor(text)}>
5454
{textData.title && (
5555
<Heading level={2} size='xs' spacing>
5656
{textData.title}

apps/theme/components/Previews/Components/Components.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export const Components = () => {
7676
Glemt passord?
7777
</Link>
7878
</Tooltip>
79-
<Button fullWidth size='sm' className={classes.userBtn}>
79+
<Button size='sm' className={classes.userBtn}>
8080
Opprett ny bruker
8181
</Button>
8282
</div>
@@ -375,17 +375,17 @@ export const Components = () => {
375375
</Accordion.Root>
376376
</div>
377377
<div className={cl(classes.card, classes.alert)}>
378-
<Alert severity='info'>
378+
<Alert color='info'>
379379
Dette er informasjon som du bør lese for å forstå hva som skjer
380380
</Alert>
381-
<Alert severity='warning'>
381+
<Alert color='warning'>
382382
Dette er en advarsel om at noe kan gå galt hvis du ikke følger med
383383
</Alert>
384-
<Alert severity='danger'>
384+
<Alert color='danger'>
385385
Dette er en melding om at noe har gått galt og du bør gjøre noe med
386386
det
387387
</Alert>
388-
<Alert severity='success'>
388+
<Alert color='success'>
389389
Dette er en melding om at noe har gått bra og du kan fortsette
390390
</Alert>
391391
</div>

packages/css/alert.css

+52-53
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,68 @@
11
.ds-alert {
2+
--dsc-alert-background: var(--ds-color-info-surface-default);
23
--dsc-alert-border-color: var(--ds-color-info-border-strong);
34
--dsc-alert-border-radius: min(1rem, var(--ds-border-radius-md));
45
--dsc-alert-color: var(--ds-color-neutral-text-default);
5-
--dsc-alert-icon-color: var(--ds-color-neutral-text-subtle);
6+
--dsc-alert-gap: var(--ds-spacing-2);
7+
--dsc-alert-icon-color: var(--ds-color-info-text-subtle);
68
--dsc-alert-icon-size: var(--ds-sizing-7);
7-
--dsc-alert-background: var(--ds-color-info-surface-default);
9+
--dsc-alert-icon-url: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' d='M3.25 4A.75.75 0 0 1 4 3.25h16a.75.75 0 0 1 .75.75v16a.75.75 0 0 1-.75.75H4a.75.75 0 0 1-.75-.75zM11 7.75a1 1 0 1 1 2 0 1 1 0 0 1-2 0m-1.25 3a.75.75 0 0 1 .75-.75H12a.75.75 0 0 1 .75.75v4.75h.75a.75.75 0 0 1 0 1.5h-3a.75.75 0 0 1 0-1.5h.75v-4h-.75a.75.75 0 0 1-.75-.75'/%3E%3C/svg%3E");
810
--dsc-alert-padding: var(--ds-spacing-6);
911

10-
border: 1px solid var(--dsc-alert-border-color);
11-
border-radius: var(--dsc-alert-border-radius);
1212
background: var(--dsc-alert-background);
13+
border-radius: var(--dsc-alert-border-radius);
14+
border: 1px solid var(--dsc-alert-border-color);
1315
color: var(--dsc-alert-color);
14-
padding: var(--dsc-alert-padding);
15-
display: grid;
16-
grid-auto-flow: column;
17-
grid-auto-columns: min-content auto;
18-
gap: var(--ds-spacing-2);
19-
}
20-
21-
.ds-alert__icon {
22-
height: var(--dsc-alert-icon-size);
23-
width: var(--dsc-alert-icon-size);
24-
color: var(--dsc-alert-icon-color);
25-
}
26-
27-
.ds-alert__content {
28-
display: flex;
29-
flex-direction: column;
30-
}
16+
padding-block: var(--dsc-alert-padding);
17+
padding-inline: calc(var(--dsc-alert-padding) + var(--dsc-alert-icon-size) + var(--dsc-alert-gap)) var(--dsc-alert-padding);
3118

32-
.ds-alert--info {
33-
--dsc-alert-border-color: var(--ds-color-info-border-strong);
34-
--dsc-alert-icon-color: var(--ds-color-info-text-subtle);
35-
--dsc-alert-background: var(--ds-color-info-surface-default);
36-
}
37-
38-
.ds-alert--warning {
39-
--dsc-alert-border-color: var(--ds-color-warning-border-default);
40-
--dsc-alert-icon-color: var(--ds-color-warning-text-subtle);
41-
--dsc-alert-background: var(--ds-color-warning-surface-default);
42-
}
19+
& > :is(h1,h2,h3,h4,h5,h6):first-child::before, /* If Alert starts with Heading, align icon to this */
20+
&:not(:has(> :is(h1,h2,h3,h4,h5,h6):first-child))::before /* If there is no Heading, align icon to Alert itself */ {
21+
background-color: var(--dsc-alert-icon-color);
22+
content: '';
23+
display: block;
24+
height: var(--dsc-alert-icon-size);
25+
margin-inline: calc((var(--dsc-alert-icon-size) + var(--dsc-alert-gap)) * -1); /* Using margin instead of top/left to avoid position: relative and to support dir="rtl" */
26+
mask: var(--dsc-alert-icon-url) center/contain no-repeat;
27+
position: absolute;
28+
translate: 0 calc(.5lh - var(--dsc-alert-icon-size) / 2); /* Center icon to line height */
29+
width: var(--dsc-alert-icon-size);
30+
}
4331

44-
.ds-alert--success {
45-
--dsc-alert-border-color: var(--ds-color-success-border-default);
46-
--dsc-alert-icon-color: var(--ds-color-success-text-subtle);
47-
--dsc-alert-background: var(--ds-color-success-surface-default);
48-
}
32+
/**
33+
* Colors
34+
*/
35+
&[data-color="warning"] {
36+
--dsc-alert-border-color: var(--ds-color-warning-border-default);
37+
--dsc-alert-icon-color: var(--ds-color-warning-text-subtle);
38+
--dsc-alert-background: var(--ds-color-warning-surface-default);
39+
--dsc-alert-icon-url: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M12 2.25a.75.75 0 0 1 .66.39l9.52 17.25a.75.75 0 0 1-.65 1.11H2.47a.75.75 0 0 1-.65-1.11l9.52-17.25a.75.75 0 0 1 .66-.39m0 6.5a.75.75 0 0 1 .75.75v4a.75.75 0 0 1-1.5 0v-4a.75.75 0 0 1 .75-.75m-1 7.75a1 1 0 1 1 2 0 1 1 0 0 1-2 0'/%3E%3C/svg%3E");
40+
}
4941

50-
.ds-alert--danger {
51-
--dsc-alert-border-color: var(--ds-color-danger-border-default);
52-
--dsc-alert-icon-color: var(--ds-color-danger-text-subtle);
53-
--dsc-alert-background: var(--ds-color-danger-surface-default);
54-
}
42+
&[data-color="success"] {
43+
--dsc-alert-background: var(--ds-color-success-surface-default);
44+
--dsc-alert-border-color: var(--ds-color-success-border-default);
45+
--dsc-alert-icon-color: var(--ds-color-success-text-subtle);
46+
--dsc-alert-icon-url: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M12 21.75a9.75 9.75 0 1 0 0-19.5 9.75 9.75 0 0 0 0 19.5m4.95-12.47a.81.81 0 0 0-1.24-1.05l-5.39 6.36-2.62-2.62a.81.81 0 0 0-1.15 1.15l3.25 3.25a.81.81 0 0 0 1.2-.05z'/%3E%3C/svg%3E");
47+
}
5548

56-
.ds-alert--sm {
57-
--dsc-alert-padding: var(--ds-spacing-5);
58-
--dsc-alert-icon-size: var(--ds-sizing-6);
59-
}
49+
&[data-color="danger"] {
50+
--dsc-alert-background: var(--ds-color-danger-surface-default);
51+
--dsc-alert-border-color: var(--ds-color-danger-border-default);
52+
--dsc-alert-icon-color: var(--ds-color-danger-text-subtle);
53+
--dsc-alert-icon-url: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill-rule='evenodd' d='M7.74 2.47a.75.75 0 0 1 .53-.22h7.46a.75.75 0 0 1 .53.22l5.27 5.27c.14.14.22.33.22.53v7.46a.75.75 0 0 1-.22.53l-5.27 5.27a.75.75 0 0 1-.53.22H8.27a.75.75 0 0 1-.53-.22l-5.27-5.27a.75.75 0 0 1-.22-.53V8.27a.75.75 0 0 1 .22-.53zm1.29 5.5a.75.75 0 0 0-1.06 1.06L10.94 12l-2.97 2.97a.75.75 0 1 0 1.06 1.06L12 13.06l2.97 2.97a.75.75 0 1 0 1.06-1.06L13.06 12l2.97-2.97a.75.75 0 0 0-1.06-1.06L12 10.94z'/%3E%3C/svg%3E");
54+
}
6055

61-
.ds-alert--md {
62-
--dsc-alert-padding: var(--ds-spacing-6);
63-
--dsc-alert-icon-size: var(--ds-sizing-7);
64-
}
56+
/**
57+
* Sizes
58+
*/
59+
&[data-size="sm"] {
60+
--dsc-alert-icon-size: var(--ds-sizing-6);
61+
--dsc-alert-padding: var(--ds-spacing-5);
62+
}
6563

66-
.ds-alert--lg {
67-
--dsc-alert-padding: var(--ds-spacing-7);
68-
--dsc-alert-icon-size: var(--ds-sizing-8);
64+
&[data-size="lg"] {
65+
--dsc-alert-icon-size: var(--ds-sizing-8);
66+
--dsc-alert-padding: var(--ds-spacing-7);
67+
}
6968
}

packages/css/avatar.css

+11-11
Original file line numberDiff line numberDiff line change
@@ -43,55 +43,55 @@
4343
mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1em' height='1em' fill='none' viewBox='0 0 24 24' focusable='false' role='img'%3E%3Cpath fill='currentColor' fill-rule='evenodd' d='M8.25 7.5a3.75 3.75 0 1 1 7.5 0 3.75 3.75 0 0 1-7.5 0M12 2.25a5.25 5.25 0 1 0 0 10.5 5.25 5.25 0 0 0 0-10.5M8.288 17.288A5.25 5.25 0 0 1 17.25 21a.75.75 0 0 0 1.5 0 6.75 6.75 0 0 0-13.5 0 .75.75 0 0 0 1.5 0 5.25 5.25 0 0 1 1.538-3.712' clip-rule='evenodd'%3E%3C/path%3E%3C/svg%3E");
4444
}
4545

46-
&[data-ds-variant='circle'] {
46+
&[data-variant='circle'] {
4747
--dsc-avatar-border-radius: var(--ds-border-radius-full);
4848
}
4949

50-
&[data-ds-variant='square'] {
50+
&[data-variant='square'] {
5151
--dsc-avatar-border-radius: var(--ds-border-radius-sm);
5252
}
5353

54-
&[data-ds-color='accent'] {
54+
&[data-color='accent'] {
5555
--dsc-avatar-background: var(--ds-color-accent-base-default);
5656
--dsc-avatar-color: var(--ds-color-accent-contrast-default);
5757
}
5858

59-
&[data-ds-color='neutral'] {
59+
&[data-color='neutral'] {
6060
--dsc-avatar-background: var(--ds-color-neutral-base-default);
6161
--dsc-avatar-color: var(--ds-color-neutral-contrast-default);
6262
}
6363

64-
&[data-ds-color='brand1'] {
64+
&[data-color='brand1'] {
6565
--dsc-avatar-background: var(--ds-color-brand1-base-default);
6666
--dsc-avatar-color: var(--ds-color-brand1-contrast-default);
6767
}
6868

69-
&[data-ds-color='brand2'] {
69+
&[data-color='brand2'] {
7070
--dsc-avatar-background: var(--ds-color-brand2-base-default);
7171
--dsc-avatar-color: var(--ds-color-brand2-contrast-default);
7272
}
7373

74-
&[data-ds-color='brand3'] {
74+
&[data-color='brand3'] {
7575
--dsc-avatar-background: var(--ds-color-brand3-base-default);
7676
--dsc-avatar-color: var(--ds-color-brand3-contrast-default);
7777
}
7878

79-
&[data-ds-size='xs'] {
79+
&[data-size='xs'] {
8080
--dsc-avatar-size: var(--ds-sizing-7);
8181
--dsc-avatar-padding: var(--ds-spacing-1);
8282
}
8383

84-
&[data-ds-size='sm'] {
84+
&[data-size='sm'] {
8585
--dsc-avatar-size: var(--ds-sizing-9);
8686
--dsc-avatar-padding: var(--ds-spacing-1);
8787
}
8888

89-
&[data-ds-size='md'] {
89+
&[data-size='md'] {
9090
--dsc-avatar-size: var(--ds-sizing-12);
9191
--dsc-avatar-padding: var(--ds-spacing-2);
9292
}
9393

94-
&[data-ds-size='lg'] {
94+
&[data-size='lg'] {
9595
--dsc-avatar-size: var(--ds-sizing-15);
9696
--dsc-avatar-padding: var(--ds-spacing-2);
9797
}

0 commit comments

Comments
 (0)