keycloakify 10.0.0-rc.36 → 10.0.0-rc.38

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 (272) hide show
  1. package/account/Fallback.d.ts +1 -2
  2. package/account/Fallback.js.map +1 -1
  3. package/account/KcContext/KcContext.d.ts +6 -6
  4. package/account/KcContext/getKcContextMock.d.ts +9 -9
  5. package/account/KcContext/getKcContextMock.js +3 -3
  6. package/account/KcContext/getKcContextMock.js.map +1 -1
  7. package/account/Template.d.ts +1 -2
  8. package/account/Template.js +7 -6
  9. package/account/Template.js.map +1 -1
  10. package/account/TemplateProps.d.ts +1 -3
  11. package/account/i18n/i18n.d.ts +9 -4
  12. package/account/i18n/i18n.js +132 -87
  13. package/account/i18n/i18n.js.map +1 -1
  14. package/account/i18n/index.d.ts +9 -2
  15. package/account/i18n/index.js +5 -1
  16. package/account/i18n/index.js.map +1 -1
  17. package/account/index.d.ts +1 -1
  18. package/account/lib/kcClsx.d.ts +9 -0
  19. package/account/lib/{useGetClassName.js → kcClsx.js} +3 -3
  20. package/account/lib/kcClsx.js.map +1 -0
  21. package/account/pages/Account.d.ts +1 -2
  22. package/account/pages/Account.js +9 -7
  23. package/account/pages/Account.js.map +1 -1
  24. package/account/pages/Applications.d.ts +1 -2
  25. package/account/pages/Applications.js +7 -7
  26. package/account/pages/Applications.js.map +1 -1
  27. package/account/pages/FederatedIdentity.d.ts +1 -2
  28. package/account/pages/FederatedIdentity.js +4 -3
  29. package/account/pages/FederatedIdentity.js.map +1 -1
  30. package/account/pages/Log.d.ts +1 -2
  31. package/account/pages/Log.js +6 -5
  32. package/account/pages/Log.js.map +1 -1
  33. package/account/pages/PageProps.d.ts +2 -4
  34. package/account/pages/Password.d.ts +1 -2
  35. package/account/pages/Password.js +10 -9
  36. package/account/pages/Password.js.map +1 -1
  37. package/account/pages/Sessions.d.ts +1 -2
  38. package/account/pages/Sessions.js +6 -6
  39. package/account/pages/Sessions.js.map +1 -1
  40. package/account/pages/Totp.d.ts +1 -2
  41. package/account/pages/Totp.js +6 -5
  42. package/account/pages/Totp.js.map +1 -1
  43. package/bin/{314.index.js → 21.index.js} +162 -4
  44. package/bin/{430.index.js → 214.index.js} +161 -2
  45. package/bin/3.index.js +81 -65
  46. package/bin/526.index.js +3 -2
  47. package/bin/538.index.js +552 -0
  48. package/bin/795.index.js +3 -2
  49. package/bin/{890.index.js → 941.index.js} +2 -159
  50. package/bin/main.js +19 -7
  51. package/lib/getKcClsx.d.ts +11 -0
  52. package/lib/getKcClsx.js +44 -0
  53. package/lib/getKcClsx.js.map +1 -0
  54. package/login/Fallback.d.ts +1 -2
  55. package/login/Fallback.js.map +1 -1
  56. package/login/KcContext/KcContext.d.ts +6 -6
  57. package/login/KcContext/getKcContextMock.d.ts +9 -9
  58. package/login/KcContext/getKcContextMock.js +3 -3
  59. package/login/KcContext/getKcContextMock.js.map +1 -1
  60. package/login/Template.d.ts +1 -2
  61. package/login/Template.js +10 -9
  62. package/login/Template.js.map +1 -1
  63. package/login/TemplateProps.d.ts +1 -3
  64. package/login/UserProfileFormFields.d.ts +5 -5
  65. package/login/UserProfileFormFields.js +35 -34
  66. package/login/UserProfileFormFields.js.map +1 -1
  67. package/login/i18n/i18n.d.ts +9 -4
  68. package/login/i18n/i18n.js +136 -91
  69. package/login/i18n/i18n.js.map +1 -1
  70. package/login/i18n/index.d.ts +9 -2
  71. package/login/i18n/index.js +5 -1
  72. package/login/i18n/index.js.map +1 -1
  73. package/login/index.d.ts +1 -1
  74. package/login/lib/kcClsx.d.ts +9 -0
  75. package/login/lib/{useGetClassName.js → kcClsx.js} +3 -3
  76. package/login/lib/kcClsx.js.map +1 -0
  77. package/login/lib/useUserProfileForm.d.ts +9 -6
  78. package/login/lib/useUserProfileForm.js +7 -5
  79. package/login/lib/useUserProfileForm.js.map +1 -1
  80. package/login/pages/Code.d.ts +1 -2
  81. package/login/pages/Code.js +6 -5
  82. package/login/pages/Code.js.map +1 -1
  83. package/login/pages/DeleteAccountConfirm.d.ts +1 -2
  84. package/login/pages/DeleteAccountConfirm.js +7 -7
  85. package/login/pages/DeleteAccountConfirm.js.map +1 -1
  86. package/login/pages/DeleteCredential.d.ts +1 -2
  87. package/login/pages/DeleteCredential.js +6 -6
  88. package/login/pages/DeleteCredential.js.map +1 -1
  89. package/login/pages/Error.d.ts +1 -2
  90. package/login/pages/Error.js +4 -3
  91. package/login/pages/Error.js.map +1 -1
  92. package/login/pages/FrontchannelLogout.d.ts +1 -2
  93. package/login/pages/FrontchannelLogout.js +4 -3
  94. package/login/pages/FrontchannelLogout.js.map +1 -1
  95. package/login/pages/IdpReviewUserProfile.d.ts +1 -2
  96. package/login/pages/IdpReviewUserProfile.js +6 -6
  97. package/login/pages/IdpReviewUserProfile.js.map +1 -1
  98. package/login/pages/Info.d.ts +1 -2
  99. package/login/pages/Info.js +4 -3
  100. package/login/pages/Info.js.map +1 -1
  101. package/login/pages/Login.d.ts +1 -2
  102. package/login/pages/Login.js +10 -8
  103. package/login/pages/Login.js.map +1 -1
  104. package/login/pages/LoginConfigTotp.d.ts +1 -2
  105. package/login/pages/LoginConfigTotp.js +8 -7
  106. package/login/pages/LoginConfigTotp.js.map +1 -1
  107. package/login/pages/LoginIdpLinkConfirm.d.ts +1 -2
  108. package/login/pages/LoginIdpLinkConfirm.js +6 -6
  109. package/login/pages/LoginIdpLinkConfirm.js.map +1 -1
  110. package/login/pages/LoginIdpLinkEmail.d.ts +1 -2
  111. package/login/pages/LoginIdpLinkEmail.js +4 -3
  112. package/login/pages/LoginIdpLinkEmail.js.map +1 -1
  113. package/login/pages/LoginOauth2DeviceVerifyUserCode.d.ts +1 -2
  114. package/login/pages/LoginOauth2DeviceVerifyUserCode.js +6 -6
  115. package/login/pages/LoginOauth2DeviceVerifyUserCode.js.map +1 -1
  116. package/login/pages/LoginOauthGrant.d.ts +1 -2
  117. package/login/pages/LoginOauthGrant.js +7 -7
  118. package/login/pages/LoginOauthGrant.js.map +1 -1
  119. package/login/pages/LoginOtp.d.ts +1 -2
  120. package/login/pages/LoginOtp.js +6 -6
  121. package/login/pages/LoginOtp.js.map +1 -1
  122. package/login/pages/LoginPageExpired.d.ts +1 -2
  123. package/login/pages/LoginPageExpired.js +4 -3
  124. package/login/pages/LoginPageExpired.js.map +1 -1
  125. package/login/pages/LoginPassword.d.ts +1 -2
  126. package/login/pages/LoginPassword.js +9 -7
  127. package/login/pages/LoginPassword.js.map +1 -1
  128. package/login/pages/LoginRecoveryAuthnCodeConfig.d.ts +1 -2
  129. package/login/pages/LoginRecoveryAuthnCodeConfig.js +9 -7
  130. package/login/pages/LoginRecoveryAuthnCodeConfig.js.map +1 -1
  131. package/login/pages/LoginRecoveryAuthnCodeInput.d.ts +1 -2
  132. package/login/pages/LoginRecoveryAuthnCodeInput.js +6 -6
  133. package/login/pages/LoginRecoveryAuthnCodeInput.js.map +1 -1
  134. package/login/pages/LoginResetOtp.d.ts +1 -2
  135. package/login/pages/LoginResetOtp.js +6 -6
  136. package/login/pages/LoginResetOtp.js.map +1 -1
  137. package/login/pages/LoginResetPassword.d.ts +1 -2
  138. package/login/pages/LoginResetPassword.js +7 -7
  139. package/login/pages/LoginResetPassword.js.map +1 -1
  140. package/login/pages/LoginUpdatePassword.d.ts +1 -2
  141. package/login/pages/LoginUpdatePassword.js +10 -9
  142. package/login/pages/LoginUpdatePassword.js.map +1 -1
  143. package/login/pages/LoginUpdateProfile.d.ts +1 -2
  144. package/login/pages/LoginUpdateProfile.js +7 -12
  145. package/login/pages/LoginUpdateProfile.js.map +1 -1
  146. package/login/pages/LoginUsername.d.ts +1 -2
  147. package/login/pages/LoginUsername.js +8 -7
  148. package/login/pages/LoginUsername.js.map +1 -1
  149. package/login/pages/LoginVerifyEmail.d.ts +1 -2
  150. package/login/pages/LoginVerifyEmail.js +4 -3
  151. package/login/pages/LoginVerifyEmail.js.map +1 -1
  152. package/login/pages/LoginX509Info.d.ts +1 -2
  153. package/login/pages/LoginX509Info.js +6 -6
  154. package/login/pages/LoginX509Info.js.map +1 -1
  155. package/login/pages/LogoutConfirm.d.ts +1 -2
  156. package/login/pages/LogoutConfirm.js +6 -6
  157. package/login/pages/LogoutConfirm.js.map +1 -1
  158. package/login/pages/PageProps.d.ts +2 -4
  159. package/login/pages/Register.d.ts +1 -2
  160. package/login/pages/Register.js +8 -16
  161. package/login/pages/Register.js.map +1 -1
  162. package/login/pages/SamlPostForm.d.ts +1 -2
  163. package/login/pages/SamlPostForm.js +4 -3
  164. package/login/pages/SamlPostForm.js.map +1 -1
  165. package/login/pages/SelectAuthenticator.d.ts +1 -2
  166. package/login/pages/SelectAuthenticator.js +6 -9
  167. package/login/pages/SelectAuthenticator.js.map +1 -1
  168. package/login/pages/Terms.d.ts +1 -2
  169. package/login/pages/Terms.js +7 -7
  170. package/login/pages/Terms.js.map +1 -1
  171. package/login/pages/UpdateEmail.d.ts +1 -2
  172. package/login/pages/UpdateEmail.js +8 -12
  173. package/login/pages/UpdateEmail.js.map +1 -1
  174. package/login/pages/WebauthnAuthenticate.d.ts +1 -2
  175. package/login/pages/WebauthnAuthenticate.js +13 -12
  176. package/login/pages/WebauthnAuthenticate.js.map +1 -1
  177. package/login/pages/WebauthnError.d.ts +1 -2
  178. package/login/pages/WebauthnError.js +7 -7
  179. package/login/pages/WebauthnError.js.map +1 -1
  180. package/login/pages/WebauthnRegister.d.ts +1 -2
  181. package/login/pages/WebauthnRegister.js +9 -8
  182. package/login/pages/WebauthnRegister.js.map +1 -1
  183. package/package.json +24 -16
  184. package/src/account/Fallback.tsx +1 -2
  185. package/src/account/KcContext/KcContext.ts +7 -7
  186. package/src/account/KcContext/getKcContextMock.ts +13 -24
  187. package/src/account/Template.tsx +8 -8
  188. package/src/account/TemplateProps.ts +1 -6
  189. package/src/account/i18n/i18n.tsx +204 -125
  190. package/src/account/i18n/index.ts +10 -2
  191. package/src/account/index.ts +1 -1
  192. package/src/account/lib/{useGetClassName.ts → kcClsx.ts} +6 -2
  193. package/src/account/pages/Account.tsx +15 -21
  194. package/src/account/pages/Applications.tsx +8 -9
  195. package/src/account/pages/FederatedIdentity.tsx +5 -5
  196. package/src/account/pages/Log.tsx +8 -8
  197. package/src/account/pages/PageProps.ts +2 -4
  198. package/src/account/pages/Password.tsx +13 -16
  199. package/src/account/pages/Sessions.tsx +9 -10
  200. package/src/account/pages/Totp.tsx +19 -28
  201. package/src/bin/keycloakify/generateSrcMainResources/generateMessageProperties.ts +2 -66
  202. package/src/bin/keycloakify/generateSrcMainResources/generateSrcMainResourcesForMainTheme.ts +7 -1
  203. package/src/bin/main.ts +15 -0
  204. package/src/bin/shared/buildOptions.ts +5 -2
  205. package/src/bin/shared/generateKcGenTs.ts +61 -0
  206. package/src/bin/tools/escapeStringForPropertiesFile.ts +64 -0
  207. package/src/bin/update-kc-gen.ts +13 -0
  208. package/src/lib/getKcClsx.ts +75 -0
  209. package/src/login/Fallback.tsx +1 -2
  210. package/src/login/KcContext/KcContext.ts +7 -7
  211. package/src/login/KcContext/getKcContextMock.ts +13 -24
  212. package/src/login/Template.tsx +36 -37
  213. package/src/login/TemplateProps.ts +1 -6
  214. package/src/login/UserProfileFormFields.tsx +66 -81
  215. package/src/login/i18n/i18n.tsx +208 -129
  216. package/src/login/i18n/index.ts +10 -2
  217. package/src/login/index.ts +1 -1
  218. package/src/login/lib/{useGetClassName.ts → kcClsx.ts} +6 -2
  219. package/src/login/lib/useUserProfileForm.tsx +29 -21
  220. package/src/login/pages/Code.tsx +10 -8
  221. package/src/login/pages/DeleteAccountConfirm.tsx +9 -10
  222. package/src/login/pages/DeleteCredential.tsx +11 -10
  223. package/src/login/pages/Error.tsx +5 -5
  224. package/src/login/pages/FrontchannelLogout.tsx +7 -5
  225. package/src/login/pages/IdpReviewUserProfile.tsx +16 -25
  226. package/src/login/pages/Info.tsx +7 -5
  227. package/src/login/pages/Login.tsx +34 -53
  228. package/src/login/pages/LoginConfigTotp.tsx +30 -38
  229. package/src/login/pages/LoginIdpLinkConfirm.tsx +10 -21
  230. package/src/login/pages/LoginIdpLinkEmail.tsx +5 -5
  231. package/src/login/pages/LoginOauth2DeviceVerifyUserCode.tsx +19 -24
  232. package/src/login/pages/LoginOauthGrant.tsx +14 -21
  233. package/src/login/pages/LoginOtp.tsx +29 -33
  234. package/src/login/pages/LoginPageExpired.tsx +5 -5
  235. package/src/login/pages/LoginPassword.tsx +23 -33
  236. package/src/login/pages/LoginRecoveryAuthnCodeConfig.tsx +21 -25
  237. package/src/login/pages/LoginRecoveryAuthnCodeInput.tsx +21 -25
  238. package/src/login/pages/LoginResetOtp.tsx +21 -25
  239. package/src/login/pages/LoginResetPassword.tsx +21 -25
  240. package/src/login/pages/LoginUpdatePassword.tsx +42 -52
  241. package/src/login/pages/LoginUpdateProfile.tsx +26 -33
  242. package/src/login/pages/LoginUsername.tsx +23 -35
  243. package/src/login/pages/LoginVerifyEmail.tsx +7 -5
  244. package/src/login/pages/LoginX509Info.tsx +27 -36
  245. package/src/login/pages/LogoutConfirm.tsx +11 -17
  246. package/src/login/pages/PageProps.ts +2 -4
  247. package/src/login/pages/Register.tsx +24 -49
  248. package/src/login/pages/SamlPostForm.tsx +5 -5
  249. package/src/login/pages/SelectAuthenticator.tsx +24 -26
  250. package/src/login/pages/Terms.tsx +11 -18
  251. package/src/login/pages/UpdateEmail.tsx +26 -36
  252. package/src/login/pages/WebauthnAuthenticate.tsx +26 -32
  253. package/src/login/pages/WebauthnError.tsx +11 -22
  254. package/src/login/pages/WebauthnRegister.tsx +20 -28
  255. package/src/tools/clsx.ts +6 -48
  256. package/src/tools/clsx_withTransform.ts +55 -0
  257. package/src/vite-plugin/vite-plugin.ts +14 -6
  258. package/tools/clsx.d.ts +3 -2
  259. package/tools/clsx.js +5 -41
  260. package/tools/clsx.js.map +1 -1
  261. package/tools/clsx_withTransform.d.ts +5 -0
  262. package/tools/clsx_withTransform.js +43 -0
  263. package/tools/clsx_withTransform.js.map +1 -0
  264. package/vite-plugin/index.js +167 -37
  265. package/account/lib/useGetClassName.d.ts +0 -7
  266. package/account/lib/useGetClassName.js.map +0 -1
  267. package/lib/useGetClassName.d.ts +0 -10
  268. package/lib/useGetClassName.js +0 -14
  269. package/lib/useGetClassName.js.map +0 -1
  270. package/login/lib/useGetClassName.d.ts +0 -7
  271. package/login/lib/useGetClassName.js.map +0 -1
  272. package/src/lib/useGetClassName.ts +0 -27
@@ -1,24 +1,26 @@
1
1
  import { useState } from "react";
2
2
  import { clsx } from "keycloakify/tools/clsx";
3
- import { useGetClassName } from "keycloakify/account/lib/useGetClassName";
3
+ import { getKcClsx } from "keycloakify/account/lib/kcClsx";
4
4
  import type { PageProps } from "keycloakify/account/pages/PageProps";
5
5
  import type { KcContext } from "../KcContext";
6
- import type { I18n } from "../i18n";
6
+ import { useI18n } from "../i18n";
7
7
 
8
- export default function Password(props: PageProps<Extract<KcContext, { pageId: "password.ftl" }>, I18n>) {
9
- const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
8
+ export default function Password(props: PageProps<Extract<KcContext, { pageId: "password.ftl" }>>) {
9
+ const { kcContext, doUseDefaultCss, Template } = props;
10
10
 
11
- const { getClassName } = useGetClassName({
11
+ const classes = {
12
+ ...props.classes,
13
+ kcBodyClass: clsx(props.classes?.kcBodyClass, "password")
14
+ };
15
+
16
+ const { kcClsx } = getKcClsx({
12
17
  doUseDefaultCss,
13
- classes: {
14
- ...classes,
15
- kcBodyClass: clsx(classes?.kcBodyClass, "password")
16
- }
18
+ classes
17
19
  });
18
20
 
19
21
  const { url, password, account, stateChecker } = kcContext;
20
22
 
21
- const { msgStr, msg } = i18n;
23
+ const { msgStr, msg } = useI18n({ kcContext });
22
24
 
23
25
  const [currentPassword, setCurrentPassword] = useState("");
24
26
  const [newPassword, setNewPassword] = useState("");
@@ -75,7 +77,6 @@ export default function Password(props: PageProps<Extract<KcContext, { pageId: "
75
77
  return kcContext.message;
76
78
  })()
77
79
  },
78
- i18n,
79
80
  doUseDefaultCss,
80
81
  classes
81
82
  }}
@@ -192,11 +193,7 @@ export default function Password(props: PageProps<Extract<KcContext, { pageId: "
192
193
  <button
193
194
  disabled={newPasswordError !== "" || newPasswordConfirmError !== ""}
194
195
  type="submit"
195
- className={clsx(
196
- getClassName("kcButtonClass"),
197
- getClassName("kcButtonPrimaryClass"),
198
- getClassName("kcButtonLargeClass")
199
- )}
196
+ className={kcClsx("kcButtonClass", "kcButtonPrimaryClass", "kcButtonLargeClass")}
200
197
  name="submitAction"
201
198
  value="Save"
202
199
  >
@@ -1,23 +1,22 @@
1
- import { clsx } from "keycloakify/tools/clsx";
2
- import { useGetClassName } from "keycloakify/account/lib/useGetClassName";
1
+ import { getKcClsx } from "keycloakify/account/lib/kcClsx";
3
2
  import type { PageProps } from "keycloakify/account/pages/PageProps";
4
3
  import type { KcContext } from "../KcContext";
5
- import type { I18n } from "../i18n";
4
+ import { useI18n } from "../i18n";
6
5
 
7
- export default function Sessions(props: PageProps<Extract<KcContext, { pageId: "sessions.ftl" }>, I18n>) {
8
- const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
6
+ export default function Sessions(props: PageProps<Extract<KcContext, { pageId: "sessions.ftl" }>>) {
7
+ const { kcContext, doUseDefaultCss, Template, classes } = props;
9
8
 
10
- const { getClassName } = useGetClassName({
9
+ const { kcClsx } = getKcClsx({
11
10
  doUseDefaultCss,
12
11
  classes
13
12
  });
14
13
 
15
14
  const { url, stateChecker, sessions } = kcContext;
16
15
 
17
- const { msg } = i18n;
16
+ const { msg } = useI18n({ kcContext });
18
17
  return (
19
- <Template {...{ kcContext, i18n, doUseDefaultCss, classes }} active="sessions">
20
- <div className={getClassName("kcContentWrapperClass")}>
18
+ <Template {...{ kcContext, doUseDefaultCss, classes }} active="sessions">
19
+ <div className={kcClsx("kcContentWrapperClass")}>
21
20
  <div className="col-md-10">
22
21
  <h2>{msg("sessionsHtmlTitle")}</h2>
23
22
  </div>
@@ -56,7 +55,7 @@ export default function Sessions(props: PageProps<Extract<KcContext, { pageId: "
56
55
 
57
56
  <form action={url.sessionsUrl} method="post">
58
57
  <input type="hidden" id="stateChecker" name="stateChecker" value={stateChecker} />
59
- <button id="logout-all-sessions" type="submit" className={clsx(getClassName("kcButtonDefaultClass"), getClassName("kcButtonClass"))}>
58
+ <button id="logout-all-sessions" type="submit" className={kcClsx("kcButtonDefaultClass", "kcButtonClass")}>
60
59
  {msg("doLogOutAllSessions")}
61
60
  </button>
62
61
  </form>
@@ -1,20 +1,20 @@
1
1
  import { clsx } from "keycloakify/tools/clsx";
2
- import { useGetClassName } from "keycloakify/account/lib/useGetClassName";
2
+ import { getKcClsx } from "keycloakify/account/lib/kcClsx";
3
3
  import type { PageProps } from "keycloakify/account/pages/PageProps";
4
4
  import type { KcContext } from "../KcContext";
5
- import type { I18n } from "../i18n";
5
+ import { useI18n } from "../i18n";
6
6
 
7
- export default function Totp(props: PageProps<Extract<KcContext, { pageId: "totp.ftl" }>, I18n>) {
8
- const { kcContext, i18n, doUseDefaultCss, Template, classes } = props;
7
+ export default function Totp(props: PageProps<Extract<KcContext, { pageId: "totp.ftl" }>>) {
8
+ const { kcContext, doUseDefaultCss, Template, classes } = props;
9
9
 
10
- const { getClassName } = useGetClassName({
10
+ const { kcClsx } = getKcClsx({
11
11
  doUseDefaultCss,
12
12
  classes
13
13
  });
14
14
 
15
15
  const { totp, mode, url, messagesPerField, stateChecker } = kcContext;
16
16
 
17
- const { msg, msgStr, advancedMsg } = i18n;
17
+ const { msg, msgStr, advancedMsg } = useI18n({ kcContext });
18
18
 
19
19
  const algToKeyUriAlg: Record<(typeof kcContext)["totp"]["policy"]["algorithm"], string> = {
20
20
  HmacSHA1: "SHA1",
@@ -23,7 +23,7 @@ export default function Totp(props: PageProps<Extract<KcContext, { pageId: "totp
23
23
  };
24
24
 
25
25
  return (
26
- <Template {...{ kcContext, i18n, doUseDefaultCss, classes }} active="totp">
26
+ <Template {...{ kcContext, doUseDefaultCss, classes }} active="totp">
27
27
  <>
28
28
  <div className="row">
29
29
  <div className="col-md-10">
@@ -140,9 +140,9 @@ export default function Totp(props: PageProps<Extract<KcContext, { pageId: "totp
140
140
  </li>
141
141
  </ol>
142
142
  <hr />
143
- <form action={url.totpUrl} className={getClassName("kcFormClass")} id="kc-totp-settings-form" method="post">
143
+ <form action={url.totpUrl} className={kcClsx("kcFormClass")} id="kc-totp-settings-form" method="post">
144
144
  <input type="hidden" id="stateChecker" name="stateChecker" value={stateChecker} />
145
- <div className={getClassName("kcFormGroupClass")}>
145
+ <div className={kcClsx("kcFormGroupClass")}>
146
146
  <div className="col-sm-2 col-md-2">
147
147
  <label htmlFor="totp" className="control-label">
148
148
  {msg("authenticatorCode")}
@@ -155,12 +155,12 @@ export default function Totp(props: PageProps<Extract<KcContext, { pageId: "totp
155
155
  id="totp"
156
156
  name="totp"
157
157
  autoComplete="off"
158
- className={getClassName("kcInputClass")}
158
+ className={kcClsx("kcInputClass")}
159
159
  aria-invalid={messagesPerField.existsError("totp")}
160
160
  />
161
161
 
162
162
  {messagesPerField.existsError("totp") && (
163
- <span id="input-error-otp-code" className={getClassName("kcInputErrorMessageClass")} aria-live="polite">
163
+ <span id="input-error-otp-code" className={kcClsx("kcInputErrorMessageClass")} aria-live="polite">
164
164
  {messagesPerField.get("totp")}
165
165
  </span>
166
166
  )}
@@ -169,9 +169,9 @@ export default function Totp(props: PageProps<Extract<KcContext, { pageId: "totp
169
169
  {mode && <input type="hidden" id="mode" value={mode} />}
170
170
  </div>
171
171
 
172
- <div className={getClassName("kcFormGroupClass")}>
172
+ <div className={kcClsx("kcFormGroupClass")}>
173
173
  <div className="col-sm-2 col-md-2">
174
- <label htmlFor="userLabel" className={getClassName("kcLabelClass")}>
174
+ <label htmlFor="userLabel" className={kcClsx("kcLabelClass")}>
175
175
  {msg("totpDeviceName")}
176
176
  </label>
177
177
  {totp.otpCredentials.length >= 1 && <span className="required">*</span>}
@@ -182,37 +182,28 @@ export default function Totp(props: PageProps<Extract<KcContext, { pageId: "totp
182
182
  id="userLabel"
183
183
  name="userLabel"
184
184
  autoComplete="off"
185
- className={getClassName("kcInputClass")}
185
+ className={kcClsx("kcInputClass")}
186
186
  aria-invalid={messagesPerField.existsError("userLabel")}
187
187
  />
188
188
  {messagesPerField.existsError("userLabel") && (
189
- <span id="input-error-otp-label" className={getClassName("kcInputErrorMessageClass")} aria-live="polite">
189
+ <span id="input-error-otp-label" className={kcClsx("kcInputErrorMessageClass")} aria-live="polite">
190
190
  {messagesPerField.get("userLabel")}
191
191
  </span>
192
192
  )}
193
193
  </div>
194
194
  </div>
195
195
 
196
- <div id="kc-form-buttons" className={clsx(getClassName("kcFormGroupClass"), "text-right")}>
197
- <div className={getClassName("kcInputWrapperClass")}>
196
+ <div id="kc-form-buttons" className={clsx(kcClsx("kcFormGroupClass"), "text-right")}>
197
+ <div className={kcClsx("kcInputWrapperClass")}>
198
198
  <input
199
199
  type="submit"
200
- className={clsx(
201
- getClassName("kcButtonClass"),
202
- getClassName("kcButtonPrimaryClass"),
203
- getClassName("kcButtonLargeClass")
204
- )}
200
+ className={kcClsx("kcButtonClass", "kcButtonPrimaryClass", "kcButtonLargeClass")}
205
201
  id="saveTOTPBtn"
206
202
  value={msgStr("doSave")}
207
203
  />
208
204
  <button
209
205
  type="submit"
210
- className={clsx(
211
- getClassName("kcButtonClass"),
212
- getClassName("kcButtonDefaultClass"),
213
- getClassName("kcButtonLargeClass"),
214
- getClassName("kcButtonLargeClass")
215
- )}
206
+ className={kcClsx("kcButtonClass", "kcButtonDefaultClass", "kcButtonLargeClass", "kcButtonLargeClass")}
216
207
  id="cancelTOTPBtn"
217
208
  name="submitAction"
218
209
  value="Cancel"
@@ -8,6 +8,7 @@ import * as recast from "recast";
8
8
  import * as babelParser from "@babel/parser";
9
9
  import babelGenerate from "@babel/generator";
10
10
  import * as babelTypes from "@babel/types";
11
+ import { escapeStringForPropertiesFile } from "../../tools/escapeStringForPropertiesFile";
11
12
 
12
13
  export function generateMessageProperties(params: {
13
14
  themeSrcDirPath: string;
@@ -146,7 +147,7 @@ export function generateMessageProperties(params: {
146
147
 
147
148
  for (const [languageTag, keyValueMap] of Object.entries(keyValueMapByLanguageTag)) {
148
149
  const propertiesFileSource = Object.entries(keyValueMap)
149
- .map(([key, value]) => `${key}=${escapeString(value)}`)
150
+ .map(([key, value]) => `${key}=${escapeStringForPropertiesFile(value)}`)
150
151
  .join("\n");
151
152
 
152
153
  out.push({
@@ -164,68 +165,3 @@ export function generateMessageProperties(params: {
164
165
 
165
166
  return out;
166
167
  }
167
-
168
- // Convert a JavaScript string to UTF-16 encoding
169
- function toUTF16(codePoint: number): string {
170
- if (codePoint <= 0xffff) {
171
- // BMP character
172
- return "\\u" + codePoint.toString(16).padStart(4, "0");
173
- } else {
174
- // Non-BMP character
175
- codePoint -= 0x10000;
176
- let highSurrogate = (codePoint >> 10) + 0xd800;
177
- let lowSurrogate = (codePoint % 0x400) + 0xdc00;
178
- return (
179
- "\\u" +
180
- highSurrogate.toString(16).padStart(4, "0") +
181
- "\\u" +
182
- lowSurrogate.toString(16).padStart(4, "0")
183
- );
184
- }
185
- }
186
-
187
- // Escapes special characters for use in a .properties file
188
- function escapeString(str: string): string {
189
- let escapedStr = "";
190
- for (const char of [...str]) {
191
- const codePoint = char.codePointAt(0);
192
- if (!codePoint) continue;
193
-
194
- switch (char) {
195
- case "\n":
196
- escapedStr += "\\n";
197
- break;
198
- case "\r":
199
- escapedStr += "\\r";
200
- break;
201
- case "\t":
202
- escapedStr += "\\t";
203
- break;
204
- case "\\":
205
- escapedStr += "\\\\";
206
- break;
207
- case ":":
208
- escapedStr += "\\:";
209
- break;
210
- case "=":
211
- escapedStr += "\\=";
212
- break;
213
- case "#":
214
- escapedStr += "\\#";
215
- break;
216
- case "!":
217
- escapedStr += "\\!";
218
- break;
219
- case "'":
220
- escapedStr += "''";
221
- break;
222
- default:
223
- if (codePoint > 0x7f) {
224
- escapedStr += toUTF16(codePoint); // Non-ASCII characters
225
- } else {
226
- escapedStr += char; // ASCII character needs no escape
227
- }
228
- }
229
- }
230
- return escapedStr;
231
- }
@@ -38,6 +38,7 @@ import {
38
38
  type MetaInfKeycloakTheme
39
39
  } from "../../shared/metaInfKeycloakThemes";
40
40
  import { objectEntries } from "tsafe/objectEntries";
41
+ import { escapeStringForPropertiesFile } from "../../tools/escapeStringForPropertiesFile";
41
42
 
42
43
  export type BuildOptionsLike = BuildOptionsLike_kcContextExclusionsFtlCode &
43
44
  BuildOptionsLike_downloadKeycloakStaticResources &
@@ -50,6 +51,7 @@ export type BuildOptionsLike = BuildOptionsLike_kcContextExclusionsFtlCode &
50
51
  urlPathname: string | undefined;
51
52
  reactAppRootDirPath: string;
52
53
  keycloakifyBuildDirPath: string;
54
+ environmentVariables: { name: string; default: string }[];
53
55
  };
54
56
 
55
57
  assert<BuildOptions extends BuildOptionsLike ? true : false>();
@@ -261,7 +263,11 @@ export async function generateSrcMainResourcesForMainTheme(params: {
261
263
  }
262
264
  assert<Equals<typeof themeType, never>>(false);
263
265
  })()}`,
264
- ...(buildOptions.extraThemeProperties ?? [])
266
+ ...(buildOptions.extraThemeProperties ?? []),
267
+ buildOptions.environmentVariables.map(
268
+ ({ name, default: defaultValue }) =>
269
+ `${name}=\${env.${name}:${escapeStringForPropertiesFile(defaultValue)}}`
270
+ )
265
271
  ].join("\n\n"),
266
272
  "utf8"
267
273
  )
package/src/bin/main.ts CHANGED
@@ -205,6 +205,21 @@ program
205
205
  }
206
206
  });
207
207
 
208
+ program
209
+ .command({
210
+ name: "update-kc-gen",
211
+ description:
212
+ "(Webpack/Create-React-App only) Create/update the kc.gen.ts file in your project."
213
+ })
214
+ .task({
215
+ skip,
216
+ handler: async cliCommandOptions => {
217
+ const { command } = await import("./update-kc-gen");
218
+
219
+ await command({ cliCommandOptions });
220
+ }
221
+ });
222
+
208
223
  // Fallback to build command if no command is provided
209
224
  {
210
225
  const [, , ...rest] = process.argv;
@@ -31,15 +31,17 @@ export type BuildOptions = {
31
31
  assetsDirPath: string;
32
32
  npmWorkspaceRootDirPath: string;
33
33
  kcContextExclusionsFtlCode: string | undefined;
34
+ environmentVariables: { name: string; default: string }[];
34
35
  };
35
36
 
36
37
  export type UserProvidedBuildOptions = {
38
+ themeName?: string | string[];
39
+ environmentVariables?: { name: string; default: string }[];
37
40
  extraThemeProperties?: string[];
38
41
  artifactId?: string;
39
42
  groupId?: string;
40
43
  loginThemeResourcesFromKeycloakVersion?: string;
41
44
  keycloakifyBuildDirPath?: string;
42
- themeName?: string | string[];
43
45
  kcContextExclusionsFtlCode?: string;
44
46
  };
45
47
 
@@ -305,6 +307,7 @@ export function readBuildOptions(params: {
305
307
  return pathJoin(reactAppBuildDirPath, resolvedViteConfig.assetsDir);
306
308
  })(),
307
309
  npmWorkspaceRootDirPath,
308
- kcContextExclusionsFtlCode: userProvidedBuildOptions.kcContextExclusionsFtlCode
310
+ kcContextExclusionsFtlCode: userProvidedBuildOptions.kcContextExclusionsFtlCode,
311
+ environmentVariables: userProvidedBuildOptions.environmentVariables ?? []
309
312
  };
310
313
  }
@@ -0,0 +1,61 @@
1
+ import { assert } from "tsafe/assert";
2
+ import type { BuildOptions } from "./buildOptions";
3
+ import { getThemeSrcDirPath } from "./getThemeSrcDirPath";
4
+ import * as fs from "fs/promises";
5
+ import { join as pathJoin } from "path";
6
+
7
+ export type BuildOptionsLike = {
8
+ reactAppRootDirPath: string;
9
+ themeNames: string[];
10
+ environmentVariables: { name: string; default: string }[];
11
+ };
12
+
13
+ assert<BuildOptions extends BuildOptionsLike ? true : false>();
14
+
15
+ export async function generateKcGenTs(params: {
16
+ buildOptions: BuildOptionsLike;
17
+ }): Promise<void> {
18
+ const { buildOptions } = params;
19
+
20
+ const { themeSrcDirPath } = getThemeSrcDirPath({
21
+ reactAppRootDirPath: buildOptions.reactAppRootDirPath
22
+ });
23
+
24
+ await fs.writeFile(
25
+ pathJoin(themeSrcDirPath, "kc.gen.ts"),
26
+ Buffer.from(
27
+ [
28
+ `/* prettier-ignore-start */`,
29
+ ``,
30
+ `/* eslint-disable */`,
31
+ ``,
32
+ `// @ts-nocheck`,
33
+ ``,
34
+ `// noinspection JSUnusedGlobalSymbols`,
35
+ ``,
36
+ `// This file is auto-generated by Keycloakify`,
37
+ ``,
38
+ `export type ThemeName = ${buildOptions.themeNames.map(themeName => `"${themeName}"`).join(" | ")};`,
39
+ ``,
40
+ `export const themeNames: ThemeName[] = [${buildOptions.themeNames.map(themeName => `"${themeName}"`).join(", ")}];`,
41
+ ``,
42
+ `export type KcEnvName = ${buildOptions.environmentVariables.length === 0 ? "never" : buildOptions.environmentVariables.map(({ name }) => `"${name}"`).join(" | ")};`,
43
+ ``,
44
+ `export const KcEnvNames: KcEnvName[] = [${buildOptions.environmentVariables.map(({ name }) => `"${name}"`).join(", ")}];`,
45
+ ``,
46
+ `export const kcEnvDefaults: Record<KcEnvName, string> = ${JSON.stringify(
47
+ Object.fromEntries(
48
+ buildOptions.environmentVariables.map(
49
+ ({ name, default: defaultValue }) => [name, defaultValue]
50
+ )
51
+ ),
52
+ null,
53
+ 2
54
+ )};`,
55
+ ``,
56
+ `/* prettier-ignore-end */`
57
+ ].join("\n"),
58
+ "utf8"
59
+ )
60
+ );
61
+ }
@@ -0,0 +1,64 @@
1
+ // Convert a JavaScript string to UTF-16 encoding
2
+ function toUTF16(codePoint: number): string {
3
+ if (codePoint <= 0xffff) {
4
+ // BMP character
5
+ return "\\u" + codePoint.toString(16).padStart(4, "0");
6
+ } else {
7
+ // Non-BMP character
8
+ codePoint -= 0x10000;
9
+ let highSurrogate = (codePoint >> 10) + 0xd800;
10
+ let lowSurrogate = (codePoint % 0x400) + 0xdc00;
11
+ return (
12
+ "\\u" +
13
+ highSurrogate.toString(16).padStart(4, "0") +
14
+ "\\u" +
15
+ lowSurrogate.toString(16).padStart(4, "0")
16
+ );
17
+ }
18
+ }
19
+
20
+ // Escapes special characters for use in a .properties file
21
+ export function escapeStringForPropertiesFile(str: string): string {
22
+ let escapedStr = "";
23
+ for (const char of [...str]) {
24
+ const codePoint = char.codePointAt(0);
25
+ if (!codePoint) continue;
26
+
27
+ switch (char) {
28
+ case "\n":
29
+ escapedStr += "\\n";
30
+ break;
31
+ case "\r":
32
+ escapedStr += "\\r";
33
+ break;
34
+ case "\t":
35
+ escapedStr += "\\t";
36
+ break;
37
+ case "\\":
38
+ escapedStr += "\\\\";
39
+ break;
40
+ case ":":
41
+ escapedStr += "\\:";
42
+ break;
43
+ case "=":
44
+ escapedStr += "\\=";
45
+ break;
46
+ case "#":
47
+ escapedStr += "\\#";
48
+ break;
49
+ case "!":
50
+ escapedStr += "\\!";
51
+ break;
52
+ case "'":
53
+ escapedStr += "''";
54
+ break;
55
+ default:
56
+ if (codePoint > 0x7f) {
57
+ escapedStr += toUTF16(codePoint); // Non-ASCII characters
58
+ } else {
59
+ escapedStr += char; // ASCII character needs no escape
60
+ }
61
+ }
62
+ }
63
+ return escapedStr;
64
+ }
@@ -0,0 +1,13 @@
1
+ import type { CliCommandOptions } from "./main";
2
+ import { readBuildOptions } from "./shared/buildOptions";
3
+ import { generateKcGenTs } from "./shared/generateKcGenTs";
4
+
5
+ export async function command(params: { cliCommandOptions: CliCommandOptions }) {
6
+ const { cliCommandOptions } = params;
7
+
8
+ const buildOptions = readBuildOptions({
9
+ cliCommandOptions
10
+ });
11
+
12
+ await generateKcGenTs({ buildOptions });
13
+ }
@@ -0,0 +1,75 @@
1
+ import type { Param0 } from "tsafe";
2
+ import { type CxArg, clsx_withTransform } from "../tools/clsx_withTransform";
3
+ import { clsx } from "../tools/clsx";
4
+ import { assert } from "tsafe/assert";
5
+ import { is } from "tsafe/is";
6
+
7
+ export function createGetKcClsx<ClassKey extends string>(params: {
8
+ defaultClasses: Record<ClassKey, string | undefined>;
9
+ }) {
10
+ const { defaultClasses } = params;
11
+
12
+ function areSameParams(
13
+ params1: Param0<typeof getKcClsx>,
14
+ params2: Param0<typeof getKcClsx>
15
+ ): boolean {
16
+ if (params1.doUseDefaultCss !== params2.doUseDefaultCss) {
17
+ return false;
18
+ }
19
+
20
+ if (params1.classes === params2.classes) {
21
+ return true;
22
+ }
23
+
24
+ return JSON.stringify(params1.classes) === JSON.stringify(params2.classes);
25
+ }
26
+
27
+ let cache:
28
+ | {
29
+ params: Param0<typeof getKcClsx>;
30
+ result: ReturnType<typeof getKcClsx>;
31
+ }
32
+ | undefined = undefined;
33
+
34
+ function getKcClsx(params: {
35
+ doUseDefaultCss: boolean;
36
+ classes: Partial<Record<ClassKey, string>> | undefined;
37
+ }): { kcClsx: (...args: CxArg<ClassKey>[]) => string } {
38
+ // NOTE: We implement a cache here only so that getClassName can be stable across renders.
39
+ // We don't want to use useConstCallback because we want this to be useable outside of React.
40
+ use_cache: {
41
+ if (cache === undefined) {
42
+ break use_cache;
43
+ }
44
+
45
+ if (!areSameParams(cache.params, params)) {
46
+ break use_cache;
47
+ }
48
+
49
+ return cache.result;
50
+ }
51
+
52
+ const { classes, doUseDefaultCss } = params;
53
+
54
+ function kcClsx(...args: CxArg<ClassKey>[]): string {
55
+ return clsx_withTransform({
56
+ args,
57
+ transform: classKey => {
58
+ assert(is<ClassKey>(classKey));
59
+
60
+ return clsx(
61
+ classKey,
62
+ doUseDefaultCss ? defaultClasses[classKey] : undefined,
63
+ classes?.[classKey]
64
+ );
65
+ }
66
+ });
67
+ }
68
+
69
+ cache = { params, result: { kcClsx } };
70
+
71
+ return { kcClsx };
72
+ }
73
+
74
+ return { getKcClsx };
75
+ }
@@ -3,7 +3,6 @@ import { assert, type Equals } from "tsafe/assert";
3
3
  import type { LazyOrNot } from "keycloakify/tools/LazyOrNot";
4
4
  import type { PageProps } from "keycloakify/login/pages/PageProps";
5
5
  import type { KcContext } from "./KcContext";
6
- import type { I18n } from "./i18n";
7
6
  import type { UserProfileFormFieldsProps } from "keycloakify/login/UserProfileFormFields";
8
7
 
9
8
  const Login = lazy(() => import("keycloakify/login/pages/Login"));
@@ -41,7 +40,7 @@ const LoginResetOtp = lazy(() => import("keycloakify/login/pages/LoginResetOtp")
41
40
  const LoginX509Info = lazy(() => import("keycloakify/login/pages/LoginX509Info"));
42
41
  const WebauthnError = lazy(() => import("keycloakify/login/pages/WebauthnError"));
43
42
 
44
- type FallbackProps = PageProps<KcContext, I18n> & {
43
+ type FallbackProps = PageProps<KcContext> & {
45
44
  UserProfileFormFields: LazyOrNot<(props: UserProfileFormFieldsProps) => JSX.Element>;
46
45
  };
47
46
 
@@ -10,20 +10,20 @@ import type { Equals } from "tsafe";
10
10
  import type { MessageKey } from "../i18n/i18n";
11
11
 
12
12
  export type ExtendKcContext<
13
- KcContextExtraProperties extends { properties?: Record<string, string | undefined> },
14
- KcContextExtraPropertiesPerPage extends Record<string, Record<string, unknown>>
13
+ KcContextExtension extends { properties?: Record<string, string | undefined> },
14
+ KcContextExtensionPerPage extends Record<string, Record<string, unknown>>
15
15
  > = ValueOf<{
16
- [PageId in keyof KcContextExtraPropertiesPerPage | KcContext["pageId"]]: Extract<
16
+ [PageId in keyof KcContextExtensionPerPage | KcContext["pageId"]]: Extract<
17
17
  KcContext,
18
18
  { pageId: PageId }
19
19
  > extends never
20
20
  ? KcContext.Common &
21
- KcContextExtraProperties & {
21
+ KcContextExtension & {
22
22
  pageId: PageId;
23
- } & KcContextExtraPropertiesPerPage[PageId]
23
+ } & KcContextExtensionPerPage[PageId]
24
24
  : Extract<KcContext, { pageId: PageId }> &
25
- KcContextExtraProperties &
26
- KcContextExtraPropertiesPerPage[PageId];
25
+ KcContextExtension &
26
+ KcContextExtensionPerPage[PageId];
27
27
  }>;
28
28
 
29
29
  /** Take theses type definition with a grain of salt.