| ... | ... | @@ -18,6 +18,7 @@ const DYNAMIC_THEME_COLOR_SELECTOR = `meta[name="${THEME_COLOR_META_NAME}"][data |
| 18 | 18 | let listeners: Array<() => void> = []; |
| 19 | 19 | let lastSnapshot: ThemeSnapshot | null = null; |
| 20 | 20 | let lastDesktopTheme: Theme | null = null; |
| 21 | let lastAppliedTheme: ThemeSnapshot | null = null; |
| 21 | 22 | |
| 22 | 23 | function emitChange() { |
| 23 | 24 | for (const listener of listeners) listener(); |
| ... | ... | @@ -28,7 +29,11 @@ function hasThemeStorage() { |
| 28 | 29 | } |
| 29 | 30 | |
| 30 | 31 | function getSystemDark() { |
| 31 | | return typeof window !== "undefined" && window.matchMedia(MEDIA_QUERY).matches; |
| 32 | return ( |
| 33 | typeof window !== "undefined" && |
| 34 | typeof window.matchMedia === "function" && |
| 35 | window.matchMedia(MEDIA_QUERY).matches |
| 36 | ); |
| 32 | 37 | } |
| 33 | 38 | |
| 34 | 39 | function getStored(): Theme { |
| ... | ... | @@ -89,11 +94,18 @@ export function syncBrowserChromeTheme() { |
| 89 | 94 | |
| 90 | 95 | function applyTheme(theme: Theme, suppressTransitions = false) { |
| 91 | 96 | if (typeof document === "undefined" || typeof window === "undefined") return; |
| 97 | const systemDark = theme === "system" ? getSystemDark() : false; |
| 98 | if (lastAppliedTheme?.theme === theme && lastAppliedTheme.systemDark === systemDark) { |
| 99 | syncDesktopTheme(theme); |
| 100 | return; |
| 101 | } |
| 102 | |
| 92 | 103 | if (suppressTransitions) { |
| 93 | 104 | document.documentElement.classList.add("no-transitions"); |
| 94 | 105 | } |
| 95 | | const isDark = theme === "dark" || (theme === "system" && getSystemDark()); |
| 106 | const isDark = theme === "dark" || (theme === "system" && systemDark); |
| 96 | 107 | document.documentElement.classList.toggle("dark", isDark); |
| 108 | lastAppliedTheme = { theme, systemDark }; |
| 97 | 109 | syncBrowserChromeTheme(); |
| 98 | 110 | syncDesktopTheme(theme); |
| 99 | 111 | if (suppressTransitions) { |
| ... | ... | @@ -148,12 +160,12 @@ function subscribe(listener: () => void): () => void { |
| 148 | 160 | listeners.push(listener); |
| 149 | 161 | |
| 150 | 162 | // Listen for system preference changes |
| 151 | | const mq = window.matchMedia(MEDIA_QUERY); |
| 163 | const mq = typeof window.matchMedia === "function" ? window.matchMedia(MEDIA_QUERY) : null; |
| 152 | 164 | const handleChange = () => { |
| 153 | 165 | if (getStored() === "system") applyTheme("system", true); |
| 154 | 166 | emitChange(); |
| 155 | 167 | }; |
| 156 | | mq.addEventListener("change", handleChange); |
| 168 | mq?.addEventListener("change", handleChange); |
| 157 | 169 | |
| 158 | 170 | // Listen for storage changes from other tabs |
| 159 | 171 | const handleStorage = (e: StorageEvent) => { |
| ... | ... | @@ -166,7 +178,7 @@ function subscribe(listener: () => void): () => void { |
| 166 | 178 | |
| 167 | 179 | return () => { |
| 168 | 180 | listeners = listeners.filter((l) => l !== listener); |
| 169 | | mq.removeEventListener("change", handleChange); |
| 181 | mq?.removeEventListener("change", handleChange); |
| 170 | 182 | window.removeEventListener("storage", handleStorage); |
| 171 | 183 | }; |
| 172 | 184 | } |