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 title?: string;
|
||||
readonly language?: string;
|
||||
readonly showLineNumbers?: boolean;
|
||||
}
|
||||
|
||||
export default function CodeBlock(props: Props): JSX.Element;
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
parseCodeBlockTitle,
|
||||
parseLanguage,
|
||||
parseLines,
|
||||
containsLineNumbers,
|
||||
ThemeClassNames,
|
||||
usePrismTheme,
|
||||
} from '@docusaurus/theme-common';
|
||||
|
@ -26,6 +27,7 @@ export default function CodeBlock({
|
|||
className: blockClassName = '',
|
||||
metastring,
|
||||
title,
|
||||
showLineNumbers,
|
||||
language: languageProp,
|
||||
}: Props): JSX.Element {
|
||||
const {prism} = useThemeConfig();
|
||||
|
@ -87,6 +89,8 @@ export default function CodeBlock({
|
|||
const language =
|
||||
languageProp ?? parseLanguage(blockClassName) ?? prism.defaultLanguage;
|
||||
const {highlightLines, code} = parseLines(content, metastring, language);
|
||||
const shouldShowLineNumbers =
|
||||
showLineNumbers || containsLineNumbers(metastring);
|
||||
|
||||
return (
|
||||
<Highlight
|
||||
|
@ -116,24 +120,45 @@ export default function CodeBlock({
|
|||
/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
|
||||
tabIndex={0}
|
||||
className={clsx(className, styles.codeBlock, 'thin-scrollbar')}>
|
||||
<code className={styles.codeBlockLines}>
|
||||
<code
|
||||
className={clsx(
|
||||
styles.codeBlockLines,
|
||||
shouldShowLineNumbers && styles.codeBlockLinesWithNumbering,
|
||||
)}>
|
||||
{tokens.map((line, i) => {
|
||||
if (line.length === 1 && line[0]!.content === '\n') {
|
||||
line[0]!.content = '';
|
||||
}
|
||||
|
||||
const lineProps = getLineProps({line, key: i});
|
||||
const lineProps = getLineProps({
|
||||
line,
|
||||
key: i,
|
||||
...(shouldShowLineNumbers && {className: styles.codeLine}),
|
||||
});
|
||||
|
||||
if (highlightLines.includes(i)) {
|
||||
lineProps.className += ' docusaurus-highlight-code-line';
|
||||
}
|
||||
|
||||
const lineTokens = line.map((token, key) => (
|
||||
<span key={key} {...getTokenProps({token, key})} />
|
||||
));
|
||||
|
||||
return (
|
||||
<span key={i} {...lineProps}>
|
||||
{line.map((token, key) => (
|
||||
<span key={key} {...getTokenProps({token, key})} />
|
||||
))}
|
||||
{shouldShowLineNumbers ? (
|
||||
<>
|
||||
<span className={styles.codeLineNumber} />
|
||||
<span className={styles.codeLineContent}>
|
||||
{lineTokens}
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{lineTokens}
|
||||
<br />
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
|
|
|
@ -28,9 +28,9 @@
|
|||
}
|
||||
|
||||
.codeBlock {
|
||||
--ifm-pre-background: inherit;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
.codeBlockTitle + .codeBlockContent .codeBlock {
|
||||
|
@ -44,14 +44,48 @@
|
|||
|
||||
.codeBlockLines {
|
||||
font: inherit;
|
||||
background: var(--ifm-pre-background);
|
||||
/* rtl:ignore */
|
||||
float: left;
|
||||
min-width: 100%;
|
||||
padding: var(--ifm-pre-padding);
|
||||
}
|
||||
|
||||
.codeBlockLinesWithNumbering {
|
||||
display: table;
|
||||
padding: var(--ifm-pre-padding) 0;
|
||||
}
|
||||
|
||||
@media print {
|
||||
.codeBlockLines {
|
||||
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,
|
||||
parseLanguage,
|
||||
parseLines,
|
||||
containsLineNumbers,
|
||||
} from './utils/codeBlockUtils';
|
||||
|
||||
export {
|
||||
|
|
|
@ -77,6 +77,10 @@ export function parseCodeBlockTitle(metastring?: string): string {
|
|||
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).
|
||||
* 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.
|
||||
<br />
|
||||
</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}
|
||||
|
||||
(Powered by [React Live](https://github.com/FormidableLabs/react-live))
|
||||
|
@ -596,7 +634,10 @@ export default function MyReactPage() {
|
|||
return (
|
||||
<div>
|
||||
{/* highlight-start */}
|
||||
<CodeBlock language="jsx" title="/src/components/HelloCodeTitle.js">
|
||||
<CodeBlock
|
||||
language="jsx"
|
||||
title="/src/components/HelloCodeTitle.js"
|
||||
showLineNumbers>
|
||||
{`function HelloCodeTitle(props) {
|
||||
return <h1>Hello, {props.name}</h1>;
|
||||
}`}
|
||||
|
@ -608,15 +649,18 @@ export default function MyReactPage() {
|
|||
```
|
||||
|
||||
<BrowserWindow>
|
||||
<CodeBlock language="jsx" title="/src/components/HelloCodeTitle.js">
|
||||
<CodeBlock
|
||||
language="jsx"
|
||||
title="/src/components/HelloCodeTitle.js"
|
||||
showLineNumbers>
|
||||
{`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.
|
||||
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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue