diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index f4cead69c404..233f229c9f84 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -170,6 +170,56 @@ declare module '@theme/CodeBlock/CopyButton' { export default function CopyButton(props: Props): JSX.Element; } +declare module '@theme/CodeBlock/Container' { + import type {ComponentProps} from 'react'; + + export default function CodeBlockContainer({ + as: As, + ...props + }: {as: T} & ComponentProps): 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 { + 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['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' { import type {PropSidebarItem} from '@docusaurus/plugin-content-docs'; diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/Container/index.tsx b/packages/docusaurus-theme-classic/src/theme/CodeBlock/Container/index.tsx new file mode 100644 index 000000000000..293d700dad35 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/Container/index.tsx @@ -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({ + as: As, + ...props +}: {as: T} & ComponentProps): JSX.Element { + const prismTheme = usePrismTheme(); + const prismCssVariables = getPrismCssVariables(prismTheme); + return ( + + ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/Container/styles.module.css b/packages/docusaurus-theme-classic/src/theme/CodeBlock/Container/styles.module.css new file mode 100644 index 000000000000..27adece6bd9b --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/Container/styles.module.css @@ -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); +} diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/Content/Element.tsx b/packages/docusaurus-theme-classic/src/theme/CodeBlock/Content/Element.tsx new file mode 100644 index 000000000000..3f130e80e6d6 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/Content/Element.tsx @@ -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'; + +//
 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 (
+    
+      {children}
+    
+  );
+}
diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/Content/String.tsx b/packages/docusaurus-theme-classic/src/theme/CodeBlock/Content/String.tsx
new file mode 100644
index 000000000000..d4e59b1718c5
--- /dev/null
+++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/Content/String.tsx
@@ -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 (
+    
+      {title && 
{title}
} +
+ + {({className, tokens, getLineProps, getTokenProps}) => ( +
+              
+                {tokens.map((line, i) => (
+                  
+                ))}
+              
+            
+ )} +
+ +
+
+ ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css b/packages/docusaurus-theme-classic/src/theme/CodeBlock/Content/styles.module.css similarity index 60% rename from packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css rename to packages/docusaurus-theme-classic/src/theme/CodeBlock/Content/styles.module.css index 970367a7e601..6f043e05c4da 100644 --- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/styles.module.css +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/Content/styles.module.css @@ -5,14 +5,6 @@ * 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 { position: relative; /* rtl:ignore */ @@ -62,31 +54,3 @@ 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); -} diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/Line/index.tsx b/packages/docusaurus-theme-classic/src/theme/CodeBlock/Line/index.tsx new file mode 100644 index 000000000000..79505f42d756 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/Line/index.tsx @@ -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) => ( + + )); + + return ( + + {showLineNumbers ? ( + <> + + {lineTokens} + + ) : ( + <> + {lineTokens} +
+ + )} +
+ ); +} diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/Line/styles.module.css b/packages/docusaurus-theme-classic/src/theme/CodeBlock/Line/styles.module.css new file mode 100644 index 000000000000..7597f007c5b2 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/Line/styles.module.css @@ -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); +} diff --git a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx index dbf000cb0aa3..9565932fafcb 100644 --- a/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx @@ -5,81 +5,11 @@ * LICENSE file in the root directory of this source tree. */ -import React, { - isValidElement, - type ComponentProps, - type ReactNode, -} from 'react'; -import clsx from 'clsx'; -import Highlight, {defaultProps, type Language} from 'prism-react-renderer'; +import React, {isValidElement, type ReactNode} from 'react'; import useIsBrowser from '@docusaurus/useIsBrowser'; -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 styles from './styles.module.css'; - -// Lib does not make this easy -type RenderProps = Parameters['children']>[0]; -type GetLineProps = RenderProps['getLineProps']; -type GetTokenProps = RenderProps['getTokenProps']; -type Token = RenderProps['tokens'][number][number]; - -function CodeBlockLine({ - line, - highlight, - showLineNumbers, - getLineProps, - getTokenProps, -}: { - line: Token[]; - highlight: boolean; - showLineNumbers: boolean; - getLineProps: GetLineProps; - getTokenProps: GetTokenProps; -}) { - 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) => ( - - )); - - return ( - - {showLineNumbers ? ( - <> - - {lineTokens} - - ) : ( - <> - {lineTokens} -
- - )} -
- ); -} +import ElementContent from '@theme/CodeBlock/Content/Element'; +import StringContent from '@theme/CodeBlock/Content/String'; /** * Best attempt to make the children a plain string so it is copyable. If there @@ -106,114 +36,10 @@ export default function CodeBlock({ const isBrowser = useIsBrowser(); const children = maybeStringifyChildren(rawChildren); const CodeBlockComp = - typeof children === 'string' ? CodeBlockString : CodeBlockJSX; + typeof children === 'string' ? StringContent : ElementContent; return ( {children as string} ); } - -function CodeBlockContainer({ - as: As, - ...props -}: {as: T} & ComponentProps) { - const prismTheme = usePrismTheme(); - const prismCssVariables = getPrismCssVariables(prismTheme); - return ( - - ); -} - -//
 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.
-function CodeBlockJSX({children, className}: Props): JSX.Element {
-  return (
-    
-      {children}
-    
-  );
-}
-
-function CodeBlockString({
-  children,
-  className: blockClassName = '',
-  metastring,
-  title: titleProp,
-  showLineNumbers: showLineNumbersProp,
-  language: languageProp,
-}: Omit & {children: string}): 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 (
-    
-      {title && 
{title}
} -
- - {({className, tokens, getLineProps, getTokenProps}) => ( -
-              
-                {tokens.map((line, i) => (
-                  
-                ))}
-              
-            
- )} -
- -
-
- ); -}