@oussemasahbeni/keycloakify-login-shadcn 250004.0.7 → 250004.0.9

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 (108) 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 +69 -62
  4. package/keycloak-theme/components/ui/button.tsx +44 -39
  5. package/keycloak-theme/components/ui/card.tsx +59 -45
  6. package/keycloak-theme/components/ui/checkbox.tsx +24 -23
  7. package/keycloak-theme/components/ui/dropdown-menu.tsx +233 -168
  8. package/keycloak-theme/components/ui/field.tsx +50 -48
  9. package/keycloak-theme/components/ui/input-otp.tsx +55 -49
  10. package/keycloak-theme/components/ui/input.tsx +18 -22
  11. package/keycloak-theme/components/ui/label.tsx +19 -21
  12. package/keycloak-theme/components/ui/radio-group.tsx +27 -26
  13. package/keycloak-theme/components/ui/select.tsx +169 -122
  14. package/keycloak-theme/components/ui/separator.tsx +23 -24
  15. package/keycloak-theme/components/ui/tooltip.tsx +53 -24
  16. package/keycloak-theme/login/KcPage.tsx +2 -5
  17. package/keycloak-theme/login/components/LogoutOtherSessions.tsx +3 -5
  18. package/keycloak-theme/login/components/PasswordWrapper.tsx +4 -4
  19. package/keycloak-theme/login/components/Template/Template.tsx +110 -58
  20. package/keycloak-theme/login/components/UserProfileFormFields/AddRemoveButtonsMultiValuedAttribute.tsx +7 -3
  21. package/keycloak-theme/login/components/UserProfileFormFields/FieldErrors.tsx +8 -4
  22. package/keycloak-theme/login/components/UserProfileFormFields/GroupLabel.tsx +33 -14
  23. package/keycloak-theme/login/components/UserProfileFormFields/InputFieldByType.tsx +9 -2
  24. package/keycloak-theme/login/components/UserProfileFormFields/InputLabel.tsx +0 -1
  25. package/keycloak-theme/login/components/UserProfileFormFields/InputTag.tsx +25 -8
  26. package/keycloak-theme/login/components/UserProfileFormFields/InputTagSelects.tsx +30 -16
  27. package/keycloak-theme/login/components/UserProfileFormFields/SelectTag.tsx +32 -11
  28. package/keycloak-theme/login/components/UserProfileFormFields/TextareaTag.tsx +19 -7
  29. package/keycloak-theme/login/components/UserProfileFormFields/UserProfileFormFields.tsx +11 -5
  30. package/keycloak-theme/login/index.css +3 -20
  31. package/keycloak-theme/login/mocks/KcPageStory.tsx +6 -2
  32. package/keycloak-theme/login/pages/PageIndex.tsx +0 -4
  33. package/keycloak-theme/login/pages/code/Page.stories.tsx +4 -5
  34. package/keycloak-theme/login/pages/code/Page.tsx +6 -6
  35. package/keycloak-theme/login/pages/delete-account-confirm/Page.stories.tsx +0 -2
  36. package/keycloak-theme/login/pages/delete-account-confirm/Page.tsx +3 -6
  37. package/keycloak-theme/login/pages/delete-credential/Page.stories.tsx +0 -1
  38. package/keycloak-theme/login/pages/delete-credential/Page.tsx +11 -6
  39. package/keycloak-theme/login/pages/error/Page.stories.tsx +0 -1
  40. package/keycloak-theme/login/pages/error/Page.tsx +13 -12
  41. package/keycloak-theme/login/pages/frontchannel-logout/Page.tsx +2 -4
  42. package/keycloak-theme/login/pages/idp-review-user-profile/Page.stories.tsx +0 -1
  43. package/keycloak-theme/login/pages/idp-review-user-profile/Page.tsx +2 -5
  44. package/keycloak-theme/login/pages/info/Page.tsx +8 -6
  45. package/keycloak-theme/login/pages/link-idp-action/Page.tsx +5 -3
  46. package/keycloak-theme/login/pages/login/Form.tsx +36 -38
  47. package/keycloak-theme/login/pages/login/Page.stories.tsx +4 -3
  48. package/keycloak-theme/login/pages/login/Page.tsx +0 -1
  49. package/keycloak-theme/login/pages/login/SocialProviders.tsx +14 -23
  50. package/keycloak-theme/login/pages/login/providers/github.svg +4 -3
  51. package/keycloak-theme/login/pages/login/providers/x.svg +4 -3
  52. package/keycloak-theme/login/pages/login/useProviderLogos.tsx +2 -3
  53. package/keycloak-theme/login/pages/login-config-totp/Page.stories.tsx +0 -1
  54. package/keycloak-theme/login/pages/login-config-totp/Page.tsx +25 -12
  55. package/keycloak-theme/login/pages/login-idp-link-confirm/Page.stories.tsx +0 -1
  56. package/keycloak-theme/login/pages/login-idp-link-confirm/Page.tsx +4 -7
  57. package/keycloak-theme/login/pages/login-idp-link-confirm-override/Page.stories.tsx +0 -1
  58. package/keycloak-theme/login/pages/login-idp-link-confirm-override/Page.tsx +4 -7
  59. package/keycloak-theme/login/pages/login-idp-link-email/Page.stories.tsx +0 -1
  60. package/keycloak-theme/login/pages/login-idp-link-email/Page.tsx +4 -7
  61. package/keycloak-theme/login/pages/login-oauth-grant/Page.tsx +21 -11
  62. package/keycloak-theme/login/pages/login-oauth2-device-verify-user-code/Page.tsx +5 -7
  63. package/keycloak-theme/login/pages/login-otp/Page.stories.tsx +0 -1
  64. package/keycloak-theme/login/pages/login-otp/Page.tsx +35 -26
  65. package/keycloak-theme/login/pages/login-page-expired/Page.stories.tsx +0 -1
  66. package/keycloak-theme/login/pages/login-page-expired/Page.tsx +4 -6
  67. package/keycloak-theme/login/pages/login-passkeys-conditional-authenticate/Page.tsx +153 -96
  68. package/keycloak-theme/login/pages/login-password/Page.tsx +14 -15
  69. package/keycloak-theme/login/pages/login-password/useScript.tsx +0 -1
  70. package/keycloak-theme/login/pages/login-recovery-authn-code-config/Page.tsx +5 -8
  71. package/keycloak-theme/login/pages/login-recovery-authn-code-input/Page.tsx +2 -3
  72. package/keycloak-theme/login/pages/login-reset-otp/Page.stories.tsx +0 -1
  73. package/keycloak-theme/login/pages/login-reset-otp/Page.tsx +3 -4
  74. package/keycloak-theme/login/pages/login-reset-password/Form.tsx +5 -6
  75. package/keycloak-theme/login/pages/login-reset-password/Page.stories.tsx +0 -1
  76. package/keycloak-theme/login/pages/login-reset-password/Page.tsx +3 -3
  77. package/keycloak-theme/login/pages/login-update-password/Page.stories.tsx +0 -1
  78. package/keycloak-theme/login/pages/login-update-password/Page.tsx +5 -7
  79. package/keycloak-theme/login/pages/login-update-profile/Page.stories.tsx +0 -1
  80. package/keycloak-theme/login/pages/login-update-profile/Page.tsx +6 -7
  81. package/keycloak-theme/login/pages/login-username/Page.stories.tsx +0 -1
  82. package/keycloak-theme/login/pages/login-username/Page.tsx +6 -6
  83. package/keycloak-theme/login/pages/login-verify-email/Page.stories.tsx +0 -1
  84. package/keycloak-theme/login/pages/login-verify-email/Page.tsx +3 -4
  85. package/keycloak-theme/login/pages/login-x509-info/Page.stories.tsx +0 -1
  86. package/keycloak-theme/login/pages/login-x509-info/Page.tsx +3 -6
  87. package/keycloak-theme/login/pages/logout-confirm/Page.stories.tsx +0 -1
  88. package/keycloak-theme/login/pages/logout-confirm/Page.tsx +3 -6
  89. package/keycloak-theme/login/pages/register/Form.tsx +8 -7
  90. package/keycloak-theme/login/pages/register/Page.stories.tsx +17 -8
  91. package/keycloak-theme/login/pages/register/TermsAcceptance.tsx +6 -7
  92. package/keycloak-theme/login/pages/saml-post-form/Page.stories.tsx +0 -1
  93. package/keycloak-theme/login/pages/saml-post-form/Page.tsx +4 -6
  94. package/keycloak-theme/login/pages/select-authenticator/Page.stories.tsx +0 -1
  95. package/keycloak-theme/login/pages/select-authenticator/Page.tsx +3 -6
  96. package/keycloak-theme/login/pages/select-organization/Page.tsx +5 -8
  97. package/keycloak-theme/login/pages/terms/Page.tsx +1 -3
  98. package/keycloak-theme/login/pages/update-email/Page.stories.tsx +0 -1
  99. package/keycloak-theme/login/pages/update-email/Page.tsx +6 -7
  100. package/keycloak-theme/login/pages/webauthn-authenticate/Page.stories.tsx +0 -1
  101. package/keycloak-theme/login/pages/webauthn-authenticate/Page.tsx +50 -46
  102. package/keycloak-theme/login/pages/webauthn-error/Page.stories.tsx +2 -5
  103. package/keycloak-theme/login/pages/webauthn-error/Page.tsx +3 -6
  104. package/keycloak-theme/login/pages/webauthn-register/Page.stories.tsx +0 -1
  105. package/keycloak-theme/login/pages/webauthn-register/Page.tsx +4 -4
  106. package/keycloak-theme/login/styleLevelCustomization.tsx +5 -6
  107. package/keycloak-theme/public/site.webmanifest +11 -1
  108. package/package.json +2 -2
@@ -1,27 +1,26 @@
1
- "use client";
1
+ import * as SeparatorPrimitive from "@radix-ui/react-separator"
2
+ import * as React from "react"
2
3
 
3
- import * as SeparatorPrimitive from "@radix-ui/react-separator";
4
- import * as React from "react";
4
+ import { cn } from '../lib/utils'
5
5
 
6
- import { cn } from "@/components/lib/utils";
7
-
8
- const Separator = React.forwardRef<
9
- React.ElementRef<typeof SeparatorPrimitive.Root>,
10
- React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
11
- >(({ className, orientation = "horizontal", decorative = true, ...props }, ref) => (
12
- <SeparatorPrimitive.Root
13
- ref={ref}
14
- decorative={decorative}
15
- orientation={orientation}
16
- className={cn(
17
- "shrink-0 bg-border",
18
- orientation === "horizontal" ? "h-px w-full" : "h-full w-px",
19
- className
20
- )}
21
- {...props}
22
- />
23
- ));
24
- Separator.displayName = SeparatorPrimitive.Root.displayName;
25
-
26
- export { Separator };
6
+ function Separator({
7
+ className,
8
+ orientation = "horizontal",
9
+ decorative = true,
10
+ ...props
11
+ }: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
12
+ return (
13
+ <SeparatorPrimitive.Root
14
+ data-slot="separator"
15
+ decorative={decorative}
16
+ orientation={orientation}
17
+ className={cn(
18
+ "bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
19
+ className
20
+ )}
21
+ {...props}
22
+ />
23
+ )
24
+ }
27
25
 
26
+ export { Separator }
@@ -1,31 +1,60 @@
1
- import * as TooltipPrimitive from "@radix-ui/react-tooltip";
2
- import * as React from "react";
1
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip"
2
+ import * as React from "react"
3
3
 
4
- import { cn } from "@/components/lib/utils";
4
+ import { cn } from '../lib/utils'
5
5
 
6
- const TooltipProvider = TooltipPrimitive.Provider;
6
+ function TooltipProvider({
7
+ delayDuration = 0,
8
+ ...props
9
+ }: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
10
+ return (
11
+ <TooltipPrimitive.Provider
12
+ data-slot="tooltip-provider"
13
+ delayDuration={delayDuration}
14
+ {...props}
15
+ />
16
+ )
17
+ }
7
18
 
8
- const Tooltip = TooltipPrimitive.Root;
19
+ function Tooltip({
20
+ ...props
21
+ }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
22
+ return (
23
+ <TooltipProvider>
24
+ <TooltipPrimitive.Root data-slot="tooltip" {...props} />
25
+ </TooltipProvider>
26
+ )
27
+ }
9
28
 
10
- const TooltipTrigger = TooltipPrimitive.Trigger;
29
+ function TooltipTrigger({
30
+ ...props
31
+ }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
32
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
33
+ }
11
34
 
12
- const TooltipContent = React.forwardRef<
13
- React.ElementRef<typeof TooltipPrimitive.Content>,
14
- React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
15
- >(({ className, sideOffset = 4, ...props }, ref) => (
16
- <TooltipPrimitive.Portal>
17
- <TooltipPrimitive.Content
18
- ref={ref}
19
- sideOffset={sideOffset}
20
- className={cn(
21
- "z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]",
22
- className
23
- )}
24
- {...props}
25
- />
26
- </TooltipPrimitive.Portal>
27
- ));
28
- TooltipContent.displayName = TooltipPrimitive.Content.displayName;
35
+ function TooltipContent({
36
+ className,
37
+ sideOffset = 0,
38
+ children,
39
+ ...props
40
+ }: React.ComponentProps<typeof TooltipPrimitive.Content>) {
41
+ return (
42
+ <TooltipPrimitive.Portal>
43
+ <TooltipPrimitive.Content
44
+ data-slot="tooltip-content"
45
+ sideOffset={sideOffset}
46
+ className={cn(
47
+ "bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
48
+ className
49
+ )}
50
+ {...props}
51
+ >
52
+ {children}
53
+ <TooltipPrimitive.Arrow className="bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%-2px)] rotate-45 rounded-[2px]" />
54
+ </TooltipPrimitive.Content>
55
+ </TooltipPrimitive.Portal>
56
+ )
57
+ }
29
58
 
30
- export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
59
+ export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }
31
60
 
@@ -4,13 +4,9 @@ import type { ReactNode } from "react";
4
4
  import { assert } from "tsafe/assert";
5
5
  import { type KcContext, KcContextProvider } from "./KcContext";
6
6
  import { I18nProvider } from "./i18n";
7
- import "./index.css";
8
7
  import { PageIndex } from "./pages/PageIndex";
9
8
  import { useStyleLevelCustomization } from "./styleLevelCustomization";
10
9
 
11
-
12
-
13
-
14
10
  export default function KcPage(props: { kcContext: KcContext }) {
15
11
  const { kcContext } = props;
16
12
 
@@ -28,7 +24,8 @@ export default function KcPage(props: { kcContext: KcContext }) {
28
24
  function StyleLevelCustomization(props: { children: ReactNode }) {
29
25
  const { children } = props;
30
26
 
31
- const { doUseDefaultCss, classes, loadCustomStylesheet, Provider } = useStyleLevelCustomization();
27
+ const { doUseDefaultCss, classes, loadCustomStylesheet, Provider } =
28
+ useStyleLevelCustomization();
32
29
 
33
30
  useExclusiveAppInstanceEffect({
34
31
  effectId: "loadCustomStylesheet",
@@ -1,10 +1,8 @@
1
- import { Checkbox } from '@/components/ui/checkbox';
2
- import { useI18n } from '@/login/i18n';
3
- import { Label } from '@radix-ui/react-label';
4
-
1
+ import { Checkbox } from "@/components/ui/checkbox";
2
+ import { useI18n } from "@/login/i18n";
3
+ import { Label } from "@radix-ui/react-label";
5
4
 
6
5
  export function LogoutOtherSessions() {
7
-
8
6
  const { msg } = useI18n();
9
7
 
10
8
  return (
@@ -1,8 +1,10 @@
1
- import { useI18n } from '@/login/i18n';
2
- import { useKcContext } from '@/login/KcContext';
1
+ import { useI18n } from "@/login/i18n";
2
+ import { useKcContext } from "@/login/KcContext";
3
3
  import { useIsPasswordRevealed } from "keycloakify/tools/useIsPasswordRevealed";
4
+ import type { JSX } from 'react';
4
5
  import { FiEye, FiEyeOff } from "react-icons/fi";
5
6
 
7
+
6
8
  export function PasswordWrapper(props: {
7
9
  passwordInputId: string;
8
10
  children: JSX.Element;
@@ -12,12 +14,10 @@ export function PasswordWrapper(props: {
12
14
 
13
15
  const { msgStr } = useI18n();
14
16
 
15
-
16
17
  const { isPasswordRevealed, toggleIsPasswordRevealed } = useIsPasswordRevealed({
17
18
  passwordInputId
18
19
  });
19
20
 
20
-
21
21
  return (
22
22
  <div className="relative">
23
23
  {children}
@@ -1,17 +1,22 @@
1
- import { Languages } from '@/components/langauges';
2
- import { ModeToggle } from '@/components/theme-toggle';
3
- import { Alert, AlertDescription } from '@/components/ui/alert';
4
- import { Button } from '@/components/ui/button';
5
- import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
6
- import { redirectUrlOrigin } from '@/login/shared/redirectUrlOrigin';
1
+ import { Languages } from "@/components/langauges";
2
+ import { ModeToggle } from "@/components/theme-toggle";
3
+ import { Alert, AlertDescription } from "@/components/ui/alert";
4
+ import { Button } from "@/components/ui/button";
5
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
6
+ import { redirectUrlOrigin } from "@/login/shared/redirectUrlOrigin";
7
7
  import { kcSanitize } from "@keycloakify/login-ui/kcSanitize";
8
8
  import { useKcClsx } from "@keycloakify/login-ui/useKcClsx";
9
- import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@radix-ui/react-tooltip';
9
+ import {
10
+ Tooltip,
11
+ TooltipContent,
12
+ TooltipProvider,
13
+ TooltipTrigger
14
+ } from "@radix-ui/react-tooltip";
10
15
  import { useSetClassName } from "keycloakify/tools/useSetClassName";
11
- import { RotateCcw } from 'lucide-react';
16
+ import { RotateCcw } from "lucide-react";
12
17
  import type { ReactNode } from "react";
13
18
  import { useEffect } from "react";
14
- import { FiHome } from 'react-icons/fi';
19
+ import { FiHome } from "react-icons/fi";
15
20
  import { useI18n } from "../../i18n";
16
21
  import { useKcContext } from "../../KcContext";
17
22
  import companylogo from "./../../assets/img/auth-logo.svg";
@@ -47,7 +52,6 @@ export function Template(props: {
47
52
 
48
53
  const { auth, url, message, isAppInitiatedAction } = kcContext;
49
54
 
50
-
51
55
  const { msg, msgStr, enabledLanguages } = useI18n();
52
56
 
53
57
  const { kcClsx } = useKcClsx();
@@ -79,20 +83,15 @@ export function Template(props: {
79
83
  <div className="flex flex-col gap-4 px-0 py-0 pb-6 lg:p-6 lg:md:p-10 lg:pt-10 min-h-screen lg:min-h-0">
80
84
  {/* navigation */}
81
85
  <div className="absolute top-4 right-4 lg:left-4 z-20 flex gap-2">
82
- <Button variant="outline" size="icon" >
86
+ <Button variant="outline" size="icon">
83
87
  <a href={kcContext.client.baseUrl ?? redirectUrlOrigin}>
84
88
  <FiHome />
85
89
  </a>
86
90
  </Button>
87
91
 
88
- {enabledLanguages.length > 1 && (
89
- <Languages />
90
- )}
91
-
92
+ {enabledLanguages.length > 1 && <Languages />}
92
93
 
93
- {kcContext.darkMode !== false && (
94
- <ModeToggle />
95
- )}
94
+ {kcContext.darkMode !== false && <ModeToggle />}
96
95
  </div>
97
96
 
98
97
  {/* Mobile header with logo */}
@@ -109,32 +108,54 @@ export function Template(props: {
109
108
  <div className="flex flex-1 items-start lg:items-center justify-center lg:mt-0 ">
110
109
  <div className="w-full max-w-xl ">
111
110
  <Card className=" shadow-none bg-transparent lg:bg-card border-0 lg:rounded-lg lg:border lg:shadow-sm rounded-t-2xl">
112
- <CardHeader className="text-center mb-3 px-6 pt-8 pb-4 lg:pt-6">
111
+ <CardHeader className="text-center">
113
112
  <CardTitle>
114
113
  {(() => {
115
- const node = !(auth !== undefined && auth.showUsername && !auth.showResetCredentials) ? (
114
+ const node = !(
115
+ auth !== undefined &&
116
+ auth.showUsername &&
117
+ !auth.showResetCredentials
118
+ ) ? (
116
119
  <h1 className="text-xl">{headerNode}</h1>
117
120
  ) : (
118
- <div id="kc-username" className="flex items-center justify-center gap-2">
119
- <label className="font-semibold text-lg" id="kc-attempted-username">
121
+ <div
122
+ id="kc-username"
123
+ className="flex items-center justify-center gap-2"
124
+ >
125
+ <label
126
+ className="font-semibold text-lg"
127
+ id="kc-attempted-username"
128
+ >
120
129
  {auth.attemptedUsername}
121
130
  </label>
122
131
 
123
132
  <TooltipProvider>
124
133
  <Tooltip>
125
134
  <TooltipTrigger asChild>
126
- <Button variant="outline" size="icon" asChild>
135
+ <Button
136
+ variant="outline"
137
+ size="icon"
138
+ asChild
139
+ >
127
140
  <a
128
141
  id="reset-login"
129
- href={url.loginRestartFlowUrl}
130
- aria-label={msgStr("restartLoginTooltip")}
142
+ href={
143
+ url.loginRestartFlowUrl
144
+ }
145
+ aria-label={msgStr(
146
+ "restartLoginTooltip"
147
+ )}
131
148
  >
132
149
  <RotateCcw className="h-4 w-4" />
133
150
  </a>
134
151
  </Button>
135
152
  </TooltipTrigger>
136
153
  <TooltipContent>
137
- <p>{msg("restartLoginTooltip")}</p>
154
+ <p>
155
+ {msg(
156
+ "restartLoginTooltip"
157
+ )}
158
+ </p>
138
159
  </TooltipContent>
139
160
  </Tooltip>
140
161
  </TooltipProvider>
@@ -147,7 +168,9 @@ export function Template(props: {
147
168
  <div>{node}</div>
148
169
  <div>
149
170
  <span className="subtitle">
150
- <span className="text-red-500">*</span>
171
+ <span className="text-red-500">
172
+ *
173
+ </span>
151
174
  {msg("requiredFields")}
152
175
  </span>
153
176
  </div>
@@ -159,42 +182,69 @@ export function Template(props: {
159
182
  })()}
160
183
  </CardTitle>
161
184
  </CardHeader>
162
- <CardContent className="px-6 pb-8">
185
+ <CardContent >
163
186
  <div id="kc-content">
164
187
  <div id="kc-content-wrapper">
165
- {displayMessage && message !== undefined && (message.type !== "warning" || !isAppInitiatedAction) && (
166
- <Alert variant={message.type} className="my-3">
167
- <AlertDescription>
168
- <div>
169
- <span
170
- dangerouslySetInnerHTML={{
171
- __html: kcSanitize(message.summary)
172
- }}
173
- />
174
- </div>
175
- </AlertDescription>
176
- </Alert>
177
- )}
188
+ {displayMessage &&
189
+ message !== undefined &&
190
+ (message.type !== "warning" ||
191
+ !isAppInitiatedAction) && (
192
+ <Alert
193
+ variant={message.type}
194
+ className="my-3"
195
+ >
196
+ <AlertDescription>
197
+ <div>
198
+ <span
199
+ dangerouslySetInnerHTML={{
200
+ __html: kcSanitize(
201
+ message.summary
202
+ )
203
+ }}
204
+ />
205
+ </div>
206
+ </AlertDescription>
207
+ </Alert>
208
+ )}
178
209
  <div className="children">{children}</div>
179
210
  {socialProvidersNode}
180
- {auth !== undefined && auth.showTryAnotherWayLink && (
181
- <form id="kc-select-try-another-way-form" action={url.loginAction} method="post">
182
- <div className={kcClsx("kcFormGroupClass")}>
183
- <input type="hidden" name="tryAnotherWay" value="on" />
184
- <a
185
- href="#"
186
- id="try-another-way"
187
- onClick={() => {
188
- document.forms["kc-select-try-another-way-form" as never].submit();
189
- return false;
190
- }}
211
+ {auth !== undefined &&
212
+ auth.showTryAnotherWayLink && (
213
+ <form
214
+ id="kc-select-try-another-way-form"
215
+ action={url.loginAction}
216
+ method="post"
217
+ >
218
+ <div
219
+ className={kcClsx(
220
+ "kcFormGroupClass"
221
+ )}
191
222
  >
192
- {msg("doTryAnotherWay")}
193
- </a>
194
- </div>
195
- </form>
223
+ <input
224
+ type="hidden"
225
+ name="tryAnotherWay"
226
+ value="on"
227
+ />
228
+ <a
229
+ href="#"
230
+ id="try-another-way"
231
+ onClick={() => {
232
+ document.forms[
233
+ "kc-select-try-another-way-form" as never
234
+ ].submit();
235
+ return false;
236
+ }}
237
+ >
238
+ {msg("doTryAnotherWay")}
239
+ </a>
240
+ </div>
241
+ </form>
242
+ )}
243
+ {displayInfo && (
244
+ <div className="text-center text-sm mt-4">
245
+ {infoNode}
246
+ </div>
196
247
  )}
197
- {displayInfo && <div className="text-center text-sm mt-4">{infoNode}</div>}
198
248
  </div>
199
249
  </div>
200
250
  </CardContent>
@@ -218,7 +268,9 @@ export function Template(props: {
218
268
  <span className="text-white text-xl"> {APP_NAME}</span>
219
269
  </div>
220
270
 
221
- <p className="text-center text-gray-400 dark:text-white/60">{msg("welcomeMessage")}</p>
271
+ <p className="text-center text-gray-400 dark:text-white/60">
272
+ {msg("welcomeMessage")}
273
+ </p>
222
274
  </div>
223
275
  </div>
224
276
  </div>
@@ -1,5 +1,5 @@
1
- import { Button } from '@/components/ui/button';
2
- import { useI18n } from '@/login/i18n';
1
+ import { Button } from "@/components/ui/button";
2
+ import { useI18n } from "@/login/i18n";
3
3
  import type { Attribute } from "@keycloakify/login-ui/KcContext";
4
4
  import {
5
5
  getButtonToDisplayForMultivaluedAttributeField,
@@ -16,7 +16,11 @@ export function AddRemoveButtonsMultiValuedAttribute(props: {
16
16
 
17
17
  const { msg } = useI18n();
18
18
 
19
- const { hasAdd, hasRemove } = getButtonToDisplayForMultivaluedAttributeField({ attribute, values, fieldIndex });
19
+ const { hasAdd, hasRemove } = getButtonToDisplayForMultivaluedAttributeField({
20
+ attribute,
21
+ values,
22
+ fieldIndex
23
+ });
20
24
 
21
25
  const idPostfix = `-${attribute.name}-${fieldIndex + 1}`;
22
26
 
@@ -1,4 +1,4 @@
1
- import { FieldError } from '@/components/ui/field';
1
+ import { FieldError } from "@/components/ui/field";
2
2
  import type { Attribute } from "@keycloakify/login-ui/KcContext";
3
3
  import type { FormFieldError } from "@keycloakify/login-ui/useUserProfileForm";
4
4
  import { Fragment } from "react";
@@ -10,14 +10,18 @@ export function FieldErrors(props: {
10
10
  }) {
11
11
  const { attribute, fieldIndex } = props;
12
12
 
13
- const displayableErrors = props.displayableErrors.filter(error => error.fieldIndex === fieldIndex);
13
+ const displayableErrors = props.displayableErrors.filter(
14
+ error => error.fieldIndex === fieldIndex
15
+ );
14
16
 
15
17
  if (displayableErrors.length === 0) {
16
18
  return null;
17
19
  }
18
20
 
19
21
  return (
20
- <FieldError id={`input-error-${attribute.name}${fieldIndex === undefined ? "" : `-${fieldIndex}`}`}>
22
+ <FieldError
23
+ id={`input-error-${attribute.name}${fieldIndex === undefined ? "" : `-${fieldIndex}`}`}
24
+ >
21
25
  {displayableErrors.map(({ errorMessage }, i, arr) => (
22
26
  <Fragment key={i}>
23
27
  {errorMessage}
@@ -26,4 +30,4 @@ export function FieldErrors(props: {
26
30
  ))}
27
31
  </FieldError>
28
32
  );
29
- }
33
+ }
@@ -1,9 +1,7 @@
1
-
2
-
3
- import { cn } from '@/components/lib/utils';
4
- import { useI18n } from '@/login/i18n';
1
+ import { cn } from "@/components/lib/utils";
2
+ import { useI18n } from "@/login/i18n";
5
3
  import type { Attribute } from "@keycloakify/login-ui/KcContext";
6
- import { useKcClsx } from '@keycloakify/login-ui/useKcClsx';
4
+ import { useKcClsx } from "@keycloakify/login-ui/useKcClsx";
7
5
  import { assert } from "tsafe/assert";
8
6
 
9
7
  export function GroupLabel(props: {
@@ -18,7 +16,6 @@ export function GroupLabel(props: {
18
16
 
19
17
  const { kcClsx } = useKcClsx();
20
18
 
21
-
22
19
  if (attribute.group?.name !== groupNameRef.current) {
23
20
  groupNameRef.current = attribute.group?.name ?? "";
24
21
 
@@ -27,32 +24,54 @@ export function GroupLabel(props: {
27
24
 
28
25
  return (
29
26
  <div
30
- className={cn("space-y-4 p-4 border rounded-lg bg-card", kcClsx("kcFormGroupClass"))}
31
- {...Object.fromEntries(Object.entries(attribute.group.html5DataAnnotations).map(([key, value]) => [`data-${key}`, value]))}
27
+ className={cn(
28
+ "space-y-4 p-4 border rounded-lg bg-card",
29
+ kcClsx("kcFormGroupClass")
30
+ )}
31
+ {...Object.fromEntries(
32
+ Object.entries(attribute.group.html5DataAnnotations).map(
33
+ ([key, value]) => [`data-${key}`, value]
34
+ )
35
+ )}
32
36
  >
33
37
  {(() => {
34
38
  const groupDisplayHeader = attribute.group.displayHeader ?? "";
35
- const groupHeaderText = groupDisplayHeader !== "" ? advancedMsg(groupDisplayHeader) : attribute.group.name;
39
+ const groupHeaderText =
40
+ groupDisplayHeader !== ""
41
+ ? advancedMsg(groupDisplayHeader)
42
+ : attribute.group.name;
36
43
 
37
44
  return (
38
45
  <div className={cn("", kcClsx("kcContentWrapperClass"))}>
39
- <h3 id={`header-${attribute.group.name}`} className={cn("text-lg font-semibold", kcClsx("kcFormGroupHeader"))}>
46
+ <h3
47
+ id={`header-${attribute.group.name}`}
48
+ className={cn(
49
+ "text-lg font-semibold",
50
+ kcClsx("kcFormGroupHeader")
51
+ )}
52
+ >
40
53
  {groupHeaderText}
41
54
  </h3>
42
55
  </div>
43
56
  );
44
57
  })()}
45
58
  {(() => {
46
- const groupDisplayDescription = attribute.group.displayDescription ?? "";
59
+ const groupDisplayDescription =
60
+ attribute.group.displayDescription ?? "";
47
61
 
48
62
  if (groupDisplayDescription !== "") {
49
- const groupDescriptionText = advancedMsg(groupDisplayDescription);
63
+ const groupDescriptionText = advancedMsg(
64
+ groupDisplayDescription
65
+ );
50
66
 
51
67
  return (
52
68
  <div className={cn("", kcClsx("kcLabelWrapperClass"))}>
53
69
  <p
54
70
  id={`description-${attribute.group.name}`}
55
- className={cn("text-sm text-muted-foreground", kcClsx("kcLabelClass"))}
71
+ className={cn(
72
+ "text-sm text-muted-foreground",
73
+ kcClsx("kcLabelClass")
74
+ )}
56
75
  >
57
76
  {groupDescriptionText}
58
77
  </p>
@@ -68,4 +87,4 @@ export function GroupLabel(props: {
68
87
  }
69
88
 
70
89
  return null;
71
- }
90
+ }
@@ -23,7 +23,14 @@ export function InputFieldByType(props: InputFieldByTypeProps) {
23
23
  // NOTE: Unfortunately, keycloak won't let you define input type="hidden" in the Admin Console.
24
24
  // sometimes in the future it might.
25
25
  case "hidden":
26
- return <input type="hidden" id={attribute.name} name={attribute.name} value={valueOrValues as string} />;
26
+ return (
27
+ <input
28
+ type="hidden"
29
+ id={attribute.name}
30
+ name={attribute.name}
31
+ value={valueOrValues as string}
32
+ />
33
+ );
27
34
  case "textarea":
28
35
  return <TextareaTag {...props} />;
29
36
  case "select":
@@ -56,4 +63,4 @@ export function InputFieldByType(props: InputFieldByTypeProps) {
56
63
  return inputNode;
57
64
  }
58
65
  }
59
- }
66
+ }
@@ -1,4 +1,3 @@
1
-
2
1
  import type { Attribute } from "@keycloakify/login-ui/KcContext";
3
2
  import { useI18n } from "../../i18n";
4
3