1
- import {
2
- createStatefulObservable ,
3
- useRerenderOnChange ,
4
- statefulObservableBidirectionalMap
5
- } from "./tools/StatefulObservable" ;
1
+ import { createStatefulObservable , useRerenderOnChange } from "./tools/StatefulObservable" ;
2
+ import { createContext , useContext } from "react" ;
6
3
import { useConstCallback } from "./tools/powerhooks/useConstCallback" ;
7
4
import { assert } from "tsafe/assert" ;
8
5
import { isBrowser } from "./tools/isBrowser" ;
@@ -12,65 +9,82 @@ export type ColorScheme = "light" | "dark";
12
9
export const data_fr_theme = "data-fr-theme" ;
13
10
export const data_fr_scheme = "data-fr-scheme" ;
14
11
15
- export const $colorScheme = createStatefulObservable < ColorScheme > ( ( ) => "light" ) ;
12
+ //export const $colorScheme = createStatefulObservable<ColorScheme>(() => "light");
13
+ export const $isDark = createStatefulObservable ( ( ) => false ) ;
16
14
17
- type UseColorScheme = ( ) => {
18
- colorScheme : ColorScheme ;
19
- setColorScheme : ( colorSchemeOrSystem : ColorScheme | "system" ) => void ;
15
+ type UseIsDark = ( ) => {
16
+ isDark : boolean ;
17
+ setIsDark : ( isDark : boolean | "system" ) => void ;
20
18
} ;
21
19
22
- const useColorSchemeClientSide : UseColorScheme = ( ) => {
23
- useRerenderOnChange ( $colorScheme ) ;
20
+ const useIsDarkClientSide : UseIsDark = ( ) => {
21
+ useRerenderOnChange ( $isDark ) ;
24
22
25
- const setColorScheme = useConstCallback ( ( colorSchemeOrSystem : ColorScheme | "system" ) =>
26
- document . documentElement . setAttribute ( data_fr_scheme , colorSchemeOrSystem )
23
+ const setIsDark = useConstCallback ( ( isDark : boolean | "system" ) =>
24
+ document . documentElement . setAttribute (
25
+ data_fr_scheme ,
26
+ ( ( ) : ColorScheme | "system" => {
27
+ switch ( isDark ) {
28
+ case "system" :
29
+ return "system" ;
30
+ case true :
31
+ return "dark" ;
32
+ case false :
33
+ return "light" ;
34
+ }
35
+ } ) ( )
36
+ )
27
37
) ;
28
38
29
- return { "colorScheme " : $colorScheme . current , setColorScheme } ;
39
+ return { "isDark " : $isDark . current , setIsDark } ;
30
40
} ;
31
41
32
- const useColorSchemeServerSide : UseColorScheme = ( ) => {
33
- const setColorScheme = useConstCallback ( ( ) => {
42
+ export const isDarkContext = createContext < boolean | undefined > ( undefined ) ;
43
+
44
+ const useIsDarkServerSide : UseIsDark = ( ) => {
45
+ const setIsDark = useConstCallback ( ( ) => {
34
46
/* nothing */
35
47
} ) ;
36
48
49
+ const isDark = useContext ( isDarkContext ) ;
50
+
51
+ assert ( isDark !== undefined , "color scheme context should be provided" ) ;
52
+
37
53
return {
38
- "colorScheme" : $colorScheme . current ,
39
- setColorScheme
54
+ isDark ,
55
+ setIsDark
40
56
} ;
41
57
} ;
42
58
43
- export const useColorScheme = isBrowser ? useColorSchemeClientSide : useColorSchemeServerSide ;
44
-
45
- function getCurrentColorSchemeFromHtmlAttribute ( ) : ColorScheme {
46
- if ( ! isBrowser ) {
47
- return "light" ;
48
- }
59
+ export const useIsDark = isBrowser ? useIsDarkClientSide : useIsDarkServerSide ;
49
60
61
+ function getCurrentIsDarkFromHtmlAttribute ( ) : boolean {
50
62
const colorSchemeReadFromDom = document . documentElement . getAttribute ( data_fr_theme ) ;
51
63
52
64
switch ( colorSchemeReadFromDom ) {
53
65
case null :
54
- return "light" ;
55
66
case "light" :
67
+ return false ;
56
68
case "dark" :
57
- return colorSchemeReadFromDom ;
69
+ return true ;
58
70
}
59
71
60
72
assert ( false ) ;
61
73
}
62
74
63
75
export function startObservingColorSchemeHtmlAttribute ( ) {
64
- $colorScheme . current = getCurrentColorSchemeFromHtmlAttribute ( ) ;
76
+ $isDark . current = getCurrentIsDarkFromHtmlAttribute ( ) ;
65
77
66
- new MutationObserver (
67
- ( ) => ( $colorScheme . current = getCurrentColorSchemeFromHtmlAttribute ( ) )
68
- ) . observe ( document . documentElement , {
69
- "attributes" : true ,
70
- "attributeFilter" : [ data_fr_theme ]
71
- } ) ;
78
+ new MutationObserver ( ( ) => ( $isDark . current = getCurrentIsDarkFromHtmlAttribute ( ) ) ) . observe (
79
+ document . documentElement ,
80
+ {
81
+ "attributes" : true ,
82
+ "attributeFilter" : [ data_fr_theme ]
83
+ }
84
+ ) ;
72
85
73
86
{
87
+ /*
74
88
const setColorSchemeCookie = (colorScheme: ColorScheme) => {
75
89
let newCookie = `${data_fr_theme}=${colorScheme};path=/;max-age=31536000`;
76
90
@@ -87,17 +101,39 @@ export function startObservingColorSchemeHtmlAttribute() {
87
101
88
102
document.cookie = newCookie;
89
103
};
104
+ */
90
105
91
- setColorSchemeCookie ( $colorScheme . current ) ;
106
+ const setColorSchemeCookie = ( isDark : boolean ) => {
107
+ const colorScheme : ColorScheme = isDark ? "dark" : "light" ;
92
108
93
- $colorScheme . subscribe ( setColorSchemeCookie ) ;
109
+ let newCookie = `${ data_fr_theme } =${ colorScheme } ;path=/;max-age=31536000` ;
110
+
111
+ set_domain: {
112
+ const { hostname } = window . location ;
113
+
114
+ //We do not set the domain if we are on localhost or an ip
115
+ if ( / ( ^ l o c a l h o s t $ ) | ( ^ ( ( 2 5 [ 0 - 5 ] | ( 2 [ 0 - 4 ] | 1 \d | [ 1 - 9 ] | ) \d ) \. ? \b ) { 4 } $ ) / . test ( hostname ) ) {
116
+ break set_domain;
117
+ }
118
+
119
+ newCookie += `;domain=${ hostname } ` ;
120
+ }
121
+
122
+ document . cookie = newCookie ;
123
+ } ;
124
+
125
+ setColorSchemeCookie ( $isDark . current ) ;
126
+
127
+ $isDark . subscribe ( setColorSchemeCookie ) ;
94
128
}
95
129
96
130
//TODO: <meta name="theme-color" content="#000091"><!-- Défini la couleur de thème du navigateur (Safari/Android) -->
97
131
98
132
//TODO: Remove once https://github.com/GouvernementFR/dsfr/issues/407 is dealt with
99
133
{
100
- const setRootColorScheme = ( colorScheme : ColorScheme ) => {
134
+ const setRootColorScheme = ( isDark : boolean ) => {
135
+ const colorScheme : ColorScheme = isDark ? "dark" : "light" ;
136
+
101
137
const id = "root-color-scheme" ;
102
138
103
139
remove_existing_element: {
@@ -119,45 +155,8 @@ export function startObservingColorSchemeHtmlAttribute() {
119
155
document . getElementsByTagName ( "head" ) [ 0 ] . appendChild ( element ) ;
120
156
} ;
121
157
122
- setRootColorScheme ( $colorScheme . current ) ;
158
+ setRootColorScheme ( $isDark . current ) ;
123
159
124
- $colorScheme . subscribe ( setRootColorScheme ) ;
160
+ $isDark . subscribe ( setRootColorScheme ) ;
125
161
}
126
162
}
127
-
128
- //NOTE: Just because it's more convenient to have a boolean than "light" | "dark"
129
-
130
- export const $isDark = statefulObservableBidirectionalMap ( {
131
- "statefulObservable" : $colorScheme ,
132
- "trInToOut" : colorScheme => {
133
- switch ( colorScheme ) {
134
- case "light" :
135
- return false ;
136
- case "dark" :
137
- return true ;
138
- }
139
- } ,
140
- "trOutToIn" : isDark => ( isDark ? "dark" : "light" )
141
- } ) ;
142
-
143
- export function useIsDark ( ) {
144
- const { colorScheme, setColorScheme } = useColorScheme ( ) ;
145
-
146
- const setIsDark = useConstCallback ( ( isDark : boolean | "system" ) =>
147
- setColorScheme ( typeof isDark !== "boolean" ? isDark : isDark ? "dark" : "light" )
148
- ) ;
149
-
150
- const isDark = ( ( ) => {
151
- switch ( colorScheme ) {
152
- case "dark" :
153
- return true ;
154
- case "light" :
155
- return false ;
156
- }
157
- } ) ( ) ;
158
-
159
- return {
160
- isDark,
161
- setIsDark
162
- } ;
163
- }
0 commit comments