feat(theme-classic): usable CodeBlock outside markdown (#6216)

This commit is contained in:
Joshua Chen 2021-12-30 00:17:09 +08:00 committed by GitHub
parent 96dbb8e7ef
commit c45281a581
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 53 additions and 18 deletions

View file

@ -114,6 +114,7 @@ declare module '@theme/CodeBlock' {
readonly className?: string; readonly className?: string;
readonly metastring?: string; readonly metastring?: string;
readonly title?: string; readonly title?: string;
readonly language?: string;
} }
const CodeBlock: (props: Props) => JSX.Element; const CodeBlock: (props: Props) => JSX.Element;

View file

@ -24,9 +24,10 @@ import styles from './styles.module.css';
export default function CodeBlock({ export default function CodeBlock({
children, children,
className: blockClassName, className: blockClassName = '',
metastring, metastring,
title, title,
language: languageProp,
}: Props): JSX.Element { }: Props): JSX.Element {
const {prism} = useThemeConfig(); const {prism} = useThemeConfig();
@ -85,8 +86,7 @@ export default function CodeBlock({
: (children as string); : (children as string);
const language = const language =
parseLanguage(blockClassName) ?? languageProp ?? parseLanguage(blockClassName) ?? prism.defaultLanguage;
(prism.defaultLanguage as Language | undefined);
const {highlightLines, code} = parseLines(content, metastring, language); const {highlightLines, code} = parseLines(content, metastring, language);
const handleCopyCode = () => { const handleCopyCode = () => {
@ -102,12 +102,16 @@ export default function CodeBlock({
key={String(mounted)} key={String(mounted)}
theme={prismTheme} theme={prismTheme}
code={code} code={code}
language={language ?? ('text' as Language)}> language={(language ?? 'text') as Language}>
{({className, style, tokens, getLineProps, getTokenProps}) => ( {({className, style, tokens, getLineProps, getTokenProps}) => (
<div <div
className={clsx( className={clsx(
styles.codeBlockContainer, styles.codeBlockContainer,
blockClassName, blockClassName,
{
[`language-${language}`]:
language && !blockClassName.includes(`language-${language}`),
},
ThemeClassNames.common.codeBlock, ThemeClassNames.common.codeBlock,
)}> )}>
{codeBlockTitle && ( {codeBlockTitle && (

View file

@ -6,7 +6,6 @@
*/ */
import rangeParser from 'parse-numeric-range'; import rangeParser from 'parse-numeric-range';
import type {Language} from 'prism-react-renderer';
const codeBlockTitleRegex = /title=(["'])(.*?)\1/; const codeBlockTitleRegex = /title=(["'])(.*?)\1/;
const highlightLinesRangeRegex = /{([\d,-]+)}/; const highlightLinesRangeRegex = /{([\d,-]+)}/;
@ -93,11 +92,11 @@ export function parseCodeBlockTitle(metastring?: string): string {
return metastring?.match(codeBlockTitleRegex)?.[2] ?? ''; return metastring?.match(codeBlockTitleRegex)?.[2] ?? '';
} }
export function parseLanguage(className?: string): Language | undefined { export function parseLanguage(className: string): string | undefined {
const languageClassName = className const languageClassName = className
?.split(' ') .split(' ')
.find((str) => str.startsWith('language-')); .find((str) => str.startsWith('language-'));
return languageClassName?.replace(/language-/, '') as Language | undefined; return languageClassName?.replace(/language-/, '');
} }
/** /**
@ -107,7 +106,7 @@ export function parseLanguage(className?: string): Language | undefined {
export function parseLines( export function parseLines(
content: string, content: string,
metastring?: string, metastring?: string,
language?: Language, language?: string,
): { ): {
highlightLines: number[]; highlightLines: number[];
code: string; code: string;

View file

@ -6,6 +6,7 @@ slug: /markdown-features/code-blocks
--- ---
import BrowserWindow from '@site/src/components/BrowserWindow'; import BrowserWindow from '@site/src/components/BrowserWindow';
import CodeBlock from '@theme/CodeBlock';
Code blocks within documentation are super-powered 💪. Code blocks within documentation are super-powered 💪.
@ -391,7 +392,7 @@ function MyPlayground(props) {
</BrowserWindow> </BrowserWindow>
## Using JSX markup in code blocks ## Using JSX markup in code blocks {using-jsx-markup}
Code block in Markdown always preserves its content as plain text, meaning you can't do something like: Code block in Markdown always preserves its content as plain text, meaning you can't do something like:
@ -564,3 +565,39 @@ npm install @docusaurus/remark-plugin-npm2yarn
```` ````
Using the `{sync: true}` option would make all tab choices synced. Because the choice is stored under the same namespace `npm2yarn`, different `npm2yarn` plugin instances would also sync their choices. Using the `{sync: true}` option would make all tab choices synced. Because the choice is stored under the same namespace `npm2yarn`, different `npm2yarn` plugin instances would also sync their choices.
## Usage in JSX {#usage-in-jsx}
Outside of Markdown, you can use the `@theme/CodeBlock` component to get the same output.
```jsx
import CodeBlock from '@theme/CodeBlock';
export default function MyReactPage() {
return (
<div>
{/* highlight-start */}
<CodeBlock language="jsx" title="/src/components/HelloCodeTitle.js">
{`function HelloCodeTitle(props) {
return <h1>Hello, {props.name}</h1>;
}`}
</CodeBlock>
{/* highlight-end */}
</div>
);
}
```
<BrowserWindow>
<CodeBlock language="jsx" title="/src/components/HelloCodeTitle.js">
{`function HelloCodeTitle(props) {
return <h1>Hello, {props.name}</h1>;
}`}
</CodeBlock>
</BrowserWindow>
The props accepted are `language` and `title`, in the same way as you write Markdown code blocks.
Although discouraged, you can also pass in a `metastring` prop like `metastring='{1-2} title="/src/components/HelloCodeTitle.js"'`, which is how Markdown code blocks are handled under the hood. However, we recommend you [use comments for highlighting lines](#highlighting-with-comments).
As [previously stated](#using-jsx-markup), syntax highlighting is only applied when the children is a simple string.

View file

@ -116,17 +116,11 @@ import MyComponentSource from '!!raw-loader!@site/src/pages/examples/_myComponen
<br /> <br />
``` ```
You can also pass `title` prop to `CodeBlock` component in order for it to appear as header above your code block: See [using code blocks in JSX](./markdown-features-code-blocks.mdx#usage-in-jsx) for more details of the `<CodeBlock>` component.
```jsx
<CodeBlock className="language-jsx" title="/src/myComponent">
{MyComponentSource}
</CodeBlock>
```
:::note :::note
You have to use `<CodeBlock>` rather than the Markdown triple-backtick ` ``` `, because the latter will ship out any of its content as-is, but you want JSX to insert the imported text here. You have to use `<CodeBlock>` rather than the Markdown triple-backtick ` ``` `, because the latter will ship out any of its content as-is, but you want to interpolate the imported text here.
::: :::