@codegouvfr/react-dsfr
Version:
French State Design System React integration library
165 lines • 7.5 kB
JavaScript
import { assert } from "tsafe/assert";
import { createStatefulObservable, useRerenderOnChange } from "../tools/StatefulObservable";
import { useConstCallback } from "../tools/powerhooks/useConstCallback";
import { getColors } from "../fr/colors";
import { data_fr_scheme, data_fr_theme, rootColorSchemeStyleTagId } from "./constants";
const $clientSideIsDark = createStatefulObservable(() => {
throw new Error("not initialized yet");
});
const $isAfterFirstEffect = createStatefulObservable(() => false);
export const useIsDarkClientSide = () => {
useRerenderOnChange($clientSideIsDark);
useRerenderOnChange($isAfterFirstEffect);
const isDark = $isAfterFirstEffect.current
? $clientSideIsDark.current
: ssrWasPerformedWithIsDark;
const setIsDark = useConstCallback(newIsDarkOrDeduceNewIsDarkFromCurrentIsDark => {
const data_fr_js_value = document.documentElement.getAttribute("data-fr-js");
const newColorScheme = (() => {
switch (typeof newIsDarkOrDeduceNewIsDarkFromCurrentIsDark === "function"
? newIsDarkOrDeduceNewIsDarkFromCurrentIsDark(isDark)
: newIsDarkOrDeduceNewIsDarkFromCurrentIsDark) {
case "system":
return typeof window.matchMedia === "function" &&
window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
case true:
return "dark";
case false:
return "light";
}
})();
document.documentElement.setAttribute(data_fr_scheme, newColorScheme);
if (data_fr_js_value !== "true") {
//NOTE: DSFR not started yet.
document.documentElement.setAttribute(data_fr_theme, newColorScheme);
localStorage.setItem("scheme", newColorScheme);
}
});
return {
isDark,
setIsDark
};
};
let ssrWasPerformedWithIsDark;
function getCurrentIsDarkFromHtmlAttribute() {
const colorSchemeFromHtmlAttribute = document.documentElement.getAttribute(data_fr_theme);
switch (colorSchemeFromHtmlAttribute) {
case null:
return undefined;
case "light":
return false;
case "dark":
return true;
}
assert(false);
}
export function startClientSideIsDarkLogic(params) {
const { doPersistDarkModePreferenceWithCookie, registerEffectAction, colorSchemeExplicitlyProvidedAsParameter } = params;
const { clientSideIsDark, ssrWasPerformedWithIsDark: ssrWasPerformedWithIsDark_ } = (() => {
var _a, _b, _c;
const isDarkFromHtmlAttribute = getCurrentIsDarkFromHtmlAttribute();
if (isDarkFromHtmlAttribute !== undefined) {
return {
"clientSideIsDark": isDarkFromHtmlAttribute,
"ssrWasPerformedWithIsDark": (_a = window.ssrWasPerformedWithIsDark) !== null && _a !== void 0 ? _a : isDarkFromHtmlAttribute
};
}
const isDarkExplicitlyProvidedAsParameter = (() => {
if (colorSchemeExplicitlyProvidedAsParameter === "system") {
return undefined;
}
switch (colorSchemeExplicitlyProvidedAsParameter) {
case "dark":
return true;
case "light":
return false;
}
})();
const isDarkFromLocalStorage = (() => {
const colorSchemeReadFromLocalStorage = localStorage.getItem("scheme");
if (colorSchemeReadFromLocalStorage === null) {
return undefined;
}
if (colorSchemeReadFromLocalStorage === "system") {
return undefined;
}
switch (colorSchemeReadFromLocalStorage) {
case "dark":
return true;
case "light":
return false;
}
})();
const isDarkFromOsPreference = (() => {
if (!window.matchMedia) {
return undefined;
}
return window.matchMedia("(prefers-color-scheme: dark)").matches;
})();
const isDarkFallback = false;
return {
"ssrWasPerformedWithIsDark": isDarkExplicitlyProvidedAsParameter !== null && isDarkExplicitlyProvidedAsParameter !== void 0 ? isDarkExplicitlyProvidedAsParameter : isDarkFallback,
"clientSideIsDark": (_c = (_b = isDarkFromLocalStorage !== null && isDarkFromLocalStorage !== void 0 ? isDarkFromLocalStorage : isDarkExplicitlyProvidedAsParameter) !== null && _b !== void 0 ? _b : isDarkFromOsPreference) !== null && _c !== void 0 ? _c : isDarkFallback
};
})();
ssrWasPerformedWithIsDark = ssrWasPerformedWithIsDark_;
$clientSideIsDark.current = clientSideIsDark;
[data_fr_scheme, data_fr_theme].forEach(attr => document.documentElement.setAttribute(attr, clientSideIsDark ? "dark" : "light"));
new MutationObserver(() => {
const isDarkFromHtmlAttribute = getCurrentIsDarkFromHtmlAttribute();
assert(isDarkFromHtmlAttribute !== undefined);
$clientSideIsDark.current = isDarkFromHtmlAttribute;
}).observe(document.documentElement, {
"attributes": true,
"attributeFilter": [data_fr_theme]
});
{
const setColorSchemeCookie = (isDark) => {
if (!doPersistDarkModePreferenceWithCookie) {
return;
}
const colorScheme = isDark ? "dark" : "light";
let newCookie = `${data_fr_theme}=${colorScheme};path=/;max-age=31536000;SameSite=Strict`;
set_domain: {
const { hostname } = window.location;
//We do not set the domain if we are on localhost or an ip
if (/(^localhost$)|(^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$)/.test(hostname)) {
break set_domain;
}
newCookie += `;domain=${hostname}`;
}
document.cookie = newCookie;
};
setColorSchemeCookie($clientSideIsDark.current);
$clientSideIsDark.subscribe(setColorSchemeCookie);
}
{
const setRootColorScheme = (isDark) => {
var _a;
(_a = document.getElementById(rootColorSchemeStyleTagId)) === null || _a === void 0 ? void 0 : _a.remove();
const element = document.createElement("style");
element.id = rootColorSchemeStyleTagId;
element.innerHTML = `:root { color-scheme: ${isDark ? "dark" : "light"}; }`;
document.head.appendChild(element);
};
setRootColorScheme($clientSideIsDark.current);
$clientSideIsDark.subscribe(setRootColorScheme);
}
{
const setThemeColor = (isDark) => {
var _a;
const name = "theme-color";
(_a = document.querySelector(`meta[name=${name}]`)) === null || _a === void 0 ? void 0 : _a.remove();
const element = document.createElement("meta");
element.name = name;
element.content = getColors(isDark).decisions.background.default.grey.default;
document.head.appendChild(element);
};
setThemeColor($clientSideIsDark.current);
$clientSideIsDark.subscribe(setThemeColor);
}
registerEffectAction(() => ($isAfterFirstEffect.current = true));
}
//# sourceMappingURL=client.js.map