keycloakify 9.6.6 → 10.0.0-rc.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.
Files changed (424) hide show
  1. package/README.md +1 -1
  2. package/account/Template.js +34 -14
  3. package/account/Template.js.map +1 -1
  4. package/account/i18n/baseMessages/de.d.ts +1 -1
  5. package/account/i18n/baseMessages/de.js +1 -1
  6. package/account/i18n/baseMessages/de.js.map +1 -1
  7. package/account/i18n/baseMessages/en.d.ts +2 -0
  8. package/account/i18n/baseMessages/en.js +2 -0
  9. package/account/i18n/baseMessages/en.js.map +1 -1
  10. package/account/i18n/baseMessages/es.d.ts +230 -0
  11. package/account/i18n/baseMessages/es.js +231 -1
  12. package/account/i18n/baseMessages/es.js.map +1 -1
  13. package/account/i18n/baseMessages/index.d.ts +353 -407
  14. package/account/i18n/baseMessages/index.js +1 -0
  15. package/account/i18n/baseMessages/index.js.map +1 -1
  16. package/account/i18n/baseMessages/pl.d.ts +115 -1
  17. package/account/i18n/baseMessages/pl.js +115 -1
  18. package/account/i18n/baseMessages/pl.js.map +1 -1
  19. package/account/i18n/baseMessages/tr.d.ts +1 -1
  20. package/account/i18n/baseMessages/tr.js +1 -1
  21. package/account/i18n/baseMessages/tr.js.map +1 -1
  22. package/account/i18n/baseMessages/uk.d.ts +337 -0
  23. package/account/i18n/baseMessages/uk.js +342 -0
  24. package/account/i18n/baseMessages/uk.js.map +1 -0
  25. package/account/i18n/baseMessages/zh-CN.d.ts +10 -0
  26. package/account/i18n/baseMessages/zh-CN.js +10 -0
  27. package/account/i18n/baseMessages/zh-CN.js.map +1 -1
  28. package/bin/constants.d.ts +0 -1
  29. package/bin/constants.js +1 -2
  30. package/bin/constants.js.map +1 -1
  31. package/bin/download-builtin-keycloak-theme.js +12 -2
  32. package/bin/download-builtin-keycloak-theme.js.map +1 -1
  33. package/bin/keycloakify/buildJars/buildJar.d.ts +14 -0
  34. package/bin/keycloakify/buildJars/buildJar.js +216 -0
  35. package/bin/keycloakify/buildJars/buildJar.js.map +1 -0
  36. package/bin/keycloakify/buildJars/buildJars.d.ts +10 -0
  37. package/bin/keycloakify/buildJars/buildJars.js +95 -0
  38. package/bin/keycloakify/buildJars/buildJars.js.map +1 -0
  39. package/bin/keycloakify/buildJars/extensionVersions.d.ts +12 -0
  40. package/bin/keycloakify/buildJars/extensionVersions.js +7 -0
  41. package/bin/keycloakify/buildJars/extensionVersions.js.map +1 -0
  42. package/bin/keycloakify/buildJars/generatePom.d.ts +13 -0
  43. package/bin/keycloakify/buildJars/generatePom.js +94 -0
  44. package/bin/keycloakify/buildJars/generatePom.js.map +1 -0
  45. package/bin/keycloakify/buildJars/getKeycloakVersionRangeForJar.d.ts +6 -0
  46. package/bin/keycloakify/buildJars/getKeycloakVersionRangeForJar.js +35 -0
  47. package/bin/keycloakify/buildJars/getKeycloakVersionRangeForJar.js.map +1 -0
  48. package/bin/keycloakify/buildJars/index.d.ts +1 -0
  49. package/bin/keycloakify/buildJars/index.js +18 -0
  50. package/bin/keycloakify/buildJars/index.js.map +1 -0
  51. package/bin/keycloakify/buildOptions/UserProvidedBuildOptions.d.ts +0 -8
  52. package/bin/keycloakify/buildOptions/UserProvidedBuildOptions.js +1 -3
  53. package/bin/keycloakify/buildOptions/UserProvidedBuildOptions.js.map +1 -1
  54. package/bin/keycloakify/buildOptions/buildOptions.d.ts +0 -2
  55. package/bin/keycloakify/buildOptions/buildOptions.js +3 -5
  56. package/bin/keycloakify/buildOptions/buildOptions.js.map +1 -1
  57. package/bin/keycloakify/buildOptions/getNpmWorkspaceRootDirPath.js +1 -1
  58. package/bin/keycloakify/buildOptions/getNpmWorkspaceRootDirPath.js.map +1 -1
  59. package/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +103 -232
  60. package/bin/keycloakify/generateFtl/generateFtl.js +17 -39
  61. package/bin/keycloakify/generateFtl/generateFtl.js.map +1 -1
  62. package/bin/keycloakify/generateFtl/pageId.d.ts +1 -1
  63. package/bin/keycloakify/generateFtl/pageId.js +11 -3
  64. package/bin/keycloakify/generateFtl/pageId.js.map +1 -1
  65. package/bin/keycloakify/generateStartKeycloakTestingContainer.d.ts +0 -1
  66. package/bin/keycloakify/generateStartKeycloakTestingContainer.js +3 -6
  67. package/bin/keycloakify/generateStartKeycloakTestingContainer.js.map +1 -1
  68. package/bin/keycloakify/generateTheme/bringInAccountV1.d.ts +1 -1
  69. package/bin/keycloakify/generateTheme/bringInAccountV1.js +5 -9
  70. package/bin/keycloakify/generateTheme/bringInAccountV1.js.map +1 -1
  71. package/bin/keycloakify/generateTheme/generateSrcMainResources.d.ts +21 -0
  72. package/bin/keycloakify/generateTheme/generateSrcMainResources.js +340 -0
  73. package/bin/keycloakify/generateTheme/generateSrcMainResources.js.map +1 -0
  74. package/bin/keycloakify/generateTheme/generateTheme.d.ts +5 -13
  75. package/bin/keycloakify/generateTheme/generateTheme.js +30 -293
  76. package/bin/keycloakify/generateTheme/generateTheme.js.map +1 -1
  77. package/bin/keycloakify/generateTheme/generateThemeVariants.d.ts +5 -0
  78. package/bin/keycloakify/generateTheme/generateThemeVariants.js +67 -0
  79. package/bin/keycloakify/generateTheme/generateThemeVariants.js.map +1 -0
  80. package/bin/keycloakify/generateTheme/readFieldNameUsage.js +54 -18
  81. package/bin/keycloakify/generateTheme/readFieldNameUsage.js.map +1 -1
  82. package/bin/keycloakify/keycloakify.js +28 -104
  83. package/bin/keycloakify/keycloakify.js.map +1 -1
  84. package/lib/useGetClassName.js +2 -2
  85. package/lib/useGetClassName.js.map +1 -1
  86. package/login/Fallback.d.ts +7 -1
  87. package/login/Fallback.js +32 -8
  88. package/login/Fallback.js.map +1 -1
  89. package/login/Template.js +76 -20
  90. package/login/Template.js.map +1 -1
  91. package/login/TemplateProps.d.ts +4 -2
  92. package/login/UserProfileFormFields.d.ts +22 -0
  93. package/login/UserProfileFormFields.js +327 -0
  94. package/login/UserProfileFormFields.js.map +1 -0
  95. package/login/i18n/baseMessages/ar.d.ts +3 -0
  96. package/login/i18n/baseMessages/ar.js +3 -0
  97. package/login/i18n/baseMessages/ar.js.map +1 -1
  98. package/login/i18n/baseMessages/ca.d.ts +1 -0
  99. package/login/i18n/baseMessages/ca.js +1 -0
  100. package/login/i18n/baseMessages/ca.js.map +1 -1
  101. package/login/i18n/baseMessages/cs.d.ts +3 -0
  102. package/login/i18n/baseMessages/cs.js +3 -0
  103. package/login/i18n/baseMessages/cs.js.map +1 -1
  104. package/login/i18n/baseMessages/da.d.ts +1 -0
  105. package/login/i18n/baseMessages/da.js +1 -0
  106. package/login/i18n/baseMessages/da.js.map +1 -1
  107. package/login/i18n/baseMessages/de.d.ts +1 -0
  108. package/login/i18n/baseMessages/de.js +1 -0
  109. package/login/i18n/baseMessages/de.js.map +1 -1
  110. package/login/i18n/baseMessages/el.d.ts +1 -0
  111. package/login/i18n/baseMessages/el.js +1 -0
  112. package/login/i18n/baseMessages/el.js.map +1 -1
  113. package/login/i18n/baseMessages/en.d.ts +7 -0
  114. package/login/i18n/baseMessages/en.js +23 -16
  115. package/login/i18n/baseMessages/en.js.map +1 -1
  116. package/login/i18n/baseMessages/es.d.ts +239 -0
  117. package/login/i18n/baseMessages/es.js +240 -1
  118. package/login/i18n/baseMessages/es.js.map +1 -1
  119. package/login/i18n/baseMessages/fa.d.ts +1 -0
  120. package/login/i18n/baseMessages/fa.js +1 -0
  121. package/login/i18n/baseMessages/fa.js.map +1 -1
  122. package/login/i18n/baseMessages/fi.d.ts +1 -0
  123. package/login/i18n/baseMessages/fi.js +1 -0
  124. package/login/i18n/baseMessages/fi.js.map +1 -1
  125. package/login/i18n/baseMessages/fr.d.ts +1 -0
  126. package/login/i18n/baseMessages/fr.js +2 -1
  127. package/login/i18n/baseMessages/fr.js.map +1 -1
  128. package/login/i18n/baseMessages/hu.d.ts +1 -0
  129. package/login/i18n/baseMessages/hu.js +1 -0
  130. package/login/i18n/baseMessages/hu.js.map +1 -1
  131. package/login/i18n/baseMessages/index.d.ts +211 -416
  132. package/login/i18n/baseMessages/index.js +1 -0
  133. package/login/i18n/baseMessages/index.js.map +1 -1
  134. package/login/i18n/baseMessages/it.d.ts +1 -0
  135. package/login/i18n/baseMessages/it.js +1 -0
  136. package/login/i18n/baseMessages/it.js.map +1 -1
  137. package/login/i18n/baseMessages/ja.d.ts +1 -0
  138. package/login/i18n/baseMessages/ja.js +1 -0
  139. package/login/i18n/baseMessages/ja.js.map +1 -1
  140. package/login/i18n/baseMessages/lt.d.ts +1 -0
  141. package/login/i18n/baseMessages/lt.js +1 -0
  142. package/login/i18n/baseMessages/lt.js.map +1 -1
  143. package/login/i18n/baseMessages/lv.d.ts +1 -0
  144. package/login/i18n/baseMessages/lv.js +1 -0
  145. package/login/i18n/baseMessages/lv.js.map +1 -1
  146. package/login/i18n/baseMessages/nl.d.ts +1 -0
  147. package/login/i18n/baseMessages/nl.js +1 -0
  148. package/login/i18n/baseMessages/nl.js.map +1 -1
  149. package/login/i18n/baseMessages/no.d.ts +1 -0
  150. package/login/i18n/baseMessages/no.js +1 -0
  151. package/login/i18n/baseMessages/no.js.map +1 -1
  152. package/login/i18n/baseMessages/pl.d.ts +1 -0
  153. package/login/i18n/baseMessages/pl.js +1 -0
  154. package/login/i18n/baseMessages/pl.js.map +1 -1
  155. package/login/i18n/baseMessages/pt-BR.d.ts +1 -0
  156. package/login/i18n/baseMessages/pt-BR.js +1 -0
  157. package/login/i18n/baseMessages/pt-BR.js.map +1 -1
  158. package/login/i18n/baseMessages/ru.d.ts +1 -0
  159. package/login/i18n/baseMessages/ru.js +1 -0
  160. package/login/i18n/baseMessages/ru.js.map +1 -1
  161. package/login/i18n/baseMessages/sk.d.ts +2 -0
  162. package/login/i18n/baseMessages/sk.js +3 -1
  163. package/login/i18n/baseMessages/sk.js.map +1 -1
  164. package/login/i18n/baseMessages/sv.d.ts +1 -0
  165. package/login/i18n/baseMessages/sv.js +1 -0
  166. package/login/i18n/baseMessages/sv.js.map +1 -1
  167. package/login/i18n/baseMessages/th.d.ts +1 -0
  168. package/login/i18n/baseMessages/th.js +1 -0
  169. package/login/i18n/baseMessages/th.js.map +1 -1
  170. package/login/i18n/baseMessages/tr.d.ts +1 -0
  171. package/login/i18n/baseMessages/tr.js +1 -0
  172. package/login/i18n/baseMessages/tr.js.map +1 -1
  173. package/login/i18n/baseMessages/uk.d.ts +433 -0
  174. package/login/i18n/baseMessages/uk.js +438 -0
  175. package/login/i18n/baseMessages/uk.js.map +1 -0
  176. package/login/i18n/baseMessages/zh-CN.d.ts +273 -3
  177. package/login/i18n/baseMessages/zh-CN.js +325 -55
  178. package/login/i18n/baseMessages/zh-CN.js.map +1 -1
  179. package/login/i18n/i18n.d.ts +4 -0
  180. package/login/i18n/i18n.js +6 -2
  181. package/login/i18n/i18n.js.map +1 -1
  182. package/login/kcContext/KcContext.d.ts +181 -105
  183. package/login/kcContext/KcContext.js +1 -1
  184. package/login/kcContext/KcContext.js.map +1 -1
  185. package/login/kcContext/createGetKcContext.js +3 -9
  186. package/login/kcContext/createGetKcContext.js.map +1 -1
  187. package/login/kcContext/kcContextMocks.d.ts +1 -1
  188. package/login/kcContext/kcContextMocks.js +92 -198
  189. package/login/kcContext/kcContextMocks.js.map +1 -1
  190. package/login/lib/useDownloadTerms.d.ts +4 -1
  191. package/login/lib/useDownloadTerms.js +9 -4
  192. package/login/lib/useDownloadTerms.js.map +1 -1
  193. package/login/lib/useGetClassName.js +112 -73
  194. package/login/lib/useGetClassName.js.map +1 -1
  195. package/login/lib/useUserProfileForm.d.ts +74 -0
  196. package/login/lib/useUserProfileForm.js +868 -0
  197. package/login/lib/useUserProfileForm.js.map +1 -0
  198. package/login/pages/{UpdateUserProfile.d.ts → Code.d.ts} +2 -2
  199. package/login/pages/Code.js +13 -0
  200. package/login/pages/Code.js.map +1 -0
  201. package/login/pages/DeleteAccountConfirm.d.ts +7 -0
  202. package/login/pages/DeleteAccountConfirm.js +14 -0
  203. package/login/pages/DeleteAccountConfirm.js.map +1 -0
  204. package/login/pages/{RegisterUserProfile.d.ts → DeleteCredential.d.ts} +2 -2
  205. package/login/pages/DeleteCredential.js +14 -0
  206. package/login/pages/DeleteCredential.js.map +1 -0
  207. package/login/pages/Error.js +2 -2
  208. package/login/pages/Error.js.map +1 -1
  209. package/login/pages/FrontchannelLogout.d.ts +7 -0
  210. package/login/pages/FrontchannelLogout.js +14 -0
  211. package/login/pages/FrontchannelLogout.js.map +1 -0
  212. package/login/pages/IdpReviewUserProfile.d.ts +8 -2
  213. package/login/pages/IdpReviewUserProfile.js +3 -4
  214. package/login/pages/IdpReviewUserProfile.js.map +1 -1
  215. package/login/pages/Info.js +14 -1
  216. package/login/pages/Info.js.map +1 -1
  217. package/login/pages/Login.js +24 -38
  218. package/login/pages/Login.js.map +1 -1
  219. package/login/pages/LoginConfigTotp.js +8 -1
  220. package/login/pages/LoginConfigTotp.js.map +1 -1
  221. package/login/pages/{LoginDeviceVerifyUserCode.d.ts → LoginOauth2DeviceVerifyUserCode.d.ts} +1 -1
  222. package/login/pages/{LoginDeviceVerifyUserCode.js → LoginOauth2DeviceVerifyUserCode.js} +2 -2
  223. package/login/pages/LoginOauth2DeviceVerifyUserCode.js.map +1 -0
  224. package/login/pages/LoginOauthGrant.js +3 -2
  225. package/login/pages/LoginOauthGrant.js.map +1 -1
  226. package/login/pages/LoginOtp.js +4 -6
  227. package/login/pages/LoginOtp.js.map +1 -1
  228. package/login/pages/LoginPageExpired.js +1 -1
  229. package/login/pages/LoginPageExpired.js.map +1 -1
  230. package/login/pages/LoginPassword.d.ts +1 -1
  231. package/login/pages/LoginPassword.js +18 -11
  232. package/login/pages/LoginPassword.js.map +1 -1
  233. package/login/pages/LoginRecoveryAuthnCodeConfig.d.ts +7 -0
  234. package/login/pages/LoginRecoveryAuthnCodeConfig.js +147 -0
  235. package/login/pages/LoginRecoveryAuthnCodeConfig.js.map +1 -0
  236. package/login/pages/LoginRecoveryAuthnCodeInput.d.ts +7 -0
  237. package/login/pages/LoginRecoveryAuthnCodeInput.js +14 -0
  238. package/login/pages/LoginRecoveryAuthnCodeInput.js.map +1 -0
  239. package/login/pages/LoginResetOtp.d.ts +7 -0
  240. package/login/pages/LoginResetOtp.js +15 -0
  241. package/login/pages/LoginResetOtp.js.map +1 -0
  242. package/login/pages/LoginResetPassword.js +4 -3
  243. package/login/pages/LoginResetPassword.js.map +1 -1
  244. package/login/pages/LoginUpdatePassword.js +21 -3
  245. package/login/pages/LoginUpdatePassword.js.map +1 -1
  246. package/login/pages/LoginUpdateProfile.d.ts +8 -2
  247. package/login/pages/LoginUpdateProfile.js +11 -5
  248. package/login/pages/LoginUpdateProfile.js.map +1 -1
  249. package/login/pages/LoginUsername.js +11 -35
  250. package/login/pages/LoginUsername.js.map +1 -1
  251. package/login/pages/LoginVerifyEmail.js +1 -1
  252. package/login/pages/LoginVerifyEmail.js.map +1 -1
  253. package/login/pages/LoginX509Info.d.ts +7 -0
  254. package/login/pages/LoginX509Info.js +14 -0
  255. package/login/pages/LoginX509Info.js.map +1 -0
  256. package/login/pages/LogoutConfirm.js +1 -1
  257. package/login/pages/LogoutConfirm.js.map +1 -1
  258. package/login/pages/Register.d.ts +8 -2
  259. package/login/pages/Register.js +26 -4
  260. package/login/pages/Register.js.map +1 -1
  261. package/login/pages/SamlPostForm.js +1 -1
  262. package/login/pages/SamlPostForm.js.map +1 -1
  263. package/login/pages/SelectAuthenticator.js +5 -21
  264. package/login/pages/SelectAuthenticator.js.map +1 -1
  265. package/login/pages/Terms.js +4 -6
  266. package/login/pages/Terms.js.map +1 -1
  267. package/login/pages/UpdateEmail.d.ts +8 -2
  268. package/login/pages/UpdateEmail.js +16 -5
  269. package/login/pages/UpdateEmail.js.map +1 -1
  270. package/login/pages/WebauthnAuthenticate.js +121 -83
  271. package/login/pages/WebauthnAuthenticate.js.map +1 -1
  272. package/login/pages/WebauthnError.d.ts +7 -0
  273. package/login/pages/WebauthnError.js +21 -0
  274. package/login/pages/WebauthnError.js.map +1 -0
  275. package/login/pages/WebauthnRegister.d.ts +7 -0
  276. package/login/pages/WebauthnRegister.js +193 -0
  277. package/login/pages/WebauthnRegister.js.map +1 -0
  278. package/package.json +138 -43
  279. package/src/account/Template.tsx +41 -14
  280. package/src/account/i18n/baseMessages/de.ts +1 -1
  281. package/src/account/i18n/baseMessages/en.ts +2 -0
  282. package/src/account/i18n/baseMessages/es.ts +231 -1
  283. package/src/account/i18n/baseMessages/index.ts +1 -0
  284. package/src/account/i18n/baseMessages/pl.ts +115 -1
  285. package/src/account/i18n/baseMessages/tr.ts +1 -1
  286. package/src/account/i18n/baseMessages/uk.ts +343 -0
  287. package/src/account/i18n/baseMessages/zh-CN.ts +10 -0
  288. package/src/bin/constants.ts +0 -1
  289. package/src/bin/download-builtin-keycloak-theme.ts +14 -1
  290. package/src/bin/keycloakify/buildJars/buildJar.ts +163 -0
  291. package/src/bin/keycloakify/buildJars/buildJars.ts +62 -0
  292. package/src/bin/keycloakify/buildJars/extensionVersions.ts +16 -0
  293. package/src/bin/keycloakify/buildJars/generatePom.ts +86 -0
  294. package/src/bin/keycloakify/buildJars/getKeycloakVersionRangeForJar.ts +37 -0
  295. package/src/bin/keycloakify/buildJars/index.ts +1 -0
  296. package/src/bin/keycloakify/buildOptions/UserProvidedBuildOptions.ts +1 -5
  297. package/src/bin/keycloakify/buildOptions/buildOptions.ts +1 -5
  298. package/src/bin/keycloakify/buildOptions/getNpmWorkspaceRootDirPath.ts +1 -1
  299. package/src/bin/keycloakify/generateFtl/ftl_object_to_js_code_declaring_an_object.ftl +103 -232
  300. package/src/bin/keycloakify/generateFtl/generateFtl.ts +15 -31
  301. package/src/bin/keycloakify/generateFtl/pageId.ts +11 -3
  302. package/src/bin/keycloakify/generateStartKeycloakTestingContainer.ts +4 -8
  303. package/src/bin/keycloakify/generateTheme/bringInAccountV1.ts +5 -11
  304. package/src/bin/keycloakify/generateTheme/generateSrcMainResources.ts +267 -0
  305. package/src/bin/keycloakify/generateTheme/generateTheme.ts +22 -309
  306. package/src/bin/keycloakify/generateTheme/generateThemeVariants.ts +50 -0
  307. package/src/bin/keycloakify/generateTheme/readFieldNameUsage.ts +33 -8
  308. package/src/bin/keycloakify/keycloakify.ts +23 -56
  309. package/src/lib/useGetClassName.ts +2 -2
  310. package/src/login/Fallback.tsx +39 -9
  311. package/src/login/Template.tsx +160 -61
  312. package/src/login/TemplateProps.ts +113 -63
  313. package/src/login/UserProfileFormFields.tsx +750 -0
  314. package/src/login/i18n/baseMessages/ar.ts +3 -0
  315. package/src/login/i18n/baseMessages/ca.ts +1 -0
  316. package/src/login/i18n/baseMessages/cs.ts +3 -0
  317. package/src/login/i18n/baseMessages/da.ts +1 -0
  318. package/src/login/i18n/baseMessages/de.ts +1 -0
  319. package/src/login/i18n/baseMessages/el.ts +1 -0
  320. package/src/login/i18n/baseMessages/en.ts +23 -16
  321. package/src/login/i18n/baseMessages/es.ts +240 -1
  322. package/src/login/i18n/baseMessages/fa.ts +1 -0
  323. package/src/login/i18n/baseMessages/fi.ts +1 -0
  324. package/src/login/i18n/baseMessages/fr.ts +2 -1
  325. package/src/login/i18n/baseMessages/hu.ts +1 -0
  326. package/src/login/i18n/baseMessages/index.ts +1 -0
  327. package/src/login/i18n/baseMessages/it.ts +1 -0
  328. package/src/login/i18n/baseMessages/ja.ts +1 -0
  329. package/src/login/i18n/baseMessages/lt.ts +1 -0
  330. package/src/login/i18n/baseMessages/lv.ts +1 -0
  331. package/src/login/i18n/baseMessages/nl.ts +1 -0
  332. package/src/login/i18n/baseMessages/no.ts +1 -0
  333. package/src/login/i18n/baseMessages/pl.ts +1 -0
  334. package/src/login/i18n/baseMessages/pt-BR.ts +1 -0
  335. package/src/login/i18n/baseMessages/ru.ts +1 -0
  336. package/src/login/i18n/baseMessages/sk.ts +3 -1
  337. package/src/login/i18n/baseMessages/sv.ts +1 -0
  338. package/src/login/i18n/baseMessages/th.ts +1 -0
  339. package/src/login/i18n/baseMessages/tr.ts +1 -0
  340. package/src/login/i18n/baseMessages/uk.ts +439 -0
  341. package/src/login/i18n/baseMessages/zh-CN.ts +325 -55
  342. package/src/login/i18n/i18n.tsx +6 -2
  343. package/src/login/kcContext/KcContext.ts +216 -103
  344. package/src/login/kcContext/createGetKcContext.ts +11 -19
  345. package/src/login/kcContext/kcContextMocks.ts +165 -226
  346. package/src/login/lib/useDownloadTerms.ts +15 -7
  347. package/src/login/lib/useGetClassName.ts +112 -83
  348. package/src/login/lib/useUserProfileForm.tsx +1227 -0
  349. package/src/login/pages/Code.tsx +35 -0
  350. package/src/login/pages/DeleteAccountConfirm.tsx +53 -0
  351. package/src/login/pages/DeleteCredential.tsx +45 -0
  352. package/src/login/pages/Error.tsx +2 -2
  353. package/src/login/pages/FrontchannelLogout.tsx +41 -0
  354. package/src/login/pages/IdpReviewUserProfile.tsx +15 -5
  355. package/src/login/pages/Info.tsx +29 -19
  356. package/src/login/pages/Login.tsx +156 -117
  357. package/src/login/pages/LoginConfigTotp.tsx +26 -1
  358. package/src/login/pages/{LoginDeviceVerifyUserCode.tsx → LoginOauth2DeviceVerifyUserCode.tsx} +3 -1
  359. package/src/login/pages/LoginOauthGrant.tsx +38 -2
  360. package/src/login/pages/LoginOtp.tsx +73 -65
  361. package/src/login/pages/LoginPageExpired.tsx +1 -1
  362. package/src/login/pages/LoginPassword.tsx +77 -28
  363. package/src/login/pages/LoginRecoveryAuthnCodeConfig.tsx +260 -0
  364. package/src/login/pages/LoginRecoveryAuthnCodeInput.tsx +73 -0
  365. package/src/login/pages/LoginResetOtp.tsx +70 -0
  366. package/src/login/pages/LoginResetPassword.tsx +11 -4
  367. package/src/login/pages/LoginUpdatePassword.tsx +120 -81
  368. package/src/login/pages/LoginUpdateProfile.tsx +41 -115
  369. package/src/login/pages/LoginUsername.tsx +93 -101
  370. package/src/login/pages/LoginVerifyEmail.tsx +14 -8
  371. package/src/login/pages/LoginX509Info.tsx +94 -0
  372. package/src/login/pages/LogoutConfirm.tsx +2 -2
  373. package/src/login/pages/Register.tsx +83 -131
  374. package/src/login/pages/SamlPostForm.tsx +1 -1
  375. package/src/login/pages/SelectAuthenticator.tsx +29 -52
  376. package/src/login/pages/Terms.tsx +4 -7
  377. package/src/login/pages/UpdateEmail.tsx +69 -54
  378. package/src/login/pages/WebauthnAuthenticate.tsx +205 -165
  379. package/src/login/pages/WebauthnError.tsx +66 -0
  380. package/src/login/pages/WebauthnRegister.tsx +285 -0
  381. package/src/tools/formatNumber.ts +48 -0
  382. package/src/tools/useInsertLinkTags.ts +82 -0
  383. package/src/tools/useInsertScriptTags.ts +106 -0
  384. package/src/tools/useSetClassName.ts +21 -0
  385. package/tools/formatNumber.d.ts +1 -0
  386. package/tools/formatNumber.js +37 -0
  387. package/tools/formatNumber.js.map +1 -0
  388. package/tools/useInsertLinkTags.d.ts +7 -0
  389. package/tools/useInsertLinkTags.js +57 -0
  390. package/tools/useInsertLinkTags.js.map +1 -0
  391. package/tools/useInsertScriptTags.d.ts +20 -0
  392. package/tools/useInsertScriptTags.js +75 -0
  393. package/tools/useInsertScriptTags.js.map +1 -0
  394. package/tools/useSetClassName.d.ts +4 -0
  395. package/tools/useSetClassName.js +16 -0
  396. package/tools/useSetClassName.js.map +1 -0
  397. package/vite-plugin/tsconfig.tsbuildinfo +1 -1
  398. package/bin/keycloakify/generatePom.d.ts +0 -12
  399. package/bin/keycloakify/generatePom.js +0 -59
  400. package/bin/keycloakify/generatePom.js.map +0 -1
  401. package/lib/usePrepareTemplate.d.ts +0 -11
  402. package/lib/usePrepareTemplate.js +0 -80
  403. package/lib/usePrepareTemplate.js.map +0 -1
  404. package/login/lib/useFormValidation.d.ts +0 -47
  405. package/login/lib/useFormValidation.js +0 -316
  406. package/login/lib/useFormValidation.js.map +0 -1
  407. package/login/pages/LoginDeviceVerifyUserCode.js.map +0 -1
  408. package/login/pages/RegisterUserProfile.js +0 -18
  409. package/login/pages/RegisterUserProfile.js.map +0 -1
  410. package/login/pages/UpdateUserProfile.js +0 -17
  411. package/login/pages/UpdateUserProfile.js.map +0 -1
  412. package/login/pages/shared/UserProfileFormFields.d.ts +0 -18
  413. package/login/pages/shared/UserProfileFormFields.js +0 -58
  414. package/login/pages/shared/UserProfileFormFields.js.map +0 -1
  415. package/src/bin/keycloakify/generatePom.ts +0 -70
  416. package/src/lib/usePrepareTemplate.ts +0 -113
  417. package/src/login/lib/useFormValidation.tsx +0 -474
  418. package/src/login/pages/RegisterUserProfile.tsx +0 -72
  419. package/src/login/pages/UpdateUserProfile.tsx +0 -82
  420. package/src/login/pages/shared/UserProfileFormFields.tsx +0 -177
  421. package/src/tools/headInsert.ts +0 -73
  422. package/tools/headInsert.d.ts +0 -12
  423. package/tools/headInsert.js +0 -50
  424. package/tools/headInsert.js.map +0 -1
@@ -0,0 +1,750 @@
1
+ import { useEffect, useReducer, Fragment } from "react";
2
+ import type { ClassKey } from "keycloakify/login/TemplateProps";
3
+ import { useUserProfileForm, type KcContextLike, type FormAction, type FormFieldError } from "keycloakify/login/lib/useUserProfileForm";
4
+ import type { Attribute } from "keycloakify/login/kcContext/KcContext";
5
+ import { assert } from "tsafe/assert";
6
+ import type { I18n } from "./i18n";
7
+
8
+ export type UserProfileFormFieldsProps = {
9
+ kcContext: KcContextLike;
10
+ i18n: I18n;
11
+ getClassName: (classKey: ClassKey) => string;
12
+ onIsFormSubmittableValueChange: (isFormSubmittable: boolean) => void;
13
+ BeforeField?: (props: BeforeAfterFieldProps) => JSX.Element | null;
14
+ AfterField?: (props: BeforeAfterFieldProps) => JSX.Element | null;
15
+ };
16
+
17
+ type BeforeAfterFieldProps = {
18
+ attribute: Attribute;
19
+ dispatchFormAction: React.Dispatch<FormAction>;
20
+ displayableErrors: FormFieldError[];
21
+ i18n: I18n;
22
+ valueOrValues: string | string[];
23
+ };
24
+
25
+ // NOTE: Enabled by default but it's a UX best practice to set it to false.
26
+ const doMakeUserConfirmPassword = true;
27
+
28
+ export default function UserProfileFormFields(props: UserProfileFormFieldsProps) {
29
+ const { kcContext, onIsFormSubmittableValueChange, i18n, getClassName, BeforeField, AfterField } = props;
30
+
31
+ const { advancedMsg } = i18n;
32
+
33
+ const {
34
+ formState: { formFieldStates, isFormSubmittable },
35
+ dispatchFormAction
36
+ } = useUserProfileForm({
37
+ kcContext,
38
+ i18n,
39
+ doMakeUserConfirmPassword
40
+ });
41
+
42
+ useEffect(() => {
43
+ onIsFormSubmittableValueChange(isFormSubmittable);
44
+ }, [isFormSubmittable]);
45
+
46
+ const groupNameRef = { "current": "" };
47
+
48
+ return (
49
+ <>
50
+ {formFieldStates.map(({ attribute, displayableErrors, valueOrValues }) => {
51
+ return (
52
+ <Fragment key={attribute.name}>
53
+ <GroupLabel attribute={attribute} getClassName={getClassName} i18n={i18n} groupNameRef={groupNameRef} />
54
+ {BeforeField !== undefined && (
55
+ <BeforeField
56
+ attribute={attribute}
57
+ dispatchFormAction={dispatchFormAction}
58
+ displayableErrors={displayableErrors}
59
+ i18n={i18n}
60
+ valueOrValues={valueOrValues}
61
+ />
62
+ )}
63
+ <div
64
+ className={getClassName("kcFormGroupClass")}
65
+ style={{ "display": attribute.name === "password-confirm" && !doMakeUserConfirmPassword ? "none" : undefined }}
66
+ >
67
+ <div className={getClassName("kcLabelWrapperClass")}>
68
+ <label htmlFor={attribute.name} className={getClassName("kcLabelClass")}>
69
+ {advancedMsg(attribute.displayName ?? "")}
70
+ </label>
71
+ {attribute.required && <>*</>}
72
+ </div>
73
+ <div className={getClassName("kcInputWrapperClass")}>
74
+ {attribute.annotations.inputHelperTextBefore !== undefined && (
75
+ <div
76
+ className={getClassName("kcInputHelperTextBeforeClass")}
77
+ id={`form-help-text-before-${attribute.name}`}
78
+ aria-live="polite"
79
+ >
80
+ {advancedMsg(attribute.annotations.inputHelperTextBefore)}
81
+ </div>
82
+ )}
83
+ <InputFiledByType
84
+ attribute={attribute}
85
+ valueOrValues={valueOrValues}
86
+ displayableErrors={displayableErrors}
87
+ formValidationDispatch={dispatchFormAction}
88
+ getClassName={getClassName}
89
+ i18n={i18n}
90
+ />
91
+ <FieldErrors
92
+ attribute={attribute}
93
+ getClassName={getClassName}
94
+ displayableErrors={displayableErrors}
95
+ fieldIndex={undefined}
96
+ />
97
+ {attribute.annotations.inputHelperTextAfter !== undefined && (
98
+ <div
99
+ className={getClassName("kcInputHelperTextAfterClass")}
100
+ id={`form-help-text-after-${attribute.name}`}
101
+ aria-live="polite"
102
+ >
103
+ {advancedMsg(attribute.annotations.inputHelperTextAfter)}
104
+ </div>
105
+ )}
106
+
107
+ {AfterField !== undefined && (
108
+ <AfterField
109
+ attribute={attribute}
110
+ dispatchFormAction={dispatchFormAction}
111
+ displayableErrors={displayableErrors}
112
+ i18n={i18n}
113
+ valueOrValues={valueOrValues}
114
+ />
115
+ )}
116
+ {/* NOTE: Downloading of html5DataAnnotations scripts is done in the useUserProfileForm hook */}
117
+ </div>
118
+ </div>
119
+ </Fragment>
120
+ );
121
+ })}
122
+ </>
123
+ );
124
+ }
125
+
126
+ function GroupLabel(props: {
127
+ attribute: Attribute;
128
+ getClassName: UserProfileFormFieldsProps["getClassName"];
129
+ i18n: I18n;
130
+ groupNameRef: {
131
+ current: string;
132
+ };
133
+ }) {
134
+ const { attribute, getClassName, i18n, groupNameRef } = props;
135
+
136
+ const { advancedMsg } = i18n;
137
+
138
+ if (attribute.group?.name !== groupNameRef.current) {
139
+ groupNameRef.current = attribute.group?.name ?? "";
140
+
141
+ if (groupNameRef.current !== "") {
142
+ assert(attribute.group !== undefined);
143
+
144
+ return (
145
+ <div
146
+ className={getClassName("kcFormGroupClass")}
147
+ {...Object.fromEntries(Object.entries(attribute.group.html5DataAnnotations).map(([key, value]) => [`data-${key}`, value]))}
148
+ >
149
+ {(() => {
150
+ const groupDisplayHeader = attribute.group.displayHeader ?? "";
151
+ const groupHeaderText = groupDisplayHeader !== "" ? advancedMsg(groupDisplayHeader) : attribute.group.name;
152
+
153
+ return (
154
+ <div className={getClassName("kcContentWrapperClass")}>
155
+ <label id={`header-${attribute.group.name}`} className={getClassName("kcFormGroupHeader")}>
156
+ {groupHeaderText}
157
+ </label>
158
+ </div>
159
+ );
160
+ })()}
161
+ {(() => {
162
+ const groupDisplayDescription = attribute.group.displayDescription ?? "";
163
+
164
+ if (groupDisplayDescription !== "") {
165
+ const groupDescriptionText = advancedMsg(groupDisplayDescription);
166
+
167
+ return (
168
+ <div className={getClassName("kcLabelWrapperClass")}>
169
+ <label id={`description-${attribute.group.name}`} className={getClassName("kcLabelClass")}>
170
+ {groupDescriptionText}
171
+ </label>
172
+ </div>
173
+ );
174
+ }
175
+
176
+ return null;
177
+ })()}
178
+ </div>
179
+ );
180
+ }
181
+ }
182
+
183
+ return null;
184
+ }
185
+
186
+ function FieldErrors(props: {
187
+ attribute: Attribute;
188
+ getClassName: UserProfileFormFieldsProps["getClassName"];
189
+ displayableErrors: FormFieldError[];
190
+ fieldIndex: number | undefined;
191
+ }) {
192
+ const { attribute, getClassName, fieldIndex } = props;
193
+
194
+ const displayableErrors = props.displayableErrors.filter(error => error.fieldIndex === fieldIndex);
195
+
196
+ if (displayableErrors.length === 0) {
197
+ return null;
198
+ }
199
+
200
+ return (
201
+ <span
202
+ id={`input-error-${attribute.name}${fieldIndex === undefined ? "" : `-${fieldIndex}`}`}
203
+ className={getClassName("kcInputErrorMessageClass")}
204
+ style={{
205
+ "position": displayableErrors.length === 1 ? "absolute" : undefined
206
+ }}
207
+ aria-live="polite"
208
+ >
209
+ {displayableErrors
210
+ .filter(error => error.fieldIndex === fieldIndex)
211
+ .map(({ errorMessage }, i, arr) => (
212
+ <>
213
+ <span key={i}>{errorMessage}</span>
214
+ {arr.length - 1 !== i && <br />}
215
+ </>
216
+ ))}
217
+ </span>
218
+ );
219
+ }
220
+
221
+ type InputFiledByTypeProps = {
222
+ attribute: Attribute;
223
+ valueOrValues: string | string[];
224
+ displayableErrors: FormFieldError[];
225
+ formValidationDispatch: React.Dispatch<FormAction>;
226
+ getClassName: UserProfileFormFieldsProps["getClassName"];
227
+ i18n: I18n;
228
+ };
229
+
230
+ function InputFiledByType(props: InputFiledByTypeProps) {
231
+ const { attribute, valueOrValues } = props;
232
+
233
+ switch (attribute.annotations.inputType) {
234
+ case "textarea":
235
+ return <TextareaTag {...props} />;
236
+ case "select":
237
+ case "multiselect":
238
+ return <SelectTag {...props} />;
239
+ case "select-radiobuttons":
240
+ case "multiselect-checkboxes":
241
+ return <InputTagSelects {...props} />;
242
+ default: {
243
+ if (valueOrValues instanceof Array) {
244
+ return (
245
+ <>
246
+ {valueOrValues.map((...[, i]) => (
247
+ <InputTag key={i} {...props} fieldIndex={i} />
248
+ ))}
249
+ </>
250
+ );
251
+ }
252
+
253
+ const inputNode = <InputTag {...props} fieldIndex={undefined} />;
254
+
255
+ if (attribute.name === "password" || attribute.name === "password-confirm") {
256
+ return (
257
+ <PasswordWrapper getClassName={props.getClassName} i18n={props.i18n} passwordInputId={attribute.name}>
258
+ {inputNode}
259
+ </PasswordWrapper>
260
+ );
261
+ }
262
+
263
+ return inputNode;
264
+ }
265
+ }
266
+ }
267
+
268
+ function PasswordWrapper(props: { getClassName: (classKey: ClassKey) => string; i18n: I18n; passwordInputId: string; children: JSX.Element }) {
269
+ const { getClassName, i18n, passwordInputId, children } = props;
270
+
271
+ const { msgStr } = i18n;
272
+
273
+ const [isPasswordRevealed, toggleIsPasswordRevealed] = useReducer((isPasswordRevealed: boolean) => !isPasswordRevealed, false);
274
+
275
+ useEffect(() => {
276
+ const passwordInputElement = document.getElementById(passwordInputId);
277
+
278
+ assert(passwordInputElement instanceof HTMLInputElement);
279
+
280
+ passwordInputElement.type = isPasswordRevealed ? "text" : "password";
281
+ }, [isPasswordRevealed]);
282
+
283
+ return (
284
+ <div className={getClassName("kcInputGroup")}>
285
+ {children}
286
+ <button
287
+ type="button"
288
+ className={getClassName("kcFormPasswordVisibilityButtonClass")}
289
+ aria-label={msgStr(isPasswordRevealed ? "hidePassword" : "showPassword")}
290
+ aria-controls={passwordInputId}
291
+ onClick={toggleIsPasswordRevealed}
292
+ >
293
+ <i
294
+ className={getClassName(isPasswordRevealed ? "kcFormPasswordVisibilityIconHide" : "kcFormPasswordVisibilityIconShow")}
295
+ aria-hidden
296
+ />
297
+ </button>
298
+ </div>
299
+ );
300
+ }
301
+
302
+ function InputTag(props: InputFiledByTypeProps & { fieldIndex: number | undefined }) {
303
+ const { attribute, fieldIndex, getClassName, formValidationDispatch, valueOrValues, i18n, displayableErrors } = props;
304
+
305
+ return (
306
+ <>
307
+ <input
308
+ type={(() => {
309
+ const { inputType } = attribute.annotations;
310
+
311
+ if (inputType?.startsWith("html5-")) {
312
+ return inputType.slice(6);
313
+ }
314
+
315
+ return inputType ?? "text";
316
+ })()}
317
+ id={attribute.name}
318
+ name={attribute.name}
319
+ value={(() => {
320
+ if (fieldIndex !== undefined) {
321
+ assert(valueOrValues instanceof Array);
322
+ return valueOrValues[fieldIndex];
323
+ }
324
+
325
+ assert(typeof valueOrValues === "string");
326
+
327
+ return valueOrValues;
328
+ })()}
329
+ className={getClassName("kcInputClass")}
330
+ aria-invalid={displayableErrors.find(error => error.fieldIndex === fieldIndex) !== undefined}
331
+ disabled={attribute.readOnly}
332
+ autoComplete={attribute.autocomplete}
333
+ placeholder={attribute.annotations.inputTypePlaceholder}
334
+ pattern={attribute.annotations.inputTypePattern}
335
+ size={attribute.annotations.inputTypeSize === undefined ? undefined : parseInt(`${attribute.annotations.inputTypeSize}`)}
336
+ maxLength={
337
+ attribute.annotations.inputTypeMaxlength === undefined ? undefined : parseInt(`${attribute.annotations.inputTypeMaxlength}`)
338
+ }
339
+ minLength={
340
+ attribute.annotations.inputTypeMinlength === undefined ? undefined : parseInt(`${attribute.annotations.inputTypeMinlength}`)
341
+ }
342
+ max={attribute.annotations.inputTypeMax}
343
+ min={attribute.annotations.inputTypeMin}
344
+ step={attribute.annotations.inputTypeStep}
345
+ {...Object.fromEntries(Object.entries(attribute.html5DataAnnotations ?? {}).map(([key, value]) => [`data-${key}`, value]))}
346
+ onChange={event =>
347
+ formValidationDispatch({
348
+ "action": "update",
349
+ "name": attribute.name,
350
+ "valueOrValues": (() => {
351
+ if (fieldIndex !== undefined) {
352
+ assert(valueOrValues instanceof Array);
353
+
354
+ return valueOrValues.map((value, i) => {
355
+ if (i === fieldIndex) {
356
+ return event.target.value;
357
+ }
358
+
359
+ return value;
360
+ });
361
+ }
362
+
363
+ return event.target.value;
364
+ })()
365
+ })
366
+ }
367
+ onBlur={() =>
368
+ props.formValidationDispatch({
369
+ "action": "focus lost",
370
+ "name": attribute.name,
371
+ "fieldIndex": fieldIndex
372
+ })
373
+ }
374
+ />
375
+ {(() => {
376
+ if (fieldIndex === undefined) {
377
+ return null;
378
+ }
379
+
380
+ assert(valueOrValues instanceof Array);
381
+
382
+ const values = valueOrValues;
383
+
384
+ return (
385
+ <>
386
+ <FieldErrors
387
+ attribute={attribute}
388
+ getClassName={getClassName}
389
+ displayableErrors={displayableErrors}
390
+ fieldIndex={fieldIndex}
391
+ />
392
+ <AddRemoveButtonsMultiValuedAttribute
393
+ attribute={attribute}
394
+ values={values}
395
+ fieldIndex={fieldIndex}
396
+ dispatchFormAction={formValidationDispatch}
397
+ i18n={i18n}
398
+ />
399
+ </>
400
+ );
401
+ })()}
402
+ </>
403
+ );
404
+ }
405
+
406
+ function AddRemoveButtonsMultiValuedAttribute(props: {
407
+ attribute: Attribute;
408
+ values: string[];
409
+ fieldIndex: number;
410
+ dispatchFormAction: React.Dispatch<Extract<FormAction, { action: "update" }>>;
411
+ i18n: I18n;
412
+ }) {
413
+ const { attribute, values, fieldIndex, dispatchFormAction, i18n } = props;
414
+
415
+ const { msg } = i18n;
416
+
417
+ const hasRemove = (() => {
418
+ if (values.length === 1) {
419
+ return false;
420
+ }
421
+
422
+ const minCount = (() => {
423
+ const { multivalued } = attribute.validators;
424
+
425
+ if (multivalued === undefined) {
426
+ return undefined;
427
+ }
428
+
429
+ const minStr = multivalued.min;
430
+
431
+ if (minStr === undefined) {
432
+ return undefined;
433
+ }
434
+
435
+ return parseInt(`${minStr}`);
436
+ })();
437
+
438
+ if (minCount === undefined) {
439
+ return true;
440
+ }
441
+
442
+ if (values.length === minCount) {
443
+ return false;
444
+ }
445
+
446
+ return true;
447
+ })();
448
+
449
+ const hasAdd = (() => {
450
+ if (fieldIndex + 1 !== values.length) {
451
+ return false;
452
+ }
453
+
454
+ const maxCount = (() => {
455
+ const { multivalued } = attribute.validators;
456
+
457
+ if (multivalued === undefined) {
458
+ return undefined;
459
+ }
460
+
461
+ const maxStr = multivalued.max;
462
+
463
+ if (maxStr === undefined) {
464
+ return undefined;
465
+ }
466
+
467
+ return parseInt(`${maxStr}`);
468
+ })();
469
+
470
+ if (maxCount === undefined) {
471
+ return false;
472
+ }
473
+
474
+ if (values.length === maxCount) {
475
+ return false;
476
+ }
477
+
478
+ return true;
479
+ })();
480
+
481
+ return (
482
+ <>
483
+ {hasRemove && (
484
+ <button
485
+ id={`kc-remove-${attribute.name}-${fieldIndex + 1}`}
486
+ type="button"
487
+ className="pf-c-button pf-m-inline pf-m-link"
488
+ onClick={() =>
489
+ dispatchFormAction({
490
+ "action": "update",
491
+ "name": attribute.name,
492
+ "valueOrValues": values.filter((_, i) => i !== fieldIndex)
493
+ })
494
+ }
495
+ >
496
+ {msg("remove")}
497
+ {hasRemove ? <>&nbsp;|&nbsp;</> : null}
498
+ </button>
499
+ )}
500
+ {hasAdd && (
501
+ <button
502
+ id="kc-add-titles-1"
503
+ type="button"
504
+ className="pf-c-button pf-m-inline pf-m-link"
505
+ onClick={() =>
506
+ dispatchFormAction({
507
+ "action": "update",
508
+ "name": attribute.name,
509
+ "valueOrValues": [...values, ""]
510
+ })
511
+ }
512
+ >
513
+ {msg("addValue")}
514
+ </button>
515
+ )}
516
+ </>
517
+ );
518
+ }
519
+
520
+ function InputTagSelects(props: InputFiledByTypeProps) {
521
+ const { attribute, formValidationDispatch, getClassName, valueOrValues } = props;
522
+
523
+ const { advancedMsg } = props.i18n;
524
+
525
+ const { classDiv, classInput, classLabel, inputType } = (() => {
526
+ const { inputType } = attribute.annotations;
527
+
528
+ assert(inputType === "select-radiobuttons" || inputType === "multiselect-checkboxes");
529
+
530
+ switch (inputType) {
531
+ case "select-radiobuttons":
532
+ return {
533
+ "inputType": "radio",
534
+ "classDiv": getClassName("kcInputClassRadio"),
535
+ "classInput": getClassName("kcInputClassRadioInput"),
536
+ "classLabel": getClassName("kcInputClassRadioLabel")
537
+ };
538
+ case "multiselect-checkboxes":
539
+ return {
540
+ "inputType": "checkbox",
541
+ "classDiv": getClassName("kcInputClassCheckbox"),
542
+ "classInput": getClassName("kcInputClassCheckboxInput"),
543
+ "classLabel": getClassName("kcInputClassCheckboxLabel")
544
+ };
545
+ }
546
+ })();
547
+
548
+ const options = (() => {
549
+ walk: {
550
+ const { inputOptionsFromValidation } = attribute.annotations;
551
+
552
+ if (inputOptionsFromValidation === undefined) {
553
+ break walk;
554
+ }
555
+
556
+ const validator = (attribute.validators as Record<string, { options?: string[] }>)[inputOptionsFromValidation];
557
+
558
+ if (validator === undefined) {
559
+ break walk;
560
+ }
561
+
562
+ if (validator.options === undefined) {
563
+ break walk;
564
+ }
565
+
566
+ return validator.options;
567
+ }
568
+
569
+ return attribute.validators.options?.options ?? [];
570
+ })();
571
+
572
+ return (
573
+ <>
574
+ {options.map(option => (
575
+ <div key={option} className={classDiv}>
576
+ <input
577
+ type={inputType}
578
+ id={`${attribute.name}-${option}`}
579
+ name={attribute.name}
580
+ value={option}
581
+ className={classInput}
582
+ aria-invalid={props.displayableErrors.length !== 0}
583
+ disabled={attribute.readOnly}
584
+ checked={valueOrValues.includes(option)}
585
+ onChange={event =>
586
+ formValidationDispatch({
587
+ "action": "update",
588
+ "name": attribute.name,
589
+ "valueOrValues": (() => {
590
+ const isChecked = event.target.checked;
591
+
592
+ if (valueOrValues instanceof Array) {
593
+ const newValues = [...valueOrValues];
594
+
595
+ if (isChecked) {
596
+ newValues.push(option);
597
+ } else {
598
+ newValues.splice(newValues.indexOf(option), 1);
599
+ }
600
+
601
+ return newValues;
602
+ }
603
+
604
+ return event.target.checked ? option : "";
605
+ })()
606
+ })
607
+ }
608
+ onBlur={() =>
609
+ formValidationDispatch({
610
+ "action": "focus lost",
611
+ "name": attribute.name,
612
+ "fieldIndex": undefined
613
+ })
614
+ }
615
+ />
616
+ <label
617
+ htmlFor={`${attribute.name}-${option}`}
618
+ className={`${classLabel}${attribute.readOnly ? ` ${getClassName("kcInputClassRadioCheckboxLabelDisabled")}` : ""}`}
619
+ >
620
+ {advancedMsg(option)}
621
+ </label>
622
+ </div>
623
+ ))}
624
+ </>
625
+ );
626
+ }
627
+
628
+ function TextareaTag(props: InputFiledByTypeProps) {
629
+ const { attribute, formValidationDispatch, getClassName, displayableErrors, valueOrValues } = props;
630
+
631
+ assert(typeof valueOrValues === "string");
632
+
633
+ const value = valueOrValues;
634
+
635
+ return (
636
+ <textarea
637
+ id={attribute.name}
638
+ name={attribute.name}
639
+ className={getClassName("kcInputClass")}
640
+ aria-invalid={displayableErrors.length !== 0}
641
+ disabled={attribute.readOnly}
642
+ cols={attribute.annotations.inputTypeCols === undefined ? undefined : parseInt(`${attribute.annotations.inputTypeCols}`)}
643
+ rows={attribute.annotations.inputTypeRows === undefined ? undefined : parseInt(`${attribute.annotations.inputTypeRows}`)}
644
+ maxLength={attribute.annotations.inputTypeMaxlength === undefined ? undefined : parseInt(`${attribute.annotations.inputTypeMaxlength}`)}
645
+ value={value}
646
+ onChange={event =>
647
+ formValidationDispatch({
648
+ "action": "update",
649
+ "name": attribute.name,
650
+ "valueOrValues": event.target.value
651
+ })
652
+ }
653
+ onBlur={() =>
654
+ formValidationDispatch({
655
+ "action": "focus lost",
656
+ "name": attribute.name,
657
+ "fieldIndex": undefined
658
+ })
659
+ }
660
+ />
661
+ );
662
+ }
663
+
664
+ function SelectTag(props: InputFiledByTypeProps) {
665
+ const { attribute, formValidationDispatch, getClassName, displayableErrors, i18n, valueOrValues } = props;
666
+
667
+ const { advancedMsg } = i18n;
668
+
669
+ const isMultiple = attribute.annotations.inputType === "multiselect";
670
+
671
+ return (
672
+ <select
673
+ id={attribute.name}
674
+ name={attribute.name}
675
+ className={getClassName("kcInputClass")}
676
+ aria-invalid={displayableErrors.length !== 0}
677
+ disabled={attribute.readOnly}
678
+ multiple={isMultiple}
679
+ size={attribute.annotations.inputTypeSize === undefined ? undefined : parseInt(`${attribute.annotations.inputTypeSize}`)}
680
+ value={valueOrValues}
681
+ onChange={event =>
682
+ formValidationDispatch({
683
+ "action": "update",
684
+ "name": attribute.name,
685
+ "valueOrValues": (() => {
686
+ if (isMultiple) {
687
+ return Array.from(event.target.selectedOptions).map(option => option.value);
688
+ }
689
+
690
+ return event.target.value;
691
+ })()
692
+ })
693
+ }
694
+ onBlur={() =>
695
+ formValidationDispatch({
696
+ "action": "focus lost",
697
+ "name": attribute.name,
698
+ "fieldIndex": undefined
699
+ })
700
+ }
701
+ >
702
+ {!isMultiple && <option value=""></option>}
703
+ {(() => {
704
+ const options = (() => {
705
+ walk: {
706
+ const { inputOptionsFromValidation } = attribute.annotations;
707
+
708
+ assert(typeof inputOptionsFromValidation === "string");
709
+
710
+ if (inputOptionsFromValidation === undefined) {
711
+ break walk;
712
+ }
713
+
714
+ const validator = (attribute.validators as Record<string, { options?: string[] }>)[inputOptionsFromValidation];
715
+
716
+ if (validator === undefined) {
717
+ break walk;
718
+ }
719
+
720
+ if (validator.options === undefined) {
721
+ break walk;
722
+ }
723
+
724
+ return validator.options;
725
+ }
726
+
727
+ return attribute.validators.options?.options ?? [];
728
+ })();
729
+
730
+ return options.map(option => (
731
+ <option key={option} value={option}>
732
+ {(() => {
733
+ if (attribute.annotations.inputOptionLabels !== undefined) {
734
+ const { inputOptionLabels } = attribute.annotations;
735
+
736
+ return advancedMsg(inputOptionLabels[option] ?? option);
737
+ }
738
+
739
+ if (attribute.annotations.inputOptionLabelsI18nPrefix !== undefined) {
740
+ return advancedMsg(`${attribute.annotations.inputOptionLabelsI18nPrefix}.${option}`);
741
+ }
742
+
743
+ return option;
744
+ })()}
745
+ </option>
746
+ ));
747
+ })()}
748
+ </select>
749
+ );
750
+ }