refactor(theme-classic): refactor TOC-related theme components (#7270)

* extract TOCItemTree component

* refactor TOCCollapsible
This commit is contained in:
Sébastien Lorber 2022-04-29 19:32:35 +02:00 committed by GitHub
parent 3bef88232f
commit e053f39cf0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 143 additions and 77 deletions

View File

@ -1061,6 +1061,19 @@ declare module '@theme/TOCItems' {
export default function TOCItems(props: Props): JSX.Element;
}
declare module '@theme/TOCItems/Tree' {
import type {TOCTreeNode} from '@docusaurus/theme-common';
export interface Props {
readonly toc: readonly TOCTreeNode[];
readonly className: string;
readonly linkClassName: string | null;
readonly isChild?: boolean;
}
export default function TOCItems(props: Props): JSX.Element;
}
declare module '@theme/TOC' {
import type {TOCItem} from '@docusaurus/types';
@ -1101,6 +1114,18 @@ declare module '@theme/TOCCollapsible' {
export default function TOCCollapsible(props: Props): JSX.Element;
}
declare module '@theme/TOCCollapsible/CollapseButton' {
import type {ComponentProps} from 'react';
export interface Props extends ComponentProps<'button'> {
collapsed: boolean;
}
export default function TOCCollapsibleCollapseButton(
props: Props,
): JSX.Element;
}
declare module '@theme/ColorModeToggle' {
import type {ColorMode} from '@docusaurus/theme-common';

View File

@ -5,12 +5,6 @@
* LICENSE file in the root directory of this source tree.
*/
.tocCollapsible {
background-color: var(--ifm-menu-color-background-active);
border-radius: var(--ifm-global-radius);
margin: 1rem 0;
}
.tocCollapsibleButton {
font-size: inherit;
display: flex;
@ -30,21 +24,6 @@
transition: transform var(--ifm-transition-fast);
}
.tocCollapsibleContent > ul {
border-left: none;
border-top: 1px solid var(--ifm-color-emphasis-300);
padding: 0.2rem 0;
font-size: 15px;
}
.tocCollapsibleContent ul li {
margin: 0.4rem 0.8rem;
}
.tocCollapsibleContent a {
display: block;
}
.tocCollapsibleExpanded .tocCollapsibleButton::after {
.tocCollapsibleButtonExpanded::after {
transform: none;
}

View File

@ -0,0 +1,35 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import React from 'react';
import clsx from 'clsx';
import Translate from '@docusaurus/Translate';
import styles from './CollapseButton.module.css';
import type {Props} from '@theme/TOCCollapsible/CollapseButton';
export default function TOCCollapsibleCollapseButton({
collapsed,
...props
}: Props): JSX.Element {
return (
<button
type="button"
{...props}
className={clsx(
'clean-btn',
styles.tocCollapsibleButton,
!collapsed && styles.tocCollapsibleButtonExpanded,
props.className,
)}>
<Translate
id="theme.TOCCollapsible.toggleButtonLabel"
description="The label used by the button on the collapsible TOC component">
On this page
</Translate>
</button>
);
}

View File

@ -0,0 +1,31 @@
/**
* 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.
*/
.tocCollapsible {
background-color: var(--ifm-menu-color-background-active);
border-radius: var(--ifm-global-radius);
margin: 1rem 0;
}
.tocCollapsibleContent > ul {
border-left: none;
border-top: 1px solid var(--ifm-color-emphasis-300);
padding: 0.2rem 0;
font-size: 15px;
}
.tocCollapsibleContent ul li {
margin: 0.4rem 0.8rem;
}
.tocCollapsibleContent a {
display: block;
}
.tocCollapsibleExpanded {
transform: none;
}

View File

@ -7,11 +7,11 @@
import React from 'react';
import clsx from 'clsx';
import Translate from '@docusaurus/Translate';
import {useCollapsible, Collapsible} from '@docusaurus/theme-common';
import styles from './styles.module.css';
import styles from './index.module.css';
import TOCItems from '@theme/TOCItems';
import type {Props} from '@theme/TOCCollapsible';
import CollapseButton from '@theme/TOCCollapsible/CollapseButton';
export default function TOCCollapsible({
toc,
@ -22,7 +22,6 @@ export default function TOCCollapsible({
const {collapsed, toggleCollapsed} = useCollapsible({
initialState: true,
});
return (
<div
className={clsx(
@ -30,17 +29,7 @@ export default function TOCCollapsible({
!collapsed && styles.tocCollapsibleExpanded,
className,
)}>
<button
type="button"
className={clsx('clean-btn', styles.tocCollapsibleButton)}
onClick={toggleCollapsed}>
<Translate
id="theme.TOCCollapsible.toggleButtonLabel"
description="The label used by the button on the collapsible TOC component">
On this page
</Translate>
</button>
<CollapseButton collapsed={collapsed} onClick={toggleCollapsed} />
<Collapsible
lazy
className={styles.tocCollapsibleContent}

View File

@ -0,0 +1,46 @@
/**
* 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 type {Props} from '@theme/TOCItems/Tree';
// Recursive component rendering the toc tree
/* eslint-disable jsx-a11y/control-has-associated-label */
function TOCItemTree({
toc,
className,
linkClassName,
isChild,
}: Props): JSX.Element | null {
if (!toc.length) {
return null;
}
return (
<ul className={isChild ? undefined : className}>
{toc.map((heading) => (
<li key={heading.id}>
<a
href={`#${heading.id}`}
className={linkClassName ?? undefined}
// Developer provided the HTML, so assume it's safe.
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{__html: heading.value}}
/>
<TOCItemTree
isChild
toc={heading.children}
className={className}
linkClassName={linkClassName}
/>
</li>
))}
</ul>
);
}
// Memo only the tree root is enough
export default React.memo(TOCItemTree);

View File

@ -7,53 +7,14 @@
import React, {useMemo} from 'react';
import type {Props} from '@theme/TOCItems';
import TOCItemTree from '@theme/TOCItems/Tree';
import {
type TOCHighlightConfig,
type TOCTreeNode,
useThemeConfig,
useTOCHighlight,
useFilteredAndTreeifiedTOC,
} from '@docusaurus/theme-common';
// Recursive component rendering the toc tree
/* eslint-disable jsx-a11y/control-has-associated-label */
function TOCItemList({
toc,
className,
linkClassName,
isChild,
}: {
readonly toc: readonly TOCTreeNode[];
readonly className: string;
readonly linkClassName: string | null;
readonly isChild?: boolean;
}): JSX.Element | null {
if (!toc.length) {
return null;
}
return (
<ul className={isChild ? undefined : className}>
{toc.map((heading) => (
<li key={heading.id}>
<a
href={`#${heading.id}`}
className={linkClassName ?? undefined}
// Developer provided the HTML, so assume it's safe.
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{__html: heading.value}}
/>
<TOCItemList
isChild
toc={heading.children}
className={className}
linkClassName={linkClassName}
/>
</li>
))}
</ul>
);
}
export default function TOCItems({
toc,
className = 'table-of-contents table-of-contents__left-border',
@ -90,7 +51,7 @@ export default function TOCItems({
useTOCHighlight(tocHighlightConfig);
return (
<TOCItemList
<TOCItemTree
toc={tocTree}
className={className}
linkClassName={linkClassName}