-
-
Notifications
You must be signed in to change notification settings - Fork 8.7k
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
Closed
Changes from 8 commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
02db474
Add a route announcer
seyoon20087 1af1a6c
Delay some time for the route announcer to change state.
seyoon20087 2ada5fc
Move route announcer to App.tsx.
seyoon20087 ebd259f
Decrease the wait time.
seyoon20087 2c9ae8f
update code - use code suggested by @Josh-Cena
seyoon20087 f271f17
Remove @reach/portal dep in favor of built-in portal
seyoon20087 df005b8
Update portal import.
seyoon20087 9608abe
update types
seyoon20087 6188ded
update lockfile
seyoon20087 36a773d
update types
seyoon20087 a5cd567
refactor
Josh-Cena fd8018d
comment fix
Josh-Cena 6686055
Merge branch 'facebook:main' into create-route-announcer
seyoon20087 75f5260
Wrap the route announcer inside `<App />`
seyoon20087 d948353
Wrap the route announcer inside `<App />`
seyoon20087 90e07e3
refactor
Josh-Cena 49e20e7
add return type
Josh-Cena 37cafa3
quick fix
Josh-Cena 7cc8df3
fallback to page path when first h1 or document.title does not exist …
seyoon20087 1060785
remove temporary fallback
seyoon20087 bbb2ffb
Merge branch 'main' into create-route-announcer
Josh-Cena 8704767
reimplement with client module
Josh-Cena 6104fcb
make text label translatable
Josh-Cena 4e2319d
fixes
Josh-Cena 00956fd
fix CSS order?
Josh-Cena 8833c65
use cleanup function
Josh-Cena 7d67a48
Merge branch 'main' into create-route-announcer
Josh-Cena File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/** | ||
* 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 {createPortal} from 'react-dom'; | ||
|
||
type PortalProps = { | ||
children: React.ReactNode; | ||
type: string; | ||
}; | ||
|
||
export function Portal({ | ||
children, | ||
type = 'docusaurus-portal', | ||
}: // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
PortalProps): any { | ||
seyoon20087 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const portalNode = React.useRef<HTMLElement | null>(null); | ||
const [, forceUpdate] = React.useState<{[key: string]: unknown}>(); | ||
React.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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/** | ||
* 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 {useLocation} from 'react-router-dom'; | ||
|
||
export function RouteAnnouncer() { | ||
const {pathname} = useLocation(); | ||
const [routeAnnouncement, setRouteAnnouncement] = React.useState(''); | ||
|
||
// Only announce the path change, but not for the first load because screen | ||
// reader will do that automatically. | ||
const previouslyLoadedPath = React.useRef(pathname); | ||
|
||
// Every time the path changes, announce the new page’s title following this | ||
// priority: first the document title (from head), otherwise the first h1, or | ||
// if none of these exist, then the pathname from the URL. This methodology is | ||
// inspired by Marcy Sutton’s accessible client routing user testing. More | ||
// information can be found here: | ||
// https://www.gatsbyjs.com/blog/2019-07-11-user-testing-accessible-client-routing/ | ||
React.useEffect(() => { | ||
// If the path hasn't change, we do nothing. | ||
if (previouslyLoadedPath.current === pathname) { | ||
return; | ||
} | ||
previouslyLoadedPath.current = pathname; | ||
|
||
const pageHeader = document.querySelector('h1'); | ||
const content = pageHeader?.innerText ?? pageHeader?.textContent; | ||
|
||
// NOTE: when setTimeout isn't used it will keep the previous page's title, | ||
// which may be annoying to some screen-reader users (in my testing). | ||
// Similar issue regarding this is https://github.com/vercel/next.js/issues/32610 | ||
setTimeout(() => { | ||
setRouteAnnouncement(document.title ?? content ?? pathname); | ||
}, 50); | ||
}, [pathname]); | ||
|
||
return ( | ||
<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> | ||
); | ||
} | ||
|
||
export default RouteAnnouncer; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3211,6 +3211,23 @@ | |
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.4.tgz#d8c7b8db9226d2d7664553a0741ad7d0397ee503" | ||
integrity sha512-q/ytXxO5NKvyT37pmisQAItCFqA7FD/vNb8dgaJy3/630Fsc+Mz9/9f2SziBoIZ30TJooXyTwZmhi1zjXmObYg== | ||
|
||
"@reach/portal@^0.16.2": | ||
seyoon20087 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
version "0.16.2" | ||
resolved "https://registry.yarnpkg.com/@reach/portal/-/portal-0.16.2.tgz#ca83696215ee03acc2bb25a5ae5d8793eaaf2f64" | ||
integrity sha512-9ur/yxNkuVYTIjAcfi46LdKUvH0uYZPfEp4usWcpt6PIp+WDF57F/5deMe/uGi/B/nfDweQu8VVwuMVrCb97JQ== | ||
dependencies: | ||
"@reach/utils" "0.16.0" | ||
tiny-warning "^1.0.3" | ||
tslib "^2.3.0" | ||
|
||
"@reach/[email protected]": | ||
version "0.16.0" | ||
resolved "https://registry.yarnpkg.com/@reach/utils/-/utils-0.16.0.tgz#5b0777cf16a7cab1ddd4728d5d02762df0ba84ce" | ||
integrity sha512-PCggBet3qaQmwFNcmQ/GqHSefadAFyNCUekq9RrWoaU9hh/S4iaFgf2MBMdM47eQj5i/Bk0Mm07cP/XPFlkN+Q== | ||
dependencies: | ||
tiny-warning "^1.0.3" | ||
tslib "^2.3.0" | ||
|
||
"@rollup/plugin-babel@^5.2.0": | ||
version "5.3.1" | ||
resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283" | ||
|
@@ -18278,7 +18295,7 @@ tslib@^1.8.1, tslib@^1.9.0: | |
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" | ||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== | ||
|
||
tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.1: | ||
tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@^2.3.1: | ||
version "2.3.1" | ||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" | ||
integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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");
?There was a problem hiding this comment.
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.