Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): route announcer #7074

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
02db474
Add a route announcer
seyoon20087 Mar 30, 2022
1af1a6c
Delay some time for the route announcer to change state.
seyoon20087 Mar 30, 2022
2ada5fc
Move route announcer to App.tsx.
seyoon20087 Mar 30, 2022
ebd259f
Decrease the wait time.
seyoon20087 Mar 30, 2022
2c9ae8f
update code - use code suggested by @Josh-Cena
seyoon20087 Mar 30, 2022
f271f17
Remove @reach/portal dep in favor of built-in portal
seyoon20087 Mar 30, 2022
df005b8
Update portal import.
seyoon20087 Mar 30, 2022
9608abe
update types
seyoon20087 Mar 30, 2022
6188ded
update lockfile
seyoon20087 Mar 30, 2022
36a773d
update types
seyoon20087 Mar 30, 2022
a5cd567
refactor
Josh-Cena Mar 30, 2022
fd8018d
comment fix
Josh-Cena Mar 30, 2022
6686055
Merge branch 'facebook:main' into create-route-announcer
seyoon20087 Apr 2, 2022
75f5260
Wrap the route announcer inside `<App />`
seyoon20087 Apr 3, 2022
d948353
Wrap the route announcer inside `<App />`
seyoon20087 Apr 3, 2022
90e07e3
refactor
Josh-Cena Apr 3, 2022
49e20e7
add return type
Josh-Cena Apr 3, 2022
37cafa3
quick fix
Josh-Cena Apr 3, 2022
7cc8df3
fallback to page path when first h1 or document.title does not exist …
seyoon20087 Apr 3, 2022
1060785
remove temporary fallback
seyoon20087 Apr 3, 2022
bbb2ffb
Merge branch 'main' into create-route-announcer
Josh-Cena Apr 30, 2022
8704767
reimplement with client module
Josh-Cena Apr 30, 2022
6104fcb
make text label translatable
Josh-Cena Apr 30, 2022
4e2319d
fixes
Josh-Cena Apr 30, 2022
00956fd
fix CSS order?
Josh-Cena Apr 30, 2022
8833c65
use cleanup function
Josh-Cena Apr 30, 2022
7d67a48
Merge branch 'main' into create-route-announcer
Josh-Cena May 25, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions packages/docusaurus/src/client/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import React from 'react';

import {useLocation} from './exports/router';
import routes from '@generated/routes';
import renderRoutes from './exports/renderRoutes';
import {BrowserContextProvider} from './browserContext';
Expand All @@ -16,6 +16,7 @@ import BaseUrlIssueBanner from './BaseUrlIssueBanner';
import SiteMetadataDefaults from './SiteMetadataDefaults';
import Root from '@theme/Root';
import SiteMetadata from '@theme/SiteMetadata';
import RouteAnnouncer from './RouteAnnouncer';

import './clientLifecyclesDispatcher';

Expand All @@ -24,6 +25,7 @@ import ErrorBoundary from '@docusaurus/ErrorBoundary';
import Error from '@theme/Error';

export default function App(): JSX.Element {
const {pathname} = useLocation();
return (
<ErrorBoundary fallback={Error}>
<DocusaurusContextProvider>
Expand All @@ -33,7 +35,9 @@ export default function App(): JSX.Element {
<SiteMetadata />
<BaseUrlIssueBanner />
<PendingNavigation routes={routes} delay={1000}>
{renderRoutes(routes)}
<RouteAnnouncer location={pathname}>
{renderRoutes(routes)}
</RouteAnnouncer>
</PendingNavigation>
</Root>
</BrowserContextProvider>
Expand Down
78 changes: 78 additions & 0 deletions packages/docusaurus/src/client/RouteAnnouncer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* 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 {Portal} from './exports/Portal';

type Props = {
// Force an update on route transition
// eslint-disable-next-line react/no-unused-prop-types
location: string;
children: React.ReactNode;
};

type State = {
routeAnnouncement: string;
};

class RouteAnnouncerWrapper extends React.Component<Props, State> {
Josh-Cena marked this conversation as resolved.
Show resolved Hide resolved
constructor(props: Props) {
super(props);
this.state = {
routeAnnouncement: '',
};
}

override componentDidUpdate(): void {
const {routeAnnouncement} = this.state;

requestAnimationFrame(() => {
Josh-Cena marked this conversation as resolved.
Show resolved Hide resolved
const firstHeading = document.querySelectorAll(`#__docusaurus h1`)[0];
Josh-Cena marked this conversation as resolved.
Show resolved Hide resolved
const pageName = firstHeading?.textContent ?? document.title;
const newAnnouncement = `Navigated to ${pageName}`;
Josh-Cena marked this conversation as resolved.
Show resolved Hide resolved
const oldAnnouncement = routeAnnouncement;
if (oldAnnouncement !== newAnnouncement) {
this.setState({
routeAnnouncement: newAnnouncement,
});
}
});
}

override render(): JSX.Element {
const {children} = this.props;
const {routeAnnouncement} = this.state;
return (
<>
{children}
Josh-Cena marked this conversation as resolved.
Show resolved Hide resolved
<Portal type="docusaurus-route-announcer">
Josh-Cena marked this conversation as resolved.
Show resolved Hide resolved
<p
aria-live="assertive" // Make the announcement immediately.
id="__docusaurus-route-announcer__"
role="alert"
style={{
border: 0,
clip: 'rect(0 0 0 0)',
height: '1px',
margin: '-1px',
overflow: 'hidden',
padding: 0,
position: 'absolute',
width: '1px',
// https://medium.com/@jessebeach/beware-smushed-off-screen-accessible-text-5952a4c2cbfe
whiteSpace: 'nowrap',
wordWrap: 'normal',
}}>
{routeAnnouncement}
</p>
</Portal>
</>
);
}
}

export default RouteAnnouncerWrapper;
34 changes: 34 additions & 0 deletions packages/docusaurus/src/client/exports/Portal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* 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 {useRef, useState, useEffect, type ReactPortal} from 'react';
import {createPortal} from 'react-dom';

type PortalProps = {
children: React.ReactNode;
type: string;
};

export function Portal({
children,
type = 'docusaurus-portal',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are other portal types planned?

What is the purpose of calling document.createElement("docusaurus-portal"); ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@slorber This is the container node's tag name. Portal elements can often be custom elements so as not to have any default user-agent styles.

}: PortalProps): ReactPortal | null {
const portalNode = useRef<HTMLElement | null>(null);
const [, forceUpdate] = useState<unknown>();
useEffect(() => {
portalNode.current = document.createElement(type);
document.body.appendChild(portalNode.current);
forceUpdate({});
return () => {
if (portalNode.current) {
document.body.removeChild(portalNode.current);
}
};
}, [type]);

return portalNode.current ? createPortal(children, portalNode.current) : null;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ exports[`base webpack config creates webpack aliases 1`] = `
"@docusaurus/Interpolate": "../../../../client/exports/Interpolate.tsx",
"@docusaurus/Link": "../../../../client/exports/Link.tsx",
"@docusaurus/Noop": "../../../../client/exports/Noop.ts",
"@docusaurus/Portal": "../../../../client/exports/Portal.tsx",
"@docusaurus/Translate": "../../../../client/exports/Translate.tsx",
"@docusaurus/constants": "../../../../client/exports/constants.ts",
"@docusaurus/isInternalUrl": "../../../../client/exports/isInternalUrl.ts",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ exports[`getDocusaurusAliases returns appropriate webpack aliases 1`] = `
"@docusaurus/Interpolate": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/Interpolate.tsx",
"@docusaurus/Link": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/Link.tsx",
"@docusaurus/Noop": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/Noop.ts",
"@docusaurus/Portal": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/Portal.tsx",
"@docusaurus/Translate": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/Translate.tsx",
"@docusaurus/constants": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/constants.ts",
"@docusaurus/isInternalUrl": "<PROJECT_ROOT>/packages/docusaurus/src/client/exports/isInternalUrl.ts",
Expand Down