@multiplatform.one/core 7.34.4 → 7.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +12 -12
- package/src/app/CreateApp.keycloak.spec.tsx +79 -0
- package/src/app/CreateApp.tsx +8 -1
- package/src/app/CreateRootLayout.spaScale.spec.tsx +56 -0
- package/src/app/CreateRootLayout.web.spec.tsx +63 -1
- package/src/app/CreateRootLayout.web.tsx +39 -3
- package/types/app/CreateApp.d.ts +1 -0
- package/types/app/CreateApp.d.ts.map +1 -1
- package/types/app/CreateRootLayout.web.d.ts +1 -1
- package/types/app/CreateRootLayout.web.d.ts.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@multiplatform.one/core",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.35.0",
|
|
4
4
|
"description": "Core framework shell, provider composition, and layout factories for multiplatform.one",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"app",
|
|
@@ -41,11 +41,11 @@
|
|
|
41
41
|
"access": "public"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@multiplatform.one/i18n": "^7.
|
|
45
|
-
"@multiplatform.one/logger": "^7.
|
|
46
|
-
"@multiplatform.one/platform": "^7.
|
|
47
|
-
"@multiplatform.one/store": "^7.
|
|
48
|
-
"@multiplatform.one/theme": "^7.
|
|
44
|
+
"@multiplatform.one/i18n": "^7.35.0",
|
|
45
|
+
"@multiplatform.one/logger": "^7.35.0",
|
|
46
|
+
"@multiplatform.one/platform": "^7.35.0",
|
|
47
|
+
"@multiplatform.one/store": "^7.35.0",
|
|
48
|
+
"@multiplatform.one/theme": "^7.35.0",
|
|
49
49
|
"@tanstack/devtools-utils": "^0.4.0",
|
|
50
50
|
"@tanstack/pacer-devtools": "1.6.0",
|
|
51
51
|
"@tanstack/react-devtools": "0.10.13",
|
|
@@ -53,8 +53,8 @@
|
|
|
53
53
|
"react-cookie": "^8.1.2"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@multiplatform.one/frappe": "7.
|
|
57
|
-
"@multiplatform.one/web3": "7.
|
|
56
|
+
"@multiplatform.one/frappe": "7.35.0",
|
|
57
|
+
"@multiplatform.one/web3": "7.35.0",
|
|
58
58
|
"@sentry/react": "^10.51.0",
|
|
59
59
|
"@tanstack/react-query": "^5.104.3",
|
|
60
60
|
"@tanstack/react-query-devtools": "^5.104.3",
|
|
@@ -72,10 +72,10 @@
|
|
|
72
72
|
"vitest": "^4.1.5"
|
|
73
73
|
},
|
|
74
74
|
"peerDependencies": {
|
|
75
|
-
"@multiplatform.one/frappe": "^7.
|
|
76
|
-
"@multiplatform.one/frappe-ui": "^7.
|
|
77
|
-
"@multiplatform.one/keycloak": "^7.
|
|
78
|
-
"@multiplatform.one/web3": "^7.
|
|
75
|
+
"@multiplatform.one/frappe": "^7.35.0",
|
|
76
|
+
"@multiplatform.one/frappe-ui": "^7.35.0",
|
|
77
|
+
"@multiplatform.one/keycloak": "^7.35.0",
|
|
78
|
+
"@multiplatform.one/web3": "^7.35.0",
|
|
79
79
|
"@sentry/react": "^9.0.0 || ^10.0.0",
|
|
80
80
|
"@tanstack/react-query": "^5.0.0",
|
|
81
81
|
"@tanstack/react-query-devtools": "^5.0.0",
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// @vitest-environment happy-dom
|
|
2
|
+
import { act, cleanup, render, screen } from "@testing-library/react";
|
|
3
|
+
import type { ComponentType, PropsWithChildren } from "react";
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
5
|
+
import { createApp } from "./CreateApp";
|
|
6
|
+
|
|
7
|
+
const { env, platform, provided } = vi.hoisted(() => ({
|
|
8
|
+
env: {} as Record<string, string>,
|
|
9
|
+
platform: { isWeb: true },
|
|
10
|
+
provided: {
|
|
11
|
+
current: {} as {
|
|
12
|
+
baseUrl?: string;
|
|
13
|
+
betterAuthBaseUrl?: string;
|
|
14
|
+
loadingComponent?: ComponentType;
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
}));
|
|
18
|
+
vi.mock("@multiplatform.one/platform", () => ({
|
|
19
|
+
config: { get: (key: string) => env[key] },
|
|
20
|
+
isDev: false,
|
|
21
|
+
get isWeb() {
|
|
22
|
+
return platform.isWeb;
|
|
23
|
+
},
|
|
24
|
+
}));
|
|
25
|
+
vi.mock("@multiplatform.one/theme", () => ({
|
|
26
|
+
ThemeProvider: ({ children }: PropsWithChildren) => children,
|
|
27
|
+
}));
|
|
28
|
+
vi.mock("@multiplatform.one/frappe-ui", () => ({
|
|
29
|
+
FrappeProvider: ({ children }: PropsWithChildren) => children,
|
|
30
|
+
}));
|
|
31
|
+
vi.mock("./TanstackProvider", () => ({ createTanstackProvider: vi.fn() }));
|
|
32
|
+
vi.mock("./loadWalletProvider", () => ({ default: () => null }));
|
|
33
|
+
vi.mock("one", () => ({ usePathname: () => "/", useRouter: () => ({ push: vi.fn() }) }));
|
|
34
|
+
vi.mock("@multiplatform.one/keycloak", () => ({
|
|
35
|
+
KeycloakProvider: ({ children, ...props }: PropsWithChildren<typeof provided.current>) => {
|
|
36
|
+
provided.current = props;
|
|
37
|
+
const Slot = props.loadingComponent;
|
|
38
|
+
return (
|
|
39
|
+
<>
|
|
40
|
+
<span>keycloak loaded</span>
|
|
41
|
+
{children}
|
|
42
|
+
{Slot && <Slot />}
|
|
43
|
+
</>
|
|
44
|
+
);
|
|
45
|
+
},
|
|
46
|
+
}));
|
|
47
|
+
afterEach(() => {
|
|
48
|
+
cleanup();
|
|
49
|
+
for (const key of Object.keys(env)) delete env[key];
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe.each([true, false])("createApp keycloak (isWeb=%s)", (isWeb) => {
|
|
53
|
+
it.each([
|
|
54
|
+
["https://explicit.test/auth", "https://public.test/auth", "https://explicit.test/auth"],
|
|
55
|
+
[undefined, "https://public.test/auth", "https://public.test/auth"],
|
|
56
|
+
[undefined, undefined, "https://app.test/auth"],
|
|
57
|
+
])("uses explicit, public, then fallback URL (%s, %s)", async (baseUrl, publicUrl, expected) => {
|
|
58
|
+
platform.isWeb = isWeb;
|
|
59
|
+
env.BASE_URL = "https://app.test";
|
|
60
|
+
if (publicUrl) env.KEYCLOAK_BASE_URL = publicUrl;
|
|
61
|
+
env.BETTER_AUTH_BASE_URL = "https://app.test/backend/prefix";
|
|
62
|
+
const Slot = () => <div>custom auth loading</div>;
|
|
63
|
+
const { AppProvider } = createApp({
|
|
64
|
+
keycloak: { enabled: true, baseUrl, loadingComponent: Slot },
|
|
65
|
+
});
|
|
66
|
+
await act(async () => {
|
|
67
|
+
render(
|
|
68
|
+
<AppProvider>
|
|
69
|
+
<span>app child</span>
|
|
70
|
+
</AppProvider>,
|
|
71
|
+
);
|
|
72
|
+
});
|
|
73
|
+
expect(screen.queryByText("keycloak loaded")).not.toBeNull();
|
|
74
|
+
expect(provided.current.baseUrl).toBe(expected);
|
|
75
|
+
expect(provided.current.betterAuthBaseUrl).toBe("https://app.test/backend/prefix");
|
|
76
|
+
expect(provided.current.loadingComponent).toBe(Slot);
|
|
77
|
+
expect(screen.queryByText("custom auth loading")).not.toBeNull();
|
|
78
|
+
});
|
|
79
|
+
});
|
package/src/app/CreateApp.tsx
CHANGED
|
@@ -138,6 +138,7 @@ export interface TanstackConfig {
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
export interface KeycloakConfig {
|
|
141
|
+
loadingComponent?: ComponentType;
|
|
141
142
|
/** Force-enable or disable. When omitted, reads KEYCLOAK_ENABLED from env config. */
|
|
142
143
|
enabled?: boolean;
|
|
143
144
|
baseUrl?: string;
|
|
@@ -346,6 +347,7 @@ export function createApp(appConfig: CreateAppConfig) {
|
|
|
346
347
|
messageHandlerKeys?: string[];
|
|
347
348
|
betterAuthBaseUrl?: string;
|
|
348
349
|
expoScheme?: string;
|
|
350
|
+
loadingComponent?: ComponentType;
|
|
349
351
|
}>
|
|
350
352
|
>,
|
|
351
353
|
};
|
|
@@ -360,7 +362,11 @@ export function createApp(appConfig: CreateAppConfig) {
|
|
|
360
362
|
<LazyKeycloakProvider
|
|
361
363
|
disabled={false}
|
|
362
364
|
debug={cfg.debug ?? config.get("DEBUG") === "1"}
|
|
363
|
-
baseUrl={
|
|
365
|
+
baseUrl={
|
|
366
|
+
cfg.baseUrl ||
|
|
367
|
+
config.get("KEYCLOAK_BASE_URL") ||
|
|
368
|
+
`${config.get("BASE_URL") || ""}/auth`
|
|
369
|
+
}
|
|
364
370
|
clientId={cfg.clientId || config.get("KEYCLOAK_CLIENT_ID")}
|
|
365
371
|
publicClientId={cfg.publicClientId || config.get("KEYCLOAK_PUBLIC_CLIENT_ID")}
|
|
366
372
|
realm={cfg.realm || config.get("KEYCLOAK_REALM") || ""}
|
|
@@ -374,6 +380,7 @@ export function createApp(appConfig: CreateAppConfig) {
|
|
|
374
380
|
undefined
|
|
375
381
|
}
|
|
376
382
|
expoScheme={cfg.expoScheme}
|
|
383
|
+
loadingComponent={cfg.loadingComponent}
|
|
377
384
|
>
|
|
378
385
|
{children}
|
|
379
386
|
</LazyKeycloakProvider>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { renderToStaticMarkup } from "react-dom/server";
|
|
2
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import { createRootLayout } from "./CreateRootLayout.web";
|
|
5
|
+
|
|
6
|
+
vi.mock("one", () => ({
|
|
7
|
+
LoadProgressBar: () => null,
|
|
8
|
+
Slot: () => null,
|
|
9
|
+
useMatches: vi.fn(() => []),
|
|
10
|
+
SchemeProvider: ({ children }: { children: ReactNode }) => children,
|
|
11
|
+
setUserScheme: vi.fn(),
|
|
12
|
+
useUserScheme: () => ({ value: "light" }),
|
|
13
|
+
}));
|
|
14
|
+
vi.mock("i18next", () => ({
|
|
15
|
+
default: {
|
|
16
|
+
use: () => ({ init: () => Promise.resolve() }),
|
|
17
|
+
changeLanguage: vi.fn(),
|
|
18
|
+
language: "en",
|
|
19
|
+
},
|
|
20
|
+
}));
|
|
21
|
+
vi.mock("react-i18next", () => ({ initReactI18next: {} }));
|
|
22
|
+
vi.mock("@multiplatform.one/platform", () => ({
|
|
23
|
+
config: { get: (_key: string, fallback?: string) => fallback },
|
|
24
|
+
isDev: false,
|
|
25
|
+
platform: { isServer: false },
|
|
26
|
+
}));
|
|
27
|
+
vi.mock("@multiplatform.one/i18n", () => ({ createI18nConfig: () => ({}) }));
|
|
28
|
+
vi.mock("@multiplatform.one/logger", () => ({ logger: { error: vi.fn() } }));
|
|
29
|
+
vi.mock("@multiplatform.one/store", () => ({ storage: {} }));
|
|
30
|
+
vi.mock("./RuntimePublicConfigScript", () => ({ RuntimePublicConfigScript: () => null }));
|
|
31
|
+
|
|
32
|
+
function renderClientRoot() {
|
|
33
|
+
const Wrapper = ({ children }: { children?: ReactNode }) => children;
|
|
34
|
+
const Layout = createRootLayout({
|
|
35
|
+
AppProvider: Wrapper,
|
|
36
|
+
RootLayout: Wrapper,
|
|
37
|
+
i18n: { defaultLanguage: "en" },
|
|
38
|
+
} as Parameters<typeof createRootLayout>[0]);
|
|
39
|
+
return renderToStaticMarkup(<Layout />);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
afterEach(() => {
|
|
43
|
+
vi.unstubAllGlobals();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe("web root preset scale on a client render (SPA route)", () => {
|
|
47
|
+
it("names the cookie's preset on <html>, since the SPA shell has no head script", () => {
|
|
48
|
+
vi.stubGlobal("document", { cookie: "a=1; mp.preset=dense" });
|
|
49
|
+
expect(renderClientRoot()).toMatch(/<html[^>]*data-mp-scale="dense"/);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("leaves the attribute off without a preset cookie", () => {
|
|
53
|
+
vi.stubGlobal("document", { cookie: "a=1" });
|
|
54
|
+
expect(renderClientRoot()).not.toMatch(/<html[^>]*data-mp-scale=/);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -6,7 +6,7 @@ import { createRootLayout } from "./CreateRootLayout.web";
|
|
|
6
6
|
vi.mock("one", () => ({
|
|
7
7
|
LoadProgressBar: () => null,
|
|
8
8
|
Slot: () => null,
|
|
9
|
-
useMatches: () => [],
|
|
9
|
+
useMatches: vi.fn(() => []),
|
|
10
10
|
SchemeProvider: ({ children }: { children: ReactNode }) => children,
|
|
11
11
|
setUserScheme: vi.fn(),
|
|
12
12
|
useUserScheme: () => ({ value: "light" }),
|
|
@@ -64,3 +64,65 @@ describe("web root title (MPO-325)", () => {
|
|
|
64
64
|
expect(renderRoot({ favicon: "/custom.svg" })).not.toContain("<title>");
|
|
65
65
|
});
|
|
66
66
|
});
|
|
67
|
+
|
|
68
|
+
describe("web root preset scale (FZ-7158 WP-a2)", () => {
|
|
69
|
+
it("runs the scale attribute script in the head before any body content", () => {
|
|
70
|
+
const html = renderRoot();
|
|
71
|
+
const head = html.slice(html.indexOf("<head>"), html.indexOf("</head>"));
|
|
72
|
+
expect(head).toContain("data-mp-scale");
|
|
73
|
+
expect(head).toContain("mp\\.preset=");
|
|
74
|
+
expect(html.indexOf("mp\\.preset=")).toBeLessThan(html.indexOf("<body"));
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("renders <html data-mp-scale> from the request's mp.preset cookie", async () => {
|
|
78
|
+
const one = await import("one");
|
|
79
|
+
vi.mocked(one.useMatches).mockReturnValueOnce([
|
|
80
|
+
{ loaderData: { cookieHeader: "a=1; mp.preset=dense" } },
|
|
81
|
+
] as unknown as ReturnType<typeof one.useMatches>);
|
|
82
|
+
const html = renderRoot();
|
|
83
|
+
expect(html).toMatch(/<html[^>]*data-mp-scale="dense"/);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("leaves the attribute off without a preset cookie", () => {
|
|
87
|
+
const html = renderRoot();
|
|
88
|
+
expect(html).not.toMatch(/<html[^>]*data-mp-scale=/);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe("web root Inter faces (FZ-7158 WP-b3)", () => {
|
|
93
|
+
it("declares five faces and preloads only the four first-screen weights", () => {
|
|
94
|
+
const html = renderRoot({ interFonts: true });
|
|
95
|
+
const faces = [...html.matchAll(/@font-face\{([^}]+)\}/g)].map((match) => match[1]);
|
|
96
|
+
expect(faces).toHaveLength(5);
|
|
97
|
+
for (const weight of [400, 500, 600, 700, 800]) {
|
|
98
|
+
expect(faces.filter((face) => face.includes(`font-weight:${weight};`))).toEqual([
|
|
99
|
+
expect.stringContaining(`src:url("/fonts/inter-${weight}.woff2")`),
|
|
100
|
+
]);
|
|
101
|
+
expect(faces.find((face) => face.includes(`font-weight:${weight};`))).toContain(
|
|
102
|
+
'font-family:"Inter";font-style:normal;',
|
|
103
|
+
);
|
|
104
|
+
expect(faces.find((face) => face.includes(`font-weight:${weight};`))).toContain(
|
|
105
|
+
"font-display:optional;",
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
const preloads = (html.match(/<link\b[^>]*>/g) ?? []).filter(
|
|
109
|
+
(link) => link.includes('rel="preload"') && link.includes('as="font"'),
|
|
110
|
+
);
|
|
111
|
+
expect(preloads.map((link) => link.match(/href="([^"]+)"/)?.[1])).toEqual(
|
|
112
|
+
[400, 600, 700, 800].map((weight) => `/fonts/inter-${weight}.woff2`),
|
|
113
|
+
);
|
|
114
|
+
for (const link of preloads) {
|
|
115
|
+
expect(link).toContain('type="font/woff2"');
|
|
116
|
+
expect(link).toContain('crossorigin=""');
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("renders no Inter declarations or preloads when disabled", () => {
|
|
121
|
+
const html = renderRoot({ interFonts: false });
|
|
122
|
+
expect(html).not.toContain("@font-face");
|
|
123
|
+
expect(html).not.toContain("__font_inter");
|
|
124
|
+
for (const weight of [400, 500, 600, 700, 800]) {
|
|
125
|
+
expect(html).not.toContain(`/fonts/inter-${weight}.woff2`);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
});
|
|
@@ -11,13 +11,18 @@ import {
|
|
|
11
11
|
useMatches,
|
|
12
12
|
useUserScheme,
|
|
13
13
|
} from "one";
|
|
14
|
-
import type
|
|
14
|
+
import { type ComponentType, type ReactNode, useState } from "react";
|
|
15
15
|
import { CookiesProvider, Cookies } from "react-cookie";
|
|
16
16
|
import { initReactI18next } from "react-i18next";
|
|
17
17
|
import { config, isDev, platform } from "@multiplatform.one/platform";
|
|
18
18
|
import { createI18nConfig } from "@multiplatform.one/i18n";
|
|
19
19
|
import { logger } from "@multiplatform.one/logger";
|
|
20
20
|
import { storage } from "@multiplatform.one/store";
|
|
21
|
+
import {
|
|
22
|
+
cookiePreset,
|
|
23
|
+
scaleAttributeFromCookie,
|
|
24
|
+
scaleAttributeScript,
|
|
25
|
+
} from "@multiplatform.one/theme/scale-attribute";
|
|
21
26
|
import { RuntimePublicConfigScript } from "./RuntimePublicConfigScript";
|
|
22
27
|
import type { CreateRootLayoutConfig, RootLoaderData } from "./rootLayoutShared";
|
|
23
28
|
|
|
@@ -116,6 +121,17 @@ export function createRootLayout(cfg: CreateRootLayoutConfig): ComponentType {
|
|
|
116
121
|
platform.isServer && rootLoaderData?.cookieHeader
|
|
117
122
|
? new Cookies(rootLoaderData.cookieHeader)
|
|
118
123
|
: undefined;
|
|
124
|
+
// The preset scale's <html> attribute: server-rendered from the request
|
|
125
|
+
// cookie, and set by the blocking head script on cached documents. An SPA
|
|
126
|
+
// route's shell has no such script and its client render re-creates
|
|
127
|
+
// <html> with only the attributes named here, so the client reads the
|
|
128
|
+
// cookie once too; later switches are ThemeProvider's.
|
|
129
|
+
const [clientScale] = useState(() =>
|
|
130
|
+
platform.isServer ? undefined : scaleAttributeFromCookie(new Cookies().get(cookiePreset)),
|
|
131
|
+
);
|
|
132
|
+
const presetScale = ssrCookies
|
|
133
|
+
? scaleAttributeFromCookie(ssrCookies.get(cookiePreset))
|
|
134
|
+
: clientScale;
|
|
119
135
|
|
|
120
136
|
// Use SSR-detected language (from loader) or fall back to i18next's current language
|
|
121
137
|
const htmlLang =
|
|
@@ -141,13 +157,20 @@ export function createRootLayout(cfg: CreateRootLayoutConfig): ComponentType {
|
|
|
141
157
|
const interFonts = cfg.head?.interFonts !== false;
|
|
142
158
|
const interFontCss = [
|
|
143
159
|
'@font-face{font-family:"Inter";font-style:normal;font-weight:400;font-display:optional;src:url("/fonts/inter-400.woff2") format("woff2")}',
|
|
160
|
+
'@font-face{font-family:"Inter";font-style:normal;font-weight:500;font-display:optional;src:url("/fonts/inter-500.woff2") format("woff2")}',
|
|
161
|
+
'@font-face{font-family:"Inter";font-style:normal;font-weight:600;font-display:optional;src:url("/fonts/inter-600.woff2") format("woff2")}',
|
|
144
162
|
'@font-face{font-family:"Inter";font-style:normal;font-weight:700;font-display:optional;src:url("/fonts/inter-700.woff2") format("woff2")}',
|
|
163
|
+
'@font-face{font-family:"Inter";font-style:normal;font-weight:800;font-display:optional;src:url("/fonts/inter-800.woff2") format("woff2")}',
|
|
145
164
|
].join("");
|
|
146
165
|
|
|
147
166
|
return (
|
|
148
|
-
<html lang={htmlLang} suppressHydrationWarning>
|
|
167
|
+
<html lang={htmlLang} data-mp-scale={presetScale} suppressHydrationWarning>
|
|
149
168
|
<head>
|
|
150
169
|
<meta charSet="utf-8" />
|
|
170
|
+
<script
|
|
171
|
+
dangerouslySetInnerHTML={{ __html: scaleAttributeScript }}
|
|
172
|
+
suppressHydrationWarning
|
|
173
|
+
/>
|
|
151
174
|
{/* RUNTIME public config, first thing after charset so it is parsed
|
|
152
175
|
and executed before the deferred app bundle constructs Config.
|
|
153
176
|
Without it the browser has NO path to config at all: Config's env
|
|
@@ -165,6 +188,13 @@ export function createRootLayout(cfg: CreateRootLayoutConfig): ComponentType {
|
|
|
165
188
|
type="font/woff2"
|
|
166
189
|
crossOrigin=""
|
|
167
190
|
/>
|
|
191
|
+
<link
|
|
192
|
+
rel="preload"
|
|
193
|
+
href="/fonts/inter-600.woff2"
|
|
194
|
+
as="font"
|
|
195
|
+
type="font/woff2"
|
|
196
|
+
crossOrigin=""
|
|
197
|
+
/>
|
|
168
198
|
<link
|
|
169
199
|
rel="preload"
|
|
170
200
|
href="/fonts/inter-700.woff2"
|
|
@@ -172,6 +202,13 @@ export function createRootLayout(cfg: CreateRootLayoutConfig): ComponentType {
|
|
|
172
202
|
type="font/woff2"
|
|
173
203
|
crossOrigin=""
|
|
174
204
|
/>
|
|
205
|
+
<link
|
|
206
|
+
rel="preload"
|
|
207
|
+
href="/fonts/inter-800.woff2"
|
|
208
|
+
as="font"
|
|
209
|
+
type="font/woff2"
|
|
210
|
+
crossOrigin=""
|
|
211
|
+
/>
|
|
175
212
|
<style precedence="reset" href="__font_inter">
|
|
176
213
|
{interFontCss}
|
|
177
214
|
</style>
|
|
@@ -189,7 +226,6 @@ export function createRootLayout(cfg: CreateRootLayoutConfig): ComponentType {
|
|
|
189
226
|
"a{color:inherit;text-decoration:none}",
|
|
190
227
|
"h1,h2,h3,h4,h5,h6{margin:0;padding:0}",
|
|
191
228
|
"p,input,textarea,button,ul,ol,li,pre,dialog{all:unset;box-sizing:border-box}",
|
|
192
|
-
"@keyframes skeleton-pulse{0%{opacity:1}50%{opacity:0.4}100%{opacity:1}}",
|
|
193
229
|
].join("")}
|
|
194
230
|
</style>
|
|
195
231
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5" />
|
package/types/app/CreateApp.d.ts
CHANGED
|
@@ -83,6 +83,7 @@ export interface TanstackConfig {
|
|
|
83
83
|
onThemeColorChange?: (color: string) => void;
|
|
84
84
|
}
|
|
85
85
|
export interface KeycloakConfig {
|
|
86
|
+
loadingComponent?: ComponentType;
|
|
86
87
|
/** Force-enable or disable. When omitted, reads KEYCLOAK_ENABLED from env config. */
|
|
87
88
|
enabled?: boolean;
|
|
88
89
|
baseUrl?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateApp.d.ts","sourceRoot":"","sources":["../../src/app/CreateApp.tsx"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"CreateApp.d.ts","sourceRoot":"","sources":["../../src/app/CreateApp.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ComponentType } from "react";
|
|
2
2
|
import type { CreateRootLayoutConfig } from "./rootLayoutShared";
|
|
3
3
|
export type { CreateRootLayoutConfig, HeadConfig, RootLayoutProps, RootLoaderData, SentryConfig, } from "./rootLayoutShared";
|
|
4
4
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateRootLayout.web.d.ts","sourceRoot":"","sources":["../../src/app/CreateRootLayout.web.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"CreateRootLayout.web.d.ts","sourceRoot":"","sources":["../../src/app/CreateRootLayout.web.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,KAAK,aAAa,EAA4B,MAAM,OAAO,CAAC;AAarE,OAAO,KAAK,EAAE,sBAAsB,EAAkB,MAAM,oBAAoB,CAAC;AAEjF,YAAY,EACV,sBAAsB,EACtB,UAAU,EACV,eAAe,EACf,cAAc,EACd,YAAY,GACb,MAAM,oBAAoB,CAAC;AAE5B;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,sBAAsB,GAAG,aAAa,CAoN3E"}
|