-
-
Notifications
You must be signed in to change notification settings - Fork 8.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(theme-classic): fix SkipToContent without JS , refactor, make it …
…public theming API (#8204) Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com> # Conflicts: # packages/docusaurus-theme-common/src/index.ts
- Loading branch information
Showing
7 changed files
with
128 additions
and
78 deletions.
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
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
58 changes: 0 additions & 58 deletions
58
packages/docusaurus-theme-common/src/hooks/useSkipToContent.ts
This file was deleted.
Oops, something went wrong.
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
103 changes: 103 additions & 0 deletions
103
packages/docusaurus-theme-common/src/utils/skipToContentUtils.tsx
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,103 @@ | ||
/** | ||
* 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, {useCallback, useRef, type ComponentProps} from 'react'; | ||
import {useHistory} from '@docusaurus/router'; | ||
import {translate} from '@docusaurus/Translate'; | ||
import {useLocationChange} from './useLocationChange'; | ||
|
||
/** | ||
* The id of the element that should become focused on a page | ||
* that does not have a <main> html tag. | ||
* Focusing the Docusaurus Layout children is a reasonable fallback. | ||
*/ | ||
export const SkipToContentFallbackId = 'docusaurus_skipToContent_fallback'; | ||
|
||
/** | ||
* Returns the skip to content element to focus when the link is clicked. | ||
*/ | ||
function getSkipToContentTarget(): HTMLElement | null { | ||
return ( | ||
// Try to focus the <main> in priority | ||
// Note: this will only work if JS is enabled | ||
// See https://github.com/facebook/docusaurus/issues/6411#issuecomment-1284136069 | ||
document.querySelector('main:first-of-type') ?? | ||
// Then try to focus the fallback element (usually the Layout children) | ||
document.getElementById(SkipToContentFallbackId) | ||
); | ||
} | ||
|
||
function programmaticFocus(el: HTMLElement) { | ||
el.setAttribute('tabindex', '-1'); | ||
el.focus(); | ||
el.removeAttribute('tabindex'); | ||
} | ||
|
||
/** This hook wires the logic for a skip-to-content link. */ | ||
function useSkipToContent(): { | ||
/** | ||
* The ref to the container. On page transition, the container will be focused | ||
* so that keyboard navigators can instantly interact with the link and jump | ||
* to content. | ||
*/ | ||
containerRef: React.RefObject<HTMLDivElement>; | ||
/** | ||
* Callback fired when the skip to content link has been clicked. | ||
* It will programmatically focus the main content. | ||
*/ | ||
onClick: (e: React.MouseEvent<HTMLAnchorElement>) => void; | ||
} { | ||
const containerRef = useRef<HTMLDivElement>(null); | ||
const {action} = useHistory(); | ||
|
||
const onClick = useCallback((e: React.MouseEvent<HTMLAnchorElement>) => { | ||
e.preventDefault(); | ||
const targetElement = getSkipToContentTarget(); | ||
if (targetElement) { | ||
programmaticFocus(targetElement); | ||
} | ||
}, []); | ||
|
||
// "Reset" focus when navigating. | ||
// See https://github.com/facebook/docusaurus/pull/8204#issuecomment-1276547558 | ||
useLocationChange(({location}) => { | ||
if (containerRef.current && !location.hash && action === 'PUSH') { | ||
programmaticFocus(containerRef.current); | ||
} | ||
}); | ||
|
||
return {containerRef, onClick}; | ||
} | ||
|
||
const DefaultSkipToContentLabel = translate({ | ||
id: 'theme.common.skipToMainContent', | ||
description: | ||
'The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation', | ||
message: 'Skip to main content', | ||
}); | ||
|
||
type SkipToContentLinkProps = Omit<ComponentProps<'a'>, 'href' | 'onClick'>; | ||
|
||
export function SkipToContentLink(props: SkipToContentLinkProps): JSX.Element { | ||
const linkLabel = props.children ?? DefaultSkipToContentLabel; | ||
const {containerRef, onClick} = useSkipToContent(); | ||
return ( | ||
<div | ||
ref={containerRef} | ||
role="region" | ||
aria-label={DefaultSkipToContentLabel}> | ||
<a | ||
{...props} | ||
// Note this is a fallback href in case JS is disabled | ||
// It has limitations, see https://github.com/facebook/docusaurus/issues/6411#issuecomment-1284136069 | ||
href={`#${SkipToContentFallbackId}`} | ||
onClick={onClick}> | ||
{linkLabel} | ||
</a> | ||
</div> | ||
); | ||
} |