Skip to content

Commit

Permalink
Fix setting system twice
Browse files Browse the repository at this point in the history
  • Loading branch information
pacocoursey committed Mar 17, 2021
1 parent 2bcb650 commit 8ab93d9
Showing 1 changed file with 42 additions and 21 deletions.
63 changes: 42 additions & 21 deletions index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React, {
useContext,
useEffect,
useState,
useRef,
memo
} from 'react'
import NextHead from 'next/head'
Expand All @@ -24,6 +25,7 @@ const ThemeContext = createContext<UseThemeProps>({
export const useTheme = () => useContext(ThemeContext)

const colorSchemes = ['light', 'dark']
const MEDIA = '(prefers-color-scheme: dark)'

interface ValueObject {
[themeName: string]: string
Expand Down Expand Up @@ -59,9 +61,22 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
const [resolvedTheme, setResolvedTheme] = useState(() => getTheme(storageKey))
const attrs = !value ? themes : Object.values(value)

const handleMediaQuery = useCallback(
(e?) => {
const systemTheme = getSystemTheme(e)
setResolvedTheme(systemTheme)
if (theme === 'system' && !forcedTheme) changeTheme(systemTheme, false)
},
[theme, forcedTheme]
)

// Ref hack to avoid adding handleMediaQuery as a dep
const mediaListener = useRef(handleMediaQuery)
mediaListener.current = handleMediaQuery

const changeTheme = useCallback(
(theme, updateStorage = true, updateDOM = true) => {
const name = value?.[theme] || theme
let name = value?.[theme] || theme

const enable =
disableTransitionOnChange && updateDOM ? disableAnimation() : null
Expand All @@ -74,6 +89,11 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
}
}

if (theme === 'system' && enableSystem) {
const resolved = getSystemTheme()
name = value?.[resolved] || resolved
}

if (updateDOM) {
const d = document.documentElement

Expand All @@ -89,29 +109,18 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
[]
)

const handleMediaQuery = useCallback(
(e) => {
const isDark = e.matches
const systemTheme = isDark ? 'dark' : 'light'
setResolvedTheme(systemTheme)

if (theme === 'system' && !forcedTheme) changeTheme(systemTheme, false)
},
[theme, forcedTheme]
)

useEffect(() => {
if (!enableSystem) {
return
}
const handler = mediaListener.current

// Always listen to System preference
const media = window.matchMedia('(prefers-color-scheme: dark)')
media.addListener(handleMediaQuery)
handleMediaQuery(media)
const media = window.matchMedia(MEDIA)

// Intentionally use deprecated listener methods to support iOS & old browsers
media.addListener(handler)
handler(media)

return () => media.removeListener(handleMediaQuery)
}, [handleMediaQuery])
return () => media.removeListener(handler)
}, [])

const setTheme = useCallback(
(newTheme) => {
Expand All @@ -125,6 +134,7 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
[forcedTheme]
)

// localStorage event handling
useEffect(() => {
const handleStorage = (e: StorageEvent) => {
if (e.key !== storageKey) {
Expand All @@ -139,6 +149,7 @@ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
return () => window.removeEventListener('storage', handleStorage)
}, [setTheme])

// color-scheme handling
useEffect(() => {
if (!enableColorScheme) return

Expand Down Expand Up @@ -249,7 +260,7 @@ const ThemeScript = memo(
key="next-themes-script"
dangerouslySetInnerHTML={{
// prettier-ignore
__html: `!function(){try {${optimization}var e=localStorage.getItem('${storageKey}');${!defaultSystem ? updateDOM(defaultTheme) + ';' : ''}if("system"===e||(!e&&${defaultSystem})){var t="(prefers-color-scheme: dark)",m=window.matchMedia(t);m.media!==t||m.matches?${updateDOM('dark')}:${updateDOM('light')}}else if(e) ${value ? `var x=${JSON.stringify(value)};` : ''}${updateDOM(value ? 'x[e]' : 'e', true)}}catch(e){}}()`
__html: `!function(){try {${optimization}var e=localStorage.getItem('${storageKey}');${!defaultSystem ? updateDOM(defaultTheme) + ';' : ''}if("system"===e||(!e&&${defaultSystem})){var t="${MEDIA}",m=window.matchMedia(t);m.media!==t||m.matches?${updateDOM('dark')}:${updateDOM('light')}}else if(e) ${value ? `var x=${JSON.stringify(value)};` : ''}${updateDOM(value ? 'x[e]' : 'e', true)}}catch(e){}}()`
}}
/>
) : (
Expand Down Expand Up @@ -303,3 +314,13 @@ const disableAnimation = () => {
}, 1)
}
}

const getSystemTheme = (e?: MediaQueryList) => {
if (!e) {
e = window.matchMedia(MEDIA)
}

const isDark = e.matches
const systemTheme = isDark ? 'dark' : 'light'
return systemTheme
}

0 comments on commit 8ab93d9

Please sign in to comment.