@scalar/use-hooks 0.4.6 → 0.4.8

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @scalar/use-hooks
2
2
 
3
+ ## 0.4.8
4
+
5
+ ### Patch Changes
6
+
7
+ - [#9710](https://github.com/scalar/scalar/pull/9710): Republish so the updated README (with the Scalar platform overview) reaches npm. Also renames the README generator metadata in package.json from `readme` to `scalarReadme`: npm treats a `readme` field as the readme text itself, so affected packages were published with a literal `[object Object]` readme on the registry instead of README.md.
8
+
9
+ ## 0.4.7
10
+
11
+ ### Patch Changes
12
+
13
+ - [#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.
14
+
3
15
  ## 0.4.6
4
16
 
5
17
  ## 0.4.5
package/README.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  A collection of utility hooks for Scalar.
4
4
 
5
+ ---
6
+
7
+ Scalar is an open-source API platform for teams who want beautiful developer interfaces without vendor lock-in.
8
+
9
+ - **[API References](https://scalar.com/products/api-references/getting-started)** — Interactive API documentation from OpenAPI and AsyncAPI specs.
10
+ - **[Docs](https://scalar.com/products/docs/getting-started)** — Write in Markdown/MDX, generate API references, sync with two-way Git.
11
+ - **[SDKs](https://scalar.com/products/sdks/getting-started)** — Type-safe client libraries in TypeScript, Python, Go, PHP, Java, and Ruby.
12
+ - **[MCP Servers](https://scalar.com/products/agent/getting-started)** — Generate secure MCP servers from your API spec.
13
+ - **[API Client](https://scalar.com/products/api-client/getting-started)** — Open-source, offline-first Postman alternative built on OpenAPI.
14
+
15
+ 20M+ monthly npm installs · 15,500+ GitHub stars · MIT licensed · [scalar.com](https://scalar.com)
16
+
17
+ ---
18
+
5
19
  ## Installation
6
20
 
7
21
  ```bash
@@ -1 +1 @@
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"}
1
+ {"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"}
@@ -1,6 +1,17 @@
1
1
  import { literal, union, validate } from '@scalar/validation';
2
2
  import { computed, onMounted, onUnmounted, ref, watch } from 'vue';
3
3
  const colorMode = ref('dark');
4
+ /**
5
+ * Reactive snapshot of the system preference, shared across every `useColorMode` instance.
6
+ *
7
+ * It defaults to `'light'` so the first client render matches the server, where
8
+ * `window`/`matchMedia` do not exist. We resolve the real value in `onMounted` to avoid a
9
+ * hydration mismatch in anything bound to the color mode (for example the dark-mode toggle).
10
+ *
11
+ * It lives at module scope (like `colorMode`) so all instances agree on a single value instead
12
+ * of each holding its own copy that resolves at a different mount time.
13
+ */
14
+ const systemPreference = ref('light');
4
15
  const colorModeSchema = union([literal('system'), literal('dark'), literal('light')]);
5
16
  /**
6
17
  * A composable hook that provides color mode (dark/light) functionality.
@@ -37,7 +48,7 @@ export function useColorMode(opts = {}) {
37
48
  }
38
49
  /** Writable computed ref for dark/light mode with system preference applied */
39
50
  const darkLightMode = computed({
40
- get: () => (colorMode.value === 'system' ? getSystemModePreference() : colorMode.value),
51
+ get: () => (colorMode.value === 'system' ? systemPreference.value : colorMode.value),
41
52
  set: setColorMode,
42
53
  });
43
54
  /** Writable computed ref for whether the current color mode is dark */
@@ -46,11 +57,13 @@ export function useColorMode(opts = {}) {
46
57
  set: (value) => setColorMode(value ? 'dark' : 'light'),
47
58
  });
48
59
  /** Applies the appropriate color mode class to the body. */
49
- function applyColorMode(mode) {
60
+ function applyColorMode() {
50
61
  if (typeof document === 'undefined' || typeof window === 'undefined') {
51
62
  return;
52
63
  }
53
- const classMode = overrideColorMode ?? (mode === 'system' ? getSystemModePreference() : mode);
64
+ // Read from the deferred `systemPreference` ref (not `getSystemModePreference()` directly) so
65
+ // the body class agrees with `darkLightMode`/the toggle before `onMounted` resolves the real value.
66
+ const classMode = overrideColorMode ?? (colorMode.value === 'system' ? systemPreference.value : colorMode.value);
54
67
  if (classMode === 'dark') {
55
68
  document.body.classList.add('dark-mode');
56
69
  document.body.classList.remove('light-mode');
@@ -66,12 +79,18 @@ export function useColorMode(opts = {}) {
66
79
  const storedValue = typeof window === 'undefined' ? 'system' : window?.localStorage?.getItem('colorMode');
67
80
  const savedColorMode = validate(colorModeSchema, storedValue) ? storedValue : null;
68
81
  colorMode.value = overrideColorMode ?? savedColorMode ?? initialColorMode;
69
- // Watch for colorMode changes and update the body class
70
- watch(colorMode, applyColorMode, { immediate: true });
71
- const handleChange = () => colorMode.value === 'system' && applyColorMode('system');
82
+ // Watch for color mode or system preference changes and update the body class. Watching
83
+ // `systemPreference` means resolving it in `onMounted` (or an OS theme change) re-applies the class.
84
+ watch([colorMode, systemPreference], applyColorMode, { immediate: true });
85
+ const handleChange = () => {
86
+ systemPreference.value = getSystemModePreference();
87
+ };
72
88
  const mediaQuery = ref(null);
73
89
  // Listen to system preference changes
74
90
  onMounted(() => {
91
+ // Now that we are on the client, resolve the real system preference so the
92
+ // color mode updates after hydration instead of mismatching the server.
93
+ systemPreference.value = getSystemModePreference();
75
94
  if (typeof window !== 'undefined' && typeof window?.matchMedia === 'function') {
76
95
  mediaQuery.value = window.matchMedia('(prefers-color-scheme: dark)');
77
96
  mediaQuery.value?.addEventListener('change', handleChange);
package/package.json CHANGED
@@ -10,7 +10,7 @@
10
10
  "url": "git+https://github.com/scalar/scalar.git",
11
11
  "directory": "packages/use-hooks"
12
12
  },
13
- "version": "0.4.6",
13
+ "version": "0.4.8",
14
14
  "engines": {
15
15
  "node": ">=22"
16
16
  },
@@ -46,8 +46,8 @@
46
46
  "cva": "1.0.0-beta.4",
47
47
  "tailwind-merge": "3.5.0",
48
48
  "vue": "^3.5.30",
49
- "@scalar/use-toasts": "0.10.2",
50
- "@scalar/validation": "0.6.0"
49
+ "@scalar/validation": "0.6.1",
50
+ "@scalar/use-toasts": "0.10.3"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@vue/test-utils": "2.4.6",