2023-03-17 20:40:29 +01:00
|
|
|
import { useReducer, useEffect } from "react";
|
2023-03-19 23:12:45 +01:00
|
|
|
import { clsx } from "keycloakify/tools/clsx";
|
2024-04-10 01:22:49 +02:00
|
|
|
import { assert } from "tsafe/assert";
|
2024-05-09 18:04:31 +02:00
|
|
|
import { useInsertScriptTags, type ScriptTag } from "keycloakify/tools/useInsertScriptTags";
|
2023-03-17 20:40:29 +01:00
|
|
|
|
|
|
|
export function usePrepareTemplate(params: {
|
2024-05-09 18:04:31 +02:00
|
|
|
styleSheetHrefs: string[];
|
|
|
|
scriptTags: ScriptTag[];
|
2023-03-20 05:14:25 +01:00
|
|
|
htmlClassName: string | undefined;
|
|
|
|
bodyClassName: string | undefined;
|
2024-04-13 01:26:41 +02:00
|
|
|
htmlLangProperty: string | undefined;
|
|
|
|
documentTitle: string | undefined;
|
2023-03-17 20:40:29 +01:00
|
|
|
}) {
|
2024-05-09 18:04:31 +02:00
|
|
|
const { styleSheetHrefs, scriptTags, htmlClassName, bodyClassName, htmlLangProperty, documentTitle } = params;
|
2023-03-17 20:40:29 +01:00
|
|
|
|
2024-04-10 01:22:49 +02:00
|
|
|
useEffect(() => {
|
|
|
|
if (htmlLangProperty === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const html = document.querySelector("html");
|
|
|
|
assert(html !== null);
|
|
|
|
html.lang = htmlLangProperty;
|
|
|
|
}, [htmlLangProperty]);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (documentTitle === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
document.title = documentTitle;
|
|
|
|
}, [documentTitle]);
|
|
|
|
|
2024-05-09 18:04:31 +02:00
|
|
|
const { areAllStyleSheetsLoaded } = useInsertLinkTags({ "hrefs": styleSheetHrefs });
|
2024-05-07 20:04:27 +02:00
|
|
|
|
2024-05-09 18:04:31 +02:00
|
|
|
// NOTE: We want to load the script after the page have been fully rendered.
|
|
|
|
useInsertScriptTags({ "scriptTags": !areAllStyleSheetsLoaded ? [] : scriptTags });
|
2023-03-17 20:40:29 +01:00
|
|
|
|
2023-03-20 05:14:25 +01:00
|
|
|
useSetClassName({
|
|
|
|
"target": "html",
|
|
|
|
"className": htmlClassName
|
|
|
|
});
|
|
|
|
|
|
|
|
useSetClassName({
|
|
|
|
"target": "body",
|
|
|
|
"className": bodyClassName
|
|
|
|
});
|
|
|
|
|
2024-05-09 18:04:31 +02:00
|
|
|
return { areAllStyleSheetsLoaded };
|
2023-03-20 05:14:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function useSetClassName(params: { target: "html" | "body"; className: string | undefined }) {
|
|
|
|
const { target, className } = params;
|
|
|
|
|
2023-03-17 20:40:29 +01:00
|
|
|
useEffect(() => {
|
2023-03-20 05:14:25 +01:00
|
|
|
if (className === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-03-21 03:01:49 +01:00
|
|
|
const htmlClassList = document.getElementsByTagName(target)[0].classList;
|
2023-03-17 20:40:29 +01:00
|
|
|
|
2023-03-21 03:01:49 +01:00
|
|
|
const tokens = clsx(className).split(" ");
|
2023-03-17 20:40:29 +01:00
|
|
|
|
|
|
|
htmlClassList.add(...tokens);
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
htmlClassList.remove(...tokens);
|
|
|
|
};
|
2023-03-20 05:14:25 +01:00
|
|
|
}, [className]);
|
2023-03-17 20:40:29 +01:00
|
|
|
}
|
2024-05-09 18:04:31 +02:00
|
|
|
|
|
|
|
const hrefByPrLoaded = new Map<string, Promise<void>>();
|
|
|
|
|
|
|
|
/** NOTE: The hrefs can't changes. There should be only one one call on this. */
|
|
|
|
function useInsertLinkTags(params: { hrefs: string[] }) {
|
|
|
|
const { hrefs } = params;
|
|
|
|
|
|
|
|
const [areAllStyleSheetsLoaded, setAllStyleSheetLoaded] = useReducer(() => true, hrefs.length === 0);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
let isActive = true;
|
|
|
|
|
|
|
|
let lastMountedHtmlElement: HTMLLinkElement | undefined = undefined;
|
|
|
|
|
|
|
|
for (const href of hrefs) {
|
|
|
|
if (hrefByPrLoaded.has(href)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const htmlElement = document.createElement("link");
|
|
|
|
|
|
|
|
hrefByPrLoaded.set(href, new Promise<void>(resolve => htmlElement.addEventListener("load", () => resolve())));
|
|
|
|
|
|
|
|
htmlElement.rel = "stylesheet";
|
|
|
|
|
|
|
|
htmlElement.href = href;
|
|
|
|
|
|
|
|
if (lastMountedHtmlElement !== undefined) {
|
|
|
|
lastMountedHtmlElement.insertAdjacentElement("afterend", htmlElement);
|
|
|
|
} else {
|
|
|
|
document.head.prepend(htmlElement);
|
|
|
|
}
|
|
|
|
|
|
|
|
lastMountedHtmlElement = htmlElement;
|
|
|
|
}
|
|
|
|
|
|
|
|
Promise.all(Array.from(hrefByPrLoaded.values())).then(() => {
|
|
|
|
if (!isActive) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
setAllStyleSheetLoaded();
|
|
|
|
});
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
isActive = false;
|
|
|
|
};
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
return { areAllStyleSheetsLoaded };
|
|
|
|
}
|