Skip to content

Commit c9cdda9

Browse files
authored
Merge branch 'main' into tm.fix/password-settings
2 parents 1c9fc74 + c6cf01c commit c9cdda9

File tree

17 files changed

+599
-48
lines changed

17 files changed

+599
-48
lines changed

.changeset/lemon-crews-hammer.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@clerk/elements': minor
3+
---
4+
5+
- Adds virtual router to support modal scenarios
6+
- Adds `routing` prop to `SignIn.Root` and `SignUp.Root` for handling `virtual` routing
7+
- Better support for Account Portal redirect callback flows

packages/elements/examples/nextjs/app/modal/page.tsx

Lines changed: 422 additions & 0 deletions
Large diffs are not rendered by default.

packages/elements/examples/nextjs/app/page.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,19 @@ export default function Home() {
7171
<p className='m-0 max-w-[30ch] text-sm opacity-50'>OTP Playground</p>
7272
</Link>
7373

74+
<Link
75+
href='/modal'
76+
className='group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30'
77+
>
78+
<h2 className='mb-3 text-2xl font-semibold'>
79+
Modal{' '}
80+
<span className='inline-block transition-transform group-hover:translate-x-1 motion-reduce:transform-none'>
81+
-&gt;
82+
</span>
83+
</h2>
84+
<p className='m-0 max-w-[30ch] text-sm opacity-50'>Modal Playground</p>
85+
</Link>
86+
7487
<a
7588
href='https://clerk.com/docs/custom-flows/overview#sign-in-flow'
7689
className='group rounded-lg border border-transparent px-5 py-4 transition-colors hover:border-gray-300 hover:bg-gray-100 hover:dark:border-neutral-700 hover:dark:bg-neutral-800/30'

packages/elements/examples/nextjs/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"@clerk/elements": "file:../../elements",
1414
"@clerk/nextjs": "file:../../nextjs",
1515
"@radix-ui/react-form": "^0.0.3",
16+
"@radix-ui/react-popover": "^1.0.7",
1617
"clsx": "^2.0.0",
1718
"framer-motion": "^11.0.28",
1819
"geist": "^1.3",

packages/elements/src/internals/constants/index.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
export const SSO_CALLBACK_PATH_ROUTE = '/sso-callback';
22
export const MAGIC_LINK_VERIFY_PATH_ROUTE = '/verify';
33

4-
export const SIGN_IN_DEFAULT_BASE_PATH = '/sign-in';
5-
export const SIGN_UP_DEFAULT_BASE_PATH = '/sign-up';
4+
export const SIGN_IN_DEFAULT_BASE_PATH =
5+
process.env.CLERK_SIGN_IN_URL ?? process.env.NEXT_PUBLIC_CLERK_SIGN_IN_URL ?? '/sign-in';
6+
export const SIGN_UP_DEFAULT_BASE_PATH =
7+
process.env.CLERK_SIGN_UP_URL ?? process.env.NEXT_PUBLIC_CLERK_SIGN_UP_URL ?? '/sign-up';
68

79
// The version that Next added support for the window.history.pushState and replaceState APIs.
810
// ref: https://nextjs.org/blog/next-14-1#windowhistorypushstate-and-windowhistoryreplacestate
@@ -37,3 +39,10 @@ export const ERROR_CODES = {
3739
SAML_USER_ATTRIBUTE_MISSING: 'saml_user_attribute_missing',
3840
USER_LOCKED: 'user_locked',
3941
};
42+
43+
export const ROUTING = {
44+
path: 'path',
45+
virtual: 'virtual',
46+
} as const;
47+
48+
export type ROUTING = (typeof ROUTING)[keyof typeof ROUTING];

packages/elements/src/internals/machines/sign-in/router.machine.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { and, assign, enqueueActions, not, or, raise, sendTo, setup } from 'xsta
55

66
import {
77
ERROR_CODES,
8+
ROUTING,
89
SIGN_IN_DEFAULT_BASE_PATH,
910
SIGN_UP_DEFAULT_BASE_PATH,
1011
SSO_CALLBACK_PATH_ROUTE,
@@ -162,10 +163,16 @@ export const SignInRouterMachine = setup({
162163
initial: 'Idle',
163164
on: {
164165
'AUTHENTICATE.OAUTH': {
165-
actions: sendTo(ThirdPartyMachineId, ({ event }) => ({
166+
actions: sendTo(ThirdPartyMachineId, ({ context, event }) => ({
166167
type: 'REDIRECT',
167168
params: {
168169
strategy: event.strategy,
170+
redirectUrl: `${
171+
context.router?.mode === ROUTING.virtual
172+
? context.clerk.__unstable__environment?.displayConfig.signInUrl
173+
: context.router?.basePath
174+
}${SSO_CALLBACK_PATH_ROUTE}`,
175+
redirectUrlComplete: context.clerk.buildAfterSignInUrl(),
169176
},
170177
})),
171178
},

packages/elements/src/internals/machines/sign-up/router.machine.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { and, assign, enqueueActions, log, not, or, raise, sendTo, setup } from
55

66
import {
77
ERROR_CODES,
8+
ROUTING,
89
SEARCH_PARAMS,
910
SIGN_IN_DEFAULT_BASE_PATH,
1011
SIGN_UP_DEFAULT_BASE_PATH,
@@ -161,10 +162,16 @@ export const SignUpRouterMachine = setup({
161162
initial: 'Idle',
162163
on: {
163164
'AUTHENTICATE.OAUTH': {
164-
actions: sendTo(ThirdPartyMachineId, ({ event }) => ({
165+
actions: sendTo(ThirdPartyMachineId, ({ context, event }) => ({
165166
type: 'REDIRECT',
166167
params: {
167168
strategy: event.strategy,
169+
redirectUrl: `${
170+
context.router?.mode === ROUTING.virtual
171+
? context.clerk.__unstable__environment?.displayConfig.signUpUrl
172+
: context.router?.basePath
173+
}${SSO_CALLBACK_PATH_ROUTE}`,
174+
redirectUrlComplete: context.clerk.buildAfterSignUpUrl(),
168175
},
169176
})),
170177
},

packages/elements/src/internals/machines/third-party/third-party.actors.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import type { SetOptional } from 'type-fest';
88
import type { AnyActorRef, AnyEventObject } from 'xstate';
99
import { fromCallback, fromPromise } from 'xstate';
1010

11-
import { SSO_CALLBACK_PATH_ROUTE } from '~/internals/constants';
1211
import { ClerkElementsRuntimeError } from '~/internals/errors';
1312
import type { WithParams, WithUnsafeMetadata } from '~/internals/machines/shared';
1413
import { ClerkJSNavigationEvent, isClerkJSNavigationEvent } from '~/internals/machines/utils/clerkjs';
@@ -27,13 +26,12 @@ export type AuthenticateWithRedirectInput = (
2726
) & { basePath: string; parent: AnyActorRef }; // TODO: Fix circular dependency
2827

2928
export const redirect = fromPromise<void, AuthenticateWithRedirectInput>(
30-
async ({ input: { basePath, flow, params, parent } }) => {
29+
async ({ input: { flow, params, parent } }) => {
3130
const clerk: LoadedClerk = parent.getSnapshot().context.clerk;
32-
const path = clerk.buildUrlWithAuth(`${basePath}${SSO_CALLBACK_PATH_ROUTE}`);
3331

3432
return clerk.client[flow].authenticateWithRedirect({
35-
redirectUrl: path,
36-
redirectUrlComplete: path,
33+
redirectUrl: clerk.buildUrlWithAuth(params.redirectUrl || '/'),
34+
redirectUrlComplete: clerk.buildUrlWithAuth(params.redirectUrlComplete || '/'),
3735
...params,
3836
});
3937
},
@@ -80,8 +78,6 @@ export const handleRedirectCallback = fromCallback<AnyEventObject, HandleRedirec
8078

8179
void loadedClerk.handleRedirectCallback(
8280
{
83-
afterSignInUrl: ClerkJSNavigationEvent.signIn,
84-
afterSignUpUrl: ClerkJSNavigationEvent.signUp,
8581
signInForceRedirectUrl: ClerkJSNavigationEvent.complete,
8682
signInFallbackRedirectUrl: ClerkJSNavigationEvent.complete,
8783
signUpForceRedirectUrl: ClerkJSNavigationEvent.signUp,

packages/elements/src/internals/machines/third-party/third-party.machine.ts

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
import type { LoadedClerk } from '@clerk/types';
21
import { assertEvent, assign, log, not, sendTo, setup } from 'xstate';
32

4-
import { SSO_CALLBACK_PATH_ROUTE } from '~/internals/constants';
53
import { sendToLoading } from '~/internals/machines/shared';
64
import { assertActorEventError } from '~/internals/machines/utils/assert';
75

@@ -79,20 +77,10 @@ export const ThirdPartyMachine = setup({
7977
input: ({ context, event }) => {
8078
assertEvent(event, 'REDIRECT');
8179

82-
const clerk: LoadedClerk = context.parent.getSnapshot().context.clerk;
83-
84-
const redirectUrl =
85-
event.params.redirectUrl || clerk.buildUrlWithAuth(`${context.basePath}${SSO_CALLBACK_PATH_ROUTE}`);
86-
const redirectUrlComplete = event.params.redirectUrlComplete || redirectUrl;
87-
8880
return {
8981
basePath: context.basePath,
9082
flow: context.flow,
91-
params: {
92-
redirectUrl,
93-
redirectUrlComplete,
94-
...event.params,
95-
},
83+
params: event.params,
9684
parent: context.parent,
9785
};
9886
},

packages/elements/src/react/router/__tests__/router.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { createClerkRouter } from '../router';
22

33
describe('createClerkRouter', () => {
44
const mockRouter = {
5+
name: 'mockRouter',
6+
mode: 'path' as const,
57
pathname: jest.fn(),
68
searchParams: jest.fn(),
79
push: jest.fn(),

0 commit comments

Comments
 (0)