@cerberus-design/react
Version:
The Cerberus Design React component library.
1 lines • 6.84 kB
Source Map (JSON)
{"version":3,"sources":["../../../src/context/theme.tsx","../../../src/hooks/useTheme.ts"],"sourcesContent":["'use client'\n\nimport { createContext, useContext, type PropsWithChildren } from 'react'\nimport { useTheme, type UseThemeOptions } from '../hooks/useTheme'\n\n/**\n * This module provides a context and hook for the theme.\n * @module Theme\n */\n\nexport type DefaultThemes = 'cerberus' | 'acheron'\nexport type CustomThemes<K extends string = DefaultThemes> = 'cerberus' | K\nexport type ColorModes = 'light' | 'dark' | 'system'\n\nexport interface ThemeContextValue<T extends string = DefaultThemes> {\n /**\n * The current theme.\n */\n theme: CustomThemes<T>\n /**\n * The current color mode.\n */\n mode: ColorModes\n /**\n * Called when the theme is updated.\n */\n updateTheme: (theme: T) => void\n /**\n * Called when the color mode is updated.\n */\n updateMode: (mode: ColorModes) => void\n}\n\nconst ThemeContext = createContext<ThemeContextValue<DefaultThemes> | null>(\n null,\n)\n\nexport interface ThemeProviderProps extends UseThemeOptions {\n /**\n * The default theme.\n */\n defaultTheme?: DefaultThemes\n /**\n * The default color mode.\n */\n defaultColorMode?: ColorModes\n}\n\n/**\n * A context provider that allows the user to set the theme and mode of the\n * application.\n * @see https://cerberus.digitalu.design/react/use-theme-context\n * @example\n * ```tsx\n * <ThemeProvider>\n * <App />\n * </ThemeProvider>\n * ```\n */\nexport function ThemeProvider(props: PropsWithChildren<ThemeProviderProps>) {\n const state = useTheme(props.defaultTheme, props.defaultColorMode, {\n cache: props.cache,\n updateMode: props.updateMode,\n updateTheme: props.updateTheme,\n }) as ThemeContextValue<DefaultThemes>\n\n return (\n <ThemeContext.Provider value={state}>\n {props.children}\n </ThemeContext.Provider>\n )\n}\n\n/**\n * Used to access the theme context.\n */\nexport function useThemeContext(): ThemeContextValue<DefaultThemes> {\n const context = useContext(ThemeContext)\n if (!context) {\n throw new Error('useThemeContext must be used within a ThemeProvider')\n }\n return context\n}\n","'use client'\n\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useState,\n} from 'react'\nimport {\n type ColorModes,\n type CustomThemes,\n type DefaultThemes,\n type ThemeContextValue,\n} from '../context/theme'\n\n/**\n * This module provides a hook for using the theme.\n * @module\n */\n\nexport const THEME_KEY = 'cerberus-theme'\nexport const MODE_KEY = 'cerberus-mode'\n\nexport interface UseThemeOptions<T extends string = DefaultThemes> {\n /**\n * Whether to cache the theme in local storage.\n */\n cache?: boolean\n /**\n * Called when the theme is updated.\n */\n updateTheme?: (theme: T) => void\n /**\n * Called when the color mode is updated.\n */\n updateMode?: (mode: ColorModes) => void\n}\n\n/**\n * Provides a hook for using the theme for a single instance of the application.\n * @see https://cerberus.digitalu.design/react/use-theme\n * @param defaultTheme The default theme.\n * @param defaultColorMode The default color mode.\n * @param options Additional options.\n */\nexport function useTheme<C extends string = DefaultThemes>(\n defaultTheme: CustomThemes<C> = 'cerberus',\n defaultColorMode: ColorModes = 'light',\n options: UseThemeOptions<C> = {},\n): ThemeContextValue<C> {\n const { updateMode, updateTheme, cache } = options\n const [theme, setTheme] = useState<CustomThemes<C>>(defaultTheme)\n const [colorMode, setColorMode] = useState<ColorModes>(defaultColorMode)\n\n const handleThemeChange = useCallback(\n (newTheme: C) => {\n setTheme(newTheme)\n updateTheme?.(newTheme)\n },\n [updateTheme],\n )\n\n const handleColorModeChange = useCallback(\n (newMode: ColorModes) => {\n setColorMode(newMode)\n updateMode?.(newMode)\n },\n [updateMode],\n )\n\n useLayoutEffect(() => {\n const theme = localStorage.getItem(THEME_KEY)\n if (theme) {\n setTheme(theme as CustomThemes<C>)\n }\n }, [])\n\n useLayoutEffect(() => {\n const mode = localStorage.getItem(MODE_KEY)\n if (mode) {\n setColorMode(mode as ColorModes)\n }\n }, [])\n\n useEffect(() => {\n const root = document.documentElement\n root.dataset.pandaTheme = theme\n\n if (cache) {\n localStorage.setItem(THEME_KEY, theme)\n }\n }, [theme, cache])\n\n useEffect(() => {\n const root = document.documentElement\n\n if (colorMode === 'system') {\n root.dataset.colorMode = window.matchMedia('(prefers-color-scheme: dark)')\n .matches\n ? 'dark'\n : 'light'\n } else {\n root.dataset.colorMode = colorMode\n }\n\n if (cache) {\n localStorage.setItem(MODE_KEY, colorMode)\n }\n }, [colorMode, cache])\n\n return useMemo(\n () => ({\n theme,\n mode: colorMode,\n updateTheme: handleThemeChange,\n updateMode: handleColorModeChange,\n }),\n [theme, colorMode, handleThemeChange, handleColorModeChange],\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,IAAAA,gBAAkE;;;ACAlE,mBAMO;AAaA,IAAM,YAAY;AAClB,IAAM,WAAW;AAwBjB,SAAS,SACd,eAAgC,YAChC,mBAA+B,SAC/B,UAA8B,CAAC,GACT;AACtB,QAAM,EAAE,YAAY,aAAa,MAAM,IAAI;AAC3C,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAA0B,YAAY;AAChE,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAqB,gBAAgB;AAEvE,QAAM,wBAAoB;AAAA,IACxB,CAAC,aAAgB;AACf,eAAS,QAAQ;AACjB,iDAAc;AAAA,IAChB;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAEA,QAAM,4BAAwB;AAAA,IAC5B,CAAC,YAAwB;AACvB,mBAAa,OAAO;AACpB,+CAAa;AAAA,IACf;AAAA,IACA,CAAC,UAAU;AAAA,EACb;AAEA,oCAAgB,MAAM;AACpB,UAAMC,SAAQ,aAAa,QAAQ,SAAS;AAC5C,QAAIA,QAAO;AACT,eAASA,MAAwB;AAAA,IACnC;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,oCAAgB,MAAM;AACpB,UAAM,OAAO,aAAa,QAAQ,QAAQ;AAC1C,QAAI,MAAM;AACR,mBAAa,IAAkB;AAAA,IACjC;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,8BAAU,MAAM;AACd,UAAM,OAAO,SAAS;AACtB,SAAK,QAAQ,aAAa;AAE1B,QAAI,OAAO;AACT,mBAAa,QAAQ,WAAW,KAAK;AAAA,IACvC;AAAA,EACF,GAAG,CAAC,OAAO,KAAK,CAAC;AAEjB,8BAAU,MAAM;AACd,UAAM,OAAO,SAAS;AAEtB,QAAI,cAAc,UAAU;AAC1B,WAAK,QAAQ,YAAY,OAAO,WAAW,8BAA8B,EACtE,UACC,SACA;AAAA,IACN,OAAO;AACL,WAAK,QAAQ,YAAY;AAAA,IAC3B;AAEA,QAAI,OAAO;AACT,mBAAa,QAAQ,UAAU,SAAS;AAAA,IAC1C;AAAA,EACF,GAAG,CAAC,WAAW,KAAK,CAAC;AAErB,aAAO;AAAA,IACL,OAAO;AAAA,MACL;AAAA,MACA,MAAM;AAAA,MACN,aAAa;AAAA,MACb,YAAY;AAAA,IACd;AAAA,IACA,CAAC,OAAO,WAAW,mBAAmB,qBAAqB;AAAA,EAC7D;AACF;;;ADrDI;AAlCJ,IAAM,mBAAe;AAAA,EACnB;AACF;AAwBO,SAAS,cAAc,OAA8C;AAC1E,QAAM,QAAQ,SAAS,MAAM,cAAc,MAAM,kBAAkB;AAAA,IACjE,OAAO,MAAM;AAAA,IACb,YAAY,MAAM;AAAA,IAClB,aAAa,MAAM;AAAA,EACrB,CAAC;AAED,SACE,4CAAC,aAAa,UAAb,EAAsB,OAAO,OAC3B,gBAAM,UACT;AAEJ;AAKO,SAAS,kBAAoD;AAClE,QAAM,cAAU,0BAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,SAAO;AACT;","names":["import_react","theme"]}