mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-16 18:46:57 +02:00
refactor(theme-classic): split CodeBlock (#7175)
* extract CodeBlockLine * stable refactor * stable refactor * stable refactor * add CodeBlockContainer * refactor * refactor * do the actual split Co-authored-by: Joshua Chen <sidachen2003@gmail.com>
This commit is contained in:
parent
0f5f6f31e0
commit
5273a534d3
10 changed files with 341 additions and 201 deletions
|
@ -148,10 +148,10 @@ declare module '@theme/BlogLayout' {
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module '@theme/CodeBlock' {
|
declare module '@theme/CodeBlock' {
|
||||||
import type {ReactElement} from 'react';
|
import type {ReactNode} from 'react';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
readonly children: string | ReactElement;
|
readonly children: ReactNode;
|
||||||
readonly className?: string;
|
readonly className?: string;
|
||||||
readonly metastring?: string;
|
readonly metastring?: string;
|
||||||
readonly title?: string;
|
readonly title?: string;
|
||||||
|
@ -170,6 +170,56 @@ declare module '@theme/CodeBlock/CopyButton' {
|
||||||
export default function CopyButton(props: Props): JSX.Element;
|
export default function CopyButton(props: Props): JSX.Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare module '@theme/CodeBlock/Container' {
|
||||||
|
import type {ComponentProps} from 'react';
|
||||||
|
|
||||||
|
export default function CodeBlockContainer<T extends 'div' | 'pre'>({
|
||||||
|
as: As,
|
||||||
|
...props
|
||||||
|
}: {as: T} & ComponentProps<T>): JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '@theme/CodeBlock/Content/Element' {
|
||||||
|
import type {Props} from '@theme/CodeBlock';
|
||||||
|
|
||||||
|
export type {Props};
|
||||||
|
|
||||||
|
export default function CodeBlockElementContent(props: Props): JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '@theme/CodeBlock/Content/String' {
|
||||||
|
import type {Props as CodeBlockProps} from '@theme/CodeBlock';
|
||||||
|
|
||||||
|
export interface Props extends Omit<CodeBlockProps, 'children'> {
|
||||||
|
readonly children: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function CodeBlockStringContent(props: Props): JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '@theme/CodeBlock/Line' {
|
||||||
|
import type {ComponentProps} from 'react';
|
||||||
|
import type Highlight from 'prism-react-renderer';
|
||||||
|
|
||||||
|
// Lib does not make this easy
|
||||||
|
type RenderProps = Parameters<
|
||||||
|
ComponentProps<typeof Highlight>['children']
|
||||||
|
>[0];
|
||||||
|
type GetLineProps = RenderProps['getLineProps'];
|
||||||
|
type GetTokenProps = RenderProps['getTokenProps'];
|
||||||
|
type Token = RenderProps['tokens'][number][number];
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
readonly line: Token[];
|
||||||
|
readonly highlight: boolean;
|
||||||
|
readonly showLineNumbers: boolean;
|
||||||
|
readonly getLineProps: GetLineProps;
|
||||||
|
readonly getTokenProps: GetTokenProps;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function CodeBlockLine(props: Props): JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
declare module '@theme/DocCard' {
|
declare module '@theme/DocCard' {
|
||||||
import type {PropSidebarItem} from '@docusaurus/plugin-content-docs';
|
import type {PropSidebarItem} from '@docusaurus/plugin-content-docs';
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, {type ComponentProps} from 'react';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import {
|
||||||
|
usePrismTheme,
|
||||||
|
getPrismCssVariables,
|
||||||
|
ThemeClassNames,
|
||||||
|
} from '@docusaurus/theme-common';
|
||||||
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
|
export default function CodeBlockContainer<T extends 'div' | 'pre'>({
|
||||||
|
as: As,
|
||||||
|
...props
|
||||||
|
}: {as: T} & ComponentProps<T>): JSX.Element {
|
||||||
|
const prismTheme = usePrismTheme();
|
||||||
|
const prismCssVariables = getPrismCssVariables(prismTheme);
|
||||||
|
return (
|
||||||
|
<As
|
||||||
|
// Polymorphic components are hard to type, without `oneOf` generics
|
||||||
|
{...(props as never)}
|
||||||
|
style={prismCssVariables}
|
||||||
|
className={clsx(
|
||||||
|
props.className,
|
||||||
|
styles.codeBlockContainer,
|
||||||
|
ThemeClassNames.common.codeBlock,
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.codeBlockContainer {
|
||||||
|
background: var(--prism-background-color);
|
||||||
|
color: var(--prism-color);
|
||||||
|
margin-bottom: var(--ifm-leading);
|
||||||
|
box-shadow: var(--ifm-global-shadow-lw);
|
||||||
|
border-radius: var(--ifm-code-border-radius);
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import Container from '@theme/CodeBlock/Container';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import type {Props} from '@theme/CodeBlock/Content/Element';
|
||||||
|
|
||||||
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
|
// <pre> tags in markdown map to CodeBlocks. They may contain JSX children. When
|
||||||
|
// the children is not a simple string, we just return a styled block without
|
||||||
|
// actually highlighting.
|
||||||
|
export default function CodeBlockJSX({
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
}: Props): JSX.Element {
|
||||||
|
return (
|
||||||
|
<Container
|
||||||
|
as="pre"
|
||||||
|
tabIndex={0}
|
||||||
|
className={clsx(styles.codeBlockStandalone, 'thin-scrollbar', className)}>
|
||||||
|
<code className={styles.codeBlockLines}>{children}</code>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
useThemeConfig,
|
||||||
|
parseCodeBlockTitle,
|
||||||
|
parseLanguage,
|
||||||
|
parseLines,
|
||||||
|
containsLineNumbers,
|
||||||
|
usePrismTheme,
|
||||||
|
} from '@docusaurus/theme-common';
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import Highlight, {defaultProps, type Language} from 'prism-react-renderer';
|
||||||
|
import Line from '@theme/CodeBlock/Line';
|
||||||
|
import CopyButton from '@theme/CodeBlock/CopyButton';
|
||||||
|
import Container from '@theme/CodeBlock/Container';
|
||||||
|
import type {Props} from '@theme/CodeBlock/Content/String';
|
||||||
|
|
||||||
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
|
export default function CodeBlockString({
|
||||||
|
children,
|
||||||
|
className: blockClassName = '',
|
||||||
|
metastring,
|
||||||
|
title: titleProp,
|
||||||
|
showLineNumbers: showLineNumbersProp,
|
||||||
|
language: languageProp,
|
||||||
|
}: Props): JSX.Element {
|
||||||
|
const {
|
||||||
|
prism: {defaultLanguage},
|
||||||
|
} = useThemeConfig();
|
||||||
|
const language =
|
||||||
|
languageProp ?? parseLanguage(blockClassName) ?? defaultLanguage;
|
||||||
|
const prismTheme = usePrismTheme();
|
||||||
|
|
||||||
|
// We still parse the metastring in case we want to support more syntax in the
|
||||||
|
// future. Note that MDX doesn't strip quotes when parsing metastring:
|
||||||
|
// "title=\"xyz\"" => title: "\"xyz\""
|
||||||
|
const title = parseCodeBlockTitle(metastring) || titleProp;
|
||||||
|
|
||||||
|
const {highlightLines, code} = parseLines(children, metastring, language);
|
||||||
|
const showLineNumbers =
|
||||||
|
showLineNumbersProp || containsLineNumbers(metastring);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container
|
||||||
|
as="div"
|
||||||
|
className={clsx(
|
||||||
|
blockClassName,
|
||||||
|
language &&
|
||||||
|
!blockClassName.includes(`language-${language}`) &&
|
||||||
|
`language-${language}`,
|
||||||
|
)}>
|
||||||
|
{title && <div className={styles.codeBlockTitle}>{title}</div>}
|
||||||
|
<div className={styles.codeBlockContent}>
|
||||||
|
<Highlight
|
||||||
|
{...defaultProps}
|
||||||
|
theme={prismTheme}
|
||||||
|
code={code}
|
||||||
|
language={(language ?? 'text') as Language}>
|
||||||
|
{({className, tokens, getLineProps, getTokenProps}) => (
|
||||||
|
<pre
|
||||||
|
/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
|
||||||
|
tabIndex={0}
|
||||||
|
className={clsx(className, styles.codeBlock, 'thin-scrollbar')}>
|
||||||
|
<code
|
||||||
|
className={clsx(
|
||||||
|
styles.codeBlockLines,
|
||||||
|
showLineNumbers && styles.codeBlockLinesWithNumbering,
|
||||||
|
)}>
|
||||||
|
{tokens.map((line, i) => (
|
||||||
|
<Line
|
||||||
|
key={i}
|
||||||
|
line={line}
|
||||||
|
getLineProps={getLineProps}
|
||||||
|
getTokenProps={getTokenProps}
|
||||||
|
highlight={highlightLines.includes(i)}
|
||||||
|
showLineNumbers={showLineNumbers}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
)}
|
||||||
|
</Highlight>
|
||||||
|
<CopyButton code={code} />
|
||||||
|
</div>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
|
@ -5,14 +5,6 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.codeBlockContainer {
|
|
||||||
background: var(--prism-background-color);
|
|
||||||
color: var(--prism-color);
|
|
||||||
margin-bottom: var(--ifm-leading);
|
|
||||||
box-shadow: var(--ifm-global-shadow-lw);
|
|
||||||
border-radius: var(--ifm-code-border-radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
.codeBlockContent {
|
.codeBlockContent {
|
||||||
position: relative;
|
position: relative;
|
||||||
/* rtl:ignore */
|
/* rtl:ignore */
|
||||||
|
@ -62,31 +54,3 @@
|
||||||
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);
|
|
||||||
}
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import type {Props} from '@theme/CodeBlock/Line';
|
||||||
|
import styles from './styles.module.css';
|
||||||
|
|
||||||
|
export default function CodeBlockLine({
|
||||||
|
line,
|
||||||
|
highlight,
|
||||||
|
showLineNumbers,
|
||||||
|
getLineProps,
|
||||||
|
getTokenProps,
|
||||||
|
}: Props): JSX.Element {
|
||||||
|
if (line.length === 1 && line[0]!.content === '\n') {
|
||||||
|
line[0]!.content = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const lineProps = getLineProps({
|
||||||
|
line,
|
||||||
|
...(showLineNumbers && {className: styles.codeLine}),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (highlight) {
|
||||||
|
lineProps.className += ' docusaurus-highlight-code-line';
|
||||||
|
}
|
||||||
|
|
||||||
|
const lineTokens = line.map((token, key) => (
|
||||||
|
<span key={key} {...getTokenProps({token, key})} />
|
||||||
|
));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span {...lineProps}>
|
||||||
|
{showLineNumbers ? (
|
||||||
|
<>
|
||||||
|
<span className={styles.codeLineNumber} />
|
||||||
|
<span className={styles.codeLineContent}>{lineTokens}</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{lineTokens}
|
||||||
|
<br />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.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);
|
||||||
|
}
|
|
@ -5,172 +5,41 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {isValidElement, useEffect, useState} from 'react';
|
import React, {isValidElement, type ReactNode} from 'react';
|
||||||
import clsx from 'clsx';
|
import useIsBrowser from '@docusaurus/useIsBrowser';
|
||||||
import Highlight, {defaultProps, type Language} from 'prism-react-renderer';
|
|
||||||
import {
|
|
||||||
useThemeConfig,
|
|
||||||
parseCodeBlockTitle,
|
|
||||||
parseLanguage,
|
|
||||||
parseLines,
|
|
||||||
containsLineNumbers,
|
|
||||||
ThemeClassNames,
|
|
||||||
usePrismTheme,
|
|
||||||
getPrismCssVariables,
|
|
||||||
} from '@docusaurus/theme-common';
|
|
||||||
import CopyButton from '@theme/CodeBlock/CopyButton';
|
|
||||||
import type {Props} from '@theme/CodeBlock';
|
import type {Props} from '@theme/CodeBlock';
|
||||||
|
import ElementContent from '@theme/CodeBlock/Content/Element';
|
||||||
|
import StringContent from '@theme/CodeBlock/Content/String';
|
||||||
|
|
||||||
import styles from './styles.module.css';
|
/**
|
||||||
|
* Best attempt to make the children a plain string so it is copyable. If there
|
||||||
|
* are react elements, we will not be able to copy the content, and it will
|
||||||
|
* return `children` as-is; otherwise, it concatenates the string children
|
||||||
|
* together.
|
||||||
|
*/
|
||||||
|
function maybeStringifyChildren(children: ReactNode): ReactNode {
|
||||||
|
if (React.Children.toArray(children).some((el) => isValidElement(el))) {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
// The children is now guaranteed to be one/more plain strings
|
||||||
|
return Array.isArray(children) ? children.join('') : (children as string);
|
||||||
|
}
|
||||||
|
|
||||||
export default function CodeBlock({
|
export default function CodeBlock({
|
||||||
children,
|
children: rawChildren,
|
||||||
className: blockClassName = '',
|
...props
|
||||||
metastring,
|
|
||||||
title,
|
|
||||||
showLineNumbers,
|
|
||||||
language: languageProp,
|
|
||||||
}: Props): JSX.Element {
|
}: Props): JSX.Element {
|
||||||
const {prism} = useThemeConfig();
|
// The Prism theme on SSR is always the default theme but the site theme can
|
||||||
|
// be in a different mode. React hydration doesn't update DOM styles that come
|
||||||
const [mounted, setMounted] = useState(false);
|
// from SSR. Hence force a re-render after mounting to apply the current
|
||||||
// The Prism theme on SSR is always the default theme but the site theme
|
// relevant styles.
|
||||||
// can be in a different mode. React hydration doesn't update DOM styles
|
const isBrowser = useIsBrowser();
|
||||||
// that come from SSR. Hence force a re-render after mounting to apply the
|
const children = maybeStringifyChildren(rawChildren);
|
||||||
// current relevant styles. There will be a flash seen of the original
|
const CodeBlockComp =
|
||||||
// styles seen using this current approach but that's probably ok. Fixing
|
typeof children === 'string' ? StringContent : ElementContent;
|
||||||
// the flash will require changing the theming approach and is not worth it
|
|
||||||
// at this point.
|
|
||||||
useEffect(() => {
|
|
||||||
setMounted(true);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// We still parse the metastring in case we want to support more syntax in the
|
|
||||||
// future. Note that MDX doesn't strip quotes when parsing metastring:
|
|
||||||
// "title=\"xyz\"" => title: "\"xyz\""
|
|
||||||
const codeBlockTitle = parseCodeBlockTitle(metastring) || title;
|
|
||||||
const prismTheme = usePrismTheme();
|
|
||||||
|
|
||||||
const prismCssVariables = getPrismCssVariables(prismTheme);
|
|
||||||
|
|
||||||
// <pre> 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 (
|
|
||||||
<Highlight
|
|
||||||
{...defaultProps}
|
|
||||||
key={String(mounted)}
|
|
||||||
theme={prismTheme}
|
|
||||||
code=""
|
|
||||||
language={'text' as Language}>
|
|
||||||
{({className}) => (
|
|
||||||
<pre
|
|
||||||
/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
|
|
||||||
tabIndex={0}
|
|
||||||
className={clsx(
|
|
||||||
className,
|
|
||||||
styles.codeBlockStandalone,
|
|
||||||
'thin-scrollbar',
|
|
||||||
styles.codeBlockContainer,
|
|
||||||
blockClassName,
|
|
||||||
ThemeClassNames.common.codeBlock,
|
|
||||||
)}
|
|
||||||
style={prismCssVariables}>
|
|
||||||
<code className={styles.codeBlockLines}>{children}</code>
|
|
||||||
</pre>
|
|
||||||
)}
|
|
||||||
</Highlight>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// The children is now guaranteed to be one/more plain strings
|
|
||||||
const content = Array.isArray(children)
|
|
||||||
? children.join('')
|
|
||||||
: (children as string);
|
|
||||||
|
|
||||||
const language =
|
|
||||||
languageProp ?? parseLanguage(blockClassName) ?? prism.defaultLanguage;
|
|
||||||
const {highlightLines, code} = parseLines(content, metastring, language);
|
|
||||||
const shouldShowLineNumbers =
|
|
||||||
showLineNumbers || containsLineNumbers(metastring);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Highlight
|
<CodeBlockComp key={String(isBrowser)} {...props}>
|
||||||
{...defaultProps}
|
{children as string}
|
||||||
key={String(mounted)}
|
</CodeBlockComp>
|
||||||
theme={prismTheme}
|
|
||||||
code={code}
|
|
||||||
language={(language ?? 'text') as Language}>
|
|
||||||
{({className, tokens, getLineProps, getTokenProps}) => (
|
|
||||||
<div
|
|
||||||
className={clsx(
|
|
||||||
styles.codeBlockContainer,
|
|
||||||
blockClassName,
|
|
||||||
{
|
|
||||||
[`language-${language}`]:
|
|
||||||
language && !blockClassName.includes(`language-${language}`),
|
|
||||||
},
|
|
||||||
ThemeClassNames.common.codeBlock,
|
|
||||||
)}
|
|
||||||
style={prismCssVariables}>
|
|
||||||
{codeBlockTitle && (
|
|
||||||
<div className={styles.codeBlockTitle}>{codeBlockTitle}</div>
|
|
||||||
)}
|
|
||||||
<div className={styles.codeBlockContent}>
|
|
||||||
<pre
|
|
||||||
/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
|
|
||||||
tabIndex={0}
|
|
||||||
className={clsx(className, styles.codeBlock, 'thin-scrollbar')}>
|
|
||||||
<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,
|
|
||||||
...(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}>
|
|
||||||
{shouldShowLineNumbers ? (
|
|
||||||
<>
|
|
||||||
<span className={styles.codeLineNumber} />
|
|
||||||
<span className={styles.codeLineContent}>
|
|
||||||
{lineTokens}
|
|
||||||
</span>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{lineTokens}
|
|
||||||
<br />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</code>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
<CopyButton code={code} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Highlight>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,11 +182,10 @@ export function getPrismCssVariables(prismTheme: PrismTheme): CSSProperties {
|
||||||
backgroundColor: '--prism-background-color',
|
backgroundColor: '--prism-background-color',
|
||||||
};
|
};
|
||||||
|
|
||||||
const properties: CSSProperties = {};
|
const properties: {[key: string]: string} = {};
|
||||||
Object.entries(prismTheme.plain).forEach(([key, value]) => {
|
Object.entries(prismTheme.plain).forEach(([key, value]) => {
|
||||||
const varName = mapping[key];
|
const varName = mapping[key];
|
||||||
if (varName && typeof value === 'string') {
|
if (varName && typeof value === 'string') {
|
||||||
// @ts-expect-error: why css variables not in inline style type?
|
|
||||||
properties[varName] = value;
|
properties[varName] = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue