mirror of
https://github.com/facebook/docusaurus.git
synced 2025-06-18 02:32:28 +02:00
feat(v2): allow specifying TOC max depth (themeConfig + frontMatter) (#5578)
* feat: add all TOC levels to MDX loader * feat: add theme-level config for heading depth * test: add remark MDX loader test * fix: limit maxDepth validation to H2 - H6 * refactor: set default `maxDepth` using `joi` * refactor: `maxDepth` -> `maxHeadingLevel * refactor: invert underlying TOC depth API * refactor: make TOC algorithm level-aware * feat: add support for per-doc TOC heading levels * feat: support document-level heading levels for blog * fix: correct validation for toc level frontmatter * fix: ensure TOC doesn't generate redundant DOM * perf: simpler TOC heading search alg * docs: document heading level props for `TOCInline` * Update website/docs/guides/markdown-features/markdown-features-inline-toc.mdx Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> * docs: fix docs (again) * create dedicated test file for heading searching logic: exhaustive tests will be simpler to write * toc search: add real-world test * fix test * add dogfooding tests for toc min/max * add test for min/max toc frontmatter * reverse min/max order * add theme minHeadingLevel + tests * simpler TOC rendering logic * simplify TOC implementation (temp, WIP) * reverse unnatural order for minHeadingLevel/maxHeadingLevel * add TOC dogfooding tests to all content plugins * expose toc min/max heading level frontmatter to all 3 content plugins * refactor blogLayout: accept toc ReactElement directly * move toc utils to theme-common * add tests for filterTOC * create new generic TOCItems component * useless css file copied * fix toc highlighting className conflicts * update doc * fix types Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Co-authored-by: slorber <lorber.sebastien@gmail.com>
This commit is contained in:
parent
caba1e4908
commit
c86dfbda61
50 changed files with 1522 additions and 214 deletions
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* 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, {useMemo} from 'react';
|
||||
import type {TOCItemsProps} from '@theme/TOCItems';
|
||||
import {TOCItem} from '@docusaurus/types';
|
||||
import {
|
||||
TOCHighlightConfig,
|
||||
useThemeConfig,
|
||||
useTOCFilter,
|
||||
useTOCHighlight,
|
||||
} from '@docusaurus/theme-common';
|
||||
|
||||
// Recursive component rendering the toc tree
|
||||
/* eslint-disable jsx-a11y/control-has-associated-label */
|
||||
function TOCItemList({
|
||||
toc,
|
||||
className = 'table-of-contents table-of-contents__left-border',
|
||||
linkClassName = 'table-of-contents__link',
|
||||
isChild,
|
||||
}: {
|
||||
readonly toc: readonly TOCItem[];
|
||||
readonly className: string;
|
||||
readonly linkClassName: string;
|
||||
readonly isChild?: boolean;
|
||||
}): JSX.Element | null {
|
||||
if (!toc.length) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<ul className={isChild ? '' : className}>
|
||||
{toc.map((heading) => (
|
||||
<li key={heading.id}>
|
||||
<a
|
||||
href={`#${heading.id}`}
|
||||
className={linkClassName}
|
||||
// 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',
|
||||
linkClassName = 'table-of-contents__link',
|
||||
linkActiveClassName = undefined,
|
||||
minHeadingLevel: minHeadingLevelOption,
|
||||
maxHeadingLevel: maxHeadingLevelOption,
|
||||
...props
|
||||
}: TOCItemsProps): JSX.Element | null {
|
||||
const themeConfig = useThemeConfig();
|
||||
|
||||
const minHeadingLevel =
|
||||
minHeadingLevelOption ?? themeConfig.tableOfContents.minHeadingLevel;
|
||||
const maxHeadingLevel =
|
||||
maxHeadingLevelOption ?? themeConfig.tableOfContents.maxHeadingLevel;
|
||||
|
||||
const tocFiltered = useTOCFilter({toc, minHeadingLevel, maxHeadingLevel});
|
||||
|
||||
const tocHighlightConfig: TOCHighlightConfig | undefined = useMemo(() => {
|
||||
if (linkClassName && linkActiveClassName) {
|
||||
return {
|
||||
linkClassName,
|
||||
linkActiveClassName,
|
||||
minHeadingLevel,
|
||||
maxHeadingLevel,
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}, [linkClassName, linkActiveClassName, minHeadingLevel, maxHeadingLevel]);
|
||||
useTOCHighlight(tocHighlightConfig);
|
||||
|
||||
return (
|
||||
<TOCItemList
|
||||
toc={tocFiltered}
|
||||
className={className}
|
||||
linkClassName={linkClassName}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue