Skip to content

Commit

Permalink
refactor(theme-classic): refactor TOC-related theme components (#7270)
Browse files Browse the repository at this point in the history
* extract TOCItemTree component

* refactor TOCCollapsible
  • Loading branch information
slorber authored Apr 29, 2022
1 parent 3bef882 commit e053f39
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 77 deletions.
25 changes: 25 additions & 0 deletions packages/docusaurus-theme-classic/src/theme-classic.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
Original file line number Diff line number Diff line change
@@ -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>
);
}
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -22,25 +22,14 @@ export default function TOCCollapsible({
const {collapsed, toggleCollapsed} = useCollapsible({
initialState: true,
});

return (
<div
className={clsx(
styles.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}
Expand Down
46 changes: 46 additions & 0 deletions packages/docusaurus-theme-classic/src/theme/TOCItems/Tree.tsx
Original file line number Diff line number Diff line change
@@ -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);
43 changes: 2 additions & 41 deletions packages/docusaurus-theme-classic/src/theme/TOCItems/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -90,7 +51,7 @@ export default function TOCItems({
useTOCHighlight(tocHighlightConfig);

return (
<TOCItemList
<TOCItemTree
toc={tocTree}
className={className}
linkClassName={linkClassName}
Expand Down

0 comments on commit e053f39

Please sign in to comment.