Last active
November 5, 2022 15:36
-
-
Save k-kinzal/7e0f169f9cc1bea3579b8157ed4ab8d6 to your computer and use it in GitHub Desktop.
test color scheme provider
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
createContext, Dispatch, | |
PropsWithChildren, | |
ReactElement, | |
useContext, useEffect, useReducer, useState | |
} from "react"; | |
import {useLocalStorageReducer} from "../hooks/localStorage"; | |
export type ColorScheme = "system" | "light" | "dark"; | |
export type Action = | |
| { type: "changeToSystem", payload: { colorScheme: "system" } } | |
| { type: "changeToLight", payload: { colorScheme: "light" } } | |
| { type: "changeToDark", payload: { colorScheme: "dark" } }; | |
const STORAGE_KEY = "colorScheme"; | |
const initializeState: ColorScheme = "system"; | |
function reducer(state: ColorScheme, action: Action): ColorScheme { | |
switch (action.type) { | |
case "changeToSystem": | |
case "changeToLight": | |
case "changeToDark": | |
return action.payload.colorScheme; | |
} | |
} | |
const ColorSchemeContext = createContext<ColorScheme | null>(null); | |
const ColorSchemeDispatchContext = createContext<Dispatch<Action> | null>(null); | |
export function useColorScheme(): ColorScheme { | |
let colorScheme = useContext(ColorSchemeContext); | |
if (!colorScheme) { | |
throw new Error('ColorSchemeProvider is not set'); | |
} | |
return colorScheme; | |
} | |
const darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)'); | |
export function useDarkMode(): boolean { | |
let [systemColorScheme, setSystemColorScheme] = useState(darkModeQuery.matches ? "dark" : "light"); | |
let colorScheme = useContext(ColorSchemeContext); | |
useEffect(() => { | |
let listener = (event: MediaQueryListEvent) => { | |
if (colorScheme === "system") { | |
setSystemColorScheme(event.matches ? "dark" : "light"); | |
} | |
}; | |
darkModeQuery.addEventListener('change', listener); | |
return () => { | |
darkModeQuery.removeEventListener('change', listener); | |
} | |
}, []) | |
switch (colorScheme) { | |
case null: | |
return false; | |
case "system": | |
return systemColorScheme === "dark"; | |
case "light": | |
return false; | |
case "dark": | |
return false; | |
} | |
} | |
export function useColorSchemeDispatch(): Dispatch<Action> { | |
let dispatch = useContext(ColorSchemeDispatchContext); | |
if (!dispatch) { | |
throw new Error("ColorSchemeProvider is not set"); | |
} | |
return dispatch; | |
} | |
export function actionChangeColorSchemeToSystem(): Action { | |
return { | |
type: "changeToSystem", | |
payload: { | |
colorScheme: "system" | |
}}; | |
} | |
export function actionChangeColorSchemeToLight(): Action { | |
return { | |
type: "changeToLight", | |
payload: { | |
colorScheme: "light" | |
}}; | |
} | |
export function actionChangeColorSchemeToDark(): Action { | |
return { | |
type: "changeToDark", | |
payload: { | |
colorScheme: "dark" | |
}}; | |
} | |
export function ColorSchemeProvider({children}: PropsWithChildren): ReactElement { | |
let [state, dispatch] = useLocalStorageReducer(STORAGE_KEY, reducer, initializeState); | |
return ( | |
<ColorSchemeContext.Provider value={state}> | |
<ColorSchemeDispatchContext.Provider value={dispatch}> | |
{children} | |
</ColorSchemeDispatchContext.Provider> | |
</ColorSchemeContext.Provider> | |
); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
Dispatch, | |
useEffect, useReducer, | |
} from "react"; | |
export function useLocalStorageReducer<S, I, A>( | |
key: string, | |
reducer: ((state: S, action: A) => S), | |
initialArg: I & S, | |
): [S, Dispatch<A>] { | |
let [state, dispatch] = useReducer(reducer, initialArg, (arg) => { | |
if (typeof window === "undefined") { | |
return arg; | |
} | |
try { | |
let item = window.localStorage.getItem(key); | |
return item ? JSON.parse(item) : arg; | |
} catch (e) { | |
console.error(e); | |
return arg; | |
} | |
}); | |
let customDispatch: Dispatch<A> = (action: A) => { | |
try { | |
if (typeof window === "undefined") { | |
dispatch(action); | |
} else { | |
let item = action instanceof Function ? action(state) : action; | |
window.localStorage.setItem(key, JSON.stringify(item)); | |
} | |
} catch (e) { | |
console.error(e); | |
} | |
}; | |
useEffect(() => { | |
if (typeof window === "undefined") { | |
return; | |
} | |
let listener = (event: StorageEvent) => { | |
if (event.storageArea !== localStorage) { | |
return; | |
} | |
if (event.key !== key) { | |
return; | |
} | |
try { | |
let item = window.localStorage.getItem(key); | |
if (item === null) { | |
return; | |
} | |
let value = JSON.parse(item); | |
dispatch(value); | |
} catch (e) { | |
console.error(e); | |
} | |
}; | |
window.addEventListener('storage', listener, false); | |
return () => { | |
window.removeEventListener("storage", listener); | |
}; | |
}, [key]); | |
return [state, customDispatch]; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import {ThemeProvider as StyledComponentsThemeProvider} from "styled-components"; | |
import {PropsWithChildren, ReactElement} from "react"; | |
import {useDarkMode} from "./colorScheme"; | |
const Theme = { | |
light: { | |
color: "black" | |
}, | |
dark: { | |
color: "white" | |
} | |
} | |
export function ThemeProvider({children}: PropsWithChildren): ReactElement { | |
let isDarkMode = useDarkMode(); | |
return ( | |
<StyledComponentsThemeProvider theme={Theme[isDarkMode ? "dark" : "light"]}> | |
{children} | |
</StyledComponentsThemeProvider> | |
) | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment