@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
@@ -1,114 +1,135 @@
1
-
2
-
3
- import { cn } from '@/components/lib/utils';
4
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
5
- import { assert } from "tsafe/assert";
6
- import type { InputFieldByTypeProps } from "./InputFieldByType";
7
- import { InputLabel } from './InputLabel';
8
-
9
- export function SelectTag(props: InputFieldByTypeProps) {
10
- const { attribute, dispatchFormAction, displayableErrors, valueOrValues } = props;
11
-
12
- const isMultiple = attribute.annotations.inputType === "multiselect";
13
-
14
- const options = (() => {
15
- walk: {
16
- const { inputOptionsFromValidation } = attribute.annotations;
17
-
18
- if (inputOptionsFromValidation === undefined) {
19
- break walk;
20
- }
21
-
22
- assert(typeof inputOptionsFromValidation === "string");
23
-
24
- const validator = (attribute.validators as Record<string, { options?: string[] }>)[inputOptionsFromValidation];
25
-
26
- if (validator === undefined) {
27
- break walk;
28
- }
29
-
30
- if (validator.options === undefined) {
31
- break walk;
32
- }
33
-
34
- return validator.options;
35
- }
36
-
37
- return attribute.validators.options?.options ?? [];
38
- })();
39
-
40
- // For multiselect, fall back to native select as shadcn doesn't support multi-select
41
- if (isMultiple) {
42
- return (
43
- <select
44
- id={attribute.name}
45
- name={attribute.name}
46
- className={cn(
47
- "flex min-h-25 h-auto w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
48
- displayableErrors.length !== 0 && "border-destructive ring-destructive/20 focus:ring-destructive"
49
- )}
50
- aria-invalid={displayableErrors.length !== 0}
51
- disabled={attribute.readOnly}
52
- multiple={true}
53
- size={attribute.annotations.inputTypeSize === undefined ? undefined : parseInt(`${attribute.annotations.inputTypeSize}`)}
54
- value={valueOrValues}
55
- onChange={event =>
56
- dispatchFormAction({
57
- action: "update",
58
- name: attribute.name,
59
- valueOrValues: Array.from(event.target.selectedOptions).map(option => option.value)
60
- })
61
- }
62
- onBlur={() =>
63
- dispatchFormAction({
64
- action: "focus lost",
65
- name: attribute.name,
66
- fieldIndex: undefined
67
- })
68
- }
69
- >
70
- {options.map(option => (
71
- <option key={option} value={option}>
72
- <InputLabel attribute={attribute} option={option} />
73
- </option>
74
- ))}
75
- </select>
76
- );
77
- }
78
-
79
- return (
80
- <Select
81
- value={typeof valueOrValues === "string" && valueOrValues !== "" ? valueOrValues : undefined}
82
- onValueChange={value =>
83
- dispatchFormAction({
84
- action: "update",
85
- name: attribute.name,
86
- valueOrValues: value
87
- })
88
- }
89
- disabled={attribute.readOnly}
90
- >
91
- <SelectTrigger
92
- id={attribute.name}
93
- className={cn("w-full", displayableErrors.length !== 0 && "border-destructive ring-destructive/20 focus-visible:ring-destructive")}
94
- aria-invalid={displayableErrors.length !== 0}
95
- onBlur={() =>
96
- dispatchFormAction({
97
- action: "focus lost",
98
- name: attribute.name,
99
- fieldIndex: undefined
100
- })
101
- }
102
- >
103
- <SelectValue placeholder="Select an option" />
104
- </SelectTrigger>
105
- <SelectContent>
106
- {options.map(option => (
107
- <SelectItem key={option} value={option}>
108
- <InputLabel attribute={attribute} option={option} />
109
- </SelectItem>
110
- ))}
111
- </SelectContent>
112
- </Select>
113
- );
114
- }
1
+ import { cn } from "@/components/lib/utils";
2
+ import {
3
+ Select,
4
+ SelectContent,
5
+ SelectItem,
6
+ SelectTrigger,
7
+ SelectValue
8
+ } from "@/components/ui/select";
9
+ import { assert } from "tsafe/assert";
10
+ import type { InputFieldByTypeProps } from "./InputFieldByType";
11
+ import { InputLabel } from "./InputLabel";
12
+
13
+ export function SelectTag(props: InputFieldByTypeProps) {
14
+ const { attribute, dispatchFormAction, displayableErrors, valueOrValues } = props;
15
+
16
+ const isMultiple = attribute.annotations.inputType === "multiselect";
17
+
18
+ const options = (() => {
19
+ walk: {
20
+ const { inputOptionsFromValidation } = attribute.annotations;
21
+
22
+ if (inputOptionsFromValidation === undefined) {
23
+ break walk;
24
+ }
25
+
26
+ assert(typeof inputOptionsFromValidation === "string");
27
+
28
+ const validator = (
29
+ attribute.validators as Record<string, { options?: string[] }>
30
+ )[inputOptionsFromValidation];
31
+
32
+ if (validator === undefined) {
33
+ break walk;
34
+ }
35
+
36
+ if (validator.options === undefined) {
37
+ break walk;
38
+ }
39
+
40
+ return validator.options;
41
+ }
42
+
43
+ return attribute.validators.options?.options ?? [];
44
+ })();
45
+
46
+ // For multiselect, fall back to native select as shadcn doesn't support multi-select
47
+ if (isMultiple) {
48
+ return (
49
+ <select
50
+ id={attribute.name}
51
+ name={attribute.name}
52
+ className={cn(
53
+ "flex min-h-25 h-auto w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
54
+ displayableErrors.length !== 0 &&
55
+ "border-destructive ring-destructive/20 focus:ring-destructive"
56
+ )}
57
+ aria-invalid={displayableErrors.length !== 0}
58
+ disabled={attribute.readOnly}
59
+ multiple={true}
60
+ size={
61
+ attribute.annotations.inputTypeSize === undefined
62
+ ? undefined
63
+ : parseInt(`${attribute.annotations.inputTypeSize}`)
64
+ }
65
+ value={valueOrValues}
66
+ onChange={event =>
67
+ dispatchFormAction({
68
+ action: "update",
69
+ name: attribute.name,
70
+ valueOrValues: Array.from(event.target.selectedOptions).map(
71
+ option => option.value
72
+ )
73
+ })
74
+ }
75
+ onBlur={() =>
76
+ dispatchFormAction({
77
+ action: "focus lost",
78
+ name: attribute.name,
79
+ fieldIndex: undefined
80
+ })
81
+ }
82
+ >
83
+ {options.map(option => (
84
+ <option key={option} value={option}>
85
+ <InputLabel attribute={attribute} option={option} />
86
+ </option>
87
+ ))}
88
+ </select>
89
+ );
90
+ }
91
+
92
+ return (
93
+ <Select
94
+ value={
95
+ typeof valueOrValues === "string" && valueOrValues !== ""
96
+ ? valueOrValues
97
+ : undefined
98
+ }
99
+ onValueChange={value =>
100
+ dispatchFormAction({
101
+ action: "update",
102
+ name: attribute.name,
103
+ valueOrValues: value
104
+ })
105
+ }
106
+ disabled={attribute.readOnly}
107
+ >
108
+ <SelectTrigger
109
+ id={attribute.name}
110
+ className={cn(
111
+ "w-full",
112
+ displayableErrors.length !== 0 &&
113
+ "border-destructive ring-destructive/20 focus-visible:ring-destructive"
114
+ )}
115
+ aria-invalid={displayableErrors.length !== 0}
116
+ onBlur={() =>
117
+ dispatchFormAction({
118
+ action: "focus lost",
119
+ name: attribute.name,
120
+ fieldIndex: undefined
121
+ })
122
+ }
123
+ >
124
+ <SelectValue placeholder="Select an option" />
125
+ </SelectTrigger>
126
+ <SelectContent>
127
+ {options.map(option => (
128
+ <SelectItem key={option} value={option}>
129
+ <InputLabel attribute={attribute} option={option} />
130
+ </SelectItem>
131
+ ))}
132
+ </SelectContent>
133
+ </Select>
134
+ );
135
+ }
@@ -1,43 +1,55 @@
1
-
2
- import { cn } from '@/components/lib/utils';
3
- import { assert } from "tsafe/assert";
4
- import type { InputFieldByTypeProps } from "./InputFieldByType";
5
-
6
- export function TextareaTag(props: InputFieldByTypeProps) {
7
- const { attribute, dispatchFormAction, displayableErrors, valueOrValues } = props;
8
-
9
- assert(typeof valueOrValues === "string");
10
-
11
- const value = valueOrValues;
12
-
13
- return (
14
- <textarea
15
- id={attribute.name}
16
- name={attribute.name}
17
- className={cn(
18
- "flex min-h-20 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
19
- displayableErrors.length !== 0 && "border-destructive ring-destructive/20 focus-visible:ring-destructive"
20
- )}
21
- aria-invalid={displayableErrors.length !== 0}
22
- disabled={attribute.readOnly}
23
- cols={attribute.annotations.inputTypeCols === undefined ? undefined : parseInt(`${attribute.annotations.inputTypeCols}`)}
24
- rows={attribute.annotations.inputTypeRows === undefined ? undefined : parseInt(`${attribute.annotations.inputTypeRows}`)}
25
- maxLength={attribute.annotations.inputTypeMaxlength === undefined ? undefined : parseInt(`${attribute.annotations.inputTypeMaxlength}`)}
26
- value={value}
27
- onChange={event =>
28
- dispatchFormAction({
29
- action: "update",
30
- name: attribute.name,
31
- valueOrValues: event.target.value
32
- })
33
- }
34
- onBlur={() =>
35
- dispatchFormAction({
36
- action: "focus lost",
37
- name: attribute.name,
38
- fieldIndex: undefined
39
- })
40
- }
41
- />
42
- );
43
- }
1
+ import { cn } from "@/components/lib/utils";
2
+ import { assert } from "tsafe/assert";
3
+ import type { InputFieldByTypeProps } from "./InputFieldByType";
4
+
5
+ export function TextareaTag(props: InputFieldByTypeProps) {
6
+ const { attribute, dispatchFormAction, displayableErrors, valueOrValues } = props;
7
+
8
+ assert(typeof valueOrValues === "string");
9
+
10
+ const value = valueOrValues;
11
+
12
+ return (
13
+ <textarea
14
+ id={attribute.name}
15
+ name={attribute.name}
16
+ className={cn(
17
+ "flex min-h-20 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
18
+ displayableErrors.length !== 0 &&
19
+ "border-destructive ring-destructive/20 focus-visible:ring-destructive"
20
+ )}
21
+ aria-invalid={displayableErrors.length !== 0}
22
+ disabled={attribute.readOnly}
23
+ cols={
24
+ attribute.annotations.inputTypeCols === undefined
25
+ ? undefined
26
+ : parseInt(`${attribute.annotations.inputTypeCols}`)
27
+ }
28
+ rows={
29
+ attribute.annotations.inputTypeRows === undefined
30
+ ? undefined
31
+ : parseInt(`${attribute.annotations.inputTypeRows}`)
32
+ }
33
+ maxLength={
34
+ attribute.annotations.inputTypeMaxlength === undefined
35
+ ? undefined
36
+ : parseInt(`${attribute.annotations.inputTypeMaxlength}`)
37
+ }
38
+ value={value}
39
+ onChange={event =>
40
+ dispatchFormAction({
41
+ action: "update",
42
+ name: attribute.name,
43
+ valueOrValues: event.target.value
44
+ })
45
+ }
46
+ onBlur={() =>
47
+ dispatchFormAction({
48
+ action: "focus lost",
49
+ name: attribute.name,
50
+ fieldIndex: undefined
51
+ })
52
+ }
53
+ />
54
+ );
55
+ }
@@ -1,127 +1,133 @@
1
-
2
- import { Field, FieldDescription, FieldLabel } from "@/components/ui/field";
3
- import type { Attribute } from "@keycloakify/login-ui/KcContext";
4
- import type { JSX } from "@keycloakify/login-ui/tools/JSX";
5
- import {
6
- useUserProfileForm,
7
- type FormAction,
8
- type FormFieldError
9
- } from "@keycloakify/login-ui/useUserProfileForm";
10
- import { Fragment, useEffect } from "react";
11
- import { assert } from "tsafe/assert";
12
- import { useKcContext } from "../../KcContext";
13
- import { useI18n } from "../../i18n";
14
- import { DO_MAKE_USER_CONFIRM_PASSWORD } from "./DO_MAKE_USER_CONFIRM_PASSWORD";
15
- import { FieldErrors } from "./FieldErrors";
16
- import { GroupLabel } from "./GroupLabel";
17
- import { InputFieldByType } from "./InputFieldByType";
18
-
19
- export type UserProfileFormFieldsProps = {
20
- onIsFormSubmittableValueChange: (isFormSubmittable: boolean) => void;
21
- BeforeField?: (props: BeforeAfterFieldProps) => JSX.Element | null;
22
- AfterField?: (props: BeforeAfterFieldProps) => JSX.Element | null;
23
- };
24
-
25
- type BeforeAfterFieldProps = {
26
- attribute: Attribute;
27
- dispatchFormAction: React.Dispatch<FormAction>;
28
- displayableErrors: FormFieldError[];
29
- valueOrValues: string | string[];
30
- };
31
-
32
- export function UserProfileFormFields(props: UserProfileFormFieldsProps) {
33
- const { onIsFormSubmittableValueChange, BeforeField, AfterField } = props;
34
-
35
- const { kcContext } = useKcContext();
36
-
37
- assert("profile" in kcContext);
38
-
39
- const i18n = useI18n();
40
-
41
- const { advancedMsg } = i18n;
42
-
43
- const {
44
- formState: { formFieldStates, isFormSubmittable },
45
- dispatchFormAction
46
- } = useUserProfileForm({
47
- kcContext,
48
- i18n,
49
- doMakeUserConfirmPassword: DO_MAKE_USER_CONFIRM_PASSWORD
50
- });
51
-
52
- useEffect(() => {
53
- onIsFormSubmittableValueChange(isFormSubmittable);
54
- }, [isFormSubmittable]);
55
-
56
- const groupNameRef = { current: "" };
57
-
58
- return (
59
- <>
60
- {formFieldStates.map(({ attribute, displayableErrors, valueOrValues }) => {
61
- return (
62
- <Fragment key={attribute.name}>
63
- <GroupLabel attribute={attribute} groupNameRef={groupNameRef} />
64
- {BeforeField !== undefined && (
65
- <BeforeField
66
- attribute={attribute}
67
- dispatchFormAction={dispatchFormAction}
68
- displayableErrors={displayableErrors}
69
- valueOrValues={valueOrValues}
70
- />
71
- )}
72
- <Field
73
- data-invalid={displayableErrors.length > 0 ? "true" : undefined}
74
- style={{
75
- display:
76
- attribute.annotations.inputType === "hidden"
77
- ? "none"
78
- : undefined
79
- }}
80
- >
81
- <FieldLabel htmlFor={attribute.name}>
82
- {advancedMsg(attribute.displayName ?? "")}
83
- {attribute.required && <> *</>}
84
- </FieldLabel>
85
- {attribute.annotations.inputHelperTextBefore !== undefined && (
86
- <FieldDescription
87
- id={`form-help-text-before-${attribute.name}`}
88
- aria-live="polite"
89
- >
90
- {advancedMsg(attribute.annotations.inputHelperTextBefore)}
91
- </FieldDescription>
92
- )}
93
- <InputFieldByType
94
- attribute={attribute}
95
- valueOrValues={valueOrValues}
96
- displayableErrors={displayableErrors}
97
- dispatchFormAction={dispatchFormAction}
98
- />
99
- <FieldErrors
100
- attribute={attribute}
101
- displayableErrors={displayableErrors}
102
- fieldIndex={undefined}
103
- />
104
- {attribute.annotations.inputHelperTextAfter !== undefined && (
105
- <FieldDescription
106
- id={`form-help-text-after-${attribute.name}`}
107
- aria-live="polite"
108
- >
109
- {advancedMsg(attribute.annotations.inputHelperTextAfter)}
110
- </FieldDescription>
111
- )}
112
- {AfterField !== undefined && (
113
- <AfterField
114
- attribute={attribute}
115
- dispatchFormAction={dispatchFormAction}
116
- displayableErrors={displayableErrors}
117
- valueOrValues={valueOrValues}
118
- />
119
- )}
120
- {/* NOTE: Downloading of html5DataAnnotations scripts is done in the useUserProfileForm hook */}
121
- </Field>
122
- </Fragment>
123
- );
124
- })}
125
- </>
126
- );
127
- }
1
+ import { Field, FieldDescription, FieldLabel } from "@/components/ui/field";
2
+ import type { Attribute } from "@keycloakify/login-ui/KcContext";
3
+ import type { JSX } from "@keycloakify/login-ui/tools/JSX";
4
+ import {
5
+ useUserProfileForm,
6
+ type FormAction,
7
+ type FormFieldError
8
+ } from "@keycloakify/login-ui/useUserProfileForm";
9
+ import { Fragment, useEffect } from "react";
10
+ import { assert } from "tsafe/assert";
11
+ import { useKcContext } from "../../KcContext";
12
+ import { useI18n } from "../../i18n";
13
+ import { DO_MAKE_USER_CONFIRM_PASSWORD } from "./DO_MAKE_USER_CONFIRM_PASSWORD";
14
+ import { FieldErrors } from "./FieldErrors";
15
+ import { GroupLabel } from "./GroupLabel";
16
+ import { InputFieldByType } from "./InputFieldByType";
17
+
18
+ export type UserProfileFormFieldsProps = {
19
+ onIsFormSubmittableValueChange: (isFormSubmittable: boolean) => void;
20
+ BeforeField?: (props: BeforeAfterFieldProps) => JSX.Element | null;
21
+ AfterField?: (props: BeforeAfterFieldProps) => JSX.Element | null;
22
+ };
23
+
24
+ type BeforeAfterFieldProps = {
25
+ attribute: Attribute;
26
+ dispatchFormAction: React.Dispatch<FormAction>;
27
+ displayableErrors: FormFieldError[];
28
+ valueOrValues: string | string[];
29
+ };
30
+
31
+ export function UserProfileFormFields(props: UserProfileFormFieldsProps) {
32
+ const { onIsFormSubmittableValueChange, BeforeField, AfterField } = props;
33
+
34
+ const { kcContext } = useKcContext();
35
+
36
+ assert("profile" in kcContext);
37
+
38
+ const i18n = useI18n();
39
+
40
+ const { advancedMsg } = i18n;
41
+
42
+ const {
43
+ formState: { formFieldStates, isFormSubmittable },
44
+ dispatchFormAction
45
+ } = useUserProfileForm({
46
+ kcContext,
47
+ i18n,
48
+ doMakeUserConfirmPassword: DO_MAKE_USER_CONFIRM_PASSWORD
49
+ });
50
+
51
+ useEffect(() => {
52
+ onIsFormSubmittableValueChange(isFormSubmittable);
53
+ }, [isFormSubmittable]);
54
+
55
+ const groupNameRef = { current: "" };
56
+
57
+ return (
58
+ <>
59
+ {formFieldStates.map(({ attribute, displayableErrors, valueOrValues }) => {
60
+ return (
61
+ <Fragment key={attribute.name}>
62
+ <GroupLabel attribute={attribute} groupNameRef={groupNameRef} />
63
+ {BeforeField !== undefined && (
64
+ <BeforeField
65
+ attribute={attribute}
66
+ dispatchFormAction={dispatchFormAction}
67
+ displayableErrors={displayableErrors}
68
+ valueOrValues={valueOrValues}
69
+ />
70
+ )}
71
+ <Field
72
+ data-invalid={
73
+ displayableErrors.length > 0 ? "true" : undefined
74
+ }
75
+ style={{
76
+ display:
77
+ attribute.annotations.inputType === "hidden"
78
+ ? "none"
79
+ : undefined
80
+ }}
81
+ >
82
+ <FieldLabel htmlFor={attribute.name}>
83
+ {advancedMsg(attribute.displayName ?? "")}
84
+ {attribute.required && <> *</>}
85
+ </FieldLabel>
86
+ {attribute.annotations.inputHelperTextBefore !==
87
+ undefined && (
88
+ <FieldDescription
89
+ id={`form-help-text-before-${attribute.name}`}
90
+ aria-live="polite"
91
+ >
92
+ {advancedMsg(
93
+ attribute.annotations.inputHelperTextBefore
94
+ )}
95
+ </FieldDescription>
96
+ )}
97
+ <InputFieldByType
98
+ attribute={attribute}
99
+ valueOrValues={valueOrValues}
100
+ displayableErrors={displayableErrors}
101
+ dispatchFormAction={dispatchFormAction}
102
+ />
103
+ <FieldErrors
104
+ attribute={attribute}
105
+ displayableErrors={displayableErrors}
106
+ fieldIndex={undefined}
107
+ />
108
+ {attribute.annotations.inputHelperTextAfter !== undefined && (
109
+ <FieldDescription
110
+ id={`form-help-text-after-${attribute.name}`}
111
+ aria-live="polite"
112
+ >
113
+ {advancedMsg(
114
+ attribute.annotations.inputHelperTextAfter
115
+ )}
116
+ </FieldDescription>
117
+ )}
118
+ {AfterField !== undefined && (
119
+ <AfterField
120
+ attribute={attribute}
121
+ dispatchFormAction={dispatchFormAction}
122
+ displayableErrors={displayableErrors}
123
+ valueOrValues={valueOrValues}
124
+ />
125
+ )}
126
+ {/* NOTE: Downloading of html5DataAnnotations scripts is done in the useUserProfileForm hook */}
127
+ </Field>
128
+ </Fragment>
129
+ );
130
+ })}
131
+ </>
132
+ );
133
+ }
@@ -1 +1 @@
1
- export * from "./UserProfileFormFields";
1
+ export * from "./UserProfileFormFields";