@@ -23,15 +23,77 @@ function useSystemDark() {
23
23
return useSyncExternalStore ( subscribe , getSnapshot , getServerSnapshot )
24
24
}
25
25
26
+ /**
27
+ * credit: https://github.com/pacocoursey/next-themes/blob/cd67bfa20ef6ea78a814d65625c530baae4075ef/packages/next-themes/src/index.tsx#L285
28
+ */
29
+ function disableAnimation ( disableTransitionExclude : string [ ] = [ ] ) {
30
+ const css = document . createElement ( 'style' )
31
+ css . append (
32
+ document . createTextNode (
33
+ `
34
+ *${ disableTransitionExclude . map ( s => `:not(${ s } )` ) . join ( '' ) } {
35
+ -webkit-transition: none !important;
36
+ -moz-transition: none !important;
37
+ -o-transition: none !important;
38
+ -ms-transition: none !important;
39
+ transition: none !important;
40
+ }
41
+ ` ,
42
+ ) ,
43
+ )
44
+ document . head . append ( css )
45
+
46
+ return ( ) => {
47
+ // Force restyle
48
+ ; ( ( ) => window . getComputedStyle ( document . body ) ) ( )
49
+
50
+ // Wait for next tick before removing
51
+ setTimeout ( ( ) => {
52
+ css . remove ( )
53
+ } , 1 )
54
+ }
55
+ }
56
+
57
+ export type Options = {
58
+ /**
59
+ * @default "use-dark"
60
+ */
61
+ storageKey ?: string
62
+
63
+ /**
64
+ * @default false
65
+ */
66
+ disableTransition ?: boolean
67
+
68
+ /**
69
+ * @default []
70
+ */
71
+ disableTransitionExclude ?: string [ ]
72
+
73
+ /**
74
+ * @default isDark => document.documentElement.classList.toggle("dark", isDark)
75
+ */
76
+ applyDarkMode ?: ( isDark : boolean ) => void
77
+ }
78
+
26
79
const themeOptions = [ 'system' , 'light' , 'dark' ] as const
27
- export type Theme = ( typeof themeOptions ) [ number ]
80
+ type Theme = ( typeof themeOptions ) [ number ]
28
81
29
- function isDarkMode ( setting ?: Theme | null , isSystemDark ?: boolean ) {
30
- return setting === 'dark' || ( isSystemDark && setting !== 'light' )
82
+ function isDarkMode ( setting ?: Theme | null , isSystemDark ?: boolean | null ) {
83
+ return setting === 'dark' || ( ! ! isSystemDark && setting !== 'light' )
31
84
}
32
85
33
- export function useDark ( themeKey = 'use-dark' ) {
34
- const [ theme , setTheme ] = useLocalStorage < Theme > ( themeKey , 'system' )
86
+ export function useDark ( options ?: Options ) {
87
+ const {
88
+ storageKey = 'use-dark' ,
89
+ disableTransition = false ,
90
+ disableTransitionExclude = [ ] ,
91
+ applyDarkMode = ( isDark : boolean ) => {
92
+ document . documentElement . classList . toggle ( 'dark' , isDark )
93
+ } ,
94
+ } = options ?? { }
95
+
96
+ const [ theme , setTheme ] = useLocalStorage < Theme > ( storageKey , 'system' )
35
97
const isSystemDark = useSystemDark ( )
36
98
37
99
const isDark = useMemo (
@@ -40,18 +102,21 @@ export function useDark(themeKey = 'use-dark') {
40
102
)
41
103
42
104
const toggleDark = ( ) => {
105
+ const enable = disableTransition
106
+ ? disableAnimation ( disableTransitionExclude )
107
+ : null
108
+
43
109
if ( theme === 'system' )
44
110
setTheme ( isSystemDark ? 'light' : 'dark' )
45
111
else
46
112
setTheme ( 'system' )
113
+
114
+ enable ?.( )
47
115
}
48
116
49
117
useEffect ( ( ) => {
50
118
const isDark = isDarkMode ( theme , isSystemDark )
51
- if ( isDark )
52
- document . documentElement . classList . toggle ( 'dark' , true )
53
- else
54
- document . documentElement . classList . toggle ( 'dark' , false )
119
+ applyDarkMode ( isDark )
55
120
56
121
if (
57
122
( theme === 'dark' && isSystemDark )
0 commit comments