@scalar/use-hooks
Advanced tools
+6
-0
| # @scalar/use-hooks | ||
| ## 0.4.7 | ||
| ### Patch Changes | ||
| - [#9540](https://github.com/scalar/scalar/pull/9540): Fix an SSR hydration mismatch in the color-mode toggle: the system preference is now resolved after mount so the first client render matches the server. | ||
| ## 0.4.6 | ||
@@ -4,0 +10,0 @@ |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"useColorMode.d.ts","sourceRoot":"","sources":["../../src/useColorMode/useColorMode.ts"],"names":[],"mappings":"AAOA,2BAA2B;AAC3B,KAAK,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;AAE5C,+BAA+B;AAC/B,KAAK,aAAa,GAAG,OAAO,GAAG,MAAM,CAAA;AAErC;;GAEG;AACH,wBAAgB,YAAY,CAC1B,IAAI,GAAE;IACJ,oCAAoC;IACpC,gBAAgB,CAAC,EAAE,SAAS,CAAA;IAC5B,8BAA8B;IAC9B,iBAAiB,CAAC,EAAE,SAAS,CAAA;CACzB;IA6FJ,yCAAyC;;IAKzC,+CAA+C;;IAE/C,yDAAyD;;IAEzD,qDAAqD;;IAErD,kDAAkD;0BAvFvB,SAAS;IAyFpC,uCAAuC;mCAhFL,aAAa;EAmFlD"} | ||
| {"version":3,"file":"useColorMode.d.ts","sourceRoot":"","sources":["../../src/useColorMode/useColorMode.ts"],"names":[],"mappings":"AAmBA,2BAA2B;AAC3B,KAAK,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;AAE5C,+BAA+B;AAC/B,KAAK,aAAa,GAAG,OAAO,GAAG,MAAM,CAAA;AAErC;;GAEG;AACH,wBAAgB,YAAY,CAC1B,IAAI,GAAE;IACJ,oCAAoC;IACpC,gBAAgB,CAAC,EAAE,SAAS,CAAA;IAC5B,8BAA8B;IAC9B,iBAAiB,CAAC,EAAE,SAAS,CAAA;CACzB;IAsGJ,yCAAyC;;IAKzC,+CAA+C;;IAE/C,yDAAyD;;IAEzD,qDAAqD;;IAErD,kDAAkD;0BAhGvB,SAAS;IAkGpC,uCAAuC;mCAzFL,aAAa;EA4FlD"} |
| import { literal, union, validate } from '@scalar/validation'; | ||
| import { computed, onMounted, onUnmounted, ref, watch } from 'vue'; | ||
| const colorMode = ref('dark'); | ||
| /** | ||
| * Reactive snapshot of the system preference, shared across every `useColorMode` instance. | ||
| * | ||
| * It defaults to `'light'` so the first client render matches the server, where | ||
| * `window`/`matchMedia` do not exist. We resolve the real value in `onMounted` to avoid a | ||
| * hydration mismatch in anything bound to the color mode (for example the dark-mode toggle). | ||
| * | ||
| * It lives at module scope (like `colorMode`) so all instances agree on a single value instead | ||
| * of each holding its own copy that resolves at a different mount time. | ||
| */ | ||
| const systemPreference = ref('light'); | ||
| const colorModeSchema = union([literal('system'), literal('dark'), literal('light')]); | ||
@@ -40,3 +51,3 @@ /** | ||
| const darkLightMode = computed({ | ||
| get: () => (colorMode.value === 'system' ? getSystemModePreference() : colorMode.value), | ||
| get: () => (colorMode.value === 'system' ? systemPreference.value : colorMode.value), | ||
| set: setColorMode, | ||
@@ -50,7 +61,9 @@ }); | ||
| /** Applies the appropriate color mode class to the body. */ | ||
| function applyColorMode(mode) { | ||
| function applyColorMode() { | ||
| if (typeof document === 'undefined' || typeof window === 'undefined') { | ||
| return; | ||
| } | ||
| const classMode = overrideColorMode ?? (mode === 'system' ? getSystemModePreference() : mode); | ||
| // Read from the deferred `systemPreference` ref (not `getSystemModePreference()` directly) so | ||
| // the body class agrees with `darkLightMode`/the toggle before `onMounted` resolves the real value. | ||
| const classMode = overrideColorMode ?? (colorMode.value === 'system' ? systemPreference.value : colorMode.value); | ||
| if (classMode === 'dark') { | ||
@@ -71,8 +84,14 @@ document.body.classList.add('dark-mode'); | ||
| colorMode.value = overrideColorMode ?? savedColorMode ?? initialColorMode; | ||
| // Watch for colorMode changes and update the body class | ||
| watch(colorMode, applyColorMode, { immediate: true }); | ||
| const handleChange = () => colorMode.value === 'system' && applyColorMode('system'); | ||
| // Watch for color mode or system preference changes and update the body class. Watching | ||
| // `systemPreference` means resolving it in `onMounted` (or an OS theme change) re-applies the class. | ||
| watch([colorMode, systemPreference], applyColorMode, { immediate: true }); | ||
| const handleChange = () => { | ||
| systemPreference.value = getSystemModePreference(); | ||
| }; | ||
| const mediaQuery = ref(null); | ||
| // Listen to system preference changes | ||
| onMounted(() => { | ||
| // Now that we are on the client, resolve the real system preference so the | ||
| // color mode updates after hydration instead of mismatching the server. | ||
| systemPreference.value = getSystemModePreference(); | ||
| if (typeof window !== 'undefined' && typeof window?.matchMedia === 'function') { | ||
@@ -79,0 +98,0 @@ mediaQuery.value = window.matchMedia('(prefers-color-scheme: dark)'); |
+1
-1
@@ -13,3 +13,3 @@ { | ||
| }, | ||
| "version": "0.4.6", | ||
| "version": "0.4.7", | ||
| "engines": { | ||
@@ -16,0 +16,0 @@ "node": ">=22" |
35782
4.18%563
3.49%