@docusaurus/theme-classic 0.0.0-4867 → 0.0.0-4870

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -148,10 +148,10 @@ declare module '@theme/BlogLayout' {
148
148
  }
149
149
 
150
150
  declare module '@theme/CodeBlock' {
151
- import type {ReactElement} from 'react';
151
+ import type {ReactNode} from 'react';
152
152
 
153
153
  export interface Props {
154
- readonly children: string | ReactElement;
154
+ readonly children: ReactNode;
155
155
  readonly className?: string;
156
156
  readonly metastring?: string;
157
157
  readonly title?: string;
@@ -170,6 +170,56 @@ declare module '@theme/CodeBlock/CopyButton' {
170
170
  export default function CopyButton(props: Props): JSX.Element;
171
171
  }
172
172
 
173
+ declare module '@theme/CodeBlock/Container' {
174
+ import type {ComponentProps} from 'react';
175
+
176
+ export default function CodeBlockContainer<T extends 'div' | 'pre'>({
177
+ as: As,
178
+ ...props
179
+ }: {as: T} & ComponentProps<T>): JSX.Element;
180
+ }
181
+
182
+ declare module '@theme/CodeBlock/Content/Element' {
183
+ import type {Props} from '@theme/CodeBlock';
184
+
185
+ export type {Props};
186
+
187
+ export default function CodeBlockElementContent(props: Props): JSX.Element;
188
+ }
189
+
190
+ declare module '@theme/CodeBlock/Content/String' {
191
+ import type {Props as CodeBlockProps} from '@theme/CodeBlock';
192
+
193
+ export interface Props extends Omit<CodeBlockProps, 'children'> {
194
+ readonly children: string;
195
+ }
196
+
197
+ export default function CodeBlockStringContent(props: Props): JSX.Element;
198
+ }
199
+
200
+ declare module '@theme/CodeBlock/Line' {
201
+ import type {ComponentProps} from 'react';
202
+ import type Highlight from 'prism-react-renderer';
203
+
204
+ // Lib does not make this easy
205
+ type RenderProps = Parameters<
206
+ ComponentProps<typeof Highlight>['children']
207
+ >[0];
208
+ type GetLineProps = RenderProps['getLineProps'];
209
+ type GetTokenProps = RenderProps['getTokenProps'];
210
+ type Token = RenderProps['tokens'][number][number];
211
+
212
+ export interface Props {
213
+ readonly line: Token[];
214
+ readonly highlight: boolean;
215
+ readonly showLineNumbers: boolean;
216
+ readonly getLineProps: GetLineProps;
217
+ readonly getTokenProps: GetTokenProps;
218
+ }
219
+
220
+ export default function CodeBlockLine(props: Props): JSX.Element;
221
+ }
222
+
173
223
  declare module '@theme/DocCard' {
174
224
  import type {PropSidebarItem} from '@docusaurus/plugin-content-docs';
175
225
 
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import React from 'react';
8
+ import clsx from 'clsx';
9
+ import {
10
+ usePrismTheme,
11
+ getPrismCssVariables,
12
+ ThemeClassNames,
13
+ } from '@docusaurus/theme-common';
14
+ import styles from './styles.module.css';
15
+ export default function CodeBlockContainer({as: As, ...props}) {
16
+ const prismTheme = usePrismTheme();
17
+ const prismCssVariables = getPrismCssVariables(prismTheme);
18
+ return (
19
+ <As // Polymorphic components are hard to type, without `oneOf` generics
20
+ {...props}
21
+ style={prismCssVariables}
22
+ className={clsx(
23
+ props.className,
24
+ styles.codeBlockContainer,
25
+ ThemeClassNames.common.codeBlock,
26
+ )}
27
+ />
28
+ );
29
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ .codeBlockContainer {
9
+ background: var(--prism-background-color);
10
+ color: var(--prism-color);
11
+ margin-bottom: var(--ifm-leading);
12
+ box-shadow: var(--ifm-global-shadow-lw);
13
+ border-radius: var(--ifm-code-border-radius);
14
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import React from 'react';
8
+ import Container from '@theme/CodeBlock/Container';
9
+ import clsx from 'clsx';
10
+ import styles from './styles.module.css'; // <pre> tags in markdown map to CodeBlocks. They may contain JSX children. When
11
+ // the children is not a simple string, we just return a styled block without
12
+ // actually highlighting.
13
+
14
+ export default function CodeBlockJSX({children, className}) {
15
+ return (
16
+ <Container
17
+ as="pre"
18
+ tabIndex={0}
19
+ className={clsx(styles.codeBlockStandalone, 'thin-scrollbar', className)}>
20
+ <code className={styles.codeBlockLines}>{children}</code>
21
+ </Container>
22
+ );
23
+ }
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import React from 'react';
8
+ import {
9
+ useThemeConfig,
10
+ parseCodeBlockTitle,
11
+ parseLanguage,
12
+ parseLines,
13
+ containsLineNumbers,
14
+ usePrismTheme,
15
+ } from '@docusaurus/theme-common';
16
+ import clsx from 'clsx';
17
+ import Highlight, {defaultProps} from 'prism-react-renderer';
18
+ import Line from '@theme/CodeBlock/Line';
19
+ import CopyButton from '@theme/CodeBlock/CopyButton';
20
+ import Container from '@theme/CodeBlock/Container';
21
+ import styles from './styles.module.css';
22
+ export default function CodeBlockString({
23
+ children,
24
+ className: blockClassName = '',
25
+ metastring,
26
+ title: titleProp,
27
+ showLineNumbers: showLineNumbersProp,
28
+ language: languageProp,
29
+ }) {
30
+ const {
31
+ prism: {defaultLanguage},
32
+ } = useThemeConfig();
33
+ const language =
34
+ languageProp ?? parseLanguage(blockClassName) ?? defaultLanguage;
35
+ const prismTheme = usePrismTheme(); // We still parse the metastring in case we want to support more syntax in the
36
+ // future. Note that MDX doesn't strip quotes when parsing metastring:
37
+ // "title=\"xyz\"" => title: "\"xyz\""
38
+
39
+ const title = parseCodeBlockTitle(metastring) || titleProp;
40
+ const {highlightLines, code} = parseLines(children, metastring, language);
41
+ const showLineNumbers =
42
+ showLineNumbersProp || containsLineNumbers(metastring);
43
+ return (
44
+ <Container
45
+ as="div"
46
+ className={clsx(
47
+ blockClassName,
48
+ language &&
49
+ !blockClassName.includes(`language-${language}`) &&
50
+ `language-${language}`,
51
+ )}>
52
+ {title && <div className={styles.codeBlockTitle}>{title}</div>}
53
+ <div className={styles.codeBlockContent}>
54
+ <Highlight
55
+ {...defaultProps}
56
+ theme={prismTheme}
57
+ code={code}
58
+ language={language ?? 'text'}>
59
+ {({className, tokens, getLineProps, getTokenProps}) => (
60
+ <pre
61
+ /* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
62
+ tabIndex={0}
63
+ className={clsx(className, styles.codeBlock, 'thin-scrollbar')}>
64
+ <code
65
+ className={clsx(
66
+ styles.codeBlockLines,
67
+ showLineNumbers && styles.codeBlockLinesWithNumbering,
68
+ )}>
69
+ {tokens.map((line, i) => (
70
+ <Line
71
+ key={i}
72
+ line={line}
73
+ getLineProps={getLineProps}
74
+ getTokenProps={getTokenProps}
75
+ highlight={highlightLines.includes(i)}
76
+ showLineNumbers={showLineNumbers}
77
+ />
78
+ ))}
79
+ </code>
80
+ </pre>
81
+ )}
82
+ </Highlight>
83
+ <CopyButton code={code} />
84
+ </div>
85
+ </Container>
86
+ );
87
+ }
@@ -5,14 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- .codeBlockContainer {
9
- background: var(--prism-background-color);
10
- color: var(--prism-color);
11
- margin-bottom: var(--ifm-leading);
12
- box-shadow: var(--ifm-global-shadow-lw);
13
- border-radius: var(--ifm-code-border-radius);
14
- }
15
-
16
8
  .codeBlockContent {
17
9
  position: relative;
18
10
  /* rtl:ignore */
@@ -62,31 +54,3 @@
62
54
  white-space: pre-wrap;
63
55
  }
64
56
  }
65
-
66
- .codeLine {
67
- display: table-row;
68
- counter-increment: line-count;
69
- }
70
-
71
- .codeLineNumber {
72
- display: table-cell;
73
- text-align: right;
74
- width: 1%;
75
- position: sticky;
76
- left: 0;
77
- padding: 0 var(--ifm-pre-padding);
78
- background: var(--ifm-pre-background);
79
- }
80
-
81
- .codeLineNumber::before {
82
- content: counter(line-count);
83
- opacity: 0.4;
84
- }
85
-
86
- :global(.docusaurus-highlight-code-line) .codeLineNumber::before {
87
- opacity: 0.8;
88
- }
89
-
90
- .codeLineContent {
91
- padding-right: var(--ifm-pre-padding);
92
- }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import React from 'react';
8
+ import styles from './styles.module.css';
9
+ export default function CodeBlockLine({
10
+ line,
11
+ highlight,
12
+ showLineNumbers,
13
+ getLineProps,
14
+ getTokenProps,
15
+ }) {
16
+ if (line.length === 1 && line[0].content === '\n') {
17
+ line[0].content = '';
18
+ }
19
+
20
+ const lineProps = getLineProps({
21
+ line,
22
+ ...(showLineNumbers && {
23
+ className: styles.codeLine,
24
+ }),
25
+ });
26
+
27
+ if (highlight) {
28
+ lineProps.className += ' docusaurus-highlight-code-line';
29
+ }
30
+
31
+ const lineTokens = line.map((token, key) => (
32
+ <span
33
+ key={key}
34
+ {...getTokenProps({
35
+ token,
36
+ key,
37
+ })}
38
+ />
39
+ ));
40
+ return (
41
+ <span {...lineProps}>
42
+ {showLineNumbers ? (
43
+ <>
44
+ <span className={styles.codeLineNumber} />
45
+ <span className={styles.codeLineContent}>{lineTokens}</span>
46
+ </>
47
+ ) : (
48
+ <>
49
+ {lineTokens}
50
+ <br />
51
+ </>
52
+ )}
53
+ </span>
54
+ );
55
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ .codeLine {
9
+ display: table-row;
10
+ counter-increment: line-count;
11
+ }
12
+
13
+ .codeLineNumber {
14
+ display: table-cell;
15
+ text-align: right;
16
+ width: 1%;
17
+ position: sticky;
18
+ left: 0;
19
+ padding: 0 var(--ifm-pre-padding);
20
+ background: var(--ifm-pre-background);
21
+ }
22
+
23
+ .codeLineNumber::before {
24
+ content: counter(line-count);
25
+ opacity: 0.4;
26
+ }
27
+
28
+ :global(.docusaurus-highlight-code-line) .codeLineNumber::before {
29
+ opacity: 0.8;
30
+ }
31
+
32
+ .codeLineContent {
33
+ padding-right: var(--ifm-pre-padding);
34
+ }
@@ -4,167 +4,37 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
- import React, {isValidElement, useEffect, useState} from 'react';
8
- import clsx from 'clsx';
9
- import Highlight, {defaultProps} from 'prism-react-renderer';
10
- import {
11
- useThemeConfig,
12
- parseCodeBlockTitle,
13
- parseLanguage,
14
- parseLines,
15
- containsLineNumbers,
16
- ThemeClassNames,
17
- usePrismTheme,
18
- getPrismCssVariables,
19
- } from '@docusaurus/theme-common';
20
- import CopyButton from '@theme/CodeBlock/CopyButton';
21
- import styles from './styles.module.css';
22
- export default function CodeBlock({
23
- children,
24
- className: blockClassName = '',
25
- metastring,
26
- title,
27
- showLineNumbers,
28
- language: languageProp,
29
- }) {
30
- const {prism} = useThemeConfig();
31
- const [mounted, setMounted] = useState(false); // The Prism theme on SSR is always the default theme but the site theme
32
- // can be in a different mode. React hydration doesn't update DOM styles
33
- // that come from SSR. Hence force a re-render after mounting to apply the
34
- // current relevant styles. There will be a flash seen of the original
35
- // styles seen using this current approach but that's probably ok. Fixing
36
- // the flash will require changing the theming approach and is not worth it
37
- // at this point.
38
-
39
- useEffect(() => {
40
- setMounted(true);
41
- }, []); // We still parse the metastring in case we want to support more syntax in the
42
- // future. Note that MDX doesn't strip quotes when parsing metastring:
43
- // "title=\"xyz\"" => title: "\"xyz\""
44
-
45
- const codeBlockTitle = parseCodeBlockTitle(metastring) || title;
46
- const prismTheme = usePrismTheme();
47
- const prismCssVariables = getPrismCssVariables(prismTheme); // <pre> tags in markdown map to CodeBlocks and they may contain JSX children.
48
- // When the children is not a simple string, we just return a styled block
49
- // without actually highlighting.
7
+ import React, {isValidElement} from 'react';
8
+ import useIsBrowser from '@docusaurus/useIsBrowser';
9
+ import ElementContent from '@theme/CodeBlock/Content/Element';
10
+ import StringContent from '@theme/CodeBlock/Content/String';
11
+ /**
12
+ * Best attempt to make the children a plain string so it is copyable. If there
13
+ * are react elements, we will not be able to copy the content, and it will
14
+ * return `children` as-is; otherwise, it concatenates the string children
15
+ * together.
16
+ */
50
17
 
18
+ function maybeStringifyChildren(children) {
51
19
  if (React.Children.toArray(children).some((el) => isValidElement(el))) {
52
- return (
53
- <Highlight
54
- {...defaultProps}
55
- key={String(mounted)}
56
- theme={prismTheme}
57
- code=""
58
- language={'text'}>
59
- {({className}) => (
60
- <pre
61
- /* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
62
- tabIndex={0}
63
- className={clsx(
64
- className,
65
- styles.codeBlockStandalone,
66
- 'thin-scrollbar',
67
- styles.codeBlockContainer,
68
- blockClassName,
69
- ThemeClassNames.common.codeBlock,
70
- )}
71
- style={prismCssVariables}>
72
- <code className={styles.codeBlockLines}>{children}</code>
73
- </pre>
74
- )}
75
- </Highlight>
76
- );
20
+ return children;
77
21
  } // The children is now guaranteed to be one/more plain strings
78
22
 
79
- const content = Array.isArray(children) ? children.join('') : children;
80
- const language =
81
- languageProp ?? parseLanguage(blockClassName) ?? prism.defaultLanguage;
82
- const {highlightLines, code} = parseLines(content, metastring, language);
83
- const shouldShowLineNumbers =
84
- showLineNumbers || containsLineNumbers(metastring);
85
- return (
86
- <Highlight
87
- {...defaultProps}
88
- key={String(mounted)}
89
- theme={prismTheme}
90
- code={code}
91
- language={language ?? 'text'}>
92
- {({className, tokens, getLineProps, getTokenProps}) => (
93
- <div
94
- className={clsx(
95
- styles.codeBlockContainer,
96
- blockClassName,
97
- {
98
- [`language-${language}`]:
99
- language && !blockClassName.includes(`language-${language}`),
100
- },
101
- ThemeClassNames.common.codeBlock,
102
- )}
103
- style={prismCssVariables}>
104
- {codeBlockTitle && (
105
- <div className={styles.codeBlockTitle}>{codeBlockTitle}</div>
106
- )}
107
- <div className={styles.codeBlockContent}>
108
- <pre
109
- /* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
110
- tabIndex={0}
111
- className={clsx(className, styles.codeBlock, 'thin-scrollbar')}>
112
- <code
113
- className={clsx(
114
- styles.codeBlockLines,
115
- shouldShowLineNumbers && styles.codeBlockLinesWithNumbering,
116
- )}>
117
- {tokens.map((line, i) => {
118
- if (line.length === 1 && line[0].content === '\n') {
119
- line[0].content = '';
120
- }
121
-
122
- const lineProps = getLineProps({
123
- line,
124
- key: i,
125
- ...(shouldShowLineNumbers && {
126
- className: styles.codeLine,
127
- }),
128
- });
129
-
130
- if (highlightLines.includes(i)) {
131
- lineProps.className += ' docusaurus-highlight-code-line';
132
- }
133
-
134
- const lineTokens = line.map((token, key) => (
135
- <span
136
- key={key}
137
- {...getTokenProps({
138
- token,
139
- key,
140
- })}
141
- />
142
- ));
143
- return (
144
- <span key={i} {...lineProps}>
145
- {shouldShowLineNumbers ? (
146
- <>
147
- <span className={styles.codeLineNumber} />
148
- <span className={styles.codeLineContent}>
149
- {lineTokens}
150
- </span>
151
- </>
152
- ) : (
153
- <>
154
- {lineTokens}
155
- <br />
156
- </>
157
- )}
158
- </span>
159
- );
160
- })}
161
- </code>
162
- </pre>
23
+ return Array.isArray(children) ? children.join('') : children;
24
+ }
163
25
 
164
- <CopyButton code={code} />
165
- </div>
166
- </div>
167
- )}
168
- </Highlight>
26
+ export default function CodeBlock({children: rawChildren, ...props}) {
27
+ // The Prism theme on SSR is always the default theme but the site theme can
28
+ // be in a different mode. React hydration doesn't update DOM styles that come
29
+ // from SSR. Hence force a re-render after mounting to apply the current
30
+ // relevant styles.
31
+ const isBrowser = useIsBrowser();
32
+ const children = maybeStringifyChildren(rawChildren);
33
+ const CodeBlockComp =
34
+ typeof children === 'string' ? StringContent : ElementContent;
35
+ return (
36
+ <CodeBlockComp key={String(isBrowser)} {...props}>
37
+ {children}
38
+ </CodeBlockComp>
169
39
  );
170
40
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docusaurus/theme-classic",
3
- "version": "0.0.0-4867",
3
+ "version": "0.0.0-4870",
4
4
  "description": "Classic theme for Docusaurus",
5
5
  "main": "lib/index.js",
6
6
  "types": "src/theme-classic.d.ts",
@@ -21,15 +21,15 @@
21
21
  "format:lib-next": "prettier --config ../../.prettierrc --write \"lib-next/**/*.{js,ts,jsx,tsc}\""
22
22
  },
23
23
  "dependencies": {
24
- "@docusaurus/core": "0.0.0-4867",
25
- "@docusaurus/plugin-content-blog": "0.0.0-4867",
26
- "@docusaurus/plugin-content-docs": "0.0.0-4867",
27
- "@docusaurus/plugin-content-pages": "0.0.0-4867",
28
- "@docusaurus/theme-common": "0.0.0-4867",
29
- "@docusaurus/theme-translations": "0.0.0-4867",
30
- "@docusaurus/utils": "0.0.0-4867",
31
- "@docusaurus/utils-common": "0.0.0-4867",
32
- "@docusaurus/utils-validation": "0.0.0-4867",
24
+ "@docusaurus/core": "0.0.0-4870",
25
+ "@docusaurus/plugin-content-blog": "0.0.0-4870",
26
+ "@docusaurus/plugin-content-docs": "0.0.0-4870",
27
+ "@docusaurus/plugin-content-pages": "0.0.0-4870",
28
+ "@docusaurus/theme-common": "0.0.0-4870",
29
+ "@docusaurus/theme-translations": "0.0.0-4870",
30
+ "@docusaurus/utils": "0.0.0-4870",
31
+ "@docusaurus/utils-common": "0.0.0-4870",
32
+ "@docusaurus/utils-validation": "0.0.0-4870",
33
33
  "@mdx-js/react": "^1.6.22",
34
34
  "clsx": "^1.1.1",
35
35
  "copy-text-to-clipboard": "^3.0.1",
@@ -45,8 +45,8 @@
45
45
  "@babel/cli": "^7.17.6",
46
46
  "@babel/core": "^7.17.9",
47
47
  "@babel/preset-typescript": "^7.16.7",
48
- "@docusaurus/module-type-aliases": "0.0.0-4867",
49
- "@docusaurus/types": "0.0.0-4867",
48
+ "@docusaurus/module-type-aliases": "0.0.0-4870",
49
+ "@docusaurus/types": "0.0.0-4870",
50
50
  "@types/mdx-js__react": "^1.5.5",
51
51
  "@types/prismjs": "^1.26.0",
52
52
  "@types/rtlcss": "^3.1.3",
@@ -62,5 +62,5 @@
62
62
  "engines": {
63
63
  "node": ">=14"
64
64
  },
65
- "gitHead": "7b45d0d34b25d64b754be282b06f2b889378a07a"
65
+ "gitHead": "c5144875378d6edd9690388245488b54d5bf509c"
66
66
  }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import React, {type ComponentProps} from 'react';
9
+ import clsx from 'clsx';
10
+ import {
11
+ usePrismTheme,
12
+ getPrismCssVariables,
13
+ ThemeClassNames,
14
+ } from '@docusaurus/theme-common';
15
+ import styles from './styles.module.css';
16
+
17
+ export default function CodeBlockContainer<T extends 'div' | 'pre'>({
18
+ as: As,
19
+ ...props
20
+ }: {as: T} & ComponentProps<T>): JSX.Element {
21
+ const prismTheme = usePrismTheme();
22
+ const prismCssVariables = getPrismCssVariables(prismTheme);
23
+ return (
24
+ <As
25
+ // Polymorphic components are hard to type, without `oneOf` generics
26
+ {...(props as never)}
27
+ style={prismCssVariables}
28
+ className={clsx(
29
+ props.className,
30
+ styles.codeBlockContainer,
31
+ ThemeClassNames.common.codeBlock,
32
+ )}
33
+ />
34
+ );
35
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ .codeBlockContainer {
9
+ background: var(--prism-background-color);
10
+ color: var(--prism-color);
11
+ margin-bottom: var(--ifm-leading);
12
+ box-shadow: var(--ifm-global-shadow-lw);
13
+ border-radius: var(--ifm-code-border-radius);
14
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import React from 'react';
9
+ import Container from '@theme/CodeBlock/Container';
10
+ import clsx from 'clsx';
11
+ import type {Props} from '@theme/CodeBlock/Content/Element';
12
+
13
+ import styles from './styles.module.css';
14
+
15
+ // <pre> tags in markdown map to CodeBlocks. They may contain JSX children. When
16
+ // the children is not a simple string, we just return a styled block without
17
+ // actually highlighting.
18
+ export default function CodeBlockJSX({
19
+ children,
20
+ className,
21
+ }: Props): JSX.Element {
22
+ return (
23
+ <Container
24
+ as="pre"
25
+ tabIndex={0}
26
+ className={clsx(styles.codeBlockStandalone, 'thin-scrollbar', className)}>
27
+ <code className={styles.codeBlockLines}>{children}</code>
28
+ </Container>
29
+ );
30
+ }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import React from 'react';
9
+ import {
10
+ useThemeConfig,
11
+ parseCodeBlockTitle,
12
+ parseLanguage,
13
+ parseLines,
14
+ containsLineNumbers,
15
+ usePrismTheme,
16
+ } from '@docusaurus/theme-common';
17
+ import clsx from 'clsx';
18
+ import Highlight, {defaultProps, type Language} from 'prism-react-renderer';
19
+ import Line from '@theme/CodeBlock/Line';
20
+ import CopyButton from '@theme/CodeBlock/CopyButton';
21
+ import Container from '@theme/CodeBlock/Container';
22
+ import type {Props} from '@theme/CodeBlock/Content/String';
23
+
24
+ import styles from './styles.module.css';
25
+
26
+ export default function CodeBlockString({
27
+ children,
28
+ className: blockClassName = '',
29
+ metastring,
30
+ title: titleProp,
31
+ showLineNumbers: showLineNumbersProp,
32
+ language: languageProp,
33
+ }: Props): JSX.Element {
34
+ const {
35
+ prism: {defaultLanguage},
36
+ } = useThemeConfig();
37
+ const language =
38
+ languageProp ?? parseLanguage(blockClassName) ?? defaultLanguage;
39
+ const prismTheme = usePrismTheme();
40
+
41
+ // We still parse the metastring in case we want to support more syntax in the
42
+ // future. Note that MDX doesn't strip quotes when parsing metastring:
43
+ // "title=\"xyz\"" => title: "\"xyz\""
44
+ const title = parseCodeBlockTitle(metastring) || titleProp;
45
+
46
+ const {highlightLines, code} = parseLines(children, metastring, language);
47
+ const showLineNumbers =
48
+ showLineNumbersProp || containsLineNumbers(metastring);
49
+
50
+ return (
51
+ <Container
52
+ as="div"
53
+ className={clsx(
54
+ blockClassName,
55
+ language &&
56
+ !blockClassName.includes(`language-${language}`) &&
57
+ `language-${language}`,
58
+ )}>
59
+ {title && <div className={styles.codeBlockTitle}>{title}</div>}
60
+ <div className={styles.codeBlockContent}>
61
+ <Highlight
62
+ {...defaultProps}
63
+ theme={prismTheme}
64
+ code={code}
65
+ language={(language ?? 'text') as Language}>
66
+ {({className, tokens, getLineProps, getTokenProps}) => (
67
+ <pre
68
+ /* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
69
+ tabIndex={0}
70
+ className={clsx(className, styles.codeBlock, 'thin-scrollbar')}>
71
+ <code
72
+ className={clsx(
73
+ styles.codeBlockLines,
74
+ showLineNumbers && styles.codeBlockLinesWithNumbering,
75
+ )}>
76
+ {tokens.map((line, i) => (
77
+ <Line
78
+ key={i}
79
+ line={line}
80
+ getLineProps={getLineProps}
81
+ getTokenProps={getTokenProps}
82
+ highlight={highlightLines.includes(i)}
83
+ showLineNumbers={showLineNumbers}
84
+ />
85
+ ))}
86
+ </code>
87
+ </pre>
88
+ )}
89
+ </Highlight>
90
+ <CopyButton code={code} />
91
+ </div>
92
+ </Container>
93
+ );
94
+ }
@@ -5,14 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- .codeBlockContainer {
9
- background: var(--prism-background-color);
10
- color: var(--prism-color);
11
- margin-bottom: var(--ifm-leading);
12
- box-shadow: var(--ifm-global-shadow-lw);
13
- border-radius: var(--ifm-code-border-radius);
14
- }
15
-
16
8
  .codeBlockContent {
17
9
  position: relative;
18
10
  /* rtl:ignore */
@@ -62,31 +54,3 @@
62
54
  white-space: pre-wrap;
63
55
  }
64
56
  }
65
-
66
- .codeLine {
67
- display: table-row;
68
- counter-increment: line-count;
69
- }
70
-
71
- .codeLineNumber {
72
- display: table-cell;
73
- text-align: right;
74
- width: 1%;
75
- position: sticky;
76
- left: 0;
77
- padding: 0 var(--ifm-pre-padding);
78
- background: var(--ifm-pre-background);
79
- }
80
-
81
- .codeLineNumber::before {
82
- content: counter(line-count);
83
- opacity: 0.4;
84
- }
85
-
86
- :global(.docusaurus-highlight-code-line) .codeLineNumber::before {
87
- opacity: 0.8;
88
- }
89
-
90
- .codeLineContent {
91
- padding-right: var(--ifm-pre-padding);
92
- }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import React from 'react';
9
+ import type {Props} from '@theme/CodeBlock/Line';
10
+ import styles from './styles.module.css';
11
+
12
+ export default function CodeBlockLine({
13
+ line,
14
+ highlight,
15
+ showLineNumbers,
16
+ getLineProps,
17
+ getTokenProps,
18
+ }: Props): JSX.Element {
19
+ if (line.length === 1 && line[0]!.content === '\n') {
20
+ line[0]!.content = '';
21
+ }
22
+
23
+ const lineProps = getLineProps({
24
+ line,
25
+ ...(showLineNumbers && {className: styles.codeLine}),
26
+ });
27
+
28
+ if (highlight) {
29
+ lineProps.className += ' docusaurus-highlight-code-line';
30
+ }
31
+
32
+ const lineTokens = line.map((token, key) => (
33
+ <span key={key} {...getTokenProps({token, key})} />
34
+ ));
35
+
36
+ return (
37
+ <span {...lineProps}>
38
+ {showLineNumbers ? (
39
+ <>
40
+ <span className={styles.codeLineNumber} />
41
+ <span className={styles.codeLineContent}>{lineTokens}</span>
42
+ </>
43
+ ) : (
44
+ <>
45
+ {lineTokens}
46
+ <br />
47
+ </>
48
+ )}
49
+ </span>
50
+ );
51
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ .codeLine {
9
+ display: table-row;
10
+ counter-increment: line-count;
11
+ }
12
+
13
+ .codeLineNumber {
14
+ display: table-cell;
15
+ text-align: right;
16
+ width: 1%;
17
+ position: sticky;
18
+ left: 0;
19
+ padding: 0 var(--ifm-pre-padding);
20
+ background: var(--ifm-pre-background);
21
+ }
22
+
23
+ .codeLineNumber::before {
24
+ content: counter(line-count);
25
+ opacity: 0.4;
26
+ }
27
+
28
+ :global(.docusaurus-highlight-code-line) .codeLineNumber::before {
29
+ opacity: 0.8;
30
+ }
31
+
32
+ .codeLineContent {
33
+ padding-right: var(--ifm-pre-padding);
34
+ }
@@ -5,172 +5,41 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import React, {isValidElement, useEffect, useState} from 'react';
9
- import clsx from 'clsx';
10
- import Highlight, {defaultProps, type Language} from 'prism-react-renderer';
11
- import {
12
- useThemeConfig,
13
- parseCodeBlockTitle,
14
- parseLanguage,
15
- parseLines,
16
- containsLineNumbers,
17
- ThemeClassNames,
18
- usePrismTheme,
19
- getPrismCssVariables,
20
- } from '@docusaurus/theme-common';
21
- import CopyButton from '@theme/CodeBlock/CopyButton';
8
+ import React, {isValidElement, type ReactNode} from 'react';
9
+ import useIsBrowser from '@docusaurus/useIsBrowser';
22
10
  import type {Props} from '@theme/CodeBlock';
11
+ import ElementContent from '@theme/CodeBlock/Content/Element';
12
+ import StringContent from '@theme/CodeBlock/Content/String';
23
13
 
24
- import styles from './styles.module.css';
25
-
26
- export default function CodeBlock({
27
- children,
28
- className: blockClassName = '',
29
- metastring,
30
- title,
31
- showLineNumbers,
32
- language: languageProp,
33
- }: Props): JSX.Element {
34
- const {prism} = useThemeConfig();
35
-
36
- const [mounted, setMounted] = useState(false);
37
- // The Prism theme on SSR is always the default theme but the site theme
38
- // can be in a different mode. React hydration doesn't update DOM styles
39
- // that come from SSR. Hence force a re-render after mounting to apply the
40
- // current relevant styles. There will be a flash seen of the original
41
- // styles seen using this current approach but that's probably ok. Fixing
42
- // the flash will require changing the theming approach and is not worth it
43
- // at this point.
44
- useEffect(() => {
45
- setMounted(true);
46
- }, []);
47
-
48
- // We still parse the metastring in case we want to support more syntax in the
49
- // future. Note that MDX doesn't strip quotes when parsing metastring:
50
- // "title=\"xyz\"" => title: "\"xyz\""
51
- const codeBlockTitle = parseCodeBlockTitle(metastring) || title;
52
- const prismTheme = usePrismTheme();
53
-
54
- const prismCssVariables = getPrismCssVariables(prismTheme);
55
-
56
- // <pre> tags in markdown map to CodeBlocks and they may contain JSX children.
57
- // When the children is not a simple string, we just return a styled block
58
- // without actually highlighting.
14
+ /**
15
+ * Best attempt to make the children a plain string so it is copyable. If there
16
+ * are react elements, we will not be able to copy the content, and it will
17
+ * return `children` as-is; otherwise, it concatenates the string children
18
+ * together.
19
+ */
20
+ function maybeStringifyChildren(children: ReactNode): ReactNode {
59
21
  if (React.Children.toArray(children).some((el) => isValidElement(el))) {
60
- return (
61
- <Highlight
62
- {...defaultProps}
63
- key={String(mounted)}
64
- theme={prismTheme}
65
- code=""
66
- language={'text' as Language}>
67
- {({className}) => (
68
- <pre
69
- /* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
70
- tabIndex={0}
71
- className={clsx(
72
- className,
73
- styles.codeBlockStandalone,
74
- 'thin-scrollbar',
75
- styles.codeBlockContainer,
76
- blockClassName,
77
- ThemeClassNames.common.codeBlock,
78
- )}
79
- style={prismCssVariables}>
80
- <code className={styles.codeBlockLines}>{children}</code>
81
- </pre>
82
- )}
83
- </Highlight>
84
- );
22
+ return children;
85
23
  }
86
-
87
24
  // The children is now guaranteed to be one/more plain strings
88
- const content = Array.isArray(children)
89
- ? children.join('')
90
- : (children as string);
91
-
92
- const language =
93
- languageProp ?? parseLanguage(blockClassName) ?? prism.defaultLanguage;
94
- const {highlightLines, code} = parseLines(content, metastring, language);
95
- const shouldShowLineNumbers =
96
- showLineNumbers || containsLineNumbers(metastring);
25
+ return Array.isArray(children) ? children.join('') : (children as string);
26
+ }
97
27
 
28
+ export default function CodeBlock({
29
+ children: rawChildren,
30
+ ...props
31
+ }: Props): JSX.Element {
32
+ // The Prism theme on SSR is always the default theme but the site theme can
33
+ // be in a different mode. React hydration doesn't update DOM styles that come
34
+ // from SSR. Hence force a re-render after mounting to apply the current
35
+ // relevant styles.
36
+ const isBrowser = useIsBrowser();
37
+ const children = maybeStringifyChildren(rawChildren);
38
+ const CodeBlockComp =
39
+ typeof children === 'string' ? StringContent : ElementContent;
98
40
  return (
99
- <Highlight
100
- {...defaultProps}
101
- key={String(mounted)}
102
- theme={prismTheme}
103
- code={code}
104
- language={(language ?? 'text') as Language}>
105
- {({className, tokens, getLineProps, getTokenProps}) => (
106
- <div
107
- className={clsx(
108
- styles.codeBlockContainer,
109
- blockClassName,
110
- {
111
- [`language-${language}`]:
112
- language && !blockClassName.includes(`language-${language}`),
113
- },
114
- ThemeClassNames.common.codeBlock,
115
- )}
116
- style={prismCssVariables}>
117
- {codeBlockTitle && (
118
- <div className={styles.codeBlockTitle}>{codeBlockTitle}</div>
119
- )}
120
- <div className={styles.codeBlockContent}>
121
- <pre
122
- /* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
123
- tabIndex={0}
124
- className={clsx(className, styles.codeBlock, 'thin-scrollbar')}>
125
- <code
126
- className={clsx(
127
- styles.codeBlockLines,
128
- shouldShowLineNumbers && styles.codeBlockLinesWithNumbering,
129
- )}>
130
- {tokens.map((line, i) => {
131
- if (line.length === 1 && line[0]!.content === '\n') {
132
- line[0]!.content = '';
133
- }
134
-
135
- const lineProps = getLineProps({
136
- line,
137
- key: i,
138
- ...(shouldShowLineNumbers && {className: styles.codeLine}),
139
- });
140
-
141
- if (highlightLines.includes(i)) {
142
- lineProps.className += ' docusaurus-highlight-code-line';
143
- }
144
-
145
- const lineTokens = line.map((token, key) => (
146
- <span key={key} {...getTokenProps({token, key})} />
147
- ));
148
-
149
- return (
150
- <span key={i} {...lineProps}>
151
- {shouldShowLineNumbers ? (
152
- <>
153
- <span className={styles.codeLineNumber} />
154
- <span className={styles.codeLineContent}>
155
- {lineTokens}
156
- </span>
157
- </>
158
- ) : (
159
- <>
160
- {lineTokens}
161
- <br />
162
- </>
163
- )}
164
- </span>
165
- );
166
- })}
167
- </code>
168
- </pre>
169
-
170
- <CopyButton code={code} />
171
- </div>
172
- </div>
173
- )}
174
- </Highlight>
41
+ <CodeBlockComp key={String(isBrowser)} {...props}>
42
+ {children as string}
43
+ </CodeBlockComp>
175
44
  );
176
45
  }
@@ -148,10 +148,10 @@ declare module '@theme/BlogLayout' {
148
148
  }
149
149
 
150
150
  declare module '@theme/CodeBlock' {
151
- import type {ReactElement} from 'react';
151
+ import type {ReactNode} from 'react';
152
152
 
153
153
  export interface Props {
154
- readonly children: string | ReactElement;
154
+ readonly children: ReactNode;
155
155
  readonly className?: string;
156
156
  readonly metastring?: string;
157
157
  readonly title?: string;
@@ -170,6 +170,56 @@ declare module '@theme/CodeBlock/CopyButton' {
170
170
  export default function CopyButton(props: Props): JSX.Element;
171
171
  }
172
172
 
173
+ declare module '@theme/CodeBlock/Container' {
174
+ import type {ComponentProps} from 'react';
175
+
176
+ export default function CodeBlockContainer<T extends 'div' | 'pre'>({
177
+ as: As,
178
+ ...props
179
+ }: {as: T} & ComponentProps<T>): JSX.Element;
180
+ }
181
+
182
+ declare module '@theme/CodeBlock/Content/Element' {
183
+ import type {Props} from '@theme/CodeBlock';
184
+
185
+ export type {Props};
186
+
187
+ export default function CodeBlockElementContent(props: Props): JSX.Element;
188
+ }
189
+
190
+ declare module '@theme/CodeBlock/Content/String' {
191
+ import type {Props as CodeBlockProps} from '@theme/CodeBlock';
192
+
193
+ export interface Props extends Omit<CodeBlockProps, 'children'> {
194
+ readonly children: string;
195
+ }
196
+
197
+ export default function CodeBlockStringContent(props: Props): JSX.Element;
198
+ }
199
+
200
+ declare module '@theme/CodeBlock/Line' {
201
+ import type {ComponentProps} from 'react';
202
+ import type Highlight from 'prism-react-renderer';
203
+
204
+ // Lib does not make this easy
205
+ type RenderProps = Parameters<
206
+ ComponentProps<typeof Highlight>['children']
207
+ >[0];
208
+ type GetLineProps = RenderProps['getLineProps'];
209
+ type GetTokenProps = RenderProps['getTokenProps'];
210
+ type Token = RenderProps['tokens'][number][number];
211
+
212
+ export interface Props {
213
+ readonly line: Token[];
214
+ readonly highlight: boolean;
215
+ readonly showLineNumbers: boolean;
216
+ readonly getLineProps: GetLineProps;
217
+ readonly getTokenProps: GetTokenProps;
218
+ }
219
+
220
+ export default function CodeBlockLine(props: Props): JSX.Element;
221
+ }
222
+
173
223
  declare module '@theme/DocCard' {
174
224
  import type {PropSidebarItem} from '@docusaurus/plugin-content-docs';
175
225