Re implement asset fetching
This commit is contained in:
parent
89fb6de2d5
commit
b1da684008
@ -2,14 +2,12 @@ import { useEffect } from "react";
|
||||
import { clsx } from "keycloakify/tools/clsx";
|
||||
import { type TemplateProps } from "keycloakify/account/TemplateProps";
|
||||
import { useGetClassName } from "keycloakify/account/lib/useGetClassName";
|
||||
import { createUseInsertLinkTags } from "keycloakify/tools/useInsertLinkTags";
|
||||
import { useInsertLinkTags } from "keycloakify/tools/useInsertLinkTags";
|
||||
import { useSetClassName } from "keycloakify/tools/useSetClassName";
|
||||
import type { KcContext } from "./kcContext";
|
||||
import type { I18n } from "./i18n";
|
||||
import { assert } from "keycloakify/tools/assert";
|
||||
|
||||
const { useInsertLinkTags } = createUseInsertLinkTags();
|
||||
|
||||
export default function Template(props: TemplateProps<KcContext, I18n>) {
|
||||
const { kcContext, i18n, doUseDefaultCss, active, classes, children } = props;
|
||||
|
||||
@ -46,6 +44,7 @@ export default function Template(props: TemplateProps<KcContext, I18n>) {
|
||||
}, []);
|
||||
|
||||
const { areAllStyleSheetsLoaded } = useInsertLinkTags({
|
||||
componentOrHookName: "Template",
|
||||
hrefs: !doUseDefaultCss
|
||||
? []
|
||||
: [
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { ExtendKcContext, KcContext as KcContextBase } from "./KcContext";
|
||||
import type { LoginThemePageId } from "keycloakify/bin/shared/constants";
|
||||
import type { AccountThemePageId } from "keycloakify/bin/shared/constants";
|
||||
import type { DeepPartial } from "keycloakify/tools/DeepPartial";
|
||||
import { deepAssign } from "keycloakify/tools/deepAssign";
|
||||
import { structuredCloneButFunctions } from "keycloakify/tools/structuredCloneButFunctions";
|
||||
@ -18,7 +18,7 @@ export function createGetKcContextMock<
|
||||
overrides?: DeepPartial<KcContextExtraProperties & KcContextBase.Common>;
|
||||
overridesPerPage?: {
|
||||
[PageId in
|
||||
| LoginThemePageId
|
||||
| AccountThemePageId
|
||||
| keyof KcContextExtraPropertiesPerPage]?: DeepPartial<
|
||||
Extract<
|
||||
ExtendKcContext<
|
||||
@ -43,7 +43,7 @@ export function createGetKcContextMock<
|
||||
>;
|
||||
|
||||
function getKcContextMock<
|
||||
PageId extends LoginThemePageId | keyof KcContextExtraPropertiesPerPage
|
||||
PageId extends AccountThemePageId | keyof KcContextExtraPropertiesPerPage
|
||||
>(params: {
|
||||
pageId: PageId;
|
||||
overrides?: DeepPartial<Extract<KcContext, { pageId: PageId }>>;
|
||||
|
@ -3,15 +3,12 @@ import { assert } from "keycloakify/tools/assert";
|
||||
import { clsx } from "keycloakify/tools/clsx";
|
||||
import { type TemplateProps } from "keycloakify/login/TemplateProps";
|
||||
import { useGetClassName } from "keycloakify/login/lib/useGetClassName";
|
||||
import { createUseInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
||||
import { createUseInsertLinkTags } from "keycloakify/tools/useInsertLinkTags";
|
||||
import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
||||
import { useInsertLinkTags } from "keycloakify/tools/useInsertLinkTags";
|
||||
import { useSetClassName } from "keycloakify/tools/useSetClassName";
|
||||
import type { KcContext } from "./kcContext";
|
||||
import type { I18n } from "./i18n";
|
||||
|
||||
const { useInsertLinkTags } = createUseInsertLinkTags();
|
||||
const { useInsertScriptTags } = createUseInsertScriptTags();
|
||||
|
||||
export default function Template(props: TemplateProps<KcContext, I18n>) {
|
||||
const {
|
||||
displayInfo = false,
|
||||
@ -63,6 +60,7 @@ export default function Template(props: TemplateProps<KcContext, I18n>) {
|
||||
}, []);
|
||||
|
||||
const { areAllStyleSheetsLoaded } = useInsertLinkTags({
|
||||
componentOrHookName: "Template",
|
||||
hrefs: !doUseDefaultCss
|
||||
? []
|
||||
: [
|
||||
@ -75,6 +73,7 @@ export default function Template(props: TemplateProps<KcContext, I18n>) {
|
||||
});
|
||||
|
||||
const { insertScriptTags } = useInsertScriptTags({
|
||||
componentOrHookName: "Template",
|
||||
scriptTags: [
|
||||
{
|
||||
type: "module",
|
||||
|
@ -1,14 +1,11 @@
|
||||
import { useEffect } from "react";
|
||||
import { memoize } from "keycloakify/tools/memoize";
|
||||
import { fallbackLanguageTag } from "keycloakify/login/i18n/i18n";
|
||||
import { useConst } from "keycloakify/tools/useConst";
|
||||
import { useConstCallback } from "keycloakify/tools/useConstCallback";
|
||||
import { assert } from "tsafe/assert";
|
||||
import {
|
||||
createStatefulObservable,
|
||||
useRerenderOnChange
|
||||
} from "keycloakify/tools/StatefulObservable";
|
||||
import { KcContext } from "../kcContext";
|
||||
import { useOnFistMount } from "keycloakify/tools/useOnFirstMount";
|
||||
|
||||
const obsTermsMarkdown = createStatefulObservable<string | undefined>(() => undefined);
|
||||
|
||||
@ -27,29 +24,18 @@ export function useDownloadTerms(params: {
|
||||
kcContext: KcContextLike;
|
||||
downloadTermMarkdown: (params: { currentLanguageTag: string }) => Promise<string>;
|
||||
}) {
|
||||
const { kcContext } = params;
|
||||
const { kcContext, downloadTermMarkdown } = params;
|
||||
|
||||
const { downloadTermMarkdownMemoized } = (function useClosure() {
|
||||
const { downloadTermMarkdown } = params;
|
||||
|
||||
const downloadTermMarkdownConst = useConstCallback(downloadTermMarkdown);
|
||||
|
||||
const downloadTermMarkdownMemoized = useConst(() =>
|
||||
memoize((currentLanguageTag: string) =>
|
||||
downloadTermMarkdownConst({ currentLanguageTag })
|
||||
)
|
||||
);
|
||||
|
||||
return { downloadTermMarkdownMemoized };
|
||||
})();
|
||||
|
||||
useEffect(() => {
|
||||
useOnFistMount(async () => {
|
||||
if (kcContext.pageId === "terms.ftl" || kcContext.termsAcceptanceRequired) {
|
||||
downloadTermMarkdownMemoized(
|
||||
const termsMarkdown = await downloadTermMarkdown({
|
||||
currentLanguageTag:
|
||||
kcContext.locale?.currentLanguageTag ?? fallbackLanguageTag
|
||||
).then(thermMarkdown => (obsTermsMarkdown.current = thermMarkdown));
|
||||
});
|
||||
|
||||
obsTermsMarkdown.current = termsMarkdown;
|
||||
}
|
||||
}, []);
|
||||
});
|
||||
}
|
||||
|
||||
export function useTermsMarkdown() {
|
||||
|
@ -3,6 +3,7 @@ import type { ClassKey } from "keycloakify/login/TemplateProps";
|
||||
|
||||
export const { useGetClassName } = createUseClassName<ClassKey>({
|
||||
defaultClasses: {
|
||||
kcHtmlClass: "login-pf",
|
||||
kcBodyClass: undefined,
|
||||
kcHeaderWrapperClass: undefined,
|
||||
kcLocaleWrapperClass: undefined,
|
||||
@ -54,7 +55,6 @@ export const { useGetClassName } = createUseClassName<ClassKey>({
|
||||
kcLogoLink: "http://www.keycloak.org",
|
||||
kcContainerClass: "container-fluid",
|
||||
kcSelectAuthListItemTitle: "select-auth-box-paragraph",
|
||||
kcHtmlClass: "login-pf",
|
||||
kcLoginOTPListItemTitleClass: "pf-c-tile__title",
|
||||
"kcLogoIdP-openshift-v4": "pf-icon pf-icon-openshift",
|
||||
kcWebAuthnUnknownIcon: "pficon pficon-key unknown-transport-class",
|
||||
|
@ -8,7 +8,7 @@ import { emailRegexp } from "keycloakify/tools/emailRegExp";
|
||||
import type { KcContext, PasswordPolicies } from "keycloakify/login/kcContext/KcContext";
|
||||
import { assert, type Equals } from "tsafe/assert";
|
||||
import { formatNumber } from "keycloakify/tools/formatNumber";
|
||||
import { createUseInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
||||
import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
||||
import { structuredCloneButFunctions } from "keycloakify/tools/structuredCloneButFunctions";
|
||||
import type { I18n } from "../i18n";
|
||||
|
||||
@ -103,12 +103,11 @@ namespace internal {
|
||||
};
|
||||
}
|
||||
|
||||
const { useInsertScriptTags } = createUseInsertScriptTags();
|
||||
|
||||
export function useUserProfileForm(params: ParamsOfUseUserProfileForm): ReturnTypeOfUseUserProfileForm {
|
||||
const { kcContext, i18n, doMakeUserConfirmPassword } = params;
|
||||
|
||||
const { insertScriptTags } = useInsertScriptTags({
|
||||
componentOrHookName: "useUserProfileForm",
|
||||
scriptTags: Object.keys(kcContext.profile?.html5DataAnnotations ?? {})
|
||||
.filter(key => key !== "kcMultivalued" && key !== "kcNumberFormat") // NOTE: Keycloakify handles it.
|
||||
.map(key => ({
|
||||
|
@ -2,12 +2,10 @@ import { useEffect } from "react";
|
||||
import { clsx } from "keycloakify/tools/clsx";
|
||||
import type { PageProps } from "keycloakify/login/pages/PageProps";
|
||||
import { useGetClassName } from "keycloakify/login/lib/useGetClassName";
|
||||
import { createUseInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
||||
import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
||||
import type { KcContext } from "../kcContext";
|
||||
import type { I18n } from "../i18n";
|
||||
|
||||
const { useInsertScriptTags } = createUseInsertScriptTags();
|
||||
|
||||
export default function LoginRecoveryAuthnCodeConfig(props: PageProps<Extract<KcContext, { pageId: "login-recovery-authn-code-config.ftl" }>, I18n>) {
|
||||
const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
|
||||
|
||||
@ -21,6 +19,7 @@ export default function LoginRecoveryAuthnCodeConfig(props: PageProps<Extract<Kc
|
||||
const { msg, msgStr } = i18n;
|
||||
|
||||
const { insertScriptTags } = useInsertScriptTags({
|
||||
componentOrHookName: "LoginRecoveryAuthnCodeConfig",
|
||||
scriptTags: [
|
||||
{
|
||||
type: "text/javascript",
|
||||
|
@ -3,12 +3,10 @@ import { clsx } from "keycloakify/tools/clsx";
|
||||
import type { PageProps } from "keycloakify/login/pages/PageProps";
|
||||
import { useGetClassName } from "keycloakify/login/lib/useGetClassName";
|
||||
import { assert } from "tsafe/assert";
|
||||
import { createUseInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
||||
import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
||||
import type { KcContext } from "../kcContext";
|
||||
import type { I18n } from "../i18n";
|
||||
|
||||
const { useInsertScriptTags } = createUseInsertScriptTags();
|
||||
|
||||
export default function WebauthnAuthenticate(props: PageProps<Extract<KcContext, { pageId: "webauthn-authenticate.ftl" }>, I18n>) {
|
||||
const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
|
||||
|
||||
@ -31,6 +29,7 @@ export default function WebauthnAuthenticate(props: PageProps<Extract<KcContext,
|
||||
const { msg, msgStr, advancedMsg } = i18n;
|
||||
|
||||
const { insertScriptTags } = useInsertScriptTags({
|
||||
componentOrHookName: "WebauthnAuthenticate",
|
||||
scriptTags: [
|
||||
{
|
||||
type: "text/javascript",
|
||||
|
@ -3,12 +3,10 @@ import { clsx } from "keycloakify/tools/clsx";
|
||||
import type { PageProps } from "keycloakify/login/pages/PageProps";
|
||||
import { useGetClassName } from "keycloakify/login/lib/useGetClassName";
|
||||
import { assert } from "tsafe/assert";
|
||||
import { createUseInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
||||
import { useInsertScriptTags } from "keycloakify/tools/useInsertScriptTags";
|
||||
import type { KcContext } from "../kcContext";
|
||||
import type { I18n } from "../i18n";
|
||||
|
||||
const { useInsertScriptTags } = createUseInsertScriptTags();
|
||||
|
||||
export default function WebauthnRegister(props: PageProps<Extract<KcContext, { pageId: "webauthn-register.ftl" }>, I18n>) {
|
||||
const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
|
||||
|
||||
@ -35,6 +33,7 @@ export default function WebauthnRegister(props: PageProps<Extract<KcContext, { p
|
||||
const { msg, msgStr } = i18n;
|
||||
|
||||
const { insertScriptTags } = useInsertScriptTags({
|
||||
componentOrHookName: "WebauthnRegister",
|
||||
scriptTags: [
|
||||
{
|
||||
type: "text/javascript",
|
||||
|
@ -5,15 +5,15 @@ import type { StatefulObservable } from "../StatefulObservable";
|
||||
/**
|
||||
* Equivalent of https://docs.evt.land/api/react-hooks
|
||||
* */
|
||||
export function useRerenderOnChange($: StatefulObservable<unknown>): void {
|
||||
export function useRerenderOnChange(obs: StatefulObservable<unknown>): void {
|
||||
//NOTE: We use function in case the state is a function
|
||||
const [, setCurrent] = useState(() => $.current);
|
||||
const [, setCurrent] = useState(() => obs.current);
|
||||
|
||||
useObservable(
|
||||
({ registerSubscription }) => {
|
||||
const subscription = $.subscribe(current => setCurrent(() => current));
|
||||
const subscription = obs.subscribe(current => setCurrent(() => current));
|
||||
registerSubscription(subscription);
|
||||
},
|
||||
[$]
|
||||
[obs]
|
||||
);
|
||||
}
|
||||
|
@ -1,55 +0,0 @@
|
||||
type SimpleType = number | string | boolean | null | undefined;
|
||||
type FuncWithSimpleParams<T extends SimpleType[], R> = (...args: T) => R;
|
||||
|
||||
export function memoize<T extends SimpleType[], R>(
|
||||
fn: FuncWithSimpleParams<T, R>,
|
||||
options?: {
|
||||
argsLength?: number;
|
||||
max?: number;
|
||||
}
|
||||
): FuncWithSimpleParams<T, R> {
|
||||
const cache = new Map<string, ReturnType<FuncWithSimpleParams<T, R>>>();
|
||||
|
||||
const { argsLength = fn.length, max = Infinity } = options ?? {};
|
||||
|
||||
return ((...args: Parameters<FuncWithSimpleParams<T, R>>) => {
|
||||
const key = JSON.stringify(
|
||||
args
|
||||
.slice(0, argsLength)
|
||||
.map(v => {
|
||||
if (v === null) {
|
||||
return "null";
|
||||
}
|
||||
if (v === undefined) {
|
||||
return "undefined";
|
||||
}
|
||||
switch (typeof v) {
|
||||
case "number":
|
||||
return `number-${v}`;
|
||||
case "string":
|
||||
return `string-${v}`;
|
||||
case "boolean":
|
||||
return `boolean-${v ? "true" : "false"}`;
|
||||
}
|
||||
})
|
||||
.join("-sIs9sAslOdeWlEdIos3-")
|
||||
);
|
||||
|
||||
if (cache.has(key)) {
|
||||
return cache.get(key);
|
||||
}
|
||||
|
||||
if (max === cache.size) {
|
||||
for (const key of cache.keys()) {
|
||||
cache.delete(key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const value = fn(...args);
|
||||
|
||||
cache.set(key, value);
|
||||
|
||||
return value;
|
||||
}) as any;
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
createStatefulObservable,
|
||||
useRerenderOnChange
|
||||
} from "keycloakify/tools/StatefulObservable";
|
||||
import { useEffect, useReducer } from "react";
|
||||
import { useConst } from "keycloakify/tools/useConst";
|
||||
import { id } from "tsafe/id";
|
||||
import { useOnFistMount } from "keycloakify/tools/useOnFirstMount";
|
||||
|
||||
const alreadyMountedComponentOrHookNames = new Set<string>();
|
||||
|
||||
/**
|
||||
* NOTE: The component that use this hook can only be mounded once!
|
||||
@ -10,28 +11,37 @@ import {
|
||||
* 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() {
|
||||
let isFistMount = true;
|
||||
export function useInsertLinkTags(params: {
|
||||
componentOrHookName: string;
|
||||
hrefs: string[];
|
||||
}) {
|
||||
const { hrefs, componentOrHookName } = params;
|
||||
|
||||
const obsAreAllStyleSheetsLoaded = createStatefulObservable(() => false);
|
||||
useOnFistMount(() => {
|
||||
const isAlreadyMounted =
|
||||
alreadyMountedComponentOrHookNames.has(componentOrHookName);
|
||||
|
||||
function useInsertLinkTags(params: { hrefs: string[] }) {
|
||||
const { hrefs } = params;
|
||||
|
||||
useRerenderOnChange(obsAreAllStyleSheetsLoaded);
|
||||
|
||||
useState(() => {
|
||||
if (!isFistMount) {
|
||||
if (isAlreadyMounted) {
|
||||
window.location.reload();
|
||||
return;
|
||||
}
|
||||
|
||||
isFistMount = false;
|
||||
alreadyMountedComponentOrHookNames.add(componentOrHookName);
|
||||
});
|
||||
|
||||
const [areAllStyleSheetsLoaded, setAllStyleSheetsLoaded] = useReducer(
|
||||
() => true,
|
||||
false
|
||||
);
|
||||
|
||||
const refPrAllStyleSheetLoaded = useConst(() => ({
|
||||
current: id<Promise<void> | undefined>(undefined)
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
let isActive = true;
|
||||
|
||||
(refPrAllStyleSheetLoaded.current ??= (async () => {
|
||||
let lastMountedHtmlElement: HTMLLinkElement | undefined = undefined;
|
||||
|
||||
const prs: Promise<void>[] = [];
|
||||
@ -58,11 +68,13 @@ export function createUseInsertLinkTags() {
|
||||
lastMountedHtmlElement = htmlElement;
|
||||
}
|
||||
|
||||
Promise.all(prs).then(() => {
|
||||
await Promise.all(prs);
|
||||
})()).then(() => {
|
||||
if (!isActive) {
|
||||
return;
|
||||
}
|
||||
obsAreAllStyleSheetsLoaded.current = true;
|
||||
|
||||
setAllStyleSheetsLoaded();
|
||||
});
|
||||
|
||||
return () => {
|
||||
@ -70,8 +82,5 @@ export function createUseInsertLinkTags() {
|
||||
};
|
||||
}, []);
|
||||
|
||||
return { areAllStyleSheetsLoaded: obsAreAllStyleSheetsLoaded.current };
|
||||
}
|
||||
|
||||
return { useInsertLinkTags };
|
||||
return { areAllStyleSheetsLoaded };
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { useCallback, useState } from "react";
|
||||
import { useCallback } from "react";
|
||||
import { assert } from "tsafe/assert";
|
||||
import { useOnFistMount } from "keycloakify/tools/useOnFirstMount";
|
||||
|
||||
export type ScriptTag = ScriptTag.TextContent | ScriptTag.Src;
|
||||
|
||||
@ -16,29 +17,38 @@ export namespace ScriptTag {
|
||||
};
|
||||
}
|
||||
|
||||
const alreadyMountedComponentOrHookNames = new Set<string>();
|
||||
|
||||
/**
|
||||
* NOTE: The component that use this hook can only be mounded once!
|
||||
* And can'r rerender with different scriptTags.
|
||||
* And can't 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.
|
||||
*
|
||||
* The returned function is supposed to be called in a useEffect and
|
||||
* will not download the scripts multiple times event if called more than once (react strict mode).
|
||||
*
|
||||
*/
|
||||
export function createUseInsertScriptTags() {
|
||||
let areScriptsInserted = false;
|
||||
export function useInsertScriptTags(params: {
|
||||
componentOrHookName: string;
|
||||
scriptTags: ScriptTag[];
|
||||
}) {
|
||||
const { scriptTags, componentOrHookName } = params;
|
||||
|
||||
let isFistMount = true;
|
||||
useOnFistMount(() => {
|
||||
const isAlreadyMounted =
|
||||
alreadyMountedComponentOrHookNames.has(componentOrHookName);
|
||||
|
||||
function useInsertScriptTags(params: { scriptTags: ScriptTag[] }) {
|
||||
const { scriptTags } = params;
|
||||
|
||||
useState(() => {
|
||||
if (!isFistMount) {
|
||||
if (isAlreadyMounted) {
|
||||
window.location.reload();
|
||||
return;
|
||||
}
|
||||
|
||||
isFistMount = false;
|
||||
alreadyMountedComponentOrHookNames.add(componentOrHookName);
|
||||
});
|
||||
|
||||
let areScriptsInserted = false;
|
||||
|
||||
const insertScriptTags = useCallback(() => {
|
||||
if (areScriptsInserted) {
|
||||
return;
|
||||
@ -89,7 +99,4 @@ export function createUseInsertScriptTags() {
|
||||
}, []);
|
||||
|
||||
return { insertScriptTags };
|
||||
}
|
||||
|
||||
return { useInsertScriptTags };
|
||||
}
|
||||
|
18
src/tools/useOnFirstMount.ts
Normal file
18
src/tools/useOnFirstMount.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { useEffect } from "react";
|
||||
import { useConst } from "powerhooks/useConst";
|
||||
import { id } from "tsafe/id";
|
||||
|
||||
/** Callback is guaranteed to be call only once per component mount event in strict mode */
|
||||
export function useOnFistMount(callback: () => void) {
|
||||
const refHasCallbackBeenCalled = useConst(() => ({ current: id<boolean>(false) }));
|
||||
|
||||
useEffect(() => {
|
||||
if (refHasCallbackBeenCalled.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
callback();
|
||||
|
||||
refHasCallbackBeenCalled.current = true;
|
||||
}, []);
|
||||
}
|
@ -1,9 +1,8 @@
|
||||
import React, { lazy, Suspense } from "react";
|
||||
import React from "react";
|
||||
import Fallback from "../../dist/account";
|
||||
import type { KcContext } from "./kcContext";
|
||||
import { useI18n } from "./i18n";
|
||||
|
||||
const DefaultTemplate = lazy(() => import("../../dist/account/Template"));
|
||||
import Template from "../../dist/account/Template";
|
||||
|
||||
export default function KcApp(props: { kcContext: KcContext }) {
|
||||
const { kcContext } = props;
|
||||
@ -14,14 +13,5 @@ export default function KcApp(props: { kcContext: KcContext }) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Suspense>
|
||||
{(() => {
|
||||
switch (kcContext.pageId) {
|
||||
default:
|
||||
return <Fallback {...{ kcContext, i18n }} Template={DefaultTemplate} doUseDefaultCss={true} />;
|
||||
}
|
||||
})()}
|
||||
</Suspense>
|
||||
);
|
||||
return <Fallback {...{ kcContext, i18n }} Template={Template} doUseDefaultCss={true} />;
|
||||
}
|
||||
|
@ -15,7 +15,11 @@ export function createPageStory<PageId extends KcContext["pageId"]>(params: { pa
|
||||
overrides
|
||||
});
|
||||
|
||||
return <KcApp kcContext={kcContextMock} />;
|
||||
return (
|
||||
<React.StrictMode>
|
||||
<KcApp kcContext={kcContextMock} />
|
||||
</React.StrictMode>
|
||||
);
|
||||
}
|
||||
|
||||
return { PageStory };
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { lazy, Suspense } from "react";
|
||||
import React from "react";
|
||||
import Fallback from "../../dist/login";
|
||||
import type { KcContext } from "./kcContext";
|
||||
import { useI18n } from "./i18n";
|
||||
@ -34,11 +34,6 @@ export default function KcApp(props: { kcContext: KcContext }) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Suspense>
|
||||
{(() => {
|
||||
switch (kcContext.pageId) {
|
||||
default:
|
||||
return (
|
||||
<Fallback
|
||||
{...{
|
||||
@ -50,8 +45,4 @@ export default function KcApp(props: { kcContext: KcContext }) {
|
||||
doUseDefaultCss={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
})()}
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
@ -15,7 +15,11 @@ export function createPageStory<PageId extends KcContext["pageId"]>(params: { pa
|
||||
overrides
|
||||
});
|
||||
|
||||
return <KcApp kcContext={kcContextMock} />;
|
||||
return (
|
||||
<React.StrictMode>
|
||||
<KcApp kcContext={kcContextMock} />
|
||||
</React.StrictMode>
|
||||
);
|
||||
}
|
||||
|
||||
return { PageStory };
|
||||
|
Loading…
x
Reference in New Issue
Block a user