fix(core): forward ref to Link's anchor element (#6644)

* feat(core): allow to pass ref into the Link component

* refactor

* add dogfood

Co-authored-by: Joshua Chen <sidachen2003@gmail.com>
This commit is contained in:
Konstantin Tarkus 2022-02-11 07:34:13 +03:00 committed by GitHub
parent 1cd4757828
commit 916e4f1a26
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 60 additions and 12 deletions

View file

@ -5,7 +5,12 @@
* LICENSE file in the root directory of this source tree.
*/
import React, {useEffect, useRef, type ComponentType} from 'react';
import React, {
useEffect,
useImperativeHandle,
useRef,
type ComponentType,
} from 'react';
import {NavLink, Link as RRLink} from 'react-router-dom';
import useDocusaurusContext from './useDocusaurusContext';
@ -31,21 +36,30 @@ declare global {
// like "introduction" to "/baseUrl/introduction" => bad behavior to fix
const shouldAddBaseUrlAutomatically = (to: string) => to.startsWith('/');
function Link({
isNavLink,
to,
href,
activeClassName,
isActive,
'data-noBrokenLinkCheck': noBrokenLinkCheck,
autoAddBaseUrl = true,
...props
}: LinkProps): JSX.Element {
function Link(
{
isNavLink,
to,
href,
activeClassName,
isActive,
'data-noBrokenLinkCheck': noBrokenLinkCheck,
autoAddBaseUrl = true,
...props
}: LinkProps,
forwardedRef: React.ForwardedRef<HTMLAnchorElement>,
): JSX.Element {
const {
siteConfig: {trailingSlash, baseUrl},
} = useDocusaurusContext();
const {withBaseUrl} = useBaseUrlUtils();
const linksCollector = useLinksCollector();
const innerRef = useRef<HTMLAnchorElement | null>(null);
useImperativeHandle(
forwardedRef,
() => innerRef.current as HTMLAnchorElement,
);
// IMPORTANT: using to or href should not change anything
// For example, MDX links will ALWAYS give us the href props
@ -111,6 +125,8 @@ function Link({
};
const handleRef = (ref: HTMLAnchorElement | null) => {
innerRef.current = ref;
if (IOSupported && ref && isInternal) {
// If IO supported and element reference found, set up Observer.
handleIntersection(ref, () => {
@ -154,6 +170,7 @@ function Link({
return isRegularHtmlLink ? (
// eslint-disable-next-line jsx-a11y/anchor-has-content
<a
ref={innerRef}
href={targetLink}
{...(targetLinkUnprefixed &&
!isInternal && {target: '_blank', rel: 'noopener noreferrer'})}
@ -172,4 +189,4 @@ function Link({
);
}
export default Link;
export default React.forwardRef(Link);

View file

@ -21,6 +21,7 @@ import Readme from "../README.md"
### Other tests
- [Code block tests](/tests/pages/code-block-tests)
- [Link tests](/tests/pages/link-tests)
- [Error boundary tests](/tests/pages/error-boundary-tests)
- [Hydration tests](/tests/pages/hydration-tests)
- [Asset linking tests](/tests/pages/markdown-tests)

View file

@ -0,0 +1,30 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import React from 'react';
import Layout from '@theme/Layout';
import Link from '@docusaurus/Link';
export default function LinkTest(): JSX.Element {
const anchorRef = React.useRef<HTMLAnchorElement>(null);
return (
<Layout>
<main className="container margin-vert--xl">
<Link ref={anchorRef} to="/">
A little link
</Link>
<button
type="button"
onClick={() => {
anchorRef.current!.style.backgroundColor = 'red';
}}>
Change the link
</button>
</main>
</Layout>
);
}