diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index b1cfd5d586..f7d0601430 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -6,7 +6,7 @@ import { LocalStorageBroadcastChannel } from '@clerk/shared/localStorageBroadcas import { logger } from '@clerk/shared/logger'; import { isHttpOrHttps, isValidProxyUrl, proxyUrlToAbsoluteURL } from '@clerk/shared/proxy'; import { eventPrebuiltComponentMounted, TelemetryCollector } from '@clerk/shared/telemetry'; -import { addClerkPrefix, stripScheme } from '@clerk/shared/url'; +import { addClerkPrefix, isAbsoluteUrl, stripScheme } from '@clerk/shared/url'; import { handleValueOrFn, noop } from '@clerk/shared/utils'; import type { __internal_UserVerificationModalProps, @@ -365,8 +365,8 @@ export class Clerk implements ClerkInterface { } }; - #isCombinedFlow(): boolean { - return this.#options.experimental?.combinedFlow && this.#options.signInUrl === this.#options.signUpUrl; + #isCombinedSignInOrUpFlow(): boolean { + return Boolean(!this.#options.signUpUrl && this.#options.signInUrl && !isAbsoluteUrl(this.#options.signInUrl)); } public signOut: SignOut = async (callbackOrOptions?: SignOutCallback | SignOutOptions, options?: SignOutOptions) => { @@ -2112,13 +2112,17 @@ export class Clerk implements ClerkInterface { return ''; } - const signInOrUpUrl = this.#options[key] || this.environment.displayConfig[key]; + let signInOrUpUrl = this.#options[key] || this.environment.displayConfig[key]; + if (this.#isCombinedSignInOrUpFlow()) { + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- The isCombinedSignInOrUpFlow() function checks for the existence of signInUrl + signInOrUpUrl = this.#options.signInUrl!; + } const redirectUrls = new RedirectUrls(this.#options, options).toSearchParams(); const initValues = new URLSearchParams(_initValues || {}); const url = buildURL( { base: signInOrUpUrl, - hashPath: this.#isCombinedFlow() && key === 'signUpUrl' ? '/create' : '', + hashPath: this.#isCombinedSignInOrUpFlow() && key === 'signUpUrl' ? '/create' : '', hashSearchParams: [initValues, redirectUrls], }, { stringify: true }, diff --git a/packages/clerk-js/src/ui/common/redirects.ts b/packages/clerk-js/src/ui/common/redirects.ts index 347b45bf9a..55ed6d4a55 100644 --- a/packages/clerk-js/src/ui/common/redirects.ts +++ b/packages/clerk-js/src/ui/common/redirects.ts @@ -9,7 +9,7 @@ export function buildEmailLinkRedirectUrl( baseUrl: string | undefined = '', ): string { const { routing, authQueryString, path } = ctx; - const isCombinedFlow = '__experimental' in ctx && ctx.__experimental?.combinedProps; + const isCombinedFlow = 'isCombinedFlow' in ctx && ctx.isCombinedFlow; return buildRedirectUrl({ routing, baseUrl, diff --git a/packages/clerk-js/src/ui/components/SignIn/SignIn.tsx b/packages/clerk-js/src/ui/components/SignIn/SignIn.tsx index ea783fc013..218eb7ba3d 100644 --- a/packages/clerk-js/src/ui/components/SignIn/SignIn.tsx +++ b/packages/clerk-js/src/ui/components/SignIn/SignIn.tsx @@ -6,7 +6,6 @@ import { SignInEmailLinkFlowComplete, SignUpEmailLinkFlowComplete } from '../../ import { SignInContext, SignUpContext, - useOptions, useSignInContext, useSignUpContext, withCoreSessionSwitchGuard, @@ -37,7 +36,6 @@ function RedirectToSignIn() { function SignInRoutes(): JSX.Element { const signInContext = useSignInContext(); const signUpContext = useSignUpContext(); - const options = useOptions(); return ( @@ -76,7 +74,7 @@ function SignInRoutes(): JSX.Element { redirectUrl='../factor-two' /> - {options.experimental?.combinedFlow && ( + {signInContext.isCombinedFlow && ( ( () => groupIdentifiers(userSettings.enabledFirstFactorIdentifiers), diff --git a/packages/clerk-js/src/ui/components/SignUp/SignUpContinue.tsx b/packages/clerk-js/src/ui/components/SignUp/SignUpContinue.tsx index 63b3748a2a..71fb2d6af4 100644 --- a/packages/clerk-js/src/ui/components/SignUp/SignUpContinue.tsx +++ b/packages/clerk-js/src/ui/components/SignUp/SignUpContinue.tsx @@ -1,7 +1,7 @@ import { useClerk } from '@clerk/shared/react'; import React, { useEffect, useMemo } from 'react'; -import { SignInContext, useCoreSignUp, useEnvironment, useOptions, useSignUpContext } from '../../contexts'; +import { SignInContext, useCoreSignUp, useEnvironment, useSignUpContext } from '../../contexts'; import { descriptors, Flex, Flow, localizationKeys } from '../../customizables'; import { Card, @@ -31,11 +31,16 @@ function _SignUpContinue() { const { navigate } = useRouter(); const { displayConfig, userSettings } = useEnvironment(); const { attributes } = userSettings; - const { afterSignUpUrl, signInUrl, unsafeMetadata, initialValues = {} } = useSignUpContext(); + const { + afterSignUpUrl, + signInUrl, + unsafeMetadata, + initialValues = {}, + isCombinedFlow: _isCombinedFlow, + } = useSignUpContext(); const signUp = useCoreSignUp(); - const options = useOptions(); const isWithinSignInContext = !!React.useContext(SignInContext); - const isCombinedFlow = !!(options.experimental?.combinedFlow && !!isWithinSignInContext); + const isCombinedFlow = !!(_isCombinedFlow && !!isWithinSignInContext); const isProgressiveSignUp = userSettings.signUp.progressive; const [activeCommIdentifierType, setActiveCommIdentifierType] = React.useState( getInitialActiveIdentifier(attributes, userSettings.signUp.progressive), diff --git a/packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx b/packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx index 3f000a1fe5..c4efcb42e7 100644 --- a/packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx +++ b/packages/clerk-js/src/ui/components/SignUp/SignUpStart.tsx @@ -4,7 +4,7 @@ import React from 'react'; import { ERROR_CODES, SIGN_UP_MODES } from '../../../core/constants'; import { getClerkQueryParam, removeClerkQueryParam } from '../../../utils/getClerkQueryParam'; import { buildSSOCallbackURL, withRedirectToAfterSignUp } from '../../common'; -import { SignInContext, useCoreSignUp, useEnvironment, useOptions, useSignUpContext } from '../../contexts'; +import { SignInContext, useCoreSignUp, useEnvironment, useSignUpContext } from '../../contexts'; import { descriptors, Flex, Flow, localizationKeys, useAppearance, useLocalizations } from '../../customizables'; import { Card, @@ -39,10 +39,9 @@ function _SignUpStart(): JSX.Element { const { attributes } = userSettings; const { setActive } = useClerk(); const ctx = useSignUpContext(); - const options = useOptions(); const isWithinSignInContext = !!React.useContext(SignInContext); - const { afterSignUpUrl, signInUrl, unsafeMetadata } = ctx; - const isCombinedFlow = !!(options.experimental?.combinedFlow && !!isWithinSignInContext); + const { afterSignUpUrl, signInUrl, unsafeMetadata, isCombinedFlow: _isCombinedFlow } = ctx; + const isCombinedFlow = !!(_isCombinedFlow && !!isWithinSignInContext); const [activeCommIdentifierType, setActiveCommIdentifierType] = React.useState( getInitialActiveIdentifier(attributes, userSettings.signUp.progressive), ); diff --git a/packages/clerk-js/src/ui/contexts/components/SignIn.ts b/packages/clerk-js/src/ui/contexts/components/SignIn.ts index e089e0f1b9..adca89d571 100644 --- a/packages/clerk-js/src/ui/contexts/components/SignIn.ts +++ b/packages/clerk-js/src/ui/contexts/components/SignIn.ts @@ -1,4 +1,5 @@ import { useClerk } from '@clerk/shared/react'; +import { isAbsoluteUrl } from '@clerk/shared/url'; import { createContext, useContext, useMemo } from 'react'; import { SIGN_IN_INITIAL_VALUE_KEYS } from '../../../core/constants'; @@ -21,6 +22,7 @@ export type SignInContextType = SignInCtx & { afterSignInUrl: string; transferable: boolean; waitlistUrl: string; + isCombinedFlow: boolean; }; export const SignInContext = createContext(null); @@ -32,6 +34,7 @@ export const useSignInContext = (): SignInContextType => { const { queryParams, queryString } = useRouter(); const options = useOptions(); const clerk = useClerk(); + const isCombinedFlow = Boolean(!options.signUpUrl && options.signInUrl && !isAbsoluteUrl(options.signInUrl)); if (context === null || context.componentName !== 'SignIn') { throw new Error(`Clerk: useSignInContext called outside of the mounted SignIn component.`); @@ -96,5 +99,6 @@ export const useSignInContext = (): SignInContextType => { queryParams, initialValues: { ...ctx.initialValues, ...initialValuesFromQueryParams }, authQueryString: redirectUrls.toSearchParams().toString(), + isCombinedFlow, }; }; diff --git a/packages/clerk-js/src/ui/contexts/components/SignUp.ts b/packages/clerk-js/src/ui/contexts/components/SignUp.ts index 643525c4ef..30ed891f88 100644 --- a/packages/clerk-js/src/ui/contexts/components/SignUp.ts +++ b/packages/clerk-js/src/ui/contexts/components/SignUp.ts @@ -1,4 +1,5 @@ import { useClerk } from '@clerk/shared/react'; +import { isAbsoluteUrl } from '@clerk/shared/url'; import { createContext, useContext, useMemo } from 'react'; import { SIGN_UP_INITIAL_VALUE_KEYS } from '../../../core/constants'; @@ -20,6 +21,7 @@ export type SignUpContextType = SignUpCtx & { afterSignUpUrl: string; afterSignInUrl: string; waitlistUrl: string; + isCombinedFlow: boolean; }; export const SignUpContext = createContext(null); @@ -31,6 +33,7 @@ export const useSignUpContext = (): SignUpContextType => { const { queryParams, queryString } = useRouter(); const options = useOptions(); const clerk = useClerk(); + const isCombinedFlow = Boolean(!options.signUpUrl && options.signInUrl && !isAbsoluteUrl(options.signInUrl)); const initialValuesFromQueryParams = useMemo( () => getInitialValuesFromQueryParams(queryString, SIGN_UP_INITIAL_VALUE_KEYS), @@ -87,5 +90,6 @@ export const useSignUpContext = (): SignUpContextType => { queryParams, initialValues: { ...ctx.initialValues, ...initialValuesFromQueryParams }, authQueryString: redirectUrls.toSearchParams().toString(), + isCombinedFlow, }; }; diff --git a/packages/types/src/clerk.ts b/packages/types/src/clerk.ts index 464886a76f..d4e19aa291 100644 --- a/packages/types/src/clerk.ts +++ b/packages/types/src/clerk.ts @@ -895,50 +895,6 @@ export type RoutingOptions = | { path?: never; routing?: Extract }; export type SignInProps = RoutingOptions & { - /** - * Full URL or path to navigate after successful sign in. - * This value has precedence over other redirect props, environment variables or search params. - * Use this prop to override the redirect URL when needed. - * @default undefined - */ - forceRedirectUrl?: string | null; - /** - * Full URL or path to navigate after successful sign in. - * This value is used when no other redirect props, environment variables or search params are present. - * @default undefined - */ - fallbackRedirectUrl?: string | null; - /** - * Full URL or path to for the sign up process. - * Used to fill the "Sign up" link in the SignUp component. - */ - signUpUrl?: string; - /** - * Customisation options to fully match the Clerk components to your own brand. - * These options serve as overrides and will be merged with the global `appearance` - * prop of ClerkProvider (if one is provided) - */ - appearance?: SignInTheme; - /** - * Initial values that are used to prefill the sign in form. - */ - initialValues?: SignInInitialValues; - /** - * Enable experimental flags to gain access to new features. These flags are not guaranteed to be stable and may change drastically in between patch or minor versions. - */ - __experimental?: Record & { newComponents?: boolean; combinedProps?: SignInCombinedProps }; - /** - * Full URL or path to for the waitlist process. - * Used to fill the "Join waitlist" link in the SignUp component. - */ - waitlistUrl?: string; -} & TransferableOption & - SignUpForceRedirectUrl & - SignUpFallbackRedirectUrl & - LegacyRedirectProps & - AfterSignOutUrl; - -export type SignInCombinedProps = RoutingOptions & { /** * Full URL or path to navigate after successful sign in. * This value has precedence over other redirect props, environment variables or search params.