Coder Social home page Coder Social logo

Comments (1)

joaopaulomoraes avatar joaopaulomoraes commented on July 18, 2024

I found a solution by just adding a listener to the media event so that the theme would be updated again.

import * as storage from 'actions/storage';
import {
  createContext,
  useContext,
  useEffect,
  useState
} from 'react';

type Theme = 'dark' | 'light' | 'system';

type ThemeProviderProps = {
  children: React.ReactNode;
  defaultTheme ? : Theme;
  storageKey ? : string;
};

type ThemeProviderState = {
  theme: Theme;
  setTheme: (theme: Theme) => void;
};

const ThemeProviderContext = createContext < ThemeProviderState > ({
  theme: 'system',
  setTheme: () => null
});

export const ThemeProvider = ({
  children,
  storageKey = '@theme',
  defaultTheme = 'system',
  ...props
}: ThemeProviderProps) => {
  const [theme, setTheme] = useState < Theme > (
    () => storage.get < Theme > (storageKey) || defaultTheme
  );

  useEffect(() => {
    const root = document.documentElement;
    const systemTheme = matchMedia('(prefers-color-scheme: dark)');

    const updateTheme = () => {
      root.classList.remove('light', 'dark');

      if (theme === 'system') {
        root.classList.add(systemTheme.matches ? 'dark' : 'light');
        return;
      }

      root.classList.add(theme);
    };

    updateTheme();
    systemTheme.addEventListener('change', updateTheme);

    return () => {
      systemTheme.removeEventListener('change', updateTheme);
    };
  }, [theme]);

  const value = {
    theme,
    setTheme: (newTheme: Theme) => {
      storage.set(storageKey, newTheme);
      setTheme(newTheme);
    }
  };

  return ( <
    ThemeProviderContext.Provider {
      ...props
    }
    value = {
      value
    } > {
      children
    } <
    /ThemeProviderContext.Provider>
  );
};

export const useTheme = () => {
  const context = useContext(ThemeProviderContext);

  if (context === null) {
    throw new Error('useTheme must be used within a ThemeProvider');
  }

  return context;
};

from ui.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.