@oussemasahbeni/keycloakify-login-shadcn 250004.0.3 → 250004.0.8

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 (187) hide show
  1. package/keycloak-theme/components/langauges.tsx +1 -1
  2. package/keycloak-theme/components/theme-toggle.tsx +0 -1
  3. package/keycloak-theme/components/ui/alert.tsx +1 -2
  4. package/keycloak-theme/components/ui/button.tsx +1 -2
  5. package/keycloak-theme/components/ui/card.tsx +0 -1
  6. package/keycloak-theme/components/ui/checkbox.tsx +0 -1
  7. package/keycloak-theme/components/ui/dropdown-menu.tsx +14 -4
  8. package/keycloak-theme/components/ui/field.tsx +0 -1
  9. package/keycloak-theme/components/ui/input-otp.tsx +0 -1
  10. package/keycloak-theme/components/ui/input.tsx +0 -1
  11. package/keycloak-theme/components/ui/label.tsx +1 -2
  12. package/keycloak-theme/components/ui/radio-group.tsx +0 -1
  13. package/keycloak-theme/components/ui/select.tsx +12 -4
  14. package/keycloak-theme/components/ui/separator.tsx +0 -1
  15. package/keycloak-theme/components/ui/tooltip.tsx +0 -1
  16. package/keycloak-theme/login/KcContext.ts +23 -23
  17. package/keycloak-theme/login/KcPage.tsx +45 -47
  18. package/keycloak-theme/login/assets/img/auth-logo.svg +100 -100
  19. package/keycloak-theme/login/assets/img/shape.svg +71 -71
  20. package/keycloak-theme/login/components/LogoutOtherSessions.tsx +24 -26
  21. package/keycloak-theme/login/components/PasswordWrapper.tsx +35 -35
  22. package/keycloak-theme/login/components/Template/Template.tsx +279 -227
  23. package/keycloak-theme/login/components/Template/index.ts +1 -1
  24. package/keycloak-theme/login/components/Template/useInitializeTemplate.ts +61 -61
  25. package/keycloak-theme/login/components/UserProfileFormFields/AddRemoveButtonsMultiValuedAttribute.tsx +65 -61
  26. package/keycloak-theme/login/components/UserProfileFormFields/DO_MAKE_USER_CONFIRM_PASSWORD.ts +2 -2
  27. package/keycloak-theme/login/components/UserProfileFormFields/FieldErrors.tsx +33 -29
  28. package/keycloak-theme/login/components/UserProfileFormFields/GroupLabel.tsx +90 -71
  29. package/keycloak-theme/login/components/UserProfileFormFields/InputFieldByType.tsx +66 -59
  30. package/keycloak-theme/login/components/UserProfileFormFields/InputLabel.tsx +0 -1
  31. package/keycloak-theme/login/components/UserProfileFormFields/InputTag.tsx +133 -116
  32. package/keycloak-theme/login/components/UserProfileFormFields/InputTagSelects.tsx +150 -136
  33. package/keycloak-theme/login/components/UserProfileFormFields/SelectTag.tsx +135 -114
  34. package/keycloak-theme/login/components/UserProfileFormFields/TextareaTag.tsx +55 -43
  35. package/keycloak-theme/login/components/UserProfileFormFields/UserProfileFormFields.tsx +133 -127
  36. package/keycloak-theme/login/components/UserProfileFormFields/index.ts +1 -1
  37. package/keycloak-theme/login/i18n.ts +47 -47
  38. package/keycloak-theme/login/mocks/KcPageStory.tsx +6 -2
  39. package/keycloak-theme/login/mocks/getKcContextMock.ts +22 -22
  40. package/keycloak-theme/login/pages/PageIndex.tsx +130 -134
  41. package/keycloak-theme/login/pages/code/Page.stories.tsx +57 -70
  42. package/keycloak-theme/login/pages/code/Page.tsx +89 -89
  43. package/keycloak-theme/login/pages/code/index.ts +3 -3
  44. package/keycloak-theme/login/pages/delete-account-confirm/Page.stories.tsx +37 -46
  45. package/keycloak-theme/login/pages/delete-account-confirm/Page.tsx +60 -63
  46. package/keycloak-theme/login/pages/delete-account-confirm/index.ts +3 -3
  47. package/keycloak-theme/login/pages/delete-credential/Page.stories.tsx +25 -30
  48. package/keycloak-theme/login/pages/delete-credential/Page.tsx +56 -51
  49. package/keycloak-theme/login/pages/delete-credential/index.ts +3 -3
  50. package/keycloak-theme/login/pages/error/Page.stories.tsx +46 -58
  51. package/keycloak-theme/login/pages/error/Page.tsx +43 -42
  52. package/keycloak-theme/login/pages/error/index.ts +3 -3
  53. package/keycloak-theme/login/pages/frontchannel-logout/Page.stories.tsx +25 -32
  54. package/keycloak-theme/login/pages/frontchannel-logout/Page.tsx +82 -84
  55. package/keycloak-theme/login/pages/frontchannel-logout/index.ts +3 -3
  56. package/keycloak-theme/login/pages/idp-review-user-profile/Page.stories.tsx +46 -59
  57. package/keycloak-theme/login/pages/idp-review-user-profile/Page.tsx +49 -52
  58. package/keycloak-theme/login/pages/idp-review-user-profile/index.ts +3 -3
  59. package/keycloak-theme/login/pages/info/Page.stories.tsx +50 -60
  60. package/keycloak-theme/login/pages/info/Page.tsx +94 -92
  61. package/keycloak-theme/login/pages/link-idp-action/Page.stories.tsx +32 -16
  62. package/keycloak-theme/login/pages/link-idp-action/Page.tsx +45 -43
  63. package/keycloak-theme/login/pages/link-idp-action/index.ts +3 -3
  64. package/keycloak-theme/login/pages/login/Form.tsx +242 -242
  65. package/keycloak-theme/login/pages/login/Info.tsx +29 -29
  66. package/keycloak-theme/login/pages/login/Page.stories.tsx +346 -365
  67. package/keycloak-theme/login/pages/login/Page.tsx +43 -44
  68. package/keycloak-theme/login/pages/login/SocialProviders.tsx +93 -107
  69. package/keycloak-theme/login/pages/login/index.ts +3 -3
  70. package/keycloak-theme/login/pages/login/providers/apple.svg +3 -3
  71. package/keycloak-theme/login/pages/login/providers/bitbucket.svg +11 -11
  72. package/keycloak-theme/login/pages/login/providers/discord.svg +4 -4
  73. package/keycloak-theme/login/pages/login/providers/facebook.svg +5 -5
  74. package/keycloak-theme/login/pages/login/providers/github.svg +3 -3
  75. package/keycloak-theme/login/pages/login/providers/gitlab.svg +7 -7
  76. package/keycloak-theme/login/pages/login/providers/google.svg +7 -7
  77. package/keycloak-theme/login/pages/login/providers/instagram.svg +31 -31
  78. package/keycloak-theme/login/pages/login/providers/linkedin.svg +3 -3
  79. package/keycloak-theme/login/pages/login/providers/microsoft.svg +6 -6
  80. package/keycloak-theme/login/pages/login/providers/oidc.svg +5 -5
  81. package/keycloak-theme/login/pages/login/providers/openshift.svg +7 -7
  82. package/keycloak-theme/login/pages/login/providers/paypal.svg +6 -6
  83. package/keycloak-theme/login/pages/login/providers/slack.svg +11 -11
  84. package/keycloak-theme/login/pages/login/providers/stackoverflow.svg +5 -5
  85. package/keycloak-theme/login/pages/login/providers/x.svg +3 -3
  86. package/keycloak-theme/login/pages/login/useProviderLogos.tsx +39 -39
  87. package/keycloak-theme/login/pages/login/useScript.tsx +62 -62
  88. package/keycloak-theme/login/pages/login-config-totp/Page.stories.tsx +45 -60
  89. package/keycloak-theme/login/pages/login-config-totp/Page.tsx +253 -240
  90. package/keycloak-theme/login/pages/login-config-totp/index.ts +3 -3
  91. package/keycloak-theme/login/pages/login-idp-link-confirm/Page.stories.tsx +30 -35
  92. package/keycloak-theme/login/pages/login-idp-link-confirm/Page.tsx +40 -43
  93. package/keycloak-theme/login/pages/login-idp-link-confirm/index.ts +3 -3
  94. package/keycloak-theme/login/pages/login-idp-link-confirm-override/Page.stories.tsx +16 -23
  95. package/keycloak-theme/login/pages/login-idp-link-confirm-override/Page.tsx +44 -47
  96. package/keycloak-theme/login/pages/login-idp-link-confirm-override/index.ts +3 -3
  97. package/keycloak-theme/login/pages/login-idp-link-email/Page.stories.tsx +54 -63
  98. package/keycloak-theme/login/pages/login-idp-link-email/Page.tsx +51 -54
  99. package/keycloak-theme/login/pages/login-idp-link-email/index.ts +3 -3
  100. package/keycloak-theme/login/pages/login-oauth-grant/Page.stories.tsx +39 -45
  101. package/keycloak-theme/login/pages/login-oauth-grant/Page.tsx +136 -126
  102. package/keycloak-theme/login/pages/login-oauth-grant/index.ts +3 -3
  103. package/keycloak-theme/login/pages/login-oauth2-device-verify-user-code/Page.stories.tsx +38 -48
  104. package/keycloak-theme/login/pages/login-oauth2-device-verify-user-code/Page.tsx +56 -58
  105. package/keycloak-theme/login/pages/login-oauth2-device-verify-user-code/index.ts +3 -3
  106. package/keycloak-theme/login/pages/login-otp/Page.stories.tsx +82 -97
  107. package/keycloak-theme/login/pages/login-otp/Page.tsx +117 -108
  108. package/keycloak-theme/login/pages/login-otp/index.ts +3 -3
  109. package/keycloak-theme/login/pages/login-page-expired/Page.stories.tsx +28 -37
  110. package/keycloak-theme/login/pages/login-page-expired/Page.tsx +45 -47
  111. package/keycloak-theme/login/pages/login-page-expired/index.ts +3 -3
  112. package/keycloak-theme/login/pages/login-passkeys-conditional-authenticate/Page.stories.tsx +20 -0
  113. package/keycloak-theme/login/pages/login-passkeys-conditional-authenticate/Page.tsx +290 -233
  114. package/keycloak-theme/login/pages/login-passkeys-conditional-authenticate/index.ts +3 -3
  115. package/keycloak-theme/login/pages/login-passkeys-conditional-authenticate/useScript.tsx +63 -63
  116. package/keycloak-theme/login/pages/login-password/Page.stories.tsx +55 -56
  117. package/keycloak-theme/login/pages/login-password/Page.tsx +148 -149
  118. package/keycloak-theme/login/pages/login-password/index.ts +3 -3
  119. package/keycloak-theme/login/pages/login-password/useScript.tsx +62 -63
  120. package/keycloak-theme/login/pages/login-recovery-authn-code-config/Page.stories.tsx +28 -36
  121. package/keycloak-theme/login/pages/login-recovery-authn-code-config/Page.tsx +178 -181
  122. package/keycloak-theme/login/pages/login-recovery-authn-code-config/index.ts +3 -3
  123. package/keycloak-theme/login/pages/login-recovery-authn-code-config/useScript.tsx +145 -145
  124. package/keycloak-theme/login/pages/login-recovery-authn-code-input/Page.stories.tsx +16 -22
  125. package/keycloak-theme/login/pages/login-recovery-authn-code-input/Page.tsx +69 -70
  126. package/keycloak-theme/login/pages/login-recovery-authn-code-input/index.ts +3 -3
  127. package/keycloak-theme/login/pages/login-reset-otp/Page.stories.tsx +62 -75
  128. package/keycloak-theme/login/pages/login-reset-otp/Page.tsx +85 -86
  129. package/keycloak-theme/login/pages/login-reset-otp/index.ts +3 -3
  130. package/keycloak-theme/login/pages/login-reset-password/Form.tsx +67 -68
  131. package/keycloak-theme/login/pages/login-reset-password/Page.stories.tsx +44 -55
  132. package/keycloak-theme/login/pages/login-reset-password/Page.tsx +27 -27
  133. package/keycloak-theme/login/pages/login-reset-password/index.ts +3 -3
  134. package/keycloak-theme/login/pages/login-update-password/Page.stories.tsx +40 -51
  135. package/keycloak-theme/login/pages/login-update-password/Page.tsx +109 -111
  136. package/keycloak-theme/login/pages/login-update-password/index.ts +3 -3
  137. package/keycloak-theme/login/pages/login-update-profile/Page.stories.tsx +28 -37
  138. package/keycloak-theme/login/pages/login-update-profile/Page.tsx +67 -68
  139. package/keycloak-theme/login/pages/login-update-profile/index.ts +3 -3
  140. package/keycloak-theme/login/pages/login-username/Page.stories.tsx +32 -43
  141. package/keycloak-theme/login/pages/login-username/Page.tsx +246 -246
  142. package/keycloak-theme/login/pages/login-username/index.ts +3 -3
  143. package/keycloak-theme/login/pages/login-username/useScript.tsx +62 -62
  144. package/keycloak-theme/login/pages/login-verify-email/Page.stories.tsx +68 -81
  145. package/keycloak-theme/login/pages/login-verify-email/Page.tsx +37 -38
  146. package/keycloak-theme/login/pages/login-verify-email/index.ts +3 -3
  147. package/keycloak-theme/login/pages/login-x509-info/Page.stories.tsx +29 -38
  148. package/keycloak-theme/login/pages/login-x509-info/Page.tsx +72 -75
  149. package/keycloak-theme/login/pages/login-x509-info/index.ts +3 -3
  150. package/keycloak-theme/login/pages/logout-confirm/Page.stories.tsx +34 -43
  151. package/keycloak-theme/login/pages/logout-confirm/Page.tsx +50 -53
  152. package/keycloak-theme/login/pages/logout-confirm/index.ts +3 -3
  153. package/keycloak-theme/login/pages/register/Form.tsx +107 -106
  154. package/keycloak-theme/login/pages/register/Page.stories.tsx +40 -14
  155. package/keycloak-theme/login/pages/register/Page.tsx +26 -26
  156. package/keycloak-theme/login/pages/register/TermsAcceptance.tsx +55 -56
  157. package/keycloak-theme/login/pages/register/index.ts +3 -3
  158. package/keycloak-theme/login/pages/saml-post-form/Page.stories.tsx +16 -23
  159. package/keycloak-theme/login/pages/saml-post-form/Page.tsx +64 -66
  160. package/keycloak-theme/login/pages/saml-post-form/index.ts +3 -3
  161. package/keycloak-theme/login/pages/select-authenticator/Page.stories.tsx +83 -96
  162. package/keycloak-theme/login/pages/select-authenticator/Page.tsx +97 -100
  163. package/keycloak-theme/login/pages/select-authenticator/index.ts +3 -3
  164. package/keycloak-theme/login/pages/select-organization/Page.stories.tsx +62 -49
  165. package/keycloak-theme/login/pages/select-organization/Page.tsx +123 -126
  166. package/keycloak-theme/login/pages/select-organization/index.ts +3 -3
  167. package/keycloak-theme/login/pages/terms/Page.stories.tsx +15 -0
  168. package/keycloak-theme/login/pages/terms/Page.tsx +49 -51
  169. package/keycloak-theme/login/pages/terms/index.ts +3 -3
  170. package/keycloak-theme/login/pages/update-email/Page.stories.tsx +27 -36
  171. package/keycloak-theme/login/pages/update-email/Page.tsx +61 -62
  172. package/keycloak-theme/login/pages/update-email/index.ts +3 -3
  173. package/keycloak-theme/login/pages/webauthn-authenticate/Page.stories.tsx +112 -127
  174. package/keycloak-theme/login/pages/webauthn-authenticate/Page.tsx +206 -202
  175. package/keycloak-theme/login/pages/webauthn-authenticate/index.ts +3 -3
  176. package/keycloak-theme/login/pages/webauthn-authenticate/useScript.tsx +55 -55
  177. package/keycloak-theme/login/pages/webauthn-error/Page.stories.tsx +52 -67
  178. package/keycloak-theme/login/pages/webauthn-error/Page.tsx +70 -73
  179. package/keycloak-theme/login/pages/webauthn-error/index.ts +3 -3
  180. package/keycloak-theme/login/pages/webauthn-register/Page.stories.tsx +39 -50
  181. package/keycloak-theme/login/pages/webauthn-register/Page.tsx +78 -78
  182. package/keycloak-theme/login/pages/webauthn-register/index.ts +3 -3
  183. package/keycloak-theme/login/pages/webauthn-register/useScript.tsx +62 -62
  184. package/keycloak-theme/login/shared/getColorScheme.ts +45 -45
  185. package/keycloak-theme/login/styleLevelCustomization.tsx +34 -36
  186. package/keycloak-theme/public/site.webmanifest +11 -1
  187. package/package.json +6 -2
@@ -14,3 +14,23 @@ export default meta;
14
14
  type Story = StoryObj<typeof meta>;
15
15
 
16
16
  export const Default: Story = {};
17
+
18
+ export const Arabic: Story = {
19
+ args: {
20
+ kcContext: {
21
+ locale: {
22
+ currentLanguageTag: "ar",
23
+ rtl: true
24
+ }
25
+ }
26
+ }
27
+ };
28
+ export const French: Story = {
29
+ args: {
30
+ kcContext: {
31
+ locale: {
32
+ currentLanguageTag: "fr"
33
+ }
34
+ }
35
+ }
36
+ };
@@ -1,233 +1,290 @@
1
- import { clsx } from "@keycloakify/login-ui/tools/clsx";
2
- import { useKcClsx } from "@keycloakify/login-ui/useKcClsx";
3
- import { Fragment } from "react";
4
- import { assert } from "tsafe/assert";
5
- import { useKcContext } from "../../KcContext";
6
- import { Template } from "../../components/Template";
7
- import { useI18n } from "../../i18n";
8
- import { useScript } from "./useScript";
9
-
10
- export function Page() {
11
- const { kcContext } = useKcContext();
12
- assert(kcContext.pageId === "login-passkeys-conditional-authenticate.ftl");
13
-
14
- const {
15
- messagesPerField,
16
- login,
17
- url,
18
- usernameHidden,
19
- shouldDisplayAuthenticators,
20
- authenticators,
21
- registrationDisabled,
22
- realm
23
- } = kcContext;
24
-
25
- const { msg, msgStr, advancedMsg } = useI18n();
26
-
27
- const { kcClsx } = useKcClsx();
28
-
29
- const webAuthnButtonId = "authenticateWebAuthnButton";
30
-
31
- useScript({ webAuthnButtonId });
32
-
33
- return (
34
- <Template
35
- headerNode={msg("passkey-login-title")}
36
- infoNode={
37
- realm.registrationAllowed &&
38
- !registrationDisabled && (
39
- <div id="kc-registration">
40
- <span>
41
- ${msg("noAccount")}{" "}
42
- <a tabIndex={6} href={url.registrationUrl}>
43
- {msg("doRegister")}
44
- </a>
45
- </span>
46
- </div>
47
- )
48
- }
49
- >
50
- <form id="webauth" action={url.loginAction} method="post">
51
- <input type="hidden" id="clientDataJSON" name="clientDataJSON" />
52
- <input type="hidden" id="authenticatorData" name="authenticatorData" />
53
- <input type="hidden" id="signature" name="signature" />
54
- <input type="hidden" id="credentialId" name="credentialId" />
55
- <input type="hidden" id="userHandle" name="userHandle" />
56
- <input type="hidden" id="error" name="error" />
57
- </form>
58
-
59
- <div className={kcClsx("kcFormGroupClass")} style={{ marginBottom: 0 }}>
60
- {authenticators !== undefined && Object.keys(authenticators).length !== 0 && (
61
- <>
62
- <form id="authn_select" className={kcClsx("kcFormClass")}>
63
- {authenticators.authenticators.map((authenticator, i) => (
64
- <input
65
- key={i}
66
- type="hidden"
67
- name="authn_use_chk"
68
- readOnly
69
- value={authenticator.credentialId}
70
- />
71
- ))}
72
- </form>
73
- {shouldDisplayAuthenticators && (
74
- <>
75
- {authenticators.authenticators.length > 1 && (
76
- <p className={kcClsx("kcSelectAuthListItemTitle")}>
77
- {msg("passkey-available-authenticators")}
78
- </p>
79
- )}
80
- <div className={kcClsx("kcFormClass")}>
81
- {authenticators.authenticators.map((authenticator, i) => (
82
- <div
83
- key={i}
84
- id={`kc-webauthn-authenticator-item-${i}`}
85
- className={kcClsx("kcSelectAuthListItemClass")}
86
- >
87
- <i
88
- className={clsx(
89
- (() => {
90
- const className = kcClsx(
91
- authenticator.transports.iconClass as any
92
- );
93
- if (
94
- className ===
95
- authenticator.transports.iconClass
96
- ) {
97
- return kcClsx("kcWebAuthnDefaultIcon");
98
- }
99
- return className;
100
- })(),
101
- kcClsx("kcSelectAuthListItemIconPropertyClass")
102
- )}
103
- />
104
- <div className={kcClsx("kcSelectAuthListItemBodyClass")}>
105
- <div
106
- id={`kc-webauthn-authenticator-label-${i}`}
107
- className={kcClsx(
108
- "kcSelectAuthListItemHeadingClass"
109
- )}
110
- >
111
- {advancedMsg(authenticator.label)}
112
- </div>
113
- {authenticator.transports !== undefined &&
114
- authenticator.transports.displayNameProperties !==
115
- undefined &&
116
- authenticator.transports.displayNameProperties
117
- .length !== 0 && (
118
- <div
119
- id={`kc-webauthn-authenticator-transport-${i}`}
120
- className={kcClsx(
121
- "kcSelectAuthListItemDescriptionClass"
122
- )}
123
- >
124
- {authenticator.transports.displayNameProperties.map(
125
- (nameProperty, i, arr) => (
126
- <Fragment key={i}>
127
- <span key={i}>
128
- {" "}
129
- {advancedMsg(
130
- nameProperty
131
- )}{" "}
132
- </span>
133
- {i !== arr.length - 1 && (
134
- <span>, </span>
135
- )}
136
- </Fragment>
137
- )
138
- )}
139
- </div>
140
- )}
141
- <div
142
- className={kcClsx(
143
- "kcSelectAuthListItemDescriptionClass"
144
- )}
145
- >
146
- <span
147
- id={`kc-webauthn-authenticator-createdlabel-${i}`}
148
- >
149
- {msg("passkey-createdAt-label")}
150
- </span>
151
- <span id={`kc-webauthn-authenticator-created-${i}`}>
152
- {authenticator.createdAt}
153
- </span>
154
- </div>
155
- </div>
156
- <div className={kcClsx("kcSelectAuthListItemFillClass")} />
157
- </div>
158
- ))}
159
- </div>
160
- </>
161
- )}
162
- </>
163
- )}
164
- <div id="kc-form">
165
- <div id="kc-form-wrapper">
166
- {realm.password && (
167
- <form
168
- id="kc-form-login"
169
- action={url.loginAction}
170
- method="post"
171
- style={{ display: "none" }}
172
- onSubmit={event => {
173
- try {
174
- // @ts-expect-error: Ok
175
- event.target.login.disabled = true;
176
- } catch { /* empty */ }
177
-
178
- return true;
179
- }}
180
- >
181
- {!usernameHidden && (
182
- <div className={kcClsx("kcFormGroupClass")}>
183
- <label htmlFor="username" className={kcClsx("kcLabelClass")}>
184
- {msg("passkey-autofill-select")}
185
- </label>
186
- <input
187
- tabIndex={1}
188
- id="username"
189
- aria-invalid={messagesPerField.existsError("username")}
190
- className={kcClsx("kcInputClass")}
191
- name="username"
192
- defaultValue={login.username ?? ""}
193
- autoComplete="username webauthn"
194
- type="text"
195
- autoFocus
196
- />
197
- {messagesPerField.existsError("username") && (
198
- <span
199
- id="input-error-username"
200
- className={kcClsx("kcInputErrorMessageClass")}
201
- aria-live="polite"
202
- >
203
- {messagesPerField.get("username")}
204
- </span>
205
- )}
206
- </div>
207
- )}
208
- </form>
209
- )}
210
- <div
211
- id="kc-form-passkey-button"
212
- className={kcClsx("kcFormButtonsClass")}
213
- style={{ display: "none" }}
214
- >
215
- <input
216
- id={webAuthnButtonId}
217
- type="button"
218
- autoFocus
219
- value={msgStr("passkey-doAuthenticate")}
220
- className={kcClsx(
221
- "kcButtonClass",
222
- "kcButtonPrimaryClass",
223
- "kcButtonBlockClass",
224
- "kcButtonLargeClass"
225
- )}
226
- />
227
- </div>
228
- </div>
229
- </div>
230
- </div>
231
- </Template>
232
- );
233
- }
1
+ import { clsx } from "@keycloakify/login-ui/tools/clsx";
2
+ import { useKcClsx } from "@keycloakify/login-ui/useKcClsx";
3
+ import { Fragment } from "react";
4
+ import { assert } from "tsafe/assert";
5
+ import { useKcContext } from "../../KcContext";
6
+ import { Template } from "../../components/Template";
7
+ import { useI18n } from "../../i18n";
8
+ import { useScript } from "./useScript";
9
+
10
+ export function Page() {
11
+ const { kcContext } = useKcContext();
12
+ assert(kcContext.pageId === "login-passkeys-conditional-authenticate.ftl");
13
+
14
+ const {
15
+ messagesPerField,
16
+ login,
17
+ url,
18
+ usernameHidden,
19
+ shouldDisplayAuthenticators,
20
+ authenticators,
21
+ registrationDisabled,
22
+ realm
23
+ } = kcContext;
24
+
25
+ const { msg, msgStr, advancedMsg } = useI18n();
26
+
27
+ const { kcClsx } = useKcClsx();
28
+
29
+ const webAuthnButtonId = "authenticateWebAuthnButton";
30
+
31
+ useScript({ webAuthnButtonId });
32
+
33
+ return (
34
+ <Template
35
+ headerNode={msg("passkey-login-title")}
36
+ infoNode={
37
+ realm.registrationAllowed &&
38
+ !registrationDisabled && (
39
+ <div id="kc-registration">
40
+ <span>
41
+ ${msg("noAccount")}{" "}
42
+ <a tabIndex={6} href={url.registrationUrl}>
43
+ {msg("doRegister")}
44
+ </a>
45
+ </span>
46
+ </div>
47
+ )
48
+ }
49
+ >
50
+ <form id="webauth" action={url.loginAction} method="post">
51
+ <input type="hidden" id="clientDataJSON" name="clientDataJSON" />
52
+ <input type="hidden" id="authenticatorData" name="authenticatorData" />
53
+ <input type="hidden" id="signature" name="signature" />
54
+ <input type="hidden" id="credentialId" name="credentialId" />
55
+ <input type="hidden" id="userHandle" name="userHandle" />
56
+ <input type="hidden" id="error" name="error" />
57
+ </form>
58
+
59
+ <div className={kcClsx("kcFormGroupClass")} style={{ marginBottom: 0 }}>
60
+ {authenticators !== undefined &&
61
+ Object.keys(authenticators).length !== 0 && (
62
+ <>
63
+ <form id="authn_select" className={kcClsx("kcFormClass")}>
64
+ {authenticators.authenticators.map((authenticator, i) => (
65
+ <input
66
+ key={i}
67
+ type="hidden"
68
+ name="authn_use_chk"
69
+ readOnly
70
+ value={authenticator.credentialId}
71
+ />
72
+ ))}
73
+ </form>
74
+ {shouldDisplayAuthenticators && (
75
+ <>
76
+ {authenticators.authenticators.length > 1 && (
77
+ <p
78
+ className={kcClsx(
79
+ "kcSelectAuthListItemTitle"
80
+ )}
81
+ >
82
+ {msg("passkey-available-authenticators")}
83
+ </p>
84
+ )}
85
+ <div className={kcClsx("kcFormClass")}>
86
+ {authenticators.authenticators.map(
87
+ (authenticator, i) => (
88
+ <div
89
+ key={i}
90
+ id={`kc-webauthn-authenticator-item-${i}`}
91
+ className={kcClsx(
92
+ "kcSelectAuthListItemClass"
93
+ )}
94
+ >
95
+ <i
96
+ className={clsx(
97
+ (() => {
98
+ const className = kcClsx(
99
+ authenticator
100
+ .transports
101
+ .iconClass as any
102
+ );
103
+ if (
104
+ className ===
105
+ authenticator
106
+ .transports
107
+ .iconClass
108
+ ) {
109
+ return kcClsx(
110
+ "kcWebAuthnDefaultIcon"
111
+ );
112
+ }
113
+ return className;
114
+ })(),
115
+ kcClsx(
116
+ "kcSelectAuthListItemIconPropertyClass"
117
+ )
118
+ )}
119
+ />
120
+ <div
121
+ className={kcClsx(
122
+ "kcSelectAuthListItemBodyClass"
123
+ )}
124
+ >
125
+ <div
126
+ id={`kc-webauthn-authenticator-label-${i}`}
127
+ className={kcClsx(
128
+ "kcSelectAuthListItemHeadingClass"
129
+ )}
130
+ >
131
+ {advancedMsg(
132
+ authenticator.label
133
+ )}
134
+ </div>
135
+ {authenticator.transports !==
136
+ undefined &&
137
+ authenticator.transports
138
+ .displayNameProperties !==
139
+ undefined &&
140
+ authenticator.transports
141
+ .displayNameProperties
142
+ .length !== 0 && (
143
+ <div
144
+ id={`kc-webauthn-authenticator-transport-${i}`}
145
+ className={kcClsx(
146
+ "kcSelectAuthListItemDescriptionClass"
147
+ )}
148
+ >
149
+ {authenticator.transports.displayNameProperties.map(
150
+ (
151
+ nameProperty,
152
+ i,
153
+ arr
154
+ ) => (
155
+ <Fragment
156
+ key={i}
157
+ >
158
+ <span
159
+ key={
160
+ i
161
+ }
162
+ >
163
+ {" "}
164
+ {advancedMsg(
165
+ nameProperty
166
+ )}{" "}
167
+ </span>
168
+ {i !==
169
+ arr.length -
170
+ 1 && (
171
+ <span>
172
+ ,{" "}
173
+ </span>
174
+ )}
175
+ </Fragment>
176
+ )
177
+ )}
178
+ </div>
179
+ )}
180
+ <div
181
+ className={kcClsx(
182
+ "kcSelectAuthListItemDescriptionClass"
183
+ )}
184
+ >
185
+ <span
186
+ id={`kc-webauthn-authenticator-createdlabel-${i}`}
187
+ >
188
+ {msg(
189
+ "passkey-createdAt-label"
190
+ )}
191
+ </span>
192
+ <span
193
+ id={`kc-webauthn-authenticator-created-${i}`}
194
+ >
195
+ {authenticator.createdAt}
196
+ </span>
197
+ </div>
198
+ </div>
199
+ <div
200
+ className={kcClsx(
201
+ "kcSelectAuthListItemFillClass"
202
+ )}
203
+ />
204
+ </div>
205
+ )
206
+ )}
207
+ </div>
208
+ </>
209
+ )}
210
+ </>
211
+ )}
212
+ <div id="kc-form">
213
+ <div id="kc-form-wrapper">
214
+ {realm.password && (
215
+ <form
216
+ id="kc-form-login"
217
+ action={url.loginAction}
218
+ method="post"
219
+ style={{ display: "none" }}
220
+ onSubmit={event => {
221
+ try {
222
+ // @ts-expect-error: Ok
223
+ event.target.login.disabled = true;
224
+ } catch {
225
+ /* empty */
226
+ }
227
+
228
+ return true;
229
+ }}
230
+ >
231
+ {!usernameHidden && (
232
+ <div className={kcClsx("kcFormGroupClass")}>
233
+ <label
234
+ htmlFor="username"
235
+ className={kcClsx("kcLabelClass")}
236
+ >
237
+ {msg("passkey-autofill-select")}
238
+ </label>
239
+ <input
240
+ tabIndex={1}
241
+ id="username"
242
+ aria-invalid={messagesPerField.existsError(
243
+ "username"
244
+ )}
245
+ className={kcClsx("kcInputClass")}
246
+ name="username"
247
+ defaultValue={login.username ?? ""}
248
+ autoComplete="username webauthn"
249
+ type="text"
250
+ autoFocus
251
+ />
252
+ {messagesPerField.existsError("username") && (
253
+ <span
254
+ id="input-error-username"
255
+ className={kcClsx(
256
+ "kcInputErrorMessageClass"
257
+ )}
258
+ aria-live="polite"
259
+ >
260
+ {messagesPerField.get("username")}
261
+ </span>
262
+ )}
263
+ </div>
264
+ )}
265
+ </form>
266
+ )}
267
+ <div
268
+ id="kc-form-passkey-button"
269
+ className={kcClsx("kcFormButtonsClass")}
270
+ style={{ display: "none" }}
271
+ >
272
+ <input
273
+ id={webAuthnButtonId}
274
+ type="button"
275
+ autoFocus
276
+ value={msgStr("passkey-doAuthenticate")}
277
+ className={kcClsx(
278
+ "kcButtonClass",
279
+ "kcButtonPrimaryClass",
280
+ "kcButtonBlockClass",
281
+ "kcButtonLargeClass"
282
+ )}
283
+ />
284
+ </div>
285
+ </div>
286
+ </div>
287
+ </div>
288
+ </Template>
289
+ );
290
+ }
@@ -1,3 +1,3 @@
1
- import { Page } from "./Page";
2
-
3
- export default Page;
1
+ import { Page } from "./Page";
2
+
3
+ export default Page;