keycloakify 10.0.0-rc.77 → 10.0.0-rc.78

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.
Files changed (62) hide show
  1. package/account/i18n/i18n.d.ts +4 -4
  2. package/account/i18n/i18n.js +12 -34
  3. package/account/i18n/i18n.js.map +1 -1
  4. package/account/i18n/index.d.ts +1 -1
  5. package/account/i18n/index.js +1 -1
  6. package/account/i18n/index.js.map +1 -1
  7. package/account/i18n/useI18n.d.ts +13 -0
  8. package/account/i18n/useI18n.js +26 -0
  9. package/account/i18n/useI18n.js.map +1 -0
  10. package/bin/440.index.js +15 -19
  11. package/bin/751.index.js +0 -2
  12. package/bin/shared/constants.d.ts +0 -1
  13. package/bin/shared/constants.js +0 -1
  14. package/bin/shared/constants.js.map +1 -1
  15. package/login/KcContext/KcContext.d.ts +5 -1
  16. package/login/KcContext/KcContext.js +0 -1
  17. package/login/KcContext/KcContext.js.map +1 -1
  18. package/login/KcContext/kcContextMocks.js +4 -1
  19. package/login/KcContext/kcContextMocks.js.map +1 -1
  20. package/login/i18n/i18n.d.ts +7 -4
  21. package/login/i18n/i18n.js +23 -38
  22. package/login/i18n/i18n.js.map +1 -1
  23. package/login/i18n/index.d.ts +1 -1
  24. package/login/i18n/index.js +1 -1
  25. package/login/i18n/index.js.map +1 -1
  26. package/login/i18n/useI18n.d.ts +13 -0
  27. package/login/i18n/useI18n.js +26 -0
  28. package/login/i18n/useI18n.js.map +1 -0
  29. package/login/lib/useDownloadTerms.d.ts +5 -4
  30. package/login/lib/useDownloadTerms.js +26 -5
  31. package/login/lib/useDownloadTerms.js.map +1 -1
  32. package/login/pages/Register.js +7 -6
  33. package/login/pages/Register.js.map +1 -1
  34. package/login/pages/Terms.d.ts +1 -1
  35. package/login/pages/Terms.js +6 -4
  36. package/login/pages/Terms.js.map +1 -1
  37. package/package.json +15 -7
  38. package/src/account/i18n/i18n.tsx +19 -53
  39. package/src/account/i18n/index.ts +1 -1
  40. package/src/account/i18n/useI18n.ts +44 -0
  41. package/src/bin/keycloakify/generateFtl/generateFtl.ts +1 -6
  42. package/src/bin/keycloakify/generateFtl/kcContextDeclarationTemplate.ftl +8 -1
  43. package/src/bin/keycloakify/generateResources/generateMessageProperties.ts +23 -17
  44. package/src/bin/shared/constants.ts +0 -2
  45. package/src/login/KcContext/KcContext.ts +6 -14
  46. package/src/login/KcContext/kcContextMocks.ts +4 -1
  47. package/src/login/i18n/i18n.tsx +37 -58
  48. package/src/login/i18n/index.ts +1 -1
  49. package/src/login/i18n/useI18n.ts +44 -0
  50. package/src/login/lib/useDownloadTerms.tsx +88 -0
  51. package/src/login/pages/Register.tsx +12 -12
  52. package/src/login/pages/Terms.tsx +12 -11
  53. package/src/tools/react-markdown.ts +3 -0
  54. package/tools/react-markdown.d.ts +3 -0
  55. package/tools/react-markdown.js +4 -0
  56. package/tools/react-markdown.js.map +1 -0
  57. package/vite-plugin/index.js +0 -2
  58. package/src/login/lib/useDownloadTerms.ts +0 -57
  59. package/src/tools/Markdown.ts +0 -3
  60. package/tools/Markdown.d.ts +0 -2
  61. package/tools/Markdown.js +0 -3
  62. package/tools/Markdown.js.map +0 -1
@@ -0,0 +1,44 @@
1
+ import { useEffect, useState } from "react";
2
+ import {
3
+ createGetI18n,
4
+ type GenericI18n,
5
+ type MessageKey,
6
+ type KcContextLike
7
+ } from "./i18n";
8
+ import { Reflect } from "tsafe/Reflect";
9
+
10
+ export function createUseI18n<ExtraMessageKey extends string = never>(extraMessages: {
11
+ [languageTag: string]: { [key in ExtraMessageKey]: string };
12
+ }) {
13
+ type I18n = GenericI18n<MessageKey | ExtraMessageKey>;
14
+
15
+ const { getI18n } = createGetI18n(extraMessages);
16
+
17
+ function useI18n(params: { kcContext: KcContextLike }): { i18n: I18n } {
18
+ const { kcContext } = params;
19
+
20
+ const { i18n, prI18n_currentLanguage } = getI18n({ kcContext });
21
+
22
+ const [i18n_toReturn, setI18n_toReturn] = useState<I18n>(i18n);
23
+
24
+ useEffect(() => {
25
+ let isActive = true;
26
+
27
+ prI18n_currentLanguage?.then(i18n => {
28
+ if (!isActive) {
29
+ return;
30
+ }
31
+
32
+ setI18n_toReturn(i18n);
33
+ });
34
+
35
+ return () => {
36
+ isActive = false;
37
+ };
38
+ }, []);
39
+
40
+ return { i18n: i18n_toReturn };
41
+ }
42
+
43
+ return { useI18n, ofTypeI18n: Reflect<I18n>() };
44
+ }
@@ -0,0 +1,88 @@
1
+ import { useState, useEffect } from "react";
2
+ import { fallbackLanguageTag } from "keycloakify/login/i18n";
3
+ import { assert } from "tsafe/assert";
4
+ import { createStatefulObservable, useRerenderOnChange } from "keycloakify/tools/StatefulObservable";
5
+ import { useOnFistMount } from "keycloakify/tools/useOnFirstMount";
6
+ import { KcContext } from "../KcContext";
7
+ import type { Options as ReactMarkdownOptions } from "../../tools/react-markdown";
8
+
9
+ const obs = createStatefulObservable<
10
+ | {
11
+ ReactMarkdown: (props: Readonly<ReactMarkdownOptions>) => JSX.Element;
12
+ termsMarkdown: string;
13
+ }
14
+ | undefined
15
+ >(() => undefined);
16
+
17
+ export type KcContextLike_useDownloadTerms = {
18
+ pageId: string;
19
+ locale?: {
20
+ currentLanguageTag: string;
21
+ };
22
+ termsAcceptanceRequired?: boolean;
23
+ };
24
+
25
+ assert<KcContext extends KcContextLike_useDownloadTerms ? true : false>();
26
+
27
+ /** Allow to avoid bundling the terms and download it on demand*/
28
+ export function useDownloadTerms(params: {
29
+ kcContext: KcContextLike_useDownloadTerms;
30
+ downloadTermsMarkdown: (params: { currentLanguageTag: string }) => Promise<{ termsMarkdown: string; termsLanguageTag: string | undefined }>;
31
+ }) {
32
+ const { kcContext, downloadTermsMarkdown } = params;
33
+
34
+ useOnFistMount(async () => {
35
+ if (kcContext.pageId === "terms.ftl" || kcContext.termsAcceptanceRequired) {
36
+ const currentLanguageTag = kcContext.locale?.currentLanguageTag ?? fallbackLanguageTag;
37
+
38
+ const [ReactMarkdown_base, { termsMarkdown, termsLanguageTag }] = await Promise.all([
39
+ import("../../tools/react-markdown").then(_ => _.default),
40
+ downloadTermsMarkdown({ currentLanguageTag })
41
+ ] as const);
42
+
43
+ const htmlLang = termsLanguageTag !== currentLanguageTag ? termsLanguageTag : undefined;
44
+
45
+ const ReactMarkdown: (props: Readonly<ReactMarkdownOptions>) => JSX.Element =
46
+ htmlLang === undefined
47
+ ? ReactMarkdown_base
48
+ : props => {
49
+ const [anchor, setAnchor] = useState<HTMLDivElement | null>(null);
50
+
51
+ useEffect(() => {
52
+ if (anchor === null) {
53
+ return;
54
+ }
55
+
56
+ const parent = anchor.parentElement;
57
+
58
+ assert(parent !== null);
59
+
60
+ parent.setAttribute("lang", htmlLang);
61
+
62
+ anchor.remove();
63
+ }, [anchor]);
64
+
65
+ return (
66
+ <>
67
+ <ReactMarkdown_base {...props} />
68
+ <div ref={setAnchor} style={{ display: "none" }} aria-hidden />
69
+ </>
70
+ );
71
+ };
72
+
73
+ obs.current = { ReactMarkdown, termsMarkdown };
74
+ }
75
+ });
76
+ }
77
+
78
+ export function useTermsMarkdown() {
79
+ useRerenderOnChange(obs);
80
+
81
+ if (obs.current === undefined) {
82
+ return { isDownloadComplete: false as const };
83
+ }
84
+
85
+ const { ReactMarkdown, termsMarkdown } = obs.current;
86
+
87
+ return { isDownloadComplete: true, ReactMarkdown, termsMarkdown };
88
+ }
@@ -1,5 +1,4 @@
1
1
  import { useState } from "react";
2
- import { Markdown } from "keycloakify/tools/Markdown";
3
2
  import type { LazyOrNot } from "keycloakify/tools/LazyOrNot";
4
3
  import { useTermsMarkdown } from "keycloakify/login/lib/useDownloadTerms";
5
4
  import { getKcClsx, type KcClsx } from "keycloakify/login/lib/kcClsx";
@@ -78,23 +77,14 @@ export default function Register(props: RegisterProps) {
78
77
  function TermsAcceptance(props: { i18n: I18n; kcClsx: KcClsx; messagesPerField: Pick<KcContext["messagesPerField"], "existsError" | "get"> }) {
79
78
  const { i18n, kcClsx, messagesPerField } = props;
80
79
 
81
- const { msg } = i18n;
82
-
83
- // NOTE: Refer to https://docs.keycloakify.dev/terms-and-conditions to load your terms and conditions.
84
- const { termsMarkdown } = useTermsMarkdown();
85
-
86
- if (termsMarkdown === undefined) {
87
- return null;
88
- }
80
+ const { msg, msgStr } = i18n;
89
81
 
90
82
  return (
91
83
  <>
92
84
  <div className="form-group">
93
85
  <div className={kcClsx("kcInputWrapperClass")}>
94
86
  {msg("termsTitle")}
95
- <div id="kc-registration-terms-text">
96
- <Markdown>{termsMarkdown}</Markdown>
97
- </div>
87
+ <div id="kc-registration-terms-text">{msgStr("termsText") ? msg("termsText") : <TermsMarkdown />}</div>
98
88
  </div>
99
89
  </div>
100
90
  <div className="form-group">
@@ -121,3 +111,13 @@ function TermsAcceptance(props: { i18n: I18n; kcClsx: KcClsx; messagesPerField:
121
111
  </>
122
112
  );
123
113
  }
114
+
115
+ function TermsMarkdown() {
116
+ const { isDownloadComplete, termsMarkdown, ReactMarkdown } = useTermsMarkdown();
117
+
118
+ if (!isDownloadComplete) {
119
+ return null;
120
+ }
121
+
122
+ return <ReactMarkdown>{termsMarkdown}</ReactMarkdown>;
123
+ }
@@ -1,4 +1,3 @@
1
- import { Markdown } from "keycloakify/tools/Markdown";
2
1
  import { getKcClsx } from "keycloakify/login/lib/kcClsx";
3
2
  import { useTermsMarkdown } from "keycloakify/login/lib/useDownloadTerms";
4
3
  import type { PageProps } from "keycloakify/login/pages/PageProps";
@@ -15,13 +14,7 @@ export default function Terms(props: PageProps<Extract<KcContext, { pageId: "ter
15
14
 
16
15
  const { msg, msgStr } = i18n;
17
16
 
18
- const { locale, url } = kcContext;
19
-
20
- const { isDownloadComplete, termsMarkdown, termsLanguageTag } = useTermsMarkdown();
21
-
22
- if (!isDownloadComplete) {
23
- return null;
24
- }
17
+ const { url } = kcContext;
25
18
 
26
19
  return (
27
20
  <Template
@@ -32,9 +25,7 @@ export default function Terms(props: PageProps<Extract<KcContext, { pageId: "ter
32
25
  displayMessage={false}
33
26
  headerNode={msg("termsTitle")}
34
27
  >
35
- <div id="kc-terms-text" lang={termsLanguageTag !== locale?.currentLanguageTag ? termsLanguageTag : undefined}>
36
- <Markdown>{termsMarkdown}</Markdown>
37
- </div>
28
+ <div id="kc-terms-text">{msgStr("termsText") ? msg("termsText") : <TermsMarkdown />}</div>
38
29
  <form className="form-actions" action={url.loginAction} method="POST">
39
30
  <input
40
31
  className={kcClsx("kcButtonClass", "kcButtonClass", "kcButtonClass", "kcButtonPrimaryClass", "kcButtonLargeClass")}
@@ -55,3 +46,13 @@ export default function Terms(props: PageProps<Extract<KcContext, { pageId: "ter
55
46
  </Template>
56
47
  );
57
48
  }
49
+
50
+ function TermsMarkdown() {
51
+ const { isDownloadComplete, termsMarkdown, ReactMarkdown } = useTermsMarkdown();
52
+
53
+ if (!isDownloadComplete) {
54
+ return null;
55
+ }
56
+
57
+ return <ReactMarkdown>{termsMarkdown}</ReactMarkdown>;
58
+ }
@@ -0,0 +1,3 @@
1
+ export * from "react-markdown";
2
+ import Markdown from "react-markdown";
3
+ export default Markdown;
@@ -0,0 +1,3 @@
1
+ export * from "react-markdown";
2
+ import Markdown from "react-markdown";
3
+ export default Markdown;
@@ -0,0 +1,4 @@
1
+ export * from "react-markdown";
2
+ import Markdown from "react-markdown";
3
+ export default Markdown;
4
+ //# sourceMappingURL=react-markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"react-markdown.js","sourceRoot":"","sources":["../src/tools/react-markdown.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,eAAe,QAAQ,CAAC"}
@@ -4569,12 +4569,10 @@ __nccwpck_require__.r(__webpack_exports__);
4569
4569
  /* harmony export */ "keycloak_resources": () => (/* binding */ keycloak_resources),
4570
4570
  /* harmony export */ "lastKeycloakVersionWithAccountV1": () => (/* binding */ lastKeycloakVersionWithAccountV1),
4571
4571
  /* harmony export */ "loginThemePageIds": () => (/* binding */ loginThemePageIds),
4572
- /* harmony export */ "nameOfTheLocalizationRealmOverridesUserProfileProperty": () => (/* binding */ nameOfTheLocalizationRealmOverridesUserProfileProperty),
4573
4572
  /* harmony export */ "resources_common": () => (/* binding */ resources_common),
4574
4573
  /* harmony export */ "themeTypes": () => (/* binding */ themeTypes),
4575
4574
  /* harmony export */ "vitePluginSubScriptEnvNames": () => (/* binding */ vitePluginSubScriptEnvNames)
4576
4575
  /* harmony export */ });
4577
- const nameOfTheLocalizationRealmOverridesUserProfileProperty = "__localizationRealmOverridesUserProfile";
4578
4576
  const keycloak_resources = "keycloak-resources";
4579
4577
  const resources_common = "resources-common";
4580
4578
  const lastKeycloakVersionWithAccountV1 = "21.1.2";
@@ -1,57 +0,0 @@
1
- import { fallbackLanguageTag } from "keycloakify/login/i18n";
2
- import { assert } from "tsafe/assert";
3
- import {
4
- createStatefulObservable,
5
- useRerenderOnChange
6
- } from "keycloakify/tools/StatefulObservable";
7
- import { useOnFistMount } from "keycloakify/tools/useOnFirstMount";
8
- import { KcContext } from "../KcContext";
9
-
10
- const obs = createStatefulObservable<
11
- | {
12
- termsMarkdown: string;
13
- termsLanguageTag: string | undefined;
14
- }
15
- | undefined
16
- >(() => undefined);
17
-
18
- export type KcContextLike = {
19
- pageId: string;
20
- locale?: {
21
- currentLanguageTag: string;
22
- };
23
- termsAcceptanceRequired?: boolean;
24
- };
25
-
26
- assert<KcContext extends KcContextLike ? true : false>();
27
-
28
- /** Allow to avoid bundling the terms and download it on demand*/
29
- export function useDownloadTerms(params: {
30
- kcContext: KcContextLike;
31
- downloadTermsMarkdown: (params: {
32
- currentLanguageTag: string;
33
- }) => Promise<{ termsMarkdown: string; termsLanguageTag: string | undefined }>;
34
- }) {
35
- const { kcContext, downloadTermsMarkdown } = params;
36
-
37
- useOnFistMount(async () => {
38
- if (kcContext.pageId === "terms.ftl" || kcContext.termsAcceptanceRequired) {
39
- obs.current = await downloadTermsMarkdown({
40
- currentLanguageTag:
41
- kcContext.locale?.currentLanguageTag ?? fallbackLanguageTag
42
- });
43
- }
44
- });
45
- }
46
-
47
- export function useTermsMarkdown() {
48
- useRerenderOnChange(obs);
49
-
50
- if (obs.current === undefined) {
51
- return { isDownloadComplete: false as const };
52
- }
53
-
54
- const { termsMarkdown, termsLanguageTag } = obs.current;
55
-
56
- return { isDownloadComplete: true, termsMarkdown, termsLanguageTag };
57
- }
@@ -1,3 +0,0 @@
1
- import Markdown from "react-markdown";
2
-
3
- export { Markdown };
@@ -1,2 +0,0 @@
1
- import Markdown from "react-markdown";
2
- export { Markdown };
package/tools/Markdown.js DELETED
@@ -1,3 +0,0 @@
1
- import Markdown from "react-markdown";
2
- export { Markdown };
3
- //# sourceMappingURL=Markdown.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Markdown.js","sourceRoot":"","sources":["../src/tools/Markdown.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAEtC,OAAO,EAAE,QAAQ,EAAE,CAAC"}