@docusaurus/theme-classic 3.7.0 → 3.8.0

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.
Files changed (136) hide show
  1. package/lib/getSwizzleConfig.js +1 -1
  2. package/lib/index.js +9 -0
  3. package/lib/inlineScripts.js +6 -27
  4. package/lib/inlineSvgSprites.d.ts +7 -0
  5. package/lib/inlineSvgSprites.js +14 -0
  6. package/lib/options.js +5 -0
  7. package/lib/theme/AnnouncementBar/index.js +6 -2
  8. package/lib/theme/CodeBlock/{WordWrapButton → Buttons/Button}/index.d.ts +2 -2
  9. package/lib/theme/CodeBlock/Buttons/Button/index.js +13 -0
  10. package/lib/theme/CodeBlock/Buttons/CopyButton/index.d.ts +9 -0
  11. package/lib/theme/CodeBlock/{CopyButton → Buttons/CopyButton}/index.js +36 -25
  12. package/lib/theme/CodeBlock/Buttons/WordWrapButton/index.d.ts +9 -0
  13. package/lib/theme/CodeBlock/{WordWrapButton → Buttons/WordWrapButton}/index.js +12 -7
  14. package/lib/theme/CodeBlock/{CopyButton → Buttons}/index.d.ts +2 -2
  15. package/lib/theme/CodeBlock/Buttons/index.js +27 -0
  16. package/lib/theme/CodeBlock/Buttons/styles.module.css +37 -0
  17. package/lib/theme/CodeBlock/Content/Element.js +4 -2
  18. package/lib/theme/CodeBlock/Content/String.d.ts +1 -1
  19. package/lib/theme/CodeBlock/Content/String.js +22 -92
  20. package/lib/theme/CodeBlock/Content/index.d.ts +9 -0
  21. package/lib/theme/CodeBlock/Content/index.js +74 -0
  22. package/lib/theme/CodeBlock/Content/styles.module.css +0 -52
  23. package/lib/theme/CodeBlock/Layout/index.d.ts +9 -0
  24. package/lib/theme/CodeBlock/Layout/index.js +30 -0
  25. package/lib/theme/CodeBlock/Layout/styles.module.css +27 -0
  26. package/lib/theme/CodeBlock/Line/Token/index.d.ts +9 -0
  27. package/lib/theme/CodeBlock/Line/Token/index.js +11 -0
  28. package/lib/theme/CodeBlock/Line/index.d.ts +1 -1
  29. package/lib/theme/CodeBlock/Line/index.js +21 -7
  30. package/lib/theme/CodeBlock/Title/index.d.ts +9 -0
  31. package/lib/theme/CodeBlock/Title/index.js +10 -0
  32. package/lib/theme/ColorModeToggle/index.d.ts +1 -1
  33. package/lib/theme/ColorModeToggle/index.js +85 -27
  34. package/lib/theme/ColorModeToggle/styles.module.css +7 -2
  35. package/lib/theme/DocBreadcrumbs/StructuredData/index.d.ts +9 -0
  36. package/lib/theme/DocBreadcrumbs/StructuredData/index.js +21 -0
  37. package/lib/theme/DocBreadcrumbs/index.js +36 -54
  38. package/lib/theme/DocCard/index.js +6 -4
  39. package/lib/theme/DocCardList/index.js +12 -6
  40. package/lib/theme/DocCardList/styles.module.css +14 -0
  41. package/lib/theme/DocCategoryGeneratedIndexPage/index.js +1 -1
  42. package/lib/theme/DocCategoryGeneratedIndexPage/styles.module.css +0 -8
  43. package/lib/theme/DocItem/Paginator/index.js +7 -1
  44. package/lib/theme/DocPaginator/index.js +3 -2
  45. package/lib/theme/DocSidebarItem/Category/index.js +8 -1
  46. package/lib/theme/Footer/Layout/index.js +2 -1
  47. package/lib/theme/Footer/Links/MultiColumn/index.js +7 -1
  48. package/lib/theme/Icon/ExternalLink/index.js +4 -5
  49. package/lib/theme/Icon/SystemColorMode/index.d.ts +9 -0
  50. package/lib/theme/Icon/SystemColorMode/index.js +16 -0
  51. package/lib/theme/Layout/index.js +1 -0
  52. package/lib/theme/Navbar/ColorModeToggle/index.js +5 -4
  53. package/lib/theme/Navbar/Content/index.js +20 -3
  54. package/lib/theme/Navbar/Content/styles.module.css +8 -0
  55. package/lib/theme/Navbar/Layout/index.js +2 -1
  56. package/lib/theme/Navbar/MobileSidebar/Layout/index.js +35 -4
  57. package/lib/theme/NavbarItem/DefaultNavbarItem/Desktop/index.d.ts +9 -0
  58. package/lib/theme/NavbarItem/DefaultNavbarItem/Desktop/index.js +29 -0
  59. package/lib/theme/NavbarItem/DefaultNavbarItem/Mobile/index.d.ts +9 -0
  60. package/lib/theme/NavbarItem/DefaultNavbarItem/Mobile/index.js +20 -0
  61. package/lib/theme/NavbarItem/DefaultNavbarItem/index.js +25 -0
  62. package/lib/theme/NavbarItem/DocsVersionDropdownNavbarItem.d.ts +1 -1
  63. package/lib/theme/NavbarItem/DocsVersionDropdownNavbarItem.js +50 -7
  64. package/lib/theme/NavbarItem/DropdownNavbarItem/Desktop/index.d.ts +9 -0
  65. package/lib/theme/NavbarItem/DropdownNavbarItem/Desktop/index.js +74 -0
  66. package/lib/theme/NavbarItem/DropdownNavbarItem/Mobile/index.d.ts +10 -0
  67. package/lib/theme/NavbarItem/DropdownNavbarItem/Mobile/index.js +142 -0
  68. package/lib/theme/NavbarItem/DropdownNavbarItem/index.js +3 -142
  69. package/lib/theme/Tag/index.js +1 -0
  70. package/lib/theme/ThemeProvider/TitleFormatter/index.d.ts +9 -0
  71. package/lib/theme/ThemeProvider/TitleFormatter/index.js +19 -0
  72. package/lib/theme/ThemeProvider/index.d.ts +9 -0
  73. package/lib/theme/ThemeProvider/index.js +11 -0
  74. package/package.json +15 -15
  75. package/src/getSwizzleConfig.ts +1 -1
  76. package/src/index.ts +9 -0
  77. package/src/inlineScripts.ts +6 -27
  78. package/src/inlineSvgSprites.ts +12 -0
  79. package/src/options.ts +15 -0
  80. package/src/theme/AnnouncementBar/index.tsx +6 -2
  81. package/src/theme/CodeBlock/Buttons/Button/index.tsx +19 -0
  82. package/src/theme/CodeBlock/{CopyButton → Buttons/CopyButton}/index.tsx +42 -26
  83. package/src/theme/CodeBlock/{WordWrapButton → Buttons/WordWrapButton}/index.tsx +15 -12
  84. package/src/theme/CodeBlock/Buttons/index.tsx +32 -0
  85. package/src/theme/CodeBlock/Buttons/styles.module.css +37 -0
  86. package/src/theme/CodeBlock/Content/Element.tsx +4 -2
  87. package/src/theme/CodeBlock/Content/String.tsx +24 -101
  88. package/src/theme/CodeBlock/Content/index.tsx +84 -0
  89. package/src/theme/CodeBlock/Content/styles.module.css +0 -52
  90. package/src/theme/CodeBlock/Layout/index.tsx +34 -0
  91. package/src/theme/CodeBlock/Layout/styles.module.css +27 -0
  92. package/src/theme/CodeBlock/Line/Token/index.tsx +18 -0
  93. package/src/theme/CodeBlock/Line/index.tsx +26 -7
  94. package/src/theme/CodeBlock/Title/index.tsx +15 -0
  95. package/src/theme/ColorModeToggle/index.tsx +102 -32
  96. package/src/theme/ColorModeToggle/styles.module.css +7 -2
  97. package/src/theme/DocBreadcrumbs/StructuredData/index.tsx +24 -0
  98. package/src/theme/DocBreadcrumbs/index.tsx +35 -57
  99. package/src/theme/DocCard/index.tsx +8 -2
  100. package/src/theme/DocCardList/index.tsx +18 -7
  101. package/src/theme/DocCardList/styles.module.css +14 -0
  102. package/src/theme/DocCategoryGeneratedIndexPage/index.tsx +1 -1
  103. package/src/theme/DocCategoryGeneratedIndexPage/styles.module.css +0 -8
  104. package/src/theme/DocItem/Paginator/index.tsx +7 -1
  105. package/src/theme/DocPaginator/index.tsx +3 -2
  106. package/src/theme/DocSidebarItem/Category/index.tsx +8 -1
  107. package/src/theme/Footer/Layout/index.tsx +2 -1
  108. package/src/theme/Footer/Links/MultiColumn/index.tsx +7 -1
  109. package/src/theme/Icon/ExternalLink/index.tsx +5 -5
  110. package/src/theme/Icon/SystemColorMode/index.tsx +20 -0
  111. package/src/theme/Layout/index.tsx +1 -0
  112. package/src/theme/Navbar/ColorModeToggle/index.tsx +5 -4
  113. package/src/theme/Navbar/Content/index.tsx +20 -3
  114. package/src/theme/Navbar/Content/styles.module.css +8 -0
  115. package/src/theme/Navbar/Layout/index.tsx +2 -1
  116. package/src/theme/Navbar/MobileSidebar/Layout/index.tsx +43 -4
  117. package/src/theme/NavbarItem/DefaultNavbarItem/Desktop/index.tsx +34 -0
  118. package/src/theme/NavbarItem/DefaultNavbarItem/Mobile/index.tsx +23 -0
  119. package/src/theme/NavbarItem/DefaultNavbarItem/index.tsx +28 -0
  120. package/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx +87 -9
  121. package/src/theme/NavbarItem/DropdownNavbarItem/Desktop/index.tsx +86 -0
  122. package/src/theme/NavbarItem/DropdownNavbarItem/Mobile/index.tsx +166 -0
  123. package/src/theme/NavbarItem/DropdownNavbarItem/index.tsx +4 -168
  124. package/src/theme/Tag/index.tsx +1 -0
  125. package/src/theme/ThemeProvider/TitleFormatter/index.tsx +27 -0
  126. package/src/theme/ThemeProvider/index.tsx +14 -0
  127. package/src/theme-classic.d.ts +175 -20
  128. package/lib/theme/NavbarItem/DefaultNavbarItem.js +0 -52
  129. package/src/theme/NavbarItem/DefaultNavbarItem.tsx +0 -66
  130. /package/lib/theme/CodeBlock/{CopyButton → Buttons/CopyButton}/styles.module.css +0 -0
  131. /package/lib/theme/CodeBlock/{WordWrapButton → Buttons/WordWrapButton}/styles.module.css +0 -0
  132. /package/lib/theme/NavbarItem/{DefaultNavbarItem.d.ts → DefaultNavbarItem/index.d.ts} +0 -0
  133. /package/lib/theme/NavbarItem/DropdownNavbarItem/{styles.module.css → Mobile/styles.module.css} +0 -0
  134. /package/src/theme/CodeBlock/{CopyButton → Buttons/CopyButton}/styles.module.css +0 -0
  135. /package/src/theme/CodeBlock/{WordWrapButton → Buttons/WordWrapButton}/styles.module.css +0 -0
  136. /package/src/theme/NavbarItem/DropdownNavbarItem/{styles.module.css → Mobile/styles.module.css} +0 -0
@@ -148,7 +148,7 @@ function getSwizzleConfig() {
148
148
  'CodeBlock/Content': {
149
149
  actions: {
150
150
  eject: 'unsafe',
151
- wrap: 'forbidden',
151
+ wrap: 'unsafe',
152
152
  },
153
153
  description: 'The folder containing components responsible for rendering different types of CodeBlock content.',
154
154
  },
package/lib/index.js CHANGED
@@ -14,6 +14,7 @@ const rtlcss_1 = tslib_1.__importDefault(require("rtlcss"));
14
14
  const theme_translations_1 = require("@docusaurus/theme-translations");
15
15
  const translations_1 = require("./translations");
16
16
  const inlineScripts_1 = require("./inlineScripts");
17
+ const inlineSvgSprites_1 = require("./inlineSvgSprites");
17
18
  function getInfimaCSSFile(direction) {
18
19
  return `infima/dist/css/default/default${direction === 'rtl' ? '-rtl' : ''}.css`;
19
20
  }
@@ -85,6 +86,14 @@ function themeClassic(context, options) {
85
86
  injectHtmlTags() {
86
87
  return {
87
88
  preBodyTags: [
89
+ {
90
+ tagName: 'svg',
91
+ attributes: {
92
+ xmlns: 'http://www.w3.org/2000/svg',
93
+ style: 'display: none;',
94
+ },
95
+ innerHTML: inlineSvgSprites_1.SvgSpriteDefs,
96
+ },
88
97
  {
89
98
  tagName: 'script',
90
99
  innerHTML: `
@@ -22,43 +22,22 @@ function getThemeInlineScript({ colorMode: { defaultMode, respectPrefersColorSch
22
22
  return `(function() {
23
23
  var defaultMode = '${defaultMode}';
24
24
  var respectPrefersColorScheme = ${respectPrefersColorScheme};
25
-
26
- function setDataThemeAttribute(theme) {
27
- document.documentElement.setAttribute('data-theme', theme);
25
+ function getSystemColorMode() {
26
+ return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
28
27
  }
29
-
30
28
  function getQueryStringTheme() {
31
29
  try {
32
30
  return new URLSearchParams(window.location.search).get('${ThemeQueryStringKey}')
33
- } catch (e) {
34
- }
31
+ } catch (e) {}
35
32
  }
36
-
37
33
  function getStoredTheme() {
38
34
  try {
39
35
  return window['${siteStorage.type}'].getItem('${themeStorageKey}');
40
- } catch (err) {
41
- }
36
+ } catch (err) {}
42
37
  }
43
-
44
38
  var initialTheme = getQueryStringTheme() || getStoredTheme();
45
- if (initialTheme !== null) {
46
- setDataThemeAttribute(initialTheme);
47
- } else {
48
- if (
49
- respectPrefersColorScheme &&
50
- window.matchMedia('(prefers-color-scheme: dark)').matches
51
- ) {
52
- setDataThemeAttribute('dark');
53
- } else if (
54
- respectPrefersColorScheme &&
55
- window.matchMedia('(prefers-color-scheme: light)').matches
56
- ) {
57
- setDataThemeAttribute('light');
58
- } else {
59
- setDataThemeAttribute(defaultMode === 'dark' ? 'dark' : 'light');
60
- }
61
- }
39
+ document.documentElement.setAttribute('data-theme', initialTheme || (respectPrefersColorScheme ? getSystemColorMode() : defaultMode));
40
+ document.documentElement.setAttribute('data-theme-choice', initialTheme || (respectPrefersColorScheme ? 'system' : defaultMode));
62
41
  })();`;
63
42
  }
64
43
  /* language=js */
@@ -0,0 +1,7 @@
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
+ export declare const SvgSpriteDefs = "<defs>\n<symbol id=\"theme-svg-external-link\" viewBox=\"0 0 24 24\"><path fill=\"currentColor\" d=\"M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z\" /></symbol>\n</defs>";
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Facebook, Inc. and its affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.SvgSpriteDefs = void 0;
10
+ // For icons that are heavily repeated in the static html output
11
+ // See also https://github.com/facebook/docusaurus/issues/5865
12
+ exports.SvgSpriteDefs = `<defs>
13
+ <symbol id="theme-svg-external-link" viewBox="0 0 24 24"><path fill="currentColor" d="M21 13v10h-21v-19h12v2h-10v15h17v-8h2zm3-12h-10.988l4.035 4-6.977 7.07 2.828 2.828 6.977-7.07 4.125 4.172v-11z" /></symbol>
14
+ </defs>`;
package/lib/options.js CHANGED
@@ -182,6 +182,11 @@ const DocsVersionDropdownNavbarItemSchema = NavbarItemBaseSchema.append({
182
182
  dropdownActiveClassDisabled: utils_validation_1.Joi.boolean(),
183
183
  dropdownItemsBefore: utils_validation_1.Joi.array().items(DropdownSubitemSchema).default([]),
184
184
  dropdownItemsAfter: utils_validation_1.Joi.array().items(DropdownSubitemSchema).default([]),
185
+ versions: utils_validation_1.Joi.alternatives().try(utils_validation_1.Joi.array().items(utils_validation_1.Joi.string().min(1)).min(1), utils_validation_1.Joi.object()
186
+ .pattern(utils_validation_1.Joi.string().min(1), utils_validation_1.Joi.object({
187
+ label: utils_validation_1.Joi.string().min(1),
188
+ }))
189
+ .min(1)),
185
190
  });
186
191
  const LocaleDropdownNavbarItemSchema = NavbarItemBaseSchema.append({
187
192
  type: utils_validation_1.Joi.string().equal('localeDropdown').required(),
@@ -5,7 +5,8 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import React from 'react';
8
- import {useThemeConfig} from '@docusaurus/theme-common';
8
+ import clsx from 'clsx';
9
+ import {ThemeClassNames, useThemeConfig} from '@docusaurus/theme-common';
9
10
  import {useAnnouncementBar} from '@docusaurus/theme-common/internal';
10
11
  import AnnouncementBarCloseButton from '@theme/AnnouncementBar/CloseButton';
11
12
  import AnnouncementBarContent from '@theme/AnnouncementBar/Content';
@@ -19,7 +20,10 @@ export default function AnnouncementBar() {
19
20
  const {backgroundColor, textColor, isCloseable} = announcementBar;
20
21
  return (
21
22
  <div
22
- className={styles.announcementBar}
23
+ className={clsx(
24
+ ThemeClassNames.announcementBar.container,
25
+ styles.announcementBar,
26
+ )}
23
27
  style={{backgroundColor, color: textColor}}
24
28
  role="banner">
25
29
  {isCloseable && <div className={styles.announcementBarPlaceholder} />}
@@ -5,5 +5,5 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import { type ReactNode } from 'react';
8
- import type { Props } from '@theme/CodeBlock/WordWrapButton';
9
- export default function WordWrapButton({ className, onClick, isEnabled, }: Props): ReactNode;
8
+ import type { Props } from '@theme/CodeBlock/Buttons/Button';
9
+ export default function CodeBlockButton({ className, ...props }: Props): ReactNode;
@@ -0,0 +1,13 @@
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
+ export default function CodeBlockButton({className, ...props}) {
10
+ return (
11
+ <button type="button" {...props} className={clsx('clean-btn', className)} />
12
+ );
13
+ }
@@ -0,0 +1,9 @@
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 { type ReactNode } from 'react';
8
+ import type { Props } from '@theme/CodeBlock/Buttons/CopyButton';
9
+ export default function CopyButton({ className }: Props): ReactNode;
@@ -8,13 +8,38 @@ import React, {useCallback, useState, useRef, useEffect} from 'react';
8
8
  import clsx from 'clsx';
9
9
  import copy from 'copy-text-to-clipboard';
10
10
  import {translate} from '@docusaurus/Translate';
11
+ import {useCodeBlockContext} from '@docusaurus/theme-common/internal';
12
+ import Button from '@theme/CodeBlock/Buttons/Button';
11
13
  import IconCopy from '@theme/Icon/Copy';
12
14
  import IconSuccess from '@theme/Icon/Success';
13
15
  import styles from './styles.module.css';
14
- export default function CopyButton({code, className}) {
16
+ function title() {
17
+ return translate({
18
+ id: 'theme.CodeBlock.copy',
19
+ message: 'Copy',
20
+ description: 'The copy button label on code blocks',
21
+ });
22
+ }
23
+ function ariaLabel(isCopied) {
24
+ return isCopied
25
+ ? translate({
26
+ id: 'theme.CodeBlock.copied',
27
+ message: 'Copied',
28
+ description: 'The copied button label on code blocks',
29
+ })
30
+ : translate({
31
+ id: 'theme.CodeBlock.copyButtonAriaLabel',
32
+ message: 'Copy code to clipboard',
33
+ description: 'The ARIA label for copy code blocks button',
34
+ });
35
+ }
36
+ function useCopyButton() {
37
+ const {
38
+ metadata: {code},
39
+ } = useCodeBlockContext();
15
40
  const [isCopied, setIsCopied] = useState(false);
16
41
  const copyTimeout = useRef(undefined);
17
- const handleCopyCode = useCallback(() => {
42
+ const copyCode = useCallback(() => {
18
43
  copy(code);
19
44
  setIsCopied(true);
20
45
  copyTimeout.current = window.setTimeout(() => {
@@ -22,38 +47,24 @@ export default function CopyButton({code, className}) {
22
47
  }, 1000);
23
48
  }, [code]);
24
49
  useEffect(() => () => window.clearTimeout(copyTimeout.current), []);
50
+ return {copyCode, isCopied};
51
+ }
52
+ export default function CopyButton({className}) {
53
+ const {copyCode, isCopied} = useCopyButton();
25
54
  return (
26
- <button
27
- type="button"
28
- aria-label={
29
- isCopied
30
- ? translate({
31
- id: 'theme.CodeBlock.copied',
32
- message: 'Copied',
33
- description: 'The copied button label on code blocks',
34
- })
35
- : translate({
36
- id: 'theme.CodeBlock.copyButtonAriaLabel',
37
- message: 'Copy code to clipboard',
38
- description: 'The ARIA label for copy code blocks button',
39
- })
40
- }
41
- title={translate({
42
- id: 'theme.CodeBlock.copy',
43
- message: 'Copy',
44
- description: 'The copy button label on code blocks',
45
- })}
55
+ <Button
56
+ aria-label={ariaLabel(isCopied)}
57
+ title={title()}
46
58
  className={clsx(
47
- 'clean-btn',
48
59
  className,
49
60
  styles.copyButton,
50
61
  isCopied && styles.copyButtonCopied,
51
62
  )}
52
- onClick={handleCopyCode}>
63
+ onClick={copyCode}>
53
64
  <span className={styles.copyButtonIcons} aria-hidden="true">
54
65
  <IconCopy className={styles.copyButtonIcon} />
55
66
  <IconSuccess className={styles.copyButtonSuccessIcon} />
56
67
  </span>
57
- </button>
68
+ </Button>
58
69
  );
59
70
  }
@@ -0,0 +1,9 @@
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 { type ReactNode } from 'react';
8
+ import type { Props } from '@theme/CodeBlock/Buttons/WordWrapButton';
9
+ export default function WordWrapButton({ className }: Props): ReactNode;
@@ -7,9 +7,16 @@
7
7
  import React from 'react';
8
8
  import clsx from 'clsx';
9
9
  import {translate} from '@docusaurus/Translate';
10
+ import {useCodeBlockContext} from '@docusaurus/theme-common/internal';
11
+ import Button from '@theme/CodeBlock/Buttons/Button';
10
12
  import IconWordWrap from '@theme/Icon/WordWrap';
11
13
  import styles from './styles.module.css';
12
- export default function WordWrapButton({className, onClick, isEnabled}) {
14
+ export default function WordWrapButton({className}) {
15
+ const {wordWrap} = useCodeBlockContext();
16
+ const canShowButton = wordWrap.isEnabled || wordWrap.isCodeScrollable;
17
+ if (!canShowButton) {
18
+ return false;
19
+ }
13
20
  const title = translate({
14
21
  id: 'theme.CodeBlock.wordWrapToggle',
15
22
  message: 'Toggle word wrap',
@@ -17,17 +24,15 @@ export default function WordWrapButton({className, onClick, isEnabled}) {
17
24
  'The title attribute for toggle word wrapping button of code block lines',
18
25
  });
19
26
  return (
20
- <button
21
- type="button"
22
- onClick={onClick}
27
+ <Button
28
+ onClick={() => wordWrap.toggle()}
23
29
  className={clsx(
24
- 'clean-btn',
25
30
  className,
26
- isEnabled && styles.wordWrapButtonEnabled,
31
+ wordWrap.isEnabled && styles.wordWrapButtonEnabled,
27
32
  )}
28
33
  aria-label={title}
29
34
  title={title}>
30
35
  <IconWordWrap className={styles.wordWrapButtonIcon} aria-hidden="true" />
31
- </button>
36
+ </Button>
32
37
  );
33
38
  }
@@ -5,5 +5,5 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import { type ReactNode } from 'react';
8
- import type { Props } from '@theme/CodeBlock/CopyButton';
9
- export default function CopyButton({ code, className }: Props): ReactNode;
8
+ import type { Props } from '@theme/CodeBlock/Buttons';
9
+ export default function CodeBlockButtons({ className }: Props): ReactNode;
@@ -0,0 +1,27 @@
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 BrowserOnly from '@docusaurus/BrowserOnly';
10
+ import CopyButton from '@theme/CodeBlock/Buttons/CopyButton';
11
+ import WordWrapButton from '@theme/CodeBlock/Buttons/WordWrapButton';
12
+ import styles from './styles.module.css';
13
+ // Code block buttons are not server-rendered on purpose
14
+ // Adding them to the initial HTML is useless and expensive (due to JSX SVG)
15
+ // They are hidden by default and require React to become interactive
16
+ export default function CodeBlockButtons({className}) {
17
+ return (
18
+ <BrowserOnly>
19
+ {() => (
20
+ <div className={clsx(className, styles.buttonGroup)}>
21
+ <WordWrapButton />
22
+ <CopyButton />
23
+ </div>
24
+ )}
25
+ </BrowserOnly>
26
+ );
27
+ }
@@ -0,0 +1,37 @@
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
+ .buttonGroup {
9
+ display: flex;
10
+ column-gap: 0.2rem;
11
+ position: absolute;
12
+ /* rtl:ignore */
13
+ right: calc(var(--ifm-pre-padding) / 2);
14
+ top: calc(var(--ifm-pre-padding) / 2);
15
+ }
16
+
17
+ .buttonGroup button {
18
+ display: flex;
19
+ align-items: center;
20
+ background: var(--prism-background-color);
21
+ color: var(--prism-color);
22
+ border: 1px solid var(--ifm-color-emphasis-300);
23
+ border-radius: var(--ifm-global-radius);
24
+ padding: 0.4rem;
25
+ line-height: 0;
26
+ transition: opacity var(--ifm-transition-fast) ease-in-out;
27
+ opacity: 0;
28
+ }
29
+
30
+ .buttonGroup button:focus-visible,
31
+ .buttonGroup button:hover {
32
+ opacity: 1 !important;
33
+ }
34
+
35
+ :global(.theme-code-block:hover) .buttonGroup button {
36
+ opacity: 0.4;
37
+ }
@@ -8,8 +8,10 @@ import React from 'react';
8
8
  import clsx from 'clsx';
9
9
  import Container from '@theme/CodeBlock/Container';
10
10
  import styles from './styles.module.css';
11
- // <pre> tags in markdown map to CodeBlocks. They may contain JSX children. When
12
- // the children is not a simple string, we just return a styled block without
11
+ // TODO Docusaurus v4: move this component at the root?
12
+ // This component only handles a rare edge-case: <pre><MyComp/></pre> in MDX
13
+ // <pre> tags in markdown map to CodeBlocks. They may contain JSX children.
14
+ // When children is not a simple string, we just return a styled block without
13
15
  // actually highlighting.
14
16
  export default function CodeBlockJSX({children, className}) {
15
17
  return (
@@ -6,4 +6,4 @@
6
6
  */
7
7
  import { type ReactNode } from 'react';
8
8
  import type { Props } from '@theme/CodeBlock/Content/String';
9
- export default function CodeBlockString({ children, className: blockClassName, metastring, title: titleProp, showLineNumbers: showLineNumbersProp, language: languageProp, }: Props): ReactNode;
9
+ export default function CodeBlockString(props: Props): ReactNode;
@@ -5,103 +5,33 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import React from 'react';
8
- import clsx from 'clsx';
9
- import {useThemeConfig, usePrismTheme} from '@docusaurus/theme-common';
8
+ import {useThemeConfig} from '@docusaurus/theme-common';
10
9
  import {
11
- parseCodeBlockTitle,
12
- parseLanguage,
13
- parseLines,
14
- containsLineNumbers,
10
+ CodeBlockContextProvider,
11
+ createCodeBlockMetadata,
15
12
  useCodeWordWrap,
16
13
  } from '@docusaurus/theme-common/internal';
17
- import {Highlight} from 'prism-react-renderer';
18
- import Line from '@theme/CodeBlock/Line';
19
- import CopyButton from '@theme/CodeBlock/CopyButton';
20
- import WordWrapButton from '@theme/CodeBlock/WordWrapButton';
21
- import Container from '@theme/CodeBlock/Container';
22
- import styles from './styles.module.css';
23
- // Prism languages are always lowercase
24
- // We want to fail-safe and allow both "php" and "PHP"
25
- // See https://github.com/facebook/docusaurus/issues/9012
26
- function normalizeLanguage(language) {
27
- return language?.toLowerCase();
14
+ import CodeBlockLayout from '@theme/CodeBlock/Layout';
15
+ function useCodeBlockMetadata(props) {
16
+ const {prism} = useThemeConfig();
17
+ return createCodeBlockMetadata({
18
+ code: props.children,
19
+ className: props.className,
20
+ metastring: props.metastring,
21
+ magicComments: prism.magicComments,
22
+ defaultLanguage: prism.defaultLanguage,
23
+ language: props.language,
24
+ title: props.title,
25
+ showLineNumbers: props.showLineNumbers,
26
+ });
28
27
  }
29
- export default function CodeBlockString({
30
- children,
31
- className: blockClassName = '',
32
- metastring,
33
- title: titleProp,
34
- showLineNumbers: showLineNumbersProp,
35
- language: languageProp,
36
- }) {
37
- const {
38
- prism: {defaultLanguage, magicComments},
39
- } = useThemeConfig();
40
- const language = normalizeLanguage(
41
- languageProp ?? parseLanguage(blockClassName) ?? defaultLanguage,
42
- );
43
- const prismTheme = usePrismTheme();
28
+ // TODO Docusaurus v4: move this component at the root?
29
+ export default function CodeBlockString(props) {
30
+ const metadata = useCodeBlockMetadata(props);
44
31
  const wordWrap = useCodeWordWrap();
45
- // We still parse the metastring in case we want to support more syntax in the
46
- // future. Note that MDX doesn't strip quotes when parsing metastring:
47
- // "title=\"xyz\"" => title: "\"xyz\""
48
- const title = parseCodeBlockTitle(metastring) || titleProp;
49
- const {lineClassNames, code} = parseLines(children, {
50
- metastring,
51
- language,
52
- magicComments,
53
- });
54
- const showLineNumbers =
55
- showLineNumbersProp ?? containsLineNumbers(metastring);
56
32
  return (
57
- <Container
58
- as="div"
59
- className={clsx(
60
- blockClassName,
61
- language &&
62
- !blockClassName.includes(`language-${language}`) &&
63
- `language-${language}`,
64
- )}>
65
- {title && <div className={styles.codeBlockTitle}>{title}</div>}
66
- <div className={styles.codeBlockContent}>
67
- <Highlight theme={prismTheme} code={code} language={language ?? 'text'}>
68
- {({className, style, tokens, getLineProps, getTokenProps}) => (
69
- <pre
70
- /* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
71
- tabIndex={0}
72
- ref={wordWrap.codeBlockRef}
73
- className={clsx(className, styles.codeBlock, 'thin-scrollbar')}
74
- style={style}>
75
- <code
76
- className={clsx(
77
- styles.codeBlockLines,
78
- showLineNumbers && styles.codeBlockLinesWithNumbering,
79
- )}>
80
- {tokens.map((line, i) => (
81
- <Line
82
- key={i}
83
- line={line}
84
- getLineProps={getLineProps}
85
- getTokenProps={getTokenProps}
86
- classNames={lineClassNames[i]}
87
- showLineNumbers={showLineNumbers}
88
- />
89
- ))}
90
- </code>
91
- </pre>
92
- )}
93
- </Highlight>
94
- <div className={styles.buttonGroup}>
95
- {(wordWrap.isEnabled || wordWrap.isCodeScrollable) && (
96
- <WordWrapButton
97
- className={styles.codeButton}
98
- onClick={() => wordWrap.toggle()}
99
- isEnabled={wordWrap.isEnabled}
100
- />
101
- )}
102
- <CopyButton className={styles.codeButton} code={code} />
103
- </div>
104
- </div>
105
- </Container>
33
+ <CodeBlockContextProvider metadata={metadata} wordWrap={wordWrap}>
34
+ <CodeBlockLayout />
35
+ </CodeBlockContextProvider>
106
36
  );
107
37
  }
@@ -0,0 +1,9 @@
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 { type ReactNode } from 'react';
8
+ import type { Props } from '@theme/CodeBlock/Content';
9
+ export default function CodeBlockContent({ className: classNameProp, }: Props): ReactNode;
@@ -0,0 +1,74 @@
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 {useCodeBlockContext} from '@docusaurus/theme-common/internal';
10
+ import {usePrismTheme} from '@docusaurus/theme-common';
11
+ import {Highlight} from 'prism-react-renderer';
12
+ import Line from '@theme/CodeBlock/Line';
13
+ import styles from './styles.module.css';
14
+ // TODO Docusaurus v4: remove useless forwardRef
15
+ const Pre = React.forwardRef((props, ref) => {
16
+ return (
17
+ <pre
18
+ ref={ref}
19
+ /* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
20
+ tabIndex={0}
21
+ {...props}
22
+ className={clsx(props.className, styles.codeBlock, 'thin-scrollbar')}
23
+ />
24
+ );
25
+ });
26
+ function Code(props) {
27
+ const {metadata} = useCodeBlockContext();
28
+ return (
29
+ <code
30
+ {...props}
31
+ className={clsx(
32
+ props.className,
33
+ styles.codeBlockLines,
34
+ metadata.lineNumbersStart !== undefined &&
35
+ styles.codeBlockLinesWithNumbering,
36
+ )}
37
+ style={{
38
+ ...props.style,
39
+ counterReset:
40
+ metadata.lineNumbersStart === undefined
41
+ ? undefined
42
+ : `line-count ${metadata.lineNumbersStart - 1}`,
43
+ }}
44
+ />
45
+ );
46
+ }
47
+ export default function CodeBlockContent({className: classNameProp}) {
48
+ const {metadata, wordWrap} = useCodeBlockContext();
49
+ const prismTheme = usePrismTheme();
50
+ const {code, language, lineNumbersStart, lineClassNames} = metadata;
51
+ return (
52
+ <Highlight theme={prismTheme} code={code} language={language}>
53
+ {({className, style, tokens: lines, getLineProps, getTokenProps}) => (
54
+ <Pre
55
+ ref={wordWrap.codeBlockRef}
56
+ className={clsx(classNameProp, className)}
57
+ style={style}>
58
+ <Code>
59
+ {lines.map((line, i) => (
60
+ <Line
61
+ key={i}
62
+ line={line}
63
+ getLineProps={getLineProps}
64
+ getTokenProps={getTokenProps}
65
+ classNames={lineClassNames[i]}
66
+ showLineNumbers={lineNumbersStart !== undefined}
67
+ />
68
+ ))}
69
+ </Code>
70
+ </Pre>
71
+ )}
72
+ </Highlight>
73
+ );
74
+ }