diff --git a/packages/docusaurus-mdx-loader/src/index.js b/packages/docusaurus-mdx-loader/src/index.js index 64a666bbd1..5023a09e77 100644 --- a/packages/docusaurus-mdx-loader/src/index.js +++ b/packages/docusaurus-mdx-loader/src/index.js @@ -12,13 +12,13 @@ const emoji = require('remark-emoji'); const matter = require('gray-matter'); const stringifyObject = require('stringify-object'); const slug = require('./remark/slug'); -const rightToc = require('./remark/rightToc'); +const toc = require('./remark/toc'); const transformImage = require('./remark/transformImage'); const transformLinks = require('./remark/transformLinks'); const DEFAULT_OPTIONS = { rehypePlugins: [], - remarkPlugins: [emoji, slug, rightToc], + remarkPlugins: [emoji, slug, toc], }; module.exports = async function docusaurusMdxLoader(fileString) { diff --git a/packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/__snapshots__/index.test.js.snap b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.js.snap similarity index 95% rename from packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/__snapshots__/index.test.js.snap rename to packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.js.snap index bdc25c3df4..36725f1c98 100644 --- a/packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/__snapshots__/index.test.js.snap +++ b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/__snapshots__/index.test.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`inline code should be escaped 1`] = ` -"export const rightToc = [ +"export const toc = [ { value: '<Head />', id: 'head-', @@ -43,7 +43,7 @@ exports[`inline code should be escaped 1`] = ` `; exports[`non text phrasing content 1`] = ` -"export const rightToc = [ +"export const toc = [ { value: 'Emphasis', id: 'emphasis', diff --git a/packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/fixtures/empty-headings.md b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/fixtures/empty-headings.md similarity index 100% rename from packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/fixtures/empty-headings.md rename to packages/docusaurus-mdx-loader/src/remark/toc/__tests__/fixtures/empty-headings.md diff --git a/packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/fixtures/inline-code.md b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/fixtures/inline-code.md similarity index 100% rename from packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/fixtures/inline-code.md rename to packages/docusaurus-mdx-loader/src/remark/toc/__tests__/fixtures/inline-code.md diff --git a/packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/fixtures/insert-below-imports.md b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/fixtures/insert-below-imports.md similarity index 100% rename from packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/fixtures/insert-below-imports.md rename to packages/docusaurus-mdx-loader/src/remark/toc/__tests__/fixtures/insert-below-imports.md diff --git a/packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/fixtures/just-content.md b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/fixtures/just-content.md similarity index 100% rename from packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/fixtures/just-content.md rename to packages/docusaurus-mdx-loader/src/remark/toc/__tests__/fixtures/just-content.md diff --git a/packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/fixtures/name-exist.md b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/fixtures/name-exist.md similarity index 50% rename from packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/fixtures/name-exist.md rename to packages/docusaurus-mdx-loader/src/remark/toc/__tests__/fixtures/name-exist.md index 4304c8f3e4..86d9aac2fd 100644 --- a/packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/fixtures/name-exist.md +++ b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/fixtures/name-exist.md @@ -1,4 +1,4 @@ -export const rightToc = ['replaceMe']; +export const toc = ['replaceMe']; ## Thanos diff --git a/packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/fixtures/non-text-content.md b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/fixtures/non-text-content.md similarity index 100% rename from packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/fixtures/non-text-content.md rename to packages/docusaurus-mdx-loader/src/remark/toc/__tests__/fixtures/non-text-content.md diff --git a/packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/index.test.js b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/index.test.js similarity index 96% rename from packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/index.test.js rename to packages/docusaurus-mdx-loader/src/remark/toc/__tests__/index.test.js index c5931ff5bb..f55c0be063 100644 --- a/packages/docusaurus-mdx-loader/src/remark/rightToc/__tests__/index.test.js +++ b/packages/docusaurus-mdx-loader/src/remark/toc/__tests__/index.test.js @@ -37,7 +37,7 @@ test('inline code should be escaped', async () => { test('text content', async () => { const result = await processFixture('just-content'); expect(result).toMatchInlineSnapshot(` - "export const rightToc = [ + "export const toc = [ { value: 'Endi', id: 'endi', @@ -83,7 +83,7 @@ test('text content', async () => { test('should export even with existing name', async () => { const result = await processFixture('name-exist'); expect(result).toMatchInlineSnapshot(` - "export const rightToc = [ + "export const toc = [ { value: 'Thanos', id: 'thanos', @@ -167,7 +167,7 @@ test('should insert below imports', async () => { import somethingElse from 'something-else'; - export const rightToc = [ + export const toc = [ { value: 'Title', id: 'title', @@ -200,7 +200,7 @@ test('should insert below imports', async () => { test('empty headings', async () => { const result = await processFixture('empty-headings'); expect(result).toMatchInlineSnapshot(` - "export const rightToc = []; + "export const toc = []; # Ignore this diff --git a/packages/docusaurus-mdx-loader/src/remark/rightToc/index.js b/packages/docusaurus-mdx-loader/src/remark/toc/index.js similarity index 97% rename from packages/docusaurus-mdx-loader/src/remark/rightToc/index.js rename to packages/docusaurus-mdx-loader/src/remark/toc/index.js index a45f941e79..949a7467bc 100644 --- a/packages/docusaurus-mdx-loader/src/remark/rightToc/index.js +++ b/packages/docusaurus-mdx-loader/src/remark/toc/index.js @@ -59,7 +59,7 @@ const getOrCreateExistingTargetIndex = (children, name) => { }; const plugin = (options = {}) => { - const name = options.name || 'rightToc'; + const name = options.name || 'toc'; const transformer = (node) => { const headings = search(node); diff --git a/packages/docusaurus-mdx-loader/src/remark/rightToc/search.js b/packages/docusaurus-mdx-loader/src/remark/toc/search.js similarity index 95% rename from packages/docusaurus-mdx-loader/src/remark/rightToc/search.js rename to packages/docusaurus-mdx-loader/src/remark/toc/search.js index bafac24e8e..0821ec6d5f 100644 --- a/packages/docusaurus-mdx-loader/src/remark/rightToc/search.js +++ b/packages/docusaurus-mdx-loader/src/remark/toc/search.js @@ -11,7 +11,7 @@ const toString = require('mdast-util-to-string'); const visit = require('unist-util-visit'); const {toValue} = require('../utils'); -/** @typedef {import('@docusaurus/types').MarkdownRightTableOfContents} TOC */ +/** @typedef {import('@docusaurus/types').TOCItem} TOC */ /** @typedef {import('unist').Node} Node */ /** diff --git a/packages/docusaurus-plugin-content-blog/index.d.ts b/packages/docusaurus-plugin-content-blog/index.d.ts index ce5f0baf59..a8ff397af3 100644 --- a/packages/docusaurus-plugin-content-blog/index.d.ts +++ b/packages/docusaurus-plugin-content-blog/index.d.ts @@ -24,7 +24,7 @@ declare module '@theme/BlogSidebar' { } declare module '@theme/BlogPostPage' { - import type {MarkdownRightTableOfContents} from '@docusaurus/types'; + import type {TOCItem} from '@docusaurus/types'; import type {BlogSidebar} from '@theme/BlogSidebar'; export type FrontMatter = { @@ -61,7 +61,7 @@ declare module '@theme/BlogPostPage' { export type Content = { readonly frontMatter: FrontMatter; readonly metadata: Metadata; - readonly rightToc: readonly MarkdownRightTableOfContents[]; + readonly toc: readonly TOCItem[]; (): JSX.Element; }; diff --git a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts index 48073603cd..48e5726ddd 100644 --- a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts +++ b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts @@ -46,7 +46,7 @@ declare module '@docusaurus/plugin-content-docs-types' { } declare module '@theme/DocItem' { - import type {MarkdownRightTableOfContents} from '@docusaurus/types'; + import type {TOCItem} from '@docusaurus/types'; export type DocumentRoute = { readonly component: () => JSX.Element; @@ -80,7 +80,7 @@ declare module '@theme/DocItem' { readonly content: { readonly frontMatter: FrontMatter; readonly metadata: Metadata; - readonly rightToc: readonly MarkdownRightTableOfContents[]; + readonly toc: readonly TOCItem[]; (): JSX.Element; }; }; diff --git a/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts b/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts index 57ef441323..4bc3a58094 100644 --- a/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts +++ b/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts @@ -6,7 +6,7 @@ */ declare module '@theme/MDXPage' { - import type {MarkdownRightTableOfContents} from '@docusaurus/types'; + import type {TOCItem} from '@docusaurus/types'; export type Props = { readonly content: { @@ -17,7 +17,7 @@ declare module '@theme/MDXPage' { readonly hide_table_of_contents?: string; }; readonly metadata: {readonly permalink: string}; - readonly rightToc: readonly MarkdownRightTableOfContents[]; + readonly toc: readonly TOCItem[]; (): JSX.Element; }; }; diff --git a/packages/docusaurus-theme-bootstrap/src/theme/TOCInline/index.tsx b/packages/docusaurus-theme-bootstrap/src/theme/TOCInline/index.tsx new file mode 100644 index 0000000000..e231482602 --- /dev/null +++ b/packages/docusaurus-theme-bootstrap/src/theme/TOCInline/index.tsx @@ -0,0 +1,14 @@ +/** + * 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'; + +function TOCInline(_props: any): JSX.Element { + return
TODO bootstrap toc
; +} + +export default TOCInline; diff --git a/packages/docusaurus-theme-classic/package.json b/packages/docusaurus-theme-classic/package.json index 168a50f1d2..1afe1b5965 100644 --- a/packages/docusaurus-theme-classic/package.json +++ b/packages/docusaurus-theme-classic/package.json @@ -15,7 +15,7 @@ "license": "MIT", "scripts": { "build": "tsc --noEmit && yarn babel:lib && yarn babel:lib-next && yarn prettier", - "watch": "yarn babel:lib --watch", + "watch": "concurrently -n \"lib,lib-next\" --kill-others \"yarn babel:lib --watch\" \"yarn babel:lib-next --watch\"", "babel:lib": "cross-env BABEL_ENV=lib babel src -d lib --extensions \".tsx,.ts\" --ignore \"**/*.d.ts\" --copy-files", "babel:lib-next": "cross-env BABEL_ENV=lib-next babel src -d lib-next --extensions \".tsx,.ts\" --ignore \"**/*.d.ts\" --copy-files", "prettier": "prettier --config ../../.prettierrc --ignore-path ../../.prettierignore --write \"**/*.{js,ts}\"" diff --git a/packages/docusaurus-theme-classic/src/index.ts b/packages/docusaurus-theme-classic/src/index.ts index fcbd564972..6129cff1d7 100644 --- a/packages/docusaurus-theme-classic/src/index.ts +++ b/packages/docusaurus-theme-classic/src/index.ts @@ -72,6 +72,16 @@ export default function docusaurusThemeClassic( return { name: 'docusaurus-theme-classic', + /* + Does not seem needed: webpack can already hot reload theme files + getPathsToWatch() { + return [ + path.join(__dirname, '..', 'lib'), + path.join(__dirname, '..', 'lib-next'), + ]; + }, + */ + getThemePath() { return path.join(__dirname, '..', 'lib-next', 'theme'); }, diff --git a/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.tsx index 688334f5a0..3e1b030e3a 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.tsx @@ -53,9 +53,9 @@ function BlogPostPage(props: Props): JSX.Element { )} - {!hideTableOfContents && BlogPostContents.rightToc && ( + {!hideTableOfContents && BlogPostContents.toc && (
- +
)} diff --git a/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx index 9d351ecad2..9b4a243a07 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocItem/index.tsx @@ -162,9 +162,9 @@ function DocItem(props: Props): JSX.Element { - {!hideTableOfContents && DocContent.rightToc && ( + {!hideTableOfContents && DocContent.toc && (
- +
)} diff --git a/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx index 00dd4a7bf3..c0c9d4b94e 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx @@ -41,9 +41,9 @@ function MDXPage(props: Props): JSX.Element { - {!hideTableOfContents && MDXPageContent.rightToc && ( + {!hideTableOfContents && MDXPageContent.toc && (
- +
)} diff --git a/packages/docusaurus-theme-classic/src/theme/TOC/index.tsx b/packages/docusaurus-theme-classic/src/theme/TOC/index.tsx index 190f51ea59..831c26b10e 100644 --- a/packages/docusaurus-theme-classic/src/theme/TOC/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/TOC/index.tsx @@ -10,14 +10,21 @@ import clsx from 'clsx'; import useTOCHighlight from '@theme/hooks/useTOCHighlight'; import type {TOCProps} from '@theme/TOC'; import styles from './styles.module.css'; +import {TOCItem} from '@docusaurus/types'; const LINK_CLASS_NAME = 'table-of-contents__link'; const ACTIVE_LINK_CLASS_NAME = 'table-of-contents__link--active'; const TOP_OFFSET = 100; /* eslint-disable jsx-a11y/control-has-associated-label */ -function Headings({headings, isChild}: TOCProps & {isChild?: boolean}) { - if (!headings.length) { +function Headings({ + toc, + isChild, +}: { + toc: readonly TOCItem[]; + isChild?: boolean; +}) { + if (!toc.length) { return null; } return ( @@ -25,7 +32,7 @@ function Headings({headings, isChild}: TOCProps & {isChild?: boolean}) { className={ isChild ? '' : 'table-of-contents table-of-contents__left-border' }> - {headings.map((heading) => ( + {toc.map((heading) => (
  • - +
  • ))} ); } -function TOC({headings}: TOCProps): JSX.Element { +function TOC({toc}: TOCProps): JSX.Element { useTOCHighlight(LINK_CLASS_NAME, ACTIVE_LINK_CLASS_NAME, TOP_OFFSET); return (
    - +
    ); } diff --git a/packages/docusaurus-theme-classic/src/theme/TOCInline/index.tsx b/packages/docusaurus-theme-classic/src/theme/TOCInline/index.tsx new file mode 100644 index 0000000000..ea65e57da9 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/TOCInline/index.tsx @@ -0,0 +1,53 @@ +/** + * 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 type {TOCProps} from '@theme/TOC'; +import styles from './styles.module.css'; +import {TOCItem} from '@docusaurus/types'; + +const LINK_CLASS_NAME = styles['table-of-contents__link--inline']; + +/* eslint-disable jsx-a11y/control-has-associated-label */ +function HeadingsInline({ + toc, + isChild, +}: { + toc: readonly TOCItem[]; + isChild?: boolean; +}) { + if (!toc.length) { + return null; + } + return ( +
    + ); +} + +function TOCInline({toc}: TOCProps): JSX.Element { + return ( +
    + +
    + ); +} + +export default TOCInline; diff --git a/packages/docusaurus-theme-classic/src/theme/TOCInline/styles.module.css b/packages/docusaurus-theme-classic/src/theme/TOCInline/styles.module.css new file mode 100644 index 0000000000..edb23f5e5a --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/TOCInline/styles.module.css @@ -0,0 +1,14 @@ +/** + * 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. + */ + +.tableOfContentsInline ul { + list-style-type: disc; +} + +.table-of-contents__link--inline { + color: var(--ifm-toc-link-color); +} diff --git a/packages/docusaurus-theme-classic/src/types.d.ts b/packages/docusaurus-theme-classic/src/types.d.ts index e31330f9b6..c212069929 100644 --- a/packages/docusaurus-theme-classic/src/types.d.ts +++ b/packages/docusaurus-theme-classic/src/types.d.ts @@ -413,16 +413,27 @@ declare module '@theme/ThemeProvider' { } declare module '@theme/TOC' { - import type {MarkdownRightTableOfContents} from '@docusaurus/types'; + import type {TOCItem} from '@docusaurus/types'; export type TOCProps = { - readonly headings: readonly MarkdownRightTableOfContents[]; + readonly toc: readonly TOCItem[]; }; const TOC: (props: TOCProps) => JSX.Element; export default TOC; } +declare module '@theme/TOCInline' { + import type {TOCItem} from '@docusaurus/types'; + + export type TOCInlineProps = { + readonly toc: readonly TOCItem[]; + }; + + const TOCInline: (props: TOCInlineProps) => JSX.Element; + export default TOCInline; +} + declare module '@theme/Toggle' { import {ComponentProps} from 'react'; import ReactToggle from 'react-toggle'; diff --git a/packages/docusaurus-types/src/index.d.ts b/packages/docusaurus-types/src/index.d.ts index 8b24666380..4812739ffd 100644 --- a/packages/docusaurus-types/src/index.d.ts +++ b/packages/docusaurus-types/src/index.d.ts @@ -344,8 +344,8 @@ export interface ValidationSchema { append(data: any): ValidationSchema; } -export interface MarkdownRightTableOfContents { +export interface TOCItem { readonly value: string; readonly id: string; - readonly children: MarkdownRightTableOfContents[]; + readonly children: TOCItem[]; } diff --git a/website/docs/cli.md b/website/docs/cli.md index a65052ba34..2314ed7669 100644 --- a/website/docs/cli.md +++ b/website/docs/cli.md @@ -20,6 +20,12 @@ Once your website is bootstrapped, the website source will contain the Docusauru } ``` +## Index + +import TOCInline from "@theme/TOCInline" + + + ## Docusaurus CLI commands Below is a list of Docusaurus CLI commands and their usages: diff --git a/website/docs/markdown-features.mdx b/website/docs/markdown-features.mdx index 8cd59e9a11..ba218b5901 100644 --- a/website/docs/markdown-features.mdx +++ b/website/docs/markdown-features.mdx @@ -471,6 +471,61 @@ import TabItem from '@theme/TabItem'; This is a banana 🍌 +## Inline table of contents + +Each markdown document displays a tab of content on the top-right corner. + +But it is also possible to display an inline table of contents directly inside a markdown document, thanks to MDX. + +### Full table of contents + +The `toc` variable is available in any MDX document, and contain all the top level headings of a MDX document. + +```jsx +import TOCInline from '@theme/TOCInline'; + +; +``` + +import TOCInline from '@theme/TOCInline'; + + + + + + + +### Custom table of contents + +The `toc` props is just a list of table of contents items: + +```ts +type TOCItem = { + value: string; + id: string; + children: TOCItem[]; +}; +``` + +You can create this TOC tree manually, or derive a new TOC tree from the `toc` variable: + +```jsx +import TOCInline from '@theme/TOCInline'; + +; +``` + + + + + + + ## Callouts/admonitions In addition to the basic Markdown syntax, we use [remark-admonitions](https://github.com/elviswolcott/remark-admonitions) alongside MDX to add support for admonitions. Admonitions are wrapped by a set of 3 colons. diff --git a/website/docs/migration/migration-manual.md b/website/docs/migration/migration-manual.md index 1f486605fa..38924979c5 100644 --- a/website/docs/migration/migration-manual.md +++ b/website/docs/migration/migration-manual.md @@ -554,9 +554,9 @@ The following code could be helpful for migration of various pages: ## Content -### Remove AUTOGENERATED_TABLE_OF_CONTENTS +### Replace AUTOGENERATED_TABLE_OF_CONTENTS -This feature is deprecated. You may read more about it in [this issue](https://github.com/facebook/docusaurus/issues/1549). If you need the feature, use [remark-toc](https://github.com/remarkjs/remark-toc) instead and pass it to docs plugin's `remarkPlugins` option. +This feature is replaced by [inline table of content](../markdown-features.mdx#inline-table-of-contents) ### Update Markdown syntax to be MDX-compatible