Address white falshes in storybook

This commit is contained in:
Joseph Garrone 2024-06-05 01:02:17 +02:00
parent 183826ca0d
commit 0b5a7544ca
5 changed files with 93 additions and 100 deletions

View File

@ -34,7 +34,6 @@ export function DocsContainer({ children, context }) {
.docblock-argstable-head th:nth-child(3), .docblock-argstable-body tr > td:nth-child(2) p { .docblock-argstable-head th:nth-child(3), .docblock-argstable-body tr > td:nth-child(2) p {
font-size: 13px; font-size: 13px;
} }
`}</style> `}</style>
<BaseContainer <BaseContainer
context={{ context={{
@ -62,20 +61,8 @@ export function DocsContainer({ children, context }) {
export function CanvasContainer({ children }) { export function CanvasContainer({ children }) {
const isStorybookUiDark = useDarkMode();
const theme = isStorybookUiDark ? darkTheme : lightTheme;
const backgroundColor = theme.appBg;
return ( return (
<> <>
<style>{`
body {
padding: 0 !important;
background-color: ${backgroundColor};
}
`}</style>
{children} {children}
</> </>
); );

View File

@ -0,0 +1,15 @@
<style>
body {
padding: 0 !important;
background-color: #393939 !important;
}
body.sb-show-preparing-docs>.sb-wrapper {
visibility: hidden;
}
body .sb-preparing-story {
visibility: hidden;
}
</style>

View File

@ -1,86 +1,68 @@
import { useReducer, useEffect } from "react"; import { useEffect, useState } from "react";
import {
createStatefulObservable,
useRerenderOnChange
} from "keycloakify/tools/StatefulObservable";
/**
* NOTE: The component that use this hook can only be mounded once!
* And can't rerender with different hrefs.
* If it's mounted again the page will be reloaded.
* This simulates the behavior of a server rendered page that imports css stylesheet in the head.
*/
export function createUseInsertLinkTags() { export function createUseInsertLinkTags() {
let linkTagsContext: let isFistMount = true;
| {
styleSheetHrefs: string[]; const obsAreAllStyleSheetsLoaded = createStatefulObservable(() => false);
prAreAllStyleSheetsLoaded: Promise<void>;
remove: () => void;
}
| undefined = undefined;
/** NOTE: The hrefs can't changes. There should be only one one call on this. */
function useInsertLinkTags(params: { hrefs: string[] }) { function useInsertLinkTags(params: { hrefs: string[] }) {
const { hrefs } = params; const { hrefs } = params;
const [areAllStyleSheetsLoaded, setAllStyleSheetLoaded] = useReducer( useRerenderOnChange(obsAreAllStyleSheetsLoaded);
() => true,
hrefs.length === 0 useState(() => {
); if (!isFistMount) {
window.location.reload();
return;
}
isFistMount = false;
});
useEffect(() => { useEffect(() => {
let isActive = true; let isActive = true;
mount_link_tags: { let lastMountedHtmlElement: HTMLLinkElement | undefined = undefined;
if (linkTagsContext !== undefined) {
if (
JSON.stringify(linkTagsContext.styleSheetHrefs) ===
JSON.stringify(hrefs)
) {
break mount_link_tags;
}
linkTagsContext.remove(); const prs: Promise<void>[] = [];
linkTagsContext = undefined; for (const href of hrefs) {
const htmlElement = document.createElement("link");
prs.push(
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);
} }
let lastMountedHtmlElement: HTMLLinkElement | undefined = undefined; lastMountedHtmlElement = htmlElement;
const prs: Promise<void>[] = [];
const removeFns: (() => void)[] = [];
for (const href of hrefs) {
const htmlElement = document.createElement("link");
prs.push(
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);
}
removeFns.push(() => {
htmlElement.remove();
});
lastMountedHtmlElement = htmlElement;
}
linkTagsContext = {
styleSheetHrefs: hrefs,
prAreAllStyleSheetsLoaded: Promise.all(prs).then(() => undefined),
remove: () => removeFns.forEach(fn => fn())
};
} }
linkTagsContext.prAreAllStyleSheetsLoaded.then(() => { Promise.all(prs).then(() => {
if (!isActive) { if (!isActive) {
return; return;
} }
setAllStyleSheetLoaded(); obsAreAllStyleSheetsLoaded.current = true;
}); });
return () => { return () => {
@ -88,7 +70,7 @@ export function createUseInsertLinkTags() {
}; };
}, []); }, []);
return { areAllStyleSheetsLoaded }; return { areAllStyleSheetsLoaded: obsAreAllStyleSheetsLoaded.current };
} }
return { useInsertLinkTags }; return { useInsertLinkTags };

View File

@ -1,4 +1,4 @@
import { useCallback } from "react"; import { useCallback, useState } from "react";
import { assert } from "tsafe/assert"; import { assert } from "tsafe/assert";
export type ScriptTag = ScriptTag.TextContent | ScriptTag.Src; export type ScriptTag = ScriptTag.TextContent | ScriptTag.Src;
@ -16,20 +16,28 @@ export namespace ScriptTag {
}; };
} }
/**
* NOTE: The component that use this hook can only be mounded once!
* And can'r rerender with different scriptTags.
* If it's mounted again the page will be reloaded.
* This simulates the behavior of a server rendered page that imports javascript in the head.
*/
export function createUseInsertScriptTags() { export function createUseInsertScriptTags() {
let areScriptsInserted = false; let areScriptsInserted = false;
let scriptTagsFingerprint: string | undefined; let isFistMount = true;
function useInsertScriptTags(params: { scriptTags: ScriptTag[] }) { function useInsertScriptTags(params: { scriptTags: ScriptTag[] }) {
const { scriptTags } = params; const { scriptTags } = params;
if (scriptTagsFingerprint === undefined) { useState(() => {
scriptTagsFingerprint = getScriptTagsFingerprint(scriptTags); if (!isFistMount) {
} else if (getScriptTagsFingerprint(scriptTags) !== scriptTagsFingerprint) { window.location.reload();
// NOTE: This is for storybook, when we switch to a page that has different scripts. return;
window.location.reload(); }
}
isFistMount = false;
});
const insertScriptTags = useCallback(() => { const insertScriptTags = useCallback(() => {
if (areScriptsInserted) { if (areScriptsInserted) {
@ -85,17 +93,3 @@ export function createUseInsertScriptTags() {
return { useInsertScriptTags }; return { useInsertScriptTags };
} }
function getScriptTagsFingerprint(scriptTags: ScriptTag[]) {
return scriptTags
.map((scriptTag): string => {
if ("textContent" in scriptTag) {
return scriptTag.textContent;
}
if ("src" in scriptTag) {
return scriptTag.src;
}
assert(false);
})
.join("---");
}

View File

@ -76,6 +76,21 @@ export const WithRecaptcha: Story = {
) )
}; };
export const WithRecaptchaFrench: Story = {
render: () => (
<PageStory
kcContext={{
locale: {
currentLanguageTag: "fr"
},
scripts: ["https://www.google.com/recaptcha/api.js?hl=fr"],
recaptchaRequired: true,
recaptchaSiteKey: "6LfQHvApAAAAAE73SYTd5vS0lB1Xr7zdiQ-6iBVa"
}}
/>
)
};
export const WithPresets: Story = { export const WithPresets: Story = {
render: () => ( render: () => (
<PageStory <PageStory