mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-15 18:17:35 +02:00
feat(theme-classic): code block showLineNumbers (#7007)
This commit is contained in:
parent
4d9a0edf21
commit
ee4c984bc7
7 changed files with 168 additions and 11 deletions
|
@ -156,6 +156,7 @@ declare module '@theme/CodeBlock' {
|
||||||
readonly metastring?: string;
|
readonly metastring?: string;
|
||||||
readonly title?: string;
|
readonly title?: string;
|
||||||
readonly language?: string;
|
readonly language?: string;
|
||||||
|
readonly showLineNumbers?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CodeBlock(props: Props): JSX.Element;
|
export default function CodeBlock(props: Props): JSX.Element;
|
||||||
|
|
|
@ -13,6 +13,7 @@ import {
|
||||||
parseCodeBlockTitle,
|
parseCodeBlockTitle,
|
||||||
parseLanguage,
|
parseLanguage,
|
||||||
parseLines,
|
parseLines,
|
||||||
|
containsLineNumbers,
|
||||||
ThemeClassNames,
|
ThemeClassNames,
|
||||||
usePrismTheme,
|
usePrismTheme,
|
||||||
} from '@docusaurus/theme-common';
|
} from '@docusaurus/theme-common';
|
||||||
|
@ -26,6 +27,7 @@ export default function CodeBlock({
|
||||||
className: blockClassName = '',
|
className: blockClassName = '',
|
||||||
metastring,
|
metastring,
|
||||||
title,
|
title,
|
||||||
|
showLineNumbers,
|
||||||
language: languageProp,
|
language: languageProp,
|
||||||
}: Props): JSX.Element {
|
}: Props): JSX.Element {
|
||||||
const {prism} = useThemeConfig();
|
const {prism} = useThemeConfig();
|
||||||
|
@ -87,6 +89,8 @@ export default function CodeBlock({
|
||||||
const language =
|
const language =
|
||||||
languageProp ?? parseLanguage(blockClassName) ?? prism.defaultLanguage;
|
languageProp ?? parseLanguage(blockClassName) ?? prism.defaultLanguage;
|
||||||
const {highlightLines, code} = parseLines(content, metastring, language);
|
const {highlightLines, code} = parseLines(content, metastring, language);
|
||||||
|
const shouldShowLineNumbers =
|
||||||
|
showLineNumbers || containsLineNumbers(metastring);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Highlight
|
<Highlight
|
||||||
|
@ -116,24 +120,45 @@ export default function CodeBlock({
|
||||||
/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
|
/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
className={clsx(className, styles.codeBlock, 'thin-scrollbar')}>
|
className={clsx(className, styles.codeBlock, 'thin-scrollbar')}>
|
||||||
<code className={styles.codeBlockLines}>
|
<code
|
||||||
|
className={clsx(
|
||||||
|
styles.codeBlockLines,
|
||||||
|
shouldShowLineNumbers && styles.codeBlockLinesWithNumbering,
|
||||||
|
)}>
|
||||||
{tokens.map((line, i) => {
|
{tokens.map((line, i) => {
|
||||||
if (line.length === 1 && line[0]!.content === '\n') {
|
if (line.length === 1 && line[0]!.content === '\n') {
|
||||||
line[0]!.content = '';
|
line[0]!.content = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const lineProps = getLineProps({line, key: i});
|
const lineProps = getLineProps({
|
||||||
|
line,
|
||||||
|
key: i,
|
||||||
|
...(shouldShowLineNumbers && {className: styles.codeLine}),
|
||||||
|
});
|
||||||
|
|
||||||
if (highlightLines.includes(i)) {
|
if (highlightLines.includes(i)) {
|
||||||
lineProps.className += ' docusaurus-highlight-code-line';
|
lineProps.className += ' docusaurus-highlight-code-line';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const lineTokens = line.map((token, key) => (
|
||||||
|
<span key={key} {...getTokenProps({token, key})} />
|
||||||
|
));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span key={i} {...lineProps}>
|
<span key={i} {...lineProps}>
|
||||||
{line.map((token, key) => (
|
{shouldShowLineNumbers ? (
|
||||||
<span key={key} {...getTokenProps({token, key})} />
|
<>
|
||||||
))}
|
<span className={styles.codeLineNumber} />
|
||||||
<br />
|
<span className={styles.codeLineContent}>
|
||||||
|
{lineTokens}
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{lineTokens}
|
||||||
|
<br />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -28,9 +28,9 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.codeBlock {
|
.codeBlock {
|
||||||
|
--ifm-pre-background: inherit;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
background-color: inherit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.codeBlockTitle + .codeBlockContent .codeBlock {
|
.codeBlockTitle + .codeBlockContent .codeBlock {
|
||||||
|
@ -44,14 +44,48 @@
|
||||||
|
|
||||||
.codeBlockLines {
|
.codeBlockLines {
|
||||||
font: inherit;
|
font: inherit;
|
||||||
|
background: var(--ifm-pre-background);
|
||||||
/* rtl:ignore */
|
/* rtl:ignore */
|
||||||
float: left;
|
float: left;
|
||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
padding: var(--ifm-pre-padding);
|
padding: var(--ifm-pre-padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.codeBlockLinesWithNumbering {
|
||||||
|
display: table;
|
||||||
|
padding: var(--ifm-pre-padding) 0;
|
||||||
|
}
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
.codeBlockLines {
|
.codeBlockLines {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.codeLine {
|
||||||
|
display: table-row;
|
||||||
|
counter-increment: line-count;
|
||||||
|
}
|
||||||
|
|
||||||
|
.codeLineNumber {
|
||||||
|
display: table-cell;
|
||||||
|
text-align: right;
|
||||||
|
width: 1%;
|
||||||
|
position: sticky;
|
||||||
|
left: 0;
|
||||||
|
padding: 0 var(--ifm-pre-padding);
|
||||||
|
background: var(--ifm-pre-background);
|
||||||
|
}
|
||||||
|
|
||||||
|
.codeLineNumber::before {
|
||||||
|
content: counter(line-count);
|
||||||
|
opacity: 0.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.docusaurus-highlight-code-line) .codeLineNumber::before {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.codeLineContent {
|
||||||
|
padding-right: var(--ifm-pre-padding);
|
||||||
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@ export {
|
||||||
parseCodeBlockTitle,
|
parseCodeBlockTitle,
|
||||||
parseLanguage,
|
parseLanguage,
|
||||||
parseLines,
|
parseLines,
|
||||||
|
containsLineNumbers,
|
||||||
} from './utils/codeBlockUtils';
|
} from './utils/codeBlockUtils';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|
|
@ -77,6 +77,10 @@ export function parseCodeBlockTitle(metastring?: string): string {
|
||||||
return metastring?.match(codeBlockTitleRegex)?.groups!.title ?? '';
|
return metastring?.match(codeBlockTitleRegex)?.groups!.title ?? '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function containsLineNumbers(metastring?: string): boolean {
|
||||||
|
return metastring?.includes('showLineNumbers') || false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the language name from the class name (set by MDX).
|
* Gets the language name from the class name (set by MDX).
|
||||||
* e.g. `"language-javascript"` => `"javascript"`.
|
* e.g. `"language-javascript"` => `"javascript"`.
|
||||||
|
|
|
@ -142,3 +142,51 @@ Multi-line text inside `pre` will turn into one-liner, but it's okay (https://gi
|
||||||
</strong>cd", at which time b is a substring.
|
</strong>cd", at which time b is a substring.
|
||||||
<br />
|
<br />
|
||||||
</CodeBlock>
|
</CodeBlock>
|
||||||
|
|
||||||
|
## Code blocks with line numbering tests
|
||||||
|
|
||||||
|
```jsx
|
||||||
|
function PageLayout(props) {
|
||||||
|
// highlight-next-line
|
||||||
|
return <Layout title="Awesome Docusaurus page" description="Test Test Test Test Test Test Test Test Test Test Test Test Test Test ">;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```jsx showLineNumbers
|
||||||
|
function PageLayout(props) {
|
||||||
|
// highlight-next-line
|
||||||
|
return <Layout title="Awesome Docusaurus page" description="Test Test Test Test Test Test Test Test Test Test Test Test Test Test ">;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```jsx {1,3,6} showLineNumbers
|
||||||
|
function PageLayout(props) {
|
||||||
|
console.log(
|
||||||
|
'Test Test Test Test Test Test Test Test Test Test Test Test Test Test ',
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
'Test Test Test Test Test Test Test Test Test Test Test Test Test Test ',
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
'Test Test Test Test Test Test Test Test Test Test Test Test Test Test ',
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
'Test Test Test Test Test Test Test Test Test Test Test Test Test Test ',
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
'Test Test Test Test Test Test Test Test Test Test Test Test Test Test ',
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
'Test Test Test Test Test Test Test Test Test Test Test Test Test Test ',
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
'Test Test Test Test Test Test Test Test Test Test Test Test Test Test ',
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
'Test Test Test Test Test Test Test Test Test Test Test Test Test Test ',
|
||||||
|
);
|
||||||
|
console.log(
|
||||||
|
'Test Test Test Test Test Test Test Test Test Test Test Test Test Test ',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
@ -275,6 +275,44 @@ In the future, we may extend the magic comment system and let you define custom
|
||||||
|
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
## Line numbering {#line-numbering}
|
||||||
|
|
||||||
|
You can enable line numbering for your code block by using `showLineNumbers` key within the language meta string (don't forget to add space directly before the key).
|
||||||
|
|
||||||
|
````md
|
||||||
|
```jsx {1,4-6,11} showLineNumbers
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
function MyComponent(props) {
|
||||||
|
if (props.isBar) {
|
||||||
|
return <div>Bar</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div>Foo</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MyComponent;
|
||||||
|
```
|
||||||
|
````
|
||||||
|
|
||||||
|
<BrowserWindow>
|
||||||
|
|
||||||
|
```jsx {1,4-6,11} showLineNumbers
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
function MyComponent(props) {
|
||||||
|
if (props.isBar) {
|
||||||
|
return <div>Bar</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div>Foo</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MyComponent;
|
||||||
|
```
|
||||||
|
|
||||||
|
</BrowserWindow>
|
||||||
|
|
||||||
## Interactive code editor {#interactive-code-editor}
|
## Interactive code editor {#interactive-code-editor}
|
||||||
|
|
||||||
(Powered by [React Live](https://github.com/FormidableLabs/react-live))
|
(Powered by [React Live](https://github.com/FormidableLabs/react-live))
|
||||||
|
@ -596,7 +634,10 @@ export default function MyReactPage() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{/* highlight-start */}
|
{/* highlight-start */}
|
||||||
<CodeBlock language="jsx" title="/src/components/HelloCodeTitle.js">
|
<CodeBlock
|
||||||
|
language="jsx"
|
||||||
|
title="/src/components/HelloCodeTitle.js"
|
||||||
|
showLineNumbers>
|
||||||
{`function HelloCodeTitle(props) {
|
{`function HelloCodeTitle(props) {
|
||||||
return <h1>Hello, {props.name}</h1>;
|
return <h1>Hello, {props.name}</h1>;
|
||||||
}`}
|
}`}
|
||||||
|
@ -608,15 +649,18 @@ export default function MyReactPage() {
|
||||||
```
|
```
|
||||||
|
|
||||||
<BrowserWindow>
|
<BrowserWindow>
|
||||||
<CodeBlock language="jsx" title="/src/components/HelloCodeTitle.js">
|
<CodeBlock
|
||||||
|
language="jsx"
|
||||||
|
title="/src/components/HelloCodeTitle.js"
|
||||||
|
showLineNumbers>
|
||||||
{`function HelloCodeTitle(props) {
|
{`function HelloCodeTitle(props) {
|
||||||
return <h1>Hello, {props.name}</h1>;
|
return <h1>Hello, {props.name}</h1>;
|
||||||
}`}
|
}`}
|
||||||
</CodeBlock>
|
</CodeBlock>
|
||||||
</BrowserWindow>
|
</BrowserWindow>
|
||||||
|
|
||||||
The props accepted are `language` and `title`, in the same way as you write Markdown code blocks.
|
The props accepted are `language`, `title` and `showLineNumbers`, 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).
|
Although discouraged, you can also pass in a `metastring` prop like `metastring='{1-2} title="/src/components/HelloCodeTitle.js" showLineNumbers'`, 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.
|
As [previously stated](#using-jsx-markup), syntax highlighting is only applied when the children is a simple string.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue