@docusaurus/theme-classic 3.7.0-canary-6252 → 3.7.0-canary-6255

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.
@@ -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 */
@@ -6,6 +6,6 @@
6
6
  */
7
7
  import React, { type ReactNode } from 'react';
8
8
  import type { Props } from '@theme/ColorModeToggle';
9
- declare function ColorModeToggle({ className, buttonClassName, value, onChange, }: Props): ReactNode;
9
+ declare function ColorModeToggle({ className, buttonClassName, respectPrefersColorScheme, value, onChange, }: Props): ReactNode;
10
10
  declare const _default: React.MemoExoticComponent<typeof ColorModeToggle>;
11
11
  export default _default;
@@ -10,30 +10,93 @@ import useIsBrowser from '@docusaurus/useIsBrowser';
10
10
  import {translate} from '@docusaurus/Translate';
11
11
  import IconLightMode from '@theme/Icon/LightMode';
12
12
  import IconDarkMode from '@theme/Icon/DarkMode';
13
+ import IconSystemColorMode from '@theme/Icon/SystemColorMode';
13
14
  import styles from './styles.module.css';
14
- function ColorModeToggle({className, buttonClassName, value, onChange}) {
15
- const isBrowser = useIsBrowser();
16
- const title = translate(
15
+ // The order of color modes is defined here, and can be customized with swizzle
16
+ function getNextColorMode(colorMode, respectPrefersColorScheme) {
17
+ // 2-value transition
18
+ if (!respectPrefersColorScheme) {
19
+ return colorMode === 'dark' ? 'light' : 'dark';
20
+ }
21
+ // 3-value transition
22
+ switch (colorMode) {
23
+ case null:
24
+ return 'light';
25
+ case 'light':
26
+ return 'dark';
27
+ case 'dark':
28
+ return null;
29
+ default:
30
+ throw new Error(`unexpected color mode ${colorMode}`);
31
+ }
32
+ }
33
+ function getColorModeLabel(colorMode) {
34
+ switch (colorMode) {
35
+ case null:
36
+ return translate({
37
+ message: 'system mode',
38
+ id: 'theme.colorToggle.ariaLabel.mode.system',
39
+ description: 'The name for the system color mode',
40
+ });
41
+ case 'light':
42
+ return translate({
43
+ message: 'light mode',
44
+ id: 'theme.colorToggle.ariaLabel.mode.light',
45
+ description: 'The name for the light color mode',
46
+ });
47
+ case 'dark':
48
+ return translate({
49
+ message: 'dark mode',
50
+ id: 'theme.colorToggle.ariaLabel.mode.dark',
51
+ description: 'The name for the dark color mode',
52
+ });
53
+ default:
54
+ throw new Error(`unexpected color mode ${colorMode}`);
55
+ }
56
+ }
57
+ function getColorModeAriaLabel(colorMode) {
58
+ return translate(
17
59
  {
18
60
  message: 'Switch between dark and light mode (currently {mode})',
19
61
  id: 'theme.colorToggle.ariaLabel',
20
- description: 'The ARIA label for the navbar color mode toggle',
62
+ description: 'The ARIA label for the color mode toggle',
21
63
  },
22
64
  {
23
- mode:
24
- value === 'dark'
25
- ? translate({
26
- message: 'dark mode',
27
- id: 'theme.colorToggle.ariaLabel.mode.dark',
28
- description: 'The name for the dark color mode',
29
- })
30
- : translate({
31
- message: 'light mode',
32
- id: 'theme.colorToggle.ariaLabel.mode.light',
33
- description: 'The name for the light color mode',
34
- }),
65
+ mode: getColorModeLabel(colorMode),
35
66
  },
36
67
  );
68
+ }
69
+ function CurrentColorModeIcon() {
70
+ // 3 icons are always rendered for technical reasons
71
+ // We use "data-theme-choice" to render the correct one
72
+ // This must work even before React hydrates
73
+ return (
74
+ <>
75
+ <IconLightMode
76
+ // a18y is handled at the button level,
77
+ // not relying on button content (svg icons)
78
+ aria-hidden
79
+ className={clsx(styles.toggleIcon, styles.lightToggleIcon)}
80
+ />
81
+ <IconDarkMode
82
+ aria-hidden
83
+ className={clsx(styles.toggleIcon, styles.darkToggleIcon)}
84
+ />
85
+ <IconSystemColorMode
86
+ aria-hidden
87
+ className={clsx(styles.toggleIcon, styles.systemToggleIcon)}
88
+ />
89
+ </>
90
+ );
91
+ }
92
+ function ColorModeToggle({
93
+ className,
94
+ buttonClassName,
95
+ respectPrefersColorScheme,
96
+ value,
97
+ onChange,
98
+ }) {
99
+ const isBrowser = useIsBrowser();
37
100
  return (
38
101
  <div className={clsx(styles.toggle, className)}>
39
102
  <button
@@ -44,18 +107,13 @@ function ColorModeToggle({className, buttonClassName, value, onChange}) {
44
107
  buttonClassName,
45
108
  )}
46
109
  type="button"
47
- onClick={() => onChange(value === 'dark' ? 'light' : 'dark')}
110
+ onClick={() =>
111
+ onChange(getNextColorMode(value, respectPrefersColorScheme))
112
+ }
48
113
  disabled={!isBrowser}
49
- title={title}
50
- aria-label={title}
51
- aria-live="polite"
52
- aria-pressed={value === 'dark' ? 'true' : 'false'}>
53
- <IconLightMode
54
- className={clsx(styles.toggleIcon, styles.lightToggleIcon)}
55
- />
56
- <IconDarkMode
57
- className={clsx(styles.toggleIcon, styles.darkToggleIcon)}
58
- />
114
+ title={getColorModeLabel(value)}
115
+ aria-label={getColorModeAriaLabel(value)}>
116
+ <CurrentColorModeIcon />
59
117
  </button>
60
118
  </div>
61
119
  );
@@ -25,11 +25,16 @@
25
25
  background: var(--ifm-color-emphasis-200);
26
26
  }
27
27
 
28
- [data-theme='light'] .darkToggleIcon,
29
- [data-theme='dark'] .lightToggleIcon {
28
+ .toggleIcon {
30
29
  display: none;
31
30
  }
32
31
 
32
+ [data-theme-choice='system'] .systemToggleIcon,
33
+ [data-theme-choice='light'] .lightToggleIcon,
34
+ [data-theme-choice='dark'] .darkToggleIcon {
35
+ display: initial;
36
+ }
37
+
33
38
  .toggleButtonDisabled {
34
39
  cursor: not-allowed;
35
40
  }
@@ -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/Icon/SystemColorMode';
9
+ export default function IconSystemColorMode(props: Props): ReactNode;
@@ -0,0 +1,16 @@
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 default function IconSystemColorMode(props) {
8
+ return (
9
+ <svg viewBox="0 0 24 24" width={24} height={24} {...props}>
10
+ <path
11
+ fill="currentColor"
12
+ d="m12 21c4.971 0 9-4.029 9-9s-4.029-9-9-9-9 4.029-9 9 4.029 9 9 9zm4.95-13.95c1.313 1.313 2.05 3.093 2.05 4.95s-0.738 3.637-2.05 4.95c-1.313 1.313-3.093 2.05-4.95 2.05v-14c1.857 0 3.637 0.737 4.95 2.05z"
13
+ />
14
+ </svg>
15
+ );
16
+ }
@@ -10,9 +10,9 @@ import ColorModeToggle from '@theme/ColorModeToggle';
10
10
  import styles from './styles.module.css';
11
11
  export default function NavbarColorModeToggle({className}) {
12
12
  const navbarStyle = useThemeConfig().navbar.style;
13
- const disabled = useThemeConfig().colorMode.disableSwitch;
14
- const {colorMode, setColorMode} = useColorMode();
15
- if (disabled) {
13
+ const {disableSwitch, respectPrefersColorScheme} = useThemeConfig().colorMode;
14
+ const {colorModeChoice, setColorMode} = useColorMode();
15
+ if (disableSwitch) {
16
16
  return null;
17
17
  }
18
18
  return (
@@ -21,7 +21,8 @@ export default function NavbarColorModeToggle({className}) {
21
21
  buttonClassName={
22
22
  navbarStyle === 'dark' ? styles.darkNavbarColorModeToggle : undefined
23
23
  }
24
- value={colorMode}
24
+ respectPrefersColorScheme={respectPrefersColorScheme}
25
+ value={colorModeChoice}
25
26
  onChange={setColorMode}
26
27
  />
27
28
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docusaurus/theme-classic",
3
- "version": "3.7.0-canary-6252",
3
+ "version": "3.7.0-canary-6255",
4
4
  "description": "Classic theme for Docusaurus",
5
5
  "main": "lib/index.js",
6
6
  "types": "src/theme-classic.d.ts",
@@ -20,19 +20,19 @@
20
20
  "copy:watch": "node ../../admin/scripts/copyUntypedFiles.js --watch"
21
21
  },
22
22
  "dependencies": {
23
- "@docusaurus/core": "3.7.0-canary-6252",
24
- "@docusaurus/logger": "3.7.0-canary-6252",
25
- "@docusaurus/mdx-loader": "3.7.0-canary-6252",
26
- "@docusaurus/module-type-aliases": "3.7.0-canary-6252",
27
- "@docusaurus/plugin-content-blog": "3.7.0-canary-6252",
28
- "@docusaurus/plugin-content-docs": "3.7.0-canary-6252",
29
- "@docusaurus/plugin-content-pages": "3.7.0-canary-6252",
30
- "@docusaurus/theme-common": "3.7.0-canary-6252",
31
- "@docusaurus/theme-translations": "3.7.0-canary-6252",
32
- "@docusaurus/types": "3.7.0-canary-6252",
33
- "@docusaurus/utils": "3.7.0-canary-6252",
34
- "@docusaurus/utils-common": "3.7.0-canary-6252",
35
- "@docusaurus/utils-validation": "3.7.0-canary-6252",
23
+ "@docusaurus/core": "3.7.0-canary-6255",
24
+ "@docusaurus/logger": "3.7.0-canary-6255",
25
+ "@docusaurus/mdx-loader": "3.7.0-canary-6255",
26
+ "@docusaurus/module-type-aliases": "3.7.0-canary-6255",
27
+ "@docusaurus/plugin-content-blog": "3.7.0-canary-6255",
28
+ "@docusaurus/plugin-content-docs": "3.7.0-canary-6255",
29
+ "@docusaurus/plugin-content-pages": "3.7.0-canary-6255",
30
+ "@docusaurus/theme-common": "3.7.0-canary-6255",
31
+ "@docusaurus/theme-translations": "3.7.0-canary-6255",
32
+ "@docusaurus/types": "3.7.0-canary-6255",
33
+ "@docusaurus/utils": "3.7.0-canary-6255",
34
+ "@docusaurus/utils-common": "3.7.0-canary-6255",
35
+ "@docusaurus/utils-validation": "3.7.0-canary-6255",
36
36
  "@mdx-js/react": "^3.0.0",
37
37
  "clsx": "^2.0.0",
38
38
  "copy-text-to-clipboard": "^3.2.0",
@@ -62,5 +62,5 @@
62
62
  "engines": {
63
63
  "node": ">=18.0"
64
64
  },
65
- "gitHead": "afaaedd499d872dcf54bcdcbe59749b1de7a941a"
65
+ "gitHead": "61f88f378e3791234f258cdc83201d0f3bda84c4"
66
66
  }
@@ -30,43 +30,22 @@ export function getThemeInlineScript({
30
30
  return `(function() {
31
31
  var defaultMode = '${defaultMode}';
32
32
  var respectPrefersColorScheme = ${respectPrefersColorScheme};
33
-
34
- function setDataThemeAttribute(theme) {
35
- document.documentElement.setAttribute('data-theme', theme);
33
+ function getSystemColorMode() {
34
+ return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
36
35
  }
37
-
38
36
  function getQueryStringTheme() {
39
37
  try {
40
38
  return new URLSearchParams(window.location.search).get('${ThemeQueryStringKey}')
41
- } catch (e) {
42
- }
39
+ } catch (e) {}
43
40
  }
44
-
45
41
  function getStoredTheme() {
46
42
  try {
47
43
  return window['${siteStorage.type}'].getItem('${themeStorageKey}');
48
- } catch (err) {
49
- }
44
+ } catch (err) {}
50
45
  }
51
-
52
46
  var initialTheme = getQueryStringTheme() || getStoredTheme();
53
- if (initialTheme !== null) {
54
- setDataThemeAttribute(initialTheme);
55
- } else {
56
- if (
57
- respectPrefersColorScheme &&
58
- window.matchMedia('(prefers-color-scheme: dark)').matches
59
- ) {
60
- setDataThemeAttribute('dark');
61
- } else if (
62
- respectPrefersColorScheme &&
63
- window.matchMedia('(prefers-color-scheme: light)').matches
64
- ) {
65
- setDataThemeAttribute('light');
66
- } else {
67
- setDataThemeAttribute(defaultMode === 'dark' ? 'dark' : 'light');
68
- }
69
- }
47
+ document.documentElement.setAttribute('data-theme', initialTheme || (respectPrefersColorScheme ? getSystemColorMode() : defaultMode));
48
+ document.documentElement.setAttribute('data-theme-choice', initialTheme || (respectPrefersColorScheme ? 'system' : defaultMode));
70
49
  })();`;
71
50
  }
72
51
 
@@ -11,40 +11,105 @@ import useIsBrowser from '@docusaurus/useIsBrowser';
11
11
  import {translate} from '@docusaurus/Translate';
12
12
  import IconLightMode from '@theme/Icon/LightMode';
13
13
  import IconDarkMode from '@theme/Icon/DarkMode';
14
+ import IconSystemColorMode from '@theme/Icon/SystemColorMode';
14
15
  import type {Props} from '@theme/ColorModeToggle';
16
+ import type {ColorMode} from '@docusaurus/theme-common';
15
17
 
16
18
  import styles from './styles.module.css';
17
19
 
18
- function ColorModeToggle({
19
- className,
20
- buttonClassName,
21
- value,
22
- onChange,
23
- }: Props): ReactNode {
24
- const isBrowser = useIsBrowser();
20
+ // The order of color modes is defined here, and can be customized with swizzle
21
+ function getNextColorMode(
22
+ colorMode: ColorMode | null,
23
+ respectPrefersColorScheme: boolean,
24
+ ) {
25
+ // 2-value transition
26
+ if (!respectPrefersColorScheme) {
27
+ return colorMode === 'dark' ? 'light' : 'dark';
28
+ }
25
29
 
26
- const title = translate(
30
+ // 3-value transition
31
+ switch (colorMode) {
32
+ case null:
33
+ return 'light';
34
+ case 'light':
35
+ return 'dark';
36
+ case 'dark':
37
+ return null;
38
+ default:
39
+ throw new Error(`unexpected color mode ${colorMode}`);
40
+ }
41
+ }
42
+
43
+ function getColorModeLabel(colorMode: ColorMode | null): string {
44
+ switch (colorMode) {
45
+ case null:
46
+ return translate({
47
+ message: 'system mode',
48
+ id: 'theme.colorToggle.ariaLabel.mode.system',
49
+ description: 'The name for the system color mode',
50
+ });
51
+ case 'light':
52
+ return translate({
53
+ message: 'light mode',
54
+ id: 'theme.colorToggle.ariaLabel.mode.light',
55
+ description: 'The name for the light color mode',
56
+ });
57
+ case 'dark':
58
+ return translate({
59
+ message: 'dark mode',
60
+ id: 'theme.colorToggle.ariaLabel.mode.dark',
61
+ description: 'The name for the dark color mode',
62
+ });
63
+ default:
64
+ throw new Error(`unexpected color mode ${colorMode}`);
65
+ }
66
+ }
67
+
68
+ function getColorModeAriaLabel(colorMode: ColorMode | null) {
69
+ return translate(
27
70
  {
28
71
  message: 'Switch between dark and light mode (currently {mode})',
29
72
  id: 'theme.colorToggle.ariaLabel',
30
- description: 'The ARIA label for the navbar color mode toggle',
73
+ description: 'The ARIA label for the color mode toggle',
31
74
  },
32
75
  {
33
- mode:
34
- value === 'dark'
35
- ? translate({
36
- message: 'dark mode',
37
- id: 'theme.colorToggle.ariaLabel.mode.dark',
38
- description: 'The name for the dark color mode',
39
- })
40
- : translate({
41
- message: 'light mode',
42
- id: 'theme.colorToggle.ariaLabel.mode.light',
43
- description: 'The name for the light color mode',
44
- }),
76
+ mode: getColorModeLabel(colorMode),
45
77
  },
46
78
  );
79
+ }
47
80
 
81
+ function CurrentColorModeIcon(): ReactNode {
82
+ // 3 icons are always rendered for technical reasons
83
+ // We use "data-theme-choice" to render the correct one
84
+ // This must work even before React hydrates
85
+ return (
86
+ <>
87
+ <IconLightMode
88
+ // a18y is handled at the button level,
89
+ // not relying on button content (svg icons)
90
+ aria-hidden
91
+ className={clsx(styles.toggleIcon, styles.lightToggleIcon)}
92
+ />
93
+ <IconDarkMode
94
+ aria-hidden
95
+ className={clsx(styles.toggleIcon, styles.darkToggleIcon)}
96
+ />
97
+ <IconSystemColorMode
98
+ aria-hidden
99
+ className={clsx(styles.toggleIcon, styles.systemToggleIcon)}
100
+ />
101
+ </>
102
+ );
103
+ }
104
+
105
+ function ColorModeToggle({
106
+ className,
107
+ buttonClassName,
108
+ respectPrefersColorScheme,
109
+ value,
110
+ onChange,
111
+ }: Props): ReactNode {
112
+ const isBrowser = useIsBrowser();
48
113
  return (
49
114
  <div className={clsx(styles.toggle, className)}>
50
115
  <button
@@ -55,18 +120,23 @@ function ColorModeToggle({
55
120
  buttonClassName,
56
121
  )}
57
122
  type="button"
58
- onClick={() => onChange(value === 'dark' ? 'light' : 'dark')}
123
+ onClick={() =>
124
+ onChange(getNextColorMode(value, respectPrefersColorScheme))
125
+ }
59
126
  disabled={!isBrowser}
60
- title={title}
61
- aria-label={title}
62
- aria-live="polite"
63
- aria-pressed={value === 'dark' ? 'true' : 'false'}>
64
- <IconLightMode
65
- className={clsx(styles.toggleIcon, styles.lightToggleIcon)}
66
- />
67
- <IconDarkMode
68
- className={clsx(styles.toggleIcon, styles.darkToggleIcon)}
69
- />
127
+ title={getColorModeLabel(value)}
128
+ aria-label={getColorModeAriaLabel(value)}
129
+
130
+ // For accessibility decisions
131
+ // See https://github.com/facebook/docusaurus/issues/7667#issuecomment-2724401796
132
+
133
+ // aria-live disabled on purpose - This is annoying because:
134
+ // - without this attribute, VoiceOver doesn't announce on button enter
135
+ // - with this attribute, VoiceOver announces twice on ctrl+opt+space
136
+ // - with this attribute, NVDA announces many times
137
+ // aria-live="polite"
138
+ >
139
+ <CurrentColorModeIcon />
70
140
  </button>
71
141
  </div>
72
142
  );
@@ -25,11 +25,16 @@
25
25
  background: var(--ifm-color-emphasis-200);
26
26
  }
27
27
 
28
- [data-theme='light'] .darkToggleIcon,
29
- [data-theme='dark'] .lightToggleIcon {
28
+ .toggleIcon {
30
29
  display: none;
31
30
  }
32
31
 
32
+ [data-theme-choice='system'] .systemToggleIcon,
33
+ [data-theme-choice='light'] .lightToggleIcon,
34
+ [data-theme-choice='dark'] .darkToggleIcon {
35
+ display: initial;
36
+ }
37
+
33
38
  .toggleButtonDisabled {
34
39
  cursor: not-allowed;
35
40
  }
@@ -0,0 +1,20 @@
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 type {ReactNode} from 'react';
9
+ import type {Props} from '@theme/Icon/SystemColorMode';
10
+
11
+ export default function IconSystemColorMode(props: Props): ReactNode {
12
+ return (
13
+ <svg viewBox="0 0 24 24" width={24} height={24} {...props}>
14
+ <path
15
+ fill="currentColor"
16
+ d="m12 21c4.971 0 9-4.029 9-9s-4.029-9-9-9-9 4.029-9 9 4.029 9 9 9zm4.95-13.95c1.313 1.313 2.05 3.093 2.05 4.95s-0.738 3.637-2.05 4.95c-1.313 1.313-3.093 2.05-4.95 2.05v-14c1.857 0 3.637 0.737 4.95 2.05z"
17
+ />
18
+ </svg>
19
+ );
20
+ }
@@ -13,10 +13,10 @@ import styles from './styles.module.css';
13
13
 
14
14
  export default function NavbarColorModeToggle({className}: Props): ReactNode {
15
15
  const navbarStyle = useThemeConfig().navbar.style;
16
- const disabled = useThemeConfig().colorMode.disableSwitch;
17
- const {colorMode, setColorMode} = useColorMode();
16
+ const {disableSwitch, respectPrefersColorScheme} = useThemeConfig().colorMode;
17
+ const {colorModeChoice, setColorMode} = useColorMode();
18
18
 
19
- if (disabled) {
19
+ if (disableSwitch) {
20
20
  return null;
21
21
  }
22
22
 
@@ -26,7 +26,8 @@ export default function NavbarColorModeToggle({className}: Props): ReactNode {
26
26
  buttonClassName={
27
27
  navbarStyle === 'dark' ? styles.darkNavbarColorModeToggle : undefined
28
28
  }
29
- value={colorMode}
29
+ respectPrefersColorScheme={respectPrefersColorScheme}
30
+ value={colorModeChoice}
30
31
  onChange={setColorMode}
31
32
  />
32
33
  );
@@ -1555,12 +1555,13 @@ declare module '@theme/ColorModeToggle' {
1555
1555
  export interface Props {
1556
1556
  readonly className?: string;
1557
1557
  readonly buttonClassName?: string;
1558
- readonly value: ColorMode;
1558
+ readonly respectPrefersColorScheme: boolean;
1559
+ readonly value: ColorMode | null;
1559
1560
  /**
1560
1561
  * The parameter represents the "to-be" value. For example, if currently in
1561
- * dark mode, clicking the button should call `onChange("light")`
1562
+ * light mode, clicking the button should call `onChange("dark")`
1562
1563
  */
1563
- readonly onChange: (colorMode: ColorMode) => void;
1564
+ readonly onChange: (colorMode: ColorMode | null) => void;
1564
1565
  }
1565
1566
 
1566
1567
  export default function ColorModeToggle(props: Props): ReactNode;
@@ -1617,6 +1618,14 @@ declare module '@theme/Icon/LightMode' {
1617
1618
  export default function IconLightMode(props: Props): ReactNode;
1618
1619
  }
1619
1620
 
1621
+ declare module '@theme/Icon/SystemColorMode' {
1622
+ import type {ComponentProps} from 'react';
1623
+
1624
+ export interface Props extends ComponentProps<'svg'> {}
1625
+
1626
+ export default function IconSystemColorMode(props: Props): JSX.Element;
1627
+ }
1628
+
1620
1629
  declare module '@theme/Icon/Menu' {
1621
1630
  import type {ComponentProps, ReactNode} from 'react';
1622
1631