#191: Enable to only customize the Template

This commit is contained in:
garronej
2022-10-13 11:58:31 +02:00
parent 3c96d2ea42
commit 688455d0aa
22 changed files with 1856 additions and 1779 deletions

View File

@ -1,23 +1,27 @@
import React, { memo } from "react"; import React, { memo } from "react";
import Template from "./Template"; import DefaultTemplate 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 type { I18n } from "../i18n"; import type { I18n } from "../i18n";
const Error = memo( export type ErrorProps = KcProps & {
({ kcContext: KcContextBase.Error;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.Error; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const Error = memo((props: ErrorProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { message, client } = kcContext; const { message, client } = kcContext;
const { msg } = i18n; const { msg } = i18n;
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
displayMessage={false} displayMessage={false}
headerNode={msg("errorTitle")} headerNode={msg("errorTitle")}
formNode={ formNode={
@ -34,7 +38,6 @@ const Error = memo(
} }
/> />
); );
} });
);
export default Error; export default Error;

View File

@ -1,18 +1,22 @@
import React, { useState, memo } from "react"; import React, { useState, memo } from "react";
import Template from "./Template"; import DefaultTemplate 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 { useCssAndCx } from "../tools/useCssAndCx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
import { UserProfileFormFields } from "./shared/UserProfileCommons"; import { UserProfileFormFields } from "./shared/UserProfileCommons";
const IdpReviewUserProfile = memo( export type IdpReviewUserProfileProps = KcProps & {
({ kcContext: KcContextBase.IdpReviewUserProfile;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.IdpReviewUserProfile; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const IdpReviewUserProfile = memo((props: IdpReviewUserProfileProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { cx } = useCssAndCx(); const { cx } = useCssAndCx();
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
@ -23,23 +27,23 @@ const IdpReviewUserProfile = memo(
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
headerNode={msg("loginIdpReviewProfileTitle")} headerNode={msg("loginIdpReviewProfileTitle")}
formNode={ formNode={
<form id="kc-idp-review-profile-form" className={cx(props.kcFormClass)} action={url.loginAction} method="post"> <form id="kc-idp-review-profile-form" className={cx(kcProps.kcFormClass)} action={url.loginAction} method="post">
<UserProfileFormFields kcContext={kcContext} onIsFormSubmittableValueChange={setIsFomSubmittable} i18n={i18n} {...props} /> <UserProfileFormFields kcContext={kcContext} onIsFormSubmittableValueChange={setIsFomSubmittable} i18n={i18n} {...kcProps} />
<div className={cx(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}> <div id="kc-form-options" className={cx(kcProps.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)} /> <div className={cx(kcProps.kcFormOptionsWrapperClass)} />
</div> </div>
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}> <div id="kc-form-buttons" className={cx(kcProps.kcFormButtonsClass)}>
<input <input
className={cx( className={cx(
props.kcButtonClass, kcProps.kcButtonClass,
props.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
props.kcButtonBlockClass, kcProps.kcButtonBlockClass,
props.kcButtonLargeClass kcProps.kcButtonLargeClass
)} )}
type="submit" type="submit"
value={msgStr("doSubmit")} value={msgStr("doSubmit")}
@ -51,7 +55,6 @@ const IdpReviewUserProfile = memo(
} }
/> />
); );
} });
);
export default IdpReviewUserProfile; export default IdpReviewUserProfile;

View File

@ -1,17 +1,21 @@
import React, { memo } from "react"; import React, { memo } from "react";
import Template from "./Template"; import DefaultTemplate from "./Template";
import type { TemplateProps } from "./Template";
import type { KcProps } from "./KcProps"; import type { KcProps } from "./KcProps";
import { assert } from "../tools/assert"; import { assert } from "../tools/assert";
import type { KcContextBase } from "../getKcContext/KcContextBase"; import type { KcContextBase } from "../getKcContext/KcContextBase";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
const Info = memo( export type InfoProps = KcProps & {
({ kcContext: KcContextBase.Info;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.Info; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const Info = memo((props: InfoProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { msgStr, msg } = i18n; const { msgStr, msg } = i18n;
assert(kcContext.message !== undefined); assert(kcContext.message !== undefined);
@ -20,7 +24,7 @@ const Info = memo(
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
displayMessage={false} displayMessage={false}
headerNode={messageHeader !== undefined ? <>{messageHeader}</> : <>{message.summary}</>} headerNode={messageHeader !== undefined ? <>{messageHeader}</> : <>{message.summary}</>}
formNode={ formNode={
@ -51,7 +55,6 @@ const Info = memo(
} }
/> />
); );
} });
);
export default Info; export default Info;

View File

@ -3,6 +3,8 @@ import type { KcContextBase } from "../getKcContext/KcContextBase";
import type { KcProps } from "./KcProps"; import type { KcProps } from "./KcProps";
import { __unsafe_useI18n as useI18n } from "../i18n"; import { __unsafe_useI18n as useI18n } from "../i18n";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
import DefaultTemplate from "./Template";
import type { TemplateProps } from "./Template";
const Login = lazy(() => import("./Login")); const Login = lazy(() => import("./Login"));
const Register = lazy(() => import("./Register")); const Register = lazy(() => import("./Register"));
@ -26,12 +28,16 @@ const LogoutConfirm = lazy(() => import("./LogoutConfirm"));
const UpdateUserProfile = lazy(() => import("./UpdateUserProfile")); const UpdateUserProfile = lazy(() => import("./UpdateUserProfile"));
const IdpReviewUserProfile = lazy(() => import("./IdpReviewUserProfile")); const IdpReviewUserProfile = lazy(() => import("./IdpReviewUserProfile"));
const KcApp = memo( export type KcAppProps = KcProps & {
({ kcContext: KcContextBase;
kcContext, i18n?: I18n;
i18n: userProvidedI18n, doFetchDefaultThemeResources?: boolean;
...kcProps Template: (props: TemplateProps) => JSX.Element | null;
}: { kcContext: KcContextBase; i18n?: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => { };
const KcApp = memo((props_: KcAppProps) => {
const { kcContext, i18n: userProvidedI18n, Template = DefaultTemplate, ...kcProps } = props_;
const i18n = (function useClosure() { const i18n = (function useClosure() {
const i18n = useI18n({ const i18n = useI18n({
kcContext, kcContext,
@ -46,59 +52,58 @@ const KcApp = memo(
return null; return null;
} }
const props = { i18n, ...kcProps }; const commonProps = { i18n, Template, ...kcProps };
return ( return (
<Suspense> <Suspense>
{(() => { {(() => {
switch (kcContext.pageId) { switch (kcContext.pageId) {
case "login.ftl": case "login.ftl":
return <Login {...{ kcContext, ...props }} />; return <Login {...{ kcContext, ...commonProps }} />;
case "register.ftl": case "register.ftl":
return <Register {...{ kcContext, ...props }} />; return <Register {...{ kcContext, ...commonProps }} />;
case "register-user-profile.ftl": case "register-user-profile.ftl":
return <RegisterUserProfile {...{ kcContext, ...props }} />; return <RegisterUserProfile {...{ kcContext, ...commonProps }} />;
case "info.ftl": case "info.ftl":
return <Info {...{ kcContext, ...props }} />; return <Info {...{ kcContext, ...commonProps }} />;
case "error.ftl": case "error.ftl":
return <Error {...{ kcContext, ...props }} />; return <Error {...{ kcContext, ...commonProps }} />;
case "login-reset-password.ftl": case "login-reset-password.ftl":
return <LoginResetPassword {...{ kcContext, ...props }} />; return <LoginResetPassword {...{ kcContext, ...commonProps }} />;
case "login-verify-email.ftl": case "login-verify-email.ftl":
return <LoginVerifyEmail {...{ kcContext, ...props }} />; return <LoginVerifyEmail {...{ kcContext, ...commonProps }} />;
case "terms.ftl": case "terms.ftl":
return <Terms {...{ kcContext, ...props }} />; return <Terms {...{ kcContext, ...commonProps }} />;
case "login-otp.ftl": case "login-otp.ftl":
return <LoginOtp {...{ kcContext, ...props }} />; return <LoginOtp {...{ kcContext, ...commonProps }} />;
case "login-username.ftl": case "login-username.ftl":
return <LoginUsername {...{ kcContext, ...props }} />; return <LoginUsername {...{ kcContext, ...commonProps }} />;
case "login-password.ftl": case "login-password.ftl":
return <LoginPassword {...{ kcContext, ...props }} />; return <LoginPassword {...{ kcContext, ...commonProps }} />;
case "webauthn-authenticate.ftl": case "webauthn-authenticate.ftl":
return <WebauthnAuthenticate {...{ kcContext, ...props }} />; return <WebauthnAuthenticate {...{ kcContext, ...commonProps }} />;
case "login-update-password.ftl": case "login-update-password.ftl":
return <LoginUpdatePassword {...{ kcContext, ...props }} />; return <LoginUpdatePassword {...{ kcContext, ...commonProps }} />;
case "login-update-profile.ftl": case "login-update-profile.ftl":
return <LoginUpdateProfile {...{ kcContext, ...props }} />; return <LoginUpdateProfile {...{ kcContext, ...commonProps }} />;
case "login-idp-link-confirm.ftl": case "login-idp-link-confirm.ftl":
return <LoginIdpLinkConfirm {...{ kcContext, ...props }} />; return <LoginIdpLinkConfirm {...{ kcContext, ...commonProps }} />;
case "login-idp-link-email.ftl": case "login-idp-link-email.ftl":
return <LoginIdpLinkEmail {...{ kcContext, ...props }} />; return <LoginIdpLinkEmail {...{ kcContext, ...commonProps }} />;
case "login-page-expired.ftl": case "login-page-expired.ftl":
return <LoginPageExpired {...{ kcContext, ...props }} />; return <LoginPageExpired {...{ kcContext, ...commonProps }} />;
case "login-config-totp.ftl": case "login-config-totp.ftl":
return <LoginConfigTotp {...{ kcContext, ...props }} />; return <LoginConfigTotp {...{ kcContext, ...commonProps }} />;
case "logout-confirm.ftl": case "logout-confirm.ftl":
return <LogoutConfirm {...{ kcContext, ...props }} />; return <LogoutConfirm {...{ kcContext, ...commonProps }} />;
case "update-user-profile.ftl": case "update-user-profile.ftl":
return <UpdateUserProfile {...{ kcContext, ...props }} />; return <UpdateUserProfile {...{ kcContext, ...commonProps }} />;
case "idp-review-user-profile.ftl": case "idp-review-user-profile.ftl":
return <IdpReviewUserProfile {...{ kcContext, ...props }} />; return <IdpReviewUserProfile {...{ kcContext, ...commonProps }} />;
} }
})()} })()}
</Suspense> </Suspense>
); );
} });
);
export default KcApp; export default KcApp;

View File

@ -1,5 +1,6 @@
import React, { useState, memo } from "react"; import React, { useState, memo } from "react";
import Template from "./Template"; import DefaultTemplate 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 { useCssAndCx } from "../tools/useCssAndCx";
@ -7,13 +8,16 @@ 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";
const Login = memo( export type LoginProps = KcProps & {
({ kcContext: KcContextBase.Login;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.Login; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const Login = memo((props: LoginProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { social, realm, url, usernameEditDisabled, login, auth, registrationDisabled } = kcContext; const { social, realm, url, usernameEditDisabled, login, auth, registrationDisabled } = kcContext;
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
@ -38,21 +42,21 @@ const Login = memo(
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
displayInfo={social.displayInfo} displayInfo={social.displayInfo}
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 && props.kcContentWrapperClass)}> <div id="kc-form" className={cx(realm.password && social.providers !== undefined && kcProps.kcContentWrapperClass)}>
<div <div
id="kc-form-wrapper" id="kc-form-wrapper"
className={cx( className={cx(
realm.password && social.providers && [props.kcFormSocialAccountContentClass, props.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(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
{(() => { {(() => {
const label = !realm.loginWithEmailAllowed const label = !realm.loginWithEmailAllowed
? "username" ? "username"
@ -64,13 +68,13 @@ const Login = memo(
return ( return (
<> <>
<label htmlFor={autoCompleteHelper} className={cx(props.kcLabelClass)}> <label htmlFor={autoCompleteHelper} className={cx(kcProps.kcLabelClass)}>
{msg(label)} {msg(label)}
</label> </label>
<input <input
tabIndex={1} tabIndex={1}
id={autoCompleteHelper} id={autoCompleteHelper}
className={cx(props.kcInputClass)} className={cx(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.
@ -88,20 +92,20 @@ const Login = memo(
); );
})()} })()}
</div> </div>
<div className={cx(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
<label htmlFor="password" className={cx(props.kcLabelClass)}> <label htmlFor="password" className={cx(kcProps.kcLabelClass)}>
{msg("password")} {msg("password")}
</label> </label>
<input <input
tabIndex={2} tabIndex={2}
id="password" id="password"
className={cx(props.kcInputClass)} className={cx(kcProps.kcInputClass)}
name="password" name="password"
type="password" type="password"
autoComplete="off" autoComplete="off"
/> />
</div> </div>
<div className={cx(props.kcFormGroupClass, props.kcFormSettingClass)}> <div className={cx(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">
@ -122,7 +126,7 @@ const Login = memo(
</div> </div>
)} )}
</div> </div>
<div className={cx(props.kcFormOptionsWrapperClass)}> <div className={cx(kcProps.kcFormOptionsWrapperClass)}>
{realm.resetPasswordAllowed && ( {realm.resetPasswordAllowed && (
<span> <span>
<a tabIndex={5} href={url.loginResetCredentialsUrl}> <a tabIndex={5} href={url.loginResetCredentialsUrl}>
@ -132,7 +136,7 @@ const Login = memo(
)} )}
</div> </div>
</div> </div>
<div id="kc-form-buttons" className={cx(props.kcFormGroupClass)}> <div id="kc-form-buttons" className={cx(kcProps.kcFormGroupClass)}>
<input <input
type="hidden" type="hidden"
id="id-hidden-input" id="id-hidden-input"
@ -146,10 +150,10 @@ const Login = memo(
<input <input
tabIndex={4} tabIndex={4}
className={cx( className={cx(
props.kcButtonClass, kcProps.kcButtonClass,
props.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
props.kcButtonBlockClass, kcProps.kcButtonBlockClass,
props.kcButtonLargeClass kcProps.kcButtonLargeClass
)} )}
name="login" name="login"
id="kc-login" id="kc-login"
@ -162,15 +166,15 @@ const Login = memo(
)} )}
</div> </div>
{realm.password && social.providers !== undefined && ( {realm.password && social.providers !== undefined && (
<div id="kc-social-providers" className={cx(props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass)}> <div id="kc-social-providers" className={cx(kcProps.kcFormSocialAccountContentClass, kcProps.kcFormSocialAccountClass)}>
<ul <ul
className={cx( className={cx(
props.kcFormSocialAccountListClass, kcProps.kcFormSocialAccountListClass,
social.providers.length > 4 && props.kcFormSocialAccountDoubleListClass social.providers.length > 4 && kcProps.kcFormSocialAccountDoubleListClass
)} )}
> >
{social.providers.map(p => ( {social.providers.map(p => (
<li key={p.providerId} className={cx(props.kcFormSocialAccountListLinkClass)}> <li key={p.providerId} className={cx(kcProps.kcFormSocialAccountListLinkClass)}>
<a href={p.loginUrl} id={`zocial-${p.alias}`} className={cx("zocial", p.providerId)}> <a href={p.loginUrl} id={`zocial-${p.alias}`} className={cx("zocial", p.providerId)}>
<span>{p.displayName}</span> <span>{p.displayName}</span>
</a> </a>
@ -197,7 +201,6 @@ const Login = memo(
} }
/> />
); );
} });
);
export default Login; export default Login;

View File

@ -1,17 +1,21 @@
import React, { memo } from "react"; import React, { memo } from "react";
import Template from "./Template"; import DefaultTemplate 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 { useCssAndCx } from "../tools/useCssAndCx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
const LoginConfigTotp = memo( export type LoginConfigTotpProps = KcProps & {
({ kcContext: KcContextBase.LoginConfigTotp;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.LoginConfigTotp; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const LoginConfigTotp = memo((props: LoginConfigTotpProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { url, isAppInitiatedAction, totp, mode, messagesPerField } = kcContext; const { url, isAppInitiatedAction, totp, mode, messagesPerField } = kcContext;
const { cx } = useCssAndCx(); const { cx } = useCssAndCx();
@ -19,14 +23,14 @@ const LoginConfigTotp = memo(
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> = {
HmacSHA1: "SHA1", "HmacSHA1": "SHA1",
HmacSHA256: "SHA256", "HmacSHA256": "SHA256",
HmacSHA512: "SHA512" "HmacSHA512": "SHA512"
}; };
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
headerNode={msg("loginTotpTitle")} headerNode={msg("loginTotpTitle")}
formNode={ formNode={
<> <>
@ -98,26 +102,26 @@ const LoginConfigTotp = memo(
</li> </li>
</ol> </ol>
<form action={url.loginAction} className={cx(props.kcFormClass)} id="kc-totp-settings-form" method="post"> <form action={url.loginAction} className={cx(kcProps.kcFormClass)} id="kc-totp-settings-form" method="post">
<div className={cx(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(kcProps.kcInputWrapperClass)}>
<label htmlFor="totp" className={cx(props.kcLabelClass)}> <label htmlFor="totp" className={cx(kcProps.kcLabelClass)}>
{msg("authenticatorCode")} {msg("authenticatorCode")}
</label>{" "} </label>{" "}
<span className="required">*</span> <span className="required">*</span>
</div> </div>
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="totp" id="totp"
name="totp" name="totp"
autoComplete="off" autoComplete="off"
className={cx(props.kcInputClass)} className={cx(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(props.kcInputErrorMessageClass)} aria-live="polite"> <span id="input-error-otp-code" className={cx(kcProps.kcInputErrorMessageClass)} aria-live="polite">
{messagesPerField.get("totp")} {messagesPerField.get("totp")}
</span> </span>
)} )}
@ -126,24 +130,24 @@ const LoginConfigTotp = memo(
{mode && <input type="hidden" id="mode" value={mode} />} {mode && <input type="hidden" id="mode" value={mode} />}
</div> </div>
<div className={cx(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(kcProps.kcInputWrapperClass)}>
<label htmlFor="userLabel" className={cx(props.kcLabelClass)}> <label htmlFor="userLabel" className={cx(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(props.kcInputWrapperClass)}> <div className={cx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="userLabel" id="userLabel"
name="userLabel" name="userLabel"
autoComplete="off" autoComplete="off"
className={cx(props.kcInputClass)} className={cx(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(props.kcInputErrorMessageClass)} aria-live="polite"> <span id="input-error-otp-label" className={cx(kcProps.kcInputErrorMessageClass)} aria-live="polite">
{messagesPerField.get("userLabel")} {messagesPerField.get("userLabel")}
</span> </span>
)} )}
@ -154,17 +158,17 @@ const LoginConfigTotp = memo(
<> <>
<input <input
type="submit" type="submit"
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonLargeClass)} className={cx(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={cx(
props.kcButtonClass, kcProps.kcButtonClass,
props.kcButtonDefaultClass, kcProps.kcButtonDefaultClass,
props.kcButtonLargeClass, kcProps.kcButtonLargeClass,
props.kcButtonLargeClass kcProps.kcButtonLargeClass
)} )}
id="cancelTOTPBtn" id="cancelTOTPBtn"
name="cancel-aia" name="cancel-aia"
@ -176,7 +180,7 @@ const LoginConfigTotp = memo(
) : ( ) : (
<input <input
type="submit" type="submit"
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonLargeClass)} className={cx(kcProps.kcButtonClass, kcProps.kcButtonPrimaryClass, kcProps.kcButtonLargeClass)}
id="saveTOTPBtn" id="saveTOTPBtn"
value={msgStr("doSubmit")} value={msgStr("doSubmit")}
/> />
@ -186,7 +190,6 @@ const LoginConfigTotp = memo(
} }
/> />
); );
} });
);
export default LoginConfigTotp; export default LoginConfigTotp;

View File

@ -1,17 +1,21 @@
import React, { memo } from "react"; import React, { memo } from "react";
import Template from "./Template"; import DefaultTemplate 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 { useCssAndCx } from "../tools/useCssAndCx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
const LoginIdpLinkConfirm = memo( export type LoginIdpLinkConfirmProps = KcProps & {
({ kcContext: KcContextBase.LoginIdpLinkConfirm;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.LoginIdpLinkConfirm; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const LoginIdpLinkConfirm = memo((props: LoginIdpLinkConfirmProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { url, idpAlias } = kcContext; const { url, idpAlias } = kcContext;
const { msg } = i18n; const { msg } = i18n;
@ -20,14 +24,19 @@ const LoginIdpLinkConfirm = memo(
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ 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(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
<button <button
type="submit" type="submit"
className={cx(props.kcButtonClass, props.kcButtonDefaultClass, props.kcButtonBlockClass, props.kcButtonLargeClass)} className={cx(
kcProps.kcButtonClass,
kcProps.kcButtonDefaultClass,
kcProps.kcButtonBlockClass,
kcProps.kcButtonLargeClass
)}
name="submitAction" name="submitAction"
id="updateProfile" id="updateProfile"
value="updateProfile" value="updateProfile"
@ -36,7 +45,12 @@ const LoginIdpLinkConfirm = memo(
</button> </button>
<button <button
type="submit" type="submit"
className={cx(props.kcButtonClass, props.kcButtonDefaultClass, props.kcButtonBlockClass, props.kcButtonLargeClass)} className={cx(
kcProps.kcButtonClass,
kcProps.kcButtonDefaultClass,
kcProps.kcButtonBlockClass,
kcProps.kcButtonLargeClass
)}
name="submitAction" name="submitAction"
id="linkAccount" id="linkAccount"
value="linkAccount" value="linkAccount"
@ -48,7 +62,6 @@ const LoginIdpLinkConfirm = memo(
} }
/> />
); );
} });
);
export default LoginIdpLinkConfirm; export default LoginIdpLinkConfirm;

View File

@ -1,23 +1,27 @@
import React, { memo } from "react"; import React, { memo } from "react";
import Template from "./Template"; import DefaultTemplate 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 type { I18n } from "../i18n"; import type { I18n } from "../i18n";
const LoginIdpLinkEmail = memo( export type LoginIdpLinkEmailProps = KcProps & {
({ kcContext: KcContextBase.LoginIdpLinkEmail;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.LoginIdpLinkEmail; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const LoginIdpLinkEmail = memo((props: LoginIdpLinkEmailProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { url, realm, brokerContext, idpAlias } = kcContext; const { url, realm, brokerContext, idpAlias } = kcContext;
const { msg } = i18n; const { msg } = i18n;
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
headerNode={msg("emailLinkIdpTitle", idpAlias)} headerNode={msg("emailLinkIdpTitle", idpAlias)}
formNode={ formNode={
<> <>
@ -34,7 +38,6 @@ const LoginIdpLinkEmail = memo(
} }
/> />
); );
} });
);
export default LoginIdpLinkEmail; export default LoginIdpLinkEmail;

View File

@ -1,5 +1,6 @@
import React, { useEffect, memo } from "react"; import React, { useEffect, memo } from "react";
import Template from "./Template"; import DefaultTemplate 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 { headInsert } from "../tools/headInsert"; import { headInsert } from "../tools/headInsert";
@ -7,13 +8,16 @@ import { pathJoin } from "../../bin/tools/pathJoin";
import { useCssAndCx } from "../tools/useCssAndCx"; import { useCssAndCx } from "../tools/useCssAndCx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
const LoginOtp = memo( export type LoginOtpProps = KcProps & {
({ kcContext: KcContextBase.LoginOtp;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.LoginOtp; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const LoginOtp = memo((props: LoginOtpProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { otpLogin, url } = kcContext; const { otpLogin, url } = kcContext;
const { cx } = useCssAndCx(); const { cx } = useCssAndCx();
@ -39,49 +43,49 @@ const LoginOtp = memo(
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
headerNode={msg("doLogIn")} headerNode={msg("doLogIn")}
formNode={ formNode={
<form id="kc-otp-login-form" className={cx(props.kcFormClass)} action={url.loginAction} method="post"> <form id="kc-otp-login-form" className={cx(kcProps.kcFormClass)} action={url.loginAction} method="post">
{otpLogin.userOtpCredentials.length > 1 && ( {otpLogin.userOtpCredentials.length > 1 && (
<div className={cx(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(kcProps.kcInputWrapperClass)}>
{otpLogin.userOtpCredentials.map(otpCredential => ( {otpLogin.userOtpCredentials.map(otpCredential => (
<div key={otpCredential.id} className={cx(props.kcSelectOTPListClass)}> <div key={otpCredential.id} className={cx(kcProps.kcSelectOTPListClass)}>
<input type="hidden" value="${otpCredential.id}" /> <input type="hidden" value="${otpCredential.id}" />
<div className={cx(props.kcSelectOTPListItemClass)}> <div className={cx(kcProps.kcSelectOTPListItemClass)}>
<span className={cx(props.kcAuthenticatorOtpCircleClass)} /> <span className={cx(kcProps.kcAuthenticatorOtpCircleClass)} />
<h2 className={cx(props.kcSelectOTPItemHeadingClass)}>{otpCredential.userLabel}</h2> <h2 className={cx(kcProps.kcSelectOTPItemHeadingClass)}>{otpCredential.userLabel}</h2>
</div> </div>
</div> </div>
))} ))}
</div> </div>
</div> </div>
)} )}
<div className={cx(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
<div className={cx(props.kcLabelWrapperClass)}> <div className={cx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="otp" className={cx(props.kcLabelClass)}> <label htmlFor="otp" className={cx(kcProps.kcLabelClass)}>
{msg("loginOtpOneTime")} {msg("loginOtpOneTime")}
</label> </label>
</div> </div>
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(kcProps.kcInputWrapperClass)}>
<input id="otp" name="otp" autoComplete="off" type="text" className={cx(props.kcInputClass)} autoFocus /> <input id="otp" name="otp" autoComplete="off" type="text" className={cx(kcProps.kcInputClass)} autoFocus />
</div> </div>
</div> </div>
<div className={cx(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}> <div id="kc-form-options" className={cx(kcProps.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)} /> <div className={cx(kcProps.kcFormOptionsWrapperClass)} />
</div> </div>
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}> <div id="kc-form-buttons" className={cx(kcProps.kcFormButtonsClass)}>
<input <input
className={cx( className={cx(
props.kcButtonClass, kcProps.kcButtonClass,
props.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
props.kcButtonBlockClass, kcProps.kcButtonBlockClass,
props.kcButtonLargeClass kcProps.kcButtonLargeClass
)} )}
name="login" name="login"
id="kc-login" id="kc-login"
@ -94,8 +98,7 @@ const LoginOtp = memo(
} }
/> />
); );
} });
);
declare const $: any; declare const $: any;

View File

@ -1,23 +1,27 @@
import React, { memo } from "react"; import React, { memo } from "react";
import Template from "./Template"; import DefaultTemplate 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 type { I18n } from "../i18n"; import type { I18n } from "../i18n";
const LoginPageExpired = memo( export type LoginPageExpired = KcProps & {
({ kcContext: KcContextBase.LoginPageExpired;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.LoginPageExpired; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const LoginPageExpired = memo((props: LoginPageExpired) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { url } = kcContext; const { url } = kcContext;
const { msg } = i18n; const { msg } = i18n;
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
displayMessage={false} displayMessage={false}
headerNode={msg("pageExpiredTitle")} headerNode={msg("pageExpiredTitle")}
formNode={ formNode={
@ -38,7 +42,6 @@ const LoginPageExpired = memo(
} }
/> />
); );
} });
);
export default LoginPageExpired; export default LoginPageExpired;

View File

@ -1,5 +1,6 @@
import React, { useState, memo } from "react"; import React, { useState, memo } from "react";
import Template from "./Template"; import DefaultTemplate 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 { useCssAndCx } from "../tools/useCssAndCx";
@ -7,13 +8,16 @@ 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";
const LoginPassword = memo( export type LoginPasswordProps = KcProps & {
({ kcContext: KcContextBase.LoginPassword;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.LoginPassword; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const LoginPassword = memo((props: LoginPasswordProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { realm, url, login } = kcContext; const { realm, url, login } = kcContext;
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
@ -34,21 +38,21 @@ const LoginPassword = memo(
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
headerNode={msg("doLogIn")} headerNode={msg("doLogIn")}
formNode={ formNode={
<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(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
<hr /> <hr />
<label htmlFor="password" className={cx(props.kcLabelClass)}> <label htmlFor="password" className={cx(kcProps.kcLabelClass)}>
{msg("password")} {msg("password")}
</label> </label>
<input <input
tabIndex={2} tabIndex={2}
id="password" id="password"
className={cx(props.kcInputClass)} className={cx(kcProps.kcInputClass)}
name="password" name="password"
type="password" type="password"
autoFocus={true} autoFocus={true}
@ -56,9 +60,9 @@ const LoginPassword = memo(
defaultValue={login.password ?? ""} defaultValue={login.password ?? ""}
/> />
</div> </div>
<div className={cx(props.kcFormGroupClass, props.kcFormSettingClass)}> <div className={cx(kcProps.kcFormGroupClass, kcProps.kcFormSettingClass)}>
<div id="kc-form-options" /> <div id="kc-form-options" />
<div className={cx(props.kcFormOptionsWrapperClass)}> <div className={cx(kcProps.kcFormOptionsWrapperClass)}>
{realm.resetPasswordAllowed && ( {realm.resetPasswordAllowed && (
<span> <span>
<a tabIndex={5} href={url.loginResetCredentialsUrl}> <a tabIndex={5} href={url.loginResetCredentialsUrl}>
@ -68,14 +72,14 @@ const LoginPassword = memo(
)} )}
</div> </div>
</div> </div>
<div id="kc-form-buttons" className={cx(props.kcFormGroupClass)}> <div id="kc-form-buttons" className={cx(kcProps.kcFormGroupClass)}>
<input <input
tabIndex={4} tabIndex={4}
className={cx( className={cx(
props.kcButtonClass, kcProps.kcButtonClass,
props.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
props.kcButtonBlockClass, kcProps.kcButtonBlockClass,
props.kcButtonLargeClass kcProps.kcButtonLargeClass
)} )}
name="login" name="login"
id="kc-login" id="kc-login"
@ -90,7 +94,6 @@ const LoginPassword = memo(
} }
/> />
); );
} });
);
export default LoginPassword; export default LoginPassword;

View File

@ -1,17 +1,21 @@
import React, { memo } from "react"; import React, { memo } from "react";
import Template from "./Template"; import DefaultTemplate 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 { useCssAndCx } from "../tools/useCssAndCx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
const LoginResetPassword = memo( export type LoginResetPasswordProps = KcProps & {
({ kcContext: KcContextBase.LoginResetPassword;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.LoginResetPassword; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const LoginResetPassword = memo((props: LoginResetPasswordProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { url, realm, auth } = kcContext; const { url, realm, auth } = kcContext;
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
@ -20,14 +24,14 @@ const LoginResetPassword = memo(
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
displayMessage={false} displayMessage={false}
headerNode={msg("emailForgotTitle")} headerNode={msg("emailForgotTitle")}
formNode={ formNode={
<form id="kc-reset-password-form" className={cx(props.kcFormClass)} action={url.loginAction} method="post"> <form id="kc-reset-password-form" className={cx(kcProps.kcFormClass)} action={url.loginAction} method="post">
<div className={cx(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
<div className={cx(props.kcLabelWrapperClass)}> <div className={cx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="username" className={cx(props.kcLabelClass)}> <label htmlFor="username" className={cx(kcProps.kcLabelClass)}>
{!realm.loginWithEmailAllowed {!realm.loginWithEmailAllowed
? msg("username") ? msg("username")
: !realm.registrationEmailAsUsername : !realm.registrationEmailAsUsername
@ -35,33 +39,33 @@ const LoginResetPassword = memo(
: msg("email")} : msg("email")}
</label> </label>
</div> </div>
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="username" id="username"
name="username" name="username"
className={cx(props.kcInputClass)} className={cx(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(props.kcFormGroupClass, props.kcFormSettingClass)}> <div className={cx(kcProps.kcFormGroupClass, kcProps.kcFormSettingClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}> <div id="kc-form-options" className={cx(kcProps.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)}> <div className={cx(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(props.kcFormButtonsClass)}> <div id="kc-form-buttons" className={cx(kcProps.kcFormButtonsClass)}>
<input <input
className={cx( className={cx(
props.kcButtonClass, kcProps.kcButtonClass,
props.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
props.kcButtonBlockClass, kcProps.kcButtonBlockClass,
props.kcButtonLargeClass kcProps.kcButtonLargeClass
)} )}
type="submit" type="submit"
value={msgStr("doSubmit")} value={msgStr("doSubmit")}
@ -73,7 +77,6 @@ const LoginResetPassword = memo(
infoNode={msg("emailInstruction")} infoNode={msg("emailInstruction")}
/> />
); );
} });
);
export default LoginResetPassword; export default LoginResetPassword;

View File

@ -1,17 +1,21 @@
import React, { memo } from "react"; import React, { memo } from "react";
import Template from "./Template"; import DefaultTemplate 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 { useCssAndCx } from "../tools/useCssAndCx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
const LoginUpdatePassword = memo( export type LoginUpdatePasswordProps = KcProps & {
({ kcContext: KcContextBase.LoginUpdatePassword;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.LoginUpdatePassword; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const LoginUpdatePassword = memo((props: LoginUpdatePasswordProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { cx } = useCssAndCx(); const { cx } = useCssAndCx();
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
@ -20,10 +24,10 @@ const LoginUpdatePassword = memo(
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
headerNode={msg("updatePasswordTitle")} headerNode={msg("updatePasswordTitle")}
formNode={ formNode={
<form id="kc-passwd-update-form" className={cx(props.kcFormClass)} action={url.loginAction} method="post"> <form id="kc-passwd-update-form" className={cx(kcProps.kcFormClass)} action={url.loginAction} method="post">
<input <input
type="text" type="text"
id="username" id="username"
@ -35,44 +39,44 @@ const LoginUpdatePassword = memo(
/> />
<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(props.kcFormGroupClass, messagesPerField.printIfExists("password", props.kcFormGroupErrorClass))}> <div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("password", kcProps.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}> <div className={cx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="password-new" className={cx(props.kcLabelClass)}> <label htmlFor="password-new" className={cx(kcProps.kcLabelClass)}>
{msg("passwordNew")} {msg("passwordNew")}
</label> </label>
</div> </div>
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(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(props.kcInputClass)} className={cx(kcProps.kcInputClass)}
/> />
</div> </div>
</div> </div>
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("password-confirm", props.kcFormGroupErrorClass))}> <div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("password-confirm", kcProps.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}> <div className={cx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="password-confirm" className={cx(props.kcLabelClass)}> <label htmlFor="password-confirm" className={cx(kcProps.kcLabelClass)}>
{msg("passwordConfirm")} {msg("passwordConfirm")}
</label> </label>
</div> </div>
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(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(props.kcInputClass)} className={cx(kcProps.kcInputClass)}
/> />
</div> </div>
</div> </div>
<div className={cx(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}> <div id="kc-form-options" className={cx(kcProps.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)}> <div className={cx(kcProps.kcFormOptionsWrapperClass)}>
{isAppInitiatedAction && ( {isAppInitiatedAction && (
<div className="checkbox"> <div className="checkbox">
<label> <label>
@ -84,16 +88,16 @@ const LoginUpdatePassword = memo(
</div> </div>
</div> </div>
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}> <div id="kc-form-buttons" className={cx(kcProps.kcFormButtonsClass)}>
{isAppInitiatedAction ? ( {isAppInitiatedAction ? (
<> <>
<input <input
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonLargeClass)} className={cx(kcProps.kcButtonClass, kcProps.kcButtonPrimaryClass, kcProps.kcButtonLargeClass)}
type="submit" type="submit"
defaultValue={msgStr("doSubmit")} defaultValue={msgStr("doSubmit")}
/> />
<button <button
className={cx(props.kcButtonClass, props.kcButtonDefaultClass, props.kcButtonLargeClass)} className={cx(kcProps.kcButtonClass, kcProps.kcButtonDefaultClass, kcProps.kcButtonLargeClass)}
type="submit" type="submit"
name="cancel-aia" name="cancel-aia"
value="true" value="true"
@ -104,10 +108,10 @@ const LoginUpdatePassword = memo(
) : ( ) : (
<input <input
className={cx( className={cx(
props.kcButtonClass, kcProps.kcButtonClass,
props.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
props.kcButtonBlockClass, kcProps.kcButtonBlockClass,
props.kcButtonLargeClass kcProps.kcButtonLargeClass
)} )}
type="submit" type="submit"
defaultValue={msgStr("doSubmit")} defaultValue={msgStr("doSubmit")}
@ -119,7 +123,6 @@ const LoginUpdatePassword = memo(
} }
/> />
); );
} });
);
export default LoginUpdatePassword; export default LoginUpdatePassword;

View File

@ -1,17 +1,21 @@
import React, { memo } from "react"; import React, { memo } from "react";
import Template from "./Template"; import DefaultTemplate 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 { useCssAndCx } from "../tools/useCssAndCx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
const LoginUpdateProfile = memo( export type LoginUpdateProfile = KcProps & {
({ kcContext: KcContextBase.LoginUpdateProfile;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.LoginUpdateProfile; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const LoginUpdateProfile = memo((props: LoginUpdateProfile) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { cx } = useCssAndCx(); const { cx } = useCssAndCx();
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
@ -20,89 +24,89 @@ const LoginUpdateProfile = memo(
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
headerNode={msg("loginProfileTitle")} headerNode={msg("loginProfileTitle")}
formNode={ formNode={
<form id="kc-update-profile-form" className={cx(props.kcFormClass)} action={url.loginAction} method="post"> <form id="kc-update-profile-form" className={cx(kcProps.kcFormClass)} action={url.loginAction} method="post">
{user.editUsernameAllowed && ( {user.editUsernameAllowed && (
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("username", props.kcFormGroupErrorClass))}> <div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("username", kcProps.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}> <div className={cx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="username" className={cx(props.kcLabelClass)}> <label htmlFor="username" className={cx(kcProps.kcLabelClass)}>
{msg("username")} {msg("username")}
</label> </label>
</div> </div>
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="username" id="username"
name="username" name="username"
defaultValue={user.username ?? ""} defaultValue={user.username ?? ""}
className={cx(props.kcInputClass)} className={cx(kcProps.kcInputClass)}
/> />
</div> </div>
</div> </div>
)} )}
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("email", props.kcFormGroupErrorClass))}> <div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("email", kcProps.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}> <div className={cx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="email" className={cx(props.kcLabelClass)}> <label htmlFor="email" className={cx(kcProps.kcLabelClass)}>
{msg("email")} {msg("email")}
</label> </label>
</div> </div>
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(kcProps.kcInputWrapperClass)}>
<input type="text" id="email" name="email" defaultValue={user.email ?? ""} className={cx(props.kcInputClass)} /> <input type="text" id="email" name="email" defaultValue={user.email ?? ""} className={cx(kcProps.kcInputClass)} />
</div> </div>
</div> </div>
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("firstName", props.kcFormGroupErrorClass))}> <div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("firstName", kcProps.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}> <div className={cx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="firstName" className={cx(props.kcLabelClass)}> <label htmlFor="firstName" className={cx(kcProps.kcLabelClass)}>
{msg("firstName")} {msg("firstName")}
</label> </label>
</div> </div>
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="firstName" id="firstName"
name="firstName" name="firstName"
defaultValue={user.firstName ?? ""} defaultValue={user.firstName ?? ""}
className={cx(props.kcInputClass)} className={cx(kcProps.kcInputClass)}
/> />
</div> </div>
</div> </div>
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("lastName", props.kcFormGroupErrorClass))}> <div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("lastName", kcProps.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}> <div className={cx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="lastName" className={cx(props.kcLabelClass)}> <label htmlFor="lastName" className={cx(kcProps.kcLabelClass)}>
{msg("lastName")} {msg("lastName")}
</label> </label>
</div> </div>
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="lastName" id="lastName"
name="lastName" name="lastName"
defaultValue={user.lastName ?? ""} defaultValue={user.lastName ?? ""}
className={cx(props.kcInputClass)} className={cx(kcProps.kcInputClass)}
/> />
</div> </div>
</div> </div>
<div className={cx(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}> <div id="kc-form-options" className={cx(kcProps.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)} /> <div className={cx(kcProps.kcFormOptionsWrapperClass)} />
</div> </div>
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}> <div id="kc-form-buttons" className={cx(kcProps.kcFormButtonsClass)}>
{isAppInitiatedAction ? ( {isAppInitiatedAction ? (
<> <>
<input <input
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonLargeClass)} className={cx(kcProps.kcButtonClass, kcProps.kcButtonPrimaryClass, kcProps.kcButtonLargeClass)}
type="submit" type="submit"
defaultValue={msgStr("doSubmit")} defaultValue={msgStr("doSubmit")}
/> />
<button <button
className={cx(props.kcButtonClass, props.kcButtonDefaultClass, props.kcButtonLargeClass)} className={cx(kcProps.kcButtonClass, kcProps.kcButtonDefaultClass, kcProps.kcButtonLargeClass)}
type="submit" type="submit"
name="cancel-aia" name="cancel-aia"
value="true" value="true"
@ -113,10 +117,10 @@ const LoginUpdateProfile = memo(
) : ( ) : (
<input <input
className={cx( className={cx(
props.kcButtonClass, kcProps.kcButtonClass,
props.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
props.kcButtonBlockClass, kcProps.kcButtonBlockClass,
props.kcButtonLargeClass kcProps.kcButtonLargeClass
)} )}
type="submit" type="submit"
defaultValue={msgStr("doSubmit")} defaultValue={msgStr("doSubmit")}
@ -128,7 +132,6 @@ const LoginUpdateProfile = memo(
} }
/> />
); );
} });
);
export default LoginUpdateProfile; export default LoginUpdateProfile;

View File

@ -1,5 +1,6 @@
import React, { useState, memo } from "react"; import React, { useState, memo } from "react";
import Template from "./Template"; import DefaultTemplate 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 { useCssAndCx } from "../tools/useCssAndCx";
@ -7,13 +8,16 @@ 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";
const LoginUsername = memo( export type LoginUsernameProps = KcProps & {
({ kcContext: KcContextBase.LoginUsername;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.LoginUsername; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const LoginUsername = memo((props: LoginUsernameProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { social, realm, url, usernameHidden, login, registrationDisabled } = kcContext; const { social, realm, url, usernameHidden, login, registrationDisabled } = kcContext;
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
@ -38,21 +42,21 @@ const LoginUsername = memo(
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
displayInfo={social.displayInfo} displayInfo={social.displayInfo}
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 && props.kcContentWrapperClass)}> <div id="kc-form" className={cx(realm.password && social.providers !== undefined && kcProps.kcContentWrapperClass)}>
<div <div
id="kc-form-wrapper" id="kc-form-wrapper"
className={cx( className={cx(
realm.password && social.providers && [props.kcFormSocialAccountContentClass, props.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(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
{!usernameHidden && {!usernameHidden &&
(() => { (() => {
const label = !realm.loginWithEmailAllowed const label = !realm.loginWithEmailAllowed
@ -65,13 +69,13 @@ const LoginUsername = memo(
return ( return (
<> <>
<label htmlFor={autoCompleteHelper} className={cx(props.kcLabelClass)}> <label htmlFor={autoCompleteHelper} className={cx(kcProps.kcLabelClass)}>
{msg(label)} {msg(label)}
</label> </label>
<input <input
tabIndex={1} tabIndex={1}
id={autoCompleteHelper} id={autoCompleteHelper}
className={cx(props.kcInputClass)} className={cx(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.
@ -85,7 +89,7 @@ const LoginUsername = memo(
); );
})()} })()}
</div> </div>
<div className={cx(props.kcFormGroupClass, props.kcFormSettingClass)}> <div className={cx(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">
@ -107,14 +111,14 @@ const LoginUsername = memo(
)} )}
</div> </div>
</div> </div>
<div id="kc-form-buttons" className={cx(props.kcFormGroupClass)}> <div id="kc-form-buttons" className={cx(kcProps.kcFormGroupClass)}>
<input <input
tabIndex={4} tabIndex={4}
className={cx( className={cx(
props.kcButtonClass, kcProps.kcButtonClass,
props.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
props.kcButtonBlockClass, kcProps.kcButtonBlockClass,
props.kcButtonLargeClass kcProps.kcButtonLargeClass
)} )}
name="login" name="login"
id="kc-login" id="kc-login"
@ -127,15 +131,15 @@ const LoginUsername = memo(
)} )}
</div> </div>
{realm.password && social.providers !== undefined && ( {realm.password && social.providers !== undefined && (
<div id="kc-social-providers" className={cx(props.kcFormSocialAccountContentClass, props.kcFormSocialAccountClass)}> <div id="kc-social-providers" className={cx(kcProps.kcFormSocialAccountContentClass, kcProps.kcFormSocialAccountClass)}>
<ul <ul
className={cx( className={cx(
props.kcFormSocialAccountListClass, kcProps.kcFormSocialAccountListClass,
social.providers.length > 4 && props.kcFormSocialAccountDoubleListClass social.providers.length > 4 && kcProps.kcFormSocialAccountDoubleListClass
)} )}
> >
{social.providers.map(p => ( {social.providers.map(p => (
<li key={p.providerId} className={cx(props.kcFormSocialAccountListLinkClass)}> <li key={p.providerId} className={cx(kcProps.kcFormSocialAccountListLinkClass)}>
<a href={p.loginUrl} id={`zocial-${p.alias}`} className={cx("zocial", p.providerId)}> <a href={p.loginUrl} id={`zocial-${p.alias}`} className={cx("zocial", p.providerId)}>
<span>{p.displayName}</span> <span>{p.displayName}</span>
</a> </a>
@ -162,7 +166,6 @@ const LoginUsername = memo(
} }
/> />
); );
} });
);
export default LoginUsername; export default LoginUsername;

View File

@ -1,23 +1,27 @@
import React, { memo } from "react"; import React, { memo } from "react";
import Template from "./Template"; import DefaultTemplate 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 type { I18n } from "../i18n"; import type { I18n } from "../i18n";
const LoginVerifyEmail = memo( export type LoginVerifyEmailProps = KcProps & {
({ kcContext: KcContextBase.LoginVerifyEmail;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.LoginVerifyEmail; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const LoginVerifyEmail = memo((props: LoginVerifyEmailProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { msg } = i18n; const { msg } = i18n;
const { url, user } = kcContext; const { url, user } = kcContext;
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
displayMessage={false} displayMessage={false}
headerNode={msg("emailVerifyTitle")} headerNode={msg("emailVerifyTitle")}
formNode={ formNode={
@ -34,7 +38,6 @@ const LoginVerifyEmail = memo(
} }
/> />
); );
} });
);
export default LoginVerifyEmail; export default LoginVerifyEmail;

View File

@ -1,17 +1,21 @@
import React, { memo } from "react"; import React, { memo } from "react";
import { useCssAndCx } from "../tools/useCssAndCx"; import { useCssAndCx } from "../tools/useCssAndCx";
import Template from "./Template"; import DefaultTemplate 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 type { I18n } from "../i18n"; import type { I18n } from "../i18n";
const LogoutConfirm = memo( export type LogoutConfirmProps = KcProps & {
({ kcContext: KcContextBase.LogoutConfirm;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.LogoutConfirm; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const LogoutConfirm = memo((props: LogoutConfirmProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { url, client, logoutConfirm } = kcContext; const { url, client, logoutConfirm } = kcContext;
const { cx } = useCssAndCx(); const { cx } = useCssAndCx();
@ -20,7 +24,7 @@ const LogoutConfirm = memo(
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
displayMessage={false} displayMessage={false}
headerNode={msg("logoutConfirmTitle")} headerNode={msg("logoutConfirmTitle")}
formNode={ formNode={
@ -29,18 +33,18 @@ const LogoutConfirm = memo(
<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(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
<div id="kc-form-options"> <div id="kc-form-options">
<div className={cx(props.kcFormOptionsWrapperClass)}></div> <div className={cx(kcProps.kcFormOptionsWrapperClass)}></div>
</div> </div>
<div id="kc-form-buttons" className={cx(props.kcFormGroupClass)}> <div id="kc-form-buttons" className={cx(kcProps.kcFormGroupClass)}>
<input <input
tabIndex={4} tabIndex={4}
className={cx( className={cx(
props.kcButtonClass, kcProps.kcButtonClass,
props.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
props.kcButtonBlockClass, kcProps.kcButtonBlockClass,
props.kcButtonLargeClass kcProps.kcButtonLargeClass
)} )}
name="confirmLogout" name="confirmLogout"
id="kc-logout" id="kc-logout"
@ -62,7 +66,6 @@ const LogoutConfirm = memo(
} }
/> />
); );
} });
);
export default LogoutConfirm; export default LogoutConfirm;

View File

@ -1,17 +1,21 @@
import React, { memo } from "react"; import React, { memo } from "react";
import Template from "./Template"; import DefaultTemplate 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 { useCssAndCx } from "../tools/useCssAndCx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
const Register = memo( export type RegisterProps = KcProps & {
({ kcContext: KcContextBase.Register;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.Register; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const Register = memo((props: RegisterProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { url, messagesPerField, register, realm, passwordRequired, recaptchaRequired, recaptchaSiteKey } = kcContext; const { url, messagesPerField, register, realm, passwordRequired, recaptchaRequired, recaptchaSiteKey } = kcContext;
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
@ -20,55 +24,55 @@ const Register = memo(
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
headerNode={msg("registerTitle")} headerNode={msg("registerTitle")}
formNode={ formNode={
<form id="kc-register-form" className={cx(props.kcFormClass)} action={url.registrationAction} method="post"> <form id="kc-register-form" className={cx(kcProps.kcFormClass)} action={url.registrationAction} method="post">
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("firstName", props.kcFormGroupErrorClass))}> <div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("firstName", kcProps.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}> <div className={cx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="firstName" className={cx(props.kcLabelClass)}> <label htmlFor="firstName" className={cx(kcProps.kcLabelClass)}>
{msg("firstName")} {msg("firstName")}
</label> </label>
</div> </div>
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="firstName" id="firstName"
className={cx(props.kcInputClass)} className={cx(kcProps.kcInputClass)}
name="firstName" name="firstName"
defaultValue={register.formData.firstName ?? ""} defaultValue={register.formData.firstName ?? ""}
/> />
</div> </div>
</div> </div>
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("lastName", props.kcFormGroupErrorClass))}> <div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("lastName", kcProps.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}> <div className={cx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="lastName" className={cx(props.kcLabelClass)}> <label htmlFor="lastName" className={cx(kcProps.kcLabelClass)}>
{msg("lastName")} {msg("lastName")}
</label> </label>
</div> </div>
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="lastName" id="lastName"
className={cx(props.kcInputClass)} className={cx(kcProps.kcInputClass)}
name="lastName" name="lastName"
defaultValue={register.formData.lastName ?? ""} defaultValue={register.formData.lastName ?? ""}
/> />
</div> </div>
</div> </div>
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("email", props.kcFormGroupErrorClass))}> <div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("email", kcProps.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}> <div className={cx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="email" className={cx(props.kcLabelClass)}> <label htmlFor="email" className={cx(kcProps.kcLabelClass)}>
{msg("email")} {msg("email")}
</label> </label>
</div> </div>
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="email" id="email"
className={cx(props.kcInputClass)} className={cx(kcProps.kcInputClass)}
name="email" name="email"
defaultValue={register.formData.email ?? ""} defaultValue={register.formData.email ?? ""}
autoComplete="email" autoComplete="email"
@ -76,17 +80,17 @@ const Register = memo(
</div> </div>
</div> </div>
{!realm.registrationEmailAsUsername && ( {!realm.registrationEmailAsUsername && (
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("username", props.kcFormGroupErrorClass))}> <div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("username", kcProps.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}> <div className={cx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="username" className={cx(props.kcLabelClass)}> <label htmlFor="username" className={cx(kcProps.kcLabelClass)}>
{msg("username")} {msg("username")}
</label> </label>
</div> </div>
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(kcProps.kcInputWrapperClass)}>
<input <input
type="text" type="text"
id="username" id="username"
className={cx(props.kcInputClass)} className={cx(kcProps.kcInputClass)}
name="username" name="username"
defaultValue={register.formData.username ?? ""} defaultValue={register.formData.username ?? ""}
autoComplete="username" autoComplete="username"
@ -96,17 +100,17 @@ const Register = memo(
)} )}
{passwordRequired && ( {passwordRequired && (
<> <>
<div className={cx(props.kcFormGroupClass, messagesPerField.printIfExists("password", props.kcFormGroupErrorClass))}> <div className={cx(kcProps.kcFormGroupClass, messagesPerField.printIfExists("password", kcProps.kcFormGroupErrorClass))}>
<div className={cx(props.kcLabelWrapperClass)}> <div className={cx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="password" className={cx(props.kcLabelClass)}> <label htmlFor="password" className={cx(kcProps.kcLabelClass)}>
{msg("password")} {msg("password")}
</label> </label>
</div> </div>
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(kcProps.kcInputWrapperClass)}>
<input <input
type="password" type="password"
id="password" id="password"
className={cx(props.kcInputClass)} className={cx(kcProps.kcInputClass)}
name="password" name="password"
autoComplete="new-password" autoComplete="new-password"
/> />
@ -115,44 +119,44 @@ const Register = memo(
<div <div
className={cx( className={cx(
props.kcFormGroupClass, kcProps.kcFormGroupClass,
messagesPerField.printIfExists("password-confirm", props.kcFormGroupErrorClass) messagesPerField.printIfExists("password-confirm", kcProps.kcFormGroupErrorClass)
)} )}
> >
<div className={cx(props.kcLabelWrapperClass)}> <div className={cx(kcProps.kcLabelWrapperClass)}>
<label htmlFor="password-confirm" className={cx(props.kcLabelClass)}> <label htmlFor="password-confirm" className={cx(kcProps.kcLabelClass)}>
{msg("passwordConfirm")} {msg("passwordConfirm")}
</label> </label>
</div> </div>
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(kcProps.kcInputWrapperClass)}>
<input type="password" id="password-confirm" className={cx(props.kcInputClass)} name="password-confirm" /> <input type="password" id="password-confirm" className={cx(kcProps.kcInputClass)} name="password-confirm" />
</div> </div>
</div> </div>
</> </>
)} )}
{recaptchaRequired && ( {recaptchaRequired && (
<div className="form-group"> <div className="form-group">
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(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(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}> <div id="kc-form-options" className={cx(kcProps.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)}> <div className={cx(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(props.kcFormButtonsClass)}> <div id="kc-form-buttons" className={cx(kcProps.kcFormButtonsClass)}>
<input <input
className={cx( className={cx(
props.kcButtonClass, kcProps.kcButtonClass,
props.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
props.kcButtonBlockClass, kcProps.kcButtonBlockClass,
props.kcButtonLargeClass kcProps.kcButtonLargeClass
)} )}
type="submit" type="submit"
value={msgStr("doRegister")} value={msgStr("doRegister")}
@ -163,7 +167,6 @@ const Register = memo(
} }
/> />
); );
} });
);
export default Register; export default Register;

View File

@ -1,28 +1,32 @@
import React, { useMemo, memo, useState } from "react"; import React, { useMemo, memo, useState } from "react";
import Template from "./Template"; import DefaultTemplate 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 { useCssAndCx } from "../tools/useCssAndCx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
import { UserProfileFormFields } from "./shared/UserProfileCommons"; import { UserProfileFormFields } from "./shared/UserProfileCommons";
const RegisterUserProfile = memo( export type RegisterUserProfileProps = KcProps & {
({ kcContext: KcContextBase.RegisterUserProfile;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props_ };
}: { kcContext: KcContextBase.RegisterUserProfile; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const RegisterUserProfile = memo((props: RegisterUserProfileProps) => {
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 { cx, css } = useCssAndCx();
const props = useMemo( const kcProps = useMemo(
() => ({ () => ({
...props_, ...kcProps_,
"kcFormGroupClass": cx(props_.kcFormGroupClass, css({ "marginBottom": 20 })) "kcFormGroupClass": cx(kcProps_.kcFormGroupClass, css({ "marginBottom": 20 }))
}), }),
[cx, css] [cx, css]
); );
@ -31,36 +35,36 @@ const RegisterUserProfile = memo(
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
displayMessage={messagesPerField.exists("global")} displayMessage={messagesPerField.exists("global")}
displayRequiredFields={true} displayRequiredFields={true}
headerNode={msg("registerTitle")} headerNode={msg("registerTitle")}
formNode={ formNode={
<form id="kc-register-form" className={cx(props.kcFormClass)} action={url.registrationAction} method="post"> <form id="kc-register-form" className={cx(kcProps.kcFormClass)} action={url.registrationAction} method="post">
<UserProfileFormFields kcContext={kcContext} onIsFormSubmittableValueChange={setIsFomSubmittable} i18n={i18n} {...props} /> <UserProfileFormFields kcContext={kcContext} onIsFormSubmittableValueChange={setIsFomSubmittable} i18n={i18n} {...kcProps} />
{recaptchaRequired && ( {recaptchaRequired && (
<div className="form-group"> <div className="form-group">
<div className={cx(props.kcInputWrapperClass)}> <div className={cx(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(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}> <div id="kc-form-options" className={cx(kcProps.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)}> <div className={cx(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(props.kcFormButtonsClass)}> <div id="kc-form-buttons" className={cx(kcProps.kcFormButtonsClass)}>
<input <input
className={cx( className={cx(
props.kcButtonClass, kcProps.kcButtonClass,
props.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
props.kcButtonBlockClass, kcProps.kcButtonBlockClass,
props.kcButtonLargeClass kcProps.kcButtonLargeClass
)} )}
type="submit" type="submit"
value={msgStr("doRegister")} value={msgStr("doRegister")}
@ -72,7 +76,6 @@ const RegisterUserProfile = memo(
} }
/> />
); );
} });
);
export default RegisterUserProfile; export default RegisterUserProfile;

View File

@ -1,5 +1,6 @@
import React, { useEffect, memo } from "react"; import React, { useEffect, memo } from "react";
import Template from "./Template"; import DefaultTemplate 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 { useCssAndCx } from "../tools/useCssAndCx";
@ -12,6 +13,7 @@ import memoize from "memoizee";
import { useConst } from "powerhooks/useConst"; import { useConst } from "powerhooks/useConst";
import { useConstCallback } from "powerhooks/useConstCallback"; import { useConstCallback } from "powerhooks/useConstCallback";
import { Markdown } from "../tools/Markdown"; import { Markdown } from "../tools/Markdown";
import type { Extends } from "tsafe";
export const evtTermMarkdown = Evt.create<string | undefined>(undefined); export const evtTermMarkdown = Evt.create<string | undefined>(undefined);
@ -22,7 +24,7 @@ export type KcContextLike = {
}; };
}; };
assert<KcContextBase extends KcContextLike ? true : false>(); assert<Extends<KcContextBase, KcContextLike>>();
/** Allow to avoid bundling the terms and download it on demand*/ /** Allow to avoid bundling the terms and download it on demand*/
export function useDownloadTerms(params: { export function useDownloadTerms(params: {
@ -54,13 +56,16 @@ export function useDownloadTerms(params: {
}, []); }, []);
} }
const Terms = memo( export type TermsProps = KcProps & {
({ kcContext: KcContextBase.Terms;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.Terms; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const Terms = memo((props: TermsProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
useRerenderOnStateChange(evtTermMarkdown); useRerenderOnStateChange(evtTermMarkdown);
@ -75,7 +80,7 @@ const Terms = memo(
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
displayMessage={false} displayMessage={false}
headerNode={msg("termsTitle")} headerNode={msg("termsTitle")}
formNode={ formNode={
@ -84,11 +89,11 @@ const Terms = memo(
<form className="form-actions" action={url.loginAction} method="POST"> <form className="form-actions" action={url.loginAction} method="POST">
<input <input
className={cx( className={cx(
props.kcButtonClass, kcProps.kcButtonClass,
props.kcButtonClass, kcProps.kcButtonClass,
props.kcButtonClass, kcProps.kcButtonClass,
props.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
props.kcButtonLargeClass kcProps.kcButtonLargeClass
)} )}
name="accept" name="accept"
id="kc-accept" id="kc-accept"
@ -96,7 +101,7 @@ const Terms = memo(
value={msgStr("doAccept")} value={msgStr("doAccept")}
/> />
<input <input
className={cx(props.kcButtonClass, props.kcButtonDefaultClass, props.kcButtonLargeClass)} className={cx(kcProps.kcButtonClass, kcProps.kcButtonDefaultClass, kcProps.kcButtonLargeClass)}
name="cancel" name="cancel"
id="kc-decline" id="kc-decline"
type="submit" type="submit"
@ -108,7 +113,6 @@ const Terms = memo(
} }
/> />
); );
} });
);
export default Terms; export default Terms;

View File

@ -1,18 +1,22 @@
import React, { useState, memo } from "react"; import React, { useState, memo } from "react";
import Template from "./Template"; import DefaultTemplate 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 { useCssAndCx } from "../tools/useCssAndCx";
import type { I18n } from "../i18n"; import type { I18n } from "../i18n";
import { UserProfileFormFields } from "./shared/UserProfileCommons"; import { UserProfileFormFields } from "./shared/UserProfileCommons";
const UpdateUserProfile = memo( export type UpdateUserProfileProps = KcProps & {
({ kcContext: KcContextBase.UpdateUserProfile;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.UpdateUserProfile; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const UpdateUserProfile = memo((props: UpdateUserProfileProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { cx } = useCssAndCx(); const { cx } = useCssAndCx();
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
@ -23,27 +27,27 @@ const UpdateUserProfile = memo(
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
headerNode={msg("loginProfileTitle")} headerNode={msg("loginProfileTitle")}
formNode={ formNode={
<form id="kc-update-profile-form" className={cx(props.kcFormClass)} action={url.loginAction} method="post"> <form id="kc-update-profile-form" className={cx(kcProps.kcFormClass)} action={url.loginAction} method="post">
<UserProfileFormFields kcContext={kcContext} onIsFormSubmittableValueChange={setIsFomSubmittable} i18n={i18n} {...props} /> <UserProfileFormFields kcContext={kcContext} onIsFormSubmittableValueChange={setIsFomSubmittable} i18n={i18n} {...kcProps} />
<div className={cx(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
<div id="kc-form-options" className={cx(props.kcFormOptionsClass)}> <div id="kc-form-options" className={cx(kcProps.kcFormOptionsClass)}>
<div className={cx(props.kcFormOptionsWrapperClass)}></div> <div className={cx(kcProps.kcFormOptionsWrapperClass)}></div>
</div> </div>
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}> <div id="kc-form-buttons" className={cx(kcProps.kcFormButtonsClass)}>
{isAppInitiatedAction ? ( {isAppInitiatedAction ? (
<> <>
<input <input
className={cx(props.kcButtonClass, props.kcButtonPrimaryClass, props.kcButtonLargeClass)} className={cx(kcProps.kcButtonClass, kcProps.kcButtonPrimaryClass, kcProps.kcButtonLargeClass)}
type="submit" type="submit"
value={msgStr("doSubmit")} value={msgStr("doSubmit")}
/> />
<button <button
className={cx(props.kcButtonClass, props.kcButtonDefaultClass, props.kcButtonLargeClass)} className={cx(kcProps.kcButtonClass, kcProps.kcButtonDefaultClass, kcProps.kcButtonLargeClass)}
type="submit" type="submit"
name="cancel-aia" name="cancel-aia"
value="true" value="true"
@ -55,10 +59,10 @@ const UpdateUserProfile = memo(
) : ( ) : (
<input <input
className={cx( className={cx(
props.kcButtonClass, kcProps.kcButtonClass,
props.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
props.kcButtonBlockClass, kcProps.kcButtonBlockClass,
props.kcButtonLargeClass kcProps.kcButtonLargeClass
)} )}
type="submit" type="submit"
defaultValue={msgStr("doSubmit")} defaultValue={msgStr("doSubmit")}
@ -71,7 +75,6 @@ const UpdateUserProfile = memo(
} }
/> />
); );
} });
);
export default UpdateUserProfile; export default UpdateUserProfile;

View File

@ -1,5 +1,6 @@
import React, { useRef, useState, memo } from "react"; import React, { useRef, useState, memo } from "react";
import Template from "./Template"; import DefaultTemplate 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 { useCssAndCx } from "../tools/useCssAndCx";
@ -7,13 +8,16 @@ import type { I18n, MessageKeyBase } from "../i18n";
import { base64url } from "rfc4648"; import { base64url } from "rfc4648";
import { useConstCallback } from "powerhooks/useConstCallback"; import { useConstCallback } from "powerhooks/useConstCallback";
const WebauthnAuthenticate = memo( export type WebauthnAuthenticateProps = KcProps & {
({ kcContext: KcContextBase.WebauthnAuthenticate;
kcContext, i18n: I18n;
i18n, doFetchDefaultThemeResources?: boolean;
doFetchDefaultThemeResources = true, Template?: (props: TemplateProps) => JSX.Element | null;
...props };
}: { kcContext: KcContextBase.WebauthnAuthenticate; i18n: I18n; doFetchDefaultThemeResources?: boolean } & KcProps) => {
const WebauthnAuthenticate = memo((props: WebauthnAuthenticateProps) => {
const { kcContext, i18n, doFetchDefaultThemeResources = true, Template = DefaultTemplate, ...kcProps } = props;
const { url } = kcContext; const { url } = kcContext;
const { msg, msgStr } = i18n; const { msg, msgStr } = i18n;
@ -95,10 +99,10 @@ const WebauthnAuthenticate = memo(
return ( return (
<Template <Template
{...{ kcContext, i18n, doFetchDefaultThemeResources, ...props }} {...{ kcContext, i18n, doFetchDefaultThemeResources, ...kcProps }}
headerNode={msg("webauthn-login-title")} headerNode={msg("webauthn-login-title")}
formNode={ formNode={
<div id="kc-form-webauthn" className={cx(props.kcFormClass)}> <div id="kc-form-webauthn" className={cx(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} />
@ -107,10 +111,10 @@ const WebauthnAuthenticate = memo(
<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(props.kcFormGroupClass)}> <div className={cx(kcProps.kcFormGroupClass)}>
{authenticators && {authenticators &&
(() => ( (() => (
<form id="authn_select" className={cx(props.kcFormClass)}> <form id="authn_select" className={cx(kcProps.kcFormClass)}>
{authenticators.authenticators.map(authenticator => ( {authenticators.authenticators.map(authenticator => (
<input <input
type="hidden" type="hidden"
@ -126,23 +130,23 @@ const WebauthnAuthenticate = memo(
(() => ( (() => (
<> <>
{authenticators.authenticators.length > 1 && ( {authenticators.authenticators.length > 1 && (
<p className={cx(props.kcSelectAuthListItemTitle)}>{msg("webauthn-available-authenticators")}</p> <p className={cx(kcProps.kcSelectAuthListItemTitle)}>{msg("webauthn-available-authenticators")}</p>
)} )}
<div className={cx(props.kcFormClass)}> <div className={cx(kcProps.kcFormClass)}>
{authenticators.authenticators.map(authenticator => ( {authenticators.authenticators.map(authenticator => (
<div id="kc-webauthn-authenticator" className={cx(props.kcSelectAuthListItemClass)}> <div id="kc-webauthn-authenticator" className={cx(kcProps.kcSelectAuthListItemClass)}>
<div className={cx(props.kcSelectAuthListItemIconClass)}> <div className={cx(kcProps.kcSelectAuthListItemIconClass)}>
<i <i
className={cx( className={cx(
props[authenticator.transports.iconClass] ?? props.kcWebAuthnDefaultIcon, kcProps[authenticator.transports.iconClass] ?? kcProps.kcWebAuthnDefaultIcon,
props.kcSelectAuthListItemIconPropertyClass kcProps.kcSelectAuthListItemIconPropertyClass
)} )}
/> />
</div> </div>
<div className={cx(props.kcSelectAuthListItemBodyClass)}> <div className={cx(kcProps.kcSelectAuthListItemBodyClass)}>
<div <div
id="kc-webauthn-authenticator-label" id="kc-webauthn-authenticator-label"
className={cx(props.kcSelectAuthListItemHeadingClass)} className={cx(kcProps.kcSelectAuthListItemHeadingClass)}
> >
{authenticator.label} {authenticator.label}
</div> </div>
@ -150,7 +154,7 @@ const WebauthnAuthenticate = memo(
{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(props.kcSelectAuthListItemDescriptionClass)} className={cx(kcProps.kcSelectAuthListItemDescriptionClass)}
> >
{authenticator.transports.displayNameProperties.map( {authenticator.transports.displayNameProperties.map(
(transport: MessageKeyBase, index: number) => ( (transport: MessageKeyBase, index: number) => (
@ -165,20 +169,18 @@ const WebauthnAuthenticate = memo(
</div> </div>
)} )}
<div className={cx(props.kcSelectAuthListItemDescriptionClass)}> <div className={cx(kcProps.kcSelectAuthListItemDescriptionClass)}>
<span id="kc-webauthn-authenticator-created-label"> <span id="kc-webauthn-authenticator-created-label">{msg("webauthn-createdAt-label")}</span>
{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(props.kcSelectAuthListItemFillClass)} /> <div className={cx(kcProps.kcSelectAuthListItemFillClass)} />
</div> </div>
))} ))}
</div> </div>
</> </>
))()} ))()}
<div id="kc-form-buttons" className={cx(props.kcFormButtonsClass)}> <div id="kc-form-buttons" className={cx(kcProps.kcFormButtonsClass)}>
<input <input
id="authenticateWebAuthnButton" id="authenticateWebAuthnButton"
type="button" type="button"
@ -186,10 +188,10 @@ const WebauthnAuthenticate = memo(
autoFocus={true} autoFocus={true}
value={msgStr("webauthn-doAuthenticate")} value={msgStr("webauthn-doAuthenticate")}
className={cx( className={cx(
props.kcButtonClass, kcProps.kcButtonClass,
props.kcButtonPrimaryClass, kcProps.kcButtonPrimaryClass,
props.kcButtonBlockClass, kcProps.kcButtonBlockClass,
props.kcButtonLargeClass kcProps.kcButtonLargeClass
)} )}
/> />
</div> </div>
@ -198,7 +200,6 @@ const WebauthnAuthenticate = memo(
} }
/> />
); );
} });
);
export default WebauthnAuthenticate; export default WebauthnAuthenticate;