Skip to content

Commit

Permalink
feat(Badge): convert to two elements (#2857)
Browse files Browse the repository at this point in the history
resolves #2457

It will be rendered as a pseudo element to make sure size works.
If we put `data-size` directly on the badge, the `font-size` set in
`bade.css` on `.ds-badge` will be ignored
  • Loading branch information
Barsnes authored Dec 11, 2024
1 parent c9c77f7 commit de912ae
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 102 deletions.
6 changes: 6 additions & 0 deletions .changeset/violet-paws-begin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@digdir/designsystemet-css": patch
"@digdir/designsystemet-react": patch
---

Badge: Convert to two elements, add `Badge.Position` component for placement
60 changes: 31 additions & 29 deletions packages/css/src/badge.css
Original file line number Diff line number Diff line change
@@ -1,91 +1,93 @@
.ds-badge {
/* color vars */
--dsc-badge-background: var(--ds-color-base-default);
--dsc-badge-color: var(--ds-color-contrast-default);

/* What do we do here? */

&[data-color='neutral'] {
--dsc-badge-background: var(--ds-color-neutral-surface-default);
--dsc-badge-color: var(--ds-color-neutral-text-default);
}

/* sizing vars */
--dsc-badge-padding: 0 calc(var(--ds-spacing-1) + calc(var(--ds-spacing-1) / 2));
--dsc-badge-size: calc(var(--ds-sizing-3) + calc(var(--ds-spacing-1) / 2));

box-sizing: border-box;
display: inline-flex;
line-height: var(--ds-line-height-sm);
position: relative;

&::before {
content: attr(data-count);
background: var(--dsc-badge-background);
border-radius: var(--ds-border-radius-full);
box-sizing: border-box;
color: var(--dsc-badge-color);
display: grid;
display: inline-grid;
font-size: var(--ds-font-size-minus-1); /* Default to small when size is not defined */
min-height: var(--dsc-badge-size);
min-width: var(--dsc-badge-size);
padding: var(--dsc-badge-padding);
place-items: center;
box-sizing: border-box;
line-height: var(--ds-line-height-sm);
width: fit-content;
}

& :where(img, svg) {
flex-shrink: 0; /* Never shrink icon */
font-size: 1.25em; /* Auto scale icon based on font-size */
/* What do we do here? */

&[data-color='neutral'] {
--dsc-badge-background: var(--ds-color-neutral-surface-default);
--dsc-badge-color: var(--ds-color-neutral-text-default);
}
}

/* If placement is present, we are floating */
&[data-placement]::before {
.ds-badge--position {
box-sizing: border-box;
display: inline-flex;
position: relative;
height: fit-content;
width: fit-content;

& .ds-badge::before {
position: absolute;
}

&[data-placement='top-right']::before {
& :where(img, svg) {
flex-shrink: 0; /* Never shrink icon */
font-size: 1.25em; /* Auto scale icon based on font-size */
}

&[data-placement='top-right'] .ds-badge::before {
top: 0;
right: 0;
translate: 50% -50%;
}

&[data-placement='top-left']::before {
&[data-placement='top-left'] .ds-badge::before {
top: 0;
left: 0;
translate: -50% -50%;
}

&[data-placement='bottom-right']::before {
&[data-placement='bottom-right'] .ds-badge::before {
bottom: 0;
right: 0;
translate: 50% 50%;
}

&[data-placement='bottom-left']::before {
&[data-placement='bottom-left'] .ds-badge::before {
bottom: 0;
left: 0;
translate: -50% 50%;
}

&[data-placement='top-right'][data-overlap='circle']::before {
&[data-placement='top-right'][data-overlap='circle'] .ds-badge::before {
top: 14%;
right: 14%;
translate: 50% -50%;
}

&[data-placement='top-left'][data-overlap='circle']::before {
&[data-placement='top-left'][data-overlap='circle'] .ds-badge::before {
top: 14%;
left: 14%;
translate: -50% -50%;
}

&[data-placement='bottom-right'][data-overlap='circle']::before {
&[data-placement='bottom-right'][data-overlap='circle'] .ds-badge::before {
bottom: 14%;
right: 14%;
translate: 50% 50%;
}

&[data-placement='bottom-left'][data-overlap='circle']::before {
&[data-placement='bottom-left'][data-overlap='circle'] .ds-badge::before {
bottom: 14%;
left: 14%;
translate: -50% 50%;
Expand Down
5 changes: 3 additions & 2 deletions packages/react/src/components/Avatar/Avatar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,12 @@ export const InDropdown: Story = () => (
<Dropdown.List>
<Dropdown.Item>
<Dropdown.Button>
<Badge overlap='circle' data-color='danger' data-size='sm'>
<Badge.Position overlap='circle'>
<Badge data-color='danger' data-size='sm'></Badge>
<Avatar aria-label='Ola Nordmann' data-size='xs'>
ON
</Avatar>
</Badge>
</Badge.Position>
Ola Nordmann
</Dropdown.Button>
</Dropdown.Item>
Expand Down
12 changes: 4 additions & 8 deletions packages/react/src/components/Badge/Badge.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,13 @@ import * as BadgeStories from './Badge.stories';
import { Badge } from '@digdir/designsystemet-react';

/* Inline */
<Badge count={5} />
<Badge />

/* Flytende over element */
<Badge count={5}>
<Badge.Position>
<Badge />
<Elem />
</Badge>

/* Flytende over element som dot */
<Badge>
<Elem />
</Badge>
</Badge.Position>
```

## Flytende over element
Expand Down
84 changes: 49 additions & 35 deletions packages/react/src/components/Badge/Badge.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from '@navikt/aksel-icons';
import { Button } from '../Button';
import { Tabs } from '../Tabs';
import { Badge } from './Badge';
import { Badge } from './';

type Story = StoryFn<typeof Badge>;

Expand All @@ -22,13 +22,13 @@ const meta: Meta<typeof Badge> = {

export default meta;

export const Preview: Story = (args) => <Badge {...args}></Badge>;
export const Preview: Story = (args) => <Badge {...args} />;

Preview.args = {
'data-size': 'md',
count: 10,
maxCount: 9,
'data-color': 'accent',
count: 15,
maxCount: 9,
};

export const Floating: Story = (args) => (
Expand All @@ -38,19 +38,24 @@ export const Floating: Story = (args) => (
gap: 'var(--ds-spacing-6)',
}}
>
<Badge data-color='accent' placement='top-right'>
<Badge.Position placement='top-right'>
<Badge data-color='accent'></Badge>
<EnvelopeClosedFillIcon title='Meldinger' />
</Badge>
<Badge data-color='accent' placement='top-left'>
</Badge.Position>
<Badge.Position placement='top-left'>
<Badge data-color='accent'></Badge>
<EnvelopeClosedFillIcon title='Meldinger' />
</Badge>
<Badge data-color='accent' placement='bottom-right'>
</Badge.Position>
<Badge.Position placement='bottom-right'>
<Badge data-color='accent'></Badge>
<EnvelopeClosedFillIcon title='Meldinger' />
</Badge>
<Badge data-color='accent' placement='bottom-left'>
</Badge.Position>
<Badge.Position placement='bottom-left'>
<Badge data-color='accent'></Badge>
<EnvelopeClosedFillIcon title='Meldinger' />
</Badge>
<Badge data-color='accent' placement='top-right' overlap='circle'>
</Badge.Position>
<Badge.Position placement='top-right' overlap='circle'>
<Badge data-color='accent'></Badge>
<div
style={{
width: '2rem',
Expand All @@ -59,8 +64,9 @@ export const Floating: Story = (args) => (
backgroundColor: 'var(--ds-color-brand2-base-default)',
}}
/>
</Badge>
<Badge data-color='accent' placement='top-left' overlap='circle'>
</Badge.Position>
<Badge.Position placement='top-left' overlap='circle'>
<Badge data-color='accent'></Badge>
<div
style={{
width: '2rem',
Expand All @@ -69,8 +75,9 @@ export const Floating: Story = (args) => (
backgroundColor: 'var(--ds-color-brand2-base-default)',
}}
/>
</Badge>
<Badge data-color='accent' placement='bottom-right' overlap='circle'>
</Badge.Position>
<Badge.Position placement='bottom-right' overlap='circle'>
<Badge data-color='accent'></Badge>
<div
style={{
width: '2rem',
Expand All @@ -79,8 +86,9 @@ export const Floating: Story = (args) => (
backgroundColor: 'var(--ds-color-brand2-base-default)',
}}
/>
</Badge>
<Badge data-color='accent' placement='bottom-left' overlap='circle'>
</Badge.Position>
<Badge.Position placement='bottom-left' overlap='circle'>
<Badge data-color='accent'></Badge>
<div
style={{
width: '2rem',
Expand All @@ -89,7 +97,7 @@ export const Floating: Story = (args) => (
backgroundColor: 'var(--ds-color-brand2-base-default)',
}}
/>
</Badge>
</Badge.Position>
</div>
);

Expand All @@ -100,16 +108,16 @@ export const CustomPlacement: Story = (args) => (
gap: 'var(--ds-spacing-6)',
}}
>
<Badge
data-color='accent'
<Badge.Position
placement='top-right'
style={{
top: '16%',
right: '10%',
}}
>
<Badge data-color='accent'></Badge>
<EnvelopeClosedFillIcon title='Meldinger' />
</Badge>
</Badge.Position>
</div>
);

Expand All @@ -120,15 +128,18 @@ export const Status: Story = (args) => (
gap: 'var(--ds-spacing-4)',
}}
>
<Badge data-color='danger' data-size='sm'>
<Badge.Position data-size='sm'>
<Badge data-color='danger' />
<VideoFillIcon title='Videokamera' />
</Badge>
<Badge data-color='danger' data-size='md'>
</Badge.Position>
<Badge.Position data-size='md'>
<Badge data-color='danger' />
<VideoFillIcon title='Videokamera' />
</Badge>
<Badge data-color='danger' data-size='lg'>
</Badge.Position>
<Badge.Position data-size='lg'>
<Badge data-color='danger' />
<VideoFillIcon title='Videokamera' />
</Badge>
</Badge.Position>
</div>
);

Expand Down Expand Up @@ -161,19 +172,22 @@ export const InButton: Story = (args) => (
}}
>
<Button icon variant='tertiary'>
<Badge data-color='danger' count={1000} maxCount={99} data-size='sm'>
<Badge.Position>
<Badge data-color='danger' count={1000} maxCount={99} />
<InboxIcon title='Innboks' />
</Badge>
</Badge.Position>
</Button>
<Button icon variant='tertiary'>
<Badge data-color='danger' count={10} data-size='sm'>
<Badge.Position>
<Badge data-color='danger' count={10} />
<ChatIcon title='Meldinger' />
</Badge>
</Badge.Position>
</Button>
<Button icon variant='tertiary'>
<Badge data-color='danger' data-size='sm'>
<Badge.Position>
<Badge data-color='danger'></Badge>
<VideoIcon title='Skru på video' />
</Badge>
</Badge.Position>
</Button>
</div>
);
Loading

0 comments on commit de912ae

Please sign in to comment.