diff options
Diffstat (limited to 'src/theme/NavbarItem/NavbarNavLink.jsx')
-rw-r--r-- | src/theme/NavbarItem/NavbarNavLink.jsx | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/src/theme/NavbarItem/NavbarNavLink.jsx b/src/theme/NavbarItem/NavbarNavLink.jsx new file mode 100644 index 0000000..cb151ea --- /dev/null +++ b/src/theme/NavbarItem/NavbarNavLink.jsx | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * Copyright (c) Facebook, Inc. and its affiliates. | ||
3 | * Copyright (c) 2023 Kristóf Marussy <kristof@marussy.com> | ||
4 | * | ||
5 | * SPDX-License-Identifier: MIT | ||
6 | * | ||
7 | * This file was derived from | ||
8 | * https://github.com/facebook/docusaurus/blob/c745021b01a8b88d34e1d772278d7171ad8acdf5/packages/docusaurus-theme-classic/src/theme/NavbarItem/NavbarNavLink.tsx | ||
9 | * via the `swizzle` mechanism of Docusaurus. | ||
10 | * | ||
11 | * It was modified to correctly track the change of the active anchor | ||
12 | * when `setHash` from `@site/src/components/ActiveSectionProvider` is called. | ||
13 | */ | ||
14 | |||
15 | import React from 'react'; | ||
16 | import Link from '@docusaurus/Link'; | ||
17 | import useBaseUrl from '@docusaurus/useBaseUrl'; | ||
18 | import isInternalUrl from '@docusaurus/isInternalUrl'; | ||
19 | import { isRegexpStringMatch } from '@docusaurus/theme-common'; | ||
20 | import IconExternalLink from '@theme/Icon/ExternalLink'; | ||
21 | import { useActiveSection } from '@site/src/components/ActiveSectionProvider'; | ||
22 | export default function NavbarNavLink({ | ||
23 | activeBasePath, | ||
24 | activeBaseRegex, | ||
25 | to, | ||
26 | href, | ||
27 | label, | ||
28 | html, | ||
29 | isDropdownLink, | ||
30 | prependBaseUrlToHref, | ||
31 | ...props | ||
32 | }) { | ||
33 | const { hash: activeSectionHash } = useActiveSection(); | ||
34 | // TODO all this seems hacky | ||
35 | // {to: 'version'} should probably be forbidden, in favor of {to: '/version'} | ||
36 | const toUrl = useBaseUrl(to); | ||
37 | // Check whether the target URL has a hash. | ||
38 | const hashMatch = toUrl?.match(/#.+$/); | ||
39 | const activeBaseUrl = useBaseUrl(activeBasePath); | ||
40 | const normalizedHref = useBaseUrl(href, { forcePrependBaseUrl: true }); | ||
41 | const isExternalLink = label && href && !isInternalUrl(href); | ||
42 | // Link content is set through html XOR label | ||
43 | const linkContentProps = html | ||
44 | ? { dangerouslySetInnerHTML: { __html: html } } | ||
45 | : { | ||
46 | children: ( | ||
47 | <> | ||
48 | {label} | ||
49 | {isExternalLink && ( | ||
50 | <IconExternalLink | ||
51 | {...(isDropdownLink && { width: 12, height: 12 })} | ||
52 | /> | ||
53 | )} | ||
54 | </> | ||
55 | ), | ||
56 | }; | ||
57 | if (href) { | ||
58 | return ( | ||
59 | <Link | ||
60 | href={prependBaseUrlToHref ? normalizedHref : href} | ||
61 | {...props} | ||
62 | {...linkContentProps} | ||
63 | /> | ||
64 | ); | ||
65 | } | ||
66 | return ( | ||
67 | <Link | ||
68 | to={toUrl} | ||
69 | isNavLink | ||
70 | {...((activeBasePath || activeBaseRegex || hashMatch) && { | ||
71 | isActive: (_match, location) => { | ||
72 | if (activeBaseRegex) { | ||
73 | return isRegexpStringMatch(activeBaseRegex, location.pathname); | ||
74 | } | ||
75 | if (activeBaseUrl) { | ||
76 | return location.pathname.startsWith(activeBaseUrl); | ||
77 | } | ||
78 | // Make sure to only highlight links with a hash when hash also matches. | ||
79 | return ( | ||
80 | !hashMatch || hashMatch[0] === (activeSectionHash ?? location.hash) | ||
81 | ); | ||
82 | }, | ||
83 | })} | ||
84 | {...props} | ||
85 | {...linkContentProps} | ||
86 | /> | ||
87 | ); | ||
88 | } | ||