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.