From a9f3f467605c53154122db51551535493ecda3e0 Mon Sep 17 00:00:00 2001 From: scar055 Date: Wed, 5 Jun 2024 12:01:21 +0200 Subject: [PATCH 1/6] chore: the breadcrumb separator moved outside link --- .../components/Breadcrumb/index.module.scss | 4 ++++ .../ui/src/components/Breadcrumb/index.tsx | 20 +++++++++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/ui/src/components/Breadcrumb/index.module.scss b/packages/ui/src/components/Breadcrumb/index.module.scss index 8708698fc..50ca7e8e1 100644 --- a/packages/ui/src/components/Breadcrumb/index.module.scss +++ b/packages/ui/src/components/Breadcrumb/index.module.scss @@ -16,6 +16,10 @@ margin-inline-end: 8px; } +.utrecht-breadcrumb-nav__separator { + margin-inline-end: var(--utrecht-space-inline-xs); +} + .utrecht-breadcrumb-nav__link { --utrecht-link-focus-color: var(--utrecht-color-black); diff --git a/packages/ui/src/components/Breadcrumb/index.tsx b/packages/ui/src/components/Breadcrumb/index.tsx index 808acab4f..8b0b0a2a9 100644 --- a/packages/ui/src/components/Breadcrumb/index.tsx +++ b/packages/ui/src/components/Breadcrumb/index.tsx @@ -72,6 +72,11 @@ export const Breadcrumbs = ({ .filter(({ label }) => label) .map(({ href, label, current }: any, index: number) => ( + {links.length === 1 && label?.toLowerCase() !== 'home' && ( + + + + )} - {links.length === 1 && label?.toLowerCase() !== 'home' && ( - - - - )} {label} - {index !== links.length - 1 && ( - - - - )} + {index !== links.length - 1 && ( + + + + )} ))} From 5db4fe7fb6f7ce9b9e6b8f01c2bf93d30d751663 Mon Sep 17 00:00:00 2001 From: scar055 Date: Wed, 5 Jun 2024 13:48:05 +0200 Subject: [PATCH 2/6] style: add media query for the small breadcrumb --- packages/ui/src/components/Breadcrumb/index.module.scss | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/ui/src/components/Breadcrumb/index.module.scss b/packages/ui/src/components/Breadcrumb/index.module.scss index 50ca7e8e1..953e64182 100644 --- a/packages/ui/src/components/Breadcrumb/index.module.scss +++ b/packages/ui/src/components/Breadcrumb/index.module.scss @@ -16,8 +16,10 @@ margin-inline-end: 8px; } -.utrecht-breadcrumb-nav__separator { - margin-inline-end: var(--utrecht-space-inline-xs); +@media (width >= 360px) { + .utrecht-breadcrumb-nav__separator { + margin-inline-end: var(--utrecht-space-inline-xs); + } } .utrecht-breadcrumb-nav__link { From 351999a83d55a53e5b8dbbc43dae99986f4b8b83 Mon Sep 17 00:00:00 2001 From: scar055 Date: Mon, 24 Jun 2024 15:21:55 +0200 Subject: [PATCH 3/6] refactor: changes to the breadcrumb removed unnececary code, add new props and changed rel --- .../ui/src/components/Breadcrumb/index.tsx | 95 +++++++++---------- 1 file changed, 45 insertions(+), 50 deletions(-) diff --git a/packages/ui/src/components/Breadcrumb/index.tsx b/packages/ui/src/components/Breadcrumb/index.tsx index 8b0b0a2a9..4cda6a66e 100644 --- a/packages/ui/src/components/Breadcrumb/index.tsx +++ b/packages/ui/src/components/Breadcrumb/index.tsx @@ -12,21 +12,24 @@ import './index.module.scss'; import styles from './index.module.scss'; import { useScreenSize } from '../../hooks'; +export const extendLink = (link: BreadcrumbLinkType) => ({ + // Use default `rel`, but actual optional rel should override this + rel: link.current ? undefined : link.href === '/' ? 'home' : 'up', + ...link, +}); + const css = classnames.bind(styles); type BreadcrumbLinkType = { href: string; label: string; current: boolean; + rel?: string; }; interface BreadcrumbProps extends BreadcrumbNavProps { links: BreadcrumbLinkType[]; Link?: ComponentType; - backLink?: { - href: string; - label: string; - current: boolean; - }; + backLink?: BreadcrumbLinkType; breakpoint?: number; } @@ -41,59 +44,51 @@ export const Breadcrumbs = ({ const smallScreen = Number(screenSize) <= breakpoint; - if (smallScreen && backLink?.href && backLink.label) { + const linkData = links.map(extendLink); + const backLinkData = backLink && extendLink(backLink); + + if ( + (smallScreen && backLinkData?.href && backLinkData.label) || + (links.length === 1 && backLinkData?.href && backLinkData.label) + ) { return ( - - - {backLink?.label?.toLowerCase() !== 'home' && ( - - - - )} - {backLink.label} - - + + {backLinkData?.rel === 'up' && } {backLinkData.label} + ); } return ( - {links && - links.length > 0 && - links - .filter(({ label }) => label) - .map(({ href, label, current }: any, index: number) => ( - - {links.length === 1 && label?.toLowerCase() !== 'home' && ( - - - - )} - - {label} - - {index !== links.length - 1 && ( - - - - )} - - ))} + {linkData + .filter(({ label }) => label) + .map(({ href, label, current, rel }: any, index: number) => ( + + + {label} + + {index !== links.length - 1 && ( + + + + )} + + ))} ); }; From 5712a4a6970c3505edcb0d912a6063f5e7a0138c Mon Sep 17 00:00:00 2001 From: Robbert Broersma Date: Mon, 29 Jul 2024 00:10:28 +0200 Subject: [PATCH 4/6] fix: render custom Link component in Breadcrumbs --- packages/ui/src/components/Breadcrumb/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui/src/components/Breadcrumb/index.tsx b/packages/ui/src/components/Breadcrumb/index.tsx index 4cda6a66e..a9cef4321 100644 --- a/packages/ui/src/components/Breadcrumb/index.tsx +++ b/packages/ui/src/components/Breadcrumb/index.tsx @@ -78,7 +78,7 @@ export const Breadcrumbs = ({ rel={rel} index={index} current={current} - Link={UtrechtLink} + Link={Link} > {label} From c3119005591704c48759856bdd99d1d9c74ba425 Mon Sep 17 00:00:00 2001 From: Robbert Broersma Date: Mon, 29 Jul 2024 00:13:58 +0200 Subject: [PATCH 5/6] chore: remove unused class names from Breadcrumbs --- packages/ui/src/components/Breadcrumb/index.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ui/src/components/Breadcrumb/index.tsx b/packages/ui/src/components/Breadcrumb/index.tsx index a9cef4321..ce0618596 100644 --- a/packages/ui/src/components/Breadcrumb/index.tsx +++ b/packages/ui/src/components/Breadcrumb/index.tsx @@ -52,9 +52,9 @@ export const Breadcrumbs = ({ (links.length === 1 && backLinkData?.href && backLinkData.label) ) { return ( - + + {linkData .filter(({ label }) => label) .map(({ href, label, current, rel }: any, index: number) => ( Date: Mon, 29 Jul 2024 00:14:44 +0200 Subject: [PATCH 6/6] test: breadcrumb navigation unit tests --- .../components/Breadcrumb/Breadcrumb.test.tsx | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 packages/ui/src/components/Breadcrumb/Breadcrumb.test.tsx diff --git a/packages/ui/src/components/Breadcrumb/Breadcrumb.test.tsx b/packages/ui/src/components/Breadcrumb/Breadcrumb.test.tsx new file mode 100644 index 000000000..489795eb2 --- /dev/null +++ b/packages/ui/src/components/Breadcrumb/Breadcrumb.test.tsx @@ -0,0 +1,93 @@ +import { render, screen } from '@testing-library/react'; +import Link from 'next/link'; +import { Breadcrumbs } from './index'; +import '@testing-library/jest-dom'; + +describe('Breadcrumb navigation', () => { + const props = { + label: 'Kruimelpad', + links: [ + { + href: 'https://www.utrecht.nl/', + label: 'Home', + current: false, + rel: 'home', + }, + { + href: '/', + label: 'Online loket', + current: true, + }, + ], + backLink: { + href: '/', + label: 'Online loket', + current: false, + }, + Link: Link, + }; + + it('renders a navigation landmark', () => { + render(); + + const navigation = screen.getByRole('navigation', { name: 'Kruimelpad' }); + + expect(navigation).toBeInTheDocument(); + }); + + it('renders links', () => { + render(); + + const links = screen.getAllByRole('link'); + + expect(links.length).toBe(props.links.length); + }); + + it('renders a link', () => { + render(); + + const link = screen.getByRole('link', { name: 'Home' }); + + expect(link).toBeInTheDocument(); + expect(link).toHaveAttribute('href', 'https://www.utrecht.nl/'); + expect(link).toHaveAttribute('rel', 'home'); + }); + + it('renders a current link', () => { + render(); + + const link = screen.getByRole('link', { name: 'Online loket', current: 'page' }); + + expect(link).toBeInTheDocument(); + }); + + it('renders no separator for one link', () => { + const { container } = render(); + + const separator = container.querySelector('.utrecht-breadcrumb-nav__separator'); + + expect(separator).not.toBeInTheDocument(); + }); + + it('renders separators between items', () => { + const { container } = render(); + + const separators = container.querySelectorAll( + '.utrecht-breadcrumb-nav__item + .utrecht-breadcrumb-nav__separator + .utrecht-breadcrumb-nav__item', + ); + + expect(separators.length).toBe(props.links.length - 1); + }); + + it('renders a custom Link component', () => { + const { container } = render( + } />, + ); + + const links = container.querySelectorAll('.custom-link'); + + expect(links.length).toBe(props.links.length); + }); + + // TODO: Test small screen breadcrumb +});