refactor(theme-classic): multiple re-arrangements (#7273)

* refactor(theme-classic): enforce collocated JSX and module CSS

* refactor
This commit is contained in:
Joshua Chen 2022-04-30 12:29:54 +08:00 committed by GitHub
parent 355a22907d
commit 710f898703
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 40 additions and 25 deletions

View file

@ -10,7 +10,7 @@ import React from 'react';
import {useDocsSidebar} from '@docusaurus/theme-common'; import {useDocsSidebar} from '@docusaurus/theme-common';
import clsx from 'clsx'; import clsx from 'clsx';
import styles from './Main.module.css'; import styles from './styles.module.css';
import type {Props} from '@theme/DocPage/Layout/Main'; import type {Props} from '@theme/DocPage/Layout/Main';
export default function DocPageLayoutMain({ export default function DocPageLayoutMain({

View file

@ -10,7 +10,7 @@ import IconArrow from '@theme/IconArrow';
import {translate} from '@docusaurus/Translate'; import {translate} from '@docusaurus/Translate';
import type {Props} from '@theme/DocPage/Layout/Sidebar/ExpandButton'; import type {Props} from '@theme/DocPage/Layout/Sidebar/ExpandButton';
import styles from './ExpandButton.module.css'; import styles from './styles.module.css';
export default function DocPageLayoutSidebarExpandButton({ export default function DocPageLayoutSidebarExpandButton({
toggleSidebar, toggleSidebar,

View file

@ -9,7 +9,6 @@ import React from 'react';
import type {Props} from '@theme/TOCItems/Tree'; import type {Props} from '@theme/TOCItems/Tree';
// Recursive component rendering the toc tree // Recursive component rendering the toc tree
/* eslint-disable jsx-a11y/control-has-associated-label */
function TOCItemTree({ function TOCItemTree({
toc, toc,
className, className,
@ -23,6 +22,7 @@ function TOCItemTree({
<ul className={isChild ? undefined : className}> <ul className={isChild ? undefined : className}>
{toc.map((heading) => ( {toc.map((heading) => (
<li key={heading.id}> <li key={heading.id}>
{/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
<a <a
href={`#${heading.id}`} href={`#${heading.id}`}
className={linkClassName ?? undefined} className={linkClassName ?? undefined}

View file

@ -32,13 +32,7 @@ export function DocsSidebarProvider({
items: PropSidebar | undefined; items: PropSidebar | undefined;
}): JSX.Element { }): JSX.Element {
const stableValue: ContextValue | null = useMemo( const stableValue: ContextValue | null = useMemo(
() => () => (name && items ? {name, items} : null),
name && items
? {
name,
items,
}
: null,
[name, items], [name, items],
); );
return <Context.Provider value={stableValue}>{children}</Context.Provider>; return <Context.Provider value={stableValue}>{children}</Context.Provider>;

View file

@ -8,8 +8,8 @@
import type React from 'react'; import type React from 'react';
import {useCallback, useRef} from 'react'; import {useCallback, useRef} from 'react';
import {useHistory} from '@docusaurus/router'; import {useHistory} from '@docusaurus/router';
import {useLocationChange} from './useLocationChange'; import {useLocationChange} from '../utils/useLocationChange';
import {ThemeClassNames} from './ThemeClassNames'; import {ThemeClassNames} from '../utils/ThemeClassNames';
function programmaticFocus(el: HTMLElement) { function programmaticFocus(el: HTMLElement) {
el.setAttribute('tabindex', '-1'); el.setAttribute('tabindex', '-1');
@ -17,8 +17,21 @@ function programmaticFocus(el: HTMLElement) {
el.removeAttribute('tabindex'); el.removeAttribute('tabindex');
} }
/** This hook wires the logic for a skip-to-content link. */
export function useSkipToContent(): { export 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. **Note:** the type is `RefObject<HTMLDivElement>` only because
* the typing for refs don't reflect that the `ref` prop is contravariant, so
* using `HTMLElement` causes type-checking to fail. You can plug the ref into
* any HTML element, as long as it can be focused.
*/
containerRef: React.RefObject<HTMLDivElement>; containerRef: React.RefObject<HTMLDivElement>;
/**
* Callback fired when the skip to content link has been interacted with. It
* will programmatically focus the main content.
*/
handleSkip: (e: React.MouseEvent<HTMLAnchorElement>) => void; handleSkip: (e: React.MouseEvent<HTMLAnchorElement>) => void;
} { } {
const containerRef = useRef<HTMLDivElement>(null); const containerRef = useRef<HTMLDivElement>(null);

View file

@ -58,8 +58,6 @@ export {
useDocRouteMetadata, useDocRouteMetadata,
} from './utils/docsUtils'; } from './utils/docsUtils';
export {useSkipToContent} from './utils/a11yUtils';
export {useTitleFormatter} from './utils/generalUtils'; export {useTitleFormatter} from './utils/generalUtils';
export {usePluralForm} from './utils/usePluralForm'; export {usePluralForm} from './utils/usePluralForm';
@ -162,3 +160,4 @@ export {useLockBodyScroll} from './hooks/useLockBodyScroll';
export {useWindowSize} from './hooks/useWindowSize'; export {useWindowSize} from './hooks/useWindowSize';
export {useSearchPage} from './hooks/useSearchPage'; export {useSearchPage} from './hooks/useSearchPage';
export {useCodeWordWrap} from './hooks/useCodeWordWrap'; export {useCodeWordWrap} from './hooks/useCodeWordWrap';
export {useSkipToContent} from './hooks/useSkipToContent';

View file

@ -20,9 +20,9 @@ import type {
PropSidebarItem, PropSidebarItem,
PropSidebarItemCategory, PropSidebarItemCategory,
PropVersionDoc, PropVersionDoc,
PropVersionMetadata,
PropSidebarBreadcrumbsItem, PropSidebarBreadcrumbsItem,
} from '@docusaurus/plugin-content-docs'; } from '@docusaurus/plugin-content-docs';
import type {Props as DocPageProps} from '@theme/DocPage';
import {useDocsPreferredVersion} from '../contexts/docsPreferredVersion'; import {useDocsPreferredVersion} from '../contexts/docsPreferredVersion';
import {useDocsVersion} from '../contexts/docsVersion'; import {useDocsVersion} from '../contexts/docsVersion';
import {useDocsSidebar} from '../contexts/docsSidebar'; import {useDocsSidebar} from '../contexts/docsSidebar';
@ -30,7 +30,6 @@ import {uniq} from './jsUtils';
import {isSamePath} from './routesUtils'; import {isSamePath} from './routesUtils';
import {matchPath, useLocation} from '@docusaurus/router'; import {matchPath, useLocation} from '@docusaurus/router';
import renderRoutes from '@docusaurus/renderRoutes'; import renderRoutes from '@docusaurus/renderRoutes';
import type {RouteConfig} from 'react-router-config';
// TODO not ideal, see also "useDocs" // TODO not ideal, see also "useDocs"
export const isDocsPluginEnabled: boolean = !!useAllDocsData; export const isDocsPluginEnabled: boolean = !!useAllDocsData;
@ -286,20 +285,32 @@ Available doc ids are:
} }
// TODO later read version/route directly from context // TODO later read version/route directly from context
/**
* The docs plugin creates nested routes, with the top-level route providing the
* version metadata, and the subroutes creating individual doc pages. This hook
* will match the current location against all known sub-routes.
*
* @param props The props received by `@theme/DocPage`
* @returns The data of the relevant document at the current location, or `null`
* if no document associated with the current location can be found.
*/
export function useDocRouteMetadata({ export function useDocRouteMetadata({
route, route,
versionMetadata, versionMetadata,
}: { }: DocPageProps): null | {
route: RouteConfig; /** The element that should be rendered at the current location. */
versionMetadata: PropVersionMetadata;
}): null | {
docElement: JSX.Element; docElement: JSX.Element;
/**
* The name of the sidebar associated with the current doc. `sidebarName` and
* `sidebarItems` correspond to the value of {@link useDocsSidebar}.
*/
sidebarName: string | undefined; sidebarName: string | undefined;
/** The items of the sidebar associated with the current doc. */
sidebarItems: PropSidebar | undefined; sidebarItems: PropSidebar | undefined;
} { } {
const location = useLocation(); const location = useLocation();
const docRoutes = route.routes; const docRoutes = route.routes!;
const currentDocRoute = docRoutes!.find((docRoute) => const currentDocRoute = docRoutes.find((docRoute) =>
matchPath(location.pathname, docRoute), matchPath(location.pathname, docRoute),
); );
if (!currentDocRoute) { if (!currentDocRoute) {
@ -313,9 +324,7 @@ export function useDocRouteMetadata({
? versionMetadata.docsSidebars[sidebarName] ? versionMetadata.docsSidebars[sidebarName]
: undefined; : undefined;
const docElement = renderRoutes(route.routes!, { const docElement = renderRoutes(docRoutes, {versionMetadata});
versionMetadata,
});
return { return {
docElement, docElement,