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" ;
63import { useConstCallback } from "./tools/powerhooks/useConstCallback" ;
74import { assert } from "tsafe/assert" ;
85import { isBrowser } from "./tools/isBrowser" ;
@@ -12,65 +9,82 @@ export type ColorScheme = "light" | "dark";
129export const data_fr_theme = "data-fr-theme" ;
1310export const data_fr_scheme = "data-fr-scheme" ;
1411
15- export const $colorScheme = createStatefulObservable < ColorScheme > ( ( ) => "light" ) ;
12+ //export const $colorScheme = createStatefulObservable<ColorScheme>(() => "light");
13+ export const $isDark = createStatefulObservable ( ( ) => false ) ;
1614
17- type UseColorScheme = ( ) => {
18- colorScheme : ColorScheme ;
19- setColorScheme : ( colorSchemeOrSystem : ColorScheme | "system" ) => void ;
15+ type UseIsDark = ( ) => {
16+ isDark : boolean ;
17+ setIsDark : ( isDark : boolean | "system" ) => void ;
2018} ;
2119
22- const useColorSchemeClientSide : UseColorScheme = ( ) => {
23- useRerenderOnChange ( $colorScheme ) ;
20+ const useIsDarkClientSide : UseIsDark = ( ) => {
21+ useRerenderOnChange ( $isDark ) ;
2422
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+ )
2737 ) ;
2838
29- return { "colorScheme " : $colorScheme . current , setColorScheme } ;
39+ return { "isDark " : $isDark . current , setIsDark } ;
3040} ;
3141
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 ( ( ) => {
3446 /* nothing */
3547 } ) ;
3648
49+ const isDark = useContext ( isDarkContext ) ;
50+
51+ assert ( isDark !== undefined , "color scheme context should be provided" ) ;
52+
3753 return {
38- "colorScheme" : $colorScheme . current ,
39- setColorScheme
54+ isDark ,
55+ setIsDark
4056 } ;
4157} ;
4258
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 ;
4960
61+ function getCurrentIsDarkFromHtmlAttribute ( ) : boolean {
5062 const colorSchemeReadFromDom = document . documentElement . getAttribute ( data_fr_theme ) ;
5163
5264 switch ( colorSchemeReadFromDom ) {
5365 case null :
54- return "light" ;
5566 case "light" :
67+ return false ;
5668 case "dark" :
57- return colorSchemeReadFromDom ;
69+ return true ;
5870 }
5971
6072 assert ( false ) ;
6173}
6274
6375export function startObservingColorSchemeHtmlAttribute ( ) {
64- $colorScheme . current = getCurrentColorSchemeFromHtmlAttribute ( ) ;
76+ $isDark . current = getCurrentIsDarkFromHtmlAttribute ( ) ;
6577
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+ ) ;
7285
7386 {
87+ /*
7488 const setColorSchemeCookie = (colorScheme: ColorScheme) => {
7589 let newCookie = `${data_fr_theme}=${colorScheme};path=/;max-age=31536000`;
7690
@@ -87,17 +101,39 @@ export function startObservingColorSchemeHtmlAttribute() {
87101
88102 document.cookie = newCookie;
89103 };
104+ */
90105
91- setColorSchemeCookie ( $colorScheme . current ) ;
106+ const setColorSchemeCookie = ( isDark : boolean ) => {
107+ const colorScheme : ColorScheme = isDark ? "dark" : "light" ;
92108
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 ) ;
94128 }
95129
96130 //TODO: <meta name="theme-color" content="#000091"><!-- Défini la couleur de thème du navigateur (Safari/Android) -->
97131
98132 //TODO: Remove once https://github.com/GouvernementFR/dsfr/issues/407 is dealt with
99133 {
100- const setRootColorScheme = ( colorScheme : ColorScheme ) => {
134+ const setRootColorScheme = ( isDark : boolean ) => {
135+ const colorScheme : ColorScheme = isDark ? "dark" : "light" ;
136+
101137 const id = "root-color-scheme" ;
102138
103139 remove_existing_element: {
@@ -119,45 +155,8 @@ export function startObservingColorSchemeHtmlAttribute() {
119155 document . getElementsByTagName ( "head" ) [ 0 ] . appendChild ( element ) ;
120156 } ;
121157
122- setRootColorScheme ( $colorScheme . current ) ;
158+ setRootColorScheme ( $isDark . current ) ;
123159
124- $colorScheme . subscribe ( setRootColorScheme ) ;
160+ $isDark . subscribe ( setRootColorScheme ) ;
125161 }
126162}
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