Skip to content

Commit 4a6a9e0

Browse files
EbonsignoriCopilot
andauthored
Migrate Breadcrumbs to @primer/react-brand (#62084)
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent 2d42689 commit 4a6a9e0

3 files changed

Lines changed: 57 additions & 51 deletions

File tree

src/fixtures/tests/breadcrumbs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ describe('breadcrumbs', () => {
2424

2525
test('short titles are preferred', async () => {
2626
const $ = await getDOM('/get-started/foo/bar')
27-
const links = $('[data-testid=breadcrumbs-in-article] a:last-child')
27+
const links = $('[data-testid=breadcrumbs-in-article] li:last-child a')
2828
expect(links.text()).toBe('Bar')
2929
})
3030

src/frame/components/page-header/Breadcrumbs.module.scss

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 56 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
import type { MouseEvent } from 'react'
2+
import { useRouter } from 'next/router'
13
import cx from 'classnames'
4+
import { Breadcrumbs as BrandBreadcrumbs } from '@primer/react-brand'
25

36
import { useMainContext } from '../context/MainContext'
4-
import { Link } from '@/frame/components/Link'
5-
6-
import styles from './Breadcrumbs.module.scss'
77

88
type Props = {
99
inHeader?: boolean
@@ -16,55 +16,64 @@ export type BreadcrumbT = {
1616

1717
export const Breadcrumbs = ({ inHeader }: Props) => {
1818
const { breadcrumbs } = useMainContext()
19+
const router = useRouter()
20+
21+
// BrandBreadcrumbs.Item renders a plain <a>, so intercept clicks to restore
22+
// next/link-style client-side navigation. Modifier/middle clicks fall through
23+
// to the browser so open-in-new-tab still works, and the <a href> keeps the
24+
// links crawlable for SSR.
25+
const handleClick = (event: MouseEvent<HTMLAnchorElement>, href: string) => {
26+
if (
27+
event.defaultPrevented ||
28+
event.button !== 0 ||
29+
event.metaKey ||
30+
event.ctrlKey ||
31+
event.shiftKey ||
32+
event.altKey ||
33+
!href.startsWith('/')
34+
) {
35+
return
36+
}
37+
event.preventDefault()
38+
// hrefs already include the locale prefix (e.g. /en/...), so disable
39+
// Next.js locale handling to avoid double-prefixing.
40+
router.push(href, undefined, { locale: false })
41+
}
1942

2043
return (
21-
/*
22-
NOTE: The breadcrumbs class and the nav tag are used by the
23-
Lunr search scripts. The a tag generated by the Link is also used.
24-
If these change, please also change
25-
updating src/search/scripts/parse-page-sections-into-records.ts.
26-
*/
27-
<nav
44+
<BrandBreadcrumbs
2845
data-testid={inHeader ? 'breadcrumbs-header' : 'breadcrumbs-in-article'}
29-
className={cx('f5 breadcrumbs', styles.breadcrumbs)}
3046
aria-label="Breadcrumb"
3147
data-container="breadcrumbs"
3248
>
33-
<ul>
34-
{Object.values(breadcrumbs)
35-
.filter(Boolean)
36-
.map((breadcrumb, i, arr) => {
37-
const title = `${breadcrumb.title}`
38-
return [
39-
!breadcrumb.href ? (
40-
<span data-testid="breadcrumb-title" key={title} className="px-2">
41-
{breadcrumb.title}
42-
</span>
43-
) : (
44-
<li className="d-inline-block" key={title}>
45-
<Link
46-
data-testid="breadcrumb-link"
47-
href={breadcrumb.href}
48-
title={title}
49-
className={cx(
50-
'Link--primary mr-2 color-fg-muted',
51-
// Show the last breadcrumb if it's in the header, but not if it's in the article
52-
// If there's only 1 breadcrumb, show it
53-
!inHeader && i === arr.length - 1 && arr.length !== 1 && 'd-none',
54-
)}
55-
>
56-
{breadcrumb.title}
57-
</Link>
58-
{i !== arr.length - 1 ? (
59-
<span className="color-fg-muted pr-2" key={`${i}-slash`}>
60-
/
61-
</span>
62-
) : null}
63-
</li>
64-
),
65-
]
66-
})}
67-
</ul>
68-
</nav>
49+
{Object.values(breadcrumbs)
50+
.filter(Boolean)
51+
.map((breadcrumb, i, arr) => {
52+
const title = `${breadcrumb.title}`
53+
if (!breadcrumb.href) {
54+
return (
55+
<li key={title}>
56+
<span data-testid="breadcrumb-title">{breadcrumb.title}</span>
57+
</li>
58+
)
59+
}
60+
return (
61+
<BrandBreadcrumbs.Item
62+
data-testid="breadcrumb-link"
63+
key={title}
64+
href={breadcrumb.href}
65+
title={title}
66+
onClick={(event) => handleClick(event, breadcrumb.href!)}
67+
className={cx(
68+
// Show the last breadcrumb if it's in the header, but not if it's in the article.
69+
// If there's only 1 breadcrumb, show it.
70+
!inHeader && i === arr.length - 1 && arr.length !== 1 && 'd-none',
71+
)}
72+
>
73+
{breadcrumb.title}
74+
</BrandBreadcrumbs.Item>
75+
)
76+
})}
77+
</BrandBreadcrumbs>
6978
)
7079
}

0 commit comments

Comments
 (0)