import React, { createContext, useContext, useReducer, useMemo, useCallback, useEffect } from 'react' const UPDATE_DARKMODE = 'UPDATE_DARKMODE' const DARKMODE_KEY = 'DARKMODE_KEY' const DARK_MODE_OPTION = { DARK: 'DARK', LIGHT: 'LIGHT' } const INITIAL_STATE = { [DARKMODE_KEY]: DARK_MODE_OPTION.LIGHT } const ApplicationContext = createContext({}) function useApplicationContext() { return useContext(ApplicationContext) } function reducer(state, { type, payload }) { switch (type) { case UPDATE_DARKMODE: { const { mode } = payload return { ...state, [DARKMODE_KEY]: mode } } default: { throw Error(`Unexpected action type in DataContext reducer: '${type}'.`) } } } export default function Provider({ children }) { const [state, dispatch] = useReducer(reducer, INITIAL_STATE) const updateDarkMode = useCallback(mode => { dispatch({ type: UPDATE_DARKMODE, payload: { mode } }) }, []) return ( <ApplicationContext.Provider value={useMemo(() => [state, { updateDarkMode }], [state, updateDarkMode])}> {children} </ApplicationContext.Provider> ) } export function Updater() { const [, { updateDarkMode }] = useApplicationContext() useEffect(() => { const root = window.document.documentElement const initialColorValue = root.style.getPropertyValue('--initial-color-mode') if (initialColorValue === 'dark') { updateDarkMode(DARK_MODE_OPTION.DARK) } else { updateDarkMode(DARK_MODE_OPTION.DARK.LIGHT) } }, []) return null } export function useDarkMode() { const [state, { updateDarkMode }] = useApplicationContext() const darkModeOn = state?.[DARKMODE_KEY] === DARK_MODE_OPTION.DARK function toggleDarkMode() { if (darkModeOn) { updateDarkMode(DARK_MODE_OPTION.LIGHT) localStorage.setItem('color-mode', 'light') } else { updateDarkMode(DARK_MODE_OPTION.DARK) localStorage.setItem('color-mode', 'dark') } } return [darkModeOn, toggleDarkMode] }