Skip to content

Commit

Permalink
feat(hanko-elements): add 'hidePasskeyButtonOnLogin' options (#865)
Browse files Browse the repository at this point in the history
* feat(hanko-elements): add 'hidePasskeyButtonOnLogin' options
* feat(hanko-elements): don't hide the passkey button, when CUI is enabled
* chore(hanko-elements): refactoring
  • Loading branch information
bjoern-m authored Jul 6, 2023
1 parent 8ff8d9b commit 43e2897
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 64 deletions.
17 changes: 9 additions & 8 deletions frontend/elements/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,15 @@ You can also pass certain options:

```javascript
const defaultOptions = {
shadow: true, // Set to false if you do not want the web component to be attached to the shadow DOM.
injectStyles: true, // Set to false if you do not want to inject any default styles.
enablePasskeys: true, // Set to false if you do not want to display passkey-related content.
translations: null, // Additional translations can be added here. English is used when the option is not
// present or set to `null`, whereas setting an empty object `{}` prevents the elements
// from displaying any translations.
translationsLocation: "/i18n", // The URL or path where the translation files are located.
fallbackLanguage: "en", // The fallback language to be used if a translation is not available.
shadow: true, // Set to false if you do not want the web component to be attached to the shadow DOM.
injectStyles: true, // Set to false if you do not want to inject any default styles.
enablePasskeys: true, // Set to false if you do not want to display passkey-related content.
hidePasskeyButtonOnLogin: false, // Hides the button to sign in with a passkey on the login page.
translations: null, // Additional translations can be added here. English is used when the option is not
// present or set to `null`, whereas setting an empty object `{}` prevents the elements
// from displaying any translations.
translationsLocation: "/i18n", // The URL or path where the translation files are located.
fallbackLanguage: "en", // The fallback language to be used if a translation is not available.
};

const {hanko} = await register("https://hanko.yourdomain.com", defaultOptions);
Expand Down
69 changes: 28 additions & 41 deletions frontend/elements/src/Elements.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { JSX, FunctionalComponent } from "preact";
import registerCustomElement from "@teamhanko/preact-custom-element";
import AppProvider from "./contexts/AppProvider";
import AppProvider, {
ComponentName,
GlobalOptions,
} from "./contexts/AppProvider";
import { Hanko } from "@teamhanko/hanko-frontend-sdk";
import { defaultTranslations, Translations } from "./i18n/translations";

Expand Down Expand Up @@ -34,6 +37,7 @@ export interface RegisterOptions {
shadow?: boolean;
injectStyles?: boolean;
enablePasskeys?: boolean;
hidePasskeyButtonOnLogin?: boolean;
translations?: Translations;
translationsLocation?: string;
fallbackLanguage?: string;
Expand All @@ -49,46 +53,27 @@ interface InternalRegisterOptions extends RegisterOptions {
observedAttributes: string[];
}

interface Global {
hanko?: Hanko;
injectStyles?: boolean;
enablePasskeys?: boolean;
translations?: Translations;
translationsLocation?: string;
fallbackLanguage?: string;
}

const global: Global = {};
const globalOptions: GlobalOptions = {};

const HankoAuth = (props: HankoAuthElementProps) => (
const createHankoComponent = (
componentName: ComponentName,
props: Record<string, any>
) => (
<AppProvider
componentName={"auth"}
componentName={componentName}
globalOptions={globalOptions}
{...props}
hanko={global.hanko}
injectStyles={global.injectStyles}
translations={global.translations}
translationsLocation={global.translationsLocation}
enablePasskeys={global.enablePasskeys}
fallbackLanguage={global.fallbackLanguage}
/>
);

const HankoProfile = (props: HankoProfileElementProps) => (
<AppProvider
componentName={"profile"}
{...props}
hanko={global.hanko}
injectStyles={global.injectStyles}
translations={global.translations}
translationsLocation={global.translationsLocation}
enablePasskeys={global.enablePasskeys}
fallbackLanguage={global.fallbackLanguage}
/>
);
const HankoAuth = (props: HankoAuthElementProps) =>
createHankoComponent("auth", props);

const HankoEvents = (props: HankoProfileElementProps) => (
<AppProvider componentName={"events"} {...props} hanko={global.hanko} />
);
const HankoProfile = (props: HankoProfileElementProps) =>
createHankoComponent("profile", props);

const HankoEvents = (props: HankoEventsElementProps) =>
createHankoComponent("events", props);

const _register = async ({
tagName,
Expand All @@ -111,18 +96,20 @@ export const register = async (
shadow: true,
injectStyles: true,
enablePasskeys: true,
hidePasskeyButtonOnLogin: false,
translations: null,
translationsLocation: "/i18n",
fallbackLanguage: "en",
...options,
};

global.hanko = new Hanko(api);
global.injectStyles = options.injectStyles;
global.enablePasskeys = options.enablePasskeys;
global.translations = options.translations || defaultTranslations;
global.translationsLocation = options.translationsLocation;
global.fallbackLanguage = options.fallbackLanguage;
globalOptions.hanko = new Hanko(api);
globalOptions.injectStyles = options.injectStyles;
globalOptions.enablePasskeys = options.enablePasskeys;
globalOptions.hidePasskeyButtonOnLogin = options.hidePasskeyButtonOnLogin;
globalOptions.translations = options.translations || defaultTranslations;
globalOptions.translationsLocation = options.translationsLocation;
globalOptions.fallbackLanguage = options.fallbackLanguage;

await Promise.all([
_register({
Expand All @@ -145,5 +132,5 @@ export const register = async (
}),
]);

return { hanko: global.hanko };
return { hanko: globalOptions.hanko };
};
35 changes: 22 additions & 13 deletions frontend/elements/src/contexts/AppProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,23 @@ import SignalLike = JSXInternal.SignalLike;

type ExperimentalFeature = "conditionalMediation";
type ExperimentalFeatures = ExperimentalFeature[];
type ComponentName = "auth" | "profile" | "events";
export type ComponentName = "auth" | "profile" | "events";

interface Props {
export interface GlobalOptions {
hanko?: Hanko;
lang?: string | SignalLike<string>;
injectStyles?: boolean;
enablePasskeys?: boolean;
hidePasskeyButtonOnLogin?: boolean;
translations?: Translations;
translationsLocation?: string;
fallbackLanguage?: string;
injectStyles?: boolean;
}

interface Props {
lang?: string | SignalLike<string>;
experimental?: string;
enablePasskeys?: boolean;
componentName: ComponentName;
globalOptions: GlobalOptions;
children?: ComponentChildren;
}

Expand Down Expand Up @@ -70,23 +75,26 @@ interface Context extends States {
emitSuccessEvent: (userID: string) => void;
enablePasskeys: boolean;
lang: string;
hidePasskeyButtonOnLogin: boolean;
}

export const AppContext = createContext<Context>(null);

const AppProvider = ({
hanko,
lang,
componentName,
experimental = "",
injectStyles = false,
enablePasskeys = true,
translations,
translationsLocation = "/i18n",
fallbackLanguage = "en",
globalOptions,
}: Props) => {
const {
hanko,
injectStyles,
enablePasskeys,
hidePasskeyButtonOnLogin,
translations,
translationsLocation,
fallbackLanguage,
} = globalOptions;
const ref = useRef<HTMLElement>(null);

const experimentalFeatures = useMemo(
() =>
experimental
Expand Down Expand Up @@ -180,6 +188,7 @@ const AppProvider = ({
experimentalFeatures,
emitSuccessEvent,
enablePasskeys,
hidePasskeyButtonOnLogin,
config,
setConfig,
userInfo,
Expand Down
5 changes: 3 additions & 2 deletions frontend/elements/src/pages/LoginEmailPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ const LoginEmailPage = (props: Props) => {
experimentalFeatures,
emitSuccessEvent,
enablePasskeys,
hidePasskeyButtonOnLogin,
config,
setPage,
setPasscode,
Expand Down Expand Up @@ -407,11 +408,11 @@ const LoginEmailPage = (props: Props) => {
{t("labels.continue")}
</Button>
</Form>
{(enablePasskeys && !conditionalMediationEnabled) ||
{(enablePasskeys && !hidePasskeyButtonOnLogin) ||
config.providers?.length ? (
<Divider>{t("labels.or")}</Divider>
) : null}
{enablePasskeys && !conditionalMediationEnabled ? (
{enablePasskeys && !hidePasskeyButtonOnLogin ? (
<Form onSubmit={onPasskeySubmit}>
<Button
secondary
Expand Down

0 comments on commit 43e2897

Please sign in to comment.