Skip to content

Commit

Permalink
feat(Breadcrumbs): new component (#2226)
Browse files Browse the repository at this point in the history
- First PR on new component - probably potential for enhancements ☺️ 
- Fixes #1104
- Adds breadcrumbs components
  • Loading branch information
eirikbacker authored Aug 14, 2024
1 parent f32f1fb commit c73d83c
Show file tree
Hide file tree
Showing 15 changed files with 534 additions and 9 deletions.
6 changes: 6 additions & 0 deletions .changeset/spotty-pumas-cross.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@digdir/designsystemet-css": patch
"@digdir/designsystemet-react": minor
---

Breadcrumbs: ✨ new component
19 changes: 12 additions & 7 deletions apps/storybook/.storybook/preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@ import { Link, List, Paragraph, Table } from '@digdir/designsystemet-react';

import customTheme from './customTheme';

const viewports = [320, 375, 576, 768, 992, 1200, 1440].map((width) => ({
name: `${width}px`,
styles: {
width: `${width}px`,
height: '100%',
},
}));
const viewports: Record<string, object> = {};
const viewportWidths = [320, 375, 576, 768, 992, 1200, 1440];

for (const width of viewportWidths) {
viewports[`${width}px`] = {
name: `${width}px`,
styles: {
width: `${width}px`,
height: '100%',
},
};
}

type Props = Record<string, unknown>;

Expand Down
72 changes: 72 additions & 0 deletions packages/css/breadcrumbs.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
.ds-breadcrumbs {
--dsc-breadcrumbs-spacing: var(--ds-spacing-2);
--dsc-breadcrumbs-chevron-size: var(--ds-sizing-6);
--dsc-breadcrumbs-link-color: inherit;
}

.ds-breadcrumbs--sm {
--dsc-breadcrumbs-spacing: var(--ds-spacing-1);
--dsc-breadcrumbs-chevron-size: var(--ds-sizing-5);
}

.ds-breadcrumbs--md {
--dsc-breadcrumbs-spacing: var(--ds-spacing-2);
--dsc-breadcrumbs-chevron-size: var(--ds-sizing-6);
}

.ds-breadcrumbs--lg {
--dsc-breadcrumbs-spacing: var(--ds-spacing-3);
--dsc-breadcrumbs-chevron-size: var(--ds-sizing-7);
}

.ds-breadcrumbs__list {
display: flex;
flex-wrap: wrap;
list-style-type: none;
margin: 0;
padding: 0;
gap: var(--dsc-breadcrumbs-spacing) 0;
}

.ds-breadcrumbs__item:where(:not(:last-child))::after,
.ds-breadcrumbs > .ds-breadcrumbs__link::before {
background: currentcolor;
content: '';
display: inline-block;
height: var(--dsc-breadcrumbs-chevron-size);
margin-inline: var(--dsc-breadcrumbs-spacing);
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24'%3E%3Cpath d='M9.47 5.97a.75.75 0 0 1 1.06 0l5.5 5.5a.75.75 0 0 1 0 1.06l-5.5 5.5a.75.75 0 1 1-1.06-1.06L14.44 12 9.47 7.03a.75.75 0 0 1 0-1.06'/%3E%3C/svg%3E")
50% / contain no-repeat;
vertical-align: middle;
width: var(--dsc-breadcrumbs-chevron-size);
}

/* When link is direct child of Breadcrumbs, make it back button */
.ds-breadcrumbs > .ds-breadcrumbs__link::before {
margin: 0;
rotate: 180deg;
}

.ds-breadcrumbs__link {
--dsc-link-color: var(--dsc-breadcrumbs-link-color);
--dsc-link-color-visited: var(--dsc-breadcrumbs-link-color);
}

.ds-breadcrumbs__link[aria-current='page'] {
text-decoration: none;
}

.ds-breadcrumbs > .ds-breadcrumbs__link:where(:not(:only-child)) {
display: none;
}

@media (max-width: 650px) {
.ds-breadcrumbs > .ds-breadcrumbs__nav:where(:not(:only-child)) {
display: none;
}

.ds-breadcrumbs > .ds-breadcrumbs__link {
display: block;
width: fit-content;
}
}
1 change: 1 addition & 0 deletions packages/css/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@
@import url('./spinner.css') layer(ds.components);
@import url('./table.css') layer(ds.components);
@import url('./combobox.css') layer(ds.components);
@import url('./breadcrumbs.css') layer(ds.components);
@import url('./badge.css') layer(ds.components);
4 changes: 2 additions & 2 deletions packages/react/src/components/Accordion/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ type AccordionComponent = {
* <Accordion.Root>
* <Accordion.Item>
* <Accordion.Heading>Heading 1</Accordion.Heading>
* <Accordion.Content>Content 1</Accordion.Content>
* </Accordion.Item>
* <Accordion.Content>Content 1</Accordion.Content>
* </Accordion.Item>
* <Accordion.Item>
*/
const Accordion = {} as AccordionComponent;
Expand Down
56 changes: 56 additions & 0 deletions packages/react/src/components/Breadcrumbs/Breadcrumbs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Meta, Controls, Primary, Canvas } from '@storybook/blocks';

import * as BreadcrumbsStories from './Breadcrumbs.stories';

<Meta of={BreadcrumbsStories} />

# Breadcrumbs

`Breadcrumb` er en navigasjon med synlig søkebane. Vi bruker denne komponenten til å hjelpe brukerne å forstå hvor de er i en struktur, for eksempel på en nettside. Da kan de lettere bytte mellom de ulike nivåene i strukturen.

<Primary />
<Controls of={BreadcrumbsStories.Preview} />

## Slik bruker du `Breadcrumb`

Den siste lenken i brødsmulestien blir automatisk markert med `aria-current="page"`

```tsx
<Breadcrumbs.Root>
<Breadcrumbs.Link aria-label="Tilbake til nivå 3">Nivå 3</Breadcrumbs.Link>
<Breadcrumbs.Nav aria-label="Du er her:">
<Breadcrumbs.List>
<Breadcrumbs.Item>
<Breadcrumbs.Link href="https://designsystemet.no/">Nivå 1</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Item>
<Breadcrumbs.Link href="https://designsystemet.no/niva-2/">Nivå 2</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Item>
<Breadcrumbs.Link href="https://designsystemet.no/niva-2/niva-3/">Nivå 3</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Item>
<Breadcrumbs.Link href="https://designsystemet.no/niva-2/niva-3/niva-4/">Nivå 4</Breadcrumbs.Link>
</Breadcrumbs.Item>
</Breadcrumbs.List>
</Breadcrumbs.Nav>
</Breadcrumbs.Root>
```

## Kun tilbake-knapp

Dersom du legger en `Breadcrumbs.Link` som direkte barn av `Breadcrumbs.Root`, vil denne lenken vises som en tilbake-knapp.

<Canvas of={BreadcrumbsStories.BackOnly} />

## Kun sti

Dersom du legger en `Breadcrumbs.List` som direkte barn av `Breadcrumbs.Root`, vil denne vises som en sti.

<Canvas of={BreadcrumbsStories.ListOnly} />

## Både sti på desktop og tilbake-knapp på mobil

Dersom du legger både en `Breadcrumbs.Link` som direkte barn av `Breadcrumbs.Root` og en `Breadcrumbs.List`, vil tilbake-knapp vises på mobil, og sti vises på desktop.

<Canvas of={BreadcrumbsStories.Preview} />
140 changes: 140 additions & 0 deletions packages/react/src/components/Breadcrumbs/Breadcrumbs.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import type { Meta, StoryFn } from '@storybook/react';

import { Breadcrumbs } from '.';

export default {
title: 'Komponenter/Breadcrumbs',
component: Breadcrumbs.Root,
args: {
size: 'md',
},
} as Meta;

export const Preview: StoryFn<typeof Breadcrumbs.Root> = (args) => (
<Breadcrumbs.Root {...args}>
<Breadcrumbs.Link href='#' aria-label='Tilbake til Nivå 3'>
Nivå 3
</Breadcrumbs.Link>
<Breadcrumbs.Nav aria-label='Du er her:'>
<Breadcrumbs.List>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>Nivå 1</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>Nivå 2</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>Nivå 3</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>Nivå 4</Breadcrumbs.Link>
</Breadcrumbs.Item>
</Breadcrumbs.List>
</Breadcrumbs.Nav>
</Breadcrumbs.Root>
);

export const ListOnly: StoryFn<typeof Breadcrumbs.Root> = (args) => (
<Breadcrumbs.Root size='md'>
<Breadcrumbs.Nav aria-label='Du er her:'>
<Breadcrumbs.List>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>Nivå 1</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>Nivå 2</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>Nivå 3</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>Nivå 4</Breadcrumbs.Link>
</Breadcrumbs.Item>
</Breadcrumbs.List>
</Breadcrumbs.Nav>
</Breadcrumbs.Root>
);

export const BackOnly: StoryFn<typeof Breadcrumbs.Root> = (args) => (
<Breadcrumbs.Root size='md'>
<Breadcrumbs.Link href='#' aria-label='Tilbake til Nivå 3'>
Nivå 3
</Breadcrumbs.Link>
</Breadcrumbs.Root>
);

export const LongItems: StoryFn<typeof Breadcrumbs.Root> = (args) => (
<Breadcrumbs.Root {...args}>
<Breadcrumbs.Link
href='#'
aria-label='Tilbake til helsesertifikat for sjømat'
>
Slik søker du om helsesertifikat for sjømat
</Breadcrumbs.Link>
<Breadcrumbs.Nav>
<Breadcrumbs.List aria-label='Du er her:'>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>Hjem</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>
Eksport til land utenfor EU/EØS
</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>Eksport av mat og drikke</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>
Eksport av fisk og sjømat
</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>
Veiledning om helsesertifikat for sjømat
</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>
Slik søker du om helsesertifikat for sjømat
</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>
Slik søker du om helsesertifikat i ny eksportløsning
</Breadcrumbs.Link>
</Breadcrumbs.Item>
</Breadcrumbs.List>
</Breadcrumbs.Nav>
</Breadcrumbs.Root>
);

export const MobileViewport: StoryFn<typeof Breadcrumbs.Root> = (args) => (
<Breadcrumbs.Root {...args}>
<Breadcrumbs.Link href='#' aria-label='Tilbake til Nivå 3'>
Nivå 3
</Breadcrumbs.Link>
<Breadcrumbs.Nav aria-label='Du er her:'>
<Breadcrumbs.List>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>Nivå 1</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>Nivå 2</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>Nivå 3</Breadcrumbs.Link>
</Breadcrumbs.Item>
<Breadcrumbs.Item>
<Breadcrumbs.Link href='#'>Nivå 4</Breadcrumbs.Link>
</Breadcrumbs.Item>
</Breadcrumbs.List>
</Breadcrumbs.Nav>
</Breadcrumbs.Root>
);

MobileViewport.parameters = {
viewport: {
defaultViewport: '375px', // Large mobile default viewport
},
};
Loading

0 comments on commit c73d83c

Please sign in to comment.