@@ -11,6 +11,8 @@ export interface ThemeSwitcherProps {
11
11
dontSync ?: boolean ;
12
12
/** force apply CSS transition property to all the elements during theme switching. E.g., `all .3s` */
13
13
themeTransition ?: string ;
14
+ /** provide styles object if you are using CSS/SCSS modules. */
15
+ styles ?: Record < string , string > ;
14
16
}
15
17
16
18
function useMediaQuery ( setThemeState : SetStateAction < ThemeState > ) {
@@ -77,13 +79,36 @@ function modifyTransition(themeTransition = "none", targetId?: string) {
77
79
} ;
78
80
}
79
81
82
+ export interface ApplyClassesProps {
83
+ targets : ( HTMLElement | null ) [ ] ;
84
+ theme : string ;
85
+ resolvedColorScheme : "light" | "dark" ;
86
+ styles ?: Record < string , string > ;
87
+ }
88
+
89
+ function applyClasses ( { targets, theme, resolvedColorScheme, styles } : ApplyClassesProps ) {
90
+ let cls = [ "dark" , "light" , theme , resolvedColorScheme ] ;
91
+ if ( styles ) cls = cls . map ( c => styles [ c ] ) ;
92
+
93
+ targets . forEach ( t => {
94
+ t ?. classList . remove ( cls [ 0 ] ) ; // dark
95
+ t ?. classList . remove ( cls [ 1 ] ) ; // light
96
+ t ?. classList . forEach ( cls => {
97
+ if ( cls . match ( / ( ^ | _ ) t h - / ) ) t . classList . remove ( cls ) ;
98
+ } ) ;
99
+ t ?. classList . add ( `th-${ cls [ 2 ] } ` ) ; // theme
100
+ t ?. classList . add ( cls [ 3 ] ) ; // resolvedColorScheme
101
+ } ) ;
102
+ }
103
+
80
104
export interface UpdateDOMProps {
81
105
targetId ?: string ;
82
106
themeState : ThemeState ;
83
107
dontSync ?: boolean ;
108
+ styles ?: Record < string , string > ;
84
109
}
85
110
86
- function updateDOM ( { targetId, themeState, dontSync } : UpdateDOMProps ) {
111
+ function updateDOM ( { targetId, themeState, dontSync, styles } : UpdateDOMProps ) {
87
112
const { theme, colorSchemePreference : csp , systemColorScheme : scs } = themeState ;
88
113
const resolvedColorScheme = csp === "system" ? scs : csp ;
89
114
const key = targetId ?? DEFAULT_ID ;
@@ -95,15 +120,7 @@ function updateDOM({ targetId, themeState, dontSync }: UpdateDOMProps) {
95
120
/** do not update documentElement for local targets */
96
121
const targets = targetId ? [ target ] : [ target , document . documentElement ] ;
97
122
98
- targets . forEach ( t => {
99
- t ?. classList . remove ( "dark" ) ;
100
- t ?. classList . remove ( "light" ) ;
101
- t ?. classList . forEach ( cls => {
102
- if ( cls . startsWith ( "th-" ) ) t . classList . remove ( cls ) ;
103
- } ) ;
104
- t ?. classList . add ( `th-${ theme } ` ) ;
105
- t ?. classList . add ( resolvedColorScheme ) ;
106
- } ) ;
123
+ applyClasses ( { targets, styles, resolvedColorScheme, theme } ) ;
107
124
108
125
if ( shoulCreateCookie ) document . cookie = `${ key } =${ theme } ,${ resolvedColorScheme } ; max-age=31536000; SameSite=Strict;` ;
109
126
}
@@ -112,7 +129,7 @@ function updateDOM({ targetId, themeState, dontSync }: UpdateDOMProps) {
112
129
* The core ThemeSwitcher component wich applies classes and transitions.
113
130
* Cookies are set only if corresponding ServerTarget is detected.
114
131
*/
115
- export function ThemeSwitcher ( { targetId, dontSync, themeTransition } : ThemeSwitcherProps ) {
132
+ export function ThemeSwitcher ( { targetId, dontSync, themeTransition, styles } : ThemeSwitcherProps ) {
116
133
if ( targetId === "" ) throw new Error ( "id can not be an empty string" ) ;
117
134
const [ themeState , setThemeState ] = useRGS < ThemeState > ( targetId ?? DEFAULT_ID , DEFAULT_THEME_STATE ) ;
118
135
@@ -123,7 +140,7 @@ export function ThemeSwitcher({ targetId, dontSync, themeTransition }: ThemeSwit
123
140
/** update DOM and storage */
124
141
React . useEffect ( ( ) => {
125
142
const restoreTransitions = modifyTransition ( themeTransition , targetId ) ;
126
- updateDOM ( { targetId, themeState, dontSync } ) ;
143
+ updateDOM ( { targetId, themeState, dontSync, styles } ) ;
127
144
if ( ! dontSync && tInit < Date . now ( ) - 300 ) {
128
145
// save to localStorage
129
146
const { theme, colorSchemePreference } = themeState ;
0 commit comments