-
-
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
Changes from 25 commits
02db474
1af1a6c
2ada5fc
ebd259f
2c9ae8f
f271f17
df005b8
9608abe
6188ded
36a773d
a5cd567
fd8018d
6686055
75f5260
d948353
90e07e3
49e20e7
37cafa3
7cc8df3
1060785
bbb2ffb
8704767
6104fcb
4e2319d
00956fd
8833c65
7d67a48
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/** | ||
* 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. | ||
*/ | ||
|
||
#docusaurus-route-announcer-content { | ||
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 */ | ||
white-space: nowrap; | ||
word-wrap: normal; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/** | ||
* 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 {translate} from '@docusaurus/Translate'; | ||
import type {ClientModule} from '@docusaurus/types'; | ||
import './routeAnnouncer.css'; | ||
|
||
const clientModule: ClientModule = { | ||
onRouteDidUpdate({location, previousLocation}) { | ||
if (!previousLocation || location.pathname === previousLocation.pathname) { | ||
return; | ||
} | ||
Array.from( | ||
document.getElementsByTagName('docusaurus-route-announcer'), | ||
).forEach(document.removeChild); | ||
const announcerContainer = document.createElement( | ||
'docusaurus-route-announcer', | ||
); | ||
const announcement = document.createElement('p'); | ||
Object.assign(announcement, { | ||
ariaLive: 'assertive', // Make the announcement immediately. | ||
id: 'docusaurus-route-announcer-content', | ||
role: 'alert', | ||
}); | ||
Comment on lines
+17
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Pure DOM manipulation. Because client modules don't have access to the React context, it would be quite cumbersome if we want to use React to do this. The alternative will be to put this in |
||
const firstHeading = document.querySelectorAll(`#__docusaurus h1`)[0]; | ||
const pageName = firstHeading?.textContent ?? document.title; | ||
announcement.innerText = translate( | ||
{ | ||
message: 'Navigated to {pageName}', | ||
id: 'theme.RouteAnnouncer.content', | ||
description: | ||
'The text announced by screen reader when the user has navigated to a new page', | ||
}, | ||
{pageName}, | ||
); | ||
announcerContainer.appendChild(announcement); | ||
document.body.appendChild(announcerContainer); | ||
}, | ||
}; | ||
|
||
export default clientModule; |
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', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are other portal types planned? What is the purpose of calling There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
---|---|---|
|
@@ -31,7 +31,6 @@ const EXPECTED_CSS_MARKERS = [ | |
// See https://github.com/facebook/docusaurus/pull/6222 | ||
'.markdown>h2', | ||
'.button--outline.button--active', | ||
'.DocSearch-Hit-content-wrapper', | ||
'.navbar__title', | ||
'--ifm-color-scheme:light', | ||
'.col[class*=col--]', | ||
|
@@ -49,6 +48,7 @@ const EXPECTED_CSS_MARKERS = [ | |
|
||
// Lazy-loaded lib | ||
'.DocSearch-Modal', | ||
'.DocSearch-Hit-content-wrapper', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm surprised that this moved, but it makes more sense this way? Not sure why it was loaded so early before. |
||
]; | ||
|
||
const cssDirName = fileURLToPath(new URL('build/assets/css', import.meta.url)); | ||
|
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.
Using an ID selector here. Not sure if we necessarily want a class name here, or if we want to use inline styles.