@cerberus-design/react 0.9.2-next-32b3154 → 0.9.2-next-cf82128

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -282,7 +282,7 @@ export { CollisionDescriptor }
282
282
 
283
283
  export { CollisionDetection }
284
284
 
285
- declare type ColorModes = 'light' | 'dark';
285
+ declare type ColorModes = 'light' | 'dark' | 'system';
286
286
  export { ColorModes }
287
287
  export { ColorModes as ColorModes_alias_1 }
288
288
 
@@ -349,7 +349,7 @@ export declare const defaultIcons: DefinedIcons;
349
349
 
350
350
  export { defaultScreenReaderInstructions }
351
351
 
352
- declare type DefaultThemes = 'cerberus';
352
+ declare type DefaultThemes = 'cerberus' | 'acheron';
353
353
  export { DefaultThemes }
354
354
  export { DefaultThemes as DefaultThemes_alias_1 }
355
355
 
@@ -1603,7 +1603,7 @@ declare interface ThemeContextValue<T extends string = DefaultThemes> {
1603
1603
  theme: CustomThemes<T>;
1604
1604
  mode: ColorModes;
1605
1605
  updateTheme: (theme: T) => void;
1606
- updateMode: () => void;
1606
+ updateMode: (mode: ColorModes) => void;
1607
1607
  }
1608
1608
  export { ThemeContextValue }
1609
1609
  export { ThemeContextValue as ThemeContextValue_alias_1 }
@@ -1617,10 +1617,17 @@ export { ThemeContextValue as ThemeContextValue_alias_1 }
1617
1617
  * </ThemeProvider>
1618
1618
  * ```
1619
1619
  */
1620
- declare function ThemeProvider(props: PropsWithChildren<unknown>): JSX.Element;
1620
+ declare function ThemeProvider(props: PropsWithChildren<ThemeProviderProps>): JSX.Element;
1621
1621
  export { ThemeProvider }
1622
1622
  export { ThemeProvider as ThemeProvider_alias_1 }
1623
1623
 
1624
+ declare interface ThemeProviderProps extends UseThemeOptions {
1625
+ defaultTheme?: DefaultThemes;
1626
+ defaultColorMode?: ColorModes;
1627
+ }
1628
+ export { ThemeProviderProps }
1629
+ export { ThemeProviderProps as ThemeProviderProps_alias_1 }
1630
+
1624
1631
  declare type ThProps = ThBaseProps & ThVariantProps;
1625
1632
  export { ThProps }
1626
1633
  export { ThProps as ThProps_alias_1 }
@@ -1759,7 +1766,7 @@ declare function useTabsKeyboardNavigation(): {
1759
1766
  export { useTabsKeyboardNavigation }
1760
1767
  export { useTabsKeyboardNavigation as useTabsKeyboardNavigation_alias_1 }
1761
1768
 
1762
- declare function useTheme<C extends string = DefaultThemes>(defaultTheme?: CustomThemes<C>, defaultColorMode?: ColorModes): ThemeContextValue<C>;
1769
+ declare function useTheme<C extends string = DefaultThemes>(defaultTheme?: CustomThemes<C>, defaultColorMode?: ColorModes, options?: UseThemeOptions<C>): ThemeContextValue<C>;
1763
1770
  export { useTheme }
1764
1771
  export { useTheme as useTheme_alias_1 }
1765
1772
 
@@ -1767,6 +1774,14 @@ declare function useThemeContext(): ThemeContextValue<DefaultThemes>;
1767
1774
  export { useThemeContext }
1768
1775
  export { useThemeContext as useThemeContext_alias_1 }
1769
1776
 
1777
+ declare interface UseThemeOptions<T extends string = DefaultThemes> {
1778
+ cache?: boolean;
1779
+ updateTheme?: (theme: T) => void;
1780
+ updateMode?: (mode: ColorModes) => void;
1781
+ }
1782
+ export { UseThemeOptions }
1783
+ export { UseThemeOptions as UseThemeOptions_alias_1 }
1784
+
1770
1785
  declare function useToggle(options?: UseToggleOptions): ToggleHookReturn;
1771
1786
  export { useToggle }
1772
1787
  export { useToggle as useToggle_alias_1 }
@@ -0,0 +1,31 @@
1
+ import {
2
+ useTheme
3
+ } from "./chunk-ETAK2CSW.js";
4
+
5
+ // src/context/theme.tsx
6
+ import { createContext, useContext } from "react";
7
+ import { jsx } from "react/jsx-runtime";
8
+ var ThemeContext = createContext(
9
+ null
10
+ );
11
+ function ThemeProvider(props) {
12
+ const state = useTheme(props.defaultTheme, props.defaultColorMode, {
13
+ cache: props.cache,
14
+ updateMode: props.updateMode,
15
+ updateTheme: props.updateTheme
16
+ });
17
+ return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: state, children: props.children });
18
+ }
19
+ function useThemeContext() {
20
+ const context = useContext(ThemeContext);
21
+ if (!context) {
22
+ throw new Error("useThemeContext must be used within a ThemeProvider");
23
+ }
24
+ return context;
25
+ }
26
+
27
+ export {
28
+ ThemeProvider,
29
+ useThemeContext
30
+ };
31
+ //# sourceMappingURL=chunk-EIQKX73Y.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/context/theme.tsx"],"sourcesContent":["'use client'\n\nimport { createContext, useContext, type PropsWithChildren } from 'react'\nimport { useTheme, type UseThemeOptions } from '../hooks/useTheme'\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 theme: CustomThemes<T>\n mode: ColorModes\n updateTheme: (theme: T) => void\n updateMode: (mode: ColorModes) => void\n}\n\nconst ThemeContext = createContext<ThemeContextValue<DefaultThemes> | null>(\n null,\n)\n\nexport interface ThemeProviderProps extends UseThemeOptions {\n defaultTheme?: DefaultThemes\n defaultColorMode?: ColorModes\n}\n\n/**\n * A context provider that allows the user to set the theme and mode of the application.\n * @example\n * ```tsx\n * <ThemeProvider>\n * <App />\n * </ThemeProvider>\n * ```\n */\nexport function ThemeProvider(\n props: PropsWithChildren<ThemeProviderProps>,\n): JSX.Element {\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\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"],"mappings":";;;;;AAEA,SAAS,eAAe,kBAA0C;AA0C9D;AA5BJ,IAAM,eAAe;AAAA,EACnB;AACF;AAgBO,SAAS,cACd,OACa;AACb,QAAM,QAAQ,SAAS,MAAM,cAAc,MAAM,kBAAkB;AAAA,IACjE,OAAO,MAAM;AAAA,IACb,YAAY,MAAM;AAAA,IAClB,aAAa,MAAM;AAAA,EACrB,CAAC;AAED,SACE,oBAAC,aAAa,UAAb,EAAsB,OAAO,OAC3B,gBAAM,UACT;AAEJ;AAEO,SAAS,kBAAoD;AAClE,QAAM,UAAU,WAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,SAAO;AACT;","names":[]}
@@ -0,0 +1,71 @@
1
+ // src/hooks/useTheme.ts
2
+ import {
3
+ useCallback,
4
+ useEffect,
5
+ useLayoutEffect,
6
+ useMemo,
7
+ useState
8
+ } from "react";
9
+ var THEME_KEY = "cerberus-theme";
10
+ var MODE_KEY = "cerberus-mode";
11
+ function useTheme(defaultTheme = "cerberus", defaultColorMode = "light", options = {}) {
12
+ const { updateMode, updateTheme, cache } = options;
13
+ const [theme, setTheme] = useState(defaultTheme);
14
+ const [colorMode, setColorMode] = useState(defaultColorMode);
15
+ const handleThemeChange = useCallback(
16
+ (newTheme) => {
17
+ setTheme(newTheme);
18
+ updateTheme?.(newTheme);
19
+ },
20
+ [updateTheme]
21
+ );
22
+ const handleColorModeChange = useCallback(
23
+ (newMode) => {
24
+ setColorMode(newMode);
25
+ updateMode?.(newMode);
26
+ },
27
+ [updateMode]
28
+ );
29
+ useLayoutEffect(() => {
30
+ const theme2 = localStorage.getItem(THEME_KEY);
31
+ if (theme2) {
32
+ setTheme(theme2);
33
+ }
34
+ }, []);
35
+ useLayoutEffect(() => {
36
+ const mode = localStorage.getItem(MODE_KEY);
37
+ if (mode) {
38
+ setColorMode(mode);
39
+ }
40
+ }, []);
41
+ useEffect(() => {
42
+ if (cache) {
43
+ const root = document.documentElement;
44
+ root.dataset.pandaTheme = theme;
45
+ localStorage.setItem(THEME_KEY, theme);
46
+ }
47
+ }, [theme, cache]);
48
+ useEffect(() => {
49
+ if (cache) {
50
+ const root = document.documentElement;
51
+ root.dataset.colorMode = colorMode;
52
+ localStorage.setItem(MODE_KEY, colorMode);
53
+ }
54
+ }, [colorMode, cache]);
55
+ return useMemo(
56
+ () => ({
57
+ theme,
58
+ mode: colorMode,
59
+ updateTheme: handleThemeChange,
60
+ updateMode: handleColorModeChange
61
+ }),
62
+ [theme, colorMode, handleThemeChange, handleColorModeChange]
63
+ );
64
+ }
65
+
66
+ export {
67
+ THEME_KEY,
68
+ MODE_KEY,
69
+ useTheme
70
+ };
71
+ //# sourceMappingURL=chunk-ETAK2CSW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/hooks/useTheme.ts"],"sourcesContent":["'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\nexport const THEME_KEY = 'cerberus-theme'\nexport const MODE_KEY = 'cerberus-mode'\n\nexport interface UseThemeOptions<T extends string = DefaultThemes> {\n cache?: boolean\n updateTheme?: (theme: T) => void\n updateMode?: (mode: ColorModes) => void\n}\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 if (cache) {\n const root = document.documentElement\n root.dataset.pandaTheme = theme\n localStorage.setItem(THEME_KEY, theme)\n }\n }, [theme, cache])\n\n useEffect(() => {\n if (cache) {\n const root = document.documentElement\n root.dataset.colorMode = colorMode\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":";AAEA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAQA,IAAM,YAAY;AAClB,IAAM,WAAW;AAQjB,SAAS,SACd,eAAgC,YAChC,mBAA+B,SAC/B,UAA8B,CAAC,GACT;AACtB,QAAM,EAAE,YAAY,aAAa,MAAM,IAAI;AAC3C,QAAM,CAAC,OAAO,QAAQ,IAAI,SAA0B,YAAY;AAChE,QAAM,CAAC,WAAW,YAAY,IAAI,SAAqB,gBAAgB;AAEvE,QAAM,oBAAoB;AAAA,IACxB,CAAC,aAAgB;AACf,eAAS,QAAQ;AACjB,oBAAc,QAAQ;AAAA,IACxB;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAEA,QAAM,wBAAwB;AAAA,IAC5B,CAAC,YAAwB;AACvB,mBAAa,OAAO;AACpB,mBAAa,OAAO;AAAA,IACtB;AAAA,IACA,CAAC,UAAU;AAAA,EACb;AAEA,kBAAgB,MAAM;AACpB,UAAMA,SAAQ,aAAa,QAAQ,SAAS;AAC5C,QAAIA,QAAO;AACT,eAASA,MAAwB;AAAA,IACnC;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,kBAAgB,MAAM;AACpB,UAAM,OAAO,aAAa,QAAQ,QAAQ;AAC1C,QAAI,MAAM;AACR,mBAAa,IAAkB;AAAA,IACjC;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,QAAI,OAAO;AACT,YAAM,OAAO,SAAS;AACtB,WAAK,QAAQ,aAAa;AAC1B,mBAAa,QAAQ,WAAW,KAAK;AAAA,IACvC;AAAA,EACF,GAAG,CAAC,OAAO,KAAK,CAAC;AAEjB,YAAU,MAAM;AACd,QAAI,OAAO;AACT,YAAM,OAAO,SAAS;AACtB,WAAK,QAAQ,YAAY;AACzB,mBAAa,QAAQ,UAAU,SAAS;AAAA,IAC1C;AAAA,EACF,GAAG,CAAC,WAAW,KAAK,CAAC;AAErB,SAAO;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;","names":["theme"]}
@@ -1,13 +1,10 @@
1
1
  "use client";
2
2
  import {
3
- MODE_KEY,
4
- THEME_KEY,
5
3
  ThemeProvider,
6
4
  useThemeContext
7
- } from "../chunk-SXXWC6UD.js";
5
+ } from "../chunk-EIQKX73Y.js";
6
+ import "../chunk-ETAK2CSW.js";
8
7
  export {
9
- MODE_KEY,
10
- THEME_KEY,
11
8
  ThemeProvider,
12
9
  useThemeContext
13
10
  };
@@ -1,8 +1,12 @@
1
1
  "use client";
2
2
  import {
3
+ MODE_KEY,
4
+ THEME_KEY,
3
5
  useTheme
4
- } from "../chunk-SXXWC6UD.js";
6
+ } from "../chunk-ETAK2CSW.js";
5
7
  export {
8
+ MODE_KEY,
9
+ THEME_KEY,
6
10
  useTheme
7
11
  };
8
12
  //# sourceMappingURL=useTheme.js.map
@@ -6,6 +6,10 @@ import {
6
6
  PromptModal,
7
7
  usePromptModal
8
8
  } from "./chunk-T7TOXGZT.js";
9
+ import {
10
+ ThemeProvider,
11
+ useThemeContext
12
+ } from "./chunk-EIQKX73Y.js";
9
13
  import {
10
14
  Tag
11
15
  } from "./chunk-Z6IWNVPN.js";
@@ -111,10 +115,8 @@ import {
111
115
  import {
112
116
  MODE_KEY,
113
117
  THEME_KEY,
114
- ThemeProvider,
115
- useTheme,
116
- useThemeContext
117
- } from "./chunk-SXXWC6UD.js";
118
+ useTheme
119
+ } from "./chunk-ETAK2CSW.js";
118
120
  import {
119
121
  useToggle
120
122
  } from "./chunk-QEA6N6TN.js";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["/**\n * This module is the entry point for the Cerberus React package.\n * @module\n */\n\n// components\n\nexport * from './components/Avatar'\nexport * from './components/Button'\nexport * from './components/Checkbox'\nexport * from './components/Droppable'\nexport * from './components/FieldMessage'\nexport * from './components/FeatureFlag'\nexport * from './components/FileStatus'\nexport * from './components/FileUploader'\nexport * from './components/IconButton'\nexport * from './components/Input'\nexport * from './components/Label'\nexport * from './components/Modal'\nexport * from './components/ModalHeader'\nexport * from './components/ModalHeading'\nexport * from './components/ModalDescription'\nexport * from './components/NavMenuTrigger'\nexport * from './components/NavMenuList'\nexport * from './components/NavMenuLink'\nexport * from './components/Notification'\nexport * from './components/NotificationHeading'\nexport * from './components/NotificationDescription'\nexport * from './components/Portal'\nexport * from './components/ProgressBar'\nexport * from './components/Radio'\nexport * from './components/Select'\nexport * from './components/Tab'\nexport * from './components/TabList'\nexport * from './components/TabPanel'\nexport * from './components/Table'\nexport * from './components/Thead'\nexport * from './components/Th'\nexport * from './components/Td'\nexport * from './components/Tbody'\nexport * from './components/Tag'\nexport * from './components/Textarea'\nexport * from './components/Toggle'\nexport * from './components/Show'\n\n// context\n\nexport * from './context/confirm-modal'\nexport * from './context/feature-flags'\nexport * from './context/field'\nexport * from './context/navMenu'\nexport * from './context/notification-center'\nexport * from './context/prompt-modal'\nexport * from './context/tabs'\nexport * from './context/theme'\n\n// hooks\n\nexport * from './hooks/useModal'\nexport * from './hooks/useTheme'\nexport * from './hooks/useToggle'\n\n// aria-helpers\n\nexport * from './aria-helpers/nav-menu.aria'\nexport * from './aria-helpers/tabs.aria'\nexport * from './aria-helpers/trap-focus.aria'\n\n// utils\n\nexport * from './config/defineIcons'\n\n// shared types\n\nexport * from './types'\n\n// 3rd party\n\nexport * from '@dnd-kit/core'\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8EA,cAAc;","names":[]}
1
+ {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["/**\n * This module is the entry point for the Cerberus React package.\n * @module\n */\n\n// components\n\nexport * from './components/Avatar'\nexport * from './components/Button'\nexport * from './components/Checkbox'\nexport * from './components/Droppable'\nexport * from './components/FieldMessage'\nexport * from './components/FeatureFlag'\nexport * from './components/FileStatus'\nexport * from './components/FileUploader'\nexport * from './components/IconButton'\nexport * from './components/Input'\nexport * from './components/Label'\nexport * from './components/Modal'\nexport * from './components/ModalHeader'\nexport * from './components/ModalHeading'\nexport * from './components/ModalDescription'\nexport * from './components/NavMenuTrigger'\nexport * from './components/NavMenuList'\nexport * from './components/NavMenuLink'\nexport * from './components/Notification'\nexport * from './components/NotificationHeading'\nexport * from './components/NotificationDescription'\nexport * from './components/Portal'\nexport * from './components/ProgressBar'\nexport * from './components/Radio'\nexport * from './components/Select'\nexport * from './components/Tab'\nexport * from './components/TabList'\nexport * from './components/TabPanel'\nexport * from './components/Table'\nexport * from './components/Thead'\nexport * from './components/Th'\nexport * from './components/Td'\nexport * from './components/Tbody'\nexport * from './components/Tag'\nexport * from './components/Textarea'\nexport * from './components/Toggle'\nexport * from './components/Show'\n\n// context\n\nexport * from './context/confirm-modal'\nexport * from './context/feature-flags'\nexport * from './context/field'\nexport * from './context/navMenu'\nexport * from './context/notification-center'\nexport * from './context/prompt-modal'\nexport * from './context/tabs'\nexport * from './context/theme'\n\n// hooks\n\nexport * from './hooks/useModal'\nexport * from './hooks/useTheme'\nexport * from './hooks/useToggle'\n\n// aria-helpers\n\nexport * from './aria-helpers/nav-menu.aria'\nexport * from './aria-helpers/tabs.aria'\nexport * from './aria-helpers/trap-focus.aria'\n\n// utils\n\nexport * from './config/defineIcons'\n\n// shared types\n\nexport * from './types'\n\n// 3rd party\n\nexport * from '@dnd-kit/core'\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8EA,cAAc;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cerberus-design/react",
3
- "version": "0.9.2-next-32b3154",
3
+ "version": "0.9.2-next-cf82128",
4
4
  "description": "The Cerberus Design React component library.",
5
5
  "browserslist": "> 0.25%, not dead",
6
6
  "sideEffects": false,
@@ -25,8 +25,8 @@
25
25
  "react": "^18",
26
26
  "react-dom": "^18",
27
27
  "tsup": "^8.1.0",
28
- "@cerberus-design/configs": "0.0.0",
29
- "@cerberus-design/styled-system": "0.9.2-next-32b3154"
28
+ "@cerberus-design/styled-system": "0.9.2-next-cf82128",
29
+ "@cerberus-design/configs": "0.0.0"
30
30
  },
31
31
  "publishConfig": {
32
32
  "access": "public"
@@ -1,26 +1,28 @@
1
1
  'use client'
2
2
 
3
3
  import { createContext, useContext, type PropsWithChildren } from 'react'
4
- import { useTheme } from '../hooks/useTheme'
4
+ import { useTheme, type UseThemeOptions } from '../hooks/useTheme'
5
5
 
6
- export type DefaultThemes = 'cerberus'
6
+ export type DefaultThemes = 'cerberus' | 'acheron'
7
7
  export type CustomThemes<K extends string = DefaultThemes> = 'cerberus' | K
8
- export type ColorModes = 'light' | 'dark'
8
+ export type ColorModes = 'light' | 'dark' | 'system'
9
9
 
10
10
  export interface ThemeContextValue<T extends string = DefaultThemes> {
11
11
  theme: CustomThemes<T>
12
12
  mode: ColorModes
13
13
  updateTheme: (theme: T) => void
14
- updateMode: () => void
14
+ updateMode: (mode: ColorModes) => void
15
15
  }
16
16
 
17
- export const THEME_KEY = 'cerberus-theme'
18
- export const MODE_KEY = 'cerberus-mode'
19
-
20
17
  const ThemeContext = createContext<ThemeContextValue<DefaultThemes> | null>(
21
18
  null,
22
19
  )
23
20
 
21
+ export interface ThemeProviderProps extends UseThemeOptions {
22
+ defaultTheme?: DefaultThemes
23
+ defaultColorMode?: ColorModes
24
+ }
25
+
24
26
  /**
25
27
  * A context provider that allows the user to set the theme and mode of the application.
26
28
  * @example
@@ -30,8 +32,15 @@ const ThemeContext = createContext<ThemeContextValue<DefaultThemes> | null>(
30
32
  * </ThemeProvider>
31
33
  * ```
32
34
  */
33
- export function ThemeProvider(props: PropsWithChildren<unknown>): JSX.Element {
34
- const state = useTheme()
35
+ export function ThemeProvider(
36
+ props: PropsWithChildren<ThemeProviderProps>,
37
+ ): JSX.Element {
38
+ const state = useTheme(props.defaultTheme, props.defaultColorMode, {
39
+ cache: props.cache,
40
+ updateMode: props.updateMode,
41
+ updateTheme: props.updateTheme,
42
+ }) as ThemeContextValue<DefaultThemes>
43
+
35
44
  return (
36
45
  <ThemeContext.Provider value={state}>
37
46
  {props.children}
@@ -8,33 +8,45 @@ import {
8
8
  useState,
9
9
  } from 'react'
10
10
  import {
11
- MODE_KEY,
12
- THEME_KEY,
13
11
  type ColorModes,
14
12
  type CustomThemes,
15
13
  type DefaultThemes,
16
14
  type ThemeContextValue,
17
15
  } from '../context/theme'
18
16
 
17
+ export const THEME_KEY = 'cerberus-theme'
18
+ export const MODE_KEY = 'cerberus-mode'
19
+
20
+ export interface UseThemeOptions<T extends string = DefaultThemes> {
21
+ cache?: boolean
22
+ updateTheme?: (theme: T) => void
23
+ updateMode?: (mode: ColorModes) => void
24
+ }
25
+
19
26
  export function useTheme<C extends string = DefaultThemes>(
20
27
  defaultTheme: CustomThemes<C> = 'cerberus',
21
28
  defaultColorMode: ColorModes = 'light',
29
+ options: UseThemeOptions<C> = {},
22
30
  ): ThemeContextValue<C> {
31
+ const { updateMode, updateTheme, cache } = options
23
32
  const [theme, setTheme] = useState<CustomThemes<C>>(defaultTheme)
24
33
  const [colorMode, setColorMode] = useState<ColorModes>(defaultColorMode)
25
34
 
26
- const handleThemeChange = useCallback((newTheme: CustomThemes<C>) => {
27
- setTheme(newTheme)
28
- localStorage.setItem(THEME_KEY, newTheme)
29
- }, [])
35
+ const handleThemeChange = useCallback(
36
+ (newTheme: C) => {
37
+ setTheme(newTheme)
38
+ updateTheme?.(newTheme)
39
+ },
40
+ [updateTheme],
41
+ )
30
42
 
31
- const handleColorModeChange = useCallback(() => {
32
- setColorMode((prev) => {
33
- const newMode = prev === 'light' ? 'dark' : 'light'
34
- localStorage.setItem(MODE_KEY, newMode)
35
- return newMode
36
- })
37
- }, [])
43
+ const handleColorModeChange = useCallback(
44
+ (newMode: ColorModes) => {
45
+ setColorMode(newMode)
46
+ updateMode?.(newMode)
47
+ },
48
+ [updateMode],
49
+ )
38
50
 
39
51
  useLayoutEffect(() => {
40
52
  const theme = localStorage.getItem(THEME_KEY)
@@ -51,14 +63,20 @@ export function useTheme<C extends string = DefaultThemes>(
51
63
  }, [])
52
64
 
53
65
  useEffect(() => {
54
- const root = document.documentElement
55
- root.dataset.theme = theme
56
- }, [theme])
66
+ if (cache) {
67
+ const root = document.documentElement
68
+ root.dataset.pandaTheme = theme
69
+ localStorage.setItem(THEME_KEY, theme)
70
+ }
71
+ }, [theme, cache])
57
72
 
58
73
  useEffect(() => {
59
- const root = document.documentElement
60
- root.dataset.colorMode = colorMode
61
- }, [colorMode])
74
+ if (cache) {
75
+ const root = document.documentElement
76
+ root.dataset.colorMode = colorMode
77
+ localStorage.setItem(MODE_KEY, colorMode)
78
+ }
79
+ }, [colorMode, cache])
62
80
 
63
81
  return useMemo(
64
82
  () => ({
@@ -1,83 +0,0 @@
1
- // src/hooks/useTheme.ts
2
- import {
3
- useCallback,
4
- useEffect,
5
- useLayoutEffect,
6
- useMemo,
7
- useState
8
- } from "react";
9
-
10
- // src/context/theme.tsx
11
- import { createContext, useContext } from "react";
12
- import { jsx } from "react/jsx-runtime";
13
- var THEME_KEY = "cerberus-theme";
14
- var MODE_KEY = "cerberus-mode";
15
- var ThemeContext = createContext(
16
- null
17
- );
18
- function ThemeProvider(props) {
19
- const state = useTheme();
20
- return /* @__PURE__ */ jsx(ThemeContext.Provider, { value: state, children: props.children });
21
- }
22
- function useThemeContext() {
23
- const context = useContext(ThemeContext);
24
- if (!context) {
25
- throw new Error("useThemeContext must be used within a ThemeProvider");
26
- }
27
- return context;
28
- }
29
-
30
- // src/hooks/useTheme.ts
31
- function useTheme(defaultTheme = "cerberus", defaultColorMode = "light") {
32
- const [theme, setTheme] = useState(defaultTheme);
33
- const [colorMode, setColorMode] = useState(defaultColorMode);
34
- const handleThemeChange = useCallback((newTheme) => {
35
- setTheme(newTheme);
36
- localStorage.setItem(THEME_KEY, newTheme);
37
- }, []);
38
- const handleColorModeChange = useCallback(() => {
39
- setColorMode((prev) => {
40
- const newMode = prev === "light" ? "dark" : "light";
41
- localStorage.setItem(MODE_KEY, newMode);
42
- return newMode;
43
- });
44
- }, []);
45
- useLayoutEffect(() => {
46
- const theme2 = localStorage.getItem(THEME_KEY);
47
- if (theme2) {
48
- setTheme(theme2);
49
- }
50
- }, []);
51
- useLayoutEffect(() => {
52
- const mode = localStorage.getItem(MODE_KEY);
53
- if (mode) {
54
- setColorMode(mode);
55
- }
56
- }, []);
57
- useEffect(() => {
58
- const root = document.documentElement;
59
- root.dataset.theme = theme;
60
- }, [theme]);
61
- useEffect(() => {
62
- const root = document.documentElement;
63
- root.dataset.colorMode = colorMode;
64
- }, [colorMode]);
65
- return useMemo(
66
- () => ({
67
- theme,
68
- mode: colorMode,
69
- updateTheme: handleThemeChange,
70
- updateMode: handleColorModeChange
71
- }),
72
- [theme, colorMode, handleThemeChange, handleColorModeChange]
73
- );
74
- }
75
-
76
- export {
77
- useTheme,
78
- THEME_KEY,
79
- MODE_KEY,
80
- ThemeProvider,
81
- useThemeContext
82
- };
83
- //# sourceMappingURL=chunk-SXXWC6UD.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/hooks/useTheme.ts","../../src/context/theme.tsx"],"sourcesContent":["'use client'\n\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useState,\n} from 'react'\nimport {\n MODE_KEY,\n THEME_KEY,\n type ColorModes,\n type CustomThemes,\n type DefaultThemes,\n type ThemeContextValue,\n} from '../context/theme'\n\nexport function useTheme<C extends string = DefaultThemes>(\n defaultTheme: CustomThemes<C> = 'cerberus',\n defaultColorMode: ColorModes = 'light',\n): ThemeContextValue<C> {\n const [theme, setTheme] = useState<CustomThemes<C>>(defaultTheme)\n const [colorMode, setColorMode] = useState<ColorModes>(defaultColorMode)\n\n const handleThemeChange = useCallback((newTheme: CustomThemes<C>) => {\n setTheme(newTheme)\n localStorage.setItem(THEME_KEY, newTheme)\n }, [])\n\n const handleColorModeChange = useCallback(() => {\n setColorMode((prev) => {\n const newMode = prev === 'light' ? 'dark' : 'light'\n localStorage.setItem(MODE_KEY, newMode)\n return newMode\n })\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.theme = theme\n }, [theme])\n\n useEffect(() => {\n const root = document.documentElement\n root.dataset.colorMode = colorMode\n }, [colorMode])\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","'use client'\n\nimport { createContext, useContext, type PropsWithChildren } from 'react'\nimport { useTheme } from '../hooks/useTheme'\n\nexport type DefaultThemes = 'cerberus'\nexport type CustomThemes<K extends string = DefaultThemes> = 'cerberus' | K\nexport type ColorModes = 'light' | 'dark'\n\nexport interface ThemeContextValue<T extends string = DefaultThemes> {\n theme: CustomThemes<T>\n mode: ColorModes\n updateTheme: (theme: T) => void\n updateMode: () => void\n}\n\nexport const THEME_KEY = 'cerberus-theme'\nexport const MODE_KEY = 'cerberus-mode'\n\nconst ThemeContext = createContext<ThemeContextValue<DefaultThemes> | null>(\n null,\n)\n\n/**\n * A context provider that allows the user to set the theme and mode of the application.\n * @example\n * ```tsx\n * <ThemeProvider>\n * <App />\n * </ThemeProvider>\n * ```\n */\nexport function ThemeProvider(props: PropsWithChildren<unknown>): JSX.Element {\n const state = useTheme()\n return (\n <ThemeContext.Provider value={state}>\n {props.children}\n </ThemeContext.Provider>\n )\n}\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"],"mappings":";AAEA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACNP,SAAS,eAAe,kBAA0C;AAiC9D;AAnBG,IAAM,YAAY;AAClB,IAAM,WAAW;AAExB,IAAM,eAAe;AAAA,EACnB;AACF;AAWO,SAAS,cAAc,OAAgD;AAC5E,QAAM,QAAQ,SAAS;AACvB,SACE,oBAAC,aAAa,UAAb,EAAsB,OAAO,OAC3B,gBAAM,UACT;AAEJ;AAEO,SAAS,kBAAoD;AAClE,QAAM,UAAU,WAAW,YAAY;AACvC,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,qDAAqD;AAAA,EACvE;AACA,SAAO;AACT;;;AD7BO,SAAS,SACd,eAAgC,YAChC,mBAA+B,SACT;AACtB,QAAM,CAAC,OAAO,QAAQ,IAAI,SAA0B,YAAY;AAChE,QAAM,CAAC,WAAW,YAAY,IAAI,SAAqB,gBAAgB;AAEvE,QAAM,oBAAoB,YAAY,CAAC,aAA8B;AACnE,aAAS,QAAQ;AACjB,iBAAa,QAAQ,WAAW,QAAQ;AAAA,EAC1C,GAAG,CAAC,CAAC;AAEL,QAAM,wBAAwB,YAAY,MAAM;AAC9C,iBAAa,CAAC,SAAS;AACrB,YAAM,UAAU,SAAS,UAAU,SAAS;AAC5C,mBAAa,QAAQ,UAAU,OAAO;AACtC,aAAO;AAAA,IACT,CAAC;AAAA,EACH,GAAG,CAAC,CAAC;AAEL,kBAAgB,MAAM;AACpB,UAAMA,SAAQ,aAAa,QAAQ,SAAS;AAC5C,QAAIA,QAAO;AACT,eAASA,MAAwB;AAAA,IACnC;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,kBAAgB,MAAM;AACpB,UAAM,OAAO,aAAa,QAAQ,QAAQ;AAC1C,QAAI,MAAM;AACR,mBAAa,IAAkB;AAAA,IACjC;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,YAAU,MAAM;AACd,UAAM,OAAO,SAAS;AACtB,SAAK,QAAQ,QAAQ;AAAA,EACvB,GAAG,CAAC,KAAK,CAAC;AAEV,YAAU,MAAM;AACd,UAAM,OAAO,SAAS;AACtB,SAAK,QAAQ,YAAY;AAAA,EAC3B,GAAG,CAAC,SAAS,CAAC;AAEd,SAAO;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;","names":["theme"]}