Drop dependency to @emotion/react

This commit is contained in:
garronej 2022-10-16 00:49:49 +02:00
parent d8206434bc
commit 8702ec29a8
23 changed files with 328 additions and 355 deletions

View File

@ -55,12 +55,10 @@
], ],
"homepage": "https://github.com/garronej/keycloakify", "homepage": "https://github.com/garronej/keycloakify",
"peerDependencies": { "peerDependencies": {
"@emotion/react": "^11.4.1",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0" "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.0.0", "@babel/core": "^7.0.0",
"@emotion/react": "^11.4.1",
"@types/memoizee": "^0.4.7", "@types/memoizee": "^0.4.7",
"@types/minimist": "^1.2.2", "@types/minimist": "^1.2.2",
"@types/node": "^17.0.25", "@types/node": "^17.0.25",
@ -72,6 +70,7 @@
"properties-parser": "^0.3.1", "properties-parser": "^0.3.1",
"react": "18.1.0", "react": "18.1.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"@emotion/react": "^11.10.4",
"typescript": "^4.2.3" "typescript": "^4.2.3"
}, },
"dependencies": { "dependencies": {
@ -88,7 +87,7 @@
"rfc4648": "^1.5.2", "rfc4648": "^1.5.2",
"scripting-tools": "^0.19.13", "scripting-tools": "^0.19.13",
"tsafe": "^1.1.3", "tsafe": "^1.1.3",
"tss-react": "^4.3.4", "tss-react": "4.4.1-rc.0",
"zod": "^3.17.10" "zod": "^3.17.10"
} }
} }

View File

@ -13,11 +13,11 @@
"packageRules": [ "packageRules": [
{ {
"packagePatterns": ["*"], "packagePatterns": ["*"],
"excludePackagePatterns": ["tss-react", "powerhooks", "tsafe", "evt"], "excludePackagePatterns": ["powerhooks", "tsafe", "evt"],
"enabled": false "enabled": false
}, },
{ {
"packagePatterns": ["tss-react", "powerhooks", "tsafe", "evt"], "packagePatterns": ["powerhooks", "tsafe", "evt"],
"matchUpdateTypes": ["minor", "patch"], "matchUpdateTypes": ["minor", "patch"],
"automerge": true, "automerge": true,
"automergeType": "branch", "automergeType": "branch",

View File

@ -3,7 +3,7 @@ import DefaultTemplate from "./Template";
import type { TemplateProps } from "./Template"; import type { TemplateProps } from "./Template";
import type { KcProps } from "./KcProps"; import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase"; import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useCssAndCx } from "../tools/useCssAndCx"; import { clsx } from "../tools/clsx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
import { UserProfileFormFields } from "./shared/UserProfileCommons"; import { UserProfileFormFields } from "./shared/UserProfileCommons";
@ -17,8 +17,6 @@ export type IdpReviewUserProfileProps = KcProps & {
const IdpReviewUserProfile = memo((props: IdpReviewUserProfileProps) => { const IdpReviewUserProfile = memo((props: IdpReviewUserProfileProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props; const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { cx } = useCssAndCx();
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
const { url } = kcContext; const { url } = kcContext;
@ -30,16 +28,16 @@ const IdpReviewUserProfile = memo((props: IdpReviewUserProfileProps) => {
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
headerNode={msg("loginIdpReviewProfileTitle")} headerNode={msg("loginIdpReviewProfileTitle")}
formNode={ formNode={
<form id="kc-idp-review-profile-form" className={cx(kcProps.kcFormClass)} action={url.loginAction} method="post"> <form id="kc-idp-review-profile-form" className={clsx(kcProps.kcFormClass)} action={url.loginAction} method="post">
<UserProfileFormFields kcContext={kcContext} onIsFormSubmittableValueChange={setIsFomSubmittable} i18n={i18n} {...kcProps} /> <UserProfileFormFields kcContext={kcContext} onIsFormSubmittableValueChange={setIsFomSubmittable} i18n={i18n} {...kcProps} />
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(kcProps.kcFormOptionsClass)}> <div id="kc-form-options" className={clsx(kcProps.kcFormOptionsClass)}>
<div className={cx(kcProps.kcFormOptionsWrapperClass)} /> <div className={clsx(kcProps.kcFormOptionsWrapperClass)} />
</div> </div>
<div id="kc-form-buttons" className={cx(kcProps.kcFormButtonsClass)}> <div id="kc-form-buttons" className={clsx(kcProps.kcFormButtonsClass)}>
<input <input
className={cx( className={clsx(
kcProps.kcButtonClass, kcProps.kcButtonClass,
kcProps.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
kcProps.kcButtonBlockClass, kcProps.kcButtonBlockClass,

View File

@ -3,7 +3,7 @@ import DefaultTemplate from "./Template";
import type { TemplateProps } from "./Template"; import type { TemplateProps } from "./Template";
import type { KcProps } from "./KcProps"; import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase"; import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useCssAndCx } from "../tools/useCssAndCx"; import { clsx } from "../tools/clsx";
import { useConstCallback } from "powerhooks/useConstCallback"; import { useConstCallback } from "powerhooks/useConstCallback";
import type { FormEventHandler } from "react"; import type { FormEventHandler } from "react";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
@ -22,8 +22,6 @@ const Login = memo((props: LoginProps) => {
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
const { cx } = useCssAndCx();
const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false); const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false);
const onSubmit = useConstCallback<FormEventHandler<HTMLFormElement>>(e => { const onSubmit = useConstCallback<FormEventHandler<HTMLFormElement>>(e => {
@ -47,16 +45,16 @@ const Login = memo((props: LoginProps) => {
displayWide={realm.password && social.providers !== undefined} displayWide={realm.password && social.providers !== undefined}
headerNode={msg("doLogIn")} headerNode={msg("doLogIn")}
formNode={ formNode={
<div id="kc-form" className={cx(realm.password && social.providers !== undefined && kcProps.kcContentWrapperClass)}> <div id="kc-form" className={clsx(realm.password && social.providers !== undefined && kcProps.kcContentWrapperClass)}>
<div <div
id="kc-form-wrapper" id="kc-form-wrapper"
className={cx( className={clsx(
realm.password && social.providers && [kcProps.kcFormSocialAccountContentClass, kcProps.kcFormSocialAccountClass] realm.password && social.providers && [kcProps.kcFormSocialAccountContentClass, kcProps.kcFormSocialAccountClass]
)} )}
> >
{realm.password && ( {realm.password && (
<form id="kc-form-login" onSubmit={onSubmit} action={url.loginAction} method="post"> <form id="kc-form-login" onSubmit={onSubmit} action={url.loginAction} method="post">
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)}>
{(() => { {(() => {
const label = !realm.loginWithEmailAllowed const label = !realm.loginWithEmailAllowed
? "username" ? "username"
@ -68,13 +66,13 @@ const Login = memo((props: LoginProps) => {
return ( return (
<> <>
<label htmlFor={autoCompleteHelper} className={cx(kcProps.kcLabelClass)}> <label htmlFor={autoCompleteHelper} className={clsx(kcProps.kcLabelClass)}>
{msg(label)} {msg(label)}
</label> </label>
<input <input
tabIndex={1} tabIndex={1}
id={autoCompleteHelper} id={autoCompleteHelper}
className={cx(kcProps.kcInputClass)} className={clsx(kcProps.kcInputClass)}
//NOTE: This is used by Google Chrome auto fill so we use it to tell //NOTE: This is used by Google Chrome auto fill so we use it to tell
//the browser how to pre fill the form but before submit we put it back //the browser how to pre fill the form but before submit we put it back
//to username because it is what keycloak expects. //to username because it is what keycloak expects.
@ -92,20 +90,20 @@ const Login = memo((props: LoginProps) => {
); );
})()} })()}
</div> </div>
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)}>
<label htmlFor="password" className={cx(kcProps.kcLabelClass)}> <label htmlFor="password" className={clsx(kcProps.kcLabelClass)}>
{msg("password")} {msg("password")}
</label> </label>
<input <input
tabIndex={2} tabIndex={2}
id="password" id="password"
className={cx(kcProps.kcInputClass)} className={clsx(kcProps.kcInputClass)}
name="password" name="password"
type="password" type="password"
autoComplete="off" autoComplete="off"
/> />
</div> </div>
<div className={cx(kcProps.kcFormGroupClass, kcProps.kcFormSettingClass)}> <div className={clsx(kcProps.kcFormGroupClass, kcProps.kcFormSettingClass)}>
<div id="kc-form-options"> <div id="kc-form-options">
{realm.rememberMe && !usernameEditDisabled && ( {realm.rememberMe && !usernameEditDisabled && (
<div className="checkbox"> <div className="checkbox">
@ -126,7 +124,7 @@ const Login = memo((props: LoginProps) => {
</div> </div>
)} )}
</div> </div>
<div className={cx(kcProps.kcFormOptionsWrapperClass)}> <div className={clsx(kcProps.kcFormOptionsWrapperClass)}>
{realm.resetPasswordAllowed && ( {realm.resetPasswordAllowed && (
<span> <span>
<a tabIndex={5} href={url.loginResetCredentialsUrl}> <a tabIndex={5} href={url.loginResetCredentialsUrl}>
@ -136,7 +134,7 @@ const Login = memo((props: LoginProps) => {
)} )}
</div> </div>
</div> </div>
<div id="kc-form-buttons" className={cx(kcProps.kcFormGroupClass)}> <div id="kc-form-buttons" className={clsx(kcProps.kcFormGroupClass)}>
<input <input
type="hidden" type="hidden"
id="id-hidden-input" id="id-hidden-input"
@ -149,7 +147,7 @@ const Login = memo((props: LoginProps) => {
/> />
<input <input
tabIndex={4} tabIndex={4}
className={cx( className={clsx(
kcProps.kcButtonClass, kcProps.kcButtonClass,
kcProps.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
kcProps.kcButtonBlockClass, kcProps.kcButtonBlockClass,
@ -166,16 +164,16 @@ const Login = memo((props: LoginProps) => {
)} )}
</div> </div>
{realm.password && social.providers !== undefined && ( {realm.password && social.providers !== undefined && (
<div id="kc-social-providers" className={cx(kcProps.kcFormSocialAccountContentClass, kcProps.kcFormSocialAccountClass)}> <div id="kc-social-providers" className={clsx(kcProps.kcFormSocialAccountContentClass, kcProps.kcFormSocialAccountClass)}>
<ul <ul
className={cx( className={clsx(
kcProps.kcFormSocialAccountListClass, kcProps.kcFormSocialAccountListClass,
social.providers.length > 4 && kcProps.kcFormSocialAccountDoubleListClass social.providers.length > 4 && kcProps.kcFormSocialAccountDoubleListClass
)} )}
> >
{social.providers.map(p => ( {social.providers.map(p => (
<li key={p.providerId} className={cx(kcProps.kcFormSocialAccountListLinkClass)}> <li key={p.providerId} className={clsx(kcProps.kcFormSocialAccountListLinkClass)}>
<a href={p.loginUrl} id={`zocial-${p.alias}`} className={cx("zocial", p.providerId)}> <a href={p.loginUrl} id={`zocial-${p.alias}`} className={clsx("zocial", p.providerId)}>
<span>{p.displayName}</span> <span>{p.displayName}</span>
</a> </a>
</li> </li>

View File

@ -3,7 +3,7 @@ import DefaultTemplate from "./Template";
import type { TemplateProps } from "./Template"; import type { TemplateProps } from "./Template";
import type { KcProps } from "./KcProps"; import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase"; import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useCssAndCx } from "../tools/useCssAndCx"; import { clsx } from "../tools/clsx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
export type LoginConfigTotpProps = KcProps & { export type LoginConfigTotpProps = KcProps & {
@ -18,8 +18,6 @@ const LoginConfigTotp = memo((props: LoginConfigTotpProps) => {
const { url, isAppInitiatedAction, totp, mode, messagesPerField } = kcContext; const { url, isAppInitiatedAction, totp, mode, messagesPerField } = kcContext;
const { cx } = useCssAndCx();
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
const algToKeyUriAlg: Record<KcContextBase.LoginConfigTotp["totp"]["policy"]["algorithm"], string> = { const algToKeyUriAlg: Record<KcContextBase.LoginConfigTotp["totp"]["policy"]["algorithm"], string> = {
@ -102,26 +100,26 @@ const LoginConfigTotp = memo((props: LoginConfigTotpProps) => {
</li> </li>
</ol> </ol>
<form action={url.loginAction} className={cx(kcProps.kcFormClass)} id="kc-totp-settings-form" method="post"> <form action={url.loginAction} className={clsx(kcProps.kcFormClass)} id="kc-totp-settings-form" method="post">
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)}>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<label htmlFor="totp" className={cx(kcProps.kcLabelClass)}> <label htmlFor="totp" className={clsx(kcProps.kcLabelClass)}>
{msg("authenticatorCode")} {msg("authenticatorCode")}
</label>{" "} </label>{" "}
<span className="required">*</span> <span className="required">*</span>
</div> </div>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="totp" id="totp"
name="totp" name="totp"
autoComplete="off" autoComplete="off"
className={cx(kcProps.kcInputClass)} className={clsx(kcProps.kcInputClass)}
aria-invalid={messagesPerField.existsError("totp")} aria-invalid={messagesPerField.existsError("totp")}
/> />
{messagesPerField.existsError("totp") && ( {messagesPerField.existsError("totp") && (
<span id="input-error-otp-code" className={cx(kcProps.kcInputErrorMessageClass)} aria-live="polite"> <span id="input-error-otp-code" className={clsx(kcProps.kcInputErrorMessageClass)} aria-live="polite">
{messagesPerField.get("totp")} {messagesPerField.get("totp")}
</span> </span>
)} )}
@ -130,24 +128,24 @@ const LoginConfigTotp = memo((props: LoginConfigTotpProps) => {
{mode && <input type="hidden" id="mode" value={mode} />} {mode && <input type="hidden" id="mode" value={mode} />}
</div> </div>
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)}>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<label htmlFor="userLabel" className={cx(kcProps.kcLabelClass)}> <label htmlFor="userLabel" className={clsx(kcProps.kcLabelClass)}>
{msg("loginTotpDeviceName")} {msg("loginTotpDeviceName")}
</label>{" "} </label>{" "}
{totp.otpCredentials.length >= 1 && <span className="required">*</span>} {totp.otpCredentials.length >= 1 && <span className="required">*</span>}
</div> </div>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="userLabel" id="userLabel"
name="userLabel" name="userLabel"
autoComplete="off" autoComplete="off"
className={cx(kcProps.kcInputClass)} className={clsx(kcProps.kcInputClass)}
aria-invalid={messagesPerField.existsError("userLabel")} aria-invalid={messagesPerField.existsError("userLabel")}
/> />
{messagesPerField.existsError("userLabel") && ( {messagesPerField.existsError("userLabel") && (
<span id="input-error-otp-label" className={cx(kcProps.kcInputErrorMessageClass)} aria-live="polite"> <span id="input-error-otp-label" className={clsx(kcProps.kcInputErrorMessageClass)} aria-live="polite">
{messagesPerField.get("userLabel")} {messagesPerField.get("userLabel")}
</span> </span>
)} )}
@ -158,13 +156,13 @@ const LoginConfigTotp = memo((props: LoginConfigTotpProps) => {
<> <>
<input <input
type="submit" type="submit"
className={cx(kcProps.kcButtonClass, kcProps.kcButtonPrimaryClass, kcProps.kcButtonLargeClass)} className={clsx(kcProps.kcButtonClass, kcProps.kcButtonPrimaryClass, kcProps.kcButtonLargeClass)}
id="saveTOTPBtn" id="saveTOTPBtn"
value={msgStr("doSubmit")} value={msgStr("doSubmit")}
/> />
<button <button
type="submit" type="submit"
className={cx( className={clsx(
kcProps.kcButtonClass, kcProps.kcButtonClass,
kcProps.kcButtonDefaultClass, kcProps.kcButtonDefaultClass,
kcProps.kcButtonLargeClass, kcProps.kcButtonLargeClass,
@ -180,7 +178,7 @@ const LoginConfigTotp = memo((props: LoginConfigTotpProps) => {
) : ( ) : (
<input <input
type="submit" type="submit"
className={cx(kcProps.kcButtonClass, kcProps.kcButtonPrimaryClass, kcProps.kcButtonLargeClass)} className={clsx(kcProps.kcButtonClass, kcProps.kcButtonPrimaryClass, kcProps.kcButtonLargeClass)}
id="saveTOTPBtn" id="saveTOTPBtn"
value={msgStr("doSubmit")} value={msgStr("doSubmit")}
/> />

View File

@ -3,7 +3,7 @@ import DefaultTemplate from "./Template";
import type { TemplateProps } from "./Template"; import type { TemplateProps } from "./Template";
import type { KcProps } from "./KcProps"; import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase"; import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useCssAndCx } from "../tools/useCssAndCx"; import { clsx } from "../tools/clsx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
export type LoginIdpLinkConfirmProps = KcProps & { export type LoginIdpLinkConfirmProps = KcProps & {
@ -20,18 +20,16 @@ const LoginIdpLinkConfirm = memo((props: LoginIdpLinkConfirmProps) => {
const { msg } = i18n; const { msg } = i18n;
const { cx } = useCssAndCx();
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
headerNode={msg("confirmLinkIdpTitle")} headerNode={msg("confirmLinkIdpTitle")}
formNode={ formNode={
<form id="kc-register-form" action={url.loginAction} method="post"> <form id="kc-register-form" action={url.loginAction} method="post">
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)}>
<button <button
type="submit" type="submit"
className={cx( className={clsx(
kcProps.kcButtonClass, kcProps.kcButtonClass,
kcProps.kcButtonDefaultClass, kcProps.kcButtonDefaultClass,
kcProps.kcButtonBlockClass, kcProps.kcButtonBlockClass,
@ -45,7 +43,7 @@ const LoginIdpLinkConfirm = memo((props: LoginIdpLinkConfirmProps) => {
</button> </button>
<button <button
type="submit" type="submit"
className={cx( className={clsx(
kcProps.kcButtonClass, kcProps.kcButtonClass,
kcProps.kcButtonDefaultClass, kcProps.kcButtonDefaultClass,
kcProps.kcButtonBlockClass, kcProps.kcButtonBlockClass,

View File

@ -5,7 +5,7 @@ import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase"; import type { KcContextBase } from "../getKcContext/KcContextBase";
import { headInsert } from "../tools/headInsert"; import { headInsert } from "../tools/headInsert";
import { pathJoin } from "../../bin/tools/pathJoin"; import { pathJoin } from "../../bin/tools/pathJoin";
import { useCssAndCx } from "../tools/useCssAndCx"; import { clsx } from "../tools/clsx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
export type LoginOtpProps = KcProps & { export type LoginOtpProps = KcProps & {
@ -20,8 +20,6 @@ const LoginOtp = memo((props: LoginOtpProps) => {
const { otpLogin, url } = kcContext; const { otpLogin, url } = kcContext;
const { cx } = useCssAndCx();
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
useEffect(() => { useEffect(() => {
@ -46,42 +44,42 @@ const LoginOtp = memo((props: LoginOtpProps) => {
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
headerNode={msg("doLogIn")} headerNode={msg("doLogIn")}
formNode={ formNode={
<form id="kc-otp-login-form" className={cx(kcProps.kcFormClass)} action={url.loginAction} method="post"> <form id="kc-otp-login-form" className={clsx(kcProps.kcFormClass)} action={url.loginAction} method="post">
{otpLogin.userOtpCredentials.length > 1 && ( {otpLogin.userOtpCredentials.length > 1 && (
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)}>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
{otpLogin.userOtpCredentials.map(otpCredential => ( {otpLogin.userOtpCredentials.map(otpCredential => (
<div key={otpCredential.id} className={cx(kcProps.kcSelectOTPListClass)}> <div key={otpCredential.id} className={clsx(kcProps.kcSelectOTPListClass)}>
<input type="hidden" value="${otpCredential.id}" /> <input type="hidden" value="${otpCredential.id}" />
<div className={cx(kcProps.kcSelectOTPListItemClass)}> <div className={clsx(kcProps.kcSelectOTPListItemClass)}>
<span className={cx(kcProps.kcAuthenticatorOtpCircleClass)} /> <span className={clsx(kcProps.kcAuthenticatorOtpCircleClass)} />
<h2 className={cx(kcProps.kcSelectOTPItemHeadingClass)}>{otpCredential.userLabel}</h2> <h2 className={clsx(kcProps.kcSelectOTPItemHeadingClass)}>{otpCredential.userLabel}</h2>
</div> </div>
</div> </div>
))} ))}
</div> </div>
</div> </div>
)} )}
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)}>
<div className={cx(kcProps.kcLabelWrapperClass)}> <div className={clsx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="otp" className={cx(kcProps.kcLabelClass)}> <label htmlFor="otp" className={clsx(kcProps.kcLabelClass)}>
{msg("loginOtpOneTime")} {msg("loginOtpOneTime")}
</label> </label>
</div> </div>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<input id="otp" name="otp" autoComplete="off" type="text" className={cx(kcProps.kcInputClass)} autoFocus /> <input id="otp" name="otp" autoComplete="off" type="text" className={clsx(kcProps.kcInputClass)} autoFocus />
</div> </div>
</div> </div>
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(kcProps.kcFormOptionsClass)}> <div id="kc-form-options" className={clsx(kcProps.kcFormOptionsClass)}>
<div className={cx(kcProps.kcFormOptionsWrapperClass)} /> <div className={clsx(kcProps.kcFormOptionsWrapperClass)} />
</div> </div>
<div id="kc-form-buttons" className={cx(kcProps.kcFormButtonsClass)}> <div id="kc-form-buttons" className={clsx(kcProps.kcFormButtonsClass)}>
<input <input
className={cx( className={clsx(
kcProps.kcButtonClass, kcProps.kcButtonClass,
kcProps.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
kcProps.kcButtonBlockClass, kcProps.kcButtonBlockClass,

View File

@ -3,7 +3,7 @@ import DefaultTemplate from "./Template";
import type { TemplateProps } from "./Template"; import type { TemplateProps } from "./Template";
import type { KcProps } from "./KcProps"; import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase"; import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useCssAndCx } from "../tools/useCssAndCx"; import { clsx } from "../tools/clsx";
import { useConstCallback } from "powerhooks/useConstCallback"; import { useConstCallback } from "powerhooks/useConstCallback";
import type { FormEventHandler } from "react"; import type { FormEventHandler } from "react";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
@ -22,8 +22,6 @@ const LoginPassword = memo((props: LoginPasswordProps) => {
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
const { cx } = useCssAndCx();
const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false); const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false);
const onSubmit = useConstCallback<FormEventHandler<HTMLFormElement>>(e => { const onSubmit = useConstCallback<FormEventHandler<HTMLFormElement>>(e => {
@ -44,15 +42,15 @@ const LoginPassword = memo((props: LoginPasswordProps) => {
<div id="kc-form"> <div id="kc-form">
<div id="kc-form-wrapper"> <div id="kc-form-wrapper">
<form id="kc-form-login" onSubmit={onSubmit} action={url.loginAction} method="post"> <form id="kc-form-login" onSubmit={onSubmit} action={url.loginAction} method="post">
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)}>
<hr /> <hr />
<label htmlFor="password" className={cx(kcProps.kcLabelClass)}> <label htmlFor="password" className={clsx(kcProps.kcLabelClass)}>
{msg("password")} {msg("password")}
</label> </label>
<input <input
tabIndex={2} tabIndex={2}
id="password" id="password"
className={cx(kcProps.kcInputClass)} className={clsx(kcProps.kcInputClass)}
name="password" name="password"
type="password" type="password"
autoFocus={true} autoFocus={true}
@ -60,9 +58,9 @@ const LoginPassword = memo((props: LoginPasswordProps) => {
defaultValue={login.password ?? ""} defaultValue={login.password ?? ""}
/> />
</div> </div>
<div className={cx(kcProps.kcFormGroupClass, kcProps.kcFormSettingClass)}> <div className={clsx(kcProps.kcFormGroupClass, kcProps.kcFormSettingClass)}>
<div id="kc-form-options" /> <div id="kc-form-options" />
<div className={cx(kcProps.kcFormOptionsWrapperClass)}> <div className={clsx(kcProps.kcFormOptionsWrapperClass)}>
{realm.resetPasswordAllowed && ( {realm.resetPasswordAllowed && (
<span> <span>
<a tabIndex={5} href={url.loginResetCredentialsUrl}> <a tabIndex={5} href={url.loginResetCredentialsUrl}>
@ -72,10 +70,10 @@ const LoginPassword = memo((props: LoginPasswordProps) => {
)} )}
</div> </div>
</div> </div>
<div id="kc-form-buttons" className={cx(kcProps.kcFormGroupClass)}> <div id="kc-form-buttons" className={clsx(kcProps.kcFormGroupClass)}>
<input <input
tabIndex={4} tabIndex={4}
className={cx( className={clsx(
kcProps.kcButtonClass, kcProps.kcButtonClass,
kcProps.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
kcProps.kcButtonBlockClass, kcProps.kcButtonBlockClass,

View File

@ -3,7 +3,7 @@ import DefaultTemplate from "./Template";
import type { TemplateProps } from "./Template"; import type { TemplateProps } from "./Template";
import type { KcProps } from "./KcProps"; import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase"; import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useCssAndCx } from "../tools/useCssAndCx"; import { clsx } from "../tools/clsx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
export type LoginResetPasswordProps = KcProps & { export type LoginResetPasswordProps = KcProps & {
@ -20,18 +20,16 @@ const LoginResetPassword = memo((props: LoginResetPasswordProps) => {
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
const { cx } = useCssAndCx();
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
displayMessage={false} displayMessage={false}
headerNode={msg("emailForgotTitle")} headerNode={msg("emailForgotTitle")}
formNode={ formNode={
<form id="kc-reset-password-form" className={cx(kcProps.kcFormClass)} action={url.loginAction} method="post"> <form id="kc-reset-password-form" className={clsx(kcProps.kcFormClass)} action={url.loginAction} method="post">
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)}>
<div className={cx(kcProps.kcLabelWrapperClass)}> <div className={clsx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="username" className={cx(kcProps.kcLabelClass)}> <label htmlFor="username" className={clsx(kcProps.kcLabelClass)}>
{!realm.loginWithEmailAllowed {!realm.loginWithEmailAllowed
? msg("username") ? msg("username")
: !realm.registrationEmailAsUsername : !realm.registrationEmailAsUsername
@ -39,29 +37,29 @@ const LoginResetPassword = memo((props: LoginResetPasswordProps) => {
: msg("email")} : msg("email")}
</label> </label>
</div> </div>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="username" id="username"
name="username" name="username"
className={cx(kcProps.kcInputClass)} className={clsx(kcProps.kcInputClass)}
autoFocus autoFocus
defaultValue={auth !== undefined && auth.showUsername ? auth.attemptedUsername : undefined} defaultValue={auth !== undefined && auth.showUsername ? auth.attemptedUsername : undefined}
/> />
</div> </div>
</div> </div>
<div className={cx(kcProps.kcFormGroupClass, kcProps.kcFormSettingClass)}> <div className={clsx(kcProps.kcFormGroupClass, kcProps.kcFormSettingClass)}>
<div id="kc-form-options" className={cx(kcProps.kcFormOptionsClass)}> <div id="kc-form-options" className={clsx(kcProps.kcFormOptionsClass)}>
<div className={cx(kcProps.kcFormOptionsWrapperClass)}> <div className={clsx(kcProps.kcFormOptionsWrapperClass)}>
<span> <span>
<a href={url.loginUrl}>{msg("backToLogin")}</a> <a href={url.loginUrl}>{msg("backToLogin")}</a>
</span> </span>
</div> </div>
</div> </div>
<div id="kc-form-buttons" className={cx(kcProps.kcFormButtonsClass)}> <div id="kc-form-buttons" className={clsx(kcProps.kcFormButtonsClass)}>
<input <input
className={cx( className={clsx(
kcProps.kcButtonClass, kcProps.kcButtonClass,
kcProps.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
kcProps.kcButtonBlockClass, kcProps.kcButtonBlockClass,

View File

@ -3,7 +3,7 @@ import DefaultTemplate from "./Template";
import type { TemplateProps } from "./Template"; import type { TemplateProps } from "./Template";
import type { KcProps } from "./KcProps"; import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase"; import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useCssAndCx } from "../tools/useCssAndCx"; import { clsx } from "../tools/clsx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
export type LoginUpdatePasswordProps = KcProps & { export type LoginUpdatePasswordProps = KcProps & {
@ -16,8 +16,6 @@ export type LoginUpdatePasswordProps = KcProps & {
const LoginUpdatePassword = memo((props: LoginUpdatePasswordProps) => { const LoginUpdatePassword = memo((props: LoginUpdatePasswordProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props; const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { cx } = useCssAndCx();
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
const { url, messagesPerField, isAppInitiatedAction, username } = kcContext; const { url, messagesPerField, isAppInitiatedAction, username } = kcContext;
@ -27,7 +25,7 @@ const LoginUpdatePassword = memo((props: LoginUpdatePasswordProps) => {
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
headerNode={msg("updatePasswordTitle")} headerNode={msg("updatePasswordTitle")}
formNode={ formNode={
<form id="kc-passwd-update-form" className={cx(kcProps.kcFormClass)} action={url.loginAction} method="post"> <form id="kc-passwd-update-form" className={clsx(kcProps.kcFormClass)} action={url.loginAction} method="post">
<input <input
type="text" type="text"
id="username" id="username"
@ -39,44 +37,46 @@ const LoginUpdatePassword = memo((props: LoginUpdatePasswordProps) => {
/> />
<input type="password" id="password" name="password" autoComplete="current-password" style={{ display: "none" }} /> <input type="password" id="password" name="password" autoComplete="current-password" style={{ display: "none" }} />
<div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("password", kcProps.kcFormGroupErrorClass))}> <div className={clsx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("password", kcProps.kcFormGroupErrorClass))}>
<div className={cx(kcProps.kcLabelWrapperClass)}> <div className={clsx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="password-new" className={cx(kcProps.kcLabelClass)}> <label htmlFor="password-new" className={clsx(kcProps.kcLabelClass)}>
{msg("passwordNew")} {msg("passwordNew")}
</label> </label>
</div> </div>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<input <input
type="password" type="password"
id="password-new" id="password-new"
name="password-new" name="password-new"
autoFocus autoFocus
autoComplete="new-password" autoComplete="new-password"
className={cx(kcProps.kcInputClass)} className={clsx(kcProps.kcInputClass)}
/> />
</div> </div>
</div> </div>
<div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("password-confirm", kcProps.kcFormGroupErrorClass))}> <div
<div className={cx(kcProps.kcLabelWrapperClass)}> className={clsx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("password-confirm", kcProps.kcFormGroupErrorClass))}
<label htmlFor="password-confirm" className={cx(kcProps.kcLabelClass)}> >
<div className={clsx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="password-confirm" className={clsx(kcProps.kcLabelClass)}>
{msg("passwordConfirm")} {msg("passwordConfirm")}
</label> </label>
</div> </div>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<input <input
type="password" type="password"
id="password-confirm" id="password-confirm"
name="password-confirm" name="password-confirm"
autoComplete="new-password" autoComplete="new-password"
className={cx(kcProps.kcInputClass)} className={clsx(kcProps.kcInputClass)}
/> />
</div> </div>
</div> </div>
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(kcProps.kcFormOptionsClass)}> <div id="kc-form-options" className={clsx(kcProps.kcFormOptionsClass)}>
<div className={cx(kcProps.kcFormOptionsWrapperClass)}> <div className={clsx(kcProps.kcFormOptionsWrapperClass)}>
{isAppInitiatedAction && ( {isAppInitiatedAction && (
<div className="checkbox"> <div className="checkbox">
<label> <label>
@ -88,16 +88,16 @@ const LoginUpdatePassword = memo((props: LoginUpdatePasswordProps) => {
</div> </div>
</div> </div>
<div id="kc-form-buttons" className={cx(kcProps.kcFormButtonsClass)}> <div id="kc-form-buttons" className={clsx(kcProps.kcFormButtonsClass)}>
{isAppInitiatedAction ? ( {isAppInitiatedAction ? (
<> <>
<input <input
className={cx(kcProps.kcButtonClass, kcProps.kcButtonPrimaryClass, kcProps.kcButtonLargeClass)} className={clsx(kcProps.kcButtonClass, kcProps.kcButtonPrimaryClass, kcProps.kcButtonLargeClass)}
type="submit" type="submit"
defaultValue={msgStr("doSubmit")} defaultValue={msgStr("doSubmit")}
/> />
<button <button
className={cx(kcProps.kcButtonClass, kcProps.kcButtonDefaultClass, kcProps.kcButtonLargeClass)} className={clsx(kcProps.kcButtonClass, kcProps.kcButtonDefaultClass, kcProps.kcButtonLargeClass)}
type="submit" type="submit"
name="cancel-aia" name="cancel-aia"
value="true" value="true"
@ -107,7 +107,7 @@ const LoginUpdatePassword = memo((props: LoginUpdatePasswordProps) => {
</> </>
) : ( ) : (
<input <input
className={cx( className={clsx(
kcProps.kcButtonClass, kcProps.kcButtonClass,
kcProps.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
kcProps.kcButtonBlockClass, kcProps.kcButtonBlockClass,

View File

@ -3,7 +3,7 @@ import DefaultTemplate from "./Template";
import type { TemplateProps } from "./Template"; import type { TemplateProps } from "./Template";
import type { KcProps } from "./KcProps"; import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase"; import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useCssAndCx } from "../tools/useCssAndCx"; import { clsx } from "../tools/clsx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
export type LoginUpdateProfile = KcProps & { export type LoginUpdateProfile = KcProps & {
@ -16,8 +16,6 @@ export type LoginUpdateProfile = KcProps & {
const LoginUpdateProfile = memo((props: LoginUpdateProfile) => { const LoginUpdateProfile = memo((props: LoginUpdateProfile) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props; const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { cx } = useCssAndCx();
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
const { url, user, messagesPerField, isAppInitiatedAction } = kcContext; const { url, user, messagesPerField, isAppInitiatedAction } = kcContext;
@ -27,86 +25,86 @@ const LoginUpdateProfile = memo((props: LoginUpdateProfile) => {
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
headerNode={msg("loginProfileTitle")} headerNode={msg("loginProfileTitle")}
formNode={ formNode={
<form id="kc-update-profile-form" className={cx(kcProps.kcFormClass)} action={url.loginAction} method="post"> <form id="kc-update-profile-form" className={clsx(kcProps.kcFormClass)} action={url.loginAction} method="post">
{user.editUsernameAllowed && ( {user.editUsernameAllowed && (
<div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("username", kcProps.kcFormGroupErrorClass))}> <div className={clsx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("username", kcProps.kcFormGroupErrorClass))}>
<div className={cx(kcProps.kcLabelWrapperClass)}> <div className={clsx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="username" className={cx(kcProps.kcLabelClass)}> <label htmlFor="username" className={clsx(kcProps.kcLabelClass)}>
{msg("username")} {msg("username")}
</label> </label>
</div> </div>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="username" id="username"
name="username" name="username"
defaultValue={user.username ?? ""} defaultValue={user.username ?? ""}
className={cx(kcProps.kcInputClass)} className={clsx(kcProps.kcInputClass)}
/> />
</div> </div>
</div> </div>
)} )}
<div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("email", kcProps.kcFormGroupErrorClass))}> <div className={clsx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("email", kcProps.kcFormGroupErrorClass))}>
<div className={cx(kcProps.kcLabelWrapperClass)}> <div className={clsx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="email" className={cx(kcProps.kcLabelClass)}> <label htmlFor="email" className={clsx(kcProps.kcLabelClass)}>
{msg("email")} {msg("email")}
</label> </label>
</div> </div>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<input type="text" id="email" name="email" defaultValue={user.email ?? ""} className={cx(kcProps.kcInputClass)} /> <input type="text" id="email" name="email" defaultValue={user.email ?? ""} className={clsx(kcProps.kcInputClass)} />
</div> </div>
</div> </div>
<div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("firstName", kcProps.kcFormGroupErrorClass))}> <div className={clsx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("firstName", kcProps.kcFormGroupErrorClass))}>
<div className={cx(kcProps.kcLabelWrapperClass)}> <div className={clsx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="firstName" className={cx(kcProps.kcLabelClass)}> <label htmlFor="firstName" className={clsx(kcProps.kcLabelClass)}>
{msg("firstName")} {msg("firstName")}
</label> </label>
</div> </div>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="firstName" id="firstName"
name="firstName" name="firstName"
defaultValue={user.firstName ?? ""} defaultValue={user.firstName ?? ""}
className={cx(kcProps.kcInputClass)} className={clsx(kcProps.kcInputClass)}
/> />
</div> </div>
</div> </div>
<div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("lastName", kcProps.kcFormGroupErrorClass))}> <div className={clsx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("lastName", kcProps.kcFormGroupErrorClass))}>
<div className={cx(kcProps.kcLabelWrapperClass)}> <div className={clsx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="lastName" className={cx(kcProps.kcLabelClass)}> <label htmlFor="lastName" className={clsx(kcProps.kcLabelClass)}>
{msg("lastName")} {msg("lastName")}
</label> </label>
</div> </div>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="lastName" id="lastName"
name="lastName" name="lastName"
defaultValue={user.lastName ?? ""} defaultValue={user.lastName ?? ""}
className={cx(kcProps.kcInputClass)} className={clsx(kcProps.kcInputClass)}
/> />
</div> </div>
</div> </div>
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(kcProps.kcFormOptionsClass)}> <div id="kc-form-options" className={clsx(kcProps.kcFormOptionsClass)}>
<div className={cx(kcProps.kcFormOptionsWrapperClass)} /> <div className={clsx(kcProps.kcFormOptionsWrapperClass)} />
</div> </div>
<div id="kc-form-buttons" className={cx(kcProps.kcFormButtonsClass)}> <div id="kc-form-buttons" className={clsx(kcProps.kcFormButtonsClass)}>
{isAppInitiatedAction ? ( {isAppInitiatedAction ? (
<> <>
<input <input
className={cx(kcProps.kcButtonClass, kcProps.kcButtonPrimaryClass, kcProps.kcButtonLargeClass)} className={clsx(kcProps.kcButtonClass, kcProps.kcButtonPrimaryClass, kcProps.kcButtonLargeClass)}
type="submit" type="submit"
defaultValue={msgStr("doSubmit")} defaultValue={msgStr("doSubmit")}
/> />
<button <button
className={cx(kcProps.kcButtonClass, kcProps.kcButtonDefaultClass, kcProps.kcButtonLargeClass)} className={clsx(kcProps.kcButtonClass, kcProps.kcButtonDefaultClass, kcProps.kcButtonLargeClass)}
type="submit" type="submit"
name="cancel-aia" name="cancel-aia"
value="true" value="true"
@ -116,7 +114,7 @@ const LoginUpdateProfile = memo((props: LoginUpdateProfile) => {
</> </>
) : ( ) : (
<input <input
className={cx( className={clsx(
kcProps.kcButtonClass, kcProps.kcButtonClass,
kcProps.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
kcProps.kcButtonBlockClass, kcProps.kcButtonBlockClass,

View File

@ -3,7 +3,7 @@ import DefaultTemplate from "./Template";
import type { TemplateProps } from "./Template"; import type { TemplateProps } from "./Template";
import type { KcProps } from "./KcProps"; import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase"; import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useCssAndCx } from "../tools/useCssAndCx"; import { clsx } from "../tools/clsx";
import { useConstCallback } from "powerhooks/useConstCallback"; import { useConstCallback } from "powerhooks/useConstCallback";
import type { FormEventHandler } from "react"; import type { FormEventHandler } from "react";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
@ -22,8 +22,6 @@ const LoginUsername = memo((props: LoginUsernameProps) => {
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
const { cx } = useCssAndCx();
const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false); const [isLoginButtonDisabled, setIsLoginButtonDisabled] = useState(false);
const onSubmit = useConstCallback<FormEventHandler<HTMLFormElement>>(e => { const onSubmit = useConstCallback<FormEventHandler<HTMLFormElement>>(e => {
@ -47,16 +45,16 @@ const LoginUsername = memo((props: LoginUsernameProps) => {
displayWide={realm.password && social.providers !== undefined} displayWide={realm.password && social.providers !== undefined}
headerNode={msg("doLogIn")} headerNode={msg("doLogIn")}
formNode={ formNode={
<div id="kc-form" className={cx(realm.password && social.providers !== undefined && kcProps.kcContentWrapperClass)}> <div id="kc-form" className={clsx(realm.password && social.providers !== undefined && kcProps.kcContentWrapperClass)}>
<div <div
id="kc-form-wrapper" id="kc-form-wrapper"
className={cx( className={clsx(
realm.password && social.providers && [kcProps.kcFormSocialAccountContentClass, kcProps.kcFormSocialAccountClass] realm.password && social.providers && [kcProps.kcFormSocialAccountContentClass, kcProps.kcFormSocialAccountClass]
)} )}
> >
{realm.password && ( {realm.password && (
<form id="kc-form-login" onSubmit={onSubmit} action={url.loginAction} method="post"> <form id="kc-form-login" onSubmit={onSubmit} action={url.loginAction} method="post">
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)}>
{!usernameHidden && {!usernameHidden &&
(() => { (() => {
const label = !realm.loginWithEmailAllowed const label = !realm.loginWithEmailAllowed
@ -69,13 +67,13 @@ const LoginUsername = memo((props: LoginUsernameProps) => {
return ( return (
<> <>
<label htmlFor={autoCompleteHelper} className={cx(kcProps.kcLabelClass)}> <label htmlFor={autoCompleteHelper} className={clsx(kcProps.kcLabelClass)}>
{msg(label)} {msg(label)}
</label> </label>
<input <input
tabIndex={1} tabIndex={1}
id={autoCompleteHelper} id={autoCompleteHelper}
className={cx(kcProps.kcInputClass)} className={clsx(kcProps.kcInputClass)}
//NOTE: This is used by Google Chrome auto fill so we use it to tell //NOTE: This is used by Google Chrome auto fill so we use it to tell
//the browser how to pre fill the form but before submit we put it back //the browser how to pre fill the form but before submit we put it back
//to username because it is what keycloak expects. //to username because it is what keycloak expects.
@ -89,7 +87,7 @@ const LoginUsername = memo((props: LoginUsernameProps) => {
); );
})()} })()}
</div> </div>
<div className={cx(kcProps.kcFormGroupClass, kcProps.kcFormSettingClass)}> <div className={clsx(kcProps.kcFormGroupClass, kcProps.kcFormSettingClass)}>
<div id="kc-form-options"> <div id="kc-form-options">
{realm.rememberMe && !usernameHidden && ( {realm.rememberMe && !usernameHidden && (
<div className="checkbox"> <div className="checkbox">
@ -111,10 +109,10 @@ const LoginUsername = memo((props: LoginUsernameProps) => {
)} )}
</div> </div>
</div> </div>
<div id="kc-form-buttons" className={cx(kcProps.kcFormGroupClass)}> <div id="kc-form-buttons" className={clsx(kcProps.kcFormGroupClass)}>
<input <input
tabIndex={4} tabIndex={4}
className={cx( className={clsx(
kcProps.kcButtonClass, kcProps.kcButtonClass,
kcProps.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
kcProps.kcButtonBlockClass, kcProps.kcButtonBlockClass,
@ -131,16 +129,16 @@ const LoginUsername = memo((props: LoginUsernameProps) => {
)} )}
</div> </div>
{realm.password && social.providers !== undefined && ( {realm.password && social.providers !== undefined && (
<div id="kc-social-providers" className={cx(kcProps.kcFormSocialAccountContentClass, kcProps.kcFormSocialAccountClass)}> <div id="kc-social-providers" className={clsx(kcProps.kcFormSocialAccountContentClass, kcProps.kcFormSocialAccountClass)}>
<ul <ul
className={cx( className={clsx(
kcProps.kcFormSocialAccountListClass, kcProps.kcFormSocialAccountListClass,
social.providers.length > 4 && kcProps.kcFormSocialAccountDoubleListClass social.providers.length > 4 && kcProps.kcFormSocialAccountDoubleListClass
)} )}
> >
{social.providers.map(p => ( {social.providers.map(p => (
<li key={p.providerId} className={cx(kcProps.kcFormSocialAccountListLinkClass)}> <li key={p.providerId} className={clsx(kcProps.kcFormSocialAccountListLinkClass)}>
<a href={p.loginUrl} id={`zocial-${p.alias}`} className={cx("zocial", p.providerId)}> <a href={p.loginUrl} id={`zocial-${p.alias}`} className={clsx("zocial", p.providerId)}>
<span>{p.displayName}</span> <span>{p.displayName}</span>
</a> </a>
</li> </li>

View File

@ -1,5 +1,5 @@
import React, { memo } from "react"; import React, { memo } from "react";
import { useCssAndCx } from "../tools/useCssAndCx"; import { clsx } from "../tools/clsx";
import DefaultTemplate from "./Template"; import DefaultTemplate from "./Template";
import type { TemplateProps } from "./Template"; import type { TemplateProps } from "./Template";
import type { KcProps } from "./KcProps"; import type { KcProps } from "./KcProps";
@ -18,8 +18,6 @@ const LogoutConfirm = memo((props: LogoutConfirmProps) => {
const { url, client, logoutConfirm } = kcContext; const { url, client, logoutConfirm } = kcContext;
const { cx } = useCssAndCx();
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
return ( return (
@ -33,14 +31,14 @@ const LogoutConfirm = memo((props: LogoutConfirmProps) => {
<p className="instruction">{msg("logoutConfirmHeader")}</p> <p className="instruction">{msg("logoutConfirmHeader")}</p>
<form className="form-actions" action={url.logoutConfirmAction} method="POST"> <form className="form-actions" action={url.logoutConfirmAction} method="POST">
<input type="hidden" name="session_code" value={logoutConfirm.code} /> <input type="hidden" name="session_code" value={logoutConfirm.code} />
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)}>
<div id="kc-form-options"> <div id="kc-form-options">
<div className={cx(kcProps.kcFormOptionsWrapperClass)}></div> <div className={clsx(kcProps.kcFormOptionsWrapperClass)}></div>
</div> </div>
<div id="kc-form-buttons" className={cx(kcProps.kcFormGroupClass)}> <div id="kc-form-buttons" className={clsx(kcProps.kcFormGroupClass)}>
<input <input
tabIndex={4} tabIndex={4}
className={cx( className={clsx(
kcProps.kcButtonClass, kcProps.kcButtonClass,
kcProps.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
kcProps.kcButtonBlockClass, kcProps.kcButtonBlockClass,

View File

@ -3,7 +3,7 @@ import DefaultTemplate from "./Template";
import type { TemplateProps } from "./Template"; import type { TemplateProps } from "./Template";
import type { KcProps } from "./KcProps"; import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase"; import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useCssAndCx } from "../tools/useCssAndCx"; import { clsx } from "../tools/clsx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
export type RegisterProps = KcProps & { export type RegisterProps = KcProps & {
@ -20,59 +20,57 @@ const Register = memo((props: RegisterProps) => {
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
const { cx } = useCssAndCx();
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
headerNode={msg("registerTitle")} headerNode={msg("registerTitle")}
formNode={ formNode={
<form id="kc-register-form" className={cx(kcProps.kcFormClass)} action={url.registrationAction} method="post"> <form id="kc-register-form" className={clsx(kcProps.kcFormClass)} action={url.registrationAction} method="post">
<div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("firstName", kcProps.kcFormGroupErrorClass))}> <div className={clsx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("firstName", kcProps.kcFormGroupErrorClass))}>
<div className={cx(kcProps.kcLabelWrapperClass)}> <div className={clsx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="firstName" className={cx(kcProps.kcLabelClass)}> <label htmlFor="firstName" className={clsx(kcProps.kcLabelClass)}>
{msg("firstName")} {msg("firstName")}
</label> </label>
</div> </div>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="firstName" id="firstName"
className={cx(kcProps.kcInputClass)} className={clsx(kcProps.kcInputClass)}
name="firstName" name="firstName"
defaultValue={register.formData.firstName ?? ""} defaultValue={register.formData.firstName ?? ""}
/> />
</div> </div>
</div> </div>
<div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("lastName", kcProps.kcFormGroupErrorClass))}> <div className={clsx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("lastName", kcProps.kcFormGroupErrorClass))}>
<div className={cx(kcProps.kcLabelWrapperClass)}> <div className={clsx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="lastName" className={cx(kcProps.kcLabelClass)}> <label htmlFor="lastName" className={clsx(kcProps.kcLabelClass)}>
{msg("lastName")} {msg("lastName")}
</label> </label>
</div> </div>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="lastName" id="lastName"
className={cx(kcProps.kcInputClass)} className={clsx(kcProps.kcInputClass)}
name="lastName" name="lastName"
defaultValue={register.formData.lastName ?? ""} defaultValue={register.formData.lastName ?? ""}
/> />
</div> </div>
</div> </div>
<div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("email", kcProps.kcFormGroupErrorClass))}> <div className={clsx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("email", kcProps.kcFormGroupErrorClass))}>
<div className={cx(kcProps.kcLabelWrapperClass)}> <div className={clsx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="email" className={cx(kcProps.kcLabelClass)}> <label htmlFor="email" className={clsx(kcProps.kcLabelClass)}>
{msg("email")} {msg("email")}
</label> </label>
</div> </div>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="email" id="email"
className={cx(kcProps.kcInputClass)} className={clsx(kcProps.kcInputClass)}
name="email" name="email"
defaultValue={register.formData.email ?? ""} defaultValue={register.formData.email ?? ""}
autoComplete="email" autoComplete="email"
@ -80,17 +78,17 @@ const Register = memo((props: RegisterProps) => {
</div> </div>
</div> </div>
{!realm.registrationEmailAsUsername && ( {!realm.registrationEmailAsUsername && (
<div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("username", kcProps.kcFormGroupErrorClass))}> <div className={clsx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("username", kcProps.kcFormGroupErrorClass))}>
<div className={cx(kcProps.kcLabelWrapperClass)}> <div className={clsx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="username" className={cx(kcProps.kcLabelClass)}> <label htmlFor="username" className={clsx(kcProps.kcLabelClass)}>
{msg("username")} {msg("username")}
</label> </label>
</div> </div>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="username" id="username"
className={cx(kcProps.kcInputClass)} className={clsx(kcProps.kcInputClass)}
name="username" name="username"
defaultValue={register.formData.username ?? ""} defaultValue={register.formData.username ?? ""}
autoComplete="username" autoComplete="username"
@ -100,17 +98,19 @@ const Register = memo((props: RegisterProps) => {
)} )}
{passwordRequired && ( {passwordRequired && (
<> <>
<div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("password", kcProps.kcFormGroupErrorClass))}> <div
<div className={cx(kcProps.kcLabelWrapperClass)}> className={clsx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("password", kcProps.kcFormGroupErrorClass))}
<label htmlFor="password" className={cx(kcProps.kcLabelClass)}> >
<div className={clsx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="password" className={clsx(kcProps.kcLabelClass)}>
{msg("password")} {msg("password")}
</label> </label>
</div> </div>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<input <input
type="password" type="password"
id="password" id="password"
className={cx(kcProps.kcInputClass)} className={clsx(kcProps.kcInputClass)}
name="password" name="password"
autoComplete="new-password" autoComplete="new-password"
/> />
@ -118,41 +118,41 @@ const Register = memo((props: RegisterProps) => {
</div> </div>
<div <div
className={cx( className={clsx(
kcProps.kcFormGroupClass, kcProps.kcFormGroupClass,
messagesPerField.printIfExists("password-confirm", kcProps.kcFormGroupErrorClass) messagesPerField.printIfExists("password-confirm", kcProps.kcFormGroupErrorClass)
)} )}
> >
<div className={cx(kcProps.kcLabelWrapperClass)}> <div className={clsx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="password-confirm" className={cx(kcProps.kcLabelClass)}> <label htmlFor="password-confirm" className={clsx(kcProps.kcLabelClass)}>
{msg("passwordConfirm")} {msg("passwordConfirm")}
</label> </label>
</div> </div>
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<input type="password" id="password-confirm" className={cx(kcProps.kcInputClass)} name="password-confirm" /> <input type="password" id="password-confirm" className={clsx(kcProps.kcInputClass)} name="password-confirm" />
</div> </div>
</div> </div>
</> </>
)} )}
{recaptchaRequired && ( {recaptchaRequired && (
<div className="form-group"> <div className="form-group">
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<div className="g-recaptcha" data-size="compact" data-sitekey={recaptchaSiteKey}></div> <div className="g-recaptcha" data-size="compact" data-sitekey={recaptchaSiteKey}></div>
</div> </div>
</div> </div>
)} )}
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(kcProps.kcFormOptionsClass)}> <div id="kc-form-options" className={clsx(kcProps.kcFormOptionsClass)}>
<div className={cx(kcProps.kcFormOptionsWrapperClass)}> <div className={clsx(kcProps.kcFormOptionsWrapperClass)}>
<span> <span>
<a href={url.loginUrl}>{msg("backToLogin")}</a> <a href={url.loginUrl}>{msg("backToLogin")}</a>
</span> </span>
</div> </div>
</div> </div>
<div id="kc-form-buttons" className={cx(kcProps.kcFormButtonsClass)}> <div id="kc-form-buttons" className={clsx(kcProps.kcFormButtonsClass)}>
<input <input
className={cx( className={clsx(
kcProps.kcButtonClass, kcProps.kcButtonClass,
kcProps.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
kcProps.kcButtonBlockClass, kcProps.kcButtonBlockClass,

View File

@ -1,9 +1,9 @@
import React, { useMemo, memo, useState } from "react"; import React, { memo, useState } from "react";
import DefaultTemplate from "./Template"; import DefaultTemplate from "./Template";
import type { TemplateProps } from "./Template"; import type { TemplateProps } from "./Template";
import type { KcProps } from "./KcProps"; import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase"; import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useCssAndCx } from "../tools/useCssAndCx"; import { clsx } from "../tools/clsx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
import { UserProfileFormFields } from "./shared/UserProfileCommons"; import { UserProfileFormFields } from "./shared/UserProfileCommons";
@ -15,22 +15,12 @@ export type RegisterUserProfileProps = KcProps & {
}; };
const RegisterUserProfile = memo((props: RegisterUserProfileProps) => { const RegisterUserProfile = memo((props: RegisterUserProfileProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps_ } = props; const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { url, messagesPerField, recaptchaRequired, recaptchaSiteKey } = kcContext; const { url, messagesPerField, recaptchaRequired, recaptchaSiteKey } = kcContext;
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
const { cx, css } = useCssAndCx();
const kcProps = useMemo(
() => ({
...kcProps_,
"kcFormGroupClass": cx(kcProps_.kcFormGroupClass, css({ "marginBottom": 20 }))
}),
[cx, css]
);
const [isFomSubmittable, setIsFomSubmittable] = useState(false); const [isFomSubmittable, setIsFomSubmittable] = useState(false);
return ( return (
@ -40,27 +30,27 @@ const RegisterUserProfile = memo((props: RegisterUserProfileProps) => {
displayRequiredFields={true} displayRequiredFields={true}
headerNode={msg("registerTitle")} headerNode={msg("registerTitle")}
formNode={ formNode={
<form id="kc-register-form" className={cx(kcProps.kcFormClass)} action={url.registrationAction} method="post"> <form id="kc-register-form" className={clsx(kcProps.kcFormClass)} action={url.registrationAction} method="post">
<UserProfileFormFields kcContext={kcContext} onIsFormSubmittableValueChange={setIsFomSubmittable} i18n={i18n} {...kcProps} /> <UserProfileFormFields kcContext={kcContext} onIsFormSubmittableValueChange={setIsFomSubmittable} i18n={i18n} {...kcProps} />
{recaptchaRequired && ( {recaptchaRequired && (
<div className="form-group"> <div className="form-group">
<div className={cx(kcProps.kcInputWrapperClass)}> <div className={clsx(kcProps.kcInputWrapperClass)}>
<div className="g-recaptcha" data-size="compact" data-sitekey={recaptchaSiteKey} /> <div className="g-recaptcha" data-size="compact" data-sitekey={recaptchaSiteKey} />
</div> </div>
</div> </div>
)} )}
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)} style={{ "marginBottom": 30 }}>
<div id="kc-form-options" className={cx(kcProps.kcFormOptionsClass)}> <div id="kc-form-options" className={clsx(kcProps.kcFormOptionsClass)}>
<div className={cx(kcProps.kcFormOptionsWrapperClass)}> <div className={clsx(kcProps.kcFormOptionsWrapperClass)}>
<span> <span>
<a href={url.loginUrl}>{msg("backToLogin")}</a> <a href={url.loginUrl}>{msg("backToLogin")}</a>
</span> </span>
</div> </div>
</div> </div>
<div id="kc-form-buttons" className={cx(kcProps.kcFormButtonsClass)}> <div id="kc-form-buttons" className={clsx(kcProps.kcFormButtonsClass)}>
<input <input
className={cx( className={clsx(
kcProps.kcButtonClass, kcProps.kcButtonClass,
kcProps.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
kcProps.kcButtonBlockClass, kcProps.kcButtonBlockClass,

View File

@ -7,7 +7,7 @@ import { headInsert } from "../tools/headInsert";
import { pathJoin } from "../../bin/tools/pathJoin"; import { pathJoin } from "../../bin/tools/pathJoin";
import { useConstCallback } from "powerhooks/useConstCallback"; import { useConstCallback } from "powerhooks/useConstCallback";
import type { KcTemplateProps } from "./KcProps"; import type { KcTemplateProps } from "./KcProps";
import { useCssAndCx } from "../tools/useCssAndCx"; import { clsx } from "../tools/clsx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
export type TemplateProps = { export type TemplateProps = {
@ -42,8 +42,6 @@ const Template = memo((props: TemplateProps) => {
doFetchDefaultThemeResources doFetchDefaultThemeResources
} = props; } = props;
const { cx } = useCssAndCx();
const { msg, changeLocale, labelBySupportedLanguageTag, currentLanguageTag } = i18n; const { msg, changeLocale, labelBySupportedLanguageTag, currentLanguageTag } = i18n;
const onChangeLanguageClickFactory = useCallbackFactory(([kcLanguageTag]: [string]) => changeLocale(kcLanguageTag)); const onChangeLanguageClickFactory = useCallbackFactory(([kcLanguageTag]: [string]) => changeLocale(kcLanguageTag));
@ -96,7 +94,7 @@ const Template = memo((props: TemplateProps) => {
if (props.kcHtmlClass !== undefined) { if (props.kcHtmlClass !== undefined) {
const htmlClassList = document.getElementsByTagName("html")[0].classList; const htmlClassList = document.getElementsByTagName("html")[0].classList;
const tokens = cx(props.kcHtmlClass).split(" "); const tokens = clsx(props.kcHtmlClass).split(" ");
htmlClassList.add(...tokens); htmlClassList.add(...tokens);
@ -115,18 +113,18 @@ const Template = memo((props: TemplateProps) => {
} }
return ( return (
<div className={cx(props.kcLoginClass)}> <div className={clsx(props.kcLoginClass)}>
<div id="kc-header" className={cx(props.kcHeaderClass)}> <div id="kc-header" className={clsx(props.kcHeaderClass)}>
<div id="kc-header-wrapper" className={cx(props.kcHeaderWrapperClass)}> <div id="kc-header-wrapper" className={clsx(props.kcHeaderWrapperClass)}>
{msg("loginTitleHtml", realm.displayNameHtml)} {msg("loginTitleHtml", realm.displayNameHtml)}
</div> </div>
</div> </div>
<div className={cx(props.kcFormCardClass, displayWide && props.kcFormCardAccountClass)}> <div className={clsx(props.kcFormCardClass, displayWide && props.kcFormCardAccountClass)}>
<header className={cx(props.kcFormHeaderClass)}> <header className={clsx(props.kcFormHeaderClass)}>
{realm.internationalizationEnabled && (assert(locale !== undefined), true) && locale.supported.length > 1 && ( {realm.internationalizationEnabled && (assert(locale !== undefined), true) && locale.supported.length > 1 && (
<div id="kc-locale"> <div id="kc-locale">
<div id="kc-locale-wrapper" className={cx(props.kcLocaleWrapperClass)}> <div id="kc-locale-wrapper" className={clsx(props.kcLocaleWrapperClass)}>
<div className="kc-dropdown" id="kc-locale-dropdown"> <div className="kc-dropdown" id="kc-locale-dropdown">
<a href="#" id="kc-current-locale-link"> <a href="#" id="kc-current-locale-link">
{labelBySupportedLanguageTag[currentLanguageTag]} {labelBySupportedLanguageTag[currentLanguageTag]}
@ -146,8 +144,8 @@ const Template = memo((props: TemplateProps) => {
)} )}
{!(auth !== undefined && auth.showUsername && !auth.showResetCredentials) ? ( {!(auth !== undefined && auth.showUsername && !auth.showResetCredentials) ? (
displayRequiredFields ? ( displayRequiredFields ? (
<div className={cx(props.kcContentWrapperClass)}> <div className={clsx(props.kcContentWrapperClass)}>
<div className={cx(props.kcLabelWrapperClass, "subtitle")}> <div className={clsx(props.kcLabelWrapperClass, "subtitle")}>
<span className="subtitle"> <span className="subtitle">
<span className="required">*</span> <span className="required">*</span>
{msg("requiredFields")} {msg("requiredFields")}
@ -161,20 +159,20 @@ const Template = memo((props: TemplateProps) => {
<h1 id="kc-page-title">{headerNode}</h1> <h1 id="kc-page-title">{headerNode}</h1>
) )
) : displayRequiredFields ? ( ) : displayRequiredFields ? (
<div className={cx(props.kcContentWrapperClass)}> <div className={clsx(props.kcContentWrapperClass)}>
<div className={cx(props.kcLabelWrapperClass, "subtitle")}> <div className={clsx(props.kcLabelWrapperClass, "subtitle")}>
<span className="subtitle"> <span className="subtitle">
<span className="required">*</span> {msg("requiredFields")} <span className="required">*</span> {msg("requiredFields")}
</span> </span>
</div> </div>
<div className="col-md-10"> <div className="col-md-10">
{showUsernameNode} {showUsernameNode}
<div className={cx(props.kcFormGroupClass)}> <div className={clsx(props.kcFormGroupClass)}>
<div id="kc-username"> <div id="kc-username">
<label id="kc-attempted-username">{auth?.attemptedUsername}</label> <label id="kc-attempted-username">{auth?.attemptedUsername}</label>
<a id="reset-login" href={url.loginRestartFlowUrl}> <a id="reset-login" href={url.loginRestartFlowUrl}>
<div className="kc-login-tooltip"> <div className="kc-login-tooltip">
<i className={cx(props.kcResetFlowIcon)}></i> <i className={clsx(props.kcResetFlowIcon)}></i>
<span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span> <span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span>
</div> </div>
</a> </a>
@ -185,12 +183,12 @@ const Template = memo((props: TemplateProps) => {
) : ( ) : (
<> <>
{showUsernameNode} {showUsernameNode}
<div className={cx(props.kcFormGroupClass)}> <div className={clsx(props.kcFormGroupClass)}>
<div id="kc-username"> <div id="kc-username">
<label id="kc-attempted-username">{auth?.attemptedUsername}</label> <label id="kc-attempted-username">{auth?.attemptedUsername}</label>
<a id="reset-login" href={url.loginRestartFlowUrl}> <a id="reset-login" href={url.loginRestartFlowUrl}>
<div className="kc-login-tooltip"> <div className="kc-login-tooltip">
<i className={cx(props.kcResetFlowIcon)}></i> <i className={clsx(props.kcResetFlowIcon)}></i>
<span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span> <span className="kc-tooltip-text">{msg("restartLoginTooltip")}</span>
</div> </div>
</a> </a>
@ -203,11 +201,11 @@ const Template = memo((props: TemplateProps) => {
<div id="kc-content-wrapper"> <div id="kc-content-wrapper">
{/* App-initiated actions should not see warning messages about the need to complete the action during login. */} {/* App-initiated actions should not see warning messages about the need to complete the action during login. */}
{displayMessage && message !== undefined && (message.type !== "warning" || !isAppInitiatedAction) && ( {displayMessage && message !== undefined && (message.type !== "warning" || !isAppInitiatedAction) && (
<div className={cx("alert", `alert-${message.type}`)}> <div className={clsx("alert", `alert-${message.type}`)}>
{message.type === "success" && <span className={cx(props.kcFeedbackSuccessIcon)}></span>} {message.type === "success" && <span className={clsx(props.kcFeedbackSuccessIcon)}></span>}
{message.type === "warning" && <span className={cx(props.kcFeedbackWarningIcon)}></span>} {message.type === "warning" && <span className={clsx(props.kcFeedbackWarningIcon)}></span>}
{message.type === "error" && <span className={cx(props.kcFeedbackErrorIcon)}></span>} {message.type === "error" && <span className={clsx(props.kcFeedbackErrorIcon)}></span>}
{message.type === "info" && <span className={cx(props.kcFeedbackInfoIcon)}></span>} {message.type === "info" && <span className={clsx(props.kcFeedbackInfoIcon)}></span>}
<span <span
className="kc-feedback-text" className="kc-feedback-text"
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{
@ -222,10 +220,10 @@ const Template = memo((props: TemplateProps) => {
id="kc-select-try-another-way-form" id="kc-select-try-another-way-form"
action={url.loginAction} action={url.loginAction}
method="post" method="post"
className={cx(displayWide && props.kcContentWrapperClass)} className={clsx(displayWide && props.kcContentWrapperClass)}
> >
<div className={cx(displayWide && [props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass])}> <div className={clsx(displayWide && [props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass])}>
<div className={cx(props.kcFormGroupClass)}> <div className={clsx(props.kcFormGroupClass)}>
<input type="hidden" name="tryAnotherWay" value="on" /> <input type="hidden" name="tryAnotherWay" value="on" />
<a href="#" id="try-another-way" onClick={onTryAnotherWayClick}> <a href="#" id="try-another-way" onClick={onTryAnotherWayClick}>
{msg("doTryAnotherWay")} {msg("doTryAnotherWay")}
@ -235,8 +233,8 @@ const Template = memo((props: TemplateProps) => {
</form> </form>
)} )}
{displayInfo && ( {displayInfo && (
<div id="kc-info" className={cx(props.kcSignUpClass)}> <div id="kc-info" className={clsx(props.kcSignUpClass)}>
<div id="kc-info-wrapper" className={cx(props.kcInfoAreaWrapperClass)}> <div id="kc-info-wrapper" className={clsx(props.kcInfoAreaWrapperClass)}>
{infoNode} {infoNode}
</div> </div>
</div> </div>

View File

@ -3,7 +3,7 @@ import DefaultTemplate from "./Template";
import type { TemplateProps } from "./Template"; import type { TemplateProps } from "./Template";
import type { KcProps } from "./KcProps"; import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase"; import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useCssAndCx } from "../tools/useCssAndCx"; import { clsx } from "../tools/clsx";
import { Evt } from "evt"; import { Evt } from "evt";
import { useRerenderOnStateChange } from "evt/hooks"; import { useRerenderOnStateChange } from "evt/hooks";
import { assert } from "tsafe/assert"; import { assert } from "tsafe/assert";
@ -70,8 +70,6 @@ const Terms = memo((props: TermsProps) => {
useRerenderOnStateChange(evtTermMarkdown); useRerenderOnStateChange(evtTermMarkdown);
const { cx } = useCssAndCx();
const { url } = kcContext; const { url } = kcContext;
if (evtTermMarkdown.state === undefined) { if (evtTermMarkdown.state === undefined) {
@ -88,7 +86,7 @@ const Terms = memo((props: TermsProps) => {
<div id="kc-terms-text">{evtTermMarkdown.state && <Markdown>{evtTermMarkdown.state}</Markdown>}</div> <div id="kc-terms-text">{evtTermMarkdown.state && <Markdown>{evtTermMarkdown.state}</Markdown>}</div>
<form className="form-actions" action={url.loginAction} method="POST"> <form className="form-actions" action={url.loginAction} method="POST">
<input <input
className={cx( className={clsx(
kcProps.kcButtonClass, kcProps.kcButtonClass,
kcProps.kcButtonClass, kcProps.kcButtonClass,
kcProps.kcButtonClass, kcProps.kcButtonClass,
@ -101,7 +99,7 @@ const Terms = memo((props: TermsProps) => {
value={msgStr("doAccept")} value={msgStr("doAccept")}
/> />
<input <input
className={cx(kcProps.kcButtonClass, kcProps.kcButtonDefaultClass, kcProps.kcButtonLargeClass)} className={clsx(kcProps.kcButtonClass, kcProps.kcButtonDefaultClass, kcProps.kcButtonLargeClass)}
name="cancel" name="cancel"
id="kc-decline" id="kc-decline"
type="submit" type="submit"

View File

@ -3,7 +3,7 @@ import DefaultTemplate from "./Template";
import type { TemplateProps } from "./Template"; import type { TemplateProps } from "./Template";
import type { KcProps } from "./KcProps"; import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase"; import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useCssAndCx } from "../tools/useCssAndCx"; import { clsx } from "../tools/clsx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
import { UserProfileFormFields } from "./shared/UserProfileCommons"; import { UserProfileFormFields } from "./shared/UserProfileCommons";
@ -17,8 +17,6 @@ export type UpdateUserProfileProps = KcProps & {
const UpdateUserProfile = memo((props: UpdateUserProfileProps) => { const UpdateUserProfile = memo((props: UpdateUserProfileProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props; const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { cx } = useCssAndCx();
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
const { url, isAppInitiatedAction } = kcContext; const { url, isAppInitiatedAction } = kcContext;
@ -30,24 +28,24 @@ const UpdateUserProfile = memo((props: UpdateUserProfileProps) => {
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
headerNode={msg("loginProfileTitle")} headerNode={msg("loginProfileTitle")}
formNode={ formNode={
<form id="kc-update-profile-form" className={cx(kcProps.kcFormClass)} action={url.loginAction} method="post"> <form id="kc-update-profile-form" className={clsx(kcProps.kcFormClass)} action={url.loginAction} method="post">
<UserProfileFormFields kcContext={kcContext} onIsFormSubmittableValueChange={setIsFomSubmittable} i18n={i18n} {...kcProps} /> <UserProfileFormFields kcContext={kcContext} onIsFormSubmittableValueChange={setIsFomSubmittable} i18n={i18n} {...kcProps} />
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(kcProps.kcFormOptionsClass)}> <div id="kc-form-options" className={clsx(kcProps.kcFormOptionsClass)}>
<div className={cx(kcProps.kcFormOptionsWrapperClass)}></div> <div className={clsx(kcProps.kcFormOptionsWrapperClass)}></div>
</div> </div>
<div id="kc-form-buttons" className={cx(kcProps.kcFormButtonsClass)}> <div id="kc-form-buttons" className={clsx(kcProps.kcFormButtonsClass)}>
{isAppInitiatedAction ? ( {isAppInitiatedAction ? (
<> <>
<input <input
className={cx(kcProps.kcButtonClass, kcProps.kcButtonPrimaryClass, kcProps.kcButtonLargeClass)} className={clsx(kcProps.kcButtonClass, kcProps.kcButtonPrimaryClass, kcProps.kcButtonLargeClass)}
type="submit" type="submit"
value={msgStr("doSubmit")} value={msgStr("doSubmit")}
/> />
<button <button
className={cx(kcProps.kcButtonClass, kcProps.kcButtonDefaultClass, kcProps.kcButtonLargeClass)} className={clsx(kcProps.kcButtonClass, kcProps.kcButtonDefaultClass, kcProps.kcButtonLargeClass)}
type="submit" type="submit"
name="cancel-aia" name="cancel-aia"
value="true" value="true"
@ -58,7 +56,7 @@ const UpdateUserProfile = memo((props: UpdateUserProfileProps) => {
</> </>
) : ( ) : (
<input <input
className={cx( className={clsx(
kcProps.kcButtonClass, kcProps.kcButtonClass,
kcProps.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
kcProps.kcButtonBlockClass, kcProps.kcButtonBlockClass,

View File

@ -3,7 +3,7 @@ import DefaultTemplate from "./Template";
import type { TemplateProps } from "./Template"; import type { TemplateProps } from "./Template";
import type { KcProps } from "./KcProps"; import type { KcProps } from "./KcProps";
import type { KcContextBase } from "../getKcContext/KcContextBase"; import type { KcContextBase } from "../getKcContext/KcContextBase";
import { useCssAndCx } from "../tools/useCssAndCx"; import { clsx } from "../tools/clsx";
import type { I18n, MessageKeyBase } from "../i18n"; import type { I18n, MessageKeyBase } from "../i18n";
import { base64url } from "rfc4648"; import { base64url } from "rfc4648";
import { useConstCallback } from "powerhooks/useConstCallback"; import { useConstCallback } from "powerhooks/useConstCallback";
@ -26,8 +26,6 @@ const WebauthnAuthenticate = memo((props: WebauthnAuthenticateProps) => {
const createTimeout = Number(kcContext.createTimeout); const createTimeout = Number(kcContext.createTimeout);
const isUserIdentified = kcContext.isUserIdentified == "true"; const isUserIdentified = kcContext.isUserIdentified == "true";
const { cx } = useCssAndCx();
const webAuthnAuthenticate = useConstCallback(async () => { const webAuthnAuthenticate = useConstCallback(async () => {
if (!isUserIdentified) { if (!isUserIdentified) {
return; return;
@ -102,7 +100,7 @@ const WebauthnAuthenticate = memo((props: WebauthnAuthenticateProps) => {
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
headerNode={msg("webauthn-login-title")} headerNode={msg("webauthn-login-title")}
formNode={ formNode={
<div id="kc-form-webauthn" className={cx(kcProps.kcFormClass)}> <div id="kc-form-webauthn" className={clsx(kcProps.kcFormClass)}>
<form id="webauth" action={url.loginAction} ref={webAuthForm} method="post"> <form id="webauth" action={url.loginAction} ref={webAuthForm} method="post">
<input type="hidden" id="clientDataJSON" name="clientDataJSON" value={clientDataJSON} /> <input type="hidden" id="clientDataJSON" name="clientDataJSON" value={clientDataJSON} />
<input type="hidden" id="authenticatorData" name="authenticatorData" value={authenticatorData} /> <input type="hidden" id="authenticatorData" name="authenticatorData" value={authenticatorData} />
@ -111,10 +109,10 @@ const WebauthnAuthenticate = memo((props: WebauthnAuthenticateProps) => {
<input type="hidden" id="userHandle" name="userHandle" value={userHandle} /> <input type="hidden" id="userHandle" name="userHandle" value={userHandle} />
<input type="hidden" id="error" name="error" value={error} /> <input type="hidden" id="error" name="error" value={error} />
</form> </form>
<div className={cx(kcProps.kcFormGroupClass)}> <div className={clsx(kcProps.kcFormGroupClass)}>
{authenticators && {authenticators &&
(() => ( (() => (
<form id="authn_select" className={cx(kcProps.kcFormClass)}> <form id="authn_select" className={clsx(kcProps.kcFormClass)}>
{authenticators.authenticators.map(authenticator => ( {authenticators.authenticators.map(authenticator => (
<input <input
type="hidden" type="hidden"
@ -130,23 +128,23 @@ const WebauthnAuthenticate = memo((props: WebauthnAuthenticateProps) => {
(() => ( (() => (
<> <>
{authenticators.authenticators.length > 1 && ( {authenticators.authenticators.length > 1 && (
<p className={cx(kcProps.kcSelectAuthListItemTitle)}>{msg("webauthn-available-authenticators")}</p> <p className={clsx(kcProps.kcSelectAuthListItemTitle)}>{msg("webauthn-available-authenticators")}</p>
)} )}
<div className={cx(kcProps.kcFormClass)}> <div className={clsx(kcProps.kcFormClass)}>
{authenticators.authenticators.map(authenticator => ( {authenticators.authenticators.map(authenticator => (
<div id="kc-webauthn-authenticator" className={cx(kcProps.kcSelectAuthListItemClass)}> <div id="kc-webauthn-authenticator" className={clsx(kcProps.kcSelectAuthListItemClass)}>
<div className={cx(kcProps.kcSelectAuthListItemIconClass)}> <div className={clsx(kcProps.kcSelectAuthListItemIconClass)}>
<i <i
className={cx( className={clsx(
kcProps[authenticator.transports.iconClass] ?? kcProps.kcWebAuthnDefaultIcon, kcProps[authenticator.transports.iconClass] ?? kcProps.kcWebAuthnDefaultIcon,
kcProps.kcSelectAuthListItemIconPropertyClass kcProps.kcSelectAuthListItemIconPropertyClass
)} )}
/> />
</div> </div>
<div className={cx(kcProps.kcSelectAuthListItemBodyClass)}> <div className={clsx(kcProps.kcSelectAuthListItemBodyClass)}>
<div <div
id="kc-webauthn-authenticator-label" id="kc-webauthn-authenticator-label"
className={cx(kcProps.kcSelectAuthListItemHeadingClass)} className={clsx(kcProps.kcSelectAuthListItemHeadingClass)}
> >
{authenticator.label} {authenticator.label}
</div> </div>
@ -154,7 +152,7 @@ const WebauthnAuthenticate = memo((props: WebauthnAuthenticateProps) => {
{authenticator.transports && authenticator.transports.displayNameProperties.length && ( {authenticator.transports && authenticator.transports.displayNameProperties.length && (
<div <div
id="kc-webauthn-authenticator-transport" id="kc-webauthn-authenticator-transport"
className={cx(kcProps.kcSelectAuthListItemDescriptionClass)} className={clsx(kcProps.kcSelectAuthListItemDescriptionClass)}
> >
{authenticator.transports.displayNameProperties.map( {authenticator.transports.displayNameProperties.map(
(transport: MessageKeyBase, index: number) => ( (transport: MessageKeyBase, index: number) => (
@ -169,25 +167,25 @@ const WebauthnAuthenticate = memo((props: WebauthnAuthenticateProps) => {
</div> </div>
)} )}
<div className={cx(kcProps.kcSelectAuthListItemDescriptionClass)}> <div className={clsx(kcProps.kcSelectAuthListItemDescriptionClass)}>
<span id="kc-webauthn-authenticator-created-label">{msg("webauthn-createdAt-label")}</span> <span id="kc-webauthn-authenticator-created-label">{msg("webauthn-createdAt-label")}</span>
<span id="kc-webauthn-authenticator-created">{authenticator.createdAt}</span> <span id="kc-webauthn-authenticator-created">{authenticator.createdAt}</span>
</div> </div>
</div> </div>
<div className={cx(kcProps.kcSelectAuthListItemFillClass)} /> <div className={clsx(kcProps.kcSelectAuthListItemFillClass)} />
</div> </div>
))} ))}
</div> </div>
</> </>
))()} ))()}
<div id="kc-form-buttons" className={cx(kcProps.kcFormButtonsClass)}> <div id="kc-form-buttons" className={clsx(kcProps.kcFormButtonsClass)}>
<input <input
id="authenticateWebAuthnButton" id="authenticateWebAuthnButton"
type="button" type="button"
onClick={webAuthnAuthenticate} onClick={webAuthnAuthenticate}
autoFocus={true} autoFocus={true}
value={msgStr("webauthn-doAuthenticate")} value={msgStr("webauthn-doAuthenticate")}
className={cx( className={clsx(
kcProps.kcButtonClass, kcProps.kcButtonClass,
kcProps.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
kcProps.kcButtonBlockClass, kcProps.kcButtonBlockClass,

View File

@ -1,7 +1,7 @@
import React, { memo, useEffect, Fragment } from "react"; import React, { memo, useEffect, Fragment } from "react";
import type { KcProps } from "../KcProps"; import type { KcProps } from "../KcProps";
import type { Attribute } from "../../getKcContext/KcContextBase"; import type { Attribute } from "../../getKcContext/KcContextBase";
import { useCssAndCx } from "../../tools/useCssAndCx"; import { clsx } from "../../tools/clsx";
import type { ReactComponent } from "../../tools/ReactComponent"; import type { ReactComponent } from "../../tools/ReactComponent";
import { useCallbackFactory } from "powerhooks/useCallbackFactory"; import { useCallbackFactory } from "powerhooks/useCallbackFactory";
import { useFormValidationSlice } from "../../useFormValidationSlice"; import { useFormValidationSlice } from "../../useFormValidationSlice";
@ -18,8 +18,6 @@ export type UserProfileFormFieldsProps = {
export const UserProfileFormFields = memo( export const UserProfileFormFields = memo(
({ kcContext, onIsFormSubmittableValueChange, i18n, BeforeField, AfterField, ...props }: UserProfileFormFieldsProps) => { ({ kcContext, onIsFormSubmittableValueChange, i18n, BeforeField, AfterField, ...props }: UserProfileFormFieldsProps) => {
const { cx, css } = useCssAndCx();
const { advancedMsg } = i18n; const { advancedMsg } = i18n;
const { const {
@ -67,20 +65,20 @@ export const UserProfileFormFields = memo(
const { value, displayableErrors } = fieldStateByAttributeName[attribute.name]; const { value, displayableErrors } = fieldStateByAttributeName[attribute.name];
const formGroupClassName = cx(props.kcFormGroupClass, displayableErrors.length !== 0 && props.kcFormGroupErrorClass); const formGroupClassName = clsx(props.kcFormGroupClass, displayableErrors.length !== 0 && props.kcFormGroupErrorClass);
return ( return (
<Fragment key={i}> <Fragment key={i}>
{group !== currentGroup && (currentGroup = group) !== "" && ( {group !== currentGroup && (currentGroup = group) !== "" && (
<div className={formGroupClassName}> <div className={formGroupClassName}>
<div className={cx(props.kcContentWrapperClass)}> <div className={clsx(props.kcContentWrapperClass)}>
<label id={`header-${group}`} className={cx(props.kcFormGroupHeader)}> <label id={`header-${group}`} className={clsx(props.kcFormGroupHeader)}>
{advancedMsg(groupDisplayHeader) || currentGroup} {advancedMsg(groupDisplayHeader) || currentGroup}
</label> </label>
</div> </div>
{groupDisplayDescription !== "" && ( {groupDisplayDescription !== "" && (
<div className={cx(props.kcLabelWrapperClass)}> <div className={clsx(props.kcLabelWrapperClass)}>
<label id={`description-${group}`} className={`${cx(props.kcLabelClass)}`}> <label id={`description-${group}`} className={`${clsx(props.kcLabelClass)}`}>
{advancedMsg(groupDisplayDescription)} {advancedMsg(groupDisplayDescription)}
</label> </label>
</div> </div>
@ -91,13 +89,13 @@ export const UserProfileFormFields = memo(
{BeforeField && <BeforeField attribute={attribute} />} {BeforeField && <BeforeField attribute={attribute} />}
<div className={formGroupClassName}> <div className={formGroupClassName}>
<div className={cx(props.kcLabelWrapperClass)}> <div className={clsx(props.kcLabelWrapperClass)}>
<label htmlFor={attribute.name} className={cx(props.kcLabelClass)}> <label htmlFor={attribute.name} className={clsx(props.kcLabelClass)}>
{advancedMsg(attribute.displayName ?? "")} {advancedMsg(attribute.displayName ?? "")}
</label> </label>
{attribute.required && <>*</>} {attribute.required && <>*</>}
</div> </div>
<div className={cx(props.kcInputWrapperClass)}> <div className={clsx(props.kcInputWrapperClass)}>
{(() => { {(() => {
const { options } = attribute.validators; const { options } = attribute.validators;
@ -134,7 +132,7 @@ export const UserProfileFormFields = memo(
name={attribute.name} name={attribute.name}
value={value} value={value}
onChange={onChangeFactory(attribute.name)} onChange={onChangeFactory(attribute.name)}
className={cx(props.kcInputClass)} className={clsx(props.kcInputClass)}
aria-invalid={displayableErrors.length !== 0} aria-invalid={displayableErrors.length !== 0}
disabled={attribute.readOnly} disabled={attribute.readOnly}
autoComplete={attribute.autocomplete} autoComplete={attribute.autocomplete}
@ -142,21 +140,26 @@ export const UserProfileFormFields = memo(
/> />
); );
})()} })()}
{displayableErrors.length !== 0 && ( {displayableErrors.length !== 0 &&
(() => {
const divId = `input-error-${attribute.name}`;
return (
<>
<style>{`#${divId} > span: { display: block; }`}</style>
<span <span
id={`input-error-${attribute.name}`} id={divId}
className={cx( className={clsx(props.kcInputErrorMessageClass)}
props.kcInputErrorMessageClass, style={{
css({ "position": displayableErrors.length === 1 ? "absolute" : undefined
"position": displayableErrors.length === 1 ? "absolute" : undefined, }}
"& > span": { "display": "block" }
})
)}
aria-live="polite" aria-live="polite"
> >
{displayableErrors.map(({ errorMessage }) => errorMessage)} {displayableErrors.map(({ errorMessage }) => errorMessage)}
</span> </span>
)} </>
);
})()}
</div> </div>
</div> </div>

7
src/lib/tools/clsx.ts Normal file
View File

@ -0,0 +1,7 @@
import { classnames } from "tss-react/tools/classnames";
import type { Cx } from "tss-react";
/** Drop in replacement for https://www.npmjs.com/package/clsx */
export const clsx: Cx = (...args) => {
return classnames(args);
};

View File

@ -1,11 +1,12 @@
import { createMakeStyles } from "tss-react"; import { clsx as cx } from "./clsx";
const { useStyles } = createMakeStyles({
"useTheme": () => ({})
});
/**
* @deprecated: Use clsx instead.
* import { clsx } from "keycloakify/lib/tools/clsx";
* You can use clsx as cx.
* If you where using the css() function you can import
* it from @emotion/css: https://emotion.sh/docs/@emotion/css
*/
export function useCssAndCx() { export function useCssAndCx() {
const { css, cx } = useStyles(); return { cx };
return { css, cx };
} }

View File

@ -104,9 +104,9 @@
"@babel/types" "^7.19.0" "@babel/types" "^7.19.0"
"@babel/helper-plugin-utils@^7.18.6": "@babel/helper-plugin-utils@^7.18.6":
version "7.18.9" version "7.19.0"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz#4b8aea3b069d8cb8a72cdfe28ddf5ceca695ef2f" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz#4796bb14961521f0f8715990bee2fb6e51ce21bf"
integrity sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w== integrity sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==
"@babel/helper-simple-access@^7.18.6": "@babel/helper-simple-access@^7.18.6":
version "7.18.6" version "7.18.6"
@ -173,9 +173,9 @@
"@babel/helper-plugin-utils" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6"
"@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3": "@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3":
version "7.18.9" version "7.19.4"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.19.4.tgz#a42f814502ee467d55b38dd1c256f53a7b885c78"
integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw== integrity sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==
dependencies: dependencies:
regenerator-runtime "^0.13.4" regenerator-runtime "^0.13.4"
@ -240,7 +240,7 @@
source-map "^0.5.7" source-map "^0.5.7"
stylis "4.0.13" stylis "4.0.13"
"@emotion/cache@*", "@emotion/cache@^11.10.0": "@emotion/cache@^11.10.0":
version "11.10.3" version "11.10.3"
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.3.tgz#c4f67904fad10c945fea5165c3a5a0583c164b87" resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.10.3.tgz#c4f67904fad10c945fea5165c3a5a0583c164b87"
integrity sha512-Psmp/7ovAa8appWh3g51goxu/z3iVms7JXOreq136D8Bbn6dYraPnmL6mdM8GThEx9vwSn92Fz+mGSjBzN8UPQ== integrity sha512-Psmp/7ovAa8appWh3g51goxu/z3iVms7JXOreq136D8Bbn6dYraPnmL6mdM8GThEx9vwSn92Fz+mGSjBzN8UPQ==
@ -261,7 +261,7 @@
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f" resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.0.tgz#f580f9beb67176fa57aae70b08ed510e1b18980f"
integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA== integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==
"@emotion/react@^11.4.1": "@emotion/react@^11.10.4":
version "11.10.4" version "11.10.4"
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.10.4.tgz#9dc6bccbda5d70ff68fdb204746c0e8b13a79199" resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.10.4.tgz#9dc6bccbda5d70ff68fdb204746c0e8b13a79199"
integrity sha512-j0AkMpr6BL8gldJZ6XQsQ8DnS9TxEQu1R+OGmDZiWjBAJtCcbt0tS3I/YffoqHXxH6MjgI7KdMbYKw3MEiU9eA== integrity sha512-j0AkMpr6BL8gldJZ6XQsQ8DnS9TxEQu1R+OGmDZiWjBAJtCcbt0tS3I/YffoqHXxH6MjgI7KdMbYKw3MEiU9eA==
@ -275,7 +275,7 @@
"@emotion/weak-memoize" "^0.3.0" "@emotion/weak-memoize" "^0.3.0"
hoist-non-react-statics "^3.3.1" hoist-non-react-statics "^3.3.1"
"@emotion/serialize@*", "@emotion/serialize@^1.1.0": "@emotion/serialize@^1.1.0":
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.0.tgz#b1f97b1011b09346a40e9796c37a3397b4ea8ea8" resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.0.tgz#b1f97b1011b09346a40e9796c37a3397b4ea8ea8"
integrity sha512-F1ZZZW51T/fx+wKbVlwsfchr5q97iW8brAnXmsskz4d0hVB4O3M/SiA3SaeH06x02lSNzkkQv+n3AX3kCXKSFA== integrity sha512-F1ZZZW51T/fx+wKbVlwsfchr5q97iW8brAnXmsskz4d0hVB4O3M/SiA3SaeH06x02lSNzkkQv+n3AX3kCXKSFA==
@ -301,7 +301,7 @@
resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz#ffadaec35dbb7885bd54de3fa267ab2f860294df" resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.0.tgz#ffadaec35dbb7885bd54de3fa267ab2f860294df"
integrity sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A== integrity sha512-1eEgUGmkaljiBnRMTdksDV1W4kUnmwgp7X9G8B++9GYwl1lUdqSndSriIrTJ0N7LQaoauY9JJ2yhiOYK5+NI4A==
"@emotion/utils@*", "@emotion/utils@^1.2.0": "@emotion/utils@^1.2.0":
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.0.tgz#9716eaccbc6b5ded2ea5a90d65562609aab0f561" resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.0.tgz#9716eaccbc6b5ded2ea5a90d65562609aab0f561"
integrity sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw== integrity sha512-sn3WH53Kzpw8oQ5mgMmIzzyAaH2ZqFEbozVVBSYp538E06OSE6ytOp7pRAjNQR+Q/orwqdQYJSe2m3hCOeznkw==
@ -763,7 +763,12 @@ concat-map@0.0.1:
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
convert-source-map@^1.5.0, convert-source-map@^1.7.0: convert-source-map@^1.5.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f"
integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==
convert-source-map@^1.7.0:
version "1.8.0" version "1.8.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
@ -1722,9 +1727,9 @@ readable-stream@~2.3.6:
util-deprecate "~1.0.1" util-deprecate "~1.0.1"
regenerator-runtime@^0.13.4: regenerator-runtime@^0.13.4:
version "0.13.9" version "0.13.10"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz#ed07b19616bcbec5da6274ebc75ae95634bfc2ee"
integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== integrity sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==
remark-parse@^9.0.0: remark-parse@^9.0.0:
version "9.0.0" version "9.0.0"
@ -2002,14 +2007,10 @@ tslib@^2.1.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
tss-react@^4.3.4: tss-react@4.4.1-rc.0:
version "4.3.4" version "4.4.1-rc.0"
resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-4.3.4.tgz#1e6d67f963562f4c232ec28ca4d90c8aac3a728b" resolved "https://registry.yarnpkg.com/tss-react/-/tss-react-4.4.1-rc.0.tgz#96f9c2edcb9208ae39e845e6bafc9a50c9b96c66"
integrity sha512-PAEB9NxGtW2nEuPDm90WISi4nb9O+bmY/XyDKp17/CoPsoaW3UqaEi+gTjBmA/P65GCRuZhpZniTOkhLcTDQqg== integrity sha512-ozltdpdDrB/6Ml6UpaL/eGwGZzTXXcHnJxwwO7mxcFaZnLaetbbbQHNUerRmqr21i9vgA6HFBAzOv9pa2PUsww==
dependencies:
"@emotion/cache" "*"
"@emotion/serialize" "*"
"@emotion/utils" "*"
type-fest@^0.21.3: type-fest@^0.21.3:
version "0.21.3" version "0.21.3"