diff --git a/CHANGELOG.md b/CHANGELOG.md index c2e5dd2ee..3712dbb0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,25 @@ To use this you'll need compatible versions: - Refactored/renamed some styling options (`resetPasswordHeaderTitle` -> `headerTitle withBackButton`) - Added a `useShadowDom` prop to the `AccessDeniedScreen` - Added an `error` prop to the `AccessDeniedScreen` that can be used to describe the reason access is denied. +- Added new MFA related components to Passwordless + - Added new prop `mfaFeature` to recipe config + - `disableDefaultUI`: can be used to disable paths: `${websiteBasePath}/mfa/otp-phone`, `${websiteBasePath}/mfa/otp-email` + - `style`: is applied on top of normal sign in/up styles on the MFA paths + - New embeddable components: + - `MfaOtpPhone` (by default handling path `${websiteBasePath}/mfa/otp-phone`) + - `MfaOtpEmail` (by default handling path `${websiteBasePath}/mfa/otp-email`) + - New overrideable components: + - `PasswordlessMFAHeader_Override` + - `PasswordlessMFAFooter_Override` + - `PasswordlessMFAOTPHeader_Override` + - `PasswordlessMFAOTPFooter_Override` + - Please note, that during MFA we re-use the existing overrideable comps for the form section: + - `PasswordlessEmailForm_Override` + - `PasswordlessPhoneForm_Override` + - `PasswordlessEmailOrPhoneForm_Override` +- Removed an `ErrorBoundary` wrapping all our feature components to make sure all errors are properly catchable by the app +- Added a `footer` prop to `EmailOrPhoneForm`, `EmailForm` and `PhoneForm` which is used to override the default sign in/up footers in case the component is for MFA +- The passwordless and thirdpartypasswordless sign in/up screens now respect the first configuration (defined in the `MultiFactorAuth` recipe or in the tenant information) when selecting the available contact methods. - Fixed a font loading issue, that caused apps using the default (Rubik) font to appear with the incorrect font weights - Some default styling has changed related to how fonts/font-weights are applied diff --git a/examples/for-tests-react-16/src/App.js b/examples/for-tests-react-16/src/App.js index 63b2e0aad..ef83fa06d 100644 --- a/examples/for-tests-react-16/src/App.js +++ b/examples/for-tests-react-16/src/App.js @@ -767,6 +767,10 @@ function getThirdPartyPasswordlessConfigs({ staticProviderList, disableDefaultUI disableDefaultUI, style: theme.style, }, + mfaFeature: { + disableDefaultUI, + style: theme, + }, }); } @@ -845,6 +849,10 @@ function getPasswordlessConfigs({ disableDefaultUI }) { disableDefaultUI, style: theme.style, }, + mfaFeature: { + disableDefaultUI, + style: theme, + }, }); } diff --git a/examples/for-tests/src/App.js b/examples/for-tests/src/App.js index 838091694..29611c0c3 100644 --- a/examples/for-tests/src/App.js +++ b/examples/for-tests/src/App.js @@ -991,6 +991,10 @@ function getThirdPartyPasswordlessConfigs({ staticProviderList, disableDefaultUI disableDefaultUI, style: theme, }, + mfaFeature: { + disableDefaultUI, + style: theme, + }, }); } @@ -1078,6 +1082,10 @@ function getPasswordlessConfigs({ disableDefaultUI }) { disableDefaultUI, style: theme, }, + mfaFeature: { + disableDefaultUI, + style: theme, + }, }); } diff --git a/lib/build/components/assets/otpEmailIcon.d.ts b/lib/build/components/assets/otpEmailIcon.d.ts new file mode 100644 index 000000000..1de53f103 --- /dev/null +++ b/lib/build/components/assets/otpEmailIcon.d.ts @@ -0,0 +1,2 @@ +/// +export declare const OTPEmailIcon: () => JSX.Element; diff --git a/lib/build/components/assets/otpSMSIcon.d.ts b/lib/build/components/assets/otpSMSIcon.d.ts new file mode 100644 index 000000000..5e409d35a --- /dev/null +++ b/lib/build/components/assets/otpSMSIcon.d.ts @@ -0,0 +1,2 @@ +/// +export declare const OTPSMSIcon: () => JSX.Element; diff --git a/lib/build/components/errorBoundary.d.ts b/lib/build/components/errorBoundary.d.ts deleted file mode 100644 index 2b672d624..000000000 --- a/lib/build/components/errorBoundary.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -import React from "react"; -import type { ErrorInfo, ReactNode } from "react"; -declare type ErrorBoundaryState = { - hasError: boolean; -}; -export default class ErrorBoundary extends React.Component { - constructor(props: { hasError: boolean }); - static getDerivedStateFromError(): ErrorBoundaryState; - componentDidCatch(error: Error, errorInfo: ErrorInfo): void; - render(): JSX.Element | ReactNode | undefined; -} -export {}; diff --git a/lib/build/emailverification-shared2.js b/lib/build/emailverification-shared2.js index 74b25374b..ec7512b09 100644 --- a/lib/build/emailverification-shared2.js +++ b/lib/build/emailverification-shared2.js @@ -6,7 +6,7 @@ var genericComponentOverrideContext = require("./genericComponentOverrideContext var translations = require("./translations.js"); var styles = - '/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 255, 155, 51;\n --palette-primaryBorder: 238, 141, 35;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 34, 34, 34;\n --palette-textLabel: 34, 34, 34;\n --palette-textInput: 34, 34, 34;\n --palette-textPrimary: 101, 101, 101;\n --palette-textLink: 0, 118, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 128, 128, 128;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n}\n\n/*\n * Default styles.\n */\n\n@-webkit-keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n\n@keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n\n@-webkit-keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n\n@keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n\n[data-supertokens~="container"] {\n font-family: "Rubik", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 0 auto;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 15px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 40px;\n letter-spacing: 0.58px;\n font-weight: 600;\n margin-bottom: 2px;\n color: rgb(var(--palette-textTitle));\n}\n\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n margin-bottom: 21px;\n}\n\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n\n/* TODO: split the link style into separate things*/\n\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-1);\n font-weight: 500;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 300;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="divider"] {\n margin-top: 1em;\n margin-bottom: 1em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n}\n\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n\n[data-supertokens~="linkButton"] {\n font-family: "Rubik", sans-serif;\n background-color: transparent;\n border: 0;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n\n[data-supertokens~="button"] {\n font-family: "Rubik", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 700;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n -webkit-filter: brightness(0.85);\n filter: brightness(0.85);\n}\n\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n\n[data-supertokens~="inputContainer"] {\n margin-top: 6px;\n}\n\n[data-supertokens~="inputWrapper"] {\n box-sizing: border-box;\n width: 100%;\n display: flex;\n align-items: center;\n background-color: rgb(var(--palette-inputBackground));\n height: 34px;\n border-radius: 6px;\n border: 1px solid rgb(var(--palette-inputBorder));\n}\n\n[data-supertokens~="inputWrapper"][focus-within] {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputWrapper"]:focus-within {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"][focus-within] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"]:focus-within {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="input"] {\n box-sizing: border-box;\n padding-left: 15px;\n -webkit-filter: none;\n filter: none;\n color: rgb(var(--palette-textInput));\n background-color: transparent;\n border-radius: 6px;\n font-size: var(--font-size-1);\n border: none;\n padding-right: 25px;\n letter-spacing: 1.2px;\n flex: 9 1 75%;\n width: 75%;\n height: 32px;\n}\n\n[data-supertokens~="input"]:focus {\n border: none;\n outline: none;\n}\n\n[data-supertokens~="input"]:-webkit-autofill,\n[data-supertokens~="input"]:-webkit-autofill:hover,\n[data-supertokens~="input"]:-webkit-autofill:focus,\n[data-supertokens~="input"]:-webkit-autofill:active {\n -webkit-text-fill-color: rgb(var(--palette-textInput));\n box-shadow: 0 0 0 30px rgb(var(--palette-inputBackground)) inset;\n}\n\n[data-supertokens~="inputAdornment"] {\n justify-content: center;\n margin-right: 5px;\n}\n\n[data-supertokens~="showPassword"] {\n cursor: pointer;\n}\n\n[data-supertokens~="forgotPasswordLink"] {\n margin-top: 10px;\n}\n\n[data-supertokens~="enterEmailSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n word-break: break-word;\n}\n\n[data-supertokens~="submitNewPasswordSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n\n[data-supertokens~="inputErrorMessage"] {\n padding-top: 5px;\n padding-bottom: 5px;\n color: rgb(var(--palette-error));\n line-height: 24px;\n font-weight: 400;\n font-size: var(--font-size-1);\n text-align: left;\n -webkit-animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n max-width: 330px;\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="inputErrorMessage"] {\n max-width: 250px;\n }\n}\n\n[data-supertokens~="inputErrorSymbol"] {\n margin-right: 5px;\n top: 1px;\n position: relative;\n left: 2px;\n}\n\n[data-supertokens~="label"] {\n text-align: left;\n font-weight: 600;\n font-size: var(--font-size-1);\n line-height: 24px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="formRow"] {\n display: flex;\n flex-direction: column;\n padding-top: 0px;\n padding-bottom: 34px;\n}\n\n[data-supertokens~="formRow"][data-supertokens~="hasError"] {\n padding-bottom: 0;\n}\n\n[data-supertokens~="sendVerifyEmailIcon"] {\n margin-top: 11px;\n}\n\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n\n[data-supertokens~="sendVerifyEmailText"] {\n line-height: 21px;\n font-size: var(--font-size-1);\n text-align: center;\n font-weight: 300;\n letter-spacing: 0.8px;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n\n[data-supertokens~="sendVerifyEmailResend"] {\n margin-top: 13px;\n font-weight: 300;\n}\n\n[data-supertokens~="sendVerifyEmailResend"]:hover {\n text-decoration: underline;\n}\n\n[data-supertokens~="noFormRow"] {\n padding-bottom: 25px;\n}\n\n[data-supertokens~="emailVerificationButtonWrapper"] {\n padding-top: 25px;\n max-width: 96px;\n margin: 0 auto;\n}\n\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n\n[data-supertokens~="resendEmailLink"] {\n display: inline-block;\n}\n'; + '/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 255, 155, 51;\n --palette-primaryBorder: 238, 141, 35;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 34, 34, 34;\n --palette-textLabel: 34, 34, 34;\n --palette-textInput: 34, 34, 34;\n --palette-textPrimary: 101, 101, 101;\n --palette-textLink: 0, 118, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 128, 128, 128;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n}\n\n/*\n * Default styles.\n */\n\n@-webkit-keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n\n@keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n\n@-webkit-keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n\n@keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n\n[data-supertokens~="container"] {\n font-family: "Rubik", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 0 auto;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 15px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 40px;\n letter-spacing: 0.58px;\n font-weight: 600;\n margin-bottom: 2px;\n color: rgb(var(--palette-textTitle));\n}\n\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n margin-bottom: 21px;\n}\n\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n\n/* TODO: split the link style into separate things*/\n\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-1);\n font-weight: 500;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 300;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="divider"] {\n margin-top: 1em;\n margin-bottom: 1em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n}\n\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n\n[data-supertokens~="linkButton"] {\n font-family: "Rubik", sans-serif;\n background-color: transparent;\n border: 0;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n\n[data-supertokens~="button"] {\n font-family: "Rubik", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 700;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n -webkit-filter: brightness(0.85);\n filter: brightness(0.85);\n}\n\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n\n[data-supertokens~="delayedRender"] {\n -webkit-animation-duration: 0.1s;\n animation-duration: 0.1s;\n -webkit-animation-name: animate-fade;\n animation-name: animate-fade;\n -webkit-animation-delay: 0.2s;\n animation-delay: 0.2s;\n -webkit-animation-fill-mode: backwards;\n animation-fill-mode: backwards;\n}\n\n@-webkit-keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n\n[data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n\n[data-supertokens~="inputContainer"] {\n margin-top: 6px;\n}\n\n[data-supertokens~="inputWrapper"] {\n box-sizing: border-box;\n width: 100%;\n display: flex;\n align-items: center;\n background-color: rgb(var(--palette-inputBackground));\n height: 34px;\n border-radius: 6px;\n border: 1px solid rgb(var(--palette-inputBorder));\n}\n\n[data-supertokens~="inputWrapper"][focus-within] {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputWrapper"]:focus-within {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"][focus-within] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"]:focus-within {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="input"] {\n box-sizing: border-box;\n padding-left: 15px;\n -webkit-filter: none;\n filter: none;\n color: rgb(var(--palette-textInput));\n background-color: transparent;\n border-radius: 6px;\n font-size: var(--font-size-1);\n border: none;\n padding-right: 25px;\n letter-spacing: 1.2px;\n flex: 9 1 75%;\n width: 75%;\n height: 32px;\n}\n\n[data-supertokens~="input"]:focus {\n border: none;\n outline: none;\n}\n\n[data-supertokens~="input"]:-webkit-autofill,\n[data-supertokens~="input"]:-webkit-autofill:hover,\n[data-supertokens~="input"]:-webkit-autofill:focus,\n[data-supertokens~="input"]:-webkit-autofill:active {\n -webkit-text-fill-color: rgb(var(--palette-textInput));\n box-shadow: 0 0 0 30px rgb(var(--palette-inputBackground)) inset;\n}\n\n[data-supertokens~="inputAdornment"] {\n justify-content: center;\n margin-right: 5px;\n}\n\n[data-supertokens~="showPassword"] {\n cursor: pointer;\n}\n\n[data-supertokens~="forgotPasswordLink"] {\n margin-top: 10px;\n}\n\n[data-supertokens~="enterEmailSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n word-break: break-word;\n}\n\n[data-supertokens~="submitNewPasswordSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n\n[data-supertokens~="inputErrorMessage"] {\n padding-top: 5px;\n padding-bottom: 5px;\n color: rgb(var(--palette-error));\n line-height: 24px;\n font-weight: 400;\n font-size: var(--font-size-1);\n text-align: left;\n -webkit-animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n max-width: 330px;\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="inputErrorMessage"] {\n max-width: 250px;\n }\n}\n\n[data-supertokens~="inputErrorSymbol"] {\n margin-right: 5px;\n top: 1px;\n position: relative;\n left: 2px;\n}\n\n[data-supertokens~="label"] {\n text-align: left;\n font-weight: 600;\n font-size: var(--font-size-1);\n line-height: 24px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="formRow"] {\n display: flex;\n flex-direction: column;\n padding-top: 0px;\n padding-bottom: 34px;\n}\n\n[data-supertokens~="formRow"][data-supertokens~="hasError"] {\n padding-bottom: 0;\n}\n\n[data-supertokens~="sendVerifyEmailIcon"] {\n margin-top: 11px;\n}\n\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n\n[data-supertokens~="sendVerifyEmailText"] {\n line-height: 21px;\n font-size: var(--font-size-1);\n text-align: center;\n font-weight: 300;\n letter-spacing: 0.8px;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n\n[data-supertokens~="sendVerifyEmailResend"] {\n margin-top: 13px;\n font-weight: 300;\n}\n\n[data-supertokens~="sendVerifyEmailResend"]:hover {\n text-decoration: underline;\n}\n\n[data-supertokens~="noFormRow"] {\n padding-bottom: 25px;\n}\n\n[data-supertokens~="emailVerificationButtonWrapper"] {\n padding-top: 25px;\n max-width: 96px;\n margin: 0 auto;\n}\n\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="resendEmailLink"] {\n display: inline-block;\n}\n'; var ThemeBase = function (_a) { var children = _a.children, diff --git a/lib/build/index2.js b/lib/build/index2.js index 31d5e4906..cfcf81a7d 100644 --- a/lib/build/index2.js +++ b/lib/build/index2.js @@ -19,31 +19,6 @@ var NormalisedURLPath__default = /*#__PURE__*/ _interopDefault(NormalisedURLPath var ComponentOverrideContext = React__default.default.createContext("IS_DEFAULT"); -/* - * Component. - */ -var ErrorBoundary = /** @class */ (function (_super) { - genericComponentOverrideContext.__extends(ErrorBoundary, _super); - function ErrorBoundary(props) { - var _this = _super.call(this, props) || this; - _this.state = { hasError: false }; - return _this; - } - ErrorBoundary.getDerivedStateFromError = function () { - return { hasError: true }; - }; - ErrorBoundary.prototype.componentDidCatch = function (error, errorInfo) { - console.info(error, errorInfo); - }; - ErrorBoundary.prototype.render = function () { - if (this.state.hasError) { - return jsxRuntime.jsx(React.Fragment, {}); - } - return this.props.children; - }; - return ErrorBoundary; -})(React__default.default.Component); - var dynamicLoginMethodsContext = React__default.default.createContext(undefined); var useDynamicLoginMethods = function () { var value = React__default.default.useContext(dynamicLoginMethodsContext); @@ -117,31 +92,29 @@ function FeatureWrapper(_a) { genericComponentOverrideContext.__assign( { value: loadedDynamicLoginMethods }, { - children: jsxRuntime.jsx(ErrorBoundary, { - children: jsxRuntime.jsx( - translationContext.TranslationContextProvider, - genericComponentOverrideContext.__assign( - { - defaultLanguage: st.languageTranslations.defaultLanguage, - defaultStore: genericComponentOverrideContext.mergeObjects( - defaultStore, - st.languageTranslations.userTranslationStore - ), - translationControlEventSource: st.languageTranslations.translationEventSource, - userTranslationFunc: st.languageTranslations.userTranslationFunc, - }, - { - children: jsxRuntime.jsx( - WithOrWithoutShadowDom, - genericComponentOverrideContext.__assign( - { useShadowDom: useShadowDom }, - { children: children } - ) - ), - } - ) - ), - }), + children: jsxRuntime.jsx( + translationContext.TranslationContextProvider, + genericComponentOverrideContext.__assign( + { + defaultLanguage: st.languageTranslations.defaultLanguage, + defaultStore: genericComponentOverrideContext.mergeObjects( + defaultStore, + st.languageTranslations.userTranslationStore + ), + translationControlEventSource: st.languageTranslations.translationEventSource, + userTranslationFunc: st.languageTranslations.userTranslationFunc, + }, + { + children: jsxRuntime.jsx( + WithOrWithoutShadowDom, + genericComponentOverrideContext.__assign( + { useShadowDom: useShadowDom }, + { children: children } + ) + ), + } + ) + ), } ) ); @@ -303,7 +276,7 @@ var withOverride = function (overrideKey, DefaultComponent) { }; var styles = - '[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 255, 155, 51;\n --palette-primaryBorder: 238, 141, 35;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 34, 34, 34;\n --palette-textLabel: 34, 34, 34;\n --palette-textInput: 34, 34, 34;\n --palette-textPrimary: 101, 101, 101;\n --palette-textLink: 0, 118, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 128, 128, 128;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n}\n/*\n * Default styles.\n */\n@-webkit-keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@-webkit-keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Rubik", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 0 auto;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 15px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 40px;\n letter-spacing: 0.58px;\n font-weight: 600;\n margin-bottom: 2px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-1);\n font-weight: 500;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 300;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="divider"] {\n margin-top: 1em;\n margin-bottom: 1em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Rubik", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Rubik", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 700;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n -webkit-filter: brightness(0.85);\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="delayedRender"] {\n -webkit-animation-duration: 0.1s;\n animation-duration: 0.1s;\n -webkit-animation-name: animate-fade;\n animation-name: animate-fade;\n -webkit-animation-delay: 0.2s;\n animation-delay: 0.2s;\n -webkit-animation-fill-mode: backwards;\n animation-fill-mode: backwards;\n}\n@-webkit-keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n'; + '[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 255, 155, 51;\n --palette-primaryBorder: 238, 141, 35;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 34, 34, 34;\n --palette-textLabel: 34, 34, 34;\n --palette-textInput: 34, 34, 34;\n --palette-textPrimary: 101, 101, 101;\n --palette-textLink: 0, 118, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 128, 128, 128;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n}\n/*\n * Default styles.\n */\n@-webkit-keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@-webkit-keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Rubik", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 0 auto;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 15px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 40px;\n letter-spacing: 0.58px;\n font-weight: 600;\n margin-bottom: 2px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-1);\n font-weight: 500;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 300;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="divider"] {\n margin-top: 1em;\n margin-bottom: 1em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Rubik", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Rubik", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 700;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n -webkit-filter: brightness(0.85);\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n[data-supertokens~="delayedRender"] {\n -webkit-animation-duration: 0.1s;\n animation-duration: 0.1s;\n -webkit-animation-name: animate-fade;\n animation-name: animate-fade;\n -webkit-animation-delay: 0.2s;\n animation-delay: 0.2s;\n -webkit-animation-fill-mode: backwards;\n animation-fill-mode: backwards;\n}\n@-webkit-keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n[data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n[data-supertokens~="delayedRender"] {\n -webkit-animation-duration: 0.1s;\n animation-duration: 0.1s;\n -webkit-animation-name: animate-fade;\n animation-name: animate-fade;\n -webkit-animation-delay: 0.2s;\n animation-delay: 0.2s;\n -webkit-animation-fill-mode: backwards;\n animation-fill-mode: backwards;\n}\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n'; var ThemeBase = function (_a) { var children = _a.children, @@ -373,15 +346,13 @@ var DynamicLoginMethodsSpinner = function () { genericComponentOverrideContext.__assign( { value: recipeComponentOverrides }, { - children: jsxRuntime.jsx(ErrorBoundary, { - children: jsxRuntime.jsx( - WithOrWithoutShadowDom, - genericComponentOverrideContext.__assign( - { useShadowDom: recipe.config.useShadowDom }, - { children: jsxRuntime.jsx(DynamicLoginMethodsSpinnerTheme, { config: recipe.config }) } - ) - ), - }), + children: jsxRuntime.jsx( + WithOrWithoutShadowDom, + genericComponentOverrideContext.__assign( + { useShadowDom: recipe.config.useShadowDom }, + { children: jsxRuntime.jsx(DynamicLoginMethodsSpinnerTheme, { config: recipe.config }) } + ) + ), } ) ); diff --git a/lib/build/multifactorauthprebuiltui.js b/lib/build/multifactorauthprebuiltui.js index 176bf6f58..5df6c54ca 100644 --- a/lib/build/multifactorauthprebuiltui.js +++ b/lib/build/multifactorauthprebuiltui.js @@ -64,7 +64,7 @@ var NormalisedURLPath__default = /*#__PURE__*/ _interopDefault(NormalisedURLPath var React__namespace = /*#__PURE__*/ _interopNamespace(React); var styles = - '[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 255, 155, 51;\n --palette-primaryBorder: 238, 141, 35;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 34, 34, 34;\n --palette-textLabel: 34, 34, 34;\n --palette-textInput: 34, 34, 34;\n --palette-textPrimary: 101, 101, 101;\n --palette-textLink: 0, 118, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 128, 128, 128;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n}\n/*\n * Default styles.\n */\n@-webkit-keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@-webkit-keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Rubik", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 0 auto;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 15px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 40px;\n letter-spacing: 0.58px;\n font-weight: 600;\n margin-bottom: 2px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-1);\n font-weight: 500;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 300;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="divider"] {\n margin-top: 1em;\n margin-bottom: 1em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Rubik", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Rubik", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 700;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n -webkit-filter: brightness(0.85);\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="mfa"][data-supertokens~="container"] {\n padding-top: 34px;\n}\n[data-supertokens~="mfa"] [data-supertokens~="row"] {\n padding-top: 6px;\n padding-bottom: 6px;\n}\n[data-supertokens~="mfa"] [data-supertokens~="headerTitle"] {\n font-size: var(--font-size-3);\n font-weight: 600;\n line-height: 30px;\n}\n[data-supertokens~="mfa"] [data-supertokens~="factorChooserList"] {\n margin-bottom: 12px;\n}\n[data-supertokens~="factorChooserOption"] {\n display: flex;\n flex-direction: row;\n border-radius: 6px;\n border: 1px solid rgb(var(--palette-inputBorder));\n padding: 20px 16px;\n cursor: pointer;\n margin-top: 12px;\n}\n[data-supertokens~="factorChooserOption"]:hover {\n border: 1px solid rgb(var(--palette-textLink));\n}\n[data-supertokens~="factorOptionText"] {\n flex-grow: 1;\n display: flex;\n flex-direction: column;\n align-items: start;\n text-align: left;\n}\n[data-supertokens~="factorLogo"] {\n flex-grow: 0;\n min-width: 30px;\n text-align: left;\n margin-top: 6px;\n}\n[data-supertokens~="factorName"] {\n color: rgb(var(--palette-textPrimary));\n font-size: var(--font-size-1);\n font-weight: 500;\n margin: 4px;\n}\n[data-supertokens~="factorChooserOption"]:hover [data-supertokens~="factorName"] {\n color: rgb(var(--palette-textLink));\n}\n[data-supertokens~="factorDescription"] {\n color: rgb(var(--palette-textGray));\n font-size: var(--font-size-0);\n margin: 4px;\n}\n[data-supertokens~="mfa"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n margin-bottom: 26px;\n text-align: right;\n}\n'; + '[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 255, 155, 51;\n --palette-primaryBorder: 238, 141, 35;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 34, 34, 34;\n --palette-textLabel: 34, 34, 34;\n --palette-textInput: 34, 34, 34;\n --palette-textPrimary: 101, 101, 101;\n --palette-textLink: 0, 118, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 128, 128, 128;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n}\n/*\n * Default styles.\n */\n@-webkit-keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@-webkit-keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Rubik", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 0 auto;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 15px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 40px;\n letter-spacing: 0.58px;\n font-weight: 600;\n margin-bottom: 2px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-1);\n font-weight: 500;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 300;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="divider"] {\n margin-top: 1em;\n margin-bottom: 1em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Rubik", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Rubik", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 700;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n -webkit-filter: brightness(0.85);\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n[data-supertokens~="delayedRender"] {\n -webkit-animation-duration: 0.1s;\n animation-duration: 0.1s;\n -webkit-animation-name: animate-fade;\n animation-name: animate-fade;\n -webkit-animation-delay: 0.2s;\n animation-delay: 0.2s;\n -webkit-animation-fill-mode: backwards;\n animation-fill-mode: backwards;\n}\n@-webkit-keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n[data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n[data-supertokens~="mfa"][data-supertokens~="container"] {\n padding-top: 34px;\n}\n[data-supertokens~="mfa"] [data-supertokens~="row"] {\n padding-top: 6px;\n padding-bottom: 6px;\n}\n[data-supertokens~="mfa"] [data-supertokens~="headerTitle"] {\n font-size: var(--font-size-3);\n font-weight: 600;\n line-height: 30px;\n}\n[data-supertokens~="mfa"] [data-supertokens~="factorChooserList"] {\n margin-bottom: 12px;\n}\n[data-supertokens~="factorChooserOption"] {\n display: flex;\n flex-direction: row;\n border-radius: 6px;\n border: 1px solid rgb(var(--palette-inputBorder));\n padding: 20px 16px;\n cursor: pointer;\n margin-top: 12px;\n}\n[data-supertokens~="factorChooserOption"]:hover {\n border: 1px solid rgb(var(--palette-textLink));\n}\n[data-supertokens~="factorOptionText"] {\n flex-grow: 1;\n display: flex;\n flex-direction: column;\n align-items: start;\n text-align: left;\n}\n[data-supertokens~="factorLogo"] {\n flex-grow: 0;\n min-width: 30px;\n text-align: left;\n margin-top: 6px;\n}\n[data-supertokens~="factorName"] {\n color: rgb(var(--palette-textPrimary));\n font-size: var(--font-size-1);\n font-weight: 500;\n margin: 4px;\n}\n[data-supertokens~="factorChooserOption"]:hover [data-supertokens~="factorName"] {\n color: rgb(var(--palette-textLink));\n}\n[data-supertokens~="factorDescription"] {\n color: rgb(var(--palette-textGray));\n font-size: var(--font-size-0);\n margin: 4px;\n}\n[data-supertokens~="mfa"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n margin-bottom: 26px;\n text-align: right;\n}\n'; var ThemeBase = function (_a) { var children = _a.children, diff --git a/lib/build/passwordless-shared2.js b/lib/build/passwordless-shared2.js index 90bcc72d8..94a68dd00 100644 --- a/lib/build/passwordless-shared2.js +++ b/lib/build/passwordless-shared2.js @@ -2,7 +2,10 @@ var genericComponentOverrideContext = require("./genericComponentOverrideContext.js"); var PasswordlessWebJS = require("supertokens-web-js/recipe/passwordless"); +var postSuperTokensInitCallbacks = require("supertokens-web-js/utils/postSuperTokensInitCallbacks"); +var jsxRuntime = require("react/jsx-runtime"); var utils = require("./authRecipe-shared.js"); +var recipe = require("./multifactorauth-shared.js"); var windowHandler = require("supertokens-web-js/utils/windowHandler"); function _interopDefault(e) { @@ -11,6 +14,88 @@ function _interopDefault(e) { var PasswordlessWebJS__default = /*#__PURE__*/ _interopDefault(PasswordlessWebJS); +var OTPEmailIcon = function () { + return jsxRuntime.jsxs( + "svg", + genericComponentOverrideContext.__assign( + { width: "17", height: "15", viewBox: "0 0 17 15", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, + { + children: [ + jsxRuntime.jsx("path", { + id: "image 414 (Traced)", + "fill-rule": "evenodd", + "clip-rule": "evenodd", + d: "M2.01513 0.0546421C1.19571 0.195435 0.393224 0.877322 0.143564 1.64496C0.0564841 1.9127 -0.00197242 1.84636 0.659082 2.22993C0.91105 2.37612 1.64082 2.80042 2.28084 3.17276C2.92086 3.54514 3.96809 4.1544 4.60811 4.52674C5.24813 4.89905 6.37321 5.55428 7.10833 5.98278C7.84346 6.41131 8.46401 6.7689 8.48736 6.77743C8.52111 6.78982 10.4367 5.69077 12.6253 4.40341C12.7865 4.30852 13.8173 3.70613 14.9159 3.06475L16.9133 1.89856L16.903 1.78079C16.8974 1.71603 16.8178 1.51568 16.7262 1.3356C16.3776 0.650318 15.6775 0.156143 14.8905 0.039982C14.4716 -0.0218423 2.38016 -0.00809191 2.01513 0.0546421ZM6.60933e-06 6.62054C0.000739608 10.251 -0.00834948 10.1158 0.27063 10.655C0.659815 11.4073 1.39721 11.8833 2.30408 11.9675C2.77169 12.0109 14.2345 12.0108 14.7024 11.9673C15.3604 11.9062 15.8152 11.7008 16.2911 11.2498C16.5236 11.0295 16.619 10.9066 16.7395 10.6725C17.0173 10.133 17.0065 10.3025 16.996 6.65494L16.9866 3.40211L15.8322 4.07294C15.1972 4.44186 13.9767 5.15156 13.1201 5.65004C11.2459 6.74049 10.2603 7.31342 9.46206 7.77628C8.76656 8.17962 8.59368 8.23389 8.2745 8.14908C8.14446 8.11454 7.64668 7.84559 6.81451 7.36034C4.15032 5.80665 0.097862 3.44588 0.0268711 3.40617C0.0117346 3.39774 -0.00032324 4.84419 6.60933e-06 6.62054Z", + fill: "url(#paint0_linear_4445_310)", + }), + jsxRuntime.jsx("defs", { + children: jsxRuntime.jsxs( + "linearGradient", + genericComponentOverrideContext.__assign( + { + id: "paint0_linear_4445_310", + x1: "8.5", + y1: "0", + x2: "8.5", + y2: "12", + gradientUnits: "userSpaceOnUse", + }, + { + children: [ + jsxRuntime.jsx("stop", { "stop-color": "#5FACFF" }), + jsxRuntime.jsx("stop", { offset: "1", "stop-color": "#1686FF" }), + ], + } + ) + ), + }), + ], + } + ) + ); +}; + +var OTPSMSIcon = function () { + return jsxRuntime.jsxs( + "svg", + genericComponentOverrideContext.__assign( + { width: "17", height: "15", viewBox: "0 0 17 15", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, + { + children: [ + jsxRuntime.jsx("path", { + id: "image 412 (Traced)", + "fill-rule": "evenodd", + "clip-rule": "evenodd", + d: "M2.23143 0.0484105C1.11677 0.26606 0.230705 1.14148 0.0548812 2.19882C0.0207171 2.40417 -0.000319148 3.89779 3.66265e-06 6.09367C0.000595481 10.0175 0.00446909 10.0713 0.330507 10.706C0.544477 11.1223 1.03692 11.597 1.49058 11.8243C1.9253 12.042 2.4213 12.1389 3.10571 12.14L3.65718 12.1409L3.65739 13.3581C3.65755 14.4585 3.66729 14.5903 3.75859 14.733C3.88347 14.9281 4.1338 15.0332 4.37209 14.9906C4.50192 14.9674 5.03536 14.5737 6.32332 13.5507L8.09582 12.1427L11.2701 12.1409C14.8062 12.1389 14.8922 12.1322 15.5441 11.8059C15.9514 11.602 16.4058 11.1868 16.6406 10.8041C16.7198 10.6748 16.8331 10.3886 16.8923 10.1681C16.9951 9.78536 17 9.6 17 6.0949C17 3.67866 16.98 2.31864 16.9417 2.11857C16.7993 1.37604 16.1965 0.620747 15.4792 0.286303C15.2652 0.186472 14.9464 0.0801328 14.7708 0.049999C14.3886 -0.0156495 2.5671 -0.0171356 2.23143 0.0484105ZM5.24433 4.97226C5.37743 5.00736 5.55471 5.1197 5.70901 5.26668C6.20818 5.74216 6.20834 6.40218 5.70933 6.86336C5.19445 7.3393 4.53167 7.33945 4.03228 6.86382C3.54451 6.3992 3.53069 5.75907 3.99822 5.28943C4.33561 4.95053 4.75602 4.84352 5.24433 4.97226ZM8.87594 4.96544C9.55686 5.14589 9.9071 5.95945 9.57246 6.58313C9.13161 7.40469 7.91806 7.41591 7.45342 6.60271C7.32215 6.37302 7.3066 6.29861 7.32494 5.98907C7.34211 5.69977 7.37455 5.59794 7.50653 5.41904C7.804 5.01592 8.36509 4.83005 8.87594 4.96544ZM12.7023 5.05815C13.4409 5.4257 13.5612 6.36097 12.94 6.90635C12.6706 7.14291 12.3468 7.24567 12.0095 7.20164C11.0115 7.07132 10.59 5.99614 11.2623 5.29563C11.6485 4.89313 12.1909 4.80365 12.7023 5.05815Z", + fill: "url(#paint0_linear_4445_316)", + }), + jsxRuntime.jsx("defs", { + children: jsxRuntime.jsxs( + "linearGradient", + genericComponentOverrideContext.__assign( + { + id: "paint0_linear_4445_316", + x1: "8.5", + y1: "0", + x2: "8.5", + y2: "15", + gradientUnits: "userSpaceOnUse", + }, + { + children: [ + jsxRuntime.jsx("stop", { "stop-color": "#5FACFF" }), + jsxRuntime.jsx("stop", { offset: "1", "stop-color": "#1585FF" }), + ], + } + ) + ), + }), + ], + } + ) + ); +}; + var getFunctionOverrides = function (onHandleEvent) { return function (originalImp) { return genericComponentOverrideContext.__assign(genericComponentOverrideContext.__assign({}, originalImp), { @@ -390,6 +475,7 @@ function normalisePasswordlessConfig(config) { validatePhoneNumber: validatePhoneNumber, signInUpFeature: signInUpFeature, linkClickedScreenFeature: normalisePasswordlessBaseConfig(config.linkClickedScreenFeature), + mfaFeature: normalisePasswordlessBaseConfig(config.mfaFeature), contactMethod: config.contactMethod, override: override, } @@ -455,6 +541,45 @@ function normalisePasswordlessBaseConfig(config) { style: style, }); } +function getEnabledContactMethods(contactMethod, currentDynamicLoginMethods) { + var _a; + var enabledContactMethods = contactMethod === "EMAIL_OR_PHONE" ? ["EMAIL", "PHONE"] : [contactMethod]; + var firstFactors; + if (currentDynamicLoginMethods.loaded && currentDynamicLoginMethods.loginMethods.firstFactors) { + firstFactors = currentDynamicLoginMethods.loginMethods.firstFactors; + } else { + firstFactors = + (_a = recipe.MultiFactorAuth.getInstance()) === null || _a === void 0 ? void 0 : _a.config.firstFactors; + } + if (firstFactors !== undefined) { + if (enabledContactMethods.includes("PHONE")) { + if (!firstFactors.includes("otp-phone") && !firstFactors.includes("link-phone")) { + enabledContactMethods = enabledContactMethods.filter(function (c) { + return c !== "PHONE"; + }); + } + } else { + if (firstFactors.includes("otp-phone") || firstFactors.includes("link-phone")) { + throw new Error("The enabled contact method is not a superset of the requested first factors"); + } + } + if (enabledContactMethods.includes("EMAIL")) { + if (!firstFactors.includes("otp-email") && !firstFactors.includes("link-email")) { + enabledContactMethods = enabledContactMethods.filter(function (c) { + return c !== "EMAIL"; + }); + } + } else { + if (firstFactors.includes("otp-email") || firstFactors.includes("link-email")) { + throw new Error("The enabled contact method is not a superset of the requested first factors"); + } + } + } + if (enabledContactMethods.length === 0) { + throw new Error("The enabled contact method is not a superset of the requested first factors"); + } + return enabledContactMethods; +} /* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. * @@ -470,6 +595,20 @@ function normalisePasswordlessBaseConfig(config) { * License for the specific language governing permissions and limitations * under the License. */ +var otpPhoneFactor = { + id: "otp-phone", + name: "SMS based OTP", + description: "Get an OTP code on your phone to complete the authentication request", + path: "/mfa/otp-phone", + logo: OTPSMSIcon, +}; +var otpEmailFactor = { + id: "otp-email", + name: "Email based OTP", + description: "Get an OTP code on your email address to complete the authentication request", + path: "/mfa/otp-email", + logo: OTPEmailIcon, +}; var passwordlessFirstFactors = ["otp-phone", "otp-email", "link-phone", "link-email"]; /* * Class. @@ -490,6 +629,12 @@ var Passwordless = /** @class */ (function (_super) { }); }); }; + postSuperTokensInitCallbacks.PostSuperTokensInitCallbacks.addPostInitCallback(function () { + var mfa = recipe.MultiFactorAuth.getInstance(); + if (mfa !== undefined) { + mfa.addMFAFactors([otpPhoneFactor, otpEmailFactor]); + } + }); return _this; } Passwordless.init = function (config) { @@ -552,6 +697,7 @@ var Passwordless = /** @class */ (function (_super) { exports.Passwordless = Passwordless; exports.defaultEmailValidator = defaultEmailValidator; exports.defaultValidate = defaultValidate; +exports.getEnabledContactMethods = getEnabledContactMethods; exports.getPhoneNumberUtils = getPhoneNumberUtils; exports.normalisePasswordlessConfig = normalisePasswordlessConfig; exports.passwordlessFirstFactors = passwordlessFirstFactors; diff --git a/lib/build/passwordless-shared3.js b/lib/build/passwordless-shared3.js index 43a217daf..62f455661 100644 --- a/lib/build/passwordless-shared3.js +++ b/lib/build/passwordless-shared3.js @@ -5,6 +5,7 @@ var jsxRuntime = require("react/jsx-runtime"); var NormalisedURLPath = require("supertokens-web-js/utils/normalisedURLPath"); var uiEntry = require("./index2.js"); var authWidgetWrapper = require("./authRecipe-shared2.js"); +var session = require("./session-shared.js"); var componentOverrideContext = require("./passwordless-shared.js"); var React = require("react"); var STGeneralError = require("supertokens-web-js/utils/error"); @@ -12,14 +13,18 @@ var recipe = require("./session-shared2.js"); var translations = require("./translations.js"); var translationContext = require("./translationContext.js"); var button = require("./emailpassword-shared2.js"); -var session = require("./session-shared.js"); +var windowHandler = require("supertokens-web-js/utils/windowHandler"); +var recipe$2 = require("./multifactorauth-shared.js"); var recipe$1 = require("./passwordless-shared2.js"); var SuperTokensBranding = require("./SuperTokensBranding.js"); var generalError = require("./emailpassword-shared.js"); +var sessionprebuiltui = require("./sessionprebuiltui.js"); var checkedRoundIcon = require("./checkedRoundIcon.js"); var formBase = require("./emailpassword-shared8.js"); var validators = require("./emailpassword-shared5.js"); var arrowLeftIcon = require("./arrowLeftIcon.js"); +var multifactorauth = require("./multifactorauth-shared2.js"); +var backButton = require("./emailpassword-shared7.js"); function _interopDefault(e) { return e && e.__esModule ? e : { default: e }; @@ -56,7 +61,7 @@ var React__namespace = /*#__PURE__*/ _interopNamespace(React); var STGeneralError__default = /*#__PURE__*/ _interopDefault(STGeneralError); var styles = - '/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 255, 155, 51;\n --palette-primaryBorder: 238, 141, 35;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 34, 34, 34;\n --palette-textLabel: 34, 34, 34;\n --palette-textInput: 34, 34, 34;\n --palette-textPrimary: 101, 101, 101;\n --palette-textLink: 0, 118, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 128, 128, 128;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n}\n\n/*\n * Default styles.\n */\n\n@-webkit-keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n\n@keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n\n@-webkit-keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n\n@keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n\n[data-supertokens~="container"] {\n font-family: "Rubik", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 0 auto;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 15px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 40px;\n letter-spacing: 0.58px;\n font-weight: 600;\n margin-bottom: 2px;\n color: rgb(var(--palette-textTitle));\n}\n\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n margin-bottom: 21px;\n}\n\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n\n/* TODO: split the link style into separate things*/\n\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-1);\n font-weight: 500;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 300;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="divider"] {\n margin-top: 1em;\n margin-bottom: 1em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n}\n\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n\n[data-supertokens~="linkButton"] {\n font-family: "Rubik", sans-serif;\n background-color: transparent;\n border: 0;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n\n[data-supertokens~="button"] {\n font-family: "Rubik", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 700;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n -webkit-filter: brightness(0.85);\n filter: brightness(0.85);\n}\n\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n\n/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n[data-supertokens~="inputContainer"] {\n margin-top: 6px;\n}\n\n[data-supertokens~="inputWrapper"] {\n box-sizing: border-box;\n width: 100%;\n display: flex;\n align-items: center;\n background-color: rgb(var(--palette-inputBackground));\n height: 34px;\n border-radius: 6px;\n border: 1px solid rgb(var(--palette-inputBorder));\n}\n\n[data-supertokens~="inputWrapper"][focus-within] {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputWrapper"]:focus-within {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"][focus-within] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"]:focus-within {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="input"] {\n box-sizing: border-box;\n padding-left: 15px;\n -webkit-filter: none;\n filter: none;\n color: rgb(var(--palette-textInput));\n background-color: transparent;\n border-radius: 6px;\n font-size: var(--font-size-1);\n border: none;\n padding-right: 25px;\n letter-spacing: 1.2px;\n flex: 9 1 75%;\n width: 75%;\n height: 32px;\n}\n\n[data-supertokens~="input"]:focus {\n border: none;\n outline: none;\n}\n\n[data-supertokens~="input"]:-webkit-autofill,\n[data-supertokens~="input"]:-webkit-autofill:hover,\n[data-supertokens~="input"]:-webkit-autofill:focus,\n[data-supertokens~="input"]:-webkit-autofill:active {\n -webkit-text-fill-color: rgb(var(--palette-textInput));\n box-shadow: 0 0 0 30px rgb(var(--palette-inputBackground)) inset;\n}\n\n[data-supertokens~="inputAdornment"] {\n justify-content: center;\n margin-right: 5px;\n}\n\n[data-supertokens~="showPassword"] {\n cursor: pointer;\n}\n\n[data-supertokens~="forgotPasswordLink"] {\n margin-top: 10px;\n}\n\n[data-supertokens~="enterEmailSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n word-break: break-word;\n}\n\n[data-supertokens~="submitNewPasswordSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n\n[data-supertokens~="inputErrorMessage"] {\n padding-top: 5px;\n padding-bottom: 5px;\n color: rgb(var(--palette-error));\n line-height: 24px;\n font-weight: 400;\n font-size: var(--font-size-1);\n text-align: left;\n -webkit-animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n max-width: 330px;\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="inputErrorMessage"] {\n max-width: 250px;\n }\n}\n\n[data-supertokens~="inputErrorSymbol"] {\n margin-right: 5px;\n top: 1px;\n position: relative;\n left: 2px;\n}\n\n[data-supertokens~="label"] {\n text-align: left;\n font-weight: 600;\n font-size: var(--font-size-1);\n line-height: 24px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="formRow"] {\n display: flex;\n flex-direction: column;\n padding-top: 0px;\n padding-bottom: 34px;\n}\n\n[data-supertokens~="formRow"][data-supertokens~="hasError"] {\n padding-bottom: 0;\n}\n\n[data-supertokens~="sendVerifyEmailIcon"] {\n margin-top: 11px;\n}\n\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n\n[data-supertokens~="sendVerifyEmailText"] {\n line-height: 21px;\n font-size: var(--font-size-1);\n text-align: center;\n font-weight: 300;\n letter-spacing: 0.8px;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n\n[data-supertokens~="sendVerifyEmailResend"] {\n margin-top: 13px;\n font-weight: 300;\n}\n\n[data-supertokens~="sendVerifyEmailResend"]:hover {\n text-decoration: underline;\n}\n\n[data-supertokens~="noFormRow"] {\n padding-bottom: 25px;\n}\n\n[data-supertokens~="emailVerificationButtonWrapper"] {\n padding-top: 25px;\n max-width: 96px;\n margin: 0 auto;\n}\n\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n\n[data-supertokens~="resendEmailLink"] {\n display: inline-block;\n}\n\n[data-supertokens~="generalSuccess"] {\n margin-bottom: 20px;\n -webkit-animation: swingIn 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) alternate 2 both;\n animation: swingIn 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) alternate 2 both;\n}\n\n[data-supertokens~="codeInputLabelWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="headerSubtitle"] strong {\n max-width: 100%;\n display: inline-block;\n vertical-align: bottom;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n[data-supertokens~="sendCodeText"] {\n margin-top: 15px;\n margin-bottom: 20px;\n}\n\n[data-supertokens~="sendCodeText"] strong {\n max-width: 100%;\n display: inline-block;\n vertical-align: bottom;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n[data-supertokens~="resendCodeBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n}\n\n[data-supertokens~="resendCodeBtn"]:hover {\n text-decoration: underline;\n}\n\n[data-supertokens~="resendCodeBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n\n[data-supertokens~="phoneInputLibRoot"] {\n display: flex;\n align-items: center;\n}\n\n[data-supertokens~="phoneInputWrapper"] {\n display: flex;\n align-items: center;\n}\n\n[data-supertokens~="phoneInputWrapper"] .iti [data-supertokens~="input"] {\n padding-left: 15px;\n}\n\n[data-supertokens~="phoneInputWrapper"] .iti {\n flex: 1 1;\n min-width: 0;\n width: 100%;\n background: transparent;\n border: none;\n color: inherit;\n outline: none;\n}\n\n[data-supertokens~="continueButtonWrapper"] {\n margin-top: 10px;\n margin-bottom: 30px;\n}\n\n.iti__country-list {\n border: 0;\n top: 40px;\n width: min(72.2vw, 320px);\n border-radius: 6;\n box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.16);\n}\n\n.iti__country {\n display: flex;\n align-items: center;\n height: 34px;\n cursor: pointer;\n\n padding: 0 8px;\n}\n\n.iti__country-name {\n color: var(--palette-textLabel);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin: "0 16px";\n}\n'; + '/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 255, 155, 51;\n --palette-primaryBorder: 238, 141, 35;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 34, 34, 34;\n --palette-textLabel: 34, 34, 34;\n --palette-textInput: 34, 34, 34;\n --palette-textPrimary: 101, 101, 101;\n --palette-textLink: 0, 118, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 128, 128, 128;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n}\n\n/*\n * Default styles.\n */\n\n@-webkit-keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n\n@keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n\n@-webkit-keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n\n@keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n\n[data-supertokens~="container"] {\n font-family: "Rubik", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 0 auto;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 15px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 40px;\n letter-spacing: 0.58px;\n font-weight: 600;\n margin-bottom: 2px;\n color: rgb(var(--palette-textTitle));\n}\n\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n margin-bottom: 21px;\n}\n\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n\n/* TODO: split the link style into separate things*/\n\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-1);\n font-weight: 500;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 300;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="divider"] {\n margin-top: 1em;\n margin-bottom: 1em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n}\n\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n\n[data-supertokens~="linkButton"] {\n font-family: "Rubik", sans-serif;\n background-color: transparent;\n border: 0;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n\n[data-supertokens~="button"] {\n font-family: "Rubik", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 700;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n -webkit-filter: brightness(0.85);\n filter: brightness(0.85);\n}\n\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n\n[data-supertokens~="delayedRender"] {\n -webkit-animation-duration: 0.1s;\n animation-duration: 0.1s;\n -webkit-animation-name: animate-fade;\n animation-name: animate-fade;\n -webkit-animation-delay: 0.2s;\n animation-delay: 0.2s;\n -webkit-animation-fill-mode: backwards;\n animation-fill-mode: backwards;\n}\n\n@-webkit-keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n\n[data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n\n/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n[data-supertokens~="inputContainer"] {\n margin-top: 6px;\n}\n\n[data-supertokens~="inputWrapper"] {\n box-sizing: border-box;\n width: 100%;\n display: flex;\n align-items: center;\n background-color: rgb(var(--palette-inputBackground));\n height: 34px;\n border-radius: 6px;\n border: 1px solid rgb(var(--palette-inputBorder));\n}\n\n[data-supertokens~="inputWrapper"][focus-within] {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputWrapper"]:focus-within {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"][focus-within] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="inputError"]:focus-within {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n\n[data-supertokens~="input"] {\n box-sizing: border-box;\n padding-left: 15px;\n -webkit-filter: none;\n filter: none;\n color: rgb(var(--palette-textInput));\n background-color: transparent;\n border-radius: 6px;\n font-size: var(--font-size-1);\n border: none;\n padding-right: 25px;\n letter-spacing: 1.2px;\n flex: 9 1 75%;\n width: 75%;\n height: 32px;\n}\n\n[data-supertokens~="input"]:focus {\n border: none;\n outline: none;\n}\n\n[data-supertokens~="input"]:-webkit-autofill,\n[data-supertokens~="input"]:-webkit-autofill:hover,\n[data-supertokens~="input"]:-webkit-autofill:focus,\n[data-supertokens~="input"]:-webkit-autofill:active {\n -webkit-text-fill-color: rgb(var(--palette-textInput));\n box-shadow: 0 0 0 30px rgb(var(--palette-inputBackground)) inset;\n}\n\n[data-supertokens~="inputAdornment"] {\n justify-content: center;\n margin-right: 5px;\n}\n\n[data-supertokens~="showPassword"] {\n cursor: pointer;\n}\n\n[data-supertokens~="forgotPasswordLink"] {\n margin-top: 10px;\n}\n\n[data-supertokens~="enterEmailSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n word-break: break-word;\n}\n\n[data-supertokens~="submitNewPasswordSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n\n[data-supertokens~="inputErrorMessage"] {\n padding-top: 5px;\n padding-bottom: 5px;\n color: rgb(var(--palette-error));\n line-height: 24px;\n font-weight: 400;\n font-size: var(--font-size-1);\n text-align: left;\n -webkit-animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n max-width: 330px;\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="inputErrorMessage"] {\n max-width: 250px;\n }\n}\n\n[data-supertokens~="inputErrorSymbol"] {\n margin-right: 5px;\n top: 1px;\n position: relative;\n left: 2px;\n}\n\n[data-supertokens~="label"] {\n text-align: left;\n font-weight: 600;\n font-size: var(--font-size-1);\n line-height: 24px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="formRow"] {\n display: flex;\n flex-direction: column;\n padding-top: 0px;\n padding-bottom: 34px;\n}\n\n[data-supertokens~="formRow"][data-supertokens~="hasError"] {\n padding-bottom: 0;\n}\n\n[data-supertokens~="sendVerifyEmailIcon"] {\n margin-top: 11px;\n}\n\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n\n[data-supertokens~="sendVerifyEmailText"] {\n line-height: 21px;\n font-size: var(--font-size-1);\n text-align: center;\n font-weight: 300;\n letter-spacing: 0.8px;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n\n[data-supertokens~="sendVerifyEmailResend"] {\n margin-top: 13px;\n font-weight: 300;\n}\n\n[data-supertokens~="sendVerifyEmailResend"]:hover {\n text-decoration: underline;\n}\n\n[data-supertokens~="noFormRow"] {\n padding-bottom: 25px;\n}\n\n[data-supertokens~="emailVerificationButtonWrapper"] {\n padding-top: 25px;\n max-width: 96px;\n margin: 0 auto;\n}\n\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="resendEmailLink"] {\n display: inline-block;\n}\n\n[data-supertokens~="generalSuccess"] {\n margin-bottom: 20px;\n -webkit-animation: swingIn 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) alternate 2 both;\n animation: swingIn 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) alternate 2 both;\n}\n\n[data-supertokens~="codeInputLabelWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n[data-supertokens~="headerSubtitle"] strong {\n max-width: 100%;\n display: inline-block;\n vertical-align: bottom;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n[data-supertokens~="sendCodeText"] {\n margin-top: 15px;\n margin-bottom: 20px;\n}\n\n[data-supertokens~="sendCodeText"] strong {\n max-width: 100%;\n display: inline-block;\n vertical-align: bottom;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n[data-supertokens~="resendCodeBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n}\n\n[data-supertokens~="resendCodeBtn"]:hover {\n text-decoration: underline;\n}\n\n[data-supertokens~="resendCodeBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n\n[data-supertokens~="phoneInputLibRoot"] {\n display: flex;\n align-items: center;\n}\n\n[data-supertokens~="phoneInputWrapper"] {\n display: flex;\n align-items: center;\n}\n\n[data-supertokens~="phoneInputWrapper"] .iti [data-supertokens~="input"] {\n padding-left: 15px;\n}\n\n[data-supertokens~="phoneInputWrapper"] .iti {\n flex: 1 1;\n min-width: 0;\n width: 100%;\n background: transparent;\n border: none;\n color: inherit;\n outline: none;\n}\n\n[data-supertokens~="continueButtonWrapper"] {\n margin-top: 10px;\n margin-bottom: 30px;\n}\n\n.iti__country-list {\n border: 0;\n top: 40px;\n width: min(72.2vw, 320px);\n border-radius: 6;\n box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.16);\n}\n\n.iti__country {\n display: flex;\n align-items: center;\n height: 34px;\n cursor: pointer;\n\n padding: 0 8px;\n}\n\n.iti__country-name {\n color: var(--palette-textLabel);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin: "0 16px";\n}\n'; var ThemeBase = function (_a) { var children = _a.children, @@ -222,6 +227,12 @@ var defaultTranslationsPasswordless = { PWLESS_USER_INPUT_CODE_HEADER_SUBTITLE: "An OTP was sent to you at", PWLESS_USER_INPUT_CODE_HEADER_SUBTITLE_LINK: "An OTP and a magic link was sent to you at", PWLESS_USER_INPUT_CODE_INPUT_LABEL: "OTP", + PWLESS_MFA_LOGOUT: "Logout", + PWLESS_MFA_HEADER_TITLE_PHONE: "SMS based OTP", + PWLESS_MFA_HEADER_TITLE_EMAIL: "Email based OTP", + PWLESS_MFA_FOOTER_CHOOSER_ANOTHER: "Choose another factor", + PWLESS_MFA_FOOTER_LOGOUT: "Logout", + PWLESS_MFA_OTP_NOT_ALLOWED_TO_SETUP: "You are not allowed to set up OTP.", /* * The following are error messages from our backend SDK. * These are returned as full messages to preserver compatibilty, but they work just like the keys above. @@ -569,6 +580,7 @@ var SignInUpFooter = uiEntry.withOverride("PasswordlessSignInUpFooter", function var EmailForm = uiEntry.withOverride("PasswordlessEmailForm", function PasswordlessEmailForm(props) { var _this = this; + var _a; var userContext = uiEntry.useUserContext(); return jsxRuntime.jsx(formBase.FormBase, { clearError: props.clearError, @@ -628,10 +640,13 @@ var EmailForm = uiEntry.withOverride("PasswordlessEmailForm", function Passwordl }, validateOnBlur: false, showLabels: true, - footer: jsxRuntime.jsx(SignInUpFooter, { - privacyPolicyLink: props.config.signInUpFeature.privacyPolicyLink, - termsOfServiceLink: props.config.signInUpFeature.termsOfServiceLink, - }), + footer: + (_a = props.footer) !== null && _a !== void 0 + ? _a + : jsxRuntime.jsx(SignInUpFooter, { + privacyPolicyLink: props.config.signInUpFeature.privacyPolicyLink, + termsOfServiceLink: props.config.signInUpFeature.termsOfServiceLink, + }), }); }); @@ -2731,812 +2746,1797 @@ var phoneNumberInputWithInjectedProps = function (injectedProps) { }; }; -var EmailOrPhoneForm = uiEntry.withOverride( - "PasswordlessEmailOrPhoneForm", - function PasswordlessEmailOrPhoneForm(props) { +var PhoneForm = uiEntry.withOverride("PasswordlessPhoneForm", function PasswordlessPhoneForm(props) { + var _this = this; + var _a; + var userContext = uiEntry.useUserContext(); + React.useEffect(function () { + // We preload this here, since it will be used almost for sure, but loading it + void recipe$1.preloadPhoneNumberUtils(); + }, []); + var phoneInput = React.useMemo( + function () { + return phoneNumberInputWithInjectedProps({ + defaultCountry: props.config.signInUpFeature.defaultCountry, + }); + }, + [props.config.signInUpFeature.defaultCountry] + ); + return jsxRuntime.jsx(formBase.FormBase, { + clearError: props.clearError, + onError: props.onError, + formFields: [ + { + id: "phoneNumber", + label: "PWLESS_SIGN_IN_UP_PHONE_LABEL", + inputComponent: phoneInput, + optional: false, + autofocus: true, + placeholder: "", + autoComplete: "tel", + validate: validators.defaultValidate, + }, + ], + buttonLabel: "PWLESS_SIGN_IN_UP_CONTINUE_BUTTON", + onSuccess: props.onSuccess, + callAPI: function (formFields) { + return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () { + var phoneNumber, validationRes, response; + var _a; + return genericComponentOverrideContext.__generator(this, function (_b) { + switch (_b.label) { + case 0: + phoneNumber = + (_a = formFields.find(function (field) { + return field.id === "phoneNumber"; + })) === null || _a === void 0 + ? void 0 + : _a.value; + if (phoneNumber === undefined) { + throw new STGeneralError__default.default("GENERAL_ERROR_PHONE_UNDEFINED"); + } + return [4 /*yield*/, props.config.validatePhoneNumber(phoneNumber)]; + case 1: + validationRes = _b.sent(); + if (validationRes !== undefined) { + throw new STGeneralError__default.default(validationRes); + } + return [ + 4 /*yield*/, + props.recipeImplementation.createCode({ + phoneNumber: phoneNumber, + userContext: userContext, + }), + ]; + case 2: + response = _b.sent(); + if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { + throw new STGeneralError__default.default(response.reason); + } + return [2 /*return*/, response]; + } + }); + }); + }, + validateOnBlur: false, + showLabels: true, + footer: + (_a = props.footer) !== null && _a !== void 0 + ? _a + : jsxRuntime.jsx(SignInUpFooter, { + privacyPolicyLink: props.config.signInUpFeature.privacyPolicyLink, + termsOfServiceLink: props.config.signInUpFeature.termsOfServiceLink, + }), + }); +}); + +var ResendButton = uiEntry.withOverride("PasswordlessResendButton", function PasswordlessResendButton(_a) { + var loginAttemptInfo = _a.loginAttemptInfo, + resendEmailOrSMSGapInSeconds = _a.resendEmailOrSMSGapInSeconds, + onClick = _a.onClick; + var t = translationContext.useTranslation(); + var getTimeLeft = React.useCallback( + function () { + var timeLeft = loginAttemptInfo.lastResend + resendEmailOrSMSGapInSeconds * 1000 - Date.now(); + return timeLeft < 0 ? undefined : Math.ceil(timeLeft / 1000); + }, + [loginAttemptInfo, resendEmailOrSMSGapInSeconds] + ); + var _b = React.useState(getTimeLeft()), + secsUntilResend = _b[0], + setSecsUntilResend = _b[1]; + React.useEffect( + function () { + // This runs every time the loginAttemptInfo updates, so after every resend + var interval = setInterval(function () { + var timeLeft = getTimeLeft(); + if (timeLeft === undefined) { + clearInterval(interval); + } + setSecsUntilResend(timeLeft); + }, 500); + return function () { + // This can safely run twice + clearInterval(interval); + }; + }, + [getTimeLeft, setSecsUntilResend] + ); + return jsxRuntime.jsx( + "button", + genericComponentOverrideContext.__assign( + { + type: "button", + disabled: secsUntilResend !== undefined, + onClick: onClick, + "data-supertokens": "link linkButton resendCodeBtn", + }, + { + children: + secsUntilResend !== undefined + ? jsxRuntime.jsxs(React__namespace.default.Fragment, { + children: [ + t("PWLESS_RESEND_BTN_DISABLED_START"), + jsxRuntime.jsxs("strong", { + children: [ + Math.floor(secsUntilResend / 60) + .toString() + .padStart(2, "0"), + ":", + (secsUntilResend % 60).toString().padStart(2, "0"), + ], + }), + t("PWLESS_RESEND_BTN_DISABLED_END"), + ], + }) + : loginAttemptInfo.contactMethod === "EMAIL" + ? t("PWLESS_RESEND_BTN_EMAIL") + : t("PWLESS_RESEND_BTN_PHONE"), + } + ) + ); +}); + +var UserInputCodeFormFooter = uiEntry.withOverride( + "PasswordlessUserInputCodeFormFooter", + function PasswordlessUserInputCodeFormFooter(_a) { + var loginAttemptInfo = _a.loginAttemptInfo, + recipeImplementation = _a.recipeImplementation; + var t = translationContext.useTranslation(); + var userContext = uiEntry.useUserContext(); + return jsxRuntime.jsx(React.Fragment, { + children: jsxRuntime.jsxs( + "div", + genericComponentOverrideContext.__assign( + { + "data-supertokens": "secondaryText secondaryLinkWithLeftArrow", + onClick: function () { + return recipeImplementation.clearLoginAttemptInfo({ + userContext: userContext, + }); + }, + }, + { + children: [ + jsxRuntime.jsx(arrowLeftIcon.ArrowLeftIcon, { color: "rgb(var(--palette-textPrimary))" }), + loginAttemptInfo.contactMethod === "EMAIL" + ? t("PWLESS_SIGN_IN_UP_CHANGE_CONTACT_INFO_EMAIL") + : t("PWLESS_SIGN_IN_UP_CHANGE_CONTACT_INFO_PHONE"), + ], + } + ) + ), + }); + } +); + +var UserInputCodeForm = uiEntry.withOverride( + "PasswordlessUserInputCodeForm", + function PasswordlessUserInputCodeForm(props) { var _this = this; - var _a = React.useState(false), - isPhoneNumber = _a[0], - setIsPhoneNumber = _a[1]; + var _a; + var t = translationContext.useTranslation(); var userContext = uiEntry.useUserContext(); - React.useEffect(function () { - // We preload this here, since it will be used almost for sure, but loading it - void recipe$1.preloadPhoneNumberUtils(); - }, []); - var emailOrPhoneInput = React.useMemo( + // We need this any because the node types are also loaded + var _b = React.useState(), + clearResendNotifTimeout = _b[0], + setClearResendNotifTimeout = _b[1]; + React.useEffect( function () { - return isPhoneNumber - ? phoneNumberInputWithInjectedProps({ - defaultCountry: props.config.signInUpFeature.defaultCountry, - }) - : undefined; + // This is just to clean up on unmount and if the clear timeout changes + return function () { + clearTimeout(clearResendNotifTimeout); + }; }, - [props.config.signInUpFeature.defaultCountry, isPhoneNumber] + [clearResendNotifTimeout] ); - return jsxRuntime.jsx(formBase.FormBase, { - clearError: props.clearError, - onError: props.onError, - formFields: [ - { - id: "emailOrPhone", - label: "PWLESS_SIGN_IN_UP_EMAIL_OR_PHONE_LABEL", - inputComponent: emailOrPhoneInput, - optional: false, - autofocus: true, - placeholder: "", - // We do not add an autocomplete prop in this case, since we do not really have any sensible option to set - // Setting them to either "tel" or "email" would give people the wrong impression since this could have either - // AFAIK we can't set them both at the same time - validate: recipe$1.defaultValidate, - }, - ], - buttonLabel: "PWLESS_SIGN_IN_UP_CONTINUE_BUTTON", - onSuccess: props.onSuccess, - callAPI: function (formFields, setValue) { - return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () { - var emailOrPhone, - emailValidationRes, - response, - phoneValidationRes, - response, - intPhoneNumber, - phoneValidationResAfterGuess, - response, - ex_1; - var _a; - return genericComponentOverrideContext.__generator(this, function (_b) { - switch (_b.label) { - case 0: - emailOrPhone = - (_a = formFields.find(function (field) { - return field.id === "emailOrPhone"; - })) === null || _a === void 0 - ? void 0 - : _a.value; - if (emailOrPhone === undefined) { - throw new STGeneralError__default.default("GENERAL_ERROR_EMAIL_OR_PHONE_UNDEFINED"); - } - return [4 /*yield*/, recipe$1.defaultEmailValidator(emailOrPhone)]; - case 1: - if (!(_b.sent() === undefined)) return [3 /*break*/, 6]; - return [4 /*yield*/, props.config.validateEmailAddress(emailOrPhone)]; - case 2: - emailValidationRes = _b.sent(); - if (!(emailValidationRes === undefined)) return [3 /*break*/, 4]; - return [ - 4 /*yield*/, - props.recipeImplementation.createCode({ - email: emailOrPhone, - userContext: userContext, - }), - ]; - case 3: - response = _b.sent(); - if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { - throw new STGeneralError__default.default(response.reason); - } - return [2 /*return*/, response]; - case 4: - throw new STGeneralError__default.default(emailValidationRes); - case 5: - return [3 /*break*/, 19]; - case 6: - return [4 /*yield*/, props.config.validatePhoneNumber(emailOrPhone)]; - case 7: - phoneValidationRes = _b.sent(); - if (!(phoneValidationRes === undefined)) return [3 /*break*/, 9]; - return [ - 4 /*yield*/, - props.recipeImplementation.createCode({ - phoneNumber: emailOrPhone, - userContext: userContext, - }), - ]; - case 8: - response = _b.sent(); - if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { - throw new STGeneralError__default.default(response.reason); + function resend() { + return genericComponentOverrideContext.__awaiter(this, void 0, void 0, function () { + var response, generalError, e_1; + return genericComponentOverrideContext.__generator(this, function (_a) { + switch (_a.label) { + case 0: + _a.trys.push([0, 5, , 6]); + response = void 0; + generalError = void 0; + _a.label = 1; + case 1: + _a.trys.push([1, 3, , 4]); + return [ + 4 /*yield*/, + props.recipeImplementation.resendCode({ + userContext: userContext, + }), + ]; + case 2: + response = _a.sent(); + return [3 /*break*/, 4]; + case 3: + e_1 = _a.sent(); + if (STGeneralError__default.default.isThisError(e_1)) { + generalError = e_1; + } else { + throw e_1; + } + return [3 /*break*/, 4]; + case 4: + if (generalError !== undefined) { + props.onError(generalError.message); + } else { + if (response === undefined) { + throw new Error("Should not come here"); } - return [2 /*return*/, response]; - case 9: - return [ - 4 /*yield*/, - props.config.signInUpFeature.guessInternationPhoneNumberFromInputPhoneNumber( - emailOrPhone, - props.config.signInUpFeature.defaultCountry - ), - ]; - case 10: - intPhoneNumber = _b.sent(); - if (!(intPhoneNumber && isPhoneNumber !== true)) return [3 /*break*/, 18]; - return [4 /*yield*/, props.config.validatePhoneNumber(intPhoneNumber)]; - case 11: - phoneValidationResAfterGuess = _b.sent(); - if (!(phoneValidationResAfterGuess === undefined)) return [3 /*break*/, 16]; - _b.label = 12; - case 12: - _b.trys.push([12, 14, , 15]); - return [ - 4 /*yield*/, - props.recipeImplementation.createCode({ - phoneNumber: intPhoneNumber, - userContext: userContext, - }), - ]; - case 13: - response = _b.sent(); - if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { - throw new STGeneralError__default.default(response.reason); + if (response.status === "OK") { + setClearResendNotifTimeout( + setTimeout(function () { + setClearResendNotifTimeout(undefined); + }, 2000) + ); } - return [2 /*return*/, response]; - case 14: - ex_1 = _b.sent(); - // General errors from the API can make createCode throw but we want to switch to the phone UI anyway - setValue("emailOrPhone", intPhoneNumber); - setIsPhoneNumber(true); - throw ex_1; - case 15: - return [3 /*break*/, 17]; - case 16: - // In this case we could get a phonenumber but not a completely valid one - // We want to switch to the phone UI and pre-fill the number - setValue("emailOrPhone", intPhoneNumber); - setIsPhoneNumber(true); - throw new STGeneralError__default.default( - "PWLESS_EMAIL_OR_PHONE_INVALID_INPUT_GUESS_PHONE_ERR" - ); - case 17: - return [3 /*break*/, 19]; - case 18: - throw new STGeneralError__default.default(phoneValidationRes); - case 19: - return [2 /*return*/]; - } - }); + } + return [3 /*break*/, 6]; + case 5: + _a.sent(); + props.onError("SOMETHING_WENT_WRONG_ERROR"); + return [3 /*break*/, 6]; + case 6: + return [2 /*return*/]; + } }); - }, - validateOnBlur: false, - showLabels: true, - footer: jsxRuntime.jsx(SignInUpFooter, { - privacyPolicyLink: props.config.signInUpFeature.privacyPolicyLink, - termsOfServiceLink: props.config.signInUpFeature.termsOfServiceLink, - }), - }); - } -); - -/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. - * - * This software is licensed under the Apache License, Version 2.0 (the - * "License") as published by the Apache Software Foundation. - * - * You may not use this file except in compliance with the License. You may - * obtain a copy of the License at http="//www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -/* - * Imports. - */ -/* - * Component. - */ -function SMSLargeIcon() { - return jsxRuntime.jsx( - "svg", - genericComponentOverrideContext.__assign( - { xmlns: "http://www.w3.org/2000/svg", width: "52.013", height: "41.889", viewBox: "0 0 52.013 41.889" }, - { - children: jsxRuntime.jsx( - "g", - genericComponentOverrideContext.__assign( - { id: "Group_10400", "data-name": "Group 10400", transform: "translate(-724.625 -241.125)" }, + }); + } + return jsxRuntime.jsxs(React__namespace.default.Fragment, { + children: [ + clearResendNotifTimeout !== undefined && + jsxRuntime.jsx( + "div", + genericComponentOverrideContext.__assign( + { "data-supertokens": "generalSuccess" }, + { + children: + props.loginAttemptInfo.contactMethod === "EMAIL" + ? t("PWLESS_RESEND_SUCCESS_EMAIL") + : t("PWLESS_RESEND_SUCCESS_PHONE"), + } + ) + ), + jsxRuntime.jsx(formBase.FormBase, { + clearError: props.clearError, + onError: props.onError, + formFields: [ { - children: jsxRuntime.jsxs( - "g", + id: "userInputCode", + label: "", + labelComponent: jsxRuntime.jsxs( + "div", genericComponentOverrideContext.__assign( - { id: "Group_10399", "data-name": "Group 10399" }, + { "data-supertokens": "codeInputLabelWrapper" }, { children: [ - jsxRuntime.jsxs( - "g", - genericComponentOverrideContext.__assign( - { id: "Group_10398", "data-name": "Group 10398" }, - { - children: [ - jsxRuntime.jsxs( - "g", - genericComponentOverrideContext.__assign( - { - id: "_2639922_sms_icon", - "data-name": "2639922_sms_icon", - transform: "translate(732.916 242)", - }, - { - children: [ - jsxRuntime.jsx("path", { - id: "Union_52", - "data-name": "Union 52", - d: "M7.124 37.96a6.26 6.26 0 0 0 3.652-5H6.593A6.592 6.592 0 0 1 0 26.367V6.592A6.592 6.592 0 0 1 6.593 0h29.664a6.592 6.592 0 0 1 6.593 6.592v19.775a6.592 6.592 0 0 1-6.593 6.592h-17.68a13.355 13.355 0 0 1-11.159 6.576zm20.893-21.48a3.3 3.3 0 1 0 3.3-3.3 3.3 3.3 0 0 0-3.3 3.3zm-9.887 0a3.3 3.3 0 1 0 3.3-3.3 3.295 3.295 0 0 0-3.3 3.3zm-9.888 0a3.3 3.3 0 1 0 3.3-3.3 3.3 3.3 0 0 0-3.301 3.3z", - transform: "translate(-.001)", - strokeWidth: "1.75px", - stroke: "#000", - fill: "#c4f3ff", - }), - jsxRuntime.jsx("ellipse", { - id: "Ellipse_3013", - "data-name": "Ellipse 3013", - cy: ".917", - ry: ".917", - transform: "translate(7.335 38.506)", - stroke: "#000", - fill: "#c4f3ff", - }), - ], - } - ) - ), - jsxRuntime.jsx("path", { - id: "Intersection_2", - "data-name": "Intersection 2", - fill: "#8ae7ff", - d: "M177.409-21836.576v-.33l-.214-1.131a6.271 6.271 0 0 0 3.651-5h-4.184a6.59 6.59 0 0 1-6.512-5.588h42.495a7.846 7.846 0 0 1-1.607 3.605 6.576 6.576 0 0 1-4.712 1.982h-14.845c-1.545-.09-2.537-.164-2.537-.164l-.077.164h-.219a13.342 13.342 0 0 1-11.156 6.572l-.082-.439z", - transform: "translate(562.766 22118)", - }), - jsxRuntime.jsx("path", { - id: "Intersection_1", - "data-name": "Intersection 1", - fill: "#8ae7ff", - d: "M209.246-21846.41s.494-22.641 0-25.178a8.7 8.7 0 0 0-2.767-4.41 6.6 6.6 0 0 1 6.369 6.59v19.775a6.6 6.6 0 0 1-5.724 6.537 6.213 6.213 0 0 0 2.122-3.314z", - transform: "translate(561.882 22118.172)", - }), - ], - } - ) - ), - jsxRuntime.jsxs( - "g", - genericComponentOverrideContext.__assign( - { - id: "_2639922_sms_icon-2", - "data-name": "2639922_sms_icon", - transform: "translate(732.916 242.174)", - }, - { - children: [ - jsxRuntime.jsx("path", { - id: "Union_52-2", - "data-name": "Union 52", - d: "M7.124 37.96a6.26 6.26 0 0 0 3.652-5H6.593A6.592 6.592 0 0 1 0 26.367V6.592A6.592 6.592 0 0 1 6.593 0h29.664a6.592 6.592 0 0 1 6.593 6.592v19.775a6.592 6.592 0 0 1-6.593 6.592h-17.68a13.355 13.355 0 0 1-11.159 6.576zm20.893-21.48a3.3 3.3 0 1 0 3.3-3.3 3.3 3.3 0 0 0-3.3 3.3zm-9.887 0a3.3 3.3 0 1 0 3.3-3.3 3.295 3.295 0 0 0-3.3 3.3zm-9.888 0a3.3 3.3 0 1 0 3.3-3.3 3.3 3.3 0 0 0-3.301 3.3z", - transform: "translate(-.001)", - fill: "none", - strokeWidth: "1.75px", - stroke: "#000", - }), - jsxRuntime.jsx("ellipse", { - id: "Ellipse_3013-2", - "data-name": "Ellipse 3013", - cy: ".917", - ry: ".917", - transform: "translate(7.335 38.506)", - fill: "none", - stroke: "#000", - }), - ], - } - ) - ), - jsxRuntime.jsxs( - "g", - genericComponentOverrideContext.__assign( - { id: "Group_10397", "data-name": "Group 10397" }, - { - children: [ - jsxRuntime.jsx("path", { - id: "Line_104", - "data-name": "Line 104", - strokeWidth: "1.75px", - fill: "none", - strokeLinecap: "round", - stroke: "#000", - transform: "translate(725.5 266.84)", - d: "M0 0h9.872", - }), - jsxRuntime.jsx("path", { - id: "Line_105", - "data-name": "Line 105", - strokeWidth: "1.75px", - fill: "none", - strokeLinecap: "round", - stroke: "#fff", - transform: "translate(725.5 268.59)", - d: "M0 0h9.872", - }), - ], - } - ) - ), - jsxRuntime.jsxs( - "g", - genericComponentOverrideContext.__assign( - { id: "Group_10396", "data-name": "Group 10396" }, - { - children: [ - jsxRuntime.jsx("path", { - id: "Line_103", - "data-name": "Line 103", - strokeWidth: "1.75px", - fill: "none", - strokeLinecap: "round", - stroke: "#000", - transform: "translate(725.5 260.17)", - d: "M0 0h12.461", - }), - jsxRuntime.jsx("path", { - id: "Line_102", - "data-name": "Line 102", - strokeWidth: "1.75px", - fill: "none", - strokeLinecap: "round", - stroke: "#fff", - transform: "translate(725.5 261.92)", - d: "M0 0h12.461", - }), - ], - } - ) - ), - jsxRuntime.jsx("path", { - id: "Path_91918", - "data-name": "Path 91918", - fill: "#8ae7ff", - d: "M599.827 22145.373a1.62 1.62 0 0 0 1.38-1.336c.247-1.234.267 1.752.267 1.752l-1.647-.178z", - transform: "translate(170 -21876)", + jsxRuntime.jsx(formBase.Label, { + value: "PWLESS_USER_INPUT_CODE_INPUT_LABEL", + "data-supertokens": "codeInputLabel", + }), + jsxRuntime.jsx(ResendButton, { + loginAttemptInfo: props.loginAttemptInfo, + resendEmailOrSMSGapInSeconds: + props.config.signInUpFeature.resendEmailOrSMSGapInSeconds, + onClick: resend, }), - jsxRuntime.jsxs( - "g", - genericComponentOverrideContext.__assign( - { id: "Group_10395", "data-name": "Group 10395" }, - { - children: [ - jsxRuntime.jsx("path", { - id: "Line_100", - "data-name": "Line 100", - strokeWidth: "1.75px", - fill: "none", - strokeLinecap: "round", - stroke: "#000", - transform: "translate(725.5 253.5)", - d: "M0 0h9.872", - }), - jsxRuntime.jsx("path", { - id: "Line_101", - "data-name": "Line 101", - strokeWidth: "1.75px", - fill: "none", - strokeLinecap: "round", - stroke: "#fff", - transform: "translate(725.5 255.25)", - d: "M0 0h9.872", - }), - ], - } - ) - ), ], } ) ), - } - ) - ), + autofocus: true, + optional: false, + clearOnSubmit: true, + autoComplete: "one-time-code", + placeholder: "", + validate: recipe$1.userInputCodeValidate, + }, + ], + onSuccess: props.onSuccess, + buttonLabel: "PWLESS_SIGN_IN_UP_CONTINUE_BUTTON", + callAPI: function (formFields) { + return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () { + var userInputCode, response; + var _a; + return genericComponentOverrideContext.__generator(this, function (_b) { + switch (_b.label) { + case 0: + userInputCode = + (_a = formFields.find(function (field) { + return field.id === "userInputCode"; + })) === null || _a === void 0 + ? void 0 + : _a.value; + if (userInputCode === undefined || userInputCode.length === 0) { + throw new STGeneralError__default.default("GENERAL_ERROR_OTP_UNDEFINED"); + } + return [ + 4 /*yield*/, + props.recipeImplementation.consumeCode({ + userInputCode: userInputCode, + userContext: userContext, + }), + ]; + case 1: + response = _b.sent(); + // We can redirect these statuses, since they all cause a redirection + // and we don't really want to show anything + if ( + response.status === "OK" || + response.status === "RESTART_FLOW_ERROR" || + response.status === "SIGN_IN_UP_NOT_ALLOWED" + ) { + return [2 /*return*/, response]; + } + if (response.status === "INCORRECT_USER_INPUT_CODE_ERROR") { + throw new STGeneralError__default.default("GENERAL_ERROR_OTP_INVALID"); + } + if (response.status === "EXPIRED_USER_INPUT_CODE_ERROR") { + throw new STGeneralError__default.default("GENERAL_ERROR_OTP_EXPIRED"); + } + throw new STGeneralError__default.default("SOMETHING_WENT_WRONG_ERROR"); + } + }); + }); + }, + validateOnBlur: false, + showLabels: true, + footer: + (_a = props.footer) !== null && _a !== void 0 + ? _a + : jsxRuntime.jsx( + UserInputCodeFormFooter, + genericComponentOverrideContext.__assign({}, props, { + loginAttemptInfo: props.loginAttemptInfo, + }) + ), + }), + ], + }); + } +); + +var MFAFooter = uiEntry.withOverride("PasswordlessMFAFooter", function PasswordlessMFAFooter(props) { + var _a, _b; + var t = translationContext.useTranslation(); + var claim = session.useClaimValue(multifactorauth.MultiFactorAuthClaim); + return jsxRuntime.jsxs( + "div", + genericComponentOverrideContext.__assign( + { "data-supertokens": "footerLinkGroupVert pwlessMFAFooter" }, + { + children: [ + claim.loading === false && + ((_b = (_a = claim.value) === null || _a === void 0 ? void 0 : _a.n.length) !== null && + _b !== void 0 + ? _b + : 0) > 1 && + jsxRuntime.jsx( + "div", + genericComponentOverrideContext.__assign( + { "data-supertokens": "secondaryText", onClick: props.onFactorChooserButtonClicked }, + { children: t("PWLESS_MFA_FOOTER_CHOOSER_ANOTHER") } + ) + ), + jsxRuntime.jsxs( + "div", + genericComponentOverrideContext.__assign( + { + "data-supertokens": "secondaryText secondaryLinkWithLeftArrow", + onClick: props.onSignOutClicked, + }, + { + children: [ + jsxRuntime.jsx(arrowLeftIcon.ArrowLeftIcon, { + color: "rgb(var(--palette-textPrimary))", + }), + t("PWLESS_MFA_FOOTER_LOGOUT"), + ], + } + ) + ), + ], } ) ); -} +}); -var ResendButton = uiEntry.withOverride("PasswordlessResendButton", function PasswordlessResendButton(_a) { +var MFAHeader = uiEntry.withOverride("PasswordlessMFAHeader", function PasswordlessMFAHeader(props) { + var _a; + var t = translationContext.useTranslation(); + var claim = session.useClaimValue(multifactorauth.MultiFactorAuthClaim); + return jsxRuntime.jsxs(React.Fragment, { + children: [ + jsxRuntime.jsxs( + "div", + genericComponentOverrideContext.__assign( + { "data-supertokens": "headerTitle withBackButton" }, + { + children: [ + claim.loading === false && + ((_a = claim.value) === null || _a === void 0 ? void 0 : _a.n.length) === 0 + ? jsxRuntime.jsx(backButton.BackButton, { onClick: props.onBackButtonClicked }) + : jsxRuntime.jsx("span", { + "data-supertokens": "backButtonPlaceholder backButtonCommon", + }), + props.contactMethod === "EMAIL" + ? t("PWLESS_MFA_HEADER_TITLE_EMAIL") + : t("PWLESS_MFA_HEADER_TITLE_PHONE"), + jsxRuntime.jsx("span", { "data-supertokens": "backButtonPlaceholder backButtonCommon" }), + ], + } + ) + ), + jsxRuntime.jsx("div", { "data-supertokens": "divider" }), + ], + }); +}); + +var MFAOTPFooter = uiEntry.withOverride("PasswordlessMFAOTPFooter", function PasswordlessMFAOTPFooter(_a) { + var _b, _c; var loginAttemptInfo = _a.loginAttemptInfo, - resendEmailOrSMSGapInSeconds = _a.resendEmailOrSMSGapInSeconds, - onClick = _a.onClick; + recipeImplementation = _a.recipeImplementation, + onSignOutClicked = _a.onSignOutClicked, + onFactorChooserButtonClicked = _a.onFactorChooserButtonClicked, + isSetupAllowed = _a.isSetupAllowed; var t = translationContext.useTranslation(); - var getTimeLeft = React.useCallback( - function () { - var timeLeft = loginAttemptInfo.lastResend + resendEmailOrSMSGapInSeconds * 1000 - Date.now(); - return timeLeft < 0 ? undefined : Math.ceil(timeLeft / 1000); - }, - [loginAttemptInfo, resendEmailOrSMSGapInSeconds] - ); - var _b = React.useState(getTimeLeft()), - secsUntilResend = _b[0], - setSecsUntilResend = _b[1]; - React.useEffect( - function () { - // This runs every time the loginAttemptInfo updates, so after every resend - var interval = setInterval(function () { - var timeLeft = getTimeLeft(); - if (timeLeft === undefined) { - clearInterval(interval); - } - setSecsUntilResend(timeLeft); - }, 500); - return function () { - // This can safely run twice - clearInterval(interval); - }; - }, - [getTimeLeft, setSecsUntilResend] - ); - return jsxRuntime.jsx( - "button", + var claim = session.useClaimValue(multifactorauth.MultiFactorAuthClaim); + var userContext = uiEntry.useUserContext(); + return jsxRuntime.jsxs( + "div", genericComponentOverrideContext.__assign( + { "data-supertokens": "footerLinkGroupVert pwlessMFAOTPFooter" }, { - type: "button", - disabled: secsUntilResend !== undefined, - onClick: onClick, - "data-supertokens": "link linkButton resendCodeBtn", - }, - { - children: - secsUntilResend !== undefined - ? jsxRuntime.jsxs(React__namespace.default.Fragment, { - children: [ - t("PWLESS_RESEND_BTN_DISABLED_START"), - jsxRuntime.jsxs("strong", { - children: [ - Math.floor(secsUntilResend / 60) - .toString() - .padStart(2, "0"), - ":", - (secsUntilResend % 60).toString().padStart(2, "0"), - ], - }), - t("PWLESS_RESEND_BTN_DISABLED_END"), - ], - }) - : loginAttemptInfo.contactMethod === "EMAIL" - ? t("PWLESS_RESEND_BTN_EMAIL") - : t("PWLESS_RESEND_BTN_PHONE"), + children: [ + isSetupAllowed + ? jsxRuntime.jsx( + "div", + genericComponentOverrideContext.__assign( + { + "data-supertokens": "secondaryText", + onClick: function () { + return recipeImplementation.clearLoginAttemptInfo({ + userContext: userContext, + }); + }, + }, + { + children: + loginAttemptInfo.contactMethod === "EMAIL" + ? t("PWLESS_SIGN_IN_UP_CHANGE_CONTACT_INFO_EMAIL") + : t("PWLESS_SIGN_IN_UP_CHANGE_CONTACT_INFO_PHONE"), + } + ) + ) + : claim.loading === false && + ((_c = (_b = claim.value) === null || _b === void 0 ? void 0 : _b.n.length) !== null && + _c !== void 0 + ? _c + : 0) > 1 && + jsxRuntime.jsx( + "div", + genericComponentOverrideContext.__assign( + { "data-supertokens": "secondaryText", onClick: onFactorChooserButtonClicked }, + { children: t("PWLESS_MFA_FOOTER_CHOOSER_ANOTHER") } + ) + ), + jsxRuntime.jsxs( + "div", + genericComponentOverrideContext.__assign( + { + "data-supertokens": "secondaryText secondaryLinkWithLeftArrow", + onClick: onSignOutClicked, + }, + { + children: [ + jsxRuntime.jsx(arrowLeftIcon.ArrowLeftIcon, { + color: "rgb(var(--palette-textPrimary))", + }), + t("PWLESS_MFA_LOGOUT"), + ], + } + ) + ), + ], } ) ); }); -var PasswordlessLinkSent = function (props) { +var MFAOTPHeader = uiEntry.withOverride("PasswordlessMFAOTPHeader", function PasswordlessMFAOTPHeader(_a) { + var _b; + var loginAttemptInfo = _a.loginAttemptInfo, + onBackButtonClicked = _a.onBackButtonClicked, + isSetupAllowed = _a.isSetupAllowed; var t = translationContext.useTranslation(); - var userContext = uiEntry.useUserContext(); - var _a = React.useState(props.error !== undefined ? "ERROR" : "READY"), - status = _a[0], - setStatus = _a[1]; - // Any because node types are included here, messing with return type of setTimeout - var resendNotifTimeout = React.useRef(); - React.useEffect(function () { - return function () { - // This can safely run even if it was cleared before - if (resendNotifTimeout.current) { - clearTimeout(resendNotifTimeout.current); - } - }; - }, []); - var resendEmail = React.useCallback( - function () { - return genericComponentOverrideContext.__awaiter(void 0, void 0, void 0, function () { - var response, generalError, e_1; - return genericComponentOverrideContext.__generator(this, function (_a) { - switch (_a.label) { - case 0: - _a.trys.push([0, 5, , 6]); - props.clearError(); - response = void 0; - generalError = void 0; - _a.label = 1; - case 1: - _a.trys.push([1, 3, , 4]); - return [ - 4 /*yield*/, - props.recipeImplementation.resendCode({ - userContext: userContext, - }), - ]; - case 2: - response = _a.sent(); - return [3 /*break*/, 4]; - case 3: - e_1 = _a.sent(); - if (STGeneralError__default.default.isThisError(e_1)) { - generalError = e_1; - } else { - throw e_1; - } - return [3 /*break*/, 4]; - case 4: - if (response !== undefined && response.status === "OK") { - setStatus("LINK_RESENT"); - resendNotifTimeout.current = setTimeout(function () { - setStatus(function (status) { - return status === "LINK_RESENT" ? "READY" : status; - }); - resendNotifTimeout.current = undefined; - }, 2000); - } else { - setStatus("ERROR"); - if (generalError !== undefined) { - props.onError(generalError.message); - } - } - return [3 /*break*/, 6]; - case 5: - _a.sent(); - setStatus("ERROR"); - return [3 /*break*/, 6]; - case 6: - return [2 /*return*/]; + var claim = session.useClaimValue(multifactorauth.MultiFactorAuthClaim); + return jsxRuntime.jsxs(React.Fragment, { + children: [ + jsxRuntime.jsxs( + "div", + genericComponentOverrideContext.__assign( + { "data-supertokens": "headerTitle withBackButton" }, + { + children: [ + claim.loading === false && + ((_b = claim.value) === null || _b === void 0 ? void 0 : _b.n.length) === 0 && + isSetupAllowed === false + ? jsxRuntime.jsx(backButton.BackButton, { onClick: onBackButtonClicked }) + : jsxRuntime.jsx("span", { + "data-supertokens": "backButtonPlaceholder backButtonCommon", + }), + t("PWLESS_USER_INPUT_CODE_HEADER_TITLE"), + jsxRuntime.jsx("span", { "data-supertokens": "backButtonPlaceholder backButtonCommon" }), + ], } - }); - }); + ) + ), + jsxRuntime.jsxs( + "div", + genericComponentOverrideContext.__assign( + { "data-supertokens": "headerSubtitle secondaryText" }, + { + children: [ + loginAttemptInfo.flowType === "USER_INPUT_CODE" + ? t("PWLESS_USER_INPUT_CODE_HEADER_SUBTITLE") + : t("PWLESS_USER_INPUT_CODE_HEADER_SUBTITLE_LINK"), + jsxRuntime.jsx("br", {}), + jsxRuntime.jsx("strong", { children: loginAttemptInfo.contactInfo }), + ], + } + ) + ), + jsxRuntime.jsx("div", { "data-supertokens": "divider" }), + ], + }); +}); + +var MFAScreens; +(function (MFAScreens) { + MFAScreens[(MFAScreens["CloseTab"] = 0)] = "CloseTab"; + MFAScreens[(MFAScreens["EmailForm"] = 1)] = "EmailForm"; + MFAScreens[(MFAScreens["PhoneForm"] = 2)] = "PhoneForm"; + MFAScreens[(MFAScreens["UserInputCodeForm"] = 3)] = "UserInputCodeForm"; + MFAScreens[(MFAScreens["AccessDenied"] = 4)] = "AccessDenied"; +})(MFAScreens || (MFAScreens = {})); +var MFATheme = function (_a) { + var activeScreen = _a.activeScreen, + featureState = _a.featureState, + onBackButtonClicked = _a.onBackButtonClicked, + props = genericComponentOverrideContext.__rest(_a, ["activeScreen", "featureState", "onBackButtonClicked"]); + var t = translationContext.useTranslation(); + var commonProps = { + recipeImplementation: props.recipeImplementation, + config: props.config, + clearError: function () { + return props.dispatch({ type: "setError", error: undefined }); }, - [props.recipeImplementation, props.loginAttemptInfo, props.config, setStatus] - ); - var resendActive = status === "LINK_RESENT"; + onError: function (error) { + return props.dispatch({ type: "setError", error: error }); + }, + error: featureState.error, + }; + if (!featureState.loaded) { + return null; + } + return activeScreen === MFAScreens.CloseTab + ? jsxRuntime.jsx(CloseTabScreen, genericComponentOverrideContext.__assign({}, commonProps)) + : activeScreen === MFAScreens.AccessDenied + ? jsxRuntime.jsx(sessionprebuiltui.AccessDeniedScreen, { useShadowDom: false, error: t(featureState.error) }) + : jsxRuntime.jsxs( + "div", + genericComponentOverrideContext.__assign( + { "data-supertokens": "container pwlessMFA" }, + { + children: [ + jsxRuntime.jsx( + "div", + genericComponentOverrideContext.__assign( + { "data-supertokens": "row" }, + { + children: jsxRuntime.jsxs(React__namespace.default.Fragment, { + children: [ + activeScreen === MFAScreens.UserInputCodeForm + ? jsxRuntime.jsx( + MFAOTPHeader, + genericComponentOverrideContext.__assign({}, commonProps, { + loginAttemptInfo: featureState.loginAttemptInfo, + isSetupAllowed: featureState.isSetupAllowed, + onBackButtonClicked: onBackButtonClicked, + }) + ) + : jsxRuntime.jsx(MFAHeader, { + onBackButtonClicked: onBackButtonClicked, + contactMethod: + activeScreen === MFAScreens.EmailForm ? "EMAIL" : "PHONE", + }), + featureState.error !== undefined && + jsxRuntime.jsx(generalError.GeneralError, { + error: featureState.error, + }), + activeScreen === MFAScreens.EmailForm + ? jsxRuntime.jsx( + EmailForm, + genericComponentOverrideContext.__assign({}, commonProps, { + footer: jsxRuntime.jsx( + MFAFooter, + genericComponentOverrideContext.__assign( + {}, + commonProps, + { + onFactorChooserButtonClicked: + props.onFactorChooserButtonClicked, + onSignOutClicked: props.onSignOutClicked, + isSetupAllowed: featureState.isSetupAllowed, + } + ) + ), + }) + ) + : activeScreen === MFAScreens.PhoneForm + ? jsxRuntime.jsx( + PhoneForm, + genericComponentOverrideContext.__assign({}, commonProps, { + footer: jsxRuntime.jsx( + MFAFooter, + genericComponentOverrideContext.__assign( + {}, + commonProps, + { + onFactorChooserButtonClicked: + props.onFactorChooserButtonClicked, + onSignOutClicked: props.onSignOutClicked, + isSetupAllowed: featureState.isSetupAllowed, + } + ) + ), + }) + ) + : activeScreen === MFAScreens.UserInputCodeForm + ? jsxRuntime.jsx( + UserInputCodeForm, + genericComponentOverrideContext.__assign({}, commonProps, { + loginAttemptInfo: featureState.loginAttemptInfo, + onSuccess: props.onSuccess, + footer: jsxRuntime.jsx( + MFAOTPFooter, + genericComponentOverrideContext.__assign( + {}, + commonProps, + { + onFactorChooserButtonClicked: + props.onFactorChooserButtonClicked, + onSignOutClicked: props.onSignOutClicked, + isSetupAllowed: featureState.isSetupAllowed, + loginAttemptInfo: featureState.loginAttemptInfo, + } + ) + ), + }) + ) + : null, + ], + }), + } + ) + ), + jsxRuntime.jsx(SuperTokensBranding.SuperTokensBranding, {}), + ], + } + ) + ); +}; +function MFAThemeWrapper(props) { + var hasFont = translations.hasFontDefined(props.config.rootStyle); + var activeScreen = getActiveScreen$1(props); + var activeStyle; + if (activeScreen === MFAScreens.CloseTab) { + activeStyle = props.config.signInUpFeature.closeTabScreenStyle; + } else if (activeScreen === MFAScreens.UserInputCodeForm) { + activeStyle = props.config.signInUpFeature.userInputCodeFormStyle; + } else if (activeScreen === MFAScreens.EmailForm) { + activeStyle = props.config.signInUpFeature.emailOrPhoneFormStyle; + } else if (activeScreen === MFAScreens.PhoneForm) { + activeStyle = props.config.signInUpFeature.emailOrPhoneFormStyle; + } else { + activeStyle = ""; // styling the access denied screen is handled through the session recipe + } return jsxRuntime.jsx( - "div", + uiEntry.UserContextWrapper, genericComponentOverrideContext.__assign( - { "data-supertokens": "container" }, + { userContext: props.userContext }, { - children: jsxRuntime.jsxs( - "div", + children: jsxRuntime.jsx( + ThemeBase, genericComponentOverrideContext.__assign( - { "data-supertokens": "row" }, { - children: [ - status === "ERROR" && - jsxRuntime.jsx(generalError.GeneralError, { - error: props.error === undefined ? "SOMETHING_WENT_WRONG_ERROR" : props.error, - }), - resendActive && - jsxRuntime.jsx( - "div", - genericComponentOverrideContext.__assign( - { "data-supertokens": "generalSuccess" }, - { children: t("PWLESS_LINK_SENT_RESEND_SUCCESS") } - ) - ), - jsxRuntime.jsx( - "div", - genericComponentOverrideContext.__assign( - { "data-supertokens": "sendCodeIcon" }, - { - children: - props.loginAttemptInfo.contactMethod === "EMAIL" - ? jsxRuntime.jsx(checkedRoundIcon.EmailLargeIcon, {}) - : jsxRuntime.jsx(SMSLargeIcon, {}), - } - ) - ), - jsxRuntime.jsx( - "div", - genericComponentOverrideContext.__assign( - { "data-supertokens": "headerTitle headerTinyTitle" }, - { children: t("PWLESS_LINK_SENT_RESEND_TITLE") } - ) - ), - jsxRuntime.jsxs( - "div", + loadDefaultFont: !hasFont, + userStyles: [props.config.rootStyle, activeStyle, props.config.mfaFeature.style], + }, + { + children: jsxRuntime.jsx( + MFATheme, + genericComponentOverrideContext.__assign({}, props, { activeScreen: activeScreen }) + ), + } + ) + ), + } + ) + ); +} +function getActiveScreen$1(props) { + if (props.featureState.successInAnotherTab) { + return MFAScreens.CloseTab; + } else if ( + props.featureState.error === "PWLESS_MFA_OTP_NOT_ALLOWED_TO_SETUP" || + (props.featureState.isSetupAllowed === false && props.featureState.loginAttemptInfo === undefined) + ) { + return MFAScreens.AccessDenied; + } else if (props.featureState.loginAttemptInfo) { + return MFAScreens.UserInputCodeForm; + } else if (props.contactMethod === "EMAIL") { + return MFAScreens.EmailForm; + } else if (props.contactMethod === "PHONE") { + return MFAScreens.PhoneForm; + } + throw new Error("Couldn't choose active screen; Should never happen"); +} + +var useSuccessInAnotherTabChecker$1 = function (callingConsumeCodeRef, recipeImpl, state, dispatch, userContext) { + React.useEffect( + function () { + // We only need to start checking this if we have an active login attempt + if (state.loginAttemptInfo && !state.successInAnotherTab) { + var checkSessionIntervalHandle_1 = setInterval(function () { + return genericComponentOverrideContext.__awaiter(void 0, void 0, void 0, function () { + var currLoginAttempt; + var _a; + return genericComponentOverrideContext.__generator(this, function (_b) { + switch (_b.label) { + case 0: + if (!(callingConsumeCodeRef.current === false)) return [3 /*break*/, 2]; + return [4 /*yield*/, recipeImpl.getLoginAttemptInfo({ userContext: userContext })]; + case 1: + currLoginAttempt = _b.sent(); + if ( + currLoginAttempt === undefined || + currLoginAttempt.deviceId !== + ((_a = state.loginAttemptInfo) === null || _a === void 0 + ? void 0 + : _a.deviceId) + ) { + dispatch({ type: "successInAnotherTab" }); + } + _b.label = 2; + case 2: + return [2 /*return*/]; + } + }); + }); + }, 2000); + return function () { + clearInterval(checkSessionIntervalHandle_1); + }; + } + // Nothing to clean up + return; + }, + [state.loginAttemptInfo, state.successInAnotherTab] + ); +}; +var useFeatureReducer$1 = function () { + return React__namespace.useReducer( + function (oldState, action) { + switch (action.type) { + case "load": + return { + loaded: true, + error: action.error, + loginAttemptInfo: action.loginAttemptInfo, + isSetupAllowed: action.isAllowedToSetup, + successInAnotherTab: false, + }; + case "resendCode": + if (!oldState.loginAttemptInfo) { + return oldState; + } + return genericComponentOverrideContext.__assign( + genericComponentOverrideContext.__assign({}, oldState), + { + error: undefined, + loginAttemptInfo: genericComponentOverrideContext.__assign( + genericComponentOverrideContext.__assign({}, oldState.loginAttemptInfo), + { lastResend: action.timestamp } + ), + } + ); + case "restartFlow": + return genericComponentOverrideContext.__assign( + genericComponentOverrideContext.__assign({}, oldState), + { error: action.error, loginAttemptInfo: undefined } + ); + case "setError": + return genericComponentOverrideContext.__assign( + genericComponentOverrideContext.__assign({}, oldState), + { loaded: true, error: action.error } + ); + case "startVerify": + return genericComponentOverrideContext.__assign( + genericComponentOverrideContext.__assign({}, oldState), + { + loaded: true, + loginAttemptInfo: action.loginAttemptInfo, + error: undefined, + successInAnotherTab: false, + } + ); + case "successInAnotherTab": + return genericComponentOverrideContext.__assign( + genericComponentOverrideContext.__assign({}, oldState), + { successInAnotherTab: true } + ); + default: + return oldState; + } + }, + { + error: undefined, + loaded: false, + loginAttemptInfo: undefined, + isSetupAllowed: false, + successInAnotherTab: false, + }, + function (initArg) { + var error = undefined; + var errorQueryParam = genericComponentOverrideContext.getQueryParams("error"); + if (errorQueryParam !== null) { + error = "SOMETHING_WENT_WRONG_ERROR"; + } + return genericComponentOverrideContext.__assign(genericComponentOverrideContext.__assign({}, initArg), { + error: error, + }); + } + ); +}; +function useChildProps$1(recipe$1, recipeImplementation, state, contactMethod, userContext, history) { + var _this = this; + return React.useMemo( + function () { + return { + onSuccess: function () { + var redirectToPath = genericComponentOverrideContext.getRedirectToPathFromURL(); + var redirectInfo = + redirectToPath === undefined + ? undefined + : { + rid: "passwordless", + successRedirectContext: { + action: "SUCCESS", + isNewRecipeUser: false, + user: undefined, + redirectToPath: redirectToPath, + }, + }; + return recipe.Session.getInstanceOrThrow().validateGlobalClaimsAndHandleSuccessRedirection( + redirectInfo, + userContext, + history + ); + }, + onSignOutClicked: function () { + return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () { + return genericComponentOverrideContext.__generator(this, function (_a) { + switch (_a.label) { + case 0: + return [ + 4 /*yield*/, + recipe.Session.getInstanceOrThrow().signOut({ userContext: userContext }), + ]; + case 1: + _a.sent(); + return [ + 4 /*yield*/, + recipeImplementation.clearLoginAttemptInfo({ userContext: userContext }), + ]; + case 2: + _a.sent(); + return [ + 4 /*yield*/, + uiEntry.redirectToAuth({ redirectBack: false, history: history }), + ]; + case 3: + _a.sent(); + return [2 /*return*/]; + } + }); + }); + }, + onBackButtonClicked: function () { + // If we don't have history available this would mean we are not using react-router-dom, so we use window's history + if (history === undefined) { + return windowHandler.WindowHandlerReference.getReferenceOrThrow() + .windowHandler.getWindowUnsafe() + .history.back(); + } + // If we do have history and goBack function on it this means we are using react-router-dom v5 or lower + if (history.goBack !== undefined) { + return history.goBack(); + } + // If we reach this code this means we are using react-router-dom v6 + return history(-1); + }, + onFactorChooserButtonClicked: function () { + return recipe$2.MultiFactorAuth.getInstanceOrThrow().redirectToFactorChooser(false, history); + }, + recipeImplementation: recipeImplementation, + config: recipe$1.config, + contactMethod: contactMethod, + }; + }, + [contactMethod, state, recipeImplementation] + ); +} +var MFAFeature = function (props) { + var recipeComponentOverrides = props.useComponentOverrides(); + var userContext = uiEntry.useUserContext(); + var callingConsumeCodeRef = React.useRef(false); + var _a = useFeatureReducer$1(), + state = _a[0], + dispatch = _a[1]; + var recipeImplementation = React__namespace.useMemo( + function () { + return ( + props.recipe && + getModifiedRecipeImplementation$1( + props.recipe.webJSRecipe, + props.recipe.config, + dispatch, + callingConsumeCodeRef + ) + ); + }, + [props.recipe] + ); + useOnLoad(props, recipeImplementation, dispatch, userContext); + var childProps = useChildProps$1( + props.recipe, + recipeImplementation, + state, + props.contactMethod, + userContext, + props.history + ); + useSuccessInAnotherTabChecker$1(callingConsumeCodeRef, recipeImplementation, state, dispatch, userContext); + return jsxRuntime.jsx( + uiEntry.ComponentOverrideContext.Provider, + genericComponentOverrideContext.__assign( + { value: recipeComponentOverrides }, + { + children: jsxRuntime.jsx( + uiEntry.FeatureWrapper, + genericComponentOverrideContext.__assign( + { + useShadowDom: props.recipe.config.useShadowDom, + defaultStore: defaultTranslationsPasswordless, + }, + { + children: jsxRuntime.jsxs(React.Fragment, { + children: [ + props.children === undefined && + jsxRuntime.jsx( + MFAThemeWrapper, + genericComponentOverrideContext.__assign({}, childProps, { + featureState: state, + dispatch: dispatch, + }) + ), + props.children && + React__namespace.Children.map(props.children, function (child) { + if (React__namespace.isValidElement(child)) { + return React__namespace.cloneElement( + child, + genericComponentOverrideContext.__assign( + genericComponentOverrideContext.__assign({}, childProps), + { featureState: state, dispatch: dispatch } + ) + ); + } + return child; + }), + ], + }), + } + ) + ), + } + ) + ); +}; +function useOnLoad(props, recipeImplementation, dispatch, userContext) { + var _this = this; + var fetchMFAInfo = React__namespace.useCallback( + function () { + return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () { + return genericComponentOverrideContext.__generator(this, function (_a) { + return [ + 2 /*return*/, + recipe$2.MultiFactorAuth.getInstanceOrThrow().webJSRecipe.getMFAInfo({ + userContext: userContext, + }), + ]; + }); + }); + }, + [userContext] + ); + var handleLoadError = React__namespace.useCallback( + function () { + return dispatch({ type: "setError", error: "SOMETHING_WENT_WRONG_ERROR" }); + }, + [dispatch] + ); + var onLoad = React__namespace.useCallback( + function (mfaInfo) { + return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () { + var error, + errorQueryParam, + doSetup, + loginAttemptInfo, + isAlreadySetup, + isAllowedToSetup, + createCodeInfo, + factorId; + return genericComponentOverrideContext.__generator(this, function (_a) { + switch (_a.label) { + case 0: + error = undefined; + errorQueryParam = genericComponentOverrideContext.getQueryParams("error"); + doSetup = genericComponentOverrideContext.getQueryParams("setup"); + if (errorQueryParam !== null) { + error = "SOMETHING_WENT_WRONG_ERROR"; + } + return [ + 4 /*yield*/, + recipeImplementation.getLoginAttemptInfo({ + userContext: userContext, + }), + ]; + case 1: + loginAttemptInfo = _a.sent(); + isAlreadySetup = + props.contactMethod === "EMAIL" + ? mfaInfo.factors.isAlreadySetup.includes("otp-email") + : mfaInfo.factors.isAlreadySetup.includes("otp-phone"); + isAllowedToSetup = + props.contactMethod === "EMAIL" + ? mfaInfo.factors.isAllowedToSetup.includes("otp-email") + : mfaInfo.factors.isAllowedToSetup.includes("otp-phone"); + if (!!loginAttemptInfo) return [3 /*break*/, 8]; + createCodeInfo = + props.contactMethod === "EMAIL" + ? { email: mfaInfo.email } + : { phoneNumber: mfaInfo.phoneNumber }; + factorId = props.contactMethod === "EMAIL" ? "otp-email" : "otp-phone"; + if (!(isAlreadySetup && doSetup !== "true")) return [3 /*break*/, 6]; + _a.label = 2; + case 2: + _a.trys.push([2, 4, , 5]); + // createCode also dispatches the necessary events + return [ + 4 /*yield*/, + recipeImplementation.createCode( genericComponentOverrideContext.__assign( - { "data-supertokens": "primaryText sendCodeText" }, - { - children: [ - props.loginAttemptInfo.contactMethod === "EMAIL" - ? t("PWLESS_LINK_SENT_RESEND_DESC_START_EMAIL") - : t("PWLESS_LINK_SENT_RESEND_DESC_START_PHONE"), - jsxRuntime.jsx("strong", { - children: props.loginAttemptInfo.contactInfo, - }), - props.loginAttemptInfo.contactMethod === "EMAIL" - ? t("PWLESS_LINK_SENT_RESEND_DESC_END_EMAIL") - : t("PWLESS_LINK_SENT_RESEND_DESC_END_PHONE"), - ], - } + genericComponentOverrideContext.__assign({}, createCodeInfo), + { userContext: userContext } ) ), - jsxRuntime.jsx(ResendButton, { - loginAttemptInfo: props.loginAttemptInfo, - resendEmailOrSMSGapInSeconds: - props.config.signInUpFeature.resendEmailOrSMSGapInSeconds, - onClick: resendEmail, - }), - jsxRuntime.jsxs( - "div", - genericComponentOverrideContext.__assign( - { - "data-supertokens": "secondaryText secondaryLinkWithLeftArrow", - onClick: function () { - return props.recipeImplementation.clearLoginAttemptInfo({ - userContext: userContext, - }); - }, - }, - { - children: [ - jsxRuntime.jsx(arrowLeftIcon.ArrowLeftIcon, { - color: "rgb(var(--palette-textPrimary))", - }), - props.loginAttemptInfo.contactMethod === "EMAIL" - ? t("PWLESS_SIGN_IN_UP_CHANGE_CONTACT_INFO_EMAIL") - : t("PWLESS_SIGN_IN_UP_CHANGE_CONTACT_INFO_PHONE"), - ], + ]; + case 3: + // createCode also dispatches the necessary events + _a.sent(); + return [3 /*break*/, 5]; + case 4: + _a.sent(); + dispatch({ type: "setError", error: "SOMETHING_WENT_WRONG_ERROR" }); + return [3 /*break*/, 5]; + case 5: + return [3 /*break*/, 7]; + case 6: + if (!mfaInfo.factors.isAllowedToSetup.includes(factorId)) { + dispatch({ + type: "load", + loginAttemptInfo: undefined, + isAllowedToSetup: false, + error: "PWLESS_MFA_OTP_NOT_ALLOWED_TO_SETUP", + }); + } else { + // since loginAttemptInfo is undefined, this will ask the user for the email/phone + dispatch({ + type: "load", + loginAttemptInfo: loginAttemptInfo, + error: error, + isAllowedToSetup: true, + }); + } + _a.label = 7; + case 7: + return [3 /*break*/, 9]; + case 8: + // No need to check if the component is unmounting, since this has no effect then. + dispatch({ + type: "load", + loginAttemptInfo: loginAttemptInfo, + error: error, + isAllowedToSetup: isAllowedToSetup, + }); + _a.label = 9; + case 9: + return [2 /*return*/]; + } + }); + }); + }, + [dispatch, recipeImplementation, props.contactMethod, userContext] + ); + genericComponentOverrideContext.useOnMountAPICall(fetchMFAInfo, onLoad, handleLoadError); +} +function getModifiedRecipeImplementation$1(originalImpl, config, dispatch, callingConsumeCodeRef) { + var _this = this; + return genericComponentOverrideContext.__assign(genericComponentOverrideContext.__assign({}, originalImpl), { + createCode: function (input) { + return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () { + var contactInfo, phoneNumberUtils, contactMethod, additionalAttemptInfo, res, loginAttemptInfo; + return genericComponentOverrideContext.__generator(this, function (_a) { + switch (_a.label) { + case 0: + return [4 /*yield*/, recipe$1.getPhoneNumberUtils()]; + case 1: + phoneNumberUtils = _a.sent(); + if ("email" in input) { + contactInfo = input.email; + } else { + contactInfo = phoneNumberUtils.formatNumber( + input.phoneNumber, + config.signInUpFeature.defaultCountry || "", + phoneNumberUtils.numberFormat.E164 + ); + } + contactMethod = "email" in input ? "EMAIL" : "PHONE"; + additionalAttemptInfo = { + lastResend: Date.now(), + contactMethod: contactMethod, + contactInfo: contactInfo, + redirectToPath: genericComponentOverrideContext.getRedirectToPathFromURL(), + }; + return [ + 4 /*yield*/, + originalImpl.createCode( + genericComponentOverrideContext.__assign( + genericComponentOverrideContext.__assign({}, input), + { + userContext: genericComponentOverrideContext.__assign( + genericComponentOverrideContext.__assign({}, input.userContext), + { additionalAttemptInfo: additionalAttemptInfo } + ), } ) ), - ], + ]; + case 2: + res = _a.sent(); + if (!(res.status === "OK")) return [3 /*break*/, 4]; + return [ + 4 /*yield*/, + originalImpl.getLoginAttemptInfo({ + userContext: input.userContext, + }), + ]; + case 3: + loginAttemptInfo = _a.sent(); + dispatch({ type: "startVerify", loginAttemptInfo: loginAttemptInfo }); + _a.label = 4; + case 4: + return [2 /*return*/, res]; + } + }); + }); + }, + resendCode: function (input) { + return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () { + var res, loginAttemptInfo, timestamp; + return genericComponentOverrideContext.__generator(this, function (_a) { + switch (_a.label) { + case 0: + return [4 /*yield*/, originalImpl.resendCode(input)]; + case 1: + res = _a.sent(); + if (!(res.status === "OK")) return [3 /*break*/, 5]; + return [ + 4 /*yield*/, + originalImpl.getLoginAttemptInfo({ + userContext: input.userContext, + }), + ]; + case 2: + loginAttemptInfo = _a.sent(); + if (!(loginAttemptInfo !== undefined)) return [3 /*break*/, 4]; + timestamp = Date.now(); + return [ + 4 /*yield*/, + originalImpl.setLoginAttemptInfo({ + userContext: input.userContext, + attemptInfo: genericComponentOverrideContext.__assign( + genericComponentOverrideContext.__assign({}, loginAttemptInfo), + { lastResend: timestamp } + ), + }), + ]; + case 3: + _a.sent(); + dispatch({ type: "resendCode", timestamp: timestamp }); + _a.label = 4; + case 4: + return [3 /*break*/, 7]; + case 5: + if (!(res.status === "RESTART_FLOW_ERROR")) return [3 /*break*/, 7]; + return [ + 4 /*yield*/, + originalImpl.clearLoginAttemptInfo({ + userContext: input.userContext, + }), + ]; + case 6: + _a.sent(); + dispatch({ type: "restartFlow", error: "ERROR_SIGN_IN_UP_RESEND_RESTART_FLOW" }); + _a.label = 7; + case 7: + return [2 /*return*/, res]; + } + }); + }); + }, + consumeCode: function (input) { + return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () { + var res; + return genericComponentOverrideContext.__generator(this, function (_a) { + switch (_a.label) { + case 0: + // We need to set call callingConsumeCodeRef to true while consumeCode is running, + // so we don't detect the login attempt disappearing too early and + // go to successInAnotherTab too early + callingConsumeCodeRef.current = true; + return [4 /*yield*/, originalImpl.consumeCode(input)]; + case 1: + res = _a.sent(); + if (!(res.status === "RESTART_FLOW_ERROR")) return [3 /*break*/, 3]; + return [ + 4 /*yield*/, + originalImpl.clearLoginAttemptInfo({ + userContext: input.userContext, + }), + ]; + case 2: + _a.sent(); + dispatch({ type: "restartFlow", error: "ERROR_SIGN_IN_UP_CODE_CONSUME_RESTART_FLOW" }); + return [3 /*break*/, 7]; + case 3: + if (!(res.status === "SIGN_IN_UP_NOT_ALLOWED")) return [3 /*break*/, 5]; + // This should never happen, but technically possible based on the API specs + // so we keep this here to cover all cases + return [ + 4 /*yield*/, + originalImpl.clearLoginAttemptInfo({ + userContext: input.userContext, + }), + ]; + case 4: + // This should never happen, but technically possible based on the API specs + // so we keep this here to cover all cases + _a.sent(); + dispatch({ type: "restartFlow", error: res.reason }); + return [3 /*break*/, 7]; + case 5: + if (!(res.status === "OK")) return [3 /*break*/, 7]; + return [ + 4 /*yield*/, + originalImpl.clearLoginAttemptInfo({ + userContext: input.userContext, + }), + ]; + case 6: + _a.sent(); + _a.label = 7; + case 7: + callingConsumeCodeRef.current = false; + return [2 /*return*/, res]; + } + }); + }); + }, + clearLoginAttemptInfo: function (input) { + return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () { + return genericComponentOverrideContext.__generator(this, function (_a) { + switch (_a.label) { + case 0: + return [ + 4 /*yield*/, + originalImpl.clearLoginAttemptInfo({ + userContext: input.userContext, + }), + ]; + case 1: + _a.sent(); + genericComponentOverrideContext.clearErrorQueryParam(); + dispatch({ type: "restartFlow", error: undefined }); + return [2 /*return*/]; + } + }); + }); + }, + }); +} + +var EmailOrPhoneForm = uiEntry.withOverride( + "PasswordlessEmailOrPhoneForm", + function PasswordlessEmailOrPhoneForm(props) { + var _this = this; + var _a; + var _b = React.useState(false), + isPhoneNumber = _b[0], + setIsPhoneNumber = _b[1]; + var userContext = uiEntry.useUserContext(); + React.useEffect(function () { + // We preload this here, since it will be used almost for sure, but loading it + void recipe$1.preloadPhoneNumberUtils(); + }, []); + var emailOrPhoneInput = React.useMemo( + function () { + return isPhoneNumber + ? phoneNumberInputWithInjectedProps({ + defaultCountry: props.config.signInUpFeature.defaultCountry, + }) + : undefined; + }, + [props.config.signInUpFeature.defaultCountry, isPhoneNumber] + ); + return jsxRuntime.jsx(formBase.FormBase, { + clearError: props.clearError, + onError: props.onError, + formFields: [ + { + id: "emailOrPhone", + label: "PWLESS_SIGN_IN_UP_EMAIL_OR_PHONE_LABEL", + inputComponent: emailOrPhoneInput, + optional: false, + autofocus: true, + placeholder: "", + // We do not add an autocomplete prop in this case, since we do not really have any sensible option to set + // Setting them to either "tel" or "email" would give people the wrong impression since this could have either + // AFAIK we can't set them both at the same time + validate: recipe$1.defaultValidate, + }, + ], + buttonLabel: "PWLESS_SIGN_IN_UP_CONTINUE_BUTTON", + onSuccess: props.onSuccess, + callAPI: function (formFields, setValue) { + return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () { + var emailOrPhone, + emailValidationRes, + response, + phoneValidationRes, + response, + intPhoneNumber, + phoneValidationResAfterGuess, + response, + ex_1; + var _a; + return genericComponentOverrideContext.__generator(this, function (_b) { + switch (_b.label) { + case 0: + emailOrPhone = + (_a = formFields.find(function (field) { + return field.id === "emailOrPhone"; + })) === null || _a === void 0 + ? void 0 + : _a.value; + if (emailOrPhone === undefined) { + throw new STGeneralError__default.default("GENERAL_ERROR_EMAIL_OR_PHONE_UNDEFINED"); + } + return [4 /*yield*/, recipe$1.defaultEmailValidator(emailOrPhone)]; + case 1: + if (!(_b.sent() === undefined)) return [3 /*break*/, 6]; + return [4 /*yield*/, props.config.validateEmailAddress(emailOrPhone)]; + case 2: + emailValidationRes = _b.sent(); + if (!(emailValidationRes === undefined)) return [3 /*break*/, 4]; + return [ + 4 /*yield*/, + props.recipeImplementation.createCode({ + email: emailOrPhone, + userContext: userContext, + }), + ]; + case 3: + response = _b.sent(); + if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { + throw new STGeneralError__default.default(response.reason); + } + return [2 /*return*/, response]; + case 4: + throw new STGeneralError__default.default(emailValidationRes); + case 5: + return [3 /*break*/, 19]; + case 6: + return [4 /*yield*/, props.config.validatePhoneNumber(emailOrPhone)]; + case 7: + phoneValidationRes = _b.sent(); + if (!(phoneValidationRes === undefined)) return [3 /*break*/, 9]; + return [ + 4 /*yield*/, + props.recipeImplementation.createCode({ + phoneNumber: emailOrPhone, + userContext: userContext, + }), + ]; + case 8: + response = _b.sent(); + if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { + throw new STGeneralError__default.default(response.reason); + } + return [2 /*return*/, response]; + case 9: + return [ + 4 /*yield*/, + props.config.signInUpFeature.guessInternationPhoneNumberFromInputPhoneNumber( + emailOrPhone, + props.config.signInUpFeature.defaultCountry + ), + ]; + case 10: + intPhoneNumber = _b.sent(); + if (!(intPhoneNumber && isPhoneNumber !== true)) return [3 /*break*/, 18]; + return [4 /*yield*/, props.config.validatePhoneNumber(intPhoneNumber)]; + case 11: + phoneValidationResAfterGuess = _b.sent(); + if (!(phoneValidationResAfterGuess === undefined)) return [3 /*break*/, 16]; + _b.label = 12; + case 12: + _b.trys.push([12, 14, , 15]); + return [ + 4 /*yield*/, + props.recipeImplementation.createCode({ + phoneNumber: intPhoneNumber, + userContext: userContext, + }), + ]; + case 13: + response = _b.sent(); + if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { + throw new STGeneralError__default.default(response.reason); + } + return [2 /*return*/, response]; + case 14: + ex_1 = _b.sent(); + // General errors from the API can make createCode throw but we want to switch to the phone UI anyway + setValue("emailOrPhone", intPhoneNumber); + setIsPhoneNumber(true); + throw ex_1; + case 15: + return [3 /*break*/, 17]; + case 16: + // In this case we could get a phonenumber but not a completely valid one + // We want to switch to the phone UI and pre-fill the number + setValue("emailOrPhone", intPhoneNumber); + setIsPhoneNumber(true); + throw new STGeneralError__default.default( + "PWLESS_EMAIL_OR_PHONE_INVALID_INPUT_GUESS_PHONE_ERR" + ); + case 17: + return [3 /*break*/, 19]; + case 18: + throw new STGeneralError__default.default(phoneValidationRes); + case 19: + return [2 /*return*/]; + } + }); + }); + }, + validateOnBlur: false, + showLabels: true, + footer: + (_a = props.footer) !== null && _a !== void 0 + ? _a + : jsxRuntime.jsx(SignInUpFooter, { + privacyPolicyLink: props.config.signInUpFeature.privacyPolicyLink, + termsOfServiceLink: props.config.signInUpFeature.termsOfServiceLink, + }), + }); + } +); + +/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http="//www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Imports. + */ +/* + * Component. + */ +function SMSLargeIcon() { + return jsxRuntime.jsx( + "svg", + genericComponentOverrideContext.__assign( + { xmlns: "http://www.w3.org/2000/svg", width: "52.013", height: "41.889", viewBox: "0 0 52.013 41.889" }, + { + children: jsxRuntime.jsx( + "g", + genericComponentOverrideContext.__assign( + { id: "Group_10400", "data-name": "Group 10400", transform: "translate(-724.625 -241.125)" }, + { + children: jsxRuntime.jsxs( + "g", + genericComponentOverrideContext.__assign( + { id: "Group_10399", "data-name": "Group 10399" }, + { + children: [ + jsxRuntime.jsxs( + "g", + genericComponentOverrideContext.__assign( + { id: "Group_10398", "data-name": "Group 10398" }, + { + children: [ + jsxRuntime.jsxs( + "g", + genericComponentOverrideContext.__assign( + { + id: "_2639922_sms_icon", + "data-name": "2639922_sms_icon", + transform: "translate(732.916 242)", + }, + { + children: [ + jsxRuntime.jsx("path", { + id: "Union_52", + "data-name": "Union 52", + d: "M7.124 37.96a6.26 6.26 0 0 0 3.652-5H6.593A6.592 6.592 0 0 1 0 26.367V6.592A6.592 6.592 0 0 1 6.593 0h29.664a6.592 6.592 0 0 1 6.593 6.592v19.775a6.592 6.592 0 0 1-6.593 6.592h-17.68a13.355 13.355 0 0 1-11.159 6.576zm20.893-21.48a3.3 3.3 0 1 0 3.3-3.3 3.3 3.3 0 0 0-3.3 3.3zm-9.887 0a3.3 3.3 0 1 0 3.3-3.3 3.295 3.295 0 0 0-3.3 3.3zm-9.888 0a3.3 3.3 0 1 0 3.3-3.3 3.3 3.3 0 0 0-3.301 3.3z", + transform: "translate(-.001)", + strokeWidth: "1.75px", + stroke: "#000", + fill: "#c4f3ff", + }), + jsxRuntime.jsx("ellipse", { + id: "Ellipse_3013", + "data-name": "Ellipse 3013", + cy: ".917", + ry: ".917", + transform: "translate(7.335 38.506)", + stroke: "#000", + fill: "#c4f3ff", + }), + ], + } + ) + ), + jsxRuntime.jsx("path", { + id: "Intersection_2", + "data-name": "Intersection 2", + fill: "#8ae7ff", + d: "M177.409-21836.576v-.33l-.214-1.131a6.271 6.271 0 0 0 3.651-5h-4.184a6.59 6.59 0 0 1-6.512-5.588h42.495a7.846 7.846 0 0 1-1.607 3.605 6.576 6.576 0 0 1-4.712 1.982h-14.845c-1.545-.09-2.537-.164-2.537-.164l-.077.164h-.219a13.342 13.342 0 0 1-11.156 6.572l-.082-.439z", + transform: "translate(562.766 22118)", + }), + jsxRuntime.jsx("path", { + id: "Intersection_1", + "data-name": "Intersection 1", + fill: "#8ae7ff", + d: "M209.246-21846.41s.494-22.641 0-25.178a8.7 8.7 0 0 0-2.767-4.41 6.6 6.6 0 0 1 6.369 6.59v19.775a6.6 6.6 0 0 1-5.724 6.537 6.213 6.213 0 0 0 2.122-3.314z", + transform: "translate(561.882 22118.172)", + }), + ], + } + ) + ), + jsxRuntime.jsxs( + "g", + genericComponentOverrideContext.__assign( + { + id: "_2639922_sms_icon-2", + "data-name": "2639922_sms_icon", + transform: "translate(732.916 242.174)", + }, + { + children: [ + jsxRuntime.jsx("path", { + id: "Union_52-2", + "data-name": "Union 52", + d: "M7.124 37.96a6.26 6.26 0 0 0 3.652-5H6.593A6.592 6.592 0 0 1 0 26.367V6.592A6.592 6.592 0 0 1 6.593 0h29.664a6.592 6.592 0 0 1 6.593 6.592v19.775a6.592 6.592 0 0 1-6.593 6.592h-17.68a13.355 13.355 0 0 1-11.159 6.576zm20.893-21.48a3.3 3.3 0 1 0 3.3-3.3 3.3 3.3 0 0 0-3.3 3.3zm-9.887 0a3.3 3.3 0 1 0 3.3-3.3 3.295 3.295 0 0 0-3.3 3.3zm-9.888 0a3.3 3.3 0 1 0 3.3-3.3 3.3 3.3 0 0 0-3.301 3.3z", + transform: "translate(-.001)", + fill: "none", + strokeWidth: "1.75px", + stroke: "#000", + }), + jsxRuntime.jsx("ellipse", { + id: "Ellipse_3013-2", + "data-name": "Ellipse 3013", + cy: ".917", + ry: ".917", + transform: "translate(7.335 38.506)", + fill: "none", + stroke: "#000", + }), + ], + } + ) + ), + jsxRuntime.jsxs( + "g", + genericComponentOverrideContext.__assign( + { id: "Group_10397", "data-name": "Group 10397" }, + { + children: [ + jsxRuntime.jsx("path", { + id: "Line_104", + "data-name": "Line 104", + strokeWidth: "1.75px", + fill: "none", + strokeLinecap: "round", + stroke: "#000", + transform: "translate(725.5 266.84)", + d: "M0 0h9.872", + }), + jsxRuntime.jsx("path", { + id: "Line_105", + "data-name": "Line 105", + strokeWidth: "1.75px", + fill: "none", + strokeLinecap: "round", + stroke: "#fff", + transform: "translate(725.5 268.59)", + d: "M0 0h9.872", + }), + ], + } + ) + ), + jsxRuntime.jsxs( + "g", + genericComponentOverrideContext.__assign( + { id: "Group_10396", "data-name": "Group 10396" }, + { + children: [ + jsxRuntime.jsx("path", { + id: "Line_103", + "data-name": "Line 103", + strokeWidth: "1.75px", + fill: "none", + strokeLinecap: "round", + stroke: "#000", + transform: "translate(725.5 260.17)", + d: "M0 0h12.461", + }), + jsxRuntime.jsx("path", { + id: "Line_102", + "data-name": "Line 102", + strokeWidth: "1.75px", + fill: "none", + strokeLinecap: "round", + stroke: "#fff", + transform: "translate(725.5 261.92)", + d: "M0 0h12.461", + }), + ], + } + ) + ), + jsxRuntime.jsx("path", { + id: "Path_91918", + "data-name": "Path 91918", + fill: "#8ae7ff", + d: "M599.827 22145.373a1.62 1.62 0 0 0 1.38-1.336c.247-1.234.267 1.752.267 1.752l-1.647-.178z", + transform: "translate(170 -21876)", + }), + jsxRuntime.jsxs( + "g", + genericComponentOverrideContext.__assign( + { id: "Group_10395", "data-name": "Group 10395" }, + { + children: [ + jsxRuntime.jsx("path", { + id: "Line_100", + "data-name": "Line 100", + strokeWidth: "1.75px", + fill: "none", + strokeLinecap: "round", + stroke: "#000", + transform: "translate(725.5 253.5)", + d: "M0 0h9.872", + }), + jsxRuntime.jsx("path", { + id: "Line_101", + "data-name": "Line 101", + strokeWidth: "1.75px", + fill: "none", + strokeLinecap: "round", + stroke: "#fff", + transform: "translate(725.5 255.25)", + d: "M0 0h9.872", + }), + ], + } + ) + ), + ], + } + ) + ), } ) ), } ) ); -}; -var LinkSent = uiEntry.withOverride("PasswordlessLinkSent", PasswordlessLinkSent); +} -var PhoneForm = uiEntry.withOverride("PasswordlessPhoneForm", function PasswordlessPhoneForm(props) { - var _this = this; +var PasswordlessLinkSent = function (props) { + var t = translationContext.useTranslation(); var userContext = uiEntry.useUserContext(); + var _a = React.useState(props.error !== undefined ? "ERROR" : "READY"), + status = _a[0], + setStatus = _a[1]; + // Any because node types are included here, messing with return type of setTimeout + var resendNotifTimeout = React.useRef(); React.useEffect(function () { - // We preload this here, since it will be used almost for sure, but loading it - void recipe$1.preloadPhoneNumberUtils(); + return function () { + // This can safely run even if it was cleared before + if (resendNotifTimeout.current) { + clearTimeout(resendNotifTimeout.current); + } + }; }, []); - var phoneInput = React.useMemo( + var resendEmail = React.useCallback( function () { - return phoneNumberInputWithInjectedProps({ - defaultCountry: props.config.signInUpFeature.defaultCountry, - }); - }, - [props.config.signInUpFeature.defaultCountry] - ); - return jsxRuntime.jsx(formBase.FormBase, { - clearError: props.clearError, - onError: props.onError, - formFields: [ - { - id: "phoneNumber", - label: "PWLESS_SIGN_IN_UP_PHONE_LABEL", - inputComponent: phoneInput, - optional: false, - autofocus: true, - placeholder: "", - autoComplete: "tel", - validate: validators.defaultValidate, - }, - ], - buttonLabel: "PWLESS_SIGN_IN_UP_CONTINUE_BUTTON", - onSuccess: props.onSuccess, - callAPI: function (formFields) { - return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () { - var phoneNumber, validationRes, response; - var _a; - return genericComponentOverrideContext.__generator(this, function (_b) { - switch (_b.label) { - case 0: - phoneNumber = - (_a = formFields.find(function (field) { - return field.id === "phoneNumber"; - })) === null || _a === void 0 - ? void 0 - : _a.value; - if (phoneNumber === undefined) { - throw new STGeneralError__default.default("GENERAL_ERROR_PHONE_UNDEFINED"); - } - return [4 /*yield*/, props.config.validatePhoneNumber(phoneNumber)]; - case 1: - validationRes = _b.sent(); - if (validationRes !== undefined) { - throw new STGeneralError__default.default(validationRes); - } - return [ - 4 /*yield*/, - props.recipeImplementation.createCode({ - phoneNumber: phoneNumber, - userContext: userContext, - }), - ]; - case 2: - response = _b.sent(); - if (response.status === "SIGN_IN_UP_NOT_ALLOWED") { - throw new STGeneralError__default.default(response.reason); - } - return [2 /*return*/, response]; - } - }); - }); - }, - validateOnBlur: false, - showLabels: true, - footer: jsxRuntime.jsx(SignInUpFooter, { - privacyPolicyLink: props.config.signInUpFeature.privacyPolicyLink, - termsOfServiceLink: props.config.signInUpFeature.termsOfServiceLink, - }), - }); -}); - -var SignInUpHeader = uiEntry.withOverride("PasswordlessSignInUpHeader", function PasswordlessSignInUpHeader() { - var t = translationContext.useTranslation(); - return jsxRuntime.jsxs(React.Fragment, { - children: [ - jsxRuntime.jsx( - "div", - genericComponentOverrideContext.__assign( - { "data-supertokens": "headerTitle" }, - { children: t("PWLESS_SIGN_IN_UP_HEADER_TITLE") } - ) - ), - jsxRuntime.jsx("div", { "data-supertokens": "divider" }), - ], - }); -}); - -var UserInputCodeFormFooter = uiEntry.withOverride( - "PasswordlessUserInputCodeFormFooter", - function PasswordlessUserInputCodeFormFooter(_a) { - var loginAttemptInfo = _a.loginAttemptInfo, - recipeImplementation = _a.recipeImplementation; - var t = translationContext.useTranslation(); - var userContext = uiEntry.useUserContext(); - return jsxRuntime.jsx(React.Fragment, { - children: jsxRuntime.jsxs( - "div", - genericComponentOverrideContext.__assign( - { - "data-supertokens": "secondaryText secondaryLinkWithLeftArrow", - onClick: function () { - return recipeImplementation.clearLoginAttemptInfo({ - userContext: userContext, - }); - }, - }, - { - children: [ - jsxRuntime.jsx(arrowLeftIcon.ArrowLeftIcon, { color: "rgb(var(--palette-textPrimary))" }), - loginAttemptInfo.contactMethod === "EMAIL" - ? t("PWLESS_SIGN_IN_UP_CHANGE_CONTACT_INFO_EMAIL") - : t("PWLESS_SIGN_IN_UP_CHANGE_CONTACT_INFO_PHONE"), - ], - } - ) - ), - }); - } -); - -var UserInputCodeForm = uiEntry.withOverride( - "PasswordlessUserInputCodeForm", - function PasswordlessUserInputCodeForm(props) { - var _this = this; - var t = translationContext.useTranslation(); - var userContext = uiEntry.useUserContext(); - // We need this any because the node types are also loaded - var _a = React.useState(), - clearResendNotifTimeout = _a[0], - setClearResendNotifTimeout = _a[1]; - React.useEffect( - function () { - // This is just to clean up on unmount and if the clear timeout changes - return function () { - clearTimeout(clearResendNotifTimeout); - }; - }, - [clearResendNotifTimeout] - ); - function resend() { - return genericComponentOverrideContext.__awaiter(this, void 0, void 0, function () { + return genericComponentOverrideContext.__awaiter(void 0, void 0, void 0, function () { var response, generalError, e_1; return genericComponentOverrideContext.__generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 5, , 6]); + props.clearError(); response = void 0; generalError = void 0; _a.label = 1; @@ -3560,141 +4560,149 @@ var UserInputCodeForm = uiEntry.withOverride( } return [3 /*break*/, 4]; case 4: - if (generalError !== undefined) { - props.onError(generalError.message); + if (response !== undefined && response.status === "OK") { + setStatus("LINK_RESENT"); + resendNotifTimeout.current = setTimeout(function () { + setStatus(function (status) { + return status === "LINK_RESENT" ? "READY" : status; + }); + resendNotifTimeout.current = undefined; + }, 2000); } else { - if (response === undefined) { - throw new Error("Should not come here"); - } - if (response.status === "OK") { - setClearResendNotifTimeout( - setTimeout(function () { - setClearResendNotifTimeout(undefined); - }, 2000) - ); + setStatus("ERROR"); + if (generalError !== undefined) { + props.onError(generalError.message); } } return [3 /*break*/, 6]; case 5: _a.sent(); - props.onError("SOMETHING_WENT_WRONG_ERROR"); + setStatus("ERROR"); return [3 /*break*/, 6]; case 6: return [2 /*return*/]; } }); }); - } - return jsxRuntime.jsxs(React__namespace.default.Fragment, { - children: [ - clearResendNotifTimeout !== undefined && - jsxRuntime.jsx( - "div", - genericComponentOverrideContext.__assign( - { "data-supertokens": "generalSuccess" }, - { - children: - props.loginAttemptInfo.contactMethod === "EMAIL" - ? t("PWLESS_RESEND_SUCCESS_EMAIL") - : t("PWLESS_RESEND_SUCCESS_PHONE"), - } - ) - ), - jsxRuntime.jsx(formBase.FormBase, { - clearError: props.clearError, - onError: props.onError, - formFields: [ + }, + [props.recipeImplementation, props.loginAttemptInfo, props.config, setStatus] + ); + var resendActive = status === "LINK_RESENT"; + return jsxRuntime.jsx( + "div", + genericComponentOverrideContext.__assign( + { "data-supertokens": "container" }, + { + children: jsxRuntime.jsxs( + "div", + genericComponentOverrideContext.__assign( + { "data-supertokens": "row" }, { - id: "userInputCode", - label: "", - labelComponent: jsxRuntime.jsxs( - "div", - genericComponentOverrideContext.__assign( - { "data-supertokens": "codeInputLabelWrapper" }, - { - children: [ - jsxRuntime.jsx(formBase.Label, { - value: "PWLESS_USER_INPUT_CODE_INPUT_LABEL", - "data-supertokens": "codeInputLabel", - }), - jsxRuntime.jsx(ResendButton, { - loginAttemptInfo: props.loginAttemptInfo, - resendEmailOrSMSGapInSeconds: - props.config.signInUpFeature.resendEmailOrSMSGapInSeconds, - onClick: resend, - }), - ], - } - ) - ), - autofocus: true, - optional: false, - clearOnSubmit: true, - autoComplete: "one-time-code", - placeholder: "", - validate: recipe$1.userInputCodeValidate, - }, - ], - onSuccess: props.onSuccess, - buttonLabel: "PWLESS_SIGN_IN_UP_CONTINUE_BUTTON", - callAPI: function (formFields) { - return genericComponentOverrideContext.__awaiter(_this, void 0, void 0, function () { - var userInputCode, response; - var _a; - return genericComponentOverrideContext.__generator(this, function (_b) { - switch (_b.label) { - case 0: - userInputCode = - (_a = formFields.find(function (field) { - return field.id === "userInputCode"; - })) === null || _a === void 0 - ? void 0 - : _a.value; - if (userInputCode === undefined || userInputCode.length === 0) { - throw new STGeneralError__default.default("GENERAL_ERROR_OTP_UNDEFINED"); - } - return [ - 4 /*yield*/, - props.recipeImplementation.consumeCode({ - userInputCode: userInputCode, - userContext: userContext, - }), - ]; - case 1: - response = _b.sent(); - // We can redirect these statuses, since they all cause a redirection - // and we don't really want to show anything - if ( - response.status === "OK" || - response.status === "RESTART_FLOW_ERROR" || - response.status === "SIGN_IN_UP_NOT_ALLOWED" - ) { - return [2 /*return*/, response]; + children: [ + status === "ERROR" && + jsxRuntime.jsx(generalError.GeneralError, { + error: props.error === undefined ? "SOMETHING_WENT_WRONG_ERROR" : props.error, + }), + resendActive && + jsxRuntime.jsx( + "div", + genericComponentOverrideContext.__assign( + { "data-supertokens": "generalSuccess" }, + { children: t("PWLESS_LINK_SENT_RESEND_SUCCESS") } + ) + ), + jsxRuntime.jsx( + "div", + genericComponentOverrideContext.__assign( + { "data-supertokens": "sendCodeIcon" }, + { + children: + props.loginAttemptInfo.contactMethod === "EMAIL" + ? jsxRuntime.jsx(checkedRoundIcon.EmailLargeIcon, {}) + : jsxRuntime.jsx(SMSLargeIcon, {}), } - if (response.status === "INCORRECT_USER_INPUT_CODE_ERROR") { - throw new STGeneralError__default.default("GENERAL_ERROR_OTP_INVALID"); + ) + ), + jsxRuntime.jsx( + "div", + genericComponentOverrideContext.__assign( + { "data-supertokens": "headerTitle headerTinyTitle" }, + { children: t("PWLESS_LINK_SENT_RESEND_TITLE") } + ) + ), + jsxRuntime.jsxs( + "div", + genericComponentOverrideContext.__assign( + { "data-supertokens": "primaryText sendCodeText" }, + { + children: [ + props.loginAttemptInfo.contactMethod === "EMAIL" + ? t("PWLESS_LINK_SENT_RESEND_DESC_START_EMAIL") + : t("PWLESS_LINK_SENT_RESEND_DESC_START_PHONE"), + jsxRuntime.jsx("strong", { + children: props.loginAttemptInfo.contactInfo, + }), + props.loginAttemptInfo.contactMethod === "EMAIL" + ? t("PWLESS_LINK_SENT_RESEND_DESC_END_EMAIL") + : t("PWLESS_LINK_SENT_RESEND_DESC_END_PHONE"), + ], } - if (response.status === "EXPIRED_USER_INPUT_CODE_ERROR") { - throw new STGeneralError__default.default("GENERAL_ERROR_OTP_EXPIRED"); + ) + ), + jsxRuntime.jsx(ResendButton, { + loginAttemptInfo: props.loginAttemptInfo, + resendEmailOrSMSGapInSeconds: + props.config.signInUpFeature.resendEmailOrSMSGapInSeconds, + onClick: resendEmail, + }), + jsxRuntime.jsxs( + "div", + genericComponentOverrideContext.__assign( + { + "data-supertokens": "secondaryText secondaryLinkWithLeftArrow", + onClick: function () { + return props.recipeImplementation.clearLoginAttemptInfo({ + userContext: userContext, + }); + }, + }, + { + children: [ + jsxRuntime.jsx(arrowLeftIcon.ArrowLeftIcon, { + color: "rgb(var(--palette-textPrimary))", + }), + props.loginAttemptInfo.contactMethod === "EMAIL" + ? t("PWLESS_SIGN_IN_UP_CHANGE_CONTACT_INFO_EMAIL") + : t("PWLESS_SIGN_IN_UP_CHANGE_CONTACT_INFO_PHONE"), + ], } - throw new STGeneralError__default.default("SOMETHING_WENT_WRONG_ERROR"); - } - }); - }); - }, - validateOnBlur: false, - showLabels: true, - footer: jsxRuntime.jsx( - UserInputCodeFormFooter, - genericComponentOverrideContext.__assign({}, props, { - loginAttemptInfo: props.loginAttemptInfo, - }) - ), - }), - ], - }); - } -); + ) + ), + ], + } + ) + ), + } + ) + ); +}; +var LinkSent = uiEntry.withOverride("PasswordlessLinkSent", PasswordlessLinkSent); + +var SignInUpHeader = uiEntry.withOverride("PasswordlessSignInUpHeader", function PasswordlessSignInUpHeader() { + var t = translationContext.useTranslation(); + return jsxRuntime.jsxs(React.Fragment, { + children: [ + jsxRuntime.jsx( + "div", + genericComponentOverrideContext.__assign( + { "data-supertokens": "headerTitle" }, + { children: t("PWLESS_SIGN_IN_UP_HEADER_TITLE") } + ) + ), + jsxRuntime.jsx("div", { "data-supertokens": "divider" }), + ], + }); +}); var UserInputCodeFormHeader = uiEntry.withOverride( "PasswordlessUserInputCodeFormHeader", @@ -3831,7 +4839,8 @@ var SignInUpTheme = function (_a) { }; function SignInUpThemeWrapper(props) { var hasFont = translations.hasFontDefined(props.config.rootStyle); - var activeScreen = getActiveScreen(props); + var currentDynamicLoginMethods = uiEntry.useDynamicLoginMethods(); + var activeScreen = getActiveScreen(props, currentDynamicLoginMethods); var activeStyle; if (activeScreen === exports.SignInUpScreens.CloseTab) { activeStyle = props.config.signInUpFeature.closeTabScreenStyle; @@ -3867,19 +4876,23 @@ function SignInUpThemeWrapper(props) { ) ); } -function getActiveScreen(props) { +function getActiveScreen(props, currentDynamicLoginMethods) { + var enabledContactMethods = recipe$1.getEnabledContactMethods( + props.config.contactMethod, + currentDynamicLoginMethods + ); if (props.featureState.successInAnotherTab) { return exports.SignInUpScreens.CloseTab; } else if (props.featureState.loginAttemptInfo && props.featureState.loginAttemptInfo.flowType === "MAGIC_LINK") { return exports.SignInUpScreens.LinkSent; } else if (props.featureState.loginAttemptInfo) { return exports.SignInUpScreens.UserInputCodeForm; - } else if (props.config.contactMethod === "EMAIL") { + } else if (enabledContactMethods.length > 1) { + return exports.SignInUpScreens.EmailOrPhoneForm; + } else if (enabledContactMethods[0] === "EMAIL") { return exports.SignInUpScreens.EmailForm; - } else if (props.config.contactMethod === "PHONE") { + } else if (enabledContactMethods[0] === "PHONE") { return exports.SignInUpScreens.PhoneForm; - } else if (props.config.contactMethod === "EMAIL_OR_PHONE") { - return exports.SignInUpScreens.EmailOrPhoneForm; } throw new Error("Couldn't choose active screen; Should never happen"); } @@ -4370,6 +5383,32 @@ var PasswordlessPreBuiltUI = /** @class */ (function (_super) { recipeID: recipe$1.Passwordless.RECIPE_ID, }; } + if (_this.recipeInstance.config.mfaFeature.disableDefaultUI !== true) { + var normalisedFullPathPhone = _this.recipeInstance.config.appInfo.websiteBasePath.appendPath( + new NormalisedURLPath__default.default("/mfa/otp-phone") + ); + features[normalisedFullPathPhone.getAsStringDangerous()] = { + matches: genericComponentOverrideContext.matchRecipeIdUsingQueryParams( + _this.recipeInstance.config.recipeId + ), + component: function (props) { + return _this.getFeatureComponent("otp-phone", props, useComponentOverrides); + }, + recipeID: recipe$1.Passwordless.RECIPE_ID, + }; + var normalisedFullPathEmail = _this.recipeInstance.config.appInfo.websiteBasePath.appendPath( + new NormalisedURLPath__default.default("/mfa/otp-email") + ); + features[normalisedFullPathEmail.getAsStringDangerous()] = { + matches: genericComponentOverrideContext.matchRecipeIdUsingQueryParams( + _this.recipeInstance.config.recipeId + ), + component: function (props) { + return _this.getFeatureComponent("otp-email", props, useComponentOverrides); + }, + recipeID: recipe$1.Passwordless.RECIPE_ID, + }; + } return features; }; _this.getFeatureComponent = function (componentName, props, useComponentOverrides) { @@ -4437,9 +5476,76 @@ var PasswordlessPreBuiltUI = /** @class */ (function (_super) { } ) ); - } else { - throw new Error("Should never come here."); } + if (componentName === "otp-email") { + return jsxRuntime.jsx( + uiEntry.UserContextWrapper, + genericComponentOverrideContext.__assign( + { userContext: props.userContext }, + { + children: jsxRuntime.jsx( + session.SessionAuth, + genericComponentOverrideContext.__assign( + { + overrideGlobalClaimValidators: function () { + return []; + }, + }, + { + children: jsxRuntime.jsx( + MFAFeature, + genericComponentOverrideContext.__assign( + { + recipe: _this.recipeInstance, + useComponentOverrides: useComponentOverrides, + contactMethod: "EMAIL", + flowType: "USER_INPUT_CODE", + }, + props + ) + ), + } + ) + ), + } + ) + ); + } + if (componentName === "otp-phone") { + return jsxRuntime.jsx( + uiEntry.UserContextWrapper, + genericComponentOverrideContext.__assign( + { userContext: props.userContext }, + { + children: jsxRuntime.jsx( + session.SessionAuth, + genericComponentOverrideContext.__assign( + { + overrideGlobalClaimValidators: function () { + return []; + }, + }, + { + children: jsxRuntime.jsx( + MFAFeature, + genericComponentOverrideContext.__assign( + { + recipe: _this.recipeInstance, + useComponentOverrides: useComponentOverrides, + contactMethod: "PHONE", + flowType: "USER_INPUT_CODE", + }, + props + ) + ), + } + ) + ), + } + ) + ); + } + throw new Error("Should never come here."); }; return _this; } @@ -4486,17 +5592,27 @@ var PasswordlessPreBuiltUI = /** @class */ (function (_super) { PasswordlessPreBuiltUI.LinkClicked = function (prop) { return _a.getFeatureComponent("linkClickedScreen", prop); }; + PasswordlessPreBuiltUI.MfaOtpPhone = function (prop) { + return _a.getFeatureComponent("otp-phone", prop); + }; + PasswordlessPreBuiltUI.MfaOtpEmail = function (prop) { + return _a.getFeatureComponent("otp-email", prop); + }; PasswordlessPreBuiltUI.SignInUpTheme = SignInUpThemeWrapper; return PasswordlessPreBuiltUI; })(uiEntry.RecipeRouter); var SignInUp = PasswordlessPreBuiltUI.SignInUp; var LinkClicked = PasswordlessPreBuiltUI.LinkClicked; +var MfaOtpPhone = PasswordlessPreBuiltUI.MfaOtpPhone; +var MfaOtpEmail = PasswordlessPreBuiltUI.MfaOtpEmail; exports.CloseTabScreen = CloseTabScreen; exports.EmailForm = EmailForm; exports.EmailOrPhoneForm = EmailOrPhoneForm; exports.LinkClicked = LinkClicked; exports.LinkSent = LinkSent; +exports.MfaOtpEmail = MfaOtpEmail; +exports.MfaOtpPhone = MfaOtpPhone; exports.PasswordlessPreBuiltUI = PasswordlessPreBuiltUI; exports.PhoneForm = PhoneForm; exports.SignInUp = SignInUp; diff --git a/lib/build/passwordless.js b/lib/build/passwordless.js index f8cba3862..ce950e342 100644 --- a/lib/build/passwordless.js +++ b/lib/build/passwordless.js @@ -20,6 +20,9 @@ require("./authRecipe-shared.js"); require("./recipeModule-shared.js"); require("./session-shared2.js"); require("supertokens-web-js/recipe/session"); +require("./multifactorauth-shared.js"); +require("supertokens-web-js/recipe/multifactorauth"); +require("supertokens-web-js/utils/sessionClaimValidatorStore"); /* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. * diff --git a/lib/build/passwordlessprebuiltui.js b/lib/build/passwordlessprebuiltui.js index 68f6309d0..b360b58e7 100644 --- a/lib/build/passwordlessprebuiltui.js +++ b/lib/build/passwordlessprebuiltui.js @@ -5,6 +5,7 @@ require("react/jsx-runtime"); require("supertokens-web-js/utils/normalisedURLPath"); require("./index2.js"); require("./authRecipe-shared2.js"); +require("./session-shared.js"); require("./passwordless-shared.js"); var passwordlessprebuiltui = require("./passwordless-shared3.js"); require("./passwordless-shared2.js"); @@ -25,21 +26,25 @@ require("supertokens-web-js/utils/sessionClaimValidatorStore"); require("./recipeModule-shared.js"); require("./session-shared2.js"); require("supertokens-web-js/recipe/session"); -require("./session-shared.js"); require("./session-shared3.js"); require("supertokens-web-js/utils/error"); require("./translations.js"); require("./emailpassword-shared2.js"); require("./SuperTokensBranding.js"); require("./emailpassword-shared.js"); +require("./sessionprebuiltui.js"); +require("./arrowLeftIcon.js"); require("./checkedRoundIcon.js"); require("./emailpassword-shared8.js"); require("./emailpassword-shared5.js"); -require("./arrowLeftIcon.js"); +require("./multifactorauth-shared2.js"); +require("./emailpassword-shared7.js"); require("supertokens-web-js/recipe/passwordless"); require("./authRecipe-shared.js"); exports.LinkClicked = passwordlessprebuiltui.LinkClicked; +exports.MfaOtpEmail = passwordlessprebuiltui.MfaOtpEmail; +exports.MfaOtpPhone = passwordlessprebuiltui.MfaOtpPhone; exports.PasswordlessPreBuiltUI = passwordlessprebuiltui.PasswordlessPreBuiltUI; exports.SignInUp = passwordlessprebuiltui.SignInUp; exports.SignInUpTheme = passwordlessprebuiltui.SignInUpThemeWrapper; diff --git a/lib/build/recipe/emailpassword/components/themes/resetPasswordUsingToken/resetPasswordEmail.d.ts b/lib/build/recipe/emailpassword/components/themes/resetPasswordUsingToken/resetPasswordEmail.d.ts index 8ff8a9b05..bcc6e2b05 100644 --- a/lib/build/recipe/emailpassword/components/themes/resetPasswordUsingToken/resetPasswordEmail.d.ts +++ b/lib/build/recipe/emailpassword/components/themes/resetPasswordUsingToken/resetPasswordEmail.d.ts @@ -1,7 +1,7 @@ /// export declare const ResetPasswordEmail: import("react").ComponentType< import("../../../../../types").ThemeBaseProps & { - formFields: import("../../../types").FormFieldThemeProps[]; + formFields: Omit[]; error: string | undefined; } & { recipeImplementation: import("supertokens-web-js/recipe/emailpassword").RecipeInterface; diff --git a/lib/build/recipe/emailpassword/components/themes/resetPasswordUsingToken/submitNewPassword.d.ts b/lib/build/recipe/emailpassword/components/themes/resetPasswordUsingToken/submitNewPassword.d.ts index b8ec36fd7..9c795dce2 100644 --- a/lib/build/recipe/emailpassword/components/themes/resetPasswordUsingToken/submitNewPassword.d.ts +++ b/lib/build/recipe/emailpassword/components/themes/resetPasswordUsingToken/submitNewPassword.d.ts @@ -1,7 +1,7 @@ /// export declare const SubmitNewPassword: import("react").ComponentType< import("../../../../../types").ThemeBaseProps & { - formFields: import("../../../types").FormFieldThemeProps[]; + formFields: Omit[]; error: string | undefined; } & { recipeImplementation: import("supertokens-web-js/recipe/emailpassword").RecipeInterface; diff --git a/lib/build/recipe/emailpassword/components/themes/signInAndUp/signIn.d.ts b/lib/build/recipe/emailpassword/components/themes/signInAndUp/signIn.d.ts index 2b40c960b..64639bb96 100644 --- a/lib/build/recipe/emailpassword/components/themes/signInAndUp/signIn.d.ts +++ b/lib/build/recipe/emailpassword/components/themes/signInAndUp/signIn.d.ts @@ -1,7 +1,7 @@ /// export declare const SignIn: import("react").ComponentType< import("../../../../../types").ThemeBaseProps & { - formFields: import("../../../types").FormFieldThemeProps[]; + formFields: Omit[]; error: string | undefined; } & { recipeImplementation: import("supertokens-web-js/recipe/emailpassword").RecipeInterface; diff --git a/lib/build/recipe/emailpassword/components/themes/signInAndUp/signInForm.d.ts b/lib/build/recipe/emailpassword/components/themes/signInAndUp/signInForm.d.ts index 7dbc1321c..f57175ca5 100644 --- a/lib/build/recipe/emailpassword/components/themes/signInAndUp/signInForm.d.ts +++ b/lib/build/recipe/emailpassword/components/themes/signInAndUp/signInForm.d.ts @@ -1,7 +1,7 @@ /// export declare const SignInForm: import("react").ComponentType< import("../../../../../types").ThemeBaseProps & { - formFields: import("../../../types").FormFieldThemeProps[]; + formFields: Omit[]; error: string | undefined; } & { recipeImplementation: import("supertokens-web-js/recipe/emailpassword").RecipeInterface; diff --git a/lib/build/recipe/emailpassword/components/themes/signInAndUp/signUp.d.ts b/lib/build/recipe/emailpassword/components/themes/signInAndUp/signUp.d.ts index 380a6e333..32bc386b1 100644 --- a/lib/build/recipe/emailpassword/components/themes/signInAndUp/signUp.d.ts +++ b/lib/build/recipe/emailpassword/components/themes/signInAndUp/signUp.d.ts @@ -1,14 +1,13 @@ /// export declare const SignUp: import("react").ComponentType< import("../../../../../types").ThemeBaseProps & { - formFields: import("../../../types").FormFieldThemeProps[]; - error: string | undefined; - } & { recipeImplementation: import("supertokens-web-js/recipe/emailpassword").RecipeInterface; clearError: () => void; onError: (error: string) => void; config: import("../../../types").NormalisedConfig; signInClicked?: (() => void) | undefined; onSuccess: (result: { user: import("supertokens-web-js/types").User }) => void; + formFields: import("../../../types").FormFieldThemeProps[]; + error: string | undefined; } >; diff --git a/lib/build/recipe/emailpassword/components/themes/signInAndUp/signUpForm.d.ts b/lib/build/recipe/emailpassword/components/themes/signInAndUp/signUpForm.d.ts index bbe4a2eb2..85b7e4c8d 100644 --- a/lib/build/recipe/emailpassword/components/themes/signInAndUp/signUpForm.d.ts +++ b/lib/build/recipe/emailpassword/components/themes/signInAndUp/signUpForm.d.ts @@ -1,15 +1,14 @@ /// export declare const SignUpForm: import("react").ComponentType< import("../../../../../types").ThemeBaseProps & { - formFields: import("../../../types").FormFieldThemeProps[]; - error: string | undefined; - } & { recipeImplementation: import("supertokens-web-js/recipe/emailpassword").RecipeInterface; clearError: () => void; onError: (error: string) => void; config: import("../../../types").NormalisedConfig; signInClicked?: (() => void) | undefined; onSuccess: (result: { user: import("supertokens-web-js/types").User }) => void; + formFields: import("../../../types").FormFieldThemeProps[]; + error: string | undefined; } & { header?: JSX.Element | undefined; footer?: JSX.Element | undefined; diff --git a/lib/build/recipe/passwordless/components/features/mfa/index.d.ts b/lib/build/recipe/passwordless/components/features/mfa/index.d.ts new file mode 100644 index 000000000..2b32343e7 --- /dev/null +++ b/lib/build/recipe/passwordless/components/features/mfa/index.d.ts @@ -0,0 +1,32 @@ +import * as React from "react"; +import type { FeatureBaseProps } from "../../../../../types"; +import type Recipe from "../../../recipe"; +import type { ComponentOverrideMap, MFAChildProps } from "../../../types"; +import type { MFAAction, MFAState } from "../../../types"; +import type { RecipeInterface } from "supertokens-web-js/recipe/passwordless"; +import type { PasswordlessFlowType } from "supertokens-web-js/recipe/thirdpartypasswordless"; +export declare const useSuccessInAnotherTabChecker: ( + callingConsumeCodeRef: React.MutableRefObject, + recipeImpl: RecipeInterface, + state: MFAState, + dispatch: React.Dispatch, + userContext: any +) => void; +export declare const useFeatureReducer: () => [MFAState, React.Dispatch]; +export declare function useChildProps( + recipe: Recipe, + recipeImplementation: RecipeInterface, + state: MFAState, + contactMethod: "PHONE" | "EMAIL", + userContext: any, + history: any +): MFAChildProps; +export declare const MFAFeature: React.FC< + FeatureBaseProps & { + contactMethod: "PHONE" | "EMAIL"; + flowType: PasswordlessFlowType; + recipe: Recipe; + useComponentOverrides: () => ComponentOverrideMap; + } +>; +export default MFAFeature; diff --git a/lib/build/recipe/passwordless/components/themes/mfa/index.d.ts b/lib/build/recipe/passwordless/components/themes/mfa/index.d.ts new file mode 100644 index 000000000..bdc60d2d1 --- /dev/null +++ b/lib/build/recipe/passwordless/components/themes/mfa/index.d.ts @@ -0,0 +1,12 @@ +/// +import type { MFAProps } from "../../../types"; +export declare enum MFAScreens { + CloseTab = 0, + EmailForm = 1, + PhoneForm = 2, + UserInputCodeForm = 3, + AccessDenied = 4, +} +declare function MFAThemeWrapper(props: MFAProps): JSX.Element; +export default MFAThemeWrapper; +export declare function getActiveScreen(props: Pick): MFAScreens; diff --git a/lib/build/recipe/passwordless/components/themes/mfa/mfaFooter.d.ts b/lib/build/recipe/passwordless/components/themes/mfa/mfaFooter.d.ts new file mode 100644 index 000000000..400242689 --- /dev/null +++ b/lib/build/recipe/passwordless/components/themes/mfa/mfaFooter.d.ts @@ -0,0 +1,3 @@ +/// +import type { MFAFooterProps } from "../../../types"; +export declare const MFAFooter: import("react").ComponentType; diff --git a/lib/build/recipe/passwordless/components/themes/mfa/mfaHeader.d.ts b/lib/build/recipe/passwordless/components/themes/mfa/mfaHeader.d.ts new file mode 100644 index 000000000..20436f4ba --- /dev/null +++ b/lib/build/recipe/passwordless/components/themes/mfa/mfaHeader.d.ts @@ -0,0 +1,5 @@ +/// +export declare const MFAHeader: import("react").ComponentType<{ + contactMethod: "EMAIL" | "PHONE"; + onBackButtonClicked: () => void; +}>; diff --git a/lib/build/recipe/passwordless/components/themes/mfa/mfaOTPFooter.d.ts b/lib/build/recipe/passwordless/components/themes/mfa/mfaOTPFooter.d.ts new file mode 100644 index 000000000..f71b639fc --- /dev/null +++ b/lib/build/recipe/passwordless/components/themes/mfa/mfaOTPFooter.d.ts @@ -0,0 +1,3 @@ +/// +import type { MFAOTPFooterProps } from "../../../types"; +export declare const MFAOTPFooter: import("react").ComponentType; diff --git a/lib/build/recipe/passwordless/components/themes/mfa/mfaOTPHeader.d.ts b/lib/build/recipe/passwordless/components/themes/mfa/mfaOTPHeader.d.ts new file mode 100644 index 000000000..f95966180 --- /dev/null +++ b/lib/build/recipe/passwordless/components/themes/mfa/mfaOTPHeader.d.ts @@ -0,0 +1,3 @@ +/// +import type { MFAOTPHeaderProps } from "../../../types"; +export declare const MFAOTPHeader: import("react").ComponentType; diff --git a/lib/build/recipe/passwordless/components/themes/signInUp/emailForm.d.ts b/lib/build/recipe/passwordless/components/themes/signInUp/emailForm.d.ts index ecf6f7a4d..41ef958b1 100644 --- a/lib/build/recipe/passwordless/components/themes/signInUp/emailForm.d.ts +++ b/lib/build/recipe/passwordless/components/themes/signInUp/emailForm.d.ts @@ -1,3 +1,7 @@ /// import type { SignInUpEmailFormProps } from "../../../types"; -export declare const EmailForm: import("react").ComponentType; +export declare const EmailForm: import("react").ComponentType< + SignInUpEmailFormProps & { + footer?: JSX.Element | undefined; + } +>; diff --git a/lib/build/recipe/passwordless/components/themes/signInUp/emailOrPhoneForm.d.ts b/lib/build/recipe/passwordless/components/themes/signInUp/emailOrPhoneForm.d.ts index 944b6e423..9db710975 100644 --- a/lib/build/recipe/passwordless/components/themes/signInUp/emailOrPhoneForm.d.ts +++ b/lib/build/recipe/passwordless/components/themes/signInUp/emailOrPhoneForm.d.ts @@ -1,3 +1,7 @@ /// import type { SignInUpEmailOrPhoneFormProps } from "../../../types"; -export declare const EmailOrPhoneForm: import("react").ComponentType; +export declare const EmailOrPhoneForm: import("react").ComponentType< + SignInUpEmailOrPhoneFormProps & { + footer?: JSX.Element | undefined; + } +>; diff --git a/lib/build/recipe/passwordless/components/themes/signInUp/index.d.ts b/lib/build/recipe/passwordless/components/themes/signInUp/index.d.ts index db29249a5..e7b8a7537 100644 --- a/lib/build/recipe/passwordless/components/themes/signInUp/index.d.ts +++ b/lib/build/recipe/passwordless/components/themes/signInUp/index.d.ts @@ -1,4 +1,5 @@ /// +import type { DynamicLoginMethodsContextValue } from "../../../../multitenancy/dynamicLoginMethodsContext"; import type { SignInUpProps } from "../../../types"; export declare enum SignInUpScreens { CloseTab = 0, @@ -10,4 +11,7 @@ export declare enum SignInUpScreens { } declare function SignInUpThemeWrapper(props: SignInUpProps): JSX.Element; export default SignInUpThemeWrapper; -export declare function getActiveScreen(props: Pick): SignInUpScreens; +export declare function getActiveScreen( + props: Pick, + currentDynamicLoginMethods: DynamicLoginMethodsContextValue +): SignInUpScreens; diff --git a/lib/build/recipe/passwordless/components/themes/signInUp/phoneForm.d.ts b/lib/build/recipe/passwordless/components/themes/signInUp/phoneForm.d.ts index d19b4dbe1..cced54acb 100644 --- a/lib/build/recipe/passwordless/components/themes/signInUp/phoneForm.d.ts +++ b/lib/build/recipe/passwordless/components/themes/signInUp/phoneForm.d.ts @@ -1,3 +1,7 @@ /// import type { SignInUpPhoneFormProps } from "../../../types"; -export declare const PhoneForm: import("react").ComponentType; +export declare const PhoneForm: import("react").ComponentType< + SignInUpPhoneFormProps & { + footer?: JSX.Element | undefined; + } +>; diff --git a/lib/build/recipe/passwordless/components/themes/signInUp/userInputCodeForm.d.ts b/lib/build/recipe/passwordless/components/themes/signInUp/userInputCodeForm.d.ts index 52d820aba..c2abc87e7 100644 --- a/lib/build/recipe/passwordless/components/themes/signInUp/userInputCodeForm.d.ts +++ b/lib/build/recipe/passwordless/components/themes/signInUp/userInputCodeForm.d.ts @@ -2,7 +2,6 @@ import React from "react"; import type { SignInUpUserInputCodeFormProps } from "../../../types"; export declare const UserInputCodeForm: React.ComponentType< SignInUpUserInputCodeFormProps & { - header?: JSX.Element | undefined; footer?: JSX.Element | undefined; } >; diff --git a/lib/build/recipe/passwordless/components/themes/translations.d.ts b/lib/build/recipe/passwordless/components/themes/translations.d.ts index 0fed6a0d3..78ccc297c 100644 --- a/lib/build/recipe/passwordless/components/themes/translations.d.ts +++ b/lib/build/recipe/passwordless/components/themes/translations.d.ts @@ -52,6 +52,12 @@ export declare const defaultTranslationsPasswordless: { PWLESS_USER_INPUT_CODE_HEADER_SUBTITLE: string; PWLESS_USER_INPUT_CODE_HEADER_SUBTITLE_LINK: string; PWLESS_USER_INPUT_CODE_INPUT_LABEL: string; + PWLESS_MFA_LOGOUT: string; + PWLESS_MFA_HEADER_TITLE_PHONE: string; + PWLESS_MFA_HEADER_TITLE_EMAIL: string; + PWLESS_MFA_FOOTER_CHOOSER_ANOTHER: string; + PWLESS_MFA_FOOTER_LOGOUT: string; + PWLESS_MFA_OTP_NOT_ALLOWED_TO_SETUP: string; "Failed to generate a one time code. Please try again": undefined; "Phone number is invalid": undefined; "Email is invalid": undefined; diff --git a/lib/build/recipe/passwordless/prebuiltui.d.ts b/lib/build/recipe/passwordless/prebuiltui.d.ts index 68c945509..a68abcdc8 100644 --- a/lib/build/recipe/passwordless/prebuiltui.d.ts +++ b/lib/build/recipe/passwordless/prebuiltui.d.ts @@ -11,7 +11,7 @@ export declare class PasswordlessPreBuiltUI extends RecipeRouter { static getInstanceOrInitAndGetInstance(): PasswordlessPreBuiltUI; static getFeatures(useComponentOverrides?: () => GenericComponentOverrideMap): RecipeFeatureComponentMap; static getFeatureComponent( - componentName: "signInUp" | "linkClickedScreen", + componentName: "signInUp" | "linkClickedScreen" | "otp-phone" | "otp-email", props: FeatureBaseProps & { redirectOnSessionExists?: boolean; userContext?: any; @@ -20,7 +20,7 @@ export declare class PasswordlessPreBuiltUI extends RecipeRouter { ): JSX.Element; getFeatures: (useComponentOverrides?: () => GenericComponentOverrideMap) => RecipeFeatureComponentMap; getFeatureComponent: ( - componentName: "signInUp" | "linkClickedScreen", + componentName: "signInUp" | "linkClickedScreen" | "otp-phone" | "otp-email", props: FeatureBaseProps & { redirectOnSessionExists?: boolean; userContext?: any; @@ -35,6 +35,8 @@ export declare class PasswordlessPreBuiltUI extends RecipeRouter { }> ) => JSX.Element; static LinkClicked: (prop?: any) => JSX.Element; + static MfaOtpPhone: (prop?: any) => JSX.Element; + static MfaOtpEmail: (prop?: any) => JSX.Element; static SignInUpTheme: typeof SignInUpTheme; } declare const SignInUp: ( @@ -44,4 +46,6 @@ declare const SignInUp: ( }> ) => JSX.Element; declare const LinkClicked: (prop?: any) => JSX.Element; -export { SignInUp, LinkClicked, SignInUpTheme }; +declare const MfaOtpPhone: (prop?: any) => JSX.Element; +declare const MfaOtpEmail: (prop?: any) => JSX.Element; +export { SignInUp, LinkClicked, SignInUpTheme, MfaOtpPhone, MfaOtpEmail }; diff --git a/lib/build/recipe/passwordless/recipe.d.ts b/lib/build/recipe/passwordless/recipe.d.ts index b3532f13e..109883c51 100644 --- a/lib/build/recipe/passwordless/recipe.d.ts +++ b/lib/build/recipe/passwordless/recipe.d.ts @@ -1,3 +1,4 @@ +/// import PasswordlessWebJS from "supertokens-web-js/recipe/passwordless"; import AuthRecipe from "../authRecipe"; import type { @@ -8,6 +9,20 @@ import type { UserInput, } from "./types"; import type { RecipeInitResult, NormalisedConfigWithAppInfoAndRecipeID, WebJSRecipeInterface } from "../../types"; +export declare const otpPhoneFactor: { + id: string; + name: string; + description: string; + path: string; + logo: () => JSX.Element; +}; +export declare const otpEmailFactor: { + id: string; + name: string; + description: string; + path: string; + logo: () => JSX.Element; +}; export declare const passwordlessFirstFactors: readonly ["otp-phone", "otp-email", "link-phone", "link-email"]; export default class Passwordless extends AuthRecipe< GetRedirectionURLContext, diff --git a/lib/build/recipe/passwordless/types.d.ts b/lib/build/recipe/passwordless/types.d.ts index 617b38663..4859c2c99 100644 --- a/lib/build/recipe/passwordless/types.d.ts +++ b/lib/build/recipe/passwordless/types.d.ts @@ -1,4 +1,8 @@ import type { LinkClickedScreen } from "./components/themes/linkClickedScreen"; +import type { MFAFooter } from "./components/themes/mfa/mfaFooter"; +import type { MFAHeader } from "./components/themes/mfa/mfaHeader"; +import type { MFAOTPFooter } from "./components/themes/mfa/mfaOTPFooter"; +import type { MFAOTPHeader } from "./components/themes/mfa/mfaOTPHeader"; import type { CloseTabScreen } from "./components/themes/signInUp/closeTabScreen"; import type { EmailForm } from "./components/themes/signInUp/emailForm"; import type { EmailOrPhoneForm } from "./components/themes/signInUp/emailOrPhoneForm"; @@ -70,6 +74,7 @@ export declare type NormalisedConfig = { disableDefaultUI?: boolean; }; linkClickedScreenFeature: PasswordlessNormalisedBaseConfig; + mfaFeature: PasswordlessNormalisedBaseConfig; contactMethod: "PHONE" | "EMAIL" | "EMAIL_OR_PHONE"; override: { functions: (originalImplementation: RecipeInterface) => RecipeInterface; @@ -120,7 +125,26 @@ export declare type UserInput = ( functions?: (originalImplementation: RecipeInterface) => RecipeInterface; }; linkClickedScreenFeature?: PasswordlessFeatureBaseConfig; + mfaFeature?: PasswordlessFeatureBaseConfig; } & AuthRecipeModuleUserInput; +export declare type MFAProps = { + recipeImplementation: RecipeImplementation; + config: NormalisedConfig; + contactMethod: "EMAIL" | "PHONE"; + onBackButtonClicked: () => void; + onSignOutClicked: () => void; + onFactorChooserButtonClicked: () => void; + onSuccess?: () => void; + dispatch: Dispatch; + featureState: { + isSetupAllowed: boolean; + loginAttemptInfo?: LoginAttemptInfo; + loaded: boolean; + successInAnotherTab: boolean; + error: string | undefined; + }; + userContext?: any; +}; export declare type SignInUpProps = { recipeImplementation: RecipeImplementation; config: NormalisedConfig; @@ -232,7 +256,41 @@ export declare type SignInUpState = { loginAttemptInfo: LoginAttemptInfo | undefined; successInAnotherTab: boolean; }; +export declare type MFAAction = + | { + type: "load"; + loginAttemptInfo: LoginAttemptInfo | undefined; + isAllowedToSetup: boolean; + error: string | undefined; + } + | { + type: "startVerify"; + loginAttemptInfo: LoginAttemptInfo; + } + | { + type: "resendCode"; + timestamp: number; + } + | { + type: "restartFlow"; + error: string | undefined; + } + | { + type: "setError"; + error: string | undefined; + } + | { + type: "successInAnotherTab"; + }; +export declare type MFAState = { + error: string | undefined; + loaded: boolean; + loginAttemptInfo: LoginAttemptInfo | undefined; + isSetupAllowed: boolean; + successInAnotherTab: boolean; +}; export declare type SignInUpChildProps = Omit; +export declare type MFAChildProps = Omit; export declare type LinkSentThemeProps = { clearError: () => void; onError: (error: string) => void; @@ -251,6 +309,28 @@ export declare type UserInputCodeFormHeaderProps = { recipeImplementation: RecipeImplementation; config: NormalisedConfig; }; +export declare type MFAFooterProps = { + isSetupAllowed: boolean; + onSignOutClicked: () => void; + onFactorChooserButtonClicked: () => void; + recipeImplementation: RecipeImplementation; + config: NormalisedConfig; +}; +export declare type MFAOTPFooterProps = { + isSetupAllowed: boolean; + onSignOutClicked: () => void; + onFactorChooserButtonClicked: () => void; + loginAttemptInfo: LoginAttemptInfo; + recipeImplementation: RecipeImplementation; + config: NormalisedConfig; +}; +export declare type MFAOTPHeaderProps = { + isSetupAllowed: boolean; + onBackButtonClicked: () => void; + loginAttemptInfo: LoginAttemptInfo; + recipeImplementation: RecipeImplementation; + config: NormalisedConfig; +}; export declare type ComponentOverrideMap = { PasswordlessSignInUpHeader_Override?: ComponentOverride; PasswordlessSignInUpFooter_Override?: ComponentOverride; @@ -263,4 +343,8 @@ export declare type ComponentOverrideMap = { PasswordlessLinkSent_Override?: ComponentOverride; PasswordlessLinkClickedScreen_Override?: ComponentOverride; PasswordlessCloseTabScreen_Override?: ComponentOverride; + PasswordlessMFAHeader_Override?: ComponentOverride; + PasswordlessMFAFooter_Override?: ComponentOverride; + PasswordlessMFAOTPHeader_Override?: ComponentOverride; + PasswordlessMFAOTPFooter_Override?: ComponentOverride; }; diff --git a/lib/build/recipe/passwordless/utils.d.ts b/lib/build/recipe/passwordless/utils.d.ts index a5b28e889..c6762d875 100644 --- a/lib/build/recipe/passwordless/utils.d.ts +++ b/lib/build/recipe/passwordless/utils.d.ts @@ -1,2 +1,7 @@ import type { Config, NormalisedConfig } from "./types"; +import type { DynamicLoginMethodsContextValue } from "../multitenancy/dynamicLoginMethodsContext"; export declare function normalisePasswordlessConfig(config: Config): NormalisedConfig; +export declare function getEnabledContactMethods( + contactMethod: "PHONE" | "EMAIL" | "EMAIL_OR_PHONE", + currentDynamicLoginMethods: DynamicLoginMethodsContextValue +): string[]; diff --git a/lib/build/recipe/thirdpartypasswordless/components/themes/translations.d.ts b/lib/build/recipe/thirdpartypasswordless/components/themes/translations.d.ts index b24b59e60..14113e5ca 100644 --- a/lib/build/recipe/thirdpartypasswordless/components/themes/translations.d.ts +++ b/lib/build/recipe/thirdpartypasswordless/components/themes/translations.d.ts @@ -54,6 +54,12 @@ export declare const defaultTranslationsThirdPartyPasswordless: { PWLESS_USER_INPUT_CODE_HEADER_SUBTITLE: string; PWLESS_USER_INPUT_CODE_HEADER_SUBTITLE_LINK: string; PWLESS_USER_INPUT_CODE_INPUT_LABEL: string; + PWLESS_MFA_LOGOUT: string; + PWLESS_MFA_HEADER_TITLE_PHONE: string; + PWLESS_MFA_HEADER_TITLE_EMAIL: string; + PWLESS_MFA_FOOTER_CHOOSER_ANOTHER: string; + PWLESS_MFA_FOOTER_LOGOUT: string; + PWLESS_MFA_OTP_NOT_ALLOWED_TO_SETUP: string; "Failed to generate a one time code. Please try again": undefined; "Phone number is invalid": undefined; "Email is invalid": undefined; diff --git a/lib/build/recipe/thirdpartypasswordless/prebuiltui.d.ts b/lib/build/recipe/thirdpartypasswordless/prebuiltui.d.ts index 773b9b4cd..cdf4b0d10 100644 --- a/lib/build/recipe/thirdpartypasswordless/prebuiltui.d.ts +++ b/lib/build/recipe/thirdpartypasswordless/prebuiltui.d.ts @@ -13,7 +13,7 @@ export declare class ThirdPartyPasswordlessPreBuiltUI extends RecipeRouter { static getInstanceOrInitAndGetInstance(): ThirdPartyPasswordlessPreBuiltUI; static getFeatures(useComponentOverrides?: () => GenericComponentOverrideMap): RecipeFeatureComponentMap; static getFeatureComponent( - componentName: "signInUp" | "linkClickedScreen" | "signinupcallback", + componentName: "signInUp" | "linkClickedScreen" | "signinupcallback" | "otp-phone" | "otp-email", props: FeatureBaseProps & { redirectOnSessionExists?: boolean; userContext?: any; @@ -21,7 +21,7 @@ export declare class ThirdPartyPasswordlessPreBuiltUI extends RecipeRouter { useComponentOverrides?: () => GenericComponentOverrideMap ): JSX.Element; getFeatureComponent: ( - componentName: "signInUp" | "linkClickedScreen" | "signinupcallback", + componentName: "signInUp" | "linkClickedScreen" | "signinupcallback" | "otp-phone" | "otp-email", props: FeatureBaseProps & { redirectOnSessionExists?: boolean; userContext?: any; @@ -39,6 +39,8 @@ export declare class ThirdPartyPasswordlessPreBuiltUI extends RecipeRouter { static ThirdPartySignInAndUpCallback: (prop?: any) => JSX.Element; static SignInUpTheme: typeof SignInUpTheme; static PasswordlessLinkClicked: (prop?: any) => JSX.Element; + static MfaOtpPhone: (prop?: any) => JSX.Element; + static MfaOtpEmail: (prop?: any) => JSX.Element; } declare const SignInAndUp: ( prop?: PropsWithChildren<{ @@ -48,4 +50,6 @@ declare const SignInAndUp: ( ) => JSX.Element; declare const ThirdPartySignInAndUpCallback: (prop?: any) => JSX.Element; declare const PasswordlessLinkClicked: (prop?: any) => JSX.Element; -export { SignInAndUp, ThirdPartySignInAndUpCallback, PasswordlessLinkClicked, SignInUpTheme }; +declare const MfaOtpPhone: (prop?: any) => JSX.Element; +declare const MfaOtpEmail: (prop?: any) => JSX.Element; +export { SignInAndUp, ThirdPartySignInAndUpCallback, PasswordlessLinkClicked, SignInUpTheme, MfaOtpPhone, MfaOtpEmail }; diff --git a/lib/build/recipe/thirdpartypasswordless/types.d.ts b/lib/build/recipe/thirdpartypasswordless/types.d.ts index b328d24f2..0fa2fc39b 100644 --- a/lib/build/recipe/thirdpartypasswordless/types.d.ts +++ b/lib/build/recipe/thirdpartypasswordless/types.d.ts @@ -89,6 +89,7 @@ export declare type UserInput = ( ) => RecipeInterface; }; linkClickedScreenFeature?: PasswordlessFeatureBaseConfig; + mfaFeature?: PasswordlessFeatureBaseConfig; oAuthCallbackScreen?: FeatureBaseConfig; disablePasswordless?: boolean; } & AuthRecipeModuleUserInput; diff --git a/lib/build/sessionprebuiltui.js b/lib/build/sessionprebuiltui.js index e4cd239bf..60f00c8a6 100644 --- a/lib/build/sessionprebuiltui.js +++ b/lib/build/sessionprebuiltui.js @@ -82,7 +82,7 @@ function LogoutButton(_a) { } var styles = - '/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 255, 155, 51;\n --palette-primaryBorder: 238, 141, 35;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 34, 34, 34;\n --palette-textLabel: 34, 34, 34;\n --palette-textInput: 34, 34, 34;\n --palette-textPrimary: 101, 101, 101;\n --palette-textLink: 0, 118, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 128, 128, 128;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n}\n\n/*\n * Default styles.\n */\n\n@-webkit-keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n\n@keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n\n@-webkit-keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n\n@keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n\n[data-supertokens~="container"] {\n font-family: "Rubik", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 0 auto;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 15px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 40px;\n letter-spacing: 0.58px;\n font-weight: 600;\n margin-bottom: 2px;\n color: rgb(var(--palette-textTitle));\n}\n\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n margin-bottom: 21px;\n}\n\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n\n/* TODO: split the link style into separate things*/\n\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-1);\n font-weight: 500;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 300;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="divider"] {\n margin-top: 1em;\n margin-bottom: 1em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n}\n\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n\n[data-supertokens~="linkButton"] {\n font-family: "Rubik", sans-serif;\n background-color: transparent;\n border: 0;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n\n[data-supertokens~="button"] {\n font-family: "Rubik", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 700;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n -webkit-filter: brightness(0.85);\n filter: brightness(0.85);\n}\n\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n\n/* Override */\n\n[data-supertokens~="accessDenied"] [data-supertokens~="row"] {\n padding-bottom: 24px;\n}\n\n[data-supertokens~="accessDenied"] [data-supertokens~="divider"] {\n padding: 0;\n margin: 34px 0 18px 0;\n}\n\n[data-supertokens~="accessDenied"] [data-supertokens~="headerTitle"] {\n margin: 10px 0 0 0;\n font-style: normal;\n font-weight: 700;\n font-size: 20px;\n line-height: 30px;\n}\n\n/* Override end */\n\n[data-supertokens~="center"] {\n height: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n flex: 1 1 auto;\n}\n\n[data-supertokens~="buttonsGroup"] {\n margin-top: 34px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n[data-supertokens~="buttonBase"] {\n font-family: "Rubik", sans-serif;\n font-size: var(--font-size-1);\n line-height: 21px;\n font-weight: 500;\n background: transparent;\n outline: none;\n border: none;\n cursor: pointer;\n}\n\n[data-supertokens~="backButton"] {\n color: rgb(var(--palette-textLink));\n}\n\n[data-supertokens~="logoutButton"] {\n display: flex;\n align-items: center;\n gap: 6px;\n color: rgb(var(--palette-textGray));\n}\n\n[data-supertokens~="primaryText"][data-supertokens~="accessDeniedError"] {\n font-weight: 400;\n}\n'; + '/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n\n[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 255, 155, 51;\n --palette-primaryBorder: 238, 141, 35;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 34, 34, 34;\n --palette-textLabel: 34, 34, 34;\n --palette-textInput: 34, 34, 34;\n --palette-textPrimary: 101, 101, 101;\n --palette-textLink: 0, 118, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 128, 128, 128;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n}\n\n/*\n * Default styles.\n */\n\n@-webkit-keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n\n@keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n\n@-webkit-keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n\n@keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n\n[data-supertokens~="container"] {\n font-family: "Rubik", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 0 auto;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 15px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 40px;\n letter-spacing: 0.58px;\n font-weight: 600;\n margin-bottom: 2px;\n color: rgb(var(--palette-textTitle));\n}\n\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n margin-bottom: 21px;\n}\n\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n\n/* TODO: split the link style into separate things*/\n\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-1);\n font-weight: 500;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 300;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n\n[data-supertokens~="divider"] {\n margin-top: 1em;\n margin-bottom: 1em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n}\n\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n\n[data-supertokens~="linkButton"] {\n font-family: "Rubik", sans-serif;\n background-color: transparent;\n border: 0;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n\n[data-supertokens~="button"] {\n font-family: "Rubik", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 700;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n -webkit-filter: brightness(0.85);\n filter: brightness(0.85);\n}\n\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n\n[data-supertokens~="delayedRender"] {\n -webkit-animation-duration: 0.1s;\n animation-duration: 0.1s;\n -webkit-animation-name: animate-fade;\n animation-name: animate-fade;\n -webkit-animation-delay: 0.2s;\n animation-delay: 0.2s;\n -webkit-animation-fill-mode: backwards;\n animation-fill-mode: backwards;\n}\n\n@-webkit-keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n\n[data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n\n/* Override */\n\n[data-supertokens~="accessDenied"] [data-supertokens~="row"] {\n padding-bottom: 24px;\n}\n\n[data-supertokens~="accessDenied"] [data-supertokens~="divider"] {\n padding: 0;\n margin: 34px 0 18px 0;\n}\n\n[data-supertokens~="accessDenied"] [data-supertokens~="headerTitle"] {\n margin: 10px 0 0 0;\n font-style: normal;\n font-weight: 700;\n font-size: 20px;\n line-height: 30px;\n}\n\n/* Override end */\n\n[data-supertokens~="center"] {\n height: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n flex: 1 1 auto;\n}\n\n[data-supertokens~="buttonsGroup"] {\n margin-top: 34px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n[data-supertokens~="buttonBase"] {\n font-family: "Rubik", sans-serif;\n font-size: var(--font-size-1);\n line-height: 21px;\n font-weight: 500;\n background: transparent;\n outline: none;\n border: none;\n cursor: pointer;\n}\n\n[data-supertokens~="backButton"] {\n color: rgb(var(--palette-textLink));\n}\n\n[data-supertokens~="logoutButton"] {\n display: flex;\n align-items: center;\n gap: 6px;\n color: rgb(var(--palette-textGray));\n}\n\n[data-supertokens~="primaryText"][data-supertokens~="accessDeniedError"] {\n font-weight: 400;\n}\n'; var ThemeBase = function (_a) { var children = _a.children, diff --git a/lib/build/thirdparty-shared2.js b/lib/build/thirdparty-shared2.js index 0d25408c5..3efbc4971 100644 --- a/lib/build/thirdparty-shared2.js +++ b/lib/build/thirdparty-shared2.js @@ -49,7 +49,7 @@ var React__namespace = /*#__PURE__*/ _interopNamespace(React); var STGeneralError__default = /*#__PURE__*/ _interopDefault(STGeneralError); var styles = - '[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 255, 155, 51;\n --palette-primaryBorder: 238, 141, 35;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 34, 34, 34;\n --palette-textLabel: 34, 34, 34;\n --palette-textInput: 34, 34, 34;\n --palette-textPrimary: 101, 101, 101;\n --palette-textLink: 0, 118, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 128, 128, 128;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n}\n/*\n * Default styles.\n */\n@-webkit-keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@-webkit-keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Rubik", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 0 auto;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 15px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 40px;\n letter-spacing: 0.58px;\n font-weight: 600;\n margin-bottom: 2px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-1);\n font-weight: 500;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 300;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="divider"] {\n margin-top: 1em;\n margin-bottom: 1em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Rubik", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Rubik", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 700;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n -webkit-filter: brightness(0.85);\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="row"] {\n padding-bottom: 30px;\n}\n[data-supertokens~="providerContainer"] {\n padding-top: 9px;\n padding-bottom: 9px;\n}\n[data-supertokens~="providerButton"] {\n border-color: rgb(221, 221, 221) !important;\n}\n[data-supertokens~="providerButton"] {\n min-height: 32px;\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 2px 8px;\n\n background-color: white;\n color: black;\n}\n[data-supertokens~="providerButton"]:hover {\n -webkit-filter: none !important;\n filter: none !important;\n}\n[data-supertokens~="providerButton"]:hover {\n background-color: #fafafa;\n}\n[data-supertokens~="providerButtonLeft"] {\n min-width: 34px;\n margin-left: 66px;\n}\n[data-supertokens~="providerButtonLogo"] {\n height: 30px;\n display: flex;\n}\n[data-supertokens~="providerButtonLogoCenter"] {\n display: flex;\n margin: auto;\n}\n[data-supertokens~="providerButtonText"] {\n font-weight: 400;\n text-align: center;\n justify-content: center;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n display: inline-block;\n}\n[data-supertokens~="providerButtonText"]:only-child {\n margin: 0 auto;\n}\n'; + '[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 255, 155, 51;\n --palette-primaryBorder: 238, 141, 35;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 34, 34, 34;\n --palette-textLabel: 34, 34, 34;\n --palette-textInput: 34, 34, 34;\n --palette-textPrimary: 101, 101, 101;\n --palette-textLink: 0, 118, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 128, 128, 128;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n}\n/*\n * Default styles.\n */\n@-webkit-keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@-webkit-keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Rubik", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 0 auto;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 15px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 40px;\n letter-spacing: 0.58px;\n font-weight: 600;\n margin-bottom: 2px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-1);\n font-weight: 500;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 300;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="divider"] {\n margin-top: 1em;\n margin-bottom: 1em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Rubik", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Rubik", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 700;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n -webkit-filter: brightness(0.85);\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n[data-supertokens~="delayedRender"] {\n -webkit-animation-duration: 0.1s;\n animation-duration: 0.1s;\n -webkit-animation-name: animate-fade;\n animation-name: animate-fade;\n -webkit-animation-delay: 0.2s;\n animation-delay: 0.2s;\n -webkit-animation-fill-mode: backwards;\n animation-fill-mode: backwards;\n}\n@-webkit-keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n[data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n[data-supertokens~="row"] {\n padding-bottom: 30px;\n}\n[data-supertokens~="providerContainer"] {\n padding-top: 9px;\n padding-bottom: 9px;\n}\n[data-supertokens~="providerButton"] {\n border-color: rgb(221, 221, 221) !important;\n}\n[data-supertokens~="providerButton"] {\n min-height: 32px;\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 2px 8px;\n\n background-color: white;\n color: black;\n}\n[data-supertokens~="providerButton"]:hover {\n -webkit-filter: none !important;\n filter: none !important;\n}\n[data-supertokens~="providerButton"]:hover {\n background-color: #fafafa;\n}\n[data-supertokens~="providerButtonLeft"] {\n min-width: 34px;\n margin-left: 66px;\n}\n[data-supertokens~="providerButtonLogo"] {\n height: 30px;\n display: flex;\n}\n[data-supertokens~="providerButtonLogoCenter"] {\n display: flex;\n margin: auto;\n}\n[data-supertokens~="providerButtonText"] {\n font-weight: 400;\n text-align: center;\n justify-content: center;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n display: inline-block;\n}\n[data-supertokens~="providerButtonText"]:only-child {\n margin: 0 auto;\n}\n'; var ThemeBase = function (_a) { var children = _a.children, diff --git a/lib/build/thirdpartyemailpasswordprebuiltui.js b/lib/build/thirdpartyemailpasswordprebuiltui.js index 803be9c24..afa1c8990 100644 --- a/lib/build/thirdpartyemailpasswordprebuiltui.js +++ b/lib/build/thirdpartyemailpasswordprebuiltui.js @@ -81,7 +81,7 @@ var NormalisedURLPath__default = /*#__PURE__*/ _interopDefault(NormalisedURLPath var React__namespace = /*#__PURE__*/ _interopNamespace(React); var styles = - '/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 255, 155, 51;\n --palette-primaryBorder: 238, 141, 35;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 34, 34, 34;\n --palette-textLabel: 34, 34, 34;\n --palette-textInput: 34, 34, 34;\n --palette-textPrimary: 101, 101, 101;\n --palette-textLink: 0, 118, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 128, 128, 128;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n}\n/*\n * Default styles.\n */\n@-webkit-keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@-webkit-keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Rubik", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 0 auto;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 15px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 40px;\n letter-spacing: 0.58px;\n font-weight: 600;\n margin-bottom: 2px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-1);\n font-weight: 500;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 300;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="divider"] {\n margin-top: 1em;\n margin-bottom: 1em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Rubik", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Rubik", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 700;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n -webkit-filter: brightness(0.85);\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="inputContainer"] {\n margin-top: 6px;\n}\n[data-supertokens~="inputWrapper"] {\n box-sizing: border-box;\n width: 100%;\n display: flex;\n align-items: center;\n background-color: rgb(var(--palette-inputBackground));\n height: 34px;\n border-radius: 6px;\n border: 1px solid rgb(var(--palette-inputBorder));\n}\n[data-supertokens~="inputWrapper"][focus-within] {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n[data-supertokens~="inputWrapper"]:focus-within {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n[data-supertokens~="inputError"] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n[data-supertokens~="inputError"][focus-within] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n[data-supertokens~="inputError"]:focus-within {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n[data-supertokens~="input"] {\n box-sizing: border-box;\n padding-left: 15px;\n -webkit-filter: none;\n filter: none;\n color: rgb(var(--palette-textInput));\n background-color: transparent;\n border-radius: 6px;\n font-size: var(--font-size-1);\n border: none;\n padding-right: 25px;\n letter-spacing: 1.2px;\n flex: 9 1 75%;\n width: 75%;\n height: 32px;\n}\n[data-supertokens~="input"]:focus {\n border: none;\n outline: none;\n}\n[data-supertokens~="input"]:-webkit-autofill,\n[data-supertokens~="input"]:-webkit-autofill:hover,\n[data-supertokens~="input"]:-webkit-autofill:focus,\n[data-supertokens~="input"]:-webkit-autofill:active {\n -webkit-text-fill-color: rgb(var(--palette-textInput));\n box-shadow: 0 0 0 30px rgb(var(--palette-inputBackground)) inset;\n}\n[data-supertokens~="inputAdornment"] {\n justify-content: center;\n margin-right: 5px;\n}\n[data-supertokens~="showPassword"] {\n cursor: pointer;\n}\n[data-supertokens~="forgotPasswordLink"] {\n margin-top: 10px;\n}\n[data-supertokens~="enterEmailSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n word-break: break-word;\n}\n[data-supertokens~="submitNewPasswordSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n[data-supertokens~="inputErrorMessage"] {\n padding-top: 5px;\n padding-bottom: 5px;\n color: rgb(var(--palette-error));\n line-height: 24px;\n font-weight: 400;\n font-size: var(--font-size-1);\n text-align: left;\n -webkit-animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n max-width: 330px;\n}\n@media (max-width: 440px) {\n [data-supertokens~="inputErrorMessage"] {\n max-width: 250px;\n }\n}\n[data-supertokens~="inputErrorSymbol"] {\n margin-right: 5px;\n top: 1px;\n position: relative;\n left: 2px;\n}\n[data-supertokens~="label"] {\n text-align: left;\n font-weight: 600;\n font-size: var(--font-size-1);\n line-height: 24px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="formRow"] {\n display: flex;\n flex-direction: column;\n padding-top: 0px;\n padding-bottom: 34px;\n}\n[data-supertokens~="formRow"][data-supertokens~="hasError"] {\n padding-bottom: 0;\n}\n[data-supertokens~="sendVerifyEmailIcon"] {\n margin-top: 11px;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n[data-supertokens~="sendVerifyEmailText"] {\n line-height: 21px;\n font-size: var(--font-size-1);\n text-align: center;\n font-weight: 300;\n letter-spacing: 0.8px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="sendVerifyEmailResend"] {\n margin-top: 13px;\n font-weight: 300;\n}\n[data-supertokens~="sendVerifyEmailResend"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="noFormRow"] {\n padding-bottom: 25px;\n}\n[data-supertokens~="emailVerificationButtonWrapper"] {\n padding-top: 25px;\n max-width: 96px;\n margin: 0 auto;\n}\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n[data-supertokens~="resendEmailLink"] {\n display: inline-block;\n}\n[data-supertokens~="row"] {\n padding-bottom: 30px;\n}\n[data-supertokens~="providerContainer"] {\n padding-top: 9px;\n padding-bottom: 9px;\n}\n[data-supertokens~="providerButton"] {\n border-color: rgb(221, 221, 221) !important;\n}\n[data-supertokens~="providerButton"] {\n min-height: 32px;\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 2px 8px;\n\n background-color: white;\n color: black;\n}\n[data-supertokens~="providerButton"]:hover {\n -webkit-filter: none !important;\n filter: none !important;\n}\n[data-supertokens~="providerButton"]:hover {\n background-color: #fafafa;\n}\n[data-supertokens~="providerButtonLeft"] {\n min-width: 34px;\n margin-left: 66px;\n}\n[data-supertokens~="providerButtonLogo"] {\n height: 30px;\n display: flex;\n}\n[data-supertokens~="providerButtonLogoCenter"] {\n display: flex;\n margin: auto;\n}\n[data-supertokens~="providerButtonText"] {\n font-weight: 400;\n text-align: center;\n justify-content: center;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n display: inline-block;\n}\n[data-supertokens~="providerButtonText"]:only-child {\n margin: 0 auto;\n}\n[data-supertokens~="thirdPartyEmailPasswordDivider"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="thirdPartyEmailPasswordDividerOr"] {\n flex: 1 1;\n margin-top: 0.75em;\n}\n[data-supertokens~="divider"] {\n flex: 3 3;\n}\n[data-supertokens~="providerButton"] {\n margin: auto !important;\n max-width: 240px !important;\n}\n[data-supertokens~="providerButtonLeft"] {\n margin-left: 30px !important;\n}\n'; + '/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 255, 155, 51;\n --palette-primaryBorder: 238, 141, 35;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 34, 34, 34;\n --palette-textLabel: 34, 34, 34;\n --palette-textInput: 34, 34, 34;\n --palette-textPrimary: 101, 101, 101;\n --palette-textLink: 0, 118, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 128, 128, 128;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n}\n/*\n * Default styles.\n */\n@-webkit-keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@-webkit-keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Rubik", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 0 auto;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 15px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 40px;\n letter-spacing: 0.58px;\n font-weight: 600;\n margin-bottom: 2px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-1);\n font-weight: 500;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 300;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="divider"] {\n margin-top: 1em;\n margin-bottom: 1em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Rubik", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Rubik", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 700;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n -webkit-filter: brightness(0.85);\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n[data-supertokens~="delayedRender"] {\n -webkit-animation-duration: 0.1s;\n animation-duration: 0.1s;\n -webkit-animation-name: animate-fade;\n animation-name: animate-fade;\n -webkit-animation-delay: 0.2s;\n animation-delay: 0.2s;\n -webkit-animation-fill-mode: backwards;\n animation-fill-mode: backwards;\n}\n@-webkit-keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n[data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n[data-supertokens~="inputContainer"] {\n margin-top: 6px;\n}\n[data-supertokens~="inputWrapper"] {\n box-sizing: border-box;\n width: 100%;\n display: flex;\n align-items: center;\n background-color: rgb(var(--palette-inputBackground));\n height: 34px;\n border-radius: 6px;\n border: 1px solid rgb(var(--palette-inputBorder));\n}\n[data-supertokens~="inputWrapper"][focus-within] {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n[data-supertokens~="inputWrapper"]:focus-within {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n[data-supertokens~="inputError"] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n[data-supertokens~="inputError"][focus-within] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n[data-supertokens~="inputError"]:focus-within {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n[data-supertokens~="input"] {\n box-sizing: border-box;\n padding-left: 15px;\n -webkit-filter: none;\n filter: none;\n color: rgb(var(--palette-textInput));\n background-color: transparent;\n border-radius: 6px;\n font-size: var(--font-size-1);\n border: none;\n padding-right: 25px;\n letter-spacing: 1.2px;\n flex: 9 1 75%;\n width: 75%;\n height: 32px;\n}\n[data-supertokens~="input"]:focus {\n border: none;\n outline: none;\n}\n[data-supertokens~="input"]:-webkit-autofill,\n[data-supertokens~="input"]:-webkit-autofill:hover,\n[data-supertokens~="input"]:-webkit-autofill:focus,\n[data-supertokens~="input"]:-webkit-autofill:active {\n -webkit-text-fill-color: rgb(var(--palette-textInput));\n box-shadow: 0 0 0 30px rgb(var(--palette-inputBackground)) inset;\n}\n[data-supertokens~="inputAdornment"] {\n justify-content: center;\n margin-right: 5px;\n}\n[data-supertokens~="showPassword"] {\n cursor: pointer;\n}\n[data-supertokens~="forgotPasswordLink"] {\n margin-top: 10px;\n}\n[data-supertokens~="enterEmailSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n word-break: break-word;\n}\n[data-supertokens~="submitNewPasswordSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n[data-supertokens~="inputErrorMessage"] {\n padding-top: 5px;\n padding-bottom: 5px;\n color: rgb(var(--palette-error));\n line-height: 24px;\n font-weight: 400;\n font-size: var(--font-size-1);\n text-align: left;\n -webkit-animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n max-width: 330px;\n}\n@media (max-width: 440px) {\n [data-supertokens~="inputErrorMessage"] {\n max-width: 250px;\n }\n}\n[data-supertokens~="inputErrorSymbol"] {\n margin-right: 5px;\n top: 1px;\n position: relative;\n left: 2px;\n}\n[data-supertokens~="label"] {\n text-align: left;\n font-weight: 600;\n font-size: var(--font-size-1);\n line-height: 24px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="formRow"] {\n display: flex;\n flex-direction: column;\n padding-top: 0px;\n padding-bottom: 34px;\n}\n[data-supertokens~="formRow"][data-supertokens~="hasError"] {\n padding-bottom: 0;\n}\n[data-supertokens~="sendVerifyEmailIcon"] {\n margin-top: 11px;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n[data-supertokens~="sendVerifyEmailText"] {\n line-height: 21px;\n font-size: var(--font-size-1);\n text-align: center;\n font-weight: 300;\n letter-spacing: 0.8px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="sendVerifyEmailResend"] {\n margin-top: 13px;\n font-weight: 300;\n}\n[data-supertokens~="sendVerifyEmailResend"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="noFormRow"] {\n padding-bottom: 25px;\n}\n[data-supertokens~="emailVerificationButtonWrapper"] {\n padding-top: 25px;\n max-width: 96px;\n margin: 0 auto;\n}\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="resendEmailLink"] {\n display: inline-block;\n}\n[data-supertokens~="row"] {\n padding-bottom: 30px;\n}\n[data-supertokens~="providerContainer"] {\n padding-top: 9px;\n padding-bottom: 9px;\n}\n[data-supertokens~="providerButton"] {\n border-color: rgb(221, 221, 221) !important;\n}\n[data-supertokens~="providerButton"] {\n min-height: 32px;\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 2px 8px;\n\n background-color: white;\n color: black;\n}\n[data-supertokens~="providerButton"]:hover {\n -webkit-filter: none !important;\n filter: none !important;\n}\n[data-supertokens~="providerButton"]:hover {\n background-color: #fafafa;\n}\n[data-supertokens~="providerButtonLeft"] {\n min-width: 34px;\n margin-left: 66px;\n}\n[data-supertokens~="providerButtonLogo"] {\n height: 30px;\n display: flex;\n}\n[data-supertokens~="providerButtonLogoCenter"] {\n display: flex;\n margin: auto;\n}\n[data-supertokens~="providerButtonText"] {\n font-weight: 400;\n text-align: center;\n justify-content: center;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n display: inline-block;\n}\n[data-supertokens~="providerButtonText"]:only-child {\n margin: 0 auto;\n}\n[data-supertokens~="thirdPartyEmailPasswordDivider"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="thirdPartyEmailPasswordDividerOr"] {\n flex: 1 1;\n margin-top: 0.75em;\n}\n[data-supertokens~="divider"] {\n flex: 3 3;\n}\n[data-supertokens~="providerButton"] {\n margin: auto !important;\n max-width: 240px !important;\n}\n[data-supertokens~="providerButtonLeft"] {\n margin-left: 30px !important;\n}\n'; var ThemeBase = function (_a) { var children = _a.children, diff --git a/lib/build/thirdpartypasswordless-shared.js b/lib/build/thirdpartypasswordless-shared.js index ef7d96ef0..47576003b 100644 --- a/lib/build/thirdpartypasswordless-shared.js +++ b/lib/build/thirdpartypasswordless-shared.js @@ -236,6 +236,7 @@ function normaliseThirdPartyPasswordlessConfig(config) { { emailOrPhoneFormStyle: thirdPartyProviderAndEmailOrPhoneFormStyle } ), linkClickedScreenFeature: config.linkClickedScreenFeature, + mfaFeature: config.mfaFeature, override: {}, }), disablePasswordless: config.disablePasswordless === true, diff --git a/lib/build/thirdpartypasswordless.js b/lib/build/thirdpartypasswordless.js index 7de9631c9..796cbe40c 100644 --- a/lib/build/thirdpartypasswordless.js +++ b/lib/build/thirdpartypasswordless.js @@ -26,6 +26,9 @@ require("supertokens-web-js/lib/build/normalisedURLPath"); require("supertokens-web-js/recipe/thirdpartypasswordless"); require("./passwordless-shared2.js"); require("supertokens-web-js/recipe/passwordless"); +require("./multifactorauth-shared.js"); +require("supertokens-web-js/recipe/multifactorauth"); +require("supertokens-web-js/utils/sessionClaimValidatorStore"); var Wrapper = /** @class */ (function () { function Wrapper() {} diff --git a/lib/build/thirdpartypasswordlessprebuiltui.js b/lib/build/thirdpartypasswordlessprebuiltui.js index 4dfaa4fb7..fdef202cd 100644 --- a/lib/build/thirdpartypasswordlessprebuiltui.js +++ b/lib/build/thirdpartypasswordlessprebuiltui.js @@ -32,10 +32,13 @@ require("./session-shared3.js"); require("./passwordless-shared.js"); require("supertokens-web-js/utils/error"); require("./emailpassword-shared2.js"); +require("./sessionprebuiltui.js"); +require("./arrowLeftIcon.js"); require("./checkedRoundIcon.js"); require("./emailpassword-shared8.js"); require("./emailpassword-shared5.js"); -require("./arrowLeftIcon.js"); +require("./multifactorauth-shared2.js"); +require("./emailpassword-shared7.js"); require("./thirdparty-shared.js"); require("supertokens-web-js/recipe/thirdparty"); require("./authRecipe-shared.js"); @@ -79,7 +82,7 @@ var NormalisedURLPath__default = /*#__PURE__*/ _interopDefault(NormalisedURLPath var React__namespace = /*#__PURE__*/ _interopNamespace(React); var styles = - '/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 255, 155, 51;\n --palette-primaryBorder: 238, 141, 35;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 34, 34, 34;\n --palette-textLabel: 34, 34, 34;\n --palette-textInput: 34, 34, 34;\n --palette-textPrimary: 101, 101, 101;\n --palette-textLink: 0, 118, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 128, 128, 128;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n}\n/*\n * Default styles.\n */\n@-webkit-keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@-webkit-keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Rubik", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 0 auto;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 15px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 40px;\n letter-spacing: 0.58px;\n font-weight: 600;\n margin-bottom: 2px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-1);\n font-weight: 500;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 300;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="divider"] {\n margin-top: 1em;\n margin-bottom: 1em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Rubik", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Rubik", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 700;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n -webkit-filter: brightness(0.85);\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n[data-supertokens~="inputContainer"] {\n margin-top: 6px;\n}\n[data-supertokens~="inputWrapper"] {\n box-sizing: border-box;\n width: 100%;\n display: flex;\n align-items: center;\n background-color: rgb(var(--palette-inputBackground));\n height: 34px;\n border-radius: 6px;\n border: 1px solid rgb(var(--palette-inputBorder));\n}\n[data-supertokens~="inputWrapper"][focus-within] {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n[data-supertokens~="inputWrapper"]:focus-within {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n[data-supertokens~="inputError"] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n[data-supertokens~="inputError"][focus-within] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n[data-supertokens~="inputError"]:focus-within {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n[data-supertokens~="input"] {\n box-sizing: border-box;\n padding-left: 15px;\n -webkit-filter: none;\n filter: none;\n color: rgb(var(--palette-textInput));\n background-color: transparent;\n border-radius: 6px;\n font-size: var(--font-size-1);\n border: none;\n padding-right: 25px;\n letter-spacing: 1.2px;\n flex: 9 1 75%;\n width: 75%;\n height: 32px;\n}\n[data-supertokens~="input"]:focus {\n border: none;\n outline: none;\n}\n[data-supertokens~="input"]:-webkit-autofill,\n[data-supertokens~="input"]:-webkit-autofill:hover,\n[data-supertokens~="input"]:-webkit-autofill:focus,\n[data-supertokens~="input"]:-webkit-autofill:active {\n -webkit-text-fill-color: rgb(var(--palette-textInput));\n box-shadow: 0 0 0 30px rgb(var(--palette-inputBackground)) inset;\n}\n[data-supertokens~="inputAdornment"] {\n justify-content: center;\n margin-right: 5px;\n}\n[data-supertokens~="showPassword"] {\n cursor: pointer;\n}\n[data-supertokens~="forgotPasswordLink"] {\n margin-top: 10px;\n}\n[data-supertokens~="enterEmailSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n word-break: break-word;\n}\n[data-supertokens~="submitNewPasswordSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n[data-supertokens~="inputErrorMessage"] {\n padding-top: 5px;\n padding-bottom: 5px;\n color: rgb(var(--palette-error));\n line-height: 24px;\n font-weight: 400;\n font-size: var(--font-size-1);\n text-align: left;\n -webkit-animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n max-width: 330px;\n}\n@media (max-width: 440px) {\n [data-supertokens~="inputErrorMessage"] {\n max-width: 250px;\n }\n}\n[data-supertokens~="inputErrorSymbol"] {\n margin-right: 5px;\n top: 1px;\n position: relative;\n left: 2px;\n}\n[data-supertokens~="label"] {\n text-align: left;\n font-weight: 600;\n font-size: var(--font-size-1);\n line-height: 24px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="formRow"] {\n display: flex;\n flex-direction: column;\n padding-top: 0px;\n padding-bottom: 34px;\n}\n[data-supertokens~="formRow"][data-supertokens~="hasError"] {\n padding-bottom: 0;\n}\n[data-supertokens~="sendVerifyEmailIcon"] {\n margin-top: 11px;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n[data-supertokens~="sendVerifyEmailText"] {\n line-height: 21px;\n font-size: var(--font-size-1);\n text-align: center;\n font-weight: 300;\n letter-spacing: 0.8px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="sendVerifyEmailResend"] {\n margin-top: 13px;\n font-weight: 300;\n}\n[data-supertokens~="sendVerifyEmailResend"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="noFormRow"] {\n padding-bottom: 25px;\n}\n[data-supertokens~="emailVerificationButtonWrapper"] {\n padding-top: 25px;\n max-width: 96px;\n margin: 0 auto;\n}\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n[data-supertokens~="resendEmailLink"] {\n display: inline-block;\n}\n[data-supertokens~="generalSuccess"] {\n margin-bottom: 20px;\n -webkit-animation: swingIn 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) alternate 2 both;\n animation: swingIn 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) alternate 2 both;\n}\n[data-supertokens~="codeInputLabelWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="headerSubtitle"] strong {\n max-width: 100%;\n display: inline-block;\n vertical-align: bottom;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n[data-supertokens~="sendCodeText"] {\n margin-top: 15px;\n margin-bottom: 20px;\n}\n[data-supertokens~="sendCodeText"] strong {\n max-width: 100%;\n display: inline-block;\n vertical-align: bottom;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n[data-supertokens~="resendCodeBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n}\n[data-supertokens~="resendCodeBtn"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="resendCodeBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n[data-supertokens~="phoneInputLibRoot"] {\n display: flex;\n align-items: center;\n}\n[data-supertokens~="phoneInputWrapper"] {\n display: flex;\n align-items: center;\n}\n[data-supertokens~="phoneInputWrapper"] .iti [data-supertokens~="input"] {\n padding-left: 15px;\n}\n[data-supertokens~="phoneInputWrapper"] .iti {\n flex: 1 1;\n min-width: 0;\n width: 100%;\n background: transparent;\n border: none;\n color: inherit;\n outline: none;\n}\n[data-supertokens~="continueButtonWrapper"] {\n margin-top: 10px;\n margin-bottom: 30px;\n}\n.iti__country-list {\n border: 0;\n top: 40px;\n width: min(72.2vw, 320px);\n border-radius: 6;\n box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.16);\n}\n.iti__country {\n display: flex;\n align-items: center;\n height: 34px;\n cursor: pointer;\n\n padding: 0 8px;\n}\n.iti__country-name {\n color: var(--palette-textLabel);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin: "0 16px";\n}\n[data-supertokens~="row"] {\n padding-bottom: 30px;\n}\n[data-supertokens~="providerContainer"] {\n padding-top: 9px;\n padding-bottom: 9px;\n}\n[data-supertokens~="providerButton"] {\n border-color: rgb(221, 221, 221) !important;\n}\n[data-supertokens~="providerButton"] {\n min-height: 32px;\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 2px 8px;\n\n background-color: white;\n color: black;\n}\n[data-supertokens~="providerButton"]:hover {\n -webkit-filter: none !important;\n filter: none !important;\n}\n[data-supertokens~="providerButton"]:hover {\n background-color: #fafafa;\n}\n[data-supertokens~="providerButtonLeft"] {\n min-width: 34px;\n margin-left: 66px;\n}\n[data-supertokens~="providerButtonLogo"] {\n height: 30px;\n display: flex;\n}\n[data-supertokens~="providerButtonLogoCenter"] {\n display: flex;\n margin: auto;\n}\n[data-supertokens~="providerButtonText"] {\n font-weight: 400;\n text-align: center;\n justify-content: center;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n display: inline-block;\n}\n[data-supertokens~="providerButtonText"]:only-child {\n margin: 0 auto;\n}\n[data-supertokens~="thirdPartyPasswordlessDivider"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="thirdPartyPasswordlessDividerText"] {\n flex: 1 1;\n margin-top: 0.75em;\n}\n[data-supertokens~="divider"] {\n flex: 3 3;\n}\n[data-supertokens~="providerButton"] {\n margin: auto !important;\n max-width: 240px !important;\n}\n[data-supertokens~="providerButtonLeft"] {\n margin-left: 30px !important;\n}\n'; + '/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n[data-supertokens~="container"] {\n --palette-background: 255, 255, 255;\n --palette-inputBackground: 250, 250, 250;\n --palette-inputBorder: 224, 224, 224;\n --palette-primary: 255, 155, 51;\n --palette-primaryBorder: 238, 141, 35;\n --palette-success: 65, 167, 0;\n --palette-successBackground: 217, 255, 191;\n --palette-error: 255, 23, 23;\n --palette-errorBackground: 255, 241, 235;\n --palette-textTitle: 34, 34, 34;\n --palette-textLabel: 34, 34, 34;\n --palette-textInput: 34, 34, 34;\n --palette-textPrimary: 101, 101, 101;\n --palette-textLink: 0, 118, 255;\n --palette-buttonText: 255, 255, 255;\n --palette-textGray: 128, 128, 128;\n --palette-superTokensBrandingBackground: 242, 245, 246;\n --palette-superTokensBrandingText: 173, 189, 196;\n\n --font-size-0: 12px;\n --font-size-1: 14px;\n --font-size-2: 16px;\n --font-size-3: 19px;\n --font-size-4: 24px;\n}\n/*\n * Default styles.\n */\n@-webkit-keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@keyframes slideTop {\n 0% {\n -webkit-transform: translateY(-5px);\n transform: translateY(-5px);\n }\n 100% {\n -webkit-transform: translateY(0px);\n transform: translateY(0px);\n }\n}\n@-webkit-keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n@keyframes swing-in-top-fwd {\n 0% {\n -webkit-transform: rotateX(-100deg);\n transform: rotateX(-100deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 0;\n }\n 100% {\n -webkit-transform: rotateX(0deg);\n transform: rotateX(0deg);\n -webkit-transform-origin: top;\n transform-origin: top;\n opacity: 1;\n }\n}\n[data-supertokens~="container"] {\n font-family: "Rubik", sans-serif;\n margin: 12px auto;\n margin-top: 26px;\n margin-bottom: 26px;\n width: 420px;\n text-align: center;\n border-radius: 8px;\n box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.16);\n background-color: rgb(var(--palette-background));\n}\n@media (max-width: 440px) {\n [data-supertokens~="container"] {\n width: 95vw;\n }\n}\n[data-supertokens~="row"] {\n margin: 0 auto;\n width: 76%;\n padding-top: 30px;\n padding-bottom: 10px;\n}\n[data-supertokens~="superTokensBranding"] {\n display: block;\n margin: 0 auto;\n background: rgb(var(--palette-superTokensBrandingBackground));\n color: rgb(var(--palette-superTokensBrandingText));\n text-decoration: none;\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n border-radius: 6px 6px 0 0;\n padding: 4px 9px;\n font-weight: 400;\n font-size: var(--font-size-0);\n letter-spacing: 0.4px;\n}\n[data-supertokens~="generalError"] {\n background: rgb(var(--palette-errorBackground));\n padding-top: 10px;\n padding-bottom: 10px;\n margin-bottom: 15px;\n padding-left: 18px;\n padding-right: 18px;\n letter-spacing: 0.2px;\n font-size: var(--font-size-1);\n border-radius: 8px;\n color: rgb(var(--palette-error));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n word-wrap: break-word;\n}\n[data-supertokens~="headerTitle"] {\n font-size: var(--font-size-4);\n line-height: 40px;\n letter-spacing: 0.58px;\n font-weight: 600;\n margin-bottom: 2px;\n color: rgb(var(--palette-textTitle));\n}\n[data-supertokens~="headerSubtitle"] {\n font-weight: 400;\n margin-bottom: 21px;\n}\n[data-supertokens~="headerSubtitle"][data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] {\n max-width: 300px;\n margin-top: 10px;\n}\n[data-supertokens~="privacyPolicyAndTermsAndConditions"] a {\n line-height: 21px;\n}\n/* TODO: split the link style into separate things*/\n/* We add this before primary and secondary text, because if they are applied to the same element the other ones take priority */\n[data-supertokens~="link"] {\n padding-left: 3px;\n padding-right: 3px;\n color: rgb(var(--palette-textLink));\n font-size: var(--font-size-1);\n cursor: pointer;\n letter-spacing: 0.16px;\n line-height: 26px;\n}\n[data-supertokens~="primaryText"] {\n font-size: var(--font-size-1);\n font-weight: 500;\n letter-spacing: 0.4px;\n line-height: 21px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="secondaryText"] {\n font-size: var(--font-size-1);\n font-weight: 300;\n letter-spacing: 0.4px;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="divider"] {\n margin-top: 1em;\n margin-bottom: 1em;\n border-bottom: 0.3px solid #dddddd;\n align-items: center;\n padding-bottom: 5px;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="generalSuccess"] {\n color: rgb(var(--palette-success));\n font-size: var(--font-size-1);\n background: rgb(var(--palette-successBackground));\n -webkit-animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n animation: swing-in-top-fwd 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;\n padding: 9px 15px 9px 15px;\n border-radius: 6px;\n display: inline-block;\n}\n[data-supertokens~="spinner"] {\n width: 80px;\n height: auto;\n padding-top: 20px;\n padding-bottom: 40px;\n margin: 0 auto;\n}\n[data-supertokens~="error"] {\n color: rgb(var(--palette-error));\n}\n[data-supertokens~="linkButton"] {\n font-family: "Rubik", sans-serif;\n background-color: transparent;\n border: 0;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n margin-top: 10px;\n margin-bottom: 40px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"] svg {\n margin-right: 0.3em;\n}\n[data-supertokens~="secondaryLinkWithLeftArrow"]:hover svg {\n position: relative;\n left: -4px;\n}\n[data-supertokens~="button"] {\n font-family: "Rubik", sans-serif;\n background-color: rgb(var(--palette-primary));\n color: rgb(var(--palette-buttonText));\n width: 100%;\n height: 34px;\n font-weight: 700;\n border-width: 1px;\n border-style: solid;\n border-radius: 6px;\n border-color: rgb(var(--palette-primaryBorder));\n background-position: center;\n transition: all 0.4s;\n background-size: 12000%;\n cursor: pointer;\n}\n[data-supertokens~="button"]:disabled {\n border: none;\n cursor: no-drop;\n}\n[data-supertokens~="button"]:active {\n outline: none;\n transition: all 0s;\n background-size: 100%;\n -webkit-filter: brightness(0.85);\n filter: brightness(0.85);\n}\n[data-supertokens~="button"]:focus {\n outline: none;\n}\n[data-supertokens~="backButtonCommon"] {\n width: 16px;\n height: 13px;\n}\n[data-supertokens~="backButton"] {\n cursor: pointer;\n border: none;\n background-color: transparent;\n padding: 0px;\n}\n[data-supertokens~="backButtonPlaceholder"] {\n display: block;\n}\n[data-supertokens~="delayedRender"] {\n -webkit-animation-duration: 0.1s;\n animation-duration: 0.1s;\n -webkit-animation-name: animate-fade;\n animation-name: animate-fade;\n -webkit-animation-delay: 0.2s;\n animation-delay: 0.2s;\n -webkit-animation-fill-mode: backwards;\n animation-fill-mode: backwards;\n}\n@-webkit-keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n@keyframes animate-fade {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] {\n display: flex;\n flex-direction: column;\n margin-top: 10px;\n gap: 24px;\n}\n[data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] {\n font-weight: 400;\n}\n[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] {\n font-weight: 500;\n position: relative;\n left: -6px; /* half the width of the left arrow */\n}\n@media (max-width: 360px) {\n [data-supertokens~="footerLinkGroupVert"] {\n flex-direction: column;\n }\n [data-supertokens~="footerLinkGroupVert"] > div {\n margin: 0 auto;\n }\n}\n[data-supertokens~="footerLinkGroupVert"] div:only-child {\n margin-left: auto;\n margin-right: auto;\n margin-top: 14px;\n}\n/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved.\n *\n * This software is licensed under the Apache License, Version 2.0 (the\n * "License") as published by the Apache Software Foundation.\n *\n * You may not use this file except in compliance with the License. You may\n * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * License for the specific language governing permissions and limitations\n * under the License.\n */\n[data-supertokens~="inputContainer"] {\n margin-top: 6px;\n}\n[data-supertokens~="inputWrapper"] {\n box-sizing: border-box;\n width: 100%;\n display: flex;\n align-items: center;\n background-color: rgb(var(--palette-inputBackground));\n height: 34px;\n border-radius: 6px;\n border: 1px solid rgb(var(--palette-inputBorder));\n}\n[data-supertokens~="inputWrapper"][focus-within] {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n[data-supertokens~="inputWrapper"]:focus-within {\n background-color: rgba(var(--palette-inputBackground), 0.25);\n border: 1px solid rgb(var(--palette-primary));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-primary), 0.25);\n outline: none;\n}\n[data-supertokens~="inputError"] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n[data-supertokens~="inputError"][focus-within] {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n[data-supertokens~="inputError"]:focus-within {\n border: 1px solid rgb(var(--palette-error));\n box-shadow: 0 0 0 0.2rem rgba(var(--palette-error), 0.25);\n outline: none;\n}\n[data-supertokens~="input"] {\n box-sizing: border-box;\n padding-left: 15px;\n -webkit-filter: none;\n filter: none;\n color: rgb(var(--palette-textInput));\n background-color: transparent;\n border-radius: 6px;\n font-size: var(--font-size-1);\n border: none;\n padding-right: 25px;\n letter-spacing: 1.2px;\n flex: 9 1 75%;\n width: 75%;\n height: 32px;\n}\n[data-supertokens~="input"]:focus {\n border: none;\n outline: none;\n}\n[data-supertokens~="input"]:-webkit-autofill,\n[data-supertokens~="input"]:-webkit-autofill:hover,\n[data-supertokens~="input"]:-webkit-autofill:focus,\n[data-supertokens~="input"]:-webkit-autofill:active {\n -webkit-text-fill-color: rgb(var(--palette-textInput));\n box-shadow: 0 0 0 30px rgb(var(--palette-inputBackground)) inset;\n}\n[data-supertokens~="inputAdornment"] {\n justify-content: center;\n margin-right: 5px;\n}\n[data-supertokens~="showPassword"] {\n cursor: pointer;\n}\n[data-supertokens~="forgotPasswordLink"] {\n margin-top: 10px;\n}\n[data-supertokens~="enterEmailSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n word-break: break-word;\n}\n[data-supertokens~="submitNewPasswordSuccessMessage"] {\n margin-top: 15px;\n margin-bottom: 15px;\n}\n[data-supertokens~="inputErrorMessage"] {\n padding-top: 5px;\n padding-bottom: 5px;\n color: rgb(var(--palette-error));\n line-height: 24px;\n font-weight: 400;\n font-size: var(--font-size-1);\n text-align: left;\n -webkit-animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n animation: slideTop 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n max-width: 330px;\n}\n@media (max-width: 440px) {\n [data-supertokens~="inputErrorMessage"] {\n max-width: 250px;\n }\n}\n[data-supertokens~="inputErrorSymbol"] {\n margin-right: 5px;\n top: 1px;\n position: relative;\n left: 2px;\n}\n[data-supertokens~="label"] {\n text-align: left;\n font-weight: 600;\n font-size: var(--font-size-1);\n line-height: 24px;\n color: rgb(var(--palette-textLabel));\n}\n[data-supertokens~="formRow"] {\n display: flex;\n flex-direction: column;\n padding-top: 0px;\n padding-bottom: 34px;\n}\n[data-supertokens~="formRow"][data-supertokens~="hasError"] {\n padding-bottom: 0;\n}\n[data-supertokens~="sendVerifyEmailIcon"] {\n margin-top: 11px;\n}\n[data-supertokens~="headerTinyTitle"] {\n margin-top: 13px;\n font-size: var(--font-size-3);\n letter-spacing: 1.1px;\n font-weight: 500;\n line-height: 28px;\n}\n[data-supertokens~="sendVerifyEmailText"] {\n line-height: 21px;\n font-size: var(--font-size-1);\n text-align: center;\n font-weight: 300;\n letter-spacing: 0.8px;\n}\n[data-supertokens~="secondaryLinkWithArrow"] {\n margin-top: 10px;\n margin-bottom: 30px;\n cursor: pointer;\n}\n[data-supertokens~="secondaryLinkWithArrow"]:hover {\n position: relative;\n left: 2px;\n word-spacing: 4px;\n}\n[data-supertokens~="sendVerifyEmailResend"] {\n margin-top: 13px;\n font-weight: 300;\n}\n[data-supertokens~="sendVerifyEmailResend"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="noFormRow"] {\n padding-bottom: 25px;\n}\n[data-supertokens~="emailVerificationButtonWrapper"] {\n padding-top: 25px;\n max-width: 96px;\n margin: 0 auto;\n}\n[data-supertokens~="withBackButton"] {\n position: relative;\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="resendEmailLink"] {\n display: inline-block;\n}\n[data-supertokens~="generalSuccess"] {\n margin-bottom: 20px;\n -webkit-animation: swingIn 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) alternate 2 both;\n animation: swingIn 1s cubic-bezier(0.175, 0.885, 0.32, 1.275) alternate 2 both;\n}\n[data-supertokens~="codeInputLabelWrapper"] {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n[data-supertokens~="headerSubtitle"] strong {\n max-width: 100%;\n display: inline-block;\n vertical-align: bottom;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n[data-supertokens~="sendCodeText"] {\n margin-top: 15px;\n margin-bottom: 20px;\n}\n[data-supertokens~="sendCodeText"] strong {\n max-width: 100%;\n display: inline-block;\n vertical-align: bottom;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n[data-supertokens~="resendCodeBtn"] {\n width: auto;\n margin-top: 0;\n line-height: 24px;\n}\n[data-supertokens~="resendCodeBtn"]:hover {\n text-decoration: underline;\n}\n[data-supertokens~="resendCodeBtn"]:disabled {\n color: rgb(var(--palette-textPrimary));\n cursor: default;\n text-decoration: none;\n}\n[data-supertokens~="phoneInputLibRoot"] {\n display: flex;\n align-items: center;\n}\n[data-supertokens~="phoneInputWrapper"] {\n display: flex;\n align-items: center;\n}\n[data-supertokens~="phoneInputWrapper"] .iti [data-supertokens~="input"] {\n padding-left: 15px;\n}\n[data-supertokens~="phoneInputWrapper"] .iti {\n flex: 1 1;\n min-width: 0;\n width: 100%;\n background: transparent;\n border: none;\n color: inherit;\n outline: none;\n}\n[data-supertokens~="continueButtonWrapper"] {\n margin-top: 10px;\n margin-bottom: 30px;\n}\n.iti__country-list {\n border: 0;\n top: 40px;\n width: min(72.2vw, 320px);\n border-radius: 6;\n box-shadow: 0px 0px 3px 0px rgba(0, 0, 0, 0.16);\n}\n.iti__country {\n display: flex;\n align-items: center;\n height: 34px;\n cursor: pointer;\n\n padding: 0 8px;\n}\n.iti__country-name {\n color: var(--palette-textLabel);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n margin: "0 16px";\n}\n[data-supertokens~="row"] {\n padding-bottom: 30px;\n}\n[data-supertokens~="providerContainer"] {\n padding-top: 9px;\n padding-bottom: 9px;\n}\n[data-supertokens~="providerButton"] {\n border-color: rgb(221, 221, 221) !important;\n}\n[data-supertokens~="providerButton"] {\n min-height: 32px;\n display: flex;\n flex-direction: row;\n align-items: center;\n padding: 2px 8px;\n\n background-color: white;\n color: black;\n}\n[data-supertokens~="providerButton"]:hover {\n -webkit-filter: none !important;\n filter: none !important;\n}\n[data-supertokens~="providerButton"]:hover {\n background-color: #fafafa;\n}\n[data-supertokens~="providerButtonLeft"] {\n min-width: 34px;\n margin-left: 66px;\n}\n[data-supertokens~="providerButtonLogo"] {\n height: 30px;\n display: flex;\n}\n[data-supertokens~="providerButtonLogoCenter"] {\n display: flex;\n margin: auto;\n}\n[data-supertokens~="providerButtonText"] {\n font-weight: 400;\n text-align: center;\n justify-content: center;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n display: inline-block;\n}\n[data-supertokens~="providerButtonText"]:only-child {\n margin: 0 auto;\n}\n[data-supertokens~="thirdPartyPasswordlessDivider"] {\n padding-top: 5px;\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n color: rgb(var(--palette-textPrimary));\n}\n[data-supertokens~="thirdPartyPasswordlessDividerText"] {\n flex: 1 1;\n margin-top: 0.75em;\n}\n[data-supertokens~="divider"] {\n flex: 3 3;\n}\n[data-supertokens~="providerButton"] {\n margin: auto !important;\n max-width: 240px !important;\n}\n[data-supertokens~="providerButtonLeft"] {\n margin-left: 30px !important;\n}\n'; var ThemeBase = function (_a) { var children = _a.children, @@ -303,14 +306,18 @@ var SignInUpTheme = function (props) { }; function SignInUpThemeWrapper(props) { var hasFont = translations.hasFontDefined(props.config.rootStyle); + var currentDynamicLoginMethods = uiEntry.useDynamicLoginMethods(); // By defining it in a single object here TSC can deduce the connection between props var childProps = props.passwordlessRecipe !== undefined && props.pwlessChildProps !== undefined ? genericComponentOverrideContext.__assign(genericComponentOverrideContext.__assign({}, props), { - activeScreen: passwordlessprebuiltui.getActiveScreen({ - config: props.pwlessChildProps.config, - featureState: props.pwlessState, - }), + activeScreen: passwordlessprebuiltui.getActiveScreen( + { + config: props.pwlessChildProps.config, + featureState: props.pwlessState, + }, + currentDynamicLoginMethods + ), pwlessChildProps: props.pwlessChildProps, passwordlessRecipe: props.passwordlessRecipe, }) @@ -559,7 +566,11 @@ var ThirdPartyPasswordlessPreBuiltUI = /** @class */ (function (_super) { ) ); } - } else if (componentName === "linkClickedScreen") { + } else if ( + "linkClickedScreen" === componentName || + "otp-phone" === componentName || + "otp-email" === componentName + ) { if (_this.passwordlessPreBuiltUI === undefined) { throw new Error( "Embedding this component requires the passwordless recipe to be enabled. Please check the value of disablePasswordless in the configuration." @@ -677,12 +688,22 @@ var ThirdPartyPasswordlessPreBuiltUI = /** @class */ (function (_super) { ThirdPartyPasswordlessPreBuiltUI.PasswordlessLinkClicked = function (prop) { return _a.getFeatureComponent("linkClickedScreen", prop); }; + ThirdPartyPasswordlessPreBuiltUI.MfaOtpPhone = function (prop) { + return _a.getFeatureComponent("otp-phone", prop); + }; + ThirdPartyPasswordlessPreBuiltUI.MfaOtpEmail = function (prop) { + return _a.getFeatureComponent("otp-email", prop); + }; return ThirdPartyPasswordlessPreBuiltUI; })(uiEntry.RecipeRouter); var SignInAndUp = ThirdPartyPasswordlessPreBuiltUI.SignInAndUp; var ThirdPartySignInAndUpCallback = ThirdPartyPasswordlessPreBuiltUI.ThirdPartySignInAndUpCallback; var PasswordlessLinkClicked = ThirdPartyPasswordlessPreBuiltUI.PasswordlessLinkClicked; +var MfaOtpPhone = passwordlessprebuiltui.PasswordlessPreBuiltUI.MfaOtpPhone; +var MfaOtpEmail = passwordlessprebuiltui.PasswordlessPreBuiltUI.MfaOtpEmail; +exports.MfaOtpEmail = MfaOtpEmail; +exports.MfaOtpPhone = MfaOtpPhone; exports.PasswordlessLinkClicked = PasswordlessLinkClicked; exports.SignInAndUp = SignInAndUp; exports.SignInUpTheme = SignInUpThemeWrapper; diff --git a/lib/ts/components/assets/otpEmailIcon.tsx b/lib/ts/components/assets/otpEmailIcon.tsx new file mode 100644 index 000000000..665747f81 --- /dev/null +++ b/lib/ts/components/assets/otpEmailIcon.tsx @@ -0,0 +1,17 @@ +export const OTPEmailIcon = () => ( + + + + + + + + + +); diff --git a/lib/ts/components/assets/otpSMSIcon.tsx b/lib/ts/components/assets/otpSMSIcon.tsx new file mode 100644 index 000000000..8e0864e81 --- /dev/null +++ b/lib/ts/components/assets/otpSMSIcon.tsx @@ -0,0 +1,17 @@ +export const OTPSMSIcon = () => ( + + + + + + + + + +); diff --git a/lib/ts/components/errorBoundary.tsx b/lib/ts/components/errorBoundary.tsx deleted file mode 100644 index 0cab7dbbf..000000000 --- a/lib/ts/components/errorBoundary.tsx +++ /dev/null @@ -1,49 +0,0 @@ -/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. - * - * This software is licensed under the Apache License, Version 2.0 (the - * "License") as published by the Apache Software Foundation. - * - * You may not use this file except in compliance with the License. You may - * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ - -/* - * Imports. - */ -import React from "react"; -import { Fragment } from "react"; - -import type { ErrorInfo, ReactNode } from "react"; - -type ErrorBoundaryState = { hasError: boolean }; -/* - * Component. - */ -export default class ErrorBoundary extends React.Component { - constructor(props: { hasError: boolean }) { - super(props); - this.state = { hasError: false }; - } - - static getDerivedStateFromError(): ErrorBoundaryState { - return { hasError: true }; - } - - componentDidCatch(error: Error, errorInfo: ErrorInfo): void { - console.info(error, errorInfo); - } - - render(): JSX.Element | ReactNode | undefined { - if (this.state.hasError) { - return ; - } - - return this.props.children; - } -} diff --git a/lib/ts/components/featureWrapper.tsx b/lib/ts/components/featureWrapper.tsx index 6a4366767..dea33ce57 100644 --- a/lib/ts/components/featureWrapper.tsx +++ b/lib/ts/components/featureWrapper.tsx @@ -29,8 +29,6 @@ import { TranslationContextProvider } from "../translation/translationContext"; import { useUserContext } from "../usercontext"; import { mergeObjects } from "../utils"; -import ErrorBoundary from "./errorBoundary"; - import type { GetLoginMethodsResponseNormalized } from "../recipe/multitenancy/types"; import type { TranslationStore } from "../translation/translationHelpers"; import type { PropsWithChildren } from "react"; @@ -74,15 +72,13 @@ export default function FeatureWrapper({ return ( - - - {children} - - + + {children} + ); } diff --git a/lib/ts/recipe/emailpassword/components/themes/styles.css b/lib/ts/recipe/emailpassword/components/themes/styles.css index bcaaa11be..a43cbf734 100644 --- a/lib/ts/recipe/emailpassword/components/themes/styles.css +++ b/lib/ts/recipe/emailpassword/components/themes/styles.css @@ -201,22 +201,6 @@ align-items: center; } -[data-supertokens~="backButtonCommon"] { - width: 16px; - height: 13px; -} - -[data-supertokens~="backButton"] { - cursor: pointer; - border: none; - background-color: transparent; - padding: 0px; -} - -[data-supertokens~="backButtonPlaceholder"] { - display: block; -} - [data-supertokens~="resendEmailLink"] { display: inline-block; } diff --git a/lib/ts/recipe/multitenancy/components/features/dynamicLoginMethodsSpinner/index.tsx b/lib/ts/recipe/multitenancy/components/features/dynamicLoginMethodsSpinner/index.tsx index 2680f8c70..b801a5328 100644 --- a/lib/ts/recipe/multitenancy/components/features/dynamicLoginMethodsSpinner/index.tsx +++ b/lib/ts/recipe/multitenancy/components/features/dynamicLoginMethodsSpinner/index.tsx @@ -13,7 +13,6 @@ * under the License. */ import { ComponentOverrideContext } from "../../../../../components/componentOverride/componentOverrideContext"; -import ErrorBoundary from "../../../../../components/errorBoundary"; import { WithOrWithoutShadowDom } from "../../../../../components/featureWrapper"; import { useRecipeComponentOverrideContext } from "../../../componentOverrideContext"; import Multitenancy from "../../../recipe"; @@ -28,11 +27,9 @@ const DynamicLoginMethodsSpinner: React.FC = () => { return ( - - - - - + + + ); }; diff --git a/lib/ts/recipe/passwordless/components/features/mfa/index.tsx b/lib/ts/recipe/passwordless/components/features/mfa/index.tsx new file mode 100644 index 000000000..2f533420f --- /dev/null +++ b/lib/ts/recipe/passwordless/components/features/mfa/index.tsx @@ -0,0 +1,480 @@ +/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Imports. + */ +import * as React from "react"; +import { Fragment } from "react"; +import { useMemo } from "react"; +import { useRef } from "react"; +import { useEffect } from "react"; +import { WindowHandlerReference } from "supertokens-web-js/utils/windowHandler"; + +import { redirectToAuth } from "../../../../.."; +import { ComponentOverrideContext } from "../../../../../components/componentOverride/componentOverrideContext"; +import FeatureWrapper from "../../../../../components/featureWrapper"; +import { useUserContext } from "../../../../../usercontext"; +import { + clearErrorQueryParam, + getQueryParams, + getRedirectToPathFromURL, + useOnMountAPICall, +} from "../../../../../utils"; +import MultiFactorAuth from "../../../../multifactorauth/recipe"; +import SessionRecipe from "../../../../session/recipe"; +import { getPhoneNumberUtils } from "../../../phoneNumberUtils"; +import MFAThemeWrapper from "../../themes/mfa"; +import { defaultTranslationsPasswordless } from "../../themes/translations"; + +import type { FeatureBaseProps } from "../../../../../types"; +import type Recipe from "../../../recipe"; +import type { AdditionalLoginAttemptInfoProperties, ComponentOverrideMap, MFAChildProps } from "../../../types"; +import type { MFAAction, MFAState, NormalisedConfig } from "../../../types"; +import type { MFAFactorInfo } from "supertokens-web-js/recipe/multifactorauth/types"; +import type { RecipeInterface } from "supertokens-web-js/recipe/passwordless"; +import type { PasswordlessFlowType } from "supertokens-web-js/recipe/thirdpartypasswordless"; + +export const useSuccessInAnotherTabChecker = ( + callingConsumeCodeRef: React.MutableRefObject, + recipeImpl: RecipeInterface, + state: MFAState, + dispatch: React.Dispatch, + userContext: any +) => { + useEffect(() => { + // We only need to start checking this if we have an active login attempt + if (state.loginAttemptInfo && !state.successInAnotherTab) { + const checkSessionIntervalHandle = setInterval(async () => { + if (callingConsumeCodeRef.current === false) { + const currLoginAttempt = await recipeImpl.getLoginAttemptInfo({ userContext }); + if ( + currLoginAttempt === undefined || + currLoginAttempt.deviceId !== state.loginAttemptInfo?.deviceId + ) { + dispatch({ type: "successInAnotherTab" }); + } + } + }, 2000); + + return () => { + clearInterval(checkSessionIntervalHandle); + }; + } + // Nothing to clean up + return; + }, [state.loginAttemptInfo, state.successInAnotherTab]); +}; + +export const useFeatureReducer = (): [MFAState, React.Dispatch] => { + return React.useReducer( + (oldState: MFAState, action: MFAAction): MFAState => { + switch (action.type) { + case "load": + return { + loaded: true, + error: action.error, + loginAttemptInfo: action.loginAttemptInfo, + isSetupAllowed: action.isAllowedToSetup, + successInAnotherTab: false, + }; + case "resendCode": + if (!oldState.loginAttemptInfo) { + return oldState; + } + return { + ...oldState, + error: undefined, + loginAttemptInfo: { + ...oldState.loginAttemptInfo, + lastResend: action.timestamp, + }, + }; + case "restartFlow": + return { + ...oldState, + error: action.error, + loginAttemptInfo: undefined, + }; + case "setError": + return { + ...oldState, + loaded: true, + error: action.error, + }; + case "startVerify": + return { + ...oldState, + loaded: true, + loginAttemptInfo: action.loginAttemptInfo, + error: undefined, + successInAnotherTab: false, + }; + case "successInAnotherTab": + return { + ...oldState, + successInAnotherTab: true, + }; + default: + return oldState; + } + }, + { + error: undefined, + loaded: false, + loginAttemptInfo: undefined, + isSetupAllowed: false, + successInAnotherTab: false, + }, + (initArg) => { + let error: string | undefined = undefined; + const errorQueryParam = getQueryParams("error"); + if (errorQueryParam !== null) { + error = "SOMETHING_WENT_WRONG_ERROR"; + } + return { + ...initArg, + error, + }; + } + ); +}; + +export function useChildProps( + recipe: Recipe, + recipeImplementation: RecipeInterface, + state: MFAState, + contactMethod: "PHONE" | "EMAIL", + userContext: any, + history: any +): MFAChildProps { + return useMemo(() => { + return { + onSuccess: () => { + const redirectToPath = getRedirectToPathFromURL(); + const redirectInfo = + redirectToPath === undefined + ? undefined + : { + rid: "passwordless", + successRedirectContext: { + action: "SUCCESS", + isNewRecipeUser: false, + user: undefined, + redirectToPath, + }, + }; + + return SessionRecipe.getInstanceOrThrow().validateGlobalClaimsAndHandleSuccessRedirection( + redirectInfo, + userContext, + history + ); + }, + onSignOutClicked: async () => { + await SessionRecipe.getInstanceOrThrow().signOut({ userContext }); + await recipeImplementation.clearLoginAttemptInfo({ userContext }); + await redirectToAuth({ redirectBack: false, history: history }); + }, + onBackButtonClicked: () => { + // If we don't have history available this would mean we are not using react-router-dom, so we use window's history + if (history === undefined) { + return WindowHandlerReference.getReferenceOrThrow().windowHandler.getWindowUnsafe().history.back(); + } + // If we do have history and goBack function on it this means we are using react-router-dom v5 or lower + if (history.goBack !== undefined) { + return history.goBack(); + } + // If we reach this code this means we are using react-router-dom v6 + return history(-1); + }, + onFactorChooserButtonClicked: () => { + return MultiFactorAuth.getInstanceOrThrow().redirectToFactorChooser(false, history); + }, + recipeImplementation: recipeImplementation, + config: recipe.config, + contactMethod, + }; + }, [contactMethod, state, recipeImplementation]); +} + +export const MFAFeature: React.FC< + FeatureBaseProps & { + contactMethod: "PHONE" | "EMAIL"; + flowType: PasswordlessFlowType; + recipe: Recipe; + useComponentOverrides: () => ComponentOverrideMap; + } +> = (props) => { + const recipeComponentOverrides = props.useComponentOverrides(); + const userContext = useUserContext(); + + const callingConsumeCodeRef = useRef(false); + const [state, dispatch] = useFeatureReducer(); + const recipeImplementation = React.useMemo( + () => + props.recipe && + getModifiedRecipeImplementation( + props.recipe.webJSRecipe, + props.recipe.config, + dispatch, + callingConsumeCodeRef + ), + [props.recipe] + ); + + useOnLoad(props, recipeImplementation, dispatch, userContext); + + const childProps = useChildProps( + props.recipe, + recipeImplementation, + state, + props.contactMethod, + userContext, + props.history + )!; + useSuccessInAnotherTabChecker(callingConsumeCodeRef, recipeImplementation, state, dispatch, userContext); + + return ( + + + + {/* No custom theme, use default. */} + {props.children === undefined && ( + + )} + + {/* Otherwise, custom theme is provided, propagate props. */} + {props.children && + React.Children.map(props.children, (child) => { + if (React.isValidElement(child)) { + return React.cloneElement(child, { + ...childProps, + featureState: state, + dispatch: dispatch, + }); + } + return child; + })} + + + + ); +}; + +export default MFAFeature; + +function useOnLoad( + props: React.PropsWithChildren< + { history?: any } & { children?: React.ReactNode } & { + contactMethod: "PHONE" | "EMAIL"; + flowType: PasswordlessFlowType; + recipe: Recipe; + useComponentOverrides: () => ComponentOverrideMap; + } + >, + recipeImplementation: RecipeInterface, + dispatch: React.Dispatch, + userContext: any +) { + const fetchMFAInfo = React.useCallback( + async () => MultiFactorAuth.getInstanceOrThrow().webJSRecipe.getMFAInfo({ userContext }), + [userContext] + ); + const handleLoadError = React.useCallback( + () => dispatch({ type: "setError", error: "SOMETHING_WENT_WRONG_ERROR" }), + [dispatch] + ); + const onLoad = React.useCallback( + async (mfaInfo: { factors: MFAFactorInfo; email?: string; phoneNumber?: string }) => { + let error: string | undefined = undefined; + const errorQueryParam = getQueryParams("error"); + const doSetup = getQueryParams("setup"); + if (errorQueryParam !== null) { + error = "SOMETHING_WENT_WRONG_ERROR"; + } + const loginAttemptInfo = + await recipeImplementation.getLoginAttemptInfo({ + userContext, + }); + + const isAlreadySetup = + props.contactMethod === "EMAIL" + ? mfaInfo.factors.isAlreadySetup.includes("otp-email") + : mfaInfo.factors.isAlreadySetup.includes("otp-phone"); + const isAllowedToSetup = + props.contactMethod === "EMAIL" + ? mfaInfo.factors.isAllowedToSetup.includes("otp-email") + : mfaInfo.factors.isAllowedToSetup.includes("otp-phone"); + + if (!loginAttemptInfo) { + // We can assume these are defined if we use these, we check that the mfaInfo states that the related factor has been set up + const createCodeInfo = + props.contactMethod === "EMAIL" ? { email: mfaInfo.email! } : { phoneNumber: mfaInfo.phoneNumber! }; + const factorId = props.contactMethod === "EMAIL" ? "otp-email" : "otp-phone"; + + if (isAlreadySetup && doSetup !== "true") { + try { + // createCode also dispatches the necessary events + await recipeImplementation!.createCode({ + ...createCodeInfo, + userContext, + }); + } catch (err) { + dispatch({ type: "setError", error: "SOMETHING_WENT_WRONG_ERROR" }); + } + } else if (!mfaInfo.factors.isAllowedToSetup.includes(factorId)) { + dispatch({ + type: "load", + loginAttemptInfo: undefined, + isAllowedToSetup: false, + error: "PWLESS_MFA_OTP_NOT_ALLOWED_TO_SETUP", + }); + } else { + // since loginAttemptInfo is undefined, this will ask the user for the email/phone + dispatch({ type: "load", loginAttemptInfo, error, isAllowedToSetup: true }); + } + } else { + // No need to check if the component is unmounting, since this has no effect then. + dispatch({ type: "load", loginAttemptInfo, error, isAllowedToSetup }); + } + }, + [dispatch, recipeImplementation, props.contactMethod, userContext] + ); + + useOnMountAPICall(fetchMFAInfo, onLoad, handleLoadError); +} + +function getModifiedRecipeImplementation( + originalImpl: RecipeInterface, + config: NormalisedConfig, + dispatch: React.Dispatch, + callingConsumeCodeRef: React.MutableRefObject +): RecipeInterface { + return { + ...originalImpl, + createCode: async (input) => { + let contactInfo; + const phoneNumberUtils = await getPhoneNumberUtils(); + if ("email" in input) { + contactInfo = input.email; + } else { + contactInfo = phoneNumberUtils.formatNumber( + input.phoneNumber, + config.signInUpFeature.defaultCountry || "", + phoneNumberUtils.numberFormat.E164 + ); + } + + // This contactMethod refers to the one that was used to deliver the login info + const contactMethod: "EMAIL" | "PHONE" = "email" in input ? "EMAIL" : "PHONE"; + const additionalAttemptInfo = { + lastResend: Date.now(), + contactMethod, + contactInfo, + redirectToPath: getRedirectToPathFromURL(), + }; + + const res = await originalImpl.createCode({ + ...input, + userContext: { ...input.userContext, additionalAttemptInfo }, + }); + + if (res.status === "OK") { + const loginAttemptInfo = (await originalImpl.getLoginAttemptInfo({ + userContext: input.userContext, + }))!; + dispatch({ type: "startVerify", loginAttemptInfo }); + } + return res; + }, + resendCode: async (input) => { + /** + * In this case we want the code that is calling resendCode in the + * UI to handle STGeneralError so we let this throw + */ + const res = await originalImpl.resendCode(input); + + if (res.status === "OK") { + const loginAttemptInfo = await originalImpl.getLoginAttemptInfo({ + userContext: input.userContext, + }); + + if (loginAttemptInfo !== undefined) { + const timestamp = Date.now(); + + await originalImpl.setLoginAttemptInfo({ + userContext: input.userContext, + attemptInfo: { + ...loginAttemptInfo, + lastResend: timestamp, + }, + }); + dispatch({ type: "resendCode", timestamp }); + } + } else if (res.status === "RESTART_FLOW_ERROR") { + await originalImpl.clearLoginAttemptInfo({ + userContext: input.userContext, + }); + + dispatch({ type: "restartFlow", error: "ERROR_SIGN_IN_UP_RESEND_RESTART_FLOW" }); + } + return res; + }, + + consumeCode: async (input) => { + // We need to set call callingConsumeCodeRef to true while consumeCode is running, + // so we don't detect the login attempt disappearing too early and + // go to successInAnotherTab too early + callingConsumeCodeRef.current = true; + + const res = await originalImpl.consumeCode(input); + + if (res.status === "RESTART_FLOW_ERROR") { + await originalImpl.clearLoginAttemptInfo({ + userContext: input.userContext, + }); + + dispatch({ type: "restartFlow", error: "ERROR_SIGN_IN_UP_CODE_CONSUME_RESTART_FLOW" }); + } else if (res.status === "SIGN_IN_UP_NOT_ALLOWED") { + // This should never happen, but technically possible based on the API specs + // so we keep this here to cover all cases + await originalImpl.clearLoginAttemptInfo({ + userContext: input.userContext, + }); + + dispatch({ type: "restartFlow", error: res.reason }); + } else if (res.status === "OK") { + await originalImpl.clearLoginAttemptInfo({ + userContext: input.userContext, + }); + // we wait for the redirection to happen in this case. + } + + callingConsumeCodeRef.current = false; + + return res; + }, + + clearLoginAttemptInfo: async (input) => { + await originalImpl.clearLoginAttemptInfo({ + userContext: input.userContext, + }); + clearErrorQueryParam(); + dispatch({ type: "restartFlow", error: undefined }); + }, + }; +} diff --git a/lib/ts/recipe/passwordless/components/themes/mfa/index.tsx b/lib/ts/recipe/passwordless/components/themes/mfa/index.tsx new file mode 100644 index 000000000..75c608b97 --- /dev/null +++ b/lib/ts/recipe/passwordless/components/themes/mfa/index.tsx @@ -0,0 +1,182 @@ +/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +import React from "react"; + +import { SuperTokensBranding } from "../../../../../components/SuperTokensBranding"; +import { hasFontDefined } from "../../../../../styles/styles"; +import { useTranslation } from "../../../../../translation/translationContext"; +import UserContextWrapper from "../../../../../usercontext/userContextWrapper"; +import GeneralError from "../../../../emailpassword/components/library/generalError"; +import { AccessDeniedScreen } from "../../../../session/prebuiltui"; +import { CloseTabScreen } from "../signInUp/closeTabScreen"; +import { EmailForm } from "../signInUp/emailForm"; +import { PhoneForm } from "../signInUp/phoneForm"; +import { UserInputCodeForm } from "../signInUp/userInputCodeForm"; +import { ThemeBase } from "../themeBase"; + +import { MFAFooter } from "./mfaFooter"; +import { MFAHeader } from "./mfaHeader"; +import { MFAOTPFooter } from "./mfaOTPFooter"; +import { MFAOTPHeader } from "./mfaOTPHeader"; + +import type { MFAProps } from "../../../types"; + +export enum MFAScreens { + CloseTab, + EmailForm, + PhoneForm, + UserInputCodeForm, + AccessDenied, +} + +const MFATheme: React.FC = ({ + activeScreen, + featureState, + onBackButtonClicked, + ...props +}) => { + const t = useTranslation(); + const commonProps = { + recipeImplementation: props.recipeImplementation, + config: props.config, + clearError: () => props.dispatch({ type: "setError", error: undefined }), + onError: (error: string) => props.dispatch({ type: "setError", error }), + error: featureState.error, + }; + + if (!featureState.loaded) { + return null; + } + + return activeScreen === MFAScreens.CloseTab ? ( + + ) : activeScreen === MFAScreens.AccessDenied ? ( + + ) : ( +
+
+ { + + {activeScreen === MFAScreens.UserInputCodeForm ? ( + + ) : ( + + )} + {featureState.error !== undefined && } + {activeScreen === MFAScreens.EmailForm ? ( + + } + /> + ) : activeScreen === MFAScreens.PhoneForm ? ( + + } + /> + ) : activeScreen === MFAScreens.UserInputCodeForm ? ( + + } + /> + ) : null} + + } +
+ +
+ ); +}; + +function MFAThemeWrapper(props: MFAProps): JSX.Element { + const hasFont = hasFontDefined(props.config.rootStyle); + + const activeScreen = getActiveScreen(props); + + let activeStyle; + if (activeScreen === MFAScreens.CloseTab) { + activeStyle = props.config.signInUpFeature.closeTabScreenStyle; + } else if (activeScreen === MFAScreens.UserInputCodeForm) { + activeStyle = props.config.signInUpFeature.userInputCodeFormStyle; + } else if (activeScreen === MFAScreens.EmailForm) { + activeStyle = props.config.signInUpFeature.emailOrPhoneFormStyle; + } else if (activeScreen === MFAScreens.PhoneForm) { + activeStyle = props.config.signInUpFeature.emailOrPhoneFormStyle; + } else { + activeStyle = ""; // styling the access denied screen is handled through the session recipe + } + + return ( + + + + + + ); +} + +export default MFAThemeWrapper; + +export function getActiveScreen(props: Pick) { + if (props.featureState.successInAnotherTab) { + return MFAScreens.CloseTab; + } else if ( + props.featureState.error === "PWLESS_MFA_OTP_NOT_ALLOWED_TO_SETUP" || + (props.featureState.isSetupAllowed === false && props.featureState.loginAttemptInfo === undefined) + ) { + return MFAScreens.AccessDenied; + } else if (props.featureState.loginAttemptInfo) { + return MFAScreens.UserInputCodeForm; + } else if (props.contactMethod === "EMAIL") { + return MFAScreens.EmailForm; + } else if (props.contactMethod === "PHONE") { + return MFAScreens.PhoneForm; + } + + throw new Error("Couldn't choose active screen; Should never happen"); +} diff --git a/lib/ts/recipe/passwordless/components/themes/mfa/mfaFooter.tsx b/lib/ts/recipe/passwordless/components/themes/mfa/mfaFooter.tsx new file mode 100644 index 000000000..8d9f9636e --- /dev/null +++ b/lib/ts/recipe/passwordless/components/themes/mfa/mfaFooter.tsx @@ -0,0 +1,44 @@ +/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +import ArrowLeftIcon from "../../../../../components/assets/arrowLeftIcon"; +import { withOverride } from "../../../../../components/componentOverride/withOverride"; +import { useTranslation } from "../../../../../translation/translationContext"; +import { MultiFactorAuthClaim } from "../../../../multifactorauth"; +import { useClaimValue } from "../../../../session"; + +import type { MFAFooterProps } from "../../../types"; + +export const MFAFooter = withOverride( + "PasswordlessMFAFooter", + function PasswordlessMFAFooter(props: MFAFooterProps): JSX.Element | null { + const t = useTranslation(); + const claim = useClaimValue(MultiFactorAuthClaim); + + return ( +
+ {claim.loading === false && (claim.value?.n.length ?? 0) > 1 && ( +
+ {t("PWLESS_MFA_FOOTER_CHOOSER_ANOTHER")} +
+ )} +
+ + {t("PWLESS_MFA_FOOTER_LOGOUT")} +
+
+ ); + } +); diff --git a/lib/ts/recipe/passwordless/components/themes/mfa/mfaHeader.tsx b/lib/ts/recipe/passwordless/components/themes/mfa/mfaHeader.tsx new file mode 100644 index 000000000..c2ac7399b --- /dev/null +++ b/lib/ts/recipe/passwordless/components/themes/mfa/mfaHeader.tsx @@ -0,0 +1,53 @@ +/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +import { Fragment } from "react"; + +import { withOverride } from "../../../../../components/componentOverride/withOverride"; +import { useTranslation } from "../../../../../translation/translationContext"; +import BackButton from "../../../../emailpassword/components/library/backButton"; +import { MultiFactorAuthClaim } from "../../../../multifactorauth"; +import { useClaimValue } from "../../../../session"; + +export const MFAHeader = withOverride( + "PasswordlessMFAHeader", + function PasswordlessMFAHeader(props: { + contactMethod: "EMAIL" | "PHONE"; + onBackButtonClicked: () => void; + }): JSX.Element { + const t = useTranslation(); + const claim = useClaimValue(MultiFactorAuthClaim); + + return ( + +
+ {claim.loading === false && claim.value?.n.length === 0 ? ( + + ) : ( + + {/* empty span for spacing the back button */} + + )} + {props.contactMethod === "EMAIL" + ? t("PWLESS_MFA_HEADER_TITLE_EMAIL") + : t("PWLESS_MFA_HEADER_TITLE_PHONE")} + + {/* empty span for spacing the back button */} + +
+
+
+ ); + } +); diff --git a/lib/ts/recipe/passwordless/components/themes/mfa/mfaOTPFooter.tsx b/lib/ts/recipe/passwordless/components/themes/mfa/mfaOTPFooter.tsx new file mode 100644 index 000000000..0a04ddc6e --- /dev/null +++ b/lib/ts/recipe/passwordless/components/themes/mfa/mfaOTPFooter.tsx @@ -0,0 +1,66 @@ +/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +import ArrowLeftIcon from "../../../../../components/assets/arrowLeftIcon"; +import { withOverride } from "../../../../../components/componentOverride/withOverride"; +import { useTranslation } from "../../../../../translation/translationContext"; +import { useUserContext } from "../../../../../usercontext"; +import { MultiFactorAuthClaim } from "../../../../multifactorauth"; +import { useClaimValue } from "../../../../session"; + +import type { MFAOTPFooterProps } from "../../../types"; + +export const MFAOTPFooter = withOverride( + "PasswordlessMFAOTPFooter", + function PasswordlessMFAOTPFooter({ + loginAttemptInfo, + recipeImplementation, + onSignOutClicked, + onFactorChooserButtonClicked, + isSetupAllowed, + }: MFAOTPFooterProps): JSX.Element { + const t = useTranslation(); + const claim = useClaimValue(MultiFactorAuthClaim); + const userContext = useUserContext(); + + return ( +
+ {isSetupAllowed ? ( +
+ recipeImplementation.clearLoginAttemptInfo({ + userContext, + }) + }> + {loginAttemptInfo.contactMethod === "EMAIL" + ? t("PWLESS_SIGN_IN_UP_CHANGE_CONTACT_INFO_EMAIL") + : t("PWLESS_SIGN_IN_UP_CHANGE_CONTACT_INFO_PHONE")} +
+ ) : ( + claim.loading === false && + (claim.value?.n.length ?? 0) > 1 && ( +
+ {t("PWLESS_MFA_FOOTER_CHOOSER_ANOTHER")} +
+ ) + )} +
+ + {t("PWLESS_MFA_LOGOUT")} +
+
+ ); + } +); diff --git a/lib/ts/recipe/passwordless/components/themes/mfa/mfaOTPHeader.tsx b/lib/ts/recipe/passwordless/components/themes/mfa/mfaOTPHeader.tsx new file mode 100644 index 000000000..60837edac --- /dev/null +++ b/lib/ts/recipe/passwordless/components/themes/mfa/mfaOTPHeader.tsx @@ -0,0 +1,61 @@ +/* Copyright (c) 2021, VRAI Labs and/or its affiliates. All rights reserved. + * + * This software is licensed under the Apache License, Version 2.0 (the + * "License") as published by the Apache Software Foundation. + * + * You may not use this file except in compliance with the License. You may + * obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +import { Fragment } from "react"; + +import { withOverride } from "../../../../../components/componentOverride/withOverride"; +import { useTranslation } from "../../../../../translation/translationContext"; +import BackButton from "../../../../emailpassword/components/library/backButton"; +import { MultiFactorAuthClaim } from "../../../../multifactorauth"; +import { useClaimValue } from "../../../../session"; + +import type { MFAOTPHeaderProps } from "../../../types"; + +export const MFAOTPHeader = withOverride( + "PasswordlessMFAOTPHeader", + function PasswordlessMFAOTPHeader({ + loginAttemptInfo, + onBackButtonClicked, + isSetupAllowed, + }: MFAOTPHeaderProps): JSX.Element { + const t = useTranslation(); + const claim = useClaimValue(MultiFactorAuthClaim); + + return ( + +
+ {claim.loading === false && claim.value?.n.length === 0 && isSetupAllowed === false ? ( + + ) : ( + + {/* empty span for spacing the back button */} + + )} + {t("PWLESS_USER_INPUT_CODE_HEADER_TITLE")} + + {/* empty span for spacing the back button */} + +
+
+ {loginAttemptInfo.flowType === "USER_INPUT_CODE" + ? t("PWLESS_USER_INPUT_CODE_HEADER_SUBTITLE") + : t("PWLESS_USER_INPUT_CODE_HEADER_SUBTITLE_LINK")} +
+ {loginAttemptInfo.contactInfo} +
+
+
+ ); + } +); diff --git a/lib/ts/recipe/passwordless/components/themes/signInUp/emailForm.tsx b/lib/ts/recipe/passwordless/components/themes/signInUp/emailForm.tsx index 97159f306..3a582cdf3 100644 --- a/lib/ts/recipe/passwordless/components/themes/signInUp/emailForm.tsx +++ b/lib/ts/recipe/passwordless/components/themes/signInUp/emailForm.tsx @@ -26,7 +26,11 @@ import type { SignInUpEmailFormProps } from "../../../types"; export const EmailForm = withOverride( "PasswordlessEmailForm", - function PasswordlessEmailForm(props: SignInUpEmailFormProps): JSX.Element { + function PasswordlessEmailForm( + props: SignInUpEmailFormProps & { + footer?: JSX.Element; + } + ): JSX.Element { const userContext = useUserContext(); return ( @@ -71,10 +75,12 @@ export const EmailForm = withOverride( validateOnBlur={false} showLabels={true} footer={ - + props.footer ?? ( + + ) } /> ); diff --git a/lib/ts/recipe/passwordless/components/themes/signInUp/emailOrPhoneForm.tsx b/lib/ts/recipe/passwordless/components/themes/signInUp/emailOrPhoneForm.tsx index 54d2f0295..6cfaa4247 100644 --- a/lib/ts/recipe/passwordless/components/themes/signInUp/emailOrPhoneForm.tsx +++ b/lib/ts/recipe/passwordless/components/themes/signInUp/emailOrPhoneForm.tsx @@ -30,7 +30,11 @@ import type { SignInUpEmailOrPhoneFormProps } from "../../../types"; export const EmailOrPhoneForm = withOverride( "PasswordlessEmailOrPhoneForm", - function PasswordlessEmailOrPhoneForm(props: SignInUpEmailOrPhoneFormProps): JSX.Element { + function PasswordlessEmailOrPhoneForm( + props: SignInUpEmailOrPhoneFormProps & { + footer?: JSX.Element; + } + ): JSX.Element { const [isPhoneNumber, setIsPhoneNumber] = useState(false); const userContext = useUserContext(); @@ -149,10 +153,12 @@ export const EmailOrPhoneForm = withOverride( validateOnBlur={false} showLabels={true} footer={ - + props.footer ?? ( + + ) } /> ); diff --git a/lib/ts/recipe/passwordless/components/themes/signInUp/index.tsx b/lib/ts/recipe/passwordless/components/themes/signInUp/index.tsx index 289f2c251..b2ddd22c8 100644 --- a/lib/ts/recipe/passwordless/components/themes/signInUp/index.tsx +++ b/lib/ts/recipe/passwordless/components/themes/signInUp/index.tsx @@ -21,6 +21,8 @@ import { SuperTokensBranding } from "../../../../../components/SuperTokensBrandi import { hasFontDefined } from "../../../../../styles/styles"; import UserContextWrapper from "../../../../../usercontext/userContextWrapper"; import GeneralError from "../../../../emailpassword/components/library/generalError"; +import { useDynamicLoginMethods } from "../../../../multitenancy/dynamicLoginMethodsContext"; +import { getEnabledContactMethods } from "../../../utils"; import { ThemeBase } from "../themeBase"; import { CloseTabScreen } from "./closeTabScreen"; @@ -32,6 +34,7 @@ import { SignInUpHeader } from "./signInUpHeader"; import { UserInputCodeForm } from "./userInputCodeForm"; import { UserInputCodeFormHeader } from "./userInputCodeFormHeader"; +import type { DynamicLoginMethodsContextValue } from "../../../../multitenancy/dynamicLoginMethodsContext"; import type { SignInUpProps } from "../../../types"; export enum SignInUpScreens { @@ -101,7 +104,8 @@ const SignInUpTheme: React.FC function SignInUpThemeWrapper(props: SignInUpProps): JSX.Element { const hasFont = hasFontDefined(props.config.rootStyle); - const activeScreen = getActiveScreen(props); + const currentDynamicLoginMethods = useDynamicLoginMethods(); + const activeScreen = getActiveScreen(props, currentDynamicLoginMethods); let activeStyle; if (activeScreen === SignInUpScreens.CloseTab) { @@ -129,19 +133,25 @@ function SignInUpThemeWrapper(props: SignInUpProps): JSX.Element { export default SignInUpThemeWrapper; -export function getActiveScreen(props: Pick) { +export function getActiveScreen( + props: Pick, + currentDynamicLoginMethods: DynamicLoginMethodsContextValue +) { + const enabledContactMethods = getEnabledContactMethods(props.config.contactMethod, currentDynamicLoginMethods); + if (props.featureState.successInAnotherTab) { return SignInUpScreens.CloseTab; } else if (props.featureState.loginAttemptInfo && props.featureState.loginAttemptInfo.flowType === "MAGIC_LINK") { return SignInUpScreens.LinkSent; } else if (props.featureState.loginAttemptInfo) { return SignInUpScreens.UserInputCodeForm; - } else if (props.config.contactMethod === "EMAIL") { + } else if (enabledContactMethods.length > 1) { + return SignInUpScreens.EmailOrPhoneForm; + } else if (enabledContactMethods[0] === "EMAIL") { return SignInUpScreens.EmailForm; - } else if (props.config.contactMethod === "PHONE") { + } else if (enabledContactMethods[0] === "PHONE") { return SignInUpScreens.PhoneForm; - } else if (props.config.contactMethod === "EMAIL_OR_PHONE") { - return SignInUpScreens.EmailOrPhoneForm; } + throw new Error("Couldn't choose active screen; Should never happen"); } diff --git a/lib/ts/recipe/passwordless/components/themes/signInUp/phoneForm.tsx b/lib/ts/recipe/passwordless/components/themes/signInUp/phoneForm.tsx index fb2b8805f..a978bc138 100644 --- a/lib/ts/recipe/passwordless/components/themes/signInUp/phoneForm.tsx +++ b/lib/ts/recipe/passwordless/components/themes/signInUp/phoneForm.tsx @@ -29,7 +29,11 @@ import type { SignInUpPhoneFormProps } from "../../../types"; export const PhoneForm = withOverride( "PasswordlessPhoneForm", - function PasswordlessPhoneForm(props: SignInUpPhoneFormProps): JSX.Element { + function PasswordlessPhoneForm( + props: SignInUpPhoneFormProps & { + footer?: JSX.Element; + } + ): JSX.Element { const userContext = useUserContext(); useEffect(() => { @@ -87,10 +91,12 @@ export const PhoneForm = withOverride( validateOnBlur={false} showLabels={true} footer={ - + props.footer ?? ( + + ) } /> ); diff --git a/lib/ts/recipe/passwordless/components/themes/signInUp/userInputCodeForm.tsx b/lib/ts/recipe/passwordless/components/themes/signInUp/userInputCodeForm.tsx index d237ed0e6..fb8203bc5 100644 --- a/lib/ts/recipe/passwordless/components/themes/signInUp/userInputCodeForm.tsx +++ b/lib/ts/recipe/passwordless/components/themes/signInUp/userInputCodeForm.tsx @@ -32,7 +32,6 @@ export const UserInputCodeForm = withOverride( "PasswordlessUserInputCodeForm", function PasswordlessUserInputCodeForm( props: SignInUpUserInputCodeFormProps & { - header?: JSX.Element; footer?: JSX.Element; } ): JSX.Element { @@ -160,7 +159,9 @@ export const UserInputCodeForm = withOverride( }} validateOnBlur={false} showLabels={true} - footer={} + footer={ + props.footer ?? + } /> ); diff --git a/lib/ts/recipe/passwordless/components/themes/translations.ts b/lib/ts/recipe/passwordless/components/themes/translations.ts index 0fa66ae81..3885a07ba 100644 --- a/lib/ts/recipe/passwordless/components/themes/translations.ts +++ b/lib/ts/recipe/passwordless/components/themes/translations.ts @@ -71,6 +71,13 @@ export const defaultTranslationsPasswordless = { PWLESS_USER_INPUT_CODE_HEADER_SUBTITLE_LINK: "An OTP and a magic link was sent to you at", PWLESS_USER_INPUT_CODE_INPUT_LABEL: "OTP", + PWLESS_MFA_LOGOUT: "Logout", + PWLESS_MFA_HEADER_TITLE_PHONE: "SMS based OTP", + PWLESS_MFA_HEADER_TITLE_EMAIL: "Email based OTP", + PWLESS_MFA_FOOTER_CHOOSER_ANOTHER: "Choose another factor", + PWLESS_MFA_FOOTER_LOGOUT: "Logout", + + PWLESS_MFA_OTP_NOT_ALLOWED_TO_SETUP: "You are not allowed to set up OTP.", /* * The following are error messages from our backend SDK. * These are returned as full messages to preserver compatibilty, but they work just like the keys above. diff --git a/lib/ts/recipe/passwordless/prebuiltui.tsx b/lib/ts/recipe/passwordless/prebuiltui.tsx index 06e7315b9..9248b54e4 100644 --- a/lib/ts/recipe/passwordless/prebuiltui.tsx +++ b/lib/ts/recipe/passwordless/prebuiltui.tsx @@ -4,9 +4,11 @@ import UserContextWrapper from "../../usercontext/userContextWrapper"; import { isTest, matchRecipeIdUsingQueryParams } from "../../utils"; import AuthWidgetWrapper from "../authRecipe/authWidgetWrapper"; import { RecipeRouter } from "../recipeRouter"; +import { SessionAuth } from "../session"; import { useRecipeComponentOverrideContext } from "./componentOverrideContext"; import LinkClickedScreen from "./components/features/linkClickedScreen"; +import MFAFeature from "./components/features/mfa"; import SignInUpFeature from "./components/features/signInAndUp"; import SignInUpTheme from "./components/themes/signInUp"; import Passwordless from "./recipe"; @@ -42,7 +44,7 @@ export class PasswordlessPreBuiltUI extends RecipeRouter { return PasswordlessPreBuiltUI.getInstanceOrInitAndGetInstance().getFeatures(useComponentOverrides); } static getFeatureComponent( - componentName: "signInUp" | "linkClickedScreen", + componentName: "signInUp" | "linkClickedScreen" | "otp-phone" | "otp-email", props: FeatureBaseProps & { redirectOnSessionExists?: boolean; userContext?: any }, useComponentOverrides: () => GenericComponentOverrideMap = useRecipeComponentOverrideContext ): JSX.Element { @@ -79,11 +81,29 @@ export class PasswordlessPreBuiltUI extends RecipeRouter { recipeID: Passwordless.RECIPE_ID, }; } + if (this.recipeInstance.config.mfaFeature.disableDefaultUI !== true) { + const normalisedFullPathPhone = this.recipeInstance.config.appInfo.websiteBasePath.appendPath( + new NormalisedURLPath("/mfa/otp-phone") + ); + features[normalisedFullPathPhone.getAsStringDangerous()] = { + matches: matchRecipeIdUsingQueryParams(this.recipeInstance.config.recipeId), + component: (props) => this.getFeatureComponent("otp-phone", props as any, useComponentOverrides), + recipeID: Passwordless.RECIPE_ID, + }; + const normalisedFullPathEmail = this.recipeInstance.config.appInfo.websiteBasePath.appendPath( + new NormalisedURLPath("/mfa/otp-email") + ); + features[normalisedFullPathEmail.getAsStringDangerous()] = { + matches: matchRecipeIdUsingQueryParams(this.recipeInstance.config.recipeId), + component: (props) => this.getFeatureComponent("otp-email", props as any, useComponentOverrides), + recipeID: Passwordless.RECIPE_ID, + }; + } return features; }; getFeatureComponent = ( - componentName: "signInUp" | "linkClickedScreen", + componentName: "signInUp" | "linkClickedScreen" | "otp-phone" | "otp-email", props: FeatureBaseProps & { redirectOnSessionExists?: boolean; userContext?: any }, useComponentOverrides: () => GenericComponentOverrideMap = useRecipeComponentOverrideContext ): JSX.Element => { @@ -129,9 +149,38 @@ export class PasswordlessPreBuiltUI extends RecipeRouter { /> ); - } else { - throw new Error("Should never come here."); } + if (componentName === "otp-email") { + return ( + + []}> + + + + ); + } + if (componentName === "otp-phone") { + return ( + + []}> + + + + ); + } + throw new Error("Should never come here."); }; // For tests @@ -148,11 +197,15 @@ export class PasswordlessPreBuiltUI extends RecipeRouter { this.getFeatureComponent("signInUp", prop); static LinkClicked = (prop?: any) => this.getFeatureComponent("linkClickedScreen", prop); + static MfaOtpPhone = (prop?: any) => this.getFeatureComponent("otp-phone", prop); + static MfaOtpEmail = (prop?: any) => this.getFeatureComponent("otp-email", prop); static SignInUpTheme = SignInUpTheme; } const SignInUp = PasswordlessPreBuiltUI.SignInUp; const LinkClicked = PasswordlessPreBuiltUI.LinkClicked; +const MfaOtpPhone = PasswordlessPreBuiltUI.MfaOtpPhone; +const MfaOtpEmail = PasswordlessPreBuiltUI.MfaOtpEmail; -export { SignInUp, LinkClicked, SignInUpTheme }; +export { SignInUp, LinkClicked, SignInUpTheme, MfaOtpPhone, MfaOtpEmail }; diff --git a/lib/ts/recipe/passwordless/recipe.tsx b/lib/ts/recipe/passwordless/recipe.tsx index 7974b587d..3c552b3b6 100644 --- a/lib/ts/recipe/passwordless/recipe.tsx +++ b/lib/ts/recipe/passwordless/recipe.tsx @@ -18,10 +18,14 @@ */ import PasswordlessWebJS from "supertokens-web-js/recipe/passwordless"; +import { PostSuperTokensInitCallbacks } from "supertokens-web-js/utils/postSuperTokensInitCallbacks"; +import { OTPEmailIcon } from "../../components/assets/otpEmailIcon"; +import { OTPSMSIcon } from "../../components/assets/otpSMSIcon"; import { SSR_ERROR } from "../../constants"; import { isTest } from "../../utils"; import AuthRecipe from "../authRecipe"; +import MultiFactorAuth from "../multifactorauth/recipe"; import { getFunctionOverrides } from "./functionOverrides"; import { normalisePasswordlessConfig } from "./utils"; @@ -37,6 +41,21 @@ import type { RecipeInitResult, NormalisedConfigWithAppInfoAndRecipeID, WebJSRec import type { NormalisedAppInfo } from "../../types"; import type RecipeModule from "../recipeModule"; +export const otpPhoneFactor = { + id: "otp-phone", + name: "SMS based OTP", + description: "Get an OTP code on your phone to complete the authentication request", + path: "/mfa/otp-phone", + logo: OTPSMSIcon, +}; +export const otpEmailFactor = { + id: "otp-email", + name: "Email based OTP", + description: "Get an OTP code on your email address to complete the authentication request", + path: "/mfa/otp-email", + logo: OTPEmailIcon, +}; + export const passwordlessFirstFactors = ["otp-phone", "otp-email", "link-phone", "link-email"] as const; /* @@ -58,6 +77,13 @@ export default class Passwordless extends AuthRecipe< public readonly webJSRecipe: WebJSRecipeInterface = PasswordlessWebJS ) { super(config); + + PostSuperTokensInitCallbacks.addPostInitCallback(() => { + const mfa = MultiFactorAuth.getInstance(); + if (mfa !== undefined) { + mfa.addMFAFactors([otpPhoneFactor, otpEmailFactor]); + } + }); } getDefaultRedirectionURL = async (context: GetRedirectionURLContext): Promise => { diff --git a/lib/ts/recipe/passwordless/types.ts b/lib/ts/recipe/passwordless/types.ts index bd78c63ce..3992c9111 100644 --- a/lib/ts/recipe/passwordless/types.ts +++ b/lib/ts/recipe/passwordless/types.ts @@ -14,6 +14,10 @@ */ import type { LinkClickedScreen } from "./components/themes/linkClickedScreen"; +import type { MFAFooter } from "./components/themes/mfa/mfaFooter"; +import type { MFAHeader } from "./components/themes/mfa/mfaHeader"; +import type { MFAOTPFooter } from "./components/themes/mfa/mfaOTPFooter"; +import type { MFAOTPHeader } from "./components/themes/mfa/mfaOTPHeader"; import type { CloseTabScreen } from "./components/themes/signInUp/closeTabScreen"; import type { EmailForm } from "./components/themes/signInUp/emailForm"; import type { EmailOrPhoneForm } from "./components/themes/signInUp/emailOrPhoneForm"; @@ -106,6 +110,7 @@ export type NormalisedConfig = { disableDefaultUI?: boolean; }; linkClickedScreenFeature: PasswordlessNormalisedBaseConfig; + mfaFeature: PasswordlessNormalisedBaseConfig; contactMethod: "PHONE" | "EMAIL" | "EMAIL_OR_PHONE"; @@ -183,8 +188,27 @@ export type UserInput = ( functions?: (originalImplementation: RecipeInterface) => RecipeInterface; }; linkClickedScreenFeature?: PasswordlessFeatureBaseConfig; + mfaFeature?: PasswordlessFeatureBaseConfig; } & AuthRecipeModuleUserInput; +export type MFAProps = { + recipeImplementation: RecipeImplementation; + config: NormalisedConfig; + contactMethod: "EMAIL" | "PHONE"; + onBackButtonClicked: () => void; + onSignOutClicked: () => void; + onFactorChooserButtonClicked: () => void; + onSuccess?: () => void; + dispatch: Dispatch; + featureState: { + isSetupAllowed: boolean; + loginAttemptInfo?: LoginAttemptInfo; + loaded: boolean; + successInAnotherTab: boolean; + error: string | undefined; + }; + userContext?: any; +}; export type SignInUpProps = { recipeImplementation: RecipeImplementation; config: NormalisedConfig; @@ -307,7 +331,42 @@ export type SignInUpState = { successInAnotherTab: boolean; }; +export type MFAAction = + | { + type: "load"; + loginAttemptInfo: LoginAttemptInfo | undefined; + isAllowedToSetup: boolean; + error: string | undefined; + } + | { + type: "startVerify"; + loginAttemptInfo: LoginAttemptInfo; + } + | { + type: "resendCode"; + timestamp: number; + } + | { + type: "restartFlow"; + error: string | undefined; + } + | { + type: "setError"; + error: string | undefined; + } + | { + type: "successInAnotherTab"; + }; +export type MFAState = { + error: string | undefined; + loaded: boolean; + loginAttemptInfo: LoginAttemptInfo | undefined; + isSetupAllowed: boolean; + successInAnotherTab: boolean; +}; + export type SignInUpChildProps = Omit; +export type MFAChildProps = Omit; export type LinkSentThemeProps = { clearError: () => void; @@ -330,6 +389,31 @@ export type UserInputCodeFormHeaderProps = { config: NormalisedConfig; }; +export type MFAFooterProps = { + isSetupAllowed: boolean; + onSignOutClicked: () => void; + onFactorChooserButtonClicked: () => void; + recipeImplementation: RecipeImplementation; + config: NormalisedConfig; +}; + +export type MFAOTPFooterProps = { + isSetupAllowed: boolean; + onSignOutClicked: () => void; + onFactorChooserButtonClicked: () => void; + loginAttemptInfo: LoginAttemptInfo; + recipeImplementation: RecipeImplementation; + config: NormalisedConfig; +}; + +export type MFAOTPHeaderProps = { + isSetupAllowed: boolean; + onBackButtonClicked: () => void; + loginAttemptInfo: LoginAttemptInfo; + recipeImplementation: RecipeImplementation; + config: NormalisedConfig; +}; + export type ComponentOverrideMap = { PasswordlessSignInUpHeader_Override?: ComponentOverride; PasswordlessSignInUpFooter_Override?: ComponentOverride; @@ -345,4 +429,9 @@ export type ComponentOverrideMap = { PasswordlessLinkClickedScreen_Override?: ComponentOverride; PasswordlessCloseTabScreen_Override?: ComponentOverride; + + PasswordlessMFAHeader_Override?: ComponentOverride; + PasswordlessMFAFooter_Override?: ComponentOverride; + PasswordlessMFAOTPHeader_Override?: ComponentOverride; + PasswordlessMFAOTPFooter_Override?: ComponentOverride; }; diff --git a/lib/ts/recipe/passwordless/utils.ts b/lib/ts/recipe/passwordless/utils.ts index d1bc38892..bd459381a 100644 --- a/lib/ts/recipe/passwordless/utils.ts +++ b/lib/ts/recipe/passwordless/utils.ts @@ -14,6 +14,7 @@ */ import { normaliseAuthRecipe } from "../authRecipe/utils"; +import MultiFactorAuth from "../multifactorauth/recipe"; import { defaultPhoneNumberValidator, @@ -25,6 +26,7 @@ import { import type { Config, NormalisedConfig, SignInUpFeatureConfigInput } from "./types"; import type { FeatureBaseConfig, NormalisedBaseConfig } from "../../types"; +import type { DynamicLoginMethodsContextValue } from "../multitenancy/dynamicLoginMethodsContext"; import type { RecipeInterface } from "supertokens-web-js/recipe/passwordless"; export function normalisePasswordlessConfig(config: Config): NormalisedConfig { @@ -71,6 +73,7 @@ export function normalisePasswordlessConfig(config: Config): NormalisedConfig { signInUpFeature, linkClickedScreenFeature: normalisePasswordlessBaseConfig(config.linkClickedScreenFeature), + mfaFeature: normalisePasswordlessBaseConfig(config.mfaFeature), contactMethod: config.contactMethod, @@ -136,3 +139,44 @@ function normalisePasswordlessBaseConfig(config?: T & FeatureBaseConfig): T & style, }; } + +export function getEnabledContactMethods( + contactMethod: "PHONE" | "EMAIL" | "EMAIL_OR_PHONE", + currentDynamicLoginMethods: DynamicLoginMethodsContextValue +) { + let enabledContactMethods = contactMethod === "EMAIL_OR_PHONE" ? ["EMAIL", "PHONE"] : [contactMethod]; + + let firstFactors; + if (currentDynamicLoginMethods.loaded && currentDynamicLoginMethods.loginMethods.firstFactors) { + firstFactors = currentDynamicLoginMethods.loginMethods.firstFactors; + } else { + firstFactors = MultiFactorAuth.getInstance()?.config.firstFactors; + } + + if (firstFactors !== undefined) { + if (enabledContactMethods.includes("PHONE")) { + if (!firstFactors.includes("otp-phone") && !firstFactors.includes("link-phone")) { + enabledContactMethods = enabledContactMethods.filter((c) => c !== "PHONE"); + } + } else { + if (firstFactors.includes("otp-phone") || firstFactors.includes("link-phone")) { + throw new Error("The enabled contact method is not a superset of the requested first factors"); + } + } + + if (enabledContactMethods.includes("EMAIL")) { + if (!firstFactors.includes("otp-email") && !firstFactors.includes("link-email")) { + enabledContactMethods = enabledContactMethods.filter((c) => c !== "EMAIL"); + } + } else { + if (firstFactors.includes("otp-email") || firstFactors.includes("link-email")) { + throw new Error("The enabled contact method is not a superset of the requested first factors"); + } + } + } + + if (enabledContactMethods.length === 0) { + throw new Error("The enabled contact method is not a superset of the requested first factors"); + } + return enabledContactMethods; +} diff --git a/lib/ts/recipe/thirdpartypasswordless/components/themes/signInUp/index.tsx b/lib/ts/recipe/thirdpartypasswordless/components/themes/signInUp/index.tsx index 8aefd9417..afb6b7ea8 100644 --- a/lib/ts/recipe/thirdpartypasswordless/components/themes/signInUp/index.tsx +++ b/lib/ts/recipe/thirdpartypasswordless/components/themes/signInUp/index.tsx @@ -152,15 +152,19 @@ const SignInUpTheme: React.FC GenericComponentOverrideMap = useRecipeComponentOverrideContext ): JSX.Element { @@ -67,7 +67,7 @@ export class ThirdPartyPasswordlessPreBuiltUI extends RecipeRouter { // Instance methods getFeatureComponent = ( - componentName: "signInUp" | "linkClickedScreen" | "signinupcallback", + componentName: "signInUp" | "linkClickedScreen" | "signinupcallback" | "otp-phone" | "otp-email", props: FeatureBaseProps & { redirectOnSessionExists?: boolean; userContext?: any }, useComponentOverrides: () => GenericComponentOverrideMap = useRecipeComponentOverrideContext ): JSX.Element => { @@ -102,7 +102,11 @@ export class ThirdPartyPasswordlessPreBuiltUI extends RecipeRouter { ); } - } else if (componentName === "linkClickedScreen") { + } else if ( + "linkClickedScreen" === componentName || + "otp-phone" === componentName || + "otp-email" === componentName + ) { if (this.passwordlessPreBuiltUI === undefined) { throw new Error( "Embedding this component requires the passwordless recipe to be enabled. Please check the value of disablePasswordless in the configuration." @@ -176,10 +180,14 @@ export class ThirdPartyPasswordlessPreBuiltUI extends RecipeRouter { static SignInUpTheme = SignInUpTheme; static PasswordlessLinkClicked = (prop?: any) => this.getFeatureComponent("linkClickedScreen", prop); + static MfaOtpPhone = (prop?: any) => this.getFeatureComponent("otp-phone", prop); + static MfaOtpEmail = (prop?: any) => this.getFeatureComponent("otp-email", prop); } const SignInAndUp = ThirdPartyPasswordlessPreBuiltUI.SignInAndUp; const ThirdPartySignInAndUpCallback = ThirdPartyPasswordlessPreBuiltUI.ThirdPartySignInAndUpCallback; const PasswordlessLinkClicked = ThirdPartyPasswordlessPreBuiltUI.PasswordlessLinkClicked; +const MfaOtpPhone = PasswordlessPreBuiltUI.MfaOtpPhone; +const MfaOtpEmail = PasswordlessPreBuiltUI.MfaOtpEmail; -export { SignInAndUp, ThirdPartySignInAndUpCallback, PasswordlessLinkClicked, SignInUpTheme }; +export { SignInAndUp, ThirdPartySignInAndUpCallback, PasswordlessLinkClicked, SignInUpTheme, MfaOtpPhone, MfaOtpEmail }; diff --git a/lib/ts/recipe/thirdpartypasswordless/types.ts b/lib/ts/recipe/thirdpartypasswordless/types.ts index 4c0bc8e98..0fa42cfec 100644 --- a/lib/ts/recipe/thirdpartypasswordless/types.ts +++ b/lib/ts/recipe/thirdpartypasswordless/types.ts @@ -123,6 +123,7 @@ export type UserInput = ( ) => RecipeInterface; }; linkClickedScreenFeature?: PasswordlessFeatureBaseConfig; + mfaFeature?: PasswordlessFeatureBaseConfig; oAuthCallbackScreen?: FeatureBaseConfig; disablePasswordless?: boolean; } & AuthRecipeModuleUserInput; diff --git a/lib/ts/recipe/thirdpartypasswordless/utils.ts b/lib/ts/recipe/thirdpartypasswordless/utils.ts index 9a0e74eeb..48ef02ba0 100644 --- a/lib/ts/recipe/thirdpartypasswordless/utils.ts +++ b/lib/ts/recipe/thirdpartypasswordless/utils.ts @@ -68,6 +68,7 @@ export function normaliseThirdPartyPasswordlessConfig(config?: Config): Normalis emailOrPhoneFormStyle: thirdPartyProviderAndEmailOrPhoneFormStyle, }, linkClickedScreenFeature: config.linkClickedScreenFeature, + mfaFeature: config.mfaFeature, override: {}, }), disablePasswordless: config.disablePasswordless === true, diff --git a/lib/ts/styles/styles.css b/lib/ts/styles/styles.css index ccb25636e..69ccc2bd0 100644 --- a/lib/ts/styles/styles.css +++ b/lib/ts/styles/styles.css @@ -260,3 +260,71 @@ [data-supertokens~="button"]:focus { outline: none; } + +[data-supertokens~="backButtonCommon"] { + width: 16px; + height: 13px; +} + +[data-supertokens~="backButton"] { + cursor: pointer; + border: none; + background-color: transparent; + padding: 0px; +} + +[data-supertokens~="backButtonPlaceholder"] { + display: block; +} + +[data-supertokens~="delayedRender"] { + animation-duration: 0.1s; + animation-name: animate-fade; + animation-delay: 0.2s; + animation-fill-mode: backwards; +} + +@keyframes animate-fade { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} + +[data-supertokens~="footerLinkGroupVert"] { + display: flex; + flex-direction: column; + margin-top: 10px; + gap: 24px; +} + +[data-supertokens~="footerLinkGroupVert"] > div { + margin: 0; +} + +[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryText"] { + font-weight: 400; +} + +[data-supertokens~="footerLinkGroupVert"] [data-supertokens~="secondaryLinkWithLeftArrow"] { + font-weight: 500; + position: relative; + left: -6px; /* half the width of the left arrow */ +} + +@media (max-width: 360px) { + [data-supertokens~="footerLinkGroupVert"] { + flex-direction: column; + } + [data-supertokens~="footerLinkGroupVert"] > div { + margin: 0 auto; + } +} + +[data-supertokens~="footerLinkGroupVert"] div:only-child { + margin-left: auto; + margin-right: auto; + margin-top: 14px; +} diff --git a/test/with-typescript/src/App.tsx b/test/with-typescript/src/App.tsx index b47daecf6..ebcd3bd1b 100644 --- a/test/with-typescript/src/App.tsx +++ b/test/with-typescript/src/App.tsx @@ -1465,3 +1465,21 @@ MultiFactorAuth.init({ { id: "asfd", logo: () =>
A
, description: "test", name: "asdf", path: "/mfa/asdf" }, ], }); + +Passwordless.init({ + contactMethod: "EMAIL", + mfaFeature: { + style: "", + }, +}); + +ThirdPartyPasswordless.init({ + contactMethod: "EMAIL", + mfaFeature: { + style: "", + }, +}); + +ThirdPartyPasswordless.init({ + contactMethod: "EMAIL", +});