UNPKG

react-vite-themes

Version:

A test/experimental React theme system created for learning purposes. Features atomic design components, SCSS variables, and dark/light theme support. Not intended for production use.

90 lines (89 loc) 3.21 kB
import { jsx as _jsx } from "react/jsx-runtime"; import React, { createContext, useContext, useState, useEffect } from 'react'; import { useLocalStorage } from '../hooks/useLocalStorage'; const ThemeContext = createContext(undefined); export const ThemeProvider = ({ children }) => { // Get system theme preference const getSystemTheme = () => { if (typeof window !== 'undefined') { return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; } return 'light'; // Default fallback }; // Initialize theme from localStorage or system preference const getInitialTheme = () => { if (typeof window !== 'undefined') { const savedTheme = localStorage.getItem('theme'); if (savedTheme === 'light' || savedTheme === 'dark') { return savedTheme; } // If no saved preference, use system theme return getSystemTheme(); } return 'light'; }; const [theme, setTheme] = useLocalStorage('theme', getInitialTheme()); const [isSystemTheme, setIsSystemTheme] = useState(() => { if (typeof window !== 'undefined') { return !localStorage.getItem('theme'); // true if no saved preference } return true; }); // Listen for system theme changes useEffect(() => { if (typeof window === 'undefined') return; const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); const handleSystemThemeChange = (e) => { if (isSystemTheme) { const newTheme = e.matches ? 'dark' : 'light'; setTheme(newTheme); } }; mediaQuery.addEventListener('change', handleSystemThemeChange); return () => { mediaQuery.removeEventListener('change', handleSystemThemeChange); }; }, [isSystemTheme, setTheme]); // Apply theme to document useEffect(() => { if (typeof document !== 'undefined') { document.documentElement.setAttribute('data-theme', theme); } }, [theme]); const toggleTheme = () => { const newTheme = theme === 'light' ? 'dark' : 'light'; setTheme(newTheme); setIsSystemTheme(false); // User manually changed theme }; const setSystemTheme = () => { const systemTheme = getSystemTheme(); setTheme(systemTheme); setIsSystemTheme(true); localStorage.removeItem('theme'); // Clear saved preference }; const setLightTheme = () => { setTheme('light'); setIsSystemTheme(false); }; const setDarkTheme = () => { setTheme('dark'); setIsSystemTheme(false); }; const value = { theme, isSystemTheme, toggleTheme, setSystemTheme, setLightTheme, setDarkTheme, }; return (_jsx(ThemeContext.Provider, { value: value, children: children })); }; export const useTheme = () => { const context = useContext(ThemeContext); if (context === undefined) { throw new Error('useTheme must be used within a ThemeProvider'); } return context; };