import { useEffect, useMemo, useState } from 'react'; import * as themes from '../themes'; import { nicinabox as defaultDarkScheme } from 'redux-devtools-themes'; import * as baseSchemes from 'base16'; import * as additionalSchemes from '../colorSchemes'; import invertColors from '../utils/invertColors'; import { Theme as ThemeBase } from '../themes/default'; export const schemes = { ...baseSchemes, ...additionalSchemes }; export const listSchemes = () => Object.keys(schemes).slice(1).sort(); // remove `__esModule` export const listThemes = () => Object.keys(themes); export type ThemeName = keyof typeof themes; export type SchemeName = keyof typeof schemes; export interface ThemeData { theme: keyof typeof themes; scheme: keyof typeof schemes; colorPreference: 'auto' | 'light' | 'dark'; } export interface ThemeFromProvider extends ThemeBase { type: keyof typeof themes; light: boolean; } const getTheme = ( type: keyof typeof themes, scheme: keyof typeof schemes, light: boolean, ): ThemeFromProvider => { let colors; if (scheme === 'default') { colors = light ? schemes.default : defaultDarkScheme; } else { colors = schemes[scheme]; if (light) colors = invertColors(colors); } let theme = { type, light, ...themes.default(colors), }; if (type !== 'default') { theme = { ...theme, ...themes[type](colors) }; } return theme; }; export const useTheme = ({ theme: type, scheme, colorPreference, }: ThemeData): ThemeFromProvider => { const [prefersDarkColorScheme, setPrefersDarkColorScheme] = useState( window.matchMedia('(prefers-color-scheme: dark)').matches, ); useEffect(() => { const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); const handleChange = ({ matches }: MediaQueryListEvent) => { setPrefersDarkColorScheme(matches); }; mediaQuery.addEventListener('change', handleChange); return () => mediaQuery.removeEventListener('change', handleChange); }, []); const light = useMemo( () => colorPreference === 'auto' ? !prefersDarkColorScheme : colorPreference === 'light', [colorPreference, prefersDarkColorScheme], ); return getTheme(type, scheme, light); };