@docusaurus/theme-common 3.7.0-canary-6252 → 3.7.0-canary-6254

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.
@@ -5,20 +5,19 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
  import { type ReactNode } from 'react';
8
+ export type ColorMode = 'light' | 'dark';
9
+ export type ColorModeChoice = ColorMode | null;
8
10
  type ContextValue = {
9
- /** Current color mode. */
11
+ /** The effective color mode. */
10
12
  readonly colorMode: ColorMode;
13
+ /** The explicitly chosen color mode */
14
+ readonly colorModeChoice: ColorModeChoice;
11
15
  /** Set new color mode. */
12
- readonly setColorMode: (colorMode: ColorMode) => void;
16
+ readonly setColorMode: (colorMode: ColorModeChoice) => void;
13
17
  readonly isDarkTheme: boolean;
14
18
  readonly setLightTheme: () => void;
15
19
  readonly setDarkTheme: () => void;
16
20
  };
17
- declare const ColorModes: {
18
- readonly light: "light";
19
- readonly dark: "dark";
20
- };
21
- export type ColorMode = (typeof ColorModes)[keyof typeof ColorModes];
22
21
  export declare function ColorModeProvider({ children, }: {
23
22
  children: ReactNode;
24
23
  }): ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"colorMode.d.ts","sourceRoot":"","sources":["../../src/contexts/colorMode.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAc,EAOZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAMf,KAAK,YAAY,GAAG;IAClB,0BAA0B;IAC1B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,0BAA0B;IAC1B,QAAQ,CAAC,YAAY,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK,IAAI,CAAC;IAItD,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,IAAI,CAAC;IACnC,QAAQ,CAAC,YAAY,EAAE,MAAM,IAAI,CAAC;CACnC,CAAC;AAOF,QAAA,MAAM,UAAU;;;CAGN,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,OAAO,UAAU,CAAC,CAAC;AA8JrE,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,GACT,EAAE;IACD,QAAQ,EAAE,SAAS,CAAC;CACrB,GAAG,SAAS,CAGZ;AAED,wBAAgB,YAAY,IAAI,YAAY,CAS3C"}
1
+ {"version":3,"file":"colorMode.d.ts","sourceRoot":"","sources":["../../src/contexts/colorMode.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAc,EAMZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAMf,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAIzC,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,IAAI,CAAC;AAyB/C,KAAK,YAAY,GAAG;IAClB,gCAAgC;IAChC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,uCAAuC;IACvC,QAAQ,CAAC,eAAe,EAAE,eAAe,CAAC;IAC1C,0BAA0B;IAC1B,QAAQ,CAAC,YAAY,EAAE,CAAC,SAAS,EAAE,eAAe,KAAK,IAAI,CAAC;IAI5D,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,aAAa,EAAE,MAAM,IAAI,CAAC;IACnC,QAAQ,CAAC,YAAY,EAAE,MAAM,IAAI,CAAC;CACnC,CAAC;AAsMF,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,GACT,EAAE;IACD,QAAQ,EAAE,SAAS,CAAC;CACrB,GAAG,SAAS,CAGZ;AAED,wBAAgB,YAAY,IAAI,YAAY,CAS3C"}
@@ -4,20 +4,34 @@
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, { useState, useCallback, useEffect, useContext, useMemo, useRef, } from 'react';
8
- import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
7
+ import React, { useState, useCallback, useEffect, useContext, useMemo, } from 'react';
9
8
  import { ReactContextError } from '../utils/reactUtils';
10
9
  import { createStorageSlot } from '../utils/storageUtils';
11
10
  import { useThemeConfig } from '../utils/useThemeConfig';
11
+ function getSystemColorMode() {
12
+ return window.matchMedia('(prefers-color-scheme: dark)').matches
13
+ ? 'dark'
14
+ : 'light';
15
+ }
16
+ function subscribeToMedia(query, listener) {
17
+ const mql = window.matchMedia(query);
18
+ mql.addEventListener('change', listener);
19
+ return () => mql.removeEventListener('change', listener);
20
+ }
21
+ function subscribeToSystemColorModeChange(onChange) {
22
+ return subscribeToMedia('(prefers-color-scheme: dark)', () => onChange(getSystemColorMode()));
23
+ }
12
24
  const Context = React.createContext(undefined);
13
25
  const ColorModeStorageKey = 'theme';
14
26
  const ColorModeStorage = createStorageSlot(ColorModeStorageKey);
15
- const ColorModes = {
16
- light: 'light',
17
- dark: 'dark',
18
- };
27
+ // We use data-theme-choice="system", not an absent attribute
28
+ // This is easier to handle for users with CSS
29
+ const SystemAttribute = 'system';
19
30
  // Ensure to always return a valid colorMode even if input is invalid
20
- const coerceToColorMode = (colorMode) => colorMode === ColorModes.dark ? ColorModes.dark : ColorModes.light;
31
+ const coerceToColorMode = (colorMode) => colorMode === 'dark' ? 'dark' : 'light';
32
+ const coerceToColorModeChoice = (colorMode) => colorMode === null || colorMode === SystemAttribute
33
+ ? null
34
+ : coerceToColorMode(colorMode);
21
35
  const ColorModeAttribute = {
22
36
  get: () => {
23
37
  return coerceToColorMode(document.documentElement.getAttribute('data-theme'));
@@ -26,14 +40,21 @@ const ColorModeAttribute = {
26
40
  document.documentElement.setAttribute('data-theme', coerceToColorMode(colorMode));
27
41
  },
28
42
  };
29
- const readInitialColorMode = () => {
30
- if (!ExecutionEnvironment.canUseDOM) {
31
- throw new Error("Can't read initial color mode on the server");
32
- }
33
- return ColorModeAttribute.get();
43
+ const ColorModeChoiceAttribute = {
44
+ get: () => {
45
+ return coerceToColorModeChoice(document.documentElement.getAttribute('data-theme-choice'));
46
+ },
47
+ set: (colorMode) => {
48
+ document.documentElement.setAttribute('data-theme-choice', coerceToColorModeChoice(colorMode) ?? SystemAttribute);
49
+ },
34
50
  };
35
- const storeColorMode = (newColorMode) => {
36
- ColorModeStorage.set(coerceToColorMode(newColorMode));
51
+ const persistColorModeChoice = (newColorMode) => {
52
+ if (newColorMode === null) {
53
+ ColorModeStorage.del();
54
+ }
55
+ else {
56
+ ColorModeStorage.set(coerceToColorMode(newColorMode));
57
+ }
37
58
  };
38
59
  // The color mode state is initialized in useEffect on purpose
39
60
  // to avoid a React hydration mismatch errors
@@ -43,14 +64,21 @@ const storeColorMode = (newColorMode) => {
43
64
  function useColorModeState() {
44
65
  const { colorMode: { defaultMode }, } = useThemeConfig();
45
66
  const [colorMode, setColorModeState] = useState(defaultMode);
67
+ const [colorModeChoice, setColorModeChoiceState] = useState(null);
46
68
  useEffect(() => {
47
- setColorModeState(readInitialColorMode());
69
+ setColorModeState(ColorModeAttribute.get());
70
+ setColorModeChoiceState(ColorModeChoiceAttribute.get());
48
71
  }, []);
49
- return [colorMode, setColorModeState];
72
+ return {
73
+ colorMode,
74
+ setColorModeState,
75
+ colorModeChoice,
76
+ setColorModeChoiceState,
77
+ };
50
78
  }
51
79
  function useContextValue() {
52
80
  const { colorMode: { defaultMode, disableSwitch, respectPrefersColorScheme }, } = useThemeConfig();
53
- const [colorMode, setColorModeState] = useColorModeState();
81
+ const { colorMode, setColorModeState, colorModeChoice, setColorModeChoiceState, } = useColorModeState();
54
82
  useEffect(() => {
55
83
  // A site is deployed without disableSwitch
56
84
  // => User visits the site and has a persisted value
@@ -60,81 +88,79 @@ function useContextValue() {
60
88
  ColorModeStorage.del();
61
89
  }
62
90
  }, [disableSwitch]);
63
- const setColorMode = useCallback((newColorMode, options = {}) => {
91
+ const setColorMode = useCallback((newColorModeChoice, options = {}) => {
64
92
  const { persist = true } = options;
65
- if (newColorMode) {
93
+ // Reset to system/default color mode
94
+ if (newColorModeChoice === null) {
95
+ // Set the effective color
96
+ const newColorMode = respectPrefersColorScheme
97
+ ? getSystemColorMode()
98
+ : defaultMode;
66
99
  ColorModeAttribute.set(newColorMode);
67
100
  setColorModeState(newColorMode);
68
- if (persist) {
69
- storeColorMode(newColorMode);
70
- }
101
+ // Set the chosen color
102
+ ColorModeChoiceAttribute.set(null);
103
+ setColorModeChoiceState(null);
71
104
  }
105
+ // Happy case, when an explicit color is provided
72
106
  else {
73
- if (respectPrefersColorScheme) {
74
- const osColorMode = window.matchMedia('(prefers-color-scheme: dark)')
75
- .matches
76
- ? ColorModes.dark
77
- : ColorModes.light;
78
- ColorModeAttribute.set(osColorMode);
79
- setColorModeState(osColorMode);
80
- }
81
- else {
82
- ColorModeAttribute.set(defaultMode);
83
- setColorModeState(defaultMode);
84
- }
85
- ColorModeStorage.del();
107
+ ColorModeAttribute.set(newColorModeChoice);
108
+ ColorModeChoiceAttribute.set(newColorModeChoice);
109
+ setColorModeState(newColorModeChoice);
110
+ setColorModeChoiceState(newColorModeChoice);
86
111
  }
87
- }, [setColorModeState, respectPrefersColorScheme, defaultMode]);
88
- useEffect(() => {
89
- if (disableSwitch) {
90
- return undefined;
112
+ if (persist) {
113
+ persistColorModeChoice(newColorModeChoice);
91
114
  }
115
+ }, [
116
+ setColorModeState,
117
+ setColorModeChoiceState,
118
+ respectPrefersColorScheme,
119
+ defaultMode,
120
+ ]);
121
+ // Synchronize theme color/choice mode with browser storage
122
+ useEffect(() => {
92
123
  return ColorModeStorage.listen((e) => {
93
- setColorMode(coerceToColorMode(e.newValue));
124
+ setColorMode(coerceToColorModeChoice(e.newValue));
94
125
  });
95
- }, [disableSwitch, setColorMode]);
96
- // PCS is coerced to light mode when printing, which causes the color mode to
97
- // be reset to dark when exiting print mode, disregarding user settings. When
98
- // the listener fires only because of a print/screen switch, we don't change
99
- // color mode. See https://github.com/facebook/docusaurus/pull/6490
100
- const previousMediaIsPrint = useRef(false);
126
+ }, [setColorMode]);
127
+ // Synchronize theme color with system color
101
128
  useEffect(() => {
102
- if (disableSwitch && !respectPrefersColorScheme) {
129
+ if (colorModeChoice !== null || !respectPrefersColorScheme) {
103
130
  return undefined;
104
131
  }
105
- const mql = window.matchMedia('(prefers-color-scheme: dark)');
106
- const onChange = () => {
107
- if (window.matchMedia('print').matches || previousMediaIsPrint.current) {
108
- previousMediaIsPrint.current = window.matchMedia('print').matches;
109
- return;
110
- }
111
- setColorMode(null);
112
- };
113
- mql.addListener(onChange);
114
- return () => mql.removeListener(onChange);
115
- }, [setColorMode, disableSwitch, respectPrefersColorScheme]);
132
+ return subscribeToSystemColorModeChange((newSystemColorMode) => {
133
+ // Note: we don't use "setColorMode" on purpose
134
+ // The system changes should never be considered an explicit theme choice
135
+ // They only affect the "effective" color, and should never be persisted
136
+ // Note: this listener also fire when printing, see https://github.com/facebook/docusaurus/pull/6490
137
+ setColorModeState(newSystemColorMode);
138
+ ColorModeAttribute.set(newSystemColorMode);
139
+ });
140
+ }, [respectPrefersColorScheme, colorModeChoice, setColorModeState]);
116
141
  return useMemo(() => ({
117
142
  colorMode,
143
+ colorModeChoice,
118
144
  setColorMode,
119
145
  get isDarkTheme() {
120
146
  if (process.env.NODE_ENV === 'development') {
121
147
  console.error('`useColorMode().isDarkTheme` is deprecated. Please use `useColorMode().colorMode === "dark"` instead.');
122
148
  }
123
- return colorMode === ColorModes.dark;
149
+ return colorMode === 'dark';
124
150
  },
125
151
  setLightTheme() {
126
152
  if (process.env.NODE_ENV === 'development') {
127
153
  console.error('`useColorMode().setLightTheme` is deprecated. Please use `useColorMode().setColorMode("light")` instead.');
128
154
  }
129
- setColorMode(ColorModes.light);
155
+ setColorMode('light');
130
156
  },
131
157
  setDarkTheme() {
132
158
  if (process.env.NODE_ENV === 'development') {
133
159
  console.error('`useColorMode().setDarkTheme` is deprecated. Please use `useColorMode().setColorMode("dark")` instead.');
134
160
  }
135
- setColorMode(ColorModes.dark);
161
+ setColorMode('dark');
136
162
  },
137
- }), [colorMode, setColorMode]);
163
+ }), [colorMode, colorModeChoice, setColorMode]);
138
164
  }
139
165
  export function ColorModeProvider({ children, }) {
140
166
  const value = useContextValue();
@@ -1 +1 @@
1
- {"version":3,"file":"colorMode.js","sourceRoot":"","sources":["../../src/contexts/colorMode.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"colorMode.js","sourceRoot":"","sources":["../../src/contexts/colorMode.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docusaurus/theme-common",
3
- "version": "3.7.0-canary-6252",
3
+ "version": "3.7.0-canary-6254",
4
4
  "description": "Common code for Docusaurus themes.",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./lib/index.d.ts",
@@ -30,10 +30,10 @@
30
30
  },
31
31
  "license": "MIT",
32
32
  "dependencies": {
33
- "@docusaurus/mdx-loader": "3.7.0-canary-6252",
34
- "@docusaurus/module-type-aliases": "3.7.0-canary-6252",
35
- "@docusaurus/utils": "3.7.0-canary-6252",
36
- "@docusaurus/utils-common": "3.7.0-canary-6252",
33
+ "@docusaurus/mdx-loader": "3.7.0-canary-6254",
34
+ "@docusaurus/module-type-aliases": "3.7.0-canary-6254",
35
+ "@docusaurus/utils": "3.7.0-canary-6254",
36
+ "@docusaurus/utils-common": "3.7.0-canary-6254",
37
37
  "@types/history": "^4.7.11",
38
38
  "@types/react": "*",
39
39
  "@types/react-router-config": "*",
@@ -44,8 +44,8 @@
44
44
  "utility-types": "^3.10.0"
45
45
  },
46
46
  "devDependencies": {
47
- "@docusaurus/core": "3.7.0-canary-6252",
48
- "@docusaurus/types": "3.7.0-canary-6252",
47
+ "@docusaurus/core": "3.7.0-canary-6254",
48
+ "@docusaurus/types": "3.7.0-canary-6254",
49
49
  "fs-extra": "^11.1.1",
50
50
  "lodash": "^4.17.21"
51
51
  },
@@ -57,5 +57,5 @@
57
57
  "engines": {
58
58
  "node": ">=18.0"
59
59
  },
60
- "gitHead": "afaaedd499d872dcf54bcdcbe59749b1de7a941a"
60
+ "gitHead": "a877206d157c7a960696a43ea62d43c0a5d211e9"
61
61
  }
@@ -11,19 +11,49 @@ import React, {
11
11
  useEffect,
12
12
  useContext,
13
13
  useMemo,
14
- useRef,
15
14
  type ReactNode,
16
15
  } from 'react';
17
- import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
18
16
  import {ReactContextError} from '../utils/reactUtils';
19
17
  import {createStorageSlot} from '../utils/storageUtils';
20
18
  import {useThemeConfig} from '../utils/useThemeConfig';
21
19
 
20
+ // The "effective" color mode
21
+ export type ColorMode = 'light' | 'dark';
22
+
23
+ // The color mode explicitly chosen by the user
24
+ // null => no choice has been made, or the choice has been reverted to OS value
25
+ export type ColorModeChoice = ColorMode | null;
26
+
27
+ function getSystemColorMode(): ColorMode {
28
+ return window.matchMedia('(prefers-color-scheme: dark)').matches
29
+ ? 'dark'
30
+ : 'light';
31
+ }
32
+
33
+ function subscribeToMedia(
34
+ query: string,
35
+ listener: (event: MediaQueryListEvent) => void,
36
+ ): () => void {
37
+ const mql = window.matchMedia(query);
38
+ mql.addEventListener('change', listener);
39
+ return () => mql.removeEventListener('change', listener);
40
+ }
41
+
42
+ function subscribeToSystemColorModeChange(
43
+ onChange: (newSystemColorMode: ColorMode) => void,
44
+ ): () => void {
45
+ return subscribeToMedia('(prefers-color-scheme: dark)', () =>
46
+ onChange(getSystemColorMode()),
47
+ );
48
+ }
49
+
22
50
  type ContextValue = {
23
- /** Current color mode. */
51
+ /** The effective color mode. */
24
52
  readonly colorMode: ColorMode;
53
+ /** The explicitly chosen color mode */
54
+ readonly colorModeChoice: ColorModeChoice;
25
55
  /** Set new color mode. */
26
- readonly setColorMode: (colorMode: ColorMode) => void;
56
+ readonly setColorMode: (colorMode: ColorModeChoice) => void;
27
57
 
28
58
  // TODO Docusaurus v4
29
59
  // legacy APIs kept for retro-compatibility: deprecate them
@@ -37,16 +67,17 @@ const Context = React.createContext<ContextValue | undefined>(undefined);
37
67
  const ColorModeStorageKey = 'theme';
38
68
  const ColorModeStorage = createStorageSlot(ColorModeStorageKey);
39
69
 
40
- const ColorModes = {
41
- light: 'light',
42
- dark: 'dark',
43
- } as const;
44
-
45
- export type ColorMode = (typeof ColorModes)[keyof typeof ColorModes];
70
+ // We use data-theme-choice="system", not an absent attribute
71
+ // This is easier to handle for users with CSS
72
+ const SystemAttribute = 'system';
46
73
 
47
74
  // Ensure to always return a valid colorMode even if input is invalid
48
- const coerceToColorMode = (colorMode?: string | null): ColorMode =>
49
- colorMode === ColorModes.dark ? ColorModes.dark : ColorModes.light;
75
+ const coerceToColorMode = (colorMode: string | null): ColorMode =>
76
+ colorMode === 'dark' ? 'dark' : 'light';
77
+ const coerceToColorModeChoice = (colorMode: string | null): ColorModeChoice =>
78
+ colorMode === null || colorMode === SystemAttribute
79
+ ? null
80
+ : coerceToColorMode(colorMode);
50
81
 
51
82
  const ColorModeAttribute = {
52
83
  get: () => {
@@ -62,15 +93,26 @@ const ColorModeAttribute = {
62
93
  },
63
94
  };
64
95
 
65
- const readInitialColorMode = (): ColorMode => {
66
- if (!ExecutionEnvironment.canUseDOM) {
67
- throw new Error("Can't read initial color mode on the server");
68
- }
69
- return ColorModeAttribute.get();
96
+ const ColorModeChoiceAttribute = {
97
+ get: () => {
98
+ return coerceToColorModeChoice(
99
+ document.documentElement.getAttribute('data-theme-choice'),
100
+ );
101
+ },
102
+ set: (colorMode: ColorModeChoice) => {
103
+ document.documentElement.setAttribute(
104
+ 'data-theme-choice',
105
+ coerceToColorModeChoice(colorMode) ?? SystemAttribute,
106
+ );
107
+ },
70
108
  };
71
109
 
72
- const storeColorMode = (newColorMode: ColorMode) => {
73
- ColorModeStorage.set(coerceToColorMode(newColorMode));
110
+ const persistColorModeChoice = (newColorMode: ColorModeChoice) => {
111
+ if (newColorMode === null) {
112
+ ColorModeStorage.del();
113
+ } else {
114
+ ColorModeStorage.set(coerceToColorMode(newColorMode));
115
+ }
74
116
  };
75
117
 
76
118
  // The color mode state is initialized in useEffect on purpose
@@ -83,20 +125,33 @@ function useColorModeState() {
83
125
  colorMode: {defaultMode},
84
126
  } = useThemeConfig();
85
127
 
86
- const [colorMode, setColorModeState] = useState(defaultMode);
128
+ const [colorMode, setColorModeState] = useState<ColorMode>(defaultMode);
129
+ const [colorModeChoice, setColorModeChoiceState] =
130
+ useState<ColorModeChoice>(null);
87
131
 
88
132
  useEffect(() => {
89
- setColorModeState(readInitialColorMode());
133
+ setColorModeState(ColorModeAttribute.get());
134
+ setColorModeChoiceState(ColorModeChoiceAttribute.get());
90
135
  }, []);
91
136
 
92
- return [colorMode, setColorModeState] as const;
137
+ return {
138
+ colorMode,
139
+ setColorModeState,
140
+ colorModeChoice,
141
+ setColorModeChoiceState,
142
+ } as const;
93
143
  }
94
144
 
95
145
  function useContextValue(): ContextValue {
96
146
  const {
97
147
  colorMode: {defaultMode, disableSwitch, respectPrefersColorScheme},
98
148
  } = useThemeConfig();
99
- const [colorMode, setColorModeState] = useColorModeState();
149
+ const {
150
+ colorMode,
151
+ setColorModeState,
152
+ colorModeChoice,
153
+ setColorModeChoiceState,
154
+ } = useColorModeState();
100
155
 
101
156
  useEffect(() => {
102
157
  // A site is deployed without disableSwitch
@@ -109,67 +164,70 @@ function useContextValue(): ContextValue {
109
164
  }, [disableSwitch]);
110
165
 
111
166
  const setColorMode = useCallback(
112
- (newColorMode: ColorMode | null, options: {persist?: boolean} = {}) => {
167
+ (
168
+ newColorModeChoice: ColorModeChoice,
169
+ options: {persist?: boolean} = {},
170
+ ) => {
113
171
  const {persist = true} = options;
114
172
 
115
- if (newColorMode) {
173
+ // Reset to system/default color mode
174
+ if (newColorModeChoice === null) {
175
+ // Set the effective color
176
+ const newColorMode = respectPrefersColorScheme
177
+ ? getSystemColorMode()
178
+ : defaultMode;
116
179
  ColorModeAttribute.set(newColorMode);
117
180
  setColorModeState(newColorMode);
118
- if (persist) {
119
- storeColorMode(newColorMode);
120
- }
121
- } else {
122
- if (respectPrefersColorScheme) {
123
- const osColorMode = window.matchMedia('(prefers-color-scheme: dark)')
124
- .matches
125
- ? ColorModes.dark
126
- : ColorModes.light;
127
- ColorModeAttribute.set(osColorMode);
128
- setColorModeState(osColorMode);
129
- } else {
130
- ColorModeAttribute.set(defaultMode);
131
- setColorModeState(defaultMode);
132
- }
133
- ColorModeStorage.del();
181
+ // Set the chosen color
182
+ ColorModeChoiceAttribute.set(null);
183
+ setColorModeChoiceState(null);
184
+ }
185
+ // Happy case, when an explicit color is provided
186
+ else {
187
+ ColorModeAttribute.set(newColorModeChoice);
188
+ ColorModeChoiceAttribute.set(newColorModeChoice);
189
+ setColorModeState(newColorModeChoice);
190
+ setColorModeChoiceState(newColorModeChoice);
191
+ }
192
+
193
+ if (persist) {
194
+ persistColorModeChoice(newColorModeChoice);
134
195
  }
135
196
  },
136
- [setColorModeState, respectPrefersColorScheme, defaultMode],
197
+ [
198
+ setColorModeState,
199
+ setColorModeChoiceState,
200
+ respectPrefersColorScheme,
201
+ defaultMode,
202
+ ],
137
203
  );
138
204
 
205
+ // Synchronize theme color/choice mode with browser storage
139
206
  useEffect(() => {
140
- if (disableSwitch) {
141
- return undefined;
142
- }
143
207
  return ColorModeStorage.listen((e) => {
144
- setColorMode(coerceToColorMode(e.newValue));
208
+ setColorMode(coerceToColorModeChoice(e.newValue));
145
209
  });
146
- }, [disableSwitch, setColorMode]);
147
-
148
- // PCS is coerced to light mode when printing, which causes the color mode to
149
- // be reset to dark when exiting print mode, disregarding user settings. When
150
- // the listener fires only because of a print/screen switch, we don't change
151
- // color mode. See https://github.com/facebook/docusaurus/pull/6490
152
- const previousMediaIsPrint = useRef(false);
210
+ }, [setColorMode]);
153
211
 
212
+ // Synchronize theme color with system color
154
213
  useEffect(() => {
155
- if (disableSwitch && !respectPrefersColorScheme) {
214
+ if (colorModeChoice !== null || !respectPrefersColorScheme) {
156
215
  return undefined;
157
216
  }
158
- const mql = window.matchMedia('(prefers-color-scheme: dark)');
159
- const onChange = () => {
160
- if (window.matchMedia('print').matches || previousMediaIsPrint.current) {
161
- previousMediaIsPrint.current = window.matchMedia('print').matches;
162
- return;
163
- }
164
- setColorMode(null);
165
- };
166
- mql.addListener(onChange);
167
- return () => mql.removeListener(onChange);
168
- }, [setColorMode, disableSwitch, respectPrefersColorScheme]);
217
+ return subscribeToSystemColorModeChange((newSystemColorMode) => {
218
+ // Note: we don't use "setColorMode" on purpose
219
+ // The system changes should never be considered an explicit theme choice
220
+ // They only affect the "effective" color, and should never be persisted
221
+ // Note: this listener also fire when printing, see https://github.com/facebook/docusaurus/pull/6490
222
+ setColorModeState(newSystemColorMode);
223
+ ColorModeAttribute.set(newSystemColorMode);
224
+ });
225
+ }, [respectPrefersColorScheme, colorModeChoice, setColorModeState]);
169
226
 
170
227
  return useMemo(
171
228
  () => ({
172
229
  colorMode,
230
+ colorModeChoice,
173
231
  setColorMode,
174
232
  get isDarkTheme() {
175
233
  if (process.env.NODE_ENV === 'development') {
@@ -177,7 +235,7 @@ function useContextValue(): ContextValue {
177
235
  '`useColorMode().isDarkTheme` is deprecated. Please use `useColorMode().colorMode === "dark"` instead.',
178
236
  );
179
237
  }
180
- return colorMode === ColorModes.dark;
238
+ return colorMode === 'dark';
181
239
  },
182
240
  setLightTheme() {
183
241
  if (process.env.NODE_ENV === 'development') {
@@ -185,7 +243,7 @@ function useContextValue(): ContextValue {
185
243
  '`useColorMode().setLightTheme` is deprecated. Please use `useColorMode().setColorMode("light")` instead.',
186
244
  );
187
245
  }
188
- setColorMode(ColorModes.light);
246
+ setColorMode('light');
189
247
  },
190
248
  setDarkTheme() {
191
249
  if (process.env.NODE_ENV === 'development') {
@@ -193,10 +251,10 @@ function useContextValue(): ContextValue {
193
251
  '`useColorMode().setDarkTheme` is deprecated. Please use `useColorMode().setColorMode("dark")` instead.',
194
252
  );
195
253
  }
196
- setColorMode(ColorModes.dark);
254
+ setColorMode('dark');
197
255
  },
198
256
  }),
199
- [colorMode, setColorMode],
257
+ [colorMode, colorModeChoice, setColorMode],
200
258
  );
201
259
  }
202
260