From 02db4746456a787efdf7d6faba947a9ec31cba23 Mon Sep 17 00:00:00 2001 From: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> Date: Wed, 30 Mar 2022 19:53:14 +0900 Subject: [PATCH 01/24] Add a route announcer By doing this, client-side route changes will be announced to screen readers, improving accessibility to screen-reader users. This was heavily inspired by https://github.com/vercel/next.js/blob/canary/packages/next/client/route-announcer.tsx. Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> --- packages/docusaurus/package.json | 1 + .../docusaurus/src/client/routeAnnouncer.tsx | 72 +++++++++++++++++++ .../src/client/theme-fallback/Root/index.tsx | 11 ++- yarn.lock | 19 ++++- 4 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 packages/docusaurus/src/client/routeAnnouncer.tsx diff --git a/packages/docusaurus/package.json b/packages/docusaurus/package.json index 544e9a85e7b1..63549063d6c4 100644 --- a/packages/docusaurus/package.json +++ b/packages/docusaurus/package.json @@ -48,6 +48,7 @@ "@docusaurus/utils": "2.0.0-beta.18", "@docusaurus/utils-common": "2.0.0-beta.18", "@docusaurus/utils-validation": "2.0.0-beta.18", + "@reach/portal": "^0.16.2", "@slorber/static-site-generator-webpack-plugin": "^4.0.4", "@svgr/webpack": "^6.2.1", "autoprefixer": "^10.4.4", diff --git a/packages/docusaurus/src/client/routeAnnouncer.tsx b/packages/docusaurus/src/client/routeAnnouncer.tsx new file mode 100644 index 000000000000..1163e1693fe3 --- /dev/null +++ b/packages/docusaurus/src/client/routeAnnouncer.tsx @@ -0,0 +1,72 @@ +/** + * 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; + + if (document.title) { + setTimeout(() => { + setRouteAnnouncement(document.title); + }, 50); + } else { + const pageHeader = document.querySelector('h1'); + const content = pageHeader?.innerText ?? pageHeader?.textContent; + setTimeout(() => { + setRouteAnnouncement(content || pathname); + }, 50); + } + }, + // TODO: switch to pathname + query object of dynamic route requirements + [pathname], + ); + + return ( + + ); +} + +export default RouteAnnouncer; diff --git a/packages/docusaurus/src/client/theme-fallback/Root/index.tsx b/packages/docusaurus/src/client/theme-fallback/Root/index.tsx index 27ef85e88a7f..898b5403cc1c 100644 --- a/packages/docusaurus/src/client/theme-fallback/Root/index.tsx +++ b/packages/docusaurus/src/client/theme-fallback/Root/index.tsx @@ -7,6 +7,8 @@ import React from 'react'; import type {Props} from '@theme/Root'; +import Portal from '@reach/portal'; +import {RouteAnnouncer} from '../../routeAnnouncer'; // Wrapper at the very top of the app, that is applied constantly // and does not depend on current route (unlike the layout) @@ -16,5 +18,12 @@ import type {Props} from '@theme/Root'; // // See https://github.com/facebook/docusaurus/issues/3919 export default function Root({children}: Props): JSX.Element { - return <>{children}; + return ( + <> + {children} + + + + + ); } diff --git a/yarn.lock b/yarn.lock index 5974ee3c406f..b049cea2a4f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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": + 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/utils@0.16.0": + 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== From 1af1a6c3e3d2da431956f70883468ee63afb6903 Mon Sep 17 00:00:00 2001 From: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> Date: Wed, 30 Mar 2022 22:04:20 +0900 Subject: [PATCH 02/24] Delay some time for the route announcer to change state. I have dived in the codebase, and it looks like it has a 1000 second wait time before a new route can load. Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> --- packages/docusaurus/src/client/routeAnnouncer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/docusaurus/src/client/routeAnnouncer.tsx b/packages/docusaurus/src/client/routeAnnouncer.tsx index 1163e1693fe3..1359226cec9a 100644 --- a/packages/docusaurus/src/client/routeAnnouncer.tsx +++ b/packages/docusaurus/src/client/routeAnnouncer.tsx @@ -32,13 +32,13 @@ export function RouteAnnouncer() { if (document.title) { setTimeout(() => { setRouteAnnouncement(document.title); - }, 50); + }, 1050); } else { const pageHeader = document.querySelector('h1'); const content = pageHeader?.innerText ?? pageHeader?.textContent; setTimeout(() => { setRouteAnnouncement(content || pathname); - }, 50); + }, 1050); } }, // TODO: switch to pathname + query object of dynamic route requirements From 2ada5fc5eeb7fd48bd7707e290074c11e919b359 Mon Sep 17 00:00:00 2001 From: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> Date: Wed, 30 Mar 2022 22:13:06 +0900 Subject: [PATCH 03/24] Move route announcer to App.tsx. Someone suggested to put it in App.tsx instead of `@theme/Root`. Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> --- packages/docusaurus/src/client/App.tsx | 7 +++++++ .../src/client/theme-fallback/Root/index.tsx | 11 +---------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/docusaurus/src/client/App.tsx b/packages/docusaurus/src/client/App.tsx index 01d74bb1cdd3..0fab9980958f 100644 --- a/packages/docusaurus/src/client/App.tsx +++ b/packages/docusaurus/src/client/App.tsx @@ -23,6 +23,10 @@ import './client-lifecycles-dispatcher'; import ErrorBoundary from '@docusaurus/ErrorBoundary'; import Error from '@theme/Error'; +// Add a route announcer +import Portal from '@reach/portal'; +import {RouteAnnouncer} from './routeAnnouncer'; + export default function App(): JSX.Element { return ( @@ -38,6 +42,9 @@ export default function App(): JSX.Element { + + + ); } diff --git a/packages/docusaurus/src/client/theme-fallback/Root/index.tsx b/packages/docusaurus/src/client/theme-fallback/Root/index.tsx index 898b5403cc1c..27ef85e88a7f 100644 --- a/packages/docusaurus/src/client/theme-fallback/Root/index.tsx +++ b/packages/docusaurus/src/client/theme-fallback/Root/index.tsx @@ -7,8 +7,6 @@ import React from 'react'; import type {Props} from '@theme/Root'; -import Portal from '@reach/portal'; -import {RouteAnnouncer} from '../../routeAnnouncer'; // Wrapper at the very top of the app, that is applied constantly // and does not depend on current route (unlike the layout) @@ -18,12 +16,5 @@ import {RouteAnnouncer} from '../../routeAnnouncer'; // // See https://github.com/facebook/docusaurus/issues/3919 export default function Root({children}: Props): JSX.Element { - return ( - <> - {children} - - - - - ); + return <>{children}; } From ebd259f630657fc2fd0bff2a735e9e71f24eeef3 Mon Sep 17 00:00:00 2001 From: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> Date: Wed, 30 Mar 2022 22:14:03 +0900 Subject: [PATCH 04/24] Decrease the wait time. In my testing 50ms is ok to me. You may change it if it something goes wrong. Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> --- packages/docusaurus/src/client/routeAnnouncer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/docusaurus/src/client/routeAnnouncer.tsx b/packages/docusaurus/src/client/routeAnnouncer.tsx index 1359226cec9a..1163e1693fe3 100644 --- a/packages/docusaurus/src/client/routeAnnouncer.tsx +++ b/packages/docusaurus/src/client/routeAnnouncer.tsx @@ -32,13 +32,13 @@ export function RouteAnnouncer() { if (document.title) { setTimeout(() => { setRouteAnnouncement(document.title); - }, 1050); + }, 50); } else { const pageHeader = document.querySelector('h1'); const content = pageHeader?.innerText ?? pageHeader?.textContent; setTimeout(() => { setRouteAnnouncement(content || pathname); - }, 1050); + }, 50); } }, // TODO: switch to pathname + query object of dynamic route requirements From 2c9ae8f24cde22971cb4ec25b278ad9c83827113 Mon Sep 17 00:00:00 2001 From: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> Date: Wed, 30 Mar 2022 23:00:54 +0900 Subject: [PATCH 05/24] update code - use code suggested by @Josh-Cena Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> --- .../docusaurus/src/client/routeAnnouncer.tsx | 38 ++++++++----------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/packages/docusaurus/src/client/routeAnnouncer.tsx b/packages/docusaurus/src/client/routeAnnouncer.tsx index 1163e1693fe3..fd1de755ef81 100644 --- a/packages/docusaurus/src/client/routeAnnouncer.tsx +++ b/packages/docusaurus/src/client/routeAnnouncer.tsx @@ -21,29 +21,23 @@ export function RouteAnnouncer() { // 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; + React.useEffect(() => { + // If the path hasn't change, we do nothing. + if (previouslyLoadedPath.current === pathname) { + return; + } + previouslyLoadedPath.current = pathname; - if (document.title) { - setTimeout(() => { - setRouteAnnouncement(document.title); - }, 50); - } else { - const pageHeader = document.querySelector('h1'); - const content = pageHeader?.innerText ?? pageHeader?.textContent; - setTimeout(() => { - setRouteAnnouncement(content || pathname); - }, 50); - } - }, - // TODO: switch to pathname + query object of dynamic route requirements - [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 (

Date: Wed, 30 Mar 2022 23:12:37 +0900 Subject: [PATCH 06/24] Remove @reach/portal dep in favor of built-in portal Someone suggested to this to adjust some code and to prevent blocked on an external dep as commented. Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> --- packages/docusaurus/package.json | 1 - .../docusaurus/src/client/exports/Portal.tsx | 34 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 packages/docusaurus/src/client/exports/Portal.tsx diff --git a/packages/docusaurus/package.json b/packages/docusaurus/package.json index 63549063d6c4..544e9a85e7b1 100644 --- a/packages/docusaurus/package.json +++ b/packages/docusaurus/package.json @@ -48,7 +48,6 @@ "@docusaurus/utils": "2.0.0-beta.18", "@docusaurus/utils-common": "2.0.0-beta.18", "@docusaurus/utils-validation": "2.0.0-beta.18", - "@reach/portal": "^0.16.2", "@slorber/static-site-generator-webpack-plugin": "^4.0.4", "@svgr/webpack": "^6.2.1", "autoprefixer": "^10.4.4", diff --git a/packages/docusaurus/src/client/exports/Portal.tsx b/packages/docusaurus/src/client/exports/Portal.tsx new file mode 100644 index 000000000000..1866ba2c74ab --- /dev/null +++ b/packages/docusaurus/src/client/exports/Portal.tsx @@ -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 React from 'react'; +import {createPortal} from 'react-dom'; + +type PortalProps = { + children: React.ReactNode; + type: string; +}; + +export function Portal({ + children, + type = 'docusaurus-portal', +}: PortalProps): React.ReactPortal { + const portalNode = React.useRef(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; +} From df005b84fcf87ac031bdb929cd3e19f36a1464c7 Mon Sep 17 00:00:00 2001 From: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> Date: Wed, 30 Mar 2022 23:14:03 +0900 Subject: [PATCH 07/24] Update portal import. Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> --- packages/docusaurus/src/client/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docusaurus/src/client/App.tsx b/packages/docusaurus/src/client/App.tsx index 0fab9980958f..82f80ff977c2 100644 --- a/packages/docusaurus/src/client/App.tsx +++ b/packages/docusaurus/src/client/App.tsx @@ -24,7 +24,7 @@ import ErrorBoundary from '@docusaurus/ErrorBoundary'; import Error from '@theme/Error'; // Add a route announcer -import Portal from '@reach/portal'; +import {Portal} from './exports/Portal'; import {RouteAnnouncer} from './routeAnnouncer'; export default function App(): JSX.Element { From 9608abe324e71b1399c58be3c226ff1b21652490 Mon Sep 17 00:00:00 2001 From: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> Date: Wed, 30 Mar 2022 23:20:46 +0900 Subject: [PATCH 08/24] update types Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> --- packages/docusaurus/src/client/exports/Portal.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/docusaurus/src/client/exports/Portal.tsx b/packages/docusaurus/src/client/exports/Portal.tsx index 1866ba2c74ab..51eaba312d5f 100644 --- a/packages/docusaurus/src/client/exports/Portal.tsx +++ b/packages/docusaurus/src/client/exports/Portal.tsx @@ -16,7 +16,8 @@ type PortalProps = { export function Portal({ children, type = 'docusaurus-portal', -}: PortalProps): React.ReactPortal { +}: // eslint-disable-next-line @typescript-eslint/no-explicit-any +PortalProps): any { const portalNode = React.useRef(null); const [, forceUpdate] = React.useState<{[key: string]: unknown}>(); React.useEffect(() => { From 6188dedae2ce627a6a97fb9d1a51f41ee340f127 Mon Sep 17 00:00:00 2001 From: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> Date: Wed, 30 Mar 2022 23:29:49 +0900 Subject: [PATCH 09/24] update lockfile Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> --- yarn.lock | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/yarn.lock b/yarn.lock index b049cea2a4f2..5974ee3c406f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3211,23 +3211,6 @@ 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": - 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/utils@0.16.0": - 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" @@ -18295,7 +18278,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.0, tslib@^2.3.1: +tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.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== From 36a773dd05fa2e2ea2d3b093ca5f999647efb65b Mon Sep 17 00:00:00 2001 From: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> Date: Wed, 30 Mar 2022 23:32:01 +0900 Subject: [PATCH 10/24] update types Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> --- packages/docusaurus/src/client/exports/Portal.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/docusaurus/src/client/exports/Portal.tsx b/packages/docusaurus/src/client/exports/Portal.tsx index 51eaba312d5f..3e42b02ca722 100644 --- a/packages/docusaurus/src/client/exports/Portal.tsx +++ b/packages/docusaurus/src/client/exports/Portal.tsx @@ -16,8 +16,7 @@ type PortalProps = { export function Portal({ children, type = 'docusaurus-portal', -}: // eslint-disable-next-line @typescript-eslint/no-explicit-any -PortalProps): any { +}: PortalProps): React.ReactPortal | null { const portalNode = React.useRef(null); const [, forceUpdate] = React.useState<{[key: string]: unknown}>(); React.useEffect(() => { From a5cd567ae76b396ee8166eee964c97265ad2fe2b Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Wed, 30 Mar 2022 23:21:03 +0800 Subject: [PATCH 11/24] refactor --- packages/docusaurus/src/client/App.tsx | 6 ++---- ...{routeAnnouncer.tsx => RouteAnnouncer.tsx} | 19 +++++++++---------- .../docusaurus/src/client/exports/Portal.tsx | 10 +++++----- .../__tests__/__snapshots__/base.test.ts.snap | 1 + .../__snapshots__/index.test.ts.snap | 1 + 5 files changed, 18 insertions(+), 19 deletions(-) rename packages/docusaurus/src/client/{routeAnnouncer.tsx => RouteAnnouncer.tsx} (84%) diff --git a/packages/docusaurus/src/client/App.tsx b/packages/docusaurus/src/client/App.tsx index 82f80ff977c2..cd88e542f61b 100644 --- a/packages/docusaurus/src/client/App.tsx +++ b/packages/docusaurus/src/client/App.tsx @@ -16,6 +16,8 @@ import BaseUrlIssueBanner from './baseUrlIssueBanner/BaseUrlIssueBanner'; import SiteMetadataDefaults from './SiteMetadataDefaults'; import Root from '@theme/Root'; import SiteMetadata from '@theme/SiteMetadata'; +import {Portal} from './exports/Portal'; +import RouteAnnouncer from './RouteAnnouncer'; import './client-lifecycles-dispatcher'; @@ -23,10 +25,6 @@ import './client-lifecycles-dispatcher'; import ErrorBoundary from '@docusaurus/ErrorBoundary'; import Error from '@theme/Error'; -// Add a route announcer -import {Portal} from './exports/Portal'; -import {RouteAnnouncer} from './routeAnnouncer'; - export default function App(): JSX.Element { return ( diff --git a/packages/docusaurus/src/client/routeAnnouncer.tsx b/packages/docusaurus/src/client/RouteAnnouncer.tsx similarity index 84% rename from packages/docusaurus/src/client/routeAnnouncer.tsx rename to packages/docusaurus/src/client/RouteAnnouncer.tsx index fd1de755ef81..29fad848ed42 100644 --- a/packages/docusaurus/src/client/routeAnnouncer.tsx +++ b/packages/docusaurus/src/client/RouteAnnouncer.tsx @@ -4,16 +4,17 @@ * 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 React, {useState, useRef, useEffect} from 'react'; import {useLocation} from 'react-router-dom'; -export function RouteAnnouncer() { +export default function RouteAnnouncer(): JSX.Element { const {pathname} = useLocation(); - const [routeAnnouncement, setRouteAnnouncement] = React.useState(''); + const [routeAnnouncement, setRouteAnnouncement] = useState(''); // Only announce the path change, but not for the first load because screen // reader will do that automatically. - const previouslyLoadedPath = React.useRef(pathname); + const previouslyLoadedPath = 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 @@ -21,10 +22,10 @@ export function RouteAnnouncer() { // 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(() => { + useEffect(() => { // If the path hasn't change, we do nothing. if (previouslyLoadedPath.current === pathname) { - return; + return undefined; } previouslyLoadedPath.current = pathname; @@ -34,9 +35,10 @@ export function RouteAnnouncer() { // 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(() => { + const timeout = window.setTimeout(() => { setRouteAnnouncement(document.title ?? content ?? pathname); }, 50); + return () => window.clearTimeout(timeout); }, [pathname]); return ( @@ -53,7 +55,6 @@ export function RouteAnnouncer() { padding: 0, position: 'absolute', width: '1px', - // https://medium.com/@jessebeach/beware-smushed-off-screen-accessible-text-5952a4c2cbfe whiteSpace: 'nowrap', wordWrap: 'normal', @@ -62,5 +63,3 @@ export function RouteAnnouncer() {

); } - -export default RouteAnnouncer; diff --git a/packages/docusaurus/src/client/exports/Portal.tsx b/packages/docusaurus/src/client/exports/Portal.tsx index 3e42b02ca722..1dea241ab608 100644 --- a/packages/docusaurus/src/client/exports/Portal.tsx +++ b/packages/docusaurus/src/client/exports/Portal.tsx @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import React from 'react'; +import {useRef, useState, useEffect, type ReactPortal} from 'react'; import {createPortal} from 'react-dom'; type PortalProps = { @@ -16,10 +16,10 @@ type PortalProps = { export function Portal({ children, type = 'docusaurus-portal', -}: PortalProps): React.ReactPortal | null { - const portalNode = React.useRef(null); - const [, forceUpdate] = React.useState<{[key: string]: unknown}>(); - React.useEffect(() => { +}: PortalProps): ReactPortal | null { + const portalNode = useRef(null); + const [, forceUpdate] = useState(); + useEffect(() => { portalNode.current = document.createElement(type); document.body.appendChild(portalNode.current); forceUpdate({}); diff --git a/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap b/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap index 6fdffc625968..ca5f23a722d7 100644 --- a/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap +++ b/packages/docusaurus/src/webpack/__tests__/__snapshots__/base.test.ts.snap @@ -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", diff --git a/packages/docusaurus/src/webpack/aliases/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus/src/webpack/aliases/__tests__/__snapshots__/index.test.ts.snap index 38a22a306e14..1ecce80b2243 100644 --- a/packages/docusaurus/src/webpack/aliases/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus/src/webpack/aliases/__tests__/__snapshots__/index.test.ts.snap @@ -10,6 +10,7 @@ exports[`getDocusaurusAliases returns appropriate webpack aliases 1`] = ` "@docusaurus/Interpolate": "/packages/docusaurus/src/client/exports/Interpolate.tsx", "@docusaurus/Link": "/packages/docusaurus/src/client/exports/Link.tsx", "@docusaurus/Noop": "/packages/docusaurus/src/client/exports/Noop.ts", + "@docusaurus/Portal": "/packages/docusaurus/src/client/exports/Portal.tsx", "@docusaurus/Translate": "/packages/docusaurus/src/client/exports/Translate.tsx", "@docusaurus/constants": "/packages/docusaurus/src/client/exports/constants.ts", "@docusaurus/isInternalUrl": "/packages/docusaurus/src/client/exports/isInternalUrl.ts", From fd8018dc37f8ab8797aa9cac52f215835d9e4b8e Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Wed, 30 Mar 2022 23:24:51 +0800 Subject: [PATCH 12/24] comment fix --- packages/docusaurus/src/client/RouteAnnouncer.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/docusaurus/src/client/RouteAnnouncer.tsx b/packages/docusaurus/src/client/RouteAnnouncer.tsx index 29fad848ed42..c55729c25468 100644 --- a/packages/docusaurus/src/client/RouteAnnouncer.tsx +++ b/packages/docusaurus/src/client/RouteAnnouncer.tsx @@ -23,7 +23,7 @@ export default function RouteAnnouncer(): JSX.Element { // information can be found here: // https://www.gatsbyjs.com/blog/2019-07-11-user-testing-accessible-client-routing/ useEffect(() => { - // If the path hasn't change, we do nothing. + // If the path hasn't changed, we do nothing. if (previouslyLoadedPath.current === pathname) { return undefined; } @@ -32,8 +32,9 @@ export default function RouteAnnouncer(): JSX.Element { 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). + // Since the component is rendered lazily with ComponentCreator, the route + // transition would not immediately lead to a repaint, and the announcer + // would announce the previous page's title instead. // Similar issue regarding this is https://github.com/vercel/next.js/issues/32610 const timeout = window.setTimeout(() => { setRouteAnnouncement(document.title ?? content ?? pathname); From 75f5260c66004a047aa88a4628cc1c40fb17a81f Mon Sep 17 00:00:00 2001 From: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> Date: Sun, 3 Apr 2022 21:12:45 +0900 Subject: [PATCH 13/24] Wrap the route announcer inside `` Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> --- packages/docusaurus/src/client/App.tsx | 36 ++++---- .../docusaurus/src/client/RouteAnnouncer.tsx | 66 -------------- .../src/client/RouteAnnouncerWrapper.tsx | 87 +++++++++++++++++++ 3 files changed, 104 insertions(+), 85 deletions(-) delete mode 100644 packages/docusaurus/src/client/RouteAnnouncer.tsx create mode 100644 packages/docusaurus/src/client/RouteAnnouncerWrapper.tsx diff --git a/packages/docusaurus/src/client/App.tsx b/packages/docusaurus/src/client/App.tsx index 490164a4098d..13ca3520f52f 100644 --- a/packages/docusaurus/src/client/App.tsx +++ b/packages/docusaurus/src/client/App.tsx @@ -16,8 +16,7 @@ import BaseUrlIssueBanner from './BaseUrlIssueBanner'; import SiteMetadataDefaults from './SiteMetadataDefaults'; import Root from '@theme/Root'; import SiteMetadata from '@theme/SiteMetadata'; -import {Portal} from './exports/Portal'; -import RouteAnnouncer from './RouteAnnouncer'; +import RouteAnnouncerWrapper from './RouteAnnouncerWrapper'; import './clientLifecyclesDispatcher'; @@ -27,22 +26,21 @@ import Error from '@theme/Error'; export default function App(): JSX.Element { return ( - - - - - - - - - {renderRoutes(routes)} - - - - - - - - + + + + + + + + + + {renderRoutes(routes)} + + + + + + ); } diff --git a/packages/docusaurus/src/client/RouteAnnouncer.tsx b/packages/docusaurus/src/client/RouteAnnouncer.tsx deleted file mode 100644 index c55729c25468..000000000000 --- a/packages/docusaurus/src/client/RouteAnnouncer.tsx +++ /dev/null @@ -1,66 +0,0 @@ -/** - * 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, {useState, useRef, useEffect} from 'react'; -import {useLocation} from 'react-router-dom'; - -export default function RouteAnnouncer(): JSX.Element { - const {pathname} = useLocation(); - const [routeAnnouncement, setRouteAnnouncement] = useState(''); - - // Only announce the path change, but not for the first load because screen - // reader will do that automatically. - const previouslyLoadedPath = 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/ - useEffect(() => { - // If the path hasn't changed, we do nothing. - if (previouslyLoadedPath.current === pathname) { - return undefined; - } - previouslyLoadedPath.current = pathname; - - const pageHeader = document.querySelector('h1'); - const content = pageHeader?.innerText ?? pageHeader?.textContent; - - // Since the component is rendered lazily with ComponentCreator, the route - // transition would not immediately lead to a repaint, and the announcer - // would announce the previous page's title instead. - // Similar issue regarding this is https://github.com/vercel/next.js/issues/32610 - const timeout = window.setTimeout(() => { - setRouteAnnouncement(document.title ?? content ?? pathname); - }, 50); - return () => window.clearTimeout(timeout); - }, [pathname]); - - return ( - - ); -} diff --git a/packages/docusaurus/src/client/RouteAnnouncerWrapper.tsx b/packages/docusaurus/src/client/RouteAnnouncerWrapper.tsx new file mode 100644 index 000000000000..6565c84b6dc2 --- /dev/null +++ b/packages/docusaurus/src/client/RouteAnnouncerWrapper.tsx @@ -0,0 +1,87 @@ +/** + * 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 {withRouter} from 'react-router-dom'; +import {Portal} from './exports/Portal'; +import type {RouteComponentProps} from 'react-router-dom'; + +/* eslint-disable @typescript-eslint/ban-ts-comment */ + +class RouteAnnouncerWrapper extends React.Component { + constructor({ + children, + location, + }: { + children: React.ReactNode; + } & RouteComponentProps) { + super({children, location}); + this.state = { + routeAnnouncement: '', + }; + } + + override componentDidUpdate(): void { + // @ts-ignore + const {pathname} = this.props.location; // @ts-ignore + const {routeAnnouncement} = this.state; + + requestAnimationFrame(() => { + let pageName = `new page at ${pathname}`; + if (document.title) { + pageName = document.title; + } + const pageHeadings = document.querySelectorAll(`#__docusaurus h1`); + if (pageHeadings?.length) { + pageName = (pageHeadings[0] as Node).textContent as string; + } + const newAnnouncement = `Navigated to ${pageName}`; + if (routeAnnouncement) { + const oldAnnouncement = routeAnnouncement; + if (!Object.is(oldAnnouncement, newAnnouncement)) { + this.setState({ + routeAnnouncement: newAnnouncement, + }); + } + } + }); + } + + override render() { + const {children} = this.props; // @ts-ignore + const {routeAnnouncement} = this.state; + return ( + <> + {children} + + + + + ); + } +} + +// @ts-ignore +export default withRouter(RouteAnnouncerWrapper); From d948353cf67867646853ff2754472a998f381d2d Mon Sep 17 00:00:00 2001 From: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> Date: Sun, 3 Apr 2022 22:32:44 +0900 Subject: [PATCH 14/24] Wrap the route announcer inside `` Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> --- packages/docusaurus/src/client/App.tsx | 36 +++++++++++-------- .../src/client/RouteAnnouncerWrapper.tsx | 16 ++++----- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/packages/docusaurus/src/client/App.tsx b/packages/docusaurus/src/client/App.tsx index 13ca3520f52f..9ac9e08eee01 100644 --- a/packages/docusaurus/src/client/App.tsx +++ b/packages/docusaurus/src/client/App.tsx @@ -17,6 +17,7 @@ import SiteMetadataDefaults from './SiteMetadataDefaults'; import Root from '@theme/Root'; import SiteMetadata from '@theme/SiteMetadata'; import RouteAnnouncerWrapper from './RouteAnnouncerWrapper'; +import {useLocation} from 'react-router'; import './clientLifecyclesDispatcher'; @@ -24,23 +25,28 @@ import './clientLifecyclesDispatcher'; import ErrorBoundary from '@docusaurus/ErrorBoundary'; import Error from '@theme/Error'; +/* eslint-disable @typescript-eslint/ban-ts-comment */ + export default function App(): JSX.Element { + const {pathname} = useLocation(); return ( - - - - - - - - - + + + + + + + + + {/* + // @ts-ignore */} + {renderRoutes(routes)} - - - - - - + + + + + + ); } diff --git a/packages/docusaurus/src/client/RouteAnnouncerWrapper.tsx b/packages/docusaurus/src/client/RouteAnnouncerWrapper.tsx index 6565c84b6dc2..59ce7ff14ae2 100644 --- a/packages/docusaurus/src/client/RouteAnnouncerWrapper.tsx +++ b/packages/docusaurus/src/client/RouteAnnouncerWrapper.tsx @@ -6,7 +6,6 @@ */ import React from 'react'; -import {withRouter} from 'react-router-dom'; import {Portal} from './exports/Portal'; import type {RouteComponentProps} from 'react-router-dom'; @@ -40,17 +39,16 @@ class RouteAnnouncerWrapper extends React.Component { pageName = (pageHeadings[0] as Node).textContent as string; } const newAnnouncement = `Navigated to ${pageName}`; - if (routeAnnouncement) { - const oldAnnouncement = routeAnnouncement; - if (!Object.is(oldAnnouncement, newAnnouncement)) { - this.setState({ - routeAnnouncement: newAnnouncement, - }); - } + const oldAnnouncement = routeAnnouncement; + if (!Object.is(oldAnnouncement, newAnnouncement)) { + this.setState({ + routeAnnouncement: newAnnouncement, + }); } }); } + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types override render() { const {children} = this.props; // @ts-ignore const {routeAnnouncement} = this.state; @@ -84,4 +82,4 @@ class RouteAnnouncerWrapper extends React.Component { } // @ts-ignore -export default withRouter(RouteAnnouncerWrapper); +export default RouteAnnouncerWrapper; From 90e07e39cbf0041f7952f784c65b3f5c78444012 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Sun, 3 Apr 2022 21:59:14 +0800 Subject: [PATCH 15/24] refactor --- packages/docusaurus/src/client/App.tsx | 12 +----- ...nnouncerWrapper.tsx => RouteAnnouncer.tsx} | 37 +++++++------------ 2 files changed, 16 insertions(+), 33 deletions(-) rename packages/docusaurus/src/client/{RouteAnnouncerWrapper.tsx => RouteAnnouncer.tsx} (66%) diff --git a/packages/docusaurus/src/client/App.tsx b/packages/docusaurus/src/client/App.tsx index 9ac9e08eee01..5b0902995e90 100644 --- a/packages/docusaurus/src/client/App.tsx +++ b/packages/docusaurus/src/client/App.tsx @@ -16,8 +16,7 @@ import BaseUrlIssueBanner from './BaseUrlIssueBanner'; import SiteMetadataDefaults from './SiteMetadataDefaults'; import Root from '@theme/Root'; import SiteMetadata from '@theme/SiteMetadata'; -import RouteAnnouncerWrapper from './RouteAnnouncerWrapper'; -import {useLocation} from 'react-router'; +import RouteAnnouncer from './RouteAnnouncer'; import './clientLifecyclesDispatcher'; @@ -25,10 +24,7 @@ import './clientLifecyclesDispatcher'; import ErrorBoundary from '@docusaurus/ErrorBoundary'; import Error from '@theme/Error'; -/* eslint-disable @typescript-eslint/ban-ts-comment */ - export default function App(): JSX.Element { - const {pathname} = useLocation(); return ( @@ -38,11 +34,7 @@ export default function App(): JSX.Element { - {/* - // @ts-ignore */} - - {renderRoutes(routes)} - + {renderRoutes(routes)} diff --git a/packages/docusaurus/src/client/RouteAnnouncerWrapper.tsx b/packages/docusaurus/src/client/RouteAnnouncer.tsx similarity index 66% rename from packages/docusaurus/src/client/RouteAnnouncerWrapper.tsx rename to packages/docusaurus/src/client/RouteAnnouncer.tsx index 59ce7ff14ae2..c6dbc17f54b6 100644 --- a/packages/docusaurus/src/client/RouteAnnouncerWrapper.tsx +++ b/packages/docusaurus/src/client/RouteAnnouncer.tsx @@ -7,40 +7,32 @@ import React from 'react'; import {Portal} from './exports/Portal'; -import type {RouteComponentProps} from 'react-router-dom'; -/* eslint-disable @typescript-eslint/ban-ts-comment */ +type Props = { + children: React.ReactNode; +}; -class RouteAnnouncerWrapper extends React.Component { - constructor({ - children, - location, - }: { - children: React.ReactNode; - } & RouteComponentProps) { - super({children, location}); +type State = { + routeAnnouncement: string; +}; + +class RouteAnnouncerWrapper extends React.Component { + constructor(props: Props) { + super(props); this.state = { routeAnnouncement: '', }; } override componentDidUpdate(): void { - // @ts-ignore - const {pathname} = this.props.location; // @ts-ignore const {routeAnnouncement} = this.state; requestAnimationFrame(() => { - let pageName = `new page at ${pathname}`; - if (document.title) { - pageName = document.title; - } - const pageHeadings = document.querySelectorAll(`#__docusaurus h1`); - if (pageHeadings?.length) { - pageName = (pageHeadings[0] as Node).textContent as string; - } + const firstHeading = document.querySelectorAll(`#__docusaurus h1`)[0]; + const pageName = firstHeading?.textContent ?? document.title; const newAnnouncement = `Navigated to ${pageName}`; const oldAnnouncement = routeAnnouncement; - if (!Object.is(oldAnnouncement, newAnnouncement)) { + if (oldAnnouncement !== newAnnouncement) { this.setState({ routeAnnouncement: newAnnouncement, }); @@ -50,7 +42,7 @@ class RouteAnnouncerWrapper extends React.Component { // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types override render() { - const {children} = this.props; // @ts-ignore + const {children} = this.props; const {routeAnnouncement} = this.state; return ( <> @@ -81,5 +73,4 @@ class RouteAnnouncerWrapper extends React.Component { } } -// @ts-ignore export default RouteAnnouncerWrapper; From 49e20e7d9dd1faa74ac243f564f2025814e3d7b6 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Sun, 3 Apr 2022 22:00:21 +0800 Subject: [PATCH 16/24] add return type --- packages/docusaurus/src/client/RouteAnnouncer.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/docusaurus/src/client/RouteAnnouncer.tsx b/packages/docusaurus/src/client/RouteAnnouncer.tsx index c6dbc17f54b6..3fe8a726881a 100644 --- a/packages/docusaurus/src/client/RouteAnnouncer.tsx +++ b/packages/docusaurus/src/client/RouteAnnouncer.tsx @@ -40,8 +40,7 @@ class RouteAnnouncerWrapper extends React.Component { }); } - // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types - override render() { + override render(): JSX.Element { const {children} = this.props; const {routeAnnouncement} = this.state; return ( From 37cafa390a2974df2a9d4df21eb37b345a1ebe64 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Sun, 3 Apr 2022 22:07:11 +0800 Subject: [PATCH 17/24] quick fix --- packages/docusaurus/src/client/App.tsx | 7 +++++-- packages/docusaurus/src/client/RouteAnnouncer.tsx | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/docusaurus/src/client/App.tsx b/packages/docusaurus/src/client/App.tsx index 5b0902995e90..03eb4aa48fb0 100644 --- a/packages/docusaurus/src/client/App.tsx +++ b/packages/docusaurus/src/client/App.tsx @@ -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'; @@ -25,6 +25,7 @@ import ErrorBoundary from '@docusaurus/ErrorBoundary'; import Error from '@theme/Error'; export default function App(): JSX.Element { + const {pathname} = useLocation(); return ( @@ -34,7 +35,9 @@ export default function App(): JSX.Element { - {renderRoutes(routes)} + + {renderRoutes(routes)} + diff --git a/packages/docusaurus/src/client/RouteAnnouncer.tsx b/packages/docusaurus/src/client/RouteAnnouncer.tsx index 3fe8a726881a..d2f02ff6d07d 100644 --- a/packages/docusaurus/src/client/RouteAnnouncer.tsx +++ b/packages/docusaurus/src/client/RouteAnnouncer.tsx @@ -9,6 +9,9 @@ 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; }; From 7cc8df36bda48c6f9b1d5f193982c4a51c0b51a4 Mon Sep 17 00:00:00 2001 From: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> Date: Sun, 3 Apr 2022 23:13:11 +0900 Subject: [PATCH 18/24] fallback to page path when first h1 or document.title does not exist -- similarly to gatsby 4 Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> --- packages/docusaurus/src/client/RouteAnnouncer.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/docusaurus/src/client/RouteAnnouncer.tsx b/packages/docusaurus/src/client/RouteAnnouncer.tsx index d2f02ff6d07d..4324aa335f2c 100644 --- a/packages/docusaurus/src/client/RouteAnnouncer.tsx +++ b/packages/docusaurus/src/client/RouteAnnouncer.tsx @@ -10,7 +10,6 @@ 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; }; @@ -29,10 +28,14 @@ class RouteAnnouncerWrapper extends React.Component { override componentDidUpdate(): void { const {routeAnnouncement} = this.state; + const {location} = this.props; requestAnimationFrame(() => { const firstHeading = document.querySelectorAll(`#__docusaurus h1`)[0]; - const pageName = firstHeading?.textContent ?? document.title; + const pageName = + firstHeading?.textContent ?? + document.title ?? + `new page at ${location}`; const newAnnouncement = `Navigated to ${pageName}`; const oldAnnouncement = routeAnnouncement; if (oldAnnouncement !== newAnnouncement) { From 1060785f3afa96f192f96e4f295359ba2087a9ee Mon Sep 17 00:00:00 2001 From: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> Date: Sun, 3 Apr 2022 23:20:13 +0900 Subject: [PATCH 19/24] remove temporary fallback Signed-off-by: Shinwon Elizabeth Yoon <24852454+seyoon20087@users.noreply.github.com> --- packages/docusaurus/src/client/RouteAnnouncer.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/docusaurus/src/client/RouteAnnouncer.tsx b/packages/docusaurus/src/client/RouteAnnouncer.tsx index 4324aa335f2c..d2f02ff6d07d 100644 --- a/packages/docusaurus/src/client/RouteAnnouncer.tsx +++ b/packages/docusaurus/src/client/RouteAnnouncer.tsx @@ -10,6 +10,7 @@ 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; }; @@ -28,14 +29,10 @@ class RouteAnnouncerWrapper extends React.Component { override componentDidUpdate(): void { const {routeAnnouncement} = this.state; - const {location} = this.props; requestAnimationFrame(() => { const firstHeading = document.querySelectorAll(`#__docusaurus h1`)[0]; - const pageName = - firstHeading?.textContent ?? - document.title ?? - `new page at ${location}`; + const pageName = firstHeading?.textContent ?? document.title; const newAnnouncement = `Navigated to ${pageName}`; const oldAnnouncement = routeAnnouncement; if (oldAnnouncement !== newAnnouncement) { From 870476779e5e825fde6e5a7fadf523998ebfa4fa Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Sat, 30 Apr 2022 10:52:01 +0800 Subject: [PATCH 20/24] reimplement with client module --- .../src/routeAnnouncer.ts | 45 +++++++++++ packages/docusaurus/src/client/App.tsx | 5 +- .../docusaurus/src/client/RouteAnnouncer.tsx | 78 ------------------- 3 files changed, 46 insertions(+), 82 deletions(-) create mode 100644 packages/docusaurus-theme-classic/src/routeAnnouncer.ts delete mode 100644 packages/docusaurus/src/client/RouteAnnouncer.tsx diff --git a/packages/docusaurus-theme-classic/src/routeAnnouncer.ts b/packages/docusaurus-theme-classic/src/routeAnnouncer.ts new file mode 100644 index 000000000000..cdd032f33169 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/routeAnnouncer.ts @@ -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 type {ClientModule} from '@docusaurus/types'; + +const clientModule: ClientModule = { + onRouteDidUpdate({location, previousLocation}) { + if (!previousLocation || location.pathname !== previousLocation.pathname) { + return; + } + const announcerContainer = document.createElement( + 'docusaurus-route-announcer', + ); + const announcement = document.createElement('p'); + Object.assign(announcement, { + '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', + }, + }); + const firstHeading = document.querySelectorAll(`#__docusaurus h1`)[0]; + const pageName = firstHeading?.textContent ?? document.title; + announcement.innerText = `Navigated to ${pageName}`; + announcerContainer.appendChild(announcement); + document.body.appendChild(announcerContainer); + }, +}; + +export default clientModule; diff --git a/packages/docusaurus/src/client/App.tsx b/packages/docusaurus/src/client/App.tsx index 6d16bd3fa008..c709c2e8515f 100644 --- a/packages/docusaurus/src/client/App.tsx +++ b/packages/docusaurus/src/client/App.tsx @@ -19,7 +19,6 @@ import BaseUrlIssueBanner from './BaseUrlIssueBanner'; import SiteMetadataDefaults from './SiteMetadataDefaults'; import Root from '@theme/Root'; import SiteMetadata from '@theme/SiteMetadata'; -import RouteAnnouncer from './RouteAnnouncer'; // TODO, quick fix for CSS insertion order import ErrorBoundary from '@docusaurus/ErrorBoundary'; @@ -37,9 +36,7 @@ export default function App(): JSX.Element { - - {routeElement} - + {routeElement} diff --git a/packages/docusaurus/src/client/RouteAnnouncer.tsx b/packages/docusaurus/src/client/RouteAnnouncer.tsx deleted file mode 100644 index d2f02ff6d07d..000000000000 --- a/packages/docusaurus/src/client/RouteAnnouncer.tsx +++ /dev/null @@ -1,78 +0,0 @@ -/** - * 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 { - constructor(props: Props) { - super(props); - this.state = { - routeAnnouncement: '', - }; - } - - override componentDidUpdate(): void { - const {routeAnnouncement} = this.state; - - requestAnimationFrame(() => { - const firstHeading = document.querySelectorAll(`#__docusaurus h1`)[0]; - const pageName = firstHeading?.textContent ?? document.title; - const newAnnouncement = `Navigated to ${pageName}`; - const oldAnnouncement = routeAnnouncement; - if (oldAnnouncement !== newAnnouncement) { - this.setState({ - routeAnnouncement: newAnnouncement, - }); - } - }); - } - - override render(): JSX.Element { - const {children} = this.props; - const {routeAnnouncement} = this.state; - return ( - <> - {children} - - - - - ); - } -} - -export default RouteAnnouncerWrapper; From 6104fcbc72bfd7fa168336ad708cf646857c9a3f Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Sat, 30 Apr 2022 10:59:29 +0800 Subject: [PATCH 21/24] make text label translatable --- .../docusaurus-theme-classic/src/routeAnnouncer.ts | 13 +++++++++++-- .../locales/ar/theme-common.json | 1 + .../locales/base/theme-common.json | 2 ++ .../locales/bn/theme-common.json | 1 + .../locales/cs/theme-common.json | 1 + .../locales/da/theme-common.json | 1 + .../locales/de/theme-common.json | 1 + .../locales/es/theme-common.json | 1 + .../locales/fa/theme-common.json | 1 + .../locales/fil/theme-common.json | 1 + .../locales/fr/theme-common.json | 1 + .../locales/he/theme-common.json | 1 + .../locales/hi/theme-common.json | 1 + .../locales/it/theme-common.json | 1 + .../locales/ja/theme-common.json | 1 + .../locales/ko/theme-common.json | 1 + .../locales/pl/theme-common.json | 1 + .../locales/pt-BR/theme-common.json | 1 + .../locales/pt-PT/theme-common.json | 1 + .../locales/ru/theme-common.json | 1 + .../locales/sr/theme-common.json | 1 + .../locales/tr/theme-common.json | 1 + .../locales/vi/theme-common.json | 1 + .../locales/zh-Hans/theme-common.json | 1 + .../locales/zh-Hant/theme-common.json | 1 + 25 files changed, 36 insertions(+), 2 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/routeAnnouncer.ts b/packages/docusaurus-theme-classic/src/routeAnnouncer.ts index cdd032f33169..a7f957648c44 100644 --- a/packages/docusaurus-theme-classic/src/routeAnnouncer.ts +++ b/packages/docusaurus-theme-classic/src/routeAnnouncer.ts @@ -5,11 +5,12 @@ * LICENSE file in the root directory of this source tree. */ +import {translate} from '@docusaurus/Translate'; import type {ClientModule} from '@docusaurus/types'; const clientModule: ClientModule = { onRouteDidUpdate({location, previousLocation}) { - if (!previousLocation || location.pathname !== previousLocation.pathname) { + if (!previousLocation || location.pathname === previousLocation.pathname) { return; } const announcerContainer = document.createElement( @@ -36,7 +37,15 @@ const clientModule: ClientModule = { }); const firstHeading = document.querySelectorAll(`#__docusaurus h1`)[0]; const pageName = firstHeading?.textContent ?? document.title; - announcement.innerText = `Navigated to ${pageName}`; + 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); }, diff --git a/packages/docusaurus-theme-translations/locales/ar/theme-common.json b/packages/docusaurus-theme-translations/locales/ar/theme-common.json index 733339b593f7..d72a21279ad3 100644 --- a/packages/docusaurus-theme-translations/locales/ar/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/ar/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "لم نتمكن من العثور على ما كنت تبحث عنه.", "theme.NotFound.p2": "يرجى الاتصال بمالك الموقع الذي ربطك بعنوان URL الأصلي وإخباره بأن الارتباط الخاص به معطل.", "theme.NotFound.title": "الصفحة غير موجودة", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "محتويات هذه الصفحة", "theme.blog.archive.description": "Archive", "theme.blog.archive.title": "Archive", diff --git a/packages/docusaurus-theme-translations/locales/base/theme-common.json b/packages/docusaurus-theme-translations/locales/base/theme-common.json index c0add97b3d82..ba7a22688b45 100644 --- a/packages/docusaurus-theme-translations/locales/base/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/base/theme-common.json @@ -23,6 +23,8 @@ "theme.NotFound.p2___DESCRIPTION": "The 2nd paragraph of the 404 page", "theme.NotFound.title": "Page Not Found", "theme.NotFound.title___DESCRIPTION": "The title of the 404 page", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", + "theme.RouteAnnouncer.content___DESCRIPTION": "The text announced by screen reader when the user has navigated to a new page", "theme.TOCCollapsible.toggleButtonLabel": "On this page", "theme.TOCCollapsible.toggleButtonLabel___DESCRIPTION": "The label used by the button on the collapsible TOC component", "theme.blog.archive.description": "Archive", diff --git a/packages/docusaurus-theme-translations/locales/bn/theme-common.json b/packages/docusaurus-theme-translations/locales/bn/theme-common.json index ab6622015aea..97fb17b50f18 100644 --- a/packages/docusaurus-theme-translations/locales/bn/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/bn/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "আপনি যা খুঁজছিলেন তা আমরা খুঁজে পাইনি।", "theme.NotFound.p2": "দয়া করে সাইটের মালিকের সাথে যোগাযোগ করুন যা আপনাকে মূল URL এর সাথে যুক্ত করেছে এবং তাদের লিঙ্কটি ভাঙ্গা রয়েছে তা তাদের জানান।", "theme.NotFound.title": "পেজটি খুঁজে পাওয়া যায়নি", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "এই পেজ এ রয়েছে", "theme.blog.archive.description": "Archive", "theme.blog.archive.title": "Archive", diff --git a/packages/docusaurus-theme-translations/locales/cs/theme-common.json b/packages/docusaurus-theme-translations/locales/cs/theme-common.json index c96d713105b7..a8a6cab1486b 100644 --- a/packages/docusaurus-theme-translations/locales/cs/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/cs/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "Nepodařilo se nám najít co jste hledal(a).", "theme.NotFound.p2": "Kontaktujte prosím vlastníka webu, který vás odkázal na původní URL a upozorněte ho, že jejich odkaz nefunguje.", "theme.NotFound.title": "Stránka nenalezena", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "Na této stránce", "theme.blog.archive.description": "Archive", "theme.blog.archive.title": "Archive", diff --git a/packages/docusaurus-theme-translations/locales/da/theme-common.json b/packages/docusaurus-theme-translations/locales/da/theme-common.json index 68883d12e37a..2b376d637346 100644 --- a/packages/docusaurus-theme-translations/locales/da/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/da/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "Vi kunne ikke finde det, du søgte.", "theme.NotFound.p2": "Venligst kontakt ejeren til webstedet, som førte dig frem denne URL, og informer dem om at linket ikke virker.", "theme.NotFound.title": "Siden blev ikke fundet", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "On this page", "theme.blog.archive.description": "Archive", "theme.blog.archive.title": "Archive", diff --git a/packages/docusaurus-theme-translations/locales/de/theme-common.json b/packages/docusaurus-theme-translations/locales/de/theme-common.json index a9d9dedff0f4..e7292fde61a0 100644 --- a/packages/docusaurus-theme-translations/locales/de/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/de/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "Wir konnten nicht finden, wonach Sie gesucht haben.", "theme.NotFound.p2": "Bitte kontaktieren Sie den Besitzer der Seite, die Sie mit der ursprünglichen URL verlinkt hat, und teilen Sie ihm mit, dass der Link nicht mehr funktioniert.", "theme.NotFound.title": "Seite nicht gefunden", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "Auf dieser Seite", "theme.blog.archive.description": "Archiv", "theme.blog.archive.title": "Archiv", diff --git a/packages/docusaurus-theme-translations/locales/es/theme-common.json b/packages/docusaurus-theme-translations/locales/es/theme-common.json index 84f444862ac9..48cc139de2b8 100644 --- a/packages/docusaurus-theme-translations/locales/es/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/es/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "No pudimos encontrar lo que buscaba.", "theme.NotFound.p2": "Comuníquese con el dueño del sitio que lo vinculó a la URL original y hágale saber que su vínculo está roto.", "theme.NotFound.title": "Página No Encontrada", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "En esta página", "theme.blog.archive.description": "Archivo", "theme.blog.archive.title": "Archivo", diff --git a/packages/docusaurus-theme-translations/locales/fa/theme-common.json b/packages/docusaurus-theme-translations/locales/fa/theme-common.json index 3a0824e8edad..68bb2dc2eff0 100644 --- a/packages/docusaurus-theme-translations/locales/fa/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/fa/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "صفحه ای که دنبال آن بودید پیدا نشد.", "theme.NotFound.p2": "لطفا با صاحب وبسایت تماس بگیرید و ایشان را از مشکل پیش آمده مطلع کنید.", "theme.NotFound.title": "صفحه ای که دنبال آن بودید پیدا نشد.", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "مطالب این صفحه", "theme.blog.archive.description": "آرشیو", "theme.blog.archive.title": "آرشیو", diff --git a/packages/docusaurus-theme-translations/locales/fil/theme-common.json b/packages/docusaurus-theme-translations/locales/fil/theme-common.json index 96f6d54218e8..f30dd57923c9 100644 --- a/packages/docusaurus-theme-translations/locales/fil/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/fil/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "Hindi namin mahanap ang iyong hinananap.", "theme.NotFound.p2": "Mangyaring makipag-ugnayan sa may-ari ng site na nag-link sa iyo sa orihinal na URL at sabihin sa kanila na ang kanilang link ay putol.", "theme.NotFound.title": "Hindi Nahanap ang Pahina", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "On this page", "theme.blog.archive.description": "Archive", "theme.blog.archive.title": "Archive", diff --git a/packages/docusaurus-theme-translations/locales/fr/theme-common.json b/packages/docusaurus-theme-translations/locales/fr/theme-common.json index 6e710a2f0263..93a0480c02ac 100644 --- a/packages/docusaurus-theme-translations/locales/fr/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/fr/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "Nous n'avons pas trouvé ce que vous recherchez.", "theme.NotFound.p2": "Veuillez contacter le propriétaire du site qui vous a lié à l'URL d'origine et leur faire savoir que leur lien est cassé.", "theme.NotFound.title": "Page introuvable", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "Sur cette page", "theme.blog.archive.description": "Archive", "theme.blog.archive.title": "Archive", diff --git a/packages/docusaurus-theme-translations/locales/he/theme-common.json b/packages/docusaurus-theme-translations/locales/he/theme-common.json index 31583e4b6be6..a49147d5bdb7 100644 --- a/packages/docusaurus-theme-translations/locales/he/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/he/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "אנחנו לא מוצאים את מה שאתה מנסה לחפש.", "theme.NotFound.p2": "הקישור אינו תקין, אנא פנה למנהל האתר ממנו קיבלת קישור זה.", "theme.NotFound.title": "דף לא נמצא", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "בעמוד זה", "theme.blog.archive.description": "Archive", "theme.blog.archive.title": "Archive", diff --git a/packages/docusaurus-theme-translations/locales/hi/theme-common.json b/packages/docusaurus-theme-translations/locales/hi/theme-common.json index e7414351fffe..01f9a2db3dd3 100644 --- a/packages/docusaurus-theme-translations/locales/hi/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/hi/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "हमें वह नहीं मिला, जिसकी आपको तलाश थी।", "theme.NotFound.p2": "कृपया उस साइट के मालिक से संपर्क करें जिसने आपको मूल URL से जोड़ा है और उन्हें बताएं कि उनका लिंक टूट गया है।", "theme.NotFound.title": "पेज नहीं मिला", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "इस पेज पर", "theme.blog.archive.description": "Archive", "theme.blog.archive.title": "Archive", diff --git a/packages/docusaurus-theme-translations/locales/it/theme-common.json b/packages/docusaurus-theme-translations/locales/it/theme-common.json index c64d605af488..9d585ab01afe 100644 --- a/packages/docusaurus-theme-translations/locales/it/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/it/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "Non siamo riusciti a trovare quello che stavi cercando.", "theme.NotFound.p2": "Contatta il proprietario del sito che ti ha collegato all'URL originale e fagli sapere che il loro collegamento è interrotto.", "theme.NotFound.title": "Pagina non trovata", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "Su questa pagina", "theme.blog.archive.description": "Archivio", "theme.blog.archive.title": "Archivio", diff --git a/packages/docusaurus-theme-translations/locales/ja/theme-common.json b/packages/docusaurus-theme-translations/locales/ja/theme-common.json index 1df195ae8098..ac489df98156 100644 --- a/packages/docusaurus-theme-translations/locales/ja/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/ja/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "お探しのページが見つかりませんでした。", "theme.NotFound.p2": "このページにリンクしているサイトの所有者に連絡をしてリンクが壊れていることを伝えてください。", "theme.NotFound.title": "ページが見つかりません", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "On this page", "theme.blog.archive.description": "Archive", "theme.blog.archive.title": "Archive", diff --git a/packages/docusaurus-theme-translations/locales/ko/theme-common.json b/packages/docusaurus-theme-translations/locales/ko/theme-common.json index d9f88a2c67f8..575544f004aa 100644 --- a/packages/docusaurus-theme-translations/locales/ko/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/ko/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "원하는 페이지를 찾을 수 없습니다.", "theme.NotFound.p2": "사이트 관리자에게 링크가 깨진 것을 알려주세요.", "theme.NotFound.title": "페이지를 찾을 수 없습니다.", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "이 페이지에서", "theme.blog.archive.description": "게시물 목록", "theme.blog.archive.title": "게시물 목록", diff --git a/packages/docusaurus-theme-translations/locales/pl/theme-common.json b/packages/docusaurus-theme-translations/locales/pl/theme-common.json index 2614e49d1e5e..1b19c749b947 100644 --- a/packages/docusaurus-theme-translations/locales/pl/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/pl/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "Nie mogliśmy znaleźć strony której szukasz.", "theme.NotFound.p2": "Proszę skontaktuj się z właścielem strony, z której link doprowadził Cię tutaj i poinformuj go, że link jest nieprawidłowy.", "theme.NotFound.title": "Strona nie została znaleziona", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "Na tej stronie", "theme.blog.archive.description": "Archiwum", "theme.blog.archive.title": "Archiwum", diff --git a/packages/docusaurus-theme-translations/locales/pt-BR/theme-common.json b/packages/docusaurus-theme-translations/locales/pt-BR/theme-common.json index 2eb57260924b..da7dd59cfa12 100644 --- a/packages/docusaurus-theme-translations/locales/pt-BR/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/pt-BR/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "Não foi possível encontrar o que você está procurando.", "theme.NotFound.p2": "Entre em contato com o proprietário do site que lhe trouxe para cá e lhe informe que o link está quebrado.", "theme.NotFound.title": "Página não encontrada", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "Nessa página", "theme.blog.archive.description": "Arquivo", "theme.blog.archive.title": "Arquivo", diff --git a/packages/docusaurus-theme-translations/locales/pt-PT/theme-common.json b/packages/docusaurus-theme-translations/locales/pt-PT/theme-common.json index efebca3723cf..9275138cbdb6 100644 --- a/packages/docusaurus-theme-translations/locales/pt-PT/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/pt-PT/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "Não foi possível encontrar o que procura.", "theme.NotFound.p2": "Por favor, contacte o proprietário do site que o trouxe aqui e informe-lhe que o link está partido.", "theme.NotFound.title": "Página não encontrada", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "On this page", "theme.blog.archive.description": "Archive", "theme.blog.archive.title": "Archive", diff --git a/packages/docusaurus-theme-translations/locales/ru/theme-common.json b/packages/docusaurus-theme-translations/locales/ru/theme-common.json index b711c9a1c6ab..21d64e1946a4 100644 --- a/packages/docusaurus-theme-translations/locales/ru/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/ru/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "К сожалению, мы не смогли найти запрашиваемую вами страницу.", "theme.NotFound.p2": "Пожалуйста, обратитесь к владельцу сайта, с которого вы перешли на эту ссылку, чтобы сообщить ему, что ссылка не работает.", "theme.NotFound.title": "Страница не найдена", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "Содержание этой страницы", "theme.blog.archive.description": "Архив", "theme.blog.archive.title": "Архив", diff --git a/packages/docusaurus-theme-translations/locales/sr/theme-common.json b/packages/docusaurus-theme-translations/locales/sr/theme-common.json index ee9180d2e7f8..3120937bede2 100644 --- a/packages/docusaurus-theme-translations/locales/sr/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/sr/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "Тражени резултат не постоји.", "theme.NotFound.p2": "Молимо вас да контактирате власника сајта који вас је упутио овде и обавестите га да је њихова веза нетачна.", "theme.NotFound.title": "Страница није пронађена", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "На овој страници", "theme.blog.archive.description": "Архива", "theme.blog.archive.title": "Архива", diff --git a/packages/docusaurus-theme-translations/locales/tr/theme-common.json b/packages/docusaurus-theme-translations/locales/tr/theme-common.json index 635c5251f0d4..f8378d28d144 100644 --- a/packages/docusaurus-theme-translations/locales/tr/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/tr/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "Aradığınız şeyi bulamadık.", "theme.NotFound.p2": "Lütfen sizi orijinal URL'ye yönlendiren sitenin sahibiyle iletişime geçin ve bağlantısının bozuk olduğunu bildirin.", "theme.NotFound.title": "Sayfa Bulunamadı", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "Bu sayfada", "theme.blog.archive.description": "Arşiv", "theme.blog.archive.title": "Arşiv", diff --git a/packages/docusaurus-theme-translations/locales/vi/theme-common.json b/packages/docusaurus-theme-translations/locales/vi/theme-common.json index 173b6f8b715e..e177c9e21e9b 100644 --- a/packages/docusaurus-theme-translations/locales/vi/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/vi/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "Chúng tôi không thể tìm thấy những gì bạn đang tìm kiếm.", "theme.NotFound.p2": "Vui lòng liên hệ với trang web đã dẫn bạn tới đây và thông báo cho họ biết rằng đường dẫn này bị hỏng.", "theme.NotFound.title": "Không tìm thấy trang", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "Trên trang này", "theme.blog.archive.description": "Lưu trữ", "theme.blog.archive.title": "Lưu trữ", diff --git a/packages/docusaurus-theme-translations/locales/zh-Hans/theme-common.json b/packages/docusaurus-theme-translations/locales/zh-Hans/theme-common.json index 5a297e3046de..3bdf568eafb6 100644 --- a/packages/docusaurus-theme-translations/locales/zh-Hans/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/zh-Hans/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "我们找不到您要找的页面。", "theme.NotFound.p2": "请联系原始链接来源网站的所有者,并告知他们链接已损坏。", "theme.NotFound.title": "找不到页面", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "本页总览", "theme.blog.archive.description": "历史博文", "theme.blog.archive.title": "历史博文", diff --git a/packages/docusaurus-theme-translations/locales/zh-Hant/theme-common.json b/packages/docusaurus-theme-translations/locales/zh-Hant/theme-common.json index 7e5b6e321923..b149c7df2c46 100644 --- a/packages/docusaurus-theme-translations/locales/zh-Hant/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/zh-Hant/theme-common.json @@ -11,6 +11,7 @@ "theme.NotFound.p1": "我們沒有您要找的頁面。", "theme.NotFound.p2": "請聯絡原始連結來源網站的所有者,並通知他們連結已毀損。", "theme.NotFound.title": "找不到頁面", + "theme.RouteAnnouncer.content": "Navigated to {pageName}", "theme.TOCCollapsible.toggleButtonLabel": "本頁導覽", "theme.blog.archive.description": "歷史文章", "theme.blog.archive.title": "歷史文章", From 4e2319d6c832f71f63cda98013fcb27e24f41494 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Sat, 30 Apr 2022 11:17:22 +0800 Subject: [PATCH 22/24] fixes --- .../docusaurus-theme-classic/src/index.ts | 1 + .../src/routeAnnouncer.css | 20 ++++++++++++++++++ .../src/routeAnnouncer.ts | 21 ++++++------------- 3 files changed, 27 insertions(+), 15 deletions(-) create mode 100644 packages/docusaurus-theme-classic/src/routeAnnouncer.css diff --git a/packages/docusaurus-theme-classic/src/index.ts b/packages/docusaurus-theme-classic/src/index.ts index d24c0b3f87e3..6ecf709fcd16 100644 --- a/packages/docusaurus-theme-classic/src/index.ts +++ b/packages/docusaurus-theme-classic/src/index.ts @@ -139,6 +139,7 @@ export default function docusaurusThemeClassic( './prism-include-languages', './admonitions.css', './nprogress', + './routeAnnouncer', ]; if (customCss) { diff --git a/packages/docusaurus-theme-classic/src/routeAnnouncer.css b/packages/docusaurus-theme-classic/src/routeAnnouncer.css new file mode 100644 index 000000000000..e8a2afd66704 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/routeAnnouncer.css @@ -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; +} diff --git a/packages/docusaurus-theme-classic/src/routeAnnouncer.ts b/packages/docusaurus-theme-classic/src/routeAnnouncer.ts index a7f957648c44..ac5914ef6efa 100644 --- a/packages/docusaurus-theme-classic/src/routeAnnouncer.ts +++ b/packages/docusaurus-theme-classic/src/routeAnnouncer.ts @@ -7,33 +7,24 @@ 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, { - 'aria-live': 'assertive', // Make the announcement immediately. - id: '__docusaurus-route-announcer__', + ariaLive: 'assertive', // Make the announcement immediately. + id: 'docusaurus-route-announcer-content', 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', - }, }); const firstHeading = document.querySelectorAll(`#__docusaurus h1`)[0]; const pageName = firstHeading?.textContent ?? document.title; From 00956fdafec2e5f206e9b2f0b72e373dfe9ce7db Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Sat, 30 Apr 2022 11:23:56 +0800 Subject: [PATCH 23/24] fix CSS order? --- website/testCSSOrder.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/testCSSOrder.mjs b/website/testCSSOrder.mjs index 0b1aaa7129a7..fc4f5223c158 100644 --- a/website/testCSSOrder.mjs +++ b/website/testCSSOrder.mjs @@ -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', ]; const cssDirName = fileURLToPath(new URL('build/assets/css', import.meta.url)); From 8833c65ee4f284c9fe994db97d74e918f7a73ce6 Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Sat, 30 Apr 2022 11:28:29 +0800 Subject: [PATCH 24/24] use cleanup function --- packages/docusaurus-theme-classic/src/routeAnnouncer.ts | 6 ++---- .../docusaurus/src/client/ClientLifecyclesDispatcher.tsx | 6 +++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/routeAnnouncer.ts b/packages/docusaurus-theme-classic/src/routeAnnouncer.ts index ac5914ef6efa..4b76892508ce 100644 --- a/packages/docusaurus-theme-classic/src/routeAnnouncer.ts +++ b/packages/docusaurus-theme-classic/src/routeAnnouncer.ts @@ -12,11 +12,8 @@ import './routeAnnouncer.css'; const clientModule: ClientModule = { onRouteDidUpdate({location, previousLocation}) { if (!previousLocation || location.pathname === previousLocation.pathname) { - return; + return undefined; } - Array.from( - document.getElementsByTagName('docusaurus-route-announcer'), - ).forEach(document.removeChild); const announcerContainer = document.createElement( 'docusaurus-route-announcer', ); @@ -39,6 +36,7 @@ const clientModule: ClientModule = { ); announcerContainer.appendChild(announcement); document.body.appendChild(announcerContainer); + return () => document.body.removeChild(announcerContainer); }, }; diff --git a/packages/docusaurus/src/client/ClientLifecyclesDispatcher.tsx b/packages/docusaurus/src/client/ClientLifecyclesDispatcher.tsx index 7c797af092d7..ba5950252423 100644 --- a/packages/docusaurus/src/client/ClientLifecyclesDispatcher.tsx +++ b/packages/docusaurus/src/client/ClientLifecyclesDispatcher.tsx @@ -46,8 +46,12 @@ function ClientLifecyclesDispatcher({ const element = document.getElementById(id); element?.scrollIntoView(); } - dispatchLifecycleAction('onRouteDidUpdate', {previousLocation, location}); + return dispatchLifecycleAction('onRouteDidUpdate', { + previousLocation, + location, + }); } + return undefined; }, [previousLocation, location]); return children; }