diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx index bf64313b6f..bab753c075 100644 --- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import React, {useEffect, useState} from 'react'; +import React, {isValidElement, useEffect, useState} from 'react'; import clsx from 'clsx'; import Highlight, {defaultProps, Language} from 'prism-react-renderer'; import copy from 'copy-text-to-clipboard'; @@ -49,13 +49,44 @@ export default function CodeBlock({ const codeBlockTitle = parseCodeBlockTitle(metastring) || title; const prismTheme = usePrismTheme(); - // In case interleaved Markdown (e.g. when using CodeBlock as standalone component). + //
tags in markdown map to CodeBlocks and they may contain JSX children.
+ // When the children is not a simple string, we just return a styled block without actually highlighting.
+ if (React.Children.toArray(children).some((el) => isValidElement(el))) {
+ return (
+
+ {({className, style}) => (
+
+ {children}
+
+ )}
+
+ );
+ }
+
+ // The children is now guaranteed to be one/more plain strings
const content = Array.isArray(children)
? children.join('')
: (children as string);
const language =
- parseLanguage(blockClassName) ?? (prism.defaultLanguage as Language);
+ parseLanguage(blockClassName) ??
+ (prism.defaultLanguage as Language | undefined);
const {highlightLines, code} = parseLines(content, metastring, language);
const handleCopyCode = () => {
@@ -71,7 +102,7 @@ export default function CodeBlock({
key={String(mounted)}
theme={prismTheme}
code={code}
- language={language}>
+ language={language ?? ('text' as Language)}>
{({className, style, tokens, getLineProps, getTokenProps}) => (
{unwrappedChildren};
},
code: (props) => {
- const {children} = props;
-
- // For retrocompatibility purposes (pretty rare use case)
- // See https://github.com/facebook/docusaurus/pull/1584
- if (isValidElement(children)) {
- return children;
- }
-
- return !children.includes('\n') ? (
-
- ) : (
-
+ const shouldBeInline = React.Children.toArray(props.children).every(
+ (el) => typeof el === 'string' && !el.includes('\n'),
);
+
+ return shouldBeInline ? : ;
},
a: (props) => ,
- pre: (props) => {
- const {children} = props;
-
- // See comment for `code` above
- if (isValidElement(children) && isValidElement(children?.props?.children)) {
- return children.props.children;
- }
-
- return (
-
- );
- },
+ pre: (props) => (
+
+ ),
details: (props): JSX.Element => {
const items = React.Children.toArray(props.children) as ReactElement[];
- // Split summary item from the rest to pass it as a separate prop to the Detais theme component
+ // Split summary item from the rest to pass it as a separate prop to the Details theme component
const summary: ReactElement> = items.find(
(item) => item?.props?.mdxType === 'summary',
)!;
diff --git a/website/_dogfooding/_pages tests/code-block-tests.mdx b/website/_dogfooding/_pages tests/code-block-tests.mdx
new file mode 100644
index 0000000000..a7219bf529
--- /dev/null
+++ b/website/_dogfooding/_pages tests/code-block-tests.mdx
@@ -0,0 +1,136 @@
+import CodeBlock from '@theme/CodeBlock';
+import BrowserWindow from '@site/src/components/BrowserWindow';
+
+# Code block tests
+
+See:
+
+- https://github.com/facebook/docusaurus/pull/1584
+- https://github.com/facebook/docusaurus/pull/3749
+- https://github.com/facebook/docusaurus/pull/6177
+
+## `pre`
+
+### `pre > string`
+
+Multi-line text inside `pre` will turn into one-liner, but it's okay (https://github.com/mdx-js/mdx/issues/1095)
+
+1 2 3
+
+
+
+1
+2
+3
+
+
+### `pre > string[]`
+
+
+ 1{'\n'}2{'\n'}3{'\n'}
+
+
+### `pre > element`
+
+
+ Lol bro
+
+
+### `pre > element[]`
+
+
+ Front page
+ {'\n'}
+ Input: a = "abcd", b = "cdabcdab"{'\n'}
+ Output: 3{'\n'}
+ Explanation: a after three repetitions become "ab
+ cdabcdabcd", at which time b is a substring.{'\n'}
+
+
+### `pre > code > element`
+
+
+
+ Hey bro
+
+
+
+## `code`
+
+### `code > string`
+
+1 2 3
+
+
+ {`link:
+ title: front page
+ path: /docs/`}
+
+
+### `code > string[]`
+
+
+ link:{' \n'}
+ {' '}title: front page{'\n'}
+ {' '}path: /docs/{'\n'}
+
+
+### `code > element`
+
+
+ Lol bro
+
+
+### `code > element[]`
+
+
+ Front page
+
+ Input: a = "abcd", b = "cdabcdab"
+
+ Output: 3
+ Explanation: a after three repetitions become "ab
+ cdabcdab
+ cd", at which time b is a substring.
+
+
+
+## `CodeBlock`
+
+### `CodeBlock > string`
+
+1 2 3
+
+
+ {`link:
+ title: front page
+ path: /docs/`}
+
+
+### `CodeBlock > string[]`
+
+
+ link:{'\n'}
+ {' '}title: front page{'\n'}
+ {' '}path: /docs/{'\n'}
+
+
+### `CodeBlock > element`
+
+
+ Lol bro
+
+
+### `CodeBlock > element[]`
+
+
+ Front page
+
+ Input: a = "abcd", b = "cdabcdab"
+
+ Output: 3
+ Explanation: a after three repetitions become "ab
+ cdabcdab
+ cd", at which time b is a substring.
+
+
diff --git a/website/_dogfooding/_pages tests/markdownPageTests.md b/website/_dogfooding/_pages tests/markdownPageTests.md
index 6b1e256edf..3db7deb697 100644
--- a/website/_dogfooding/_pages tests/markdownPageTests.md
+++ b/website/_dogfooding/_pages tests/markdownPageTests.md
@@ -160,41 +160,8 @@ function Clock(props) {
}
```
-
- test
-
-
-test
-
-## direct using of `pre`
-
-test
-
-
-
-1
-2
-3
-
-
## Custom heading id {#custom}
-## Children elements inside pre/code elements
-
-See https://github.com/facebook/docusaurus/pull/1584
-
-
-
- Lol bro
-
-
-
-
-
- Lol bro
-
-
-
## Pipe
Code tag + double pipe: ||
diff --git a/website/docs/guides/markdown-features/markdown-features-code-blocks.mdx b/website/docs/guides/markdown-features/markdown-features-code-blocks.mdx
index 5c355f1e46..7eb0cd4ca1 100644
--- a/website/docs/guides/markdown-features/markdown-features-code-blocks.mdx
+++ b/website/docs/guides/markdown-features/markdown-features-code-blocks.mdx
@@ -362,6 +362,48 @@ function MyPlayground(props) {
}
```
+## Using JSX markup in code blocks
+
+Code blocks in Markdown always preserves its content as plain text, meaning you can't do something like:
+
+```ts
+type EditUrlFunction = (params: {
+ version: string;
+ // This doesn't turn into a link (for good reason!)
+ // See doc versioning
+ versionDocsDirPath: string;
+ docPath: string;
+ permalink: string;
+ locale: string;
+}) => string | undefined;
+```
+
+If you want to embed HTML markup such as anchor links or bold type, you can use the `` tag, `` tag, or `` component.
+
+```jsx
+
+ Input: 1 2 3 4{'\n'}
+ Output: "366300745"{'\n'}
+
+```
+
+
+ Input: 1 2 3 4{'\n'}
+ Output: "366300745"{'\n'}
+
+
+:::caution MDX is whitespace insensitive
+
+MDX is in line with JSX behavior: line break characters, even when inside ``, are turned into spaces. You have to explicitly write the new line character for it to be printed out.
+
+:::
+
+:::caution
+
+Syntax highlighting only works on plain strings. Docusaurus will not attempt to parse code block content containing JSX children.
+
+:::
+
## Multi-language support code blocks {#multi-language-support-code-blocks}
With MDX, you can easily create interactive components within your documentation, for example, to display code in multiple programming languages and switching between them using a tabs component.