theme-watcher 0.1.0 → 0.1.1
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/README.md +28 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +34 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -40,6 +40,8 @@ Props:
|
|
|
40
40
|
- `storageKey?: string` default: `"theme-watcher"`
|
|
41
41
|
- `attribute?: "data-theme" | "class"` default: `"data-theme"`
|
|
42
42
|
- `defaultTheme?: "light" | "dark" | "system"` default: `"system"`
|
|
43
|
+
- `enableColorScheme?: boolean` default: `true`
|
|
44
|
+
- `variables?: { light?: Record<string, string>; dark?: Record<string, string> }`
|
|
43
45
|
|
|
44
46
|
### `useTheme()`
|
|
45
47
|
|
|
@@ -57,6 +59,32 @@ Returns:
|
|
|
57
59
|
- Cross-tab updates are synced through `storage` events.
|
|
58
60
|
- Package is ESM-only.
|
|
59
61
|
|
|
62
|
+
## CSS variable support
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
<ThemeWatcher
|
|
66
|
+
variables={{
|
|
67
|
+
light: {
|
|
68
|
+
"--background": "#ffffff",
|
|
69
|
+
"--foreground": "#111111"
|
|
70
|
+
},
|
|
71
|
+
dark: {
|
|
72
|
+
"--background": "#111111",
|
|
73
|
+
"--foreground": "#ffffff"
|
|
74
|
+
}
|
|
75
|
+
}}
|
|
76
|
+
/>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Then in CSS:
|
|
80
|
+
|
|
81
|
+
```css
|
|
82
|
+
body {
|
|
83
|
+
background: var(--background);
|
|
84
|
+
color: var(--foreground);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
60
88
|
## Development
|
|
61
89
|
|
|
62
90
|
This repo uses Bun for package management and scripts, but the published package has no Bun runtime dependency.
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ type Theme = "light" | "dark";
|
|
|
2
2
|
type ThemePreference = Theme | "system";
|
|
3
3
|
type ThemeSource = "prop" | "storage" | "default" | "system";
|
|
4
4
|
type ThemeAttribute = "data-theme" | "class";
|
|
5
|
+
type ThemeVariables = Partial<Record<Theme, Record<string, string>>>;
|
|
5
6
|
interface ThemeState {
|
|
6
7
|
theme: ThemePreference;
|
|
7
8
|
resolvedTheme: Theme;
|
|
@@ -12,13 +13,15 @@ interface ThemeWatcherProps {
|
|
|
12
13
|
storageKey?: string;
|
|
13
14
|
attribute?: ThemeAttribute;
|
|
14
15
|
defaultTheme?: ThemePreference;
|
|
16
|
+
variables?: ThemeVariables;
|
|
17
|
+
enableColorScheme?: boolean;
|
|
15
18
|
}
|
|
16
19
|
interface ThemeApi extends ThemeState {
|
|
17
20
|
set: (theme: ThemePreference) => void;
|
|
18
21
|
get: () => ThemePreference;
|
|
19
22
|
}
|
|
20
23
|
|
|
21
|
-
declare function ThemeWatcher({ theme, storageKey, attribute, defaultTheme }: ThemeWatcherProps): null;
|
|
24
|
+
declare function ThemeWatcher({ theme, storageKey, attribute, defaultTheme, variables, enableColorScheme }: ThemeWatcherProps): null;
|
|
22
25
|
|
|
23
26
|
declare function useTheme(): ThemeApi;
|
|
24
27
|
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,8 @@ import { useEffect } from "react";
|
|
|
5
5
|
var DEFAULT_CONFIG = {
|
|
6
6
|
storageKey: "theme-watcher",
|
|
7
7
|
attribute: "data-theme",
|
|
8
|
-
defaultTheme: "system"
|
|
8
|
+
defaultTheme: "system",
|
|
9
|
+
enableColorScheme: true
|
|
9
10
|
};
|
|
10
11
|
var VALID_PREFERENCES = /* @__PURE__ */ new Set(["light", "dark", "system"]);
|
|
11
12
|
var config = { ...DEFAULT_CONFIG };
|
|
@@ -71,6 +72,29 @@ function applyDomTheme(resolvedTheme) {
|
|
|
71
72
|
}
|
|
72
73
|
root.setAttribute("data-theme", resolvedTheme);
|
|
73
74
|
}
|
|
75
|
+
function applyThemeVariables(resolvedTheme) {
|
|
76
|
+
if (!isBrowserReady()) return;
|
|
77
|
+
const root = document.documentElement;
|
|
78
|
+
const lightVars = config.variables?.light ?? {};
|
|
79
|
+
const darkVars = config.variables?.dark ?? {};
|
|
80
|
+
const allKeys = /* @__PURE__ */ new Set([...Object.keys(lightVars), ...Object.keys(darkVars)]);
|
|
81
|
+
for (const key of allKeys) {
|
|
82
|
+
root.style.removeProperty(key);
|
|
83
|
+
}
|
|
84
|
+
const nextVars = config.variables?.[resolvedTheme];
|
|
85
|
+
if (!nextVars) return;
|
|
86
|
+
for (const [key, value] of Object.entries(nextVars)) {
|
|
87
|
+
root.style.setProperty(key, value);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function applyColorScheme(resolvedTheme) {
|
|
91
|
+
if (!isBrowserReady()) return;
|
|
92
|
+
if (!config.enableColorScheme) {
|
|
93
|
+
document.documentElement.style.removeProperty("color-scheme");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
document.documentElement.style.setProperty("color-scheme", resolvedTheme);
|
|
97
|
+
}
|
|
74
98
|
function emit() {
|
|
75
99
|
for (const callback of subscribers) {
|
|
76
100
|
callback();
|
|
@@ -80,6 +104,8 @@ function recompute() {
|
|
|
80
104
|
const stored = readStoredTheme();
|
|
81
105
|
state = resolveTheme(controlledTheme, stored, config.defaultTheme);
|
|
82
106
|
applyDomTheme(state.resolvedTheme);
|
|
107
|
+
applyThemeVariables(state.resolvedTheme);
|
|
108
|
+
applyColorScheme(state.resolvedTheme);
|
|
83
109
|
emit();
|
|
84
110
|
}
|
|
85
111
|
function handleMediaChange() {
|
|
@@ -137,6 +163,8 @@ function setTheme(theme) {
|
|
|
137
163
|
writeStoredTheme(theme);
|
|
138
164
|
state = resolveTheme(controlledTheme, theme, config.defaultTheme);
|
|
139
165
|
applyDomTheme(state.resolvedTheme);
|
|
166
|
+
applyThemeVariables(state.resolvedTheme);
|
|
167
|
+
applyColorScheme(state.resolvedTheme);
|
|
140
168
|
emit();
|
|
141
169
|
}
|
|
142
170
|
function getTheme() {
|
|
@@ -158,11 +186,13 @@ function ThemeWatcher({
|
|
|
158
186
|
theme,
|
|
159
187
|
storageKey = "theme-watcher",
|
|
160
188
|
attribute = "data-theme",
|
|
161
|
-
defaultTheme = "system"
|
|
189
|
+
defaultTheme = "system",
|
|
190
|
+
variables,
|
|
191
|
+
enableColorScheme = true
|
|
162
192
|
}) {
|
|
163
193
|
useEffect(() => {
|
|
164
|
-
return mountWatcher({ storageKey, attribute, defaultTheme }, theme);
|
|
165
|
-
}, [theme, storageKey, attribute, defaultTheme]);
|
|
194
|
+
return mountWatcher({ storageKey, attribute, defaultTheme, variables, enableColorScheme }, theme);
|
|
195
|
+
}, [theme, storageKey, attribute, defaultTheme, variables, enableColorScheme]);
|
|
166
196
|
return null;
|
|
167
197
|
}
|
|
168
198
|
|